]> git.kernelconcepts.de Git - karo-tx-uboot.git/blobdiff - tools/ifdtool.c
karo: configs: Update the tx6*_defconfig files from defconfigs generated with 'make...
[karo-tx-uboot.git] / tools / ifdtool.c
index b794516189cd66991b6826f6f58b089864dfe7fe..1f95203eea9ed12c88ccf7af5aee75c5eee1f098 100644 (file)
@@ -768,6 +768,8 @@ static int scan_ucode(const void *blob, char *ucode_base, int *countp,
                        return -ENOENT;
                }
 
+               if (ucode_base)
+                       memcpy(ucode, data, data_size);
                ucode += data_size;
        }
 
@@ -781,16 +783,61 @@ static int scan_ucode(const void *blob, char *ucode_base, int *countp,
        return ucode - ucode_base;
 }
 
+static int remove_ucode(char *blob)
+{
+       int node, count;
+       int ret;
+
+       /* Keep going until we find no more microcode to remove */
+       do {
+               for (node = 0, count = 0; node >= 0;) {
+                       int ret;
+
+                       node = fdt_node_offset_by_compatible(blob, node,
+                                                            "intel,microcode");
+                       if (node < 0)
+                               break;
+
+                       ret = fdt_delprop(blob, node, "data");
+
+                       /*
+                        * -FDT_ERR_NOTFOUND means we already removed the
+                        * data for this one, so we just continue.
+                        * 0 means we did remove it, so offsets may have
+                        * changed and we need to restart our scan.
+                        * Anything else indicates an error we should report.
+                        */
+                       if (ret == -FDT_ERR_NOTFOUND)
+                               continue;
+                       else if (!ret)
+                               node = 0;
+                       else
+                               return ret;
+               }
+       } while (count);
+
+       /* Pack down to remove excees space */
+       ret = fdt_pack(blob);
+       if (ret)
+               return ret;
+
+       return fdt_totalsize(blob);
+}
+
 static int write_ucode(char *image, int size, struct input_file *fdt,
-                      int fdt_size, unsigned int ucode_ptr)
+                      int fdt_size, unsigned int ucode_ptr,
+                      int collate_ucode)
 {
        const char *data = NULL;
+       char *ucode_buf;
        const void *blob;
+       char *ucode_base;
        uint32_t *ptr;
        int ucode_size;
        int data_size;
        int offset;
        int count;
+       int ret;
 
        blob = (void *)image + (uint32_t)(fdt->addr + size);
 
@@ -805,12 +852,53 @@ static int write_ucode(char *image, int size, struct input_file *fdt,
                return -ENOENT;
        }
 
-       if (count > 1) {
+       if (count > 1 && !collate_ucode) {
                fprintf(stderr,
-                       "Cannot handle multiple microcode blocks\n");
+                       "Cannot handle multiple microcode blocks - please use -C flag to collate them\n");
                return -EMLINK;
        }
 
+       /*
+        * Collect the microcode into a buffer, remove it from the device
+        * tree and place it immediately above the (now smaller) device tree.
+        */
+       if (collate_ucode && count > 1) {
+               ucode_buf = malloc(ucode_size);
+               if (!ucode_buf) {
+                       fprintf(stderr,
+                               "Out of memory for microcode (%d bytes)\n",
+                               ucode_size);
+                       return -ENOMEM;
+               }
+               ret = scan_ucode(blob, ucode_buf, NULL, NULL, NULL);
+               if (ret < 0)
+                       return ret;
+
+               /* Remove the microcode from the device tree */
+               ret = remove_ucode((char *)blob);
+               if (ret < 0) {
+                       debug("Could not remove FDT microcode: %s\n",
+                             fdt_strerror(ret));
+                       return -EINVAL;
+               }
+               debug("Collated %d microcode block(s)\n", count);
+               debug("Device tree reduced from %x to %x bytes\n",
+                     fdt_size, ret);
+               fdt_size = ret;
+
+               /*
+                * Place microcode area immediately above the FDT, aligned
+                * to a 16-byte boundary.
+                */
+               ucode_base = (char *)(((unsigned long)blob + fdt_size + 15) &
+                               ~15);
+
+               data = ucode_base;
+               data_size = ucode_size;
+               memcpy(ucode_base, ucode_buf, ucode_size);
+               free(ucode_buf);
+       }
+
        offset = (uint32_t)(ucode_ptr + size);
        ptr = (void *)image + offset;
 
@@ -819,7 +907,8 @@ static int write_ucode(char *image, int size, struct input_file *fdt,
        debug("Wrote microcode pointer at %x: addr=%x, size=%x\n", ucode_ptr,
              ptr[0], ptr[1]);
 
-       return 0;
+       return (collate_ucode ? data + data_size : (char *)blob + fdt_size) -
+                       image;
 }
 
 /**
@@ -837,7 +926,8 @@ static int write_ucode(char *image, int size, struct input_file *fdt,
  * @return 0 if OK, -ve on error
  */
 static int write_uboot(char *image, int size, struct input_file *uboot,
-                      struct input_file *fdt, unsigned int ucode_ptr)
+                      struct input_file *fdt, unsigned int ucode_ptr,
+                      int collate_ucode)
 {
        const void *blob;
        int uboot_size, fdt_size;
@@ -852,8 +942,10 @@ static int write_uboot(char *image, int size, struct input_file *uboot,
                return fdt_size;
        blob = (void *)image + (uint32_t)(fdt->addr + size);
 
-       if (ucode_ptr)
-               return write_ucode(image, size, fdt, fdt_size, ucode_ptr);
+       if (ucode_ptr) {
+               return write_ucode(image, size, fdt, fdt_size, ucode_ptr,
+                                  collate_ucode);
+       }
 
        return ((char *)blob + fdt_size) - image;
 }
@@ -919,7 +1011,7 @@ int main(int argc, char *argv[])
        int mode_dump = 0, mode_extract = 0, mode_inject = 0;
        int mode_spifreq = 0, mode_em100 = 0, mode_locked = 0;
        int mode_unlocked = 0, mode_write = 0, mode_write_descriptor = 0;
-       int create = 0;
+       int create = 0, collate_ucode = 0;
        char *region_type_string = NULL, *inject_fname = NULL;
        char *desc_fname = NULL, *addr_str = NULL;
        int region_type = -1, inputfreq = 0;
@@ -939,6 +1031,7 @@ int main(int argc, char *argv[])
        int ret;
        static struct option long_options[] = {
                {"create", 0, NULL, 'c'},
+               {"collate-microcode", 0, NULL, 'C'},
                {"dump", 0, NULL, 'd'},
                {"descriptor", 1, NULL, 'D'},
                {"em100", 0, NULL, 'e'},
@@ -957,12 +1050,15 @@ int main(int argc, char *argv[])
                {0, 0, 0, 0}
        };
 
-       while ((opt = getopt_long(argc, argv, "cdD:ef:hi:lm:r:s:uU:vw:x?",
+       while ((opt = getopt_long(argc, argv, "cCdD:ef:hi:lm:r:s:uU:vw:x?",
                                  long_options, &option_index)) != EOF) {
                switch (opt) {
                case 'c':
                        create = 1;
                        break;
+               case 'C':
+                       collate_ucode = 1;
+                       break;
                case 'd':
                        mode_dump = 1;
                        break;
@@ -1186,7 +1282,7 @@ int main(int argc, char *argv[])
                                continue;
                        } else if (ifile->type == IF_uboot) {
                                ret = write_uboot(image, size, ifile, fdt,
-                                                 ucode_ptr);
+                                                 ucode_ptr, collate_ucode);
                                offset_uboot_top = ret;
                        } else {
                                ret = write_data(image, size, ifile->addr,