Home | History | Annotate | Download | only in tricorder
      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