env_mmc.c 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321
  1. /*
  2. * (C) Copyright 2008-2011 Freescale Semiconductor, Inc.
  3. *
  4. * SPDX-License-Identifier: GPL-2.0+
  5. */
  6. /* #define DEBUG */
  7. #include <common.h>
  8. #include <command.h>
  9. #include <environment.h>
  10. #include <linux/stddef.h>
  11. #include <malloc.h>
  12. #include <mmc.h>
  13. #include <search.h>
  14. #include <errno.h>
  15. #if defined(CONFIG_ENV_SIZE_REDUND) && \
  16. (CONFIG_ENV_SIZE_REDUND != CONFIG_ENV_SIZE)
  17. #error CONFIG_ENV_SIZE_REDUND should be the same as CONFIG_ENV_SIZE
  18. #endif
  19. char *env_name_spec = "MMC";
  20. #ifdef ENV_IS_EMBEDDED
  21. env_t *env_ptr = &environment;
  22. #else /* ! ENV_IS_EMBEDDED */
  23. env_t *env_ptr;
  24. #endif /* ENV_IS_EMBEDDED */
  25. DECLARE_GLOBAL_DATA_PTR;
  26. #if !defined(CONFIG_ENV_OFFSET)
  27. #define CONFIG_ENV_OFFSET 0
  28. #endif
  29. __weak int mmc_get_env_addr(struct mmc *mmc, int copy, u32 *env_addr)
  30. {
  31. s64 offset;
  32. offset = CONFIG_ENV_OFFSET;
  33. #ifdef CONFIG_ENV_OFFSET_REDUND
  34. if (copy)
  35. offset = CONFIG_ENV_OFFSET_REDUND;
  36. #endif
  37. if (offset < 0)
  38. offset += mmc->capacity;
  39. *env_addr = offset;
  40. return 0;
  41. }
  42. int env_init(void)
  43. {
  44. /* use default */
  45. gd->env_addr = (ulong)&default_environment[0];
  46. gd->env_valid = 1;
  47. return 0;
  48. }
  49. static int init_mmc_for_env(struct mmc *mmc)
  50. {
  51. #ifdef CONFIG_SYS_MMC_ENV_PART
  52. int dev = CONFIG_SYS_MMC_ENV_DEV;
  53. #ifdef CONFIG_SPL_BUILD
  54. dev = 0;
  55. #endif
  56. #endif
  57. if (!mmc) {
  58. puts("No MMC card found\n");
  59. return -1;
  60. }
  61. if (mmc_init(mmc)) {
  62. puts("MMC init failed\n");
  63. return -1;
  64. }
  65. #ifdef CONFIG_SYS_MMC_ENV_PART
  66. if (CONFIG_SYS_MMC_ENV_PART != mmc->part_num) {
  67. if (mmc_switch_part(dev, CONFIG_SYS_MMC_ENV_PART)) {
  68. puts("MMC partition switch failed\n");
  69. return -1;
  70. }
  71. }
  72. #endif
  73. return 0;
  74. }
  75. static void fini_mmc_for_env(struct mmc *mmc)
  76. {
  77. #ifdef CONFIG_SYS_MMC_ENV_PART
  78. int dev = CONFIG_SYS_MMC_ENV_DEV;
  79. #ifdef CONFIG_SPL_BUILD
  80. dev = 0;
  81. #endif
  82. if (CONFIG_SYS_MMC_ENV_PART != mmc->part_num)
  83. mmc_switch_part(dev, mmc->part_num);
  84. #endif
  85. }
  86. #ifdef CONFIG_CMD_SAVEENV
  87. static inline int write_env(struct mmc *mmc, unsigned long size,
  88. unsigned long offset, const void *buffer)
  89. {
  90. uint blk_start, blk_cnt, n;
  91. blk_start = ALIGN(offset, mmc->write_bl_len) / mmc->write_bl_len;
  92. blk_cnt = ALIGN(size, mmc->write_bl_len) / mmc->write_bl_len;
  93. n = mmc->block_dev.block_write(CONFIG_SYS_MMC_ENV_DEV, blk_start,
  94. blk_cnt, (u_char *)buffer);
  95. return (n == blk_cnt) ? 0 : -1;
  96. }
  97. #ifdef CONFIG_ENV_OFFSET_REDUND
  98. static unsigned char env_flags;
  99. #endif
  100. int saveenv(void)
  101. {
  102. ALLOC_CACHE_ALIGN_BUFFER(env_t, env_new, 1);
  103. struct mmc *mmc = find_mmc_device(CONFIG_SYS_MMC_ENV_DEV);
  104. u32 offset;
  105. int ret, copy = 0;
  106. if (init_mmc_for_env(mmc))
  107. return 1;
  108. ret = env_export(env_new);
  109. if (ret)
  110. goto fini;
  111. #ifdef CONFIG_ENV_OFFSET_REDUND
  112. env_new->flags = ++env_flags; /* increase the serial */
  113. if (gd->env_valid == 1)
  114. copy = 1;
  115. #endif
  116. if (mmc_get_env_addr(mmc, copy, &offset)) {
  117. ret = 1;
  118. goto fini;
  119. }
  120. printf("Writing to %sMMC(%d)... ", copy ? "redundant " : "",
  121. CONFIG_SYS_MMC_ENV_DEV);
  122. if (write_env(mmc, CONFIG_ENV_SIZE, offset, (u_char *)env_new)) {
  123. puts("failed\n");
  124. ret = 1;
  125. goto fini;
  126. }
  127. puts("done\n");
  128. ret = 0;
  129. #ifdef CONFIG_ENV_OFFSET_REDUND
  130. gd->env_valid = gd->env_valid == 2 ? 1 : 2;
  131. #endif
  132. fini:
  133. fini_mmc_for_env(mmc);
  134. return ret;
  135. }
  136. #endif /* CONFIG_CMD_SAVEENV */
  137. static inline int read_env(struct mmc *mmc, unsigned long size,
  138. unsigned long offset, const void *buffer)
  139. {
  140. uint blk_start, blk_cnt, n;
  141. int dev = CONFIG_SYS_MMC_ENV_DEV;
  142. #ifdef CONFIG_SPL_BUILD
  143. dev = 0;
  144. #endif
  145. blk_start = ALIGN(offset, mmc->read_bl_len) / mmc->read_bl_len;
  146. blk_cnt = ALIGN(size, mmc->read_bl_len) / mmc->read_bl_len;
  147. n = mmc->block_dev.block_read(dev, blk_start, blk_cnt, (uchar *)buffer);
  148. return (n == blk_cnt) ? 0 : -1;
  149. }
  150. #ifdef CONFIG_ENV_OFFSET_REDUND
  151. void env_relocate_spec(void)
  152. {
  153. #if !defined(ENV_IS_EMBEDDED)
  154. struct mmc *mmc;
  155. u32 offset1, offset2;
  156. int read1_fail = 0, read2_fail = 0;
  157. int crc1_ok = 0, crc2_ok = 0;
  158. env_t *ep;
  159. int ret;
  160. int dev = CONFIG_SYS_MMC_ENV_DEV;
  161. ALLOC_CACHE_ALIGN_BUFFER(env_t, tmp_env1, 1);
  162. ALLOC_CACHE_ALIGN_BUFFER(env_t, tmp_env2, 1);
  163. #ifdef CONFIG_SPL_BUILD
  164. dev = 0;
  165. #endif
  166. mmc = find_mmc_device(dev);
  167. if (init_mmc_for_env(mmc)) {
  168. ret = 1;
  169. goto err;
  170. }
  171. if (mmc_get_env_addr(mmc, 0, &offset1) ||
  172. mmc_get_env_addr(mmc, 1, &offset2)) {
  173. ret = 1;
  174. goto fini;
  175. }
  176. read1_fail = read_env(mmc, CONFIG_ENV_SIZE, offset1, tmp_env1);
  177. read2_fail = read_env(mmc, CONFIG_ENV_SIZE, offset2, tmp_env2);
  178. if (read1_fail && read2_fail)
  179. puts("*** Error - No Valid Environment Area found\n");
  180. else if (read1_fail || read2_fail)
  181. puts("*** Warning - some problems detected "
  182. "reading environment; recovered successfully\n");
  183. crc1_ok = !read1_fail &&
  184. (crc32(0, tmp_env1->data, ENV_SIZE) == tmp_env1->crc);
  185. crc2_ok = !read2_fail &&
  186. (crc32(0, tmp_env2->data, ENV_SIZE) == tmp_env2->crc);
  187. if (!crc1_ok && !crc2_ok) {
  188. ret = 1;
  189. goto fini;
  190. } else if (crc1_ok && !crc2_ok) {
  191. gd->env_valid = 1;
  192. } else if (!crc1_ok && crc2_ok) {
  193. gd->env_valid = 2;
  194. } else {
  195. /* both ok - check serial */
  196. if (tmp_env1->flags == 255 && tmp_env2->flags == 0)
  197. gd->env_valid = 2;
  198. else if (tmp_env2->flags == 255 && tmp_env1->flags == 0)
  199. gd->env_valid = 1;
  200. else if (tmp_env1->flags > tmp_env2->flags)
  201. gd->env_valid = 1;
  202. else if (tmp_env2->flags > tmp_env1->flags)
  203. gd->env_valid = 2;
  204. else /* flags are equal - almost impossible */
  205. gd->env_valid = 1;
  206. }
  207. free(env_ptr);
  208. if (gd->env_valid == 1)
  209. ep = tmp_env1;
  210. else
  211. ep = tmp_env2;
  212. env_flags = ep->flags;
  213. env_import((char *)ep, 0);
  214. ret = 0;
  215. fini:
  216. fini_mmc_for_env(mmc);
  217. err:
  218. if (ret)
  219. set_default_env(NULL);
  220. #endif
  221. }
  222. #else /* ! CONFIG_ENV_OFFSET_REDUND */
  223. void env_relocate_spec(void)
  224. {
  225. #if !defined(ENV_IS_EMBEDDED)
  226. ALLOC_CACHE_ALIGN_BUFFER(char, buf, CONFIG_ENV_SIZE);
  227. struct mmc *mmc;
  228. u32 offset;
  229. int ret;
  230. int dev = CONFIG_SYS_MMC_ENV_DEV;
  231. #ifdef CONFIG_SPL_BUILD
  232. dev = 0;
  233. #endif
  234. mmc = find_mmc_device(dev);
  235. if (init_mmc_for_env(mmc)) {
  236. ret = 1;
  237. goto err;
  238. }
  239. if (mmc_get_env_addr(mmc, 0, &offset)) {
  240. ret = 1;
  241. goto fini;
  242. }
  243. if (read_env(mmc, CONFIG_ENV_SIZE, offset, buf)) {
  244. ret = 1;
  245. goto fini;
  246. }
  247. env_import(buf, 1);
  248. ret = 0;
  249. fini:
  250. fini_mmc_for_env(mmc);
  251. err:
  252. if (ret)
  253. set_default_env(NULL);
  254. #endif
  255. }
  256. #endif /* CONFIG_ENV_OFFSET_REDUND */