1 /*
2 * Carsten Langgaard, carstenl@mips.com
3 * Copyright (C) 2000 MIPS Technologies, Inc. All rights reserved.
4 *
5 * ########################################################################
6 *
7 * This program is free software; you can distribute it and/or modify it
8 * under the terms of the GNU General Public License (Version 2) as
9 * published by the Free Software Foundation.
10 *
11 * This program is distributed in the hope it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * for more details.
15 *
16 * You should have received a copy of the GNU General Public License along
17 * with this program; if not, write to the Free Software Foundation, Inc.,
18 * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
19 *
20 * ########################################################################
21 *
22 * This is the interface to the remote debugger stub.
23 *
24 */
25 #include <linux/config.h>
26 #include <linux/serialP.h>
27 #include <linux/serial_reg.h>
28
29 #include <asm/serial.h>
30 #include <asm/io.h>
31
32 static struct serial_state rs_table[RS_TABLE_SIZE] = {
33 SERIAL_PORT_DFNS /* Defined in serial.h */
34 };
35
36 static struct async_struct kdb_port_info = {0};
37
38 int (*generic_putDebugChar)(char);
39 char (*generic_getDebugChar)(void);
40
serial_in(struct async_struct * info,int offset)41 static __inline__ unsigned int serial_in(struct async_struct *info, int offset)
42 {
43 return inb(info->port + offset);
44 }
45
serial_out(struct async_struct * info,int offset,int value)46 static __inline__ void serial_out(struct async_struct *info, int offset,
47 int value)
48 {
49 outb(value, info->port+offset);
50 }
51
rs_kgdb_hook(int tty_no)52 void rs_kgdb_hook(int tty_no) {
53 int t;
54 struct serial_state *ser = &rs_table[tty_no];
55
56 kdb_port_info.state = ser;
57 kdb_port_info.magic = SERIAL_MAGIC;
58 kdb_port_info.port = ser->port;
59 kdb_port_info.flags = ser->flags;
60
61 /*
62 * Clear all interrupts
63 */
64 serial_in(&kdb_port_info, UART_LSR);
65 serial_in(&kdb_port_info, UART_RX);
66 serial_in(&kdb_port_info, UART_IIR);
67 serial_in(&kdb_port_info, UART_MSR);
68
69 /*
70 * Now, initialize the UART
71 */
72 serial_out(&kdb_port_info, UART_LCR, UART_LCR_WLEN8); /* reset DLAB */
73 if (kdb_port_info.flags & ASYNC_FOURPORT) {
74 kdb_port_info.MCR = UART_MCR_DTR | UART_MCR_RTS;
75 t = UART_MCR_DTR | UART_MCR_OUT1;
76 } else {
77 kdb_port_info.MCR
78 = UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2;
79 t = UART_MCR_DTR | UART_MCR_RTS;
80 }
81
82 kdb_port_info.MCR = t; /* no interrupts, please */
83 serial_out(&kdb_port_info, UART_MCR, kdb_port_info.MCR);
84
85 /*
86 * and set the speed of the serial port
87 * (currently hardwired to 9600 8N1
88 */
89
90 /* baud rate is fixed to 9600 (is this sufficient?)*/
91 t = kdb_port_info.state->baud_base / 9600;
92 /* set DLAB */
93 serial_out(&kdb_port_info, UART_LCR, UART_LCR_WLEN8 | UART_LCR_DLAB);
94 serial_out(&kdb_port_info, UART_DLL, t & 0xff);/* LS of divisor */
95 serial_out(&kdb_port_info, UART_DLM, t >> 8); /* MS of divisor */
96 /* reset DLAB */
97 serial_out(&kdb_port_info, UART_LCR, UART_LCR_WLEN8);
98 }
99
putDebugChar(char c)100 int putDebugChar(char c)
101 {
102 return generic_putDebugChar(c);
103 }
104
getDebugChar(void)105 char getDebugChar(void)
106 {
107 return generic_getDebugChar();
108 }
109
rs_putDebugChar(char c)110 int rs_putDebugChar(char c)
111 {
112
113 if (!kdb_port_info.state) { /* need to init device first */
114 return 0;
115 }
116
117 while ((serial_in(&kdb_port_info, UART_LSR) & UART_LSR_THRE) == 0)
118 ;
119
120 serial_out(&kdb_port_info, UART_TX, c);
121
122 return 1;
123 }
124
rs_getDebugChar(void)125 char rs_getDebugChar(void)
126 {
127 if (!kdb_port_info.state) { /* need to init device first */
128 return 0;
129 }
130
131 while (!(serial_in(&kdb_port_info, UART_LSR) & 1))
132 ;
133
134 return(serial_in(&kdb_port_info, UART_RX));
135 }
136
137
138 #ifdef CONFIG_MIPS_ATLAS
139
140 #include <asm/mips-boards/atlas.h>
141 #include <asm/mips-boards/saa9730_uart.h>
142
143 #define INB(a) inb((unsigned long)a)
144 #define OUTB(x,a) outb(x,(unsigned long)a)
145
146 /*
147 * This is the interface to the remote debugger stub
148 * if the Philips part is used for the debug port,
149 * called from the platform setup code.
150 *
151 * PCI init will not have been done yet, we make a
152 * universal assumption about the way the bootloader (YAMON)
153 * have located and set up the chip.
154 */
155 static t_uart_saa9730_regmap *kgdb_uart = (void *)(ATLAS_SAA9730_REG + SAA9730_UART_REGS_ADDR);
156
157 static int saa9730_kgdb_active = 0;
158
saa9730_kgdb_hook(void)159 void saa9730_kgdb_hook(void)
160 {
161 volatile unsigned char t;
162
163 /*
164 * Clear all interrupts
165 */
166 t = INB(&kgdb_uart->Lsr);
167 t += INB(&kgdb_uart->Msr);
168 t += INB(&kgdb_uart->Thr_Rbr);
169 t += INB(&kgdb_uart->Iir_Fcr);
170
171 /*
172 * Now, initialize the UART
173 */
174 /* 8 data bits, one stop bit, no parity */
175 OUTB(SAA9730_LCR_DATA8, &kgdb_uart->Lcr);
176
177 /* baud rate is fixed to 9600 (is this sufficient?)*/
178 OUTB(0, &kgdb_uart->BaudDivMsb); /* HACK - Assumes standard crystal */
179 OUTB(23, &kgdb_uart->BaudDivLsb); /* HACK - known for MIPS Atlas */
180
181 /* Set RTS/DTR active */
182 OUTB(SAA9730_MCR_DTR | SAA9730_MCR_RTS, &kgdb_uart->Mcr);
183 saa9730_kgdb_active = 1;
184 }
185
saa9730_putDebugChar(char c)186 int saa9730_putDebugChar(char c)
187 {
188
189 if (!saa9730_kgdb_active) { /* need to init device first */
190 return 0;
191 }
192
193 while (!(INB(&kgdb_uart->Lsr) & SAA9730_LSR_THRE))
194 ;
195 OUTB(c, &kgdb_uart->Thr_Rbr);
196
197 return 1;
198 }
199
saa9730_getDebugChar(void)200 char saa9730_getDebugChar(void)
201 {
202 char c;
203
204 if (!saa9730_kgdb_active) { /* need to init device first */
205 return 0;
206 }
207 while (!(INB(&kgdb_uart->Lsr) & SAA9730_LSR_DR))
208 ;
209
210 c = INB(&kgdb_uart->Thr_Rbr);
211 return(c);
212 }
213
214 #endif
215