Import 2.3.50pre1
[davej-history.git] / arch / ppc / xmon / start.c
blob95b19ba475fb2b44c8be027390e6413df3f80b8c
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/kernel.h>
12 #include <asm/prom.h>
13 #include <asm/bootx.h>
14 #include <asm/feature.h>
15 #include <asm/processor.h>
17 static volatile unsigned char *sccc, *sccd;
18 unsigned long TXRDY, RXRDY;
19 extern void xmon_printf(const char *fmt, ...);
20 extern void prom_drawchar(char);
21 extern void prom_drawstring(const char *str);
22 static int xmon_expect(const char *str, unsigned int timeout);
24 static int console = 0;
25 static int use_screen = 1; /* default */
26 static int via_modem = 0;
27 static int xmon_use_sccb = 0;
28 static struct device_node *macio_node;
30 #define TB_SPEED 25000000
32 static inline unsigned int readtb(void)
34 unsigned int ret;
36 asm volatile("mftb %0" : "=r" (ret) :);
37 return ret;
40 void buf_access(void)
42 if ( _machine == _MACH_chrp )
43 sccd[3] &= ~0x80; /* reset DLAB */
46 void
47 xmon_map_scc(void)
49 volatile unsigned char *base;
51 use_screen = 0;
53 if ( _machine == _MACH_Pmac )
55 struct device_node *np;
56 unsigned long addr;
57 #ifdef CONFIG_BOOTX_TEXT
58 extern boot_infos_t *disp_bi;
60 /* needs to be hacked if xmon_printk is to be used
61 from within find_via_pmu() */
62 if (!via_modem && disp_bi && find_via_pmu()) {
63 prom_drawstring("xmon uses screen and keyboard\n");
64 use_screen = 1;
65 return;
67 #endif
69 #ifdef CHRP_ESCC
70 addr = 0xc1013020;
71 #else
72 addr = 0xf3013020;
73 #endif
74 TXRDY = 4;
75 RXRDY = 1;
77 np = find_devices("mac-io");
78 if (np && np->n_addrs) {
79 macio_node = np;
80 addr = np->addrs[0].address + 0x13000;
81 /* use the B channel on the iMac */
82 if (!xmon_use_sccb)
83 addr += 0x20; /* use A channel */
85 base = (volatile unsigned char *) ioremap(addr & PAGE_MASK, PAGE_SIZE);
86 sccc = base + (addr & ~PAGE_MASK);
87 #ifdef CHRP_ESCC
88 sccd = sccc + (0xc1013030 - 0xc1013020);
89 #else
90 sccd = sccc + (0xf3013030 - 0xf3013020);
91 #endif
93 else if ( _machine & _MACH_gemini )
95 /* should already be mapped by the kernel boot */
96 sccc = (volatile unsigned char *) 0xffeffb0d;
97 sccd = (volatile unsigned char *) 0xffeffb08;
98 TXRDY = 0x20;
99 RXRDY = 1;
100 console = 1;
102 else
104 /* should already be mapped by the kernel boot */
105 sccc = (volatile unsigned char *) (isa_io_base + 0x3fd);
106 sccd = (volatile unsigned char *) (isa_io_base + 0x3f8);
107 TXRDY = 0x20;
108 RXRDY = 1;
112 static int scc_initialized = 0;
114 void xmon_init_scc(void);
115 extern void pmu_poll(void);
118 xmon_write(void *handle, void *ptr, int nb)
120 char *p = ptr;
121 int i, c, ct;
123 #ifdef CONFIG_BOOTX_TEXT
124 if (use_screen) {
125 /* write it on the screen */
126 for (i = 0; i < nb; ++i)
127 prom_drawchar(*p++);
128 return nb;
130 #endif
131 if (!scc_initialized)
132 xmon_init_scc();
133 ct = 0;
134 for (i = 0; i < nb; ++i) {
135 while ((*sccc & TXRDY) == 0) {
136 #ifdef CONFIG_ADB
137 if (sys_ctrler == SYS_CTRLER_PMU)
138 pmu_poll();
139 #endif /* CONFIG_ADB */
141 c = p[i];
142 if (c == '\n' && !ct) {
143 c = '\r';
144 ct = 1;
145 --i;
146 } else {
147 prom_drawchar(c);
148 if (console)
149 printk("%c", c);
150 ct = 0;
152 buf_access();
153 *sccd = c;
155 return i;
158 int xmon_wants_key;
159 int xmon_pmu_keycode;
161 #ifdef CONFIG_BOOTX_TEXT
162 static int xmon_pmu_shiftstate;
164 static unsigned char xmon_keytab[128] =
165 "asdfhgzxcv\000bqwer" /* 0x00 - 0x0f */
166 "yt123465=97-80o]" /* 0x10 - 0x1f */
167 "u[ip\rlj'k;\\,/nm." /* 0x20 - 0x2f */
168 "\t `\177\0\033\0\0\0\0\0\0\0\0\0\0" /* 0x30 - 0x3f */
169 "\0.\0*\0+\0\0\0\0\0/\r\0-\0" /* 0x40 - 0x4f */
170 "\0\0000123456789\0\0\0"; /* 0x50 - 0x5f */
172 static unsigned char xmon_shift_keytab[128] =
173 "ASDFHGZXCV\000BQWER" /* 0x00 - 0x0f */
174 "YT!@#$^%+(&=*)}O" /* 0x10 - 0x1f */
175 "U{IP\rLJ\"K:|<?NM>" /* 0x20 - 0x2f */
176 "\t ~\177\0\033\0\0\0\0\0\0\0\0\0\0" /* 0x30 - 0x3f */
177 "\0.\0*\0+\0\0\0\0\0/\r\0-\0" /* 0x40 - 0x4f */
178 "\0\0000123456789\0\0\0"; /* 0x50 - 0x5f */
180 static int
181 xmon_get_pmu_key(void)
183 int k, t, on;
185 xmon_wants_key = 1;
186 for (;;) {
187 xmon_pmu_keycode = -1;
188 t = 0;
189 on = 0;
190 do {
191 if (--t < 0) {
192 on = 1 - on;
193 prom_drawchar(on? 0xdb: 0x20);
194 prom_drawchar('\b');
195 t = 200000;
197 pmu_poll();
198 } while (xmon_pmu_keycode == -1);
199 k = xmon_pmu_keycode;
200 if (on)
201 prom_drawstring(" \b");
203 /* test for shift keys */
204 if ((k & 0x7f) == 0x38 || (k & 0x7f) == 0x7b) {
205 xmon_pmu_shiftstate = (k & 0x80) == 0;
206 continue;
208 if (k >= 0x80)
209 continue; /* ignore up transitions */
210 k = (xmon_pmu_shiftstate? xmon_shift_keytab: xmon_keytab)[k];
211 if (k != 0)
212 break;
214 xmon_wants_key = 0;
215 return k;
217 #endif /* CONFIG_BOOTX_TEXT */
220 xmon_read(void *handle, void *ptr, int nb)
222 char *p = ptr;
223 int i;
225 #ifdef CONFIG_BOOTX_TEXT
226 if (use_screen) {
227 for (i = 0; i < nb; ++i)
228 *p++ = xmon_get_pmu_key();
229 return i;
231 #endif
232 if (!scc_initialized)
233 xmon_init_scc();
234 for (i = 0; i < nb; ++i) {
235 while ((*sccc & RXRDY) == 0)
236 #ifdef CONFIG_ADB
237 if (sys_ctrler == SYS_CTRLER_PMU)
238 pmu_poll();
239 #else
241 #endif /* CONFIG_ADB */
242 buf_access();
243 *p++ = *sccd;
245 return i;
249 xmon_read_poll(void)
251 if ((*sccc & RXRDY) == 0) {
252 #ifdef CONFIG_ADB
253 if (sys_ctrler == SYS_CTRLER_PMU)
254 pmu_poll();
255 #else
257 #endif
258 return -1;
260 buf_access();
261 return *sccd;
264 static unsigned char scc_inittab[] = {
265 13, 0, /* set baud rate divisor */
266 12, 1,
267 14, 1, /* baud rate gen enable, src=rtxc */
268 11, 0x50, /* clocks = br gen */
269 5, 0xea, /* tx 8 bits, assert DTR & RTS */
270 4, 0x46, /* x16 clock, 1 stop */
271 3, 0xc1, /* rx enable, 8 bits */
274 void
275 xmon_init_scc()
277 if ( _machine == _MACH_chrp )
279 sccd[3] = 0x83; eieio(); /* LCR = 8N1 + DLAB */
280 sccd[0] = 3; eieio(); /* DLL = 38400 baud */
281 sccd[1] = 0; eieio();
282 sccd[2] = 0; eieio(); /* FCR = 0 */
283 sccd[3] = 3; eieio(); /* LCR = 8N1 */
284 sccd[1] = 0; eieio(); /* IER = 0 */
286 else if ( _machine == _MACH_Pmac )
288 int i, x;
290 if (macio_node != 0)
291 feature_set(macio_node, FEATURE_Serial_enable);
292 if (via_modem && macio_node != 0) {
293 unsigned int t0;
295 feature_set(macio_node, FEATURE_Modem_power);
296 t0 = readtb();
297 while (readtb() - t0 < 3*TB_SPEED)
298 eieio();
300 for (i = 20000; i != 0; --i) {
301 x = *sccc; eieio();
303 *sccc = 9; eieio(); /* reset A or B side */
304 *sccc = ((unsigned long)sccc & 0x20)? 0x80: 0x40; eieio();
305 for (i = 0; i < sizeof(scc_inittab); ++i) {
306 *sccc = scc_inittab[i];
307 eieio();
310 scc_initialized = 1;
311 if (via_modem) {
312 for (;;) {
313 xmon_write(0, "ATE1V1\r", 7);
314 if (xmon_expect("OK", 5)) {
315 xmon_write(0, "ATA\r", 4);
316 if (xmon_expect("CONNECT", 40))
317 break;
319 xmon_write(0, "+++", 3);
320 xmon_expect("OK", 3);
325 #if 0
326 extern int (*prom_entry)(void *);
329 xmon_exit(void)
331 struct prom_args {
332 char *service;
333 } args;
335 for (;;) {
336 args.service = "exit";
337 (*prom_entry)(&args);
340 #endif
342 void *xmon_stdin;
343 void *xmon_stdout;
344 void *xmon_stderr;
346 void
347 xmon_init(void)
352 xmon_putc(int c, void *f)
354 char ch = c;
356 if (c == '\n')
357 xmon_putc('\r', f);
358 return xmon_write(f, &ch, 1) == 1? c: -1;
362 xmon_putchar(int c)
364 return xmon_putc(c, xmon_stdout);
368 xmon_fputs(char *str, void *f)
370 int n = strlen(str);
372 return xmon_write(f, str, n) == n? 0: -1;
376 xmon_readchar(void)
378 char ch;
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;
391 static char line[256];
392 static char *lineptr;
393 static int lineleft;
395 int xmon_expect(const char *str, unsigned int timeout)
397 int c;
398 unsigned int t0;
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;
411 if (c == '\n')
412 break;
413 if (c != '\r' && lineptr < &line[sizeof(line) - 1])
414 *lineptr++ = c;
416 *lineptr = 0;
417 } while (strstr(line, str) == NULL);
418 return 1;
422 xmon_getchar(void)
424 int c;
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;
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;
446 break;
447 case 'U' & 0x1F:
448 while (lineptr > line) {
449 xmon_putchar('\b');
450 xmon_putchar(' ');
451 xmon_putchar('\b');
452 --lineptr;
454 break;
455 default:
456 if (lineptr >= &line[sizeof(line) - 1])
457 xmon_putchar('\a');
458 else {
459 xmon_putchar(c);
460 *lineptr++ = c;
464 lineleft = lineptr - line;
465 lineptr = line;
467 if (lineleft == 0)
468 return -1;
469 --lineleft;
470 return *lineptr++;
473 char *
474 xmon_fgets(char *str, int nb, void *f)
476 char *p;
477 int c;
479 for (p = str; p < str + nb - 1; ) {
480 c = xmon_getchar();
481 if (c == -1) {
482 if (p == str)
483 return 0;
484 break;
486 *p++ = c;
487 if (c == '\n')
488 break;
490 *p = 0;
491 return str;