223 lines
		
	
	
		
			5.8 KiB
		
	
	
	
		
			C
		
	
	
	
			
		
		
	
	
			223 lines
		
	
	
		
			5.8 KiB
		
	
	
	
		
			C
		
	
	
	
| // SPDX-License-Identifier: GPL-2.0+
 | |
| /*
 | |
|  * (C) Copyright 2013
 | |
|  * Corscience GmbH & Co. KG, <www.corscience.de>
 | |
|  * Andreas Bießmann <andreas.biessmann@corscience.de>
 | |
|  */
 | |
| #include <common.h>
 | |
| #include <i2c.h>
 | |
| 
 | |
| #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)
 | |
| 			return tricorder_eeprom_read(dev_addr);
 | |
| 	} 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)
 | |
| 			return tricorder_eeprom_write(dev_addr, name, version,
 | |
| 						      serial, interface);
 | |
| 	}
 | |
| 
 | |
| 	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 */
 |