3 * Andreas Bießmann <andreas.devel@googlemail.com>
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 #%d 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
;
327 static struct image_type_params atmelimage_params
= {
328 .name
= "ATMEL ROM-Boot Image support",
331 .check_image_type
= atmel_check_image_type
,
332 .verify_header
= atmel_verify_header
,
333 .print_header
= atmel_print_header
,
334 .set_header
= atmel_set_header
,
335 .check_params
= atmel_check_params
,
336 .vrec_header
= atmel_vrec_header
,
339 void init_atmel_image_type(void)
341 register_image_type(&atmelimage_params
);