diff options
153 files changed, 4643 insertions, 825 deletions
@@ -114,6 +114,15 @@ if EXPERT Warning: When disabling this, please check if malloc calls, maybe should be replaced by calloc - if one expects zeroed memory. + +config TOOLS_DEBUG + bool "Enable debug information for tools" + help + Enable generation of debug information for tools such as mkimage. + This can be used for debugging purposes. With debug information + it is possible to set breakpoints on particular lines, single-step + debug through the source code, etc. + endif endmenu # General setup @@ -313,6 +322,20 @@ config SPL_LOAD_FIT particular it can handle selecting from multiple device tree and passing the correct one to U-Boot. +config SPL_FIT_IMAGE_POST_PROCESS + bool "Enable post-processing of FIT artifacts after loading by the SPL" + depends on SPL_LOAD_FIT && TI_SECURE_DEVICE + help + Allows doing any sort of manipulation to blobs after they got extracted + from the U-Boot FIT image like stripping off headers or modifying the + size of the blob, verification, authentication, decryption etc. in a + platform or board specific way. In order to use this feature a platform + or board-specific implementation of board_fit_image_post_process() must + be provided. Also, anything done during this post-processing step would + need to be comprehended in how the images were prepared before being + injected into the FIT creation (i.e. the blobs would have been pre- + processed before being added to the FIT image). + config SYS_CLK_FREQ depends on ARC || ARCH_SUNXI int "CPU clock frequency" @@ -256,7 +256,8 @@ CONFIG_SHELL := $(shell if [ -x "$$BASH" ]; then echo $$BASH; \ HOSTCC = cc HOSTCXX = c++ -HOSTCFLAGS = -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer +HOSTCFLAGS = -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer \ + $(if $(CONFIG_TOOLS_DEBUG),-g) HOSTCXXFLAGS = -O2 ifeq ($(HOSTOS),cygwin) @@ -801,7 +802,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)" @@ -1318,7 +1319,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 @@ -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 diff --git a/arch/Kconfig b/arch/Kconfig index c43787c..92d4b97 100644 --- a/arch/Kconfig +++ b/arch/Kconfig @@ -1,6 +1,9 @@ config CREATE_ARCH_SYMLINK bool +config HAVE_ARCH_IOREMAP + bool + choice prompt "Architecture select" default SANDBOX @@ -33,6 +36,7 @@ config MICROBLAZE config MIPS bool "MIPS architecture" + select HAVE_ARCH_IOREMAP select HAVE_PRIVATE_LIBGCC select SUPPORT_OF_CONTROL diff --git a/arch/arm/cpu/arm11/cpu.c b/arch/arm/cpu/arm11/cpu.c index 1e4c214..7244c2e 100644 --- a/arch/arm/cpu/arm11/cpu.c +++ b/arch/arm/cpu/arm11/cpu.c @@ -69,23 +69,6 @@ void flush_dcache_all(void) asm volatile("mcr p15, 0, %0, c7, c10, 4" : : "r" (0)); } -static int check_cache_range(unsigned long start, unsigned long stop) -{ - int ok = 1; - - if (start & (CONFIG_SYS_CACHELINE_SIZE - 1)) - ok = 0; - - if (stop & (CONFIG_SYS_CACHELINE_SIZE - 1)) - ok = 0; - - if (!ok) - debug("CACHE: Misaligned operation at range [%08lx, %08lx]\n", - start, stop); - - return ok; -} - void invalidate_dcache_range(unsigned long start, unsigned long stop) { if (!check_cache_range(start, stop)) diff --git a/arch/arm/cpu/arm926ejs/cache.c b/arch/arm/cpu/arm926ejs/cache.c index 2839c86..2119382 100644 --- a/arch/arm/cpu/arm926ejs/cache.c +++ b/arch/arm/cpu/arm926ejs/cache.c @@ -29,23 +29,6 @@ void flush_dcache_all(void) ); } -static int check_cache_range(unsigned long start, unsigned long stop) -{ - int ok = 1; - - if (start & (CONFIG_SYS_CACHELINE_SIZE - 1)) - ok = 0; - - if (stop & (CONFIG_SYS_CACHELINE_SIZE - 1)) - ok = 0; - - if (!ok) - debug("CACHE: Misaligned operation at range [%08lx, %08lx]\n", - start, stop); - - return ok; -} - void invalidate_dcache_range(unsigned long start, unsigned long stop) { if (!check_cache_range(start, stop)) diff --git a/arch/arm/cpu/armv7/am33xx/config.mk b/arch/arm/cpu/armv7/am33xx/config.mk index 6d95d32..ab94708 100644 --- a/arch/arm/cpu/armv7/am33xx/config.mk +++ b/arch/arm/cpu/armv7/am33xx/config.mk @@ -26,6 +26,7 @@ endif else ifeq ($(CONFIG_TI_SECURE_DEVICE),y) ALL-$(CONFIG_QSPI_BOOT) += u-boot_HS_XIP_X-LOADER +ALL-y += u-boot_HS.img endif ALL-y += u-boot.img endif diff --git a/arch/arm/cpu/armv7/cache_v7.c b/arch/arm/cpu/armv7/cache_v7.c index dc309da..52f1856 100644 --- a/arch/arm/cpu/armv7/cache_v7.c +++ b/arch/arm/cpu/armv7/cache_v7.c @@ -19,23 +19,6 @@ void v7_flush_dcache_all(void); void v7_invalidate_dcache_all(void); -static int check_cache_range(unsigned long start, unsigned long stop) -{ - int ok = 1; - - if (start & (CONFIG_SYS_CACHELINE_SIZE - 1)) - ok = 0; - - if (stop & (CONFIG_SYS_CACHELINE_SIZE - 1)) - ok = 0; - - if (!ok) - debug("CACHE: Misaligned operation at range [%08lx, %08lx]\n", - start, stop); - - return ok; -} - static u32 get_ccsidr(void) { u32 ccsidr; @@ -61,27 +44,8 @@ static void v7_dcache_inval_range(u32 start, u32 stop, u32 line_len) { u32 mva; - /* - * If start address is not aligned to cache-line do not - * invalidate the first cache-line - */ - if (start & (line_len - 1)) { - printf("ERROR: %s - start address is not aligned - 0x%08x\n", - __func__, start); - /* move to next cache line */ - start = (start + line_len - 1) & ~(line_len - 1); - } - - /* - * If stop address is not aligned to cache-line do not - * invalidate the last cache-line - */ - if (stop & (line_len - 1)) { - printf("ERROR: %s - stop address is not aligned - 0x%08x\n", - __func__, stop); - /* align to the beginning of this cache line */ - stop &= ~(line_len - 1); - } + if (!check_cache_range(start, stop)) + return; for (mva = start; mva < stop; mva = mva + line_len) { /* DCIMVAC - Invalidate data cache by MVA to PoC */ @@ -195,6 +159,14 @@ void flush_dcache_all(void) { } +void invalidate_dcache_range(unsigned long start, unsigned long stop) +{ +} + +void flush_dcache_range(unsigned long start, unsigned long stop) +{ +} + void arm_init_before_mmu(void) { } diff --git a/arch/arm/cpu/armv7/omap-common/Makefile b/arch/arm/cpu/armv7/omap-common/Makefile index 87a7ac0..3172bae 100644 --- a/arch/arm/cpu/armv7/omap-common/Makefile +++ b/arch/arm/cpu/armv7/omap-common/Makefile @@ -36,3 +36,5 @@ obj-y += boot-common.o obj-y += lowlevel_init.o obj-y += mem-common.o + +obj-$(CONFIG_TI_SECURE_DEVICE) += sec-common.o diff --git a/arch/arm/cpu/armv7/omap-common/config_secure.mk b/arch/arm/cpu/armv7/omap-common/config_secure.mk index c7bb101..1122439 100644 --- a/arch/arm/cpu/armv7/omap-common/config_secure.mk +++ b/arch/arm/cpu/armv7/omap-common/config_secure.mk @@ -12,8 +12,8 @@ cmd_mkomapsecimg = $(TI_SECURE_DEV_PKG)/scripts/create-boot-image.sh \ $(if $(KBUILD_VERBOSE:1=), >/dev/null) else cmd_mkomapsecimg = $(TI_SECURE_DEV_PKG)/scripts/create-boot-image.sh \ - $(patsubst u-boot_HS_%,%,$(@F)) $< $@ $(CONFIG_ISW_ENTRY_ADDR) \ - $(if $(KBUILD_VERBOSE:1=), >/dev/null) + $(patsubst u-boot_HS_%,%,$(@F)) $< $@ $(CONFIG_ISW_ENTRY_ADDR) \ + $(if $(KBUILD_VERBOSE:1=), >/dev/null) endif else cmd_mkomapsecimg = echo "WARNING:" \ @@ -25,14 +25,33 @@ cmd_mkomapsecimg = echo "WARNING: TI_SECURE_DEV_PKG environment" \ "variable must be defined for TI secure devices. $@ was NOT created!" endif +ifdef CONFIG_SPL_LOAD_FIT +quiet_cmd_omapsecureimg = SECURE $@ +ifneq ($(TI_SECURE_DEV_PKG),) +ifneq ($(wildcard $(TI_SECURE_DEV_PKG)/scripts/secure-binary-image.sh),) +cmd_omapsecureimg = $(TI_SECURE_DEV_PKG)/scripts/secure-binary-image.sh \ + $< $@ \ + $(if $(KBUILD_VERBOSE:1=), >/dev/null) +else +cmd_omapsecureimg = echo "WARNING:" \ + "$(TI_SECURE_DEV_PKG)/scripts/secure-binary-image.sh not found." \ + "$@ was NOT created!"; cp $< $@ +endif +else +cmd_omapsecureimg = echo "WARNING: TI_SECURE_DEV_PKG environment" \ + "variable must be defined for TI secure devices." \ + "$@ was NOT created!"; cp $< $@ +endif +endif + + # Standard X-LOADER target (QPSI, NOR flash) u-boot-spl_HS_X-LOADER: $(obj)/u-boot-spl.bin $(call if_changed,mkomapsecimg) -# For MLO targets (SD card boot) the final file name -# that is copied to the SD card fAT partition must -# be MLO, so we make a copy of the output file to a -# new file with that name +# For MLO targets (SD card boot) the final file name that is copied to the SD +# card FAT partition must be MLO, so we make a copy of the output file to a new +# file with that name u-boot-spl_HS_MLO: $(obj)/u-boot-spl.bin $(call if_changed,mkomapsecimg) @if [ -f $@ ]; then \ @@ -51,16 +70,44 @@ u-boot-spl_HS_ULO: $(obj)/u-boot-spl.bin u-boot-spl_HS_ISSW: $(obj)/u-boot-spl.bin $(call if_changed,mkomapsecimg) -# For SPI flash on AM335x and AM43xx, these -# require special byte swap handling so we use -# the SPI_X-LOADER target instead of X-LOADER -# and let the create-boot-image.sh script handle -# that +# For SPI flash on AM335x and AM43xx, these require special byte swap handling +# so we use the SPI_X-LOADER target instead of X-LOADER and let the +# create-boot-image.sh script handle that u-boot-spl_HS_SPI_X-LOADER: $(obj)/u-boot-spl.bin $(call if_changed,mkomapsecimg) -# For supporting single stage XiP QSPI on AM43xx, the -# image is a full u-boot file, not an SPL. In this case -# the mkomapsecimg command looks for a u-boot-HS_* prefix +# For supporting single stage XiP QSPI on AM43xx, the image is a full u-boot +# file, not an SPL. In this case the mkomapsecimg command looks for a +# u-boot-HS_* prefix u-boot_HS_XIP_X-LOADER: $(obj)/u-boot.bin $(call if_changed,mkomapsecimg) + +# For supporting the SPL loading and interpreting of FIT images whose +# components are pre-processed before being integrated into the FIT image in +# order to secure them in some way +ifdef CONFIG_SPL_LOAD_FIT + +MKIMAGEFLAGS_u-boot_HS.img = -f auto -A $(ARCH) -T firmware -C none -O u-boot \ + -a $(CONFIG_SYS_TEXT_BASE) -e $(CONFIG_SYS_UBOOT_START) \ + -n "U-Boot $(UBOOTRELEASE) for $(BOARD) board" -E \ + $(patsubst %,-b arch/$(ARCH)/dts/%.dtb,$(subst ",,$(CONFIG_OF_LIST))) + +OF_LIST_TARGETS = $(patsubst %,arch/$(ARCH)/dts/%.dtb,$(subst ",,$(CONFIG_OF_LIST))) +$(OF_LIST_TARGETS): dtbs + +%_HS.dtb: %.dtb + $(call if_changed,omapsecureimg) + $(Q)if [ -f $@ ]; then \ + cp -f $@ $<; \ + fi + +u-boot-nodtb_HS.bin: u-boot-nodtb.bin + $(call if_changed,omapsecureimg) + +u-boot_HS.img: u-boot-nodtb_HS.bin u-boot.img $(patsubst %.dtb,%_HS.dtb,$(OF_LIST_TARGETS)) + $(call if_changed,mkimage) + $(Q)if [ -f $@ ]; then \ + cp -f $@ u-boot.img; \ + fi + +endif diff --git a/arch/arm/cpu/armv7/omap-common/emif-common.c b/arch/arm/cpu/armv7/omap-common/emif-common.c index 9a9c764..2b79010 100644 --- a/arch/arm/cpu/armv7/omap-common/emif-common.c +++ b/arch/arm/cpu/armv7/omap-common/emif-common.c @@ -37,7 +37,8 @@ void set_lpmode_selfrefresh(u32 base) void force_emif_self_refresh() { set_lpmode_selfrefresh(EMIF1_BASE); - set_lpmode_selfrefresh(EMIF2_BASE); + if (!is_dra72x()) + set_lpmode_selfrefresh(EMIF2_BASE); } inline u32 emif_num(u32 base) diff --git a/arch/arm/cpu/armv7/omap-common/hwinit-common.c b/arch/arm/cpu/armv7/omap-common/hwinit-common.c index 2f9693f..f317293 100644 --- a/arch/arm/cpu/armv7/omap-common/hwinit-common.c +++ b/arch/arm/cpu/armv7/omap-common/hwinit-common.c @@ -147,8 +147,7 @@ void early_system_init(void) hw_data_init(); #ifdef CONFIG_SPL_BUILD - if (warm_reset() && - (is_omap44xx() || (omap_revision() == OMAP5430_ES1_0))) + if (warm_reset()) force_emif_self_refresh(); #endif watchdog_init(); diff --git a/arch/arm/cpu/armv7/omap-common/lowlevel_init.S b/arch/arm/cpu/armv7/omap-common/lowlevel_init.S index 5283135..66a3b3d 100644 --- a/arch/arm/cpu/armv7/omap-common/lowlevel_init.S +++ b/arch/arm/cpu/armv7/omap-common/lowlevel_init.S @@ -16,9 +16,10 @@ #include <asm/arch/spl.h> #include <linux/linkage.h> +.arch_extension sec + #ifdef CONFIG_SPL ENTRY(save_boot_params) - ldr r1, =OMAP_SRAM_SCRATCH_BOOT_PARAMS str r0, [r1] b save_boot_params_ret @@ -26,14 +27,40 @@ ENDPROC(save_boot_params) #endif ENTRY(omap_smc1) - PUSH {r4-r12, lr} @ save registers - ROM code may pollute + push {r4-r12, lr} @ save registers - ROM code may pollute @ our registers - MOV r12, r0 @ Service - MOV r0, r1 @ Argument - DSB - DMB - .word 0xe1600070 @ SMC #0 - hand assembled for GCC versions - @ call ROM Code API for the service requested + mov r12, r0 @ Service + mov r0, r1 @ Argument - POP {r4-r12, pc} + dsb + dmb + smc 0 @ SMC #0 to enter monitor mode + @ call ROM Code API for the service requested + pop {r4-r12, pc} ENDPROC(omap_smc1) + +ENTRY(omap_smc_sec) + push {r4-r12, lr} @ save registers - ROM code may pollute + @ our registers + mov r6, #0xFF @ Indicate new Task call + mov r12, #0x00 @ Secure Service ID in R12 + + dsb + dmb + smc 0 @ SMC #0 to enter monitor mode + + b omap_smc_sec_end @ exit at end of the service execution + nop + + @ In case of IRQ happening in Secure, then ARM will branch here. + @ At that moment, IRQ will be pending and ARM will jump to Non Secure + @ IRQ handler + mov r12, #0xFE + + dsb + dmb + smc 0 @ SMC #0 to enter monitor mode + +omap_smc_sec_end: + pop {r4-r12, pc} +ENDPROC(omap_smc_sec) diff --git a/arch/arm/cpu/armv7/omap-common/sec-common.c b/arch/arm/cpu/armv7/omap-common/sec-common.c new file mode 100644 index 0000000..246a239 --- /dev/null +++ b/arch/arm/cpu/armv7/omap-common/sec-common.c @@ -0,0 +1,139 @@ +/* + * + * Common security related functions for OMAP devices + * + * (C) Copyright 2016 + * Texas Instruments, <www.ti.com> + * + * Daniel Allred <d-allred@ti.com> + * Andreas Dannenberg <dannenberg@ti.com> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <stdarg.h> + +#include <asm/arch/sys_proto.h> +#include <asm/omap_common.h> +#include <asm/omap_sec_common.h> +#include <asm/spl.h> +#include <spl.h> + +/* Index for signature verify ROM API */ +#define API_HAL_KM_VERIFYCERTIFICATESIGNATURE_INDEX (0x0000000E) + +static uint32_t secure_rom_call_args[5] __aligned(ARCH_DMA_MINALIGN); + +u32 secure_rom_call(u32 service, u32 proc_id, u32 flag, ...) +{ + int i; + u32 num_args; + va_list ap; + + va_start(ap, flag); + + num_args = va_arg(ap, u32); + + if (num_args > 4) + return 1; + + /* Copy args to aligned args structure */ + for (i = 0; i < num_args; i++) + secure_rom_call_args[i + 1] = va_arg(ap, u32); + + secure_rom_call_args[0] = num_args; + + va_end(ap); + + /* if data cache is enabled, flush the aligned args structure */ + flush_dcache_range( + (unsigned int)&secure_rom_call_args[0], + (unsigned int)&secure_rom_call_args[0] + + roundup(sizeof(secure_rom_call_args), ARCH_DMA_MINALIGN)); + + return omap_smc_sec(service, proc_id, flag, secure_rom_call_args); +} + +static u32 find_sig_start(char *image, size_t size) +{ + char *image_end = image + size; + char *sig_start_magic = "CERT_"; + int magic_str_len = strlen(sig_start_magic); + char *ch; + + while (--image_end > image) { + if (*image_end == '_') { + ch = image_end - magic_str_len + 1; + if (!strncmp(ch, sig_start_magic, magic_str_len)) + return (u32)ch; + } + } + return 0; +} + +int secure_boot_verify_image(void **image, size_t *size) +{ + int result = 1; + u32 cert_addr, sig_addr; + size_t cert_size; + + /* Perform cache writeback on input buffer */ + flush_dcache_range( + (u32)*image, + (u32)*image + roundup(*size, ARCH_DMA_MINALIGN)); + + cert_addr = (uint32_t)*image; + sig_addr = find_sig_start((char *)*image, *size); + + if (sig_addr == 0) { + printf("No signature found in image!\n"); + result = 1; + goto auth_exit; + } + + *size = sig_addr - cert_addr; /* Subtract out the signature size */ + cert_size = *size; + + /* Check if image load address is 32-bit aligned */ + if (!IS_ALIGNED(cert_addr, 4)) { + printf("Image is not 4-byte aligned!\n"); + result = 1; + goto auth_exit; + } + + /* Image size also should be multiple of 4 */ + if (!IS_ALIGNED(cert_size, 4)) { + printf("Image size is not 4-byte aligned!\n"); + result = 1; + goto auth_exit; + } + + /* Call ROM HAL API to verify certificate signature */ + debug("%s: load_addr = %x, size = %x, sig_addr = %x\n", __func__, + cert_addr, cert_size, sig_addr); + + result = secure_rom_call( + API_HAL_KM_VERIFYCERTIFICATESIGNATURE_INDEX, 0, 0, + 4, cert_addr, cert_size, sig_addr, 0xFFFFFFFF); +auth_exit: + if (result != 0) { + printf("Authentication failed!\n"); + printf("Return Value = %08X\n", result); + hang(); + } + + /* + * Output notification of successful authentication as well the name of + * the signing certificate used to re-assure the user that the secure + * code is being processed as expected. However suppress any such log + * output in case of building for SPL and booting via YMODEM. This is + * done to avoid disturbing the YMODEM serial protocol transactions. + */ + if (!(IS_ENABLED(CONFIG_SPL_BUILD) && + IS_ENABLED(CONFIG_SPL_YMODEM_SUPPORT) && + spl_boot_device() == BOOT_DEVICE_UART)) + printf("Authentication passed: %s\n", (char *)sig_addr); + + return result; +} diff --git a/arch/arm/cpu/armv7/omap5/config.mk b/arch/arm/cpu/armv7/omap5/config.mk index a7e55a5..d245572 100644 --- a/arch/arm/cpu/armv7/omap5/config.mk +++ b/arch/arm/cpu/armv7/omap5/config.mk @@ -15,5 +15,8 @@ else ALL-y += MLO endif else +ifeq ($(CONFIG_TI_SECURE_DEVICE),y) +ALL-y += u-boot_HS.img +endif ALL-y += u-boot.img endif diff --git a/arch/arm/cpu/armv7m/config.mk b/arch/arm/cpu/armv7m/config.mk index 4a53006..db4660e 100644 --- a/arch/arm/cpu/armv7m/config.mk +++ b/arch/arm/cpu/armv7m/config.mk @@ -5,4 +5,4 @@ # SPDX-License-Identifier: GPL-2.0+ # -PLATFORM_CPPFLAGS += -march=armv7-m -mthumb +PLATFORM_CPPFLAGS += -march=armv7-m -mthumb -mno-unaligned-access diff --git a/arch/arm/cpu/armv8/Kconfig b/arch/arm/cpu/armv8/Kconfig index 3d19bbf..acf2460 100644 --- a/arch/arm/cpu/armv8/Kconfig +++ b/arch/arm/cpu/armv8/Kconfig @@ -3,4 +3,22 @@ if ARM64 config ARMV8_MULTIENTRY boolean "Enable multiple CPUs to enter into U-Boot" +config ARMV8_SPIN_TABLE + bool "Support spin-table enable method" + depends on ARMV8_MULTIENTRY && OF_LIBFDT + help + Say Y here to support "spin-table" enable method for booting Linux. + + To use this feature, you must do: + - Specify enable-method = "spin-table" in each CPU node in the + Device Tree you are using to boot the kernel + - Let secondary CPUs in U-Boot (in a board specific manner) + before the master CPU jumps to the kernel + + U-Boot automatically does: + - Set "cpu-release-addr" property of each CPU node + (overwrites it if already exists). + - Reserve the code for the spin-table and the release address + via a /memreserve/ region in the Device Tree. + endif diff --git a/arch/arm/cpu/armv8/Makefile b/arch/arm/cpu/armv8/Makefile index bf8644c..f6eb9f4 100644 --- a/arch/arm/cpu/armv8/Makefile +++ b/arch/arm/cpu/armv8/Makefile @@ -15,6 +15,9 @@ obj-y += cache.o obj-y += tlb.o obj-y += transition.o obj-y += fwcall.o +ifndef CONFIG_SPL_BUILD +obj-$(CONFIG_ARMV8_SPIN_TABLE) += spin_table.o spin_table_v8.o +endif obj-$(CONFIG_FSL_LAYERSCAPE) += fsl-layerscape/ obj-$(CONFIG_S32V234) += s32v234/ diff --git a/arch/arm/cpu/armv8/spin_table.c b/arch/arm/cpu/armv8/spin_table.c new file mode 100644 index 0000000..ec1c9b8 --- /dev/null +++ b/arch/arm/cpu/armv8/spin_table.c @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2016 Socionext Inc. + * Author: Masahiro Yamada <yamada.masahiro@socionext.com> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <libfdt.h> +#include <asm/spin_table.h> + +int spin_table_update_dt(void *fdt) +{ + int cpus_offset, offset; + const char *prop; + int ret; + unsigned long rsv_addr = (unsigned long)&spin_table_reserve_begin; + unsigned long rsv_size = &spin_table_reserve_end - + &spin_table_reserve_begin; + + cpus_offset = fdt_path_offset(fdt, "/cpus"); + if (cpus_offset < 0) + return -ENODEV; + + for (offset = fdt_first_subnode(fdt, cpus_offset); + offset >= 0; + offset = fdt_next_subnode(fdt, offset)) { + prop = fdt_getprop(fdt, offset, "device_type", NULL); + if (!prop || strcmp(prop, "cpu")) + continue; + + /* + * In the first loop, we check if every CPU node specifies + * spin-table. Otherwise, just return successfully to not + * disturb other methods, like psci. + */ + prop = fdt_getprop(fdt, offset, "enable-method", NULL); + if (!prop || strcmp(prop, "spin-table")) + return 0; + } + + for (offset = fdt_first_subnode(fdt, cpus_offset); + offset >= 0; + offset = fdt_next_subnode(fdt, offset)) { + prop = fdt_getprop(fdt, offset, "device_type", NULL); + if (!prop || strcmp(prop, "cpu")) + continue; + + ret = fdt_setprop_u64(fdt, offset, "cpu-release-addr", + (unsigned long)&spin_table_cpu_release_addr); + if (ret) + return -ENOSPC; + } + + ret = fdt_add_mem_rsv(fdt, rsv_addr, rsv_size); + if (ret) + return -ENOSPC; + + printf(" Reserved memory region for spin-table: addr=%lx size=%lx\n", + rsv_addr, rsv_size); + + return 0; +} diff --git a/arch/arm/cpu/armv8/spin_table_v8.S b/arch/arm/cpu/armv8/spin_table_v8.S new file mode 100644 index 0000000..d7f78a6 --- /dev/null +++ b/arch/arm/cpu/armv8/spin_table_v8.S @@ -0,0 +1,23 @@ +/* + * Copyright (C) 2016 Socionext Inc. + * Author: Masahiro Yamada <yamada.masahiro@socionext.com> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <linux/linkage.h> + +ENTRY(spin_table_secondary_jump) +.globl spin_table_reserve_begin +spin_table_reserve_begin: +0: wfe + ldr x0, spin_table_cpu_release_addr + cbz x0, 0b + br x0 +.globl spin_table_cpu_release_addr + .align 3 +spin_table_cpu_release_addr: + .quad 0 +.globl spin_table_reserve_end +spin_table_reserve_end: +ENDPROC(spin_table_secondary_jump) diff --git a/arch/arm/cpu/armv8/start.S b/arch/arm/cpu/armv8/start.S index 670e323..67edf94 100644 --- a/arch/arm/cpu/armv8/start.S +++ b/arch/arm/cpu/armv8/start.S @@ -94,7 +94,11 @@ reset: /* Processor specific initialization */ bl lowlevel_init -#ifdef CONFIG_ARMV8_MULTIENTRY +#if CONFIG_IS_ENABLED(ARMV8_SPIN_TABLE) + branch_if_master x0, x1, master_cpu + b spin_table_secondary_jump + /* never return */ +#elif defined(CONFIG_ARMV8_MULTIENTRY) branch_if_master x0, x1, master_cpu /* @@ -106,10 +110,8 @@ slave_cpu: ldr x0, [x1] cbz x0, slave_cpu br x0 /* branch to the given address */ -master_cpu: - /* On the master CPU */ #endif /* CONFIG_ARMV8_MULTIENTRY */ - +master_cpu: bl _main #ifdef CONFIG_SYS_RESET_SCTRL diff --git a/arch/arm/dts/exynos4210-origen.dts b/arch/arm/dts/exynos4210-origen.dts index 3f87761..26c4d7f 100644 --- a/arch/arm/dts/exynos4210-origen.dts +++ b/arch/arm/dts/exynos4210-origen.dts @@ -22,7 +22,7 @@ aliases { serial0 = "/serial@13800000"; console = "/serial@13820000"; - mmc2 = "sdhci@12530000"; + mmc2 = "/sdhci@12530000"; }; sdhci@12510000 { diff --git a/arch/arm/dts/exynos4210-trats.dts b/arch/arm/dts/exynos4210-trats.dts index f3fac80..2ed38f3 100644 --- a/arch/arm/dts/exynos4210-trats.dts +++ b/arch/arm/dts/exynos4210-trats.dts @@ -29,8 +29,8 @@ i2c7 = "/i2c@138d0000"; serial0 = "/serial@13800000"; console = "/serial@13820000"; - mmc0 = "sdhci@12510000"; - mmc2 = "sdhci@12530000"; + mmc0 = "/sdhci@12510000"; + mmc2 = "/sdhci@12530000"; }; fimd@11c00000 { diff --git a/arch/arm/dts/exynos4210-universal_c210.dts b/arch/arm/dts/exynos4210-universal_c210.dts index ad3527e..8cac7dd 100644 --- a/arch/arm/dts/exynos4210-universal_c210.dts +++ b/arch/arm/dts/exynos4210-universal_c210.dts @@ -17,8 +17,8 @@ aliases { serial0 = "/serial@13800000"; console = "/serial@13820000"; - mmc0 = "sdhci@12510000"; - mmc2 = "sdhci@12530000"; + mmc0 = "/sdhci@12510000"; + mmc2 = "/sdhci@12530000"; }; sdhci@12510000 { diff --git a/arch/arm/dts/exynos4412-odroid.dts b/arch/arm/dts/exynos4412-odroid.dts index a63e8ab..188cb93 100644 --- a/arch/arm/dts/exynos4412-odroid.dts +++ b/arch/arm/dts/exynos4412-odroid.dts @@ -25,8 +25,8 @@ i2c7 = "/i2c@138d0000"; serial0 = "/serial@13800000"; console = "/serial@13810000"; - mmc2 = "sdhci@12530000"; - mmc4 = "dwmmc@12550000"; + mmc2 = "/sdhci@12530000"; + mmc4 = "/dwmmc@12550000"; }; i2c@13860000 { diff --git a/arch/arm/dts/exynos4412-trats2.dts b/arch/arm/dts/exynos4412-trats2.dts index 2d4e522..1fbcf89 100644 --- a/arch/arm/dts/exynos4412-trats2.dts +++ b/arch/arm/dts/exynos4412-trats2.dts @@ -29,9 +29,9 @@ i2c7 = "/i2c@138d0000"; serial0 = "/serial@13800000"; console = "/serial@13820000"; - mmc0 = "sdhci@12510000"; - mmc2 = "sdhci@12530000"; - mmc4 = "dwmmc@12550000"; + mmc0 = "/sdhci@12510000"; + mmc2 = "/sdhci@12530000"; + mshc0 = "/dwmmc@12550000"; }; i2c@138d0000 { diff --git a/arch/arm/dts/rk3288-firefly.dts b/arch/arm/dts/rk3288-firefly.dts index aed8d3a..3176d50 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 d3de42d..e08e28f 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 { @@ -81,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/include/asm/arch-stm32f7/fmc.h b/arch/arm/include/asm/arch-stm32f7/fmc.h new file mode 100644 index 0000000..7dd5077 --- /dev/null +++ b/arch/arm/include/asm/arch-stm32f7/fmc.h @@ -0,0 +1,75 @@ +/* + * (C) Copyright 2013 + * Pavel Boldin, Emcraft Systems, paboldin@emcraft.com + * + * (C) Copyright 2015 + * Kamil Lulko, <kamil.lulko@gmail.com> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef _MACH_FMC_H_ +#define _MACH_FMC_H_ + +struct stm32_fmc_regs { + u32 sdcr1; /* Control register 1 */ + u32 sdcr2; /* Control register 2 */ + u32 sdtr1; /* Timing register 1 */ + u32 sdtr2; /* Timing register 2 */ + u32 sdcmr; /* Mode register */ + u32 sdrtr; /* Refresh timing register */ + u32 sdsr; /* Status register */ +}; + +/* + * FMC registers base + */ +#define STM32_SDRAM_FMC_BASE 0xA0000140 +#define STM32_SDRAM_FMC ((struct stm32_fmc_regs *)STM32_SDRAM_FMC_BASE) + +/* Control register SDCR */ +#define FMC_SDCR_RPIPE_SHIFT 13 /* RPIPE bit shift */ +#define FMC_SDCR_RBURST_SHIFT 12 /* RBURST bit shift */ +#define FMC_SDCR_SDCLK_SHIFT 10 /* SDRAM clock divisor shift */ +#define FMC_SDCR_WP_SHIFT 9 /* Write protection shift */ +#define FMC_SDCR_CAS_SHIFT 7 /* CAS latency shift */ +#define FMC_SDCR_NB_SHIFT 6 /* Number of banks shift */ +#define FMC_SDCR_MWID_SHIFT 4 /* Memory width shift */ +#define FMC_SDCR_NR_SHIFT 2 /* Number of row address bits shift */ +#define FMC_SDCR_NC_SHIFT 0 /* Number of col address bits shift */ + +/* Timings register SDTR */ +#define FMC_SDTR_TMRD_SHIFT 0 /* Load mode register to active */ +#define FMC_SDTR_TXSR_SHIFT 4 /* Exit self-refresh time */ +#define FMC_SDTR_TRAS_SHIFT 8 /* Self-refresh time */ +#define FMC_SDTR_TRC_SHIFT 12 /* Row cycle delay */ +#define FMC_SDTR_TWR_SHIFT 16 /* Recovery delay */ +#define FMC_SDTR_TRP_SHIFT 20 /* Row precharge delay */ +#define FMC_SDTR_TRCD_SHIFT 24 /* Row-to-column delay */ + + +#define FMC_SDCMR_NRFS_SHIFT 5 + +#define FMC_SDCMR_MODE_NORMAL 0 +#define FMC_SDCMR_MODE_START_CLOCK 1 +#define FMC_SDCMR_MODE_PRECHARGE 2 +#define FMC_SDCMR_MODE_AUTOREFRESH 3 +#define FMC_SDCMR_MODE_WRITE_MODE 4 +#define FMC_SDCMR_MODE_SELFREFRESH 5 +#define FMC_SDCMR_MODE_POWERDOWN 6 + +#define FMC_SDCMR_BANK_1 (1 << 4) +#define FMC_SDCMR_BANK_2 (1 << 3) + +#define FMC_SDCMR_MODE_REGISTER_SHIFT 9 + +#define FMC_SDSR_BUSY (1 << 5) + +#define FMC_BUSY_WAIT() do { \ + __asm__ __volatile__ ("dsb" : : : "memory"); \ + while (STM32_SDRAM_FMC->sdsr & FMC_SDSR_BUSY) \ + ; \ + } while (0) + + +#endif /* _MACH_FMC_H_ */ diff --git a/arch/arm/include/asm/arch-stm32f7/stm32.h b/arch/arm/include/asm/arch-stm32f7/stm32.h index 68bdab0..de55ae5 100644 --- a/arch/arm/include/asm/arch-stm32f7/stm32.h +++ b/arch/arm/include/asm/arch-stm32f7/stm32.h @@ -64,6 +64,52 @@ enum clock { }; #define STM32_BUS_MASK 0xFFFF0000 +struct stm32_rcc_regs { + u32 cr; /* RCC clock control */ + u32 pllcfgr; /* RCC PLL configuration */ + u32 cfgr; /* RCC clock configuration */ + u32 cir; /* RCC clock interrupt */ + u32 ahb1rstr; /* RCC AHB1 peripheral reset */ + u32 ahb2rstr; /* RCC AHB2 peripheral reset */ + u32 ahb3rstr; /* RCC AHB3 peripheral reset */ + u32 rsv0; + u32 apb1rstr; /* RCC APB1 peripheral reset */ + u32 apb2rstr; /* RCC APB2 peripheral reset */ + u32 rsv1[2]; + u32 ahb1enr; /* RCC AHB1 peripheral clock enable */ + u32 ahb2enr; /* RCC AHB2 peripheral clock enable */ + u32 ahb3enr; /* RCC AHB3 peripheral clock enable */ + u32 rsv2; + u32 apb1enr; /* RCC APB1 peripheral clock enable */ + u32 apb2enr; /* RCC APB2 peripheral clock enable */ + u32 rsv3[2]; + u32 ahb1lpenr; /* RCC AHB1 periph clk enable in low pwr mode */ + u32 ahb2lpenr; /* RCC AHB2 periph clk enable in low pwr mode */ + u32 ahb3lpenr; /* RCC AHB3 periph clk enable in low pwr mode */ + u32 rsv4; + u32 apb1lpenr; /* RCC APB1 periph clk enable in low pwr mode */ + u32 apb2lpenr; /* RCC APB2 periph clk enable in low pwr mode */ + u32 rsv5[2]; + u32 bdcr; /* RCC Backup domain control */ + u32 csr; /* RCC clock control & status */ + u32 rsv6[2]; + u32 sscgr; /* RCC spread spectrum clock generation */ + u32 plli2scfgr; /* RCC PLLI2S configuration */ + u32 pllsaicfgr; + u32 dckcfgr; +}; +#define STM32_RCC ((struct stm32_rcc_regs *)RCC_BASE) + +struct stm32_pwr_regs { + u32 cr1; /* power control register 1 */ + u32 csr1; /* power control/status register 2 */ + u32 cr2; /* power control register 2 */ + u32 csr2; /* power control/status register 2 */ +}; +#define STM32_PWR ((struct stm32_pwr_regs *)PWR_BASE) + int configure_clocks(void); +unsigned long clock_get(enum clock clck); +void stm32_flash_latency_cfg(int latency); #endif /* _ASM_ARCH_HARDWARE_H */ diff --git a/arch/arm/include/asm/arch-stm32f7/stm32_periph.h b/arch/arm/include/asm/arch-stm32f7/stm32_periph.h index 38adc4e..0bd4695 100644 --- a/arch/arm/include/asm/arch-stm32f7/stm32_periph.h +++ b/arch/arm/include/asm/arch-stm32f7/stm32_periph.h @@ -17,11 +17,13 @@ enum periph_id { UART1_GPIOA_9_10 = 0, UART2_GPIOD_5_6, + UART6_GPIOC_6_7, }; enum periph_clock { USART1_CLOCK_CFG = 0, USART2_CLOCK_CFG, + USART6_CLOCK_CFG, GPIO_A_CLOCK_CFG, GPIO_B_CLOCK_CFG, GPIO_C_CLOCK_CFG, diff --git a/arch/arm/include/asm/armv7m.h b/arch/arm/include/asm/armv7m.h index 200444d..54d8a2b 100644 --- a/arch/arm/include/asm/armv7m.h +++ b/arch/arm/include/asm/armv7m.h @@ -51,10 +51,21 @@ struct v7m_mpu { #define V7M_MPU_CTRL_ENABLE (1 << 0) #define V7M_MPU_CTRL_HFNMIENA (1 << 1) +#define V7M_MPU_CTRL_ENABLE (1 << 0) +#define V7M_MPU_CTRL_DISABLE (0 << 0) +#define V7M_MPU_CTRL_HFNMIENA (1 << 1) + #define V7M_MPU_RASR_EN (1 << 0) #define V7M_MPU_RASR_SIZE_BITS 1 #define V7M_MPU_RASR_SIZE_4GB (31 << V7M_MPU_RASR_SIZE_BITS) +#define V7M_MPU_RASR_SIZE_8MB (24 << V7M_MPU_RASR_SIZE_BITS) +#define V7M_MPU_RASR_TEX_SHIFT 19 +#define V7M_MPU_RASR_S_SHIFT 18 +#define V7M_MPU_RASR_C_SHIFT 17 +#define V7M_MPU_RASR_B_SHIFT 16 #define V7M_MPU_RASR_AP_RW_RW (3 << 24) +#define V7M_MPU_RASR_XN_ENABLE (0 << 28) +#define V7M_MPU_RASR_XN_DISABLE (1 << 28) #endif /* !defined(__ASSEMBLY__) */ #endif /* ARMV7M_H */ diff --git a/arch/arm/include/asm/cache.h b/arch/arm/include/asm/cache.h index 1f63127..16e65c3 100644 --- a/arch/arm/include/asm/cache.h +++ b/arch/arm/include/asm/cache.h @@ -29,6 +29,8 @@ static inline void invalidate_l2_cache(void) } #endif +int check_cache_range(unsigned long start, unsigned long stop); + void l2_cache_enable(void); void l2_cache_disable(void); void set_section_dcache(int section, enum dcache_option option); diff --git a/arch/arm/include/asm/io.h b/arch/arm/include/asm/io.h index 9d185a6..6121f1d 100644 --- a/arch/arm/include/asm/io.h +++ b/arch/arm/include/asm/io.h @@ -292,40 +292,6 @@ static inline void __raw_readsl(unsigned long addr, void *data, int longlen) #define readsb(a, d, s) __raw_readsb((unsigned long)a, d, s) /* - * ioremap and friends. - * - * ioremap takes a PCI memory address, as specified in - * linux/Documentation/IO-mapping.txt. If you want a - * physical address, use __ioremap instead. - */ -extern void * __ioremap(unsigned long offset, size_t size, unsigned long flags); -extern void __iounmap(void *addr); - -/* - * Generic ioremap support. - * - * Define: - * iomem_valid_addr(off,size) - * iomem_to_phys(off) - */ -#ifdef iomem_valid_addr -#define __arch_ioremap(off,sz,nocache) \ - ({ \ - unsigned long _off = (off), _size = (sz); \ - void *_ret = (void *)0; \ - if (iomem_valid_addr(_off, _size)) \ - _ret = __ioremap(iomem_to_phys(_off),_size,nocache); \ - _ret; \ - }) - -#define __arch_iounmap __iounmap -#endif - -#define ioremap(off,sz) __arch_ioremap((off),(sz),0) -#define ioremap_nocache(off,sz) __arch_ioremap((off),(sz),1) -#define iounmap(_addr) __arch_iounmap(_addr) - -/* * DMA-consistent mapping functions. These allocate/free a region of * uncached, unwrite-buffered mapped memory space for use with DMA * devices. This is the "generic" version. The PCI specific version diff --git a/arch/arm/include/asm/omap_common.h b/arch/arm/include/asm/omap_common.h index 07f3848..605c549 100644 --- a/arch/arm/include/asm/omap_common.h +++ b/arch/arm/include/asm/omap_common.h @@ -627,6 +627,12 @@ void recalibrate_iodelay(void); void omap_smc1(u32 service, u32 val); +/* + * Low-level helper function used when performing secure ROM calls on high- + * security (HS) device variants by doing a specially-formed smc entry. + */ +u32 omap_smc_sec(u32 service, u32 proc_id, u32 flag, u32 *params); + void enable_edma3_clocks(void); void disable_edma3_clocks(void); diff --git a/arch/arm/include/asm/omap_sec_common.h b/arch/arm/include/asm/omap_sec_common.h new file mode 100644 index 0000000..842f2af --- /dev/null +++ b/arch/arm/include/asm/omap_sec_common.h @@ -0,0 +1,30 @@ +/* + * (C) Copyright 2016 + * Texas Instruments, <www.ti.com> + * + * Andreas Dannenberg <dannenberg@ti.com> + * + * SPDX-License-Identifier: GPL-2.0+ + */ +#ifndef _OMAP_SEC_COMMON_H_ +#define _OMAP_SEC_COMMON_H_ + +#include <common.h> + +/* + * Invoke secure ROM API on high-security (HS) device variants. It formats + * the variable argument list into the format expected by the ROM code before + * triggering the actual low-level smc entry. + */ +u32 secure_rom_call(u32 service, u32 proc_id, u32 flag, ...); + +/* + * Invoke a secure ROM API on high-secure (HS) device variants that can be used + * to verify a secure blob by authenticating and optionally decrypting it. The + * exact operation performed depends on how the certificate that was embedded + * into the blob during the signing/encryption step when the secure blob was + * first created. + */ +int secure_boot_verify_image(void **p_image, size_t *p_size); + +#endif /* _OMAP_SEC_COMMON_H_ */ diff --git a/arch/arm/include/asm/spin_table.h b/arch/arm/include/asm/spin_table.h new file mode 100644 index 0000000..8b57539 --- /dev/null +++ b/arch/arm/include/asm/spin_table.h @@ -0,0 +1,14 @@ +/* + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef __ASM_SPIN_TABLE_H__ +#define __ASM_SPIN_TABLE_H__ + +extern u64 spin_table_cpu_release_addr; +extern char spin_table_reserve_begin; +extern char spin_table_reserve_end; + +int spin_table_update_dt(void *fdt); + +#endif /* __ASM_SPIN_TABLE_H__ */ diff --git a/arch/arm/include/asm/types.h b/arch/arm/include/asm/types.h index d108915..9af7353 100644 --- a/arch/arm/include/asm/types.h +++ b/arch/arm/include/asm/types.h @@ -71,5 +71,4 @@ typedef u32 dma_addr_t; #endif /* __KERNEL__ */ -typedef unsigned long resource_size_t; #endif diff --git a/arch/arm/lib/bootm-fdt.c b/arch/arm/lib/bootm-fdt.c index 76b75d8..2c0b56a 100644 --- a/arch/arm/lib/bootm-fdt.c +++ b/arch/arm/lib/bootm-fdt.c @@ -21,6 +21,7 @@ #include <asm/armv7.h> #endif #include <asm/psci.h> +#include <asm/spin_table.h> DECLARE_GLOBAL_DATA_PTR; @@ -45,6 +46,12 @@ int arch_fixup_fdt(void *blob) if (ret) return ret; +#ifdef CONFIG_ARMV8_SPIN_TABLE + ret = spin_table_update_dt(blob); + if (ret) + return ret; +#endif + #ifdef CONFIG_ARMV7_NONSEC ret = psci_update_dt(blob); if (ret) diff --git a/arch/arm/lib/cache.c b/arch/arm/lib/cache.c index 3bd8710..d330b09 100644 --- a/arch/arm/lib/cache.c +++ b/arch/arm/lib/cache.c @@ -10,6 +10,10 @@ #include <common.h> #include <malloc.h> +#ifndef CONFIG_SYS_CACHELINE_SIZE +#define CONFIG_SYS_CACHELINE_SIZE 32 +#endif + /* * Flush range from all levels of d-cache/unified-cache. * Affects the range [start, start + size - 1]. @@ -46,6 +50,24 @@ __weak void flush_dcache_range(unsigned long start, unsigned long stop) /* An empty stub, real implementation should be in platform code */ } +int check_cache_range(unsigned long start, unsigned long stop) +{ + int ok = 1; + + if (start & (CONFIG_SYS_CACHELINE_SIZE - 1)) + ok = 0; + + if (stop & (CONFIG_SYS_CACHELINE_SIZE - 1)) + ok = 0; + + if (!ok) { + warn_non_spl("CACHE: Misaligned operation at range [%08lx, %08lx]\n", + start, stop); + } + + return ok; +} + #ifdef CONFIG_SYS_NONCACHED_MEMORY /* * Reserve one MMU section worth of address space below the malloc() area that diff --git a/arch/arm/mach-exynos/include/mach/dwmmc.h b/arch/arm/mach-exynos/include/mach/dwmmc.h index bd997ad..ab8361f 100644 --- a/arch/arm/mach-exynos/include/mach/dwmmc.h +++ b/arch/arm/mach-exynos/include/mach/dwmmc.h @@ -28,4 +28,3 @@ #define DWMCI_DIVRATIO_MASK 0x7 int exynos_dwmmc_init(const void *blob); -int exynos_dwmci_add_port(int index, u32 regbase, int bus_width, u32 clksel); diff --git a/arch/arm/mach-rockchip/rk3288-board-spl.c b/arch/arm/mach-rockchip/rk3288-board-spl.c index 15f1266..123f58b 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; } @@ -114,7 +116,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 +145,6 @@ static int configure_emmc(struct udevice *pinctrl) debug("gpio value ret=%d\n", ret); return ret; } -#endif return 0; } @@ -247,15 +247,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 diff --git a/arch/arm/mach-rockchip/rk3288/sdram_rk3288.c b/arch/arm/mach-rockchip/rk3288/sdram_rk3288.c index 55ac73e..b36b6af 100644 --- a/arch/arm/mach-rockchip/rk3288/sdram_rk3288.c +++ b/arch/arm/mach-rockchip/rk3288/sdram_rk3288.c @@ -10,6 +10,7 @@ #include <common.h> #include <clk.h> #include <dm.h> +#include <dt-structs.h> #include <errno.h> #include <ram.h> #include <regmap.h> @@ -41,6 +42,19 @@ struct dram_info { struct rk3288_grf *grf; struct rk3288_sgrf *sgrf; struct rk3288_pmu *pmu; + bool is_veyron; +}; + +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; + struct rk3288_base_params base; + int num_channels; + struct regmap *map; }; #ifdef CONFIG_SPL_BUILD @@ -703,7 +717,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 +793,36 @@ 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) +{ +#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; 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,46 +830,82 @@ 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; + priv->is_veyron = !fdt_node_check_compatible(blob, 0, "google,veyron"); +#endif + 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])); } -# endif + 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 sdram_init(priv, ¶ms); + return 0; } #endif 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; 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); @@ -849,14 +917,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; @@ -898,10 +964,16 @@ 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, +#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 }; diff --git a/arch/arm/mach-rockchip/rk3288/syscon_rk3288.c b/arch/arm/mach-rockchip/rk3288/syscon_rk3288.c index c9f7c4e..be4b2b0 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 diff --git a/arch/arm/mach-stm32/stm32f7/Makefile b/arch/arm/mach-stm32/stm32f7/Makefile index 40f1ad3..643d4d9 100644 --- a/arch/arm/mach-stm32/stm32f7/Makefile +++ b/arch/arm/mach-stm32/stm32f7/Makefile @@ -5,4 +5,4 @@ # SPDX-License-Identifier: GPL-2.0+ # -obj-y += timer.o clock.o +obj-y += timer.o clock.o soc.o diff --git a/arch/arm/mach-stm32/stm32f7/clock.c b/arch/arm/mach-stm32/stm32f7/clock.c index 17a715b..ac47850 100644 --- a/arch/arm/mach-stm32/stm32f7/clock.c +++ b/arch/arm/mach-stm32/stm32f7/clock.c @@ -11,12 +11,243 @@ #include <asm/arch/stm32.h> #include <asm/arch/stm32_periph.h> +#define RCC_CR_HSION (1 << 0) +#define RCC_CR_HSEON (1 << 16) +#define RCC_CR_HSERDY (1 << 17) +#define RCC_CR_HSEBYP (1 << 18) +#define RCC_CR_CSSON (1 << 19) +#define RCC_CR_PLLON (1 << 24) +#define RCC_CR_PLLRDY (1 << 25) + +#define RCC_PLLCFGR_PLLM_MASK 0x3F +#define RCC_PLLCFGR_PLLN_MASK 0x7FC0 +#define RCC_PLLCFGR_PLLP_MASK 0x30000 +#define RCC_PLLCFGR_PLLQ_MASK 0xF000000 +#define RCC_PLLCFGR_PLLSRC (1 << 22) +#define RCC_PLLCFGR_PLLM_SHIFT 0 +#define RCC_PLLCFGR_PLLN_SHIFT 6 +#define RCC_PLLCFGR_PLLP_SHIFT 16 +#define RCC_PLLCFGR_PLLQ_SHIFT 24 + +#define RCC_CFGR_AHB_PSC_MASK 0xF0 +#define RCC_CFGR_APB1_PSC_MASK 0x1C00 +#define RCC_CFGR_APB2_PSC_MASK 0xE000 +#define RCC_CFGR_SW0 (1 << 0) +#define RCC_CFGR_SW1 (1 << 1) +#define RCC_CFGR_SW_MASK 0x3 +#define RCC_CFGR_SW_HSI 0 +#define RCC_CFGR_SW_HSE RCC_CFGR_SW0 +#define RCC_CFGR_SW_PLL RCC_CFGR_SW1 +#define RCC_CFGR_SWS0 (1 << 2) +#define RCC_CFGR_SWS1 (1 << 3) +#define RCC_CFGR_SWS_MASK 0xC +#define RCC_CFGR_SWS_HSI 0 +#define RCC_CFGR_SWS_HSE RCC_CFGR_SWS0 +#define RCC_CFGR_SWS_PLL RCC_CFGR_SWS1 +#define RCC_CFGR_HPRE_SHIFT 4 +#define RCC_CFGR_PPRE1_SHIFT 10 +#define RCC_CFGR_PPRE2_SHIFT 13 + +#define RCC_APB1ENR_PWREN (1 << 28) + +/* + * RCC USART specific definitions + */ +#define RCC_ENR_USART1EN (1 << 4) +#define RCC_ENR_USART2EN (1 << 17) +#define RCC_ENR_USART3EN (1 << 18) +#define RCC_ENR_USART6EN (1 << 5) + +/* + * Offsets of some PWR registers + */ +#define PWR_CR1_ODEN (1 << 16) +#define PWR_CR1_ODSWEN (1 << 17) +#define PWR_CSR1_ODRDY (1 << 16) +#define PWR_CSR1_ODSWRDY (1 << 17) + + +/* + * RCC GPIO specific definitions + */ +#define RCC_ENR_GPIO_A_EN (1 << 0) +#define RCC_ENR_GPIO_B_EN (1 << 1) +#define RCC_ENR_GPIO_C_EN (1 << 2) +#define RCC_ENR_GPIO_D_EN (1 << 3) +#define RCC_ENR_GPIO_E_EN (1 << 4) +#define RCC_ENR_GPIO_F_EN (1 << 5) +#define RCC_ENR_GPIO_G_EN (1 << 6) +#define RCC_ENR_GPIO_H_EN (1 << 7) +#define RCC_ENR_GPIO_I_EN (1 << 8) +#define RCC_ENR_GPIO_J_EN (1 << 9) +#define RCC_ENR_GPIO_K_EN (1 << 10) + +struct pll_psc { + u8 pll_m; + u16 pll_n; + u8 pll_p; + u8 pll_q; + u8 ahb_psc; + u8 apb1_psc; + u8 apb2_psc; +}; + +#define AHB_PSC_1 0 +#define AHB_PSC_2 0x8 +#define AHB_PSC_4 0x9 +#define AHB_PSC_8 0xA +#define AHB_PSC_16 0xB +#define AHB_PSC_64 0xC +#define AHB_PSC_128 0xD +#define AHB_PSC_256 0xE +#define AHB_PSC_512 0xF + +#define APB_PSC_1 0 +#define APB_PSC_2 0x4 +#define APB_PSC_4 0x5 +#define APB_PSC_8 0x6 +#define APB_PSC_16 0x7 + +#if !defined(CONFIG_STM32_HSE_HZ) +#error "CONFIG_STM32_HSE_HZ not defined!" +#else +#if (CONFIG_STM32_HSE_HZ == 25000000) +#if (CONFIG_SYS_CLK_FREQ == 200000000) +/* 200 MHz */ +struct pll_psc sys_pll_psc = { + .pll_m = 25, + .pll_n = 400, + .pll_p = 2, + .pll_q = 8, + .ahb_psc = AHB_PSC_1, + .apb1_psc = APB_PSC_4, + .apb2_psc = APB_PSC_2 +}; +#endif +#else +#error "No PLL/Prescaler configuration for given CONFIG_STM32_HSE_HZ exists" +#endif +#endif + +int configure_clocks(void) +{ + /* Reset RCC configuration */ + setbits_le32(&STM32_RCC->cr, RCC_CR_HSION); + writel(0, &STM32_RCC->cfgr); /* Reset CFGR */ + clrbits_le32(&STM32_RCC->cr, (RCC_CR_HSEON | RCC_CR_CSSON + | RCC_CR_PLLON)); + writel(0x24003010, &STM32_RCC->pllcfgr); /* Reset value from RM */ + clrbits_le32(&STM32_RCC->cr, RCC_CR_HSEBYP); + writel(0, &STM32_RCC->cir); /* Disable all interrupts */ + + /* Configure for HSE+PLL operation */ + setbits_le32(&STM32_RCC->cr, RCC_CR_HSEON); + while (!(readl(&STM32_RCC->cr) & RCC_CR_HSERDY)) + ; + + setbits_le32(&STM32_RCC->cfgr, (( + sys_pll_psc.ahb_psc << RCC_CFGR_HPRE_SHIFT) + | (sys_pll_psc.apb1_psc << RCC_CFGR_PPRE1_SHIFT) + | (sys_pll_psc.apb2_psc << RCC_CFGR_PPRE2_SHIFT))); + + /* Configure the main PLL */ + uint32_t pllcfgr = 0; + pllcfgr = RCC_PLLCFGR_PLLSRC; /* pll source HSE */ + pllcfgr |= sys_pll_psc.pll_m << RCC_PLLCFGR_PLLM_SHIFT; + pllcfgr |= sys_pll_psc.pll_n << RCC_PLLCFGR_PLLN_SHIFT; + pllcfgr |= ((sys_pll_psc.pll_p >> 1) - 1) << RCC_PLLCFGR_PLLP_SHIFT; + pllcfgr |= sys_pll_psc.pll_q << RCC_PLLCFGR_PLLQ_SHIFT; + writel(pllcfgr, &STM32_RCC->pllcfgr); + + /* Enable the main PLL */ + setbits_le32(&STM32_RCC->cr, RCC_CR_PLLON); + while (!(readl(&STM32_RCC->cr) & RCC_CR_PLLRDY)) + ; + + /* Enable high performance mode, System frequency up to 200 MHz */ + setbits_le32(&STM32_RCC->apb1enr, RCC_APB1ENR_PWREN); + setbits_le32(&STM32_PWR->cr1, PWR_CR1_ODEN); + /* Infinite wait! */ + while (!(readl(&STM32_PWR->csr1) & PWR_CSR1_ODRDY)) + ; + /* Enable the Over-drive switch */ + setbits_le32(&STM32_PWR->cr1, PWR_CR1_ODSWEN); + /* Infinite wait! */ + while (!(readl(&STM32_PWR->csr1) & PWR_CSR1_ODSWRDY)) + ; + + stm32_flash_latency_cfg(5); + clrbits_le32(&STM32_RCC->cfgr, (RCC_CFGR_SW0 | RCC_CFGR_SW1)); + setbits_le32(&STM32_RCC->cfgr, RCC_CFGR_SW_PLL); + + while ((readl(&STM32_RCC->cfgr) & RCC_CFGR_SWS_MASK) != + RCC_CFGR_SWS_PLL) + ; + + return 0; +} + +unsigned long clock_get(enum clock clck) +{ + u32 sysclk = 0; + u32 shift = 0; + /* Prescaler table lookups for clock computation */ + u8 ahb_psc_table[16] = { + 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 6, 7, 8, 9 + }; + u8 apb_psc_table[8] = { + 0, 0, 0, 0, 1, 2, 3, 4 + }; + + if ((readl(&STM32_RCC->cfgr) & RCC_CFGR_SWS_MASK) == + RCC_CFGR_SWS_PLL) { + u16 pllm, plln, pllp; + pllm = (readl(&STM32_RCC->pllcfgr) & RCC_PLLCFGR_PLLM_MASK); + plln = ((readl(&STM32_RCC->pllcfgr) & RCC_PLLCFGR_PLLN_MASK) + >> RCC_PLLCFGR_PLLN_SHIFT); + pllp = ((((readl(&STM32_RCC->pllcfgr) & RCC_PLLCFGR_PLLP_MASK) + >> RCC_PLLCFGR_PLLP_SHIFT) + 1) << 1); + sysclk = ((CONFIG_STM32_HSE_HZ / pllm) * plln) / pllp; + } + + switch (clck) { + case CLOCK_CORE: + return sysclk; + break; + case CLOCK_AHB: + shift = ahb_psc_table[( + (readl(&STM32_RCC->cfgr) & RCC_CFGR_AHB_PSC_MASK) + >> RCC_CFGR_HPRE_SHIFT)]; + return sysclk >>= shift; + break; + case CLOCK_APB1: + shift = apb_psc_table[( + (readl(&STM32_RCC->cfgr) & RCC_CFGR_APB1_PSC_MASK) + >> RCC_CFGR_PPRE1_SHIFT)]; + return sysclk >>= shift; + break; + case CLOCK_APB2: + shift = apb_psc_table[( + (readl(&STM32_RCC->cfgr) & RCC_CFGR_APB2_PSC_MASK) + >> RCC_CFGR_PPRE2_SHIFT)]; + return sysclk >>= shift; + break; + default: + return 0; + break; + } +} + + void clock_setup(int peripheral) { switch (peripheral) { case USART1_CLOCK_CFG: setbits_le32(RCC_BASE + RCC_APB2ENR, RCC_ENR_USART1EN); break; + case USART6_CLOCK_CFG: + setbits_le32(RCC_BASE + RCC_APB2ENR, RCC_ENR_USART6EN); + break; case GPIO_A_CLOCK_CFG: setbits_le32(RCC_BASE + RCC_AHB1ENR, RCC_ENR_GPIO_A_EN); break; diff --git a/arch/arm/mach-stm32/stm32f7/soc.c b/arch/arm/mach-stm32/stm32f7/soc.c new file mode 100644 index 0000000..8baee99 --- /dev/null +++ b/arch/arm/mach-stm32/stm32f7/soc.c @@ -0,0 +1,76 @@ +/* + * (C) Copyright 2015 + * Kamil Lulko, <kamil.lulko@gmail.com> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <asm/io.h> +#include <asm/armv7m.h> +#include <asm/arch/stm32.h> + +u32 get_cpu_rev(void) +{ + return 0; +} + +int arch_cpu_init(void) +{ + configure_clocks(); + + /* + * Configure the memory protection unit (MPU) + * 0x00000000 - 0xffffffff: Strong-order, Shareable + * 0xC0000000 - 0xC0800000: Normal, Outer and inner Non-cacheable + */ + + /* Disable MPU */ + writel(0, &V7M_MPU->ctrl); + + writel( + 0x00000000 /* address */ + | 1 << 4 /* VALID */ + | 0 << 0 /* REGION */ + , &V7M_MPU->rbar + ); + + /* Strong-order, Shareable */ + /* TEX=000, S=1, C=0, B=0*/ + writel( + (V7M_MPU_RASR_XN_ENABLE + | V7M_MPU_RASR_AP_RW_RW + | 0x01 << V7M_MPU_RASR_S_SHIFT + | 0x00 << V7M_MPU_RASR_TEX_SHIFT + | V7M_MPU_RASR_SIZE_4GB + | V7M_MPU_RASR_EN) + , &V7M_MPU->rasr + ); + + writel( + 0xC0000000 /* address */ + | 1 << 4 /* VALID */ + | 1 << 0 /* REGION */ + , &V7M_MPU->rbar + ); + + /* Normal, Outer and inner Non-cacheable */ + /* TEX=001, S=0, C=0, B=0*/ + writel( + (V7M_MPU_RASR_XN_ENABLE + | V7M_MPU_RASR_AP_RW_RW + | 0x01 << V7M_MPU_RASR_TEX_SHIFT + | V7M_MPU_RASR_SIZE_8MB + | V7M_MPU_RASR_EN) + , &V7M_MPU->rasr + ); + + /* Enable MPU */ + writel(V7M_MPU_CTRL_ENABLE | V7M_MPU_CTRL_HFNMIENA, &V7M_MPU->ctrl); + + return 0; +} + +void s_init(void) +{ +} diff --git a/arch/nds32/include/asm/io.h b/arch/nds32/include/asm/io.h index 04708e9..b2c4d0e 100644 --- a/arch/nds32/include/asm/io.h +++ b/arch/nds32/include/asm/io.h @@ -344,40 +344,6 @@ static inline void writesl(unsigned int *addr, const void * data, int longlen) #define insl_p(port, to, len) insl(port, to, len) /* - * ioremap and friends. - * - * ioremap takes a PCI memory address, as specified in - * linux/Documentation/IO-mapping.txt. If you want a - * physical address, use __ioremap instead. - */ -extern void *__ioremap(unsigned long offset, size_t size, unsigned long flags); -extern void __iounmap(void *addr); - -/* - * Generic ioremap support. - * - * Define: - * iomem_valid_addr(off,size) - * iomem_to_phys(off) - */ -#ifdef iomem_valid_addr -#define __arch_ioremap(off, sz, nocache) \ -({ \ - unsigned long _off = (off), _size = (sz); \ - void *_ret = (void *)0; \ - if (iomem_valid_addr(_off, _size)) \ - _ret = __ioremap(iomem_to_phys(_off), _size, 0); \ - _ret; \ -}) - -#define __arch_iounmap __iounmap -#endif - -#define ioremap(off, sz) __arch_ioremap((off), (sz), 0) -#define ioremap_nocache(off, sz) __arch_ioremap((off), (sz), 1) -#define iounmap(_addr) __arch_iounmap(_addr) - -/* * DMA-consistent mapping functions. These allocate/free a region of * uncached, unwrite-buffered mapped memory space for use with DMA * devices. This is the "generic" version. The PCI specific version diff --git a/arch/sandbox/Kconfig b/arch/sandbox/Kconfig index a8a90cb..d4c1ee0 100644 --- a/arch/sandbox/Kconfig +++ b/arch/sandbox/Kconfig @@ -10,8 +10,13 @@ config SYS_BOARD config SYS_CPU default "sandbox" +config SANDBOX_SPL + bool "Enable SPL for sandbox" + select SUPPORT_SPL + config SYS_CONFIG_NAME - default "sandbox" + default "sandbox_spl" if SANDBOX_SPL + default "sandbox" if !SANDBOX_SPL config PCI bool "PCI support" diff --git a/arch/sandbox/config.mk b/arch/sandbox/config.mk index 16fd6d5..6d62abb 100644 --- a/arch/sandbox/config.mk +++ b/arch/sandbox/config.mk @@ -20,4 +20,9 @@ cmd_u-boot__ = $(CC) -o $@ -Wl,-T u-boot.lds \ -Wl,--start-group $(u-boot-main) -Wl,--end-group \ $(PLATFORM_LIBS) -Wl,-Map -Wl,u-boot.map +cmd_u-boot-spl = (cd $(obj) && $(CC) -o $(SPL_BIN) -Wl,-T u-boot-spl.lds \ + -Wl,--start-group $(patsubst $(obj)/%,%,$(u-boot-spl-main)) \ + $(patsubst $(obj)/%,%,$(u-boot-spl-platdata)) -Wl,--end-group \ + $(PLATFORM_LIBS) -Wl,-Map -Wl,u-boot-spl.map -Wl,--gc-sections) + CONFIG_ARCH_DEVICE_TREE := sandbox diff --git a/arch/sandbox/cpu/Makefile b/arch/sandbox/cpu/Makefile index 1b42fee..db43633 100644 --- a/arch/sandbox/cpu/Makefile +++ b/arch/sandbox/cpu/Makefile @@ -8,6 +8,7 @@ # obj-y := cpu.o os.o start.o state.o +obj-$(CONFIG_SPL_BUILD) += spl.o obj-$(CONFIG_ETH_SANDBOX_RAW) += eth-raw-os.o obj-$(CONFIG_SANDBOX_SDL) += sdl.o diff --git a/arch/sandbox/cpu/cpu.c b/arch/sandbox/cpu/cpu.c index 196f3e1..2def722 100644 --- a/arch/sandbox/cpu/cpu.c +++ b/arch/sandbox/cpu/cpu.c @@ -4,10 +4,12 @@ */ #define DEBUG #include <common.h> -#include <dm/root.h> +#include <errno.h> +#include <libfdt.h> #include <os.h> #include <asm/io.h> #include <asm/state.h> +#include <dm/root.h> DECLARE_GLOBAL_DATA_PTR; @@ -55,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/cpu/os.c b/arch/sandbox/cpu/os.c index 8a4d719..2d63dd8 100644 --- a/arch/sandbox/cpu/os.c +++ b/arch/sandbox/cpu/os.c @@ -541,6 +541,57 @@ int os_jump_to_image(const void *dest, int size) return unlink(fname); } +int os_find_u_boot(char *fname, int maxlen) +{ + struct sandbox_state *state = state_get_current(); + const char *progname = state->argv[0]; + int len = strlen(progname); + char *p; + int fd; + + if (len >= maxlen || len < 4) + return -ENOSPC; + + /* Look for 'u-boot' in the same directory as 'u-boot-spl' */ + strcpy(fname, progname); + if (!strcmp(fname + len - 4, "-spl")) { + fname[len - 4] = '\0'; + fd = os_open(fname, O_RDONLY); + if (fd >= 0) { + close(fd); + return 0; + } + } + + /* Look for 'u-boot' in the parent directory of spl/ */ + p = strstr(fname, "/spl/"); + if (p) { + strcpy(p, p + 4); + fd = os_open(fname, O_RDONLY); + if (fd >= 0) { + close(fd); + return 0; + } + } + + return -ENOENT; +} + +int os_spl_to_uboot(const char *fname) +{ + struct sandbox_state *state = state_get_current(); + char *argv[state->argc + 1]; + int ret; + + memcpy(argv, state->argv, sizeof(char *) * (state->argc + 1)); + argv[0] = (char *)fname; + ret = execv(fname, argv); + if (ret) + return ret; + + return unlink(fname); +} + void os_localtime(struct rtc_time *rt) { time_t t = time(NULL); diff --git a/arch/sandbox/cpu/spl.c b/arch/sandbox/cpu/spl.c new file mode 100644 index 0000000..e8349c0 --- /dev/null +++ b/arch/sandbox/cpu/spl.c @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2016 Google, Inc + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <dm.h> +#include <os.h> +#include <spl.h> +#include <asm/spl.h> +#include <asm/state.h> + +DECLARE_GLOBAL_DATA_PTR; + +void board_init_f(ulong flag) +{ + struct sandbox_state *state = state_get_current(); + + gd->arch.ram_buf = state->ram_buf; + gd->ram_size = state->ram_size; +} + +u32 spl_boot_device(void) +{ + return BOOT_DEVICE_BOARD; +} + +void spl_board_announce_boot_device(void) +{ + char fname[256]; + int ret; + + ret = os_find_u_boot(fname, sizeof(fname)); + if (ret) { + printf("(%s not found, error %d)\n", fname, ret); + return; + } + printf("%s\n", fname); +} + +int spl_board_load_image(void) +{ + char fname[256]; + int ret; + + ret = os_find_u_boot(fname, sizeof(fname)); + if (ret) + return ret; + + /* Hopefully this will not return */ + return os_spl_to_uboot(fname); +} + +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/cpu/start.c b/arch/sandbox/cpu/start.c index 969618e..6e4ec01 100644 --- a/arch/sandbox/cpu/start.c +++ b/arch/sandbox/cpu/start.c @@ -73,6 +73,7 @@ static int sandbox_cmdline_cb_help(struct sandbox_state *state, const char *arg) } SANDBOX_CMDLINE_OPT_SHORT(help, 'h', 0, "Display help"); +#ifndef CONFIG_SPL_BUILD int sandbox_main_loop_init(void) { struct sandbox_state *state = state_get_current(); @@ -97,6 +98,7 @@ int sandbox_main_loop_init(void) return 0; } +#endif static int sandbox_cmdline_cb_boot(struct sandbox_state *state, const char *arg) diff --git a/arch/sandbox/cpu/u-boot-spl.lds b/arch/sandbox/cpu/u-boot-spl.lds new file mode 100644 index 0000000..7e92b4a --- /dev/null +++ b/arch/sandbox/cpu/u-boot-spl.lds @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2011-2012 The Chromium OS Authors. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +SECTIONS +{ + + . = ALIGN(4); + .u_boot_list : { + KEEP(*(SORT(.u_boot_list*))); + } + + __u_boot_sandbox_option_start = .; + _u_boot_sandbox_getopt : { *(.u_boot_sandbox_getopt) } + __u_boot_sandbox_option_end = .; + + __bss_start = .; +} + +INSERT BEFORE .data; diff --git a/arch/sandbox/dts/sandbox.dts b/arch/sandbox/dts/sandbox.dts index 2ae4014..e6d336f 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/arch/sandbox/include/asm/spl.h b/arch/sandbox/include/asm/spl.h new file mode 100644 index 0000000..59f2401 --- /dev/null +++ b/arch/sandbox/include/asm/spl.h @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2016 Google, Inc + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef __asm_spl_h +#define __asm_spl_h + +#define CONFIG_SPL_BOARD_LOAD_IMAGE + +/** + * Board-specific load method for boards that have a special way of loading + * U-Boot, which does not fit with the existing SPL code. + * + * @return 0 on success, negative errno value on failure. + */ +int spl_board_load_image(void); + +enum { + BOOT_DEVICE_BOARD, +}; + +#endif diff --git a/arch/sandbox/lib/Makefile b/arch/sandbox/lib/Makefile index 96761e2..7820c55 100644 --- a/arch/sandbox/lib/Makefile +++ b/arch/sandbox/lib/Makefile @@ -8,5 +8,7 @@ # obj-y += interrupts.o +ifndef CONFIG_SPL_BUILD obj-$(CONFIG_PCI) += pci_io.o +endif obj-$(CONFIG_CMD_BOOTM) += bootm.o diff --git a/arch/sandbox/lib/bootm.c b/arch/sandbox/lib/bootm.c index d49c927..0c9a797 100644 --- a/arch/sandbox/lib/bootm.c +++ b/arch/sandbox/lib/bootm.c @@ -56,7 +56,7 @@ int do_bootm_linux(int flag, int argc, char *argv[], bootm_headers_t *images) bootstage_mark(BOOTSTAGE_ID_RUN_OS); printf("## Transferring control to Linux (at address %08lx)...\n", images->ep); - reset_cpu(0); + printf("sandbox: continuing, as we cannot run Linux\n"); } return 0; diff --git a/arch/sh/include/asm/io.h b/arch/sh/include/asm/io.h index 0a00db3..5dc27be 100644 --- a/arch/sh/include/asm/io.h +++ b/arch/sh/include/asm/io.h @@ -128,39 +128,6 @@ extern void __raw_readsl(unsigned int addr, void *data, int longlen); #define in_8(port) inb(port) #define in_le16(port) inw(port) #define in_le32(port) inl(port) -/* - * ioremap and friends. - * - * ioremap takes a PCI memory address, as specified in - * linux/Documentation/IO-mapping.txt. If you want a - * physical address, use __ioremap instead. - */ -extern void *__ioremap(unsigned long offset, size_t size, unsigned long flags); -extern void __iounmap(void *addr); - -/* - * Generic ioremap support. - * - * Define: - * iomem_valid_addr(off,size) - * iomem_to_phys(off) - */ -#ifdef iomem_valid_addr -#define __arch_ioremap(off, sz, nocache) \ -({ \ - unsigned long _off = (off), _size = (sz); \ - void *_ret = (void *)0; \ - if (iomem_valid_addr(_off, _size)) \ - _ret = __ioremap(iomem_to_phys(_off), _size, 0); \ - _ret; \ -}) - -#define __arch_iounmap __iounmap -#endif - -#define ioremap(off, sz) __arch_ioremap((off), (sz), 0) -#define ioremap_nocache(off, sz) __arch_ioremap((off), (sz), 1) -#define iounmap(_addr) __arch_iounmap(_addr) /* * DMA-consistent mapping functions. These allocate/free a region of diff --git a/board/sandbox/MAINTAINERS b/board/sandbox/MAINTAINERS index f5db773..4dcbf4b 100644 --- a/board/sandbox/MAINTAINERS +++ b/board/sandbox/MAINTAINERS @@ -11,3 +11,10 @@ S: Maintained F: board/sandbox/ F: include/configs/sandbox.h F: configs/sandbox_noblk_defconfig + +SANDBOX SPL BOARD +M: Simon Glass <sjg@chromium.org> +S: Maintained +F: board/sandbox/ +F: include/configs/sandbox_spl.h +F: configs/sandbox_spl_defconfig diff --git a/board/st/stm32f746-disco/stm32f746-disco.c b/board/st/stm32f746-disco/stm32f746-disco.c index 0e04d14..47aa058 100644 --- a/board/st/stm32f746-disco/stm32f746-disco.c +++ b/board/st/stm32f746-disco/stm32f746-disco.c @@ -10,6 +10,8 @@ #include <asm/armv7m.h> #include <asm/arch/stm32.h> #include <asm/arch/gpio.h> +#include <asm/arch/rcc.h> +#include <asm/arch/fmc.h> #include <dm/platdata.h> #include <dm/platform_data/serial_stm32x7.h> #include <asm/arch/stm32_periph.h> @@ -30,12 +32,227 @@ const struct stm32_gpio_ctl gpio_ctl_usart = { .otype = STM32_GPIO_OTYPE_PP, .speed = STM32_GPIO_SPEED_50M, .pupd = STM32_GPIO_PUPD_UP, - .af = STM32_GPIO_AF7 + .af = STM32_GPIO_AF8 }; +const struct stm32_gpio_ctl gpio_ctl_fmc = { + .mode = STM32_GPIO_MODE_AF, + .otype = STM32_GPIO_OTYPE_PP, + .speed = STM32_GPIO_SPEED_100M, + .pupd = STM32_GPIO_PUPD_NO, + .af = STM32_GPIO_AF12 +}; + +static const struct stm32_gpio_dsc ext_ram_fmc_gpio[] = { + /* Chip is LQFP144, see DM00077036.pdf for details */ + {STM32_GPIO_PORT_D, STM32_GPIO_PIN_10}, /* 79, FMC_D15 */ + {STM32_GPIO_PORT_D, STM32_GPIO_PIN_9}, /* 78, FMC_D14 */ + {STM32_GPIO_PORT_D, STM32_GPIO_PIN_8}, /* 77, FMC_D13 */ + {STM32_GPIO_PORT_E, STM32_GPIO_PIN_15}, /* 68, FMC_D12 */ + {STM32_GPIO_PORT_E, STM32_GPIO_PIN_14}, /* 67, FMC_D11 */ + {STM32_GPIO_PORT_E, STM32_GPIO_PIN_13}, /* 66, FMC_D10 */ + {STM32_GPIO_PORT_E, STM32_GPIO_PIN_12}, /* 65, FMC_D9 */ + {STM32_GPIO_PORT_E, STM32_GPIO_PIN_11}, /* 64, FMC_D8 */ + {STM32_GPIO_PORT_E, STM32_GPIO_PIN_10}, /* 63, FMC_D7 */ + {STM32_GPIO_PORT_E, STM32_GPIO_PIN_9}, /* 60, FMC_D6 */ + {STM32_GPIO_PORT_E, STM32_GPIO_PIN_8}, /* 59, FMC_D5 */ + {STM32_GPIO_PORT_E, STM32_GPIO_PIN_7}, /* 58, FMC_D4 */ + {STM32_GPIO_PORT_D, STM32_GPIO_PIN_1}, /* 115, FMC_D3 */ + {STM32_GPIO_PORT_D, STM32_GPIO_PIN_0}, /* 114, FMC_D2 */ + {STM32_GPIO_PORT_D, STM32_GPIO_PIN_15}, /* 86, FMC_D1 */ + {STM32_GPIO_PORT_D, STM32_GPIO_PIN_14}, /* 85, FMC_D0 */ + + {STM32_GPIO_PORT_E, STM32_GPIO_PIN_1}, /* 142, FMC_NBL1 */ + {STM32_GPIO_PORT_E, STM32_GPIO_PIN_0}, /* 141, FMC_NBL0 */ + + {STM32_GPIO_PORT_G, STM32_GPIO_PIN_5}, /* 90, FMC_A15, BA1 */ + {STM32_GPIO_PORT_G, STM32_GPIO_PIN_4}, /* 89, FMC_A14, BA0 */ + + {STM32_GPIO_PORT_G, STM32_GPIO_PIN_1}, /* 57, FMC_A11 */ + {STM32_GPIO_PORT_G, STM32_GPIO_PIN_0}, /* 56, FMC_A10 */ + {STM32_GPIO_PORT_F, STM32_GPIO_PIN_15}, /* 55, FMC_A9 */ + {STM32_GPIO_PORT_F, STM32_GPIO_PIN_14}, /* 54, FMC_A8 */ + {STM32_GPIO_PORT_F, STM32_GPIO_PIN_13}, /* 53, FMC_A7 */ + {STM32_GPIO_PORT_F, STM32_GPIO_PIN_12}, /* 50, FMC_A6 */ + {STM32_GPIO_PORT_F, STM32_GPIO_PIN_5}, /* 15, FMC_A5 */ + {STM32_GPIO_PORT_F, STM32_GPIO_PIN_4}, /* 14, FMC_A4 */ + {STM32_GPIO_PORT_F, STM32_GPIO_PIN_3}, /* 13, FMC_A3 */ + {STM32_GPIO_PORT_F, STM32_GPIO_PIN_2}, /* 12, FMC_A2 */ + {STM32_GPIO_PORT_F, STM32_GPIO_PIN_1}, /* 11, FMC_A1 */ + {STM32_GPIO_PORT_F, STM32_GPIO_PIN_0}, /* 10, FMC_A0 */ + + {STM32_GPIO_PORT_H, STM32_GPIO_PIN_3}, /* 136, SDRAM_NE */ + {STM32_GPIO_PORT_F, STM32_GPIO_PIN_11}, /* 49, SDRAM_NRAS */ + {STM32_GPIO_PORT_G, STM32_GPIO_PIN_15}, /* 132, SDRAM_NCAS */ + {STM32_GPIO_PORT_H, STM32_GPIO_PIN_5}, /* 26, SDRAM_NWE */ + {STM32_GPIO_PORT_C, STM32_GPIO_PIN_3}, /* 135, SDRAM_CKE */ + + {STM32_GPIO_PORT_G, STM32_GPIO_PIN_8}, /* 93, SDRAM_CLK */ +}; + +static int fmc_setup_gpio(void) +{ + int rv = 0; + int i; + + clock_setup(GPIO_B_CLOCK_CFG); + clock_setup(GPIO_C_CLOCK_CFG); + clock_setup(GPIO_D_CLOCK_CFG); + clock_setup(GPIO_E_CLOCK_CFG); + clock_setup(GPIO_F_CLOCK_CFG); + clock_setup(GPIO_G_CLOCK_CFG); + clock_setup(GPIO_H_CLOCK_CFG); + + for (i = 0; i < ARRAY_SIZE(ext_ram_fmc_gpio); i++) { + rv = stm32_gpio_config(&ext_ram_fmc_gpio[i], + &gpio_ctl_fmc); + if (rv) + goto out; + } + +out: + return rv; +} + +/* + * STM32 RCC FMC specific definitions + */ +#define RCC_ENR_FMC (1 << 0) /* FMC module clock */ + +static inline u32 _ns2clk(u32 ns, u32 freq) +{ + u32 tmp = freq/1000000; + return (tmp * ns) / 1000; +} + +#define NS2CLK(ns) (_ns2clk(ns, freq)) + +/* + * Following are timings for IS42S16400J, from corresponding datasheet + */ +#define SDRAM_CAS 3 /* 3 cycles */ +#define SDRAM_NB 1 /* Number of banks */ +#define SDRAM_MWID 1 /* 16 bit memory */ + +#define SDRAM_NR 0x1 /* 12-bit row */ +#define SDRAM_NC 0x0 /* 8-bit col */ +#define SDRAM_RBURST 0x1 /* Single read requests always as bursts */ +#define SDRAM_RPIPE 0x0 /* No HCLK clock cycle delay */ + +#define SDRAM_TRRD NS2CLK(12) +#define SDRAM_TRCD NS2CLK(18) +#define SDRAM_TRP NS2CLK(18) +#define SDRAM_TRAS NS2CLK(42) +#define SDRAM_TRC NS2CLK(60) +#define SDRAM_TRFC NS2CLK(60) +#define SDRAM_TCDL (1 - 1) +#define SDRAM_TRDL NS2CLK(12) +#define SDRAM_TBDL (1 - 1) +#define SDRAM_TREF (NS2CLK(64000000 / 8192) - 20) +#define SDRAM_TCCD (1 - 1) + +#define SDRAM_TXSR SDRAM_TRFC /* Row cycle time after precharge */ +#define SDRAM_TMRD 1 /* Page 10, Mode Register Set */ + + +/* Last data in to row precharge, need also comply ineq on page 1648 */ +#define SDRAM_TWR max(\ + (int)max((int)SDRAM_TRDL, (int)(SDRAM_TRAS - SDRAM_TRCD)), \ + (int)(SDRAM_TRC - SDRAM_TRCD - SDRAM_TRP)\ +) + + +#define SDRAM_MODE_BL_SHIFT 0 +#define SDRAM_MODE_CAS_SHIFT 4 +#define SDRAM_MODE_BL 0 +#define SDRAM_MODE_CAS SDRAM_CAS + +int dram_init(void) +{ + u32 freq; + int rv; + + rv = fmc_setup_gpio(); + if (rv) + return rv; + + setbits_le32(RCC_BASE + RCC_AHB3ENR, RCC_ENR_FMC); + + /* + * Get frequency for NS2CLK calculation. + */ + freq = clock_get(CLOCK_AHB) / CONFIG_SYS_RAM_FREQ_DIV; + + writel( + CONFIG_SYS_RAM_FREQ_DIV << FMC_SDCR_SDCLK_SHIFT + | SDRAM_CAS << FMC_SDCR_CAS_SHIFT + | SDRAM_NB << FMC_SDCR_NB_SHIFT + | SDRAM_MWID << FMC_SDCR_MWID_SHIFT + | SDRAM_NR << FMC_SDCR_NR_SHIFT + | SDRAM_NC << FMC_SDCR_NC_SHIFT + | SDRAM_RPIPE << FMC_SDCR_RPIPE_SHIFT + | SDRAM_RBURST << FMC_SDCR_RBURST_SHIFT, + &STM32_SDRAM_FMC->sdcr1); + + writel( + SDRAM_TRCD << FMC_SDTR_TRCD_SHIFT + | SDRAM_TRP << FMC_SDTR_TRP_SHIFT + | SDRAM_TWR << FMC_SDTR_TWR_SHIFT + | SDRAM_TRC << FMC_SDTR_TRC_SHIFT + | SDRAM_TRAS << FMC_SDTR_TRAS_SHIFT + | SDRAM_TXSR << FMC_SDTR_TXSR_SHIFT + | SDRAM_TMRD << FMC_SDTR_TMRD_SHIFT, + &STM32_SDRAM_FMC->sdtr1); + + writel(FMC_SDCMR_BANK_1 | FMC_SDCMR_MODE_START_CLOCK, + &STM32_SDRAM_FMC->sdcmr); + + udelay(200); /* 200 us delay, page 10, "Power-Up" */ + FMC_BUSY_WAIT(); + + writel(FMC_SDCMR_BANK_1 | FMC_SDCMR_MODE_PRECHARGE, + &STM32_SDRAM_FMC->sdcmr); + + udelay(100); + FMC_BUSY_WAIT(); + + writel((FMC_SDCMR_BANK_1 | FMC_SDCMR_MODE_AUTOREFRESH + | 7 << FMC_SDCMR_NRFS_SHIFT), &STM32_SDRAM_FMC->sdcmr); + + udelay(100); + FMC_BUSY_WAIT(); + + writel(FMC_SDCMR_BANK_1 | (SDRAM_MODE_BL << SDRAM_MODE_BL_SHIFT + | SDRAM_MODE_CAS << SDRAM_MODE_CAS_SHIFT) + << FMC_SDCMR_MODE_REGISTER_SHIFT | FMC_SDCMR_MODE_WRITE_MODE, + &STM32_SDRAM_FMC->sdcmr); + + udelay(100); + + FMC_BUSY_WAIT(); + + writel(FMC_SDCMR_BANK_1 | FMC_SDCMR_MODE_NORMAL, + &STM32_SDRAM_FMC->sdcmr); + + FMC_BUSY_WAIT(); + + /* Refresh timer */ + writel(SDRAM_TREF, &STM32_SDRAM_FMC->sdrtr); + + /* + * Fill in global info with description of SRAM configuration + */ + gd->bd->bi_dram[0].start = CONFIG_SYS_RAM_BASE; + gd->bd->bi_dram[0].size = CONFIG_SYS_RAM_SIZE; + + gd->ram_size = CONFIG_SYS_RAM_SIZE; + + return rv; +} + static const struct stm32_gpio_dsc usart_gpio[] = { - {STM32_GPIO_PORT_A, STM32_GPIO_PIN_9}, /* TX */ - {STM32_GPIO_PORT_B, STM32_GPIO_PIN_7}, /* RX */ + {STM32_GPIO_PORT_C, STM32_GPIO_PIN_6}, /* TX */ + {STM32_GPIO_PORT_C, STM32_GPIO_PIN_7}, /* RX */ }; int uart_setup_gpio(void) @@ -43,8 +260,7 @@ int uart_setup_gpio(void) int i; int rv = 0; - clock_setup(GPIO_A_CLOCK_CFG); - clock_setup(GPIO_B_CLOCK_CFG); + clock_setup(GPIO_C_CLOCK_CFG); for (i = 0; i < ARRAY_SIZE(usart_gpio); i++) { rv = stm32_gpio_config(&usart_gpio[i], &gpio_ctl_usart); if (rv) @@ -56,7 +272,7 @@ out: } static const struct stm32x7_serial_platdata serial_platdata = { - .base = (struct stm32_usart *)USART1_BASE, + .base = (struct stm32_usart *)USART6_BASE, .clock = CONFIG_SYS_CLK_FREQ, }; @@ -75,7 +291,7 @@ int board_early_init_f(void) int res; res = uart_setup_gpio(); - clock_setup(USART1_CLOCK_CFG); + clock_setup(USART6_CLOCK_CFG); if (res) return res; @@ -88,12 +304,3 @@ int board_init(void) return 0; } - -int dram_init(void) -{ - gd->bd->bi_dram[0].start = CONFIG_SYS_RAM_BASE; - gd->bd->bi_dram[0].size = CONFIG_SYS_RAM_SIZE; - - gd->ram_size = CONFIG_SYS_RAM_SIZE; - return 0; -} diff --git a/board/ti/am43xx/board.c b/board/ti/am43xx/board.c index f005762..27c311e 100644 --- a/board/ti/am43xx/board.c +++ b/board/ti/am43xx/board.c @@ -13,6 +13,7 @@ #include <asm/errno.h> #include <spl.h> #include <usb.h> +#include <asm/omap_sec_common.h> #include <asm/arch/clock.h> #include <asm/arch/sys_proto.h> #include <asm/arch/mux.h> @@ -862,3 +863,10 @@ int board_fit_config_name_match(const char *name) return -1; } #endif + +#ifdef CONFIG_TI_SECURE_DEVICE +void board_fit_image_post_process(void **p_image, size_t *p_size) +{ + secure_boot_verify_image(p_image, p_size); +} +#endif diff --git a/board/ti/am57xx/board.c b/board/ti/am57xx/board.c index 08cf14d..927d136 100644 --- a/board/ti/am57xx/board.c +++ b/board/ti/am57xx/board.c @@ -13,6 +13,7 @@ #include <sata.h> #include <usb.h> #include <asm/omap_common.h> +#include <asm/omap_sec_common.h> #include <asm/emif.h> #include <asm/gpio.h> #include <asm/arch/gpio.h> @@ -750,3 +751,10 @@ int board_fit_config_name_match(const char *name) return -1; } #endif + +#ifdef CONFIG_TI_SECURE_DEVICE +void board_fit_image_post_process(void **p_image, size_t *p_size) +{ + secure_boot_verify_image(p_image, p_size); +} +#endif diff --git a/board/ti/dra7xx/evm.c b/board/ti/dra7xx/evm.c index 6a4d027..99e8254 100644 --- a/board/ti/dra7xx/evm.c +++ b/board/ti/dra7xx/evm.c @@ -17,6 +17,8 @@ #include <asm/gpio.h> #include <usb.h> #include <linux/usb/gadget.h> +#include <asm/omap_common.h> +#include <asm/omap_sec_common.h> #include <asm/arch/gpio.h> #include <asm/arch/dra7xx_iodelay.h> #include <asm/emif.h> @@ -834,3 +836,10 @@ int board_fit_config_name_match(const char *name) return -1; } #endif + +#ifdef CONFIG_TI_SECURE_DEVICE +void board_fit_image_post_process(void **p_image, size_t *p_size) +{ + secure_boot_verify_image(p_image, p_size); +} +#endif diff --git a/common/board_f.c b/common/board_f.c index d405b5b..8d936cc 100644 --- a/common/board_f.c +++ b/common/board_f.c @@ -117,10 +117,11 @@ static int init_func_watchdog_init(void) # if defined(CONFIG_HW_WATCHDOG) && (defined(CONFIG_BLACKFIN) || \ defined(CONFIG_M68K) || defined(CONFIG_MICROBLAZE) || \ defined(CONFIG_SH) || defined(CONFIG_AT91SAM9_WATCHDOG) || \ + defined(CONFIG_DESIGNWARE_WATCHDOG) || \ defined(CONFIG_IMX_WATCHDOG)) hw_watchdog_init(); -# endif puts(" Watchdog enabled\n"); +# endif WATCHDOG_RESET(); return 0; diff --git a/common/bootm.c b/common/bootm.c index 2431019..9ed6428 100644 --- a/common/bootm.c +++ b/common/bootm.c @@ -635,10 +635,6 @@ int do_bootm_states(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[], goto err; else if (ret == BOOTM_ERR_OVERLAP) ret = 0; -#if defined(CONFIG_SILENT_CONSOLE) && !defined(CONFIG_SILENT_U_BOOT_ONLY) - if (images->os.os == IH_OS_LINUX) - fixup_silent_linux(); -#endif } /* Relocate the ramdisk */ @@ -678,13 +674,19 @@ int do_bootm_states(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[], return 1; } + /* Call various other states that are not generally used */ if (!ret && (states & BOOTM_STATE_OS_CMDLINE)) ret = boot_fn(BOOTM_STATE_OS_CMDLINE, argc, argv, images); if (!ret && (states & BOOTM_STATE_OS_BD_T)) ret = boot_fn(BOOTM_STATE_OS_BD_T, argc, argv, images); - if (!ret && (states & BOOTM_STATE_OS_PREP)) + if (!ret && (states & BOOTM_STATE_OS_PREP)) { +#if defined(CONFIG_SILENT_CONSOLE) && !defined(CONFIG_SILENT_U_BOOT_ONLY) + if (images->os.os == IH_OS_LINUX) + fixup_silent_linux(); +#endif ret = boot_fn(BOOTM_STATE_OS_PREP, argc, argv, images); + } #ifdef CONFIG_TRACE /* Pretend to run the OS, then run a user command */ diff --git a/common/bootm_os.c b/common/bootm_os.c index 9ec84bd..e3f5a46 100644 --- a/common/bootm_os.c +++ b/common/bootm_os.c @@ -481,6 +481,7 @@ int boot_selected_os(int argc, char * const argv[], int state, /* Stand-alone may return when 'autostart' is 'no' */ if (images->os.type == IH_TYPE_STANDALONE || + IS_ENABLED(CONFIG_SANDBOX) || state == BOOTM_STATE_OS_FAKE_GO) /* We expect to return */ return 0; bootstage_error(BOOTSTAGE_ID_BOOT_OS_RETURNED); diff --git a/common/image.c b/common/image.c index 0be09e5..af155b2 100644 --- a/common/image.c +++ b/common/image.c @@ -69,7 +69,7 @@ static const image_header_t *image_get_ramdisk(ulong rd_addr, uint8_t arch, #endif static const table_entry_t uimage_arch[] = { - { IH_ARCH_INVALID, NULL, "Invalid ARCH", }, + { IH_ARCH_INVALID, "invalid", "Invalid ARCH", }, { IH_ARCH_ALPHA, "alpha", "Alpha", }, { IH_ARCH_ARM, "arm", "ARM", }, { IH_ARCH_I386, "x86", "Intel x86", }, @@ -97,7 +97,7 @@ static const table_entry_t uimage_arch[] = { }; static const table_entry_t uimage_os[] = { - { IH_OS_INVALID, NULL, "Invalid OS", }, + { IH_OS_INVALID, "invalid", "Invalid OS", }, { IH_OS_LINUX, "linux", "Linux", }, #if defined(CONFIG_LYNXKDI) || defined(USE_HOSTCC) { IH_OS_LYNXOS, "lynxos", "LynxOS", }, @@ -144,7 +144,7 @@ static const table_entry_t uimage_type[] = { { IH_TYPE_KERNEL_NOLOAD, "kernel_noload", "Kernel Image (no loading done)", }, { IH_TYPE_KWBIMAGE, "kwbimage", "Kirkwood Boot Image",}, { IH_TYPE_IMXIMAGE, "imximage", "Freescale i.MX Boot Image",}, - { IH_TYPE_INVALID, NULL, "Invalid Image", }, + { IH_TYPE_INVALID, "invalid", "Invalid Image", }, { IH_TYPE_MULTI, "multi", "Multi-File Image", }, { IH_TYPE_OMAPIMAGE, "omapimage", "TI OMAP SPL With GP CH",}, { IH_TYPE_PBLIMAGE, "pblimage", "Freescale PBL Boot Image",}, @@ -176,6 +176,19 @@ static const table_entry_t uimage_comp[] = { { -1, "", "", }, }; +struct table_info { + const char *desc; + int count; + const table_entry_t *table; +}; + +static const struct table_info table_info[IH_COUNT] = { + { "architecture", IH_ARCH_COUNT, uimage_arch }, + { "compression", IH_COMP_COUNT, uimage_comp }, + { "operating system", IH_OS_COUNT, uimage_os }, + { "image type", IH_TYPE_COUNT, uimage_type }, +}; + /*****************************************************************************/ /* Legacy format routines */ /*****************************************************************************/ @@ -570,6 +583,74 @@ const table_entry_t *get_table_entry(const table_entry_t *table, int id) return NULL; } +static const char *unknown_msg(enum ih_category category) +{ + static char msg[30]; + + strcpy(msg, "Unknown "); + strcat(msg, table_info[category].desc); + + return msg; +} + +/** + * get_cat_table_entry_name - translate entry id to long name + * @category: category to look up (enum ih_category) + * @id: entry id to be translated + * + * This will scan the translation table trying to find the entry that matches + * the given id. + * + * @retur long entry name if translation succeeds; error string on failure + */ +const char *genimg_get_cat_name(enum ih_category category, uint id) +{ + const table_entry_t *entry; + + entry = get_table_entry(table_info[category].table, id); + if (!entry) + return unknown_msg(category); +#if defined(USE_HOSTCC) || !defined(CONFIG_NEEDS_MANUAL_RELOC) + return entry->lname; +#else + return entry->lname + gd->reloc_off; +#endif +} + +/** + * get_cat_table_entry_short_name - translate entry id to short name + * @category: category to look up (enum ih_category) + * @id: entry id to be translated + * + * This will scan the translation table trying to find the entry that matches + * the given id. + * + * @retur short entry name if translation succeeds; error string on failure + */ +const char *genimg_get_cat_short_name(enum ih_category category, uint id) +{ + const table_entry_t *entry; + + entry = get_table_entry(table_info[category].table, id); + if (!entry) + return unknown_msg(category); +#if defined(USE_HOSTCC) || !defined(CONFIG_NEEDS_MANUAL_RELOC) + return entry->sname; +#else + return entry->sname + gd->reloc_off; +#endif +} + +int genimg_get_cat_count(enum ih_category category) +{ + return table_info[category].count; +} + +const char *genimg_get_cat_desc(enum ih_category category) +{ + return table_info[category].desc; +} + /** * get_table_entry_name - translate entry id to long name * @table: pointer to a translation table for entries of a specific type diff --git a/common/spl/spl.c b/common/spl/spl.c index 0039716..14320fe 100644 --- a/common/spl/spl.c +++ b/common/spl/spl.c @@ -13,7 +13,6 @@ #include <nand.h> #include <fat.h> #include <version.h> -#include <i2c.h> #include <image.h> #include <malloc.h> #include <dm/root.h> @@ -203,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); @@ -211,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; diff --git a/common/spl/spl_fit.c b/common/spl/spl_fit.c index 9874708..069e94d 100644 --- a/common/spl/spl_fit.c +++ b/common/spl/spl_fit.c @@ -132,7 +132,7 @@ int spl_load_simple_fit(struct spl_load_info *info, ulong sector, void *fit) int data_offset, data_size; int base_offset, align_len = ARCH_DMA_MINALIGN - 1; int src_sector; - void *dst; + void *dst, *src; /* * Figure out where the external images start. This is the base for the @@ -206,8 +206,13 @@ int spl_load_simple_fit(struct spl_load_info *info, ulong sector, void *fit) return -EIO; debug("image: dst=%p, data_offset=%x, size=%x\n", dst, data_offset, data_size); - memcpy(dst, dst + get_aligned_image_overhead(info, data_offset), - data_size); + src = dst + get_aligned_image_overhead(info, data_offset); + +#ifdef CONFIG_SPL_FIT_IMAGE_POST_PROCESS + board_fit_image_post_process((void **)&src, (size_t *)&data_size); +#endif + + memcpy(dst, src, data_size); /* Figure out which device tree the board wants to use */ fdt_len = spl_fit_select_fdt(fit, images, &fdt_offset); @@ -236,8 +241,14 @@ int spl_load_simple_fit(struct spl_load_info *info, ulong sector, void *fit) */ debug("fdt: dst=%p, data_offset=%x, size=%x\n", dst, fdt_offset, fdt_len); - memcpy(load_ptr + data_size, - dst + get_aligned_image_overhead(info, fdt_offset), fdt_len); + src = dst + get_aligned_image_overhead(info, fdt_offset); + dst = load_ptr + data_size; + +#ifdef CONFIG_SPL_FIT_IMAGE_POST_PROCESS + board_fit_image_post_process((void **)&src, (size_t *)&fdt_len); +#endif + + memcpy(dst, src, fdt_len); return 0; } diff --git a/configs/am43xx_hs_evm_defconfig b/configs/am43xx_hs_evm_defconfig index 4856a19..68dfb6c 100644 --- a/configs/am43xx_hs_evm_defconfig +++ b/configs/am43xx_hs_evm_defconfig @@ -13,6 +13,7 @@ CONFIG_SPL_STACK_R=y CONFIG_FIT=y CONFIG_SYS_EXTRA_OPTIONS="CONS_INDEX=1, NAND" CONFIG_SPL_LOAD_FIT=y +CONFIG_SPL_FIT_IMAGE_POST_PROCESS=y CONFIG_HUSH_PARSER=y CONFIG_CMD_BOOTZ=y # CONFIG_CMD_IMLS is not set diff --git a/configs/am57xx_hs_evm_defconfig b/configs/am57xx_hs_evm_defconfig index e01e504..01a4701 100644 --- a/configs/am57xx_hs_evm_defconfig +++ b/configs/am57xx_hs_evm_defconfig @@ -40,4 +40,5 @@ CONFIG_USB_XHCI_DWC3=y CONFIG_FIT=y CONFIG_SPL_OF_LIBFDT=y CONFIG_SPL_LOAD_FIT=y +CONFIG_SPL_FIT_IMAGE_POST_PROCESS=y CONFIG_OF_LIST="am57xx-beagle-x15" diff --git a/configs/da850evm_defconfig b/configs/da850evm_defconfig index 0e281a5..40ab975 100644 --- a/configs/da850evm_defconfig +++ b/configs/da850evm_defconfig @@ -5,6 +5,7 @@ CONFIG_SPL=y CONFIG_SYS_EXTRA_OPTIONS="MAC_ADDR_IN_SPIFLASH" CONFIG_BOOTDELAY=3 CONFIG_HUSH_PARSER=y +CONFIG_CMD_BOOTZ=y CONFIG_SYS_PROMPT="U-Boot > " # CONFIG_CMD_IMLS is not set CONFIG_CMD_ASKENV=y diff --git a/configs/dra7xx_hs_evm_defconfig b/configs/dra7xx_hs_evm_defconfig index 6933ab5..eb01f41 100644 --- a/configs/dra7xx_hs_evm_defconfig +++ b/configs/dra7xx_hs_evm_defconfig @@ -58,4 +58,5 @@ CONFIG_G_DNL_PRODUCT_NUM=0xd022 CONFIG_FIT=y CONFIG_SPL_OF_LIBFDT=y CONFIG_SPL_LOAD_FIT=y +CONFIG_SPL_FIT_IMAGE_POST_PROCESS=y CONFIG_OF_LIST="dra7-evm dra72-evm" diff --git a/configs/firefly-rk3288_defconfig b/configs/firefly-rk3288_defconfig index 4af9120..bdafc71 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 diff --git a/configs/sandbox_spl_defconfig b/configs/sandbox_spl_defconfig new file mode 100644 index 0000000..0f6dda8 --- /dev/null +++ b/configs/sandbox_spl_defconfig @@ -0,0 +1,183 @@ +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_SPL_OF_PLATDATA=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/doc/README.ti-secure b/doc/README.ti-secure index 7fc9b9b..54c996d 100644 --- a/doc/README.ti-secure +++ b/doc/README.ti-secure @@ -19,69 +19,80 @@ control restrictions. Access must be requested and granted by TI before the package is viewable and downloadable. Contact TI, either online or by way of a local TI representative, to request access. -When CONFIG_TI_SECURE_DEVICE is set, the U-Boot SPL build process requires -the presence and use of these tools in order to create a viable boot image. -The build process will look for the environment variable TI_SECURE_DEV_PKG, -which should be the path of the installed SECDEV package. If the -TI_SECURE_DEV_PKG variable is not defined or if it is defined but doesn't -point to a valid SECDEV package, a warning is issued during the build to -indicate that a final secure bootable image was not created. - -Within the SECDEV package exists an image creation script: - -${TI_SECURE_DEV_PKG}/scripts/create-boot-image.sh - -This is called as part of the SPL/u-boot build process. As the secure boot -image formats and requirements differ between secure SOC from TI, the -purpose of this script is to abstract these details as much as possible. - -The script is basically the only required interface to the TI SECDEV package -for secure TI devices. - -Invoking the script for AM43xx Secure Devices -============================================= - -create-boot-image.sh <IMAGE_FLAG> <INPUT_FILE> <OUTPUT_FILE> <SPL_LOAD_ADDR> - -<IMAGE_FLAG> is a value that specifies the type of the image to generate OR -the action the image generation tool will take. Valid values are: - SPI_X-LOADER - Generates an image for SPI flash (byte swapped) - XIP_X-LOADER - Generates a single stage u-boot for NOR/QSPI XiP - ISSW - Generates an image for all other boot modes - -<INPUT_FILE> is the full path and filename of the public world boot loader -binary file (depending on the boot media, this is usually either -u-boot-spl.bin or u-boot.bin). - -<OUTPUT_FILE> is the full path and filename of the final secure image. The -output binary images should be used in place of the standard non-secure -binary images (see the platform-specific user's guides and releases notes -for how the non-secure images are typically used) +Booting of U-Boot SPL +===================== + + When CONFIG_TI_SECURE_DEVICE is set, the U-Boot SPL build process + requires the presence and use of these tools in order to create a + viable boot image. The build process will look for the environment + variable TI_SECURE_DEV_PKG, which should be the path of the installed + SECDEV package. If the TI_SECURE_DEV_PKG variable is not defined or + if it is defined but doesn't point to a valid SECDEV package, a + warning is issued during the build to indicate that a final secure + bootable image was not created. + + Within the SECDEV package exists an image creation script: + + ${TI_SECURE_DEV_PKG}/scripts/create-boot-image.sh + + This is called as part of the SPL/u-boot build process. As the secure + boot image formats and requirements differ between secure SOC from TI, + the purpose of this script is to abstract these details as much as + possible. + + The script is basically the only required interface to the TI SECDEV + package for creating a bootable SPL image for secure TI devices. + + Invoking the script for AM43xx Secure Devices + ============================================= + + create-boot-image.sh \ + <IMAGE_FLAG> <INPUT_FILE> <OUTPUT_FILE> <SPL_LOAD_ADDR> + + <IMAGE_FLAG> is a value that specifies the type of the image to + generate OR the action the image generation tool will take. Valid + values are: + SPI_X-LOADER - Generates an image for SPI flash (byte + swapped) + XIP_X-LOADER - Generates a single stage u-boot for + NOR/QSPI XiP + ISSW - Generates an image for all other boot modes + + <INPUT_FILE> is the full path and filename of the public world boot + loaderbinary file (depending on the boot media, this is usually + either u-boot-spl.bin or u-boot.bin). + + <OUTPUT_FILE> is the full path and filename of the final secure + image. The output binary images should be used in place of the standard + non-secure binary images (see the platform-specific user's guides and + releases notes for how the non-secure images are typically used) u-boot-spl_HS_SPI_X-LOADER - byte swapped boot image for SPI flash u-boot_HS_XIP_X-LOADER - boot image for NOR or QSPI flash u-boot-spl_HS_ISSW - boot image for all other boot media -<SPL_LOAD_ADDR> is the address at which SOC ROM should load the <INPUT_FILE> + <SPL_LOAD_ADDR> is the address at which SOC ROM should load the + <INPUT_FILE> -Invoking the script for DRA7xx/AM57xx Secure Devices -==================================================== + Invoking the script for DRA7xx/AM57xx Secure Devices + ==================================================== -create-boot-image.sh <IMAGE_TYPE> <INPUT_FILE> <OUTPUT_FILE> + create-boot-image.sh <IMAGE_TYPE> <INPUT_FILE> <OUTPUT_FILE> -<IMAGE_TYPE> is a value that specifies the type of the image to generate OR -the action the image generation tool will take. Valid values are: - X-LOADER - Generates an image for NOR or QSPI boot modes - MLO - Generates an image for SD/MMC/eMMC boot modes - ULO - Generates an image for USB/UART peripheral boot modes - Note: ULO is not yet used by the u-boot build process + <IMAGE_TYPE> is a value that specifies the type of the image to + generate OR the action the image generation tool will take. Valid + values are: + X-LOADER - Generates an image for NOR or QSPI boot modes + MLO - Generates an image for SD/MMC/eMMC boot modes + ULO - Generates an image for USB/UART peripheral boot modes + Note: ULO is not yet used by the u-boot build process -<INPUT_FILE> is the full path and filename of the public world boot loader -binary file (for this platform, this is always u-boot-spl.bin). + <INPUT_FILE> is the full path and filename of the public world boot + loader binary file (for this platform, this is always u-boot-spl.bin). -<OUTPUT_FILE> is the full path and filename of the final secure image. The -output binary images should be used in place of the standard non-secure -binary images (see the platform-specific user's guides and releases notes -for how the non-secure images are typically used) + <OUTPUT_FILE> is the full path and filename of the final secure image. + The output binary images should be used in place of the standard + non-secure binary images (see the platform-specific user's guides + and releases notes for how the non-secure images are typically used) u-boot-spl_HS_MLO - boot image for SD/MMC/eMMC. This image is copied to a file named MLO, which is the name that the device ROM bootloader requires for loading from @@ -89,3 +100,61 @@ for how the non-secure images are typically used) non-secure devices) u-boot-spl_HS_X-LOADER - boot image for all other flash memories including QSPI and NOR flash + +Booting of Primary U-Boot (u-boot.img) +====================================== + + The SPL image is responsible for loading the next stage boot loader, + which is the main u-boot image. For secure TI devices, the SPL will + be authenticated, as described above, as part of the particular + device's ROM boot process. In order to continue the secure boot + process, the authenticated SPL must authenticate the main u-boot + image that it loads. + + The configurations for secure TI platforms are written to make the boot + process use the FIT image format for the u-boot.img (CONFIG_SPL_FRAMEWORK + and CONFIG_SPL_LOAD_FIT). With these configurations the binary + components that the SPL loads include a specific DTB image and u-boot + image. These DTB image may be one of many available to the boot + process. In order to secure these components so that they can be + authenticated by the SPL as they are loaded from the FIT image, the + build procedure for secure TI devices will secure these images before + they are integrated into the FIT image. When those images are extracted + from the FIT image at boot time, they are post-processed to verify that + they are still secure. The outlined security-related SPL post-processing + is enabled through the CONFIG_SPL_FIT_IMAGE_POST_PROCESS option which + must be enabled for the secure boot scheme to work. In order to allow + verifying proper operation of the secure boot chain in case of successful + authentication messages like "Authentication passed: CERT_U-BOOT-NOD" are + output by the SPL to the console for each blob that got extracted from the + FIT image. Note that the last part of this log message is the (truncated) + name of the signing certificate embedded into the blob that got processed. + + The exact details of the how the images are secured is handled by the + SECDEV package. Within the SECDEV package exists a script to process + an input binary image: + + ${TI_SECURE_DEV_PKG}/scripts/secure-binary-image.sh + + This is called as part of the u-boot build process. As the secure + image formats and requirements can differ between the various secure + SOCs from TI, this script in the SECDEV package abstracts these + details. This script is essentially the only required interface to the + TI SECDEV package for creating a u-boot.img image for secure TI + devices. + + The SPL/u-boot code contains calls to dedicated secure ROM functions + to perform the validation on the secured images. The details of the + interface to those functions is shown in the code. The summary + is that they are accessed by invoking an ARM secure monitor call to + the device's secure ROM (fixed read-only-memory that is secure and + only accessible when the ARM core is operating in the secure mode). + + Invoking the secure-binary-image script for Secure Devices + ========================================================== + + secure-binary-image.sh <INPUT_FILE> <OUTPUT_FILE> + + <INPUT_FILE> is the full path and filename of the input binary image + + <OUTPUT_FILE> is the full path and filename of the output secure image. diff --git a/doc/driver-model/of-plat.txt b/doc/driver-model/of-plat.txt new file mode 100644 index 0000000..86e5e25 --- /dev/null +++ b/doc/driver-model/of-plat.txt @@ -0,0 +1,310 @@ +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 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 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 +strictly necessary. Notable problems include: + + - 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 + 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 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 + normally also supports device tree it must use #ifdef to separate + out this code, since the structures are only available in SPL. + + +How it works +------------ + +The feature is enabled by CONFIG SPL_OF_PLATDATA. This is only available +in SPL and should be tested with: + + #if CONFIG_IS_ENABLED(SPL_OF_PLATDATA) + +A new tool called 'dtoc' converts a device tree file either into a set of +struct declarations, one for each compatible node, or a set of +U_BOOT_DEVICE() declarations along with the actual platform data for each +device. As an example, consider this MMC node: + + sdmmc: dwmmc@ff0c0000 { + compatible = "rockchip,rk3288-dw-mshc"; + clock-freq-min-max = <400000 150000000>; + clocks = <&cru HCLK_SDMMC>, <&cru SCLK_SDMMC>, + <&cru SCLK_SDMMC_DRV>, <&cru SCLK_SDMMC_SAMPLE>; + clock-names = "biu", "ciu", "ciu_drv", "ciu_sample"; + fifo-depth = <0x100>; + interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_HIGH>; + reg = <0xff0c0000 0x4000>; + bus-width = <4>; + cap-mmc-highspeed; + cap-sd-highspeed; + card-detect-delay = <200>; + disable-wp; + num-slots = <1>; + pinctrl-names = "default"; + pinctrl-0 = <&sdmmc_clk>, <&sdmmc_cmd>, <&sdmmc_cd>, <&sdmmc_bus4>; + vmmc-supply = <&vcc_sd>; + status = "okay"; + u-boot,dm-pre-reloc; + }; + + +Some of these properties are dropped by U-Boot under control of the +CONFIG_OF_SPL_REMOVE_PROPS option. The rest are processed. This will produce +the following C struct declaration: + +struct dtd_rockchip_rk3288_dw_mshc { + fdt32_t bus_width; + bool cap_mmc_highspeed; + bool cap_sd_highspeed; + fdt32_t card_detect_delay; + fdt32_t clock_freq_min_max[2]; + struct phandle_2_cell clocks[4]; + bool disable_wp; + fdt32_t fifo_depth; + fdt32_t interrupts[3]; + fdt32_t num_slots; + fdt32_t reg[2]; + 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, + .platdata_size = sizeof(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. + + +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 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: + + #include <dt-structs.h> + + struct mmc_platdata { + #if CONFIG_IS_ENABLED(SPL_OF_PLATDATA) + /* 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 (or the C structures when of-platdata is used). + */ + int fifo_depth; + }; + + 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; + + 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) + /* Decode the of-platdata from the C structures */ + struct dtd_mmc *dtplat = &plat->dtplat; + + plat->fifo_depth = dtplat->fifo_depth; + #endif + /* Set up the device from the plat data */ + writel(plat->fifo_depth, ...) + } + + 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 +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. + +The device tree becomes in accessible when CONFIG_SPL_OF_PLATDATA is enabled, +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 +--------- + +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. 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. + +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. 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 <trini@konsulko.com>. + + +Future work +----------- +- Consider programmatically reading binding files instead of device tree + contents +- Complete the phandle feature +- Move to using a full Python libfdt module + +-- +Simon Glass <sjg@chromium.org> +Google, Inc +6/6/16 +Updated Independence Day 2016 diff --git a/drivers/clk/clk-uclass.c b/drivers/clk/clk-uclass.c index 6e4d672..e0f8567 100644 --- a/drivers/clk/clk-uclass.c +++ b/drivers/clk/clk-uclass.c @@ -10,6 +10,7 @@ #include <clk.h> #include <clk-uclass.h> #include <dm.h> +#include <dt-structs.h> #include <errno.h> 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 797e537..9c4d2b3 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/drivers/clk/clk_rk3288.c b/drivers/clk/clk_rk3288.c index 2285453..679f010 100644 --- a/drivers/clk/clk_rk3288.c +++ b/drivers/clk/clk_rk3288.c @@ -7,7 +7,9 @@ #include <common.h> #include <clk-uclass.h> #include <dm.h> +#include <dt-structs.h> #include <errno.h> +#include <mapmem.h> #include <syscon.h> #include <asm/io.h> #include <asm/arch/clock.h> @@ -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; @@ -783,13 +791,30 @@ 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) { +#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; +} + +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 +#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 @@ -813,12 +838,14 @@ 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, .probe = rk3288_clk_probe, }; diff --git a/drivers/core/device-remove.c b/drivers/core/device-remove.c index 0e56b23..a7f77b4 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 f7fb0cc..5bb1d77 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) @@ -608,7 +629,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)) { @@ -738,7 +759,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/drivers/core/lists.c b/drivers/core/lists.c index 0c27717..6a634e6 100644 --- a/drivers/core/lists.c +++ b/drivers/core/lists.c @@ -99,7 +99,7 @@ int device_bind_driver_to_node(struct udevice *parent, const char *drv_name, return 0; } -#if CONFIG_IS_ENABLED(OF_CONTROL) +#if CONFIG_IS_ENABLED(OF_CONTROL) && !CONFIG_IS_ENABLED(OF_PLATDATA) /** * driver_check_compatible() - Check if a driver is compatible with this node * diff --git a/drivers/core/regmap.c b/drivers/core/regmap.c index 519832f..0299ff0 100644 --- a/drivers/core/regmap.c +++ b/drivers/core/regmap.c @@ -15,6 +15,49 @@ 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, u32 *reg, int count, + struct regmap **mapp) +{ + 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 int regmap_init_mem(struct udevice *dev, struct regmap **mapp) { const void *blob = gd->fdt_blob; @@ -37,22 +80,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++) { @@ -64,6 +96,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/drivers/core/root.c b/drivers/core/root.c index 95886ad..1587024 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); diff --git a/drivers/core/syscon-uclass.c b/drivers/core/syscon-uclass.c index e03f46a..01bd968 100644 --- a/drivers/core/syscon-uclass.c +++ b/drivers/core/syscon-uclass.c @@ -29,7 +29,20 @@ static int syscon_pre_probe(struct udevice *dev) { struct syscon_uc_info *priv = dev_get_uclass_priv(dev); + /* + * With OF_PLATDATA we really have no way of knowing the format of + * the device-specific platform data. So we assume that it starts with + * a 'reg' member, and this holds a single address and size. Drivers + * using OF_PLATDATA will need to ensure that this is true. + */ +#if CONFIG_IS_ENABLED(OF_PLATDATA) + struct syscon_base_platdata *plat = dev_get_platdata(dev); + + return regmap_init_mem_platdata(dev, plat->reg, ARRAY_SIZE(plat->reg), + &priv->regmap); +#else return regmap_init_mem(dev, &priv->regmap); +#endif } int syscon_get_by_driver_data(ulong driver_data, struct udevice **devp) diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index 066639b..fff6f0c 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile @@ -29,12 +29,19 @@ 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 obj-$(CONFIG_SANDBOX) += swap_case.o +ifdef CONFIG_SPL_OF_PLATDATA +ifdef CONFIG_SPL_BUILD +obj-$(CONFIG_SANDBOX) += spltest_sandbox.o +endif +endif obj-$(CONFIG_SANDBOX) += syscon_sandbox.o obj-$(CONFIG_TWL4030_LED) += twl4030_led.o obj-$(CONFIG_FSL_IFC) += fsl_ifc.o diff --git a/drivers/misc/spltest_sandbox.c b/drivers/misc/spltest_sandbox.c new file mode 100644 index 0000000..1fef825 --- /dev/null +++ b/drivers/misc/spltest_sandbox.c @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2016 Google, Inc + * Written by Simon Glass <sjg@chromium.org> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <dm.h> +#include <dt-structs.h> + +DECLARE_GLOBAL_DATA_PTR; + +static int sandbox_spl_probe(struct udevice *dev) +{ + struct dtd_sandbox_spl_test *plat = dev_get_platdata(dev); + 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, +}; diff --git a/drivers/mmc/exynos_dw_mmc.c b/drivers/mmc/exynos_dw_mmc.c index 863bbb3..283befc 100644 --- a/drivers/mmc/exynos_dw_mmc.c +++ b/drivers/mmc/exynos_dw_mmc.c @@ -23,8 +23,21 @@ #define DWMMC_MMC0_SDR_TIMING_VAL 0x03030001 #define DWMMC_MMC2_SDR_TIMING_VAL 0x03020001 +#ifdef CONFIG_DM_MMC +#include <dm.h> +DECLARE_GLOBAL_DATA_PTR; + +struct exynos_mmc_plat { + struct mmc_config cfg; + struct mmc mmc; +}; +#endif + /* Exynos implmentation specific drver private data */ struct dwmci_exynos_priv_data { +#ifdef CONFIG_DM_MMC + struct dwmci_host host; +#endif u32 sdr_timing; }; @@ -80,11 +93,10 @@ static void exynos_dwmci_board_init(struct dwmci_host *host) exynos_dwmci_clksel(host); } -static int exynos_dwmci_core_init(struct dwmci_host *host, int index) +static int exynos_dwmci_core_init(struct dwmci_host *host) { unsigned int div; unsigned long freq, sclk; - struct dwmci_exynos_priv_data *priv = host->priv; if (host->bus_hz) freq = host->bus_hz; @@ -92,10 +104,10 @@ static int exynos_dwmci_core_init(struct dwmci_host *host, int index) freq = DWMMC_MAX_FREQ; /* request mmc clock vlaue of 52MHz. */ - sclk = get_mmc_clk(index); + sclk = get_mmc_clk(host->dev_index); div = DIV_ROUND_UP(sclk, freq); /* set the clock divisor for mmc */ - set_mmc_clk(index, div); + set_mmc_clk(host->dev_index, div); host->name = "EXYNOS DWMMC"; #ifdef CONFIG_EXYNOS5420 @@ -103,78 +115,35 @@ static int exynos_dwmci_core_init(struct dwmci_host *host, int index) #endif host->board_init = exynos_dwmci_board_init; - if (!priv->sdr_timing) { - if (index == 0) - priv->sdr_timing = DWMMC_MMC0_SDR_TIMING_VAL; - else if (index == 2) - priv->sdr_timing = DWMMC_MMC2_SDR_TIMING_VAL; - } - host->caps = MMC_MODE_DDR_52MHz; host->clksel = exynos_dwmci_clksel; - host->dev_index = index; host->get_mmc_clk = exynos_dwmci_get_clk; + +#ifndef CONFIG_DM_MMC /* Add the mmc channel to be registered with mmc core */ if (add_dwmci(host, DWMMC_MAX_FREQ, DWMMC_MIN_FREQ)) { - printf("DWMMC%d registration failed\n", index); + printf("DWMMC%d registration failed\n", host->dev_index); return -1; } - return 0; -} - -/* - * This function adds the mmc channel to be registered with mmc core. - * index - mmc channel number. - * regbase - register base address of mmc channel specified in 'index'. - * bus_width - operating bus width of mmc channel specified in 'index'. - * clksel - value to be written into CLKSEL register in case of FDT. - * NULL in case od non-FDT. - */ -int exynos_dwmci_add_port(int index, u32 regbase, int bus_width, u32 clksel) -{ - struct dwmci_host *host = NULL; - struct dwmci_exynos_priv_data *priv; - - host = malloc(sizeof(struct dwmci_host)); - if (!host) { - error("dwmci_host malloc fail!\n"); - return -ENOMEM; - } - - priv = malloc(sizeof(struct dwmci_exynos_priv_data)); - if (!priv) { - error("dwmci_exynos_priv_data malloc fail!\n"); - return -ENOMEM; - } - - host->ioaddr = (void *)regbase; - host->buswidth = bus_width; - - if (clksel) - priv->sdr_timing = clksel; - - host->priv = priv; +#endif - return exynos_dwmci_core_init(host, index); + return 0; } -#if CONFIG_IS_ENABLED(OF_CONTROL) static struct dwmci_host dwmci_host[DWMMC_MAX_CH_NUM]; static int do_dwmci_init(struct dwmci_host *host) { - int index, flag, err; - - index = host->dev_index; + int flag, err; flag = host->buswidth == 8 ? PINMUX_FLAG_8BIT_MODE : PINMUX_FLAG_NONE; err = exynos_pinmux_config(host->dev_id, flag); if (err) { - printf("DWMMC%d not configure\n", index); + printf("DWMMC%d not configure\n", host->dev_index); return err; } - return exynos_dwmci_core_init(host, index); + return exynos_dwmci_core_init(host); } static int exynos_dwmci_get_config(const void *blob, int node, @@ -197,13 +166,14 @@ static int exynos_dwmci_get_config(const void *blob, int node, if (host->dev_index == host->dev_id) host->dev_index = host->dev_id - PERIPH_ID_SDMMC0; - /* Get the bus width from the device node */ - host->buswidth = fdtdec_get_int(blob, node, "samsung,bus-width", 0); - if (host->buswidth <= 0) { - printf("DWMMC%d: Can't get bus-width\n", host->dev_index); + if (host->dev_index > 4) { + printf("DWMMC%d: Can't get the dev index\n", host->dev_index); return -EINVAL; } + /* Get the bus width from the device node (Default is 4bit buswidth) */ + host->buswidth = fdtdec_get_int(blob, node, "samsung,bus-width", 4); + /* Set the base address from the device node */ base = fdtdec_get_addr(blob, node, "reg"); if (!base) { @@ -265,15 +235,13 @@ static int exynos_dwmci_process_node(const void *blob, int exynos_dwmmc_init(const void *blob) { - int compat_id; int node_list[DWMMC_MAX_CH_NUM]; int boot_dev_node; int err = 0, count; - compat_id = COMPAT_SAMSUNG_EXYNOS_DWMMC; - count = fdtdec_find_aliases_for_id(blob, "mmc", - compat_id, node_list, DWMMC_MAX_CH_NUM); + COMPAT_SAMSUNG_EXYNOS_DWMMC, node_list, + DWMMC_MAX_CH_NUM); /* For DWMMC always set boot device as mmc 0 */ if (count >= 3 && get_boot_mode() == BOOT_MODE_SD) { @@ -286,4 +254,58 @@ int exynos_dwmmc_init(const void *blob) return err; } + +#ifdef CONFIG_DM_MMC +static int exynos_dwmmc_probe(struct udevice *dev) +{ + struct exynos_mmc_plat *plat = dev_get_platdata(dev); + struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev); + struct dwmci_exynos_priv_data *priv = dev_get_priv(dev); + struct dwmci_host *host = &priv->host; + int err; + + err = exynos_dwmci_get_config(gd->fdt_blob, dev->of_offset, host); + if (err) + return err; + err = do_dwmci_init(host); + if (err) + return err; + + dwmci_setup_cfg(&plat->cfg, host->name, host->buswidth, host->caps, + DWMMC_MAX_FREQ, DWMMC_MIN_FREQ); + host->mmc = &plat->mmc; + host->mmc->priv = &priv->host; + host->priv = dev; + upriv->mmc = host->mmc; + + return dwmci_probe(dev); +} + +static int exynos_dwmmc_bind(struct udevice *dev) +{ + struct exynos_mmc_plat *plat = dev_get_platdata(dev); + int ret; + + ret = dwmci_bind(dev, &plat->mmc, &plat->cfg); + if (ret) + return ret; + + return 0; +} + +static const struct udevice_id exynos_dwmmc_ids[] = { + { .compatible = "samsung,exynos4412-dw-mshc" }, + { } +}; + +U_BOOT_DRIVER(exynos_dwmmc_drv) = { + .name = "exynos_dwmmc", + .id = UCLASS_MMC, + .of_match = exynos_dwmmc_ids, + .bind = exynos_dwmmc_bind, + .ops = &dm_dwmci_ops, + .probe = exynos_dwmmc_probe, + .priv_auto_alloc_size = sizeof(struct dwmci_exynos_priv_data), + .platdata_auto_alloc_size = sizeof(struct exynos_mmc_plat), +}; #endif diff --git a/drivers/mmc/rockchip_dw_mmc.c b/drivers/mmc/rockchip_dw_mmc.c index 691a515..020a59b 100644 --- a/drivers/mmc/rockchip_dw_mmc.c +++ b/drivers/mmc/rockchip_dw_mmc.c @@ -7,8 +7,10 @@ #include <common.h> #include <clk.h> #include <dm.h> +#include <dt-structs.h> #include <dwmmc.h> #include <errno.h> +#include <mapmem.h> #include <pwrseq.h> #include <syscon.h> #include <asm/gpio.h> @@ -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; }; @@ -26,6 +31,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) @@ -45,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; @@ -61,6 +70,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; +#endif return 0; } @@ -71,28 +90,34 @@ 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; +#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; - - 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; - +#endif 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 +130,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; @@ -132,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, diff --git a/drivers/pinctrl/rockchip/pinctrl_rk3288.c b/drivers/pinctrl/rockchip/pinctrl_rk3288.c index 1fa1daa..8cb3b82 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), diff --git a/drivers/rtc/date.c b/drivers/rtc/date.c index 8c643a0..bfa2e13 100644 --- a/drivers/rtc/date.c +++ b/drivers/rtc/date.c @@ -5,10 +5,6 @@ * SPDX-License-Identifier: GPL-2.0+ */ -/* - * Date & Time support for Philips PCF8563 RTC - */ - #include <common.h> #include <command.h> #include <errno.h> @@ -28,53 +24,52 @@ static int month_days[12] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; +static int month_offset[] = { + 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 +}; + /* * This only works for the Gregorian calendar - i.e. after 1752 (in the UK) */ int rtc_calc_weekday(struct rtc_time *tm) { - int leapsToDate; - int lastYear; + int leaps_to_date; + int last_year; int day; - int MonthOffset[] = { 0,31,59,90,120,151,181,212,243,273,304,334 }; if (tm->tm_year < 1753) - return -EINVAL; - lastYear=tm->tm_year-1; + return -1; + last_year = tm->tm_year - 1; - /* - * Number of leap corrections to apply up to end of last year - */ - leapsToDate = lastYear/4 - lastYear/100 + lastYear/400; + /* Number of leap corrections to apply up to end of last year */ + leaps_to_date = last_year / 4 - last_year / 100 + last_year / 400; /* * This year is a leap year if it is divisible by 4 except when it is * divisible by 100 unless it is divisible by 400 * - * e.g. 1904 was a leap year, 1900 was not, 1996 is, and 2000 will be + * e.g. 1904 was a leap year, 1900 was not, 1996 is, and 2000 is. */ - if((tm->tm_year%4==0) && - ((tm->tm_year%100!=0) || (tm->tm_year%400==0)) && - (tm->tm_mon>2)) { - /* - * We are past Feb. 29 in a leap year - */ - day=1; + if (tm->tm_year % 4 == 0 && + ((tm->tm_year % 100 != 0) || (tm->tm_year % 400 == 0)) && + tm->tm_mon > 2) { + /* We are past Feb. 29 in a leap year */ + day = 1; } else { - day=0; + day = 0; } - day += lastYear*365 + leapsToDate + MonthOffset[tm->tm_mon-1] + tm->tm_mday; - - tm->tm_wday=day%7; + day += last_year * 365 + leaps_to_date + month_offset[tm->tm_mon - 1] + + tm->tm_mday; + tm->tm_wday = day % 7; return 0; } int rtc_to_tm(int tim, struct rtc_time *tm) { - register int i; - register long hms, day; + register int i; + register long hms, day; day = tim / SECDAY; hms = tim % SECDAY; @@ -85,22 +80,19 @@ int rtc_to_tm(int tim, struct rtc_time *tm) tm->tm_sec = (hms % 3600) % 60; /* Number of years in days */ - for (i = STARTOFTIME; day >= days_in_year(i); i++) { + for (i = STARTOFTIME; day >= days_in_year(i); i++) day -= days_in_year(i); - } tm->tm_year = i; /* Number of months in days left */ - if (leapyear(tm->tm_year)) { + if (leapyear(tm->tm_year)) days_in_month(FEBRUARY) = 29; - } - for (i = 1; day >= days_in_month(i); i++) { + for (i = 1; day >= days_in_month(i); i++) day -= days_in_month(i); - } days_in_month(FEBRUARY) = 28; tm->tm_mon = i; - /* Days are what is left over (+1) from all that. */ + /* Days are what is left over (+1) from all that */ tm->tm_mday = day + 1; /* Zero unused fields */ @@ -113,19 +105,20 @@ int rtc_to_tm(int tim, struct rtc_time *tm) return rtc_calc_weekday(tm); } -/* Converts Gregorian date to seconds since 1970-01-01 00:00:00. +/* + * Converts Gregorian date to seconds since 1970-01-01 00:00:00. * Assumes input in normal date format, i.e. 1980-12-31 23:59:59 * => year=1980, mon=12, day=31, hour=23, min=59, sec=59. * * [For the Julian calendar (which was used in Russia before 1917, * Britain & colonies before 1752, anywhere else before 1582, * and is still in use by some communities) leave out the - * -year/100+year/400 terms, and add 10.] + * -year / 100 + year / 400 terms, and add 10.] * * This algorithm was first published by Gauss (I think). * * WARNING: this function will overflow on 2106-02-07 06:28:16 on - * machines were long is 32-bit! (However, as time_t is signed, we + * machines where long is 32-bit! (However, as time_t is signed, we * will already get problems at other places on 2038-01-19 03:14:08) */ unsigned long rtc_mktime(const struct rtc_time *tm) @@ -135,8 +128,8 @@ unsigned long rtc_mktime(const struct rtc_time *tm) int days, hours; mon -= 2; - if (0 >= (int)mon) { /* 1..12 -> 11,12,1..10 */ - mon += 12; /* Puts Feb last since it has leap day */ + if (0 >= (int)mon) { /* 1..12 -> 11, 12, 1..10 */ + mon += 12; /* Puts Feb last since it has leap day */ year -= 1; } diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig index 0e38903..9ff7234 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 92cbea5..6986d65 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/ns16550.c b/drivers/serial/ns16550.c index c6cb3eb..88fca15 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 */ diff --git a/drivers/serial/sandbox.c b/drivers/serial/sandbox.c index 58f882b..bcc3465 100644 --- a/drivers/serial/sandbox.c +++ b/drivers/serial/sandbox.c @@ -115,7 +115,9 @@ static int sandbox_serial_pending(struct udevice *dev, bool input) return 0; os_usleep(100); +#ifndef CONFIG_SPL_BUILD video_sync_all(); +#endif if (next_index == serial_buf_read) return 1; /* buffer full */ diff --git a/drivers/serial/serial-uclass.c b/drivers/serial/serial-uclass.c index 0ce5c44..19f38e1 100644 --- a/drivers/serial/serial-uclass.c +++ b/drivers/serial/serial-uclass.c @@ -33,7 +33,13 @@ static void serial_find_console_or_panic(void) struct udevice *dev; int node; - if (CONFIG_IS_ENABLED(OF_CONTROL) && blob) { + if (CONFIG_IS_ENABLED(OF_PLATDATA)) { + uclass_first_device(UCLASS_SERIAL, &dev); + if (dev) { + gd->cur_serial_dev = dev; + return; + } + } else if (CONFIG_IS_ENABLED(OF_CONTROL) && blob) { /* Check for a chosen console */ node = fdtdec_get_chosen_node(blob, "stdout-path"); if (node < 0) { diff --git a/drivers/serial/serial_rockchip.c b/drivers/serial/serial_rockchip.c new file mode 100644 index 0000000..6bac95a --- /dev/null +++ b/drivers/serial/serial_rockchip.c @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2015 Google, Inc + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <debug_uart.h> +#include <dm.h> +#include <dt-structs.h> +#include <ns16550.h> +#include <serial.h> +#include <asm/arch/clock.h> + +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, +}; diff --git a/drivers/serial/serial_stm32x7.c b/drivers/serial/serial_stm32x7.c index cfbfab7..592c0bd 100644 --- a/drivers/serial/serial_stm32x7.c +++ b/drivers/serial/serial_stm32x7.c @@ -9,6 +9,7 @@ #include <dm.h> #include <asm/io.h> #include <serial.h> +#include <asm/arch/stm32.h> #include <dm/platform_data/serial_stm32x7.h> #include "serial_stm32x7.h" @@ -18,7 +19,20 @@ static int stm32_serial_setbrg(struct udevice *dev, int baudrate) { struct stm32x7_serial_platdata *plat = dev->platdata; struct stm32_usart *const usart = plat->base; - writel(plat->clock/baudrate, &usart->brr); + u32 clock, int_div, frac_div, tmp; + + if (((u32)usart & STM32_BUS_MASK) == APB1_PERIPH_BASE) + clock = clock_get(CLOCK_APB1); + else if (((u32)usart & STM32_BUS_MASK) == APB2_PERIPH_BASE) + clock = clock_get(CLOCK_APB2); + else + return -EINVAL; + + int_div = (25 * clock) / (4 * baudrate); + tmp = ((int_div / 100) << USART_BRR_M_SHIFT) & USART_BRR_M_MASK; + frac_div = int_div - (100 * (tmp >> USART_BRR_M_SHIFT)); + tmp |= (((frac_div * 16) + 50) / 100) & USART_BRR_F_MASK; + writel(tmp, &usart->brr); return 0; } diff --git a/dts/Kconfig b/dts/Kconfig index c56c129..4b7d8b1 100644 --- a/dts/Kconfig +++ b/dts/Kconfig @@ -85,4 +85,25 @@ config OF_SPL_REMOVE_PROPS can be discarded. This option defines the list of properties to discard. +config SPL_OF_PLATDATA + bool "Generate platform data for use in SPL" + depends on SPL_OF_CONTROL + help + For very constrained SPL environments the overhead of decoding + device tree nodes and converting their contents into platform data + is too large. This overhead includes libfdt code as well as the + device tree contents itself. The latter is fairly compact, but the + former can add 3KB or more to a Thumb 2 Image. + + This option enables generation of platform data from the device + tree as C code. This code creates devices using U_BOOT_DEVICE() + declarations. The benefit is that it allows driver code to access + the platform data directly in C structures, avoidin the libfdt + overhead. + + This option works by generating C structure declarations for each + compatible string, then adding platform data and U_BOOT_DEVICE + declarations for each node. See README.platdata for more + information. + endmenu diff --git a/include/clk.h b/include/clk.h index 2f31cf7..161bc28 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. * diff --git a/include/common.h b/include/common.h index 3feaae6..e9f0dea 100644 --- a/include/common.h +++ b/include/common.h @@ -101,6 +101,13 @@ typedef volatile unsigned char vu_char; #define _DEBUG 0 #endif +#ifdef CONFIG_SPL_BUILD +#define _SPL_BUILD 1 +#else +#define _SPL_BUILD 0 +#endif + +/* Define this at the top of a file to add a prefix to debug messages */ #ifndef pr_fmt #define pr_fmt(fmt) fmt #endif @@ -116,9 +123,14 @@ typedef volatile unsigned char vu_char; printf(pr_fmt(fmt), ##args); \ } while (0) +/* Show a message if DEBUG is defined in a file */ #define debug(fmt, args...) \ debug_cond(_DEBUG, fmt, ##args) +/* Show a message if not in SPL */ +#define warn_non_spl(fmt, args...) \ + debug_cond(!_SPL_BUILD, fmt, ##args) + /* * An assertion is run-time check done in debug mode only. If DEBUG is not * defined then it is skipped. If DEBUG is defined and the assertion fails, diff --git a/include/configs/dragonboard410c.h b/include/configs/dragonboard410c.h index 4b00922..1dbe219 100644 --- a/include/configs/dragonboard410c.h +++ b/include/configs/dragonboard410c.h @@ -84,8 +84,8 @@ #define BOOT_TARGET_DEVICES(func) \ func(USB, usb, 0) \ - func(MMC, mmc, 0) \ func(MMC, mmc, 1) \ + func(MMC, mmc, 0) \ func(DHCP, dhcp, na) #include <config_distro_bootcmd.h> @@ -126,6 +126,8 @@ REFLASH(dragonboard/u-boot.img, 8)\ "fdtfile=apq8016-sbc.dtb\0" \ "fdt_addr_r=0x83000000\0"\ "ramdisk_addr_r=0x84000000\0"\ + "scriptaddr=0x90000000\0"\ + "pxefile_addr_r=0x90100000\0"\ BOOTENV #define CONFIG_ENV_IS_NOWHERE diff --git a/include/configs/sandbox.h b/include/configs/sandbox.h index 23a0c40..4de89f8 100644 --- a/include/configs/sandbox.h +++ b/include/configs/sandbox.h @@ -16,8 +16,10 @@ #endif +#ifndef CONFIG_SPL_BUILD #define CONFIG_IO_TRACE #define CONFIG_CMD_IOTRACE +#endif #ifndef CONFIG_TIMER #define CONFIG_SYS_TIMER_RATE 1000000 @@ -192,6 +194,7 @@ #define CONFIG_CMD_LZMADEC #define CONFIG_CMD_DATE +#ifndef CONFIG_SPL_BUILD #define CONFIG_CMD_IDE #define CONFIG_SYS_IDE_MAXBUS 1 #define CONFIG_SYS_ATA_IDE0_OFFSET 0 @@ -201,6 +204,7 @@ #define CONFIG_SYS_ATA_REG_OFFSET 1 #define CONFIG_SYS_ATA_ALT_OFFSET 2 #define CONFIG_SYS_ATA_STRIDE 4 +#endif #define CONFIG_SCSI #define CONFIG_SCSI_AHCI_PLAT diff --git a/include/configs/sandbox_spl.h b/include/configs/sandbox_spl.h new file mode 100644 index 0000000..ffc3098 --- /dev/null +++ b/include/configs/sandbox_spl.h @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2016 Google, Inc + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef __SANDBOX_SPL_CONFIG_H +#define __SANDBOX_SPL_CONFIG_H + +#include <configs/sandbox.h> + +#define CONFIG_SPL_BOARD_INIT + +#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 diff --git a/include/configs/stm32f746-disco.h b/include/configs/stm32f746-disco.h index e544a21..4391bff 100644 --- a/include/configs/stm32f746-disco.h +++ b/include/configs/stm32f746-disco.h @@ -24,13 +24,13 @@ * Configuration of the external SDRAM memory */ #define CONFIG_NR_DRAM_BANKS 1 -#define CONFIG_SYS_RAM_SIZE ((64 + 192) << 10) +#define CONFIG_SYS_RAM_SIZE (8 * 1024 * 1024) #define CONFIG_SYS_RAM_CS 1 #define CONFIG_SYS_RAM_FREQ_DIV 2 -#define CONFIG_SYS_RAM_BASE 0x20000000 +#define CONFIG_SYS_RAM_BASE 0xC0000000 #define CONFIG_SYS_SDRAM_BASE CONFIG_SYS_RAM_BASE -#define CONFIG_SYS_LOAD_ADDR 0x20000000 -#define CONFIG_LOADADDR 0x20000000 +#define CONFIG_SYS_LOAD_ADDR 0xC0400000 +#define CONFIG_LOADADDR 0xC0400000 #define CONFIG_SYS_MAX_FLASH_SECT 8 #define CONFIG_SYS_MAX_FLASH_BANKS 1 @@ -42,7 +42,8 @@ #define CONFIG_STM32_FLASH #define CONFIG_STM32X7_SERIAL -#define CONFIG_SYS_CLK_FREQ 16*1000*1000 /* 180 MHz */ +#define CONFIG_STM32_HSE_HZ 25000000 +#define CONFIG_SYS_CLK_FREQ 200000000 /* 200 MHz */ #define CONFIG_SYS_HZ_CLOCK 1000000 /* Timer is clocked at 1MHz */ #define CONFIG_CMDLINE_TAG diff --git a/include/dm/device.h b/include/dm/device.h index 1bfcf3b..c825d47 100644 --- a/include/dm/device.h +++ b/include/dm/device.h @@ -42,7 +42,9 @@ 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) + +#define DM_FLAG_OF_PLATDATA (1 << 8) /** * struct udevice - An instance of a driver @@ -553,7 +555,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 diff --git a/include/dm/platdata.h b/include/dm/platdata.h index 6f4f001..488b2ab 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/include/dt-structs.h b/include/dt-structs.h new file mode 100644 index 0000000..e13afa6 --- /dev/null +++ b/include/dt-structs.h @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2016 Google, Inc + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef __DT_STTUCTS +#define __DT_STTUCTS + +/* These structures may only be used in SPL */ +#if CONFIG_IS_ENABLED(OF_PLATDATA) +struct phandle_2_cell { + const void *node; + int id; +}; +#include <generated/dt-structs.h> +#endif + +#endif diff --git a/include/image.h b/include/image.h index d788c26..2a5b560 100644 --- a/include/image.h +++ b/include/image.h @@ -123,62 +123,79 @@ struct lmb; # define IMAGE_OF_SYSTEM_SETUP 0 #endif +enum ih_category { + IH_ARCH, + IH_COMP, + IH_OS, + IH_TYPE, + + IH_COUNT, +}; + /* * Operating System Codes */ -#define IH_OS_INVALID 0 /* Invalid OS */ -#define IH_OS_OPENBSD 1 /* OpenBSD */ -#define IH_OS_NETBSD 2 /* NetBSD */ -#define IH_OS_FREEBSD 3 /* FreeBSD */ -#define IH_OS_4_4BSD 4 /* 4.4BSD */ -#define IH_OS_LINUX 5 /* Linux */ -#define IH_OS_SVR4 6 /* SVR4 */ -#define IH_OS_ESIX 7 /* Esix */ -#define IH_OS_SOLARIS 8 /* Solaris */ -#define IH_OS_IRIX 9 /* Irix */ -#define IH_OS_SCO 10 /* SCO */ -#define IH_OS_DELL 11 /* Dell */ -#define IH_OS_NCR 12 /* NCR */ -#define IH_OS_LYNXOS 13 /* LynxOS */ -#define IH_OS_VXWORKS 14 /* VxWorks */ -#define IH_OS_PSOS 15 /* pSOS */ -#define IH_OS_QNX 16 /* QNX */ -#define IH_OS_U_BOOT 17 /* Firmware */ -#define IH_OS_RTEMS 18 /* RTEMS */ -#define IH_OS_ARTOS 19 /* ARTOS */ -#define IH_OS_UNITY 20 /* Unity OS */ -#define IH_OS_INTEGRITY 21 /* INTEGRITY */ -#define IH_OS_OSE 22 /* OSE */ -#define IH_OS_PLAN9 23 /* Plan 9 */ -#define IH_OS_OPENRTOS 24 /* OpenRTOS */ +enum { + IH_OS_INVALID = 0, /* Invalid OS */ + IH_OS_OPENBSD, /* OpenBSD */ + IH_OS_NETBSD, /* NetBSD */ + IH_OS_FREEBSD, /* FreeBSD */ + IH_OS_4_4BSD, /* 4.4BSD */ + IH_OS_LINUX, /* Linux */ + IH_OS_SVR4, /* SVR4 */ + IH_OS_ESIX, /* Esix */ + IH_OS_SOLARIS, /* Solaris */ + IH_OS_IRIX, /* Irix */ + IH_OS_SCO, /* SCO */ + IH_OS_DELL, /* Dell */ + IH_OS_NCR, /* NCR */ + IH_OS_LYNXOS, /* LynxOS */ + IH_OS_VXWORKS, /* VxWorks */ + IH_OS_PSOS, /* pSOS */ + IH_OS_QNX, /* QNX */ + IH_OS_U_BOOT, /* Firmware */ + IH_OS_RTEMS, /* RTEMS */ + IH_OS_ARTOS, /* ARTOS */ + IH_OS_UNITY, /* Unity OS */ + IH_OS_INTEGRITY, /* INTEGRITY */ + IH_OS_OSE, /* OSE */ + IH_OS_PLAN9, /* Plan 9 */ + IH_OS_OPENRTOS, /* OpenRTOS */ + + IH_OS_COUNT, +}; /* * CPU Architecture Codes (supported by Linux) */ -#define IH_ARCH_INVALID 0 /* Invalid CPU */ -#define IH_ARCH_ALPHA 1 /* Alpha */ -#define IH_ARCH_ARM 2 /* ARM */ -#define IH_ARCH_I386 3 /* Intel x86 */ -#define IH_ARCH_IA64 4 /* IA64 */ -#define IH_ARCH_MIPS 5 /* MIPS */ -#define IH_ARCH_MIPS64 6 /* MIPS 64 Bit */ -#define IH_ARCH_PPC 7 /* PowerPC */ -#define IH_ARCH_S390 8 /* IBM S390 */ -#define IH_ARCH_SH 9 /* SuperH */ -#define IH_ARCH_SPARC 10 /* Sparc */ -#define IH_ARCH_SPARC64 11 /* Sparc 64 Bit */ -#define IH_ARCH_M68K 12 /* M68K */ -#define IH_ARCH_MICROBLAZE 14 /* MicroBlaze */ -#define IH_ARCH_NIOS2 15 /* Nios-II */ -#define IH_ARCH_BLACKFIN 16 /* Blackfin */ -#define IH_ARCH_AVR32 17 /* AVR32 */ -#define IH_ARCH_ST200 18 /* STMicroelectronics ST200 */ -#define IH_ARCH_SANDBOX 19 /* Sandbox architecture (test only) */ -#define IH_ARCH_NDS32 20 /* ANDES Technology - NDS32 */ -#define IH_ARCH_OPENRISC 21 /* OpenRISC 1000 */ -#define IH_ARCH_ARM64 22 /* ARM64 */ -#define IH_ARCH_ARC 23 /* Synopsys DesignWare ARC */ -#define IH_ARCH_X86_64 24 /* AMD x86_64, Intel and Via */ +enum { + IH_ARCH_INVALID = 0, /* Invalid CPU */ + IH_ARCH_ALPHA, /* Alpha */ + IH_ARCH_ARM, /* ARM */ + IH_ARCH_I386, /* Intel x86 */ + IH_ARCH_IA64, /* IA64 */ + IH_ARCH_MIPS, /* MIPS */ + IH_ARCH_MIPS64, /* MIPS 64 Bit */ + IH_ARCH_PPC, /* PowerPC */ + IH_ARCH_S390, /* IBM S390 */ + IH_ARCH_SH, /* SuperH */ + IH_ARCH_SPARC, /* Sparc */ + IH_ARCH_SPARC64, /* Sparc 64 Bit */ + IH_ARCH_M68K, /* M68K */ + IH_ARCH_MICROBLAZE, /* MicroBlaze */ + IH_ARCH_NIOS2, /* Nios-II */ + IH_ARCH_BLACKFIN, /* Blackfin */ + IH_ARCH_AVR32, /* AVR32 */ + IH_ARCH_ST200, /* STMicroelectronics ST200 */ + IH_ARCH_SANDBOX, /* Sandbox architecture (test only) */ + IH_ARCH_NDS32, /* ANDES Technology - NDS32 */ + IH_ARCH_OPENRISC, /* OpenRISC 1000 */ + IH_ARCH_ARM64, /* ARM64 */ + IH_ARCH_ARC, /* Synopsys DesignWare ARC */ + IH_ARCH_X86_64, /* AMD x86_64, Intel and Via */ + + IH_ARCH_COUNT, +}; /* * Image Types @@ -219,47 +236,54 @@ struct lmb; * as command interpreter (=> Shell Scripts). */ -#define IH_TYPE_INVALID 0 /* Invalid Image */ -#define IH_TYPE_STANDALONE 1 /* Standalone Program */ -#define IH_TYPE_KERNEL 2 /* OS Kernel Image */ -#define IH_TYPE_RAMDISK 3 /* RAMDisk Image */ -#define IH_TYPE_MULTI 4 /* Multi-File Image */ -#define IH_TYPE_FIRMWARE 5 /* Firmware Image */ -#define IH_TYPE_SCRIPT 6 /* Script file */ -#define IH_TYPE_FILESYSTEM 7 /* Filesystem Image (any type) */ -#define IH_TYPE_FLATDT 8 /* Binary Flat Device Tree Blob */ -#define IH_TYPE_KWBIMAGE 9 /* Kirkwood Boot Image */ -#define IH_TYPE_IMXIMAGE 10 /* Freescale IMXBoot Image */ -#define IH_TYPE_UBLIMAGE 11 /* Davinci UBL Image */ -#define IH_TYPE_OMAPIMAGE 12 /* TI OMAP Config Header Image */ -#define IH_TYPE_AISIMAGE 13 /* TI Davinci AIS Image */ -#define IH_TYPE_KERNEL_NOLOAD 14 /* OS Kernel Image, can run from any load address */ -#define IH_TYPE_PBLIMAGE 15 /* Freescale PBL Boot Image */ -#define IH_TYPE_MXSIMAGE 16 /* Freescale MXSBoot Image */ -#define IH_TYPE_GPIMAGE 17 /* TI Keystone GPHeader Image */ -#define IH_TYPE_ATMELIMAGE 18 /* ATMEL ROM bootable Image */ -#define IH_TYPE_SOCFPGAIMAGE 19 /* Altera SOCFPGA Preloader */ -#define IH_TYPE_X86_SETUP 20 /* x86 setup.bin Image */ -#define IH_TYPE_LPC32XXIMAGE 21 /* x86 setup.bin Image */ -#define IH_TYPE_LOADABLE 22 /* A list of typeless images */ -#define IH_TYPE_RKIMAGE 23 /* Rockchip Boot Image */ -#define IH_TYPE_RKSD 24 /* Rockchip SD card */ -#define IH_TYPE_RKSPI 25 /* Rockchip SPI image */ -#define IH_TYPE_ZYNQIMAGE 26 /* Xilinx Zynq Boot Image */ -#define IH_TYPE_ZYNQMPIMAGE 27 /* Xilinx ZynqMP Boot Image */ -#define IH_TYPE_FPGA 28 /* FPGA Image */ - -#define IH_TYPE_COUNT 29 /* Number of image types */ +enum { + IH_TYPE_INVALID = 0, /* Invalid Image */ + IH_TYPE_STANDALONE, /* Standalone Program */ + IH_TYPE_KERNEL, /* OS Kernel Image */ + IH_TYPE_RAMDISK, /* RAMDisk Image */ + IH_TYPE_MULTI, /* Multi-File Image */ + IH_TYPE_FIRMWARE, /* Firmware Image */ + IH_TYPE_SCRIPT, /* Script file */ + IH_TYPE_FILESYSTEM, /* Filesystem Image (any type) */ + IH_TYPE_FLATDT, /* Binary Flat Device Tree Blob */ + IH_TYPE_KWBIMAGE, /* Kirkwood Boot Image */ + IH_TYPE_IMXIMAGE, /* Freescale IMXBoot Image */ + IH_TYPE_UBLIMAGE, /* Davinci UBL Image */ + IH_TYPE_OMAPIMAGE, /* TI OMAP Config Header Image */ + IH_TYPE_AISIMAGE, /* TI Davinci AIS Image */ + /* OS Kernel Image, can run from any load address */ + IH_TYPE_KERNEL_NOLOAD, + IH_TYPE_PBLIMAGE, /* Freescale PBL Boot Image */ + IH_TYPE_MXSIMAGE, /* Freescale MXSBoot Image */ + IH_TYPE_GPIMAGE, /* TI Keystone GPHeader Image */ + IH_TYPE_ATMELIMAGE, /* ATMEL ROM bootable Image */ + IH_TYPE_SOCFPGAIMAGE, /* Altera SOCFPGA Preloader */ + IH_TYPE_X86_SETUP, /* x86 setup.bin Image */ + IH_TYPE_LPC32XXIMAGE, /* x86 setup.bin Image */ + IH_TYPE_LOADABLE, /* A list of typeless images */ + IH_TYPE_RKIMAGE, /* Rockchip Boot Image */ + IH_TYPE_RKSD, /* Rockchip SD card */ + IH_TYPE_RKSPI, /* Rockchip SPI image */ + IH_TYPE_ZYNQIMAGE, /* Xilinx Zynq Boot Image */ + IH_TYPE_ZYNQMPIMAGE, /* Xilinx ZynqMP Boot Image */ + IH_TYPE_FPGA, /* FPGA Image */ + + IH_TYPE_COUNT, /* Number of image types */ +}; /* * Compression Types */ -#define IH_COMP_NONE 0 /* No Compression Used */ -#define IH_COMP_GZIP 1 /* gzip Compression Used */ -#define IH_COMP_BZIP2 2 /* bzip2 Compression Used */ -#define IH_COMP_LZMA 3 /* lzma Compression Used */ -#define IH_COMP_LZO 4 /* lzo Compression Used */ -#define IH_COMP_LZ4 5 /* lz4 Compression Used */ +enum { + IH_COMP_NONE = 0, /* No Compression Used */ + IH_COMP_GZIP, /* gzip Compression Used */ + IH_COMP_BZIP2, /* bzip2 Compression Used */ + IH_COMP_LZMA, /* lzma Compression Used */ + IH_COMP_LZO, /* lzo Compression Used */ + IH_COMP_LZ4, /* lz4 Compression Used */ + + IH_COMP_COUNT, +}; #define IH_MAGIC 0x27051956 /* Image Magic Number */ #define IH_NMLEN 32 /* Image Name Length */ @@ -454,6 +478,40 @@ const char *genimg_get_comp_name(uint8_t comp); */ const char *genimg_get_comp_short_name(uint8_t comp); +/** + * genimg_get_cat_name() - Get the name of an item in a category + * + * @category: Category of item + * @id: Item ID + * @return name of item, or "Unknown ..." if unknown + */ +const char *genimg_get_cat_name(enum ih_category category, uint id); + +/** + * genimg_get_cat_short_name() - Get the short name of an item in a category + * + * @category: Category of item + * @id: Item ID + * @return short name of item, or "Unknown ..." if unknown + */ +const char *genimg_get_cat_short_name(enum ih_category category, uint id); + +/** + * genimg_get_cat_count() - Get the number of items in a category + * + * @category: Category to check + * @return the number of items in the category (IH_xxx_COUNT) + */ +int genimg_get_cat_count(enum ih_category category); + +/** + * genimg_get_cat_desc() - Get the description of a category + * + * @return the description of a category, e.g. "architecture". This + * effectively converts the enum to a string. + */ +const char *genimg_get_cat_desc(enum ih_category category); + int genimg_get_os_id(const char *name); int genimg_get_arch_id(const char *name); int genimg_get_type_id(const char *name); @@ -1173,4 +1231,21 @@ void android_print_contents(const struct andr_img_hdr *hdr); */ int board_fit_config_name_match(const char *name); +#ifdef CONFIG_SPL_FIT_IMAGE_POST_PROCESS +/** + * board_fit_image_post_process() - Do any post-process on FIT binary data + * + * This is used to do any sort of image manipulation, verification, decryption + * etc. in a platform or board specific way. Obviously, anything done here would + * need to be comprehended in how the images were prepared before being injected + * into the FIT creation (i.e. the binary blobs would have been pre-processed + * before being added to the FIT image). + * + * @image: pointer to the image start pointer + * @size: pointer to the image size + * @return no return value (failure should be handled internally) + */ +void board_fit_image_post_process(void **p_image, size_t *p_size); +#endif /* CONFIG_SPL_FIT_IMAGE_POST_PROCESS */ + #endif /* __IMAGE_H__ */ diff --git a/include/linux/io.h b/include/linux/io.h index 1b36a22..a104b7e 100644 --- a/include/linux/io.h +++ b/include/linux/io.h @@ -5,6 +5,22 @@ #ifndef _LINUX_IO_H #define _LINUX_IO_H +#include <linux/compiler.h> +#include <linux/types.h> #include <asm/io.h> +#ifndef CONFIG_HAVE_ARCH_IOREMAP +static inline void __iomem *ioremap(resource_size_t offset, + resource_size_t size) +{ + return (void __iomem *)(unsigned long)offset; +} + +static inline void iounmap(void __iomem *addr) +{ +} + +#define devm_ioremap(dev, offset, size) ioremap(offset, size) +#endif + #endif /* _LINUX_IO_H */ diff --git a/include/linux/types.h b/include/linux/types.h index 6f75be4..416fa66 100644 --- a/include/linux/types.h +++ b/include/linux/types.h @@ -124,6 +124,10 @@ typedef __UINT64_TYPE__ u_int64_t; typedef __INT64_TYPE__ int64_t; #endif +#ifdef __KERNEL__ +typedef phys_addr_t resource_size_t; +#endif + /* * Below are truly Linux-specific types that should never collide with * any application/library that wants linux/types.h. diff --git a/include/os.h b/include/os.h index 954a48c..1782e50 100644 --- a/include/os.h +++ b/include/os.h @@ -287,6 +287,31 @@ int os_read_ram_buf(const char *fname); int os_jump_to_image(const void *dest, int size); /** + * os_find_u_boot() - Determine the path to U-Boot proper + * + * This function is intended to be called from within sandbox SPL. It uses + * a few heuristics to find U-Boot proper. Normally it is either in the same + * directory, or the directory above (since u-boot-spl is normally in an + * spl/ subdirectory when built). + * + * @fname: Place to put full path to U-Boot + * @maxlen: Maximum size of @fname + * @return 0 if OK, -NOSPC if the filename is too large, -ENOENT if not found + */ +int os_find_u_boot(char *fname, int maxlen); + +/** + * os_spl_to_uboot() - Run U-Boot proper + * + * When called from SPL, this runs U-Boot proper. The filename is obtained by + * calling os_find_u_boot(). + * + * @fname: Full pathname to U-Boot executable + * @return 0 if OK, -ve on error + */ +int os_spl_to_uboot(const char *fname); + +/** * Read the current system time * * This reads the current Local Time and places it into the provided diff --git a/include/regmap.h b/include/regmap.h index eccf770..1eed94e 100644 --- a/include/regmap.h +++ b/include/regmap.h @@ -57,6 +57,22 @@ int regmap_read(struct regmap *map, uint offset, uint *valp); int regmap_init_mem(struct udevice *dev, struct regmap **mapp); /** + * 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); + +/** * regmap_get_range() - Obtain the base memory address of a regmap range * * @map: Regmap to query diff --git a/include/syscon.h b/include/syscon.h index 4593b6e..34842aa 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 * diff --git a/lib/Makefile b/lib/Makefile index f48d901..f6a8ba1 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 diff --git a/lib/libfdt/libfdt.swig b/lib/libfdt/libfdt.swig new file mode 100644 index 0000000..14f583d --- /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 0000000..62e7bcc --- /dev/null +++ b/lib/libfdt/setup.py @@ -0,0 +1,38 @@ +#!/usr/bin/env python + +""" +setup.py file for SWIG libfdt +""" + +from distutils.core import setup, Extension +import os +import sys + +# Don't cross-compile - always use the host compiler. +del os.environ['CROSS_COMPILE'] +del os.environ['CC'] + +progname = sys.argv[0] +cflags = sys.argv[1] +files = sys.argv[2:] + +if cflags: + cflags = [flag for flag in cflags.split(' ') if flag] +else: + cflags = None + +libfdt_module = Extension( + '_libfdt', + sources = files, + extra_compile_args = cflags +) + +sys.argv = [progname, '--quiet', 'build_ext', '--inplace'] + +setup (name = 'libfdt', + version = '0.1', + author = "SWIG Docs", + description = """Simple swig libfdt from docs""", + ext_modules = [libfdt_module], + py_modules = ["libfdt"], + ) diff --git a/lib/libfdt/test_libfdt.py b/lib/libfdt/test_libfdt.py new file mode 100644 index 0000000..14d0da4 --- /dev/null +++ b/lib/libfdt/test_libfdt.py @@ -0,0 +1,14 @@ +#!/usr/bin/python + +import os +import sys + +our_path = os.path.dirname(os.path.realpath(__file__)) +sys.path.append(os.path.join(our_path, '../../b/sandbox_spl/tools')) + +import libfdt + +with open('b/sandbox_spl/u-boot.dtb') as fd: + fdt = fd.read() + +print libfdt.fdt_path_offset(fdt, "/aliases") diff --git a/lib/tiny-printf.c b/lib/tiny-printf.c index b334f05..1aa43ab 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(); +} diff --git a/scripts/Makefile.host b/scripts/Makefile.host index bff8b5b..763a699 100644 --- a/scripts/Makefile.host +++ b/scripts/Makefile.host @@ -28,12 +28,16 @@ __hostprogs := $(sort $(hostprogs-y) $(hostprogs-m)) # C code # Executables compiled from a single .c file host-csingle := $(foreach m,$(__hostprogs), \ - $(if $($(m)-objs)$($(m)-cxxobjs),,$(m))) + $(if $($(m)-objs)$($(m)-cxxobjs)$($(m)-sharedobjs),,$(m))) # C executables linked based on several .o files host-cmulti := $(foreach m,$(__hostprogs),\ $(if $($(m)-cxxobjs),,$(if $($(m)-objs),$(m)))) +# Shared object libraries +host-shared := $(foreach m,$(__hostprogs),\ + $(if $($(m)-sharedobjs),$(m)))) + # Object (.o) files compiled from .c files host-cobjs := $(sort $(foreach m,$(__hostprogs),$($(m)-objs))) @@ -59,6 +63,7 @@ host-cmulti := $(addprefix $(obj)/,$(host-cmulti)) host-cobjs := $(addprefix $(obj)/,$(host-cobjs)) host-cxxmulti := $(addprefix $(obj)/,$(host-cxxmulti)) host-cxxobjs := $(addprefix $(obj)/,$(host-cxxobjs)) +host-shared := $(addprefix $(obj)/,$(host-shared)) host-objdirs := $(addprefix $(obj)/,$(host-objdirs)) obj-dirs += $(host-objdirs) @@ -128,4 +133,4 @@ $(host-cxxobjs): $(obj)/%.o: $(src)/%.cc FORCE $(call if_changed_dep,host-cxxobjs) targets += $(host-csingle) $(host-cmulti) $(host-cobjs)\ - $(host-cxxmulti) $(host-cxxobjs) + $(host-cxxmulti) $(host-cxxobjs) $(host-shared) diff --git a/scripts/Makefile.spl b/scripts/Makefile.spl index 0997fd9..3ba9742 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 @@ -169,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) @@ -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 @@ -241,19 +271,24 @@ 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 \ + $(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 $@ diff --git a/test/README b/test/README new file mode 100644 index 0000000..ee55972 --- /dev/null +++ b/test/README @@ -0,0 +1,92 @@ +Testing in U-Boot +================= + +U-Boot has a large amount of code. This file describes how this code is +tested and what tests you should write when adding a new feature. + + +Running tests +------------- + +To run most tests on sandbox, type this: + + test/run + +in the U-Boot directory. Note that only the pytest suite is run using this +comment. + + +Sandbox +------- +U-Boot can be built as a user-space application (e.g. for Linux). This +allows test to be executed without needing target hardware. The 'sandbox' +target provides this feature and it is widely used in tests. + + +Pytest Suite +------------ + +Many tests are available using the pytest suite, in test/py. This can run +either on sandbox or on real hardware. It relies on the U-Boot console to +inject test commands and check the result. It is slower to run than C code, +but provides the ability to unify lots of test and summarise their results. + +You can run the tests on sandbox with: + + ./test/py/test.py --bd sandbox --build + +This will produce HTML output in build-sandbox/test-log.html + +See test/py/README.md for more information about the pytest suite. + + +tbot +---- + +Tbot provides a way to execute tests on target hardware. It is intended for +trying out both U-Boot and Linux (and potentially other software) on a +number of boards automatically. It can be used to create a continuous test +environment. See tools/tbot/README for more information. + + +Ad-hoc tests +------------ + +There are several ad-hoc tests which run outside the pytest environment: + + test/fs - File system test (shell script) + test/image - FIT and lagacy image tests (shell script and Python) + test/stdint - A test that stdint.h can be used in U-Boot (shell script) + trace - Test for the tracing feature (shell script) + +The above should be converted to run as part of the pytest suite. + + +When to write tests +------------------- + +If you add code to U-Boot without a test you are taking a risk. Even if you +perform thorough manual testing at the time of submission, it may break when +future changes are made to U-Boot. It may even break when applied to mainline, +if other changes interact with it. A good mindset is that untested code +probably doesn't work and should be deleted. + +You can assume that the Pytest suite will be run before patches are accepted +to mainline, so this provides protection against future breakage. + +On the other hand there is quite a bit of code that is not covered with tests, +or is covered sparingly. So here are some suggestions: + +- If you are adding a new uclass, add a sandbox driver and a test that uses it +- If you are modifying code covered by an existing test, add a new test case + to cover your changes +- If the code you are modifying has not tests, consider writing one. Even a + very basic test is useful, and may be picked up and enhanced by others. It + is much easier to add onto a test - writing a new large test can seem + daunting to most contributors. + + +Future work +----------- + +Converting existing shell scripts into pytest tests. diff --git a/test/py/conftest.py b/test/py/conftest.py index 449f98b..5b3a923 100644 --- a/test/py/conftest.py +++ b/test/py/conftest.py @@ -179,6 +179,7 @@ def pytest_configure(config): ubconfig.board_type = board_type ubconfig.board_identity = board_identity ubconfig.gdbserver = gdbserver + ubconfig.dtb = build_dir + '/arch/sandbox/dts/test.dtb' env_vars = ( 'board_type', @@ -192,7 +193,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: diff --git a/test/py/multiplexed_log.py b/test/py/multiplexed_log.py index 68917eb..35a32fb 100644 --- a/test/py/multiplexed_log.py +++ b/test/py/multiplexed_log.py @@ -101,6 +101,7 @@ class RunAndLog(object): self.logfile = logfile self.name = name self.chained_file = chained_file + self.output = None def close(self): """Clean up any resources managed by this object.""" @@ -109,6 +110,9 @@ class RunAndLog(object): def run(self, cmd, cwd=None, ignore_errors=False): """Run a command as a sub-process, and log the results. + The output is available at self.output which can be useful if there is + an exception. + Args: cmd: The command to execute. cwd: The directory to run the command in. Can be None to use the @@ -119,7 +123,7 @@ class RunAndLog(object): raised if such problems occur. Returns: - Nothing. + The output as a string. """ msg = '+' + ' '.join(cmd) + '\n' @@ -159,8 +163,12 @@ class RunAndLog(object): self.logfile.write(self, output) if self.chained_file: self.chained_file.write(output) + + # Store the output so it can be accessed if we raise an exception. + self.output = output if exception: raise exception + return output class SectionCtxMgr(object): """A context manager for Python's "with" statement, which allows a certain diff --git a/test/py/tests/test_ofplatdata.py b/test/py/tests/test_ofplatdata.py new file mode 100644 index 0000000..c8b309e --- /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 <NULL> +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 diff --git a/test/py/tests/test_vboot.py b/test/py/tests/test_vboot.py new file mode 100644 index 0000000..c779895 --- /dev/null +++ b/test/py/tests/test_vboot.py @@ -0,0 +1,185 @@ +# Copyright (c) 2013, Google Inc. +# +# SPDX-License-Identifier: GPL-2.0+ +# +# U-Boot Verified Boot Test + +""" +This tests verified boot in the following ways: + +For image verification: +- Create FIT (unsigned) with mkimage +- Check that verification shows that no keys are verified +- Sign image +- Check that verification shows that a key is now verified + +For configuration verification: +- Corrupt signature and check for failure +- Create FIT (with unsigned configuration) with mkimage +- Check that image veriication works +- Sign the FIT and mark the key as 'required' for verification +- Check that image verification works +- Corrupt the signature +- Check that image verification no-longer works + +Tests run with both SHA1 and SHA256 hashing. +""" + +import pytest +import sys +import u_boot_utils as util + +@pytest.mark.buildconfigspec('fit_signature') +def test_vboot(u_boot_console): + """Test verified boot signing with mkimage and verification with 'bootm'. + + This works using sandbox only as it needs to update the device tree used + by U-Boot to hold public keys from the signing process. + + The SHA1 and SHA256 tests are combined into a single test since the + key-generation process is quite slow and we want to avoid doing it twice. + """ + def dtc(dts): + """Run the device-tree compiler to compile a .dts file + + The output file will be the same as the input file but with a .dtb + extension. + + Args: + dts: Device tree file to compile. + """ + dtb = dts.replace('.dts', '.dtb') + util.cmd(cons, 'dtc %s %s%s -O dtb ' + '-o %s%s' % (dtc_args, datadir, dts, tmpdir, dtb)) + + def run_bootm(test_type, expect_string): + """Run a 'bootm' command U-Boot. + + This always starts a fresh U-Boot instance since the device tree may + contain a new public key. + + Args: + test_type: A string identifying the test type + expect_string: A string which is expected in the output + """ + cons.cleanup_spawn() + cons.ensure_spawned() + cons.log.action('%s: Test Verified Boot Run: %s' % (algo, test_type)) + output = cons.run_command_list( + ['sb load hostfs - 100 %stest.fit' % tmpdir, + 'fdt addr 100', + 'bootm 100']) + assert(expect_string in output) + + def make_fit(its): + """Make a new FIT from the .its source file + + This runs 'mkimage -f' to create a new FIT. + + Args: + its: Filename containing .its source + """ + util.run_and_log(cons, [mkimage, '-D', dtc_args, '-f', + '%s%s' % (datadir, its), fit]) + + def sign_fit(): + """Sign the FIT + + Signs the FIT and writes the signature into it. It also writes the + public key into the dtb. + """ + cons.log.action('%s: Sign images' % algo) + util.run_and_log(cons, [mkimage, '-F', '-k', tmpdir, '-K', dtb, + '-r', fit]) + + def test_with_algo(sha): + """Test verified boot with the given hash algorithm + + This is the main part of the test code. The same procedure is followed + for both hashing algorithms. + + Args: + sha: Either 'sha1' or 'sha256', to select the algorithm to use + """ + global algo + + algo = sha + + # Compile our device tree files for kernel and U-Boot + dtc('sandbox-kernel.dts') + dtc('sandbox-u-boot.dts') + + # Build the FIT, but don't sign anything yet + cons.log.action('%s: Test FIT with signed images' % algo) + make_fit('sign-images-%s.its' % algo) + run_bootm('unsigned images', 'dev-') + + # Sign images with our dev keys + sign_fit() + run_bootm('signed images', 'dev+') + + # Create a fresh .dtb without the public keys + dtc('sandbox-u-boot.dts') + + cons.log.action('%s: Test FIT with signed configuration' % algo) + make_fit('sign-configs-%s.its' % algo) + run_bootm('unsigned config', '%s+ OK' % algo) + + # Sign images with our dev keys + sign_fit() + run_bootm('signed config', 'dev+') + + cons.log.action('%s: Check signed config on the host' % algo) + + util.run_and_log(cons, [fit_check_sign, '-f', fit, '-k', tmpdir, + '-k', dtb]) + + # Increment the first byte of the signature, which should cause failure + sig = util.cmd(cons, 'fdtget -t bx %s %s value' % (fit, sig_node)) + byte_list = sig.split() + byte = int(byte_list[0], 16) + byte_list = ['%x' % (byte + 1)] + byte_list[1:] + sig = ' '.join(byte_list) + util.cmd(cons, 'fdtput -t bx %s %s value %s' % (fit, sig_node, sig)) + + run_bootm('Signed config with bad hash', 'Bad Data Hash') + + cons.log.action('%s: Check bad config on the host' % algo) + util.run_and_log_expect_exception(cons, [fit_check_sign, '-f', fit, + '-k', dtb], 1, 'Failed to verify required signature') + + cons = u_boot_console + tmpdir = cons.config.result_dir + '/' + tmp = tmpdir + 'vboot.tmp' + datadir = 'test/py/tests/vboot/' + fit = '%stest.fit' % tmpdir + mkimage = cons.config.build_dir + '/tools/mkimage' + fit_check_sign = cons.config.build_dir + '/tools/fit_check_sign' + dtc_args = '-I dts -O dtb -i %s' % tmpdir + dtb = '%ssandbox-u-boot.dtb' % tmpdir + sig_node = '/configurations/conf@1/signature@1' + + # Create an RSA key pair + public_exponent = 65537 + util.cmd(cons, 'openssl genpkey -algorithm RSA -out %sdev.key ' + '-pkeyopt rsa_keygen_bits:2048 ' + '-pkeyopt rsa_keygen_pubexp:%d ' + '2>/dev/null' % (tmpdir, public_exponent)) + + # Create a certificate containing the public key + util.cmd(cons, 'openssl req -batch -new -x509 -key %sdev.key -out ' + '%sdev.crt' % (tmpdir, tmpdir)) + + # Create a number kernel image with zeroes + with open('%stest-kernel.bin' % tmpdir, 'w') as fd: + fd.write(5000 * chr(0)) + + try: + # We need to use our own device tree file. Remember to restore it + # afterwards. + old_dtb = cons.config.dtb + cons.config.dtb = dtb + test_with_algo('sha1') + test_with_algo('sha256') + finally: + cons.config.dtb = old_dtb diff --git a/test/vboot/sandbox-kernel.dts b/test/py/tests/vboot/sandbox-kernel.dts index a1e853c..a1e853c 100644 --- a/test/vboot/sandbox-kernel.dts +++ b/test/py/tests/vboot/sandbox-kernel.dts diff --git a/test/vboot/sandbox-u-boot.dts b/test/py/tests/vboot/sandbox-u-boot.dts index 63f8f40..63f8f40 100644 --- a/test/vboot/sandbox-u-boot.dts +++ b/test/py/tests/vboot/sandbox-u-boot.dts diff --git a/test/vboot/sign-configs-sha1.its b/test/py/tests/vboot/sign-configs-sha1.its index db2ed79..db2ed79 100644 --- a/test/vboot/sign-configs-sha1.its +++ b/test/py/tests/vboot/sign-configs-sha1.its diff --git a/test/vboot/sign-configs-sha256.its b/test/py/tests/vboot/sign-configs-sha256.its index 1b3432e..1b3432e 100644 --- a/test/vboot/sign-configs-sha256.its +++ b/test/py/tests/vboot/sign-configs-sha256.its diff --git a/test/vboot/sign-images-sha1.its b/test/py/tests/vboot/sign-images-sha1.its index f69326a..f69326a 100644 --- a/test/vboot/sign-images-sha1.its +++ b/test/py/tests/vboot/sign-images-sha1.its diff --git a/test/vboot/sign-images-sha256.its b/test/py/tests/vboot/sign-images-sha256.its index e6aa9fc..e6aa9fc 100644 --- a/test/vboot/sign-images-sha256.its +++ b/test/py/tests/vboot/sign-images-sha256.its diff --git a/test/py/u_boot_console_base.py b/test/py/u_boot_console_base.py index 815fa64..4606ad4 100644 --- a/test/py/u_boot_console_base.py +++ b/test/py/u_boot_console_base.py @@ -216,6 +216,22 @@ class ConsoleBase(object): self.cleanup_spawn() raise + def run_command_list(self, cmds): + """Run a list of commands. + + This is a helper function to call run_command() with default arguments + for each command in a list. + + Args: + cmd: List of commands (each a string) + Returns: + Combined output of all commands, as a string + """ + output = '' + for cmd in cmds: + output += self.run_command(cmd) + return output + def ctrlc(self): """Send a CTRL-C character to U-Boot. @@ -329,7 +345,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: @@ -377,6 +393,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_console_sandbox.py b/test/py/u_boot_console_sandbox.py index 04654ae..647e1f8 100644 --- a/test/py/u_boot_console_sandbox.py +++ b/test/py/u_boot_console_sandbox.py @@ -39,14 +39,18 @@ 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' + self.config.dtb ] return Spawn(cmd, cwd=self.config.source_dir) diff --git a/test/py/u_boot_spawn.py b/test/py/u_boot_spawn.py index d155173..3a0fbfa 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 diff --git a/test/py/u_boot_utils.py b/test/py/u_boot_utils.py index e4765e3..e358c58 100644 --- a/test/py/u_boot_utils.py +++ b/test/py/u_boot_utils.py @@ -165,12 +165,47 @@ def run_and_log(u_boot_console, cmd, ignore_errors=False): problems occur. Returns: - Nothing. + The output as a string. """ runner = u_boot_console.log.get_runner(cmd[0], sys.stdout) - runner.run(cmd, ignore_errors=ignore_errors) + output = runner.run(cmd, ignore_errors=ignore_errors) runner.close() + return output + +def cmd(u_boot_console, cmd_str): + """Run a single command string and log its output. + + Args: + u_boot_console: A console connection to U-Boot. + cmd: The command to run, as a string. + + Returns: + The output as a string. + """ + return run_and_log(u_boot_console, cmd_str.split()) + +def run_and_log_expect_exception(u_boot_console, cmd, retcode, msg): + """Run a command which is expected to fail. + + This runs a command and checks that it fails with the expected return code + and exception method. If not, an exception is raised. + + Args: + u_boot_console: A console connection to U-Boot. + cmd: The command to run, as an array of argv[]. + retcode: Expected non-zero return code from the command. + msg: String which should be contained within the command's output. + """ + try: + runner = u_boot_console.log.get_runner(cmd[0], sys.stdout) + runner.run(cmd) + except Exception as e: + assert(msg in runner.output) + else: + raise Exception('Expected exception, but not raised') + finally: + runner.close() ram_base = None def find_ram_base(u_boot_console): diff --git a/test/run b/test/run new file mode 100755 index 0000000..a6dcf8f --- /dev/null +++ b/test/run @@ -0,0 +1,4 @@ +#!/bin/sh + +# Run all tests +./test/py/test.py --bd sandbox --build diff --git a/test/vboot/.gitignore b/test/vboot/.gitignore deleted file mode 100644 index 4631242..0000000 --- a/test/vboot/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -/*.dtb -/test.fit -/dev-keys diff --git a/test/vboot/vboot_test.sh b/test/vboot/vboot_test.sh deleted file mode 100755 index 6d7abb8..0000000 --- a/test/vboot/vboot_test.sh +++ /dev/null @@ -1,151 +0,0 @@ -#!/bin/bash -# -# Copyright (c) 2013, Google Inc. -# -# Simple Verified Boot Test Script -# -# SPDX-License-Identifier: GPL-2.0+ - -set -e - -# Run U-Boot and report the result -# Args: -# $1: Test message -run_uboot() { - echo -n "Test Verified Boot Run: $1: " - ${uboot} -d sandbox-u-boot.dtb >${tmp} -c ' -sb load hostfs - 100 test.fit; -fdt addr 100; -bootm 100; -reset' - if ! grep -q "$2" ${tmp}; then - echo - echo "Verified boot key check failed, output follows:" - cat ${tmp} - false - else - echo "OK" - fi -} - -echo "Simple Verified Boot Test" -echo "=========================" -echo -echo "Please see doc/uImage.FIT/verified-boot.txt for more information" -echo - -err=0 -tmp=/tmp/vboot_test.$$ - -dir=$(dirname $0) - -if [ -z ${O} ]; then - O=. -fi -O=$(readlink -f ${O}) - -dtc="-I dts -O dtb -p 2000" -uboot="${O}/u-boot" -mkimage="${O}/tools/mkimage" -fit_check_sign="${O}/tools/fit_check_sign" -keys="${dir}/dev-keys" -echo ${mkimage} -D "${dtc}" - -echo "Build keys" -mkdir -p ${keys} - -PUBLIC_EXPONENT=${1} - -if [ -z "${PUBLIC_EXPONENT}" ]; then - PUBLIC_EXPONENT=65537 -fi - -# Create an RSA key pair -openssl genpkey -algorithm RSA -out ${keys}/dev.key \ - -pkeyopt rsa_keygen_bits:2048 \ - -pkeyopt rsa_keygen_pubexp:${PUBLIC_EXPONENT} 2>/dev/null - -# Create a certificate containing the public key -openssl req -batch -new -x509 -key ${keys}/dev.key -out ${keys}/dev.crt - -pushd ${dir} >/dev/null - -function do_test { - echo do $sha test - # Compile our device tree files for kernel and U-Boot - dtc -p 0x1000 sandbox-kernel.dts -O dtb -o sandbox-kernel.dtb - dtc -p 0x1000 sandbox-u-boot.dts -O dtb -o sandbox-u-boot.dtb - - # Create a number kernel image with zeroes - head -c 5000 /dev/zero >test-kernel.bin - - # Build the FIT, but don't sign anything yet - echo Build FIT with signed images - ${mkimage} -D "${dtc}" -f sign-images-$sha.its test.fit >${tmp} - - run_uboot "unsigned signatures:" "dev-" - - # Sign images with our dev keys - echo Sign images - ${mkimage} -D "${dtc}" -F -k dev-keys -K sandbox-u-boot.dtb \ - -r test.fit >${tmp} - - run_uboot "signed images" "dev+" - - - # Create a fresh .dtb without the public keys - dtc -p 0x1000 sandbox-u-boot.dts -O dtb -o sandbox-u-boot.dtb - - echo Build FIT with signed configuration - ${mkimage} -D "${dtc}" -f sign-configs-$sha.its test.fit >${tmp} - - run_uboot "unsigned config" $sha"+ OK" - - # Sign images with our dev keys - echo Sign images - ${mkimage} -D "${dtc}" -F -k dev-keys -K sandbox-u-boot.dtb \ - -r test.fit >${tmp} - - run_uboot "signed config" "dev+" - - echo check signed config on the host - if ! ${fit_check_sign} -f test.fit -k sandbox-u-boot.dtb >${tmp}; then - echo - echo "Verified boot key check on host failed, output follows:" - cat ${tmp} - false - else - if ! grep -q "dev+" ${tmp}; then - echo - echo "Verified boot key check failed, output follows:" - cat ${tmp} - false - else - echo "OK" - fi - fi - - run_uboot "signed config" "dev+" - - # Increment the first byte of the signature, which should cause failure - sig=$(fdtget -t bx test.fit /configurations/conf@1/signature@1 value) - newbyte=$(printf %x $((0x${sig:0:2} + 1))) - sig="${newbyte} ${sig:2}" - fdtput -t bx test.fit /configurations/conf@1/signature@1 value ${sig} - - run_uboot "signed config with bad hash" "Bad Data Hash" -} - -sha=sha1 -do_test -sha=sha256 -do_test - -popd >/dev/null - -echo -if ${ok}; then - echo "Test passed" -else - echo "Test failed" -fi diff --git a/tools/Makefile b/tools/Makefile index f72294a..421414b 100644 --- a/tools/Makefile +++ b/tools/Makefile @@ -107,6 +107,20 @@ 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 +# 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: + +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/.gitignore b/tools/dtoc/.gitignore new file mode 100644 index 0000000..0d20b64 --- /dev/null +++ b/tools/dtoc/.gitignore @@ -0,0 +1 @@ +*.pyc diff --git a/tools/dtoc/dtoc b/tools/dtoc/dtoc new file mode 120000 index 0000000..896ca44 --- /dev/null +++ b/tools/dtoc/dtoc @@ -0,0 +1 @@ +dtoc.py
\ No newline at end of file diff --git a/tools/dtoc/dtoc.py b/tools/dtoc/dtoc.py new file mode 100755 index 0000000..ec80abe --- /dev/null +++ b/tools/dtoc/dtoc.py @@ -0,0 +1,394 @@ +#!/usr/bin/python +# +# Copyright (C) 2016 Google, Inc +# Written by Simon Glass <sjg@chromium.org> +# +# 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', + 'u-boot,dm-pre-reloc', +] + +# 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 <stdbool.h>\n') + self.Out('#include <libfdt.h>\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 <common.h>\n') + self.Out('#include <dm.h>\n') + self.Out('#include <dt-structs.h>\n') + self.Out('\n') + node_txt_list = [] + for node in self._valid_nodes: + struct_name = self.GetCompatName(node) + var_name = Conv_name_to_c(node.name) + self.Buf('static struct %s%s %s%s = {\n' % + (STRUCT_PREFIX, struct_name, VAL_PREFIX, var_name)) + for pname, prop in node.props.iteritems(): + if pname in PROP_IGNORE_LIST or pname[0] == '#': + continue + ptype = TYPE_NAMES[prop.type] + member_name = Conv_name_to_c(prop.name) + self.Buf('\t%s= ' % TabTo(3, '.' + member_name)) + + # Special handling for lists + if type(prop.value) == list: + self.Buf('{') + vals = [] + # For phandles, output a reference to the platform data + # of the target node. + if self.IsPhandle(prop): + # Process the list as pairs of (phandle, id) + it = iter(prop.value) + for phandle_cell, id_cell in zip(it, it): + phandle = fdt_util.fdt32_to_cpu(phandle_cell) + id = fdt_util.fdt32_to_cpu(id_cell) + target_node = self._phandle_node[phandle] + name = Conv_name_to_c(target_node.name) + vals.append('{&%s%s, %d}' % (VAL_PREFIX, name, id)) + else: + for val in prop.value: + vals.append(self.GetValue(prop.type, val)) + self.Buf(', '.join(vals)) + self.Buf('}') + else: + self.Buf(self.GetValue(prop.type, prop.value)) + self.Buf(',\n') + self.Buf('};\n') + + # Add a device declaration + self.Buf('U_BOOT_DEVICE(%s) = {\n' % var_name) + self.Buf('\t.name\t\t= "%s",\n' % struct_name) + self.Buf('\t.platdata\t= &%s%s,\n' % (VAL_PREFIX, var_name)) + self.Buf('\t.platdata_size\t= sizeof(%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) diff --git a/tools/dtoc/fdt.py b/tools/dtoc/fdt.py new file mode 100644 index 0000000..1d913a9 --- /dev/null +++ b/tools/dtoc/fdt.py @@ -0,0 +1,180 @@ +#!/usr/bin/python +# +# Copyright (C) 2016 Google, Inc +# Written by Simon Glass <sjg@chromium.org> +# +# SPDX-License-Identifier: GPL-2.0+ +# + +import fdt_util +import libfdt +import sys + +# This deals with a device tree, presenting it as a list of Node and Prop +# objects, representing nodes and properties, respectively. +# +# This implementation uses a libfdt Python library to access the device tree, +# so it is fairly efficient. + +class Prop: + """A device tree property + + Properties: + name: Property name (as per the device tree) + value: Property value as a string of bytes, or a list of strings of + bytes + type: Value type + """ + def __init__(self, name, bytes): + self.name = name + self.value = None + if not bytes: + self.type = fdt_util.TYPE_BOOL + 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 diff --git a/tools/dtoc/fdt_fallback.py b/tools/dtoc/fdt_fallback.py new file mode 100644 index 0000000..14decf3 --- /dev/null +++ b/tools/dtoc/fdt_fallback.py @@ -0,0 +1,207 @@ +#!/usr/bin/python +# +# Copyright (C) 2016 Google, Inc +# Written by Simon Glass <sjg@chromium.org> +# +# SPDX-License-Identifier: GPL-2.0+ +# + +import command +import fdt_util +import sys + +# This deals with a device tree, presenting it as a list of Node and Prop +# objects, representing nodes and properties, respectively. +# +# This implementation uses the fdtget tool to access the device tree, so it +# is not very efficient for larger trees. The tool is called once for each +# node and property in the tree. + +class Prop: + """A device tree property + + Properties: + name: Property name (as per the device tree) + value: Property value as a string of bytes, or a list of strings of + bytes + type: Value type + """ + def __init__(self, name, byte_list_str): + self.name = name + self.value = None + if not byte_list_str.strip(): + self.type = fdt_util.TYPE_BOOL + return + bytes = [chr(int(byte, 16)) for byte in byte_list_str.strip().split(' ')] + self.type, self.value = fdt_util.BytesToValue(''.join(bytes)) + + def GetPhandle(self): + """Get a (single) phandle value from a property + + Gets the phandle valuie from a property and returns it as an integer + """ + return fdt_util.fdt32_to_cpu(self.value[:4]) + + def Widen(self, newprop): + """Figure out which property type is more general + + Given a current property and a new property, this function returns the + one that is less specific as to type. The less specific property will + be ble to represent the data in the more specific property. This is + used for things like: + + node1 { + compatible = "fred"; + value = <1>; + }; + node1 { + compatible = "fred"; + value = <1 2>; + }; + + He we want to use an int array for 'value'. The first property + suggests that a single int is enough, but the second one shows that + it is not. Calling this function with these two propertes would + update the current property to be like the second, since it is less + specific. + """ + if newprop.type < self.type: + self.type = newprop.type + + if type(newprop.value) == list and type(self.value) != list: + self.value = newprop.value + +class Node: + """A device tree node + + Properties: + name: Device tree node tname + path: Full path to node, along with the node name itself + _fdt: Device tree object + subnodes: A list of subnodes for this node, each a Node object + props: A dict of properties for this node, each a Prop object. + Keyed by property name + """ + def __init__(self, fdt, name, path): + self.name = name + self.path = path + self._fdt = fdt + self.subnodes = [] + self.props = {} + + def Scan(self): + """Scan a node's properties and subnodes + + This fills in the props and subnodes properties, recursively + searching into subnodes so that the entire tree is built. + """ + for name, byte_list_str in self._fdt.GetProps(self.path).iteritems(): + prop = Prop(name, byte_list_str) + self.props[name] = prop + + for name in self._fdt.GetSubNodes(self.path): + sep = '' if self.path[-1] == '/' else '/' + path = self.path + sep + name + node = Node(self._fdt, name, path) + self.subnodes.append(node) + + node.Scan() + + +class Fdt: + """Provides simple access to a flat device tree blob. + + Properties: + fname: Filename of fdt + _root: Root of device tree (a Node object) + """ + + def __init__(self, fname): + self.fname = fname + + def Scan(self): + """Scan a device tree, building up a tree of Node objects + + This fills in the self._root property + """ + self._root = Node(self, '/', '/') + self._root.Scan() + + def GetRoot(self): + """Get the root Node of the device tree + + Returns: + The root Node object + """ + return self._root + + def GetSubNodes(self, node): + """Returns a list of sub-nodes of a given node + + Args: + node: Node name to return children from + + Returns: + List of children in the node (each a string node name) + + Raises: + CmdError: if the node does not exist. + """ + out = command.Output('fdtget', self.fname, '-l', node) + return out.strip().splitlines() + + def GetProps(self, node, convert_dashes=False): + """Get all properties from a node + + Args: + node: full path to node name to look in + convert_dashes: True to convert - to _ in node names + + Returns: + A dictionary containing all the properties, indexed by node name. + The entries are simply strings - no decoding of lists or numbers + is done. + + Raises: + CmdError: if the node does not exist. + """ + out = command.Output('fdtget', self.fname, node, '-p') + props = out.strip().splitlines() + props_dict = {} + for prop in props: + name = prop + if convert_dashes: + prop = re.sub('-', '_', prop) + props_dict[prop] = self.GetProp(node, name) + return props_dict + + def GetProp(self, node, prop, default=None, typespec=None): + """Get a property from a device tree. + + This looks up the given node and property, and returns the value as a + string, + + If the node or property does not exist, this will return the default + value. + + Args: + node: Full path to node to look up. + prop: Property name to look up. + default: Default value to return if nothing is present in the fdt, + or None to raise in this case. This will be converted to a + string. + typespec: Type character to use (None for default, 's' for string) + + Returns: + string containing the property value. + + Raises: + CmdError: if the property does not exist and no default is provided. + """ + args = [self.fname, node, prop, '-t', 'bx'] + if default is not None: + args += ['-d', str(default)] + if typespec is not None: + args += ['-t%s' % typespec] + out = command.Output('fdtget', *args) + return out.strip() diff --git a/tools/dtoc/fdt_util.py b/tools/dtoc/fdt_util.py new file mode 100644 index 0000000..929b524 --- /dev/null +++ b/tools/dtoc/fdt_util.py @@ -0,0 +1,86 @@ +#!/usr/bin/python +# +# Copyright (C) 2016 Google, Inc +# Written by Simon Glass <sjg@chromium.org> +# +# SPDX-License-Identifier: GPL-2.0+ +# + +import struct + +# A list of types we support +(TYPE_BYTE, TYPE_INT, TYPE_STRING, TYPE_BOOL) = range(4) + +def BytesToValue(bytes): + """Converts a string of bytes into a type and value + + Args: + A string containing bytes + + Return: + A tuple: + Type of data + Data, either a single element or a list of elements. Each element + is one of: + TYPE_STRING: string value from the property + TYPE_INT: a byte-swapped integer 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', 0); + elif type == TYPE_STRING: + return '' + else: + return True + +def fdt32_to_cpu(val): + """Convert a device tree cell to an integer + + Args: + Value to convert (4-character string representing the cell value) + + Return: + A native-endian integer value + """ + return struct.unpack(">I", val)[0] diff --git a/tools/fit_image.c b/tools/fit_image.c index 58aa8e2..10fd6d4 100644 --- a/tools/fit_image.c +++ b/tools/fit_image.c @@ -195,7 +195,8 @@ static int fit_write_images(struct image_tool_params *params, char *fdt) fdt_begin_node(fdt, str); fdt_property_string(fdt, "description", params->imagename); fdt_property_string(fdt, "type", typename); - fdt_property_string(fdt, "arch", genimg_get_arch_name(params->arch)); + fdt_property_string(fdt, "arch", + genimg_get_arch_short_name(params->arch)); fdt_property_string(fdt, "os", genimg_get_os_short_name(params->os)); fdt_property_string(fdt, "compression", genimg_get_comp_short_name(params->comp)); @@ -650,8 +651,8 @@ static int fit_handle_file(struct image_tool_params *params) } if (ret) { - fprintf(stderr, "%s Can't add hashes to FIT blob\n", - params->cmdname); + fprintf(stderr, "%s Can't add hashes to FIT blob: %d\n", + params->cmdname, ret); goto err_system; } diff --git a/tools/image-host.c b/tools/image-host.c index 7effb6c..3e14fdc 100644 --- a/tools/image-host.c +++ b/tools/image-host.c @@ -38,7 +38,7 @@ static int fit_set_hash_value(void *fit, int noffset, uint8_t *value, printf("Can't set hash '%s' property for '%s' node(%s)\n", FIT_VALUE_PROP, fit_get_name(fit, noffset, NULL), fdt_strerror(ret)); - return -1; + return ret == -FDT_ERR_NOSPACE ? -ENOSPC : -EIO; } return 0; @@ -64,25 +64,27 @@ static int fit_image_process_hash(void *fit, const char *image_name, const char *node_name; int value_len; char *algo; + int ret; node_name = fit_get_name(fit, noffset, NULL); if (fit_image_hash_get_algo(fit, noffset, &algo)) { printf("Can't get hash algo property for '%s' hash node in '%s' image node\n", node_name, image_name); - return -1; + return -ENOENT; } if (calculate_hash(data, size, algo, value, &value_len)) { printf("Unsupported hash algorithm (%s) for '%s' hash node in '%s' image node\n", algo, node_name, image_name); - return -1; + return -EPROTONOSUPPORT; } - if (fit_set_hash_value(fit, noffset, value, value_len)) { + ret = fit_set_hash_value(fit, noffset, value, value_len); + if (ret) { printf("Can't set hash value for '%s' hash node in '%s' image node\n", node_name, image_name); - return -1; + return ret; } return 0; @@ -322,7 +324,7 @@ int fit_image_add_verification_data(const char *keydir, void *keydest, comment, require_keys); } if (ret) - return -1; + return ret; } return 0; diff --git a/tools/mkimage.c b/tools/mkimage.c index ff3024a..d993958 100644 --- a/tools/mkimage.c +++ b/tools/mkimage.c @@ -25,45 +25,47 @@ static struct image_tool_params params = { .imagename2 = "", }; -static int h_compare_image_name(const void *vtype1, const void *vtype2) +static enum ih_category cur_category; + +static int h_compare_category_name(const void *vtype1, const void *vtype2) { const int *type1 = vtype1; const int *type2 = vtype2; - const char *name1 = genimg_get_type_short_name(*type1); - const char *name2 = genimg_get_type_short_name(*type2); + const char *name1 = genimg_get_cat_short_name(cur_category, *type1); + const char *name2 = genimg_get_cat_short_name(cur_category, *type2); return strcmp(name1, name2); } -/* Show all image types supported by mkimage */ -static void show_image_types(void) +static int show_valid_options(enum ih_category category) { - struct image_type_params *tparams; - int order[IH_TYPE_COUNT]; + int *order; int count; - int type; + int item; int i; + count = genimg_get_cat_count(category); + order = calloc(count, sizeof(*order)); + if (!order) + return -ENOMEM; + /* Sort the names in order of short name for easier reading */ - memset(order, '\0', sizeof(order)); - for (count = 0, type = 0; type < IH_TYPE_COUNT; type++) { - tparams = imagetool_get_type(type); - if (tparams) - order[count++] = type; - } - qsort(order, count, sizeof(int), h_compare_image_name); + for (item = 0; item < count; item++) + order[item] = item; + cur_category = category; + qsort(order, count, sizeof(int), h_compare_category_name); - fprintf(stderr, "\nInvalid image type. Supported image types:\n"); + fprintf(stderr, "\nInvalid %s, supported are:\n", + genimg_get_cat_desc(category)); for (i = 0; i < count; i++) { - type = order[i]; - tparams = imagetool_get_type(type); - if (tparams) { - fprintf(stderr, "\t%-15s %s\n", - genimg_get_type_short_name(type), - genimg_get_type_name(type)); - } + item = order[i]; + fprintf(stderr, "\t%-15s %s\n", + genimg_get_cat_short_name(category, item), + genimg_get_cat_name(category, item)); } fprintf(stderr, "\n"); + + return 0; } static void usage(const char *msg) @@ -150,8 +152,10 @@ static void process_args(int argc, char **argv) break; case 'A': params.arch = genimg_get_arch_id(optarg); - if (params.arch < 0) + if (params.arch < 0) { + show_valid_options(IH_ARCH); usage("Invalid architecture"); + } break; case 'b': if (add_content(IH_TYPE_FLATDT, optarg)) { @@ -166,8 +170,10 @@ static void process_args(int argc, char **argv) break; case 'C': params.comp = genimg_get_comp_id(optarg); - if (params.comp < 0) + if (params.comp < 0) { + show_valid_options(IH_COMP); usage("Invalid compression type"); + } break; case 'd': params.datafile = optarg; @@ -197,7 +203,6 @@ static void process_args(int argc, char **argv) * The flattened image tree (FIT) format * requires a flattened device tree image type */ - params.fit_image_type = params.type; params.type = IH_TYPE_FLATDT; params.fflag = 1; break; @@ -215,8 +220,10 @@ static void process_args(int argc, char **argv) break; case 'O': params.os = genimg_get_os_id(optarg); - if (params.os < 0) + if (params.os < 0) { + show_valid_options(IH_OS); usage("Invalid operating system"); + } break; case 'p': params.external_offset = strtoull(optarg, &ptr, 16); @@ -225,6 +232,7 @@ static void process_args(int argc, char **argv) params.cmdname, optarg); exit(EXIT_FAILURE); } + break; case 'q': params.quiet = 1; break; @@ -244,7 +252,7 @@ static void process_args(int argc, char **argv) case 'T': type = genimg_get_type_id(optarg); if (type < 0) { - show_image_types(); + show_valid_options(IH_TYPE); usage("Invalid image type"); } break; @@ -272,9 +280,12 @@ static void process_args(int argc, char **argv) * will always be IH_TYPE_FLATDT in this case). */ if (params.type == IH_TYPE_FLATDT) { - params.fit_image_type = type; + params.fit_image_type = type ? type : IH_TYPE_KERNEL; + /* For auto_its, datafile is always 'auto' */ if (!params.auto_its) params.datafile = datafile; + else if (!params.datafile) + usage("Missing data file for auto-FIT (use -d)"); } else if (type != IH_TYPE_INVALID) { params.type = type; } @@ -283,7 +294,6 @@ static void process_args(int argc, char **argv) usage("Missing output filename"); } - int main(int argc, char **argv) { int ifd = -1; |