1/* 16550 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/nmi.h> 19 20#include <asm/pgtable.h> 21#include <asm/system.h> 22#include <asm/gdb-stub.h> 23#include <asm/exceptions.h> 24#include <asm/serial-regs.h> 25#include <unit/serial.h> 26 27/* 28 * initialise the GDB stub 29 */ 30void gdbstub_io_init(void) 31{ 32 u16 tmp; 33 34 /* set up the serial port */ 35 GDBPORT_SERIAL_LCR = UART_LCR_WLEN8; /* 1N8 */ 36 GDBPORT_SERIAL_FCR = (UART_FCR_ENABLE_FIFO | UART_FCR_CLEAR_RCVR | 37 UART_FCR_CLEAR_XMIT); 38 39 FLOWCTL_CLEAR(DTR); 40 FLOWCTL_SET(RTS); 41 42 gdbstub_io_set_baud(115200); 43 44 /* we want to get serial receive interrupts */ 45 XIRQxICR(GDBPORT_SERIAL_IRQ) = 0; 46 tmp = XIRQxICR(GDBPORT_SERIAL_IRQ); 47 48 IVAR0 = EXCEP_IRQ_LEVEL0; 49 set_intr_stub(EXCEP_IRQ_LEVEL0, gdbstub_io_rx_handler); 50 51 XIRQxICR(GDBPORT_SERIAL_IRQ) &= ~GxICR_REQUEST; 52 XIRQxICR(GDBPORT_SERIAL_IRQ) = GxICR_ENABLE | GxICR_LEVEL_0; 53 tmp = XIRQxICR(GDBPORT_SERIAL_IRQ); 54 55 GDBPORT_SERIAL_IER = UART_IER_RDI | UART_IER_RLSI; 56 57 /* permit level 0 IRQs to take place */ 58 asm volatile( 59 " and %0,epsw \n" 60 " or %1,epsw \n" 61 : 62 : "i"(~EPSW_IM), "i"(EPSW_IE | EPSW_IM_1) 63 ); 64} 65 66/* 67 * set up the GDB stub serial port baud rate timers 68 */ 69void gdbstub_io_set_baud(unsigned baud) 70{ 71 unsigned value; 72 u8 lcr; 73 74 value = 18432000 / 16 / baud; 75 76 lcr = GDBPORT_SERIAL_LCR; 77 GDBPORT_SERIAL_LCR |= UART_LCR_DLAB; 78 GDBPORT_SERIAL_DLL = value & 0xff; 79 GDBPORT_SERIAL_DLM = (value >> 8) & 0xff; 80 GDBPORT_SERIAL_LCR = lcr; 81} 82 83/* 84 * wait for a character to come from the debugger 85 */ 86int gdbstub_io_rx_char(unsigned char *_ch, int nonblock) 87{ 88 unsigned ix; 89 u8 ch, st; 90 91 *_ch = 0xff; 92 93 if (gdbstub_rx_unget) { 94 *_ch = gdbstub_rx_unget; 95 gdbstub_rx_unget = 0; 96 return 0; 97 } 98 99 try_again: 100 /* pull chars out of the buffer */ 101 ix = gdbstub_rx_outp; 102 barrier(); 103 if (ix == gdbstub_rx_inp) { 104 if (nonblock) 105 return -EAGAIN; 106#ifdef CONFIG_MN10300_WD_TIMER 107 watchdog_alert_counter = 0; 108#endif /* CONFIG_MN10300_WD_TIMER */ 109 goto try_again; 110 } 111 112 ch = gdbstub_rx_buffer[ix++]; 113 st = gdbstub_rx_buffer[ix++]; 114 barrier(); 115 gdbstub_rx_outp = ix & 0x00000fff; 116 117 if (st & UART_LSR_BI) { 118 gdbstub_proto("### GDB Rx Break Detected ###\n"); 119 return -EINTR; 120 } else if (st & (UART_LSR_FE | UART_LSR_OE | UART_LSR_PE)) { 121 gdbstub_proto("### GDB Rx Error (st=%02x) ###\n", st); 122 return -EIO; 123 } else { 124 gdbstub_proto("### GDB Rx %02x (st=%02x) ###\n", ch, st); 125 *_ch = ch & 0x7f; 126 return 0; 127 } 128} 129 130/* 131 * send a character to the debugger 132 */ 133void gdbstub_io_tx_char(unsigned char ch) 134{ 135 FLOWCTL_SET(DTR); 136 LSR_WAIT_FOR(THRE); 137 /* FLOWCTL_WAIT_FOR(CTS); */ 138 139 if (ch == 0x0a) { 140 GDBPORT_SERIAL_TX = 0x0d; 141 LSR_WAIT_FOR(THRE); 142 /* FLOWCTL_WAIT_FOR(CTS); */ 143 } 144 GDBPORT_SERIAL_TX = ch; 145 146 FLOWCTL_CLEAR(DTR); 147} 148 149/* 150 * send a character to the debugger 151 */ 152void gdbstub_io_tx_flush(void) 153{ 154 LSR_WAIT_FOR(TEMT); 155 LSR_WAIT_FOR(THRE); 156 FLOWCTL_CLEAR(DTR); 157} 158