PageRenderTime 30ms CodeModel.GetById 11ms app.highlight 15ms RepoModel.GetById 1ms app.codeStats 0ms

/arch/mn10300/kernel/gdb-io-ttysm.c

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