| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | /* gdb-io.c: FR403 GDB stub I/O
 | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Copyright (C) 2003 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 License | 
					
						
							|  |  |  |  * as published by the Free Software Foundation; either version | 
					
						
							|  |  |  |  * 2 of the License, 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/serial_reg.h>
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include <asm/pgtable.h>
 | 
					
						
							|  |  |  | #include <asm/irc-regs.h>
 | 
					
						
							|  |  |  | #include <asm/timer-regs.h>
 | 
					
						
							|  |  |  | #include <asm/gdb-stub.h>
 | 
					
						
							|  |  |  | #include "gdb-io.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #ifdef CONFIG_GDBSTUB_UART0
 | 
					
						
							|  |  |  | #define __UART(X) (*(volatile uint8_t *)(UART0_BASE + (UART_##X)))
 | 
					
						
							|  |  |  | #define __UART_IRR_NMI 0xff0f0000
 | 
					
						
							|  |  |  | #else /* CONFIG_GDBSTUB_UART1 */
 | 
					
						
							|  |  |  | #define __UART(X) (*(volatile uint8_t *)(UART1_BASE + (UART_##X)))
 | 
					
						
							|  |  |  | #define __UART_IRR_NMI 0xfff00000
 | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #define LSR_WAIT_FOR(STATE)			\
 | 
					
						
							|  |  |  | do {						\ | 
					
						
							|  |  |  | 	gdbstub_do_rx();			\ | 
					
						
							|  |  |  | } while (!(__UART(LSR) & UART_LSR_##STATE)) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #define FLOWCTL_QUERY(LINE)	({ __UART(MSR) & UART_MSR_##LINE; })
 | 
					
						
							|  |  |  | #define FLOWCTL_CLEAR(LINE)	do { __UART(MCR) &= ~UART_MCR_##LINE; mb(); } while (0)
 | 
					
						
							|  |  |  | #define FLOWCTL_SET(LINE)	do { __UART(MCR) |= UART_MCR_##LINE;  mb(); } while (0)
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #define FLOWCTL_WAIT_FOR(LINE)			\
 | 
					
						
							|  |  |  | do {						\ | 
					
						
							|  |  |  | 	gdbstub_do_rx();			\ | 
					
						
							|  |  |  | } while(!FLOWCTL_QUERY(LINE)) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*****************************************************************************/ | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  |  * initialise the GDB stub | 
					
						
							|  |  |  |  * - called with PSR.ET==0, so can't incur external interrupts | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | void gdbstub_io_init(void) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	/* set up the serial port */ | 
					
						
							|  |  |  | 	__UART(LCR) = UART_LCR_WLEN8; /* 1N8 */ | 
					
						
							|  |  |  | 	__UART(FCR) = | 
					
						
							|  |  |  | 		UART_FCR_ENABLE_FIFO | | 
					
						
							|  |  |  | 		UART_FCR_CLEAR_RCVR | | 
					
						
							|  |  |  | 		UART_FCR_CLEAR_XMIT | | 
					
						
							|  |  |  | 		UART_FCR_TRIGGER_1; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	FLOWCTL_CLEAR(DTR); | 
					
						
							|  |  |  | 	FLOWCTL_SET(RTS); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | //	gdbstub_set_baud(115200);
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* we want to get serial receive interrupts */ | 
					
						
							|  |  |  | 	__UART(IER) = UART_IER_RDI | UART_IER_RLSI; | 
					
						
							|  |  |  | 	mb(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	__set_IRR(6, __UART_IRR_NMI);	/* map ERRs and UARTx to NMI */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | } /* end gdbstub_io_init() */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*****************************************************************************/ | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  |  * set up the GDB stub serial port baud rate timers | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | void gdbstub_set_baud(unsigned baud) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	unsigned value, high, low; | 
					
						
							|  |  |  | 	u8 lcr; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* work out the divisor to give us the nearest higher baud rate */ | 
					
						
							|  |  |  | 	value = __serial_clock_speed_HZ / 16 / baud; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* determine the baud rate range */ | 
					
						
							|  |  |  | 	high = __serial_clock_speed_HZ / 16 / value; | 
					
						
							|  |  |  | 	low = __serial_clock_speed_HZ / 16 / (value + 1); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* pick the nearest bound */ | 
					
						
							|  |  |  | 	if (low + (high - low) / 2 > baud) | 
					
						
							|  |  |  | 		value++; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	lcr = __UART(LCR); | 
					
						
							|  |  |  | 	__UART(LCR) |= UART_LCR_DLAB; | 
					
						
							|  |  |  | 	mb(); | 
					
						
							|  |  |  | 	__UART(DLL) = value & 0xff; | 
					
						
							|  |  |  | 	__UART(DLM) = (value >> 8) & 0xff; | 
					
						
							|  |  |  | 	mb(); | 
					
						
							|  |  |  | 	__UART(LCR) = lcr; | 
					
						
							|  |  |  | 	mb(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | } /* end gdbstub_set_baud() */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*****************************************************************************/ | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  |  * receive characters into the receive FIFO | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | void gdbstub_do_rx(void) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	unsigned ix, nix; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ix = gdbstub_rx_inp; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	while (__UART(LSR) & UART_LSR_DR) { | 
					
						
							|  |  |  | 		nix = (ix + 2) & 0xfff; | 
					
						
							|  |  |  | 		if (nix == gdbstub_rx_outp) | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		gdbstub_rx_buffer[ix++] = __UART(LSR); | 
					
						
							|  |  |  | 		gdbstub_rx_buffer[ix++] = __UART(RX); | 
					
						
							|  |  |  | 		ix = nix; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	gdbstub_rx_inp = ix; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	__clr_RC(15); | 
					
						
							|  |  |  | 	__clr_IRL(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | } /* end gdbstub_do_rx() */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*****************************************************************************/ | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  |  * wait for a character to come from the debugger | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | int gdbstub_rx_char(unsigned char *_ch, int nonblock) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	unsigned ix; | 
					
						
							|  |  |  | 	u8 ch, st; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	*_ch = 0xff; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (gdbstub_rx_unget) { | 
					
						
							|  |  |  | 		*_ch = gdbstub_rx_unget; | 
					
						
							|  |  |  | 		gdbstub_rx_unget = 0; | 
					
						
							|  |  |  | 		return 0; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |  try_again: | 
					
						
							|  |  |  | 	gdbstub_do_rx(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* pull chars out of the buffer */ | 
					
						
							|  |  |  | 	ix = gdbstub_rx_outp; | 
					
						
							|  |  |  | 	if (ix == gdbstub_rx_inp) { | 
					
						
							|  |  |  | 		if (nonblock) | 
					
						
							|  |  |  | 			return -EAGAIN; | 
					
						
							|  |  |  | 		//watchdog_alert_counter = 0;
 | 
					
						
							|  |  |  | 		goto try_again; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	st = gdbstub_rx_buffer[ix++]; | 
					
						
							|  |  |  | 	ch = gdbstub_rx_buffer[ix++]; | 
					
						
							|  |  |  | 	gdbstub_rx_outp = ix & 0x00000fff; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (st & UART_LSR_BI) { | 
					
						
							|  |  |  | 		gdbstub_proto("### GDB Rx Break Detected ###\n"); | 
					
						
							|  |  |  | 		return -EINTR; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	else if (st & (UART_LSR_FE|UART_LSR_OE|UART_LSR_PE)) { | 
					
						
							| 
									
										
										
										
											2010-05-24 14:32:54 -07:00
										 |  |  | 		gdbstub_io("### GDB Rx Error (st=%02x) ###\n",st); | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 		return -EIO; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	else { | 
					
						
							| 
									
										
										
										
											2010-05-24 14:32:54 -07:00
										 |  |  | 		gdbstub_io("### GDB Rx %02x (st=%02x) ###\n",ch,st); | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 		*_ch = ch & 0x7f; | 
					
						
							|  |  |  | 		return 0; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | } /* end gdbstub_rx_char() */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*****************************************************************************/ | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  |  * send a character to the debugger | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | void gdbstub_tx_char(unsigned char ch) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	FLOWCTL_SET(DTR); | 
					
						
							|  |  |  | 	LSR_WAIT_FOR(THRE); | 
					
						
							|  |  |  | //	FLOWCTL_WAIT_FOR(CTS);
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (ch == 0x0a) { | 
					
						
							|  |  |  | 		__UART(TX) = 0x0d; | 
					
						
							|  |  |  | 		mb(); | 
					
						
							|  |  |  | 		LSR_WAIT_FOR(THRE); | 
					
						
							|  |  |  | //		FLOWCTL_WAIT_FOR(CTS);
 | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	__UART(TX) = ch; | 
					
						
							|  |  |  | 	mb(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	FLOWCTL_CLEAR(DTR); | 
					
						
							|  |  |  | } /* end gdbstub_tx_char() */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*****************************************************************************/ | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  |  * send a character to the debugger | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | void gdbstub_tx_flush(void) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	LSR_WAIT_FOR(TEMT); | 
					
						
							|  |  |  | 	LSR_WAIT_FOR(THRE); | 
					
						
							|  |  |  | 	FLOWCTL_CLEAR(DTR); | 
					
						
							|  |  |  | } /* end gdbstub_tx_flush() */ |