tricorder: add tricordereeprom command
authorAndreas Bießmann <andreas.biessmann@corscience.de>
Fri, 6 Sep 2013 13:04:52 +0000 (15:04 +0200)
committerTom Rini <trini@ti.com>
Fri, 1 Nov 2013 19:55:58 +0000 (15:55 -0400)
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
board/corscience/tricorder/tricorder-eeprom.c [new file with mode: 0644]
board/corscience/tricorder/tricorder-eeprom.h [new file with mode: 0644]
include/configs/tricorder.h

index 2ab12bb9541ab44d67e4c971a47b6d851435e9c6..22ad8c510c9c745b9fcbe64a677e7d59ef951054 100644 (file)
@@ -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 (file)
index 0000000..1c74a0f
--- /dev/null
@@ -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 (file)
index 0000000..06ed9a5
--- /dev/null
@@ -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_ */
index ec900e59d315a18e32ba1ca411b684fd29dd24d0..a3d8f12f9765a1e79089a35a4bda4001160f1a03 100644 (file)
 #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