env_nand.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433
  1. /*
  2. * (C) Copyright 2000-2010
  3. * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
  4. *
  5. * (C) Copyright 2008
  6. * Stuart Wood, Lab X Technologies <stuart.wood@labxtechnologies.com>
  7. *
  8. * (C) Copyright 2004
  9. * Jian Zhang, Texas Instruments, jzhang@ti.com.
  10. *
  11. * (C) Copyright 2001 Sysgo Real-Time Solutions, GmbH <www.elinos.com>
  12. * Andreas Heppel <aheppel@sysgo.de>
  13. *
  14. * See file CREDITS for list of people who contributed to this
  15. * project.
  16. *
  17. * This program is free software; you can redistribute it and/or
  18. * modify it under the terms of the GNU General Public License as
  19. * published by the Free Software Foundation; either version 2 of
  20. * the License, or (at your option) any later version.
  21. *
  22. * This program is distributed in the hope that it will be useful,
  23. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  24. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  25. * GNU General Public License for more details.
  26. *
  27. * You should have received a copy of the GNU General Public License
  28. * along with this program; if not, write to the Free Software
  29. * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
  30. * MA 02111-1307 USA
  31. */
  32. #define DEBUG
  33. #include <common.h>
  34. #include <command.h>
  35. #include <environment.h>
  36. #include <linux/stddef.h>
  37. #include <malloc.h>
  38. #include <nand.h>
  39. #include <search.h>
  40. #include <errno.h>
  41. #if defined(CONFIG_CMD_SAVEENV) && defined(CONFIG_CMD_NAND)
  42. #define CMD_SAVEENV
  43. #elif defined(CONFIG_ENV_OFFSET_REDUND)
  44. #error CONFIG_ENV_OFFSET_REDUND must have CONFIG_CMD_SAVEENV & CONFIG_CMD_NAND
  45. #endif
  46. #if defined(CONFIG_ENV_SIZE_REDUND) && \
  47. (CONFIG_ENV_SIZE_REDUND != CONFIG_ENV_SIZE)
  48. #error CONFIG_ENV_SIZE_REDUND should be the same as CONFIG_ENV_SIZE
  49. #endif
  50. #ifndef CONFIG_ENV_RANGE
  51. #define CONFIG_ENV_RANGE CONFIG_ENV_SIZE
  52. #endif
  53. char *env_name_spec = "NAND";
  54. #if defined(ENV_IS_EMBEDDED)
  55. env_t *env_ptr = &environment;
  56. #elif defined(CONFIG_NAND_ENV_DST)
  57. env_t *env_ptr = (env_t *)CONFIG_NAND_ENV_DST;
  58. #else /* ! ENV_IS_EMBEDDED */
  59. env_t *env_ptr;
  60. #endif /* ENV_IS_EMBEDDED */
  61. DECLARE_GLOBAL_DATA_PTR;
  62. uchar env_get_char_spec(int index)
  63. {
  64. return *((uchar *)(gd->env_addr + index));
  65. }
  66. /*
  67. * This is called before nand_init() so we can't read NAND to
  68. * validate env data.
  69. *
  70. * Mark it OK for now. env_relocate() in env_common.c will call our
  71. * relocate function which does the real validation.
  72. *
  73. * When using a NAND boot image (like sequoia_nand), the environment
  74. * can be embedded or attached to the U-Boot image in NAND flash.
  75. * This way the SPL loads not only the U-Boot image from NAND but
  76. * also the environment.
  77. */
  78. int env_init(void)
  79. {
  80. #if defined(ENV_IS_EMBEDDED) || defined(CONFIG_NAND_ENV_DST)
  81. int crc1_ok = 0, crc2_ok = 0;
  82. env_t *tmp_env1;
  83. #ifdef CONFIG_ENV_OFFSET_REDUND
  84. env_t *tmp_env2;
  85. tmp_env2 = (env_t *)((ulong)env_ptr + CONFIG_ENV_SIZE);
  86. crc2_ok = crc32(0, tmp_env2->data, ENV_SIZE) == tmp_env2->crc;
  87. #endif
  88. tmp_env1 = env_ptr;
  89. crc1_ok = crc32(0, tmp_env1->data, ENV_SIZE) == tmp_env1->crc;
  90. if (!crc1_ok && !crc2_ok) {
  91. gd->env_addr = 0;
  92. gd->env_valid = 0;
  93. return 0;
  94. } else if (crc1_ok && !crc2_ok) {
  95. gd->env_valid = 1;
  96. }
  97. #ifdef CONFIG_ENV_OFFSET_REDUND
  98. else if (!crc1_ok && crc2_ok) {
  99. gd->env_valid = 2;
  100. } else {
  101. /* both ok - check serial */
  102. if (tmp_env1->flags == 255 && tmp_env2->flags == 0)
  103. gd->env_valid = 2;
  104. else if (tmp_env2->flags == 255 && tmp_env1->flags == 0)
  105. gd->env_valid = 1;
  106. else if (tmp_env1->flags > tmp_env2->flags)
  107. gd->env_valid = 1;
  108. else if (tmp_env2->flags > tmp_env1->flags)
  109. gd->env_valid = 2;
  110. else /* flags are equal - almost impossible */
  111. gd->env_valid = 1;
  112. }
  113. if (gd->env_valid == 2)
  114. env_ptr = tmp_env2;
  115. else
  116. #endif
  117. if (gd->env_valid == 1)
  118. env_ptr = tmp_env1;
  119. gd->env_addr = (ulong)env_ptr->data;
  120. #else /* ENV_IS_EMBEDDED || CONFIG_NAND_ENV_DST */
  121. gd->env_addr = (ulong)&default_environment[0];
  122. gd->env_valid = 1;
  123. #endif /* ENV_IS_EMBEDDED || CONFIG_NAND_ENV_DST */
  124. return 0;
  125. }
  126. #ifdef CMD_SAVEENV
  127. /*
  128. * The legacy NAND code saved the environment in the first NAND device i.e.,
  129. * nand_dev_desc + 0. This is also the behaviour using the new NAND code.
  130. */
  131. int writeenv(size_t offset, u_char *buf)
  132. {
  133. size_t end = offset + CONFIG_ENV_RANGE;
  134. size_t amount_saved = 0;
  135. size_t blocksize, len;
  136. u_char *char_ptr;
  137. blocksize = nand_info[0].erasesize;
  138. len = min(blocksize, CONFIG_ENV_SIZE);
  139. while (amount_saved < CONFIG_ENV_SIZE && offset < end) {
  140. if (nand_block_isbad(&nand_info[0], offset)) {
  141. offset += blocksize;
  142. } else {
  143. char_ptr = &buf[amount_saved];
  144. if (nand_write(&nand_info[0], offset, &len, char_ptr))
  145. return 1;
  146. offset += blocksize;
  147. amount_saved += len;
  148. }
  149. }
  150. if (amount_saved != CONFIG_ENV_SIZE)
  151. return 1;
  152. return 0;
  153. }
  154. #ifdef CONFIG_ENV_OFFSET_REDUND
  155. static unsigned char env_flags;
  156. int saveenv(void)
  157. {
  158. env_t env_new;
  159. ssize_t len;
  160. char *res;
  161. int ret = 0;
  162. nand_erase_options_t nand_erase_options;
  163. memset(&nand_erase_options, 0, sizeof(nand_erase_options));
  164. nand_erase_options.length = CONFIG_ENV_RANGE;
  165. if (CONFIG_ENV_RANGE < CONFIG_ENV_SIZE)
  166. return 1;
  167. res = (char *)&env_new.data;
  168. len = hexport_r(&env_htab, '\0', &res, ENV_SIZE, 0, NULL);
  169. if (len < 0) {
  170. error("Cannot export environment: errno = %d\n", errno);
  171. return 1;
  172. }
  173. env_new.crc = crc32(0, env_new.data, ENV_SIZE);
  174. env_new.flags = ++env_flags; /* increase the serial */
  175. if (gd->env_valid == 1) {
  176. puts("Erasing redundant NAND...\n");
  177. nand_erase_options.offset = CONFIG_ENV_OFFSET_REDUND;
  178. if (nand_erase_opts(&nand_info[0], &nand_erase_options))
  179. return 1;
  180. puts("Writing to redundant NAND... ");
  181. ret = writeenv(CONFIG_ENV_OFFSET_REDUND, (u_char *)&env_new);
  182. } else {
  183. puts("Erasing NAND...\n");
  184. nand_erase_options.offset = CONFIG_ENV_OFFSET;
  185. if (nand_erase_opts(&nand_info[0], &nand_erase_options))
  186. return 1;
  187. puts("Writing to NAND... ");
  188. ret = writeenv(CONFIG_ENV_OFFSET, (u_char *)&env_new);
  189. }
  190. if (ret) {
  191. puts("FAILED!\n");
  192. return 1;
  193. }
  194. puts("done\n");
  195. gd->env_valid = gd->env_valid == 2 ? 1 : 2;
  196. return ret;
  197. }
  198. #else /* ! CONFIG_ENV_OFFSET_REDUND */
  199. int saveenv(void)
  200. {
  201. int ret = 0;
  202. env_t env_new;
  203. ssize_t len;
  204. char *res;
  205. nand_erase_options_t nand_erase_options;
  206. memset(&nand_erase_options, 0, sizeof(nand_erase_options));
  207. nand_erase_options.length = CONFIG_ENV_RANGE;
  208. nand_erase_options.offset = CONFIG_ENV_OFFSET;
  209. if (CONFIG_ENV_RANGE < CONFIG_ENV_SIZE)
  210. return 1;
  211. res = (char *)&env_new.data;
  212. len = hexport_r(&env_htab, '\0', &res, ENV_SIZE, 0, NULL);
  213. if (len < 0) {
  214. error("Cannot export environment: errno = %d\n", errno);
  215. return 1;
  216. }
  217. env_new.crc = crc32(0, env_new.data, ENV_SIZE);
  218. puts("Erasing Nand...\n");
  219. if (nand_erase_opts(&nand_info[0], &nand_erase_options))
  220. return 1;
  221. puts("Writing to Nand... ");
  222. if (writeenv(CONFIG_ENV_OFFSET, (u_char *)&env_new)) {
  223. puts("FAILED!\n");
  224. return 1;
  225. }
  226. puts("done\n");
  227. return ret;
  228. }
  229. #endif /* CONFIG_ENV_OFFSET_REDUND */
  230. #endif /* CMD_SAVEENV */
  231. int readenv(size_t offset, u_char *buf)
  232. {
  233. size_t end = offset + CONFIG_ENV_RANGE;
  234. size_t amount_loaded = 0;
  235. size_t blocksize, len;
  236. u_char *char_ptr;
  237. blocksize = nand_info[0].erasesize;
  238. if (!blocksize)
  239. return 1;
  240. len = min(blocksize, CONFIG_ENV_SIZE);
  241. while (amount_loaded < CONFIG_ENV_SIZE && offset < end) {
  242. if (nand_block_isbad(&nand_info[0], offset)) {
  243. offset += blocksize;
  244. } else {
  245. char_ptr = &buf[amount_loaded];
  246. if (nand_read_skip_bad(&nand_info[0], offset,
  247. &len, char_ptr))
  248. return 1;
  249. offset += blocksize;
  250. amount_loaded += len;
  251. }
  252. }
  253. if (amount_loaded != CONFIG_ENV_SIZE)
  254. return 1;
  255. return 0;
  256. }
  257. #ifdef CONFIG_ENV_OFFSET_OOB
  258. int get_nand_env_oob(nand_info_t *nand, unsigned long *result)
  259. {
  260. struct mtd_oob_ops ops;
  261. uint32_t oob_buf[ENV_OFFSET_SIZE / sizeof(uint32_t)];
  262. int ret;
  263. ops.datbuf = NULL;
  264. ops.mode = MTD_OOB_AUTO;
  265. ops.ooboffs = 0;
  266. ops.ooblen = ENV_OFFSET_SIZE;
  267. ops.oobbuf = (void *)oob_buf;
  268. ret = nand->read_oob(nand, ENV_OFFSET_SIZE, &ops);
  269. if (ret) {
  270. printf("error reading OOB block 0\n");
  271. return ret;
  272. }
  273. if (oob_buf[0] == ENV_OOB_MARKER) {
  274. *result = oob_buf[1] * nand->erasesize;
  275. } else if (oob_buf[0] == ENV_OOB_MARKER_OLD) {
  276. *result = oob_buf[1];
  277. } else {
  278. printf("No dynamic environment marker in OOB block 0\n");
  279. return -ENOENT;
  280. }
  281. return 0;
  282. }
  283. #endif
  284. #ifdef CONFIG_ENV_OFFSET_REDUND
  285. void env_relocate_spec(void)
  286. {
  287. #if !defined(ENV_IS_EMBEDDED)
  288. int crc1_ok = 0, crc2_ok = 0;
  289. env_t *ep, *tmp_env1, *tmp_env2;
  290. tmp_env1 = (env_t *)malloc(CONFIG_ENV_SIZE);
  291. tmp_env2 = (env_t *)malloc(CONFIG_ENV_SIZE);
  292. if (tmp_env1 == NULL || tmp_env2 == NULL) {
  293. puts("Can't allocate buffers for environment\n");
  294. set_default_env("!malloc() failed");
  295. goto done;
  296. }
  297. if (readenv(CONFIG_ENV_OFFSET, (u_char *) tmp_env1))
  298. puts("No Valid Environment Area found\n");
  299. if (readenv(CONFIG_ENV_OFFSET_REDUND, (u_char *) tmp_env2))
  300. puts("No Valid Redundant Environment Area found\n");
  301. crc1_ok = crc32(0, tmp_env1->data, ENV_SIZE) == tmp_env1->crc;
  302. crc2_ok = crc32(0, tmp_env2->data, ENV_SIZE) == tmp_env2->crc;
  303. if (!crc1_ok && !crc2_ok) {
  304. set_default_env("!bad CRC");
  305. goto done;
  306. } else if (crc1_ok && !crc2_ok) {
  307. gd->env_valid = 1;
  308. } else if (!crc1_ok && crc2_ok) {
  309. gd->env_valid = 2;
  310. } else {
  311. /* both ok - check serial */
  312. if (tmp_env1->flags == 255 && tmp_env2->flags == 0)
  313. gd->env_valid = 2;
  314. else if (tmp_env2->flags == 255 && tmp_env1->flags == 0)
  315. gd->env_valid = 1;
  316. else if (tmp_env1->flags > tmp_env2->flags)
  317. gd->env_valid = 1;
  318. else if (tmp_env2->flags > tmp_env1->flags)
  319. gd->env_valid = 2;
  320. else /* flags are equal - almost impossible */
  321. gd->env_valid = 1;
  322. }
  323. free(env_ptr);
  324. if (gd->env_valid == 1)
  325. ep = tmp_env1;
  326. else
  327. ep = tmp_env2;
  328. env_flags = ep->flags;
  329. env_import((char *)ep, 0);
  330. done:
  331. free(tmp_env1);
  332. free(tmp_env2);
  333. #endif /* ! ENV_IS_EMBEDDED */
  334. }
  335. #else /* ! CONFIG_ENV_OFFSET_REDUND */
  336. /*
  337. * The legacy NAND code saved the environment in the first NAND
  338. * device i.e., nand_dev_desc + 0. This is also the behaviour using
  339. * the new NAND code.
  340. */
  341. void env_relocate_spec(void)
  342. {
  343. #if !defined(ENV_IS_EMBEDDED)
  344. int ret;
  345. char buf[CONFIG_ENV_SIZE];
  346. #if defined(CONFIG_ENV_OFFSET_OOB)
  347. ret = get_nand_env_oob(&nand_info[0], &nand_env_oob_offset);
  348. /*
  349. * If unable to read environment offset from NAND OOB then fall through
  350. * to the normal environment reading code below
  351. */
  352. if (!ret) {
  353. printf("Found Environment offset in OOB..\n");
  354. } else {
  355. set_default_env("!no env offset in OOB");
  356. return;
  357. }
  358. #endif
  359. ret = readenv(CONFIG_ENV_OFFSET, (u_char *)buf);
  360. if (ret) {
  361. set_default_env("!readenv() failed");
  362. return;
  363. }
  364. env_import(buf, 1);
  365. #endif /* ! ENV_IS_EMBEDDED */
  366. }
  367. #endif /* CONFIG_ENV_OFFSET_REDUND */