xref: /OK3568_Linux_fs/u-boot/cmd/armflash.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
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