quicc2_scc_serial.c

来自「开放源码实时操作系统源码.」· C语言 代码 · 共 852 行 · 第 1/3 页

C
852
字号
    IMM->io_regs[PORT_D].pdir |=  QUICC2_SCC1_PORTD_PDIR;
    IMM->io_regs[PORT_D].podr &= ~QUICC2_SCC1_PORTD_PPAR;

    // Set-up the PORT C pins
    IMM->io_regs[PORT_C].psor &= ~QUICC2_SCC1_PORTC_PPAR;
    IMM->io_regs[PORT_C].ppar |=  QUICC2_SCC1_PORTC_PPAR;
    IMM->io_regs[PORT_C].pdir &= ~QUICC2_SCC1_PORTC_PPAR;
    IMM->io_regs[PORT_C].podr &= ~QUICC2_SCC1_PORTC_PPAR;

    // Select the baud rate generator and connect it 
    IMM->cpm_mux_cmxscr &= QUICC2_CMX_SCC1_CLR;

    switch (BRG_index) {
    case 1:
      scc_chan->brg = &(IMM->brgs_brgc1);
      IMM->cpm_mux_cmxscr |= QUICC2_CMX_SCC1_BRG1;
      break;
    case 2:
      scc_chan->brg = &(IMM->brgs_brgc2);
      IMM->cpm_mux_cmxscr |= QUICC2_CMX_SCC1_BRG2;
      break;
    case 3:
      scc_chan->brg = &(IMM->brgs_brgc3);
      IMM->cpm_mux_cmxscr |= QUICC2_CMX_SCC1_BRG3;
      break;
    case 4:
      scc_chan->brg = &(IMM->brgs_brgc4);
      IMM->cpm_mux_cmxscr |= QUICC2_CMX_SCC1_BRG4;
      break;
    }
#ifdef CYGPKG_HAL_POWERPC_VADS     
    // Enable the transciever
    bcsr->bcsr1 &= ~(QUICC2_BCSR_EN_SCC1);
#endif
    break;

  case 2:
    // Put the data into the info structure 
    scc_chan->scc_cpcr = QUICC2_CPCR_SCC2;
    scc_chan->scc_regs = &(IMM->scc_regs[1]);
    scc_chan->scc_pram = &(IMM->pram.serials.scc_pram[1]);
    scc_chan->int_vector = CYGNUM_HAL_INTERRUPT_SCC2;

    // Set-up the PORT D pins
    IMM->io_regs[PORT_D].psor &= ~QUICC2_SCC2_PORTD_PPAR;
    IMM->io_regs[PORT_D].ppar |=  QUICC2_SCC2_PORTD_PPAR;
    IMM->io_regs[PORT_D].pdir &= ~QUICC2_SCC2_PORTD_PPAR;
    IMM->io_regs[PORT_D].pdir |=  QUICC2_SCC2_PORTD_PDIR;
    IMM->io_regs[PORT_D].podr &= ~QUICC2_SCC2_PORTD_PPAR;

    // Set-up the PORT C pins
    IMM->io_regs[PORT_C].psor &= ~QUICC2_SCC2_PORTC_PPAR;
    IMM->io_regs[PORT_C].ppar |=  QUICC2_SCC2_PORTC_PPAR;
    IMM->io_regs[PORT_C].pdir &= ~QUICC2_SCC2_PORTC_PPAR;
    IMM->io_regs[PORT_C].podr &= ~QUICC2_SCC2_PORTC_PPAR;

    // Select the baud rate generator and connect it 
    IMM->cpm_mux_cmxscr &= QUICC2_CMX_SCC2_CLR;

    switch (BRG_index) {
    case 1:
      scc_chan->brg = &(IMM->brgs_brgc1);
      IMM->cpm_mux_cmxscr |= QUICC2_CMX_SCC2_BRG1;
      break;
    case 2:
      scc_chan->brg = &(IMM->brgs_brgc2);
      IMM->cpm_mux_cmxscr |= QUICC2_CMX_SCC2_BRG2;
      break;
    case 3:
      scc_chan->brg = &(IMM->brgs_brgc3);
      IMM->cpm_mux_cmxscr |= QUICC2_CMX_SCC2_BRG3;
      break;
    case 4:
      scc_chan->brg = &(IMM->brgs_brgc4);
      IMM->cpm_mux_cmxscr |= QUICC2_CMX_SCC2_BRG4;
      break;
    } 
#ifdef CYGPKG_HAL_POWERPC_VADS 
    // Enable the transciever
    bcsr->bcsr1 &= ~(QUICC2_BCSR_EN_SCC2);
#endif
    break;

  default:
    diag_printf("Incorrect SCC index in quicc2_scc_serial_init_info \n");
    break;
  }

  // Initialize common SCC PRAM
  scc_chan->tbase = (scc_bd *) (QUICC2_VADS_IMM_BASE + TxBD);
  scc_chan->rbase = (scc_bd *) (QUICC2_VADS_IMM_BASE + RxBD);
  scc_chan->txbd  = (scc_bd *) (QUICC2_VADS_IMM_BASE + TxBD);
  scc_chan->rxbd  = (scc_bd *) (QUICC2_VADS_IMM_BASE + RxBD);
  scc_chan->txsize = TxSIZE;
  scc_chan->rxsize = RxSIZE;

  scc_chan->scc_pram->rbase = RxBD;
  scc_chan->scc_pram->tbase = TxBD;
  scc_chan->scc_pram->rfcr  = 0x10;
  scc_chan->scc_pram->tfcr  = 0x10;
  scc_chan->scc_pram->mrblr = RxSIZE;

  // Initialize UART PRAM
  uart_pram = &(scc_chan->scc_pram->SpecificProtocol.u);
    
  uart_pram->max_idl = 4;
  uart_pram->brkcr   = 1;
  uart_pram->brkln   = 0;
  uart_pram->parec   = 0;
  uart_pram->frmec   = 0;
  uart_pram->nosec   = 0;
  uart_pram->brkec   = 0;
  uart_pram->uaddr1  = 0;
  uart_pram->uaddr2  = 0;
  uart_pram->toseq   = 0;
  uart_pram->cc[0] = 0x8000;
  uart_pram->cc[1] = 0x8000;
  uart_pram->cc[2] = 0x8000;
  uart_pram->cc[3] = 0x8000;
  uart_pram->cc[4] = 0x8000;
  uart_pram->cc[5] = 0x8000;
  uart_pram->cc[6] = 0x8000;
  uart_pram->cc[7] = 0x8000;
  uart_pram->rccm  = 0xC0FF;

  // Initialize registers
  scc_chan->scc_regs->gsmr_l = QUICC2_SCC_GSMR_L_INIT;
  scc_chan->scc_regs->gsmr_h = QUICC2_SCC_GSMR_H_INIT;
  // scc_chan->scc_regs->psmr   = 0x8000;  // Set by config
  scc_chan->scc_regs->todr   = 0;
  //  scc_chan->scc_regs->dsr    = 0x7e7e; // Set by config
  scc_chan->scc_regs->scce   = 0xffff;
  scc_chan->scc_regs->sccm   = (QUICC2_SCCE_BSY | QUICC2_SCCE_TX | QUICC2_SCCE_RX);

  /* setup RX buffer descriptors */
  rxbd = (struct scc_bd *)((char *) QUICC2_VADS_IMM_BASE + RxBD);

  for (i = 0;  i < RxNUM;  i++) {
    rxbd->ctrl   = QUICC2_BD_CTL_Ready | QUICC2_BD_CTL_Int;
    rxbd->length = 0;
    rxbd->buffer = RxBUF;

    RxBUF += RxSIZE;
    rxbd++;
  }

  rxbd--;
  rxbd->ctrl |= QUICC2_BD_CTL_Wrap;  // Last buffer

  /* setup TX buffer descriptors */
  txbd = (struct scc_bd *)((char *) QUICC2_VADS_IMM_BASE + TxBD);

  for (i = 0;  i < TxNUM;  i++) {
    txbd->ctrl   = 0;
    txbd->length = 0;
    txbd->buffer = TxBUF;
    TxBUF += TxSIZE;
    txbd++;
  }

  txbd--;
  txbd->ctrl |= QUICC2_BD_CTL_Wrap;  // Last buffer
  
  // Issue Init RX & TX Parameters Command 
  while (IMM->cpm_cpcr & QUICC2_CPCR_READY);
  IMM->cpm_cpcr = scc_chan->scc_cpcr | QUICC2_CPCR_INIT_TX_RX | QUICC2_CPCR_READY;
  while (IMM->cpm_cpcr & QUICC2_CPCR_READY);

  return;

}

// Function to initialize the device.  Called at bootstrap time.
static bool 
quicc2_scc_serial_init(struct cyg_devtab_entry *tab)
{
  serial_channel *chan = (serial_channel *)tab->priv;
  quicc2_scc_serial_info *scc_chan = (quicc2_scc_serial_info *)chan->dev_priv;
  volatile t_PQ2IMM *IMM = (volatile t_PQ2IMM *) QUICC2_VADS_IMM_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("QUICC2_SCC SERIAL init - dev: %x\n", 
              scc_chan->channel);
#endif
    if (first_init) {
        // Set up tables since many fields are dynamic [computed at runtime]
        first_init = 0;
#ifdef CYGPKG_IO_SERIAL_POWERPC_QUICC2_SCC_SCC1

        // Totally reset the CP
        while (IMM->cpm_cpcr & QUICC2_CPCR_READY);
        IMM->cpm_cpcr = QUICC2_CPCR_RESET | QUICC2_CPCR_READY;
        while (IMM->cpm_cpcr & QUICC2_CPCR_READY);

        TxBD = 0x2800;  // Note: this should be configurable
        RxBD = TxBD + CYGNUM_IO_SERIAL_POWERPC_QUICC2_SCC_SCC1_TxNUM*8;
        quicc2_scc_serial_init_info(&quicc2_scc_serial_info1,
                                    1, // indicates SCC1
                                    CYGNUM_IO_SERIAL_POWERPC_QUICC2_SCC_SCC1_BRG,
                                    TxBD, 
                                    CYGNUM_IO_SERIAL_POWERPC_QUICC2_SCC_SCC1_TxNUM,
                                    CYGNUM_IO_SERIAL_POWERPC_QUICC2_SCC_SCC1_TxSIZE,
                                    ALIGN_TO_CACHELINES(&quicc2_scc1_txbuf[0][0]),
                                    RxBD, 
                                    CYGNUM_IO_SERIAL_POWERPC_QUICC2_SCC_SCC1_RxNUM,
                                    CYGNUM_IO_SERIAL_POWERPC_QUICC2_SCC_SCC1_RxSIZE,
                                    ALIGN_TO_CACHELINES(&quicc2_scc1_rxbuf[0][0])
                                    );
#else
#ifdef CYGPKG_HAL_POWERPC_MPC8260
        // Ensure that SCC1 side is initialized first
        diag_init(); // (pull in constructor that inits diag channel)
        TxBD = 0x2900;  // Note : this should be inferred from the
                        // chip state
#else
        // there is no diag device wanting to use the QUICC, so prepare it
        // for SCC2 use only.
        while (IMM->cpm_cpcr & QUICC2_CPCR_READY); // Totally reset the CP
        IMM->cpm_cpcr = QUICC2_CPCR_RESET | QUICC2_CPCR_READY;
        while (IMM->cpm_cpcr & QUICC2_CPCR_READY);
        TxBD = 0x2800; // Note: this should be configurable
#endif
#endif
#ifdef CYGPKG_IO_SERIAL_POWERPC_QUICC2_SCC_SCC2

        RxBD = TxBD + CYGNUM_IO_SERIAL_POWERPC_QUICC2_SCC_SCC2_TxNUM*8;
        quicc2_scc_serial_init_info(&quicc2_scc_serial_info2,
                                    2, // indicates SCC2
                                    CYGNUM_IO_SERIAL_POWERPC_QUICC2_SCC_SCC2_BRG,
                                    TxBD, 
                                    CYGNUM_IO_SERIAL_POWERPC_QUICC2_SCC_SCC2_TxNUM,
                                    CYGNUM_IO_SERIAL_POWERPC_QUICC2_SCC_SCC2_TxSIZE,
                                    ALIGN_TO_CACHELINES(&quicc2_scc2_txbuf[0][0]),
                                    RxBD, 
                                    CYGNUM_IO_SERIAL_POWERPC_QUICC2_SCC_SCC2_RxNUM,
                                    CYGNUM_IO_SERIAL_POWERPC_QUICC2_SCC_SCC2_RxSIZE,
                                    ALIGN_TO_CACHELINES(&quicc2_scc2_rxbuf[0][0])
            );
#endif
    }

    // Really only required for interrupt driven devices
    (chan->callbacks->serial_init)(chan);  
    if (chan->out_cbuf.len != 0) {
        cyg_drv_interrupt_create(scc_chan->int_vector,
                                 0, // CYGARC_SIU_PRIORITY_HIGH, - unused 
                                 (cyg_addrword_t)chan,   //  Data item passed to interrupt handler
                                 quicc2_scc_serial_ISR,
                                 quicc2_scc_serial_DSR,
                                 &scc_chan->serial_interrupt_handle,
                                 &scc_chan->serial_interrupt);
        cyg_drv_interrupt_attach(scc_chan->serial_interrupt_handle);
        cyg_drv_interrupt_acknowledge(scc_chan->int_vector);
        cyg_drv_interrupt_unmask(scc_chan->int_vector);
    }
    quicc2_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 
quicc2_scc_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
quicc2_scc_serial_flush(quicc2_scc_serial_info *scc_chan)
{
  volatile struct scc_bd *txbd = scc_chan->txbd;

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?