Blame view

env/eeprom.c 5.3 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;
ea882baf9   Wolfgang Denk   New implementatio...
23
  static int eeprom_bus_read(unsigned dev_addr, unsigned offset,
dd2a233c9   Igor Grinberg   env: clean env_ee...
24
  			   uchar *buffer, unsigned cnt)
548738b4d   Heiko Schocher   cmd_eeprom: I2C u...
25
26
27
28
  {
  	int rcode;
  #if defined(CONFIG_I2C_ENV_EEPROM_BUS)
  	int old_bus = i2c_get_bus_num();
3f4978c71   Heiko Schocher   i2c: common chang...
29
30
  	if (old_bus != CONFIG_I2C_ENV_EEPROM_BUS)
  		i2c_set_bus_num(CONFIG_I2C_ENV_EEPROM_BUS);
548738b4d   Heiko Schocher   cmd_eeprom: I2C u...
31
  #endif
dd2a233c9   Igor Grinberg   env: clean env_ee...
32
  	rcode = eeprom_read(dev_addr, offset, buffer, cnt);
ea882baf9   Wolfgang Denk   New implementatio...
33

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

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

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

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

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

b2cdef486   Goldschmidt Simon   env: restore old ...
59
60
61
62
  /** 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
63
64
  {
  	uchar c;
dd2a233c9   Igor Grinberg   env: clean env_ee...
65
  	unsigned int off = CONFIG_ENV_OFFSET;
ea882baf9   Wolfgang Denk   New implementatio...
66

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

dd2a233c9   Igor Grinberg   env: clean env_ee...
74
  	return c;
0bc4a1ac8   wdenk   Initial revision
75
  }
c59519919   Simon Glass   env: Adjust the l...
76
  static int env_eeprom_load(void)
0bc4a1ac8   wdenk   Initial revision
77
  {
e3cc5bc58   Ludger Dreier   env_eeprom.c: Cor...
78
  	char buf_env[CONFIG_ENV_SIZE];
1567b596d   Heiko Schocher   env, eeprom: add ...
79
  	unsigned int off = CONFIG_ENV_OFFSET;
ea882baf9   Wolfgang Denk   New implementatio...
80

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

354e3ed75   Marek Vasut   eeprom: Add bus a...
87
  	eeprom_init(-1);	/* prepare for EEPROM read/write */
1567b596d   Heiko Schocher   env, eeprom: add ...
88
89
90
91
92
93
  
  	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...
94
  		eeprom_bus_read(CONFIG_SYS_DEF_EEPROM_ADDR,
dd2a233c9   Igor Grinberg   env: clean env_ee...
95
96
  				off_env[i] + offsetof(env_t, crc),
  				(uchar *)&crc[i], sizeof(ulong));
1567b596d   Heiko Schocher   env, eeprom: add ...
97
  		/* read FLAGS */
ea882baf9   Wolfgang Denk   New implementatio...
98
  		eeprom_bus_read(CONFIG_SYS_DEF_EEPROM_ADDR,
dd2a233c9   Igor Grinberg   env: clean env_ee...
99
100
  				off_env[i] + offsetof(env_t, flags),
  				(uchar *)&flags[i], sizeof(uchar));
1567b596d   Heiko Schocher   env, eeprom: add ...
101

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

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

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

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

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

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