diff options
author | Stephen Warren <swarren@nvidia.com> | 2015-08-11 15:10:39 -0600 |
---|---|---|
committer | Edward Cragg <edward.cragg@codethink.co.uk> | 2016-03-14 10:52:03 +0000 |
commit | 591a5cf57c261bd3e0e2ac6054c6e8659d803217 (patch) | |
tree | 482dc16ab20e356bf20a09b9ab88628a99d0b1da | |
parent | ae765f3a8243faa39d4a32ba2baede638e40c768 (diff) | |
download | u-boot-591a5cf57c261bd3e0e2ac6054c6e8659d803217.tar.gz |
ARM: tegra: copy tboot DT to U-Boot DT
One of the primary reasons for using U-Boot is its ability to load kernel
and DTB from arbitrary locations under the control over environment
variables, scripts, or extlinux.conf menus.
However, the L4T kernel expects the DTB it receives to contain certain
runtime-generated data, such as LPDDR4 training results. These are
obviously not contained in any DTB loaded from disk or network.
Rather, tboot (which runs before U-Boot) loads a DTB from a specific
partition in the boot flash, modifies it, and passes it on to subsequent
software.
In order to pass that information to the kernel, U-Boot has two choices:
a) Pass the tboot-supplied DTB to the kernel. This had the disadvantage
that it removes all of U-Boot's flexibility in location/loading the DTB.
b) Copy the relevant information from the tboot-supplied copy of the DTB
into the U-Boot-loaded DTB before booting the kernel.
This patch implements option (b) above.
tboot stores the DTB at address 0x83080000. Hence, $ramdisk_addr_r is
modified to avoid loading any initrd over the top of the tboot-supplied
DTB.
Bug 200051179
Change-Id: I04fe1a6a64d17249a1548b13568d0122dad31609
Signed-off-by: Stephen Warren <swarren@nvidia.com>
Reviewed-on: http://git-master/r/782016
Reviewed-by: Tom Warren <twarren@nvidia.com>
-rw-r--r-- | arch/arm/mach-tegra/board2.c | 165 | ||||
-rw-r--r-- | include/configs/tegra210-common.h | 6 |
2 files changed, 170 insertions, 1 deletions
diff --git a/arch/arm/mach-tegra/board2.c b/arch/arm/mach-tegra/board2.c index ac274e17e8..3c941a6fef 100644 --- a/arch/arm/mach-tegra/board2.c +++ b/arch/arm/mach-tegra/board2.c @@ -5,6 +5,7 @@ * SPDX-License-Identifier: GPL-2.0+ */ +#include <stdlib.h> #include <common.h> #include <dm.h> #include <errno.h> @@ -383,6 +384,170 @@ void dram_init_banksize(void) } } +#ifdef CONFIG_OF_COPY_NODES +#define fdt_for_each_property(fdt, prop, parent) \ + for (prop = fdt_first_property_offset(fdt, parent); \ + prop >= 0; \ + prop = fdt_next_property_offset(fdt, prop)) + +int fdt_copy_node_content(void *blob_src, int ofs_src, void *blob_dst, + int ofs_dst, int indent) +{ + int ofs_src_child, ofs_dst_child; + + /* + * FIXME: This doesn't remove properties or nodes in the destination + * that are not present in the source. For the nodes we care about + * right now, this is not an issue. + */ + + fdt_for_each_property(blob_src, ofs_src_child, ofs_src) { + const char *prop; + const char *name; + int len, ret; + + prop = fdt_getprop_by_offset(blob_src, ofs_src_child, &name, + &len); + debug("%*scopy prop: %s\n", indent, "", name); + + ret = fdt_setprop(blob_dst, ofs_dst, name, prop, len); + if (ret < 0) { + printf("Can't create DT prop %s to copy\n", name); + return ret; + } + } + + fdt_for_each_subnode(blob_src, ofs_src_child, ofs_src) { + const char *name; + + name = fdt_get_name(blob_src, ofs_src_child, NULL); + debug("%*scopy node: %s\n", indent, "", name); + + ofs_dst_child = fdt_subnode_offset(blob_dst, ofs_dst, name); + if (ofs_dst_child < 0) { + debug("%*s(creating it in dst)\n", indent, ""); + ofs_dst_child = fdt_add_subnode(blob_dst, ofs_dst, + name); + if (ofs_dst_child < 0) { + printf("Can't create DT node %s to copy\n", name); + return ofs_dst_child; + } + } + + fdt_copy_node_content(blob_src, ofs_src_child, blob_dst, + ofs_dst_child, indent + 2); + } + + return 0; +} + +int ft_copy_node(void *blob_src, void *blob_dst, const char *nodename) +{ + int ofs_dst_mc, ofs_src_mc; + int ret; + + ofs_dst_mc = fdt_path_offset(blob_dst, nodename); + if (ofs_dst_mc < 0) { + ofs_dst_mc = fdt_add_subnode(blob_dst, 0, nodename); + if (ofs_dst_mc < 0) { + printf("Can't create DT node %s to copy\n", nodename); + return ofs_dst_mc; + } + } else { + if (!fdtdec_get_is_enabled(blob_dst, ofs_dst_mc)) { + printf("DT node %s disabled in dst; skipping copy\n", + nodename); + return 0; + } + } + + ofs_src_mc = fdt_path_offset(blob_src, nodename); + if (ofs_src_mc < 0) { + printf("DT node %s missing in source; can't copy\n", + nodename); + return 0; + } + + ret = fdt_copy_node_content(blob_src, ofs_src_mc, blob_dst, + ofs_dst_mc, 2); + if (ret < 0) + return ret; + + return 0; +} + +int ft_copy_nodes(void *blob_dst) +{ + char *src_addr_s; + ulong src_addr; + char *node_names, *tmp, *node_name; + int ret; + + src_addr_s = getenv("fdt_copy_src_addr"); + if (!src_addr_s) + return 0; + src_addr = simple_strtoul(src_addr_s, NULL, 16); + + node_names = getenv("fdt_copy_node_names"); + if (!node_names) + return 0; + node_names = strdup(node_names); + if (!node_names) { + printf("%s:strdup failed", __func__); + ret = -1; + goto out; + } + + tmp = node_names; + while (true) { + node_name = strsep(&tmp, ":"); + if (!node_name) + break; + debug("node to copy: %s\n", node_name); + ret = ft_copy_node((void *)src_addr, blob_dst, node_name); + if (ret < 0) { + ret = -1; + goto out; + } + } + + ret = 0; + +out: + free(node_names); + + return ret; +} +#endif + +#ifdef CONFIG_OF_BOARD_SETUP +int ft_board_setup(void *blob, bd_t *bd) +{ + int ret; + +#ifdef CONFIG_OF_REMOVE_FIRMWARE_NODES + ret = ft_remove_firmware_nodes(blob); + if (ret) + return ret; +#endif + + /* Overwrite DT file with right board info properties */ +#ifdef CONFIG_SERIAL_TAG + ret = fdt_serial_tag_setup(blob, bd); + if (ret) + return ret; +#endif /* SERIAL_TAG */ + +#ifdef CONFIG_OF_COPY_NODES + ret = ft_copy_nodes(blob); + if (ret) + return ret; +#endif + + return 0; +} +#endif + /* * Most hardware on 64-bit Tegra is still restricted to DMA to the lower * 32-bits of the physical address space. Cap the maximum usable RAM area diff --git a/include/configs/tegra210-common.h b/include/configs/tegra210-common.h index 8f35a7bf3d..2a2753e944 100644 --- a/include/configs/tegra210-common.h +++ b/include/configs/tegra210-common.h @@ -61,7 +61,9 @@ "pxefile_addr_r=0x90100000\0" \ "kernel_addr_r=" __stringify(CONFIG_LOADADDR) "\0" \ "fdt_addr_r=0x82000000\0" \ - "ramdisk_addr_r=0x82100000\0" + "ramdisk_addr_r=0x83100000\0" \ + "fdt_copy_src_addr=0x83080000\0" \ + "fdt_copy_node_names=/memory-controller@7001b000\0" /* Defines for SPL */ #define CONFIG_SPL_TEXT_BASE 0x80108000 @@ -75,5 +77,7 @@ /* GPU needs setup */ #define CONFIG_TEGRA_GPU +#define CONFIG_OF_BOARD_SETUP +#define CONFIG_OF_COPY_NODES #endif /* _TEGRA210_COMMON_H_ */ |