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