Blame view

env/eeprom.c 5.42 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
12
  #include <command.h>
  #include <environment.h>
0bc4a1ac8   wdenk   Initial revision
13
  #include <linux/stddef.h>
548738b4d   Heiko Schocher   cmd_eeprom: I2C u...
14
15
16
  #if defined(CONFIG_I2C_ENV_EEPROM_BUS)
  #include <i2c.h>
  #endif
ea882baf9   Wolfgang Denk   New implementatio...
17
18
19
  #include <search.h>
  #include <errno.h>
  #include <linux/compiler.h>	/* for BUG_ON */
0bc4a1ac8   wdenk   Initial revision
20

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

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

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

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

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

548738b4d   Heiko Schocher   cmd_eeprom: I2C u...
55
56
  	return rcode;
  }
0bc4a1ac8   wdenk   Initial revision
57

b2cdef486   Goldschmidt Simon   env: restore old ...
58
59
60
61
  /** 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
62
63
  {
  	uchar c;
565d9002a   Ye Li   MLK-22279-1 env: ...
64
  	unsigned int off = env_get_offset(CONFIG_ENV_OFFSET);
ea882baf9   Wolfgang Denk   New implementatio...
65

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

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

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

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

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

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

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

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

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

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

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