uboot/arch/mips/cpu/mips32/incaip/asc_serial.c
<<
>>
Prefs
   1/*
   2 * (INCA) ASC UART support
   3 */
   4
   5#include <config.h>
   6#include <common.h>
   7#include <asm/inca-ip.h>
   8#include <serial.h>
   9#include <linux/compiler.h>
  10#include "asc_serial.h"
  11
  12
  13#define SET_BIT(reg, mask)                  reg |= (mask)
  14#define CLEAR_BIT(reg, mask)                reg &= (~mask)
  15#define CLEAR_BITS(reg, mask)               CLEAR_BIT(reg, mask)
  16#define SET_BITS(reg, mask)                 SET_BIT(reg, mask)
  17#define SET_BITFIELD(reg, mask, off, val)   {reg &= (~mask); reg |= (val << off);}
  18
  19extern uint incaip_get_fpiclk(void);
  20
  21static int serial_setopt (void);
  22
  23/* pointer to ASC register base address */
  24static volatile incaAsc_t *pAsc = (incaAsc_t *)INCA_IP_ASC;
  25
  26/******************************************************************************
  27*
  28* serial_init - initialize a INCAASC channel
  29*
  30* This routine initializes the number of data bits, parity
  31* and set the selected baud rate. Interrupts are disabled.
  32* Set the modem control signals if the option is selected.
  33*
  34* RETURNS: N/A
  35*/
  36
  37static int asc_serial_init(void)
  38{
  39    /* we have to set PMU.EN13 bit to enable an ASC device*/
  40    INCAASC_PMU_ENABLE(13);
  41
  42    /* and we have to set CLC register*/
  43    CLEAR_BIT(pAsc->asc_clc, ASCCLC_DISS);
  44    SET_BITFIELD(pAsc->asc_clc, ASCCLC_RMCMASK, ASCCLC_RMCOFFSET, 0x0001);
  45
  46    /* initialy we are in async mode */
  47    pAsc->asc_con = ASCCON_M_8ASYNC;
  48
  49    /* select input port */
  50    pAsc->asc_pisel = (CONSOLE_TTY & 0x1);
  51
  52    /* TXFIFO's filling level */
  53    SET_BITFIELD(pAsc->asc_txfcon, ASCTXFCON_TXFITLMASK,
  54                    ASCTXFCON_TXFITLOFF, INCAASC_TXFIFO_FL);
  55    /* enable TXFIFO */
  56    SET_BIT(pAsc->asc_txfcon, ASCTXFCON_TXFEN);
  57
  58    /* RXFIFO's filling level */
  59    SET_BITFIELD(pAsc->asc_txfcon, ASCRXFCON_RXFITLMASK,
  60                    ASCRXFCON_RXFITLOFF, INCAASC_RXFIFO_FL);
  61    /* enable RXFIFO */
  62    SET_BIT(pAsc->asc_rxfcon, ASCRXFCON_RXFEN);
  63
  64    /* enable error signals */
  65    SET_BIT(pAsc->asc_con, ASCCON_FEN);
  66    SET_BIT(pAsc->asc_con, ASCCON_OEN);
  67
  68    /* acknowledge ASC interrupts */
  69    ASC_INTERRUPTS_CLEAR(INCAASC_IRQ_LINE_ALL);
  70
  71    /* disable ASC interrupts */
  72    ASC_INTERRUPTS_DISABLE(INCAASC_IRQ_LINE_ALL);
  73
  74    /* set FIFOs into the transparent mode */
  75    SET_BIT(pAsc->asc_txfcon, ASCTXFCON_TXTMEN);
  76    SET_BIT(pAsc->asc_rxfcon, ASCRXFCON_RXTMEN);
  77
  78    /* set baud rate */
  79    serial_setbrg();
  80
  81    /* set the options */
  82    serial_setopt();
  83
  84    return 0;
  85}
  86
  87static void asc_serial_setbrg(void)
  88{
  89    ulong      uiReloadValue, fdv;
  90    ulong      f_ASC;
  91
  92    f_ASC = incaip_get_fpiclk();
  93
  94#ifndef INCAASC_USE_FDV
  95    fdv = 2;
  96    uiReloadValue = (f_ASC / (fdv * 16 * CONFIG_BAUDRATE)) - 1;
  97#else
  98    fdv = INCAASC_FDV_HIGH_BAUDRATE;
  99    uiReloadValue = (f_ASC / (8192 * CONFIG_BAUDRATE / fdv)) - 1;
 100#endif /* INCAASC_USE_FDV */
 101
 102    if ( (uiReloadValue < 0) || (uiReloadValue > 8191) )
 103    {
 104#ifndef INCAASC_USE_FDV
 105        fdv = 3;
 106        uiReloadValue = (f_ASC / (fdv * 16 * CONFIG_BAUDRATE)) - 1;
 107#else
 108        fdv = INCAASC_FDV_LOW_BAUDRATE;
 109        uiReloadValue = (f_ASC / (8192 * CONFIG_BAUDRATE / fdv)) - 1;
 110#endif /* INCAASC_USE_FDV */
 111
 112        if ( (uiReloadValue < 0) || (uiReloadValue > 8191) )
 113        {
 114            return;    /* can't impossibly generate that baud rate */
 115        }
 116    }
 117
 118    /* Disable Baud Rate Generator; BG should only be written when R=0 */
 119    CLEAR_BIT(pAsc->asc_con, ASCCON_R);
 120
 121#ifndef INCAASC_USE_FDV
 122    /*
 123     * Disable Fractional Divider (FDE)
 124     * Divide clock by reload-value + constant (BRS)
 125     */
 126    /* FDE = 0 */
 127    CLEAR_BIT(pAsc->asc_con, ASCCON_FDE);
 128
 129    if ( fdv == 2 )
 130        CLEAR_BIT(pAsc->asc_con, ASCCON_BRS);   /* BRS = 0 */
 131    else
 132        SET_BIT(pAsc->asc_con, ASCCON_BRS); /* BRS = 1 */
 133
 134#else /* INCAASC_USE_FDV */
 135
 136    /* Enable Fractional Divider */
 137    SET_BIT(pAsc->asc_con, ASCCON_FDE); /* FDE = 1 */
 138
 139    /* Set fractional divider value */
 140    pAsc->asc_fdv = fdv & ASCFDV_VALUE_MASK;
 141
 142#endif /* INCAASC_USE_FDV */
 143
 144    /* Set reload value in BG */
 145    pAsc->asc_bg = uiReloadValue;
 146
 147    /* Enable Baud Rate Generator */
 148    SET_BIT(pAsc->asc_con, ASCCON_R);           /* R = 1 */
 149}
 150
 151/*******************************************************************************
 152*
 153* serial_setopt - set the serial options
 154*
 155* Set the channel operating mode to that specified. Following options
 156* are supported: CREAD, CSIZE, PARENB, and PARODD.
 157*
 158* Note, this routine disables the transmitter.  The calling routine
 159* may have to re-enable it.
 160*
 161* RETURNS:
 162* Returns 0 to indicate success, otherwise -1 is returned
 163*/
 164
 165static int serial_setopt (void)
 166{
 167    ulong  con;
 168
 169    switch ( ASC_OPTIONS & ASCOPT_CSIZE )
 170    {
 171    /* 7-bit-data */
 172    case ASCOPT_CS7:
 173        con = ASCCON_M_7ASYNCPAR;   /* 7-bit-data and parity bit */
 174        break;
 175
 176    /* 8-bit-data */
 177    case ASCOPT_CS8:
 178        if ( ASC_OPTIONS & ASCOPT_PARENB )
 179            con = ASCCON_M_8ASYNCPAR;   /* 8-bit-data and parity bit */
 180        else
 181            con = ASCCON_M_8ASYNC;      /* 8-bit-data no parity */
 182        break;
 183
 184    /*
 185     *  only 7 and 8-bit frames are supported
 186     *  if we don't use IOCTL extensions
 187     */
 188    default:
 189        return -1;
 190    }
 191
 192    if ( ASC_OPTIONS & ASCOPT_STOPB )
 193        SET_BIT(con, ASCCON_STP);       /* 2 stop bits */
 194    else
 195        CLEAR_BIT(con, ASCCON_STP);     /* 1 stop bit */
 196
 197    if ( ASC_OPTIONS & ASCOPT_PARENB )
 198        SET_BIT(con, ASCCON_PEN);           /* enable parity checking */
 199    else
 200        CLEAR_BIT(con, ASCCON_PEN);         /* disable parity checking */
 201
 202    if ( ASC_OPTIONS & ASCOPT_PARODD )
 203        SET_BIT(con, ASCCON_ODD);       /* odd parity */
 204    else
 205        CLEAR_BIT(con, ASCCON_ODD);     /* even parity */
 206
 207    if ( ASC_OPTIONS & ASCOPT_CREAD )
 208        SET_BIT(pAsc->asc_whbcon, ASCWHBCON_SETREN); /* Receiver enable */
 209
 210    pAsc->asc_con |= con;
 211
 212    return 0;
 213}
 214
 215static void asc_serial_putc(const char c)
 216{
 217    uint txFl = 0;
 218
 219    if (c == '\n') serial_putc ('\r');
 220
 221    /* check do we have a free space in the TX FIFO */
 222    /* get current filling level */
 223    do
 224    {
 225        txFl = ( pAsc->asc_fstat & ASCFSTAT_TXFFLMASK ) >> ASCFSTAT_TXFFLOFF;
 226    }
 227    while ( txFl == INCAASC_TXFIFO_FULL );
 228
 229    pAsc->asc_tbuf = c; /* write char to Transmit Buffer Register */
 230
 231    /* check for errors */
 232    if ( pAsc->asc_con & ASCCON_OE )
 233    {
 234        SET_BIT(pAsc->asc_whbcon, ASCWHBCON_CLROE);
 235        return;
 236    }
 237}
 238
 239static int asc_serial_getc(void)
 240{
 241    ulong symbol_mask;
 242    char c;
 243
 244    while (!serial_tstc());
 245
 246    symbol_mask =
 247        ((ASC_OPTIONS & ASCOPT_CSIZE) == ASCOPT_CS7) ? (0x7f) : (0xff);
 248
 249    c = (char)(pAsc->asc_rbuf & symbol_mask);
 250
 251    return c;
 252}
 253
 254static int asc_serial_tstc(void)
 255{
 256    int res = 1;
 257
 258    if ( (pAsc->asc_fstat & ASCFSTAT_RXFFLMASK) == 0 )
 259    {
 260        res = 0;
 261    }
 262    else if ( pAsc->asc_con & ASCCON_FE )
 263    {
 264        SET_BIT(pAsc->asc_whbcon, ASCWHBCON_CLRFE);
 265        res = 0;
 266    }
 267    else if ( pAsc->asc_con & ASCCON_PE )
 268    {
 269        SET_BIT(pAsc->asc_whbcon, ASCWHBCON_CLRPE);
 270        res = 0;
 271    }
 272    else if ( pAsc->asc_con & ASCCON_OE )
 273    {
 274        SET_BIT(pAsc->asc_whbcon, ASCWHBCON_CLROE);
 275        res = 0;
 276    }
 277
 278    return res;
 279}
 280
 281static struct serial_device asc_serial_drv = {
 282        .name   = "asc_serial",
 283        .start  = asc_serial_init,
 284        .stop   = NULL,
 285        .setbrg = asc_serial_setbrg,
 286        .putc   = asc_serial_putc,
 287        .puts   = default_serial_puts,
 288        .getc   = asc_serial_getc,
 289        .tstc   = asc_serial_tstc,
 290};
 291
 292void asc_serial_initialize(void)
 293{
 294        serial_register(&asc_serial_drv);
 295}
 296
 297__weak struct serial_device *default_serial_console(void)
 298{
 299        return &asc_serial_drv;
 300}
 301