Blame view

env/eeprom.c 5.53 KB
83d290c56   Tom Rini   SPDX: Convert all...
1
  // SPDX-License-Identifier: GPL-2.0+
0bc4a1ac8   wdenk   Initial revision
2
  /*
ea882baf9   Wolfgang Denk   New implementatio...
3
   * (C) Copyright 2000-2010
0bc4a1ac8   wdenk   Initial revision
4
5
6
7
   * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
   *
   * (C) Copyright 2001 Sysgo Real-Time Solutions, GmbH <www.elinos.com>
   * Andreas Heppel <aheppel@sysgo.de>
0bc4a1ac8   wdenk   Initial revision
8
9
10
   */
  
  #include <common.h>
0bc4a1ac8   wdenk   Initial revision
11
  #include <command.h>
cb3ef6810   Simon Glass   common: Move old ...
12
  #include <eeprom.h>
7b51b576d   Simon Glass   env: Move env_get...
13
  #include <env.h>
f3998fdc4   Simon Glass   env: Rename envir...
14
  #include <env_internal.h>
0bc4a1ac8   wdenk   Initial revision
15
  #include <linux/stddef.h>
3db711085   Simon Glass   crc32: Use the cr...
16
  #include <u-boot/crc.h>
548738b4d   Heiko Schocher   cmd_eeprom: I2C u...
17
18
19
  #if defined(CONFIG_I2C_ENV_EEPROM_BUS)
  #include <i2c.h>
  #endif
ea882baf9   Wolfgang Denk   New implementatio...
20
21
22
  #include <search.h>
  #include <errno.h>
  #include <linux/compiler.h>	/* for BUG_ON */
0bc4a1ac8   wdenk   Initial revision
23

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

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

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

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

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

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

b2cdef486   Goldschmidt Simon   env: restore old ...
61
62
63
64
  /** Call this function from overridden env_get_char_spec() if you need
   * this functionality.
   */
  int env_eeprom_get_char(int index)
0bc4a1ac8   wdenk   Initial revision
65
66
  {
  	uchar c;
445f20fe7   Ye Li   MLK-22279-1 env: ...
67
  	unsigned int off = env_get_offset(CONFIG_ENV_OFFSET);
ea882baf9   Wolfgang Denk   New implementatio...
68

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

dd2a233c9   Igor Grinberg   env: clean env_ee...
76
  	return c;
0bc4a1ac8   wdenk   Initial revision
77
  }
c59519919   Simon Glass   env: Adjust the l...
78
  static int env_eeprom_load(void)
0bc4a1ac8   wdenk   Initial revision
79
  {
e3cc5bc58   Ludger Dreier   env_eeprom.c: Cor...
80
  	char buf_env[CONFIG_ENV_SIZE];
445f20fe7   Ye Li   MLK-22279-1 env: ...
81
  	unsigned int off = env_get_offset(CONFIG_ENV_OFFSET);
ea882baf9   Wolfgang Denk   New implementatio...
82

1567b596d   Heiko Schocher   env, eeprom: add ...
83
  #ifdef CONFIG_ENV_OFFSET_REDUND
dd2a233c9   Igor Grinberg   env: clean env_ee...
84
  	ulong len, crc[2], crc_tmp;
e3cc5bc58   Ludger Dreier   env_eeprom.c: Cor...
85
86
  	unsigned int off_env[2];
  	uchar rdbuf[64], flags[2];
dd2a233c9   Igor Grinberg   env: clean env_ee...
87
  	int i, crc_ok[2] = {0, 0};
1567b596d   Heiko Schocher   env, eeprom: add ...
88

354e3ed75   Marek Vasut   eeprom: Add bus a...
89
  	eeprom_init(-1);	/* prepare for EEPROM read/write */
1567b596d   Heiko Schocher   env, eeprom: add ...
90

445f20fe7   Ye Li   MLK-22279-1 env: ...
91
  	off_env[0] = env_get_offset(CONFIG_ENV_OFFSET);
1567b596d   Heiko Schocher   env, eeprom: add ...
92
93
94
95
  	off_env[1] = CONFIG_ENV_OFFSET_REDUND;
  
  	for (i = 0; i < 2; i++) {
  		/* read CRC */
ea882baf9   Wolfgang Denk   New implementatio...
96
  		eeprom_bus_read(CONFIG_SYS_DEF_EEPROM_ADDR,
dd2a233c9   Igor Grinberg   env: clean env_ee...
97
98
  				off_env[i] + offsetof(env_t, crc),
  				(uchar *)&crc[i], sizeof(ulong));
1567b596d   Heiko Schocher   env, eeprom: add ...
99
  		/* read FLAGS */
ea882baf9   Wolfgang Denk   New implementatio...
100
  		eeprom_bus_read(CONFIG_SYS_DEF_EEPROM_ADDR,
dd2a233c9   Igor Grinberg   env: clean env_ee...
101
102
  				off_env[i] + offsetof(env_t, flags),
  				(uchar *)&flags[i], sizeof(uchar));
1567b596d   Heiko Schocher   env, eeprom: add ...
103

ea882baf9   Wolfgang Denk   New implementatio...
104
  		crc_tmp = 0;
1567b596d   Heiko Schocher   env, eeprom: add ...
105
  		len = ENV_SIZE;
dd2a233c9   Igor Grinberg   env: clean env_ee...
106
  		off = off_env[i] + offsetof(env_t, data);
1567b596d   Heiko Schocher   env, eeprom: add ...
107
  		while (len > 0) {
e3cc5bc58   Ludger Dreier   env_eeprom.c: Cor...
108
  			int n = (len > sizeof(rdbuf)) ? sizeof(rdbuf) : len;
1567b596d   Heiko Schocher   env, eeprom: add ...
109

ea882baf9   Wolfgang Denk   New implementatio...
110
  			eeprom_bus_read(CONFIG_SYS_DEF_EEPROM_ADDR, off,
e3cc5bc58   Ludger Dreier   env_eeprom.c: Cor...
111
  					rdbuf, n);
1567b596d   Heiko Schocher   env, eeprom: add ...
112

e3cc5bc58   Ludger Dreier   env_eeprom.c: Cor...
113
  			crc_tmp = crc32(crc_tmp, rdbuf, n);
1567b596d   Heiko Schocher   env, eeprom: add ...
114
115
116
  			len -= n;
  			off += n;
  		}
dd2a233c9   Igor Grinberg   env: clean env_ee...
117

1567b596d   Heiko Schocher   env, eeprom: add ...
118
119
120
121
122
  		if (crc_tmp == crc[i])
  			crc_ok[i] = 1;
  	}
  
  	if (!crc_ok[0] && !crc_ok[1]) {
dd2a233c9   Igor Grinberg   env: clean env_ee...
123
  		gd->env_addr	= 0;
2d7cb5b42   Simon Glass   env: Replace all ...
124
  		gd->env_valid = ENV_INVALID;
1567b596d   Heiko Schocher   env, eeprom: add ...
125
  	} else if (crc_ok[0] && !crc_ok[1]) {
203e94f6c   Simon Glass   env: Add an enum ...
126
  		gd->env_valid = ENV_VALID;
dd2a233c9   Igor Grinberg   env: clean env_ee...
127
  	} else if (!crc_ok[0] && crc_ok[1]) {
203e94f6c   Simon Glass   env: Add an enum ...
128
  		gd->env_valid = ENV_REDUND;
1567b596d   Heiko Schocher   env, eeprom: add ...
129
130
  	} else {
  		/* both ok - check serial */
d3716dd64   Simon Glass   env: Rename the r...
131
132
  		if (flags[0] == ENV_REDUND_ACTIVE &&
  		    flags[1] == ENV_REDUND_OBSOLETE)
203e94f6c   Simon Glass   env: Add an enum ...
133
  			gd->env_valid = ENV_VALID;
d3716dd64   Simon Glass   env: Rename the r...
134
135
  		else if (flags[0] == ENV_REDUND_OBSOLETE &&
  			 flags[1] == ENV_REDUND_ACTIVE)
203e94f6c   Simon Glass   env: Add an enum ...
136
  			gd->env_valid = ENV_REDUND;
1567b596d   Heiko Schocher   env, eeprom: add ...
137
  		else if (flags[0] == 0xFF && flags[1] == 0)
203e94f6c   Simon Glass   env: Add an enum ...
138
  			gd->env_valid = ENV_REDUND;
dd2a233c9   Igor Grinberg   env: clean env_ee...
139
  		else if (flags[1] == 0xFF && flags[0] == 0)
203e94f6c   Simon Glass   env: Add an enum ...
140
  			gd->env_valid = ENV_VALID;
1567b596d   Heiko Schocher   env, eeprom: add ...
141
  		else /* flags are equal - almost impossible */
203e94f6c   Simon Glass   env: Add an enum ...
142
  			gd->env_valid = ENV_VALID;
1567b596d   Heiko Schocher   env, eeprom: add ...
143
  	}
e3cc5bc58   Ludger Dreier   env_eeprom.c: Cor...
144
  #else /* CONFIG_ENV_OFFSET_REDUND */
0bc4a1ac8   wdenk   Initial revision
145
  	ulong crc, len, new;
e3cc5bc58   Ludger Dreier   env_eeprom.c: Cor...
146
  	uchar rdbuf[64];
0bc4a1ac8   wdenk   Initial revision
147

354e3ed75   Marek Vasut   eeprom: Add bus a...
148
  	eeprom_init(-1);	/* prepare for EEPROM read/write */
0bc4a1ac8   wdenk   Initial revision
149
150
  
  	/* read old CRC */
ea882baf9   Wolfgang Denk   New implementatio...
151
  	eeprom_bus_read(CONFIG_SYS_DEF_EEPROM_ADDR,
445f20fe7   Ye Li   MLK-22279-1 env: ...
152
  			env_get_offset(CONFIG_ENV_OFFSET) + offsetof(env_t, crc),
dd2a233c9   Igor Grinberg   env: clean env_ee...
153
  			(uchar *)&crc, sizeof(ulong));
0bc4a1ac8   wdenk   Initial revision
154
155
156
  
  	new = 0;
  	len = ENV_SIZE;
dd2a233c9   Igor Grinberg   env: clean env_ee...
157
  	off = offsetof(env_t, data);
0bc4a1ac8   wdenk   Initial revision
158
  	while (len > 0) {
e3cc5bc58   Ludger Dreier   env_eeprom.c: Cor...
159
  		int n = (len > sizeof(rdbuf)) ? sizeof(rdbuf) : len;
0bc4a1ac8   wdenk   Initial revision
160

ea882baf9   Wolfgang Denk   New implementatio...
161
  		eeprom_bus_read(CONFIG_SYS_DEF_EEPROM_ADDR,
445f20fe7   Ye Li   MLK-22279-1 env: ...
162
  				env_get_offset(CONFIG_ENV_OFFSET) + off, rdbuf, n);
e3cc5bc58   Ludger Dreier   env_eeprom.c: Cor...
163
  		new = crc32(new, rdbuf, n);
0bc4a1ac8   wdenk   Initial revision
164
165
166
167
168
  		len -= n;
  		off += n;
  	}
  
  	if (crc == new) {
2d7cb5b42   Simon Glass   env: Replace all ...
169
  		gd->env_valid = ENV_VALID;
0bc4a1ac8   wdenk   Initial revision
170
  	} else {
2d7cb5b42   Simon Glass   env: Replace all ...
171
  		gd->env_valid = ENV_INVALID;
0bc4a1ac8   wdenk   Initial revision
172
  	}
e3cc5bc58   Ludger Dreier   env_eeprom.c: Cor...
173
  #endif /* CONFIG_ENV_OFFSET_REDUND */
445f20fe7   Ye Li   MLK-22279-1 env: ...
174
  	off = env_get_offset(CONFIG_ENV_OFFSET);
e3cc5bc58   Ludger Dreier   env_eeprom.c: Cor...
175
  #ifdef CONFIG_ENV_OFFSET_REDUND
203e94f6c   Simon Glass   env: Add an enum ...
176
  	if (gd->env_valid == ENV_REDUND)
e3cc5bc58   Ludger Dreier   env_eeprom.c: Cor...
177
178
179
180
181
  		off = CONFIG_ENV_OFFSET_REDUND;
  #endif
  
  	eeprom_bus_read(CONFIG_SYS_DEF_EEPROM_ADDR,
  		off, (uchar *)buf_env, CONFIG_ENV_SIZE);
2166ebf78   Simon Goldschmidt   env: make env dri...
182
  	return env_import(buf_env, 1);
e3cc5bc58   Ludger Dreier   env_eeprom.c: Cor...
183
  }
e5bce247b   Simon Glass   env: Switch over ...
184
  static int env_eeprom_save(void)
e3cc5bc58   Ludger Dreier   env_eeprom.c: Cor...
185
186
187
  {
  	env_t	env_new;
  	int	rc;
445f20fe7   Ye Li   MLK-22279-1 env: ...
188
  	unsigned int off	= env_get_offset(CONFIG_ENV_OFFSET);
e3cc5bc58   Ludger Dreier   env_eeprom.c: Cor...
189
190
  #ifdef CONFIG_ENV_OFFSET_REDUND
  	unsigned int off_red	= CONFIG_ENV_OFFSET_REDUND;
d3716dd64   Simon Glass   env: Rename the r...
191
  	char flag_obsolete	= ENV_REDUND_OBSOLETE;
e3cc5bc58   Ludger Dreier   env_eeprom.c: Cor...
192
  #endif
e3cc5bc58   Ludger Dreier   env_eeprom.c: Cor...
193
194
195
196
197
  	rc = env_export(&env_new);
  	if (rc)
  		return rc;
  
  #ifdef CONFIG_ENV_OFFSET_REDUND
203e94f6c   Simon Glass   env: Add an enum ...
198
  	if (gd->env_valid == ENV_VALID) {
e3cc5bc58   Ludger Dreier   env_eeprom.c: Cor...
199
  		off	= CONFIG_ENV_OFFSET_REDUND;
445f20fe7   Ye Li   MLK-22279-1 env: ...
200
  		off_red	= env_get_offset(CONFIG_ENV_OFFSET);
e3cc5bc58   Ludger Dreier   env_eeprom.c: Cor...
201
  	}
d3716dd64   Simon Glass   env: Rename the r...
202
  	env_new.flags = ENV_REDUND_ACTIVE;
e3cc5bc58   Ludger Dreier   env_eeprom.c: Cor...
203
204
205
206
207
208
209
210
211
212
  #endif
  
  	rc = eeprom_bus_write(CONFIG_SYS_DEF_EEPROM_ADDR,
  			      off, (uchar *)&env_new, CONFIG_ENV_SIZE);
  
  #ifdef CONFIG_ENV_OFFSET_REDUND
  	if (rc == 0) {
  		eeprom_bus_write(CONFIG_SYS_DEF_EEPROM_ADDR,
  				 off_red + offsetof(env_t, flags),
  				 (uchar *)&flag_obsolete, 1);
203e94f6c   Simon Glass   env: Add an enum ...
213
214
  		if (gd->env_valid == ENV_VALID)
  			gd->env_valid = ENV_REDUND;
e3cc5bc58   Ludger Dreier   env_eeprom.c: Cor...
215
  		else
203e94f6c   Simon Glass   env: Add an enum ...
216
  			gd->env_valid = ENV_VALID;
e3cc5bc58   Ludger Dreier   env_eeprom.c: Cor...
217
218
219
220
  	}
  #endif
  	return rc;
  }
4415f1d1f   Simon Glass   env: Create a loc...
221
222
  U_BOOT_ENV_LOCATION(eeprom) = {
  	.location	= ENVL_EEPROM,
ac358beb8   Simon Glass   env: Drop the env...
223
  	ENV_NAME("EEPROM")
e5bce247b   Simon Glass   env: Switch over ...
224
225
  	.load		= env_eeprom_load,
  	.save		= env_save_ptr(env_eeprom_save),
4415f1d1f   Simon Glass   env: Create a loc...
226
  };