SPI chip select behaviour

Hello!
I have a problem with the Kernel customization regarding SPI. The existing hardware connects a FRAM and a TPM module on one SPI, using CS0 and CS1. It is running fine with a Jetson Nano already, the problem with the Xavier NX module is a different behaviour of the hardware controlled chip select signal (CS0). The following description applies to the FRAM, the TPM is no problem is both configurations.
The SPI is controlled by the “ioctl” function, making use of the option “cs_change”. The FRAM needs the Opcode, the 24bit address followed by memory data. The CS must be held low from Opcode till the end of the data stream. Following code is running fine on the Nano:

  uint8_t tx[4] = { OPCODE_WRITE };
  tx[1] = (uint8_t) (address >> 16) & 0xFF;
  tx[2] = (uint8_t) (address >> 8) & 0xFF;
  tx[3] = (uint8_t) (address & 0xFF);

  struct spi_ioc_transfer tr = { .tx_buf = (unsigned long) tx, .rx_buf = 0,
      .len = 4, .delay_usecs = delay, .speed_hz = 0, .bits_per_word = 0,
      .cs_change = 0, };

  struct spi_ioc_transfer tr2 = { .tx_buf = (unsigned long) send, .rx_buf = 0,
      .len = len, .delay_usecs = delay, .speed_hz = 0, .bits_per_word = 0,
      .cs_change = 1, };

  ret = ioctl(fd, SPI_IOC_MESSAGE(1), &tr);
  if (ret < 0)
  {
    spi_fram_debug_out("can't send spi message");
  }

  ret = ioctl(fd, SPI_IOC_MESSAGE(1), &tr2);

The cs_change option works as expected on the Nano but not on the Xavier NX. I believe the problem arises from the setup in the DTS files. These are attached to this topic.

To illustrate the problem, this is the capture in the Nano setup:

and this is the Xavier setup:

The marked CS high happens between the 4 byte Opcode+address and the data section.

Any hints to the DTS configuration for this problem?

tegra194-p3668-nb_xav_nx.dts (246.2 KB)

tegra210-nb_nano.dts (326.2 KB)

Try to add the spi*_xxx to the dts

                header-40pin-pinmux {
                        phandle = <0x179>;
                        linux,phandle = <0x179>;

                        pin37 {
                                nvidia,lpdr = <0x0>;
                                nvidia,io-high-voltage = <0x0>;
                                nvidia,enable-input = <0x1>;
                                nvidia,tristate = <0x0>;
                                nvidia,pull = <0x1>;
                                nvidia,pins = "spi3_mosi_py2";
                                nvidia,function = "spi3";
                        };

                        pin28 {
                                nvidia,lpdr = <0x1>;
                                nvidia,io-high-voltage = <0x1>;
                                nvidia,enable-input = <0x1>;
                                nvidia,tristate = <0x0>;
                                nvidia,pull = <0x0>;
                                nvidia,pins = "gen2_i2c_scl_pcc7";
                                nvidia,function = "i2c2";
                        };

                        pin27 {
                                nvidia,lpdr = <0x1>;
                                nvidia,io-high-voltage = <0x1>;
                                nvidia,enable-input = <0x1>;
                                nvidia,tristate = <0x0>;
                                nvidia,pull = <0x0>;
                                nvidia,pins = "gen2_i2c_sda_pdd0";
                                nvidia,function = "i2c2";
                        };

                        pin26 {
                                nvidia,lpdr = <0x0>;
                                nvidia,enable-input = <0x1>;
                                nvidia,tristate = <0x0>;
                                nvidia,pull = <0x2>;
                                nvidia,pins = "spi1_cs1_pz7";
                                nvidia,function = "spi1";
                        };

                        pin24 {
                                nvidia,lpdr = <0x0>;
                                nvidia,enable-input = <0x1>;
                                nvidia,tristate = <0x0>;
                                nvidia,pull = <0x2>;
                                nvidia,pins = "spi1_cs0_pz6";
                                nvidia,function = "spi1";
                        };

                        pin23 {
                                nvidia,lpdr = <0x0>;
                                nvidia,enable-input = <0x1>;
                                nvidia,tristate = <0x0>;
                                nvidia,pull = <0x1>;
                                nvidia,pins = "spi1_sck_pz3";
                                nvidia,function = "spi1";
                        };

                        pin22 {
                                nvidia,lpdr = <0x0>;
                                nvidia,io-high-voltage = <0x0>;
                                nvidia,enable-input = <0x1>;
                                nvidia,tristate = <0x0>;
                                nvidia,pull = <0x1>;
                                nvidia,pins = "spi3_miso_py1";
                                nvidia,function = "spi3";
                        };

                        pin21 {
                                nvidia,lpdr = <0x0>;
                                nvidia,enable-input = <0x1>;
                                nvidia,tristate = <0x0>;
                                nvidia,pull = <0x1>;
                                nvidia,pins = "spi1_miso_pz4";
                                nvidia,function = "spi1";
                        };

                        pin19 {
                                nvidia,lpdr = <0x0>;
                                nvidia,enable-input = <0x1>;
                                nvidia,tristate = <0x0>;
                                nvidia,pull = <0x1>;
                                nvidia,pins = "spi1_mosi_pz5";
                                nvidia,function = "spi1";
                        };

                        pin18 {
                                nvidia,lpdr = <0x0>;
                                nvidia,io-high-voltage = <0x0>;
                                nvidia,enable-input = <0x1>;
                                nvidia,tristate = <0x0>;
                                nvidia,pull = <0x2>;
                                nvidia,pins = "spi3_cs0_py3";
                                nvidia,function = "spi3";
                        };

                        pin16 {
                                nvidia,lpdr = <0x0>;
                                nvidia,io-high-voltage = <0x0>;
                                nvidia,enable-input = <0x1>;
                                nvidia,tristate = <0x0>;
                                nvidia,pull = <0x2>;
                                nvidia,pins = "spi3_cs1_py4";
                                nvidia,function = "spi3";
                        };

                        pin13 {
                                nvidia,lpdr = <0x0>;
                                nvidia,io-high-voltage = <0x0>;
                                nvidia,enable-input = <0x1>;
                                nvidia,tristate = <0x0>;
                                nvidia,pull = <0x1>;
                                nvidia,pins = "spi3_sck_py0";
                                nvidia,function = "spi3";
                        };

                        pin10 {
                                nvidia,lpdr = <0x0>;
                                nvidia,io-high-voltage = <0x0>;
                                nvidia,enable-input = <0x1>;
                                nvidia,tristate = <0x1>;
                                nvidia,pull = <0x2>;
                                nvidia,pins = "uart1_rx_pr3";
                                nvidia,function = "uarta";
                        };

                        pin8 {
                                nvidia,lpdr = <0x0>;
                                nvidia,io-high-voltage = <0x0>;
                                nvidia,enable-input = <0x0>;
                                nvidia,tristate = <0x0>;
                                nvidia,pull = <0x0>;
                                nvidia,pins = "uart1_tx_pr2";
                                nvidia,function = "uarta";
                        };
                };

Add the spi to the dts with the 40-pin-hedaer changed nothing.
We use the spidev0.0 to communicate with the FRAM.

I think there is a mistake in section spi@3210000, but we don’t now where the mistake is:

spi@3210000 {
		compatible = "nvidia,tegra186-spi";
		reg = <0x0 0x3210000 0x0 0x10000>;
		interrupts = <0x0 0x24 0x4>;
		#address-cells = <0x1>;
		#size-cells = <0x0>;
		iommus = <0x2 0x20>;
		dma-coherent;
		dmas = <0x1b 0xf 0x1b 0xf>;
		dma-names = "rx", "tx";
		nvidia,clk-parents = "pll_p", "clk_m";
		clocks = <0x4 0x87 0x4 0x66 0x4 0xe>;
		clock-names = "spi", "pll_p", "clk_m";
		resets = <0x5 0x5b>;
		reset-names = "spi";
		status = "okay";
		cs-gpios = <0x0 0x13 0xcf 0x0>;
		linux,phandle = <0xf6>;
		phandle = <0xf6>;

		spi@0 {
			compatible = "spidev";
			reg = <0x0>;
			spi-max-frequency = <0x17d7840>;

			controller-data {
				nvidia,enable-hw-based-cs;
				nvidia,rx-clk-tap-delay = <0x7>;
			};
		};

		tpm_tis_spi@1 {
			compatible = "tcg,tpm_tis_spi";
			reg = <0x1>;
			spi-max-frequency = <0x989680>;

			controller-data {
				nvidia,rx-clk-tap-delay = <0x7>;
			};
		};
	};

The Nano runs with this configuration:

	spi@7000d400 {
		compatible = "nvidia,tegra210-spi";
		reg = <0x0 0x7000d400 0x0 0x200>;
		interrupts = <0x0 0x3b 0x4>;
		iommus = <0x30 0xe>;
		#address-cells = <0x1>;
		#size-cells = <0x0>;
		dmas = <0x51 0xf 0x51 0xf>;
		dma-names = "rx", "tx";
		nvidia,clk-parents = "pll_p", "clk_m";
		clocks = <0x26 0x29 0x26 0xf3 0x26 0xe9>;
		clock-names = "spi", "pll_p", "clk_m";
		resets = <0x26 0x29>;
		reset-names = "spi";
		status = "okay";
		cs-gpios = <0x0 0x5b 0x14 0x0>;
		linux,phandle = <0x110>;
		phandle = <0x110>;

		prod-settings {
			#prod-cells = <0x3>;

			prod {
				prod = <0x4 0xfff 0x0>;
			};

			prod_c_flash {
				status = "disabled";
				prod = <0x4 0x3f 0x7>;
			};

			prod_c_loop {
				status = "disabled";
				prod = <0x4 0xfff 0x44b>;
			};
		};

		spi@0 {
			compatible = "spidev";
			reg = <0x0>;
			spi-max-frequency = <0x1f78a40>;

			controller-data {
				nvidia,enable-hw-based-cs;
				nvidia,rx-clk-tap-delay = <0x7>;
			};
		};

		tpm_tis_spi@1 {
			compatible = "tcg,tpm_tis_spi";
			reg = <0x1>;
			spi-max-frequency = <0x989680>;

			controller-data {
				nvidia,rx-clk-tap-delay = <0x7>;
			};
		};
	};

Any idea where the mistake is?

Dear Shane,
Thanks for your quick answer! To clear things up a bit, ADV-LUT is my colleague, he answered this thread while I had a day off. He tried the suggested solution already, unfortunately with no success. We do not use the 40pin header as we have our own hardware. But the SPI is the same and one component on this bus (the TPM) is running fine already. So is your suggestion a declaration of the 40pin Header or will it change anything in the SPI hardware behaviour?

Just want to confirm the pinmux configure is correct.
Do you have verify the configure by the loopback test?

Tested the SPI by loopback test with success.

Spidev_test.txt (336 Bytes)

Is there any other suggestion on this topic? The loopback test was fine. Maybe I have to point out that there are two SPI components on the same bus - a TPM module and a FRAM. The TPM is running fine on both platforms, the Nano and the Xavier NX. The FRAM is running on the Nano but not on the Xavier NX. The driving software is absolutely the same. So I am not sure what problem the suggested loopback test could have identified since the CS lines are not involved.

It is all about the extra “glitch” on the FRAM-CS as seen above. Basically the hardware CS does work but the option “cs_change = 0” before the ioctl is ignored on the Xavier.

Meanwhile we digged into this a little bit deeper but still no solution. We already believe this behaviour has nothing to do with the DTS configuration, since the hardware control of the CS pin basically works. The option “CS held between packets” is a bit in the SPI hardware control register. I already found the “spi-tegra114.c” kernel driver module in the source, where this option is handled. But there are so many dependencies to other related driver parts that I cannot trace down exactly to the point, where this bit is set. Obviously the Nano and the Xavier NX both use the same “spi-tegra114.c” part. Can anyone confirm this?

I found similar SPI issues in this forum, where errors in the kernel source where found and patched. So my hope is that this “CS hold between packets” can be solved by patch.

Or are we heading the wrong direction?

Have a reference to this topic to check if your code base include the patch for it.

Thanks for the quick reply! We will check this during the day.

Unfortunately the patch from you link made no difference.

Both, the Nano and the Xavier NX are using the same spi-tegra114.c source. What I really do not understand is the fact, that Nano runs fine on this code base but the Xavier NX not. As far as I can see there are no compiler switches for the different platforms.
Any other hints?

Could you change the compatible to "nvidia,tegra194-spi " for NX to try.

Many thanks for coming back to this issue! We give it a try today or tomorrow.

Bad news, the suggested change of the compatible made no difference. Unfortunately I had to remove the logic analyzer from the prototype board meanwhile. Tomorrow we will set up the logic analyzer again and will update this topic with new logic analyzer results using the tegra194-spi driver.

I reinstalled the Logic Analyzer, please see the attached picture. As already suspected the tegra194-spi makes no difference.