uboot/cpu/ppc4xx/4xx_uart.c
<<
>>
Prefs
   1/*
   2 * (C) Copyright 2000-2006
   3 * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
   4 *
   5 * See file CREDITS for list of people who contributed to this
   6 * project.
   7 *
   8 * This program is free software; you can redistribute it and/or
   9 * modify it under the terms of the GNU General Public License as
  10 * published by the Free Software Foundation; either version 2 of
  11 * the License, or (at your option) any later version.
  12 *
  13 * This program is distributed in the hope that it will be useful,
  14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  16 * GNU General Public License for more details.
  17 *
  18 * You should have received a copy of the GNU General Public License
  19 * along with this program; if not, write to the Free Software
  20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
  21 * MA 02111-1307 USA
  22 */
  23
  24/*
  25 * This source code has been made available to you by IBM on an AS-IS
  26 * basis.  Anyone receiving this source is licensed under IBM
  27 * copyrights to use it in any way he or she deems fit, including
  28 * copying it, modifying it, compiling it, and redistributing it either
  29 * with or without modifications.  No license under IBM patents or
  30 * patent applications is to be implied by the copyright license.
  31 *
  32 * Any user of this software should understand that IBM cannot provide
  33 * technical support for this software and will not be responsible for
  34 * any consequences resulting from the use of this software.
  35 *
  36 * Any person who transfers this source code or any derivative work
  37 * must include the IBM copyright notice, this paragraph, and the
  38 * preceding two paragraphs in the transferred software.
  39 *
  40 * COPYRIGHT   I B M   CORPORATION 1995
  41 * LICENSED MATERIAL  -  PROGRAM PROPERTY OF I B M
  42 */
  43
  44#include <common.h>
  45#include <commproc.h>
  46#include <asm/processor.h>
  47#include <asm/io.h>
  48#include <watchdog.h>
  49#include <ppc4xx.h>
  50
  51#ifdef CONFIG_SERIAL_MULTI
  52#include <serial.h>
  53#endif
  54
  55#ifdef CONFIG_SERIAL_SOFTWARE_FIFO
  56#include <malloc.h>
  57#endif
  58
  59DECLARE_GLOBAL_DATA_PTR;
  60
  61#if defined(CONFIG_405GP) || defined(CONFIG_405CR) || \
  62    defined(CONFIG_405EP) || defined(CONFIG_405EZ) || \
  63    defined(CONFIG_405EX) || defined(CONFIG_440)
  64
  65#if defined(CONFIG_440)
  66#if defined(CONFIG_440EP) || defined(CONFIG_440GR) || \
  67    defined(CONFIG_440EPX) || defined(CONFIG_440GRX) || \
  68    defined(CONFIG_460EX) || defined(CONFIG_460GT)
  69#define UART0_BASE      (CONFIG_SYS_PERIPHERAL_BASE + 0x00000300)
  70#define UART1_BASE      (CONFIG_SYS_PERIPHERAL_BASE + 0x00000400)
  71#else
  72#define UART0_BASE      (CONFIG_SYS_PERIPHERAL_BASE + 0x00000200)
  73#define UART1_BASE      (CONFIG_SYS_PERIPHERAL_BASE + 0x00000300)
  74#endif
  75
  76#if defined(CONFIG_440SP) || defined(CONFIG_440SPE)
  77#define UART2_BASE      (CONFIG_SYS_PERIPHERAL_BASE + 0x00000600)
  78#endif
  79
  80#if defined(CONFIG_460EX) || defined(CONFIG_460GT)
  81#define UART2_BASE      (CONFIG_SYS_PERIPHERAL_BASE + 0x00000500)
  82#define UART3_BASE      (CONFIG_SYS_PERIPHERAL_BASE + 0x00000600)
  83#endif
  84
  85#if defined(CONFIG_440GP)
  86#define CR0_MASK        0x3fff0000
  87#define CR0_EXTCLK_ENA  0x00600000
  88#define CR0_UDIV_POS    16
  89#define UDIV_SUBTRACT   1
  90#define UART0_SDR       cntrl0
  91#define MFREG(a, d)     d = mfdcr(a)
  92#define MTREG(a, d)     mtdcr(a, d)
  93#else /* #if defined(CONFIG_440GP) */
  94/* all other 440 PPC's access clock divider via sdr register */
  95#define CR0_MASK        0xdfffffff
  96#define CR0_EXTCLK_ENA  0x00800000
  97#define CR0_UDIV_POS    0
  98#define UDIV_SUBTRACT   0
  99#define UART0_SDR       sdr_uart0
 100#define UART1_SDR       sdr_uart1
 101#if defined(CONFIG_440EP) || defined(CONFIG_440EPX) || \
 102    defined(CONFIG_440GR) || defined(CONFIG_440GRX) || \
 103    defined(CONFIG_440SP) || defined(CONFIG_440SPE) || \
 104    defined(CONFIG_460EX) || defined(CONFIG_460GT)
 105#define UART2_SDR       sdr_uart2
 106#endif
 107#if defined(CONFIG_440EP) || defined(CONFIG_440EPX) || \
 108    defined(CONFIG_440GR) || defined(CONFIG_440GRX) || \
 109    defined(CONFIG_460EX) || defined(CONFIG_460GT)
 110#define UART3_SDR       sdr_uart3
 111#endif
 112#define MFREG(a, d)     mfsdr(a, d)
 113#define MTREG(a, d)     mtsdr(a, d)
 114#endif /* #if defined(CONFIG_440GP) */
 115#elif defined(CONFIG_405EP) || defined(CONFIG_405EZ)
 116#define UART0_BASE      0xef600300
 117#define UART1_BASE      0xef600400
 118#define UCR0_MASK       0x0000007f
 119#define UCR1_MASK       0x00007f00
 120#define UCR0_UDIV_POS   0
 121#define UCR1_UDIV_POS   8
 122#define UDIV_MAX        127
 123#elif defined(CONFIG_405EX)
 124#define UART0_BASE      0xef600200
 125#define UART1_BASE      0xef600300
 126#define CR0_MASK        0x000000ff
 127#define CR0_EXTCLK_ENA  0x00800000
 128#define CR0_UDIV_POS    0
 129#define UDIV_SUBTRACT   0
 130#define UART0_SDR       sdr_uart0
 131#define UART1_SDR       sdr_uart1
 132#else /* CONFIG_405GP || CONFIG_405CR */
 133#define UART0_BASE      0xef600300
 134#define UART1_BASE      0xef600400
 135#define CR0_MASK        0x00001fff
 136#define CR0_EXTCLK_ENA  0x000000c0
 137#define CR0_UDIV_POS    1
 138#define UDIV_MAX        32
 139#endif
 140
 141/* using serial port 0 or 1 as U-Boot console ? */
 142#if defined(CONFIG_UART1_CONSOLE)
 143#define ACTING_UART0_BASE       UART1_BASE
 144#define ACTING_UART1_BASE       UART0_BASE
 145#else
 146#define ACTING_UART0_BASE       UART0_BASE
 147#define ACTING_UART1_BASE       UART1_BASE
 148#endif
 149
 150#if defined(CONFIG_405EP) && defined(CONFIG_SYS_EXT_SERIAL_CLOCK)
 151#error "External serial clock not supported on AMCC PPC405EP!"
 152#endif
 153
 154#define UART_RBR    0x00
 155#define UART_THR    0x00
 156#define UART_IER    0x01
 157#define UART_IIR    0x02
 158#define UART_FCR    0x02
 159#define UART_LCR    0x03
 160#define UART_MCR    0x04
 161#define UART_LSR    0x05
 162#define UART_MSR    0x06
 163#define UART_SCR    0x07
 164#define UART_DLL    0x00
 165#define UART_DLM    0x01
 166
 167/*-----------------------------------------------------------------------------+
 168  | Line Status Register.
 169  +-----------------------------------------------------------------------------*/
 170#define asyncLSRDataReady1            0x01
 171#define asyncLSROverrunError1         0x02
 172#define asyncLSRParityError1          0x04
 173#define asyncLSRFramingError1         0x08
 174#define asyncLSRBreakInterrupt1       0x10
 175#define asyncLSRTxHoldEmpty1          0x20
 176#define asyncLSRTxShiftEmpty1         0x40
 177#define asyncLSRRxFifoError1          0x80
 178
 179#ifdef CONFIG_SERIAL_SOFTWARE_FIFO
 180/*-----------------------------------------------------------------------------+
 181  | Fifo
 182  +-----------------------------------------------------------------------------*/
 183typedef struct {
 184        char *rx_buffer;
 185        ulong rx_put;
 186        ulong rx_get;
 187} serial_buffer_t;
 188
 189volatile static serial_buffer_t buf_info;
 190#endif
 191
 192static void serial_init_common(u32 base, u32 udiv, u16 bdiv)
 193{
 194        PPC4xx_SYS_INFO sys_info;
 195        u8 val;
 196
 197        get_sys_info(&sys_info);
 198
 199        /* Correct UART frequency in bd-info struct now that
 200         * the UART divisor is available
 201         */
 202#ifdef CONFIG_SYS_EXT_SERIAL_CLOCK
 203        gd->uart_clk = CONFIG_SYS_EXT_SERIAL_CLOCK;
 204#else
 205        gd->uart_clk = sys_info.freqUART / udiv;
 206#endif
 207
 208        out_8((u8 *)base + UART_LCR, 0x80);     /* set DLAB bit */
 209        out_8((u8 *)base + UART_DLL, bdiv);     /* set baudrate divisor */
 210        out_8((u8 *)base + UART_DLM, bdiv >> 8); /* set baudrate divisor */
 211        out_8((u8 *)base + UART_LCR, 0x03);     /* clear DLAB; set 8 bits, no parity */
 212        out_8((u8 *)base + UART_FCR, 0x00);     /* disable FIFO */
 213        out_8((u8 *)base + UART_MCR, 0x00);     /* no modem control DTR RTS */
 214        val = in_8((u8 *)base + UART_LSR);      /* clear line status */
 215        val = in_8((u8 *)base + UART_RBR);      /* read receive buffer */
 216        out_8((u8 *)base + UART_SCR, 0x00);     /* set scratchpad */
 217        out_8((u8 *)base + UART_IER, 0x00);     /* set interrupt enable reg */
 218}
 219
 220#if (defined(CONFIG_440) || defined(CONFIG_405EX)) &&   \
 221    !defined(CONFIG_SYS_EXT_SERIAL_CLOCK)
 222static void serial_divs (int baudrate, unsigned long *pudiv,
 223                         unsigned short *pbdiv)
 224{
 225        sys_info_t sysinfo;
 226        unsigned long div;              /* total divisor udiv * bdiv */
 227        unsigned long umin;             /* minimum udiv */
 228        unsigned short diff;            /* smallest diff */
 229        unsigned long udiv;             /* best udiv */
 230        unsigned short idiff;           /* current diff */
 231        unsigned short ibdiv;           /* current bdiv */
 232        unsigned long i;
 233        unsigned long est;              /* current estimate */
 234
 235        get_sys_info(&sysinfo);
 236
 237        udiv = 32;                      /* Assume lowest possible serial clk */
 238        div = sysinfo.freqPLB / (16 * baudrate); /* total divisor */
 239        umin = sysinfo.pllOpbDiv << 1;  /* 2 x OPB divisor */
 240        diff = 32;                      /* highest possible */
 241
 242        /* i is the test udiv value -- start with the largest
 243         * possible (32) to minimize serial clock and constrain
 244         * search to umin.
 245         */
 246        for (i = 32; i > umin; i--) {
 247                ibdiv = div / i;
 248                est = i * ibdiv;
 249                idiff = (est > div) ? (est-div) : (div-est);
 250                if (idiff == 0) {
 251                        udiv = i;
 252                        break;      /* can't do better */
 253                } else if (idiff < diff) {
 254                        udiv = i;       /* best so far */
 255                        diff = idiff;   /* update lowest diff*/
 256                }
 257        }
 258
 259        *pudiv = udiv;
 260        *pbdiv = div / udiv;
 261}
 262
 263#elif defined(CONFIG_405EZ)
 264
 265static void serial_divs (int baudrate, unsigned long *pudiv,
 266                         unsigned short *pbdiv)
 267{
 268        sys_info_t sysinfo;
 269        unsigned long div;              /* total divisor udiv * bdiv */
 270        unsigned long umin;             /* minimum udiv */
 271        unsigned short diff;            /* smallest diff */
 272        unsigned long udiv;             /* best udiv */
 273        unsigned short idiff;           /* current diff */
 274        unsigned short ibdiv;           /* current bdiv */
 275        unsigned long i;
 276        unsigned long est;              /* current estimate */
 277        unsigned long plloutb;
 278        unsigned long cpr_pllc;
 279        u32 reg;
 280
 281        /* check the pll feedback source */
 282        mfcpr(cprpllc, cpr_pllc);
 283
 284        get_sys_info(&sysinfo);
 285
 286        plloutb = ((CONFIG_SYS_CLK_FREQ * ((cpr_pllc & PLLC_SRC_MASK) ?
 287                                           sysinfo.pllFwdDivB : sysinfo.pllFwdDiv) *
 288                    sysinfo.pllFbkDiv) / sysinfo.pllFwdDivB);
 289        udiv = 256;                     /* Assume lowest possible serial clk */
 290        div = plloutb / (16 * baudrate); /* total divisor */
 291        umin = (plloutb / get_OPB_freq()) << 1; /* 2 x OPB divisor */
 292        diff = 256;                     /* highest possible */
 293
 294        /* i is the test udiv value -- start with the largest
 295         * possible (256) to minimize serial clock and constrain
 296         * search to umin.
 297         */
 298        for (i = 256; i > umin; i--) {
 299                ibdiv = div / i;
 300                est = i * ibdiv;
 301                idiff = (est > div) ? (est-div) : (div-est);
 302                if (idiff == 0) {
 303                        udiv = i;
 304                        break;      /* can't do better */
 305                } else if (idiff < diff) {
 306                        udiv = i;       /* best so far */
 307                        diff = idiff;   /* update lowest diff*/
 308                }
 309        }
 310
 311        *pudiv = udiv;
 312        mfcpr(cprperd0, reg);
 313        reg &= ~0x0000ffff;
 314        reg |= ((udiv - 0) << 8) | (udiv - 0);
 315        mtcpr(cprperd0, reg);
 316        *pbdiv = div / udiv;
 317}
 318#endif /* defined(CONFIG_440) && !defined(CONFIG_SYS_EXT_SERIAL_CLK) */
 319
 320/*
 321 * Minimal serial functions needed to use one of the SMC ports
 322 * as serial console interface.
 323 */
 324
 325#if defined(CONFIG_440)
 326int serial_init_dev(unsigned long base)
 327{
 328        unsigned long reg;
 329        unsigned long udiv;
 330        unsigned short bdiv;
 331#ifdef CONFIG_SYS_EXT_SERIAL_CLOCK
 332        unsigned long tmp;
 333#endif
 334
 335        MFREG(UART0_SDR, reg);
 336        reg &= ~CR0_MASK;
 337
 338#ifdef CONFIG_SYS_EXT_SERIAL_CLOCK
 339        reg |= CR0_EXTCLK_ENA;
 340        udiv = 1;
 341        tmp  = gd->baudrate * 16;
 342        bdiv = (CONFIG_SYS_EXT_SERIAL_CLOCK + tmp / 2) / tmp;
 343#else
 344        /* For 440, the cpu clock is on divider chain A, UART on divider
 345         * chain B ... so cpu clock is irrelevant. Get the "optimized"
 346         * values that are subject to the 1/2 opb clock constraint
 347         */
 348        serial_divs (gd->baudrate, &udiv, &bdiv);
 349#endif
 350
 351        reg |= (udiv - UDIV_SUBTRACT) << CR0_UDIV_POS;  /* set the UART divisor */
 352
 353        /*
 354         * Configure input clock to baudrate generator for all
 355         * available serial ports here
 356         */
 357        MTREG(UART0_SDR, reg);
 358#if defined(UART1_SDR)
 359        MTREG(UART1_SDR, reg);
 360#endif
 361#if defined(UART2_SDR)
 362        MTREG(UART2_SDR, reg);
 363#endif
 364#if defined(UART3_SDR)
 365        MTREG(UART3_SDR, reg);
 366#endif
 367
 368        serial_init_common(base, udiv, bdiv);
 369
 370        return (0);
 371}
 372
 373#else /* !defined(CONFIG_440) */
 374
 375int serial_init_dev (unsigned long base)
 376{
 377        unsigned long reg;
 378        unsigned long tmp;
 379        unsigned long clk;
 380        unsigned long udiv;
 381        unsigned short bdiv;
 382
 383#ifdef CONFIG_405EX
 384        clk = tmp = 0;
 385        mfsdr(UART0_SDR, reg);
 386        reg &= ~CR0_MASK;
 387#ifdef CONFIG_SYS_EXT_SERIAL_CLOCK
 388        reg |= CR0_EXTCLK_ENA;
 389        udiv = 1;
 390        tmp  = gd->baudrate * 16;
 391        bdiv = (CONFIG_SYS_EXT_SERIAL_CLOCK + tmp / 2) / tmp;
 392#else
 393        serial_divs(gd->baudrate, &udiv, &bdiv);
 394#endif
 395        reg |= (udiv - UDIV_SUBTRACT) << CR0_UDIV_POS;  /* set the UART divisor */
 396
 397        /*
 398         * Configure input clock to baudrate generator for all
 399         * available serial ports here
 400         */
 401        mtsdr(UART0_SDR, reg);
 402
 403#if defined(UART1_SDR)
 404        mtsdr(UART1_SDR, reg);
 405#endif
 406
 407#elif defined(CONFIG_405EZ)
 408        serial_divs(gd->baudrate, &udiv, &bdiv);
 409        clk = tmp = reg = 0;
 410#else
 411#ifdef CONFIG_405EP
 412        reg = mfdcr(cpc0_ucr) & ~(UCR0_MASK | UCR1_MASK);
 413        clk = gd->cpu_clk;
 414        tmp = CONFIG_SYS_BASE_BAUD * 16;
 415        udiv = (clk + tmp / 2) / tmp;
 416        if (udiv > UDIV_MAX)                    /* max. n bits for udiv */
 417                udiv = UDIV_MAX;
 418        reg |= (udiv) << UCR0_UDIV_POS;         /* set the UART divisor */
 419        reg |= (udiv) << UCR1_UDIV_POS;         /* set the UART divisor */
 420        mtdcr (cpc0_ucr, reg);
 421#else /* CONFIG_405EP */
 422        reg = mfdcr(cntrl0) & ~CR0_MASK;
 423#ifdef CONFIG_SYS_EXT_SERIAL_CLOCK
 424        clk = CONFIG_SYS_EXT_SERIAL_CLOCK;
 425        udiv = 1;
 426        reg |= CR0_EXTCLK_ENA;
 427#else
 428        clk = gd->cpu_clk;
 429#ifdef CONFIG_SYS_405_UART_ERRATA_59
 430        udiv = 31;                      /* Errata 59: stuck at 31 */
 431#else
 432        tmp = CONFIG_SYS_BASE_BAUD * 16;
 433        udiv = (clk + tmp / 2) / tmp;
 434        if (udiv > UDIV_MAX)                    /* max. n bits for udiv */
 435                udiv = UDIV_MAX;
 436#endif
 437#endif
 438        reg |= (udiv - 1) << CR0_UDIV_POS;      /* set the UART divisor */
 439        mtdcr (cntrl0, reg);
 440#endif /* CONFIG_405EP */
 441        tmp = gd->baudrate * udiv * 16;
 442        bdiv = (clk + tmp / 2) / tmp;
 443#endif /* CONFIG_405EX */
 444
 445        serial_init_common(base, udiv, bdiv);
 446
 447        return (0);
 448}
 449
 450#endif /* if defined(CONFIG_440) */
 451
 452void serial_setbrg_dev(unsigned long base)
 453{
 454        serial_init_dev(base);
 455}
 456
 457void serial_putc_dev(unsigned long base, const char c)
 458{
 459        int i;
 460
 461        if (c == '\n')
 462                serial_putc_dev(base, '\r');
 463
 464        /* check THRE bit, wait for transmiter available */
 465        for (i = 1; i < 3500; i++) {
 466                if ((in_8((u8 *)base + UART_LSR) & 0x20) == 0x20)
 467                        break;
 468                udelay (100);
 469        }
 470
 471        out_8((u8 *)base + UART_THR, c);        /* put character out */
 472}
 473
 474void serial_puts_dev (unsigned long base, const char *s)
 475{
 476        while (*s)
 477                serial_putc_dev (base, *s++);
 478}
 479
 480int serial_getc_dev (unsigned long base)
 481{
 482        unsigned char status = 0;
 483
 484        while (1) {
 485#if defined(CONFIG_HW_WATCHDOG)
 486                WATCHDOG_RESET ();      /* Reset HW Watchdog, if needed */
 487#endif  /* CONFIG_HW_WATCHDOG */
 488
 489                status = in_8((u8 *)base + UART_LSR);
 490                if ((status & asyncLSRDataReady1) != 0x0)
 491                        break;
 492
 493                if ((status & ( asyncLSRFramingError1 |
 494                                asyncLSROverrunError1 |
 495                                asyncLSRParityError1  |
 496                                asyncLSRBreakInterrupt1 )) != 0) {
 497                        out_8((u8 *)base + UART_LSR,
 498                              asyncLSRFramingError1 |
 499                              asyncLSROverrunError1 |
 500                              asyncLSRParityError1  |
 501                              asyncLSRBreakInterrupt1);
 502                }
 503        }
 504
 505        return (0x000000ff & (int) in_8((u8 *)base));
 506}
 507
 508int serial_tstc_dev (unsigned long base)
 509{
 510        unsigned char status;
 511
 512        status = in_8((u8 *)base + UART_LSR);
 513        if ((status & asyncLSRDataReady1) != 0x0)
 514                return (1);
 515
 516        if ((status & ( asyncLSRFramingError1 |
 517                        asyncLSROverrunError1 |
 518                        asyncLSRParityError1  |
 519                        asyncLSRBreakInterrupt1 )) != 0) {
 520                out_8((u8 *)base + UART_LSR,
 521                      asyncLSRFramingError1 |
 522                      asyncLSROverrunError1 |
 523                      asyncLSRParityError1  |
 524                      asyncLSRBreakInterrupt1);
 525        }
 526
 527        return 0;
 528}
 529
 530#ifdef CONFIG_SERIAL_SOFTWARE_FIFO
 531
 532void serial_isr (void *arg)
 533{
 534        int space;
 535        int c;
 536        const int rx_get = buf_info.rx_get;
 537        int rx_put = buf_info.rx_put;
 538
 539        if (rx_get <= rx_put)
 540                space = CONFIG_SERIAL_SOFTWARE_FIFO - (rx_put - rx_get);
 541        else
 542                space = rx_get - rx_put;
 543
 544        while (serial_tstc_dev (ACTING_UART0_BASE)) {
 545                c = serial_getc_dev (ACTING_UART0_BASE);
 546                if (space) {
 547                        buf_info.rx_buffer[rx_put++] = c;
 548                        space--;
 549                }
 550                if (rx_put == CONFIG_SERIAL_SOFTWARE_FIFO)
 551                        rx_put = 0;
 552                if (space < CONFIG_SERIAL_SOFTWARE_FIFO / 4) {
 553                        /* Stop flow by setting RTS inactive */
 554                        out_8((u8 *)ACTING_UART0_BASE + UART_MCR,
 555                              in_8((u8 *)ACTING_UART0_BASE + UART_MCR) &
 556                              (0xFF ^ 0x02));
 557                }
 558        }
 559        buf_info.rx_put = rx_put;
 560}
 561
 562void serial_buffered_init (void)
 563{
 564        serial_puts ("Switching to interrupt driven serial input mode.\n");
 565        buf_info.rx_buffer = malloc (CONFIG_SERIAL_SOFTWARE_FIFO);
 566        buf_info.rx_put = 0;
 567        buf_info.rx_get = 0;
 568
 569        if (in_8((u8 *)ACTING_UART0_BASE + UART_MSR) & 0x10)
 570                serial_puts ("Check CTS signal present on serial port: OK.\n");
 571        else
 572                serial_puts ("WARNING: CTS signal not present on serial port.\n");
 573
 574        irq_install_handler ( VECNUM_U0 /*UART0 */ /*int vec */ ,
 575                              serial_isr /*interrupt_handler_t *handler */ ,
 576                              (void *) &buf_info /*void *arg */ );
 577
 578        /* Enable "RX Data Available" Interrupt on UART */
 579        out_8(ACTING_UART0_BASE + UART_IER, 0x01);
 580        /* Set DTR active */
 581        out_8(ACTING_UART0_BASE + UART_MCR,
 582              in_8((u8 *)ACTING_UART0_BASE + UART_MCR) | 0x01);
 583        /* Start flow by setting RTS active */
 584        out_8(ACTING_UART0_BASE + UART_MCR,
 585              in_8((u8 *)ACTING_UART0_BASE + UART_MCR) | 0x02);
 586        /* Setup UART FIFO: RX trigger level: 4 byte, Enable FIFO */
 587        out_8(ACTING_UART0_BASE + UART_FCR, (1 << 6) | 1);
 588}
 589
 590void serial_buffered_putc (const char c)
 591{
 592        /* Wait for CTS */
 593#if defined(CONFIG_HW_WATCHDOG)
 594        while (!(in_8((u8 *)ACTING_UART0_BASE + UART_MSR) & 0x10))
 595                WATCHDOG_RESET ();
 596#else
 597        while (!(in_8((u8 *)ACTING_UART0_BASE + UART_MSR) & 0x10));
 598#endif
 599        serial_putc (c);
 600}
 601
 602void serial_buffered_puts (const char *s)
 603{
 604        serial_puts (s);
 605}
 606
 607int serial_buffered_getc (void)
 608{
 609        int space;
 610        int c;
 611        int rx_get = buf_info.rx_get;
 612        int rx_put;
 613
 614#if defined(CONFIG_HW_WATCHDOG)
 615        while (rx_get == buf_info.rx_put)
 616                WATCHDOG_RESET ();
 617#else
 618        while (rx_get == buf_info.rx_put);
 619#endif
 620        c = buf_info.rx_buffer[rx_get++];
 621        if (rx_get == CONFIG_SERIAL_SOFTWARE_FIFO)
 622                rx_get = 0;
 623        buf_info.rx_get = rx_get;
 624
 625        rx_put = buf_info.rx_put;
 626        if (rx_get <= rx_put)
 627                space = CONFIG_SERIAL_SOFTWARE_FIFO - (rx_put - rx_get);
 628        else
 629                space = rx_get - rx_put;
 630
 631        if (space > CONFIG_SERIAL_SOFTWARE_FIFO / 2) {
 632                /* Start flow by setting RTS active */
 633                out_8(ACTING_UART0_BASE + UART_MCR,
 634                      in_8((u8 *)ACTING_UART0_BASE + UART_MCR) | 0x02);
 635        }
 636
 637        return c;
 638}
 639
 640int serial_buffered_tstc (void)
 641{
 642        return (buf_info.rx_get != buf_info.rx_put) ? 1 : 0;
 643}
 644
 645#endif  /* CONFIG_SERIAL_SOFTWARE_FIFO */
 646
 647#if defined(CONFIG_CMD_KGDB)
 648/*
 649  AS HARNOIS : according to CONFIG_KGDB_SER_INDEX kgdb uses serial port
 650  number 0 or number 1
 651  - if CONFIG_KGDB_SER_INDEX = 1 => serial port number 0 :
 652  configuration has been already done
 653  - if CONFIG_KGDB_SER_INDEX = 2 => serial port number 1 :
 654  configure port 1 for serial I/O with rate = CONFIG_KGDB_BAUDRATE
 655*/
 656#if (CONFIG_KGDB_SER_INDEX & 2)
 657void kgdb_serial_init (void)
 658{
 659        u8 val;
 660        u16 br_reg;
 661
 662        get_clocks ();
 663        br_reg = (((((gd->cpu_clk / 16) / 18) * 10) / CONFIG_KGDB_BAUDRATE) +
 664                  5) / 10;
 665        /*
 666         * Init onboard 16550 UART
 667         */
 668        out_8((u8 *)ACTING_UART1_BASE + UART_LCR, 0x80);        /* set DLAB bit */
 669        out_8((u8 *)ACTING_UART1_BASE + UART_DLL, (br_reg & 0x00ff)); /* set divisor for 9600 baud */
 670        out_8((u8 *)ACTING_UART1_BASE + UART_DLM, ((br_reg & 0xff00) >> 8)); /* set divisor for 9600 baud */
 671        out_8((u8 *)ACTING_UART1_BASE + UART_LCR, 0x03);        /* line control 8 bits no parity */
 672        out_8((u8 *)ACTING_UART1_BASE + UART_FCR, 0x00);        /* disable FIFO */
 673        out_8((u8 *)ACTING_UART1_BASE + UART_MCR, 0x00);        /* no modem control DTR RTS */
 674        val = in_8((u8 *)ACTING_UART1_BASE + UART_LSR);         /* clear line status */
 675        val = in_8((u8 *)ACTING_UART1_BASE + UART_RBR);         /* read receive buffer */
 676        out_8((u8 *)ACTING_UART1_BASE + UART_SCR, 0x00);        /* set scratchpad */
 677        out_8((u8 *)ACTING_UART1_BASE + UART_IER, 0x00);        /* set interrupt enable reg */
 678}
 679
 680void putDebugChar (const char c)
 681{
 682        if (c == '\n')
 683                serial_putc ('\r');
 684
 685        out_8((u8 *)ACTING_UART1_BASE + UART_THR, c);   /* put character out */
 686
 687        /* check THRE bit, wait for transfer done */
 688        while ((in_8((u8 *)ACTING_UART1_BASE + UART_LSR) & 0x20) != 0x20);
 689}
 690
 691void putDebugStr (const char *s)
 692{
 693        while (*s)
 694                serial_putc (*s++);
 695}
 696
 697int getDebugChar (void)
 698{
 699        unsigned char status = 0;
 700
 701        while (1) {
 702                status = in_8((u8 *)ACTING_UART1_BASE + UART_LSR);
 703                if ((status & asyncLSRDataReady1) != 0x0)
 704                        break;
 705
 706                if ((status & (asyncLSRFramingError1 |
 707                               asyncLSROverrunError1 |
 708                               asyncLSRParityError1  |
 709                               asyncLSRBreakInterrupt1 )) != 0) {
 710                        out_8((u8 *)ACTING_UART1_BASE + UART_LSR,
 711                              asyncLSRFramingError1 |
 712                              asyncLSROverrunError1 |
 713                              asyncLSRParityError1  |
 714                              asyncLSRBreakInterrupt1);
 715                }
 716        }
 717
 718        return (0x000000ff & (int) in_8((u8 *)ACTING_UART1_BASE));
 719}
 720
 721void kgdb_interruptible (int yes)
 722{
 723        return;
 724}
 725
 726#else   /* ! (CONFIG_KGDB_SER_INDEX & 2) */
 727
 728void kgdb_serial_init (void)
 729{
 730        serial_printf ("[on serial] ");
 731}
 732
 733void putDebugChar (int c)
 734{
 735        serial_putc (c);
 736}
 737
 738void putDebugStr (const char *str)
 739{
 740        serial_puts (str);
 741}
 742
 743int getDebugChar (void)
 744{
 745        return serial_getc ();
 746}
 747
 748void kgdb_interruptible (int yes)
 749{
 750        return;
 751}
 752#endif  /* (CONFIG_KGDB_SER_INDEX & 2) */
 753#endif
 754
 755
 756#if defined(CONFIG_SERIAL_MULTI)
 757int serial0_init(void)
 758{
 759        return (serial_init_dev(UART0_BASE));
 760}
 761
 762int serial1_init(void)
 763{
 764        return (serial_init_dev(UART1_BASE));
 765}
 766
 767void serial0_setbrg (void)
 768{
 769        serial_setbrg_dev(UART0_BASE);
 770}
 771
 772void serial1_setbrg (void)
 773{
 774        serial_setbrg_dev(UART1_BASE);
 775}
 776
 777void serial0_putc(const char c)
 778{
 779        serial_putc_dev(UART0_BASE,c);
 780}
 781
 782void serial1_putc(const char c)
 783{
 784        serial_putc_dev(UART1_BASE, c);
 785}
 786
 787void serial0_puts(const char *s)
 788{
 789        serial_puts_dev(UART0_BASE, s);
 790}
 791
 792void serial1_puts(const char *s)
 793{
 794        serial_puts_dev(UART1_BASE, s);
 795}
 796
 797int serial0_getc(void)
 798{
 799        return(serial_getc_dev(UART0_BASE));
 800}
 801
 802int serial1_getc(void)
 803{
 804        return(serial_getc_dev(UART1_BASE));
 805}
 806
 807int serial0_tstc(void)
 808{
 809        return (serial_tstc_dev(UART0_BASE));
 810}
 811
 812int serial1_tstc(void)
 813{
 814        return (serial_tstc_dev(UART1_BASE));
 815}
 816
 817struct serial_device serial0_device =
 818{
 819        "serial0",
 820        "UART0",
 821        serial0_init,
 822        serial0_setbrg,
 823        serial0_getc,
 824        serial0_tstc,
 825        serial0_putc,
 826        serial0_puts,
 827};
 828
 829struct serial_device serial1_device =
 830{
 831        "serial1",
 832        "UART1",
 833        serial1_init,
 834        serial1_setbrg,
 835        serial1_getc,
 836        serial1_tstc,
 837        serial1_putc,
 838        serial1_puts,
 839};
 840#else
 841/*
 842 * Wrapper functions
 843 */
 844int serial_init(void)
 845{
 846        return serial_init_dev(ACTING_UART0_BASE);
 847}
 848
 849void serial_setbrg(void)
 850{
 851        serial_setbrg_dev(ACTING_UART0_BASE);
 852}
 853
 854void serial_putc(const char c)
 855{
 856        serial_putc_dev(ACTING_UART0_BASE, c);
 857}
 858
 859void serial_puts(const char *s)
 860{
 861        serial_puts_dev(ACTING_UART0_BASE, s);
 862}
 863
 864int serial_getc(void)
 865{
 866        return serial_getc_dev(ACTING_UART0_BASE);
 867}
 868
 869int serial_tstc(void)
 870{
 871        return serial_tstc_dev(ACTING_UART0_BASE);
 872}
 873#endif /* CONFIG_SERIAL_MULTI */
 874
 875#endif  /* CONFIG_405GP || CONFIG_405CR */
 876