/* * (C) Copyright 2013 * Corscience GmbH & Co. KG, * Andreas Bießmann * * SPDX-License-Identifier: GPL-2.0+ */ #include #include #include "tricorder-eeprom.h" static inline void warn_wrong_value(const char *msg, unsigned int a, unsigned int b) { printf("Expected EEPROM %s %08x, got %08x\n", msg, a, b); } static int handle_eeprom_v0(struct tricorder_eeprom *eeprom) { struct tricorder_eeprom_v0 { uint32_t magic; uint16_t length; uint16_t version; char board_name[TRICORDER_BOARD_NAME_LENGTH]; char board_version[TRICORDER_BOARD_VERSION_LENGTH]; char board_serial[TRICORDER_BOARD_SERIAL_LENGTH]; uint32_t crc32; } __packed eepromv0; uint32_t crc; printf("Old EEPROM (v0), consider rewrite!\n"); if (be16_to_cpu(eeprom->length) != sizeof(eepromv0)) { warn_wrong_value("length", sizeof(eepromv0), be16_to_cpu(eeprom->length)); return 1; } memcpy(&eepromv0, eeprom, sizeof(eepromv0)); crc = crc32(0L, (unsigned char *)&eepromv0, sizeof(eepromv0) - sizeof(eepromv0.crc32)); if (be32_to_cpu(eepromv0.crc32) != crc) { warn_wrong_value("CRC", be32_to_cpu(eepromv0.crc32), crc); return 1; } /* Ok the content is correct, do the conversion */ memset(eeprom->interface_version, 0x0, TRICORDER_INTERFACE_VERSION_LENGTH); crc = crc32(0L, (unsigned char *)eeprom, TRICORDER_EEPROM_CRC_SIZE); eeprom->crc32 = cpu_to_be32(crc); return 0; } static int handle_eeprom_v1(struct tricorder_eeprom *eeprom) { uint32_t crc; if (be16_to_cpu(eeprom->length) != TRICORDER_EEPROM_SIZE) { warn_wrong_value("length", TRICORDER_EEPROM_SIZE, be16_to_cpu(eeprom->length)); return 1; } crc = crc32(0L, (unsigned char *)eeprom, TRICORDER_EEPROM_CRC_SIZE); if (be32_to_cpu(eeprom->crc32) != crc) { warn_wrong_value("CRC", be32_to_cpu(eeprom->crc32), crc); return 1; } return 0; } int tricorder_get_eeprom(int addr, struct tricorder_eeprom *eeprom) { unsigned int bus = i2c_get_bus_num(); i2c_set_bus_num(CONFIG_SYS_EEPROM_BUS_NUM); memset(eeprom, 0, TRICORDER_EEPROM_SIZE); i2c_read(addr, 0, 2, (unsigned char *)eeprom, TRICORDER_EEPROM_SIZE); i2c_set_bus_num(bus); if (be32_to_cpu(eeprom->magic) != TRICORDER_EEPROM_MAGIC) { warn_wrong_value("magic", TRICORDER_EEPROM_MAGIC, be32_to_cpu(eeprom->magic)); return 1; } switch (be16_to_cpu(eeprom->version)) { case 0: return handle_eeprom_v0(eeprom); case 1: return handle_eeprom_v1(eeprom); default: warn_wrong_value("version", TRICORDER_EEPROM_VERSION, be16_to_cpu(eeprom->version)); return 1; } } #if !defined(CONFIG_SPL) int tricorder_eeprom_read(unsigned devaddr) { struct tricorder_eeprom eeprom; int ret = tricorder_get_eeprom(devaddr, &eeprom); if (ret) return ret; printf("Board type: %.*s\n", sizeof(eeprom.board_name), eeprom.board_name); printf("Board version: %.*s\n", sizeof(eeprom.board_version), eeprom.board_version); printf("Board serial: %.*s\n", sizeof(eeprom.board_serial), eeprom.board_serial); printf("Board interface version: %.*s\n", sizeof(eeprom.interface_version), eeprom.interface_version); return ret; } int tricorder_eeprom_write(unsigned devaddr, const char *name, const char *version, const char *serial, const char *interface) { struct tricorder_eeprom eeprom, eeprom_verify; size_t length; uint32_t crc; int ret; unsigned char *p; int i; memset(eeprom, 0, TRICORDER_EEPROM_SIZE); memset(eeprom_verify, 0, TRICORDER_EEPROM_SIZE); eeprom.magic = cpu_to_be32(TRICORDER_EEPROM_MAGIC); eeprom.length = cpu_to_be16(TRICORDER_EEPROM_SIZE); eeprom.version = cpu_to_be16(TRICORDER_EEPROM_VERSION); length = min(sizeof(eeprom.board_name), strlen(name)); strncpy(eeprom.board_name, name, length); length = min(sizeof(eeprom.board_version), strlen(version)); strncpy(eeprom.board_version, version, length); length = min(sizeof(eeprom.board_serial), strlen(serial)); strncpy(eeprom.board_serial, serial, length); if (interface) { length = min(sizeof(eeprom.interface_version), strlen(interface)); strncpy(eeprom.interface_version, interface, length); } crc = crc32(0L, (unsigned char *)&eeprom, TRICORDER_EEPROM_CRC_SIZE); eeprom.crc32 = cpu_to_be32(crc); #if defined(DEBUG) puts("Tricorder EEPROM content:\n"); print_buffer(0, &eeprom, 1, sizeof(eeprom), 16); #endif eeprom_init(CONFIG_SYS_EEPROM_BUS_NUM); ret = eeprom_write(devaddr, 0, (unsigned char *)&eeprom, TRICORDER_EEPROM_SIZE); if (ret) printf("Tricorder: Could not write EEPROM content!\n"); ret = eeprom_read(devaddr, 0, (unsigned char *)&eeprom_verify, TRICORDER_EEPROM_SIZE); if (ret) printf("Tricorder: Could not read EEPROM content!\n"); if (memcmp(&eeprom, &eeprom_verify, sizeof(eeprom)) != 0) { printf("Tricorder: Could not verify EEPROM content!\n"); ret = 1; } return ret; } int do_tricorder_eeprom(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) { if (argc == 3) { ulong dev_addr = simple_strtoul(argv[2], NULL, 16); if (strcmp(argv[1], "read") == 0) { int rcode; rcode = tricorder_eeprom_read(dev_addr); return rcode; } } else if (argc == 6 || argc == 7) { ulong dev_addr = simple_strtoul(argv[2], NULL, 16); char *name = argv[3]; char *version = argv[4]; char *serial = argv[5]; char *interface = NULL; if (argc == 7) interface = argv[6]; if (strcmp(argv[1], "write") == 0) { int rcode; rcode = tricorder_eeprom_write(dev_addr, name, version, serial, interface); return rcode; } } return CMD_RET_USAGE; } U_BOOT_CMD( tricordereeprom, 7, 1, do_tricorder_eeprom, "Tricorder EEPROM", "read devaddr\n" " - read Tricorder EEPROM at devaddr and print content\n" "tricordereeprom write devaddr name version serial [interface]\n" " - write Tricorder EEPROM at devaddr with 'name', 'version'" "and 'serial'\n" " optional add an HW interface parameter" ); #endif /* CONFIG_SPL */