atmelimage.c 7.0 KB

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