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 651d446087SMaxime Ripard static bool env_has_inited(enum env_location location) 661d446087SMaxime Ripard { 671d446087SMaxime Ripard return gd->env_has_init & BIT(location); 681d446087SMaxime Ripard } 691d446087SMaxime Ripard 701d446087SMaxime Ripard static void env_set_inited(enum env_location location) 711d446087SMaxime Ripard { 721d446087SMaxime Ripard /* 731d446087SMaxime Ripard * We're using a 32-bits bitmask stored in gd (env_has_init) 741d446087SMaxime Ripard * using the above enum value as the bit index. We need to 751d446087SMaxime Ripard * make sure that we're not overflowing it. 761d446087SMaxime Ripard */ 771d446087SMaxime Ripard BUILD_BUG_ON(ARRAY_SIZE(env_locations) > BITS_PER_LONG); 781d446087SMaxime Ripard 791d446087SMaxime Ripard gd->env_has_init |= BIT(location); 801d446087SMaxime Ripard } 811d446087SMaxime Ripard 828a3a7e22SMaxime Ripard /** 838a3a7e22SMaxime Ripard * env_get_location() - Returns the best env location for a board 848a3a7e22SMaxime Ripard * @op: operations performed on the environment 858a3a7e22SMaxime Ripard * @prio: priority between the multiple environments, 0 being the 868a3a7e22SMaxime Ripard * highest priority 878a3a7e22SMaxime Ripard * 888a3a7e22SMaxime Ripard * This will return the preferred environment for the given priority. 8940c08a68SMaxime Ripard * This is overridable by boards if they need to. 908a3a7e22SMaxime Ripard * 918a3a7e22SMaxime Ripard * All implementations are free to use the operation, the priority and 928a3a7e22SMaxime Ripard * any other data relevant to their choice, but must take into account 938a3a7e22SMaxime Ripard * the fact that the lowest prority (0) is the most important location 948a3a7e22SMaxime Ripard * in the system. The following locations should be returned by order 958a3a7e22SMaxime Ripard * of descending priorities, from the highest to the lowest priority. 968a3a7e22SMaxime Ripard * 978a3a7e22SMaxime Ripard * Returns: 988a3a7e22SMaxime Ripard * an enum env_location value on success, a negative error code otherwise 998a3a7e22SMaxime Ripard */ 10040c08a68SMaxime Ripard __weak enum env_location env_get_location(enum env_operation op, int prio) 101c9d728ddSSimon Glass { 1027d714a24SMaxime Ripard switch (op) { 1037d714a24SMaxime Ripard case ENVOP_GET_CHAR: 1047d714a24SMaxime Ripard case ENVOP_INIT: 1057d714a24SMaxime Ripard case ENVOP_LOAD: 1067d714a24SMaxime Ripard if (prio >= ARRAY_SIZE(env_locations)) 1078a3a7e22SMaxime Ripard return ENVL_UNKNOWN; 1088a3a7e22SMaxime Ripard 109*e1caa584SYork Sun gd->env_load_location = env_locations[prio]; 110*e1caa584SYork Sun return gd->env_load_location; 1117d714a24SMaxime Ripard 1127d714a24SMaxime Ripard case ENVOP_SAVE: 113*e1caa584SYork Sun return gd->env_load_location; 1147d714a24SMaxime Ripard } 1157d714a24SMaxime Ripard 116c9d728ddSSimon Glass return ENVL_UNKNOWN; 117c9d728ddSSimon Glass } 118c9d728ddSSimon Glass 1198a3a7e22SMaxime Ripard 1208a3a7e22SMaxime Ripard /** 1218a3a7e22SMaxime Ripard * env_driver_lookup() - Finds the most suited environment location 1228a3a7e22SMaxime Ripard * @op: operations performed on the environment 1238a3a7e22SMaxime Ripard * @prio: priority between the multiple environments, 0 being the 1248a3a7e22SMaxime Ripard * highest priority 1258a3a7e22SMaxime Ripard * 1268a3a7e22SMaxime Ripard * This will try to find the available environment with the highest 1278a3a7e22SMaxime Ripard * priority in the system. 1288a3a7e22SMaxime Ripard * 1298a3a7e22SMaxime Ripard * Returns: 1308a3a7e22SMaxime Ripard * NULL on error, a pointer to a struct env_driver otherwise 1318a3a7e22SMaxime Ripard */ 1328a3a7e22SMaxime Ripard static struct env_driver *env_driver_lookup(enum env_operation op, int prio) 133c9d728ddSSimon Glass { 1348a3a7e22SMaxime Ripard enum env_location loc = env_get_location(op, prio); 135c9d728ddSSimon Glass struct env_driver *drv; 136c9d728ddSSimon Glass 1378a3a7e22SMaxime Ripard if (loc == ENVL_UNKNOWN) 1388a3a7e22SMaxime Ripard return NULL; 1398a3a7e22SMaxime Ripard 14052746c43SMaxime Ripard drv = _env_driver_lookup(loc); 141c9d728ddSSimon Glass if (!drv) { 142c9d728ddSSimon Glass debug("%s: No environment driver for location %d\n", __func__, 143c9d728ddSSimon Glass loc); 144c9d728ddSSimon Glass return NULL; 145c9d728ddSSimon Glass } 146c9d728ddSSimon Glass 147c9d728ddSSimon Glass return drv; 148c9d728ddSSimon Glass } 149c9d728ddSSimon Glass 150a69d0f60SSimon Glass int env_get_char(int index) 151c9d728ddSSimon Glass { 1528a3a7e22SMaxime Ripard struct env_driver *drv; 1538a3a7e22SMaxime Ripard int prio; 154c9d728ddSSimon Glass 1552d7cb5b4SSimon Glass if (gd->env_valid == ENV_INVALID) 156a69d0f60SSimon Glass return default_environment[index]; 1578a3a7e22SMaxime Ripard 1588a3a7e22SMaxime Ripard for (prio = 0; (drv = env_driver_lookup(ENVOP_GET_CHAR, prio)); prio++) { 1598a3a7e22SMaxime Ripard int ret; 1608a3a7e22SMaxime Ripard 161c9d728ddSSimon Glass if (!drv->get_char) 1628a3a7e22SMaxime Ripard continue; 1638a3a7e22SMaxime Ripard 1641d446087SMaxime Ripard if (!env_has_inited(drv->location)) 1651d446087SMaxime Ripard continue; 1661d446087SMaxime Ripard 167c9d728ddSSimon Glass ret = drv->get_char(index); 1688a3a7e22SMaxime Ripard if (!ret) 1698a3a7e22SMaxime Ripard return 0; 1708a3a7e22SMaxime Ripard 1718a3a7e22SMaxime Ripard debug("%s: Environment %s failed to load (err=%d)\n", __func__, 1728a3a7e22SMaxime Ripard drv->name, ret); 173c9d728ddSSimon Glass } 174c9d728ddSSimon Glass 1758a3a7e22SMaxime Ripard return -ENODEV; 176c9d728ddSSimon Glass } 177c9d728ddSSimon Glass 178c9d728ddSSimon Glass int env_load(void) 179c9d728ddSSimon Glass { 1808a3a7e22SMaxime Ripard struct env_driver *drv; 1818a3a7e22SMaxime Ripard int prio; 182c9d728ddSSimon Glass 1838a3a7e22SMaxime Ripard for (prio = 0; (drv = env_driver_lookup(ENVOP_LOAD, prio)); prio++) { 1848a3a7e22SMaxime Ripard int ret; 1858a3a7e22SMaxime Ripard 186c9d728ddSSimon Glass if (!drv->load) 1878a3a7e22SMaxime Ripard continue; 1888a3a7e22SMaxime Ripard 1891d446087SMaxime Ripard if (!env_has_inited(drv->location)) 1901d446087SMaxime Ripard continue; 1911d446087SMaxime Ripard 1923574ba01SMaxime Ripard printf("Loading Environment from %s... ", drv->name); 193c55d8b94SSimon Glass ret = drv->load(); 1943574ba01SMaxime Ripard if (ret) 1953574ba01SMaxime Ripard printf("Failed (%d)\n", ret); 1963574ba01SMaxime Ripard else 1973574ba01SMaxime Ripard printf("OK\n"); 1983574ba01SMaxime Ripard 1998a3a7e22SMaxime Ripard if (!ret) 2008a3a7e22SMaxime Ripard return 0; 201c9d728ddSSimon Glass } 202c9d728ddSSimon Glass 2038a3a7e22SMaxime Ripard return -ENODEV; 204c9d728ddSSimon Glass } 205c9d728ddSSimon Glass 206c9d728ddSSimon Glass int env_save(void) 207c9d728ddSSimon Glass { 2088a3a7e22SMaxime Ripard struct env_driver *drv; 2098a3a7e22SMaxime Ripard int prio; 2108a3a7e22SMaxime Ripard 2118a3a7e22SMaxime Ripard for (prio = 0; (drv = env_driver_lookup(ENVOP_SAVE, prio)); prio++) { 212c9d728ddSSimon Glass int ret; 213c9d728ddSSimon Glass 214c9d728ddSSimon Glass if (!drv->save) 2158a3a7e22SMaxime Ripard continue; 2169c24dfb2SMaxime Ripard 2171d446087SMaxime Ripard if (!env_has_inited(drv->location)) 2181d446087SMaxime Ripard continue; 2191d446087SMaxime Ripard 2209efac3c8SMaxime Ripard printf("Saving Environment to %s... ", drv->name); 221c9d728ddSSimon Glass ret = drv->save(); 2223574ba01SMaxime Ripard if (ret) 2233574ba01SMaxime Ripard printf("Failed (%d)\n", ret); 2243574ba01SMaxime Ripard else 2253574ba01SMaxime Ripard printf("OK\n"); 2263574ba01SMaxime Ripard 2278a3a7e22SMaxime Ripard if (!ret) 2288a3a7e22SMaxime Ripard return 0; 229c9d728ddSSimon Glass } 230c9d728ddSSimon Glass 2318a3a7e22SMaxime Ripard return -ENODEV; 232c9d728ddSSimon Glass } 233c9d728ddSSimon Glass 2346eeae424SSimon Glass int env_init(void) 235c9d728ddSSimon Glass { 2368a3a7e22SMaxime Ripard struct env_driver *drv; 2377938822aSSimon Glass int ret = -ENOENT; 2388a3a7e22SMaxime Ripard int prio; 239c9d728ddSSimon Glass 2408a3a7e22SMaxime Ripard for (prio = 0; (drv = env_driver_lookup(ENVOP_INIT, prio)); prio++) { 2411d446087SMaxime Ripard if (!drv->init || !(ret = drv->init())) 2421d446087SMaxime Ripard env_set_inited(drv->location); 2438a3a7e22SMaxime Ripard 2441d446087SMaxime Ripard debug("%s: Environment %s init done (ret=%d)\n", __func__, 2458a3a7e22SMaxime Ripard drv->name, ret); 2468a3a7e22SMaxime Ripard } 2478a3a7e22SMaxime Ripard 2488a3a7e22SMaxime Ripard if (!prio) 2498a3a7e22SMaxime Ripard return -ENODEV; 2508a3a7e22SMaxime Ripard 2517938822aSSimon Glass if (ret == -ENOENT) { 2527938822aSSimon Glass gd->env_addr = (ulong)&default_environment[0]; 253eeba55cbSTom Rini gd->env_valid = ENV_VALID; 2547938822aSSimon Glass 2557938822aSSimon Glass return 0; 256c9d728ddSSimon Glass } 257c9d728ddSSimon Glass 2588a3a7e22SMaxime Ripard return ret; 259c9d728ddSSimon Glass } 260