SPI slave in L4T 32.2.1

Hi,

I’m trying to evaluate SPI0 in slave mode and when i perform the read, the read just blocks and the ioctl doesnt get finished.I am configuring one nano device as Master and an another as slave and use SPI0 in both of them. I have tested loopback mode in SPI0 in both devices. I am providing the dtb entries for SPI below,

Slave

spi@7000d400 {
    compatible = "nvidia,tegra210-spi-slave";
    reg = <0x00000000 0x00000003 0x0000003b 0x00000545>;
    interrupts = <0x00000000 0x00000008 0x00000003>;
    iommus = <0x0000002b 0x0000001c>;
    #address-cells = <0x00000001>;
    #size-cells = <0x00000000>;
    dmas = <0x0000004c 0x00000003 0x78000000 0x00000003>;
    dma-names = "rx", "tx";
    nvidia,clock-always-on;
    nvidia,clk-parents = "pll_p", "clk_m";
    clocks = <0x00000021 0x00000021 0x000001ba 0x6b5f6d00 0x00000021 0x00000219>;
    clock-names = "spi", "pll_p", "clk_m";
    resets = <0x00000021 0x00000219>;
    reset-names = "spi";
    status = "okay";
    num-cs = <0x00000001>;
    cs-gpios = <0x00000056 0x00000008 0x00000003>;
    nvidia,dma-request-selector = <0x0000004c 0x00000113>;
    linux,phandle = <0x000000fd>;
    phandle = <0x000000fd>;
    prod-settings {
        #prod-cells = <0x00000003>;
        prod {
            prod = <0x00000004 0x00000001 0x00000000>;
        };
        prod_c_flash {
            status = "disabled";
            prod = <0x00000004 0x00000001 0x00000003>;
        };
        prod_c_loop {
            status = "disabled";
            prod = <0x00000004 0x00000002 0x00000003>;
        };
    };
    spi0_0 {
        #address-cells = <0x00000001>;
        #size-cells = <0x00000000>;
        compatible = "spidev";
        status = "okay";
        reg = <0x00000000>;
        spi-max-frequency = <0x03dfd240>;
        controller-data {
            nvidia,cs-setup-clk-count = <0x0000001e>;
            nvidia,cs-hold-clk-count = <0x0000001e>;
            nvidia,rx-clk-tap-delay = <0x0000001f>;
            nvidia,tx-clk-tap-delay = <0x00000000>;
        };
    };
};

Master:

 spi@7000d400 {
    compatible = "nvidia,tegra210-spi";
    reg = <0x00000000 0x00000003 0x0000003b 0x00000545>;
    interrupts = <0x00000000 0x00000008 0x00000003>;
    iommus = <0x0000002b 0x0000001c>;
    #address-cells = <0x00000001>;
    #size-cells = <0x00000000>;
    dmas = <0x0000004c 0x00000003 0x78000000 0x00000003>;
    dma-names = "rx", "tx";
    nvidia,clk-parents = "pll_p", "clk_m";
    clocks = <0x00000021 0x00000021 0x000001ba 0x6b5f6d00 0x00000021 0x00000219>;
    clock-names = "spi", "pll_p", "clk_m";
    resets = <0x00000021 0x00000219>;
    reset-names = "spi";
    status = "okay";
    num-cs = <0x00000001>;
    cs-gpios = <0x00000056 0x00000008 0x00000003>;
    nvidia,dma-request-selector = <0x0000004c 0x00000113>;
    linux,phandle = <0x000000fd>;
    phandle = <0x000000fd>;
    prod-settings {
        #prod-cells = <0x00000003>;
        prod {
            prod = <0x00000004 0x00000001 0x00000000>;
        };
        prod_c_flash {
            status = "disabled";
            prod = <0x00000004 0x00000001 0x00000003>;
        };
        prod_c_loop {
            status = "disabled";
            prod = <0x00000004 0x00000002 0x00000003>;
        };
    };
    spi0_0 {
        #address-cells = <0x00000001>;
        #size-cells = <0x00000000>;
        compatible = "spidev";
        status = "okay";
        reg = <0x00000000>;
        spi-max-frequency = <0x03dfd240>;
        controller-data {
            nvidia,cs-setup-clk-count = <0x0000001e>;
            nvidia,cs-hold-clk-count = <0x0000001e>;
            nvidia,rx-clk-tap-delay = <0x0000001f>;
            nvidia,tx-clk-tap-delay = <0x00000000>;
        };
    };
};

Can you share the code used for transferring data?
Bits per word, data block size, etc.
The pinmux device tree would also help. You have to make sure that on the slave device, the pins are all configured the opposite of the master. For instance, MOSI on the slave has to be configured for input with no pull up/down, etc.

Could you remove the “cs-gpios = …” and set those pull to TEGRA_PIN_PULL_NONE

		spi2_mosi_pb4 {
			nvidia,pins = "spi2_mosi_pb4";
			nvidia,function = "spi2";
			nvidia,pull = <TEGRA_PIN_PULL_NONE>;
			nvidia,tristate = <TEGRA_PIN_DISABLE>;
			nvidia,enable-input = <TEGRA_PIN_ENABLE>;
		};

		spi2_miso_pb5 {
			nvidia,pins = "spi2_miso_pb5";
			nvidia,function = "spi2";
			nvidia,pull = <TEGRA_PIN_PULL_NONE>;
			nvidia,tristate = <TEGRA_PIN_DISABLE>;
			nvidia,enable-input = <TEGRA_PIN_ENABLE>;
		};

		spi2_sck_pb6 {
			nvidia,pins = "spi2_sck_pb6";
			nvidia,function = "spi2";
			nvidia,pull = <TEGRA_PIN_PULL_NONE>;
			nvidia,tristate = <TEGRA_PIN_DISABLE>;
			nvidia,enable-input = <TEGRA_PIN_ENABLE>;
		};

		spi2_cs0_pb7 {
			nvidia,pins = "spi2_cs0_pb7";
			nvidia,function = "spi2";
			nvidia,pull = <TEGRA_PIN_PULL_NONE>;
			nvidia,tristate = <TEGRA_PIN_DISABLE>;
			nvidia,enable-input = <TEGRA_PIN_ENABLE>;
		};

		spi2_cs1_pdd0 {
			nvidia,pins = "spi2_cs1_pdd0";
			nvidia,function = "spi2";
			nvidia,pull = <TEGRA_PIN_PULL_NONE>;
			nvidia,tristate = <TEGRA_PIN_DISABLE>;
			nvidia,enable-input = <TEGRA_PIN_ENABLE>;
1 Like

@ShaneCCC Slightly off topic but is anyone actively working on the driver to fix up the issues that have been reported over the last 6 months or so? Most of them are around the controller-data timings.

Yes, we are still working on it, however due to the covid-19 our office are closed the progress could be slow. Sorry for that.

@ShaneCCC No need to apologize! It’s a tough time right now. I just wanted to make sure it hadn’t gotten lost.

Thanks for the understanding, we have file internal bug to trace this shouldn’t be lost it.

OK Cool. I should have phrased my question a little better, sorry. Be Safe!

Hi, Thanks for the help @ShaneCCC and @gtj . I changed the pull entry to TEGRA_PIN_PULL_NONE and my Nano SPI slave was able to detect that data is sent from the master but the received data seems to be not what i had sent.

I use the following program to read the SPI data

#include <stdint.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <linux/ioctl.h>
#include <sys/stat.h>
#include <linux/types.h>
#include <linux/spi/spidev.h>

int main() {
    int block_size = 10;
    uint32_t mode = 0;
    uint8_t bits = 8;
    uint32_t speed = 500000;
    uint8_t rx[block_size];
    int ret;
    int fd;
    int i;
            printf("before read\n");
    fd = open("/dev/spidev0.0", O_RDONLY);

    // Example mode. Just use the modes you need if any.
    // mode = SPI_CPHA | SPI_CPOL | SPI_LSB_FIRST | SPI_LSB_FIRST | SPI_NO_CCS;
    ret = ioctl(fd, SPI_IOC_WR_MODE32, &mode);
    ret = ioctl(fd, SPI_IOC_WR_BITS_PER_WORD, &bits);
    ret = ioctl(fd, SPI_IOC_WR_MAX_SPEED_HZ, &speed);
    printf("before read\n");
    ret = read(fd, rx, block_size);
    printf("after read\n");
for(i=0;i<block_size;i++){
        if(i%10 == 0)
        printf("\n");
    else
        printf("0x%2x ", rx[i]);
}
    return 0;

}

When i run the program, initially the code blocks and then when i send the SPI data i get some data but they are the ones that i’m sending. I get the following message in my dmesg.

[73559.254036] spi_master spi0: transferred[0] != requested[10]
[73559.260031] spi_master spi0:   CMD[03f01027]:  Sl M0 CS0 [HHHH] MSB MSb Rx  Pa 8b TRANS[00ff0000]:BSY   I:255 B:0
[73559.260031]  FIFO[00400005]:RxF:0 TxE:64 Err[] RxSTA[E] TxSTA[E]DMA[00000000]:    RxTr:0 TxTr:0 B:9
[73559.279345] spi_master spi0: cpu-xfer-err [status:80400005]
[73559.285112] spi_master spi0:   CMD[03f01027]:  Sl M0 CS0 [HHHH] MSB MSb Rx  Pa 8b TRANS[00ff0000]:BSY I:255 B:0
[73559.285112]  FIFO[00400005]:RxF:0 TxE:64 Err[] RxSTA[E] TxSTA[E]DMA[00000000]:    RxTr:0 TxTr:0 B:9
[73559.304434] spi_master spi0: failed to transfer one message from queue

I have provided the current spi entry and pin mux details of the SPI1 pins

spi@7000d400 {
    compatible = "nvidia,tegra210-spi-slave";
    reg = <0x00000000 0x00000003 0x0000003b 0x00000545>;
    interrupts = <0x00000000 0x00000008 0x00000003>;
    iommus = <0x0000002b 0x0000001c>;
    #address-cells = <0x00000001>;
    #size-cells = <0x00000000>;
    dmas = <0x0000004c 0x00000003 0x78000000 0x00000003>;
    dma-names = "rx", "tx";
    nvidia,clock-always-on;
    nvidia,clk-parents = "pll_p", "clk_m";
    clocks = <0x00000021 0x00000021 0x000001ba 0x6b5f6d00 0x00000021 0x00000219>;
    clock-names = "spi", "pll_p", "clk_m";
    resets = <0x00000021 0x00000219>;
    reset-names = "spi";
    status = "okay";
    nvidia,dma-request-selector = <0x0000004c 0x00000113>;
    linux,phandle = <0x000000fd>;
    phandle = <0x000000fd>;
    prod-settings {
        #prod-cells = <0x00000003>;
        prod {
            prod = <0x00000004 0x00000001 0x00000000>;
        };
        prod_c_flash {
            status = "disabled";
            prod = <0x00000004 0x00000001 0x00000003>;
        };
        prod_c_loop {
            status = "disabled";
            prod = <0x00000004 0x00000002 0x00000003>;
        };
    };
    spi0_0 {
        #address-cells = <0x00000001>;
        #size-cells = <0x00000000>;
        compatible = "spidev";
        status = "okay";
        reg = <0x00000000>;
        spi-max-frequency = <0x03dfd240>;
        controller-data {
            nvidia,cs-setup-clk-count = <0x0000001e>;
            nvidia,cs-hold-clk-count = <0x0000001e>;
            nvidia,rx-clk-tap-delay = <0x0000001f>;
            nvidia,tx-clk-tap-delay = <0x00000000>;
        };
    };
};
spi1_mosi_pc0 {
			nvidia,pins = "spi1_mosi_pc0";
			nvidia,function = "spi1";
			nvidia,pull = <TEGRA_PIN_PULL_NONE>;
			nvidia,tristate = <TEGRA_PIN_DISABLE>;
			nvidia,enable-input = <TEGRA_PIN_ENABLE>;
		};

		spi1_miso_pc1 {
			nvidia,pins = "spi1_miso_pc1";
			nvidia,function = "spi1";
			nvidia,pull = <TEGRA_PIN_PULL_NONE>;
			nvidia,tristate = <TEGRA_PIN_DISABLE>;
			nvidia,enable-input = <TEGRA_PIN_ENABLE>;
		};

		spi1_sck_pc2 {
			nvidia,pins = "spi1_sck_pc2";
			nvidia,function = "spi1";
			nvidia,pull = <TEGRA_PIN_PULL_NONE>;
			nvidia,tristate = <TEGRA_PIN_DISABLE>;
			nvidia,enable-input = <TEGRA_PIN_ENABLE>;
		};

The SPI master is configured with these parameters

  1. 500Khz clock
  2. SPI Mode 0
  3. MSB First
  4. 8bit data size

I’m sending two bytes of data (0xFF,0xFF) but the data i receive is different. Looking at the dmesg and dts could you decipher where the root cause of issue could be? Thanks for your support even at such times.

It seems that the error messages in dmesg are because I had provided the wrong block size. After providing the proper block size i was able to read the data. After re-checking the connection / clocks , i was getting transferred data as 1 instead of 0 as i had mentioned before. I was able to read data after changing the block size to 1.

@ShaneCCC @gtj Hi, I am trying to transfer data from an SPI master(MCU) to SPI slave(Nano) but I can’t transfer more than 1 block. If I try to set the block size as 3 (which is the number of bytes I m sending), I’m getting an error. How does Nano perceive that data has been read and its size? Due to lockdown I have to work from home and i dont have access to a logic analyser. Is there something in the SPI registers that could help me?
How does one reset the SPI from userspace? since after i get the error, the subsequent SPI tranfers are showing invalid data. I am using the same SPI configuration as i had mentioned before.

Can you provide more details about the test is running ? I would like to know whether is using the spidev or using a dedicated client driver for the slave( i.e. Nano in this case).

How does Nano perceive that data has been read and its size.

One way to check is by reading the SPI_FIFO_STATUS_REGISTER and SPI_TRANSFER_STATUS_REGISTERS.

How does one reset the SPI from user space?

There is no support to reset SPI from user space using SPIDEV.