[U-Boot] [PATCH v4 3/7] ARM: omap-common: Add standard access for board description EEPROM

Steve Kipisz s-kipisz2 at ti.com
Fri Nov 6 01:39:32 CET 2015


From: Lokesh Vutla <lokeshvutla at ti.com>

Several TI EVMs have EEPROM that can contain board description information
such as revision, DDR definition, serial number, etc. In just about all
cases, these EEPROM are on the I2C bus and provides us the opportunity
to centralize the generic operations involved.

The on-board EEPROM on the BeagleBone Black, BeagleBone, AM335x EVM,
AM43x GP EVM, AM57xx-evm, BeagleBoard-X15 share the same format.
However, DRA-7* EVMs, OMAP4SDP use a modified format.

We hence introduce logic which is generic between these platforms
without enforcing any specific format. This allows the boards to use the
relevant format for operations that they might choose.

This module will compile for all TI SoC based boards when I2C is enabled,
even non-TI boards that do not have the EEPROM. If the functions are not
used, they will not be linked in.

It is important to note that this logic is fundamental to the board
configuration process such as DDR configuration which is needed in
SPL, hence cannot be part of the standard u-boot driver model (which
is available later in the process). Hence, to aid efficiency, the
eeprom contents are copied over to SRAM scratchpad memory area at the
first invocation to retrieve data.

The follow on patches introduce the use of this library for AM335x,
AM437x, and AM57xx.

Signed-off-by: Lokesh Vutla <lokeshvutla at ti.com>
Signed-off-by: Steve Kipisz <s-kipisz2 at ti.com>
---
Changes in v4 (since v3):
 - Now depends on https://patchwork.ozlabs.org/patch/540280/
 - Started using __maybe_unused for compiler optimization for
   platforms that do not require it
 - Added a weak function for gpi2c_init
 - Merge board.c and ti-i2c-eeprom.c into one file board-detect.c
 - Rename board.h to board-detect.h
 - unexported functions are static
 - exported function documentation exists only in header
 - in case of 2 byte read fail, attempt 1 byte read (to keep am335x legacy
   platforms functional)

v3:  https://patchwork.ozlabs.org/patch/540197/

v2:  http://marc.info/?t=144655344800001&r=1&w=2
      (mailing list squashed original submission)

Changes in v2:
 - New patch

 arch/arm/include/asm/omap_common.h |   4 +-
 board/ti/common/Makefile           |   6 ++
 board/ti/common/board_detect.c     | 189 +++++++++++++++++++++++++++++++++++++
 board/ti/common/board_detect.h     | 117 +++++++++++++++++++++++
 4 files changed, 315 insertions(+), 1 deletion(-)
 create mode 100644 board/ti/common/Makefile
 create mode 100644 board/ti/common/board_detect.c
 create mode 100644 board/ti/common/board_detect.h

diff --git a/arch/arm/include/asm/omap_common.h b/arch/arm/include/asm/omap_common.h
index d773b0430ad4..aef31266ce9e 100644
--- a/arch/arm/include/asm/omap_common.h
+++ b/arch/arm/include/asm/omap_common.h
@@ -713,7 +713,9 @@ static inline u8 is_dra72x(void)
 #define OMAP_SRAM_SCRATCH_VCORES_PTR    (SRAM_SCRATCH_SPACE_ADDR + 0x1C)
 #define OMAP_SRAM_SCRATCH_SYS_CTRL	(SRAM_SCRATCH_SPACE_ADDR + 0x20)
 #define OMAP_SRAM_SCRATCH_BOOT_PARAMS	(SRAM_SCRATCH_SPACE_ADDR + 0x24)
-#define OMAP5_SRAM_SCRATCH_SPACE_END	(SRAM_SCRATCH_SPACE_ADDR + 0x28)
+#define OMAP_SRAM_SCRATCH_BOARD_EEPROM_START (SRAM_SCRATCH_SPACE_ADDR + 0x28)
+#define OMAP_SRAM_SCRATCH_BOARD_EEPROM_END (SRAM_SCRATCH_SPACE_ADDR + 0x200)
+#define OMAP_SRAM_SCRATCH_SPACE_END	(OMAP_SRAM_SCRATCH_BOARD_EEPROM_END)
 
 /* Boot parameters */
 #define DEVICE_DATA_OFFSET	0x18
diff --git a/board/ti/common/Makefile b/board/ti/common/Makefile
new file mode 100644
index 000000000000..267d73556fd3
--- /dev/null
+++ b/board/ti/common/Makefile
@@ -0,0 +1,6 @@
+# Copyright (C) 2015 Texas Instruments Incorporated - http://www.ti.com/
+#
+# SPDX-License-Identifier:	GPL-2.0+
+#
+
+obj-${CONFIG_I2C} += board_detect.o
diff --git a/board/ti/common/board_detect.c b/board/ti/common/board_detect.c
new file mode 100644
index 000000000000..3d2b1bb1465e
--- /dev/null
+++ b/board/ti/common/board_detect.c
@@ -0,0 +1,189 @@
+/*
+ * Library to support early TI EVM EEPROM handling
+ *
+ * Copyright (C) 2015 Texas Instruments Incorporated - http://www.ti.com/
+ *	Lokesh Vutla
+ *	Steve Kipisz
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+
+#include <common.h>
+#include <asm/omap_common.h>
+#include <i2c.h>
+
+#include "board_detect.h"
+
+/**
+ * ti_i2c_eeprom_init - Initialize an i2c bus and probe for a device
+ * @i2c_bus: i2c bus number to initialize
+ * @dev_addr: Device address to probe for
+ *
+ * Return: 0 on success or corresponding error on failure.
+ */
+static int __maybe_unused ti_i2c_eeprom_init(int i2c_bus, int dev_addr)
+{
+	int rc;
+
+	if (i2c_bus >= 0) {
+		rc = i2c_set_bus_num(i2c_bus);
+		if (rc)
+			return rc;
+	}
+
+	return i2c_probe(dev_addr);
+}
+
+/**
+ * ti_i2c_eeprom_read - Read data from an EEPROM
+ * @dev_addr: The device address of the EEPROM
+ * @offset: Offset to start reading in the EEPROM
+ * @ep: Pointer to a buffer to read into
+ * @epsize: Size of buffer
+ *
+ * Return: 0 on success or corresponding result of i2c_read
+ */
+static int __maybe_unused ti_i2c_eeprom_read(int dev_addr, int offset,
+					     uchar *ep, int epsize)
+{
+	return i2c_read(dev_addr, offset, 2, ep, epsize);
+}
+
+/**
+ * ti_eeprom_string_cleanup() - Handle eeprom programming errors
+ * @s:	eeprom string (should be NULL terminated)
+ *
+ * Some Board manufacturers do not add a NULL termination at the
+ * end of string, instead some binary information is kludged in, hence
+ * convert the string to just printable characters of ASCII chart.
+ */
+static void __maybe_unused ti_eeprom_string_cleanup(char *s)
+{
+	int i, l;
+
+	l = strlen(s);
+	for (i = 0; i < l; i++, s++)
+		if (*s < ' ' || *s > '~') {
+			*s = 0;
+			break;
+		}
+}
+
+__weak void gpi2c_init(void)
+{
+}
+
+int __maybe_unused ti_i2c_eeprom_am_get(int bus_addr, int dev_addr,
+					struct ti_am_eeprom **epp)
+{
+	int rc;
+	struct ti_am_eeprom *ep;
+
+	if (!epp)
+		return -1;
+
+	ep = TI_AM_EEPROM_DATA;
+	if (ep->header == TI_EEPROM_HEADER_MAGIC)
+		goto already_read;
+
+	/* Initialize with a known bad marker for i2c fails.. */
+	ep->header = 0xADEAD12C;
+
+	gpi2c_init();
+	rc = ti_i2c_eeprom_init(bus_addr, dev_addr);
+	if (rc)
+		return rc;
+	rc = i2c_read(dev_addr, 0x0, 2, (uint8_t *)ep, sizeof(*ep));
+	if (rc)
+		return rc;
+
+	/* Corrupted data??? */
+	if (ep->header != TI_EEPROM_HEADER_MAGIC) {
+		rc = i2c_read(dev_addr, 0x0, 2, (uint8_t *)ep, sizeof(*ep));
+		/*
+		 * read the eeprom using i2c again, but use only a 1 byte
+		 * address (some legacy boards need this..)
+		 */
+		if (rc)
+			rc = i2c_read(dev_addr, 0x0, 1, (uint8_t *)ep,
+				      sizeof(*ep));
+		if (rc)
+			return rc;
+	}
+	if (ep->header != TI_EEPROM_HEADER_MAGIC)
+		return -1;
+
+already_read:
+	*epp = ep;
+
+	return 0;
+}
+
+int __maybe_unused ti_i2c_eeprom_am_get_print(int bus_addr, int dev_addr,
+					      struct ti_am_eeprom_printable *p)
+{
+	struct ti_am_eeprom *ep;
+	int rc;
+
+	/* Incase of invalid eeprom contents */
+	p->name[0] = 0x00;
+	p->version[0] = 0x00;
+	p->serial[0] = 0x00;
+
+	rc = ti_i2c_eeprom_am_get(bus_addr, dev_addr, &ep);
+	if (rc)
+		return rc;
+
+	/*
+	 * Alas! we have to null terminate and cleanup the strings!
+	 */
+	strlcpy(p->name, ep->name, TI_EEPROM_HDR_NAME_LEN);
+	ti_eeprom_string_cleanup(p->name);
+	strlcpy(p->version, ep->version, TI_EEPROM_HDR_NAME_LEN);
+	ti_eeprom_string_cleanup(p->version);
+	strlcpy(p->serial, ep->serial, TI_EEPROM_HDR_NAME_LEN);
+	ti_eeprom_string_cleanup(p->serial);
+	return 0;
+}
+
+bool __maybe_unused board_am_is(char *name_tag)
+{
+	struct ti_am_eeprom *ep = TI_AM_EEPROM_DATA;
+
+	if (ep->header != TI_EEPROM_HEADER_MAGIC)
+		return false;
+	return !strncmp(ep->name, name_tag, TI_EEPROM_HDR_NAME_LEN);
+}
+
+bool __maybe_unused board_am_rev_is(char *rev_tag, int cmp_len)
+{
+	struct ti_am_eeprom *ep = TI_AM_EEPROM_DATA;
+	int l;
+
+	if (ep->header != TI_EEPROM_HEADER_MAGIC)
+		return false;
+
+	l = cmp_len > TI_EEPROM_HDR_REV_LEN ? TI_EEPROM_HDR_NAME_LEN : cmp_len;
+	return !strncmp(ep->version, rev_tag, l);
+}
+
+void __maybe_unused set_board_info_env(char *name, char *revision,
+				       char *serial)
+{
+	char *unknown = "unknown";
+
+	if (name)
+		setenv("board_name", name);
+	else
+		setenv("board_name", unknown);
+
+	if (revision)
+		setenv("board_rev", revision);
+	else
+		setenv("board_rev", unknown);
+
+	if (serial)
+		setenv("board_serial", serial);
+	else
+		setenv("board_serial", unknown);
+}
diff --git a/board/ti/common/board_detect.h b/board/ti/common/board_detect.h
new file mode 100644
index 000000000000..7d5478ae65a3
--- /dev/null
+++ b/board/ti/common/board_detect.h
@@ -0,0 +1,117 @@
+/*
+ * Library to support early TI EVM EEPROM handling
+ *
+ * Copyright (C) 2015, Texas Instruments, Incorporated - http://www.ti.com
+ *
+ * SPDX-L	icense-Identifier:	GPL-2.0+
+ */
+
+#ifndef __BOARD_DETECT_H
+#define __BOARD_DETECT_H
+
+/* TI EEPROM MAGIC Header identifier */
+#define TI_EEPROM_HEADER_MAGIC	0xEE3355AA
+
+#define TI_EEPROM_HDR_NAME_LEN		8
+#define TI_EEPROM_HDR_REV_LEN		12
+#define TI_EEPROM_HDR_SERIAL_LEN	4
+#define TI_EEPROM_HDR_CONFIG_LEN	32
+#define TI_EEPROM_HDR_NO_OF_MAC_ADDR	3
+#define TI_EEPROM_HDR_ETH_ALEN		6
+
+/**
+ * struct ti_am_eeprom - This structure holds data read in from the
+ *                     AM335x, AM437x, AM57xx TI EVM EEPROMs.
+ * @header: This holds the magic number
+ * @name: The name of the board
+ * @version: Board revision
+ * @serial: Board serial number
+ * @config: Reserved
+ * @mac_addr: Any MAC addresses written in the EEPROM
+ *
+ * The data is this structure is read from the EEPROM on the board.
+ * It is used for board detection which is based on name. It is used
+ * to configure specific TI boards. This allows booting of multiple
+ * TI boards with a single MLO and u-boot.
+ */
+struct ti_am_eeprom {
+	unsigned int header;
+	char name[TI_EEPROM_HDR_NAME_LEN];
+	char version[TI_EEPROM_HDR_REV_LEN];
+	char serial[TI_EEPROM_HDR_SERIAL_LEN];
+	char config[TI_EEPROM_HDR_CONFIG_LEN];
+	char mac_addr[TI_EEPROM_HDR_NO_OF_MAC_ADDR][TI_EEPROM_HDR_ETH_ALEN];
+} __attribute__ ((__packed__));
+
+/**
+ * struct ti_am_eeprom_printable - Null terminated, printable EEPROM contents
+ * @name:	NULL terminated name
+ * @version:	NULL terminated version
+ * @serial:	NULL terminated serial number
+ */
+struct ti_am_eeprom_printable {
+	char name[TI_EEPROM_HDR_NAME_LEN + 1];
+	char version[TI_EEPROM_HDR_REV_LEN + 1];
+	char serial[TI_EEPROM_HDR_SERIAL_LEN + 1];
+};
+#define TI_AM_EEPROM_DATA ((struct ti_am_eeprom *)\
+				OMAP_SRAM_SCRATCH_BOARD_EEPROM_START)
+
+/**
+ * ti_i2c_eeprom_am_get() - Consolidated eeprom data collection for AM* TI EVMs
+ * @bus_addr:	I2C bus address
+ * @dev_addr:	I2C slave address
+ * @epp:	Pointer to eeprom structure
+ *
+ * *epp is populated by the this AM generic function that consolidates
+ * the basic initialization logic common accross all AM* platforms.
+ */
+int ti_i2c_eeprom_am_get(int bus_addr, int dev_addr, struct ti_am_eeprom **epp);
+
+/**
+ * ti_i2c_eeprom_am_get_print() - Get a printable representation of eeprom data
+ * @bus_addr:	I2C bus address
+ * @dev_addr:	I2C slave address
+ * @p:		Pointer to eeprom structure
+ *
+ * This reads the eeprom and converts the data into a printable string for
+ * further processing for AM* platforms.
+ */
+int ti_i2c_eeprom_am_get_print(int bus_addr, int dev_addr,
+			       struct ti_am_eeprom_printable *p);
+
+
+/**
+ * board_am_is() - Board detection logic for TI AM* EVMs
+ * @name_tag:	Tag used in eeprom for the board
+ *
+ * Return: false if board information does not match OR eeprom wasn't read.
+ *	   true otherwise
+ */
+bool board_am_is(char *name_tag);
+
+/**
+ * board_am_rev_is() - Compare board revision for AM* TI EVMs
+ * @rev_tag:	Revision tag to check in eeprom
+ * @cmp_len:	How many chars to compare?
+ *
+ * NOTE: revision information is often messed up (hence the str len match) :(
+ *
+ * Return: false if board information does not match OR eeprom was'nt read.
+ *	   true otherwise
+ */
+bool board_am_rev_is(char *rev_tag, int cmp_len);
+
+/**
+ * set_board_info_env() - Setup commonly used board information environment vars
+ * @name:	Name of the board
+ * @revision:	Revision of the board
+ * @serial:	Serial Number of the board
+ *
+ * In case of NULL revision or serial information "unknown" is setup.
+ * If name is NULL, default_name is used.
+ */
+void set_board_info_env(char *name, char *revision,
+			char *serial);
+
+#endif	/* __BOARD_DETECT_H */
-- 
1.9.1



More information about the U-Boot mailing list