/* * 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; }
void _adder_set_leds(int pat) { volatile EPPC *eppc = (volatile EPPC *)eppc_base(); eppc->pip_pbdat = (eppc->pip_pbdat & ~0x00000007) |(~(pat&0x0007) ); }
int _adder_get_leds(void) { volatile EPPC *eppc = (volatile EPPC *)eppc_base(); return ((~(eppc->pip_pbdat & 0x00000007)) & 0x0007 ); }
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; }
// // 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)) ; }
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; }
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; }
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 }
//-------------------------------------------------------------------------- // 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); }
// 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; }
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 }
// 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; }
// 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; }
// // 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; }
// // [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; }
/* * 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; }
// // 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; }
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 }
// 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); }
// 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; }
/* * 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 }
// 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); }
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(); }