summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStephen Warren <swarren@nvidia.com>2015-08-11 15:10:39 -0600
committerEdward Cragg <edward.cragg@codethink.co.uk>2016-03-14 10:52:03 +0000
commit591a5cf57c261bd3e0e2ac6054c6e8659d803217 (patch)
tree482dc16ab20e356bf20a09b9ab88628a99d0b1da
parentae765f3a8243faa39d4a32ba2baede638e40c768 (diff)
downloadu-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.c165
-rw-r--r--include/configs/tegra210-common.h6
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_ */