All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCHv3 00/10] Introduce B1x5v2 support
@ 2020-08-21 16:16 Sebastian Reichel
  2020-08-21 16:16 ` [PATCHv3 01/10] bootcount: add a DM SPI flash backing store for bootcount Sebastian Reichel
                   ` (9 more replies)
  0 siblings, 10 replies; 12+ messages in thread
From: Sebastian Reichel @ 2020-08-21 16:16 UTC (permalink / raw)
  To: u-boot

This series introduces support for a new i.MX6DL based GE patient
monitor series.

Patch 1: Add support for storing bootcount in SPI-flash
Patch 2: Fix reading the status of output GPIOs
Patch 3+4: Improve M41T62 RTC driver's reset routine.
PATCH 5: Support disable_ldb_di_clock_sources for i.MX6DL
Patch 6: Add poweroff-gpio support
Patch 7-9: restructure common GE code
Patch 10: Add the actual board, using SPL and DM

Changes since PATCHv2 [1]:

* PATCH 10: Fixed network phy mode ("rgmii" -> "rgmii-id")
* PATCH 6: Fixed nits reported by Simon Glass and added is
  Reviewed-by Tag.

Changes since PATCHv1 [0]:

* Rebased to v2020.10-rc2
* Original patch 1 (support for DM_SPI_FLASH with non-DM SPL)
  has been dropped, since a similar patch has been merged
  in the meantime
* poweroff-gpio support is now added using sysreset uclass
  instead of introducing a new poweroff uclass
* B1x5v2 patch has been updated to follow recent U-Boot
  changes and to add USB mass storage support

[0] http://patchwork.ozlabs.org/project/uboot/list/?series=187150
[1] http://patchwork.ozlabs.org/project/uboot/list/?series=195398

-- Sebastian

Sebastian Reichel (10):
  bootcount: add a DM SPI flash backing store for bootcount
  gpio: mxc_gpio: add support to read status of output gpios
  rtc: m41t62: reset SQW in m41t62_rtc_reset
  rtc: m41t62: add oscillator fail bit reset support
  imx6: allow usage of disable_ldb_di_clock_sources for CONFIG_MX6QDL
  sysreset: Add poweroff-gpio driver
  board: ge: common: rename ge_common.c to ge_rtc.c
  board: ge: common: add config option for RTC and VPD feature
  board: ge: common: vpd: separate I2C specific code
  board: ge: b1x5v2: Add GE B1x5v2 and B1x5Pv2

 arch/arm/dts/Makefile                     |   1 +
 arch/arm/dts/imx6dl-b1x5v2.dts            | 654 ++++++++++++++++++++
 arch/arm/mach-imx/mx6/Kconfig             |  10 +
 arch/arm/mach-imx/mx6/clock.c             |   2 +-
 board/ge/b1x5v2/Kconfig                   |  14 +
 board/ge/b1x5v2/Makefile                  |   6 +
 board/ge/b1x5v2/b1x5v2.c                  | 698 ++++++++++++++++++++++
 board/ge/b1x5v2/spl.c                     | 587 ++++++++++++++++++
 board/ge/bx50v3/Kconfig                   |   2 +
 board/ge/bx50v3/bx50v3.c                  |   4 +-
 board/ge/common/Kconfig                   |   7 +
 board/ge/common/Makefile                  |   3 +-
 board/ge/common/{ge_common.c => ge_rtc.c} |   0
 board/ge/common/{ge_common.h => ge_rtc.h} |   0
 board/ge/common/vpd_reader.c              |  12 +-
 board/ge/common/vpd_reader.h              |  23 +-
 board/ge/mx53ppd/Kconfig                  |   2 +
 board/ge/mx53ppd/mx53ppd.c                |   4 +-
 configs/ge_b1x5v2_defconfig               | 136 +++++
 drivers/bootcount/Kconfig                 |  10 +
 drivers/bootcount/Makefile                |   1 +
 drivers/bootcount/spi-flash.c             | 125 ++++
 drivers/gpio/mxc_gpio.c                   |  10 +-
 drivers/rtc/m41t62.c                      | 139 ++++-
 drivers/sysreset/Kconfig                  |   7 +
 drivers/sysreset/Makefile                 |   1 +
 drivers/sysreset/poweroff_gpio.c          |  92 +++
 include/configs/ge_b1x5v2.h               | 127 ++++
 28 files changed, 2654 insertions(+), 23 deletions(-)
 create mode 100644 arch/arm/dts/imx6dl-b1x5v2.dts
 create mode 100644 board/ge/b1x5v2/Kconfig
 create mode 100644 board/ge/b1x5v2/Makefile
 create mode 100644 board/ge/b1x5v2/b1x5v2.c
 create mode 100644 board/ge/b1x5v2/spl.c
 create mode 100644 board/ge/common/Kconfig
 rename board/ge/common/{ge_common.c => ge_rtc.c} (100%)
 rename board/ge/common/{ge_common.h => ge_rtc.h} (100%)
 create mode 100644 configs/ge_b1x5v2_defconfig
 create mode 100644 drivers/bootcount/spi-flash.c
 create mode 100644 drivers/sysreset/poweroff_gpio.c
 create mode 100644 include/configs/ge_b1x5v2.h

-- 
2.28.0

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

* [PATCHv3 01/10] bootcount: add a DM SPI flash backing store for bootcount
  2020-08-21 16:16 [PATCHv3 00/10] Introduce B1x5v2 support Sebastian Reichel
@ 2020-08-21 16:16 ` Sebastian Reichel
  2020-08-21 16:16 ` [PATCHv3 02/10] gpio: mxc_gpio: add support to read status of output gpios Sebastian Reichel
                   ` (8 subsequent siblings)
  9 siblings, 0 replies; 12+ messages in thread
From: Sebastian Reichel @ 2020-08-21 16:16 UTC (permalink / raw)
  To: u-boot

This driver allows to use SPI flash as backing store for
boot counter values with DM enabled.

Signed-off-by: Sebastian Reichel <sebastian.reichel@collabora.com>
---
 drivers/bootcount/Kconfig     |  10 +++
 drivers/bootcount/Makefile    |   1 +
 drivers/bootcount/spi-flash.c | 125 ++++++++++++++++++++++++++++++++++
 3 files changed, 136 insertions(+)
 create mode 100644 drivers/bootcount/spi-flash.c

diff --git a/drivers/bootcount/Kconfig b/drivers/bootcount/Kconfig
index c8e6fa7f8925..b5ccea0d9c20 100644
--- a/drivers/bootcount/Kconfig
+++ b/drivers/bootcount/Kconfig
@@ -108,6 +108,16 @@ config DM_BOOTCOUNT_I2C_EEPROM
 	  pointing to the underlying i2c eeprom device) and an optional 'offset'
 	  property are supported.
 
+config DM_BOOTCOUNT_SPI_FLASH
+	bool "Support SPI flash devices as a backing store for bootcount"
+	depends on DM_SPI_FLASH
+	help
+	  Enabled reading/writing the bootcount in a DM SPI flash device.
+	  The wrapper device is to be specified with the compatible string
+	  'u-boot,bootcount-spi-flash' and the 'spi-flash'-property (a phandle
+	  pointing to the underlying SPI flash device) and an optional 'offset'
+	  property are supported.
+
 config BOOTCOUNT_MEM
 	bool "Support memory based bootcounter"
 	help
diff --git a/drivers/bootcount/Makefile b/drivers/bootcount/Makefile
index 059d40d16b0c..51d860b00e18 100644
--- a/drivers/bootcount/Makefile
+++ b/drivers/bootcount/Makefile
@@ -12,3 +12,4 @@ obj-$(CONFIG_BOOTCOUNT_EXT)	+= bootcount_ext.o
 obj-$(CONFIG_DM_BOOTCOUNT)      += bootcount-uclass.o
 obj-$(CONFIG_DM_BOOTCOUNT_RTC)  += rtc.o
 obj-$(CONFIG_DM_BOOTCOUNT_I2C_EEPROM)	+= i2c-eeprom.o
+obj-$(CONFIG_DM_BOOTCOUNT_SPI_FLASH)	+= spi-flash.o
diff --git a/drivers/bootcount/spi-flash.c b/drivers/bootcount/spi-flash.c
new file mode 100644
index 000000000000..7cd388e6616c
--- /dev/null
+++ b/drivers/bootcount/spi-flash.c
@@ -0,0 +1,125 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2019 Collabora
+ * (C) Copyright 2019 GE
+ */
+
+#include <common.h>
+#include <bootcount.h>
+#include <dm.h>
+#include <spi_flash.h>
+
+static const u8 bootcount_magic = 0xbc;
+
+struct bootcount_spi_flash_priv {
+	struct udevice *spi_flash;
+	u32 offset;
+};
+
+static int bootcount_spi_flash_update(struct udevice *dev, u32 offset, u32 len, const void *buf)
+{
+	struct spi_flash *flash = dev_get_uclass_priv(dev);
+	u32 sector_size = flash->sector_size;
+	u32 sector_offset = offset % sector_size;
+	u32 sector = offset - sector_offset;
+	int err = 0;
+
+	/* code only supports updating a single sector */
+	if (sector_offset + len > sector_size)
+		return -ENOSYS;
+
+	u8 *buffer = malloc(sector_size);
+	if (!buffer)
+		return -ENOMEM;
+
+	err = spi_flash_read_dm(dev, sector, sector_size, buffer);
+	if (err < 0)
+		goto out;
+
+	memcpy(buffer + sector_offset, buf, len);
+
+	err = spi_flash_erase_dm(dev, sector, sector_size);
+	if (err < 0)
+		goto out;
+
+	err = spi_flash_write_dm(dev, sector, sector_size, buffer);
+	if (err < 0)
+		goto out;
+
+out:
+	free(buffer);
+	return err;
+}
+
+static int bootcount_spi_flash_set(struct udevice *dev, const u32 a)
+{
+	struct bootcount_spi_flash_priv *priv = dev_get_priv(dev);
+	const u16 val = bootcount_magic << 8 | (a & 0xff);
+
+	if (bootcount_spi_flash_update(priv->spi_flash, priv->offset, 2, &val) < 0) {
+		debug("%s: write failed\n", __func__);
+		return -EIO;
+	}
+
+	return 0;
+}
+
+static int bootcount_spi_flash_get(struct udevice *dev, u32 *a)
+{
+	struct bootcount_spi_flash_priv *priv = dev_get_priv(dev);
+	u16 val;
+
+	if (spi_flash_read_dm(priv->spi_flash, priv->offset, 2, &val) < 0) {
+		debug("%s: read failed\n", __func__);
+		return -EIO;
+	}
+
+	if (val >> 8 == bootcount_magic) {
+		*a = val & 0xff;
+		return 0;
+	}
+
+	debug("%s: bootcount magic does not match on %04x\n", __func__, val);
+	return -EIO;
+}
+
+static int bootcount_spi_flash_probe(struct udevice *dev)
+{
+	struct ofnode_phandle_args phandle_args;
+	struct bootcount_spi_flash_priv *priv = dev_get_priv(dev);
+	struct udevice *spi_flash;
+
+	if (dev_read_phandle_with_args(dev, "spi-flash", NULL, 0, 0, &phandle_args)) {
+		debug("%s: spi-flash backing device not specified\n", dev->name);
+		return -ENOENT;
+	}
+
+	if (uclass_get_device_by_ofnode(UCLASS_SPI_FLASH, phandle_args.node, &spi_flash)) {
+		debug("%s: could not get backing device\n", dev->name);
+		return -ENODEV;
+	}
+
+	priv->spi_flash = spi_flash;
+	priv->offset = dev_read_u32_default(dev, "offset", 0);
+
+	return 0;
+}
+
+static const struct bootcount_ops bootcount_spi_flash_ops = {
+	.get = bootcount_spi_flash_get,
+	.set = bootcount_spi_flash_set,
+};
+
+static const struct udevice_id bootcount_spi_flash_ids[] = {
+	{ .compatible = "u-boot,bootcount-spi-flash" },
+	{ }
+};
+
+U_BOOT_DRIVER(bootcount_spi_flash) = {
+	.name	= "bootcount-spi-flash",
+	.id	= UCLASS_BOOTCOUNT,
+	.priv_auto_alloc_size = sizeof(struct bootcount_spi_flash_priv),
+	.probe	= bootcount_spi_flash_probe,
+	.of_match = bootcount_spi_flash_ids,
+	.ops	= &bootcount_spi_flash_ops,
+};
-- 
2.28.0

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

* [PATCHv3 02/10] gpio: mxc_gpio: add support to read status of output gpios
  2020-08-21 16:16 [PATCHv3 00/10] Introduce B1x5v2 support Sebastian Reichel
  2020-08-21 16:16 ` [PATCHv3 01/10] bootcount: add a DM SPI flash backing store for bootcount Sebastian Reichel
@ 2020-08-21 16:16 ` Sebastian Reichel
  2020-08-23 14:44   ` Fabio Estevam
  2020-08-21 16:16 ` [PATCHv3 03/10] rtc: m41t62: reset SQW in m41t62_rtc_reset Sebastian Reichel
                   ` (7 subsequent siblings)
  9 siblings, 1 reply; 12+ messages in thread
From: Sebastian Reichel @ 2020-08-21 16:16 UTC (permalink / raw)
  To: u-boot

This is supported by the hardware when the pinmux is configured
correctly. Usually it is not, so this adds explicit code for this.
This fixes all GPIO regulators being shown as disabled.

Signed-off-by: Sebastian Reichel <sebastian.reichel@collabora.com>
---
 drivers/gpio/mxc_gpio.c | 10 +++++++++-
 1 file changed, 9 insertions(+), 1 deletion(-)

diff --git a/drivers/gpio/mxc_gpio.c b/drivers/gpio/mxc_gpio.c
index 88b920a0746b..ddf79c3bb2d0 100644
--- a/drivers/gpio/mxc_gpio.c
+++ b/drivers/gpio/mxc_gpio.c
@@ -209,6 +209,11 @@ static void mxc_gpio_bank_set_value(struct gpio_regs *regs, int offset,
 	writel(l, &regs->gpio_dr);
 }
 
+static int mxc_gpio_bank_get_out_value(struct gpio_regs *regs, int offset)
+{
+	return (readl(&regs->gpio_dr) >> offset) & 1;
+}
+
 static int mxc_gpio_bank_get_value(struct gpio_regs *regs, int offset)
 {
 	return (readl(&regs->gpio_psr) >> offset) & 0x01;
@@ -245,7 +250,10 @@ static int mxc_gpio_get_value(struct udevice *dev, unsigned offset)
 {
 	struct mxc_bank_info *bank = dev_get_priv(dev);
 
-	return mxc_gpio_bank_get_value(bank->regs, offset);
+	if (mxc_gpio_is_output(bank->regs, offset))
+		return mxc_gpio_bank_get_out_value(bank->regs, offset);
+	else
+		return mxc_gpio_bank_get_value(bank->regs, offset);
 }
 
 /* write GPIO OUT value to pin 'gpio' */
-- 
2.28.0

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

* [PATCHv3 03/10] rtc: m41t62: reset SQW in m41t62_rtc_reset
  2020-08-21 16:16 [PATCHv3 00/10] Introduce B1x5v2 support Sebastian Reichel
  2020-08-21 16:16 ` [PATCHv3 01/10] bootcount: add a DM SPI flash backing store for bootcount Sebastian Reichel
  2020-08-21 16:16 ` [PATCHv3 02/10] gpio: mxc_gpio: add support to read status of output gpios Sebastian Reichel
@ 2020-08-21 16:16 ` Sebastian Reichel
  2020-08-21 16:16 ` [PATCHv3 04/10] rtc: m41t62: add oscillator fail bit reset support Sebastian Reichel
                   ` (6 subsequent siblings)
  9 siblings, 0 replies; 12+ messages in thread
From: Sebastian Reichel @ 2020-08-21 16:16 UTC (permalink / raw)
  To: u-boot

This takes care of resetting the 32kHz square wave, which is
used by some boards as clock source for the SoC.

Signed-off-by: Sebastian Reichel <sebastian.reichel@collabora.com>
---
 drivers/rtc/m41t62.c | 89 +++++++++++++++++++++++++++++++++++++++++---
 1 file changed, 83 insertions(+), 6 deletions(-)

diff --git a/drivers/rtc/m41t62.c b/drivers/rtc/m41t62.c
index 94a6b523aab3..85d6eb02593f 100644
--- a/drivers/rtc/m41t62.c
+++ b/drivers/rtc/m41t62.c
@@ -22,6 +22,7 @@
 #include <log.h>
 #include <rtc.h>
 #include <i2c.h>
+#include <linux/log2.h>
 
 #define M41T62_REG_SSEC	0
 #define M41T62_REG_SEC	1
@@ -49,6 +50,11 @@
 #define M41T62_FLAGS_AF		(1 << 6)	/* AF: Alarm Flag Bit */
 #define M41T62_FLAGS_BATT_LOW	(1 << 4)	/* BL: Battery Low Bit */
 
+#define M41T62_WDAY_SQW_FREQ_MASK	0xf0
+#define M41T62_WDAY_SQW_FREQ_SHIFT	4
+
+#define M41T62_SQW_MAX_FREQ	32768
+
 #define M41T62_FEATURE_HT	(1 << 0)
 #define M41T62_FEATURE_BL	(1 << 1)
 
@@ -139,21 +145,92 @@ static int m41t62_rtc_set(struct udevice *dev, const struct rtc_time *tm)
 	return 0;
 }
 
-static int m41t62_rtc_reset(struct udevice *dev)
+static int m41t62_sqw_enable(struct udevice *dev, bool enable)
+{
+	u8 val;
+	int ret;
+
+	ret = dm_i2c_read(dev, M41T62_REG_ALARM_MON, &val, sizeof(val));
+	if (ret)
+		return ret;
+
+	if (enable)
+		val |= M41T62_ALMON_SQWE;
+	else
+		val &= ~M41T62_ALMON_SQWE;
+
+	return dm_i2c_write(dev, M41T62_REG_ALARM_MON, &val, sizeof(val));
+}
+
+static int m41t62_sqw_set_rate(struct udevice *dev, unsigned int rate)
+{
+	u8 val, newval, sqwrateval;
+	int ret;
+
+	if (rate >= M41T62_SQW_MAX_FREQ)
+		sqwrateval = 1;
+	else if (rate >= M41T62_SQW_MAX_FREQ / 4)
+		sqwrateval = 2;
+	else if (rate)
+		sqwrateval = 15 - ilog2(rate);
+
+	ret = dm_i2c_read(dev, M41T62_REG_WDAY, &val, sizeof(val));
+	if (ret)
+		return ret;
+
+	newval = val;
+	newval &= ~M41T62_WDAY_SQW_FREQ_MASK;
+	newval |= (sqwrateval << M41T62_WDAY_SQW_FREQ_SHIFT);
+
+	/*
+	 * Try to avoid writing unchanged values. Writing to this register
+	 * will reset the internal counter pipeline and thus affect system
+	 * time.
+	 */
+	if (newval == val)
+		return 0;
+
+	return dm_i2c_write(dev, M41T62_REG_WDAY, &newval, sizeof(newval));
+}
+
+static int m41t62_rtc_clear_ht(struct udevice *dev)
 {
 	u8 val;
+	int ret;
 
 	/*
 	 * M41T82: Make sure HT (Halt Update) bit is cleared.
 	 * This bit is 0 in M41T62 so its save to clear it always.
 	 */
 
-	int ret = dm_i2c_read(dev, M41T62_REG_ALARM_HOUR, &val, sizeof(val));
-
+	ret = dm_i2c_read(dev, M41T62_REG_ALARM_HOUR, &val, sizeof(val));
+	if (ret)
+		return ret;
 	val &= ~M41T80_ALHOUR_HT;
-	ret |= dm_i2c_write(dev, M41T62_REG_ALARM_HOUR, &val, sizeof(val));
+	ret = dm_i2c_write(dev, M41T62_REG_ALARM_HOUR, &val, sizeof(val));
+	if (ret)
+		return ret;
+
+	return 0;
+}
 
-	return ret;
+static int m41t62_rtc_reset(struct udevice *dev)
+{
+	int ret;
+
+	ret = m41t62_rtc_clear_ht(dev);
+	if (ret)
+		return ret;
+
+	/*
+	 * Some boards feed the square wave as clock input into
+	 * the SoC. This enables a 32.768kHz square wave, which is
+	 * also the hardware default after power-loss.
+	 */
+	ret = m41t62_sqw_set_rate(dev, 32768);
+	if (ret)
+		return ret;
+	return m41t62_sqw_enable(dev, true);
 }
 
 /*
@@ -162,7 +239,7 @@ static int m41t62_rtc_reset(struct udevice *dev)
  */
 static int m41t62_rtc_probe(struct udevice *dev)
 {
-	return m41t62_rtc_reset(dev);
+	return m41t62_rtc_clear_ht(dev);
 }
 
 static const struct rtc_ops m41t62_rtc_ops = {
-- 
2.28.0

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

* [PATCHv3 04/10] rtc: m41t62: add oscillator fail bit reset support
  2020-08-21 16:16 [PATCHv3 00/10] Introduce B1x5v2 support Sebastian Reichel
                   ` (2 preceding siblings ...)
  2020-08-21 16:16 ` [PATCHv3 03/10] rtc: m41t62: reset SQW in m41t62_rtc_reset Sebastian Reichel
@ 2020-08-21 16:16 ` Sebastian Reichel
  2020-08-21 16:16 ` [PATCHv3 05/10] imx6: allow usage of disable_ldb_di_clock_sources for CONFIG_MX6QDL Sebastian Reichel
                   ` (5 subsequent siblings)
  9 siblings, 0 replies; 12+ messages in thread
From: Sebastian Reichel @ 2020-08-21 16:16 UTC (permalink / raw)
  To: u-boot

In case of empty battery or glitches the oscillator fail
bit might be set. This will reset the bit in the reset
routine.

Signed-off-by: Sebastian Reichel <sebastian.reichel@collabora.com>
---
 drivers/rtc/m41t62.c | 50 ++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 50 insertions(+)

diff --git a/drivers/rtc/m41t62.c b/drivers/rtc/m41t62.c
index 85d6eb02593f..0a4e12d69827 100644
--- a/drivers/rtc/m41t62.c
+++ b/drivers/rtc/m41t62.c
@@ -23,6 +23,7 @@
 #include <rtc.h>
 #include <i2c.h>
 #include <linux/log2.h>
+#include <linux/delay.h>
 
 #define M41T62_REG_SSEC	0
 #define M41T62_REG_SEC	1
@@ -48,6 +49,7 @@
 #define M41T62_ALMON_SQWE	(1 << 6)	/* SQWE: SQW Enable Bit */
 #define M41T62_ALHOUR_HT	(1 << 6)	/* HT: Halt Update Bit */
 #define M41T62_FLAGS_AF		(1 << 6)	/* AF: Alarm Flag Bit */
+#define M41T62_FLAGS_OF		(1 << 2)	/* OF: Oscillator Flag Bit */
 #define M41T62_FLAGS_BATT_LOW	(1 << 4)	/* BL: Battery Low Bit */
 
 #define M41T62_WDAY_SQW_FREQ_MASK	0xf0
@@ -193,6 +195,50 @@ static int m41t62_sqw_set_rate(struct udevice *dev, unsigned int rate)
 	return dm_i2c_write(dev, M41T62_REG_WDAY, &newval, sizeof(newval));
 }
 
+static int m41t62_rtc_restart_osc(struct udevice *dev)
+{
+	u8 val;
+	int ret;
+
+	/* 0. check if oscillator failure happened */
+	ret = dm_i2c_read(dev, M41T62_REG_FLAGS, &val, sizeof(val));
+	if (ret)
+		return ret;
+	if (!(val & M41T62_FLAGS_OF))
+		return 0;
+
+	ret = dm_i2c_read(dev, M41T62_REG_SEC, &val, sizeof(val));
+	if (ret)
+		return ret;
+
+	/* 1. Set stop bit */
+	val |= M41T62_SEC_ST;
+	ret = dm_i2c_write(dev, M41T62_REG_ALARM_HOUR, &val, sizeof(val));
+	if (ret)
+		return ret;
+
+	/* 2. Clear stop bit */
+	val &= ~M41T62_SEC_ST;
+	ret = dm_i2c_write(dev, M41T62_REG_ALARM_HOUR, &val, sizeof(val));
+	if (ret)
+		return ret;
+
+	/* 3. wait 4 seconds */
+	mdelay(4000);
+
+	ret = dm_i2c_read(dev, M41T62_REG_FLAGS, &val, sizeof(val));
+	if (ret)
+		return ret;
+
+	/* 4. clear M41T62_FLAGS_OF bit */
+	val &= ~M41T62_FLAGS_OF;
+	ret = dm_i2c_write(dev, M41T62_REG_FLAGS, &val, sizeof(val));
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
 static int m41t62_rtc_clear_ht(struct udevice *dev)
 {
 	u8 val;
@@ -218,6 +264,10 @@ static int m41t62_rtc_reset(struct udevice *dev)
 {
 	int ret;
 
+	ret = m41t62_rtc_restart_osc(dev);
+	if (ret)
+		return ret;
+
 	ret = m41t62_rtc_clear_ht(dev);
 	if (ret)
 		return ret;
-- 
2.28.0

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

* [PATCHv3 05/10] imx6: allow usage of disable_ldb_di_clock_sources for CONFIG_MX6QDL
  2020-08-21 16:16 [PATCHv3 00/10] Introduce B1x5v2 support Sebastian Reichel
                   ` (3 preceding siblings ...)
  2020-08-21 16:16 ` [PATCHv3 04/10] rtc: m41t62: add oscillator fail bit reset support Sebastian Reichel
@ 2020-08-21 16:16 ` Sebastian Reichel
  2020-08-21 16:16 ` [PATCHv3 06/10] sysreset: Add poweroff-gpio driver Sebastian Reichel
                   ` (4 subsequent siblings)
  9 siblings, 0 replies; 12+ messages in thread
From: Sebastian Reichel @ 2020-08-21 16:16 UTC (permalink / raw)
  To: u-boot

Allow using disable_ldb_di_clock_sources with just the combined
CONFIG_MX6QDL being enabled.

Signed-off-by: Sebastian Reichel <sebastian.reichel@collabora.com>
---
 arch/arm/mach-imx/mx6/clock.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/arch/arm/mach-imx/mx6/clock.c b/arch/arm/mach-imx/mx6/clock.c
index fb5e5b6f05c4..cb9d629be408 100644
--- a/arch/arm/mach-imx/mx6/clock.c
+++ b/arch/arm/mach-imx/mx6/clock.c
@@ -1341,7 +1341,7 @@ int do_mx6_showclocks(struct cmd_tbl *cmdtp, int flag, int argc,
 }
 
 #if defined(CONFIG_MX6Q) || defined(CONFIG_MX6D) || defined(CONFIG_MX6DL) || \
-	defined(CONFIG_MX6S)
+	defined(CONFIG_MX6S) || defined(CONFIG_MX6QDL)
 static void disable_ldb_di_clock_sources(void)
 {
 	struct mxc_ccm_reg *mxc_ccm = (struct mxc_ccm_reg *)CCM_BASE_ADDR;
-- 
2.28.0

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

* [PATCHv3 06/10] sysreset: Add poweroff-gpio driver
  2020-08-21 16:16 [PATCHv3 00/10] Introduce B1x5v2 support Sebastian Reichel
                   ` (4 preceding siblings ...)
  2020-08-21 16:16 ` [PATCHv3 05/10] imx6: allow usage of disable_ldb_di_clock_sources for CONFIG_MX6QDL Sebastian Reichel
@ 2020-08-21 16:16 ` Sebastian Reichel
  2020-08-21 16:16 ` [PATCHv3 07/10] board: ge: common: rename ge_common.c to ge_rtc.c Sebastian Reichel
                   ` (3 subsequent siblings)
  9 siblings, 0 replies; 12+ messages in thread
From: Sebastian Reichel @ 2020-08-21 16:16 UTC (permalink / raw)
  To: u-boot

Add GPIO poweroff driver, which is based on the Linux
driver and uses the same DT binding.

Reviewed-by: Simon Glass <sjg@chromium.org>
Signed-off-by: Sebastian Reichel <sebastian.reichel@collabora.com>
---
 drivers/sysreset/Kconfig         |  7 +++
 drivers/sysreset/Makefile        |  1 +
 drivers/sysreset/poweroff_gpio.c | 92 ++++++++++++++++++++++++++++++++
 3 files changed, 100 insertions(+)
 create mode 100644 drivers/sysreset/poweroff_gpio.c

diff --git a/drivers/sysreset/Kconfig b/drivers/sysreset/Kconfig
index 6ebc90e1d33b..bf042f32c848 100644
--- a/drivers/sysreset/Kconfig
+++ b/drivers/sysreset/Kconfig
@@ -43,6 +43,13 @@ config SYSRESET_CMD_POWEROFF
 
 endif
 
+config POWEROFF_GPIO
+	bool "Enable support for GPIO poweroff driver"
+	select DM_GPIO
+	help
+	  Support for system poweroff using a GPIO pin. This can be used
+	  for systems having a single GPIO to trigger a system poweroff.
+
 config SYSRESET_GPIO
 	bool "Enable support for GPIO reset driver"
 	select DM_GPIO
diff --git a/drivers/sysreset/Makefile b/drivers/sysreset/Makefile
index df2293b8489d..90a9b26abef4 100644
--- a/drivers/sysreset/Makefile
+++ b/drivers/sysreset/Makefile
@@ -7,6 +7,7 @@ obj-$(CONFIG_ARCH_ASPEED) += sysreset_ast.o
 obj-$(CONFIG_ARCH_ROCKCHIP) += sysreset_rockchip.o
 obj-$(CONFIG_ARCH_STI) += sysreset_sti.o
 obj-$(CONFIG_SANDBOX) += sysreset_sandbox.o
+obj-$(CONFIG_POWEROFF_GPIO) += poweroff_gpio.o
 obj-$(CONFIG_SYSRESET_GPIO) += sysreset_gpio.o
 obj-$(CONFIG_SYSRESET_MPC83XX) += sysreset_mpc83xx.o
 obj-$(CONFIG_SYSRESET_MICROBLAZE) += sysreset_microblaze.o
diff --git a/drivers/sysreset/poweroff_gpio.c b/drivers/sysreset/poweroff_gpio.c
new file mode 100644
index 000000000000..ac482c37f48f
--- /dev/null
+++ b/drivers/sysreset/poweroff_gpio.c
@@ -0,0 +1,92 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Toggles a GPIO pin to power down a device
+ *
+ * Created using the Linux driver as reference, which
+ * has been written by:
+ *
+ * Jamie Lentin <jm@lentin.co.uk>
+ * Andrew Lunn <andrew@lunn.ch>
+ *
+ * Copyright (C) 2012 Jamie Lentin
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <log.h>
+#include <sysreset.h>
+
+#include <asm/gpio.h>
+#include <linux/delay.h>
+
+struct poweroff_gpio_info {
+	struct gpio_desc gpio;
+	u32 active_delay_ms;
+	u32 inactive_delay_ms;
+	u32 timeout_ms;
+};
+
+static int poweroff_gpio_request(struct udevice *dev, enum sysreset_t type)
+{
+	struct poweroff_gpio_info *priv = dev_get_priv(dev);
+	int r;
+
+	if (type != SYSRESET_POWER_OFF)
+		return -ENOSYS;
+
+	debug("GPIO poweroff\n");
+
+	/* drive it active, also inactive->active edge */
+	r = dm_gpio_set_value(&priv->gpio, 1);
+	if (r < 0)
+		return r;
+	mdelay(priv->active_delay_ms);
+
+	/* drive inactive, also active->inactive edge */
+	r = dm_gpio_set_value(&priv->gpio, 0);
+	if (r < 0)
+		return r;
+	mdelay(priv->inactive_delay_ms);
+
+	/* drive it active, also inactive->active edge */
+	r = dm_gpio_set_value(&priv->gpio, 1);
+	if (r < 0)
+		return r;
+
+	/* give it some time */
+	mdelay(priv->timeout_ms);
+
+	return -EINPROGRESS;
+}
+
+static int poweroff_gpio_probe(struct udevice *dev)
+{
+	struct poweroff_gpio_info *priv = dev_get_priv(dev);
+	int flags;
+
+	flags = dev_read_bool(dev, "input") ? GPIOD_IS_IN : GPIOD_IS_OUT;
+	priv->active_delay_ms = dev_read_u32_default(dev, "active-delay-ms", 100);
+	priv->inactive_delay_ms = dev_read_u32_default(dev, "inactive-delay-ms", 100);
+	priv->timeout_ms = dev_read_u32_default(dev, "timeout-ms", 3000);
+
+	return gpio_request_by_name(dev, "gpios", 0, &priv->gpio, flags);
+}
+
+static struct sysreset_ops poweroff_gpio_ops = {
+	.request = poweroff_gpio_request,
+};
+
+static const struct udevice_id poweroff_gpio_ids[] = {
+	{ .compatible = "gpio-poweroff", },
+	{},
+};
+
+U_BOOT_DRIVER(poweroff_gpio) = {
+	.name		= "poweroff-gpio",
+	.id		= UCLASS_SYSRESET,
+	.ops		= &poweroff_gpio_ops,
+	.probe		= poweroff_gpio_probe,
+	.priv_auto_alloc_size = sizeof(struct poweroff_gpio_info),
+	.of_match	= poweroff_gpio_ids,
+};
-- 
2.28.0

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

* [PATCHv3 07/10] board: ge: common: rename ge_common.c to ge_rtc.c
  2020-08-21 16:16 [PATCHv3 00/10] Introduce B1x5v2 support Sebastian Reichel
                   ` (5 preceding siblings ...)
  2020-08-21 16:16 ` [PATCHv3 06/10] sysreset: Add poweroff-gpio driver Sebastian Reichel
@ 2020-08-21 16:16 ` Sebastian Reichel
  2020-08-21 16:16 ` [PATCHv3 08/10] board: ge: common: add config option for RTC and VPD feature Sebastian Reichel
                   ` (2 subsequent siblings)
  9 siblings, 0 replies; 12+ messages in thread
From: Sebastian Reichel @ 2020-08-21 16:16 UTC (permalink / raw)
  To: u-boot

The file only contains RTC related code, so let's name
it accordingly.

Signed-off-by: Sebastian Reichel <sebastian.reichel@collabora.com>
---
 board/ge/bx50v3/bx50v3.c                  | 2 +-
 board/ge/common/Makefile                  | 2 +-
 board/ge/common/{ge_common.c => ge_rtc.c} | 0
 board/ge/common/{ge_common.h => ge_rtc.h} | 0
 board/ge/mx53ppd/mx53ppd.c                | 2 +-
 5 files changed, 3 insertions(+), 3 deletions(-)
 rename board/ge/common/{ge_common.c => ge_rtc.c} (100%)
 rename board/ge/common/{ge_common.h => ge_rtc.h} (100%)

diff --git a/board/ge/bx50v3/bx50v3.c b/board/ge/bx50v3/bx50v3.c
index cf76cf7a3387..c6b0af8c776a 100644
--- a/board/ge/bx50v3/bx50v3.c
+++ b/board/ge/bx50v3/bx50v3.c
@@ -35,7 +35,7 @@
 #include <version.h>
 #include <stdlib.h>
 #include <dm/root.h>
-#include "../common/ge_common.h"
+#include "../common/ge_rtc.h"
 #include "../common/vpd_reader.h"
 #include "../../../drivers/net/e1000.h"
 #include <pci.h>
diff --git a/board/ge/common/Makefile b/board/ge/common/Makefile
index 8a21dcb8b533..36bedb198077 100644
--- a/board/ge/common/Makefile
+++ b/board/ge/common/Makefile
@@ -2,4 +2,4 @@
 #
 # Copyright 2017 General Electric Company
 
-obj-y  := vpd_reader.o ge_common.o
+obj-y  := vpd_reader.o ge_rtc.o
diff --git a/board/ge/common/ge_common.c b/board/ge/common/ge_rtc.c
similarity index 100%
rename from board/ge/common/ge_common.c
rename to board/ge/common/ge_rtc.c
diff --git a/board/ge/common/ge_common.h b/board/ge/common/ge_rtc.h
similarity index 100%
rename from board/ge/common/ge_common.h
rename to board/ge/common/ge_rtc.h
diff --git a/board/ge/mx53ppd/mx53ppd.c b/board/ge/mx53ppd/mx53ppd.c
index 7627e9c370fb..2e9d389850a2 100644
--- a/board/ge/mx53ppd/mx53ppd.c
+++ b/board/ge/mx53ppd/mx53ppd.c
@@ -36,7 +36,7 @@
 #include <watchdog.h>
 #include "ppd_gpio.h"
 #include <stdlib.h>
-#include "../../ge/common/ge_common.h"
+#include "../../ge/common/ge_rtc.h"
 #include "../../ge/common/vpd_reader.h"
 
 DECLARE_GLOBAL_DATA_PTR;
-- 
2.28.0

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

* [PATCHv3 08/10] board: ge: common: add config option for RTC and VPD feature
  2020-08-21 16:16 [PATCHv3 00/10] Introduce B1x5v2 support Sebastian Reichel
                   ` (6 preceding siblings ...)
  2020-08-21 16:16 ` [PATCHv3 07/10] board: ge: common: rename ge_common.c to ge_rtc.c Sebastian Reichel
@ 2020-08-21 16:16 ` Sebastian Reichel
  2020-08-21 16:16 ` [PATCHv3 09/10] board: ge: common: vpd: separate I2C specific code Sebastian Reichel
  2020-08-21 16:16 ` [PATCHv3 10/10] board: ge: b1x5v2: Add GE B1x5v2 and B1x5Pv2 Sebastian Reichel
  9 siblings, 0 replies; 12+ messages in thread
From: Sebastian Reichel @ 2020-08-21 16:16 UTC (permalink / raw)
  To: u-boot

While this code is being used by all GE platforms its useful
to have it behind a config option for hardware bringup of
new platforms.

Signed-off-by: Sebastian Reichel <sebastian.reichel@collabora.com>
---
 board/ge/bx50v3/Kconfig  | 2 ++
 board/ge/common/Kconfig  | 7 +++++++
 board/ge/common/Makefile | 3 ++-
 board/ge/mx53ppd/Kconfig | 2 ++
 4 files changed, 13 insertions(+), 1 deletion(-)
 create mode 100644 board/ge/common/Kconfig

diff --git a/board/ge/bx50v3/Kconfig b/board/ge/bx50v3/Kconfig
index 993b0559302b..05938560abda 100644
--- a/board/ge/bx50v3/Kconfig
+++ b/board/ge/bx50v3/Kconfig
@@ -15,4 +15,6 @@ config SYS_SOC
 config SYS_CONFIG_NAME
 	default "ge_bx50v3"
 
+source "board/ge/common/Kconfig"
+
 endif
diff --git a/board/ge/common/Kconfig b/board/ge/common/Kconfig
new file mode 100644
index 000000000000..323ed1f99607
--- /dev/null
+++ b/board/ge/common/Kconfig
@@ -0,0 +1,7 @@
+config GE_VPD
+	bool "Enable GE VPD Support"
+	default y
+
+config GE_RTC
+	bool "Enable GE RTC Support"
+	default y
diff --git a/board/ge/common/Makefile b/board/ge/common/Makefile
index 36bedb198077..8bd44e3c8a0f 100644
--- a/board/ge/common/Makefile
+++ b/board/ge/common/Makefile
@@ -2,4 +2,5 @@
 #
 # Copyright 2017 General Electric Company
 
-obj-y  := vpd_reader.o ge_rtc.o
+obj-$(CONFIG_GE_VPD)  += vpd_reader.o
+obj-$(CONFIG_GE_RTC)  += ge_rtc.o
diff --git a/board/ge/mx53ppd/Kconfig b/board/ge/mx53ppd/Kconfig
index 6dc3818cb7bb..bebb2fab0173 100644
--- a/board/ge/mx53ppd/Kconfig
+++ b/board/ge/mx53ppd/Kconfig
@@ -13,4 +13,6 @@ config SYS_SOC
 config SYS_CONFIG_NAME
 	default "mx53ppd"
 
+source "board/ge/common/Kconfig"
+
 endif
-- 
2.28.0

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

* [PATCHv3 09/10] board: ge: common: vpd: separate I2C specific code
  2020-08-21 16:16 [PATCHv3 00/10] Introduce B1x5v2 support Sebastian Reichel
                   ` (7 preceding siblings ...)
  2020-08-21 16:16 ` [PATCHv3 08/10] board: ge: common: add config option for RTC and VPD feature Sebastian Reichel
@ 2020-08-21 16:16 ` Sebastian Reichel
  2020-08-21 16:16 ` [PATCHv3 10/10] board: ge: b1x5v2: Add GE B1x5v2 and B1x5Pv2 Sebastian Reichel
  9 siblings, 0 replies; 12+ messages in thread
From: Sebastian Reichel @ 2020-08-21 16:16 UTC (permalink / raw)
  To: u-boot

This separates the I2C specific code from the generic
GE vital product data code, so that the generic parts
can be used on hardware with VPD stored in SPI flash
memory.

Signed-off-by: Sebastian Reichel <sebastian.reichel@collabora.com>
---
 board/ge/bx50v3/bx50v3.c     |  2 +-
 board/ge/common/vpd_reader.c | 12 ++++++------
 board/ge/common/vpd_reader.h | 23 +++++++++++++++++++----
 board/ge/mx53ppd/mx53ppd.c   |  2 +-
 4 files changed, 27 insertions(+), 12 deletions(-)

diff --git a/board/ge/bx50v3/bx50v3.c b/board/ge/bx50v3/bx50v3.c
index c6b0af8c776a..8a38ac5d4e4c 100644
--- a/board/ge/bx50v3/bx50v3.c
+++ b/board/ge/bx50v3/bx50v3.c
@@ -429,7 +429,7 @@ static void set_confidx(const struct vpd_cache* vpd)
 
 int board_init(void)
 {
-	if (!read_vpd(&vpd, vpd_callback)) {
+	if (!read_i2c_vpd(&vpd, vpd_callback)) {
 		int ret, rescan;
 
 		vpd.is_read = true;
diff --git a/board/ge/common/vpd_reader.c b/board/ge/common/vpd_reader.c
index d42b00da2fe6..421fee592291 100644
--- a/board/ge/common/vpd_reader.c
+++ b/board/ge/common/vpd_reader.c
@@ -110,9 +110,9 @@ static const size_t HEADER_BLOCK_ECC_LEN = 4;
 
 static const u8 ECC_BLOCK_ID = 0xFF;
 
-static int vpd_reader(size_t size, u8 *data, struct vpd_cache *userdata,
-		      int (*fn)(struct vpd_cache *, u8 id, u8 version, u8 type,
-				size_t size, u8 const *data))
+int vpd_reader(size_t size, u8 *data, struct vpd_cache *userdata,
+	       int (*fn)(struct vpd_cache *, u8 id, u8 version, u8 type,
+			 size_t size, u8 const *data))
 {
 	if (size < HEADER_BLOCK_LEN || !data || !fn)
 		return -EINVAL;
@@ -200,9 +200,9 @@ static int vpd_reader(size_t size, u8 *data, struct vpd_cache *userdata,
 	}
 }
 
-int read_vpd(struct vpd_cache *cache,
-	     int (*process_block)(struct vpd_cache *, u8 id, u8 version,
-				  u8 type, size_t size, u8 const *data))
+int read_i2c_vpd(struct vpd_cache *cache,
+		 int (*process_block)(struct vpd_cache *, u8 id, u8 version,
+				      u8 type, size_t size, u8 const *data))
 {
 	struct udevice *dev;
 	int ret;
diff --git a/board/ge/common/vpd_reader.h b/board/ge/common/vpd_reader.h
index 3045b7e21e22..0c51dc57e902 100644
--- a/board/ge/common/vpd_reader.h
+++ b/board/ge/common/vpd_reader.h
@@ -16,7 +16,22 @@ struct vpd_cache;
  *
  * Returns Non-zero on error.  Negative numbers encode errno.
  */
-int read_vpd(struct vpd_cache *cache,
-	     int (*process_block)(struct vpd_cache *,
-				  u8 id, u8 version, u8 type,
-				  size_t size, u8 const *data));
+int read_i2c_vpd(struct vpd_cache *cache,
+		 int (*process_block)(struct vpd_cache *, u8 id, u8 version,
+				      u8 type, size_t size, u8 const *data));
+
+/*
+ * Read VPD from given data, verify content, call callback for each vital
+ * product data block.
+ *
+ * size: size of the raw VPD data in bytes
+ * data: raw VPD data read from device
+ * cache: structure used by process block to store VPD information
+ * process_block: callback called for each VPD data block
+ *
+ * Returns Non-zero on error.  Negative numbers encode errno.
+ */
+
+int vpd_reader(size_t size, u8 *data, struct vpd_cache *cache,
+	       int (*process_block)(struct vpd_cache *, u8 id, u8 version, u8 type,
+				    size_t size, u8 const *data));
diff --git a/board/ge/mx53ppd/mx53ppd.c b/board/ge/mx53ppd/mx53ppd.c
index 2e9d389850a2..ef689733c41d 100644
--- a/board/ge/mx53ppd/mx53ppd.c
+++ b/board/ge/mx53ppd/mx53ppd.c
@@ -225,7 +225,7 @@ int board_late_init(void)
 	struct vpd_cache vpd;
 
 	memset(&vpd, 0, sizeof(vpd));
-	res = read_vpd(&vpd, vpd_callback);
+	res = read_i2c_vpd(&vpd, vpd_callback);
 	if (!res)
 		process_vpd(&vpd);
 	else
-- 
2.28.0

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

* [PATCHv3 10/10] board: ge: b1x5v2: Add GE B1x5v2 and B1x5Pv2
  2020-08-21 16:16 [PATCHv3 00/10] Introduce B1x5v2 support Sebastian Reichel
                   ` (8 preceding siblings ...)
  2020-08-21 16:16 ` [PATCHv3 09/10] board: ge: common: vpd: separate I2C specific code Sebastian Reichel
@ 2020-08-21 16:16 ` Sebastian Reichel
  9 siblings, 0 replies; 12+ messages in thread
From: Sebastian Reichel @ 2020-08-21 16:16 UTC (permalink / raw)
  To: u-boot

GE B1x5v2 patient monitor series is similar to the CARESCAPE Monitor
series (GE Bx50). It consists of a carrier PCB used in combination
with a Congatec QMX6 SoM. This adds U-Boot support using device model
everywhere and SPL for memory initialization.

Proper configuration is provided as 'ge_b1x5v2_defconfig' and the
combined image u-boot-with-spi.imx can be flashed directly to 1024
byte offset to /dev/mtdblock0. Alternatively SPL and u-boot.imx can
be loaded separately via USB-OTG using e.g. imx_usb.

Signed-off-by: Sebastian Reichel <sebastian.reichel@collabora.com>
---
 arch/arm/dts/Makefile          |   1 +
 arch/arm/dts/imx6dl-b1x5v2.dts | 654 ++++++++++++++++++++++++++++++
 arch/arm/mach-imx/mx6/Kconfig  |  10 +
 board/ge/b1x5v2/Kconfig        |  14 +
 board/ge/b1x5v2/Makefile       |   6 +
 board/ge/b1x5v2/b1x5v2.c       | 698 +++++++++++++++++++++++++++++++++
 board/ge/b1x5v2/spl.c          | 587 +++++++++++++++++++++++++++
 configs/ge_b1x5v2_defconfig    | 136 +++++++
 include/configs/ge_b1x5v2.h    | 127 ++++++
 9 files changed, 2233 insertions(+)
 create mode 100644 arch/arm/dts/imx6dl-b1x5v2.dts
 create mode 100644 board/ge/b1x5v2/Kconfig
 create mode 100644 board/ge/b1x5v2/Makefile
 create mode 100644 board/ge/b1x5v2/b1x5v2.c
 create mode 100644 board/ge/b1x5v2/spl.c
 create mode 100644 configs/ge_b1x5v2_defconfig
 create mode 100644 include/configs/ge_b1x5v2.h

diff --git a/arch/arm/dts/Makefile b/arch/arm/dts/Makefile
index 8ecf63e98864..0454a0c1f163 100644
--- a/arch/arm/dts/Makefile
+++ b/arch/arm/dts/Makefile
@@ -972,6 +972,7 @@ dtb-$(CONFIG_TARGET_GE_BX50V3) += \
 	imx6q-b650v3.dtb \
 	imx6q-b450v3.dtb
 
+dtb-$(CONFIG_TARGET_GE_B1X5V2) += imx6dl-b1x5v2.dtb
 dtb-$(CONFIG_TARGET_MX53PPD) += imx53-ppd.dtb
 
 dtb-$(CONFIG_TARGET_VEXPRESS_CA5X2) += vexpress-v2p-ca5s.dtb
diff --git a/arch/arm/dts/imx6dl-b1x5v2.dts b/arch/arm/dts/imx6dl-b1x5v2.dts
new file mode 100644
index 000000000000..638e50dab700
--- /dev/null
+++ b/arch/arm/dts/imx6dl-b1x5v2.dts
@@ -0,0 +1,654 @@
+/*
+ * GE B1x5v2 Patient Monitor
+ *
+ * Copyright 2018-2020 GE Inc.
+ * Copyright 2018-2020 Collabora Ltd.
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+
+/dts-v1/;
+
+#include "imx6dl.dtsi"
+#include <dt-bindings/gpio/gpio.h>
+
+/ {
+	compatible = "ge,imx6dl-b1x5v2", "congatec,qmx6", "fsl,imx6dl";
+
+	chosen {
+		bootargs = "console=ttymxc2,115200";
+		stdout-path = &uart3;
+	};
+
+	reg_3p3v: 3p3v {
+		compatible = "regulator-fixed";
+		regulator-name = "3P3V";
+		regulator-min-microvolt = <3300000>;
+		regulator-max-microvolt = <3300000>;
+		regulator-always-on;
+	};
+
+	reg_5v: regulator-5v {
+		compatible = "regulator-fixed";
+		regulator-name = "5V";
+		regulator-min-microvolt = <5000000>;
+		regulator-max-microvolt = <5000000>;
+		regulator-always-on;
+	};
+
+	reg_5v0_audio: regulator-5v0-audio {
+		compatible = "regulator-fixed";
+		regulator-name = "5V0_AUDIO";
+		regulator-min-microvolt = <5000000>;
+		regulator-max-microvolt = <5000000>;
+		vin-supply = <&reg_5v>;
+
+		gpio = <&tca6424a 16 GPIO_ACTIVE_HIGH>;
+		enable-active-high;
+
+		/*
+		 * This must be always-on for da7212, which has some not properly
+		 * documented dependencies for it's speaker supply pin. The issue
+		 * manifests as speaker volume being very low.
+		 */
+		regulator-always-on;
+		regulator-boot-on;
+	};
+
+	reg_lcd: regulator-lcd {
+		compatible = "regulator-fixed";
+		regulator-name = "LED_VCC";
+		regulator-min-microvolt = <12000000>;
+		regulator-max-microvolt = <12000000>;
+
+		pinctrl-0 = <&pinctrl_q7_lcd_power>;
+		pinctrl-names = "default";
+		gpio = <&gpio1 7 GPIO_ACTIVE_HIGH>; // LCDPWR
+		enable-active-high;
+	};
+
+	usb_power: regulator-usb-power {
+		compatible = "regulator-fixed";
+		regulator-name = "USB POWER";
+		regulator-min-microvolt = <5000000>;
+		regulator-max-microvolt = <5000000>;
+		vin-supply = <&reg_5v>;
+	};
+
+	backlight: backlight {
+		compatible = "pwm-backlight";
+		pinctrl-names = "default";
+		pinctrl-0 = <&pinctrl_q7_backlight_enable>;
+		power-supply = <&reg_lcd>;
+		pwms = <&pwm4 0 5000000>;
+		brightness-levels = <0 4 8 16 32 64 128 255>;
+		default-brightness-level = <7>;
+		enable-gpios = <&gpio1 9 GPIO_ACTIVE_HIGH>;
+	};
+
+	panel {
+		compatible = "simple-panel";
+		backlight = <&backlight>;
+
+		port {
+			panel_in: endpoint {
+				remote-endpoint = <&lvds0_out>;
+			};
+		};
+	};
+
+	bootcount {
+		compatible = "u-boot,bootcount-spi-flash";
+		spi-flash = <&flash>;
+		offset = <0x01003fe>;
+	};
+
+	leds {
+		compatible = "gpio-leds";
+		pinctrl-names = "default";
+		pinctrl-0 = <&pinctrl_q7_gpio1 &pinctrl_q7_gpio3 &pinctrl_q7_gpio5>;
+
+		alarm1 {
+			label = "alarm:red";
+			gpios = <&gpio1 8 GPIO_ACTIVE_HIGH>;
+		};
+
+		alarm2 {
+			label = "alarm:yellow";
+			gpios = <&gpio4 27 GPIO_ACTIVE_HIGH>;
+		};
+
+		alarm3 {
+			label = "alarm:blue";
+			gpios = <&gpio4 15 GPIO_ACTIVE_HIGH>;
+		};
+	};
+
+	poweroff {
+		compatible = "gpio-poweroff";
+		pinctrl-names = "default";
+		pinctrl-0 = <&pinctrl_q7_spi_cs1>;
+		gpios = <&gpio4 25 GPIO_ACTIVE_LOW>;
+		active-delay-ms = <1000>;
+		inactive-delay-ms = <0>;
+		timeout-ms = <5000>;
+	};
+
+	i2cmux {
+		compatible = "i2c-mux-gpio";
+		#address-cells = <1>;
+		#size-cells = <0>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&pinctrl_i2cmux>;
+		mux-gpios = <&gpio6 9 GPIO_ACTIVE_HIGH>;
+		i2c-parent = <&i2c2>;
+		idle-state = <1>;
+
+		i2c5: i2c at 0 {
+			reg = <0>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			tmp112: temperature-sensor at 48 {
+				compatible = "ti,tmp112";
+				reg = <0x48>;
+				interrupt-parent = <&tca6424a>;
+				interrupts = <2 IRQ_TYPE_LEVEL_LOW>;
+			};
+
+			tca6424a: gpio-controller at 22 {
+				compatible = "ti,tca6424";
+				reg = <0x22>;
+				gpio-controller;
+				#gpio-cells = <2>;
+
+				interrupt-parent = <&gpio7>;
+				interrupts = <11 IRQ_TYPE_EDGE_RISING>;
+				pinctrl-names = "default";
+				pinctrl-0 = <&pinctrl_q7_gpio6>;
+				interrupt-controller;
+				#interrupt-cells = <2>;
+
+				gpio-line-names = "GPIO_ROTOR#", "", "TMP_SENSOR_IRQ", "ACM_GPIO1", "ACM_GPIO2", "BATT_T", "", "",
+						  "ACM_GPIO3", "ACM_GPIO4", "USB1_POWER_EN", "EGPIO_CC_CTL0", "EGPIO_CC_CTL1", "12V_OEMNBP_EN", "CP2105_RST", "",
+						  "SPEAKER_PA_EN", "ARM7_UPI_RESET", "ARM7_PWR_RST", "NURSE_CALL", "MARKER_EN", "EGPIO_TOUCH_RST", "", "";
+			};
+		};
+
+		i2c6: i2c at 1 {
+			reg = <1>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			pmic: pmic at 08 {
+				compatible = "fsl,pfuze100";
+				reg = <0x08>;
+			};
+		};
+	};
+};
+
+&usbh1 {
+	/* Connected to USB-Hub SMSC USB2514, provides P0, P2, P3, P4 on Qseven connector */
+	vbus-supply = <&reg_5v>;
+	status = "okay";
+};
+
+&usbotg {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_usbotg>;
+	vbus-supply = <&usb_power>;
+	disable-over-current;
+	dr_mode = "host";
+	status = "okay";
+};
+
+&pmic {
+	regulators {
+		sw1a_reg: sw1ab {
+			regulator-min-microvolt = <300000>;
+			regulator-max-microvolt = <1875000>;
+			regulator-boot-on;
+			regulator-always-on;
+			regulator-ramp-delay = <6250>;
+		};
+
+		sw1c_reg: sw1c {
+			regulator-min-microvolt = <300000>;
+			regulator-max-microvolt = <1875000>;
+			regulator-boot-on;
+			regulator-always-on;
+			regulator-ramp-delay = <6250>;
+		};
+
+		sw2_reg: sw2 {
+			regulator-min-microvolt = <800000>;
+			regulator-max-microvolt = <3300000>;
+			regulator-boot-on;
+			regulator-always-on;
+		};
+
+		sw3a_reg: sw3a {
+			regulator-min-microvolt = <400000>;
+			regulator-max-microvolt = <1975000>;
+			regulator-boot-on;
+			regulator-always-on;
+		};
+
+		sw3b_reg: sw3b {
+			regulator-min-microvolt = <400000>;
+			regulator-max-microvolt = <1975000>;
+			regulator-boot-on;
+			regulator-always-on;
+		};
+
+		sw4_reg: sw4 {
+			regulator-min-microvolt = <675000>;
+			regulator-max-microvolt = <3300000>;
+			regulator-boot-on;
+			regulator-always-on;
+		};
+
+		swbst_reg: swbst {
+			regulator-min-microvolt = <5000000>;
+			regulator-max-microvolt = <5150000>;
+		};
+
+		snvs_reg: vsnvs {
+			regulator-min-microvolt = <1000000>;
+			regulator-max-microvolt = <3000000>;
+			regulator-boot-on;
+			regulator-always-on;
+		};
+
+		vref_reg: vrefddr {
+			regulator-boot-on;
+			regulator-always-on;
+		};
+
+		/* keep VGEN3, VGEN4 and VGEN5 enabled in order to maintain backward compatibility with hw-rev. A.0 */
+		vgen3_reg: vgen3 {
+			regulator-min-microvolt = <1800000>;
+			regulator-max-microvolt = <3300000>;
+			regulator-always-on;
+		};
+
+		vgen4_reg: vgen4 {
+			regulator-min-microvolt = <2500000>;
+			regulator-max-microvolt = <2500000>;
+			regulator-always-on;
+		};
+
+		vgen5_reg: vgen5 {
+			regulator-min-microvolt = <1800000>;
+			regulator-max-microvolt = <3300000>;
+			regulator-always-on;
+		};
+
+		/* supply voltage for eMMC */
+		vgen6_reg: vgen6 {
+			regulator-min-microvolt = <1800000>;
+			regulator-max-microvolt = <1800000>;
+			regulator-boot-on;
+			regulator-always-on;
+		};
+	};
+};
+
+&uart2 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_uart2>;
+	status = "okay";
+};
+
+&uart3 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_uart3>;
+	status = "okay";
+};
+
+&usdhc2 {
+	/* MicroSD card slot */
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_usdhc2>;
+	cd-gpios = <&gpio1 4 GPIO_ACTIVE_LOW>;
+	no-1-8-v;
+	keep-power-in-suspend;
+	wakeup-source;
+	vmmc-supply = <&reg_3p3v>;
+	status = "okay";
+};
+
+&usdhc3 {
+	/* eMMC module */
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_usdhc3>;
+	non-removable;
+	bus-width = <8>;
+	no-1-8-v;
+	keep-power-in-suspend;
+	wakeup-source;
+	vmmc-supply = <&reg_3p3v>;
+	status = "okay";
+};
+
+&i2c1 {
+	status = "okay";
+	pinctrl-names = "default", "gpio";
+	pinctrl-0 = <&pinctrl_i2c1>;
+	pinctrl-1 = <&pinctrl_i2c1_gpio>;
+	scl-gpios = <&gpio3 21 GPIO_ACTIVE_HIGH>;
+	sda-gpios = <&gpio3 28 GPIO_ACTIVE_HIGH>;
+
+	clock-frequency = <100000>;
+};
+
+&i2c2 {
+	status = "okay";
+	pinctrl-names = "default", "gpio";
+	pinctrl-0 = <&pinctrl_i2c2>;
+	pinctrl-1 = <&pinctrl_i2c2_gpio>;
+	scl-gpios = <&gpio4 12 GPIO_ACTIVE_HIGH>;
+	sda-gpios = <&gpio4 13 GPIO_ACTIVE_HIGH>;
+
+	clock-frequency = <100000>;
+};
+
+&i2c3 {
+	status = "okay";
+	pinctrl-names = "default", "gpio";
+	pinctrl-0 = <&pinctrl_i2c3>;
+	pinctrl-1 = <&pinctrl_i2c3_gpio>;
+	scl-gpios = <&gpio1 3 GPIO_ACTIVE_HIGH>;
+	sda-gpios = <&gpio1 6 GPIO_ACTIVE_HIGH>;
+
+	clock-frequency = <100000>;
+
+	rtc: m41t62 at 68 {
+		compatible = "st,m41t62";
+		reg = <0x68>;
+	};
+};
+
+&ldb {
+	status = "okay";
+
+	lvds0: lvds-channel at 0 {
+		status = "okay";
+		fsl,data-mapping = "spwg";
+		fsl,data-width = <24>;
+
+		port at 4 {
+			reg = <4>;
+			lvds0_out: endpoint {
+				remote-endpoint = <&panel_in>;
+			};
+		};
+	};
+};
+
+&hdmi {
+	status = "okay";
+};
+
+&fec {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_enet &pinctrl_phy_reset>;
+	phy-mode = "rgmii-id";
+	phy-handle = <&phy>;
+	status = "okay";
+
+	fsl,magic-packet;
+
+	mdio {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		phy: ethernet-phy at 6 {
+			compatible = "ethernet-phy-ieee802.3-c22";
+			reg = <6>;
+			qca,clk-out-frequency = <125000000>;
+			reset-gpios = <&gpio3 23 GPIO_ACTIVE_LOW>;
+			reset-assert-us = <2000>;
+		};
+	};
+};
+
+&ecspi1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_ecspi1>;
+	status = "okay";
+
+	num-cs = <1>;
+	cs-gpios = <&gpio3 19 GPIO_ACTIVE_LOW>;
+
+	flash: m25p80 at 0 {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		compatible = "st,sst25vf032b", "jedec,spi-nor";
+		spi-max-frequency = <20000000>;
+		reg = <0>;
+
+		partition at 0 {
+			label = "bootloader";
+			reg = <0x0000000 0x100000>;
+		};
+
+		partition at 100000 {
+			label = "user";
+			reg = <0x0100000 0x2fc000>;
+		};
+
+		partition at 3fc000 {
+			label = "reserved";
+			reg = <0x03fc000 0x4000>;
+			read-only;
+		};
+	};
+};
+
+&pwm4 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_pwm4>;
+	status = "okay";
+};
+
+&wdog1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_wdog>;
+	fsl,ext-reset-output;
+};
+
+&iomuxc {
+	imx6qdl-congatec-qmx6 {
+		pinctrl_uart2: uart2grp {
+			fsl,pins = <
+				MX6QDL_PAD_EIM_D26__UART2_TX_DATA	0x1b0b1
+				MX6QDL_PAD_EIM_D27__UART2_RX_DATA	0x1b0b1
+			>;
+		};
+
+		pinctrl_uart3: uart3grp {
+			fsl,pins = <
+				MX6QDL_PAD_EIM_D25__UART3_RX_DATA	0x1b0b1
+				MX6QDL_PAD_EIM_D24__UART3_TX_DATA	0x1b0b1
+			>;
+		};
+
+		pinctrl_wdog: wdoggrp {
+			fsl,pins = <
+				MX6QDL_PAD_DISP0_DAT8__WDOG1_B		0x1b0b0
+			>;
+		};
+
+		pinctrl_usdhc2: usdhc2grp {
+			fsl,pins = <
+				MX6QDL_PAD_SD2_CMD__SD2_CMD		0x17059
+				MX6QDL_PAD_SD2_CLK__SD2_CLK		0x10059
+				MX6QDL_PAD_SD2_DAT0__SD2_DATA0		0x17059
+				MX6QDL_PAD_SD2_DAT1__SD2_DATA1		0x17059
+				MX6QDL_PAD_SD2_DAT2__SD2_DATA2		0x17059
+				MX6QDL_PAD_SD2_DAT3__SD2_DATA3		0x17059
+			>;
+		};
+
+		pinctrl_usdhc2_cd: sd2cdgrp {
+			fsl,pins = <
+				MX6QDL_PAD_GPIO_4__GPIO1_IO04		0x1b0b0
+			>;
+		};
+
+		pinctrl_usdhc3: usdhc4grp {
+			fsl,pins = <
+				MX6QDL_PAD_SD3_CMD__SD3_CMD		0x17059
+				MX6QDL_PAD_SD3_CLK__SD3_CLK		0x10059
+				MX6QDL_PAD_SD3_DAT0__SD3_DATA0		0x17059
+				MX6QDL_PAD_SD3_DAT1__SD3_DATA1		0x17059
+				MX6QDL_PAD_SD3_DAT2__SD3_DATA2		0x17059
+				MX6QDL_PAD_SD3_DAT3__SD3_DATA3		0x17059
+				MX6QDL_PAD_SD3_DAT4__SD3_DATA4		0x17059
+				MX6QDL_PAD_SD3_DAT5__SD3_DATA5		0x17059
+				MX6QDL_PAD_SD3_DAT6__SD3_DATA6		0x17059
+				MX6QDL_PAD_SD3_DAT7__SD3_DATA7		0x17059
+			>;
+		};
+
+		pinctrl_i2c1: i2c1grp {
+			fsl,pins = <
+				MX6QDL_PAD_EIM_D21__I2C1_SCL		0x4001b8b1
+				MX6QDL_PAD_EIM_D28__I2C1_SDA		0x4001b8b1
+			>;
+		};
+
+		pinctrl_i2c1_gpio: i2c1gpiogrp {
+			fsl,pins = <
+				MX6QDL_PAD_EIM_D21__GPIO3_IO21		0x1b0b0
+				MX6QDL_PAD_EIM_D28__GPIO3_IO28		0x1b0b0
+			>;
+		};
+
+		pinctrl_i2c2: i2c2grp {
+			fsl,pins = <
+				MX6QDL_PAD_KEY_COL3__I2C2_SCL		0x4001b8b1
+				MX6QDL_PAD_KEY_ROW3__I2C2_SDA		0x4001b8b1
+			>;
+		};
+
+		pinctrl_i2c2_gpio: i2c2gpiogrp {
+			fsl,pins = <
+				MX6QDL_PAD_KEY_COL3__GPIO4_IO12		0x1b0b0
+				MX6QDL_PAD_KEY_ROW3__GPIO4_IO13		0x1b0b0
+			>;
+		};
+
+		pinctrl_i2c3: i2c3grp {
+			fsl,pins = <
+				MX6QDL_PAD_GPIO_3__I2C3_SCL		0x4001b8b1
+				MX6QDL_PAD_GPIO_6__I2C3_SDA		0x4001b8b1
+			>;
+		};
+
+		pinctrl_i2c3_gpio: i2c3gpiogrp {
+			fsl,pins = <
+				MX6QDL_PAD_GPIO_3__GPIO1_IO03		0x1b0b0
+				MX6QDL_PAD_GPIO_6__GPIO1_IO06		0x1b0b0
+			>;
+		};
+
+		pinctrl_ecspi1: ecspi1grp {
+			fsl,pins = <
+				MX6QDL_PAD_EIM_D16__ECSPI1_SCLK		0x100b1
+				MX6QDL_PAD_EIM_D17__ECSPI1_MISO		0x100b1
+				MX6QDL_PAD_EIM_D18__ECSPI1_MOSI		0x100b1
+				MX6QDL_PAD_EIM_D19__GPIO3_IO19          0x1b0b0
+			>;
+		};
+
+		pinctrl_enet: enetgrp {
+			fsl,pins = <
+				MX6QDL_PAD_ENET_MDIO__ENET_MDIO		0x1b0b0
+				MX6QDL_PAD_ENET_MDC__ENET_MDC		0x1b0b0
+				MX6QDL_PAD_RGMII_TXC__RGMII_TXC		0x1b030
+				MX6QDL_PAD_RGMII_TD0__RGMII_TD0		0x1b030
+				MX6QDL_PAD_RGMII_TD1__RGMII_TD1		0x1b030
+				MX6QDL_PAD_RGMII_TD2__RGMII_TD2		0x1b030
+				MX6QDL_PAD_RGMII_TD3__RGMII_TD3		0x1b030
+				MX6QDL_PAD_RGMII_TX_CTL__RGMII_TX_CTL	0x1b030
+				MX6QDL_PAD_ENET_REF_CLK__ENET_TX_CLK	0x1b0b0
+				MX6QDL_PAD_RGMII_RXC__RGMII_RXC		0x1b030
+				MX6QDL_PAD_RGMII_RD0__RGMII_RD0		0x1b030
+				MX6QDL_PAD_RGMII_RD1__RGMII_RD1		0x1b030
+				MX6QDL_PAD_RGMII_RD2__RGMII_RD2		0x1b030
+				MX6QDL_PAD_RGMII_RD3__RGMII_RD3		0x1b030
+				MX6QDL_PAD_RGMII_RX_CTL__RGMII_RX_CTL	0x1b030
+				MX6QDL_PAD_ENET_TX_EN__ENET_TX_EN	0x1b0b0
+			>;
+		};
+
+		pinctrl_phy_reset: phyrstgrp {
+			fsl,pins = <
+				MX6QDL_PAD_EIM_D23__GPIO3_IO23		0x1b0b0		/* RGMII Phy Reset */
+			>;
+		};
+
+		pinctrl_pwm4: pwm4grp {
+			fsl,pins = <
+				MX6QDL_PAD_SD1_CMD__PWM4_OUT		0x1b0b1		/* Q7[123] LVDS_BLT_CTRL */
+			>;
+		};
+
+		pinctrl_q7_lcd_power: lcdpwrgrp {
+			fsl,pins = <
+				MX6QDL_PAD_GPIO_7__GPIO1_IO07		0x1b0b0		/* Q7[111] LVDS_PPEN */
+			>;
+		};
+
+		pinctrl_q7_backlight_enable: blengrp {
+			fsl,pins = <
+				MX6QDL_PAD_GPIO_9__GPIO1_IO09		0x1b0b0		/* Q7[112] LVDS_BLEN */
+			>;
+		};
+
+		pinctrl_q7_gpio1: q7gpio1grp {
+			fsl,pins = <
+				MX6QDL_PAD_GPIO_8__GPIO1_IO08		0x1b0b0		/* Q7[186] GPIO1 */
+			>;
+		};
+
+		pinctrl_q7_gpio3: q7gpio3grp {
+			fsl,pins = <
+				MX6QDL_PAD_DISP0_DAT6__GPIO4_IO27	0x1b0b0		/* Q7[188] GPIO3 */
+			>;
+		};
+
+		pinctrl_q7_gpio5: q7gpio5grp {
+			fsl,pins = <
+				MX6QDL_PAD_KEY_ROW4__GPIO4_IO15		0x1b0b0		/* Q7[190] GPIO5 */
+			>;
+		};
+
+		pinctrl_q7_gpio6: q7gpio6grp {
+			fsl,pins = <
+				MX6QDL_PAD_GPIO_16__GPIO7_IO11		0x1b0b0		/* Q7[191] GPIO6 */
+			>;
+		};
+
+		pinctrl_q7_spi_cs1: spics1grp {
+			fsl,pins = <
+				MX6QDL_PAD_DISP0_DAT4__GPIO4_IO25	0x1b0b0		/* Q7[202] SPI_CS1# */
+			>;
+		};
+
+		pinctrl_i2cmux: i2cmuxgrp {
+			fsl,pins = <
+				MX6QDL_PAD_NANDF_WP_B__GPIO6_IO09	0x1b0b0
+			>;
+		};
+
+		pinctrl_usbotg: usbotggrp {
+			fsl,pins = <
+				MX6QDL_PAD_GPIO_1__USB_OTG_ID		0x17059		/* Q7[92] USB_ID */
+			>;
+		};
+	};
+};
diff --git a/arch/arm/mach-imx/mx6/Kconfig b/arch/arm/mach-imx/mx6/Kconfig
index 17173f983924..b8dd2f932bb5 100644
--- a/arch/arm/mach-imx/mx6/Kconfig
+++ b/arch/arm/mach-imx/mx6/Kconfig
@@ -249,6 +249,15 @@ config TARGET_GE_BX50V3
 	select BOARD_LATE_INIT
 	select MX6Q
 
+config TARGET_GE_B1X5V2
+	bool "General Electric B1x5v2"
+	select CPU_V7
+	select BOARD_LATE_INIT
+	select DM
+	select DM_THERMAL
+	select MX6QDL
+	select SUPPORT_SPL
+
 config TARGET_GW_VENTANA
 	bool "gw_ventana"
 	select MX6QDL
@@ -703,6 +712,7 @@ config SYS_SOC
 	default "mx6"
 
 source "board/ge/bx50v3/Kconfig"
+source "board/ge/b1x5v2/Kconfig"
 source "board/advantech/dms-ba16/Kconfig"
 source "board/aristainetos/Kconfig"
 source "board/armadeus/opos6uldev/Kconfig"
diff --git a/board/ge/b1x5v2/Kconfig b/board/ge/b1x5v2/Kconfig
new file mode 100644
index 000000000000..80a5bcae7dee
--- /dev/null
+++ b/board/ge/b1x5v2/Kconfig
@@ -0,0 +1,14 @@
+if TARGET_GE_B1X5V2
+
+config SYS_BOARD
+	default "b1x5v2"
+
+config SYS_VENDOR
+	default "ge"
+
+config SYS_CONFIG_NAME
+	default "ge_b1x5v2"
+
+source "board/ge/common/Kconfig"
+
+endif
diff --git a/board/ge/b1x5v2/Makefile b/board/ge/b1x5v2/Makefile
new file mode 100644
index 000000000000..8a27af52e1ae
--- /dev/null
+++ b/board/ge/b1x5v2/Makefile
@@ -0,0 +1,6 @@
+# SPDX-License-Identifier: GPL-2.0+
+#
+# Copyright 2018-2020 Collabora
+# Copyright 2018-2020 GE
+
+obj-y :=  b1x5v2.o spl.o
diff --git a/board/ge/b1x5v2/b1x5v2.c b/board/ge/b1x5v2/b1x5v2.c
new file mode 100644
index 000000000000..1cb347fd9e54
--- /dev/null
+++ b/board/ge/b1x5v2/b1x5v2.c
@@ -0,0 +1,698 @@
+/*
+ * GE B105v2, B125v2, B155v2
+ *
+ * Copyright 2018-2020 GE Inc.
+ * Copyright 2018-2020 Collabora Ltd.
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+
+#include <asm/arch/clock.h>
+#include <asm/arch/crm_regs.h>
+#include <asm/arch/imx-regs.h>
+#include <asm/arch/iomux.h>
+#include <asm/arch/sys_proto.h>
+#include <asm/gpio.h>
+#include <asm/io.h>
+#include <asm/mach-imx/video.h>
+#include <command.h>
+#include <common.h>
+#include <i2c.h>
+#include <input.h>
+#include <ipu_pixfmt.h>
+#include <linux/delay.h>
+#include <linux/fb.h>
+#include <malloc.h>
+#include <miiphy.h>
+#include <micrel.h>
+#include <netdev.h>
+#include <panel.h>
+#include <rtc.h>
+#include <spi_flash.h>
+#include <version.h>
+
+#include "../common/vpd_reader.h"
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#ifndef CONFIG_SPL_BUILD
+
+#define B1X5V2_GE_VPD_OFFSET	0x0100000
+#define B1X5V2_GE_VPD_SIZE	1022
+
+#define VPD_TYPE_INVALID	0x00
+#define VPD_BLOCK_NETWORK	0x20
+#define VPD_BLOCK_HWID		0x44
+#define VPD_MAC_ADDRESS_LENGTH	6
+
+#define VPD_FLAG_VALID_MAC	BIT(1)
+
+#define AR8035_PHY_ID			0x004dd072
+#define AR8035_PHY_DEBUG_ADDR_REG	0x1d
+#define AR8035_PHY_DEBUG_DATA_REG	0x1e
+#define AR8035_HIB_CTRL_REG		0xb
+#define AR8035_HIBERNATE_EN		(1 << 15)
+
+static struct vpd_cache {
+	bool is_read;
+	u8 product_id;
+	unsigned char mac[VPD_MAC_ADDRESS_LENGTH];
+	u32 flags;
+} vpd;
+
+enum product_type {
+	PRODUCT_TYPE_B105V2 = 6,
+	PRODUCT_TYPE_B105PV2 = 7,
+	PRODUCT_TYPE_B125V2 = 8,
+	PRODUCT_TYPE_B125PV2 = 9,
+	PRODUCT_TYPE_B155V2 = 10,
+
+	PRODUCT_TYPE_INVALID = 0,
+};
+
+int dram_init(void) {
+	gd->ram_size = imx_ddr_size();
+	return 0;
+}
+
+int power_init_board(void)
+{
+	/* all required PMIC configuration happens via DT */
+	return 0;
+}
+
+static int disable_phy_hibernation(struct phy_device *phydev)
+{
+	unsigned short val;
+
+	if (phydev->drv->uid == AR8035_PHY_ID) {
+		/* Disable hibernation, other configuration has been done by PHY driver */
+		phy_write(phydev, MDIO_DEVAD_NONE, AR8035_PHY_DEBUG_ADDR_REG, AR8035_HIB_CTRL_REG);
+		val = phy_read(phydev, MDIO_DEVAD_NONE, AR8035_PHY_DEBUG_DATA_REG);
+		val &= ~AR8035_HIBERNATE_EN;
+		phy_write(phydev, MDIO_DEVAD_NONE, AR8035_PHY_DEBUG_DATA_REG, val);
+	} else {
+		printf("Unknown PHY: %08x\n", phydev->drv->uid);
+	}
+
+	return 0;
+}
+
+int board_phy_config(struct phy_device *phydev)
+{
+	if (phydev->drv->config)
+		phydev->drv->config(phydev);
+
+	disable_phy_hibernation(phydev);
+
+	return 0;
+}
+
+static int auo_g101evn01_detect(const struct display_info_t *info)
+{
+	char *dev = env_get("devicetype");
+	return !strcmp(dev, "B105v2") || !strcmp(dev, "B105Pv2");
+}
+
+static int auo_g121ean01_detect(const struct display_info_t *info)
+{
+	char *dev = env_get("devicetype");
+	return !strcmp(dev, "B125v2") || !strcmp(dev, "B125Pv2");;
+}
+
+static int auo_g156xtn01_detect(const struct display_info_t *info)
+{
+	char *dev = env_get("devicetype");
+	return !strcmp(dev, "B155v2");
+}
+
+static void b1x5v2_backlight_enable(int percent)
+{
+	struct udevice *panel;
+	int ret;
+
+	ret = uclass_get_device(UCLASS_PANEL, 0, &panel);
+	if (ret) {
+		printf("Could not find panel: %d\n", ret);
+		return;
+	}
+
+	panel_set_backlight(panel, percent);
+	panel_enable_backlight(panel);
+
+}
+
+static void lcd_enable(const struct display_info_t *info)
+{
+	printf("Enable backlight...\n");
+	b1x5v2_backlight_enable(100);
+}
+
+struct display_info_t const displays[] = {
+{
+	.di = 0,
+	.bus = -1,
+	.addr = -1,
+	.pixfmt = IPU_PIX_FMT_RGB24,
+	.detect = auo_g156xtn01_detect,
+	.enable = lcd_enable,
+	.mode = {
+		.name = "AUO G156XTN01",
+		.refresh = 60,
+		.xres = 1368, /* because of i.MX6 limitation, actually 1366 */
+		.yres = 768,
+		.pixclock = 13158, /* 76 MHz in ps */
+		.left_margin = 33,
+		.right_margin = 67,
+		.upper_margin = 4,
+		.lower_margin = 4,
+		.hsync_len = 94,
+		.vsync_len = 30,
+		.sync = FB_SYNC_EXT,
+		.vmode = FB_VMODE_NONINTERLACED
+	}
+},
+{
+	.di = 0,
+	.bus = -1,
+	.addr = -1,
+	.pixfmt = IPU_PIX_FMT_RGB24,
+	.detect = auo_g121ean01_detect,
+	.enable = lcd_enable,
+	.mode = {
+		.name = "AUO G121EAN01.4",
+		.refresh = 60,
+		.xres = 1280,
+		.yres = 800,
+		.pixclock = 14992, /* 66.7 MHz in ps */
+		.left_margin = 8,
+		.right_margin = 58,
+		.upper_margin = 6,
+		.lower_margin = 4,
+		.hsync_len = 70,
+		.vsync_len = 10,
+		.sync = FB_SYNC_EXT,
+		.vmode = FB_VMODE_NONINTERLACED
+	}
+},
+{
+	.di = 0,
+	.bus = -1,
+	.addr = -1,
+	.pixfmt = IPU_PIX_FMT_RGB24,
+	.detect = auo_g101evn01_detect,
+	.enable = lcd_enable,
+	.mode = {
+		.name = "AUO G101EVN01.3",
+		.refresh = 60,
+		.xres = 1280,
+		.yres = 800,
+		.pixclock = 14992, /* 66.7 MHz in ps */
+		.left_margin = 8,
+		.right_margin = 58,
+		.upper_margin = 6,
+		.lower_margin = 4,
+		.hsync_len = 70,
+		.vsync_len = 10,
+		.sync = FB_SYNC_EXT,
+		.vmode = FB_VMODE_NONINTERLACED
+	}
+}
+};
+size_t display_count = ARRAY_SIZE(displays);
+
+static void enable_videopll(void)
+{
+	struct mxc_ccm_reg *ccm = (struct mxc_ccm_reg *)CCM_BASE_ADDR;
+	s32 timeout = 100000;
+
+	setbits_le32(&ccm->analog_pll_video, BM_ANADIG_PLL_VIDEO_POWERDOWN);
+
+	/* PLL_VIDEO  455MHz (24MHz * (37+11/12) / 2)
+	 *   |
+	 * PLL5
+	 *   |
+	 * CS2CDR[LDB_DI0_CLK_SEL]
+	 *   |
+	 *   +----> LDB_DI0_SERIAL_CLK_ROOT
+	 *   |
+	 *   +--> CSCMR2[LDB_DI0_IPU_DIV] --> LDB_DI0_IPU  455 / 7 = 65 MHz
+	 */
+
+	clrsetbits_le32(&ccm->analog_pll_video,
+			BM_ANADIG_PLL_VIDEO_DIV_SELECT |
+			BM_ANADIG_PLL_VIDEO_POST_DIV_SELECT,
+			BF_ANADIG_PLL_VIDEO_DIV_SELECT(37) |
+			BF_ANADIG_PLL_VIDEO_POST_DIV_SELECT(1));
+
+	writel(BF_ANADIG_PLL_VIDEO_NUM_A(11), &ccm->analog_pll_video_num);
+	writel(BF_ANADIG_PLL_VIDEO_DENOM_B(12), &ccm->analog_pll_video_denom);
+
+	clrbits_le32(&ccm->analog_pll_video, BM_ANADIG_PLL_VIDEO_POWERDOWN);
+
+	while (timeout--)
+		if (readl(&ccm->analog_pll_video) & BM_ANADIG_PLL_VIDEO_LOCK)
+			break;
+
+	if (timeout < 0)
+		printf("Warning: video pll lock timeout!\n");
+
+	clrsetbits_le32(&ccm->analog_pll_video,
+			BM_ANADIG_PLL_VIDEO_BYPASS,
+			BM_ANADIG_PLL_VIDEO_ENABLE);
+}
+
+static void setup_display(void)
+{
+	struct mxc_ccm_reg *mxc_ccm = (struct mxc_ccm_reg *)CCM_BASE_ADDR;
+	struct iomuxc *iomux = (struct iomuxc *)IOMUXC_BASE_ADDR;
+
+	enable_videopll();
+
+	/* When a reset/reboot is performed the display power needs to be turned
+	 * off for atleast 500ms. The boot time is ~300ms, we need to wait for
+	 * an additional 200ms here. Unfortunately we use external PMIC for
+	 * doing the reset, so can not differentiate between POR vs soft reset
+	 */
+	mdelay(200);
+
+	/* CCM_CSCMR2 -> ldb_di0_ipu_div [IMX6SDLRM page 839] */
+	/* divide IPU clock by 7 */
+	setbits_le32(&mxc_ccm->cscmr2, MXC_CCM_CSCMR2_LDB_DI0_IPU_DIV);
+
+	/* CCM_CHSCCDR -> ipu1_di0_clk_sel [IMX6SDLRM page 849] */
+	/* Set LDB_DI0 as clock source for IPU_DI0 */
+	clrsetbits_le32(&mxc_ccm->chsccdr,
+			MXC_CCM_CHSCCDR_IPU1_DI0_CLK_SEL_MASK,
+			(CHSCCDR_CLK_SEL_LDB_DI0 <<
+			MXC_CCM_CHSCCDR_IPU1_DI0_CLK_SEL_OFFSET));
+
+	/* Turn on IPU LDB DI0 clocks */
+	setbits_le32(&mxc_ccm->CCGR3, MXC_CCM_CCGR3_LDB_DI0_MASK);
+
+	enable_ipu_clock();
+
+	/* IOMUXC_GPR2 [IMX6SDLRM page 2049] */
+	/* Set LDB Channel 0 in SPWG 24 Bit mode */
+	writel(IOMUXC_GPR2_DI0_VS_POLARITY_ACTIVE_HIGH |
+	       IOMUXC_GPR2_BIT_MAPPING_CH0_SPWG |
+	       IOMUXC_GPR2_DATA_WIDTH_CH0_24BIT |
+	       IOMUXC_GPR2_LVDS_CH0_MODE_ENABLED_DI0,
+	       &iomux->gpr[2]);
+
+	/* IOMUXC_GPR3 [IMX6SDLRM page 2051] */
+	/* LVDS0 is connected to IPU DI0 */
+	clrsetbits_le32(&iomux->gpr[3],
+			IOMUXC_GPR3_LVDS0_MUX_CTL_MASK,
+		       (IOMUXC_GPR3_MUX_SRC_IPU1_DI0 <<
+			IOMUXC_GPR3_LVDS0_MUX_CTL_OFFSET));
+}
+
+/*
+ * Do not overwrite the console
+ * Use always serial for U-Boot console
+ */
+int overwrite_console(void)
+{
+	return 1;
+}
+
+int board_early_init_f(void)
+{
+	select_ldb_di_clock_source(MXC_PLL5_CLK);
+
+	return 0;
+}
+
+static int eeti_touch_get_model(struct udevice *dev, char *result) {
+	u8 query[68] = {0x67, 0x00, 0x42, 0x00, 0x03, 0x01, 'E', 0x00, 0x00, 0x00};
+	struct i2c_msg qmsg = {
+		.addr = 0x2a,
+		.flags = 0,
+		.len = sizeof(query),
+		.buf = query,
+	};
+	u8 reply[66] = {0};
+	struct i2c_msg rmsg = {
+		.addr = 0x2a,
+		.flags = I2C_M_RD,
+		.len = sizeof(reply),
+		.buf = reply,
+	};
+	int err;
+
+	err = dm_i2c_xfer(dev, &qmsg, 1);
+	if (err)
+		return err;
+
+	/*
+	 * device sends IRQ when its ok to read. To keep the code
+	 * simple we just wait an arbitrary, long enough time period.
+	 */
+	mdelay(10);
+
+	err = dm_i2c_xfer(dev, &rmsg, 1);
+	if (err)
+		return err;
+
+	if (reply[0] != 0x42 || reply[1] != 0x00 ||
+	    reply[2] != 0x03 || reply[4] != 'E')
+		return -EPROTO;
+
+	memcpy(result, reply+5, 10);
+	return 0;
+}
+
+static bool b1x5v2_board_is_p_model(void)
+{
+	struct udevice *bus = NULL;
+	struct udevice *dev = NULL;
+	int err;
+
+	err = uclass_get_device_by_name(UCLASS_I2C, "i2c at 21a0000", &bus);
+	if (err || !bus) {
+		printf("Could not get I2C bus: %d\n", err);
+		return true;
+	}
+
+	/* The P models do not have this port expander */
+	err = dm_i2c_probe(bus, 0x21, 0, &dev);
+	if (err || !dev) {
+		return true;
+	}
+
+	return false;
+}
+
+static enum product_type b1x5v2_board_type(void)
+{
+	struct udevice *bus = NULL;
+	struct udevice *dev = NULL;
+	char model[11] = {0};
+	int err;
+	int retry;
+
+	err = uclass_get_device_by_name(UCLASS_I2C, "i2c@21a8000", &bus);
+	if (err) {
+		printf("Could not get I2C bus: %d\n", err);
+		return PRODUCT_TYPE_INVALID;
+	}
+
+	err = dm_i2c_probe(bus, 0x41, 0, &dev);
+	if (!err && dev) { /* Ilitek Touchscreen */
+		if (b1x5v2_board_is_p_model()) {
+			return PRODUCT_TYPE_B105PV2;
+		} else {
+			return PRODUCT_TYPE_B105V2;
+		}
+	}
+
+	err = dm_i2c_probe(bus, 0x2a, 0, &dev);
+	if (err || !dev) {
+		printf("Could not find touchscreen: %d\n", err);
+		return PRODUCT_TYPE_INVALID;
+	}
+
+	for (retry = 0; retry < 3; ++retry) {
+		err = eeti_touch_get_model(dev, model);
+		if (!err)
+			break;
+		printf("Retry %d read EETI touchscreen model: %d\n", retry + 1, err);
+	}
+	if (err) {
+		printf("Could not read EETI touchscreen model: %d\n", err);
+		return PRODUCT_TYPE_INVALID;
+	}
+
+	if (!strcmp(model, "Orion_1320")) { /* EETI EXC80H60 */
+		if (b1x5v2_board_is_p_model()) {
+			return PRODUCT_TYPE_B125PV2;
+		} else {
+			return PRODUCT_TYPE_B125V2;
+		}
+	} else if (!strcmp(model, "Orion_1343")) { /* EETI EXC80H84 */
+		return PRODUCT_TYPE_B155V2;
+	}
+
+	printf("Unknown EETI touchscreen model: %s\n", model);
+	return PRODUCT_TYPE_INVALID;
+}
+
+static void set_env_per_board_type(enum product_type type)
+{
+	switch (type) {
+	case PRODUCT_TYPE_B105V2:
+		env_set("resolution", "1280x800");
+		env_set("devicetype", "B105v2");
+		env_set("fdtfile", "imx6dl-b105v2.dtb");
+		break;
+	case PRODUCT_TYPE_B105PV2:
+		env_set("resolution", "1280x800");
+		env_set("devicetype", "B105Pv2");
+		env_set("fdtfile", "imx6dl-b105pv2.dtb");
+		break;
+	case PRODUCT_TYPE_B125V2:
+		env_set("resolution", "1280x800");
+		env_set("devicetype", "B125v2");
+		env_set("fdtfile", "imx6dl-b125v2.dtb");
+		break;
+	case PRODUCT_TYPE_B125PV2:
+		env_set("resolution", "1280x800");
+		env_set("devicetype", "B125Pv2");
+		env_set("fdtfile", "imx6dl-b125pv2.dtb");
+		break;
+	case PRODUCT_TYPE_B155V2:
+		env_set("resolution", "1366x768");
+		env_set("devicetype", "B155v2");
+		env_set("fdtfile", "imx6dl-b155v2.dtb");
+		break;
+	default:
+		break;
+	}
+}
+
+static int b1x5v2_board_type_autodetect(void)
+{
+	enum product_type product = b1x5v2_board_type();
+	if (product != PRODUCT_TYPE_INVALID) {
+		set_env_per_board_type(product);
+		return 0;
+	}
+	return -1;
+}
+
+/*
+ * Extracts MAC and product information from the VPD.
+ */
+static int vpd_callback(struct vpd_cache *vpd, u8 id, u8 version, u8 type,
+			size_t size, u8 const *data)
+{
+	if (type == VPD_TYPE_INVALID)
+		return 0;
+
+	if (id == VPD_BLOCK_HWID && version == 1 && size >= 1) {
+		vpd->product_id = data[0];
+	} else if (id == VPD_BLOCK_NETWORK && version == 1) {
+		if (size >= VPD_MAC_ADDRESS_LENGTH) {
+			memcpy(vpd->mac, data, VPD_MAC_ADDRESS_LENGTH);
+			vpd->flags |= VPD_FLAG_VALID_MAC;
+		}
+	}
+
+	return 0;
+}
+
+static int read_spi_vpd(struct vpd_cache *cache,
+		 int (*process_block)(struct vpd_cache *, u8 id, u8 version,
+				      u8 type, size_t size, u8 const *data))
+{
+	static const int size = B1X5V2_GE_VPD_SIZE;
+	struct udevice *dev;
+	int ret;
+	u8 *data;
+
+	ret = uclass_get_device_by_name(UCLASS_SPI_FLASH, "m25p80 at 0", &dev);
+	if (ret)
+		return ret;
+
+	data = malloc(size);
+	if (!data)
+		return -ENOMEM;
+
+	ret = spi_flash_read_dm(dev, B1X5V2_GE_VPD_OFFSET, size, data);
+	if (ret) {
+		free(data);
+		return ret;
+	}
+
+	ret = vpd_reader(size, data, cache, process_block);
+
+	free(data);
+
+	return ret;
+}
+
+int board_init(void)
+{
+	if (!read_spi_vpd(&vpd, vpd_callback)) {
+		vpd.is_read = true;
+	}
+
+	/* address of boot parameters */
+	gd->bd->bi_boot_params = PHYS_SDRAM + 0x100;
+	setup_display();
+
+	return 0;
+}
+
+static void init_bootcause(void)
+{
+	const char *cause;
+
+	/* We care about WDOG only, treating everything else as
+	 * a power-on-reset.
+	 */
+	if (get_imx_reset_cause() & 0x0010)
+		cause = "WDOG";
+	else
+		cause = "POR";
+
+	env_set("bootcause", cause);
+}
+
+int misc_init_r(void)
+{
+	init_bootcause();
+
+	return 0;
+}
+
+#define M41T62_REG_FLAGS	0xf
+#define M41T62_FLAGS_OF		(1 << 2)
+static void check_time(void)
+{
+	struct udevice *rtc = NULL;
+	struct rtc_time tm;
+	u8 val;
+	int ret;
+
+	ret = uclass_get_device_by_name(UCLASS_RTC, "m41t62@68", &rtc);
+	if (ret) {
+		printf("Could not get RTC: %d\n", ret);
+		env_set("rtc_status", "FAIL");
+		return;
+	}
+
+	ret = dm_i2c_read(rtc, M41T62_REG_FLAGS, &val, sizeof(val));
+	if (ret) {
+		printf("Could not read RTC register: %d\n", ret);
+		env_set("rtc_status", "FAIL");
+		return;
+	}
+
+	ret = dm_rtc_reset(rtc);
+	if (ret) {
+		printf("Could not reset RTC: %d\n", ret);
+		env_set("rtc_status", "FAIL");
+		return;
+	}
+
+	if (val & M41T62_FLAGS_OF) {
+		env_set("rtc_status", "STOP");
+		return;
+	}
+
+	ret = dm_rtc_get(rtc, &tm);
+	if (ret) {
+		printf("Could not read RTC: %d\n", ret);
+		env_set("rtc_status", "FAIL");
+		return;
+	}
+
+	if (tm.tm_year > 2037) {
+		tm.tm_sec  = 0;
+		tm.tm_min  = 0;
+		tm.tm_hour = 0;
+		tm.tm_mday = 1;
+		tm.tm_wday = 2;
+		tm.tm_mon  = 1;
+		tm.tm_year = 2036;
+
+		ret = dm_rtc_set(rtc, &tm);
+		if (ret) {
+			printf("Could not update RTC: %d\n", ret);
+			env_set("rtc_status", "FAIL");
+			return;
+		}
+
+		printf("RTC behind 2037, capped to 2036 for userspace handling\n");
+		env_set("rtc_status", "2038");
+		return;
+	}
+
+	env_set("rtc_status", "OK");
+}
+
+static void process_vpd(struct vpd_cache *vpd)
+{
+	if (!vpd->is_read) {
+		printf("VPD wasn't read\n");
+		return;
+	}
+
+	if (vpd->flags & VPD_FLAG_VALID_MAC) {
+		eth_env_set_enetaddr_by_index("eth", 0, vpd->mac);
+		env_set("ethact", "eth0");
+	}
+}
+
+int board_late_init(void)
+{
+	process_vpd(&vpd);
+
+	if (vpd.product_id >= PRODUCT_TYPE_B105V2 &&
+	    vpd.product_id <= PRODUCT_TYPE_B155V2) {
+		set_env_per_board_type((enum product_type)vpd.product_id);
+	} else {
+		b1x5v2_board_type_autodetect();
+	}
+
+	printf("Board: GE %s\n", env_get("devicetype"));
+
+	check_time();
+
+	return 0;
+}
+
+#ifdef CONFIG_OF_BOARD_SETUP
+int ft_board_setup(void *blob, struct bd_info *bd)
+{
+	char *rtc_status = env_get("rtc_status");
+
+	fdt_setprop(blob, 0, "ge,boot-ver", version_string,
+	                                    strlen(version_string) + 1);
+	fdt_setprop(blob, 0, "ge,rtc-status", rtc_status,
+	                                    strlen(rtc_status) + 1);
+
+	return 0;
+}
+#endif
+
+static int do_b1x5v2_autodetect(struct cmd_tbl *cmdtp, int flag, int argc, char * const argv[])
+{
+	int err;
+
+	err = b1x5v2_board_type_autodetect();
+	if (!err)
+		printf("Identified %s\n", env_get("devicetype"));
+
+	return 0;
+}
+
+U_BOOT_CMD(
+       autodetect_devtype, 1,      1,      do_b1x5v2_autodetect,
+       "autodetect b1x5v2 device type",
+       ""
+);
+
+#endif // CONFIG_SPL_BUILD
diff --git a/board/ge/b1x5v2/spl.c b/board/ge/b1x5v2/spl.c
new file mode 100644
index 000000000000..2e6f905219fe
--- /dev/null
+++ b/board/ge/b1x5v2/spl.c
@@ -0,0 +1,587 @@
+/*
+ * GE b1x5v2 - QMX6 SPL
+ *
+ * Copyright 2013, Adeneo Embedded <www.adeneo-embedded.com>
+ * Copyright 2018-2020 GE Inc.
+ * Copyright 2018-2020 Collabora Ltd.
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+
+#include <asm/arch/clock.h>
+#include <asm/arch/crm_regs.h>
+#include <asm/arch/imx-regs.h>
+#include <asm/arch/iomux.h>
+#include <asm/arch/mx6-pins.h>
+#include <asm/arch/sys_proto.h>
+#include <asm/gpio.h>
+#include <init.h>
+#include <spi.h>
+#include <spi_flash.h>
+#include <spl.h>
+
+#if defined(CONFIG_SPL_BUILD)
+
+#include <asm/arch/mx6-ddr.h>
+
+#define IMX6DQ_DRIVE_STRENGTH_40_OHM		0x30
+#define IMX6DQ_DRIVE_STRENGTH_48_OHM		0x28
+#define IMX6DQ_DRIVE_STRENGTH			IMX6DQ_DRIVE_STRENGTH_40_OHM
+
+#define QMX6_DDR_PKE_DISABLED			0x00000000
+#define QMX6_DDR_ODT_60_OHM			(2 << 16)
+#define QMX6_DDR_TYPE_DDR3			0x000c0000
+
+#define QMX6_DRAM_SDCKE_PULLUP_100K		0x00003000
+#define QMX6_DRAM_SDBA2_PULLUP_NONE		0x00000000
+
+#define SPI_PAD_CTRL (PAD_CTL_HYS |				\
+	PAD_CTL_SPEED_MED |		\
+	PAD_CTL_DSE_40ohm | PAD_CTL_SRE_FAST)
+
+#define UART_PAD_CTRL  (PAD_CTL_PUS_100K_UP |			\
+	PAD_CTL_SPEED_MED | PAD_CTL_DSE_40ohm |			\
+	PAD_CTL_SRE_FAST  | PAD_CTL_HYS)
+
+#define SPI1_CS0 IMX_GPIO_NR(3, 19)
+#define POWEROFF IMX_GPIO_NR(4, 25)
+
+static iomux_v3_cfg_t const poweroff_pads[] = {
+	IOMUX_PADS(PAD_DISP0_DAT4__GPIO4_IO25 | MUX_PAD_CTRL(NO_PAD_CTRL)),
+};
+
+static iomux_v3_cfg_t const uart2_pads[] = {
+	IOMUX_PADS(PAD_EIM_D26__UART2_TX_DATA | MUX_PAD_CTRL(UART_PAD_CTRL)),
+	IOMUX_PADS(PAD_EIM_D27__UART2_RX_DATA | MUX_PAD_CTRL(UART_PAD_CTRL)),
+};
+
+static iomux_v3_cfg_t const uart3_pads[] = {
+	IOMUX_PADS(PAD_EIM_D24__UART3_TX_DATA | MUX_PAD_CTRL(UART_PAD_CTRL)),
+	IOMUX_PADS(PAD_EIM_D25__UART3_RX_DATA | MUX_PAD_CTRL(UART_PAD_CTRL)),
+};
+
+static iomux_v3_cfg_t const ecspi1_pads[] = {
+	IOMUX_PADS(PAD_EIM_D16__ECSPI1_SCLK | MUX_PAD_CTRL(SPI_PAD_CTRL)),
+	IOMUX_PADS(PAD_EIM_D17__ECSPI1_MISO | MUX_PAD_CTRL(SPI_PAD_CTRL)),
+	IOMUX_PADS(PAD_EIM_D18__ECSPI1_MOSI | MUX_PAD_CTRL(SPI_PAD_CTRL)),
+	IOMUX_PADS(PAD_EIM_D19__GPIO3_IO19 | MUX_PAD_CTRL(NO_PAD_CTRL)),
+};
+
+static struct mx6dq_iomux_ddr_regs mx6q_ddr_ioregs = {
+	.dram_sdclk_0 = IMX6DQ_DRIVE_STRENGTH,
+	.dram_sdclk_1 = IMX6DQ_DRIVE_STRENGTH,
+	.dram_cas = IMX6DQ_DRIVE_STRENGTH,
+	.dram_ras = IMX6DQ_DRIVE_STRENGTH,
+	.dram_reset = IMX6DQ_DRIVE_STRENGTH,
+	.dram_sdcke0 = QMX6_DRAM_SDCKE_PULLUP_100K,
+	.dram_sdcke1 = QMX6_DRAM_SDCKE_PULLUP_100K,
+	.dram_sdba2 = QMX6_DRAM_SDBA2_PULLUP_NONE,
+	.dram_sdodt0 = IMX6DQ_DRIVE_STRENGTH,
+	.dram_sdodt1 = IMX6DQ_DRIVE_STRENGTH,
+	.dram_sdqs0 = IMX6DQ_DRIVE_STRENGTH,
+	.dram_sdqs1 = IMX6DQ_DRIVE_STRENGTH,
+	.dram_sdqs2 = IMX6DQ_DRIVE_STRENGTH,
+	.dram_sdqs3 = IMX6DQ_DRIVE_STRENGTH,
+	.dram_sdqs4 = IMX6DQ_DRIVE_STRENGTH,
+	.dram_sdqs5 = IMX6DQ_DRIVE_STRENGTH,
+	.dram_sdqs6 = IMX6DQ_DRIVE_STRENGTH,
+	.dram_sdqs7 = IMX6DQ_DRIVE_STRENGTH,
+	.dram_dqm0 = IMX6DQ_DRIVE_STRENGTH,
+	.dram_dqm1 = IMX6DQ_DRIVE_STRENGTH,
+	.dram_dqm2 = IMX6DQ_DRIVE_STRENGTH,
+	.dram_dqm3 = IMX6DQ_DRIVE_STRENGTH,
+	.dram_dqm4 = IMX6DQ_DRIVE_STRENGTH,
+	.dram_dqm5 = IMX6DQ_DRIVE_STRENGTH,
+	.dram_dqm6 = IMX6DQ_DRIVE_STRENGTH,
+	.dram_dqm7 = IMX6DQ_DRIVE_STRENGTH,
+};
+
+static const struct mx6sdl_iomux_ddr_regs mx6dl_ddr_ioregs = {
+	.dram_sdclk_0 = IMX6DQ_DRIVE_STRENGTH,
+	.dram_sdclk_1 = IMX6DQ_DRIVE_STRENGTH,
+	.dram_cas = IMX6DQ_DRIVE_STRENGTH,
+	.dram_ras = IMX6DQ_DRIVE_STRENGTH,
+	.dram_reset = IMX6DQ_DRIVE_STRENGTH,
+	.dram_sdcke0 = QMX6_DRAM_SDCKE_PULLUP_100K,
+	.dram_sdcke1 = QMX6_DRAM_SDCKE_PULLUP_100K,
+	.dram_sdba2 = QMX6_DRAM_SDBA2_PULLUP_NONE,
+	.dram_sdodt0 = IMX6DQ_DRIVE_STRENGTH,
+	.dram_sdodt1 = IMX6DQ_DRIVE_STRENGTH,
+	.dram_sdqs0 = IMX6DQ_DRIVE_STRENGTH,
+	.dram_sdqs1 = IMX6DQ_DRIVE_STRENGTH,
+	.dram_sdqs2 = IMX6DQ_DRIVE_STRENGTH,
+	.dram_sdqs3 = IMX6DQ_DRIVE_STRENGTH,
+	.dram_sdqs4 = IMX6DQ_DRIVE_STRENGTH,
+	.dram_sdqs5 = IMX6DQ_DRIVE_STRENGTH,
+	.dram_sdqs6 = IMX6DQ_DRIVE_STRENGTH,
+	.dram_sdqs7 = IMX6DQ_DRIVE_STRENGTH,
+	.dram_dqm0 = IMX6DQ_DRIVE_STRENGTH,
+	.dram_dqm1 = IMX6DQ_DRIVE_STRENGTH,
+	.dram_dqm2 = IMX6DQ_DRIVE_STRENGTH,
+	.dram_dqm3 = IMX6DQ_DRIVE_STRENGTH,
+	.dram_dqm4 = IMX6DQ_DRIVE_STRENGTH,
+	.dram_dqm5 = IMX6DQ_DRIVE_STRENGTH,
+	.dram_dqm6 = IMX6DQ_DRIVE_STRENGTH,
+	.dram_dqm7 = IMX6DQ_DRIVE_STRENGTH,
+};
+
+static struct mx6dq_iomux_grp_regs mx6q_grp_ioregs = {
+	.grp_ddr_type = QMX6_DDR_TYPE_DDR3,
+	.grp_ddrmode_ctl = QMX6_DDR_ODT_60_OHM,
+	.grp_ddrpke = QMX6_DDR_PKE_DISABLED,
+	.grp_addds = IMX6DQ_DRIVE_STRENGTH,
+	.grp_ctlds = IMX6DQ_DRIVE_STRENGTH,
+	.grp_ddrmode = QMX6_DDR_ODT_60_OHM,
+	.grp_b0ds = IMX6DQ_DRIVE_STRENGTH,
+	.grp_b1ds = IMX6DQ_DRIVE_STRENGTH,
+	.grp_b2ds = IMX6DQ_DRIVE_STRENGTH,
+	.grp_b3ds = IMX6DQ_DRIVE_STRENGTH,
+	.grp_b4ds = IMX6DQ_DRIVE_STRENGTH,
+	.grp_b5ds = IMX6DQ_DRIVE_STRENGTH,
+	.grp_b6ds = IMX6DQ_DRIVE_STRENGTH,
+	.grp_b7ds = IMX6DQ_DRIVE_STRENGTH,
+};
+
+static const struct mx6sdl_iomux_grp_regs mx6sdl_grp_ioregs = {
+	.grp_ddr_type = QMX6_DDR_TYPE_DDR3,
+	.grp_ddrmode_ctl = QMX6_DDR_ODT_60_OHM,
+	.grp_ddrpke = QMX6_DDR_PKE_DISABLED,
+	.grp_addds = IMX6DQ_DRIVE_STRENGTH,
+	.grp_ctlds = IMX6DQ_DRIVE_STRENGTH,
+	.grp_ddrmode = QMX6_DDR_ODT_60_OHM,
+	.grp_b0ds = IMX6DQ_DRIVE_STRENGTH,
+	.grp_b1ds = IMX6DQ_DRIVE_STRENGTH,
+	.grp_b2ds = IMX6DQ_DRIVE_STRENGTH,
+	.grp_b3ds = IMX6DQ_DRIVE_STRENGTH,
+	.grp_b4ds = IMX6DQ_DRIVE_STRENGTH,
+	.grp_b5ds = IMX6DQ_DRIVE_STRENGTH,
+	.grp_b6ds = IMX6DQ_DRIVE_STRENGTH,
+	.grp_b7ds = IMX6DQ_DRIVE_STRENGTH,
+};
+
+const struct mx6_mmdc_calibration mx6q_mmcd_calib = {
+	.p0_mpwldectrl0 =  0x0016001A,
+	.p0_mpwldectrl1 =  0x0023001C,
+	.p1_mpwldectrl0 =  0x0028003A,
+	.p1_mpwldectrl1 =  0x001F002C,
+	.p0_mpdgctrl0 =  0x43440354,
+	.p0_mpdgctrl1 =  0x033C033C,
+	.p1_mpdgctrl0 =  0x43300368,
+	.p1_mpdgctrl1 =  0x03500330,
+	.p0_mprddlctl =  0x3228242E,
+	.p1_mprddlctl =  0x2C2C2636,
+	.p0_mpwrdlctl =  0x36323A38,
+	.p1_mpwrdlctl =  0x42324440,
+};
+
+const struct mx6_mmdc_calibration mx6q_2g_mmcd_calib = {
+	.p0_mpwldectrl0 =  0x00080016,
+	.p0_mpwldectrl1 =  0x001D0016,
+	.p1_mpwldectrl0 =  0x0018002C,
+	.p1_mpwldectrl1 =  0x000D001D,
+	.p0_mpdgctrl0 =    0x43200334,
+	.p0_mpdgctrl1 =    0x0320031C,
+	.p1_mpdgctrl0 =    0x0344034C,
+	.p1_mpdgctrl1 =    0x03380314,
+	.p0_mprddlctl =    0x3E36383A,
+	.p1_mprddlctl =    0x38363240,
+	.p0_mpwrdlctl =	   0x36364238,
+	.p1_mpwrdlctl =    0x4230423E,
+};
+
+const struct mx6_mmdc_calibration mx6q_4g_mmcd_calib = {
+	.p0_mpwldectrl0 =  0x00180018,
+	.p0_mpwldectrl1 =  0x00220018,
+	.p1_mpwldectrl0 =  0x00330046,
+	.p1_mpwldectrl1 =  0x002B003D,
+	.p0_mpdgctrl0 =    0x4344034C,
+	.p0_mpdgctrl1 =    0x033C033C,
+	.p1_mpdgctrl0 =    0x03700374,
+	.p1_mpdgctrl1 =    0x03600338,
+	.p0_mprddlctl =    0x443E3E40,
+	.p1_mprddlctl =    0x423E3E48,
+	.p0_mpwrdlctl =	   0x3C3C4442,
+	.p1_mpwrdlctl =    0x46384C46,
+};
+
+static const struct mx6_mmdc_calibration mx6s_mmcd_calib = {
+	.p0_mpwldectrl0 =  0x00480049,
+	.p0_mpwldectrl1 =  0x00410044,
+	.p0_mpdgctrl0 =    0x42480248,
+	.p0_mpdgctrl1 =    0x023C023C,
+	.p0_mprddlctl =    0x40424644,
+	.p0_mpwrdlctl =    0x34323034,
+};
+
+static const struct mx6_mmdc_calibration mx6s_2g_mmcd_calib = {
+	.p0_mpwldectrl0 =  0x00450048,
+	.p0_mpwldectrl1 =  0x003B003F,
+	.p0_mpdgctrl0 =    0x424C0248,
+	.p0_mpdgctrl1 =    0x0234023C,
+	.p0_mprddlctl =    0x40444848,
+	.p0_mpwrdlctl =    0x38363232,
+};
+
+static const struct mx6_mmdc_calibration mx6dl_mmcd_calib = {
+	.p0_mpwldectrl0 =  0x0043004B,
+	.p0_mpwldectrl1 =  0x003A003E,
+	.p1_mpwldectrl0 =  0x0047004F,
+	.p1_mpwldectrl1 =  0x004E0061,
+	.p0_mpdgctrl0 =    0x42500250,
+	.p0_mpdgctrl1 =	   0x0238023C,
+	.p1_mpdgctrl0 =    0x42640264,
+	.p1_mpdgctrl1 =    0x02500258,
+	.p0_mprddlctl =    0x40424846,
+	.p1_mprddlctl =    0x46484842,
+	.p0_mpwrdlctl =    0x38382C30,
+	.p1_mpwrdlctl =    0x34343430,
+};
+
+static const struct mx6_mmdc_calibration mx6dl_2g_mmcd_calib = {
+	.p0_mpwldectrl0 =  0x00450045,
+	.p0_mpwldectrl1 =  0x00390043,
+	.p1_mpwldectrl0 =  0x0049004D,
+	.p1_mpwldectrl1 =  0x004E0061,
+	.p0_mpdgctrl0 =    0x4240023C,
+	.p0_mpdgctrl1 =	   0x0228022C,
+	.p1_mpdgctrl0 =    0x02400244,
+	.p1_mpdgctrl1 =    0x02340238,
+	.p0_mprddlctl =    0x42464648,
+	.p1_mprddlctl =    0x4446463C,
+	.p0_mpwrdlctl =    0x3C38323A,
+	.p1_mpwrdlctl =    0x34323430,
+};
+
+static struct mx6_ddr3_cfg mem_ddr_2g = {
+	.mem_speed = 1600,
+	.density = 2,
+	.width = 16,
+	.banks = 8,
+	.rowaddr = 14,
+	.coladdr = 10,
+	.pagesz = 2,
+	.trcd = 1310,
+	.trcmin = 4875,
+	.trasmin = 3500,
+};
+
+static struct mx6_ddr3_cfg mem_ddr_4g = {
+	.mem_speed = 1600,
+	.density = 4,
+	.width = 16,
+	.banks = 8,
+	.rowaddr = 15,
+	.coladdr = 10,
+	.pagesz = 2,
+	.trcd = 1310,
+	.trcmin = 4875,
+	.trasmin = 3500,
+};
+
+static struct mx6_ddr3_cfg mem_ddr_8g = {
+	.mem_speed = 1600,
+	.density = 8,
+	.width = 16,
+	.banks = 8,
+	.rowaddr = 16,
+	.coladdr = 10,
+	.pagesz = 2,
+	.trcd = 1310,
+	.trcmin = 4875,
+	.trasmin = 3500,
+};
+
+static void spl_dram_init(u8 width, u32 memsize) {
+	struct mx6_ddr_sysinfo sysinfo = {
+		 /* width of data bus: 0=16, 1=32, 2=64 */
+		.dsize		= width / 32,
+		/* config for full 4GB range so that get_mem_size() works */
+		.cs_density	= 32,	/* 32Gb per CS */
+
+		.ncs = 1,
+		.cs1_mirror = 0,
+		.rtt_wr = 2,
+		.rtt_nom = 2,
+		.walat = 0,
+		.ralat = 5,
+		.mif3_mode = 3,
+		.bi_on = 1,
+		.sde_to_rst = 0x0d,
+		.rst_to_cke = 0x20,
+	};
+
+	if (is_cpu_type(MXC_CPU_MX6SOLO)) {
+		sysinfo.walat = 1;
+		mx6sdl_dram_iocfg(width, &mx6dl_ddr_ioregs, &mx6sdl_grp_ioregs);
+
+		switch(memsize) {
+		case 512:
+			mx6_dram_cfg(&sysinfo, &mx6s_2g_mmcd_calib, &mem_ddr_2g);
+			break;
+		default:
+			mx6_dram_cfg(&sysinfo, &mx6s_mmcd_calib, &mem_ddr_4g);
+			break;
+		}
+	} else if (is_cpu_type(MXC_CPU_MX6DL)) {
+		sysinfo.walat = 1;
+		mx6sdl_dram_iocfg(width, &mx6dl_ddr_ioregs, &mx6sdl_grp_ioregs);
+
+		switch(memsize) {
+		case 2048:
+			mx6_dram_cfg(&sysinfo, &mx6dl_2g_mmcd_calib, &mem_ddr_4g);
+			break;
+		default:
+			mx6_dram_cfg(&sysinfo, &mx6dl_mmcd_calib, &mem_ddr_2g);
+			break;
+		}
+	} else if (is_cpu_type(MXC_CPU_MX6Q)) {
+		mx6dq_dram_iocfg(width, &mx6q_ddr_ioregs, &mx6q_grp_ioregs);
+
+		switch(memsize) {
+		case 4096:
+			sysinfo.cs_density = 16;
+			sysinfo.ncs = 2;
+			mx6_dram_cfg(&sysinfo, &mx6q_4g_mmcd_calib, &mem_ddr_8g);
+			break;
+		case 2048:
+			mx6_dram_cfg(&sysinfo, &mx6q_2g_mmcd_calib, &mem_ddr_4g);
+			break;
+		default:
+			mx6_dram_cfg(&sysinfo, &mx6q_mmcd_calib, &mem_ddr_2g);
+			break;
+		}
+	}
+}
+
+/* Define a minimal structure so that the part number can be read via SPL */
+#define CFG_MFG_ADDR_OFFSET	(spi->size - SZ_16K)
+struct mfgdata {
+	unsigned char tsize;
+	/* size of checksummed part in bytes */
+	unsigned char ckcnt;
+	/* checksum corrected byte */
+	unsigned char cksum;
+	/* decimal serial number, packed BCD */
+	unsigned char serial[6];
+	 /* part number, right justified, ASCII */
+	unsigned char pn[16];
+};
+
+static void conv_ascii(unsigned char *dst, unsigned char *src, int len)
+{
+	int remain = len;
+	unsigned char *sptr = src;
+	unsigned char *dptr = dst;
+
+	while (remain) {
+		if (*sptr) {
+			*dptr = *sptr;
+			dptr++;
+		}
+		sptr++;
+		remain--;
+	}
+	*dptr = 0x0;
+}
+
+/*
+ * Returns the total size of the memory [in MB] the board is equipped with
+ *
+ * This is determined via the partnumber which is stored in the
+ * congatec manufacturing area
+ */
+static int get_boardmem_size(struct spi_flash *spi)
+{
+	int ret;
+	int i;
+	int arraysize;
+	char buf[sizeof(struct mfgdata)];
+	struct mfgdata *data = (struct mfgdata *)buf;
+	unsigned char outbuf[32];
+	char partnumbers_2g[4][7] = { "016104", "016105", "016304", "016305" };
+	char partnumbers_4g[2][7] = { "016308", "016318" };
+	char partnumbers_512m[2][7] = { "016203", "616300" };
+
+	ret = spi_flash_read(spi, CFG_MFG_ADDR_OFFSET, sizeof(struct mfgdata),
+			     buf);
+	if (ret)
+		return 1024; /* default to 1GByte in case of error */
+
+	conv_ascii(outbuf, data->pn, sizeof(data->pn));
+
+	printf("Detected Congatec QMX6 SOM: %s\n", outbuf);
+
+	/* congatec PN 016104, 016105, 016304, 016305 have 2GiB of RAM */
+	arraysize = sizeof(partnumbers_2g) / sizeof(partnumbers_2g[0]);
+	for (i=0; i < arraysize; i++) {
+		if (!memcmp(outbuf,partnumbers_2g[i],6))
+			return 2048;
+	}
+
+	/* congatec PN 016308, 016318 have 4GiB of RAM */
+	arraysize = sizeof(partnumbers_4g) / sizeof(partnumbers_4g[0]);
+	for (i=0; i < arraysize; i++) {
+		if (!memcmp(outbuf,partnumbers_4g[i],6))
+			return 4096;
+	}
+
+	/* congatec PN 016203, 616300 has 512MiB of RAM */
+	arraysize = sizeof(partnumbers_512m) / sizeof(partnumbers_512m[0]);
+	for (i=0; i < arraysize; i++) {
+		if (!memcmp(outbuf,partnumbers_512m[i],6))
+			return 512;
+	}
+
+	/* default to 1GByte */
+	return 1024;
+}
+
+void reset_cpu(ulong addr)
+{
+}
+
+int board_spi_cs_gpio(unsigned bus, unsigned cs)
+{
+	if (bus == 0 && cs == 0)
+		return (SPI1_CS0);
+	else
+		return -1;
+}
+
+static void memory_init(void) {
+	struct spi_flash *spi;
+	u8 width;
+	u32 size;
+
+	SETUP_IOMUX_PADS(ecspi1_pads);
+	gpio_direction_output(SPI1_CS0, 0);
+
+	spi = spi_flash_probe(CONFIG_ENV_SPI_BUS,
+			      CONFIG_ENV_SPI_CS,
+			      CONFIG_ENV_SPI_MAX_HZ, CONFIG_ENV_SPI_MODE);
+	if (!spi)
+		panic("Cannot identify board type: SPI-NOR flash module not detected\n");
+
+	/* lock manufacturer area */
+	spi_flash_protect(spi, CFG_MFG_ADDR_OFFSET, SZ_16K, true);
+
+	width = is_cpu_type(MXC_CPU_MX6SOLO) ? 32 : 64;
+	size = get_boardmem_size(spi);
+	printf("Detected Memory Size: %u\n", size);
+
+	spl_dram_init(width, size);
+}
+
+static void ccgr_init(void)
+{
+	struct mxc_ccm_reg *ccm = (struct mxc_ccm_reg *)CCM_BASE_ADDR;
+
+	static const uint32_t ccgr0 =
+		MXC_CCM_CCGR0_AIPS_TZ1_MASK |
+		MXC_CCM_CCGR0_AIPS_TZ2_MASK |
+		MXC_CCM_CCGR0_APBHDMA_MASK |
+		MXC_CCM_CCGR0_CAAM_SECURE_MEM_MASK |
+		MXC_CCM_CCGR0_CAAM_WRAPPER_ACLK_MASK |
+		MXC_CCM_CCGR0_CAAM_WRAPPER_IPG_MASK |
+		MXC_CCM_CCGR0_CHEETAH_DBG_CLK_MASK;
+
+	static const uint32_t ccgr1 =
+		MXC_CCM_CCGR1_ECSPI1S_MASK |
+		MXC_CCM_CCGR1_ENET_MASK |
+		MXC_CCM_CCGR1_EPIT1S_MASK |
+		MXC_CCM_CCGR1_EPIT2S_MASK |
+		MXC_CCM_CCGR1_GPT_BUS_MASK;
+
+	static const uint32_t ccgr2 =
+		MXC_CCM_CCGR2_IOMUX_IPT_CLK_IO_MASK |
+		MXC_CCM_CCGR2_IPMUX1_MASK |
+		MXC_CCM_CCGR2_IPMUX2_MASK |
+		MXC_CCM_CCGR2_IPMUX3_MASK |
+		MXC_CCM_CCGR2_IPSYNC_IP2APB_TZASC1_IPGS_MASK |
+		MXC_CCM_CCGR2_IPSYNC_IP2APB_TZASC2_IPG_MASK |
+		MXC_CCM_CCGR2_IPSYNC_VDOA_IPG_MASTER_CLK_MASK;
+
+	static const uint32_t ccgr3 =
+		MXC_CCM_CCGR3_MMDC_CORE_ACLK_FAST_CORE_P0_MASK |
+		MXC_CCM_CCGR3_MMDC_CORE_ACLK_FAST_CORE_P1_MASK |
+		MXC_CCM_CCGR3_MMDC_CORE_IPG_CLK_P0_MASK |
+		MXC_CCM_CCGR3_MMDC_CORE_IPG_CLK_P1_MASK |
+		MXC_CCM_CCGR3_OCRAM_MASK;
+
+	static const uint32_t ccgr4 =
+		MXC_CCM_CCGR4_PL301_MX6QFAST1_S133_MASK |
+		MXC_CCM_CCGR4_PL301_MX6QPER1_BCH_MASK |
+		MXC_CCM_CCGR4_PL301_MX6QPER2_MAINCLK_ENABLE_MASK |
+		MXC_CCM_CCGR4_PWM1_MASK |
+		MXC_CCM_CCGR4_PWM2_MASK |
+		MXC_CCM_CCGR4_PWM3_MASK |
+		MXC_CCM_CCGR4_PWM4_MASK;
+
+	static const uint32_t ccgr5 =
+		MXC_CCM_CCGR5_ROM_MASK |
+		MXC_CCM_CCGR5_SDMA_MASK |
+		MXC_CCM_CCGR5_UART_MASK |
+		MXC_CCM_CCGR5_UART_SERIAL_MASK;
+
+	static const uint32_t ccgr6 =
+		MXC_CCM_CCGR6_USBOH3_MASK |
+		MXC_CCM_CCGR6_USDHC1_MASK |
+		MXC_CCM_CCGR6_USDHC2_MASK |
+		MXC_CCM_CCGR6_SIM1_CLK_MASK |
+		MXC_CCM_CCGR6_SIM2_CLK_MASK;
+
+	writel(ccgr0, &ccm->CCGR0);
+	writel(ccgr1, &ccm->CCGR1);
+	writel(ccgr2, &ccm->CCGR2);
+	writel(ccgr3, &ccm->CCGR3);
+	writel(ccgr4, &ccm->CCGR4);
+	writel(ccgr5, &ccm->CCGR5);
+	writel(ccgr6, &ccm->CCGR6);
+}
+
+void board_init_f(ulong dummy)
+{
+	/* setup clock gating */
+	ccgr_init();
+
+	/* setup AIPS and disable watchdog */
+	arch_cpu_init();
+
+	/* setup AXI */
+	gpr_init();
+
+	/*
+	 * setup poweroff GPIO. This controls system power regulator. Once
+	 * the power button is released this must be enabled to keep system
+	 * running. Not enabling it (or disabling it later) will turn off
+	 * the main system regulator and instantly poweroff the system. We
+	 * do this very early, to reduce the time users have to press the
+	 * power button.
+	 */
+	SETUP_IOMUX_PADS(poweroff_pads);
+	gpio_direction_output(POWEROFF, 1);
+
+	/* setup GP timer */
+	timer_init();
+
+	/* iomux */
+	if (CONFIG_MXC_UART_BASE == UART2_BASE)
+		SETUP_IOMUX_PADS(uart2_pads);
+	else if (CONFIG_MXC_UART_BASE == UART3_BASE)
+		SETUP_IOMUX_PADS(uart3_pads);
+
+	/* UART clocks enabled and gd valid - init serial console */
+	preloader_console_init();
+
+	/* Needed for malloc() [used by SPI] to work in SPL prior to board_init_r() */
+	spl_init();
+
+	/* DDR initialization */
+	memory_init();
+}
+
+void spl_board_prepare_for_boot(void)
+{
+	printf("Load normal U-Boot...\n");
+}
+#endif
diff --git a/configs/ge_b1x5v2_defconfig b/configs/ge_b1x5v2_defconfig
new file mode 100644
index 000000000000..e2e368e9302d
--- /dev/null
+++ b/configs/ge_b1x5v2_defconfig
@@ -0,0 +1,136 @@
+CONFIG_ARM=y
+CONFIG_ARCH_MX6=y
+CONFIG_SYS_TEXT_BASE=0x17800000
+CONFIG_SPL_GPIO_SUPPORT=y
+CONFIG_SPL_LIBCOMMON_SUPPORT=y
+CONFIG_SPL_LIBGENERIC_SUPPORT=y
+CONFIG_SYS_MALLOC_F_LEN=0x4000
+CONFIG_NR_DRAM_BANKS=1
+CONFIG_ENV_SIZE=0x2000
+CONFIG_ENV_OFFSET=0xC0000
+CONFIG_ENV_SECT_SIZE=0x10000
+CONFIG_SYS_SPI_U_BOOT_OFFS=0x11400
+# CONFIG_GE_RTC is not set
+CONFIG_TARGET_GE_B1X5V2=y
+CONFIG_SPL_TEXT_BASE=0x00908000
+CONFIG_SPL_SERIAL_SUPPORT=y
+CONFIG_BOOTCOUNT_BOOTLIMIT=10
+CONFIG_SPL=y
+CONFIG_DEBUG_UART_BASE=0x21ec000
+CONFIG_DEBUG_UART_CLOCK=24000000
+CONFIG_SPL_LIBDISK_SUPPORT=y
+CONFIG_SPL_SPI_FLASH_SUPPORT=y
+CONFIG_SPL_SPI_SUPPORT=y
+CONFIG_SPL_PAYLOAD="u-boot.img"
+CONFIG_DEFAULT_DEVICE_TREE="imx6dl-b1x5v2"
+CONFIG_DEBUG_UART=y
+CONFIG_FIT=y
+CONFIG_OF_BOARD_SETUP=y
+CONFIG_SYS_EXTRA_OPTIONS="IMX_CONFIG=arch/arm/mach-imx/spl_sd.cfg"
+CONFIG_BOOTDELAY=1
+CONFIG_SYS_CONSOLE_OVERWRITE_ROUTINE=y
+CONFIG_LOG_MAX_LEVEL=8
+CONFIG_LOG_DEFAULT_LEVEL=4
+CONFIG_SUPPORT_RAW_INITRD=y
+CONFIG_DEFAULT_FDT_FILE="imx6dl-b1x5v2.dtb"
+CONFIG_MISC_INIT_R=y
+CONFIG_BOUNCE_BUFFER=y
+CONFIG_BOARD_EARLY_INIT_F=y
+CONFIG_SPL_SPI_LOAD=y
+CONFIG_SPL_USB_HOST_SUPPORT=y
+CONFIG_SPL_USB_GADGET=y
+CONFIG_SPL_USB_SDP_SUPPORT=y
+CONFIG_HUSH_PARSER=y
+CONFIG_CMD_BOOTZ=y
+CONFIG_CMD_GREPENV=y
+CONFIG_CMD_MEMINFO=y
+CONFIG_CMD_DM=y
+CONFIG_CMD_GPIO=y
+CONFIG_CMD_I2C=y
+CONFIG_CMD_MMC=y
+CONFIG_CMD_POWEROFF=y
+CONFIG_CMD_SPI=y
+CONFIG_CMD_USB=y
+CONFIG_CMD_USB_SDP=y
+CONFIG_CMD_DHCP=y
+CONFIG_CMD_MII=y
+CONFIG_CMD_PING=y
+CONFIG_CMD_SNTP=y
+CONFIG_CMD_DNS=y
+CONFIG_CMD_BMP=y
+CONFIG_CMD_BOOTCOUNT=y
+CONFIG_CMD_CACHE=y
+CONFIG_CMD_CLS=y
+CONFIG_CMD_TIME=y
+CONFIG_CMD_PMIC=y
+CONFIG_CMD_REGULATOR=y
+CONFIG_CMD_EXT2=y
+CONFIG_CMD_EXT4=y
+CONFIG_CMD_EXT4_WRITE=y
+CONFIG_CMD_FAT=y
+CONFIG_CMD_FS_GENERIC=y
+CONFIG_CMD_LOG=y
+# CONFIG_SPL_DOS_PARTITION is not set
+CONFIG_OF_CONTROL=y
+CONFIG_ENV_IS_IN_SPI_FLASH=y
+CONFIG_BOOTCOUNT_LIMIT=y
+CONFIG_DM_BOOTCOUNT=y
+CONFIG_DM_BOOTCOUNT_SPI_FLASH=y
+CONFIG_DM_PCA953X=y
+CONFIG_DM_I2C=y
+CONFIG_SYS_I2C_MXC=y
+CONFIG_I2C_MUX=y
+CONFIG_I2C_MUX_GPIO=y
+CONFIG_LED=y
+CONFIG_LED_GPIO=y
+CONFIG_DM_MMC=y
+CONFIG_FSL_USDHC=y
+CONFIG_DM_SPI_FLASH=y
+CONFIG_SF_DEFAULT_MODE=0
+CONFIG_SF_DEFAULT_SPEED=20000000
+CONFIG_SPI_FLASH_SST=y
+CONFIG_SPI_FLASH_WINBOND=y
+CONFIG_PHYLIB=y
+CONFIG_PHY_ATHEROS=y
+CONFIG_DM_ETH=y
+CONFIG_DM_MDIO=y
+CONFIG_DM_ETH_PHY=y
+CONFIG_FEC_MXC=y
+CONFIG_MII=y
+CONFIG_PINCTRL=y
+CONFIG_PINCTRL_IMX6=y
+CONFIG_DM_PMIC=y
+# CONFIG_SPL_PMIC_CHILDREN is not set
+CONFIG_DM_PMIC_PFUZE100=y
+CONFIG_DM_REGULATOR=y
+CONFIG_DM_REGULATOR_FIXED=y
+CONFIG_DM_REGULATOR_GPIO=y
+CONFIG_DM_PWM=y
+CONFIG_PWM_IMX=y
+CONFIG_DM_RTC=y
+CONFIG_RTC_M41T62=y
+CONFIG_DM_SERIAL=y
+CONFIG_MXC_UART=y
+CONFIG_SPI=y
+CONFIG_DM_SPI=y
+CONFIG_MXC_SPI=y
+CONFIG_SYSRESET=y
+CONFIG_SYSRESET_CMD_POWEROFF=y
+CONFIG_POWEROFF_GPIO=y
+CONFIG_SYSRESET_WATCHDOG=y
+CONFIG_IMX_THERMAL=y
+CONFIG_USB=y
+CONFIG_DM_USB=y
+CONFIG_USB_STORAGE=y
+CONFIG_USB_KEYBOARD=y
+CONFIG_USB_GADGET=y
+CONFIG_USB_GADGET_MANUFACTURER="Congatec"
+CONFIG_USB_GADGET_VENDOR_NUM=0x0525
+CONFIG_USB_GADGET_PRODUCT_NUM=0xa4a5
+CONFIG_CI_UDC=y
+CONFIG_USB_GADGET_DOWNLOAD=y
+CONFIG_DM_VIDEO=y
+CONFIG_VIDEO_IPUV3=y
+CONFIG_WATCHDOG_TIMEOUT_MSECS=30000
+CONFIG_IMX_WATCHDOG=y
+CONFIG_BCH=y
diff --git a/include/configs/ge_b1x5v2.h b/include/configs/ge_b1x5v2.h
new file mode 100644
index 000000000000..7db6afd88c23
--- /dev/null
+++ b/include/configs/ge_b1x5v2.h
@@ -0,0 +1,127 @@
+/*
+ * GE B1x5v2
+ *
+ * Copyright 2018-2020 GE Inc.
+ * Copyright 2018-2020 Collabora Ltd.
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+
+#ifndef __GE_B1X5V2_CONFIG_H
+#define __GE_B1X5V2_CONFIG_H
+
+#include "mx6_common.h"
+
+#include "imx6_spl.h"
+#define CONFIG_SPL_TARGET		"u-boot-with-spl.imx"
+
+/* Size of malloc() pool */
+#define CONFIG_SYS_MALLOC_LEN		(10 * SZ_1M)
+
+/* PWM */
+#define CONFIG_IMX6_PWM_PER_CLK		66000000
+
+/* UART */
+#define CONFIG_MXC_UART_BASE		UART3_BASE
+
+#if CONFIG_MXC_UART_BASE == UART2_BASE
+/* UART2 requires CONFIG_DEBUG_UART_BASE=0x21e8000 */
+#define CONSOLE_DEVICE "ttymxc1" /* System on Module debug connector */
+#else
+/* UART3 requires CONFIG_DEBUG_UART_BASE=0x21ec000 */
+#define CONSOLE_DEVICE "ttymxc2" /* Base board debug connector */
+#endif
+
+/* USB */
+#define CONFIG_EHCI_HCD_INIT_AFTER_RESET
+#define CONFIG_MXC_USB_PORTSC		(PORT_PTS_UTMI | PORT_PTS_PTW)
+#define CONFIG_MXC_USB_FLAGS		0
+#define CONFIG_USB_MAX_CONTROLLER_COUNT 2 /* Enabled USB controller number */
+#define CONFIG_USBD_HS
+
+/* Video */
+#define CONFIG_HIDE_LOGO_VERSION
+#define CONFIG_IMX_VIDEO_SKIP
+
+/* Memory */
+#define PHYS_SDRAM		       MMDC0_ARB_BASE_ADDR
+
+#define CONFIG_SYS_SDRAM_BASE	       PHYS_SDRAM
+#define CONFIG_SYS_INIT_RAM_ADDR       IRAM_BASE_ADDR
+#define CONFIG_SYS_INIT_RAM_SIZE       IRAM_SIZE
+
+#define CONFIG_SYS_INIT_SP_OFFSET \
+	(CONFIG_SYS_INIT_RAM_SIZE - GENERATED_GBL_DATA_SIZE)
+#define CONFIG_SYS_INIT_SP_ADDR \
+	(CONFIG_SYS_INIT_RAM_ADDR + CONFIG_SYS_INIT_SP_OFFSET)
+
+/* Command definition */
+#define CONFIG_EXTRA_ENV_SETTINGS \
+	"image=/boot/fitImage\0" \
+	"fdt_addr_r=0x18000000\0" \
+	"splash_addr_r=0x20000000\0" \
+	"mmcdev=2\0" \
+	"mmcpart=1\0" \
+	"console=console="CONSOLE_DEVICE",115200\0" \
+	"quiet=quiet loglevel=0\0" \
+	"rootdev=/dev/mmcblk1p\0" \
+	"setargs=setenv bootargs ${console} ${quiet} ${fsckforcerepair} " \
+		"bootcause=${bootcause} vt.global_cursor_default=0 vt.cur_default=1 " \
+		"root=${rootdev}${mmcpart} video=HDMI-A-1:${resolution} rootwait ro\0" \
+	"loadimage=load mmc ${mmcdev}:${mmcpart} ${loadaddr} ${image}\0" \
+	"showsplashscreen=load mmc ${mmcdev}:${mmcpart} ${splash_addr_r} /boot/splashscreen-${resolution}.bmp; " \
+		"bmp display ${splash_addr_r};\0" \
+	"setconfidx=" \
+		"if test \"${devicetype}\" = \"B105v2\"; then " \
+			"setenv confidx 1; " \
+		"elif test \"${devicetype}\" = \"B125v2\"; then " \
+			"setenv confidx 2; " \
+		"elif test \"${devicetype}\" = \"B155v2\"; then " \
+			"setenv confidx 3; " \
+		"elif test \"${devicetype}\" = \"B105Pv2\"; then " \
+			"setenv confidx 4; " \
+		"elif test \"${devicetype}\" = \"B125Pv2\"; then " \
+			"setenv confidx 5; " \
+		"fi;\0" \
+	"set_default_type=setenv devicetype B155v2; setenv resolution 1366x768;" \
+		"setenv fdtfile imx6dl-b155v2.dtb; run setconfidx;\0" \
+	"checkconfidx=env exists confidx || run set_default_type;\0" \
+	"checkfsckforcerepair=" \
+		"if test \"${bootcount}\" > \"3\" ; then " \
+			"setenv fsckforcerepair fsck.repair=1; " \
+		"fi;\0" \
+	"helix=run setconfidx; run checkconfidx; run checkfsckforcerepair; run setargs; " \
+		"regulator dev LED_VCC; regulator enable; " \
+		"regulator dev 5V0_AUDIO; regulator enable; " \
+		"bootm ${loadaddr}#conf@${confidx};\0" \
+	"failbootcmd=" \
+		"echo reached failbootcmd;" \
+		"cls; setcurs 5 4; " \
+		"lcdputs \"Monitor failed to start. Try again, or contact GE Service for support.\"; " \
+		"bootcount reset; \0" \
+	"hasfirstboot=" \
+		"load mmc ${mmcdev}:${mmcpart} ${loadaddr} " \
+		"/boot/bootcause/firstboot;\0" \
+	"swappartitions=" \
+		"setexpr mmcpart 3 - ${mmcpart};\0" \
+	"doboot=" \
+		"echo Booting from mmc:${mmcdev}:${mmcpart} ...; " \
+		"run helix;\0" \
+	"altbootcmd=" \
+		"setenv mmcpart 1; run hasfirstboot || setenv mmcpart 2; " \
+		"run hasfirstboot || setenv mmcpart 0; " \
+		"if test ${mmcpart} != 0; then " \
+			"setenv bootcause REVERT; " \
+			"run swappartitions loadimage doboot; " \
+		"fi; " \
+		"run failbootcmd\0" \
+	"tryboot=" \
+		"setenv mmcpart 1; run hasfirstboot || setenv mmcpart 2; " \
+		"run loadimage || run swappartitions && run loadimage || " \
+		"setenv mmcpart 0 && echo MISSING IMAGE;" \
+		"run showsplashscreen; sleep 1; " \
+		"run doboot; run failbootcmd;\0" \
+
+#define CONFIG_BOOTCOMMAND "run tryboot;"
+
+#endif /* __GE_B1X5V2_CONFIG_H */
-- 
2.28.0

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

* [PATCHv3 02/10] gpio: mxc_gpio: add support to read status of output gpios
  2020-08-21 16:16 ` [PATCHv3 02/10] gpio: mxc_gpio: add support to read status of output gpios Sebastian Reichel
@ 2020-08-23 14:44   ` Fabio Estevam
  0 siblings, 0 replies; 12+ messages in thread
From: Fabio Estevam @ 2020-08-23 14:44 UTC (permalink / raw)
  To: u-boot

Hi Sebastian,

On Fri, Aug 21, 2020 at 1:16 PM Sebastian Reichel
<sebastian.reichel@collabora.com> wrote:
>
> This is supported by the hardware when the pinmux is configured

I assume you are referring to the SION bit.

> correctly. Usually it is not, so this adds explicit code for this.
> This fixes all GPIO regulators being shown as disabled.

This has come up in the past and the consensus was to set the SION bit
when reading the output of a GPIO is needed.

Please see commit:

commit 5dafa4543c399d329c7b01df1afa98437861cac0
Author: Beno?t Th?baudeau <benoit.thebaudeau@advansee.com>
Date:   Mon Aug 20 10:55:41 2012 +0000

    mxc: Make gpio_get_value() use PSR

    gpio_get_value() should use PSR like Linux, not DR, because DR
does not always
    reflect the pin state, while PSR does. This is especially useful to detect a
    short circuit on a GPIO pin configured as output, or to read the
level of a pin
    controlled by a non-GPIO IOMUX function.

    Signed-off-by: Beno?t Th?baudeau <benoit.thebaudeau@advansee.com>
    Cc: Stefano Babic <sbabic@denx.de>
    Acked-by: Stefano Babic <sbabic@denx.de>

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

end of thread, other threads:[~2020-08-23 14:44 UTC | newest]

Thread overview: 12+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-08-21 16:16 [PATCHv3 00/10] Introduce B1x5v2 support Sebastian Reichel
2020-08-21 16:16 ` [PATCHv3 01/10] bootcount: add a DM SPI flash backing store for bootcount Sebastian Reichel
2020-08-21 16:16 ` [PATCHv3 02/10] gpio: mxc_gpio: add support to read status of output gpios Sebastian Reichel
2020-08-23 14:44   ` Fabio Estevam
2020-08-21 16:16 ` [PATCHv3 03/10] rtc: m41t62: reset SQW in m41t62_rtc_reset Sebastian Reichel
2020-08-21 16:16 ` [PATCHv3 04/10] rtc: m41t62: add oscillator fail bit reset support Sebastian Reichel
2020-08-21 16:16 ` [PATCHv3 05/10] imx6: allow usage of disable_ldb_di_clock_sources for CONFIG_MX6QDL Sebastian Reichel
2020-08-21 16:16 ` [PATCHv3 06/10] sysreset: Add poweroff-gpio driver Sebastian Reichel
2020-08-21 16:16 ` [PATCHv3 07/10] board: ge: common: rename ge_common.c to ge_rtc.c Sebastian Reichel
2020-08-21 16:16 ` [PATCHv3 08/10] board: ge: common: add config option for RTC and VPD feature Sebastian Reichel
2020-08-21 16:16 ` [PATCHv3 09/10] board: ge: common: vpd: separate I2C specific code Sebastian Reichel
2020-08-21 16:16 ` [PATCHv3 10/10] board: ge: b1x5v2: Add GE B1x5v2 and B1x5Pv2 Sebastian Reichel

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.