static inline cyg_uint32 tx_dma_channel_setup(cyg_spi_freescale_dspi_bus_t* dspi_bus, cyg_uint8* data_buf, cyg_uint32 count, cyg_bool bus_16bit, cyg_uint32 pushr, cyg_bool drop_cs) { cyghwr_hal_freescale_dma_set_t *dma_set_p = dspi_bus->setup_p->dma_set_p; cyghwr_hal_freescale_edma_t *edma_p = dma_set_p->edma_p; volatile cyghwr_hal_freescale_edma_tcd_t *tcd_p; cyg_uint32 remain=0; cyg_uint32 dma_chan_i; remain = dma_pushque_fill(dspi_bus, data_buf, count, bus_16bit, pushr, drop_cs); dma_chan_i = SPI_DMA_CHAN_I(dma_set_p, TX); tcd_p = &edma_p->tcd[dma_chan_i]; tcd_p->saddr = dspi_bus->pushque_p; DEBUG2_PRINTF("DSPI: Tx channel setup\n"); #if DEBUG_SPI >= 3 hal_freescale_edma_transfer_diag(edma_p, dma_chan_i, true); #endif return remain; }
static void spi_transaction_do (cyg_spi_device* device, cyg_bool tick_only, cyg_bool polled, cyg_uint32 count, const cyg_uint8* tx_data, cyg_uint8* rx_data, cyg_bool drop_cs) { cyg_spi_freescale_dspi_bus_t* dspi_bus = (cyg_spi_freescale_dspi_bus_t*) device->spi_bus; cyg_spi_freescale_dspi_device_t* dspi_device = (cyg_spi_freescale_dspi_device_t*) device; cyg_bool bus_16bit = dspi_device->clocking.bus_16bit; cyghwr_devs_freescale_dspi_t* dspi_p = dspi_bus->setup_p->dspi_p; cyghwr_hal_freescale_dma_set_t* dma_set_p; cyghwr_hal_freescale_edma_t* edma_p = NULL; cyg_uint32 count_down; cyg_uint32 txfifo_n = dspi_bus->txfifo_n; cyg_uint32 pushr; cyg_uint32 pushque_n; cyg_uint32 dma_chan_rx_i = 0; cyg_uint32 dma_chan_tx_i = 0; #if DEBUG_SPI >= 2 cyg_uint32 first_turn = 1; #endif DEBUG2_PRINTF("DSPI: transaction: count=%d drop_cs=%d\n", count, drop_cs); // Set up peripheral CS field. DSPI automatically asserts and deasserts CS pushr = dspi_chip_select_set(tick_only ? -1 : dspi_device->dev_num, dspi_p->mcr & FREESCALE_DSPI_MCR_PCSSE_M, true); pushr |= FREESCALE_DSPI_PUSHR_CONT_M; dspi_fifo_clear(dspi_p); dspi_fifo_drain(dspi_p); pushque_n = dspi_bus->pushque_n; if(bus_16bit) txfifo_n *= 2; if((dma_set_p=dspi_bus->setup_p->dma_set_p)) { edma_p = dma_set_p->edma_p; // Set up the DMA channels. dma_chan_rx_i = SPI_DMA_CHAN_I(dma_set_p, RX); dma_chan_tx_i = SPI_DMA_CHAN_I(dma_set_p, TX); rx_dma_channel_setup(dma_set_p, (cyg_uint8*) rx_data, bus_16bit, &edma_p->tcd[dma_chan_rx_i]); hal_freescale_edma_erq_enable(edma_p, dma_chan_rx_i); } if(!polled) cyg_drv_interrupt_unmask(dspi_bus->setup_p->intr_num); count_down = count; while(count_down) { #if DEBUG_SPI >= 2 if(first_turn) { if(dspi_bus->pushque_p) dspi_bus->pushque_p[0] |= FREESCALE_DSPI_PUSHR_CTCNT_M; first_turn = 0; } #endif if(dma_set_p && (count_down > txfifo_n)) { // Transfer size is larger than DSPI FIFO // Use DMA Tx count_down = tx_dma_channel_setup(dspi_bus, (cyg_uint8*) tx_data, count_down, bus_16bit, pushr, drop_cs); #if DEBUG_SPI >= 3 hal_freescale_edma_transfer_diag(edma_p, dma_chan_rx_i, true); #endif // Enable the Tx DMA / SPI controller. hal_freescale_edma_erq_enable(edma_p, dma_chan_tx_i); DSPI_EOQ_CLEAR(dspi_p); } else { // Transfer size fits within DSPI FIFO // No need for DMA Tx DSPI_EOQ_CLEAR(dspi_p); count_down = fifo_pushque_fill(dspi_bus, (cyg_uint8*) tx_data, count_down, bus_16bit, pushr, drop_cs); #if DEBUG_SPI >= 3 cyghwr_devs_freescale_dspi_diag(dspi_bus); #endif } if(polled) { DEBUG2_PRINTF("DSPI Polled:\n"); // Busy-wait for DSPI/DMA (polling for completion). while(!(dspi_p->sr & FREESCALE_DSPI_SR_EOQF_M)); if(dma_set_p) // Disable the Tx DMA channel on completion. hal_freescale_edma_erq_disable(edma_p, dma_chan_tx_i); } else { // Wait for DSPI/DMA completion. (interrupt driven). cyg_drv_mutex_lock(&dspi_bus->transfer_mutex); cyg_drv_dsr_lock(); DSPI_IRQ_ENABLE(dspi_p); DEBUG2_PRINTF("DSPI IRQ: Enabled\n"); // Sit back and wait for the ISR/DSRs to signal completion. cyg_drv_cond_wait (&dspi_bus->transfer_done); cyg_drv_dsr_unlock(); cyg_drv_mutex_unlock(&dspi_bus->transfer_mutex); } if(dma_set_p) { // Make sure that Rx has been drained by DMA. if(rx_data) while((dspi_p->sr & FREESCALE_DSPI_SR_RFDF_M)); } else { // No DMA - "manually" drain Rx FIFO DEBUG2_PRINTF("DSPI FIFO: 'Manually' drain Rx fifo\n"); #if DEBUG_SPI >= 3 cyghwr_devs_freescale_dspi_diag(dspi_bus); #endif if(rx_data) { if(bus_16bit) { cyg_uint16* rx_data16 = (cyg_uint16*) rx_data; while(dspi_p->sr & FREESCALE_DSPI_SR_RXCTR_M) *rx_data16++ = dspi_p->popr; rx_data = (cyg_uint8*) rx_data16; } else { while(dspi_p->sr & FREESCALE_DSPI_SR_RXCTR_M) *rx_data++ = dspi_p->popr; } } else { dspi_fifo_drain(dspi_p); } } dspi_fifo_clear(dspi_p); // Prepare for next iteration if(tx_data) { tx_data += pushque_n; if(bus_16bit) tx_data += pushque_n; } } if(dma_set_p && rx_data) { // Rx buffer may be out of sync with cache. DEBUG2_PRINTF("DSPI DMA: Invalidate cache\n"); HAL_DCACHE_INVALIDATE(rx_data, count); DEBUG2_PRINTF("DSPI DMA: Cache invalidated\n"); } if(!polled) cyg_drv_interrupt_mask(dspi_bus->setup_p->intr_num); dspi_device->chip_sel = !drop_cs; }
static void dspi_bus_setup(cyg_spi_freescale_dspi_bus_t* spi_bus_p) { cyghwr_devs_freescale_dspi_t* dspi_p = spi_bus_p->setup_p->dspi_p; cyghwr_hal_freescale_dma_set_t* dma_set_p; cyghwr_hal_freescale_edma_t* edma_p; cyg_uint32 dma_chan_i; // Get the clock frequency from HAL. spi_bus_p->clock_freq = CYGHWR_IO_SPI_FREESCALE_DSPI_CLOCK; DEBUG1_PRINTF("DSPI BUS %p: SysClk=%d\n", spi_bus_p, spi_bus_p->clock_freq); // Set up the pins. dspi_pin_setup(spi_bus_p->setup_p->spi_pin_list_p, spi_bus_p->setup_p->cs_pin_list_p, spi_bus_p->setup_p->cs_pin_num); // Set up default SPI configuration. dspi_p->mcr = spi_bus_p->setup_p->mcr_opt | FREESCALE_DSPI_MCR_MSTR_M | FREESCALE_DSPI_MCR_CLR_RXF_M | FREESCALE_DSPI_MCR_CLR_TXF_M | FREESCALE_DSPI_MCR_MDIS_M; // Enable DSPI controller. dspi_enable(dspi_p); if((dma_set_p=spi_bus_p->setup_p->dma_set_p)) { // Initialize DMA channels hal_freescale_edma_init_chanset(dma_set_p); #if DEBUG_SPI >= 1 hal_freescale_edma_diag(dma_set_p, 0xffff); cyghwr_devs_freescale_dspi_diag(spi_bus_p); #endif // Set up DMA transfer control descriptors edma_p = dma_set_p->edma_p; dma_chan_i = dma_set_p->chan_p[SPI_DMA_CHAN_TX_I].dma_chan_i; hal_freescale_edma_transfer_init(edma_p, dma_chan_i, spi_bus_p->tx_dma_tcd_ini_p); #if DEBUG_SPI >= 1 hal_freescale_edma_transfer_diag(edma_p, dma_chan_i, true); #endif dma_chan_i = dma_set_p->chan_p[SPI_DMA_CHAN_RX_I].dma_chan_i; hal_freescale_edma_transfer_init(edma_p, dma_chan_i, spi_bus_p->rx_dma_tcd_ini_p); #if DEBUG_SPI >= 1 hal_freescale_edma_transfer_diag(edma_p, dma_chan_i, true); #endif // Enable SPI DMA requests dspi_p->rser = FREESCALE_DSPI_RSER_TFFF_DIRS_M | FREESCALE_DSPI_RSER_RFDF_DIRS_M | FREESCALE_DSPI_RSER_TFFF_RE_M | FREESCALE_DSPI_RSER_RFDF_RE_M; } #if DEBUG_SPI >= 1 cyghwr_devs_freescale_dspi_diag(spi_bus_p); #endif // Initialise the synchronisation primitivies. cyg_drv_mutex_init (&spi_bus_p->transfer_mutex); cyg_drv_cond_init (&spi_bus_p->transfer_done, &spi_bus_p->transfer_mutex); // Hook up the ISR and DSR. cyg_drv_interrupt_create (spi_bus_p->setup_p->intr_num, spi_bus_p->setup_p->intr_prio, (cyg_addrword_t) spi_bus_p, dma_set_p ? dspi_dma_ISR : dspi_nodma_ISR, dspi_DSR, &spi_bus_p->intr_handle, &spi_bus_p->intr_data); cyg_drv_interrupt_attach (spi_bus_p->intr_handle); dspi_p->ctar[1] = dspi_calc_ctar(&aux_clocking, spi_bus_p->clock_freq); // Call upper layer bus init. CYG_SPI_BUS_COMMON_INIT(&spi_bus_p->spi_bus); }
static void spi_transaction_do (cyg_spi_device* device, cyg_bool tick_only, cyg_bool polled, cyg_uint32 count, const cyg_uint8* tx_data, cyg_uint8* rx_data, cyg_bool drop_cs) { cyg_spi_freescale_dspi_bus_t* dspi_bus = (cyg_spi_freescale_dspi_bus_t*) device->spi_bus; cyg_spi_freescale_dspi_device_t* dspi_device = (cyg_spi_freescale_dspi_device_t*) device; cyg_bool bus_16bit = dspi_device->clocking.bus_16bit; cyghwr_devs_freescale_dspi_t* dspi_p = dspi_bus->setup_p->dspi_p; cyghwr_hal_freescale_dma_set_t* dma_set_p; cyghwr_hal_freescale_edma_t* edma_p = NULL; cyg_uint32 count_down; cyg_uint32 txfifo_n = dspi_bus->txfifo_n; cyg_uint32 pushr; cyg_uint32 pushque_n; cyg_uint32 dma_chan_rx_i = 0; cyg_uint32 dma_chan_tx_i = 0; cyg_uint8* rx_data0; #if DEBUG_SPI >= 2 cyg_uint32 first_turn = 1; #endif DEBUG2_PRINTF("DSPI: transaction: count=%d drop_cs=%d tick_only=%d\n", count, drop_cs, tick_only); // Set up peripheral CS field. DSPI automatically asserts and deasserts CS pushr = #ifndef CYGOPT_DEVS_SPI_FREESCALE_DSPI_TICK_ONLY_DROPS_CS // Compatibility option // eCos Reference Manual states that CS should drop prior to sending // ticks, but other SPI drivers do not touch the CS. tick_only ? dspi_p->pushr & 0x87FF0000 : #endif dspi_chip_select_set( #ifdef CYGOPT_DEVS_SPI_FREESCALE_DSPI_TICK_ONLY_DROPS_CS // Compatibility option. See comment above. tick_only ? -1 : #endif dspi_device->dev_num, dspi_p->mcr & FREESCALE_DSPI_MCR_PCSSE_M, true); pushr |= FREESCALE_DSPI_PUSHR_CONT_M; dspi_fifo_clear(dspi_p); pushque_n = dspi_bus->pushque_n; if(bus_16bit) txfifo_n *= 2; dma_set_p = dspi_bus->setup_p->dma_set_p; if((count > txfifo_n) && dma_set_p) { rx_data0 = rx_data; edma_p = dma_set_p->edma_p; // Set up the DMA channels. dma_chan_rx_i = SPI_DMA_CHAN_I(dma_set_p, RX); dma_chan_tx_i = SPI_DMA_CHAN_I(dma_set_p, TX); rx_dma_channel_setup(dma_set_p, (cyg_uint8*) rx_data, bus_16bit, &edma_p->tcd[dma_chan_rx_i]); hal_freescale_edma_erq_enable(edma_p, dma_chan_rx_i); dspi_irq_enable(dspi_p, FREESCALE_DSPI_RSER_TFFF_RE_M | FREESCALE_DSPI_RSER_RFDF_RE_M | FREESCALE_DSPI_RSER_TFFF_DIRS_M | FREESCALE_DSPI_RSER_RFDF_DIRS_M); } else { rx_data0 = NULL; // If byte count fits in the FIFO don't bother with DMA. if(dma_set_p) { edma_p = dma_set_p->edma_p; hal_freescale_edma_erq_disable(edma_p, SPI_DMA_CHAN_I(dma_set_p, RX)); } dma_set_p = NULL; dspi_irq_disable(dspi_p, FREESCALE_DSPI_RSER_TFFF_RE_M | FREESCALE_DSPI_RSER_RFDF_RE_M | FREESCALE_DSPI_RSER_TFFF_DIRS_M | FREESCALE_DSPI_RSER_RFDF_DIRS_M); } if(!polled) cyg_drv_interrupt_unmask(dspi_bus->setup_p->intr_num); count_down = count; while(count_down) { #if DEBUG_SPI >= 2 if(first_turn) { if(dspi_bus->pushque_p) dspi_bus->pushque_p[0] |= FREESCALE_DSPI_PUSHR_CTCNT_M; first_turn = 0; } #endif if(dma_set_p && (count_down > txfifo_n)) { // Transfer size is larger than DSPI FIFO // Use DMA Tx count_down = tx_dma_channel_setup(dspi_bus, (cyg_uint8*) tx_data, count_down, bus_16bit, pushr, drop_cs); #if DEBUG_SPI >= 3 hal_freescale_edma_transfer_diag(edma_p, dma_chan_rx_i, true); #endif // Enable the Tx DMA / SPI controller. hal_freescale_edma_erq_enable(edma_p, dma_chan_tx_i); DSPI_EOQ_CLEAR(dspi_p); } else { // Transfer size fits within DSPI FIFO // No need for DMA Tx DSPI_EOQ_CLEAR(dspi_p); count_down = fifo_pushque_fill(dspi_bus, (cyg_uint8*) tx_data, count_down, bus_16bit, pushr, drop_cs); #if DEBUG_SPI >= 3 cyghwr_devs_freescale_dspi_diag(dspi_bus); #endif } if(polled) { DEBUG2_PRINTF("DSPI Polled:\n"); // Busy-wait for DSPI/DMA (polling for completion). while(!(dspi_p->sr & FREESCALE_DSPI_SR_EOQF_M)); if(dma_set_p) { // Disable the Tx DMA channel on completion. hal_freescale_edma_erq_disable(edma_p, dma_chan_tx_i); } } else { // Wait for DSPI/DMA completion. (interrupt driven). cyg_drv_mutex_lock(&dspi_bus->transfer_mutex); cyg_drv_dsr_lock(); DSPI_IRQ_ENABLE(dspi_p); DEBUG2_PRINTF("DSPI IRQ: Enabled\n"); // Sit back and wait for the ISR/DSRs to signal completion. cyg_drv_cond_wait (&dspi_bus->transfer_done); cyg_drv_dsr_unlock(); cyg_drv_mutex_unlock(&dspi_bus->transfer_mutex); } if(dma_set_p) { // Make sure that Rx has been drained by DMA. while((dspi_p->sr & FREESCALE_DSPI_SR_RFDF_M)); DEBUG2_PRINTF("Fifo Drained by DMA 0x%08x\n", dspi_p->sr); if(count_down <= txfifo_n && count_down > 0) { hal_freescale_edma_erq_disable(edma_p, dma_chan_rx_i); dma_set_p = NULL; } } else { // No DMA - "manually" drain Rx FIFO DEBUG2_PRINTF("DSPI FIFO: 'Manually' drain Rx fifo rx_data=%p bus_16bit=%d\n", rx_data, bus_16bit); #if DEBUG_SPI >= 3 cyghwr_devs_freescale_dspi_diag(dspi_bus); #endif if(rx_data) { if(bus_16bit) { cyg_uint16* rx_data16 = (cyg_uint16*) rx_data; while(dspi_p->sr & FREESCALE_DSPI_SR_RXCTR_M) { DEBUG2_PRINTF(" Fifo Pull16 at %p\n", rx_data16); *rx_data16++ = dspi_p->popr; } rx_data = (cyg_uint8*) rx_data16; } else { while(dspi_p->sr & FREESCALE_DSPI_SR_RXCTR_M) { DEBUG2_PRINTF(" Fifo Pull at %p\n", rx_data); *rx_data++ = dspi_p->popr; } } } dspi_fifo_drain(dspi_p); } dspi_fifo_clear(dspi_p); // Prepare for next iteration if(tx_data) { tx_data += pushque_n; if(bus_16bit) tx_data += pushque_n; } } if(rx_data0) { // Rx buffer may be out of sync with cache. DEBUG2_PRINTF("DSPI DMA: Flush cache %p len=%d\n", rx_data0, count); HAL_DCACHE_INVALIDATE(rx_data0, count); DEBUG2_PRINTF("DSPI DMA: Cache flushed\n"); } if(!polled) cyg_drv_interrupt_mask(dspi_bus->setup_p->intr_num); dspi_device->chip_sel = !drop_cs; DEBUG2_PRINTF("cyg_transaction_do() chip_sel = %d drop_cs = %d\n", dspi_device->chip_sel, drop_cs); }