|  | /* | 
|  | * (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 "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; | 
|  | } |