AnsweredAssumed Answered

DMA SPI Slave Issues

Question asked by Curtis Belknap on Jan 31, 2019
Latest reply on Feb 6, 2019 by igorpadykov

I have implemented a DMA SPI slave driver for Linux and I am seeing a strange issue.

I have a data structure that is 4096 bytes long. When I initiate a SPI transfer on the master side, I find that I have to transfer an additional 4 bytes to collect the full message on the slave side. The strange part is that these extra 4 bytes do not end up in any buffers. Performing a CRC32 on the data structure on the master side, then slave side shows that the data is consistent as long as I add the extra 4 bytes. 

 

Can someone offer some guidance as to where the last 4 bytes are going? And why the extra bytes are necessary?

 

I have configured the SPI device as follows:

reg = 0;
reg |= IMX6_ECSPI_DMA_RXTDEN;
reg |= IMX6_ECSPI_DMA_RX_LEN(SPI_DMA_RX_BURST_LEN); // RX_DMA_LENGTH = 32
reg |= IMX6_ECSPI_DMA_RXDEN;
reg |= IMX6_ECSPI_DMA_RX_THR(SPI_DMA_RX_THRESHOLD - 1); // RX_THRESHOLD = 31
writel(reg, spislv->base + IMX6_ECSPI_DMA);

The DMA (slave side) is configured to fill a buffer of 4096 bytes in 32 word (128 byte) increments. The Linux DMA engine is configured as follows:

slave_config.dst_addr = (dma_addr_t) spislv->phybase + IMX6_ECSPI_DATA_TX;
slave_config.src_addr = (dma_addr_t) spislv->phybase + IMX6_ECSPI_DATA_RX;
slave_config.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
slave_config.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
slave_config.src_maxburst = SPI_DMA_RX_BURST_LEN; // 32 Words
slave_config.dst_maxburst = SPI_DMA_RX_BURST_LEN; // 32 Words
slave_config.device_fc = true;
slave_config.direction = DMA_DEV_TO_MEM;

if (dmaengine_slave_config(spislv->dma.rx_dma_chan, &slave_config)) {
    dev_err(&spislv->pdev->dev, "can't configure rx dma channel\n");
    return -EINVAL;
}
rx_desc = dmaengine_prep_dma_cyclic(spislv->dma.rx_dma_chan,
        spislv->dma.handle,
        2 * SPI_RX_BUFF_SIZE, // 2 * 4096 Bytes
        SPI_RX_BUFF_SIZE, // 4096 Bytes
        DMA_DEV_TO_MEM,
        DMA_PREP_INTERRUPT);
if (!rx_desc)
return -ENOMEM;

Outcomes