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. #include <common.h>
  33. #include <command.h>
  34. #include <environment.h>
  35. #include <linux/stddef.h>
  36. #include <malloc.h>
  37. #include <nand.h>
  38. #include <search.h>
  39. #include <errno.h>
  40. #if defined(CONFIG_CMD_SAVEENV) && defined(CONFIG_CMD_NAND)
  41. #define CMD_SAVEENV
  42. #elif defined(CONFIG_ENV_OFFSET_REDUND)
  43. #error CONFIG_ENV_OFFSET_REDUND must have CONFIG_CMD_SAVEENV & CONFIG_CMD_NAND
  44. #endif
  45. #if defined(CONFIG_ENV_SIZE_REDUND) && \
  46. (CONFIG_ENV_SIZE_REDUND != CONFIG_ENV_SIZE)
  47. #error CONFIG_ENV_SIZE_REDUND should be the same as CONFIG_ENV_SIZE
  48. #endif
  49. #ifndef CONFIG_ENV_RANGE
  50. #define CONFIG_ENV_RANGE CONFIG_ENV_SIZE
  51. #endif
  52. char *env_name_spec = "NAND";
  53. #if defined(ENV_IS_EMBEDDED)
  54. env_t *env_ptr = &environment;
  55. #elif defined(CONFIG_NAND_ENV_DST)
  56. env_t *env_ptr = (env_t *)CONFIG_NAND_ENV_DST;
  57. #else /* ! ENV_IS_EMBEDDED */
  58. env_t *env_ptr;
  59. #endif /* ENV_IS_EMBEDDED */
  60. DECLARE_GLOBAL_DATA_PTR;
  61. /*
  62. * This is called before nand_init() so we can't read NAND to
  63. * validate env data.
  64. *
  65. * Mark it OK for now. env_relocate() in env_common.c will call our
  66. * relocate function which does the real validation.
  67. *
  68. * When using a NAND boot image (like sequoia_nand), the environment
  69. * can be embedded or attached to the U-Boot image in NAND flash.
  70. * This way the SPL loads not only the U-Boot image from NAND but
  71. * also the environment.
  72. */
  73. int env_init(void)
  74. {
  75. #if defined(ENV_IS_EMBEDDED) || defined(CONFIG_NAND_ENV_DST)
  76. int crc1_ok = 0, crc2_ok = 0;
  77. env_t *tmp_env1;
  78. #ifdef CONFIG_ENV_OFFSET_REDUND
  79. env_t *tmp_env2;
  80. tmp_env2 = (env_t *)((ulong)env_ptr + CONFIG_ENV_SIZE);
  81. crc2_ok = crc32(0, tmp_env2->data, ENV_SIZE) == tmp_env2->crc;
  82. #endif
  83. tmp_env1 = env_ptr;
  84. crc1_ok = crc32(0, tmp_env1->data, ENV_SIZE) == tmp_env1->crc;
  85. if (!crc1_ok && !crc2_ok) {
  86. gd->env_addr = 0;
  87. gd->env_valid = 0;
  88. return 0;
  89. } else if (crc1_ok && !crc2_ok) {
  90. gd->env_valid = 1;
  91. }
  92. #ifdef CONFIG_ENV_OFFSET_REDUND
  93. else if (!crc1_ok && crc2_ok) {
  94. gd->env_valid = 2;
  95. } else {
  96. /* both ok - check serial */
  97. if (tmp_env1->flags == 255 && tmp_env2->flags == 0)
  98. gd->env_valid = 2;
  99. else if (tmp_env2->flags == 255 && tmp_env1->flags == 0)
  100. gd->env_valid = 1;
  101. else if (tmp_env1->flags > tmp_env2->flags)
  102. gd->env_valid = 1;
  103. else if (tmp_env2->flags > tmp_env1->flags)
  104. gd->env_valid = 2;
  105. else /* flags are equal - almost impossible */
  106. gd->env_valid = 1;
  107. }
  108. if (gd->env_valid == 2)
  109. env_ptr = tmp_env2;
  110. else
  111. #endif
  112. if (gd->env_valid == 1)
  113. env_ptr = tmp_env1;
  114. gd->env_addr = (ulong)env_ptr->data;
  115. #else /* ENV_IS_EMBEDDED || CONFIG_NAND_ENV_DST */
  116. gd->env_addr = (ulong)&default_environment[0];
  117. gd->env_valid = 1;
  118. #endif /* ENV_IS_EMBEDDED || CONFIG_NAND_ENV_DST */
  119. return 0;
  120. }
  121. #ifdef CMD_SAVEENV
  122. /*
  123. * The legacy NAND code saved the environment in the first NAND device i.e.,
  124. * nand_dev_desc + 0. This is also the behaviour using the new NAND code.
  125. */
  126. int writeenv(size_t offset, u_char *buf)
  127. {
  128. size_t end = offset + CONFIG_ENV_RANGE;
  129. size_t amount_saved = 0;
  130. size_t blocksize, len;
  131. u_char *char_ptr;
  132. blocksize = nand_info[0].erasesize;
  133. len = min(blocksize, CONFIG_ENV_SIZE);
  134. while (amount_saved < CONFIG_ENV_SIZE && offset < end) {
  135. if (nand_block_isbad(&nand_info[0], offset)) {
  136. offset += blocksize;
  137. } else {
  138. char_ptr = &buf[amount_saved];
  139. if (nand_write(&nand_info[0], offset, &len, char_ptr))
  140. return 1;
  141. offset += blocksize;
  142. amount_saved += len;
  143. }
  144. }
  145. if (amount_saved != CONFIG_ENV_SIZE)
  146. return 1;
  147. return 0;
  148. }
  149. #ifdef CONFIG_ENV_OFFSET_REDUND
  150. static unsigned char env_flags;
  151. int saveenv(void)
  152. {
  153. env_t env_new;
  154. ssize_t len;
  155. char *res;
  156. int ret = 0;
  157. nand_erase_options_t nand_erase_options;
  158. memset(&nand_erase_options, 0, sizeof(nand_erase_options));
  159. nand_erase_options.length = CONFIG_ENV_RANGE;
  160. if (CONFIG_ENV_RANGE < CONFIG_ENV_SIZE)
  161. return 1;
  162. res = (char *)&env_new.data;
  163. len = hexport_r(&env_htab, '\0', 0, &res, ENV_SIZE, 0, NULL);
  164. if (len < 0) {
  165. error("Cannot export environment: errno = %d\n", errno);
  166. return 1;
  167. }
  168. env_new.crc = crc32(0, env_new.data, ENV_SIZE);
  169. env_new.flags = ++env_flags; /* increase the serial */
  170. if (gd->env_valid == 1) {
  171. puts("Erasing redundant NAND...\n");
  172. nand_erase_options.offset = CONFIG_ENV_OFFSET_REDUND;
  173. if (nand_erase_opts(&nand_info[0], &nand_erase_options))
  174. return 1;
  175. puts("Writing to redundant NAND... ");
  176. ret = writeenv(CONFIG_ENV_OFFSET_REDUND, (u_char *)&env_new);
  177. } else {
  178. puts("Erasing NAND...\n");
  179. nand_erase_options.offset = CONFIG_ENV_OFFSET;
  180. if (nand_erase_opts(&nand_info[0], &nand_erase_options))
  181. return 1;
  182. puts("Writing to NAND... ");
  183. ret = writeenv(CONFIG_ENV_OFFSET, (u_char *)&env_new);
  184. }
  185. if (ret) {
  186. puts("FAILED!\n");
  187. return 1;
  188. }
  189. puts("done\n");
  190. gd->env_valid = gd->env_valid == 2 ? 1 : 2;
  191. return ret;
  192. }
  193. #else /* ! CONFIG_ENV_OFFSET_REDUND */
  194. int saveenv(void)
  195. {
  196. int ret = 0;
  197. ALLOC_CACHE_ALIGN_BUFFER(env_t, env_new, 1);
  198. ssize_t len;
  199. char *res;
  200. nand_erase_options_t nand_erase_options;
  201. memset(&nand_erase_options, 0, sizeof(nand_erase_options));
  202. nand_erase_options.length = CONFIG_ENV_RANGE;
  203. nand_erase_options.offset = CONFIG_ENV_OFFSET;
  204. if (CONFIG_ENV_RANGE < CONFIG_ENV_SIZE)
  205. return 1;
  206. res = (char *)&env_new->data;
  207. len = hexport_r(&env_htab, '\0', 0, &res, ENV_SIZE, 0, NULL);
  208. if (len < 0) {
  209. error("Cannot export environment: errno = %d\n", errno);
  210. return 1;
  211. }
  212. env_new->crc = crc32(0, env_new->data, ENV_SIZE);
  213. puts("Erasing Nand...\n");
  214. if (nand_erase_opts(&nand_info[0], &nand_erase_options))
  215. return 1;
  216. puts("Writing to Nand... ");
  217. if (writeenv(CONFIG_ENV_OFFSET, (u_char *)env_new)) {
  218. puts("FAILED!\n");
  219. return 1;
  220. }
  221. puts("done\n");
  222. return ret;
  223. }
  224. #endif /* CONFIG_ENV_OFFSET_REDUND */
  225. #endif /* CMD_SAVEENV */
  226. int readenv(size_t offset, u_char *buf)
  227. {
  228. size_t end = offset + CONFIG_ENV_RANGE;
  229. size_t amount_loaded = 0;
  230. size_t blocksize, len;
  231. u_char *char_ptr;
  232. blocksize = nand_info[0].erasesize;
  233. if (!blocksize)
  234. return 1;
  235. len = min(blocksize, CONFIG_ENV_SIZE);
  236. while (amount_loaded < CONFIG_ENV_SIZE && offset < end) {
  237. if (nand_block_isbad(&nand_info[0], offset)) {
  238. offset += blocksize;
  239. } else {
  240. char_ptr = &buf[amount_loaded];
  241. if (nand_read_skip_bad(&nand_info[0], offset,
  242. &len, NULL,
  243. nand_info[0].size, char_ptr))
  244. return 1;
  245. offset += blocksize;
  246. amount_loaded += len;
  247. }
  248. }
  249. if (amount_loaded != CONFIG_ENV_SIZE)
  250. return 1;
  251. return 0;
  252. }
  253. #ifdef CONFIG_ENV_OFFSET_OOB
  254. int get_nand_env_oob(nand_info_t *nand, unsigned long *result)
  255. {
  256. struct mtd_oob_ops ops;
  257. uint32_t oob_buf[ENV_OFFSET_SIZE / sizeof(uint32_t)];
  258. int ret;
  259. ops.datbuf = NULL;
  260. ops.mode = MTD_OOB_AUTO;
  261. ops.ooboffs = 0;
  262. ops.ooblen = ENV_OFFSET_SIZE;
  263. ops.oobbuf = (void *)oob_buf;
  264. ret = nand->read_oob(nand, ENV_OFFSET_SIZE, &ops);
  265. if (ret) {
  266. printf("error reading OOB block 0\n");
  267. return ret;
  268. }
  269. if (oob_buf[0] == ENV_OOB_MARKER) {
  270. *result = oob_buf[1] * nand->erasesize;
  271. } else if (oob_buf[0] == ENV_OOB_MARKER_OLD) {
  272. *result = oob_buf[1];
  273. } else {
  274. printf("No dynamic environment marker in OOB block 0\n");
  275. return -ENOENT;
  276. }
  277. return 0;
  278. }
  279. #endif
  280. #ifdef CONFIG_ENV_OFFSET_REDUND
  281. void env_relocate_spec(void)
  282. {
  283. #if !defined(ENV_IS_EMBEDDED)
  284. int read1_fail = 0, read2_fail = 0;
  285. int crc1_ok = 0, crc2_ok = 0;
  286. env_t *ep, *tmp_env1, *tmp_env2;
  287. tmp_env1 = (env_t *)malloc(CONFIG_ENV_SIZE);
  288. tmp_env2 = (env_t *)malloc(CONFIG_ENV_SIZE);
  289. if (tmp_env1 == NULL || tmp_env2 == NULL) {
  290. puts("Can't allocate buffers for environment\n");
  291. set_default_env("!malloc() failed");
  292. goto done;
  293. }
  294. read1_fail = readenv(CONFIG_ENV_OFFSET, (u_char *) tmp_env1);
  295. read2_fail = readenv(CONFIG_ENV_OFFSET_REDUND, (u_char *) tmp_env2);
  296. if (read1_fail && read2_fail)
  297. puts("*** Error - No Valid Environment Area found\n");
  298. else if (read1_fail || read2_fail)
  299. puts("*** Warning - some problems detected "
  300. "reading environment; recovered successfully\n");
  301. crc1_ok = !read1_fail &&
  302. (crc32(0, tmp_env1->data, ENV_SIZE) == tmp_env1->crc);
  303. crc2_ok = !read2_fail &&
  304. (crc32(0, tmp_env2->data, ENV_SIZE) == tmp_env2->crc);
  305. if (!crc1_ok && !crc2_ok) {
  306. set_default_env("!bad CRC");
  307. goto done;
  308. } else if (crc1_ok && !crc2_ok) {
  309. gd->env_valid = 1;
  310. } else if (!crc1_ok && crc2_ok) {
  311. gd->env_valid = 2;
  312. } else {
  313. /* both ok - check serial */
  314. if (tmp_env1->flags == 255 && tmp_env2->flags == 0)
  315. gd->env_valid = 2;
  316. else if (tmp_env2->flags == 255 && tmp_env1->flags == 0)
  317. gd->env_valid = 1;
  318. else if (tmp_env1->flags > tmp_env2->flags)
  319. gd->env_valid = 1;
  320. else if (tmp_env2->flags > tmp_env1->flags)
  321. gd->env_valid = 2;
  322. else /* flags are equal - almost impossible */
  323. gd->env_valid = 1;
  324. }
  325. free(env_ptr);
  326. if (gd->env_valid == 1)
  327. ep = tmp_env1;
  328. else
  329. ep = tmp_env2;
  330. env_flags = ep->flags;
  331. env_import((char *)ep, 0);
  332. done:
  333. free(tmp_env1);
  334. free(tmp_env2);
  335. #endif /* ! ENV_IS_EMBEDDED */
  336. }
  337. #else /* ! CONFIG_ENV_OFFSET_REDUND */
  338. /*
  339. * The legacy NAND code saved the environment in the first NAND
  340. * device i.e., nand_dev_desc + 0. This is also the behaviour using
  341. * the new NAND code.
  342. */
  343. void env_relocate_spec(void)
  344. {
  345. #if !defined(ENV_IS_EMBEDDED)
  346. int ret;
  347. ALLOC_CACHE_ALIGN_BUFFER(char, buf, CONFIG_ENV_SIZE);
  348. #if defined(CONFIG_ENV_OFFSET_OOB)
  349. ret = get_nand_env_oob(&nand_info[0], &nand_env_oob_offset);
  350. /*
  351. * If unable to read environment offset from NAND OOB then fall through
  352. * to the normal environment reading code below
  353. */
  354. if (!ret) {
  355. printf("Found Environment offset in OOB..\n");
  356. } else {
  357. set_default_env("!no env offset in OOB");
  358. return;
  359. }
  360. #endif
  361. ret = readenv(CONFIG_ENV_OFFSET, (u_char *)buf);
  362. if (ret) {
  363. set_default_env("!readenv() failed");
  364. return;
  365. }
  366. env_import(buf, 1);
  367. #endif /* ! ENV_IS_EMBEDDED */
  368. }
  369. #endif /* CONFIG_ENV_OFFSET_REDUND */