blob: 8941e0f5ff3966c87568431f270f22f2432776ec [file] [log] [blame]
Tom Rini10e47792018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
Terry Lvb4eceac2010-05-17 10:57:01 +08002/*
Mingkai Hua55fce32011-01-24 17:09:55 +00003 * (C) Copyright 2008-2011 Freescale Semiconductor, Inc.
Terry Lvb4eceac2010-05-17 10:57:01 +08004 */
5
6/* #define DEBUG */
7
8#include <common.h>
Simon Glass3ba929a2020-10-30 21:38:53 -06009#include <asm/global_data.h>
Terry Lvb4eceac2010-05-17 10:57:01 +080010
11#include <command.h>
Simon Glass97385862019-08-01 09:47:00 -060012#include <env.h>
Simon Glass9d1f6192019-08-02 09:44:25 -060013#include <env_internal.h>
Philipp Tomsich8ab507b2017-05-16 00:16:31 +020014#include <fdtdec.h>
Terry Lvb4eceac2010-05-17 10:57:01 +080015#include <linux/stddef.h>
16#include <malloc.h>
Simon Glass2dd337a2015-09-02 17:24:58 -060017#include <memalign.h>
Terry Lvb4eceac2010-05-17 10:57:01 +080018#include <mmc.h>
Jorge Ramirez-Ortiz03ab46c2017-11-06 14:16:37 +010019#include <part.h>
Lei Wen9f84f212010-11-10 07:39:23 +080020#include <search.h>
Lei Wenff833ed2010-10-13 11:07:21 +080021#include <errno.h>
Simon Glass0034d962021-08-07 07:24:01 -060022#include <dm/ofnode.h>
Terry Lvb4eceac2010-05-17 10:57:01 +080023
Jorge Ramirez-Ortiz03ab46c2017-11-06 14:16:37 +010024#define __STR(X) #X
25#define STR(X) __STR(X)
26
Patrick Delaunayf080c4c2022-11-10 11:48:58 +010027#define ENV_MMC_INVALID_OFFSET ((s64)-1)
28
Patrick Delaunay41e143f2022-11-10 11:49:01 +010029#if defined(CONFIG_ENV_MMC_USE_DT)
30/* ENV offset is invalid when not defined in Device Tree */
31#define ENV_MMC_OFFSET ENV_MMC_INVALID_OFFSET
32#define ENV_MMC_OFFSET_REDUND ENV_MMC_INVALID_OFFSET
33
34#else
Patrick Delaunayf080c4c2022-11-10 11:48:58 +010035/* Default ENV offset when not defined in Device Tree */
36#define ENV_MMC_OFFSET CONFIG_ENV_OFFSET
37
38#if defined(CONFIG_ENV_OFFSET_REDUND)
39#define ENV_MMC_OFFSET_REDUND CONFIG_ENV_OFFSET_REDUND
40#else
41#define ENV_MMC_OFFSET_REDUND ENV_MMC_INVALID_OFFSET
42#endif
Patrick Delaunay41e143f2022-11-10 11:49:01 +010043#endif
Patrick Delaunayf080c4c2022-11-10 11:48:58 +010044
Terry Lvb4eceac2010-05-17 10:57:01 +080045DECLARE_GLOBAL_DATA_PTR;
46
Marek Vasut509f36e2021-10-17 19:23:36 +020047/*
48 * In case the environment is redundant, stored in eMMC hardware boot
49 * partition and the environment and redundant environment offsets are
50 * identical, store the environment and redundant environment in both
51 * eMMC boot partitions, one copy in each.
52 * */
53#if (defined(CONFIG_SYS_REDUNDAND_ENVIRONMENT) && \
54 (CONFIG_SYS_MMC_ENV_PART == 1) && \
55 (CONFIG_ENV_OFFSET == CONFIG_ENV_OFFSET_REDUND))
Patrick Delaunay036a3582022-11-10 11:48:59 +010056#define ENV_MMC_HWPART_REDUND 1
Marek Vasut509f36e2021-10-17 19:23:36 +020057#endif
58
Philipp Tomsich8ab507b2017-05-16 00:16:31 +020059#if CONFIG_IS_ENABLED(OF_CONTROL)
Patrick Delaunayeff81952020-06-15 10:38:57 +020060static inline int mmc_offset_try_partition(const char *str, int copy, s64 *val)
Jorge Ramirez-Ortiz03ab46c2017-11-06 14:16:37 +010061{
Simon Glassc1c4a8f2020-05-10 11:39:57 -060062 struct disk_partition info;
Jorge Ramirez-Ortiz03ab46c2017-11-06 14:16:37 +010063 struct blk_desc *desc;
64 int len, i, ret;
Patrick Delaunay530cb452020-06-15 10:38:55 +020065 char dev_str[4];
Jorge Ramirez-Ortiz03ab46c2017-11-06 14:16:37 +010066
Patrick Delaunay530cb452020-06-15 10:38:55 +020067 snprintf(dev_str, sizeof(dev_str), "%d", mmc_get_env_dev());
68 ret = blk_get_device_by_str("mmc", dev_str, &desc);
Jorge Ramirez-Ortiz03ab46c2017-11-06 14:16:37 +010069 if (ret < 0)
70 return (ret);
71
72 for (i = 1;;i++) {
73 ret = part_get_info(desc, i, &info);
74 if (ret < 0)
75 return ret;
76
Patrick Delaunayeb787872022-11-10 11:49:03 +010077 if (str && !strncmp((const char *)info.name, str, sizeof(info.name)))
Jorge Ramirez-Ortiz03ab46c2017-11-06 14:16:37 +010078 break;
Patrick Delaunayeb787872022-11-10 11:49:03 +010079#ifdef CONFIG_PARTITION_TYPE_GUID
80 if (!str) {
81 const efi_guid_t env_guid = PARTITION_U_BOOT_ENVIRONMENT;
82 efi_guid_t type_guid;
83
84 uuid_str_to_bin(info.type_guid, type_guid.b, UUID_STR_FORMAT_GUID);
85 if (!memcmp(&env_guid, &type_guid, sizeof(efi_guid_t)))
86 break;
87 }
88#endif
Jorge Ramirez-Ortiz03ab46c2017-11-06 14:16:37 +010089 }
90
91 /* round up to info.blksz */
Patrick Delaunay66fba3a2020-06-15 10:38:56 +020092 len = DIV_ROUND_UP(CONFIG_ENV_SIZE, info.blksz);
Jorge Ramirez-Ortiz03ab46c2017-11-06 14:16:37 +010093
94 /* use the top of the partion for the environment */
Patrick Delaunayeff81952020-06-15 10:38:57 +020095 *val = (info.start + info.size - (1 + copy) * len) * info.blksz;
Jorge Ramirez-Ortiz03ab46c2017-11-06 14:16:37 +010096
97 return 0;
98}
99
Philipp Tomsich8ab507b2017-05-16 00:16:31 +0200100static inline s64 mmc_offset(int copy)
101{
Jorge Ramirez-Ortiz03ab46c2017-11-06 14:16:37 +0100102 const struct {
103 const char *offset_redund;
104 const char *partition;
105 const char *offset;
106 } dt_prop = {
107 .offset_redund = "u-boot,mmc-env-offset-redundant",
108 .partition = "u-boot,mmc-env-partition",
109 .offset = "u-boot,mmc-env-offset",
110 };
Philipp Tomsich745d8de2017-11-21 23:29:40 +0100111 s64 val = 0, defvalue;
Jorge Ramirez-Ortiz03ab46c2017-11-06 14:16:37 +0100112 const char *propname;
113 const char *str;
114 int err;
115
116 /* look for the partition in mmc CONFIG_SYS_MMC_ENV_DEV */
Simon Glass0034d962021-08-07 07:24:01 -0600117 str = ofnode_conf_read_str(dt_prop.partition);
Jorge Ramirez-Ortiz03ab46c2017-11-06 14:16:37 +0100118 if (str) {
119 /* try to place the environment at end of the partition */
Patrick Delaunayeff81952020-06-15 10:38:57 +0200120 err = mmc_offset_try_partition(str, copy, &val);
Jorge Ramirez-Ortiz03ab46c2017-11-06 14:16:37 +0100121 if (!err)
122 return val;
Patrick Delaunay01b07982022-11-10 11:49:04 +0100123 debug("env partition '%s' not found (%d)", str, err);
Jorge Ramirez-Ortiz03ab46c2017-11-06 14:16:37 +0100124 }
125
Patrick Delaunayeb787872022-11-10 11:49:03 +0100126 /* try the GPT partition with "U-Boot ENV" TYPE GUID */
127 if (IS_ENABLED(CONFIG_PARTITION_TYPE_GUID)) {
128 err = mmc_offset_try_partition(NULL, copy, &val);
129 if (!err)
130 return val;
131 }
132
Patrick Delaunayf080c4c2022-11-10 11:48:58 +0100133 defvalue = ENV_MMC_OFFSET;
Jorge Ramirez-Ortiz03ab46c2017-11-06 14:16:37 +0100134 propname = dt_prop.offset;
Philipp Tomsich8ab507b2017-05-16 00:16:31 +0200135
Patrick Delaunay036a3582022-11-10 11:48:59 +0100136 if (IS_ENABLED(CONFIG_SYS_REDUNDAND_ENVIRONMENT) && copy) {
Patrick Delaunayf080c4c2022-11-10 11:48:58 +0100137 defvalue = ENV_MMC_OFFSET_REDUND;
Jorge Ramirez-Ortiz03ab46c2017-11-06 14:16:37 +0100138 propname = dt_prop.offset_redund;
Philipp Tomsich8ab507b2017-05-16 00:16:31 +0200139 }
Patrick Delaunay036a3582022-11-10 11:48:59 +0100140
Simon Glass0034d962021-08-07 07:24:01 -0600141 return ofnode_conf_read_int(propname, defvalue);
Philipp Tomsich8ab507b2017-05-16 00:16:31 +0200142}
143#else
144static inline s64 mmc_offset(int copy)
Mingkai Hua55fce32011-01-24 17:09:55 +0000145{
Patrick Delaunayf080c4c2022-11-10 11:48:58 +0100146 s64 offset = ENV_MMC_OFFSET;
Stephen Warren24dc2032013-06-11 15:14:02 -0600147
Patrick Delaunay036a3582022-11-10 11:48:59 +0100148 if (IS_ENABLED(CONFIG_SYS_REDUNDAND_ENVIRONMENT) && copy)
Patrick Delaunayf080c4c2022-11-10 11:48:58 +0100149 offset = ENV_MMC_OFFSET_REDUND;
Patrick Delaunay036a3582022-11-10 11:48:59 +0100150
Philipp Tomsich8ab507b2017-05-16 00:16:31 +0200151 return offset;
152}
153#endif
154
155__weak int mmc_get_env_addr(struct mmc *mmc, int copy, u32 *env_addr)
156{
157 s64 offset = mmc_offset(copy);
Stephen Warren24dc2032013-06-11 15:14:02 -0600158
Patrick Delaunayf080c4c2022-11-10 11:48:58 +0100159 if (offset == ENV_MMC_INVALID_OFFSET) {
160 printf("Invalid ENV offset in MMC, copy=%d\n", copy);
161 return -ENOENT;
162 }
163
Stephen Warren24dc2032013-06-11 15:14:02 -0600164 if (offset < 0)
165 offset += mmc->capacity;
166
167 *env_addr = offset;
168
Mingkai Hua55fce32011-01-24 17:09:55 +0000169 return 0;
170}
Mingkai Hua55fce32011-01-24 17:09:55 +0000171
Tom Rinic929f822014-03-28 12:03:34 -0400172#ifdef CONFIG_SYS_MMC_ENV_PART
Dmitry Lifshitz97d2fb92014-07-30 13:19:06 +0300173__weak uint mmc_get_env_part(struct mmc *mmc)
174{
175 return CONFIG_SYS_MMC_ENV_PART;
176}
177
Stephen Warren1e0f92a2015-12-07 11:38:49 -0700178static unsigned char env_mmc_orig_hwpart;
179
Marek Vasut509f36e2021-10-17 19:23:36 +0200180static int mmc_set_env_part(struct mmc *mmc, uint part)
Dmitry Lifshitz97d2fb92014-07-30 13:19:06 +0300181{
Clemens Gruberf7b61442016-01-20 15:43:37 +0100182 int dev = mmc_get_env_dev();
Dmitry Lifshitz97d2fb92014-07-30 13:19:06 +0300183 int ret = 0;
Tom Rinic929f822014-03-28 12:03:34 -0400184
Simon Glassdbfa32c2022-08-11 19:34:59 -0600185 ret = blk_select_hwpart_devnum(UCLASS_MMC, dev, part);
Stephen Warren1e0f92a2015-12-07 11:38:49 -0700186 if (ret)
187 puts("MMC partition switch failed\n");
Dmitry Lifshitz97d2fb92014-07-30 13:19:06 +0300188
189 return ret;
190}
Patrick Delaunay036a3582022-11-10 11:48:59 +0100191
192static bool mmc_set_env_part_init(struct mmc *mmc)
193{
194 env_mmc_orig_hwpart = mmc_get_blk_desc(mmc)->hwpart;
195 if (mmc_set_env_part(mmc, mmc_get_env_part(mmc)))
196 return false;
197
198 return true;
199}
200
201static int mmc_set_env_part_restore(struct mmc *mmc)
202{
203 return mmc_set_env_part(mmc, env_mmc_orig_hwpart);
204}
Dmitry Lifshitz97d2fb92014-07-30 13:19:06 +0300205#else
Marek Vasut509f36e2021-10-17 19:23:36 +0200206static inline int mmc_set_env_part(struct mmc *mmc, uint part) {return 0; };
Patrick Delaunay036a3582022-11-10 11:48:59 +0100207static bool mmc_set_env_part_init(struct mmc *mmc) {return true; }
208static inline int mmc_set_env_part_restore(struct mmc *mmc) {return 0; };
Tom Rinic929f822014-03-28 12:03:34 -0400209#endif
210
Tim Harveyeda75c32015-05-08 14:52:09 -0700211static const char *init_mmc_for_env(struct mmc *mmc)
Dmitry Lifshitz97d2fb92014-07-30 13:19:06 +0300212{
Tim Harveyeda75c32015-05-08 14:52:09 -0700213 if (!mmc)
Yaniv Levinskyb2bb9bc2018-06-24 19:16:57 +0300214 return "No MMC card found";
Terry Lvb4eceac2010-05-17 10:57:01 +0800215
Sjoerd Simons5e4546d2018-03-22 22:53:50 +0100216#if CONFIG_IS_ENABLED(BLK)
Simon Glass1d9907c2017-05-27 11:37:18 -0600217 struct udevice *dev;
218
219 if (blk_get_from_parent(mmc->dev, &dev))
Yaniv Levinskyb2bb9bc2018-06-24 19:16:57 +0300220 return "No block device";
Simon Glass1d9907c2017-05-27 11:37:18 -0600221#else
Tim Harveyeda75c32015-05-08 14:52:09 -0700222 if (mmc_init(mmc))
Yaniv Levinskyb2bb9bc2018-06-24 19:16:57 +0300223 return "MMC init failed";
Simon Glass86d78c72017-04-23 20:02:04 -0600224#endif
Patrick Delaunay036a3582022-11-10 11:48:59 +0100225 if (!mmc_set_env_part_init(mmc))
Yaniv Levinskyb2bb9bc2018-06-24 19:16:57 +0300226 return "MMC partition switch failed";
Tim Harveyeda75c32015-05-08 14:52:09 -0700227
228 return NULL;
Terry Lvb4eceac2010-05-17 10:57:01 +0800229}
230
Stephen Warren27ee0f32012-07-30 10:55:44 +0000231static void fini_mmc_for_env(struct mmc *mmc)
232{
Patrick Delaunay036a3582022-11-10 11:48:59 +0100233 mmc_set_env_part_restore(mmc);
Stephen Warren27ee0f32012-07-30 10:55:44 +0000234}
235
Simon Glass082af922017-08-03 12:22:01 -0600236#if defined(CONFIG_CMD_SAVEENV) && !defined(CONFIG_SPL_BUILD)
Igor Grinbergecbfb622011-11-07 01:14:05 +0000237static inline int write_env(struct mmc *mmc, unsigned long size,
238 unsigned long offset, const void *buffer)
Terry Lvb4eceac2010-05-17 10:57:01 +0800239{
240 uint blk_start, blk_cnt, n;
Simon Glassda898922016-05-14 14:03:03 -0600241 struct blk_desc *desc = mmc_get_blk_desc(mmc);
Terry Lvb4eceac2010-05-17 10:57:01 +0800242
Igor Grinbergecbfb622011-11-07 01:14:05 +0000243 blk_start = ALIGN(offset, mmc->write_bl_len) / mmc->write_bl_len;
244 blk_cnt = ALIGN(size, mmc->write_bl_len) / mmc->write_bl_len;
Terry Lvb4eceac2010-05-17 10:57:01 +0800245
Simon Glassda898922016-05-14 14:03:03 -0600246 n = blk_dwrite(desc, blk_start, blk_cnt, (u_char *)buffer);
Terry Lvb4eceac2010-05-17 10:57:01 +0800247
248 return (n == blk_cnt) ? 0 : -1;
249}
250
Simon Glass082af922017-08-03 12:22:01 -0600251static int env_mmc_save(void)
Terry Lvb4eceac2010-05-17 10:57:01 +0800252{
Tom Rinia840b8e2013-04-05 14:55:21 -0400253 ALLOC_CACHE_ALIGN_BUFFER(env_t, env_new, 1);
Clemens Gruberf7b61442016-01-20 15:43:37 +0100254 int dev = mmc_get_env_dev();
255 struct mmc *mmc = find_mmc_device(dev);
Igor Grinbergecbfb622011-11-07 01:14:05 +0000256 u32 offset;
Michael Heimpolda1d25a32013-04-10 10:36:19 +0000257 int ret, copy = 0;
Tim Harveyeda75c32015-05-08 14:52:09 -0700258 const char *errmsg;
Terry Lvb4eceac2010-05-17 10:57:01 +0800259
Tim Harveyeda75c32015-05-08 14:52:09 -0700260 errmsg = init_mmc_for_env(mmc);
261 if (errmsg) {
262 printf("%s\n", errmsg);
Terry Lvb4eceac2010-05-17 10:57:01 +0800263 return 1;
Tim Harveyeda75c32015-05-08 14:52:09 -0700264 }
Terry Lvb4eceac2010-05-17 10:57:01 +0800265
Marek Vasutd73c1292014-03-05 19:59:50 +0100266 ret = env_export(env_new);
267 if (ret)
Stephen Warren27ee0f32012-07-30 10:55:44 +0000268 goto fini;
Michael Heimpolda1d25a32013-04-10 10:36:19 +0000269
Patrick Delaunay036a3582022-11-10 11:48:59 +0100270 if (IS_ENABLED(CONFIG_SYS_REDUNDAND_ENVIRONMENT)) {
271 if (gd->env_valid == ENV_VALID)
272 copy = 1;
Marek Vasut509f36e2021-10-17 19:23:36 +0200273
Patrick Delaunay036a3582022-11-10 11:48:59 +0100274 if (IS_ENABLED(ENV_MMC_HWPART_REDUND)) {
275 ret = mmc_set_env_part(mmc, copy + 1);
276 if (ret)
277 goto fini;
278 }
Michael Heimpolda1d25a32013-04-10 10:36:19 +0000279
Patrick Delaunay036a3582022-11-10 11:48:59 +0100280 if (mmc_get_env_addr(mmc, copy, &offset)) {
281 ret = 1;
282 goto fini;
283 }
Michael Heimpolda1d25a32013-04-10 10:36:19 +0000284 }
285
Clemens Gruberf7b61442016-01-20 15:43:37 +0100286 printf("Writing to %sMMC(%d)... ", copy ? "redundant " : "", dev);
Stephen Warren42a3c442012-05-24 11:38:33 +0000287 if (write_env(mmc, CONFIG_ENV_SIZE, offset, (u_char *)env_new)) {
Terry Lvb4eceac2010-05-17 10:57:01 +0800288 puts("failed\n");
Stephen Warren27ee0f32012-07-30 10:55:44 +0000289 ret = 1;
290 goto fini;
Terry Lvb4eceac2010-05-17 10:57:01 +0800291 }
292
Stephen Warren27ee0f32012-07-30 10:55:44 +0000293 ret = 0;
294
Patrick Delaunay036a3582022-11-10 11:48:59 +0100295 if (IS_ENABLED(CONFIG_SYS_REDUNDAND_ENVIRONMENT))
296 gd->env_valid = gd->env_valid == ENV_REDUND ? ENV_VALID : ENV_REDUND;
Michael Heimpolda1d25a32013-04-10 10:36:19 +0000297
Stephen Warren27ee0f32012-07-30 10:55:44 +0000298fini:
299 fini_mmc_for_env(mmc);
Patrick Delaunay036a3582022-11-10 11:48:59 +0100300
Stephen Warren27ee0f32012-07-30 10:55:44 +0000301 return ret;
Terry Lvb4eceac2010-05-17 10:57:01 +0800302}
Frank Wunderlich81f087e2019-06-29 11:36:20 +0200303
Frank Wunderlich81f087e2019-06-29 11:36:20 +0200304static inline int erase_env(struct mmc *mmc, unsigned long size,
305 unsigned long offset)
306{
307 uint blk_start, blk_cnt, n;
308 struct blk_desc *desc = mmc_get_blk_desc(mmc);
Patrick Delaunayab5ea4d2022-02-15 16:23:23 +0100309 u32 erase_size;
Frank Wunderlich81f087e2019-06-29 11:36:20 +0200310
Patrick Delaunayab5ea4d2022-02-15 16:23:23 +0100311 erase_size = mmc->erase_grp_size * desc->blksz;
312 blk_start = ALIGN_DOWN(offset, erase_size) / desc->blksz;
313 blk_cnt = ALIGN(size, erase_size) / desc->blksz;
Frank Wunderlich81f087e2019-06-29 11:36:20 +0200314
315 n = blk_derase(desc, blk_start, blk_cnt);
Patrick Delaunayab5ea4d2022-02-15 16:23:23 +0100316 printf("%d blocks erased at 0x%x: %s\n", n, blk_start,
317 (n == blk_cnt) ? "OK" : "ERROR");
Frank Wunderlich81f087e2019-06-29 11:36:20 +0200318
319 return (n == blk_cnt) ? 0 : 1;
320}
321
322static int env_mmc_erase(void)
323{
324 int dev = mmc_get_env_dev();
325 struct mmc *mmc = find_mmc_device(dev);
326 int ret, copy = 0;
327 u32 offset;
328 const char *errmsg;
329
330 errmsg = init_mmc_for_env(mmc);
331 if (errmsg) {
332 printf("%s\n", errmsg);
333 return 1;
334 }
335
Marek Vasutd07a6e32021-10-06 18:29:53 +0200336 if (mmc_get_env_addr(mmc, copy, &offset)) {
337 ret = CMD_RET_FAILURE;
338 goto fini;
339 }
Frank Wunderlich81f087e2019-06-29 11:36:20 +0200340
Patrick Delaunayab5ea4d2022-02-15 16:23:23 +0100341 printf("\n");
Frank Wunderlich81f087e2019-06-29 11:36:20 +0200342 ret = erase_env(mmc, CONFIG_ENV_SIZE, offset);
343
Patrick Delaunay036a3582022-11-10 11:48:59 +0100344 if (IS_ENABLED(CONFIG_SYS_REDUNDAND_ENVIRONMENT)) {
345 copy = 1;
Frank Wunderlich81f087e2019-06-29 11:36:20 +0200346
Patrick Delaunay036a3582022-11-10 11:48:59 +0100347 if (IS_ENABLED(ENV_MMC_HWPART_REDUND)) {
348 ret = mmc_set_env_part(mmc, copy + 1);
349 if (ret)
350 goto fini;
351 }
Marek Vasut509f36e2021-10-17 19:23:36 +0200352
Patrick Delaunay036a3582022-11-10 11:48:59 +0100353 if (mmc_get_env_addr(mmc, copy, &offset)) {
354 ret = CMD_RET_FAILURE;
355 goto fini;
356 }
Frank Wunderlich81f087e2019-06-29 11:36:20 +0200357
Patrick Delaunay036a3582022-11-10 11:48:59 +0100358 ret |= erase_env(mmc, CONFIG_ENV_SIZE, offset);
359 }
Frank Wunderlich81f087e2019-06-29 11:36:20 +0200360
Marek Vasutd07a6e32021-10-06 18:29:53 +0200361fini:
362 fini_mmc_for_env(mmc);
Frank Wunderlich81f087e2019-06-29 11:36:20 +0200363 return ret;
364}
Simon Glass082af922017-08-03 12:22:01 -0600365#endif /* CONFIG_CMD_SAVEENV && !CONFIG_SPL_BUILD */
Terry Lvb4eceac2010-05-17 10:57:01 +0800366
Igor Grinbergecbfb622011-11-07 01:14:05 +0000367static inline int read_env(struct mmc *mmc, unsigned long size,
368 unsigned long offset, const void *buffer)
Terry Lvb4eceac2010-05-17 10:57:01 +0800369{
370 uint blk_start, blk_cnt, n;
Simon Glassda898922016-05-14 14:03:03 -0600371 struct blk_desc *desc = mmc_get_blk_desc(mmc);
Terry Lvb4eceac2010-05-17 10:57:01 +0800372
Igor Grinbergecbfb622011-11-07 01:14:05 +0000373 blk_start = ALIGN(offset, mmc->read_bl_len) / mmc->read_bl_len;
374 blk_cnt = ALIGN(size, mmc->read_bl_len) / mmc->read_bl_len;
Terry Lvb4eceac2010-05-17 10:57:01 +0800375
Simon Glassda898922016-05-14 14:03:03 -0600376 n = blk_dread(desc, blk_start, blk_cnt, (uchar *)buffer);
Terry Lvb4eceac2010-05-17 10:57:01 +0800377
378 return (n == blk_cnt) ? 0 : -1;
379}
380
Patrick Delaunayd948e712022-11-10 11:49:00 +0100381#if defined(ENV_IS_EMBEDDED)
Simon Glass99778492017-08-03 12:22:17 -0600382static int env_mmc_load(void)
Michael Heimpolda1d25a32013-04-10 10:36:19 +0000383{
Patrick Delaunayd948e712022-11-10 11:49:00 +0100384 return 0;
385}
386#elif defined(CONFIG_SYS_REDUNDAND_ENVIRONMENT)
387static int env_mmc_load(void)
388{
Tom Rinic929f822014-03-28 12:03:34 -0400389 struct mmc *mmc;
Michael Heimpolda1d25a32013-04-10 10:36:19 +0000390 u32 offset1, offset2;
391 int read1_fail = 0, read2_fail = 0;
Michael Heimpolda1d25a32013-04-10 10:36:19 +0000392 int ret;
Clemens Gruberf7b61442016-01-20 15:43:37 +0100393 int dev = mmc_get_env_dev();
Tim Harveyeda75c32015-05-08 14:52:09 -0700394 const char *errmsg = NULL;
Michael Heimpolda1d25a32013-04-10 10:36:19 +0000395
Markus Niebel6ef41fd2013-10-04 15:48:03 +0200396 ALLOC_CACHE_ALIGN_BUFFER(env_t, tmp_env1, 1);
397 ALLOC_CACHE_ALIGN_BUFFER(env_t, tmp_env2, 1);
398
Faiz Abbasaae518f2018-02-12 19:24:31 +0530399 mmc_initialize(NULL);
400
Tom Rinic929f822014-03-28 12:03:34 -0400401 mmc = find_mmc_device(dev);
402
Tim Harveyeda75c32015-05-08 14:52:09 -0700403 errmsg = init_mmc_for_env(mmc);
404 if (errmsg) {
Simon Glass99778492017-08-03 12:22:17 -0600405 ret = -EIO;
Michael Heimpolda1d25a32013-04-10 10:36:19 +0000406 goto err;
407 }
408
409 if (mmc_get_env_addr(mmc, 0, &offset1) ||
410 mmc_get_env_addr(mmc, 1, &offset2)) {
Simon Glass99778492017-08-03 12:22:17 -0600411 ret = -EIO;
Michael Heimpolda1d25a32013-04-10 10:36:19 +0000412 goto fini;
413 }
414
Patrick Delaunay036a3582022-11-10 11:48:59 +0100415 if (IS_ENABLED(ENV_MMC_HWPART_REDUND)) {
416 ret = mmc_set_env_part(mmc, 1);
417 if (ret)
418 goto fini;
419 }
Marek Vasut509f36e2021-10-17 19:23:36 +0200420
Michael Heimpolda1d25a32013-04-10 10:36:19 +0000421 read1_fail = read_env(mmc, CONFIG_ENV_SIZE, offset1, tmp_env1);
Marek Vasut509f36e2021-10-17 19:23:36 +0200422
Patrick Delaunay036a3582022-11-10 11:48:59 +0100423 if (IS_ENABLED(ENV_MMC_HWPART_REDUND)) {
424 ret = mmc_set_env_part(mmc, 2);
425 if (ret)
426 goto fini;
427 }
Marek Vasut509f36e2021-10-17 19:23:36 +0200428
Michael Heimpolda1d25a32013-04-10 10:36:19 +0000429 read2_fail = read_env(mmc, CONFIG_ENV_SIZE, offset2, tmp_env2);
430
Simon Goldschmidte07096e2018-01-31 14:47:11 +0100431 ret = env_import_redund((char *)tmp_env1, read1_fail, (char *)tmp_env2,
Marek Vasutdfe4b7e2020-07-07 20:51:35 +0200432 read2_fail, H_EXTERNAL);
Michael Heimpolda1d25a32013-04-10 10:36:19 +0000433
434fini:
435 fini_mmc_for_env(mmc);
436err:
437 if (ret)
Simon Glass97385862019-08-01 09:47:00 -0600438 env_set_default(errmsg, 0);
Simon Glass99778492017-08-03 12:22:17 -0600439
Simon Glass99778492017-08-03 12:22:17 -0600440 return ret;
Michael Heimpolda1d25a32013-04-10 10:36:19 +0000441}
Patrick Delaunay036a3582022-11-10 11:48:59 +0100442#else /* ! CONFIG_SYS_REDUNDAND_ENVIRONMENT */
Simon Glass99778492017-08-03 12:22:17 -0600443static int env_mmc_load(void)
Terry Lvb4eceac2010-05-17 10:57:01 +0800444{
Tom Rinia840b8e2013-04-05 14:55:21 -0400445 ALLOC_CACHE_ALIGN_BUFFER(char, buf, CONFIG_ENV_SIZE);
Tom Rinic929f822014-03-28 12:03:34 -0400446 struct mmc *mmc;
Mingkai Hua55fce32011-01-24 17:09:55 +0000447 u32 offset;
Stephen Warren27ee0f32012-07-30 10:55:44 +0000448 int ret;
Clemens Gruberf7b61442016-01-20 15:43:37 +0100449 int dev = mmc_get_env_dev();
Tim Harveyeda75c32015-05-08 14:52:09 -0700450 const char *errmsg;
Pankit Gargc2342f62019-11-19 09:49:31 +0000451 env_t *ep = NULL;
Tom Rinic929f822014-03-28 12:03:34 -0400452
Tom Rinic929f822014-03-28 12:03:34 -0400453 mmc = find_mmc_device(dev);
Stephen Warren27ee0f32012-07-30 10:55:44 +0000454
Tim Harveyeda75c32015-05-08 14:52:09 -0700455 errmsg = init_mmc_for_env(mmc);
456 if (errmsg) {
Simon Glass99778492017-08-03 12:22:17 -0600457 ret = -EIO;
Stephen Warren27ee0f32012-07-30 10:55:44 +0000458 goto err;
459 }
Terry Lvb4eceac2010-05-17 10:57:01 +0800460
Michael Heimpolda1d25a32013-04-10 10:36:19 +0000461 if (mmc_get_env_addr(mmc, 0, &offset)) {
Simon Glass99778492017-08-03 12:22:17 -0600462 ret = -EIO;
Stephen Warren27ee0f32012-07-30 10:55:44 +0000463 goto fini;
464 }
Terry Lvb4eceac2010-05-17 10:57:01 +0800465
Tom Rinia840b8e2013-04-05 14:55:21 -0400466 if (read_env(mmc, CONFIG_ENV_SIZE, offset, buf)) {
Tim Harveyeda75c32015-05-08 14:52:09 -0700467 errmsg = "!read failed";
Simon Glass99778492017-08-03 12:22:17 -0600468 ret = -EIO;
Stephen Warren27ee0f32012-07-30 10:55:44 +0000469 goto fini;
470 }
Terry Lvb4eceac2010-05-17 10:57:01 +0800471
Marek Vasutdfe4b7e2020-07-07 20:51:35 +0200472 ret = env_import(buf, 1, H_EXTERNAL);
Pankit Gargc2342f62019-11-19 09:49:31 +0000473 if (!ret) {
474 ep = (env_t *)buf;
475 gd->env_addr = (ulong)&ep->data;
476 }
Stephen Warren27ee0f32012-07-30 10:55:44 +0000477
478fini:
479 fini_mmc_for_env(mmc);
480err:
481 if (ret)
Simon Glass97385862019-08-01 09:47:00 -0600482 env_set_default(errmsg, 0);
Patrick Delaunayd948e712022-11-10 11:49:00 +0100483
Simon Glass99778492017-08-03 12:22:17 -0600484 return ret;
Terry Lvb4eceac2010-05-17 10:57:01 +0800485}
Patrick Delaunay036a3582022-11-10 11:48:59 +0100486#endif /* CONFIG_SYS_REDUNDAND_ENVIRONMENT */
Simon Glassc10a88e2017-08-03 12:21:58 -0600487
488U_BOOT_ENV_LOCATION(mmc) = {
489 .location = ENVL_MMC,
Simon Glassd8273ed2017-08-03 12:22:03 -0600490 ENV_NAME("MMC")
Simon Glass082af922017-08-03 12:22:01 -0600491 .load = env_mmc_load,
Simon Glassc10a88e2017-08-03 12:21:58 -0600492#ifndef CONFIG_SPL_BUILD
Simon Glass082af922017-08-03 12:22:01 -0600493 .save = env_save_ptr(env_mmc_save),
Patrick Delaunay50f6f112021-02-09 11:48:50 +0100494 .erase = ENV_ERASE_PTR(env_mmc_erase)
Simon Glassc10a88e2017-08-03 12:21:58 -0600495#endif
Simon Glassc10a88e2017-08-03 12:21:58 -0600496};