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