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