d74a883e5bdeab5b82e1069e6cae3fe038c1472d
[linux-3.10.git] / arch / ppc / xmon / start.c
1 /*
2  * Copyright (C) 1996 Paul Mackerras.
3  */
4 #include <linux/string.h>
5 #include <asm/machdep.h>
6 #include <asm/io.h>
7 #include <asm/page.h>
8 #include <linux/kernel.h>
9 #include <linux/errno.h>
10 #include <linux/sysrq.h>
11 #include <linux/bitops.h>
12 #include <asm/xmon.h>
13 #include <asm/machdep.h>
14 #include <asm/errno.h>
15 #include <asm/processor.h>
16 #include <asm/delay.h>
17 #include <asm/btext.h>
18 #include <asm/ibm4xx.h>
19
20 static volatile unsigned char *sccc, *sccd;
21 unsigned int TXRDY, RXRDY, DLAB;
22 static int xmon_expect(const char *str, unsigned int timeout);
23
24 static int via_modem;
25
26 #define TB_SPEED        25000000
27
28 static inline unsigned int readtb(void)
29 {
30         unsigned int ret;
31
32         asm volatile("mftb %0" : "=r" (ret) :);
33         return ret;
34 }
35
36 void buf_access(void)
37 {
38         if (DLAB)
39                 sccd[3] &= ~DLAB;       /* reset DLAB */
40 }
41
42
43 #ifdef CONFIG_MAGIC_SYSRQ
44 static void sysrq_handle_xmon(int key, struct pt_regs *regs,
45                               struct tty_struct *tty)
46 {
47         xmon(regs);
48 }
49
50 static struct sysrq_key_op sysrq_xmon_op =
51 {
52         .handler =      sysrq_handle_xmon,
53         .help_msg =     "Xmon",
54         .action_msg =   "Entering xmon",
55 };
56 #endif
57
58 void
59 xmon_map_scc(void)
60 {
61 #if defined(CONFIG_GEMINI)
62         /* should already be mapped by the kernel boot */
63         sccd = (volatile unsigned char *) 0xffeffb08;
64 #elif defined(CONFIG_405GP)
65         sccd = (volatile unsigned char *)0xef600300;
66 #elif defined(CONFIG_440EP)
67         sccd = (volatile unsigned char *) ioremap(PPC440EP_UART0_ADDR, 8);
68 #elif defined(CONFIG_440SP)
69         sccd = (volatile unsigned char *) ioremap64(PPC440SP_UART0_ADDR, 8);
70 #elif defined(CONFIG_440SPE)
71         sccd = (volatile unsigned char *) ioremap64(PPC440SPE_UART0_ADDR, 8);
72 #elif defined(CONFIG_44x)
73         /* This is the default for 44x platforms.  Any boards that have a
74            different UART address need to be put in cases before this or the
75            port will be mapped incorrectly */
76         sccd = (volatile unsigned char *) ioremap64(PPC440GP_UART0_ADDR, 8);
77 #endif /* platform */
78
79 #ifndef CONFIG_PPC_PREP
80         sccc = sccd + 5;
81         TXRDY = 0x20;
82         RXRDY = 1;
83         DLAB = 0x80;
84 #endif
85
86         register_sysrq_key('x', &sysrq_xmon_op);
87 }
88
89 static int scc_initialized;
90
91 void xmon_init_scc(void);
92
93 int
94 xmon_write(void *handle, void *ptr, int nb)
95 {
96         char *p = ptr;
97         int i, c, ct;
98
99 #ifdef CONFIG_SMP
100         static unsigned long xmon_write_lock;
101         int lock_wait = 1000000;
102         int locked;
103
104         while ((locked = test_and_set_bit(0, &xmon_write_lock)) != 0)
105                 if (--lock_wait == 0)
106                         break;
107 #endif
108
109         if (!scc_initialized)
110                 xmon_init_scc();
111         ct = 0;
112         for (i = 0; i < nb; ++i) {
113                 while ((*sccc & TXRDY) == 0)
114                         ;
115                 c = p[i];
116                 if (c == '\n' && !ct) {
117                         c = '\r';
118                         ct = 1;
119                         --i;
120                 } else {
121                         ct = 0;
122                 }
123                 buf_access();
124                 *sccd = c;
125                 eieio();
126         }
127
128 #ifdef CONFIG_SMP
129         if (!locked)
130                 clear_bit(0, &xmon_write_lock);
131 #endif
132         return nb;
133 }
134
135 int xmon_wants_key;
136
137
138 int
139 xmon_read(void *handle, void *ptr, int nb)
140 {
141     char *p = ptr;
142     int i;
143
144     if (!scc_initialized)
145         xmon_init_scc();
146     for (i = 0; i < nb; ++i) {
147         while ((*sccc & RXRDY) == 0)
148             ;
149         buf_access();
150         *p++ = *sccd;
151     }
152     return i;
153 }
154
155 int
156 xmon_read_poll(void)
157 {
158         if ((*sccc & RXRDY) == 0) {
159                 ;
160                 return -1;
161         }
162         buf_access();
163         return *sccd;
164 }
165
166 void
167 xmon_init_scc(void)
168 {
169         scc_initialized = 1;
170         if (via_modem) {
171                 for (;;) {
172                         xmon_write(NULL, "ATE1V1\r", 7);
173                         if (xmon_expect("OK", 5)) {
174                                 xmon_write(NULL, "ATA\r", 4);
175                                 if (xmon_expect("CONNECT", 40))
176                                         break;
177                         }
178                         xmon_write(NULL, "+++", 3);
179                         xmon_expect("OK", 3);
180                 }
181         }
182 }
183
184
185 void *xmon_stdin;
186 void *xmon_stdout;
187 void *xmon_stderr;
188
189 void
190 xmon_init(int arg)
191 {
192         xmon_map_scc();
193 }
194
195 int
196 xmon_putc(int c, void *f)
197 {
198     char ch = c;
199
200     if (c == '\n')
201         xmon_putc('\r', f);
202     return xmon_write(f, &ch, 1) == 1? c: -1;
203 }
204
205 int
206 xmon_putchar(int c)
207 {
208     return xmon_putc(c, xmon_stdout);
209 }
210
211 int
212 xmon_fputs(char *str, void *f)
213 {
214     int n = strlen(str);
215
216     return xmon_write(f, str, n) == n? 0: -1;
217 }
218
219 int
220 xmon_readchar(void)
221 {
222     char ch;
223
224     for (;;) {
225         switch (xmon_read(xmon_stdin, &ch, 1)) {
226         case 1:
227             return ch;
228         case -1:
229             xmon_printf("read(stdin) returned -1\r\n", 0, 0);
230             return -1;
231         }
232     }
233 }
234
235 static char line[256];
236 static char *lineptr;
237 static int lineleft;
238
239 int xmon_expect(const char *str, unsigned int timeout)
240 {
241         int c;
242         unsigned int t0;
243
244         timeout *= TB_SPEED;
245         t0 = readtb();
246         do {
247                 lineptr = line;
248                 for (;;) {
249                         c = xmon_read_poll();
250                         if (c == -1) {
251                                 if (readtb() - t0 > timeout)
252                                         return 0;
253                                 continue;
254                         }
255                         if (c == '\n')
256                                 break;
257                         if (c != '\r' && lineptr < &line[sizeof(line) - 1])
258                                 *lineptr++ = c;
259                 }
260                 *lineptr = 0;
261         } while (strstr(line, str) == NULL);
262         return 1;
263 }
264
265 int
266 xmon_getchar(void)
267 {
268     int c;
269
270     if (lineleft == 0) {
271         lineptr = line;
272         for (;;) {
273             c = xmon_readchar();
274             if (c == -1 || c == 4)
275                 break;
276             if (c == '\r' || c == '\n') {
277                 *lineptr++ = '\n';
278                 xmon_putchar('\n');
279                 break;
280             }
281             switch (c) {
282             case 0177:
283             case '\b':
284                 if (lineptr > line) {
285                     xmon_putchar('\b');
286                     xmon_putchar(' ');
287                     xmon_putchar('\b');
288                     --lineptr;
289                 }
290                 break;
291             case 'U' & 0x1F:
292                 while (lineptr > line) {
293                     xmon_putchar('\b');
294                     xmon_putchar(' ');
295                     xmon_putchar('\b');
296                     --lineptr;
297                 }
298                 break;
299             default:
300                 if (lineptr >= &line[sizeof(line) - 1])
301                     xmon_putchar('\a');
302                 else {
303                     xmon_putchar(c);
304                     *lineptr++ = c;
305                 }
306             }
307         }
308         lineleft = lineptr - line;
309         lineptr = line;
310     }
311     if (lineleft == 0)
312         return -1;
313     --lineleft;
314     return *lineptr++;
315 }
316
317 char *
318 xmon_fgets(char *str, int nb, void *f)
319 {
320     char *p;
321     int c;
322
323     for (p = str; p < str + nb - 1; ) {
324         c = xmon_getchar();
325         if (c == -1) {
326             if (p == str)
327                 return NULL;
328             break;
329         }
330         *p++ = c;
331         if (c == '\n')
332             break;
333     }
334     *p = 0;
335     return str;
336 }
337
338 void
339 xmon_enter(void)
340 {
341 }
342
343 void
344 xmon_leave(void)
345 {
346 }