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