quicc_smc_serial.c
来自「开放源码实时操作系统源码.」· C语言 代码 · 共 1,115 行 · 第 1/4 页
C
1,115 行
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;
/*
* 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;
}
// This routine is called when the device is "looked" up (i.e. attached)
static Cyg_ErrNo
quicc_sxx_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 sent
static void
quicc_sxx_serial_flush(quicc_sxx_serial_info *smc_chan)
{
volatile struct cp_bufdesc *txbd = smc_chan->txbd;
int cache_state;
HAL_DCACHE_IS_ENABLED(cache_state);
if (cache_state) {
HAL_DCACHE_FLUSH(txbd->buffer, smc_chan->txsize);
}
if ((txbd->length > 0) &&
((txbd->ctrl & (QUICC_BD_CTL_Ready|QUICC_BD_CTL_Int)) == 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 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);
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?