This provides a way to load a FIT containing U-Boot and a selection of device
tree files from a File system. Making sure that all the reads and writes
are aligned to their respective needs.

Signed-off-by: Lokesh Vutla <lokeshvu...@ti.com>
---
 common/spl/spl_fit.c | 76 +++++++++++++++++++++++++++++++++++++++++-----------
 include/spl.h        | 10 +++++++
 2 files changed, 71 insertions(+), 15 deletions(-)

diff --git a/common/spl/spl_fit.c b/common/spl/spl_fit.c
index b1cfa97..ace2543 100644
--- a/common/spl/spl_fit.c
+++ b/common/spl/spl_fit.c
@@ -82,6 +82,42 @@ static int spl_fit_select_fdt(const void *fdt, int images, 
int *fdt_offsetp)
        return -ENOENT;
 }
 
+static int get_aligned_image_offset(struct spl_load_info *info, int offset)
+{
+       /*
+        * If it is a FS read, get the first address before offset which is
+        * aligned to ARCH_DMA_MINALIGN. If it is raw read return the
+        * block number to which offset belongs.
+        */
+       if (info->priv)
+               return offset & ~(ARCH_DMA_MINALIGN - 1);
+
+       return offset / info->bl_len;
+}
+
+static int get_aligned_image_overhead(struct spl_load_info *info, int offset)
+{
+       /*
+        * If it is a FS read, get the difference between the offset and
+        * the first address before offset which is aligned to
+        * ARCH_DMA_MINALIGN. If it is raw read return the offset within the
+        * block.
+        */
+       if (info->priv)
+               return offset & (ARCH_DMA_MINALIGN - 1);
+
+       return offset % info->bl_len;
+}
+
+static int get_aligned_image_size(struct spl_load_info *info, int data_size,
+                                 int offset)
+{
+       if (info->priv)
+               return data_size + get_aligned_image_overhead(info, offset);
+
+       return (data_size + info->bl_len - 1) / info->bl_len;
+}
+
 int spl_load_simple_fit(struct spl_load_info *info, ulong sector, void *fit)
 {
        int sectors;
@@ -91,7 +127,7 @@ int spl_load_simple_fit(struct spl_load_info *info, ulong 
sector, void *fit)
        void *load_ptr;
        int fdt_offset, fdt_len;
        int data_offset, data_size;
-       int base_offset;
+       int base_offset, align_len;
        int src_sector;
        void *dst;
 
@@ -117,8 +153,10 @@ int spl_load_simple_fit(struct spl_load_info *info, ulong 
sector, void *fit)
         * In fact the FIT has its own load address, but we assume it cannot
         * be before CONFIG_SYS_TEXT_BASE.
         */
-       fit = (void *)(CONFIG_SYS_TEXT_BASE - size - info->bl_len);
-       sectors = (size + info->bl_len - 1) / info->bl_len;
+       align_len = ARCH_DMA_MINALIGN - 1;
+       fit = (void *)((CONFIG_SYS_TEXT_BASE - size - info->bl_len -
+                       align_len) & ~align_len);
+       sectors = get_aligned_image_size(info, size, 0);
        count = info->read(info, sector, sectors, fit);
        debug("fit read sector %lx, sectors=%d, dst=%p, count=%lu\n",
              sector, sectors, fit, count);
@@ -151,19 +189,23 @@ int spl_load_simple_fit(struct spl_load_info *info, ulong 
sector, void *fit)
         * byte will be at 'load'. This may mean we need to load it starting
         * before then, since we can only read whole blocks.
         */
-       sectors = (data_size + info->bl_len - 1) / info->bl_len;
        data_offset += base_offset;
+       sectors = get_aligned_image_size(info, data_size, data_offset);
        load_ptr = (void *)load;
        debug("U-Boot size %x, data %p\n", data_size, load_ptr);
-       dst = load_ptr - (data_offset % info->bl_len);
+       dst = load_ptr;
 
        /* Read the image */
-       src_sector = sector + data_offset / info->bl_len;
-       debug("image: data_offset=%x, dst=%p, src_sector=%x, sectors=%x\n",
-             data_offset, dst, src_sector, sectors);
+       src_sector = sector + get_aligned_image_offset(info, data_offset);
+       debug("Aligned image read: dst=%p, src_sector=%x, sectors=%x\n",
+             dst, src_sector, sectors);
        count = info->read(info, src_sector, sectors, dst);
        if (count != sectors)
                return -EIO;
+       debug("image: dst=%p, data_offset=%x, size=%x\n", dst, data_offset,
+             data_size);
+       memcpy(dst, dst + get_aligned_image_overhead(info, data_offset),
+              data_size);
 
        /* Figure out which device tree the board wants to use */
        fdt_len = spl_fit_select_fdt(fit, images, &fdt_offset);
@@ -173,14 +215,15 @@ int spl_load_simple_fit(struct spl_load_info *info, ulong 
sector, void *fit)
        /*
         * Read the device tree and place it after the image. There may be
         * some extra data before it since we can only read entire blocks.
+        * And also align the destination address to ARCH_DMA_MINALIGN.
         */
-       dst = load_ptr + data_size;
+       dst = (void *)((load + data_size + align_len) & ~align_len);
        fdt_offset += base_offset;
-       sectors = (fdt_len + info->bl_len - 1) / info->bl_len;
-       count = info->read(info, sector + fdt_offset / info->bl_len, sectors,
-                          dst);
-       debug("fit read %x sectors to %x, dst %p, data_offset %x\n",
-             sectors, spl_image.load_addr, dst, fdt_offset);
+       sectors = get_aligned_image_size(info, fdt_len, fdt_offset);
+       src_sector = sector + get_aligned_image_offset(info, fdt_offset);
+       count = info->read(info, src_sector, sectors, dst);
+       debug("Aligned fdt read: dst %p, src_sector = %x, sectors %x\n",
+             dst, src_sector, sectors);
        if (count != sectors)
                return -EIO;
 
@@ -189,7 +232,10 @@ int spl_load_simple_fit(struct spl_load_info *info, ulong 
sector, void *fit)
         * After this we will have the U-Boot image and its device tree ready
         * for us to start.
         */
-       memcpy(dst, dst + fdt_offset % info->bl_len, fdt_len);
+       debug("fdt: dst=%p, data_offset=%x, size=%x\n", dst, fdt_offset,
+             fdt_len);
+       memcpy(load_ptr + data_size,
+              dst + get_aligned_image_overhead(info, fdt_offset), fdt_len);
 
        return 0;
 }
diff --git a/include/spl.h b/include/spl.h
index de4f70a..358e81b 100644
--- a/include/spl.h
+++ b/include/spl.h
@@ -45,6 +45,16 @@ struct spl_load_info {
                      void *buf);
 };
 
+/**
+ * spl_load_simple_fit() - Loads a fit image from a device.
+ * @info:      Structure containing the information required to load data.
+ * @sector:    Sector number where FIT image is located in the device
+ * @fdt:       Pointer to the copied FIT header.
+ *
+ * Reads the FIT image @sector in the device. Loads u-boot image to
+ * specified load address and copies the dtb to end of u-boot image.
+ * Returns 0 on success.
+ */
 int spl_load_simple_fit(struct spl_load_info *info, ulong sector, void *fdt);
 
 #define SPL_COPY_PAYLOAD_ONLY  1
-- 
2.7.4

_______________________________________________
U-Boot mailing list
U-Boot@lists.denx.de
http://lists.denx.de/mailman/listinfo/u-boot

Reply via email to