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;
dd2a233c9   Igor Grinberg   env: clean env_ee...
95
96
  	int	rc;
  	unsigned int off	= CONFIG_ENV_OFFSET;
1567b596d   Heiko Schocher   env, eeprom: add ...
97
  #ifdef CONFIG_ENV_OFFSET_REDUND
dd2a233c9   Igor Grinberg   env: clean env_ee...
98
99
  	unsigned int off_red	= CONFIG_ENV_OFFSET_REDUND;
  	char flag_obsolete	= OBSOLETE_FLAG;
ea882baf9   Wolfgang Denk   New implementatio...
100
101
102
  #endif
  
  	BUG_ON(env_ptr != NULL);
7ce1526ed   Marek Vasut   env: Add env_expo...
103
104
105
  	rc = env_export(&env_new);
  	if (rc)
  		return rc;
ea882baf9   Wolfgang Denk   New implementatio...
106
107
  
  #ifdef CONFIG_ENV_OFFSET_REDUND
1567b596d   Heiko Schocher   env, eeprom: add ...
108
  	if (gd->env_valid == 1) {
dd2a233c9   Igor Grinberg   env: clean env_ee...
109
110
  		off	= CONFIG_ENV_OFFSET_REDUND;
  		off_red	= CONFIG_ENV_OFFSET;
1567b596d   Heiko Schocher   env, eeprom: add ...
111
  	}
cd0f4fa1c   Tom Rini   Revert "env: fix ...
112
  	env_new.flags = ACTIVE_FLAG;
1567b596d   Heiko Schocher   env, eeprom: add ...
113
  #endif
ea882baf9   Wolfgang Denk   New implementatio...
114
  	rc = eeprom_bus_write(CONFIG_SYS_DEF_EEPROM_ADDR,
cd0f4fa1c   Tom Rini   Revert "env: fix ...
115
  			      off, (uchar *)&env_new, CONFIG_ENV_SIZE);
1567b596d   Heiko Schocher   env, eeprom: add ...
116
117
118
  
  #ifdef CONFIG_ENV_OFFSET_REDUND
  	if (rc == 0) {
ea882baf9   Wolfgang Denk   New implementatio...
119
  		eeprom_bus_write(CONFIG_SYS_DEF_EEPROM_ADDR,
dd2a233c9   Igor Grinberg   env: clean env_ee...
120
121
  				 off_red + offsetof(env_t, flags),
  				 (uchar *)&flag_obsolete, 1);
1567b596d   Heiko Schocher   env, eeprom: add ...
122
123
124
125
  		if (gd->env_valid == 1)
  			gd->env_valid = 2;
  		else
  			gd->env_valid = 1;
1567b596d   Heiko Schocher   env, eeprom: add ...
126
127
  	}
  #endif
1567b596d   Heiko Schocher   env, eeprom: add ...
128
  	return rc;
0bc4a1ac8   wdenk   Initial revision
129
  }
ea882baf9   Wolfgang Denk   New implementatio...
130
  /*
0bc4a1ac8   wdenk   Initial revision
131
132
   * Initialize Environment use
   *
ea882baf9   Wolfgang Denk   New implementatio...
133
   * We are still running from ROM, so data use is limited.
0bc4a1ac8   wdenk   Initial revision
134
135
   * Use a (moderately small) buffer on the stack
   */
1567b596d   Heiko Schocher   env, eeprom: add ...
136
137
138
  #ifdef CONFIG_ENV_OFFSET_REDUND
  int env_init(void)
  {
ed6a5d4f8   Siva Durga Prasad Paladugu   env_eeprom: Assig...
139
  #ifdef ENV_IS_EMBEDDED
dd2a233c9   Igor Grinberg   env: clean env_ee...
140
  	ulong len, crc[2], crc_tmp;
1567b596d   Heiko Schocher   env, eeprom: add ...
141
  	unsigned int off, off_env[2];
dd2a233c9   Igor Grinberg   env: clean env_ee...
142
143
  	uchar buf[64], flags[2];
  	int i, crc_ok[2] = {0, 0};
1567b596d   Heiko Schocher   env, eeprom: add ...
144

ea882baf9   Wolfgang Denk   New implementatio...
145
  	eeprom_init();	/* prepare for EEPROM read/write */
1567b596d   Heiko Schocher   env, eeprom: add ...
146
147
148
149
150
151
  
  	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...
152
  		eeprom_bus_read(CONFIG_SYS_DEF_EEPROM_ADDR,
dd2a233c9   Igor Grinberg   env: clean env_ee...
153
154
  				off_env[i] + offsetof(env_t, crc),
  				(uchar *)&crc[i], sizeof(ulong));
1567b596d   Heiko Schocher   env, eeprom: add ...
155
  		/* read FLAGS */
ea882baf9   Wolfgang Denk   New implementatio...
156
  		eeprom_bus_read(CONFIG_SYS_DEF_EEPROM_ADDR,
dd2a233c9   Igor Grinberg   env: clean env_ee...
157
158
  				off_env[i] + offsetof(env_t, flags),
  				(uchar *)&flags[i], sizeof(uchar));
1567b596d   Heiko Schocher   env, eeprom: add ...
159

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

ea882baf9   Wolfgang Denk   New implementatio...
168
  			crc_tmp = crc32(crc_tmp, buf, n);
1567b596d   Heiko Schocher   env, eeprom: add ...
169
170
171
  			len -= n;
  			off += n;
  		}
dd2a233c9   Igor Grinberg   env: clean env_ee...
172

1567b596d   Heiko Schocher   env, eeprom: add ...
173
174
175
176
177
  		if (crc_tmp == crc[i])
  			crc_ok[i] = 1;
  	}
  
  	if (!crc_ok[0] && !crc_ok[1]) {
dd2a233c9   Igor Grinberg   env: clean env_ee...
178
179
  		gd->env_addr	= 0;
  		gd->env_valid	= 0;
1567b596d   Heiko Schocher   env, eeprom: add ...
180
181
182
183
  
  		return 0;
  	} else if (crc_ok[0] && !crc_ok[1]) {
  		gd->env_valid = 1;
dd2a233c9   Igor Grinberg   env: clean env_ee...
184
  	} else if (!crc_ok[0] && crc_ok[1]) {
1567b596d   Heiko Schocher   env, eeprom: add ...
185
186
187
188
189
190
191
192
193
  		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...
194
  		else if (flags[1] == 0xFF && flags[0] == 0)
1567b596d   Heiko Schocher   env, eeprom: add ...
195
196
197
198
199
200
  			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...
201
  		gd->env_addr = off_env[1] + offsetof(env_t, data);
1567b596d   Heiko Schocher   env, eeprom: add ...
202
  	else if (gd->env_valid == 1)
dd2a233c9   Igor Grinberg   env: clean env_ee...
203
  		gd->env_addr = off_env[0] + offsetof(env_t, data);
ed6a5d4f8   Siva Durga Prasad Paladugu   env_eeprom: Assig...
204
205
206
207
  #else
  	gd->env_addr = (ulong)&default_environment[0];
  	gd->env_valid = 1;
  #endif
dd2a233c9   Igor Grinberg   env: clean env_ee...
208
  	return 0;
1567b596d   Heiko Schocher   env, eeprom: add ...
209
210
  }
  #else
0bc4a1ac8   wdenk   Initial revision
211
212
  int env_init(void)
  {
ed6a5d4f8   Siva Durga Prasad Paladugu   env_eeprom: Assig...
213
  #ifdef ENV_IS_EMBEDDED
0bc4a1ac8   wdenk   Initial revision
214
215
216
  	ulong crc, len, new;
  	unsigned off;
  	uchar buf[64];
ea882baf9   Wolfgang Denk   New implementatio...
217
  	eeprom_init();	/* prepare for EEPROM read/write */
0bc4a1ac8   wdenk   Initial revision
218
219
  
  	/* read old CRC */
ea882baf9   Wolfgang Denk   New implementatio...
220
  	eeprom_bus_read(CONFIG_SYS_DEF_EEPROM_ADDR,
dd2a233c9   Igor Grinberg   env: clean env_ee...
221
222
  			CONFIG_ENV_OFFSET + offsetof(env_t, crc),
  			(uchar *)&crc, sizeof(ulong));
0bc4a1ac8   wdenk   Initial revision
223
224
225
  
  	new = 0;
  	len = ENV_SIZE;
dd2a233c9   Igor Grinberg   env: clean env_ee...
226
  	off = offsetof(env_t, data);
ea882baf9   Wolfgang Denk   New implementatio...
227

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