mmc.c 8.3 KB

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