| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1 | /* gdb-io.c: FR403 GDB stub I/O | 
 | 2 |  * | 
 | 3 |  * Copyright (C) 2003 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 License | 
 | 8 |  * as published by the Free Software Foundation; either version | 
 | 9 |  * 2 of the License, or (at your option) any later version. | 
 | 10 |  */ | 
 | 11 |  | 
 | 12 | #include <linux/string.h> | 
 | 13 | #include <linux/kernel.h> | 
 | 14 | #include <linux/signal.h> | 
 | 15 | #include <linux/sched.h> | 
 | 16 | #include <linux/mm.h> | 
 | 17 | #include <linux/console.h> | 
 | 18 | #include <linux/init.h> | 
 | 19 | #include <linux/serial_reg.h> | 
 | 20 |  | 
 | 21 | #include <asm/pgtable.h> | 
 | 22 | #include <asm/system.h> | 
 | 23 | #include <asm/irc-regs.h> | 
 | 24 | #include <asm/timer-regs.h> | 
 | 25 | #include <asm/gdb-stub.h> | 
 | 26 | #include "gdb-io.h" | 
 | 27 |  | 
 | 28 | #ifdef CONFIG_GDBSTUB_UART0 | 
 | 29 | #define __UART(X) (*(volatile uint8_t *)(UART0_BASE + (UART_##X))) | 
 | 30 | #define __UART_IRR_NMI 0xff0f0000 | 
 | 31 | #else /* CONFIG_GDBSTUB_UART1 */ | 
 | 32 | #define __UART(X) (*(volatile uint8_t *)(UART1_BASE + (UART_##X))) | 
 | 33 | #define __UART_IRR_NMI 0xfff00000 | 
 | 34 | #endif | 
 | 35 |  | 
 | 36 | #define LSR_WAIT_FOR(STATE)			\ | 
 | 37 | do {						\ | 
 | 38 | 	gdbstub_do_rx();			\ | 
 | 39 | } while (!(__UART(LSR) & UART_LSR_##STATE)) | 
 | 40 |  | 
 | 41 | #define FLOWCTL_QUERY(LINE)	({ __UART(MSR) & UART_MSR_##LINE; }) | 
 | 42 | #define FLOWCTL_CLEAR(LINE)	do { __UART(MCR) &= ~UART_MCR_##LINE; mb(); } while (0) | 
 | 43 | #define FLOWCTL_SET(LINE)	do { __UART(MCR) |= UART_MCR_##LINE;  mb(); } while (0) | 
 | 44 |  | 
 | 45 | #define FLOWCTL_WAIT_FOR(LINE)			\ | 
 | 46 | do {						\ | 
 | 47 | 	gdbstub_do_rx();			\ | 
 | 48 | } while(!FLOWCTL_QUERY(LINE)) | 
 | 49 |  | 
 | 50 | /*****************************************************************************/ | 
 | 51 | /* | 
 | 52 |  * initialise the GDB stub | 
 | 53 |  * - called with PSR.ET==0, so can't incur external interrupts | 
 | 54 |  */ | 
 | 55 | void gdbstub_io_init(void) | 
 | 56 | { | 
 | 57 | 	/* set up the serial port */ | 
 | 58 | 	__UART(LCR) = UART_LCR_WLEN8; /* 1N8 */ | 
 | 59 | 	__UART(FCR) = | 
 | 60 | 		UART_FCR_ENABLE_FIFO | | 
 | 61 | 		UART_FCR_CLEAR_RCVR | | 
 | 62 | 		UART_FCR_CLEAR_XMIT | | 
 | 63 | 		UART_FCR_TRIGGER_1; | 
 | 64 |  | 
 | 65 | 	FLOWCTL_CLEAR(DTR); | 
 | 66 | 	FLOWCTL_SET(RTS); | 
 | 67 |  | 
 | 68 | //	gdbstub_set_baud(115200); | 
 | 69 |  | 
 | 70 | 	/* we want to get serial receive interrupts */ | 
 | 71 | 	__UART(IER) = UART_IER_RDI | UART_IER_RLSI; | 
 | 72 | 	mb(); | 
 | 73 |  | 
 | 74 | 	__set_IRR(6, __UART_IRR_NMI);	/* map ERRs and UARTx to NMI */ | 
 | 75 |  | 
 | 76 | } /* end gdbstub_io_init() */ | 
 | 77 |  | 
 | 78 | /*****************************************************************************/ | 
 | 79 | /* | 
 | 80 |  * set up the GDB stub serial port baud rate timers | 
 | 81 |  */ | 
 | 82 | void gdbstub_set_baud(unsigned baud) | 
 | 83 | { | 
 | 84 | 	unsigned value, high, low; | 
 | 85 | 	u8 lcr; | 
 | 86 |  | 
 | 87 | 	/* work out the divisor to give us the nearest higher baud rate */ | 
 | 88 | 	value = __serial_clock_speed_HZ / 16 / baud; | 
 | 89 |  | 
 | 90 | 	/* determine the baud rate range */ | 
 | 91 | 	high = __serial_clock_speed_HZ / 16 / value; | 
 | 92 | 	low = __serial_clock_speed_HZ / 16 / (value + 1); | 
 | 93 |  | 
 | 94 | 	/* pick the nearest bound */ | 
 | 95 | 	if (low + (high - low) / 2 > baud) | 
 | 96 | 		value++; | 
 | 97 |  | 
 | 98 | 	lcr = __UART(LCR); | 
 | 99 | 	__UART(LCR) |= UART_LCR_DLAB; | 
 | 100 | 	mb(); | 
 | 101 | 	__UART(DLL) = value & 0xff; | 
 | 102 | 	__UART(DLM) = (value >> 8) & 0xff; | 
 | 103 | 	mb(); | 
 | 104 | 	__UART(LCR) = lcr; | 
 | 105 | 	mb(); | 
 | 106 |  | 
 | 107 | } /* end gdbstub_set_baud() */ | 
 | 108 |  | 
 | 109 | /*****************************************************************************/ | 
 | 110 | /* | 
 | 111 |  * receive characters into the receive FIFO | 
 | 112 |  */ | 
 | 113 | void gdbstub_do_rx(void) | 
 | 114 | { | 
 | 115 | 	unsigned ix, nix; | 
 | 116 |  | 
 | 117 | 	ix = gdbstub_rx_inp; | 
 | 118 |  | 
 | 119 | 	while (__UART(LSR) & UART_LSR_DR) { | 
 | 120 | 		nix = (ix + 2) & 0xfff; | 
 | 121 | 		if (nix == gdbstub_rx_outp) | 
 | 122 | 			break; | 
 | 123 |  | 
 | 124 | 		gdbstub_rx_buffer[ix++] = __UART(LSR); | 
 | 125 | 		gdbstub_rx_buffer[ix++] = __UART(RX); | 
 | 126 | 		ix = nix; | 
 | 127 | 	} | 
 | 128 |  | 
 | 129 | 	gdbstub_rx_inp = ix; | 
 | 130 |  | 
 | 131 | 	__clr_RC(15); | 
 | 132 | 	__clr_IRL(); | 
 | 133 |  | 
 | 134 | } /* end gdbstub_do_rx() */ | 
 | 135 |  | 
 | 136 | /*****************************************************************************/ | 
 | 137 | /* | 
 | 138 |  * wait for a character to come from the debugger | 
 | 139 |  */ | 
 | 140 | int gdbstub_rx_char(unsigned char *_ch, int nonblock) | 
 | 141 | { | 
 | 142 | 	unsigned ix; | 
 | 143 | 	u8 ch, st; | 
 | 144 |  | 
 | 145 | 	*_ch = 0xff; | 
 | 146 |  | 
 | 147 | 	if (gdbstub_rx_unget) { | 
 | 148 | 		*_ch = gdbstub_rx_unget; | 
 | 149 | 		gdbstub_rx_unget = 0; | 
 | 150 | 		return 0; | 
 | 151 | 	} | 
 | 152 |  | 
 | 153 |  try_again: | 
 | 154 | 	gdbstub_do_rx(); | 
 | 155 |  | 
 | 156 | 	/* pull chars out of the buffer */ | 
 | 157 | 	ix = gdbstub_rx_outp; | 
 | 158 | 	if (ix == gdbstub_rx_inp) { | 
 | 159 | 		if (nonblock) | 
 | 160 | 			return -EAGAIN; | 
 | 161 | 		//watchdog_alert_counter = 0; | 
 | 162 | 		goto try_again; | 
 | 163 | 	} | 
 | 164 |  | 
 | 165 | 	st = gdbstub_rx_buffer[ix++]; | 
 | 166 | 	ch = gdbstub_rx_buffer[ix++]; | 
 | 167 | 	gdbstub_rx_outp = ix & 0x00000fff; | 
 | 168 |  | 
 | 169 | 	if (st & UART_LSR_BI) { | 
 | 170 | 		gdbstub_proto("### GDB Rx Break Detected ###\n"); | 
 | 171 | 		return -EINTR; | 
 | 172 | 	} | 
 | 173 | 	else if (st & (UART_LSR_FE|UART_LSR_OE|UART_LSR_PE)) { | 
 | 174 | 		gdbstub_proto("### GDB Rx Error (st=%02x) ###\n",st); | 
 | 175 | 		return -EIO; | 
 | 176 | 	} | 
 | 177 | 	else { | 
 | 178 | 		gdbstub_proto("### GDB Rx %02x (st=%02x) ###\n",ch,st); | 
 | 179 | 		*_ch = ch & 0x7f; | 
 | 180 | 		return 0; | 
 | 181 | 	} | 
 | 182 |  | 
 | 183 | } /* end gdbstub_rx_char() */ | 
 | 184 |  | 
 | 185 | /*****************************************************************************/ | 
 | 186 | /* | 
 | 187 |  * send a character to the debugger | 
 | 188 |  */ | 
 | 189 | void gdbstub_tx_char(unsigned char ch) | 
 | 190 | { | 
 | 191 | 	FLOWCTL_SET(DTR); | 
 | 192 | 	LSR_WAIT_FOR(THRE); | 
 | 193 | //	FLOWCTL_WAIT_FOR(CTS); | 
 | 194 |  | 
 | 195 | 	if (ch == 0x0a) { | 
 | 196 | 		__UART(TX) = 0x0d; | 
 | 197 | 		mb(); | 
 | 198 | 		LSR_WAIT_FOR(THRE); | 
 | 199 | //		FLOWCTL_WAIT_FOR(CTS); | 
 | 200 | 	} | 
 | 201 | 	__UART(TX) = ch; | 
 | 202 | 	mb(); | 
 | 203 |  | 
 | 204 | 	FLOWCTL_CLEAR(DTR); | 
 | 205 | } /* end gdbstub_tx_char() */ | 
 | 206 |  | 
 | 207 | /*****************************************************************************/ | 
 | 208 | /* | 
 | 209 |  * send a character to the debugger | 
 | 210 |  */ | 
 | 211 | void gdbstub_tx_flush(void) | 
 | 212 | { | 
 | 213 | 	LSR_WAIT_FOR(TEMT); | 
 | 214 | 	LSR_WAIT_FOR(THRE); | 
 | 215 | 	FLOWCTL_CLEAR(DTR); | 
 | 216 | } /* end gdbstub_tx_flush() */ |