]> git.ipfire.org Git - people/ms/u-boot.git/blame - env/eeprom.c
Merge git://git.denx.de/u-boot-fsl-qoriq
[people/ms/u-boot.git] / env / eeprom.c
CommitLineData
0bc4a1ac 1/*
ea882baf 2 * (C) Copyright 2000-2010
0bc4a1ac
WD
3 * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
4 *
5 * (C) Copyright 2001 Sysgo Real-Time Solutions, GmbH <www.elinos.com>
6 * Andreas Heppel <aheppel@sysgo.de>
ea882baf 7 *
3765b3e7 8 * SPDX-License-Identifier: GPL-2.0+
0bc4a1ac
WD
9 */
10
11#include <common.h>
0bc4a1ac
WD
12#include <command.h>
13#include <environment.h>
0bc4a1ac 14#include <linux/stddef.h>
548738b4
HS
15#if defined(CONFIG_I2C_ENV_EEPROM_BUS)
16#include <i2c.h>
17#endif
ea882baf
WD
18#include <search.h>
19#include <errno.h>
20#include <linux/compiler.h> /* for BUG_ON */
0bc4a1ac 21
d87080b7
WD
22DECLARE_GLOBAL_DATA_PTR;
23
ea882baf 24static int eeprom_bus_read(unsigned dev_addr, unsigned offset,
dd2a233c 25 uchar *buffer, unsigned cnt)
548738b4
HS
26{
27 int rcode;
28#if defined(CONFIG_I2C_ENV_EEPROM_BUS)
29 int old_bus = i2c_get_bus_num();
30
3f4978c7
HS
31 if (old_bus != CONFIG_I2C_ENV_EEPROM_BUS)
32 i2c_set_bus_num(CONFIG_I2C_ENV_EEPROM_BUS);
548738b4
HS
33#endif
34
dd2a233c 35 rcode = eeprom_read(dev_addr, offset, buffer, cnt);
ea882baf 36
548738b4 37#if defined(CONFIG_I2C_ENV_EEPROM_BUS)
6d001e7d 38 i2c_set_bus_num(old_bus);
548738b4 39#endif
9a2accb4 40
548738b4
HS
41 return rcode;
42}
43
ea882baf 44static int eeprom_bus_write(unsigned dev_addr, unsigned offset,
dd2a233c 45 uchar *buffer, unsigned cnt)
548738b4
HS
46{
47 int rcode;
48#if defined(CONFIG_I2C_ENV_EEPROM_BUS)
49 int old_bus = i2c_get_bus_num();
50
3f4978c7
HS
51 if (old_bus != CONFIG_I2C_ENV_EEPROM_BUS)
52 i2c_set_bus_num(CONFIG_I2C_ENV_EEPROM_BUS);
548738b4 53#endif
9a2accb4 54
ea882baf 55 rcode = eeprom_write(dev_addr, offset, buffer, cnt);
9a2accb4 56
548738b4
HS
57#if defined(CONFIG_I2C_ENV_EEPROM_BUS)
58 i2c_set_bus_num(old_bus);
59#endif
6d001e7d 60
548738b4
HS
61 return rcode;
62}
0bc4a1ac 63
21f63944 64static int env_eeprom_get_char(int index)
0bc4a1ac
WD
65{
66 uchar c;
dd2a233c 67 unsigned int off = CONFIG_ENV_OFFSET;
ea882baf 68
1567b596 69#ifdef CONFIG_ENV_OFFSET_REDUND
203e94f6 70 if (gd->env_valid == ENV_REDUND)
1567b596
HS
71 off = CONFIG_ENV_OFFSET_REDUND;
72#endif
ea882baf 73 eeprom_bus_read(CONFIG_SYS_DEF_EEPROM_ADDR,
dd2a233c 74 off + index + offsetof(env_t, data), &c, 1);
0bc4a1ac 75
dd2a233c 76 return c;
0bc4a1ac
WD
77}
78
c5951991 79static int env_eeprom_load(void)
0bc4a1ac 80{
e3cc5bc5 81 char buf_env[CONFIG_ENV_SIZE];
1567b596 82 unsigned int off = CONFIG_ENV_OFFSET;
ea882baf 83
1567b596 84#ifdef CONFIG_ENV_OFFSET_REDUND
dd2a233c 85 ulong len, crc[2], crc_tmp;
e3cc5bc5
LD
86 unsigned int off_env[2];
87 uchar rdbuf[64], flags[2];
dd2a233c 88 int i, crc_ok[2] = {0, 0};
1567b596 89
354e3ed7 90 eeprom_init(-1); /* prepare for EEPROM read/write */
1567b596
HS
91
92 off_env[0] = CONFIG_ENV_OFFSET;
93 off_env[1] = CONFIG_ENV_OFFSET_REDUND;
94
95 for (i = 0; i < 2; i++) {
96 /* read CRC */
ea882baf 97 eeprom_bus_read(CONFIG_SYS_DEF_EEPROM_ADDR,
dd2a233c
IG
98 off_env[i] + offsetof(env_t, crc),
99 (uchar *)&crc[i], sizeof(ulong));
1567b596 100 /* read FLAGS */
ea882baf 101 eeprom_bus_read(CONFIG_SYS_DEF_EEPROM_ADDR,
dd2a233c
IG
102 off_env[i] + offsetof(env_t, flags),
103 (uchar *)&flags[i], sizeof(uchar));
1567b596 104
ea882baf 105 crc_tmp = 0;
1567b596 106 len = ENV_SIZE;
dd2a233c 107 off = off_env[i] + offsetof(env_t, data);
1567b596 108 while (len > 0) {
e3cc5bc5 109 int n = (len > sizeof(rdbuf)) ? sizeof(rdbuf) : len;
1567b596 110
ea882baf 111 eeprom_bus_read(CONFIG_SYS_DEF_EEPROM_ADDR, off,
e3cc5bc5 112 rdbuf, n);
1567b596 113
e3cc5bc5 114 crc_tmp = crc32(crc_tmp, rdbuf, n);
1567b596
HS
115 len -= n;
116 off += n;
117 }
dd2a233c 118
1567b596
HS
119 if (crc_tmp == crc[i])
120 crc_ok[i] = 1;
121 }
122
123 if (!crc_ok[0] && !crc_ok[1]) {
dd2a233c 124 gd->env_addr = 0;
2d7cb5b4 125 gd->env_valid = ENV_INVALID;
1567b596 126 } else if (crc_ok[0] && !crc_ok[1]) {
203e94f6 127 gd->env_valid = ENV_VALID;
dd2a233c 128 } else if (!crc_ok[0] && crc_ok[1]) {
203e94f6 129 gd->env_valid = ENV_REDUND;
1567b596
HS
130 } else {
131 /* both ok - check serial */
132 if (flags[0] == ACTIVE_FLAG && flags[1] == OBSOLETE_FLAG)
203e94f6 133 gd->env_valid = ENV_VALID;
1567b596 134 else if (flags[0] == OBSOLETE_FLAG && flags[1] == ACTIVE_FLAG)
203e94f6 135 gd->env_valid = ENV_REDUND;
1567b596 136 else if (flags[0] == 0xFF && flags[1] == 0)
203e94f6 137 gd->env_valid = ENV_REDUND;
dd2a233c 138 else if (flags[1] == 0xFF && flags[0] == 0)
203e94f6 139 gd->env_valid = ENV_VALID;
1567b596 140 else /* flags are equal - almost impossible */
203e94f6 141 gd->env_valid = ENV_VALID;
1567b596
HS
142 }
143
e3cc5bc5 144#else /* CONFIG_ENV_OFFSET_REDUND */
0bc4a1ac 145 ulong crc, len, new;
e3cc5bc5 146 uchar rdbuf[64];
0bc4a1ac 147
354e3ed7 148 eeprom_init(-1); /* prepare for EEPROM read/write */
0bc4a1ac
WD
149
150 /* read old CRC */
ea882baf 151 eeprom_bus_read(CONFIG_SYS_DEF_EEPROM_ADDR,
dd2a233c
IG
152 CONFIG_ENV_OFFSET + offsetof(env_t, crc),
153 (uchar *)&crc, sizeof(ulong));
0bc4a1ac
WD
154
155 new = 0;
156 len = ENV_SIZE;
dd2a233c 157 off = offsetof(env_t, data);
0bc4a1ac 158 while (len > 0) {
e3cc5bc5 159 int n = (len > sizeof(rdbuf)) ? sizeof(rdbuf) : len;
0bc4a1ac 160
ea882baf 161 eeprom_bus_read(CONFIG_SYS_DEF_EEPROM_ADDR,
e3cc5bc5
LD
162 CONFIG_ENV_OFFSET + off, rdbuf, n);
163 new = crc32(new, rdbuf, n);
0bc4a1ac
WD
164 len -= n;
165 off += n;
166 }
167
168 if (crc == new) {
2d7cb5b4 169 gd->env_valid = ENV_VALID;
0bc4a1ac 170 } else {
2d7cb5b4 171 gd->env_valid = ENV_INVALID;
0bc4a1ac 172 }
e3cc5bc5
LD
173#endif /* CONFIG_ENV_OFFSET_REDUND */
174
175 off = CONFIG_ENV_OFFSET;
176#ifdef CONFIG_ENV_OFFSET_REDUND
203e94f6 177 if (gd->env_valid == ENV_REDUND)
e3cc5bc5
LD
178 off = CONFIG_ENV_OFFSET_REDUND;
179#endif
180
181 eeprom_bus_read(CONFIG_SYS_DEF_EEPROM_ADDR,
182 off, (uchar *)buf_env, CONFIG_ENV_SIZE);
183
184 env_import(buf_env, 1);
c5951991
SG
185
186 return 0;
e3cc5bc5
LD
187}
188
e5bce247 189static int env_eeprom_save(void)
e3cc5bc5
LD
190{
191 env_t env_new;
192 int rc;
193 unsigned int off = CONFIG_ENV_OFFSET;
194#ifdef CONFIG_ENV_OFFSET_REDUND
195 unsigned int off_red = CONFIG_ENV_OFFSET_REDUND;
196 char flag_obsolete = OBSOLETE_FLAG;
197#endif
198
e3cc5bc5
LD
199 rc = env_export(&env_new);
200 if (rc)
201 return rc;
202
203#ifdef CONFIG_ENV_OFFSET_REDUND
203e94f6 204 if (gd->env_valid == ENV_VALID) {
e3cc5bc5
LD
205 off = CONFIG_ENV_OFFSET_REDUND;
206 off_red = CONFIG_ENV_OFFSET;
207 }
208
209 env_new.flags = ACTIVE_FLAG;
210#endif
211
212 rc = eeprom_bus_write(CONFIG_SYS_DEF_EEPROM_ADDR,
213 off, (uchar *)&env_new, CONFIG_ENV_SIZE);
214
215#ifdef CONFIG_ENV_OFFSET_REDUND
216 if (rc == 0) {
217 eeprom_bus_write(CONFIG_SYS_DEF_EEPROM_ADDR,
218 off_red + offsetof(env_t, flags),
219 (uchar *)&flag_obsolete, 1);
220
203e94f6
SG
221 if (gd->env_valid == ENV_VALID)
222 gd->env_valid = ENV_REDUND;
e3cc5bc5 223 else
203e94f6 224 gd->env_valid = ENV_VALID;
e3cc5bc5
LD
225 }
226#endif
227 return rc;
228}
229
4415f1d1
SG
230U_BOOT_ENV_LOCATION(eeprom) = {
231 .location = ENVL_EEPROM,
ac358beb 232 ENV_NAME("EEPROM")
e5bce247
SG
233 .get_char = env_eeprom_get_char,
234 .load = env_eeprom_load,
235 .save = env_save_ptr(env_eeprom_save),
4415f1d1 236};