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