1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun * (C) Copyright 2015
3*4882a593Smuzhiyun * Linus Walleij, Linaro
4*4882a593Smuzhiyun *
5*4882a593Smuzhiyun * Support for ARM Flash Partitions
6*4882a593Smuzhiyun *
7*4882a593Smuzhiyun * SPDX-License-Identifier: GPL-2.0+
8*4882a593Smuzhiyun */
9*4882a593Smuzhiyun #include <common.h>
10*4882a593Smuzhiyun #include <command.h>
11*4882a593Smuzhiyun #include <console.h>
12*4882a593Smuzhiyun #include <asm/io.h>
13*4882a593Smuzhiyun
14*4882a593Smuzhiyun #define MAX_REGIONS 4
15*4882a593Smuzhiyun #define MAX_IMAGES 32
16*4882a593Smuzhiyun
17*4882a593Smuzhiyun struct afs_region {
18*4882a593Smuzhiyun u32 load_address;
19*4882a593Smuzhiyun u32 size;
20*4882a593Smuzhiyun u32 offset;
21*4882a593Smuzhiyun };
22*4882a593Smuzhiyun
23*4882a593Smuzhiyun struct afs_image {
24*4882a593Smuzhiyun flash_info_t *flinfo;
25*4882a593Smuzhiyun const char *name;
26*4882a593Smuzhiyun u32 version;
27*4882a593Smuzhiyun u32 entrypoint;
28*4882a593Smuzhiyun u32 attributes;
29*4882a593Smuzhiyun u32 region_count;
30*4882a593Smuzhiyun struct afs_region regions[MAX_REGIONS];
31*4882a593Smuzhiyun ulong flash_mem_start;
32*4882a593Smuzhiyun ulong flash_mem_end;
33*4882a593Smuzhiyun };
34*4882a593Smuzhiyun
35*4882a593Smuzhiyun static struct afs_image afs_images[MAX_IMAGES];
36*4882a593Smuzhiyun static int num_afs_images;
37*4882a593Smuzhiyun
compute_crc(ulong start,u32 len)38*4882a593Smuzhiyun static u32 compute_crc(ulong start, u32 len)
39*4882a593Smuzhiyun {
40*4882a593Smuzhiyun u32 sum = 0;
41*4882a593Smuzhiyun int i;
42*4882a593Smuzhiyun
43*4882a593Smuzhiyun if (len % 4 != 0) {
44*4882a593Smuzhiyun printf("bad checksumming\n");
45*4882a593Smuzhiyun return 0;
46*4882a593Smuzhiyun }
47*4882a593Smuzhiyun
48*4882a593Smuzhiyun for (i = 0; i < len; i += 4) {
49*4882a593Smuzhiyun u32 val;
50*4882a593Smuzhiyun
51*4882a593Smuzhiyun val = readl((void *)start + i);
52*4882a593Smuzhiyun if (val > ~sum)
53*4882a593Smuzhiyun sum++;
54*4882a593Smuzhiyun sum += val;
55*4882a593Smuzhiyun }
56*4882a593Smuzhiyun return ~sum;
57*4882a593Smuzhiyun }
58*4882a593Smuzhiyun
parse_bank(ulong bank)59*4882a593Smuzhiyun static void parse_bank(ulong bank)
60*4882a593Smuzhiyun {
61*4882a593Smuzhiyun int i;
62*4882a593Smuzhiyun ulong flstart, flend;
63*4882a593Smuzhiyun flash_info_t *info;
64*4882a593Smuzhiyun
65*4882a593Smuzhiyun info = &flash_info[bank];
66*4882a593Smuzhiyun if (info->flash_id != FLASH_MAN_CFI) {
67*4882a593Smuzhiyun printf("Bank %lu: missing or unknown FLASH type\n", bank);
68*4882a593Smuzhiyun return;
69*4882a593Smuzhiyun }
70*4882a593Smuzhiyun if (!info->sector_count) {
71*4882a593Smuzhiyun printf("Bank %lu: no FLASH sectors\n", bank);
72*4882a593Smuzhiyun return;
73*4882a593Smuzhiyun }
74*4882a593Smuzhiyun
75*4882a593Smuzhiyun flstart = info->start[0];
76*4882a593Smuzhiyun flend = flstart + info->size;
77*4882a593Smuzhiyun
78*4882a593Smuzhiyun for (i = 0; i < info->sector_count; ++i) {
79*4882a593Smuzhiyun ulong secend;
80*4882a593Smuzhiyun u32 foot1, foot2;
81*4882a593Smuzhiyun
82*4882a593Smuzhiyun if (ctrlc())
83*4882a593Smuzhiyun break;
84*4882a593Smuzhiyun
85*4882a593Smuzhiyun if (i == info->sector_count-1)
86*4882a593Smuzhiyun secend = flend;
87*4882a593Smuzhiyun else
88*4882a593Smuzhiyun secend = info->start[i+1];
89*4882a593Smuzhiyun
90*4882a593Smuzhiyun /* Check for v1 header */
91*4882a593Smuzhiyun foot1 = readl((void *)secend - 0x0c);
92*4882a593Smuzhiyun if (foot1 == 0xA0FFFF9FU) {
93*4882a593Smuzhiyun struct afs_image *afi = &afs_images[num_afs_images];
94*4882a593Smuzhiyun ulong imginfo;
95*4882a593Smuzhiyun
96*4882a593Smuzhiyun afi->flinfo = info;
97*4882a593Smuzhiyun afi->version = 1;
98*4882a593Smuzhiyun afi->flash_mem_start = readl((void *)secend - 0x10);
99*4882a593Smuzhiyun afi->flash_mem_end = readl((void *)secend - 0x14);
100*4882a593Smuzhiyun afi->attributes = readl((void *)secend - 0x08);
101*4882a593Smuzhiyun /* Adjust to even address */
102*4882a593Smuzhiyun imginfo = afi->flash_mem_end + afi->flash_mem_end % 4;
103*4882a593Smuzhiyun /* Record as a single region */
104*4882a593Smuzhiyun afi->region_count = 1;
105*4882a593Smuzhiyun afi->regions[0].offset = readl((void *)imginfo + 0x04);
106*4882a593Smuzhiyun afi->regions[0].load_address =
107*4882a593Smuzhiyun readl((void *)imginfo + 0x08);
108*4882a593Smuzhiyun afi->regions[0].size = readl((void *)imginfo + 0x0C);
109*4882a593Smuzhiyun afi->entrypoint = readl((void *)imginfo + 0x10);
110*4882a593Smuzhiyun afi->name = (const char *)imginfo + 0x14;
111*4882a593Smuzhiyun num_afs_images++;
112*4882a593Smuzhiyun }
113*4882a593Smuzhiyun
114*4882a593Smuzhiyun /* Check for v2 header */
115*4882a593Smuzhiyun foot1 = readl((void *)secend - 0x04);
116*4882a593Smuzhiyun foot2 = readl((void *)secend - 0x08);
117*4882a593Smuzhiyun /* This makes up the string "HSLFTOOF" flash footer */
118*4882a593Smuzhiyun if (foot1 == 0x464F4F54U && foot2 == 0x464C5348U) {
119*4882a593Smuzhiyun struct afs_image *afi = &afs_images[num_afs_images];
120*4882a593Smuzhiyun ulong imginfo;
121*4882a593Smuzhiyun u32 block_start, block_end;
122*4882a593Smuzhiyun int j;
123*4882a593Smuzhiyun
124*4882a593Smuzhiyun afi->flinfo = info;
125*4882a593Smuzhiyun afi->version = readl((void *)secend - 0x0c);
126*4882a593Smuzhiyun imginfo = secend - 0x30 - readl((void *)secend - 0x10);
127*4882a593Smuzhiyun afi->name = (const char *)secend - 0x30;
128*4882a593Smuzhiyun
129*4882a593Smuzhiyun afi->entrypoint = readl((void *)imginfo+0x08);
130*4882a593Smuzhiyun afi->attributes = readl((void *)imginfo+0x0c);
131*4882a593Smuzhiyun afi->region_count = readl((void *)imginfo+0x10);
132*4882a593Smuzhiyun block_start = readl((void *)imginfo+0x54);
133*4882a593Smuzhiyun block_end = readl((void *)imginfo+0x58);
134*4882a593Smuzhiyun afi->flash_mem_start = afi->flinfo->start[block_start];
135*4882a593Smuzhiyun afi->flash_mem_end = afi->flinfo->start[block_end];
136*4882a593Smuzhiyun
137*4882a593Smuzhiyun /*
138*4882a593Smuzhiyun * Check footer CRC, the algorithm saves the inverse
139*4882a593Smuzhiyun * checksum as part of the summed words, and thus
140*4882a593Smuzhiyun * the result should be zero.
141*4882a593Smuzhiyun */
142*4882a593Smuzhiyun if (compute_crc(imginfo + 8, 0x88) != 0) {
143*4882a593Smuzhiyun printf("BAD CRC on ARM image info\n");
144*4882a593Smuzhiyun printf("(continuing anyway)\n");
145*4882a593Smuzhiyun }
146*4882a593Smuzhiyun
147*4882a593Smuzhiyun /* Parse regions */
148*4882a593Smuzhiyun for (j = 0; j < afi->region_count; j++) {
149*4882a593Smuzhiyun afi->regions[j].load_address =
150*4882a593Smuzhiyun readl((void *)imginfo+0x14 + j*0x10);
151*4882a593Smuzhiyun afi->regions[j].size =
152*4882a593Smuzhiyun readl((void *)imginfo+0x18 + j*0x10);
153*4882a593Smuzhiyun afi->regions[j].offset =
154*4882a593Smuzhiyun readl((void *)imginfo+0x1c + j*0x10);
155*4882a593Smuzhiyun /*
156*4882a593Smuzhiyun * At offset 0x20 + j*0x10 there is a region
157*4882a593Smuzhiyun * checksum which seems to be the running
158*4882a593Smuzhiyun * sum + 3, however since we anyway checksum
159*4882a593Smuzhiyun * the entire footer this is skipped over for
160*4882a593Smuzhiyun * checking here.
161*4882a593Smuzhiyun */
162*4882a593Smuzhiyun }
163*4882a593Smuzhiyun num_afs_images++;
164*4882a593Smuzhiyun }
165*4882a593Smuzhiyun }
166*4882a593Smuzhiyun }
167*4882a593Smuzhiyun
parse_flash(void)168*4882a593Smuzhiyun static void parse_flash(void)
169*4882a593Smuzhiyun {
170*4882a593Smuzhiyun ulong bank;
171*4882a593Smuzhiyun
172*4882a593Smuzhiyun /* We have already parsed the images in flash */
173*4882a593Smuzhiyun if (num_afs_images > 0)
174*4882a593Smuzhiyun return;
175*4882a593Smuzhiyun for (bank = 0; bank < CONFIG_SYS_MAX_FLASH_BANKS; ++bank)
176*4882a593Smuzhiyun parse_bank(bank);
177*4882a593Smuzhiyun }
178*4882a593Smuzhiyun
load_image(const char * const name,const ulong address)179*4882a593Smuzhiyun static int load_image(const char * const name, const ulong address)
180*4882a593Smuzhiyun {
181*4882a593Smuzhiyun struct afs_image *afi = NULL;
182*4882a593Smuzhiyun int i;
183*4882a593Smuzhiyun
184*4882a593Smuzhiyun parse_flash();
185*4882a593Smuzhiyun for (i = 0; i < num_afs_images; i++) {
186*4882a593Smuzhiyun struct afs_image *tmp = &afs_images[i];
187*4882a593Smuzhiyun
188*4882a593Smuzhiyun if (!strcmp(tmp->name, name)) {
189*4882a593Smuzhiyun afi = tmp;
190*4882a593Smuzhiyun break;
191*4882a593Smuzhiyun }
192*4882a593Smuzhiyun }
193*4882a593Smuzhiyun if (!afi) {
194*4882a593Smuzhiyun printf("image \"%s\" not found in flash\n", name);
195*4882a593Smuzhiyun return CMD_RET_FAILURE;
196*4882a593Smuzhiyun }
197*4882a593Smuzhiyun
198*4882a593Smuzhiyun for (i = 0; i < afi->region_count; i++) {
199*4882a593Smuzhiyun ulong from, to;
200*4882a593Smuzhiyun
201*4882a593Smuzhiyun from = afi->flash_mem_start + afi->regions[i].offset;
202*4882a593Smuzhiyun if (address) {
203*4882a593Smuzhiyun to = address;
204*4882a593Smuzhiyun } else if (afi->regions[i].load_address) {
205*4882a593Smuzhiyun to = afi->regions[i].load_address;
206*4882a593Smuzhiyun } else {
207*4882a593Smuzhiyun printf("no valid load address\n");
208*4882a593Smuzhiyun return CMD_RET_FAILURE;
209*4882a593Smuzhiyun }
210*4882a593Smuzhiyun
211*4882a593Smuzhiyun memcpy((void *)to, (void *)from, afi->regions[i].size);
212*4882a593Smuzhiyun
213*4882a593Smuzhiyun printf("loaded region %d from %08lX to %08lX, %08X bytes\n",
214*4882a593Smuzhiyun i,
215*4882a593Smuzhiyun from,
216*4882a593Smuzhiyun to,
217*4882a593Smuzhiyun afi->regions[i].size);
218*4882a593Smuzhiyun }
219*4882a593Smuzhiyun return CMD_RET_SUCCESS;
220*4882a593Smuzhiyun }
221*4882a593Smuzhiyun
print_images(void)222*4882a593Smuzhiyun static void print_images(void)
223*4882a593Smuzhiyun {
224*4882a593Smuzhiyun int i;
225*4882a593Smuzhiyun
226*4882a593Smuzhiyun parse_flash();
227*4882a593Smuzhiyun for (i = 0; i < num_afs_images; i++) {
228*4882a593Smuzhiyun struct afs_image *afi = &afs_images[i];
229*4882a593Smuzhiyun int j;
230*4882a593Smuzhiyun
231*4882a593Smuzhiyun printf("Image: \"%s\" (v%d):\n", afi->name, afi->version);
232*4882a593Smuzhiyun printf(" Entry point: 0x%08X\n", afi->entrypoint);
233*4882a593Smuzhiyun printf(" Attributes: 0x%08X: ", afi->attributes);
234*4882a593Smuzhiyun if (afi->attributes == 0x01)
235*4882a593Smuzhiyun printf("ARM executable");
236*4882a593Smuzhiyun if (afi->attributes == 0x08)
237*4882a593Smuzhiyun printf("ARM backup");
238*4882a593Smuzhiyun printf("\n");
239*4882a593Smuzhiyun printf(" Flash mem start: 0x%08lX\n",
240*4882a593Smuzhiyun afi->flash_mem_start);
241*4882a593Smuzhiyun printf(" Flash mem end: 0x%08lX\n",
242*4882a593Smuzhiyun afi->flash_mem_end);
243*4882a593Smuzhiyun for (j = 0; j < afi->region_count; j++) {
244*4882a593Smuzhiyun printf(" region %d\n"
245*4882a593Smuzhiyun " load address: %08X\n"
246*4882a593Smuzhiyun " size: %08X\n"
247*4882a593Smuzhiyun " offset: %08X\n",
248*4882a593Smuzhiyun j,
249*4882a593Smuzhiyun afi->regions[j].load_address,
250*4882a593Smuzhiyun afi->regions[j].size,
251*4882a593Smuzhiyun afi->regions[j].offset);
252*4882a593Smuzhiyun }
253*4882a593Smuzhiyun }
254*4882a593Smuzhiyun }
255*4882a593Smuzhiyun
exists(const char * const name)256*4882a593Smuzhiyun static int exists(const char * const name)
257*4882a593Smuzhiyun {
258*4882a593Smuzhiyun int i;
259*4882a593Smuzhiyun
260*4882a593Smuzhiyun parse_flash();
261*4882a593Smuzhiyun for (i = 0; i < num_afs_images; i++) {
262*4882a593Smuzhiyun struct afs_image *afi = &afs_images[i];
263*4882a593Smuzhiyun
264*4882a593Smuzhiyun if (strcmp(afi->name, name) == 0)
265*4882a593Smuzhiyun return CMD_RET_SUCCESS;
266*4882a593Smuzhiyun }
267*4882a593Smuzhiyun return CMD_RET_FAILURE;
268*4882a593Smuzhiyun }
269*4882a593Smuzhiyun
do_afs(cmd_tbl_t * cmdtp,int flag,int argc,char * const argv[])270*4882a593Smuzhiyun static int do_afs(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
271*4882a593Smuzhiyun {
272*4882a593Smuzhiyun int ret = CMD_RET_SUCCESS;
273*4882a593Smuzhiyun
274*4882a593Smuzhiyun if (argc == 1) {
275*4882a593Smuzhiyun print_images();
276*4882a593Smuzhiyun } else if (argc == 3 && !strcmp(argv[1], "exists")) {
277*4882a593Smuzhiyun ret = exists(argv[2]);
278*4882a593Smuzhiyun } else if (argc == 3 && !strcmp(argv[1], "load")) {
279*4882a593Smuzhiyun ret = load_image(argv[2], 0x0);
280*4882a593Smuzhiyun } else if (argc == 4 && !strcmp(argv[1], "load")) {
281*4882a593Smuzhiyun ulong load_addr;
282*4882a593Smuzhiyun
283*4882a593Smuzhiyun load_addr = simple_strtoul(argv[3], NULL, 16);
284*4882a593Smuzhiyun ret = load_image(argv[2], load_addr);
285*4882a593Smuzhiyun } else {
286*4882a593Smuzhiyun return CMD_RET_USAGE;
287*4882a593Smuzhiyun }
288*4882a593Smuzhiyun
289*4882a593Smuzhiyun return ret;
290*4882a593Smuzhiyun }
291*4882a593Smuzhiyun
292*4882a593Smuzhiyun U_BOOT_CMD(afs, 4, 0, do_afs, "show AFS partitions",
293*4882a593Smuzhiyun "no arguments\n"
294*4882a593Smuzhiyun " - list images in flash\n"
295*4882a593Smuzhiyun "exists <image>\n"
296*4882a593Smuzhiyun " - returns 1 if an image exists, else 0\n"
297*4882a593Smuzhiyun "load <image>\n"
298*4882a593Smuzhiyun " - load an image to the location indicated in the header\n"
299*4882a593Smuzhiyun "load <image> 0x<address>\n"
300*4882a593Smuzhiyun " - load an image to the location specified\n");
301