]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/blob - arch/ppc/xmon/start.c
Linux-2.6.12-rc2
[mirror_ubuntu-artful-kernel.git] / 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/pmac_feature.h>
22 #include <asm/processor.h>
23 #include <asm/delay.h>
24 #include <asm/btext.h>
25
26 static volatile unsigned char *sccc, *sccd;
27 unsigned int TXRDY, RXRDY, DLAB;
28 static int xmon_expect(const char *str, unsigned int timeout);
29
30 static int use_serial;
31 static int use_screen;
32 static int via_modem;
33 static int xmon_use_sccb;
34 static struct device_node *channel_node;
35
36 #define TB_SPEED 25000000
37
38 static inline unsigned int readtb(void)
39 {
40 unsigned int ret;
41
42 asm volatile("mftb %0" : "=r" (ret) :);
43 return ret;
44 }
45
46 void buf_access(void)
47 {
48 if (DLAB)
49 sccd[3] &= ~DLAB; /* reset DLAB */
50 }
51
52 extern int adb_init(void);
53
54 #ifdef CONFIG_PPC_CHRP
55 /*
56 * This looks in the "ranges" property for the primary PCI host bridge
57 * to find the physical address of the start of PCI/ISA I/O space.
58 * It is basically a cut-down version of pci_process_bridge_OF_ranges.
59 */
60 static unsigned long chrp_find_phys_io_base(void)
61 {
62 struct device_node *node;
63 unsigned int *ranges;
64 unsigned long base = CHRP_ISA_IO_BASE;
65 int rlen = 0;
66 int np;
67
68 node = find_devices("isa");
69 if (node != NULL) {
70 node = node->parent;
71 if (node == NULL || node->type == NULL
72 || strcmp(node->type, "pci") != 0)
73 node = NULL;
74 }
75 if (node == NULL)
76 node = find_devices("pci");
77 if (node == NULL)
78 return base;
79
80 ranges = (unsigned int *) get_property(node, "ranges", &rlen);
81 np = prom_n_addr_cells(node) + 5;
82 while ((rlen -= np * sizeof(unsigned int)) >= 0) {
83 if ((ranges[0] >> 24) == 1 && ranges[2] == 0) {
84 /* I/O space starting at 0, grab the phys base */
85 base = ranges[np - 3];
86 break;
87 }
88 ranges += np;
89 }
90 return base;
91 }
92 #endif /* CONFIG_PPC_CHRP */
93
94 #ifdef CONFIG_MAGIC_SYSRQ
95 static void sysrq_handle_xmon(int key, struct pt_regs *regs,
96 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",
106 };
107 #endif
108
109 void
110 xmon_map_scc(void)
111 {
112 #ifdef CONFIG_PPC_MULTIPLATFORM
113 volatile unsigned char *base;
114
115 if (_machine == _MACH_Pmac) {
116 struct device_node *np;
117 unsigned long addr;
118 #ifdef CONFIG_BOOTX_TEXT
119 if (!use_screen && !use_serial
120 && !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)
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 register_sysrq_key('x', &sysrq_xmon_op);
219 }
220
221 static int scc_initialized = 0;
222
223 void xmon_init_scc(void);
224 extern void cuda_poll(void);
225
226 static inline void do_poll_adb(void)
227 {
228 #ifdef CONFIG_ADB_PMU
229 if (sys_ctrler == SYS_CTRLER_PMU)
230 pmu_poll_adb();
231 #endif /* CONFIG_ADB_PMU */
232 #ifdef CONFIG_ADB_CUDA
233 if (sys_ctrler == SYS_CTRLER_CUDA)
234 cuda_poll();
235 #endif /* CONFIG_ADB_CUDA */
236 }
237
238 int
239 xmon_write(void *handle, void *ptr, int nb)
240 {
241 char *p = ptr;
242 int i, c, ct;
243
244 #ifdef CONFIG_SMP
245 static unsigned long xmon_write_lock;
246 int lock_wait = 1000000;
247 int locked;
248
249 while ((locked = test_and_set_bit(0, &xmon_write_lock)) != 0)
250 if (--lock_wait == 0)
251 break;
252 #endif
253
254 #ifdef CONFIG_BOOTX_TEXT
255 if (use_screen) {
256 /* write it on the screen */
257 for (i = 0; i < nb; ++i)
258 btext_drawchar(*p++);
259 goto out;
260 }
261 #endif
262 if (!scc_initialized)
263 xmon_init_scc();
264 ct = 0;
265 for (i = 0; i < nb; ++i) {
266 while ((*sccc & TXRDY) == 0)
267 do_poll_adb();
268 c = p[i];
269 if (c == '\n' && !ct) {
270 c = '\r';
271 ct = 1;
272 --i;
273 } else {
274 ct = 0;
275 }
276 buf_access();
277 *sccd = c;
278 eieio();
279 }
280
281 out:
282 #ifdef CONFIG_SMP
283 if (!locked)
284 clear_bit(0, &xmon_write_lock);
285 #endif
286 return nb;
287 }
288
289 int xmon_wants_key;
290 int xmon_adb_keycode;
291
292 #ifdef CONFIG_BOOTX_TEXT
293 static int xmon_adb_shiftstate;
294
295 static unsigned char xmon_keytab[128] =
296 "asdfhgzxcv\000bqwer" /* 0x00 - 0x0f */
297 "yt123465=97-80]o" /* 0x10 - 0x1f */
298 "u[ip\rlj'k;\\,/nm." /* 0x20 - 0x2f */
299 "\t `\177\0\033\0\0\0\0\0\0\0\0\0\0" /* 0x30 - 0x3f */
300 "\0.\0*\0+\0\0\0\0\0/\r\0-\0" /* 0x40 - 0x4f */
301 "\0\0000123456789\0\0\0"; /* 0x50 - 0x5f */
302
303 static unsigned char xmon_shift_keytab[128] =
304 "ASDFHGZXCV\000BQWER" /* 0x00 - 0x0f */
305 "YT!@#$^%+(&_*)}O" /* 0x10 - 0x1f */
306 "U{IP\rLJ\"K:|<?NM>" /* 0x20 - 0x2f */
307 "\t ~\177\0\033\0\0\0\0\0\0\0\0\0\0" /* 0x30 - 0x3f */
308 "\0.\0*\0+\0\0\0\0\0/\r\0-\0" /* 0x40 - 0x4f */
309 "\0\0000123456789\0\0\0"; /* 0x50 - 0x5f */
310
311 static int
312 xmon_get_adb_key(void)
313 {
314 int k, t, on;
315
316 xmon_wants_key = 1;
317 for (;;) {
318 xmon_adb_keycode = -1;
319 t = 0;
320 on = 0;
321 do {
322 if (--t < 0) {
323 on = 1 - on;
324 btext_drawchar(on? 0xdb: 0x20);
325 btext_drawchar('\b');
326 t = 200000;
327 }
328 do_poll_adb();
329 } while (xmon_adb_keycode == -1);
330 k = xmon_adb_keycode;
331 if (on)
332 btext_drawstring(" \b");
333
334 /* test for shift keys */
335 if ((k & 0x7f) == 0x38 || (k & 0x7f) == 0x7b) {
336 xmon_adb_shiftstate = (k & 0x80) == 0;
337 continue;
338 }
339 if (k >= 0x80)
340 continue; /* ignore up transitions */
341 k = (xmon_adb_shiftstate? xmon_shift_keytab: xmon_keytab)[k];
342 if (k != 0)
343 break;
344 }
345 xmon_wants_key = 0;
346 return k;
347 }
348 #endif /* CONFIG_BOOTX_TEXT */
349
350 int
351 xmon_read(void *handle, void *ptr, int nb)
352 {
353 char *p = ptr;
354 int i;
355
356 #ifdef CONFIG_BOOTX_TEXT
357 if (use_screen) {
358 for (i = 0; i < nb; ++i)
359 *p++ = xmon_get_adb_key();
360 return i;
361 }
362 #endif
363 if (!scc_initialized)
364 xmon_init_scc();
365 for (i = 0; i < nb; ++i) {
366 while ((*sccc & RXRDY) == 0)
367 do_poll_adb();
368 buf_access();
369 *p++ = *sccd;
370 }
371 return i;
372 }
373
374 int
375 xmon_read_poll(void)
376 {
377 if ((*sccc & RXRDY) == 0) {
378 do_poll_adb();
379 return -1;
380 }
381 buf_access();
382 return *sccd;
383 }
384
385 static unsigned char scc_inittab[] = {
386 13, 0, /* set baud rate divisor */
387 12, 1,
388 14, 1, /* baud rate gen enable, src=rtxc */
389 11, 0x50, /* clocks = br gen */
390 5, 0xea, /* tx 8 bits, assert DTR & RTS */
391 4, 0x46, /* x16 clock, 1 stop */
392 3, 0xc1, /* rx enable, 8 bits */
393 };
394
395 void
396 xmon_init_scc(void)
397 {
398 if ( _machine == _MACH_chrp )
399 {
400 sccd[3] = 0x83; eieio(); /* LCR = 8N1 + DLAB */
401 sccd[0] = 12; eieio(); /* DLL = 9600 baud */
402 sccd[1] = 0; eieio();
403 sccd[2] = 0; eieio(); /* FCR = 0 */
404 sccd[3] = 3; eieio(); /* LCR = 8N1 */
405 sccd[1] = 0; eieio(); /* IER = 0 */
406 }
407 else if ( _machine == _MACH_Pmac )
408 {
409 int i, x;
410
411 if (channel_node != 0)
412 pmac_call_feature(
413 PMAC_FTR_SCC_ENABLE,
414 channel_node,
415 PMAC_SCC_ASYNC | PMAC_SCC_FLAG_XMON, 1);
416 printk(KERN_INFO "Serial port locked ON by debugger !\n");
417 if (via_modem && channel_node != 0) {
418 unsigned int t0;
419
420 pmac_call_feature(
421 PMAC_FTR_MODEM_ENABLE,
422 channel_node, 0, 1);
423 printk(KERN_INFO "Modem powered up by debugger !\n");
424 t0 = readtb();
425 while (readtb() - t0 < 3*TB_SPEED)
426 eieio();
427 }
428 /* use the B channel if requested */
429 if (xmon_use_sccb) {
430 sccc = (volatile unsigned char *)
431 ((unsigned long)sccc & ~0x20);
432 sccd = sccc + 0x10;
433 }
434 for (i = 20000; i != 0; --i) {
435 x = *sccc; eieio();
436 }
437 *sccc = 9; eieio(); /* reset A or B side */
438 *sccc = ((unsigned long)sccc & 0x20)? 0x80: 0x40; eieio();
439 for (i = 0; i < sizeof(scc_inittab); ++i) {
440 *sccc = scc_inittab[i];
441 eieio();
442 }
443 }
444 scc_initialized = 1;
445 if (via_modem) {
446 for (;;) {
447 xmon_write(NULL, "ATE1V1\r", 7);
448 if (xmon_expect("OK", 5)) {
449 xmon_write(NULL, "ATA\r", 4);
450 if (xmon_expect("CONNECT", 40))
451 break;
452 }
453 xmon_write(NULL, "+++", 3);
454 xmon_expect("OK", 3);
455 }
456 }
457 }
458
459 #if 0
460 extern int (*prom_entry)(void *);
461
462 int
463 xmon_exit(void)
464 {
465 struct prom_args {
466 char *service;
467 } args;
468
469 for (;;) {
470 args.service = "exit";
471 (*prom_entry)(&args);
472 }
473 }
474 #endif
475
476 void *xmon_stdin;
477 void *xmon_stdout;
478 void *xmon_stderr;
479
480 void
481 xmon_init(void)
482 {
483 }
484
485 int
486 xmon_putc(int c, void *f)
487 {
488 char ch = c;
489
490 if (c == '\n')
491 xmon_putc('\r', f);
492 return xmon_write(f, &ch, 1) == 1? c: -1;
493 }
494
495 int
496 xmon_putchar(int c)
497 {
498 return xmon_putc(c, xmon_stdout);
499 }
500
501 int
502 xmon_fputs(char *str, void *f)
503 {
504 int n = strlen(str);
505
506 return xmon_write(f, str, n) == n? 0: -1;
507 }
508
509 int
510 xmon_readchar(void)
511 {
512 char ch;
513
514 for (;;) {
515 switch (xmon_read(xmon_stdin, &ch, 1)) {
516 case 1:
517 return ch;
518 case -1:
519 xmon_printf("read(stdin) returned -1\r\n", 0, 0);
520 return -1;
521 }
522 }
523 }
524
525 static char line[256];
526 static char *lineptr;
527 static int lineleft;
528
529 int xmon_expect(const char *str, unsigned int timeout)
530 {
531 int c;
532 unsigned int t0;
533
534 timeout *= TB_SPEED;
535 t0 = readtb();
536 do {
537 lineptr = line;
538 for (;;) {
539 c = xmon_read_poll();
540 if (c == -1) {
541 if (readtb() - t0 > timeout)
542 return 0;
543 continue;
544 }
545 if (c == '\n')
546 break;
547 if (c != '\r' && lineptr < &line[sizeof(line) - 1])
548 *lineptr++ = c;
549 }
550 *lineptr = 0;
551 } while (strstr(line, str) == NULL);
552 return 1;
553 }
554
555 int
556 xmon_getchar(void)
557 {
558 int c;
559
560 if (lineleft == 0) {
561 lineptr = line;
562 for (;;) {
563 c = xmon_readchar();
564 if (c == -1 || c == 4)
565 break;
566 if (c == '\r' || c == '\n') {
567 *lineptr++ = '\n';
568 xmon_putchar('\n');
569 break;
570 }
571 switch (c) {
572 case 0177:
573 case '\b':
574 if (lineptr > line) {
575 xmon_putchar('\b');
576 xmon_putchar(' ');
577 xmon_putchar('\b');
578 --lineptr;
579 }
580 break;
581 case 'U' & 0x1F:
582 while (lineptr > line) {
583 xmon_putchar('\b');
584 xmon_putchar(' ');
585 xmon_putchar('\b');
586 --lineptr;
587 }
588 break;
589 default:
590 if (lineptr >= &line[sizeof(line) - 1])
591 xmon_putchar('\a');
592 else {
593 xmon_putchar(c);
594 *lineptr++ = c;
595 }
596 }
597 }
598 lineleft = lineptr - line;
599 lineptr = line;
600 }
601 if (lineleft == 0)
602 return -1;
603 --lineleft;
604 return *lineptr++;
605 }
606
607 char *
608 xmon_fgets(char *str, int nb, void *f)
609 {
610 char *p;
611 int c;
612
613 for (p = str; p < str + nb - 1; ) {
614 c = xmon_getchar();
615 if (c == -1) {
616 if (p == str)
617 return NULL;
618 break;
619 }
620 *p++ = c;
621 if (c == '\n')
622 break;
623 }
624 *p = 0;
625 return str;
626 }
627
628 void
629 xmon_enter(void)
630 {
631 #ifdef CONFIG_ADB_PMU
632 if (_machine == _MACH_Pmac) {
633 pmu_suspend();
634 }
635 #endif
636 }
637
638 void
639 xmon_leave(void)
640 {
641 #ifdef CONFIG_ADB_PMU
642 if (_machine == _MACH_Pmac) {
643 pmu_resume();
644 }
645 #endif
646 }