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.