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 297d714a24SMaxime Ripard static enum env_location env_locations[] = { 307d714a24SMaxime Ripard #ifdef CONFIG_ENV_IS_IN_EEPROM 317d714a24SMaxime Ripard ENVL_EEPROM, 327d714a24SMaxime Ripard #endif 337d714a24SMaxime Ripard #ifdef CONFIG_ENV_IS_IN_EXT4 347d714a24SMaxime Ripard ENVL_EXT4, 357d714a24SMaxime Ripard #endif 367d714a24SMaxime Ripard #ifdef CONFIG_ENV_IS_IN_FAT 377d714a24SMaxime Ripard ENVL_FAT, 387d714a24SMaxime Ripard #endif 397d714a24SMaxime Ripard #ifdef CONFIG_ENV_IS_IN_FLASH 407d714a24SMaxime Ripard ENVL_FLASH, 417d714a24SMaxime Ripard #endif 427d714a24SMaxime Ripard #ifdef CONFIG_ENV_IS_IN_MMC 437d714a24SMaxime Ripard ENVL_MMC, 447d714a24SMaxime Ripard #endif 457d714a24SMaxime Ripard #ifdef CONFIG_ENV_IS_IN_NAND 467d714a24SMaxime Ripard ENVL_NAND, 477d714a24SMaxime Ripard #endif 487d714a24SMaxime Ripard #ifdef CONFIG_ENV_IS_IN_NVRAM 497d714a24SMaxime Ripard ENVL_NVRAM, 507d714a24SMaxime Ripard #endif 517d714a24SMaxime Ripard #ifdef CONFIG_ENV_IS_IN_REMOTE 527d714a24SMaxime Ripard ENVL_REMOTE, 537d714a24SMaxime Ripard #endif 547d714a24SMaxime Ripard #ifdef CONFIG_ENV_IS_IN_SPI_FLASH 557d714a24SMaxime Ripard ENVL_SPI_FLASH, 567d714a24SMaxime Ripard #endif 577d714a24SMaxime Ripard #ifdef CONFIG_ENV_IS_IN_UBI 587d714a24SMaxime Ripard ENVL_UBI, 597d714a24SMaxime Ripard #endif 607d714a24SMaxime Ripard #ifdef CONFIG_ENV_IS_NOWHERE 617d714a24SMaxime Ripard ENVL_NOWHERE, 627d714a24SMaxime Ripard #endif 637d714a24SMaxime Ripard }; 647d714a24SMaxime Ripard 657d714a24SMaxime Ripard static enum env_location env_load_location = ENVL_UNKNOWN; 667d714a24SMaxime Ripard 671d446087SMaxime Ripard static bool env_has_inited(enum env_location location) 681d446087SMaxime Ripard { 691d446087SMaxime Ripard return gd->env_has_init & BIT(location); 701d446087SMaxime Ripard } 711d446087SMaxime Ripard 721d446087SMaxime Ripard static void env_set_inited(enum env_location location) 731d446087SMaxime Ripard { 741d446087SMaxime Ripard /* 751d446087SMaxime Ripard * We're using a 32-bits bitmask stored in gd (env_has_init) 761d446087SMaxime Ripard * using the above enum value as the bit index. We need to 771d446087SMaxime Ripard * make sure that we're not overflowing it. 781d446087SMaxime Ripard */ 791d446087SMaxime Ripard BUILD_BUG_ON(ARRAY_SIZE(env_locations) > BITS_PER_LONG); 801d446087SMaxime Ripard 811d446087SMaxime Ripard gd->env_has_init |= BIT(location); 821d446087SMaxime Ripard } 831d446087SMaxime Ripard 848a3a7e22SMaxime Ripard /** 858a3a7e22SMaxime Ripard * env_get_location() - Returns the best env location for a board 868a3a7e22SMaxime Ripard * @op: operations performed on the environment 878a3a7e22SMaxime Ripard * @prio: priority between the multiple environments, 0 being the 888a3a7e22SMaxime Ripard * highest priority 898a3a7e22SMaxime Ripard * 908a3a7e22SMaxime Ripard * This will return the preferred environment for the given priority. 91*40c08a68SMaxime Ripard * This is overridable by boards if they need to. 928a3a7e22SMaxime Ripard * 938a3a7e22SMaxime Ripard * All implementations are free to use the operation, the priority and 948a3a7e22SMaxime Ripard * any other data relevant to their choice, but must take into account 958a3a7e22SMaxime Ripard * the fact that the lowest prority (0) is the most important location 968a3a7e22SMaxime Ripard * in the system. The following locations should be returned by order 978a3a7e22SMaxime Ripard * of descending priorities, from the highest to the lowest priority. 988a3a7e22SMaxime Ripard * 998a3a7e22SMaxime Ripard * Returns: 1008a3a7e22SMaxime Ripard * an enum env_location value on success, a negative error code otherwise 1018a3a7e22SMaxime Ripard */ 102*40c08a68SMaxime Ripard __weak enum env_location env_get_location(enum env_operation op, int prio) 103c9d728ddSSimon Glass { 1047d714a24SMaxime Ripard switch (op) { 1057d714a24SMaxime Ripard case ENVOP_GET_CHAR: 1067d714a24SMaxime Ripard case ENVOP_INIT: 1077d714a24SMaxime Ripard case ENVOP_LOAD: 1087d714a24SMaxime Ripard if (prio >= ARRAY_SIZE(env_locations)) 1098a3a7e22SMaxime Ripard return ENVL_UNKNOWN; 1108a3a7e22SMaxime Ripard 1117d714a24SMaxime Ripard env_load_location = env_locations[prio]; 1127d714a24SMaxime Ripard return env_load_location; 1137d714a24SMaxime Ripard 1147d714a24SMaxime Ripard case ENVOP_SAVE: 1157d714a24SMaxime Ripard return env_load_location; 1167d714a24SMaxime Ripard } 1177d714a24SMaxime Ripard 118c9d728ddSSimon Glass return ENVL_UNKNOWN; 119c9d728ddSSimon Glass } 120c9d728ddSSimon Glass 1218a3a7e22SMaxime Ripard 1228a3a7e22SMaxime Ripard /** 1238a3a7e22SMaxime Ripard * env_driver_lookup() - Finds the most suited environment location 1248a3a7e22SMaxime Ripard * @op: operations performed on the environment 1258a3a7e22SMaxime Ripard * @prio: priority between the multiple environments, 0 being the 1268a3a7e22SMaxime Ripard * highest priority 1278a3a7e22SMaxime Ripard * 1288a3a7e22SMaxime Ripard * This will try to find the available environment with the highest 1298a3a7e22SMaxime Ripard * priority in the system. 1308a3a7e22SMaxime Ripard * 1318a3a7e22SMaxime Ripard * Returns: 1328a3a7e22SMaxime Ripard * NULL on error, a pointer to a struct env_driver otherwise 1338a3a7e22SMaxime Ripard */ 1348a3a7e22SMaxime Ripard static struct env_driver *env_driver_lookup(enum env_operation op, int prio) 135c9d728ddSSimon Glass { 1368a3a7e22SMaxime Ripard enum env_location loc = env_get_location(op, prio); 137c9d728ddSSimon Glass struct env_driver *drv; 138c9d728ddSSimon Glass 1398a3a7e22SMaxime Ripard if (loc == ENVL_UNKNOWN) 1408a3a7e22SMaxime Ripard return NULL; 1418a3a7e22SMaxime Ripard 14252746c43SMaxime Ripard drv = _env_driver_lookup(loc); 143c9d728ddSSimon Glass if (!drv) { 144c9d728ddSSimon Glass debug("%s: No environment driver for location %d\n", __func__, 145c9d728ddSSimon Glass loc); 146c9d728ddSSimon Glass return NULL; 147c9d728ddSSimon Glass } 148c9d728ddSSimon Glass 149c9d728ddSSimon Glass return drv; 150c9d728ddSSimon Glass } 151c9d728ddSSimon Glass 152a69d0f60SSimon Glass int env_get_char(int index) 153c9d728ddSSimon Glass { 1548a3a7e22SMaxime Ripard struct env_driver *drv; 1558a3a7e22SMaxime Ripard int prio; 156c9d728ddSSimon Glass 1572d7cb5b4SSimon Glass if (gd->env_valid == ENV_INVALID) 158a69d0f60SSimon Glass return default_environment[index]; 1598a3a7e22SMaxime Ripard 1608a3a7e22SMaxime Ripard for (prio = 0; (drv = env_driver_lookup(ENVOP_GET_CHAR, prio)); prio++) { 1618a3a7e22SMaxime Ripard int ret; 1628a3a7e22SMaxime Ripard 163c9d728ddSSimon Glass if (!drv->get_char) 1648a3a7e22SMaxime Ripard continue; 1658a3a7e22SMaxime Ripard 1661d446087SMaxime Ripard if (!env_has_inited(drv->location)) 1671d446087SMaxime Ripard continue; 1681d446087SMaxime Ripard 169c9d728ddSSimon Glass ret = drv->get_char(index); 1708a3a7e22SMaxime Ripard if (!ret) 1718a3a7e22SMaxime Ripard return 0; 1728a3a7e22SMaxime Ripard 1738a3a7e22SMaxime Ripard debug("%s: Environment %s failed to load (err=%d)\n", __func__, 1748a3a7e22SMaxime Ripard drv->name, ret); 175c9d728ddSSimon Glass } 176c9d728ddSSimon Glass 1778a3a7e22SMaxime Ripard return -ENODEV; 178c9d728ddSSimon Glass } 179c9d728ddSSimon Glass 180c9d728ddSSimon Glass int env_load(void) 181c9d728ddSSimon Glass { 1828a3a7e22SMaxime Ripard struct env_driver *drv; 1838a3a7e22SMaxime Ripard int prio; 184c9d728ddSSimon Glass 1858a3a7e22SMaxime Ripard for (prio = 0; (drv = env_driver_lookup(ENVOP_LOAD, prio)); prio++) { 1868a3a7e22SMaxime Ripard int ret; 1878a3a7e22SMaxime Ripard 188c9d728ddSSimon Glass if (!drv->load) 1898a3a7e22SMaxime Ripard continue; 1908a3a7e22SMaxime Ripard 1911d446087SMaxime Ripard if (!env_has_inited(drv->location)) 1921d446087SMaxime Ripard continue; 1931d446087SMaxime Ripard 1943574ba01SMaxime Ripard printf("Loading Environment from %s... ", drv->name); 195c55d8b94SSimon Glass ret = drv->load(); 1963574ba01SMaxime Ripard if (ret) 1973574ba01SMaxime Ripard printf("Failed (%d)\n", ret); 1983574ba01SMaxime Ripard else 1993574ba01SMaxime Ripard printf("OK\n"); 2003574ba01SMaxime Ripard 2018a3a7e22SMaxime Ripard if (!ret) 2028a3a7e22SMaxime Ripard return 0; 203c9d728ddSSimon Glass } 204c9d728ddSSimon Glass 2058a3a7e22SMaxime Ripard return -ENODEV; 206c9d728ddSSimon Glass } 207c9d728ddSSimon Glass 208c9d728ddSSimon Glass int env_save(void) 209c9d728ddSSimon Glass { 2108a3a7e22SMaxime Ripard struct env_driver *drv; 2118a3a7e22SMaxime Ripard int prio; 2128a3a7e22SMaxime Ripard 2138a3a7e22SMaxime Ripard for (prio = 0; (drv = env_driver_lookup(ENVOP_SAVE, prio)); prio++) { 214c9d728ddSSimon Glass int ret; 215c9d728ddSSimon Glass 216c9d728ddSSimon Glass if (!drv->save) 2178a3a7e22SMaxime Ripard continue; 2189c24dfb2SMaxime Ripard 2191d446087SMaxime Ripard if (!env_has_inited(drv->location)) 2201d446087SMaxime Ripard continue; 2211d446087SMaxime Ripard 2229efac3c8SMaxime Ripard printf("Saving Environment to %s... ", drv->name); 223c9d728ddSSimon Glass ret = drv->save(); 2243574ba01SMaxime Ripard if (ret) 2253574ba01SMaxime Ripard printf("Failed (%d)\n", ret); 2263574ba01SMaxime Ripard else 2273574ba01SMaxime Ripard printf("OK\n"); 2283574ba01SMaxime Ripard 2298a3a7e22SMaxime Ripard if (!ret) 2308a3a7e22SMaxime Ripard return 0; 231c9d728ddSSimon Glass } 232c9d728ddSSimon Glass 2338a3a7e22SMaxime Ripard return -ENODEV; 234c9d728ddSSimon Glass } 235c9d728ddSSimon Glass 2366eeae424SSimon Glass int env_init(void) 237c9d728ddSSimon Glass { 2388a3a7e22SMaxime Ripard struct env_driver *drv; 2397938822aSSimon Glass int ret = -ENOENT; 2408a3a7e22SMaxime Ripard int prio; 241c9d728ddSSimon Glass 2428a3a7e22SMaxime Ripard for (prio = 0; (drv = env_driver_lookup(ENVOP_INIT, prio)); prio++) { 2431d446087SMaxime Ripard if (!drv->init || !(ret = drv->init())) 2441d446087SMaxime Ripard env_set_inited(drv->location); 2458a3a7e22SMaxime Ripard 2461d446087SMaxime Ripard debug("%s: Environment %s init done (ret=%d)\n", __func__, 2478a3a7e22SMaxime Ripard drv->name, ret); 2488a3a7e22SMaxime Ripard } 2498a3a7e22SMaxime Ripard 2508a3a7e22SMaxime Ripard if (!prio) 2518a3a7e22SMaxime Ripard return -ENODEV; 2528a3a7e22SMaxime Ripard 2537938822aSSimon Glass if (ret == -ENOENT) { 2547938822aSSimon Glass gd->env_addr = (ulong)&default_environment[0]; 255eeba55cbSTom Rini gd->env_valid = ENV_VALID; 2567938822aSSimon Glass 2577938822aSSimon Glass return 0; 258c9d728ddSSimon Glass } 259c9d728ddSSimon Glass 2608a3a7e22SMaxime Ripard return ret; 261c9d728ddSSimon Glass } 262