move ifxmips uboot to package/
[openwrt/svn-archive/archive.git] / package / uboot-ifxmips / files / cpu / mips / danube / asc_serial.c
diff --git a/package/uboot-ifxmips/files/cpu/mips/danube/asc_serial.c b/package/uboot-ifxmips/files/cpu/mips/danube/asc_serial.c
new file mode 100644 (file)
index 0000000..d95ec3f
--- /dev/null
@@ -0,0 +1,371 @@
+/*
+ * (INCA) ASC UART support
+ */
+
+#include <config.h>
+
+#if defined(CONFIG_PURPLE) || defined(CONFIG_INCA_IP)
+
+#ifdef CONFIG_PURPLE
+#define        serial_init     asc_serial_init
+#define        serial_putc     asc_serial_putc
+#define        serial_puts     asc_serial_puts
+#define        serial_getc     asc_serial_getc
+#define        serial_tstc     asc_serial_tstc
+#define        serial_setbrg   asc_serial_setbrg
+#endif
+
+#include <common.h>
+#include <asm/inca-ip.h>
+#include "asc_serial.h"
+
+#ifdef CONFIG_PURPLE
+
+#undef ASC_FIFO_PRESENT
+#define TOUT_LOOP      100000
+
+/* Set base address for second FPI interrupt control register bank */
+#define SFPI_INTCON_BASEADDR   0xBF0F0000
+
+/* Register offset from base address */
+#define FBS_ISR                0x00000000      /* Interrupt status register */
+#define FBS_IMR                0x00000008      /* Interrupt mask register */
+#define FBS_IDIS       0x00000010      /* Interrupt disable register */
+
+/* Interrupt status register bits */
+#define FBS_ISR_AT     0x00000040      /* ASC transmit interrupt */
+#define FBS_ISR_AR     0x00000020      /* ASC receive interrupt */
+#define FBS_ISR_AE     0x00000010      /* ASC error interrupt */
+#define FBS_ISR_AB     0x00000008      /* ASC transmit buffer interrupt */
+#define FBS_ISR_AS      0x00000004     /* ASC start of autobaud detection interrupt */
+#define FBS_ISR_AF     0x00000002      /* ASC end of autobaud detection interrupt */
+
+#else
+
+#define ASC_FIFO_PRESENT
+
+#endif
+
+
+#define SET_BIT(reg, mask)                  reg |= (mask)
+#define CLEAR_BIT(reg, mask)                reg &= (~mask)
+#define CLEAR_BITS(reg, mask)               CLEAR_BIT(reg, mask)
+#define SET_BITS(reg, mask)                 SET_BIT(reg, mask)
+#define SET_BITFIELD(reg, mask, off, val)   {reg &= (~mask); reg |= (val << off);}
+
+extern uint incaip_get_fpiclk(void);
+
+static int serial_setopt (void);
+
+/* pointer to ASC register base address */
+static volatile incaAsc_t *pAsc = (incaAsc_t *)INCA_IP_ASC;
+
+/******************************************************************************
+*
+* serial_init - initialize a INCAASC channel
+*
+* This routine initializes the number of data bits, parity
+* and set the selected baud rate. Interrupts are disabled.
+* Set the modem control signals if the option is selected.
+*
+* RETURNS: N/A
+*/
+
+int serial_init (void)
+{
+#ifdef CONFIG_INCA_IP
+    /* we have to set PMU.EN13 bit to enable an ASC device*/
+    INCAASC_PMU_ENABLE(13);
+#endif
+
+    /* and we have to set CLC register*/
+    CLEAR_BIT(pAsc->asc_clc, ASCCLC_DISS);
+    SET_BITFIELD(pAsc->asc_clc, ASCCLC_RMCMASK, ASCCLC_RMCOFFSET, 0x0001);
+
+    /* initialy we are in async mode */
+    pAsc->asc_con = ASCCON_M_8ASYNC;
+
+    /* select input port */
+    pAsc->asc_pisel = (CONSOLE_TTY & 0x1);
+
+#ifdef ASC_FIFO_PRESENT
+    /* TXFIFO's filling level */
+    SET_BITFIELD(pAsc->asc_txfcon, ASCTXFCON_TXFITLMASK,
+                   ASCTXFCON_TXFITLOFF, INCAASC_TXFIFO_FL);
+    /* enable TXFIFO */
+    SET_BIT(pAsc->asc_txfcon, ASCTXFCON_TXFEN);
+
+    /* RXFIFO's filling level */
+    SET_BITFIELD(pAsc->asc_txfcon, ASCRXFCON_RXFITLMASK,
+                   ASCRXFCON_RXFITLOFF, INCAASC_RXFIFO_FL);
+    /* enable RXFIFO */
+    SET_BIT(pAsc->asc_rxfcon, ASCRXFCON_RXFEN);
+#endif
+
+    /* enable error signals */
+    SET_BIT(pAsc->asc_con, ASCCON_FEN);
+    SET_BIT(pAsc->asc_con, ASCCON_OEN);
+
+#ifdef CONFIG_INCA_IP
+    /* acknowledge ASC interrupts */
+    ASC_INTERRUPTS_CLEAR(INCAASC_IRQ_LINE_ALL);
+
+    /* disable ASC interrupts */
+    ASC_INTERRUPTS_DISABLE(INCAASC_IRQ_LINE_ALL);
+#endif
+
+#ifdef ASC_FIFO_PRESENT
+    /* set FIFOs into the transparent mode */
+    SET_BIT(pAsc->asc_txfcon, ASCTXFCON_TXTMEN);
+    SET_BIT(pAsc->asc_rxfcon, ASCRXFCON_RXTMEN);
+#endif
+
+    /* set baud rate */
+    serial_setbrg();
+
+    /* set the options */
+    serial_setopt();
+
+    return 0;
+}
+
+void serial_setbrg (void)
+{
+    ulong      uiReloadValue, fdv;
+    ulong      f_ASC;
+
+#ifdef CONFIG_INCA_IP
+    f_ASC = incaip_get_fpiclk();
+#else
+    f_ASC = ASC_CLOCK_RATE;
+#endif
+
+#ifndef INCAASC_USE_FDV
+    fdv = 2;
+    uiReloadValue = (f_ASC / (fdv * 16 * CONFIG_BAUDRATE)) - 1;
+#else
+    fdv = INCAASC_FDV_HIGH_BAUDRATE;
+    uiReloadValue = (f_ASC / (8192 * CONFIG_BAUDRATE / fdv)) - 1;
+#endif /* INCAASC_USE_FDV */
+
+    if ( (uiReloadValue < 0) || (uiReloadValue > 8191) )
+    {
+#ifndef INCAASC_USE_FDV
+       fdv = 3;
+       uiReloadValue = (f_ASC / (fdv * 16 * CONFIG_BAUDRATE)) - 1;
+#else
+       fdv = INCAASC_FDV_LOW_BAUDRATE;
+       uiReloadValue = (f_ASC / (8192 * CONFIG_BAUDRATE / fdv)) - 1;
+#endif /* INCAASC_USE_FDV */
+
+       if ( (uiReloadValue < 0) || (uiReloadValue > 8191) )
+       {
+           return;    /* can't impossibly generate that baud rate */
+       }
+    }
+
+    /* Disable Baud Rate Generator; BG should only be written when R=0 */
+    CLEAR_BIT(pAsc->asc_con, ASCCON_R);
+
+#ifndef INCAASC_USE_FDV
+    /*
+     * Disable Fractional Divider (FDE)
+     * Divide clock by reload-value + constant (BRS)
+     */
+    /* FDE = 0 */
+    CLEAR_BIT(pAsc->asc_con, ASCCON_FDE);
+
+    if ( fdv == 2 )
+       CLEAR_BIT(pAsc->asc_con, ASCCON_BRS);   /* BRS = 0 */
+    else
+       SET_BIT(pAsc->asc_con, ASCCON_BRS); /* BRS = 1 */
+
+#else /* INCAASC_USE_FDV */
+
+    /* Enable Fractional Divider */
+    SET_BIT(pAsc->asc_con, ASCCON_FDE); /* FDE = 1 */
+
+    /* Set fractional divider value */
+    pAsc->asc_fdv = fdv & ASCFDV_VALUE_MASK;
+
+#endif /* INCAASC_USE_FDV */
+
+    /* Set reload value in BG */
+    pAsc->asc_bg = uiReloadValue;
+
+    /* Enable Baud Rate Generator */
+    SET_BIT(pAsc->asc_con, ASCCON_R);           /* R = 1 */
+}
+
+/*******************************************************************************
+*
+* serial_setopt - set the serial options
+*
+* Set the channel operating mode to that specified. Following options
+* are supported: CREAD, CSIZE, PARENB, and PARODD.
+*
+* Note, this routine disables the transmitter.  The calling routine
+* may have to re-enable it.
+*
+* RETURNS:
+* Returns 0 to indicate success, otherwise -1 is returned
+*/
+
+static int serial_setopt (void)
+{
+    ulong  con;
+
+    switch ( ASC_OPTIONS & ASCOPT_CSIZE )
+    {
+    /* 7-bit-data */
+    case ASCOPT_CS7:
+       con = ASCCON_M_7ASYNCPAR;   /* 7-bit-data and parity bit */
+       break;
+
+    /* 8-bit-data */
+    case ASCOPT_CS8:
+       if ( ASC_OPTIONS & ASCOPT_PARENB )
+           con = ASCCON_M_8ASYNCPAR;   /* 8-bit-data and parity bit */
+       else
+           con = ASCCON_M_8ASYNC;      /* 8-bit-data no parity */
+       break;
+
+    /*
+     *  only 7 and 8-bit frames are supported
+     *  if we don't use IOCTL extensions
+     */
+    default:
+       return -1;
+    }
+
+    if ( ASC_OPTIONS & ASCOPT_STOPB )
+       SET_BIT(con, ASCCON_STP);       /* 2 stop bits */
+    else
+       CLEAR_BIT(con, ASCCON_STP);     /* 1 stop bit */
+
+    if ( ASC_OPTIONS & ASCOPT_PARENB )
+       SET_BIT(con, ASCCON_PEN);           /* enable parity checking */
+    else
+       CLEAR_BIT(con, ASCCON_PEN);         /* disable parity checking */
+
+    if ( ASC_OPTIONS & ASCOPT_PARODD )
+       SET_BIT(con, ASCCON_ODD);       /* odd parity */
+    else
+       CLEAR_BIT(con, ASCCON_ODD);     /* even parity */
+
+    if ( ASC_OPTIONS & ASCOPT_CREAD )
+       SET_BIT(pAsc->asc_whbcon, ASCWHBCON_SETREN); /* Receiver enable */
+
+    pAsc->asc_con |= con;
+
+    return 0;
+}
+
+void serial_putc (const char c)
+{
+#ifdef ASC_FIFO_PRESENT
+    uint txFl = 0;
+#else
+    uint timeout = 0;
+#endif
+
+    if (c == '\n') serial_putc ('\r');
+
+#ifdef ASC_FIFO_PRESENT
+    /* check do we have a free space in the TX FIFO */
+    /* get current filling level */
+    do
+    {
+       txFl = ( pAsc->asc_fstat & ASCFSTAT_TXFFLMASK ) >> ASCFSTAT_TXFFLOFF;
+    }
+    while ( txFl == INCAASC_TXFIFO_FULL );
+#else
+
+    while(!(*(volatile unsigned long*)(SFPI_INTCON_BASEADDR + FBS_ISR) &
+                          FBS_ISR_AB))
+    {
+           if (timeout++ > TOUT_LOOP)
+           {
+                   break;
+           }
+    }
+#endif
+
+    pAsc->asc_tbuf = c; /* write char to Transmit Buffer Register */
+
+#ifndef ASC_FIFO_PRESENT
+    *(volatile unsigned long*)(SFPI_INTCON_BASEADDR + FBS_ISR) = FBS_ISR_AB |
+                                                                FBS_ISR_AT;
+#endif
+
+    /* check for errors */
+    if ( pAsc->asc_con & ASCCON_OE )
+    {
+       SET_BIT(pAsc->asc_whbcon, ASCWHBCON_CLROE);
+       return;
+    }
+}
+
+void serial_puts (const char *s)
+{
+    while (*s)
+    {
+       serial_putc (*s++);
+    }
+}
+
+int serial_getc (void)
+{
+    ulong symbol_mask;
+    char c;
+
+    while (!serial_tstc());
+
+    symbol_mask =
+       ((ASC_OPTIONS & ASCOPT_CSIZE) == ASCOPT_CS7) ? (0x7f) : (0xff);
+
+    c = (char)(pAsc->asc_rbuf & symbol_mask);
+
+#ifndef ASC_FIFO_PRESENT
+    *(volatile unsigned long*)(SFPI_INTCON_BASEADDR + FBS_ISR) = FBS_ISR_AR;
+#endif
+
+    return c;
+}
+
+int serial_tstc (void)
+{
+    int res = 1;
+
+#ifdef ASC_FIFO_PRESENT
+    if ( (pAsc->asc_fstat & ASCFSTAT_RXFFLMASK) == 0 )
+    {
+       res = 0;
+    }
+#else
+    if (!(*(volatile unsigned long*)(SFPI_INTCON_BASEADDR + FBS_ISR) &
+                                                               FBS_ISR_AR))
+
+    {
+       res = 0;
+    }
+#endif
+    else if ( pAsc->asc_con & ASCCON_FE )
+    {
+       SET_BIT(pAsc->asc_whbcon, ASCWHBCON_CLRFE);
+       res = 0;
+    }
+    else if ( pAsc->asc_con & ASCCON_PE )
+    {
+       SET_BIT(pAsc->asc_whbcon, ASCWHBCON_CLRPE);
+       res = 0;
+    }
+    else if ( pAsc->asc_con & ASCCON_OE )
+    {
+       SET_BIT(pAsc->asc_whbcon, ASCWHBCON_CLROE);
+       res = 0;
+    }
+
+    return res;
+}
+#endif /* CONFIG_PURPLE || CONFIG_INCA_IP */