Skip to contentSkip to conversation

Run-time configuration of U-Boot via a flat device tree (fdt)

RFC PATCH New Simon Glass 3 participants 11 messages Sep 1, 2011 – Sep 2, 2011

Subsystems (2)
lore
Share & tools
lore
#0 lore raw

cover Run-time configuration of U-Boot via a flat device tree (fdt)

At present in U-Boot configuration is mostly done using CONFIG options in the board file. This patch set aims to make it possible for a single U-Boot binary to support multiple boards, with the exact configuration of each board controlled by a flat device tree (fdt). This is the approach recently taken by the ARM Linux kernel and has been used by PowerPC for some time.

The fdt is a convenient vehicle for implementing run-time configuration for three reasons. Firstly it is easy to use, being a simple text file. It is extensible since it consists of nodes and properties in a nice hierarchical format.

Finally, there is already excellent infrastructure for the fdt: a compiler checks the text file and converts it to a compact binary format, and a library is already available in U-Boot (libfdt) for handling this format.

To read about fdts, take a look at the specification here:

https://www.power.org/resources/downloads/Power_ePAPR_APPROVED_v1.0.pdf

You also might find this section of the Linux kernel documentation useful:
(access this in the Linux kernel source code)

Documentation/devicetree/booting-without-of.txt

To use this patch set you will need to get the device tree compiler here:

git://jdl.com/software/dtc.git

and add some defines to your board (only ARM is currently supported):

#define CONFIG_OF_CONTROL (to enable run-time config control via fdt)
#define CONFIG_OF_EMBED or CONFIG_OF_SEPARATE
(either build the fdt blob into U-Boot, or create a separate u-boot.dtb)
#define CONFIG_DEFAULT_DEVICE_TREE "<your name>"
(to specify the name of the device tree file is
board/<vendor>/<board>/<your name>.dts)

This patch set does not include any drivers which actually use the fdt. I have some concerns about spreading fdt code around the U-Boot code base so am thinking of having a support file which makes this easier. I can provide a UART driver modified to use fdt if there is interest.

It is important to understand that the fdt only selects options available in the platform / drivers. It cannot add new drivers (yet). So you must still have the CONFIG option to enable the driver. For example, you need to define CONFIG_SYS_NS16550 to bring in the NS16550 driver, but can use the fdt to specific the UART clock, peripheral address, etc. In very broad terms, the CONFIG options in general control *what* driver files are pulled in, and the fdt controls *how* those files work.

While only ARM is supported in this patch series, it should be easy enough to add support for other architectures.

Simon Glass (4):
fdt: ARM: Add device tree control of U-Boot (CONFIG_OF_CONTROL)
fdt: Add support for embedded device tree (CONFIG_OF_EMBED)
fdt: Add support for a separate device tree (CONFIG_OF_SEPARATE)
fdt: ARM: Implement embedded and separate device tree

 .gitignore                         |    1 +
 Makefile                           |    9 ++
 README                             |   25 ++++++
 arch/arm/include/asm/global_data.h |    1 +
 arch/arm/lib/board.c               |   22 +++++
 config.mk                          |    1 +
 doc/README.fdt-control             |  168 ++++++++++++++++++++++++++++++++++++
 dts/Makefile                       |  100 +++++++++++++++++++++
 include/common.h                   |    1 +
 9 files changed, 328 insertions(+), 0 deletions(-)
 create mode 100644 doc/README.fdt-control
 create mode 100644 dts/Makefile
Signature · 1 line
1.7.3.1
#1 lore raw

RFC PATCH 1/4 fdt: ARM: Add device tree control of U-Boot (CONFIG_OF_CONTROL)

This adds a device tree pointer to the global data. It can be set by board code. A later commit will add support for embedding it in U-Boot.

---
 README                             |   11 +++++++++++
 arch/arm/include/asm/global_data.h |    1 +
 2 files changed, 12 insertions(+), 0 deletions(-)
README +11 -0
index 0886987..812805f 100644
@@ -795,6 +795,17 @@ The following options need to be configured:
 
 		XXX - this list needs to get updated!
 
+- Device tree:
+		CONFIG_OF_CONTROL
+		If this variable is defined, U-Boot will use a device tree
+		to configure its devices, instead of relying on statically
+		compiled #defines in the board file. This option is
+		experimental and only available on a few boards. The device
+		tree is available in the global data as gd->blob.
+
+		U-Boot needs to get its device tree from somewhere. This will
+		be enabled in a future patch.
+
 - Watchdog:
 		CONFIG_WATCHDOG
 		If this variable is defined, it enables watchdog
arch/arm/include/asm/global_data.h +1 -0
index 4fc51fd..818eced 100644
@@ -73,6 +73,7 @@ typedef	struct	global_data {
 #if !(defined(CONFIG_SYS_ICACHE_OFF) && defined(CONFIG_SYS_DCACHE_OFF))
 	unsigned long	tlb_addr;
 #endif
+	const void	*blob;		/* Our device tree, NULL if none */
 	void		**jt;		/* jump table */
 	char		env_buf[32];	/* buffer for getenv() before reloc. */
 } gd_t;
Signature · 1 line
1.7.3.1
#2 lore raw

RFC PATCH 1/4 fdt: ARM: Add device tree control of U-Boot (CONFIG_OF_CONTROL)

arch/arm/include/asm/global_data.h

Quoted 4 lines · On Thursday, September 01, 2011 16:49:06 Simon Glass wrote:
arch/arm/include/asm/global_data.h +1 -0
 
+	const void	*blob;		/* Our device tree, NULL if none */

let's call it "fdt_blob" or something less generic than "blob"
-mike
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 836 bytes
Desc: This is a digitally signed message part.
Url : http://lists.denx.de/pipermail/u-boot/attachments/20110902/8b256d34/attachment.pgp

#3 lore raw

RFC PATCH 1/4 fdt: ARM: Add device tree control of U-Boot (CONFIG_OF_CONTROL)

Hi Mike,

Quoted 9 lines · Mike Frysinger

arch/arm/include/asm/global_data.h

Quoted 4 lines · On Thursday, September 01, 2011 16:49:06 Simon Glass wrote:
arch/arm/include/asm/global_data.h +1 -0
 
+ ? ? const void ? ? ?*blob; ? ? ? ? ?/* Our device tree, NULL if none */

let's call it "fdt_blob" or something less generic than "blob" -mike

OK, will change to fdt_blob within the global data.

Regards,
Simon

#4 lore raw

RFC PATCH 2/4 fdt: Add support for embedded device tree (CONFIG_OF_EMBED)

In reply to Simon Glass

This new option allows U-Boot to embed a binary device tree into its image to allow run-time control of peripherals. This device tree is for U-Boot's own use and is not necessarily the same one as is passed to the kernel.

The device tree compiler output should be placed in the $(obj) rooted tree. Since $(OBJCOPY) insists on adding the path to the generated symbol names, to ensure consistency it should be invoked from the directory where the .dtb file is located and given the input file name without the path.

This commit contains my entry for the ugliest Makefile / shell interaction competition.

---
 Makefile         |    4 ++
 README           |   11 +++++-
 config.mk        |    1 +
 dts/Makefile     |  100 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 include/common.h |    1 +
 5 files changed, 115 insertions(+), 2 deletions(-)
 create mode 100644 dts/Makefile
Makefile +4 -0
index 03d80b7..c53d573 100644
@@ -224,6 +224,9 @@ endif
 ifeq ($(CPU),ixp)
 LIBS += arch/arm/cpu/ixp/npe/libnpe.o
 endif
+ifeq ($(CONFIG_OF_EMBED),y)
+LIBS += dts/libdts.o
+endif
 LIBS += arch/$(ARCH)/lib/lib$(ARCH).o
 LIBS += fs/cramfs/libcramfs.o fs/fat/libfat.o fs/fdos/libfdos.o fs/jffs2/libjffs2.o \
 	fs/reiserfs/libreiserfs.o fs/ext2/libext2fs.o fs/yaffs2/libyaffs2.o \
@@ -1045,6 +1048,7 @@ clobber:	clean
 	@rm -f $(obj)u-boot.kwb
 	@rm -f $(obj)u-boot.imx
 	@rm -f $(obj)u-boot.ubl
+	@rm -f $(obj)u-boot.dtb
 	@rm -f $(obj)tools/{env/crc32.c,inca-swap-bytes}
 	@rm -f $(obj)arch/powerpc/cpu/mpc824x/bedbug_603e.c
 	@rm -fr $(obj)include/asm/proc $(obj)include/asm/arch $(obj)include/asm
README +9 -2
index 812805f..5a2f060 100644
@@ -803,8 +803,15 @@ The following options need to be configured:
 		experimental and only available on a few boards. The device
 		tree is available in the global data as gd->blob.
 
-		U-Boot needs to get its device tree from somewhere. This will
-		be enabled in a future patch.
+		U-Boot needs to get its device tree from somewhere. At present
+		the only way is to embed it in the image with CONFIG_OF_EMBED.
+
+		CONFIG_OF_EMBED
+		If this variable is defined, U-Boot will embed a device tree
+		binary in its image. This device tree file should be in the
+		board directory and called <soc>-<board>.dts. The binary file
+		is then picked up in board_init_f() and made available through
+		the global data structure as gd->blob.
 
 - Watchdog:
 		CONFIG_WATCHDOG
config.mk +1 -0
index e2b440d..6e61eb6 100644
@@ -124,6 +124,7 @@ STRIP	= $(CROSS_COMPILE)strip
 OBJCOPY = $(CROSS_COMPILE)objcopy
 OBJDUMP = $(CROSS_COMPILE)objdump
 RANLIB	= $(CROSS_COMPILE)RANLIB
+DTC	= dtc
 
 #########################################################################
 
dts/Makefile new file +100 -0

100 lines not on this page · raw message

include/common.h +1 -0
index 12a1074..2fd7ef5 100644
@@ -249,6 +249,7 @@ int	checkdram     (void);
 int	last_stage_init(void);
 extern ulong monitor_flash_len;
 int mac_read_from_eeprom(void);
+extern u8 _binary_dt_dtb_start[];	/* embedded device tree blob */
 
 /* common/flash.c */
 void flash_perror (int);
Signature · 1 line
1.7.3.1
#5 lore raw

RFC PATCH 3/4 fdt: Add support for a separate device tree (CONFIG_OF_SEPARATE)

In reply to Simon Glass

This adds support for an FDT to be build as a separate binary file called u-boot.dtb. This can be concatenated with the U-Boot binary to provide a device tree located at run-time by U-Boot.

---
 .gitignore             |    1 +
 Makefile               |    5 ++
 README                 |   11 +++-
 doc/README.fdt-control |  168 ++++++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 183 insertions(+), 2 deletions(-)
 create mode 100644 doc/README.fdt-control
.gitignore +1 -0
index dbf545f..c4ebd34 100644
@@ -34,6 +34,7 @@
 /u-boot.dis
 /u-boot.lds
 /u-boot.ubl
+/u-boot.dtb
 
 #
 # Generated files
Makefile +5 -0
index c53d573..3a36ef5 100644
@@ -352,9 +352,14 @@ ALL-$(CONFIG_ONENAND_U_BOOT) += $(obj)u-boot-onenand.bin
 ONENAND_BIN ?= $(obj)onenand_ipl/onenand-ipl-2k.bin
 ALL-$(CONFIG_MMC_U_BOOT) += $(obj)mmc_spl/u-boot-mmc-spl.bin
 ALL-$(CONFIG_SPL) += $(obj)spl/u-boot-spl.bin
+ALL-$(CONFIG_OF_SEPARATE) += $(obj)u-boot.dtb
 
 all:		$(ALL-y)
 
+$(obj)u-boot.dtb:	$(obj)u-boot
+		$(MAKE) -C dts binary
+		mv $(obj)dts/dt.dtb $@
+
 $(obj)u-boot.hex:	$(obj)u-boot
 		$(OBJCOPY) ${OBJCFLAGS} -O ihex $< $@
 
README +9 -2
index 5a2f060..0b8f338 100644
@@ -803,8 +803,8 @@ The following options need to be configured:
 		experimental and only available on a few boards. The device
 		tree is available in the global data as gd->blob.
 
-		U-Boot needs to get its device tree from somewhere. At present
-		the only way is to embed it in the image with CONFIG_OF_EMBED.
+		U-Boot needs to get its device tree from somewhere. This can
+		be done using one of the two options below:
 
 		CONFIG_OF_EMBED
 		If this variable is defined, U-Boot will embed a device tree
@@ -813,6 +813,13 @@ The following options need to be configured:
 		is then picked up in board_init_f() and made available through
 		the global data structure as gd->blob.
 
+		CONFIG_OF_SEPARATE
+		If this variable is defined, U-Boot will build a device tree
+		binary. It will be called u-boot.dtb. Architecture-specific
+		code will locate it at run-time. Generally this works by:
+
+			cat u-boot.bin u-boot.dtb >image.bin
+
 - Watchdog:
 		CONFIG_WATCHDOG
 		If this variable is defined, it enables watchdog
doc/README.fdt-control new file +168 -0

168 lines not on this page · raw message

Signature · 1 line
1.7.3.1
#6 lore raw

RFC PATCH 4/4 fdt: ARM: Implement embedded and separate device tree

In reply to Simon Glass

This locates the device tree either embedded within U-Boot or attached to the end as a separate binary.

When CONFIG_OF_CONTROL is defined, U-Boot requires a valid fdt. A check is provided for this early in initialisation.

---
 arch/arm/lib/board.c |   22 ++++++++++++++++++++++
 1 files changed, 22 insertions(+), 0 deletions(-)
arch/arm/lib/board.c +22 -0
index 14a56f6..1f4061e 100644
@@ -48,6 +48,7 @@
 #include <nand.h>
 #include <onenand_uboot.h>
 #include <mmc.h>
+#include <libfdt.h>
 
 #ifdef CONFIG_BITBANGMII
 #include <miiphy.h>
@@ -195,6 +196,17 @@ static int arm_pci_init(void)
 }
 #endif /* CONFIG_CMD_PCI || CONFIG_PCI */
 
+#ifdef CONFIG_OF_CONTROL
+static int check_fdt(void)
+{
+	/* We must have an fdt */
+	if (fdt_check_header(gd->blob))
+		panic("No valid fdt found - please append one to U-Boot\n"
+			"binary or define CONFIG_OF_EMBED\n");
+	return 0;
+}
+#endif
+
 /*
  * Breathe some life into the board...
  *
@@ -237,6 +249,9 @@ init_fnc_t *init_sequence[] = {
 #if defined(CONFIG_BOARD_EARLY_INIT_F)
 	board_early_init_f,
 #endif
+#ifdef CONFIG_OF_CONTROL
+	check_fdt,
+#endif
 	timer_init,		/* initialize timer */
 #ifdef CONFIG_FSL_ESDHC
 	get_clocks,
@@ -274,6 +289,13 @@ void board_init_f(ulong bootflag)
 	memset((void *)gd, 0, sizeof(gd_t));
 
 	gd->mon_len = _bss_end_ofs;
+#ifdef CONFIG_OF_EMBED
+	/* Get a pointer to the FDT */
+	gd->blob = _binary_dt_dtb_start;
+#elif defined CONFIG_OF_SEPARATE
+	/* FDT is at end of image */
+	gd->blob = (void *)(_end_ofs + _TEXT_BASE);
+#endif
 
 #ifdef CONFIG_MACH_TYPE
 	gd->bd->bi_arch_number = CONFIG_MACH_TYPE; /* board id for Linux */
Signature · 1 line
1.7.3.1
#7 lore raw

cover Run-time configuration of U-Boot via a flat device tree (fdt)

In reply to Simon Glass

Hi Simon,

Quoted 5 lines · Simon Glass

At present in U-Boot configuration is mostly done using CONFIG options in the board file. This patch set aims to make it possible for a single U-Boot binary to support multiple boards, with the exact configuration of each board controlled by a flat device tree (fdt). This is the approach recently taken by the ARM Linux kernel and has been used by PowerPC for some time.

Very exciting. I've thought about doing this for years, but never had the ambition (or time).

[snip]

Quoted 9 lines

and add some defines to your board (only ARM is currently supported):

#define CONFIG_OF_CONTROL (to enable run-time config control via fdt)
#define CONFIG_OF_EMBED or CONFIG_OF_SEPARATE
(either build the fdt blob into U-Boot, or create a separate u-boot.dtb)
#define CONFIG_DEFAULT_DEVICE_TREE "<your name>"
(to specify the name of the device tree file is
board/<vendor>/<board>/<your name>.dts)

Quoted 4 lines

This patch set does not include any drivers which actually use the fdt. I have some concerns about spreading fdt code around the U-Boot code base so am thinking of having a support file which makes this easier. I can provide a UART driver modified to use fdt if there is interest.

Please. A concrete reference is very useful, especially for discussion.

Quoted 7 lines

It is important to understand that the fdt only selects options available in the platform / drivers. It cannot add new drivers (yet). So you must still have the CONFIG option to enable the driver. For example, you need to define CONFIG_SYS_NS16550 to bring in the NS16550 driver, but can use the fdt to specific the UART clock, peripheral address, etc. In very broad terms, the CONFIG options in general control *what* driver files are pulled in, and the fdt controls *how* those files work.

Sounds reasonable and practical. One of the things u-boot struggles with is staying small (but it is nice to be able to make it all inclusive and big if you have the flash).

Quoted 2 lines

While only ARM is supported in this patch series, it should be easy enough to add support for other architectures.

Exercise left for the students. :-)

[snip]

Thanks!
gvb

#8 lore raw

cover Run-time configuration of U-Boot via a flat device tree (fdt)

Hi Jerry,

Quoted 13 lines · Jerry Van Baren

Hi Simon,

Quoted 9 lines · Simon Glass

At present in U-Boot configuration is mostly done using CONFIG options in the
board file. This patch set aims to make it possible for a single U-Boot binary to support multiple boards, with the exact configuration of each board
controlled by a flat device tree (fdt). This is the approach recently taken
by the ARM Linux kernel and has been used by PowerPC for some time.

Quoted 2 lines

Very exciting. ?I've thought about doing this for years, but never had the ambition (or time).

Thanks for your comments. Yes there was mention of it in the UBML a few years ago:

http://lists.denx.de/pipermail/u-boot/2008-August/038052.html

Quoted 4 lines · where Wolfgang

A much more powerful concept is to have U-Boot read and interpret the DT dynamically - only then can you use the same U-Boot binary image on different board configurations, which is an important feature for many board vendors.

This is basically what my patch set sets out to do.

Quoted 14 lines

[snip]

Quoted 11 lines

and add some defines to your board (only ARM is currently supported):

?#define CONFIG_OF_CONTROL ? ? ? (to enable run-time config control via fdt)
?#define CONFIG_OF_EMBED or CONFIG_OF_SEPARATE
? ? ?(either build the fdt blob into U-Boot, or create a separate u-boot.dtb)
?#define CONFIG_DEFAULT_DEVICE_TREE ? ?"<your name>"
? ? ?(to specify the name of the device tree file is
? ? ? board/<vendor>/<board>/<your name>.dts)

Quoted 7 lines
Quoted 5 lines

This patch set does not include any drivers which actually use the fdt. I have
some concerns about spreading fdt code around the U-Boot code base so am thinking of having a support file which makes this easier. I can provide a UART driver modified to use fdt if there is interest.

Please. ?A concrete reference is very useful, especially for discussion.

I will try to create a driver for something for which we have a device tree definition in the kernel. Will post to the list as an RFC.

Quoted 12 lines
Quoted 11 lines

It is important to understand that the fdt only selects options available in
the platform / drivers. It cannot add new drivers (yet). So you must still have the CONFIG option to enable the driver. For example, you need to define
CONFIG_SYS_NS16550 to bring in the NS16550 driver, but can use the fdt to specific the UART clock, peripheral address, etc. In very broad terms, the CONFIG options in general control *what* driver files are pulled in, and the
fdt controls *how* those files work.

Quoted 3 lines

Sounds reasonable and practical. ?One of the things u-boot struggles with is staying small (but it is nice to be able to make it all inclusive and big if you have the flash).

Yes to some extent this is a halfway house, but it is a way of introducing this feature without changing the way things currently work. I almost feel as if there are two types of configs, and perhaps the naming should recognize that (SELECT_ and CONFIG_?). No, I don't want to modify all the board files...

Quoted 6 lines
Quoted 4 lines

While only ARM is supported in this patch series, it should be easy enough to
add support for other architectures.

Exercise left for the students. ?:-)

Yes - you can pretty-much just copy the ARM board.c code into your board.c file to try this out.

Regards,
Simon

Quoted 6 lines

[snip]

Thanks!
gvb

#9 lore raw

cover Run-time configuration of U-Boot via a flat device tree (fdt)

In reply to Simon Glass
Quoted 7 lines · On Thursday, September 01, 2011 16:49:05 Simon Glass wrote:

At present in U-Boot configuration is mostly done using CONFIG options in the board file. This patch set aims to make it possible for a single U-Boot binary to support multiple boards, with the exact configuration of each board controlled by a flat device tree (fdt). This is the approach recently taken by the ARM Linux kernel and has been used by PowerPC for some time.

Quoted 8 lines

The fdt is a convenient vehicle for implementing run-time configuration for three reasons. Firstly it is easy to use, being a simple text file. It is extensible since it consists of nodes and properties in a nice hierarchical format.

Finally, there is already excellent infrastructure for the fdt: a compiler checks the text file and converts it to a compact binary format, and a library is already available in U-Boot (libfdt) for handling this format.

i guess the important questions for u-boot: size and speed. have you done any comparisons in this area ?
-mike
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 836 bytes
Desc: This is a digitally signed message part.
Url : http://lists.denx.de/pipermail/u-boot/attachments/20110902/eeb02433/attachment.pgp

#10 lore raw

cover Run-time configuration of U-Boot via a flat device tree (fdt)

HI Mike,

Quoted 13 lines · Mike Frysinger
Quoted 12 lines · On Thursday, September 01, 2011 16:49:05 Simon Glass wrote:

At present in U-Boot configuration is mostly done using CONFIG options in the board file. This patch set aims to make it possible for a single U-Boot binary to support multiple boards, with the exact configuration of each board controlled by a flat device tree (fdt). This is the approach recently taken by the ARM Linux kernel and has been used by PowerPC for some time.

The fdt is a convenient vehicle for implementing run-time configuration for three reasons. Firstly it is easy to use, being a simple text file. It is extensible since it consists of nodes and properties in a nice hierarchical format.

Quoted 6 lines
Quoted 3 lines

Finally, there is already excellent infrastructure for the fdt: a compiler checks the text file and converts it to a compact binary format, and a library is already available in U-Boot (libfdt) for handling this format.

i guess the important questions for u-boot: size and speed. ?have you done any comparisons in this area ?

In general the main difference between compile-time and run-time config is the device init. Rather than spreading CONFIG_ items through the driiver, we can define a structure which holds the config. Then it can be set up at driver init, either by assigning from CONFIG items, or decoding values from the fdt. Using this structure could in some cases have some small affect on code size and performance within the driver. For example, if the driver has something like:

   for (very tight loop executed 1000 times) {
      writel(CONFIG_SOME_VALUE / 9, &periph->reg);
   }

then the compiler can work out the value at run time, whereas when the driver is modified to use a structure:

      writel(config.some_value / 9, &periph->reg);

the compiler must actually do the calculation. I don't see much of this in the code base though. So overall the performance difference is small, and with a little effort can be close to zero.

In terms of code size, apart from adding the init code to decode from the fdt, I don't see a difference. I think an fdt_decode library is a good idea so that drivers have helper functions for doing common tasks (higher level than the existing fdt_support library, with specific driver decode support). That means that the fdt decode code size hit might happen once per driver class, maybe.

Regards,
Simon

Quoted 2 lines

-mike