]> git.kernelconcepts.de Git - karo-tx-uboot.git/blobdiff - tools/ifdtool.c
LG Optimus Black (P970) codename sniper support
[karo-tx-uboot.git] / tools / ifdtool.c
index 4077ba8b2edb0e116b36843461a864fe7b6ae81d..df166161f439f7fe66d2f9f2675298e2785bb20f 100644 (file)
@@ -18,6 +18,7 @@
 #include <unistd.h>
 #include <sys/types.h>
 #include <sys/stat.h>
+#include <libfdt.h>
 #include "ifdtool.h"
 
 #undef DEBUG
@@ -34,6 +35,8 @@
 
 enum input_file_type_t {
        IF_normal,
+       IF_fdt,
+       IF_uboot,
 };
 
 struct input_file {
@@ -459,7 +462,7 @@ static int write_regions(char *image, int size)
                if (ret)
                        return ret;
                dump_region(i, frba);
-               if (region.size == 0)
+               if (region.size <= 0)
                        continue;
                region_fd = open(region_filename(i),
                                 O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR |
@@ -703,7 +706,7 @@ int inject_region(char *image, int size, int region_type, char *region_fname)
  *                     0xffffffff so use an address relative to that. For an
  *                     8MB ROM the start address is 0xfff80000.
  * @write_fname:       Filename to add to the image
- * @return 0 if OK, -ve on error
+ * @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)
@@ -715,7 +718,7 @@ static int write_data(char *image, int size, unsigned int addr,
        if (write_fd < 0)
                return write_fd;
 
-       offset = addr + size;
+       offset = (uint32_t)(addr + size);
        debug("Writing %s to offset %#x\n", write_fname, offset);
 
        if (offset < 0 || offset + write_size > size) {
@@ -731,6 +734,68 @@ static int write_data(char *image, int size, unsigned int addr,
 
        close(write_fd);
 
+       return write_size;
+}
+
+/**
+ * write_uboot() - Write U-Boot, device tree and microcode pointer
+ *
+ * This writes U-Boot into a place in the flash, followed by its device tree.
+ * The microcode pointer is written so that U-Boot can find the microcode in
+ * the device tree very early in boot.
+ *
+ * @image:     Pointer to image
+ * @size:      Size of image in bytes
+ * @uboot:     Input file information for u-boot.bin
+ * @fdt:       Input file information for u-boot.dtb
+ * @ucode_ptr: Address in U-Boot where the microcode pointer should be placed
+ * @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)
+{
+       const void *blob;
+       const char *data;
+       int uboot_size;
+       uint32_t *ptr;
+       int data_size;
+       int offset;
+       int node;
+       int ret;
+
+       uboot_size = write_data(image, size, uboot->addr, uboot->fname);
+       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);
+       ret = write_data(image, size, fdt->addr, fdt->fname);
+       if (ret < 0)
+               return ret;
+
+       if (ucode_ptr) {
+               blob = (void *)image + (uint32_t)(fdt->addr + size);
+               debug("DTB at %lx\n", (char *)blob - image);
+               node = fdt_node_offset_by_compatible(blob, 0,
+                                                    "intel,microcode");
+               if (node < 0) {
+                       debug("No microcode found in FDT: %s\n",
+                             fdt_strerror(node));
+                       return -ENOENT;
+               }
+               data = fdt_getprop(blob, node, "data", &data_size);
+               if (!data) {
+                       debug("No microcode data found in FDT: %s\n",
+                             fdt_strerror(data_size));
+                       return -ENOENT;
+               }
+               offset = (uint32_t)(ucode_ptr + size);
+               ptr = (void *)image + offset;
+               ptr[0] = (data - image) - size;
+               ptr[1] = data_size;
+               debug("Wrote microcode pointer at %x: addr=%x, size=%x\n",
+                     ucode_ptr, ptr[0], ptr[1]);
+       }
+
        return 0;
 }
 
@@ -800,7 +865,7 @@ int main(int argc, char *argv[])
        char *desc_fname = NULL, *addr_str = NULL;
        int region_type = -1, inputfreq = 0;
        enum spi_frequency spifreq = SPI_FREQUENCY_20MHZ;
-       struct input_file input_file[WRITE_MAX], *ifile;
+       struct input_file input_file[WRITE_MAX], *ifile, *fdt = NULL;
        unsigned char wr_idx, wr_num = 0;
        int rom_size = -1;
        bool write_it;
@@ -808,6 +873,8 @@ int main(int argc, char *argv[])
        char *outfile = NULL;
        struct stat buf;
        int size = 0;
+       unsigned int ucode_ptr = 0;
+       bool have_uboot = false;
        int bios_fd;
        char *image;
        int ret;
@@ -817,18 +884,21 @@ int main(int argc, char *argv[])
                {"descriptor", 1, NULL, 'D'},
                {"em100", 0, NULL, 'e'},
                {"extract", 0, NULL, 'x'},
+               {"fdt", 1, NULL, 'f'},
                {"inject", 1, NULL, 'i'},
                {"lock", 0, NULL, 'l'},
+               {"microcode", 1, NULL, 'm'},
                {"romsize", 1, NULL, 'r'},
                {"spifreq", 1, NULL, 's'},
                {"unlock", 0, NULL, 'u'},
+               {"uboot", 1, NULL, 'U'},
                {"write", 1, NULL, 'w'},
                {"version", 0, NULL, 'v'},
                {"help", 0, NULL, 'h'},
                {0, 0, 0, 0}
        };
 
-       while ((opt = getopt_long(argc, argv, "cdD:ehi:lr:s:uvw:x?",
+       while ((opt = getopt_long(argc, argv, "cdD:ef:hi:lm:r:s:uU:vw:x?",
                                  long_options, &option_index)) != EOF) {
                switch (opt) {
                case 'c':
@@ -871,6 +941,9 @@ int main(int argc, char *argv[])
                case 'l':
                        mode_locked = 1;
                        break;
+               case 'm':
+                       ucode_ptr = strtoul(optarg, NULL, 0);
+                       break;
                case 'r':
                        rom_size = strtol(optarg, NULL, 0);
                        debug("ROM size %d\n", rom_size);
@@ -904,6 +977,8 @@ int main(int argc, char *argv[])
                        exit(EXIT_SUCCESS);
                        break;
                case 'w':
+               case 'U':
+               case 'f':
                        ifile = &input_file[wr_num];
                        mode_write = 1;
                        if (wr_num < WRITE_MAX) {
@@ -912,8 +987,13 @@ int main(int argc, char *argv[])
                                        print_usage(argv[0]);
                                        exit(EXIT_FAILURE);
                                }
-                               ifile->addr = strtol(optarg, NULL, 0);
-                               ifile->type = IF_normal;
+                               ifile->addr = strtoll(optarg, NULL, 0);
+                               ifile->type = opt == 'f' ? IF_fdt :
+                                       opt == 'U' ? IF_uboot : IF_normal;
+                               if (ifile->type == IF_fdt)
+                                       fdt = ifile;
+                               else if (ifile->type == IF_uboot)
+                                       have_uboot = true;
                                wr_num++;
                        } else {
                                fprintf(stderr,
@@ -970,6 +1050,13 @@ int main(int argc, char *argv[])
                exit(EXIT_FAILURE);
        }
 
+       if (have_uboot && !fdt) {
+               fprintf(stderr,
+                       "You must supply a device tree file for U-Boot\n\n");
+               print_usage(argv[0]);
+               exit(EXIT_FAILURE);
+       }
+
        filename = argv[optind];
        if (optind + 2 != argc)
                outfile = argv[optind + 1];
@@ -1034,9 +1121,16 @@ int main(int argc, char *argv[])
        if (mode_write) {
                for (wr_idx = 0; wr_idx < wr_num; wr_idx++) {
                        ifile = &input_file[wr_idx];
-                       ret = write_data(image, size, ifile->addr,
+                       if (ifile->type == IF_fdt) {
+                               continue;
+                       } else if (ifile->type == IF_uboot) {
+                               ret = write_uboot(image, size, ifile, fdt,
+                                                 ucode_ptr);
+                       } else {
+                               ret = write_data(image, size, ifile->addr,
                                         ifile->fname);
-                       if (ret)
+                       }
+                       if (ret < 0)
                                break;
                }
        }
@@ -1071,5 +1165,5 @@ int main(int argc, char *argv[])
        free(image);
        close(bios_fd);
 
-       return ret ? 1 : 0;
+       return ret < 0 ? 1 : 0;
 }