1459f1da8SAndreas Bießmann /*
2459f1da8SAndreas Bießmann * (C) Copyright 2013
3459f1da8SAndreas Bießmann * Corscience GmbH & Co. KG, <www.corscience.de>
4459f1da8SAndreas Bießmann * Andreas Bießmann <andreas.biessmann@corscience.de>
5459f1da8SAndreas Bießmann *
6459f1da8SAndreas Bießmann * SPDX-License-Identifier: GPL-2.0+
7459f1da8SAndreas Bießmann */
8459f1da8SAndreas Bießmann #include <common.h>
9459f1da8SAndreas Bießmann #include <i2c.h>
10459f1da8SAndreas Bießmann
11459f1da8SAndreas Bießmann #include "tricorder-eeprom.h"
12459f1da8SAndreas Bießmann
warn_wrong_value(const char * msg,unsigned int a,unsigned int b)13459f1da8SAndreas Bießmann static inline void warn_wrong_value(const char *msg, unsigned int a,
14459f1da8SAndreas Bießmann unsigned int b)
15459f1da8SAndreas Bießmann {
16459f1da8SAndreas Bießmann printf("Expected EEPROM %s %08x, got %08x\n", msg, a, b);
17459f1da8SAndreas Bießmann }
18459f1da8SAndreas Bießmann
handle_eeprom_v0(struct tricorder_eeprom * eeprom)19459f1da8SAndreas Bießmann static int handle_eeprom_v0(struct tricorder_eeprom *eeprom)
20459f1da8SAndreas Bießmann {
21459f1da8SAndreas Bießmann struct tricorder_eeprom_v0 {
22459f1da8SAndreas Bießmann uint32_t magic;
23459f1da8SAndreas Bießmann uint16_t length;
24459f1da8SAndreas Bießmann uint16_t version;
25459f1da8SAndreas Bießmann char board_name[TRICORDER_BOARD_NAME_LENGTH];
26459f1da8SAndreas Bießmann char board_version[TRICORDER_BOARD_VERSION_LENGTH];
27459f1da8SAndreas Bießmann char board_serial[TRICORDER_BOARD_SERIAL_LENGTH];
28459f1da8SAndreas Bießmann uint32_t crc32;
29459f1da8SAndreas Bießmann } __packed eepromv0;
30459f1da8SAndreas Bießmann uint32_t crc;
31459f1da8SAndreas Bießmann
32459f1da8SAndreas Bießmann printf("Old EEPROM (v0), consider rewrite!\n");
33459f1da8SAndreas Bießmann
34459f1da8SAndreas Bießmann if (be16_to_cpu(eeprom->length) != sizeof(eepromv0)) {
35459f1da8SAndreas Bießmann warn_wrong_value("length", sizeof(eepromv0),
36459f1da8SAndreas Bießmann be16_to_cpu(eeprom->length));
37459f1da8SAndreas Bießmann return 1;
38459f1da8SAndreas Bießmann }
39459f1da8SAndreas Bießmann
40459f1da8SAndreas Bießmann memcpy(&eepromv0, eeprom, sizeof(eepromv0));
41459f1da8SAndreas Bießmann
42459f1da8SAndreas Bießmann crc = crc32(0L, (unsigned char *)&eepromv0,
43459f1da8SAndreas Bießmann sizeof(eepromv0) - sizeof(eepromv0.crc32));
44459f1da8SAndreas Bießmann if (be32_to_cpu(eepromv0.crc32) != crc) {
45459f1da8SAndreas Bießmann warn_wrong_value("CRC", be32_to_cpu(eepromv0.crc32),
46459f1da8SAndreas Bießmann crc);
47459f1da8SAndreas Bießmann return 1;
48459f1da8SAndreas Bießmann }
49459f1da8SAndreas Bießmann
50459f1da8SAndreas Bießmann /* Ok the content is correct, do the conversion */
51459f1da8SAndreas Bießmann memset(eeprom->interface_version, 0x0,
52459f1da8SAndreas Bießmann TRICORDER_INTERFACE_VERSION_LENGTH);
53459f1da8SAndreas Bießmann crc = crc32(0L, (unsigned char *)eeprom, TRICORDER_EEPROM_CRC_SIZE);
54459f1da8SAndreas Bießmann eeprom->crc32 = cpu_to_be32(crc);
55459f1da8SAndreas Bießmann
56459f1da8SAndreas Bießmann return 0;
57459f1da8SAndreas Bießmann }
58459f1da8SAndreas Bießmann
handle_eeprom_v1(struct tricorder_eeprom * eeprom)59459f1da8SAndreas Bießmann static int handle_eeprom_v1(struct tricorder_eeprom *eeprom)
60459f1da8SAndreas Bießmann {
61459f1da8SAndreas Bießmann uint32_t crc;
62459f1da8SAndreas Bießmann
63459f1da8SAndreas Bießmann if (be16_to_cpu(eeprom->length) != TRICORDER_EEPROM_SIZE) {
64459f1da8SAndreas Bießmann warn_wrong_value("length", TRICORDER_EEPROM_SIZE,
65459f1da8SAndreas Bießmann be16_to_cpu(eeprom->length));
66459f1da8SAndreas Bießmann return 1;
67459f1da8SAndreas Bießmann }
68459f1da8SAndreas Bießmann
69459f1da8SAndreas Bießmann crc = crc32(0L, (unsigned char *)eeprom, TRICORDER_EEPROM_CRC_SIZE);
70459f1da8SAndreas Bießmann if (be32_to_cpu(eeprom->crc32) != crc) {
71459f1da8SAndreas Bießmann warn_wrong_value("CRC", be32_to_cpu(eeprom->crc32), crc);
72459f1da8SAndreas Bießmann return 1;
73459f1da8SAndreas Bießmann }
74459f1da8SAndreas Bießmann
75459f1da8SAndreas Bießmann return 0;
76459f1da8SAndreas Bießmann }
77459f1da8SAndreas Bießmann
tricorder_get_eeprom(int addr,struct tricorder_eeprom * eeprom)78459f1da8SAndreas Bießmann int tricorder_get_eeprom(int addr, struct tricorder_eeprom *eeprom)
79459f1da8SAndreas Bießmann {
80459f1da8SAndreas Bießmann unsigned int bus = i2c_get_bus_num();
81459f1da8SAndreas Bießmann i2c_set_bus_num(CONFIG_SYS_EEPROM_BUS_NUM);
82459f1da8SAndreas Bießmann
83459f1da8SAndreas Bießmann memset(eeprom, 0, TRICORDER_EEPROM_SIZE);
84459f1da8SAndreas Bießmann
85459f1da8SAndreas Bießmann i2c_read(addr, 0, 2, (unsigned char *)eeprom, TRICORDER_EEPROM_SIZE);
86459f1da8SAndreas Bießmann i2c_set_bus_num(bus);
87459f1da8SAndreas Bießmann
88459f1da8SAndreas Bießmann if (be32_to_cpu(eeprom->magic) != TRICORDER_EEPROM_MAGIC) {
89459f1da8SAndreas Bießmann warn_wrong_value("magic", TRICORDER_EEPROM_MAGIC,
90459f1da8SAndreas Bießmann be32_to_cpu(eeprom->magic));
91459f1da8SAndreas Bießmann return 1;
92459f1da8SAndreas Bießmann }
93459f1da8SAndreas Bießmann
94459f1da8SAndreas Bießmann switch (be16_to_cpu(eeprom->version)) {
95459f1da8SAndreas Bießmann case 0:
96459f1da8SAndreas Bießmann return handle_eeprom_v0(eeprom);
97459f1da8SAndreas Bießmann case 1:
98459f1da8SAndreas Bießmann return handle_eeprom_v1(eeprom);
99459f1da8SAndreas Bießmann default:
100459f1da8SAndreas Bießmann warn_wrong_value("version", TRICORDER_EEPROM_VERSION,
101459f1da8SAndreas Bießmann be16_to_cpu(eeprom->version));
102459f1da8SAndreas Bießmann return 1;
103459f1da8SAndreas Bießmann }
104459f1da8SAndreas Bießmann }
105459f1da8SAndreas Bießmann
106459f1da8SAndreas Bießmann #if !defined(CONFIG_SPL)
tricorder_eeprom_read(unsigned devaddr)107459f1da8SAndreas Bießmann int tricorder_eeprom_read(unsigned devaddr)
108459f1da8SAndreas Bießmann {
109459f1da8SAndreas Bießmann struct tricorder_eeprom eeprom;
110459f1da8SAndreas Bießmann int ret = tricorder_get_eeprom(devaddr, &eeprom);
111459f1da8SAndreas Bießmann
112459f1da8SAndreas Bießmann if (ret)
113459f1da8SAndreas Bießmann return ret;
114459f1da8SAndreas Bießmann
115459f1da8SAndreas Bießmann printf("Board type: %.*s\n",
116459f1da8SAndreas Bießmann sizeof(eeprom.board_name), eeprom.board_name);
117459f1da8SAndreas Bießmann printf("Board version: %.*s\n",
118459f1da8SAndreas Bießmann sizeof(eeprom.board_version), eeprom.board_version);
119459f1da8SAndreas Bießmann printf("Board serial: %.*s\n",
120459f1da8SAndreas Bießmann sizeof(eeprom.board_serial), eeprom.board_serial);
121459f1da8SAndreas Bießmann printf("Board interface version: %.*s\n",
122459f1da8SAndreas Bießmann sizeof(eeprom.interface_version),
123459f1da8SAndreas Bießmann eeprom.interface_version);
124459f1da8SAndreas Bießmann
125459f1da8SAndreas Bießmann return ret;
126459f1da8SAndreas Bießmann }
127459f1da8SAndreas Bießmann
tricorder_eeprom_write(unsigned devaddr,const char * name,const char * version,const char * serial,const char * interface)128459f1da8SAndreas Bießmann int tricorder_eeprom_write(unsigned devaddr, const char *name,
129459f1da8SAndreas Bießmann const char *version, const char *serial, const char *interface)
130459f1da8SAndreas Bießmann {
131459f1da8SAndreas Bießmann struct tricorder_eeprom eeprom, eeprom_verify;
132459f1da8SAndreas Bießmann size_t length;
133459f1da8SAndreas Bießmann uint32_t crc;
134459f1da8SAndreas Bießmann int ret;
135459f1da8SAndreas Bießmann unsigned char *p;
136459f1da8SAndreas Bießmann int i;
137459f1da8SAndreas Bießmann
138459f1da8SAndreas Bießmann memset(eeprom, 0, TRICORDER_EEPROM_SIZE);
139459f1da8SAndreas Bießmann memset(eeprom_verify, 0, TRICORDER_EEPROM_SIZE);
140459f1da8SAndreas Bießmann
141459f1da8SAndreas Bießmann eeprom.magic = cpu_to_be32(TRICORDER_EEPROM_MAGIC);
142459f1da8SAndreas Bießmann eeprom.length = cpu_to_be16(TRICORDER_EEPROM_SIZE);
143459f1da8SAndreas Bießmann eeprom.version = cpu_to_be16(TRICORDER_EEPROM_VERSION);
144459f1da8SAndreas Bießmann
145459f1da8SAndreas Bießmann length = min(sizeof(eeprom.board_name), strlen(name));
146459f1da8SAndreas Bießmann strncpy(eeprom.board_name, name, length);
147459f1da8SAndreas Bießmann
148459f1da8SAndreas Bießmann length = min(sizeof(eeprom.board_version), strlen(version));
149459f1da8SAndreas Bießmann strncpy(eeprom.board_version, version, length);
150459f1da8SAndreas Bießmann
151459f1da8SAndreas Bießmann length = min(sizeof(eeprom.board_serial), strlen(serial));
152459f1da8SAndreas Bießmann strncpy(eeprom.board_serial, serial, length);
153459f1da8SAndreas Bießmann
154459f1da8SAndreas Bießmann if (interface) {
155459f1da8SAndreas Bießmann length = min(sizeof(eeprom.interface_version),
156459f1da8SAndreas Bießmann strlen(interface));
157459f1da8SAndreas Bießmann strncpy(eeprom.interface_version, interface, length);
158459f1da8SAndreas Bießmann }
159459f1da8SAndreas Bießmann
160459f1da8SAndreas Bießmann crc = crc32(0L, (unsigned char *)&eeprom, TRICORDER_EEPROM_CRC_SIZE);
161459f1da8SAndreas Bießmann eeprom.crc32 = cpu_to_be32(crc);
162459f1da8SAndreas Bießmann
163459f1da8SAndreas Bießmann #if defined(DEBUG)
164459f1da8SAndreas Bießmann puts("Tricorder EEPROM content:\n");
165459f1da8SAndreas Bießmann print_buffer(0, &eeprom, 1, sizeof(eeprom), 16);
166459f1da8SAndreas Bießmann #endif
167459f1da8SAndreas Bießmann
1688961dac9SAndreas Bießmann eeprom_init(CONFIG_SYS_EEPROM_BUS_NUM);
169459f1da8SAndreas Bießmann
1708961dac9SAndreas Bießmann ret = eeprom_write(devaddr, 0, (unsigned char *)&eeprom,
171459f1da8SAndreas Bießmann TRICORDER_EEPROM_SIZE);
1728961dac9SAndreas Bießmann if (ret)
1738961dac9SAndreas Bießmann printf("Tricorder: Could not write EEPROM content!\n");
1748961dac9SAndreas Bießmann
1758961dac9SAndreas Bießmann ret = eeprom_read(devaddr, 0, (unsigned char *)&eeprom_verify,
1768961dac9SAndreas Bießmann TRICORDER_EEPROM_SIZE);
1778961dac9SAndreas Bießmann if (ret)
1788961dac9SAndreas Bießmann printf("Tricorder: Could not read EEPROM content!\n");
179459f1da8SAndreas Bießmann
180459f1da8SAndreas Bießmann if (memcmp(&eeprom, &eeprom_verify, sizeof(eeprom)) != 0) {
181459f1da8SAndreas Bießmann printf("Tricorder: Could not verify EEPROM content!\n");
182459f1da8SAndreas Bießmann ret = 1;
183459f1da8SAndreas Bießmann }
184459f1da8SAndreas Bießmann
185459f1da8SAndreas Bießmann return ret;
186459f1da8SAndreas Bießmann }
187459f1da8SAndreas Bießmann
do_tricorder_eeprom(cmd_tbl_t * cmdtp,int flag,int argc,char * argv[])188459f1da8SAndreas Bießmann int do_tricorder_eeprom(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
189459f1da8SAndreas Bießmann {
190459f1da8SAndreas Bießmann if (argc == 3) {
191459f1da8SAndreas Bießmann ulong dev_addr = simple_strtoul(argv[2], NULL, 16);
1928961dac9SAndreas Bießmann
193*63a7578eSMasahiro Yamada if (strcmp(argv[1], "read") == 0)
194*63a7578eSMasahiro Yamada return tricorder_eeprom_read(dev_addr);
195459f1da8SAndreas Bießmann } else if (argc == 6 || argc == 7) {
196459f1da8SAndreas Bießmann ulong dev_addr = simple_strtoul(argv[2], NULL, 16);
197459f1da8SAndreas Bießmann char *name = argv[3];
198459f1da8SAndreas Bießmann char *version = argv[4];
199459f1da8SAndreas Bießmann char *serial = argv[5];
200459f1da8SAndreas Bießmann char *interface = NULL;
201459f1da8SAndreas Bießmann
202459f1da8SAndreas Bießmann if (argc == 7)
203459f1da8SAndreas Bießmann interface = argv[6];
204459f1da8SAndreas Bießmann
205*63a7578eSMasahiro Yamada if (strcmp(argv[1], "write") == 0)
206*63a7578eSMasahiro Yamada return tricorder_eeprom_write(dev_addr, name, version,
207459f1da8SAndreas Bießmann serial, interface);
208459f1da8SAndreas Bießmann }
209459f1da8SAndreas Bießmann
210459f1da8SAndreas Bießmann return CMD_RET_USAGE;
211459f1da8SAndreas Bießmann }
212459f1da8SAndreas Bießmann
213459f1da8SAndreas Bießmann U_BOOT_CMD(
214459f1da8SAndreas Bießmann tricordereeprom, 7, 1, do_tricorder_eeprom,
215459f1da8SAndreas Bießmann "Tricorder EEPROM",
216459f1da8SAndreas Bießmann "read devaddr\n"
217459f1da8SAndreas Bießmann " - read Tricorder EEPROM at devaddr and print content\n"
218459f1da8SAndreas Bießmann "tricordereeprom write devaddr name version serial [interface]\n"
219459f1da8SAndreas Bießmann " - write Tricorder EEPROM at devaddr with 'name', 'version'"
220459f1da8SAndreas Bießmann "and 'serial'\n"
221459f1da8SAndreas Bießmann " optional add an HW interface parameter"
222459f1da8SAndreas Bießmann );
223459f1da8SAndreas Bießmann #endif /* CONFIG_SPL */
224