diff options
Diffstat (limited to 'arch/frv/kernel/gdb-io.c')
-rw-r--r-- | arch/frv/kernel/gdb-io.c | 216 |
1 files changed, 216 insertions, 0 deletions
diff --git a/arch/frv/kernel/gdb-io.c b/arch/frv/kernel/gdb-io.c new file mode 100644 index 000000000000..c997bccb9221 --- /dev/null +++ b/arch/frv/kernel/gdb-io.c | |||
@@ -0,0 +1,216 @@ | |||
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() */ | ||