cleanup
[linux-2.4.21-pre4.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
26 struct NS16550 {
27         /* this struct must be packed */
28         unsigned char rbr;  /* 0 */
29         unsigned char ier;  /* 1 */
30         unsigned char fcr;  /* 2 */
31         unsigned char lcr;  /* 3 */
32         unsigned char mcr;  /* 4 */
33         unsigned char lsr;  /* 5 */
34         unsigned char msr;  /* 6 */
35         unsigned char scr;  /* 7 */
36 };
37
38 #define thr rbr
39 #define iir fcr
40 #define dll rbr
41 #define dlm ier
42 #define dlab lcr
43
44 #define LSR_DR   0x01  /* Data ready */
45 #define LSR_OE   0x02  /* Overrun */
46 #define LSR_PE   0x04  /* Parity error */
47 #define LSR_FE   0x08  /* Framing error */
48 #define LSR_BI   0x10  /* Break */
49 #define LSR_THRE 0x20  /* Xmit holding register empty */
50 #define LSR_TEMT 0x40  /* Xmitter empty */
51 #define LSR_ERR  0x80  /* Error */
52
53 volatile struct NS16550 *udbg_comport;
54
55 void
56 udbg_init_uart(void *comport)
57 {
58         if (comport) {
59                 udbg_comport = (struct NS16550 *)comport;
60                 udbg_comport->lcr = 0x00; eieio();
61                 udbg_comport->ier = 0xFF; eieio();
62                 udbg_comport->ier = 0x00; eieio();
63                 udbg_comport->lcr = 0x80; eieio();      /* Access baud rate */
64                 udbg_comport->dll = 12;   eieio();      /* 1 = 115200,  2 = 57600, 3 = 38400, 12 = 9600 baud */
65                 udbg_comport->dlm = 0;    eieio();      /* dll >> 8 which should be zero for fast rates; */
66                 udbg_comport->lcr = 0x03; eieio();      /* 8 data, 1 stop, no parity */
67                 udbg_comport->mcr = 0x03; eieio();      /* RTS/DTR */
68                 udbg_comport->fcr = 0x07; eieio();      /* Clear & enable FIFOs */
69         }
70 }
71
72 void
73 udbg_putc(unsigned char c)
74 {
75         if ( udbg_comport ) {
76                 while ((udbg_comport->lsr & LSR_THRE) == 0)
77                         /* wait for idle */;
78                 udbg_comport->thr = c; eieio();
79                 if (c == '\n') {
80                         /* Also put a CR.  This is for convenience. */
81                         while ((udbg_comport->lsr & LSR_THRE) == 0)
82                                 /* wait for idle */;
83                         udbg_comport->thr = '\r'; eieio();
84                 }
85         } else if (systemcfg->platform == PLATFORM_ISERIES_LPAR) {
86                 /* ToDo: switch this via ppc_md */
87                 printk("%c", c);
88         }
89 }
90
91 int udbg_getc_poll(void)
92 {
93         if (udbg_comport) {
94                 if ((udbg_comport->lsr & LSR_DR) != 0)
95                         return udbg_comport->rbr;
96                 else
97                         return -1;
98         }
99         return -1;
100 }
101
102 unsigned char
103 udbg_getc(void)
104 {
105         if ( udbg_comport ) {
106                 while ((udbg_comport->lsr & LSR_DR) == 0)
107                         /* wait for char */;
108                 return udbg_comport->rbr;
109         }
110         return 0;
111 }
112
113 void
114 udbg_puts(const char *s)
115 {
116         if (ppc_md.udbg_putc) {
117                 char c;
118
119                 if (s && *s != '\0') {
120                         while ((c = *s++) != '\0')
121                                 ppc_md.udbg_putc(c);
122                 }
123         } else {
124                 printk("%s", s);
125         }
126 }
127
128 int
129 udbg_write(const char *s, int n)
130 {
131         int remain = n;
132         char c;
133         if (!ppc_md.udbg_putc)
134                 for (;;);       /* stop here for cpuctl */
135         if ( s && *s != '\0' ) {
136                 while ( (( c = *s++ ) != '\0') && (remain-- > 0)) {
137                         ppc_md.udbg_putc(c);
138                 }
139         }
140         return n - remain;
141 }
142
143 int
144 udbg_read(char *buf, int buflen) {
145         char c, *p = buf;
146         int i;
147         if (!ppc_md.udbg_putc)
148                 for (;;);       /* stop here for cpuctl */
149         for (i = 0; i < buflen; ++i) {
150                 do {
151                         c = ppc_md.udbg_getc();
152                 } while (c == 0x11 || c == 0x13);
153                 *p++ = c;
154         }
155         return i;
156 }
157
158 void
159 udbg_console_write(struct console *con, const char *s, unsigned int n)
160 {
161         udbg_write(s, n);
162 }
163
164 void
165 udbg_puthex(unsigned long val)
166 {
167         int i, nibbles = sizeof(val)*2;
168         unsigned char buf[sizeof(val)*2+1];
169         for (i = nibbles-1;  i >= 0;  i--) {
170                 buf[i] = (val & 0xf) + '0';
171                 if (buf[i] > '9')
172                     buf[i] += ('a'-'0'-10);
173                 val >>= 4;
174         }
175         buf[nibbles] = '\0';
176         udbg_puts(buf);
177 }
178
179 void
180 udbg_printSP(const char *s)
181 {
182         if (systemcfg->platform == PLATFORM_PSERIES) {
183                 unsigned long sp;
184                 asm("mr %0,1" : "=r" (sp) :);
185                 if (s)
186                         udbg_puts(s);
187                 udbg_puthex(sp);
188         }
189 }
190
191 void
192 udbg_printf(const char *fmt, ...)
193 {
194         unsigned char buf[256];
195
196         va_list args;
197         va_start(args, fmt);
198
199         vsprintf(buf, fmt, args);
200         udbg_puts(buf);
201
202         va_end(args);
203 }
204
205 /* Special print used by PPCDBG() macro */
206 void
207 udbg_ppcdbg(unsigned long debug_flags, const char *fmt, ...)
208 {
209         unsigned long active_debugs = debug_flags & naca->debug_switch;
210
211         if ( active_debugs ) {
212                 va_list ap;
213                 unsigned char buf[256];
214                 unsigned long i, len = 0;
215
216                 for(i=0; i < PPCDBG_NUM_FLAGS ;i++) {
217                         if (((1U << i) & active_debugs) && 
218                             trace_names[i]) {
219                                 len += strlen(trace_names[i]); 
220                                 udbg_puts(trace_names[i]);
221                                 break;
222                         }
223                 }
224                 sprintf(buf, " [%s]: ", current->comm);
225                 len += strlen(buf); 
226                 udbg_puts(buf);
227
228                 while(len < 18) {
229                         udbg_puts(" ");
230                         len++;
231                 }
232
233                 va_start(ap, fmt);
234                 vsprintf(buf, fmt, ap);
235                 udbg_puts(buf);
236                 
237                 va_end(ap);
238         }
239 }
240
241 unsigned long
242 udbg_ifdebug(unsigned long flags)
243 {
244         return (flags & naca->debug_switch);
245 }