Jetson Nano Devkit with Letstrust TPM2 / infineon slb9672

So, I’m trying to install a Letstrust TPM Module on the Jetson Nano Development kit with an ao2 chip.

I’m not an electrical engineer and am working the first time with spi, device trees and gpio pins.

I connected the tpm with the pins 17-26 (Schema) and am powering the nano with via the micro usb port.

Using the Jetson Hacks buildKernelAndModule scripts, I modified the kernel to edit the config using this script

#!/bin/bash

SOURCE_TARGET="/usr/src/"
KERNEL_RELEASE=$( uname -r | cut -d. -f1-2)
KERNEL_URI=$SOURCE_TARGET"kernel/kernel-"$KERNEL_RELEASE
if [ ! -d "$KERNEL_URI" ] ; then
  echo "Cannot find kernel source in $SOURCE_TARGET."
  echo "You will need to install the kernel source before proceeding."
  exit 1
fi

cd "$KERNEL_URI"

sudo bash scripts/config --file .config \
	--set-val CONFIG_HW_RANDOM_TPM m \
	--set-val CONFIG_TCG_TPM m \
	--set-val CONFIG_TCG_TIS_CORE m \
	--set-val CONFIG_TCG_TIS_SPI m \
	--set-val CONFIG_SECURITYFS y

echo "Config edit complete"

Build the kernel

./makeKernel.sh

Build the required modules

./makeModules.sh

and applied the new Image

./copyImage.sh

and rebooted the nano

Using

cat /proc/config.gz | gunzip | grep TCG
CONFIG_TCG_TPM=m
CONFIG_TCG_TIS_CORE=m
CONFIG_TCG_TIS_SPI=m

and

cat /proc/config.gz | gunzip | grep TPM
CONFIG_HW_RANDOM_TPM=m
CONFIG_TCG_TPM=m

I was able to verify that the config has been applied.

I also added the modules to /etc/modules so they can load at boot time

tpm-rng
tpm_tis_spi
tpm_tis_core
tpm

I already dug through countless forum topics of people who are trying to achieve something similar, and scrambled this dts file together

/dts-v1/;
/plugin/;

#include <dt-bindings/pinctrl/pinctrl-tegra.h>
#include <dt-bindings/gpio/tegra-gpio.h>

/ {
	compatible = "nvidia,p3449-0000-a02+p3448-0000-a02", "nvidia,jetson-nano", "nvidia,tegra210";
	overlay-name = "Letstrust TPM2 slb9670";
	jetson-header-name = "Jetson 40pin Header";

	fragment@0 {
		target-path = "/spi@7000d400";

		__overlay__ {
			status = "okay";
			#address-cells = <0x1>;
			#size-cells = <0x0>;

			cs-gpios = <&gpio TEGRA_GPIO(C, 4) GPIO_ACTIVE_LOW>;
			gpio-sck = <&gpio TEGRA_GPIO(C, 2) GPIO_ACTIVE_HIGH>;
			gpio-mosi = <&gpio TEGRA_GPIO(C, 0) GPIO_ACTIVE_HIGH>;
			gpio-miso = <&gpio TEGRA_GPIO(C, 1) GPIO_ACTIVE_HIGH>;

			sck-gpios = <&gpio TEGRA_GPIO(C, 2) GPIO_ACTIVE_HIGH>;
			mosi-gpios = <&gpio TEGRA_GPIO(C, 0) GPIO_ACTIVE_HIGH>;
			miso-gpios = <&gpio TEGRA_GPIO(C, 1) GPIO_ACTIVE_HIGH>;
			num-chipselect = <1>;


			spi@0 {
				status = "disabled";
			};

			spi@1 {
				status = "disabled";
			};

			slb9670: slb9670@0 {
				status = "okay";
				compatible = "infineon,slb9670", "tis,tpm2-spi", "tcg,tpm_tis-spi";
				reg = <1>;
				spi-max-frequency = <32000000>;
				#address-cells = <1>;
				#size-cells = <0>;
				gpio-reset = <&gpio TEGRA_GPIO(C, 7) GPIO_ACTIVE_LOW>;

				controller-data {
					/* nvidia,enable-hw-based-cs; */
					nvidia,variable-length-transfer;
					nvidia,rx-clk-tap-delay = <7>;
				};
			};
		};
	};

	fragment@1 {
		target-path = "/";

		__overlay__ {
			pinctrl-names = "default";
			pinctrl-0 = <0x1>;

			exp-header-pinmux {
				linux,phandle = <0x1>;
				phandle = <0x1>;

				hdr40-pin19 {
					nvidia,pins = "spi1_mosi_pc0";
					nvidia,function = "spi1";
					nvidia,pull = <TEGRA_PIN_PULL_DOWN>;
					nvidia,tristate = <TEGRA_PIN_DISABLE>;
					nvidia,enable-input = <TEGRA_PIN_DISABLE>;
				};

				hdr40-pin21 {
					nvidia,pins = "spi1_miso_pc1";
					nvidia,function = "spi1";
					nvidia,pull = <TEGRA_PIN_PULL_DOWN>;
					nvidia,tristate = <TEGRA_PIN_ENABLE>;
					nvidia,enable-input = <TEGRA_PIN_ENABLE>;
				};

				hdr40-pin23 {
					nvidia,pins = "spi1_sck_pc2";
					nvidia,function = "spi1";
					nvidia,pull = <TEGRA_PIN_PULL_DOWN>;
					nvidia,tristate = <TEGRA_PIN_DISABLE>;
					nvidia,enable-input = <TEGRA_PIN_DISABLE>;
				};

				hdr40-pin24  {
					nvidia,pins = "spi1_cs0_pc3";
					nvidia,function = "spi1";
					vidia,pull = <TEGRA_PIN_PULL_DOWN>;
					nvidia,tristate = <TEGRA_PIN_DISABLE>;
					nvidia,enable-input = <TEGRA_PIN_DISABLE>;
				};

				hdr40-pin26 {
					nvidia,pins = "spi1_cs1_pc4";
					nvidia,function = "spi1";
					nvidia,pull = <TEGRA_PIN_PULL_DOWN>;
					nvidia,tristate = <TEGRA_PIN_DISABLE>;
					nvidia,enable-input = <TEGRA_PIN_DISABLE>;
				};

			};

		};

	};
};

To compile the file, I created this Makefile

COMPILE_DTS_TARGET:="letstrust-tpm-overlay.dts"
COMPILE_DTS_OUTPUT:="/boot/slb9670-overlay.dtbo" 

decompile-user-custom:
	dtc -I dtb -O dts /boot/*user-custom.dtb -o user-custom.dts.decompiled
decompile-overlay:
	dtc -I dtb -O dts $(COMPILE_DTS_OUTPUT) -o $(COMPILE_DTS_TARGET).decompiled

preprocess:
	cpp -nostdinc -I include -I arch -undef -x assembler-with-cpp ${COMPILE_DTS_TARGET}  ${COMPILE_DTS_TARGET}.preprocessed
dtb: preprocess
	sudo dtc -O dtb -o ${COMPILE_DTS_OUTPUT} -@ ${COMPILE_DTS_TARGET}.preprocessed

list-devices:
	sudo /opt/nvidia/jetson-io/config-by-hardware.py -l
apply:
	sudo /opt/nvidia/jetson-io/config-by-hardware.py -n "Letstrust TPM2 slb9670"

cleanup:
	echo "Removing tmp files"
	rm *.preprocessed

all: dtb cleanup apply 

As you can see, I’m using the /opt/nvidia/jetson-io/configure-by-hardware.py script to apply my dts overlay. After rebooting my device is available under /proc/device-tree/spi@7000d400/slb9670@0/

However, the tpm device is not being detected. It is not available under /dev/tpm0 and

dmesg | grep -i tpm

returns nothing

dmesg | grep -i spi
[    0.441419] iommu: Adding device 7000d400.spi to group 7
[    0.441679] iommu: Adding device 7000d600.spi to group 8
[    0.441953] iommu: Adding device 70410000.spi to group 9
[    1.187799] tegra-qspi 70410000.spi: Prod settings list not found
[    1.189179] qspi_mtd spi32766.0: MX25U3235F (4096 Kbytes)
[    1.189189] qspi_mtd spi32766.0: mtd .name = spi32766.0, .size = 0x400000 (4MiB) .erasesize = 0x00001000 (4KiB) .numeraseregions = 0
cat /proc/interrupts | grep spi
 66:        204          0          0          0       LIC  59 Level     7000d400.spi
 67:          0          0          0          0       LIC  82 Level     7000d600.spi
 68:      45238          0          0          0       LIC  10 Level     70410000.spi

Looking into /var/log/syslog is also not very informative.
I don’t have access to an oscilloscope so checking the currents is also not possible for me.

I have already studied those forum posts for hours, but sadly the OP’s haven’t posted what they have changed to make their systems work. The “solution” of those posts are only linking to the 40 pin usage considerations but I only understand a third of it and don’t know how this is supposed to help me:

I’m also unsure about some of the setting ins my spi file:

/* what is there purpose? */
nvidia,enable-hw-based-cs;
nvidia,variable-length-transfer;

nvidia,rx-clk-tap-delay = </*how do i know which value I need? */>;

Where can I look up what they do? If I google them, I only get forum posts using them without any further elaboration on what they do

Hi alexander.ruppe,

Are you using SD or eMMC module of Jetson Nano on the devkit?

As my understanding, you don’t need to specify the PIN of MISO/MOSI/SCK.
You can just put the configurations in the correct SPI node.

Please share the full dmesg and device tree for further check.
You can run the following command to capture the whole device tree configuration on your board.

$ sudo dtc -I fs -O dts -o extracted_proc.dts /proc/device-tree

Hello Kevin

I’m using the SD module.

I tried to specify the PIN manually, just because I didn’t knew what else I could try out.

Here are the requested files
dmesg.txt (63.9 KB)
extracted_proc.dts.zip (45.8 KB)

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

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

		slb9670@0 {
			compatible = "infineon,slb9670", "tis,tpm2-spi", "tcg,tpm_tis-spi", "infineon,slb9672";
			status = "okay";
			#address-cells = <0x1>;
			#size-cells = <0x0>;
			phandle = <0x122>;
			reg = <0x1>;
			spi-max-frequency = <0x1e84800>;
			gpio-reset = <0x5b 0x17 0x1>;

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

Maybe you should remove spi@0 since you’ve added slb9670@0.

Please also request the porting guide from your vendor.

Removing the node didn’t work, but I have now access to an Oscilloscope and I could do some measurements.

For some reason, the cs0 pin is always low and cs1 always high. According to the letstrust page the chip only supports cs1 unless you resolder a resistor. As those are ACTIVE_LOW pins, I am assuming that the permanently active cs0 signal is blocking cs1 which makes it impossible to initialize the module.

I managed it to get a second tpm module, which suffers under the same problem if used on the Jetson Nano. However, I when tested on a Raspberry Pi 4B, both modules worked as expected. While installed on the Rpi both cs pins were constantly on HIGH.

After reading again through the letstrust data sheet, the cs0 pin is not connected, which explains why it behaves like any other unconfigured pins. Additionally, cs1 had a voltage of 3V3 which seemed odd as all other pins had a voltage of 1V, while being pulled down.

I adjusted my config so spi1_cs0 is unconfigured and changed the reg of slb9670 to 0. Now cs1 has a voltage of 1V, when the tpm is connected and 3V3 when not, which I am interpreting as the PIN being pulled up correctly. During the booting process it also jumps from 3V3 to 1V. However, the TPM still doesn’t work. If I’m looking into the slb9670 voltage specifications, the chip registers voltages of <0.3V as an ACTIVE_LOW input, meaning that the provided 1V still counts an high

After further testing my theory looks to be partially correct.

CS1 on RPI while booting

Jetson Nano
CS1 with reg = <0>

CS1 with reg = <1>

While the RPI manages it to completely pull the voltage of cs1 down to 0V, when initializing it, the Jetson Nano only sets it to 1V, which is too high for the TPM to be considered as an input

oh, and I have also modified my kernel according to this patch guide

The voltage being pulled to 1V seems only to appear if cs1 on the jetson and cs1 on the tpm module are connected.

If they are not connected, the jetson nano pin is being pulled down to 0V as expected, but the pin on the tpm module still has a consistend voltage of 3V3, which comes probably from the 3V3 pin on the tpm module.

I don’t know enough about electrical engineering to know why the resulting voltage is 1V

Since it could be pulled down to 0V if you don’t connect the TPM module, the 1V may be pulled by your module even if the Jetson has pulled it down.
Please check this with your HW team or the vendor of your module for details.

Could you try if adding nvidia,enable-hw-based-cs; in device tree may help for your case?

I have already enabled nvidia,enable-hw-based-cs; in my current config. After a lot of experimenting, I have managed it to come up with this circuit, which is basically a level shifter, which reduces to range of the voltage to 0.16V-0.38V.

circuit

Now dmesg | grep -i tpm spits out these errors

[    1.149208] tpm tpm0: tpm_transmit: tpm_send: error -5
[    1.149515] tpm_tis_spi: probe of spi0.1 failed with error -5

I am assuming that the voltage range is still wrong, as the TPM needs >0.7V for a high signal

But i would call it progress

If you are using any pin of 40-pin header, please read below doc in which there are some requirements to the load of each pin coming through the level shift.

Jetson Nano Developer Kit 40-Pin Expansion Header GPIO Usage Considerations Applications Note

I have now switched to an Infineon slb9672 redhat, which does not have the problemes of the pin not being able to be pulled to 0V, but still gets the error posted above.

The MISO pin seems constantly on HIGH despite being an active high pin, which could be the reason for this error

Have you used Jetson-IO to configure the pinmux for SPI pins?

Please share the result of the following commands on your board.

$ sudo cat /sys/kernel/debug/tegra_gpio
$ sudo cat /sys/kernel/debug/tegra_pinctrl_reg | grep -i spi

Yes, but I realized that my pinmux config from the dts overlay is not being applied, so I decompiled the from the Jetson-IO generated user-custom.dtb and manually configured the spi pins

jetson@jetson-desktop:~$ sudo cat /sys/kernel/debug/tegra_gpio
Name:Bank:Port CNF OE OUT IN INT_STA INT_ENB INT_LVL
 A: 0:0 64 40 40 04 00 00 000000
 B: 0:1 00 00 00 00 00 00 000000
 C: 0:2 00 00 00 00 00 00 000000
 D: 0:3 00 00 00 00 00 00 000000
 E: 1:0 40 00 00 00 00 00 000000
 F: 1:1 00 00 00 00 00 00 000000
 G: 1:2 0c 00 00 00 00 00 000000
 H: 1:3 fd 99 00 60 00 00 000000
 I: 2:0 07 05 00 02 00 00 000000
 J: 2:1 00 00 00 00 00 00 000000
 K: 2:2 00 00 00 00 00 00 000000
 L: 2:3 00 00 00 00 00 00 000000
 M: 3:0 00 00 00 00 00 00 000000
 N: 3:1 00 00 00 00 00 00 000000
 O: 3:2 00 00 00 00 00 00 000000
 P: 3:3 00 00 00 00 00 00 000000
 Q: 4:0 00 00 00 00 00 00 000000
 R: 4:1 00 00 00 00 00 00 000000
 S: 4:2 20 80 00 00 00 00 000000
 T: 4:3 01 01 00 00 00 00 000000
 U: 5:0 00 00 00 00 00 00 000000
 V: 5:1 01 00 00 00 00 00 000000
 W: 5:2 00 00 00 00 00 00 000000
 X: 5:3 78 08 08 70 00 60 606000
 Y: 6:0 06 00 00 02 00 00 000000
 Z: 6:1 0f 08 08 04 00 06 020600
AA: 6:2 00 00 00 00 00 00 000000
BB: 6:3 01 00 00 00 00 00 000000
CC: 7:0 92 80 80 00 00 12 121200
DD: 7:1 00 00 00 00 00 00 000000
EE: 7:2 00 00 00 00 00 00 000000
FF: 7:3 00 00 00 00 00 00 000000
jetson@jetson-desktop:~$ sudo cat /sys/kernel/debug/tegra_pinctrl_reg | grep -i spi
Bank: 1 Reg: 0x70003050 Val: 0x0000e044 -> spi1_mosi_pc0
Bank: 1 Reg: 0x70003054 Val: 0x0000e054 -> spi1_miso_pc1
Bank: 1 Reg: 0x70003058 Val: 0x0000e044 -> spi1_sck_pc2
Bank: 1 Reg: 0x7000305c Val: 0x0000e048 -> spi1_cs0_pc3
Bank: 1 Reg: 0x70003060 Val: 0x0000e048 -> spi1_cs1_pc4
Bank: 1 Reg: 0x70003064 Val: 0x00006046 -> spi2_mosi_pb4
Bank: 1 Reg: 0x70003068 Val: 0x00006046 -> spi2_miso_pb5
Bank: 1 Reg: 0x7000306c Val: 0x00006046 -> spi2_sck_pb6
Bank: 1 Reg: 0x70003070 Val: 0x00006046 -> spi2_cs0_pb7
Bank: 1 Reg: 0x70003074 Val: 0x00006045 -> spi2_cs1_pdd0
Bank: 1 Reg: 0x70003078 Val: 0x0000e015 -> spi4_mosi_pc7
Bank: 1 Reg: 0x7000307c Val: 0x0000e015 -> spi4_miso_pd0
Bank: 1 Reg: 0x70003080 Val: 0x0000e015 -> spi4_sck_pc5
Bank: 1 Reg: 0x70003084 Val: 0x0000e015 -> spi4_cs0_pc6
Bank: 1 Reg: 0x70003088 Val: 0x00002040 -> qspi_sck_pee0
Bank: 1 Reg: 0x7000308c Val: 0x00002000 -> qspi_cs_n_pee1
Bank: 1 Reg: 0x70003090 Val: 0x00002040 -> qspi_io0_pee2
Bank: 1 Reg: 0x70003094 Val: 0x00002040 -> qspi_io1_pee3
Bank: 1 Reg: 0x70003098 Val: 0x00002040 -> qspi_io2_pee4
Bank: 1 Reg: 0x7000309c Val: 0x00002040 -> qspi_io3_pee5
Bank: 0 Reg: 0x70000b70 Val: 0x00000001 -> drive_qspi_comp_control
Bank: 0 Reg: 0x70000b78 Val: 0x00000001 -> drive_qspi_lpbk_control
Bank: 0 Reg: 0x70000a78 Val: 0x00808000 -> drive_qspi_comp

Just in case my current /proc/device-tree structure
extracted_proc.dts.zip (45.7 KB)

This register should be 0xe044. How did you configure it in pinmux?
Or you can try using the following command to configure the register and check the waveform again.

$ sudo busybox devmem 0x70003054 0x0000e044 

I have enabled tristate. After disabling it, the register looks as expected, but the voltage remains at 3.5V. I have also checked how the pin behaves on the PI4 and as expected, it defaults to 0V and has some spikes during bootup.

I have also sent you my current /proc/device-tree on the comment above your most recent reply

There’s no 3.5V on Jetson board. Please check from your device side to check why it pull to 3.5V.

My bad. It’s actually 3.3V. My oscilloscope doesn’t print the current Voltage anywhere, except on the graph. The 3.5V is the difference between the lowest and highest measured voltage.

According to the Data Sheet, the pin isn’t connected to an internal voltage pin, meaning the voltage must come from the jetson.