mail archive of the barebox mailing list
 help / color / mirror / Atom feed
* [PATCH v3 0/6] prepare Protonic board code for mainline
@ 2020-08-13 12:55 Oleksij Rempel
  2020-08-13 12:55 ` [PATCH v3 1/6] gpiolib: add gpio_array_to_id helper to get ID out of GPIO array Oleksij Rempel
                   ` (5 more replies)
  0 siblings, 6 replies; 9+ messages in thread
From: Oleksij Rempel @ 2020-08-13 12:55 UTC (permalink / raw)
  To: barebox, david; +Cc: Oleksij Rempel

changes v3:
- remove barebox-serial driver and use read the rfid directy from board
  code (as was done in initial implementation)
- use initcall instead of registering driver in the board code
- add delayed USB scan
- add rampoops node
- add partition tables 

changes v2:
- add power init support for KvG boards
- spell fixes
- do not print error on probe exit
- add of_console_get_by_alias() helper
- free requested gpio array
- exit fec init only in case of PROBE_DEFERED

This patch series is a preparation and actual Protonic board code.
Following changes was made in the main code:
- register DT root node as device to make it possible to loade board
  code as usual driver
- provide helpers to read ethernet mac from nvmem cell register in a
  devicetree.
- provide barebox-serial driver which should be a nvmem cell consumer
  and
  serial-number DT property provider.
- provide gpio helper to read gpio based board revision.

Oleksij Rempel (6):
  gpiolib: add gpio_array_to_id helper to get ID out of GPIO array
  common: console_common: add of_console_get_by_alias() helper
  of: of_device_get_match_compatible() helper
  ARM: protonic-imx6: port Protonic specific board code
  ARM: dts: unify barebox and barebox,env partitions for all Protonic
    boards
  ARM: dts: imx6q-prti6q: add pstore/ramoops node

 arch/arm/boards/protonic-imx6/Makefile |    1 +
 arch/arm/boards/protonic-imx6/board.c  | 1002 ++++++++++++++++++++++++
 arch/arm/dts/imx6dl-plym2m.dts         |   25 +
 arch/arm/dts/imx6dl-prtrvt.dts         |    1 +
 arch/arm/dts/imx6q-prti6q.dts          |   24 +-
 arch/arm/dts/imx6qdl-prti6q-nor.dtsi   |   10 +
 arch/arm/dts/imx6qdl-prti6q.dtsi       |   31 +
 arch/arm/dts/imx6qdl-vicut1.dtsi       |   26 +
 common/console_common.c                |   18 +
 drivers/gpio/gpiolib.c                 |   31 +
 drivers/of/device.c                    |   12 +
 include/console.h                      |    1 +
 include/gpio.h                         |    5 +
 include/of_device.h                    |    6 +
 14 files changed, 1170 insertions(+), 23 deletions(-)
 create mode 100644 arch/arm/boards/protonic-imx6/board.c
 create mode 100644 arch/arm/dts/imx6qdl-prti6q-nor.dtsi

-- 
2.28.0


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

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

* [PATCH v3 1/6] gpiolib: add gpio_array_to_id helper to get ID out of GPIO array
  2020-08-13 12:55 [PATCH v3 0/6] prepare Protonic board code for mainline Oleksij Rempel
@ 2020-08-13 12:55 ` Oleksij Rempel
  2020-08-13 12:55 ` [PATCH v3 2/6] common: console_common: add of_console_get_by_alias() helper Oleksij Rempel
                   ` (4 subsequent siblings)
  5 siblings, 0 replies; 9+ messages in thread
From: Oleksij Rempel @ 2020-08-13 12:55 UTC (permalink / raw)
  To: barebox, david; +Cc: Oleksij Rempel

Some boards provide a board version and/or ID coded by pull-up/down
resistors connected to the gpio pins (or pins which can be multiplexed
at some point as gpio). In this case every one implements own gpio id
reader function.

To avoid it, provide the common helper function to extract a value out
of provided gpio array.

Signed-off-by: Oleksij Rempel <o.rempel@pengutronix.de>
---
 drivers/gpio/gpiolib.c | 31 +++++++++++++++++++++++++++++++
 include/gpio.h         |  5 +++++
 2 files changed, 36 insertions(+)

diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
index 27674af54c..6088cadd8a 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -381,6 +381,37 @@ void gpio_free_array(const struct gpio *array, size_t num)
 }
 EXPORT_SYMBOL_GPL(gpio_free_array);
 
+int gpio_array_to_id(const struct gpio *array, size_t num, u32 *val)
+{
+	u32 id = 0;
+	int ret, i;
+
+	if (num > 32)
+		return -EOVERFLOW;
+
+	ret = gpio_request_array(array, num);
+	if (ret)
+		return ret;
+
+	/* Wait until logic level will be stable */
+	udelay(5);
+	for (i = 0; i < num; i++) {
+		ret = gpio_is_active(array[i].gpio);
+		if (ret < 0)
+			goto free_array;
+		if (ret)
+			id |= 1UL << i;
+	}
+
+	*val = id;
+	ret = 0;
+
+free_array:
+	gpio_free_array(array, num);
+	return ret;
+}
+EXPORT_SYMBOL(gpio_array_to_id);
+
 static int gpiochip_find_base(int start, int ngpio)
 {
 	int i;
diff --git a/include/gpio.h b/include/gpio.h
index 98c5b93ba2..81beb47309 100644
--- a/include/gpio.h
+++ b/include/gpio.h
@@ -145,6 +145,10 @@ static inline void gpio_free_array(const struct gpio *array, size_t num)
 	/* GPIO can never have been requested */
 	WARN_ON(1);
 }
+static inline int gpio_array_to_id(const struct gpio *array, size_t num, u32 *val)
+{
+	return -EINVAL;
+}
 #else
 int gpio_request(unsigned gpio, const char *label);
 int gpio_find_by_name(const char *name);
@@ -153,6 +157,7 @@ void gpio_free(unsigned gpio);
 int gpio_request_one(unsigned gpio, unsigned long flags, const char *label);
 int gpio_request_array(const struct gpio *array, size_t num);
 void gpio_free_array(const struct gpio *array, size_t num);
+int gpio_array_to_id(const struct gpio *array, size_t num, u32 *val);
 #endif
 
 struct gpio_chip;
-- 
2.28.0


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

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

* [PATCH v3 2/6] common: console_common: add of_console_get_by_alias() helper
  2020-08-13 12:55 [PATCH v3 0/6] prepare Protonic board code for mainline Oleksij Rempel
  2020-08-13 12:55 ` [PATCH v3 1/6] gpiolib: add gpio_array_to_id helper to get ID out of GPIO array Oleksij Rempel
@ 2020-08-13 12:55 ` Oleksij Rempel
  2020-08-13 12:55 ` [PATCH v3 3/6] of: of_device_get_match_compatible() helper Oleksij Rempel
                   ` (3 subsequent siblings)
  5 siblings, 0 replies; 9+ messages in thread
From: Oleksij Rempel @ 2020-08-13 12:55 UTC (permalink / raw)
  To: barebox, david; +Cc: Oleksij Rempel

Add helper function to get console device by devicetree alias

Signed-off-by: Oleksij Rempel <o.rempel@pengutronix.de>
---
 common/console_common.c | 18 ++++++++++++++++++
 include/console.h       |  1 +
 2 files changed, 19 insertions(+)

diff --git a/common/console_common.c b/common/console_common.c
index a174c2deed..8cd57e623d 100644
--- a/common/console_common.c
+++ b/common/console_common.c
@@ -23,6 +23,7 @@
 #include <environment.h>
 #include <globalvar.h>
 #include <magicvar.h>
+#include <of.h>
 #include <password.h>
 #include <clock.h>
 #include <malloc.h>
@@ -323,6 +324,23 @@ struct console_device *console_get_first_active(void)
 }
 EXPORT_SYMBOL(console_get_first_active);
 
+struct console_device *of_console_get_by_alias(const char *alias)
+{
+	struct device_node *node;
+	struct device_d *dev;
+
+	node = of_find_node_by_alias(NULL, alias);
+	if (!node)
+		return NULL;
+
+	dev = of_find_device_by_node(node);
+	if (!dev)
+		return NULL;
+
+	return console_get_by_dev(dev);
+}
+EXPORT_SYMBOL(of_console_get_by_alias);
+
 #endif /* !CONFIG_CONSOLE_NONE */
 
 int dprintf(int file, const char *fmt, ...)
diff --git a/include/console.h b/include/console.h
index 5b5c037026..a71d0da42e 100644
--- a/include/console.h
+++ b/include/console.h
@@ -87,6 +87,7 @@ int console_unregister(struct console_device *cdev);
 
 struct console_device *console_get_by_dev(struct device_d *dev);
 struct console_device *console_get_by_name(const char *name);
+struct console_device *of_console_get_by_alias(const char *alias);
 
 extern struct list_head console_list;
 #define for_each_console(console) list_for_each_entry(console, &console_list, list)
-- 
2.28.0


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

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

* [PATCH v3 3/6] of: of_device_get_match_compatible() helper
  2020-08-13 12:55 [PATCH v3 0/6] prepare Protonic board code for mainline Oleksij Rempel
  2020-08-13 12:55 ` [PATCH v3 1/6] gpiolib: add gpio_array_to_id helper to get ID out of GPIO array Oleksij Rempel
  2020-08-13 12:55 ` [PATCH v3 2/6] common: console_common: add of_console_get_by_alias() helper Oleksij Rempel
@ 2020-08-13 12:55 ` Oleksij Rempel
  2020-08-13 12:55 ` [PATCH v3 4/6] ARM: protonic-imx6: port Protonic specific board code Oleksij Rempel
                   ` (2 subsequent siblings)
  5 siblings, 0 replies; 9+ messages in thread
From: Oleksij Rempel @ 2020-08-13 12:55 UTC (permalink / raw)
  To: barebox, david; +Cc: Oleksij Rempel

Some times we need to know, against which compatible did the driver
was registered. So, instead of coding it in the driver, add generic
helper for all drivers.

Signed-off-by: Oleksij Rempel <o.rempel@pengutronix.de>
---
 drivers/of/device.c | 12 ++++++++++++
 include/of_device.h |  6 ++++++
 2 files changed, 18 insertions(+)

diff --git a/drivers/of/device.c b/drivers/of/device.c
index 67a67bd565..b3f522e1fa 100644
--- a/drivers/of/device.c
+++ b/drivers/of/device.c
@@ -31,3 +31,15 @@ const void *of_device_get_match_data(const struct device_d *dev)
 	return match->data;
 }
 EXPORT_SYMBOL(of_device_get_match_data);
+
+const char *of_device_get_match_compatible(const struct device_d *dev)
+{
+	const struct of_device_id *match;
+
+	match = of_match_device(dev->driver->of_compatible, dev);
+	if (!match)
+		return NULL;
+
+	return match->compatible;
+}
+EXPORT_SYMBOL(of_device_get_match_compatible);
diff --git a/include/of_device.h b/include/of_device.h
index 244f5fcbbb..cef6d5b5cc 100644
--- a/include/of_device.h
+++ b/include/of_device.h
@@ -22,6 +22,7 @@ static inline int of_driver_match_device(struct device_d *dev,
 }
 
 extern const void *of_device_get_match_data(const struct device_d *dev);
+extern const char *of_device_get_match_compatible(const struct device_d *dev);
 
 #else /* CONFIG_OFTREE */
 
@@ -36,6 +37,11 @@ static inline const void *of_device_get_match_data(const struct device_d *dev)
 	return NULL;
 }
 
+static inline const char *of_device_get_match_compatible(const struct device_d *dev)
+{
+	return NULL;
+}
+
 static inline const struct of_device_id *__of_match_device(
 		const struct of_device_id *matches, const struct device_d *dev)
 {
-- 
2.28.0


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

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

* [PATCH v3 4/6] ARM: protonic-imx6: port Protonic specific board code
  2020-08-13 12:55 [PATCH v3 0/6] prepare Protonic board code for mainline Oleksij Rempel
                   ` (2 preceding siblings ...)
  2020-08-13 12:55 ` [PATCH v3 3/6] of: of_device_get_match_compatible() helper Oleksij Rempel
@ 2020-08-13 12:55 ` Oleksij Rempel
  2020-08-13 14:07   ` David Jander
  2020-08-13 12:55 ` [PATCH v3 5/6] ARM: dts: unify barebox and barebox, env partitions for all Protonic boards Oleksij Rempel
  2020-08-13 12:55 ` [PATCH v3 6/6] ARM: dts: imx6q-prti6q: add pstore/ramoops node Oleksij Rempel
  5 siblings, 1 reply; 9+ messages in thread
From: Oleksij Rempel @ 2020-08-13 12:55 UTC (permalink / raw)
  To: barebox, david; +Cc: Oleksij Rempel

Signed-off-by: Oleksij Rempel <o.rempel@pengutronix.de>
---
 arch/arm/boards/protonic-imx6/Makefile |    1 +
 arch/arm/boards/protonic-imx6/board.c  | 1002 ++++++++++++++++++++++++
 2 files changed, 1003 insertions(+)
 create mode 100644 arch/arm/boards/protonic-imx6/board.c

diff --git a/arch/arm/boards/protonic-imx6/Makefile b/arch/arm/boards/protonic-imx6/Makefile
index b08c4a93ca..01c7a259e9 100644
--- a/arch/arm/boards/protonic-imx6/Makefile
+++ b/arch/arm/boards/protonic-imx6/Makefile
@@ -1 +1,2 @@
+obj-y += board.o
 lwl-y += lowlevel.o
diff --git a/arch/arm/boards/protonic-imx6/board.c b/arch/arm/boards/protonic-imx6/board.c
new file mode 100644
index 0000000000..f3bd0dd86a
--- /dev/null
+++ b/arch/arm/boards/protonic-imx6/board.c
@@ -0,0 +1,1002 @@
+// SPDX-License-Identifier: GPL-2.0-only
+// SPDX-FileCopyrightText: 2012 Steffen Trumtrar, Pengutronix
+// SPDX-FileCopyrightText: 2014 Protonic Holland
+// SPDX-FileCopyrightText: 2020 Oleksij Rempel, Pengutronix
+
+#include <bbu.h>
+#include <common.h>
+#include <environment.h>
+#include <gpio.h>
+#include <mach/bbu.h>
+#include <mach/imx6.h>
+#include <of_device.h>
+
+#include <usb/usb.h>
+#include <sys/mount.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <net.h>
+#include <i2c/i2c.h>
+
+#define GPIO_HW_REV_ID  {\
+	{IMX_GPIO_NR(2, 8), GPIOF_DIR_IN | GPIOF_ACTIVE_LOW, "rev_id0"}, \
+	{IMX_GPIO_NR(2, 9), GPIOF_DIR_IN | GPIOF_ACTIVE_LOW, "rev_id1"}, \
+	{IMX_GPIO_NR(2, 10), GPIOF_DIR_IN | GPIOF_ACTIVE_LOW, "rev_id2"} \
+}
+
+#define GPIO_HW_TYPE_ID  {\
+	{IMX_GPIO_NR(2, 11), GPIOF_DIR_IN | GPIOF_ACTIVE_LOW, "hw_id0"}, \
+	{IMX_GPIO_NR(2, 12), GPIOF_DIR_IN | GPIOF_ACTIVE_LOW, "hw_id1"}, \
+	{IMX_GPIO_NR(2, 13), GPIOF_DIR_IN | GPIOF_ACTIVE_LOW, "hw_id2"}, \
+	{IMX_GPIO_NR(2, 14), GPIOF_DIR_IN | GPIOF_ACTIVE_LOW, "hw_id3"}, \
+	{IMX_GPIO_NR(2, 15), GPIOF_DIR_IN | GPIOF_ACTIVE_LOW, "hw_id4"} \
+}
+
+enum {
+	HW_TYPE_PRTI6Q = 0,
+	HW_TYPE_PRTWD2 = 1,
+	HW_TYPE_ALTI6S = 2,
+	HW_TYPE_VICUT1 = 4,
+	HW_TYPE_ALTI6P = 6,
+	HW_TYPE_PRTMVT = 8,
+	HW_TYPE_PRTI6G = 10,
+	HW_TYPE_PRTRVT = 12,
+	HW_TYPE_VICUT2 = 16,
+	HW_TYPE_PLYM2M = 20,
+	HW_TYPE_PRTVT7 = 22,
+	HW_TYPE_LANMCU = 23,
+	HW_TYPE_PLYBAS = 24,
+	HW_TYPE_VICTGO = 28,
+};
+
+enum prt_imx6_kvg_pw_mode {
+	PW_MODE_KVG_WITH_YACO = 0,
+	PW_MODE_KVG_NEW = 1,
+	PW_MODE_KUBOTA = 2,
+};
+
+/* board specific flags */
+#define PRT_IMX6_BOOTCHOOSER		BIT(3)
+#define PRT_IMX6_USB_LONG_DELAY		BIT(2)
+#define PRT_IMX6_BOOTSRC_EMMC		BIT(1)
+#define PRT_IMX6_BOOTSRC_SPI_NOR	BIT(0)
+
+static struct prt_imx6_priv *prt_priv;
+struct prt_machine_data {
+	unsigned int hw_id;
+	unsigned int hw_rev;
+	unsigned int i2c_addr;
+	unsigned int i2c_adapter;
+	unsigned int flags;
+	int (*init)(struct prt_imx6_priv *priv);
+};
+
+struct prt_imx6_priv {
+	struct device_d *dev;
+	const struct prt_machine_data *dcfg;
+	unsigned int hw_id;
+	unsigned int hw_rev;
+	const char *name;
+	struct poller_async poller;
+	unsigned int usb_delay;
+};
+
+struct prti6q_rfid_contents {
+	u8 mac[6];
+	char serial[10];
+	u8 cs;
+} __attribute__ ((packed));
+
+#define GPIO_DIP1_FB   IMX_GPIO_NR(4, 18)
+#define GPIO_FORCE_ON1 IMX_GPIO_NR(2, 30)
+#define GPIO_ON1_CTRL  IMX_GPIO_NR(4, 21)
+#define GPIO_ON2_CTRL  IMX_GPIO_NR(4, 22)
+
+static const struct gpio prt_imx6_kvg_gpios[] = {
+	{
+		.gpio = GPIO_DIP1_FB,
+		.flags = GPIOF_IN,
+		.label = "DIP1_FB",
+	},
+	{
+		.gpio = GPIO_FORCE_ON1,
+		.flags = GPIOF_OUT_INIT_HIGH,
+		.label = "FORCE_ON1",
+	},
+	{
+		.gpio = GPIO_ON1_CTRL,
+		.flags = GPIOF_IN,
+		.label = "ON1_CTRL",
+	},
+	{
+		.gpio = GPIO_ON2_CTRL,
+		.flags = GPIOF_IN,
+		.label = "ON2_CTRL",
+	},
+};
+
+static int prt_imx6_read_rfid(struct prt_imx6_priv *priv, void *buf,
+			      size_t size)
+{
+	const struct prt_machine_data *dcfg = priv->dcfg;
+	struct device_d *dev = priv->dev;
+	struct i2c_client cl;
+	int ret;
+
+	cl.addr = dcfg->i2c_addr;
+	cl.adapter = i2c_get_adapter(dcfg->i2c_adapter);
+	if (!cl.adapter) {
+		dev_err(dev, "i2c bus not found\n");
+		return -ENODEV;
+	}
+
+	/* 0x6000 user storage in the RFID tag */
+	ret = i2c_read_reg(&cl, 0x6000 | I2C_ADDR_16_BIT, buf, size);
+	if (ret < 0) {
+		dev_err(dev, "Filed to read the RFID: %i\n", ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+static u8 prt_imx6_calc_rfid_crc(void *buf, size_t size)
+{
+	unsigned int cs = 0;
+	u8 *dat = buf;
+	int t;
+
+	for (t = 0; t < size - 1; t++) {
+		cs += dat[t];
+	}
+
+	cs ^= 0xff;
+
+	return cs & 0xff;
+
+}
+
+static int prt_imx6_set_mac(struct prt_imx6_priv *priv,
+			    struct prti6q_rfid_contents *rfid)
+{
+	struct device_d *dev = priv->dev;
+	struct device_node *node;
+
+	node = of_find_node_by_alias(of_get_root_node(), "ethernet0");
+	if (!node) {
+		dev_err(dev, "Cannot find FEC!\n");
+		return -ENODEV;
+	}
+
+	if (!is_valid_ether_addr(&rfid->mac[0])) {
+		dev_err(dev, "bad MAC addr\n");
+		return -EILSEQ;
+	}
+
+	of_eth_register_ethaddr(node, &rfid->mac[0]);
+
+	return 0;
+}
+
+static int prt_of_fixup_serial(struct device_node *dstroot, void *arg)
+{
+	struct device_node *srcroot = arg;
+	const char *ser;
+	int len;
+
+	ser = of_get_property(srcroot, "serial-number", &len);
+	return of_set_property(dstroot, "serial-number", ser, len, 1);
+}
+
+static void prt_oftree_fixup_serial(const char *serial)
+{
+	struct device_node *root = of_get_root_node();
+
+	of_set_property(root, "serial-number", serial, strlen(serial) + 1, 1);
+	of_register_fixup(prt_of_fixup_serial, root);
+}
+
+static int prt_imx6_set_serial(struct prt_imx6_priv *priv,
+			       struct prti6q_rfid_contents *rfid)
+{
+	rfid->serial[9] = 0; /* Failsafe */
+	dev_info(priv->dev, "Serial number: %s\n", rfid->serial);
+	prt_oftree_fixup_serial(rfid->serial);
+
+	return 0;
+}
+
+static int prt_imx6_read_i2c_mac_serial(struct prt_imx6_priv *priv)
+{
+	struct device_d *dev = priv->dev;
+	struct prti6q_rfid_contents rfid;
+	int ret;
+
+	ret = prt_imx6_read_rfid(priv, &rfid, sizeof(rfid));
+	if (ret)
+		return ret;
+
+	if (rfid.cs != prt_imx6_calc_rfid_crc(&rfid, sizeof(rfid))) {
+		dev_err(dev, "RFID: bad checksum!\n");
+		return -EBADMSG;
+	}
+
+	ret = prt_imx6_set_mac(priv, &rfid);
+	if (ret)
+		return ret;
+
+	ret = prt_imx6_set_serial(priv, &rfid);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+#define OTG_PORTSC1 (MX6_OTG_BASE_ADDR+0x184)
+
+static void prt_imx6_check_usb_boot(void *data)
+{
+	struct prt_imx6_priv *priv = data;
+	struct device_d *dev = priv->dev;
+	char *second_word, *bootsrc;
+	unsigned int v;
+	ssize_t size;
+	char buf[16];
+	int fd, ret;
+
+	v = *((unsigned int *)OTG_PORTSC1);
+	if ((v & 0x0c00) == 0) /* LS == SE0 ==> nothing connected */
+		return;
+
+	usb_rescan();
+
+	ret = mkdir("/usb", 0);
+	if (ret) {
+		dev_err(dev, "Cannot mkdir /usb\n");
+		goto exit_usb_boot;
+	}
+
+	ret = mount("/dev/disk0.0", NULL, "usb", NULL);
+	if (ret) {
+		dev_warn(dev, "Filed to mount USB Disk partition with error (%i), trying bare device\n", ret);
+
+		ret = mount("/dev/disk0", NULL, "usb", NULL);
+		if (ret) {
+			dev_err(dev, "USB mount failed!\n");
+			goto exit_usb_boot;
+		}
+	}
+
+	fd = open("/usb/boot_target", O_RDONLY);
+	if (fd < 0) {
+		dev_err(dev, "Can't open /usb/boot_target file\n");
+		ret = fd;
+		goto exit_usb_boot;
+	}
+
+	size = read(fd, buf, sizeof(buf));
+	close(fd);
+	if (size < 0) {
+		ret = size;
+		goto exit_usb_boot;
+	}
+
+	/* length of "vicut1 usb", the shortest possible target */
+	if (size < sizeof("vicut1 usb")) {
+		dev_err(dev, "Invalid boot target file!\n");
+		ret = -EINVAL;
+		goto exit_usb_boot;
+	}
+
+	if (strncmp(buf, priv->name, 6) && strncmp(buf, "prti6qp ", 8)) {
+		dev_err(dev, "Boot target for a different board! (%s %s)\n",
+			buf, priv->name);
+		ret = -EINVAL;
+		goto exit_usb_boot;
+	}
+
+	second_word = strchr(buf, 32);
+	second_word++;
+
+	if (strncmp(second_word, "usb", 3) == 0) {
+		bootsrc = "disk0.0";
+	} else if (strncmp(second_word, "recovery", 8) == 0) {
+		bootsrc = "recovery";
+	} else {
+		dev_err(dev, "Unknown boot target!\n");
+		ret = -ENODEV;
+		goto exit_usb_boot;
+	}
+
+	ret = setenv("global.boot.default", bootsrc);
+	if (ret)
+		goto exit_usb_boot;
+
+	return;
+
+exit_usb_boot:
+	dev_err(dev, "Failed to run usb boot: %i\n", ret);
+
+	return;
+}
+
+static int prt_imx6_env_init(struct prt_imx6_priv *priv)
+{
+	const struct prt_machine_data *dcfg = priv->dcfg;
+	struct device_d *dev = priv->dev;
+	char *delay, *bootsrc;
+	int ret;
+
+	ret = setenv("global.linux.bootargs.base", "consoleblank=0 vt.color=0x00");
+	if (ret)
+		goto exit_env_init;
+
+	if (dcfg->flags & PRT_IMX6_USB_LONG_DELAY)
+		priv->usb_delay = 4;
+	else
+		priv->usb_delay = 1;
+
+	/* the usb_delay value is used for poller_call_async() */
+	delay = basprintf("%d", priv->usb_delay);
+	ret = setenv("global.autoboot_timeout", delay);
+	if (ret)
+		goto exit_env_init;
+
+	if (dcfg->flags & PRT_IMX6_BOOTCHOOSER)
+		bootsrc = "bootchooser";
+	else
+		bootsrc = "mmc2";
+
+	ret = setenv("global.boot.default", bootsrc);
+	if (ret)
+		goto exit_env_init;
+
+	dev_info(dev, "Board specific env init is done\n");
+	return 0;
+
+exit_env_init:
+	dev_err(dev, "Failed to set env: %i\n", ret);
+
+	return ret;
+}
+
+static int prt_imx6_bbu(struct prt_imx6_priv *priv)
+{
+	const struct prt_machine_data *dcfg = priv->dcfg;
+	u32 emmc_flags = 0;
+	int ret;
+
+	if (dcfg->flags & PRT_IMX6_BOOTSRC_SPI_NOR) {
+		ret = imx6_bbu_internal_spi_i2c_register_handler("SPI", "/dev/m25p0.barebox",
+							 BBU_HANDLER_FLAG_DEFAULT);
+		if (ret)
+			goto exit_bbu;
+	} else {
+		emmc_flags = BBU_HANDLER_FLAG_DEFAULT;
+	}
+
+	ret = imx6_bbu_internal_mmcboot_register_handler("eMMC", "/dev/mmc2",
+						   emmc_flags);
+	if (ret)
+		goto exit_bbu;
+
+	ret = imx6_bbu_internal_mmc_register_handler("SD", "/dev/mmc0", 0);
+	if (ret)
+		goto exit_bbu;
+
+	return 0;
+exit_bbu:
+	dev_err(priv->dev, "Failed to register bbu: %i\n", ret);
+	return ret;
+}
+
+static int prt_imx6_devices_init(void)
+{
+	struct prt_imx6_priv *priv = prt_priv;
+	int ret;
+
+	if (!priv)
+		return 0;
+
+	if (priv->dcfg->init) {
+		ret = priv->dcfg->init(priv);
+		if (ret)
+			return ret;
+	}
+
+	ret = prt_imx6_bbu(priv);
+	if (ret)
+		return ret;
+
+	ret = prt_imx6_read_i2c_mac_serial(priv);
+	if (ret)
+		return ret;
+
+	ret = prt_imx6_env_init(priv);
+	if (ret)
+		return ret;
+
+	ret = poller_async_register(&priv->poller, "usb-boot");
+	if (ret) {
+		dev_err(priv->dev, "can't setup poller\n");
+		return ret;
+	}
+
+	poller_call_async(&priv->poller, priv->usb_delay * SECOND,
+			  &prt_imx6_check_usb_boot, priv);
+
+	return 0;
+}
+late_initcall(prt_imx6_devices_init);
+
+static int prt_imx6_init_kvg_set_ctrl(struct prt_imx6_priv *priv, bool val)
+{
+	int ret;
+
+	ret = gpio_direction_output(GPIO_ON1_CTRL, val);
+	if (ret)
+		return ret;
+
+	ret = gpio_direction_output(GPIO_ON2_CTRL, val);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static int prt_imx6_yaco_set_kvg_power_mode(struct prt_imx6_priv *priv,
+					    char *serial)
+{
+	static const char command[] = "{\"command\":\"mode\",\"value\":\"kvg\",\"on2\":true}";
+	struct device_d *dev = priv->dev;
+	struct console_device *yccon;
+	int ret;
+
+	yccon = of_console_get_by_alias(serial);
+	if (!yccon) {
+		dev_dbg(dev, "Cant find the %s node, try later\n", serial);
+		return -EPROBE_DEFER;
+	}
+
+	ret = console_set_baudrate(yccon, 115200);
+	if (ret)
+		goto exit_yaco_set_kvg_power_mode;
+
+	yccon->puts(yccon, command, sizeof(command));
+
+	dev_info(dev, "Send YaCO power init sequence to the %s\n", serial);
+	return 0;
+
+exit_yaco_set_kvg_power_mode:
+	dev_err(dev, "Failed to set YaCO pw mode: %i", ret);
+
+	return ret;
+}
+
+static int prt_imx6_init_kvg_power(struct prt_imx6_priv *priv,
+				   enum prt_imx6_kvg_pw_mode pw_mode)
+{
+	const char *mode;
+	int ret;
+
+	ret = gpio_request_array(prt_imx6_kvg_gpios,
+				 ARRAY_SIZE(prt_imx6_kvg_gpios));
+	if (ret)
+		goto exit_init_kvg_vicut;
+
+	mdelay(1);
+
+	if (!gpio_get_value(GPIO_DIP1_FB))
+		pw_mode = PW_MODE_KUBOTA;
+
+	switch (pw_mode) {
+	case PW_MODE_KVG_WITH_YACO:
+		mode = "KVG (with YaCO)";
+
+		/* GPIO_ON1_CTRL and GPIO_ON2_CTRL are N.C. on the SoC for
+		 * older revisions */
+
+		/* Inform YaCO of power mode */
+		ret = prt_imx6_yaco_set_kvg_power_mode(priv, "serial0");
+		break;
+	case PW_MODE_KVG_NEW:
+		mode = "KVG (new)";
+
+		ret = prt_imx6_init_kvg_set_ctrl(priv, true);
+		if (ret)
+			goto exit_init_kvg_vicut;
+		break;
+	case PW_MODE_KUBOTA:
+		mode = "Kubota";
+		ret = prt_imx6_init_kvg_set_ctrl(priv, false);
+		if (ret)
+			goto exit_init_kvg_vicut;
+		break;
+	default:
+		ret = -ENODEV;
+		goto exit_init_kvg_vicut;
+	}
+
+	dev_info(priv->dev, "Power mode: %s\n", mode);
+
+	return 0;
+
+exit_init_kvg_vicut:
+	dev_err(priv->dev, "KvG power init failed: %i\n", ret);
+
+	return ret;
+}
+
+static int prt_imx6_init_victgo(struct prt_imx6_priv *priv)
+{
+	int ret = 0;
+
+	/* Bit 1 of HW-REV is pulled low by 2k2, but must be high on some
+	 * revisions
+	 */
+	if (priv->hw_rev & 2) {
+		ret = gpio_direction_output(IMX_GPIO_NR(2, 9), 1);
+		if (ret) {
+			dev_err(priv->dev, "Failed to set gpio up\n");
+			return ret;
+		}
+	}
+
+	return prt_imx6_init_kvg_power(priv, PW_MODE_KVG_NEW);
+}
+
+static int prt_imx6_init_kvg_new(struct prt_imx6_priv *priv)
+{
+	return prt_imx6_init_kvg_power(priv, PW_MODE_KVG_NEW);
+}
+
+static int prt_imx6_init_kvg_yaco(struct prt_imx6_priv *priv)
+{
+	return prt_imx6_init_kvg_power(priv, PW_MODE_KVG_WITH_YACO);
+}
+
+static int prt_imx6_rfid_fixup(struct prt_imx6_priv *priv,
+			       struct device_node *root)
+{
+	const struct prt_machine_data *dcfg = priv->dcfg;
+	struct device_node *node, *i2c_node;
+	char *eeprom_node_name, *alias;
+	int na, ns, len = 0;
+	int ret;
+	u8 *tmp;
+
+	alias = basprintf("i2c%d", dcfg->i2c_adapter);
+	if (!alias) {
+		ret = -ENOMEM;
+		goto exit_error;
+	}
+
+	i2c_node = of_find_node_by_alias(root, alias);
+	if (!i2c_node) {
+		dev_err(priv->dev, "Unsupported i2c adapter\n");
+		ret = -ENODEV;
+		goto free_alias;
+	}
+
+	eeprom_node_name = basprintf("/eeprom@%x", dcfg->i2c_addr);
+	if (!eeprom_node_name) {
+		ret = -ENOMEM;
+		goto free_alias;
+	}
+
+	node = of_create_node(i2c_node, eeprom_node_name);
+	if (!node) {
+		dev_err(priv->dev, "Failed to create node %s\n",
+			eeprom_node_name);
+		ret = -ENOMEM;
+		goto free_eeprom;
+	}
+
+	ret = of_property_write_string(node, "compatible", "atmel,24c256");
+	if (ret)
+		goto free_eeprom;
+
+	na = of_n_addr_cells(node);
+	ns = of_n_size_cells(node);
+	tmp = xzalloc((na + ns) * 4);
+
+	of_write_number(tmp + len, dcfg->i2c_addr, na);
+	len += na * 4;
+	of_write_number(tmp + len, 0, ns);
+	len += ns * 4;
+
+	ret = of_set_property(node, "reg", tmp, len, 1);
+	kfree(tmp);
+	if (ret)
+		goto free_eeprom;
+
+	return 0;
+free_eeprom:
+	kfree(eeprom_node_name);
+free_alias:
+	kfree(alias);
+exit_error:
+	dev_err(priv->dev, "Failed to apply fixup: %i\n", ret);
+	return ret;
+}
+
+static int prt_imx6_of_fixup(struct device_node *root, void *data)
+{
+	struct prt_imx6_priv *priv = data;
+	int ret;
+
+	if (!root) {
+		dev_err(priv->dev, "Unable to find the root node\n");
+		return -ENODEV;
+	}
+
+	ret = prt_imx6_rfid_fixup(priv, root);
+	if (ret)
+		goto exit_of_fixups;
+
+	return 0;
+exit_of_fixups:
+	dev_err(priv->dev, "Failed to apply OF fixups: %i\n", ret);
+	return ret;
+}
+
+static int prt_imx6_get_id(struct prt_imx6_priv *priv)
+{
+	struct gpio gpios_type[] = GPIO_HW_TYPE_ID;
+	struct gpio gpios_rev[] = GPIO_HW_REV_ID;
+	int ret;
+
+	ret = gpio_array_to_id(gpios_type, ARRAY_SIZE(gpios_type), &priv->hw_id);
+	if (ret)
+		goto exit_get_id;
+
+	ret = gpio_array_to_id(gpios_rev, ARRAY_SIZE(gpios_rev), &priv->hw_rev);
+	if (ret)
+		goto exit_get_id;
+
+	return 0;
+exit_get_id:
+	dev_err(priv->dev, "Failed to read gpio ID: %i\n", ret);
+	return ret;
+}
+
+static int prt_imx6_get_dcfg(struct prt_imx6_priv *priv)
+{
+	const struct prt_machine_data *dcfg, *found = NULL;
+	int ret;
+
+	dcfg = of_device_get_match_data(priv->dev);
+	if (!dcfg) {
+		ret = -EINVAL;
+		goto exit_get_dcfg;
+	}
+
+	for (; dcfg->hw_id != UINT_MAX; dcfg++) {
+		if (dcfg->hw_id != priv->hw_id)
+			continue;
+		if (dcfg->hw_rev > priv->hw_rev)
+			break;
+		found = dcfg;
+	}
+
+	if (!found) {
+		ret = -ENODEV;
+		goto exit_get_dcfg;
+	}
+
+	priv->dcfg = found;
+
+	return 0;
+exit_get_dcfg:
+	dev_err(priv->dev, "Failed to get dcfg: %i\n", ret);
+	return ret;
+}
+
+static int prt_imx6_probe(struct device_d *dev)
+{
+	struct prt_imx6_priv *priv;
+	const char *name, *ptr;
+	struct param_d *p;
+	int ret;
+
+	priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	priv->dev = dev;
+	name = of_device_get_match_compatible(priv->dev);
+	ptr = strchr(name, ',');
+	priv->name =  ptr ? ptr + 1 : name;
+
+	pr_info("Detected machine type: %s\n", priv->name);
+
+	ret = prt_imx6_get_id(priv);
+	if (ret)
+		goto free_priv;
+
+	pr_info("  HW type:     %d\n", priv->hw_id);
+	pr_info("  HW revision: %d\n", priv->hw_rev);
+
+	ret = prt_imx6_get_dcfg(priv);
+	if (ret)
+		goto free_priv;
+
+	p = dev_add_param_uint32_ro(dev, "boardrev", &priv->hw_rev, "%u");
+	if (IS_ERR(p)) {
+		ret = PTR_ERR(p);
+		goto free_priv;
+	}
+
+	p = dev_add_param_uint32_ro(dev, "boardid", &priv->hw_id, "%u");
+	if (IS_ERR(p)) {
+		ret = PTR_ERR(p);
+		goto free_priv;
+	}
+
+	ret = prt_imx6_of_fixup(of_get_root_node(), priv);
+	if (ret)
+		goto free_priv;
+
+	ret = of_register_fixup(prt_imx6_of_fixup, priv);
+	if (ret) {
+		dev_err(dev, "Failed to register fixup\n");
+		goto free_priv;
+	}
+
+	prt_priv = priv;
+
+	return 0;
+free_priv:
+	kfree(priv);
+	return ret;
+}
+
+static const struct prt_machine_data prt_imx6_cfg_alti6p[] = {
+	{
+		.hw_id = HW_TYPE_ALTI6P,
+		.hw_rev = 0,
+		.i2c_addr = 0x51,
+		.i2c_adapter = 0,
+		.flags = PRT_IMX6_BOOTSRC_EMMC,
+	}, {
+		.hw_id = UINT_MAX
+	},
+};
+
+static const struct prt_machine_data prt_imx6_cfg_victgo[] = {
+	{
+		.hw_id = HW_TYPE_VICTGO,
+		.hw_rev = 0,
+		.i2c_addr = 0x51,
+		.i2c_adapter = 0,
+		.init = prt_imx6_init_victgo,
+		.flags = PRT_IMX6_BOOTSRC_SPI_NOR,
+	}, {
+		.hw_id = UINT_MAX
+	},
+};
+
+static const struct prt_machine_data prt_imx6_cfg_vicut1[] = {
+	{
+		.hw_id = HW_TYPE_VICUT1,
+		.hw_rev = 0,
+		.i2c_addr = 0x50,
+		.i2c_adapter = 1,
+		.flags = PRT_IMX6_BOOTSRC_SPI_NOR,
+	}, {
+		.hw_id = HW_TYPE_VICUT1,
+		.hw_rev = 1,
+		.i2c_addr = 0x51,
+		.i2c_adapter = 0,
+		.init = prt_imx6_init_kvg_yaco,
+		.flags = PRT_IMX6_BOOTSRC_SPI_NOR,
+	}, {
+		.hw_id = HW_TYPE_VICUT2,
+		.hw_rev = 1,
+		.i2c_addr = 0x51,
+		.i2c_adapter = 0,
+		.init = prt_imx6_init_kvg_new,
+		.flags = PRT_IMX6_BOOTSRC_SPI_NOR,
+	}, {
+		.hw_id = UINT_MAX
+	},
+};
+
+static const struct prt_machine_data prt_imx6_cfg_vicut1q[] = {
+	{
+		.hw_id = HW_TYPE_VICUT1,
+		.hw_rev = 0,
+		.i2c_addr = 0x50,
+		.i2c_adapter = 1,
+		.flags = PRT_IMX6_BOOTSRC_SPI_NOR,
+	}, {
+		.hw_id = HW_TYPE_VICUT1,
+		.hw_rev = 1,
+		.i2c_addr = 0x51,
+		.i2c_adapter = 0,
+		.init = prt_imx6_init_kvg_yaco,
+		.flags = PRT_IMX6_BOOTSRC_SPI_NOR,
+	}, {
+		.hw_id = HW_TYPE_VICUT2,
+		.hw_rev = 0,
+		.i2c_addr = 0x51,
+		.i2c_adapter = 0,
+		.init = prt_imx6_init_kvg_yaco,
+		.flags = PRT_IMX6_BOOTSRC_SPI_NOR,
+	}, {
+		.hw_id = HW_TYPE_VICUT2,
+		.hw_rev = 1,
+		.i2c_addr = 0x51,
+		.i2c_adapter = 0,
+		.init = prt_imx6_init_kvg_new,
+		.flags = PRT_IMX6_BOOTSRC_SPI_NOR,
+	}, {
+		.hw_id = UINT_MAX
+	},
+};
+
+static const struct prt_machine_data prt_imx6_cfg_vicutp[] = {
+	{
+		.hw_id = HW_TYPE_VICUT2,
+		.hw_rev = 1,
+		.i2c_addr = 0x51,
+		.i2c_adapter = 0,
+		.init = prt_imx6_init_kvg_new,
+		.flags = PRT_IMX6_BOOTSRC_SPI_NOR,
+	}, {
+		.hw_id = UINT_MAX
+	},
+};
+
+static const struct prt_machine_data prt_imx6_cfg_lanmcu[] = {
+	{
+		.hw_id = HW_TYPE_LANMCU,
+		.hw_rev = 0,
+		.i2c_addr = 0x51,
+		.i2c_adapter = 0,
+		.flags = PRT_IMX6_BOOTSRC_EMMC | PRT_IMX6_BOOTCHOOSER,
+	}, {
+		.hw_id = UINT_MAX
+	},
+};
+
+static const struct prt_machine_data prt_imx6_cfg_plybas[] = {
+	{
+		.hw_id = HW_TYPE_PLYBAS,
+		.hw_rev = 0,
+		.i2c_addr = 0x51,
+		.i2c_adapter = 0,
+		.flags = PRT_IMX6_BOOTSRC_SPI_NOR | PRT_IMX6_USB_LONG_DELAY,
+	}, {
+		.hw_id = UINT_MAX
+	},
+};
+
+static const struct prt_machine_data prt_imx6_cfg_plym2m[] = {
+	{
+		.hw_id = HW_TYPE_PLYM2M,
+		.hw_rev = 0,
+		.i2c_addr = 0x51,
+		.i2c_adapter = 0,
+		.flags = PRT_IMX6_BOOTSRC_SPI_NOR | PRT_IMX6_USB_LONG_DELAY,
+	}, {
+		.hw_id = UINT_MAX
+	},
+};
+
+static const struct prt_machine_data prt_imx6_cfg_prti6g[] = {
+	{
+		.hw_id = HW_TYPE_PRTI6G,
+		.hw_rev = 0,
+		.i2c_addr = 0x51,
+		.i2c_adapter = 0,
+		.flags = PRT_IMX6_BOOTSRC_EMMC,
+	}, {
+		.hw_id = UINT_MAX
+	},
+};
+
+static const struct prt_machine_data prt_imx6_cfg_prti6q[] = {
+	{
+		.hw_id = HW_TYPE_PRTI6Q,
+		.hw_rev = 0,
+		.i2c_addr = 0x51,
+		.i2c_adapter = 2,
+		.flags = PRT_IMX6_BOOTSRC_SPI_NOR,
+	}, {
+		.hw_id = HW_TYPE_PRTI6Q,
+		.hw_rev = 1,
+		.i2c_addr = 0x51,
+		.i2c_adapter = 0,
+		.flags = PRT_IMX6_BOOTSRC_SPI_NOR,
+	}, {
+		.hw_id = UINT_MAX
+	},
+};
+
+static const struct prt_machine_data prt_imx6_cfg_prtmvt[] = {
+	{
+		.hw_id = HW_TYPE_PRTMVT,
+		.hw_rev = 0,
+		.i2c_addr = 0x51,
+		.i2c_adapter = 0,
+		.flags = PRT_IMX6_BOOTSRC_SPI_NOR,
+	}, {
+		.hw_id = UINT_MAX
+	},
+};
+
+static const struct prt_machine_data prt_imx6_cfg_prtrvt[] = {
+	{
+		.hw_id = HW_TYPE_PRTRVT,
+		.hw_rev = 0,
+		.i2c_addr = 0x51,
+		.i2c_adapter = 0,
+		.flags = PRT_IMX6_BOOTSRC_SPI_NOR,
+	}, {
+		.hw_id = UINT_MAX
+	},
+};
+
+static const struct prt_machine_data prt_imx6_cfg_prtvt7[] = {
+	{
+		.hw_id = HW_TYPE_PRTVT7,
+		.hw_rev = 0,
+		.i2c_addr = 0x51,
+		.i2c_adapter = 0,
+		.flags = PRT_IMX6_BOOTSRC_EMMC | PRT_IMX6_BOOTCHOOSER,
+	}, {
+		.hw_id = UINT_MAX
+	},
+};
+
+static const struct prt_machine_data prt_imx6_cfg_prtwd2[] = {
+	{
+		.hw_id = HW_TYPE_PRTWD2,
+		.hw_rev = 0,
+		.i2c_addr = 0x51,
+		.i2c_adapter = 0,
+		.flags = PRT_IMX6_BOOTSRC_EMMC,
+	}, {
+		.hw_id = UINT_MAX
+	},
+};
+
+static const struct prt_machine_data prt_imx6_cfg_prtwd3[] = {
+	{
+		.hw_id = HW_TYPE_PRTWD2,
+		.hw_rev = 2,
+		.i2c_addr = 0x51,
+		.i2c_adapter = 0,
+		.flags = PRT_IMX6_BOOTSRC_EMMC,
+	}, {
+		.hw_id = UINT_MAX
+	},
+};
+
+static const struct of_device_id prt_imx6_of_match[] = {
+	{ .compatible = "alt,alti6p", .data = &prt_imx6_cfg_alti6p },
+	{ .compatible = "kvg,victgo", .data = &prt_imx6_cfg_victgo },
+	{ .compatible = "kvg,vicut1", .data = &prt_imx6_cfg_vicut1 },
+	{ .compatible = "kvg,vicut1q", .data = &prt_imx6_cfg_vicut1q },
+	{ .compatible = "kvg,vicutp", .data = &prt_imx6_cfg_vicutp },
+	{ .compatible = "lan,lanmcu", .data = &prt_imx6_cfg_lanmcu },
+	{ .compatible = "ply,plybas", .data = &prt_imx6_cfg_plybas },
+	{ .compatible = "ply,plym2m", .data = &prt_imx6_cfg_plym2m },
+	{ .compatible = "prt,prti6g", .data = &prt_imx6_cfg_prti6g },
+	{ .compatible = "prt,prti6q", .data = &prt_imx6_cfg_prti6q },
+	{ .compatible = "prt,prtmvt", .data = &prt_imx6_cfg_prtmvt },
+	{ .compatible = "prt,prtrvt", .data = &prt_imx6_cfg_prtrvt },
+	{ .compatible = "prt,prtvt7", .data = &prt_imx6_cfg_prtvt7 },
+	{ .compatible = "prt,prtwd2", .data = &prt_imx6_cfg_prtwd2 },
+	{ .compatible = "prt,prtwd3", .data = &prt_imx6_cfg_prtwd3 },
+	{ /* sentinel */ },
+};
+
+static struct driver_d prt_imx6_board_driver = {
+	.name = "board-protonic-imx6",
+	.probe = prt_imx6_probe,
+	.of_compatible = DRV_OF_COMPAT(prt_imx6_of_match),
+};
+postcore_platform_driver(prt_imx6_board_driver);
-- 
2.28.0


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

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

* [PATCH v3 5/6] ARM: dts: unify barebox and barebox, env partitions for all Protonic boards
  2020-08-13 12:55 [PATCH v3 0/6] prepare Protonic board code for mainline Oleksij Rempel
                   ` (3 preceding siblings ...)
  2020-08-13 12:55 ` [PATCH v3 4/6] ARM: protonic-imx6: port Protonic specific board code Oleksij Rempel
@ 2020-08-13 12:55 ` Oleksij Rempel
  2020-08-13 12:55 ` [PATCH v3 6/6] ARM: dts: imx6q-prti6q: add pstore/ramoops node Oleksij Rempel
  5 siblings, 0 replies; 9+ messages in thread
From: Oleksij Rempel @ 2020-08-13 12:55 UTC (permalink / raw)
  To: barebox, david; +Cc: Oleksij Rempel

Signed-off-by: Oleksij Rempel <o.rempel@pengutronix.de>
---
 arch/arm/dts/imx6dl-plym2m.dts       | 25 +++++++++++++++++++++++++
 arch/arm/dts/imx6dl-prtrvt.dts       |  1 +
 arch/arm/dts/imx6q-prti6q.dts        | 24 +-----------------------
 arch/arm/dts/imx6qdl-prti6q-nor.dtsi | 10 ++++++++++
 arch/arm/dts/imx6qdl-prti6q.dtsi     | 20 ++++++++++++++++++++
 arch/arm/dts/imx6qdl-vicut1.dtsi     | 26 ++++++++++++++++++++++++++
 6 files changed, 83 insertions(+), 23 deletions(-)
 create mode 100644 arch/arm/dts/imx6qdl-prti6q-nor.dtsi

diff --git a/arch/arm/dts/imx6dl-plym2m.dts b/arch/arm/dts/imx6dl-plym2m.dts
index b66321fb46..335cb6f342 100644
--- a/arch/arm/dts/imx6dl-plym2m.dts
+++ b/arch/arm/dts/imx6dl-plym2m.dts
@@ -6,6 +6,7 @@
 /dts-v1/;
 #include <arm/imx6dl.dtsi>
 #include "imx6qdl-prti6q.dtsi"
+#include "imx6qdl-prti6q-nor.dtsi"
 
 / {
 	model = "Plymovent M2M board";
@@ -28,6 +29,20 @@
 	};
 };
 
+&ecspi1 {
+	cs-gpios = <&gpio3 19 GPIO_ACTIVE_HIGH>;
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_ecspi1>;
+	status = "okay";
+
+	flash@0 {
+		compatible = "jedec,spi-nor";
+		reg = <0>;
+		spi-max-frequency = <20000000>;
+		#address-cells = <1>;
+		#size-cells = <1>;
+	};
+};
 
 &fec {
 	pinctrl-names = "default";
@@ -58,6 +73,16 @@
 		>;
 	};
 
+	pinctrl_ecspi1: ecspi1grp {
+		fsl,pins = <
+			MX6QDL_PAD_EIM_D17__ECSPI1_MISO		0x100b1
+			MX6QDL_PAD_EIM_D18__ECSPI1_MOSI		0x100b1
+			MX6QDL_PAD_EIM_D16__ECSPI1_SCLK		0x100b1
+			/* CS */
+			MX6QDL_PAD_EIM_D19__GPIO3_IO19		0x000b1
+		>;
+	};
+
 	pinctrl_usbotg: usbotggrp {
 		fsl,pins = <
 			MX6QDL_PAD_EIM_D21__USB_OTG_OC	0x1b0b0
diff --git a/arch/arm/dts/imx6dl-prtrvt.dts b/arch/arm/dts/imx6dl-prtrvt.dts
index 802bd50ae6..c403ba3ea7 100644
--- a/arch/arm/dts/imx6dl-prtrvt.dts
+++ b/arch/arm/dts/imx6dl-prtrvt.dts
@@ -6,6 +6,7 @@
 /dts-v1/;
 #include <arm/imx6dl.dtsi>
 #include "imx6qdl-prti6q.dtsi"
+#include "imx6qdl-prti6q-nor.dtsi"
 #include <dt-bindings/leds/common.h>
 
 / {
diff --git a/arch/arm/dts/imx6q-prti6q.dts b/arch/arm/dts/imx6q-prti6q.dts
index 76bb4d53d3..63a02149f1 100644
--- a/arch/arm/dts/imx6q-prti6q.dts
+++ b/arch/arm/dts/imx6q-prti6q.dts
@@ -6,6 +6,7 @@
 /dts-v1/;
 #include <arm/imx6q.dtsi>
 #include "imx6qdl-prti6q.dtsi"
+#include "imx6qdl-prti6q-nor.dtsi"
 #include <dt-bindings/leds/common.h>
 #include <dt-bindings/sound/fsl-imx-audmux.h>
 
@@ -13,13 +14,6 @@
 	model = "Protonic PRTI6Q board";
 	compatible = "prt,prti6q", "fsl,imx6q";
 
-	chosen {
-		environment {
-			compatible = "barebox,environment";
-			device-path = &ecspi1, "partname:env";
-		};
-	};
-
 	memory@10000000 {
 		device_type = "memory";
 		reg = <0x10000000 0xf0000000>;
@@ -161,24 +155,8 @@
 		compatible = "jedec,spi-nor";
 		reg = <0>;
 		spi-max-frequency = <20000000>;
-
 		#address-cells = <1>;
 		#size-cells = <1>;
-
-		partition@0 {
-			label = "boot";
-			reg = <0x0 0x100000>;
-		};
-
-		partition@100000 {
-			label = "env";
-			reg = <0x100000 0x10000>;
-		};
-
-		partition@110000 {
-			label = "spare";
-			reg = <0x110000 0x2f0000>;
-		};
 	};
 };
 
diff --git a/arch/arm/dts/imx6qdl-prti6q-nor.dtsi b/arch/arm/dts/imx6qdl-prti6q-nor.dtsi
new file mode 100644
index 0000000000..ad718ce421
--- /dev/null
+++ b/arch/arm/dts/imx6qdl-prti6q-nor.dtsi
@@ -0,0 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-or-later OR MIT
+
+&ecspi1 {
+	flash@0 {
+		partition@0 {
+			label = "barebox";
+			reg = <0x0 0x100000>;
+		};
+	};
+};
diff --git a/arch/arm/dts/imx6qdl-prti6q.dtsi b/arch/arm/dts/imx6qdl-prti6q.dtsi
index ed526d185f..19acca042d 100644
--- a/arch/arm/dts/imx6qdl-prti6q.dtsi
+++ b/arch/arm/dts/imx6qdl-prti6q.dtsi
@@ -9,6 +9,11 @@
 / {
 	chosen {
 		stdout-path = &uart4;
+
+		environment-emmc {
+			compatible = "barebox,environment";
+			device-path = &usdhc3, "partname:barebox-environment";
+		};
 	};
 
 	reg_1v8: regulator-1v8 {
@@ -105,7 +110,22 @@
 	pinctrl-0 = <&pinctrl_usdhc3>;
 	bus-width = <8>;
 	non-removable;
+	no-sdio;
+	no-sd;
 	status = "okay";
+
+	#address-cells = <1>;
+	#size-cells = <1>;
+
+	partition@100000 {
+		label = "barebox-environment";
+		reg = <0x100000 0x100000>;
+	};
+
+	partition@200000 {
+		label = "state";
+		reg = <0x200000 0x100000>;
+	};
 };
 
 &iomuxc {
diff --git a/arch/arm/dts/imx6qdl-vicut1.dtsi b/arch/arm/dts/imx6qdl-vicut1.dtsi
index dc18614f89..dbfcf2527c 100644
--- a/arch/arm/dts/imx6qdl-vicut1.dtsi
+++ b/arch/arm/dts/imx6qdl-vicut1.dtsi
@@ -4,6 +4,7 @@
  */
 
 #include "imx6qdl-prti6q.dtsi"
+#include "imx6qdl-prti6q-nor.dtsi"
 #include <dt-bindings/input/input.h>
 
 / {
@@ -74,6 +75,21 @@
 	};
 };
 
+&ecspi1 {
+	cs-gpios = <&gpio3 19 GPIO_ACTIVE_HIGH>;
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_ecspi1>;
+	status = "okay";
+
+	flash@0 {
+		compatible = "jedec,spi-nor";
+		reg = <0>;
+		spi-max-frequency = <20000000>;
+		#address-cells = <1>;
+		#size-cells = <1>;
+	};
+};
+
 &iomuxc {
 	pinctrl_hog: hoggrp {
 		fsl,pins = <
@@ -151,6 +167,16 @@
 		>;
 	};
 
+	pinctrl_ecspi1: ecspi1grp {
+		fsl,pins = <
+			MX6QDL_PAD_EIM_D17__ECSPI1_MISO		0x100b1
+			MX6QDL_PAD_EIM_D18__ECSPI1_MOSI		0x100b1
+			MX6QDL_PAD_EIM_D16__ECSPI1_SCLK		0x100b1
+			/* CS */
+			MX6QDL_PAD_EIM_D19__GPIO3_IO19		0x000b1
+		>;
+	};
+
 	pinctrl_usbotg: usbotggrp {
 		fsl,pins = <
 			MX6QDL_PAD_EIM_D21__USB_OTG_OC	0x1b0b0
-- 
2.28.0


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

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

* [PATCH v3 6/6] ARM: dts: imx6q-prti6q: add pstore/ramoops node
  2020-08-13 12:55 [PATCH v3 0/6] prepare Protonic board code for mainline Oleksij Rempel
                   ` (4 preceding siblings ...)
  2020-08-13 12:55 ` [PATCH v3 5/6] ARM: dts: unify barebox and barebox, env partitions for all Protonic boards Oleksij Rempel
@ 2020-08-13 12:55 ` Oleksij Rempel
  5 siblings, 0 replies; 9+ messages in thread
From: Oleksij Rempel @ 2020-08-13 12:55 UTC (permalink / raw)
  To: barebox, david; +Cc: Oleksij Rempel

Signed-off-by: Oleksij Rempel <o.rempel@pengutronix.de>
---
 arch/arm/dts/imx6qdl-prti6q.dtsi | 11 +++++++++++
 1 file changed, 11 insertions(+)

diff --git a/arch/arm/dts/imx6qdl-prti6q.dtsi b/arch/arm/dts/imx6qdl-prti6q.dtsi
index 19acca042d..f2b36553d4 100644
--- a/arch/arm/dts/imx6qdl-prti6q.dtsi
+++ b/arch/arm/dts/imx6qdl-prti6q.dtsi
@@ -16,6 +16,17 @@
 		};
 	};
 
+	reserved-memory {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		ranges;
+
+		/* Address will be determined by the bootloader */
+		ramoops {
+			compatible = "ramoops";
+		};
+	};
+
 	reg_1v8: regulator-1v8 {
 		compatible = "regulator-fixed";
 		regulator-name = "1v8";
-- 
2.28.0


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

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

* Re: [PATCH v3 4/6] ARM: protonic-imx6: port Protonic specific board code
  2020-08-13 12:55 ` [PATCH v3 4/6] ARM: protonic-imx6: port Protonic specific board code Oleksij Rempel
@ 2020-08-13 14:07   ` David Jander
  2020-08-17  6:54     ` Oleksij Rempel
  0 siblings, 1 reply; 9+ messages in thread
From: David Jander @ 2020-08-13 14:07 UTC (permalink / raw)
  To: Oleksij Rempel; +Cc: barebox

On Thu, 13 Aug 2020 14:55:12 +0200
Oleksij Rempel <o.rempel@pengutronix.de> wrote:

> Signed-off-by: Oleksij Rempel <o.rempel@pengutronix.de>
> ---
>  arch/arm/boards/protonic-imx6/Makefile |    1 +
>  arch/arm/boards/protonic-imx6/board.c  | 1002 ++++++++++++++++++++++++
>  2 files changed, 1003 insertions(+)
>  create mode 100644 arch/arm/boards/protonic-imx6/board.c
> 
> diff --git a/arch/arm/boards/protonic-imx6/Makefile b/arch/arm/boards/protonic-imx6/Makefile
> index b08c4a93ca..01c7a259e9 100644
> --- a/arch/arm/boards/protonic-imx6/Makefile
> +++ b/arch/arm/boards/protonic-imx6/Makefile
> @@ -1 +1,2 @@
> +obj-y += board.o
>  lwl-y += lowlevel.o
> diff --git a/arch/arm/boards/protonic-imx6/board.c b/arch/arm/boards/protonic-imx6/board.c
> new file mode 100644
> index 0000000000..f3bd0dd86a
> --- /dev/null
> +++ b/arch/arm/boards/protonic-imx6/board.c
> @@ -0,0 +1,1002 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +// SPDX-FileCopyrightText: 2012 Steffen Trumtrar, Pengutronix
> +// SPDX-FileCopyrightText: 2014 Protonic Holland
> +// SPDX-FileCopyrightText: 2020 Oleksij Rempel, Pengutronix
> +
> +#include <bbu.h>
> +#include <common.h>
> +#include <environment.h>
> +#include <gpio.h>
> +#include <mach/bbu.h>
> +#include <mach/imx6.h>
> +#include <of_device.h>
> +
> +#include <usb/usb.h>
> +#include <sys/mount.h>
> +#include <sys/stat.h>
> +#include <fcntl.h>
> +#include <unistd.h>
> +#include <net.h>
> +#include <i2c/i2c.h>
> +
> +#define GPIO_HW_REV_ID  {\
> +	{IMX_GPIO_NR(2, 8), GPIOF_DIR_IN | GPIOF_ACTIVE_LOW, "rev_id0"}, \
> +	{IMX_GPIO_NR(2, 9), GPIOF_DIR_IN | GPIOF_ACTIVE_LOW, "rev_id1"}, \
> +	{IMX_GPIO_NR(2, 10), GPIOF_DIR_IN | GPIOF_ACTIVE_LOW, "rev_id2"} \
> +}
> +
> +#define GPIO_HW_TYPE_ID  {\
> +	{IMX_GPIO_NR(2, 11), GPIOF_DIR_IN | GPIOF_ACTIVE_LOW, "hw_id0"}, \
> +	{IMX_GPIO_NR(2, 12), GPIOF_DIR_IN | GPIOF_ACTIVE_LOW, "hw_id1"}, \
> +	{IMX_GPIO_NR(2, 13), GPIOF_DIR_IN | GPIOF_ACTIVE_LOW, "hw_id2"}, \
> +	{IMX_GPIO_NR(2, 14), GPIOF_DIR_IN | GPIOF_ACTIVE_LOW, "hw_id3"}, \
> +	{IMX_GPIO_NR(2, 15), GPIOF_DIR_IN | GPIOF_ACTIVE_LOW, "hw_id4"} \
> +}
> +
> +enum {
> +	HW_TYPE_PRTI6Q = 0,
> +	HW_TYPE_PRTWD2 = 1,
> +	HW_TYPE_ALTI6S = 2,
> +	HW_TYPE_VICUT1 = 4,
> +	HW_TYPE_ALTI6P = 6,
> +	HW_TYPE_PRTMVT = 8,
> +	HW_TYPE_PRTI6G = 10,
> +	HW_TYPE_PRTRVT = 12,
> +	HW_TYPE_VICUT2 = 16,
> +	HW_TYPE_PLYM2M = 20,
> +	HW_TYPE_PRTVT7 = 22,
> +	HW_TYPE_LANMCU = 23,
> +	HW_TYPE_PLYBAS = 24,
> +	HW_TYPE_VICTGO = 28,
> +};
> +
> +enum prt_imx6_kvg_pw_mode {
> +	PW_MODE_KVG_WITH_YACO = 0,
> +	PW_MODE_KVG_NEW = 1,
> +	PW_MODE_KUBOTA = 2,
> +};
> +
> +/* board specific flags */
> +#define PRT_IMX6_BOOTCHOOSER		BIT(3)
> +#define PRT_IMX6_USB_LONG_DELAY		BIT(2)
> +#define PRT_IMX6_BOOTSRC_EMMC		BIT(1)
> +#define PRT_IMX6_BOOTSRC_SPI_NOR	BIT(0)
> +
> +static struct prt_imx6_priv *prt_priv;
> +struct prt_machine_data {
> +	unsigned int hw_id;
> +	unsigned int hw_rev;
> +	unsigned int i2c_addr;
> +	unsigned int i2c_adapter;
> +	unsigned int flags;
> +	int (*init)(struct prt_imx6_priv *priv);
> +};
> +
> +struct prt_imx6_priv {
> +	struct device_d *dev;
> +	const struct prt_machine_data *dcfg;
> +	unsigned int hw_id;
> +	unsigned int hw_rev;
> +	const char *name;
> +	struct poller_async poller;
> +	unsigned int usb_delay;
> +};
> +
> +struct prti6q_rfid_contents {
> +	u8 mac[6];
> +	char serial[10];
> +	u8 cs;
> +} __attribute__ ((packed));
> +
> +#define GPIO_DIP1_FB   IMX_GPIO_NR(4, 18)
> +#define GPIO_FORCE_ON1 IMX_GPIO_NR(2, 30)
> +#define GPIO_ON1_CTRL  IMX_GPIO_NR(4, 21)
> +#define GPIO_ON2_CTRL  IMX_GPIO_NR(4, 22)
> +
> +static const struct gpio prt_imx6_kvg_gpios[] = {
> +	{
> +		.gpio = GPIO_DIP1_FB,
> +		.flags = GPIOF_IN,
> +		.label = "DIP1_FB",
> +	},
> +	{
> +		.gpio = GPIO_FORCE_ON1,
> +		.flags = GPIOF_OUT_INIT_HIGH,
> +		.label = "FORCE_ON1",
> +	},
> +	{
> +		.gpio = GPIO_ON1_CTRL,
> +		.flags = GPIOF_IN,
> +		.label = "ON1_CTRL",
> +	},
> +	{
> +		.gpio = GPIO_ON2_CTRL,
> +		.flags = GPIOF_IN,
> +		.label = "ON2_CTRL",
> +	},
> +};
> +
> +static int prt_imx6_read_rfid(struct prt_imx6_priv *priv, void *buf,
> +			      size_t size)
> +{
> +	const struct prt_machine_data *dcfg = priv->dcfg;
> +	struct device_d *dev = priv->dev;
> +	struct i2c_client cl;
> +	int ret;
> +
> +	cl.addr = dcfg->i2c_addr;
> +	cl.adapter = i2c_get_adapter(dcfg->i2c_adapter);
> +	if (!cl.adapter) {
> +		dev_err(dev, "i2c bus not found\n");
> +		return -ENODEV;
> +	}
> +
> +	/* 0x6000 user storage in the RFID tag */
> +	ret = i2c_read_reg(&cl, 0x6000 | I2C_ADDR_16_BIT, buf, size);
> +	if (ret < 0) {
> +		dev_err(dev, "Filed to read the RFID: %i\n", ret);
> +		return ret;
> +	}
> +
> +	return 0;
> +}
> +
> +static u8 prt_imx6_calc_rfid_crc(void *buf, size_t size)
> +{

This is really a simple checksum, not a form of CRC code, so maybe
prt_imx6_calc_rfid_cs is a better name for the function.

> +	unsigned int cs = 0;
> +	u8 *dat = buf;
> +	int t;
> +
> +	for (t = 0; t < size - 1; t++) {
> +		cs += dat[t];
> +	}
> +
> +	cs ^= 0xff;
> +
> +	return cs & 0xff;
> +
> +}
> +
> +static int prt_imx6_set_mac(struct prt_imx6_priv *priv,
> +			    struct prti6q_rfid_contents *rfid)
> +{
> +	struct device_d *dev = priv->dev;
> +	struct device_node *node;
> +
> +	node = of_find_node_by_alias(of_get_root_node(), "ethernet0");
> +	if (!node) {
> +		dev_err(dev, "Cannot find FEC!\n");
> +		return -ENODEV;
> +	}
> +
> +	if (!is_valid_ether_addr(&rfid->mac[0])) {
> +		dev_err(dev, "bad MAC addr\n");
> +		return -EILSEQ;
> +	}
> +
> +	of_eth_register_ethaddr(node, &rfid->mac[0]);
> +
> +	return 0;
> +}
> +
> +static int prt_of_fixup_serial(struct device_node *dstroot, void *arg)
> +{
> +	struct device_node *srcroot = arg;
> +	const char *ser;
> +	int len;
> +
> +	ser = of_get_property(srcroot, "serial-number", &len);
> +	return of_set_property(dstroot, "serial-number", ser, len, 1);
> +}
> +
> +static void prt_oftree_fixup_serial(const char *serial)
> +{
> +	struct device_node *root = of_get_root_node();
> +
> +	of_set_property(root, "serial-number", serial, strlen(serial) + 1, 1);
> +	of_register_fixup(prt_of_fixup_serial, root);
> +}
> +
> +static int prt_imx6_set_serial(struct prt_imx6_priv *priv,
> +			       struct prti6q_rfid_contents *rfid)
> +{
> +	rfid->serial[9] = 0; /* Failsafe */
> +	dev_info(priv->dev, "Serial number: %s\n", rfid->serial);
> +	prt_oftree_fixup_serial(rfid->serial);
> +
> +	return 0;
> +}
> +
> +static int prt_imx6_read_i2c_mac_serial(struct prt_imx6_priv *priv)
> +{
> +	struct device_d *dev = priv->dev;
> +	struct prti6q_rfid_contents rfid;
> +	int ret;
> +
> +	ret = prt_imx6_read_rfid(priv, &rfid, sizeof(rfid));
> +	if (ret)
> +		return ret;
> +
> +	if (rfid.cs != prt_imx6_calc_rfid_crc(&rfid, sizeof(rfid))) {
> +		dev_err(dev, "RFID: bad checksum!\n");
> +		return -EBADMSG;
> +	}
> +
> +	ret = prt_imx6_set_mac(priv, &rfid);
> +	if (ret)
> +		return ret;
> +
> +	ret = prt_imx6_set_serial(priv, &rfid);
> +	if (ret)
> +		return ret;
> +
> +	return 0;
> +}
> +
> +#define OTG_PORTSC1 (MX6_OTG_BASE_ADDR+0x184)
> +
> +static void prt_imx6_check_usb_boot(void *data)
> +{
> +	struct prt_imx6_priv *priv = data;
> +	struct device_d *dev = priv->dev;
> +	char *second_word, *bootsrc;
> +	unsigned int v;
> +	ssize_t size;
> +	char buf[16];
> +	int fd, ret;
> +
> +	v = *((unsigned int *)OTG_PORTSC1);
> +	if ((v & 0x0c00) == 0) /* LS == SE0 ==> nothing connected */
> +		return;
> +
> +	usb_rescan();
> +
> +	ret = mkdir("/usb", 0);
> +	if (ret) {
> +		dev_err(dev, "Cannot mkdir /usb\n");
> +		goto exit_usb_boot;
> +	}
> +
> +	ret = mount("/dev/disk0.0", NULL, "usb", NULL);
> +	if (ret) {
> +		dev_warn(dev, "Filed to mount USB Disk partition with error (%i), trying bare device\n", ret);
> +
> +		ret = mount("/dev/disk0", NULL, "usb", NULL);
> +		if (ret) {
> +			dev_err(dev, "USB mount failed!\n");
> +			goto exit_usb_boot;
> +		}
> +	}
> +
> +	fd = open("/usb/boot_target", O_RDONLY);
> +	if (fd < 0) {
> +		dev_err(dev, "Can't open /usb/boot_target file\n");
> +		ret = fd;
> +		goto exit_usb_boot;
> +	}
> +
> +	size = read(fd, buf, sizeof(buf));
> +	close(fd);
> +	if (size < 0) {
> +		ret = size;
> +		goto exit_usb_boot;
> +	}
> +
> +	/* length of "vicut1 usb", the shortest possible target */
> +	if (size < sizeof("vicut1 usb")) {
> +		dev_err(dev, "Invalid boot target file!\n");
> +		ret = -EINVAL;
> +		goto exit_usb_boot;
> +	}
> +
> +	if (strncmp(buf, priv->name, 6) && strncmp(buf, "prti6qp ", 8)) {
> +		dev_err(dev, "Boot target for a different board! (%s %s)\n",
> +			buf, priv->name);
> +		ret = -EINVAL;
> +		goto exit_usb_boot;
> +	}
> +
> +	second_word = strchr(buf, 32);
> +	second_word++;
> +
> +	if (strncmp(second_word, "usb", 3) == 0) {
> +		bootsrc = "disk0.0";

Does this work if the USB stick does not have a partition table?

> +	} else if (strncmp(second_word, "recovery", 8) == 0) {
> +		bootsrc = "recovery";
> +	} else {
> +		dev_err(dev, "Unknown boot target!\n");
> +		ret = -ENODEV;
> +		goto exit_usb_boot;
> +	}
> +
> +	ret = setenv("global.boot.default", bootsrc);
> +	if (ret)
> +		goto exit_usb_boot;
> +
> +	return;
> +
> +exit_usb_boot:
> +	dev_err(dev, "Failed to run usb boot: %i\n", ret);
> +
> +	return;
> +}
> +
> +static int prt_imx6_env_init(struct prt_imx6_priv *priv)
> +{
> +	const struct prt_machine_data *dcfg = priv->dcfg;
> +	struct device_d *dev = priv->dev;
> +	char *delay, *bootsrc;
> +	int ret;
> +
> +	ret = setenv("global.linux.bootargs.base", "consoleblank=0 vt.color=0x00");
> +	if (ret)
> +		goto exit_env_init;
> +
> +	if (dcfg->flags & PRT_IMX6_USB_LONG_DELAY)
> +		priv->usb_delay = 4;
> +	else
> +		priv->usb_delay = 1;
> +
> +	/* the usb_delay value is used for poller_call_async() */
> +	delay = basprintf("%d", priv->usb_delay);
> +	ret = setenv("global.autoboot_timeout", delay);
> +	if (ret)
> +		goto exit_env_init;
> +
> +	if (dcfg->flags & PRT_IMX6_BOOTCHOOSER)
> +		bootsrc = "bootchooser";
> +	else
> +		bootsrc = "mmc2";
> +
> +	ret = setenv("global.boot.default", bootsrc);
> +	if (ret)
> +		goto exit_env_init;
> +
> +	dev_info(dev, "Board specific env init is done\n");
> +	return 0;
> +
> +exit_env_init:
> +	dev_err(dev, "Failed to set env: %i\n", ret);
> +
> +	return ret;
> +}
> +
> +static int prt_imx6_bbu(struct prt_imx6_priv *priv)
> +{
> +	const struct prt_machine_data *dcfg = priv->dcfg;
> +	u32 emmc_flags = 0;
> +	int ret;
> +
> +	if (dcfg->flags & PRT_IMX6_BOOTSRC_SPI_NOR) {
> +		ret = imx6_bbu_internal_spi_i2c_register_handler("SPI", "/dev/m25p0.barebox",
> +							 BBU_HANDLER_FLAG_DEFAULT);
> +		if (ret)
> +			goto exit_bbu;
> +	} else {
> +		emmc_flags = BBU_HANDLER_FLAG_DEFAULT;
> +	}
> +
> +	ret = imx6_bbu_internal_mmcboot_register_handler("eMMC", "/dev/mmc2",
> +						   emmc_flags);
> +	if (ret)
> +		goto exit_bbu;
> +
> +	ret = imx6_bbu_internal_mmc_register_handler("SD", "/dev/mmc0", 0);
> +	if (ret)
> +		goto exit_bbu;
> +
> +	return 0;
> +exit_bbu:
> +	dev_err(priv->dev, "Failed to register bbu: %i\n", ret);
> +	return ret;
> +}
> +
> +static int prt_imx6_devices_init(void)
> +{
> +	struct prt_imx6_priv *priv = prt_priv;
> +	int ret;
> +
> +	if (!priv)
> +		return 0;
> +
> +	if (priv->dcfg->init) {
> +		ret = priv->dcfg->init(priv);
> +		if (ret)
> +			return ret;
> +	}
> +
> +	ret = prt_imx6_bbu(priv);
> +	if (ret)
> +		return ret;
> +
> +	ret = prt_imx6_read_i2c_mac_serial(priv);
> +	if (ret)
> +		return ret;

Why are we bailing out here if the I2C contents are not (yet) correct?

> +
> +	ret = prt_imx6_env_init(priv);
> +	if (ret)
> +		return ret;
> +
> +	ret = poller_async_register(&priv->poller, "usb-boot");
> +	if (ret) {
> +		dev_err(priv->dev, "can't setup poller\n");
> +		return ret;
> +	}
> +
> +	poller_call_async(&priv->poller, priv->usb_delay * SECOND,
> +			  &prt_imx6_check_usb_boot, priv);
> +
> +	return 0;
> +}
> +late_initcall(prt_imx6_devices_init);
> +
> +static int prt_imx6_init_kvg_set_ctrl(struct prt_imx6_priv *priv, bool val)
> +{
> +	int ret;
> +
> +	ret = gpio_direction_output(GPIO_ON1_CTRL, val);
> +	if (ret)
> +		return ret;
> +
> +	ret = gpio_direction_output(GPIO_ON2_CTRL, val);
> +	if (ret)
> +		return ret;
> +
> +	return 0;
> +}
> +
> +static int prt_imx6_yaco_set_kvg_power_mode(struct prt_imx6_priv *priv,
> +					    char *serial)
> +{
> +	static const char command[] = "{\"command\":\"mode\",\"value\":\"kvg\",\"on2\":true}";
> +	struct device_d *dev = priv->dev;
> +	struct console_device *yccon;
> +	int ret;
> +
> +	yccon = of_console_get_by_alias(serial);
> +	if (!yccon) {
> +		dev_dbg(dev, "Cant find the %s node, try later\n", serial);
> +		return -EPROBE_DEFER;
> +	}
> +
> +	ret = console_set_baudrate(yccon, 115200);
> +	if (ret)
> +		goto exit_yaco_set_kvg_power_mode;
> +
> +	yccon->puts(yccon, command, sizeof(command));
> +
> +	dev_info(dev, "Send YaCO power init sequence to the %s\n", serial);

I think the word "the" here is not necessary.

> +	return 0;
> +
> +exit_yaco_set_kvg_power_mode:
> +	dev_err(dev, "Failed to set YaCO pw mode: %i", ret);
> +
> +	return ret;
> +}
> +
> +static int prt_imx6_init_kvg_power(struct prt_imx6_priv *priv,
> +				   enum prt_imx6_kvg_pw_mode pw_mode)
> +{
> +	const char *mode;
> +	int ret;
> +
> +	ret = gpio_request_array(prt_imx6_kvg_gpios,
> +				 ARRAY_SIZE(prt_imx6_kvg_gpios));
> +	if (ret)
> +		goto exit_init_kvg_vicut;
> +
> +	mdelay(1);
> +
> +	if (!gpio_get_value(GPIO_DIP1_FB))
> +		pw_mode = PW_MODE_KUBOTA;
> +
> +	switch (pw_mode) {
> +	case PW_MODE_KVG_WITH_YACO:
> +		mode = "KVG (with YaCO)";
> +
> +		/* GPIO_ON1_CTRL and GPIO_ON2_CTRL are N.C. on the SoC for
> +		 * older revisions */
> +
> +		/* Inform YaCO of power mode */
> +		ret = prt_imx6_yaco_set_kvg_power_mode(priv, "serial0");
> +		break;
> +	case PW_MODE_KVG_NEW:
> +		mode = "KVG (new)";
> +
> +		ret = prt_imx6_init_kvg_set_ctrl(priv, true);
> +		if (ret)
> +			goto exit_init_kvg_vicut;
> +		break;
> +	case PW_MODE_KUBOTA:
> +		mode = "Kubota";
> +		ret = prt_imx6_init_kvg_set_ctrl(priv, false);
> +		if (ret)
> +			goto exit_init_kvg_vicut;
> +		break;
> +	default:
> +		ret = -ENODEV;
> +		goto exit_init_kvg_vicut;
> +	}
> +
> +	dev_info(priv->dev, "Power mode: %s\n", mode);
> +
> +	return 0;
> +
> +exit_init_kvg_vicut:
> +	dev_err(priv->dev, "KvG power init failed: %i\n", ret);
> +
> +	return ret;
> +}
> +
> +static int prt_imx6_init_victgo(struct prt_imx6_priv *priv)
> +{
> +	int ret = 0;
> +
> +	/* Bit 1 of HW-REV is pulled low by 2k2, but must be high on some
> +	 * revisions
> +	 */
> +	if (priv->hw_rev & 2) {
> +		ret = gpio_direction_output(IMX_GPIO_NR(2, 9), 1);
> +		if (ret) {
> +			dev_err(priv->dev, "Failed to set gpio up\n");
> +			return ret;
> +		}
> +	}
> +
> +	return prt_imx6_init_kvg_power(priv, PW_MODE_KVG_NEW);
> +}
> +
> +static int prt_imx6_init_kvg_new(struct prt_imx6_priv *priv)
> +{
> +	return prt_imx6_init_kvg_power(priv, PW_MODE_KVG_NEW);
> +}
> +
> +static int prt_imx6_init_kvg_yaco(struct prt_imx6_priv *priv)
> +{
> +	return prt_imx6_init_kvg_power(priv, PW_MODE_KVG_WITH_YACO);
> +}
> +
> +static int prt_imx6_rfid_fixup(struct prt_imx6_priv *priv,
> +			       struct device_node *root)
> +{
> +	const struct prt_machine_data *dcfg = priv->dcfg;
> +	struct device_node *node, *i2c_node;
> +	char *eeprom_node_name, *alias;
> +	int na, ns, len = 0;
> +	int ret;
> +	u8 *tmp;
> +
> +	alias = basprintf("i2c%d", dcfg->i2c_adapter);
> +	if (!alias) {
> +		ret = -ENOMEM;
> +		goto exit_error;
> +	}
> +
> +	i2c_node = of_find_node_by_alias(root, alias);
> +	if (!i2c_node) {
> +		dev_err(priv->dev, "Unsupported i2c adapter\n");
> +		ret = -ENODEV;
> +		goto free_alias;
> +	}
> +
> +	eeprom_node_name = basprintf("/eeprom@%x", dcfg->i2c_addr);
> +	if (!eeprom_node_name) {
> +		ret = -ENOMEM;
> +		goto free_alias;
> +	}
> +
> +	node = of_create_node(i2c_node, eeprom_node_name);
> +	if (!node) {
> +		dev_err(priv->dev, "Failed to create node %s\n",
> +			eeprom_node_name);
> +		ret = -ENOMEM;
> +		goto free_eeprom;
> +	}
> +
> +	ret = of_property_write_string(node, "compatible", "atmel,24c256");
> +	if (ret)
> +		goto free_eeprom;
> +
> +	na = of_n_addr_cells(node);
> +	ns = of_n_size_cells(node);
> +	tmp = xzalloc((na + ns) * 4);
> +
> +	of_write_number(tmp + len, dcfg->i2c_addr, na);
> +	len += na * 4;
> +	of_write_number(tmp + len, 0, ns);
> +	len += ns * 4;
> +
> +	ret = of_set_property(node, "reg", tmp, len, 1);
> +	kfree(tmp);
> +	if (ret)
> +		goto free_eeprom;
> +
> +	return 0;
> +free_eeprom:
> +	kfree(eeprom_node_name);
> +free_alias:
> +	kfree(alias);
> +exit_error:
> +	dev_err(priv->dev, "Failed to apply fixup: %i\n", ret);
> +	return ret;
> +}
> +
> +static int prt_imx6_of_fixup(struct device_node *root, void *data)
> +{
> +	struct prt_imx6_priv *priv = data;
> +	int ret;
> +
> +	if (!root) {
> +		dev_err(priv->dev, "Unable to find the root node\n");
> +		return -ENODEV;
> +	}
> +
> +	ret = prt_imx6_rfid_fixup(priv, root);
> +	if (ret)
> +		goto exit_of_fixups;
> +
> +	return 0;
> +exit_of_fixups:
> +	dev_err(priv->dev, "Failed to apply OF fixups: %i\n", ret);
> +	return ret;
> +}
> +
> +static int prt_imx6_get_id(struct prt_imx6_priv *priv)
> +{
> +	struct gpio gpios_type[] = GPIO_HW_TYPE_ID;
> +	struct gpio gpios_rev[] = GPIO_HW_REV_ID;
> +	int ret;
> +
> +	ret = gpio_array_to_id(gpios_type, ARRAY_SIZE(gpios_type), &priv->hw_id);
> +	if (ret)
> +		goto exit_get_id;
> +
> +	ret = gpio_array_to_id(gpios_rev, ARRAY_SIZE(gpios_rev), &priv->hw_rev);
> +	if (ret)
> +		goto exit_get_id;
> +
> +	return 0;
> +exit_get_id:
> +	dev_err(priv->dev, "Failed to read gpio ID: %i\n", ret);
> +	return ret;
> +}
> +
> +static int prt_imx6_get_dcfg(struct prt_imx6_priv *priv)
> +{
> +	const struct prt_machine_data *dcfg, *found = NULL;
> +	int ret;
> +
> +	dcfg = of_device_get_match_data(priv->dev);
> +	if (!dcfg) {
> +		ret = -EINVAL;
> +		goto exit_get_dcfg;
> +	}
> +
> +	for (; dcfg->hw_id != UINT_MAX; dcfg++) {
> +		if (dcfg->hw_id != priv->hw_id)
> +			continue;
> +		if (dcfg->hw_rev > priv->hw_rev)
> +			break;
> +		found = dcfg;
> +	}
> +
> +	if (!found) {
> +		ret = -ENODEV;
> +		goto exit_get_dcfg;
> +	}
> +
> +	priv->dcfg = found;
> +
> +	return 0;
> +exit_get_dcfg:
> +	dev_err(priv->dev, "Failed to get dcfg: %i\n", ret);
> +	return ret;
> +}
> +
> +static int prt_imx6_probe(struct device_d *dev)
> +{
> +	struct prt_imx6_priv *priv;
> +	const char *name, *ptr;
> +	struct param_d *p;
> +	int ret;
> +
> +	priv = kzalloc(sizeof(*priv), GFP_KERNEL);
> +	if (!priv)
> +		return -ENOMEM;
> +
> +	priv->dev = dev;
> +	name = of_device_get_match_compatible(priv->dev);
> +	ptr = strchr(name, ',');
> +	priv->name =  ptr ? ptr + 1 : name;
> +
> +	pr_info("Detected machine type: %s\n", priv->name);
> +
> +	ret = prt_imx6_get_id(priv);
> +	if (ret)
> +		goto free_priv;
> +
> +	pr_info("  HW type:     %d\n", priv->hw_id);
> +	pr_info("  HW revision: %d\n", priv->hw_rev);
> +
> +	ret = prt_imx6_get_dcfg(priv);
> +	if (ret)
> +		goto free_priv;
> +
> +	p = dev_add_param_uint32_ro(dev, "boardrev", &priv->hw_rev, "%u");
> +	if (IS_ERR(p)) {
> +		ret = PTR_ERR(p);
> +		goto free_priv;
> +	}
> +
> +	p = dev_add_param_uint32_ro(dev, "boardid", &priv->hw_id, "%u");
> +	if (IS_ERR(p)) {
> +		ret = PTR_ERR(p);
> +		goto free_priv;
> +	}
> +
> +	ret = prt_imx6_of_fixup(of_get_root_node(), priv);
> +	if (ret)
> +		goto free_priv;
> +
> +	ret = of_register_fixup(prt_imx6_of_fixup, priv);
> +	if (ret) {
> +		dev_err(dev, "Failed to register fixup\n");
> +		goto free_priv;
> +	}
> +
> +	prt_priv = priv;
> +
> +	return 0;
> +free_priv:
> +	kfree(priv);
> +	return ret;
> +}
> +
> +static const struct prt_machine_data prt_imx6_cfg_alti6p[] = {
> +	{
> +		.hw_id = HW_TYPE_ALTI6P,
> +		.hw_rev = 0,
> +		.i2c_addr = 0x51,
> +		.i2c_adapter = 0,
> +		.flags = PRT_IMX6_BOOTSRC_EMMC,
> +	}, {
> +		.hw_id = UINT_MAX
> +	},
> +};
> +
> +static const struct prt_machine_data prt_imx6_cfg_victgo[] = {
> +	{
> +		.hw_id = HW_TYPE_VICTGO,
> +		.hw_rev = 0,
> +		.i2c_addr = 0x51,
> +		.i2c_adapter = 0,
> +		.init = prt_imx6_init_victgo,
> +		.flags = PRT_IMX6_BOOTSRC_SPI_NOR,
> +	}, {
> +		.hw_id = UINT_MAX
> +	},
> +};
> +
> +static const struct prt_machine_data prt_imx6_cfg_vicut1[] = {
> +	{
> +		.hw_id = HW_TYPE_VICUT1,
> +		.hw_rev = 0,
> +		.i2c_addr = 0x50,
> +		.i2c_adapter = 1,
> +		.flags = PRT_IMX6_BOOTSRC_SPI_NOR,
> +	}, {
> +		.hw_id = HW_TYPE_VICUT1,
> +		.hw_rev = 1,
> +		.i2c_addr = 0x51,
> +		.i2c_adapter = 0,
> +		.init = prt_imx6_init_kvg_yaco,
> +		.flags = PRT_IMX6_BOOTSRC_SPI_NOR,
> +	}, {
> +		.hw_id = HW_TYPE_VICUT2,
> +		.hw_rev = 1,
> +		.i2c_addr = 0x51,
> +		.i2c_adapter = 0,
> +		.init = prt_imx6_init_kvg_new,
> +		.flags = PRT_IMX6_BOOTSRC_SPI_NOR,
> +	}, {
> +		.hw_id = UINT_MAX
> +	},
> +};
> +
> +static const struct prt_machine_data prt_imx6_cfg_vicut1q[] = {
> +	{
> +		.hw_id = HW_TYPE_VICUT1,
> +		.hw_rev = 0,
> +		.i2c_addr = 0x50,
> +		.i2c_adapter = 1,
> +		.flags = PRT_IMX6_BOOTSRC_SPI_NOR,
> +	}, {
> +		.hw_id = HW_TYPE_VICUT1,
> +		.hw_rev = 1,
> +		.i2c_addr = 0x51,
> +		.i2c_adapter = 0,
> +		.init = prt_imx6_init_kvg_yaco,
> +		.flags = PRT_IMX6_BOOTSRC_SPI_NOR,
> +	}, {
> +		.hw_id = HW_TYPE_VICUT2,
> +		.hw_rev = 0,
> +		.i2c_addr = 0x51,
> +		.i2c_adapter = 0,
> +		.init = prt_imx6_init_kvg_yaco,
> +		.flags = PRT_IMX6_BOOTSRC_SPI_NOR,
> +	}, {
> +		.hw_id = HW_TYPE_VICUT2,
> +		.hw_rev = 1,
> +		.i2c_addr = 0x51,
> +		.i2c_adapter = 0,
> +		.init = prt_imx6_init_kvg_new,
> +		.flags = PRT_IMX6_BOOTSRC_SPI_NOR,
> +	}, {
> +		.hw_id = UINT_MAX
> +	},
> +};
> +
> +static const struct prt_machine_data prt_imx6_cfg_vicutp[] = {
> +	{
> +		.hw_id = HW_TYPE_VICUT2,
> +		.hw_rev = 1,
> +		.i2c_addr = 0x51,
> +		.i2c_adapter = 0,
> +		.init = prt_imx6_init_kvg_new,
> +		.flags = PRT_IMX6_BOOTSRC_SPI_NOR,
> +	}, {
> +		.hw_id = UINT_MAX
> +	},
> +};
> +
> +static const struct prt_machine_data prt_imx6_cfg_lanmcu[] = {
> +	{
> +		.hw_id = HW_TYPE_LANMCU,
> +		.hw_rev = 0,
> +		.i2c_addr = 0x51,
> +		.i2c_adapter = 0,
> +		.flags = PRT_IMX6_BOOTSRC_EMMC | PRT_IMX6_BOOTCHOOSER,
> +	}, {
> +		.hw_id = UINT_MAX
> +	},
> +};
> +
> +static const struct prt_machine_data prt_imx6_cfg_plybas[] = {
> +	{
> +		.hw_id = HW_TYPE_PLYBAS,
> +		.hw_rev = 0,
> +		.i2c_addr = 0x51,
> +		.i2c_adapter = 0,
> +		.flags = PRT_IMX6_BOOTSRC_SPI_NOR | PRT_IMX6_USB_LONG_DELAY,
> +	}, {
> +		.hw_id = UINT_MAX
> +	},
> +};
> +
> +static const struct prt_machine_data prt_imx6_cfg_plym2m[] = {
> +	{
> +		.hw_id = HW_TYPE_PLYM2M,
> +		.hw_rev = 0,
> +		.i2c_addr = 0x51,
> +		.i2c_adapter = 0,
> +		.flags = PRT_IMX6_BOOTSRC_SPI_NOR | PRT_IMX6_USB_LONG_DELAY,
> +	}, {
> +		.hw_id = UINT_MAX
> +	},
> +};
> +
> +static const struct prt_machine_data prt_imx6_cfg_prti6g[] = {
> +	{
> +		.hw_id = HW_TYPE_PRTI6G,
> +		.hw_rev = 0,
> +		.i2c_addr = 0x51,
> +		.i2c_adapter = 0,
> +		.flags = PRT_IMX6_BOOTSRC_EMMC,
> +	}, {
> +		.hw_id = UINT_MAX
> +	},
> +};
> +
> +static const struct prt_machine_data prt_imx6_cfg_prti6q[] = {
> +	{
> +		.hw_id = HW_TYPE_PRTI6Q,
> +		.hw_rev = 0,
> +		.i2c_addr = 0x51,
> +		.i2c_adapter = 2,
> +		.flags = PRT_IMX6_BOOTSRC_SPI_NOR,
> +	}, {
> +		.hw_id = HW_TYPE_PRTI6Q,
> +		.hw_rev = 1,
> +		.i2c_addr = 0x51,
> +		.i2c_adapter = 0,
> +		.flags = PRT_IMX6_BOOTSRC_SPI_NOR,
> +	}, {
> +		.hw_id = UINT_MAX
> +	},
> +};
> +
> +static const struct prt_machine_data prt_imx6_cfg_prtmvt[] = {
> +	{
> +		.hw_id = HW_TYPE_PRTMVT,
> +		.hw_rev = 0,
> +		.i2c_addr = 0x51,
> +		.i2c_adapter = 0,
> +		.flags = PRT_IMX6_BOOTSRC_SPI_NOR,
> +	}, {
> +		.hw_id = UINT_MAX
> +	},
> +};
> +
> +static const struct prt_machine_data prt_imx6_cfg_prtrvt[] = {
> +	{
> +		.hw_id = HW_TYPE_PRTRVT,
> +		.hw_rev = 0,
> +		.i2c_addr = 0x51,
> +		.i2c_adapter = 0,
> +		.flags = PRT_IMX6_BOOTSRC_SPI_NOR,
> +	}, {
> +		.hw_id = UINT_MAX
> +	},
> +};
> +
> +static const struct prt_machine_data prt_imx6_cfg_prtvt7[] = {
> +	{
> +		.hw_id = HW_TYPE_PRTVT7,
> +		.hw_rev = 0,
> +		.i2c_addr = 0x51,
> +		.i2c_adapter = 0,
> +		.flags = PRT_IMX6_BOOTSRC_EMMC | PRT_IMX6_BOOTCHOOSER,
> +	}, {
> +		.hw_id = UINT_MAX
> +	},
> +};
> +
> +static const struct prt_machine_data prt_imx6_cfg_prtwd2[] = {
> +	{
> +		.hw_id = HW_TYPE_PRTWD2,
> +		.hw_rev = 0,
> +		.i2c_addr = 0x51,
> +		.i2c_adapter = 0,
> +		.flags = PRT_IMX6_BOOTSRC_EMMC,
> +	}, {
> +		.hw_id = UINT_MAX
> +	},
> +};
> +
> +static const struct prt_machine_data prt_imx6_cfg_prtwd3[] = {
> +	{
> +		.hw_id = HW_TYPE_PRTWD2,
> +		.hw_rev = 2,
> +		.i2c_addr = 0x51,
> +		.i2c_adapter = 0,
> +		.flags = PRT_IMX6_BOOTSRC_EMMC,
> +	}, {
> +		.hw_id = UINT_MAX
> +	},
> +};
> +
> +static const struct of_device_id prt_imx6_of_match[] = {
> +	{ .compatible = "alt,alti6p", .data = &prt_imx6_cfg_alti6p },
> +	{ .compatible = "kvg,victgo", .data = &prt_imx6_cfg_victgo },
> +	{ .compatible = "kvg,vicut1", .data = &prt_imx6_cfg_vicut1 },
> +	{ .compatible = "kvg,vicut1q", .data = &prt_imx6_cfg_vicut1q },
> +	{ .compatible = "kvg,vicutp", .data = &prt_imx6_cfg_vicutp },
> +	{ .compatible = "lan,lanmcu", .data = &prt_imx6_cfg_lanmcu },
> +	{ .compatible = "ply,plybas", .data = &prt_imx6_cfg_plybas },
> +	{ .compatible = "ply,plym2m", .data = &prt_imx6_cfg_plym2m },
> +	{ .compatible = "prt,prti6g", .data = &prt_imx6_cfg_prti6g },
> +	{ .compatible = "prt,prti6q", .data = &prt_imx6_cfg_prti6q },
> +	{ .compatible = "prt,prtmvt", .data = &prt_imx6_cfg_prtmvt },
> +	{ .compatible = "prt,prtrvt", .data = &prt_imx6_cfg_prtrvt },
> +	{ .compatible = "prt,prtvt7", .data = &prt_imx6_cfg_prtvt7 },
> +	{ .compatible = "prt,prtwd2", .data = &prt_imx6_cfg_prtwd2 },
> +	{ .compatible = "prt,prtwd3", .data = &prt_imx6_cfg_prtwd3 },
> +	{ /* sentinel */ },
> +};
> +
> +static struct driver_d prt_imx6_board_driver = {
> +	.name = "board-protonic-imx6",
> +	.probe = prt_imx6_probe,
> +	.of_compatible = DRV_OF_COMPAT(prt_imx6_of_match),
> +};
> +postcore_platform_driver(prt_imx6_board_driver);

Best regards,

-- 
David Jander
Protonic Holland.

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

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

* Re: [PATCH v3 4/6] ARM: protonic-imx6: port Protonic specific board code
  2020-08-13 14:07   ` David Jander
@ 2020-08-17  6:54     ` Oleksij Rempel
  0 siblings, 0 replies; 9+ messages in thread
From: Oleksij Rempel @ 2020-08-17  6:54 UTC (permalink / raw)
  To: David Jander; +Cc: barebox

On Thu, Aug 13, 2020 at 04:07:26PM +0200, David Jander wrote:
> On Thu, 13 Aug 2020 14:55:12 +0200
> Oleksij Rempel <o.rempel@pengutronix.de> wrote:
> 
> > Signed-off-by: Oleksij Rempel <o.rempel@pengutronix.de>
> > ---
> >  arch/arm/boards/protonic-imx6/Makefile |    1 +
> >  arch/arm/boards/protonic-imx6/board.c  | 1002 ++++++++++++++++++++++++
> >  2 files changed, 1003 insertions(+)
> >  create mode 100644 arch/arm/boards/protonic-imx6/board.c
> > 
> > diff --git a/arch/arm/boards/protonic-imx6/Makefile b/arch/arm/boards/protonic-imx6/Makefile
> > index b08c4a93ca..01c7a259e9 100644
> > --- a/arch/arm/boards/protonic-imx6/Makefile
> > +++ b/arch/arm/boards/protonic-imx6/Makefile
> > @@ -1 +1,2 @@
> > +obj-y += board.o
> >  lwl-y += lowlevel.o
> > diff --git a/arch/arm/boards/protonic-imx6/board.c b/arch/arm/boards/protonic-imx6/board.c
> > new file mode 100644
> > index 0000000000..f3bd0dd86a
> > --- /dev/null
> > +++ b/arch/arm/boards/protonic-imx6/board.c
> > @@ -0,0 +1,1002 @@
> > +// SPDX-License-Identifier: GPL-2.0-only
> > +// SPDX-FileCopyrightText: 2012 Steffen Trumtrar, Pengutronix
> > +// SPDX-FileCopyrightText: 2014 Protonic Holland
> > +// SPDX-FileCopyrightText: 2020 Oleksij Rempel, Pengutronix
> > +
> > +#include <bbu.h>
> > +#include <common.h>
> > +#include <environment.h>
> > +#include <gpio.h>
> > +#include <mach/bbu.h>
> > +#include <mach/imx6.h>
> > +#include <of_device.h>
> > +
> > +#include <usb/usb.h>
> > +#include <sys/mount.h>
> > +#include <sys/stat.h>
> > +#include <fcntl.h>
> > +#include <unistd.h>
> > +#include <net.h>
> > +#include <i2c/i2c.h>
> > +
> > +#define GPIO_HW_REV_ID  {\
> > +	{IMX_GPIO_NR(2, 8), GPIOF_DIR_IN | GPIOF_ACTIVE_LOW, "rev_id0"}, \
> > +	{IMX_GPIO_NR(2, 9), GPIOF_DIR_IN | GPIOF_ACTIVE_LOW, "rev_id1"}, \
> > +	{IMX_GPIO_NR(2, 10), GPIOF_DIR_IN | GPIOF_ACTIVE_LOW, "rev_id2"} \
> > +}
> > +
> > +#define GPIO_HW_TYPE_ID  {\
> > +	{IMX_GPIO_NR(2, 11), GPIOF_DIR_IN | GPIOF_ACTIVE_LOW, "hw_id0"}, \
> > +	{IMX_GPIO_NR(2, 12), GPIOF_DIR_IN | GPIOF_ACTIVE_LOW, "hw_id1"}, \
> > +	{IMX_GPIO_NR(2, 13), GPIOF_DIR_IN | GPIOF_ACTIVE_LOW, "hw_id2"}, \
> > +	{IMX_GPIO_NR(2, 14), GPIOF_DIR_IN | GPIOF_ACTIVE_LOW, "hw_id3"}, \
> > +	{IMX_GPIO_NR(2, 15), GPIOF_DIR_IN | GPIOF_ACTIVE_LOW, "hw_id4"} \
> > +}
> > +
> > +enum {
> > +	HW_TYPE_PRTI6Q = 0,
> > +	HW_TYPE_PRTWD2 = 1,
> > +	HW_TYPE_ALTI6S = 2,
> > +	HW_TYPE_VICUT1 = 4,
> > +	HW_TYPE_ALTI6P = 6,
> > +	HW_TYPE_PRTMVT = 8,
> > +	HW_TYPE_PRTI6G = 10,
> > +	HW_TYPE_PRTRVT = 12,
> > +	HW_TYPE_VICUT2 = 16,
> > +	HW_TYPE_PLYM2M = 20,
> > +	HW_TYPE_PRTVT7 = 22,
> > +	HW_TYPE_LANMCU = 23,
> > +	HW_TYPE_PLYBAS = 24,
> > +	HW_TYPE_VICTGO = 28,
> > +};
> > +
> > +enum prt_imx6_kvg_pw_mode {
> > +	PW_MODE_KVG_WITH_YACO = 0,
> > +	PW_MODE_KVG_NEW = 1,
> > +	PW_MODE_KUBOTA = 2,
> > +};
> > +
> > +/* board specific flags */
> > +#define PRT_IMX6_BOOTCHOOSER		BIT(3)
> > +#define PRT_IMX6_USB_LONG_DELAY		BIT(2)
> > +#define PRT_IMX6_BOOTSRC_EMMC		BIT(1)
> > +#define PRT_IMX6_BOOTSRC_SPI_NOR	BIT(0)
> > +
> > +static struct prt_imx6_priv *prt_priv;
> > +struct prt_machine_data {
> > +	unsigned int hw_id;
> > +	unsigned int hw_rev;
> > +	unsigned int i2c_addr;
> > +	unsigned int i2c_adapter;
> > +	unsigned int flags;
> > +	int (*init)(struct prt_imx6_priv *priv);
> > +};
> > +
> > +struct prt_imx6_priv {
> > +	struct device_d *dev;
> > +	const struct prt_machine_data *dcfg;
> > +	unsigned int hw_id;
> > +	unsigned int hw_rev;
> > +	const char *name;
> > +	struct poller_async poller;
> > +	unsigned int usb_delay;
> > +};
> > +
> > +struct prti6q_rfid_contents {
> > +	u8 mac[6];
> > +	char serial[10];
> > +	u8 cs;
> > +} __attribute__ ((packed));
> > +
> > +#define GPIO_DIP1_FB   IMX_GPIO_NR(4, 18)
> > +#define GPIO_FORCE_ON1 IMX_GPIO_NR(2, 30)
> > +#define GPIO_ON1_CTRL  IMX_GPIO_NR(4, 21)
> > +#define GPIO_ON2_CTRL  IMX_GPIO_NR(4, 22)
> > +
> > +static const struct gpio prt_imx6_kvg_gpios[] = {
> > +	{
> > +		.gpio = GPIO_DIP1_FB,
> > +		.flags = GPIOF_IN,
> > +		.label = "DIP1_FB",
> > +	},
> > +	{
> > +		.gpio = GPIO_FORCE_ON1,
> > +		.flags = GPIOF_OUT_INIT_HIGH,
> > +		.label = "FORCE_ON1",
> > +	},
> > +	{
> > +		.gpio = GPIO_ON1_CTRL,
> > +		.flags = GPIOF_IN,
> > +		.label = "ON1_CTRL",
> > +	},
> > +	{
> > +		.gpio = GPIO_ON2_CTRL,
> > +		.flags = GPIOF_IN,
> > +		.label = "ON2_CTRL",
> > +	},
> > +};
> > +
> > +static int prt_imx6_read_rfid(struct prt_imx6_priv *priv, void *buf,
> > +			      size_t size)
> > +{
> > +	const struct prt_machine_data *dcfg = priv->dcfg;
> > +	struct device_d *dev = priv->dev;
> > +	struct i2c_client cl;
> > +	int ret;
> > +
> > +	cl.addr = dcfg->i2c_addr;
> > +	cl.adapter = i2c_get_adapter(dcfg->i2c_adapter);
> > +	if (!cl.adapter) {
> > +		dev_err(dev, "i2c bus not found\n");
> > +		return -ENODEV;
> > +	}
> > +
> > +	/* 0x6000 user storage in the RFID tag */
> > +	ret = i2c_read_reg(&cl, 0x6000 | I2C_ADDR_16_BIT, buf, size);
> > +	if (ret < 0) {
> > +		dev_err(dev, "Filed to read the RFID: %i\n", ret);
> > +		return ret;
> > +	}
> > +
> > +	return 0;
> > +}
> > +
> > +static u8 prt_imx6_calc_rfid_crc(void *buf, size_t size)
> > +{
> 
> This is really a simple checksum, not a form of CRC code, so maybe
> prt_imx6_calc_rfid_cs is a better name for the function.

done

> > +	unsigned int cs = 0;
> > +	u8 *dat = buf;
> > +	int t;
> > +
> > +	for (t = 0; t < size - 1; t++) {
> > +		cs += dat[t];
> > +	}
> > +
> > +	cs ^= 0xff;
> > +
> > +	return cs & 0xff;
> > +
> > +}
> > +
> > +static int prt_imx6_set_mac(struct prt_imx6_priv *priv,
> > +			    struct prti6q_rfid_contents *rfid)
> > +{
> > +	struct device_d *dev = priv->dev;
> > +	struct device_node *node;
> > +
> > +	node = of_find_node_by_alias(of_get_root_node(), "ethernet0");
> > +	if (!node) {
> > +		dev_err(dev, "Cannot find FEC!\n");
> > +		return -ENODEV;
> > +	}
> > +
> > +	if (!is_valid_ether_addr(&rfid->mac[0])) {
> > +		dev_err(dev, "bad MAC addr\n");
> > +		return -EILSEQ;
> > +	}
> > +
> > +	of_eth_register_ethaddr(node, &rfid->mac[0]);
> > +
> > +	return 0;
> > +}
> > +
> > +static int prt_of_fixup_serial(struct device_node *dstroot, void *arg)
> > +{
> > +	struct device_node *srcroot = arg;
> > +	const char *ser;
> > +	int len;
> > +
> > +	ser = of_get_property(srcroot, "serial-number", &len);
> > +	return of_set_property(dstroot, "serial-number", ser, len, 1);
> > +}
> > +
> > +static void prt_oftree_fixup_serial(const char *serial)
> > +{
> > +	struct device_node *root = of_get_root_node();
> > +
> > +	of_set_property(root, "serial-number", serial, strlen(serial) + 1, 1);
> > +	of_register_fixup(prt_of_fixup_serial, root);
> > +}
> > +
> > +static int prt_imx6_set_serial(struct prt_imx6_priv *priv,
> > +			       struct prti6q_rfid_contents *rfid)
> > +{
> > +	rfid->serial[9] = 0; /* Failsafe */
> > +	dev_info(priv->dev, "Serial number: %s\n", rfid->serial);
> > +	prt_oftree_fixup_serial(rfid->serial);
> > +
> > +	return 0;
> > +}
> > +
> > +static int prt_imx6_read_i2c_mac_serial(struct prt_imx6_priv *priv)
> > +{
> > +	struct device_d *dev = priv->dev;
> > +	struct prti6q_rfid_contents rfid;
> > +	int ret;
> > +
> > +	ret = prt_imx6_read_rfid(priv, &rfid, sizeof(rfid));
> > +	if (ret)
> > +		return ret;
> > +
> > +	if (rfid.cs != prt_imx6_calc_rfid_crc(&rfid, sizeof(rfid))) {
> > +		dev_err(dev, "RFID: bad checksum!\n");
> > +		return -EBADMSG;
> > +	}
> > +
> > +	ret = prt_imx6_set_mac(priv, &rfid);
> > +	if (ret)
> > +		return ret;
> > +
> > +	ret = prt_imx6_set_serial(priv, &rfid);
> > +	if (ret)
> > +		return ret;
> > +
> > +	return 0;
> > +}
> > +
> > +#define OTG_PORTSC1 (MX6_OTG_BASE_ADDR+0x184)
> > +
> > +static void prt_imx6_check_usb_boot(void *data)
> > +{
> > +	struct prt_imx6_priv *priv = data;
> > +	struct device_d *dev = priv->dev;
> > +	char *second_word, *bootsrc;
> > +	unsigned int v;
> > +	ssize_t size;
> > +	char buf[16];
> > +	int fd, ret;
> > +
> > +	v = *((unsigned int *)OTG_PORTSC1);
> > +	if ((v & 0x0c00) == 0) /* LS == SE0 ==> nothing connected */
> > +		return;
> > +
> > +	usb_rescan();
> > +
> > +	ret = mkdir("/usb", 0);
> > +	if (ret) {
> > +		dev_err(dev, "Cannot mkdir /usb\n");
> > +		goto exit_usb_boot;
> > +	}
> > +
> > +	ret = mount("/dev/disk0.0", NULL, "usb", NULL);
> > +	if (ret) {
> > +		dev_warn(dev, "Filed to mount USB Disk partition with error (%i), trying bare device\n", ret);
> > +
> > +		ret = mount("/dev/disk0", NULL, "usb", NULL);
> > +		if (ret) {
> > +			dev_err(dev, "USB mount failed!\n");
> > +			goto exit_usb_boot;
> > +		}
> > +	}
> > +
> > +	fd = open("/usb/boot_target", O_RDONLY);
> > +	if (fd < 0) {
> > +		dev_err(dev, "Can't open /usb/boot_target file\n");
> > +		ret = fd;
> > +		goto exit_usb_boot;
> > +	}
> > +
> > +	size = read(fd, buf, sizeof(buf));
> > +	close(fd);
> > +	if (size < 0) {
> > +		ret = size;
> > +		goto exit_usb_boot;
> > +	}
> > +
> > +	/* length of "vicut1 usb", the shortest possible target */
> > +	if (size < sizeof("vicut1 usb")) {
> > +		dev_err(dev, "Invalid boot target file!\n");
> > +		ret = -EINVAL;
> > +		goto exit_usb_boot;
> > +	}
> > +
> > +	if (strncmp(buf, priv->name, 6) && strncmp(buf, "prti6qp ", 8)) {
> > +		dev_err(dev, "Boot target for a different board! (%s %s)\n",
> > +			buf, priv->name);
> > +		ret = -EINVAL;
> > +		goto exit_usb_boot;
> > +	}
> > +
> > +	second_word = strchr(buf, 32);
> > +	second_word++;
> > +
> > +	if (strncmp(second_word, "usb", 3) == 0) {
> > +		bootsrc = "disk0.0";
> 
> Does this work if the USB stick does not have a partition table?

good point! fixed.

> > +	} else if (strncmp(second_word, "recovery", 8) == 0) {
> > +		bootsrc = "recovery";
> > +	} else {
> > +		dev_err(dev, "Unknown boot target!\n");
> > +		ret = -ENODEV;
> > +		goto exit_usb_boot;
> > +	}
> > +
> > +	ret = setenv("global.boot.default", bootsrc);
> > +	if (ret)
> > +		goto exit_usb_boot;
> > +
> > +	return;
> > +
> > +exit_usb_boot:
> > +	dev_err(dev, "Failed to run usb boot: %i\n", ret);
> > +
> > +	return;
> > +}
> > +
> > +static int prt_imx6_env_init(struct prt_imx6_priv *priv)
> > +{
> > +	const struct prt_machine_data *dcfg = priv->dcfg;
> > +	struct device_d *dev = priv->dev;
> > +	char *delay, *bootsrc;
> > +	int ret;
> > +
> > +	ret = setenv("global.linux.bootargs.base", "consoleblank=0 vt.color=0x00");
> > +	if (ret)
> > +		goto exit_env_init;
> > +
> > +	if (dcfg->flags & PRT_IMX6_USB_LONG_DELAY)
> > +		priv->usb_delay = 4;
> > +	else
> > +		priv->usb_delay = 1;
> > +
> > +	/* the usb_delay value is used for poller_call_async() */
> > +	delay = basprintf("%d", priv->usb_delay);
> > +	ret = setenv("global.autoboot_timeout", delay);
> > +	if (ret)
> > +		goto exit_env_init;
> > +
> > +	if (dcfg->flags & PRT_IMX6_BOOTCHOOSER)
> > +		bootsrc = "bootchooser";
> > +	else
> > +		bootsrc = "mmc2";
> > +
> > +	ret = setenv("global.boot.default", bootsrc);
> > +	if (ret)
> > +		goto exit_env_init;
> > +
> > +	dev_info(dev, "Board specific env init is done\n");
> > +	return 0;
> > +
> > +exit_env_init:
> > +	dev_err(dev, "Failed to set env: %i\n", ret);
> > +
> > +	return ret;
> > +}
> > +
> > +static int prt_imx6_bbu(struct prt_imx6_priv *priv)
> > +{
> > +	const struct prt_machine_data *dcfg = priv->dcfg;
> > +	u32 emmc_flags = 0;
> > +	int ret;
> > +
> > +	if (dcfg->flags & PRT_IMX6_BOOTSRC_SPI_NOR) {
> > +		ret = imx6_bbu_internal_spi_i2c_register_handler("SPI", "/dev/m25p0.barebox",
> > +							 BBU_HANDLER_FLAG_DEFAULT);
> > +		if (ret)
> > +			goto exit_bbu;
> > +	} else {
> > +		emmc_flags = BBU_HANDLER_FLAG_DEFAULT;
> > +	}
> > +
> > +	ret = imx6_bbu_internal_mmcboot_register_handler("eMMC", "/dev/mmc2",
> > +						   emmc_flags);
> > +	if (ret)
> > +		goto exit_bbu;
> > +
> > +	ret = imx6_bbu_internal_mmc_register_handler("SD", "/dev/mmc0", 0);
> > +	if (ret)
> > +		goto exit_bbu;
> > +
> > +	return 0;
> > +exit_bbu:
> > +	dev_err(priv->dev, "Failed to register bbu: %i\n", ret);
> > +	return ret;
> > +}
> > +
> > +static int prt_imx6_devices_init(void)
> > +{
> > +	struct prt_imx6_priv *priv = prt_priv;
> > +	int ret;
> > +
> > +	if (!priv)
> > +		return 0;
> > +
> > +	if (priv->dcfg->init) {
> > +		ret = priv->dcfg->init(priv);
> > +		if (ret)
> > +			return ret;
> > +	}
> > +
> > +	ret = prt_imx6_bbu(priv);
> > +	if (ret)
> > +		return ret;
> > +
> > +	ret = prt_imx6_read_i2c_mac_serial(priv);
> > +	if (ret)
> > +		return ret;
> 
> Why are we bailing out here if the I2C contents are not (yet) correct?

fixed. in this case it would make sense to ignore error for most of
prt_imx6_devices_init() callees. 

> > +
> > +	ret = prt_imx6_env_init(priv);
> > +	if (ret)
> > +		return ret;
> > +
> > +	ret = poller_async_register(&priv->poller, "usb-boot");
> > +	if (ret) {
> > +		dev_err(priv->dev, "can't setup poller\n");
> > +		return ret;
> > +	}
> > +
> > +	poller_call_async(&priv->poller, priv->usb_delay * SECOND,
> > +			  &prt_imx6_check_usb_boot, priv);
> > +
> > +	return 0;
> > +}
> > +late_initcall(prt_imx6_devices_init);
> > +
> > +static int prt_imx6_init_kvg_set_ctrl(struct prt_imx6_priv *priv, bool val)
> > +{
> > +	int ret;
> > +
> > +	ret = gpio_direction_output(GPIO_ON1_CTRL, val);
> > +	if (ret)
> > +		return ret;
> > +
> > +	ret = gpio_direction_output(GPIO_ON2_CTRL, val);
> > +	if (ret)
> > +		return ret;
> > +
> > +	return 0;
> > +}
> > +
> > +static int prt_imx6_yaco_set_kvg_power_mode(struct prt_imx6_priv *priv,
> > +					    char *serial)
> > +{
> > +	static const char command[] = "{\"command\":\"mode\",\"value\":\"kvg\",\"on2\":true}";
> > +	struct device_d *dev = priv->dev;
> > +	struct console_device *yccon;
> > +	int ret;
> > +
> > +	yccon = of_console_get_by_alias(serial);
> > +	if (!yccon) {
> > +		dev_dbg(dev, "Cant find the %s node, try later\n", serial);
> > +		return -EPROBE_DEFER;
> > +	}
> > +
> > +	ret = console_set_baudrate(yccon, 115200);
> > +	if (ret)
> > +		goto exit_yaco_set_kvg_power_mode;
> > +
> > +	yccon->puts(yccon, command, sizeof(command));
> > +
> > +	dev_info(dev, "Send YaCO power init sequence to the %s\n", serial);
> 
> I think the word "the" here is not necessary.

removed.

> > +	return 0;
> > +
> > +exit_yaco_set_kvg_power_mode:
> > +	dev_err(dev, "Failed to set YaCO pw mode: %i", ret);
> > +
> > +	return ret;
> > +}
> > +
> > +static int prt_imx6_init_kvg_power(struct prt_imx6_priv *priv,
> > +				   enum prt_imx6_kvg_pw_mode pw_mode)
> > +{
> > +	const char *mode;
> > +	int ret;
> > +
> > +	ret = gpio_request_array(prt_imx6_kvg_gpios,
> > +				 ARRAY_SIZE(prt_imx6_kvg_gpios));
> > +	if (ret)
> > +		goto exit_init_kvg_vicut;
> > +
> > +	mdelay(1);
> > +
> > +	if (!gpio_get_value(GPIO_DIP1_FB))
> > +		pw_mode = PW_MODE_KUBOTA;
> > +
> > +	switch (pw_mode) {
> > +	case PW_MODE_KVG_WITH_YACO:
> > +		mode = "KVG (with YaCO)";
> > +
> > +		/* GPIO_ON1_CTRL and GPIO_ON2_CTRL are N.C. on the SoC for
> > +		 * older revisions */
> > +
> > +		/* Inform YaCO of power mode */
> > +		ret = prt_imx6_yaco_set_kvg_power_mode(priv, "serial0");
> > +		break;
> > +	case PW_MODE_KVG_NEW:
> > +		mode = "KVG (new)";
> > +
> > +		ret = prt_imx6_init_kvg_set_ctrl(priv, true);
> > +		if (ret)
> > +			goto exit_init_kvg_vicut;
> > +		break;
> > +	case PW_MODE_KUBOTA:
> > +		mode = "Kubota";
> > +		ret = prt_imx6_init_kvg_set_ctrl(priv, false);
> > +		if (ret)
> > +			goto exit_init_kvg_vicut;
> > +		break;
> > +	default:
> > +		ret = -ENODEV;
> > +		goto exit_init_kvg_vicut;
> > +	}
> > +
> > +	dev_info(priv->dev, "Power mode: %s\n", mode);
> > +
> > +	return 0;
> > +
> > +exit_init_kvg_vicut:
> > +	dev_err(priv->dev, "KvG power init failed: %i\n", ret);
> > +
> > +	return ret;
> > +}
> > +
> > +static int prt_imx6_init_victgo(struct prt_imx6_priv *priv)
> > +{
> > +	int ret = 0;
> > +
> > +	/* Bit 1 of HW-REV is pulled low by 2k2, but must be high on some
> > +	 * revisions
> > +	 */
> > +	if (priv->hw_rev & 2) {
> > +		ret = gpio_direction_output(IMX_GPIO_NR(2, 9), 1);
> > +		if (ret) {
> > +			dev_err(priv->dev, "Failed to set gpio up\n");
> > +			return ret;
> > +		}
> > +	}
> > +
> > +	return prt_imx6_init_kvg_power(priv, PW_MODE_KVG_NEW);
> > +}
> > +
> > +static int prt_imx6_init_kvg_new(struct prt_imx6_priv *priv)
> > +{
> > +	return prt_imx6_init_kvg_power(priv, PW_MODE_KVG_NEW);
> > +}
> > +
> > +static int prt_imx6_init_kvg_yaco(struct prt_imx6_priv *priv)
> > +{
> > +	return prt_imx6_init_kvg_power(priv, PW_MODE_KVG_WITH_YACO);
> > +}
> > +
> > +static int prt_imx6_rfid_fixup(struct prt_imx6_priv *priv,
> > +			       struct device_node *root)
> > +{
> > +	const struct prt_machine_data *dcfg = priv->dcfg;
> > +	struct device_node *node, *i2c_node;
> > +	char *eeprom_node_name, *alias;
> > +	int na, ns, len = 0;
> > +	int ret;
> > +	u8 *tmp;
> > +
> > +	alias = basprintf("i2c%d", dcfg->i2c_adapter);
> > +	if (!alias) {
> > +		ret = -ENOMEM;
> > +		goto exit_error;
> > +	}
> > +
> > +	i2c_node = of_find_node_by_alias(root, alias);
> > +	if (!i2c_node) {
> > +		dev_err(priv->dev, "Unsupported i2c adapter\n");
> > +		ret = -ENODEV;
> > +		goto free_alias;
> > +	}
> > +
> > +	eeprom_node_name = basprintf("/eeprom@%x", dcfg->i2c_addr);
> > +	if (!eeprom_node_name) {
> > +		ret = -ENOMEM;
> > +		goto free_alias;
> > +	}
> > +
> > +	node = of_create_node(i2c_node, eeprom_node_name);
> > +	if (!node) {
> > +		dev_err(priv->dev, "Failed to create node %s\n",
> > +			eeprom_node_name);
> > +		ret = -ENOMEM;
> > +		goto free_eeprom;
> > +	}
> > +
> > +	ret = of_property_write_string(node, "compatible", "atmel,24c256");
> > +	if (ret)
> > +		goto free_eeprom;
> > +
> > +	na = of_n_addr_cells(node);
> > +	ns = of_n_size_cells(node);
> > +	tmp = xzalloc((na + ns) * 4);
> > +
> > +	of_write_number(tmp + len, dcfg->i2c_addr, na);
> > +	len += na * 4;
> > +	of_write_number(tmp + len, 0, ns);
> > +	len += ns * 4;
> > +
> > +	ret = of_set_property(node, "reg", tmp, len, 1);
> > +	kfree(tmp);
> > +	if (ret)
> > +		goto free_eeprom;
> > +
> > +	return 0;
> > +free_eeprom:
> > +	kfree(eeprom_node_name);
> > +free_alias:
> > +	kfree(alias);
> > +exit_error:
> > +	dev_err(priv->dev, "Failed to apply fixup: %i\n", ret);
> > +	return ret;
> > +}
> > +
> > +static int prt_imx6_of_fixup(struct device_node *root, void *data)
> > +{
> > +	struct prt_imx6_priv *priv = data;
> > +	int ret;
> > +
> > +	if (!root) {
> > +		dev_err(priv->dev, "Unable to find the root node\n");
> > +		return -ENODEV;
> > +	}
> > +
> > +	ret = prt_imx6_rfid_fixup(priv, root);
> > +	if (ret)
> > +		goto exit_of_fixups;
> > +
> > +	return 0;
> > +exit_of_fixups:
> > +	dev_err(priv->dev, "Failed to apply OF fixups: %i\n", ret);
> > +	return ret;
> > +}
> > +
> > +static int prt_imx6_get_id(struct prt_imx6_priv *priv)
> > +{
> > +	struct gpio gpios_type[] = GPIO_HW_TYPE_ID;
> > +	struct gpio gpios_rev[] = GPIO_HW_REV_ID;
> > +	int ret;
> > +
> > +	ret = gpio_array_to_id(gpios_type, ARRAY_SIZE(gpios_type), &priv->hw_id);
> > +	if (ret)
> > +		goto exit_get_id;
> > +
> > +	ret = gpio_array_to_id(gpios_rev, ARRAY_SIZE(gpios_rev), &priv->hw_rev);
> > +	if (ret)
> > +		goto exit_get_id;
> > +
> > +	return 0;
> > +exit_get_id:
> > +	dev_err(priv->dev, "Failed to read gpio ID: %i\n", ret);
> > +	return ret;
> > +}
> > +
> > +static int prt_imx6_get_dcfg(struct prt_imx6_priv *priv)
> > +{
> > +	const struct prt_machine_data *dcfg, *found = NULL;
> > +	int ret;
> > +
> > +	dcfg = of_device_get_match_data(priv->dev);
> > +	if (!dcfg) {
> > +		ret = -EINVAL;
> > +		goto exit_get_dcfg;
> > +	}
> > +
> > +	for (; dcfg->hw_id != UINT_MAX; dcfg++) {
> > +		if (dcfg->hw_id != priv->hw_id)
> > +			continue;
> > +		if (dcfg->hw_rev > priv->hw_rev)
> > +			break;
> > +		found = dcfg;
> > +	}
> > +
> > +	if (!found) {
> > +		ret = -ENODEV;
> > +		goto exit_get_dcfg;
> > +	}
> > +
> > +	priv->dcfg = found;
> > +
> > +	return 0;
> > +exit_get_dcfg:
> > +	dev_err(priv->dev, "Failed to get dcfg: %i\n", ret);
> > +	return ret;
> > +}
> > +
> > +static int prt_imx6_probe(struct device_d *dev)
> > +{
> > +	struct prt_imx6_priv *priv;
> > +	const char *name, *ptr;
> > +	struct param_d *p;
> > +	int ret;
> > +
> > +	priv = kzalloc(sizeof(*priv), GFP_KERNEL);
> > +	if (!priv)
> > +		return -ENOMEM;
> > +
> > +	priv->dev = dev;
> > +	name = of_device_get_match_compatible(priv->dev);
> > +	ptr = strchr(name, ',');
> > +	priv->name =  ptr ? ptr + 1 : name;
> > +
> > +	pr_info("Detected machine type: %s\n", priv->name);
> > +
> > +	ret = prt_imx6_get_id(priv);
> > +	if (ret)
> > +		goto free_priv;
> > +
> > +	pr_info("  HW type:     %d\n", priv->hw_id);
> > +	pr_info("  HW revision: %d\n", priv->hw_rev);
> > +
> > +	ret = prt_imx6_get_dcfg(priv);
> > +	if (ret)
> > +		goto free_priv;
> > +
> > +	p = dev_add_param_uint32_ro(dev, "boardrev", &priv->hw_rev, "%u");
> > +	if (IS_ERR(p)) {
> > +		ret = PTR_ERR(p);
> > +		goto free_priv;
> > +	}
> > +
> > +	p = dev_add_param_uint32_ro(dev, "boardid", &priv->hw_id, "%u");
> > +	if (IS_ERR(p)) {
> > +		ret = PTR_ERR(p);
> > +		goto free_priv;
> > +	}
> > +
> > +	ret = prt_imx6_of_fixup(of_get_root_node(), priv);
> > +	if (ret)
> > +		goto free_priv;
> > +
> > +	ret = of_register_fixup(prt_imx6_of_fixup, priv);
> > +	if (ret) {
> > +		dev_err(dev, "Failed to register fixup\n");
> > +		goto free_priv;
> > +	}
> > +
> > +	prt_priv = priv;
> > +
> > +	return 0;
> > +free_priv:
> > +	kfree(priv);
> > +	return ret;
> > +}
> > +
> > +static const struct prt_machine_data prt_imx6_cfg_alti6p[] = {
> > +	{
> > +		.hw_id = HW_TYPE_ALTI6P,
> > +		.hw_rev = 0,
> > +		.i2c_addr = 0x51,
> > +		.i2c_adapter = 0,
> > +		.flags = PRT_IMX6_BOOTSRC_EMMC,
> > +	}, {
> > +		.hw_id = UINT_MAX
> > +	},
> > +};
> > +
> > +static const struct prt_machine_data prt_imx6_cfg_victgo[] = {
> > +	{
> > +		.hw_id = HW_TYPE_VICTGO,
> > +		.hw_rev = 0,
> > +		.i2c_addr = 0x51,
> > +		.i2c_adapter = 0,
> > +		.init = prt_imx6_init_victgo,
> > +		.flags = PRT_IMX6_BOOTSRC_SPI_NOR,
> > +	}, {
> > +		.hw_id = UINT_MAX
> > +	},
> > +};
> > +
> > +static const struct prt_machine_data prt_imx6_cfg_vicut1[] = {
> > +	{
> > +		.hw_id = HW_TYPE_VICUT1,
> > +		.hw_rev = 0,
> > +		.i2c_addr = 0x50,
> > +		.i2c_adapter = 1,
> > +		.flags = PRT_IMX6_BOOTSRC_SPI_NOR,
> > +	}, {
> > +		.hw_id = HW_TYPE_VICUT1,
> > +		.hw_rev = 1,
> > +		.i2c_addr = 0x51,
> > +		.i2c_adapter = 0,
> > +		.init = prt_imx6_init_kvg_yaco,
> > +		.flags = PRT_IMX6_BOOTSRC_SPI_NOR,
> > +	}, {
> > +		.hw_id = HW_TYPE_VICUT2,
> > +		.hw_rev = 1,
> > +		.i2c_addr = 0x51,
> > +		.i2c_adapter = 0,
> > +		.init = prt_imx6_init_kvg_new,
> > +		.flags = PRT_IMX6_BOOTSRC_SPI_NOR,
> > +	}, {
> > +		.hw_id = UINT_MAX
> > +	},
> > +};
> > +
> > +static const struct prt_machine_data prt_imx6_cfg_vicut1q[] = {
> > +	{
> > +		.hw_id = HW_TYPE_VICUT1,
> > +		.hw_rev = 0,
> > +		.i2c_addr = 0x50,
> > +		.i2c_adapter = 1,
> > +		.flags = PRT_IMX6_BOOTSRC_SPI_NOR,
> > +	}, {
> > +		.hw_id = HW_TYPE_VICUT1,
> > +		.hw_rev = 1,
> > +		.i2c_addr = 0x51,
> > +		.i2c_adapter = 0,
> > +		.init = prt_imx6_init_kvg_yaco,
> > +		.flags = PRT_IMX6_BOOTSRC_SPI_NOR,
> > +	}, {
> > +		.hw_id = HW_TYPE_VICUT2,
> > +		.hw_rev = 0,
> > +		.i2c_addr = 0x51,
> > +		.i2c_adapter = 0,
> > +		.init = prt_imx6_init_kvg_yaco,
> > +		.flags = PRT_IMX6_BOOTSRC_SPI_NOR,
> > +	}, {
> > +		.hw_id = HW_TYPE_VICUT2,
> > +		.hw_rev = 1,
> > +		.i2c_addr = 0x51,
> > +		.i2c_adapter = 0,
> > +		.init = prt_imx6_init_kvg_new,
> > +		.flags = PRT_IMX6_BOOTSRC_SPI_NOR,
> > +	}, {
> > +		.hw_id = UINT_MAX
> > +	},
> > +};
> > +
> > +static const struct prt_machine_data prt_imx6_cfg_vicutp[] = {
> > +	{
> > +		.hw_id = HW_TYPE_VICUT2,
> > +		.hw_rev = 1,
> > +		.i2c_addr = 0x51,
> > +		.i2c_adapter = 0,
> > +		.init = prt_imx6_init_kvg_new,
> > +		.flags = PRT_IMX6_BOOTSRC_SPI_NOR,
> > +	}, {
> > +		.hw_id = UINT_MAX
> > +	},
> > +};
> > +
> > +static const struct prt_machine_data prt_imx6_cfg_lanmcu[] = {
> > +	{
> > +		.hw_id = HW_TYPE_LANMCU,
> > +		.hw_rev = 0,
> > +		.i2c_addr = 0x51,
> > +		.i2c_adapter = 0,
> > +		.flags = PRT_IMX6_BOOTSRC_EMMC | PRT_IMX6_BOOTCHOOSER,
> > +	}, {
> > +		.hw_id = UINT_MAX
> > +	},
> > +};
> > +
> > +static const struct prt_machine_data prt_imx6_cfg_plybas[] = {
> > +	{
> > +		.hw_id = HW_TYPE_PLYBAS,
> > +		.hw_rev = 0,
> > +		.i2c_addr = 0x51,
> > +		.i2c_adapter = 0,
> > +		.flags = PRT_IMX6_BOOTSRC_SPI_NOR | PRT_IMX6_USB_LONG_DELAY,
> > +	}, {
> > +		.hw_id = UINT_MAX
> > +	},
> > +};
> > +
> > +static const struct prt_machine_data prt_imx6_cfg_plym2m[] = {
> > +	{
> > +		.hw_id = HW_TYPE_PLYM2M,
> > +		.hw_rev = 0,
> > +		.i2c_addr = 0x51,
> > +		.i2c_adapter = 0,
> > +		.flags = PRT_IMX6_BOOTSRC_SPI_NOR | PRT_IMX6_USB_LONG_DELAY,
> > +	}, {
> > +		.hw_id = UINT_MAX
> > +	},
> > +};
> > +
> > +static const struct prt_machine_data prt_imx6_cfg_prti6g[] = {
> > +	{
> > +		.hw_id = HW_TYPE_PRTI6G,
> > +		.hw_rev = 0,
> > +		.i2c_addr = 0x51,
> > +		.i2c_adapter = 0,
> > +		.flags = PRT_IMX6_BOOTSRC_EMMC,
> > +	}, {
> > +		.hw_id = UINT_MAX
> > +	},
> > +};
> > +
> > +static const struct prt_machine_data prt_imx6_cfg_prti6q[] = {
> > +	{
> > +		.hw_id = HW_TYPE_PRTI6Q,
> > +		.hw_rev = 0,
> > +		.i2c_addr = 0x51,
> > +		.i2c_adapter = 2,
> > +		.flags = PRT_IMX6_BOOTSRC_SPI_NOR,
> > +	}, {
> > +		.hw_id = HW_TYPE_PRTI6Q,
> > +		.hw_rev = 1,
> > +		.i2c_addr = 0x51,
> > +		.i2c_adapter = 0,
> > +		.flags = PRT_IMX6_BOOTSRC_SPI_NOR,
> > +	}, {
> > +		.hw_id = UINT_MAX
> > +	},
> > +};
> > +
> > +static const struct prt_machine_data prt_imx6_cfg_prtmvt[] = {
> > +	{
> > +		.hw_id = HW_TYPE_PRTMVT,
> > +		.hw_rev = 0,
> > +		.i2c_addr = 0x51,
> > +		.i2c_adapter = 0,
> > +		.flags = PRT_IMX6_BOOTSRC_SPI_NOR,
> > +	}, {
> > +		.hw_id = UINT_MAX
> > +	},
> > +};
> > +
> > +static const struct prt_machine_data prt_imx6_cfg_prtrvt[] = {
> > +	{
> > +		.hw_id = HW_TYPE_PRTRVT,
> > +		.hw_rev = 0,
> > +		.i2c_addr = 0x51,
> > +		.i2c_adapter = 0,
> > +		.flags = PRT_IMX6_BOOTSRC_SPI_NOR,
> > +	}, {
> > +		.hw_id = UINT_MAX
> > +	},
> > +};
> > +
> > +static const struct prt_machine_data prt_imx6_cfg_prtvt7[] = {
> > +	{
> > +		.hw_id = HW_TYPE_PRTVT7,
> > +		.hw_rev = 0,
> > +		.i2c_addr = 0x51,
> > +		.i2c_adapter = 0,
> > +		.flags = PRT_IMX6_BOOTSRC_EMMC | PRT_IMX6_BOOTCHOOSER,
> > +	}, {
> > +		.hw_id = UINT_MAX
> > +	},
> > +};
> > +
> > +static const struct prt_machine_data prt_imx6_cfg_prtwd2[] = {
> > +	{
> > +		.hw_id = HW_TYPE_PRTWD2,
> > +		.hw_rev = 0,
> > +		.i2c_addr = 0x51,
> > +		.i2c_adapter = 0,
> > +		.flags = PRT_IMX6_BOOTSRC_EMMC,
> > +	}, {
> > +		.hw_id = UINT_MAX
> > +	},
> > +};
> > +
> > +static const struct prt_machine_data prt_imx6_cfg_prtwd3[] = {
> > +	{
> > +		.hw_id = HW_TYPE_PRTWD2,
> > +		.hw_rev = 2,
> > +		.i2c_addr = 0x51,
> > +		.i2c_adapter = 0,
> > +		.flags = PRT_IMX6_BOOTSRC_EMMC,
> > +	}, {
> > +		.hw_id = UINT_MAX
> > +	},
> > +};
> > +
> > +static const struct of_device_id prt_imx6_of_match[] = {
> > +	{ .compatible = "alt,alti6p", .data = &prt_imx6_cfg_alti6p },
> > +	{ .compatible = "kvg,victgo", .data = &prt_imx6_cfg_victgo },
> > +	{ .compatible = "kvg,vicut1", .data = &prt_imx6_cfg_vicut1 },
> > +	{ .compatible = "kvg,vicut1q", .data = &prt_imx6_cfg_vicut1q },
> > +	{ .compatible = "kvg,vicutp", .data = &prt_imx6_cfg_vicutp },
> > +	{ .compatible = "lan,lanmcu", .data = &prt_imx6_cfg_lanmcu },
> > +	{ .compatible = "ply,plybas", .data = &prt_imx6_cfg_plybas },
> > +	{ .compatible = "ply,plym2m", .data = &prt_imx6_cfg_plym2m },
> > +	{ .compatible = "prt,prti6g", .data = &prt_imx6_cfg_prti6g },
> > +	{ .compatible = "prt,prti6q", .data = &prt_imx6_cfg_prti6q },
> > +	{ .compatible = "prt,prtmvt", .data = &prt_imx6_cfg_prtmvt },
> > +	{ .compatible = "prt,prtrvt", .data = &prt_imx6_cfg_prtrvt },
> > +	{ .compatible = "prt,prtvt7", .data = &prt_imx6_cfg_prtvt7 },
> > +	{ .compatible = "prt,prtwd2", .data = &prt_imx6_cfg_prtwd2 },
> > +	{ .compatible = "prt,prtwd3", .data = &prt_imx6_cfg_prtwd3 },
> > +	{ /* sentinel */ },
> > +};
> > +
> > +static struct driver_d prt_imx6_board_driver = {
> > +	.name = "board-protonic-imx6",
> > +	.probe = prt_imx6_probe,
> > +	.of_compatible = DRV_OF_COMPAT(prt_imx6_of_match),
> > +};
> > +postcore_platform_driver(prt_imx6_board_driver);

Best regards,
Oleksij
-- 
Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
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] 9+ messages in thread

end of thread, other threads:[~2020-08-17  6:54 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-08-13 12:55 [PATCH v3 0/6] prepare Protonic board code for mainline Oleksij Rempel
2020-08-13 12:55 ` [PATCH v3 1/6] gpiolib: add gpio_array_to_id helper to get ID out of GPIO array Oleksij Rempel
2020-08-13 12:55 ` [PATCH v3 2/6] common: console_common: add of_console_get_by_alias() helper Oleksij Rempel
2020-08-13 12:55 ` [PATCH v3 3/6] of: of_device_get_match_compatible() helper Oleksij Rempel
2020-08-13 12:55 ` [PATCH v3 4/6] ARM: protonic-imx6: port Protonic specific board code Oleksij Rempel
2020-08-13 14:07   ` David Jander
2020-08-17  6:54     ` Oleksij Rempel
2020-08-13 12:55 ` [PATCH v3 5/6] ARM: dts: unify barebox and barebox, env partitions for all Protonic boards Oleksij Rempel
2020-08-13 12:55 ` [PATCH v3 6/6] ARM: dts: imx6q-prti6q: add pstore/ramoops node Oleksij Rempel

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