Blame view

common/env_mmc.c 6.18 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
13
14
15
   */
  
  /* #define DEBUG */
  
  #include <common.h>
  
  #include <command.h>
  #include <environment.h>
  #include <linux/stddef.h>
  #include <malloc.h>
  #include <mmc.h>
6d1d51b32   Lei Wen   env_mmc: fix comp...
16
  #include <search.h>
e79f48393   Lei Wen   env_mmc: fix cann...
17
  #include <errno.h>
a80603598   Terry Lv   Save environment ...
18

d196bd880   Michael Heimpold   env_mmc: add supp...
19
20
21
22
  #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 ...
23
24
25
  char *env_name_spec = "MMC";
  
  #ifdef ENV_IS_EMBEDDED
994bc671c   Igor Grinberg   env: move extern ...
26
  env_t *env_ptr = &environment;
a80603598   Terry Lv   Save environment ...
27
  #else /* ! ENV_IS_EMBEDDED */
e8db8f71c   Igor Grinberg   env: clean env_mm...
28
  env_t *env_ptr;
a80603598   Terry Lv   Save environment ...
29
  #endif /* ENV_IS_EMBEDDED */
a80603598   Terry Lv   Save environment ...
30
  DECLARE_GLOBAL_DATA_PTR;
97039ab98   Mingkai Hu   env_mmc: Allow bo...
31
32
33
  #if !defined(CONFIG_ENV_OFFSET)
  #define CONFIG_ENV_OFFSET 0
  #endif
d196bd880   Michael Heimpold   env_mmc: add supp...
34
  __weak int mmc_get_env_addr(struct mmc *mmc, int copy, u32 *env_addr)
97039ab98   Mingkai Hu   env_mmc: Allow bo...
35
  {
5c088ee84   Stephen Warren   env_mmc: allow ne...
36
37
38
  	s64 offset;
  
  	offset = CONFIG_ENV_OFFSET;
d196bd880   Michael Heimpold   env_mmc: add supp...
39
40
  #ifdef CONFIG_ENV_OFFSET_REDUND
  	if (copy)
5c088ee84   Stephen Warren   env_mmc: allow ne...
41
  		offset = CONFIG_ENV_OFFSET_REDUND;
d196bd880   Michael Heimpold   env_mmc: add supp...
42
  #endif
5c088ee84   Stephen Warren   env_mmc: allow ne...
43
44
45
46
47
  
  	if (offset < 0)
  		offset += mmc->capacity;
  
  	*env_addr = offset;
97039ab98   Mingkai Hu   env_mmc: Allow bo...
48
49
  	return 0;
  }
97039ab98   Mingkai Hu   env_mmc: Allow bo...
50

a80603598   Terry Lv   Save environment ...
51
52
53
  int env_init(void)
  {
  	/* use default */
e8db8f71c   Igor Grinberg   env: clean env_mm...
54
55
  	gd->env_addr	= (ulong)&default_environment[0];
  	gd->env_valid	= 1;
a80603598   Terry Lv   Save environment ...
56
57
58
  
  	return 0;
  }
e8db8f71c   Igor Grinberg   env: clean env_mm...
59
  static int init_mmc_for_env(struct mmc *mmc)
a80603598   Terry Lv   Save environment ...
60
61
62
63
64
65
66
67
68
69
  {
  	if (!mmc) {
  		puts("No MMC card found
  ");
  		return -1;
  	}
  
  	if (mmc_init(mmc)) {
  		puts("MMC init failed
  ");
e8db8f71c   Igor Grinberg   env: clean env_mm...
70
  		return -1;
a80603598   Terry Lv   Save environment ...
71
  	}
9404a5fc7   Stephen Warren   env_mmc: allow en...
72
73
74
75
76
77
78
79
80
81
  #ifdef CONFIG_SYS_MMC_ENV_PART
  	if (CONFIG_SYS_MMC_ENV_PART != mmc->part_num) {
  		if (mmc_switch_part(CONFIG_SYS_MMC_ENV_DEV,
  				    CONFIG_SYS_MMC_ENV_PART)) {
  			puts("MMC partition switch failed
  ");
  			return -1;
  		}
  	}
  #endif
a80603598   Terry Lv   Save environment ...
82
83
  	return 0;
  }
9404a5fc7   Stephen Warren   env_mmc: allow en...
84
85
86
87
88
89
90
91
  static void fini_mmc_for_env(struct mmc *mmc)
  {
  #ifdef CONFIG_SYS_MMC_ENV_PART
  	if (CONFIG_SYS_MMC_ENV_PART != mmc->part_num)
  		mmc_switch_part(CONFIG_SYS_MMC_ENV_DEV,
  				mmc->part_num);
  #endif
  }
a80603598   Terry Lv   Save environment ...
92
  #ifdef CONFIG_CMD_SAVEENV
e8db8f71c   Igor Grinberg   env: clean env_mm...
93
94
  static inline int write_env(struct mmc *mmc, unsigned long size,
  			    unsigned long offset, const void *buffer)
a80603598   Terry Lv   Save environment ...
95
96
  {
  	uint blk_start, blk_cnt, n;
e8db8f71c   Igor Grinberg   env: clean env_mm...
97
98
  	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 ...
99
100
101
102
103
104
  
  	n = mmc->block_dev.block_write(CONFIG_SYS_MMC_ENV_DEV, blk_start,
  					blk_cnt, (u_char *)buffer);
  
  	return (n == blk_cnt) ? 0 : -1;
  }
d196bd880   Michael Heimpold   env_mmc: add supp...
105
106
107
  #ifdef CONFIG_ENV_OFFSET_REDUND
  static unsigned char env_flags;
  #endif
a80603598   Terry Lv   Save environment ...
108
109
  int saveenv(void)
  {
cd0f4fa1c   Tom Rini   Revert "env: fix ...
110
  	ALLOC_CACHE_ALIGN_BUFFER(env_t, env_new, 1);
e79f48393   Lei Wen   env_mmc: fix cann...
111
112
  	ssize_t	len;
  	char	*res;
a80603598   Terry Lv   Save environment ...
113
  	struct mmc *mmc = find_mmc_device(CONFIG_SYS_MMC_ENV_DEV);
e8db8f71c   Igor Grinberg   env: clean env_mm...
114
  	u32	offset;
d196bd880   Michael Heimpold   env_mmc: add supp...
115
  	int	ret, copy = 0;
a80603598   Terry Lv   Save environment ...
116

9404a5fc7   Stephen Warren   env_mmc: allow en...
117
  	if (init_mmc_for_env(mmc))
97039ab98   Mingkai Hu   env_mmc: Allow bo...
118
  		return 1;
cd0f4fa1c   Tom Rini   Revert "env: fix ...
119
  	res = (char *)&env_new->data;
be11235ab   Joe Hershberger   env: Hide '.' var...
120
  	len = hexport_r(&env_htab, '\0', 0, &res, ENV_SIZE, 0, NULL);
e79f48393   Lei Wen   env_mmc: fix cann...
121
122
123
  	if (len < 0) {
  		error("Cannot export environment: errno = %d
  ", errno);
9404a5fc7   Stephen Warren   env_mmc: allow en...
124
125
  		ret = 1;
  		goto fini;
e79f48393   Lei Wen   env_mmc: fix cann...
126
  	}
e8db8f71c   Igor Grinberg   env: clean env_mm...
127

cd0f4fa1c   Tom Rini   Revert "env: fix ...
128
  	env_new->crc = crc32(0, &env_new->data[0], ENV_SIZE);
d196bd880   Michael Heimpold   env_mmc: add supp...
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
  
  #ifdef CONFIG_ENV_OFFSET_REDUND
  	env_new->flags	= ++env_flags; /* increase the serial */
  
  	if (gd->env_valid == 1)
  		copy = 1;
  #endif
  
  	if (mmc_get_env_addr(mmc, copy, &offset)) {
  		ret = 1;
  		goto fini;
  	}
  
  	printf("Writing to %sMMC(%d)... ", copy ? "redundant " : "",
  	       CONFIG_SYS_MMC_ENV_DEV);
4036b6301   Stephen Warren   env_mmc: align bu...
144
  	if (write_env(mmc, CONFIG_ENV_SIZE, offset, (u_char *)env_new)) {
a80603598   Terry Lv   Save environment ...
145
146
  		puts("failed
  ");
9404a5fc7   Stephen Warren   env_mmc: allow en...
147
148
  		ret = 1;
  		goto fini;
a80603598   Terry Lv   Save environment ...
149
150
151
152
  	}
  
  	puts("done
  ");
9404a5fc7   Stephen Warren   env_mmc: allow en...
153
  	ret = 0;
d196bd880   Michael Heimpold   env_mmc: add supp...
154
155
156
  #ifdef CONFIG_ENV_OFFSET_REDUND
  	gd->env_valid = gd->env_valid == 2 ? 1 : 2;
  #endif
9404a5fc7   Stephen Warren   env_mmc: allow en...
157
158
159
  fini:
  	fini_mmc_for_env(mmc);
  	return ret;
a80603598   Terry Lv   Save environment ...
160
161
  }
  #endif /* CONFIG_CMD_SAVEENV */
e8db8f71c   Igor Grinberg   env: clean env_mm...
162
163
  static inline int read_env(struct mmc *mmc, unsigned long size,
  			   unsigned long offset, const void *buffer)
a80603598   Terry Lv   Save environment ...
164
165
  {
  	uint blk_start, blk_cnt, n;
e8db8f71c   Igor Grinberg   env: clean env_mm...
166
167
  	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 ...
168
169
170
171
172
173
  
  	n = mmc->block_dev.block_read(CONFIG_SYS_MMC_ENV_DEV, blk_start,
  					blk_cnt, (uchar *)buffer);
  
  	return (n == blk_cnt) ? 0 : -1;
  }
d196bd880   Michael Heimpold   env_mmc: add supp...
174
175
176
177
178
179
180
181
  #ifdef CONFIG_ENV_OFFSET_REDUND
  void env_relocate_spec(void)
  {
  #if !defined(ENV_IS_EMBEDDED)
  	struct mmc *mmc = find_mmc_device(CONFIG_SYS_MMC_ENV_DEV);
  	u32 offset1, offset2;
  	int read1_fail = 0, read2_fail = 0;
  	int crc1_ok = 0, crc2_ok = 0;
452a2722e   Markus Niebel   env_mmc: fix buff...
182
  	env_t *ep;
d196bd880   Michael Heimpold   env_mmc: add supp...
183
  	int ret;
452a2722e   Markus Niebel   env_mmc: fix buff...
184
185
  	ALLOC_CACHE_ALIGN_BUFFER(env_t, tmp_env1, 1);
  	ALLOC_CACHE_ALIGN_BUFFER(env_t, tmp_env2, 1);
d196bd880   Michael Heimpold   env_mmc: add supp...
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
  	if (tmp_env1 == NULL || tmp_env2 == NULL) {
  		puts("Can't allocate buffers for environment
  ");
  		ret = 1;
  		goto err;
  	}
  
  	if (init_mmc_for_env(mmc)) {
  		ret = 1;
  		goto err;
  	}
  
  	if (mmc_get_env_addr(mmc, 0, &offset1) ||
  	    mmc_get_env_addr(mmc, 1, &offset2)) {
  		ret = 1;
  		goto fini;
  	}
  
  	read1_fail = read_env(mmc, CONFIG_ENV_SIZE, offset1, tmp_env1);
  	read2_fail = read_env(mmc, CONFIG_ENV_SIZE, offset2, tmp_env2);
  
  	if (read1_fail && read2_fail)
  		puts("*** Error - No Valid Environment Area found
  ");
  	else if (read1_fail || read2_fail)
  		puts("*** Warning - some problems detected "
  		     "reading environment; recovered successfully
  ");
  
  	crc1_ok = !read1_fail &&
  		(crc32(0, tmp_env1->data, ENV_SIZE) == tmp_env1->crc);
  	crc2_ok = !read2_fail &&
  		(crc32(0, tmp_env2->data, ENV_SIZE) == tmp_env2->crc);
  
  	if (!crc1_ok && !crc2_ok) {
  		ret = 1;
  		goto fini;
  	} else if (crc1_ok && !crc2_ok) {
  		gd->env_valid = 1;
  	} else if (!crc1_ok && crc2_ok) {
  		gd->env_valid = 2;
  	} else {
  		/* both ok - check serial */
  		if (tmp_env1->flags == 255 && tmp_env2->flags == 0)
  			gd->env_valid = 2;
  		else if (tmp_env2->flags == 255 && tmp_env1->flags == 0)
  			gd->env_valid = 1;
  		else if (tmp_env1->flags > tmp_env2->flags)
  			gd->env_valid = 1;
  		else if (tmp_env2->flags > tmp_env1->flags)
  			gd->env_valid = 2;
  		else /* flags are equal - almost impossible */
  			gd->env_valid = 1;
  	}
  
  	free(env_ptr);
  
  	if (gd->env_valid == 1)
  		ep = tmp_env1;
  	else
  		ep = tmp_env2;
  
  	env_flags = ep->flags;
  	env_import((char *)ep, 0);
  	ret = 0;
  
  fini:
  	fini_mmc_for_env(mmc);
  err:
  	if (ret)
  		set_default_env(NULL);
d196bd880   Michael Heimpold   env_mmc: add supp...
257
258
259
  #endif
  }
  #else /* ! CONFIG_ENV_OFFSET_REDUND */
a80603598   Terry Lv   Save environment ...
260
261
262
  void env_relocate_spec(void)
  {
  #if !defined(ENV_IS_EMBEDDED)
cd0f4fa1c   Tom Rini   Revert "env: fix ...
263
  	ALLOC_CACHE_ALIGN_BUFFER(char, buf, CONFIG_ENV_SIZE);
a80603598   Terry Lv   Save environment ...
264
  	struct mmc *mmc = find_mmc_device(CONFIG_SYS_MMC_ENV_DEV);
97039ab98   Mingkai Hu   env_mmc: Allow bo...
265
  	u32 offset;
9404a5fc7   Stephen Warren   env_mmc: allow en...
266
  	int ret;
a80603598   Terry Lv   Save environment ...
267

9404a5fc7   Stephen Warren   env_mmc: allow en...
268
269
270
271
  	if (init_mmc_for_env(mmc)) {
  		ret = 1;
  		goto err;
  	}
a80603598   Terry Lv   Save environment ...
272

d196bd880   Michael Heimpold   env_mmc: add supp...
273
  	if (mmc_get_env_addr(mmc, 0, &offset)) {
9404a5fc7   Stephen Warren   env_mmc: allow en...
274
275
276
  		ret = 1;
  		goto fini;
  	}
cd0f4fa1c   Tom Rini   Revert "env: fix ...
277
  	if (read_env(mmc, CONFIG_ENV_SIZE, offset, buf)) {
9404a5fc7   Stephen Warren   env_mmc: allow en...
278
279
280
  		ret = 1;
  		goto fini;
  	}
a80603598   Terry Lv   Save environment ...
281

cd0f4fa1c   Tom Rini   Revert "env: fix ...
282
  	env_import(buf, 1);
9404a5fc7   Stephen Warren   env_mmc: allow en...
283
284
285
286
287
288
289
  	ret = 0;
  
  fini:
  	fini_mmc_for_env(mmc);
  err:
  	if (ret)
  		set_default_env(NULL);
a80603598   Terry Lv   Save environment ...
290
291
  #endif
  }
d196bd880   Michael Heimpold   env_mmc: add supp...
292
  #endif /* CONFIG_ENV_OFFSET_REDUND */