1 // SPDX-License-Identifier: GPL-2.0+
3 * (C) Copyright 2008-2011 Freescale Semiconductor, Inc.
9 #include <asm/global_data.h>
13 #include <env_internal.h>
15 #include <linux/stddef.h>
22 #include <dm/ofnode.h>
24 #define ENV_MMC_INVALID_OFFSET ((s64)-1)
26 #if defined(CONFIG_ENV_MMC_USE_DT)
27 /* ENV offset is invalid when not defined in Device Tree */
28 #define ENV_MMC_OFFSET ENV_MMC_INVALID_OFFSET
29 #define ENV_MMC_OFFSET_REDUND ENV_MMC_INVALID_OFFSET
32 /* Default ENV offset when not defined in Device Tree */
33 #define ENV_MMC_OFFSET CONFIG_ENV_OFFSET
35 #if defined(CONFIG_ENV_OFFSET_REDUND)
36 #define ENV_MMC_OFFSET_REDUND CONFIG_ENV_OFFSET_REDUND
38 #define ENV_MMC_OFFSET_REDUND ENV_MMC_INVALID_OFFSET
42 DECLARE_GLOBAL_DATA_PTR;
45 * In case the environment is redundant, stored in eMMC hardware boot
46 * partition and the environment and redundant environment offsets are
47 * identical, store the environment and redundant environment in both
48 * eMMC boot partitions, one copy in each.
50 #if (defined(CONFIG_SYS_REDUNDAND_ENVIRONMENT) && \
51 (CONFIG_SYS_MMC_ENV_PART == 1) && \
52 (CONFIG_ENV_OFFSET == CONFIG_ENV_OFFSET_REDUND))
53 #define ENV_MMC_HWPART_REDUND 1
56 #if CONFIG_IS_ENABLED(OF_CONTROL)
57 static inline int mmc_offset_try_partition(const char *str, int copy, s64 *val)
59 struct disk_partition info;
60 struct blk_desc *desc;
64 snprintf(dev_str, sizeof(dev_str), "%d", mmc_get_env_dev());
65 ret = blk_get_device_by_str("mmc", dev_str, &desc);
70 ret = part_get_info(desc, i, &info);
74 if (str && !strncmp((const char *)info.name, str, sizeof(info.name)))
76 #ifdef CONFIG_PARTITION_TYPE_GUID
78 const efi_guid_t env_guid = PARTITION_U_BOOT_ENVIRONMENT;
81 uuid_str_to_bin(info.type_guid, type_guid.b, UUID_STR_FORMAT_GUID);
82 if (!memcmp(&env_guid, &type_guid, sizeof(efi_guid_t)))
88 /* round up to info.blksz */
89 len = DIV_ROUND_UP(CONFIG_ENV_SIZE, info.blksz);
91 /* use the top of the partion for the environment */
92 *val = (info.start + info.size - (1 + copy) * len) * info.blksz;
97 static inline s64 mmc_offset(struct mmc *mmc, int copy)
100 const char *offset_redund;
101 const char *partition;
104 .offset_redund = "u-boot,mmc-env-offset-redundant",
105 .partition = "u-boot,mmc-env-partition",
106 .offset = "u-boot,mmc-env-offset",
108 s64 val = 0, defvalue;
109 const char *propname;
114 if (IS_ENABLED(CONFIG_SYS_MMC_ENV_PART))
115 hwpart = mmc_get_env_part(mmc);
117 /* look for the partition in mmc CONFIG_SYS_MMC_ENV_DEV */
118 str = ofnode_conf_read_str(dt_prop.partition);
120 /* try to place the environment at end of the partition */
121 err = mmc_offset_try_partition(str, copy, &val);
124 debug("env partition '%s' not found (%d)", str, err);
127 /* try the GPT partition with "U-Boot ENV" TYPE GUID */
128 if (IS_ENABLED(CONFIG_PARTITION_TYPE_GUID) && hwpart == 0) {
129 err = mmc_offset_try_partition(NULL, copy, &val);
134 defvalue = ENV_MMC_OFFSET;
135 propname = dt_prop.offset;
137 if (IS_ENABLED(CONFIG_SYS_REDUNDAND_ENVIRONMENT) && copy) {
138 defvalue = ENV_MMC_OFFSET_REDUND;
139 propname = dt_prop.offset_redund;
142 return ofnode_conf_read_int(propname, defvalue);
145 static inline s64 mmc_offset(struct mmc *mmc, int copy)
147 s64 offset = ENV_MMC_OFFSET;
149 if (IS_ENABLED(CONFIG_SYS_REDUNDAND_ENVIRONMENT) && copy)
150 offset = ENV_MMC_OFFSET_REDUND;
156 __weak int mmc_get_env_addr(struct mmc *mmc, int copy, u32 *env_addr)
158 s64 offset = mmc_offset(mmc, copy);
160 if (offset == ENV_MMC_INVALID_OFFSET) {
161 printf("Invalid ENV offset in MMC, copy=%d\n", copy);
166 offset += mmc->capacity;
173 #ifdef CONFIG_SYS_MMC_ENV_PART
174 __weak uint mmc_get_env_part(struct mmc *mmc)
176 return CONFIG_SYS_MMC_ENV_PART;
179 static unsigned char env_mmc_orig_hwpart;
181 static int mmc_set_env_part(struct mmc *mmc, uint part)
183 int dev = mmc_get_env_dev();
186 ret = blk_select_hwpart_devnum(UCLASS_MMC, dev, part);
188 puts("MMC partition switch failed\n");
193 static bool mmc_set_env_part_init(struct mmc *mmc)
195 env_mmc_orig_hwpart = mmc_get_blk_desc(mmc)->hwpart;
196 if (mmc_set_env_part(mmc, mmc_get_env_part(mmc)))
202 static int mmc_set_env_part_restore(struct mmc *mmc)
204 return mmc_set_env_part(mmc, env_mmc_orig_hwpart);
207 static inline int mmc_set_env_part(struct mmc *mmc, uint part) {return 0; };
208 static bool mmc_set_env_part_init(struct mmc *mmc) {return true; }
209 static inline int mmc_set_env_part_restore(struct mmc *mmc) {return 0; };
212 static const char *init_mmc_for_env(struct mmc *mmc)
215 return "No MMC card found";
217 #if CONFIG_IS_ENABLED(BLK)
220 if (blk_get_from_parent(mmc->dev, &dev))
221 return "No block device";
224 return "MMC init failed";
226 if (!mmc_set_env_part_init(mmc))
227 return "MMC partition switch failed";
232 static void fini_mmc_for_env(struct mmc *mmc)
234 mmc_set_env_part_restore(mmc);
237 #if defined(CONFIG_CMD_SAVEENV) && !defined(CONFIG_SPL_BUILD)
238 static inline int write_env(struct mmc *mmc, unsigned long size,
239 unsigned long offset, const void *buffer)
241 uint blk_start, blk_cnt, n;
242 struct blk_desc *desc = mmc_get_blk_desc(mmc);
244 blk_start = ALIGN(offset, mmc->write_bl_len) / mmc->write_bl_len;
245 blk_cnt = ALIGN(size, mmc->write_bl_len) / mmc->write_bl_len;
247 n = blk_dwrite(desc, blk_start, blk_cnt, (u_char *)buffer);
249 return (n == blk_cnt) ? 0 : -1;
252 static int env_mmc_save(void)
254 ALLOC_CACHE_ALIGN_BUFFER(env_t, env_new, 1);
255 int dev = mmc_get_env_dev();
256 struct mmc *mmc = find_mmc_device(dev);
261 errmsg = init_mmc_for_env(mmc);
263 printf("%s\n", errmsg);
267 ret = env_export(env_new);
271 if (IS_ENABLED(CONFIG_SYS_REDUNDAND_ENVIRONMENT)) {
272 if (gd->env_valid == ENV_VALID)
275 if (IS_ENABLED(ENV_MMC_HWPART_REDUND)) {
276 ret = mmc_set_env_part(mmc, copy + 1);
282 if (mmc_get_env_addr(mmc, copy, &offset)) {
287 printf("Writing to %sMMC(%d)... ", copy ? "redundant " : "", dev);
288 if (write_env(mmc, CONFIG_ENV_SIZE, offset, (u_char *)env_new)) {
296 if (IS_ENABLED(CONFIG_SYS_REDUNDAND_ENVIRONMENT))
297 gd->env_valid = gd->env_valid == ENV_REDUND ? ENV_VALID : ENV_REDUND;
300 fini_mmc_for_env(mmc);
305 static inline int erase_env(struct mmc *mmc, unsigned long size,
306 unsigned long offset)
308 uint blk_start, blk_cnt, n;
309 struct blk_desc *desc = mmc_get_blk_desc(mmc);
312 erase_size = mmc->erase_grp_size * desc->blksz;
313 blk_start = ALIGN_DOWN(offset, erase_size) / desc->blksz;
314 blk_cnt = ALIGN(size, erase_size) / desc->blksz;
316 n = blk_derase(desc, blk_start, blk_cnt);
317 printf("%d blocks erased at 0x%x: %s\n", n, blk_start,
318 (n == blk_cnt) ? "OK" : "ERROR");
320 return (n == blk_cnt) ? 0 : 1;
323 static int env_mmc_erase(void)
325 int dev = mmc_get_env_dev();
326 struct mmc *mmc = find_mmc_device(dev);
331 errmsg = init_mmc_for_env(mmc);
333 printf("%s\n", errmsg);
337 if (mmc_get_env_addr(mmc, copy, &offset)) {
338 ret = CMD_RET_FAILURE;
343 ret = erase_env(mmc, CONFIG_ENV_SIZE, offset);
345 if (IS_ENABLED(CONFIG_SYS_REDUNDAND_ENVIRONMENT)) {
348 if (IS_ENABLED(ENV_MMC_HWPART_REDUND)) {
349 ret = mmc_set_env_part(mmc, copy + 1);
354 if (mmc_get_env_addr(mmc, copy, &offset)) {
355 ret = CMD_RET_FAILURE;
359 ret |= erase_env(mmc, CONFIG_ENV_SIZE, offset);
363 fini_mmc_for_env(mmc);
366 #endif /* CONFIG_CMD_SAVEENV && !CONFIG_SPL_BUILD */
368 static inline int read_env(struct mmc *mmc, unsigned long size,
369 unsigned long offset, const void *buffer)
371 uint blk_start, blk_cnt, n;
372 struct blk_desc *desc = mmc_get_blk_desc(mmc);
374 blk_start = ALIGN(offset, mmc->read_bl_len) / mmc->read_bl_len;
375 blk_cnt = ALIGN(size, mmc->read_bl_len) / mmc->read_bl_len;
377 n = blk_dread(desc, blk_start, blk_cnt, (uchar *)buffer);
379 return (n == blk_cnt) ? 0 : -1;
382 #if defined(ENV_IS_EMBEDDED)
383 static int env_mmc_load(void)
387 #elif defined(CONFIG_SYS_REDUNDAND_ENVIRONMENT)
388 static int env_mmc_load(void)
391 u32 offset1, offset2;
392 int read1_fail = 0, read2_fail = 0;
394 int dev = mmc_get_env_dev();
395 const char *errmsg = NULL;
397 ALLOC_CACHE_ALIGN_BUFFER(env_t, tmp_env1, 1);
398 ALLOC_CACHE_ALIGN_BUFFER(env_t, tmp_env2, 1);
400 mmc_initialize(NULL);
402 mmc = find_mmc_device(dev);
404 errmsg = init_mmc_for_env(mmc);
410 if (mmc_get_env_addr(mmc, 0, &offset1) ||
411 mmc_get_env_addr(mmc, 1, &offset2)) {
416 if (IS_ENABLED(ENV_MMC_HWPART_REDUND)) {
417 ret = mmc_set_env_part(mmc, 1);
422 read1_fail = read_env(mmc, CONFIG_ENV_SIZE, offset1, tmp_env1);
424 if (IS_ENABLED(ENV_MMC_HWPART_REDUND)) {
425 ret = mmc_set_env_part(mmc, 2);
430 read2_fail = read_env(mmc, CONFIG_ENV_SIZE, offset2, tmp_env2);
432 ret = env_import_redund((char *)tmp_env1, read1_fail, (char *)tmp_env2,
433 read2_fail, H_EXTERNAL);
436 fini_mmc_for_env(mmc);
439 env_set_default(errmsg, 0);
443 #else /* ! CONFIG_SYS_REDUNDAND_ENVIRONMENT */
444 static int env_mmc_load(void)
446 ALLOC_CACHE_ALIGN_BUFFER(char, buf, CONFIG_ENV_SIZE);
450 int dev = mmc_get_env_dev();
454 mmc = find_mmc_device(dev);
456 errmsg = init_mmc_for_env(mmc);
462 if (mmc_get_env_addr(mmc, 0, &offset)) {
467 if (read_env(mmc, CONFIG_ENV_SIZE, offset, buf)) {
468 errmsg = "!read failed";
473 ret = env_import(buf, 1, H_EXTERNAL);
476 gd->env_addr = (ulong)&ep->data;
480 fini_mmc_for_env(mmc);
483 env_set_default(errmsg, 0);
487 #endif /* CONFIG_SYS_REDUNDAND_ENVIRONMENT */
489 U_BOOT_ENV_LOCATION(mmc) = {
490 .location = ENVL_MMC,
492 .load = env_mmc_load,
493 #ifndef CONFIG_SPL_BUILD
494 .save = env_save_ptr(env_mmc_save),
495 .erase = ENV_ERASE_PTR(env_mmc_erase)