summaryrefslogtreecommitdiffstats
path: root/c/src/lib/libbsp/arm/atsam/spi/atsam_spi_bus.c
diff options
context:
space:
mode:
authorSebastian Huber <sebastian.huber@embedded-brains.de>2016-12-15 09:56:12 +0100
committerSebastian Huber <sebastian.huber@embedded-brains.de>2016-12-15 11:05:09 +0100
commitd1c771cc8b1988916f1eb926986d9ab74873ba37 (patch)
tree5e6f182ebe9f86090bf0c9eabcebf9479d234857 /c/src/lib/libbsp/arm/atsam/spi/atsam_spi_bus.c
parentbsp/atsam: Use _Assert() instead of assert() (diff)
downloadrtems-d1c771cc8b1988916f1eb926986d9ab74873ba37.tar.bz2
bsp/atsam: Move XDMA IRQ handler to XDMA module
The XDMA is shared by all DMA capable modules. Placing the XDMA interrupt handler into the SPI module is wrong.
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.c311
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);
}