Commit eafd5410af2ade58f25da707edaba85e44999621
Committed by
Tom Rini
1 parent
4d9d34a7f2
Exists in
v2017.01-smarct4x
and in
25 other branches
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
include/spl.h
... | ... | @@ -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 |