xref: /openbmc/u-boot/env/env.c (revision 7d714a24)
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 
29*7d714a24SMaxime Ripard static enum env_location env_locations[] = {
30*7d714a24SMaxime Ripard #ifdef CONFIG_ENV_IS_IN_EEPROM
31*7d714a24SMaxime Ripard 	ENVL_EEPROM,
32*7d714a24SMaxime Ripard #endif
33*7d714a24SMaxime Ripard #ifdef CONFIG_ENV_IS_IN_EXT4
34*7d714a24SMaxime Ripard 	ENVL_EXT4,
35*7d714a24SMaxime Ripard #endif
36*7d714a24SMaxime Ripard #ifdef CONFIG_ENV_IS_IN_FAT
37*7d714a24SMaxime Ripard 	ENVL_FAT,
38*7d714a24SMaxime Ripard #endif
39*7d714a24SMaxime Ripard #ifdef CONFIG_ENV_IS_IN_FLASH
40*7d714a24SMaxime Ripard 	ENVL_FLASH,
41*7d714a24SMaxime Ripard #endif
42*7d714a24SMaxime Ripard #ifdef CONFIG_ENV_IS_IN_MMC
43*7d714a24SMaxime Ripard 	ENVL_MMC,
44*7d714a24SMaxime Ripard #endif
45*7d714a24SMaxime Ripard #ifdef CONFIG_ENV_IS_IN_NAND
46*7d714a24SMaxime Ripard 	ENVL_NAND,
47*7d714a24SMaxime Ripard #endif
48*7d714a24SMaxime Ripard #ifdef CONFIG_ENV_IS_IN_NVRAM
49*7d714a24SMaxime Ripard 	ENVL_NVRAM,
50*7d714a24SMaxime Ripard #endif
51*7d714a24SMaxime Ripard #ifdef CONFIG_ENV_IS_IN_REMOTE
52*7d714a24SMaxime Ripard 	ENVL_REMOTE,
53*7d714a24SMaxime Ripard #endif
54*7d714a24SMaxime Ripard #ifdef CONFIG_ENV_IS_IN_SPI_FLASH
55*7d714a24SMaxime Ripard 	ENVL_SPI_FLASH,
56*7d714a24SMaxime Ripard #endif
57*7d714a24SMaxime Ripard #ifdef CONFIG_ENV_IS_IN_UBI
58*7d714a24SMaxime Ripard 	ENVL_UBI,
59*7d714a24SMaxime Ripard #endif
60*7d714a24SMaxime Ripard #ifdef CONFIG_ENV_IS_NOWHERE
61*7d714a24SMaxime Ripard 	ENVL_NOWHERE,
62*7d714a24SMaxime Ripard #endif
63*7d714a24SMaxime Ripard };
64*7d714a24SMaxime Ripard 
65*7d714a24SMaxime Ripard static enum env_location env_load_location = ENVL_UNKNOWN;
66*7d714a24SMaxime Ripard 
678a3a7e22SMaxime Ripard /**
688a3a7e22SMaxime Ripard  * env_get_location() - Returns the best env location for a board
698a3a7e22SMaxime Ripard  * @op: operations performed on the environment
708a3a7e22SMaxime Ripard  * @prio: priority between the multiple environments, 0 being the
718a3a7e22SMaxime Ripard  *        highest priority
728a3a7e22SMaxime Ripard  *
738a3a7e22SMaxime Ripard  * This will return the preferred environment for the given priority.
748a3a7e22SMaxime Ripard  *
758a3a7e22SMaxime Ripard  * All implementations are free to use the operation, the priority and
768a3a7e22SMaxime Ripard  * any other data relevant to their choice, but must take into account
778a3a7e22SMaxime Ripard  * the fact that the lowest prority (0) is the most important location
788a3a7e22SMaxime Ripard  * in the system. The following locations should be returned by order
798a3a7e22SMaxime Ripard  * of descending priorities, from the highest to the lowest priority.
808a3a7e22SMaxime Ripard  *
818a3a7e22SMaxime Ripard  * Returns:
828a3a7e22SMaxime Ripard  * an enum env_location value on success, a negative error code otherwise
838a3a7e22SMaxime Ripard  */
848a3a7e22SMaxime Ripard static enum env_location env_get_location(enum env_operation op, int prio)
85c9d728ddSSimon Glass {
86*7d714a24SMaxime Ripard 	switch (op) {
87*7d714a24SMaxime Ripard 	case ENVOP_GET_CHAR:
88*7d714a24SMaxime Ripard 	case ENVOP_INIT:
89*7d714a24SMaxime Ripard 	case ENVOP_LOAD:
90*7d714a24SMaxime Ripard 		if (prio >= ARRAY_SIZE(env_locations))
918a3a7e22SMaxime Ripard 			return ENVL_UNKNOWN;
928a3a7e22SMaxime Ripard 
93*7d714a24SMaxime Ripard 		env_load_location = env_locations[prio];
94*7d714a24SMaxime Ripard 		return env_load_location;
95*7d714a24SMaxime Ripard 
96*7d714a24SMaxime Ripard 	case ENVOP_SAVE:
97*7d714a24SMaxime Ripard 		return env_load_location;
98*7d714a24SMaxime Ripard 	}
99*7d714a24SMaxime Ripard 
100c9d728ddSSimon Glass 	return ENVL_UNKNOWN;
101c9d728ddSSimon Glass }
102c9d728ddSSimon Glass 
1038a3a7e22SMaxime Ripard 
1048a3a7e22SMaxime Ripard /**
1058a3a7e22SMaxime Ripard  * env_driver_lookup() - Finds the most suited environment location
1068a3a7e22SMaxime Ripard  * @op: operations performed on the environment
1078a3a7e22SMaxime Ripard  * @prio: priority between the multiple environments, 0 being the
1088a3a7e22SMaxime Ripard  *        highest priority
1098a3a7e22SMaxime Ripard  *
1108a3a7e22SMaxime Ripard  * This will try to find the available environment with the highest
1118a3a7e22SMaxime Ripard  * priority in the system.
1128a3a7e22SMaxime Ripard  *
1138a3a7e22SMaxime Ripard  * Returns:
1148a3a7e22SMaxime Ripard  * NULL on error, a pointer to a struct env_driver otherwise
1158a3a7e22SMaxime Ripard  */
1168a3a7e22SMaxime Ripard static struct env_driver *env_driver_lookup(enum env_operation op, int prio)
117c9d728ddSSimon Glass {
1188a3a7e22SMaxime Ripard 	enum env_location loc = env_get_location(op, prio);
119c9d728ddSSimon Glass 	struct env_driver *drv;
120c9d728ddSSimon Glass 
1218a3a7e22SMaxime Ripard 	if (loc == ENVL_UNKNOWN)
1228a3a7e22SMaxime Ripard 		return NULL;
1238a3a7e22SMaxime Ripard 
12452746c43SMaxime Ripard 	drv = _env_driver_lookup(loc);
125c9d728ddSSimon Glass 	if (!drv) {
126c9d728ddSSimon Glass 		debug("%s: No environment driver for location %d\n", __func__,
127c9d728ddSSimon Glass 		      loc);
128c9d728ddSSimon Glass 		return NULL;
129c9d728ddSSimon Glass 	}
130c9d728ddSSimon Glass 
131c9d728ddSSimon Glass 	return drv;
132c9d728ddSSimon Glass }
133c9d728ddSSimon Glass 
134a69d0f60SSimon Glass int env_get_char(int index)
135c9d728ddSSimon Glass {
1368a3a7e22SMaxime Ripard 	struct env_driver *drv;
1378a3a7e22SMaxime Ripard 	int prio;
138c9d728ddSSimon Glass 
1392d7cb5b4SSimon Glass 	if (gd->env_valid == ENV_INVALID)
140a69d0f60SSimon Glass 		return default_environment[index];
1418a3a7e22SMaxime Ripard 
1428a3a7e22SMaxime Ripard 	for (prio = 0; (drv = env_driver_lookup(ENVOP_GET_CHAR, prio)); prio++) {
1438a3a7e22SMaxime Ripard 		int ret;
1448a3a7e22SMaxime Ripard 
145c9d728ddSSimon Glass 		if (!drv->get_char)
1468a3a7e22SMaxime Ripard 			continue;
1478a3a7e22SMaxime Ripard 
148c9d728ddSSimon Glass 		ret = drv->get_char(index);
1498a3a7e22SMaxime Ripard 		if (!ret)
1508a3a7e22SMaxime Ripard 			return 0;
1518a3a7e22SMaxime Ripard 
1528a3a7e22SMaxime Ripard 		debug("%s: Environment %s failed to load (err=%d)\n", __func__,
1538a3a7e22SMaxime Ripard 		      drv->name, ret);
154c9d728ddSSimon Glass 	}
155c9d728ddSSimon Glass 
1568a3a7e22SMaxime Ripard 	return -ENODEV;
157c9d728ddSSimon Glass }
158c9d728ddSSimon Glass 
159c9d728ddSSimon Glass int env_load(void)
160c9d728ddSSimon Glass {
1618a3a7e22SMaxime Ripard 	struct env_driver *drv;
1628a3a7e22SMaxime Ripard 	int prio;
163c9d728ddSSimon Glass 
1648a3a7e22SMaxime Ripard 	for (prio = 0; (drv = env_driver_lookup(ENVOP_LOAD, prio)); prio++) {
1658a3a7e22SMaxime Ripard 		int ret;
1668a3a7e22SMaxime Ripard 
167c9d728ddSSimon Glass 		if (!drv->load)
1688a3a7e22SMaxime Ripard 			continue;
1698a3a7e22SMaxime Ripard 
1703574ba01SMaxime Ripard 		printf("Loading Environment from %s... ", drv->name);
171c55d8b94SSimon Glass 		ret = drv->load();
1723574ba01SMaxime Ripard 		if (ret)
1733574ba01SMaxime Ripard 			printf("Failed (%d)\n", ret);
1743574ba01SMaxime Ripard 		else
1753574ba01SMaxime Ripard 			printf("OK\n");
1763574ba01SMaxime Ripard 
1778a3a7e22SMaxime Ripard 		if (!ret)
1788a3a7e22SMaxime Ripard 			return 0;
179c9d728ddSSimon Glass 	}
180c9d728ddSSimon Glass 
1818a3a7e22SMaxime Ripard 	return -ENODEV;
182c9d728ddSSimon Glass }
183c9d728ddSSimon Glass 
184c9d728ddSSimon Glass int env_save(void)
185c9d728ddSSimon Glass {
1868a3a7e22SMaxime Ripard 	struct env_driver *drv;
1878a3a7e22SMaxime Ripard 	int prio;
1888a3a7e22SMaxime Ripard 
1898a3a7e22SMaxime Ripard 	for (prio = 0; (drv = env_driver_lookup(ENVOP_SAVE, prio)); prio++) {
190c9d728ddSSimon Glass 		int ret;
191c9d728ddSSimon Glass 
192c9d728ddSSimon Glass 		if (!drv->save)
1938a3a7e22SMaxime Ripard 			continue;
1949c24dfb2SMaxime Ripard 
1959efac3c8SMaxime Ripard 		printf("Saving Environment to %s... ", drv->name);
196c9d728ddSSimon Glass 		ret = drv->save();
1973574ba01SMaxime Ripard 		if (ret)
1983574ba01SMaxime Ripard 			printf("Failed (%d)\n", ret);
1993574ba01SMaxime Ripard 		else
2003574ba01SMaxime Ripard 			printf("OK\n");
2013574ba01SMaxime Ripard 
2028a3a7e22SMaxime Ripard 		if (!ret)
2038a3a7e22SMaxime Ripard 			return 0;
204c9d728ddSSimon Glass 	}
205c9d728ddSSimon Glass 
2068a3a7e22SMaxime Ripard 	return -ENODEV;
207c9d728ddSSimon Glass }
208c9d728ddSSimon Glass 
2096eeae424SSimon Glass int env_init(void)
210c9d728ddSSimon Glass {
2118a3a7e22SMaxime Ripard 	struct env_driver *drv;
2127938822aSSimon Glass 	int ret = -ENOENT;
2138a3a7e22SMaxime Ripard 	int prio;
214c9d728ddSSimon Glass 
2158a3a7e22SMaxime Ripard 	for (prio = 0; (drv = env_driver_lookup(ENVOP_INIT, prio)); prio++) {
2168a3a7e22SMaxime Ripard 		if (!drv->init)
2178a3a7e22SMaxime Ripard 			continue;
2188a3a7e22SMaxime Ripard 
219c9d728ddSSimon Glass 		ret = drv->init();
2208a3a7e22SMaxime Ripard 		if (!ret)
2218a3a7e22SMaxime Ripard 			return 0;
2228a3a7e22SMaxime Ripard 
2238a3a7e22SMaxime Ripard 		debug("%s: Environment %s failed to init (err=%d)\n", __func__,
2248a3a7e22SMaxime Ripard 		      drv->name, ret);
2258a3a7e22SMaxime Ripard 	}
2268a3a7e22SMaxime Ripard 
2278a3a7e22SMaxime Ripard 	if (!prio)
2288a3a7e22SMaxime Ripard 		return -ENODEV;
2298a3a7e22SMaxime Ripard 
2307938822aSSimon Glass 	if (ret == -ENOENT) {
2317938822aSSimon Glass 		gd->env_addr = (ulong)&default_environment[0];
232eeba55cbSTom Rini 		gd->env_valid = ENV_VALID;
2337938822aSSimon Glass 
2347938822aSSimon Glass 		return 0;
235c9d728ddSSimon Glass 	}
236c9d728ddSSimon Glass 
2378a3a7e22SMaxime Ripard 	return ret;
238c9d728ddSSimon Glass }
239