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