1 /* 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 11 DECLARE_GLOBAL_DATA_PTR; 12 13 static struct env_driver *_env_driver_lookup(enum env_location loc) 14 { 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 29 static enum env_location env_locations[] = { 30 #ifdef CONFIG_ENV_IS_IN_EEPROM 31 ENVL_EEPROM, 32 #endif 33 #ifdef CONFIG_ENV_IS_IN_EXT4 34 ENVL_EXT4, 35 #endif 36 #ifdef CONFIG_ENV_IS_IN_FAT 37 ENVL_FAT, 38 #endif 39 #ifdef CONFIG_ENV_IS_IN_FLASH 40 ENVL_FLASH, 41 #endif 42 #ifdef CONFIG_ENV_IS_IN_MMC 43 ENVL_MMC, 44 #endif 45 #ifdef CONFIG_ENV_IS_IN_NAND 46 ENVL_NAND, 47 #endif 48 #ifdef CONFIG_ENV_IS_IN_NVRAM 49 ENVL_NVRAM, 50 #endif 51 #ifdef CONFIG_ENV_IS_IN_REMOTE 52 ENVL_REMOTE, 53 #endif 54 #ifdef CONFIG_ENV_IS_IN_SPI_FLASH 55 ENVL_SPI_FLASH, 56 #endif 57 #ifdef CONFIG_ENV_IS_IN_UBI 58 ENVL_UBI, 59 #endif 60 #ifdef CONFIG_ENV_IS_NOWHERE 61 ENVL_NOWHERE, 62 #endif 63 }; 64 65 static enum env_location env_load_location = ENVL_UNKNOWN; 66 67 static bool env_has_inited(enum env_location location) 68 { 69 return gd->env_has_init & BIT(location); 70 } 71 72 static void env_set_inited(enum env_location location) 73 { 74 /* 75 * We're using a 32-bits bitmask stored in gd (env_has_init) 76 * using the above enum value as the bit index. We need to 77 * make sure that we're not overflowing it. 78 */ 79 BUILD_BUG_ON(ARRAY_SIZE(env_locations) > BITS_PER_LONG); 80 81 gd->env_has_init |= BIT(location); 82 } 83 84 /** 85 * env_get_location() - Returns the best env location for a board 86 * @op: operations performed on the environment 87 * @prio: priority between the multiple environments, 0 being the 88 * highest priority 89 * 90 * This will return the preferred environment for the given priority. 91 * This is overridable by boards if they need to. 92 * 93 * All implementations are free to use the operation, the priority and 94 * any other data relevant to their choice, but must take into account 95 * the fact that the lowest prority (0) is the most important location 96 * in the system. The following locations should be returned by order 97 * of descending priorities, from the highest to the lowest priority. 98 * 99 * Returns: 100 * an enum env_location value on success, a negative error code otherwise 101 */ 102 __weak enum env_location env_get_location(enum env_operation op, int prio) 103 { 104 switch (op) { 105 case ENVOP_GET_CHAR: 106 case ENVOP_INIT: 107 case ENVOP_LOAD: 108 if (prio >= ARRAY_SIZE(env_locations)) 109 return ENVL_UNKNOWN; 110 111 env_load_location = env_locations[prio]; 112 return env_load_location; 113 114 case ENVOP_SAVE: 115 return env_load_location; 116 } 117 118 return ENVL_UNKNOWN; 119 } 120 121 122 /** 123 * env_driver_lookup() - Finds the most suited environment location 124 * @op: operations performed on the environment 125 * @prio: priority between the multiple environments, 0 being the 126 * highest priority 127 * 128 * This will try to find the available environment with the highest 129 * priority in the system. 130 * 131 * Returns: 132 * NULL on error, a pointer to a struct env_driver otherwise 133 */ 134 static struct env_driver *env_driver_lookup(enum env_operation op, int prio) 135 { 136 enum env_location loc = env_get_location(op, prio); 137 struct env_driver *drv; 138 139 if (loc == ENVL_UNKNOWN) 140 return NULL; 141 142 drv = _env_driver_lookup(loc); 143 if (!drv) { 144 debug("%s: No environment driver for location %d\n", __func__, 145 loc); 146 return NULL; 147 } 148 149 return drv; 150 } 151 152 int env_get_char(int index) 153 { 154 struct env_driver *drv; 155 int prio; 156 157 if (gd->env_valid == ENV_INVALID) 158 return default_environment[index]; 159 160 for (prio = 0; (drv = env_driver_lookup(ENVOP_GET_CHAR, prio)); prio++) { 161 int ret; 162 163 if (!drv->get_char) 164 continue; 165 166 if (!env_has_inited(drv->location)) 167 continue; 168 169 ret = drv->get_char(index); 170 if (!ret) 171 return 0; 172 173 debug("%s: Environment %s failed to load (err=%d)\n", __func__, 174 drv->name, ret); 175 } 176 177 return -ENODEV; 178 } 179 180 int env_load(void) 181 { 182 struct env_driver *drv; 183 int prio; 184 185 for (prio = 0; (drv = env_driver_lookup(ENVOP_LOAD, prio)); prio++) { 186 int ret; 187 188 if (!drv->load) 189 continue; 190 191 if (!env_has_inited(drv->location)) 192 continue; 193 194 printf("Loading Environment from %s... ", drv->name); 195 ret = drv->load(); 196 if (ret) 197 printf("Failed (%d)\n", ret); 198 else 199 printf("OK\n"); 200 201 if (!ret) 202 return 0; 203 } 204 205 return -ENODEV; 206 } 207 208 int env_save(void) 209 { 210 struct env_driver *drv; 211 int prio; 212 213 for (prio = 0; (drv = env_driver_lookup(ENVOP_SAVE, prio)); prio++) { 214 int ret; 215 216 if (!drv->save) 217 continue; 218 219 if (!env_has_inited(drv->location)) 220 continue; 221 222 printf("Saving Environment to %s... ", drv->name); 223 ret = drv->save(); 224 if (ret) 225 printf("Failed (%d)\n", ret); 226 else 227 printf("OK\n"); 228 229 if (!ret) 230 return 0; 231 } 232 233 return -ENODEV; 234 } 235 236 int env_init(void) 237 { 238 struct env_driver *drv; 239 int ret = -ENOENT; 240 int prio; 241 242 for (prio = 0; (drv = env_driver_lookup(ENVOP_INIT, prio)); prio++) { 243 if (!drv->init || !(ret = drv->init())) 244 env_set_inited(drv->location); 245 246 debug("%s: Environment %s init done (ret=%d)\n", __func__, 247 drv->name, ret); 248 } 249 250 if (!prio) 251 return -ENODEV; 252 253 if (ret == -ENOENT) { 254 gd->env_addr = (ulong)&default_environment[0]; 255 gd->env_valid = ENV_VALID; 256 257 return 0; 258 } 259 260 return ret; 261 } 262