Blame view

env/mmc.c 7.17 KB
a80603598   Terry Lv   Save environment ...
1
  /*
97039ab98   Mingkai Hu   env_mmc: Allow bo...
2
   * (C) Copyright 2008-2011 Freescale Semiconductor, Inc.
a80603598   Terry Lv   Save environment ...
3
   *
3765b3e7b   Wolfgang Denk   Coding Style clea...
4
   * SPDX-License-Identifier:	GPL-2.0+
a80603598   Terry Lv   Save environment ...
5
6
7
8
9
10
11
12
   */
  
  /* #define DEBUG */
  
  #include <common.h>
  
  #include <command.h>
  #include <environment.h>
f8b8a5546   Philipp Tomsich   env_mmc: configur...
13
  #include <fdtdec.h>
a80603598   Terry Lv   Save environment ...
14
15
  #include <linux/stddef.h>
  #include <malloc.h>
cf92e05c0   Simon Glass   Move ALLOC_CACHE_...
16
  #include <memalign.h>
a80603598   Terry Lv   Save environment ...
17
  #include <mmc.h>
c9e87ba66   Jorge Ramirez-Ortiz   env: Save environ...
18
  #include <part.h>
6d1d51b32   Lei Wen   env_mmc: fix comp...
19
  #include <search.h>
e79f48393   Lei Wen   env_mmc: fix cann...
20
  #include <errno.h>
a80603598   Terry Lv   Save environment ...
21

c9e87ba66   Jorge Ramirez-Ortiz   env: Save environ...
22
23
  #define __STR(X) #X
  #define STR(X) __STR(X)
d196bd880   Michael Heimpold   env_mmc: add supp...
24
25
26
27
  #if defined(CONFIG_ENV_SIZE_REDUND) &&  \
  	(CONFIG_ENV_SIZE_REDUND != CONFIG_ENV_SIZE)
  #error CONFIG_ENV_SIZE_REDUND should be the same as CONFIG_ENV_SIZE
  #endif
a80603598   Terry Lv   Save environment ...
28
  DECLARE_GLOBAL_DATA_PTR;
97039ab98   Mingkai Hu   env_mmc: Allow bo...
29
30
31
  #if !defined(CONFIG_ENV_OFFSET)
  #define CONFIG_ENV_OFFSET 0
  #endif
f8b8a5546   Philipp Tomsich   env_mmc: configur...
32
  #if CONFIG_IS_ENABLED(OF_CONTROL)
c9e87ba66   Jorge Ramirez-Ortiz   env: Save environ...
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
  static inline int mmc_offset_try_partition(const char *str, s64 *val)
  {
  	disk_partition_t info;
  	struct blk_desc *desc;
  	int len, i, ret;
  
  	ret = blk_get_device_by_str("mmc", STR(CONFIG_SYS_MMC_ENV_DEV), &desc);
  	if (ret < 0)
  		return (ret);
  
  	for (i = 1;;i++) {
  		ret = part_get_info(desc, i, &info);
  		if (ret < 0)
  			return ret;
  
  		if (!strncmp((const char *)info.name, str, sizeof(str)))
  			break;
  	}
  
  	/* round up to info.blksz */
  	len = (CONFIG_ENV_SIZE + info.blksz - 1) & ~(info.blksz - 1);
  
  	/* use the top of the partion for the environment */
  	*val = (info.start + info.size - 1) - len / info.blksz;
  
  	return 0;
  }
f8b8a5546   Philipp Tomsich   env_mmc: configur...
60
61
  static inline s64 mmc_offset(int copy)
  {
c9e87ba66   Jorge Ramirez-Ortiz   env: Save environ...
62
63
64
65
66
67
68
69
70
  	const struct {
  		const char *offset_redund;
  		const char *partition;
  		const char *offset;
  	} dt_prop = {
  		.offset_redund = "u-boot,mmc-env-offset-redundant",
  		.partition = "u-boot,mmc-env-partition",
  		.offset = "u-boot,mmc-env-offset",
  	};
fd374665c   Philipp Tomsich   env: suppress a s...
71
  	s64 val = 0, defvalue;
c9e87ba66   Jorge Ramirez-Ortiz   env: Save environ...
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
  	const char *propname;
  	const char *str;
  	int err;
  
  	/* look for the partition in mmc CONFIG_SYS_MMC_ENV_DEV */
  	str = fdtdec_get_config_string(gd->fdt_blob, dt_prop.partition);
  	if (str) {
  		/* try to place the environment at end of the partition */
  		err = mmc_offset_try_partition(str, &val);
  		if (!err)
  			return val;
  	}
  
  	defvalue = CONFIG_ENV_OFFSET;
  	propname = dt_prop.offset;
f8b8a5546   Philipp Tomsich   env_mmc: configur...
87
88
89
  
  #if defined(CONFIG_ENV_OFFSET_REDUND)
  	if (copy) {
f8b8a5546   Philipp Tomsich   env_mmc: configur...
90
  		defvalue = CONFIG_ENV_OFFSET_REDUND;
c9e87ba66   Jorge Ramirez-Ortiz   env: Save environ...
91
  		propname = dt_prop.offset_redund;
f8b8a5546   Philipp Tomsich   env_mmc: configur...
92
93
  	}
  #endif
f8b8a5546   Philipp Tomsich   env_mmc: configur...
94
95
96
97
  	return fdtdec_get_config_int(gd->fdt_blob, propname, defvalue);
  }
  #else
  static inline s64 mmc_offset(int copy)
97039ab98   Mingkai Hu   env_mmc: Allow bo...
98
  {
f8b8a5546   Philipp Tomsich   env_mmc: configur...
99
  	s64 offset = CONFIG_ENV_OFFSET;
5c088ee84   Stephen Warren   env_mmc: allow ne...
100

f8b8a5546   Philipp Tomsich   env_mmc: configur...
101
  #if defined(CONFIG_ENV_OFFSET_REDUND)
d196bd880   Michael Heimpold   env_mmc: add supp...
102
  	if (copy)
5c088ee84   Stephen Warren   env_mmc: allow ne...
103
  		offset = CONFIG_ENV_OFFSET_REDUND;
d196bd880   Michael Heimpold   env_mmc: add supp...
104
  #endif
f8b8a5546   Philipp Tomsich   env_mmc: configur...
105
106
107
108
109
110
111
  	return offset;
  }
  #endif
  
  __weak int mmc_get_env_addr(struct mmc *mmc, int copy, u32 *env_addr)
  {
  	s64 offset = mmc_offset(copy);
5c088ee84   Stephen Warren   env_mmc: allow ne...
112
113
114
115
116
  
  	if (offset < 0)
  		offset += mmc->capacity;
  
  	*env_addr = offset;
97039ab98   Mingkai Hu   env_mmc: Allow bo...
117
118
  	return 0;
  }
97039ab98   Mingkai Hu   env_mmc: Allow bo...
119

e92029c0f   Clemens Gruber   env_mmc: support ...
120
121
122
123
  __weak int mmc_get_env_dev(void)
  {
  	return CONFIG_SYS_MMC_ENV_DEV;
  }
b9c8ccaba   Tom Rini   env_mmc.c: Allow ...
124
  #ifdef CONFIG_SYS_MMC_ENV_PART
6e7b7df4d   Dmitry Lifshitz   env_mmc: support ...
125
126
127
128
  __weak uint mmc_get_env_part(struct mmc *mmc)
  {
  	return CONFIG_SYS_MMC_ENV_PART;
  }
873cc1d77   Stephen Warren   mmc: store hwpart...
129
  static unsigned char env_mmc_orig_hwpart;
6e7b7df4d   Dmitry Lifshitz   env_mmc: support ...
130
131
132
  static int mmc_set_env_part(struct mmc *mmc)
  {
  	uint part = mmc_get_env_part(mmc);
e92029c0f   Clemens Gruber   env_mmc: support ...
133
  	int dev = mmc_get_env_dev();
6e7b7df4d   Dmitry Lifshitz   env_mmc: support ...
134
  	int ret = 0;
b9c8ccaba   Tom Rini   env_mmc.c: Allow ...
135

69f45cd53   Simon Glass   dm: mmc: Use the ...
136
137
  	env_mmc_orig_hwpart = mmc_get_blk_desc(mmc)->hwpart;
  	ret = blk_select_hwpart_devnum(IF_TYPE_MMC, dev, part);
873cc1d77   Stephen Warren   mmc: store hwpart...
138
139
140
  	if (ret)
  		puts("MMC partition switch failed
  ");
6e7b7df4d   Dmitry Lifshitz   env_mmc: support ...
141
142
143
144
145
  
  	return ret;
  }
  #else
  static inline int mmc_set_env_part(struct mmc *mmc) {return 0; };
b9c8ccaba   Tom Rini   env_mmc.c: Allow ...
146
  #endif
c75648d75   Tim Harvey   env_mmc: add erro...
147
  static const char *init_mmc_for_env(struct mmc *mmc)
6e7b7df4d   Dmitry Lifshitz   env_mmc: support ...
148
  {
c75648d75   Tim Harvey   env_mmc: add erro...
149
  	if (!mmc)
a85da21f7   Hans de Goede   env_mmc: Properly...
150
  		return "!No MMC card found";
a80603598   Terry Lv   Save environment ...
151

01b73fe63   Simon Glass   dm: mmc: Ensure t...
152
153
154
155
156
157
  #ifdef CONFIG_BLK
  	struct udevice *dev;
  
  	if (blk_get_from_parent(mmc->dev, &dev))
  		return "!No block device";
  #else
c75648d75   Tim Harvey   env_mmc: add erro...
158
  	if (mmc_init(mmc))
a85da21f7   Hans de Goede   env_mmc: Properly...
159
  		return "!MMC init failed";
e7017a3c7   Simon Glass   dm: mmc: Don't re...
160
  #endif
c75648d75   Tim Harvey   env_mmc: add erro...
161
  	if (mmc_set_env_part(mmc))
a85da21f7   Hans de Goede   env_mmc: Properly...
162
  		return "!MMC partition switch failed";
a80603598   Terry Lv   Save environment ...
163

c75648d75   Tim Harvey   env_mmc: add erro...
164
  	return NULL;
a80603598   Terry Lv   Save environment ...
165
  }
9404a5fc7   Stephen Warren   env_mmc: allow en...
166
167
168
  static void fini_mmc_for_env(struct mmc *mmc)
  {
  #ifdef CONFIG_SYS_MMC_ENV_PART
e92029c0f   Clemens Gruber   env_mmc: support ...
169
  	int dev = mmc_get_env_dev();
b9c8ccaba   Tom Rini   env_mmc.c: Allow ...
170

69f45cd53   Simon Glass   dm: mmc: Use the ...
171
  	blk_select_hwpart_devnum(IF_TYPE_MMC, dev, env_mmc_orig_hwpart);
9404a5fc7   Stephen Warren   env_mmc: allow en...
172
173
  #endif
  }
e5bce247b   Simon Glass   env: Switch over ...
174
  #if defined(CONFIG_CMD_SAVEENV) && !defined(CONFIG_SPL_BUILD)
e8db8f71c   Igor Grinberg   env: clean env_mm...
175
176
  static inline int write_env(struct mmc *mmc, unsigned long size,
  			    unsigned long offset, const void *buffer)
a80603598   Terry Lv   Save environment ...
177
178
  {
  	uint blk_start, blk_cnt, n;
5461acba4   Simon Glass   dm: env: mmc: Con...
179
  	struct blk_desc *desc = mmc_get_blk_desc(mmc);
a80603598   Terry Lv   Save environment ...
180

e8db8f71c   Igor Grinberg   env: clean env_mm...
181
182
  	blk_start	= ALIGN(offset, mmc->write_bl_len) / mmc->write_bl_len;
  	blk_cnt		= ALIGN(size, mmc->write_bl_len) / mmc->write_bl_len;
a80603598   Terry Lv   Save environment ...
183

5461acba4   Simon Glass   dm: env: mmc: Con...
184
  	n = blk_dwrite(desc, blk_start, blk_cnt, (u_char *)buffer);
a80603598   Terry Lv   Save environment ...
185
186
187
  
  	return (n == blk_cnt) ? 0 : -1;
  }
e5bce247b   Simon Glass   env: Switch over ...
188
  static int env_mmc_save(void)
a80603598   Terry Lv   Save environment ...
189
  {
cd0f4fa1c   Tom Rini   Revert "env: fix ...
190
  	ALLOC_CACHE_ALIGN_BUFFER(env_t, env_new, 1);
e92029c0f   Clemens Gruber   env_mmc: support ...
191
192
  	int dev = mmc_get_env_dev();
  	struct mmc *mmc = find_mmc_device(dev);
e8db8f71c   Igor Grinberg   env: clean env_mm...
193
  	u32	offset;
d196bd880   Michael Heimpold   env_mmc: add supp...
194
  	int	ret, copy = 0;
c75648d75   Tim Harvey   env_mmc: add erro...
195
  	const char *errmsg;
a80603598   Terry Lv   Save environment ...
196

c75648d75   Tim Harvey   env_mmc: add erro...
197
198
199
200
  	errmsg = init_mmc_for_env(mmc);
  	if (errmsg) {
  		printf("%s
  ", errmsg);
97039ab98   Mingkai Hu   env_mmc: Allow bo...
201
  		return 1;
c75648d75   Tim Harvey   env_mmc: add erro...
202
  	}
97039ab98   Mingkai Hu   env_mmc: Allow bo...
203

7ce1526ed   Marek Vasut   env: Add env_expo...
204
205
  	ret = env_export(env_new);
  	if (ret)
9404a5fc7   Stephen Warren   env_mmc: allow en...
206
  		goto fini;
d196bd880   Michael Heimpold   env_mmc: add supp...
207
208
  
  #ifdef CONFIG_ENV_OFFSET_REDUND
203e94f6c   Simon Glass   env: Add an enum ...
209
  	if (gd->env_valid == ENV_VALID)
d196bd880   Michael Heimpold   env_mmc: add supp...
210
211
212
213
214
215
216
  		copy = 1;
  #endif
  
  	if (mmc_get_env_addr(mmc, copy, &offset)) {
  		ret = 1;
  		goto fini;
  	}
e92029c0f   Clemens Gruber   env_mmc: support ...
217
  	printf("Writing to %sMMC(%d)... ", copy ? "redundant " : "", dev);
4036b6301   Stephen Warren   env_mmc: align bu...
218
  	if (write_env(mmc, CONFIG_ENV_SIZE, offset, (u_char *)env_new)) {
a80603598   Terry Lv   Save environment ...
219
220
  		puts("failed
  ");
9404a5fc7   Stephen Warren   env_mmc: allow en...
221
222
  		ret = 1;
  		goto fini;
a80603598   Terry Lv   Save environment ...
223
  	}
9404a5fc7   Stephen Warren   env_mmc: allow en...
224
  	ret = 0;
d196bd880   Michael Heimpold   env_mmc: add supp...
225
  #ifdef CONFIG_ENV_OFFSET_REDUND
203e94f6c   Simon Glass   env: Add an enum ...
226
  	gd->env_valid = gd->env_valid == ENV_REDUND ? ENV_VALID : ENV_REDUND;
d196bd880   Michael Heimpold   env_mmc: add supp...
227
  #endif
9404a5fc7   Stephen Warren   env_mmc: allow en...
228
229
230
  fini:
  	fini_mmc_for_env(mmc);
  	return ret;
a80603598   Terry Lv   Save environment ...
231
  }
e5bce247b   Simon Glass   env: Switch over ...
232
  #endif /* CONFIG_CMD_SAVEENV && !CONFIG_SPL_BUILD */
a80603598   Terry Lv   Save environment ...
233

e8db8f71c   Igor Grinberg   env: clean env_mm...
234
235
  static inline int read_env(struct mmc *mmc, unsigned long size,
  			   unsigned long offset, const void *buffer)
a80603598   Terry Lv   Save environment ...
236
237
  {
  	uint blk_start, blk_cnt, n;
5461acba4   Simon Glass   dm: env: mmc: Con...
238
  	struct blk_desc *desc = mmc_get_blk_desc(mmc);
a80603598   Terry Lv   Save environment ...
239

e8db8f71c   Igor Grinberg   env: clean env_mm...
240
241
  	blk_start	= ALIGN(offset, mmc->read_bl_len) / mmc->read_bl_len;
  	blk_cnt		= ALIGN(size, mmc->read_bl_len) / mmc->read_bl_len;
a80603598   Terry Lv   Save environment ...
242

5461acba4   Simon Glass   dm: env: mmc: Con...
243
  	n = blk_dread(desc, blk_start, blk_cnt, (uchar *)buffer);
a80603598   Terry Lv   Save environment ...
244
245
246
  
  	return (n == blk_cnt) ? 0 : -1;
  }
d196bd880   Michael Heimpold   env_mmc: add supp...
247
  #ifdef CONFIG_ENV_OFFSET_REDUND
c59519919   Simon Glass   env: Adjust the l...
248
  static int env_mmc_load(void)
d196bd880   Michael Heimpold   env_mmc: add supp...
249
250
  {
  #if !defined(ENV_IS_EMBEDDED)
b9c8ccaba   Tom Rini   env_mmc.c: Allow ...
251
  	struct mmc *mmc;
d196bd880   Michael Heimpold   env_mmc: add supp...
252
253
  	u32 offset1, offset2;
  	int read1_fail = 0, read2_fail = 0;
d196bd880   Michael Heimpold   env_mmc: add supp...
254
  	int ret;
e92029c0f   Clemens Gruber   env_mmc: support ...
255
  	int dev = mmc_get_env_dev();
c75648d75   Tim Harvey   env_mmc: add erro...
256
  	const char *errmsg = NULL;
d196bd880   Michael Heimpold   env_mmc: add supp...
257

452a2722e   Markus Niebel   env_mmc: fix buff...
258
259
  	ALLOC_CACHE_ALIGN_BUFFER(env_t, tmp_env1, 1);
  	ALLOC_CACHE_ALIGN_BUFFER(env_t, tmp_env2, 1);
26862b4a4   Faiz Abbas   env: mmc/fat/ext4...
260
  	mmc_initialize(NULL);
b9c8ccaba   Tom Rini   env_mmc.c: Allow ...
261
  	mmc = find_mmc_device(dev);
c75648d75   Tim Harvey   env_mmc: add erro...
262
263
  	errmsg = init_mmc_for_env(mmc);
  	if (errmsg) {
c59519919   Simon Glass   env: Adjust the l...
264
  		ret = -EIO;
d196bd880   Michael Heimpold   env_mmc: add supp...
265
266
267
268
269
  		goto err;
  	}
  
  	if (mmc_get_env_addr(mmc, 0, &offset1) ||
  	    mmc_get_env_addr(mmc, 1, &offset2)) {
c59519919   Simon Glass   env: Adjust the l...
270
  		ret = -EIO;
d196bd880   Michael Heimpold   env_mmc: add supp...
271
272
273
274
275
  		goto fini;
  	}
  
  	read1_fail = read_env(mmc, CONFIG_ENV_SIZE, offset1, tmp_env1);
  	read2_fail = read_env(mmc, CONFIG_ENV_SIZE, offset2, tmp_env2);
31f044bd9   Simon Goldschmidt   env: move more co...
276
277
  	ret = env_import_redund((char *)tmp_env1, read1_fail, (char *)tmp_env2,
  				read2_fail);
d196bd880   Michael Heimpold   env_mmc: add supp...
278
279
280
281
282
  
  fini:
  	fini_mmc_for_env(mmc);
  err:
  	if (ret)
c75648d75   Tim Harvey   env_mmc: add erro...
283
  		set_default_env(errmsg);
c59519919   Simon Glass   env: Adjust the l...
284

d196bd880   Michael Heimpold   env_mmc: add supp...
285
  #endif
c59519919   Simon Glass   env: Adjust the l...
286
  	return ret;
d196bd880   Michael Heimpold   env_mmc: add supp...
287
288
  }
  #else /* ! CONFIG_ENV_OFFSET_REDUND */
c59519919   Simon Glass   env: Adjust the l...
289
  static int env_mmc_load(void)
a80603598   Terry Lv   Save environment ...
290
291
  {
  #if !defined(ENV_IS_EMBEDDED)
cd0f4fa1c   Tom Rini   Revert "env: fix ...
292
  	ALLOC_CACHE_ALIGN_BUFFER(char, buf, CONFIG_ENV_SIZE);
b9c8ccaba   Tom Rini   env_mmc.c: Allow ...
293
  	struct mmc *mmc;
97039ab98   Mingkai Hu   env_mmc: Allow bo...
294
  	u32 offset;
9404a5fc7   Stephen Warren   env_mmc: allow en...
295
  	int ret;
e92029c0f   Clemens Gruber   env_mmc: support ...
296
  	int dev = mmc_get_env_dev();
c75648d75   Tim Harvey   env_mmc: add erro...
297
  	const char *errmsg;
b9c8ccaba   Tom Rini   env_mmc.c: Allow ...
298

b9c8ccaba   Tom Rini   env_mmc.c: Allow ...
299
  	mmc = find_mmc_device(dev);
a80603598   Terry Lv   Save environment ...
300

c75648d75   Tim Harvey   env_mmc: add erro...
301
302
  	errmsg = init_mmc_for_env(mmc);
  	if (errmsg) {
c59519919   Simon Glass   env: Adjust the l...
303
  		ret = -EIO;
9404a5fc7   Stephen Warren   env_mmc: allow en...
304
305
  		goto err;
  	}
a80603598   Terry Lv   Save environment ...
306

d196bd880   Michael Heimpold   env_mmc: add supp...
307
  	if (mmc_get_env_addr(mmc, 0, &offset)) {
c59519919   Simon Glass   env: Adjust the l...
308
  		ret = -EIO;
9404a5fc7   Stephen Warren   env_mmc: allow en...
309
310
  		goto fini;
  	}
cd0f4fa1c   Tom Rini   Revert "env: fix ...
311
  	if (read_env(mmc, CONFIG_ENV_SIZE, offset, buf)) {
c75648d75   Tim Harvey   env_mmc: add erro...
312
  		errmsg = "!read failed";
c59519919   Simon Glass   env: Adjust the l...
313
  		ret = -EIO;
9404a5fc7   Stephen Warren   env_mmc: allow en...
314
315
  		goto fini;
  	}
a80603598   Terry Lv   Save environment ...
316

2166ebf78   Simon Goldschmidt   env: make env dri...
317
  	ret = env_import(buf, 1);
9404a5fc7   Stephen Warren   env_mmc: allow en...
318
319
320
321
322
  
  fini:
  	fini_mmc_for_env(mmc);
  err:
  	if (ret)
c75648d75   Tim Harvey   env_mmc: add erro...
323
  		set_default_env(errmsg);
a80603598   Terry Lv   Save environment ...
324
  #endif
c59519919   Simon Glass   env: Adjust the l...
325
  	return ret;
a80603598   Terry Lv   Save environment ...
326
  }
d196bd880   Michael Heimpold   env_mmc: add supp...
327
  #endif /* CONFIG_ENV_OFFSET_REDUND */
4415f1d1f   Simon Glass   env: Create a loc...
328
329
330
  
  U_BOOT_ENV_LOCATION(mmc) = {
  	.location	= ENVL_MMC,
ac358beb8   Simon Glass   env: Drop the env...
331
  	ENV_NAME("MMC")
e5bce247b   Simon Glass   env: Switch over ...
332
  	.load		= env_mmc_load,
4415f1d1f   Simon Glass   env: Create a loc...
333
  #ifndef CONFIG_SPL_BUILD
e5bce247b   Simon Glass   env: Switch over ...
334
  	.save		= env_save_ptr(env_mmc_save),
4415f1d1f   Simon Glass   env: Create a loc...
335
  #endif
4415f1d1f   Simon Glass   env: Create a loc...
336
  };