source: SVN/rincon/u-boot/cpu/i386/serial.c @ 55

Last change on this file since 55 was 55, checked in by Tim Harvey, 22 months ago

rincon: added latest u-boot source

restored form server backup

Signed-off-by: Tim Harvey <tharvey@…>

File size: 11.9 KB
Line 
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
58DECLARE_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  +-----------------------------------------------------------------------------*/
90typedef struct {
91        char *rx_buffer;
92        ulong rx_put;
93        ulong rx_get;
94        int cts;
95} serial_buffer_t;
96
97volatile serial_buffer_t buf_info;
98static int serial_buffer_active=0;
99#endif
100
101
102static 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
129int 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
149void 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
162void 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
180void serial_puts(const char *s)
181{
182        while (*s) {
183                serial_putc(*s++);
184        }
185}
186
187
188int 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
220int 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
249void 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
292void 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
324void 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
351void serial_buffered_puts(const char *s)
352{
353        serial_puts (s);
354}
355
356int 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
389int 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 defined(CONFIG_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)
407void 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
428void 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
440void putDebugStr(const char *s)
441{
442        while (*s) {
443                serial_putc(*s++);
444        }
445}
446
447
448int 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
471void kgdb_interruptible(int yes)
472{
473        return;
474}
475
476#else   /* ! (CONFIG_KGDB_SER_INDEX & 2) */
477
478void kgdb_serial_init(void)
479{
480        serial_printf ("[on serial] ");
481}
482
483void putDebugChar(int c)
484{
485        serial_putc (c);
486}
487
488void putDebugStr(const char *str)
489{
490        serial_puts (str);
491}
492
493int getDebugChar(void)
494{
495        return serial_getc ();
496}
497
498void kgdb_interruptible(int yes)
499{
500        return;
501}
502#endif  /* (CONFIG_KGDB_SER_INDEX & 2) */
503#endif
Note: See TracBrowser for help on using the repository browser.