Commit eafd5410af2ade58f25da707edaba85e44999621

Authored by Lokesh Vutla
Committed by Tom Rini
1 parent 4d9d34a7f2

spl: Allow to load a FIT containing U-Boot from FS

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.

Tested-by: Michal Simek <michal.simek@xilinx.com>
Reviewed-by: Simon Glass <sjg@chromium.org>
Reviewed-by: Tom Rini <trini@konsulko.com>
Signed-off-by: Lokesh Vutla <lokeshvutla@ti.com>
[trini: Make this still apply with Michal's alignment change for 'fit']
Signed-off-by: Tom Rini <trini@konsulko.com>

Showing 3 changed files with 71 additions and 14 deletions Side-by-side Diff

common/spl/spl_fit.c
... ... @@ -87,6 +87,42 @@
87 87 return -ENOENT;
88 88 }
89 89  
  90 +static int get_aligned_image_offset(struct spl_load_info *info, int offset)
  91 +{
  92 + /*
  93 + * If it is a FS read, get the first address before offset which is
  94 + * aligned to ARCH_DMA_MINALIGN. If it is raw read return the
  95 + * block number to which offset belongs.
  96 + */
  97 + if (info->filename)
  98 + return offset & ~(ARCH_DMA_MINALIGN - 1);
  99 +
  100 + return offset / info->bl_len;
  101 +}
  102 +
  103 +static int get_aligned_image_overhead(struct spl_load_info *info, int offset)
  104 +{
  105 + /*
  106 + * If it is a FS read, get the difference between the offset and
  107 + * the first address before offset which is aligned to
  108 + * ARCH_DMA_MINALIGN. If it is raw read return the offset within the
  109 + * block.
  110 + */
  111 + if (info->filename)
  112 + return offset & (ARCH_DMA_MINALIGN - 1);
  113 +
  114 + return offset % info->bl_len;
  115 +}
  116 +
  117 +static int get_aligned_image_size(struct spl_load_info *info, int data_size,
  118 + int offset)
  119 +{
  120 + if (info->filename)
  121 + return data_size + get_aligned_image_overhead(info, offset);
  122 +
  123 + return (data_size + info->bl_len - 1) / info->bl_len;
  124 +}
  125 +
90 126 int spl_load_simple_fit(struct spl_load_info *info, ulong sector, void *fit)
91 127 {
92 128 int sectors;
... ... @@ -96,7 +132,7 @@
96 132 void *load_ptr;
97 133 int fdt_offset, fdt_len;
98 134 int data_offset, data_size;
99   - int base_offset;
  135 + int base_offset, align_len = ARCH_DMA_MINALIGN - 1;
100 136 int src_sector;
101 137 void *dst;
102 138  
... ... @@ -124,7 +160,7 @@
124 160 */
125 161 fit = (void *)(CONFIG_SYS_TEXT_BASE - size - info->bl_len);
126 162 fit = (void *)ALIGN((ulong)fit, 8);
127   - sectors = (size + info->bl_len - 1) / info->bl_len;
  163 + sectors = get_aligned_image_size(info, size, 0);
128 164 count = info->read(info, sector, sectors, fit);
129 165 debug("fit read sector %lx, sectors=%d, dst=%p, count=%lu\n",
130 166 sector, sectors, fit, count);
131 167  
132 168  
133 169  
134 170  
... ... @@ -157,19 +193,23 @@
157 193 * byte will be at 'load'. This may mean we need to load it starting
158 194 * before then, since we can only read whole blocks.
159 195 */
160   - sectors = (data_size + info->bl_len - 1) / info->bl_len;
161 196 data_offset += base_offset;
  197 + sectors = get_aligned_image_size(info, data_size, data_offset);
162 198 load_ptr = (void *)load;
163 199 debug("U-Boot size %x, data %p\n", data_size, load_ptr);
164   - dst = load_ptr - (data_offset % info->bl_len);
  200 + dst = load_ptr;
165 201  
166 202 /* Read the image */
167   - src_sector = sector + data_offset / info->bl_len;
168   - debug("image: data_offset=%x, dst=%p, src_sector=%x, sectors=%x\n",
169   - data_offset, dst, src_sector, sectors);
  203 + src_sector = sector + get_aligned_image_offset(info, data_offset);
  204 + debug("Aligned image read: dst=%p, src_sector=%x, sectors=%x\n",
  205 + dst, src_sector, sectors);
170 206 count = info->read(info, src_sector, sectors, dst);
171 207 if (count != sectors)
172 208 return -EIO;
  209 + debug("image: dst=%p, data_offset=%x, size=%x\n", dst, data_offset,
  210 + data_size);
  211 + memcpy(dst, dst + get_aligned_image_overhead(info, data_offset),
  212 + data_size);
173 213  
174 214 /* Figure out which device tree the board wants to use */
175 215 fdt_len = spl_fit_select_fdt(fit, images, &fdt_offset);
176 216  
177 217  
... ... @@ -179,14 +219,15 @@
179 219 /*
180 220 * Read the device tree and place it after the image. There may be
181 221 * some extra data before it since we can only read entire blocks.
  222 + * And also align the destination address to ARCH_DMA_MINALIGN.
182 223 */
183   - dst = load_ptr + data_size;
  224 + dst = (void *)((load + data_size + align_len) & ~align_len);
184 225 fdt_offset += base_offset;
185   - sectors = (fdt_len + info->bl_len - 1) / info->bl_len;
186   - count = info->read(info, sector + fdt_offset / info->bl_len, sectors,
187   - dst);
188   - debug("fit read %x sectors to %x, dst %p, data_offset %x\n",
189   - sectors, spl_image.load_addr, dst, fdt_offset);
  226 + sectors = get_aligned_image_size(info, fdt_len, fdt_offset);
  227 + src_sector = sector + get_aligned_image_offset(info, fdt_offset);
  228 + count = info->read(info, src_sector, sectors, dst);
  229 + debug("Aligned fdt read: dst %p, src_sector = %x, sectors %x\n",
  230 + dst, src_sector, sectors);
190 231 if (count != sectors)
191 232 return -EIO;
192 233  
... ... @@ -195,7 +236,10 @@
195 236 * After this we will have the U-Boot image and its device tree ready
196 237 * for us to start.
197 238 */
198   - memcpy(dst, dst + fdt_offset % info->bl_len, fdt_len);
  239 + debug("fdt: dst=%p, data_offset=%x, size=%x\n", dst, fdt_offset,
  240 + fdt_len);
  241 + memcpy(load_ptr + data_size,
  242 + dst + get_aligned_image_overhead(info, fdt_offset), fdt_len);
199 243  
200 244 return 0;
201 245 }
common/spl/spl_mmc.c
... ... @@ -77,6 +77,7 @@
77 77 debug("Found FIT\n");
78 78 load.dev = mmc;
79 79 load.priv = NULL;
  80 + load.filename = NULL;
80 81 load.bl_len = mmc->read_bl_len;
81 82 load.read = h_spl_load_read;
82 83 ret = spl_load_simple_fit(&load, sector, header);
... ... @@ -35,16 +35,28 @@
35 35 * @dev: Pointer to the device, e.g. struct mmc *
36 36 * @priv: Private data for the device
37 37 * @bl_len: Block length for reading in bytes
  38 + * @filename: Name of the fit image file.
38 39 * @read: Function to call to read from the device
39 40 */
40 41 struct spl_load_info {
41 42 void *dev;
42 43 void *priv;
43 44 int bl_len;
  45 + const char *filename;
44 46 ulong (*read)(struct spl_load_info *load, ulong sector, ulong count,
45 47 void *buf);
46 48 };
47 49  
  50 +/**
  51 + * spl_load_simple_fit() - Loads a fit image from a device.
  52 + * @info: Structure containing the information required to load data.
  53 + * @sector: Sector number where FIT image is located in the device
  54 + * @fdt: Pointer to the copied FIT header.
  55 + *
  56 + * Reads the FIT image @sector in the device. Loads u-boot image to
  57 + * specified load address and copies the dtb to end of u-boot image.
  58 + * Returns 0 on success.
  59 + */
48 60 int spl_load_simple_fit(struct spl_load_info *info, ulong sector, void *fdt);
49 61  
50 62 #define SPL_COPY_PAYLOAD_ONLY 1