mmc.c 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441
  1. // SPDX-License-Identifier: GPL-2.0+
  2. /*
  3. * (C) Copyright 2008-2011 Freescale Semiconductor, Inc.
  4. */
  5. /* #define DEBUG */
  6. #include <common.h>
  7. #include <asm/global_data.h>
  8. #include <command.h>
  9. #include <env.h>
  10. #include <env_internal.h>
  11. #include <fdtdec.h>
  12. #include <linux/stddef.h>
  13. #include <malloc.h>
  14. #include <memalign.h>
  15. #include <mmc.h>
  16. #include <part.h>
  17. #include <search.h>
  18. #include <errno.h>
  19. #include <dm/ofnode.h>
  20. #define __STR(X) #X
  21. #define STR(X) __STR(X)
  22. DECLARE_GLOBAL_DATA_PTR;
  23. /*
  24. * In case the environment is redundant, stored in eMMC hardware boot
  25. * partition and the environment and redundant environment offsets are
  26. * identical, store the environment and redundant environment in both
  27. * eMMC boot partitions, one copy in each.
  28. * */
  29. #if (defined(CONFIG_SYS_REDUNDAND_ENVIRONMENT) && \
  30. (CONFIG_SYS_MMC_ENV_PART == 1) && \
  31. (CONFIG_ENV_OFFSET == CONFIG_ENV_OFFSET_REDUND))
  32. #define ENV_MMC_HWPART_REDUND
  33. #endif
  34. #if CONFIG_IS_ENABLED(OF_CONTROL)
  35. static inline int mmc_offset_try_partition(const char *str, int copy, s64 *val)
  36. {
  37. struct disk_partition info;
  38. struct blk_desc *desc;
  39. int len, i, ret;
  40. char dev_str[4];
  41. snprintf(dev_str, sizeof(dev_str), "%d", mmc_get_env_dev());
  42. ret = blk_get_device_by_str("mmc", dev_str, &desc);
  43. if (ret < 0)
  44. return (ret);
  45. for (i = 1;;i++) {
  46. ret = part_get_info(desc, i, &info);
  47. if (ret < 0)
  48. return ret;
  49. if (!strncmp((const char *)info.name, str, sizeof(info.name)))
  50. break;
  51. }
  52. /* round up to info.blksz */
  53. len = DIV_ROUND_UP(CONFIG_ENV_SIZE, info.blksz);
  54. /* use the top of the partion for the environment */
  55. *val = (info.start + info.size - (1 + copy) * len) * info.blksz;
  56. return 0;
  57. }
  58. static inline s64 mmc_offset(int copy)
  59. {
  60. const struct {
  61. const char *offset_redund;
  62. const char *partition;
  63. const char *offset;
  64. } dt_prop = {
  65. .offset_redund = "u-boot,mmc-env-offset-redundant",
  66. .partition = "u-boot,mmc-env-partition",
  67. .offset = "u-boot,mmc-env-offset",
  68. };
  69. s64 val = 0, defvalue;
  70. const char *propname;
  71. const char *str;
  72. int err;
  73. /* look for the partition in mmc CONFIG_SYS_MMC_ENV_DEV */
  74. str = ofnode_conf_read_str(dt_prop.partition);
  75. if (str) {
  76. /* try to place the environment at end of the partition */
  77. err = mmc_offset_try_partition(str, copy, &val);
  78. if (!err)
  79. return val;
  80. }
  81. defvalue = CONFIG_ENV_OFFSET;
  82. propname = dt_prop.offset;
  83. #if defined(CONFIG_ENV_OFFSET_REDUND)
  84. if (copy) {
  85. defvalue = CONFIG_ENV_OFFSET_REDUND;
  86. propname = dt_prop.offset_redund;
  87. }
  88. #endif
  89. return ofnode_conf_read_int(propname, defvalue);
  90. }
  91. #else
  92. static inline s64 mmc_offset(int copy)
  93. {
  94. s64 offset = CONFIG_ENV_OFFSET;
  95. #if defined(CONFIG_ENV_OFFSET_REDUND)
  96. if (copy)
  97. offset = CONFIG_ENV_OFFSET_REDUND;
  98. #endif
  99. return offset;
  100. }
  101. #endif
  102. __weak int mmc_get_env_addr(struct mmc *mmc, int copy, u32 *env_addr)
  103. {
  104. s64 offset = mmc_offset(copy);
  105. if (offset < 0)
  106. offset += mmc->capacity;
  107. *env_addr = offset;
  108. return 0;
  109. }
  110. #ifdef CONFIG_SYS_MMC_ENV_PART
  111. __weak uint mmc_get_env_part(struct mmc *mmc)
  112. {
  113. return CONFIG_SYS_MMC_ENV_PART;
  114. }
  115. static unsigned char env_mmc_orig_hwpart;
  116. static int mmc_set_env_part(struct mmc *mmc, uint part)
  117. {
  118. int dev = mmc_get_env_dev();
  119. int ret = 0;
  120. ret = blk_select_hwpart_devnum(IF_TYPE_MMC, dev, part);
  121. if (ret)
  122. puts("MMC partition switch failed\n");
  123. return ret;
  124. }
  125. #else
  126. static inline int mmc_set_env_part(struct mmc *mmc, uint part) {return 0; };
  127. #endif
  128. static const char *init_mmc_for_env(struct mmc *mmc)
  129. {
  130. if (!mmc)
  131. return "No MMC card found";
  132. #if CONFIG_IS_ENABLED(BLK)
  133. struct udevice *dev;
  134. if (blk_get_from_parent(mmc->dev, &dev))
  135. return "No block device";
  136. #else
  137. if (mmc_init(mmc))
  138. return "MMC init failed";
  139. #endif
  140. env_mmc_orig_hwpart = mmc_get_blk_desc(mmc)->hwpart;
  141. if (mmc_set_env_part(mmc, mmc_get_env_part(mmc)))
  142. return "MMC partition switch failed";
  143. return NULL;
  144. }
  145. static void fini_mmc_for_env(struct mmc *mmc)
  146. {
  147. #ifdef CONFIG_SYS_MMC_ENV_PART
  148. int dev = mmc_get_env_dev();
  149. blk_select_hwpart_devnum(IF_TYPE_MMC, dev, env_mmc_orig_hwpart);
  150. #endif
  151. }
  152. #if defined(CONFIG_CMD_SAVEENV) && !defined(CONFIG_SPL_BUILD)
  153. static inline int write_env(struct mmc *mmc, unsigned long size,
  154. unsigned long offset, const void *buffer)
  155. {
  156. uint blk_start, blk_cnt, n;
  157. struct blk_desc *desc = mmc_get_blk_desc(mmc);
  158. blk_start = ALIGN(offset, mmc->write_bl_len) / mmc->write_bl_len;
  159. blk_cnt = ALIGN(size, mmc->write_bl_len) / mmc->write_bl_len;
  160. n = blk_dwrite(desc, blk_start, blk_cnt, (u_char *)buffer);
  161. return (n == blk_cnt) ? 0 : -1;
  162. }
  163. static int env_mmc_save(void)
  164. {
  165. ALLOC_CACHE_ALIGN_BUFFER(env_t, env_new, 1);
  166. int dev = mmc_get_env_dev();
  167. struct mmc *mmc = find_mmc_device(dev);
  168. u32 offset;
  169. int ret, copy = 0;
  170. const char *errmsg;
  171. errmsg = init_mmc_for_env(mmc);
  172. if (errmsg) {
  173. printf("%s\n", errmsg);
  174. return 1;
  175. }
  176. ret = env_export(env_new);
  177. if (ret)
  178. goto fini;
  179. #ifdef CONFIG_ENV_OFFSET_REDUND
  180. if (gd->env_valid == ENV_VALID)
  181. copy = 1;
  182. #ifdef ENV_MMC_HWPART_REDUND
  183. ret = mmc_set_env_part(mmc, copy + 1);
  184. if (ret)
  185. goto fini;
  186. #endif
  187. #endif
  188. if (mmc_get_env_addr(mmc, copy, &offset)) {
  189. ret = 1;
  190. goto fini;
  191. }
  192. printf("Writing to %sMMC(%d)... ", copy ? "redundant " : "", dev);
  193. if (write_env(mmc, CONFIG_ENV_SIZE, offset, (u_char *)env_new)) {
  194. puts("failed\n");
  195. ret = 1;
  196. goto fini;
  197. }
  198. ret = 0;
  199. #ifdef CONFIG_ENV_OFFSET_REDUND
  200. gd->env_valid = gd->env_valid == ENV_REDUND ? ENV_VALID : ENV_REDUND;
  201. #endif
  202. fini:
  203. fini_mmc_for_env(mmc);
  204. return ret;
  205. }
  206. static inline int erase_env(struct mmc *mmc, unsigned long size,
  207. unsigned long offset)
  208. {
  209. uint blk_start, blk_cnt, n;
  210. struct blk_desc *desc = mmc_get_blk_desc(mmc);
  211. blk_start = ALIGN(offset, mmc->write_bl_len) / mmc->write_bl_len;
  212. blk_cnt = ALIGN(size, mmc->write_bl_len) / mmc->write_bl_len;
  213. n = blk_derase(desc, blk_start, blk_cnt);
  214. printf("%d blocks erased: %s\n", n, (n == blk_cnt) ? "OK" : "ERROR");
  215. return (n == blk_cnt) ? 0 : 1;
  216. }
  217. static int env_mmc_erase(void)
  218. {
  219. int dev = mmc_get_env_dev();
  220. struct mmc *mmc = find_mmc_device(dev);
  221. int ret, copy = 0;
  222. u32 offset;
  223. const char *errmsg;
  224. errmsg = init_mmc_for_env(mmc);
  225. if (errmsg) {
  226. printf("%s\n", errmsg);
  227. return 1;
  228. }
  229. if (mmc_get_env_addr(mmc, copy, &offset)) {
  230. ret = CMD_RET_FAILURE;
  231. goto fini;
  232. }
  233. ret = erase_env(mmc, CONFIG_ENV_SIZE, offset);
  234. #ifdef CONFIG_ENV_OFFSET_REDUND
  235. copy = 1;
  236. #ifdef ENV_MMC_HWPART_REDUND
  237. ret = mmc_set_env_part(mmc, copy + 1);
  238. if (ret)
  239. goto fini;
  240. #endif
  241. if (mmc_get_env_addr(mmc, copy, &offset)) {
  242. ret = CMD_RET_FAILURE;
  243. goto fini;
  244. }
  245. ret |= erase_env(mmc, CONFIG_ENV_SIZE, offset);
  246. #endif
  247. fini:
  248. fini_mmc_for_env(mmc);
  249. return ret;
  250. }
  251. #endif /* CONFIG_CMD_SAVEENV && !CONFIG_SPL_BUILD */
  252. static inline int read_env(struct mmc *mmc, unsigned long size,
  253. unsigned long offset, const void *buffer)
  254. {
  255. uint blk_start, blk_cnt, n;
  256. struct blk_desc *desc = mmc_get_blk_desc(mmc);
  257. blk_start = ALIGN(offset, mmc->read_bl_len) / mmc->read_bl_len;
  258. blk_cnt = ALIGN(size, mmc->read_bl_len) / mmc->read_bl_len;
  259. n = blk_dread(desc, blk_start, blk_cnt, (uchar *)buffer);
  260. return (n == blk_cnt) ? 0 : -1;
  261. }
  262. #ifdef CONFIG_ENV_OFFSET_REDUND
  263. static int env_mmc_load(void)
  264. {
  265. #if !defined(ENV_IS_EMBEDDED)
  266. struct mmc *mmc;
  267. u32 offset1, offset2;
  268. int read1_fail = 0, read2_fail = 0;
  269. int ret;
  270. int dev = mmc_get_env_dev();
  271. const char *errmsg = NULL;
  272. ALLOC_CACHE_ALIGN_BUFFER(env_t, tmp_env1, 1);
  273. ALLOC_CACHE_ALIGN_BUFFER(env_t, tmp_env2, 1);
  274. mmc_initialize(NULL);
  275. mmc = find_mmc_device(dev);
  276. errmsg = init_mmc_for_env(mmc);
  277. if (errmsg) {
  278. ret = -EIO;
  279. goto err;
  280. }
  281. if (mmc_get_env_addr(mmc, 0, &offset1) ||
  282. mmc_get_env_addr(mmc, 1, &offset2)) {
  283. ret = -EIO;
  284. goto fini;
  285. }
  286. #ifdef ENV_MMC_HWPART_REDUND
  287. ret = mmc_set_env_part(mmc, 1);
  288. if (ret)
  289. goto fini;
  290. #endif
  291. read1_fail = read_env(mmc, CONFIG_ENV_SIZE, offset1, tmp_env1);
  292. #ifdef ENV_MMC_HWPART_REDUND
  293. ret = mmc_set_env_part(mmc, 2);
  294. if (ret)
  295. goto fini;
  296. #endif
  297. read2_fail = read_env(mmc, CONFIG_ENV_SIZE, offset2, tmp_env2);
  298. ret = env_import_redund((char *)tmp_env1, read1_fail, (char *)tmp_env2,
  299. read2_fail, H_EXTERNAL);
  300. fini:
  301. fini_mmc_for_env(mmc);
  302. err:
  303. if (ret)
  304. env_set_default(errmsg, 0);
  305. #endif
  306. return ret;
  307. }
  308. #else /* ! CONFIG_ENV_OFFSET_REDUND */
  309. static int env_mmc_load(void)
  310. {
  311. #if !defined(ENV_IS_EMBEDDED)
  312. ALLOC_CACHE_ALIGN_BUFFER(char, buf, CONFIG_ENV_SIZE);
  313. struct mmc *mmc;
  314. u32 offset;
  315. int ret;
  316. int dev = mmc_get_env_dev();
  317. const char *errmsg;
  318. env_t *ep = NULL;
  319. mmc = find_mmc_device(dev);
  320. errmsg = init_mmc_for_env(mmc);
  321. if (errmsg) {
  322. ret = -EIO;
  323. goto err;
  324. }
  325. if (mmc_get_env_addr(mmc, 0, &offset)) {
  326. ret = -EIO;
  327. goto fini;
  328. }
  329. if (read_env(mmc, CONFIG_ENV_SIZE, offset, buf)) {
  330. errmsg = "!read failed";
  331. ret = -EIO;
  332. goto fini;
  333. }
  334. ret = env_import(buf, 1, H_EXTERNAL);
  335. if (!ret) {
  336. ep = (env_t *)buf;
  337. gd->env_addr = (ulong)&ep->data;
  338. }
  339. fini:
  340. fini_mmc_for_env(mmc);
  341. err:
  342. if (ret)
  343. env_set_default(errmsg, 0);
  344. #endif
  345. return ret;
  346. }
  347. #endif /* CONFIG_ENV_OFFSET_REDUND */
  348. U_BOOT_ENV_LOCATION(mmc) = {
  349. .location = ENVL_MMC,
  350. ENV_NAME("MMC")
  351. .load = env_mmc_load,
  352. #ifndef CONFIG_SPL_BUILD
  353. .save = env_save_ptr(env_mmc_save),
  354. .erase = ENV_ERASE_PTR(env_mmc_erase)
  355. #endif
  356. };