The below instructions will help you boot an upstream U-Boot and Linux kernel on the Jetson Nano.
It is assumed that you've downloaded the L4T Jetson Nano Driver package from here:
You may also want to download the sample root filesystem:
As well as the quickstart guide:
You may also be interested in the other downloads available in the Jetson Download Center:
Extract the tarball and follow the quickstart instructions to flash L4T. You can check if the flashing operation was successful by booting the system (it should do an automatic reboot after flashing is complete).
Patches to add support for the Jetson Nano have been posted to the U-Boot mailing list:
and are available in the p3450 branch in this repository:
To build U-Boot for the board, do the following:
$ tools/genboardscfg.py $ make O=build/p3450-0000 p3450-0000_defconfig $ make O=build/p3450-0000
This assumes that you've set up the CROSS_COMPILE environment variable to point at the prefix of your cross compiler.
Once the build is finished, you can flash L4T, using the above instructions, but use the newly built version of U-Boot. To do so, run the following:
$ sudo ./flash.sh -K path/to/u-boot.git/build/p3450-0000/u-boot.bin jetson-nano-sd mmcblk0p1
Patches to add support for Jetson Nano to the upstream Linux kernel are available on patchwork:
and in the p3450 branch of the following repository:
https://github.com/thierryreding/linux (branch p3450)
They will also be available in linux-next in the next couple of days.
To build a kernel image and the device tree blobs, run the following commands:
$ make ARCH=arm64 O=build/jetson-nano defconfig $ make ARCH=arm64 O=build/jetson-nano -j32
If you haven't opened a terminal to the debug UART yet, now's the right time:
$ screen /dev/ttyUSB0 115200
Make sure to substitute the correct TTY for your setup. screen works really well as a terminal program, but any other should work just fine, too. You should see the U-Boot prompt in the terminal, if not reset the board and wait for U-Boot to boot up. Then interrupt the automatic boot by pressing any key.
Now put U-Boot on the Jetson Nano into USB mass storage (UMS) mode:
Tegra210 (P3450-0000) # ums 0 mmc 0
This will export the SD card as block device over USB. Before running the above you might want to watch the kernel log to see what block device the SD card is associated with:
$ dmesg --follow
When you enter UMS mode (make sure you have the Jetson Nano hooked up to your host via the micro-USB cable), the log should show something like this:
kernel: usb 4-1.6.4: new high-speed USB device number 14 using ehci-pci kernel: usb 4-1.6.4: New USB device found, idVendor=0955, idProduct=701a, bcdDevice= 2.21 kernel: usb 4-1.6.4: New USB device strings: Mfr=1, Product=2, SerialNumber=0 kernel: usb 4-1.6.4: Product: USB download gadget kernel: usb 4-1.6.4: Manufacturer: NVIDIA kernel: usb-storage 4-1.6.4:1.0: USB Mass Storage device detected kernel: scsi host9: usb-storage 4-1.6.4:1.0 kernel: scsi 9:0:0:0: Direct-Access Linux UMS disk 0 ffff PQ: 0 ANSI: 2 kernel: sd 9:0:0:0: Attached scsi generic sg5 type 0 kernel: sd 9:0:0:0: [sdf] 30253056 512-byte logical blocks: (15.5 GB/14.4 GiB) kernel: sd 9:0:0:0: [sdf] Write Protect is off kernel: sd 9:0:0:0: [sdf] Mode Sense: 0f 00 00 00 kernel: sd 9:0:0:0: [sdf] Write cache: enabled, read cache: enabled, doesn't support DPO or FUA kernel: sdf: sdf1 sdf2 sdf3 sdf4 sdf5 sdf6 sdf7 sdf8 sdf9 sdf10 sdf11 sdf12 sdf13 sdf14 kernel: sd 9:0:0:0: [sdf] Attached SCSI removable disk
The sdf (and more precisely sdc1) in the above is what you are going to need. Mount the root partition:
# mount /dev/sdf1 /mnt
Copy your kernel and DTB files to the root partition:
# cp build/jetson-nano/arch/arm64/boot/Image /mnt/boot/Image-upstream # cp build/jetson-nano/arch/arm64/boot/dts/nvidia/tegra210-p3450-0000.dtb /mnt/boot/
Note that this keeps the original kernel. If you're not interested in keeping the L4T installation (if you've opted for the Arch Linux root filesystem you probably aren't), you might just as well copy the upstream kernel image over the existing one.
If you have built some of the drivers as loadable modules, which you have if you have used the default configuration, make sure to install the modules:
# sudo make ARCH=arm64 O=build/jetson-nano INSTALL_MOD_PATH=/mnt modules_install
Now the bootloader must be configured to be able to boot the upstream kernel. The L4T kernel requires a bunch of command-line parameters that the upstream kernel doesn't, so again, if you want to keep the L4T setup in place, you can simply add an extlinux.conf configuration snippet:
# vim /mnt/boot/extlinux/extlinux.conf
Add the following to the end of the file, or overwrite the existing "primary kernel" entry with it:
LABEL upstream MENU LABEL upstream kernel LINUX /boot/Image-upstream FDT /boot/tegra210-p3450-0000.dtb APPEND root=/dev/mmcblk0p1 rw rootwait
Save the file and unmount the partition:
# umount /mnt
You can now exit UMS mode by pressing Ctrl+C in the terminal window.
That's it. You're now ready to boot your upstream kernel:
Tegra210 (P3450-0000) # boot
If you've opted to keep L4T in place, U-Boot will detect that you have two configurations and will ask you which one to boot. If you have a single configuration you can simply wait for the auto-boot timer to run out. If all goes well this should boot you to a login- or command-prompt.
U-Boot and the Linux kernel also support network booting. In order to do so you can follow the procedure outlined above with a couple of small changes.
First, you need to make sure that the r8169 driver is built-in or included in your initial ramdisk. For the former, edit the .config file in the kernel build directory and make sure the R8169 Kconfig option is set like this:
Including the module in the initial ramdisk doesn't really have any benefits over the built-in option and is fairly complicated. Refer to the distribution documentation to learn how to do that.
Use the following command to flash the board:
$ sudo ./flash.sh -N 192.168.1.1:/srv/nfs/jetson-nano -K /path/to/u-boot.git/build/p3450-0000/u-boot.bin jetson-nano-sd eth0
This assumes that you have installed the L4T sample root filesystem, or any other root filesystem of your choice in /srv/nfs/jetson-nano and configured an NFS server to provide this at an address 192.168.1.1. Setting up an NFS server is outside the scope of this guide, but you can find plenty of data on how to do that on the Internet.
If you need an initial ramdisk to boot from NFS, make sure to copy it to the SD card (similar to how you did for the kernel image and DTB) and instruct extlinux to load it via the following updated entry:
LABEL upstream MENU LABEL upstream kernel LINUX /boot/Image-upstream INITRD /boot/initrd.gz FDT /boot/tegra210-p3450-0000.dtb APPEND root=/dev/nfs ip=:::::eth0:dhcp root=/dev/nfs nfsroot=192.168.1.1:/srv/nfs/jetson-nano rw rootwait
Note that there seem to be slight incompatibilities between the Ubuntu root filesystem provided with L4T and the upstream kernel configuration which may cause unexpected behaviour during boot. The L4T root filesystem also ships some binaries which will not work on an upstream kernel because it lacks the required support. You might want to replace the Ubuntu root filesystem with something like Arch Linux which you can download from here. To do this, follow the quickstart instructions but instead of extracting the L4T sample root filesystem extract the Arch Linux root filesystem. If you do so, you might want to skip the step that installs the L4T-specific binaries as well.
Note that the upstream U-Boot is currently not able to boot the downstream Linux kernel. If you want to be able to boot both upstream and downstream kernels in a dual-boot setup, you need to stick with the downstream U-Boot for the time being. This has a couple of shortcomings itself, such as that it doesn't properly pass the MAC address to the kernel (but the kernel can generate a random one, so networking should still work).
The upstream Linux kernel does not implement EMC frequency scaling as of next-20190318. This is being worked on and may be ready in time for Linux v5.2. Until then the kernel won't be able to change the memory frequency and run at the default of 408 MHz. This creates some restrictions on the use-cases. One example that is known not to work is using the GPU to render a UHD resolution image and displaying it over HDMI at 60 Hz. The lack of bandwidth will cause the display controller FIFOs to underrun and contents will likely not be recognizable. FHD resolution at 60 Hz is known to work, though and UHD at 30 Hz may also work, but is untested as of this writing.
DisplayPort support is currently not supported upstream. This is being worked on and may be ready for Linux v5.2, though v5.3 is more likely.
If you get stuck anywhere in the above, feel free to let me know. You can reach me, as well as other people working on upstream support via email or on IRC (#tegra on Freenode).
To help troubleshoot issues, you might want to add one or more of the following kernel command-line parameters:
- earlycon=uart8250,mmio32,0x70006000 earlyprintk: Enable debug UART
output early during the boot process. This is useful to diagnose problems that appear to be hangs with no output to the serial console at all.
- ignore_loglevel: ignore kernel message log level (useful to see more