Xavier NX spi cs problems and timing

G’day All,

I’ve been trying to use the Xavier NX to control a chip over spi, but cannot seem to configure it properly. Specifically, we require the cs line to drop low every 2-bytes (16-bits) and some other clock timing parameters, but can’t seem to get any settings to work. The spidev loopback test works, but the chip-select only toggles for the full message rather than on a per n-byte basis.

Any help would be appreciated.

The current approach is to use jetson-io to generate an overlay to enable spi, and then modify it. The current overlay looks like:
~/src/device_trees/spi_overlay.dts


/ {
	jetson-header-name = "Jetson 40pin Header";
	overlay-name = "User Custom [2023-01-20-095732]";
	compatible = "nvidia,p3509-0000+p3668-0000\0nvidia,p3509-0000+p3668-0001";

	fragment@1 {
		target-path = "/spi@3210000/spi@0";
		__overlay__ {
			compatible = "linux,spidev";

			controller-data {
				// nvidia,enable-hw-based-cs = <0x01>;  // defaults
				// nvidia,tx-clk-tap-delay = <0x00>;  // defaults
				// nvidia,rx-clk-tap-delay = <0x10>;  // defaults
	
				nvidia,cs-setup-clk-count = <0x02>;
				// nvidia,cs-hold-clk-count = <0x05>;
				// nvidia,cs-inactive-cycles = <0x06>;
				// nvidia,clk-delay-between-packets = <0x07>;
			};
                };
	};

	fragment@0 {
		target = <0xffffffff>;

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

			exp-header-pinmux {
				phandle = <0x01>;

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

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

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

				hdr40-pin24 {
					nvidia,pins = "spi1_cs0_pz6";
					nvidia,function = "spi1";
					nvidia,pull = <0x02>;
					nvidia,tristate = <0x00>;
					nvidia,enable-input = <0x01>;
					nvidia,lpdr = <0x00>;
				};

				hdr40-pin26 {
					nvidia,pins = "spi1_cs1_pz7";
					nvidia,function = "spi1";
					nvidia,pull = <0x02>;
					nvidia,tristate = <0x00>;
					nvidia,enable-input = <0x01>;
					nvidia,lpdr = <0x00>;
				};
			};
		};
	};

	__symbols__ {
		jetson_io_pinmux = "/fragment@0/__overlay__/exp-header-pinmux";
	};

	__fixups__ {
		pinmux = "/fragment@0:target:0";
	};

	__local_fixups__ {

		fragment@0 {

			__overlay__ {
				pinctrl-0 = <0x00>;
			};
		};
	};
};

Cheers,

Jacob

Sorry for the late response, have you managed to get issue resolved or still need the support? Thanks

Hi,
Not sure which SPI you use in your use-case. On Xavier NX developer kit, we support SPI1 and SPI3 in 40-pin expansion header. If you use either one, please jetson-io.py to generate device tree for reference or give it a try.

Hi @DaneLLL and @kayccc, we’re still having challenges.

In regards to the pin configuration, we have used the jetson-io to configure our pins for spi1 (device tree pov) (aka spidev0.0 from linux pov), and that works.
One note is that we also needed modify the compatibility line tegra,spidev as it was not recognised. Switching it to linux,spidev was a workaround, but not a great solution, so some advice would be appreciated.

However, the main issue is that we cannot seem to configure the chip-select and timing properties. We desire the cs line to be toggled after every 16 bits, but this setting is not being recognised. Any ideas?

Jacob

Hi,
For information, do you use Jetpack 4 or 5?

Hi,

We tried using both Jetson Linux 35.1.0 and 35.2.1

Jacob

Hi,
Please enable nvidia,enable-hw-based-cs = <0x01>; and try again. If it still does not meet the request, please add prints in tegra_spi_set_timing1() in

kernel-5.10/drivers/spi/spi-tegra114.c

To check and confirm if the function is called and the timing is set as expected.

I’ve made some edits to the device tree, but most importantly the kernel module. More investigation is needed, but similar issues were found in How to set SPI CS(chip select) timing?, Bug in spi-tegra114.c and other spi related things, https://forums.developer.nvidia.com/t/spi-slave-can-only-receive-the-second-packet-from-nano-dev-kit-spi-master/110132and for some reason, not all of the proposed patches/fixes made it into the current kernel. I’ve done a quick hack to get something working, but this is not at all robust and may not solve all issues. Basically I commented out a check for gpio chip select, changed tegra-spidev to linux,spidev, and disabled prod-settings in the device tree.

Below I included some quite verbose notes on how I did this for anyone and/or myself in the future.


Getting Kernel Sources

Get the sources:

RELEASE=35
VERSION=1.0
KERNEL=5.10
RELEASE_VERSION=r${RELEASE}_release_v${VERSION}
ARCHIVE_NAME=public_sources_${RELEASE_VERSION}
SOURCES_NAME=Linux_for_Tegra_${RELEASE_VERSION}
mkdir -p ${HOME}/src/nvidia/l4t_sources/xavier_nx && cd ${HOME}/src/nvidia/l4t_sources/xavier_nx
wget https://developer.nvidia.com/embedded/l4t/${RELEASE_VERSION}/sources/public_sources.tbz2
mv public_sources.tbz2 ${ARCHIVE_NAME}.tbz2
tar -xvf ${ARCHIVE_NAME}.tbz2 && mv Linux_for_Tegra ${SOURCES_NAME}
cd ${SOURCES_NAME}/source/public
JETSON_XAVIER_NX_KERNEL_SOURCES=$(pwd)
tar -xvf kernel_src.tbz2


Kernel Module Modifications

Copy the driver

# Make a copy of the spi driver
SPI_DIR=kernel/kernel-${KERNEL}/drivers/spi
SPI_DRIVER_DIR=${JETSON_XAVIER_NX_KERNEL_SOURCES}/${SPI_DIR}
mkdir -p ${HOME}/src/spi && cd ${HOME}/src/spi
cp ${SPI_DRIVER_DIR}/spi-tegra114.c ./

Create a Makefile containing the following with nano Makefile:

obj-m += spi-tegra114.o
	
all:
	make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
clean:
	make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean
install:
	make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules_install

Edit the spi kernel driver. We modified it by commenting out checks on gpio chip selects and inactive cycles as follows: nano spi-tegra114.c

// line 1302
	if (cdata && cdata->clk_delay_between_packets) {
		// if (cdata->cs_inactive_cycles || !cstate->cs_gpio_valid) {
		// if (cdata->cs_inactive_cycles) {
		// 	dev_err(&spi->dev,
		// 		"Invalid cs packet delay config\n");
		// 	tegra_spi_cleanup(spi);
		// 	return -EINVAL;
		// }
		cdata->cs_inactive_cycles = cdata->clk_delay_between_packets;
	}

It was rebuilt as spi-tegra114.ko and placed in /lib/modules/$(uname -r)/kernel/drivers/spi/:

make
mv /lib/modules/$(uname -r)/kernel/drivers/spi/spi-tegra114.ko /lib/modules/$(uname -r)/kernel/drivers/spi/spi-tegra114.ko.bak
cp ${HOME}/src/spi/spi-tegra114.ko /lib/modules/$(uname -r)/kernel/drivers/spi/


Device Tree Preparation

The device tree was prepared as:

# Prepare tree and image
echo DEVICE=tegra194-p3668-0001-p3509-0000 >> ${HOME}/.bashrc && . ${HOME}/.bashrc
echo BOOT_LOCATION=/boot >> ${HOME}/.bashrc && . ${HOME}/.bashrc
sudo cp ${BOOT_LOCATION}/dtb/kernel_${DEVICE}.dtb /boot/dtb/kernel_${DEVICE}.dtb.bak
sudo cp ${BOOT_LOCATION}/Image ${BOOT_LOCATION}/Image.bak

# Get the original device tree
mkdir -p ${HOME}/src/device_trees
dtc -I dtb -O dts -o ~/src/device_trees/original_tree.dts ${BOOT_LOCATION}/dtb/kernel_${DEVICE}.dtb.bak

# Prepare the spi overlay
sudo /opt/nvidia/jetson-io/config-by-function.py spi1 -o dtbo
sudo mv ${BOOT_LOCATION}/kernel_${DEVICE}-hdr40-user-custom.dtbo ~/src/device_trees/kernel_${DEVICE}-hdr40-user-custom.dtbo && dtc -I dtb -O dts -o ~/src/device_trees/spi_overlay.dts ~/src/device_trees/kernel_${DEVICE}-hdr40-user-custom.dtbo

Edit the new overlay: nano ${HOME}/src/device_trees/spi_overlay.dts to add in the following fragment:

fragment@1 {
    target-path = "/spi@3210000";
    __overlay__ {

        prod-settings {
            status= "disabled";
        };

        spi@0 {
            compatible = "linux,spidev";
            
            controller-data {
                nvidia,clk-delay-between-packets = <2>;
            };
        };
    };
};

Apply the new overlay:

dtc -I dts -O dtb -@ -o ${HOME}/src/device_trees/original_tree.dtb ${HOME}/src/device_trees/original_tree.dts && dtc -I dts -O dtb -@ -o ${HOME}/src/device_trees/spi_overlay.dtbo ${HOME}/src/device_trees/spi_overlay.dts && sudo fdtoverlay -i ${HOME}/src/device_trees/original_tree.dtb -o ${BOOT_LOCATION}/dtb/kernel_${DEVICE}.dtb ${HOME}/src/device_trees/spi_overlay.dtbo


Testing

Basic tests were carried out with GitHub - rm-hull/spidev-test

mkdir -p ${HOME}/src/ && cd ${HOME}/src/
git clone https://github.com/rm-hull/spidev-test
cd spidev-test
gcc spidev_test.c -o spidev_test

The test was run ${HOME}/src/spidev-test/spidev_test and produced:

Which is a good start. Next, exact timing controls will be investigated.


As noted before by @gtj in Bug in spi-tegra114.c and other spi related things , there are still issues with spi-tegra114.c . To enable timing controls, the following changes had to be made by commenting out sections of code. For hardware chip-selct we have:

// line 1301
if (cdata && cdata->clk_delay_between_packets) {
	// if (cdata->cs_inactive_cycles || !cstate->cs_gpio_valid) {
	// 	dev_err(&spi->dev,
	// 		"Invalid cs packet delay config\n");
	// 	tegra_spi_cleanup(spi);
	// 	return -EINVAL;
	// }
	cdata->cs_inactive_cycles = cdata->clk_delay_between_packets;
}

and for timing control:

// line 916
if (!cdata || tspi->prod_list)
	return;
// if (!cdata->clk_delay_between_packets)
// 	return;
if (cdata->cs_inactive_cycles) { ...

Now when setting the device tree overlay as:

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

    __overlay__ {

        prod-settings {
            status= "disabled";
        };

        spi@0 {
            compatible = "linux,spidev";
            
            controller-data {
                nvidia,clk-delay-between-packets = <2>;     // There should be a delay of at least 2 SPI Clocks between consecutive CS
                nvidia,cs-setup-clk-count = <2>;            // Host should ensure that there is a delay of at least 2 SPI clocks between CS going low and start of SPI clock
            };
        };
    };
};

and using running spidev-test -b 16, we get the behaviour we desire:


It seems that although there have been people working on this issue in the past, and even resolutions to the problem, these updates may not have made it into the main kernel branch.

2 Likes

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.