Esempio n. 1
0
/*
 * Get a character from a port, non-blocking
 * This function can be called on either an SMC or SCC port
 */
static cyg_bool
cyg_hal_sxx_getc_nonblock(void* __ch_data, cyg_uint8* ch)
{
    volatile struct cp_bufdesc *bd;
    EPPC *eppc = eppc_base();
    struct port_info *info = (struct port_info *)__ch_data;
    volatile struct smc_uart_pram *uart_pram = (volatile struct smc_uart_pram *)((char *)eppc + info->pram);
    int cache_state;

    /* rx buffer descriptor */
    bd = info->next_rxbd;

    if (bd->ctrl & QUICC_BD_CTL_Ready)
        return false;

    *ch = bd->buffer[0];

    bd->length = 0;
    bd->buffer[0] = '\0';
    bd->ctrl |= QUICC_BD_CTL_Ready;
    if (bd->ctrl & QUICC_BD_CTL_Wrap) {
        bd = (struct cp_bufdesc *)((char *)eppc + uart_pram->rbase);
    } else {
        bd++;
    }
    info->next_rxbd = bd;

    // Note: the MBX860 does not seem to snoop/invalidate the data cache properly!
    HAL_DCACHE_IS_ENABLED(cache_state);
    if (cache_state) {
        HAL_DCACHE_INVALIDATE(bd->buffer, uart_pram->mrblr);  // Make sure no stale data
    }

    return true;
}
Esempio n. 2
0
void
_adder_set_leds(int pat)
{
    volatile EPPC *eppc = (volatile EPPC *)eppc_base();

    eppc->pip_pbdat = (eppc->pip_pbdat & ~0x00000007) |(~(pat&0x0007) );
}
Esempio n. 3
0
int
_adder_get_leds(void)
{
    volatile EPPC *eppc = (volatile EPPC *)eppc_base();

    return ((~(eppc->pip_pbdat & 0x00000007)) & 0x0007 );
}
Esempio n. 4
0
static void
quicc_eth_command( struct eth_drv_sc *sc, unsigned long cmd)
{
   volatile EPPC *eppc = (volatile EPPC *)eppc_base();
   
   eppc->cp_cr = QUICC_CPM_SCCx | cmd | QUICC_CPM_CR_BUSY;

   while (eppc->cp_cr & QUICC_CPM_CR_BUSY )
       continue;
}
Esempio n. 5
0
//
// PHY unit access (via MII channel)
//
static void
phy_write(int reg, int addr, unsigned short data)
{
    volatile EPPC *eppc = (volatile EPPC *)eppc_base();
    volatile struct fec *fec = (volatile struct fec *)((unsigned char *)eppc + FEC_OFFSET);
    int timeout = 0x100000;

    fec->iEvent = iEvent_MII;    
    fec->MiiData = MII_Start | MII_Write | MII_Phy(addr) | MII_Reg(reg) | MII_TA | data;
    while (!(fec->iEvent & iEvent_MII) && (--timeout > 0)) ;
}
Esempio n. 6
0
static bool
phy_read(int reg, int addr, unsigned short *val)
{
    volatile EPPC *eppc = (volatile EPPC *)eppc_base();
    volatile struct fec *fec = (volatile struct fec *)((unsigned char *)eppc + FEC_OFFSET);
    int timeout = 0x100000;

    fec->iEvent = iEvent_MII;    
    fec->MiiData = MII_Start | MII_Read | MII_Phy(addr) | MII_Reg(reg) | MII_TA;
    while (!(fec->iEvent & iEvent_MII)) {
        if (--timeout <= 0) {
            return false;
        }
    }
    *val = fec->MiiData & 0x0000FFFF;
    return true;
}
Esempio n. 7
0
static int
cyg_hal_sccx_isr(void *__ch_data, int* __ctrlc, 
                 CYG_ADDRWORD __vector, CYG_ADDRWORD __data)
{
    EPPC *eppc = eppc_base();
    volatile struct cp_bufdesc *bd;
    struct port_info *info = (struct port_info *)__ch_data;
    volatile struct scc_regs *regs = (volatile struct scc_regs *)((char *)eppc + info->regs);
    volatile struct uart_pram *uart_pram = (volatile struct uart_pram *)((char *)eppc + info->pram);
    char ch;
    int res = 0;
    CYGARC_HAL_SAVE_GP();

    *__ctrlc = 0;
    if (regs->scc_scce & QUICC_SMCE_RX) {

        regs->scc_scce = QUICC_SMCE_RX;

        /* rx buffer descriptors */
        bd = info->next_rxbd;

        if ((bd->ctrl & QUICC_BD_CTL_Ready) == 0) {
            
            // then there be a character waiting
            ch = bd->buffer[0];
            bd->length = 1;
            bd->ctrl   |= QUICC_BD_CTL_Ready | QUICC_BD_CTL_Int;
            if (bd->ctrl & QUICC_BD_CTL_Wrap) {
                bd = (struct cp_bufdesc *)((char *)eppc + uart_pram->rbase);
            } else {
                bd++;
            }
            info->next_rxbd = bd;
        
            if( cyg_hal_is_break( &ch , 1 ) )
                *__ctrlc = 1;
        }

        // Interrupt handled. Acknowledge it.
        HAL_INTERRUPT_ACKNOWLEDGE(info->intnum);
        res = CYG_ISR_HANDLED;
    }

    CYGARC_HAL_RESTORE_GP();
    return res;
}
Esempio n. 8
0
void hal_diag_init(void)
{
    static int init = 0;
    if (init) return;
    init++;

    // hardwired base
    eppc = eppc_base();

    // init the actual serial port
    cyg_hal_plf_serial_init_channel();
#ifdef CYGSEM_HAL_DIAG_MANGLER_GDB
#ifndef CYG_HAL_STARTUP_ROM
    // We are talking to GDB; ack the "go" packet!
    cyg_hal_plf_serial_putc(eppc, '+');
#endif
#endif
}
Esempio n. 9
0
//--------------------------------------------------------------------------
// Platform init code.
void
hal_platform_init(void)
{
    volatile EPPC *eppc = (volatile EPPC *)eppc_base();

    // Special routing information for CICR
    eppc->cpmi_cicr &= ~0xFF0000;  // Routing bits
    eppc->cpmi_cicr |= 0x240000;   // SCC2, SCC3 on "normal" bit positions

#if defined(CYGHWR_HAL_POWERPC_ADDER_I)
    eppc->pip_pbpar &= ~0x0000400E;   // PB29..30 AS GPIO
    eppc->pip_pbdir |=  0x0000400E;
    eppc->pip_pbdat  =  0x00004000;
#endif

#if defined(CYGHWR_HAL_POWERPC_ADDER_II)  

#if defined(CYGHWR_HAL_POWERPC_MPC8XX_852T)
    // Special settings - according to manual errata
    eppc->pio_papar &= ~0xffffffff;   // PA manatory settings
    eppc->pio_padir |=  0xffffffff;

    eppc->pip_pbpar &= ~0x0003ff07;   // PB29..31 AS GPIO
    eppc->pip_pbdir |=  0x0003ff07;
    eppc->pip_pbdat  =  0x00010007;
    
    eppc->pio_pcpar &= ~0xffffffff;   // PC manatory settings
    eppc->pio_pcdir |=  0xffffffff;
#endif

    eppc->pip_pbpar &= ~0x00000007;   // PB29..31 AS GPIO for LEDS
    eppc->pip_pbdir |=  0x00000007;
    eppc->pip_pbdat |=  0x00000007;
#endif

    hal_if_init();

    _adder_set_leds(0x1);
}
Esempio n. 10
0
// Send a character to the device output buffer.
// Return 'true' if character is sent to device
static bool
quicc_sxx_serial_putc(serial_channel *chan, unsigned char c)
{
    quicc_sxx_serial_info *smc_chan = (quicc_sxx_serial_info *)chan->dev_priv;
    volatile struct cp_bufdesc *txbd, *txfirst;
    volatile struct smc_uart_pram *pram = (volatile struct smc_uart_pram *)smc_chan->pram;
    EPPC *eppc = eppc_base();
    bool res;

    cyg_drv_dsr_lock();  // Avoid race condition testing pointers
    txbd = (struct cp_bufdesc *)((char *)eppc + pram->tbptr);
    txfirst = txbd;
    // Scan for a non-busy buffer
    while (txbd->ctrl & QUICC_BD_CTL_Ready) {
        // This buffer is busy, move to next one
        if (txbd->ctrl & QUICC_BD_CTL_Wrap) {
            txbd = smc_chan->tbase;
        } else {
            txbd++;
        }
        if (txbd == txfirst) break;  // Went all the way around
    }
    smc_chan->txbd = txbd;
    if ((txbd->ctrl & (QUICC_BD_CTL_Ready|QUICC_BD_CTL_Int)) == 0) {
        // Transmit buffer is not full/busy
        txbd->buffer[txbd->length++] = c;
        if (txbd->length == smc_chan->txsize) {
            // This buffer is now full, tell SMC to start processing it
            quicc_sxx_serial_flush(smc_chan);
        }
        res = true;
    } else {
        // No space
        res = false;
    }
    cyg_drv_dsr_unlock();
    return res;
}
Esempio n. 11
0
void
show_rxbd(int dump_all)
{
#ifdef CYGDBG_DIAG_BUF
    EPPC *eppc = eppc_base();
    struct smc_uart_pram *pram = &eppc->pram[2].scc.pothers.smc_modem.psmc.u;
    struct cp_bufdesc *rxbd = (struct cp_bufdesc *)((char *)eppc+pram->rbase);
    int _enable = enable_diag_uart;
    enable_diag_uart = 0;
#if 1
    diag_printf("SMC Mask: %x, Events: %x, Rbase: %x, Rbptr: %x\n", 
                eppc->smc_regs[0].smc_smcm, eppc->smc_regs[0].smc_smce,
                pram->rbase, pram->rbptr);
    while (true) {
        diag_printf("Rx BD: %x, ctl: %x, length: %d\n", rxbd, rxbd->ctrl, rxbd->length);
        if (rxbd->ctrl & QUICC_BD_CTL_Wrap) break;
        rxbd++;
    }
#endif
    enable_diag_uart = _enable;
    if (dump_all) dump_diag_buf();
#endif // CYGDBG_DIAG_BUF
}
Esempio n. 12
0
// Internal function to actually configure the hardware to desired baud rate, etc.
static bool
quicc_scc_serial_config_port(serial_channel *chan, cyg_serial_info_t *new_config, bool init)
{
    quicc_sxx_serial_info *scc_chan = (quicc_sxx_serial_info *)chan->dev_priv;
    unsigned int baud_divisor = select_baud[new_config->baud];
    EPPC *eppc = eppc_base();
    volatile struct scc_regs *regs = (volatile struct scc_regs *)scc_chan->ctl;

    if (baud_divisor == 0) return false;
    // Set baud rate generator
    *scc_chan->brg = 0x10000 | (UART_BITRATE(baud_divisor)<<1);
    // Disable channel during setup
    HAL_IO_BARRIER();  // Inforce I/O ordering
    regs->scc_gsmr_l = 0;
    regs->scc_psmr = QUICC_SCC_PSMR_ASYNC | 
        scc_select_word_length[new_config->word_length - CYGNUM_SERIAL_WORD_LENGTH_5] | 
        scc_select_stop_bits[new_config->stop] |
        scc_select_parity[new_config->parity];

    // Enable channel with new configuration
    regs->scc_gsmr_h = 0x20;          // 8bit FIFO
    regs->scc_gsmr_l = 0x00028004;    // 16x TxCLK, 16x RxCLK, UART

    /*
     *  Init Rx & Tx params for SCCX
     */
    HAL_IO_BARRIER();  // Inforce I/O ordering
    eppc->cp_cr = QUICC_CPM_CR_INIT_TXRX | scc_chan->channel | QUICC_CPM_CR_BUSY;
    while (eppc->cp_cr & QUICC_CPM_CR_BUSY )
        continue;
    HAL_IO_BARRIER();  // Inforce I/O ordering
    regs->scc_gsmr_l |= (QUICC_SCC_GSMR_L_Tx | QUICC_SCC_GSMR_L_Rx);  // Enable Rx, Tx
    if (new_config != &chan->config) {
        chan->config = *new_config;
    }
    return true;
}
Esempio n. 13
0
// Internal function to actually configure the hardware to desired baud rate, etc.
static bool
quicc_smc_serial_config_port(serial_channel *chan, cyg_serial_info_t *new_config, bool init)
{
    quicc_sxx_serial_info *smc_chan = (quicc_sxx_serial_info *)chan->dev_priv;
    unsigned int baud_divisor = select_baud[new_config->baud];
    cyg_uint32 _lcr;
    EPPC *eppc = eppc_base();
    volatile struct smc_regs *ctl = (volatile struct smc_regs *)smc_chan->ctl;

    if (baud_divisor == 0) return false;
    // Stop transmitter while changing baud rate
    eppc->cp_cr = smc_chan->channel | QUICC_SMC_CMD_Go | QUICC_SMC_CMD_StopTx;
    while (eppc->cp_cr & QUICC_SMC_CMD_Go )
        continue;
    HAL_IO_BARRIER();  // Inforce I/O ordering
    // Disable channel during setup
    ctl->smc_smcmr = QUICC_SMCMR_UART;  // Disabled, UART mode
    HAL_IO_BARRIER();  // Inforce I/O ordering
    // Disable port interrupts while changing hardware
    _lcr = QUICC_SMCMR_CLEN(new_config->word_length + ((new_config->parity == CYGNUM_SERIAL_PARITY_NONE)? 0: 1) + ((new_config->stop == CYGNUM_SERIAL_STOP_2)? 2: 1)) |
        smc_select_stop_bits[new_config->stop] |
        smc_select_parity[new_config->parity];
    HAL_IO_BARRIER();  // Inforce I/O ordering
    // Set baud rate generator
    *smc_chan->brg = 0x10000 | (UART_BITRATE(baud_divisor)<<1);

    // Enable channel with new configuration
    ctl->smc_smcmr = QUICC_SMCMR_UART|QUICC_SMCMR_TEN|QUICC_SMCMR_REN|_lcr;
    HAL_IO_BARRIER();  // Inforce I/O ordering
    eppc->cp_cr = smc_chan->channel | QUICC_SMC_CMD_Go | QUICC_SMC_CMD_RestartTx;
    while (eppc->cp_cr & QUICC_SMC_CMD_Go )
        continue;
    if (new_config != &chan->config) {
        chan->config = *new_config;
    }
    return true;
}
Esempio n. 14
0
//
// Initialize the interface - performed at system startup
// This function must set up the interface, including arranging to
// handle interrupts, etc, so that it may be "started" cheaply later.
//
static bool
quicc_eth_init(struct cyg_netdevtab_entry *tab)
{
    struct eth_drv_sc *sc = (struct eth_drv_sc *)tab->device_instance;
    struct quicc_eth_info *qi = (struct quicc_eth_info *)sc->driver_private;
    volatile EPPC *eppc = (volatile EPPC *)eppc_base();
    struct cp_bufdesc *rxbd, *txbd;
    unsigned char *RxBUF, *TxBUF, *ep, *ap;
    volatile struct ethernet_pram *enet_pram;
    volatile struct scc_regs *scc;
    int TxBD, RxBD;
    int cache_state;
    int i;
    bool esa_ok;

    // Fetch the board address from the VPD
#define VPD_ETHERNET_ADDRESS 0x08
    if (_mbx_fetch_VPD(VPD_ETHERNET_ADDRESS, enaddr, sizeof(enaddr)) == 0) {
#if defined(CYGPKG_REDBOOT) && \
    defined(CYGSEM_REDBOOT_FLASH_CONFIG)
        esa_ok = flash_get_config("quicc_esa", enaddr, CONFIG_ESA);
#else
        esa_ok = CYGACC_CALL_IF_FLASH_CFG_OP(CYGNUM_CALL_IF_FLASH_CFG_GET,
                                             "quicc_esa", enaddr, CONFIG_ESA);
#endif
        if (!esa_ok) {
            // Can't figure out ESA
            diag_printf("QUICC_ETH - Warning! ESA unknown\n");
            memcpy(&enaddr, &_default_enaddr, sizeof(enaddr));
        }
    }

    // Ensure consistent state between cache and what the QUICC sees
    HAL_DCACHE_IS_ENABLED(cache_state);
    HAL_DCACHE_SYNC();
    HAL_DCACHE_DISABLE();

#ifdef CYGINT_IO_ETH_INT_SUPPORT_REQUIRED
    // Set up to handle interrupts
    cyg_drv_interrupt_create(CYGNUM_HAL_INTERRUPT_CPM_SCC1,
                             CYGARC_SIU_PRIORITY_HIGH,
                             (cyg_addrword_t)sc, //  Data item passed to interrupt handler
                             (cyg_ISR_t *)quicc_eth_isr,
                             (cyg_DSR_t *)eth_drv_dsr,
                             &quicc_eth_interrupt_handle,
                             &quicc_eth_interrupt);
    cyg_drv_interrupt_attach(quicc_eth_interrupt_handle);
    cyg_drv_interrupt_acknowledge(CYGNUM_HAL_INTERRUPT_CPM_SCC1);
    cyg_drv_interrupt_unmask(CYGNUM_HAL_INTERRUPT_CPM_SCC1);
#endif

    qi->pram = enet_pram = &eppc->pram[0].enet_scc;
    qi->ctl = scc = &eppc->scc_regs[0];  // Use SCC1

    // Shut down ethernet, in case it is already running
    scc->scc_gsmr_l &= ~(QUICC_SCC_GSML_ENR | QUICC_SCC_GSML_ENT);

    memset((void *)enet_pram, 0, sizeof(*enet_pram));

    TxBD = 0x2C00;  // FIXME
    RxBD = TxBD + CYGNUM_DEVS_ETH_POWERPC_QUICC_TxNUM * sizeof(struct cp_bufdesc);

    txbd = (struct cp_bufdesc *)((char *)eppc + TxBD);
    rxbd = (struct cp_bufdesc *)((char *)eppc + RxBD);
    qi->tbase = txbd;
    qi->txbd = txbd;
    qi->tnext = txbd;
    qi->rbase = rxbd;
    qi->rxbd = rxbd;
    qi->rnext = rxbd;

    RxBUF = &quicc_eth_rxbufs[0][0];
    TxBUF = &quicc_eth_txbufs[0][0];

    // setup buffer descriptors
    for (i = 0;  i < CYGNUM_DEVS_ETH_POWERPC_QUICC_RxNUM;  i++) {
        rxbd->length = 0;
        rxbd->buffer = RxBUF;
        rxbd->ctrl   = QUICC_BD_CTL_Ready | QUICC_BD_CTL_Int;
        RxBUF += CYGNUM_DEVS_ETH_POWERPC_QUICC_BUFSIZE;
        rxbd++;
    }
    rxbd--;
    rxbd->ctrl |= QUICC_BD_CTL_Wrap;  // Last buffer
    for (i = 0;  i < CYGNUM_DEVS_ETH_POWERPC_QUICC_TxNUM;  i++) {
        txbd->length = 0;
        txbd->buffer = TxBUF;
        txbd->ctrl   = 0;
        TxBUF += CYGNUM_DEVS_ETH_POWERPC_QUICC_BUFSIZE;
        txbd++;
    }
    txbd--;
    txbd->ctrl |= QUICC_BD_CTL_Wrap;  // Last buffer

    // Set up parallel ports for connection to MC68160 ethernet tranceiver
    eppc->pio_papar |= (QUICC_MBX_PA_RXD | QUICC_MBX_PA_TXD);
    eppc->pio_padir &= ~(QUICC_MBX_PA_RXD | QUICC_MBX_PA_TXD);
    eppc->pio_paodr &= ~QUICC_MBX_PA_TXD;

    eppc->pio_pcpar &= ~(QUICC_MBX_PC_COLLISION | QUICC_MBX_PC_Rx_ENABLE);
    eppc->pio_pcdir &= ~(QUICC_MBX_PC_COLLISION | QUICC_MBX_PC_Rx_ENABLE);
    eppc->pio_pcso  |= (QUICC_MBX_PC_COLLISION | QUICC_MBX_PC_Rx_ENABLE);

    eppc->pio_papar |= (QUICC_MBX_PA_Tx_CLOCK | QUICC_MBX_PA_Rx_CLOCK);
    eppc->pio_padir &= ~(QUICC_MBX_PA_Tx_CLOCK | QUICC_MBX_PA_Rx_CLOCK);

    // Set up clock routing
    eppc->si_sicr &= ~QUICC_MBX_SICR_MASK;
    eppc->si_sicr |= QUICC_MBX_SICR_ENET;
    eppc->si_sicr &= ~QUICC_MBX_SICR_SCC1_ENABLE;

    // Set up DMA mode
    eppc->dma_sdcr = 0x0001;

    // Initialize shared PRAM
    enet_pram->rbase = RxBD;
    enet_pram->tbase = TxBD;

    // Set Big Endian mode
    enet_pram->rfcr = QUICC_SCC_FCR_BE;
    enet_pram->tfcr = QUICC_SCC_FCR_BE;

    // Size of receive buffers
    enet_pram->mrblr = CYGNUM_DEVS_ETH_POWERPC_QUICC_BUFSIZE;

    // Initialize CRC calculations
    enet_pram->c_pres = 0xFFFFFFFF;
    enet_pram->c_mask = 0xDEBB20E3;  // Actual CRC formula
    enet_pram->crcec = 0;
    enet_pram->alec = 0;
    enet_pram->disfc = 0;

    // Frame padding
    enet_pram->pads = 0x8888;
    enet_pram->pads = 0x0000;

    // Retries
    enet_pram->ret_lim = 15;
    enet_pram->ret_cnt = 0;

    // Frame sizes
    enet_pram->mflr = IEEE_8023_MAX_FRAME;
    enet_pram->minflr = IEEE_8023_MIN_FRAME;
    enet_pram->maxd1 = CYGNUM_DEVS_ETH_POWERPC_QUICC_BUFSIZE;
    enet_pram->maxd2 = CYGNUM_DEVS_ETH_POWERPC_QUICC_BUFSIZE;

    // Group address hash
    enet_pram->gaddr1 = 0;
    enet_pram->gaddr2 = 0;
    enet_pram->gaddr3 = 0;
    enet_pram->gaddr4 = 0;

    // Device physical address
    ep = &enaddr[sizeof(enaddr)];
    ap = (unsigned char *)&enet_pram->paddr_h;
    for (i = 0;  i < sizeof(enaddr);  i++) {
        *ap++ = *--ep;
    }

    // Persistence counter
    enet_pram->p_per = 0;

    // Individual address filter
    enet_pram->iaddr1 = 0;
    enet_pram->iaddr2 = 0;
    enet_pram->iaddr3 = 0;
    enet_pram->iaddr4 = 0;

    // Temp address
    enet_pram->taddr_h = 0;
    enet_pram->taddr_m = 0;
    enet_pram->taddr_l = 0;

    // Initialize the CPM (set up buffer pointers, etc).
    eppc->cp_cr = QUICC_CPM_SCC1 | QUICC_CPM_CR_INIT_TXRX | QUICC_CPM_CR_BUSY;
    while (eppc->cp_cr & QUICC_CPM_CR_BUSY) ;

    // Clear any pending interrupt/exceptions
    scc->scc_scce = 0xFFFF;

    // Enable interrupts
    scc->scc_sccm = QUICC_SCCE_INTS;

    // Set up SCC1 to run in ethernet mode
    scc->scc_gsmr_h = 0;
    scc->scc_gsmr_l = QUICC_SCC_GSML_TCI | QUICC_SCC_GSML_TPL_48 |
                      QUICC_SCC_GSML_TPP_01 | QUICC_SCC_GSML_MODE_ENET;

    // Sync delimiters
    scc->scc_dsr = 0xD555;

    // Protocol specifics (as if GSML wasn't enough)
    scc->scc_psmr = QUICC_PMSR_ENET_CRC | QUICC_PMSR_SEARCH_AFTER_22 |
                    QUICC_PMSR_RCV_SHORT_FRAMES;

    // Configure board interface
    *MBX_CTL1 = MBX_CTL1_ETEN | MBX_CTL1_TPEN;  // Enable ethernet, TP mode

    // Enable ethernet interface
    eppc->pio_pcpar |= QUICC_MBX_PC_Tx_ENABLE;
    eppc->pio_pcdir &= ~QUICC_MBX_PC_Tx_ENABLE;

    if (cache_state)
        HAL_DCACHE_ENABLE();

    // Initialize upper level driver
    (sc->funs->eth_drv->init)(sc, (unsigned char *)&enaddr);

    return true;
}
Esempio n. 15
0
//
// [re]Initialize the ethernet controller
//   Done separately since shutting down the device requires a 
//   full reconfiguration when re-enabling.
//   when 
static bool
fec_eth_reset(struct eth_drv_sc *sc, unsigned char *enaddr, int flags)
{
    struct fec_eth_info *qi = (struct fec_eth_info *)sc->driver_private;
    volatile EPPC *eppc = (volatile EPPC *)eppc_base();
    volatile struct fec *fec = (volatile struct fec *)((unsigned char *)eppc + FEC_OFFSET);
    volatile struct fec_bd *rxbd, *txbd;
    unsigned char *RxBUF, *TxBUF;
    int cache_state, int_state;
    int i;

    // Ignore unless device is idle/stopped
    if ((qi->fec->eControl & eControl_EN) != 0) {
        return true;
    }

    // Make sure interrupts are off while we mess with the device
    HAL_DISABLE_INTERRUPTS(int_state);

    // Ensure consistent state between cache and what the FEC sees
    HAL_DCACHE_IS_ENABLED(cache_state);
    HAL_DCACHE_SYNC();
    HAL_DCACHE_DISABLE();

    // Shut down ethernet controller, in case it is already running
    fec->eControl = eControl_RESET;
    i = 0;
    while ((fec->eControl & eControl_RESET) != 0) {
      if (++i >= 500000) {
	os_printf("FEC Ethernet does not reset\n");
	if (cache_state)
	  HAL_DCACHE_ENABLE();
        HAL_RESTORE_INTERRUPTS(int_state);
	return false;
      }
    }

    fec->iMask  = 0x0000000;  // Disables all interrupts
    fec->iEvent = 0xFFFFFFFF; // Clear all interrupts
    fec->iVector = (1<<29);   // Caution - must match FEC_ETH_INT above

#define ROUNDUP(b,s) (((unsigned long)(b) + (s-1)) & ~(s-1))
#ifdef FEC_USE_EPPC_BD
    txbd = (struct fec_bd *)(0x2C00 + (cyg_uint32)eppc);
    rxbd = &txbd[CYGNUM_DEVS_ETH_POWERPC_FEC_TxNUM];
#else
    txbd = fec_eth_txring;
    rxbd = fec_eth_rxring;
#endif
    qi->tbase = qi->txbd = qi->tnext = txbd;
    qi->rbase = qi->rxbd = qi->rnext = rxbd;
    qi->txactive = 0;

    RxBUF = (unsigned char *)ROUNDUP(&fec_eth_rxbufs[0][0], 32);
    TxBUF = (unsigned char *)ROUNDUP(&fec_eth_txbufs[0][0], 32);

    // setup buffer descriptors
    for (i = 0;  i < CYGNUM_DEVS_ETH_POWERPC_FEC_RxNUM;  i++) {
        rxbd->length = 0;
        rxbd->buffer = RxBUF;
        rxbd->ctrl   = FEC_BD_Rx_Empty;
        RxBUF += CYGNUM_DEVS_ETH_POWERPC_FEC_BUFSIZE;
        rxbd++;
    }
    rxbd--;
    rxbd->ctrl |= FEC_BD_Rx_Wrap;  // Last buffer
    for (i = 0;  i < CYGNUM_DEVS_ETH_POWERPC_FEC_TxNUM;  i++) {
        txbd->length = 0;
        txbd->buffer = TxBUF;
        txbd->ctrl   = 0;
        TxBUF += CYGNUM_DEVS_ETH_POWERPC_FEC_BUFSIZE;
        txbd++;
    }
    txbd--;
    txbd->ctrl |= FEC_BD_Tx_Wrap;  // Last buffer

    // Reset interrupts
    fec->iMask  = 0x00000000;  // No interrupts enabled
    fec->iEvent = 0xFFFFFFFF;  // Clear all interrupts

    // Initialize shared PRAM
    fec->RxRing = qi->rbase;
    fec->TxRing = qi->tbase;

    // Size of receive buffers
    fec->RxBufSize = CYGNUM_DEVS_ETH_POWERPC_FEC_BUFSIZE;

    // Receiver control
    fec->RxControl = RxControl_MII | RxControl_DRT;
//    fec->RxControl = RxControl_MII | RxControl_LOOP | RxControl_PROM;
    fec->RxHash = IEEE_8023_MAX_FRAME; // Largest possible ethernet frame

    // Transmit control
    fec->TxControl = 4+0;

    // Use largest possible Tx FIFO
    fec->TxWater = 3;

    // DMA control
    fec->FunCode = ((2<<29) | (2<<27) | (0<<24));

    // MII speed control (50MHz)
    fec->MiiSpeed = 0x14;

    // Group address hash
    fec->hash[0] = 0;
    fec->hash[1] = 0;

    // Device physical address
    fec->addr[0] = *(unsigned long *)&enaddr[0];
    fec->addr[1] = *(unsigned long *)&enaddr[4];
    // os_printf("FEC ESA = %08x/%08x\n", fec->addr[0], fec->addr[1]);

    // Enable device
    fec->eControl = eControl_EN | eControl_MUX;
    fec->RxUpdate = 0x0F0F0F0F;  // Any write tells machine to look for work

#ifdef _FEC_USE_INTS
    // Set up for interrupts
    fec->iMask = iEvent_TFINT | iEvent_TXB |
                 iEvent_RFINT | iEvent_RXB;
    fec->iEvent = 0xFFFFFFFF;  // Clear all interrupts
#endif

    if (cache_state)
        HAL_DCACHE_ENABLE();

    // Set LED state
    clear_led(LED_TxACTIVE);
    clear_led(LED_RxACTIVE);

    HAL_RESTORE_INTERRUPTS(int_state);
    return true;
}
Esempio n. 16
0
/*
 *  Initialize an SCC as a uart.
 *
 *  Comments below reference Motorola's "MPC860 User Manual".
 *  The basic initialization steps are from Section 16.15.8
 *  of that manual.
 */	
static void
cyg_hal_sccx_init_channel(struct port_info *info, int port)
{
    EPPC *eppc = eppc_base();
    int i;
    volatile struct uart_pram *uart_pram = (volatile struct uart_pram *)((char *)eppc + info->pram);
    volatile struct scc_regs *regs = (volatile struct scc_regs *)((char *)eppc + info->regs);
    struct cp_bufdesc *txbd, *rxbd;

    if (info->init) return;
    info->init = 1;

    /*
     *  Set up the Port pins for UART operation.
     */
    switch (port) {
#if CYGNUM_HAL_QUICC_SCC1 > 0
    case QUICC_CPM_SCC1:
        eppc->pio_papar |= 0x03;
        eppc->pio_padir &= ~0x03;
        eppc->pio_paodr &= ~0x03;

        /* CTS on PortC.11 */
        eppc->pio_pcdir &= 0x800;
        eppc->pio_pcpar &= 0x800;
        eppc->pio_pcso  |= 0x800;

        /* RTS on PortB.19 */
        eppc->pip_pbpar |= 0x1000;
        eppc->pip_pbdir |= 0x1000;

        break;
#endif
#if CYGNUM_HAL_QUICC_SCC2 > 0
    case QUICC_CPM_SCC2:
#error FIXME
        eppc->pio_papar |= 0x0C;
        eppc->pio_padir &= ~0x0C;
        eppc->pio_paodr &= ~0x0C;

        /* CTS on PortC.11 */
        eppc->pio_pcdir &= 0xC00;
        eppc->pio_pcpar &= 0xC00;
        eppc->pio_pcso  |= 0xC00;

        /* RTS on PortB.19 */
        eppc->pip_pbpar |= 0x2000;
        eppc->pip_pbdir |= 0x2000;

        break;
#endif
#if CYGNUM_HAL_QUICC_SCC3 > 0
    case QUICC_CPM_SCC3:
#if defined(CYGHWR_HAL_POWERPC_MPC8XX_850)
#if 0
// CAUTION!  Enabling these bits made the port get stuck :-(
        /* CTS/RTS/CD on PortC.4/5/13 */
        eppc->pio_pcdir &= 0x0C04;
        eppc->pio_pcpar &= 0x0C00;
//        eppc->pio_pcpar |= 0x0004;
        eppc->pio_pcso  |= 0x0C00;
#endif

        /* RxD/TxD on PortB.24/25 */
        eppc->pip_pbpar |= 0x00C0;
        eppc->pip_pbdir |= 0x00C0;
        eppc->pip_pbodr &= ~0x00C0;

#elif defined(CYGHWR_HAL_POWERPC_MPC8XX_852T)
        eppc->pio_papar |= 0x30;
        eppc->pio_padir &= ~0x30;
        eppc->pio_paodr &= ~0x30;
#else
#error "Cannot route SCC3 I/O"
#endif // 850T
        break;
#endif // SCC3
    }

    // Set up baud rate generator.  These are allocated from a
    // pool, based on the port number and type.  The allocator
    // will arrange to have the selected baud rate clock steered
    // to this device.
    info->brg = _mpc8xx_allocate_brg(port);
    *(info->brg) = 0x10000 | (UART_BIT_RATE(UART_BAUD_RATE)<<1);

    /*
     *  Set pointers to buffer descriptors.
     */
    uart_pram->rbase = _mpc8xx_allocBd(sizeof(struct cp_bufdesc)*info->Rxnum + info->Rxnum);
    uart_pram->tbase = _mpc8xx_allocBd(sizeof(struct cp_bufdesc)*info->Txnum + info->Txnum);

    /*
     *  SDMA & LCD bus request level 5
     */
    eppc->dma_sdcr = 1;

    /*
     *  Set Rx and Tx function code
     */
    uart_pram->rfcr = 0x18;
    uart_pram->tfcr = 0x18;

    /* max receive buffer length */
    uart_pram->mrblr = 1;

    /* disable max_idle feature */
    uart_pram->max_idl = 0;

    /* no last brk char received */
    uart_pram->brkln = 0;

    /* no break condition occurred */
    uart_pram->brkec = 0;

    /* 1 break char sent on top XMIT */
    uart_pram->brkcr = 1;

    /* character mask */
    uart_pram->rccm  = 0xC0FF;

    /* control characters */
    for (i = 0;  i < 8;  i++) {
        uart_pram->cc[i] = 0x8000;  // Mark unused
    }

    /* setup RX buffer descriptors */
    rxbd = (struct cp_bufdesc *)((char *)eppc + uart_pram->rbase);
    info->next_rxbd = rxbd;
    for (i = 0;  i < info->Rxnum;  i++) {
        rxbd->length = 0;
        rxbd->buffer = ((char *)eppc + (uart_pram->rbase+(info->Rxnum*sizeof(struct cp_bufdesc))))+i;
        rxbd->ctrl   = QUICC_BD_CTL_Ready | QUICC_BD_CTL_Int;
        rxbd++;
    }
    rxbd--;
    rxbd->ctrl   |= QUICC_BD_CTL_Wrap;

    /* setup TX buffer descriptor */
    txbd = (struct cp_bufdesc *)((char *)eppc + uart_pram->tbase);
    txbd->length = 0;
    txbd->buffer = ((char *)eppc + (uart_pram->tbase+(info->Txnum*sizeof(struct cp_bufdesc))));
    txbd->ctrl   = 0x2000;

    /*
     *  Clear any previous events. Mask interrupts.
     *  (Section 16.15.7.14 and 16.15.7.15)
     */
    regs->scc_scce = 0xffff;
    regs->scc_sccm = 1; // RX interrupts only, for ctrl-c

    /*
     *  Set 8,n,1 characters
     */
    regs->scc_psmr = (3<<12);
    regs->scc_gsmr_h = 0x20;          // 8bit FIFO
    regs->scc_gsmr_l = 0x00028004;    // 16x TxCLK, 16x RxCLK, UART

    /*
     *  Init Rx & Tx params for SCCX
     */
    eppc->cp_cr = QUICC_CPM_CR_INIT_TXRX | port | QUICC_CPM_CR_BUSY;

    regs->scc_gsmr_l |= 0x30;         // Enable Rx, Tx

    info->irq = 0;
}
Esempio n. 17
0
//
// Initialize the interface - performed at system startup
// This function must set up the interface, including arranging to
// handle interrupts, etc, so that it may be "started" cheaply later.
//
static bool 
fec_eth_init(struct cyg_netdevtab_entry *tab)
{
    struct eth_drv_sc *sc = (struct eth_drv_sc *)tab->device_instance;
    struct fec_eth_info *qi = (struct fec_eth_info *)sc->driver_private;
    volatile EPPC *eppc = (volatile EPPC *)eppc_base();
    volatile struct fec *fec = (volatile struct fec *)((unsigned char *)eppc + FEC_OFFSET);
    unsigned short phy_state = 0;
    int cache_state;
    int i;
    unsigned long proc_rev;
    bool esa_ok, phy_ok;
    int phy_timeout = 5*1000;  // Wait 5 seconds max for link to clear

    // Ensure consistent state between cache and what the FEC sees
    HAL_DCACHE_IS_ENABLED(cache_state);
    HAL_DCACHE_SYNC();
    HAL_DCACHE_DISABLE();

    qi->fec = fec;
    fec_eth_stop(sc);  // Make sure it's not running yet

#ifdef CYGINT_IO_ETH_INT_SUPPORT_REQUIRED
#ifdef _FEC_USE_INTS
    // Set up to handle interrupts
    cyg_drv_interrupt_create(FEC_ETH_INT,
                             CYGARC_SIU_PRIORITY_HIGH,
                             (cyg_addrword_t)sc, //  Data item passed to interrupt handler
                             (cyg_ISR_t *)fec_eth_isr,
                             (cyg_DSR_t *)eth_drv_dsr,
                             &fec_eth_interrupt_handle,
                             &fec_eth_interrupt);
    cyg_drv_interrupt_attach(fec_eth_interrupt_handle);
    cyg_drv_interrupt_acknowledge(FEC_ETH_INT);
    cyg_drv_interrupt_unmask(FEC_ETH_INT);
#else // _FEC_USE_INTS
    // Hack - use a thread to simulate interrupts
    cyg_thread_create(1,                 // Priority
                      fec_fake_int,   // entry
                      (cyg_addrword_t)sc, // entry parameter
                      "CS8900 int",      // Name
                      &fec_fake_int_stack[0],         // Stack
                      STACK_SIZE,        // Size
                      &fec_fake_int_thread_handle,    // Handle
                      &fec_fake_int_thread_data       // Thread data structure
            );
    cyg_thread_resume(fec_fake_int_thread_handle);  // Start it
#endif
#endif

    // Set up parallel port for connection to ethernet tranceiver
    eppc->pio_pdpar = 0x1FFF;
    CYGARC_MFSPR( CYGARC_REG_PVR, proc_rev );
#define PROC_REVB 0x0020
    if ((proc_rev & 0x0000FFFF) == PROC_REVB) {
        eppc->pio_pddir = 0x1C58;
    } else {
        eppc->pio_pddir = 0x1FFF;
    }

    // Get physical device address
#ifdef CYGPKG_REDBOOT
    esa_ok = flash_get_config("fec_esa", enaddr, CONFIG_ESA);
#else
    esa_ok = CYGACC_CALL_IF_FLASH_CFG_OP(CYGNUM_CALL_IF_FLASH_CFG_GET,         
                                         "fec_esa", enaddr, CONFIG_ESA);
#endif
    if (!esa_ok) {
        // Can't figure out ESA
        os_printf("FEC_ETH - Warning! ESA unknown\n");
        memcpy(&enaddr, &_default_enaddr, sizeof(enaddr));
    }

    // Configure the device
    if (!fec_eth_reset(sc, enaddr, 0)) {
        return false;
    }

    // Reset PHY (transceiver)
    eppc->pip_pbdat &= ~0x00004000;  // Reset PHY chip
    CYGACC_CALL_IF_DELAY_US(10000);   // 10ms
    eppc->pip_pbdat |= 0x00004000;   // Enable PHY chip
    // Enable transceiver (PHY)    
    phy_ok = 0;
    phy_write(PHY_BMCR, 0, PHY_BMCR_RESET);
    for (i = 0;  i < 10;  i++) {
        phy_ok = phy_read(PHY_BMCR, 0, &phy_state);
        if (!phy_ok) break;
        if (!(phy_state & PHY_BMCR_RESET)) break;
    }
    if (!phy_ok || (phy_state & PHY_BMCR_RESET)) {
        os_printf("FEC: Can't get PHY unit to reset: %x\n", phy_state);
        return false;
    }
    fec->iEvent = 0xFFFFFFFF;  // Clear all interrupts
    phy_write(PHY_BMCR, 0, PHY_BMCR_AUTO_NEG|PHY_BMCR_RESTART);
    while (phy_timeout-- >= 0) {
        int ev = fec->iEvent;
        unsigned short state;
        fec->iEvent = ev;
        if (ev & iEvent_MII) {
            phy_ok = phy_read(PHY_BMSR, 0, &state);
            if (phy_ok && (state & PHY_BMSR_AUTO_NEG)) {
//                os_printf("State: %x\n", state);
                break;
            } else {
                CYGACC_CALL_IF_DELAY_US(1000);   // 1ms
            }
        }
    }
    if (phy_timeout <= 0) {
        os_printf("** FEC Warning: PHY auto-negotiation failed\n");
    }

    // Initialize upper level driver
    (sc->funs->eth_drv->init)(sc, (unsigned char *)&enaddr);
    
    return true;
}
Esempio n. 18
0
static void
_mbx_init_i2c(void)
{
    volatile EPPC *eppc = eppc_base();
    unsigned char *sp, *ep;
    int i, len, RxBD, TxBD;
    struct i2c_pram *i2c;
    volatile struct cp_bufdesc *rxbd, *txbd;    
    unsigned char i2c_address[521];
    static int i2c_init = 0;

    if (i2c_init) return;
    i2c_init = 1;
    eppc->cp_rccr = 0;  // Disables any current ucode running
#ifdef _DOWNLOAD_UCODE_UPDATE // Not currently used
    // Patch the ucode
    sp = i2c_ucode_low;
    ep = (unsigned char *)eppc->udata_ucode;
    for (i = 0;  i < sizeof(i2c_ucode_low);  i++) {
        *ep++ = *sp++;
    }
    sp = i2c_ucode_high;
    ep = (unsigned char *)eppc->udata_ext;
    for (i = 0;  i < sizeof(i2c_ucode_high);  i++) {
        *ep++ = *sp++;
    }
    eppc->cp_rctr1 = 0x802A;
    eppc->cp_rctr2 = 0x8028;
    eppc->cp_rctr3 = 0x802E;
    eppc->cp_rctr4 = 0x802C;
    diag_printf("RCCR: %x, RTCRx: %x/%x/%x/%x\n",
                eppc->cp_rccr, eppc->cp_rctr1, eppc->cp_rctr2, eppc->cp_rctr3, eppc->cp_rctr4);
    diag_dump_buf(eppc->udata_ucode, 256);
    diag_dump_buf(&eppc->pram[0].scc.pothers.i2c_idma, 0x40);
    eppc->cp_rccr = 0x01;  // Enable ucode
    diag_printf("RCCR: %x, RTCRx: %x/%x/%x/%x\n",
                eppc->cp_rccr, eppc->cp_rctr1, eppc->cp_rctr2, eppc->cp_rctr3, eppc->cp_rctr4);
    diag_dump_buf(eppc->udata_ucode, 256);
    diag_dump_buf(&eppc->pram[0].scc.pothers.i2c_idma, 0x40);
    diag_printf("RPBASE = %x/%x\n", eppc->pram[0].scc.pothers.i2c_idma.i2c.rpbase, &eppc->pram[0].scc.pothers.i2c_idma.i2c.rpbase);
    eppc->pram[0].scc.pothers.i2c_idma.i2c.rpbase = (unsigned long)&eppc->i2c_spare_pram - (unsigned long)eppc;
    diag_printf("RPBASE = %x/%x\n", eppc->pram[0].scc.pothers.i2c_idma.i2c.rpbase, &eppc->pram[0].scc.pothers.i2c_idma.i2c.rpbase);
    eppc->i2c_i2mod = 0;  // Disable I2C controller
    i2c = (struct i2c_pram *)&eppc->i2c_spare_pram;
#else
    eppc->i2c_i2mod = 0;  // Disable I2C controller
    i2c = (struct i2c_pram *)&eppc->pram[0].scc.pothers.i2c_idma.i2c;
#endif // _DOWNLOAD_UCODE_UPDATE
    sp = (unsigned char *)i2c;
    for (i = 0;  i < sizeof(*i2c);  i++) {
        *sp++ = 0;
    }
    RxBD = 0x2E08;  // CAUTION
    TxBD = 0x2E00;
    i2c->rbase = RxBD;
    i2c->tbase = TxBD;
    i2c->rfcr = QUICC_I2C_FCR_BE;
    i2c->tfcr = QUICC_I2C_FCR_BE;
    i2c->mrblr = sizeof(i2c_address);
    rxbd = (volatile struct cp_bufdesc *)((char *)eppc + RxBD);
    rxbd->ctrl = QUICC_BD_CTL_Ready | QUICC_BD_CTL_Wrap | QUICC_BD_CTL_Last;
    rxbd->length = 257;
    rxbd->buffer = i2c_address;
    txbd = (volatile struct cp_bufdesc *)((char *)eppc + TxBD);
    txbd->length = 1+520;
    i2c_address[0] = MBX_CONFIG_EEPROM;
    txbd->buffer = i2c_address;
    txbd->ctrl = QUICC_BD_CTL_Ready | QUICC_BD_CTL_Wrap | QUICC_BD_CTL_Last;
    eppc->i2c_i2add = 0x00;
    eppc->i2c_i2brg = 0x50;
    eppc->i2c_i2mod = QUICC_I2C_MOD_EN;  // Enable I2C interface
    // Initialize the CPM (set up buffer pointers, etc).
    // This needs to be done *after* the interface is enabled.
    eppc->cp_cr = QUICC_CPM_I2C | QUICC_CPM_CR_INIT_RX | QUICC_CPM_CR_BUSY;
    while (eppc->cp_cr & QUICC_CPM_CR_BUSY) ;
    eppc->cp_cr = QUICC_CPM_I2C | QUICC_CPM_CR_INIT_TX | QUICC_CPM_CR_BUSY;
    while (eppc->cp_cr & QUICC_CPM_CR_BUSY) ;
    eppc->i2c_i2com = QUICC_I2C_CMD_MASTER | QUICC_I2C_CMD_START;
    i = 0;
    while (txbd->ctrl & QUICC_BD_CTL_Ready) {
        if (++i > 50000) break;
    }
    // Rebuild the actual VPD
    for (i = 0;  i < sizeof(_MBX_eeprom_data);  i++) {
        _MBX_eeprom_data[i] = VPD_EOD;  // Undefined
    }
    sp = (unsigned char *)&i2c_address[1];
    ep = (unsigned char *)&i2c_address[sizeof(i2c_address)];
    while (sp != ep) {
        if ((sp[0] == 'M') && (sp[1] == 'O') && (sp[2] == 'T')) {
            // Found the "eye catcher" string
            sp += 8;
            len = (sp[0] << 8) | sp[1];
            sp += 2;
            for (i = 0;  i < len;  i++) {
                _MBX_eeprom_data[i] = *sp++;
                if (sp == ep) sp = (unsigned char *)&i2c_address[1];
            }
            break;
        }
        sp++;
    }
    eppc->i2c_i2mod = 0;  // Disable I2C interface
}
Esempio n. 19
0
// Function to set up internal tables for device.
static void
quicc_scc_serial_init_info(quicc_sxx_serial_info *scc_chan,
                           volatile struct uart_pram *uart_pram,
                           volatile struct scc_regs *ctl,
                           int TxBD, int TxNUM, int TxSIZE,
                           cyg_uint8 *TxBUF,
                           int RxBD, int RxNUM, int RxSIZE,
                           cyg_uint8 *RxBUF,
                           int portAmask, int portBmask, int portCmask,
                           int port)
{
    EPPC *eppc = eppc_base();
    struct cp_bufdesc *txbd, *rxbd;
    int i;

    // Disable channel during setup
    ctl->scc_gsmr_l = 0;
    scc_chan->pram = (void *)uart_pram;
    scc_chan->ctl = (void *)ctl;

    // Set up baud rate generator
    scc_chan->brg = _mpc8xx_allocate_brg(port);

    /*
     *  Set up the PortA/B/C pins for UART operation.
     */
    eppc->pio_papar |= portAmask;
    eppc->pio_padir &= ~portAmask;
    eppc->pio_paodr &= ~portAmask;

    eppc->pio_pcdir &= portCmask;
    eppc->pio_pcpar &= portCmask;
    eppc->pio_pcso  |= portCmask;

    eppc->pip_pbpar |= portBmask;
    eppc->pip_pbdir |= portBmask;

    /*
     *  SDMA & LCD bus request level 5
     *  (Section 16.10.2.1)
     */
    eppc->dma_sdcr = 1;
    /*
     *  Set Rx and Tx function code
     *  (Section 16.15.4.2)
     */
    uart_pram->rfcr = 0x18;
    uart_pram->tfcr = 0x18;
    /*
     *  Set pointers to buffer descriptors.
     *  (Sections 16.15.4.1, 16.15.7.12, and 16.15.7.13)
     */
    uart_pram->rbase = RxBD;
    uart_pram->tbase = TxBD;
    /* tx and rx buffer descriptors */
    txbd = (struct cp_bufdesc *)((char *)eppc + TxBD);
    rxbd = (struct cp_bufdesc *)((char *)eppc + RxBD);
    scc_chan->txbd = txbd;
    scc_chan->tbase = txbd;
    scc_chan->txsize = TxSIZE;
    scc_chan->rxbd = rxbd;
    scc_chan->rbase = rxbd;
    scc_chan->rxsize = RxSIZE;
    /* max receive buffer length */
    uart_pram->mrblr = RxSIZE;
    /* set max_idle feature - generate interrupt after 4 chars idle period */
    uart_pram->max_idl = 4;
    /* no last brk char received */
    uart_pram->brkln = 0;
    /* no break condition occurred */
    uart_pram->brkec = 0;
    /* 1 break char sent on top XMIT */
    uart_pram->brkcr = 1;
    /* character mask */
    uart_pram->rccm  = 0xC0FF;
    /* control characters */
    for (i = 0;  i < 8;  i++) {
        uart_pram->cc[i] = 0x8000;  // Mark unused
    }
    /* setup RX buffer descriptors */
    for (i = 0;  i < RxNUM;  i++) {
        rxbd->length = 0;
        rxbd->buffer = RxBUF;
        rxbd->ctrl   = QUICC_BD_CTL_Ready | QUICC_BD_CTL_Int;
        if (i == (RxNUM-1)) rxbd->ctrl |= QUICC_BD_CTL_Wrap;  // Last buffer
        RxBUF += RxSIZE;
        rxbd++;
    }
    /* setup TX buffer descriptors */
    for (i = 0;  i < TxNUM;  i++) {
        txbd->length = 0;
        txbd->buffer = TxBUF;
        txbd->ctrl   = 0;
        if (i == (TxNUM-1)) txbd->ctrl |= QUICC_BD_CTL_Wrap;  // Last buffer
        TxBUF += TxSIZE;
        txbd++;
    }
    /*
     *  Reset Rx & Tx params
     */
    HAL_IO_BARRIER();  // Inforce I/O ordering
    eppc->cp_cr = scc_chan->channel | QUICC_SMC_CMD_Go | QUICC_SMC_CMD_InitTxRx;
    while (eppc->cp_cr & QUICC_SMC_CMD_Go )
        continue;
    /*
     *  Clear any previous events. Enable interrupts.
     *  (Section 16.15.7.14 and 16.15.7.15)
     */
    HAL_IO_BARRIER();  // Inforce I/O ordering
    ctl->scc_scce = 0xFFFF;
    ctl->scc_sccm = (QUICC_SCCE_BSY | QUICC_SCCE_TX | QUICC_SCCE_RX);
}
Esempio n. 20
0
// Function to initialize the device.  Called at bootstrap time.
static bool 
quicc_sxx_serial_init(struct cyg_devtab_entry *tab)
{
    serial_channel *chan = (serial_channel *)tab->priv;
    quicc_sxx_serial_info *smc_chan = (quicc_sxx_serial_info *)chan->dev_priv;
    volatile EPPC *eppc = (volatile EPPC *)eppc_base();
    int TxBD, RxBD;
    int cache_state;

    HAL_DCACHE_IS_ENABLED(cache_state);
    HAL_DCACHE_SYNC();
    HAL_DCACHE_DISABLE();
#ifdef CYGDBG_IO_INIT
    diag_printf("QUICC_SMC SERIAL init - dev: %x.%d = %s\n", smc_chan->channel, smc_chan->int_num, tab->name);
#endif
#ifdef CYGPKG_IO_SERIAL_POWERPC_QUICC_SMC_SMC1
    if (chan == &quicc_sxx_serial_channel_smc1) {
        TxBD = _mpc8xx_allocBd(sizeof(struct cp_bufdesc)*CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SMC1_TxNUM);
        RxBD = _mpc8xx_allocBd(sizeof(struct cp_bufdesc)*CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SMC1_RxNUM);
        quicc_smc_serial_init_info(&quicc_sxx_serial_info_smc1,
                                   &eppc->pram[2].scc.pothers.smc_modem.psmc.u, // PRAM
                                   &eppc->smc_regs[0], // Control registers
                                   TxBD, 
                                   CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SMC1_TxNUM,
                                   CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SMC1_TxSIZE,
                                   &quicc_smc1_txbuf[0],
                                   RxBD, 
                                   CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SMC1_RxNUM,
                                   CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SMC1_RxSIZE,
                                   &quicc_smc1_rxbuf[0],
                                   0xC0, // PortB mask
                                   QUICC_CPM_SMC1
            );
    }
#endif
#ifdef CYGPKG_IO_SERIAL_POWERPC_QUICC_SMC_SMC2
    if (chan == &quicc_sxx_serial_channel_smc2) {
        TxBD = _mpc8xx_allocBd(sizeof(struct cp_bufdesc)*CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SMC2_TxNUM);
        RxBD = _mpc8xx_allocBd(sizeof(struct cp_bufdesc)*CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SMC2_RxNUM);
        quicc_smc_serial_init_info(&quicc_sxx_serial_info_smc2,
                                   &eppc->pram[3].scc.pothers.smc_modem.psmc.u, // PRAM
                                   &eppc->smc_regs[1], // Control registers
                                   TxBD, 
                                   CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SMC2_TxNUM,
                                   CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SMC2_TxSIZE,
                                   &quicc_smc2_txbuf[0],
                                   RxBD, 
                                   CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SMC2_RxNUM,
                                   CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SMC2_RxSIZE,
                                   &quicc_smc2_rxbuf[0],
                                   0xC00, // PortB mask
                                   QUICC_CPM_SMC2
            );
    }
#endif
#ifdef CYGPKG_IO_SERIAL_POWERPC_QUICC_SMC_SCC1
    if (chan == &quicc_sxx_serial_channel_scc1) {
        TxBD = _mpc8xx_allocBd(sizeof(struct cp_bufdesc)*CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SCC1_TxNUM);
        RxBD = _mpc8xx_allocBd(sizeof(struct cp_bufdesc)*CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SCC1_RxNUM);
        quicc_scc_serial_init_info(&quicc_sxx_serial_info_scc1,
                                   &eppc->pram[0].scc.pscc.u, // PRAM
                                   &eppc->scc_regs[0],        // Control registersn
                                   TxBD, 
                                   CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SCC1_TxNUM,
                                   CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SCC1_TxSIZE,
                                   &quicc_scc1_txbuf[0],
                                   RxBD, 
                                   CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SCC1_RxNUM,
                                   CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SCC1_RxSIZE,
                                   &quicc_scc1_rxbuf[0],
                                   0x0003, // PortA mask
                                   0x1000, // PortB mask
                                   0x0800, // PortC mask
                                   QUICC_CPM_SCC1
            );
    }
#endif
#ifdef CYGPKG_IO_SERIAL_POWERPC_QUICC_SMC_SCC2
    if (chan == &quicc_sxx_serial_channel_scc2) {
        TxBD = _mpc8xx_allocBd(sizeof(struct cp_bufdesc)*CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SCC2_TxNUM);
        RxBD = _mpc8xx_allocBd(sizeof(struct cp_bufdesc)*CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SCC2_RxNUM);
        quicc_scc_serial_init_info(&quicc_sxx_serial_info_scc2,
                                   &eppc->pram[1].scc.pscc.u, // PRAM
                                   &eppc->scc_regs[1],        // Control registersn
                                   TxBD, 
                                   CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SCC2_TxNUM,
                                   CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SCC2_TxSIZE,
                                   &quicc_scc2_txbuf[0],
                                   RxBD, 
                                   CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SCC2_RxNUM,
                                   CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SCC2_RxSIZE,
                                   &quicc_scc2_rxbuf[0],
                                   0x000C, // PortA mask
                                   0x2000, // PortB mask
                                   0x0C00, // PortC mask
                                   QUICC_CPM_SCC2
            );
    }
#endif
#ifdef CYGPKG_IO_SERIAL_POWERPC_QUICC_SMC_SCC3
    if (chan == &quicc_sxx_serial_channel_scc3) {
        TxBD = _mpc8xx_allocBd(sizeof(struct cp_bufdesc)*CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SCC3_TxNUM);
        RxBD = _mpc8xx_allocBd(sizeof(struct cp_bufdesc)*CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SCC3_RxNUM);
        quicc_scc_serial_init_info(&quicc_sxx_serial_info_scc3,
                                   &eppc->pram[2].scc.pscc.u, // PRAM
                                   &eppc->scc_regs[2],        // Control registersn
                                   TxBD, 
                                   CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SCC3_TxNUM,
                                   CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SCC3_TxSIZE,
                                   &quicc_scc3_txbuf[0],
                                   RxBD, 
                                   CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SCC3_RxNUM,
                                   CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SCC3_RxSIZE,
                                   &quicc_scc3_rxbuf[0],
#if defined(CYGHWR_HAL_POWERPC_MPC8XX_850)
                                   0x0000, // PortA mask
                                   0x00C0, // PortB mask
                                   0x0000, // PortC mask
#elif defined(CYGHWR_HAL_POWERPC_MPC8XX_852T)
                                   0x0030, // PortA mask
                                   0x0000, // PortB mask
                                   0x0000, // PortC mask
#elif defined(CYGHWR_HAL_POWERPC_MPC8XX_823)
                                   0x0000, // PortA mask
                                   0x00C0, // PortB mask
                                   0x0000, // PortC mask
#else
#error "Cannot route SCC3"
#endif
                                   QUICC_CPM_SCC3
            );
    }
#endif
    (chan->callbacks->serial_init)(chan);  // Really only required for interrupt driven devices
    if (chan->out_cbuf.len != 0) {
        cyg_drv_interrupt_create(smc_chan->int_num,
                                 CYGARC_SIU_PRIORITY_HIGH, // Priority - unused (but asserted)
                                 (cyg_addrword_t)chan,   //  Data item passed to interrupt handler
                                 quicc_sxx_serial_ISR,
                                 quicc_sxx_serial_DSR,
                                 &smc_chan->serial_interrupt_handle,
                                 &smc_chan->serial_interrupt);
        cyg_drv_interrupt_attach(smc_chan->serial_interrupt_handle);
        cyg_drv_interrupt_unmask(smc_chan->int_num);
    }
    if (smc_chan->type == _SMC_CHAN) {
        quicc_smc_serial_config_port(chan, &chan->config, true);
    } else {
        quicc_scc_serial_config_port(chan, &chan->config, true);
    }
    if (cache_state)
        HAL_DCACHE_ENABLE();
    return true;
}
Esempio n. 21
0
/*
 *  Initialize SMCX as a uart.
 *
 *  Comments below reference Motorola's "MPC860 User Manual".
 *  The basic initialization steps are from Section 16.15.8
 *  of that manual.
 */	
static void
cyg_hal_smcx_init_channel(struct port_info *info, int port)
{
    EPPC *eppc = eppc_base();
    int i;
    volatile struct smc_uart_pram *uart_pram = (volatile struct smc_uart_pram *)((char *)eppc + info->pram);
    volatile struct smc_regs *regs = (volatile struct smc_regs *)((char *)eppc + info->regs);
    struct cp_bufdesc *txbd, *rxbd;

    if (info->init) return;
    info->init = 1;

    switch (port) {
#if CYGNUM_HAL_QUICC_SMC1 > 0
    case QUICC_CPM_SMC1:
        /*
         *  Set up the PortB pins for UART operation.
         *  Set PAR and DIR to allow SMCTXD1 and SMRXD1
         *  (Table 16-39)
         */
        eppc->pip_pbpar |= 0xc0;
        eppc->pip_pbdir &= ~0xc0;

        break;
#endif
#if CYGNUM_HAL_QUICC_SMC2 > 0
    case QUICC_CPM_SMC2:
        /*
         *  Set up the PortA pins for UART operation.
         *  Set PAR and DIR to allow SMCTXD2 and SMRXD2
         *  (Table 16-39)
         */
        eppc->pio_papar |= 0xc0;
        eppc->pio_padir &= ~0xc0;
        eppc->pio_paodr &= ~0xc0;

        break;
#endif
    }

    // Set up baud rate generator.  These are allocated from a
    // pool, based on the port number and type.  The allocator
    // will arrange to have the selected baud rate clock steered
    // to this device.
    info->brg = _mpc8xx_allocate_brg(port);
    *(info->brg) = 0x10000 | (UART_BIT_RATE(UART_BAUD_RATE)<<1);

    /*
     *  Set pointers to buffer descriptors.
     *  (Sections 16.15.4.1, 16.15.7.12, and 16.15.7.13)
     */
    uart_pram->rbase = _mpc8xx_allocBd(sizeof(struct cp_bufdesc)*info->Rxnum + info->Rxnum);
    uart_pram->tbase = _mpc8xx_allocBd(sizeof(struct cp_bufdesc)*info->Txnum + info->Txnum);

    /*
     *  SDMA & LCD bus request level 5
     *  (Section 16.10.2.1)
     */
    eppc->dma_sdcr = 1;

    /*
     *  Set Rx and Tx function code
     *  (Section 16.15.4.2)
     */
    uart_pram->rfcr = 0x18;
    uart_pram->tfcr = 0x18;

    /* max receive buffer length */
    uart_pram->mrblr = 1;

    /* disable max_idle feature */
    uart_pram->max_idl = 0;

    /* no last brk char received */
    uart_pram->brkln = 0;

    /* no break condition occurred */
    uart_pram->brkec = 0;

    /* 1 break char sent on top XMIT */
    uart_pram->brkcr = 1;

    /* setup RX buffer descriptors */
    rxbd = (struct cp_bufdesc *)((char *)eppc + uart_pram->rbase);
    info->next_rxbd = rxbd;
    for (i = 0;  i < info->Rxnum;  i++) {
        rxbd->length = 0;
        rxbd->buffer = ((char *)eppc + (uart_pram->rbase+(info->Rxnum*sizeof(struct cp_bufdesc))))+i;
        rxbd->ctrl   = QUICC_BD_CTL_Ready | QUICC_BD_CTL_Int;
        rxbd++;
    }
    rxbd--;
    rxbd->ctrl   |= QUICC_BD_CTL_Wrap;

    /* setup TX buffer descriptor */
    txbd = (struct cp_bufdesc *)((char *)eppc + uart_pram->tbase);
    txbd->length = 1;
    txbd->buffer = ((char *)eppc + (uart_pram->tbase+(info->Txnum*sizeof(struct cp_bufdesc))));
    txbd->ctrl   = 0x2000;

    /*
     *  Clear any previous events. Mask interrupts.
     *  (Section 16.15.7.14 and 16.15.7.15)
     */
    regs->smc_smce = 0xff;
    regs->smc_smcm = 1; // RX interrupts only, for ctrl-c

    /*
     *  Set 8,n,1 characters, then also enable rx and tx.
     *  (Section 16.15.7.11)
     */
    regs->smc_smcmr = 0x4820;
    regs->smc_smcmr = 0x4823;

    /*
     *  Init Rx & Tx params for SMCx
     */
    eppc->cp_cr = QUICC_CPM_CR_INIT_TXRX | port | QUICC_CPM_CR_BUSY;

    info->irq = 0;  // Interrupts not enabled
}
Esempio n. 22
0
// Serial I/O - high level interrupt handler (DSR)
static void
quicc_smc_serial_DSR(serial_channel *chan)
{
    quicc_sxx_serial_info *smc_chan = (quicc_sxx_serial_info *)chan->dev_priv;
    volatile struct smc_regs *ctl = (volatile struct smc_regs *)smc_chan->ctl;
    volatile struct cp_bufdesc *txbd;
    volatile struct cp_bufdesc *rxbd = smc_chan->rxbd;
    volatile struct smc_uart_pram *pram = (volatile struct smc_uart_pram *)smc_chan->pram;
    struct cp_bufdesc *rxlast;
    int i, cache_state;

    if (ctl->smc_smce & QUICC_SMCE_TX) {
        // Transmit interrupt
        ctl->smc_smce = QUICC_SMCE_TX;  // Reset interrupt state;
        txbd = smc_chan->tbase;  // First buffer
        while (true) {
            if ((txbd->ctrl & (QUICC_BD_CTL_Ready|QUICC_BD_CTL_Int)) == QUICC_BD_CTL_Int) {
                txbd->length = 0;
                txbd->ctrl &= ~QUICC_BD_CTL_Int;  // Reset interrupt bit
            }
            if (txbd->ctrl & QUICC_BD_CTL_Wrap) {
                txbd = smc_chan->tbase;
                break;
            } else {
                txbd++;
            }
        }
        (chan->callbacks->xmt_char)(chan);
    }
    while (ctl->smc_smce & QUICC_SMCE_RX) {
        // Receive interrupt
        ctl->smc_smce = QUICC_SMCE_RX;  // Reset interrupt state;
        rxlast = (struct cp_bufdesc *) ((char *)eppc_base() + pram->rbptr);
        while (rxbd != rxlast) {
            if ((rxbd->ctrl & QUICC_BD_CTL_Ready) == 0) {
                if((rxbd->ctrl & (QUICC_BD_CTL_Frame | QUICC_BD_CTL_Parity)) == 0) {
                    for (i = 0;  i < rxbd->length;  i++) {
                        (chan->callbacks->rcv_char)(chan, rxbd->buffer[i]);
                    }
                } else {
                    // is this necessary?
                    rxbd->ctrl &= QUICC_BD_CTL_MASK;
                    // should we report the error?
                }
                // Note: the MBX860 does not seem to snoop/invalidate the data cache properly!
                HAL_DCACHE_IS_ENABLED(cache_state);
                if (cache_state) {
                    HAL_DCACHE_INVALIDATE(rxbd->buffer, smc_chan->rxsize);  // Make sure no stale data
                }
                rxbd->length = 0;
                rxbd->ctrl |= QUICC_BD_CTL_Ready;
            }
            if (rxbd->ctrl & QUICC_BD_CTL_Wrap) {
                rxbd = smc_chan->rbase;
            } else {
                rxbd++;
            }
        }
        smc_chan->rxbd = (struct cp_bufdesc *)rxbd;
    }
    if (ctl->smc_smce & QUICC_SMCE_BSY) {
        ctl->smc_smce = QUICC_SMCE_BSY;  // Reset interrupt state;
    }
    cyg_drv_interrupt_acknowledge(smc_chan->int_num);
    cyg_drv_interrupt_unmask(smc_chan->int_num);
}
Esempio n. 23
0
static void 
cyg_hal_sxx_putc(void* __ch_data, cyg_uint8 ch)
{
    volatile struct cp_bufdesc *bd, *first;
    EPPC *eppc = eppc_base();
    struct port_info *info = (struct port_info *)__ch_data;
    volatile struct smc_uart_pram *uart_pram = (volatile struct smc_uart_pram *)((char *)eppc + info->pram);
    volatile struct smc_regs *regs = (volatile struct smc_regs *)((char *)eppc + info->regs);
    int timeout;
    int cache_state;
    CYGARC_HAL_SAVE_GP();

    /* tx buffer descriptor */
    bd = (struct cp_bufdesc *)((char *)eppc + uart_pram->tbptr);

    // Scan for a free buffer
    first = bd;
    while (bd->ctrl & QUICC_BD_CTL_Ready) {
        if (bd->ctrl & QUICC_BD_CTL_Wrap) {
            bd = (struct cp_bufdesc *)((char *)eppc + uart_pram->tbase);
        } else {
            bd++;
        }
        if (bd == first) break;
    }

    while (bd->ctrl & QUICC_BD_CTL_Ready) ;  // Wait for buffer free
    if (bd->ctrl & QUICC_BD_CTL_Int) {
        // This buffer has just completed interrupt output.  Reset bits
        bd->ctrl &= ~QUICC_BD_CTL_Int;
        bd->length = 0;
    }

    bd->length = 1;
    bd->buffer[0] = ch;
    bd->ctrl      |= QUICC_BD_CTL_Ready;
    // Flush cache if necessary - buffer may be in cacheable memory
    HAL_DCACHE_IS_ENABLED(cache_state);
    if (cache_state) {
      HAL_DCACHE_FLUSH(bd->buffer, 1);
    }

#ifdef CYGDBG_DIAG_BUF
        enable_diag_uart = 0;
#endif // CYGDBG_DIAG_BUF
    timeout = 0;
    while (bd->ctrl & QUICC_BD_CTL_Ready) {
// Wait until buffer free
        if (++timeout == 0x7FFFF) {
            // A really long time!
#ifdef CYGDBG_DIAG_BUF
            diag_printf("bd fail? bd: %x, ctrl: %x, tx state: %x\n", bd, bd->ctrl, uart_pram->tstate);
#endif // CYGDBG_DIAG_BUF
            regs->smc_smcmr &= ~QUICC_SMCMR_TEN;  // Disable transmitter
            bd->ctrl &= ~QUICC_BD_CTL_Ready;
            regs->smc_smcmr |= QUICC_SMCMR_TEN;   // Enable transmitter
            bd->ctrl |= QUICC_BD_CTL_Ready;
            timeout = 0;
#ifdef CYGDBG_DIAG_BUF
            diag_printf("bd retry? bd: %x, ctrl: %x, tx state: %x\n", bd, bd->ctrl, uart_pram->tstate);
            first = (struct cp_bufdesc *)((char *)eppc + uart_pram->tbase);
            while (true) {
                diag_printf("bd: %x, ctrl: %x, length: %x\n", first, first->ctrl, first->length);
                if (first->ctrl & QUICC_BD_CTL_Wrap) break;
                first++;
            }
#endif // CYGDBG_DIAG_BUF
        }
    }
    while (bd->ctrl & QUICC_BD_CTL_Ready) ;  // Wait until buffer free
    bd->length = 0;
#ifdef CYGDBG_DIAG_BUF
    enable_diag_uart = 1;
#endif // CYGDBG_DIAG_BUF

    CYGARC_HAL_RESTORE_GP();
}