Disintegrate asm/system.h for MN10300. Signed-off-by: David Howells <dhowells@redhat.com> cc: linux-am33-list@redhat.com
		
			
				
	
	
		
			303 lines
		
	
	
	
		
			6.9 KiB
			
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			303 lines
		
	
	
	
		
			6.9 KiB
			
		
	
	
	
		
			C
		
	
	
	
	
	
/* MN10300 On-chip serial driver for gdbstub I/O
 | 
						|
 *
 | 
						|
 * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
 | 
						|
 * Written by David Howells (dhowells@redhat.com)
 | 
						|
 *
 | 
						|
 * This program is free software; you can redistribute it and/or
 | 
						|
 * modify it under the terms of the GNU General Public Licence
 | 
						|
 * as published by the Free Software Foundation; either version
 | 
						|
 * 2 of the Licence, or (at your option) any later version.
 | 
						|
 */
 | 
						|
#include <linux/string.h>
 | 
						|
#include <linux/kernel.h>
 | 
						|
#include <linux/signal.h>
 | 
						|
#include <linux/sched.h>
 | 
						|
#include <linux/mm.h>
 | 
						|
#include <linux/console.h>
 | 
						|
#include <linux/init.h>
 | 
						|
#include <linux/tty.h>
 | 
						|
#include <asm/pgtable.h>
 | 
						|
#include <asm/gdb-stub.h>
 | 
						|
#include <asm/exceptions.h>
 | 
						|
#include <unit/clock.h>
 | 
						|
#include "mn10300-serial.h"
 | 
						|
 | 
						|
#if defined(CONFIG_GDBSTUB_ON_TTYSM0)
 | 
						|
struct mn10300_serial_port *const gdbstub_port = &mn10300_serial_port_sif0;
 | 
						|
#elif defined(CONFIG_GDBSTUB_ON_TTYSM1)
 | 
						|
struct mn10300_serial_port *const gdbstub_port = &mn10300_serial_port_sif1;
 | 
						|
#else
 | 
						|
struct mn10300_serial_port *const gdbstub_port = &mn10300_serial_port_sif2;
 | 
						|
#endif
 | 
						|
 | 
						|
 | 
						|
/*
 | 
						|
 * initialise the GDB stub I/O routines
 | 
						|
 */
 | 
						|
void __init gdbstub_io_init(void)
 | 
						|
{
 | 
						|
	uint16_t scxctr;
 | 
						|
	int tmp;
 | 
						|
 | 
						|
	switch (gdbstub_port->clock_src) {
 | 
						|
	case MNSCx_CLOCK_SRC_IOCLK:
 | 
						|
		gdbstub_port->ioclk = MN10300_IOCLK;
 | 
						|
		break;
 | 
						|
 | 
						|
#ifdef MN10300_IOBCLK
 | 
						|
	case MNSCx_CLOCK_SRC_IOBCLK:
 | 
						|
		gdbstub_port->ioclk = MN10300_IOBCLK;
 | 
						|
		break;
 | 
						|
#endif
 | 
						|
	default:
 | 
						|
		BUG();
 | 
						|
	}
 | 
						|
 | 
						|
	/* set up the serial port */
 | 
						|
	gdbstub_io_set_baud(115200);
 | 
						|
 | 
						|
	/* we want to get serial receive interrupts */
 | 
						|
	set_intr_level(gdbstub_port->rx_irq,
 | 
						|
		NUM2GxICR_LEVEL(CONFIG_DEBUGGER_IRQ_LEVEL));
 | 
						|
	set_intr_level(gdbstub_port->tx_irq,
 | 
						|
		NUM2GxICR_LEVEL(CONFIG_DEBUGGER_IRQ_LEVEL));
 | 
						|
	set_intr_stub(NUM2EXCEP_IRQ_LEVEL(CONFIG_DEBUGGER_IRQ_LEVEL),
 | 
						|
		gdbstub_io_rx_handler);
 | 
						|
 | 
						|
	*gdbstub_port->rx_icr |= GxICR_ENABLE;
 | 
						|
	tmp = *gdbstub_port->rx_icr;
 | 
						|
 | 
						|
	/* enable the device */
 | 
						|
	scxctr = SC01CTR_CLN_8BIT;	/* 1N8 */
 | 
						|
	switch (gdbstub_port->div_timer) {
 | 
						|
	case MNSCx_DIV_TIMER_16BIT:
 | 
						|
		scxctr |= SC0CTR_CK_TM8UFLOW_8; /* == SC1CTR_CK_TM9UFLOW_8
 | 
						|
						   == SC2CTR_CK_TM10UFLOW_8 */
 | 
						|
		break;
 | 
						|
 | 
						|
	case MNSCx_DIV_TIMER_8BIT:
 | 
						|
		scxctr |= SC0CTR_CK_TM2UFLOW_8;
 | 
						|
		break;
 | 
						|
	}
 | 
						|
 | 
						|
	scxctr |= SC01CTR_TXE | SC01CTR_RXE;
 | 
						|
 | 
						|
	*gdbstub_port->_control = scxctr;
 | 
						|
	tmp = *gdbstub_port->_control;
 | 
						|
 | 
						|
	/* permit level 0 IRQs only */
 | 
						|
	arch_local_change_intr_mask_level(
 | 
						|
		NUM2EPSW_IM(CONFIG_DEBUGGER_IRQ_LEVEL + 1));
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
 * set up the GDB stub serial port baud rate timers
 | 
						|
 */
 | 
						|
void gdbstub_io_set_baud(unsigned baud)
 | 
						|
{
 | 
						|
	const unsigned bits = 10; /* 1 [start] + 8 [data] + 0 [parity] +
 | 
						|
				   * 1 [stop] */
 | 
						|
	unsigned long ioclk = gdbstub_port->ioclk;
 | 
						|
	unsigned xdiv, tmp;
 | 
						|
	uint16_t tmxbr;
 | 
						|
	uint8_t tmxmd;
 | 
						|
 | 
						|
	if (!baud) {
 | 
						|
		baud = 9600;
 | 
						|
	} else if (baud == 134) {
 | 
						|
		baud = 269;	/* 134 is really 134.5 */
 | 
						|
		xdiv = 2;
 | 
						|
	}
 | 
						|
 | 
						|
try_alternative:
 | 
						|
	xdiv = 1;
 | 
						|
 | 
						|
	switch (gdbstub_port->div_timer) {
 | 
						|
	case MNSCx_DIV_TIMER_16BIT:
 | 
						|
		tmxmd = TM8MD_SRC_IOCLK;
 | 
						|
		tmxbr = tmp = (ioclk / (baud * xdiv) + 4) / 8 - 1;
 | 
						|
		if (tmp > 0 && tmp <= 65535)
 | 
						|
			goto timer_okay;
 | 
						|
 | 
						|
		tmxmd = TM8MD_SRC_IOCLK_8;
 | 
						|
		tmxbr = tmp = (ioclk / (baud * 8 * xdiv) + 4) / 8 - 1;
 | 
						|
		if (tmp > 0 && tmp <= 65535)
 | 
						|
			goto timer_okay;
 | 
						|
 | 
						|
		tmxmd = TM8MD_SRC_IOCLK_32;
 | 
						|
		tmxbr = tmp = (ioclk / (baud * 32 * xdiv) + 4) / 8 - 1;
 | 
						|
		if (tmp > 0 && tmp <= 65535)
 | 
						|
			goto timer_okay;
 | 
						|
 | 
						|
		break;
 | 
						|
 | 
						|
	case MNSCx_DIV_TIMER_8BIT:
 | 
						|
		tmxmd = TM2MD_SRC_IOCLK;
 | 
						|
		tmxbr = tmp = (ioclk / (baud * xdiv) + 4) / 8 - 1;
 | 
						|
		if (tmp > 0 && tmp <= 255)
 | 
						|
			goto timer_okay;
 | 
						|
 | 
						|
		tmxmd = TM2MD_SRC_IOCLK_8;
 | 
						|
		tmxbr = tmp = (ioclk / (baud * 8 * xdiv) + 4) / 8 - 1;
 | 
						|
		if (tmp > 0 && tmp <= 255)
 | 
						|
			goto timer_okay;
 | 
						|
 | 
						|
		tmxmd = TM2MD_SRC_IOCLK_32;
 | 
						|
		tmxbr = tmp = (ioclk / (baud * 32 * xdiv) + 4) / 8 - 1;
 | 
						|
		if (tmp > 0 && tmp <= 255)
 | 
						|
			goto timer_okay;
 | 
						|
		break;
 | 
						|
	}
 | 
						|
 | 
						|
	/* as a last resort, if the quotient is zero, default to 9600 bps */
 | 
						|
	baud = 9600;
 | 
						|
	goto try_alternative;
 | 
						|
 | 
						|
timer_okay:
 | 
						|
	gdbstub_port->uart.timeout = (2 * bits * HZ) / baud;
 | 
						|
	gdbstub_port->uart.timeout += HZ / 50;
 | 
						|
 | 
						|
	/* set the timer to produce the required baud rate */
 | 
						|
	switch (gdbstub_port->div_timer) {
 | 
						|
	case MNSCx_DIV_TIMER_16BIT:
 | 
						|
		*gdbstub_port->_tmxmd = 0;
 | 
						|
		*gdbstub_port->_tmxbr = tmxbr;
 | 
						|
		*gdbstub_port->_tmxmd = TM8MD_INIT_COUNTER;
 | 
						|
		*gdbstub_port->_tmxmd = tmxmd | TM8MD_COUNT_ENABLE;
 | 
						|
		break;
 | 
						|
 | 
						|
	case MNSCx_DIV_TIMER_8BIT:
 | 
						|
		*gdbstub_port->_tmxmd = 0;
 | 
						|
		*(volatile u8 *) gdbstub_port->_tmxbr = (u8)tmxbr;
 | 
						|
		*gdbstub_port->_tmxmd = TM2MD_INIT_COUNTER;
 | 
						|
		*gdbstub_port->_tmxmd = tmxmd | TM2MD_COUNT_ENABLE;
 | 
						|
		break;
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
 * wait for a character to come from the debugger
 | 
						|
 */
 | 
						|
int gdbstub_io_rx_char(unsigned char *_ch, int nonblock)
 | 
						|
{
 | 
						|
	unsigned ix;
 | 
						|
	u8 ch, st;
 | 
						|
#if defined(CONFIG_MN10300_WD_TIMER)
 | 
						|
	int cpu;
 | 
						|
#endif
 | 
						|
 | 
						|
	*_ch = 0xff;
 | 
						|
 | 
						|
	if (gdbstub_rx_unget) {
 | 
						|
		*_ch = gdbstub_rx_unget;
 | 
						|
		gdbstub_rx_unget = 0;
 | 
						|
		return 0;
 | 
						|
	}
 | 
						|
 | 
						|
try_again:
 | 
						|
	/* pull chars out of the buffer */
 | 
						|
	ix = gdbstub_rx_outp;
 | 
						|
	barrier();
 | 
						|
	if (ix == gdbstub_rx_inp) {
 | 
						|
		if (nonblock)
 | 
						|
			return -EAGAIN;
 | 
						|
#ifdef CONFIG_MN10300_WD_TIMER
 | 
						|
	for (cpu = 0; cpu < NR_CPUS; cpu++)
 | 
						|
		watchdog_alert_counter[cpu] = 0;
 | 
						|
#endif
 | 
						|
		goto try_again;
 | 
						|
	}
 | 
						|
 | 
						|
	ch = gdbstub_rx_buffer[ix++];
 | 
						|
	st = gdbstub_rx_buffer[ix++];
 | 
						|
	barrier();
 | 
						|
	gdbstub_rx_outp = ix & (PAGE_SIZE - 1);
 | 
						|
 | 
						|
	st &= SC01STR_RXF | SC01STR_RBF | SC01STR_FEF | SC01STR_PEF |
 | 
						|
		SC01STR_OEF;
 | 
						|
 | 
						|
	/* deal with what we've got
 | 
						|
	 * - note that the UART doesn't do BREAK-detection for us
 | 
						|
	 */
 | 
						|
	if (st & SC01STR_FEF && ch == 0) {
 | 
						|
		switch (gdbstub_port->rx_brk) {
 | 
						|
		case 0:	gdbstub_port->rx_brk = 1;	goto try_again;
 | 
						|
		case 1:	gdbstub_port->rx_brk = 2;	goto try_again;
 | 
						|
		case 2:
 | 
						|
			gdbstub_port->rx_brk = 3;
 | 
						|
			gdbstub_proto("### GDB MNSERIAL Rx Break Detected"
 | 
						|
				      " ###\n");
 | 
						|
			return -EINTR;
 | 
						|
		default:
 | 
						|
			goto try_again;
 | 
						|
		}
 | 
						|
	} else if (st & SC01STR_FEF) {
 | 
						|
		if (gdbstub_port->rx_brk)
 | 
						|
			goto try_again;
 | 
						|
 | 
						|
		gdbstub_proto("### GDB MNSERIAL Framing Error ###\n");
 | 
						|
		return -EIO;
 | 
						|
	} else if (st & SC01STR_OEF) {
 | 
						|
		if (gdbstub_port->rx_brk)
 | 
						|
			goto try_again;
 | 
						|
 | 
						|
		gdbstub_proto("### GDB MNSERIAL Overrun Error ###\n");
 | 
						|
		return -EIO;
 | 
						|
	} else if (st & SC01STR_PEF) {
 | 
						|
		if (gdbstub_port->rx_brk)
 | 
						|
			goto try_again;
 | 
						|
 | 
						|
		gdbstub_proto("### GDB MNSERIAL Parity Error ###\n");
 | 
						|
		return -EIO;
 | 
						|
	} else {
 | 
						|
		/* look for the tail-end char on a break run */
 | 
						|
		if (gdbstub_port->rx_brk == 3) {
 | 
						|
			switch (ch) {
 | 
						|
			case 0xFF:
 | 
						|
			case 0xFE:
 | 
						|
			case 0xFC:
 | 
						|
			case 0xF8:
 | 
						|
			case 0xF0:
 | 
						|
			case 0xE0:
 | 
						|
			case 0xC0:
 | 
						|
			case 0x80:
 | 
						|
			case 0x00:
 | 
						|
				gdbstub_port->rx_brk = 0;
 | 
						|
				goto try_again;
 | 
						|
			default:
 | 
						|
				break;
 | 
						|
			}
 | 
						|
		}
 | 
						|
 | 
						|
		gdbstub_port->rx_brk = 0;
 | 
						|
		gdbstub_io("### GDB Rx %02x (st=%02x) ###\n", ch, st);
 | 
						|
		*_ch = ch & 0x7f;
 | 
						|
		return 0;
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
 * send a character to the debugger
 | 
						|
 */
 | 
						|
void gdbstub_io_tx_char(unsigned char ch)
 | 
						|
{
 | 
						|
	while (*gdbstub_port->_status & SC01STR_TBF)
 | 
						|
		continue;
 | 
						|
 | 
						|
	if (ch == 0x0a) {
 | 
						|
		*(u8 *) gdbstub_port->_txb = 0x0d;
 | 
						|
		while (*gdbstub_port->_status & SC01STR_TBF)
 | 
						|
			continue;
 | 
						|
	}
 | 
						|
 | 
						|
	*(u8 *) gdbstub_port->_txb = ch;
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
 * flush the transmission buffers
 | 
						|
 */
 | 
						|
void gdbstub_io_tx_flush(void)
 | 
						|
{
 | 
						|
	while (*gdbstub_port->_status & (SC01STR_TBF | SC01STR_TXF))
 | 
						|
		continue;
 | 
						|
}
 |