3 * Linus Walleij, Linaro
5 * Support for ARM Flash Partitions
7 * SPDX-License-Identifier: GPL-2.0+
30 struct afs_region regions
[MAX_REGIONS
];
31 ulong flash_mem_start
;
35 static struct afs_image afs_images
[MAX_IMAGES
];
36 static int num_afs_images
;
38 static u32
compute_crc(ulong start
, u32 len
)
44 printf("bad checksumming\n");
48 for (i
= 0; i
< len
; i
+= 4) {
51 val
= readl((void *)start
+ i
);
59 static void parse_bank(ulong bank
)
65 info
= &flash_info
[bank
];
66 if (info
->flash_id
!= FLASH_MAN_CFI
) {
67 printf("Bank %lu: missing or unknown FLASH type\n", bank
);
70 if (!info
->sector_count
) {
71 printf("Bank %lu: no FLASH sectors\n", bank
);
75 flstart
= info
->start
[0];
76 flend
= flstart
+ info
->size
;
78 for (i
= 0; i
< info
->sector_count
; ++i
) {
85 if (i
== info
->sector_count
-1)
88 secend
= info
->start
[i
+1];
90 /* Check for v1 header */
91 foot1
= readl((void *)secend
- 0x0c);
92 if (foot1
== 0xA0FFFF9FU
) {
93 struct afs_image
*afi
= &afs_images
[num_afs_images
];
98 afi
->flash_mem_start
= readl((void *)secend
- 0x10);
99 afi
->flash_mem_end
= readl((void *)secend
- 0x14);
100 afi
->attributes
= readl((void *)secend
- 0x08);
101 /* Adjust to even address */
102 imginfo
= afi
->flash_mem_end
+ afi
->flash_mem_end
% 4;
103 /* Record as a single region */
104 afi
->region_count
= 1;
105 afi
->regions
[0].offset
= readl((void *)imginfo
+ 0x04);
106 afi
->regions
[0].load_address
=
107 readl((void *)imginfo
+ 0x08);
108 afi
->regions
[0].size
= readl((void *)imginfo
+ 0x0C);
109 afi
->entrypoint
= readl((void *)imginfo
+ 0x10);
110 afi
->name
= (const char *)imginfo
+ 0x14;
114 /* Check for v2 header */
115 foot1
= readl((void *)secend
- 0x04);
116 foot2
= readl((void *)secend
- 0x08);
117 /* This makes up the string "HSLFTOOF" flash footer */
118 if (foot1
== 0x464F4F54U
&& foot2
== 0x464C5348U
) {
119 struct afs_image
*afi
= &afs_images
[num_afs_images
];
121 u32 block_start
, block_end
;
125 afi
->version
= readl((void *)secend
- 0x0c);
126 imginfo
= secend
- 0x30 - readl((void *)secend
- 0x10);
127 afi
->name
= (const char *)secend
- 0x30;
129 afi
->entrypoint
= readl((void *)imginfo
+0x08);
130 afi
->attributes
= readl((void *)imginfo
+0x0c);
131 afi
->region_count
= readl((void *)imginfo
+0x10);
132 block_start
= readl((void *)imginfo
+0x54);
133 block_end
= readl((void *)imginfo
+0x58);
134 afi
->flash_mem_start
= afi
->flinfo
->start
[block_start
];
135 afi
->flash_mem_end
= afi
->flinfo
->start
[block_end
];
138 * Check footer CRC, the algorithm saves the inverse
139 * checksum as part of the summed words, and thus
140 * the result should be zero.
142 if (compute_crc(imginfo
+ 8, 0x88) != 0) {
143 printf("BAD CRC on ARM image info\n");
144 printf("(continuing anyway)\n");
148 for (j
= 0; j
< afi
->region_count
; j
++) {
149 afi
->regions
[j
].load_address
=
150 readl((void *)imginfo
+0x14 + j
*0x10);
151 afi
->regions
[j
].size
=
152 readl((void *)imginfo
+0x18 + j
*0x10);
153 afi
->regions
[j
].offset
=
154 readl((void *)imginfo
+0x1c + j
*0x10);
156 * At offset 0x20 + j*0x10 there is a region
157 * checksum which seems to be the running
158 * sum + 3, however since we anyway checksum
159 * the entire footer this is skipped over for
168 static void parse_flash(void)
172 /* We have already parsed the images in flash */
173 if (num_afs_images
> 0)
175 for (bank
= 0; bank
< CONFIG_SYS_MAX_FLASH_BANKS
; ++bank
)
179 static int load_image(const char * const name
, const ulong address
)
181 struct afs_image
*afi
= NULL
;
185 for (i
= 0; i
< num_afs_images
; i
++) {
186 struct afs_image
*tmp
= &afs_images
[i
];
188 if (!strcmp(tmp
->name
, name
)) {
194 printf("image \"%s\" not found in flash\n", name
);
195 return CMD_RET_FAILURE
;
198 for (i
= 0; i
< afi
->region_count
; i
++) {
201 from
= afi
->flash_mem_start
+ afi
->regions
[i
].offset
;
204 } else if (afi
->regions
[i
].load_address
) {
205 to
= afi
->regions
[i
].load_address
;
207 printf("no valid load address\n");
208 return CMD_RET_FAILURE
;
211 memcpy((void *)to
, (void *)from
, afi
->regions
[i
].size
);
213 printf("loaded region %d from %08lX to %08lX, %08X bytes\n",
217 afi
->regions
[i
].size
);
219 return CMD_RET_SUCCESS
;
222 static void print_images(void)
227 for (i
= 0; i
< num_afs_images
; i
++) {
228 struct afs_image
*afi
= &afs_images
[i
];
231 printf("Image: \"%s\" (v%d):\n", afi
->name
, afi
->version
);
232 printf(" Entry point: 0x%08X\n", afi
->entrypoint
);
233 printf(" Attributes: 0x%08X: ", afi
->attributes
);
234 if (afi
->attributes
== 0x01)
235 printf("ARM executable");
236 if (afi
->attributes
== 0x08)
237 printf("ARM backup");
239 printf(" Flash mem start: 0x%08lX\n",
240 afi
->flash_mem_start
);
241 printf(" Flash mem end: 0x%08lX\n",
243 for (j
= 0; j
< afi
->region_count
; j
++) {
244 printf(" region %d\n"
245 " load address: %08X\n"
249 afi
->regions
[j
].load_address
,
250 afi
->regions
[j
].size
,
251 afi
->regions
[j
].offset
);
256 static int exists(const char * const name
)
261 for (i
= 0; i
< num_afs_images
; i
++) {
262 struct afs_image
*afi
= &afs_images
[i
];
264 if (strcmp(afi
->name
, name
) == 0)
265 return CMD_RET_SUCCESS
;
267 return CMD_RET_FAILURE
;
270 static int do_afs(cmd_tbl_t
*cmdtp
, int flag
, int argc
, char * const argv
[])
272 int ret
= CMD_RET_SUCCESS
;
276 } else if (argc
== 3 && !strcmp(argv
[1], "exists")) {
277 ret
= exists(argv
[2]);
278 } else if (argc
== 3 && !strcmp(argv
[1], "load")) {
279 ret
= load_image(argv
[2], 0x0);
280 } else if (argc
== 4 && !strcmp(argv
[1], "load")) {
283 load_addr
= simple_strtoul(argv
[3], NULL
, 16);
284 ret
= load_image(argv
[2], load_addr
);
286 return CMD_RET_USAGE
;
292 U_BOOT_CMD(afs
, 4, 0, do_afs
, "show AFS partitions",
294 " - list images in flash\n"
296 " - returns 1 if an image exists, else 0\n"
298 " - load an image to the location indicated in the header\n"
299 "load <image> 0x<address>\n"
300 " - load an image to the location specified\n");