I am using the Spectrum Digital DM365 EVM with DVSDK 3.10.00.12. We have a need for SPI slave usage on the DM365, so we have modified the Linux drivers to include SPI slave support, including EDMA support. I am focusing on SPI slave read at the moment. With my current setup, I am able to successfully receive exactly one message per bootup on SPI2. After completing one EDMA transfer, the davinci_spi_irq in davinci_spi.c never gets called on successive SPI messages until the DM365 is rebooted. I have checked all of the global interrupt controller registers, the SPI2 registers, and the EDMA registers and do not see any register settings after the one successful reception which would prevent the IRQ from getting called.
For our setup, the first two bytes of the SPI message is the length of the message. The IRQ reads the first two bytes of the message to obtain the length, with the length being the number of bytes in the message not including the length field (i.e., the first two bytes of the SPI message specify the length of the EDMA transfer). The IRQ then disables SPI interrupts and finishes setting up the EDMA transfer with the known SPI message length. In the RX callback for the EDMA transfer(davinci_spi_dma_rx_callback), the EDMA is disabled and the SPI interrupt is enabled. Below is a summary of the functions that I believe are related to the issue. I removed the parts relative to SPI master, since that is not applicable to this issue.
static irqreturn_t davinci_spi_irq(s32 irq, void *context_data)
{
struct davinci_spi_platform_data *pdata;
struct davinci_spi *davinci_spi = context_data;
u32 int_status, rx_data = 0;
irqreturn_t ret = IRQ_HANDLED;
u32 rx_length;
u32 data;
u8 *tx_buf;
u32 data1_reg_val;
int_status = ioread32(davinci_spi->base + SPIFLG);
if (likely(int_status & SPIFLG_RX_INTR_MASK)) {
/* Disable Receive Interrupt */
iowrite32(~(SPIINT_RX_INTR | SPIINT_TX_INTR), davinci_spi->base + SPIINT);
/* Read in the lower 8 bits of the length field */
rx_length = ioread32(davinci_spi->base + SPIBUF) & 0x000000FF;
/* Write some more data and then wait for transfer to complete */
data1_reg_val = ioread32(davinci_spi->base + SPIDAT1);
data1_reg_val &= ~(0xFFFF);
data1_reg_val |= (davinci_spi->current_tx_length >> 8) & 0xFF;
iowrite32(data1_reg_val, davinci_spi->base + SPIDAT1);
/* Wait for transfer to complete */
while ((data = ioread32(davinci_spi->base + SPIBUF))
& SPIBUF_RXEMPTY_MASK);
/* Add the upper 8 bits to the length field */
data &= 0x000000FF;
data <<= 8;
rx_length += data;
/* Master actually has data to send */
if (rx_length > 3) {
/* Get free buffer from bitbang */
u32 tx_length;
u8 *rx_buf = spi_bitbang_get_free_rx_buf(&davinci_spi->bitbang);
if (rx_buf == NULL) {
/* If no free buffer is available, return error to master */
tx_buf = rx_not_ready_buf;
}
else {
// Put the length into buffer.
rx_buf[0] = rx_length & 0xff;
rx_buf[1] = (rx_length >> 8) & 0xff;
/* Get a buffer to transmit, if the user has provided one */
tx_buf = spi_bitbang_get_tx_buf(&davinci_spi->bitbang, &tx_length);
}
/* Setup and start DMA */
davinci_spi_slave_dma(davinci_spi, tx_buf, tx_length, &rx_buf[2], rx_length);
}
} else
(void)davinci_spi_check_error(davinci_spi, int_status);
int_status = ioread32(davinci_spi->base + SPIFLG);
return ret;
}
static void davinci_spi_dma_rx_callback(unsigned lch, u16 ch_status, void *data)
{
struct spi_device *spi = (struct spi_device *)data;
struct davinci_spi *davinci_spi;
struct davinci_spi_dma *davinci_spi_dma;
struct davinci_spi_platform_data *pdata;
struct device *sdev;
davinci_spi = spi_master_get_devdata(spi->master);
davinci_spi_dma = &(davinci_spi->dma_channels[spi->chip_select]);
pdata = davinci_spi->pdata;
sdev = davinci_spi->bitbang.master->dev.parent;
/* We must disable the DMA RX request */
davinci_spi_set_dma_req(spi, 0);
// Kill the EDMA so another transfer doesn't start
edma_stop(davinci_spi_dma->dma_rx_channel);
/* Enable Rx interrupt */
set_io_bits(davinci_spi->base + SPIINT, SPIINT_RX_INTR);
/* Notify bitbang that a DMA transfer has completed */
spi_bitbang_notify_rx_complete(&davinci_spi->bitbang, davinci_spi_dma->dma_last_rx_length+2);
edma_free_channel(davinci_spi_dma->dma_rx_channel);
davinci_spi_dma->dma_rx_channel = -1;
}
Does anyone have any idea why I can receive only one message? Is there an order to the EDMA shutdown/SPI setup that is causing problems? Any suggestions at what to look at to determine why davinci_spi_irq is not called on successive SPI message receptions?