xref: /openbmc/u-boot/env/env.c (revision 40c08a68)
1c9d728ddSSimon Glass /*
2c9d728ddSSimon Glass  * Copyright (C) 2017 Google, Inc
3c9d728ddSSimon Glass  * Written by Simon Glass <sjg@chromium.org>
4c9d728ddSSimon Glass  *
5c9d728ddSSimon Glass  * SPDX-License-Identifier:     GPL-2.0+
6c9d728ddSSimon Glass  */
7c9d728ddSSimon Glass 
8c9d728ddSSimon Glass #include <common.h>
9c9d728ddSSimon Glass #include <environment.h>
10c9d728ddSSimon Glass 
11c9d728ddSSimon Glass DECLARE_GLOBAL_DATA_PTR;
12c9d728ddSSimon Glass 
1352746c43SMaxime Ripard static struct env_driver *_env_driver_lookup(enum env_location loc)
14c9d728ddSSimon Glass {
15c9d728ddSSimon Glass 	struct env_driver *drv;
16c9d728ddSSimon Glass 	const int n_ents = ll_entry_count(struct env_driver, env_driver);
17c9d728ddSSimon Glass 	struct env_driver *entry;
18c9d728ddSSimon Glass 
19c9d728ddSSimon Glass 	drv = ll_entry_start(struct env_driver, env_driver);
20c9d728ddSSimon Glass 	for (entry = drv; entry != drv + n_ents; entry++) {
21c9d728ddSSimon Glass 		if (loc == entry->location)
22c9d728ddSSimon Glass 			return entry;
23c9d728ddSSimon Glass 	}
24c9d728ddSSimon Glass 
25c9d728ddSSimon Glass 	/* Not found */
26c9d728ddSSimon Glass 	return NULL;
27c9d728ddSSimon Glass }
28c9d728ddSSimon Glass 
297d714a24SMaxime Ripard static enum env_location env_locations[] = {
307d714a24SMaxime Ripard #ifdef CONFIG_ENV_IS_IN_EEPROM
317d714a24SMaxime Ripard 	ENVL_EEPROM,
327d714a24SMaxime Ripard #endif
337d714a24SMaxime Ripard #ifdef CONFIG_ENV_IS_IN_EXT4
347d714a24SMaxime Ripard 	ENVL_EXT4,
357d714a24SMaxime Ripard #endif
367d714a24SMaxime Ripard #ifdef CONFIG_ENV_IS_IN_FAT
377d714a24SMaxime Ripard 	ENVL_FAT,
387d714a24SMaxime Ripard #endif
397d714a24SMaxime Ripard #ifdef CONFIG_ENV_IS_IN_FLASH
407d714a24SMaxime Ripard 	ENVL_FLASH,
417d714a24SMaxime Ripard #endif
427d714a24SMaxime Ripard #ifdef CONFIG_ENV_IS_IN_MMC
437d714a24SMaxime Ripard 	ENVL_MMC,
447d714a24SMaxime Ripard #endif
457d714a24SMaxime Ripard #ifdef CONFIG_ENV_IS_IN_NAND
467d714a24SMaxime Ripard 	ENVL_NAND,
477d714a24SMaxime Ripard #endif
487d714a24SMaxime Ripard #ifdef CONFIG_ENV_IS_IN_NVRAM
497d714a24SMaxime Ripard 	ENVL_NVRAM,
507d714a24SMaxime Ripard #endif
517d714a24SMaxime Ripard #ifdef CONFIG_ENV_IS_IN_REMOTE
527d714a24SMaxime Ripard 	ENVL_REMOTE,
537d714a24SMaxime Ripard #endif
547d714a24SMaxime Ripard #ifdef CONFIG_ENV_IS_IN_SPI_FLASH
557d714a24SMaxime Ripard 	ENVL_SPI_FLASH,
567d714a24SMaxime Ripard #endif
577d714a24SMaxime Ripard #ifdef CONFIG_ENV_IS_IN_UBI
587d714a24SMaxime Ripard 	ENVL_UBI,
597d714a24SMaxime Ripard #endif
607d714a24SMaxime Ripard #ifdef CONFIG_ENV_IS_NOWHERE
617d714a24SMaxime Ripard 	ENVL_NOWHERE,
627d714a24SMaxime Ripard #endif
637d714a24SMaxime Ripard };
647d714a24SMaxime Ripard 
657d714a24SMaxime Ripard static enum env_location env_load_location = ENVL_UNKNOWN;
667d714a24SMaxime Ripard 
671d446087SMaxime Ripard static bool env_has_inited(enum env_location location)
681d446087SMaxime Ripard {
691d446087SMaxime Ripard 	return gd->env_has_init & BIT(location);
701d446087SMaxime Ripard }
711d446087SMaxime Ripard 
721d446087SMaxime Ripard static void env_set_inited(enum env_location location)
731d446087SMaxime Ripard {
741d446087SMaxime Ripard 	/*
751d446087SMaxime Ripard 	 * We're using a 32-bits bitmask stored in gd (env_has_init)
761d446087SMaxime Ripard 	 * using the above enum value as the bit index. We need to
771d446087SMaxime Ripard 	 * make sure that we're not overflowing it.
781d446087SMaxime Ripard 	 */
791d446087SMaxime Ripard 	BUILD_BUG_ON(ARRAY_SIZE(env_locations) > BITS_PER_LONG);
801d446087SMaxime Ripard 
811d446087SMaxime Ripard 	gd->env_has_init |= BIT(location);
821d446087SMaxime Ripard }
831d446087SMaxime Ripard 
848a3a7e22SMaxime Ripard /**
858a3a7e22SMaxime Ripard  * env_get_location() - Returns the best env location for a board
868a3a7e22SMaxime Ripard  * @op: operations performed on the environment
878a3a7e22SMaxime Ripard  * @prio: priority between the multiple environments, 0 being the
888a3a7e22SMaxime Ripard  *        highest priority
898a3a7e22SMaxime Ripard  *
908a3a7e22SMaxime Ripard  * This will return the preferred environment for the given priority.
91*40c08a68SMaxime Ripard  * This is overridable by boards if they need to.
928a3a7e22SMaxime Ripard  *
938a3a7e22SMaxime Ripard  * All implementations are free to use the operation, the priority and
948a3a7e22SMaxime Ripard  * any other data relevant to their choice, but must take into account
958a3a7e22SMaxime Ripard  * the fact that the lowest prority (0) is the most important location
968a3a7e22SMaxime Ripard  * in the system. The following locations should be returned by order
978a3a7e22SMaxime Ripard  * of descending priorities, from the highest to the lowest priority.
988a3a7e22SMaxime Ripard  *
998a3a7e22SMaxime Ripard  * Returns:
1008a3a7e22SMaxime Ripard  * an enum env_location value on success, a negative error code otherwise
1018a3a7e22SMaxime Ripard  */
102*40c08a68SMaxime Ripard __weak enum env_location env_get_location(enum env_operation op, int prio)
103c9d728ddSSimon Glass {
1047d714a24SMaxime Ripard 	switch (op) {
1057d714a24SMaxime Ripard 	case ENVOP_GET_CHAR:
1067d714a24SMaxime Ripard 	case ENVOP_INIT:
1077d714a24SMaxime Ripard 	case ENVOP_LOAD:
1087d714a24SMaxime Ripard 		if (prio >= ARRAY_SIZE(env_locations))
1098a3a7e22SMaxime Ripard 			return ENVL_UNKNOWN;
1108a3a7e22SMaxime Ripard 
1117d714a24SMaxime Ripard 		env_load_location = env_locations[prio];
1127d714a24SMaxime Ripard 		return env_load_location;
1137d714a24SMaxime Ripard 
1147d714a24SMaxime Ripard 	case ENVOP_SAVE:
1157d714a24SMaxime Ripard 		return env_load_location;
1167d714a24SMaxime Ripard 	}
1177d714a24SMaxime Ripard 
118c9d728ddSSimon Glass 	return ENVL_UNKNOWN;
119c9d728ddSSimon Glass }
120c9d728ddSSimon Glass 
1218a3a7e22SMaxime Ripard 
1228a3a7e22SMaxime Ripard /**
1238a3a7e22SMaxime Ripard  * env_driver_lookup() - Finds the most suited environment location
1248a3a7e22SMaxime Ripard  * @op: operations performed on the environment
1258a3a7e22SMaxime Ripard  * @prio: priority between the multiple environments, 0 being the
1268a3a7e22SMaxime Ripard  *        highest priority
1278a3a7e22SMaxime Ripard  *
1288a3a7e22SMaxime Ripard  * This will try to find the available environment with the highest
1298a3a7e22SMaxime Ripard  * priority in the system.
1308a3a7e22SMaxime Ripard  *
1318a3a7e22SMaxime Ripard  * Returns:
1328a3a7e22SMaxime Ripard  * NULL on error, a pointer to a struct env_driver otherwise
1338a3a7e22SMaxime Ripard  */
1348a3a7e22SMaxime Ripard static struct env_driver *env_driver_lookup(enum env_operation op, int prio)
135c9d728ddSSimon Glass {
1368a3a7e22SMaxime Ripard 	enum env_location loc = env_get_location(op, prio);
137c9d728ddSSimon Glass 	struct env_driver *drv;
138c9d728ddSSimon Glass 
1398a3a7e22SMaxime Ripard 	if (loc == ENVL_UNKNOWN)
1408a3a7e22SMaxime Ripard 		return NULL;
1418a3a7e22SMaxime Ripard 
14252746c43SMaxime Ripard 	drv = _env_driver_lookup(loc);
143c9d728ddSSimon Glass 	if (!drv) {
144c9d728ddSSimon Glass 		debug("%s: No environment driver for location %d\n", __func__,
145c9d728ddSSimon Glass 		      loc);
146c9d728ddSSimon Glass 		return NULL;
147c9d728ddSSimon Glass 	}
148c9d728ddSSimon Glass 
149c9d728ddSSimon Glass 	return drv;
150c9d728ddSSimon Glass }
151c9d728ddSSimon Glass 
152a69d0f60SSimon Glass int env_get_char(int index)
153c9d728ddSSimon Glass {
1548a3a7e22SMaxime Ripard 	struct env_driver *drv;
1558a3a7e22SMaxime Ripard 	int prio;
156c9d728ddSSimon Glass 
1572d7cb5b4SSimon Glass 	if (gd->env_valid == ENV_INVALID)
158a69d0f60SSimon Glass 		return default_environment[index];
1598a3a7e22SMaxime Ripard 
1608a3a7e22SMaxime Ripard 	for (prio = 0; (drv = env_driver_lookup(ENVOP_GET_CHAR, prio)); prio++) {
1618a3a7e22SMaxime Ripard 		int ret;
1628a3a7e22SMaxime Ripard 
163c9d728ddSSimon Glass 		if (!drv->get_char)
1648a3a7e22SMaxime Ripard 			continue;
1658a3a7e22SMaxime Ripard 
1661d446087SMaxime Ripard 		if (!env_has_inited(drv->location))
1671d446087SMaxime Ripard 			continue;
1681d446087SMaxime Ripard 
169c9d728ddSSimon Glass 		ret = drv->get_char(index);
1708a3a7e22SMaxime Ripard 		if (!ret)
1718a3a7e22SMaxime Ripard 			return 0;
1728a3a7e22SMaxime Ripard 
1738a3a7e22SMaxime Ripard 		debug("%s: Environment %s failed to load (err=%d)\n", __func__,
1748a3a7e22SMaxime Ripard 		      drv->name, ret);
175c9d728ddSSimon Glass 	}
176c9d728ddSSimon Glass 
1778a3a7e22SMaxime Ripard 	return -ENODEV;
178c9d728ddSSimon Glass }
179c9d728ddSSimon Glass 
180c9d728ddSSimon Glass int env_load(void)
181c9d728ddSSimon Glass {
1828a3a7e22SMaxime Ripard 	struct env_driver *drv;
1838a3a7e22SMaxime Ripard 	int prio;
184c9d728ddSSimon Glass 
1858a3a7e22SMaxime Ripard 	for (prio = 0; (drv = env_driver_lookup(ENVOP_LOAD, prio)); prio++) {
1868a3a7e22SMaxime Ripard 		int ret;
1878a3a7e22SMaxime Ripard 
188c9d728ddSSimon Glass 		if (!drv->load)
1898a3a7e22SMaxime Ripard 			continue;
1908a3a7e22SMaxime Ripard 
1911d446087SMaxime Ripard 		if (!env_has_inited(drv->location))
1921d446087SMaxime Ripard 			continue;
1931d446087SMaxime Ripard 
1943574ba01SMaxime Ripard 		printf("Loading Environment from %s... ", drv->name);
195c55d8b94SSimon Glass 		ret = drv->load();
1963574ba01SMaxime Ripard 		if (ret)
1973574ba01SMaxime Ripard 			printf("Failed (%d)\n", ret);
1983574ba01SMaxime Ripard 		else
1993574ba01SMaxime Ripard 			printf("OK\n");
2003574ba01SMaxime Ripard 
2018a3a7e22SMaxime Ripard 		if (!ret)
2028a3a7e22SMaxime Ripard 			return 0;
203c9d728ddSSimon Glass 	}
204c9d728ddSSimon Glass 
2058a3a7e22SMaxime Ripard 	return -ENODEV;
206c9d728ddSSimon Glass }
207c9d728ddSSimon Glass 
208c9d728ddSSimon Glass int env_save(void)
209c9d728ddSSimon Glass {
2108a3a7e22SMaxime Ripard 	struct env_driver *drv;
2118a3a7e22SMaxime Ripard 	int prio;
2128a3a7e22SMaxime Ripard 
2138a3a7e22SMaxime Ripard 	for (prio = 0; (drv = env_driver_lookup(ENVOP_SAVE, prio)); prio++) {
214c9d728ddSSimon Glass 		int ret;
215c9d728ddSSimon Glass 
216c9d728ddSSimon Glass 		if (!drv->save)
2178a3a7e22SMaxime Ripard 			continue;
2189c24dfb2SMaxime Ripard 
2191d446087SMaxime Ripard 		if (!env_has_inited(drv->location))
2201d446087SMaxime Ripard 			continue;
2211d446087SMaxime Ripard 
2229efac3c8SMaxime Ripard 		printf("Saving Environment to %s... ", drv->name);
223c9d728ddSSimon Glass 		ret = drv->save();
2243574ba01SMaxime Ripard 		if (ret)
2253574ba01SMaxime Ripard 			printf("Failed (%d)\n", ret);
2263574ba01SMaxime Ripard 		else
2273574ba01SMaxime Ripard 			printf("OK\n");
2283574ba01SMaxime Ripard 
2298a3a7e22SMaxime Ripard 		if (!ret)
2308a3a7e22SMaxime Ripard 			return 0;
231c9d728ddSSimon Glass 	}
232c9d728ddSSimon Glass 
2338a3a7e22SMaxime Ripard 	return -ENODEV;
234c9d728ddSSimon Glass }
235c9d728ddSSimon Glass 
2366eeae424SSimon Glass int env_init(void)
237c9d728ddSSimon Glass {
2388a3a7e22SMaxime Ripard 	struct env_driver *drv;
2397938822aSSimon Glass 	int ret = -ENOENT;
2408a3a7e22SMaxime Ripard 	int prio;
241c9d728ddSSimon Glass 
2428a3a7e22SMaxime Ripard 	for (prio = 0; (drv = env_driver_lookup(ENVOP_INIT, prio)); prio++) {
2431d446087SMaxime Ripard 		if (!drv->init || !(ret = drv->init()))
2441d446087SMaxime Ripard 			env_set_inited(drv->location);
2458a3a7e22SMaxime Ripard 
2461d446087SMaxime Ripard 		debug("%s: Environment %s init done (ret=%d)\n", __func__,
2478a3a7e22SMaxime Ripard 		      drv->name, ret);
2488a3a7e22SMaxime Ripard 	}
2498a3a7e22SMaxime Ripard 
2508a3a7e22SMaxime Ripard 	if (!prio)
2518a3a7e22SMaxime Ripard 		return -ENODEV;
2528a3a7e22SMaxime Ripard 
2537938822aSSimon Glass 	if (ret == -ENOENT) {
2547938822aSSimon Glass 		gd->env_addr = (ulong)&default_environment[0];
255eeba55cbSTom Rini 		gd->env_valid = ENV_VALID;
2567938822aSSimon Glass 
2577938822aSSimon Glass 		return 0;
258c9d728ddSSimon Glass 	}
259c9d728ddSSimon Glass 
2608a3a7e22SMaxime Ripard 	return ret;
261c9d728ddSSimon Glass }
262