summaryrefslogtreecommitdiff
path: root/boot
diff options
context:
space:
mode:
authorMarek Vasut <marex@denx.de>2022-04-08 03:09:19 +0300
committerTom Rini <trini@konsulko.com>2022-04-20 18:14:39 +0300
commita96d56572536f02c0d1f09f72bfedfa9cb4ae560 (patch)
treea98e3d91a0f435ca0e331c43bf2625943a9bcd9d /boot
parent4448d0c702c07277190be1d5f1d3f256a960d303 (diff)
downloadu-boot-a96d56572536f02c0d1f09f72bfedfa9cb4ae560.tar.xz
image: fdt: Fix DT relocation handling with multiple DRAM banks with gap
The current implementation of boot_relocate_fdt() places DT at the highest usable DRAM address, which is calculated as: env_get_bootm_low() + env_get_bootm_mapsize() which by default becomes gd->ram_base + gd->ram_size. Systems like i.MX53 can have multiple DRAM banks with gap between them, e.g. have DRAM at 0x70000000-0x8fffffff and 0xb0000000-0xcfffffff , so for them the calculated highest DRAM address is 0xafffffff, which is exactly in the gap and thus not usable. Fix this by iterating over all DRAM banks and tracking the remaining amount of the total mapping size obtained from env_get_bootm_mapsize(). Limit the maximum LMB area size to each bank, to avoid using nonexistent DRAM. Reviewed-by: Simon Glass <sjg@chromium.org> Signed-off-by: Marek Vasut <marex@denx.de> Cc: Heinrich Schuchardt <xypron.glpk@gmx.de> Cc: Simon Glass <sjg@chromium.org> Cc: Tom Rini <trini@konsulko.com>
Diffstat (limited to 'boot')
-rw-r--r--boot/image-fdt.c40
1 files changed, 36 insertions, 4 deletions
diff --git a/boot/image-fdt.c b/boot/image-fdt.c
index fdb69926a2..9db2cee994 100644
--- a/boot/image-fdt.c
+++ b/boot/image-fdt.c
@@ -165,8 +165,11 @@ int boot_relocate_fdt(struct lmb *lmb, char **of_flat_tree, ulong *of_size)
{
void *fdt_blob = *of_flat_tree;
void *of_start = NULL;
+ u64 start, size, usable;
char *fdt_high;
+ ulong mapsize, low;
ulong of_len = 0;
+ int bank;
int err;
int disable_relocation = 0;
@@ -206,10 +209,39 @@ int boot_relocate_fdt(struct lmb *lmb, char **of_flat_tree, ulong *of_size)
(void *)(ulong) lmb_alloc(lmb, of_len, 0x1000);
}
} else {
- of_start =
- (void *)(ulong) lmb_alloc_base(lmb, of_len, 0x1000,
- env_get_bootm_mapsize()
- + env_get_bootm_low());
+ mapsize = env_get_bootm_mapsize();
+ low = env_get_bootm_low();
+ of_start = NULL;
+
+ for (bank = 0; bank < CONFIG_NR_DRAM_BANKS; bank++) {
+ start = gd->bd->bi_dram[bank].start;
+ size = gd->bd->bi_dram[bank].size;
+
+ /* DRAM bank addresses are too low, skip it. */
+ if (start + size < low)
+ continue;
+
+ usable = min(size, (u64)mapsize);
+
+ /*
+ * At least part of this DRAM bank is usable, try
+ * using it for LMB allocation.
+ */
+ of_start =
+ (void *)(ulong) lmb_alloc_base(lmb, of_len, 0x1000,
+ start + usable);
+ /* Allocation succeeded, use this block. */
+ if (of_start != NULL)
+ break;
+
+ /*
+ * Reduce the mapping size in the next bank
+ * by the size of attempt in current bank.
+ */
+ mapsize -= usable - max(start, (u64)low);
+ if (!mapsize)
+ break;
+ }
}
if (of_start == NULL) {