1 // SPDX-License-Identifier: GPL-2.0+
4 * Linus Walleij, Linaro
6 * Support for ARM Flash Partitions
29 struct afs_region regions
[MAX_REGIONS
];
30 ulong flash_mem_start
;
34 static struct afs_image afs_images
[MAX_IMAGES
];
35 static int num_afs_images
;
37 static u32
compute_crc(ulong start
, u32 len
)
43 printf("bad checksumming\n");
47 for (i
= 0; i
< len
; i
+= 4) {
50 val
= readl((void *)start
+ i
);
58 static void parse_bank(ulong bank
)
64 info
= &flash_info
[bank
];
65 if (info
->flash_id
!= FLASH_MAN_CFI
) {
66 printf("Bank %lu: missing or unknown FLASH type\n", bank
);
69 if (!info
->sector_count
) {
70 printf("Bank %lu: no FLASH sectors\n", bank
);
74 flstart
= info
->start
[0];
75 flend
= flstart
+ info
->size
;
77 for (i
= 0; i
< info
->sector_count
; ++i
) {
84 if (i
== info
->sector_count
-1)
87 secend
= info
->start
[i
+1];
89 /* Check for v1 header */
90 foot1
= readl((void *)secend
- 0x0c);
91 if (foot1
== 0xA0FFFF9FU
) {
92 struct afs_image
*afi
= &afs_images
[num_afs_images
];
97 afi
->flash_mem_start
= readl((void *)secend
- 0x10);
98 afi
->flash_mem_end
= readl((void *)secend
- 0x14);
99 afi
->attributes
= readl((void *)secend
- 0x08);
100 /* Adjust to even address */
101 imginfo
= afi
->flash_mem_end
+ afi
->flash_mem_end
% 4;
102 /* Record as a single region */
103 afi
->region_count
= 1;
104 afi
->regions
[0].offset
= readl((void *)imginfo
+ 0x04);
105 afi
->regions
[0].load_address
=
106 readl((void *)imginfo
+ 0x08);
107 afi
->regions
[0].size
= readl((void *)imginfo
+ 0x0C);
108 afi
->entrypoint
= readl((void *)imginfo
+ 0x10);
109 afi
->name
= (const char *)imginfo
+ 0x14;
113 /* Check for v2 header */
114 foot1
= readl((void *)secend
- 0x04);
115 foot2
= readl((void *)secend
- 0x08);
116 /* This makes up the string "HSLFTOOF" flash footer */
117 if (foot1
== 0x464F4F54U
&& foot2
== 0x464C5348U
) {
118 struct afs_image
*afi
= &afs_images
[num_afs_images
];
120 u32 block_start
, block_end
;
124 afi
->version
= readl((void *)secend
- 0x0c);
125 imginfo
= secend
- 0x30 - readl((void *)secend
- 0x10);
126 afi
->name
= (const char *)secend
- 0x30;
128 afi
->entrypoint
= readl((void *)imginfo
+0x08);
129 afi
->attributes
= readl((void *)imginfo
+0x0c);
130 afi
->region_count
= readl((void *)imginfo
+0x10);
131 block_start
= readl((void *)imginfo
+0x54);
132 block_end
= readl((void *)imginfo
+0x58);
133 afi
->flash_mem_start
= afi
->flinfo
->start
[block_start
];
134 afi
->flash_mem_end
= afi
->flinfo
->start
[block_end
];
137 * Check footer CRC, the algorithm saves the inverse
138 * checksum as part of the summed words, and thus
139 * the result should be zero.
141 if (compute_crc(imginfo
+ 8, 0x88) != 0) {
142 printf("BAD CRC on ARM image info\n");
143 printf("(continuing anyway)\n");
147 for (j
= 0; j
< afi
->region_count
; j
++) {
148 afi
->regions
[j
].load_address
=
149 readl((void *)imginfo
+0x14 + j
*0x10);
150 afi
->regions
[j
].size
=
151 readl((void *)imginfo
+0x18 + j
*0x10);
152 afi
->regions
[j
].offset
=
153 readl((void *)imginfo
+0x1c + j
*0x10);
155 * At offset 0x20 + j*0x10 there is a region
156 * checksum which seems to be the running
157 * sum + 3, however since we anyway checksum
158 * the entire footer this is skipped over for
167 static void parse_flash(void)
171 /* We have already parsed the images in flash */
172 if (num_afs_images
> 0)
174 for (bank
= 0; bank
< CONFIG_SYS_MAX_FLASH_BANKS
; ++bank
)
178 static int load_image(const char * const name
, const ulong address
)
180 struct afs_image
*afi
= NULL
;
184 for (i
= 0; i
< num_afs_images
; i
++) {
185 struct afs_image
*tmp
= &afs_images
[i
];
187 if (!strcmp(tmp
->name
, name
)) {
193 printf("image \"%s\" not found in flash\n", name
);
194 return CMD_RET_FAILURE
;
197 for (i
= 0; i
< afi
->region_count
; i
++) {
200 from
= afi
->flash_mem_start
+ afi
->regions
[i
].offset
;
203 } else if (afi
->regions
[i
].load_address
) {
204 to
= afi
->regions
[i
].load_address
;
206 printf("no valid load address\n");
207 return CMD_RET_FAILURE
;
210 memcpy((void *)to
, (void *)from
, afi
->regions
[i
].size
);
212 printf("loaded region %d from %08lX to %08lX, %08X bytes\n",
216 afi
->regions
[i
].size
);
218 return CMD_RET_SUCCESS
;
221 static void print_images(void)
226 for (i
= 0; i
< num_afs_images
; i
++) {
227 struct afs_image
*afi
= &afs_images
[i
];
230 printf("Image: \"%s\" (v%d):\n", afi
->name
, afi
->version
);
231 printf(" Entry point: 0x%08X\n", afi
->entrypoint
);
232 printf(" Attributes: 0x%08X: ", afi
->attributes
);
233 if (afi
->attributes
== 0x01)
234 printf("ARM executable");
235 if (afi
->attributes
== 0x08)
236 printf("ARM backup");
238 printf(" Flash mem start: 0x%08lX\n",
239 afi
->flash_mem_start
);
240 printf(" Flash mem end: 0x%08lX\n",
242 for (j
= 0; j
< afi
->region_count
; j
++) {
243 printf(" region %d\n"
244 " load address: %08X\n"
248 afi
->regions
[j
].load_address
,
249 afi
->regions
[j
].size
,
250 afi
->regions
[j
].offset
);
255 static int exists(const char * const name
)
260 for (i
= 0; i
< num_afs_images
; i
++) {
261 struct afs_image
*afi
= &afs_images
[i
];
263 if (strcmp(afi
->name
, name
) == 0)
264 return CMD_RET_SUCCESS
;
266 return CMD_RET_FAILURE
;
269 static int do_afs(cmd_tbl_t
*cmdtp
, int flag
, int argc
, char * const argv
[])
271 int ret
= CMD_RET_SUCCESS
;
275 } else if (argc
== 3 && !strcmp(argv
[1], "exists")) {
276 ret
= exists(argv
[2]);
277 } else if (argc
== 3 && !strcmp(argv
[1], "load")) {
278 ret
= load_image(argv
[2], 0x0);
279 } else if (argc
== 4 && !strcmp(argv
[1], "load")) {
282 load_addr
= simple_strtoul(argv
[3], NULL
, 16);
283 ret
= load_image(argv
[2], load_addr
);
285 return CMD_RET_USAGE
;
291 U_BOOT_CMD(afs
, 4, 0, do_afs
, "show AFS partitions",
293 " - list images in flash\n"
295 " - returns 1 if an image exists, else 0\n"
297 " - load an image to the location indicated in the header\n"
298 "load <image> 0x<address>\n"
299 " - load an image to the location specified\n");