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 */ 252