3 * Andreas Bießmann <andreas@biessmann.org>
5 * SPDX-License-Identifier: GPL-2.0+
13 #define pr_err(fmt, args...) fprintf(stderr, "atmelimage Error: " fmt, ##args)
15 static int atmel_check_image_type(uint8_t type)
17 if (type == IH_TYPE_ATMELIMAGE)
23 static uint32_t nand_pmecc_header[52];
26 * A helper struct for parsing the mkimage -n parameter
28 * Keep in same order as the configs array!
30 static struct pmecc_config {
40 * Strings used for configure the PMECC header via -n mkimage switch
42 * We estimate a coma separated list of key=value pairs. The mkimage -n
43 * parameter argument should not contain any whitespace.
45 * Keep in same order as struct pmecc_config!
47 static const char * const configs[] = {
56 static int atmel_find_pmecc_parameter_in_token(const char *token)
61 debug("token: '%s'\n", token);
63 for (pos = 0; pos < ARRAY_SIZE(configs); pos++) {
64 if (strncmp(token, configs[pos], strlen(configs[pos])) == 0) {
65 param = strstr(token, "=");
70 debug("\t%s parameter: '%s'\n", configs[pos], param);
74 pmecc.use_pmecc = strtol(param, NULL, 10);
77 pmecc.sector_per_page = strtol(param, NULL, 10);
80 pmecc.spare_size = strtol(param, NULL, 10);
83 pmecc.ecc_bits = strtol(param, NULL, 10);
86 pmecc.sector_size = strtol(param, NULL, 10);
89 pmecc.ecc_offset = strtol(param, NULL, 10);
96 pr_err("Could not find parameter in token '%s'\n", token);
100 static int atmel_parse_pmecc_params(char *txt)
104 token = strtok(txt, ",");
105 while (token != NULL) {
106 if (atmel_find_pmecc_parameter_in_token(token))
109 token = strtok(NULL, ",");
115 static int atmel_verify_header(unsigned char *ptr, int image_size,
116 struct image_tool_params *params)
118 uint32_t *ints = (uint32_t *)ptr;
120 size_t size = image_size;
122 /* check if we have an PMECC header attached */
123 for (pos = 0; pos < ARRAY_SIZE(nand_pmecc_header); pos++)
124 if (ints[pos] >> 28 != 0xC)
127 if (pos == ARRAY_SIZE(nand_pmecc_header)) {
128 ints += ARRAY_SIZE(nand_pmecc_header);
129 size -= sizeof(nand_pmecc_header);
132 /* check the seven interrupt vectors of binary */
133 for (pos = 0; pos < 7; pos++) {
134 debug("atmelimage: interrupt vector #%zu is 0x%08X\n", pos+1,
137 * all vectors except the 6'th one must contain valid
141 /* 6'th vector has image size set, check later */
143 if ((ints[pos] & 0xff000000) == 0xea000000)
146 if ((ints[pos] & 0xfffff000) == 0xe59ff000)
147 /* valid LDR (I=0, P=1, U=1, B=0, W=0, L=1) */
149 /* ouch, one of the checks has missed ... */
153 return ints[5] != cpu_to_le32(size);
156 static void atmel_print_pmecc_header(const uint32_t word)
160 printf("\t\tPMECC header\n");
162 printf("\t\t====================\n");
164 val = (word >> 18) & 0x1ff;
165 printf("\t\teccOffset: %9i\n", val);
167 val = (((word >> 16) & 0x3) == 0) ? 512 : 1024;
168 printf("\t\tsectorSize: %8i\n", val);
170 if (((word >> 13) & 0x7) <= 2)
171 val = (2 << ((word >> 13) & 0x7));
173 val = (12 << (((word >> 13) & 0x7) - 3));
174 printf("\t\teccBitReq: %9i\n", val);
176 val = (word >> 4) & 0x1ff;
177 printf("\t\tspareSize: %9i\n", val);
179 val = (1 << ((word >> 1) & 0x3));
180 printf("\t\tnbSectorPerPage: %3i\n", val);
182 printf("\t\tusePmecc: %10i\n", word & 0x1);
183 printf("\t\t====================\n");
186 static void atmel_print_header(const void *ptr)
188 uint32_t *ints = (uint32_t *)ptr;
191 /* check if we have an PMECC header attached */
192 for (pos = 0; pos < ARRAY_SIZE(nand_pmecc_header); pos++)
193 if (ints[pos] >> 28 != 0xC)
196 if (pos == ARRAY_SIZE(nand_pmecc_header)) {
197 printf("Image Type:\tATMEL ROM-Boot Image with PMECC Header\n");
198 atmel_print_pmecc_header(ints[0]);
201 printf("Image Type:\tATMEL ROM-Boot Image without PMECC Header\n");
204 printf("\t\t6'th vector has %u set\n", le32_to_cpu(ints[pos]));
207 static void atmel_set_header(void *ptr, struct stat *sbuf, int ifd,
208 struct image_tool_params *params)
210 /* just save the image size into 6'th interrupt vector */
211 uint32_t *ints = (uint32_t *)ptr;
214 size_t size = sbuf->st_size;
216 for (cnt = 0; cnt < ARRAY_SIZE(nand_pmecc_header); cnt++)
217 if (ints[cnt] >> 28 != 0xC)
220 if (cnt == ARRAY_SIZE(nand_pmecc_header)) {
221 pos += ARRAY_SIZE(nand_pmecc_header);
222 size -= sizeof(nand_pmecc_header);
225 ints[pos] = cpu_to_le32(size);
228 static int atmel_check_params(struct image_tool_params *params)
230 if (strlen(params->imagename) > 0)
231 if (atmel_parse_pmecc_params(params->imagename))
234 return !(!params->eflag &&
237 ((params->dflag && !params->lflag) ||
238 (params->lflag && !params->dflag)));
241 static int atmel_vrec_header(struct image_tool_params *params,
242 struct image_type_params *tparams)
247 if (strlen(params->imagename) == 0)
252 tmp |= (pmecc.ecc_offset & 0x1ff) << 18;
254 switch (pmecc.sector_size) {
263 pr_err("Wrong sectorSize (%i) for PMECC header\n",
268 switch (pmecc.ecc_bits) {
286 pr_err("Wrong eccBits (%i) for PMECC header\n",
291 tmp |= (pmecc.spare_size & 0x1ff) << 4;
293 switch (pmecc.sector_per_page) {
308 pr_err("Wrong sectorPerPage (%i) for PMECC header\n",
309 pmecc.sector_per_page);
316 for (pos = 0; pos < ARRAY_SIZE(nand_pmecc_header); pos++)
317 nand_pmecc_header[pos] = tmp;
319 debug("PMECC header filled 52 times with 0x%08X\n", tmp);
321 tparams->header_size = sizeof(nand_pmecc_header);
322 tparams->hdr = nand_pmecc_header;
329 "ATMEL ROM-Boot Image support",
337 atmel_check_image_type,