forked from Imagelibrary/rtems
bsp/atsam: Reduce context switches for SPI transf
This commit is contained in:
@@ -38,9 +38,11 @@
|
|||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
spi_bus base;
|
spi_bus base;
|
||||||
|
bool msg_cs_change;
|
||||||
|
const spi_ioc_transfer *msg_current;
|
||||||
uint32_t msg_todo;
|
uint32_t msg_todo;
|
||||||
const spi_ioc_transfer *msgs;
|
int msg_error;
|
||||||
rtems_id task_id;
|
rtems_id msg_task;
|
||||||
sXdmad xdma;
|
sXdmad xdma;
|
||||||
Spid SpiDma;
|
Spid SpiDma;
|
||||||
uint32_t dma_tx_channel;
|
uint32_t dma_tx_channel;
|
||||||
@@ -50,78 +52,13 @@ typedef struct {
|
|||||||
bool chip_select_active;
|
bool chip_select_active;
|
||||||
} atsam_spi_bus;
|
} atsam_spi_bus;
|
||||||
|
|
||||||
static void atsam_spi_interrupt(void *arg)
|
static void atsam_spi_wakeup_task(atsam_spi_bus *bus)
|
||||||
{
|
{
|
||||||
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;
|
|
||||||
rtems_status_code sc;
|
rtems_status_code sc;
|
||||||
assert(xdma != NULL);
|
|
||||||
|
|
||||||
xdmac = xdma->pXdmacs;
|
sc = rtems_event_transient_send(bus->msg_task);
|
||||||
xdmaGlobaIntStatus = XDMAC_GetGIsr(xdmac);
|
|
||||||
|
|
||||||
if ((xdmaGlobaIntStatus & 0xFFFFFF) != 0) {
|
|
||||||
xdmaGlobalChStatus = XDMAC_GetGlobalChStatus(xdmac);
|
|
||||||
|
|
||||||
for (channel = 0; channel < xdma->numChannels; channel ++) {
|
|
||||||
if (!(xdmaGlobaIntStatus & (1 << channel))) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
ch = &xdma->XdmaChannels[channel];
|
|
||||||
|
|
||||||
if (ch->state == XDMAD_STATE_FREE) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
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) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (bExec == 1 && (channel == bus->dma_rx_channel)) {
|
|
||||||
bus->rx_transfer_done = true;
|
|
||||||
XDMAC_DisableGIt(spid->pXdmad->pXdmacs, bus->dma_rx_channel);
|
|
||||||
} else if (bExec == 1 && (channel == bus->dma_tx_channel)) {
|
|
||||||
bus->tx_transfer_done = true;
|
|
||||||
XDMAC_DisableGIt(spid->pXdmad->pXdmacs, bus->dma_tx_channel);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (bus->rx_transfer_done && bus->tx_transfer_done) {
|
|
||||||
sc = rtems_event_transient_send(bus->task_id);
|
|
||||||
assert(sc == RTEMS_SUCCESSFUL);
|
assert(sc == RTEMS_SUCCESSFUL);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static uint8_t atsam_calculate_dlybcs(uint16_t delay_in_us)
|
static uint8_t atsam_calculate_dlybcs(uint16_t delay_in_us)
|
||||||
{
|
{
|
||||||
@@ -328,33 +265,108 @@ static int atsam_check_configure_spi(atsam_spi_bus *bus, const spi_ioc_transfer
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int atsam_spi_setup_transfer(atsam_spi_bus *bus)
|
static void atsam_spi_setup_transfer(atsam_spi_bus *bus)
|
||||||
{
|
{
|
||||||
const spi_ioc_transfer *msgs = bus->msgs;
|
|
||||||
uint32_t msg_todo = bus->msg_todo;
|
uint32_t msg_todo = bus->msg_todo;
|
||||||
uint32_t i;
|
|
||||||
int error;
|
|
||||||
|
|
||||||
for (i = 0; i < msg_todo; ++i) {
|
|
||||||
error = atsam_check_configure_spi(bus, &msgs[i]);
|
|
||||||
if (error < 0) {
|
|
||||||
return error;
|
|
||||||
}
|
|
||||||
|
|
||||||
atsam_spi_do_transfer(bus, &msgs[i]);
|
|
||||||
rtems_event_transient_receive(RTEMS_WAIT, RTEMS_NO_TIMEOUT);
|
|
||||||
|
|
||||||
bus->rx_transfer_done = false;
|
bus->rx_transfer_done = false;
|
||||||
bus->tx_transfer_done = false;
|
bus->tx_transfer_done = false;
|
||||||
|
|
||||||
if (msgs[i].cs_change > 0) {
|
if (bus->msg_cs_change) {
|
||||||
bus->chip_select_active = false;
|
bus->chip_select_active = false;
|
||||||
SPI_ReleaseCS(bus->SpiDma.pSpiHw);
|
SPI_ReleaseCS(bus->SpiDma.pSpiHw);
|
||||||
SPI_Disable(bus->SpiDma.pSpiHw);
|
SPI_Disable(bus->SpiDma.pSpiHw);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (msg_todo > 0) {
|
||||||
|
const spi_ioc_transfer *msg = bus->msg_current;
|
||||||
|
int error;
|
||||||
|
|
||||||
|
bus->msg_cs_change = msg->cs_change;
|
||||||
|
bus->msg_current = msg + 1;
|
||||||
|
bus->msg_todo = msg_todo - 1;
|
||||||
|
|
||||||
|
error = atsam_check_configure_spi(bus, msg);
|
||||||
|
if (error == 0) {
|
||||||
|
atsam_spi_do_transfer(bus, msg);
|
||||||
|
} else {
|
||||||
|
bus->msg_error = error;
|
||||||
|
atsam_spi_wakeup_task(bus);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
atsam_spi_wakeup_task(bus);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
static void atsam_spi_interrupt(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);
|
||||||
|
|
||||||
|
if ((xdmaGlobaIntStatus & 0xFFFFFF) != 0) {
|
||||||
|
xdmaGlobalChStatus = XDMAC_GetGlobalChStatus(xdmac);
|
||||||
|
|
||||||
|
for (channel = 0; channel < xdma->numChannels; channel ++) {
|
||||||
|
if (!(xdmaGlobaIntStatus & (1 << channel))) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
ch = &xdma->XdmaChannels[channel];
|
||||||
|
|
||||||
|
if (ch->state == XDMAD_STATE_FREE) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
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) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bExec == 1 && (channel == bus->dma_rx_channel)) {
|
||||||
|
bus->rx_transfer_done = true;
|
||||||
|
XDMAC_DisableGIt(spid->pXdmad->pXdmacs, bus->dma_rx_channel);
|
||||||
|
} else if (bExec == 1 && (channel == bus->dma_tx_channel)) {
|
||||||
|
bus->tx_transfer_done = true;
|
||||||
|
XDMAC_DisableGIt(spid->pXdmad->pXdmacs, bus->dma_tx_channel);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bus->rx_transfer_done && bus->tx_transfer_done) {
|
||||||
|
atsam_spi_setup_transfer(bus);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int atsam_spi_transfer(
|
static int atsam_spi_transfer(
|
||||||
@@ -363,20 +375,16 @@ static int atsam_spi_transfer(
|
|||||||
uint32_t msg_count
|
uint32_t msg_count
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
int rv;
|
|
||||||
atsam_spi_bus *bus = (atsam_spi_bus *)base;
|
atsam_spi_bus *bus = (atsam_spi_bus *)base;
|
||||||
|
|
||||||
if (msg_count == 0) {
|
bus->msg_cs_change = false;
|
||||||
return 0;
|
bus->msg_current = &msgs[0];
|
||||||
}
|
|
||||||
|
|
||||||
bus->msgs = &msgs[0];
|
|
||||||
bus->msg_todo = msg_count;
|
bus->msg_todo = msg_count;
|
||||||
bus->task_id = rtems_task_self();
|
bus->msg_error = 0;
|
||||||
|
bus->msg_task = rtems_task_self();
|
||||||
rv = atsam_spi_setup_transfer(bus);
|
atsam_spi_setup_transfer(bus);
|
||||||
|
rtems_event_transient_receive(RTEMS_WAIT, RTEMS_NO_TIMEOUT);
|
||||||
return rv;
|
return bus->msg_error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user