Jetson TK1 unable to reduce SPI clock below ~3.2MHz

It seems that many of us are attempting a very similar procedure, setting up some form of SPI device on the TK1 that requires a SPI clock to be relatively low speed. There are many replies primarily in the grinch threads, but I figured I could start a new discussion on the subject, as the problem seems to span different kernel versions.

Following many tutorials on SPI, specifically @NeuroBots’s amazing tutorial: http://neurorobotictech.com/Community/Blog/tabid/184/ID/11/Using-the-Jetson-TK1-SPI--Part-1-Why-is-SPI-important.aspx, I was able to set up spidev for user-space access to the SPI-bus, but I am stuck attempting to reduce the SPI clock speed below 3.2MHz in order to interface my device.

Hooking the TK1 up to a logic analyzer shows that the SPI clock speed never drops below about 3.18MHz (as originally discovered by @neelfirst https://devtalk.nvidia.com/default/topic/823132/embedded-systems/-customkernel-the-grinch-21-3-4-for-jetson-tk1-developed/post/4575643/#4575643). Any attempt to set the speed lower than 3.2MHz (whether using the device tree or ioctl() commands) results in the TK1 reverting to the last speed that was faster than 3.2MHz.

Here is a snippet from my device tree corresponding to the spidev entry for reference:

spi@7000d400 {
compatible = “nvidia,tegra114-spi”;
reg = <0x7000d400 0x200>;
interrupts = <0x0 0x3b 0x4>;
nvidia,dma-request-selector = <0x7 0xf>;
nvidia,memory-clients = <0xe>;
#address-cells = <0x1>;
#size-cells = <0x0>;
status = “okay”;
spi-max-frequency = <25000000>;

    spi0_0 {
            compatible = "spidev";
            reg = <0>;
            spi-max-frequency = <25000000>;
            spi-cpha;
            spi-cpol;
            nvidia,enable-hw-based-cs;
    };

};

I’m fairly certain that the spidev driver is allowing me to set the speed correctly. There are no errors using the ioctl() commands, and the device tree compiler has no complaints. I’ve enabled SPI debug mode in the kernel, and here is a snippet of two runs using two seperate SPI speeds from dmesg. Note the drop in frequency as was requested by me through spidev. In both cases, the speed remains at 3.5MHz (the initial speed above the lower bound), and both requested speeds are different than the spidev entry in the device tree, meaning that the commands are affecting the SPI bus speed, but only to a certain limit.

[ 7401.389176] spidev spi0.0: setup 16 bpw, cpol, cpha, 3500000Hz
[ 7401.389483] spidev spi0.0: setup mode 3, 16 bits/w, 3500000 Hz max → 0
[ 7401.389500] spidev spi0.0: spi mode 03
[ 7401.389521] spidev spi0.0: setup 16 bpw, cpol, cpha, 3500000Hz
[ 7401.389576] spidev spi0.0: setup mode 3, 16 bits/w, 3500000 Hz max → 0
[ 7401.389584] spidev spi0.0: 16 bits per word
[ 7401.389597] spidev spi0.0: setup 16 bpw, cpol, cpha, 3500000Hz
[ 7401.389645] spidev spi0.0: setup mode 3, 16 bits/w, 3500000 Hz max → 0
[ 7401.389652] spidev spi0.0: 3500000 Hz (max)
[ 7401.391912] spi-tegra114 spi-tegra114.0: The def 0x40c00000 and written 0x70c0182f
[ 7470.636012] spidev spi0.0: setup 16 bpw, cpol, cpha, 3500000Hz
[ 7470.636172] spidev spi0.0: setup mode 3, 16 bits/w, 3500000 Hz max → 0
[ 7470.636186] spidev spi0.0: spi mode 03
[ 7470.637516] spidev spi0.0: setup 16 bpw, cpol, cpha, 3500000Hz
[ 7470.637646] spidev spi0.0: setup mode 3, 16 bits/w, 3500000 Hz max → 0
[ 7470.637725] spidev spi0.0: 16 bits per word
[ 7470.637742] spidev spi0.0: setup 16 bpw, cpol, cpha, 1500000Hz
[ 7470.637804] spidev spi0.0: setup mode 3, 16 bits/w, 1500000 Hz max → 0
[ 7470.637812] spidev spi0.0: 1500000 Hz (max)
[ 7470.639482] spi-tegra114 spi-tegra114.0: The def 0x40c00000 and written 0x70c0182f

I’m pretty new to all this stuff, and I’m terrible at reading these things, but: On page 66 of the TRM, where the SPI clocks are referenced, it mentions a “Divide 8”. Based on the example, I assume this means 8-bit, but the division seems to cap at 4 bits:

50MHz/(2^4) = 3.125 MHz. (note 50MHz spec pulled from TRM pg 2443)

Am I overlooking something?

Any insight/new ideas would be a huge help.

Thanks,
Curtis

I lack a logic analyzer or oscilloscope (sadly my trusty Tektronix scope died), but one thing that might be relevant I found on TRM page 56, near the top. Here’s a partial quote:

  • Clock dividers:
  • An unsigned 8-bit divider that provides 7 bits of mantissa and 1 bit of fraction (U7.1). Tegra K1 devices have reduced the number of divider types and in particular this U7.1 divider is the default divider for most all blocks in Tegra K1 devices.

The description seems to imply that this is the nature of at least the bulk of 8-bit dividers, that it may not be just an unsigned divide. Maybe someone can verify that the high order bit differs in behavior from the 7 lower order bits for the SPI divider.

Hi @murtis.

found this but it seems to be irreverent for the kernel I am using. [U-Boot] [PATCH v3 04/15] tegra: spi: Support slow SPI rates.

I also need to figure out how to reduce the frequency as all level shifters at freq >750Khz seem to not produce full logic. I have tried using TXB0140, BSS138. Next I am going to try NXP GTL2003.

I am using grinch kernel 19.3.6. The new kernel has a different SPI device definition where you can specify the source but I cant get it to work as the new grinch kernel has conflicting CS pin assignment.

Benzun

specify the clk source

Based on chpater 5.7 Clock and Reset Controller Registers ,
CLK_RST_CONTROLLER_CLK_SOURCE_SPI1_0
bit7:0 SPI1_CLK_DIVISOR: N = divider by (n+1) [ lsb denotes 0.5x]

So SPI Frequency = Clock Source / ((SPI_CLK_DIVISOR*0.5)+1)
The clock source of spi is pll_p that frequency is 408Mhz .

So the minimum spi frequency : 408 / (0xFF * 0.5) +1 = 3.17509 Mhz
This is why you can’t set spi freq below 3.2 Mhz

Do you know how to change the clock source for the spi. I read in the TRM that it is configurable but i dont clealy understand how the Device Tree file works to change it correctly.

Unfortunately my DTS file does not use any naming convention, so it is difficult to read what clocks, pins, etc are being referenced. However I found some hints in the LXR Free Electrons source (though not for the same kernel version, i.e. Linux 3.10):

  1. this is a DTS file that contains more human-readable variables etc
    http://lxr.free-electrons.com/source/arch/arm/boot/dts/tegra124.dtsi?v=3.15
  2. this is an include file that contains #defines for variables used in 1)
    http://lxr.free-electrons.com/source/arch/arm/boot/dts/include/dt-bindings/clock/tegra124-car-common.h

You can see various correspondences, i.e. the SPI clock used in 0x7000d400 is TEGRA_CLK_SBC1, which corresponds to 41 or 0x29, which is what is in my less-readable DTS. Similarly &tegra_car seems to correspond to 0xc or 12, or TEGRA124_CLK_I2C1 in the H file. You can perhaps use this to select a different clock from the list, but I haven’t had the time myself to trawl through the TRM and figure out which clock would be more appropriate. Nor can I see why I should - SBC1 should be the optimal clock for SPI, and even with a 7.1-bit divisor surely I should get sub 1MHz clocks.

Regarding level shifting, I am using the LSF0204PWR, which can support 50-100 MHz clocks. I also see problems on its output end only with the Jetson - the 3.3V side does not swing above 2.4V. Fortunately this is good enough for me but I have no reason to doubt this level shifter in prior use.

You can try to change clk source in ardbeg_clk_init_table from board-ardbeg.c

Hi linuxdev et.al
CLock source for SPI1 as per page130 of TRM can be one 0f 6 , PLLP_OUT0/PPLC2_OUT0/PLLC_OUT0/PLLC3_OUT0/PLLM_OUT0/CLK_M.

What are the min. values for these clocks ? Kind of hard to figure this out.
can’t we change this register with ioctl 0 instead of changing board-ardbeg.c ?

Would like to get the spi running @ 1 MHz and below .

thanks
…ravi