Merge master.kernel.org:/home/rmk/linux-2.6-arm
[linux-2.6] / arch / powerpc / xmon / start_32.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/bitops.h>
15 #include <asm/xmon.h>
16 #include <asm/prom.h>
17 #include <asm/bootx.h>
18 #include <asm/machdep.h>
19 #include <asm/errno.h>
20 #include <asm/pmac_feature.h>
21 #include <asm/processor.h>
22 #include <asm/delay.h>
23 #include <asm/btext.h>
24 #include <asm/time.h>
25 #include "nonstdio.h"
26
27 static volatile unsigned char __iomem *sccc, *sccd;
28 unsigned int TXRDY, RXRDY, DLAB;
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 void buf_access(void)
37 {
38         if (DLAB)
39                 sccd[3] &= ~DLAB;       /* reset DLAB */
40 }
41
42 extern int adb_init(void);
43
44 #ifdef CONFIG_PPC_CHRP
45 /*
46  * This looks in the "ranges" property for the primary PCI host bridge
47  * to find the physical address of the start of PCI/ISA I/O space.
48  * It is basically a cut-down version of pci_process_bridge_OF_ranges.
49  */
50 static unsigned long chrp_find_phys_io_base(void)
51 {
52         struct device_node *node;
53         unsigned int *ranges;
54         unsigned long base = CHRP_ISA_IO_BASE;
55         int rlen = 0;
56         int np;
57
58         node = find_devices("isa");
59         if (node != NULL) {
60                 node = node->parent;
61                 if (node == NULL || node->type == NULL
62                     || strcmp(node->type, "pci") != 0)
63                         node = NULL;
64         }
65         if (node == NULL)
66                 node = find_devices("pci");
67         if (node == NULL)
68                 return base;
69
70         ranges = (unsigned int *) get_property(node, "ranges", &rlen);
71         np = prom_n_addr_cells(node) + 5;
72         while ((rlen -= np * sizeof(unsigned int)) >= 0) {
73                 if ((ranges[0] >> 24) == 1 && ranges[2] == 0) {
74                         /* I/O space starting at 0, grab the phys base */
75                         base = ranges[np - 3];
76                         break;
77                 }
78                 ranges += np;
79         }
80         return base;
81 }
82 #endif /* CONFIG_PPC_CHRP */
83
84 void xmon_map_scc(void)
85 {
86 #ifdef CONFIG_PPC_MULTIPLATFORM
87         volatile unsigned char __iomem *base;
88
89         if (_machine == _MACH_Pmac) {
90                 struct device_node *np;
91                 unsigned long addr;
92 #ifdef CONFIG_BOOTX_TEXT
93                 if (!use_screen && !use_serial
94                     && !machine_is_compatible("iMac")) {
95                         /* see if there is a keyboard in the device tree
96                            with a parent of type "adb" */
97                         for (np = find_devices("keyboard"); np; np = np->next)
98                                 if (np->parent && np->parent->type
99                                     && strcmp(np->parent->type, "adb") == 0)
100                                         break;
101
102                         /* needs to be hacked if xmon_printk is to be used
103                            from within find_via_pmu() */
104 #ifdef CONFIG_ADB_PMU
105                         if (np != NULL && boot_text_mapped && find_via_pmu())
106                                 use_screen = 1;
107 #endif
108 #ifdef CONFIG_ADB_CUDA
109                         if (np != NULL && boot_text_mapped && find_via_cuda())
110                                 use_screen = 1;
111 #endif
112                 }
113                 if (!use_screen && (np = find_devices("escc")) != NULL) {
114                         /*
115                          * look for the device node for the serial port
116                          * we're using and see if it says it has a modem
117                          */
118                         char *name = xmon_use_sccb? "ch-b": "ch-a";
119                         char *slots;
120                         int l;
121
122                         np = np->child;
123                         while (np != NULL && strcmp(np->name, name) != 0)
124                                 np = np->sibling;
125                         if (np != NULL) {
126                                 /* XXX should parse this properly */
127                                 channel_node = np;
128                                 slots = get_property(np, "slot-names", &l);
129                                 if (slots != NULL && l >= 10
130                                     && strcmp(slots+4, "Modem") == 0)
131                                         via_modem = 1;
132                         }
133                 }
134                 btext_drawstring("xmon uses ");
135                 if (use_screen)
136                         btext_drawstring("screen and keyboard\n");
137                 else {
138                         if (via_modem)
139                                 btext_drawstring("modem on ");
140                         btext_drawstring(xmon_use_sccb? "printer": "modem");
141                         btext_drawstring(" port\n");
142                 }
143
144 #endif /* CONFIG_BOOTX_TEXT */
145
146 #ifdef CHRP_ESCC
147                 addr = 0xc1013020;
148 #else
149                 addr = 0xf3013020;
150 #endif
151                 TXRDY = 4;
152                 RXRDY = 1;
153         
154                 np = find_devices("mac-io");
155                 if (np && np->n_addrs)
156                         addr = np->addrs[0].address + 0x13020;
157                 base = (volatile unsigned char *) ioremap(addr & PAGE_MASK, PAGE_SIZE);
158                 sccc = base + (addr & ~PAGE_MASK);
159                 sccd = sccc + 0x10;
160
161         } else {
162                 base = (volatile unsigned char *) isa_io_base;
163
164 #ifdef CONFIG_PPC_CHRP
165                 if (_machine == _MACH_chrp)
166                         base = (volatile unsigned char __iomem *)
167                                 ioremap(chrp_find_phys_io_base(), 0x1000);
168 #endif
169
170                 sccc = base + 0x3fd;
171                 sccd = base + 0x3f8;
172                 if (xmon_use_sccb) {
173                         sccc -= 0x100;
174                         sccd -= 0x100;
175                 }
176                 TXRDY = 0x20;
177                 RXRDY = 1;
178                 DLAB = 0x80;
179         }
180 #elif defined(CONFIG_GEMINI)
181         /* should already be mapped by the kernel boot */
182         sccc = (volatile unsigned char __iomem *) 0xffeffb0d;
183         sccd = (volatile unsigned char __iomem *) 0xffeffb08;
184         TXRDY = 0x20;
185         RXRDY = 1;
186         DLAB = 0x80;
187 #elif defined(CONFIG_405GP)
188         sccc = (volatile unsigned char __iomem *)0xef600305;
189         sccd = (volatile unsigned char __iomem *)0xef600300;
190         TXRDY = 0x20;
191         RXRDY = 1;
192         DLAB = 0x80;
193 #endif /* platform */
194 }
195
196 static int scc_initialized = 0;
197
198 void xmon_init_scc(void);
199 extern void cuda_poll(void);
200
201 static inline void do_poll_adb(void)
202 {
203 #ifdef CONFIG_ADB_PMU
204         if (sys_ctrler == SYS_CTRLER_PMU)
205                 pmu_poll_adb();
206 #endif /* CONFIG_ADB_PMU */
207 #ifdef CONFIG_ADB_CUDA
208         if (sys_ctrler == SYS_CTRLER_CUDA)
209                 cuda_poll();
210 #endif /* CONFIG_ADB_CUDA */
211 }
212
213 int xmon_write(void *ptr, int nb)
214 {
215         char *p = ptr;
216         int i, c, ct;
217
218 #ifdef CONFIG_SMP
219         static unsigned long xmon_write_lock;
220         int lock_wait = 1000000;
221         int locked;
222
223         while ((locked = test_and_set_bit(0, &xmon_write_lock)) != 0)
224                 if (--lock_wait == 0)
225                         break;
226 #endif
227
228 #ifdef CONFIG_BOOTX_TEXT
229         if (use_screen) {
230                 /* write it on the screen */
231                 for (i = 0; i < nb; ++i)
232                         btext_drawchar(*p++);
233                 goto out;
234         }
235 #endif
236         if (!scc_initialized)
237                 xmon_init_scc();
238         ct = 0;
239         for (i = 0; i < nb; ++i) {
240                 while ((*sccc & TXRDY) == 0)
241                         do_poll_adb();
242                 c = p[i];
243                 if (c == '\n' && !ct) {
244                         c = '\r';
245                         ct = 1;
246                         --i;
247                 } else {
248                         ct = 0;
249                 }
250                 buf_access();
251                 *sccd = c;
252                 eieio();
253         }
254
255  out:
256 #ifdef CONFIG_SMP
257         if (!locked)
258                 clear_bit(0, &xmon_write_lock);
259 #endif
260         return nb;
261 }
262
263 int xmon_wants_key;
264 int xmon_adb_keycode;
265
266 #ifdef CONFIG_BOOTX_TEXT
267 static int xmon_adb_shiftstate;
268
269 static unsigned char xmon_keytab[128] =
270         "asdfhgzxcv\000bqwer"                           /* 0x00 - 0x0f */
271         "yt123465=97-80]o"                              /* 0x10 - 0x1f */
272         "u[ip\rlj'k;\\,/nm."                            /* 0x20 - 0x2f */
273         "\t `\177\0\033\0\0\0\0\0\0\0\0\0\0"            /* 0x30 - 0x3f */
274         "\0.\0*\0+\0\0\0\0\0/\r\0-\0"                   /* 0x40 - 0x4f */
275         "\0\0000123456789\0\0\0";                       /* 0x50 - 0x5f */
276
277 static unsigned char xmon_shift_keytab[128] =
278         "ASDFHGZXCV\000BQWER"                           /* 0x00 - 0x0f */
279         "YT!@#$^%+(&_*)}O"                              /* 0x10 - 0x1f */
280         "U{IP\rLJ\"K:|<?NM>"                            /* 0x20 - 0x2f */
281         "\t ~\177\0\033\0\0\0\0\0\0\0\0\0\0"            /* 0x30 - 0x3f */
282         "\0.\0*\0+\0\0\0\0\0/\r\0-\0"                   /* 0x40 - 0x4f */
283         "\0\0000123456789\0\0\0";                       /* 0x50 - 0x5f */
284
285 static int xmon_get_adb_key(void)
286 {
287         int k, t, on;
288
289         xmon_wants_key = 1;
290         for (;;) {
291                 xmon_adb_keycode = -1;
292                 t = 0;
293                 on = 0;
294                 do {
295                         if (--t < 0) {
296                                 on = 1 - on;
297                                 btext_drawchar(on? 0xdb: 0x20);
298                                 btext_drawchar('\b');
299                                 t = 200000;
300                         }
301                         do_poll_adb();
302                 } while (xmon_adb_keycode == -1);
303                 k = xmon_adb_keycode;
304                 if (on)
305                         btext_drawstring(" \b");
306
307                 /* test for shift keys */
308                 if ((k & 0x7f) == 0x38 || (k & 0x7f) == 0x7b) {
309                         xmon_adb_shiftstate = (k & 0x80) == 0;
310                         continue;
311                 }
312                 if (k >= 0x80)
313                         continue;       /* ignore up transitions */
314                 k = (xmon_adb_shiftstate? xmon_shift_keytab: xmon_keytab)[k];
315                 if (k != 0)
316                         break;
317         }
318         xmon_wants_key = 0;
319         return k;
320 }
321 #endif /* CONFIG_BOOTX_TEXT */
322
323 int xmon_readchar(void)
324 {
325 #ifdef CONFIG_BOOTX_TEXT
326         if (use_screen)
327                 return xmon_get_adb_key();
328 #endif
329         if (!scc_initialized)
330                 xmon_init_scc();
331         while ((*sccc & RXRDY) == 0)
332                 do_poll_adb();
333         buf_access();
334         return *sccd;
335 }
336
337 int xmon_read_poll(void)
338 {
339         if ((*sccc & RXRDY) == 0) {
340                 do_poll_adb();
341                 return -1;
342         }
343         buf_access();
344         return *sccd;
345 }
346
347 static unsigned char scc_inittab[] = {
348     13, 0,              /* set baud rate divisor */
349     12, 1,
350     14, 1,              /* baud rate gen enable, src=rtxc */
351     11, 0x50,           /* clocks = br gen */
352     5,  0xea,           /* tx 8 bits, assert DTR & RTS */
353     4,  0x46,           /* x16 clock, 1 stop */
354     3,  0xc1,           /* rx enable, 8 bits */
355 };
356
357 void xmon_init_scc(void)
358 {
359         if ( _machine == _MACH_chrp )
360         {
361                 sccd[3] = 0x83; eieio();        /* LCR = 8N1 + DLAB */
362                 sccd[0] = 12; eieio();          /* DLL = 9600 baud */
363                 sccd[1] = 0; eieio();
364                 sccd[2] = 0; eieio();           /* FCR = 0 */
365                 sccd[3] = 3; eieio();           /* LCR = 8N1 */
366                 sccd[1] = 0; eieio();           /* IER = 0 */
367         }
368         else if ( _machine == _MACH_Pmac )
369         {
370                 int i, x;
371                 unsigned long timeout;
372
373                 if (channel_node != 0)
374                         pmac_call_feature(
375                                 PMAC_FTR_SCC_ENABLE,
376                                 channel_node,
377                                 PMAC_SCC_ASYNC | PMAC_SCC_FLAG_XMON, 1);
378                         printk(KERN_INFO "Serial port locked ON by debugger !\n");
379                 if (via_modem && channel_node != 0) {
380                         unsigned int t0;
381
382                         pmac_call_feature(
383                                 PMAC_FTR_MODEM_ENABLE,
384                                 channel_node, 0, 1);
385                         printk(KERN_INFO "Modem powered up by debugger !\n");
386                         t0 = get_tbl();
387                         timeout = 3 * tb_ticks_per_sec;
388                         if (timeout == 0)
389                                 /* assume 25MHz if tb_ticks_per_sec not set */
390                                 timeout = 75000000;
391                         while (get_tbl() - t0 < timeout)
392                                 eieio();
393                 }
394                 /* use the B channel if requested */
395                 if (xmon_use_sccb) {
396                         sccc = (volatile unsigned char *)
397                                 ((unsigned long)sccc & ~0x20);
398                         sccd = sccc + 0x10;
399                 }
400                 for (i = 20000; i != 0; --i) {
401                         x = *sccc; eieio();
402                 }
403                 *sccc = 9; eieio();             /* reset A or B side */
404                 *sccc = ((unsigned long)sccc & 0x20)? 0x80: 0x40; eieio();
405                 for (i = 0; i < sizeof(scc_inittab); ++i) {
406                         *sccc = scc_inittab[i];
407                         eieio();
408                 }
409         }
410         scc_initialized = 1;
411         if (via_modem) {
412                 for (;;) {
413                         xmon_write("ATE1V1\r", 7);
414                         if (xmon_expect("OK", 5)) {
415                                 xmon_write("ATA\r", 4);
416                                 if (xmon_expect("CONNECT", 40))
417                                         break;
418                         }
419                         xmon_write("+++", 3);
420                         xmon_expect("OK", 3);
421                 }
422         }
423 }
424
425 void xmon_enter(void)
426 {
427 #ifdef CONFIG_ADB_PMU
428         if (_machine == _MACH_Pmac) {
429                 pmu_suspend();
430         }
431 #endif
432 }
433
434 void xmon_leave(void)
435 {
436 #ifdef CONFIG_ADB_PMU
437         if (_machine == _MACH_Pmac) {
438                 pmu_resume();
439         }
440 #endif
441 }