Merge branch 'perf/urgent' into perf/core
[pandora-kernel.git] / arch / powerpc / kernel / udbg_16550.c
1 /*
2  * udbg 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  */
11 #include <linux/types.h>
12 #include <asm/udbg.h>
13 #include <asm/io.h>
14
15 extern u8 real_readb(volatile u8 __iomem  *addr);
16 extern void real_writeb(u8 data, volatile u8 __iomem *addr);
17 extern u8 real_205_readb(volatile u8 __iomem  *addr);
18 extern void real_205_writeb(u8 data, volatile u8 __iomem *addr);
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
47 #define LCR_DLAB 0x80
48
49 static struct NS16550 __iomem *udbg_comport;
50
51 static void udbg_550_flush(void)
52 {
53         if (udbg_comport) {
54                 while ((in_8(&udbg_comport->lsr) & LSR_THRE) == 0)
55                         /* wait for idle */;
56         }
57 }
58
59 static void udbg_550_putc(char c)
60 {
61         if (udbg_comport) {
62                 if (c == '\n')
63                         udbg_550_putc('\r');
64                 udbg_550_flush();
65                 out_8(&udbg_comport->thr, c);
66         }
67 }
68
69 static int udbg_550_getc_poll(void)
70 {
71         if (udbg_comport) {
72                 if ((in_8(&udbg_comport->lsr) & LSR_DR) != 0)
73                         return in_8(&udbg_comport->rbr);
74                 else
75                         return -1;
76         }
77         return -1;
78 }
79
80 static int udbg_550_getc(void)
81 {
82         if (udbg_comport) {
83                 while ((in_8(&udbg_comport->lsr) & LSR_DR) == 0)
84                         /* wait for char */;
85                 return in_8(&udbg_comport->rbr);
86         }
87         return -1;
88 }
89
90 void udbg_init_uart(void __iomem *comport, unsigned int speed,
91                     unsigned int clock)
92 {
93         unsigned int dll, base_bauds;
94
95         if (clock == 0)
96                 clock = 1843200;
97         if (speed == 0)
98                 speed = 9600;
99
100         base_bauds = clock / 16;
101         dll = base_bauds / speed;
102
103         if (comport) {
104                 udbg_comport = (struct NS16550 __iomem *)comport;
105                 out_8(&udbg_comport->lcr, 0x00);
106                 out_8(&udbg_comport->ier, 0xff);
107                 out_8(&udbg_comport->ier, 0x00);
108                 out_8(&udbg_comport->lcr, LCR_DLAB);
109                 out_8(&udbg_comport->dll, dll & 0xff);
110                 out_8(&udbg_comport->dlm, dll >> 8);
111                 /* 8 data, 1 stop, no parity */
112                 out_8(&udbg_comport->lcr, 0x03);
113                 /* RTS/DTR */
114                 out_8(&udbg_comport->mcr, 0x03);
115                 /* Clear & enable FIFOs */
116                 out_8(&udbg_comport->fcr ,0x07);
117                 udbg_putc = udbg_550_putc;
118                 udbg_flush = udbg_550_flush;
119                 udbg_getc = udbg_550_getc;
120                 udbg_getc_poll = udbg_550_getc_poll;
121         }
122 }
123
124 unsigned int udbg_probe_uart_speed(void __iomem *comport, unsigned int clock)
125 {
126         unsigned int dll, dlm, divisor, prescaler, speed;
127         u8 old_lcr;
128         struct NS16550 __iomem *port = comport;
129
130         old_lcr = in_8(&port->lcr);
131
132         /* select divisor latch registers.  */
133         out_8(&port->lcr, LCR_DLAB);
134
135         /* now, read the divisor */
136         dll = in_8(&port->dll);
137         dlm = in_8(&port->dlm);
138         divisor = dlm << 8 | dll;
139
140         /* check prescaling */
141         if (in_8(&port->mcr) & 0x80)
142                 prescaler = 4;
143         else
144                 prescaler = 1;
145
146         /* restore the LCR */
147         out_8(&port->lcr, old_lcr);
148
149         /* calculate speed */
150         speed = (clock / prescaler) / (divisor * 16);
151
152         /* sanity check */
153         if (speed > (clock / 16))
154                 speed = 9600;
155
156         return speed;
157 }
158
159 #ifdef CONFIG_PPC_MAPLE
160 void udbg_maple_real_flush(void)
161 {
162         if (udbg_comport) {
163                 while ((real_readb(&udbg_comport->lsr) & LSR_THRE) == 0)
164                         /* wait for idle */;
165         }
166 }
167
168 void udbg_maple_real_putc(char c)
169 {
170         if (udbg_comport) {
171                 if (c == '\n')
172                         udbg_maple_real_putc('\r');
173                 udbg_maple_real_flush();
174                 real_writeb(c, &udbg_comport->thr); eieio();
175         }
176 }
177
178 void __init udbg_init_maple_realmode(void)
179 {
180         udbg_comport = (struct NS16550 __iomem *)0xf40003f8;
181
182         udbg_putc = udbg_maple_real_putc;
183         udbg_flush = udbg_maple_real_flush;
184         udbg_getc = NULL;
185         udbg_getc_poll = NULL;
186 }
187 #endif /* CONFIG_PPC_MAPLE */
188
189 #ifdef CONFIG_PPC_PASEMI
190 void udbg_pas_real_flush(void)
191 {
192         if (udbg_comport) {
193                 while ((real_205_readb(&udbg_comport->lsr) & LSR_THRE) == 0)
194                         /* wait for idle */;
195         }
196 }
197
198 void udbg_pas_real_putc(char c)
199 {
200         if (udbg_comport) {
201                 if (c == '\n')
202                         udbg_pas_real_putc('\r');
203                 udbg_pas_real_flush();
204                 real_205_writeb(c, &udbg_comport->thr); eieio();
205         }
206 }
207
208 void udbg_init_pas_realmode(void)
209 {
210         udbg_comport = (struct NS16550 __iomem *)0xfcff03f8UL;
211
212         udbg_putc = udbg_pas_real_putc;
213         udbg_flush = udbg_pas_real_flush;
214         udbg_getc = NULL;
215         udbg_getc_poll = NULL;
216 }
217 #endif /* CONFIG_PPC_MAPLE */
218
219 #ifdef CONFIG_PPC_EARLY_DEBUG_44x
220 #include <platforms/44x/44x.h>
221
222 static void udbg_44x_as1_flush(void)
223 {
224         if (udbg_comport) {
225                 while ((as1_readb(&udbg_comport->lsr) & LSR_THRE) == 0)
226                         /* wait for idle */;
227         }
228 }
229
230 static void udbg_44x_as1_putc(char c)
231 {
232         if (udbg_comport) {
233                 if (c == '\n')
234                         udbg_44x_as1_putc('\r');
235                 udbg_44x_as1_flush();
236                 as1_writeb(c, &udbg_comport->thr); eieio();
237         }
238 }
239
240 static int udbg_44x_as1_getc(void)
241 {
242         if (udbg_comport) {
243                 while ((as1_readb(&udbg_comport->lsr) & LSR_DR) == 0)
244                         ; /* wait for char */
245                 return as1_readb(&udbg_comport->rbr);
246         }
247         return -1;
248 }
249
250 void __init udbg_init_44x_as1(void)
251 {
252         udbg_comport =
253                 (struct NS16550 __iomem *)PPC44x_EARLY_DEBUG_VIRTADDR;
254
255         udbg_putc = udbg_44x_as1_putc;
256         udbg_flush = udbg_44x_as1_flush;
257         udbg_getc = udbg_44x_as1_getc;
258 }
259 #endif /* CONFIG_PPC_EARLY_DEBUG_44x */
260
261 #ifdef CONFIG_PPC_EARLY_DEBUG_40x
262 static void udbg_40x_real_flush(void)
263 {
264         if (udbg_comport) {
265                 while ((real_readb(&udbg_comport->lsr) & LSR_THRE) == 0)
266                         /* wait for idle */;
267         }
268 }
269
270 static void udbg_40x_real_putc(char c)
271 {
272         if (udbg_comport) {
273                 if (c == '\n')
274                         udbg_40x_real_putc('\r');
275                 udbg_40x_real_flush();
276                 real_writeb(c, &udbg_comport->thr); eieio();
277         }
278 }
279
280 static int udbg_40x_real_getc(void)
281 {
282         if (udbg_comport) {
283                 while ((real_readb(&udbg_comport->lsr) & LSR_DR) == 0)
284                         ; /* wait for char */
285                 return real_readb(&udbg_comport->rbr);
286         }
287         return -1;
288 }
289
290 void __init udbg_init_40x_realmode(void)
291 {
292         udbg_comport = (struct NS16550 __iomem *)
293                 CONFIG_PPC_EARLY_DEBUG_40x_PHYSADDR;
294
295         udbg_putc = udbg_40x_real_putc;
296         udbg_flush = udbg_40x_real_flush;
297         udbg_getc = udbg_40x_real_getc;
298         udbg_getc_poll = NULL;
299 }
300 #endif /* CONFIG_PPC_EARLY_DEBUG_40x */