tricorder: add tricordereeprom command
[karo-tx-uboot.git] / board / corscience / tricorder / tricorder-eeprom.c
1 /*
2  * (C) Copyright 2013
3  * Corscience GmbH & Co. KG, <www.corscience.de>
4  * Andreas BieƟmann <andreas.biessmann@corscience.de>
5  *
6  * SPDX-License-Identifier:     GPL-2.0+
7  */
8 #include <common.h>
9 #include <i2c.h>
10
11 #include "tricorder-eeprom.h"
12
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
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
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
78 int tricorder_get_eeprom(int addr, struct tricorder_eeprom *eeprom)
79 {
80 #ifdef CONFIG_SYS_EEPROM_BUS_NUM
81         unsigned int bus = i2c_get_bus_num();
82         i2c_set_bus_num(CONFIG_SYS_EEPROM_BUS_NUM);
83 #endif
84
85         memset(eeprom, 0, TRICORDER_EEPROM_SIZE);
86
87         i2c_read(addr, 0, 2, (unsigned char *)eeprom, TRICORDER_EEPROM_SIZE);
88 #ifdef CONFIG_SYS_EEPROM_BUS_NUM
89         i2c_set_bus_num(bus);
90 #endif
91
92         if (be32_to_cpu(eeprom->magic) != TRICORDER_EEPROM_MAGIC) {
93                 warn_wrong_value("magic", TRICORDER_EEPROM_MAGIC,
94                                  be32_to_cpu(eeprom->magic));
95                 return 1;
96         }
97
98         switch (be16_to_cpu(eeprom->version)) {
99         case 0:
100                 return handle_eeprom_v0(eeprom);
101         case 1:
102                 return handle_eeprom_v1(eeprom);
103         default:
104                 warn_wrong_value("version", TRICORDER_EEPROM_VERSION,
105                                  be16_to_cpu(eeprom->version));
106                 return 1;
107         }
108 }
109
110 #if !defined(CONFIG_SPL)
111 int tricorder_eeprom_read(unsigned devaddr)
112 {
113         struct tricorder_eeprom eeprom;
114         int ret = tricorder_get_eeprom(devaddr, &eeprom);
115
116         if (ret)
117                 return ret;
118
119         printf("Board type:               %.*s\n",
120                sizeof(eeprom.board_name), eeprom.board_name);
121         printf("Board version:            %.*s\n",
122                sizeof(eeprom.board_version), eeprom.board_version);
123         printf("Board serial:             %.*s\n",
124                sizeof(eeprom.board_serial), eeprom.board_serial);
125         printf("Board interface version:  %.*s\n",
126                sizeof(eeprom.interface_version),
127                eeprom.interface_version);
128
129         return ret;
130 }
131
132 int tricorder_eeprom_write(unsigned devaddr, const char *name,
133                 const char *version, const char *serial, const char *interface)
134 {
135         struct tricorder_eeprom eeprom, eeprom_verify;
136         size_t length;
137         uint32_t crc;
138         int ret;
139         unsigned char *p;
140         int i;
141 #ifdef CONFIG_SYS_EEPROM_BUS_NUM
142         unsigned int bus;
143 #endif
144
145         memset(eeprom, 0, TRICORDER_EEPROM_SIZE);
146         memset(eeprom_verify, 0, TRICORDER_EEPROM_SIZE);
147
148         eeprom.magic = cpu_to_be32(TRICORDER_EEPROM_MAGIC);
149         eeprom.length = cpu_to_be16(TRICORDER_EEPROM_SIZE);
150         eeprom.version = cpu_to_be16(TRICORDER_EEPROM_VERSION);
151
152         length = min(sizeof(eeprom.board_name), strlen(name));
153         strncpy(eeprom.board_name, name, length);
154
155         length = min(sizeof(eeprom.board_version), strlen(version));
156         strncpy(eeprom.board_version, version, length);
157
158         length = min(sizeof(eeprom.board_serial), strlen(serial));
159         strncpy(eeprom.board_serial, serial, length);
160
161         if (interface) {
162                 length = min(sizeof(eeprom.interface_version),
163                                 strlen(interface));
164                 strncpy(eeprom.interface_version, interface, length);
165         }
166
167         crc = crc32(0L, (unsigned char *)&eeprom, TRICORDER_EEPROM_CRC_SIZE);
168         eeprom.crc32 = cpu_to_be32(crc);
169
170 #if defined(DEBUG)
171         puts("Tricorder EEPROM content:\n");
172         print_buffer(0, &eeprom, 1, sizeof(eeprom), 16);
173 #endif
174
175 #ifdef CONFIG_SYS_EEPROM_BUS_NUM
176         bus = i2c_get_bus_num();
177         i2c_set_bus_num(CONFIG_SYS_EEPROM_BUS_NUM);
178 #endif
179
180         /* do page write to the eeprom */
181         for (i = 0, p = (unsigned char *)&eeprom;
182              i < sizeof(eeprom);
183              i += 32, p += 32) {
184                 ret = i2c_write(devaddr, i, CONFIG_SYS_I2C_EEPROM_ADDR_LEN,
185                                 p, min(sizeof(eeprom) - i, 32));
186                 if (ret)
187                         break;
188                 udelay(5000); /* 5ms write cycle timing */
189         }
190
191         ret = i2c_read(devaddr, 0, 2, (unsigned char *)&eeprom_verify,
192                         TRICORDER_EEPROM_SIZE);
193
194         if (memcmp(&eeprom, &eeprom_verify, sizeof(eeprom)) != 0) {
195                 printf("Tricorder: Could not verify EEPROM content!\n");
196                 ret = 1;
197         }
198
199 #ifdef CONFIG_SYS_EEPROM_BUS_NUM
200         i2c_set_bus_num(bus);
201 #endif
202         return ret;
203 }
204
205 int do_tricorder_eeprom(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
206 {
207         if (argc == 3) {
208                 ulong dev_addr = simple_strtoul(argv[2], NULL, 16);
209                 eeprom_init();
210                 if (strcmp(argv[1], "read") == 0) {
211                         int rcode;
212
213                         rcode = tricorder_eeprom_read(dev_addr);
214
215                         return rcode;
216                 }
217         } else if (argc == 6 || argc == 7) {
218                 ulong dev_addr = simple_strtoul(argv[2], NULL, 16);
219                 char *name = argv[3];
220                 char *version = argv[4];
221                 char *serial = argv[5];
222                 char *interface = NULL;
223                 eeprom_init();
224
225                 if (argc == 7)
226                         interface = argv[6];
227
228                 if (strcmp(argv[1], "write") == 0) {
229                         int rcode;
230
231                         rcode = tricorder_eeprom_write(dev_addr, name, version,
232                                         serial, interface);
233
234                         return rcode;
235                 }
236         }
237
238         return CMD_RET_USAGE;
239 }
240
241 U_BOOT_CMD(
242         tricordereeprom,        7,      1,      do_tricorder_eeprom,
243         "Tricorder EEPROM",
244         "read  devaddr\n"
245         "       - read Tricorder EEPROM at devaddr and print content\n"
246         "tricordereeprom write devaddr name version serial [interface]\n"
247         "       - write Tricorder EEPROM at devaddr with 'name', 'version'"
248         "and 'serial'\n"
249         "         optional add an HW interface parameter"
250 );
251 #endif /* CONFIG_SPL */