1 /* 2 * (C) Copyright 2014 3 * Andreas Bießmann <andreas@biessmann.org> 4 * 5 * SPDX-License-Identifier: GPL-2.0+ 6 */ 7 8 #include "imagetool.h" 9 #include "mkimage.h" 10 11 #include <image.h> 12 13 #define pr_err(fmt, args...) fprintf(stderr, "atmelimage Error: " fmt, ##args) 14 15 static int atmel_check_image_type(uint8_t type) 16 { 17 if (type == IH_TYPE_ATMELIMAGE) 18 return EXIT_SUCCESS; 19 else 20 return EXIT_FAILURE; 21 } 22 23 static uint32_t nand_pmecc_header[52]; 24 25 /* 26 * A helper struct for parsing the mkimage -n parameter 27 * 28 * Keep in same order as the configs array! 29 */ 30 static struct pmecc_config { 31 int use_pmecc; 32 int sector_per_page; 33 int spare_size; 34 int ecc_bits; 35 int sector_size; 36 int ecc_offset; 37 } pmecc; 38 39 /* 40 * Strings used for configure the PMECC header via -n mkimage switch 41 * 42 * We estimate a coma separated list of key=value pairs. The mkimage -n 43 * parameter argument should not contain any whitespace. 44 * 45 * Keep in same order as struct pmecc_config! 46 */ 47 static const char * const configs[] = { 48 "usePmecc", 49 "sectorPerPage", 50 "spareSize", 51 "eccBits", 52 "sectorSize", 53 "eccOffset" 54 }; 55 56 static int atmel_find_pmecc_parameter_in_token(const char *token) 57 { 58 size_t pos; 59 char *param; 60 61 debug("token: '%s'\n", token); 62 63 for (pos = 0; pos < ARRAY_SIZE(configs); pos++) { 64 if (strncmp(token, configs[pos], strlen(configs[pos])) == 0) { 65 param = strstr(token, "="); 66 if (!param) 67 goto err; 68 69 param++; 70 debug("\t%s parameter: '%s'\n", configs[pos], param); 71 72 switch (pos) { 73 case 0: 74 pmecc.use_pmecc = strtol(param, NULL, 10); 75 return EXIT_SUCCESS; 76 case 1: 77 pmecc.sector_per_page = strtol(param, NULL, 10); 78 return EXIT_SUCCESS; 79 case 2: 80 pmecc.spare_size = strtol(param, NULL, 10); 81 return EXIT_SUCCESS; 82 case 3: 83 pmecc.ecc_bits = strtol(param, NULL, 10); 84 return EXIT_SUCCESS; 85 case 4: 86 pmecc.sector_size = strtol(param, NULL, 10); 87 return EXIT_SUCCESS; 88 case 5: 89 pmecc.ecc_offset = strtol(param, NULL, 10); 90 return EXIT_SUCCESS; 91 } 92 } 93 } 94 95 err: 96 pr_err("Could not find parameter in token '%s'\n", token); 97 return EXIT_FAILURE; 98 } 99 100 static int atmel_parse_pmecc_params(char *txt) 101 { 102 char *token; 103 104 token = strtok(txt, ","); 105 while (token != NULL) { 106 if (atmel_find_pmecc_parameter_in_token(token)) 107 return EXIT_FAILURE; 108 109 token = strtok(NULL, ","); 110 } 111 112 return EXIT_SUCCESS; 113 } 114 115 static int atmel_verify_header(unsigned char *ptr, int image_size, 116 struct image_tool_params *params) 117 { 118 uint32_t *ints = (uint32_t *)ptr; 119 size_t pos; 120 size_t size = image_size; 121 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) 125 break; 126 127 if (pos == ARRAY_SIZE(nand_pmecc_header)) { 128 ints += ARRAY_SIZE(nand_pmecc_header); 129 size -= sizeof(nand_pmecc_header); 130 } 131 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, 135 ints[pos]); 136 /* 137 * all vectors except the 6'th one must contain valid 138 * LDR or B Opcode 139 */ 140 if (pos == 5) 141 /* 6'th vector has image size set, check later */ 142 continue; 143 if ((ints[pos] & 0xff000000) == 0xea000000) 144 /* valid B Opcode */ 145 continue; 146 if ((ints[pos] & 0xfffff000) == 0xe59ff000) 147 /* valid LDR (I=0, P=1, U=1, B=0, W=0, L=1) */ 148 continue; 149 /* ouch, one of the checks has missed ... */ 150 return 1; 151 } 152 153 return ints[5] != cpu_to_le32(size); 154 } 155 156 static void atmel_print_pmecc_header(const uint32_t word) 157 { 158 int val; 159 160 printf("\t\tPMECC header\n"); 161 162 printf("\t\t====================\n"); 163 164 val = (word >> 18) & 0x1ff; 165 printf("\t\teccOffset: %9i\n", val); 166 167 val = (((word >> 16) & 0x3) == 0) ? 512 : 1024; 168 printf("\t\tsectorSize: %8i\n", val); 169 170 if (((word >> 13) & 0x7) <= 2) 171 val = (2 << ((word >> 13) & 0x7)); 172 else 173 val = (12 << (((word >> 13) & 0x7) - 3)); 174 printf("\t\teccBitReq: %9i\n", val); 175 176 val = (word >> 4) & 0x1ff; 177 printf("\t\tspareSize: %9i\n", val); 178 179 val = (1 << ((word >> 1) & 0x3)); 180 printf("\t\tnbSectorPerPage: %3i\n", val); 181 182 printf("\t\tusePmecc: %10i\n", word & 0x1); 183 printf("\t\t====================\n"); 184 } 185 186 static void atmel_print_header(const void *ptr) 187 { 188 uint32_t *ints = (uint32_t *)ptr; 189 size_t pos; 190 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) 194 break; 195 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]); 199 pos += 5; 200 } else { 201 printf("Image Type:\tATMEL ROM-Boot Image without PMECC Header\n"); 202 pos = 5; 203 } 204 printf("\t\t6'th vector has %u set\n", le32_to_cpu(ints[pos])); 205 } 206 207 static void atmel_set_header(void *ptr, struct stat *sbuf, int ifd, 208 struct image_tool_params *params) 209 { 210 /* just save the image size into 6'th interrupt vector */ 211 uint32_t *ints = (uint32_t *)ptr; 212 size_t cnt; 213 size_t pos = 5; 214 size_t size = sbuf->st_size; 215 216 for (cnt = 0; cnt < ARRAY_SIZE(nand_pmecc_header); cnt++) 217 if (ints[cnt] >> 28 != 0xC) 218 break; 219 220 if (cnt == ARRAY_SIZE(nand_pmecc_header)) { 221 pos += ARRAY_SIZE(nand_pmecc_header); 222 size -= sizeof(nand_pmecc_header); 223 } 224 225 ints[pos] = cpu_to_le32(size); 226 } 227 228 static int atmel_check_params(struct image_tool_params *params) 229 { 230 if (strlen(params->imagename) > 0) 231 if (atmel_parse_pmecc_params(params->imagename)) 232 return EXIT_FAILURE; 233 234 return !(!params->eflag && 235 !params->fflag && 236 !params->xflag && 237 ((params->dflag && !params->lflag) || 238 (params->lflag && !params->dflag))); 239 } 240 241 static int atmel_vrec_header(struct image_tool_params *params, 242 struct image_type_params *tparams) 243 { 244 uint32_t tmp; 245 size_t pos; 246 247 if (strlen(params->imagename) == 0) 248 return EXIT_SUCCESS; 249 250 tmp = 0xC << 28; 251 252 tmp |= (pmecc.ecc_offset & 0x1ff) << 18; 253 254 switch (pmecc.sector_size) { 255 case 512: 256 tmp |= 0 << 16; 257 break; 258 case 1024: 259 tmp |= 1 << 16; 260 break; 261 262 default: 263 pr_err("Wrong sectorSize (%i) for PMECC header\n", 264 pmecc.sector_size); 265 return EXIT_FAILURE; 266 } 267 268 switch (pmecc.ecc_bits) { 269 case 2: 270 tmp |= 0 << 13; 271 break; 272 case 4: 273 tmp |= 1 << 13; 274 break; 275 case 8: 276 tmp |= 2 << 13; 277 break; 278 case 12: 279 tmp |= 3 << 13; 280 break; 281 case 24: 282 tmp |= 4 << 13; 283 break; 284 285 default: 286 pr_err("Wrong eccBits (%i) for PMECC header\n", 287 pmecc.ecc_bits); 288 return EXIT_FAILURE; 289 } 290 291 tmp |= (pmecc.spare_size & 0x1ff) << 4; 292 293 switch (pmecc.sector_per_page) { 294 case 1: 295 tmp |= 0 << 1; 296 break; 297 case 2: 298 tmp |= 1 << 1; 299 break; 300 case 4: 301 tmp |= 2 << 1; 302 break; 303 case 8: 304 tmp |= 3 << 1; 305 break; 306 307 default: 308 pr_err("Wrong sectorPerPage (%i) for PMECC header\n", 309 pmecc.sector_per_page); 310 return EXIT_FAILURE; 311 } 312 313 if (pmecc.use_pmecc) 314 tmp |= 1; 315 316 for (pos = 0; pos < ARRAY_SIZE(nand_pmecc_header); pos++) 317 nand_pmecc_header[pos] = tmp; 318 319 debug("PMECC header filled 52 times with 0x%08X\n", tmp); 320 321 tparams->header_size = sizeof(nand_pmecc_header); 322 tparams->hdr = nand_pmecc_header; 323 324 return EXIT_SUCCESS; 325 } 326 327 U_BOOT_IMAGE_TYPE( 328 atmelimage, 329 "ATMEL ROM-Boot Image support", 330 0, 331 NULL, 332 atmel_check_params, 333 atmel_verify_header, 334 atmel_print_header, 335 atmel_set_header, 336 NULL, 337 atmel_check_image_type, 338 NULL, 339 atmel_vrec_header 340 ); 341