]>
Commit | Line | Data |
---|---|---|
7f853352 MM |
1 | /* |
2 | * udbg for for NS16550 compatable serial ports | |
3 | * | |
4 | * Copyright (C) 2001-2005 PPC 64 Team, IBM Corp | |
5 | * | |
6 | * This program is free software; you can redistribute it and/or | |
7 | * modify it under the terms of the GNU General Public License | |
8 | * as published by the Free Software Foundation; either version | |
9 | * 2 of the License, or (at your option) any later version. | |
10 | */ | |
7f853352 | 11 | #include <linux/types.h> |
188d2ce7 | 12 | #include <asm/udbg.h> |
7f853352 | 13 | #include <asm/io.h> |
7f853352 MM |
14 | |
15 | extern u8 real_readb(volatile u8 __iomem *addr); | |
16 | extern void real_writeb(u8 data, volatile u8 __iomem *addr); | |
39c870d5 OJ |
17 | extern u8 real_205_readb(volatile u8 __iomem *addr); |
18 | extern void real_205_writeb(u8 data, volatile u8 __iomem *addr); | |
7f853352 MM |
19 | |
20 | struct NS16550 { | |
21 | /* this struct must be packed */ | |
22 | unsigned char rbr; /* 0 */ | |
23 | unsigned char ier; /* 1 */ | |
24 | unsigned char fcr; /* 2 */ | |
25 | unsigned char lcr; /* 3 */ | |
26 | unsigned char mcr; /* 4 */ | |
27 | unsigned char lsr; /* 5 */ | |
28 | unsigned char msr; /* 6 */ | |
29 | unsigned char scr; /* 7 */ | |
30 | }; | |
31 | ||
32 | #define thr rbr | |
33 | #define iir fcr | |
34 | #define dll rbr | |
35 | #define dlm ier | |
36 | #define dlab lcr | |
37 | ||
38 | #define LSR_DR 0x01 /* Data ready */ | |
39 | #define LSR_OE 0x02 /* Overrun */ | |
40 | #define LSR_PE 0x04 /* Parity error */ | |
41 | #define LSR_FE 0x08 /* Framing error */ | |
42 | #define LSR_BI 0x10 /* Break */ | |
43 | #define LSR_THRE 0x20 /* Xmit holding register empty */ | |
44 | #define LSR_TEMT 0x40 /* Xmitter empty */ | |
45 | #define LSR_ERR 0x80 /* Error */ | |
46 | ||
463ce0e1 BH |
47 | #define LCR_DLAB 0x80 |
48 | ||
f276b5ba | 49 | static struct NS16550 __iomem *udbg_comport; |
7f853352 | 50 | |
51d3082f | 51 | static void udbg_550_putc(char c) |
7f853352 MM |
52 | { |
53 | if (udbg_comport) { | |
54 | while ((in_8(&udbg_comport->lsr) & LSR_THRE) == 0) | |
55 | /* wait for idle */; | |
56 | out_8(&udbg_comport->thr, c); | |
57 | if (c == '\n') | |
58 | udbg_550_putc('\r'); | |
59 | } | |
60 | } | |
61 | ||
62 | static int udbg_550_getc_poll(void) | |
63 | { | |
64 | if (udbg_comport) { | |
65 | if ((in_8(&udbg_comport->lsr) & LSR_DR) != 0) | |
66 | return in_8(&udbg_comport->rbr); | |
67 | else | |
68 | return -1; | |
69 | } | |
70 | return -1; | |
71 | } | |
72 | ||
bb6b9b28 | 73 | static int udbg_550_getc(void) |
7f853352 MM |
74 | { |
75 | if (udbg_comport) { | |
76 | while ((in_8(&udbg_comport->lsr) & LSR_DR) == 0) | |
77 | /* wait for char */; | |
78 | return in_8(&udbg_comport->rbr); | |
79 | } | |
bb6b9b28 | 80 | return -1; |
7f853352 MM |
81 | } |
82 | ||
463ce0e1 BH |
83 | void udbg_init_uart(void __iomem *comport, unsigned int speed, |
84 | unsigned int clock) | |
7f853352 | 85 | { |
171505da | 86 | unsigned int dll, base_bauds; |
463ce0e1 | 87 | |
171505da BH |
88 | if (clock == 0) |
89 | clock = 1843200; | |
463ce0e1 BH |
90 | if (speed == 0) |
91 | speed = 9600; | |
171505da BH |
92 | |
93 | base_bauds = clock / 16; | |
463ce0e1 | 94 | dll = base_bauds / speed; |
7f853352 MM |
95 | |
96 | if (comport) { | |
97 | udbg_comport = (struct NS16550 __iomem *)comport; | |
98 | out_8(&udbg_comport->lcr, 0x00); | |
99 | out_8(&udbg_comport->ier, 0xff); | |
100 | out_8(&udbg_comport->ier, 0x00); | |
463ce0e1 BH |
101 | out_8(&udbg_comport->lcr, LCR_DLAB); |
102 | out_8(&udbg_comport->dll, dll & 0xff); | |
103 | out_8(&udbg_comport->dlm, dll >> 8); | |
104 | /* 8 data, 1 stop, no parity */ | |
105 | out_8(&udbg_comport->lcr, 0x03); | |
106 | /* RTS/DTR */ | |
107 | out_8(&udbg_comport->mcr, 0x03); | |
108 | /* Clear & enable FIFOs */ | |
109 | out_8(&udbg_comport->fcr ,0x07); | |
c8f1c8be MM |
110 | udbg_putc = udbg_550_putc; |
111 | udbg_getc = udbg_550_getc; | |
112 | udbg_getc_poll = udbg_550_getc_poll; | |
7f853352 MM |
113 | } |
114 | } | |
115 | ||
463ce0e1 BH |
116 | unsigned int udbg_probe_uart_speed(void __iomem *comport, unsigned int clock) |
117 | { | |
118 | unsigned int dll, dlm, divisor, prescaler, speed; | |
119 | u8 old_lcr; | |
f276b5ba | 120 | struct NS16550 __iomem *port = comport; |
463ce0e1 BH |
121 | |
122 | old_lcr = in_8(&port->lcr); | |
123 | ||
124 | /* select divisor latch registers. */ | |
125 | out_8(&port->lcr, LCR_DLAB); | |
126 | ||
127 | /* now, read the divisor */ | |
128 | dll = in_8(&port->dll); | |
129 | dlm = in_8(&port->dlm); | |
130 | divisor = dlm << 8 | dll; | |
131 | ||
132 | /* check prescaling */ | |
133 | if (in_8(&port->mcr) & 0x80) | |
134 | prescaler = 4; | |
135 | else | |
136 | prescaler = 1; | |
137 | ||
138 | /* restore the LCR */ | |
139 | out_8(&port->lcr, old_lcr); | |
140 | ||
141 | /* calculate speed */ | |
142 | speed = (clock / prescaler) / (divisor * 16); | |
143 | ||
144 | /* sanity check */ | |
d0e132b5 | 145 | if (speed < 0 || speed > (clock / 16)) |
463ce0e1 BH |
146 | speed = 9600; |
147 | ||
148 | return speed; | |
149 | } | |
150 | ||
7f853352 | 151 | #ifdef CONFIG_PPC_MAPLE |
4009d980 | 152 | void udbg_maple_real_putc(char c) |
7f853352 MM |
153 | { |
154 | if (udbg_comport) { | |
155 | while ((real_readb(&udbg_comport->lsr) & LSR_THRE) == 0) | |
156 | /* wait for idle */; | |
157 | real_writeb(c, &udbg_comport->thr); eieio(); | |
158 | if (c == '\n') | |
159 | udbg_maple_real_putc('\r'); | |
160 | } | |
161 | } | |
162 | ||
296167ae | 163 | void __init udbg_init_maple_realmode(void) |
7f853352 | 164 | { |
f276b5ba | 165 | udbg_comport = (struct NS16550 __iomem *)0xf40003f8; |
7f853352 | 166 | |
c8f1c8be MM |
167 | udbg_putc = udbg_maple_real_putc; |
168 | udbg_getc = NULL; | |
169 | udbg_getc_poll = NULL; | |
7f853352 MM |
170 | } |
171 | #endif /* CONFIG_PPC_MAPLE */ | |
39c870d5 OJ |
172 | |
173 | #ifdef CONFIG_PPC_PASEMI | |
174 | void udbg_pas_real_putc(char c) | |
175 | { | |
176 | if (udbg_comport) { | |
177 | while ((real_205_readb(&udbg_comport->lsr) & LSR_THRE) == 0) | |
178 | /* wait for idle */; | |
179 | real_205_writeb(c, &udbg_comport->thr); eieio(); | |
180 | if (c == '\n') | |
181 | udbg_pas_real_putc('\r'); | |
182 | } | |
183 | } | |
184 | ||
185 | void udbg_init_pas_realmode(void) | |
186 | { | |
f276b5ba | 187 | udbg_comport = (struct NS16550 __iomem *)0xfcff03f8UL; |
39c870d5 OJ |
188 | |
189 | udbg_putc = udbg_pas_real_putc; | |
190 | udbg_getc = NULL; | |
191 | udbg_getc_poll = NULL; | |
192 | } | |
193 | #endif /* CONFIG_PPC_MAPLE */ | |
d9b55a03 DG |
194 | |
195 | #ifdef CONFIG_PPC_EARLY_DEBUG_44x | |
196 | #include <platforms/44x/44x.h> | |
197 | ||
198 | static void udbg_44x_as1_putc(char c) | |
199 | { | |
200 | if (udbg_comport) { | |
201 | while ((as1_readb(&udbg_comport->lsr) & LSR_THRE) == 0) | |
202 | /* wait for idle */; | |
203 | as1_writeb(c, &udbg_comport->thr); eieio(); | |
204 | if (c == '\n') | |
205 | udbg_44x_as1_putc('\r'); | |
206 | } | |
207 | } | |
208 | ||
70dea47d HB |
209 | static int udbg_44x_as1_getc(void) |
210 | { | |
211 | if (udbg_comport) { | |
212 | while ((as1_readb(&udbg_comport->lsr) & LSR_DR) == 0) | |
213 | ; /* wait for char */ | |
214 | return as1_readb(&udbg_comport->rbr); | |
215 | } | |
216 | return -1; | |
217 | } | |
218 | ||
d9b55a03 DG |
219 | void __init udbg_init_44x_as1(void) |
220 | { | |
221 | udbg_comport = | |
f276b5ba | 222 | (struct NS16550 __iomem *)PPC44x_EARLY_DEBUG_VIRTADDR; |
d9b55a03 DG |
223 | |
224 | udbg_putc = udbg_44x_as1_putc; | |
70dea47d | 225 | udbg_getc = udbg_44x_as1_getc; |
d9b55a03 DG |
226 | } |
227 | #endif /* CONFIG_PPC_EARLY_DEBUG_44x */ | |
9dae8afd BH |
228 | |
229 | #ifdef CONFIG_PPC_EARLY_DEBUG_40x | |
230 | static void udbg_40x_real_putc(char c) | |
231 | { | |
232 | if (udbg_comport) { | |
233 | while ((real_readb(&udbg_comport->lsr) & LSR_THRE) == 0) | |
234 | /* wait for idle */; | |
235 | real_writeb(c, &udbg_comport->thr); eieio(); | |
236 | if (c == '\n') | |
237 | udbg_40x_real_putc('\r'); | |
238 | } | |
239 | } | |
240 | ||
241 | static int udbg_40x_real_getc(void) | |
242 | { | |
243 | if (udbg_comport) { | |
244 | while ((real_readb(&udbg_comport->lsr) & LSR_DR) == 0) | |
245 | ; /* wait for char */ | |
246 | return real_readb(&udbg_comport->rbr); | |
247 | } | |
248 | return -1; | |
249 | } | |
250 | ||
251 | void __init udbg_init_40x_realmode(void) | |
252 | { | |
253 | udbg_comport = (struct NS16550 __iomem *) | |
254 | CONFIG_PPC_EARLY_DEBUG_40x_PHYSADDR; | |
255 | ||
256 | udbg_putc = udbg_40x_real_putc; | |
257 | udbg_getc = udbg_40x_real_getc; | |
258 | udbg_getc_poll = NULL; | |
259 | } | |
260 | #endif /* CONFIG_PPC_EARLY_DEBUG_40x */ |