blob: 90d65974d0c9e05c5d4133ca3f6b08f44f20cbdd [file] [log] [blame]
Simon Glass15e5a1a2017-08-03 12:22:00 -06001/*
2 * Copyright (C) 2017 Google, Inc
3 * Written by Simon Glass <sjg@chromium.org>
4 *
5 * SPDX-License-Identifier: GPL-2.0+
6 */
7
8#include <common.h>
9#include <environment.h>
10
11DECLARE_GLOBAL_DATA_PTR;
12
Siva Durga Prasad Paladugu75c65792018-04-13 07:57:21 +020013#if defined(CONFIG_NEEDS_MANUAL_RELOC)
14void env_fix_drivers(void)
15{
16 struct env_driver *drv;
17 const int n_ents = ll_entry_count(struct env_driver, env_driver);
18 struct env_driver *entry;
19
20 drv = ll_entry_start(struct env_driver, env_driver);
21 for (entry = drv; entry != drv + n_ents; entry++) {
22 if (entry->name)
23 entry->name += gd->reloc_off;
24 if (entry->load)
25 entry->load += gd->reloc_off;
26 if (entry->save)
27 entry->save += gd->reloc_off;
28 if (entry->init)
29 entry->init += gd->reloc_off;
30 }
31}
32#endif
33
Maxime Ripardb7da89a2018-01-23 21:16:51 +010034static struct env_driver *_env_driver_lookup(enum env_location loc)
Simon Glass15e5a1a2017-08-03 12:22:00 -060035{
36 struct env_driver *drv;
37 const int n_ents = ll_entry_count(struct env_driver, env_driver);
38 struct env_driver *entry;
39
40 drv = ll_entry_start(struct env_driver, env_driver);
41 for (entry = drv; entry != drv + n_ents; entry++) {
42 if (loc == entry->location)
43 return entry;
44 }
45
46 /* Not found */
47 return NULL;
48}
49
Maxime Ripard520cf802018-01-23 21:16:58 +010050static enum env_location env_locations[] = {
51#ifdef CONFIG_ENV_IS_IN_EEPROM
52 ENVL_EEPROM,
53#endif
54#ifdef CONFIG_ENV_IS_IN_EXT4
55 ENVL_EXT4,
56#endif
57#ifdef CONFIG_ENV_IS_IN_FAT
58 ENVL_FAT,
59#endif
60#ifdef CONFIG_ENV_IS_IN_FLASH
61 ENVL_FLASH,
62#endif
63#ifdef CONFIG_ENV_IS_IN_MMC
64 ENVL_MMC,
65#endif
66#ifdef CONFIG_ENV_IS_IN_NAND
67 ENVL_NAND,
68#endif
69#ifdef CONFIG_ENV_IS_IN_NVRAM
70 ENVL_NVRAM,
71#endif
72#ifdef CONFIG_ENV_IS_IN_REMOTE
73 ENVL_REMOTE,
74#endif
75#ifdef CONFIG_ENV_IS_IN_SPI_FLASH
76 ENVL_SPI_FLASH,
77#endif
78#ifdef CONFIG_ENV_IS_IN_UBI
79 ENVL_UBI,
80#endif
81#ifdef CONFIG_ENV_IS_NOWHERE
82 ENVL_NOWHERE,
83#endif
84};
85
Maxime Ripard2131c5e2018-01-23 21:16:59 +010086static bool env_has_inited(enum env_location location)
87{
88 return gd->env_has_init & BIT(location);
89}
90
91static void env_set_inited(enum env_location location)
92{
93 /*
94 * We're using a 32-bits bitmask stored in gd (env_has_init)
95 * using the above enum value as the bit index. We need to
96 * make sure that we're not overflowing it.
97 */
98 BUILD_BUG_ON(ARRAY_SIZE(env_locations) > BITS_PER_LONG);
99
100 gd->env_has_init |= BIT(location);
101}
102
Maxime Ripardfd3158e2018-01-23 21:16:52 +0100103/**
104 * env_get_location() - Returns the best env location for a board
105 * @op: operations performed on the environment
106 * @prio: priority between the multiple environments, 0 being the
107 * highest priority
108 *
109 * This will return the preferred environment for the given priority.
Maxime Ripard89448752018-01-23 21:17:02 +0100110 * This is overridable by boards if they need to.
Maxime Ripardfd3158e2018-01-23 21:16:52 +0100111 *
112 * All implementations are free to use the operation, the priority and
113 * any other data relevant to their choice, but must take into account
114 * the fact that the lowest prority (0) is the most important location
115 * in the system. The following locations should be returned by order
116 * of descending priorities, from the highest to the lowest priority.
117 *
118 * Returns:
119 * an enum env_location value on success, a negative error code otherwise
120 */
Maxime Ripard89448752018-01-23 21:17:02 +0100121__weak enum env_location env_get_location(enum env_operation op, int prio)
Simon Glass15e5a1a2017-08-03 12:22:00 -0600122{
Maxime Ripard520cf802018-01-23 21:16:58 +0100123 switch (op) {
124 case ENVOP_GET_CHAR:
125 case ENVOP_INIT:
126 case ENVOP_LOAD:
127 if (prio >= ARRAY_SIZE(env_locations))
128 return ENVL_UNKNOWN;
129
York Sun470947d2018-02-07 14:17:11 -0800130 gd->env_load_location = env_locations[prio];
131 return gd->env_load_location;
Maxime Ripard520cf802018-01-23 21:16:58 +0100132
133 case ENVOP_SAVE:
York Sun470947d2018-02-07 14:17:11 -0800134 return gd->env_load_location;
Maxime Ripard520cf802018-01-23 21:16:58 +0100135 }
Maxime Ripardfd3158e2018-01-23 21:16:52 +0100136
Maxime Ripard520cf802018-01-23 21:16:58 +0100137 return ENVL_UNKNOWN;
Simon Glass15e5a1a2017-08-03 12:22:00 -0600138}
139
Maxime Ripardfd3158e2018-01-23 21:16:52 +0100140
141/**
142 * env_driver_lookup() - Finds the most suited environment location
143 * @op: operations performed on the environment
144 * @prio: priority between the multiple environments, 0 being the
145 * highest priority
146 *
147 * This will try to find the available environment with the highest
148 * priority in the system.
149 *
150 * Returns:
151 * NULL on error, a pointer to a struct env_driver otherwise
152 */
153static struct env_driver *env_driver_lookup(enum env_operation op, int prio)
Simon Glass15e5a1a2017-08-03 12:22:00 -0600154{
Maxime Ripardfd3158e2018-01-23 21:16:52 +0100155 enum env_location loc = env_get_location(op, prio);
Simon Glass15e5a1a2017-08-03 12:22:00 -0600156 struct env_driver *drv;
157
Maxime Ripardfd3158e2018-01-23 21:16:52 +0100158 if (loc == ENVL_UNKNOWN)
159 return NULL;
160
Maxime Ripardb7da89a2018-01-23 21:16:51 +0100161 drv = _env_driver_lookup(loc);
Simon Glass15e5a1a2017-08-03 12:22:00 -0600162 if (!drv) {
163 debug("%s: No environment driver for location %d\n", __func__,
164 loc);
165 return NULL;
166 }
167
168 return drv;
169}
170
Goldschmidt Simon9b0d66b2018-02-09 20:23:17 +0000171__weak int env_get_char_spec(int index)
Simon Glass15e5a1a2017-08-03 12:22:00 -0600172{
Goldschmidt Simon9b0d66b2018-02-09 20:23:17 +0000173 return *(uchar *)(gd->env_addr + index);
174}
Simon Glass15e5a1a2017-08-03 12:22:00 -0600175
Goldschmidt Simon9b0d66b2018-02-09 20:23:17 +0000176int env_get_char(int index)
177{
Simon Glass1f39d0b2017-08-20 04:45:15 -0600178 if (gd->env_valid == ENV_INVALID)
Simon Glass10b0d7b2017-08-03 12:22:06 -0600179 return default_environment[index];
Goldschmidt Simon9b0d66b2018-02-09 20:23:17 +0000180 else
181 return env_get_char_spec(index);
Simon Glass15e5a1a2017-08-03 12:22:00 -0600182}
183
184int env_load(void)
185{
Maxime Ripardfd3158e2018-01-23 21:16:52 +0100186 struct env_driver *drv;
187 int prio;
Simon Glass15e5a1a2017-08-03 12:22:00 -0600188
Maxime Ripardfd3158e2018-01-23 21:16:52 +0100189 for (prio = 0; (drv = env_driver_lookup(ENVOP_LOAD, prio)); prio++) {
190 int ret;
191
192 if (!drv->load)
193 continue;
194
Maxime Ripard2131c5e2018-01-23 21:16:59 +0100195 if (!env_has_inited(drv->location))
196 continue;
197
Maxime Ripard185402a2018-01-23 21:16:54 +0100198 printf("Loading Environment from %s... ", drv->name);
Maxime Ripardfd3158e2018-01-23 21:16:52 +0100199 ret = drv->load();
Maxime Ripard185402a2018-01-23 21:16:54 +0100200 if (ret)
201 printf("Failed (%d)\n", ret);
202 else
203 printf("OK\n");
204
Maxime Ripardfd3158e2018-01-23 21:16:52 +0100205 if (!ret)
206 return 0;
Simon Glass15e5a1a2017-08-03 12:22:00 -0600207 }
208
Maxime Ripardfd3158e2018-01-23 21:16:52 +0100209 return -ENODEV;
Simon Glass15e5a1a2017-08-03 12:22:00 -0600210}
211
212int env_save(void)
213{
Maxime Ripardfd3158e2018-01-23 21:16:52 +0100214 struct env_driver *drv;
215 int prio;
Simon Glass15e5a1a2017-08-03 12:22:00 -0600216
Maxime Ripardfd3158e2018-01-23 21:16:52 +0100217 for (prio = 0; (drv = env_driver_lookup(ENVOP_SAVE, prio)); prio++) {
218 int ret;
Maxime Ripard3c0b2e52018-01-23 21:16:50 +0100219
Maxime Ripardfd3158e2018-01-23 21:16:52 +0100220 if (!drv->save)
221 continue;
222
Maxime Ripard2131c5e2018-01-23 21:16:59 +0100223 if (!env_has_inited(drv->location))
224 continue;
225
Maxime Ripard1e8294d2018-01-23 21:16:53 +0100226 printf("Saving Environment to %s... ", drv->name);
Maxime Ripardfd3158e2018-01-23 21:16:52 +0100227 ret = drv->save();
Maxime Ripard185402a2018-01-23 21:16:54 +0100228 if (ret)
229 printf("Failed (%d)\n", ret);
230 else
231 printf("OK\n");
232
Maxime Ripardfd3158e2018-01-23 21:16:52 +0100233 if (!ret)
234 return 0;
Simon Glass15e5a1a2017-08-03 12:22:00 -0600235 }
236
Maxime Ripardfd3158e2018-01-23 21:16:52 +0100237 return -ENODEV;
Simon Glass15e5a1a2017-08-03 12:22:00 -0600238}
239
Simon Glass36d85812017-08-03 12:22:05 -0600240int env_init(void)
Simon Glass15e5a1a2017-08-03 12:22:00 -0600241{
Maxime Ripardfd3158e2018-01-23 21:16:52 +0100242 struct env_driver *drv;
Simon Glassd40d8042017-08-03 12:22:02 -0600243 int ret = -ENOENT;
Maxime Ripardfd3158e2018-01-23 21:16:52 +0100244 int prio;
Simon Glass15e5a1a2017-08-03 12:22:00 -0600245
Maxime Ripardfd3158e2018-01-23 21:16:52 +0100246 for (prio = 0; (drv = env_driver_lookup(ENVOP_INIT, prio)); prio++) {
Maxime Ripard2131c5e2018-01-23 21:16:59 +0100247 if (!drv->init || !(ret = drv->init()))
248 env_set_inited(drv->location);
Maxime Ripardfd3158e2018-01-23 21:16:52 +0100249
Maxime Ripard2131c5e2018-01-23 21:16:59 +0100250 debug("%s: Environment %s init done (ret=%d)\n", __func__,
Maxime Ripardfd3158e2018-01-23 21:16:52 +0100251 drv->name, ret);
252 }
253
254 if (!prio)
255 return -ENODEV;
256
Simon Glassd40d8042017-08-03 12:22:02 -0600257 if (ret == -ENOENT) {
258 gd->env_addr = (ulong)&default_environment[0];
Tom Rini8a7c44b2017-08-19 22:27:57 -0400259 gd->env_valid = ENV_VALID;
Simon Glassd40d8042017-08-03 12:22:02 -0600260
261 return 0;
Simon Glass15e5a1a2017-08-03 12:22:00 -0600262 }
263
Maxime Ripardfd3158e2018-01-23 21:16:52 +0100264 return ret;
Simon Glass15e5a1a2017-08-03 12:22:00 -0600265}