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 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) 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 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 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