aboutsummaryrefslogtreecommitdiffstats
path: root/roms/u-boot/drivers/w1-eeprom
diff options
context:
space:
mode:
Diffstat (limited to 'roms/u-boot/drivers/w1-eeprom')
-rw-r--r--roms/u-boot/drivers/w1-eeprom/Kconfig42
-rw-r--r--roms/u-boot/drivers/w1-eeprom/Makefile6
-rw-r--r--roms/u-boot/drivers/w1-eeprom/ds24xxx.c62
-rw-r--r--roms/u-boot/drivers/w1-eeprom/ds2502.c251
-rw-r--r--roms/u-boot/drivers/w1-eeprom/eep_sandbox.c61
-rw-r--r--roms/u-boot/drivers/w1-eeprom/w1-eeprom-uclass.c86
6 files changed, 508 insertions, 0 deletions
diff --git a/roms/u-boot/drivers/w1-eeprom/Kconfig b/roms/u-boot/drivers/w1-eeprom/Kconfig
new file mode 100644
index 000000000..34aca4b90
--- /dev/null
+++ b/roms/u-boot/drivers/w1-eeprom/Kconfig
@@ -0,0 +1,42 @@
+#
+# EEPROM subsystem configuration
+#
+
+menu "1-wire EEPROM support"
+
+config W1_EEPROM
+ bool "Enable support for EEPROMs on 1wire interface"
+ depends on DM
+ help
+ Support for the EEPROMs connected on 1-wire Dallas protocol interface
+
+if W1_EEPROM
+
+config W1_EEPROM_DS24XXX
+ bool "Enable Maxim DS24 families EEPROM support"
+ depends on W1
+ help
+ Maxim DS24 EEPROMs 1-Wire EEPROM support
+
+config W1_EEPROM_DS2502
+ bool "Enable Maxim DS2502 Add-Only Memory support"
+ depends on W1
+ help
+ Maxim DS2502 1-Wire add-only memory support.
+ This device has 128 bytes of data memory, organized as 4 pages of
+ 32 bytes and 8 out of band status bytes that may be used to redirect
+ pages, allowing data to be modified up to 4 times (by external
+ programming).
+
+ The device may be seen as a 32 byte memory, using the page redirection
+ or as a 128 byte memory, ignoring the page redirection.
+
+config W1_EEPROM_SANDBOX
+ bool "Enable sandbox onewire EEPROM driver"
+ depends on W1
+ help
+ Sandbox driver for a onewire EEPROM memory
+
+endif
+
+endmenu
diff --git a/roms/u-boot/drivers/w1-eeprom/Makefile b/roms/u-boot/drivers/w1-eeprom/Makefile
new file mode 100644
index 000000000..83f4008bb
--- /dev/null
+++ b/roms/u-boot/drivers/w1-eeprom/Makefile
@@ -0,0 +1,6 @@
+obj-$(CONFIG_W1_EEPROM) += w1-eeprom-uclass.o
+
+obj-$(CONFIG_W1_EEPROM_DS24XXX) += ds24xxx.o
+obj-$(CONFIG_W1_EEPROM_DS2502) += ds2502.o
+
+obj-$(CONFIG_W1_EEPROM_SANDBOX) += eep_sandbox.o
diff --git a/roms/u-boot/drivers/w1-eeprom/ds24xxx.c b/roms/u-boot/drivers/w1-eeprom/ds24xxx.c
new file mode 100644
index 000000000..4be378b43
--- /dev/null
+++ b/roms/u-boot/drivers/w1-eeprom/ds24xxx.c
@@ -0,0 +1,62 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ *
+ * Copyright (c) 2015 Free Electrons
+ * Copyright (c) 2015 NextThing Co
+ * Copyright (c) 2018 Microchip Technology, Inc.
+ *
+ */
+
+#include <common.h>
+#include <linux/err.h>
+#include <dm.h>
+#include <w1-eeprom.h>
+#include <w1.h>
+
+#define W1_F2D_READ_EEPROM 0xf0
+
+static int ds24xxx_read_buf(struct udevice *dev, unsigned int offset,
+ u8 *buf, unsigned int count)
+{
+ w1_reset_select(dev);
+
+ w1_write_byte(dev, W1_F2D_READ_EEPROM);
+ w1_write_byte(dev, offset & 0xff);
+ w1_write_byte(dev, offset >> 8);
+
+ return w1_read_buf(dev, buf, count);
+}
+
+static int ds24xxx_probe(struct udevice *dev)
+{
+ struct w1_device *w1;
+
+ w1 = dev_get_parent_plat(dev);
+ w1->id = 0;
+ return 0;
+}
+
+static const struct w1_eeprom_ops ds24xxx_ops = {
+ .read_buf = ds24xxx_read_buf,
+};
+
+static const struct udevice_id ds24xxx_id[] = {
+ { .compatible = "maxim,ds24b33", .data = W1_FAMILY_DS24B33 },
+ { .compatible = "maxim,ds2431", .data = W1_FAMILY_DS2431 },
+ { },
+};
+
+U_BOOT_DRIVER(ds24xxx) = {
+ .name = "ds24xxx",
+ .id = UCLASS_W1_EEPROM,
+ .of_match = ds24xxx_id,
+ .ops = &ds24xxx_ops,
+ .probe = ds24xxx_probe,
+};
+
+u8 family_supported[] = {
+ W1_FAMILY_DS24B33,
+ W1_FAMILY_DS2431,
+};
+
+U_BOOT_W1_DEVICE(ds24xxx, family_supported);
diff --git a/roms/u-boot/drivers/w1-eeprom/ds2502.c b/roms/u-boot/drivers/w1-eeprom/ds2502.c
new file mode 100644
index 000000000..a67f5edd0
--- /dev/null
+++ b/roms/u-boot/drivers/w1-eeprom/ds2502.c
@@ -0,0 +1,251 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Driver for DS-2502 One wire "Add only Memory".
+ *
+ * The chip has 4 pages of 32 bytes.
+ * In addition it has 8 out of band status bytes that are used, by software,
+ * as page redirection bytes by an algorithm described in the data sheet.
+ * This is useful since data cannot be erased once written but it can be
+ * "patched" up to four times by switching pages.
+ *
+ * So, when a read request is entirely in the first page automatically
+ * apply the page redirection bytes (which allows the device to be seen as
+ * a 32 byte PROM, writable 4 times).
+ *
+ * If the read request is outside of or larger than the first page then read
+ * the raw data (which allows the device to be seen as a 128 byte PROM,
+ * writable once).
+ *
+ * Copyright (c) 2018 Flowbird
+ * Martin Fuzzey <martin.fuzzey@flowbird.group>
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <dm/device_compat.h>
+#include <linux/err.h>
+#include <w1-eeprom.h>
+#include <w1.h>
+
+#define DS2502_PAGE_SIZE 32
+#define DS2502_PAGE_COUNT 4
+#define DS2502_STATUS_SIZE 8
+
+#define DS2502_CMD_READ_STATUS 0xAA
+#define DS2502_CMD_READ_GEN_CRC 0xC3
+
+/* u-boot crc8() is CCITT CRC8, we need x^8 + x^5 + x^4 + 1 LSB first */
+static unsigned int ds2502_crc8(const u8 *buf, int len)
+{
+ static const u8 poly = 0x8C; /* (1 + x^4 + x^5) + x^8 */
+ u8 crc = 0;
+ int i;
+
+ for (i = 0; i < len; i++) {
+ u8 data = buf[i];
+ int j;
+
+ for (j = 0; j < 8; j++) {
+ u8 mix = (crc ^ data) & 1;
+
+ crc >>= 1;
+ if (mix)
+ crc ^= poly;
+ data >>= 1;
+ }
+ }
+ return crc;
+}
+
+static int ds2502_read(struct udevice *dev, u8 cmd,
+ int bytes_in_page, int pos,
+ u8 *buf, int bytes_for_user)
+{
+ int retry;
+ int ret = 0;
+
+ for (retry = 0; retry < 3; retry++) {
+ u8 pagebuf[DS2502_PAGE_SIZE + 1]; /* 1 byte for CRC8 */
+ u8 crc;
+ int i;
+
+ ret = w1_reset_select(dev);
+ if (ret)
+ return ret;
+
+ /* send read to end of page and generate CRC command */
+ pagebuf[0] = cmd;
+ pagebuf[1] = pos & 0xff;
+ pagebuf[2] = pos >> 8;
+ crc = ds2502_crc8(pagebuf, 3);
+ for (i = 0; i < 3; i++)
+ w1_write_byte(dev, pagebuf[i]);
+
+ /* Check command CRC */
+ ret = w1_read_byte(dev);
+ if (ret < 0) {
+ dev_dbg(dev, "Error %d reading command CRC\n", ret);
+ continue;
+ }
+
+ if (ret != crc) {
+ dev_dbg(dev,
+ "bad CRC8 for cmd %02x got=%02X exp=%02X\n",
+ cmd, ret, crc);
+ ret = -EIO;
+ continue;
+ }
+
+ /* read data and check CRC */
+ ret = w1_read_buf(dev, pagebuf, bytes_in_page + 1);
+ if (ret < 0) {
+ dev_dbg(dev, "Error %d reading data\n", ret);
+ continue;
+ }
+
+ crc = ds2502_crc8(pagebuf, bytes_in_page);
+ if (crc == pagebuf[bytes_in_page]) {
+ memcpy(buf, pagebuf, bytes_for_user);
+ ret = 0;
+ break;
+ }
+ dev_dbg(dev, "Bad CRC8 got=%02X exp=%02X pos=%04X\n",
+ pagebuf[bytes_in_page], crc, pos);
+ ret = -EIO;
+ }
+
+ return ret;
+}
+
+static inline int ds2502_read_status_bytes(struct udevice *dev, u8 *buf)
+{
+ return ds2502_read(dev, DS2502_CMD_READ_STATUS,
+ DS2502_STATUS_SIZE, 0,
+ buf, DS2502_STATUS_SIZE);
+}
+
+/*
+ * Status bytes (from index 1) contain 1's complement page indirection
+ * So for N writes:
+ * N=1: ff ff ff ff ff ff ff 00
+ * N=2: ff fe ff ff ff ff ff 00
+ * N=3: ff fe fd ff ff ff ff 00
+ * N=4: ff fe fd fc ff ff ff 00
+ */
+static int ds2502_indirect_page(struct udevice *dev, u8 *status, int page)
+{
+ int page_seen = 0;
+
+ do {
+ u8 sb = status[page + 1];
+
+ if (sb == 0xff)
+ break;
+
+ page = ~sb & 0xff;
+
+ if (page >= DS2502_PAGE_COUNT) {
+ dev_err(dev,
+ "Illegal page redirection status byte %02x\n",
+ sb);
+ return -EINVAL;
+ }
+
+ if (page_seen & (1 << page)) {
+ dev_err(dev, "Infinite loop in page redirection\n");
+ return -EINVAL;
+ }
+
+ page_seen |= (1 << page);
+ } while (1);
+
+ return page;
+}
+
+static int ds2502_read_buf(struct udevice *dev, unsigned int offset,
+ u8 *buf, unsigned int count)
+{
+ unsigned int min_page = offset / DS2502_PAGE_SIZE;
+ unsigned int max_page = (offset + count - 1) / DS2502_PAGE_SIZE;
+ int xfered = 0;
+ u8 status_bytes[DS2502_STATUS_SIZE];
+ int i;
+ int ret;
+
+ if (min_page >= DS2502_PAGE_COUNT || max_page >= DS2502_PAGE_COUNT)
+ return -EINVAL;
+
+ if (min_page == 0 && max_page == 0) {
+ ret = ds2502_read_status_bytes(dev, status_bytes);
+ if (ret)
+ return ret;
+ } else {
+ /* Dummy one to one page redirection */
+ memset(status_bytes, 0xff, sizeof(status_bytes));
+ }
+
+ for (i = min_page; i <= max_page; i++) {
+ int page;
+ int pos;
+ int bytes_in_page;
+ int bytes_for_user;
+
+ page = ds2502_indirect_page(dev, status_bytes, i);
+ if (page < 0)
+ return page;
+ dev_dbg(dev, "page logical %d => physical %d\n", i, page);
+
+ pos = page * DS2502_PAGE_SIZE;
+ if (i == min_page)
+ pos += offset % DS2502_PAGE_SIZE;
+
+ bytes_in_page = DS2502_PAGE_SIZE - (pos % DS2502_PAGE_SIZE);
+
+ if (i == max_page)
+ bytes_for_user = count - xfered;
+ else
+ bytes_for_user = bytes_in_page;
+
+ ret = ds2502_read(dev, DS2502_CMD_READ_GEN_CRC,
+ bytes_in_page, pos,
+ &buf[xfered], bytes_for_user);
+ if (ret < 0)
+ return ret;
+
+ xfered += bytes_for_user;
+ }
+
+ return 0;
+}
+
+static int ds2502_probe(struct udevice *dev)
+{
+ struct w1_device *w1;
+
+ w1 = dev_get_parent_plat(dev);
+ w1->id = 0;
+ return 0;
+}
+
+static const struct w1_eeprom_ops ds2502_ops = {
+ .read_buf = ds2502_read_buf,
+};
+
+static const struct udevice_id ds2502_id[] = {
+ { .compatible = "maxim,ds2502", .data = W1_FAMILY_DS2502 },
+ { },
+};
+
+U_BOOT_DRIVER(ds2502) = {
+ .name = "ds2502",
+ .id = UCLASS_W1_EEPROM,
+ .of_match = ds2502_id,
+ .ops = &ds2502_ops,
+ .probe = ds2502_probe,
+};
+
+u8 family_supported[] = {
+ W1_FAMILY_DS2502,
+};
+
+U_BOOT_W1_DEVICE(ds2502, family_supported);
diff --git a/roms/u-boot/drivers/w1-eeprom/eep_sandbox.c b/roms/u-boot/drivers/w1-eeprom/eep_sandbox.c
new file mode 100644
index 000000000..27c7f9f1b
--- /dev/null
+++ b/roms/u-boot/drivers/w1-eeprom/eep_sandbox.c
@@ -0,0 +1,61 @@
+/* SPDX-License-Identifier: GPL-2.0+
+ *
+ * Copyright (c) 2018 Microchip Technology, Inc.
+ *
+ */
+
+#include <common.h>
+#include <linux/err.h>
+#include <dm.h>
+#include <w1-eeprom.h>
+#include <w1.h>
+
+#define W1_F2D_READ_EEPROM 0xf0
+
+#define EEP_SANDBOX_SAMPLE_MEM "this is a sample EEPROM memory string."
+
+static int eep_sandbox_read_buf(struct udevice *dev, unsigned int offset,
+ u8 *buf, unsigned int count)
+{
+ /* do not allow to copy more than our maximum sample string */
+ if (offset + count < strlen(EEP_SANDBOX_SAMPLE_MEM)) {
+ offset = 0;
+ count = strlen(EEP_SANDBOX_SAMPLE_MEM);
+ }
+ strncpy((char *)buf, EEP_SANDBOX_SAMPLE_MEM, count);
+
+ /*
+ * in case the w1 subsystem uses some different kind of sandbox testing,
+ * like randomized gpio values , we take the buffer from there
+ */
+
+ w1_reset_select(dev);
+
+ w1_write_byte(dev, W1_F2D_READ_EEPROM);
+ w1_write_byte(dev, offset & 0xff);
+ w1_write_byte(dev, offset >> 8);
+
+ w1_read_buf(dev, buf, count);
+
+ /*
+ * even if read buf from w1 fails, return success as we hardcoded
+ * the buffer.
+ */
+ return 0;
+}
+
+static const struct w1_eeprom_ops eep_sandbox_ops = {
+ .read_buf = eep_sandbox_read_buf,
+};
+
+static const struct udevice_id eep_sandbox_id[] = {
+ { .compatible = "sandbox,w1-eeprom", .data = W1_FAMILY_EEP_SANDBOX },
+ { },
+};
+
+U_BOOT_DRIVER(eep_sandbox) = {
+ .name = "eep_sandbox",
+ .id = UCLASS_W1_EEPROM,
+ .of_match = eep_sandbox_id,
+ .ops = &eep_sandbox_ops,
+};
diff --git a/roms/u-boot/drivers/w1-eeprom/w1-eeprom-uclass.c b/roms/u-boot/drivers/w1-eeprom/w1-eeprom-uclass.c
new file mode 100644
index 000000000..7a02af3dd
--- /dev/null
+++ b/roms/u-boot/drivers/w1-eeprom/w1-eeprom-uclass.c
@@ -0,0 +1,86 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ *
+ * Copyright (c) 2015 Free Electrons
+ * Copyright (c) 2015 NextThing Co.
+ * Copyright (c) 2018 Microchip Technology, Inc.
+ *
+ * Maxime Ripard <maxime.ripard@free-electrons.com>
+ * Eugen Hristev <eugen.hristev@microchip.com>
+ *
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <log.h>
+#include <w1.h>
+#include <w1-eeprom.h>
+
+#include <dm/device-internal.h>
+
+int w1_eeprom_read_buf(struct udevice *dev, unsigned int offset,
+ u8 *buf, unsigned int count)
+{
+ const struct w1_eeprom_ops *ops = device_get_ops(dev);
+ u64 id = 0;
+ int ret;
+
+ if (!ops->read_buf)
+ return -ENOSYS;
+
+ ret = w1_eeprom_get_id(dev, &id);
+ if (ret)
+ return ret;
+ if (!id)
+ return -ENODEV;
+
+ return ops->read_buf(dev, offset, buf, count);
+}
+
+int w1_eeprom_get_id(struct udevice *dev, u64 *id)
+{
+ struct w1_device *w1 = dev_get_parent_plat(dev);
+
+ if (!w1)
+ return -ENODEV;
+ *id = w1->id;
+
+ return 0;
+}
+
+UCLASS_DRIVER(w1_eeprom) = {
+ .name = "w1_eeprom",
+ .id = UCLASS_W1_EEPROM,
+ .flags = DM_UC_FLAG_SEQ_ALIAS,
+#if CONFIG_IS_ENABLED(OF_CONTROL)
+ .post_bind = dm_scan_fdt_dev,
+#endif
+};
+
+int w1_eeprom_dm_init(void)
+{
+ struct udevice *dev;
+ struct uclass *uc;
+ int ret;
+
+ ret = uclass_get(UCLASS_W1_EEPROM, &uc);
+ if (ret) {
+ debug("W1_EEPROM uclass not available\n");
+ return ret;
+ }
+
+ uclass_foreach_dev(dev, uc) {
+ ret = device_probe(dev);
+ if (ret == -ENODEV) { /* No such device. */
+ debug("W1_EEPROM not available.\n");
+ continue;
+ }
+
+ if (ret) { /* Other error. */
+ printf("W1_EEPROM probe failed, error %d\n", ret);
+ continue;
+ }
+ }
+
+ return 0;
+}