mail archive of the barebox mailing list
 help / color / mirror / Atom feed
* [PATCH 0/4] RDU1 config blob loading
@ 2018-11-05 18:32 Andrey Smirnov
  2018-11-05 18:32 ` [PATCH 1/4] lib: Port CRC8 implementation from Linux kernel Andrey Smirnov
                   ` (4 more replies)
  0 siblings, 5 replies; 6+ messages in thread
From: Andrey Smirnov @ 2018-11-05 18:32 UTC (permalink / raw)
  To: barebox; +Cc: Andrey Smirnov

Everyone:

This is a small series adding patches necessary to load config blob on
RDU1 boards, which, among other things, contains MAC address to be
used for FEC. Hopefully all of the commits are self-explanatory.

Feedback is welcome!

Thanks,
Andrey Smirnov

Andrey Smirnov (4):
  lib: Port CRC8 implementation from Linux kernel
  nvmem: Port Linux driver for Microwire 93XX46 EEPROM chips
  ARM: rdu1: Add an alias for Microwire EEPROM
  ARM: rdu1: Implement RDU1 config loading

 arch/arm/boards/zii-imx51-rdu1/board.c | 179 ++++++++++
 arch/arm/dts/imx51-zii-rdu1.dts        |  12 +
 arch/arm/mach-imx/Kconfig              |   1 +
 drivers/nvmem/Kconfig                  |   8 +
 drivers/nvmem/Makefile                 |   5 +-
 drivers/nvmem/eeprom_93xx46.c          | 446 +++++++++++++++++++++++++
 include/linux/crc8.h                   | 101 ++++++
 lib/Kconfig                            |   7 +
 lib/Makefile                           |   1 +
 lib/crc8.c                             |  82 +++++
 10 files changed, 841 insertions(+), 1 deletion(-)
 create mode 100644 drivers/nvmem/eeprom_93xx46.c
 create mode 100644 include/linux/crc8.h
 create mode 100644 lib/crc8.c

-- 
2.19.1


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 6+ messages in thread

* [PATCH 1/4] lib: Port CRC8 implementation from Linux kernel
  2018-11-05 18:32 [PATCH 0/4] RDU1 config blob loading Andrey Smirnov
@ 2018-11-05 18:32 ` Andrey Smirnov
  2018-11-05 18:32 ` [PATCH 2/4] nvmem: Port Linux driver for Microwire 93XX46 EEPROM chips Andrey Smirnov
                   ` (3 subsequent siblings)
  4 siblings, 0 replies; 6+ messages in thread
From: Andrey Smirnov @ 2018-11-05 18:32 UTC (permalink / raw)
  To: barebox; +Cc: Andrey Smirnov

Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com>
---
 include/linux/crc8.h | 101 +++++++++++++++++++++++++++++++++++++++++++
 lib/Kconfig          |   7 +++
 lib/Makefile         |   1 +
 lib/crc8.c           |  82 +++++++++++++++++++++++++++++++++++
 4 files changed, 191 insertions(+)
 create mode 100644 include/linux/crc8.h
 create mode 100644 lib/crc8.c

diff --git a/include/linux/crc8.h b/include/linux/crc8.h
new file mode 100644
index 000000000..13c8dabb0
--- /dev/null
+++ b/include/linux/crc8.h
@@ -0,0 +1,101 @@
+/*
+ * Copyright (c) 2011 Broadcom Corporation
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+#ifndef __CRC8_H_
+#define __CRC8_H_
+
+#include <linux/types.h>
+
+/* see usage of this value in crc8() description */
+#define CRC8_INIT_VALUE		0xFF
+
+/*
+ * Return value of crc8() indicating valid message+crc. This is true
+ * if a CRC is inverted before transmission. The CRC computed over the
+ * whole received bitstream is _table[x], where x is the bit pattern
+ * of the modification (almost always 0xff).
+ */
+#define CRC8_GOOD_VALUE(_table)	(_table[0xFF])
+
+/* required table size for crc8 algorithm */
+#define CRC8_TABLE_SIZE			256
+
+/* helper macro assuring right table size is used */
+#define DECLARE_CRC8_TABLE(_table) \
+	static u8 _table[CRC8_TABLE_SIZE]
+
+/**
+ * crc8_populate_lsb - fill crc table for given polynomial in regular bit order.
+ *
+ * @table:	table to be filled.
+ * @polynomial:	polynomial for which table is to be filled.
+ *
+ * This function fills the provided table according the polynomial provided for
+ * regular bit order (lsb first). Polynomials in CRC algorithms are typically
+ * represented as shown below.
+ *
+ *	poly = x^8 + x^7 + x^6 + x^4 + x^2 + 1
+ *
+ * For lsb first direction x^7 maps to the lsb. So the polynomial is as below.
+ *
+ * - lsb first: poly = 10101011(1) = 0xAB
+ */
+void crc8_populate_lsb(u8 table[CRC8_TABLE_SIZE], u8 polynomial);
+
+/**
+ * crc8_populate_msb - fill crc table for given polynomial in reverse bit order.
+ *
+ * @table:	table to be filled.
+ * @polynomial:	polynomial for which table is to be filled.
+ *
+ * This function fills the provided table according the polynomial provided for
+ * reverse bit order (msb first). Polynomials in CRC algorithms are typically
+ * represented as shown below.
+ *
+ *	poly = x^8 + x^7 + x^6 + x^4 + x^2 + 1
+ *
+ * For msb first direction x^7 maps to the msb. So the polynomial is as below.
+ *
+ * - msb first: poly = (1)11010101 = 0xD5
+ */
+void crc8_populate_msb(u8 table[CRC8_TABLE_SIZE], u8 polynomial);
+
+/**
+ * crc8() - calculate a crc8 over the given input data.
+ *
+ * @table:	crc table used for calculation.
+ * @pdata:	pointer to data buffer.
+ * @nbytes:	number of bytes in data buffer.
+ * @crc:	previous returned crc8 value.
+ *
+ * The CRC8 is calculated using the polynomial given in crc8_populate_msb()
+ * or crc8_populate_lsb().
+ *
+ * The caller provides the initial value (either %CRC8_INIT_VALUE
+ * or the previous returned value) to allow for processing of
+ * discontiguous blocks of data.  When generating the CRC the
+ * caller is responsible for complementing the final return value
+ * and inserting it into the byte stream.  When validating a byte
+ * stream (including CRC8), a final return value of %CRC8_GOOD_VALUE
+ * indicates the byte stream data can be considered valid.
+ *
+ * Reference:
+ * "A Painless Guide to CRC Error Detection Algorithms", ver 3, Aug 1993
+ * Williams, Ross N., ross<at>ross.net
+ * (see URL http://www.ross.net/crc/download/crc_v3.txt).
+ */
+u8 crc8(const u8 table[CRC8_TABLE_SIZE], u8 *pdata, size_t nbytes, u8 crc);
+
+#endif /* __CRC8_H_ */
diff --git a/lib/Kconfig b/lib/Kconfig
index 860d471de..67680adbb 100644
--- a/lib/Kconfig
+++ b/lib/Kconfig
@@ -118,6 +118,13 @@ config CRC_CCITT
 	  the kernel tree does. Such modules that use library CRC-CCITT
 	  functions require M here.
 
+config CRC8
+        bool "CRC8 function"
+	help
+	  This option provides CRC8 function. Drivers may select this
+	  when they need to do cyclic redundancy check according CRC8
+	  algorithm. Module will be called crc8.
+
 source lib/gui/Kconfig
 
 source lib/fonts/Kconfig
diff --git a/lib/Makefile b/lib/Makefile
index 24dc3d9ee..8ece2c284 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -66,6 +66,7 @@ obj-y			+= int_sqrt.o
 obj-y			+= parseopt.o
 obj-y			+= clz_ctz.o
 obj-$(CONFIG_CRC_CCITT) += crc-ccitt.o
+obj-$(CONFIG_CRC8)	+= crc8.o
 
 # GCC library routines
 obj-$(CONFIG_GENERIC_LIB_ASHLDI3) += ashldi3.o
diff --git a/lib/crc8.c b/lib/crc8.c
new file mode 100644
index 000000000..a89160bde
--- /dev/null
+++ b/lib/crc8.c
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2011 Broadcom Corporation
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+#include <module.h>
+#include <linux/crc8.h>
+
+/**
+ * crc8_populate_msb - fill crc table for given polynomial in reverse bit order.
+ *
+ * @table:	table to be filled.
+ * @polynomial:	polynomial for which table is to be filled.
+ */
+void crc8_populate_msb(u8 table[CRC8_TABLE_SIZE], u8 polynomial)
+{
+	int i, j;
+	const u8 msbit = 0x80;
+	u8 t = msbit;
+
+	table[0] = 0;
+
+	for (i = 1; i < CRC8_TABLE_SIZE; i *= 2) {
+		t = (t << 1) ^ (t & msbit ? polynomial : 0);
+		for (j = 0; j < i; j++)
+			table[i+j] = table[j] ^ t;
+	}
+}
+EXPORT_SYMBOL(crc8_populate_msb);
+
+/**
+ * crc8_populate_lsb - fill crc table for given polynomial in regular bit order.
+ *
+ * @table:	table to be filled.
+ * @polynomial:	polynomial for which table is to be filled.
+ */
+void crc8_populate_lsb(u8 table[CRC8_TABLE_SIZE], u8 polynomial)
+{
+	int i, j;
+	u8 t = 1;
+
+	table[0] = 0;
+
+	for (i = (CRC8_TABLE_SIZE >> 1); i; i >>= 1) {
+		t = (t >> 1) ^ (t & 1 ? polynomial : 0);
+		for (j = 0; j < CRC8_TABLE_SIZE; j += 2*i)
+			table[i+j] = table[j] ^ t;
+	}
+}
+EXPORT_SYMBOL(crc8_populate_lsb);
+
+/**
+ * crc8 - calculate a crc8 over the given input data.
+ *
+ * @table: crc table used for calculation.
+ * @pdata: pointer to data buffer.
+ * @nbytes: number of bytes in data buffer.
+ * @crc: previous returned crc8 value.
+ */
+u8 crc8(const u8 table[CRC8_TABLE_SIZE], u8 *pdata, size_t nbytes, u8 crc)
+{
+	/* loop over the buffer data */
+	while (nbytes-- > 0)
+		crc = table[(crc ^ *pdata++) & 0xff];
+
+	return crc;
+}
+EXPORT_SYMBOL(crc8);
+
+MODULE_DESCRIPTION("CRC8 (by Williams, Ross N.) function");
+MODULE_AUTHOR("Broadcom Corporation");
+MODULE_LICENSE("Dual BSD/GPL");
-- 
2.19.1


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 6+ messages in thread

* [PATCH 2/4] nvmem: Port Linux driver for Microwire 93XX46 EEPROM chips
  2018-11-05 18:32 [PATCH 0/4] RDU1 config blob loading Andrey Smirnov
  2018-11-05 18:32 ` [PATCH 1/4] lib: Port CRC8 implementation from Linux kernel Andrey Smirnov
@ 2018-11-05 18:32 ` Andrey Smirnov
  2018-11-05 18:32 ` [PATCH 3/4] ARM: rdu1: Add an alias for Microwire EEPROM Andrey Smirnov
                   ` (2 subsequent siblings)
  4 siblings, 0 replies; 6+ messages in thread
From: Andrey Smirnov @ 2018-11-05 18:32 UTC (permalink / raw)
  To: barebox; +Cc: Andrey Smirnov

Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com>
---
 drivers/nvmem/Kconfig         |   8 +
 drivers/nvmem/Makefile        |   5 +-
 drivers/nvmem/eeprom_93xx46.c | 446 ++++++++++++++++++++++++++++++++++
 3 files changed, 458 insertions(+), 1 deletion(-)
 create mode 100644 drivers/nvmem/eeprom_93xx46.c

diff --git a/drivers/nvmem/Kconfig b/drivers/nvmem/Kconfig
index 38b6f4241..c28a6d4e4 100644
--- a/drivers/nvmem/Kconfig
+++ b/drivers/nvmem/Kconfig
@@ -43,4 +43,12 @@ config RAVE_SP_EEPROM
 	help
 	  Say y here to enable Rave SP EEPROM support.
 
+config EEPROM_93XX46
+	bool "Microwire EEPROM 93XX46 support"
+	depends on SPI
+	help
+	  Driver for the microwire EEPROM chipsets 93xx46x. The driver
+	  supports both read and write commands and also the command to
+	  erase the whole EEPROM.
+
 endif
diff --git a/drivers/nvmem/Makefile b/drivers/nvmem/Makefile
index 716e5dbe8..abf9dae42 100644
--- a/drivers/nvmem/Makefile
+++ b/drivers/nvmem/Makefile
@@ -13,4 +13,7 @@ obj-$(CONFIG_IMX_OCOTP)		+= nvmem_ocotp.o
 nvmem_ocotp-y			:= ocotp.o
 
 obj-$(CONFIG_RAVE_SP_EEPROM)	+= nvmem-rave-sp-eeprom.o
-nvmem-rave-sp-eeprom-y		:= rave-sp-eeprom.o
\ No newline at end of file
+nvmem-rave-sp-eeprom-y		:= rave-sp-eeprom.o
+
+obj-$(CONFIG_EEPROM_93XX46)	+= nvmem_eeprom_93xx46.o
+nvmem_eeprom_93xx46-y		:= eeprom_93xx46.o
\ No newline at end of file
diff --git a/drivers/nvmem/eeprom_93xx46.c b/drivers/nvmem/eeprom_93xx46.c
new file mode 100644
index 000000000..d96ba32d0
--- /dev/null
+++ b/drivers/nvmem/eeprom_93xx46.c
@@ -0,0 +1,446 @@
+/*
+ * Driver for 93xx46 EEPROMs
+ *
+ * (C) 2011 DENX Software Engineering, Anatolij Gustschin <agust@denx.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <common.h>
+#include <init.h>
+#include <driver.h>
+#include <of.h>
+#include <spi/spi.h>
+#include <of.h>
+#include <spi/spi.h>
+#include <malloc.h>
+#include <gpio.h>
+#include <of_gpio.h>
+#include <of_device.h>
+
+#include <linux/nvmem-provider.h>
+
+
+#define OP_START	0x4
+#define OP_WRITE	(OP_START | 0x1)
+#define OP_READ		(OP_START | 0x2)
+#define ADDR_EWDS	0x00
+#define ADDR_ERAL	0x20
+#define ADDR_EWEN	0x30
+
+struct eeprom_93xx46_platform_data {
+	unsigned char	flags;
+#define EE_ADDR8	0x01		/*  8 bit addr. cfg */
+#define EE_ADDR16	0x02		/* 16 bit addr. cfg */
+#define EE_READONLY	0x08		/* forbid writing */
+
+	unsigned int	quirks;
+/* Single word read transfers only; no sequential read. */
+#define EEPROM_93XX46_QUIRK_SINGLE_WORD_READ		(1 << 0)
+/* Instructions such as EWEN are (addrlen + 2) in length. */
+#define EEPROM_93XX46_QUIRK_INSTRUCTION_LENGTH		(1 << 1)
+
+	/*
+	 * optional hooks to control additional logic
+	 * before and after spi transfer.
+	 */
+	void (*prepare)(void *);
+	void (*finish)(void *);
+	int select;
+};
+
+struct eeprom_93xx46_devtype_data {
+	unsigned int quirks;
+};
+
+static const struct eeprom_93xx46_devtype_data atmel_at93c46d_data = {
+	.quirks = EEPROM_93XX46_QUIRK_SINGLE_WORD_READ |
+		  EEPROM_93XX46_QUIRK_INSTRUCTION_LENGTH,
+};
+
+struct eeprom_93xx46_dev {
+	struct spi_device *spi;
+	struct eeprom_93xx46_platform_data *pdata;
+	struct nvmem_config nvmem_config;
+	struct nvmem_device *nvmem;
+	int addrlen;
+	int size;
+};
+
+static inline bool has_quirk_single_word_read(struct eeprom_93xx46_dev *edev)
+{
+	return edev->pdata->quirks & EEPROM_93XX46_QUIRK_SINGLE_WORD_READ;
+}
+
+static inline bool has_quirk_instruction_length(struct eeprom_93xx46_dev *edev)
+{
+	return edev->pdata->quirks & EEPROM_93XX46_QUIRK_INSTRUCTION_LENGTH;
+}
+
+static int eeprom_93xx46_read(struct device_d *dev, int off,
+			      void *val, int count)
+{
+	struct eeprom_93xx46_dev *edev = dev->parent->priv;
+	char *buf = val;
+	int err = 0;
+
+	if (unlikely(off >= edev->size))
+		return 0;
+	if ((off + count) > edev->size)
+		count = edev->size - off;
+	if (unlikely(!count))
+		return count;
+
+	if (edev->pdata->prepare)
+		edev->pdata->prepare(edev);
+
+	while (count) {
+		struct spi_message m;
+		struct spi_transfer t[2] = { { 0 } };
+		u16 cmd_addr = OP_READ << edev->addrlen;
+		size_t nbytes = count;
+		int bits;
+
+		if (edev->addrlen == 7) {
+			cmd_addr |= off & 0x7f;
+			bits = 10;
+			if (has_quirk_single_word_read(edev))
+				nbytes = 1;
+		} else {
+			cmd_addr |= (off >> 1) & 0x3f;
+			bits = 9;
+			if (has_quirk_single_word_read(edev))
+				nbytes = 2;
+		}
+
+		dev_dbg(&edev->spi->dev, "read cmd 0x%x, %d Hz\n",
+			cmd_addr, edev->spi->max_speed_hz);
+
+		spi_message_init(&m);
+
+		t[0].tx_buf = (char *)&cmd_addr;
+		t[0].len = 2;
+		t[0].bits_per_word = bits;
+		spi_message_add_tail(&t[0], &m);
+
+		t[1].rx_buf = buf;
+		t[1].len = count;
+		t[1].bits_per_word = 8;
+		spi_message_add_tail(&t[1], &m);
+
+		err = spi_sync(edev->spi, &m);
+		/* have to wait at least Tcsl ns */
+		ndelay(250);
+
+		if (err) {
+			dev_err(&edev->spi->dev, "read %zu bytes at %d: err. %d\n",
+				nbytes, (int)off, err);
+			break;
+		}
+
+		buf += nbytes;
+		off += nbytes;
+		count -= nbytes;
+	}
+
+	if (edev->pdata->finish)
+		edev->pdata->finish(edev);
+
+	return err;
+}
+
+static int eeprom_93xx46_ew(struct eeprom_93xx46_dev *edev, int is_on)
+{
+	struct spi_message m;
+	struct spi_transfer t;
+	int bits, ret;
+	u16 cmd_addr;
+
+	cmd_addr = OP_START << edev->addrlen;
+	if (edev->addrlen == 7) {
+		cmd_addr |= (is_on ? ADDR_EWEN : ADDR_EWDS) << 1;
+		bits = 10;
+	} else {
+		cmd_addr |= (is_on ? ADDR_EWEN : ADDR_EWDS);
+		bits = 9;
+	}
+
+	if (has_quirk_instruction_length(edev)) {
+		cmd_addr <<= 2;
+		bits += 2;
+	}
+
+	dev_dbg(&edev->spi->dev, "ew%s cmd 0x%04x, %d bits\n",
+			is_on ? "en" : "ds", cmd_addr, bits);
+
+	spi_message_init(&m);
+	memset(&t, 0, sizeof(t));
+
+	t.tx_buf = &cmd_addr;
+	t.len = 2;
+	t.bits_per_word = bits;
+	spi_message_add_tail(&t, &m);
+
+	if (edev->pdata->prepare)
+		edev->pdata->prepare(edev);
+
+	ret = spi_sync(edev->spi, &m);
+	/* have to wait at least Tcsl ns */
+	ndelay(250);
+	if (ret)
+		dev_err(&edev->spi->dev, "erase/write %sable error %d\n",
+			is_on ? "en" : "dis", ret);
+
+	if (edev->pdata->finish)
+		edev->pdata->finish(edev);
+
+	return ret;
+}
+
+static ssize_t
+eeprom_93xx46_write_word(struct eeprom_93xx46_dev *edev,
+			 const char *buf, unsigned off)
+{
+	struct spi_message m;
+	struct spi_transfer t[2];
+	int bits, data_len, ret;
+	u16 cmd_addr;
+
+	cmd_addr = OP_WRITE << edev->addrlen;
+
+	if (edev->addrlen == 7) {
+		cmd_addr |= off & 0x7f;
+		bits = 10;
+		data_len = 1;
+	} else {
+		cmd_addr |= (off >> 1) & 0x3f;
+		bits = 9;
+		data_len = 2;
+	}
+
+	dev_dbg(&edev->spi->dev, "write cmd 0x%x\n", cmd_addr);
+
+	spi_message_init(&m);
+	memset(t, 0, sizeof(t));
+
+	t[0].tx_buf = (char *)&cmd_addr;
+	t[0].len = 2;
+	t[0].bits_per_word = bits;
+	spi_message_add_tail(&t[0], &m);
+
+	t[1].tx_buf = buf;
+	t[1].len = data_len;
+	t[1].bits_per_word = 8;
+	spi_message_add_tail(&t[1], &m);
+
+	ret = spi_sync(edev->spi, &m);
+	/* have to wait program cycle time Twc ms */
+	mdelay(6);
+	return ret;
+}
+
+static int eeprom_93xx46_write(struct device_d *dev, const int off,
+			       const void *val, int count)
+{
+	struct eeprom_93xx46_dev *edev = dev->parent->priv;
+	const char *buf = val;
+	int i, ret, step = 1;
+
+	if (unlikely(off >= edev->size))
+		return -EFBIG;
+	if ((off + count) > edev->size)
+		count = edev->size - off;
+	if (unlikely(!count))
+		return count;
+
+	/* only write even number of bytes on 16-bit devices */
+	if (edev->addrlen == 6) {
+		step = 2;
+		count &= ~1;
+	}
+
+	/* erase/write enable */
+	ret = eeprom_93xx46_ew(edev, 1);
+	if (ret)
+		return ret;
+
+	if (edev->pdata->prepare)
+		edev->pdata->prepare(edev);
+
+	for (i = 0; i < count; i += step) {
+		ret = eeprom_93xx46_write_word(edev, &buf[i], off + i);
+		if (ret) {
+			dev_err(&edev->spi->dev, "write failed at %d: %d\n",
+				(int)off + i, ret);
+			break;
+		}
+	}
+
+	if (edev->pdata->finish)
+		edev->pdata->finish(edev);
+
+	/* erase/write disable */
+	eeprom_93xx46_ew(edev, 0);
+	return ret;
+}
+
+static void select_assert(void *context)
+{
+	struct eeprom_93xx46_dev *edev = context;
+
+	if (gpio_is_valid(edev->pdata->select))
+		gpio_set_active(edev->pdata->select, true);
+}
+
+static void select_deassert(void *context)
+{
+	struct eeprom_93xx46_dev *edev = context;
+
+	if (gpio_is_valid(edev->pdata->select))
+		gpio_set_active(edev->pdata->select, false);
+}
+
+static const struct of_device_id eeprom_93xx46_of_table[] = {
+	{ .compatible = "eeprom-93xx46", },
+	{ .compatible = "atmel,at93c46d", .data = &atmel_at93c46d_data, },
+	{}
+};
+
+static int eeprom_93xx46_probe_dt(struct spi_device *spi)
+{
+	const struct of_device_id *of_id =
+		of_match_device(eeprom_93xx46_of_table, &spi->dev);
+	struct device_node *np = spi->dev.device_node;
+	struct eeprom_93xx46_platform_data *pd;
+	enum of_gpio_flags of_flags;
+	unsigned long flags = GPIOF_OUT_INIT_INACTIVE;
+	u32 tmp;
+	int ret;
+
+	pd = xzalloc(sizeof(*pd));
+
+	ret = of_property_read_u32(np, "data-size", &tmp);
+	if (ret < 0) {
+		dev_err(&spi->dev, "data-size property not found\n");
+		return ret;
+	}
+
+	if (tmp == 8) {
+		pd->flags |= EE_ADDR8;
+	} else if (tmp == 16) {
+		pd->flags |= EE_ADDR16;
+	} else {
+		dev_err(&spi->dev, "invalid data-size (%d)\n", tmp);
+		return -EINVAL;
+	}
+
+	if (of_property_read_bool(np, "read-only"))
+		pd->flags |= EE_READONLY;
+
+	pd->select =of_get_named_gpio_flags(np, "select", 0, &of_flags);
+	if (gpio_is_valid(pd->select)) {
+		char *name;
+
+		if (of_flags & OF_GPIO_ACTIVE_LOW)
+			flags |= GPIOF_ACTIVE_LOW;
+
+		name = basprintf("%s select", dev_name(&spi->dev));
+		ret  = gpio_request_one(pd->select, flags, name);
+		if (ret < 0)
+			return ret;
+	}
+
+	pd->prepare = select_assert;
+	pd->finish = select_deassert;
+
+	if (gpio_is_valid(pd->select))
+		gpio_set_active(pd->select, false);
+
+	if (of_id->data) {
+		const struct eeprom_93xx46_devtype_data *data = of_id->data;
+
+		pd->quirks = data->quirks;
+	}
+
+	spi->dev.platform_data = pd;
+
+	return 0;
+}
+
+static const struct nvmem_bus eeprom_93xx46_nvmem_bus = {
+	.write = eeprom_93xx46_write,
+	.read  = eeprom_93xx46_read,
+};
+
+static int eeprom_93xx46_probe(struct device_d *dev)
+{
+	struct spi_device *spi = (struct spi_device *)dev->type_data;
+	struct eeprom_93xx46_platform_data *pd;
+	struct eeprom_93xx46_dev *edev;
+	int err;
+
+	if (dev->device_node) {
+		err = eeprom_93xx46_probe_dt(spi);
+		if (err < 0)
+			return err;
+	}
+
+	pd = spi->dev.platform_data;
+	if (!pd) {
+		dev_err(&spi->dev, "missing platform data\n");
+		return -ENODEV;
+	}
+
+	edev = xzalloc(sizeof(*edev));
+
+	if (pd->flags & EE_ADDR8)
+		edev->addrlen = 7;
+	else if (pd->flags & EE_ADDR16)
+		edev->addrlen = 6;
+	else {
+		dev_err(&spi->dev, "unspecified address type\n");
+		err = -EINVAL;
+		goto fail;
+	}
+
+	edev->spi = spi;
+	edev->pdata = pd;
+
+	edev->size = 128;
+	edev->nvmem_config.name = dev_name(&spi->dev);
+	edev->nvmem_config.dev = &spi->dev;
+	edev->nvmem_config.read_only = pd->flags & EE_READONLY;
+	edev->nvmem_config.bus = &eeprom_93xx46_nvmem_bus;
+	edev->nvmem_config.stride = 4;
+	edev->nvmem_config.word_size = 1;
+	edev->nvmem_config.size = edev->size;
+
+	dev->priv = edev;
+
+	edev->nvmem = nvmem_register(&edev->nvmem_config);
+	if (IS_ERR(edev->nvmem)) {
+		err = PTR_ERR(edev->nvmem);
+		goto fail;
+	}
+
+	dev_info(&spi->dev, "%d-bit eeprom %s\n",
+		(pd->flags & EE_ADDR8) ? 8 : 16,
+		(pd->flags & EE_READONLY) ? "(readonly)" : "");
+
+	return 0;
+fail:
+	kfree(edev);
+	return err;
+}
+
+static struct driver_d eeprom_93xx46_driver = {
+	.name = "93xx46",
+	.probe = eeprom_93xx46_probe,
+	.of_compatible = DRV_OF_COMPAT(eeprom_93xx46_of_table),
+};
+device_spi_driver(eeprom_93xx46_driver);
+
+
+
-- 
2.19.1


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 6+ messages in thread

* [PATCH 3/4] ARM: rdu1: Add an alias for Microwire EEPROM
  2018-11-05 18:32 [PATCH 0/4] RDU1 config blob loading Andrey Smirnov
  2018-11-05 18:32 ` [PATCH 1/4] lib: Port CRC8 implementation from Linux kernel Andrey Smirnov
  2018-11-05 18:32 ` [PATCH 2/4] nvmem: Port Linux driver for Microwire 93XX46 EEPROM chips Andrey Smirnov
@ 2018-11-05 18:32 ` Andrey Smirnov
  2018-11-05 18:32 ` [PATCH 4/4] ARM: rdu1: Implement RDU1 config loading Andrey Smirnov
  2018-11-06  8:53 ` [PATCH 0/4] RDU1 config blob loading Sascha Hauer
  4 siblings, 0 replies; 6+ messages in thread
From: Andrey Smirnov @ 2018-11-05 18:32 UTC (permalink / raw)
  To: barebox; +Cc: Andrey Smirnov

Add an alias for Microwire EEPROM to give it a better name in /dev.

Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com>
---
 arch/arm/dts/imx51-zii-rdu1.dts | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/arch/arm/dts/imx51-zii-rdu1.dts b/arch/arm/dts/imx51-zii-rdu1.dts
index c649db45c..b5744dac1 100644
--- a/arch/arm/dts/imx51-zii-rdu1.dts
+++ b/arch/arm/dts/imx51-zii-rdu1.dts
@@ -32,6 +32,7 @@
                  * fact to create a desirable naming
 		 */
 		switch-eeprom = &switch;
+		microwire-eeprom = &microwire_eeprom;
 	};
 };
 
@@ -64,6 +65,10 @@
 	switch: switch@0 {};
 };
 
+&spi_gpio {
+	microwire_eeprom: eeprom@0 {};
+};
+
 &uart3 {
 	rave-sp {
 		watchdog {
-- 
2.19.1


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 6+ messages in thread

* [PATCH 4/4] ARM: rdu1: Implement RDU1 config loading
  2018-11-05 18:32 [PATCH 0/4] RDU1 config blob loading Andrey Smirnov
                   ` (2 preceding siblings ...)
  2018-11-05 18:32 ` [PATCH 3/4] ARM: rdu1: Add an alias for Microwire EEPROM Andrey Smirnov
@ 2018-11-05 18:32 ` Andrey Smirnov
  2018-11-06  8:53 ` [PATCH 0/4] RDU1 config blob loading Sascha Hauer
  4 siblings, 0 replies; 6+ messages in thread
From: Andrey Smirnov @ 2018-11-05 18:32 UTC (permalink / raw)
  To: barebox; +Cc: Andrey Smirnov

RDU1 stores various configuration parameters, including FEC's MAC
address, in a configuration blob that can be located in on of three
places: SPI NOR, RAVE SP EEPROM or Microwire EEPROM.

This patch add an initcall to load those configuration variables from
a valid source (CRC8 checked) as well as expose then as "config_<var>"
environment variables.

This patch also adds appropriate code to register MAC address obtained
from config blob.

Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com>
---
 arch/arm/boards/zii-imx51-rdu1/board.c | 179 +++++++++++++++++++++++++
 arch/arm/dts/imx51-zii-rdu1.dts        |   7 +
 arch/arm/mach-imx/Kconfig              |   1 +
 3 files changed, 187 insertions(+)

diff --git a/arch/arm/boards/zii-imx51-rdu1/board.c b/arch/arm/boards/zii-imx51-rdu1/board.c
index 46368cccc..f739f3b7b 100644
--- a/arch/arm/boards/zii-imx51-rdu1/board.c
+++ b/arch/arm/boards/zii-imx51-rdu1/board.c
@@ -17,9 +17,16 @@
 
 #include <common.h>
 #include <init.h>
+#include <environment.h>
 #include <mach/bbu.h>
 #include <libfile.h>
 #include <mach/imx5.h>
+#include <net.h>
+#include <linux/crc8.h>
+#include <linux/sizes.h>
+#include <linux/nvmem-consumer.h>
+
+#include <envfs.h>
 
 static int zii_rdu1_init(void)
 {
@@ -45,3 +52,175 @@ static int zii_rdu1_init(void)
 	return 0;
 }
 coredevice_initcall(zii_rdu1_init);
+
+#define KEY		0
+#define VALUE		1
+#define STRINGS_NUM	2
+
+static int zii_rdu1_load_config(void)
+{
+	struct device_node *np, *root;
+	size_t len, remaining_space;
+	const uint8_t crc8_polynomial = 0x8c;
+	DECLARE_CRC8_TABLE(crc8_table);
+	const char *cursor, *end;
+	const char *file = "/dev/dataflash0.config";
+	uint8_t *config;
+	int ret = 0;
+	enum {
+		BLOB_SPINOR,
+		BLOB_RAVE_SP_EEPROM,
+		BLOB_MICROWIRE,
+	} blob;
+
+	if (!of_machine_is_compatible("zii,imx51-rdu1"))
+		return 0;
+
+	crc8_populate_lsb(crc8_table, crc8_polynomial);
+
+	for (blob = BLOB_SPINOR; blob <= BLOB_MICROWIRE; blob++) {
+		switch (blob) {
+		case BLOB_MICROWIRE:
+			file = "/dev/microwire-eeprom";
+			/* FALLTHROUGH */
+		case BLOB_SPINOR:
+			config = read_file(file, &remaining_space);
+			if (!config) {
+				pr_err("Failed to read %s\n", file);
+				return -EIO;
+			}
+			break;
+		case BLOB_RAVE_SP_EEPROM:
+			/* Needed for error logging below */
+			file = "shadow copy in RAVE SP EEPROM";
+
+			root = of_get_root_node();
+			np   = of_find_node_by_name(root, "eeprom@a4");
+			if (!np)
+				return -ENODEV;
+
+			pr_info("Loading %s, this may take a while\n", file);
+
+			remaining_space = SZ_1K;
+			config = nvmem_cell_get_and_read(np, "shadow-config",
+							 remaining_space);
+			if (IS_ERR(config))
+				return PTR_ERR(config);
+
+			break;
+		}
+
+		/*
+		 * The environment blob has its CRC8 stored as the
+		 * last byte of the blob, so calculating CRC8 over the
+		 * whole things should return 0
+		 */
+		if (crc8(crc8_table, config, remaining_space, 0)) {
+			pr_err("CRC mismatch for %s\n", file);
+			free(config);
+			config = NULL;
+		} else {
+			/*
+			 * We are done if there's a blob with a valid
+			 * CRC8
+			 */
+			break;
+		}
+	}
+
+	if (!config) {
+		pr_err("No valid config blobs were found\n");
+		ret = -EINVAL;
+		goto free_config;
+	}
+
+	/*
+	 * Last byte is CRC8, so it is of no use for our parsing
+	 * algorithm
+	 */
+	remaining_space--;
+
+	cursor = config;
+	end = cursor + remaining_space;
+
+	/*
+	 * The environemnt is stored a a bunch of zero-terminated
+	 * ASCII strings in "key":"value" pairs
+	 */
+	while (cursor < end) {
+		const char *strings[STRINGS_NUM] = { NULL, NULL };
+		char *key;
+		unsigned int i;
+
+		for (i = 0; i < ARRAY_SIZE(strings); i++) {
+			if (!*cursor) {
+				/* We assume that last key:value pair
+				 * will be terminated by an extra '\0'
+				 * at the end */
+				goto free_config;
+			}
+
+			len = strnlen(cursor, remaining_space);
+			if (len >= remaining_space) {
+				ret = -EOVERFLOW;
+				goto free_config;
+			}
+
+			strings[i] = cursor;
+
+			len++;	/* Account for '\0' at the end of the string */
+			cursor += len;
+			remaining_space -= len;
+
+			if (cursor > end) {
+				ret = -EOVERFLOW;
+				goto free_config;
+			}
+		}
+
+		key = basprintf("config_%s", strings[KEY]);
+		ret = setenv(key, strings[VALUE]);
+		free(key);
+
+		if (ret)
+			goto free_config;
+	}
+
+free_config:
+	free(config);
+	return ret;
+}
+late_initcall(zii_rdu1_load_config);
+
+static int zii_rdu1_ethernet_init(void)
+{
+	const char *mac_string;
+	struct device_node *np, *root;
+	uint8_t mac[ETH_ALEN];
+	int ret;
+
+	if (!of_machine_is_compatible("zii,imx51-rdu1"))
+		return 0;
+
+	root = of_get_root_node();
+
+	np = of_find_node_by_alias(root, "ethernet0");
+	if (!np) {
+		pr_warn("Failed to find ethernet0\n");
+		return -ENOENT;
+	}
+
+	mac_string = getenv("config_mac");
+	if (!mac_string)
+		return -ENOENT;
+
+	ret = string_to_ethaddr(mac_string, mac);
+	if (ret < 0)
+		return ret;
+
+	of_eth_register_ethaddr(np, mac);
+	return 0;
+}
+/* This needs to happen only after zii_rdu1_load_config was
+ * executed */
+environment_initcall(zii_rdu1_ethernet_init);
diff --git a/arch/arm/dts/imx51-zii-rdu1.dts b/arch/arm/dts/imx51-zii-rdu1.dts
index b5744dac1..01e46baf2 100644
--- a/arch/arm/dts/imx51-zii-rdu1.dts
+++ b/arch/arm/dts/imx51-zii-rdu1.dts
@@ -77,9 +77,16 @@
 		};
 
 		eeprom@a4 {
+			nvmem-cells = <&shadow_config>;
+			nvmem-cell-names = "shadow-config";
+
 			boot_source: boot-source@83 {
 				reg = <0x83 1>;
 			};
+
+			shadow_config: shadow-config@1000 {
+				reg = <0x1000 0x400>;
+			};
 		};
 	};
 };
diff --git a/arch/arm/mach-imx/Kconfig b/arch/arm/mach-imx/Kconfig
index c0788e7d9..c0a4cc1c8 100644
--- a/arch/arm/mach-imx/Kconfig
+++ b/arch/arm/mach-imx/Kconfig
@@ -425,6 +425,7 @@ config MACH_ZII_RDU1
 	bool "ZII i.MX51 RDU1"
 	select ARCH_IMX51
 	select MACH_FREESCALE_MX51_PDK_POWER
+	select CRC8
 
 config MACH_ZII_RDU2
 	bool "ZII i.MX6Q(+) RDU2"
-- 
2.19.1


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH 0/4] RDU1 config blob loading
  2018-11-05 18:32 [PATCH 0/4] RDU1 config blob loading Andrey Smirnov
                   ` (3 preceding siblings ...)
  2018-11-05 18:32 ` [PATCH 4/4] ARM: rdu1: Implement RDU1 config loading Andrey Smirnov
@ 2018-11-06  8:53 ` Sascha Hauer
  4 siblings, 0 replies; 6+ messages in thread
From: Sascha Hauer @ 2018-11-06  8:53 UTC (permalink / raw)
  To: Andrey Smirnov; +Cc: barebox

On Mon, Nov 05, 2018 at 10:32:18AM -0800, Andrey Smirnov wrote:
> Everyone:
> 
> This is a small series adding patches necessary to load config blob on
> RDU1 boards, which, among other things, contains MAC address to be
> used for FEC. Hopefully all of the commits are self-explanatory.
> 
> Feedback is welcome!
> 
> Thanks,
> Andrey Smirnov
> 
> Andrey Smirnov (4):
>   lib: Port CRC8 implementation from Linux kernel
>   nvmem: Port Linux driver for Microwire 93XX46 EEPROM chips
>   ARM: rdu1: Add an alias for Microwire EEPROM
>   ARM: rdu1: Implement RDU1 config loading

Applied, thanks

Sascha

> 
>  arch/arm/boards/zii-imx51-rdu1/board.c | 179 ++++++++++
>  arch/arm/dts/imx51-zii-rdu1.dts        |  12 +
>  arch/arm/mach-imx/Kconfig              |   1 +
>  drivers/nvmem/Kconfig                  |   8 +
>  drivers/nvmem/Makefile                 |   5 +-
>  drivers/nvmem/eeprom_93xx46.c          | 446 +++++++++++++++++++++++++
>  include/linux/crc8.h                   | 101 ++++++
>  lib/Kconfig                            |   7 +
>  lib/Makefile                           |   1 +
>  lib/crc8.c                             |  82 +++++
>  10 files changed, 841 insertions(+), 1 deletion(-)
>  create mode 100644 drivers/nvmem/eeprom_93xx46.c
>  create mode 100644 include/linux/crc8.h
>  create mode 100644 lib/crc8.c
> 
> -- 
> 2.19.1
> 
> 
> _______________________________________________
> barebox mailing list
> barebox@lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/barebox
> 

-- 
Pengutronix e.K.                           |                             |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2018-11-06  8:53 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-11-05 18:32 [PATCH 0/4] RDU1 config blob loading Andrey Smirnov
2018-11-05 18:32 ` [PATCH 1/4] lib: Port CRC8 implementation from Linux kernel Andrey Smirnov
2018-11-05 18:32 ` [PATCH 2/4] nvmem: Port Linux driver for Microwire 93XX46 EEPROM chips Andrey Smirnov
2018-11-05 18:32 ` [PATCH 3/4] ARM: rdu1: Add an alias for Microwire EEPROM Andrey Smirnov
2018-11-05 18:32 ` [PATCH 4/4] ARM: rdu1: Implement RDU1 config loading Andrey Smirnov
2018-11-06  8:53 ` [PATCH 0/4] RDU1 config blob loading Sascha Hauer

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox