From 7fcdac0ee96fb19013056e7a083e46f74c8dad66 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Mon, 4 Jul 2016 11:57:41 -0600 Subject: [PATCH 01/62] sandbox: Don't print a warning for CONFIG_I2C_COMPAT 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 --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 88128ec72a..e5b07d802a 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)" From 392853260d46e18963be60f97306aab6ce770652 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Mon, 4 Jul 2016 11:57:42 -0600 Subject: [PATCH 02/62] README: Remove CONFIG_SYS_MALLOC_F_LEN comment This option is now widely available, so remove the comment that it is only available on ARM and sandbox. Signed-off-by: Simon Glass --- README | 3 --- 1 file changed, 3 deletions(-) diff --git a/README b/README index 26d5ad273e..e906253fa2 100644 --- a/README +++ b/README @@ -3835,9 +3835,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 From 12c550d4fbfae272793c222c51af77613ffc5963 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Mon, 4 Jul 2016 11:57:43 -0600 Subject: [PATCH 03/62] spl: Drop include of i2c.h This file does not appear to use I2C, so drop this include. Signed-off-by: Simon Glass --- common/spl/spl.c | 1 - 1 file changed, 1 deletion(-) diff --git a/common/spl/spl.c b/common/spl/spl.c index 840910a684..5fbf101fb1 100644 --- a/common/spl/spl.c +++ b/common/spl/spl.c @@ -13,7 +13,6 @@ #include #include #include -#include #include #include #include From 72a7e0760447ed46ca50174cb8798a2e84dedf85 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Mon, 4 Jul 2016 11:57:44 -0600 Subject: [PATCH 04/62] Makefile: Allow the SPL final link rule to be overridden 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 --- scripts/Makefile.spl | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/scripts/Makefile.spl b/scripts/Makefile.spl index 0997fd9fdd..2b5c9954d3 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)) From d4e33f5a72accc891e3600cb2d2bc579004de9e1 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Mon, 4 Jul 2016 11:57:45 -0600 Subject: [PATCH 05/62] sandbox: Allow chaining from SPL to U-Boot proper 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 --- 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 8a4d719835..2d63dd88f1 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 954a48c991..1782e50e77 100644 --- a/include/os.h +++ b/include/os.h @@ -286,6 +286,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 * From 4cfc416701e2fb4214dffa78ba2c3f7e2ffed3bb Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Mon, 4 Jul 2016 11:57:46 -0600 Subject: [PATCH 06/62] sandbox: Support building an SPL image 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 --- arch/sandbox/config.mk | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/arch/sandbox/config.mk b/arch/sandbox/config.mk index 16fd6d508a..6d62abb035 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 From 6e20650425842244603380c275e7d7701305d2a0 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Mon, 4 Jul 2016 11:57:47 -0600 Subject: [PATCH 07/62] sandbox: Correct header file order in cpu.c The dm/ file should go at the end. Move it. Signed-off-by: Simon Glass --- 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 196f3e1191..7a622c8092 100644 --- a/arch/sandbox/cpu/cpu.c +++ b/arch/sandbox/cpu/cpu.c @@ -4,10 +4,10 @@ */ #define DEBUG #include -#include #include #include #include +#include DECLARE_GLOBAL_DATA_PTR; From f4289cbd8a8d607399b507cb695b46cd771d6c1b Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Mon, 4 Jul 2016 11:57:48 -0600 Subject: [PATCH 08/62] sandbox: Add some missing headers in cpu.c These headers are needed in case they are not transitively included. Signed-off-by: Simon Glass --- 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 7a622c8092..4975eb288c 100644 --- a/arch/sandbox/cpu/cpu.c +++ b/arch/sandbox/cpu/cpu.c @@ -4,6 +4,8 @@ */ #define DEBUG #include +#include +#include #include #include #include From a7d9caecd770684e6e189dfa24240145ba29379e Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Mon, 4 Jul 2016 11:57:49 -0600 Subject: [PATCH 09/62] sandbox: Don't use PCI in SPL PCI is not supported in SPL for sandbox, so avoid using it. Signed-off-by: Simon Glass --- 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 4975eb288c..2def72212d 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 96761e27f7..7820c55c85 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 From d0d0746e0c7c9eeddc82106cf7d4c596eb45f6c2 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Mon, 4 Jul 2016 11:57:50 -0600 Subject: [PATCH 10/62] sandbox: Don't include the main loop in SPL SPL does not have a command interface so we should not include the main loop code. Signed-off-by: Simon Glass --- 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 969618ef87..6e4ec017cc 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) From e961a66df91ea4cbf9b6978995f1ba6c8d67aa33 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Mon, 4 Jul 2016 11:57:51 -0600 Subject: [PATCH 11/62] sandbox: Add basic SPL implementation Add an sandbox implementation for the generic SPL framework. This supports locating and running U-Boot proper. Signed-off-by: Simon Glass --- 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 1b42fee141..db4363358a 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 0000000000..e17c0ed087 --- /dev/null +++ b/arch/sandbox/cpu/spl.c @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2016 Google, Inc + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include +#include +#include + +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 0000000000..59f2401170 --- /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 From 1c12bcee70d99fa4f4124a87ea965526ee164d3c Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Mon, 4 Jul 2016 11:57:52 -0600 Subject: [PATCH 12/62] sandbox: Don't use IDE and iotrace in SPL These functions are not supported in SPL, so drop them. Signed-off-by: Simon Glass --- include/configs/sandbox.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/include/configs/sandbox.h b/include/configs/sandbox.h index 23a0c40ca5..4de89f8879 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 From 0110f509c85de1e4bc7fff301a1194fdee4bdc5f Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Mon, 4 Jul 2016 11:57:53 -0600 Subject: [PATCH 13/62] sandbox: serial: Don't sync video in SPL 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 --- drivers/serial/sandbox.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/serial/sandbox.c b/drivers/serial/sandbox.c index 58f882b22a..bcc3465312 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 */ From 8797b2cae3ac5ddb005665e4b5cde4783a4f5555 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Mon, 4 Jul 2016 11:57:54 -0600 Subject: [PATCH 14/62] sandbox: Add a new sandbox_spl board 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 --- arch/sandbox/Kconfig | 7 +- arch/sandbox/cpu/u-boot-spl.lds | 24 +++++ board/sandbox/MAINTAINERS | 7 ++ configs/sandbox_spl_defconfig | 182 ++++++++++++++++++++++++++++++++ include/configs/sandbox_spl.h | 18 ++++ 5 files changed, 237 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 a8a90cb7a4..d4c1ee0662 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 0000000000..7e92b4ac66 --- /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 f5db773a47..4dcbf4ba03 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 +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 0000000000..d92597b110 --- /dev/null +++ b/configs/sandbox_spl_defconfig @@ -0,0 +1,182 @@ +CONFIG_SYS_MALLOC_F_LEN=0x2000 +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_SPL_DM=y +CONFIG_REGMAP=y +CONFIG_SPL_REGMAP=y +CONFIG_SYSCON=y +CONFIG_SPL_SYSCON=y +CONFIG_DEVRES=y +CONFIG_DEBUG_DEVRES=y +# CONFIG_SPL_SIMPLE_BUS is not set +CONFIG_ADC=y +CONFIG_ADC_SANDBOX=y +CONFIG_BLK=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_OPS=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_RESET=y +CONFIG_SANDBOX_RESET=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 0000000000..7b5c3f3e03 --- /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 + +#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 From a091a8f084f731953fa77a3da3b5bec72d37ad0f Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Mon, 4 Jul 2016 11:57:55 -0600 Subject: [PATCH 15/62] sandbox: Add a test device that uses of-platdata Start up the test devices. These print out of-platdata contents, providing a check that the of-platdata feature is working correctly. The device-tree changes are made to sandbox.dts rather than test.dts. since the former controls the of-platdata generation. Signed-off-by: Simon Glass --- arch/sandbox/cpu/spl.c | 17 +++++++++++++++++ arch/sandbox/dts/sandbox.dts | 31 +++++++++++++++++++++++++++++++ include/configs/sandbox_spl.h | 2 ++ 3 files changed, 50 insertions(+) diff --git a/arch/sandbox/cpu/spl.c b/arch/sandbox/cpu/spl.c index e17c0ed087..e8349c0b93 100644 --- a/arch/sandbox/cpu/spl.c +++ b/arch/sandbox/cpu/spl.c @@ -6,6 +6,7 @@ #include #include #include +#include #include #include @@ -49,3 +50,19 @@ 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; + + preloader_console_init(); + + /* + * Scan all the devices so that we can output their platform data. See + * sandbox_spl_probe(). + */ + for (uclass_first_device(UCLASS_MISC, &dev); + dev; + uclass_next_device(&dev)) + ; +} diff --git a/arch/sandbox/dts/sandbox.dts b/arch/sandbox/dts/sandbox.dts index 2ae40148b0..e6d336f16a 100644 --- a/arch/sandbox/dts/sandbox.dts +++ b/arch/sandbox/dts/sandbox.dts @@ -172,6 +172,37 @@ }; }; + spl-test { + u-boot,dm-pre-reloc; + compatible = "sandbox,spl-test"; + boolval; + intval = <1>; + intarray = <2 3 4>; + byteval = [05]; + bytearray = [06]; + longbytearray = [09 0a 0b 0c 0d 0e 0f 10 11]; + stringval = "message"; + stringarray = "multi-word", "message"; + }; + + spl-test2 { + u-boot,dm-pre-reloc; + compatible = "sandbox,spl-test"; + intval = <3>; + intarray = <5>; + byteval = [08]; + bytearray = [01 23 34]; + longbytearray = [09 0a 0b 0c]; + stringval = "message2"; + stringarray = "another", "multi-word", "message"; + }; + + spl-test3 { + u-boot,dm-pre-reloc; + compatible = "sandbox,spl-test"; + stringarray = "one"; + }; + square { compatible = "demo-shape"; colour = "blue"; diff --git a/include/configs/sandbox_spl.h b/include/configs/sandbox_spl.h index 7b5c3f3e03..ffc309867a 100644 --- a/include/configs/sandbox_spl.h +++ b/include/configs/sandbox_spl.h @@ -8,6 +8,8 @@ #include +#define CONFIG_SPL_BOARD_INIT + #define CONFIG_SPL_DRIVERS_MISC_SUPPORT #define CONFIG_SPL_ENV_SUPPORT #define CONFIG_SPL_FRAMEWORK From d223e0a82255b5fa6049f92556236f8ffd6b745c Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Mon, 4 Jul 2016 11:57:56 -0600 Subject: [PATCH 16/62] dm: spl: Don't set up device tree with of-platdata When this feature is enabled, we should not access the device tree. Signed-off-by: Simon Glass --- 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 5fbf101fb1..59f41a1223 100644 --- a/common/spl/spl.c +++ b/common/spl/spl.c @@ -202,7 +202,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); From 054b3a1e80fcbca02cb0d0728629af02f18517f5 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Mon, 4 Jul 2016 11:57:57 -0600 Subject: [PATCH 17/62] dm: Makefile: Build of-platdata before SPL Since SPL needs the of-platdata structures, build these before starting to build any SPL components. Signed-off-by: Simon Glass --- Makefile | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index e5b07d802a..84bb620a19 100644 --- a/Makefile +++ b/Makefile @@ -1318,7 +1318,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 From 29629eb897f8d8119b06477d0ca3c4b424726e51 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Mon, 4 Jul 2016 11:57:58 -0600 Subject: [PATCH 18/62] dm: core: Don't use device tree with of-platdata 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 --- 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 f7fb0cc0fa..d8f9d5b554 100644 --- a/drivers/core/device.c +++ b/drivers/core/device.c @@ -608,7 +608,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 0c27717790..6a634e6951 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 95886add23..158702406e 100644 --- a/drivers/core/root.c +++ b/drivers/core/root.c @@ -188,7 +188,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) { @@ -244,7 +244,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); From 3b2a29e0971397085c616c89a3a09f2609f50ca4 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Mon, 4 Jul 2016 11:57:59 -0600 Subject: [PATCH 19/62] dm: regmap: Add a dummy implementation for of-platdata Add a placeholder for now so that this code will compile. It currently does nothing. Signed-off-by: Simon Glass --- 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 519832f173..7e073cf9c0 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 eccf7707f4..922b39fad0 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 * From 04ecf36ba60f41f695095226e53310b4acaebf1e Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Mon, 4 Jul 2016 11:58:00 -0600 Subject: [PATCH 20/62] dm: syscon: Add support for of-platdata Provide a new function which can cope with obtaining information from of-platdata instead of the device tree. Signed-off-by: Simon Glass --- drivers/core/syscon-uclass.c | 13 +++++++++++++ include/syscon.h | 11 +++++++++++ 2 files changed, 24 insertions(+) diff --git a/drivers/core/syscon-uclass.c b/drivers/core/syscon-uclass.c index e03f46af57..01bd9683a7 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 4593b6e3eb..34842aa470 100644 --- a/include/syscon.h +++ b/include/syscon.h @@ -23,6 +23,17 @@ struct syscon_ops { #define syscon_get_ops(dev) ((struct syscon_ops *)(dev)->driver->ops) +#if CONFIG_IS_ENABLED(OF_PLATDATA) +/* + * We don't support 64-bit machines. If they are so resource-contrained that + * they need to use OF_PLATDATA, something is horribly wrong with the + * education of our hardware engineers. + */ +struct syscon_base_platdata { + u32 reg[2]; +}; +#endif + /** * syscon_get_regmap() - Get access to a register map * From bab8233a1d17de222e83e0cbf8eb1d9d691adaf3 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Mon, 4 Jul 2016 11:58:01 -0600 Subject: [PATCH 21/62] dm: sandbox: Add a simple driver to test of-platdata Add a driver which uses of-platdata to obtain its platform data. This can be used to test the feature in sandbox. It displays the contents of its platform data. Signed-off-by: Simon Glass --- drivers/misc/Makefile | 5 ++++ drivers/misc/spltest_sandbox.c | 53 ++++++++++++++++++++++++++++++++++ 2 files changed, 58 insertions(+) create mode 100644 drivers/misc/spltest_sandbox.c diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index 066639ba1f..3eac0245ea 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 0000000000..1fef8252ab --- /dev/null +++ b/drivers/misc/spltest_sandbox.c @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2016 Google, Inc + * Written by Simon Glass + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include + +DECLARE_GLOBAL_DATA_PTR; + +static int sandbox_spl_probe(struct udevice *dev) +{ + struct dtd_sandbox_spl_test *plat = dev_get_platdata(dev); + int i; + + printf("of-platdata probe:\n"); + printf("bool %d\n", plat->boolval); + + printf("byte %02x\n", plat->byteval); + printf("bytearray"); + for (i = 0; i < sizeof(plat->bytearray); i++) + printf(" %02x", plat->bytearray[i]); + printf("\n"); + + printf("int %d\n", plat->intval); + printf("intarray"); + for (i = 0; i < ARRAY_SIZE(plat->intarray); i++) + printf(" %d", plat->intarray[i]); + printf("\n"); + + printf("longbytearray"); + for (i = 0; i < sizeof(plat->longbytearray); i++) + printf(" %02x", plat->longbytearray[i]); + printf("\n"); + + printf("string %s\n", plat->stringval); + printf("stringarray"); + for (i = 0; i < ARRAY_SIZE(plat->stringarray); i++) + printf(" \"%s\"", plat->stringarray[i]); + printf("\n"); + + return 0; +} + +U_BOOT_DRIVER(sandbox_spl_test) = { + .name = "sandbox_spl_test", + .id = UCLASS_MISC, + .flags = DM_FLAG_PRE_RELOC, + .probe = sandbox_spl_probe, +}; From f24770d8124c097b7b57ccc22b67aaf02bb6e850 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Mon, 4 Jul 2016 11:58:02 -0600 Subject: [PATCH 22/62] dm: Add a header that provides access to the of-platdata structs 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 --- 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 0000000000..e13afa6608 --- /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 +#endif + +#endif From 7423daa60eb30b6613dfc19a51c55de23fd4d703 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Mon, 4 Jul 2016 11:58:03 -0600 Subject: [PATCH 23/62] dm: clk: Add support for of-platdata Add support for this feature in the core clock code. Signed-off-by: Simon Glass --- drivers/clk/clk-uclass.c | 22 ++++++++++++++++++++-- drivers/clk/clk_fixed_rate.c | 2 ++ include/clk.h | 4 ++++ 3 files changed, 26 insertions(+), 2 deletions(-) diff --git a/drivers/clk/clk-uclass.c b/drivers/clk/clk-uclass.c index 6e4d67220a..e0f85677e3 100644 --- a/drivers/clk/clk-uclass.c +++ b/drivers/clk/clk-uclass.c @@ -10,6 +10,7 @@ #include #include #include +#include #include DECLARE_GLOBAL_DATA_PTR; @@ -21,6 +22,22 @@ static inline struct clk_ops *clk_dev_ops(struct udevice *dev) #if CONFIG_IS_ENABLED(OF_CONTROL) #ifdef CONFIG_SPL_BUILD +# if CONFIG_IS_ENABLED(OF_PLATDATA) +int clk_get_by_index_platdata(struct udevice *dev, int index, + struct phandle_2_cell *cells, struct clk *clk) +{ + int ret; + + if (index != 0) + return -ENOSYS; + ret = uclass_get_device(UCLASS_CLK, 0, &clk->dev); + if (ret) + return ret; + clk->id = cells[0].id; + + return 0; +} +# else int clk_get_by_index(struct udevice *dev, int index, struct clk *clk) { int ret; @@ -39,6 +56,7 @@ int clk_get_by_index(struct udevice *dev, int index, struct clk *clk) clk->id = cell[1]; return 0; } +# endif /* OF_PLATDATA */ int clk_get_by_name(struct udevice *dev, const char *name, struct clk *clk) { @@ -117,8 +135,8 @@ int clk_get_by_name(struct udevice *dev, const char *name, struct clk *clk) return clk_get_by_index(dev, index, clk); } -#endif -#endif +#endif /* CONFIG_SPL_BUILD */ +#endif /* OF_CONTROL */ int clk_request(struct udevice *dev, struct clk *clk) { diff --git a/drivers/clk/clk_fixed_rate.c b/drivers/clk/clk_fixed_rate.c index 797e537907..9c4d2b322f 100644 --- a/drivers/clk/clk_fixed_rate.c +++ b/drivers/clk/clk_fixed_rate.c @@ -30,9 +30,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 2f31cf70e3..161bc2825f 100644 --- a/include/clk.h +++ b/include/clk.h @@ -60,6 +60,10 @@ struct clk { }; #if CONFIG_IS_ENABLED(OF_CONTROL) +struct phandle_2_cell; +int clk_get_by_index_platdata(struct udevice *dev, int index, + struct phandle_2_cell *cells, struct clk *clk); + /** * clock_get_by_index - Get/request a clock by integer index. * From b484b0daefc43bb3a6258a44040b53602060b2af Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Mon, 4 Jul 2016 11:58:04 -0600 Subject: [PATCH 24/62] dm: serial: Add support for of-platdata 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 --- 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 0ce5c44f33..19f38e162e 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) { From 7a53a54073e663d79ea0e08818e98f14fde5685a Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Mon, 4 Jul 2016 11:58:05 -0600 Subject: [PATCH 25/62] dm: Don't include fdtdec functions when of-platdata is enabled We cannot access the device tree in this case, so avoid compiling in the various device-tree helper functions. Signed-off-by: Simon Glass --- lib/Makefile | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/lib/Makefile b/lib/Makefile index f48d90103d..f6a8ba1227 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -48,11 +48,10 @@ obj-$(CONFIG_$(SPL_)SHA1) += sha1.o obj-$(CONFIG_$(SPL_)SHA256) += sha256.o 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 From 2789ddb9d5bc6acd1f7a2822fed08cd7cf2a965e Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Mon, 4 Jul 2016 11:58:06 -0600 Subject: [PATCH 26/62] dm: Add an option to enable the of-platdata feature Add a Kconfig option to enable this feature. Signed-off-by: Simon Glass --- dts/Kconfig | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/dts/Kconfig b/dts/Kconfig index c56c1299c0..4b7d8b15cc 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 From 39782afb1ae86c15e59b1118278513a1a545652c Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Mon, 4 Jul 2016 11:58:07 -0600 Subject: [PATCH 27/62] dm: Add a README for of-platdata Add documentation on how this works, including the benefits and drawbacks. Signed-off-by: Simon Glass --- doc/driver-model/of-plat.txt | 268 +++++++++++++++++++++++++++++++++++ 1 file changed, 268 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 0000000000..96b9b4642c --- /dev/null +++ b/doc/driver-model/of-plat.txt @@ -0,0 +1,268 @@ +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 = ; + 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 + + 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. + +The 'swig' tool is needed to build the libfdt Python module. + + +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 +6/6/16 From ec564b47dad46e57347cef7b3f7f5bb51a329302 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Mon, 4 Jul 2016 11:58:08 -0600 Subject: [PATCH 28/62] dm: Add a library to provide simple device-tree access 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 --- tools/dtoc/.gitignore | 1 + tools/dtoc/fdt_fallback.py | 207 +++++++++++++++++++++++++++++++++++++ tools/dtoc/fdt_util.py | 86 +++++++++++++++ 3 files changed, 294 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 0000000000..0d20b6487c --- /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 0000000000..14decf394d --- /dev/null +++ b/tools/dtoc/fdt_fallback.py @@ -0,0 +1,207 @@ +#!/usr/bin/python +# +# Copyright (C) 2016 Google, Inc +# Written by Simon Glass +# +# 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 0000000000..929b524fcf --- /dev/null +++ b/tools/dtoc/fdt_util.py @@ -0,0 +1,86 @@ +#!/usr/bin/python +# +# Copyright (C) 2016 Google, Inc +# Written by Simon Glass +# +# 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 stored as a 4-byte string + TYPE_BYTE: a byte stored as a single-byte string + """ + 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 GetEmpty(type): + """Get an empty / zero value of the given type + + Returns: + A single value of the given type + """ + if type == TYPE_BYTE: + return chr(0) + elif type == TYPE_INT: + return struct.pack('I", val)[0] From 69f2ed7746c8944b2865c3838c36d97908305586 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Mon, 4 Jul 2016 11:58:09 -0600 Subject: [PATCH 29/62] dm: Add a tool to generate C code from a device tree 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 --- tools/dtoc/dtoc | 1 + tools/dtoc/dtoc.py | 391 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 392 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 0000000000..896ca44e62 --- /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 0000000000..24f3858561 --- /dev/null +++ b/tools/dtoc/dtoc.py @@ -0,0 +1,391 @@ +#!/usr/bin/python +# +# Copyright (C) 2016 Google, Inc +# Written by Simon Glass +# +# SPDX-License-Identifier: GPL-2.0+ +# + +import copy +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 ScanStructs(self): + """Scan the device tree building up the C structures we will use. + + 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. + + Once the widest property is determined, all other properties are + updated to match that width. + """ + structs = {} + for node in self._valid_nodes: + node_name = self.GetCompatName(node) + fields = {} + + # Get a list of all the valid properties in this node. + for name, prop in node.props.iteritems(): + if name not in PROP_IGNORE_LIST and name[0] != '#': + fields[name] = copy.deepcopy(prop) + + # If we've seen this node_name before, update the existing struct. + if node_name in structs: + struct = structs[node_name] + for name, prop in fields.iteritems(): + oldprop = struct.get(name) + if oldprop: + oldprop.Widen(prop) + else: + struct[name] = prop + + # Otherwise store this as a new struct. + else: + structs[node_name] = fields + + upto = 0 + for node in self._valid_nodes: + node_name = self.GetCompatName(node) + struct = structs[node_name] + for name, prop in node.props.iteritems(): + if name not in PROP_IGNORE_LIST and name[0] != '#': + prop.Widen(struct[name]) + upto += 1 + return structs + + def GenerateStructs(self, structs): + """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 \n') + self.Out('#include \n') + + # 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 \n') + self.Out('#include \n') + self.Out('#include \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) +structs = plat.ScanStructs() + +for cmd in args[0].split(','): + if cmd == 'struct': + plat.GenerateStructs(structs) + elif cmd == 'platdata': + plat.GenerateTables() + else: + raise ValueError("Unknown command '%s': (use: struct, platdata)" % cmd) From dbbe2e6401fc8539f456cab7ef1dd38f9495591d Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Mon, 4 Jul 2016 11:58:10 -0600 Subject: [PATCH 30/62] dm: Makefile: Build of-platdata files when the feature is enabled 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 --- scripts/Makefile.spl | 39 ++++++++++++++++++++++++++++++++++++--- 1 file changed, 36 insertions(+), 3 deletions(-) diff --git a/scripts/Makefile.spl b/scripts/Makefile.spl index 2b5c9954d3..324b03fb22 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 $@ From 76bce10d2131938fcd5b1bbb0479cdb66daffa29 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Mon, 4 Jul 2016 11:58:11 -0600 Subject: [PATCH 31/62] dm: Add a more efficient libfdt library 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. It requires the 'swig' to build. Signed-off-by: Simon Glass --- lib/libfdt/libfdt.swig | 89 +++++++++++++++++++ lib/libfdt/setup.py | 38 ++++++++ lib/libfdt/test_libfdt.py | 14 +++ scripts/Makefile.host | 9 +- tools/Makefile | 11 +++ tools/dtoc/fdt.py | 180 ++++++++++++++++++++++++++++++++++++++ 6 files changed, 339 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 0000000000..14f583dfbe --- /dev/null +++ b/lib/libfdt/libfdt.swig @@ -0,0 +1,89 @@ +/* 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]; +}; + +/* + * This is a work-around since I'm not sure of a better way to copy out the + * contents of a string. This is used in dtoc/GetProps(). The intent is to + * pass in a pointer to a property and access the data field at the end of + * it. Ideally the Data() function above would be able to do this directly, + * but I'm not sure how to do that. + */ +#pragma SWIG nowarn=454 +%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 0000000000..62e7bcc1ac --- /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 0000000000..14d0da4fb3 --- /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 bff8b5bc61..763a699c4c 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 f72294a98a..2731b7ac9f 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 0000000000..1d913a925e --- /dev/null +++ b/tools/dtoc/fdt.py @@ -0,0 +1,180 @@ +#!/usr/bin/python +# +# Copyright (C) 2016 Google, Inc +# Written by Simon Glass +# +# 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 + self.value = True + 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 = [self.value] + + if type(self.value) == list and len(newprop.value) > len(self.value): + val = fdt_util.GetEmpty(self.type) + while len(self.value) < len(newprop.value): + self.value.append(val) + + +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 From 162a7a421718a2d15716a78ffb7abb1d94f6b03a Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Mon, 4 Jul 2016 11:58:12 -0600 Subject: [PATCH 32/62] Only build the libfdt python module if 'swig' is available When swig is not available, we can still build correctly. So make this optional. Add a comment about how to enable this build. Signed-off-by: Simon Glass --- tools/Makefile | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tools/Makefile b/tools/Makefile index 2731b7ac9f..421414bc15 100644 --- a/tools/Makefile +++ b/tools/Makefile @@ -107,7 +107,10 @@ 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 +# Build a libfdt Python module if swig is available +# Use 'sudo apt-get install swig libpython-dev' to enable this +hostprogs-$(CONFIG_SPL_OF_PLATDATA) += \ + $(if $(shell which swig),_libfdt.so) _libfdt.so-sharedobjs += $(LIBFDT_OBJS) libfdt: From e24091398d50961ece2fcb2924d7c37d329abc09 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Mon, 4 Jul 2016 11:58:13 -0600 Subject: [PATCH 33/62] tiny-printf: Support assert() At present assert() is not supported with tiny-printf, so when DEBUG is enabled a build error is generated for each assert(). Add an __assert_fail() function to correct this. It prints a message and then hangs. Signed-off-by: Simon Glass --- lib/tiny-printf.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/lib/tiny-printf.c b/lib/tiny-printf.c index b334f053cc..1aa43aba44 100644 --- a/lib/tiny-printf.c +++ b/lib/tiny-printf.c @@ -185,3 +185,12 @@ int snprintf(char *buf, size_t size, const char *fmt, ...) return ret; } + +void __assert_fail(const char *assertion, const char *file, unsigned line, + const char *function) +{ + /* This will not return */ + printf("%s:%u: %s: Assertion `%s' failed.", file, line, function, + assertion); + hang(); +} From 7d23b9cf2b1a5a86f7e89a443e3a2de9dac8a9ad Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Mon, 4 Jul 2016 11:58:14 -0600 Subject: [PATCH 34/62] dm: spl: Bind in all devices in SPL with of-platdata When CONFIG_OF_PLATDATA is enabled, we cannot use the u-boot,dm-pre-reloc device tree property since the device tree is not available. However, dt-platdata.c only includes devices which would have been present in the device tree, and we can assume that all such devices are needed for SPL. If they were not needed, they would have been omitted to save space. So in this case, bind all devices regardless of the u-boot,dm-pre-reloc setting. This avoids needing to add a DM_FLAG_PRE_RELOC to every driver, thus affecting U-Boot proper also. Signed-off-by: Simon Glass --- common/spl/spl.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/common/spl/spl.c b/common/spl/spl.c index 59f41a1223..12aed02935 100644 --- a/common/spl/spl.c +++ b/common/spl/spl.c @@ -210,7 +210,8 @@ int spl_init(void) } } if (IS_ENABLED(CONFIG_SPL_DM)) { - ret = dm_init_and_scan(true); + /* With CONFIG_OF_PLATDATA, bring in all devices */ + ret = dm_init_and_scan(!CONFIG_IS_ENABLED(OF_PLATDATA)); if (ret) { debug("dm_init_and_scan() returned error %d\n", ret); return ret; From fd1c2d9b6a3a9b41ae070ca47361bd6cc6aaaf09 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Mon, 4 Jul 2016 11:58:15 -0600 Subject: [PATCH 35/62] dm: core: Rename DM_NAME_ALLOCED to DM_FLAG_NAME_ALLOCED This is a flag. Adjust the name to be consistent with the other flags. Signed-off-by: Simon Glass --- drivers/core/device-remove.c | 2 +- drivers/core/device.c | 2 +- include/dm/device.h | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/core/device-remove.c b/drivers/core/device-remove.c index 0e56b23fbb..a7f77b4a21 100644 --- a/drivers/core/device-remove.c +++ b/drivers/core/device-remove.c @@ -112,7 +112,7 @@ int device_unbind(struct udevice *dev) devres_release_all(dev); - if (dev->flags & DM_NAME_ALLOCED) + if (dev->flags & DM_FLAG_NAME_ALLOCED) free((char *)dev->name); free(dev); diff --git a/drivers/core/device.c b/drivers/core/device.c index d8f9d5b554..6967c3df0f 100644 --- a/drivers/core/device.c +++ b/drivers/core/device.c @@ -738,7 +738,7 @@ bool device_is_last_sibling(struct udevice *dev) void device_set_name_alloced(struct udevice *dev) { - dev->flags |= DM_NAME_ALLOCED; + dev->flags |= DM_FLAG_NAME_ALLOCED; } int device_set_name(struct udevice *dev, const char *name) diff --git a/include/dm/device.h b/include/dm/device.h index 1bfcf3bcbc..fc35f4dfd4 100644 --- a/include/dm/device.h +++ b/include/dm/device.h @@ -42,7 +42,7 @@ struct driver_info; #define DM_FLAG_BOUND (1 << 6) /* Device name is allocated and should be freed on unbind() */ -#define DM_NAME_ALLOCED (1 << 7) +#define DM_FLAG_NAME_ALLOCED (1 << 7) /** * struct udevice - An instance of a driver @@ -553,7 +553,7 @@ int device_set_name(struct udevice *dev, const char *name); /** * device_set_name_alloced() - note that a device name is allocated * - * This sets the DM_NAME_ALLOCED flag for the device, so that when it is + * This sets the DM_FLAG_NAME_ALLOCED flag for the device, so that when it is * unbound the name will be freed. This avoids memory leaks. * * @dev: Device to update From efefe1221bd779f319b810c5415e577c331edec8 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Mon, 4 Jul 2016 11:58:16 -0600 Subject: [PATCH 36/62] dtoc: Ignore the u-boot, dm-pre-reloc property This property is not useful for of-platdata, so omit it. Signed-off-by: Simon Glass --- tools/dtoc/dtoc.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/dtoc/dtoc.py b/tools/dtoc/dtoc.py index 24f3858561..374ad1ca49 100755 --- a/tools/dtoc/dtoc.py +++ b/tools/dtoc/dtoc.py @@ -40,6 +40,7 @@ PROP_IGNORE_LIST = [ 'linux,phandle', "status", 'phandle', + 'u-boot,dm-pre-reloc', ] # C type declarations for the tyues we support From d22199b166e7064ad68cba52be390b88f2de79c9 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Mon, 4 Jul 2016 11:58:17 -0600 Subject: [PATCH 37/62] dm: Don't attach the device tree to SPL with of-platdata When of-platdata is used in SPL we don't use the device tree. So there is no point in attaching it. Adjust the Makefile to skip attaching the device tree when of-platdata is enabled. Signed-off-by: Simon Glass --- scripts/Makefile.spl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/Makefile.spl b/scripts/Makefile.spl index 324b03fb22..3ba974226b 100644 --- a/scripts/Makefile.spl +++ b/scripts/Makefile.spl @@ -173,7 +173,7 @@ cmd_cat = cat $(filter-out $(PHONY), $^) > $@ quiet_cmd_copy = COPY $@ cmd_copy = cp $< $@ -ifeq ($(CONFIG_SPL_OF_CONTROL)$(CONFIG_OF_SEPARATE),yy) +ifeq ($(CONFIG_SPL_OF_CONTROL)$(CONFIG_OF_SEPARATE)$(CONFIG_SPL_OF_PLATDATA),yy) $(obj)/$(SPL_BIN)-dtb.bin: $(obj)/$(SPL_BIN)-nodtb.bin $(obj)/$(SPL_BIN)-pad.bin \ $(obj)/$(SPL_BIN).dtb FORCE $(call if_changed,cat) From 9fa28190091e59b7c9b9ba32e5a81fa432c485b6 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Mon, 4 Jul 2016 11:58:18 -0600 Subject: [PATCH 38/62] dm: core: Expand platdata for of-platdata devices Devices which use of-platdata have their own platdata. However, in many cases the driver will have its own auto-alloced platdata, for use with the device tree. The ofdata_to_platdata() method converts the device tree settings to platdata. With of-platdata we would not normally allocate the platdata since it is provided by the U_BOOT_DEVICE() declaration. However this is inconvenient since the of-platdata struct is closely tied to the device tree properties. It is unlikely to exactly match the platdata needed by the driver. In fact a useful approach is to declare platdata in the driver like this: struct r3288_mmc_platdata { struct dtd_rockchip_rk3288_dw_mshc of_platdata; /* the 'normal' fields go here */ }; In this case we have dt_platadata available, but the normal fields are not present, since ofdata_to_platdata() is never called. In fact driver model doesn't allocate any space for the 'normal' fields, since it sees that there is already platform data attached to the device. To make this easier, adjust driver model to allocate the full size of the struct (i.e. platdata_auto_alloc_size from the driver) and copy in the of-platdata. This means that when the driver's bind() method is called, the of-platdata will be present, followed by zero bytes for the empty 'normal field' portion. A new DM_FLAG_OF_PLATDATA flag is available that indicates that the platdata came from of-platdata. When the allocation/copy happens, the DM_FLAG_ALLOC_PDATA flag will be set as well. The dtoc tool is updated to output the platdata_size field, since U-Boot has no other way of knowing the size of the of-platdata struct. Signed-off-by: Simon Glass --- drivers/core/device.c | 43 ++++++++++++++++++++++++++++++++----------- include/dm/device.h | 2 ++ include/dm/platdata.h | 5 +++++ tools/dtoc/dtoc.py | 2 ++ 4 files changed, 41 insertions(+), 11 deletions(-) diff --git a/drivers/core/device.c b/drivers/core/device.c index 6967c3df0f..5bb1d7793d 100644 --- a/drivers/core/device.c +++ b/drivers/core/device.c @@ -30,7 +30,7 @@ DECLARE_GLOBAL_DATA_PTR; static int device_bind_common(struct udevice *parent, const struct driver *drv, const char *name, void *platdata, ulong driver_data, int of_offset, - struct udevice **devp) + uint of_platdata_size, struct udevice **devp) { struct udevice *dev; struct uclass *uc; @@ -84,12 +84,29 @@ static int device_bind_common(struct udevice *parent, const struct driver *drv, } } - if (!dev->platdata && drv->platdata_auto_alloc_size) { - dev->flags |= DM_FLAG_ALLOC_PDATA; - dev->platdata = calloc(1, drv->platdata_auto_alloc_size); - if (!dev->platdata) { - ret = -ENOMEM; - goto fail_alloc1; + if (drv->platdata_auto_alloc_size) { + bool alloc = !platdata; + + if (CONFIG_IS_ENABLED(OF_PLATDATA)) { + if (of_platdata_size) { + dev->flags |= DM_FLAG_OF_PLATDATA; + if (of_platdata_size < + drv->platdata_auto_alloc_size) + alloc = true; + } + } + if (alloc) { + dev->flags |= DM_FLAG_ALLOC_PDATA; + dev->platdata = calloc(1, + drv->platdata_auto_alloc_size); + if (!dev->platdata) { + ret = -ENOMEM; + goto fail_alloc1; + } + if (CONFIG_IS_ENABLED(OF_PLATDATA) && platdata) { + memcpy(dev->platdata, platdata, + of_platdata_size); + } } } @@ -202,14 +219,14 @@ int device_bind_with_driver_data(struct udevice *parent, struct udevice **devp) { return device_bind_common(parent, drv, name, NULL, driver_data, - of_offset, devp); + of_offset, 0, devp); } int device_bind(struct udevice *parent, const struct driver *drv, const char *name, void *platdata, int of_offset, struct udevice **devp) { - return device_bind_common(parent, drv, name, platdata, 0, of_offset, + return device_bind_common(parent, drv, name, platdata, 0, of_offset, 0, devp); } @@ -217,6 +234,7 @@ int device_bind_by_name(struct udevice *parent, bool pre_reloc_only, const struct driver_info *info, struct udevice **devp) { struct driver *drv; + uint platdata_size = 0; drv = lists_driver_lookup_name(info->name); if (!drv) @@ -224,8 +242,11 @@ int device_bind_by_name(struct udevice *parent, bool pre_reloc_only, if (pre_reloc_only && !(drv->flags & DM_FLAG_PRE_RELOC)) return -EPERM; - return device_bind(parent, drv, info->name, (void *)info->platdata, - -1, devp); +#if CONFIG_IS_ENABLED(OF_PLATDATA) + platdata_size = info->platdata_size; +#endif + return device_bind_common(parent, drv, info->name, + (void *)info->platdata, 0, -1, platdata_size, devp); } static void *alloc_priv(int size, uint flags) diff --git a/include/dm/device.h b/include/dm/device.h index fc35f4dfd4..c825d47236 100644 --- a/include/dm/device.h +++ b/include/dm/device.h @@ -44,6 +44,8 @@ struct driver_info; /* Device name is allocated and should be freed on unbind() */ #define DM_FLAG_NAME_ALLOCED (1 << 7) +#define DM_FLAG_OF_PLATDATA (1 << 8) + /** * struct udevice - An instance of a driver * diff --git a/include/dm/platdata.h b/include/dm/platdata.h index 6f4f00140e..488b2ab0ae 100644 --- a/include/dm/platdata.h +++ b/include/dm/platdata.h @@ -22,10 +22,15 @@ * * @name: Driver name * @platdata: Driver-specific platform data + * @platdata_size: Size of platform data structure + * @flags: Platform data flags (DM_FLAG_...) */ struct driver_info { const char *name; const void *platdata; +#if CONFIG_IS_ENABLED(OF_PLATDATA) + uint platdata_size; +#endif }; /** diff --git a/tools/dtoc/dtoc.py b/tools/dtoc/dtoc.py index 374ad1ca49..ec80abe717 100755 --- a/tools/dtoc/dtoc.py +++ b/tools/dtoc/dtoc.py @@ -346,6 +346,8 @@ class DtbPlatdata: 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('\t.platdata_size\t= sizeof(%s%s),\n' % + (VAL_PREFIX, var_name)) self.Buf('};\n') self.Buf('\n') From 2c9dfb5807bfbf97b60481586d5db3c677cba65b Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Mon, 4 Jul 2016 11:58:19 -0600 Subject: [PATCH 39/62] sandbox: Don't bring in the eeprom emulator in SPL This driver should not be used in SPL since we do not have I2C support enabled in SPL on sandbox. Signed-off-by: Simon Glass --- drivers/misc/Makefile | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index 3eac0245ea..fff6f0cdf9 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile @@ -29,8 +29,10 @@ obj-$(CONFIG_PDSP188x) += pdsp188x.o obj-$(CONFIG_$(SPL_)PWRSEQ) += pwrseq-uclass.o obj-$(CONFIG_SANDBOX) += sysreset_sandbox.o ifdef CONFIG_DM_I2C +ifndef CONFIG_SPL_BUILD obj-$(CONFIG_SANDBOX) += i2c_eeprom_emul.o endif +endif obj-$(CONFIG_SMSC_LPC47M) += smsc_lpc47m.o obj-$(CONFIG_SMSC_SIO1007) += smsc_sio1007.o obj-$(CONFIG_STATUS_LED) += status_led.o From 3949a413edb2c2be6ad930a5ba4b240bbca53d08 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Mon, 4 Jul 2016 11:58:20 -0600 Subject: [PATCH 40/62] dm: sandbox: Enable of-platdata for sandbox_spl Enable this feature so that we can use it for testing in sandbox_spl. Signed-off-by: Simon Glass --- configs/sandbox_spl_defconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/configs/sandbox_spl_defconfig b/configs/sandbox_spl_defconfig index d92597b110..0f6dda8c7e 100644 --- a/configs/sandbox_spl_defconfig +++ b/configs/sandbox_spl_defconfig @@ -64,6 +64,7 @@ CONFIG_CMD_FS_GENERIC=y CONFIG_OF_CONTROL=y CONFIG_SPL_OF_CONTROL=y CONFIG_OF_HOSTFILE=y +CONFIG_SPL_OF_PLATDATA=y CONFIG_NETCONSOLE=y CONFIG_SPL_DM=y CONFIG_REGMAP=y From a951431e827cfd862a4c095e85e8650a6b8370f7 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Mon, 4 Jul 2016 11:58:21 -0600 Subject: [PATCH 41/62] dm: core: Move regmap allocation into a separate function We plan to add a new way of creating a regmap for of-platdata. Move the allocation code into a separate function so that it can be shared. Signed-off-by: Simon Glass --- drivers/core/regmap.c | 34 ++++++++++++++++++++++------------ 1 file changed, 22 insertions(+), 12 deletions(-) diff --git a/drivers/core/regmap.c b/drivers/core/regmap.c index 7e073cf9c0..dcb1a30d5f 100644 --- a/drivers/core/regmap.c +++ b/drivers/core/regmap.c @@ -15,6 +15,27 @@ DECLARE_GLOBAL_DATA_PTR; +static struct regmap *regmap_alloc_count(int count) +{ + struct regmap *map; + + map = malloc(sizeof(struct regmap)); + if (!map) + return NULL; + if (count <= 1) { + map->range = &map->base_range; + } else { + map->range = malloc(count * sizeof(struct regmap_range)); + if (!map->range) { + free(map); + return NULL; + } + } + map->range_count = count; + + return map; +} + #if CONFIG_IS_ENABLED(OF_PLATDATA) int regmap_init_mem_platdata(struct udevice *dev, fdt32_t *reg, int size, struct regmap **mapp) @@ -45,22 +66,11 @@ int regmap_init_mem(struct udevice *dev, struct regmap **mapp) if (!cell || !count) return -EINVAL; - map = malloc(sizeof(struct regmap)); + map = regmap_alloc_count(count); if (!map) return -ENOMEM; - if (count <= 1) { - map->range = &map->base_range; - } else { - map->range = malloc(count * sizeof(struct regmap_range)); - if (!map->range) { - free(map); - return -ENOMEM; - } - } - map->base = fdtdec_get_number(cell, addr_len); - map->range_count = count; for (range = map->range; count > 0; count--, cell += both_len, range++) { From 1e6ca1a6ad7285569b22465b8387db242b310553 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Mon, 4 Jul 2016 11:58:22 -0600 Subject: [PATCH 42/62] dm: core: Add an implementation of regmap_init_mem_platdata() Add an implementation of this function which mirrors the functions of the automatic device-tree implementation. This can be used with of-platdata to create regmaps. Signed-off-by: Simon Glass --- drivers/core/regmap.c | 18 ++++++++++++++++-- include/regmap.h | 15 ++++++++++++++- 2 files changed, 30 insertions(+), 3 deletions(-) diff --git a/drivers/core/regmap.c b/drivers/core/regmap.c index dcb1a30d5f..0299ff0879 100644 --- a/drivers/core/regmap.c +++ b/drivers/core/regmap.c @@ -37,10 +37,24 @@ static struct regmap *regmap_alloc_count(int count) } #if CONFIG_IS_ENABLED(OF_PLATDATA) -int regmap_init_mem_platdata(struct udevice *dev, fdt32_t *reg, int size, +int regmap_init_mem_platdata(struct udevice *dev, u32 *reg, int count, struct regmap **mapp) { - /* TODO(sjg@chromium.org): Implement this when needed */ + struct regmap_range *range; + struct regmap *map; + + map = regmap_alloc_count(count); + if (!map) + return -ENOMEM; + + map->base = *reg; + for (range = map->range; count > 0; reg += 2, range++, count--) { + range->start = *reg; + range->size = reg[1]; + } + + *mapp = map; + return 0; } #else diff --git a/include/regmap.h b/include/regmap.h index 922b39fad0..1eed94e47a 100644 --- a/include/regmap.h +++ b/include/regmap.h @@ -56,7 +56,20 @@ 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, +/** + * regmap_init_mem_platdata() - Set up a new memory register map for of-platdata + * + * This creates a new regmap with a list of regions passed in, rather than + * using the device tree. It only supports 32-bit machines. + * + * Use regmap_uninit() to free it. + * + * @dev: Device that uses this map + * @reg: List of address, size pairs + * @count: Number of pairs (e.g. 1 if the regmap has a single entry) + * @mapp: Returns allocated map + */ +int regmap_init_mem_platdata(struct udevice *dev, u32 *reg, int count, struct regmap **mapp); /** From b2927fbaa89d2c7f7ac3977bc0cab2a4b7924acd Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Mon, 4 Jul 2016 11:58:23 -0600 Subject: [PATCH 43/62] dm: serial: ns16550: Update to support of-platdata With of-platdata this driver cannot know the format of the of-platdata struct, so we cannot use generic code for accessing the of-platdata. Each SoC that uses this driver will need to set up ns16550's platdata for it. So don't compile in the generic code. Signed-off-by: Simon Glass --- drivers/serial/ns16550.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/serial/ns16550.c b/drivers/serial/ns16550.c index c6cb3eb500..88fca15357 100644 --- a/drivers/serial/ns16550.c +++ b/drivers/serial/ns16550.c @@ -347,7 +347,7 @@ int ns16550_serial_probe(struct udevice *dev) return 0; } -#if CONFIG_IS_ENABLED(OF_CONTROL) +#if CONFIG_IS_ENABLED(OF_CONTROL) && !CONFIG_IS_ENABLED(OF_PLATDATA) int ns16550_serial_ofdata_to_platdata(struct udevice *dev) { struct ns16550_platdata *plat = dev->platdata; @@ -416,6 +416,7 @@ const struct dm_serial_ops ns16550_serial_ops = { .setbrg = ns16550_serial_setbrg, }; +#if !CONFIG_IS_ENABLED(OF_PLATDATA) #if CONFIG_IS_ENABLED(OF_CONTROL) /* * Please consider existing compatible strings before adding a new @@ -452,4 +453,5 @@ U_BOOT_DRIVER(ns16550_serial) = { .flags = DM_FLAG_PRE_RELOC, }; #endif +#endif /* !OF_PLATDATA */ #endif /* CONFIG_DM_SERIAL */ From 2fc24d5335a35a4880fdc04cf4d45754d29cd415 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Mon, 4 Jul 2016 11:58:24 -0600 Subject: [PATCH 44/62] rockchip: serial: Add an of-platdata driver for rockchip Add a driver that works with of-platdata. It sets up the platform data and calls the standard ns16550 driver. Signed-off-by: Simon Glass --- drivers/serial/Kconfig | 9 +++++++ drivers/serial/Makefile | 3 +++ drivers/serial/serial_rockchip.c | 43 ++++++++++++++++++++++++++++++++ 3 files changed, 55 insertions(+) create mode 100644 drivers/serial/serial_rockchip.c diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig index 0e3890391b..9ff7234d61 100644 --- a/drivers/serial/Kconfig +++ b/drivers/serial/Kconfig @@ -312,6 +312,15 @@ config SYS_NS16550 be used. It can be a constant or a function to get clock, eg, get_serial_clock(). +config ROCKCHIP_SERIAL + bool "Rockchip on-chip UART support" + depends on DM_SERIAL && SPL_OF_PLATDATA + help + Select this to enable a debug UART for Rockchip devices when using + CONFIG_OF_PLATDATA (i.e. a compiled-in device tree replacemenmt). + This uses the ns16550 driver, converting the platdata from of-platdata + to the ns16550 format. + config SANDBOX_SERIAL bool "Sandbox UART support" depends on SANDBOX diff --git a/drivers/serial/Makefile b/drivers/serial/Makefile index 92cbea5913..6986d659ab 100644 --- a/drivers/serial/Makefile +++ b/drivers/serial/Makefile @@ -28,6 +28,9 @@ obj-$(CONFIG_S5P) += serial_s5p.o obj-$(CONFIG_MXC_UART) += serial_mxc.o obj-$(CONFIG_PXA_SERIAL) += serial_pxa.o obj-$(CONFIG_MESON_SERIAL) += serial_meson.o +ifdef CONFIG_SPL_BUILD +obj-$(CONFIG_ROCKCHIP_SERIAL) += serial_rockchip.o +endif obj-$(CONFIG_S3C24X0_SERIAL) += serial_s3c24x0.o obj-$(CONFIG_XILINX_UARTLITE) += serial_xuartlite.o obj-$(CONFIG_SANDBOX_SERIAL) += sandbox.o diff --git a/drivers/serial/serial_rockchip.c b/drivers/serial/serial_rockchip.c new file mode 100644 index 0000000000..6bac95a414 --- /dev/null +++ b/drivers/serial/serial_rockchip.c @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2015 Google, Inc + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include +#include +#include +#include +#include + +struct rockchip_uart_platdata { + struct dtd_rockchip_rk3288_uart dtplat; + struct ns16550_platdata plat; +}; + +struct dtd_rockchip_rk3288_uart *dtplat, s_dtplat; + +static int rockchip_serial_probe(struct udevice *dev) +{ + struct rockchip_uart_platdata *plat = dev_get_platdata(dev); + + /* Create some new platform data for the standard driver */ + plat->plat.base = plat->dtplat.reg[0]; + plat->plat.reg_shift = plat->dtplat.reg_shift; + plat->plat.clock = plat->dtplat.clock_frequency; + dev->platdata = &plat->plat; + + return ns16550_serial_probe(dev); +} + +U_BOOT_DRIVER(rockchip_rk3288_uart) = { + .name = "rockchip_rk3288_uart", + .id = UCLASS_SERIAL, + .priv_auto_alloc_size = sizeof(struct NS16550), + .platdata_auto_alloc_size = sizeof(struct rockchip_uart_platdata), + .probe = rockchip_serial_probe, + .ops = &ns16550_serial_ops, + .flags = DM_FLAG_PRE_RELOC, +}; From 9ca7e6720e96e82be1de9ec0ba6bac9f1beeb02f Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Mon, 4 Jul 2016 11:58:25 -0600 Subject: [PATCH 45/62] rockchip: Update the sdram-channel property to support of-platdata Add an extra byte so that this data is not byteswapped. Add a comment to the code to explain the purpose. Signed-off-by: Simon Glass --- arch/arm/dts/rk3288-firefly.dts | 3 ++- arch/arm/include/asm/arch-rockchip/sdram.h | 6 ++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/arch/arm/dts/rk3288-firefly.dts b/arch/arm/dts/rk3288-firefly.dts index aed8d3a712..3176d5046b 100644 --- a/arch/arm/dts/rk3288-firefly.dts +++ b/arch/arm/dts/rk3288-firefly.dts @@ -30,7 +30,8 @@ 0x5 0x0>; rockchip,phy-timing = <0x48f9aab4 0xea0910 0x1002c200 0xa60 0x40 0x10 0x0>; - rockchip,sdram-channel = /bits/ 8 <0x1 0xa 0x3 0x2 0x1 0x0 0xf 0xf>; + /* Add a dummy value to cause of-platdata think this is bytes */ + rockchip,sdram-channel = /bits/ 8 <0x1 0xa 0x3 0x2 0x1 0x0 0xf 0xf 0xff>; rockchip,sdram-params = <0x30B25564 0x627 3 666000000 3 9 1>; }; diff --git a/arch/arm/include/asm/arch-rockchip/sdram.h b/arch/arm/include/asm/arch-rockchip/sdram.h index d3de42d297..c9e3001720 100644 --- a/arch/arm/include/asm/arch-rockchip/sdram.h +++ b/arch/arm/include/asm/arch-rockchip/sdram.h @@ -24,6 +24,12 @@ struct rk3288_sdram_channel { u8 row_3_4; u8 cs0_row; u8 cs1_row; + /* + * For of-platdata, which would otherwise convert this into two + * byte-swapped integers. With a size of 9 bytes, this struct will + * appear in of-platdata as a byte array. + */ + u8 dummy; }; struct rk3288_sdram_pctl_timing { From 6809b04f48fe02c26127383391d153d18134c77b Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Mon, 4 Jul 2016 11:58:26 -0600 Subject: [PATCH 46/62] rockchip: mmc: Move all DT decoding to ofdata_to_platdata() It is more correct to avoid touching the device tree in the probe() method. Update the driver to work this way. Signed-off-by: Simon Glass --- drivers/mmc/rockchip_dw_mmc.c | 32 +++++++++++++++++--------------- 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/drivers/mmc/rockchip_dw_mmc.c b/drivers/mmc/rockchip_dw_mmc.c index 691a51557d..7296c5f6f9 100644 --- a/drivers/mmc/rockchip_dw_mmc.c +++ b/drivers/mmc/rockchip_dw_mmc.c @@ -26,6 +26,9 @@ struct rockchip_mmc_plat { struct rockchip_dwmmc_priv { struct clk clk; struct dwmci_host host; + int fifo_depth; + bool fifo_mode; + u32 minmax[2]; }; static uint rockchip_dwmmc_get_mmc_clk(struct dwmci_host *host, uint freq) @@ -61,6 +64,16 @@ static int rockchip_dwmmc_ofdata_to_platdata(struct udevice *dev) else host->dev_index = 1; + priv->fifo_depth = fdtdec_get_int(gd->fdt_blob, dev->of_offset, + "fifo-depth", 0); + if (priv->fifo_depth < 0) + return -EINVAL; + priv->fifo_mode = fdtdec_get_bool(gd->fdt_blob, dev->of_offset, + "fifo-mode"); + if (fdtdec_get_int_array(gd->fdt_blob, dev->of_offset, + "clock-freq-min-max", priv->minmax, 2)) + return -EINVAL; + return 0; } @@ -71,28 +84,17 @@ static int rockchip_dwmmc_probe(struct udevice *dev) struct rockchip_dwmmc_priv *priv = dev_get_priv(dev); struct dwmci_host *host = &priv->host; struct udevice *pwr_dev __maybe_unused; - u32 minmax[2]; int ret; - int fifo_depth; ret = clk_get_by_index(dev, 0, &priv->clk); if (ret < 0) return ret; - if (fdtdec_get_int_array(gd->fdt_blob, dev->of_offset, - "clock-freq-min-max", minmax, 2)) - return -EINVAL; - - fifo_depth = fdtdec_get_int(gd->fdt_blob, dev->of_offset, - "fifo-depth", 0); - if (fifo_depth < 0) - return -EINVAL; - host->fifoth_val = MSIZE(0x2) | - RX_WMARK(fifo_depth / 2 - 1) | TX_WMARK(fifo_depth / 2); + RX_WMARK(priv->fifo_depth / 2 - 1) | + TX_WMARK(priv->fifo_depth / 2); - if (fdtdec_get_bool(gd->fdt_blob, dev->of_offset, "fifo-mode")) - host->fifo_mode = true; + host->fifo_mode = priv->fifo_mode; #ifdef CONFIG_PWRSEQ /* Enable power if needed */ @@ -105,7 +107,7 @@ static int rockchip_dwmmc_probe(struct udevice *dev) } #endif dwmci_setup_cfg(&plat->cfg, dev->name, host->buswidth, host->caps, - minmax[1], minmax[0]); + priv->minmax[1], priv->minmax[0]); host->mmc = &plat->mmc; host->mmc->priv = &priv->host; host->mmc->dev = dev; From bfeb443e3d583a5e7bbd98a67175f3a082a5e3d2 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Mon, 4 Jul 2016 11:58:27 -0600 Subject: [PATCH 47/62] rockchip: mmc: Update the driver to support of-platdata Add support for of-platdata with rk3288. This requires decoding the of-platdata struct and setting up the device from that. Also the driver needs to be renamed to match the string that of-platdata will search for. Signed-off-by: Simon Glass --- drivers/mmc/rockchip_dw_mmc.c | 29 ++++++++++++++++++++++++++--- 1 file changed, 26 insertions(+), 3 deletions(-) diff --git a/drivers/mmc/rockchip_dw_mmc.c b/drivers/mmc/rockchip_dw_mmc.c index 7296c5f6f9..020a59b921 100644 --- a/drivers/mmc/rockchip_dw_mmc.c +++ b/drivers/mmc/rockchip_dw_mmc.c @@ -7,8 +7,10 @@ #include #include #include +#include #include #include +#include #include #include #include @@ -19,6 +21,9 @@ DECLARE_GLOBAL_DATA_PTR; struct rockchip_mmc_plat { +#if CONFIG_IS_ENABLED(OF_PLATDATA) + struct dtd_rockchip_rk3288_dw_mshc dtplat; +#endif struct mmc_config cfg; struct mmc mmc; }; @@ -48,6 +53,7 @@ static uint rockchip_dwmmc_get_mmc_clk(struct dwmci_host *host, uint freq) static int rockchip_dwmmc_ofdata_to_platdata(struct udevice *dev) { +#if !CONFIG_IS_ENABLED(OF_PLATDATA) struct rockchip_dwmmc_priv *priv = dev_get_priv(dev); struct dwmci_host *host = &priv->host; @@ -73,7 +79,7 @@ static int rockchip_dwmmc_ofdata_to_platdata(struct udevice *dev) if (fdtdec_get_int_array(gd->fdt_blob, dev->of_offset, "clock-freq-min-max", priv->minmax, 2)) return -EINVAL; - +#endif return 0; } @@ -86,10 +92,27 @@ static int rockchip_dwmmc_probe(struct udevice *dev) struct udevice *pwr_dev __maybe_unused; int ret; +#if CONFIG_IS_ENABLED(OF_PLATDATA) + struct dtd_rockchip_rk3288_dw_mshc *dtplat = &plat->dtplat; + + host->name = dev->name; + host->ioaddr = map_sysmem(dtplat->reg[0], dtplat->reg[1]); + host->buswidth = dtplat->bus_width; + host->get_mmc_clk = rockchip_dwmmc_get_mmc_clk; + host->priv = dev; + host->dev_index = 0; + priv->fifo_depth = dtplat->fifo_depth; + priv->fifo_mode = 0; + memcpy(priv->minmax, dtplat->clock_freq_min_max, sizeof(priv->minmax)); + + ret = clk_get_by_index_platdata(dev, 0, dtplat->clocks, &priv->clk); + if (ret < 0) + return ret; +#else ret = clk_get_by_index(dev, 0, &priv->clk); if (ret < 0) return ret; - +#endif host->fifoth_val = MSIZE(0x2) | RX_WMARK(priv->fifo_depth / 2 - 1) | TX_WMARK(priv->fifo_depth / 2); @@ -134,7 +157,7 @@ static const struct udevice_id rockchip_dwmmc_ids[] = { }; U_BOOT_DRIVER(rockchip_dwmmc_drv) = { - .name = "rockchip_dwmmc", + .name = "rockchip_rk3288_dw_mshc", .id = UCLASS_MMC, .of_match = rockchip_dwmmc_ids, .ofdata_to_platdata = rockchip_dwmmc_ofdata_to_platdata, From 08fd82cf3e55c0ab7b1038d82a7c744d3193c269 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Mon, 4 Jul 2016 11:58:28 -0600 Subject: [PATCH 48/62] rockchip: clk: Move all DT decoding to ofdata_to_platdata() It is more correct to avoid touching the device tree in the probe() method. Update the driver to work this way. Also add an error check on grf since if that fails then we should not use it. Signed-off-by: Simon Glass --- drivers/clk/clk_rk3288.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/drivers/clk/clk_rk3288.c b/drivers/clk/clk_rk3288.c index 2285453e8d..1c2bf6423e 100644 --- a/drivers/clk/clk_rk3288.c +++ b/drivers/clk/clk_rk3288.c @@ -783,12 +783,22 @@ static struct clk_ops rk3288_clk_ops = { .set_rate = rk3288_clk_set_rate, }; -static int rk3288_clk_probe(struct udevice *dev) +static int rk3288_clk_ofdata_to_platdata(struct udevice *dev) { struct rk3288_clk_priv *priv = dev_get_priv(dev); priv->cru = (struct rk3288_cru *)dev_get_addr(dev); + + return 0; +} + +static int rk3288_clk_probe(struct udevice *dev) +{ + struct rk3288_clk_priv *priv = dev_get_priv(dev); + priv->grf = syscon_get_first_range(ROCKCHIP_SYSCON_GRF); + if (IS_ERR(priv->grf)) + return PTR_ERR(priv->grf); #ifdef CONFIG_SPL_BUILD rkclk_init(priv->cru, priv->grf); #endif @@ -820,5 +830,6 @@ U_BOOT_DRIVER(clk_rk3288) = { .priv_auto_alloc_size = sizeof(struct rk3288_clk_priv), .ops = &rk3288_clk_ops, .bind = rk3288_clk_bind, + .ofdata_to_platdata = rk3288_clk_ofdata_to_platdata, .probe = rk3288_clk_probe, }; From 2d143bd6199c6c7ed6513c6a066569f76b1289f4 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Mon, 4 Jul 2016 11:58:29 -0600 Subject: [PATCH 49/62] rockchip: clk: Update the rk3288 driver to support of-platdata Add support for of-platdata with rk3288. This requires decoding the of-platdata struct and setting up the devices from that. Also the driver needs to be renamed to match the string that of-platdata will search for. Signed-off-by: Simon Glass --- drivers/clk/clk_rk3288.c | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/drivers/clk/clk_rk3288.c b/drivers/clk/clk_rk3288.c index 1c2bf6423e..679f010bb7 100644 --- a/drivers/clk/clk_rk3288.c +++ b/drivers/clk/clk_rk3288.c @@ -7,7 +7,9 @@ #include #include #include +#include #include +#include #include #include #include @@ -21,6 +23,12 @@ DECLARE_GLOBAL_DATA_PTR; +struct rk3288_clk_plat { +#if CONFIG_IS_ENABLED(OF_PLATDATA) + struct dtd_rockchip_rk3288_cru dtd; +#endif +}; + struct rk3288_clk_priv { struct rk3288_grf *grf; struct rk3288_cru *cru; @@ -785,9 +793,11 @@ static struct clk_ops rk3288_clk_ops = { static int rk3288_clk_ofdata_to_platdata(struct udevice *dev) { +#if !CONFIG_IS_ENABLED(OF_PLATDATA) struct rk3288_clk_priv *priv = dev_get_priv(dev); priv->cru = (struct rk3288_cru *)dev_get_addr(dev); +#endif return 0; } @@ -800,6 +810,11 @@ static int rk3288_clk_probe(struct udevice *dev) if (IS_ERR(priv->grf)) return PTR_ERR(priv->grf); #ifdef CONFIG_SPL_BUILD +#if CONFIG_IS_ENABLED(OF_PLATDATA) + struct rk3288_clk_plat *plat = dev_get_platdata(dev); + + priv->cru = map_sysmem(plat->dtd.reg[0], plat->dtd.reg[1]); +#endif rkclk_init(priv->cru, priv->grf); #endif @@ -823,11 +838,12 @@ static const struct udevice_id rk3288_clk_ids[] = { { } }; -U_BOOT_DRIVER(clk_rk3288) = { - .name = "clk_rk3288", +U_BOOT_DRIVER(rockchip_rk3288_cru) = { + .name = "rockchip_rk3288_cru", .id = UCLASS_CLK, .of_match = rk3288_clk_ids, .priv_auto_alloc_size = sizeof(struct rk3288_clk_priv), + .platdata_auto_alloc_size = sizeof(struct rk3288_clk_plat), .ops = &rk3288_clk_ops, .bind = rk3288_clk_bind, .ofdata_to_platdata = rk3288_clk_ofdata_to_platdata, From d95b14ffab33713c3058008bac9c05a792d39a17 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Mon, 4 Jul 2016 11:58:30 -0600 Subject: [PATCH 50/62] rockchip: pinctrl: Update the rk3288 driver to support of-platdata Add support for of-platdata with rk3288. This requires disabling access to the device tree and renaming the driver to match the string that of-platdata will search for. Signed-off-by: Simon Glass --- drivers/pinctrl/rockchip/pinctrl_rk3288.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/pinctrl/rockchip/pinctrl_rk3288.c b/drivers/pinctrl/rockchip/pinctrl_rk3288.c index 1fa1daa939..8cb3b8228e 100644 --- a/drivers/pinctrl/rockchip/pinctrl_rk3288.c +++ b/drivers/pinctrl/rockchip/pinctrl_rk3288.c @@ -476,6 +476,7 @@ static int rk3288_pinctrl_request(struct udevice *dev, int func, int flags) static int rk3288_pinctrl_get_periph_id(struct udevice *dev, struct udevice *periph) { +#if !CONFIG_IS_ENABLED(OF_PLATDATA) u32 cell[3]; int ret; @@ -506,6 +507,7 @@ static int rk3288_pinctrl_get_periph_id(struct udevice *dev, case 103: return PERIPH_ID_HDMI; } +#endif return -ENOENT; } @@ -664,8 +666,12 @@ static struct pinctrl_ops rk3288_pinctrl_ops = { static int rk3288_pinctrl_bind(struct udevice *dev) { +#if CONFIG_IS_ENABLED(OF_PLATDATA) + return 0; +#else /* scan child GPIO banks */ return dm_scan_fdt_node(dev, gd->fdt_blob, dev->of_offset, false); +#endif } #ifndef CONFIG_SPL_BUILD @@ -719,7 +725,7 @@ static const struct udevice_id rk3288_pinctrl_ids[] = { }; U_BOOT_DRIVER(pinctrl_rk3288) = { - .name = "pinctrl_rk3288", + .name = "rockchip_rk3288_pinctrl", .id = UCLASS_PINCTRL, .of_match = rk3288_pinctrl_ids, .priv_auto_alloc_size = sizeof(struct rk3288_pinctrl_priv), From 6efeeea79c880d3dd262e0dca9da2687f0ab68c9 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Mon, 4 Jul 2016 11:58:31 -0600 Subject: [PATCH 51/62] rockchip: Move the MMC setup check earlier When the boot ROM sets up MMC we don't need to do it again. Remove the MMC setup code entirely. Signed-off-by: Simon Glass --- arch/arm/mach-rockchip/rk3288-board-spl.c | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/arch/arm/mach-rockchip/rk3288-board-spl.c b/arch/arm/mach-rockchip/rk3288-board-spl.c index 15f1266a7b..d8c9ca71cf 100644 --- a/arch/arm/mach-rockchip/rk3288-board-spl.c +++ b/arch/arm/mach-rockchip/rk3288-board-spl.c @@ -114,7 +114,6 @@ static void configure_l2ctlr(void) #ifdef CONFIG_SPL_MMC_SUPPORT static int configure_emmc(struct udevice *pinctrl) { -#if !defined(CONFIG_TARGET_ROCK2) && !defined(CONFIG_TARGET_FIREFLY_RK3288) struct gpio_desc desc; int ret; @@ -144,7 +143,6 @@ static int configure_emmc(struct udevice *pinctrl) debug("gpio value ret=%d\n", ret); return ret; } -#endif return 0; } @@ -247,15 +245,18 @@ void spl_board_init(void) goto err; } #ifdef CONFIG_SPL_MMC_SUPPORT - ret = pinctrl_request_noflags(pinctrl, PERIPH_ID_SDCARD); - if (ret) { - debug("%s: Failed to set up SD card\n", __func__); - goto err; - } - ret = configure_emmc(pinctrl); - if (ret) { - debug("%s: Failed to set up eMMC\n", __func__); - goto err; + if (!IS_ENABLED(CONFIG_TARGET_ROCK2) && + !IS_ENABLED(CONFIG_TARGET_FIREFLY_RK3288)) { + ret = pinctrl_request_noflags(pinctrl, PERIPH_ID_SDCARD); + if (ret) { + debug("%s: Failed to set up SD card\n", __func__); + goto err; + } + ret = configure_emmc(pinctrl); + if (ret) { + debug("%s: Failed to set up eMMC\n", __func__); + goto err; + } } #endif From 6afc4661e0a2daa655096702171c420518f8c2a8 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Mon, 4 Jul 2016 11:58:32 -0600 Subject: [PATCH 52/62] rockchip: Don't use spl_boot_device() with of-platdata This function cannot look at the device tree when of-platdata is used. Update the code to handle this. Signed-off-by: Simon Glass --- arch/arm/mach-rockchip/rk3288-board-spl.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/arm/mach-rockchip/rk3288-board-spl.c b/arch/arm/mach-rockchip/rk3288-board-spl.c index d8c9ca71cf..123f58b27f 100644 --- a/arch/arm/mach-rockchip/rk3288-board-spl.c +++ b/arch/arm/mach-rockchip/rk3288-board-spl.c @@ -29,6 +29,7 @@ DECLARE_GLOBAL_DATA_PTR; u32 spl_boot_device(void) { +#if !CONFIG_IS_ENABLED(OF_PLATDATA) const void *blob = gd->fdt_blob; struct udevice *dev; const char *bootdev; @@ -63,6 +64,7 @@ u32 spl_boot_device(void) } fallback: +#endif return BOOT_DEVICE_MMC1; } From 5ce4bb2709cea7bde2196ad5f3af11f8f3aa3375 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Mon, 4 Jul 2016 11:58:33 -0600 Subject: [PATCH 53/62] rockchip: syscon: Update to work with of-platdata The syscon devices all end up having diffent driver names with of-platdata, since the driver name comes from the first string in the compatible list. Add separate device declarations for each one, and add a bind method to set up driver_data correctly. Signed-off-by: Simon Glass --- arch/arm/mach-rockchip/rk3288/syscon_rk3288.c | 38 +++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/arch/arm/mach-rockchip/rk3288/syscon_rk3288.c b/arch/arm/mach-rockchip/rk3288/syscon_rk3288.c index c9f7c4e32f..be4b2b00c3 100644 --- a/arch/arm/mach-rockchip/rk3288/syscon_rk3288.c +++ b/arch/arm/mach-rockchip/rk3288/syscon_rk3288.c @@ -23,3 +23,41 @@ U_BOOT_DRIVER(syscon_rk3288) = { .id = UCLASS_SYSCON, .of_match = rk3288_syscon_ids, }; + +#if CONFIG_IS_ENABLED(OF_PLATDATA) +static int rk3288_syscon_bind_of_platdata(struct udevice *dev) +{ + dev->driver_data = dev->driver->of_match->data; + debug("syscon: %s %d\n", dev->name, (uint)dev->driver_data); + + return 0; +} + +U_BOOT_DRIVER(rockchip_rk3288_noc) = { + .name = "rockchip_rk3288_noc", + .id = UCLASS_SYSCON, + .of_match = rk3288_syscon_ids, + .bind = rk3288_syscon_bind_of_platdata, +}; + +U_BOOT_DRIVER(rockchip_rk3288_grf) = { + .name = "rockchip_rk3288_grf", + .id = UCLASS_SYSCON, + .of_match = rk3288_syscon_ids + 1, + .bind = rk3288_syscon_bind_of_platdata, +}; + +U_BOOT_DRIVER(rockchip_rk3288_sgrf) = { + .name = "rockchip_rk3288_sgrf", + .id = UCLASS_SYSCON, + .of_match = rk3288_syscon_ids + 2, + .bind = rk3288_syscon_bind_of_platdata, +}; + +U_BOOT_DRIVER(rockchip_rk3288_pmu) = { + .name = "rockchip_rk3288_pmu", + .id = UCLASS_SYSCON, + .of_match = rk3288_syscon_ids + 3, + .bind = rk3288_syscon_bind_of_platdata, +}; +#endif From fb4baf5d58c212f0b78ac125ee2d7c595b6437e9 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Mon, 4 Jul 2016 11:58:34 -0600 Subject: [PATCH 54/62] rockchip: sdram: Move all DT decoding to ofdata_to_platdata() It is more correct to avoid touching the device tree in the probe() method. Update the driver to work this way. Note that only SPL needs to fiddle with the SDRAM registers, so decoding the platform data fully is not necessary in U-Boot proper. Signed-off-by: Simon Glass --- arch/arm/include/asm/arch-rockchip/sdram.h | 8 -- arch/arm/mach-rockchip/rk3288/sdram_rk3288.c | 96 +++++++++++++------- 2 files changed, 65 insertions(+), 39 deletions(-) diff --git a/arch/arm/include/asm/arch-rockchip/sdram.h b/arch/arm/include/asm/arch-rockchip/sdram.h index c9e3001720..e08e28f4f0 100644 --- a/arch/arm/include/asm/arch-rockchip/sdram.h +++ b/arch/arm/include/asm/arch-rockchip/sdram.h @@ -87,12 +87,4 @@ struct rk3288_base_params { u32 odt; }; -struct rk3288_sdram_params { - struct rk3288_sdram_channel ch[2]; - struct rk3288_sdram_pctl_timing pctl_timing; - struct rk3288_sdram_phy_timing phy_timing; - struct rk3288_base_params base; - int num_channels; -}; - #endif diff --git a/arch/arm/mach-rockchip/rk3288/sdram_rk3288.c b/arch/arm/mach-rockchip/rk3288/sdram_rk3288.c index 55ac73e9d2..940ee58a64 100644 --- a/arch/arm/mach-rockchip/rk3288/sdram_rk3288.c +++ b/arch/arm/mach-rockchip/rk3288/sdram_rk3288.c @@ -41,6 +41,16 @@ struct dram_info { struct rk3288_grf *grf; struct rk3288_sgrf *sgrf; struct rk3288_pmu *pmu; + bool is_veyron; +}; + +struct rk3288_sdram_params { + struct rk3288_sdram_channel ch[2]; + struct rk3288_sdram_pctl_timing pctl_timing; + struct rk3288_sdram_phy_timing phy_timing; + struct rk3288_base_params base; + int num_channels; + struct regmap *map; }; #ifdef CONFIG_SPL_BUILD @@ -703,7 +713,7 @@ static int sdram_init(struct dram_info *dram, return 0; } -#endif +#endif /* CONFIG_SPL_BUILD */ size_t sdram_size_mb(struct rk3288_pmu *pmu) { @@ -779,18 +789,35 @@ static int veyron_init(struct dram_info *priv) static int setup_sdram(struct udevice *dev) { struct dram_info *priv = dev_get_priv(dev); - struct rk3288_sdram_params params; + struct rk3288_sdram_params *params = dev_get_platdata(dev); + +# ifdef CONFIG_ROCKCHIP_FAST_SPL + if (priv->is_veyron) { + int ret; + + ret = veyron_init(priv); + if (ret) + return ret; + } +# endif + + return sdram_init(priv, params); +} + +static int rk3288_dmc_ofdata_to_platdata(struct udevice *dev) +{ + struct rk3288_sdram_params *params = dev_get_platdata(dev); const void *blob = gd->fdt_blob; int node = dev->of_offset; int i, ret; - params.num_channels = fdtdec_get_int(blob, node, - "rockchip,num-channels", 1); - for (i = 0; i < params.num_channels; i++) { + params->num_channels = fdtdec_get_int(blob, node, + "rockchip,num-channels", 1); + for (i = 0; i < params->num_channels; i++) { ret = fdtdec_get_byte_array(blob, node, "rockchip,sdram-channel", - (u8 *)¶ms.ch[i], - sizeof(params.ch[i])); + (u8 *)¶ms->ch[i], + sizeof(params->ch[i])); if (ret) { debug("%s: Cannot read rockchip,sdram-channel\n", __func__); @@ -798,41 +825,44 @@ static int setup_sdram(struct udevice *dev) } } ret = fdtdec_get_int_array(blob, node, "rockchip,pctl-timing", - (u32 *)¶ms.pctl_timing, - sizeof(params.pctl_timing) / sizeof(u32)); + (u32 *)¶ms->pctl_timing, + sizeof(params->pctl_timing) / sizeof(u32)); if (ret) { debug("%s: Cannot read rockchip,pctl-timing\n", __func__); return -EINVAL; } ret = fdtdec_get_int_array(blob, node, "rockchip,phy-timing", - (u32 *)¶ms.phy_timing, - sizeof(params.phy_timing) / sizeof(u32)); + (u32 *)¶ms->phy_timing, + sizeof(params->phy_timing) / sizeof(u32)); if (ret) { debug("%s: Cannot read rockchip,phy-timing\n", __func__); return -EINVAL; } ret = fdtdec_get_int_array(blob, node, "rockchip,sdram-params", - (u32 *)¶ms.base, - sizeof(params.base) / sizeof(u32)); + (u32 *)¶ms->base, + sizeof(params->base) / sizeof(u32)); if (ret) { debug("%s: Cannot read rockchip,sdram-params\n", __func__); return -EINVAL; } +#ifdef CONFIG_ROCKCHIP_FAST_SPL + struct dram_info *priv = dev_get_priv(dev); -# ifdef CONFIG_ROCKCHIP_FAST_SPL - if (!fdt_node_check_compatible(blob, 0, "google,veyron")) { - ret = veyron_init(priv); - if (ret) - return ret; - } -# endif - - return sdram_init(priv, ¶ms); -} + priv->is_veyron = !fdt_node_check_compatible(blob, 0, "google,veyron"); #endif + ret = regmap_init_mem(dev, ¶ms->map); + if (ret) + return ret; + + return 0; +} +#endif /* CONFIG_SPL_BUILD */ static int rk3288_dmc_probe(struct udevice *dev) { +#ifdef CONFIG_SPL_BUILD + struct rk3288_sdram_params *plat = dev_get_platdata(dev); +#endif struct dram_info *priv = dev_get_priv(dev); struct regmap *map; int ret; @@ -849,14 +879,12 @@ static int rk3288_dmc_probe(struct udevice *dev) priv->sgrf = syscon_get_first_range(ROCKCHIP_SYSCON_SGRF); priv->pmu = syscon_get_first_range(ROCKCHIP_SYSCON_PMU); - ret = regmap_init_mem(dev, &map); - if (ret) - return ret; - priv->chan[0].pctl = regmap_get_range(map, 0); - priv->chan[0].publ = regmap_get_range(map, 1); - priv->chan[1].pctl = regmap_get_range(map, 2); - priv->chan[1].publ = regmap_get_range(map, 3); - +#ifdef CONFIG_SPL_BUILD + priv->chan[0].pctl = regmap_get_range(plat->map, 0); + priv->chan[0].publ = regmap_get_range(plat->map, 1); + priv->chan[1].pctl = regmap_get_range(plat->map, 2); + priv->chan[1].publ = regmap_get_range(plat->map, 3); +#endif ret = uclass_get_device(UCLASS_CLK, 0, &dev_clk); if (ret) return ret; @@ -902,6 +930,12 @@ U_BOOT_DRIVER(dmc_rk3288) = { .id = UCLASS_RAM, .of_match = rk3288_dmc_ids, .ops = &rk3288_dmc_ops, +#ifdef CONFIG_SPL_BUILD + .ofdata_to_platdata = rk3288_dmc_ofdata_to_platdata, +#endif .probe = rk3288_dmc_probe, .priv_auto_alloc_size = sizeof(struct dram_info), +#ifdef CONFIG_SPL_BUILD + .platdata_auto_alloc_size = sizeof(struct rk3288_sdram_params), +#endif }; From 086ec0e26d6117f492bad138b4dbee9318ff61bd Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Mon, 4 Jul 2016 11:58:35 -0600 Subject: [PATCH 55/62] rockchip: sdram: Update the driver to support of-platdata Add support for of-platdata with rk3288 SDRAM initr. This requires decoding the of-platdata struct and setting up the device from that. Also the driver needs to be renamed to match the string that of-platdata will search for. The platform data is copied from the of-platdata structure to the one used by the driver. This allows the same code to be used with device tree and of-platdata. Signed-off-by: Simon Glass --- arch/arm/mach-rockchip/rk3288/sdram_rk3288.c | 40 +++++++++++++++++++- 1 file changed, 39 insertions(+), 1 deletion(-) diff --git a/arch/arm/mach-rockchip/rk3288/sdram_rk3288.c b/arch/arm/mach-rockchip/rk3288/sdram_rk3288.c index 940ee58a64..b36b6afcd9 100644 --- a/arch/arm/mach-rockchip/rk3288/sdram_rk3288.c +++ b/arch/arm/mach-rockchip/rk3288/sdram_rk3288.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -45,6 +46,9 @@ struct dram_info { }; struct rk3288_sdram_params { +#if CONFIG_IS_ENABLED(OF_PLATDATA) + struct dtd_rockchip_rk3288_dmc of_plat; +#endif struct rk3288_sdram_channel ch[2]; struct rk3288_sdram_pctl_timing pctl_timing; struct rk3288_sdram_phy_timing phy_timing; @@ -806,6 +810,7 @@ static int setup_sdram(struct udevice *dev) static int rk3288_dmc_ofdata_to_platdata(struct udevice *dev) { +#if !CONFIG_IS_ENABLED(OF_PLATDATA) struct rk3288_sdram_params *params = dev_get_platdata(dev); const void *blob = gd->fdt_blob; int node = dev->of_offset; @@ -853,11 +858,39 @@ static int rk3288_dmc_ofdata_to_platdata(struct udevice *dev) ret = regmap_init_mem(dev, ¶ms->map); if (ret) return ret; +#endif return 0; } #endif /* CONFIG_SPL_BUILD */ +#if CONFIG_IS_ENABLED(OF_PLATDATA) +static int conv_of_platdata(struct udevice *dev) +{ + struct rk3288_sdram_params *plat = dev_get_platdata(dev); + struct dtd_rockchip_rk3288_dmc *of_plat = &plat->of_plat; + int i, ret; + + for (i = 0; i < 2; i++) { + memcpy(&plat->ch[i], of_plat->rockchip_sdram_channel, + sizeof(plat->ch[i])); + } + memcpy(&plat->pctl_timing, of_plat->rockchip_pctl_timing, + sizeof(plat->pctl_timing)); + memcpy(&plat->phy_timing, of_plat->rockchip_phy_timing, + sizeof(plat->phy_timing)); + memcpy(&plat->base, of_plat->rockchip_sdram_params, sizeof(plat->base)); + plat->num_channels = of_plat->rockchip_num_channels; + ret = regmap_init_mem_platdata(dev, of_plat->reg, + ARRAY_SIZE(of_plat->reg) / 2, + &plat->map); + if (ret) + return ret; + + return 0; +} +#endif + static int rk3288_dmc_probe(struct udevice *dev) { #ifdef CONFIG_SPL_BUILD @@ -868,6 +901,11 @@ static int rk3288_dmc_probe(struct udevice *dev) int ret; struct udevice *dev_clk; +#if CONFIG_IS_ENABLED(OF_PLATDATA) + ret = conv_of_platdata(dev); + if (ret) + return ret; +#endif map = syscon_get_regmap_by_driver_data(ROCKCHIP_SYSCON_NOC); if (IS_ERR(map)) return PTR_ERR(map); @@ -926,7 +964,7 @@ static const struct udevice_id rk3288_dmc_ids[] = { }; U_BOOT_DRIVER(dmc_rk3288) = { - .name = "rk3288_dmc", + .name = "rockchip_rk3288_dmc", .id = UCLASS_RAM, .of_match = rk3288_dmc_ids, .ops = &rk3288_dmc_ops, From 97feca3325bb2065a7ef7d30e1f308b74f1fb33c Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Mon, 4 Jul 2016 11:58:36 -0600 Subject: [PATCH 56/62] rockchip: Use of-platdata for firefly-rk3288 As an experiment, move this board over to use of-platdata. This means that its SPL configuration will come from C structures generated at build-time from the device tree, instead of coming from the device tree at run-time. Signed-off-by: Simon Glass --- configs/firefly-rk3288_defconfig | 3 +++ 1 file changed, 3 insertions(+) diff --git a/configs/firefly-rk3288_defconfig b/configs/firefly-rk3288_defconfig index 4af91206dc..bdafc716aa 100644 --- a/configs/firefly-rk3288_defconfig +++ b/configs/firefly-rk3288_defconfig @@ -69,3 +69,6 @@ CONFIG_USE_PRIVATE_LIBGCC=y CONFIG_USE_TINY_PRINTF=y CONFIG_CMD_DHRYSTONE=y CONFIG_ERRNO_STR=y +CONFIG_SPL_OF_PLATDATA=y +# CONFIG_SPL_OF_LIBFDT is not set +CONFIG_ROCKCHIP_SERIAL=y From 2fedbaa4aea4f781863c9b11879ae4d43149c447 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Mon, 4 Jul 2016 11:58:37 -0600 Subject: [PATCH 57/62] test/py: Handle testing with the sandbox_spl board This board can sometimes be used for tests. Handle it the same way as sandbox. Note: I plan to drop the sandbox_spl board at some point and merge its features into sandbox. So this commit may not be necessary. Signed-off-by: Simon Glass --- test/py/conftest.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/py/conftest.py b/test/py/conftest.py index 449f98bee3..050f6e409d 100644 --- a/test/py/conftest.py +++ b/test/py/conftest.py @@ -192,7 +192,7 @@ def pytest_configure(config): for v in env_vars: os.environ['U_BOOT_' + v.upper()] = getattr(ubconfig, v) - if board_type == 'sandbox': + if board_type.startswith('sandbox'): import u_boot_console_sandbox console = u_boot_console_sandbox.ConsoleSandbox(log, ubconfig) else: From c7f636f59d7d506b89d7fc52aa6509329e9ded1b Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Mon, 4 Jul 2016 11:58:38 -0600 Subject: [PATCH 58/62] test/py: Note which console produced unexpected output At present the SPL and U-Boot consoles both present the same error message when the expected console output does not appear. Add "SPL" to the SPL error message to resolve this ambiguity. Signed-off-by: Simon Glass --- test/py/u_boot_console_base.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/py/u_boot_console_base.py b/test/py/u_boot_console_base.py index 815fa64d5f..2dcb2894f9 100644 --- a/test/py/u_boot_console_base.py +++ b/test/py/u_boot_console_base.py @@ -329,7 +329,7 @@ class ConsoleBase(object): m = self.p.expect([pattern_u_boot_spl_signon] + self.bad_patterns) if m != 0: - raise Exception('Bad pattern found on console: ' + + raise Exception('Bad pattern found on SPL console: ' + self.bad_pattern_ids[m - 1]) m = self.p.expect([pattern_u_boot_main_signon] + self.bad_patterns) if m != 0: From ebec58fbcb6da7404b535b9d860546d9baef55c2 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Mon, 4 Jul 2016 11:58:39 -0600 Subject: [PATCH 59/62] test/py: Provide a way to get early console output Some tests want to check the console output from SPL or U-Boot proper. Provide a means to do this. Signed-off-by: Simon Glass --- test/py/u_boot_console_base.py | 10 ++++++++++ test/py/u_boot_spawn.py | 13 +++++++++++++ 2 files changed, 23 insertions(+) diff --git a/test/py/u_boot_console_base.py b/test/py/u_boot_console_base.py index 2dcb2894f9..3d2ac44875 100644 --- a/test/py/u_boot_console_base.py +++ b/test/py/u_boot_console_base.py @@ -377,6 +377,16 @@ class ConsoleBase(object): pass self.p = None + def get_spawn_output(self): + """Return the start-up output from U-Boot + + Returns: + The output produced by ensure_spawed(), as a string. + """ + if self.p: + return self.p.get_expect_output() + return None + def validate_version_string_in_text(self, text): """Assert that a command's output includes the U-Boot signon message. diff --git a/test/py/u_boot_spawn.py b/test/py/u_boot_spawn.py index d15517389e..3a0fbfad90 100644 --- a/test/py/u_boot_spawn.py +++ b/test/py/u_boot_spawn.py @@ -18,6 +18,9 @@ class Timeout(Exception): class Spawn(object): """Represents the stdio of a freshly created sub-process. Commands may be sent to the process, and responses waited for. + + Members: + output: accumulated output from expect() """ def __init__(self, args, cwd=None): @@ -34,6 +37,7 @@ class Spawn(object): self.waited = False self.buf = '' + self.output = '' self.logfile_read = None self.before = '' self.after = '' @@ -154,6 +158,7 @@ class Spawn(object): posafter = earliest_m.end() self.before = self.buf[:pos] self.after = self.buf[pos:posafter] + self.output += self.buf[:posafter] self.buf = self.buf[posafter:] return earliest_pi tnow_s = time.time() @@ -198,3 +203,11 @@ class Spawn(object): if not self.isalive(): break time.sleep(0.1) + + def get_expect_output(self): + """Return the output read by expect() + + Returns: + The output processed by expect(), as a string. + """ + return self.output From a811779b174f8c5c687aaa5574dfdea9f3745f98 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Mon, 4 Jul 2016 11:58:40 -0600 Subject: [PATCH 60/62] test/py: Start sandbox SPL when enabled When sandbox SPL is enabled we want to start that rather than U-Boot proper, since some tests may rely on running it first. Signed-off-by: Simon Glass --- test/py/u_boot_console_sandbox.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/test/py/u_boot_console_sandbox.py b/test/py/u_boot_console_sandbox.py index 04654ae8c9..6bf4653083 100644 --- a/test/py/u_boot_console_sandbox.py +++ b/test/py/u_boot_console_sandbox.py @@ -39,11 +39,15 @@ class ConsoleSandbox(ConsoleBase): A u_boot_spawn.Spawn object that is attached to U-Boot. """ + bcfg = self.config.buildconfig + config_spl = bcfg.get('config_spl', 'n') == 'y' + fname = '/spl/u-boot-spl' if config_spl else '/u-boot' + print fname cmd = [] if self.config.gdbserver: cmd += ['gdbserver', self.config.gdbserver] cmd += [ - self.config.build_dir + '/u-boot', + self.config.build_dir + fname, '-v', '-d', self.config.build_dir + '/arch/sandbox/dts/test.dtb' From b979d3d4c55def30cd0eb1e2c82beefb30fc8e87 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Mon, 4 Jul 2016 11:58:41 -0600 Subject: [PATCH 61/62] dm: Add a test for of-platdata Add a simple test which checks that the of-platdata system is working correctly. The sequence is as follows: - SPL starts up and probes all the UCLASS_MISC drivers - There are 3 of these in sandbox.dts - Therefore there should be 3 U_BOOT_DEVICE() declarations in dt-platdata.c - These should produce 3 sandbox_spl_test devices - Each device prints out its platform data when probed - This test checks for this output and compares it against expectations Signed-off-by: Simon Glass --- test/py/tests/test_ofplatdata.py | 42 ++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100644 test/py/tests/test_ofplatdata.py diff --git a/test/py/tests/test_ofplatdata.py b/test/py/tests/test_ofplatdata.py new file mode 100644 index 0000000000..c8b309e3d2 --- /dev/null +++ b/test/py/tests/test_ofplatdata.py @@ -0,0 +1,42 @@ +# Copyright (c) 2016 Google, Inc +# +# SPDX-License-Identifier: GPL-2.0+ + +import pytest + +OF_PLATDATA_OUTPUT = ''' +of-platdata probe: +bool 1 +byte 05 +bytearray 06 00 00 +int 1 +intarray 2 3 4 0 +longbytearray 09 0a 0b 0c 0d 0e 0f 10 11 +string message +stringarray "multi-word" "message" "" +of-platdata probe: +bool 0 +byte 08 +bytearray 01 23 34 +int 3 +intarray 5 0 0 0 +longbytearray 09 00 00 00 00 00 00 00 00 +string message2 +stringarray "another" "multi-word" "message" +of-platdata probe: +bool 0 +byte 00 +bytearray 00 00 00 +int 0 +intarray 0 0 0 0 +longbytearray 00 00 00 00 00 00 00 00 00 +string +stringarray "one" "" "" +''' + +@pytest.mark.buildconfigspec('spl') +def test_ofplatdata(u_boot_console): + """Test that of-platdata can be generated and used in sandbox""" + cons = u_boot_console + output = cons.get_spawn_output().replace('\r', '') + assert OF_PLATDATA_OUTPUT in output From 1269625177f120d659f66b18de4b532b16c44561 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Mon, 4 Jul 2016 11:58:42 -0600 Subject: [PATCH 62/62] dm: Update the of-platdata README for the new features Revise the content based on the v2 additions. This is kept as a separate patch to avoid confusing those who have already reviewed the v1 series. Signed-off-by: Simon Glass Suggested-by: Tom Rini --- doc/driver-model/of-plat.txt | 110 ++++++++++++++++++++++++----------- 1 file changed, 76 insertions(+), 34 deletions(-) diff --git a/doc/driver-model/of-plat.txt b/doc/driver-model/of-plat.txt index 96b9b4642c..86e5e25300 100644 --- a/doc/driver-model/of-plat.txt +++ b/doc/driver-model/of-plat.txt @@ -19,24 +19,28 @@ 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. +for it, and reference that data in a U_BOOT_DEVICE() declaration. This +bypasses the use of device tree completely, effectively creating a parallel +configuration mechanism. But it is an available option for SPL. -As an alternative, a new 'of-platdata' feature is provided. This converts +As an alternative, a new 'of-platdata' feature is provided. This converts the 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. +Note: Quite a bit of thought has gone into the design of this feature. +However it still has many rough edges and comments and suggestions are +strongly encouraged! Quite possibly there is a much better approach. + Caveats ------- There are many problems with this features. It should only be used when -stricly necessary. Notable problems include: +strictly 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 + - Device tree does not describe data types. But the C code must define a + type for each property. These 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 @@ -45,14 +49,15 @@ stricly necessary. Notable problems include: - 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 + 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. + a different C struct name, and a likely a different 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 @@ -112,7 +117,6 @@ struct dtd_rockchip_rk3288_dw_mshc { fdt32_t interrupts[3]; fdt32_t num_slots; fdt32_t reg[2]; - bool u_boot_dm_pre_reloc; fdt32_t vmmc_supply; }; @@ -125,7 +129,10 @@ static struct dtd_rockchip_rk3288_dw_mshc dtv_dwmmc_at_ff0c0000 = { .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}}, + .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, @@ -136,6 +143,7 @@ static struct dtd_rockchip_rk3288_dw_mshc dtv_dwmmc_at_ff0c0000 = { U_BOOT_DEVICE(dwmmc_at_ff0c0000) = { .name = "rockchip_rk3288_dw_mshc", .platdata = &dtv_dwmmc_at_ff0c0000, + .platdata_size = sizeof(dtv_dwmmc_at_ff0c0000), }; The device is then instantiated at run-time and the platform data can be @@ -149,15 +157,31 @@ platform data in the driver. The ofdata_to_platdata() method should therefore do nothing in such a driver. +Converting of-platdata to a useful form +--------------------------------------- + +Of course it would be possible use the of-platdata directly in your driver +whenever configuration information is required. However this meands that the +driver will not be able to support device tree, since the of-platdata +structure is not available when device tree is used. It would make no sense +to use this structure if device tree were available, since the structure has +all the limitations metioned in caveats above. + +Therefore it is recommended that the of-platdata structure should be used +only in the probe() method of your driver. It cannot be used in the +ofdata_to_platdata() method since this is not called when platform data is +already present. + + 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. +Your driver should convert the platdata struct in its probe() method. The +existing device tree decoding logic should be kept in the +ofdata_to_platdata() method and wrapped with #if. For example: @@ -165,13 +189,12 @@ For example: struct mmc_platdata { #if CONFIG_IS_ENABLED(SPL_OF_PLATDATA) - /* Put this first */ + /* Put this first since driver model will copy the data here */ 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. + * the device tree (or the C structures when of-platdata is used). */ int fifo_depth; }; @@ -179,6 +202,7 @@ For example: static int mmc_ofdata_to_platdata(struct udevice *dev) { #if !CONFIG_IS_ENABLED(SPL_OF_PLATDATA) + /* Decode the device tree data */ struct mmc_platdata *plat = dev_get_platdata(dev); const void *blob = gd->fdt_blob; int node = dev->of_offset; @@ -192,15 +216,15 @@ For example: static int mmc_probe(struct udevice *dev) { struct mmc_platdata *plat = dev_get_platdata(dev); + #if CONFIG_IS_ENABLED(SPL_OF_PLATDATA) + /* Decode the of-platdata from the C structures */ struct dtd_mmc *dtplat = &plat->dtplat; - /* Set up the device from the dtplat data */ - writel(dtplat->fifo_depth, ...) - #else + plat->fifo_depth = dtplat->fifo_depth; + #endif /* Set up the device from the plat data */ writel(plat->fifo_depth, ...) - #endif } static const struct udevice_id mmc_ids[] = { @@ -220,15 +244,26 @@ For example: 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. +still used to allocate space for the platform data. This is different from +the normal behaviour and is triggered by the use of of-platdata (strictly +speaking it is a non-zero platdata_size which triggers this). + +The of-platdata struct contents is copied from the C structure data to the +start of the newly allocated area. 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 still set up the platform data (and the +of-platdata struct will not be present). + +SPL must use either of-platdata or device tree. Drivers cannot use both at +the same time, but they must support device tree. Supporting of-platdata is +optional. -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. - +since the device-tree access code is not compiled in. A corollary is that +a board can only move to using of-platdata if all the drivers it uses support +it. There would be little point in having some drivers require the device +tree data, since then libfdt would still be needed for those drivers and +there would be no code-size benefit. Internals --------- @@ -236,7 +271,8 @@ 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. +prevents them being used inadvertently. All usage must be bracketed with +#if CONFIG_IS_ENABLED(SPL_OF_PLATDATA). The dt-platdata.c file contains the device declarations and is is built in spl/dt-platdata.c. @@ -249,20 +285,26 @@ yet implemented, however. The beginnings of a libfdt Python module are provided. So far this only implements a subset of the features. -The 'swig' tool is needed to build the libfdt Python module. +The 'swig' tool is needed to build the libfdt Python module. If this is not +found then the Python model is not used and a fallback is used instead, which +makes use of fdtget. + + +Credits +------- + +This is an implementation of an idea by Tom Rini . 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 +Google, Inc 6/6/16 +Updated Independence Day 2016