blob: c0d2e8aa14f3dec6ccced3e5ea265f95233def23 [file] [log] [blame]
wdenk2262cfe2002-11-18 00:14:45 +00001/*
2 * (C) Copyright 2002
3 * Daniel Engström, Omicron Ceti AB, daniel@omicron.se
4 *
5 * (C) Copyright 2000
6 * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
7 *
8 * See file CREDITS for list of people who contributed to this
9 * project.
10 *
11 * This program is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU General Public License as
13 * published by the Free Software Foundation; either version 2 of
14 * the License, or (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
24 * MA 02111-1307 USA
25 */
26/*------------------------------------------------------------------------------+ */
27/*
28 * This source code has been made available to you by IBM on an AS-IS
29 * basis. Anyone receiving this source is licensed under IBM
30 * copyrights to use it in any way he or she deems fit, including
31 * copying it, modifying it, compiling it, and redistributing it either
32 * with or without modifications. No license under IBM patents or
33 * patent applications is to be implied by the copyright license.
34 *
35 * Any user of this software should understand that IBM cannot provide
36 * technical support for this software and will not be responsible for
37 * any consequences resulting from the use of this software.
38 *
39 * Any person who transfers this source code or any derivative work
40 * must include the IBM copyright notice, this paragraph, and the
41 * preceding two paragraphs in the transferred software.
42 *
43 * COPYRIGHT I B M CORPORATION 1995
44 * LICENSED MATERIAL - PROGRAM PROPERTY OF I B M
45 */
46/*------------------------------------------------------------------------------- */
47
48#include <common.h>
49#include <watchdog.h>
50#include <asm/io.h>
51#include <asm/ibmpc.h>
52
53#if CONFIG_SERIAL_SOFTWARE_FIFO
54#include <malloc.h>
55#endif
56
57#define UART_RBR 0x00
58#define UART_THR 0x00
59#define UART_IER 0x01
60#define UART_IIR 0x02
61#define UART_FCR 0x02
62#define UART_LCR 0x03
63#define UART_MCR 0x04
64#define UART_LSR 0x05
65#define UART_MSR 0x06
66#define UART_SCR 0x07
67#define UART_DLL 0x00
68#define UART_DLM 0x01
69
70/*-----------------------------------------------------------------------------+
71 | Line Status Register.
72 +-----------------------------------------------------------------------------*/
73#define asyncLSRDataReady1 0x01
74#define asyncLSROverrunError1 0x02
75#define asyncLSRParityError1 0x04
76#define asyncLSRFramingError1 0x08
77#define asyncLSRBreakInterrupt1 0x10
78#define asyncLSRTxHoldEmpty1 0x20
79#define asyncLSRTxShiftEmpty1 0x40
80#define asyncLSRRxFifoError1 0x80
81
82
83
84#if CONFIG_SERIAL_SOFTWARE_FIFO
85/*-----------------------------------------------------------------------------+
86 | Fifo
87 +-----------------------------------------------------------------------------*/
88typedef struct {
89 char *rx_buffer;
90 ulong rx_put;
91 ulong rx_get;
92} serial_buffer_t;
93
94volatile static serial_buffer_t buf_info;
95#endif
96
97
98static int serial_div (int baudrate )
99{
100
101 switch (baudrate) {
102 case 1200:
103 return 96;
104 case 9600:
105 return 12;
106 case 19200:
107 return 6;
108 case 38400:
109 return 3;
110 case 57600:
111 return 2;
112 case 115200:
113 return 1;
114 }
115 hang ();
116}
117
118
119/*
120 * Minimal serial functions needed to use one of the SMC ports
121 * as serial console interface.
122 */
123
124int serial_init (void)
125{
126 DECLARE_GLOBAL_DATA_PTR;
127
128 volatile char val;
129
130 int bdiv = serial_div(gd->baudrate);
131
132
133 outb(0x80, UART0_BASE + UART_LCR); /* set DLAB bit */
134 outb(bdiv, UART0_BASE + UART_DLL); /* set baudrate divisor */
135 outb(bdiv >> 8, UART0_BASE + UART_DLM);/* set baudrate divisor */
136 outb(0x03, UART0_BASE + UART_LCR); /* clear DLAB; set 8 bits, no parity */
137 outb(0x00, UART0_BASE + UART_FCR); /* disable FIFO */
138 outb(0x00, UART0_BASE + UART_MCR); /* no modem control DTR RTS */
139 val = inb(UART0_BASE + UART_LSR); /* clear line status */
140 val = inb(UART0_BASE + UART_RBR); /* read receive buffer */
141 outb(0x00, UART0_BASE + UART_SCR); /* set scratchpad */
142 outb(0x00, UART0_BASE + UART_IER); /* set interrupt enable reg */
143
144 return (0);
145}
146
147
148void serial_setbrg (void)
149{
150 DECLARE_GLOBAL_DATA_PTR;
151
152 unsigned short bdiv;
153
154 bdiv = serial_div (gd->baudrate);
155
156 outb(0x80, UART0_BASE + UART_LCR); /* set DLAB bit */
157 outb(bdiv&0xff, UART0_BASE + UART_DLL); /* set baudrate divisor */
158 outb(bdiv >> 8, UART0_BASE + UART_DLM);/* set baudrate divisor */
159 outb(0x03, UART0_BASE + UART_LCR); /* clear DLAB; set 8 bits, no parity */
160}
161
162
163void serial_putc (const char c)
164{
165 int i;
166
167 if (c == '\n')
168 serial_putc ('\r');
169
170 /* check THRE bit, wait for transmiter available */
171 for (i = 1; i < 3500; i++) {
172 if ((inb (UART0_BASE + UART_LSR) & 0x20) == 0x20)
173 break;
174 udelay (100);
175 }
176 outb(c, UART0_BASE + UART_THR); /* put character out */
177}
178
179
180void serial_puts (const char *s)
181{
182 while (*s) {
183 serial_putc (*s++);
184 }
185}
186
187
188int serial_getc ()
189{
190 unsigned char status = 0;
191
192 while (1) {
193#if defined(CONFIG_HW_WATCHDOG)
194 WATCHDOG_RESET (); /* Reset HW Watchdog, if needed */
195#endif /* CONFIG_HW_WATCHDOG */
196 status = inb (UART0_BASE + UART_LSR);
197 if ((status & asyncLSRDataReady1) != 0x0) {
198 break;
199 }
200 if ((status & ( asyncLSRFramingError1 |
201 asyncLSROverrunError1 |
202 asyncLSRParityError1 |
203 asyncLSRBreakInterrupt1 )) != 0) {
204 outb(asyncLSRFramingError1 |
205 asyncLSROverrunError1 |
206 asyncLSRParityError1 |
207 asyncLSRBreakInterrupt1, UART0_BASE + UART_LSR);
208 }
209 }
210 return (0x000000ff & (int) inb (UART0_BASE));
211}
212
213
214int serial_tstc ()
215{
216 unsigned char status;
217
218 status = inb (UART0_BASE + UART_LSR);
219 if ((status & asyncLSRDataReady1) != 0x0) {
220 return (1);
221 }
222 if ((status & ( asyncLSRFramingError1 |
223 asyncLSROverrunError1 |
224 asyncLSRParityError1 |
225 asyncLSRBreakInterrupt1 )) != 0) {
226 outb(asyncLSRFramingError1 |
227 asyncLSROverrunError1 |
228 asyncLSRParityError1 |
229 asyncLSRBreakInterrupt1, UART0_BASE + UART_LSR);
230 }
231 return 0;
232}
233
234
235#if CONFIG_SERIAL_SOFTWARE_FIFO
236
237void serial_isr (void *arg)
238{
239 int space;
240 int c;
241 const int rx_get = buf_info.rx_get;
242 int rx_put = buf_info.rx_put;
243
244 if (rx_get <= rx_put) {
245 space = CONFIG_SERIAL_SOFTWARE_FIFO - (rx_put - rx_get);
246 } else {
247 space = rx_get - rx_put;
248 }
249 while (serial_tstc ()) {
250 c = serial_getc ();
251 if (space) {
252 buf_info.rx_buffer[rx_put++] = c;
253 space--;
254 }
255 if (rx_put == CONFIG_SERIAL_SOFTWARE_FIFO)
256 rx_put = 0;
257 if (space < CONFIG_SERIAL_SOFTWARE_FIFO / 4) {
258 /* Stop flow by setting RTS inactive */
259 outb(inb (UART0_BASE + UART_MCR) & (0xFF ^ 0x02),
260 UART0_BASE + UART_MCR);
261 }
262 }
263 buf_info.rx_put = rx_put;
264}
265
266void serial_buffered_init (void)
267{
268 serial_puts ("Switching to interrupt driven serial input mode.\n");
269 buf_info.rx_buffer = malloc (CONFIG_SERIAL_SOFTWARE_FIFO);
270 buf_info.rx_put = 0;
271 buf_info.rx_get = 0;
272
273 if (inb (UART0_BASE + UART_MSR) & 0x10) {
274 serial_puts ("Check CTS signal present on serial port: OK.\n");
275 } else {
276 serial_puts ("WARNING: CTS signal not present on serial port.\n");
277 }
278
279 irq_install_handler ( VECNUM_U0 /*UART0 *//*int vec */ ,
280 serial_isr /*interrupt_handler_t *handler */ ,
281 (void *) &buf_info /*void *arg */ );
282
283 /* Enable "RX Data Available" Interrupt on UART */
284 /* outb(inb(UART0_BASE + UART_IER) |0x01, UART0_BASE + UART_IER); */
285 outb(0x01, UART0_BASE + UART_IER);
286 /* Set DTR active */
287 outb(inb (UART0_BASE + UART_MCR) | 0x01, UART0_BASE + UART_MCR);
288 /* Start flow by setting RTS active */
289 outb(inb (UART0_BASE + UART_MCR) | 0x02, UART0_BASE + UART_MCR);
290 /* Setup UART FIFO: RX trigger level: 4 byte, Enable FIFO */
291 outb((1 << 6) | 1, UART0_BASE + UART_FCR);
292}
293
294void serial_buffered_putc (const char c)
295{
296 /* Wait for CTS */
297#if defined(CONFIG_HW_WATCHDOG)
298 while (!(inb (UART0_BASE + UART_MSR) & 0x10))
299 WATCHDOG_RESET ();
300#else
301 while (!(inb (UART0_BASE + UART_MSR) & 0x10));
302#endif
303 serial_putc (c);
304}
305
306void serial_buffered_puts (const char *s)
307{
308 serial_puts (s);
309}
310
311int serial_buffered_getc (void)
312{
313 int space;
314 int c;
315 int rx_get = buf_info.rx_get;
316 int rx_put;
317
318#if defined(CONFIG_HW_WATCHDOG)
319 while (rx_get == buf_info.rx_put)
320 WATCHDOG_RESET ();
321#else
322 while (rx_get == buf_info.rx_put);
323#endif
324 c = buf_info.rx_buffer[rx_get++];
325 if (rx_get == CONFIG_SERIAL_SOFTWARE_FIFO)
326 rx_get = 0;
327 buf_info.rx_get = rx_get;
328
329 rx_put = buf_info.rx_put;
330 if (rx_get <= rx_put) {
331 space = CONFIG_SERIAL_SOFTWARE_FIFO - (rx_put - rx_get);
332 } else {
333 space = rx_get - rx_put;
334 }
335 if (space > CONFIG_SERIAL_SOFTWARE_FIFO / 2) {
336 /* Start flow by setting RTS active */
337 outb(inb (UART0_BASE + UART_MCR) | 0x02, UART0_BASE + UART_MCR);
338 }
339
340 return c;
341}
342
343int serial_buffered_tstc (void)
344{
345 return (buf_info.rx_get != buf_info.rx_put) ? 1 : 0;
346}
347
348#endif /* CONFIG_SERIAL_SOFTWARE_FIFO */
349
350
351#if (CONFIG_COMMANDS & CFG_CMD_KGDB)
352/*
353 AS HARNOIS : according to CONFIG_KGDB_SER_INDEX kgdb uses serial port
354 number 0 or number 1
355 - if CONFIG_KGDB_SER_INDEX = 1 => serial port number 0 :
356 configuration has been already done
357 - if CONFIG_KGDB_SER_INDEX = 2 => serial port number 1 :
358 configure port 1 for serial I/O with rate = CONFIG_KGDB_BAUDRATE
359*/
360#if (CONFIG_KGDB_SER_INDEX & 2)
361void kgdb_serial_init (void)
362{
363 DECLARE_GLOBAL_DATA_PTR;
364
365 volatile char val;
366 bdiv = serial_div (CONFIG_KGDB_BAUDRATE);
367
368 /*
369 * Init onboard 16550 UART
370 */
371 outb(0x80, UART1_BASE + UART_LCR); /* set DLAB bit */
372 outb(bdiv & 0xff), UART1_BASE + UART_DLL); /* set divisor for 9600 baud */
373 outb(bdiv >> 8), UART1_BASE + UART_DLM); /* set divisor for 9600 baud */
374 outb(0x03, UART1_BASE + UART_LCR); /* line control 8 bits no parity */
375 outb(0x00, UART1_BASE + UART_FCR); /* disable FIFO */
376 outb(0x00, UART1_BASE + UART_MCR); /* no modem control DTR RTS */
377 val = inb(UART1_BASE + UART_LSR); /* clear line status */
378 val = inb(UART1_BASE + UART_RBR); /* read receive buffer */
379 outb(0x00, UART1_BASE + UART_SCR); /* set scratchpad */
380 outb(0x00, UART1_BASE + UART_IER); /* set interrupt enable reg */
381}
382
383
384void putDebugChar (const char c)
385{
386 if (c == '\n')
387 serial_putc ('\r');
388
389 outb(c, UART1_BASE + UART_THR); /* put character out */
390
391 /* check THRE bit, wait for transfer done */
392 while ((inb(UART1_BASE + UART_LSR) & 0x20) != 0x20);
393}
394
395
396void putDebugStr (const char *s)
397{
398 while (*s) {
399 serial_putc(*s++);
400 }
401}
402
403
404int getDebugChar (void)
405{
406 unsigned char status = 0;
407
408 while (1) {
409 status = inb(UART1_BASE + UART_LSR);
410 if ((status & asyncLSRDataReady1) != 0x0) {
411 break;
412 }
413 if ((status & ( asyncLSRFramingError1 |
414 asyncLSROverrunError1 |
415 asyncLSRParityError1 |
416 asyncLSRBreakInterrupt1 )) != 0) {
417 outb(asyncLSRFramingError1 |
418 asyncLSROverrunError1 |
419 asyncLSRParityError1 |
420 asyncLSRBreakInterrupt1, UART1_BASE + UART_LSR);
421 }
422 }
423 return (0x000000ff & (int) inb(UART1_BASE));
424}
425
426
427void kgdb_interruptible (int yes)
428{
429 return;
430}
431
432#else /* ! (CONFIG_KGDB_SER_INDEX & 2) */
433
434void kgdb_serial_init (void)
435{
436 serial_printf ("[on serial] ");
437}
438
439void putDebugChar (int c)
440{
441 serial_putc (c);
442}
443
444void putDebugStr (const char *str)
445{
446 serial_puts (str);
447}
448
449int getDebugChar (void)
450{
451 return serial_getc ();
452}
453
454void kgdb_interruptible (int yes)
455{
456 return;
457}
458#endif /* (CONFIG_KGDB_SER_INDEX & 2) */
459#endif /* CFG_CMD_KGDB */
460