Patchwork [U-Boot,07/13] tricorder: add tricordereeprom command

login
register
mail settings
Submitter Andreas Bießmann
Date Sept. 6, 2013, 1:04 p.m.
Message ID <1378472698-18557-7-git-send-email-andreas.devel@googlemail.com>
Download mbox | patch
Permalink /patch/273182/
State Accepted
Delegated to: Tom Rini
Headers show

Comments

Andreas Bießmann - Sept. 6, 2013, 1:04 p.m.
From: Andreas Bießmann <andreas.biessmann@corscience.de>

The new tricordereeprom command can read and write the eeprom for hardware
detection on tricorder devices.

Signed-off-by: Andreas Bießmann <andreas.biessmann@corscience.de>
---
 board/corscience/tricorder/Makefile           |    2 +-
 board/corscience/tricorder/tricorder-eeprom.c |  251 +++++++++++++++++++++++++
 board/corscience/tricorder/tricorder-eeprom.h |   41 ++++
 include/configs/tricorder.h                   |    7 +
 4 files changed, 300 insertions(+), 1 deletion(-)
 create mode 100644 board/corscience/tricorder/tricorder-eeprom.c
 create mode 100644 board/corscience/tricorder/tricorder-eeprom.h

Patch

diff --git a/board/corscience/tricorder/Makefile b/board/corscience/tricorder/Makefile
index 2ab12bb..22ad8c5 100644
--- a/board/corscience/tricorder/Makefile
+++ b/board/corscience/tricorder/Makefile
@@ -12,7 +12,7 @@  include $(TOPDIR)/config.mk
 
 LIB	= $(obj)lib$(BOARD).o
 
-COBJS	:= tricorder.o
+COBJS	:= tricorder.o tricorder-eeprom.o
 
 SRCS	:= $(COBJS:.o=.c)
 OBJS	:= $(addprefix $(obj),$(COBJS))
diff --git a/board/corscience/tricorder/tricorder-eeprom.c b/board/corscience/tricorder/tricorder-eeprom.c
new file mode 100644
index 0000000..1c74a0f
--- /dev/null
+++ b/board/corscience/tricorder/tricorder-eeprom.c
@@ -0,0 +1,251 @@ 
+/*
+ * (C) Copyright 2013
+ * Corscience GmbH & Co. KG, <www.corscience.de>
+ * Andreas Bießmann <andreas.biessmann@corscience.de>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+#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)
+{
+#ifdef CONFIG_SYS_EEPROM_BUS_NUM
+	unsigned int bus = i2c_get_bus_num();
+	i2c_set_bus_num(CONFIG_SYS_EEPROM_BUS_NUM);
+#endif
+
+	memset(eeprom, 0, TRICORDER_EEPROM_SIZE);
+
+	i2c_read(addr, 0, 2, (unsigned char *)eeprom, TRICORDER_EEPROM_SIZE);
+#ifdef CONFIG_SYS_EEPROM_BUS_NUM
+	i2c_set_bus_num(bus);
+#endif
+
+	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;
+#ifdef CONFIG_SYS_EEPROM_BUS_NUM
+	unsigned int bus;
+#endif
+
+	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
+
+#ifdef CONFIG_SYS_EEPROM_BUS_NUM
+	bus = i2c_get_bus_num();
+	i2c_set_bus_num(CONFIG_SYS_EEPROM_BUS_NUM);
+#endif
+
+	/* do page write to the eeprom */
+	for (i = 0, p = (unsigned char *)&eeprom;
+	     i < sizeof(eeprom);
+	     i += 32, p += 32) {
+		ret = i2c_write(devaddr, i, CONFIG_SYS_I2C_EEPROM_ADDR_LEN,
+				p, min(sizeof(eeprom) - i, 32));
+		if (ret)
+			break;
+		udelay(5000); /* 5ms write cycle timing */
+	}
+
+	ret = i2c_read(devaddr, 0, 2, (unsigned char *)&eeprom_verify,
+			TRICORDER_EEPROM_SIZE);
+
+	if (memcmp(&eeprom, &eeprom_verify, sizeof(eeprom)) != 0) {
+		printf("Tricorder: Could not verify EEPROM content!\n");
+		ret = 1;
+	}
+
+#ifdef CONFIG_SYS_EEPROM_BUS_NUM
+	i2c_set_bus_num(bus);
+#endif
+	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);
+		eeprom_init();
+		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;
+		eeprom_init();
+
+		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 */
diff --git a/board/corscience/tricorder/tricorder-eeprom.h b/board/corscience/tricorder/tricorder-eeprom.h
new file mode 100644
index 0000000..06ed9a5
--- /dev/null
+++ b/board/corscience/tricorder/tricorder-eeprom.h
@@ -0,0 +1,41 @@ 
+/*
+ * (C) Copyright 2013
+ * Corscience GmbH & Co. KG, <www.corscience.de>
+ * Andreas Bießmann <andreas.biessmann@corscience.de>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+#ifndef TRICORDER_EEPROM_H_
+#define TRICORDER_EEPROM_H_
+
+#include <linux/compiler.h>
+
+#define TRICORDER_EEPROM_MAGIC 0xc2a94f52
+#define TRICORDER_EEPROM_VERSION 1
+
+#define TRICORDER_BOARD_NAME_LENGTH		12
+#define TRICORDER_BOARD_VERSION_LENGTH		4
+#define TRICORDER_BOARD_SERIAL_LENGTH		12
+#define TRICORDER_INTERFACE_VERSION_LENGTH	4
+
+struct tricorder_eeprom {
+	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];
+	char interface_version[TRICORDER_INTERFACE_VERSION_LENGTH];
+	uint32_t crc32;
+} __packed;
+
+#define TRICORDER_EEPROM_SIZE		sizeof(struct tricorder_eeprom)
+#define TRICORDER_EEPROM_CRC_SIZE	(TRICORDER_EEPROM_SIZE - \
+					 sizeof(uint32_t))
+
+/**
+ * @brief read eeprom information from a specific eeprom address
+ */
+int tricorder_get_eeprom(int addr, struct tricorder_eeprom *eeprom);
+
+#endif /* TRICORDER_EEPROM_H_ */
diff --git a/include/configs/tricorder.h b/include/configs/tricorder.h
index abd5bb3..9e4e0f0 100644
--- a/include/configs/tricorder.h
+++ b/include/configs/tricorder.h
@@ -82,6 +82,13 @@ 
 #define CONFIG_SYS_I2C_SPEED		100000
 #define CONFIG_SYS_I2C_SLAVE		1
 #define CONFIG_DRIVER_OMAP34XX_I2C	1
+#define CONFIG_I2C_MULTI_BUS
+
+/* EEPROM */
+#define CONFIG_SYS_I2C_MULTI_EEPROMS
+#define CONFIG_CMD_EEPROM
+#define CONFIG_SYS_I2C_EEPROM_ADDR_LEN	2
+#define CONFIG_SYS_EEPROM_BUS_NUM	1
 
 /* TWL4030 */
 #define CONFIG_TWL4030_POWER