mpc8xxx_serial.c
来自「开放源码实时操作系统源码.」· C语言 代码 · 共 1,017 行 · 第 1/3 页
C
1,017 行
if (baud_divisor == 0) return false;
// Disable channel during setup
ctl->smc_smcmr = MPC8XXX_SMCMR_UART; // Disabled, UART mode
HAL_IO_BARRIER(); // Inforce I/O ordering
// Disable port interrupts while changing hardware
_lcr = smc_select_word_length[new_config->word_length - CYGNUM_SERIAL_WORD_LENGTH_5] |
smc_select_stop_bits[new_config->stop] |
smc_select_parity[new_config->parity];
// Stop transmitter while changing baud rate
IMM->cpm_cpcr = smc_chan->channel | CPCR_STOP_TX | CPCR_FLG;
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 = MPC8XXX_SMCMR_UART|MPC8XXX_SMCMR_TEN|MPC8XXX_SMCMR_REN|_lcr;
HAL_IO_BARRIER(); // Inforce I/O ordering
IMM->cpm_cpcr = smc_chan->channel | CPCR_INIT_TX_RX_PARAMS | CPCR_FLG;
if (new_config != &chan->config) {
chan->config = *new_config;
}
return true;
}
// Function to set up internal tables for device.
static void
mpc8xxx_smc_serial_init_info(mpc8xxx_sxx_serial_info *smc_chan,
t_Smc_Pram *uart_pram,
volatile struct smc_regs_8260 *ctl,
unsigned long *brg,
int TxBD, int TxNUM, int TxSIZE,
cyg_uint8 *TxBUF,
int RxBD, int RxNUM, int RxSIZE,
cyg_uint8 *RxBUF)
{
struct cp_bufdesc *txbd, *rxbd;
int i;
smc_chan->pram = (void *)uart_pram;
smc_chan->ctl = (void *)ctl;
// Set up baud rate generator
smc_chan->brg = (void *)brg;
// Disable channel during setup
ctl->smc_smcmr = MPC8XXX_SMCMR_UART; // Disabled, UART mode
// Rx, Tx function codes (used for access)
uart_pram->rfcr = 0x18;
uart_pram->tfcr = 0x18;
// Pointers to Rx & Tx buffer descriptor rings
uart_pram->rbase = RxBD;
uart_pram->tbase = TxBD;
/* tx and rx buffer descriptors */
txbd = (struct cp_bufdesc *)((char *)IMM + TxBD);
rxbd = (struct cp_bufdesc *)((char *)IMM + 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;
/* 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 = _BD_CTL_Ready | _BD_CTL_Int;
if (i == (RxNUM-1)) rxbd->ctrl |= _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 |= _BD_CTL_Wrap; // Last buffer
TxBUF += TxSIZE;
txbd++;
}
/*
* Reset Rx & Tx params
*/
HAL_IO_BARRIER(); // Inforce I/O ordering
IMM->cpm_cpcr = smc_chan->channel | CPCR_INIT_TX_RX_PARAMS | CPCR_FLG;
HAL_IO_BARRIER(); // Inforce I/O ordering
/*
* Clear any previous events. Enable interrupts.
* (Section 16.15.7.14 and 16.15.7.15)
*/
ctl->smc_smce = 0xFF;
ctl->smc_smcm = SMCE_Bsy|SMCE_Tx|SMCE_Rx;
}
// Internal function to actually configure the hardware to desired baud rate, etc.
static bool
mpc8xxx_scc_serial_config_port(serial_channel *chan, cyg_serial_info_t *new_config, bool init)
{
mpc8xxx_sxx_serial_info *scc_chan = (mpc8xxx_sxx_serial_info *)chan->dev_priv;
unsigned int baud_divisor = select_baud[new_config->baud];
volatile struct scc_regs_8260 *regs = (volatile struct scc_regs_8260*)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->gsmr_l = 0;
regs->psmr = MPC8XXX_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->gsmr_h = 0x20; // 8bit FIFO
regs->gsmr_l = 0x00028004; // 16x TxCLK, 16x RxCLK, UART
/*
* Init Rx & Tx params for SCCX
*/
HAL_IO_BARRIER(); // Inforce I/O ordering
IMM->cpm_cpcr = CPCR_INIT_TX_RX_PARAMS | scc_chan->channel | CPCR_FLG;
HAL_IO_BARRIER(); // Inforce I/O ordering
regs->gsmr_l |= GSMR_L1_ENT | GSMR_L1_ENR; // Enable Rx, Tx
if (new_config != &chan->config) {
chan->config = *new_config;
}
return true;
}
// Function to set up internal tables for device.
static void
mpc8xxx_scc_serial_init_info(mpc8xxx_sxx_serial_info *scc_chan,
volatile t_Scc_Pram *uart_pram,
volatile struct scc_regs_8260 *ctl,
unsigned long *brg,
int TxBD, int TxNUM, int TxSIZE,
cyg_uint8 *TxBUF,
int RxBD, int RxNUM, int RxSIZE,
cyg_uint8 *RxBUF)
{
struct cp_bufdesc *txbd, *rxbd;
int i;
// Disable channel during setup
ctl->gsmr_l = 0;
scc_chan->pram = (void *)uart_pram;
scc_chan->ctl = (void *)ctl;
// Set up baud rate generator
scc_chan->brg = brg;
/*
* 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 *)IMM + TxBD);
rxbd = (struct cp_bufdesc *)((char *)IMM + 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->SpecificProtocol.u.max_idl = 4;
/* no last brk char received */
uart_pram->SpecificProtocol.u.brkln = 0;
/* no break condition occurred */
uart_pram->SpecificProtocol.u.brkec = 0;
/* 1 break char sent on top XMIT */
uart_pram->SpecificProtocol.u.brkcr = 1;
/* character mask */
uart_pram->SpecificProtocol.u.rccm = 0xC0FF;
/* control characters */
for (i = 0; i < 8; i++) {
uart_pram->SpecificProtocol.u.cc[i] = 0x8000; // Mark unused
}
/* setup RX buffer descriptors */
for (i = 0; i < RxNUM; i++) {
rxbd->length = 0;
rxbd->buffer = RxBUF;
rxbd->ctrl = _BD_CTL_Ready | _BD_CTL_Int;
if (i == (RxNUM-1)) rxbd->ctrl |= _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 |= _BD_CTL_Wrap; // Last buffer
TxBUF += TxSIZE;
txbd++;
}
/*
* Reset Rx & Tx params
*/
HAL_IO_BARRIER(); // Inforce I/O ordering
IMM->cpm_cpcr = scc_chan->channel | CPCR_INIT_TX_RX_PARAMS | CPCR_FLG;
/*
* Clear any previous events. Enable interrupts.
* (Section 16.15.7.14 and 16.15.7.15)
*/
HAL_IO_BARRIER(); // Inforce I/O ordering
ctl->scce = 0xFFFF;
ctl->sccm = (SCCE_Bsy | SCCE_Tx | SCCE_Rx);
}
// 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,
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?