| /* |
| * (INCA) ASC UART support |
| */ |
| |
| #include <config.h> |
| |
| #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 "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; |
| } |