xref: /openbmc/u-boot/env/mmc.c (revision c5d548a9f881b2268f1d81dab9cd329ae336607e)
183d290c5STom Rini // SPDX-License-Identifier: GPL-2.0+
20649cd0dSSimon Glass /*
30649cd0dSSimon Glass  * (C) Copyright 2008-2011 Freescale Semiconductor, Inc.
40649cd0dSSimon Glass  */
50649cd0dSSimon Glass 
60649cd0dSSimon Glass /* #define DEBUG */
70649cd0dSSimon Glass 
80649cd0dSSimon Glass #include <common.h>
90649cd0dSSimon Glass 
100649cd0dSSimon Glass #include <command.h>
110649cd0dSSimon Glass #include <environment.h>
120649cd0dSSimon Glass #include <fdtdec.h>
130649cd0dSSimon Glass #include <linux/stddef.h>
140649cd0dSSimon Glass #include <malloc.h>
150649cd0dSSimon Glass #include <memalign.h>
160649cd0dSSimon Glass #include <mmc.h>
17c9e87ba6SJorge Ramirez-Ortiz #include <part.h>
180649cd0dSSimon Glass #include <search.h>
190649cd0dSSimon Glass #include <errno.h>
200649cd0dSSimon Glass 
21c9e87ba6SJorge Ramirez-Ortiz #define __STR(X) #X
22c9e87ba6SJorge Ramirez-Ortiz #define STR(X) __STR(X)
23c9e87ba6SJorge Ramirez-Ortiz 
240649cd0dSSimon Glass #if defined(CONFIG_ENV_SIZE_REDUND) &&  \
250649cd0dSSimon Glass 	(CONFIG_ENV_SIZE_REDUND != CONFIG_ENV_SIZE)
260649cd0dSSimon Glass #error CONFIG_ENV_SIZE_REDUND should be the same as CONFIG_ENV_SIZE
270649cd0dSSimon Glass #endif
280649cd0dSSimon Glass 
290649cd0dSSimon Glass DECLARE_GLOBAL_DATA_PTR;
300649cd0dSSimon Glass 
310649cd0dSSimon Glass #if !defined(CONFIG_ENV_OFFSET)
320649cd0dSSimon Glass #define CONFIG_ENV_OFFSET 0
330649cd0dSSimon Glass #endif
340649cd0dSSimon Glass 
350649cd0dSSimon Glass #if CONFIG_IS_ENABLED(OF_CONTROL)
mmc_offset_try_partition(const char * str,s64 * val)36c9e87ba6SJorge Ramirez-Ortiz static inline int mmc_offset_try_partition(const char *str, s64 *val)
37c9e87ba6SJorge Ramirez-Ortiz {
38c9e87ba6SJorge Ramirez-Ortiz 	disk_partition_t info;
39c9e87ba6SJorge Ramirez-Ortiz 	struct blk_desc *desc;
40c9e87ba6SJorge Ramirez-Ortiz 	int len, i, ret;
41c9e87ba6SJorge Ramirez-Ortiz 
42c9e87ba6SJorge Ramirez-Ortiz 	ret = blk_get_device_by_str("mmc", STR(CONFIG_SYS_MMC_ENV_DEV), &desc);
43c9e87ba6SJorge Ramirez-Ortiz 	if (ret < 0)
44c9e87ba6SJorge Ramirez-Ortiz 		return (ret);
45c9e87ba6SJorge Ramirez-Ortiz 
46c9e87ba6SJorge Ramirez-Ortiz 	for (i = 1;;i++) {
47c9e87ba6SJorge Ramirez-Ortiz 		ret = part_get_info(desc, i, &info);
48c9e87ba6SJorge Ramirez-Ortiz 		if (ret < 0)
49c9e87ba6SJorge Ramirez-Ortiz 			return ret;
50c9e87ba6SJorge Ramirez-Ortiz 
51c9e87ba6SJorge Ramirez-Ortiz 		if (!strncmp((const char *)info.name, str, sizeof(str)))
52c9e87ba6SJorge Ramirez-Ortiz 			break;
53c9e87ba6SJorge Ramirez-Ortiz 	}
54c9e87ba6SJorge Ramirez-Ortiz 
55c9e87ba6SJorge Ramirez-Ortiz 	/* round up to info.blksz */
56c9e87ba6SJorge Ramirez-Ortiz 	len = (CONFIG_ENV_SIZE + info.blksz - 1) & ~(info.blksz - 1);
57c9e87ba6SJorge Ramirez-Ortiz 
58c9e87ba6SJorge Ramirez-Ortiz 	/* use the top of the partion for the environment */
59c9e87ba6SJorge Ramirez-Ortiz 	*val = (info.start + info.size - 1) - len / info.blksz;
60c9e87ba6SJorge Ramirez-Ortiz 
61c9e87ba6SJorge Ramirez-Ortiz 	return 0;
62c9e87ba6SJorge Ramirez-Ortiz }
63c9e87ba6SJorge Ramirez-Ortiz 
mmc_offset(int copy)640649cd0dSSimon Glass static inline s64 mmc_offset(int copy)
650649cd0dSSimon Glass {
66c9e87ba6SJorge Ramirez-Ortiz 	const struct {
67c9e87ba6SJorge Ramirez-Ortiz 		const char *offset_redund;
68c9e87ba6SJorge Ramirez-Ortiz 		const char *partition;
69c9e87ba6SJorge Ramirez-Ortiz 		const char *offset;
70c9e87ba6SJorge Ramirez-Ortiz 	} dt_prop = {
71c9e87ba6SJorge Ramirez-Ortiz 		.offset_redund = "u-boot,mmc-env-offset-redundant",
72c9e87ba6SJorge Ramirez-Ortiz 		.partition = "u-boot,mmc-env-partition",
73c9e87ba6SJorge Ramirez-Ortiz 		.offset = "u-boot,mmc-env-offset",
74c9e87ba6SJorge Ramirez-Ortiz 	};
75fd374665SPhilipp Tomsich 	s64 val = 0, defvalue;
76c9e87ba6SJorge Ramirez-Ortiz 	const char *propname;
77c9e87ba6SJorge Ramirez-Ortiz 	const char *str;
78c9e87ba6SJorge Ramirez-Ortiz 	int err;
79c9e87ba6SJorge Ramirez-Ortiz 
80c9e87ba6SJorge Ramirez-Ortiz 	/* look for the partition in mmc CONFIG_SYS_MMC_ENV_DEV */
81c9e87ba6SJorge Ramirez-Ortiz 	str = fdtdec_get_config_string(gd->fdt_blob, dt_prop.partition);
82c9e87ba6SJorge Ramirez-Ortiz 	if (str) {
83c9e87ba6SJorge Ramirez-Ortiz 		/* try to place the environment at end of the partition */
84c9e87ba6SJorge Ramirez-Ortiz 		err = mmc_offset_try_partition(str, &val);
85c9e87ba6SJorge Ramirez-Ortiz 		if (!err)
86c9e87ba6SJorge Ramirez-Ortiz 			return val;
87c9e87ba6SJorge Ramirez-Ortiz 	}
88c9e87ba6SJorge Ramirez-Ortiz 
89c9e87ba6SJorge Ramirez-Ortiz 	defvalue = CONFIG_ENV_OFFSET;
90c9e87ba6SJorge Ramirez-Ortiz 	propname = dt_prop.offset;
910649cd0dSSimon Glass 
920649cd0dSSimon Glass #if defined(CONFIG_ENV_OFFSET_REDUND)
930649cd0dSSimon Glass 	if (copy) {
940649cd0dSSimon Glass 		defvalue = CONFIG_ENV_OFFSET_REDUND;
95c9e87ba6SJorge Ramirez-Ortiz 		propname = dt_prop.offset_redund;
960649cd0dSSimon Glass 	}
970649cd0dSSimon Glass #endif
980649cd0dSSimon Glass 	return fdtdec_get_config_int(gd->fdt_blob, propname, defvalue);
990649cd0dSSimon Glass }
1000649cd0dSSimon Glass #else
mmc_offset(int copy)1010649cd0dSSimon Glass static inline s64 mmc_offset(int copy)
1020649cd0dSSimon Glass {
1030649cd0dSSimon Glass 	s64 offset = CONFIG_ENV_OFFSET;
1040649cd0dSSimon Glass 
1050649cd0dSSimon Glass #if defined(CONFIG_ENV_OFFSET_REDUND)
1060649cd0dSSimon Glass 	if (copy)
1070649cd0dSSimon Glass 		offset = CONFIG_ENV_OFFSET_REDUND;
1080649cd0dSSimon Glass #endif
1090649cd0dSSimon Glass 	return offset;
1100649cd0dSSimon Glass }
1110649cd0dSSimon Glass #endif
1120649cd0dSSimon Glass 
mmc_get_env_addr(struct mmc * mmc,int copy,u32 * env_addr)1130649cd0dSSimon Glass __weak int mmc_get_env_addr(struct mmc *mmc, int copy, u32 *env_addr)
1140649cd0dSSimon Glass {
1150649cd0dSSimon Glass 	s64 offset = mmc_offset(copy);
1160649cd0dSSimon Glass 
1170649cd0dSSimon Glass 	if (offset < 0)
1180649cd0dSSimon Glass 		offset += mmc->capacity;
1190649cd0dSSimon Glass 
1200649cd0dSSimon Glass 	*env_addr = offset;
1210649cd0dSSimon Glass 
1220649cd0dSSimon Glass 	return 0;
1230649cd0dSSimon Glass }
1240649cd0dSSimon Glass 
mmc_get_env_dev(void)1250649cd0dSSimon Glass __weak int mmc_get_env_dev(void)
1260649cd0dSSimon Glass {
1270649cd0dSSimon Glass 	return CONFIG_SYS_MMC_ENV_DEV;
1280649cd0dSSimon Glass }
1290649cd0dSSimon Glass 
1300649cd0dSSimon Glass #ifdef CONFIG_SYS_MMC_ENV_PART
mmc_get_env_part(struct mmc * mmc)1310649cd0dSSimon Glass __weak uint mmc_get_env_part(struct mmc *mmc)
1320649cd0dSSimon Glass {
1330649cd0dSSimon Glass 	return CONFIG_SYS_MMC_ENV_PART;
1340649cd0dSSimon Glass }
1350649cd0dSSimon Glass 
1360649cd0dSSimon Glass static unsigned char env_mmc_orig_hwpart;
1370649cd0dSSimon Glass 
mmc_set_env_part(struct mmc * mmc)1380649cd0dSSimon Glass static int mmc_set_env_part(struct mmc *mmc)
1390649cd0dSSimon Glass {
1400649cd0dSSimon Glass 	uint part = mmc_get_env_part(mmc);
1410649cd0dSSimon Glass 	int dev = mmc_get_env_dev();
1420649cd0dSSimon Glass 	int ret = 0;
1430649cd0dSSimon Glass 
1440649cd0dSSimon Glass 	env_mmc_orig_hwpart = mmc_get_blk_desc(mmc)->hwpart;
1450649cd0dSSimon Glass 	ret = blk_select_hwpart_devnum(IF_TYPE_MMC, dev, part);
1460649cd0dSSimon Glass 	if (ret)
1470649cd0dSSimon Glass 		puts("MMC partition switch failed\n");
1480649cd0dSSimon Glass 
1490649cd0dSSimon Glass 	return ret;
1500649cd0dSSimon Glass }
1510649cd0dSSimon Glass #else
mmc_set_env_part(struct mmc * mmc)1520649cd0dSSimon Glass static inline int mmc_set_env_part(struct mmc *mmc) {return 0; };
1530649cd0dSSimon Glass #endif
1540649cd0dSSimon Glass 
init_mmc_for_env(struct mmc * mmc)1550649cd0dSSimon Glass static const char *init_mmc_for_env(struct mmc *mmc)
1560649cd0dSSimon Glass {
1570649cd0dSSimon Glass 	if (!mmc)
158*c5d548a9SYaniv Levinsky 		return "No MMC card found";
1590649cd0dSSimon Glass 
160d48b8d11SSjoerd Simons #if CONFIG_IS_ENABLED(BLK)
1610649cd0dSSimon Glass 	struct udevice *dev;
1620649cd0dSSimon Glass 
1630649cd0dSSimon Glass 	if (blk_get_from_parent(mmc->dev, &dev))
164*c5d548a9SYaniv Levinsky 		return "No block device";
1650649cd0dSSimon Glass #else
1660649cd0dSSimon Glass 	if (mmc_init(mmc))
167*c5d548a9SYaniv Levinsky 		return "MMC init failed";
1680649cd0dSSimon Glass #endif
1690649cd0dSSimon Glass 	if (mmc_set_env_part(mmc))
170*c5d548a9SYaniv Levinsky 		return "MMC partition switch failed";
1710649cd0dSSimon Glass 
1720649cd0dSSimon Glass 	return NULL;
1730649cd0dSSimon Glass }
1740649cd0dSSimon Glass 
fini_mmc_for_env(struct mmc * mmc)1750649cd0dSSimon Glass static void fini_mmc_for_env(struct mmc *mmc)
1760649cd0dSSimon Glass {
1770649cd0dSSimon Glass #ifdef CONFIG_SYS_MMC_ENV_PART
1780649cd0dSSimon Glass 	int dev = mmc_get_env_dev();
1790649cd0dSSimon Glass 
1800649cd0dSSimon Glass 	blk_select_hwpart_devnum(IF_TYPE_MMC, dev, env_mmc_orig_hwpart);
1810649cd0dSSimon Glass #endif
1820649cd0dSSimon Glass }
1830649cd0dSSimon Glass 
184e5bce247SSimon Glass #if defined(CONFIG_CMD_SAVEENV) && !defined(CONFIG_SPL_BUILD)
write_env(struct mmc * mmc,unsigned long size,unsigned long offset,const void * buffer)1850649cd0dSSimon Glass static inline int write_env(struct mmc *mmc, unsigned long size,
1860649cd0dSSimon Glass 			    unsigned long offset, const void *buffer)
1870649cd0dSSimon Glass {
1880649cd0dSSimon Glass 	uint blk_start, blk_cnt, n;
1890649cd0dSSimon Glass 	struct blk_desc *desc = mmc_get_blk_desc(mmc);
1900649cd0dSSimon Glass 
1910649cd0dSSimon Glass 	blk_start	= ALIGN(offset, mmc->write_bl_len) / mmc->write_bl_len;
1920649cd0dSSimon Glass 	blk_cnt		= ALIGN(size, mmc->write_bl_len) / mmc->write_bl_len;
1930649cd0dSSimon Glass 
1940649cd0dSSimon Glass 	n = blk_dwrite(desc, blk_start, blk_cnt, (u_char *)buffer);
1950649cd0dSSimon Glass 
1960649cd0dSSimon Glass 	return (n == blk_cnt) ? 0 : -1;
1970649cd0dSSimon Glass }
1980649cd0dSSimon Glass 
env_mmc_save(void)199e5bce247SSimon Glass static int env_mmc_save(void)
2000649cd0dSSimon Glass {
2010649cd0dSSimon Glass 	ALLOC_CACHE_ALIGN_BUFFER(env_t, env_new, 1);
2020649cd0dSSimon Glass 	int dev = mmc_get_env_dev();
2030649cd0dSSimon Glass 	struct mmc *mmc = find_mmc_device(dev);
2040649cd0dSSimon Glass 	u32	offset;
2050649cd0dSSimon Glass 	int	ret, copy = 0;
2060649cd0dSSimon Glass 	const char *errmsg;
2070649cd0dSSimon Glass 
2080649cd0dSSimon Glass 	errmsg = init_mmc_for_env(mmc);
2090649cd0dSSimon Glass 	if (errmsg) {
2100649cd0dSSimon Glass 		printf("%s\n", errmsg);
2110649cd0dSSimon Glass 		return 1;
2120649cd0dSSimon Glass 	}
2130649cd0dSSimon Glass 
2140649cd0dSSimon Glass 	ret = env_export(env_new);
2150649cd0dSSimon Glass 	if (ret)
2160649cd0dSSimon Glass 		goto fini;
2170649cd0dSSimon Glass 
2180649cd0dSSimon Glass #ifdef CONFIG_ENV_OFFSET_REDUND
219203e94f6SSimon Glass 	if (gd->env_valid == ENV_VALID)
2200649cd0dSSimon Glass 		copy = 1;
2210649cd0dSSimon Glass #endif
2220649cd0dSSimon Glass 
2230649cd0dSSimon Glass 	if (mmc_get_env_addr(mmc, copy, &offset)) {
2240649cd0dSSimon Glass 		ret = 1;
2250649cd0dSSimon Glass 		goto fini;
2260649cd0dSSimon Glass 	}
2270649cd0dSSimon Glass 
2280649cd0dSSimon Glass 	printf("Writing to %sMMC(%d)... ", copy ? "redundant " : "", dev);
2290649cd0dSSimon Glass 	if (write_env(mmc, CONFIG_ENV_SIZE, offset, (u_char *)env_new)) {
2300649cd0dSSimon Glass 		puts("failed\n");
2310649cd0dSSimon Glass 		ret = 1;
2320649cd0dSSimon Glass 		goto fini;
2330649cd0dSSimon Glass 	}
2340649cd0dSSimon Glass 
2350649cd0dSSimon Glass 	ret = 0;
2360649cd0dSSimon Glass 
2370649cd0dSSimon Glass #ifdef CONFIG_ENV_OFFSET_REDUND
238203e94f6SSimon Glass 	gd->env_valid = gd->env_valid == ENV_REDUND ? ENV_VALID : ENV_REDUND;
2390649cd0dSSimon Glass #endif
2400649cd0dSSimon Glass 
2410649cd0dSSimon Glass fini:
2420649cd0dSSimon Glass 	fini_mmc_for_env(mmc);
2430649cd0dSSimon Glass 	return ret;
2440649cd0dSSimon Glass }
245e5bce247SSimon Glass #endif /* CONFIG_CMD_SAVEENV && !CONFIG_SPL_BUILD */
2460649cd0dSSimon Glass 
read_env(struct mmc * mmc,unsigned long size,unsigned long offset,const void * buffer)2470649cd0dSSimon Glass static inline int read_env(struct mmc *mmc, unsigned long size,
2480649cd0dSSimon Glass 			   unsigned long offset, const void *buffer)
2490649cd0dSSimon Glass {
2500649cd0dSSimon Glass 	uint blk_start, blk_cnt, n;
2510649cd0dSSimon Glass 	struct blk_desc *desc = mmc_get_blk_desc(mmc);
2520649cd0dSSimon Glass 
2530649cd0dSSimon Glass 	blk_start	= ALIGN(offset, mmc->read_bl_len) / mmc->read_bl_len;
2540649cd0dSSimon Glass 	blk_cnt		= ALIGN(size, mmc->read_bl_len) / mmc->read_bl_len;
2550649cd0dSSimon Glass 
2560649cd0dSSimon Glass 	n = blk_dread(desc, blk_start, blk_cnt, (uchar *)buffer);
2570649cd0dSSimon Glass 
2580649cd0dSSimon Glass 	return (n == blk_cnt) ? 0 : -1;
2590649cd0dSSimon Glass }
2600649cd0dSSimon Glass 
2610649cd0dSSimon Glass #ifdef CONFIG_ENV_OFFSET_REDUND
env_mmc_load(void)262c5951991SSimon Glass static int env_mmc_load(void)
2630649cd0dSSimon Glass {
2640649cd0dSSimon Glass #if !defined(ENV_IS_EMBEDDED)
2650649cd0dSSimon Glass 	struct mmc *mmc;
2660649cd0dSSimon Glass 	u32 offset1, offset2;
2670649cd0dSSimon Glass 	int read1_fail = 0, read2_fail = 0;
2680649cd0dSSimon Glass 	int ret;
2690649cd0dSSimon Glass 	int dev = mmc_get_env_dev();
2700649cd0dSSimon Glass 	const char *errmsg = NULL;
2710649cd0dSSimon Glass 
2720649cd0dSSimon Glass 	ALLOC_CACHE_ALIGN_BUFFER(env_t, tmp_env1, 1);
2730649cd0dSSimon Glass 	ALLOC_CACHE_ALIGN_BUFFER(env_t, tmp_env2, 1);
2740649cd0dSSimon Glass 
27526862b4aSFaiz Abbas 	mmc_initialize(NULL);
27626862b4aSFaiz Abbas 
2770649cd0dSSimon Glass 	mmc = find_mmc_device(dev);
2780649cd0dSSimon Glass 
2790649cd0dSSimon Glass 	errmsg = init_mmc_for_env(mmc);
2800649cd0dSSimon Glass 	if (errmsg) {
281c5951991SSimon Glass 		ret = -EIO;
2820649cd0dSSimon Glass 		goto err;
2830649cd0dSSimon Glass 	}
2840649cd0dSSimon Glass 
2850649cd0dSSimon Glass 	if (mmc_get_env_addr(mmc, 0, &offset1) ||
2860649cd0dSSimon Glass 	    mmc_get_env_addr(mmc, 1, &offset2)) {
287c5951991SSimon Glass 		ret = -EIO;
2880649cd0dSSimon Glass 		goto fini;
2890649cd0dSSimon Glass 	}
2900649cd0dSSimon Glass 
2910649cd0dSSimon Glass 	read1_fail = read_env(mmc, CONFIG_ENV_SIZE, offset1, tmp_env1);
2920649cd0dSSimon Glass 	read2_fail = read_env(mmc, CONFIG_ENV_SIZE, offset2, tmp_env2);
2930649cd0dSSimon Glass 
29431f044bdSSimon Goldschmidt 	ret = env_import_redund((char *)tmp_env1, read1_fail, (char *)tmp_env2,
29531f044bdSSimon Goldschmidt 				read2_fail);
2960649cd0dSSimon Glass 
2970649cd0dSSimon Glass fini:
2980649cd0dSSimon Glass 	fini_mmc_for_env(mmc);
2990649cd0dSSimon Glass err:
3000649cd0dSSimon Glass 	if (ret)
301*c5d548a9SYaniv Levinsky 		set_default_env(errmsg, 0);
302c5951991SSimon Glass 
3030649cd0dSSimon Glass #endif
304c5951991SSimon Glass 	return ret;
3050649cd0dSSimon Glass }
3060649cd0dSSimon Glass #else /* ! CONFIG_ENV_OFFSET_REDUND */
env_mmc_load(void)307c5951991SSimon Glass static int env_mmc_load(void)
3080649cd0dSSimon Glass {
3090649cd0dSSimon Glass #if !defined(ENV_IS_EMBEDDED)
3100649cd0dSSimon Glass 	ALLOC_CACHE_ALIGN_BUFFER(char, buf, CONFIG_ENV_SIZE);
3110649cd0dSSimon Glass 	struct mmc *mmc;
3120649cd0dSSimon Glass 	u32 offset;
3130649cd0dSSimon Glass 	int ret;
3140649cd0dSSimon Glass 	int dev = mmc_get_env_dev();
3150649cd0dSSimon Glass 	const char *errmsg;
3160649cd0dSSimon Glass 
3170649cd0dSSimon Glass 	mmc = find_mmc_device(dev);
3180649cd0dSSimon Glass 
3190649cd0dSSimon Glass 	errmsg = init_mmc_for_env(mmc);
3200649cd0dSSimon Glass 	if (errmsg) {
321c5951991SSimon Glass 		ret = -EIO;
3220649cd0dSSimon Glass 		goto err;
3230649cd0dSSimon Glass 	}
3240649cd0dSSimon Glass 
3250649cd0dSSimon Glass 	if (mmc_get_env_addr(mmc, 0, &offset)) {
326c5951991SSimon Glass 		ret = -EIO;
3270649cd0dSSimon Glass 		goto fini;
3280649cd0dSSimon Glass 	}
3290649cd0dSSimon Glass 
3300649cd0dSSimon Glass 	if (read_env(mmc, CONFIG_ENV_SIZE, offset, buf)) {
3310649cd0dSSimon Glass 		errmsg = "!read failed";
332c5951991SSimon Glass 		ret = -EIO;
3330649cd0dSSimon Glass 		goto fini;
3340649cd0dSSimon Glass 	}
3350649cd0dSSimon Glass 
3362166ebf7SSimon Goldschmidt 	ret = env_import(buf, 1);
3370649cd0dSSimon Glass 
3380649cd0dSSimon Glass fini:
3390649cd0dSSimon Glass 	fini_mmc_for_env(mmc);
3400649cd0dSSimon Glass err:
3410649cd0dSSimon Glass 	if (ret)
342*c5d548a9SYaniv Levinsky 		set_default_env(errmsg, 0);
3430649cd0dSSimon Glass #endif
344c5951991SSimon Glass 	return ret;
3450649cd0dSSimon Glass }
3460649cd0dSSimon Glass #endif /* CONFIG_ENV_OFFSET_REDUND */
3474415f1d1SSimon Glass 
3484415f1d1SSimon Glass U_BOOT_ENV_LOCATION(mmc) = {
3494415f1d1SSimon Glass 	.location	= ENVL_MMC,
350ac358bebSSimon Glass 	ENV_NAME("MMC")
351e5bce247SSimon Glass 	.load		= env_mmc_load,
3524415f1d1SSimon Glass #ifndef CONFIG_SPL_BUILD
353e5bce247SSimon Glass 	.save		= env_save_ptr(env_mmc_save),
3544415f1d1SSimon Glass #endif
3554415f1d1SSimon Glass };
356