arm: a37xx: pci: Fix a3700_fdt_fix_pcie_regions() function
[pandora-u-boot.git] / cmd / pxe_utils.c
index ba4bb63..71c5af4 100644 (file)
@@ -8,10 +8,13 @@
 #include <command.h>
 #include <env.h>
 #include <image.h>
+#include <log.h>
 #include <malloc.h>
 #include <mapmem.h>
 #include <lcd.h>
 #include <net.h>
+#include <fdt_support.h>
+#include <linux/libfdt.h>
 #include <linux/string.h>
 #include <linux/ctype.h>
 #include <errno.h>
@@ -283,6 +286,9 @@ static void label_destroy(struct pxe_label *label)
        if (label->fdtdir)
                free(label->fdtdir);
 
+       if (label->fdtoverlays)
+               free(label->fdtoverlays);
+
        free(label);
 }
 
@@ -321,7 +327,8 @@ static int label_localboot(struct pxe_label *label)
        if (label->append) {
                char bootargs[CONFIG_SYS_CBSIZE];
 
-               cli_simple_process_macros(label->append, bootargs);
+               cli_simple_process_macros(label->append, bootargs,
+                                         sizeof(bootargs));
                env_set("bootargs", bootargs);
        }
 
@@ -330,6 +337,92 @@ static int label_localboot(struct pxe_label *label)
        return run_command_list(localcmd, strlen(localcmd), 0);
 }
 
+/*
+ * Loads fdt overlays specified in 'fdtoverlays'.
+ */
+#ifdef CONFIG_OF_LIBFDT_OVERLAY
+static void label_boot_fdtoverlay(struct cmd_tbl *cmdtp, struct pxe_label *label)
+{
+       char *fdtoverlay = label->fdtoverlays;
+       struct fdt_header *working_fdt;
+       char *fdtoverlay_addr_env;
+       ulong fdtoverlay_addr;
+       ulong fdt_addr;
+       int err;
+
+       /* Get the main fdt and map it */
+       fdt_addr = simple_strtoul(env_get("fdt_addr_r"), NULL, 16);
+       working_fdt = map_sysmem(fdt_addr, 0);
+       err = fdt_check_header(working_fdt);
+       if (err)
+               return;
+
+       /* Get the specific overlay loading address */
+       fdtoverlay_addr_env = env_get("fdtoverlay_addr_r");
+       if (!fdtoverlay_addr_env) {
+               printf("Invalid fdtoverlay_addr_r for loading overlays\n");
+               return;
+       }
+
+       fdtoverlay_addr = simple_strtoul(fdtoverlay_addr_env, NULL, 16);
+
+       /* Cycle over the overlay files and apply them in order */
+       do {
+               struct fdt_header *blob;
+               char *overlayfile;
+               char *end;
+               int len;
+
+               /* Drop leading spaces */
+               while (*fdtoverlay == ' ')
+                       ++fdtoverlay;
+
+               /* Copy a single filename if multiple provided */
+               end = strstr(fdtoverlay, " ");
+               if (end) {
+                       len = (int)(end - fdtoverlay);
+                       overlayfile = malloc(len + 1);
+                       strncpy(overlayfile, fdtoverlay, len);
+                       overlayfile[len] = '\0';
+               } else
+                       overlayfile = fdtoverlay;
+
+               if (!strlen(overlayfile))
+                       goto skip_overlay;
+
+               /* Load overlay file */
+               err = get_relfile_envaddr(cmdtp, overlayfile,
+                                         "fdtoverlay_addr_r");
+               if (err < 0) {
+                       printf("Failed loading overlay %s\n", overlayfile);
+                       goto skip_overlay;
+               }
+
+               /* Resize main fdt */
+               fdt_shrink_to_minimum(working_fdt, 8192);
+
+               blob = map_sysmem(fdtoverlay_addr, 0);
+               err = fdt_check_header(blob);
+               if (err) {
+                       printf("Invalid overlay %s, skipping\n",
+                              overlayfile);
+                       goto skip_overlay;
+               }
+
+               err = fdt_overlay_apply_verbose(working_fdt, blob);
+               if (err) {
+                       printf("Failed to apply overlay %s, skipping\n",
+                              overlayfile);
+                       goto skip_overlay;
+               }
+
+skip_overlay:
+               if (end)
+                       free(overlayfile);
+       } while ((fdtoverlay = strstr(fdtoverlay, " ")));
+}
+#endif
+
 /*
  * Boot according to the contents of a pxe_label.
  *
@@ -399,16 +492,16 @@ static int label_boot(struct cmd_tbl *cmdtp, struct pxe_label *label)
                        env_get("gatewayip"), env_get("netmask"));
        }
 
-#ifdef CONFIG_CMD_NET
-       if (label->ipappend & 0x2) {
-               int err;
+       if (IS_ENABLED(CONFIG_CMD_NET)) {
+               if (label->ipappend & 0x2) {
+                       int err;
 
-               strcpy(mac_str, " BOOTIF=");
-               err = format_mac_pxe(mac_str + 8, sizeof(mac_str) - 8);
-               if (err < 0)
-                       mac_str[0] = '\0';
+                       strcpy(mac_str, " BOOTIF=");
+                       err = format_mac_pxe(mac_str + 8, sizeof(mac_str) - 8);
+                       if (err < 0)
+                               mac_str[0] = '\0';
+               }
        }
-#endif
 
        if ((label->ipappend & 0x3) || label->append) {
                char bootargs[CONFIG_SYS_CBSIZE] = "";
@@ -429,7 +522,8 @@ static int label_boot(struct cmd_tbl *cmdtp, struct pxe_label *label)
                strcat(bootargs, ip_str);
                strcat(bootargs, mac_str);
 
-               cli_simple_process_macros(bootargs, finalbootargs);
+               cli_simple_process_macros(bootargs, finalbootargs,
+                                         sizeof(finalbootargs));
                env_set("bootargs", finalbootargs);
                printf("append: %s\n", finalbootargs);
        }
@@ -450,11 +544,14 @@ static int label_boot(struct cmd_tbl *cmdtp, struct pxe_label *label)
 
        /*
         * fdt usage is optional:
-        * It handles the following scenarios. All scenarios are exclusive
+        * It handles the following scenarios.
         *
-        * Scenario 1: If fdt_addr_r specified and "fdt" label is defined in
-        * pxe file, retrieve fdt blob from server. Pass fdt_addr_r to bootm,
-        * and adjust argc appropriately.
+        * Scenario 1: If fdt_addr_r specified and "fdt" or "fdtdir" label is
+        * defined in pxe file, retrieve fdt blob from server. Pass fdt_addr_r to
+        * bootm, and adjust argc appropriately.
+        *
+        * If retrieve fails and no exact fdt blob is specified in pxe file with
+        * "fdt" label, try Scenario 2.
         *
         * Scenario 2: If there is an fdt_addr specified, pass it along to
         * bootm, and adjust argc appropriately.
@@ -520,10 +617,19 @@ static int label_boot(struct cmd_tbl *cmdtp, struct pxe_label *label)
 
                        free(fdtfilefree);
                        if (err < 0) {
-                               printf("Skipping %s for failure retrieving fdt\n",
-                                      label->name);
-                               goto cleanup;
+                               bootm_argv[3] = NULL;
+
+                               if (label->fdt) {
+                                       printf("Skipping %s for failure retrieving FDT\n",
+                                              label->name);
+                                       goto cleanup;
+                               }
                        }
+
+#ifdef CONFIG_OF_LIBFDT_OVERLAY
+                       if (label->fdtoverlays)
+                               label_boot_fdtoverlay(cmdtp, label);
+#endif
                } else {
                        bootm_argv[3] = NULL;
                }
@@ -543,15 +649,16 @@ static int label_boot(struct cmd_tbl *cmdtp, struct pxe_label *label)
        /* Try bootm for legacy and FIT format image */
        if (genimg_get_format(buf) != IMAGE_FORMAT_INVALID)
                do_bootm(cmdtp, 0, bootm_argc, bootm_argv);
-#ifdef CONFIG_CMD_BOOTI
        /* Try booting an AArch64 Linux kernel image */
-       else
+       else if (IS_ENABLED(CONFIG_CMD_BOOTI))
                do_booti(cmdtp, 0, bootm_argc, bootm_argv);
-#elif defined(CONFIG_CMD_BOOTZ)
        /* Try booting a Image */
-       else
+       else if (IS_ENABLED(CONFIG_CMD_BOOTZ))
                do_bootz(cmdtp, 0, bootm_argc, bootm_argv);
-#endif
+       /* Try booting an x86_64 Linux kernel image */
+       else if (IS_ENABLED(CONFIG_CMD_ZBOOT))
+               do_zboot_parent(cmdtp, 0, bootm_argc, bootm_argv, NULL);
+
        unmap_sysmem(buf);
 
 cleanup:
@@ -581,6 +688,7 @@ enum token_type {
        T_INCLUDE,
        T_FDT,
        T_FDTDIR,
+       T_FDTOVERLAYS,
        T_ONTIMEOUT,
        T_IPAPPEND,
        T_BACKGROUND,
@@ -615,6 +723,7 @@ static const struct token keywords[] = {
        {"fdt", T_FDT},
        {"devicetreedir", T_FDTDIR},
        {"fdtdir", T_FDTDIR},
+       {"fdtoverlays", T_FDTOVERLAYS},
        {"ontimeout", T_ONTIMEOUT,},
        {"ipappend", T_IPAPPEND,},
        {"background", T_BACKGROUND,},
@@ -1047,6 +1156,11 @@ static int parse_label(char **c, struct pxe_menu *cfg)
                                err = parse_sliteral(c, &label->fdtdir);
                        break;
 
+               case T_FDTOVERLAYS:
+                       if (!label->fdtoverlays)
+                               err = parse_sliteral(c, &label->fdtoverlays);
+                       break;
+
                case T_LOCALBOOT:
                        label->localboot = 1;
                        err = parse_integer(c, &label->localboot_val);
@@ -1311,20 +1425,20 @@ void handle_pxe_menu(struct cmd_tbl *cmdtp, struct pxe_menu *cfg)
        struct menu *m;
        int err;
 
-#ifdef CONFIG_CMD_BMP
-       /* display BMP if available */
-       if (cfg->bmp) {
-               if (get_relfile(cmdtp, cfg->bmp, image_load_addr)) {
-                       if (CONFIG_IS_ENABLED(CMD_CLS))
-                               run_command("cls", 0);
-                       bmp_display(image_load_addr,
-                                   BMP_ALIGN_CENTER, BMP_ALIGN_CENTER);
-               } else {
-                       printf("Skipping background bmp %s for failure\n",
-                              cfg->bmp);
+       if (IS_ENABLED(CONFIG_CMD_BMP)) {
+               /* display BMP if available */
+               if (cfg->bmp) {
+                       if (get_relfile(cmdtp, cfg->bmp, image_load_addr)) {
+                               if (CONFIG_IS_ENABLED(CMD_CLS))
+                                       run_command("cls", 0);
+                               bmp_display(image_load_addr,
+                                           BMP_ALIGN_CENTER, BMP_ALIGN_CENTER);
+                       } else {
+                               printf("Skipping background bmp %s for failure\n",
+                                      cfg->bmp);
+                       }
                }
        }
-#endif
 
        m = pxe_menu_to_menu(cfg);
        if (!m)