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