Blame view

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

c9e87ba66   Jorge Ramirez-Ortiz   env: Save environ...
21
22
  #define __STR(X) #X
  #define STR(X) __STR(X)
d196bd880   Michael Heimpold   env_mmc: add supp...
23
24
25
26
  #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 ...
27
  DECLARE_GLOBAL_DATA_PTR;
97039ab98   Mingkai Hu   env_mmc: Allow bo...
28
29
30
  #if !defined(CONFIG_ENV_OFFSET)
  #define CONFIG_ENV_OFFSET 0
  #endif
f8b8a5546   Philipp Tomsich   env_mmc: configur...
31
  #if CONFIG_IS_ENABLED(OF_CONTROL)
c9e87ba66   Jorge Ramirez-Ortiz   env: Save environ...
32
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
  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...
59
60
  static inline s64 mmc_offset(int copy)
  {
c9e87ba66   Jorge Ramirez-Ortiz   env: Save environ...
61
62
63
64
65
66
67
68
69
  	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...
70
  	s64 val = 0, defvalue;
c9e87ba66   Jorge Ramirez-Ortiz   env: Save environ...
71
72
73
74
75
76
77
78
79
80
81
82
  	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;
  	}
565d9002a   Ye Li   MLK-22279-1 env: ...
83
  	defvalue = env_get_offset(CONFIG_ENV_OFFSET);
c9e87ba66   Jorge Ramirez-Ortiz   env: Save environ...
84
  	propname = dt_prop.offset;
f8b8a5546   Philipp Tomsich   env_mmc: configur...
85
86
87
  
  #if defined(CONFIG_ENV_OFFSET_REDUND)
  	if (copy) {
f8b8a5546   Philipp Tomsich   env_mmc: configur...
88
  		defvalue = CONFIG_ENV_OFFSET_REDUND;
c9e87ba66   Jorge Ramirez-Ortiz   env: Save environ...
89
  		propname = dt_prop.offset_redund;
f8b8a5546   Philipp Tomsich   env_mmc: configur...
90
91
  	}
  #endif
f8b8a5546   Philipp Tomsich   env_mmc: configur...
92
93
94
95
  	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...
96
  {
565d9002a   Ye Li   MLK-22279-1 env: ...
97
  	s64 offset = env_get_offset(CONFIG_ENV_OFFSET);
5c088ee84   Stephen Warren   env_mmc: allow ne...
98

f8b8a5546   Philipp Tomsich   env_mmc: configur...
99
  #if defined(CONFIG_ENV_OFFSET_REDUND)
d196bd880   Michael Heimpold   env_mmc: add supp...
100
  	if (copy)
5c088ee84   Stephen Warren   env_mmc: allow ne...
101
  		offset = CONFIG_ENV_OFFSET_REDUND;
d196bd880   Michael Heimpold   env_mmc: add supp...
102
  #endif
f8b8a5546   Philipp Tomsich   env_mmc: configur...
103
104
105
106
107
108
109
  	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...
110
111
112
113
114
  
  	if (offset < 0)
  		offset += mmc->capacity;
  
  	*env_addr = offset;
97039ab98   Mingkai Hu   env_mmc: Allow bo...
115
116
  	return 0;
  }
97039ab98   Mingkai Hu   env_mmc: Allow bo...
117

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

69f45cd53   Simon Glass   dm: mmc: Use the ...
134
135
  	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...
136
137
138
  	if (ret)
  		puts("MMC partition switch failed
  ");
6e7b7df4d   Dmitry Lifshitz   env_mmc: support ...
139
140
141
142
143
  
  	return ret;
  }
  #else
  static inline int mmc_set_env_part(struct mmc *mmc) {return 0; };
b9c8ccaba   Tom Rini   env_mmc.c: Allow ...
144
  #endif
c75648d75   Tim Harvey   env_mmc: add erro...
145
  static const char *init_mmc_for_env(struct mmc *mmc)
6e7b7df4d   Dmitry Lifshitz   env_mmc: support ...
146
  {
c75648d75   Tim Harvey   env_mmc: add erro...
147
  	if (!mmc)
c5d548a9f   Yaniv Levinsky   env: common: acce...
148
  		return "No MMC card found";
a80603598   Terry Lv   Save environment ...
149

d48b8d113   Sjoerd Simons   env: Properly che...
150
  #if CONFIG_IS_ENABLED(BLK)
01b73fe63   Simon Glass   dm: mmc: Ensure t...
151
152
153
  	struct udevice *dev;
  
  	if (blk_get_from_parent(mmc->dev, &dev))
c5d548a9f   Yaniv Levinsky   env: common: acce...
154
  		return "No block device";
01b73fe63   Simon Glass   dm: mmc: Ensure t...
155
  #else
c75648d75   Tim Harvey   env_mmc: add erro...
156
  	if (mmc_init(mmc))
c5d548a9f   Yaniv Levinsky   env: common: acce...
157
  		return "MMC init failed";
e7017a3c7   Simon Glass   dm: mmc: Don't re...
158
  #endif
c75648d75   Tim Harvey   env_mmc: add erro...
159
  	if (mmc_set_env_part(mmc))
c5d548a9f   Yaniv Levinsky   env: common: acce...
160
  		return "MMC partition switch failed";
a80603598   Terry Lv   Save environment ...
161

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

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

e8db8f71c   Igor Grinberg   env: clean env_mm...
179
180
  	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 ...
181

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

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

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

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

e8db8f71c   Igor Grinberg   env: clean env_mm...
238
239
  	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 ...
240

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

452a2722e   Markus Niebel   env_mmc: fix buff...
256
257
  	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...
258
  	mmc_initialize(NULL);
b9c8ccaba   Tom Rini   env_mmc.c: Allow ...
259
  	mmc = find_mmc_device(dev);
c75648d75   Tim Harvey   env_mmc: add erro...
260
261
  	errmsg = init_mmc_for_env(mmc);
  	if (errmsg) {
c59519919   Simon Glass   env: Adjust the l...
262
  		ret = -EIO;
d196bd880   Michael Heimpold   env_mmc: add supp...
263
264
265
266
267
  		goto err;
  	}
  
  	if (mmc_get_env_addr(mmc, 0, &offset1) ||
  	    mmc_get_env_addr(mmc, 1, &offset2)) {
c59519919   Simon Glass   env: Adjust the l...
268
  		ret = -EIO;
d196bd880   Michael Heimpold   env_mmc: add supp...
269
270
271
272
273
  		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...
274
275
  	ret = env_import_redund((char *)tmp_env1, read1_fail, (char *)tmp_env2,
  				read2_fail);
d196bd880   Michael Heimpold   env_mmc: add supp...
276
277
278
279
280
  
  fini:
  	fini_mmc_for_env(mmc);
  err:
  	if (ret)
c5d548a9f   Yaniv Levinsky   env: common: acce...
281
  		set_default_env(errmsg, 0);
c59519919   Simon Glass   env: Adjust the l...
282

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

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

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

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

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