1c9d728ddSSimon Glass /* 2c9d728ddSSimon Glass * Copyright (C) 2017 Google, Inc 3c9d728ddSSimon Glass * Written by Simon Glass <sjg@chromium.org> 4c9d728ddSSimon Glass * 5c9d728ddSSimon Glass * SPDX-License-Identifier: GPL-2.0+ 6c9d728ddSSimon Glass */ 7c9d728ddSSimon Glass 8c9d728ddSSimon Glass #include <common.h> 9c9d728ddSSimon Glass #include <environment.h> 10c9d728ddSSimon Glass 11c9d728ddSSimon Glass DECLARE_GLOBAL_DATA_PTR; 12c9d728ddSSimon Glass 1352746c43SMaxime Ripard static struct env_driver *_env_driver_lookup(enum env_location loc) 14c9d728ddSSimon Glass { 15c9d728ddSSimon Glass struct env_driver *drv; 16c9d728ddSSimon Glass const int n_ents = ll_entry_count(struct env_driver, env_driver); 17c9d728ddSSimon Glass struct env_driver *entry; 18c9d728ddSSimon Glass 19c9d728ddSSimon Glass drv = ll_entry_start(struct env_driver, env_driver); 20c9d728ddSSimon Glass for (entry = drv; entry != drv + n_ents; entry++) { 21c9d728ddSSimon Glass if (loc == entry->location) 22c9d728ddSSimon Glass return entry; 23c9d728ddSSimon Glass } 24c9d728ddSSimon Glass 25c9d728ddSSimon Glass /* Not found */ 26c9d728ddSSimon Glass return NULL; 27c9d728ddSSimon Glass } 28c9d728ddSSimon Glass 29*7d714a24SMaxime Ripard static enum env_location env_locations[] = { 30*7d714a24SMaxime Ripard #ifdef CONFIG_ENV_IS_IN_EEPROM 31*7d714a24SMaxime Ripard ENVL_EEPROM, 32*7d714a24SMaxime Ripard #endif 33*7d714a24SMaxime Ripard #ifdef CONFIG_ENV_IS_IN_EXT4 34*7d714a24SMaxime Ripard ENVL_EXT4, 35*7d714a24SMaxime Ripard #endif 36*7d714a24SMaxime Ripard #ifdef CONFIG_ENV_IS_IN_FAT 37*7d714a24SMaxime Ripard ENVL_FAT, 38*7d714a24SMaxime Ripard #endif 39*7d714a24SMaxime Ripard #ifdef CONFIG_ENV_IS_IN_FLASH 40*7d714a24SMaxime Ripard ENVL_FLASH, 41*7d714a24SMaxime Ripard #endif 42*7d714a24SMaxime Ripard #ifdef CONFIG_ENV_IS_IN_MMC 43*7d714a24SMaxime Ripard ENVL_MMC, 44*7d714a24SMaxime Ripard #endif 45*7d714a24SMaxime Ripard #ifdef CONFIG_ENV_IS_IN_NAND 46*7d714a24SMaxime Ripard ENVL_NAND, 47*7d714a24SMaxime Ripard #endif 48*7d714a24SMaxime Ripard #ifdef CONFIG_ENV_IS_IN_NVRAM 49*7d714a24SMaxime Ripard ENVL_NVRAM, 50*7d714a24SMaxime Ripard #endif 51*7d714a24SMaxime Ripard #ifdef CONFIG_ENV_IS_IN_REMOTE 52*7d714a24SMaxime Ripard ENVL_REMOTE, 53*7d714a24SMaxime Ripard #endif 54*7d714a24SMaxime Ripard #ifdef CONFIG_ENV_IS_IN_SPI_FLASH 55*7d714a24SMaxime Ripard ENVL_SPI_FLASH, 56*7d714a24SMaxime Ripard #endif 57*7d714a24SMaxime Ripard #ifdef CONFIG_ENV_IS_IN_UBI 58*7d714a24SMaxime Ripard ENVL_UBI, 59*7d714a24SMaxime Ripard #endif 60*7d714a24SMaxime Ripard #ifdef CONFIG_ENV_IS_NOWHERE 61*7d714a24SMaxime Ripard ENVL_NOWHERE, 62*7d714a24SMaxime Ripard #endif 63*7d714a24SMaxime Ripard }; 64*7d714a24SMaxime Ripard 65*7d714a24SMaxime Ripard static enum env_location env_load_location = ENVL_UNKNOWN; 66*7d714a24SMaxime Ripard 678a3a7e22SMaxime Ripard /** 688a3a7e22SMaxime Ripard * env_get_location() - Returns the best env location for a board 698a3a7e22SMaxime Ripard * @op: operations performed on the environment 708a3a7e22SMaxime Ripard * @prio: priority between the multiple environments, 0 being the 718a3a7e22SMaxime Ripard * highest priority 728a3a7e22SMaxime Ripard * 738a3a7e22SMaxime Ripard * This will return the preferred environment for the given priority. 748a3a7e22SMaxime Ripard * 758a3a7e22SMaxime Ripard * All implementations are free to use the operation, the priority and 768a3a7e22SMaxime Ripard * any other data relevant to their choice, but must take into account 778a3a7e22SMaxime Ripard * the fact that the lowest prority (0) is the most important location 788a3a7e22SMaxime Ripard * in the system. The following locations should be returned by order 798a3a7e22SMaxime Ripard * of descending priorities, from the highest to the lowest priority. 808a3a7e22SMaxime Ripard * 818a3a7e22SMaxime Ripard * Returns: 828a3a7e22SMaxime Ripard * an enum env_location value on success, a negative error code otherwise 838a3a7e22SMaxime Ripard */ 848a3a7e22SMaxime Ripard static enum env_location env_get_location(enum env_operation op, int prio) 85c9d728ddSSimon Glass { 86*7d714a24SMaxime Ripard switch (op) { 87*7d714a24SMaxime Ripard case ENVOP_GET_CHAR: 88*7d714a24SMaxime Ripard case ENVOP_INIT: 89*7d714a24SMaxime Ripard case ENVOP_LOAD: 90*7d714a24SMaxime Ripard if (prio >= ARRAY_SIZE(env_locations)) 918a3a7e22SMaxime Ripard return ENVL_UNKNOWN; 928a3a7e22SMaxime Ripard 93*7d714a24SMaxime Ripard env_load_location = env_locations[prio]; 94*7d714a24SMaxime Ripard return env_load_location; 95*7d714a24SMaxime Ripard 96*7d714a24SMaxime Ripard case ENVOP_SAVE: 97*7d714a24SMaxime Ripard return env_load_location; 98*7d714a24SMaxime Ripard } 99*7d714a24SMaxime Ripard 100c9d728ddSSimon Glass return ENVL_UNKNOWN; 101c9d728ddSSimon Glass } 102c9d728ddSSimon Glass 1038a3a7e22SMaxime Ripard 1048a3a7e22SMaxime Ripard /** 1058a3a7e22SMaxime Ripard * env_driver_lookup() - Finds the most suited environment location 1068a3a7e22SMaxime Ripard * @op: operations performed on the environment 1078a3a7e22SMaxime Ripard * @prio: priority between the multiple environments, 0 being the 1088a3a7e22SMaxime Ripard * highest priority 1098a3a7e22SMaxime Ripard * 1108a3a7e22SMaxime Ripard * This will try to find the available environment with the highest 1118a3a7e22SMaxime Ripard * priority in the system. 1128a3a7e22SMaxime Ripard * 1138a3a7e22SMaxime Ripard * Returns: 1148a3a7e22SMaxime Ripard * NULL on error, a pointer to a struct env_driver otherwise 1158a3a7e22SMaxime Ripard */ 1168a3a7e22SMaxime Ripard static struct env_driver *env_driver_lookup(enum env_operation op, int prio) 117c9d728ddSSimon Glass { 1188a3a7e22SMaxime Ripard enum env_location loc = env_get_location(op, prio); 119c9d728ddSSimon Glass struct env_driver *drv; 120c9d728ddSSimon Glass 1218a3a7e22SMaxime Ripard if (loc == ENVL_UNKNOWN) 1228a3a7e22SMaxime Ripard return NULL; 1238a3a7e22SMaxime Ripard 12452746c43SMaxime Ripard drv = _env_driver_lookup(loc); 125c9d728ddSSimon Glass if (!drv) { 126c9d728ddSSimon Glass debug("%s: No environment driver for location %d\n", __func__, 127c9d728ddSSimon Glass loc); 128c9d728ddSSimon Glass return NULL; 129c9d728ddSSimon Glass } 130c9d728ddSSimon Glass 131c9d728ddSSimon Glass return drv; 132c9d728ddSSimon Glass } 133c9d728ddSSimon Glass 134a69d0f60SSimon Glass int env_get_char(int index) 135c9d728ddSSimon Glass { 1368a3a7e22SMaxime Ripard struct env_driver *drv; 1378a3a7e22SMaxime Ripard int prio; 138c9d728ddSSimon Glass 1392d7cb5b4SSimon Glass if (gd->env_valid == ENV_INVALID) 140a69d0f60SSimon Glass return default_environment[index]; 1418a3a7e22SMaxime Ripard 1428a3a7e22SMaxime Ripard for (prio = 0; (drv = env_driver_lookup(ENVOP_GET_CHAR, prio)); prio++) { 1438a3a7e22SMaxime Ripard int ret; 1448a3a7e22SMaxime Ripard 145c9d728ddSSimon Glass if (!drv->get_char) 1468a3a7e22SMaxime Ripard continue; 1478a3a7e22SMaxime Ripard 148c9d728ddSSimon Glass ret = drv->get_char(index); 1498a3a7e22SMaxime Ripard if (!ret) 1508a3a7e22SMaxime Ripard return 0; 1518a3a7e22SMaxime Ripard 1528a3a7e22SMaxime Ripard debug("%s: Environment %s failed to load (err=%d)\n", __func__, 1538a3a7e22SMaxime Ripard drv->name, ret); 154c9d728ddSSimon Glass } 155c9d728ddSSimon Glass 1568a3a7e22SMaxime Ripard return -ENODEV; 157c9d728ddSSimon Glass } 158c9d728ddSSimon Glass 159c9d728ddSSimon Glass int env_load(void) 160c9d728ddSSimon Glass { 1618a3a7e22SMaxime Ripard struct env_driver *drv; 1628a3a7e22SMaxime Ripard int prio; 163c9d728ddSSimon Glass 1648a3a7e22SMaxime Ripard for (prio = 0; (drv = env_driver_lookup(ENVOP_LOAD, prio)); prio++) { 1658a3a7e22SMaxime Ripard int ret; 1668a3a7e22SMaxime Ripard 167c9d728ddSSimon Glass if (!drv->load) 1688a3a7e22SMaxime Ripard continue; 1698a3a7e22SMaxime Ripard 1703574ba01SMaxime Ripard printf("Loading Environment from %s... ", drv->name); 171c55d8b94SSimon Glass ret = drv->load(); 1723574ba01SMaxime Ripard if (ret) 1733574ba01SMaxime Ripard printf("Failed (%d)\n", ret); 1743574ba01SMaxime Ripard else 1753574ba01SMaxime Ripard printf("OK\n"); 1763574ba01SMaxime Ripard 1778a3a7e22SMaxime Ripard if (!ret) 1788a3a7e22SMaxime Ripard return 0; 179c9d728ddSSimon Glass } 180c9d728ddSSimon Glass 1818a3a7e22SMaxime Ripard return -ENODEV; 182c9d728ddSSimon Glass } 183c9d728ddSSimon Glass 184c9d728ddSSimon Glass int env_save(void) 185c9d728ddSSimon Glass { 1868a3a7e22SMaxime Ripard struct env_driver *drv; 1878a3a7e22SMaxime Ripard int prio; 1888a3a7e22SMaxime Ripard 1898a3a7e22SMaxime Ripard for (prio = 0; (drv = env_driver_lookup(ENVOP_SAVE, prio)); prio++) { 190c9d728ddSSimon Glass int ret; 191c9d728ddSSimon Glass 192c9d728ddSSimon Glass if (!drv->save) 1938a3a7e22SMaxime Ripard continue; 1949c24dfb2SMaxime Ripard 1959efac3c8SMaxime Ripard printf("Saving Environment to %s... ", drv->name); 196c9d728ddSSimon Glass ret = drv->save(); 1973574ba01SMaxime Ripard if (ret) 1983574ba01SMaxime Ripard printf("Failed (%d)\n", ret); 1993574ba01SMaxime Ripard else 2003574ba01SMaxime Ripard printf("OK\n"); 2013574ba01SMaxime Ripard 2028a3a7e22SMaxime Ripard if (!ret) 2038a3a7e22SMaxime Ripard return 0; 204c9d728ddSSimon Glass } 205c9d728ddSSimon Glass 2068a3a7e22SMaxime Ripard return -ENODEV; 207c9d728ddSSimon Glass } 208c9d728ddSSimon Glass 2096eeae424SSimon Glass int env_init(void) 210c9d728ddSSimon Glass { 2118a3a7e22SMaxime Ripard struct env_driver *drv; 2127938822aSSimon Glass int ret = -ENOENT; 2138a3a7e22SMaxime Ripard int prio; 214c9d728ddSSimon Glass 2158a3a7e22SMaxime Ripard for (prio = 0; (drv = env_driver_lookup(ENVOP_INIT, prio)); prio++) { 2168a3a7e22SMaxime Ripard if (!drv->init) 2178a3a7e22SMaxime Ripard continue; 2188a3a7e22SMaxime Ripard 219c9d728ddSSimon Glass ret = drv->init(); 2208a3a7e22SMaxime Ripard if (!ret) 2218a3a7e22SMaxime Ripard return 0; 2228a3a7e22SMaxime Ripard 2238a3a7e22SMaxime Ripard debug("%s: Environment %s failed to init (err=%d)\n", __func__, 2248a3a7e22SMaxime Ripard drv->name, ret); 2258a3a7e22SMaxime Ripard } 2268a3a7e22SMaxime Ripard 2278a3a7e22SMaxime Ripard if (!prio) 2288a3a7e22SMaxime Ripard return -ENODEV; 2298a3a7e22SMaxime Ripard 2307938822aSSimon Glass if (ret == -ENOENT) { 2317938822aSSimon Glass gd->env_addr = (ulong)&default_environment[0]; 232eeba55cbSTom Rini gd->env_valid = ENV_VALID; 2337938822aSSimon Glass 2347938822aSSimon Glass return 0; 235c9d728ddSSimon Glass } 236c9d728ddSSimon Glass 2378a3a7e22SMaxime Ripard return ret; 238c9d728ddSSimon Glass } 239