Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound-2.6
[linux-2.6] / arch / mn10300 / kernel / gdb-io-ttysm.c
1 /* MN10300 On-chip serial driver for gdbstub I/O
2  *
3  * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
4  * Written by David Howells (dhowells@redhat.com)
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public Licence
8  * as published by the Free Software Foundation; either version
9  * 2 of the Licence, or (at your option) any later version.
10  */
11 #include <linux/string.h>
12 #include <linux/kernel.h>
13 #include <linux/signal.h>
14 #include <linux/sched.h>
15 #include <linux/mm.h>
16 #include <linux/console.h>
17 #include <linux/init.h>
18 #include <linux/tty.h>
19 #include <asm/pgtable.h>
20 #include <asm/system.h>
21 #include <asm/gdb-stub.h>
22 #include <asm/exceptions.h>
23 #include <asm/unit/clock.h>
24 #include "mn10300-serial.h"
25
26 #if defined(CONFIG_GDBSTUB_ON_TTYSM0)
27 struct mn10300_serial_port *const gdbstub_port = &mn10300_serial_port_sif0;
28 #elif defined(CONFIG_GDBSTUB_ON_TTYSM1)
29 struct mn10300_serial_port *const gdbstub_port = &mn10300_serial_port_sif1;
30 #else
31 struct mn10300_serial_port *const gdbstub_port = &mn10300_serial_port_sif2;
32 #endif
33
34
35 /*
36  * initialise the GDB stub I/O routines
37  */
38 void __init gdbstub_io_init(void)
39 {
40         uint16_t scxctr;
41         int tmp;
42
43         switch (gdbstub_port->clock_src) {
44         case MNSCx_CLOCK_SRC_IOCLK:
45                 gdbstub_port->ioclk = MN10300_IOCLK;
46                 break;
47
48 #ifdef MN10300_IOBCLK
49         case MNSCx_CLOCK_SRC_IOBCLK:
50                 gdbstub_port->ioclk = MN10300_IOBCLK;
51                 break;
52 #endif
53         default:
54                 BUG();
55         }
56
57         /* set up the serial port */
58         gdbstub_io_set_baud(115200);
59
60         /* we want to get serial receive interrupts */
61         set_intr_level(gdbstub_port->rx_irq, GxICR_LEVEL_0);
62         set_intr_level(gdbstub_port->tx_irq, GxICR_LEVEL_0);
63         set_intr_stub(EXCEP_IRQ_LEVEL0, gdbstub_io_rx_handler);
64
65         *gdbstub_port->rx_icr |= GxICR_ENABLE;
66         tmp = *gdbstub_port->rx_icr;
67
68         /* enable the device */
69         scxctr = SC01CTR_CLN_8BIT;      /* 1N8 */
70         switch (gdbstub_port->div_timer) {
71         case MNSCx_DIV_TIMER_16BIT:
72                 scxctr |= SC0CTR_CK_TM8UFLOW_8; /* == SC1CTR_CK_TM9UFLOW_8
73                                                    == SC2CTR_CK_TM10UFLOW_8 */
74                 break;
75
76         case MNSCx_DIV_TIMER_8BIT:
77                 scxctr |= SC0CTR_CK_TM2UFLOW_8;
78                 break;
79         }
80
81         scxctr |= SC01CTR_TXE | SC01CTR_RXE;
82
83         *gdbstub_port->_control = scxctr;
84         tmp = *gdbstub_port->_control;
85
86         /* permit level 0 IRQs only */
87         asm volatile(
88                 "       and %0,epsw     \n"
89                 "       or %1,epsw      \n"
90                 :
91                 : "i"(~EPSW_IM), "i"(EPSW_IE|EPSW_IM_1)
92                 );
93 }
94
95 /*
96  * set up the GDB stub serial port baud rate timers
97  */
98 void gdbstub_io_set_baud(unsigned baud)
99 {
100         const unsigned bits = 10; /* 1 [start] + 8 [data] + 0 [parity] +
101                                    * 1 [stop] */
102         unsigned long ioclk = gdbstub_port->ioclk;
103         unsigned xdiv, tmp;
104         uint16_t tmxbr;
105         uint8_t tmxmd;
106
107         if (!baud) {
108                 baud = 9600;
109         } else if (baud == 134) {
110                 baud = 269;     /* 134 is really 134.5 */
111                 xdiv = 2;
112         }
113
114 try_alternative:
115         xdiv = 1;
116
117         switch (gdbstub_port->div_timer) {
118         case MNSCx_DIV_TIMER_16BIT:
119                 tmxmd = TM8MD_SRC_IOCLK;
120                 tmxbr = tmp = (ioclk / (baud * xdiv) + 4) / 8 - 1;
121                 if (tmp > 0 && tmp <= 65535)
122                         goto timer_okay;
123
124                 tmxmd = TM8MD_SRC_IOCLK_8;
125                 tmxbr = tmp = (ioclk / (baud * 8 * xdiv) + 4) / 8 - 1;
126                 if (tmp > 0 && tmp <= 65535)
127                         goto timer_okay;
128
129                 tmxmd = TM8MD_SRC_IOCLK_32;
130                 tmxbr = tmp = (ioclk / (baud * 32 * xdiv) + 4) / 8 - 1;
131                 if (tmp > 0 && tmp <= 65535)
132                         goto timer_okay;
133
134                 break;
135
136         case MNSCx_DIV_TIMER_8BIT:
137                 tmxmd = TM2MD_SRC_IOCLK;
138                 tmxbr = tmp = (ioclk / (baud * xdiv) + 4) / 8 - 1;
139                 if (tmp > 0 && tmp <= 255)
140                         goto timer_okay;
141
142                 tmxmd = TM2MD_SRC_IOCLK_8;
143                 tmxbr = tmp = (ioclk / (baud * 8 * xdiv) + 4) / 8 - 1;
144                 if (tmp > 0 && tmp <= 255)
145                         goto timer_okay;
146
147                 tmxmd = TM2MD_SRC_IOCLK_32;
148                 tmxbr = tmp = (ioclk / (baud * 32 * xdiv) + 4) / 8 - 1;
149                 if (tmp > 0 && tmp <= 255)
150                         goto timer_okay;
151                 break;
152         }
153
154         /* as a last resort, if the quotient is zero, default to 9600 bps */
155         baud = 9600;
156         goto try_alternative;
157
158 timer_okay:
159         gdbstub_port->uart.timeout = (2 * bits * HZ) / baud;
160         gdbstub_port->uart.timeout += HZ / 50;
161
162         /* set the timer to produce the required baud rate */
163         switch (gdbstub_port->div_timer) {
164         case MNSCx_DIV_TIMER_16BIT:
165                 *gdbstub_port->_tmxmd = 0;
166                 *gdbstub_port->_tmxbr = tmxbr;
167                 *gdbstub_port->_tmxmd = TM8MD_INIT_COUNTER;
168                 *gdbstub_port->_tmxmd = tmxmd | TM8MD_COUNT_ENABLE;
169                 break;
170
171         case MNSCx_DIV_TIMER_8BIT:
172                 *gdbstub_port->_tmxmd = 0;
173                 *(volatile u8 *) gdbstub_port->_tmxbr = (u8)tmxbr;
174                 *gdbstub_port->_tmxmd = TM2MD_INIT_COUNTER;
175                 *gdbstub_port->_tmxmd = tmxmd | TM2MD_COUNT_ENABLE;
176                 break;
177         }
178 }
179
180 /*
181  * wait for a character to come from the debugger
182  */
183 int gdbstub_io_rx_char(unsigned char *_ch, int nonblock)
184 {
185         unsigned ix;
186         u8 ch, st;
187
188         *_ch = 0xff;
189
190         if (gdbstub_rx_unget) {
191                 *_ch = gdbstub_rx_unget;
192                 gdbstub_rx_unget = 0;
193                 return 0;
194         }
195
196 try_again:
197         /* pull chars out of the buffer */
198         ix = gdbstub_rx_outp;
199         barrier();
200         if (ix == gdbstub_rx_inp) {
201                 if (nonblock)
202                         return -EAGAIN;
203 #ifdef CONFIG_MN10300_WD_TIMER
204                 watchdog_alert_counter = 0;
205 #endif /* CONFIG_MN10300_WD_TIMER */
206                 goto try_again;
207         }
208
209         ch = gdbstub_rx_buffer[ix++];
210         st = gdbstub_rx_buffer[ix++];
211         barrier();
212         gdbstub_rx_outp = ix & (PAGE_SIZE - 1);
213
214         st &= SC01STR_RXF | SC01STR_RBF | SC01STR_FEF | SC01STR_PEF |
215                 SC01STR_OEF;
216
217         /* deal with what we've got
218          * - note that the UART doesn't do BREAK-detection for us
219          */
220         if (st & SC01STR_FEF && ch == 0) {
221                 switch (gdbstub_port->rx_brk) {
222                 case 0: gdbstub_port->rx_brk = 1;       goto try_again;
223                 case 1: gdbstub_port->rx_brk = 2;       goto try_again;
224                 case 2:
225                         gdbstub_port->rx_brk = 3;
226                         gdbstub_proto("### GDB MNSERIAL Rx Break Detected"
227                                       " ###\n");
228                         return -EINTR;
229                 default:
230                         goto try_again;
231                 }
232         } else if (st & SC01STR_FEF) {
233                 if (gdbstub_port->rx_brk)
234                         goto try_again;
235
236                 gdbstub_proto("### GDB MNSERIAL Framing Error ###\n");
237                 return -EIO;
238         } else if (st & SC01STR_OEF) {
239                 if (gdbstub_port->rx_brk)
240                         goto try_again;
241
242                 gdbstub_proto("### GDB MNSERIAL Overrun Error ###\n");
243                 return -EIO;
244         } else if (st & SC01STR_PEF) {
245                 if (gdbstub_port->rx_brk)
246                         goto try_again;
247
248                 gdbstub_proto("### GDB MNSERIAL Parity Error ###\n");
249                 return -EIO;
250         } else {
251                 /* look for the tail-end char on a break run */
252                 if (gdbstub_port->rx_brk == 3) {
253                         switch (ch) {
254                         case 0xFF:
255                         case 0xFE:
256                         case 0xFC:
257                         case 0xF8:
258                         case 0xF0:
259                         case 0xE0:
260                         case 0xC0:
261                         case 0x80:
262                         case 0x00:
263                                 gdbstub_port->rx_brk = 0;
264                                 goto try_again;
265                         default:
266                                 break;
267                         }
268                 }
269
270                 gdbstub_port->rx_brk = 0;
271                 gdbstub_io("### GDB Rx %02x (st=%02x) ###\n", ch, st);
272                 *_ch = ch & 0x7f;
273                 return 0;
274         }
275 }
276
277 /*
278  * send a character to the debugger
279  */
280 void gdbstub_io_tx_char(unsigned char ch)
281 {
282         while (*gdbstub_port->_status & SC01STR_TBF)
283                 continue;
284
285         if (ch == 0x0a) {
286                 *(u8 *) gdbstub_port->_txb = 0x0d;
287                 while (*gdbstub_port->_status & SC01STR_TBF)
288                         continue;
289         }
290
291         *(u8 *) gdbstub_port->_txb = ch;
292 }
293
294 /*
295  * flush the transmission buffers
296  */
297 void gdbstub_io_tx_flush(void)
298 {
299         while (*gdbstub_port->_status & (SC01STR_TBF | SC01STR_TXF))
300                 continue;
301 }