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 #if defined(CONFIG_NEEDS_MANUAL_RELOC) 14 void 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 34 static struct env_driver *_env_driver_lookup(enum env_location loc) 35 { 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 50 static 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 86 static bool env_has_inited(enum env_location location) 87 { 88 return gd->env_has_init & BIT(location); 89 } 90 91 static 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 103 /** 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. 110 * This is overridable by boards if they need to. 111 * 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 */ 121 __weak enum env_location env_get_location(enum env_operation op, int prio) 122 { 123 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 130 gd->env_load_location = env_locations[prio]; 131 return gd->env_load_location; 132 133 case ENVOP_SAVE: 134 return gd->env_load_location; 135 } 136 137 return ENVL_UNKNOWN; 138 } 139 140 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 */ 153 static struct env_driver *env_driver_lookup(enum env_operation op, int prio) 154 { 155 enum env_location loc = env_get_location(op, prio); 156 struct env_driver *drv; 157 158 if (loc == ENVL_UNKNOWN) 159 return NULL; 160 161 drv = _env_driver_lookup(loc); 162 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 171 __weak int env_get_char_spec(int index) 172 { 173 return *(uchar *)(gd->env_addr + index); 174 } 175 176 int env_get_char(int index) 177 { 178 if (gd->env_valid == ENV_INVALID) 179 return default_environment[index]; 180 else 181 return env_get_char_spec(index); 182 } 183 184 int env_load(void) 185 { 186 struct env_driver *drv; 187 int prio; 188 189 for (prio = 0; (drv = env_driver_lookup(ENVOP_LOAD, prio)); prio++) { 190 int ret; 191 192 if (!drv->load) 193 continue; 194 195 if (!env_has_inited(drv->location)) 196 continue; 197 198 printf("Loading Environment from %s... ", drv->name); 199 ret = drv->load(); 200 if (ret) 201 printf("Failed (%d)\n", ret); 202 else 203 printf("OK\n"); 204 205 if (!ret) 206 return 0; 207 } 208 209 return -ENODEV; 210 } 211 212 int env_save(void) 213 { 214 struct env_driver *drv; 215 int prio; 216 217 for (prio = 0; (drv = env_driver_lookup(ENVOP_SAVE, prio)); prio++) { 218 int ret; 219 220 if (!drv->save) 221 continue; 222 223 if (!env_has_inited(drv->location)) 224 continue; 225 226 printf("Saving Environment to %s... ", drv->name); 227 ret = drv->save(); 228 if (ret) 229 printf("Failed (%d)\n", ret); 230 else 231 printf("OK\n"); 232 233 if (!ret) 234 return 0; 235 } 236 237 return -ENODEV; 238 } 239 240 int env_init(void) 241 { 242 struct env_driver *drv; 243 int ret = -ENOENT; 244 int prio; 245 246 for (prio = 0; (drv = env_driver_lookup(ENVOP_INIT, prio)); prio++) { 247 if (!drv->init || !(ret = drv->init())) 248 env_set_inited(drv->location); 249 250 debug("%s: Environment %s init done (ret=%d)\n", __func__, 251 drv->name, ret); 252 } 253 254 if (!prio) 255 return -ENODEV; 256 257 if (ret == -ENOENT) { 258 gd->env_addr = (ulong)&default_environment[0]; 259 gd->env_valid = ENV_VALID; 260 261 return 0; 262 } 263 264 return ret; 265 } 266