ftp://ftp.kernel.org/pub/linux/kernel/v2.6/linux-2.6.6.tar.bz2
[linux-2.6.git] / arch / ppc64 / kernel / udbg.c
1 /*
2  * NS16550 Serial Port (uart) debugging stuff.
3  *
4  * c 2001 PPC 64 Team, IBM Corp
5  *
6  * NOTE: I am trying to make this code avoid any static data references to
7  *  simplify debugging early boot.  We'll see how that goes...
8  *
9  * To use this call udbg_init() first.  It will init the uart to 9600 8N1.
10  * You may need to update the COM1 define if your uart is at a different addr.
11  *
12  *      This program is free software; you can redistribute it and/or
13  *      modify it under the terms of the GNU General Public License
14  *      as published by the Free Software Foundation; either version
15  *      2 of the License, or (at your option) any later version.
16  */
17
18 #include <stdarg.h>
19 #define WANT_PPCDBG_TAB /* Only defined here */
20 #include <asm/ppcdebug.h>
21 #include <asm/processor.h>
22 #include <asm/naca.h>
23 #include <asm/uaccess.h>
24 #include <asm/machdep.h>
25 #include <asm/io.h>
26 #include <asm/prom.h>
27 #include <asm/pmac_feature.h>
28
29 struct NS16550 {
30         /* this struct must be packed */
31         unsigned char rbr;  /* 0 */
32         unsigned char ier;  /* 1 */
33         unsigned char fcr;  /* 2 */
34         unsigned char lcr;  /* 3 */
35         unsigned char mcr;  /* 4 */
36         unsigned char lsr;  /* 5 */
37         unsigned char msr;  /* 6 */
38         unsigned char scr;  /* 7 */
39 };
40
41 #define thr rbr
42 #define iir fcr
43 #define dll rbr
44 #define dlm ier
45 #define dlab lcr
46
47 #define LSR_DR   0x01  /* Data ready */
48 #define LSR_OE   0x02  /* Overrun */
49 #define LSR_PE   0x04  /* Parity error */
50 #define LSR_FE   0x08  /* Framing error */
51 #define LSR_BI   0x10  /* Break */
52 #define LSR_THRE 0x20  /* Xmit holding register empty */
53 #define LSR_TEMT 0x40  /* Xmitter empty */
54 #define LSR_ERR  0x80  /* Error */
55
56 volatile struct NS16550 *udbg_comport;
57
58 void
59 udbg_init_uart(void *comport)
60 {
61         if (comport) {
62                 udbg_comport = (struct NS16550 *)comport;
63                 udbg_comport->lcr = 0x00; eieio();
64                 udbg_comport->ier = 0xFF; eieio();
65                 udbg_comport->ier = 0x00; eieio();
66                 udbg_comport->lcr = 0x80; eieio();      /* Access baud rate */
67                 udbg_comport->dll = 12;   eieio();      /* 1 = 115200,  2 = 57600, 3 = 38400, 12 = 9600 baud */
68                 udbg_comport->dlm = 0;    eieio();      /* dll >> 8 which should be zero for fast rates; */
69                 udbg_comport->lcr = 0x03; eieio();      /* 8 data, 1 stop, no parity */
70                 udbg_comport->mcr = 0x03; eieio();      /* RTS/DTR */
71                 udbg_comport->fcr = 0x07; eieio();      /* Clear & enable FIFOs */
72         }
73 }
74
75 #ifdef CONFIG_PPC_PMAC
76
77 #define SCC_TXRDY       4
78 #define SCC_RXRDY       1
79
80 static volatile u8 *sccc, *sccd;
81
82 static unsigned char scc_inittab[] = {
83     13, 0,              /* set baud rate divisor */
84     12, 0,
85     14, 1,              /* baud rate gen enable, src=rtxc */
86     11, 0x50,           /* clocks = br gen */
87     5,  0xea,           /* tx 8 bits, assert DTR & RTS */
88     4,  0x46,           /* x16 clock, 1 stop */
89     3,  0xc1,           /* rx enable, 8 bits */
90 };
91
92 void
93 udbg_init_scc(struct device_node *np)
94 {
95         unsigned long addr;
96         int i, x;
97
98         if (np == NULL)
99                 np = of_find_node_by_name(NULL, "escc");
100         if (np == NULL)
101                 return;
102         
103         /* Lock-enable the SCC channel */
104         pmac_call_feature(PMAC_FTR_SCC_ENABLE, np, PMAC_SCC_ASYNC | PMAC_SCC_FLAG_XMON, 1);
105
106         /* Setup for 57600 8N1 */
107         addr = np->addrs[0].address + 0x20;
108         sccc = (volatile u8 *) ioremap(addr & PAGE_MASK, PAGE_SIZE) ;
109         sccc += addr & ~PAGE_MASK;
110         sccd = sccc + 0x10;
111
112         for (i = 20000; i != 0; --i)
113                 x = *sccc; eieio();
114         *sccc = 9; eieio();             /* reset A or B side */
115         *sccc = 0xc0; eieio();
116         for (i = 0; i < sizeof(scc_inittab); ++i) {
117                 *sccc = scc_inittab[i];
118                 eieio();
119         }
120
121         ppc_md.udbg_putc = udbg_putc;
122         ppc_md.udbg_getc = udbg_getc;
123         ppc_md.udbg_getc_poll = udbg_getc_poll;
124
125         udbg_puts("Hello World !\n");
126 }
127
128 #endif /* CONFIG_PPC_PMAC */
129
130 void
131 udbg_putc(unsigned char c)
132 {
133         if ( udbg_comport ) {
134                 while ((udbg_comport->lsr & LSR_THRE) == 0)
135                         /* wait for idle */;
136                 udbg_comport->thr = c; eieio();
137                 if (c == '\n') {
138                         /* Also put a CR.  This is for convenience. */
139                         while ((udbg_comport->lsr & LSR_THRE) == 0)
140                                 /* wait for idle */;
141                         udbg_comport->thr = '\r'; eieio();
142                 }
143         }
144 #ifdef CONFIG_PPC_PMAC
145         else if (sccc) {
146                 while ((*sccc & SCC_TXRDY) == 0)
147                         eieio();
148                 *sccd = c;              
149                 eieio();
150                 if (c == '\n')
151                         udbg_putc('\r');
152         }
153 #endif /* CONFIG_PPC_PMAC */
154 }
155
156 int udbg_getc_poll(void)
157 {
158         if (udbg_comport) {
159                 if ((udbg_comport->lsr & LSR_DR) != 0)
160                         return udbg_comport->rbr;
161                 else
162                         return -1;
163         }
164 #ifdef CONFIG_PPC_PMAC
165         else if (sccc) {
166                 eieio();
167                 if ((*sccc & SCC_RXRDY) != 0)
168                         return *sccd;
169                 else
170                         return -1;
171         }
172 #endif /* CONFIG_PPC_PMAC */
173         return -1;
174 }
175
176 unsigned char
177 udbg_getc(void)
178 {
179         if ( udbg_comport ) {
180                 while ((udbg_comport->lsr & LSR_DR) == 0)
181                         /* wait for char */;
182                 return udbg_comport->rbr;
183         }
184 #ifdef CONFIG_PPC_PMAC
185         else if (sccc) {
186                 eieio();
187                 while ((*sccc & SCC_RXRDY) == 0)
188                         eieio();
189                 return *sccd;
190         }
191 #endif /* CONFIG_PPC_PMAC */
192         return 0;
193 }
194
195 void
196 udbg_puts(const char *s)
197 {
198         if (ppc_md.udbg_putc) {
199                 char c;
200
201                 if (s && *s != '\0') {
202                         while ((c = *s++) != '\0')
203                                 ppc_md.udbg_putc(c);
204                 }
205         } else {
206                 printk("%s", s);
207         }
208 }
209
210 int
211 udbg_write(const char *s, int n)
212 {
213         int remain = n;
214         char c;
215
216         if (!ppc_md.udbg_putc)
217                 return 0;
218
219         if ( s && *s != '\0' ) {
220                 while ( (( c = *s++ ) != '\0') && (remain-- > 0)) {
221                         ppc_md.udbg_putc(c);
222                 }
223         }
224         return n - remain;
225 }
226
227 int
228 udbg_read(char *buf, int buflen) {
229         char c, *p = buf;
230         int i;
231         if (!ppc_md.udbg_putc)
232                 for (;;);       /* stop here for cpuctl */
233         for (i = 0; i < buflen; ++i) {
234                 do {
235                         c = ppc_md.udbg_getc();
236                 } while (c == 0x11 || c == 0x13);
237                 if (c == 0)
238                         break;
239                 *p++ = c;
240         }
241         return i;
242 }
243
244 void
245 udbg_console_write(struct console *con, const char *s, unsigned int n)
246 {
247         udbg_write(s, n);
248 }
249
250 void
251 udbg_puthex(unsigned long val)
252 {
253         int i, nibbles = sizeof(val)*2;
254         unsigned char buf[sizeof(val)*2+1];
255         for (i = nibbles-1;  i >= 0;  i--) {
256                 buf[i] = (val & 0xf) + '0';
257                 if (buf[i] > '9')
258                     buf[i] += ('a'-'0'-10);
259                 val >>= 4;
260         }
261         buf[nibbles] = '\0';
262         udbg_puts(buf);
263 }
264
265 void
266 udbg_printSP(const char *s)
267 {
268         if (systemcfg->platform == PLATFORM_PSERIES) {
269                 unsigned long sp;
270                 asm("mr %0,1" : "=r" (sp) :);
271                 if (s)
272                         udbg_puts(s);
273                 udbg_puthex(sp);
274         }
275 }
276
277 void
278 udbg_printf(const char *fmt, ...)
279 {
280         unsigned char buf[256];
281
282         va_list args;
283         va_start(args, fmt);
284
285         vsprintf(buf, fmt, args);
286         udbg_puts(buf);
287
288         va_end(args);
289 }
290
291 /* Special print used by PPCDBG() macro */
292 void
293 udbg_ppcdbg(unsigned long debug_flags, const char *fmt, ...)
294 {
295         unsigned long active_debugs = debug_flags & naca->debug_switch;
296
297         if ( active_debugs ) {
298                 va_list ap;
299                 unsigned char buf[256];
300                 unsigned long i, len = 0;
301
302                 for(i=0; i < PPCDBG_NUM_FLAGS ;i++) {
303                         if (((1U << i) & active_debugs) && 
304                             trace_names[i]) {
305                                 len += strlen(trace_names[i]); 
306                                 udbg_puts(trace_names[i]);
307                                 break;
308                         }
309                 }
310                 sprintf(buf, " [%s]: ", current->comm);
311                 len += strlen(buf); 
312                 udbg_puts(buf);
313
314                 while(len < 18) {
315                         udbg_puts(" ");
316                         len++;
317                 }
318
319                 va_start(ap, fmt);
320                 vsprintf(buf, fmt, ap);
321                 udbg_puts(buf);
322                 
323                 va_end(ap);
324         }
325 }
326
327 unsigned long
328 udbg_ifdebug(unsigned long flags)
329 {
330         return (flags & naca->debug_switch);
331 }