blob: 157f1e6568c42976820b257f4de06a2aec82496b [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
Maxime Ripardb7da89a2018-01-23 21:16:51 +010013static struct env_driver *_env_driver_lookup(enum env_location loc)
Simon Glass15e5a1a2017-08-03 12:22:00 -060014{
15 struct env_driver *drv;
16 const int n_ents = ll_entry_count(struct env_driver, env_driver);
17 struct env_driver *entry;
18
19 drv = ll_entry_start(struct env_driver, env_driver);
20 for (entry = drv; entry != drv + n_ents; entry++) {
21 if (loc == entry->location)
22 return entry;
23 }
24
25 /* Not found */
26 return NULL;
27}
28
Maxime Ripardfd3158e2018-01-23 21:16:52 +010029/**
30 * env_get_location() - Returns the best env location for a board
31 * @op: operations performed on the environment
32 * @prio: priority between the multiple environments, 0 being the
33 * highest priority
34 *
35 * This will return the preferred environment for the given priority.
36 *
37 * All implementations are free to use the operation, the priority and
38 * any other data relevant to their choice, but must take into account
39 * the fact that the lowest prority (0) is the most important location
40 * in the system. The following locations should be returned by order
41 * of descending priorities, from the highest to the lowest priority.
42 *
43 * Returns:
44 * an enum env_location value on success, a negative error code otherwise
45 */
46static enum env_location env_get_location(enum env_operation op, int prio)
Simon Glass15e5a1a2017-08-03 12:22:00 -060047{
Maxime Ripardfd3158e2018-01-23 21:16:52 +010048 /*
49 * We support a single environment, so any environment asked
50 * with a priority that is not zero is out of our supported
51 * bounds.
52 */
53 if (prio >= 1)
54 return ENVL_UNKNOWN;
55
Tuomas Tynkkynenbfef2972017-10-10 21:59:40 +030056 if IS_ENABLED(CONFIG_ENV_IS_IN_EEPROM)
Simon Glass15e5a1a2017-08-03 12:22:00 -060057 return ENVL_EEPROM;
58 else if IS_ENABLED(CONFIG_ENV_IS_IN_FAT)
59 return ENVL_FAT;
Jorge Ramirez-Ortiz4a4c26d2018-01-10 11:33:48 +010060 else if IS_ENABLED(CONFIG_ENV_IS_IN_EXT4)
61 return ENVL_EXT4;
Simon Glass15e5a1a2017-08-03 12:22:00 -060062 else if IS_ENABLED(CONFIG_ENV_IS_IN_FLASH)
63 return ENVL_FLASH;
64 else if IS_ENABLED(CONFIG_ENV_IS_IN_MMC)
65 return ENVL_MMC;
66 else if IS_ENABLED(CONFIG_ENV_IS_IN_NAND)
67 return ENVL_NAND;
68 else if IS_ENABLED(CONFIG_ENV_IS_IN_NVRAM)
69 return ENVL_NVRAM;
70 else if IS_ENABLED(CONFIG_ENV_IS_IN_REMOTE)
71 return ENVL_REMOTE;
72 else if IS_ENABLED(CONFIG_ENV_IS_IN_SPI_FLASH)
73 return ENVL_SPI_FLASH;
74 else if IS_ENABLED(CONFIG_ENV_IS_IN_UBI)
75 return ENVL_UBI;
76 else if IS_ENABLED(CONFIG_ENV_IS_NOWHERE)
77 return ENVL_NOWHERE;
78 else
79 return ENVL_UNKNOWN;
80}
81
Maxime Ripardfd3158e2018-01-23 21:16:52 +010082
83/**
84 * env_driver_lookup() - Finds the most suited environment location
85 * @op: operations performed on the environment
86 * @prio: priority between the multiple environments, 0 being the
87 * highest priority
88 *
89 * This will try to find the available environment with the highest
90 * priority in the system.
91 *
92 * Returns:
93 * NULL on error, a pointer to a struct env_driver otherwise
94 */
95static struct env_driver *env_driver_lookup(enum env_operation op, int prio)
Simon Glass15e5a1a2017-08-03 12:22:00 -060096{
Maxime Ripardfd3158e2018-01-23 21:16:52 +010097 enum env_location loc = env_get_location(op, prio);
Simon Glass15e5a1a2017-08-03 12:22:00 -060098 struct env_driver *drv;
99
Maxime Ripardfd3158e2018-01-23 21:16:52 +0100100 if (loc == ENVL_UNKNOWN)
101 return NULL;
102
Maxime Ripardb7da89a2018-01-23 21:16:51 +0100103 drv = _env_driver_lookup(loc);
Simon Glass15e5a1a2017-08-03 12:22:00 -0600104 if (!drv) {
105 debug("%s: No environment driver for location %d\n", __func__,
106 loc);
107 return NULL;
108 }
109
110 return drv;
111}
112
Simon Glass10b0d7b2017-08-03 12:22:06 -0600113int env_get_char(int index)
Simon Glass15e5a1a2017-08-03 12:22:00 -0600114{
Maxime Ripardfd3158e2018-01-23 21:16:52 +0100115 struct env_driver *drv;
116 int prio;
Simon Glass15e5a1a2017-08-03 12:22:00 -0600117
Simon Glass1f39d0b2017-08-20 04:45:15 -0600118 if (gd->env_valid == ENV_INVALID)
Simon Glass10b0d7b2017-08-03 12:22:06 -0600119 return default_environment[index];
Maxime Ripardfd3158e2018-01-23 21:16:52 +0100120
121 for (prio = 0; (drv = env_driver_lookup(ENVOP_GET_CHAR, prio)); prio++) {
122 int ret;
123
124 if (!drv->get_char)
125 continue;
126
127 ret = drv->get_char(index);
128 if (!ret)
129 return 0;
130
131 debug("%s: Environment %s failed to load (err=%d)\n", __func__,
132 drv->name, ret);
Simon Glass15e5a1a2017-08-03 12:22:00 -0600133 }
134
Maxime Ripardfd3158e2018-01-23 21:16:52 +0100135 return -ENODEV;
Simon Glass15e5a1a2017-08-03 12:22:00 -0600136}
137
138int env_load(void)
139{
Maxime Ripardfd3158e2018-01-23 21:16:52 +0100140 struct env_driver *drv;
141 int prio;
Simon Glass15e5a1a2017-08-03 12:22:00 -0600142
Maxime Ripardfd3158e2018-01-23 21:16:52 +0100143 for (prio = 0; (drv = env_driver_lookup(ENVOP_LOAD, prio)); prio++) {
144 int ret;
145
146 if (!drv->load)
147 continue;
148
149 ret = drv->load();
150 if (!ret)
151 return 0;
152
153 debug("%s: Environment %s failed to load (err=%d)\n", __func__,
154 drv->name, ret);
Simon Glass15e5a1a2017-08-03 12:22:00 -0600155 }
156
Maxime Ripardfd3158e2018-01-23 21:16:52 +0100157 return -ENODEV;
Simon Glass15e5a1a2017-08-03 12:22:00 -0600158}
159
160int env_save(void)
161{
Maxime Ripardfd3158e2018-01-23 21:16:52 +0100162 struct env_driver *drv;
163 int prio;
Simon Glass15e5a1a2017-08-03 12:22:00 -0600164
Maxime Ripardfd3158e2018-01-23 21:16:52 +0100165 for (prio = 0; (drv = env_driver_lookup(ENVOP_SAVE, prio)); prio++) {
166 int ret;
Maxime Ripard3c0b2e52018-01-23 21:16:50 +0100167
Maxime Ripardfd3158e2018-01-23 21:16:52 +0100168 if (!drv->save)
169 continue;
170
Maxime Ripard1e8294d2018-01-23 21:16:53 +0100171 printf("Saving Environment to %s... ", drv->name);
Maxime Ripardfd3158e2018-01-23 21:16:52 +0100172 ret = drv->save();
Maxime Ripard1e8294d2018-01-23 21:16:53 +0100173 printf("%s\n", ret ? "Failed" : "OK");
Maxime Ripardfd3158e2018-01-23 21:16:52 +0100174 if (!ret)
175 return 0;
176
177 debug("%s: Environment %s failed to save (err=%d)\n", __func__,
178 drv->name, ret);
Simon Glass15e5a1a2017-08-03 12:22:00 -0600179 }
180
Maxime Ripardfd3158e2018-01-23 21:16:52 +0100181 return -ENODEV;
Simon Glass15e5a1a2017-08-03 12:22:00 -0600182}
183
Simon Glass36d85812017-08-03 12:22:05 -0600184int env_init(void)
Simon Glass15e5a1a2017-08-03 12:22:00 -0600185{
Maxime Ripardfd3158e2018-01-23 21:16:52 +0100186 struct env_driver *drv;
Simon Glassd40d8042017-08-03 12:22:02 -0600187 int ret = -ENOENT;
Maxime Ripardfd3158e2018-01-23 21:16:52 +0100188 int prio;
Simon Glass15e5a1a2017-08-03 12:22:00 -0600189
Maxime Ripardfd3158e2018-01-23 21:16:52 +0100190 for (prio = 0; (drv = env_driver_lookup(ENVOP_INIT, prio)); prio++) {
191 if (!drv->init)
192 continue;
193
Simon Glassd40d8042017-08-03 12:22:02 -0600194 ret = drv->init();
Maxime Ripardfd3158e2018-01-23 21:16:52 +0100195 if (!ret)
196 return 0;
197
198 debug("%s: Environment %s failed to init (err=%d)\n", __func__,
199 drv->name, ret);
200 }
201
202 if (!prio)
203 return -ENODEV;
204
Simon Glassd40d8042017-08-03 12:22:02 -0600205 if (ret == -ENOENT) {
206 gd->env_addr = (ulong)&default_environment[0];
Tom Rini8a7c44b2017-08-19 22:27:57 -0400207 gd->env_valid = ENV_VALID;
Simon Glassd40d8042017-08-03 12:22:02 -0600208
209 return 0;
Simon Glass15e5a1a2017-08-03 12:22:00 -0600210 }
211
Maxime Ripardfd3158e2018-01-23 21:16:52 +0100212 return ret;
Simon Glass15e5a1a2017-08-03 12:22:00 -0600213}