Difference between revisions of "Kernel-with-device-tree"

From ArmadeusWiki
Jump to: navigation, search
(dtb)
(info already elsewhere)
 
(45 intermediate revisions by 4 users not shown)
Line 1: Line 1:
 
=Background=
 
=Background=
  
The idea behind device tree is quite simple.  
+
The idea behind device tree is quite simple. When the kernel starts, it needs to initialize the drivers for the devices on the board. But often on embedded systems, devices can't be discover at running time. In this case, the Linux kernel has a C "machine" file that initializes/describes the devices for the board. So the kernel must be modified/compiled for each board.  
When the kernel start he needs to initialize the driver for the device on the board. But often on embedded,
+
device can't be discover at running time. In this case, the linux kernel has a c file that initialize the driver
+
for the board. So the kernel must be modified/compiled for each board.  
+
  
Another way is to provide a small file that describe the board to the linux kernel. When the kernel start, it reads
+
Another way is to provide a small file that describes the board to the Linux kernel. When the kernel start, it reads this file (called dtb for Device Tree Binary) to know the devices on the board, and initializes useful drivers.  
this file (called dtb for Device Tree Binary) to know the device on the board, and initialize usefull drivers.  
+
  
 
+
Some informations on device tree may be found here:
Some information on device tree may be found here:
+
 
* http://elinux.org/Device_Trees
 
* http://elinux.org/Device_Trees
 
* http://devicetree.org/Main_Page
 
* http://devicetree.org/Main_Page
Line 18: Line 13:
 
=Compilation=
 
=Compilation=
  
To use device tree on arm both bootloader (u-boot) and kernel should  
+
To use device tree on ARM platforms, both bootloader (U-Boot) and kernel (Linux) should be compiled with the support of device tree.
be compiled with the support of device tree.
+
  
==u-boot==
+
==U-Boot==
'''NOTE: The APF27/U-boot 2012.04.01 patch 3.6, APF28/U-Boot 2012.04.01 patch 1.5 and APF51/U-Boot 2012.04.01 patch 1.5 are already configured to support device tree.'''
+
{{Note|The APF27/U-boot 2012.04.01 patch 3.6, APF28/U-Boot 2012.04.01 patch 1.5, APF51/U-Boot 2012.04.01 patch 1.5 and APF6/All U-Boots are already configured to support device tree.}}
 +
* If you have an older U-Boot, instructions are kept [[Talk:Kernel-with-device-tree|here]].
  
To enable device tree on u-boot, it's quite simple:
+
==Linux==
* add "#define CONFIG_OF_LIBFDT" in the u-boot configuration file (include/configs/<board>.h).
+
  
On armadeus SDK, this file is in this directory: buildroot/target/device/armadeus/<board>/<board>-u-boot-<version>.h
+
The 3.4+ kernels have already the Device Tree support for some ARM SoC.
 +
* i.mxl (apf9328) : no
 +
* i.mx27 (apf27) : yes
 +
* i.mx51 (apf51) : yes
 +
* i.mx28 ([[APF28]]) : yes
 +
* i.mx6 ([[APF6]]) : yes
 +
* i.mx6ul ([[OPOS6UL]]) : yes
  
For example, for u-boot 2012.04 on apf27, it's: buildroot/target/device/armadeus/apf27/apf27-u-boot-2012.04.h
+
Nothing else needs to be done, because the kernel image is build by the armadeus SDK with the "make" command.
  
Nothing else needs to be done, because the u-boot image is build by the armadeus SDK with the command "make".
+
* Starting with 3.8+ kernels, multi arch support is activated for i.MX(1/2/3/5) processors and so ''loadaddr'' should be given at ''uImage'' build time:
 +
<pre class="host">
 +
$ make linux LOADADDR=0xA0008000      (APF27)
  
NOTE: on u-boot 2012.04, the command bootm with device tree is broken. If you want to use it,
+
$ make linux LOADADDR=0x40008000      (APF28)
  
you need to fix it with the following patch: http://git.denx.de/?p=u-boot.git;a=commit;h=1723997610ace497252d6f9a44ec76c06951ae43
+
$ make linux LOADADDR=0x90008000      (APF51)
 
+
</pre>
NOTE2: it's fixed on u-boot 2012.04.01 that's the current (since June 2012) release used on all the APF boards.
+
* or configured inside Buildroot (2013.05+), here for [[APF51]]:
 
+
<pre class="host">
==kernel==
+
$ make menuconfig
 
+
</pre>
The kernel 3.4 has already the support of some arm SoC.
+
<pre class="config">
 
+
    Kernel  --->
* imxl (apf9328) : no
+
        (0x90008000) load address (for 3.7+ multi-platform image)
* imx27 (apf27) : yes
+
</pre>
* imx51 (apf51) : yes
+
* imx28 (apf28) : yes
+
 
+
The configuration file should have:
+
* CONFIG_MACH_IMX27_DT (on apf27)
+
* CONFIG_MACH_IMX51_DT (on apf51)
+
* CONFIG_SERIAL_IMX
+
* CONFIG_SERIAL_IMX_CONSOLE
+
 
+
Nothing else needs to be done, because the kernel image is build by the armadeus SDK with the command "make".
+
  
 
==dtb==
 
==dtb==
Line 60: Line 52:
 
A dtb (Device Tree Binary) file is created from a dts (Device Tree Source) file.
 
A dtb (Device Tree Binary) file is created from a dts (Device Tree Source) file.
  
The kernel has already the support of device tree for imx27 (apf27), imx28 (apf28) and imx51 (apf51).
+
The 3.8+ kernel already have the support of device tree for all Armadeus platforms except [[APF9328]].
  
But both board (apf28 and apf51) hasn't a dts file. So a file <board>.dts must be added
+
If your board hasn't a dts file, a ''<board>.dts'' must be added in the directory ''arch/arm/boot/dts/'' of the linux kernel.
to in the directory arch/arm/boot/dts of the linux kernel.
+
  
The armadeus SDK don't have support for dtb image generation. So you have to do it yourself.
+
Only recent Buildroot have direct support for dtb image generation (example for APF51):
* go to the directory buildroot/output/build/linux-<version>
+
<pre class=host>
* add the file <soc>-<board>.dts the directory arch/arm/boot/dts/
+
$ make menuconfig
* build the dtb with the command: make ARCH=arm <soc>-<board>.dtb
+
</pre>
 +
<pre class=config>
 +
Kernel  --->
 +
    ...
 +
    [*]  Device tree support
 +
          Device tree source (Use a device tree present in the kernel.)  --->
 +
          (imx51-apf51dev) Device Tree Source file names
 +
</pre>
  
The file <soc>-<board>.dtb should appear in arch/arm/boot
+
If your armadeus SDK/BSP doesn't have support for dtb image generation, you will have to do it yourself:
 +
* go to the directory ''buildroot/output/build/linux-<version>''
 +
* add the file <soc>-<board>.dts the directory ''arch/arm/boot/dts/''
 +
* build the dtb with the command:
 +
<pre class=host>
 +
$ make ARCH=arm CROSS_COMPILE=../../host/usr/bin/arm-linux- <soc>-<board>.dtb
 +
</pre>
  
=Running=
+
The file <soc>-<board>.dtb should then appear in ''arch/arm/boot/''. Copy it to your TFTP directory:
 +
<pre class=host>
 +
$ cp buildroot/output/build/linux-3.5-rc5/arch/arm/boot/imx28-apf28.dtb /tftpboot/apf28.dtb
 +
</pre>
  
 +
by naming your dtb file in /tftpboot apfXX.dtb you will be able to use the U-Boot 2013.03 scripts download_dtb, flash_dtb and update_dtb. These scripts are equivalent to usual kernel scripts download_kernel, flash_kernel and update_kernel.
  
Start the u-boot previously compiled, and then :
+
=Running=
  
* load the kernel in memory
+
==Boot Linux manually (deprecated)==
* load the dtb in memor
+
* Infos are kept [[Talk:Kernel-with-device-tree|here]].
* run the command bootm with 3 arguments: <kernel addr> - <dtb addr>
+
  
The second argument is "-", it means that there isn't an initrd to load.
+
==Boot Linux using U-Boot scripts==
 
+
On the APF27/28/51, [[APF6]] and [[OPOS6UL]] with the latest U-Boot version things are even simpler:
For example, it should be something like this:
+
* Device Tree can be loaded from the Flash/eMMC memory
 +
* The variable fdt_addr_r defines the RAM address to load the DTB structure and will be used to notify the kernel of the DT location in RAM
 +
** APF27: Set the fdt_addr_r to A1000000
 +
** APF28: set the fdt_addr_r to 41000000
 +
** APF51: set the fdt_addr_r to 91000000
 +
** [[APF6]]: fdt_addr is set to 0x18000000 by default
 +
** [[OPOS6UL]]: fdt_addr is set to 0x88000000 by default
 +
* Some scripts are available to update the dtb partition:
 +
** ''download_dtb'' (download the dtb into the RAM from your local network)
 +
** ''flash_dtb'' (transfer a dtb from RAM to flash)
 +
** ''update_dtb'' (download and flash a dtb)
 +
* the boot scripts ''ubifsboot'', ''nfsboot'' and ''mmcboot'' support booting a kernel with a DT
  
 +
Here is the example on the [[APF27]]:
 
<pre class="apf">
 
<pre class="apf">
 
BIOS> setenv consoledev ttymxc0
 
BIOS> setenv consoledev ttymxc0
BIOS> setenv baudrate 115200
+
BIOS> setenv fdt_addr_r a1000000
BIOS> setenv dtbaddr 0xa0800000
+
BIOS> saveenv
BIOS> tftp $loadaddr apf27-linux.bin
+
BIOS> run update_kernel
BIOS> tftp $dtbaddr imx27-apf27.dtb
+
BIOS> run update_dtb
BIOS> setenv consoledev ttymxc0
+
BIOS> boot
BIOS> setenv console console=$consoledev,115200
+
BIOS> setenv bootargs ${console} earlyprintk
+
BIOS> run addnfsargs addipargs
+
BIOS> bootm $loadaddr - $dtbaddr
+
 
</pre>
 
</pre>
  
On the APF27, 28 and 51 with the latest U-Boot version things are even simpler:
+
Here is the example on the [[APF51]]:
- Device Tree can be loaded from the Flash memory
+
<pre class="apf">
- The variable fdt_addr_r defines the RAM address to load the DTB structure and will be used to notify the kernel of the DT location in RAM
+
BIOS> setenv consoledev ttymxc2
- APF27: Set the fdt_addr_r to A1000000 - APF28: set the fdt_addr_r to 41000000
+
BIOS> setenv fdt_addr_r 91000000
- Some scripts are availaible to update the dtb partition: download_dtb (download the dtb in RAM from your local network) - flash_dtb (tranfert a dtb from RAM to flash) - update_dtb (download and flash a dtb)
+
BIOS> saveenv
- the boot scripts ubifsboot, nfsboot and mmcboot support to boot a kernel with a DT
+
BIOS> run update_kernel
 +
BIOS> run update_dtb
 +
BIOS> boot
 +
</pre>
  
Here is the example on the apf27:
+
Here is the example on the [[APF28]]:
 
<pre class="apf">
 
<pre class="apf">
BIOS> setenv consoledev ttymxc0
+
BIOS> setenv consoledev ttyAMA0
BIOS> setenv fdt_addr_r a1000000 (with the apf27 - 41000000 with an apf28 - 91000000 with an apf51 )
+
BIOS> setenv fdt_addr_r 41000000
 +
BIOS> saveenv
 
BIOS> run update_kernel
 
BIOS> run update_kernel
 
BIOS> run update_dtb
 
BIOS> run update_dtb
BIOS> run nfsboot (and ubifsboot as soon as the nand is supported in the DT)
+
BIOS> boot
 +
</pre>
 +
 
 +
===Remove DT boot===
 +
* just in case you want to come back to normal boot:
 +
<pre class="apf">
 +
BIOS> setenv fdt_addr_r
 +
BIOS> saveenv
 +
</pre>
 +
 
 +
=Runtime changes=
 +
==U-Boot==
 +
U-boot has support for live device tree content modifying through ''fdt'' command set. Following instructions apply for [[OPOS6UL]] and show how to change USB functionality of USB OTG connector (from "otg" to "host") of [[OPOS6ULDev]].
 +
<pre class="apf">
 +
BIOS> load mmc ${mmcdev}:${mmcpart} ${fdt_addr} /boot/imx6ul-${fdt_name}.dtb
 +
BIOS> fdt addr ${fdt_addr}
 +
 
 +
BIOS> fdt get value toto /soc/aips-bus@02100000/usb@02184000/ dr_mode
 +
BIOS> printenv toto
 +
BIOS> fdt resize
 +
 
 +
BIOS> fdt set /soc/aips-bus@02100000/usb@02184000/ dr_mode host
 +
 
 +
# Remove loading of device tree from emmcboot command, as we already loaded it:
 +
BIOS> setenv emmcboot 'run initargs; run addmmcargs; load mmc ${mmcdev}:${mmcpart} ${loadaddr} /boot/${kernelimg} && bootz ${loadaddr} - ${fdt_addr};'
 +
 
 +
BIOS> boot
 
</pre>
 
</pre>

Latest revision as of 09:20, 16 September 2020

Background

The idea behind device tree is quite simple. When the kernel starts, it needs to initialize the drivers for the devices on the board. But often on embedded systems, devices can't be discover at running time. In this case, the Linux kernel has a C "machine" file that initializes/describes the devices for the board. So the kernel must be modified/compiled for each board.

Another way is to provide a small file that describes the board to the Linux kernel. When the kernel start, it reads this file (called dtb for Device Tree Binary) to know the devices on the board, and initializes useful drivers.

Some informations on device tree may be found here:

Compilation

To use device tree on ARM platforms, both bootloader (U-Boot) and kernel (Linux) should be compiled with the support of device tree.

U-Boot

Note Note: The APF27/U-boot 2012.04.01 patch 3.6, APF28/U-Boot 2012.04.01 patch 1.5, APF51/U-Boot 2012.04.01 patch 1.5 and APF6/All U-Boots are already configured to support device tree.
  • If you have an older U-Boot, instructions are kept here.

Linux

The 3.4+ kernels have already the Device Tree support for some ARM SoC.

  • i.mxl (apf9328) : no
  • i.mx27 (apf27) : yes
  • i.mx51 (apf51) : yes
  • i.mx28 (APF28) : yes
  • i.mx6 (APF6) : yes
  • i.mx6ul (OPOS6UL) : yes

Nothing else needs to be done, because the kernel image is build by the armadeus SDK with the "make" command.

  • Starting with 3.8+ kernels, multi arch support is activated for i.MX(1/2/3/5) processors and so loadaddr should be given at uImage build time:
$ make linux LOADADDR=0xA0008000       (APF27)

$ make linux LOADADDR=0x40008000       (APF28)

$ make linux LOADADDR=0x90008000       (APF51)
  • or configured inside Buildroot (2013.05+), here for APF51:
$ make menuconfig
    Kernel  --->
        (0x90008000) load address (for 3.7+ multi-platform image)

dtb

A dtb (Device Tree Binary) file is created from a dts (Device Tree Source) file.

The 3.8+ kernel already have the support of device tree for all Armadeus platforms except APF9328.

If your board hasn't a dts file, a <board>.dts must be added in the directory arch/arm/boot/dts/ of the linux kernel.

Only recent Buildroot have direct support for dtb image generation (example for APF51):

$ make menuconfig
Kernel  --->
    ...
    [*]   Device tree support
          Device tree source (Use a device tree present in the kernel.)  --->
          (imx51-apf51dev) Device Tree Source file names

If your armadeus SDK/BSP doesn't have support for dtb image generation, you will have to do it yourself:

  • go to the directory buildroot/output/build/linux-<version>
  • add the file <soc>-<board>.dts the directory arch/arm/boot/dts/
  • build the dtb with the command:
$ make ARCH=arm CROSS_COMPILE=../../host/usr/bin/arm-linux- <soc>-<board>.dtb

The file <soc>-<board>.dtb should then appear in arch/arm/boot/. Copy it to your TFTP directory:

$ cp buildroot/output/build/linux-3.5-rc5/arch/arm/boot/imx28-apf28.dtb /tftpboot/apf28.dtb

by naming your dtb file in /tftpboot apfXX.dtb you will be able to use the U-Boot 2013.03 scripts download_dtb, flash_dtb and update_dtb. These scripts are equivalent to usual kernel scripts download_kernel, flash_kernel and update_kernel.

Running

Boot Linux manually (deprecated)

  • Infos are kept here.

Boot Linux using U-Boot scripts

On the APF27/28/51, APF6 and OPOS6UL with the latest U-Boot version things are even simpler:

  • Device Tree can be loaded from the Flash/eMMC memory
  • The variable fdt_addr_r defines the RAM address to load the DTB structure and will be used to notify the kernel of the DT location in RAM
    • APF27: Set the fdt_addr_r to A1000000
    • APF28: set the fdt_addr_r to 41000000
    • APF51: set the fdt_addr_r to 91000000
    • APF6: fdt_addr is set to 0x18000000 by default
    • OPOS6UL: fdt_addr is set to 0x88000000 by default
  • Some scripts are available to update the dtb partition:
    • download_dtb (download the dtb into the RAM from your local network)
    • flash_dtb (transfer a dtb from RAM to flash)
    • update_dtb (download and flash a dtb)
  • the boot scripts ubifsboot, nfsboot and mmcboot support booting a kernel with a DT

Here is the example on the APF27:

BIOS> setenv consoledev ttymxc0
BIOS> setenv fdt_addr_r a1000000
BIOS> saveenv
BIOS> run update_kernel
BIOS> run update_dtb
BIOS> boot

Here is the example on the APF51:

BIOS> setenv consoledev ttymxc2
BIOS> setenv fdt_addr_r 91000000
BIOS> saveenv
BIOS> run update_kernel
BIOS> run update_dtb
BIOS> boot

Here is the example on the APF28:

BIOS> setenv consoledev ttyAMA0
BIOS> setenv fdt_addr_r 41000000
BIOS> saveenv
BIOS> run update_kernel
BIOS> run update_dtb
BIOS> boot

Remove DT boot

  • just in case you want to come back to normal boot:
BIOS> setenv fdt_addr_r
BIOS> saveenv

Runtime changes

U-Boot

U-boot has support for live device tree content modifying through fdt command set. Following instructions apply for OPOS6UL and show how to change USB functionality of USB OTG connector (from "otg" to "host") of OPOS6ULDev.

BIOS> load mmc ${mmcdev}:${mmcpart} ${fdt_addr} /boot/imx6ul-${fdt_name}.dtb
BIOS> fdt addr ${fdt_addr}

BIOS> fdt get value toto /soc/aips-bus@02100000/usb@02184000/ dr_mode
BIOS> printenv toto
BIOS> fdt resize

BIOS> fdt set /soc/aips-bus@02100000/usb@02184000/ dr_mode host

# Remove loading of device tree from emmcboot command, as we already loaded it:
BIOS> setenv emmcboot 'run initargs; run addmmcargs; load mmc ${mmcdev}:${mmcpart} ${loadaddr} /boot/${kernelimg} && bootz ${loadaddr} - ${fdt_addr};'

BIOS> boot