uboot/cpu/i386/serial.c
<<
>>
Prefs
   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
 504