Setting ecspi Burst length on i.MX8mp

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

Setting ecspi Burst length on i.MX8mp

1,174 Views
frk
Contributor III

Hello all,

I've got a question regarding the ecspi burst length on a i.MX8mp target.

I'm trying to send bytes over ecspi using spidev and from a certain number of bytes, the chip select toggles every bytes.

Up to 64 bytes, there is only one chip select level change and from 65, CS is toggling on every byte.

Below capture when I send less or equal to 64 bytes :

frk_0-1684253490596.png

Below capture when I send more than 64 bytes :

frk_1-1684253809637.png

 

Regarding the reference manual, we can use the ECSPIx_CONREG :

frk_2-1684254370281.png

 

My question is : where can I set this value in Linux kernel?

I assume that spi-imx.c (Linux 5.10.104) is the right file but I'm wondering where.

 

Best regards,

 

Frederic.

0 Kudos
6 Replies

1,140 Views
ceggers
Contributor V

Hi Frederic,

only a guess from side (I haven't fully checked this):

For short transfers (less than FIFO size), the ECSPI driver always uses PIO transfers, regardless whether you have configured (S)DMA for this ECSPI instance in your device tree (see spi_imx_can_dma()). For larger transfers, SDMA may be used.

For PIO transfers, the driver implements a feature called "dynamic burst". The drivers tries to set the burst length to the number of bytes x number of bits per byte (e.g. 8). This brings a better performance as it avoids having small delays between each byte.

For the SDMA case, the dynamic burst feature is not implemented yet. So for DMA transfers, the ECSPI driver seems to use a fixed burst size (e.g. 8 bit). This introduces small delays and a CS toggle between each byte. You can probably avoid this by configuring CS as a GPIO. The ECSPI driver supports either controlling the CS pin in "ECSPI mode" or "GPIO mode". Actually this depends only on your device tree configuration, you can use the same physical pin for this.

Conclusion: Although using DMA should generally bring a better performance, for the ECSPI case the PIO case may be more suitable for you (due to the "dynamic burst" feature). You have the following options:

  1. Configure the ECSPI in your device tree for using CS in GPIO mode.
  2. Disable SDMA for this ECSPI instance in your device tree
  3. Implement "dynamic burst" for DMA transfers. This would need adaption of the Linux driver and the SDMA firmware.

regards,
Christian

 

0 Kudos

1,146 Views
brian14
NXP TechSupport
NXP TechSupport

Hi @frk

I really appreciate your support in this case @kef2

As @kef2 metioned, the answer is yes in imx-linux/drivers/spi/spi-imx.c you can find the function spi_imx_set_burst_len and you can set the burst for this communication protocol.
In addition to that I suggest using the test for SPI located on imx-test/test/mxc_spi_test/mxc_spi_test1.c.

I hope this information will be helpful.

Have a great day!

0 Kudos

1,149 Views
kef2
Senior Contributor IV
  • My question is : where can I set this value in Linux kernel?
  • I assume that spi-imx.c (Linux 5.10.104) is the right file but I'm wondering where.

Yes, it is annoying when someone renames documentation terms and uses his own in public code without any dictionary provided. At least they could mention it in comments to magic defines:

#define MX51_ECSPI_CTRL_BL_OFFSET 20
#define MX51_ECSPI_CTRL_BL_MASK (0xfff << 20)

spi_imx_set_burst_len() function setups BURST_LENGTH

 

  1. Regarding issue you see. eCSPI provides 64 x 32bits FIFO. Which is enough to transfer message of up to 256 bytes without any intermediate interrupts or DMA involvement.
  2. BURST_LENGTH allows up to 512 bytes messages (4096 bits). It means you can automate leading and trailing CS toggle only for messages, which fit BURST_LENGTH limit. 
  3. As I understand someone decided that automatic CS function is less important than unlimited message length served by DMA and GPIO-CS toggled by CPU. That's perhaps good idea to use eCSPI with flash memories. But why one would use eCSPI for flash when there's dedicated QSPI, which supports not only 4/8bit data per clock, but as well simple 1bit /clock memories?...
  4. Sending messages, which are not multiple of unit32_t, remainder 1-3 bytes have to by pushed to FIFO first, not at the end of transfer. Perhaps someone was to lazy to create SDMA script, which would handle odd length transfer. I think for simplicity they decided to instead send multiple of bits-per-word messages. As you know, SPI on Linux supports 8/16/32 bits per word transfers. That turns to up to 64x8 / 64x16 or 64x32 transfer without DMA and without CS toggle between bits-per-word items. Above that limit you see multiple of 8 / 16 / 32 -bit transfers with CS toggles. 

If you don't need very long SPI messages, then try disabling SPI DMA. 

0 Kudos

687 Views
chen-wust1
Contributor I

Hi

       I have a similar problem now. When the number of transmitted bytes is less than 64, no sdma transmission is used. When the value is greater than 64, sdma is used for transmission.

      When using sdma transfers, the spi clock is not continuous. There will be a 1us delay between each byte, and cs-gpio will remain low during this time. I think this 1us delay will affect its transmission efficiency. Excuse me, is there a way to solve this? It makes the clock continuous during sdma transmission. 

      kernel: 5.4.70

      ECSPI2_CONREG :  0x1F70 10F1

       ECSPI2_CONFIGREG : 0x0000 0100

      

      

0 Kudos

1,074 Views
frk
Contributor III

Thanks for this reply.

I'll try to set use_dma to false and see what's going on.

0 Kudos

1,126 Views
kef2
Senior Contributor IV

BTW latest driver seems being totally incompatible with eCSPI-CS, only GPIO-CS. You can't send even 4 bytes with single eCSPI controlled CS pulse.

Looks like this commit broke it

https://github.com/nxp-imx/linux-imx/commit/63cd96b70f9366f67048fbc07294ce5823001ded

 

And here's simple patch for imx7 (compatible = "fsl,imx51-ecspi") against previous to above commit here to extend PIO limit from 64 bytes to 256, which should be enough for many SPI devices. 

 

diff --git a/spi-imx.c b/spi-imx.c
index 166d6b3..87fab7a 100644
--- a/spi-imx.c
+++ b/spi-imx.c
@@ -24,7 +24,7 @@
 #include <linux/of_device.h>
 #include <linux/property.h>
 
-#include <linux/platform_data/dma-imx.h>
+#include <linux/dma/imx-dma.h>
 
 #define DRIVER_NAME "spi_imx"
 
@@ -240,7 +240,8 @@ static bool spi_imx_can_dma(struct spi_master *master, struct spi_device *spi,
 	if (spi_imx->slave_mode)
 		return false;
 
-	if (transfer->len < spi_imx->devtype_data->fifo_size)
+	/* <= - we can send 256 bytes in PIO mode, not 255 */
+	if (transfer->len <= spi_imx->devtype_data->fifo_size)
 		return false;
 
 	spi_imx->dynamic_burst = 0;
@@ -1035,7 +1036,9 @@ static struct spi_imx_devtype_data imx51_ecspi_devtype_data = {
 	.reset = mx51_ecspi_reset,
 	.setup_wml = mx51_setup_wml,
 	.disable_dma = mx51_disable_dma,
-	.fifo_size = 64,
+/* 64 is amount of FIFO DWORDS. So 256 bytes for PIO data limit
+   and 64 bytes for DMA */
+	.fifo_size = 64*sizeof(uint32_t),
 	.has_dmamode = true,
 	.dynamic_burst = true,
 	.has_slavemode = true,
@@ -1300,7 +1303,7 @@ static int spi_imx_sdma_init(struct device *dev, struct spi_imx_data *spi_imx,
 {
 	int ret;
 
-	spi_imx->wml = spi_imx->devtype_data->fifo_size / 2;
+	spi_imx->wml = spi_imx->devtype_data->fifo_size / (sizeof(uint32_t)*2);
 
 	/* Prepare for TX DMA: */
 	master->dma_tx = dma_request_chan(dev, "tx");
@@ -1375,7 +1378,7 @@ static int spi_imx_dma_transfer(struct spi_imx_data *spi_imx,
 
 	/* Get the right burst length from the last sg to ensure no tail data */
 	bytes_per_word = spi_imx_bytes_per_word(transfer->bits_per_word);
-	for (i = spi_imx->devtype_data->fifo_size / 2; i > 0; i--) {
+	for (i = spi_imx->devtype_data->fifo_size / (sizeof(uint32_t)*2); i > 0; i--) {
 		if (!(sg_dma_len(last_sg) % (i * bytes_per_word)))
 			break;
 	}

 

 

Edit:

In latest code variant dynamic_boorst is reset in spi_imx_can_dma(). It breaks PIO to gaps between each adjacent bits-per-word units. 

Please disregard patch above, there's a counter in the code, which counts FIFO DWORDs written, so above patch is not corrent. Fix for nice no gaps PIO up to 256 bytes is much simpler. In the same spi_imc_can_dma() is should be like this:

   if (transfer->len <= spi_imx->devtype_data->fifo_size * sizeof(u32)) {
         // spi_imx->dynamic_burst = 0;
         return false;
   }

 

 

 

0 Kudos