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 switch (op) { 123 case ENVOP_GET_CHAR: 124 case ENVOP_INIT: 125 case ENVOP_LOAD: 126 if (prio >= ARRAY_SIZE(env_locations)) 127 return ENVL_UNKNOWN; 128 129 gd->env_load_location = env_locations[prio]; 130 return gd->env_load_location; 131 132 case ENVOP_SAVE: 133 return gd->env_load_location; 134 } 135 136 return ENVL_UNKNOWN; 137 } 138 139 140 /** 141 * env_driver_lookup() - Finds the most suited environment location 142 * @op: operations performed on the environment 143 * @prio: priority between the multiple environments, 0 being the 144 * highest priority 145 * 146 * This will try to find the available environment with the highest 147 * priority in the system. 148 * 149 * Returns: 150 * NULL on error, a pointer to a struct env_driver otherwise 151 */ 152 static struct env_driver *env_driver_lookup(enum env_operation op, int prio) 153 { 154 enum env_location loc = env_get_location(op, prio); 155 struct env_driver *drv; 156 157 if (loc == ENVL_UNKNOWN) 158 return NULL; 159 160 drv = _env_driver_lookup(loc); 161 if (!drv) { 162 debug("%s: No environment driver for location %d\n", __func__, 163 loc); 164 return NULL; 165 } 166 167 return drv; 168 } 169 170 __weak int env_get_char_spec(int index) 171 { 172 return *(uchar *)(gd->env_addr + index); 173 } 174 175 int env_get_char(int index) 176 { 177 if (gd->env_valid == ENV_INVALID) 178 return default_environment[index]; 179 else 180 return env_get_char_spec(index); 181 } 182 183 int env_load(void) 184 { 185 struct env_driver *drv; 186 int prio; 187 188 for (prio = 0; (drv = env_driver_lookup(ENVOP_LOAD, prio)); prio++) { 189 int ret; 190 191 if (!drv->load) 192 continue; 193 194 if (!env_has_inited(drv->location)) 195 continue; 196 197 printf("Loading Environment from %s... ", drv->name); 198 ret = drv->load(); 199 if (ret) 200 printf("Failed (%d)\n", ret); 201 else 202 printf("OK\n"); 203 204 if (!ret) 205 return 0; 206 } 207 208 return -ENODEV; 209 } 210 211 int env_save(void) 212 { 213 struct env_driver *drv; 214 int prio; 215 216 for (prio = 0; (drv = env_driver_lookup(ENVOP_SAVE, prio)); prio++) { 217 int ret; 218 219 if (!drv->save) 220 continue; 221 222 if (!env_has_inited(drv->location)) 223 continue; 224 225 printf("Saving Environment to %s... ", drv->name); 226 ret = drv->save(); 227 if (ret) 228 printf("Failed (%d)\n", ret); 229 else 230 printf("OK\n"); 231 232 if (!ret) 233 return 0; 234 } 235 236 return -ENODEV; 237 } 238 239 int env_init(void) 240 { 241 struct env_driver *drv; 242 int ret = -ENOENT; 243 int prio; 244 245 for (prio = 0; (drv = env_driver_lookup(ENVOP_INIT, prio)); prio++) { 246 if (!drv->init || !(ret = drv->init())) 247 env_set_inited(drv->location); 248 249 debug("%s: Environment %s init done (ret=%d)\n", __func__, 250 drv->name, ret); 251 } 252 253 if (!prio) 254 return -ENODEV; 255 256 if (ret == -ENOENT) { 257 gd->env_addr = (ulong)&default_environment[0]; 258 gd->env_valid = ENV_VALID; 259 260 return 0; 261 } 262 263 return ret; 264 } 265