How do i change the device tree?

I am trying to get a SPI → CAN module to work on the jetson nano. I tried with a raspberry pi and it worked.

I need to make changes to the device tree in order to get a ´CAN-socket’. For the raspberry pi i only needed to add some lines to the config.txt but on the Jetson i am lost! I have read many guides and they say you need to compile your device tree blob file. But how do i do that and where do i put it then? I am really lost and would need an instruction from scratch.

I have already downloaded and installed the nvidia-sdk-manager. But i don´t know how to use it. Is there a non-outdated guide? I tried looking for one but only found old ones.

  • i have a MCP2515 SPI to CAN module
  • i want a socketcan in the jetson nano so i can ‘talk’ to other CAN controllers.

Thanks for any help, i appreciate it.

OK i found this guide:

https://docs.nvidia.com/jetson/archives/l4t-archived/l4t-321/index.html#page/Tegra%2520Linux%2520Driver%2520Package%2520Development%2520Guide%2Fkernel_custom.html%23

I am trying to follow it. But there are some steps missing.

It starts with installing GIT but then it wants you to start a sh file which of course you don’t have. I poked around and found out that you have to do some extra steps. Just for future reference i will list them for anyone finding this via google:

  1. install Ubuntu 18.04 (has to be that version not the current 20.04)
  2. download the nvidia SDK-manager
  3. navigate to the .deb file and install via: $ sudo dpkg -i sdkmanager_1.2.0-6738_amd64.deb
    i got some errors but it got installed non the less.
  4. start the SDK manager and log in with your nvidia account. Set everything you need to according to your needs. EG Product Category, Hardwar Configuration, Target Operating System.
  5. Download and install.
  6. press the folder symbol behind the name and it will open the folder where it has downloaded the files.
  7. in that folder you will find the ‘source_sync.sh’ file.
  8. continue with the linked guide

i managed to follow the guide, install the toolchain, exported all needed variables. However i am stuck at the following step:>

'Building the NVIDIA Kernel ’ number 3:
3. Execute the following commands to create the .config file:

$ cd <kernel_source>

$ mkdir -p $TEGRA_KERNEL_OUT

$ make ARCH=arm64 O=$TEGRA_KERNEL_OUT tegra_defconfig

Where:

• <kernel_source> directory contains the kernel sources.

The error i get is the following:

$ make ARCH=arm64 O=$TEGRA_KERNEL_OUT tegra_defconfig
make: *** No rule to make target ‘tegra_defconfig’. Stop.

i can’t find the ‘tegra_defconfig’ file. I tried looking in all downloaded folders. Am i missing something? I tried searching the whole ubuntu system via the ubuntu search feature for that file but couldn’t find anything.

ok i did manage to download the sources manually in another way… i found them in this link:

https://developer.nvidia.com/embedded/L4T/r32_Release_v4.3/sources/T210/public_sources.tbz2

so i needed to unpack the tbz2 format and found a file called ‘kernel_src.tbz2’ i also unpacked that one and used cd to move into it. There i issued the command:

$ make ARCH=arm64 O=$TEGRA_KERNEL_OUT tegra_defconfig

It did work and now i have some files and folders in my KERNEL OUT folder that i created as stated in the guide.

i assume this is the kernel? What do i do with that folder now? How can i change the device tree on my jetson with that?
I feel like i am running away from the actual issue. There has to be a better way to do all of that.

After the “tegra_defconfig” step it is just kernel source, but it is configured for what a basic Jetson would use. You might need to edit device tree content based on your above guide, specifically, the device tree part.

Note that there are several things which can be built from kernel source. I recommend that you start with “make ARCH=arm64 O=$TEGRA_KERNEL_OUT Image” after adding your device tree edits even if you don’t use the full kernel Image. I say this for two reasons: 1. A sanity check, and 2., because it completes some configuration (that extra configuration can be done in other ways).

Your final target would be:

make ARCH=arm64 O=$TEGRA_KERNEL_OUT dtbs

You can get this to be installed to a separate location to make it easier to find. In the same way that you created a temporary kernel source output location and set up $TEGRA_KERNEL_OUT, you could also create such a location for the firmware out:

mkdir ~/firmware
cd ~/firmware
export TEGRA_FIRMWARE_OUT=`pwd`
# Verify:
echo $TEGRA_FIRMWARE_OUT
make O=$TEGRA_KERNEL_OUT firmware_install INSTALL_FW_PATH=$TEGRA_FIRMWARE_OUT

Then there will be a directory tree within “$TEGRA_FIRMWARE_OUT”, and this will probably include the device tree you were after (and much more). You could just search for the dtb file in the $TEGRA_KERNEL_OUT and skip this extra target firmware_install.

Thank you for your reply!

I have been working on this problem for some time now. I learned how to flash the nano. I learned where the DTB files are. I learned that i can read the DTB files with the ‘dtc’ command.

however i don know what i should write into those files and where to put them. Is there any information about this?

Do i have to flash the nano again with the new DTB files? Can’t i just replace the ones that i found in /boot and in /boot/dtb ?

There are differences in procedure for various versions of Jetson. There are also differences in procedure for different releases. There are times when that device tree goes into a partition as signed binary data, but if the changes are for use by the kernel after Linux begins, then you can probably just copy the “.dtb” file into the Jetson’s “/boot”, and edit “/boot/extlinux/extlinux.conf” to name the file (the “FDT” key/value pair). This latter method is quite simple.

In cases where you have some sort of secure boot implemented, then you’d likely need to use a partition via a flash command.

Do you have serial console set up? Any time you are working on boot testing, then you risk making the system unbootable and may require flash to fix the issue every single time. With serial console you can pick among multiple entries in extlinux.conf and keep a known working configuration to pick if your test version fails. Serial console can interrupt boot by hitting a key at the right time and then picking the number of the kernel entry.

If you have serial console, then if you hit a key slightly too soon you drop into the boot command line, and can use command “boot” to continue. A very short time after that you can hit any key and it will wait for you to select the kernel entry. You’d use the backspace key to get rid of the key you hit to enter kernel selection, and then the number of the entry (e.g., “1” or “2”).

An example of a default entry remaining the unmodified entry, plus a second entry with a new FDT device tree entry is:

TIMEOUT 30
DEFAULT primary

MENU TITLE L4T boot options

LABEL primary
      MENU LABEL primary kernel
      LINUX /boot/Image
      INITRD /boot/initrd
      APPEND ${cbootargs} root=/dev/mmcblk0p1 rw rootwait rootfstype=ext4 console=ttyTCU0,115200n8 console=tty0 fbcon=map:0 net.ifnames=0

LABEL testing
      MENU LABEL testing FDT
      LINUX /boot/Image
      INITRD /boot/initrd
      FDT /boot/YourCustomDeviceTree.dtb
      APPEND ${cbootargs} root=/dev/mmcblk0p1 rw rootwait rootfstype=ext4 console=ttyTCU0,115200n8 console=tty0 fbcon=map:0 net.ifnames=0

(and you would of course have to have “YourCustomDeviceTree.dtb” in “/boot”…and I’d use a better name, but that illustrates the idea that it is custom)

During boot and at kernel selection “1” would be default and “2” would boot your FDT enabled entry (which is otherwise the same as the default entry). If “2” fails, then simply use “1”.

I don’t have serial. Can I simply overwrite all the dtb files on boot? I tried, and then I did hexedit /proc/device-tree/interrupt-controller reg to see if the new reg entried I added were really added (from here arm64: tegra_defconfig: enable KVM · antmicro/kvm-aosp-linux@f4d540a · GitHub) but they weren’t.

However if I decompile every file from /boot/*dtb, they all have the new reg values. What is happening?

I also tried setting the default to my new label:

TIMEOUT 30
DEFAULT kvm

MENU TITLE L4T boot options

LABEL primary
      MENU LABEL primary kernel
      LINUX /boot/Image
      INITRD /boot/initrd
      APPEND ${cbootargs} quiet root=/dev/mmcblk0p1 rw rootwait rootfstype=ext4 loglevel=7 console=ttyS0,115200n8 console=tty0 fbco$

LABEL kvm
      MENU LABEL kvm device tree with gic
      LINUX /boot/Image
      INITRD /boot/initrd
      FDT /boot/tegra210-p3448-0000-p3449-0000-b00.dtb
      APPEND ${cbootargs} quiet root=/dev/mmcblk0p1 rw rootwait rootfstype=ext4 loglevel=7 console=ttyS0,115200n8 console=tty0 fbco$

it boots but I also see no modifications on the device tree.

Also, how do I know which of the .dtb the jetson nano takes? There ar elotfs of them starting with /tegra210-p3448, would be nice to know so I can edit only the one I need, or which one I should edit (so I don’t edit the wrong one)

1 Like

This is an old topic, so you should probably start a new topic. Much has changed since the original topic.

FYI, you cannot edit “/proc/device-tree”, this is simply the driver telling you what is currently loaded, and these are not actual files on the hard drive. Also, there are many dtb files in “/boot” which are not used and are only in place for convenience. One would have to add the FDT as you have, but it is possible a bug would require you to place your new “kvm” block of extlinux.conf before the old “primary” block.

Incidentally, if the initrd needs a different device tree, then there might also be a need to add use of the device tree there…it just depends on circumstances. Do start a new topic though if this does not help.

I called hexedit on /proc/device-tree just to see if the regs I added were there.

Making a default kvm on extlinux.conf did not work, but selecting it using 2 through the serial worked.

lz@jetson:~/Linux_for_Tegra/source/public$ dmesg | grep -i kernel
[    0.000000] Kernel command line: tegraid=21.1.2.0.0 ddr_die=4096M@2048M section=512M memtype=0 vpr_resize usb_port_owner_info=0 lane_owner_info=0 emc_max_dvfs=0 touch_id=0@63 video=tegrafb no_console_suspend=1 console=ttyS0,115200n8 debug_uartport=lsport,4 earlyprintk=uart8250-32bit,0x70006000 maxcpus=4 usbcore.old_scheme_first=1 lp0_vec=0x1000@0xff780000 core_edp_mv=1075 core_edp_ma=4000 gpt tegra_fbmem=0x800000@0x92ca9000 is_hdmi_initialised=1  earlycon=uart8250,mmio32,0x70006000  root=/dev/mmcblk0p1 rw rootwait rootfstype=ext4 console=ttyS0,115200n8 console=tty0 fbcon=map:0 net.ifnames=0  
[    0.000000] Memory: 3559708K/4159488K available (15486K kernel code, 2962K rwdata, 7052K rodata, 8640K init, 609K bss, 124644K reserved, 475136K cma-reserved)
[    0.000000] Virtual kernel memory layout:
[    0.022544] kmemleak: Kernel memory leak detector disabled
[    0.236710] DTS File Name: /home/lz/Linux_for_Tegra/source/public/kernel/kernel-4.9/arch/arm64/boot/dts/../../../../../../hardware/nvidia/platform/t210/porg/kernel-dts/tegra210-p3448-0000-p3449-0000-a00.dts
[    0.349717] alternatives: patching kernel code
[    0.449149] DTS File Name: /home/lz/Linux_for_Tegra/source/public/kernel/kernel-4.9/arch/arm64/boot/dts/../../../../../../hardware/nvidia/platform/t210/porg/kernel-dts/tegra210-p3448-0000-p3449-0000-a00.dts
[    0.594271] eventlib_kernel: keventlib is initialized, test id: 0
[    5.416625] KERNEL: PMC reset status reg: 0x3
[    5.994490] Freeing unused kernel memory: 8640K

It looks like that when I compile the kernel locally and substitute the Image on /boot/Image, that is, I don’t use any of the flash utilities from NVIDIA, it starts loading the device tree from the local folder where I compiled the kernel:


[    0.236710] DTS File Name: /home/lz/Linux_for_Tegra/source/public/kernel/kernel-4.9/arch/arm64/boot/dts/../../../../../../hardware/nvidia/platform/t210/porg/kernel-dts/tegra210-p3448-0000-p3449-0000-a00.dts

thus substituting the device trees in /boot did not have any effect unless with extlinux.conf. Do you know how is the kernel loading the dtb files from the local kernel source compilation results like /home/lz/Linux_for_Tegra/source/public/kernel/kernel-4.9/arch/arm64/boot/dts/../../../../../../hardware/nvidia/platform/t210/porg/kernel-dts/tegra210-p3448-0000-p3449-0000-a00.dts?

That is a bug in handling extlinux.conf. If you make your new default the first entry (not the second), then it should use that entry for default when booting.

If you have burned security fuses, then only the signed device tree partition would be used, but chances are that you just need to make the kvm entry of extlinux.conf the first entry in order to get past the bug where it isn’t making the second entry a default per file settings.

Incidentally, for NVIDIA, someone might want to check on the extlinux.conf “default” code to see if it correctly changes the default to a new label when that label is not the first entry.

for me its okay now that I found my serial device to select the right profile on extlinux.conf, I’m more concerned on the fact that without setting the FDT on it, it loads the kernel DTB files from

/home/lz/Linux_for_Tegra/source/public/kernel/kernel-4.9/arch/arm64/boot/dts/../../../../../../hardware/nvidia/platform/t210/porg/kernel-dts/tegra210-p3448-0000-p3449-0000-a00.dts

which is where I compiled the kernel. I don’t understand why, but I guess this path is hardcoded inside the /boot/Image that I just copied from /home/lz/Linux_for_Tegra/source/public/kernel/kernel-4.9/arch/arm64/boot/. I’d like to change this so people don’t need to edit extlinux.conf and instead just replace /boot/*.dtb with the compiled ones from the kernel source

It should not be pulling from the home directory location unless the FDT entry in extlinux.conf has named that location. What is more likely is that the exact file has a copy somewhere else, and perhaps you are seeing something about where it is compiled rather than where it is loaded from. What message or event makes it look like the device tree is located from the home directory version of the file?

Do note that it is possible that an initrd also reads a device tree, but this is unlikely. A log of everything leading up to this read location would be useful.

I think it’s loading from that local place because when I replaced all the .dtb files of /boot and rebooted, my modifications didn’t take place. hexedit /proc/device-tree/interrupt-controller/regs showed the original regs, not the ones I made. I even decompiled the files from /boot just to confirm that they had the new regs and they had. The regs were only changed when I added the FDT entry on extlinux.conf. This makes me think that the device trees were being loaded from somewhere else, and given that that local path appears in the dmesg, it should be from there.

I extracted the initrd and could not find any device trees also.

The above is working as expected. If there is no FDT entry, then trees are pulled from partitions, and not the files in “/boot”. What is your exact FDT entry? Can that file be decompiled and show changes you’ve made, and do those changes fail to show up in “/proc/device-tree”?

Perhaps more important, in the original tree, are the modifications for (what I assume to be “interrupt-controller/regs”) what you are changing being edited, or are they being added from previously non-existing entries? I ask because I wonder if perhaps you are trying to add something which would be rejected…it is different to have a valid parameter behave incorrectly, versus adding a parameter which isn’t allowed. I couldn’t tell you if the parameter you are adding is valid or not, but someone else probably can if they know what the change is.

Keep in mind that earlier boot stages do have their own device tree sources, and this is inherited by succeeding boot stages (perhaps after edits). Then, when it loads the FDT entry, this is appended. To indirectly illustrate, look closely at the “/boot/extlinux/extlinux.conf”. Note the “APPEND” key/value pair starts with “${cbootargs}”. Then examine what occurs in “APPENDafter${cbootargs}”. If you run command “cat /proc/cmdline”, then you will see the sum total of “${cbootargs}” plus the appended extra content in the extlinux.conf file. If the start of your cmdline contains content not equal to the suffix of the APPEND key/value pair, then that is content which was inherited, and not content from extlinux.conf.

The important point here is that the “${cbootargs}” is actually a device tree entry, the “chosen->bootargs” tree node. The content of “chosen->bootargs” is not necessarily from your tree, but could originate from another device tree location inside of a partition which was read by early boot stages.

The FDT entry is a good place for you to add changes, but it cannot be guaranteed to be the entire device tree source since this is a merge with early boot stage content.

If you added something with the FDT entry, and it shows up, then this is valid behavior. If there is something inherited from earlier stages, then this too is valid behavior. If what you are adding does not have some sort of conflict, then it should show up in “/proc/device-tree”. Your specific changes and how you add these, and whether or not the rest of the boot tree is non-custom (it would be custom for third party carrier boards or if you’ve ever told it to flash a tree to a partition), has to all be considered to know if something really went wrong.

Incidentally, the initrd is its own file. Some changes to tree won’t matter there, as the initrd is likely reading the actual “/boot” partition and not reading from inside the initrd, but it isn’t a guarantee. Changes which alter the initrd might be a bit confusing, e.g., for a custom carrier board.