Path: blob/master/arch/mn10300/kernel/gdb-io-ttysm.c
10817 views
/* MN10300 On-chip serial driver for gdbstub I/O1*2* Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.3* Written by David Howells ([email protected])4*5* This program is free software; you can redistribute it and/or6* modify it under the terms of the GNU General Public Licence7* as published by the Free Software Foundation; either version8* 2 of the Licence, or (at your option) any later version.9*/10#include <linux/string.h>11#include <linux/kernel.h>12#include <linux/signal.h>13#include <linux/sched.h>14#include <linux/mm.h>15#include <linux/console.h>16#include <linux/init.h>17#include <linux/tty.h>18#include <asm/pgtable.h>19#include <asm/system.h>20#include <asm/gdb-stub.h>21#include <asm/exceptions.h>22#include <unit/clock.h>23#include "mn10300-serial.h"2425#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#else30struct mn10300_serial_port *const gdbstub_port = &mn10300_serial_port_sif2;31#endif323334/*35* initialise the GDB stub I/O routines36*/37void __init gdbstub_io_init(void)38{39uint16_t scxctr;40int tmp;4142switch (gdbstub_port->clock_src) {43case MNSCx_CLOCK_SRC_IOCLK:44gdbstub_port->ioclk = MN10300_IOCLK;45break;4647#ifdef MN10300_IOBCLK48case MNSCx_CLOCK_SRC_IOBCLK:49gdbstub_port->ioclk = MN10300_IOBCLK;50break;51#endif52default:53BUG();54}5556/* set up the serial port */57gdbstub_io_set_baud(115200);5859/* we want to get serial receive interrupts */60set_intr_level(gdbstub_port->rx_irq,61NUM2GxICR_LEVEL(CONFIG_DEBUGGER_IRQ_LEVEL));62set_intr_level(gdbstub_port->tx_irq,63NUM2GxICR_LEVEL(CONFIG_DEBUGGER_IRQ_LEVEL));64set_intr_stub(NUM2EXCEP_IRQ_LEVEL(CONFIG_DEBUGGER_IRQ_LEVEL),65gdbstub_io_rx_handler);6667*gdbstub_port->rx_icr |= GxICR_ENABLE;68tmp = *gdbstub_port->rx_icr;6970/* enable the device */71scxctr = SC01CTR_CLN_8BIT; /* 1N8 */72switch (gdbstub_port->div_timer) {73case MNSCx_DIV_TIMER_16BIT:74scxctr |= SC0CTR_CK_TM8UFLOW_8; /* == SC1CTR_CK_TM9UFLOW_875== SC2CTR_CK_TM10UFLOW_8 */76break;7778case MNSCx_DIV_TIMER_8BIT:79scxctr |= SC0CTR_CK_TM2UFLOW_8;80break;81}8283scxctr |= SC01CTR_TXE | SC01CTR_RXE;8485*gdbstub_port->_control = scxctr;86tmp = *gdbstub_port->_control;8788/* permit level 0 IRQs only */89arch_local_change_intr_mask_level(90NUM2EPSW_IM(CONFIG_DEBUGGER_IRQ_LEVEL + 1));91}9293/*94* set up the GDB stub serial port baud rate timers95*/96void gdbstub_io_set_baud(unsigned baud)97{98const unsigned bits = 10; /* 1 [start] + 8 [data] + 0 [parity] +99* 1 [stop] */100unsigned long ioclk = gdbstub_port->ioclk;101unsigned xdiv, tmp;102uint16_t tmxbr;103uint8_t tmxmd;104105if (!baud) {106baud = 9600;107} else if (baud == 134) {108baud = 269; /* 134 is really 134.5 */109xdiv = 2;110}111112try_alternative:113xdiv = 1;114115switch (gdbstub_port->div_timer) {116case MNSCx_DIV_TIMER_16BIT:117tmxmd = TM8MD_SRC_IOCLK;118tmxbr = tmp = (ioclk / (baud * xdiv) + 4) / 8 - 1;119if (tmp > 0 && tmp <= 65535)120goto timer_okay;121122tmxmd = TM8MD_SRC_IOCLK_8;123tmxbr = tmp = (ioclk / (baud * 8 * xdiv) + 4) / 8 - 1;124if (tmp > 0 && tmp <= 65535)125goto timer_okay;126127tmxmd = TM8MD_SRC_IOCLK_32;128tmxbr = tmp = (ioclk / (baud * 32 * xdiv) + 4) / 8 - 1;129if (tmp > 0 && tmp <= 65535)130goto timer_okay;131132break;133134case MNSCx_DIV_TIMER_8BIT:135tmxmd = TM2MD_SRC_IOCLK;136tmxbr = tmp = (ioclk / (baud * xdiv) + 4) / 8 - 1;137if (tmp > 0 && tmp <= 255)138goto timer_okay;139140tmxmd = TM2MD_SRC_IOCLK_8;141tmxbr = tmp = (ioclk / (baud * 8 * xdiv) + 4) / 8 - 1;142if (tmp > 0 && tmp <= 255)143goto timer_okay;144145tmxmd = TM2MD_SRC_IOCLK_32;146tmxbr = tmp = (ioclk / (baud * 32 * xdiv) + 4) / 8 - 1;147if (tmp > 0 && tmp <= 255)148goto timer_okay;149break;150}151152/* as a last resort, if the quotient is zero, default to 9600 bps */153baud = 9600;154goto try_alternative;155156timer_okay:157gdbstub_port->uart.timeout = (2 * bits * HZ) / baud;158gdbstub_port->uart.timeout += HZ / 50;159160/* set the timer to produce the required baud rate */161switch (gdbstub_port->div_timer) {162case 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;167break;168169case 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;174break;175}176}177178/*179* wait for a character to come from the debugger180*/181int gdbstub_io_rx_char(unsigned char *_ch, int nonblock)182{183unsigned ix;184u8 ch, st;185#if defined(CONFIG_MN10300_WD_TIMER)186int cpu;187#endif188189*_ch = 0xff;190191if (gdbstub_rx_unget) {192*_ch = gdbstub_rx_unget;193gdbstub_rx_unget = 0;194return 0;195}196197try_again:198/* pull chars out of the buffer */199ix = gdbstub_rx_outp;200barrier();201if (ix == gdbstub_rx_inp) {202if (nonblock)203return -EAGAIN;204#ifdef CONFIG_MN10300_WD_TIMER205for (cpu = 0; cpu < NR_CPUS; cpu++)206watchdog_alert_counter[cpu] = 0;207#endif208goto try_again;209}210211ch = gdbstub_rx_buffer[ix++];212st = gdbstub_rx_buffer[ix++];213barrier();214gdbstub_rx_outp = ix & (PAGE_SIZE - 1);215216st &= SC01STR_RXF | SC01STR_RBF | SC01STR_FEF | SC01STR_PEF |217SC01STR_OEF;218219/* deal with what we've got220* - note that the UART doesn't do BREAK-detection for us221*/222if (st & SC01STR_FEF && ch == 0) {223switch (gdbstub_port->rx_brk) {224case 0: gdbstub_port->rx_brk = 1; goto try_again;225case 1: gdbstub_port->rx_brk = 2; goto try_again;226case 2:227gdbstub_port->rx_brk = 3;228gdbstub_proto("### GDB MNSERIAL Rx Break Detected"229" ###\n");230return -EINTR;231default:232goto try_again;233}234} else if (st & SC01STR_FEF) {235if (gdbstub_port->rx_brk)236goto try_again;237238gdbstub_proto("### GDB MNSERIAL Framing Error ###\n");239return -EIO;240} else if (st & SC01STR_OEF) {241if (gdbstub_port->rx_brk)242goto try_again;243244gdbstub_proto("### GDB MNSERIAL Overrun Error ###\n");245return -EIO;246} else if (st & SC01STR_PEF) {247if (gdbstub_port->rx_brk)248goto try_again;249250gdbstub_proto("### GDB MNSERIAL Parity Error ###\n");251return -EIO;252} else {253/* look for the tail-end char on a break run */254if (gdbstub_port->rx_brk == 3) {255switch (ch) {256case 0xFF:257case 0xFE:258case 0xFC:259case 0xF8:260case 0xF0:261case 0xE0:262case 0xC0:263case 0x80:264case 0x00:265gdbstub_port->rx_brk = 0;266goto try_again;267default:268break;269}270}271272gdbstub_port->rx_brk = 0;273gdbstub_io("### GDB Rx %02x (st=%02x) ###\n", ch, st);274*_ch = ch & 0x7f;275return 0;276}277}278279/*280* send a character to the debugger281*/282void gdbstub_io_tx_char(unsigned char ch)283{284while (*gdbstub_port->_status & SC01STR_TBF)285continue;286287if (ch == 0x0a) {288*(u8 *) gdbstub_port->_txb = 0x0d;289while (*gdbstub_port->_status & SC01STR_TBF)290continue;291}292293*(u8 *) gdbstub_port->_txb = ch;294}295296/*297* flush the transmission buffers298*/299void gdbstub_io_tx_flush(void)300{301while (*gdbstub_port->_status & (SC01STR_TBF | SC01STR_TXF))302continue;303}304305306