spl: mmc: refactor device location code to its own function
[oweals/u-boot.git] / tools / ifdtool.c
index d966c563da4a261360003def2568cfc6b00414ae..48059c02b550ee8db3cbfc7c9702b152936a0d4e 100644 (file)
@@ -707,10 +707,12 @@ int inject_region(char *image, int size, int region_type, char *region_fname)
  *                     8MB ROM the start address is 0xfff80000.
  * @write_fname:       Filename to add to the image
  * @offset_uboot_top:  Offset of the top of U-Boot
+ * @offset_uboot_start:        Offset of the start of U-Boot
  * @return number of bytes written if OK, -ve on error
  */
 static int write_data(char *image, int size, unsigned int addr,
-                     const char *write_fname, int offset_uboot_top)
+                     const char *write_fname, int offset_uboot_top,
+                     int offset_uboot_start)
 {
        int write_fd, write_size;
        int offset;
@@ -720,13 +722,25 @@ static int write_data(char *image, int size, unsigned int addr,
                return write_fd;
 
        offset = (uint32_t)(addr + size);
-       if (offset_uboot_top && offset_uboot_top >= offset) {
-               fprintf(stderr, "U-Boot image overlaps with region '%s'\n",
-                       write_fname);
-               fprintf(stderr,
-                       "U-Boot finishes at offset %x, file starts at %x\n",
-                       offset_uboot_top, offset);
-               return -EXDEV;
+       if (offset_uboot_top) {
+               if (offset_uboot_start < offset &&
+                   offset_uboot_top >= offset) {
+                       fprintf(stderr, "U-Boot image overlaps with region '%s'\n",
+                               write_fname);
+                       fprintf(stderr,
+                               "U-Boot finishes at offset %x, file starts at %x\n",
+                               offset_uboot_top, offset);
+                       return -EXDEV;
+               }
+               if (offset_uboot_start > offset &&
+                   offset_uboot_start <= offset + write_size) {
+                       fprintf(stderr, "U-Boot image overlaps with region '%s'\n",
+                               write_fname);
+                       fprintf(stderr,
+                               "U-Boot starts at offset %x, file finishes at %x\n",
+                               offset_uboot_start, offset + write_size);
+                       return -EXDEV;
+               }
        }
        debug("Writing %s to offset %#x\n", write_fname, offset);
 
@@ -783,6 +797,47 @@ 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 collate_ucode)
@@ -818,8 +873,8 @@ static int write_ucode(char *image, int size, struct input_file *fdt,
        }
 
        /*
-        * Collect the microcode into a buffer and place it immediately above
-        * the device tree.
+        * 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);
@@ -833,7 +888,17 @@ static int write_ucode(char *image, int size, struct input_file *fdt,
                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
@@ -876,27 +941,36 @@ static int write_ucode(char *image, int size, struct input_file *fdt,
  */
 static int write_uboot(char *image, int size, struct input_file *uboot,
                       struct input_file *fdt, unsigned int ucode_ptr,
-                      int collate_ucode)
+                      int collate_ucode, int *offset_uboot_top,
+                      int *offset_uboot_start)
 {
-       const void *blob;
        int uboot_size, fdt_size;
+       int uboot_top;
 
-       uboot_size = write_data(image, size, uboot->addr, uboot->fname, 0);
+       uboot_size = write_data(image, size, uboot->addr, uboot->fname, 0, 0);
        if (uboot_size < 0)
                return uboot_size;
        fdt->addr = uboot->addr + uboot_size;
        debug("U-Boot size %#x, FDT at %#x\n", uboot_size, fdt->addr);
-       fdt_size = write_data(image, size, fdt->addr, fdt->fname, 0);
+       fdt_size = write_data(image, size, fdt->addr, fdt->fname, 0, 0);
        if (fdt_size < 0)
                return fdt_size;
-       blob = (void *)image + (uint32_t)(fdt->addr + size);
+
+       uboot_top = (uint32_t)(fdt->addr + size) + fdt_size;
 
        if (ucode_ptr) {
-               return write_ucode(image, size, fdt, fdt_size, ucode_ptr,
-                                  collate_ucode);
+               uboot_top = write_ucode(image, size, fdt, fdt_size, ucode_ptr,
+                                       collate_ucode);
+               if (uboot_top < 0)
+                       return uboot_top;
        }
 
-       return ((char *)blob + fdt_size) - image;
+       if (offset_uboot_top && offset_uboot_start) {
+               *offset_uboot_top = uboot_top;
+               *offset_uboot_start = (uint32_t)(uboot->addr + size);
+       }
+
+       return 0;
 }
 
 static void print_version(void)
@@ -1217,13 +1291,14 @@ int main(int argc, char *argv[])
        }
 
        if (mode_write_descriptor)
-               ret = write_data(image, size, -size, desc_fname, 0);
+               ret = write_data(image, size, -size, desc_fname, 0, 0);
 
        if (mode_inject)
                ret = inject_region(image, size, region_type, inject_fname);
 
        if (mode_write) {
                int offset_uboot_top = 0;
+               int offset_uboot_start = 0;
 
                for (wr_idx = 0; wr_idx < wr_num; wr_idx++) {
                        ifile = &input_file[wr_idx];
@@ -1231,11 +1306,13 @@ int main(int argc, char *argv[])
                                continue;
                        } else if (ifile->type == IF_uboot) {
                                ret = write_uboot(image, size, ifile, fdt,
-                                                 ucode_ptr, collate_ucode);
-                               offset_uboot_top = ret;
+                                                 ucode_ptr, collate_ucode,
+                                                 &offset_uboot_top,
+                                                 &offset_uboot_start);
                        } else {
                                ret = write_data(image, size, ifile->addr,
-                                        ifile->fname, offset_uboot_top);
+                                                ifile->fname, offset_uboot_top,
+                                                offset_uboot_start);
                        }
                        if (ret < 0)
                                break;