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