doc: fix mistyped "env flags" command
[pandora-u-boot.git] / boot / image-fdt.c
index 7aad6d5..75bdd55 100644 (file)
@@ -9,6 +9,7 @@
  */
 
 #include <common.h>
+#include <command.h>
 #include <fdt_support.h>
 #include <fdtdec.h>
 #include <env.h>
 #include <linux/libfdt.h>
 #include <mapmem.h>
 #include <asm/io.h>
+#include <dm/ofnode.h>
 #include <tee/optee.h>
 
-#ifndef CONFIG_SYS_FDT_PAD
-#define CONFIG_SYS_FDT_PAD 0x3000
-#endif
-
-/* adding a ramdisk needs 0x44 bytes in version 2008.10 */
-#define FDT_RAMDISK_OVERHEAD   0x80
-
 DECLARE_GLOBAL_DATA_PTR;
 
 static void fdt_error(const char *msg)
@@ -40,9 +35,9 @@ static void fdt_error(const char *msg)
 }
 
 #if CONFIG_IS_ENABLED(LEGACY_IMAGE_FORMAT)
-static const image_header_t *image_get_fdt(ulong fdt_addr)
+static const struct legacy_img_hdr *image_get_fdt(ulong fdt_addr)
 {
-       const image_header_t *fdt_hdr = map_sysmem(fdt_addr, 0);
+       const struct legacy_img_hdr *fdt_hdr = map_sysmem(fdt_addr, 0);
 
        image_print_contents(fdt_hdr);
 
@@ -165,8 +160,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;
 
@@ -186,30 +184,59 @@ int boot_relocate_fdt(struct lmb *lmb, char **of_flat_tree, ulong *of_size)
        /* If fdt_high is set use it to select the relocation address */
        fdt_high = env_get("fdt_high");
        if (fdt_high) {
-               void *desired_addr = (void *)hextoul(fdt_high, NULL);
+               ulong desired_addr = hextoul(fdt_high, NULL);
+               ulong addr;
 
-               if (((ulong) desired_addr) == ~0UL) {
+               if (desired_addr == ~0UL) {
                        /* All ones means use fdt in place */
                        of_start = fdt_blob;
-                       lmb_reserve(lmb, (ulong)of_start, of_len);
+                       lmb_reserve(lmb, map_to_sysmem(of_start), of_len);
                        disable_relocation = 1;
                } else if (desired_addr) {
-                       of_start =
-                           (void *)(ulong) lmb_alloc_base(lmb, of_len, 0x1000,
-                                                          (ulong)desired_addr);
+                       addr = lmb_alloc_base(lmb, of_len, 0x1000,
+                                             desired_addr);
+                       of_start = map_sysmem(addr, of_len);
                        if (of_start == NULL) {
                                puts("Failed using fdt_high value for Device Tree");
                                goto error;
                        }
                } else {
-                       of_start =
-                           (void *)(ulong) lmb_alloc(lmb, of_len, 0x1000);
+                       addr = lmb_alloc(lmb, of_len, 0x1000);
+                       of_start = map_sysmem(addr, of_len);
                }
        } 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 = map_sysmem((ulong)lmb_alloc_base(lmb,
+                                   of_len, 0x1000, start + usable), of_len);
+                       /* 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) {
@@ -243,7 +270,7 @@ int boot_relocate_fdt(struct lmb *lmb, char **of_flat_tree, ulong *of_size)
        *of_flat_tree = of_start;
        *of_size = of_len;
 
-       if (CONFIG_IS_ENABLED(CMD_FDT))
+       if (IS_ENABLED(CONFIG_CMD_FDT))
                set_working_fdt_addr(map_to_sysmem(*of_flat_tree));
        return 0;
 
@@ -258,11 +285,11 @@ error:
  * @select: name of FDT to select, or NULL for any
  * @arch: expected FDT architecture
  * @fdt_addrp: pointer to a ulong variable, will hold FDT pointer
- * @return 0 if OK, -ENOPKG if no FDT (but an error should not be reported),
+ * Return: 0 if OK, -ENOPKG if no FDT (but an error should not be reported),
  *     other -ve value on other error
  */
 
-static int select_fdt(bootm_headers_t *images, const char *select, u8 arch,
+static int select_fdt(struct bootm_headers *images, const char *select, u8 arch,
                      ulong *fdt_addrp)
 {
        const char *buf;
@@ -329,7 +356,7 @@ static int select_fdt(bootm_headers_t *images, const char *select, u8 arch,
        switch (genimg_get_format(buf)) {
 #if CONFIG_IS_ENABLED(LEGACY_IMAGE_FORMAT)
        case IMAGE_FORMAT_LEGACY: {
-                       const image_header_t *fdt_hdr;
+                       const struct legacy_img_hdr *fdt_hdr;
                        ulong load, load_end;
                        ulong image_start, image_data, image_end;
 
@@ -418,45 +445,16 @@ static int select_fdt(bootm_headers_t *images, const char *select, u8 arch,
        return 0;
 }
 
-/**
- * boot_get_fdt - main fdt handling routine
- * @argc: command argument count
- * @argv: command argument list
- * @arch: architecture (IH_ARCH_...)
- * @images: pointer to the bootm images structure
- * @of_flat_tree: pointer to a char* variable, will hold fdt start address
- * @of_size: pointer to a ulong variable, will hold fdt length
- *
- * boot_get_fdt() is responsible for finding a valid flat device tree image.
- * Currently supported are the following ramdisk sources:
- *      - multicomponent kernel/ramdisk image,
- *      - commandline provided address of decicated ramdisk image.
- *
- * returns:
- *     0, if fdt image was found and valid, or skipped
- *     of_flat_tree and of_size are set to fdt start address and length if
- *     fdt image is found and valid
- *
- *     1, if fdt image is found but corrupted
- *     of_flat_tree and of_size are set to 0 if no fdt exists
- */
-int boot_get_fdt(int flag, int argc, char *const argv[], uint8_t arch,
-                bootm_headers_t *images, char **of_flat_tree, ulong *of_size)
+int boot_get_fdt(void *buf, const char *select, uint arch,
+                struct bootm_headers *images, char **of_flat_tree,
+                ulong *of_size)
 {
-       ulong           img_addr;
-       ulong           fdt_addr;
-       char            *fdt_blob = NULL;
-       void            *buf;
-       const char *select = NULL;
+       char *fdt_blob = NULL;
+       ulong fdt_addr;
 
        *of_flat_tree = NULL;
        *of_size = 0;
 
-       img_addr = (argc == 0) ? image_load_addr : hextoul(argv[0], NULL);
-       buf = map_sysmem(img_addr, 0);
-
-       if (argc > 2)
-               select = argv[2];
        if (select || genimg_has_config(images)) {
                int ret;
 
@@ -500,14 +498,15 @@ int boot_get_fdt(int flag, int argc, char *const argv[], uint8_t arch,
                }
 #ifdef CONFIG_ANDROID_BOOT_IMAGE
        } else if (genimg_get_format(buf) == IMAGE_FORMAT_ANDROID) {
-               struct andr_img_hdr *hdr = buf;
+               void *hdr = buf;
                ulong           fdt_data, fdt_len;
                u32                     fdt_size, dtb_idx;
                /*
                 * Firstly check if this android boot image has dtb field.
                 */
                dtb_idx = (u32)env_get_ulong("adtb_idx", 10, 0);
-               if (android_image_get_dtb_by_index((ulong)hdr, dtb_idx, &fdt_addr, &fdt_size)) {
+               if (android_image_get_dtb_by_index((ulong)hdr, 0,
+                                                  dtb_idx, &fdt_addr, &fdt_size)) {
                        fdt_blob = (char *)map_sysmem(fdt_addr, 0);
                        if (fdt_check_header(fdt_blob))
                                goto no_fdt;
@@ -573,13 +572,27 @@ __weak int arch_fixup_fdt(void *blob)
        return 0;
 }
 
-int image_setup_libfdt(bootm_headers_t *images, void *blob,
-                      int of_size, struct lmb *lmb)
+int image_setup_libfdt(struct bootm_headers *images, void *blob,
+                      struct lmb *lmb)
 {
        ulong *initrd_start = &images->initrd_start;
        ulong *initrd_end = &images->initrd_end;
-       int ret = -EPERM;
-       int fdt_ret;
+       int ret, fdt_ret, of_size;
+
+       if (IS_ENABLED(CONFIG_OF_ENV_SETUP)) {
+               const char *fdt_fixup;
+
+               fdt_fixup = env_get("fdt_fixup");
+               if (fdt_fixup) {
+                       set_working_fdt_addr(map_to_sysmem(blob));
+                       ret = run_command_list(fdt_fixup, -1, 0);
+                       if (ret)
+                               printf("WARNING: fdt_fixup command returned %d\n",
+                                      ret);
+               }
+       }
+
+       ret = -EPERM;
 
        if (fdt_root(blob) < 0) {
                printf("ERROR: root node setup failed\n");
@@ -601,9 +614,15 @@ int image_setup_libfdt(bootm_headers_t *images, void *blob,
                goto err;
        }
 
+       /* Store name of configuration node as u-boot,bootconf in /chosen node */
+       if (images->fit_uname_cfg)
+               fdt_find_and_setprop(blob, "/chosen", "u-boot,bootconf",
+                                       images->fit_uname_cfg,
+                                       strlen(images->fit_uname_cfg) + 1, 1);
+
        /* Update ethernet nodes */
        fdt_fixup_ethernet(blob);
-#if CONFIG_IS_ENABLED(CMD_PSTORE)
+#if IS_ENABLED(CONFIG_CMD_PSTORE)
        /* Append PStore configuration */
        fdt_fixup_pstore(blob);
 #endif
@@ -631,27 +650,40 @@ int image_setup_libfdt(bootm_headers_t *images, void *blob,
                }
        }
 
+       if (fdt_initrd(blob, *initrd_start, *initrd_end))
+               goto err;
+
+       if (!ft_verify_fdt(blob))
+               goto err;
+
+       /* after here we are using a livetree */
+       if (!of_live_active() && CONFIG_IS_ENABLED(EVENT)) {
+               struct event_ft_fixup fixup;
+
+               fixup.tree = oftree_from_fdt(blob);
+               fixup.images = images;
+               if (oftree_valid(fixup.tree)) {
+                       ret = event_notify(EVT_FT_FIXUP, &fixup, sizeof(fixup));
+                       if (ret) {
+                               printf("ERROR: fdt fixup event failed: %d\n",
+                                      ret);
+                               goto err;
+                       }
+               }
+       }
+
        /* Delete the old LMB reservation */
        if (lmb)
-               lmb_free(lmb, (phys_addr_t)(u32)(uintptr_t)blob,
-                        (phys_size_t)fdt_totalsize(blob));
+               lmb_free(lmb, map_to_sysmem(blob), fdt_totalsize(blob));
 
        ret = fdt_shrink_to_minimum(blob, 0);
        if (ret < 0)
                goto err;
        of_size = ret;
 
-       if (*initrd_start && *initrd_end) {
-               of_size += FDT_RAMDISK_OVERHEAD;
-               fdt_set_totalsize(blob, of_size);
-       }
        /* Create a new LMB reservation */
        if (lmb)
-               lmb_reserve(lmb, (ulong)blob, of_size);
-
-       fdt_initrd(blob, *initrd_start, *initrd_end);
-       if (!ft_verify_fdt(blob))
-               goto err;
+               lmb_reserve(lmb, map_to_sysmem(blob), of_size);
 
 #if defined(CONFIG_ARCH_KEYSTONE)
        if (IS_ENABLED(CONFIG_OF_BOARD_SETUP))