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