📄 quicc_smc_serial.c
字号:
}// Function to set up internal tables for device.static voidquicc_smc_serial_init_info(quicc_smc_serial_info *smc_chan, volatile struct smc_uart_pram *uart_pram, volatile struct smc_regs *ctl, int TxBD, int TxNUM, int TxSIZE, cyg_uint8 *TxBUF, int RxBD, int RxNUM, int RxSIZE, cyg_uint8 *RxBUF, int portBmask, int BRG, int SIpos){ EPPC *eppc = eppc_base(); struct cp_bufdesc *txbd, *rxbd; cyg_uint32 simode = 0; int i; // Disable channel during setup ctl->smc_smcmr = QUICC_SMCMR_UART; // Disabled, UART mode smc_chan->pram = uart_pram; smc_chan->ctl = ctl; /* * SDMA & LCD bus request level 5 * (Section 16.10.2.1) */ eppc->dma_sdcr = 1; switch (BRG) { case 1: smc_chan->brg = (cyg_uint32 *)&eppc->brgc1; simode = 0; break; case 2: smc_chan->brg = (cyg_uint32 *)&eppc->brgc2; simode = 1; break; case 3: smc_chan->brg = (cyg_uint32 *)&eppc->brgc3; simode = 2; break; case 4: smc_chan->brg = (cyg_uint32 *)&eppc->brgc4; simode = 3; break; } // NMSI mode, BRGn to SMCm (Section 16.12.5.2) eppc->si_simode = (eppc->si_simode & ~(0xF<<SIpos)) | (simode<<SIpos); /* * Set up the PortB pins for UART operation. * Set PAR and DIR to allow SMCTXDx and SMRXDx * (Table 16-39) */ eppc->pip_pbpar |= portBmask; eppc->pip_pbdir &= ~portBmask; /* * Reset Rx & Tx params */ eppc->cp_cr = smc_chan->channel | QUICC_SMC_CMD_Go | QUICC_SMC_CMD_InitTxRx; /* * 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); smc_chan->txbd = txbd; smc_chan->tbase = txbd; smc_chan->txsize = TxSIZE; smc_chan->rxbd = rxbd; smc_chan->rbase = rxbd; smc_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; /* 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++; } /* * Clear any previous events. Enable interrupts. * (Section 16.15.7.14 and 16.15.7.15) */ ctl->smc_smce = 0xFF; ctl->smc_smcm = QUICC_SMCE_BSY|QUICC_SMCE_TX|QUICC_SMCE_RX;}// Function to initialize the device. Called at bootstrap time.static bool quicc_smc_serial_init(struct cyg_devtab_entry *tab){ serial_channel *chan = (serial_channel *)tab->priv; quicc_smc_serial_info *smc_chan = (quicc_smc_serial_info *)chan->dev_priv; volatile EPPC *eppc = (volatile EPPC *)eppc_base(); int TxBD, RxBD; static int first_init = 1; 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\n", smc_chan->channel, smc_chan->int_num);#endif if (first_init) { // Set up tables since many fields are dynamic [computed at runtime] first_init = 0;#ifdef CYGPKG_IO_SERIAL_POWERPC_QUICC_SMC_SMC1 eppc->cp_cr = QUICC_SMC_CMD_Reset | QUICC_SMC_CMD_Go; // Totally reset CP while (eppc->cp_cr & QUICC_SMC_CMD_Reset) ; TxBD = 0x2800; // Note: this should be configurable RxBD = TxBD + CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SMC1_TxNUM*8; quicc_smc_serial_init_info(&quicc_smc_serial_info1, &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][0], RxBD, CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SMC1_RxNUM, CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SMC1_RxSIZE, &quicc_smc1_rxbuf[0][0], 0xC0, // PortB mask CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SMC1_BRG, 12 // SI mask position ); TxBD = RxBD + CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SMC1_RxNUM*8;#else#ifdef CYGPKG_HAL_POWERPC_MBX // Ensure the SMC1 side is initialized first and use shared mem // above where it plays: diag_init(); // (pull in constructor that inits diag channel) TxBD = 0x2830; // Note: this should be inferred from the chip state#else // there is no diag device wanting to use the QUICC, so prepare it // for SMC2 use only. eppc->cp_cr = QUICC_SMC_CMD_Reset | QUICC_SMC_CMD_Go; // Totally reset CP while (eppc->cp_cr & QUICC_SMC_CMD_Reset) ; TxBD = 0x2800; // Note: this should be configurable#endif #endif#ifdef CYGPKG_IO_SERIAL_POWERPC_QUICC_SMC_SMC2 RxBD = TxBD + CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SMC2_TxNUM*8; quicc_smc_serial_init_info(&quicc_smc_serial_info2, &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][0], RxBD, CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SMC2_RxNUM, CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SMC2_RxSIZE, &quicc_smc2_rxbuf[0][0], 0xC00, // PortB mask CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SMC2_BRG, 28 // SI mask position );#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_smc_serial_ISR, quicc_smc_serial_DSR, &smc_chan->serial_interrupt_handle, &smc_chan->serial_interrupt); cyg_drv_interrupt_attach(smc_chan->serial_interrupt_handle); cyg_drv_interrupt_mask(smc_chan->int_num); smc_chan->tx_enabled = false; } quicc_smc_serial_config_port(chan, &chan->config, true); if (cache_state) HAL_DCACHE_ENABLE(); return true;}// This routine is called when the device is "looked" up (i.e. attached)static Cyg_ErrNo quicc_smc_serial_lookup(struct cyg_devtab_entry **tab, struct cyg_devtab_entry *sub_tab, const char *name){ serial_channel *chan = (serial_channel *)(*tab)->priv; (chan->callbacks->serial_init)(chan); // Really only required for interrupt driven devices return ENOERR;}// Force the current transmit buffer to be sentstatic voidquicc_smc_serial_flush(quicc_smc_serial_info *smc_chan){ volatile struct cp_bufdesc *txbd = smc_chan->txbd; if ((txbd->length > 0) && ((txbd->ctrl & QUICC_BD_CTL_Ready) == 0)) { txbd->ctrl |= QUICC_BD_CTL_Ready|QUICC_BD_CTL_Int; // Signal buffer ready if (txbd->ctrl & QUICC_BD_CTL_Wrap) { txbd = smc_chan->tbase; } else { txbd++; } smc_chan->txbd = txbd; }}// Send a character to the device output buffer.// Return 'true' if character is sent to devicestatic boolquicc_smc_serial_putc(serial_channel *chan, unsigned char c){ quicc_smc_serial_info *smc_chan = (quicc_smc_serial_info *)chan->dev_priv; volatile struct cp_bufdesc *txbd, *txfirst; EPPC *eppc = eppc_base();
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -