• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /asuswrt-rt-n18u-9.0.0.4.380.2695/release/src-rt-6.x.4708/linux/linux-2.6/arch/mn10300/kernel/
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 <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	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 */
280void 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 */
297void gdbstub_io_tx_flush(void)
298{
299	while (*gdbstub_port->_status & (SC01STR_TBF | SC01STR_TXF))
300		continue;
301}
302