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