static void dspi_transaction_end(cyg_spi_device* device)
{
    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;

    const cyghwr_hal_freescale_dma_set_t *dma_set_p = dspi_bus->setup_p->dma_set_p;
    cyghwr_hal_freescale_edma_t *edma_p;
    cyghwr_devs_freescale_dspi_t* dspi_p = dspi_bus->setup_p->dspi_p;

    DEBUG2_PRINTF("cyg_transaction_end() chip_sel = %d\n", dspi_device->chip_sel);
    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, TX));
        hal_freescale_edma_erq_disable(edma_p, SPI_DMA_CHAN_I(dma_set_p, RX));
    }

    if(dspi_device->chip_sel){
        // Clear peripheral CS by executing a dummy 4 bit transfer.
        dspi_p->pushr = PUSHR_NULL | FREESCALE_DSPI_PUSHR_EOQ_M |
                        FREESCALE_DSPI_PUSHR_CTAS(1);
        while(!(dspi_p->sr & FREESCALE_DSPI_SR_EOQF_M));
        DSPI_EOQ_CLEAR(dspi_p);
        dspi_fifo_drain(dspi_p);
        dspi_device->chip_sel = 0;
    }
}
Example #2
0
static int dspi_get_config (cyg_spi_device* device, cyg_uint32 key,
                            void* buf, cyg_uint32* len)
{
    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_uint32* data_p = buf;

    switch (key) {
    case CYG_IO_GET_CONFIG_SPI_CLOCKRATE :
        // Sanity check
        if (NULL == len) {
            CYG_ASSERT (false, "Freescale DSPI:"
                        " Null pointer as len argument for dspi_get_config().");
            return -1;
        } else if (sizeof(cyg_uint32) != *len) {
            CYG_ASSERT (false, "Freescale DSPI:"
                        " Invalid length with dspi_get_config().");
            return -1;
        } else if (NULL == buf) {
            CYG_ASSERT (false, "Freescale DSPI:"
                        " Null poiter as buf argument for dspi_get_config().");
            return -1;
        } else {
            cyg_uint32 ctar, dbr, br, pbr;

            ctar = dspi_device->clocking.dspi_ctar;
            dbr = (ctar & FREESCALE_DSPI_CTAR_DBR_M) >>
                  FREESCALE_DSPI_CTAR_DBR_S;
            br = (ctar & FREESCALE_DSPI_CTAR_BR_M) >>
                  FREESCALE_DSPI_CTAR_BR_S;
            pbr = (ctar & FREESCALE_DSPI_CTAR_PBR_M) >>
                  FREESCALE_DSPI_CTAR_PBR_S;
            *data_p = (dspi_bus->clock_freq * (1+dbr)) / (pbr * br);

            DEBUG2_PRINTF("DSPI Get Config: baud = %d\n", *data_p);

            return 0;
        }

    default :
        break;
    }
    return -1;
}
static void dspi_transaction_tick(cyg_spi_device* device, cyg_bool polled,
                                  cyg_uint32 count)
{
    cyg_spi_freescale_dspi_device_t* dspi_device =
          (cyg_spi_freescale_dspi_device_t*) device;

    // Check for unsupported transactions.
    CYG_ASSERT (count > 0, "DSPI: Null transfer requested.");

    // We check that count is a multiple of two in order
    // to carry out the 16-bit transfer.
    if (dspi_device->clocking.bus_16bit) {
        CYG_ASSERT (!(count & 1),
                    "DSPI: Misaligned data in 16-bit transfer.");
    }

    // Perform null transfer
    DEBUG2_PRINTF("cyg_transaction_tick()\n");
    spi_transaction_do (device, true, polled, count, NULL, NULL, false);
}
Example #4
0
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 dspi_transaction_transfer(cyg_spi_device* device, cyg_bool polled,
                                      cyg_uint32 count,
                                      const cyg_uint8* tx_data,
                                      cyg_uint8* rx_data,
                                      cyg_bool drop_cs)
{
    cyg_spi_freescale_dspi_device_t* dspi_device =
          (cyg_spi_freescale_dspi_device_t*) device;

    DEBUG2_PRINTF("Transaction rx_data = %p tx_data = %p count=%d\n", rx_data, tx_data, count);

    // Check for unsupported transactions.
    CYG_ASSERT (count > 0, "DSPI: Null transfer requested.");

    // We check that the buffers are half-word aligned and that count is a
    // multiple of two in order to carry out the 16-bit transfer.
    if (dspi_device->clocking.bus_16bit) {
        CYG_ASSERT (!(count & 1) && !((cyg_uint32) tx_data & 1) &&
                    !((cyg_uint32) rx_data & 1),
                    "DSPI: Misaligned data in 16-bit transfer.");
    }
    spi_transaction_do (device, false, polled, count, tx_data, rx_data, drop_cs);
}
Example #6
0
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;
}
Example #7
0
static inline volatile cyg_uint32
dma_pushque_fill(cyg_spi_freescale_dspi_bus_t* dspi_bus, cyg_uint8* data_p,
                 cyg_uint32 count, cyg_bool bus_16bit, cyg_uint32 pushr,
                 cyg_bool drop_cs)
{
    volatile cyg_uint32* pushque_p;
    volatile cyg_uint32* pushque_end;

    pushque_p = dspi_bus->pushque_p;
    pushque_end = pushque_p + dspi_bus->pushque_n;
    pushque_p = dspi_bus->pushque_p;
    if(data_p) {
        if(!bus_16bit) {
            do {
                if(pushque_p == pushque_end) {
                    pushque_p[0] = pushr;
                    pushque_p[-1] |= FREESCALE_DSPI_PUSHR_EOQ_M;
                    DEBUG2_PRINTF(debug_format, 8, "BRK", pushque_p-1,
                                  pushque_p[-1], count);
                    return count;
                }
                *pushque_p++ = pushr | *data_p++;
                DEBUG3_PRINTF(debug_format, 8, "ADD", pushque_p-1,
                              pushque_p[-1], count-1);
            } while(--count > 1);
            pushr |= *data_p;
        } else {
            cyg_uint16* data16_p = (cyg_uint16 *)data_p;
            cyg_uint16 data_word;
            do {
                if(pushque_p == pushque_end) {
                    pushque_p[0] = pushr;
                    pushque_p[-1] |= FREESCALE_DSPI_PUSHR_EOQ_M;
                    DEBUG2_PRINTF(debug_format, 16, "BRK", pushque_p-1,
                                  pushque_p[-1], count);
                    return count;
                }
                data_word = *data16_p++;
                *pushque_p++ = pushr | data_word;
                DEBUG3_PRINTF(debug_format, 16, "ADD", pushque_p-1,
                              pushque_p[-1], count-2);
            } while((count -= 2) > 2);
            data_word = *data16_p;
            pushr |= data_word;
        }
    } else {
        do {
            if(pushque_p == pushque_end) {
                pushque_p[0] = pushr;
                pushque_p[-1] |= FREESCALE_DSPI_PUSHR_EOQ_M;
                DEBUG2_PRINTF(debug_format, 0, "BRK", pushque_p-1,
                              pushque_p[-1], count);
                return count;
            }
            *pushque_p++ = pushr;
            DEBUG3_PRINTF(debug_format, 0, "BRK", pushque_p-1, pushque_p[-1],
                          count-1);
        } while(--count > 1);
    }
    if(drop_cs) pushr &= ~FREESCALE_DSPI_PUSHR_CONT_M;
    pushque_p[1] = pushr;
    *pushque_p = pushr |= FREESCALE_DSPI_PUSHR_EOQ_M;
    DEBUG2_PRINTF(debug_format, data_p ? (bus_16bit ? 16 :8) : 0,
                  (drop_cs ? "END" : "SGM"), pushque_p, pushque_p[0], 0);
    return 0;
}
Example #8
0
static inline volatile cyg_uint32
fifo_pushque_fill(cyg_spi_freescale_dspi_bus_t* dspi_bus, cyg_uint8*
                  data_p, cyg_uint32 count, cyg_bool bus_16bit, cyg_uint32 pushr,
                  cyg_bool drop_cs)
{
    cyghwr_devs_freescale_dspi_t* dspi_p = dspi_bus->setup_p->dspi_p;
    cyg_uint32 txfifo_n = dspi_bus->txfifo_n;

    if(data_p) {
        if(!bus_16bit) {
            for(; count > 1; count--) {
                if(!(--txfifo_n)) {
                    dspi_p->pushr = pushr |= *data_p | FREESCALE_DSPI_PUSHR_EOQ_M;
                    count--;
                    DEBUG2_PRINTF(debug_format, 8, "FBK", &dspi_p->pushr,
                                  pushr | *data_p, count);
                    return count;
                }
                dspi_p->pushr = pushr | *data_p++;
                DEBUG3_PRINTF(debug_format, 8, "FAD", &dspi_p->pushr,
                              pushr | data_p[-1], count-1);
            }
            pushr |= *data_p;
        } else {
            cyg_uint16* data16_p = (cyg_uint16 *)data_p;
            cyg_uint16 data_word;

            for(; count > 2; count-=2) {
                if(!(--txfifo_n)) {
                    dspi_p->pushr = pushr |= *data16_p | FREESCALE_DSPI_PUSHR_EOQ_M;
                    count-=2;
                    DEBUG2_PRINTF(debug_format, 16, "FBK", &dspi_p->pushr,
                                  pushr, count);
                    return count;
                }
                data_word = *data16_p++;
                dspi_p->pushr = pushr | data_word;
                DEBUG3_PRINTF(debug_format, 16, "FAD", &dspi_p->pushr,
                              pushr | data_word, (count-1)*2);
            }
            data_word = *data16_p;
            pushr |= data_word;
        }
    } else {
        for(; count > 1; count--) {
            if(!(--txfifo_n)) {
                dspi_p->pushr = pushr |= FREESCALE_DSPI_PUSHR_EOQ_M;
                count--;
                DEBUG2_PRINTF(debug_format, 0, "FBK", &dspi_p->pushr,
                              pushr, count);
                return count;
            }
            dspi_p->pushr = pushr;
            DEBUG3_PRINTF(debug_format, 0, "FAD", &dspi_p->pushr, pushr,
                          count-1);
        }
    }
    if(drop_cs)
        pushr &= ~FREESCALE_DSPI_PUSHR_CONT_M;
    dspi_p->pushr = pushr |= FREESCALE_DSPI_PUSHR_EOQ_M;
    DEBUG3_PRINTF(debug_format, data_p ? (bus_16bit ? 16 :8) : pushr,
                  (drop_cs ? "FEN" : "FSG"), &dspi_p->pushr, pushr, 0);
    return 0;
}
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);
}