This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

AM4378: SPI driver stalls with DMA enabled

Part Number: AM4378
Other Parts Discussed in Thread: TMDSEVM437X

Hello,

I'm using the SPI1 interface on a TMDSEVM437X evaluation board.

It all works as expected with fewer than 160 bytes sent in a single block.  In this case the driver uses PIO mode.

With 160 bytes or more, the driver uses DMA mode, at least that is the intention.  However CS0 goes low, SCLK stays low, D1 (MOSI) stays high, and the driver hangs in this state.

After much reading and experimentation it's still unclear how to enable the magic of DMA.  Hopefully someone can put me on the right track.

Edit: updated detail in follow-up post.

I can see that the driver spins forever on the txrxdone flag:

static unsigned omap2_mcspi_rx_dma(struct spi_device *spi, struct
    spi_transfer *xfer, struct dma_slave_config cfg, unsigned es)
{
    /* ... */

    ret = mcspi_wait_for_completion(mcspi, &mcspi->txrxdone);

    /* ... */
}

Below are some plots demonstrating the issue and the commands used to test:

root@am437x-evm:~# spi-pipe -d /dev/spidev1.0 -m 0 -s 100000 -n 1 -b 8 < /dev/urandom > /dev/null
root@am437x-evm:~# spi-pipe -d /dev/spidev1.0 -m 0 -s 100000 -n 1 -b 159 < /dev/urandom > /dev/null
root@am437x-evm:~# spi-pipe -d /dev/spidev1.0 -m 0 -s 100000 -n 1 -b 160 < /dev/urandom > /dev/null <-- command hangs

8 bytes

159 bytes

160 bytes

For the avoidance of doubt, with the two lines commented from the dts, i.e. DMA disabled, it's possible to transfer up to 4096 bytes in a single block with no apparent issue.

4096 bytes

  • I've updated the dts file having found some relevant examples.  I'm using am437x-gp-evm.dts, which targets the TMDSEVM437X board in use, with the following changes.  Sadly the pin behaviour is precisely as previously described, so whilst it may be more correct, DMA still isn't working.

    --- arch/arm/boot/dts/am437x-gp-evm.dts.orig	2022-12-17 16:26:07.896847833 +0000
    +++ arch/arm/boot/dts/am437x-gp-evm.dts	2022-12-17 17:58:24.308768199 +0000
    @@ -526,10 +526,6 @@
     			AM4372_IOPAD(0x868, PIN_INPUT_PULLDOWN | MUX_MODE7)
     			AM4372_IOPAD(0x86c, PIN_INPUT_PULLDOWN | MUX_MODE7)
     			AM4372_IOPAD(0x950, PIN_INPUT_PULLDOWN | MUX_MODE7)
    -			AM4372_IOPAD(0x990, PIN_INPUT_PULLDOWN | MUX_MODE7)
    -			AM4372_IOPAD(0x994, PIN_INPUT_PULLDOWN | MUX_MODE7)
    -			AM4372_IOPAD(0x998, PIN_INPUT_PULLDOWN | MUX_MODE7)
    -			AM4372_IOPAD(0x99c, PIN_INPUT_PULLDOWN | MUX_MODE7)
     			AM4372_IOPAD(0x9a0, PIN_INPUT_PULLDOWN | MUX_MODE7)
     			AM4372_IOPAD(0xa3c, PIN_INPUT | PULL_DISABLE | MUX_MODE7)
     			AM4372_IOPAD(0xa40, PIN_INPUT_PULLDOWN | MUX_MODE7)
    @@ -613,6 +609,24 @@
     			AM4372_IOPAD(0x954, PIN_INPUT_PULLDOWN | MUX_MODE0)
     		>;
     	};
    +
    +        spi1_pins_default: spi1_pins_default { /* pin configuration for SPI1-master */
    +                pinctrl-single,pins = <
    +                        AM4372_IOPAD(0x990, PIN_INPUT        | MUX_MODE3) /* (N24) SPI1_SCLK */
    +                        AM4372_IOPAD(0x994, PIN_INPUT_PULLUP | MUX_MODE3) /* (N22) SPI1_D0 */
    +                        AM4372_IOPAD(0x998, PIN_OUTPUT       | MUX_MODE3) /* (H23) SPI1_D1 */
    +                        AM4372_IOPAD(0x99c, PIN_OUTPUT       | MUX_MODE3) /* (M24) SPI1_CS0 */
    +                >;
    +        };
    +
    +        spi1_pins_sleep: spi1_pins_sleep {
    +                pinctrl-single,pins = <
    +                        AM4372_IOPAD(0x990, PIN_INPUT_PULLUP | MUX_MODE3) /* (N24) SPI1_SCLK */
    +                        AM4372_IOPAD(0x994, PIN_INPUT_PULLUP | MUX_MODE3) /* (N22) SPI1_D0 */
    +                        AM4372_IOPAD(0x998, PIN_INPUT_PULLUP | MUX_MODE3) /* (H23) SPI1_D1 */
    +                        AM4372_IOPAD(0x99c, PIN_INPUT_PULLUP | MUX_MODE3) /* (M24) SPI1_CS0 */
    +                >;
    +        };
     };
     
     &uart0 {
    @@ -1123,3 +1137,19 @@
     	ti,set-io-isolation;
     	ti,scale-data-fw = "am43x-evm-scale-data.bin";
     };
    +
    +&spi1 {
    +        status = "okay";
    +        pinctrl-names = "default", "sleep";
    +        pinctrl-0 = <&spi1_pins_default>;
    +        pinctrl-1 = <&spi1_pins_sleep>;
    +
    +        dmas = <&edma 16 0 &edma 17 0>;
    +        dma-names = "tx0", "rx0";
    +
    +        spidev@0 {        // using CONFIG_SPI_SPIDEV=y
    +                compatible="linux,spidev";
    +                spi-max-frequency = <12000000>;
    +                reg = <0>;
    +        };
    +};
    

    By instrumenting the driver code, spi-omap2-mcspi.c, I can see that it writes the following register values ...

    MODULCTRL = 0x00000001
    WAKEUPENABLE = 0x00000001
    CHCTRL0 = 0x00000000
    CHCONF0 = 0x200103cc
    CHCONF0 = 0x200103cc
    CHCTRL0 = 0x00000000
    CHCONF0 = 0x200103cc
    CHCONF0 = 0x200103cc
    CHCTRL0 = 0x00000000
    CHCONF0 = 0x200103cc
    CHCONF0 = 0x200103cc
    CHCTRL0 = 0x00001d00
    CHCONF0 = 0x200103fc
    CHCONF0 = 0x200103fc
    CHCONF0 = 0x201103fc
    CHCTRL0 = 0x00001d00
    CHCTRL0 = 0x00001d00
    CHCONF0 = 0x201103fc
    CHCONF0 = 0x201103fc
    XFERLEVEL = 0x00a00000
    CHCONF0 = 0x381103fc
    CHCTRL0 = 0x00001d01
    IRQENABLE = 0x00020000
    CHCONF0 = 0x381143fc
    CHCONF0 = 0x3811c3fc
    

    ... before spinning forever on the txrxdone flag:

    static unsigned omap2_mcspi_rx_dma(struct spi_device *spi, struct
        spi_transfer *xfer, struct dma_slave_config cfg, unsigned es)
    {
        /* ... */
    
        ret = mcspi_wait_for_completion(mcspi, &mcspi->txrxdone);
    
        /* ... */
    }

  • Hi Ted,

    I noticed this case has been open for a while already, please let me know if this still needs attention.

    Regards, Andreas