1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3 * (C) Copyright 2013
4 * Corscience GmbH & Co. KG, <www.corscience.de>
5 * Andreas Bießmann <andreas.biessmann@corscience.de>
6 */
7 #include <common.h>
8 #include <eeprom.h>
9 #include <i2c.h>
10
11 #include "tricorder-eeprom.h"
12
warn_wrong_value(const char * msg,unsigned int a,unsigned int b)13 static inline void warn_wrong_value(const char *msg, unsigned int a,
14 unsigned int b)
15 {
16 printf("Expected EEPROM %s %08x, got %08x\n", msg, a, b);
17 }
18
handle_eeprom_v0(struct tricorder_eeprom * eeprom)19 static int handle_eeprom_v0(struct tricorder_eeprom *eeprom)
20 {
21 struct tricorder_eeprom_v0 {
22 uint32_t magic;
23 uint16_t length;
24 uint16_t version;
25 char board_name[TRICORDER_BOARD_NAME_LENGTH];
26 char board_version[TRICORDER_BOARD_VERSION_LENGTH];
27 char board_serial[TRICORDER_BOARD_SERIAL_LENGTH];
28 uint32_t crc32;
29 } __packed eepromv0;
30 uint32_t crc;
31
32 printf("Old EEPROM (v0), consider rewrite!\n");
33
34 if (be16_to_cpu(eeprom->length) != sizeof(eepromv0)) {
35 warn_wrong_value("length", sizeof(eepromv0),
36 be16_to_cpu(eeprom->length));
37 return 1;
38 }
39
40 memcpy(&eepromv0, eeprom, sizeof(eepromv0));
41
42 crc = crc32(0L, (unsigned char *)&eepromv0,
43 sizeof(eepromv0) - sizeof(eepromv0.crc32));
44 if (be32_to_cpu(eepromv0.crc32) != crc) {
45 warn_wrong_value("CRC", be32_to_cpu(eepromv0.crc32),
46 crc);
47 return 1;
48 }
49
50 /* Ok the content is correct, do the conversion */
51 memset(eeprom->interface_version, 0x0,
52 TRICORDER_INTERFACE_VERSION_LENGTH);
53 crc = crc32(0L, (unsigned char *)eeprom, TRICORDER_EEPROM_CRC_SIZE);
54 eeprom->crc32 = cpu_to_be32(crc);
55
56 return 0;
57 }
58
handle_eeprom_v1(struct tricorder_eeprom * eeprom)59 static int handle_eeprom_v1(struct tricorder_eeprom *eeprom)
60 {
61 uint32_t crc;
62
63 if (be16_to_cpu(eeprom->length) != TRICORDER_EEPROM_SIZE) {
64 warn_wrong_value("length", TRICORDER_EEPROM_SIZE,
65 be16_to_cpu(eeprom->length));
66 return 1;
67 }
68
69 crc = crc32(0L, (unsigned char *)eeprom, TRICORDER_EEPROM_CRC_SIZE);
70 if (be32_to_cpu(eeprom->crc32) != crc) {
71 warn_wrong_value("CRC", be32_to_cpu(eeprom->crc32), crc);
72 return 1;
73 }
74
75 return 0;
76 }
77
tricorder_get_eeprom(int addr,struct tricorder_eeprom * eeprom)78 int tricorder_get_eeprom(int addr, struct tricorder_eeprom *eeprom)
79 {
80 unsigned int bus = i2c_get_bus_num();
81 i2c_set_bus_num(CONFIG_SYS_EEPROM_BUS_NUM);
82
83 memset(eeprom, 0, TRICORDER_EEPROM_SIZE);
84
85 i2c_read(addr, 0, 2, (unsigned char *)eeprom, TRICORDER_EEPROM_SIZE);
86 i2c_set_bus_num(bus);
87
88 if (be32_to_cpu(eeprom->magic) != TRICORDER_EEPROM_MAGIC) {
89 warn_wrong_value("magic", TRICORDER_EEPROM_MAGIC,
90 be32_to_cpu(eeprom->magic));
91 return 1;
92 }
93
94 switch (be16_to_cpu(eeprom->version)) {
95 case 0:
96 return handle_eeprom_v0(eeprom);
97 case 1:
98 return handle_eeprom_v1(eeprom);
99 default:
100 warn_wrong_value("version", TRICORDER_EEPROM_VERSION,
101 be16_to_cpu(eeprom->version));
102 return 1;
103 }
104 }
105
106 #if !defined(CONFIG_SPL)
tricorder_eeprom_read(unsigned devaddr)107 int tricorder_eeprom_read(unsigned devaddr)
108 {
109 struct tricorder_eeprom eeprom;
110 int ret = tricorder_get_eeprom(devaddr, &eeprom);
111
112 if (ret)
113 return ret;
114
115 printf("Board type: %.*s\n",
116 sizeof(eeprom.board_name), eeprom.board_name);
117 printf("Board version: %.*s\n",
118 sizeof(eeprom.board_version), eeprom.board_version);
119 printf("Board serial: %.*s\n",
120 sizeof(eeprom.board_serial), eeprom.board_serial);
121 printf("Board interface version: %.*s\n",
122 sizeof(eeprom.interface_version),
123 eeprom.interface_version);
124
125 return ret;
126 }
127
tricorder_eeprom_write(unsigned devaddr,const char * name,const char * version,const char * serial,const char * interface)128 int tricorder_eeprom_write(unsigned devaddr, const char *name,
129 const char *version, const char *serial, const char *interface)
130 {
131 struct tricorder_eeprom eeprom, eeprom_verify;
132 size_t length;
133 uint32_t crc;
134 int ret;
135 unsigned char *p;
136 int i;
137
138 memset(eeprom, 0, TRICORDER_EEPROM_SIZE);
139 memset(eeprom_verify, 0, TRICORDER_EEPROM_SIZE);
140
141 eeprom.magic = cpu_to_be32(TRICORDER_EEPROM_MAGIC);
142 eeprom.length = cpu_to_be16(TRICORDER_EEPROM_SIZE);
143 eeprom.version = cpu_to_be16(TRICORDER_EEPROM_VERSION);
144
145 length = min(sizeof(eeprom.board_name), strlen(name));
146 strncpy(eeprom.board_name, name, length);
147
148 length = min(sizeof(eeprom.board_version), strlen(version));
149 strncpy(eeprom.board_version, version, length);
150
151 length = min(sizeof(eeprom.board_serial), strlen(serial));
152 strncpy(eeprom.board_serial, serial, length);
153
154 if (interface) {
155 length = min(sizeof(eeprom.interface_version),
156 strlen(interface));
157 strncpy(eeprom.interface_version, interface, length);
158 }
159
160 crc = crc32(0L, (unsigned char *)&eeprom, TRICORDER_EEPROM_CRC_SIZE);
161 eeprom.crc32 = cpu_to_be32(crc);
162
163 #if defined(DEBUG)
164 puts("Tricorder EEPROM content:\n");
165 print_buffer(0, &eeprom, 1, sizeof(eeprom), 16);
166 #endif
167
168 eeprom_init(CONFIG_SYS_EEPROM_BUS_NUM);
169
170 ret = eeprom_write(devaddr, 0, (unsigned char *)&eeprom,
171 TRICORDER_EEPROM_SIZE);
172 if (ret)
173 printf("Tricorder: Could not write EEPROM content!\n");
174
175 ret = eeprom_read(devaddr, 0, (unsigned char *)&eeprom_verify,
176 TRICORDER_EEPROM_SIZE);
177 if (ret)
178 printf("Tricorder: Could not read EEPROM content!\n");
179
180 if (memcmp(&eeprom, &eeprom_verify, sizeof(eeprom)) != 0) {
181 printf("Tricorder: Could not verify EEPROM content!\n");
182 ret = 1;
183 }
184
185 return ret;
186 }
187
do_tricorder_eeprom(cmd_tbl_t * cmdtp,int flag,int argc,char * argv[])188 int do_tricorder_eeprom(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
189 {
190 if (argc == 3) {
191 ulong dev_addr = simple_strtoul(argv[2], NULL, 16);
192
193 if (strcmp(argv[1], "read") == 0)
194 return tricorder_eeprom_read(dev_addr);
195 } else if (argc == 6 || argc == 7) {
196 ulong dev_addr = simple_strtoul(argv[2], NULL, 16);
197 char *name = argv[3];
198 char *version = argv[4];
199 char *serial = argv[5];
200 char *interface = NULL;
201
202 if (argc == 7)
203 interface = argv[6];
204
205 if (strcmp(argv[1], "write") == 0)
206 return tricorder_eeprom_write(dev_addr, name, version,
207 serial, interface);
208 }
209
210 return CMD_RET_USAGE;
211 }
212
213 U_BOOT_CMD(
214 tricordereeprom, 7, 1, do_tricorder_eeprom,
215 "Tricorder EEPROM",
216 "read devaddr\n"
217 " - read Tricorder EEPROM at devaddr and print content\n"
218 "tricordereeprom write devaddr name version serial [interface]\n"
219 " - write Tricorder EEPROM at devaddr with 'name', 'version'"
220 "and 'serial'\n"
221 " optional add an HW interface parameter"
222 );
223 #endif /* CONFIG_SPL */
224