Blame view

common/env_eeprom.c 5.52 KB
0bc4a1ac8   wdenk   Initial revision
1
  /*
ea882baf9   Wolfgang Denk   New implementatio...
2
   * (C) Copyright 2000-2010
0bc4a1ac8   wdenk   Initial revision
3
4
5
6
   * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
   *
   * (C) Copyright 2001 Sysgo Real-Time Solutions, GmbH <www.elinos.com>
   * Andreas Heppel <aheppel@sysgo.de>
ea882baf9   Wolfgang Denk   New implementatio...
7
   *
3765b3e7b   Wolfgang Denk   Coding Style clea...
8
   * SPDX-License-Identifier:	GPL-2.0+
0bc4a1ac8   wdenk   Initial revision
9
10
11
   */
  
  #include <common.h>
0bc4a1ac8   wdenk   Initial revision
12
13
  #include <command.h>
  #include <environment.h>
0bc4a1ac8   wdenk   Initial revision
14
  #include <linux/stddef.h>
548738b4d   Heiko Schocher   cmd_eeprom: I2C u...
15
16
17
  #if defined(CONFIG_I2C_ENV_EEPROM_BUS)
  #include <i2c.h>
  #endif
ea882baf9   Wolfgang Denk   New implementatio...
18
19
20
  #include <search.h>
  #include <errno.h>
  #include <linux/compiler.h>	/* for BUG_ON */
0bc4a1ac8   wdenk   Initial revision
21

d87080b72   Wolfgang Denk   GCC-4.x fixes: cl...
22
  DECLARE_GLOBAL_DATA_PTR;
dd2a233c9   Igor Grinberg   env: clean env_ee...
23
  env_t *env_ptr;
0bc4a1ac8   wdenk   Initial revision
24

ea882baf9   Wolfgang Denk   New implementatio...
25
  char *env_name_spec = "EEPROM";
548738b4d   Heiko Schocher   cmd_eeprom: I2C u...
26

ea882baf9   Wolfgang Denk   New implementatio...
27
  static int eeprom_bus_read(unsigned dev_addr, unsigned offset,
dd2a233c9   Igor Grinberg   env: clean env_ee...
28
  			   uchar *buffer, unsigned cnt)
548738b4d   Heiko Schocher   cmd_eeprom: I2C u...
29
30
31
32
  {
  	int rcode;
  #if defined(CONFIG_I2C_ENV_EEPROM_BUS)
  	int old_bus = i2c_get_bus_num();
3f4978c71   Heiko Schocher   i2c: common chang...
33
34
  	if (old_bus != CONFIG_I2C_ENV_EEPROM_BUS)
  		i2c_set_bus_num(CONFIG_I2C_ENV_EEPROM_BUS);
548738b4d   Heiko Schocher   cmd_eeprom: I2C u...
35
  #endif
dd2a233c9   Igor Grinberg   env: clean env_ee...
36
  	rcode = eeprom_read(dev_addr, offset, buffer, cnt);
ea882baf9   Wolfgang Denk   New implementatio...
37

548738b4d   Heiko Schocher   cmd_eeprom: I2C u...
38
  #if defined(CONFIG_I2C_ENV_EEPROM_BUS)
6d001e7df   Alexey Brodkin   env_eeprom - fix ...
39
  	i2c_set_bus_num(old_bus);
548738b4d   Heiko Schocher   cmd_eeprom: I2C u...
40
  #endif
9a2accb44   Heiko Schocher   i2c, multibus: ge...
41

548738b4d   Heiko Schocher   cmd_eeprom: I2C u...
42
43
  	return rcode;
  }
ea882baf9   Wolfgang Denk   New implementatio...
44
  static int eeprom_bus_write(unsigned dev_addr, unsigned offset,
dd2a233c9   Igor Grinberg   env: clean env_ee...
45
  			    uchar *buffer, unsigned cnt)
548738b4d   Heiko Schocher   cmd_eeprom: I2C u...
46
47
48
49
  {
  	int rcode;
  #if defined(CONFIG_I2C_ENV_EEPROM_BUS)
  	int old_bus = i2c_get_bus_num();
3f4978c71   Heiko Schocher   i2c: common chang...
50
51
  	if (old_bus != CONFIG_I2C_ENV_EEPROM_BUS)
  		i2c_set_bus_num(CONFIG_I2C_ENV_EEPROM_BUS);
548738b4d   Heiko Schocher   cmd_eeprom: I2C u...
52
  #endif
9a2accb44   Heiko Schocher   i2c, multibus: ge...
53

ea882baf9   Wolfgang Denk   New implementatio...
54
  	rcode = eeprom_write(dev_addr, offset, buffer, cnt);
9a2accb44   Heiko Schocher   i2c, multibus: ge...
55

548738b4d   Heiko Schocher   cmd_eeprom: I2C u...
56
57
58
  #if defined(CONFIG_I2C_ENV_EEPROM_BUS)
  	i2c_set_bus_num(old_bus);
  #endif
6d001e7df   Alexey Brodkin   env_eeprom - fix ...
59

548738b4d   Heiko Schocher   cmd_eeprom: I2C u...
60
61
  	return rcode;
  }
0bc4a1ac8   wdenk   Initial revision
62

dd2a233c9   Igor Grinberg   env: clean env_ee...
63
  uchar env_get_char_spec(int index)
0bc4a1ac8   wdenk   Initial revision
64
65
  {
  	uchar c;
dd2a233c9   Igor Grinberg   env: clean env_ee...
66
  	unsigned int off = CONFIG_ENV_OFFSET;
ea882baf9   Wolfgang Denk   New implementatio...
67

1567b596d   Heiko Schocher   env, eeprom: add ...
68
69
70
71
  #ifdef CONFIG_ENV_OFFSET_REDUND
  	if (gd->env_valid == 2)
  		off = CONFIG_ENV_OFFSET_REDUND;
  #endif
ea882baf9   Wolfgang Denk   New implementatio...
72
  	eeprom_bus_read(CONFIG_SYS_DEF_EEPROM_ADDR,
dd2a233c9   Igor Grinberg   env: clean env_ee...
73
  			off + index + offsetof(env_t, data), &c, 1);
0bc4a1ac8   wdenk   Initial revision
74

dd2a233c9   Igor Grinberg   env: clean env_ee...
75
  	return c;
0bc4a1ac8   wdenk   Initial revision
76
  }
dd2a233c9   Igor Grinberg   env: clean env_ee...
77
  void env_relocate_spec(void)
0bc4a1ac8   wdenk   Initial revision
78
  {
cd0f4fa1c   Tom Rini   Revert "env: fix ...
79
  	char buf[CONFIG_ENV_SIZE];
1567b596d   Heiko Schocher   env, eeprom: add ...
80
  	unsigned int off = CONFIG_ENV_OFFSET;
ea882baf9   Wolfgang Denk   New implementatio...
81

1567b596d   Heiko Schocher   env, eeprom: add ...
82
83
84
85
  #ifdef CONFIG_ENV_OFFSET_REDUND
  	if (gd->env_valid == 2)
  		off = CONFIG_ENV_OFFSET_REDUND;
  #endif
ea882baf9   Wolfgang Denk   New implementatio...
86
  	eeprom_bus_read(CONFIG_SYS_DEF_EEPROM_ADDR,
dd2a233c9   Igor Grinberg   env: clean env_ee...
87
  			off, (uchar *)buf, CONFIG_ENV_SIZE);
ea882baf9   Wolfgang Denk   New implementatio...
88
89
  
  	env_import(buf, 1);
0bc4a1ac8   wdenk   Initial revision
90
91
92
93
  }
  
  int saveenv(void)
  {
cd0f4fa1c   Tom Rini   Revert "env: fix ...
94
  	env_t	env_new;
ea882baf9   Wolfgang Denk   New implementatio...
95
96
  	ssize_t	len;
  	char	*res;
dd2a233c9   Igor Grinberg   env: clean env_ee...
97
98
  	int	rc;
  	unsigned int off	= CONFIG_ENV_OFFSET;
1567b596d   Heiko Schocher   env, eeprom: add ...
99
  #ifdef CONFIG_ENV_OFFSET_REDUND
dd2a233c9   Igor Grinberg   env: clean env_ee...
100
101
  	unsigned int off_red	= CONFIG_ENV_OFFSET_REDUND;
  	char flag_obsolete	= OBSOLETE_FLAG;
ea882baf9   Wolfgang Denk   New implementatio...
102
103
104
  #endif
  
  	BUG_ON(env_ptr != NULL);
cd0f4fa1c   Tom Rini   Revert "env: fix ...
105
  	res = (char *)&env_new.data;
be11235ab   Joe Hershberger   env: Hide '.' var...
106
  	len = hexport_r(&env_htab, '\0', 0, &res, ENV_SIZE, 0, NULL);
ea882baf9   Wolfgang Denk   New implementatio...
107
108
109
110
111
  	if (len < 0) {
  		error("Cannot export environment: errno = %d
  ", errno);
  		return 1;
  	}
cd0f4fa1c   Tom Rini   Revert "env: fix ...
112
  	env_new.crc = crc32(0, env_new.data, ENV_SIZE);
ea882baf9   Wolfgang Denk   New implementatio...
113
114
  
  #ifdef CONFIG_ENV_OFFSET_REDUND
1567b596d   Heiko Schocher   env, eeprom: add ...
115
  	if (gd->env_valid == 1) {
dd2a233c9   Igor Grinberg   env: clean env_ee...
116
117
  		off	= CONFIG_ENV_OFFSET_REDUND;
  		off_red	= CONFIG_ENV_OFFSET;
1567b596d   Heiko Schocher   env, eeprom: add ...
118
  	}
cd0f4fa1c   Tom Rini   Revert "env: fix ...
119
  	env_new.flags = ACTIVE_FLAG;
1567b596d   Heiko Schocher   env, eeprom: add ...
120
  #endif
ea882baf9   Wolfgang Denk   New implementatio...
121
  	rc = eeprom_bus_write(CONFIG_SYS_DEF_EEPROM_ADDR,
cd0f4fa1c   Tom Rini   Revert "env: fix ...
122
  			      off, (uchar *)&env_new, CONFIG_ENV_SIZE);
1567b596d   Heiko Schocher   env, eeprom: add ...
123
124
125
  
  #ifdef CONFIG_ENV_OFFSET_REDUND
  	if (rc == 0) {
ea882baf9   Wolfgang Denk   New implementatio...
126
  		eeprom_bus_write(CONFIG_SYS_DEF_EEPROM_ADDR,
dd2a233c9   Igor Grinberg   env: clean env_ee...
127
128
  				 off_red + offsetof(env_t, flags),
  				 (uchar *)&flag_obsolete, 1);
1567b596d   Heiko Schocher   env, eeprom: add ...
129
130
131
132
  		if (gd->env_valid == 1)
  			gd->env_valid = 2;
  		else
  			gd->env_valid = 1;
1567b596d   Heiko Schocher   env, eeprom: add ...
133
134
  	}
  #endif
1567b596d   Heiko Schocher   env, eeprom: add ...
135
  	return rc;
0bc4a1ac8   wdenk   Initial revision
136
  }
ea882baf9   Wolfgang Denk   New implementatio...
137
  /*
0bc4a1ac8   wdenk   Initial revision
138
139
   * Initialize Environment use
   *
ea882baf9   Wolfgang Denk   New implementatio...
140
   * We are still running from ROM, so data use is limited.
0bc4a1ac8   wdenk   Initial revision
141
142
   * Use a (moderately small) buffer on the stack
   */
1567b596d   Heiko Schocher   env, eeprom: add ...
143
144
145
  #ifdef CONFIG_ENV_OFFSET_REDUND
  int env_init(void)
  {
dd2a233c9   Igor Grinberg   env: clean env_ee...
146
  	ulong len, crc[2], crc_tmp;
1567b596d   Heiko Schocher   env, eeprom: add ...
147
  	unsigned int off, off_env[2];
dd2a233c9   Igor Grinberg   env: clean env_ee...
148
149
  	uchar buf[64], flags[2];
  	int i, crc_ok[2] = {0, 0};
1567b596d   Heiko Schocher   env, eeprom: add ...
150

ea882baf9   Wolfgang Denk   New implementatio...
151
  	eeprom_init();	/* prepare for EEPROM read/write */
1567b596d   Heiko Schocher   env, eeprom: add ...
152
153
154
155
156
157
  
  	off_env[0] = CONFIG_ENV_OFFSET;
  	off_env[1] = CONFIG_ENV_OFFSET_REDUND;
  
  	for (i = 0; i < 2; i++) {
  		/* read CRC */
ea882baf9   Wolfgang Denk   New implementatio...
158
  		eeprom_bus_read(CONFIG_SYS_DEF_EEPROM_ADDR,
dd2a233c9   Igor Grinberg   env: clean env_ee...
159
160
  				off_env[i] + offsetof(env_t, crc),
  				(uchar *)&crc[i], sizeof(ulong));
1567b596d   Heiko Schocher   env, eeprom: add ...
161
  		/* read FLAGS */
ea882baf9   Wolfgang Denk   New implementatio...
162
  		eeprom_bus_read(CONFIG_SYS_DEF_EEPROM_ADDR,
dd2a233c9   Igor Grinberg   env: clean env_ee...
163
164
  				off_env[i] + offsetof(env_t, flags),
  				(uchar *)&flags[i], sizeof(uchar));
1567b596d   Heiko Schocher   env, eeprom: add ...
165

ea882baf9   Wolfgang Denk   New implementatio...
166
  		crc_tmp = 0;
1567b596d   Heiko Schocher   env, eeprom: add ...
167
  		len = ENV_SIZE;
dd2a233c9   Igor Grinberg   env: clean env_ee...
168
  		off = off_env[i] + offsetof(env_t, data);
1567b596d   Heiko Schocher   env, eeprom: add ...
169
170
  		while (len > 0) {
  			int n = (len > sizeof(buf)) ? sizeof(buf) : len;
ea882baf9   Wolfgang Denk   New implementatio...
171
  			eeprom_bus_read(CONFIG_SYS_DEF_EEPROM_ADDR, off,
dd2a233c9   Igor Grinberg   env: clean env_ee...
172
  					buf, n);
1567b596d   Heiko Schocher   env, eeprom: add ...
173

ea882baf9   Wolfgang Denk   New implementatio...
174
  			crc_tmp = crc32(crc_tmp, buf, n);
1567b596d   Heiko Schocher   env, eeprom: add ...
175
176
177
  			len -= n;
  			off += n;
  		}
dd2a233c9   Igor Grinberg   env: clean env_ee...
178

1567b596d   Heiko Schocher   env, eeprom: add ...
179
180
181
182
183
  		if (crc_tmp == crc[i])
  			crc_ok[i] = 1;
  	}
  
  	if (!crc_ok[0] && !crc_ok[1]) {
dd2a233c9   Igor Grinberg   env: clean env_ee...
184
185
  		gd->env_addr	= 0;
  		gd->env_valid	= 0;
1567b596d   Heiko Schocher   env, eeprom: add ...
186
187
188
189
  
  		return 0;
  	} else if (crc_ok[0] && !crc_ok[1]) {
  		gd->env_valid = 1;
dd2a233c9   Igor Grinberg   env: clean env_ee...
190
  	} else if (!crc_ok[0] && crc_ok[1]) {
1567b596d   Heiko Schocher   env, eeprom: add ...
191
192
193
194
195
196
197
198
199
  		gd->env_valid = 2;
  	} else {
  		/* both ok - check serial */
  		if (flags[0] == ACTIVE_FLAG && flags[1] == OBSOLETE_FLAG)
  			gd->env_valid = 1;
  		else if (flags[0] == OBSOLETE_FLAG && flags[1] == ACTIVE_FLAG)
  			gd->env_valid = 2;
  		else if (flags[0] == 0xFF && flags[1] == 0)
  			gd->env_valid = 2;
dd2a233c9   Igor Grinberg   env: clean env_ee...
200
  		else if (flags[1] == 0xFF && flags[0] == 0)
1567b596d   Heiko Schocher   env, eeprom: add ...
201
202
203
204
205
206
  			gd->env_valid = 1;
  		else /* flags are equal - almost impossible */
  			gd->env_valid = 1;
  	}
  
  	if (gd->env_valid == 2)
dd2a233c9   Igor Grinberg   env: clean env_ee...
207
  		gd->env_addr = off_env[1] + offsetof(env_t, data);
1567b596d   Heiko Schocher   env, eeprom: add ...
208
  	else if (gd->env_valid == 1)
dd2a233c9   Igor Grinberg   env: clean env_ee...
209
  		gd->env_addr = off_env[0] + offsetof(env_t, data);
1567b596d   Heiko Schocher   env, eeprom: add ...
210

dd2a233c9   Igor Grinberg   env: clean env_ee...
211
  	return 0;
1567b596d   Heiko Schocher   env, eeprom: add ...
212
213
  }
  #else
0bc4a1ac8   wdenk   Initial revision
214
215
  int env_init(void)
  {
0bc4a1ac8   wdenk   Initial revision
216
217
218
  	ulong crc, len, new;
  	unsigned off;
  	uchar buf[64];
ea882baf9   Wolfgang Denk   New implementatio...
219
  	eeprom_init();	/* prepare for EEPROM read/write */
0bc4a1ac8   wdenk   Initial revision
220
221
  
  	/* read old CRC */
ea882baf9   Wolfgang Denk   New implementatio...
222
  	eeprom_bus_read(CONFIG_SYS_DEF_EEPROM_ADDR,
dd2a233c9   Igor Grinberg   env: clean env_ee...
223
224
  			CONFIG_ENV_OFFSET + offsetof(env_t, crc),
  			(uchar *)&crc, sizeof(ulong));
0bc4a1ac8   wdenk   Initial revision
225
226
227
  
  	new = 0;
  	len = ENV_SIZE;
dd2a233c9   Igor Grinberg   env: clean env_ee...
228
  	off = offsetof(env_t, data);
ea882baf9   Wolfgang Denk   New implementatio...
229

0bc4a1ac8   wdenk   Initial revision
230
231
  	while (len > 0) {
  		int n = (len > sizeof(buf)) ? sizeof(buf) : len;
ea882baf9   Wolfgang Denk   New implementatio...
232
  		eeprom_bus_read(CONFIG_SYS_DEF_EEPROM_ADDR,
548738b4d   Heiko Schocher   cmd_eeprom: I2C u...
233
  				CONFIG_ENV_OFFSET + off, buf, n);
ea882baf9   Wolfgang Denk   New implementatio...
234
  		new = crc32(new, buf, n);
0bc4a1ac8   wdenk   Initial revision
235
236
237
238
239
  		len -= n;
  		off += n;
  	}
  
  	if (crc == new) {
dd2a233c9   Igor Grinberg   env: clean env_ee...
240
241
  		gd->env_addr	= offsetof(env_t, data);
  		gd->env_valid	= 1;
0bc4a1ac8   wdenk   Initial revision
242
  	} else {
dd2a233c9   Igor Grinberg   env: clean env_ee...
243
244
  		gd->env_addr	= 0;
  		gd->env_valid	= 0;
0bc4a1ac8   wdenk   Initial revision
245
  	}
dd2a233c9   Igor Grinberg   env: clean env_ee...
246
  	return 0;
0bc4a1ac8   wdenk   Initial revision
247
  }
1567b596d   Heiko Schocher   env, eeprom: add ...
248
  #endif