]> git.ipfire.org Git - thirdparty/u-boot.git/blame - env/mmc.c
env: Remove <common.h> and add needed includes
[thirdparty/u-boot.git] / env / mmc.c
CommitLineData
83d290c5 1// SPDX-License-Identifier: GPL-2.0+
a8060359 2/*
97039ab9 3 * (C) Copyright 2008-2011 Freescale Semiconductor, Inc.
a8060359
TL
4 */
5
6/* #define DEBUG */
7
401d1c4f 8#include <asm/global_data.h>
a8060359
TL
9
10#include <command.h>
0ac7d722 11#include <env.h>
f3998fdc 12#include <env_internal.h>
f8b8a554 13#include <fdtdec.h>
a8060359
TL
14#include <linux/stddef.h>
15#include <malloc.h>
cf92e05c 16#include <memalign.h>
a8060359 17#include <mmc.h>
c9e87ba6 18#include <part.h>
6d1d51b3 19#include <search.h>
e79f4839 20#include <errno.h>
7de8bd03 21#include <dm/ofnode.h>
a8060359 22
f7e07a7e
PD
23#define ENV_MMC_INVALID_OFFSET ((s64)-1)
24
d2103e20
PD
25#if defined(CONFIG_ENV_MMC_USE_DT)
26/* ENV offset is invalid when not defined in Device Tree */
27#define ENV_MMC_OFFSET ENV_MMC_INVALID_OFFSET
28#define ENV_MMC_OFFSET_REDUND ENV_MMC_INVALID_OFFSET
29
30#else
f7e07a7e
PD
31/* Default ENV offset when not defined in Device Tree */
32#define ENV_MMC_OFFSET CONFIG_ENV_OFFSET
33
34#if defined(CONFIG_ENV_OFFSET_REDUND)
35#define ENV_MMC_OFFSET_REDUND CONFIG_ENV_OFFSET_REDUND
36#else
37#define ENV_MMC_OFFSET_REDUND ENV_MMC_INVALID_OFFSET
38#endif
d2103e20 39#endif
f7e07a7e 40
a8060359
TL
41DECLARE_GLOBAL_DATA_PTR;
42
d11d1bec
MV
43/*
44 * In case the environment is redundant, stored in eMMC hardware boot
45 * partition and the environment and redundant environment offsets are
46 * identical, store the environment and redundant environment in both
47 * eMMC boot partitions, one copy in each.
48 * */
49#if (defined(CONFIG_SYS_REDUNDAND_ENVIRONMENT) && \
50 (CONFIG_SYS_MMC_ENV_PART == 1) && \
51 (CONFIG_ENV_OFFSET == CONFIG_ENV_OFFSET_REDUND))
46c9016b 52#define ENV_MMC_HWPART_REDUND 1
d11d1bec
MV
53#endif
54
f8b8a554 55#if CONFIG_IS_ENABLED(OF_CONTROL)
5d4f7b4e 56static inline int mmc_offset_try_partition(const char *str, int copy, s64 *val)
c9e87ba6 57{
0528979f 58 struct disk_partition info;
c9e87ba6
JRO
59 struct blk_desc *desc;
60 int len, i, ret;
2b2f7275 61 char dev_str[4];
c9e87ba6 62
2b2f7275
PD
63 snprintf(dev_str, sizeof(dev_str), "%d", mmc_get_env_dev());
64 ret = blk_get_device_by_str("mmc", dev_str, &desc);
c9e87ba6
JRO
65 if (ret < 0)
66 return (ret);
67
68 for (i = 1;;i++) {
69 ret = part_get_info(desc, i, &info);
70 if (ret < 0)
71 return ret;
72
80105d8f 73 if (str && !strncmp((const char *)info.name, str, sizeof(info.name)))
c9e87ba6 74 break;
80105d8f
PD
75#ifdef CONFIG_PARTITION_TYPE_GUID
76 if (!str) {
77 const efi_guid_t env_guid = PARTITION_U_BOOT_ENVIRONMENT;
78 efi_guid_t type_guid;
79
80 uuid_str_to_bin(info.type_guid, type_guid.b, UUID_STR_FORMAT_GUID);
81 if (!memcmp(&env_guid, &type_guid, sizeof(efi_guid_t)))
82 break;
83 }
84#endif
c9e87ba6
JRO
85 }
86
87 /* round up to info.blksz */
76b640c3 88 len = DIV_ROUND_UP(CONFIG_ENV_SIZE, info.blksz);
c9e87ba6
JRO
89
90 /* use the top of the partion for the environment */
5d4f7b4e 91 *val = (info.start + info.size - (1 + copy) * len) * info.blksz;
c9e87ba6
JRO
92
93 return 0;
94}
95
5b4acb0f 96static inline s64 mmc_offset(struct mmc *mmc, int copy)
f8b8a554 97{
c9e87ba6
JRO
98 const struct {
99 const char *offset_redund;
100 const char *partition;
101 const char *offset;
102 } dt_prop = {
103 .offset_redund = "u-boot,mmc-env-offset-redundant",
104 .partition = "u-boot,mmc-env-partition",
105 .offset = "u-boot,mmc-env-offset",
106 };
fd374665 107 s64 val = 0, defvalue;
c9e87ba6
JRO
108 const char *propname;
109 const char *str;
5b4acb0f 110 int hwpart = 0;
c9e87ba6
JRO
111 int err;
112
5b4acb0f
MV
113 if (IS_ENABLED(CONFIG_SYS_MMC_ENV_PART))
114 hwpart = mmc_get_env_part(mmc);
115
9e70676c
EDF
116#if defined(CONFIG_ENV_MMC_PARTITION)
117 str = CONFIG_ENV_MMC_PARTITION;
118#else
c9e87ba6 119 /* look for the partition in mmc CONFIG_SYS_MMC_ENV_DEV */
7de8bd03 120 str = ofnode_conf_read_str(dt_prop.partition);
9e70676c
EDF
121#endif
122
c9e87ba6
JRO
123 if (str) {
124 /* try to place the environment at end of the partition */
5d4f7b4e 125 err = mmc_offset_try_partition(str, copy, &val);
c9e87ba6
JRO
126 if (!err)
127 return val;
52e9aa3c 128 debug("env partition '%s' not found (%d)", str, err);
c9e87ba6
JRO
129 }
130
80105d8f 131 /* try the GPT partition with "U-Boot ENV" TYPE GUID */
5b4acb0f 132 if (IS_ENABLED(CONFIG_PARTITION_TYPE_GUID) && hwpart == 0) {
80105d8f
PD
133 err = mmc_offset_try_partition(NULL, copy, &val);
134 if (!err)
135 return val;
136 }
137
f7e07a7e 138 defvalue = ENV_MMC_OFFSET;
c9e87ba6 139 propname = dt_prop.offset;
f8b8a554 140
46c9016b 141 if (IS_ENABLED(CONFIG_SYS_REDUNDAND_ENVIRONMENT) && copy) {
f7e07a7e 142 defvalue = ENV_MMC_OFFSET_REDUND;
c9e87ba6 143 propname = dt_prop.offset_redund;
f8b8a554 144 }
46c9016b 145
7de8bd03 146 return ofnode_conf_read_int(propname, defvalue);
f8b8a554
PT
147}
148#else
5b4acb0f 149static inline s64 mmc_offset(struct mmc *mmc, int copy)
97039ab9 150{
f7e07a7e 151 s64 offset = ENV_MMC_OFFSET;
5c088ee8 152
46c9016b 153 if (IS_ENABLED(CONFIG_SYS_REDUNDAND_ENVIRONMENT) && copy)
f7e07a7e 154 offset = ENV_MMC_OFFSET_REDUND;
46c9016b 155
f8b8a554
PT
156 return offset;
157}
158#endif
159
160__weak int mmc_get_env_addr(struct mmc *mmc, int copy, u32 *env_addr)
161{
5b4acb0f 162 s64 offset = mmc_offset(mmc, copy);
5c088ee8 163
f7e07a7e
PD
164 if (offset == ENV_MMC_INVALID_OFFSET) {
165 printf("Invalid ENV offset in MMC, copy=%d\n", copy);
166 return -ENOENT;
167 }
168
5c088ee8
SW
169 if (offset < 0)
170 offset += mmc->capacity;
171
172 *env_addr = offset;
173
97039ab9
MH
174 return 0;
175}
97039ab9 176
b9c8ccab 177#ifdef CONFIG_SYS_MMC_ENV_PART
6e7b7df4
DL
178__weak uint mmc_get_env_part(struct mmc *mmc)
179{
180 return CONFIG_SYS_MMC_ENV_PART;
181}
182
873cc1d7
SW
183static unsigned char env_mmc_orig_hwpart;
184
d11d1bec 185static int mmc_set_env_part(struct mmc *mmc, uint part)
6e7b7df4 186{
e92029c0 187 int dev = mmc_get_env_dev();
6e7b7df4 188 int ret = 0;
b9c8ccab 189
e33a5c6b 190 ret = blk_select_hwpart_devnum(UCLASS_MMC, dev, part);
873cc1d7
SW
191 if (ret)
192 puts("MMC partition switch failed\n");
6e7b7df4
DL
193
194 return ret;
195}
46c9016b
PD
196
197static bool mmc_set_env_part_init(struct mmc *mmc)
198{
199 env_mmc_orig_hwpart = mmc_get_blk_desc(mmc)->hwpart;
200 if (mmc_set_env_part(mmc, mmc_get_env_part(mmc)))
201 return false;
202
203 return true;
204}
205
206static int mmc_set_env_part_restore(struct mmc *mmc)
207{
208 return mmc_set_env_part(mmc, env_mmc_orig_hwpart);
209}
6e7b7df4 210#else
d11d1bec 211static inline int mmc_set_env_part(struct mmc *mmc, uint part) {return 0; };
46c9016b
PD
212static bool mmc_set_env_part_init(struct mmc *mmc) {return true; }
213static inline int mmc_set_env_part_restore(struct mmc *mmc) {return 0; };
b9c8ccab
TR
214#endif
215
c75648d7 216static const char *init_mmc_for_env(struct mmc *mmc)
6e7b7df4 217{
c75648d7 218 if (!mmc)
c5d548a9 219 return "No MMC card found";
a8060359 220
d48b8d11 221#if CONFIG_IS_ENABLED(BLK)
01b73fe6
SG
222 struct udevice *dev;
223
224 if (blk_get_from_parent(mmc->dev, &dev))
c5d548a9 225 return "No block device";
01b73fe6 226#else
c75648d7 227 if (mmc_init(mmc))
c5d548a9 228 return "MMC init failed";
e7017a3c 229#endif
46c9016b 230 if (!mmc_set_env_part_init(mmc))
c5d548a9 231 return "MMC partition switch failed";
a8060359 232
c75648d7 233 return NULL;
a8060359
TL
234}
235
9404a5fc
SW
236static void fini_mmc_for_env(struct mmc *mmc)
237{
46c9016b 238 mmc_set_env_part_restore(mmc);
9404a5fc
SW
239}
240
e5bce247 241#if defined(CONFIG_CMD_SAVEENV) && !defined(CONFIG_SPL_BUILD)
e8db8f71
IG
242static inline int write_env(struct mmc *mmc, unsigned long size,
243 unsigned long offset, const void *buffer)
a8060359
TL
244{
245 uint blk_start, blk_cnt, n;
5461acba 246 struct blk_desc *desc = mmc_get_blk_desc(mmc);
a8060359 247
e8db8f71
IG
248 blk_start = ALIGN(offset, mmc->write_bl_len) / mmc->write_bl_len;
249 blk_cnt = ALIGN(size, mmc->write_bl_len) / mmc->write_bl_len;
a8060359 250
5461acba 251 n = blk_dwrite(desc, blk_start, blk_cnt, (u_char *)buffer);
a8060359
TL
252
253 return (n == blk_cnt) ? 0 : -1;
254}
255
e5bce247 256static int env_mmc_save(void)
a8060359 257{
cd0f4fa1 258 ALLOC_CACHE_ALIGN_BUFFER(env_t, env_new, 1);
e92029c0
CG
259 int dev = mmc_get_env_dev();
260 struct mmc *mmc = find_mmc_device(dev);
e8db8f71 261 u32 offset;
d196bd88 262 int ret, copy = 0;
c75648d7 263 const char *errmsg;
a8060359 264
c75648d7
TH
265 errmsg = init_mmc_for_env(mmc);
266 if (errmsg) {
267 printf("%s\n", errmsg);
97039ab9 268 return 1;
c75648d7 269 }
97039ab9 270
7ce1526e
MV
271 ret = env_export(env_new);
272 if (ret)
9404a5fc 273 goto fini;
d196bd88 274
46c9016b
PD
275 if (IS_ENABLED(CONFIG_SYS_REDUNDAND_ENVIRONMENT)) {
276 if (gd->env_valid == ENV_VALID)
277 copy = 1;
d11d1bec 278
46c9016b
PD
279 if (IS_ENABLED(ENV_MMC_HWPART_REDUND)) {
280 ret = mmc_set_env_part(mmc, copy + 1);
281 if (ret)
282 goto fini;
283 }
ccd0542a 284 }
d196bd88 285
ccd0542a
YL
286 if (mmc_get_env_addr(mmc, copy, &offset)) {
287 ret = 1;
288 goto fini;
d196bd88
MH
289 }
290
e92029c0 291 printf("Writing to %sMMC(%d)... ", copy ? "redundant " : "", dev);
4036b630 292 if (write_env(mmc, CONFIG_ENV_SIZE, offset, (u_char *)env_new)) {
a8060359 293 puts("failed\n");
9404a5fc
SW
294 ret = 1;
295 goto fini;
a8060359
TL
296 }
297
9404a5fc
SW
298 ret = 0;
299
46c9016b
PD
300 if (IS_ENABLED(CONFIG_SYS_REDUNDAND_ENVIRONMENT))
301 gd->env_valid = gd->env_valid == ENV_REDUND ? ENV_VALID : ENV_REDUND;
d196bd88 302
9404a5fc
SW
303fini:
304 fini_mmc_for_env(mmc);
46c9016b 305
9404a5fc 306 return ret;
a8060359 307}
34853925 308
34853925
FW
309static inline int erase_env(struct mmc *mmc, unsigned long size,
310 unsigned long offset)
311{
312 uint blk_start, blk_cnt, n;
313 struct blk_desc *desc = mmc_get_blk_desc(mmc);
d7226704 314 u32 erase_size;
34853925 315
d7226704
PD
316 erase_size = mmc->erase_grp_size * desc->blksz;
317 blk_start = ALIGN_DOWN(offset, erase_size) / desc->blksz;
318 blk_cnt = ALIGN(size, erase_size) / desc->blksz;
34853925
FW
319
320 n = blk_derase(desc, blk_start, blk_cnt);
d7226704
PD
321 printf("%d blocks erased at 0x%x: %s\n", n, blk_start,
322 (n == blk_cnt) ? "OK" : "ERROR");
34853925
FW
323
324 return (n == blk_cnt) ? 0 : 1;
325}
326
327static int env_mmc_erase(void)
328{
329 int dev = mmc_get_env_dev();
330 struct mmc *mmc = find_mmc_device(dev);
331 int ret, copy = 0;
332 u32 offset;
333 const char *errmsg;
334
335 errmsg = init_mmc_for_env(mmc);
336 if (errmsg) {
337 printf("%s\n", errmsg);
338 return 1;
339 }
340
f47f87f2
MV
341 if (mmc_get_env_addr(mmc, copy, &offset)) {
342 ret = CMD_RET_FAILURE;
343 goto fini;
344 }
34853925 345
d7226704 346 printf("\n");
34853925
FW
347 ret = erase_env(mmc, CONFIG_ENV_SIZE, offset);
348
46c9016b
PD
349 if (IS_ENABLED(CONFIG_SYS_REDUNDAND_ENVIRONMENT)) {
350 copy = 1;
34853925 351
46c9016b
PD
352 if (IS_ENABLED(ENV_MMC_HWPART_REDUND)) {
353 ret = mmc_set_env_part(mmc, copy + 1);
354 if (ret)
355 goto fini;
356 }
d11d1bec 357
46c9016b
PD
358 if (mmc_get_env_addr(mmc, copy, &offset)) {
359 ret = CMD_RET_FAILURE;
360 goto fini;
361 }
34853925 362
46c9016b
PD
363 ret |= erase_env(mmc, CONFIG_ENV_SIZE, offset);
364 }
34853925 365
f47f87f2
MV
366fini:
367 fini_mmc_for_env(mmc);
34853925
FW
368 return ret;
369}
e5bce247 370#endif /* CONFIG_CMD_SAVEENV && !CONFIG_SPL_BUILD */
a8060359 371
e8db8f71
IG
372static inline int read_env(struct mmc *mmc, unsigned long size,
373 unsigned long offset, const void *buffer)
a8060359
TL
374{
375 uint blk_start, blk_cnt, n;
5461acba 376 struct blk_desc *desc = mmc_get_blk_desc(mmc);
a8060359 377
e8db8f71
IG
378 blk_start = ALIGN(offset, mmc->read_bl_len) / mmc->read_bl_len;
379 blk_cnt = ALIGN(size, mmc->read_bl_len) / mmc->read_bl_len;
a8060359 380
5461acba 381 n = blk_dread(desc, blk_start, blk_cnt, (uchar *)buffer);
a8060359
TL
382
383 return (n == blk_cnt) ? 0 : -1;
384}
385
8566050e
PD
386#if defined(ENV_IS_EMBEDDED)
387static int env_mmc_load(void)
388{
389 return 0;
390}
391#elif defined(CONFIG_SYS_REDUNDAND_ENVIRONMENT)
c5951991 392static int env_mmc_load(void)
d196bd88 393{
b9c8ccab 394 struct mmc *mmc;
d196bd88
MH
395 u32 offset1, offset2;
396 int read1_fail = 0, read2_fail = 0;
d196bd88 397 int ret;
e92029c0 398 int dev = mmc_get_env_dev();
c75648d7 399 const char *errmsg = NULL;
d196bd88 400
452a2722
MN
401 ALLOC_CACHE_ALIGN_BUFFER(env_t, tmp_env1, 1);
402 ALLOC_CACHE_ALIGN_BUFFER(env_t, tmp_env2, 1);
403
26862b4a
FA
404 mmc_initialize(NULL);
405
b9c8ccab
TR
406 mmc = find_mmc_device(dev);
407
c75648d7
TH
408 errmsg = init_mmc_for_env(mmc);
409 if (errmsg) {
c5951991 410 ret = -EIO;
d196bd88
MH
411 goto err;
412 }
413
414 if (mmc_get_env_addr(mmc, 0, &offset1) ||
415 mmc_get_env_addr(mmc, 1, &offset2)) {
c5951991 416 ret = -EIO;
d196bd88
MH
417 goto fini;
418 }
419
46c9016b
PD
420 if (IS_ENABLED(ENV_MMC_HWPART_REDUND)) {
421 ret = mmc_set_env_part(mmc, 1);
422 if (ret)
423 goto fini;
424 }
d11d1bec 425
d196bd88 426 read1_fail = read_env(mmc, CONFIG_ENV_SIZE, offset1, tmp_env1);
d11d1bec 427
46c9016b
PD
428 if (IS_ENABLED(ENV_MMC_HWPART_REDUND)) {
429 ret = mmc_set_env_part(mmc, 2);
430 if (ret)
431 goto fini;
432 }
d11d1bec 433
d196bd88
MH
434 read2_fail = read_env(mmc, CONFIG_ENV_SIZE, offset2, tmp_env2);
435
31f044bd 436 ret = env_import_redund((char *)tmp_env1, read1_fail, (char *)tmp_env2,
890feeca 437 read2_fail, H_EXTERNAL);
97b34f6a 438 printf("Reading from %sMMC(%d)... ", gd->env_valid == ENV_REDUND ? "redundant " : "", dev);
d196bd88
MH
439
440fini:
441 fini_mmc_for_env(mmc);
442err:
443 if (ret)
0ac7d722 444 env_set_default(errmsg, 0);
c5951991 445
c5951991 446 return ret;
d196bd88 447}
46c9016b 448#else /* ! CONFIG_SYS_REDUNDAND_ENVIRONMENT */
c5951991 449static int env_mmc_load(void)
a8060359 450{
cd0f4fa1 451 ALLOC_CACHE_ALIGN_BUFFER(char, buf, CONFIG_ENV_SIZE);
b9c8ccab 452 struct mmc *mmc;
97039ab9 453 u32 offset;
9404a5fc 454 int ret;
e92029c0 455 int dev = mmc_get_env_dev();
c75648d7 456 const char *errmsg;
0536b440 457 env_t *ep = NULL;
b9c8ccab 458
b9c8ccab 459 mmc = find_mmc_device(dev);
a8060359 460
c75648d7
TH
461 errmsg = init_mmc_for_env(mmc);
462 if (errmsg) {
c5951991 463 ret = -EIO;
9404a5fc
SW
464 goto err;
465 }
a8060359 466
d196bd88 467 if (mmc_get_env_addr(mmc, 0, &offset)) {
c5951991 468 ret = -EIO;
9404a5fc
SW
469 goto fini;
470 }
471
cd0f4fa1 472 if (read_env(mmc, CONFIG_ENV_SIZE, offset, buf)) {
c75648d7 473 errmsg = "!read failed";
c5951991 474 ret = -EIO;
9404a5fc
SW
475 goto fini;
476 }
a8060359 477
97b34f6a
QS
478 printf("Reading from MMC(%d)... ", dev);
479
890feeca 480 ret = env_import(buf, 1, H_EXTERNAL);
0536b440
PG
481 if (!ret) {
482 ep = (env_t *)buf;
483 gd->env_addr = (ulong)&ep->data;
484 }
9404a5fc
SW
485
486fini:
487 fini_mmc_for_env(mmc);
488err:
489 if (ret)
0ac7d722 490 env_set_default(errmsg, 0);
8566050e 491
c5951991 492 return ret;
a8060359 493}
46c9016b 494#endif /* CONFIG_SYS_REDUNDAND_ENVIRONMENT */
4415f1d1
SG
495
496U_BOOT_ENV_LOCATION(mmc) = {
497 .location = ENVL_MMC,
ac358beb 498 ENV_NAME("MMC")
e5bce247 499 .load = env_mmc_load,
f7fac5e7 500#if defined(CONFIG_CMD_SAVEENV) && !defined(CONFIG_SPL_BUILD)
e5bce247 501 .save = env_save_ptr(env_mmc_save),
1af031ac 502 .erase = ENV_ERASE_PTR(env_mmc_erase)
4415f1d1 503#endif
4415f1d1 504};