Merge branch 'upstream-fixes' of master.kernel.org:/pub/scm/linux/kernel/git/jgarzik...
[linux-2.6] / arch / ppc / xmon / start.c
1 /*
2  * Copyright (C) 1996 Paul Mackerras.
3  */
4 #include <linux/config.h>
5 #include <linux/string.h>
6 #include <asm/machdep.h>
7 #include <asm/io.h>
8 #include <asm/page.h>
9 #include <linux/adb.h>
10 #include <linux/pmu.h>
11 #include <linux/cuda.h>
12 #include <linux/kernel.h>
13 #include <linux/errno.h>
14 #include <linux/sysrq.h>
15 #include <linux/bitops.h>
16 #include <asm/xmon.h>
17 #include <asm/prom.h>
18 #include <asm/bootx.h>
19 #include <asm/machdep.h>
20 #include <asm/errno.h>
21 #include <asm/processor.h>
22 #include <asm/delay.h>
23 #include <asm/btext.h>
24
25 static volatile unsigned char *sccc, *sccd;
26 unsigned int TXRDY, RXRDY, DLAB;
27 static int xmon_expect(const char *str, unsigned int timeout);
28
29 static int use_screen;
30 static int via_modem;
31 static int xmon_use_sccb;
32
33 #define TB_SPEED        25000000
34
35 static inline unsigned int readtb(void)
36 {
37         unsigned int ret;
38
39         asm volatile("mftb %0" : "=r" (ret) :);
40         return ret;
41 }
42
43 void buf_access(void)
44 {
45         if (DLAB)
46                 sccd[3] &= ~DLAB;       /* reset DLAB */
47 }
48
49 extern int adb_init(void);
50
51 #ifdef CONFIG_PPC_CHRP
52 /*
53  * This looks in the "ranges" property for the primary PCI host bridge
54  * to find the physical address of the start of PCI/ISA I/O space.
55  * It is basically a cut-down version of pci_process_bridge_OF_ranges.
56  */
57 static unsigned long chrp_find_phys_io_base(void)
58 {
59         struct device_node *node;
60         unsigned int *ranges;
61         unsigned long base = CHRP_ISA_IO_BASE;
62         int rlen = 0;
63         int np;
64
65         node = find_devices("isa");
66         if (node != NULL) {
67                 node = node->parent;
68                 if (node == NULL || node->type == NULL
69                     || strcmp(node->type, "pci") != 0)
70                         node = NULL;
71         }
72         if (node == NULL)
73                 node = find_devices("pci");
74         if (node == NULL)
75                 return base;
76
77         ranges = (unsigned int *) get_property(node, "ranges", &rlen);
78         np = prom_n_addr_cells(node) + 5;
79         while ((rlen -= np * sizeof(unsigned int)) >= 0) {
80                 if ((ranges[0] >> 24) == 1 && ranges[2] == 0) {
81                         /* I/O space starting at 0, grab the phys base */
82                         base = ranges[np - 3];
83                         break;
84                 }
85                 ranges += np;
86         }
87         return base;
88 }
89 #endif /* CONFIG_PPC_CHRP */
90
91 #ifdef CONFIG_MAGIC_SYSRQ
92 static void sysrq_handle_xmon(int key, struct pt_regs *regs,
93                               struct tty_struct *tty)
94 {
95         xmon(regs);
96 }
97
98 static struct sysrq_key_op sysrq_xmon_op =
99 {
100         .handler =      sysrq_handle_xmon,
101         .help_msg =     "Xmon",
102         .action_msg =   "Entering xmon",
103 };
104 #endif
105
106 void
107 xmon_map_scc(void)
108 {
109 #ifdef CONFIG_PPC_MULTIPLATFORM
110         volatile unsigned char *base;
111
112 #ifdef CONFIG_PPC_CHRP
113         base = (volatile unsigned char *) isa_io_base;
114         if (_machine == _MACH_chrp)
115                 base = (volatile unsigned char *)
116                         ioremap(chrp_find_phys_io_base(), 0x1000);
117
118         sccc = base + 0x3fd;
119         sccd = base + 0x3f8;
120         if (xmon_use_sccb) {
121                 sccc -= 0x100;
122                 sccd -= 0x100;
123         }
124         TXRDY = 0x20;
125         RXRDY = 1;
126         DLAB = 0x80;
127 #endif /* CONFIG_PPC_CHRP */
128 #elif defined(CONFIG_GEMINI)
129         /* should already be mapped by the kernel boot */
130         sccc = (volatile unsigned char *) 0xffeffb0d;
131         sccd = (volatile unsigned char *) 0xffeffb08;
132         TXRDY = 0x20;
133         RXRDY = 1;
134         DLAB = 0x80;
135 #elif defined(CONFIG_405GP)
136         sccc = (volatile unsigned char *)0xef600305;
137         sccd = (volatile unsigned char *)0xef600300;
138         TXRDY = 0x20;
139         RXRDY = 1;
140         DLAB = 0x80;
141 #endif /* platform */
142
143         register_sysrq_key('x', &sysrq_xmon_op);
144 }
145
146 static int scc_initialized = 0;
147
148 void xmon_init_scc(void);
149
150 int
151 xmon_write(void *handle, void *ptr, int nb)
152 {
153         char *p = ptr;
154         int i, c, ct;
155
156 #ifdef CONFIG_SMP
157         static unsigned long xmon_write_lock;
158         int lock_wait = 1000000;
159         int locked;
160
161         while ((locked = test_and_set_bit(0, &xmon_write_lock)) != 0)
162                 if (--lock_wait == 0)
163                         break;
164 #endif
165
166 #ifdef CONFIG_BOOTX_TEXT
167         if (use_screen) {
168                 /* write it on the screen */
169                 for (i = 0; i < nb; ++i)
170                         btext_drawchar(*p++);
171                 goto out;
172         }
173 #endif
174         if (!scc_initialized)
175                 xmon_init_scc();
176         ct = 0;
177         for (i = 0; i < nb; ++i) {
178                 while ((*sccc & TXRDY) == 0)
179                         ;
180                 c = p[i];
181                 if (c == '\n' && !ct) {
182                         c = '\r';
183                         ct = 1;
184                         --i;
185                 } else {
186                         ct = 0;
187                 }
188                 buf_access();
189                 *sccd = c;
190                 eieio();
191         }
192
193  out:
194 #ifdef CONFIG_SMP
195         if (!locked)
196                 clear_bit(0, &xmon_write_lock);
197 #endif
198         return nb;
199 }
200
201 int xmon_wants_key;
202 int xmon_adb_keycode;
203
204 #ifdef CONFIG_BOOTX_TEXT
205 static int xmon_adb_shiftstate;
206
207 static unsigned char xmon_keytab[128] =
208         "asdfhgzxcv\000bqwer"                           /* 0x00 - 0x0f */
209         "yt123465=97-80]o"                              /* 0x10 - 0x1f */
210         "u[ip\rlj'k;\\,/nm."                            /* 0x20 - 0x2f */
211         "\t `\177\0\033\0\0\0\0\0\0\0\0\0\0"            /* 0x30 - 0x3f */
212         "\0.\0*\0+\0\0\0\0\0/\r\0-\0"                   /* 0x40 - 0x4f */
213         "\0\0000123456789\0\0\0";                       /* 0x50 - 0x5f */
214
215 static unsigned char xmon_shift_keytab[128] =
216         "ASDFHGZXCV\000BQWER"                           /* 0x00 - 0x0f */
217         "YT!@#$^%+(&_*)}O"                              /* 0x10 - 0x1f */
218         "U{IP\rLJ\"K:|<?NM>"                            /* 0x20 - 0x2f */
219         "\t ~\177\0\033\0\0\0\0\0\0\0\0\0\0"            /* 0x30 - 0x3f */
220         "\0.\0*\0+\0\0\0\0\0/\r\0-\0"                   /* 0x40 - 0x4f */
221         "\0\0000123456789\0\0\0";                       /* 0x50 - 0x5f */
222
223 static int
224 xmon_get_adb_key(void)
225 {
226         int k, t, on;
227
228         xmon_wants_key = 1;
229         for (;;) {
230                 xmon_adb_keycode = -1;
231                 t = 0;
232                 on = 0;
233                 do {
234                         if (--t < 0) {
235                                 on = 1 - on;
236                                 btext_drawchar(on? 0xdb: 0x20);
237                                 btext_drawchar('\b');
238                                 t = 200000;
239                         }
240                         do_poll_adb();
241                 } while (xmon_adb_keycode == -1);
242                 k = xmon_adb_keycode;
243                 if (on)
244                         btext_drawstring(" \b");
245
246                 /* test for shift keys */
247                 if ((k & 0x7f) == 0x38 || (k & 0x7f) == 0x7b) {
248                         xmon_adb_shiftstate = (k & 0x80) == 0;
249                         continue;
250                 }
251                 if (k >= 0x80)
252                         continue;       /* ignore up transitions */
253                 k = (xmon_adb_shiftstate? xmon_shift_keytab: xmon_keytab)[k];
254                 if (k != 0)
255                         break;
256         }
257         xmon_wants_key = 0;
258         return k;
259 }
260 #endif /* CONFIG_BOOTX_TEXT */
261
262 int
263 xmon_read(void *handle, void *ptr, int nb)
264 {
265     char *p = ptr;
266     int i;
267
268 #ifdef CONFIG_BOOTX_TEXT
269     if (use_screen) {
270         for (i = 0; i < nb; ++i)
271             *p++ = xmon_get_adb_key();
272         return i;
273     }
274 #endif
275     if (!scc_initialized)
276         xmon_init_scc();
277     for (i = 0; i < nb; ++i) {
278         while ((*sccc & RXRDY) == 0)
279             do_poll_adb();
280         buf_access();
281         *p++ = *sccd;
282     }
283     return i;
284 }
285
286 int
287 xmon_read_poll(void)
288 {
289         if ((*sccc & RXRDY) == 0) {
290                 do_poll_adb();
291                 return -1;
292         }
293         buf_access();
294         return *sccd;
295 }
296
297 void
298 xmon_init_scc(void)
299 {
300         if ( _machine == _MACH_chrp )
301         {
302                 sccd[3] = 0x83; eieio();        /* LCR = 8N1 + DLAB */
303                 sccd[0] = 12; eieio();          /* DLL = 9600 baud */
304                 sccd[1] = 0; eieio();
305                 sccd[2] = 0; eieio();           /* FCR = 0 */
306                 sccd[3] = 3; eieio();           /* LCR = 8N1 */
307                 sccd[1] = 0; eieio();           /* IER = 0 */
308         }
309         scc_initialized = 1;
310         if (via_modem) {
311                 for (;;) {
312                         xmon_write(NULL, "ATE1V1\r", 7);
313                         if (xmon_expect("OK", 5)) {
314                                 xmon_write(NULL, "ATA\r", 4);
315                                 if (xmon_expect("CONNECT", 40))
316                                         break;
317                         }
318                         xmon_write(NULL, "+++", 3);
319                         xmon_expect("OK", 3);
320                 }
321         }
322 }
323
324 #if 0
325 extern int (*prom_entry)(void *);
326
327 int
328 xmon_exit(void)
329 {
330     struct prom_args {
331         char *service;
332     } args;
333
334     for (;;) {
335         args.service = "exit";
336         (*prom_entry)(&args);
337     }
338 }
339 #endif
340
341 void *xmon_stdin;
342 void *xmon_stdout;
343 void *xmon_stderr;
344
345 void
346 xmon_init(int arg)
347 {
348         xmon_map_scc();
349 }
350
351 int
352 xmon_putc(int c, void *f)
353 {
354     char ch = c;
355
356     if (c == '\n')
357         xmon_putc('\r', f);
358     return xmon_write(f, &ch, 1) == 1? c: -1;
359 }
360
361 int
362 xmon_putchar(int c)
363 {
364     return xmon_putc(c, xmon_stdout);
365 }
366
367 int
368 xmon_fputs(char *str, void *f)
369 {
370     int n = strlen(str);
371
372     return xmon_write(f, str, n) == n? 0: -1;
373 }
374
375 int
376 xmon_readchar(void)
377 {
378     char ch;
379
380     for (;;) {
381         switch (xmon_read(xmon_stdin, &ch, 1)) {
382         case 1:
383             return ch;
384         case -1:
385             xmon_printf("read(stdin) returned -1\r\n", 0, 0);
386             return -1;
387         }
388     }
389 }
390
391 static char line[256];
392 static char *lineptr;
393 static int lineleft;
394
395 int xmon_expect(const char *str, unsigned int timeout)
396 {
397         int c;
398         unsigned int t0;
399
400         timeout *= TB_SPEED;
401         t0 = readtb();
402         do {
403                 lineptr = line;
404                 for (;;) {
405                         c = xmon_read_poll();
406                         if (c == -1) {
407                                 if (readtb() - t0 > timeout)
408                                         return 0;
409                                 continue;
410                         }
411                         if (c == '\n')
412                                 break;
413                         if (c != '\r' && lineptr < &line[sizeof(line) - 1])
414                                 *lineptr++ = c;
415                 }
416                 *lineptr = 0;
417         } while (strstr(line, str) == NULL);
418         return 1;
419 }
420
421 int
422 xmon_getchar(void)
423 {
424     int c;
425
426     if (lineleft == 0) {
427         lineptr = line;
428         for (;;) {
429             c = xmon_readchar();
430             if (c == -1 || c == 4)
431                 break;
432             if (c == '\r' || c == '\n') {
433                 *lineptr++ = '\n';
434                 xmon_putchar('\n');
435                 break;
436             }
437             switch (c) {
438             case 0177:
439             case '\b':
440                 if (lineptr > line) {
441                     xmon_putchar('\b');
442                     xmon_putchar(' ');
443                     xmon_putchar('\b');
444                     --lineptr;
445                 }
446                 break;
447             case 'U' & 0x1F:
448                 while (lineptr > line) {
449                     xmon_putchar('\b');
450                     xmon_putchar(' ');
451                     xmon_putchar('\b');
452                     --lineptr;
453                 }
454                 break;
455             default:
456                 if (lineptr >= &line[sizeof(line) - 1])
457                     xmon_putchar('\a');
458                 else {
459                     xmon_putchar(c);
460                     *lineptr++ = c;
461                 }
462             }
463         }
464         lineleft = lineptr - line;
465         lineptr = line;
466     }
467     if (lineleft == 0)
468         return -1;
469     --lineleft;
470     return *lineptr++;
471 }
472
473 char *
474 xmon_fgets(char *str, int nb, void *f)
475 {
476     char *p;
477     int c;
478
479     for (p = str; p < str + nb - 1; ) {
480         c = xmon_getchar();
481         if (c == -1) {
482             if (p == str)
483                 return NULL;
484             break;
485         }
486         *p++ = c;
487         if (c == '\n')
488             break;
489     }
490     *p = 0;
491     return str;
492 }
493
494 void
495 xmon_enter(void)
496 {
497 }
498
499 void
500 xmon_leave(void)
501 {
502 }