env_nand.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441
  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 Cannot use CONFIG_ENV_OFFSET_REDUND without CONFIG_CMD_SAVEENV & CONFIG_CMD_NAND
  45. #endif
  46. #if defined(CONFIG_ENV_SIZE_REDUND) && (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. extern uchar environment[];
  55. env_t *env_ptr = (env_t *)(&environment[0]);
  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 = 0;
  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,
  145. char_ptr))
  146. return 1;
  147. offset += blocksize;
  148. amount_saved += len;
  149. }
  150. }
  151. if (amount_saved != CONFIG_ENV_SIZE)
  152. return 1;
  153. return 0;
  154. }
  155. #ifdef CONFIG_ENV_OFFSET_REDUND
  156. static unsigned char env_flags;
  157. int saveenv(void)
  158. {
  159. env_t env_new;
  160. ssize_t len;
  161. char *res;
  162. int ret = 0;
  163. nand_erase_options_t nand_erase_options;
  164. memset(&nand_erase_options, 0, sizeof(nand_erase_options));
  165. nand_erase_options.length = CONFIG_ENV_RANGE;
  166. if (CONFIG_ENV_RANGE < CONFIG_ENV_SIZE)
  167. return 1;
  168. res = (char *)&env_new.data;
  169. len = hexport_r(&env_htab, '\0', &res, ENV_SIZE, 0, NULL);
  170. if (len < 0) {
  171. error("Cannot export environment: errno = %d\n", errno);
  172. return 1;
  173. }
  174. env_new.crc = crc32(0, env_new.data, ENV_SIZE);
  175. env_new.flags = ++env_flags; /* increase the serial */
  176. if(gd->env_valid == 1) {
  177. puts("Erasing redundant NAND...\n");
  178. nand_erase_options.offset = CONFIG_ENV_OFFSET_REDUND;
  179. if (nand_erase_opts(&nand_info[0], &nand_erase_options))
  180. return 1;
  181. puts("Writing to redundant NAND... ");
  182. ret = writeenv(CONFIG_ENV_OFFSET_REDUND,
  183. (u_char *)&env_new);
  184. } else {
  185. puts("Erasing NAND...\n");
  186. nand_erase_options.offset = CONFIG_ENV_OFFSET;
  187. if (nand_erase_opts(&nand_info[0], &nand_erase_options))
  188. return 1;
  189. puts("Writing to NAND... ");
  190. ret = writeenv(CONFIG_ENV_OFFSET,
  191. (u_char *)&env_new);
  192. }
  193. if (ret) {
  194. puts("FAILED!\n");
  195. return 1;
  196. }
  197. puts("done\n");
  198. gd->env_valid = (gd->env_valid == 2 ? 1 : 2);
  199. return ret;
  200. }
  201. #else /* ! CONFIG_ENV_OFFSET_REDUND */
  202. int saveenv(void)
  203. {
  204. int ret = 0;
  205. env_t env_new;
  206. ssize_t len;
  207. char *res;
  208. nand_erase_options_t nand_erase_options;
  209. memset(&nand_erase_options, 0, sizeof(nand_erase_options));
  210. nand_erase_options.length = CONFIG_ENV_RANGE;
  211. nand_erase_options.offset = CONFIG_ENV_OFFSET;
  212. if (CONFIG_ENV_RANGE < CONFIG_ENV_SIZE)
  213. return 1;
  214. res = (char *)&env_new.data;
  215. len = hexport_r(&env_htab, '\0', &res, ENV_SIZE, 0, NULL);
  216. if (len < 0) {
  217. error("Cannot export environment: errno = %d\n", errno);
  218. return 1;
  219. }
  220. env_new.crc = crc32(0, env_new.data, ENV_SIZE);
  221. puts("Erasing Nand...\n");
  222. if (nand_erase_opts(&nand_info[0], &nand_erase_options))
  223. return 1;
  224. puts("Writing to Nand... ");
  225. if (writeenv(CONFIG_ENV_OFFSET, (u_char *)&env_new)) {
  226. puts("FAILED!\n");
  227. return 1;
  228. }
  229. puts("done\n");
  230. return ret;
  231. }
  232. #endif /* CONFIG_ENV_OFFSET_REDUND */
  233. #endif /* CMD_SAVEENV */
  234. int readenv(size_t offset, u_char * buf)
  235. {
  236. size_t end = offset + CONFIG_ENV_RANGE;
  237. size_t amount_loaded = 0;
  238. size_t blocksize, len;
  239. u_char *char_ptr;
  240. blocksize = nand_info[0].erasesize;
  241. if (!blocksize)
  242. return 1;
  243. len = min(blocksize, CONFIG_ENV_SIZE);
  244. while (amount_loaded < CONFIG_ENV_SIZE && offset < end) {
  245. if (nand_block_isbad(&nand_info[0], offset)) {
  246. offset += blocksize;
  247. } else {
  248. char_ptr = &buf[amount_loaded];
  249. if (nand_read_skip_bad(&nand_info[0], offset, &len, char_ptr))
  250. return 1;
  251. offset += blocksize;
  252. amount_loaded += len;
  253. }
  254. }
  255. if (amount_loaded != CONFIG_ENV_SIZE)
  256. return 1;
  257. return 0;
  258. }
  259. #ifdef CONFIG_ENV_OFFSET_OOB
  260. int get_nand_env_oob(nand_info_t *nand, unsigned long *result)
  261. {
  262. struct mtd_oob_ops ops;
  263. uint32_t oob_buf[ENV_OFFSET_SIZE/sizeof(uint32_t)];
  264. int ret;
  265. ops.datbuf = NULL;
  266. ops.mode = MTD_OOB_AUTO;
  267. ops.ooboffs = 0;
  268. ops.ooblen = ENV_OFFSET_SIZE;
  269. ops.oobbuf = (void *) oob_buf;
  270. ret = nand->read_oob(nand, ENV_OFFSET_SIZE, &ops);
  271. if (ret) {
  272. printf("error reading OOB block 0\n");
  273. return ret;
  274. }
  275. if (oob_buf[0] == ENV_OOB_MARKER) {
  276. *result = oob_buf[1] * nand->erasesize;
  277. } else if (oob_buf[0] == ENV_OOB_MARKER_OLD) {
  278. *result = oob_buf[1];
  279. } else {
  280. printf("No dynamic environment marker in OOB block 0\n");
  281. return -ENOENT;
  282. }
  283. return 0;
  284. }
  285. #endif
  286. #ifdef CONFIG_ENV_OFFSET_REDUND
  287. void env_relocate_spec(void)
  288. {
  289. #if !defined(ENV_IS_EMBEDDED)
  290. int crc1_ok = 0, crc2_ok = 0;
  291. env_t *ep, *tmp_env1, *tmp_env2;
  292. tmp_env1 = (env_t *)malloc(CONFIG_ENV_SIZE);
  293. tmp_env2 = (env_t *)malloc(CONFIG_ENV_SIZE);
  294. if ((tmp_env1 == NULL) || (tmp_env2 == NULL)) {
  295. puts("Can't allocate buffers for environment\n");
  296. free(tmp_env1);
  297. free(tmp_env2);
  298. set_default_env("!malloc() failed");
  299. return;
  300. }
  301. if (readenv(CONFIG_ENV_OFFSET, (u_char *) tmp_env1))
  302. puts("No Valid Environment Area found\n");
  303. if (readenv(CONFIG_ENV_OFFSET_REDUND, (u_char *) tmp_env2))
  304. puts("No Valid Redundant Environment Area found\n");
  305. crc1_ok = (crc32(0, tmp_env1->data, ENV_SIZE) == tmp_env1->crc);
  306. crc2_ok = (crc32(0, tmp_env2->data, ENV_SIZE) == tmp_env2->crc);
  307. if (!crc1_ok && !crc2_ok) {
  308. free(tmp_env1);
  309. free(tmp_env2);
  310. set_default_env("!bad CRC");
  311. return;
  312. } else if (crc1_ok && !crc2_ok) {
  313. gd->env_valid = 1;
  314. } else if (!crc1_ok && crc2_ok) {
  315. gd->env_valid = 2;
  316. } else {
  317. /* both ok - check serial */
  318. if (tmp_env1->flags == 255 && tmp_env2->flags == 0)
  319. gd->env_valid = 2;
  320. else if (tmp_env2->flags == 255 && tmp_env1->flags == 0)
  321. gd->env_valid = 1;
  322. else if (tmp_env1->flags > tmp_env2->flags)
  323. gd->env_valid = 1;
  324. else if (tmp_env2->flags > tmp_env1->flags)
  325. gd->env_valid = 2;
  326. else /* flags are equal - almost impossible */
  327. gd->env_valid = 1;
  328. }
  329. free(env_ptr);
  330. if (gd->env_valid == 1)
  331. ep = tmp_env1;
  332. else
  333. ep = tmp_env2;
  334. env_flags = ep->flags;
  335. env_import((char *)ep, 0);
  336. free(tmp_env1);
  337. free(tmp_env2);
  338. #endif /* ! ENV_IS_EMBEDDED */
  339. }
  340. #else /* ! CONFIG_ENV_OFFSET_REDUND */
  341. /*
  342. * The legacy NAND code saved the environment in the first NAND
  343. * device i.e., nand_dev_desc + 0. This is also the behaviour using
  344. * the new NAND code.
  345. */
  346. void env_relocate_spec (void)
  347. {
  348. #if !defined(ENV_IS_EMBEDDED)
  349. int ret;
  350. char buf[CONFIG_ENV_SIZE];
  351. #if defined(CONFIG_ENV_OFFSET_OOB)
  352. ret = get_nand_env_oob(&nand_info[0], &nand_env_oob_offset);
  353. /*
  354. * If unable to read environment offset from NAND OOB then fall through
  355. * to the normal environment reading code below
  356. */
  357. if (!ret) {
  358. printf("Found Environment offset in OOB..\n");
  359. } else {
  360. set_default_env("!no env offset in OOB");
  361. return;
  362. }
  363. #endif
  364. ret = readenv(CONFIG_ENV_OFFSET, (u_char *)buf);
  365. if (ret) {
  366. set_default_env("!readenv() failed");
  367. return;
  368. }
  369. env_import(buf, 1);
  370. #endif /* ! ENV_IS_EMBEDDED */
  371. }
  372. #endif /* CONFIG_ENV_OFFSET_REDUND */