]> git.ipfire.org Git - thirdparty/u-boot.git/blame - common/env_mmc.c
Coding Style cleanup: remove trailing white space
[thirdparty/u-boot.git] / common / env_mmc.c
CommitLineData
a8060359 1/*
97039ab9 2 * (C) Copyright 2008-2011 Freescale Semiconductor, Inc.
a8060359 3 *
3765b3e7 4 * SPDX-License-Identifier: GPL-2.0+
a8060359
TL
5 */
6
7/* #define DEBUG */
8
9#include <common.h>
10
11#include <command.h>
12#include <environment.h>
13#include <linux/stddef.h>
14#include <malloc.h>
15#include <mmc.h>
6d1d51b3 16#include <search.h>
e79f4839 17#include <errno.h>
a8060359 18
d196bd88
MH
19#if defined(CONFIG_ENV_SIZE_REDUND) && \
20 (CONFIG_ENV_SIZE_REDUND != CONFIG_ENV_SIZE)
21#error CONFIG_ENV_SIZE_REDUND should be the same as CONFIG_ENV_SIZE
22#endif
23
a8060359
TL
24char *env_name_spec = "MMC";
25
26#ifdef ENV_IS_EMBEDDED
994bc671 27env_t *env_ptr = &environment;
a8060359 28#else /* ! ENV_IS_EMBEDDED */
e8db8f71 29env_t *env_ptr;
a8060359
TL
30#endif /* ENV_IS_EMBEDDED */
31
a8060359
TL
32DECLARE_GLOBAL_DATA_PTR;
33
97039ab9
MH
34#if !defined(CONFIG_ENV_OFFSET)
35#define CONFIG_ENV_OFFSET 0
36#endif
37
d196bd88 38__weak int mmc_get_env_addr(struct mmc *mmc, int copy, u32 *env_addr)
97039ab9 39{
5c088ee8
SW
40 s64 offset;
41
42 offset = CONFIG_ENV_OFFSET;
d196bd88
MH
43#ifdef CONFIG_ENV_OFFSET_REDUND
44 if (copy)
5c088ee8 45 offset = CONFIG_ENV_OFFSET_REDUND;
d196bd88 46#endif
5c088ee8
SW
47
48 if (offset < 0)
49 offset += mmc->capacity;
50
51 *env_addr = offset;
52
97039ab9
MH
53 return 0;
54}
97039ab9 55
a8060359
TL
56int env_init(void)
57{
58 /* use default */
e8db8f71
IG
59 gd->env_addr = (ulong)&default_environment[0];
60 gd->env_valid = 1;
a8060359
TL
61
62 return 0;
63}
64
e8db8f71 65static int init_mmc_for_env(struct mmc *mmc)
a8060359
TL
66{
67 if (!mmc) {
68 puts("No MMC card found\n");
69 return -1;
70 }
71
72 if (mmc_init(mmc)) {
73 puts("MMC init failed\n");
e8db8f71 74 return -1;
a8060359
TL
75 }
76
9404a5fc
SW
77#ifdef CONFIG_SYS_MMC_ENV_PART
78 if (CONFIG_SYS_MMC_ENV_PART != mmc->part_num) {
79 if (mmc_switch_part(CONFIG_SYS_MMC_ENV_DEV,
80 CONFIG_SYS_MMC_ENV_PART)) {
81 puts("MMC partition switch failed\n");
82 return -1;
83 }
84 }
85#endif
86
a8060359
TL
87 return 0;
88}
89
9404a5fc
SW
90static void fini_mmc_for_env(struct mmc *mmc)
91{
92#ifdef CONFIG_SYS_MMC_ENV_PART
93 if (CONFIG_SYS_MMC_ENV_PART != mmc->part_num)
94 mmc_switch_part(CONFIG_SYS_MMC_ENV_DEV,
95 mmc->part_num);
96#endif
97}
98
a8060359 99#ifdef CONFIG_CMD_SAVEENV
e8db8f71
IG
100static inline int write_env(struct mmc *mmc, unsigned long size,
101 unsigned long offset, const void *buffer)
a8060359
TL
102{
103 uint blk_start, blk_cnt, n;
104
e8db8f71
IG
105 blk_start = ALIGN(offset, mmc->write_bl_len) / mmc->write_bl_len;
106 blk_cnt = ALIGN(size, mmc->write_bl_len) / mmc->write_bl_len;
a8060359
TL
107
108 n = mmc->block_dev.block_write(CONFIG_SYS_MMC_ENV_DEV, blk_start,
109 blk_cnt, (u_char *)buffer);
110
111 return (n == blk_cnt) ? 0 : -1;
112}
113
d196bd88
MH
114#ifdef CONFIG_ENV_OFFSET_REDUND
115static unsigned char env_flags;
116#endif
117
a8060359
TL
118int saveenv(void)
119{
cd0f4fa1 120 ALLOC_CACHE_ALIGN_BUFFER(env_t, env_new, 1);
e79f4839
LW
121 ssize_t len;
122 char *res;
a8060359 123 struct mmc *mmc = find_mmc_device(CONFIG_SYS_MMC_ENV_DEV);
e8db8f71 124 u32 offset;
d196bd88 125 int ret, copy = 0;
a8060359 126
9404a5fc 127 if (init_mmc_for_env(mmc))
97039ab9
MH
128 return 1;
129
cd0f4fa1 130 res = (char *)&env_new->data;
be11235a 131 len = hexport_r(&env_htab, '\0', 0, &res, ENV_SIZE, 0, NULL);
e79f4839
LW
132 if (len < 0) {
133 error("Cannot export environment: errno = %d\n", errno);
9404a5fc
SW
134 ret = 1;
135 goto fini;
e79f4839 136 }
e8db8f71 137
cd0f4fa1 138 env_new->crc = crc32(0, &env_new->data[0], ENV_SIZE);
d196bd88
MH
139
140#ifdef CONFIG_ENV_OFFSET_REDUND
141 env_new->flags = ++env_flags; /* increase the serial */
142
143 if (gd->env_valid == 1)
144 copy = 1;
145#endif
146
147 if (mmc_get_env_addr(mmc, copy, &offset)) {
148 ret = 1;
149 goto fini;
150 }
151
152 printf("Writing to %sMMC(%d)... ", copy ? "redundant " : "",
153 CONFIG_SYS_MMC_ENV_DEV);
4036b630 154 if (write_env(mmc, CONFIG_ENV_SIZE, offset, (u_char *)env_new)) {
a8060359 155 puts("failed\n");
9404a5fc
SW
156 ret = 1;
157 goto fini;
a8060359
TL
158 }
159
160 puts("done\n");
9404a5fc
SW
161 ret = 0;
162
d196bd88
MH
163#ifdef CONFIG_ENV_OFFSET_REDUND
164 gd->env_valid = gd->env_valid == 2 ? 1 : 2;
165#endif
166
9404a5fc
SW
167fini:
168 fini_mmc_for_env(mmc);
169 return ret;
a8060359
TL
170}
171#endif /* CONFIG_CMD_SAVEENV */
172
e8db8f71
IG
173static inline int read_env(struct mmc *mmc, unsigned long size,
174 unsigned long offset, const void *buffer)
a8060359
TL
175{
176 uint blk_start, blk_cnt, n;
177
e8db8f71
IG
178 blk_start = ALIGN(offset, mmc->read_bl_len) / mmc->read_bl_len;
179 blk_cnt = ALIGN(size, mmc->read_bl_len) / mmc->read_bl_len;
a8060359
TL
180
181 n = mmc->block_dev.block_read(CONFIG_SYS_MMC_ENV_DEV, blk_start,
182 blk_cnt, (uchar *)buffer);
183
184 return (n == blk_cnt) ? 0 : -1;
185}
186
d196bd88
MH
187#ifdef CONFIG_ENV_OFFSET_REDUND
188void env_relocate_spec(void)
189{
190#if !defined(ENV_IS_EMBEDDED)
191 struct mmc *mmc = find_mmc_device(CONFIG_SYS_MMC_ENV_DEV);
192 u32 offset1, offset2;
193 int read1_fail = 0, read2_fail = 0;
194 int crc1_ok = 0, crc2_ok = 0;
452a2722 195 env_t *ep;
d196bd88
MH
196 int ret;
197
452a2722
MN
198 ALLOC_CACHE_ALIGN_BUFFER(env_t, tmp_env1, 1);
199 ALLOC_CACHE_ALIGN_BUFFER(env_t, tmp_env2, 1);
200
d196bd88
MH
201 if (tmp_env1 == NULL || tmp_env2 == NULL) {
202 puts("Can't allocate buffers for environment\n");
203 ret = 1;
204 goto err;
205 }
206
207 if (init_mmc_for_env(mmc)) {
208 ret = 1;
209 goto err;
210 }
211
212 if (mmc_get_env_addr(mmc, 0, &offset1) ||
213 mmc_get_env_addr(mmc, 1, &offset2)) {
214 ret = 1;
215 goto fini;
216 }
217
218 read1_fail = read_env(mmc, CONFIG_ENV_SIZE, offset1, tmp_env1);
219 read2_fail = read_env(mmc, CONFIG_ENV_SIZE, offset2, tmp_env2);
220
221 if (read1_fail && read2_fail)
222 puts("*** Error - No Valid Environment Area found\n");
223 else if (read1_fail || read2_fail)
224 puts("*** Warning - some problems detected "
225 "reading environment; recovered successfully\n");
226
227 crc1_ok = !read1_fail &&
228 (crc32(0, tmp_env1->data, ENV_SIZE) == tmp_env1->crc);
229 crc2_ok = !read2_fail &&
230 (crc32(0, tmp_env2->data, ENV_SIZE) == tmp_env2->crc);
231
232 if (!crc1_ok && !crc2_ok) {
233 ret = 1;
234 goto fini;
235 } else if (crc1_ok && !crc2_ok) {
236 gd->env_valid = 1;
237 } else if (!crc1_ok && crc2_ok) {
238 gd->env_valid = 2;
239 } else {
240 /* both ok - check serial */
241 if (tmp_env1->flags == 255 && tmp_env2->flags == 0)
242 gd->env_valid = 2;
243 else if (tmp_env2->flags == 255 && tmp_env1->flags == 0)
244 gd->env_valid = 1;
245 else if (tmp_env1->flags > tmp_env2->flags)
246 gd->env_valid = 1;
247 else if (tmp_env2->flags > tmp_env1->flags)
248 gd->env_valid = 2;
249 else /* flags are equal - almost impossible */
250 gd->env_valid = 1;
251 }
252
253 free(env_ptr);
254
255 if (gd->env_valid == 1)
256 ep = tmp_env1;
257 else
258 ep = tmp_env2;
259
260 env_flags = ep->flags;
261 env_import((char *)ep, 0);
262 ret = 0;
263
264fini:
265 fini_mmc_for_env(mmc);
266err:
267 if (ret)
268 set_default_env(NULL);
269
d196bd88
MH
270#endif
271}
272#else /* ! CONFIG_ENV_OFFSET_REDUND */
a8060359
TL
273void env_relocate_spec(void)
274{
275#if !defined(ENV_IS_EMBEDDED)
cd0f4fa1 276 ALLOC_CACHE_ALIGN_BUFFER(char, buf, CONFIG_ENV_SIZE);
a8060359 277 struct mmc *mmc = find_mmc_device(CONFIG_SYS_MMC_ENV_DEV);
97039ab9 278 u32 offset;
9404a5fc 279 int ret;
a8060359 280
9404a5fc
SW
281 if (init_mmc_for_env(mmc)) {
282 ret = 1;
283 goto err;
284 }
a8060359 285
d196bd88 286 if (mmc_get_env_addr(mmc, 0, &offset)) {
9404a5fc
SW
287 ret = 1;
288 goto fini;
289 }
290
cd0f4fa1 291 if (read_env(mmc, CONFIG_ENV_SIZE, offset, buf)) {
9404a5fc
SW
292 ret = 1;
293 goto fini;
294 }
a8060359 295
cd0f4fa1 296 env_import(buf, 1);
9404a5fc
SW
297 ret = 0;
298
299fini:
300 fini_mmc_for_env(mmc);
301err:
302 if (ret)
303 set_default_env(NULL);
a8060359
TL
304#endif
305}
d196bd88 306#endif /* CONFIG_ENV_OFFSET_REDUND */