[U-Boot] [PATCH v4 0/6] 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 makes 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.
In other words, manufacturers can potentially use a single U-Boot binary across an entire product line, with one fdt per model.
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 and u-boot-dtb.bin) #define CONFIG_DEFAULT_DEVICE_TREE "<your name>" (to specify the name of the device tree file is board/<vendor>/dts/<your name>.dts)
Typically a CPU device tree include file is provided which defines all the devices available on that CPU/SOC, with each set to 'status = "ok"'. Board device tree files should adjust only the devices they need to. If a device should be disabled, then it should be changed to 'status = 'disabled"' to indicate this. To facilitate this, a CPU/SOC device tree header is supported in arch/<arch>/dts. The name of this is defined by CONFIG_ARCH_DEVICE_TREE, typically defined in arch/<arch>/cpu/.../config.mk. You can use the following line within the board device tree file to include this header:
/include/ ARCH_CPU_DTS
For example, for Tegra2 we might have in arch/arm/cpu/armv7/tegra2/config.mk these lines:
CONFIG_ARCH_DEVICE_TREE := tegra20
This means that ARCH_CPU_DTS will point to arch/arm/dts/tegra20.dtsi.
This patch set does not include any drivers which actually use the fdt, but there is a basic fdt decode library (fdtdec) to simplify this process. I have provided an example i2c implementation previously:
http://patchwork.ozlabs.org/patch/114425/
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.
I experimented with using dtc's asm output to avoid all the arch/oformat ugliness in dts/Makefile as suggested by Stephen Warren swarren@nvidia.com. This simplified the Makefile commands greatly by removing the need to detect the output format and architecture. However Grant Likely grant.likely@secretlab.ca explained that this feature is not well tested and still has some big-endian-ims in it.
Changes in v2: - Modify Makefile to create combined U-boot/fdt (u-boot-dtb.bin) - Add example proposed decode helper library
Changes in v3: - Rename gd->blob to gd->fdt_blob - Move fdt files into board/<vendor>/dts - Provide access to ARCH_CPU_DTS which is the CPU's base device tree - Add fdtcontroladdr environment variable - Simplify decode library to remove provide only primitive functions - Remove i2c decode function - Rename fdt_decode to fdtdec, since it will be used a lot - Moved fdt_decode.c to /lib - Export almost all functions from fdtdec, to allow widespread use - Remove use of FDT_ERR_MISSING which is not strictly needed now
Changes in v4: - Fix reference to gd->blob which should be gd->fdt_blob - Remove unused 'clean' targets in dts/Makefile (remmove *.tmp at top-level) - Move documentation into the first 'fdt' patch in the series - Add note about CONFIG_ARCH_DEVICE_TREE - Add assert on sprintf() string length - Rename addr_t to fdt_addr_t to make it more fdt-specific - Remove gpio.h header in fdtdec.c which is not needed yet
Simon Glass (6): 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 and verify embedded and separate device tree fdt: ARM: Add fdtcontroladdr to set device tree address in environment fdt: add decode helper library
.gitignore | 1 + Makefile | 13 +++ README | 34 +++++++ arch/arm/include/asm/global_data.h | 1 + arch/arm/lib/board.c | 52 +++++++++-- config.mk | 1 + doc/README.fdt-control | 184 ++++++++++++++++++++++++++++++++++++ dts/Makefile | 103 ++++++++++++++++++++ include/common.h | 1 + include/fdtdec.h | 122 ++++++++++++++++++++++++ lib/Makefile | 1 + lib/fdtdec.c | 131 +++++++++++++++++++++++++ 12 files changed, 637 insertions(+), 7 deletions(-) create mode 100644 doc/README.fdt-control create mode 100644 dts/Makefile create mode 100644 include/fdtdec.h create mode 100644 lib/fdtdec.c

This adds a device tree pointer to the global data. It can be set by board code. A later commit will add support for making a device tree binary blob available to U-Boot for run-time configuration.
Signed-off-by: Simon Glass sjg@chromium.org --- Changes in v3: - Rename gd->blob to gd->fdt_blob
Changes in v4: - Fix reference to gd->blob which should be gd->fdt_blob
README | 11 +++++++++++ arch/arm/include/asm/global_data.h | 1 + 2 files changed, 12 insertions(+), 0 deletions(-)
diff --git a/README b/README index 7e032a9..499349f 100644 --- a/README +++ b/README @@ -811,6 +811,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->fdt_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 diff --git a/arch/arm/include/asm/global_data.h b/arch/arm/include/asm/global_data.h index fac98d5..c3ff789 100644 --- a/arch/arm/include/asm/global_data.h +++ b/arch/arm/include/asm/global_data.h @@ -76,6 +76,7 @@ typedef struct global_data { #if !(defined(CONFIG_SYS_ICACHE_OFF) && defined(CONFIG_SYS_DCACHE_OFF)) unsigned long tlb_addr; #endif + const void *fdt_blob; /* Our device tree, NULL if none */ void **jt; /* jump table */ char env_buf[32]; /* buffer for getenv() before reloc. */ #if defined(CONFIG_POST) || defined(CONFIG_LOGBUFFER)

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.
Signed-off-by: Simon Glass sjg@chromium.org --- Changes in v3: - Move fdt files into board/<vendor>/dts - Provide access to ARCH_CPU_DTS which is the CPU's base device tree
Changes in v4: - Remove unused 'clean' targets in dts/Makefile (remmove *.tmp at top-level) - Move documentation into the first 'fdt' patch in the series - Add note about CONFIG_ARCH_DEVICE_TREE
Makefile | 5 ++ README | 11 +++- config.mk | 1 + doc/README.fdt-control | 172 ++++++++++++++++++++++++++++++++++++++++++++++++ dts/Makefile | 103 +++++++++++++++++++++++++++++ include/common.h | 1 + 6 files changed, 291 insertions(+), 2 deletions(-) create mode 100644 doc/README.fdt-control create mode 100644 dts/Makefile
diff --git a/Makefile b/Makefile index 5db2e0e..05f64b7 100644 --- a/Makefile +++ b/Makefile @@ -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 \ @@ -962,6 +965,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 @@ -969,6 +973,7 @@ clobber: clean @[ ! -d $(obj)nand_spl ] || find $(obj)nand_spl -name "*" -type l -print | xargs rm -f @[ ! -d $(obj)onenand_ipl ] || find $(obj)onenand_ipl -name "*" -type l -print | xargs rm -f @[ ! -d $(obj)mmc_spl ] || find $(obj)mmc_spl -name "*" -type l -print | xargs rm -f + @rm -f $(obj)dts/*.tmp
mrproper \ distclean: clobber unconfig diff --git a/README b/README index 499349f..b5cdcb5 100644 --- a/README +++ b/README @@ -819,8 +819,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->fdt_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 diff --git a/config.mk b/config.mk index e2b440d..6e61eb6 100644 --- a/config.mk +++ b/config.mk @@ -124,6 +124,7 @@ STRIP = $(CROSS_COMPILE)strip OBJCOPY = $(CROSS_COMPILE)objcopy OBJDUMP = $(CROSS_COMPILE)objdump RANLIB = $(CROSS_COMPILE)RANLIB +DTC = dtc
#########################################################################
diff --git a/doc/README.fdt-control b/doc/README.fdt-control new file mode 100644 index 0000000..3f8bb5a --- /dev/null +++ b/doc/README.fdt-control @@ -0,0 +1,172 @@ +# +# Copyright (c) 2011 The Chromium OS Authors. +# +# See file CREDITS for list of people who contributed to this +# project. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License as +# published by the Free Software Foundatio; either version 2 of +# the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, +# MA 02111-1307 USA +# + +Device Tree Control in U-Boot +============================= + +This feature provides for run-time configuration of U-Boot via a flat +device tree (fdt). U-Boot configuration has traditionally been done +using CONFIG options in the board config file. This feature 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. + +The dts directory contains a Makefile for building the device tree blob +and embedding it in your U-Boot image. This is useful since it allows +U-Boot to configure itself according to what it finds there. If you have +a number of similar boards with different peripherals, you can describe +the features of each board in the device tree file, and have a single +generic source base. + +To enable this feature, add CONFIG_OF_CONTROL to your board config file. + + +What is a Flat Device Tree? +--------------------------- + +An fdt can be specified in source format as a text file. To read about +the fdt syntax, 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 + +There is also a mailing list: + + http://lists.ozlabs.org/listinfo/devicetree-discuss + +In case you are wondering, OF stands for Open Firmware. + + +Tools +----- + +To use this feature you will need to get the device tree compiler here: + + git://jdl.com/software/dtc.git + +For example: + + $ git clone git://jdl.com/software/dtc.git + $ cd dtc + $ make + $ sudo make install + +Then run the compiler (your version will vary): + + $ dtc -v + Version: DTC 1.2.0-g2cb4b51f + $ make tests + $ cd tests + $ ./run_tests.sh + ********** TEST SUMMARY + * Total testcases: 1371 + * PASS: 1371 + * FAIL: 0 + * Bad configuration: 0 + * Strange test result: 0 + +You will also find a useful ftdump utility for decoding a binary file. + + +Where do I get an fdt file for my board? +---------------------------------------- + +You may find that the Linux kernel has a suitable file. Look in the +kernel source in arch/<arch>/boot/dts. + +If not you might find other boards with suitable files that you can +modify to your needs. Look in the board directories for files with a +.dts extension. + +Failing that, you could write one from scratch yourself! + + +Configuration +------------- + +Use: + +#define CONFIG_DEFAULT_DEVICE_TREE "<name>" + +to set the filename of the device tree source. Then put your device tree +file into + + board/<vendor>/dts/<name>.dts + +This should include your CPU or SOC's device tree file, placed in +arch/<arch>/dts, and then make any adjustments required. The name of this +is CONFIG_ARCH_DEVICE_TREE.dts. + +If CONFIG_OF_EMBED is defined, then it will be picked up and built into +the U-Boot image (including u-boot.bin). + +If CONFIG_OF_SEPARATE is defined, then it will be built and placed in +a u-boot.dtb file alongside u-boot.bin. A common approach is then to +join the two: + + cat u-boot.bin u-boot.dtb >image.bin + +and then flash image.bin onto your board. + +You cannot use both of these options at the same time. + + +Limitations +----------- + +U-Boot is designed to build with a single architecture type and CPU +type. So for example it is not possible to build a single ARM binary +which runs on your AT91 and OMAP boards, relying on an fdt to configure +the various features. This is because you must select one of +the CPU families within arch/arm/cpu/arm926ejs (omap or at91) at build +time. Similarly you cannot build for multiple cpu types or +architectures. + +That said the complexity reduction by using fdt to support variants of +boards which use the same SOC / CPU can be substantial. + +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. + +-- +Simon Glass sjg@chromium.org +1-Sep-11 diff --git a/dts/Makefile b/dts/Makefile new file mode 100644 index 0000000..5792afd --- /dev/null +++ b/dts/Makefile @@ -0,0 +1,103 @@ +# +# Copyright (c) 2011 The Chromium OS Authors. +# +# See file CREDITS for list of people who contributed to this +# project. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License as +# published by the Free Software Foundatio; either version 2 of +# the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, +# MA 02111-1307 USA +# + +# This Makefile builds the internal U-Boot fdt if CONFIG_OF_CONTROL is +# enabled. See doc/README.fdt-control for more details. + +include $(TOPDIR)/config.mk + +LIB = $(obj)libdts.o + +$(if $(CONFIG_DEFAULT_DEVICE_TREE),,\ +$(error Please define CONFIG_DEFAULT_DEVICE_TREE in your board header file)) +DEVICE_TREE = $(subst ",,$(CONFIG_DEFAULT_DEVICE_TREE)) + +$(if $(CONFIG_ARCH_DEVICE_TREE),,\ +$(error Your architecture does not have device tree support enabled. \ +Please define CONFIG_ARCH_DEVICE_TREE)) + +# We preprocess the device tree file provide a useful define +DTS_CPPFLAGS := -DARCH_CPU_DTS="../arch/$(ARCH)/dts/$(CONFIG_ARCH_DEVICE_TREE).dtsi" + +all: $(obj).depend $(LIB) + +# Use a constant name for this so we can access it from C code. +# objcopy doesn't seem to allow us to set the symbol name independently of +# the filename. +DT_BIN := $(obj)dt.dtb + +$(DT_BIN): $(TOPDIR)/board/$(VENDOR)/dts/$(DEVICE_TREE).dts + cat $< | $(CPP) -P $(DTS_CPPFLAGS) - >$@.tmp + $(DTC) -R 4 -p 0x1000 -O dtb -o ${DT_BIN} $@.tmp + rm $@.tmp + +process_lds = \ + $(1) | sed -r -n 's/^OUTPUT_$(2)[ ("]*([^")]*).*/\1/p' + +# Run the compiler and get the link script from the linker +GET_LDS = $(CC) $(CFLAGS) $(LDFLAGS) -Wl,--verbose 2>&1 + +$(obj)dt.o: $(DT_BIN) + # We want the output format and arch. + # We also hope to win a prize for ugliest Makefile / shell interaction + # We look in the LDSCRIPT first. + # Then try the linker which should give us the answer. + # Then check it worked. + oformat=`$(call process_lds,cat $(LDSCRIPT),FORMAT)` ;\ + oarch=`$(call process_lds,cat $(LDSCRIPT),ARCH)` ;\ + \ + [ -z $${oformat} ] && \ + oformat=`$(call process_lds,$(GET_LDS),FORMAT)` ;\ + [ -z $${oarch} ] && \ + oarch=`$(call process_lds,$(GET_LDS),ARCH)` ;\ + \ + [ -z $${oformat} ] && \ + echo "Cannot read OUTPUT_FORMAT from lds file $(LDSCRIPT)" && \ + exit 1 || true ;\ + [ -z $${oarch} ] && \ + echo "Cannot read OUTPUT_ARCH from lds file $(LDSCRIPT)" && \ + exit 1 || true ;\ + \ + cd $(dir ${DT_BIN}) && \ + $(OBJCOPY) -I binary -O $${oformat} -B $${oarch} \ + $(notdir ${DT_BIN}) $@ + rm $(DT_BIN) + +OBJS-$(CONFIG_OF_EMBED) := dt.o + +COBJS := $(OBJS-y) + +OBJS := $(addprefix $(obj),$(COBJS)) + +binary: $(DT_BIN) + +$(LIB): $(OBJS) $(DTB) + $(call cmd_link_o_target, $(OBJS)) + +######################################################################### + +# defines $(obj).depend target +include $(SRCTREE)/rules.mk + +sinclude $(obj).depend + +######################################################################### diff --git a/include/common.h b/include/common.h index eb19a44..1feeaf4 100644 --- a/include/common.h +++ b/include/common.h @@ -270,6 +270,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);

Dear Simon,
On 15.10.2011 17:48, Simon Glass wrote:
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.
Signed-off-by: Simon Glasssjg@chromium.org
...
diff --git a/doc/README.fdt-control b/doc/README.fdt-control new file mode 100644 index 0000000..3f8bb5a --- /dev/null +++ b/doc/README.fdt-control
...
Reading your README.fdt-control and browsing the source code a little for the CONFIG_OF_* options I found two questions. Sorry if I haven't read carefully enough ;)
+Device Tree Control in U-Boot +=============================
+This feature provides for run-time configuration of U-Boot via a flat +device tree (fdt). U-Boot configuration has traditionally been done +using CONFIG options in the board config file. This feature 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.
+The dts directory contains a Makefile for building the device tree blob +and embedding it in your U-Boot image. This is useful since it allows +U-Boot to configure itself according to what it finds there. If you have +a number of similar boards with different peripherals, you can describe +the features of each board in the device tree file, and have a single +generic source base.
+To enable this feature, add CONFIG_OF_CONTROL to your board config file.
...
+Where do I get an fdt file for my board? +----------------------------------------
+You may find that the Linux kernel has a suitable file. Look in the +kernel source in arch/<arch>/boot/dts.
+If not you might find other boards with suitable files that you can +modify to your needs. Look in the board directories for files with a +.dts extension.
+Failing that, you could write one from scratch yourself!
+Configuration +-------------
+Use:
+#define CONFIG_DEFAULT_DEVICE_TREE "<name>"
+to set the filename of the device tree source. Then put your device tree +file into
- board/<vendor>/dts/<name>.dts
+This should include your CPU or SOC's device tree file, placed in +arch/<arch>/dts, and then make any adjustments required. The name of this +is CONFIG_ARCH_DEVICE_TREE.dts.
+If CONFIG_OF_EMBED is defined, then it will be picked up and built into +the U-Boot image (including u-boot.bin).
+If CONFIG_OF_SEPARATE is defined, then it will be built and placed in +a u-boot.dtb file alongside u-boot.bin. A common approach is then to +join the two:
- cat u-boot.bin u-boot.dtb>image.bin
+and then flash image.bin onto your board.
1. Above, the README.fdt-control talks about "make it possible for a single U-Boot binary to support multiple boards". Now, if I understood correctly, the 'Configuration' section above describes how to include/append *one* dtb. But wouldn't we need to include *multiple* dtbs to support multiple boards?
2. The section 'Where do I get an fdt file for my board' talks about taking the fdt from the Linux kernel. This is fine. Is U-Boot able to pass the included/appended (OF_EMBED/OF_SEPARATE) dtb to the Linux kernel, then, too? Or is the included/appended dtb only used for the U-Boot configuration? And the one passed to the Linux kernel has to be taken from anywhere else, additionally?
Many thanks and best regards
Dirk
P.S.: Any idea about
http://lists.denx.de/pipermail/u-boot/2012-March/120916.html
?

Hi Dirk,
On Mon, Apr 9, 2012 at 12:52 AM, Dirk Behme dirk.behme@googlemail.com wrote:
Dear Simon,
On 15.10.2011 17:48, Simon Glass wrote:
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.
Signed-off-by: Simon Glasssjg@chromium.org
...
diff --git a/doc/README.fdt-control b/doc/README.fdt-control new file mode 100644 index 0000000..3f8bb5a --- /dev/null +++ b/doc/README.fdt-control
...
Reading your README.fdt-control and browsing the source code a little for the CONFIG_OF_* options I found two questions. Sorry if I haven't read carefully enough ;)
+Device Tree Control in U-Boot +=============================
+This feature provides for run-time configuration of U-Boot via a flat +device tree (fdt). U-Boot configuration has traditionally been done +using CONFIG options in the board config file. This feature 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.
+The dts directory contains a Makefile for building the device tree blob +and embedding it in your U-Boot image. This is useful since it allows +U-Boot to configure itself according to what it finds there. If you have +a number of similar boards with different peripherals, you can describe +the features of each board in the device tree file, and have a single +generic source base.
+To enable this feature, add CONFIG_OF_CONTROL to your board config file.
...
+Where do I get an fdt file for my board? +----------------------------------------
+You may find that the Linux kernel has a suitable file. Look in the +kernel source in arch/<arch>/boot/dts.
+If not you might find other boards with suitable files that you can +modify to your needs. Look in the board directories for files with a +.dts extension.
+Failing that, you could write one from scratch yourself!
+Configuration +-------------
+Use:
+#define CONFIG_DEFAULT_DEVICE_TREE "<name>"
+to set the filename of the device tree source. Then put your device tree +file into
- board/<vendor>/dts/<name>.dts
+This should include your CPU or SOC's device tree file, placed in +arch/<arch>/dts, and then make any adjustments required. The name of this +is CONFIG_ARCH_DEVICE_TREE.dts.
+If CONFIG_OF_EMBED is defined, then it will be picked up and built into +the U-Boot image (including u-boot.bin).
+If CONFIG_OF_SEPARATE is defined, then it will be built and placed in +a u-boot.dtb file alongside u-boot.bin. A common approach is then to +join the two:
- cat u-boot.bin u-boot.dtb>image.bin
+and then flash image.bin onto your board.
- Above, the README.fdt-control talks about "make it possible for a single
U-Boot binary to support multiple boards". Now, if I understood correctly, the 'Configuration' section above describes how to include/append *one* dtb. But wouldn't we need to include *multiple* dtbs to support multiple boards?
The intent is that you build one u-boot.bin (same for all your boards), and then flash it along with the correct device tree binary for your board, when you flash your board.
What you ask for isn't necessarily useful for U-Boot in the same way as it is for the kernel, since there is in general no way for U-Boot to probe which hardware it has. For the kernel we can do this by having U-Boot select from the available FDTs and pass one to the kernel. For U-Boot there would need to be some sort of hardware register / strapping to select this. This would be a board-specific thing and one wonders whether it might not be better just to select the correct hardware/device tree at flashing time.
- The section 'Where do I get an fdt file for my board' talks about taking
the fdt from the Linux kernel. This is fine. Is U-Boot able to pass the included/appended (OF_EMBED/OF_SEPARATE) dtb to the Linux kernel, then, too? Or is the included/appended dtb only used for the U-Boot configuration? And the one passed to the Linux kernel has to be taken from anywhere else, additionally?
There is no specific support for passing the appended dtb to the kernel, although it would not be hard to add. The reason is that is is common to field-upgrade U-Boot and the kernel at different times. In fact U-Boot may never change after shipping, yet every kernel may require a new device tree binary to go with it.
Basically the intent was not to interfere in any way with the way U-Boot already selects and passes an device tree to the kernel.
Many thanks and best regards
Dirk
P.S.: Any idea about
http://lists.denx.de/pipermail/u-boot/2012-March/120916.html
Will take a look.
?
Regards, Simon

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. The Makefile is modified to provide this file in u-boot-dtb.bin.
Signed-off-by: Simon Glass sjg@chromium.org --- Changes in v2: - Modify Makefile to create combined U-boot/fdt (u-boot-dtb.bin)
.gitignore | 1 + Makefile | 8 ++++++++ README | 16 ++++++++++++++-- 3 files changed, 23 insertions(+), 2 deletions(-)
diff --git a/.gitignore b/.gitignore index 0a9dc0c..a367082 100644 --- a/.gitignore +++ b/.gitignore @@ -35,6 +35,7 @@ /u-boot.dis /u-boot.lds /u-boot.ubl +/u-boot.dtb
# # Generated files diff --git a/Makefile b/Makefile index 05f64b7..9a640e9 100644 --- a/Makefile +++ b/Makefile @@ -354,9 +354,17 @@ 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 $(obj)u-boot-dtb.bin
all: $(ALL-y)
+$(obj)u-boot.dtb: $(obj)u-boot + $(MAKE) -C dts binary + mv $(obj)dts/dt.dtb $@ + +$(obj)u-boot-dtb.bin: $(obj)u-boot.bin $(obj)u-boot.dtb + cat $^ >$@ + $(obj)u-boot.hex: $(obj)u-boot $(OBJCOPY) ${OBJCFLAGS} -O ihex $< $@
diff --git a/README b/README index b5cdcb5..fc1cd00 100644 --- a/README +++ b/README @@ -819,8 +819,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->fdt_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 @@ -829,6 +829,18 @@ 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 + + and in fact, U-Boot does this for you, creating a file called + u-boot-dtb.bin which is useful in the common case. You can + still use the individual files if you need something more + exotic. + - Watchdog: CONFIG_WATCHDOG If this variable is defined, it enables watchdog

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.
Signed-off-by: Simon Glass sjg@chromium.org --- arch/arm/lib/board.c | 22 ++++++++++++++++++++++ 1 files changed, 22 insertions(+), 0 deletions(-)
diff --git a/arch/arm/lib/board.c b/arch/arm/lib/board.c index 1fe3751..b0f3162 100644 --- a/arch/arm/lib/board.c +++ b/arch/arm/lib/board.c @@ -48,6 +48,7 @@ #include <nand.h> #include <onenand_uboot.h> #include <mmc.h> +#include <libfdt.h> #include <post.h> #include <logbuff.h>
@@ -197,6 +198,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->fdt_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... * @@ -239,6 +251,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, @@ -276,6 +291,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->fdt_blob = _binary_dt_dtb_start; +#elif defined CONFIG_OF_SEPARATE + /* FDT is at end of image */ + gd->fdt_blob = (void *)(_end_ofs + _TEXT_BASE); +#endif
for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) { if ((*init_fnc_ptr)() != 0) {

On Oct 15, 2011, at 10:48 AM, Simon Glass wrote:
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.
Signed-off-by: Simon Glass sjg@chromium.org
arch/arm/lib/board.c | 22 ++++++++++++++++++++++ 1 files changed, 22 insertions(+), 0 deletions(-)
diff --git a/arch/arm/lib/board.c b/arch/arm/lib/board.c index 1fe3751..b0f3162 100644 --- a/arch/arm/lib/board.c +++ b/arch/arm/lib/board.c @@ -48,6 +48,7 @@ #include <nand.h> #include <onenand_uboot.h> #include <mmc.h> +#include <libfdt.h> #include <post.h> #include <logbuff.h>
@@ -197,6 +198,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->fdt_blob))
panic("No valid fdt found - please append one to U-Boot\n"
"binary or define CONFIG_OF_EMBED\n");
- return 0;
+} +#endif
this isn't arm specific, maybe put in fdt_support.c
/*
- Breathe some life into the board...
@@ -239,6 +251,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, @@ -276,6 +291,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->fdt_blob = _binary_dt_dtb_start;
+#elif defined CONFIG_OF_SEPARATE
- /* FDT is at end of image */
- gd->fdt_blob = (void *)(_end_ofs + _TEXT_BASE);
+#endif
for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) { if ((*init_fnc_ptr)() != 0) { -- 1.7.3.1

Hi Kumar,
On Thu, Oct 20, 2011 at 10:13 PM, Kumar Gala galak@kernel.crashing.org wrote:
On Oct 15, 2011, at 10:48 AM, Simon Glass wrote:
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.
Signed-off-by: Simon Glass sjg@chromium.org
arch/arm/lib/board.c | 22 ++++++++++++++++++++++ 1 files changed, 22 insertions(+), 0 deletions(-)
diff --git a/arch/arm/lib/board.c b/arch/arm/lib/board.c index 1fe3751..b0f3162 100644 --- a/arch/arm/lib/board.c +++ b/arch/arm/lib/board.c @@ -48,6 +48,7 @@ #include <nand.h> #include <onenand_uboot.h> #include <mmc.h> +#include <libfdt.h> #include <post.h> #include <logbuff.h>
@@ -197,6 +198,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->fdt_blob))
- panic("No valid fdt found - please append one to U-Boot\n"
- "binary or define CONFIG_OF_EMBED\n");
- return 0;
+} +#endif
this isn't arm specific, maybe put in fdt_support.c
Thanks. I have made this change in v6.
Regards, Simon
/* * Breathe some life into the board... * @@ -239,6 +251,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, @@ -276,6 +291,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->fdt_blob = _binary_dt_dtb_start;
+#elif defined CONFIG_OF_SEPARATE
- /* FDT is at end of image */
- gd->fdt_blob = (void *)(_end_ofs + _TEXT_BASE);
+#endif
for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) { if ((*init_fnc_ptr)() != 0) { -- 1.7.3.1

This adds support for a new environment variable called 'fdtcontroladdr'. If defined, the hex address is used as the address of the control fdt for U-Boot.
Note: I have not changed CONFIG_PRAM section as I already have an outstanding patch on that.
Signed-off-by: Simon Glass sjg@chromium.org --- Changes in v3: - Add fdtcontroladdr environment variable
README | 4 ++++ arch/arm/lib/board.c | 30 +++++++++++++++++++++++------- doc/README.fdt-control | 12 ++++++++++++ 3 files changed, 39 insertions(+), 7 deletions(-)
diff --git a/README b/README index fc1cd00..3b1faf9 100644 --- a/README +++ b/README @@ -3493,6 +3493,10 @@ List of environment variables (most likely not complete): add the information it needs into it, and the memory must be accessible by the kernel.
+ fdtcontroladdr- if set this is the address of the control flattened + device tree used by U-Boot when CONFIG_OF_CONTROL is + defined. + i2cfast - (PPC405GP|PPC405EP only) if set to 'y' configures Linux I2C driver for fast mode (400kHZ). This environment variable is used in diff --git a/arch/arm/lib/board.c b/arch/arm/lib/board.c index b0f3162..f26d77a 100644 --- a/arch/arm/lib/board.c +++ b/arch/arm/lib/board.c @@ -116,18 +116,31 @@ void blue_led_off(void) __attribute__((weak, alias("__blue_led_off"))); * but let's get it working (again) first... */
+/** + * Decode the value of an environment variable and return it. + * + * @param name Name of environemnt variable + * @param base Number base to use (normally 10, or 16 for hex) + * @param default_val Default value to return if the variable is not + * found + * @return the decoded value, or default_val if not found + */ +static int getenv_int(const char *name, int base, int default_val) +{ + char tmp[64]; /* long enough for environment variables */ + int i = getenv_f(name, tmp, sizeof(tmp)); + + return (i > 0) + ? (int) simple_strtoul(tmp, NULL, base) + : default_val; +} + #if defined(CONFIG_ARM_DCC) && !defined(CONFIG_BAUDRATE) #define CONFIG_BAUDRATE 115200 #endif static int init_baudrate(void) { - char tmp[64]; /* long enough for environment variables */ - int i = getenv_f("baudrate", tmp, sizeof(tmp)); - - gd->baudrate = (i > 0) - ? (int) simple_strtoul(tmp, NULL, 10) - : CONFIG_BAUDRATE; - + gd->baudrate = getenv_int("baudrate", 10, CONFIG_BAUDRATE); return (0); }
@@ -298,6 +311,9 @@ void board_init_f(ulong bootflag) /* FDT is at end of image */ gd->fdt_blob = (void *)(_end_ofs + _TEXT_BASE); #endif + /* Allow the early environment to override the fdt address */ + gd->fdt_blob = (void *)getenv_int("fdtcontroladdr", 16, + (uintptr_t)gd->fdt_blob);
for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) { if ((*init_fnc_ptr)() != 0) { diff --git a/doc/README.fdt-control b/doc/README.fdt-control index 3f8bb5a..85bda03 100644 --- a/doc/README.fdt-control +++ b/doc/README.fdt-control @@ -144,6 +144,18 @@ and then flash image.bin onto your board.
You cannot use both of these options at the same time.
+If you wish to put the fdt at a different address in memory, you can +define the "fdtcontroladdr" environment variable. This is the hex +address of the fdt binary blob, and will override either of the options. +Be aware that this environment variable is checked prior to relocation, +when only the compiled-in environment is available. Therefore it is not +possible to define this variable in the saved SPI/NAND flash +environment, for example (it will be ignored). + +To use this, put something like this in your board header file: + +#define CONFIG_EXTRA_ENV_SETTINGS "fdtcontroladdr=10000\0" +
Limitations -----------

This library provides useful functions to drivers which want to use the fdt to control their operation. Functions are provided to:
- look up and enumerate a device type (for example assigning i2c bus 0, i2c bus 1, etc.) - decode basic types from the fdt, like addresses and integers
While this library is not strictly necessary, it helps to minimise the changes to a driver, in order to make it work under fdt control. Less code is required, and so the barrier to switch drivers over is lower.
Additional functions to read arrays and GPIOs could be made available here also.
Signed-off-by: Simon Glass sjg@chromium.org --- Changes in v2: - Add example proposed decode helper library
Changes in v3: - Simplify decode library to remove provide only primitive functions - Remove i2c decode function - Rename fdt_decode to fdtdec, since it will be used a lot - Moved fdt_decode.c to /lib - Export almost all functions from fdtdec, to allow widespread use - Remove use of FDT_ERR_MISSING which is not strictly needed now
Changes in v4: - Add assert on sprintf() string length - Rename addr_t to fdt_addr_t to make it more fdt-specific - Remove gpio.h header in fdtdec.c which is not needed yet
include/fdtdec.h | 122 ++++++++++++++++++++++++++++++++++++++++++++++++++ lib/Makefile | 1 + lib/fdtdec.c | 131 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 254 insertions(+), 0 deletions(-) create mode 100644 include/fdtdec.h create mode 100644 lib/fdtdec.c
diff --git a/include/fdtdec.h b/include/fdtdec.h new file mode 100644 index 0000000..ae36f9c --- /dev/null +++ b/include/fdtdec.h @@ -0,0 +1,122 @@ +/* + * Copyright (c) 2011 The Chromium OS Authors. + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + + +/* + * This file contains convenience functions for decoding useful and + * enlightening information from FDTs. It is intended to be used by device + * drivers and board-specific code within U-Boot. It aims to reduce the + * amount of FDT munging required within U-Boot itself, so that driver code + * changes to support FDT are minimized. + */ + +#include <libfdt.h> + +/* + * A typedef for a physical address. Note that fdt data is always big + * endian even on a litle endian machine. + */ +#ifdef CONFIG_PHYS_64BIT +typedef u64 fdt_addr_t; +#define FDT_ADDR_T_NONE (-1ULL) +#define fdt_addr_to_cpu(reg) be64_to_cpu(reg) +#else +typedef u32 fdt_addr_t; +#define FDT_ADDR_T_NONE (-1U) +#define fdt_addr_to_cpu(reg) be32_to_cpu(reg) +#endif + +/* Information obtained about memory from the FDT */ +struct fdt_memory { + fdt_addr_t start; + fdt_addr_t end; +}; + +/** + * Compat types that we know about and for which we might have drivers. + * Each is named COMPAT_<dir>_<filename> where <dir> is the directory + * within drivers. + */ +enum fdt_compat_id { + COMPAT_UNKNOWN, + + COMPAT_COUNT, +}; + +/** + * Find the next numbered alias for a peripheral. This is used to enumerate + * all the peripherals of a certain type. + * + * Do the first call with *upto = 0. Assuming /aliases/<name>0 exists then + * this function will return a pointer to the node the alias points to, and + * then update *upto to 1. Next time you call this function, the next node + * will be returned. + * + * All nodes returned will match the compatible ID, as it is assumed that + * all peripherals use the same driver. + * + * @param blob FDT blob to use + * @param name Root name of alias to search for + * @param id Compatible ID to look for + * @return offset of next compatible node, or -FDT_ERR_NOTFOUND if no more + */ +int fdtdec_next_alias(const void *blob, const char *name, + enum fdt_compat_id id, int *upto); + +/** + * Look up an address property in a node and return it as an address. + * The property must hold either one address with no trailing data or + * one address with a length. This is only tested on 32-bit machines. + * + * @param blob FDT blob + * @param node node to examine + * @param prop_name name of property to find + * @return address, if found, or FDT_ADDR_T_NONE if not + */ +fdt_addr_t fdtdec_get_addr(const void *blob, int node, + const char *prop_name); + +/** + * Look up a 32-bit integer property in a node and return it. The property + * must have at least 4 bytes of data. The value of the first cell is + * returned. + * + * @param blob FDT blob + * @param node node to examine + * @param prop_name name of property to find + * @param default_val default value to return if the property is not found + * @return integer value, if found, or default_val if not + */ +s32 fdtdec_get_int(const void *blob, int node, const char *prop_name, + s32 default_val); + +/** + * Checks whether a node is enabled. + * This looks for a 'status' property. If this exists, then returns 1 if + * the status is 'ok' and 0 otherwise. If there is no status property, + * it returns the default value. + * + * @param blob FDT blob + * @param node node to examine + * @param default_val default value to return if no 'status' property exists + * @return integer value 0/1, if found, or default_val if not + */ +int fdtdec_get_is_enabled(const void *blob, int node, int default_val); diff --git a/lib/Makefile b/lib/Makefile index 884f64c..3b901c9 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -38,6 +38,7 @@ COBJS-y += crc16.o COBJS-y += crc32.o COBJS-y += display_options.o COBJS-y += errno.o +COBJS-$(CONFIG_OF_CONTROL) += fdtdec.o COBJS-$(CONFIG_GZIP) += gunzip.o COBJS-y += hashtable.o COBJS-$(CONFIG_LMB) += lmb.o diff --git a/lib/fdtdec.c b/lib/fdtdec.c new file mode 100644 index 0000000..eb20f6e --- /dev/null +++ b/lib/fdtdec.c @@ -0,0 +1,131 @@ +/* + * Copyright (c) 2011 The Chromium OS Authors. + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include <common.h> +#include <serial.h> +#include <libfdt.h> +#include <fdtdec.h> + +/* + * Here are the type we know about. One day we might allow drivers to + * register. For now we just put them here. The COMPAT macro allows us to + * turn this into a sparse list later, and keeps the ID with the name. + */ +#define COMPAT(id, name) name +static const char *compat_names[COMPAT_COUNT] = { +}; + +/** + * Look in the FDT for an alias with the given name and return its node. + * + * @param blob FDT blob + * @param name alias name to look up + * @return node offset if found, or an error code < 0 otherwise + */ +static int find_alias_node(const void *blob, const char *name) +{ + const char *path; + int alias_node; + + debug("find_alias_node: %s\n", name); + alias_node = fdt_path_offset(blob, "/aliases"); + if (alias_node < 0) + return alias_node; + path = fdt_getprop(blob, alias_node, name, NULL); + if (!path) + return -FDT_ERR_NOTFOUND; + return fdt_path_offset(blob, path); +} + +fdt_addr_t fdtdec_get_addr(const void *blob, int node, + const char *prop_name) +{ + const fdt_addr_t *cell; + int len; + + debug("get_addr: %s\n", prop_name); + cell = fdt_getprop(blob, node, prop_name, &len); + if (cell && (len == sizeof(fdt_addr_t) || + len == sizeof(fdt_addr_t) * 2)) + return fdt_addr_to_cpu(*cell); + return FDT_ADDR_T_NONE; +} + +s32 fdtdec_get_int(const void *blob, int node, const char *prop_name, + s32 default_val) +{ + const s32 *cell; + int len; + + debug("get_size: %s\n", prop_name); + cell = fdt_getprop(blob, node, prop_name, &len); + if (cell && len >= sizeof(s32)) + return fdt32_to_cpu(cell[0]); + return default_val; +} + +int fdtdec_get_is_enabled(const void *blob, int node, int default_val) +{ + const char *cell; + + cell = fdt_getprop(blob, node, "status", NULL); + if (cell) + return 0 == strcmp(cell, "ok"); + return default_val; +} + +enum fdt_compat_id fd_dec_lookup(const void *blob, int node) +{ + enum fdt_compat_id id; + + /* Search our drivers */ + for (id = COMPAT_UNKNOWN; id < COMPAT_COUNT; id++) + if (0 == fdt_node_check_compatible(blob, node, + compat_names[id])) + return id; + return COMPAT_UNKNOWN; +} + +int fdtdec_next_compatible(const void *blob, int node, + enum fdt_compat_id id) +{ + return fdt_node_offset_by_compatible(blob, node, compat_names[id]); +} + +int fdtdec_next_alias(const void *blob, const char *name, + enum fdt_compat_id id, int *upto) +{ +#define MAX_STR_LEN 20 + char str[MAX_STR_LEN + 20]; + int node, err; + + /* snprintf() is not available */ + assert(strlen(name) < MAX_STR_LEN); + sprintf(str, "%.*s%d", MAX_STR_LEN, name, *upto); + (*upto)++; + node = find_alias_node(blob, str); + if (node < 0) + return node; + err = fdt_node_check_compatible(blob, node, compat_names[id]); + if (err < 0) + return err; + return err ? -FDT_ERR_NOTFOUND : node; +}

On Saturday 15 October 2011 11:48:25 Simon Glass wrote:
--- /dev/null +++ b/lib/fdtdec.c
+static const char *compat_names[COMPAT_COUNT] = {
static const char * const compat_names[COMPAT_COUNT] = { -mike

Hi Mike,
On Sat, Oct 15, 2011 at 10:14 PM, Mike Frysinger vapier@gentoo.org wrote:
On Saturday 15 October 2011 11:48:25 Simon Glass wrote:
--- /dev/null +++ b/lib/fdtdec.c
+static const char *compat_names[COMPAT_COUNT] = {
static const char * const compat_names[COMPAT_COUNT] = { -mike
Oops I missed that one - will send another version for just this patch. Thanks for spotting it.
Regards, Simon

Dear Simon Glass,
is there going to be an updated version of this patch series?
Best regards,
Wolfgang Denk

Hi Wolfgang,
On Sun, Oct 23, 2011 at 1:56 PM, Wolfgang Denk wd@denx.de wrote:
Dear Simon Glass,
is there going to be an updated version of this patch series?
There was a request to move the check_fdt function into the fdtdec library, and I think it makes sense. So I will do that and send an update. I don't have any other changes ATM.
Regards, Simon
Best regards,
Wolfgang Denk
-- DENX Software Engineering GmbH, MD: Wolfgang Denk & Detlev Zundel HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email: wd@denx.de "The algorithm to do that is extremely nasty. You might want to mug someone with it." - M. Devine, Computer Science 340

Dear Simon Glass,
In message CAPnjgZ22OPHxn5DDuOLoRwaeCDeWV11FdqeqpD4e=ba9ZyfsHA@mail.gmail.com you wrote:
There was a request to move the check_fdt function into the fdtdec library, and I think it makes sense. So I will do that and send an
That was my unerstanding, too.
update. I don't have any other changes ATM.
And that's why I asked :-)
Best regards,
Wolfgang Denk

Hi Wolfgang,
On Mon, Oct 24, 2011 at 11:49 AM, Wolfgang Denk wd@denx.de wrote:
Dear Simon Glass,
In message CAPnjgZ22OPHxn5DDuOLoRwaeCDeWV11FdqeqpD4e=ba9ZyfsHA@mail.gmail.com you wrote:
There was a request to move the check_fdt function into the fdtdec library, and I think it makes sense. So I will do that and send an
That was my unerstanding, too.
update. I don't have any other changes ATM.
And that's why I asked :-)
OK I have sent v6 with that change.
Regards, Simon
Best regards,
Wolfgang Denk
-- DENX Software Engineering GmbH, MD: Wolfgang Denk & Detlev Zundel HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email: wd@denx.de "To IBM, 'open' means there is a modicum of interoperability among some of their equipment." - Harv Masterson
participants (5)
-
Dirk Behme
-
Kumar Gala
-
Mike Frysinger
-
Simon Glass
-
Wolfgang Denk