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