Colibri T20 upstream Linux kernel

This article shows how to use a recent mainline/upstream Linux kernel on Toradex Colibri T20. Although Toradex provides a Linux BSP (based on L4T Kernel 3.1), there are reasons to use a mainline Linux kernel. Most prominent is to get a recent version of the Kernel itself, along with updated and new drivers. Having mainline support also might lead to having Distribution support in future, such as Debian or Fedora.

However, the mainline Linux kernel for Tegra 2 is not feature complete, especially proper DFVS (dynamic frequency and voltage scaling), NAND flash driver and a hardware accelerated 3D driver are missing. There are efforts reverse engineering the Tegra 2/3 graphic stack (see grate).

This how-to wipes the whole module, including the configuration block which contains serial number and MAC address. Its possible to restore those information using Toradex BSP and the utility. Since Toradex Tegra modules are not locked by a manufacturer key, one can use nvflash or tegrarcm to access the Boot ROM and reflash the device (see also this Blog post about that topic). The modules are, from a flashing perspective, unbrickable!

Ok, lets get started. Make sure you have a Linux cross compile toolchain for ARM ready (e.g. from Linaro) along with a device tree compiler (DTC).


We start with cloning U-Boot and checkout latest release of it:

$ mkdir ~/toradex-mainline && cd ~/toradex-mainline
$ git clone git://
$ cd u-boot
$ git checkout v2014.01
$ git checkout -b colibri-t20

In order to access NAND, one patch is required which did not made it upstream so far. The second patch enabled ext4 file system which we need to load the kernel directly from the root file system later.

$ wget
$ tar xzf colibri-t20-u-boot-patches.tar.gz
$ git am *.patch

In the next step we configure and compile U-Boot. Although the configuration is for the Iris Carrier Board, U-Boot works fine on the Colibri Evaluation board too.

$ export CROSS_COMPILE=~/gcc-linaro/bin/arm-linux-gnueabihf-
$ export ARCH=arm
$ make colibri_t20_iris_config
Configuring for colibri_t20_iris board...
$ make -j 8

In order to flash U-Boot you need the utilities tegrarcm and cbootimage. Both are open source and differ from what NVIDIA uses in its L4T project. Ubuntu has them in the universe repository (cbootimage, tegrarcm). Alternatively you can build them from source directly (cbootimage, tegrarcm). To run and flash U-Boot we need configuration files. The cbootimage-configs repository on Github holds configuration files for several Tegra based products in one repository, get a clone of it:

$ cd ~/toradex-mainline
$ git clone
$ cd cbootimage-configs

Now we create a BCT and an image containing BCT and U-Boot, hence we need to copy the U-Boot binary to the current directory. Its crucial to pick the right configuration file, check the colibri-t20 folder. Also note the slightly different command options and configuration files for these two steps!

$ cbootimage -gbct -t20 tegra20/toradex/colibri-t20/colibri-t20_512_v12_nand.bct.cfg colibri-t20_512_v12_nand.bct
New BCT file colibri-t20_512_v12_nand.bct has been successfully generated!
$ cp ../u-boot/u-boot-dtb-tegra.bin u-boot.bin
$ cbootimage -t20 tegra20/toradex/colibri-t20/colibri-t20_512_v12_nand.img.cfg colibri-t20_512_v12_nand.img
Image file colibri-t20_512_v12_nand.img has been successfully generated!

Put your module into recover mode. Using the tegrarcm utility we can communicate with the Boot ROM. The BCT helps the Boot ROM to configure the hardware (e.g. memory controller). Then, tegrarcm transfers U-Boot directly into RAM and runs it.You should see a starting U-Boot on your serial console after this command:

$ tegrarcm --bct colibri-t20_512_v12_nand.bct --loadaddr=0x00108000 --bootloader=../u-boot/u-boot-dtb-tegra.bin

Now lets flash U-Boot to NAND. We cannot flash U-Boot itself directly, since the Boot ROM needs a valid BCT to start. This is where the generated image from above comes in. I use TFTP to transfer the image. Copy it to the shared folder…

$ sudo cp colibri-t20_512_v12_nand.img /srv/tftp/

…and transfer it to your device:

Tegra20 (Colibri) # usb start
(Re)start USB...
scanning bus 0 for devices... 1 USB Device(s) found
scanning bus 1 for devices... 1 USB Device(s) found
scanning bus 2 for devices... 2 USB Device(s) found
 scanning usb for storage devices... 0 Storage Device(s) found
 scanning usb for ethernet devices... 1 Ethernet Device(s) found
Tegra20 (Colibri) # setenv ipaddr; setenv serverip 
Tegra20 (Colibri) # tftpboot 0x02100000 colibri-t20_512_v12_nand.img
Waiting for Ethernet connection... done.
Using asx0 device
TFTP from server; our IP address is
Filename 'colibri-t20_512_v12_nand.img'.
Load address: 0x02100000
Loading: ##################################################
         3.6 MiB/s
Bytes transferred = 729088 (b2000 hex)
Tegra20 (Colibri) #

Now lets flash it to the NAND device. Note the length of the image from the transfer above (0xb2000):

Tegra20 (Colibri) # nand erase.chip

NAND erase.chip: device 0 whole chip
Erasing at 0x3ffc0000 -- 100% complete.
Tegra20 (Colibri) # nand write 0x02100000 0 0xb2000

NAND write: device 0 offset 0x0, size 0x95000
 577536 bytes written: OK

Reset the module. Your new U-Boot should now appear by itself.

Linux Kernel

This was the hard part. Now we have a recent U-Boot on our target, lets boot a kernel using it. First, clone Linux and checkout a recent version (3.13 or later is recommended, it contains some fixes solving issues with the PMIC on newer module revisions). We can use the default Tegra configuration.

$ cd ~/toradex-mainline
$ git clone git://
$ cd linux
$ git checkout v3.13
$ make tegra_defconfig
$ make -j 8

Ok, now we can boot that kernel over TFTP, just to make sure the kernel works:

$ sudo cp arch/arm/boot/zImage /srv/tftp/
$ sudo cp arch/arm/boot/dts/tegra20-iris-512.dtb /srv/tftp
Tegra20 (Colibri) # usb start
Tegra20 (Colibri) # setenv ipaddr; setenv serverip 
Tegra20 (Colibri) # tftpboot ${kernel_addr_r} zImage 
Tegra20 (Colibri) # tftpboot ${fdt_addr_r} tegra20-iris-512.dtb 
Tegra20 (Colibri) # set bootargs console=ttyS0,115200
Tegra20 (Colibri) # bootz ${kernel_addr_r} - ${fdt_addr_r}

[ 1.693098] VFS: Cannot open root device "(null)" or unknown-block(0,0): error -6
[ 1.700635] Please append a correct "root=" boot option; here are the available partitions:

This is the expected “graceful” Kernel panic, which tells us that there is no root file system specified…

Linux Root Filesystem

I choose a Fedora root file system. Since there is no NAND driver in the Linux kernel, I put the root file system on a SD-Card. I followed basically the official Fedora ARM Installation instructions. Download a prepared root file system from and put it on a SD-Card with at least 4GB capacity:

$ xzcat Fedora-Xfce-armhfp-20-1-sda.raw.xz > /dev/mmcblk0

Although, the instruction state that a installer should show up on startup, it didn’t when I tried it. Therefor I cleared the root password completely in the shadow file after reinserting the card (remove the hash after root:).

$ vi /run/media/sag/__/etc/shadow

Copy the kernel and the device tree binary directly into the boot partition. U-Boot automatically runs boot.scr on the boot partition, hence create a custom boot script to boot from SD-Card. The file need to be generated from a plain text file using mkimage. You can run this commands from your host (install u-boot-tools), or start the first time manually and create the script directly on the target (mkimage is preinstalled).

$ cd /run/media/sag/__boot/
$ cp ~/toradex-mainline/arch/arm/boot/dts/tegra20-iris-512.dtb .
$ cp ~/toradex-mainline/arch/arm/boot/zImage .
$ vi boot.cmd
... enter content from below...
$ mkimage -A arm -O linux -T script -C none -a 0 -e 0 -n "Custom" -d boot.cmd boot.scr

The boot.cmd content looks like this:

ext4load mmc 0 ${kernel_addr_r} zImage
ext4load mmc 0 ${fdt_addr_r} tegra20-iris-512.dtb
bootz ${kernel_addr_r} - ${fdt_addr_r}

Finally you should get a fully workable Desktop on the DVI/HDMI output:

Fedora 20 on Toradex Colibri T20

Fedora 20 on Toradex Colibri T20

Some thoughts:

  • On Github, Stephen Warren also maintains a Python flasher scripts which automates a lot of those commands. For better understanding whats going on, I prefer documenting the manual steps.
  • Using original U-Boot from Toradex to boot mainline Kernel does not work out of the Box. Some clocks are not initialized by that U-Boot version, which the mainline Kernel expects to be enabled.
  • Fedora contains a highly sophisticated boot script. However, I did not had a look into this and created directly my own for simplicity.
  • I also tried Arch Linux for ARM. There are tar.gz files which one can copy directly on a SD-Card.
  • I’m working on Colibri T30, altough those patches are not ready to be sent to the mailing list. Initial version can be found on my Git repository Don’t relay on those branches, I might change history!
  1. Thank you for this great tutorial. I am really looking forward to see Fedora running on my Colibri T20. I have been following it with some problems on the way, but I guess I fixed all of them because I got to the end of flashing U-Boot with no errors. The problem now is that after flashing NAND image of U-Boot with command
    nand write 0x02100000 0 0xb2000
    and restarting the module serial port stays silent. Even after succesfully re-running this command:
    tegrarcm --bct colibri-t20_512_v12_nand.bct --loadaddr=0x00108000 --bootloader=../u-boot/u-boot-dtb-tegra.bin
    I don’t get any output.
    If you know what’s wrong, please let me know.

  2. There could be many reasons why the serial port keeps silet: Maybe the ROM can’t load the image at all (correct BCT?), or U-Boot crashes at a very early stage… The latest official Toradex release uses cbootimage and tegrarcm too, along with U-Boot based on the 2015.04 release. My post on the other hand is more than a year old. I would recommend try to use the bootloader provided by Toradex.

  3. David Heidelberg

    After 6 years, tegra20 is in pretty good shape in mainline :mrgreen:

  4. Yes, I noticed, amazing work. A bit late, but still cool 🙂

Leave a Comment