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 <asm/prom.h>
16 #include <asm/bootx.h>
17 #include <asm/machdep.h>
18 #include <asm/errno.h>
19 #include <asm/pmac_feature.h>
20 #include <asm/processor.h>
21 #include <asm/delay.h>
22 #include <asm/btext.h>
23 #ifdef CONFIG_SMP
24 #include <asm/bitops.h>
25 #endif
26
27 static volatile unsigned char *sccc, *sccd;
28 unsigned int TXRDY, RXRDY, DLAB;
29 extern void xmon_printf(const char *fmt, ...);
30 static int xmon_expect(const char *str, unsigned int timeout);
31
32 static int use_screen;
33 static int via_modem;
34 static int xmon_use_sccb;
35 static struct device_node *channel_node;
36
37 #define TB_SPEED 25000000
38
readtb(void)39 static inline unsigned int readtb(void)
40 {
41 unsigned int ret;
42
43 asm volatile("mftb %0" : "=r" (ret) :);
44 return ret;
45 }
46
buf_access(void)47 void buf_access(void)
48 {
49 if (DLAB)
50 sccd[3] &= ~DLAB; /* reset DLAB */
51 }
52
53 extern int adb_init(void);
54
55 #ifdef CONFIG_ALL_PPC
56 /*
57 * This looks in the "ranges" property for the primary PCI host bridge
58 * to find the physical address of the start of PCI/ISA I/O space.
59 * It is basically a cut-down version of pci_process_bridge_OF_ranges.
60 */
chrp_find_phys_io_base(void)61 static unsigned long chrp_find_phys_io_base(void)
62 {
63 struct device_node *node;
64 unsigned int *ranges;
65 unsigned long base = CHRP_ISA_IO_BASE;
66 int rlen = 0;
67 int np;
68
69 node = find_devices("isa");
70 if (node != NULL) {
71 node = node->parent;
72 if (node == NULL || node->type == NULL
73 || strcmp(node->type, "pci") != 0)
74 node = NULL;
75 }
76 if (node == NULL)
77 node = find_devices("pci");
78 if (node == NULL)
79 return base;
80
81 ranges = (unsigned int *) get_property(node, "ranges", &rlen);
82 np = prom_n_addr_cells(node) + 5;
83 while ((rlen -= np * sizeof(unsigned int)) >= 0) {
84 if ((ranges[0] >> 24) == 1 && ranges[2] == 0) {
85 /* I/O space starting at 0, grab the phys base */
86 base = ranges[np - 3];
87 break;
88 }
89 ranges += np;
90 }
91 return base;
92 }
93 #endif /* CONFIG_ALL_PPC */
94
sysrq_handle_xmon(int key,struct pt_regs * regs,struct kbd_struct * kbd,struct tty_struct * tty)95 static void sysrq_handle_xmon(int key, struct pt_regs *regs,
96 struct kbd_struct *kbd, struct tty_struct *tty)
97 {
98 xmon(regs);
99 }
100
101 static struct sysrq_key_op sysrq_xmon_op =
102 {
103 handler: sysrq_handle_xmon,
104 help_msg: "Xmon",
105 action_msg: "Entering xmon\n",
106 };
107
108 void
xmon_map_scc(void)109 xmon_map_scc(void)
110 {
111 #ifdef CONFIG_ALL_PPC
112 volatile unsigned char *base;
113
114 use_screen = 0;
115
116 if (_machine == _MACH_Pmac) {
117 struct device_node *np;
118 unsigned long addr;
119 #ifdef CONFIG_BOOTX_TEXT
120 if (!machine_is_compatible("iMac")) {
121 /* see if there is a keyboard in the device tree
122 with a parent of type "adb" */
123 for (np = find_devices("keyboard"); np; np = np->next)
124 if (np->parent && np->parent->type
125 && strcmp(np->parent->type, "adb") == 0)
126 break;
127
128 /* needs to be hacked if xmon_printk is to be used
129 from within find_via_pmu() */
130 #ifdef CONFIG_ADB_PMU
131 if (np != NULL && boot_text_mapped && find_via_pmu())
132 use_screen = 1;
133 #endif
134 #ifdef CONFIG_ADB_CUDA
135 if (np != NULL && boot_text_mapped && find_via_cuda())
136 use_screen = 1;
137 #endif
138 }
139 if (!use_screen && (np = find_devices("escc")) != NULL) {
140 /*
141 * look for the device node for the serial port
142 * we're using and see if it says it has a modem
143 */
144 char *name = xmon_use_sccb? "ch-b": "ch-a";
145 char *slots;
146 int l;
147
148 np = np->child;
149 while (np != NULL && strcmp(np->name, name) != 0)
150 np = np->sibling;
151 if (np != NULL) {
152 /* XXX should parse this properly */
153 channel_node = np;
154 slots = get_property(np, "slot-names", &l);
155 if (slots != NULL && l >= 10
156 && strcmp(slots+4, "Modem") == 0)
157 via_modem = 1;
158 }
159 }
160 btext_drawstring("xmon uses ");
161 if (use_screen)
162 btext_drawstring("screen and keyboard\n");
163 else {
164 if (via_modem)
165 btext_drawstring("modem on ");
166 btext_drawstring(xmon_use_sccb? "printer": "modem");
167 btext_drawstring(" port\n");
168 }
169
170 #endif /* CONFIG_BOOTX_TEXT */
171
172 #ifdef CHRP_ESCC
173 addr = 0xc1013020;
174 #else
175 addr = 0xf3013020;
176 #endif
177 TXRDY = 4;
178 RXRDY = 1;
179
180 np = find_devices("mac-io");
181 if (np && np->n_addrs)
182 addr = np->addrs[0].address + 0x13020;
183 base = (volatile unsigned char *) ioremap(addr & PAGE_MASK, PAGE_SIZE);
184 sccc = base + (addr & ~PAGE_MASK);
185 sccd = sccc + 0x10;
186
187 } else {
188 base = (volatile unsigned char *) isa_io_base;
189 if (_machine == _MACH_chrp)
190 base = (volatile unsigned char *)
191 ioremap(chrp_find_phys_io_base(), 0x1000);
192
193 sccc = base + 0x3fd;
194 sccd = base + 0x3f8;
195 if (xmon_use_sccb) {
196 sccc -= 0x100;
197 sccd -= 0x100;
198 }
199 TXRDY = 0x20;
200 RXRDY = 1;
201 DLAB = 0x80;
202 }
203 #elif defined(CONFIG_GEMINI)
204 /* should already be mapped by the kernel boot */
205 sccc = (volatile unsigned char *) 0xffeffb0d;
206 sccd = (volatile unsigned char *) 0xffeffb08;
207 TXRDY = 0x20;
208 RXRDY = 1;
209 DLAB = 0x80;
210 #elif defined(CONFIG_405GP) || defined(CONFIG_405LP) || defined(CONFIG_405EP)
211 sccc = (volatile unsigned char *)0xef600305;
212 sccd = (volatile unsigned char *)0xef600300;
213 TXRDY = 0x20;
214 RXRDY = 1;
215 DLAB = 0x80;
216 #endif /* platform */
217
218 __sysrq_put_key_op('x', &sysrq_xmon_op);
219 }
220
221 static int scc_initialized = 0;
222
223 void xmon_init_scc(void);
224 extern void pmu_poll(void);
225 extern void cuda_poll(void);
226
do_poll_adb(void)227 static inline void do_poll_adb(void)
228 {
229 #ifdef CONFIG_ADB_PMU
230 if (sys_ctrler == SYS_CTRLER_PMU)
231 pmu_poll();
232 #endif /* CONFIG_ADB_PMU */
233 #ifdef CONFIG_ADB_CUDA
234 if (sys_ctrler == SYS_CTRLER_CUDA)
235 cuda_poll();
236 #endif /* CONFIG_ADB_CUDA */
237 }
238
239 int
xmon_write(void * handle,void * ptr,int nb)240 xmon_write(void *handle, void *ptr, int nb)
241 {
242 char *p = ptr;
243 int i, c, ct;
244
245 #ifdef CONFIG_SMP
246 static unsigned long xmon_write_lock;
247 int lock_wait = 1000000;
248 int locked;
249
250 while ((locked = test_and_set_bit(0, &xmon_write_lock)) != 0)
251 if (--lock_wait == 0)
252 break;
253 #endif
254
255 #ifdef CONFIG_BOOTX_TEXT
256 if (use_screen) {
257 /* write it on the screen */
258 for (i = 0; i < nb; ++i)
259 btext_drawchar(*p++);
260 goto out;
261 }
262 #endif
263 if (!scc_initialized)
264 xmon_init_scc();
265 ct = 0;
266 for (i = 0; i < nb; ++i) {
267 while ((*sccc & TXRDY) == 0)
268 do_poll_adb();
269 c = p[i];
270 if (c == '\n' && !ct) {
271 c = '\r';
272 ct = 1;
273 --i;
274 } else {
275 ct = 0;
276 }
277 buf_access();
278 *sccd = c;
279 eieio();
280 }
281
282 out:
283 #ifdef CONFIG_SMP
284 if (!locked)
285 clear_bit(0, &xmon_write_lock);
286 #endif
287 return nb;
288 }
289
290 int xmon_wants_key;
291 int xmon_adb_keycode;
292
293 #ifdef CONFIG_BOOTX_TEXT
294 static int xmon_adb_shiftstate;
295
296 static unsigned char xmon_keytab[128] =
297 "asdfhgzxcv\000bqwer" /* 0x00 - 0x0f */
298 "yt123465=97-80]o" /* 0x10 - 0x1f */
299 "u[ip\rlj'k;\\,/nm." /* 0x20 - 0x2f */
300 "\t `\177\0\033\0\0\0\0\0\0\0\0\0\0" /* 0x30 - 0x3f */
301 "\0.\0*\0+\0\0\0\0\0/\r\0-\0" /* 0x40 - 0x4f */
302 "\0\0000123456789\0\0\0"; /* 0x50 - 0x5f */
303
304 static unsigned char xmon_shift_keytab[128] =
305 "ASDFHGZXCV\000BQWER" /* 0x00 - 0x0f */
306 "YT!@#$^%+(&_*)}O" /* 0x10 - 0x1f */
307 "U{IP\rLJ\"K:|<?NM>" /* 0x20 - 0x2f */
308 "\t ~\177\0\033\0\0\0\0\0\0\0\0\0\0" /* 0x30 - 0x3f */
309 "\0.\0*\0+\0\0\0\0\0/\r\0-\0" /* 0x40 - 0x4f */
310 "\0\0000123456789\0\0\0"; /* 0x50 - 0x5f */
311
312 static int
xmon_get_adb_key(void)313 xmon_get_adb_key(void)
314 {
315 int k, t, on;
316
317 xmon_wants_key = 1;
318 for (;;) {
319 xmon_adb_keycode = -1;
320 t = 0;
321 on = 0;
322 do {
323 if (--t < 0) {
324 on = 1 - on;
325 btext_drawchar(on? 0xdb: 0x20);
326 btext_drawchar('\b');
327 t = 200000;
328 }
329 do_poll_adb();
330 } while (xmon_adb_keycode == -1);
331 k = xmon_adb_keycode;
332 if (on)
333 btext_drawstring(" \b");
334
335 /* test for shift keys */
336 if ((k & 0x7f) == 0x38 || (k & 0x7f) == 0x7b) {
337 xmon_adb_shiftstate = (k & 0x80) == 0;
338 continue;
339 }
340 if (k >= 0x80)
341 continue; /* ignore up transitions */
342 k = (xmon_adb_shiftstate? xmon_shift_keytab: xmon_keytab)[k];
343 if (k != 0)
344 break;
345 }
346 xmon_wants_key = 0;
347 return k;
348 }
349 #endif /* CONFIG_BOOTX_TEXT */
350
351 int
xmon_read(void * handle,void * ptr,int nb)352 xmon_read(void *handle, void *ptr, int nb)
353 {
354 char *p = ptr;
355 int i;
356
357 #ifdef CONFIG_BOOTX_TEXT
358 if (use_screen) {
359 for (i = 0; i < nb; ++i)
360 *p++ = xmon_get_adb_key();
361 return i;
362 }
363 #endif
364 if (!scc_initialized)
365 xmon_init_scc();
366 for (i = 0; i < nb; ++i) {
367 while ((*sccc & RXRDY) == 0)
368 do_poll_adb();
369 buf_access();
370 *p++ = *sccd;
371 }
372 return i;
373 }
374
375 int
xmon_read_poll(void)376 xmon_read_poll(void)
377 {
378 if ((*sccc & RXRDY) == 0) {
379 do_poll_adb();
380 return -1;
381 }
382 buf_access();
383 return *sccd;
384 }
385
386 static unsigned char scc_inittab[] = {
387 13, 0, /* set baud rate divisor */
388 12, 1,
389 14, 1, /* baud rate gen enable, src=rtxc */
390 11, 0x50, /* clocks = br gen */
391 5, 0xea, /* tx 8 bits, assert DTR & RTS */
392 4, 0x46, /* x16 clock, 1 stop */
393 3, 0xc1, /* rx enable, 8 bits */
394 };
395
396 void
xmon_init_scc()397 xmon_init_scc()
398 {
399 if ( _machine == _MACH_chrp )
400 {
401 sccd[3] = 0x83; eieio(); /* LCR = 8N1 + DLAB */
402 sccd[0] = 12; eieio(); /* DLL = 9600 baud */
403 sccd[1] = 0; eieio();
404 sccd[2] = 0; eieio(); /* FCR = 0 */
405 sccd[3] = 3; eieio(); /* LCR = 8N1 */
406 sccd[1] = 0; eieio(); /* IER = 0 */
407 }
408 else if ( _machine == _MACH_Pmac )
409 {
410 int i, x;
411
412 if (channel_node != 0)
413 pmac_call_feature(
414 PMAC_FTR_SCC_ENABLE,
415 channel_node,
416 PMAC_SCC_ASYNC | PMAC_SCC_FLAG_XMON, 1);
417 printk(KERN_INFO "Serial port locked ON by debugger !\n");
418 if (via_modem && channel_node != 0) {
419 unsigned int t0;
420
421 pmac_call_feature(
422 PMAC_FTR_MODEM_ENABLE,
423 channel_node, 0, 1);
424 printk(KERN_INFO "Modem powered up by debugger !\n");
425 t0 = readtb();
426 while (readtb() - t0 < 3*TB_SPEED)
427 eieio();
428 }
429 /* use the B channel if requested */
430 if (xmon_use_sccb) {
431 sccc = (volatile unsigned char *)
432 ((unsigned long)sccc & ~0x20);
433 sccd = sccc + 0x10;
434 }
435 for (i = 20000; i != 0; --i) {
436 x = *sccc; eieio();
437 }
438 *sccc = 9; eieio(); /* reset A or B side */
439 *sccc = ((unsigned long)sccc & 0x20)? 0x80: 0x40; eieio();
440 for (i = 0; i < sizeof(scc_inittab); ++i) {
441 *sccc = scc_inittab[i];
442 eieio();
443 }
444 }
445 scc_initialized = 1;
446 if (via_modem) {
447 for (;;) {
448 xmon_write(0, "ATE1V1\r", 7);
449 if (xmon_expect("OK", 5)) {
450 xmon_write(0, "ATA\r", 4);
451 if (xmon_expect("CONNECT", 40))
452 break;
453 }
454 xmon_write(0, "+++", 3);
455 xmon_expect("OK", 3);
456 }
457 }
458 }
459
460 #if 0
461 extern int (*prom_entry)(void *);
462
463 int
464 xmon_exit(void)
465 {
466 struct prom_args {
467 char *service;
468 } args;
469
470 for (;;) {
471 args.service = "exit";
472 (*prom_entry)(&args);
473 }
474 }
475 #endif
476
477 void *xmon_stdin;
478 void *xmon_stdout;
479 void *xmon_stderr;
480
481 void
xmon_init(void)482 xmon_init(void)
483 {
484 }
485
486 int
xmon_putc(int c,void * f)487 xmon_putc(int c, void *f)
488 {
489 char ch = c;
490
491 if (c == '\n')
492 xmon_putc('\r', f);
493 return xmon_write(f, &ch, 1) == 1? c: -1;
494 }
495
496 int
xmon_putchar(int c)497 xmon_putchar(int c)
498 {
499 return xmon_putc(c, xmon_stdout);
500 }
501
502 int
xmon_fputs(char * str,void * f)503 xmon_fputs(char *str, void *f)
504 {
505 int n = strlen(str);
506
507 return xmon_write(f, str, n) == n? 0: -1;
508 }
509
510 int
xmon_readchar(void)511 xmon_readchar(void)
512 {
513 char ch;
514
515 for (;;) {
516 switch (xmon_read(xmon_stdin, &ch, 1)) {
517 case 1:
518 return ch;
519 case -1:
520 xmon_printf("read(stdin) returned -1\r\n", 0, 0);
521 return -1;
522 }
523 }
524 }
525
526 static char line[256];
527 static char *lineptr;
528 static int lineleft;
529
xmon_expect(const char * str,unsigned int timeout)530 int xmon_expect(const char *str, unsigned int timeout)
531 {
532 int c;
533 unsigned int t0;
534
535 timeout *= TB_SPEED;
536 t0 = readtb();
537 do {
538 lineptr = line;
539 for (;;) {
540 c = xmon_read_poll();
541 if (c == -1) {
542 if (readtb() - t0 > timeout)
543 return 0;
544 continue;
545 }
546 if (c == '\n')
547 break;
548 if (c != '\r' && lineptr < &line[sizeof(line) - 1])
549 *lineptr++ = c;
550 }
551 *lineptr = 0;
552 } while (strstr(line, str) == NULL);
553 return 1;
554 }
555
556 int
xmon_getchar(void)557 xmon_getchar(void)
558 {
559 int c;
560
561 if (lineleft == 0) {
562 lineptr = line;
563 for (;;) {
564 c = xmon_readchar();
565 if (c == -1 || c == 4)
566 break;
567 if (c == '\r' || c == '\n') {
568 *lineptr++ = '\n';
569 xmon_putchar('\n');
570 break;
571 }
572 switch (c) {
573 case 0177:
574 case '\b':
575 if (lineptr > line) {
576 xmon_putchar('\b');
577 xmon_putchar(' ');
578 xmon_putchar('\b');
579 --lineptr;
580 }
581 break;
582 case 'U' & 0x1F:
583 while (lineptr > line) {
584 xmon_putchar('\b');
585 xmon_putchar(' ');
586 xmon_putchar('\b');
587 --lineptr;
588 }
589 break;
590 default:
591 if (lineptr >= &line[sizeof(line) - 1])
592 xmon_putchar('\a');
593 else {
594 xmon_putchar(c);
595 *lineptr++ = c;
596 }
597 }
598 }
599 lineleft = lineptr - line;
600 lineptr = line;
601 }
602 if (lineleft == 0)
603 return -1;
604 --lineleft;
605 return *lineptr++;
606 }
607
608 char *
xmon_fgets(char * str,int nb,void * f)609 xmon_fgets(char *str, int nb, void *f)
610 {
611 char *p;
612 int c;
613
614 for (p = str; p < str + nb - 1; ) {
615 c = xmon_getchar();
616 if (c == -1) {
617 if (p == str)
618 return 0;
619 break;
620 }
621 *p++ = c;
622 if (c == '\n')
623 break;
624 }
625 *p = 0;
626 return str;
627 }
628
629 void
xmon_enter(void)630 xmon_enter(void)
631 {
632 #ifdef CONFIG_ADB_PMU
633 if (_machine == _MACH_Pmac) {
634 pmu_suspend();
635 }
636 #endif
637 }
638
639 void
xmon_leave(void)640 xmon_leave(void)
641 {
642 #ifdef CONFIG_ADB_PMU
643 if (_machine == _MACH_Pmac) {
644 pmu_resume();
645 }
646 #endif
647 }
648