[U-Boot] [PATCH 00/31] RFC: dm: Add support for compiled-in platform data

This series provides a way to compile in the contents of a device tree as C code into U-Boot. It is intended to deal with extremely tight environments where there is not enough space for the ~3KB device tree code overhead. Examples include SPL where there is only 16KB of available RAM yet a full MMC stack is required.
To provide a reasonable test environment, SPL support is added to sandbox, through a new 'sandbox_spl' target. A new tool 'dtoc' converts device tree data to C code (and structure definitions).
More work is needed before this feature is ready for use, but this series contains enough to attract initial comments and testing.
Simon Glass (31): sandbox: Don't print a warning for CONFIG_I2C_COMPAT README: Remove CONFIG_SYS_MALLOC_F_LEN comment spl: Drop include of i2c.h Makefile: Allow the SPL final link rule to be overridden sandbox: Allow chaining from SPL to U-Boot proper sandbox: Support building an SPL image sandbox: Correct header file order in cpu.c sandbox: Add some missing headers in cpu.c sandbox: Don't use PCI in SPL sandbox: Don't include the main loop in SPL sandbox: Add basic SPL implementation sandbox: Don't use IDE and iotrace in SPL sandbox: serial: Don't sync video in SPL sandbox: Add a new sandbox_spl board sandbox: Add a test device that uses of-platdata dm: spl: Don't set up device tree with of-platdata dm: Makefile: Build of-platdata before SPL dm: core: Don't use device tree with of-platdata dm: regmap: Add a dummy implementation for of-platdata dm: syscon: Add support for of-platdata dm: sandbox: Add a simple driver to test of-platdata dm: Add a header that provides access to the of-platdata structs dm: clk: Add support for of-platdata dm: serial: Add support for of-platdata dm: Don't include fdtdec functions when of-platdata is enabled dm: Add an option to enable the of-platdata feature dm: Add a README for of-platdata dm: Add a library to provide simple device-tree access dm: Add a tool to generate C code from a device tree dm: Makefile: Build of-platdata files when the feature is enabled dm: Add a more efficient libfdt library
Makefile | 5 +- README | 3 - arch/sandbox/Kconfig | 7 +- arch/sandbox/config.mk | 5 + arch/sandbox/cpu/Makefile | 1 + arch/sandbox/cpu/cpu.c | 6 +- arch/sandbox/cpu/os.c | 51 ++++++ arch/sandbox/cpu/spl.c | 60 +++++++ arch/sandbox/cpu/start.c | 2 + arch/sandbox/cpu/u-boot-spl.lds | 24 +++ arch/sandbox/dts/sandbox.dts | 13 ++ arch/sandbox/include/asm/spl.h | 23 +++ arch/sandbox/lib/Makefile | 2 + board/sandbox/MAINTAINERS | 7 + common/spl/spl.c | 3 +- configs/sandbox_spl_defconfig | 177 +++++++++++++++++++ doc/driver-model/of-plat.txt | 266 +++++++++++++++++++++++++++++ drivers/clk/clk-uclass.c | 20 +++ drivers/clk/clk_fixed_rate.c | 2 + drivers/core/device.c | 2 +- drivers/core/lists.c | 2 +- drivers/core/regmap.c | 9 + drivers/core/root.c | 4 +- drivers/core/syscon-uclass.c | 13 ++ drivers/misc/Makefile | 5 + drivers/misc/spltest_sandbox.c | 28 +++ drivers/serial/sandbox.c | 2 + drivers/serial/serial-uclass.c | 8 +- dts/Kconfig | 21 +++ include/clk.h | 4 + include/configs/sandbox.h | 4 + include/configs/sandbox_spl.h | 20 +++ include/dt-structs.h | 19 +++ include/os.h | 25 +++ include/regmap.h | 3 + include/syscon.h | 6 + lib/Makefile | 5 +- lib/libfdt/libfdt.swig | 81 +++++++++ lib/libfdt/setup.py | 38 +++++ lib/libfdt/test_libfdt.py | 14 ++ scripts/Makefile.host | 9 +- scripts/Makefile.spl | 45 ++++- tools/Makefile | 11 ++ tools/dtoc/.gitignore | 1 + tools/dtoc/dtoc | 1 + tools/dtoc/dtoc.py | 365 ++++++++++++++++++++++++++++++++++++++++ tools/dtoc/fdt.py | 174 +++++++++++++++++++ tools/dtoc/fdt_fallback.py | 207 +++++++++++++++++++++++ tools/dtoc/fdt_util.py | 71 ++++++++ 49 files changed, 1849 insertions(+), 25 deletions(-) create mode 100644 arch/sandbox/cpu/spl.c create mode 100644 arch/sandbox/cpu/u-boot-spl.lds create mode 100644 arch/sandbox/include/asm/spl.h create mode 100644 configs/sandbox_spl_defconfig create mode 100644 doc/driver-model/of-plat.txt create mode 100644 drivers/misc/spltest_sandbox.c create mode 100644 include/configs/sandbox_spl.h create mode 100644 include/dt-structs.h create mode 100644 lib/libfdt/libfdt.swig create mode 100644 lib/libfdt/setup.py create mode 100644 lib/libfdt/test_libfdt.py create mode 100644 tools/dtoc/.gitignore create mode 120000 tools/dtoc/dtoc create mode 100755 tools/dtoc/dtoc.py create mode 100644 tools/dtoc/fdt.py create mode 100644 tools/dtoc/fdt_fallback.py create mode 100644 tools/dtoc/fdt_util.py

Sandbox includes this code to provide build coverage. While we retain this feature we should have sandbox build it. Sandbox does not in fact use the I2C compatibility mode. Showing a warning for sandbox is just confusing, since no conversion is expected.
Drop the warning for sandbox.
Signed-off-by: Simon Glass sjg@chromium.org ---
Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/Makefile b/Makefile index 0f7d6f3..5b03095 100644 --- a/Makefile +++ b/Makefile @@ -801,7 +801,7 @@ quiet_cmd_pad_cat = CAT $@ cmd_pad_cat = $(cmd_objcopy) && $(append) || rm -f $@
all: $(ALL-y) -ifeq ($(CONFIG_DM_I2C_COMPAT),y) +ifeq ($(CONFIG_DM_I2C_COMPAT)$(CONFIG_SANDBOX),y) @echo "===================== WARNING ======================" @echo "This board uses CONFIG_DM_I2C_COMPAT. Please remove" @echo "(possibly in a subsequent patch in your series)"

This option is now widely available, so remove the comment that it is only available on ARM and sandbox.
Signed-off-by: Simon Glass sjg@chromium.org ---
README | 3 --- 1 file changed, 3 deletions(-)
diff --git a/README b/README index 1d0b946..c3dcfbd 100644 --- a/README +++ b/README @@ -3852,9 +3852,6 @@ Configuration Settings: The memory will be freed (or in fact just forgotten) when U-Boot relocates itself.
- Pre-relocation malloc() is only supported on ARM and sandbox - at present but is fairly easy to enable for other archs. - - CONFIG_SYS_MALLOC_SIMPLE Provides a simple and small malloc() and calloc() for those boards which do not use the full malloc in SPL (which is

This file does not appear to use I2C, so drop this include.
Signed-off-by: Simon Glass sjg@chromium.org ---
common/spl/spl.c | 1 - 1 file changed, 1 deletion(-)
diff --git a/common/spl/spl.c b/common/spl/spl.c index c8dfc14..e931edd 100644 --- a/common/spl/spl.c +++ b/common/spl/spl.c @@ -13,7 +13,6 @@ #include <nand.h> #include <fat.h> #include <version.h> -#include <i2c.h> #include <image.h> #include <malloc.h> #include <dm/root.h>

Overriding the final link rule is possible with U-Boot proper. It us used to create a sandbox image links with host libraries. To build a sandbox SPL image we need the same feature for SPL.
To support this, update the SPL link rule so sandbox can override it.
Signed-off-by: Simon Glass sjg@chromium.org ---
scripts/Makefile.spl | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/scripts/Makefile.spl b/scripts/Makefile.spl index 0997fd9..2b5c995 100644 --- a/scripts/Makefile.spl +++ b/scripts/Makefile.spl @@ -241,8 +241,10 @@ cmd_mksunxiboot = $(objtree)/tools/mksunxiboot $< $@ $(obj)/sunxi-spl.bin: $(obj)/$(SPL_BIN).bin FORCE $(call if_changed,mksunxiboot)
-quiet_cmd_u-boot-spl = LD $@ - cmd_u-boot-spl = (cd $(obj) && $(LD) $(LDFLAGS) $(LDFLAGS_$(@F)) \ +# Rule to link u-boot-spl +# May be overridden by arch/$(ARCH)/config.mk +quiet_cmd_u-boot-spl ?= LD $@ + cmd_u-boot-spl ?= (cd $(obj) && $(LD) $(LDFLAGS) $(LDFLAGS_$(@F)) \ $(patsubst $(obj)/%,%,$(u-boot-spl-init)) --start-group \ $(patsubst $(obj)/%,%,$(u-boot-spl-main)) --end-group \ $(PLATFORM_LIBS) -Map $(SPL_BIN).map -o $(SPL_BIN))

SPL is expected to load and run U-Boot. This needs to work with sandbox also. Provide a function to locate the U-Boot image, and another to start it. This allows SPL to function on sandbox as it does on other archs.
Signed-off-by: Simon Glass sjg@chromium.org ---
arch/sandbox/cpu/os.c | 51 +++++++++++++++++++++++++++++++++++++++++++++++++++ include/os.h | 25 +++++++++++++++++++++++++ 2 files changed, 76 insertions(+)
diff --git a/arch/sandbox/cpu/os.c b/arch/sandbox/cpu/os.c index 8a4d719..2d63dd8 100644 --- a/arch/sandbox/cpu/os.c +++ b/arch/sandbox/cpu/os.c @@ -541,6 +541,57 @@ int os_jump_to_image(const void *dest, int size) return unlink(fname); }
+int os_find_u_boot(char *fname, int maxlen) +{ + struct sandbox_state *state = state_get_current(); + const char *progname = state->argv[0]; + int len = strlen(progname); + char *p; + int fd; + + if (len >= maxlen || len < 4) + return -ENOSPC; + + /* Look for 'u-boot' in the same directory as 'u-boot-spl' */ + strcpy(fname, progname); + if (!strcmp(fname + len - 4, "-spl")) { + fname[len - 4] = '\0'; + fd = os_open(fname, O_RDONLY); + if (fd >= 0) { + close(fd); + return 0; + } + } + + /* Look for 'u-boot' in the parent directory of spl/ */ + p = strstr(fname, "/spl/"); + if (p) { + strcpy(p, p + 4); + fd = os_open(fname, O_RDONLY); + if (fd >= 0) { + close(fd); + return 0; + } + } + + return -ENOENT; +} + +int os_spl_to_uboot(const char *fname) +{ + struct sandbox_state *state = state_get_current(); + char *argv[state->argc + 1]; + int ret; + + memcpy(argv, state->argv, sizeof(char *) * (state->argc + 1)); + argv[0] = (char *)fname; + ret = execv(fname, argv); + if (ret) + return ret; + + return unlink(fname); +} + void os_localtime(struct rtc_time *rt) { time_t t = time(NULL); diff --git a/include/os.h b/include/os.h index 954a48c..1782e50 100644 --- a/include/os.h +++ b/include/os.h @@ -287,6 +287,31 @@ int os_read_ram_buf(const char *fname); int os_jump_to_image(const void *dest, int size);
/** + * os_find_u_boot() - Determine the path to U-Boot proper + * + * This function is intended to be called from within sandbox SPL. It uses + * a few heuristics to find U-Boot proper. Normally it is either in the same + * directory, or the directory above (since u-boot-spl is normally in an + * spl/ subdirectory when built). + * + * @fname: Place to put full path to U-Boot + * @maxlen: Maximum size of @fname + * @return 0 if OK, -NOSPC if the filename is too large, -ENOENT if not found + */ +int os_find_u_boot(char *fname, int maxlen); + +/** + * os_spl_to_uboot() - Run U-Boot proper + * + * When called from SPL, this runs U-Boot proper. The filename is obtained by + * calling os_find_u_boot(). + * + * @fname: Full pathname to U-Boot executable + * @return 0 if OK, -ve on error + */ +int os_spl_to_uboot(const char *fname); + +/** * Read the current system time * * This reads the current Local Time and places it into the provided

When building an SPL image, override the link flags so that it uses the system libraries. This is similar to the way the non-SPL image is built.
Signed-off-by: Simon Glass sjg@chromium.org ---
arch/sandbox/config.mk | 5 +++++ 1 file changed, 5 insertions(+)
diff --git a/arch/sandbox/config.mk b/arch/sandbox/config.mk index 16fd6d5..6d62abb 100644 --- a/arch/sandbox/config.mk +++ b/arch/sandbox/config.mk @@ -20,4 +20,9 @@ cmd_u-boot__ = $(CC) -o $@ -Wl,-T u-boot.lds \ -Wl,--start-group $(u-boot-main) -Wl,--end-group \ $(PLATFORM_LIBS) -Wl,-Map -Wl,u-boot.map
+cmd_u-boot-spl = (cd $(obj) && $(CC) -o $(SPL_BIN) -Wl,-T u-boot-spl.lds \ + -Wl,--start-group $(patsubst $(obj)/%,%,$(u-boot-spl-main)) \ + $(patsubst $(obj)/%,%,$(u-boot-spl-platdata)) -Wl,--end-group \ + $(PLATFORM_LIBS) -Wl,-Map -Wl,u-boot-spl.map -Wl,--gc-sections) + CONFIG_ARCH_DEVICE_TREE := sandbox

The dm/ file should go at the end. Move it.
Signed-off-by: Simon Glass sjg@chromium.org ---
arch/sandbox/cpu/cpu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/arch/sandbox/cpu/cpu.c b/arch/sandbox/cpu/cpu.c index 196f3e1..7a622c8 100644 --- a/arch/sandbox/cpu/cpu.c +++ b/arch/sandbox/cpu/cpu.c @@ -4,10 +4,10 @@ */ #define DEBUG #include <common.h> -#include <dm/root.h> #include <os.h> #include <asm/io.h> #include <asm/state.h> +#include <dm/root.h>
DECLARE_GLOBAL_DATA_PTR;

These headers are needed in case they are not transitively included.
Signed-off-by: Simon Glass sjg@chromium.org ---
arch/sandbox/cpu/cpu.c | 2 ++ 1 file changed, 2 insertions(+)
diff --git a/arch/sandbox/cpu/cpu.c b/arch/sandbox/cpu/cpu.c index 7a622c8..4975eb2 100644 --- a/arch/sandbox/cpu/cpu.c +++ b/arch/sandbox/cpu/cpu.c @@ -4,6 +4,8 @@ */ #define DEBUG #include <common.h> +#include <errno.h> +#include <libfdt.h> #include <os.h> #include <asm/io.h> #include <asm/state.h>

PCI is not supported in SPL for sandbox, so avoid using it.
Signed-off-by: Simon Glass sjg@chromium.org ---
arch/sandbox/cpu/cpu.c | 2 +- arch/sandbox/lib/Makefile | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-)
diff --git a/arch/sandbox/cpu/cpu.c b/arch/sandbox/cpu/cpu.c index 4975eb2..2def722 100644 --- a/arch/sandbox/cpu/cpu.c +++ b/arch/sandbox/cpu/cpu.c @@ -57,7 +57,7 @@ int cleanup_before_linux_select(int flags)
void *map_physmem(phys_addr_t paddr, unsigned long len, unsigned long flags) { -#ifdef CONFIG_PCI +#if defined(CONFIG_PCI) && !defined(CONFIG_SPL_BUILD) unsigned long plen = len; void *ptr;
diff --git a/arch/sandbox/lib/Makefile b/arch/sandbox/lib/Makefile index 96761e2..7820c55 100644 --- a/arch/sandbox/lib/Makefile +++ b/arch/sandbox/lib/Makefile @@ -8,5 +8,7 @@ #
obj-y += interrupts.o +ifndef CONFIG_SPL_BUILD obj-$(CONFIG_PCI) += pci_io.o +endif obj-$(CONFIG_CMD_BOOTM) += bootm.o

SPL does not have a command interface so we should not include the main loop code.
Signed-off-by: Simon Glass sjg@chromium.org ---
arch/sandbox/cpu/start.c | 2 ++ 1 file changed, 2 insertions(+)
diff --git a/arch/sandbox/cpu/start.c b/arch/sandbox/cpu/start.c index 969618e..6e4ec01 100644 --- a/arch/sandbox/cpu/start.c +++ b/arch/sandbox/cpu/start.c @@ -73,6 +73,7 @@ static int sandbox_cmdline_cb_help(struct sandbox_state *state, const char *arg) } SANDBOX_CMDLINE_OPT_SHORT(help, 'h', 0, "Display help");
+#ifndef CONFIG_SPL_BUILD int sandbox_main_loop_init(void) { struct sandbox_state *state = state_get_current(); @@ -97,6 +98,7 @@ int sandbox_main_loop_init(void)
return 0; } +#endif
static int sandbox_cmdline_cb_boot(struct sandbox_state *state, const char *arg)

Add an sandbox implementation for the generic SPL framework. This supports locating and running U-Boot proper.
Signed-off-by: Simon Glass sjg@chromium.org ---
arch/sandbox/cpu/Makefile | 1 + arch/sandbox/cpu/spl.c | 51 ++++++++++++++++++++++++++++++++++++++++++ arch/sandbox/include/asm/spl.h | 23 +++++++++++++++++++ 3 files changed, 75 insertions(+) create mode 100644 arch/sandbox/cpu/spl.c create mode 100644 arch/sandbox/include/asm/spl.h
diff --git a/arch/sandbox/cpu/Makefile b/arch/sandbox/cpu/Makefile index 1b42fee..db43633 100644 --- a/arch/sandbox/cpu/Makefile +++ b/arch/sandbox/cpu/Makefile @@ -8,6 +8,7 @@ #
obj-y := cpu.o os.o start.o state.o +obj-$(CONFIG_SPL_BUILD) += spl.o obj-$(CONFIG_ETH_SANDBOX_RAW) += eth-raw-os.o obj-$(CONFIG_SANDBOX_SDL) += sdl.o
diff --git a/arch/sandbox/cpu/spl.c b/arch/sandbox/cpu/spl.c new file mode 100644 index 0000000..e17c0ed --- /dev/null +++ b/arch/sandbox/cpu/spl.c @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2016 Google, Inc + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <dm.h> +#include <os.h> +#include <asm/spl.h> +#include <asm/state.h> + +DECLARE_GLOBAL_DATA_PTR; + +void board_init_f(ulong flag) +{ + struct sandbox_state *state = state_get_current(); + + gd->arch.ram_buf = state->ram_buf; + gd->ram_size = state->ram_size; +} + +u32 spl_boot_device(void) +{ + return BOOT_DEVICE_BOARD; +} + +void spl_board_announce_boot_device(void) +{ + char fname[256]; + int ret; + + ret = os_find_u_boot(fname, sizeof(fname)); + if (ret) { + printf("(%s not found, error %d)\n", fname, ret); + return; + } + printf("%s\n", fname); +} + +int spl_board_load_image(void) +{ + char fname[256]; + int ret; + + ret = os_find_u_boot(fname, sizeof(fname)); + if (ret) + return ret; + + /* Hopefully this will not return */ + return os_spl_to_uboot(fname); +} diff --git a/arch/sandbox/include/asm/spl.h b/arch/sandbox/include/asm/spl.h new file mode 100644 index 0000000..59f2401 --- /dev/null +++ b/arch/sandbox/include/asm/spl.h @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2016 Google, Inc + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef __asm_spl_h +#define __asm_spl_h + +#define CONFIG_SPL_BOARD_LOAD_IMAGE + +/** + * Board-specific load method for boards that have a special way of loading + * U-Boot, which does not fit with the existing SPL code. + * + * @return 0 on success, negative errno value on failure. + */ +int spl_board_load_image(void); + +enum { + BOOT_DEVICE_BOARD, +}; + +#endif

These functions are not supported in SPL, so drop them.
Signed-off-by: Simon Glass sjg@chromium.org ---
include/configs/sandbox.h | 4 ++++ 1 file changed, 4 insertions(+)
diff --git a/include/configs/sandbox.h b/include/configs/sandbox.h index 23a0c40..4de89f8 100644 --- a/include/configs/sandbox.h +++ b/include/configs/sandbox.h @@ -16,8 +16,10 @@
#endif
+#ifndef CONFIG_SPL_BUILD #define CONFIG_IO_TRACE #define CONFIG_CMD_IOTRACE +#endif
#ifndef CONFIG_TIMER #define CONFIG_SYS_TIMER_RATE 1000000 @@ -192,6 +194,7 @@ #define CONFIG_CMD_LZMADEC #define CONFIG_CMD_DATE
+#ifndef CONFIG_SPL_BUILD #define CONFIG_CMD_IDE #define CONFIG_SYS_IDE_MAXBUS 1 #define CONFIG_SYS_ATA_IDE0_OFFSET 0 @@ -201,6 +204,7 @@ #define CONFIG_SYS_ATA_REG_OFFSET 1 #define CONFIG_SYS_ATA_ALT_OFFSET 2 #define CONFIG_SYS_ATA_STRIDE 4 +#endif
#define CONFIG_SCSI #define CONFIG_SCSI_AHCI_PLAT

SPL does not support an LCD display so there is no need to sync the video when there is serial output.
Signed-off-by: Simon Glass sjg@chromium.org ---
drivers/serial/sandbox.c | 2 ++ 1 file changed, 2 insertions(+)
diff --git a/drivers/serial/sandbox.c b/drivers/serial/sandbox.c index 58f882b..bcc3465 100644 --- a/drivers/serial/sandbox.c +++ b/drivers/serial/sandbox.c @@ -115,7 +115,9 @@ static int sandbox_serial_pending(struct udevice *dev, bool input) return 0;
os_usleep(100); +#ifndef CONFIG_SPL_BUILD video_sync_all(); +#endif if (next_index == serial_buf_read) return 1; /* buffer full */

It is useful to be able to build SPL for sandbox. It provides additional build coverage and allows SPL features to be tested in sandbox. However it does not need worthwhile to always create an SPL build. It nearly doubles the build time and the feature is (so far) seldom used.
So for now, create a separate build target for sandbox SPL. This allows experimentation with this new feature without impacting existing workflows.
Signed-off-by: Simon Glass sjg@chromium.org ---
arch/sandbox/Kconfig | 7 +- arch/sandbox/cpu/u-boot-spl.lds | 24 ++++++ board/sandbox/MAINTAINERS | 7 ++ configs/sandbox_spl_defconfig | 177 ++++++++++++++++++++++++++++++++++++++++ include/configs/sandbox_spl.h | 18 ++++ 5 files changed, 232 insertions(+), 1 deletion(-) create mode 100644 arch/sandbox/cpu/u-boot-spl.lds create mode 100644 configs/sandbox_spl_defconfig create mode 100644 include/configs/sandbox_spl.h
diff --git a/arch/sandbox/Kconfig b/arch/sandbox/Kconfig index a8a90cb..d4c1ee0 100644 --- a/arch/sandbox/Kconfig +++ b/arch/sandbox/Kconfig @@ -10,8 +10,13 @@ config SYS_BOARD config SYS_CPU default "sandbox"
+config SANDBOX_SPL + bool "Enable SPL for sandbox" + select SUPPORT_SPL + config SYS_CONFIG_NAME - default "sandbox" + default "sandbox_spl" if SANDBOX_SPL + default "sandbox" if !SANDBOX_SPL
config PCI bool "PCI support" diff --git a/arch/sandbox/cpu/u-boot-spl.lds b/arch/sandbox/cpu/u-boot-spl.lds new file mode 100644 index 0000000..7e92b4a --- /dev/null +++ b/arch/sandbox/cpu/u-boot-spl.lds @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2011-2012 The Chromium OS Authors. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +SECTIONS +{ + + . = ALIGN(4); + .u_boot_list : { + KEEP(*(SORT(.u_boot_list*))); + } + + __u_boot_sandbox_option_start = .; + _u_boot_sandbox_getopt : { *(.u_boot_sandbox_getopt) } + __u_boot_sandbox_option_end = .; + + __bss_start = .; +} + +INSERT BEFORE .data; diff --git a/board/sandbox/MAINTAINERS b/board/sandbox/MAINTAINERS index f5db773..4dcbf4b 100644 --- a/board/sandbox/MAINTAINERS +++ b/board/sandbox/MAINTAINERS @@ -11,3 +11,10 @@ S: Maintained F: board/sandbox/ F: include/configs/sandbox.h F: configs/sandbox_noblk_defconfig + +SANDBOX SPL BOARD +M: Simon Glass sjg@chromium.org +S: Maintained +F: board/sandbox/ +F: include/configs/sandbox_spl.h +F: configs/sandbox_spl_defconfig diff --git a/configs/sandbox_spl_defconfig b/configs/sandbox_spl_defconfig new file mode 100644 index 0000000..ac30d6b --- /dev/null +++ b/configs/sandbox_spl_defconfig @@ -0,0 +1,177 @@ +CONFIG_SYS_MALLOC_F_LEN=0x2000 +CONFIG_SPL_DM=y +CONFIG_BLK=y +CONFIG_MMC=y +CONFIG_SANDBOX_SPL=y +CONFIG_PCI=y +CONFIG_DEFAULT_DEVICE_TREE="sandbox" +CONFIG_I8042_KEYB=y +CONFIG_SPL=y +CONFIG_FIT=y +CONFIG_FIT_VERBOSE=y +CONFIG_FIT_SIGNATURE=y +CONFIG_SPL_LOAD_FIT=y +CONFIG_BOOTSTAGE=y +CONFIG_BOOTSTAGE_REPORT=y +CONFIG_BOOTSTAGE_USER_COUNT=0x20 +CONFIG_BOOTSTAGE_FDT=y +CONFIG_BOOTSTAGE_STASH=y +CONFIG_BOOTSTAGE_STASH_ADDR=0x0 +CONFIG_BOOTSTAGE_STASH_SIZE=0x4096 +CONFIG_CONSOLE_RECORD=y +CONFIG_CONSOLE_RECORD_OUT_SIZE=0x1000 +CONFIG_HUSH_PARSER=y +CONFIG_CMD_CPU=y +CONFIG_CMD_LICENSE=y +CONFIG_CMD_BOOTZ=y +# CONFIG_CMD_ELF is not set +# CONFIG_CMD_IMLS is not set +CONFIG_CMD_ASKENV=y +CONFIG_CMD_GREPENV=y +CONFIG_LOOPW=y +CONFIG_CMD_MEMTEST=y +CONFIG_CMD_MX_CYCLIC=y +CONFIG_CMD_MEMINFO=y +CONFIG_CMD_DEMO=y +CONFIG_CMD_SF=y +CONFIG_CMD_SPI=y +CONFIG_CMD_I2C=y +CONFIG_CMD_USB=y +CONFIG_CMD_REMOTEPROC=y +CONFIG_CMD_GPIO=y +CONFIG_CMD_TFTPPUT=y +CONFIG_CMD_TFTPSRV=y +CONFIG_CMD_RARP=y +CONFIG_CMD_DHCP=y +CONFIG_CMD_MII=y +CONFIG_CMD_PING=y +CONFIG_CMD_CDP=y +CONFIG_CMD_SNTP=y +CONFIG_CMD_DNS=y +CONFIG_CMD_LINK_LOCAL=y +CONFIG_CMD_TIME=y +CONFIG_CMD_TIMER=y +CONFIG_CMD_SOUND=y +CONFIG_CMD_QFW=y +CONFIG_CMD_BOOTSTAGE=y +CONFIG_CMD_PMIC=y +CONFIG_CMD_REGULATOR=y +CONFIG_CMD_TPM=y +CONFIG_CMD_TPM_TEST=y +CONFIG_CMD_EXT2=y +CONFIG_CMD_EXT4=y +CONFIG_CMD_EXT4_WRITE=y +CONFIG_CMD_FAT=y +CONFIG_CMD_FS_GENERIC=y +CONFIG_OF_CONTROL=y +CONFIG_SPL_OF_CONTROL=y +CONFIG_OF_HOSTFILE=y +CONFIG_NETCONSOLE=y +CONFIG_REGMAP=y +CONFIG_SYSCON=y +CONFIG_DEVRES=y +CONFIG_DEBUG_DEVRES=y +CONFIG_ADC=y +CONFIG_ADC_SANDBOX=y +CONFIG_CLK=y +CONFIG_CPU=y +CONFIG_DM_DEMO=y +CONFIG_DM_DEMO_SIMPLE=y +CONFIG_DM_DEMO_SHAPE=y +CONFIG_PM8916_GPIO=y +CONFIG_SANDBOX_GPIO=y +CONFIG_DM_I2C_COMPAT=y +CONFIG_I2C_CROS_EC_TUNNEL=y +CONFIG_I2C_CROS_EC_LDO=y +CONFIG_DM_I2C_GPIO=y +CONFIG_SYS_I2C_SANDBOX=y +CONFIG_I2C_MUX=y +CONFIG_SPL_I2C_MUX=y +CONFIG_I2C_ARB_GPIO_CHALLENGE=y +CONFIG_CROS_EC_KEYB=y +CONFIG_LED=y +CONFIG_LED_GPIO=y +CONFIG_DM_MAILBOX=y +CONFIG_SANDBOX_MBOX=y +CONFIG_MISC=y +CONFIG_CMD_CROS_EC=y +CONFIG_CROS_EC=y +CONFIG_CROS_EC_I2C=y +CONFIG_CROS_EC_LPC=y +CONFIG_CROS_EC_SANDBOX=y +CONFIG_CROS_EC_SPI=y +CONFIG_PWRSEQ=y +CONFIG_SPL_PWRSEQ=y +CONFIG_SYSRESET=y +CONFIG_DM_MMC=y +CONFIG_SANDBOX_MMC=y +CONFIG_SPI_FLASH_SANDBOX=y +CONFIG_SPI_FLASH=y +CONFIG_SPI_FLASH_ATMEL=y +CONFIG_SPI_FLASH_EON=y +CONFIG_SPI_FLASH_GIGADEVICE=y +CONFIG_SPI_FLASH_MACRONIX=y +CONFIG_SPI_FLASH_SPANSION=y +CONFIG_SPI_FLASH_STMICRO=y +CONFIG_SPI_FLASH_SST=y +CONFIG_SPI_FLASH_WINBOND=y +CONFIG_DM_ETH=y +CONFIG_DM_PCI=y +CONFIG_DM_PCI_COMPAT=y +CONFIG_PCI_SANDBOX=y +CONFIG_PINCTRL=y +CONFIG_PINCONF=y +CONFIG_ROCKCHIP_PINCTRL=y +CONFIG_ROCKCHIP_3036_PINCTRL=y +CONFIG_PINCTRL_SANDBOX=y +CONFIG_DM_PMIC=y +CONFIG_PMIC_ACT8846=y +CONFIG_DM_PMIC_PFUZE100=y +CONFIG_DM_PMIC_MAX77686=y +CONFIG_PMIC_PM8916=y +CONFIG_PMIC_RK808=y +CONFIG_PMIC_S2MPS11=y +CONFIG_DM_PMIC_SANDBOX=y +CONFIG_PMIC_S5M8767=y +CONFIG_PMIC_TPS65090=y +CONFIG_DM_REGULATOR=y +CONFIG_REGULATOR_ACT8846=y +CONFIG_DM_REGULATOR_PFUZE100=y +CONFIG_DM_REGULATOR_MAX77686=y +CONFIG_DM_REGULATOR_FIXED=y +CONFIG_REGULATOR_RK808=y +CONFIG_REGULATOR_S5M8767=y +CONFIG_DM_REGULATOR_SANDBOX=y +CONFIG_REGULATOR_TPS65090=y +CONFIG_RAM=y +CONFIG_REMOTEPROC_SANDBOX=y +CONFIG_DM_RTC=y +CONFIG_SANDBOX_SERIAL=y +CONFIG_SOUND=y +CONFIG_SOUND_SANDBOX=y +CONFIG_SANDBOX_SPI=y +CONFIG_SPMI=y +CONFIG_SPMI_SANDBOX=y +CONFIG_TIMER=y +CONFIG_TIMER_EARLY=y +CONFIG_SANDBOX_TIMER=y +CONFIG_TPM_TIS_SANDBOX=y +CONFIG_USB=y +CONFIG_DM_USB=y +CONFIG_USB_EMUL=y +CONFIG_USB_STORAGE=y +CONFIG_USB_KEYBOARD=y +CONFIG_SYS_USB_EVENT_POLL=y +CONFIG_DM_VIDEO=y +CONFIG_CONSOLE_ROTATION=y +CONFIG_CONSOLE_TRUETYPE=y +CONFIG_CONSOLE_TRUETYPE_CANTORAONE=y +CONFIG_VIDEO_SANDBOX_SDL=y +CONFIG_CMD_DHRYSTONE=y +CONFIG_TPM=y +CONFIG_LZ4=y +CONFIG_ERRNO_STR=y +CONFIG_UNIT_TEST=y +CONFIG_UT_TIME=y +CONFIG_UT_DM=y +CONFIG_UT_ENV=y diff --git a/include/configs/sandbox_spl.h b/include/configs/sandbox_spl.h new file mode 100644 index 0000000..7b5c3f3 --- /dev/null +++ b/include/configs/sandbox_spl.h @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2016 Google, Inc + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef __SANDBOX_SPL_CONFIG_H +#define __SANDBOX_SPL_CONFIG_H + +#include <configs/sandbox.h> + +#define CONFIG_SPL_DRIVERS_MISC_SUPPORT +#define CONFIG_SPL_ENV_SUPPORT +#define CONFIG_SPL_FRAMEWORK +#define CONFIG_SPL_LIBCOMMON_SUPPORT +#define CONFIG_SPL_LIBGENERIC_SUPPORT +#define CONFIG_SPL_SERIAL_SUPPORT + +#endif

Add a simple test device that provides a check that the of-platdata feature is working correctly.
Signed-off-by: Simon Glass sjg@chromium.org ---
arch/sandbox/cpu/spl.c | 9 +++++++++ arch/sandbox/dts/sandbox.dts | 13 +++++++++++++ include/configs/sandbox_spl.h | 2 ++ 3 files changed, 24 insertions(+)
diff --git a/arch/sandbox/cpu/spl.c b/arch/sandbox/cpu/spl.c index e17c0ed..b064709 100644 --- a/arch/sandbox/cpu/spl.c +++ b/arch/sandbox/cpu/spl.c @@ -49,3 +49,12 @@ int spl_board_load_image(void) /* Hopefully this will not return */ return os_spl_to_uboot(fname); } + +void spl_board_init(void) +{ + struct udevice *dev; + int ret; + + ret = uclass_first_device(UCLASS_MISC, &dev); + printf("ret=%d, dev=%p\n", ret, dev); +} diff --git a/arch/sandbox/dts/sandbox.dts b/arch/sandbox/dts/sandbox.dts index 2ae4014..3455bc0 100644 --- a/arch/sandbox/dts/sandbox.dts +++ b/arch/sandbox/dts/sandbox.dts @@ -172,6 +172,19 @@ }; };
+ spl-test { + u-boot,dm-pre-reloc; + compatible = "sandbox,spl-test"; + boolval; + intval = <1>; + intarray = <2 3 4>; + byteval = [05]; + bytearray = [06 07 08]; + longbytearray = [09 0a 0b 0c 0d 0e 0f 10 11]; + string = "message"; + stringarray = "multi-word", "message"; + }; + square { compatible = "demo-shape"; colour = "blue"; diff --git a/include/configs/sandbox_spl.h b/include/configs/sandbox_spl.h index 7b5c3f3..ffc3098 100644 --- a/include/configs/sandbox_spl.h +++ b/include/configs/sandbox_spl.h @@ -8,6 +8,8 @@
#include <configs/sandbox.h>
+#define CONFIG_SPL_BOARD_INIT + #define CONFIG_SPL_DRIVERS_MISC_SUPPORT #define CONFIG_SPL_ENV_SUPPORT #define CONFIG_SPL_FRAMEWORK

When this feature is enabled, we should not access the device tree.
Signed-off-by: Simon Glass sjg@chromium.org ---
common/spl/spl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/common/spl/spl.c b/common/spl/spl.c index e931edd..45a988d 100644 --- a/common/spl/spl.c +++ b/common/spl/spl.c @@ -197,7 +197,7 @@ int spl_init(void) gd->malloc_limit = CONFIG_SYS_MALLOC_F_LEN; gd->malloc_ptr = 0; #endif - if (CONFIG_IS_ENABLED(OF_CONTROL)) { + if (CONFIG_IS_ENABLED(OF_CONTROL) && !CONFIG_IS_ENABLED(OF_PLATDATA)) { ret = fdtdec_setup(); if (ret) { debug("fdtdec_setup() returned error %d\n", ret);

Since SPL needs the of-platdata structures, build these before starting to build any SPL components.
Signed-off-by: Simon Glass sjg@chromium.org ---
Makefile | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/Makefile b/Makefile index 5b03095..edefc0b 100644 --- a/Makefile +++ b/Makefile @@ -1316,7 +1316,8 @@ u-boot.lds: $(LDSCRIPT) prepare FORCE
spl/u-boot-spl.bin: spl/u-boot-spl @: -spl/u-boot-spl: tools prepare $(if $(CONFIG_OF_SEPARATE),dts/dt.dtb) +spl/u-boot-spl: tools prepare \ + $(if $(CONFIG_OF_SEPARATE)$(CONFIG_SPL_OF_PLATDATA),dts/dt.dtb) $(Q)$(MAKE) obj=spl -f $(srctree)/scripts/Makefile.spl all
spl/sunxi-spl.bin: spl/u-boot-spl

When CONFIG_SPL_OF_PLATDATA is enabled we should not access the device tree. Remove all references to this in the core driver-model code.
Signed-off-by: Simon Glass sjg@chromium.org ---
drivers/core/device.c | 2 +- drivers/core/lists.c | 2 +- drivers/core/root.c | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/drivers/core/device.c b/drivers/core/device.c index eb75b17..de52f07 100644 --- a/drivers/core/device.c +++ b/drivers/core/device.c @@ -607,7 +607,7 @@ const char *dev_get_uclass_name(struct udevice *dev)
fdt_addr_t dev_get_addr_index(struct udevice *dev, int index) { -#if CONFIG_IS_ENABLED(OF_CONTROL) +#if CONFIG_IS_ENABLED(OF_CONTROL) && !CONFIG_IS_ENABLED(OF_PLATDATA) fdt_addr_t addr;
if (CONFIG_IS_ENABLED(OF_TRANSLATE)) { diff --git a/drivers/core/lists.c b/drivers/core/lists.c index 0c27717..6a634e6 100644 --- a/drivers/core/lists.c +++ b/drivers/core/lists.c @@ -99,7 +99,7 @@ int device_bind_driver_to_node(struct udevice *parent, const char *drv_name, return 0; }
-#if CONFIG_IS_ENABLED(OF_CONTROL) +#if CONFIG_IS_ENABLED(OF_CONTROL) && !CONFIG_IS_ENABLED(OF_PLATDATA) /** * driver_check_compatible() - Check if a driver is compatible with this node * diff --git a/drivers/core/root.c b/drivers/core/root.c index 13c2713..0743aeb 100644 --- a/drivers/core/root.c +++ b/drivers/core/root.c @@ -173,7 +173,7 @@ int dm_scan_platdata(bool pre_reloc_only) return ret; }
-#if CONFIG_IS_ENABLED(OF_CONTROL) +#if CONFIG_IS_ENABLED(OF_CONTROL) && !CONFIG_IS_ENABLED(OF_PLATDATA) int dm_scan_fdt_node(struct udevice *parent, const void *blob, int offset, bool pre_reloc_only) { @@ -229,7 +229,7 @@ int dm_init_and_scan(bool pre_reloc_only) return ret; }
- if (CONFIG_IS_ENABLED(OF_CONTROL)) { + if (CONFIG_IS_ENABLED(OF_CONTROL) && !CONFIG_IS_ENABLED(OF_PLATDATA)) { ret = dm_scan_fdt(gd->fdt_blob, pre_reloc_only); if (ret) { debug("dm_scan_fdt() failed: %d\n", ret);

Add a placeholder for now so that this code will compile. It currently does nothing.
Signed-off-by: Simon Glass sjg@chromium.org ---
drivers/core/regmap.c | 9 +++++++++ include/regmap.h | 3 +++ 2 files changed, 12 insertions(+)
diff --git a/drivers/core/regmap.c b/drivers/core/regmap.c index 519832f..7e073cf 100644 --- a/drivers/core/regmap.c +++ b/drivers/core/regmap.c @@ -15,6 +15,14 @@
DECLARE_GLOBAL_DATA_PTR;
+#if CONFIG_IS_ENABLED(OF_PLATDATA) +int regmap_init_mem_platdata(struct udevice *dev, fdt32_t *reg, int size, + struct regmap **mapp) +{ + /* TODO(sjg@chromium.org): Implement this when needed */ + return 0; +} +#else int regmap_init_mem(struct udevice *dev, struct regmap **mapp) { const void *blob = gd->fdt_blob; @@ -64,6 +72,7 @@ int regmap_init_mem(struct udevice *dev, struct regmap **mapp)
return 0; } +#endif
void *regmap_get_range(struct regmap *map, unsigned int range_num) { diff --git a/include/regmap.h b/include/regmap.h index eccf770..922b39f 100644 --- a/include/regmap.h +++ b/include/regmap.h @@ -56,6 +56,9 @@ int regmap_read(struct regmap *map, uint offset, uint *valp); */ int regmap_init_mem(struct udevice *dev, struct regmap **mapp);
+int regmap_init_mem_platdata(struct udevice *dev, fdt32_t *reg, int size, + struct regmap **mapp); + /** * regmap_get_range() - Obtain the base memory address of a regmap range *

Provide a new function which can cope with obtaining information from of-platdata instead of the device tree.
Signed-off-by: Simon Glass sjg@chromium.org ---
drivers/core/syscon-uclass.c | 13 +++++++++++++ include/syscon.h | 6 ++++++ 2 files changed, 19 insertions(+)
diff --git a/drivers/core/syscon-uclass.c b/drivers/core/syscon-uclass.c index e03f46a..01bd968 100644 --- a/drivers/core/syscon-uclass.c +++ b/drivers/core/syscon-uclass.c @@ -29,7 +29,20 @@ static int syscon_pre_probe(struct udevice *dev) { struct syscon_uc_info *priv = dev_get_uclass_priv(dev);
+ /* + * With OF_PLATDATA we really have no way of knowing the format of + * the device-specific platform data. So we assume that it starts with + * a 'reg' member, and this holds a single address and size. Drivers + * using OF_PLATDATA will need to ensure that this is true. + */ +#if CONFIG_IS_ENABLED(OF_PLATDATA) + struct syscon_base_platdata *plat = dev_get_platdata(dev); + + return regmap_init_mem_platdata(dev, plat->reg, ARRAY_SIZE(plat->reg), + &priv->regmap); +#else return regmap_init_mem(dev, &priv->regmap); +#endif }
int syscon_get_by_driver_data(ulong driver_data, struct udevice **devp) diff --git a/include/syscon.h b/include/syscon.h index 4593b6e..19c66b3 100644 --- a/include/syscon.h +++ b/include/syscon.h @@ -23,6 +23,12 @@ struct syscon_ops {
#define syscon_get_ops(dev) ((struct syscon_ops *)(dev)->driver->ops)
+#if CONFIG_IS_ENABLED(OF_PLATDATA) +struct syscon_base_platdata { + u32 reg[2]; +}; +#endif + /** * syscon_get_regmap() - Get access to a register map *

Add a driver which uses of-platdata to obtain its platform data. This can be used to test the feature in sandbox.
Signed-off-by: Simon Glass sjg@chromium.org ---
drivers/misc/Makefile | 5 +++++ drivers/misc/spltest_sandbox.c | 28 ++++++++++++++++++++++++++++ 2 files changed, 33 insertions(+) create mode 100644 drivers/misc/spltest_sandbox.c
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index 066639b..3eac024 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile @@ -35,6 +35,11 @@ obj-$(CONFIG_SMSC_LPC47M) += smsc_lpc47m.o obj-$(CONFIG_SMSC_SIO1007) += smsc_sio1007.o obj-$(CONFIG_STATUS_LED) += status_led.o obj-$(CONFIG_SANDBOX) += swap_case.o +ifdef CONFIG_SPL_OF_PLATDATA +ifdef CONFIG_SPL_BUILD +obj-$(CONFIG_SANDBOX) += spltest_sandbox.o +endif +endif obj-$(CONFIG_SANDBOX) += syscon_sandbox.o obj-$(CONFIG_TWL4030_LED) += twl4030_led.o obj-$(CONFIG_FSL_IFC) += fsl_ifc.o diff --git a/drivers/misc/spltest_sandbox.c b/drivers/misc/spltest_sandbox.c new file mode 100644 index 0000000..ac4d10c --- /dev/null +++ b/drivers/misc/spltest_sandbox.c @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2016 Google, Inc + * Written by Simon Glass sjg@chromium.org + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <dm.h> +#include <dt-structs.h> + +DECLARE_GLOBAL_DATA_PTR; + +static int sandbox_spl_probe(struct udevice *dev) +{ + struct dtd_sandbox_spl_test *plat = dev_get_platdata(dev); + + printf("here %s\n", plat->string); + + return 0; +} + +U_BOOT_DRIVER(sandbox_spl_test) = { + .name = "sandbox_spl_test", + .id = UCLASS_MISC, + .flags = DM_FLAG_PRE_RELOC, + .probe = sandbox_spl_probe, +};

This header can be included from anywhere, but will only pull in the of-platdata struct definitions when this feature is enabled (and only in SPL).
Signed-off-by: Simon Glass sjg@chromium.org ---
include/dt-structs.h | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 include/dt-structs.h
diff --git a/include/dt-structs.h b/include/dt-structs.h new file mode 100644 index 0000000..e13afa6 --- /dev/null +++ b/include/dt-structs.h @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2016 Google, Inc + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef __DT_STTUCTS +#define __DT_STTUCTS + +/* These structures may only be used in SPL */ +#if CONFIG_IS_ENABLED(OF_PLATDATA) +struct phandle_2_cell { + const void *node; + int id; +}; +#include <generated/dt-structs.h> +#endif + +#endif

Add support for this feature in the core clock code.
Signed-off-by: Simon Glass sjg@chromium.org ---
drivers/clk/clk-uclass.c | 20 ++++++++++++++++++++ drivers/clk/clk_fixed_rate.c | 2 ++ include/clk.h | 4 ++++ 3 files changed, 26 insertions(+)
diff --git a/drivers/clk/clk-uclass.c b/drivers/clk/clk-uclass.c index b483c1e..efe2d4e 100644 --- a/drivers/clk/clk-uclass.c +++ b/drivers/clk/clk-uclass.c @@ -8,6 +8,7 @@ #include <common.h> #include <clk.h> #include <dm.h> +#include <dt-structs.h> #include <errno.h> #include <dm/lists.h> #include <dm/root.h> @@ -65,6 +66,22 @@ ulong clk_set_periph_rate(struct udevice *dev, int periph, ulong rate) }
#if CONFIG_IS_ENABLED(OF_CONTROL) +# if CONFIG_IS_ENABLED(OF_PLATDATA) +int clk_get_by_index_platdata(struct udevice *dev, int index, + struct phandle_2_cell *cells, + struct udevice **clk_devp) +{ + int ret; + + if (index != 0) + return -ENOSYS; + assert(*clk_devp); + ret = uclass_get_device(UCLASS_CLK, 0, clk_devp); + if (ret) + return ret; + return cells[0].id; +} +# else int clk_get_by_index(struct udevice *dev, int index, struct udevice **clk_devp) { int ret; @@ -104,6 +121,9 @@ int clk_get_by_index(struct udevice *dev, int index, struct udevice **clk_devp) return args.args_count > 0 ? args.args[0] : 0; #endif } +# endif /* OF_PLATDATA */ +#else + #endif
UCLASS_DRIVER(clk) = { diff --git a/drivers/clk/clk_fixed_rate.c b/drivers/clk/clk_fixed_rate.c index 8beda9c..8c3fb8f 100644 --- a/drivers/clk/clk_fixed_rate.c +++ b/drivers/clk/clk_fixed_rate.c @@ -33,9 +33,11 @@ const struct clk_ops clk_fixed_rate_ops = {
static int clk_fixed_rate_ofdata_to_platdata(struct udevice *dev) { +#if !CONFIG_IS_ENABLED(OF_PLATDATA) to_clk_fixed_rate(dev)->fixed_rate = fdtdec_get_int(gd->fdt_blob, dev->of_offset, "clock-frequency", 0); +#endif
return 0; } diff --git a/include/clk.h b/include/clk.h index ca20c3d..e4d23be 100644 --- a/include/clk.h +++ b/include/clk.h @@ -120,6 +120,10 @@ ulong clk_set_periph_rate(struct udevice *dev, int periph, ulong rate); * argument after the clock node phandle. If there is no arguemnt, * returns 0. Return -ve error code on any error */ +struct phandle_2_cell; +int clk_get_by_index_platdata(struct udevice *dev, int index, + struct phandle_2_cell *cells, + struct udevice **clk_devp); int clk_get_by_index(struct udevice *dev, int index, struct udevice **clk_devp); #else static inline int clk_get_by_index(struct udevice *dev, int index,

When this feature is enabled, we cannot access the device tree to find out which serial device to use. Just use the first serial driver we find.
Signed-off-by: Simon Glass sjg@chromium.org ---
drivers/serial/serial-uclass.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-)
diff --git a/drivers/serial/serial-uclass.c b/drivers/serial/serial-uclass.c index 0ce5c44..19f38e1 100644 --- a/drivers/serial/serial-uclass.c +++ b/drivers/serial/serial-uclass.c @@ -33,7 +33,13 @@ static void serial_find_console_or_panic(void) struct udevice *dev; int node;
- if (CONFIG_IS_ENABLED(OF_CONTROL) && blob) { + if (CONFIG_IS_ENABLED(OF_PLATDATA)) { + uclass_first_device(UCLASS_SERIAL, &dev); + if (dev) { + gd->cur_serial_dev = dev; + return; + } + } else if (CONFIG_IS_ENABLED(OF_CONTROL) && blob) { /* Check for a chosen console */ node = fdtdec_get_chosen_node(blob, "stdout-path"); if (node < 0) {

We cannot access the device tree in this case, so avoid compiling in the various device-tree helper functions.
Signed-off-by: Simon Glass sjg@chromium.org ---
lib/Makefile | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-)
diff --git a/lib/Makefile b/lib/Makefile index f77befe..2fc0272 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -49,11 +49,10 @@ obj-y += list_sort.o endif
obj-$(CONFIG_$(SPL_)OF_LIBFDT) += libfdt/ -ifdef CONFIG_SPL_OF_CONTROL -obj-$(CONFIG_OF_LIBFDT) += libfdt/ -endif +ifneq ($(CONFIG_SPL_BUILD)$(CONFIG_SPL_OF_PLATDATA),yy) obj-$(CONFIG_$(SPL_)OF_CONTROL) += fdtdec_common.o obj-$(CONFIG_$(SPL_)OF_CONTROL) += fdtdec.o +endif
ifdef CONFIG_SPL_BUILD obj-$(CONFIG_SPL_YMODEM_SUPPORT) += crc16.o

Add a Kconfig option to enable this feature.
Signed-off-by: Simon Glass sjg@chromium.org ---
dts/Kconfig | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+)
diff --git a/dts/Kconfig b/dts/Kconfig index c56c129..4b7d8b1 100644 --- a/dts/Kconfig +++ b/dts/Kconfig @@ -85,4 +85,25 @@ config OF_SPL_REMOVE_PROPS can be discarded. This option defines the list of properties to discard.
+config SPL_OF_PLATDATA + bool "Generate platform data for use in SPL" + depends on SPL_OF_CONTROL + help + For very constrained SPL environments the overhead of decoding + device tree nodes and converting their contents into platform data + is too large. This overhead includes libfdt code as well as the + device tree contents itself. The latter is fairly compact, but the + former can add 3KB or more to a Thumb 2 Image. + + This option enables generation of platform data from the device + tree as C code. This code creates devices using U_BOOT_DEVICE() + declarations. The benefit is that it allows driver code to access + the platform data directly in C structures, avoidin the libfdt + overhead. + + This option works by generating C structure declarations for each + compatible string, then adding platform data and U_BOOT_DEVICE + declarations for each node. See README.platdata for more + information. + endmenu

Add documentation on how this works, including the benefits and drawbacks.
Signed-off-by: Simon Glass sjg@chromium.org ---
doc/driver-model/of-plat.txt | 266 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 266 insertions(+) create mode 100644 doc/driver-model/of-plat.txt
diff --git a/doc/driver-model/of-plat.txt b/doc/driver-model/of-plat.txt new file mode 100644 index 0000000..a644e9a --- /dev/null +++ b/doc/driver-model/of-plat.txt @@ -0,0 +1,266 @@ +Driver Model Compiled-in Device Tree / Platform Data +==================================================== + + +Introduction +------------ + +Device tree is the standard configuration method in U-Boot. It is used to +define what devices are in the system and provide configuration information +to these devices. + +The overhead of adding device tree access to U-Boot is fairly modest, +approximately 3KB on Thumb 2 (plus the size of the DT itself). This means +that in most cases it is best to use device tree for configuration. + +However there are some very constrained environments where U-Boot needs to +work. These include SPL with severe memory limitations. For example, some +SoCs require a 16KB SPL image which must include a full MMC stack. In this +case the overhead of device tree access may be too great. + +It is possible to create platform data manually by defining C structures +for it, and referencing that data in a U_BOOT_DEVICE() declaration. This +bypasses the use of device tree completely, but is an available option for +SPL. + +As an alternative, a new 'of-platdata' feature is provided. This converts +device tree contents into C code which can be compiled into the SPL binary. +This saves the 3KB of code overhead and perhaps a few hundred more bytes due +to more efficient storage of the data. + + +Caveats +------- + +There are many problems with this features. It should only be used when +stricly necessary. Notable problems include: + + - Device tree does not describe data types but the C code must define a + type for each property. Thesee are guessed using heuristics which + are wrong in several fairly common cases. For example an 8-byte value + is considered to be a 2-item integer array, and is byte-swapped. A + boolean value that is not present means 'false', but cannot be + included in the structures since there is generally no mention of it + in the device tree file. + + - Naming of nodes and properties is automatic. This means that they follow + the naming in the device tree, which may result in C identifiers that + look a bit strange + + - It is not possible to find a value given a property name. Code must use + the associated C member variable directly in the code. This makes + the code less robust in the face of device-tree changes. It also + makes it very unlikely that your driver code will be useful for more + than one SoC. Even if the code is common, each SoC will end up with + a different C struct and format for the platform data. + + - The platform data is provided to drivers as a C structure. The driver + must use the same structure to access the data. Since a driver + normally also supports device tree it must use #ifdef to separate + out this code, since the structures are only available in SPL. + + +How it works +------------ + +The feature is enabled by CONFIG SPL_OF_PLATDATA. This is only available +in SPL and should be tested with: + + #if CONFIG_IS_ENABLED(SPL_OF_PLATDATA) + +A new tool called 'dtoc' converts a device tree file either into a set of +struct declarations, one for each compatible node, or a set of +U_BOOT_DEVICE() declarations along with the actual platform data for each +device. As an example, consider this MMC node: + + sdmmc: dwmmc@ff0c0000 { + compatible = "rockchip,rk3288-dw-mshc"; + clock-freq-min-max = <400000 150000000>; + clocks = <&cru HCLK_SDMMC>, <&cru SCLK_SDMMC>, + <&cru SCLK_SDMMC_DRV>, <&cru SCLK_SDMMC_SAMPLE>; + clock-names = "biu", "ciu", "ciu_drv", "ciu_sample"; + fifo-depth = <0x100>; + interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_HIGH>; + reg = <0xff0c0000 0x4000>; + bus-width = <4>; + cap-mmc-highspeed; + cap-sd-highspeed; + card-detect-delay = <200>; + disable-wp; + num-slots = <1>; + pinctrl-names = "default"; + pinctrl-0 = <&sdmmc_clk>, <&sdmmc_cmd>, <&sdmmc_cd>, <&sdmmc_bus4>; + vmmc-supply = <&vcc_sd>; + status = "okay"; + u-boot,dm-pre-reloc; + }; + + +Some of these properties are dropped by U-Boot under control of the +CONFIG_OF_SPL_REMOVE_PROPS option. The rest are processed. This will produce +the following C struct declaration: + +struct dtd_rockchip_rk3288_dw_mshc { + fdt32_t bus_width; + bool cap_mmc_highspeed; + bool cap_sd_highspeed; + fdt32_t card_detect_delay; + fdt32_t clock_freq_min_max[2]; + struct phandle_2_cell clocks[4]; + bool disable_wp; + fdt32_t fifo_depth; + fdt32_t interrupts[3]; + fdt32_t num_slots; + fdt32_t reg[2]; + bool u_boot_dm_pre_reloc; + fdt32_t vmmc_supply; +}; + +and the following device declaration: + +static struct dtd_rockchip_rk3288_dw_mshc dtv_dwmmc_at_ff0c0000 = { + .fifo_depth = 0x100, + .cap_sd_highspeed = true, + .interrupts = {0x0, 0x20, 0x4}, + .clock_freq_min_max = {0x61a80, 0x8f0d180}, + .vmmc_supply = 0xb, + .num_slots = 0x1, + .clocks = {{&dtv_clock_controller_at_ff760000, 456}, {&dtv_clock_controller_at_ff760000, 68}, {&dtv_clock_controller_at_ff760000, 114}, {&dtv_clock_controller_at_ff760000, 118}}, + .cap_mmc_highspeed = true, + .disable_wp = true, + .bus_width = 0x4, + .u_boot_dm_pre_reloc = true, + .reg = {0xff0c0000, 0x4000}, + .card_detect_delay = 0xc8, +}; +U_BOOT_DEVICE(dwmmc_at_ff0c0000) = { + .name = "rockchip_rk3288_dw_mshc", + .platdata = &dtv_dwmmc_at_ff0c0000, +}; + +The device is then instantiated at run-time and the platform data can be +accessed using: + + struct udevice *dev; + struct dtd_rockchip_rk3288_dw_mshc *plat = dev_get_platdata(dev); + +This avoids the code overhead of converting the device tree data to +platform data in the driver. The ofdata_to_platdata() method should +therefore do nothing in such a driver. + + +How to structure your driver +---------------------------- + +Drivers should always support device tree as an option. The of-platdata +feature is intended as a add-on to existing drivers. + +Your driver should directly access the platdata struct in its probe() +method. The existing device tree decoding logic should be kept in the +ofdata_to_platdata() and wrapped with #ifdef. + +For example: + + #include <dt-structs.h> + + struct mmc_platdata { + #if CONFIG_IS_ENABLED(SPL_OF_PLATDATA) + /* Put this first */ + struct dtd_mmc dtplat; + #endif + /* + * Other fields can go here, to be filled in by decoding from + * the device tree. They will point to random memory in the + * of-plat case. + */ + int fifo_depth; + }; + + static int mmc_ofdata_to_platdata(struct udevice *dev) + { + #if !CONFIG_IS_ENABLED(SPL_OF_PLATDATA) + struct mmc_platdata *plat = dev_get_platdata(dev); + const void *blob = gd->fdt_blob; + int node = dev->of_offset; + + plat->fifo_depth = fdtdec_get_int(blob, node, "fifo-depth", 0); + #endif + + return 0; + } + + static int mmc_probe(struct udevice *dev) + { + struct mmc_platdata *plat = dev_get_platdata(dev); + #if CONFIG_IS_ENABLED(SPL_OF_PLATDATA) + struct dtd_mmc *dtplat = &plat->dtplat; + + /* Set up the device from the dtplat data */ + writel(dtplat->fifo_depth, ...) + #else + /* Set up the device from the plat data */ + writel(plat->fifo_depth, ...) + #endif + } + + static const struct udevice_id mmc_ids[] = { + { .compatible = "vendor,mmc" }, + { } + }; + + U_BOOT_DRIVER(mmc_drv) = { + .name = "mmc", + .id = UCLASS_MMC, + .of_match = mmc_ids, + .ofdata_to_platdata = mmc_ofdata_to_platdata, + .probe = mmc_probe, + .priv_auto_alloc_size = sizeof(struct mmc_priv), + .platdata_auto_alloc_size = sizeof(struct mmc_platdata), + }; + + +In the case where SPL_OF_PLATDATA is enabled, platdata_auto_alloc_size is +ignored, and the platform data points to the C structure data. In the case +where device tree is used, the platform data is allocated, and starts +zeroed. In this case the ofdata_to_platdata() method should set up the +platform data. + +SPL must use either of-platdata or device tree. Drivers cannot use both. +The device tree becomes in accessible when CONFIG_SPL_OF_PLATDATA is enabled, +since the device-tree access code is not compiled in. + + +Internals +--------- + +The dt-structs.h file includes the generated file +(include/generated//dt-structs.h) if CONFIG_SPL_OF_PLATDATA is enabled. +Otherwise (such as in U-Boot proper) these structs are not available. This +prevents them being used inadvertently. + +The dt-platdata.c file contains the device declarations and is is built in +spl/dt-platdata.c. + +Some phandles (thsoe that are recognised as such) are converted into +points to platform data. This pointer can potentially be used to access the +referenced device (by searching for the pointer value). This feature is not +yet implemented, however. + +The beginnings of a libfdt Python module are provided. So far this only +implements a subset of the features. + + +Future work +----------- +- Add unit tests +- Add a sandbox_spl functional test +- Consider programmatically reading binding files instead of device tree + contents +- Drop the device tree data from the SPL image +- Complete the phandle feature +- Get this running on a Rockchip board +- Move to using a full Python libfdt module + +-- +Simon Glass sjg@chromium.org +6/6/16

This Python library provides a way to access the contents of the device tree. It uses fdtget, so is inefficient for larger device tree files.
Signed-off-by: Simon Glass sjg@chromium.org ---
tools/dtoc/.gitignore | 1 + tools/dtoc/fdt_fallback.py | 207 +++++++++++++++++++++++++++++++++++++++++++++ tools/dtoc/fdt_util.py | 71 ++++++++++++++++ 3 files changed, 279 insertions(+) create mode 100644 tools/dtoc/.gitignore create mode 100644 tools/dtoc/fdt_fallback.py create mode 100644 tools/dtoc/fdt_util.py
diff --git a/tools/dtoc/.gitignore b/tools/dtoc/.gitignore new file mode 100644 index 0000000..0d20b64 --- /dev/null +++ b/tools/dtoc/.gitignore @@ -0,0 +1 @@ +*.pyc diff --git a/tools/dtoc/fdt_fallback.py b/tools/dtoc/fdt_fallback.py new file mode 100644 index 0000000..14decf3 --- /dev/null +++ b/tools/dtoc/fdt_fallback.py @@ -0,0 +1,207 @@ +#!/usr/bin/python +# +# Copyright (C) 2016 Google, Inc +# Written by Simon Glass sjg@chromium.org +# +# SPDX-License-Identifier: GPL-2.0+ +# + +import command +import fdt_util +import sys + +# This deals with a device tree, presenting it as a list of Node and Prop +# objects, representing nodes and properties, respectively. +# +# This implementation uses the fdtget tool to access the device tree, so it +# is not very efficient for larger trees. The tool is called once for each +# node and property in the tree. + +class Prop: + """A device tree property + + Properties: + name: Property name (as per the device tree) + value: Property value as a string of bytes, or a list of strings of + bytes + type: Value type + """ + def __init__(self, name, byte_list_str): + self.name = name + self.value = None + if not byte_list_str.strip(): + self.type = fdt_util.TYPE_BOOL + return + bytes = [chr(int(byte, 16)) for byte in byte_list_str.strip().split(' ')] + self.type, self.value = fdt_util.BytesToValue(''.join(bytes)) + + def GetPhandle(self): + """Get a (single) phandle value from a property + + Gets the phandle valuie from a property and returns it as an integer + """ + return fdt_util.fdt32_to_cpu(self.value[:4]) + + def Widen(self, newprop): + """Figure out which property type is more general + + Given a current property and a new property, this function returns the + one that is less specific as to type. The less specific property will + be ble to represent the data in the more specific property. This is + used for things like: + + node1 { + compatible = "fred"; + value = <1>; + }; + node1 { + compatible = "fred"; + value = <1 2>; + }; + + He we want to use an int array for 'value'. The first property + suggests that a single int is enough, but the second one shows that + it is not. Calling this function with these two propertes would + update the current property to be like the second, since it is less + specific. + """ + if newprop.type < self.type: + self.type = newprop.type + + if type(newprop.value) == list and type(self.value) != list: + self.value = newprop.value + +class Node: + """A device tree node + + Properties: + name: Device tree node tname + path: Full path to node, along with the node name itself + _fdt: Device tree object + subnodes: A list of subnodes for this node, each a Node object + props: A dict of properties for this node, each a Prop object. + Keyed by property name + """ + def __init__(self, fdt, name, path): + self.name = name + self.path = path + self._fdt = fdt + self.subnodes = [] + self.props = {} + + def Scan(self): + """Scan a node's properties and subnodes + + This fills in the props and subnodes properties, recursively + searching into subnodes so that the entire tree is built. + """ + for name, byte_list_str in self._fdt.GetProps(self.path).iteritems(): + prop = Prop(name, byte_list_str) + self.props[name] = prop + + for name in self._fdt.GetSubNodes(self.path): + sep = '' if self.path[-1] == '/' else '/' + path = self.path + sep + name + node = Node(self._fdt, name, path) + self.subnodes.append(node) + + node.Scan() + + +class Fdt: + """Provides simple access to a flat device tree blob. + + Properties: + fname: Filename of fdt + _root: Root of device tree (a Node object) + """ + + def __init__(self, fname): + self.fname = fname + + def Scan(self): + """Scan a device tree, building up a tree of Node objects + + This fills in the self._root property + """ + self._root = Node(self, '/', '/') + self._root.Scan() + + def GetRoot(self): + """Get the root Node of the device tree + + Returns: + The root Node object + """ + return self._root + + def GetSubNodes(self, node): + """Returns a list of sub-nodes of a given node + + Args: + node: Node name to return children from + + Returns: + List of children in the node (each a string node name) + + Raises: + CmdError: if the node does not exist. + """ + out = command.Output('fdtget', self.fname, '-l', node) + return out.strip().splitlines() + + def GetProps(self, node, convert_dashes=False): + """Get all properties from a node + + Args: + node: full path to node name to look in + convert_dashes: True to convert - to _ in node names + + Returns: + A dictionary containing all the properties, indexed by node name. + The entries are simply strings - no decoding of lists or numbers + is done. + + Raises: + CmdError: if the node does not exist. + """ + out = command.Output('fdtget', self.fname, node, '-p') + props = out.strip().splitlines() + props_dict = {} + for prop in props: + name = prop + if convert_dashes: + prop = re.sub('-', '_', prop) + props_dict[prop] = self.GetProp(node, name) + return props_dict + + def GetProp(self, node, prop, default=None, typespec=None): + """Get a property from a device tree. + + This looks up the given node and property, and returns the value as a + string, + + If the node or property does not exist, this will return the default + value. + + Args: + node: Full path to node to look up. + prop: Property name to look up. + default: Default value to return if nothing is present in the fdt, + or None to raise in this case. This will be converted to a + string. + typespec: Type character to use (None for default, 's' for string) + + Returns: + string containing the property value. + + Raises: + CmdError: if the property does not exist and no default is provided. + """ + args = [self.fname, node, prop, '-t', 'bx'] + if default is not None: + args += ['-d', str(default)] + if typespec is not None: + args += ['-t%s' % typespec] + out = command.Output('fdtget', *args) + return out.strip() diff --git a/tools/dtoc/fdt_util.py b/tools/dtoc/fdt_util.py new file mode 100644 index 0000000..dd689fb --- /dev/null +++ b/tools/dtoc/fdt_util.py @@ -0,0 +1,71 @@ +#!/usr/bin/python +# +# Copyright (C) 2016 Google, Inc +# Written by Simon Glass sjg@chromium.org +# +# SPDX-License-Identifier: GPL-2.0+ +# + +import struct + +# A list of types we support +(TYPE_BYTE, TYPE_INT, TYPE_STRING, TYPE_BOOL) = range(4) + +def BytesToValue(bytes): + """Converts a string of bytes into a type and value + + Args: + A string containing bytes + + Return: + A tuple: + Type of data + Data, either a single element or a list of elements. Each element + is one of: + TYPE_STRING: string value from the property + TYPE_INT: a byte-swapped integer + TYPE_BYTE: a byte + """ + size = len(bytes) + strings = bytes.split('\0') + is_string = True + count = len(strings) - 1 + if count > 0 and not strings[-1]: + for string in strings[:-1]: + if not string: + is_string = False + break + for ch in string: + if ch < ' ' or ch > '~': + is_string = False + break + else: + is_string = False + if is_string: + if count == 1: + return TYPE_STRING, strings[0] + else: + return TYPE_STRING, strings[:-1] + if size % 4: + if size == 1: + return TYPE_BYTE, bytes[0] + else: + return TYPE_BYTE, list(bytes) + val = [] + for i in range(0, size, 4): + val.append(bytes[i:i + 4]) + if size == 4: + return TYPE_INT, val[0] + else: + return TYPE_INT, val + +def fdt32_to_cpu(val): + """Convert a device tree cell to an integer + + Args: + Value to convert (4-character string representing the cell value) + + Return: + A native-endian integer value + """ + return struct.unpack(">I", val)[0]

This tool can produce C struct definitions and C platform data tables. This is used to support the of-platdata feature.
Signed-off-by: Simon Glass sjg@chromium.org ---
tools/dtoc/dtoc | 1 + tools/dtoc/dtoc.py | 365 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 366 insertions(+) create mode 120000 tools/dtoc/dtoc create mode 100755 tools/dtoc/dtoc.py
diff --git a/tools/dtoc/dtoc b/tools/dtoc/dtoc new file mode 120000 index 0000000..896ca44 --- /dev/null +++ b/tools/dtoc/dtoc @@ -0,0 +1 @@ +dtoc.py \ No newline at end of file diff --git a/tools/dtoc/dtoc.py b/tools/dtoc/dtoc.py new file mode 100755 index 0000000..6a2f6ef --- /dev/null +++ b/tools/dtoc/dtoc.py @@ -0,0 +1,365 @@ +#!/usr/bin/python +# +# Copyright (C) 2016 Google, Inc +# Written by Simon Glass sjg@chromium.org +# +# SPDX-License-Identifier: GPL-2.0+ +# + +from optparse import OptionError, OptionParser +import os +import sys + +import fdt_util + +# Bring in the patman libraries +our_path = os.path.dirname(os.path.realpath(__file__)) +sys.path.append(os.path.join(our_path, '../patman')) + +# Bring in either the normal fdt library (which relies on libfdt) or the +# fallback one (which uses fdtget and is slower). Both provide the same +# interfface for this file to use. +try: + from fdt import Fdt + import fdt + have_libfdt = True +except ImportError: + have_libfdt = False + from fdt_fallback import Fdt + import fdt_fallback as fdt + +import struct + +# When we see these properties we ignore them - i.e. do not create a structure member +PROP_IGNORE_LIST = [ + '#address-cells', + '#gpio-cells', + '#size-cells', + 'compatible', + 'linux,phandle', + "status", + 'phandle', +] + +# C type declarations for the tyues we support +TYPE_NAMES = { + fdt_util.TYPE_INT: 'fdt32_t', + fdt_util.TYPE_BYTE: 'unsigned char', + fdt_util.TYPE_STRING: 'const char *', + fdt_util.TYPE_BOOL: 'bool', +}; + +STRUCT_PREFIX = 'dtd_' +VAL_PREFIX = 'dtv_' + +def Conv_name_to_c(name): + """Convert a device-tree name to a C identifier + + Args: + name: Name to convert + Return: + String containing the C version of this name + """ + str = name.replace('@', '_at_') + str = str.replace('-', '_') + str = str.replace(',', '_') + str = str.replace('/', '__') + return str + +def TabTo(num_tabs, str): + if len(str) >= num_tabs * 8: + return str + ' ' + return str + '\t' * (num_tabs - len(str) / 8) + +class DtbPlatdata: + """Provide a means to convert device tree binary data to platform data + + The output of this process is C structures which can be used in space- + constrained encvironments where the ~3KB code overhead of device tree + code is not affordable. + + Properties: + fdt: Fdt object, referencing the device tree + _dtb_fname: Filename of the input device tree binary file + _valid_nodes: A list of Node object with compatible strings + _options: Command-line options + _phandle_node: A dict of nodes indexed by phandle number (1, 2...) + _outfile: The current output file (sys.stdout or a real file) + _lines: Stashed list of output lines for outputting in the future + _phandle_node: A dict of Nodes indexed by phandle (an integer) + """ + def __init__(self, dtb_fname, options): + self._dtb_fname = dtb_fname + self._valid_nodes = None + self._options = options + self._phandle_node = {} + self._outfile = None + self._lines = [] + + def SetupOutput(self, fname): + """Set up the output destination + + Once this is done, future calls to self.Out() will output to this + file. + + Args: + fname: Filename to send output to, or '-' for stdout + """ + if fname == '-': + self._outfile = sys.stdout + else: + self._outfile = open(fname, 'w') + + def Out(self, str): + """Output a string to the output file + + Args: + str: String to output + """ + self._outfile.write(str) + + def Buf(self, str): + """Buffer up a string to send later + + Args: + str: String to add to our 'buffer' list + """ + self._lines.append(str) + + def GetBuf(self): + """Get the contents of the output buffer, and clear it + + Returns: + The output buffer, which is then cleared for future use + """ + lines = self._lines + self._lines = [] + return lines + + def GetValue(self, type, value): + """Get a value as a C expression + + For integers this returns a byte-swapped (little-endian) hex string + For bytes this returns a hex string, e.g. 0x12 + For strings this returns a literal string enclosed in quotes + For booleans this return 'true' + + Args: + type: Data type (fdt_util) + value: Data value, as a string of bytes + """ + if type == fdt_util.TYPE_INT: + return '%#x' % fdt_util.fdt32_to_cpu(value) + elif type == fdt_util.TYPE_BYTE: + return '%#x' % ord(value[0]) + elif type == fdt_util.TYPE_STRING: + return '"%s"' % value + elif type == fdt_util.TYPE_BOOL: + return 'true' + + def GetCompatName(self, node): + """Get a node's first compatible string as a C identifier + + Args: + node: Node object to check + Return: + C identifier for the first compatible string + """ + compat = node.props['compatible'].value + if type(compat) == list: + compat = compat[0] + return Conv_name_to_c(compat) + + def ScanDtb(self): + """Scan the device tree to obtain a tree of notes and properties + + Once this is done, self.fdt.GetRoot() can be called to obtain the + device tree root node, and progress from there. + """ + self.fdt = Fdt(self._dtb_fname) + self.fdt.Scan() + + def ScanTree(self): + """Scan the device tree for useful information + + This fills in the following properties: + _phandle_node: A dict of Nodes indexed by phandle (an integer) + _valid_nodes: A list of nodes we wish to consider include in the + platform data + """ + node_list = [] + self._phandle_node = {} + for node in self.fdt.GetRoot().subnodes: + if 'compatible' in node.props: + status = node.props.get('status') + if (not options.include_disabled and not status or + status.value != 'disabled'): + node_list.append(node) + phandle_prop = node.props.get('phandle') + if phandle_prop: + phandle = phandle_prop.GetPhandle() + self._phandle_node[phandle] = node + + self._valid_nodes = node_list + + def IsPhandle(self, prop): + """Check if a node contains phandles + + We have no reliable way of detecting whether a node uses a phandle + or not. As an interim measure, use a list of known property names. + + Args: + prop: Prop object to check + Return: + True if the object value contains phandles, else False + """ + if prop.name in ['clocks']: + return True + return False + + def GenerateStructs(self): + """Generate struct defintions for the platform data + + This writes out the body of a header file consisting of structure + definitions for node in self._valid_nodes. See the documentation in + README.of-plat for more information. + """ + self.Out('#include <stdbool.h>\n') + self.Out('#include <libfdt.h>\n') + + # Build a dict keyed by C struct name containing a dict of Prop + # object for each struct field (keyed by property name). Where the + # same struct appears multiple times, try to use the 'widest' + # property, i.e. the one with a type which can express all others. + structs = {} + for node in self._valid_nodes: + node_name = self.GetCompatName(node) + fields = {} + for name, prop in node.props.iteritems(): + if name not in PROP_IGNORE_LIST and name[0] != '#': + fields[name] = prop + if node_name in structs: + struct = structs[node_name] + for name, prop in fields.iteritems(): + oldprop = struct.get(name) + if oldprop: + struct[name].Widen(oldprop) + else: + struct[name] = prop + else: + structs[node_name] = fields + + # Output the struct definition + for name in sorted(structs): + self.Out('struct %s%s {\n' % (STRUCT_PREFIX, name)); + for pname in sorted(structs[name]): + prop = structs[name][pname] + if self.IsPhandle(prop): + # For phandles, include a reference to the target + self.Out('\t%s%s[%d]' % (TabTo(2, 'struct phandle_2_cell'), + Conv_name_to_c(prop.name), + len(prop.value) / 2)) + else: + ptype = TYPE_NAMES[prop.type] + self.Out('\t%s%s' % (TabTo(2, ptype), Conv_name_to_c(prop.name))) + if type(prop.value) == list: + self.Out('[%d]' % len(prop.value)) + self.Out(';\n') + self.Out('};\n') + + def GenerateTables(self): + """Generate device defintions for the platform data + + This writes out C platform data initialisation data and + U_BOOT_DEVICE() declarations for each valid node. See the + documentation in README.of-plat for more information. + """ + self.Out('#include <common.h>\n') + self.Out('#include <dm.h>\n') + self.Out('#include <dt-structs.h>\n') + self.Out('\n') + node_txt_list = [] + for node in self._valid_nodes: + struct_name = self.GetCompatName(node) + var_name = Conv_name_to_c(node.name) + self.Buf('static struct %s%s %s%s = {\n' % + (STRUCT_PREFIX, struct_name, VAL_PREFIX, var_name)) + for pname, prop in node.props.iteritems(): + if pname in PROP_IGNORE_LIST or pname[0] == '#': + continue + ptype = TYPE_NAMES[prop.type] + member_name = Conv_name_to_c(prop.name) + self.Buf('\t%s= ' % TabTo(3, '.' + member_name)) + + # Special handling for lists + if type(prop.value) == list: + self.Buf('{') + vals = [] + # For phandles, output a reference to the platform data + # of the target node. + if self.IsPhandle(prop): + # Process the list as pairs of (phandle, id) + it = iter(prop.value) + for phandle_cell, id_cell in zip(it, it): + phandle = fdt_util.fdt32_to_cpu(phandle_cell) + id = fdt_util.fdt32_to_cpu(id_cell) + target_node = self._phandle_node[phandle] + name = Conv_name_to_c(target_node.name) + vals.append('{&%s%s, %d}' % (VAL_PREFIX, name, id)) + else: + for val in prop.value: + vals.append(self.GetValue(prop.type, val)) + self.Buf(', '.join(vals)) + self.Buf('}') + else: + self.Buf(self.GetValue(prop.type, prop.value)) + self.Buf(',\n') + self.Buf('};\n') + + # Add a device declaration + self.Buf('U_BOOT_DEVICE(%s) = {\n' % var_name) + self.Buf('\t.name\t\t= "%s",\n' % struct_name) + self.Buf('\t.platdata\t= &%s%s,\n' % (VAL_PREFIX, var_name)) + self.Buf('};\n') + self.Buf('\n') + + # Output phandle target nodes first, since they may be referenced + # by others + if 'phandle' in node.props: + self.Out(''.join(self.GetBuf())) + else: + node_txt_list.append(self.GetBuf()) + + # Output all the nodes which are not phandle targets themselves, but + # may reference them. This avoids the need for forward declarations. + for node_txt in node_txt_list: + self.Out(''.join(node_txt)) + + +if __name__ != "__main__": + pass + +parser = OptionParser() +parser.add_option('-d', '--dtb-file', action='store', + help='Specify the .dtb input file') +parser.add_option('--include-disabled', action='store_true', + help='Include disabled nodes') +parser.add_option('-o', '--output', action='store', default='-', + help='Select output filename') +(options, args) = parser.parse_args() + +if not args: + raise ValueError('Please specify a command: struct, platdata') + +plat = DtbPlatdata(options.dtb_file, options) +plat.ScanDtb() +plat.ScanTree() +plat.SetupOutput(options.output) + +for cmd in args[0].split(','): + if cmd == 'struct': + plat.GenerateStructs() + elif cmd == 'platdata': + plat.GenerateTables() + else: + raise ValueError("Unknown command '%s': (use: struct, platdata)" % cmd)

Update the Makefile to call dtoc to create the C header and source files, then build these into the image.
Signed-off-by: Simon Glass sjg@chromium.org ---
scripts/Makefile.spl | 39 ++++++++++++++++++++++++++++++++++++--- 1 file changed, 36 insertions(+), 3 deletions(-)
diff --git a/scripts/Makefile.spl b/scripts/Makefile.spl index 2b5c995..324b03f 100644 --- a/scripts/Makefile.spl +++ b/scripts/Makefile.spl @@ -45,6 +45,7 @@ LDFLAGS_FINAL += --gc-sections # FIX ME cpp_flags := $(KBUILD_CPPFLAGS) $(PLATFORM_CPPFLAGS) $(UBOOTINCLUDE) \ $(NOSTDINC_FLAGS) +c_flags := $(KBUILD_CFLAGS) $(cpp_flags)
HAVE_VENDOR_COMMON_LIB = $(if $(wildcard $(srctree)/board/$(VENDOR)/common/Makefile),y,n)
@@ -76,6 +77,9 @@ endif
u-boot-spl-init := $(head-y) u-boot-spl-main := $(libs-y) +ifdef CONFIG_SPL_OF_PLATDATA +u-boot-spl-platdata := $(obj)/dts/dt-platdata.o +endif
# Linker Script ifdef CONFIG_SPL_LDSCRIPT @@ -207,6 +211,32 @@ cmd_cpp_cfg = $(CPP) -Wp,-MD,$(depfile) $(cpp_flags) $(LDPPFLAGS) -ansi \ $(obj)/$(SPL_BIN).cfg: include/config.h FORCE $(call if_changed,cpp_cfg)
+pythonpath = PYTHONPATH=tools + +quiet_cmd_dtocc = DTOC C $@ +cmd_dtocc = $(pythonpath) $(srctree)/tools/dtoc/dtoc -d $(obj)/$(SPL_BIN).dtb -o $@ platdata + +quiet_cmd_dtoch = DTOC H $@ +cmd_dtoch = $(pythonpath) $(srctree)/tools/dtoc/dtoc -d $(obj)/$(SPL_BIN).dtb -o $@ struct + +quiet_cmd_plat = PLAT $@ +cmd_plat = $(CC) $(c_flags) -c $< -o $@ + +$(obj)/dts/dt-platdata.o: $(obj)/dts/dt-platdata.c include/generated/dt-structs.h + $(call if_changed,plat) + +PHONY += dts_dir +dts_dir: + $(shell [ -d $(obj)/dts ] || mkdir -p $(obj)/dts) + +include/generated/dt-structs.h: $(obj)/$(SPL_BIN).dtb dts_dir dtoc + $(call if_changed,dtoch) + +$(obj)/dts/dt-platdata.c: $(obj)/$(SPL_BIN).dtb dts_dir dtoc + $(call if_changed,dtocc) + +dtoc: #$(objtree)/tools/_libfdt.so + ifdef CONFIG_SAMSUNG ifdef CONFIG_VAR_SIZE_SPL VAR_SIZE_PARAM = --vs @@ -246,16 +276,19 @@ $(obj)/sunxi-spl.bin: $(obj)/$(SPL_BIN).bin FORCE quiet_cmd_u-boot-spl ?= LD $@ cmd_u-boot-spl ?= (cd $(obj) && $(LD) $(LDFLAGS) $(LDFLAGS_$(@F)) \ $(patsubst $(obj)/%,%,$(u-boot-spl-init)) --start-group \ - $(patsubst $(obj)/%,%,$(u-boot-spl-main)) --end-group \ + $(patsubst $(obj)/%,%,$(u-boot-spl-main)) \ + $(patsubst $(obj)/%,%,$(u-boot-spl-platdata)) \ + --end-group \ $(PLATFORM_LIBS) -Map $(SPL_BIN).map -o $(SPL_BIN))
-$(obj)/$(SPL_BIN): $(u-boot-spl-init) $(u-boot-spl-main) $(obj)/u-boot-spl.lds FORCE +$(obj)/$(SPL_BIN): $(u-boot-spl-platdata) $(u-boot-spl-init) \ + $(u-boot-spl-main) $(obj)/u-boot-spl.lds FORCE $(call if_changed,u-boot-spl)
$(sort $(u-boot-spl-init) $(u-boot-spl-main)): $(u-boot-spl-dirs) ;
PHONY += $(u-boot-spl-dirs) -$(u-boot-spl-dirs): +$(u-boot-spl-dirs): $(u-boot-spl-platdata) $(Q)$(MAKE) $(build)=$@
quiet_cmd_cpp_lds = LDS $@

Add a Python version of the libfdt library which contains enough features to support the dtoc tool. This is only a very bare-bones implementation.
Signed-off-by: Simon Glass sjg@chromium.org ---
lib/libfdt/libfdt.swig | 81 +++++++++++++++++++++ lib/libfdt/setup.py | 38 ++++++++++ lib/libfdt/test_libfdt.py | 14 ++++ scripts/Makefile.host | 9 ++- tools/Makefile | 11 +++ tools/dtoc/fdt.py | 174 ++++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 325 insertions(+), 2 deletions(-) create mode 100644 lib/libfdt/libfdt.swig create mode 100644 lib/libfdt/setup.py create mode 100644 lib/libfdt/test_libfdt.py create mode 100644 tools/dtoc/fdt.py
diff --git a/lib/libfdt/libfdt.swig b/lib/libfdt/libfdt.swig new file mode 100644 index 0000000..95c3e9e --- /dev/null +++ b/lib/libfdt/libfdt.swig @@ -0,0 +1,81 @@ +/* File: libfdt.i */ +%module libfdt + +%{ +#define SWIG_FILE_WITH_INIT +#include "libfdt.h" +%} + +%pythoncode %{ +def Raise(errnum): + raise ValueError('Error %s' % fdt_strerror(errnum)) + +def Name(fdt, offset): + name, len = fdt_get_name(fdt, offset) + return name + +def String(fdt, offset): + offset = fdt32_to_cpu(offset) + name = fdt_string(fdt, offset) + return name + +def swap32(x): + return (((x << 24) & 0xFF000000) | + ((x << 8) & 0x00FF0000) | + ((x >> 8) & 0x0000FF00) | + ((x >> 24) & 0x000000FF)) + +def fdt32_to_cpu(x): + return swap32(x) + +def Data(prop): + set_prop(prop) + return get_prop_data() +%} + +%include "typemaps.i" +%include "cstring.i" + +%typemap(in) void* = char*; + +typedef int fdt32_t; + +struct fdt_property { + fdt32_t tag; + fdt32_t len; + fdt32_t nameoff; + char data[0]; +}; + +%inline %{ + static struct fdt_property *cur_prop; + + void set_prop(struct fdt_property *prop) { + cur_prop = prop; + } +%} + +%cstring_output_allocate_size(char **s, int *sz, free(*$1)); +%inline %{ + void get_prop_data(char **s, int *sz) { + *sz = fdt32_to_cpu(cur_prop->len); + *s = (char *)malloc(*sz); + if (!*s) + *sz = 0; + else + memcpy(*s, cur_prop + 1, *sz); + } +%} + +const void *fdt_offset_ptr(const void *fdt, int offset, unsigned int checklen); +int fdt_path_offset(const void *fdt, const char *path); +int fdt_first_property_offset(const void *fdt, int nodeoffset); +int fdt_next_property_offset(const void *fdt, int offset); +const char *fdt_strerror(int errval); +const struct fdt_property *fdt_get_property_by_offset(const void *fdt, + int offset, + int *OUTPUT); +const char *fdt_get_name(const void *fdt, int nodeoffset, int *OUTPUT); +const char *fdt_string(const void *fdt, int stroffset); +int fdt_first_subnode(const void *fdt, int offset); +int fdt_next_subnode(const void *fdt, int offset); diff --git a/lib/libfdt/setup.py b/lib/libfdt/setup.py new file mode 100644 index 0000000..62e7bcc --- /dev/null +++ b/lib/libfdt/setup.py @@ -0,0 +1,38 @@ +#!/usr/bin/env python + +""" +setup.py file for SWIG libfdt +""" + +from distutils.core import setup, Extension +import os +import sys + +# Don't cross-compile - always use the host compiler. +del os.environ['CROSS_COMPILE'] +del os.environ['CC'] + +progname = sys.argv[0] +cflags = sys.argv[1] +files = sys.argv[2:] + +if cflags: + cflags = [flag for flag in cflags.split(' ') if flag] +else: + cflags = None + +libfdt_module = Extension( + '_libfdt', + sources = files, + extra_compile_args = cflags +) + +sys.argv = [progname, '--quiet', 'build_ext', '--inplace'] + +setup (name = 'libfdt', + version = '0.1', + author = "SWIG Docs", + description = """Simple swig libfdt from docs""", + ext_modules = [libfdt_module], + py_modules = ["libfdt"], + ) diff --git a/lib/libfdt/test_libfdt.py b/lib/libfdt/test_libfdt.py new file mode 100644 index 0000000..14d0da4 --- /dev/null +++ b/lib/libfdt/test_libfdt.py @@ -0,0 +1,14 @@ +#!/usr/bin/python + +import os +import sys + +our_path = os.path.dirname(os.path.realpath(__file__)) +sys.path.append(os.path.join(our_path, '../../b/sandbox_spl/tools')) + +import libfdt + +with open('b/sandbox_spl/u-boot.dtb') as fd: + fdt = fd.read() + +print libfdt.fdt_path_offset(fdt, "/aliases") diff --git a/scripts/Makefile.host b/scripts/Makefile.host index bff8b5b..763a699 100644 --- a/scripts/Makefile.host +++ b/scripts/Makefile.host @@ -28,12 +28,16 @@ __hostprogs := $(sort $(hostprogs-y) $(hostprogs-m)) # C code # Executables compiled from a single .c file host-csingle := $(foreach m,$(__hostprogs), \ - $(if $($(m)-objs)$($(m)-cxxobjs),,$(m))) + $(if $($(m)-objs)$($(m)-cxxobjs)$($(m)-sharedobjs),,$(m)))
# C executables linked based on several .o files host-cmulti := $(foreach m,$(__hostprogs),\ $(if $($(m)-cxxobjs),,$(if $($(m)-objs),$(m))))
+# Shared object libraries +host-shared := $(foreach m,$(__hostprogs),\ + $(if $($(m)-sharedobjs),$(m)))) + # Object (.o) files compiled from .c files host-cobjs := $(sort $(foreach m,$(__hostprogs),$($(m)-objs)))
@@ -59,6 +63,7 @@ host-cmulti := $(addprefix $(obj)/,$(host-cmulti)) host-cobjs := $(addprefix $(obj)/,$(host-cobjs)) host-cxxmulti := $(addprefix $(obj)/,$(host-cxxmulti)) host-cxxobjs := $(addprefix $(obj)/,$(host-cxxobjs)) +host-shared := $(addprefix $(obj)/,$(host-shared)) host-objdirs := $(addprefix $(obj)/,$(host-objdirs))
obj-dirs += $(host-objdirs) @@ -128,4 +133,4 @@ $(host-cxxobjs): $(obj)/%.o: $(src)/%.cc FORCE $(call if_changed_dep,host-cxxobjs)
targets += $(host-csingle) $(host-cmulti) $(host-cobjs)\ - $(host-cxxmulti) $(host-cxxobjs) + $(host-cxxmulti) $(host-cxxobjs) $(host-shared) diff --git a/tools/Makefile b/tools/Makefile index 63355aa..a813217 100644 --- a/tools/Makefile +++ b/tools/Makefile @@ -107,6 +107,17 @@ mkimage-objs := $(dumpimage-mkimage-objs) mkimage.o fit_info-objs := $(dumpimage-mkimage-objs) fit_info.o fit_check_sign-objs := $(dumpimage-mkimage-objs) fit_check_sign.o
+hostprogs-$(CONFIG_SPL_OF_PLATDATA) += _libfdt.so +_libfdt.so-sharedobjs += $(LIBFDT_OBJS) +libfdt: + +tools/_libfdt.so: $(patsubst %.o,%.c,$(LIBFDT_OBJS)) tools/libfdt_wrap.c + python $(srctree)/lib/libfdt/setup.py "$(_hostc_flags)" $^ + mv _libfdt.so $@ + +tools/libfdt_wrap.c: $(srctree)/lib/libfdt/libfdt.swig + swig -python -o $@ $< + # TODO(sjg@chromium.org): Is this correct on Mac OS?
ifneq ($(CONFIG_MX23)$(CONFIG_MX28),) diff --git a/tools/dtoc/fdt.py b/tools/dtoc/fdt.py new file mode 100644 index 0000000..3787cb5 --- /dev/null +++ b/tools/dtoc/fdt.py @@ -0,0 +1,174 @@ +#!/usr/bin/python +# +# Copyright (C) 2016 Google, Inc +# Written by Simon Glass sjg@chromium.org +# +# SPDX-License-Identifier: GPL-2.0+ +# + +import fdt_util +import libfdt +import sys + +# This deals with a device tree, presenting it as a list of Node and Prop +# objects, representing nodes and properties, respectively. +# +# This implementation uses a libfdt Python library to access the device tree, +# so it is fairly efficient. + +class Prop: + """A device tree property + + Properties: + name: Property name (as per the device tree) + value: Property value as a string of bytes, or a list of strings of + bytes + type: Value type + """ + def __init__(self, name, bytes): + self.name = name + self.value = None + if not bytes: + self.type = fdt_util.TYPE_BOOL + return + self.type, self.value = fdt_util.BytesToValue(bytes) + + def GetPhandle(self): + """Get a (single) phandle value from a property + + Gets the phandle valuie from a property and returns it as an integer + """ + return fdt_util.fdt32_to_cpu(self.value[:4]) + + def Widen(self, newprop): + """Figure out which property type is more general + + Given a current property and a new property, this function returns the + one that is less specific as to type. The less specific property will + be ble to represent the data in the more specific property. This is + used for things like: + + node1 { + compatible = "fred"; + value = <1>; + }; + node1 { + compatible = "fred"; + value = <1 2>; + }; + + He we want to use an int array for 'value'. The first property + suggests that a single int is enough, but the second one shows that + it is not. Calling this function with these two propertes would + update the current property to be like the second, since it is less + specific. + """ + if newprop.type < self.type: + self.type = newprop.type + + if type(newprop.value) == list and type(self.value) != list: + self.value = newprop.value + + +class Node: + """A device tree node + + Properties: + offset: Integer offset in the device tree + name: Device tree node tname + path: Full path to node, along with the node name itself + _fdt: Device tree object + subnodes: A list of subnodes for this node, each a Node object + props: A dict of properties for this node, each a Prop object. + Keyed by property name + """ + def __init__(self, fdt, offset, name, path): + self.offset = offset + self.name = name + self.path = path + self._fdt = fdt + self.subnodes = [] + self.props = {} + + def Scan(self): + """Scan a node's properties and subnodes + + This fills in the props and subnodes properties, recursively + searching into subnodes so that the entire tree is built. + """ + self.props = self._fdt.GetProps(self.path) + + offset = libfdt.fdt_first_subnode(self._fdt.GetFdt(), self.offset) + while offset >= 0: + sep = '' if self.path[-1] == '/' else '/' + name = libfdt.Name(self._fdt.GetFdt(), offset) + path = self.path + sep + name + node = Node(self._fdt, offset, name, path) + self.subnodes.append(node) + + node.Scan() + offset = libfdt.fdt_next_subnode(self._fdt.GetFdt(), offset) + + +class Fdt: + """Provides simple access to a flat device tree blob. + + Properties: + fname: Filename of fdt + _root: Root of device tree (a Node object) + """ + + def __init__(self, fname): + self.fname = fname + with open(fname) as fd: + self._fdt = fd.read() + + def GetFdt(self): + """Get the contents of the FDT + + Returns: + The FDT contents as a string of bytes + """ + return self._fdt + + def Scan(self): + """Scan a device tree, building up a tree of Node objects + + This fills in the self._root property + """ + self._root = Node(self, 0, '/', '/') + self._root.Scan() + + def GetRoot(self): + """Get the root Node of the device tree + + Returns: + The root Node object + """ + return self._root + + def GetProps(self, node): + """Get all properties from a node. + + Args: + node: Full path to node name to look in. + + Returns: + A dictionary containing all the properties, indexed by node name. + The entries are Prop objects. + + Raises: + ValueError: if the node does not exist. + """ + offset = libfdt.fdt_path_offset(self._fdt, node) + if offset < 0: + libfdt.Raise(offset) + props_dict = {} + poffset = libfdt.fdt_first_property_offset(self._fdt, offset) + while poffset >= 0: + dprop, plen = libfdt.fdt_get_property_by_offset(self._fdt, poffset) + prop = Prop(libfdt.String(self._fdt, dprop.nameoff), libfdt.Data(dprop)) + props_dict[prop.name] = prop + + poffset = libfdt.fdt_next_property_offset(self._fdt, poffset) + return props_dict

On Tue, Jun 07, 2016 at 08:47:38PM -0600, Simon Glass wrote:
This series provides a way to compile in the contents of a device tree as C code into U-Boot. It is intended to deal with extremely tight environments where there is not enough space for the ~3KB device tree code overhead. Examples include SPL where there is only 16KB of available RAM yet a full MMC stack is required.
To provide a reasonable test environment, SPL support is added to sandbox, through a new 'sandbox_spl' target. A new tool 'dtoc' converts device tree data to C code (and structure definitions).
More work is needed before this feature is ready for use, but this series contains enough to attract initial comments and testing.
Sorry for the late reply, thanks for doing all of this. In so far as there's non-sandbox changes, it all looks good here. Is there a rockchip platform or similar that you can also convert here? Thanks!
participants (2)
-
Simon Glass
-
Tom Rini