Merge branch 'for-linus' of git://oss.sgi.com/xfs/xfs
[pandora-kernel.git] / arch / powerpc / kernel / udbg_16550.c
1 /*
2  * udbg for NS16550 compatible 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  */
11 #include <linux/types.h>
12 #include <asm/udbg.h>
13 #include <asm/io.h>
14 #include <asm/reg_a2.h>
15
16 extern u8 real_readb(volatile u8 __iomem  *addr);
17 extern void real_writeb(u8 data, volatile u8 __iomem *addr);
18 extern u8 real_205_readb(volatile u8 __iomem  *addr);
19 extern void real_205_writeb(u8 data, volatile u8 __iomem *addr);
20
21 struct NS16550 {
22         /* this struct must be packed */
23         unsigned char rbr;  /* 0 */
24         unsigned char ier;  /* 1 */
25         unsigned char fcr;  /* 2 */
26         unsigned char lcr;  /* 3 */
27         unsigned char mcr;  /* 4 */
28         unsigned char lsr;  /* 5 */
29         unsigned char msr;  /* 6 */
30         unsigned char scr;  /* 7 */
31 };
32
33 #define thr rbr
34 #define iir fcr
35 #define dll rbr
36 #define dlm ier
37 #define dlab lcr
38
39 #define LSR_DR   0x01  /* Data ready */
40 #define LSR_OE   0x02  /* Overrun */
41 #define LSR_PE   0x04  /* Parity error */
42 #define LSR_FE   0x08  /* Framing error */
43 #define LSR_BI   0x10  /* Break */
44 #define LSR_THRE 0x20  /* Xmit holding register empty */
45 #define LSR_TEMT 0x40  /* Xmitter empty */
46 #define LSR_ERR  0x80  /* Error */
47
48 #define LCR_DLAB 0x80
49
50 static struct NS16550 __iomem *udbg_comport;
51
52 static void udbg_550_flush(void)
53 {
54         if (udbg_comport) {
55                 while ((in_8(&udbg_comport->lsr) & LSR_THRE) == 0)
56                         /* wait for idle */;
57         }
58 }
59
60 static void udbg_550_putc(char c)
61 {
62         if (udbg_comport) {
63                 if (c == '\n')
64                         udbg_550_putc('\r');
65                 udbg_550_flush();
66                 out_8(&udbg_comport->thr, c);
67         }
68 }
69
70 static int udbg_550_getc_poll(void)
71 {
72         if (udbg_comport) {
73                 if ((in_8(&udbg_comport->lsr) & LSR_DR) != 0)
74                         return in_8(&udbg_comport->rbr);
75                 else
76                         return -1;
77         }
78         return -1;
79 }
80
81 static int udbg_550_getc(void)
82 {
83         if (udbg_comport) {
84                 while ((in_8(&udbg_comport->lsr) & LSR_DR) == 0)
85                         /* wait for char */;
86                 return in_8(&udbg_comport->rbr);
87         }
88         return -1;
89 }
90
91 void udbg_init_uart(void __iomem *comport, unsigned int speed,
92                     unsigned int clock)
93 {
94         unsigned int dll, base_bauds;
95
96         if (clock == 0)
97                 clock = 1843200;
98         if (speed == 0)
99                 speed = 9600;
100
101         base_bauds = clock / 16;
102         dll = base_bauds / speed;
103
104         if (comport) {
105                 udbg_comport = (struct NS16550 __iomem *)comport;
106                 out_8(&udbg_comport->lcr, 0x00);
107                 out_8(&udbg_comport->ier, 0xff);
108                 out_8(&udbg_comport->ier, 0x00);
109                 out_8(&udbg_comport->lcr, LCR_DLAB);
110                 out_8(&udbg_comport->dll, dll & 0xff);
111                 out_8(&udbg_comport->dlm, dll >> 8);
112                 /* 8 data, 1 stop, no parity */
113                 out_8(&udbg_comport->lcr, 0x03);
114                 /* RTS/DTR */
115                 out_8(&udbg_comport->mcr, 0x03);
116                 /* Clear & enable FIFOs */
117                 out_8(&udbg_comport->fcr ,0x07);
118                 udbg_putc = udbg_550_putc;
119                 udbg_flush = udbg_550_flush;
120                 udbg_getc = udbg_550_getc;
121                 udbg_getc_poll = udbg_550_getc_poll;
122         }
123 }
124
125 unsigned int udbg_probe_uart_speed(void __iomem *comport, unsigned int clock)
126 {
127         unsigned int dll, dlm, divisor, prescaler, speed;
128         u8 old_lcr;
129         struct NS16550 __iomem *port = comport;
130
131         old_lcr = in_8(&port->lcr);
132
133         /* select divisor latch registers.  */
134         out_8(&port->lcr, LCR_DLAB);
135
136         /* now, read the divisor */
137         dll = in_8(&port->dll);
138         dlm = in_8(&port->dlm);
139         divisor = dlm << 8 | dll;
140
141         /* check prescaling */
142         if (in_8(&port->mcr) & 0x80)
143                 prescaler = 4;
144         else
145                 prescaler = 1;
146
147         /* restore the LCR */
148         out_8(&port->lcr, old_lcr);
149
150         /* calculate speed */
151         speed = (clock / prescaler) / (divisor * 16);
152
153         /* sanity check */
154         if (speed > (clock / 16))
155                 speed = 9600;
156
157         return speed;
158 }
159
160 #ifdef CONFIG_PPC_MAPLE
161 void udbg_maple_real_flush(void)
162 {
163         if (udbg_comport) {
164                 while ((real_readb(&udbg_comport->lsr) & LSR_THRE) == 0)
165                         /* wait for idle */;
166         }
167 }
168
169 void udbg_maple_real_putc(char c)
170 {
171         if (udbg_comport) {
172                 if (c == '\n')
173                         udbg_maple_real_putc('\r');
174                 udbg_maple_real_flush();
175                 real_writeb(c, &udbg_comport->thr); eieio();
176         }
177 }
178
179 void __init udbg_init_maple_realmode(void)
180 {
181         udbg_comport = (struct NS16550 __iomem *)0xf40003f8;
182
183         udbg_putc = udbg_maple_real_putc;
184         udbg_flush = udbg_maple_real_flush;
185         udbg_getc = NULL;
186         udbg_getc_poll = NULL;
187 }
188 #endif /* CONFIG_PPC_MAPLE */
189
190 #ifdef CONFIG_PPC_PASEMI
191 void udbg_pas_real_flush(void)
192 {
193         if (udbg_comport) {
194                 while ((real_205_readb(&udbg_comport->lsr) & LSR_THRE) == 0)
195                         /* wait for idle */;
196         }
197 }
198
199 void udbg_pas_real_putc(char c)
200 {
201         if (udbg_comport) {
202                 if (c == '\n')
203                         udbg_pas_real_putc('\r');
204                 udbg_pas_real_flush();
205                 real_205_writeb(c, &udbg_comport->thr); eieio();
206         }
207 }
208
209 void udbg_init_pas_realmode(void)
210 {
211         udbg_comport = (struct NS16550 __iomem *)0xfcff03f8UL;
212
213         udbg_putc = udbg_pas_real_putc;
214         udbg_flush = udbg_pas_real_flush;
215         udbg_getc = NULL;
216         udbg_getc_poll = NULL;
217 }
218 #endif /* CONFIG_PPC_MAPLE */
219
220 #ifdef CONFIG_PPC_EARLY_DEBUG_44x
221 #include <platforms/44x/44x.h>
222
223 static void udbg_44x_as1_flush(void)
224 {
225         if (udbg_comport) {
226                 while ((as1_readb(&udbg_comport->lsr) & LSR_THRE) == 0)
227                         /* wait for idle */;
228         }
229 }
230
231 static void udbg_44x_as1_putc(char c)
232 {
233         if (udbg_comport) {
234                 if (c == '\n')
235                         udbg_44x_as1_putc('\r');
236                 udbg_44x_as1_flush();
237                 as1_writeb(c, &udbg_comport->thr); eieio();
238         }
239 }
240
241 static int udbg_44x_as1_getc(void)
242 {
243         if (udbg_comport) {
244                 while ((as1_readb(&udbg_comport->lsr) & LSR_DR) == 0)
245                         ; /* wait for char */
246                 return as1_readb(&udbg_comport->rbr);
247         }
248         return -1;
249 }
250
251 void __init udbg_init_44x_as1(void)
252 {
253         udbg_comport =
254                 (struct NS16550 __iomem *)PPC44x_EARLY_DEBUG_VIRTADDR;
255
256         udbg_putc = udbg_44x_as1_putc;
257         udbg_flush = udbg_44x_as1_flush;
258         udbg_getc = udbg_44x_as1_getc;
259 }
260 #endif /* CONFIG_PPC_EARLY_DEBUG_44x */
261
262 #ifdef CONFIG_PPC_EARLY_DEBUG_40x
263 static void udbg_40x_real_flush(void)
264 {
265         if (udbg_comport) {
266                 while ((real_readb(&udbg_comport->lsr) & LSR_THRE) == 0)
267                         /* wait for idle */;
268         }
269 }
270
271 static void udbg_40x_real_putc(char c)
272 {
273         if (udbg_comport) {
274                 if (c == '\n')
275                         udbg_40x_real_putc('\r');
276                 udbg_40x_real_flush();
277                 real_writeb(c, &udbg_comport->thr); eieio();
278         }
279 }
280
281 static int udbg_40x_real_getc(void)
282 {
283         if (udbg_comport) {
284                 while ((real_readb(&udbg_comport->lsr) & LSR_DR) == 0)
285                         ; /* wait for char */
286                 return real_readb(&udbg_comport->rbr);
287         }
288         return -1;
289 }
290
291 void __init udbg_init_40x_realmode(void)
292 {
293         udbg_comport = (struct NS16550 __iomem *)
294                 CONFIG_PPC_EARLY_DEBUG_40x_PHYSADDR;
295
296         udbg_putc = udbg_40x_real_putc;
297         udbg_flush = udbg_40x_real_flush;
298         udbg_getc = udbg_40x_real_getc;
299         udbg_getc_poll = NULL;
300 }
301 #endif /* CONFIG_PPC_EARLY_DEBUG_40x */
302
303 #ifdef CONFIG_PPC_EARLY_DEBUG_WSP
304 static void udbg_wsp_flush(void)
305 {
306         if (udbg_comport) {
307                 while ((readb(&udbg_comport->lsr) & LSR_THRE) == 0)
308                         /* wait for idle */;
309         }
310 }
311
312 static void udbg_wsp_putc(char c)
313 {
314         if (udbg_comport) {
315                 if (c == '\n')
316                         udbg_wsp_putc('\r');
317                 udbg_wsp_flush();
318                 writeb(c, &udbg_comport->thr); eieio();
319         }
320 }
321
322 static int udbg_wsp_getc(void)
323 {
324         if (udbg_comport) {
325                 while ((readb(&udbg_comport->lsr) & LSR_DR) == 0)
326                         ; /* wait for char */
327                 return readb(&udbg_comport->rbr);
328         }
329         return -1;
330 }
331
332 static int udbg_wsp_getc_poll(void)
333 {
334         if (udbg_comport)
335                 if (readb(&udbg_comport->lsr) & LSR_DR)
336                         return readb(&udbg_comport->rbr);
337         return -1;
338 }
339
340 void __init udbg_init_wsp(void)
341 {
342         udbg_comport = (struct NS16550 __iomem *)WSP_UART_VIRT;
343
344         udbg_init_uart(udbg_comport, 57600, 50000000);
345
346         udbg_putc = udbg_wsp_putc;
347         udbg_flush = udbg_wsp_flush;
348         udbg_getc = udbg_wsp_getc;
349         udbg_getc_poll = udbg_wsp_getc_poll;
350 }
351 #endif /* CONFIG_PPC_EARLY_DEBUG_WSP */