int flash_hwr_init(void) { struct FLASH_query data, *qp; extern char flash_query[], flash_query_end[]; typedef int code_fun(unsigned char *); code_fun *_flash_query; int code_len, stat, num_regions, region_size, buffer_size; int icache_on, dcache_on; HAL_DCACHE_IS_ENABLED(dcache_on); HAL_ICACHE_IS_ENABLED(icache_on); // Copy 'program' code to RAM for execution code_len = (unsigned long)&flash_query_end - (unsigned long)&flash_query; _flash_query = (code_fun *)flash_info.work_space; memcpy(_flash_query, &flash_query, code_len); if (dcache_on) { HAL_DCACHE_SYNC(); // Should guarantee this code will run } if (icache_on) { HAL_ICACHE_DISABLE(); // is also required to avoid old contents } stat = (*_flash_query)((unsigned char *)&data); if (icache_on) { HAL_ICACHE_ENABLE(); } qp = &data; if ( (qp->manuf_code == FLASH_Intel_code) #ifdef CYGOPT_FLASH_IS_BOOTBLOCK // device types go as follows: 0x90 for 16-bits, 0xD0 for 8-bits, // plus 0 or 1 for -T (Top Boot) or -B (Bottom Boot) // [FIXME: whatever that means :FIXME] // [I think it means the boot blocks are top/bottom of addr space] // plus the following size codes: // 0: 16Mbit 2: 8Mbit 4: 4Mbit // 6: 32Mbit 8: 64Mbit #if 16 == CYGNUM_FLASH_WIDTH && (0x90 == (0xF0 & qp->device_code)) // 16-bit devices #elif 8 == CYGNUM_FLASH_WIDTH && (0xD0 == (0xF0 & qp->device_code)) // 8-bit devices #else && 0 #error Only understand 16 and 8-bit bootblock flash types #endif ) { int lookup[] = { 16, 8, 4, 32, 64 }; #define BLOCKSIZE (0x10000) region_size = BLOCKSIZE; num_regions = qp->device_code & 0x0F; num_regions >>= 1; if ( num_regions > 4 ) goto flash_type_unknown; num_regions = lookup[num_regions]; num_regions *= 1024 * 1024; // to bits num_regions /= 8; // to bytes num_regions /= BLOCKSIZE; // to blocks buffer_size = 0; #else // CYGOPT_FLASH_IS_BOOTBLOCK && (strncmp(qp->id, "QRY", 3) == 0)) { num_regions = _si(qp->num_regions)+1; region_size = _si(qp->region_size)*256; if (_si(qp->buffer_size)) { buffer_size = CYGNUM_FLASH_DEVICES << _si(qp->buffer_size); } else { buffer_size = 0; } #endif // Not CYGOPT_FLASH_IS_BOOTBLOCK flash_info.block_size = region_size*CYGNUM_FLASH_DEVICES; flash_info.buffer_size = buffer_size; flash_info.blocks = num_regions; flash_info.start = (void *)CYGNUM_FLASH_BASE; flash_info.end = (void *)(CYGNUM_FLASH_BASE + (num_regions*region_size*CYGNUM_FLASH_DEVICES)); #ifdef CYGNUM_FLASH_BASE_MASK // Then this gives us a maximum size for the (visible) device. // This is to cope with oversize devices fitted, with some high // address lines ignored. if ( ((unsigned int)flash_info.start & CYGNUM_FLASH_BASE_MASK) != (((unsigned int)flash_info.end - 1) & CYGNUM_FLASH_BASE_MASK ) ) { // then the size of the device appears to span >1 device-worth! unsigned int x; x = (~(CYGNUM_FLASH_BASE_MASK)) + 1; // expected device size x += (unsigned int)flash_info.start; if ( x < (unsigned int)flash_info.end ) { // 2nd sanity check (*flash_info.pf)("\nFLASH: Oversized device! End addr %p changed to %p\n", flash_info.end, (void *)x ); flash_info.end = (void *)x; // Also adjust the block count else unlock crashes! x = ((cyg_uint8 *)flash_info.end - (cyg_uint8 *)flash_info.start) / flash_info.block_size; flash_info.blocks = x; } } #endif // CYGNUM_FLASH_BASE_MASK return FLASH_ERR_OK; } #ifdef CYGOPT_FLASH_IS_BOOTBLOCK flash_type_unknown: #endif (*flash_info.pf)("Can't identify FLASH, sorry, man %x, dev %x, id [%4s] stat %x\n", qp->manuf_code, qp->device_code, qp->id, stat ); diag_dump_buf(qp, sizeof(data)); return FLASH_ERR_HWR; }
// // 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 = false; #ifdef QUICC_ETH_FETCH_ESA QUICC_ETH_FETCH_ESA(esa_ok); #endif if (!esa_ok) { #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(QUICC_ETH_INT, 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(QUICC_ETH_INT); cyg_drv_interrupt_unmask(QUICC_ETH_INT); #endif qi->pram = enet_pram = &eppc->pram[QUICC_ETH_SCC].enet_scc; qi->ctl = scc = &eppc->scc_regs[QUICC_ETH_SCC]; // Use SCCx // 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 = _mpc8xx_allocBd(CYGNUM_DEVS_ETH_POWERPC_QUICC_TxNUM * sizeof(struct cp_bufdesc)); RxBD = _mpc8xx_allocBd(CYGNUM_DEVS_ETH_POWERPC_QUICC_RxNUM * 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; qi->txactive = 0; 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 ethernet tranceiver eppc->pio_papar |= (QUICC_ETH_PA_RXD | QUICC_ETH_PA_TXD); eppc->pio_padir &= ~(QUICC_ETH_PA_RXD | QUICC_ETH_PA_TXD); eppc->pio_paodr &= ~QUICC_ETH_PA_TXD; eppc->pio_pcpar &= ~(QUICC_ETH_PC_COLLISION | QUICC_ETH_PC_Rx_ENABLE); eppc->pio_pcdir &= ~(QUICC_ETH_PC_COLLISION | QUICC_ETH_PC_Rx_ENABLE); eppc->pio_pcso |= (QUICC_ETH_PC_COLLISION | QUICC_ETH_PC_Rx_ENABLE); eppc->pio_papar |= (QUICC_ETH_PA_Tx_CLOCK | QUICC_ETH_PA_Rx_CLOCK); eppc->pio_padir &= ~(QUICC_ETH_PA_Tx_CLOCK | QUICC_ETH_PA_Rx_CLOCK); // Set up clock routing eppc->si_sicr &= ~QUICC_ETH_SICR_MASK; eppc->si_sicr |= QUICC_ETH_SICR_ENET; eppc->si_sicr &= ~QUICC_ETH_SICR_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_SCCx | 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 | QUICC_SCCE_GRC | QUICC_SCCE_BSY; // Set up SCCx 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; #ifdef QUICC_ETH_ENABLE QUICC_ETH_ENABLE(); #endif #ifdef QUICC_ETH_RESET_PHY QUICC_ETH_RESET_PHY(); #endif // Enable ethernet interface #ifdef QUICC_ETH_PC_Tx_ENABLE eppc->pio_pcpar |= QUICC_ETH_PC_Tx_ENABLE; eppc->pio_pcdir &= ~QUICC_ETH_PC_Tx_ENABLE; #else eppc->pip_pbpar |= QUICC_ETH_PB_Tx_ENABLE; eppc->pip_pbdir |= QUICC_ETH_PB_Tx_ENABLE; #endif if (cache_state) HAL_DCACHE_ENABLE(); // Initialize upper level driver (sc->funs->eth_drv->init)(sc, (unsigned char *)&enaddr); // Set LED state clear_led(LED_TxACTIVE); clear_led(LED_RxACTIVE); return true; }
// Serial I/O - high level interrupt handler (DSR) static void mpc8xxx_smc_serial_DSR(serial_channel *chan) { mpc8xxx_sxx_serial_info *smc_chan = (mpc8xxx_sxx_serial_info *)chan->dev_priv; volatile struct smc_regs_8260 *ctl = (volatile struct smc_regs_8260 *)smc_chan->ctl; volatile struct cp_bufdesc *txbd; volatile struct cp_bufdesc *rxbd = smc_chan->rxbd; volatile t_Smc_Pram *pram = (volatile t_Smc_Pram *)smc_chan->pram; struct cp_bufdesc *rxlast; int i, cache_state; if (ctl->smc_smce & SMCE_Tx) { // Transmit interrupt ctl->smc_smce = SMCE_Tx; // Reset interrupt state; txbd = smc_chan->tbase; // First buffer while (true) { if ((txbd->ctrl & (_BD_CTL_Ready|_BD_CTL_Int)) == _BD_CTL_Int) { txbd->length = 0; txbd->ctrl &= ~_BD_CTL_Int; // Reset interrupt bit } if (txbd->ctrl & _BD_CTL_Wrap) { txbd = smc_chan->tbase; break; } else { txbd++; } } (chan->callbacks->xmt_char)(chan); } while (ctl->smc_smce & SMCE_Rx) { // Receive interrupt ctl->smc_smce = SMCE_Rx; // Reset interrupt state; rxlast = (struct cp_bufdesc *) ( (char *)IMM + pram->rbptr ); while (rxbd != rxlast) { if ((rxbd->ctrl & _BD_CTL_Ready) == 0) { for (i = 0; i < rxbd->length; i++) { (chan->callbacks->rcv_char)(chan, rxbd->buffer[i]); } // 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 |= _BD_CTL_Ready; } if (rxbd->ctrl & _BD_CTL_Wrap) { rxbd = smc_chan->rbase; } else { rxbd++; } } smc_chan->rxbd = (struct cp_bufdesc *)rxbd; } if (ctl->smc_smce & SMCE_Bsy) { ctl->smc_smce = SMCE_Bsy; // Reset interrupt state; } cyg_drv_interrupt_acknowledge(smc_chan->int_num); cyg_drv_interrupt_unmask(smc_chan->int_num); }
// Function to initialize the device. Called at bootstrap time. static bool mpc8xxx_sxx_serial_init(struct cyg_devtab_entry *tab) { serial_channel *chan = (serial_channel *)tab->priv; mpc8xxx_sxx_serial_info *smc_chan = (mpc8xxx_sxx_serial_info *)chan->dev_priv; int TxBD, RxBD; int cache_state; HAL_DCACHE_IS_ENABLED(cache_state); HAL_DCACHE_SYNC(); HAL_DCACHE_DISABLE(); #ifdef CYGDBG_IO_INIT diag_printf("MPC8XXX_SMC SERIAL init - dev: %x.%d = %s\n", smc_chan->channel, smc_chan->int_num, tab->name); #endif #ifdef CYGPKG_IO_SERIAL_POWERPC_MPC8XXX_SMC1 if (chan == &mpc8xxx_sxx_serial_channel_smc1) { TxBD = _mpc8xxx_allocBd(sizeof(struct cp_bufdesc)*CYGNUM_IO_SERIAL_POWERPC_MPC8XXX_SMC1_TxNUM); RxBD = _mpc8xxx_allocBd(sizeof(struct cp_bufdesc)*CYGNUM_IO_SERIAL_POWERPC_MPC8XXX_SMC1_RxNUM); mpc8xxx_smc_serial_init_info(&mpc8xxx_sxx_serial_info_smc1, (t_Smc_Pram *)((char *)IMM + DPRAM_SMC1_OFFSET), &IMM->smc_regs[SMC1], (unsigned long *)&IMM->brgs_brgc7, TxBD, CYGNUM_IO_SERIAL_POWERPC_MPC8XXX_SMC1_TxNUM, CYGNUM_IO_SERIAL_POWERPC_MPC8XXX_SMC1_TxSIZE, &mpc8xxx_smc1_txbuf[0], RxBD, CYGNUM_IO_SERIAL_POWERPC_MPC8XXX_SMC1_RxNUM, CYGNUM_IO_SERIAL_POWERPC_MPC8XXX_SMC1_RxSIZE, &mpc8xxx_smc1_rxbuf[0] ); } #endif #ifdef CYGPKG_IO_SERIAL_POWERPC_MPC8XXX_SMC2 #warning "Serial driver on SMC2 is unverified" if (chan == &mpc8xxx_sxx_serial_channel_smc2) { TxBD = _mpc8xxx_allocBd(sizeof(struct cp_bufdesc)*CYGNUM_IO_SERIAL_POWERPC_MPC8XXX_SMC2_TxNUM); RxBD = _mpc8xxx_allocBd(sizeof(struct cp_bufdesc)*CYGNUM_IO_SERIAL_POWERPC_MPC8XXX_SMC2_RxNUM); mpc8xxx_smc_serial_init_info(&mpc8xxx_sxx_serial_info_smc2, &IMM->pram[3].scc.pothers.smc_modem.psmc.u, // PRAM &IMM->smc_regs[1], // Control registers &IMM->brgs_brgc7, TxBD, CYGNUM_IO_SERIAL_POWERPC_MPC8XXX_SMC2_TxNUM, CYGNUM_IO_SERIAL_POWERPC_MPC8XXX_SMC2_TxSIZE, &mpc8xxx_smc2_txbuf[0], RxBD, CYGNUM_IO_SERIAL_POWERPC_MPC8XXX_SMC2_RxNUM, CYGNUM_IO_SERIAL_POWERPC_MPC8XXX_SMC2_RxSIZE, &mpc8xxx_smc2_rxbuf[0] ); } #endif #ifdef CYGPKG_IO_SERIAL_POWERPC_MPC8XXX_SCC1 if (chan == &mpc8xxx_sxx_serial_channel_scc1) { TxBD = _mpc8xxx_allocBd(sizeof(struct cp_bufdesc)*CYGNUM_IO_SERIAL_POWERPC_MPC8XXX_SCC1_TxNUM); RxBD = _mpc8xxx_allocBd(sizeof(struct cp_bufdesc)*CYGNUM_IO_SERIAL_POWERPC_MPC8XXX_SCC1_RxNUM); mpc8xxx_scc_serial_init_info(&mpc8xxx_sxx_serial_info_scc1, &IMM->pram.serials.scc_pram[SCC1], &IMM->scc_regs[SCC1], (unsigned long *)&IMM->brgs_brgc1, TxBD, CYGNUM_IO_SERIAL_POWERPC_MPC8XXX_SCC1_TxNUM, CYGNUM_IO_SERIAL_POWERPC_MPC8XXX_SCC1_TxSIZE, &mpc8xxx_scc1_txbuf[0], RxBD, CYGNUM_IO_SERIAL_POWERPC_MPC8XXX_SCC1_RxNUM, CYGNUM_IO_SERIAL_POWERPC_MPC8XXX_SCC1_RxSIZE, &mpc8xxx_scc1_rxbuf[0] ); } #endif #ifdef CYGPKG_IO_SERIAL_POWERPC_MPC8XXX_SCC2 #warning "Serial driver on SCC2 is unverified" if (chan == &mpc8xxx_sxx_serial_channel_scc2) { TxBD = _mpc8xxx_allocBd(sizeof(struct cp_bufdesc)*CYGNUM_IO_SERIAL_POWERPC_MPC8XXX_SCC2_TxNUM); RxBD = _mpc8xxx_allocBd(sizeof(struct cp_bufdesc)*CYGNUM_IO_SERIAL_POWERPC_MPC8XXX_SCC2_RxNUM); mpc8xxx_scc_serial_init_info(&mpc8xxx_sxx_serial_info_scc2, &IMM->pram[1].scc.pscc.u, // PRAM &IMM->scc_regs[1], // Control registers &IMM->brgs_brgc2, TxBD, CYGNUM_IO_SERIAL_POWERPC_MPC8XXX_SCC2_TxNUM, CYGNUM_IO_SERIAL_POWERPC_MPC8XXX_SCC2_TxSIZE, &mpc8xxx_scc2_txbuf[0], RxBD, CYGNUM_IO_SERIAL_POWERPC_MPC8XXX_SCC2_RxNUM, CYGNUM_IO_SERIAL_POWERPC_MPC8XXX_SCC2_RxSIZE, &mpc8xxx_scc2_rxbuf[0] ); } #endif #ifdef CYGPKG_IO_SERIAL_POWERPC_MPC8XXX_SCC3 #warning "Serial driver on SCC3 is unverified" if (chan == &mpc8xxx_sxx_serial_channel_scc3) { TxBD = _mpc8xxx_allocBd(sizeof(struct cp_bufdesc)*CYGNUM_IO_SERIAL_POWERPC_MPC8XXX_SCC3_TxNUM); RxBD = _mpc8xxx_allocBd(sizeof(struct cp_bufdesc)*CYGNUM_IO_SERIAL_POWERPC_MPC8XXX_SCC3_RxNUM); mpc8xxx_scc_serial_init_info(&mpc8xxx_sxx_serial_info_scc3, &IMM->pram[2].scc.pscc.u, // PRAM &IMM->scc_regs[2], // Control registersn &IMM->brgs_brgc3, TxBD, CYGNUM_IO_SERIAL_POWERPC_MPC8XXX_SCC3_TxNUM, CYGNUM_IO_SERIAL_POWERPC_MPC8XXX_SCC3_TxSIZE, &mpc8xxx_scc3_txbuf[0], RxBD, CYGNUM_IO_SERIAL_POWERPC_MPC8XXX_SCC3_RxNUM, CYGNUM_IO_SERIAL_POWERPC_MPC8XXX_SCC3_RxSIZE, &mpc8xxx_scc3_rxbuf[0] ); } #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, 0, // Priority - unused (but asserted) (cyg_addrword_t)chan, // Data item passed to interrupt handler mpc8xxx_sxx_serial_ISR, mpc8xxx_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) { mpc8xxx_smc_serial_config_port(chan, &chan->config, true); } else { mpc8xxx_scc_serial_config_port(chan, &chan->config, true); } if (cache_state) HAL_DCACHE_ENABLE(); return true; }
// // 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; }
// // [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; }