]> git.karo-electronics.de Git - karo-tx-linux.git/blob - arch/ppc/xmon/start.c
Merge branch 'upstream'
[karo-tx-linux.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/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 extern void cuda_poll(void);
150
151 static inline void do_poll_adb(void)
152 {
153 #ifdef CONFIG_ADB_PMU
154         if (sys_ctrler == SYS_CTRLER_PMU)
155                 pmu_poll_adb();
156 #endif /* CONFIG_ADB_PMU */
157 #ifdef CONFIG_ADB_CUDA
158         if (sys_ctrler == SYS_CTRLER_CUDA)
159                 cuda_poll();
160 #endif /* CONFIG_ADB_CUDA */
161 }
162
163 int
164 xmon_write(void *handle, void *ptr, int nb)
165 {
166         char *p = ptr;
167         int i, c, ct;
168
169 #ifdef CONFIG_SMP
170         static unsigned long xmon_write_lock;
171         int lock_wait = 1000000;
172         int locked;
173
174         while ((locked = test_and_set_bit(0, &xmon_write_lock)) != 0)
175                 if (--lock_wait == 0)
176                         break;
177 #endif
178
179 #ifdef CONFIG_BOOTX_TEXT
180         if (use_screen) {
181                 /* write it on the screen */
182                 for (i = 0; i < nb; ++i)
183                         btext_drawchar(*p++);
184                 goto out;
185         }
186 #endif
187         if (!scc_initialized)
188                 xmon_init_scc();
189         ct = 0;
190         for (i = 0; i < nb; ++i) {
191                 while ((*sccc & TXRDY) == 0)
192                         do_poll_adb();
193                 c = p[i];
194                 if (c == '\n' && !ct) {
195                         c = '\r';
196                         ct = 1;
197                         --i;
198                 } else {
199                         ct = 0;
200                 }
201                 buf_access();
202                 *sccd = c;
203                 eieio();
204         }
205
206  out:
207 #ifdef CONFIG_SMP
208         if (!locked)
209                 clear_bit(0, &xmon_write_lock);
210 #endif
211         return nb;
212 }
213
214 int xmon_wants_key;
215 int xmon_adb_keycode;
216
217 #ifdef CONFIG_BOOTX_TEXT
218 static int xmon_adb_shiftstate;
219
220 static unsigned char xmon_keytab[128] =
221         "asdfhgzxcv\000bqwer"                           /* 0x00 - 0x0f */
222         "yt123465=97-80]o"                              /* 0x10 - 0x1f */
223         "u[ip\rlj'k;\\,/nm."                            /* 0x20 - 0x2f */
224         "\t `\177\0\033\0\0\0\0\0\0\0\0\0\0"            /* 0x30 - 0x3f */
225         "\0.\0*\0+\0\0\0\0\0/\r\0-\0"                   /* 0x40 - 0x4f */
226         "\0\0000123456789\0\0\0";                       /* 0x50 - 0x5f */
227
228 static unsigned char xmon_shift_keytab[128] =
229         "ASDFHGZXCV\000BQWER"                           /* 0x00 - 0x0f */
230         "YT!@#$^%+(&_*)}O"                              /* 0x10 - 0x1f */
231         "U{IP\rLJ\"K:|<?NM>"                            /* 0x20 - 0x2f */
232         "\t ~\177\0\033\0\0\0\0\0\0\0\0\0\0"            /* 0x30 - 0x3f */
233         "\0.\0*\0+\0\0\0\0\0/\r\0-\0"                   /* 0x40 - 0x4f */
234         "\0\0000123456789\0\0\0";                       /* 0x50 - 0x5f */
235
236 static int
237 xmon_get_adb_key(void)
238 {
239         int k, t, on;
240
241         xmon_wants_key = 1;
242         for (;;) {
243                 xmon_adb_keycode = -1;
244                 t = 0;
245                 on = 0;
246                 do {
247                         if (--t < 0) {
248                                 on = 1 - on;
249                                 btext_drawchar(on? 0xdb: 0x20);
250                                 btext_drawchar('\b');
251                                 t = 200000;
252                         }
253                         do_poll_adb();
254                 } while (xmon_adb_keycode == -1);
255                 k = xmon_adb_keycode;
256                 if (on)
257                         btext_drawstring(" \b");
258
259                 /* test for shift keys */
260                 if ((k & 0x7f) == 0x38 || (k & 0x7f) == 0x7b) {
261                         xmon_adb_shiftstate = (k & 0x80) == 0;
262                         continue;
263                 }
264                 if (k >= 0x80)
265                         continue;       /* ignore up transitions */
266                 k = (xmon_adb_shiftstate? xmon_shift_keytab: xmon_keytab)[k];
267                 if (k != 0)
268                         break;
269         }
270         xmon_wants_key = 0;
271         return k;
272 }
273 #endif /* CONFIG_BOOTX_TEXT */
274
275 int
276 xmon_read(void *handle, void *ptr, int nb)
277 {
278     char *p = ptr;
279     int i;
280
281 #ifdef CONFIG_BOOTX_TEXT
282     if (use_screen) {
283         for (i = 0; i < nb; ++i)
284             *p++ = xmon_get_adb_key();
285         return i;
286     }
287 #endif
288     if (!scc_initialized)
289         xmon_init_scc();
290     for (i = 0; i < nb; ++i) {
291         while ((*sccc & RXRDY) == 0)
292             do_poll_adb();
293         buf_access();
294         *p++ = *sccd;
295     }
296     return i;
297 }
298
299 int
300 xmon_read_poll(void)
301 {
302         if ((*sccc & RXRDY) == 0) {
303                 do_poll_adb();
304                 return -1;
305         }
306         buf_access();
307         return *sccd;
308 }
309
310 void
311 xmon_init_scc(void)
312 {
313         if ( _machine == _MACH_chrp )
314         {
315                 sccd[3] = 0x83; eieio();        /* LCR = 8N1 + DLAB */
316                 sccd[0] = 12; eieio();          /* DLL = 9600 baud */
317                 sccd[1] = 0; eieio();
318                 sccd[2] = 0; eieio();           /* FCR = 0 */
319                 sccd[3] = 3; eieio();           /* LCR = 8N1 */
320                 sccd[1] = 0; eieio();           /* IER = 0 */
321         }
322         scc_initialized = 1;
323         if (via_modem) {
324                 for (;;) {
325                         xmon_write(NULL, "ATE1V1\r", 7);
326                         if (xmon_expect("OK", 5)) {
327                                 xmon_write(NULL, "ATA\r", 4);
328                                 if (xmon_expect("CONNECT", 40))
329                                         break;
330                         }
331                         xmon_write(NULL, "+++", 3);
332                         xmon_expect("OK", 3);
333                 }
334         }
335 }
336
337 #if 0
338 extern int (*prom_entry)(void *);
339
340 int
341 xmon_exit(void)
342 {
343     struct prom_args {
344         char *service;
345     } args;
346
347     for (;;) {
348         args.service = "exit";
349         (*prom_entry)(&args);
350     }
351 }
352 #endif
353
354 void *xmon_stdin;
355 void *xmon_stdout;
356 void *xmon_stderr;
357
358 void
359 xmon_init(int arg)
360 {
361         xmon_map_scc();
362 }
363
364 int
365 xmon_putc(int c, void *f)
366 {
367     char ch = c;
368
369     if (c == '\n')
370         xmon_putc('\r', f);
371     return xmon_write(f, &ch, 1) == 1? c: -1;
372 }
373
374 int
375 xmon_putchar(int c)
376 {
377     return xmon_putc(c, xmon_stdout);
378 }
379
380 int
381 xmon_fputs(char *str, void *f)
382 {
383     int n = strlen(str);
384
385     return xmon_write(f, str, n) == n? 0: -1;
386 }
387
388 int
389 xmon_readchar(void)
390 {
391     char ch;
392
393     for (;;) {
394         switch (xmon_read(xmon_stdin, &ch, 1)) {
395         case 1:
396             return ch;
397         case -1:
398             xmon_printf("read(stdin) returned -1\r\n", 0, 0);
399             return -1;
400         }
401     }
402 }
403
404 static char line[256];
405 static char *lineptr;
406 static int lineleft;
407
408 int xmon_expect(const char *str, unsigned int timeout)
409 {
410         int c;
411         unsigned int t0;
412
413         timeout *= TB_SPEED;
414         t0 = readtb();
415         do {
416                 lineptr = line;
417                 for (;;) {
418                         c = xmon_read_poll();
419                         if (c == -1) {
420                                 if (readtb() - t0 > timeout)
421                                         return 0;
422                                 continue;
423                         }
424                         if (c == '\n')
425                                 break;
426                         if (c != '\r' && lineptr < &line[sizeof(line) - 1])
427                                 *lineptr++ = c;
428                 }
429                 *lineptr = 0;
430         } while (strstr(line, str) == NULL);
431         return 1;
432 }
433
434 int
435 xmon_getchar(void)
436 {
437     int c;
438
439     if (lineleft == 0) {
440         lineptr = line;
441         for (;;) {
442             c = xmon_readchar();
443             if (c == -1 || c == 4)
444                 break;
445             if (c == '\r' || c == '\n') {
446                 *lineptr++ = '\n';
447                 xmon_putchar('\n');
448                 break;
449             }
450             switch (c) {
451             case 0177:
452             case '\b':
453                 if (lineptr > line) {
454                     xmon_putchar('\b');
455                     xmon_putchar(' ');
456                     xmon_putchar('\b');
457                     --lineptr;
458                 }
459                 break;
460             case 'U' & 0x1F:
461                 while (lineptr > line) {
462                     xmon_putchar('\b');
463                     xmon_putchar(' ');
464                     xmon_putchar('\b');
465                     --lineptr;
466                 }
467                 break;
468             default:
469                 if (lineptr >= &line[sizeof(line) - 1])
470                     xmon_putchar('\a');
471                 else {
472                     xmon_putchar(c);
473                     *lineptr++ = c;
474                 }
475             }
476         }
477         lineleft = lineptr - line;
478         lineptr = line;
479     }
480     if (lineleft == 0)
481         return -1;
482     --lineleft;
483     return *lineptr++;
484 }
485
486 char *
487 xmon_fgets(char *str, int nb, void *f)
488 {
489     char *p;
490     int c;
491
492     for (p = str; p < str + nb - 1; ) {
493         c = xmon_getchar();
494         if (c == -1) {
495             if (p == str)
496                 return NULL;
497             break;
498         }
499         *p++ = c;
500         if (c == '\n')
501             break;
502     }
503     *p = 0;
504     return str;
505 }
506
507 void
508 xmon_enter(void)
509 {
510 }
511
512 void
513 xmon_leave(void)
514 {
515 }