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