From a90b5946f488e8a36bd318220244ecd0908ce1d3 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Thu, 14 Sep 2023 10:55:39 -0600 Subject: lib: rational: Move the Kconfigs into the correct place These should not be part of the 'system tables' menu. Move them outside on their own. Signed-off-by: Simon Glass Fixes: 7d0f3fbb93c ("lib: rational: copy the rational fraction lib...") Reviewed-by: Tom Rini --- lib/Kconfig | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/Kconfig b/lib/Kconfig index 42e559ad0b5..9addcfab373 100644 --- a/lib/Kconfig +++ b/lib/Kconfig @@ -989,6 +989,8 @@ config GENERATE_SMBIOS_TABLE See also SMBIOS_SYSINFO which allows SMBIOS values to be provided in the devicetree. +endmenu + config LIB_RATIONAL bool "enable continued fraction calculation routines" @@ -996,8 +998,6 @@ config SPL_LIB_RATIONAL bool "enable continued fraction calculation routines for SPL" depends on SPL -endmenu - config ASN1_COMPILER bool help -- cgit v1.3.1 From d761eeabcdd127b3a26ee140e9a38b45d20fbd1b Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Thu, 14 Sep 2023 10:55:40 -0600 Subject: Kconfig: Move API into general setup This is perhaps not a commonly used feature so should not have its own option in the main menu. Move it under general setup. Signed-off-by: Simon Glass Reviewed-by: Tom Rini --- Kconfig | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Kconfig b/Kconfig index 91170bf8d22..0a2e97578df 100644 --- a/Kconfig +++ b/Kconfig @@ -585,10 +585,10 @@ config MP This provides an option to bringup different processors in multiprocessor cases. -endmenu # General setup - source "api/Kconfig" +endmenu # General setup + source "boot/Kconfig" source "common/Kconfig" -- cgit v1.3.1 From 8168359160525c57e54e294a00abb8db43a8cee1 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Thu, 14 Sep 2023 10:55:41 -0600 Subject: video: Move bmp code to drivers/video This relates to graphics which is only active when CONFIG_VIDEO is enabled. Move it into that directory. For most boards there is no harm in compiling it always, since it if not used it will be dropped by the linker. But for the EFI app this is not the case, so retain use of the BMP Kconfig. Signed-off-by: Simon Glass Reviewed-by: Tom Rini --- common/Makefile | 1 - common/bmp.c | 142 ------------------------------------------------- drivers/video/Makefile | 1 + drivers/video/bmp.c | 142 +++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 143 insertions(+), 143 deletions(-) delete mode 100644 common/bmp.c create mode 100644 drivers/video/bmp.c diff --git a/common/Makefile b/common/Makefile index f5c3d90f067..0a3f75f2f1c 100644 --- a/common/Makefile +++ b/common/Makefile @@ -45,7 +45,6 @@ endif # !CONFIG_SPL_BUILD obj-$(CONFIG_$(SPL_TPL_)BOOTSTAGE) += bootstage.o obj-$(CONFIG_$(SPL_TPL_)BLOBLIST) += bloblist.o -obj-$(CONFIG_$(SPL_)BMP) += bmp.o ifdef CONFIG_SPL_BUILD ifdef CONFIG_SPL_DFU diff --git a/common/bmp.c b/common/bmp.c deleted file mode 100644 index bab6fa7265a..00000000000 --- a/common/bmp.c +++ /dev/null @@ -1,142 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * (C) Copyright 2002 - * Detlev Zundel, DENX Software Engineering, dzu@denx.de. - */ - -/* - * BMP handling routines - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* - * Allocate and decompress a BMP image using gunzip(). - * - * Returns a pointer to the decompressed image data. This pointer is - * aligned to 32-bit-aligned-address + 2. - * See doc/README.displaying-bmps for explanation. - * - * The allocation address is passed to 'alloc_addr' and must be freed - * by the caller after use. - * - * Returns NULL if decompression failed, or if the decompressed data - * didn't contain a valid BMP signature or decompression is not enabled in - * Kconfig. - */ -struct bmp_image *gunzip_bmp(unsigned long addr, unsigned long *lenp, - void **alloc_addr) -{ - void *dst; - unsigned long len; - struct bmp_image *bmp; - - if (!CONFIG_IS_ENABLED(VIDEO_BMP_GZIP)) - return NULL; - - /* - * Decompress bmp image - */ - len = CONFIG_VAL(VIDEO_LOGO_MAX_SIZE); - /* allocate extra 3 bytes for 32-bit-aligned-address + 2 alignment */ - dst = malloc(CONFIG_VAL(VIDEO_LOGO_MAX_SIZE) + 3); - if (!dst) { - puts("Error: malloc in gunzip failed!\n"); - return NULL; - } - - /* align to 32-bit-aligned-address + 2 */ - bmp = dst + 2; - - if (gunzip(bmp, CONFIG_VAL(VIDEO_LOGO_MAX_SIZE), map_sysmem(addr, 0), - &len)) { - free(dst); - return NULL; - } - if (len == CONFIG_VAL(VIDEO_LOGO_MAX_SIZE)) - puts("Image could be truncated (increase CONFIG_VIDEO_LOGO_MAX_SIZE)!\n"); - - /* - * Check for bmp mark 'BM' - */ - if (!((bmp->header.signature[0] == 'B') && - (bmp->header.signature[1] == 'M'))) { - free(dst); - return NULL; - } - - debug("Gzipped BMP image detected!\n"); - - *alloc_addr = dst; - return bmp; -} - -int bmp_info(ulong addr) -{ - struct bmp_image *bmp = (struct bmp_image *)map_sysmem(addr, 0); - void *bmp_alloc_addr = NULL; - unsigned long len; - - if (!((bmp->header.signature[0] == 'B') && - (bmp->header.signature[1] == 'M'))) - bmp = gunzip_bmp(addr, &len, &bmp_alloc_addr); - - if (!bmp) { - printf("There is no valid bmp file at the given address\n"); - return 1; - } - - printf("Image size : %d x %d\n", le32_to_cpu(bmp->header.width), - le32_to_cpu(bmp->header.height)); - printf("Bits per pixel: %d\n", le16_to_cpu(bmp->header.bit_count)); - printf("Compression : %d\n", le32_to_cpu(bmp->header.compression)); - - if (bmp_alloc_addr) - free(bmp_alloc_addr); - - return 0; -} - -int bmp_display(ulong addr, int x, int y) -{ - struct udevice *dev; - int ret; - struct bmp_image *bmp = map_sysmem(addr, 0); - void *bmp_alloc_addr = NULL; - unsigned long len; - - if (!((bmp->header.signature[0] == 'B') && - (bmp->header.signature[1] == 'M'))) - bmp = gunzip_bmp(addr, &len, &bmp_alloc_addr); - - if (!bmp) { - printf("There is no valid bmp file at the given address\n"); - return 1; - } - addr = map_to_sysmem(bmp); - - ret = uclass_first_device_err(UCLASS_VIDEO, &dev); - if (!ret) { - bool align = false; - - if (x == BMP_ALIGN_CENTER || y == BMP_ALIGN_CENTER) - align = true; - - ret = video_bmp_display(dev, addr, x, y, align); - } - - if (bmp_alloc_addr) - free(bmp_alloc_addr); - - return ret ? CMD_RET_FAILURE : 0; -} diff --git a/drivers/video/Makefile b/drivers/video/Makefile index d13af9f3b19..fdc29376324 100644 --- a/drivers/video/Makefile +++ b/drivers/video/Makefile @@ -25,6 +25,7 @@ obj-$(CONFIG_PANEL_HX8238D) += hx8238d.o obj-$(CONFIG_$(SPL_TPL_)SIMPLE_PANEL) += simple_panel.o obj-$(CONFIG_VIDEO_LOGO) += u_boot_logo.o +obj-$(CONFIG_$(SPL_TPL_)BMP) += bmp.o endif diff --git a/drivers/video/bmp.c b/drivers/video/bmp.c new file mode 100644 index 00000000000..bab6fa7265a --- /dev/null +++ b/drivers/video/bmp.c @@ -0,0 +1,142 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * (C) Copyright 2002 + * Detlev Zundel, DENX Software Engineering, dzu@denx.de. + */ + +/* + * BMP handling routines + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * Allocate and decompress a BMP image using gunzip(). + * + * Returns a pointer to the decompressed image data. This pointer is + * aligned to 32-bit-aligned-address + 2. + * See doc/README.displaying-bmps for explanation. + * + * The allocation address is passed to 'alloc_addr' and must be freed + * by the caller after use. + * + * Returns NULL if decompression failed, or if the decompressed data + * didn't contain a valid BMP signature or decompression is not enabled in + * Kconfig. + */ +struct bmp_image *gunzip_bmp(unsigned long addr, unsigned long *lenp, + void **alloc_addr) +{ + void *dst; + unsigned long len; + struct bmp_image *bmp; + + if (!CONFIG_IS_ENABLED(VIDEO_BMP_GZIP)) + return NULL; + + /* + * Decompress bmp image + */ + len = CONFIG_VAL(VIDEO_LOGO_MAX_SIZE); + /* allocate extra 3 bytes for 32-bit-aligned-address + 2 alignment */ + dst = malloc(CONFIG_VAL(VIDEO_LOGO_MAX_SIZE) + 3); + if (!dst) { + puts("Error: malloc in gunzip failed!\n"); + return NULL; + } + + /* align to 32-bit-aligned-address + 2 */ + bmp = dst + 2; + + if (gunzip(bmp, CONFIG_VAL(VIDEO_LOGO_MAX_SIZE), map_sysmem(addr, 0), + &len)) { + free(dst); + return NULL; + } + if (len == CONFIG_VAL(VIDEO_LOGO_MAX_SIZE)) + puts("Image could be truncated (increase CONFIG_VIDEO_LOGO_MAX_SIZE)!\n"); + + /* + * Check for bmp mark 'BM' + */ + if (!((bmp->header.signature[0] == 'B') && + (bmp->header.signature[1] == 'M'))) { + free(dst); + return NULL; + } + + debug("Gzipped BMP image detected!\n"); + + *alloc_addr = dst; + return bmp; +} + +int bmp_info(ulong addr) +{ + struct bmp_image *bmp = (struct bmp_image *)map_sysmem(addr, 0); + void *bmp_alloc_addr = NULL; + unsigned long len; + + if (!((bmp->header.signature[0] == 'B') && + (bmp->header.signature[1] == 'M'))) + bmp = gunzip_bmp(addr, &len, &bmp_alloc_addr); + + if (!bmp) { + printf("There is no valid bmp file at the given address\n"); + return 1; + } + + printf("Image size : %d x %d\n", le32_to_cpu(bmp->header.width), + le32_to_cpu(bmp->header.height)); + printf("Bits per pixel: %d\n", le16_to_cpu(bmp->header.bit_count)); + printf("Compression : %d\n", le32_to_cpu(bmp->header.compression)); + + if (bmp_alloc_addr) + free(bmp_alloc_addr); + + return 0; +} + +int bmp_display(ulong addr, int x, int y) +{ + struct udevice *dev; + int ret; + struct bmp_image *bmp = map_sysmem(addr, 0); + void *bmp_alloc_addr = NULL; + unsigned long len; + + if (!((bmp->header.signature[0] == 'B') && + (bmp->header.signature[1] == 'M'))) + bmp = gunzip_bmp(addr, &len, &bmp_alloc_addr); + + if (!bmp) { + printf("There is no valid bmp file at the given address\n"); + return 1; + } + addr = map_to_sysmem(bmp); + + ret = uclass_first_device_err(UCLASS_VIDEO, &dev); + if (!ret) { + bool align = false; + + if (x == BMP_ALIGN_CENTER || y == BMP_ALIGN_CENTER) + align = true; + + ret = video_bmp_display(dev, addr, x, y, align); + } + + if (bmp_alloc_addr) + free(bmp_alloc_addr); + + return ret ? CMD_RET_FAILURE : 0; +} -- cgit v1.3.1 From 31b097a26540887b7c57552dd7dbbf7fb76dfe61 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Thu, 14 Sep 2023 10:55:42 -0600 Subject: video: Move the BMP options These appear prominently in the main menu at present. Move them to the video Kconfig where they belong. Signed-off-by: Simon Glass Reviewed-by: Tom Rini --- common/Kconfig | 11 ----------- drivers/video/Kconfig | 16 ++++++++++++++++ 2 files changed, 16 insertions(+), 11 deletions(-) diff --git a/common/Kconfig b/common/Kconfig index d916194b942..d11292f52c2 100644 --- a/common/Kconfig +++ b/common/Kconfig @@ -1168,14 +1168,3 @@ config FDT_SIMPLEFB config IO_TRACE bool - -config BMP - bool "Enable bmp image display" - help - Enable bmp functions to display bmp image and get bmp info. - -config SPL_BMP - bool "Enable bmp image display at SPL" - depends on SPL_VIDEO - help - Enable bmp functions to display bmp image and get bmp info at SPL. diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig index 09f2cb1a732..ab927641bb7 100644 --- a/drivers/video/Kconfig +++ b/drivers/video/Kconfig @@ -959,6 +959,14 @@ config SPLASH_SOURCE endif # SPLASH_SCREEN +config BMP + bool "Enable bmp image display" + help + Enable bmp functions to display bmp image and get bmp info. + + BMP is a simple graphics-image file format designed to store bitmap + images. It is primarily used on Windows devices. + config VIDEO_BMP_GZIP bool "Gzip compressed BMP image support" depends on BMP || SPLASH_SCREEN @@ -1162,6 +1170,14 @@ config SPL_SPLASH_SOURCE endif # SPL_SPLASH_SCREEN +config SPL_BMP + bool "Enable bmp image display at SPL" + help + Enable bmp functions to display bmp image and get bmp info in SPL. + + BMP is a simple graphics-image file format designed to store bitmap + images. It is primarily used on Windows devices. + config SPL_VIDEO_BMP_GZIP bool "Gzip compressed BMP image support at SPL" depends on SPL_SPLASH_SCREEN || SPL_BMP -- cgit v1.3.1 From 4cc40f618a83f58216f49040f08e3b5f1868c990 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Thu, 14 Sep 2023 10:55:43 -0600 Subject: FWU: Avoid showing an unselectable menu option Use a menuconfig to avoid showing a menu which cannot be selected in many cases. Signed-off-by: Simon Glass Acked-by: Sughosh Ganu Reviewed-by: Tom Rini Acked-by: Ilias Apalodimas --- lib/Kconfig | 4 ---- lib/fwu_updates/Kconfig | 9 +++++---- 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/lib/Kconfig b/lib/Kconfig index 9addcfab373..bfab2f3165a 100644 --- a/lib/Kconfig +++ b/lib/Kconfig @@ -1118,8 +1118,4 @@ config PHANDLE_CHECK_SEQ endmenu -menu "FWU Multi Bank Updates" - source lib/fwu_updates/Kconfig - -endmenu diff --git a/lib/fwu_updates/Kconfig b/lib/fwu_updates/Kconfig index 71f34793d92..d35247d0e5d 100644 --- a/lib/fwu_updates/Kconfig +++ b/lib/fwu_updates/Kconfig @@ -1,4 +1,4 @@ -config FWU_MULTI_BANK_UPDATE +menuconfig FWU_MULTI_BANK_UPDATE bool "Enable FWU Multi Bank Update Feature" depends on EFI_CAPSULE_ON_DISK select PARTITION_TYPE_GUID @@ -10,24 +10,25 @@ config FWU_MULTI_BANK_UPDATE multiple banks(copies) of the firmware images. One of the bank is selected for updating all the firmware components +if FWU_MULTI_BANK_UPDATE + config FWU_NUM_BANKS int "Number of Banks defined by the platform" - depends on FWU_MULTI_BANK_UPDATE help Define the number of banks of firmware images on a platform config FWU_NUM_IMAGES_PER_BANK int "Number of firmware images per bank" - depends on FWU_MULTI_BANK_UPDATE help Define the number of firmware images per bank. This value should be the same for all the banks. config FWU_TRIAL_STATE_CNT int "Number of times system boots in Trial State" - depends on FWU_MULTI_BANK_UPDATE default 3 help With FWU Multi Bank Update feature enabled, number of times the platform is allowed to boot in Trial State after an update. + +endif -- cgit v1.3.1 From 36778dfc9d58c271f59ebcf20a6a1aa438df9780 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Thu, 14 Sep 2023 10:55:44 -0600 Subject: test: Move POST under a renamed Testing section Rename Unit tests to Testing, since it is a stretch to describe some of the tests as unit tests. Move POST there as well, so it doesn't show up by itself in the top-level menu. Signed-off-by: Simon Glass Reviewed-by: Tom Rini --- test/Kconfig | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/test/Kconfig b/test/Kconfig index 6e859fb7d0d..830245b6f9a 100644 --- a/test/Kconfig +++ b/test/Kconfig @@ -1,9 +1,4 @@ -config POST - bool "Power On Self Test support" - help - See doc/README.POST for more details - -menu "Unit tests" +menu "Testing" config UNIT_TEST bool "Unit tests" @@ -110,4 +105,9 @@ source "test/lib/Kconfig" source "test/optee/Kconfig" source "test/overlay/Kconfig" +config POST + bool "Power On Self Test support" + help + See doc/README.POST for more details + endmenu -- cgit v1.3.1 From b1a4b46734af68d734978cd5220b1af33d124814 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Thu, 14 Sep 2023 10:55:45 -0600 Subject: boot: Move fdt_support to boot/ This relates to booting since it fixes up the devicetree for the OS. Move it into the boot/ directory. Signed-off-by: Simon Glass Reviewed-by: Tom Rini --- boot/Makefile | 3 + boot/fdt_support.c | 2150 ++++++++++++++++++++++++++++++++++++++++++++++++++ common/Makefile | 2 - common/fdt_support.c | 2150 -------------------------------------------------- 4 files changed, 2153 insertions(+), 2152 deletions(-) create mode 100644 boot/fdt_support.c delete mode 100644 common/fdt_support.c diff --git a/boot/Makefile b/boot/Makefile index 10f01572237..f15a161614f 100644 --- a/boot/Makefile +++ b/boot/Makefile @@ -16,6 +16,7 @@ obj-$(CONFIG_QFW) += bootmeth_qfw.o endif obj-y += image.o image-board.o + obj-$(CONFIG_ANDROID_AB) += android_ab.o obj-$(CONFIG_ANDROID_BOOT_IMAGE) += image-android.o image-android-dt.o @@ -37,6 +38,8 @@ obj-$(CONFIG_$(SPL_TPL_)BOOTSTD) += bootflow_menu.o obj-$(CONFIG_$(SPL_TPL_)CEDIT) += cedit.o endif +obj-$(CONFIG_$(SPL_TPL_)OF_LIBFDT) += fdt_support.o + obj-$(CONFIG_$(SPL_TPL_)OF_LIBFDT) += image-fdt.o obj-$(CONFIG_$(SPL_TPL_)FIT_SIGNATURE) += fdt_region.o obj-$(CONFIG_$(SPL_TPL_)FIT) += image-fit.o diff --git a/boot/fdt_support.c b/boot/fdt_support.c new file mode 100644 index 00000000000..5e49078f8c3 --- /dev/null +++ b/boot/fdt_support.c @@ -0,0 +1,2150 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * (C) Copyright 2007 + * Gerald Van Baren, Custom IDEAS, vanbaren@cideas.com + * + * Copyright 2010-2011 Freescale Semiconductor, Inc. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/** + * fdt_getprop_u32_default_node - Return a node's property or a default + * + * @fdt: ptr to device tree + * @off: offset of node + * @cell: cell offset in property + * @prop: property name + * @dflt: default value if the property isn't found + * + * Convenience function to return a node's property or a default value if + * the property doesn't exist. + */ +u32 fdt_getprop_u32_default_node(const void *fdt, int off, int cell, + const char *prop, const u32 dflt) +{ + const fdt32_t *val; + int len; + + val = fdt_getprop(fdt, off, prop, &len); + + /* Check if property exists */ + if (!val) + return dflt; + + /* Check if property is long enough */ + if (len < ((cell + 1) * sizeof(uint32_t))) + return dflt; + + return fdt32_to_cpu(*val); +} + +/** + * fdt_getprop_u32_default - Find a node and return it's property or a default + * + * @fdt: ptr to device tree + * @path: path of node + * @prop: property name + * @dflt: default value if the property isn't found + * + * Convenience function to find a node and return it's property or a + * default value if it doesn't exist. + */ +u32 fdt_getprop_u32_default(const void *fdt, const char *path, + const char *prop, const u32 dflt) +{ + int off; + + off = fdt_path_offset(fdt, path); + if (off < 0) + return dflt; + + return fdt_getprop_u32_default_node(fdt, off, 0, prop, dflt); +} + +/** + * fdt_find_and_setprop: Find a node and set it's property + * + * @fdt: ptr to device tree + * @node: path of node + * @prop: property name + * @val: ptr to new value + * @len: length of new property value + * @create: flag to create the property if it doesn't exist + * + * Convenience function to directly set a property given the path to the node. + */ +int fdt_find_and_setprop(void *fdt, const char *node, const char *prop, + const void *val, int len, int create) +{ + int nodeoff = fdt_path_offset(fdt, node); + + if (nodeoff < 0) + return nodeoff; + + if ((!create) && (fdt_get_property(fdt, nodeoff, prop, NULL) == NULL)) + return 0; /* create flag not set; so exit quietly */ + + return fdt_setprop(fdt, nodeoff, prop, val, len); +} + +/** + * fdt_find_or_add_subnode() - find or possibly add a subnode of a given node + * + * @fdt: pointer to the device tree blob + * @parentoffset: structure block offset of a node + * @name: name of the subnode to locate + * + * fdt_subnode_offset() finds a subnode of the node with a given name. + * If the subnode does not exist, it will be created. + */ +int fdt_find_or_add_subnode(void *fdt, int parentoffset, const char *name) +{ + int offset; + + offset = fdt_subnode_offset(fdt, parentoffset, name); + + if (offset == -FDT_ERR_NOTFOUND) + offset = fdt_add_subnode(fdt, parentoffset, name); + + if (offset < 0) + printf("%s: %s: %s\n", __func__, name, fdt_strerror(offset)); + + return offset; +} + +#if defined(CONFIG_OF_STDOUT_VIA_ALIAS) && defined(CONFIG_CONS_INDEX) +static int fdt_fixup_stdout(void *fdt, int chosenoff) +{ + int err; + int aliasoff; + char sername[9] = { 0 }; + const void *path; + int len; + char tmp[256]; /* long enough */ + + sprintf(sername, "serial%d", CONFIG_CONS_INDEX - 1); + + aliasoff = fdt_path_offset(fdt, "/aliases"); + if (aliasoff < 0) { + err = aliasoff; + goto noalias; + } + + path = fdt_getprop(fdt, aliasoff, sername, &len); + if (!path) { + err = len; + goto noalias; + } + + /* fdt_setprop may break "path" so we copy it to tmp buffer */ + memcpy(tmp, path, len); + + err = fdt_setprop(fdt, chosenoff, "linux,stdout-path", tmp, len); + if (err < 0) + printf("WARNING: could not set linux,stdout-path %s.\n", + fdt_strerror(err)); + + return err; + +noalias: + printf("WARNING: %s: could not read %s alias: %s\n", + __func__, sername, fdt_strerror(err)); + + return 0; +} +#else +static int fdt_fixup_stdout(void *fdt, int chosenoff) +{ + return 0; +} +#endif + +static inline int fdt_setprop_uxx(void *fdt, int nodeoffset, const char *name, + uint64_t val, int is_u64) +{ + if (is_u64) + return fdt_setprop_u64(fdt, nodeoffset, name, val); + else + return fdt_setprop_u32(fdt, nodeoffset, name, (uint32_t)val); +} + +int fdt_root(void *fdt) +{ + char *serial; + int err; + + err = fdt_check_header(fdt); + if (err < 0) { + printf("fdt_root: %s\n", fdt_strerror(err)); + return err; + } + + serial = env_get("serial#"); + if (serial) { + err = fdt_setprop(fdt, 0, "serial-number", serial, + strlen(serial) + 1); + + if (err < 0) { + printf("WARNING: could not set serial-number %s.\n", + fdt_strerror(err)); + return err; + } + } + + return 0; +} + +int fdt_initrd(void *fdt, ulong initrd_start, ulong initrd_end) +{ + int nodeoffset; + int err, j, total; + int is_u64; + uint64_t addr, size; + + /* just return if the size of initrd is zero */ + if (initrd_start == initrd_end) + return 0; + + /* find or create "/chosen" node. */ + nodeoffset = fdt_find_or_add_subnode(fdt, 0, "chosen"); + if (nodeoffset < 0) + return nodeoffset; + + total = fdt_num_mem_rsv(fdt); + + /* + * Look for an existing entry and update it. If we don't find + * the entry, we will j be the next available slot. + */ + for (j = 0; j < total; j++) { + err = fdt_get_mem_rsv(fdt, j, &addr, &size); + if (addr == initrd_start) { + fdt_del_mem_rsv(fdt, j); + break; + } + } + + err = fdt_add_mem_rsv(fdt, initrd_start, initrd_end - initrd_start); + if (err < 0) { + printf("fdt_initrd: %s\n", fdt_strerror(err)); + return err; + } + + is_u64 = (fdt_address_cells(fdt, 0) == 2); + + err = fdt_setprop_uxx(fdt, nodeoffset, "linux,initrd-start", + (uint64_t)initrd_start, is_u64); + + if (err < 0) { + printf("WARNING: could not set linux,initrd-start %s.\n", + fdt_strerror(err)); + return err; + } + + err = fdt_setprop_uxx(fdt, nodeoffset, "linux,initrd-end", + (uint64_t)initrd_end, is_u64); + + if (err < 0) { + printf("WARNING: could not set linux,initrd-end %s.\n", + fdt_strerror(err)); + + return err; + } + + return 0; +} + +/** + * board_fdt_chosen_bootargs - boards may override this function to use + * alternative kernel command line arguments + */ +__weak char *board_fdt_chosen_bootargs(void) +{ + return env_get("bootargs"); +} + +int fdt_chosen(void *fdt) +{ + struct abuf buf = {}; + int nodeoffset; + int err; + char *str; /* used to set string properties */ + + err = fdt_check_header(fdt); + if (err < 0) { + printf("fdt_chosen: %s\n", fdt_strerror(err)); + return err; + } + + /* find or create "/chosen" node. */ + nodeoffset = fdt_find_or_add_subnode(fdt, 0, "chosen"); + if (nodeoffset < 0) + return nodeoffset; + + if (IS_ENABLED(CONFIG_BOARD_RNG_SEED) && !board_rng_seed(&buf)) { + err = fdt_setprop(fdt, nodeoffset, "rng-seed", + abuf_data(&buf), abuf_size(&buf)); + abuf_uninit(&buf); + if (err < 0) { + printf("WARNING: could not set rng-seed %s.\n", + fdt_strerror(err)); + return err; + } + } + + str = board_fdt_chosen_bootargs(); + + if (str) { + err = fdt_setprop(fdt, nodeoffset, "bootargs", str, + strlen(str) + 1); + if (err < 0) { + printf("WARNING: could not set bootargs %s.\n", + fdt_strerror(err)); + return err; + } + } + + /* add u-boot version */ + err = fdt_setprop(fdt, nodeoffset, "u-boot,version", PLAIN_VERSION, + strlen(PLAIN_VERSION) + 1); + if (err < 0) { + printf("WARNING: could not set u-boot,version %s.\n", + fdt_strerror(err)); + return err; + } + + return fdt_fixup_stdout(fdt, nodeoffset); +} + +void do_fixup_by_path(void *fdt, const char *path, const char *prop, + const void *val, int len, int create) +{ +#if defined(DEBUG) + int i; + debug("Updating property '%s/%s' = ", path, prop); + for (i = 0; i < len; i++) + debug(" %.2x", *(u8*)(val+i)); + debug("\n"); +#endif + int rc = fdt_find_and_setprop(fdt, path, prop, val, len, create); + if (rc) + printf("Unable to update property %s:%s, err=%s\n", + path, prop, fdt_strerror(rc)); +} + +void do_fixup_by_path_u32(void *fdt, const char *path, const char *prop, + u32 val, int create) +{ + fdt32_t tmp = cpu_to_fdt32(val); + do_fixup_by_path(fdt, path, prop, &tmp, sizeof(tmp), create); +} + +void do_fixup_by_prop(void *fdt, + const char *pname, const void *pval, int plen, + const char *prop, const void *val, int len, + int create) +{ + int off; +#if defined(DEBUG) + int i; + debug("Updating property '%s' = ", prop); + for (i = 0; i < len; i++) + debug(" %.2x", *(u8*)(val+i)); + debug("\n"); +#endif + off = fdt_node_offset_by_prop_value(fdt, -1, pname, pval, plen); + while (off != -FDT_ERR_NOTFOUND) { + if (create || (fdt_get_property(fdt, off, prop, NULL) != NULL)) + fdt_setprop(fdt, off, prop, val, len); + off = fdt_node_offset_by_prop_value(fdt, off, pname, pval, plen); + } +} + +void do_fixup_by_prop_u32(void *fdt, + const char *pname, const void *pval, int plen, + const char *prop, u32 val, int create) +{ + fdt32_t tmp = cpu_to_fdt32(val); + do_fixup_by_prop(fdt, pname, pval, plen, prop, &tmp, 4, create); +} + +void do_fixup_by_compat(void *fdt, const char *compat, + const char *prop, const void *val, int len, int create) +{ + int off = -1; +#if defined(DEBUG) + int i; + debug("Updating property '%s' = ", prop); + for (i = 0; i < len; i++) + debug(" %.2x", *(u8*)(val+i)); + debug("\n"); +#endif + fdt_for_each_node_by_compatible(off, fdt, -1, compat) + if (create || (fdt_get_property(fdt, off, prop, NULL) != NULL)) + fdt_setprop(fdt, off, prop, val, len); +} + +void do_fixup_by_compat_u32(void *fdt, const char *compat, + const char *prop, u32 val, int create) +{ + fdt32_t tmp = cpu_to_fdt32(val); + do_fixup_by_compat(fdt, compat, prop, &tmp, 4, create); +} + +#ifdef CONFIG_ARCH_FIXUP_FDT_MEMORY +/* + * fdt_pack_reg - pack address and size array into the "reg"-suitable stream + */ +static int fdt_pack_reg(const void *fdt, void *buf, u64 *address, u64 *size, + int n) +{ + int i; + int address_cells = fdt_address_cells(fdt, 0); + int size_cells = fdt_size_cells(fdt, 0); + char *p = buf; + + for (i = 0; i < n; i++) { + if (address_cells == 2) + *(fdt64_t *)p = cpu_to_fdt64(address[i]); + else + *(fdt32_t *)p = cpu_to_fdt32(address[i]); + p += 4 * address_cells; + + if (size_cells == 2) + *(fdt64_t *)p = cpu_to_fdt64(size[i]); + else + *(fdt32_t *)p = cpu_to_fdt32(size[i]); + p += 4 * size_cells; + } + + return p - (char *)buf; +} + +#if CONFIG_NR_DRAM_BANKS > 4 +#define MEMORY_BANKS_MAX CONFIG_NR_DRAM_BANKS +#else +#define MEMORY_BANKS_MAX 4 +#endif + +/** + * fdt_fixup_memory_banks - Update DT memory node + * @blob: Pointer to DT blob + * @start: Pointer to memory start addresses array + * @size: Pointer to memory sizes array + * @banks: Number of memory banks + * + * Return: 0 on success, negative value on failure + * + * Based on the passed number of banks and arrays, the function is able to + * update existing DT memory nodes to match run time detected/changed memory + * configuration. Implementation is handling one specific case with only one + * memory node where multiple tuples could be added/updated. + * The case where multiple memory nodes with a single tuple (base, size) are + * used, this function is only updating the first memory node without removing + * others. + */ +int fdt_fixup_memory_banks(void *blob, u64 start[], u64 size[], int banks) +{ + int err, nodeoffset; + int len, i; + u8 tmp[MEMORY_BANKS_MAX * 16]; /* Up to 64-bit address + 64-bit size */ + + if (banks > MEMORY_BANKS_MAX) { + printf("%s: num banks %d exceeds hardcoded limit %d." + " Recompile with higher MEMORY_BANKS_MAX?\n", + __FUNCTION__, banks, MEMORY_BANKS_MAX); + return -1; + } + + err = fdt_check_header(blob); + if (err < 0) { + printf("%s: %s\n", __FUNCTION__, fdt_strerror(err)); + return err; + } + + /* find or create "/memory" node. */ + nodeoffset = fdt_find_or_add_subnode(blob, 0, "memory"); + if (nodeoffset < 0) + return nodeoffset; + + err = fdt_setprop(blob, nodeoffset, "device_type", "memory", + sizeof("memory")); + if (err < 0) { + printf("WARNING: could not set %s %s.\n", "device_type", + fdt_strerror(err)); + return err; + } + + for (i = 0; i < banks; i++) { + if (start[i] == 0 && size[i] == 0) + break; + } + + banks = i; + + if (!banks) + return 0; + + len = fdt_pack_reg(blob, tmp, start, size, banks); + + err = fdt_setprop(blob, nodeoffset, "reg", tmp, len); + if (err < 0) { + printf("WARNING: could not set %s %s.\n", + "reg", fdt_strerror(err)); + return err; + } + return 0; +} + +int fdt_set_usable_memory(void *blob, u64 start[], u64 size[], int areas) +{ + int err, nodeoffset; + int len; + u8 tmp[8 * 16]; /* Up to 64-bit address + 64-bit size */ + + if (areas > 8) { + printf("%s: num areas %d exceeds hardcoded limit %d\n", + __func__, areas, 8); + return -1; + } + + err = fdt_check_header(blob); + if (err < 0) { + printf("%s: %s\n", __func__, fdt_strerror(err)); + return err; + } + + /* find or create "/memory" node. */ + nodeoffset = fdt_find_or_add_subnode(blob, 0, "memory"); + if (nodeoffset < 0) + return nodeoffset; + + len = fdt_pack_reg(blob, tmp, start, size, areas); + + err = fdt_setprop(blob, nodeoffset, "linux,usable-memory", tmp, len); + if (err < 0) { + printf("WARNING: could not set %s %s.\n", + "reg", fdt_strerror(err)); + return err; + } + + return 0; +} +#endif + +int fdt_fixup_memory(void *blob, u64 start, u64 size) +{ + return fdt_fixup_memory_banks(blob, &start, &size, 1); +} + +void fdt_fixup_ethernet(void *fdt) +{ + int i = 0, j, prop; + char *tmp, *end; + char mac[16]; + const char *path; + unsigned char mac_addr[ARP_HLEN]; + int offset; +#ifdef FDT_SEQ_MACADDR_FROM_ENV + int nodeoff; + const struct fdt_property *fdt_prop; +#endif + + if (fdt_path_offset(fdt, "/aliases") < 0) + return; + + /* Cycle through all aliases */ + for (prop = 0; ; prop++) { + const char *name; + + /* FDT might have been edited, recompute the offset */ + offset = fdt_first_property_offset(fdt, + fdt_path_offset(fdt, "/aliases")); + /* Select property number 'prop' */ + for (j = 0; j < prop; j++) + offset = fdt_next_property_offset(fdt, offset); + + if (offset < 0) + break; + + path = fdt_getprop_by_offset(fdt, offset, &name, NULL); + if (!strncmp(name, "ethernet", 8)) { + /* Treat plain "ethernet" same as "ethernet0". */ + if (!strcmp(name, "ethernet") +#ifdef FDT_SEQ_MACADDR_FROM_ENV + || !strcmp(name, "ethernet0") +#endif + ) + i = 0; +#ifndef FDT_SEQ_MACADDR_FROM_ENV + else + i = trailing_strtol(name); +#endif + if (i != -1) { + if (i == 0) + strcpy(mac, "ethaddr"); + else + sprintf(mac, "eth%daddr", i); + } else { + continue; + } +#ifdef FDT_SEQ_MACADDR_FROM_ENV + nodeoff = fdt_path_offset(fdt, path); + fdt_prop = fdt_get_property(fdt, nodeoff, "status", + NULL); + if (fdt_prop && !strcmp(fdt_prop->data, "disabled")) + continue; + i++; +#endif + tmp = env_get(mac); + if (!tmp) + continue; + + for (j = 0; j < 6; j++) { + mac_addr[j] = tmp ? + hextoul(tmp, &end) : 0; + if (tmp) + tmp = (*end) ? end + 1 : end; + } + + do_fixup_by_path(fdt, path, "mac-address", + &mac_addr, 6, 0); + do_fixup_by_path(fdt, path, "local-mac-address", + &mac_addr, 6, 1); + } + } +} + +int fdt_record_loadable(void *blob, u32 index, const char *name, + uintptr_t load_addr, u32 size, uintptr_t entry_point, + const char *type, const char *os, const char *arch) +{ + int err, node; + + err = fdt_check_header(blob); + if (err < 0) { + printf("%s: %s\n", __func__, fdt_strerror(err)); + return err; + } + + /* find or create "/fit-images" node */ + node = fdt_find_or_add_subnode(blob, 0, "fit-images"); + if (node < 0) + return node; + + /* find or create "/fit-images/" node */ + node = fdt_find_or_add_subnode(blob, node, name); + if (node < 0) + return node; + + fdt_setprop_u64(blob, node, "load", load_addr); + if (entry_point != -1) + fdt_setprop_u64(blob, node, "entry", entry_point); + fdt_setprop_u32(blob, node, "size", size); + if (type) + fdt_setprop_string(blob, node, "type", type); + if (os) + fdt_setprop_string(blob, node, "os", os); + if (arch) + fdt_setprop_string(blob, node, "arch", arch); + + return node; +} + +/* Resize the fdt to its actual size + a bit of padding */ +int fdt_shrink_to_minimum(void *blob, uint extrasize) +{ + int i; + uint64_t addr, size; + int total, ret; + uint actualsize; + int fdt_memrsv = 0; + + if (!blob) + return 0; + + total = fdt_num_mem_rsv(blob); + for (i = 0; i < total; i++) { + fdt_get_mem_rsv(blob, i, &addr, &size); + if (addr == (uintptr_t)blob) { + fdt_del_mem_rsv(blob, i); + fdt_memrsv = 1; + break; + } + } + + /* + * Calculate the actual size of the fdt + * plus the size needed for 5 fdt_add_mem_rsv, one + * for the fdt itself and 4 for a possible initrd + * ((initrd-start + initrd-end) * 2 (name & value)) + */ + actualsize = fdt_off_dt_strings(blob) + + fdt_size_dt_strings(blob) + 5 * sizeof(struct fdt_reserve_entry); + + actualsize += extrasize; + /* Make it so the fdt ends on a page boundary */ + actualsize = ALIGN(actualsize + ((uintptr_t)blob & 0xfff), 0x1000); + actualsize = actualsize - ((uintptr_t)blob & 0xfff); + + /* Change the fdt header to reflect the correct size */ + fdt_set_totalsize(blob, actualsize); + + if (fdt_memrsv) { + /* Add the new reservation */ + ret = fdt_add_mem_rsv(blob, map_to_sysmem(blob), actualsize); + if (ret < 0) + return ret; + } + + return actualsize; +} + +/** + * fdt_delete_disabled_nodes: Delete all nodes with status == "disabled" + * + * @blob: ptr to device tree + */ +int fdt_delete_disabled_nodes(void *blob) +{ + while (1) { + int ret, offset; + + offset = fdt_node_offset_by_prop_value(blob, -1, "status", + "disabled", 9); + if (offset < 0) + break; + + ret = fdt_del_node(blob, offset); + if (ret < 0) + return ret; + } + + return 0; +} + +#ifdef CONFIG_PCI +#define CFG_SYS_PCI_NR_INBOUND_WIN 4 + +#define FDT_PCI_PREFETCH (0x40000000) +#define FDT_PCI_MEM32 (0x02000000) +#define FDT_PCI_IO (0x01000000) +#define FDT_PCI_MEM64 (0x03000000) + +int fdt_pci_dma_ranges(void *blob, int phb_off, struct pci_controller *hose) { + + int addrcell, sizecell, len, r; + u32 *dma_range; + /* sized based on pci addr cells, size-cells, & address-cells */ + u32 dma_ranges[(3 + 2 + 2) * CFG_SYS_PCI_NR_INBOUND_WIN]; + + addrcell = fdt_getprop_u32_default(blob, "/", "#address-cells", 1); + sizecell = fdt_getprop_u32_default(blob, "/", "#size-cells", 1); + + dma_range = &dma_ranges[0]; + for (r = 0; r < hose->region_count; r++) { + u64 bus_start, phys_start, size; + + /* skip if !PCI_REGION_SYS_MEMORY */ + if (!(hose->regions[r].flags & PCI_REGION_SYS_MEMORY)) + continue; + + bus_start = (u64)hose->regions[r].bus_start; + phys_start = (u64)hose->regions[r].phys_start; + size = (u64)hose->regions[r].size; + + dma_range[0] = 0; + if (size >= 0x100000000ull) + dma_range[0] |= cpu_to_fdt32(FDT_PCI_MEM64); + else + dma_range[0] |= cpu_to_fdt32(FDT_PCI_MEM32); + if (hose->regions[r].flags & PCI_REGION_PREFETCH) + dma_range[0] |= cpu_to_fdt32(FDT_PCI_PREFETCH); +#ifdef CONFIG_SYS_PCI_64BIT + dma_range[1] = cpu_to_fdt32(bus_start >> 32); +#else + dma_range[1] = 0; +#endif + dma_range[2] = cpu_to_fdt32(bus_start & 0xffffffff); + + if (addrcell == 2) { + dma_range[3] = cpu_to_fdt32(phys_start >> 32); + dma_range[4] = cpu_to_fdt32(phys_start & 0xffffffff); + } else { + dma_range[3] = cpu_to_fdt32(phys_start & 0xffffffff); + } + + if (sizecell == 2) { + dma_range[3 + addrcell + 0] = + cpu_to_fdt32(size >> 32); + dma_range[3 + addrcell + 1] = + cpu_to_fdt32(size & 0xffffffff); + } else { + dma_range[3 + addrcell + 0] = + cpu_to_fdt32(size & 0xffffffff); + } + + dma_range += (3 + addrcell + sizecell); + } + + len = dma_range - &dma_ranges[0]; + if (len) + fdt_setprop(blob, phb_off, "dma-ranges", &dma_ranges[0], len*4); + + return 0; +} +#endif + +int fdt_increase_size(void *fdt, int add_len) +{ + int newlen; + + newlen = fdt_totalsize(fdt) + add_len; + + /* Open in place with a new len */ + return fdt_open_into(fdt, fdt, newlen); +} + +#ifdef CONFIG_FDT_FIXUP_PARTITIONS +#include +#include + +static int fdt_del_subnodes(const void *blob, int parent_offset) +{ + int off, ndepth; + int ret; + + for (ndepth = 0, off = fdt_next_node(blob, parent_offset, &ndepth); + (off >= 0) && (ndepth > 0); + off = fdt_next_node(blob, off, &ndepth)) { + if (ndepth == 1) { + debug("delete %s: offset: %x\n", + fdt_get_name(blob, off, 0), off); + ret = fdt_del_node((void *)blob, off); + if (ret < 0) { + printf("Can't delete node: %s\n", + fdt_strerror(ret)); + return ret; + } else { + ndepth = 0; + off = parent_offset; + } + } + } + return 0; +} + +static int fdt_del_partitions(void *blob, int parent_offset) +{ + const void *prop; + int ndepth = 0; + int off; + int ret; + + off = fdt_next_node(blob, parent_offset, &ndepth); + if (off > 0 && ndepth == 1) { + prop = fdt_getprop(blob, off, "label", NULL); + if (prop == NULL) { + /* + * Could not find label property, nand {}; node? + * Check subnode, delete partitions there if any. + */ + return fdt_del_partitions(blob, off); + } else { + ret = fdt_del_subnodes(blob, parent_offset); + if (ret < 0) { + printf("Can't remove subnodes: %s\n", + fdt_strerror(ret)); + return ret; + } + } + } + return 0; +} + +static int fdt_node_set_part_info(void *blob, int parent_offset, + struct mtd_device *dev) +{ + struct list_head *pentry; + struct part_info *part; + int off, ndepth = 0; + int part_num, ret; + int sizecell; + char buf[64]; + + ret = fdt_del_partitions(blob, parent_offset); + if (ret < 0) + return ret; + + /* + * Check if size/address is 1 or 2 cells. + * We assume #address-cells and #size-cells have same value. + */ + sizecell = fdt_getprop_u32_default_node(blob, parent_offset, + 0, "#size-cells", 1); + + /* + * Check if it is nand {}; subnode, adjust + * the offset in this case + */ + off = fdt_next_node(blob, parent_offset, &ndepth); + if (off > 0 && ndepth == 1) + parent_offset = off; + + part_num = 0; + list_for_each_prev(pentry, &dev->parts) { + int newoff; + + part = list_entry(pentry, struct part_info, link); + + debug("%2d: %-20s0x%08llx\t0x%08llx\t%d\n", + part_num, part->name, part->size, + part->offset, part->mask_flags); + + sprintf(buf, "partition@%llx", part->offset); +add_sub: + ret = fdt_add_subnode(blob, parent_offset, buf); + if (ret == -FDT_ERR_NOSPACE) { + ret = fdt_increase_size(blob, 512); + if (!ret) + goto add_sub; + else + goto err_size; + } else if (ret < 0) { + printf("Can't add partition node: %s\n", + fdt_strerror(ret)); + return ret; + } + newoff = ret; + + /* Check MTD_WRITEABLE_CMD flag */ + if (part->mask_flags & 1) { +add_ro: + ret = fdt_setprop(blob, newoff, "read_only", NULL, 0); + if (ret == -FDT_ERR_NOSPACE) { + ret = fdt_increase_size(blob, 512); + if (!ret) + goto add_ro; + else + goto err_size; + } else if (ret < 0) + goto err_prop; + } + +add_reg: + if (sizecell == 2) { + ret = fdt_setprop_u64(blob, newoff, + "reg", part->offset); + if (!ret) + ret = fdt_appendprop_u64(blob, newoff, + "reg", part->size); + } else { + ret = fdt_setprop_u32(blob, newoff, + "reg", part->offset); + if (!ret) + ret = fdt_appendprop_u32(blob, newoff, + "reg", part->size); + } + + if (ret == -FDT_ERR_NOSPACE) { + ret = fdt_increase_size(blob, 512); + if (!ret) + goto add_reg; + else + goto err_size; + } else if (ret < 0) + goto err_prop; + +add_label: + ret = fdt_setprop_string(blob, newoff, "label", part->name); + if (ret == -FDT_ERR_NOSPACE) { + ret = fdt_increase_size(blob, 512); + if (!ret) + goto add_label; + else + goto err_size; + } else if (ret < 0) + goto err_prop; + + part_num++; + } + return 0; +err_size: + printf("Can't increase blob size: %s\n", fdt_strerror(ret)); + return ret; +err_prop: + printf("Can't add property: %s\n", fdt_strerror(ret)); + return ret; +} + +/* + * Update partitions in nor/nand nodes using info from + * mtdparts environment variable. The nodes to update are + * specified by node_info structure which contains mtd device + * type and compatible string: E. g. the board code in + * ft_board_setup() could use: + * + * struct node_info nodes[] = { + * { "fsl,mpc5121-nfc", MTD_DEV_TYPE_NAND, }, + * { "cfi-flash", MTD_DEV_TYPE_NOR, }, + * }; + * + * fdt_fixup_mtdparts(blob, nodes, ARRAY_SIZE(nodes)); + */ +void fdt_fixup_mtdparts(void *blob, const struct node_info *node_info, + int node_info_size) +{ + struct mtd_device *dev; + int i, idx; + int noff, parts; + bool inited = false; + + for (i = 0; i < node_info_size; i++) { + idx = 0; + + fdt_for_each_node_by_compatible(noff, blob, -1, + node_info[i].compat) { + const char *prop; + + prop = fdt_getprop(blob, noff, "status", NULL); + if (prop && !strcmp(prop, "disabled")) + continue; + + debug("%s: %s, mtd dev type %d\n", + fdt_get_name(blob, noff, 0), + node_info[i].compat, node_info[i].type); + + if (!inited) { + if (mtdparts_init() != 0) + return; + inited = true; + } + + dev = device_find(node_info[i].type, idx++); + if (dev) { + parts = fdt_subnode_offset(blob, noff, + "partitions"); + if (parts < 0) + parts = noff; + + if (fdt_node_set_part_info(blob, parts, dev)) + return; /* return on error */ + } + } + } +} +#endif + +int fdt_copy_fixed_partitions(void *blob) +{ + ofnode node, subnode; + int off, suboff, res; + char path[256]; + int address_cells, size_cells; + u8 i, j, child_count; + + node = ofnode_by_compatible(ofnode_null(), "fixed-partitions"); + while (ofnode_valid(node)) { + /* copy the U-Boot fixed partition */ + address_cells = ofnode_read_simple_addr_cells(node); + size_cells = ofnode_read_simple_size_cells(node); + + res = ofnode_get_path(ofnode_get_parent(node), path, sizeof(path)); + if (res) + return res; + + off = fdt_path_offset(blob, path); + if (off < 0) + return -ENODEV; + + off = fdt_find_or_add_subnode(blob, off, "partitions"); + res = fdt_setprop_string(blob, off, "compatible", "fixed-partitions"); + if (res) + return res; + + res = fdt_setprop_u32(blob, off, "#address-cells", address_cells); + if (res) + return res; + + res = fdt_setprop_u32(blob, off, "#size-cells", size_cells); + if (res) + return res; + + /* + * parse partition in reverse order as fdt_find_or_add_subnode() only + * insert the new node after the parent's properties + */ + child_count = ofnode_get_child_count(node); + for (i = child_count; i > 0 ; i--) { + subnode = ofnode_first_subnode(node); + if (!ofnode_valid(subnode)) + break; + + for (j = 0; (j < i - 1); j++) + subnode = ofnode_next_subnode(subnode); + + if (!ofnode_valid(subnode)) + break; + + const u32 *reg; + int len; + + suboff = fdt_find_or_add_subnode(blob, off, ofnode_get_name(subnode)); + res = fdt_setprop_string(blob, suboff, "label", + ofnode_read_string(subnode, "label")); + if (res) + return res; + + reg = ofnode_get_property(subnode, "reg", &len); + res = fdt_setprop(blob, suboff, "reg", reg, len); + if (res) + return res; + } + + /* go to next fixed-partitions node */ + node = ofnode_by_compatible(node, "fixed-partitions"); + } + + return 0; +} + +void fdt_del_node_and_alias(void *blob, const char *alias) +{ + int off = fdt_path_offset(blob, alias); + + if (off < 0) + return; + + fdt_del_node(blob, off); + + off = fdt_path_offset(blob, "/aliases"); + fdt_delprop(blob, off, alias); +} + +/* Max address size we deal with */ +#define OF_MAX_ADDR_CELLS 4 +#define OF_CHECK_COUNTS(na, ns) ((na) > 0 && (na) <= OF_MAX_ADDR_CELLS && \ + (ns) > 0) + +/* Debug utility */ +#ifdef DEBUG +static void of_dump_addr(const char *s, const fdt32_t *addr, int na) +{ + printf("%s", s); + while(na--) + printf(" %08x", *(addr++)); + printf("\n"); +} +#else +static void of_dump_addr(const char *s, const fdt32_t *addr, int na) { } +#endif + +/** + * struct of_bus - Callbacks for bus specific translators + * @name: A string used to identify this bus in debug output. + * @addresses: The name of the DT property from which addresses are + * to be read, typically "reg". + * @match: Return non-zero if the node whose parent is at + * parentoffset in the FDT blob corresponds to a bus + * of this type, otherwise return zero. If NULL a match + * is assumed. + * @count_cells:Count how many cells (be32 values) a node whose parent + * is at parentoffset in the FDT blob will require to + * represent its address (written to *addrc) & size + * (written to *sizec). + * @map: Map the address addr from the address space of this + * bus to that of its parent, making use of the ranges + * read from DT to an array at range. na and ns are the + * number of cells (be32 values) used to hold and address + * or size, respectively, for this bus. pna is the number + * of cells used to hold an address for the parent bus. + * Returns the address in the address space of the parent + * bus. + * @translate: Update the value of the address cells at addr within an + * FDT by adding offset to it. na specifies the number of + * cells used to hold the address being translated. Returns + * zero on success, non-zero on error. + * + * Each bus type will include a struct of_bus in the of_busses array, + * providing implementations of some or all of the functions used to + * match the bus & handle address translation for its children. + */ +struct of_bus { + const char *name; + const char *addresses; + int (*match)(const void *blob, int parentoffset); + void (*count_cells)(const void *blob, int parentoffset, + int *addrc, int *sizec); + u64 (*map)(fdt32_t *addr, const fdt32_t *range, + int na, int ns, int pna); + int (*translate)(fdt32_t *addr, u64 offset, int na); +}; + +/* Default translator (generic bus) */ +void fdt_support_default_count_cells(const void *blob, int parentoffset, + int *addrc, int *sizec) +{ + const fdt32_t *prop; + + if (addrc) + *addrc = fdt_address_cells(blob, parentoffset); + + if (sizec) { + prop = fdt_getprop(blob, parentoffset, "#size-cells", NULL); + if (prop) + *sizec = be32_to_cpup(prop); + else + *sizec = 1; + } +} + +static u64 of_bus_default_map(fdt32_t *addr, const fdt32_t *range, + int na, int ns, int pna) +{ + u64 cp, s, da; + + cp = fdt_read_number(range, na); + s = fdt_read_number(range + na + pna, ns); + da = fdt_read_number(addr, na); + + debug("OF: default map, cp=%llx, s=%llx, da=%llx\n", cp, s, da); + + if (da < cp || da >= (cp + s)) + return OF_BAD_ADDR; + return da - cp; +} + +static int of_bus_default_translate(fdt32_t *addr, u64 offset, int na) +{ + u64 a = fdt_read_number(addr, na); + memset(addr, 0, na * 4); + a += offset; + if (na > 1) + addr[na - 2] = cpu_to_fdt32(a >> 32); + addr[na - 1] = cpu_to_fdt32(a & 0xffffffffu); + + return 0; +} + +#ifdef CONFIG_OF_ISA_BUS + +/* ISA bus translator */ +static int of_bus_isa_match(const void *blob, int parentoffset) +{ + const char *name; + + name = fdt_get_name(blob, parentoffset, NULL); + if (!name) + return 0; + + return !strcmp(name, "isa"); +} + +static void of_bus_isa_count_cells(const void *blob, int parentoffset, + int *addrc, int *sizec) +{ + if (addrc) + *addrc = 2; + if (sizec) + *sizec = 1; +} + +static u64 of_bus_isa_map(fdt32_t *addr, const fdt32_t *range, + int na, int ns, int pna) +{ + u64 cp, s, da; + + /* Check address type match */ + if ((addr[0] ^ range[0]) & cpu_to_be32(1)) + return OF_BAD_ADDR; + + cp = fdt_read_number(range + 1, na - 1); + s = fdt_read_number(range + na + pna, ns); + da = fdt_read_number(addr + 1, na - 1); + + debug("OF: ISA map, cp=%llx, s=%llx, da=%llx\n", cp, s, da); + + if (da < cp || da >= (cp + s)) + return OF_BAD_ADDR; + return da - cp; +} + +static int of_bus_isa_translate(fdt32_t *addr, u64 offset, int na) +{ + return of_bus_default_translate(addr + 1, offset, na - 1); +} + +#endif /* CONFIG_OF_ISA_BUS */ + +/* Array of bus specific translators */ +static struct of_bus of_busses[] = { +#ifdef CONFIG_OF_ISA_BUS + /* ISA */ + { + .name = "isa", + .addresses = "reg", + .match = of_bus_isa_match, + .count_cells = of_bus_isa_count_cells, + .map = of_bus_isa_map, + .translate = of_bus_isa_translate, + }, +#endif /* CONFIG_OF_ISA_BUS */ + /* Default */ + { + .name = "default", + .addresses = "reg", + .count_cells = fdt_support_default_count_cells, + .map = of_bus_default_map, + .translate = of_bus_default_translate, + }, +}; + +static struct of_bus *of_match_bus(const void *blob, int parentoffset) +{ + struct of_bus *bus; + + if (ARRAY_SIZE(of_busses) == 1) + return of_busses; + + for (bus = of_busses; bus; bus++) { + if (!bus->match || bus->match(blob, parentoffset)) + return bus; + } + + /* + * We should always have matched the default bus at least, since + * it has a NULL match field. If we didn't then it somehow isn't + * in the of_busses array or something equally catastrophic has + * gone wrong. + */ + assert(0); + return NULL; +} + +static int of_translate_one(const void *blob, int parent, struct of_bus *bus, + struct of_bus *pbus, fdt32_t *addr, + int na, int ns, int pna, const char *rprop) +{ + const fdt32_t *ranges; + int rlen; + int rone; + u64 offset = OF_BAD_ADDR; + + /* Normally, an absence of a "ranges" property means we are + * crossing a non-translatable boundary, and thus the addresses + * below the current not cannot be converted to CPU physical ones. + * Unfortunately, while this is very clear in the spec, it's not + * what Apple understood, and they do have things like /uni-n or + * /ht nodes with no "ranges" property and a lot of perfectly + * useable mapped devices below them. Thus we treat the absence of + * "ranges" as equivalent to an empty "ranges" property which means + * a 1:1 translation at that level. It's up to the caller not to try + * to translate addresses that aren't supposed to be translated in + * the first place. --BenH. + */ + ranges = fdt_getprop(blob, parent, rprop, &rlen); + if (ranges == NULL || rlen == 0) { + offset = fdt_read_number(addr, na); + memset(addr, 0, pna * 4); + debug("OF: no ranges, 1:1 translation\n"); + goto finish; + } + + debug("OF: walking ranges...\n"); + + /* Now walk through the ranges */ + rlen /= 4; + rone = na + pna + ns; + for (; rlen >= rone; rlen -= rone, ranges += rone) { + offset = bus->map(addr, ranges, na, ns, pna); + if (offset != OF_BAD_ADDR) + break; + } + if (offset == OF_BAD_ADDR) { + debug("OF: not found !\n"); + return 1; + } + memcpy(addr, ranges + na, 4 * pna); + + finish: + of_dump_addr("OF: parent translation for:", addr, pna); + debug("OF: with offset: %llu\n", offset); + + /* Translate it into parent bus space */ + return pbus->translate(addr, offset, pna); +} + +/* + * Translate an address from the device-tree into a CPU physical address, + * this walks up the tree and applies the various bus mappings on the + * way. + * + * Note: We consider that crossing any level with #size-cells == 0 to mean + * that translation is impossible (that is we are not dealing with a value + * that can be mapped to a cpu physical address). This is not really specified + * that way, but this is traditionally the way IBM at least do things + */ +static u64 __of_translate_address(const void *blob, int node_offset, + const fdt32_t *in_addr, const char *rprop) +{ + int parent; + struct of_bus *bus, *pbus; + fdt32_t addr[OF_MAX_ADDR_CELLS]; + int na, ns, pna, pns; + u64 result = OF_BAD_ADDR; + + debug("OF: ** translation for device %s **\n", + fdt_get_name(blob, node_offset, NULL)); + + /* Get parent & match bus type */ + parent = fdt_parent_offset(blob, node_offset); + if (parent < 0) + goto bail; + bus = of_match_bus(blob, parent); + + /* Cound address cells & copy address locally */ + bus->count_cells(blob, parent, &na, &ns); + if (!OF_CHECK_COUNTS(na, ns)) { + printf("%s: Bad cell count for %s\n", __FUNCTION__, + fdt_get_name(blob, node_offset, NULL)); + goto bail; + } + memcpy(addr, in_addr, na * 4); + + debug("OF: bus is %s (na=%d, ns=%d) on %s\n", + bus->name, na, ns, fdt_get_name(blob, parent, NULL)); + of_dump_addr("OF: translating address:", addr, na); + + /* Translate */ + for (;;) { + /* Switch to parent bus */ + node_offset = parent; + parent = fdt_parent_offset(blob, node_offset); + + /* If root, we have finished */ + if (parent < 0) { + debug("OF: reached root node\n"); + result = fdt_read_number(addr, na); + break; + } + + /* Get new parent bus and counts */ + pbus = of_match_bus(blob, parent); + pbus->count_cells(blob, parent, &pna, &pns); + if (!OF_CHECK_COUNTS(pna, pns)) { + printf("%s: Bad cell count for %s\n", __FUNCTION__, + fdt_get_name(blob, node_offset, NULL)); + break; + } + + debug("OF: parent bus is %s (na=%d, ns=%d) on %s\n", + pbus->name, pna, pns, fdt_get_name(blob, parent, NULL)); + + /* Apply bus translation */ + if (of_translate_one(blob, node_offset, bus, pbus, + addr, na, ns, pna, rprop)) + break; + + /* Complete the move up one level */ + na = pna; + ns = pns; + bus = pbus; + + of_dump_addr("OF: one level translation:", addr, na); + } + bail: + + return result; +} + +u64 fdt_translate_address(const void *blob, int node_offset, + const fdt32_t *in_addr) +{ + return __of_translate_address(blob, node_offset, in_addr, "ranges"); +} + +u64 fdt_translate_dma_address(const void *blob, int node_offset, + const fdt32_t *in_addr) +{ + return __of_translate_address(blob, node_offset, in_addr, "dma-ranges"); +} + +int fdt_get_dma_range(const void *blob, int node, phys_addr_t *cpu, + dma_addr_t *bus, u64 *size) +{ + bool found_dma_ranges = false; + struct of_bus *bus_node; + const fdt32_t *ranges; + int na, ns, pna, pns; + int parent = node; + int ret = 0; + int len; + + /* Find the closest dma-ranges property */ + while (parent >= 0) { + ranges = fdt_getprop(blob, parent, "dma-ranges", &len); + + /* Ignore empty ranges, they imply no translation required */ + if (ranges && len > 0) + break; + + /* Once we find 'dma-ranges', then a missing one is an error */ + if (found_dma_ranges && !ranges) { + ret = -EINVAL; + goto out; + } + + if (ranges) + found_dma_ranges = true; + + parent = fdt_parent_offset(blob, parent); + } + + if (!ranges || parent < 0) { + debug("no dma-ranges found for node %s\n", + fdt_get_name(blob, node, NULL)); + ret = -ENOENT; + goto out; + } + + /* switch to that node */ + node = parent; + parent = fdt_parent_offset(blob, node); + if (parent < 0) { + printf("Found dma-ranges in root node, shouldn't happen\n"); + ret = -EINVAL; + goto out; + } + + /* Get the address sizes both for the bus and its parent */ + bus_node = of_match_bus(blob, node); + bus_node->count_cells(blob, node, &na, &ns); + if (!OF_CHECK_COUNTS(na, ns)) { + printf("%s: Bad cell count for %s\n", __FUNCTION__, + fdt_get_name(blob, node, NULL)); + return -EINVAL; + goto out; + } + + bus_node = of_match_bus(blob, parent); + bus_node->count_cells(blob, parent, &pna, &pns); + if (!OF_CHECK_COUNTS(pna, pns)) { + printf("%s: Bad cell count for %s\n", __FUNCTION__, + fdt_get_name(blob, parent, NULL)); + return -EINVAL; + goto out; + } + + *bus = fdt_read_number(ranges, na); + *cpu = fdt_translate_dma_address(blob, node, ranges + na); + *size = fdt_read_number(ranges + na + pna, ns); +out: + return ret; +} + +/** + * fdt_node_offset_by_compat_reg: Find a node that matches compatible and + * who's reg property matches a physical cpu address + * + * @blob: ptr to device tree + * @compat: compatible string to match + * @compat_off: property name + * + */ +int fdt_node_offset_by_compat_reg(void *blob, const char *compat, + phys_addr_t compat_off) +{ + int len, off; + + fdt_for_each_node_by_compatible(off, blob, -1, compat) { + const fdt32_t *reg = fdt_getprop(blob, off, "reg", &len); + if (reg && compat_off == fdt_translate_address(blob, off, reg)) + return off; + } + + return -FDT_ERR_NOTFOUND; +} + +static int vnode_offset_by_pathf(void *blob, const char *fmt, va_list ap) +{ + char path[512]; + int len; + + len = vsnprintf(path, sizeof(path), fmt, ap); + if (len < 0 || len + 1 > sizeof(path)) + return -FDT_ERR_NOSPACE; + + return fdt_path_offset(blob, path); +} + +/** + * fdt_node_offset_by_pathf: Find node offset by sprintf formatted path + * + * @blob: ptr to device tree + * @fmt: path format + * @ap: vsnprintf arguments + */ +int fdt_node_offset_by_pathf(void *blob, const char *fmt, ...) +{ + va_list ap; + int res; + + va_start(ap, fmt); + res = vnode_offset_by_pathf(blob, fmt, ap); + va_end(ap); + + return res; +} + +/* + * fdt_set_phandle: Create a phandle property for the given node + * + * @fdt: ptr to device tree + * @nodeoffset: node to update + * @phandle: phandle value to set (must be unique) + */ +int fdt_set_phandle(void *fdt, int nodeoffset, uint32_t phandle) +{ + int ret; + +#ifdef DEBUG + int off = fdt_node_offset_by_phandle(fdt, phandle); + + if ((off >= 0) && (off != nodeoffset)) { + char buf[64]; + + fdt_get_path(fdt, nodeoffset, buf, sizeof(buf)); + printf("Trying to update node %s with phandle %u ", + buf, phandle); + + fdt_get_path(fdt, off, buf, sizeof(buf)); + printf("that already exists in node %s.\n", buf); + return -FDT_ERR_BADPHANDLE; + } +#endif + + ret = fdt_setprop_cell(fdt, nodeoffset, "phandle", phandle); + + return ret; +} + +/* + * fdt_create_phandle: Get or create a phandle property for the given node + * + * @fdt: ptr to device tree + * @nodeoffset: node to update + */ +unsigned int fdt_create_phandle(void *fdt, int nodeoffset) +{ + /* see if there is a phandle already */ + uint32_t phandle = fdt_get_phandle(fdt, nodeoffset); + + /* if we got 0, means no phandle so create one */ + if (phandle == 0) { + int ret; + + ret = fdt_generate_phandle(fdt, &phandle); + if (ret < 0) { + printf("Can't generate phandle: %s\n", + fdt_strerror(ret)); + return 0; + } + + ret = fdt_set_phandle(fdt, nodeoffset, phandle); + if (ret < 0) { + printf("Can't set phandle %u: %s\n", phandle, + fdt_strerror(ret)); + return 0; + } + } + + return phandle; +} + +/** + * fdt_create_phandle_by_compatible: Get or create a phandle for first node with + * given compatible + * + * @fdt: ptr to device tree + * @compat: node's compatible string + */ +unsigned int fdt_create_phandle_by_compatible(void *fdt, const char *compat) +{ + int offset = fdt_node_offset_by_compatible(fdt, -1, compat); + + if (offset < 0) { + printf("Can't find node with compatible \"%s\": %s\n", compat, + fdt_strerror(offset)); + return 0; + } + + return fdt_create_phandle(fdt, offset); +} + +/** + * fdt_create_phandle_by_pathf: Get or create a phandle for node given by + * sprintf-formatted path + * + * @fdt: ptr to device tree + * @fmt, ...: path format string and arguments to pass to sprintf + */ +unsigned int fdt_create_phandle_by_pathf(void *fdt, const char *fmt, ...) +{ + va_list ap; + int offset; + + va_start(ap, fmt); + offset = vnode_offset_by_pathf(fdt, fmt, ap); + va_end(ap); + + if (offset < 0) { + printf("Can't find node by given path: %s\n", + fdt_strerror(offset)); + return 0; + } + + return fdt_create_phandle(fdt, offset); +} + +/* + * fdt_set_node_status: Set status for the given node + * + * @fdt: ptr to device tree + * @nodeoffset: node to update + * @status: FDT_STATUS_OKAY, FDT_STATUS_DISABLED, FDT_STATUS_FAIL + */ +int fdt_set_node_status(void *fdt, int nodeoffset, enum fdt_status status) +{ + int ret = 0; + + if (nodeoffset < 0) + return nodeoffset; + + switch (status) { + case FDT_STATUS_OKAY: + ret = fdt_setprop_string(fdt, nodeoffset, "status", "okay"); + break; + case FDT_STATUS_DISABLED: + ret = fdt_setprop_string(fdt, nodeoffset, "status", "disabled"); + break; + case FDT_STATUS_FAIL: + ret = fdt_setprop_string(fdt, nodeoffset, "status", "fail"); + break; + default: + printf("Invalid fdt status: %x\n", status); + ret = -1; + break; + } + + return ret; +} + +/* + * fdt_set_status_by_alias: Set status for the given node given an alias + * + * @fdt: ptr to device tree + * @alias: alias of node to update + * @status: FDT_STATUS_OKAY, FDT_STATUS_DISABLED, FDT_STATUS_FAIL + */ +int fdt_set_status_by_alias(void *fdt, const char* alias, + enum fdt_status status) +{ + int offset = fdt_path_offset(fdt, alias); + + return fdt_set_node_status(fdt, offset, status); +} + +/** + * fdt_set_status_by_compatible: Set node status for first node with given + * compatible + * + * @fdt: ptr to device tree + * @compat: node's compatible string + * @status: FDT_STATUS_OKAY, FDT_STATUS_DISABLED, FDT_STATUS_FAIL + */ +int fdt_set_status_by_compatible(void *fdt, const char *compat, + enum fdt_status status) +{ + int offset = fdt_node_offset_by_compatible(fdt, -1, compat); + + if (offset < 0) + return offset; + + return fdt_set_node_status(fdt, offset, status); +} + +/** + * fdt_set_status_by_pathf: Set node status for node given by sprintf-formatted + * path + * + * @fdt: ptr to device tree + * @status: FDT_STATUS_OKAY, FDT_STATUS_DISABLED, FDT_STATUS_FAIL + * @fmt, ...: path format string and arguments to pass to sprintf + */ +int fdt_set_status_by_pathf(void *fdt, enum fdt_status status, const char *fmt, + ...) +{ + va_list ap; + int offset; + + va_start(ap, fmt); + offset = vnode_offset_by_pathf(fdt, fmt, ap); + va_end(ap); + + if (offset < 0) + return offset; + + return fdt_set_node_status(fdt, offset, status); +} + +/* + * Verify the physical address of device tree node for a given alias + * + * This function locates the device tree node of a given alias, and then + * verifies that the physical address of that device matches the given + * parameter. It displays a message if there is a mismatch. + * + * Returns 1 on success, 0 on failure + */ +int fdt_verify_alias_address(void *fdt, int anode, const char *alias, u64 addr) +{ + const char *path; + const fdt32_t *reg; + int node, len; + u64 dt_addr; + + path = fdt_getprop(fdt, anode, alias, NULL); + if (!path) { + /* If there's no such alias, then it's not a failure */ + return 1; + } + + node = fdt_path_offset(fdt, path); + if (node < 0) { + printf("Warning: device tree alias '%s' points to invalid " + "node %s.\n", alias, path); + return 0; + } + + reg = fdt_getprop(fdt, node, "reg", &len); + if (!reg) { + printf("Warning: device tree node '%s' has no address.\n", + path); + return 0; + } + + dt_addr = fdt_translate_address(fdt, node, reg); + if (addr != dt_addr) { + printf("Warning: U-Boot configured device %s at address %llu,\n" + "but the device tree has it address %llx.\n", + alias, addr, dt_addr); + return 0; + } + + return 1; +} + +/* + * Returns the base address of an SOC or PCI node + */ +u64 fdt_get_base_address(const void *fdt, int node) +{ + int size; + const fdt32_t *prop; + + prop = fdt_getprop(fdt, node, "reg", &size); + + return prop ? fdt_translate_address(fdt, node, prop) : OF_BAD_ADDR; +} + +/* + * Read a property of size . Currently only supports 1 or 2 cells, + * or 3 cells specially for a PCI address. + */ +static int fdt_read_prop(const fdt32_t *prop, int prop_len, int cell_off, + uint64_t *val, int cells) +{ + const fdt32_t *prop32; + const unaligned_fdt64_t *prop64; + + if ((cell_off + cells) > prop_len) + return -FDT_ERR_NOSPACE; + + prop32 = &prop[cell_off]; + + /* + * Special handling for PCI address in PCI bus + * + * PCI child address is made up of 3 cells. Advance the cell offset + * by 1 so that the PCI child address can be correctly read. + */ + if (cells == 3) + cell_off += 1; + prop64 = (const fdt64_t *)&prop[cell_off]; + + switch (cells) { + case 1: + *val = fdt32_to_cpu(*prop32); + break; + case 2: + case 3: + *val = fdt64_to_cpu(*prop64); + break; + default: + return -FDT_ERR_NOSPACE; + } + + return 0; +} + +/** + * fdt_read_range - Read a node's n'th range property + * + * @fdt: ptr to device tree + * @node: offset of node + * @n: range index + * @child_addr: pointer to storage for the "child address" field + * @addr: pointer to storage for the CPU view translated physical start + * @len: pointer to storage for the range length + * + * Convenience function that reads and interprets a specific range out of + * a number of the "ranges" property array. + */ +int fdt_read_range(void *fdt, int node, int n, uint64_t *child_addr, + uint64_t *addr, uint64_t *len) +{ + int pnode = fdt_parent_offset(fdt, node); + const fdt32_t *ranges; + int pacells; + int acells; + int scells; + int ranges_len; + int cell = 0; + int r = 0; + + /* + * The "ranges" property is an array of + * { } + * + * All 3 elements can span a diffent number of cells. Fetch their size. + */ + pacells = fdt_getprop_u32_default_node(fdt, pnode, 0, "#address-cells", 1); + acells = fdt_getprop_u32_default_node(fdt, node, 0, "#address-cells", 1); + scells = fdt_getprop_u32_default_node(fdt, node, 0, "#size-cells", 1); + + /* Now try to get the ranges property */ + ranges = fdt_getprop(fdt, node, "ranges", &ranges_len); + if (!ranges) + return -FDT_ERR_NOTFOUND; + ranges_len /= sizeof(uint32_t); + + /* Jump to the n'th entry */ + cell = n * (pacells + acells + scells); + + /* Read */ + if (child_addr) { + r = fdt_read_prop(ranges, ranges_len, cell, child_addr, + acells); + if (r) + return r; + } + cell += acells; + + /* Read */ + if (addr) + *addr = fdt_translate_address(fdt, node, ranges + cell); + cell += pacells; + + /* Read */ + if (len) { + r = fdt_read_prop(ranges, ranges_len, cell, len, scells); + if (r) + return r; + } + + return 0; +} + +/** + * fdt_setup_simplefb_node - Fill and enable a simplefb node + * + * @fdt: ptr to device tree + * @node: offset of the simplefb node + * @base_address: framebuffer base address + * @width: width in pixels + * @height: height in pixels + * @stride: bytes per line + * @format: pixel format string + * + * Convenience function to fill and enable a simplefb node. + */ +int fdt_setup_simplefb_node(void *fdt, int node, u64 base_address, u32 width, + u32 height, u32 stride, const char *format) +{ + char name[32]; + fdt32_t cells[4]; + int i, addrc, sizec, ret; + + fdt_support_default_count_cells(fdt, fdt_parent_offset(fdt, node), + &addrc, &sizec); + i = 0; + if (addrc == 2) + cells[i++] = cpu_to_fdt32(base_address >> 32); + cells[i++] = cpu_to_fdt32(base_address); + if (sizec == 2) + cells[i++] = 0; + cells[i++] = cpu_to_fdt32(height * stride); + + ret = fdt_setprop(fdt, node, "reg", cells, sizeof(cells[0]) * i); + if (ret < 0) + return ret; + + snprintf(name, sizeof(name), "framebuffer@%llx", base_address); + ret = fdt_set_name(fdt, node, name); + if (ret < 0) + return ret; + + ret = fdt_setprop_u32(fdt, node, "width", width); + if (ret < 0) + return ret; + + ret = fdt_setprop_u32(fdt, node, "height", height); + if (ret < 0) + return ret; + + ret = fdt_setprop_u32(fdt, node, "stride", stride); + if (ret < 0) + return ret; + + ret = fdt_setprop_string(fdt, node, "format", format); + if (ret < 0) + return ret; + + ret = fdt_setprop_string(fdt, node, "status", "okay"); + if (ret < 0) + return ret; + + return 0; +} + +/* + * Update native-mode in display-timings from display environment variable. + * The node to update are specified by path. + */ +int fdt_fixup_display(void *blob, const char *path, const char *display) +{ + int off, toff; + + if (!display || !path) + return -FDT_ERR_NOTFOUND; + + toff = fdt_path_offset(blob, path); + if (toff >= 0) + toff = fdt_subnode_offset(blob, toff, "display-timings"); + if (toff < 0) + return toff; + + for (off = fdt_first_subnode(blob, toff); + off >= 0; + off = fdt_next_subnode(blob, off)) { + uint32_t h = fdt_get_phandle(blob, off); + debug("%s:0x%x\n", fdt_get_name(blob, off, NULL), + fdt32_to_cpu(h)); + if (strcasecmp(fdt_get_name(blob, off, NULL), display) == 0) + return fdt_setprop_u32(blob, toff, "native-mode", h); + } + return toff; +} + +#ifdef CONFIG_OF_LIBFDT_OVERLAY +/** + * fdt_overlay_apply_verbose - Apply an overlay with verbose error reporting + * + * @fdt: ptr to device tree + * @fdto: ptr to device tree overlay + * + * Convenience function to apply an overlay and display helpful messages + * in the case of an error + */ +int fdt_overlay_apply_verbose(void *fdt, void *fdto) +{ + int err; + bool has_symbols; + + err = fdt_path_offset(fdt, "/__symbols__"); + has_symbols = err >= 0; + + err = fdt_overlay_apply(fdt, fdto); + if (err < 0) { + printf("failed on fdt_overlay_apply(): %s\n", + fdt_strerror(err)); + if (!has_symbols) { + printf("base fdt does did not have a /__symbols__ node\n"); + printf("make sure you've compiled with -@\n"); + } + } + return err; +} +#endif + +/** + * fdt_valid() - Check if an FDT is valid. If not, change it to NULL + * + * @blobp: Pointer to FDT pointer + * Return: 1 if OK, 0 if bad (in which case *blobp is set to NULL) + */ +int fdt_valid(struct fdt_header **blobp) +{ + const void *blob = *blobp; + int err; + + if (!blob) { + printf("The address of the fdt is invalid (NULL).\n"); + return 0; + } + + err = fdt_check_header(blob); + if (err == 0) + return 1; /* valid */ + + if (err < 0) { + printf("libfdt fdt_check_header(): %s", fdt_strerror(err)); + /* + * Be more informative on bad version. + */ + if (err == -FDT_ERR_BADVERSION) { + if (fdt_version(blob) < + FDT_FIRST_SUPPORTED_VERSION) { + printf(" - too old, fdt %d < %d", + fdt_version(blob), + FDT_FIRST_SUPPORTED_VERSION); + } + if (fdt_last_comp_version(blob) > + FDT_LAST_SUPPORTED_VERSION) { + printf(" - too new, fdt %d > %d", + fdt_version(blob), + FDT_LAST_SUPPORTED_VERSION); + } + } + printf("\n"); + *blobp = NULL; + return 0; + } + return 1; +} diff --git a/common/Makefile b/common/Makefile index 0a3f75f2f1c..0948721d0b4 100644 --- a/common/Makefile +++ b/common/Makefile @@ -18,7 +18,6 @@ obj-$(CONFIG_DISPLAY_BOARDINFO) += board_info.o obj-$(CONFIG_DISPLAY_BOARDINFO_LATE) += board_info.o obj-$(CONFIG_FDT_SIMPLEFB) += fdt_simplefb.o -obj-$(CONFIG_$(SPL_TPL_)OF_LIBFDT) += fdt_support.o obj-$(CONFIG_MII) += miiphyutil.o obj-$(CONFIG_CMD_MII) += miiphyutil.o obj-$(CONFIG_PHYLIB) += miiphyutil.o @@ -51,7 +50,6 @@ ifdef CONFIG_SPL_DFU obj-$(CONFIG_DFU_OVER_USB) += dfu.o endif obj-$(CONFIG_SPL_NET) += miiphyutil.o -obj-$(CONFIG_$(SPL_TPL_)OF_LIBFDT) += fdt_support.o obj-$(CONFIG_SPL_USB_HOST) += usb.o usb_hub.o obj-$(CONFIG_SPL_USB_STORAGE) += usb_storage.o diff --git a/common/fdt_support.c b/common/fdt_support.c deleted file mode 100644 index 5e49078f8c3..00000000000 --- a/common/fdt_support.c +++ /dev/null @@ -1,2150 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * (C) Copyright 2007 - * Gerald Van Baren, Custom IDEAS, vanbaren@cideas.com - * - * Copyright 2010-2011 Freescale Semiconductor, Inc. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/** - * fdt_getprop_u32_default_node - Return a node's property or a default - * - * @fdt: ptr to device tree - * @off: offset of node - * @cell: cell offset in property - * @prop: property name - * @dflt: default value if the property isn't found - * - * Convenience function to return a node's property or a default value if - * the property doesn't exist. - */ -u32 fdt_getprop_u32_default_node(const void *fdt, int off, int cell, - const char *prop, const u32 dflt) -{ - const fdt32_t *val; - int len; - - val = fdt_getprop(fdt, off, prop, &len); - - /* Check if property exists */ - if (!val) - return dflt; - - /* Check if property is long enough */ - if (len < ((cell + 1) * sizeof(uint32_t))) - return dflt; - - return fdt32_to_cpu(*val); -} - -/** - * fdt_getprop_u32_default - Find a node and return it's property or a default - * - * @fdt: ptr to device tree - * @path: path of node - * @prop: property name - * @dflt: default value if the property isn't found - * - * Convenience function to find a node and return it's property or a - * default value if it doesn't exist. - */ -u32 fdt_getprop_u32_default(const void *fdt, const char *path, - const char *prop, const u32 dflt) -{ - int off; - - off = fdt_path_offset(fdt, path); - if (off < 0) - return dflt; - - return fdt_getprop_u32_default_node(fdt, off, 0, prop, dflt); -} - -/** - * fdt_find_and_setprop: Find a node and set it's property - * - * @fdt: ptr to device tree - * @node: path of node - * @prop: property name - * @val: ptr to new value - * @len: length of new property value - * @create: flag to create the property if it doesn't exist - * - * Convenience function to directly set a property given the path to the node. - */ -int fdt_find_and_setprop(void *fdt, const char *node, const char *prop, - const void *val, int len, int create) -{ - int nodeoff = fdt_path_offset(fdt, node); - - if (nodeoff < 0) - return nodeoff; - - if ((!create) && (fdt_get_property(fdt, nodeoff, prop, NULL) == NULL)) - return 0; /* create flag not set; so exit quietly */ - - return fdt_setprop(fdt, nodeoff, prop, val, len); -} - -/** - * fdt_find_or_add_subnode() - find or possibly add a subnode of a given node - * - * @fdt: pointer to the device tree blob - * @parentoffset: structure block offset of a node - * @name: name of the subnode to locate - * - * fdt_subnode_offset() finds a subnode of the node with a given name. - * If the subnode does not exist, it will be created. - */ -int fdt_find_or_add_subnode(void *fdt, int parentoffset, const char *name) -{ - int offset; - - offset = fdt_subnode_offset(fdt, parentoffset, name); - - if (offset == -FDT_ERR_NOTFOUND) - offset = fdt_add_subnode(fdt, parentoffset, name); - - if (offset < 0) - printf("%s: %s: %s\n", __func__, name, fdt_strerror(offset)); - - return offset; -} - -#if defined(CONFIG_OF_STDOUT_VIA_ALIAS) && defined(CONFIG_CONS_INDEX) -static int fdt_fixup_stdout(void *fdt, int chosenoff) -{ - int err; - int aliasoff; - char sername[9] = { 0 }; - const void *path; - int len; - char tmp[256]; /* long enough */ - - sprintf(sername, "serial%d", CONFIG_CONS_INDEX - 1); - - aliasoff = fdt_path_offset(fdt, "/aliases"); - if (aliasoff < 0) { - err = aliasoff; - goto noalias; - } - - path = fdt_getprop(fdt, aliasoff, sername, &len); - if (!path) { - err = len; - goto noalias; - } - - /* fdt_setprop may break "path" so we copy it to tmp buffer */ - memcpy(tmp, path, len); - - err = fdt_setprop(fdt, chosenoff, "linux,stdout-path", tmp, len); - if (err < 0) - printf("WARNING: could not set linux,stdout-path %s.\n", - fdt_strerror(err)); - - return err; - -noalias: - printf("WARNING: %s: could not read %s alias: %s\n", - __func__, sername, fdt_strerror(err)); - - return 0; -} -#else -static int fdt_fixup_stdout(void *fdt, int chosenoff) -{ - return 0; -} -#endif - -static inline int fdt_setprop_uxx(void *fdt, int nodeoffset, const char *name, - uint64_t val, int is_u64) -{ - if (is_u64) - return fdt_setprop_u64(fdt, nodeoffset, name, val); - else - return fdt_setprop_u32(fdt, nodeoffset, name, (uint32_t)val); -} - -int fdt_root(void *fdt) -{ - char *serial; - int err; - - err = fdt_check_header(fdt); - if (err < 0) { - printf("fdt_root: %s\n", fdt_strerror(err)); - return err; - } - - serial = env_get("serial#"); - if (serial) { - err = fdt_setprop(fdt, 0, "serial-number", serial, - strlen(serial) + 1); - - if (err < 0) { - printf("WARNING: could not set serial-number %s.\n", - fdt_strerror(err)); - return err; - } - } - - return 0; -} - -int fdt_initrd(void *fdt, ulong initrd_start, ulong initrd_end) -{ - int nodeoffset; - int err, j, total; - int is_u64; - uint64_t addr, size; - - /* just return if the size of initrd is zero */ - if (initrd_start == initrd_end) - return 0; - - /* find or create "/chosen" node. */ - nodeoffset = fdt_find_or_add_subnode(fdt, 0, "chosen"); - if (nodeoffset < 0) - return nodeoffset; - - total = fdt_num_mem_rsv(fdt); - - /* - * Look for an existing entry and update it. If we don't find - * the entry, we will j be the next available slot. - */ - for (j = 0; j < total; j++) { - err = fdt_get_mem_rsv(fdt, j, &addr, &size); - if (addr == initrd_start) { - fdt_del_mem_rsv(fdt, j); - break; - } - } - - err = fdt_add_mem_rsv(fdt, initrd_start, initrd_end - initrd_start); - if (err < 0) { - printf("fdt_initrd: %s\n", fdt_strerror(err)); - return err; - } - - is_u64 = (fdt_address_cells(fdt, 0) == 2); - - err = fdt_setprop_uxx(fdt, nodeoffset, "linux,initrd-start", - (uint64_t)initrd_start, is_u64); - - if (err < 0) { - printf("WARNING: could not set linux,initrd-start %s.\n", - fdt_strerror(err)); - return err; - } - - err = fdt_setprop_uxx(fdt, nodeoffset, "linux,initrd-end", - (uint64_t)initrd_end, is_u64); - - if (err < 0) { - printf("WARNING: could not set linux,initrd-end %s.\n", - fdt_strerror(err)); - - return err; - } - - return 0; -} - -/** - * board_fdt_chosen_bootargs - boards may override this function to use - * alternative kernel command line arguments - */ -__weak char *board_fdt_chosen_bootargs(void) -{ - return env_get("bootargs"); -} - -int fdt_chosen(void *fdt) -{ - struct abuf buf = {}; - int nodeoffset; - int err; - char *str; /* used to set string properties */ - - err = fdt_check_header(fdt); - if (err < 0) { - printf("fdt_chosen: %s\n", fdt_strerror(err)); - return err; - } - - /* find or create "/chosen" node. */ - nodeoffset = fdt_find_or_add_subnode(fdt, 0, "chosen"); - if (nodeoffset < 0) - return nodeoffset; - - if (IS_ENABLED(CONFIG_BOARD_RNG_SEED) && !board_rng_seed(&buf)) { - err = fdt_setprop(fdt, nodeoffset, "rng-seed", - abuf_data(&buf), abuf_size(&buf)); - abuf_uninit(&buf); - if (err < 0) { - printf("WARNING: could not set rng-seed %s.\n", - fdt_strerror(err)); - return err; - } - } - - str = board_fdt_chosen_bootargs(); - - if (str) { - err = fdt_setprop(fdt, nodeoffset, "bootargs", str, - strlen(str) + 1); - if (err < 0) { - printf("WARNING: could not set bootargs %s.\n", - fdt_strerror(err)); - return err; - } - } - - /* add u-boot version */ - err = fdt_setprop(fdt, nodeoffset, "u-boot,version", PLAIN_VERSION, - strlen(PLAIN_VERSION) + 1); - if (err < 0) { - printf("WARNING: could not set u-boot,version %s.\n", - fdt_strerror(err)); - return err; - } - - return fdt_fixup_stdout(fdt, nodeoffset); -} - -void do_fixup_by_path(void *fdt, const char *path, const char *prop, - const void *val, int len, int create) -{ -#if defined(DEBUG) - int i; - debug("Updating property '%s/%s' = ", path, prop); - for (i = 0; i < len; i++) - debug(" %.2x", *(u8*)(val+i)); - debug("\n"); -#endif - int rc = fdt_find_and_setprop(fdt, path, prop, val, len, create); - if (rc) - printf("Unable to update property %s:%s, err=%s\n", - path, prop, fdt_strerror(rc)); -} - -void do_fixup_by_path_u32(void *fdt, const char *path, const char *prop, - u32 val, int create) -{ - fdt32_t tmp = cpu_to_fdt32(val); - do_fixup_by_path(fdt, path, prop, &tmp, sizeof(tmp), create); -} - -void do_fixup_by_prop(void *fdt, - const char *pname, const void *pval, int plen, - const char *prop, const void *val, int len, - int create) -{ - int off; -#if defined(DEBUG) - int i; - debug("Updating property '%s' = ", prop); - for (i = 0; i < len; i++) - debug(" %.2x", *(u8*)(val+i)); - debug("\n"); -#endif - off = fdt_node_offset_by_prop_value(fdt, -1, pname, pval, plen); - while (off != -FDT_ERR_NOTFOUND) { - if (create || (fdt_get_property(fdt, off, prop, NULL) != NULL)) - fdt_setprop(fdt, off, prop, val, len); - off = fdt_node_offset_by_prop_value(fdt, off, pname, pval, plen); - } -} - -void do_fixup_by_prop_u32(void *fdt, - const char *pname, const void *pval, int plen, - const char *prop, u32 val, int create) -{ - fdt32_t tmp = cpu_to_fdt32(val); - do_fixup_by_prop(fdt, pname, pval, plen, prop, &tmp, 4, create); -} - -void do_fixup_by_compat(void *fdt, const char *compat, - const char *prop, const void *val, int len, int create) -{ - int off = -1; -#if defined(DEBUG) - int i; - debug("Updating property '%s' = ", prop); - for (i = 0; i < len; i++) - debug(" %.2x", *(u8*)(val+i)); - debug("\n"); -#endif - fdt_for_each_node_by_compatible(off, fdt, -1, compat) - if (create || (fdt_get_property(fdt, off, prop, NULL) != NULL)) - fdt_setprop(fdt, off, prop, val, len); -} - -void do_fixup_by_compat_u32(void *fdt, const char *compat, - const char *prop, u32 val, int create) -{ - fdt32_t tmp = cpu_to_fdt32(val); - do_fixup_by_compat(fdt, compat, prop, &tmp, 4, create); -} - -#ifdef CONFIG_ARCH_FIXUP_FDT_MEMORY -/* - * fdt_pack_reg - pack address and size array into the "reg"-suitable stream - */ -static int fdt_pack_reg(const void *fdt, void *buf, u64 *address, u64 *size, - int n) -{ - int i; - int address_cells = fdt_address_cells(fdt, 0); - int size_cells = fdt_size_cells(fdt, 0); - char *p = buf; - - for (i = 0; i < n; i++) { - if (address_cells == 2) - *(fdt64_t *)p = cpu_to_fdt64(address[i]); - else - *(fdt32_t *)p = cpu_to_fdt32(address[i]); - p += 4 * address_cells; - - if (size_cells == 2) - *(fdt64_t *)p = cpu_to_fdt64(size[i]); - else - *(fdt32_t *)p = cpu_to_fdt32(size[i]); - p += 4 * size_cells; - } - - return p - (char *)buf; -} - -#if CONFIG_NR_DRAM_BANKS > 4 -#define MEMORY_BANKS_MAX CONFIG_NR_DRAM_BANKS -#else -#define MEMORY_BANKS_MAX 4 -#endif - -/** - * fdt_fixup_memory_banks - Update DT memory node - * @blob: Pointer to DT blob - * @start: Pointer to memory start addresses array - * @size: Pointer to memory sizes array - * @banks: Number of memory banks - * - * Return: 0 on success, negative value on failure - * - * Based on the passed number of banks and arrays, the function is able to - * update existing DT memory nodes to match run time detected/changed memory - * configuration. Implementation is handling one specific case with only one - * memory node where multiple tuples could be added/updated. - * The case where multiple memory nodes with a single tuple (base, size) are - * used, this function is only updating the first memory node without removing - * others. - */ -int fdt_fixup_memory_banks(void *blob, u64 start[], u64 size[], int banks) -{ - int err, nodeoffset; - int len, i; - u8 tmp[MEMORY_BANKS_MAX * 16]; /* Up to 64-bit address + 64-bit size */ - - if (banks > MEMORY_BANKS_MAX) { - printf("%s: num banks %d exceeds hardcoded limit %d." - " Recompile with higher MEMORY_BANKS_MAX?\n", - __FUNCTION__, banks, MEMORY_BANKS_MAX); - return -1; - } - - err = fdt_check_header(blob); - if (err < 0) { - printf("%s: %s\n", __FUNCTION__, fdt_strerror(err)); - return err; - } - - /* find or create "/memory" node. */ - nodeoffset = fdt_find_or_add_subnode(blob, 0, "memory"); - if (nodeoffset < 0) - return nodeoffset; - - err = fdt_setprop(blob, nodeoffset, "device_type", "memory", - sizeof("memory")); - if (err < 0) { - printf("WARNING: could not set %s %s.\n", "device_type", - fdt_strerror(err)); - return err; - } - - for (i = 0; i < banks; i++) { - if (start[i] == 0 && size[i] == 0) - break; - } - - banks = i; - - if (!banks) - return 0; - - len = fdt_pack_reg(blob, tmp, start, size, banks); - - err = fdt_setprop(blob, nodeoffset, "reg", tmp, len); - if (err < 0) { - printf("WARNING: could not set %s %s.\n", - "reg", fdt_strerror(err)); - return err; - } - return 0; -} - -int fdt_set_usable_memory(void *blob, u64 start[], u64 size[], int areas) -{ - int err, nodeoffset; - int len; - u8 tmp[8 * 16]; /* Up to 64-bit address + 64-bit size */ - - if (areas > 8) { - printf("%s: num areas %d exceeds hardcoded limit %d\n", - __func__, areas, 8); - return -1; - } - - err = fdt_check_header(blob); - if (err < 0) { - printf("%s: %s\n", __func__, fdt_strerror(err)); - return err; - } - - /* find or create "/memory" node. */ - nodeoffset = fdt_find_or_add_subnode(blob, 0, "memory"); - if (nodeoffset < 0) - return nodeoffset; - - len = fdt_pack_reg(blob, tmp, start, size, areas); - - err = fdt_setprop(blob, nodeoffset, "linux,usable-memory", tmp, len); - if (err < 0) { - printf("WARNING: could not set %s %s.\n", - "reg", fdt_strerror(err)); - return err; - } - - return 0; -} -#endif - -int fdt_fixup_memory(void *blob, u64 start, u64 size) -{ - return fdt_fixup_memory_banks(blob, &start, &size, 1); -} - -void fdt_fixup_ethernet(void *fdt) -{ - int i = 0, j, prop; - char *tmp, *end; - char mac[16]; - const char *path; - unsigned char mac_addr[ARP_HLEN]; - int offset; -#ifdef FDT_SEQ_MACADDR_FROM_ENV - int nodeoff; - const struct fdt_property *fdt_prop; -#endif - - if (fdt_path_offset(fdt, "/aliases") < 0) - return; - - /* Cycle through all aliases */ - for (prop = 0; ; prop++) { - const char *name; - - /* FDT might have been edited, recompute the offset */ - offset = fdt_first_property_offset(fdt, - fdt_path_offset(fdt, "/aliases")); - /* Select property number 'prop' */ - for (j = 0; j < prop; j++) - offset = fdt_next_property_offset(fdt, offset); - - if (offset < 0) - break; - - path = fdt_getprop_by_offset(fdt, offset, &name, NULL); - if (!strncmp(name, "ethernet", 8)) { - /* Treat plain "ethernet" same as "ethernet0". */ - if (!strcmp(name, "ethernet") -#ifdef FDT_SEQ_MACADDR_FROM_ENV - || !strcmp(name, "ethernet0") -#endif - ) - i = 0; -#ifndef FDT_SEQ_MACADDR_FROM_ENV - else - i = trailing_strtol(name); -#endif - if (i != -1) { - if (i == 0) - strcpy(mac, "ethaddr"); - else - sprintf(mac, "eth%daddr", i); - } else { - continue; - } -#ifdef FDT_SEQ_MACADDR_FROM_ENV - nodeoff = fdt_path_offset(fdt, path); - fdt_prop = fdt_get_property(fdt, nodeoff, "status", - NULL); - if (fdt_prop && !strcmp(fdt_prop->data, "disabled")) - continue; - i++; -#endif - tmp = env_get(mac); - if (!tmp) - continue; - - for (j = 0; j < 6; j++) { - mac_addr[j] = tmp ? - hextoul(tmp, &end) : 0; - if (tmp) - tmp = (*end) ? end + 1 : end; - } - - do_fixup_by_path(fdt, path, "mac-address", - &mac_addr, 6, 0); - do_fixup_by_path(fdt, path, "local-mac-address", - &mac_addr, 6, 1); - } - } -} - -int fdt_record_loadable(void *blob, u32 index, const char *name, - uintptr_t load_addr, u32 size, uintptr_t entry_point, - const char *type, const char *os, const char *arch) -{ - int err, node; - - err = fdt_check_header(blob); - if (err < 0) { - printf("%s: %s\n", __func__, fdt_strerror(err)); - return err; - } - - /* find or create "/fit-images" node */ - node = fdt_find_or_add_subnode(blob, 0, "fit-images"); - if (node < 0) - return node; - - /* find or create "/fit-images/" node */ - node = fdt_find_or_add_subnode(blob, node, name); - if (node < 0) - return node; - - fdt_setprop_u64(blob, node, "load", load_addr); - if (entry_point != -1) - fdt_setprop_u64(blob, node, "entry", entry_point); - fdt_setprop_u32(blob, node, "size", size); - if (type) - fdt_setprop_string(blob, node, "type", type); - if (os) - fdt_setprop_string(blob, node, "os", os); - if (arch) - fdt_setprop_string(blob, node, "arch", arch); - - return node; -} - -/* Resize the fdt to its actual size + a bit of padding */ -int fdt_shrink_to_minimum(void *blob, uint extrasize) -{ - int i; - uint64_t addr, size; - int total, ret; - uint actualsize; - int fdt_memrsv = 0; - - if (!blob) - return 0; - - total = fdt_num_mem_rsv(blob); - for (i = 0; i < total; i++) { - fdt_get_mem_rsv(blob, i, &addr, &size); - if (addr == (uintptr_t)blob) { - fdt_del_mem_rsv(blob, i); - fdt_memrsv = 1; - break; - } - } - - /* - * Calculate the actual size of the fdt - * plus the size needed for 5 fdt_add_mem_rsv, one - * for the fdt itself and 4 for a possible initrd - * ((initrd-start + initrd-end) * 2 (name & value)) - */ - actualsize = fdt_off_dt_strings(blob) + - fdt_size_dt_strings(blob) + 5 * sizeof(struct fdt_reserve_entry); - - actualsize += extrasize; - /* Make it so the fdt ends on a page boundary */ - actualsize = ALIGN(actualsize + ((uintptr_t)blob & 0xfff), 0x1000); - actualsize = actualsize - ((uintptr_t)blob & 0xfff); - - /* Change the fdt header to reflect the correct size */ - fdt_set_totalsize(blob, actualsize); - - if (fdt_memrsv) { - /* Add the new reservation */ - ret = fdt_add_mem_rsv(blob, map_to_sysmem(blob), actualsize); - if (ret < 0) - return ret; - } - - return actualsize; -} - -/** - * fdt_delete_disabled_nodes: Delete all nodes with status == "disabled" - * - * @blob: ptr to device tree - */ -int fdt_delete_disabled_nodes(void *blob) -{ - while (1) { - int ret, offset; - - offset = fdt_node_offset_by_prop_value(blob, -1, "status", - "disabled", 9); - if (offset < 0) - break; - - ret = fdt_del_node(blob, offset); - if (ret < 0) - return ret; - } - - return 0; -} - -#ifdef CONFIG_PCI -#define CFG_SYS_PCI_NR_INBOUND_WIN 4 - -#define FDT_PCI_PREFETCH (0x40000000) -#define FDT_PCI_MEM32 (0x02000000) -#define FDT_PCI_IO (0x01000000) -#define FDT_PCI_MEM64 (0x03000000) - -int fdt_pci_dma_ranges(void *blob, int phb_off, struct pci_controller *hose) { - - int addrcell, sizecell, len, r; - u32 *dma_range; - /* sized based on pci addr cells, size-cells, & address-cells */ - u32 dma_ranges[(3 + 2 + 2) * CFG_SYS_PCI_NR_INBOUND_WIN]; - - addrcell = fdt_getprop_u32_default(blob, "/", "#address-cells", 1); - sizecell = fdt_getprop_u32_default(blob, "/", "#size-cells", 1); - - dma_range = &dma_ranges[0]; - for (r = 0; r < hose->region_count; r++) { - u64 bus_start, phys_start, size; - - /* skip if !PCI_REGION_SYS_MEMORY */ - if (!(hose->regions[r].flags & PCI_REGION_SYS_MEMORY)) - continue; - - bus_start = (u64)hose->regions[r].bus_start; - phys_start = (u64)hose->regions[r].phys_start; - size = (u64)hose->regions[r].size; - - dma_range[0] = 0; - if (size >= 0x100000000ull) - dma_range[0] |= cpu_to_fdt32(FDT_PCI_MEM64); - else - dma_range[0] |= cpu_to_fdt32(FDT_PCI_MEM32); - if (hose->regions[r].flags & PCI_REGION_PREFETCH) - dma_range[0] |= cpu_to_fdt32(FDT_PCI_PREFETCH); -#ifdef CONFIG_SYS_PCI_64BIT - dma_range[1] = cpu_to_fdt32(bus_start >> 32); -#else - dma_range[1] = 0; -#endif - dma_range[2] = cpu_to_fdt32(bus_start & 0xffffffff); - - if (addrcell == 2) { - dma_range[3] = cpu_to_fdt32(phys_start >> 32); - dma_range[4] = cpu_to_fdt32(phys_start & 0xffffffff); - } else { - dma_range[3] = cpu_to_fdt32(phys_start & 0xffffffff); - } - - if (sizecell == 2) { - dma_range[3 + addrcell + 0] = - cpu_to_fdt32(size >> 32); - dma_range[3 + addrcell + 1] = - cpu_to_fdt32(size & 0xffffffff); - } else { - dma_range[3 + addrcell + 0] = - cpu_to_fdt32(size & 0xffffffff); - } - - dma_range += (3 + addrcell + sizecell); - } - - len = dma_range - &dma_ranges[0]; - if (len) - fdt_setprop(blob, phb_off, "dma-ranges", &dma_ranges[0], len*4); - - return 0; -} -#endif - -int fdt_increase_size(void *fdt, int add_len) -{ - int newlen; - - newlen = fdt_totalsize(fdt) + add_len; - - /* Open in place with a new len */ - return fdt_open_into(fdt, fdt, newlen); -} - -#ifdef CONFIG_FDT_FIXUP_PARTITIONS -#include -#include - -static int fdt_del_subnodes(const void *blob, int parent_offset) -{ - int off, ndepth; - int ret; - - for (ndepth = 0, off = fdt_next_node(blob, parent_offset, &ndepth); - (off >= 0) && (ndepth > 0); - off = fdt_next_node(blob, off, &ndepth)) { - if (ndepth == 1) { - debug("delete %s: offset: %x\n", - fdt_get_name(blob, off, 0), off); - ret = fdt_del_node((void *)blob, off); - if (ret < 0) { - printf("Can't delete node: %s\n", - fdt_strerror(ret)); - return ret; - } else { - ndepth = 0; - off = parent_offset; - } - } - } - return 0; -} - -static int fdt_del_partitions(void *blob, int parent_offset) -{ - const void *prop; - int ndepth = 0; - int off; - int ret; - - off = fdt_next_node(blob, parent_offset, &ndepth); - if (off > 0 && ndepth == 1) { - prop = fdt_getprop(blob, off, "label", NULL); - if (prop == NULL) { - /* - * Could not find label property, nand {}; node? - * Check subnode, delete partitions there if any. - */ - return fdt_del_partitions(blob, off); - } else { - ret = fdt_del_subnodes(blob, parent_offset); - if (ret < 0) { - printf("Can't remove subnodes: %s\n", - fdt_strerror(ret)); - return ret; - } - } - } - return 0; -} - -static int fdt_node_set_part_info(void *blob, int parent_offset, - struct mtd_device *dev) -{ - struct list_head *pentry; - struct part_info *part; - int off, ndepth = 0; - int part_num, ret; - int sizecell; - char buf[64]; - - ret = fdt_del_partitions(blob, parent_offset); - if (ret < 0) - return ret; - - /* - * Check if size/address is 1 or 2 cells. - * We assume #address-cells and #size-cells have same value. - */ - sizecell = fdt_getprop_u32_default_node(blob, parent_offset, - 0, "#size-cells", 1); - - /* - * Check if it is nand {}; subnode, adjust - * the offset in this case - */ - off = fdt_next_node(blob, parent_offset, &ndepth); - if (off > 0 && ndepth == 1) - parent_offset = off; - - part_num = 0; - list_for_each_prev(pentry, &dev->parts) { - int newoff; - - part = list_entry(pentry, struct part_info, link); - - debug("%2d: %-20s0x%08llx\t0x%08llx\t%d\n", - part_num, part->name, part->size, - part->offset, part->mask_flags); - - sprintf(buf, "partition@%llx", part->offset); -add_sub: - ret = fdt_add_subnode(blob, parent_offset, buf); - if (ret == -FDT_ERR_NOSPACE) { - ret = fdt_increase_size(blob, 512); - if (!ret) - goto add_sub; - else - goto err_size; - } else if (ret < 0) { - printf("Can't add partition node: %s\n", - fdt_strerror(ret)); - return ret; - } - newoff = ret; - - /* Check MTD_WRITEABLE_CMD flag */ - if (part->mask_flags & 1) { -add_ro: - ret = fdt_setprop(blob, newoff, "read_only", NULL, 0); - if (ret == -FDT_ERR_NOSPACE) { - ret = fdt_increase_size(blob, 512); - if (!ret) - goto add_ro; - else - goto err_size; - } else if (ret < 0) - goto err_prop; - } - -add_reg: - if (sizecell == 2) { - ret = fdt_setprop_u64(blob, newoff, - "reg", part->offset); - if (!ret) - ret = fdt_appendprop_u64(blob, newoff, - "reg", part->size); - } else { - ret = fdt_setprop_u32(blob, newoff, - "reg", part->offset); - if (!ret) - ret = fdt_appendprop_u32(blob, newoff, - "reg", part->size); - } - - if (ret == -FDT_ERR_NOSPACE) { - ret = fdt_increase_size(blob, 512); - if (!ret) - goto add_reg; - else - goto err_size; - } else if (ret < 0) - goto err_prop; - -add_label: - ret = fdt_setprop_string(blob, newoff, "label", part->name); - if (ret == -FDT_ERR_NOSPACE) { - ret = fdt_increase_size(blob, 512); - if (!ret) - goto add_label; - else - goto err_size; - } else if (ret < 0) - goto err_prop; - - part_num++; - } - return 0; -err_size: - printf("Can't increase blob size: %s\n", fdt_strerror(ret)); - return ret; -err_prop: - printf("Can't add property: %s\n", fdt_strerror(ret)); - return ret; -} - -/* - * Update partitions in nor/nand nodes using info from - * mtdparts environment variable. The nodes to update are - * specified by node_info structure which contains mtd device - * type and compatible string: E. g. the board code in - * ft_board_setup() could use: - * - * struct node_info nodes[] = { - * { "fsl,mpc5121-nfc", MTD_DEV_TYPE_NAND, }, - * { "cfi-flash", MTD_DEV_TYPE_NOR, }, - * }; - * - * fdt_fixup_mtdparts(blob, nodes, ARRAY_SIZE(nodes)); - */ -void fdt_fixup_mtdparts(void *blob, const struct node_info *node_info, - int node_info_size) -{ - struct mtd_device *dev; - int i, idx; - int noff, parts; - bool inited = false; - - for (i = 0; i < node_info_size; i++) { - idx = 0; - - fdt_for_each_node_by_compatible(noff, blob, -1, - node_info[i].compat) { - const char *prop; - - prop = fdt_getprop(blob, noff, "status", NULL); - if (prop && !strcmp(prop, "disabled")) - continue; - - debug("%s: %s, mtd dev type %d\n", - fdt_get_name(blob, noff, 0), - node_info[i].compat, node_info[i].type); - - if (!inited) { - if (mtdparts_init() != 0) - return; - inited = true; - } - - dev = device_find(node_info[i].type, idx++); - if (dev) { - parts = fdt_subnode_offset(blob, noff, - "partitions"); - if (parts < 0) - parts = noff; - - if (fdt_node_set_part_info(blob, parts, dev)) - return; /* return on error */ - } - } - } -} -#endif - -int fdt_copy_fixed_partitions(void *blob) -{ - ofnode node, subnode; - int off, suboff, res; - char path[256]; - int address_cells, size_cells; - u8 i, j, child_count; - - node = ofnode_by_compatible(ofnode_null(), "fixed-partitions"); - while (ofnode_valid(node)) { - /* copy the U-Boot fixed partition */ - address_cells = ofnode_read_simple_addr_cells(node); - size_cells = ofnode_read_simple_size_cells(node); - - res = ofnode_get_path(ofnode_get_parent(node), path, sizeof(path)); - if (res) - return res; - - off = fdt_path_offset(blob, path); - if (off < 0) - return -ENODEV; - - off = fdt_find_or_add_subnode(blob, off, "partitions"); - res = fdt_setprop_string(blob, off, "compatible", "fixed-partitions"); - if (res) - return res; - - res = fdt_setprop_u32(blob, off, "#address-cells", address_cells); - if (res) - return res; - - res = fdt_setprop_u32(blob, off, "#size-cells", size_cells); - if (res) - return res; - - /* - * parse partition in reverse order as fdt_find_or_add_subnode() only - * insert the new node after the parent's properties - */ - child_count = ofnode_get_child_count(node); - for (i = child_count; i > 0 ; i--) { - subnode = ofnode_first_subnode(node); - if (!ofnode_valid(subnode)) - break; - - for (j = 0; (j < i - 1); j++) - subnode = ofnode_next_subnode(subnode); - - if (!ofnode_valid(subnode)) - break; - - const u32 *reg; - int len; - - suboff = fdt_find_or_add_subnode(blob, off, ofnode_get_name(subnode)); - res = fdt_setprop_string(blob, suboff, "label", - ofnode_read_string(subnode, "label")); - if (res) - return res; - - reg = ofnode_get_property(subnode, "reg", &len); - res = fdt_setprop(blob, suboff, "reg", reg, len); - if (res) - return res; - } - - /* go to next fixed-partitions node */ - node = ofnode_by_compatible(node, "fixed-partitions"); - } - - return 0; -} - -void fdt_del_node_and_alias(void *blob, const char *alias) -{ - int off = fdt_path_offset(blob, alias); - - if (off < 0) - return; - - fdt_del_node(blob, off); - - off = fdt_path_offset(blob, "/aliases"); - fdt_delprop(blob, off, alias); -} - -/* Max address size we deal with */ -#define OF_MAX_ADDR_CELLS 4 -#define OF_CHECK_COUNTS(na, ns) ((na) > 0 && (na) <= OF_MAX_ADDR_CELLS && \ - (ns) > 0) - -/* Debug utility */ -#ifdef DEBUG -static void of_dump_addr(const char *s, const fdt32_t *addr, int na) -{ - printf("%s", s); - while(na--) - printf(" %08x", *(addr++)); - printf("\n"); -} -#else -static void of_dump_addr(const char *s, const fdt32_t *addr, int na) { } -#endif - -/** - * struct of_bus - Callbacks for bus specific translators - * @name: A string used to identify this bus in debug output. - * @addresses: The name of the DT property from which addresses are - * to be read, typically "reg". - * @match: Return non-zero if the node whose parent is at - * parentoffset in the FDT blob corresponds to a bus - * of this type, otherwise return zero. If NULL a match - * is assumed. - * @count_cells:Count how many cells (be32 values) a node whose parent - * is at parentoffset in the FDT blob will require to - * represent its address (written to *addrc) & size - * (written to *sizec). - * @map: Map the address addr from the address space of this - * bus to that of its parent, making use of the ranges - * read from DT to an array at range. na and ns are the - * number of cells (be32 values) used to hold and address - * or size, respectively, for this bus. pna is the number - * of cells used to hold an address for the parent bus. - * Returns the address in the address space of the parent - * bus. - * @translate: Update the value of the address cells at addr within an - * FDT by adding offset to it. na specifies the number of - * cells used to hold the address being translated. Returns - * zero on success, non-zero on error. - * - * Each bus type will include a struct of_bus in the of_busses array, - * providing implementations of some or all of the functions used to - * match the bus & handle address translation for its children. - */ -struct of_bus { - const char *name; - const char *addresses; - int (*match)(const void *blob, int parentoffset); - void (*count_cells)(const void *blob, int parentoffset, - int *addrc, int *sizec); - u64 (*map)(fdt32_t *addr, const fdt32_t *range, - int na, int ns, int pna); - int (*translate)(fdt32_t *addr, u64 offset, int na); -}; - -/* Default translator (generic bus) */ -void fdt_support_default_count_cells(const void *blob, int parentoffset, - int *addrc, int *sizec) -{ - const fdt32_t *prop; - - if (addrc) - *addrc = fdt_address_cells(blob, parentoffset); - - if (sizec) { - prop = fdt_getprop(blob, parentoffset, "#size-cells", NULL); - if (prop) - *sizec = be32_to_cpup(prop); - else - *sizec = 1; - } -} - -static u64 of_bus_default_map(fdt32_t *addr, const fdt32_t *range, - int na, int ns, int pna) -{ - u64 cp, s, da; - - cp = fdt_read_number(range, na); - s = fdt_read_number(range + na + pna, ns); - da = fdt_read_number(addr, na); - - debug("OF: default map, cp=%llx, s=%llx, da=%llx\n", cp, s, da); - - if (da < cp || da >= (cp + s)) - return OF_BAD_ADDR; - return da - cp; -} - -static int of_bus_default_translate(fdt32_t *addr, u64 offset, int na) -{ - u64 a = fdt_read_number(addr, na); - memset(addr, 0, na * 4); - a += offset; - if (na > 1) - addr[na - 2] = cpu_to_fdt32(a >> 32); - addr[na - 1] = cpu_to_fdt32(a & 0xffffffffu); - - return 0; -} - -#ifdef CONFIG_OF_ISA_BUS - -/* ISA bus translator */ -static int of_bus_isa_match(const void *blob, int parentoffset) -{ - const char *name; - - name = fdt_get_name(blob, parentoffset, NULL); - if (!name) - return 0; - - return !strcmp(name, "isa"); -} - -static void of_bus_isa_count_cells(const void *blob, int parentoffset, - int *addrc, int *sizec) -{ - if (addrc) - *addrc = 2; - if (sizec) - *sizec = 1; -} - -static u64 of_bus_isa_map(fdt32_t *addr, const fdt32_t *range, - int na, int ns, int pna) -{ - u64 cp, s, da; - - /* Check address type match */ - if ((addr[0] ^ range[0]) & cpu_to_be32(1)) - return OF_BAD_ADDR; - - cp = fdt_read_number(range + 1, na - 1); - s = fdt_read_number(range + na + pna, ns); - da = fdt_read_number(addr + 1, na - 1); - - debug("OF: ISA map, cp=%llx, s=%llx, da=%llx\n", cp, s, da); - - if (da < cp || da >= (cp + s)) - return OF_BAD_ADDR; - return da - cp; -} - -static int of_bus_isa_translate(fdt32_t *addr, u64 offset, int na) -{ - return of_bus_default_translate(addr + 1, offset, na - 1); -} - -#endif /* CONFIG_OF_ISA_BUS */ - -/* Array of bus specific translators */ -static struct of_bus of_busses[] = { -#ifdef CONFIG_OF_ISA_BUS - /* ISA */ - { - .name = "isa", - .addresses = "reg", - .match = of_bus_isa_match, - .count_cells = of_bus_isa_count_cells, - .map = of_bus_isa_map, - .translate = of_bus_isa_translate, - }, -#endif /* CONFIG_OF_ISA_BUS */ - /* Default */ - { - .name = "default", - .addresses = "reg", - .count_cells = fdt_support_default_count_cells, - .map = of_bus_default_map, - .translate = of_bus_default_translate, - }, -}; - -static struct of_bus *of_match_bus(const void *blob, int parentoffset) -{ - struct of_bus *bus; - - if (ARRAY_SIZE(of_busses) == 1) - return of_busses; - - for (bus = of_busses; bus; bus++) { - if (!bus->match || bus->match(blob, parentoffset)) - return bus; - } - - /* - * We should always have matched the default bus at least, since - * it has a NULL match field. If we didn't then it somehow isn't - * in the of_busses array or something equally catastrophic has - * gone wrong. - */ - assert(0); - return NULL; -} - -static int of_translate_one(const void *blob, int parent, struct of_bus *bus, - struct of_bus *pbus, fdt32_t *addr, - int na, int ns, int pna, const char *rprop) -{ - const fdt32_t *ranges; - int rlen; - int rone; - u64 offset = OF_BAD_ADDR; - - /* Normally, an absence of a "ranges" property means we are - * crossing a non-translatable boundary, and thus the addresses - * below the current not cannot be converted to CPU physical ones. - * Unfortunately, while this is very clear in the spec, it's not - * what Apple understood, and they do have things like /uni-n or - * /ht nodes with no "ranges" property and a lot of perfectly - * useable mapped devices below them. Thus we treat the absence of - * "ranges" as equivalent to an empty "ranges" property which means - * a 1:1 translation at that level. It's up to the caller not to try - * to translate addresses that aren't supposed to be translated in - * the first place. --BenH. - */ - ranges = fdt_getprop(blob, parent, rprop, &rlen); - if (ranges == NULL || rlen == 0) { - offset = fdt_read_number(addr, na); - memset(addr, 0, pna * 4); - debug("OF: no ranges, 1:1 translation\n"); - goto finish; - } - - debug("OF: walking ranges...\n"); - - /* Now walk through the ranges */ - rlen /= 4; - rone = na + pna + ns; - for (; rlen >= rone; rlen -= rone, ranges += rone) { - offset = bus->map(addr, ranges, na, ns, pna); - if (offset != OF_BAD_ADDR) - break; - } - if (offset == OF_BAD_ADDR) { - debug("OF: not found !\n"); - return 1; - } - memcpy(addr, ranges + na, 4 * pna); - - finish: - of_dump_addr("OF: parent translation for:", addr, pna); - debug("OF: with offset: %llu\n", offset); - - /* Translate it into parent bus space */ - return pbus->translate(addr, offset, pna); -} - -/* - * Translate an address from the device-tree into a CPU physical address, - * this walks up the tree and applies the various bus mappings on the - * way. - * - * Note: We consider that crossing any level with #size-cells == 0 to mean - * that translation is impossible (that is we are not dealing with a value - * that can be mapped to a cpu physical address). This is not really specified - * that way, but this is traditionally the way IBM at least do things - */ -static u64 __of_translate_address(const void *blob, int node_offset, - const fdt32_t *in_addr, const char *rprop) -{ - int parent; - struct of_bus *bus, *pbus; - fdt32_t addr[OF_MAX_ADDR_CELLS]; - int na, ns, pna, pns; - u64 result = OF_BAD_ADDR; - - debug("OF: ** translation for device %s **\n", - fdt_get_name(blob, node_offset, NULL)); - - /* Get parent & match bus type */ - parent = fdt_parent_offset(blob, node_offset); - if (parent < 0) - goto bail; - bus = of_match_bus(blob, parent); - - /* Cound address cells & copy address locally */ - bus->count_cells(blob, parent, &na, &ns); - if (!OF_CHECK_COUNTS(na, ns)) { - printf("%s: Bad cell count for %s\n", __FUNCTION__, - fdt_get_name(blob, node_offset, NULL)); - goto bail; - } - memcpy(addr, in_addr, na * 4); - - debug("OF: bus is %s (na=%d, ns=%d) on %s\n", - bus->name, na, ns, fdt_get_name(blob, parent, NULL)); - of_dump_addr("OF: translating address:", addr, na); - - /* Translate */ - for (;;) { - /* Switch to parent bus */ - node_offset = parent; - parent = fdt_parent_offset(blob, node_offset); - - /* If root, we have finished */ - if (parent < 0) { - debug("OF: reached root node\n"); - result = fdt_read_number(addr, na); - break; - } - - /* Get new parent bus and counts */ - pbus = of_match_bus(blob, parent); - pbus->count_cells(blob, parent, &pna, &pns); - if (!OF_CHECK_COUNTS(pna, pns)) { - printf("%s: Bad cell count for %s\n", __FUNCTION__, - fdt_get_name(blob, node_offset, NULL)); - break; - } - - debug("OF: parent bus is %s (na=%d, ns=%d) on %s\n", - pbus->name, pna, pns, fdt_get_name(blob, parent, NULL)); - - /* Apply bus translation */ - if (of_translate_one(blob, node_offset, bus, pbus, - addr, na, ns, pna, rprop)) - break; - - /* Complete the move up one level */ - na = pna; - ns = pns; - bus = pbus; - - of_dump_addr("OF: one level translation:", addr, na); - } - bail: - - return result; -} - -u64 fdt_translate_address(const void *blob, int node_offset, - const fdt32_t *in_addr) -{ - return __of_translate_address(blob, node_offset, in_addr, "ranges"); -} - -u64 fdt_translate_dma_address(const void *blob, int node_offset, - const fdt32_t *in_addr) -{ - return __of_translate_address(blob, node_offset, in_addr, "dma-ranges"); -} - -int fdt_get_dma_range(const void *blob, int node, phys_addr_t *cpu, - dma_addr_t *bus, u64 *size) -{ - bool found_dma_ranges = false; - struct of_bus *bus_node; - const fdt32_t *ranges; - int na, ns, pna, pns; - int parent = node; - int ret = 0; - int len; - - /* Find the closest dma-ranges property */ - while (parent >= 0) { - ranges = fdt_getprop(blob, parent, "dma-ranges", &len); - - /* Ignore empty ranges, they imply no translation required */ - if (ranges && len > 0) - break; - - /* Once we find 'dma-ranges', then a missing one is an error */ - if (found_dma_ranges && !ranges) { - ret = -EINVAL; - goto out; - } - - if (ranges) - found_dma_ranges = true; - - parent = fdt_parent_offset(blob, parent); - } - - if (!ranges || parent < 0) { - debug("no dma-ranges found for node %s\n", - fdt_get_name(blob, node, NULL)); - ret = -ENOENT; - goto out; - } - - /* switch to that node */ - node = parent; - parent = fdt_parent_offset(blob, node); - if (parent < 0) { - printf("Found dma-ranges in root node, shouldn't happen\n"); - ret = -EINVAL; - goto out; - } - - /* Get the address sizes both for the bus and its parent */ - bus_node = of_match_bus(blob, node); - bus_node->count_cells(blob, node, &na, &ns); - if (!OF_CHECK_COUNTS(na, ns)) { - printf("%s: Bad cell count for %s\n", __FUNCTION__, - fdt_get_name(blob, node, NULL)); - return -EINVAL; - goto out; - } - - bus_node = of_match_bus(blob, parent); - bus_node->count_cells(blob, parent, &pna, &pns); - if (!OF_CHECK_COUNTS(pna, pns)) { - printf("%s: Bad cell count for %s\n", __FUNCTION__, - fdt_get_name(blob, parent, NULL)); - return -EINVAL; - goto out; - } - - *bus = fdt_read_number(ranges, na); - *cpu = fdt_translate_dma_address(blob, node, ranges + na); - *size = fdt_read_number(ranges + na + pna, ns); -out: - return ret; -} - -/** - * fdt_node_offset_by_compat_reg: Find a node that matches compatible and - * who's reg property matches a physical cpu address - * - * @blob: ptr to device tree - * @compat: compatible string to match - * @compat_off: property name - * - */ -int fdt_node_offset_by_compat_reg(void *blob, const char *compat, - phys_addr_t compat_off) -{ - int len, off; - - fdt_for_each_node_by_compatible(off, blob, -1, compat) { - const fdt32_t *reg = fdt_getprop(blob, off, "reg", &len); - if (reg && compat_off == fdt_translate_address(blob, off, reg)) - return off; - } - - return -FDT_ERR_NOTFOUND; -} - -static int vnode_offset_by_pathf(void *blob, const char *fmt, va_list ap) -{ - char path[512]; - int len; - - len = vsnprintf(path, sizeof(path), fmt, ap); - if (len < 0 || len + 1 > sizeof(path)) - return -FDT_ERR_NOSPACE; - - return fdt_path_offset(blob, path); -} - -/** - * fdt_node_offset_by_pathf: Find node offset by sprintf formatted path - * - * @blob: ptr to device tree - * @fmt: path format - * @ap: vsnprintf arguments - */ -int fdt_node_offset_by_pathf(void *blob, const char *fmt, ...) -{ - va_list ap; - int res; - - va_start(ap, fmt); - res = vnode_offset_by_pathf(blob, fmt, ap); - va_end(ap); - - return res; -} - -/* - * fdt_set_phandle: Create a phandle property for the given node - * - * @fdt: ptr to device tree - * @nodeoffset: node to update - * @phandle: phandle value to set (must be unique) - */ -int fdt_set_phandle(void *fdt, int nodeoffset, uint32_t phandle) -{ - int ret; - -#ifdef DEBUG - int off = fdt_node_offset_by_phandle(fdt, phandle); - - if ((off >= 0) && (off != nodeoffset)) { - char buf[64]; - - fdt_get_path(fdt, nodeoffset, buf, sizeof(buf)); - printf("Trying to update node %s with phandle %u ", - buf, phandle); - - fdt_get_path(fdt, off, buf, sizeof(buf)); - printf("that already exists in node %s.\n", buf); - return -FDT_ERR_BADPHANDLE; - } -#endif - - ret = fdt_setprop_cell(fdt, nodeoffset, "phandle", phandle); - - return ret; -} - -/* - * fdt_create_phandle: Get or create a phandle property for the given node - * - * @fdt: ptr to device tree - * @nodeoffset: node to update - */ -unsigned int fdt_create_phandle(void *fdt, int nodeoffset) -{ - /* see if there is a phandle already */ - uint32_t phandle = fdt_get_phandle(fdt, nodeoffset); - - /* if we got 0, means no phandle so create one */ - if (phandle == 0) { - int ret; - - ret = fdt_generate_phandle(fdt, &phandle); - if (ret < 0) { - printf("Can't generate phandle: %s\n", - fdt_strerror(ret)); - return 0; - } - - ret = fdt_set_phandle(fdt, nodeoffset, phandle); - if (ret < 0) { - printf("Can't set phandle %u: %s\n", phandle, - fdt_strerror(ret)); - return 0; - } - } - - return phandle; -} - -/** - * fdt_create_phandle_by_compatible: Get or create a phandle for first node with - * given compatible - * - * @fdt: ptr to device tree - * @compat: node's compatible string - */ -unsigned int fdt_create_phandle_by_compatible(void *fdt, const char *compat) -{ - int offset = fdt_node_offset_by_compatible(fdt, -1, compat); - - if (offset < 0) { - printf("Can't find node with compatible \"%s\": %s\n", compat, - fdt_strerror(offset)); - return 0; - } - - return fdt_create_phandle(fdt, offset); -} - -/** - * fdt_create_phandle_by_pathf: Get or create a phandle for node given by - * sprintf-formatted path - * - * @fdt: ptr to device tree - * @fmt, ...: path format string and arguments to pass to sprintf - */ -unsigned int fdt_create_phandle_by_pathf(void *fdt, const char *fmt, ...) -{ - va_list ap; - int offset; - - va_start(ap, fmt); - offset = vnode_offset_by_pathf(fdt, fmt, ap); - va_end(ap); - - if (offset < 0) { - printf("Can't find node by given path: %s\n", - fdt_strerror(offset)); - return 0; - } - - return fdt_create_phandle(fdt, offset); -} - -/* - * fdt_set_node_status: Set status for the given node - * - * @fdt: ptr to device tree - * @nodeoffset: node to update - * @status: FDT_STATUS_OKAY, FDT_STATUS_DISABLED, FDT_STATUS_FAIL - */ -int fdt_set_node_status(void *fdt, int nodeoffset, enum fdt_status status) -{ - int ret = 0; - - if (nodeoffset < 0) - return nodeoffset; - - switch (status) { - case FDT_STATUS_OKAY: - ret = fdt_setprop_string(fdt, nodeoffset, "status", "okay"); - break; - case FDT_STATUS_DISABLED: - ret = fdt_setprop_string(fdt, nodeoffset, "status", "disabled"); - break; - case FDT_STATUS_FAIL: - ret = fdt_setprop_string(fdt, nodeoffset, "status", "fail"); - break; - default: - printf("Invalid fdt status: %x\n", status); - ret = -1; - break; - } - - return ret; -} - -/* - * fdt_set_status_by_alias: Set status for the given node given an alias - * - * @fdt: ptr to device tree - * @alias: alias of node to update - * @status: FDT_STATUS_OKAY, FDT_STATUS_DISABLED, FDT_STATUS_FAIL - */ -int fdt_set_status_by_alias(void *fdt, const char* alias, - enum fdt_status status) -{ - int offset = fdt_path_offset(fdt, alias); - - return fdt_set_node_status(fdt, offset, status); -} - -/** - * fdt_set_status_by_compatible: Set node status for first node with given - * compatible - * - * @fdt: ptr to device tree - * @compat: node's compatible string - * @status: FDT_STATUS_OKAY, FDT_STATUS_DISABLED, FDT_STATUS_FAIL - */ -int fdt_set_status_by_compatible(void *fdt, const char *compat, - enum fdt_status status) -{ - int offset = fdt_node_offset_by_compatible(fdt, -1, compat); - - if (offset < 0) - return offset; - - return fdt_set_node_status(fdt, offset, status); -} - -/** - * fdt_set_status_by_pathf: Set node status for node given by sprintf-formatted - * path - * - * @fdt: ptr to device tree - * @status: FDT_STATUS_OKAY, FDT_STATUS_DISABLED, FDT_STATUS_FAIL - * @fmt, ...: path format string and arguments to pass to sprintf - */ -int fdt_set_status_by_pathf(void *fdt, enum fdt_status status, const char *fmt, - ...) -{ - va_list ap; - int offset; - - va_start(ap, fmt); - offset = vnode_offset_by_pathf(fdt, fmt, ap); - va_end(ap); - - if (offset < 0) - return offset; - - return fdt_set_node_status(fdt, offset, status); -} - -/* - * Verify the physical address of device tree node for a given alias - * - * This function locates the device tree node of a given alias, and then - * verifies that the physical address of that device matches the given - * parameter. It displays a message if there is a mismatch. - * - * Returns 1 on success, 0 on failure - */ -int fdt_verify_alias_address(void *fdt, int anode, const char *alias, u64 addr) -{ - const char *path; - const fdt32_t *reg; - int node, len; - u64 dt_addr; - - path = fdt_getprop(fdt, anode, alias, NULL); - if (!path) { - /* If there's no such alias, then it's not a failure */ - return 1; - } - - node = fdt_path_offset(fdt, path); - if (node < 0) { - printf("Warning: device tree alias '%s' points to invalid " - "node %s.\n", alias, path); - return 0; - } - - reg = fdt_getprop(fdt, node, "reg", &len); - if (!reg) { - printf("Warning: device tree node '%s' has no address.\n", - path); - return 0; - } - - dt_addr = fdt_translate_address(fdt, node, reg); - if (addr != dt_addr) { - printf("Warning: U-Boot configured device %s at address %llu,\n" - "but the device tree has it address %llx.\n", - alias, addr, dt_addr); - return 0; - } - - return 1; -} - -/* - * Returns the base address of an SOC or PCI node - */ -u64 fdt_get_base_address(const void *fdt, int node) -{ - int size; - const fdt32_t *prop; - - prop = fdt_getprop(fdt, node, "reg", &size); - - return prop ? fdt_translate_address(fdt, node, prop) : OF_BAD_ADDR; -} - -/* - * Read a property of size . Currently only supports 1 or 2 cells, - * or 3 cells specially for a PCI address. - */ -static int fdt_read_prop(const fdt32_t *prop, int prop_len, int cell_off, - uint64_t *val, int cells) -{ - const fdt32_t *prop32; - const unaligned_fdt64_t *prop64; - - if ((cell_off + cells) > prop_len) - return -FDT_ERR_NOSPACE; - - prop32 = &prop[cell_off]; - - /* - * Special handling for PCI address in PCI bus - * - * PCI child address is made up of 3 cells. Advance the cell offset - * by 1 so that the PCI child address can be correctly read. - */ - if (cells == 3) - cell_off += 1; - prop64 = (const fdt64_t *)&prop[cell_off]; - - switch (cells) { - case 1: - *val = fdt32_to_cpu(*prop32); - break; - case 2: - case 3: - *val = fdt64_to_cpu(*prop64); - break; - default: - return -FDT_ERR_NOSPACE; - } - - return 0; -} - -/** - * fdt_read_range - Read a node's n'th range property - * - * @fdt: ptr to device tree - * @node: offset of node - * @n: range index - * @child_addr: pointer to storage for the "child address" field - * @addr: pointer to storage for the CPU view translated physical start - * @len: pointer to storage for the range length - * - * Convenience function that reads and interprets a specific range out of - * a number of the "ranges" property array. - */ -int fdt_read_range(void *fdt, int node, int n, uint64_t *child_addr, - uint64_t *addr, uint64_t *len) -{ - int pnode = fdt_parent_offset(fdt, node); - const fdt32_t *ranges; - int pacells; - int acells; - int scells; - int ranges_len; - int cell = 0; - int r = 0; - - /* - * The "ranges" property is an array of - * { } - * - * All 3 elements can span a diffent number of cells. Fetch their size. - */ - pacells = fdt_getprop_u32_default_node(fdt, pnode, 0, "#address-cells", 1); - acells = fdt_getprop_u32_default_node(fdt, node, 0, "#address-cells", 1); - scells = fdt_getprop_u32_default_node(fdt, node, 0, "#size-cells", 1); - - /* Now try to get the ranges property */ - ranges = fdt_getprop(fdt, node, "ranges", &ranges_len); - if (!ranges) - return -FDT_ERR_NOTFOUND; - ranges_len /= sizeof(uint32_t); - - /* Jump to the n'th entry */ - cell = n * (pacells + acells + scells); - - /* Read */ - if (child_addr) { - r = fdt_read_prop(ranges, ranges_len, cell, child_addr, - acells); - if (r) - return r; - } - cell += acells; - - /* Read */ - if (addr) - *addr = fdt_translate_address(fdt, node, ranges + cell); - cell += pacells; - - /* Read */ - if (len) { - r = fdt_read_prop(ranges, ranges_len, cell, len, scells); - if (r) - return r; - } - - return 0; -} - -/** - * fdt_setup_simplefb_node - Fill and enable a simplefb node - * - * @fdt: ptr to device tree - * @node: offset of the simplefb node - * @base_address: framebuffer base address - * @width: width in pixels - * @height: height in pixels - * @stride: bytes per line - * @format: pixel format string - * - * Convenience function to fill and enable a simplefb node. - */ -int fdt_setup_simplefb_node(void *fdt, int node, u64 base_address, u32 width, - u32 height, u32 stride, const char *format) -{ - char name[32]; - fdt32_t cells[4]; - int i, addrc, sizec, ret; - - fdt_support_default_count_cells(fdt, fdt_parent_offset(fdt, node), - &addrc, &sizec); - i = 0; - if (addrc == 2) - cells[i++] = cpu_to_fdt32(base_address >> 32); - cells[i++] = cpu_to_fdt32(base_address); - if (sizec == 2) - cells[i++] = 0; - cells[i++] = cpu_to_fdt32(height * stride); - - ret = fdt_setprop(fdt, node, "reg", cells, sizeof(cells[0]) * i); - if (ret < 0) - return ret; - - snprintf(name, sizeof(name), "framebuffer@%llx", base_address); - ret = fdt_set_name(fdt, node, name); - if (ret < 0) - return ret; - - ret = fdt_setprop_u32(fdt, node, "width", width); - if (ret < 0) - return ret; - - ret = fdt_setprop_u32(fdt, node, "height", height); - if (ret < 0) - return ret; - - ret = fdt_setprop_u32(fdt, node, "stride", stride); - if (ret < 0) - return ret; - - ret = fdt_setprop_string(fdt, node, "format", format); - if (ret < 0) - return ret; - - ret = fdt_setprop_string(fdt, node, "status", "okay"); - if (ret < 0) - return ret; - - return 0; -} - -/* - * Update native-mode in display-timings from display environment variable. - * The node to update are specified by path. - */ -int fdt_fixup_display(void *blob, const char *path, const char *display) -{ - int off, toff; - - if (!display || !path) - return -FDT_ERR_NOTFOUND; - - toff = fdt_path_offset(blob, path); - if (toff >= 0) - toff = fdt_subnode_offset(blob, toff, "display-timings"); - if (toff < 0) - return toff; - - for (off = fdt_first_subnode(blob, toff); - off >= 0; - off = fdt_next_subnode(blob, off)) { - uint32_t h = fdt_get_phandle(blob, off); - debug("%s:0x%x\n", fdt_get_name(blob, off, NULL), - fdt32_to_cpu(h)); - if (strcasecmp(fdt_get_name(blob, off, NULL), display) == 0) - return fdt_setprop_u32(blob, toff, "native-mode", h); - } - return toff; -} - -#ifdef CONFIG_OF_LIBFDT_OVERLAY -/** - * fdt_overlay_apply_verbose - Apply an overlay with verbose error reporting - * - * @fdt: ptr to device tree - * @fdto: ptr to device tree overlay - * - * Convenience function to apply an overlay and display helpful messages - * in the case of an error - */ -int fdt_overlay_apply_verbose(void *fdt, void *fdto) -{ - int err; - bool has_symbols; - - err = fdt_path_offset(fdt, "/__symbols__"); - has_symbols = err >= 0; - - err = fdt_overlay_apply(fdt, fdto); - if (err < 0) { - printf("failed on fdt_overlay_apply(): %s\n", - fdt_strerror(err)); - if (!has_symbols) { - printf("base fdt does did not have a /__symbols__ node\n"); - printf("make sure you've compiled with -@\n"); - } - } - return err; -} -#endif - -/** - * fdt_valid() - Check if an FDT is valid. If not, change it to NULL - * - * @blobp: Pointer to FDT pointer - * Return: 1 if OK, 0 if bad (in which case *blobp is set to NULL) - */ -int fdt_valid(struct fdt_header **blobp) -{ - const void *blob = *blobp; - int err; - - if (!blob) { - printf("The address of the fdt is invalid (NULL).\n"); - return 0; - } - - err = fdt_check_header(blob); - if (err == 0) - return 1; /* valid */ - - if (err < 0) { - printf("libfdt fdt_check_header(): %s", fdt_strerror(err)); - /* - * Be more informative on bad version. - */ - if (err == -FDT_ERR_BADVERSION) { - if (fdt_version(blob) < - FDT_FIRST_SUPPORTED_VERSION) { - printf(" - too old, fdt %d < %d", - fdt_version(blob), - FDT_FIRST_SUPPORTED_VERSION); - } - if (fdt_last_comp_version(blob) > - FDT_LAST_SUPPORTED_VERSION) { - printf(" - too new, fdt %d > %d", - fdt_version(blob), - FDT_LAST_SUPPORTED_VERSION); - } - } - printf("\n"); - *blobp = NULL; - return 0; - } - return 1; -} -- cgit v1.3.1 From ddc5f9b13ec6665e480e3415a3cd2a3e5668cb4d Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Thu, 14 Sep 2023 10:55:46 -0600 Subject: Move fdt_simplefb to boot/ This relates to booting, so move it there. Create a new Kconfig menu for things related to devicetree fixup. Signed-off-by: Simon Glass Reviewed-by: Tom Rini --- boot/Kconfig | 16 +++++++ boot/Makefile | 1 + boot/fdt_simplefb.c | 116 ++++++++++++++++++++++++++++++++++++++++++++++++++ common/Kconfig | 9 ---- common/Makefile | 1 - common/fdt_simplefb.c | 116 -------------------------------------------------- 6 files changed, 133 insertions(+), 126 deletions(-) create mode 100644 boot/fdt_simplefb.c delete mode 100644 common/fdt_simplefb.c diff --git a/boot/Kconfig b/boot/Kconfig index 0a98f1e2220..39c51e9e2fe 100644 --- a/boot/Kconfig +++ b/boot/Kconfig @@ -1538,6 +1538,22 @@ config SPL_IMAGE_PRE_LOAD_SIG endmenu +if OF_LIBFDT + +menu "Devicetree fixup" + +config FDT_SIMPLEFB + bool "FDT tools for simplefb support" + help + Enable the fdt tools to manage the simple fb nodes in device tree. + These functions can be used by board to indicate to the OS + the presence of the simple frame buffer with associated reserved + memory + +endmenu + +endif # OF_LIBFDT + config USE_BOOTARGS bool "Enable boot arguments" help diff --git a/boot/Makefile b/boot/Makefile index f15a161614f..6ce983b83fa 100644 --- a/boot/Makefile +++ b/boot/Makefile @@ -39,6 +39,7 @@ obj-$(CONFIG_$(SPL_TPL_)CEDIT) += cedit.o endif obj-$(CONFIG_$(SPL_TPL_)OF_LIBFDT) += fdt_support.o +obj-$(CONFIG_$(SPL_TPL_)FDT_SIMPLEFB) += fdt_simplefb.o obj-$(CONFIG_$(SPL_TPL_)OF_LIBFDT) += image-fdt.o obj-$(CONFIG_$(SPL_TPL_)FIT_SIGNATURE) += fdt_region.o diff --git a/boot/fdt_simplefb.c b/boot/fdt_simplefb.c new file mode 100644 index 00000000000..069ced75a7f --- /dev/null +++ b/boot/fdt_simplefb.c @@ -0,0 +1,116 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Simplefb device tree support + * + * (C) Copyright 2015 + * Stephen Warren + */ + +#include +#include +#include +#include +#include +#include + +DECLARE_GLOBAL_DATA_PTR; + +static int fdt_simplefb_configure_node(void *blob, int off) +{ + int xsize, ysize; + int bpix; /* log2 of bits per pixel */ + const char *name; + ulong fb_base; + struct video_uc_plat *plat; + struct video_priv *uc_priv; + struct udevice *dev; + int ret; + + ret = uclass_first_device_err(UCLASS_VIDEO, &dev); + if (ret) + return ret; + uc_priv = dev_get_uclass_priv(dev); + plat = dev_get_uclass_plat(dev); + xsize = uc_priv->xsize; + ysize = uc_priv->ysize; + bpix = uc_priv->bpix; + fb_base = plat->base; + switch (bpix) { + case 4: /* VIDEO_BPP16 */ + name = "r5g6b5"; + break; + case 5: /* VIDEO_BPP32 */ + name = "a8r8g8b8"; + break; + default: + return -EINVAL; + } + + return fdt_setup_simplefb_node(blob, off, fb_base, xsize, ysize, + xsize * (1 << bpix) / 8, name); +} + +int fdt_simplefb_add_node(void *blob) +{ + static const char compat[] = "simple-framebuffer"; + static const char disabled[] = "disabled"; + int off, ret; + + off = fdt_add_subnode(blob, 0, "framebuffer"); + if (off < 0) + return -1; + + ret = fdt_setprop(blob, off, "status", disabled, sizeof(disabled)); + if (ret < 0) + return -1; + + ret = fdt_setprop(blob, off, "compatible", compat, sizeof(compat)); + if (ret < 0) + return -1; + + return fdt_simplefb_configure_node(blob, off); +} + +/** + * fdt_simplefb_enable_existing_node() - enable simple-framebuffer DT node + * + * @blob: device-tree + * Return: 0 on success, non-zero otherwise + */ +static int fdt_simplefb_enable_existing_node(void *blob) +{ + int off; + + off = fdt_node_offset_by_compatible(blob, -1, "simple-framebuffer"); + if (off < 0) + return -1; + + return fdt_simplefb_configure_node(blob, off); +} + +#if IS_ENABLED(CONFIG_VIDEO) +int fdt_simplefb_enable_and_mem_rsv(void *blob) +{ + struct fdt_memory mem; + int ret; + + /* nothing to do when video is not active */ + if (!video_is_active()) + return 0; + + ret = fdt_simplefb_enable_existing_node(blob); + if (ret) + return ret; + + /* nothing to do when the frame buffer is not defined */ + if (gd->video_bottom == gd->video_top) + return 0; + + /* reserved with no-map tag the video buffer */ + mem.start = gd->video_bottom; + mem.end = gd->video_top - 1; + + return fdtdec_add_reserved_memory(blob, "framebuffer", &mem, NULL, 0, NULL, + FDTDEC_RESERVED_MEMORY_NO_MAP); +} +#endif diff --git a/common/Kconfig b/common/Kconfig index d11292f52c2..21eaa5e815f 100644 --- a/common/Kconfig +++ b/common/Kconfig @@ -1157,14 +1157,5 @@ config VPL_IMAGE_SIGN_INFO endif -config FDT_SIMPLEFB - bool "FDT tools for simplefb support" - depends on OF_LIBFDT - help - Enable the fdt tools to manage the simple fb nodes in device tree. - These functions can be used by board to indicate to the OS - the presence of the simple frame buffer with associated reserved - memory - config IO_TRACE bool diff --git a/common/Makefile b/common/Makefile index 0948721d0b4..5c1617206f0 100644 --- a/common/Makefile +++ b/common/Makefile @@ -17,7 +17,6 @@ obj-y += board_r.o obj-$(CONFIG_DISPLAY_BOARDINFO) += board_info.o obj-$(CONFIG_DISPLAY_BOARDINFO_LATE) += board_info.o -obj-$(CONFIG_FDT_SIMPLEFB) += fdt_simplefb.o obj-$(CONFIG_MII) += miiphyutil.o obj-$(CONFIG_CMD_MII) += miiphyutil.o obj-$(CONFIG_PHYLIB) += miiphyutil.o diff --git a/common/fdt_simplefb.c b/common/fdt_simplefb.c deleted file mode 100644 index 069ced75a7f..00000000000 --- a/common/fdt_simplefb.c +++ /dev/null @@ -1,116 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * Simplefb device tree support - * - * (C) Copyright 2015 - * Stephen Warren - */ - -#include -#include -#include -#include -#include -#include - -DECLARE_GLOBAL_DATA_PTR; - -static int fdt_simplefb_configure_node(void *blob, int off) -{ - int xsize, ysize; - int bpix; /* log2 of bits per pixel */ - const char *name; - ulong fb_base; - struct video_uc_plat *plat; - struct video_priv *uc_priv; - struct udevice *dev; - int ret; - - ret = uclass_first_device_err(UCLASS_VIDEO, &dev); - if (ret) - return ret; - uc_priv = dev_get_uclass_priv(dev); - plat = dev_get_uclass_plat(dev); - xsize = uc_priv->xsize; - ysize = uc_priv->ysize; - bpix = uc_priv->bpix; - fb_base = plat->base; - switch (bpix) { - case 4: /* VIDEO_BPP16 */ - name = "r5g6b5"; - break; - case 5: /* VIDEO_BPP32 */ - name = "a8r8g8b8"; - break; - default: - return -EINVAL; - } - - return fdt_setup_simplefb_node(blob, off, fb_base, xsize, ysize, - xsize * (1 << bpix) / 8, name); -} - -int fdt_simplefb_add_node(void *blob) -{ - static const char compat[] = "simple-framebuffer"; - static const char disabled[] = "disabled"; - int off, ret; - - off = fdt_add_subnode(blob, 0, "framebuffer"); - if (off < 0) - return -1; - - ret = fdt_setprop(blob, off, "status", disabled, sizeof(disabled)); - if (ret < 0) - return -1; - - ret = fdt_setprop(blob, off, "compatible", compat, sizeof(compat)); - if (ret < 0) - return -1; - - return fdt_simplefb_configure_node(blob, off); -} - -/** - * fdt_simplefb_enable_existing_node() - enable simple-framebuffer DT node - * - * @blob: device-tree - * Return: 0 on success, non-zero otherwise - */ -static int fdt_simplefb_enable_existing_node(void *blob) -{ - int off; - - off = fdt_node_offset_by_compatible(blob, -1, "simple-framebuffer"); - if (off < 0) - return -1; - - return fdt_simplefb_configure_node(blob, off); -} - -#if IS_ENABLED(CONFIG_VIDEO) -int fdt_simplefb_enable_and_mem_rsv(void *blob) -{ - struct fdt_memory mem; - int ret; - - /* nothing to do when video is not active */ - if (!video_is_active()) - return 0; - - ret = fdt_simplefb_enable_existing_node(blob); - if (ret) - return ret; - - /* nothing to do when the frame buffer is not defined */ - if (gd->video_bottom == gd->video_top) - return 0; - - /* reserved with no-map tag the video buffer */ - mem.start = gd->video_bottom; - mem.end = gd->video_top - 1; - - return fdtdec_add_reserved_memory(blob, "framebuffer", &mem, NULL, 0, NULL, - FDTDEC_RESERVED_MEMORY_NO_MAP); -} -#endif -- cgit v1.3.1 From 96095e131ccaebc4aee2e4fac92602a619f1aa57 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Thu, 14 Sep 2023 10:55:47 -0600 Subject: boot: Move some other fdt-fixup options to the same menu Move more options relating to fixing up a device tree into the new devicetree-fixup menu. Signed-off-by: Simon Glass Reviewed-by: Tom Rini --- boot/Kconfig | 55 ++++++++++++++++++++++++++----------------------------- 1 file changed, 26 insertions(+), 29 deletions(-) diff --git a/boot/Kconfig b/boot/Kconfig index 39c51e9e2fe..f8b8d608951 100644 --- a/boot/Kconfig +++ b/boot/Kconfig @@ -696,35 +696,6 @@ config SUPPORT_RAW_INITRD address of the initrd must be augmented by it's size, in the following format: ":". -config OF_BOARD_SETUP - bool "Set up board-specific details in device tree before boot" - depends on OF_LIBFDT - help - This causes U-Boot to call ft_board_setup() before booting into - the Operating System. This function can set up various - board-specific information in the device tree for use by the OS. - The device tree is then passed to the OS. - -config OF_SYSTEM_SETUP - bool "Set up system-specific details in device tree before boot" - depends on OF_LIBFDT - help - This causes U-Boot to call ft_system_setup() before booting into - the Operating System. This function can set up various - system-specific information in the device tree for use by the OS. - The device tree is then passed to the OS. - -config OF_STDOUT_VIA_ALIAS - bool "Update the device-tree stdout alias from U-Boot" - depends on OF_LIBFDT - help - This uses U-Boot's serial alias from the aliases node to update - the device tree passed to the OS. The "linux,stdout-path" property - in the chosen node is set to point to the correct serial node. - This option currently references CONFIG_CONS_INDEX, which is - incorrect when used with device tree as this option does not - exist / should not be used. - config HAVE_TEXT_BASE bool depends on !NIOS2 && !XTENSA @@ -1542,6 +1513,32 @@ if OF_LIBFDT menu "Devicetree fixup" +config OF_BOARD_SETUP + bool "Set up board-specific details in device tree before boot" + help + This causes U-Boot to call ft_board_setup() before booting into + the Operating System. This function can set up various + board-specific information in the device tree for use by the OS. + The device tree is then passed to the OS. + +config OF_SYSTEM_SETUP + bool "Set up system-specific details in device tree before boot" + help + This causes U-Boot to call ft_system_setup() before booting into + the Operating System. This function can set up various + system-specific information in the device tree for use by the OS. + The device tree is then passed to the OS. + +config OF_STDOUT_VIA_ALIAS + bool "Update the device-tree stdout alias from U-Boot" + help + This uses U-Boot's serial alias from the aliases node to update + the device tree passed to the OS. The "linux,stdout-path" property + in the chosen node is set to point to the correct serial node. + This option currently references CONFIG_CONS_INDEX, which is + incorrect when used with device tree as this option does not + exist / should not be used. + config FDT_SIMPLEFB bool "FDT tools for simplefb support" help -- cgit v1.3.1 From 47b18c0e33ea58d83e76d5e4bb4a25bb3e55657e Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Thu, 14 Sep 2023 10:55:48 -0600 Subject: boot: Rename Android-boot text Phrases like 'Enable support for' are pointless since this is an option which enables things. Drop that part so it is easier to follow. Signed-off-by: Simon Glass Reviewed-by: Mattijs Korpershoek Reviewed-by: Tom Rini --- boot/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/boot/Kconfig b/boot/Kconfig index f8b8d608951..017f7117d57 100644 --- a/boot/Kconfig +++ b/boot/Kconfig @@ -3,7 +3,7 @@ menu "Boot options" menu "Boot images" config ANDROID_BOOT_IMAGE - bool "Enable support for Android Boot Images" + bool "Android Boot Images" default y if FASTBOOT help This enables support for booting images which use the Android -- cgit v1.3.1 From 12a7ea005957b3439fd10654da2bc6bac8c53f4e Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Thu, 14 Sep 2023 10:55:49 -0600 Subject: Kconfig: Create a menu for FIT This is a major feature with a lot of options. Give it its own menu to tidy up the 'make menuconfig' display. Drop the 'depends on FIT' pieces which are now unnecessary, since they are now bracketed by an 'if FIT'. Leave CONFIG_TIMESTAMP out since it affects legacy images too. Signed-off-by: Simon Glass Reviewed-by: Tom Rini --- boot/Kconfig | 38 ++++++++++++++++++-------------------- 1 file changed, 18 insertions(+), 20 deletions(-) diff --git a/boot/Kconfig b/boot/Kconfig index 017f7117d57..99a2ffca2fc 100644 --- a/boot/Kconfig +++ b/boot/Kconfig @@ -9,8 +9,19 @@ config ANDROID_BOOT_IMAGE This enables support for booting images which use the Android image format header. -config FIT - bool "Support Flattened Image Tree" +config TIMESTAMP + bool "Show image date and time when displaying image information" + default y if CMD_DATE + help + When CONFIG_TIMESTAMP is selected, the timestamp (date and time) of + an image is printed by image commands like bootm or iminfo. This + is shown as 'Timestamp: xxx' and 'Created: xxx'. If this option is + enabled, then U-Boot requires FITs to have a timestamp. If a FIT is + loaded that does not, the message 'Wrong FIT format: no timestamp' + is shown. + +menuconfig FIT + bool "Flattened Image Tree (FIT)" select HASH select MD5 select SHA1 @@ -25,20 +36,10 @@ config FIT multiple configurations, verification through hashing and also verified boot (secure boot using RSA). -config TIMESTAMP - bool "Show image date and time when displaying image information" - default y if CMD_DATE - help - When CONFIG_TIMESTAMP is selected, the timestamp (date and time) of - an image is printed by image commands like bootm or iminfo. This - is shown as 'Timestamp: xxx' and 'Created: xxx'. If this option is - enabled, then U-Boot requires FITs to have a timestamp. If a FIT is - loaded that does not, the message 'Wrong FIT format: no timestamp' - is shown. +if FIT config FIT_EXTERNAL_OFFSET hex "FIT external data offset" - depends on FIT default 0x0 help This specifies a data offset in fit image. @@ -49,7 +50,6 @@ config FIT_EXTERNAL_OFFSET config FIT_FULL_CHECK bool "Do a full check of the FIT before using it" - depends on FIT default y help Enable this do a full check of the FIT to make sure it is valid. This @@ -59,7 +59,7 @@ config FIT_FULL_CHECK config FIT_SIGNATURE bool "Enable signature verification of FIT uImages" - depends on DM && FIT + depends on DM select HASH imply RSA imply RSA_VERIFY @@ -97,7 +97,7 @@ config FIT_RSASSA_PSS config FIT_CIPHER bool "Enable ciphering data in a FIT uImages" - depends on DM && FIT + depends on DM select AES help Enable the feature of data ciphering/unciphering in the tool mkimage @@ -105,7 +105,6 @@ config FIT_CIPHER config FIT_VERBOSE bool "Show verbose messages when FIT images fail" - depends on FIT help Generally a system will have valid FIT images so debug messages are a waste of code space. If you are debugging your images then @@ -114,7 +113,6 @@ config FIT_VERBOSE config FIT_BEST_MATCH bool "Select the best match for the kernel device tree" - depends on FIT help When no configuration is explicitly selected, default to the one whose fdt's compatibility field best matches that of @@ -124,7 +122,6 @@ config FIT_BEST_MATCH config FIT_IMAGE_POST_PROCESS bool "Enable post-processing of FIT artifacts after loading by U-Boot" - depends on FIT depends on SOCFPGA_SECURE_VAB_AUTH help Allows doing any sort of manipulation to blobs after they got extracted @@ -139,11 +136,12 @@ config FIT_IMAGE_POST_PROCESS config FIT_PRINT bool "Support FIT printing" - depends on FIT default y help Support printing the content of the fitImage in a verbose manner. +endif # FIT + config SPL_FIT bool "Support Flattened Image Tree within SPL" depends on SPL && FIT -- cgit v1.3.1 From 63f0da65e16ff50a3f011b1107fcae67b24b4afb Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Thu, 14 Sep 2023 10:55:50 -0600 Subject: spl: Tidy up load address in spl_ram This CONFIG is used but is not given a value by some boards. Use a default value of 0 explicitly, rather than relying on the 0 value provided by CONFIG_SPL_LOAD_FIT_ADDRESS This will allow us to make SPL_LOAD_FIT_ADDRESS depend on SPL_LOAD_FIT as it should. Signed-off-by: Simon Glass Reviewed-by: Tom Rini --- common/spl/spl_ram.c | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/common/spl/spl_ram.c b/common/spl/spl_ram.c index 93cf420d810..4158ed1c32d 100644 --- a/common/spl/spl_ram.c +++ b/common/spl/spl_ram.c @@ -20,12 +20,16 @@ static ulong spl_ram_load_read(struct spl_load_info *load, ulong sector, ulong count, void *buf) { - ulong addr; + ulong addr = 0; debug("%s: sector %lx, count %lx, buf %lx\n", __func__, sector, count, (ulong)buf); - addr = (ulong)CONFIG_SPL_LOAD_FIT_ADDRESS + sector; + if (IS_ENABLED(CONFIG_SPL_LOAD_FIT)) { + addr = IF_ENABLED_INT(CONFIG_SPL_LOAD_FIT, + CONFIG_SPL_LOAD_FIT_ADDRESS); + } + addr += sector; if (CONFIG_IS_ENABLED(IMAGE_PRE_LOAD)) addr += image_load_offset; @@ -38,20 +42,23 @@ static int spl_ram_load_image(struct spl_image_info *spl_image, struct spl_boot_device *bootdev) { struct legacy_img_hdr *header; + ulong addr = 0; int ret; - header = (struct legacy_img_hdr *)CONFIG_SPL_LOAD_FIT_ADDRESS; + if (IS_ENABLED(CONFIG_SPL_LOAD_FIT)) { + addr = IF_ENABLED_INT(CONFIG_SPL_LOAD_FIT, + CONFIG_SPL_LOAD_FIT_ADDRESS); + } if (CONFIG_IS_ENABLED(IMAGE_PRE_LOAD)) { - unsigned long addr = (unsigned long)header; ret = image_pre_load(addr); if (ret) return ret; addr += image_load_offset; - header = (struct legacy_img_hdr *)addr; } + header = map_sysmem(addr, 0); #if CONFIG_IS_ENABLED(DFU) if (bootdev->boot_device == BOOT_DEVICE_DFU) @@ -84,7 +91,7 @@ static int spl_ram_load_image(struct spl_image_info *spl_image, u_boot_pos = (ulong)spl_get_load_buffer(-sizeof(*header), sizeof(*header)); } - header = (struct legacy_img_hdr *)map_sysmem(u_boot_pos, 0); + header = map_sysmem(u_boot_pos, 0); ret = spl_parse_image_header(spl_image, bootdev, header); } -- cgit v1.3.1 From 815f8d3f86dcabea7b82d302aefa86c6cc09a210 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Thu, 14 Sep 2023 10:55:51 -0600 Subject: spl: Drop SPL/TPL_RAM_SUPPORT option for SPL_LOAD_FIT_ADDRESS All boards which actually define this address enable SPL_LOAD_FIT, or at least just rely on the default value of 0. So drop the dependency. Signed-off-by: Simon Glass Reviewed-by: Tom Rini --- boot/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/boot/Kconfig b/boot/Kconfig index 99a2ffca2fc..f564cb8dd84 100644 --- a/boot/Kconfig +++ b/boot/Kconfig @@ -217,7 +217,7 @@ config SPL_LOAD_FIT config SPL_LOAD_FIT_ADDRESS hex "load address of fit image" - depends on SPL_LOAD_FIT || SPL_RAM_SUPPORT || TPL_RAM_SUPPORT + depends on SPL_LOAD_FIT default 0x0 help Specify the load address of the fit image that will be loaded -- cgit v1.3.1 From 4d8ea26f99062c92e93d25a1cb7613600b30b3c7 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Thu, 14 Sep 2023 10:55:52 -0600 Subject: Kconfig: Move SPL_FIT under FIT This option already depends on FIT, so put it under the same umbrella, so that it appears in the FIT menu. Signed-off-by: Simon Glass Reviewed-by: Tom Rini --- boot/Kconfig | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/boot/Kconfig b/boot/Kconfig index f564cb8dd84..9b09d636d05 100644 --- a/boot/Kconfig +++ b/boot/Kconfig @@ -140,11 +140,9 @@ config FIT_PRINT help Support printing the content of the fitImage in a verbose manner. -endif # FIT - config SPL_FIT bool "Support Flattened Image Tree within SPL" - depends on SPL && FIT + depends on SPL select SPL_HASH select SPL_OF_LIBFDT @@ -195,7 +193,7 @@ config SPL_FIT_RSASSA_PSS config SPL_LOAD_FIT bool "Enable SPL loading U-Boot as a FIT (basic fitImage features)" - depends on SPL && FIT + depends on SPL select SPL_FIT help Normally with the SPL framework a legacy image is generated as part @@ -243,7 +241,6 @@ config SPL_LOAD_FIT_APPLY_OVERLAY_BUF_SZ config SPL_LOAD_FIT_FULL bool "Enable SPL loading U-Boot as a FIT (full fitImage features)" - depends on FIT select SPL_FIT help Normally with the SPL framework a legacy image is generated as part @@ -341,6 +338,8 @@ config VPL_FIT_SIGNATURE_MAX_SIZE endif # VPL +endif # FIT + config PXE_UTILS bool select MENU -- cgit v1.3.1 From 4a8fcb6e0b384c42906e411f051e3c54d168516d Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Thu, 14 Sep 2023 10:55:53 -0600 Subject: boot: Make standard boot a menu Collect these options into a menu for easier viewing. Signed-off-by: Simon Glass Reviewed-by: Tom Rini --- boot/Kconfig | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/boot/Kconfig b/boot/Kconfig index 9b09d636d05..a885fea692f 100644 --- a/boot/Kconfig +++ b/boot/Kconfig @@ -372,8 +372,8 @@ config BOOT_DEFAULTS of U-Boot to boot various images. Currently much functionality is tied to enabling the command that exercises it. -config BOOTSTD - bool "Standard boot support" +menuconfig BOOTSTD + bool "Standard boot" default y depends on DM && OF_CONTROL && BLK help @@ -393,6 +393,8 @@ config BOOTSTD U-Boot) - bootflow - a description of how to boot (owned by the distro) +if BOOTSTD + config SPL_BOOTSTD bool "Standard boot support in SPL" depends on SPL && SPL_DM && SPL_OF_CONTROL && SPL_BLK @@ -413,8 +415,6 @@ config VPL_BOOTSTD boot. It is enabled by default since the main purpose of VPL is to handle the firmware part of VBE. -if BOOTSTD - config BOOTSTD_FULL bool "Enhanced features for standard boot" default y if SANDBOX @@ -673,7 +673,7 @@ config BOOTMETH_SCRIPT This provides a way to try out standard boot on an existing boot flow. It is not enabled by default to save space. -endif +endif # BOOTSTD config LEGACY_IMAGE_FORMAT bool "Enable support for the legacy image format" -- cgit v1.3.1 From 064a57d019781906e32ccaa16ce122e254dc6533 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Thu, 14 Sep 2023 10:55:54 -0600 Subject: Kconfig: Move TEXT_BASE et al under general setup These don't relate to booting. Move them out of there and into the same place as the other related settings. Signed-off-by: Simon Glass Reviewed-by: Tom Rini --- Kconfig | 65 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ boot/Kconfig | 65 ------------------------------------------------------------ 2 files changed, 65 insertions(+), 65 deletions(-) diff --git a/Kconfig b/Kconfig index 0a2e97578df..2d4b8214986 100644 --- a/Kconfig +++ b/Kconfig @@ -585,6 +585,71 @@ config MP This provides an option to bringup different processors in multiprocessor cases. +config HAVE_TEXT_BASE + bool + depends on !NIOS2 && !XTENSA + depends on !EFI_APP + default y + +config TEXT_BASE + depends on HAVE_TEXT_BASE + default 0x0 if POSITION_INDEPENDENT + default 0x80800000 if ARCH_OMAP2PLUS || ARCH_K3 + default 0x81700000 if MACH_SUNIV + default 0x2a000000 if MACH_SUN9I + default 0x4a000000 if SUNXI_MINIMUM_DRAM_MB >= 256 + default 0x42e00000 if SUNXI_MINIMUM_DRAM_MB >= 64 + hex "Text Base" + help + The address in memory that U-Boot will be running from, initially. + +config HAVE_SYS_MONITOR_BASE + bool + depends on ARC || MIPS || M68K || NIOS2 || PPC || XTENSA || X86 \ + || ENV_IS_IN_FLASH || MTD_NOR_FLASH + depends on !EFI_APP + default y + +config SYS_MONITOR_BASE + depends on HAVE_SYS_MONITOR_BASE + hex "Physical start address of boot monitor code" + default TEXT_BASE + help + The physical start address of boot monitor code (which is the same as + CONFIG_TEXT_BASE when linking) and the same as CFG_SYS_FLASH_BASE + when booting from flash. + +config SPL_SYS_MONITOR_BASE + depends on MPC85xx && SPL && HAVE_SYS_MONITOR_BASE + hex "Physical start address of SPL monitor code" + default SPL_TEXT_BASE + +config TPL_SYS_MONITOR_BASE + depends on MPC85xx && TPL && HAVE_SYS_MONITOR_BASE + hex "Physical start address of TPL monitor code" + +config DYNAMIC_SYS_CLK_FREQ + bool "Determine CPU clock frequency at run-time" + help + Implement a get_board_sys_clk function that will determine the CPU + clock frequency at run time, rather than define it statically. + +config SYS_CLK_FREQ + depends on !DYNAMIC_SYS_CLK_FREQ + int "CPU clock frequency" + default 125000000 if ARCH_LS1012A + default 100000000 if ARCH_P2020 || ARCH_T1024 || ARCH_T1042 || \ + ARCH_LS1021A || FSL_LSCH2 || FSL_LSCH3 + default 66666666 if ARCH_P1010 || ARCH_P1020 || ARCH_T4240 + default 66660000 if ARCH_T2080 + default 33333333 if RCAR_GEN3 + default 24000000 if ARCH_EXYNOS + default 20000000 if RCAR_GEN2 + default 0 + help + A static value for the CPU frequency. Note that if not required + for a given SoC, this can be left at 0. + source "api/Kconfig" endmenu # General setup diff --git a/boot/Kconfig b/boot/Kconfig index a885fea692f..4ebcf310911 100644 --- a/boot/Kconfig +++ b/boot/Kconfig @@ -693,71 +693,6 @@ config SUPPORT_RAW_INITRD address of the initrd must be augmented by it's size, in the following format: ":". -config HAVE_TEXT_BASE - bool - depends on !NIOS2 && !XTENSA - depends on !EFI_APP - default y - -config TEXT_BASE - depends on HAVE_TEXT_BASE - default 0x0 if POSITION_INDEPENDENT - default 0x80800000 if ARCH_OMAP2PLUS || ARCH_K3 - default 0x81700000 if MACH_SUNIV - default 0x2a000000 if MACH_SUN9I - default 0x4a000000 if SUNXI_MINIMUM_DRAM_MB >= 256 - default 0x42e00000 if SUNXI_MINIMUM_DRAM_MB >= 64 - hex "Text Base" - help - The address in memory that U-Boot will be running from, initially. - -config HAVE_SYS_MONITOR_BASE - bool - depends on ARC || MIPS || M68K || NIOS2 || PPC || XTENSA || X86 \ - || ENV_IS_IN_FLASH || MTD_NOR_FLASH - depends on !EFI_APP - default y - -config SYS_MONITOR_BASE - depends on HAVE_SYS_MONITOR_BASE - hex "Physical start address of boot monitor code" - default TEXT_BASE - help - The physical start address of boot monitor code (which is the same as - CONFIG_TEXT_BASE when linking) and the same as CFG_SYS_FLASH_BASE - when booting from flash. - -config SPL_SYS_MONITOR_BASE - depends on MPC85xx && SPL && HAVE_SYS_MONITOR_BASE - hex "Physical start address of SPL monitor code" - default SPL_TEXT_BASE - -config TPL_SYS_MONITOR_BASE - depends on MPC85xx && TPL && HAVE_SYS_MONITOR_BASE - hex "Physical start address of TPL monitor code" - -config DYNAMIC_SYS_CLK_FREQ - bool "Determine CPU clock frequency at run-time" - help - Implement a get_board_sys_clk function that will determine the CPU - clock frequency at run time, rather than define it statically. - -config SYS_CLK_FREQ - depends on !DYNAMIC_SYS_CLK_FREQ - int "CPU clock frequency" - default 125000000 if ARCH_LS1012A - default 100000000 if ARCH_P2020 || ARCH_T1024 || ARCH_T1042 || \ - ARCH_LS1021A || FSL_LSCH2 || FSL_LSCH3 - default 66666666 if ARCH_P1010 || ARCH_P1020 || ARCH_T4240 - default 66660000 if ARCH_T2080 - default 33333333 if RCAR_GEN3 - default 24000000 if ARCH_EXYNOS - default 20000000 if RCAR_GEN2 - default 0 - help - A static value for the CPU frequency. Note that if not required - for a given SoC, this can be left at 0. - config ARCH_FIXUP_FDT_MEMORY bool "Enable arch_fixup_memory_banks() call" default y -- cgit v1.3.1 From 3b58de4d0b6bde8f8dab0fa0c0dc417e57b6c804 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Thu, 14 Sep 2023 10:55:55 -0600 Subject: Mark DISTRO_DEFAULTS as deprecated Standard boot has been in place for a while now. Quite a few problems have been found and fixed. It seems like a good time to mark the script-based approach as deprecated and encourage people to use standard boot. Update the DISTRO_DEFAULTS Kconfig to encourage people to move to standard boot, which is able to boot Linux distributions automatically. Add a short migration guide to make this easier. Signed-off-by: Simon Glass Reviewed-by: Tom Rini --- boot/Kconfig | 6 +++++- doc/develop/bootstd.rst | 23 +++++++++++++++++++++++ 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/boot/Kconfig b/boot/Kconfig index 4ebcf310911..7ef44a26fb9 100644 --- a/boot/Kconfig +++ b/boot/Kconfig @@ -784,7 +784,7 @@ config SYS_BOOT_RAMDISK_HIGH endmenu # Boot images config DISTRO_DEFAULTS - bool "Select defaults suitable for booting general purpose Linux distributions" + bool "(deprecated) Script-based booting of Linux distributions" select BOOT_DEFAULTS select AUTO_COMPLETE select CMDLINE_EDITING @@ -792,6 +792,10 @@ config DISTRO_DEFAULTS select HUSH_PARSER select SYS_LONGHELP help + Note: These scripts have been replaced by Standard Boot. Do not use + them on new boards. See 'Migrating from distro_boot' at + doc/develop/bootstd.rst + Select this to enable various options and commands which are suitable for building u-boot for booting general purpose Linux distributions. diff --git a/doc/develop/bootstd.rst b/doc/develop/bootstd.rst index e8b90752f08..6172dc906bd 100644 --- a/doc/develop/bootstd.rst +++ b/doc/develop/bootstd.rst @@ -464,6 +464,28 @@ ready File was loaded and is ready for use. In this state the bootflow is ======= ======================================================================= +Migrating from distro_boot +-------------------------- + +To migrate from distro_boot: + +#. Update your board header files to remove the BOOTENV and BOOT_TARGET_xxx + defines. Standard boot finds available boot devices automatically. + +#. Remove the "boot_targets" variable unless you need it. Standard boot uses a + default order from fastest to slowest, which generally matches the order used + by boards. + +#. Make sure that CONFIG_BOOTSTD_DEFAULTS is enabled by your board, so it can + boot common Linux distributions. + +An example patch is at migrate_patch_. + +If you are using custom boot scripts for your board, consider creating your +own bootmeth to hold the logic. There are various examples at +`boot/bootmeth_...`. + + Theory of operation ------------------- @@ -775,3 +797,4 @@ Other ideas: .. _BootLoaderSpec: http://www.freedesktop.org/wiki/Specifications/BootLoaderSpec/ .. _distro_boot: https://github.com/u-boot/u-boot/blob/master/boot/distro.c .. _bootflow_h: https://github.com/u-boot/u-boot/blob/master/include/bootflow.h +.. _migrate_patch: https://patchwork.ozlabs.org/project/uboot/patch/20230727215433.578830-2-sjg@chromium.org/ -- cgit v1.3.1 From 4483184127f8ac36869d014ebe116d4822b30ca7 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Thu, 14 Sep 2023 10:55:56 -0600 Subject: Make ARCH_FIXUP_FDT_MEMORY depend on OF_LIBFDT We need CONFIG_OF_LIBFDT to be able to do fdt fixups, so add that condition. Signed-off-by: Simon Glass Reviewed-by: Tom Rini --- boot/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/boot/Kconfig b/boot/Kconfig index 7ef44a26fb9..2dd05e2e166 100644 --- a/boot/Kconfig +++ b/boot/Kconfig @@ -695,7 +695,7 @@ config SUPPORT_RAW_INITRD config ARCH_FIXUP_FDT_MEMORY bool "Enable arch_fixup_memory_banks() call" - default y + default y if OF_LIBFDT help Enable FDT memory map syncup before OS boot. This feature can be used for booting OS with different memory setup where the part of -- cgit v1.3.1 From 040a604880c6eb86779ef564c055deb7b1bcb828 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Thu, 14 Sep 2023 10:55:57 -0600 Subject: boot: Join FDT_FIXUP_PARTITIONS with related options Move this to be with the other devicetree-fixup options. Signed-off-by: Simon Glass Reviewed-by: Tom Rini --- boot/Kconfig | 8 ++++++++ lib/Kconfig | 9 --------- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/boot/Kconfig b/boot/Kconfig index 2dd05e2e166..a1592a74e62 100644 --- a/boot/Kconfig +++ b/boot/Kconfig @@ -1475,6 +1475,14 @@ config OF_STDOUT_VIA_ALIAS incorrect when used with device tree as this option does not exist / should not be used. +config FDT_FIXUP_PARTITIONS + bool "overwrite MTD partitions in DTS through defined in 'mtdparts'" + depends on CMD_MTDPARTS + help + Allow overwriting defined partitions in the device tree blob + using partition info defined in the 'mtdparts' environment + variable. + config FDT_SIMPLEFB bool "FDT tools for simplefb support" help diff --git a/lib/Kconfig b/lib/Kconfig index bfab2f3165a..eb2b1016182 100644 --- a/lib/Kconfig +++ b/lib/Kconfig @@ -953,15 +953,6 @@ config VPL_OF_LIBFDT_ASSUME_MASK 0xff means all assumptions are made and any invalid data may cause unsafe execution. See FDT_ASSUME_PERFECT, etc. in libfdt_internal.h -config FDT_FIXUP_PARTITIONS - bool "overwrite MTD partitions in DTS through defined in 'mtdparts'" - depends on OF_LIBFDT - depends on CMD_MTDPARTS - help - Allow overwriting defined partitions in the device tree blob - using partition info defined in the 'mtdparts' environment - variable. - menu "System tables" depends on (!EFI && !SYS_COREBOOT) || (ARM && EFI_LOADER) -- cgit v1.3.1 From 400a6a3a1be8c7a058253e326ec20cd935d124fb Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Thu, 14 Sep 2023 10:55:58 -0600 Subject: boot: Drop CMD_MTDPARTS condition for FDT_FIXUP_PARTITIONS This is not needed, so drop it. Also use a capital 'O' for the option, while we are here. Signed-off-by: Simon Glass Suggested-by: Tom Rini Reviewed-by: Tom Rini --- boot/Kconfig | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/boot/Kconfig b/boot/Kconfig index a1592a74e62..235c5a7a993 100644 --- a/boot/Kconfig +++ b/boot/Kconfig @@ -1476,8 +1476,7 @@ config OF_STDOUT_VIA_ALIAS exist / should not be used. config FDT_FIXUP_PARTITIONS - bool "overwrite MTD partitions in DTS through defined in 'mtdparts'" - depends on CMD_MTDPARTS + bool "Overwrite MTD partitions in DTS through defined in 'mtdparts'" help Allow overwriting defined partitions in the device tree blob using partition info defined in the 'mtdparts' environment -- cgit v1.3.1 From c0e5b0ebab6ae8f04cf42bd4ac10c19af58af3a2 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Thu, 14 Sep 2023 10:55:59 -0600 Subject: boot: Join ARCH_FIXUP_FDT_MEMORY with related options Move this to be with the other devicetree-fixup options. Signed-off-by: Simon Glass Reviewed-by: Tom Rini --- boot/Kconfig | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/boot/Kconfig b/boot/Kconfig index 235c5a7a993..a01e6cb8aaf 100644 --- a/boot/Kconfig +++ b/boot/Kconfig @@ -693,14 +693,6 @@ config SUPPORT_RAW_INITRD address of the initrd must be augmented by it's size, in the following format: ":". -config ARCH_FIXUP_FDT_MEMORY - bool "Enable arch_fixup_memory_banks() call" - default y if OF_LIBFDT - help - Enable FDT memory map syncup before OS boot. This feature can be - used for booting OS with different memory setup where the part of - the memory location should be used for different purpose. - config CHROMEOS bool "Support booting Chrome OS" help @@ -1490,6 +1482,14 @@ config FDT_SIMPLEFB the presence of the simple frame buffer with associated reserved memory +config ARCH_FIXUP_FDT_MEMORY + bool "Enable arch_fixup_memory_banks() call" + default y + help + Enable FDT memory map syncup before OS boot. This feature can be + used for booting OS with different memory setup where the part of + the memory location should be used for different purpose. + endmenu endif # OF_LIBFDT -- cgit v1.3.1