i.mx ecspi DMA issue

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

i.mx ecspi DMA issue

3,516 Views
stevenyu
Contributor III

Hi Support,

Basically, the ecspi DMA works fine until we modify below function to enable burst transfer. Because originally a SPI clock burst can only transfer 8 bits, and we would like to transfer more bits in one SPI clock burst. However, when we configure MX51_ECSPI_CTRL_BL_OFFSET and MX51_ECSPI_CONFIG_SBBCTRL to enable burst transfer, the return data of DMA are wrong (e.g. half 0x00 and half 0xff). Anythings we miss when we want to use BL(Burst Length) in ecspi DMA ?

Regards,

Steven Yu

static int mx51_ecspi_config(struct spi_device *spi)

=====from: 8 bits per SPI clock=====

ctrl |= (bits - 1) << MX51_ECSPI_CTRL_BL_OFFSET;
cfg |= MX51_ECSPI_CONFIG_SBBCTRL(spi->chip_select);

=====to: x bits per SPI clock; x depends on data length=====

....

spi_imx->rxcount = spi_imx->len;

....

if (reg > 0) {
ctrl |= reg << (MX51_ECSPI_CTRL_BL_OFFSET + 5);
}


cfg &= ~(MX51_ECSPI_CONFIG_SBBCTRL(spi->chip_select));

Labels (1)
0 Kudos
10 Replies

3,026 Views
igorpadykov
NXP Employee
NXP Employee

Hi Steven

description of usage these parameters in sdma scripts can be found

in sect. A.3.1.1 Parameters Required by Data Transfer Script Involving a
Peripheral i.MX53 Reference Manual

https://www.nxp.com/docs/en/reference-manual/iMX53RM.pdf

Freescale i.MX SDMA tutorial (part I) 

Best regards
igor

0 Kudos

3,026 Views
lepol
NXP Employee
NXP Employee

Hi Steven,

Did you managed to solve this problem? What is the length of burst you are trying to send? Just to be sure, you should be able to increase burst length in the SPI peripheral like you do for 8-bits per SPI clock but you should also configure DMA word len and watermark attributes respectively. So if the burst length is for example 512 bits then the DMA word len is 4 bytes and DMA watermark is 64.

0 Kudos

3,026 Views
stevenyu
Contributor III

Hi Lenka Polaskova,

We try the length for example 498 or 1048, and it should use peripheral DMA function. 

The SPI burst length is coded as below, it is a patch in the internet actually. What is DMA word length and watermark you mentioned ?

Regards,

Steven Yu

  /*
   * calculate the Burst Length,
   * refer to 21.7.3 Control Register (ECSPIx_CONREG)
   * for details.
   */
  switch (spi_imx->len%4) {
  case 1:
   ctrl |= 7 << MX51_ECSPI_CTRL_BL_OFFSET;
   reg = (spi_imx->len-1) / 4;//pr_err("config->len % 4 =%d ctrl=%x reg=%x\n", (config->len%4), 7 << MX51_ECSPI_CTRL_BL_OFFSET, reg );
   break;
  case 2:
   ctrl |= 15 << MX51_ECSPI_CTRL_BL_OFFSET;
   reg = (spi_imx->len-2) / 4;//pr_err("config->len % 4 =%d ctrl=%x reg=%x\n", (config->len%4), 15 << MX51_ECSPI_CTRL_BL_OFFSET, reg );
   break;
  case 3:
   ctrl |= 23 << MX51_ECSPI_CTRL_BL_OFFSET;
   reg = (spi_imx->len-3) / 4;//pr_err("config->len % 4 =%d ctrl=%x reg=%x\n", (config->len%4), 23 << MX51_ECSPI_CTRL_BL_OFFSET, reg );
   break;
  case 0:
   ctrl |= 31 << MX51_ECSPI_CTRL_BL_OFFSET;
   reg = (spi_imx->len-4) / 4;//pr_err("config->len % 4 =%d ctrl=%x reg=%x\n", (config->len%4), 31 << MX51_ECSPI_CTRL_BL_OFFSET, reg );
   break;
  }
  if (reg > 0) {//pr_err("len=%d value:0x%08x\n", config->len, (reg << (MX51_ECSPI_CTRL_BL_OFFSET + 5)));
   ctrl |= reg << (MX51_ECSPI_CTRL_BL_OFFSET + 5);
  }
  cfg &= ~(MX51_ECSPI_CONFIG_SBBCTRL(spi->chip_select));
0 Kudos

3,026 Views
lepol
NXP Employee
NXP Employee

Hi Steven,

For burst length in SPI I believe you could do simply:
ctrl |= (len*8 - 1) << MX51_ECSPI_CTRL_BL_OFFSET;

How do you configure sdma? Generally, DMA word length is the width on the payload the DMA pushes out of periferal's register and the DMA watermark is the number of cycles the DMA will push the payload out in one DMA request. If you use script targeted for transfer from MCU to CSPI then the word length should be fixed to 32-bits, the script should receive watermark level as an argument and the DMA use Burst unit (which has only 36-byte FIFO). You wrote that "return data of DMA are wrong (e.g. half 0x00 and half 0xff)". In that terms do you mean 16 LSB or half of burst? Is any part of data valid?

Igor do you have any idea?

Lenka

0 Kudos

3,026 Views
stevenyu
Contributor III

Hi Lenka,

We use original codebase as below to init sdma. Would you please advise which registers are DMA word and DMA watermark as you mentioned?

If single burst is 8 bits, DMA works fine.

If single burst equals to data length*8bits, the return data are as below (many 00 and ff)

==code to init sdma==

static int spi_imx_sdma_init(struct device *dev, struct spi_imx_data *spi_imx,
struct spi_master *master)
{
int ret;
int fifosize = spi_imx_get_fifosize(spi_imx);

spi_imx->wml = fifosize / 2;

/* Prepare for TX DMA: */
master->dma_tx = dma_request_slave_channel_reason(dev, "tx");
if (IS_ERR(master->dma_tx)) {
ret = PTR_ERR(master->dma_tx);
master->dma_tx = NULL;
if (ret == -EPROBE_DEFER)
return ret;
dev_err(dev, "can't get the TX DMA channel, error %d!\n", ret);
return ret;
}

spi_imx->tx_config.direction = DMA_MEM_TO_DEV;
spi_imx->tx_config.dst_addr = spi_imx->base_phys + MXC_CSPITXDATA;
spi_imx->tx_config.dst_maxburst = (!cspi_quirk(spi_imx, QUIRK_ERR009165) ||
(spi_imx->speed_hz > 40000000)) ? spi_imx->wml : fifosize;
//pr_err(">>>>>>>>>>>>> %s: tx maxburst %d\n", __func__, spi_imx->tx_config.dst_maxburst); // print out 32
/* Prepare for RX : */
master->dma_rx = dma_request_slave_channel_reason(dev, "rx");
if (IS_ERR(master->dma_rx)) {
ret = PTR_ERR(master->dma_rx);
dev_dbg(dev, "can't get the RX DMA channel, error %d\n", ret);
master->dma_rx = NULL;
goto err;
}

spi_imx->rx_config.direction = DMA_DEV_TO_MEM;
spi_imx->rx_config.src_addr = spi_imx->base_phys + MXC_CSPIRXDATA;
spi_imx->rx_config.src_maxburst = spi_imx->wml;
init_completion(&spi_imx->dma_rx_completion);
init_completion(&spi_imx->dma_tx_completion);
master->can_dma = spi_imx_can_dma;
master->max_dma_len = MAX_SDMA_BD_BYTES;
spi_imx->bitbang.master->flags = SPI_MASTER_MUST_RX |
SPI_MASTER_MUST_TX;
//pr_err(">>>>>>>>>>>>> %s: rx maxburst %d, master->max_dma_len %d\n", __func__, spi_imx->rx_config.src_maxburst, master->max_dma_len); // print out 32, 32768

/*
* I have no idea why this is needed, but a dma error
* happens on 1st dma without it
*/
spi_imx->tx_config.dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
ret = dmaengine_slave_config(spi_imx->bitbang.master->dma_tx,
&spi_imx->tx_config);
if (ret) {
dev_err(spi_imx->dev, "error(%d) in TX dma configuration.\n", ret);
goto err;
}
return 0;
err:
spi_imx_sdma_exit(spi_imx);
return ret;
}

==return data==

rxskb 00 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00
rxskb 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
rxskb 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
rxskb 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
rxskb 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
rxskb 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
rxskb 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
rxskb 00 00 00 00 00 00 00 00 00 00 00 e5 ff ff ff ff
rxskb ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
rxskb ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
rxskb ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
rxskb ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
rxskb ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
rxskb ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
rxskb ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff

0 Kudos

3,026 Views
lepol
NXP Employee
NXP Employee

Hi Steven,

From the code above I assume that dst_maxburst and src_maxburst are DMA watermarks and dst_addr_width defines the word size. The SPI burst length should be a multiple of DMA word size and DMA watermark. The DMA will shift out data of size of DMA word size.

Could you please try change your configuration this way?


SPI_CTRL |= (len*8 - 1) << MX51_ECSPI_CTRL_BL_OFFSET;

spi_imx->tx_config.dst_maxburst = len > fifosize ? fifosize : len;
spi_imx->rx_config.src_maxburst = len > fifosize / 2 ? fifosize / 2 : len;

spi_imx->rx_wml = spi_imx->rx_config.src_maxburst - 1;
spi_imx->tx_wml = spi_imx->tx_config.dst_maxburst - 1;

switch (len % 4) {
case 0:
spi_imx->tx_config.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTE; // size of TX shift register
spi_imx->rx_config.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTE; // size of RX shift register
break;
case 2:
spi_imx->tx_config.dst_addr_width = DMA_SLAVE_BUSWIDTH_2_BYTE;
spi_imx->rx_config.src_addr_width = DMA_SLAVE_BUSWIDTH_2_BYTE;
break;
case 1:
spi_imx->tx_config.dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
spi_imx->rx_config.src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
break;
}

spi_imx->rx_config.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTE; // maximal width of data requested from memory on one clock is the size of functional unit bus
spi_imx->tx_config.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTE;

ret = dmaengine_slave_config(spi_imx->bitbang.master->dma_tx,
&spi_imx->tx_config);
ret = dmaengine_slave_config(spi_imx->bitbang.master->dma_rx,
&spi_imx->rx_config);

/* start DMA */

This code I propose with experience with eDMA and LPSPI (I work on i.MX8) but I hope the principle on which both DMA work would be quite similar.

Please, have you checked the output data via oscilloscope? It is useful to know if the problem is caused in receive or transmit operation.

Lenka

0 Kudos

3,026 Views
stevenyu
Contributor III

Hi Lenka,

Thanks your idea. 

We use original code "8 bits per SPI clock" and the DMA return correct data as below. 

===8 bits per SPI clock===

rxskb 01 01 00 00 28 00 00 00 01 00 00 01 13 00 20 00
rxskb 02 00 00 00 0c 00 00 00 24 00 00 00 00 00 00 00
rxskb c8 01 00 00 3b 00 00 00 00 00 00 00 00 00 64 00

....

Then, we switch to "492*8 bits per SPI clock" and use your hint to configure DMA_SLAVE_BUSWIDTH_4_BYTE. Now, we can have some information in DMA return data. However, the endian looks different (01 01 00 00 vs 00 00 01 01). Do you know if NXP DMA support different endian order configuration?

===492*8 bits per SPI clock===
rxskb 00 00 01 01 00 00 00 28 01 00 00 01 00 20 00 13
rxskb 00 00 00 02 00 00 00 0c 00 00 00 24 00 00 00 00
rxskb 00 00 01 c8 00 00 00 3b 00 00 00 00 00 64 00 00
....

Regards,

Steven Yu

0 Kudos

3,026 Views
lepol
NXP Employee
NXP Employee

Hi Steven,

I think that sDMA script has fixed word length and endianess. The way would be, if possible, to change the asm instructions responsible for reading/writing from/to shift registers in the sDMA script.

Lenka

0 Kudos

3,026 Views
stevenyu
Contributor III

Hi Lenka,

In fact, we have seen some description in RM, but we cannot find related register to configure.

47.4.12.1.8.3 Endianness-Burst DMA Unit
Big and Little Endian are supported by the Burst DMA, but data is always stored in MD
in Big Endian.

We have briefly checked the asm files, but cannot identify the position to handle this. To change the asm instructions, do you have any idea ? 

Anyway, thanks for your support.

kernel-source/arch/arm/mach-imx$ ls -al *.S
-rw-r--r-- 1 stephen stephen 20681 Dec 5 18:02 ddr3_freq_imx6.S
-rw-r--r-- 1 stephen stephen 14656 Dec 5 18:02 ddr3_freq_imx6sx.S
-rw-r--r-- 1 stephen stephen 10355 Dec 5 18:02 ddr3_freq_imx7d.S
-rw-r--r-- 1 stephen stephen 947 Dec 5 18:02 headsmp.S
-rw-r--r-- 1 stephen stephen 15691 Dec 5 18:02 imx6sll_low_power_idle.S
-rw-r--r-- 1 stephen stephen 14574 Dec 5 18:02 imx6sl_low_power_idle.S
-rw-r--r-- 1 stephen stephen 17716 Dec 5 18:02 imx6sx_low_power_idle.S
-rw-r--r-- 1 stephen stephen 15293 Dec 5 18:02 imx6ull_low_power_idle.S
-rw-r--r-- 1 stephen stephen 16392 Dec 5 18:02 imx6ul_low_power_idle.S
-rw-r--r-- 1 stephen stephen 15963 Dec 5 18:02 imx7d_low_power_idle.S
-rw-r--r-- 1 stephen stephen 15002 Dec 5 18:02 lpddr2_freq_imx6q.S
-rw-r--r-- 1 stephen stephen 11389 Dec 5 18:02 lpddr2_freq_imx6.S
-rw-r--r-- 1 stephen stephen 8613 Dec 5 18:02 lpddr2_freq_imx6sll.S
-rw-r--r-- 1 stephen stephen 9176 Dec 5 18:02 lpddr2_freq_imx6sx.S
-rw-r--r-- 1 stephen stephen 8247 Dec 5 18:02 lpddr3_freq_imx.S
-rw-r--r-- 1 stephen stephen 2460 Dec 5 18:02 smp_wfe_imx6.S
-rw-r--r-- 1 stephen stephen 2063 Dec 5 18:02 smp_wfe.S
-rw-r--r-- 1 stephen stephen 3010 Dec 5 18:02 ssi-fiq.S
-rw-r--r-- 1 stephen stephen 16765 Dec 5 18:02 suspend-imx6.S
-rw-r--r-- 1 stephen stephen 15222 Dec 5 18:02 suspend-imx7.S

Regards,

Steven Yu

0 Kudos

3,026 Views
lepol
NXP Employee
NXP Employee

Hi Steven,

as I know the sdma scripts are in form of either pure asm code *.asm or binary *.bin or some developers have the binary stored in the byte array in the sdma header files so RAM code. This is a question for scripts developers rather then me. I would recommend you to put a new question on this topic.

Best regards,

Lenka

0 Kudos