aboutsummaryrefslogtreecommitdiffstats
path: root/arch/mn10300/kernel/gdb-io-ttysm.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/mn10300/kernel/gdb-io-ttysm.c')
-rw-r--r--arch/mn10300/kernel/gdb-io-ttysm.c299
1 files changed, 299 insertions, 0 deletions
diff --git a/arch/mn10300/kernel/gdb-io-ttysm.c b/arch/mn10300/kernel/gdb-io-ttysm.c
new file mode 100644
index 000000000000..c5451592d403
--- /dev/null
+++ b/arch/mn10300/kernel/gdb-io-ttysm.c
@@ -0,0 +1,299 @@
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)
27struct mn10300_serial_port *const gdbstub_port = &mn10300_serial_port_sif0;
28#elif defined(CONFIG_GDBSTUB_ON_TTYSM1)
29struct mn10300_serial_port *const gdbstub_port = &mn10300_serial_port_sif1;
30#else
31struct mn10300_serial_port *const gdbstub_port = &mn10300_serial_port_sif2;
32#endif
33
34
35/*
36 * initialise the GDB stub I/O routines
37 */
38void __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 */
98void 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
114try_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
158timer_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 */
183int 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
196try_again:
197 /* pull chars out of the buffer */
198 ix = gdbstub_rx_outp;
199 if (ix == gdbstub_rx_inp) {
200 if (nonblock)
201 return -EAGAIN;
202#ifdef CONFIG_MN10300_WD_TIMER
203 watchdog_alert_counter = 0;
204#endif /* CONFIG_MN10300_WD_TIMER */
205 goto try_again;
206 }
207
208 ch = gdbstub_rx_buffer[ix++];
209 st = gdbstub_rx_buffer[ix++];
210 gdbstub_rx_outp = ix & (PAGE_SIZE - 1);
211
212 st &= SC01STR_RXF | SC01STR_RBF | SC01STR_FEF | SC01STR_PEF |
213 SC01STR_OEF;
214
215 /* deal with what we've got
216 * - note that the UART doesn't do BREAK-detection for us
217 */
218 if (st & SC01STR_FEF && ch == 0) {
219 switch (gdbstub_port->rx_brk) {
220 case 0: gdbstub_port->rx_brk = 1; goto try_again;
221 case 1: gdbstub_port->rx_brk = 2; goto try_again;
222 case 2:
223 gdbstub_port->rx_brk = 3;
224 gdbstub_proto("### GDB MNSERIAL Rx Break Detected"
225 " ###\n");
226 return -EINTR;
227 default:
228 goto try_again;
229 }
230 } else if (st & SC01STR_FEF) {
231 if (gdbstub_port->rx_brk)
232 goto try_again;
233
234 gdbstub_proto("### GDB MNSERIAL Framing Error ###\n");
235 return -EIO;
236 } else if (st & SC01STR_OEF) {
237 if (gdbstub_port->rx_brk)
238 goto try_again;
239
240 gdbstub_proto("### GDB MNSERIAL Overrun Error ###\n");
241 return -EIO;
242 } else if (st & SC01STR_PEF) {
243 if (gdbstub_port->rx_brk)
244 goto try_again;
245
246 gdbstub_proto("### GDB MNSERIAL Parity Error ###\n");
247 return -EIO;
248 } else {
249 /* look for the tail-end char on a break run */
250 if (gdbstub_port->rx_brk == 3) {
251 switch (ch) {
252 case 0xFF:
253 case 0xFE:
254 case 0xFC:
255 case 0xF8:
256 case 0xF0:
257 case 0xE0:
258 case 0xC0:
259 case 0x80:
260 case 0x00:
261 gdbstub_port->rx_brk = 0;
262 goto try_again;
263 default:
264 break;
265 }
266 }
267
268 gdbstub_port->rx_brk = 0;
269 gdbstub_io("### GDB Rx %02x (st=%02x) ###\n", ch, st);
270 *_ch = ch & 0x7f;
271 return 0;
272 }
273}
274
275/*
276 * send a character to the debugger
277 */
278void gdbstub_io_tx_char(unsigned char ch)
279{
280 while (*gdbstub_port->_status & SC01STR_TBF)
281 continue;
282
283 if (ch == 0x0a) {
284 *(u8 *) gdbstub_port->_txb = 0x0d;
285 while (*gdbstub_port->_status & SC01STR_TBF)
286 continue;
287 }
288
289 *(u8 *) gdbstub_port->_txb = ch;
290}
291
292/*
293 * flush the transmission buffers
294 */
295void gdbstub_io_tx_flush(void)
296{
297 while (*gdbstub_port->_status & (SC01STR_TBF | SC01STR_TXF))
298 continue;
299}