diff options
Diffstat (limited to 'c/src/lib/libbsp/arm/atsam/spi/atsam_spi_bus.c')
-rw-r--r-- | c/src/lib/libbsp/arm/atsam/spi/atsam_spi_bus.c | 311 |
1 files changed, 131 insertions, 180 deletions
diff --git a/c/src/lib/libbsp/arm/atsam/spi/atsam_spi_bus.c b/c/src/lib/libbsp/arm/atsam/spi/atsam_spi_bus.c index 2bc61665ea..77a1e9bb4f 100644 --- a/c/src/lib/libbsp/arm/atsam/spi/atsam_spi_bus.c +++ b/c/src/lib/libbsp/arm/atsam/spi/atsam_spi_bus.c @@ -30,16 +30,10 @@ #include <bsp/atsam-spi.h> -#include <rtems/irq-extension.h> - #include <dev/spi/spi.h> #define MAX_SPI_FREQUENCY 50000000 -#define TX_IN_PROGRESS 0x1 - -#define RX_IN_PROGRESS 0x2 - typedef struct { spi_bus base; bool msg_cs_change; @@ -51,7 +45,7 @@ typedef struct { Spid SpiDma; uint32_t dma_tx_channel; uint32_t dma_rx_channel; - int transfer_status; + int transfer_in_progress; bool chip_select_active; } atsam_spi_bus; @@ -120,93 +114,6 @@ static void atsam_configure_spi(atsam_spi_bus *bus) SPI_ConfigureNPCS(bus->SpiDma.pSpiHw, bus->base.cs, csr); } -static void atsam_spi_init_xdma(atsam_spi_bus *bus) -{ - sXdmadCfg cfg; - uint32_t xdmaInt; - uint8_t channel; - eXdmadRC rc; - - bus->dma_tx_channel = XDMAD_AllocateChannel( - &bus->xdma, - XDMAD_TRANSFER_MEMORY, - bus->SpiDma.spiId - ); - assert(bus->dma_tx_channel != XDMAD_ALLOC_FAILED); - - bus->dma_rx_channel = XDMAD_AllocateChannel( - &bus->xdma, - bus->SpiDma.spiId, - XDMAD_TRANSFER_MEMORY - ); - assert(bus->dma_rx_channel != XDMAD_ALLOC_FAILED); - - rc = XDMAD_PrepareChannel(&bus->xdma, bus->dma_rx_channel); - assert(rc == XDMAD_OK); - - rc = XDMAD_PrepareChannel(&bus->xdma, bus->dma_tx_channel); - assert(rc == XDMAD_OK); - - /* Put all interrupts on for non LLI list setup of DMA */ - xdmaInt = ( - XDMAC_CIE_BIE | - XDMAC_CIE_DIE | - XDMAC_CIE_FIE | - XDMAC_CIE_RBIE | - XDMAC_CIE_WBIE | - XDMAC_CIE_ROIE); - - /* Setup RX */ - memset(&cfg, 0, sizeof(cfg)); - channel = XDMAIF_Get_ChannelNumber(bus->SpiDma.spiId, XDMAD_TRANSFER_RX); - cfg.mbr_sa = (uint32_t)&bus->SpiDma.pSpiHw->SPI_RDR; - cfg.mbr_cfg = - XDMAC_CC_TYPE_PER_TRAN | - XDMAC_CC_MBSIZE_SINGLE | - XDMAC_CC_DSYNC_PER2MEM | - XDMAC_CC_CSIZE_CHK_1 | - XDMAC_CC_DWIDTH_BYTE | - XDMAC_CC_SIF_AHB_IF1 | - XDMAC_CC_DIF_AHB_IF1 | - XDMAC_CC_SAM_FIXED_AM | - XDMAC_CC_DAM_INCREMENTED_AM | - XDMAC_CC_PERID(channel); - rc = XDMAD_ConfigureTransfer( - &bus->xdma, - bus->dma_rx_channel, - &cfg, - 0, - 0, - xdmaInt - ); - assert(rc == XDMAD_OK); - - /* Setup TX */ - memset(&cfg, 0, sizeof(cfg)); - channel = XDMAIF_Get_ChannelNumber(bus->SpiDma.spiId, XDMAD_TRANSFER_TX); - cfg.mbr_da = (uint32_t)&bus->SpiDma.pSpiHw->SPI_TDR; - cfg.mbr_cfg = - XDMAC_CC_TYPE_PER_TRAN | - XDMAC_CC_MBSIZE_SINGLE | - XDMAC_CC_DSYNC_MEM2PER | - XDMAC_CC_CSIZE_CHK_1 | - XDMAC_CC_DWIDTH_BYTE | - XDMAC_CC_SIF_AHB_IF1 | - XDMAC_CC_DIF_AHB_IF1 | - XDMAC_CC_SAM_INCREMENTED_AM | - XDMAC_CC_DAM_FIXED_AM | - XDMAC_CC_PERID(channel); - rc = XDMAD_ConfigureTransfer( - &bus->xdma, - bus->dma_tx_channel, - &cfg, - 0, - 0, - xdmaInt - ); - assert(rc == XDMAD_OK); -} - static void atsam_spi_start_dma_transfer( atsam_spi_bus *bus, const spi_ioc_transfer *msg @@ -272,7 +179,7 @@ static void atsam_spi_setup_transfer(atsam_spi_bus *bus) { uint32_t msg_todo = bus->msg_todo; - bus->transfer_status = RX_IN_PROGRESS | TX_IN_PROGRESS; + bus->transfer_in_progress = 2; if (bus->msg_cs_change) { bus->chip_select_active = false; @@ -300,70 +207,14 @@ static void atsam_spi_setup_transfer(atsam_spi_bus *bus) } } -static void atsam_spi_interrupt(void *arg) +static void atsam_spi_dma_callback(uint32_t channel, void *arg) { atsam_spi_bus *bus = (atsam_spi_bus *)arg; - sXdmad *xdma = &bus->xdma; - Spid *spid = &bus->SpiDma; - Xdmac *xdmac; - sXdmadChannel *ch; - uint32_t xdmaChannelIntStatus, xdmaGlobaIntStatus, xdmaGlobalChStatus; - uint8_t channel; - uint8_t bExec = 0; - assert(xdma != NULL); - xdmac = xdma->pXdmacs; - xdmaGlobaIntStatus = XDMAC_GetGIsr(xdmac) & 0xFFFFFF; - xdmaGlobalChStatus = XDMAC_GetGlobalChStatus(xdmac); - - while (xdmaGlobaIntStatus != 0) { - channel = 31 - __builtin_clz(xdmaGlobaIntStatus); - xdmaGlobaIntStatus &= ~(UINT32_C(1) << channel); - - ch = &xdma->XdmaChannels[channel]; - - if (ch->state == XDMAD_STATE_FREE) { - continue; - } - - if ((xdmaGlobalChStatus & (XDMAC_GS_ST0 << channel)) == 0) { - bExec = 0; - xdmaChannelIntStatus = XDMAC_GetMaskChannelIsr(xdmac, channel); - - if (xdmaChannelIntStatus & XDMAC_CIS_BIS) { - if ((XDMAC_GetChannelItMask(xdmac, channel) & XDMAC_CIM_LIM) == 0) { - ch->state = XDMAD_STATE_DONE; - bExec = 1; - } - } - - if (xdmaChannelIntStatus & XDMAC_CIS_LIS) { - ch->state = XDMAD_STATE_DONE; - bExec = 1; - } - - if (xdmaChannelIntStatus & XDMAC_CIS_DIS) { - ch->state = XDMAD_STATE_DONE; - bExec = 1; - } - - } else { - /* Block end interrupt for LLI dma mode */ - if (XDMAC_GetChannelIsr(xdmac, channel) & XDMAC_CIS_BIS) { - } - } + --bus->transfer_in_progress; - if (bExec == 1 && (channel == bus->dma_rx_channel)) { - bus->transfer_status &= ~RX_IN_PROGRESS; - XDMAC_DisableGIt(spid->pXdmad->pXdmacs, bus->dma_rx_channel); - } else if (bExec == 1 && (channel == bus->dma_tx_channel)) { - bus->transfer_status &= ~TX_IN_PROGRESS; - XDMAC_DisableGIt(spid->pXdmad->pXdmacs, bus->dma_tx_channel); - } - - if (bus->transfer_status == 0) { - atsam_spi_setup_transfer(bus); - } + if (bus->transfer_in_progress == 0) { + atsam_spi_setup_transfer(bus); } } @@ -389,14 +240,26 @@ static int atsam_spi_transfer( static void atsam_spi_destroy(spi_bus *base) { atsam_spi_bus *bus = (atsam_spi_bus *)base; - rtems_status_code sc; + eXdmadRC rc; - /* Free XDMAD Channels */ - XDMAD_FreeChannel(bus->SpiDma.pXdmad, 0); - XDMAD_FreeChannel(bus->SpiDma.pXdmad, 1); + rc = XDMAD_SetCallback( + &bus->xdma, + bus->dma_rx_channel, + XDMAD_DoNothingCallback, + NULL + ); + assert(rc == XDMAD_OK); - sc = rtems_interrupt_handler_remove(ID_XDMAC, atsam_spi_interrupt, bus); - assert(sc == RTEMS_SUCCESSFUL); + rc = XDMAD_SetCallback( + &bus->xdma, + bus->dma_tx_channel, + XDMAD_DoNothingCallback, + NULL + ); + assert(rc == XDMAD_OK); + + XDMAD_FreeChannel(bus->SpiDma.pXdmad, bus->dma_rx_channel); + XDMAD_FreeChannel(bus->SpiDma.pXdmad, bus->dma_tx_channel); SPI_Disable(bus->SpiDma.pSpiHw); PMC_DisablePeripheral(bus->SpiDma.spiId); @@ -419,6 +282,109 @@ static int atsam_spi_setup(spi_bus *base) return 0; } +static void atsam_spi_init_xdma(atsam_spi_bus *bus) +{ + sXdmadCfg cfg; + uint32_t xdmaInt; + uint8_t channel; + eXdmadRC rc; + + bus->dma_tx_channel = XDMAD_AllocateChannel( + &bus->xdma, + XDMAD_TRANSFER_MEMORY, + bus->SpiDma.spiId + ); + assert(bus->dma_tx_channel != XDMAD_ALLOC_FAILED); + + bus->dma_rx_channel = XDMAD_AllocateChannel( + &bus->xdma, + bus->SpiDma.spiId, + XDMAD_TRANSFER_MEMORY + ); + assert(bus->dma_rx_channel != XDMAD_ALLOC_FAILED); + + rc = XDMAD_SetCallback( + &bus->xdma, + bus->dma_rx_channel, + atsam_spi_dma_callback, + bus + ); + assert(rc == XDMAD_OK); + + rc = XDMAD_SetCallback( + &bus->xdma, + bus->dma_tx_channel, + atsam_spi_dma_callback, + bus + ); + assert(rc == XDMAD_OK); + + rc = XDMAD_PrepareChannel(&bus->xdma, bus->dma_rx_channel); + assert(rc == XDMAD_OK); + + rc = XDMAD_PrepareChannel(&bus->xdma, bus->dma_tx_channel); + assert(rc == XDMAD_OK); + + /* Put all interrupts on for non LLI list setup of DMA */ + xdmaInt = ( + XDMAC_CIE_BIE | + XDMAC_CIE_DIE | + XDMAC_CIE_FIE | + XDMAC_CIE_RBIE | + XDMAC_CIE_WBIE | + XDMAC_CIE_ROIE); + + /* Setup RX */ + memset(&cfg, 0, sizeof(cfg)); + channel = XDMAIF_Get_ChannelNumber(bus->SpiDma.spiId, XDMAD_TRANSFER_RX); + cfg.mbr_sa = (uint32_t)&bus->SpiDma.pSpiHw->SPI_RDR; + cfg.mbr_cfg = + XDMAC_CC_TYPE_PER_TRAN | + XDMAC_CC_MBSIZE_SINGLE | + XDMAC_CC_DSYNC_PER2MEM | + XDMAC_CC_CSIZE_CHK_1 | + XDMAC_CC_DWIDTH_BYTE | + XDMAC_CC_SIF_AHB_IF1 | + XDMAC_CC_DIF_AHB_IF1 | + XDMAC_CC_SAM_FIXED_AM | + XDMAC_CC_DAM_INCREMENTED_AM | + XDMAC_CC_PERID(channel); + rc = XDMAD_ConfigureTransfer( + &bus->xdma, + bus->dma_rx_channel, + &cfg, + 0, + 0, + xdmaInt + ); + assert(rc == XDMAD_OK); + + /* Setup TX */ + memset(&cfg, 0, sizeof(cfg)); + channel = XDMAIF_Get_ChannelNumber(bus->SpiDma.spiId, XDMAD_TRANSFER_TX); + cfg.mbr_da = (uint32_t)&bus->SpiDma.pSpiHw->SPI_TDR; + cfg.mbr_cfg = + XDMAC_CC_TYPE_PER_TRAN | + XDMAC_CC_MBSIZE_SINGLE | + XDMAC_CC_DSYNC_MEM2PER | + XDMAC_CC_CSIZE_CHK_1 | + XDMAC_CC_DWIDTH_BYTE | + XDMAC_CC_SIF_AHB_IF1 | + XDMAC_CC_DIF_AHB_IF1 | + XDMAC_CC_SAM_INCREMENTED_AM | + XDMAC_CC_DAM_FIXED_AM | + XDMAC_CC_PERID(channel); + rc = XDMAD_ConfigureTransfer( + &bus->xdma, + bus->dma_tx_channel, + &cfg, + 0, + 0, + xdmaInt + ); + assert(rc == XDMAD_OK); +} + int spi_bus_register_atsam( const char *bus_path, uint8_t spi_peripheral_id, @@ -428,13 +394,16 @@ int spi_bus_register_atsam( ) { atsam_spi_bus *bus; - rtems_status_code sc; bus = (atsam_spi_bus *) spi_bus_alloc_and_init(sizeof(*bus)); if (bus == NULL) { return -1; } + bus->base.transfer = atsam_spi_transfer; + bus->base.destroy = atsam_spi_destroy; + bus->base.setup = atsam_spi_setup; + bus->base.max_speed_hz = MAX_SPI_FREQUENCY; bus->base.bits_per_word = 8; bus->base.speed_hz = bus->base.max_speed_hz; bus->base.delay_usecs = 1; @@ -448,23 +417,5 @@ int spi_bus_register_atsam( atsam_configure_spi(bus); atsam_spi_init_xdma(bus); - sc = rtems_interrupt_handler_install( - ID_XDMAC, - "SPI", - RTEMS_INTERRUPT_UNIQUE, - atsam_spi_interrupt, - bus - ); - if (sc != RTEMS_SUCCESSFUL) { - (*bus->base.destroy)(&bus->base); - - rtems_set_errno_and_return_minus_one(EIO); - } - - bus->base.transfer = atsam_spi_transfer; - bus->base.destroy = atsam_spi_destroy; - bus->base.setup = atsam_spi_setup; - bus->base.max_speed_hz = MAX_SPI_FREQUENCY; - return spi_bus_register(&bus->base, bus_path); } |