mail archive of the barebox mailing list
 help / color / mirror / Atom feed
* [PATCH v6 00/10] ARM: i.MX8MQ and EVK support
@ 2018-06-14  6:27 Andrey Smirnov
  2018-06-14  6:27 ` [PATCH v6 01/10] ARM: i.MX: ocotp: Provide missing .format_mac for i.MX8MQ Andrey Smirnov
                   ` (9 more replies)
  0 siblings, 10 replies; 13+ messages in thread
From: Andrey Smirnov @ 2018-06-14  6:27 UTC (permalink / raw)
  To: barebox; +Cc: Andrey Smirnov

Everyone:

Picking up where Sascha left off, this is the next version of the
patchset that adds support for i.MX8MQ EVK board.

This patchest is also availible at:

  https://github.com/ndreys/barebox/tree/imx8m-support-v6

Changes since [v6]:

  - Patchset rebased on latest master, so it is now down to 10 patches

  - <linux/iopoll.h> support in PBL is now done by stubbing out
    get_time_ns() and is_timeout() in clock.h

  - Additional speeling fixes

Changes since [v4]:

  - Fix a critical OCOTP bug (missing .format_mac in "ARM: i.MX:
    ocotp: Add i.MX8MQ support") introduced in v3 and was exposed by
    defconfig change in v4

  - Minor spelling/gramatical fixes in various commits and commit
    messages

Changes since [v3]:

  - Timeout/delay functions were moved into lib/ instead of being
    inline in order to avoid image size increase.

  - Imx-image chages were reworked to fix regression identified by
    Alexander Kurz in [regression1]

  - Minor fix to "clock: Use udelay() to implement mdelay()" (33/54)
    to prevent 32-bit ARM EABI toolchain from issuing a call to
    unsigned long division helper

  - Imx_v8_defconfig was modified to be as close to imx_v7_defconfig
    as possible.

        Removed options:
		CONFIG_PBL_CONSOLE=y
		CONFIG_CONSOLE_RATP=y

    	Added options:
		CONFIG_CONSOLE_ACTIVATE_NONE=y
		CONFIG_CMD_DHCP=y
		CONFIG_CMD_MIITOOL=y
		CONFIG_CMD_PING=y
		CONFIG_CMD_I2C=y
		CONFIG_NET=y
		CONFIG_NET_NETCONSOLE=y
		CONFIG_NET_RESOLV=y
		CONFIG_DRIVER_NET_FEC_IMX=y
		CONFIG_I2C=y
		CONFIG_I2C_IMX=y
		CONFIG_FS_TFTP=y
		CONFIG_FS_NFS=y

Changes since [v2]:

  - i.MX8 specific eSDHC bootstrap code code fixed to function
    correctly with high capacity SD cards

  - DDR PHY firmware converted to use Sascha's firmware framework and
    be SoC specific (can be shared among different boards)

  - DDR register definitions moved to imx8-ddrc.h as well as cleaned
    up to contain only constants that are being used

  - Incorporated imx-image i.MX8 work done by Sascha as well as extend
    it to create valid AArch64 header

  - Patchset is rebase on latest 'next' branch to accomodate recent
    OCOTP changes

Changes since [v1]:

  - The patchset now allows building 1st stage bootloader that can be
    progammed on SD card and booted standalone

Currently out of scope of this patch (not tested or documented, will
be coming in a follow up series):

  - Integration of ARM Trusted Firmware

  - Booting Linux kernel

Current assumptions (all subject to change, but listed below to be
explicit):

  - DDR initialization code is auto-generated by i.MX8M DDR Tool and
    used as close to as-is as possible.

Feedback is wellcome!

Thanks,
Andrey Smirnov

[v1] http://lists.infradead.org/pipermail/barebox/2018-March/032386.html
[v2] http://lists.infradead.org/pipermail/barebox/2018-May/033149.html
[v3] http://lists.infradead.org/pipermail/barebox/2018-June/033390.html
[regression1] http://lists.infradead.org/pipermail/barebox/2018-June/033475.html
[v4] http://lists.infradead.org/pipermail/barebox/2018-June/033504.html
[v5] http://lists.infradead.org/pipermail/barebox/2018-June/033592.html

Andrey Smirnov (7):
  Port <linux/iopoll.h> from U-Boot
  clock: Use udelay() to implement mdelay()
  ARM: i.MX8: Add DDRC PHY support code
  ARM: Specify HAVE_PBL_IMAGE for CPU_64
  scripts: imx-image: Use a loop to create multiple header copies
  scripts: imx-image: Share the code to write barebox header
  ARM: Introduce imx_v8_defconfig

Sascha Hauer (3):
  ARM: i.MX: ocotp: Provide missing .format_mac for i.MX8MQ
  scripts: imx-image: Add i.MX8MQ support
  ARM: i.MX8: Add i.MX8mq EVK support

 Documentation/boards/imx.rst                  |   13 +-
 Documentation/boards/imx/nxp-imx8mq-evk.rst   |  116 ++
 arch/arm/boards/Makefile                      |    1 +
 arch/arm/boards/nxp-imx8mq-evk/.gitignore     |    1 +
 arch/arm/boards/nxp-imx8mq-evk/Makefile       |    4 +
 arch/arm/boards/nxp-imx8mq-evk/board.c        |   44 +
 arch/arm/boards/nxp-imx8mq-evk/ddr.h          |   28 +
 arch/arm/boards/nxp-imx8mq-evk/ddr_init.c     |  223 ++++
 arch/arm/boards/nxp-imx8mq-evk/ddrphy_train.c | 1026 +++++++++++++++++
 .../flash-header-imx8mq-evk.imxcfg            |    4 +
 arch/arm/boards/nxp-imx8mq-evk/lowlevel.c     |   81 ++
 arch/arm/configs/imx_v8_defconfig             |  107 ++
 arch/arm/cpu/Kconfig                          |    1 +
 arch/arm/dts/Makefile                         |    1 +
 arch/arm/dts/imx8mq-evk.dts                   |  444 +++++++
 arch/arm/mach-imx/Kconfig                     |    5 +
 arch/arm/mach-imx/Makefile                    |    1 +
 arch/arm/mach-imx/imx8-ddrc.c                 |  107 ++
 arch/arm/mach-imx/include/mach/imx8-ddrc.h    |   66 ++
 common/clock.c                                |    8 +-
 drivers/nvmem/ocotp.c                         |    1 +
 firmware/Kconfig                              |    3 +
 firmware/Makefile                             |    6 +
 images/Makefile.imx                           |    7 +
 include/clock.h                               |   14 +
 include/linux/iopoll.h                        |   69 ++
 scripts/imx/imx-image.c                       |   99 +-
 scripts/imx/imx.c                             |   23 +-
 scripts/imx/imx.h                             |    2 +
 29 files changed, 2463 insertions(+), 42 deletions(-)
 create mode 100644 Documentation/boards/imx/nxp-imx8mq-evk.rst
 create mode 100644 arch/arm/boards/nxp-imx8mq-evk/.gitignore
 create mode 100644 arch/arm/boards/nxp-imx8mq-evk/Makefile
 create mode 100644 arch/arm/boards/nxp-imx8mq-evk/board.c
 create mode 100644 arch/arm/boards/nxp-imx8mq-evk/ddr.h
 create mode 100644 arch/arm/boards/nxp-imx8mq-evk/ddr_init.c
 create mode 100644 arch/arm/boards/nxp-imx8mq-evk/ddrphy_train.c
 create mode 100644 arch/arm/boards/nxp-imx8mq-evk/flash-header-imx8mq-evk.imxcfg
 create mode 100644 arch/arm/boards/nxp-imx8mq-evk/lowlevel.c
 create mode 100644 arch/arm/configs/imx_v8_defconfig
 create mode 100644 arch/arm/dts/imx8mq-evk.dts
 create mode 100644 arch/arm/mach-imx/imx8-ddrc.c
 create mode 100644 arch/arm/mach-imx/include/mach/imx8-ddrc.h
 create mode 100644 include/linux/iopoll.h

-- 
2.17.0


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

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

* [PATCH v6 01/10] ARM: i.MX: ocotp: Provide missing .format_mac for i.MX8MQ
  2018-06-14  6:27 [PATCH v6 00/10] ARM: i.MX8MQ and EVK support Andrey Smirnov
@ 2018-06-14  6:27 ` Andrey Smirnov
  2018-06-14  6:27 ` [PATCH v6 02/10] Port <linux/iopoll.h> from U-Boot Andrey Smirnov
                   ` (8 subsequent siblings)
  9 siblings, 0 replies; 13+ messages in thread
From: Andrey Smirnov @ 2018-06-14  6:27 UTC (permalink / raw)
  To: barebox; +Cc: Andrey Smirnov

From: Sascha Hauer <s.hauer@pengutronix.de>

Provide missing .format_mac for i.MX8MQ to prevent driver from
crashing on start.

Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com>
---
 drivers/nvmem/ocotp.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/nvmem/ocotp.c b/drivers/nvmem/ocotp.c
index f3af8620e..c2d2982ee 100644
--- a/drivers/nvmem/ocotp.c
+++ b/drivers/nvmem/ocotp.c
@@ -652,6 +652,7 @@ static struct imx_ocotp_data imx8mq_ocotp_data = {
 	.addr_to_offset = imx6sl_addr_to_offset,
 	.mac_offsets_num = 1,
 	.mac_offsets = { 0x90 },
+	.format_mac = imx_ocotp_format_mac,
 };
 
 static __maybe_unused struct of_device_id imx_ocotp_dt_ids[] = {
-- 
2.17.0


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

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

* [PATCH v6 02/10] Port <linux/iopoll.h> from U-Boot
  2018-06-14  6:27 [PATCH v6 00/10] ARM: i.MX8MQ and EVK support Andrey Smirnov
  2018-06-14  6:27 ` [PATCH v6 01/10] ARM: i.MX: ocotp: Provide missing .format_mac for i.MX8MQ Andrey Smirnov
@ 2018-06-14  6:27 ` Andrey Smirnov
  2018-06-14  6:27 ` [PATCH v6 03/10] clock: Use udelay() to implement mdelay() Andrey Smirnov
                   ` (7 subsequent siblings)
  9 siblings, 0 replies; 13+ messages in thread
From: Andrey Smirnov @ 2018-06-14  6:27 UTC (permalink / raw)
  To: barebox; +Cc: Andrey Smirnov

Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com>
---
 include/clock.h        | 14 +++++++++
 include/linux/iopoll.h | 69 ++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 83 insertions(+)
 create mode 100644 include/linux/iopoll.h

diff --git a/include/clock.h b/include/clock.h
index 5f2f53ab6..58d84b912 100644
--- a/include/clock.h
+++ b/include/clock.h
@@ -25,13 +25,27 @@ static inline uint32_t cyc2ns(struct clocksource *cs, uint64_t cycles)
 
 int init_clock(struct clocksource *);
 
+#ifndef __PBL__
 uint64_t get_time_ns(void);
+#else
+static inline uint64_t get_time_ns(void)
+{
+	return 0;
+}
+#endif
 
 void clocks_calc_mult_shift(uint32_t *mult, uint32_t *shift, uint32_t from, uint32_t to, uint32_t maxsec);
 
 uint32_t clocksource_hz2mult(uint32_t hz, uint32_t shift_constant);
 
+#ifndef __PBL__
 int is_timeout(uint64_t start_ns, uint64_t time_offset_ns);
+#else
+static inline int is_timeout(uint64_t start_ns, uint64_t time_offset_ns)
+{
+	return 0;
+}
+#endif
 int is_timeout_non_interruptible(uint64_t start_ns, uint64_t time_offset_ns);
 
 void ndelay(unsigned long nsecs);
diff --git a/include/linux/iopoll.h b/include/linux/iopoll.h
new file mode 100644
index 000000000..0213e5c8d
--- /dev/null
+++ b/include/linux/iopoll.h
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2012-2014 The Linux Foundation. All rights reserved.
+ *
+ * SPDX-License-Identifier:	GPL-2.0
+ */
+
+#ifndef _LINUX_IOPOLL_H
+#define _LINUX_IOPOLL_H
+
+#include <errno.h>
+#include <io.h>
+#include <clock.h>
+
+/**
+ * readx_poll_timeout - Periodically poll an address until a condition is met or a timeout occurs
+ * @op: accessor function (takes @addr as its only argument)
+ * @addr: Address to poll
+ * @val: Variable to read the value into
+ * @cond: Break condition (usually involving @val)
+ * @timeout_us: Timeout in us, 0 means never timeout
+ *
+ * Returns 0 on success and -ETIMEDOUT upon a timeout. In either
+ * case, the last read value at @addr is stored in @val.
+ *
+ * When available, you'll probably want to use one of the specialized
+ * macros defined below rather than this macro directly.
+ */
+#define readx_poll_timeout(op, addr, val, cond, timeout_us)	\
+({ \
+	uint64_t start = get_time_ns(); \
+	for (;;) { \
+		(val) = op(addr); \
+		if (cond) \
+			break; \
+		if (timeout_us && \
+		    is_timeout(start, ((timeout_us) * USECOND))) { \
+			(val) = op(addr); \
+			break; \
+		} \
+	} \
+	(cond) ? 0 : -ETIMEDOUT; \
+})
+
+
+#define readb_poll_timeout(addr, val, cond, timeout_us) \
+	readx_poll_timeout(readb, addr, val, cond, timeout_us)
+
+#define readw_poll_timeout(addr, val, cond, timeout_us) \
+	readx_poll_timeout(readw, addr, val, cond, timeout_us)
+
+#define readl_poll_timeout(addr, val, cond, timeout_us) \
+	readx_poll_timeout(readl, addr, val, cond, timeout_us)
+
+#define readq_poll_timeout(addr, val, cond, timeout_us) \
+	readx_poll_timeout(readq, addr, val, cond, timeout_us)
+
+#define readb_relaxed_poll_timeout(addr, val, cond, timeout_us) \
+	readx_poll_timeout(readb_relaxed, addr, val, cond, timeout_us)
+
+#define readw_relaxed_poll_timeout(addr, val, cond, timeout_us) \
+	readx_poll_timeout(readw_relaxed, addr, val, cond, timeout_us)
+
+#define readl_relaxed_poll_timeout(addr, val, cond, timeout_us) \
+	readx_poll_timeout(readl_relaxed, addr, val, cond, timeout_us)
+
+#define readq_relaxed_poll_timeout(addr, val, cond, timeout_us) \
+	readx_poll_timeout(readq_relaxed, addr, val, cond, timeout_us)
+
+#endif /* _LINUX_IOPOLL_H */
-- 
2.17.0


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

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

* [PATCH v6 03/10] clock: Use udelay() to implement mdelay()
  2018-06-14  6:27 [PATCH v6 00/10] ARM: i.MX8MQ and EVK support Andrey Smirnov
  2018-06-14  6:27 ` [PATCH v6 01/10] ARM: i.MX: ocotp: Provide missing .format_mac for i.MX8MQ Andrey Smirnov
  2018-06-14  6:27 ` [PATCH v6 02/10] Port <linux/iopoll.h> from U-Boot Andrey Smirnov
@ 2018-06-14  6:27 ` Andrey Smirnov
  2018-06-14 10:04   ` Antony Pavlov
  2018-06-14  6:27 ` [PATCH v6 04/10] ARM: i.MX8: Add DDRC PHY support code Andrey Smirnov
                   ` (6 subsequent siblings)
  9 siblings, 1 reply; 13+ messages in thread
From: Andrey Smirnov @ 2018-06-14  6:27 UTC (permalink / raw)
  To: barebox; +Cc: Andrey Smirnov

Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com>
---
 common/clock.c | 8 +++++---
 1 file changed, 5 insertions(+), 3 deletions(-)

diff --git a/common/clock.c b/common/clock.c
index f98176dd5..dab6e979f 100644
--- a/common/clock.c
+++ b/common/clock.c
@@ -206,9 +206,11 @@ EXPORT_SYMBOL(udelay);
 
 void mdelay(unsigned long msecs)
 {
-	uint64_t start = get_time_ns();
-
-	while(!is_timeout(start, msecs * MSECOND));
+	/*
+	 * Parens around division below are needed to pervent ARM/EABI
+	 * toolchain from emitting a call to __aeabi_uldivmod.
+	 */
+	udelay(msecs * (MSECOND / USECOND));
 }
 EXPORT_SYMBOL(mdelay);
 
-- 
2.17.0


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

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

* [PATCH v6 04/10] ARM: i.MX8: Add DDRC PHY support code
  2018-06-14  6:27 [PATCH v6 00/10] ARM: i.MX8MQ and EVK support Andrey Smirnov
                   ` (2 preceding siblings ...)
  2018-06-14  6:27 ` [PATCH v6 03/10] clock: Use udelay() to implement mdelay() Andrey Smirnov
@ 2018-06-14  6:27 ` Andrey Smirnov
  2018-06-14  6:27 ` [PATCH v6 05/10] ARM: Specify HAVE_PBL_IMAGE for CPU_64 Andrey Smirnov
                   ` (5 subsequent siblings)
  9 siblings, 0 replies; 13+ messages in thread
From: Andrey Smirnov @ 2018-06-14  6:27 UTC (permalink / raw)
  To: barebox; +Cc: Andrey Smirnov

Add DDRC PHY support code needed to upload DDR training firwmare as
well as to wait for the training process to complete.

Those are needed to support board specific DDR initialization code.

Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com>
---
 arch/arm/mach-imx/Makefile                 |   1 +
 arch/arm/mach-imx/imx8-ddrc.c              | 107 +++++++++++++++++++++
 arch/arm/mach-imx/include/mach/imx8-ddrc.h |  66 +++++++++++++
 3 files changed, 174 insertions(+)
 create mode 100644 arch/arm/mach-imx/imx8-ddrc.c
 create mode 100644 arch/arm/mach-imx/include/mach/imx8-ddrc.h

diff --git a/arch/arm/mach-imx/Makefile b/arch/arm/mach-imx/Makefile
index 442039a27..28fe60dba 100644
--- a/arch/arm/mach-imx/Makefile
+++ b/arch/arm/mach-imx/Makefile
@@ -17,6 +17,7 @@ lwl-$(CONFIG_ARCH_IMX6) += imx6-mmdc.o
 obj-$(CONFIG_ARCH_IMX7) += imx7.o
 obj-$(CONFIG_ARCH_VF610) += vf610.o
 obj-$(CONFIG_ARCH_IMX8MQ) += imx8mq.o
+lwl-$(CONFIG_ARCH_IMX8MQ) += imx8-ddrc.o
 obj-$(CONFIG_ARCH_IMX_XLOAD) += xload.o
 obj-$(CONFIG_IMX_IIM)	+= iim.o
 obj-$(CONFIG_NAND_IMX) += nand.o
diff --git a/arch/arm/mach-imx/imx8-ddrc.c b/arch/arm/mach-imx/imx8-ddrc.c
new file mode 100644
index 000000000..18454a915
--- /dev/null
+++ b/arch/arm/mach-imx/imx8-ddrc.c
@@ -0,0 +1,107 @@
+#include <common.h>
+#include <linux/iopoll.h>
+#include <mach/imx8-ddrc.h>
+#include <debug_ll.h>
+
+void ddrc_phy_load_firmware(void __iomem *phy,
+			    enum ddrc_phy_firmware_offset offset,
+			    const u16 *blob, size_t size)
+{
+	while (size) {
+		writew(*blob++, phy + DDRC_PHY_REG(offset));
+		offset++;
+		size -= sizeof(*blob);
+	}
+}
+
+enum pmc_constants {
+	PMC_MESSAGE_ID,
+	PMC_MESSAGE_STREAM,
+
+	PMC_TRAIN_SUCCESS	= 0x07,
+	PMC_TRAIN_STREAM_START	= 0x08,
+	PMC_TRAIN_FAIL		= 0xff,
+};
+
+static u32 ddrc_phy_get_message(void __iomem *phy, int type)
+{
+	u32 r, message;
+
+	/*
+	 * When BIT0 set to 0, the PMU has a message for the user
+	 * 10ms seems not enough for poll message, so use 1s here.
+	 */
+	readl_poll_timeout(phy + DDRC_PHY_REG(0xd0004),
+			   r, !(r & BIT(0)), 0);
+
+	switch (type) {
+	case PMC_MESSAGE_ID:
+		/*
+		 * Get the major message ID
+		 */
+		message = readl(phy + DDRC_PHY_REG(0xd0032));
+		break;
+	case PMC_MESSAGE_STREAM:
+		message = readl(phy + DDRC_PHY_REG(0xd0034));
+		message <<= 16;
+		message |= readl(phy + DDRC_PHY_REG(0xd0032));
+		break;
+	}
+
+	/*
+	 * By setting this register to 0, the user acknowledges the
+	 * receipt of the message.
+	 */
+	writel(0x00000000, phy + DDRC_PHY_REG(0xd0031));
+	/*
+	 * When BIT0 set to 0, the PMU has a message for the user
+	 */
+	readl_poll_timeout(phy + DDRC_PHY_REG(0xd0004),
+			   r, r & BIT(0), 0);
+
+	writel(0x00000001, phy + DDRC_PHY_REG(0xd0031));
+
+	return message;
+}
+
+static void ddrc_phy_fetch_streaming_message(void __iomem *phy)
+{
+	const u16 index = ddrc_phy_get_message(phy, PMC_MESSAGE_STREAM);
+	u16 i;
+
+	putc_ll('|');
+	puthex_ll(index);
+
+	for (i = 0; i < index; i++) {
+		const u32 arg = ddrc_phy_get_message(phy, PMC_MESSAGE_STREAM);
+
+		putc_ll('|');
+		puthex_ll(arg);
+	}
+}
+
+void ddrc_phy_wait_training_complete(void __iomem *phy)
+{
+	for (;;) {
+		const u32 m = ddrc_phy_get_message(phy, PMC_MESSAGE_ID);
+
+		puthex_ll(m);
+
+		switch (m) {
+		case PMC_TRAIN_STREAM_START:
+			ddrc_phy_fetch_streaming_message(phy);
+			break;
+		case PMC_TRAIN_SUCCESS:
+			putc_ll('P');
+			putc_ll('\r');
+			putc_ll('\n');
+			return;
+		case PMC_TRAIN_FAIL:
+			putc_ll('F');
+			hang();
+		}
+
+		putc_ll('\r');
+		putc_ll('\n');
+	}
+}
\ No newline at end of file
diff --git a/arch/arm/mach-imx/include/mach/imx8-ddrc.h b/arch/arm/mach-imx/include/mach/imx8-ddrc.h
new file mode 100644
index 000000000..d49e29f26
--- /dev/null
+++ b/arch/arm/mach-imx/include/mach/imx8-ddrc.h
@@ -0,0 +1,66 @@
+#ifndef __IMX8_DDRC_H__
+#define __IMX8_DDRC_H__
+
+#include <mach/imx8mq-regs.h>
+#include <io.h>
+#include <firmware.h>
+#include <linux/compiler.h>
+
+enum ddrc_phy_firmware_offset {
+	DDRC_PHY_IMEM = 0x00050000U,
+	DDRC_PHY_DMEM = 0x00054000U,
+};
+
+void ddrc_phy_load_firmware(void __iomem *,
+			    enum ddrc_phy_firmware_offset,
+			    const u16 *, size_t);
+
+#define DDRC_PHY_REG(x)	((x) * 4)
+
+void ddrc_phy_wait_training_complete(void __iomem *phy);
+
+
+/*
+ * i.MX8M DDR Tool compatibility layer
+ */
+
+#define reg32_write(a, v)	writel(v, a)
+#define reg32_read(a)		readl(a)
+
+static inline void wait_ddrphy_training_complete(void)
+{
+	ddrc_phy_wait_training_complete(IOMEM(MX8MQ_DDRC_PHY_BASE_ADDR));
+}
+
+#define __ddr_load_train_code(imem, dmem)				\
+	do {								\
+		const u16 *__mem;					\
+		size_t __size;						\
+									\
+		get_builtin_firmware(imem, &__mem, &__size);		\
+		ddrc_phy_load_firmware(IOMEM(MX8MQ_DDRC_PHY_BASE_ADDR),	\
+				       DDRC_PHY_IMEM, __mem, __size);	\
+									\
+		get_builtin_firmware(dmem, &__mem, &__size);		\
+		ddrc_phy_load_firmware(IOMEM(MX8MQ_DDRC_PHY_BASE_ADDR),	\
+				       DDRC_PHY_DMEM, __mem, __size);	\
+	} while (0)
+
+#define ddr_load_train_code(imem_dmem) __ddr_load_train_code(imem_dmem)
+
+#define DDRC_IPS_BASE_ADDR(X) (0x3d400000 + (X * 0x2000000))
+
+#define DDRC_STAT(X)             (DDRC_IPS_BASE_ADDR(X) + 0x04)
+#define DDRC_MRSTAT(X)           (DDRC_IPS_BASE_ADDR(X) + 0x18)
+#define DDRC_PWRCTL(X)           (DDRC_IPS_BASE_ADDR(X) + 0x30)
+#define DDRC_RFSHCTL3(X)         (DDRC_IPS_BASE_ADDR(X) + 0x60)
+#define DDRC_CRCPARSTAT(X)       (DDRC_IPS_BASE_ADDR(X) + 0xcc)
+#define DDRC_DFIMISC(X)          (DDRC_IPS_BASE_ADDR(X) + 0x1b0)
+#define DDRC_DFISTAT(X)          (DDRC_IPS_BASE_ADDR(X) + 0x1bc)
+#define DDRC_SWCTL(X)            (DDRC_IPS_BASE_ADDR(X) + 0x320)
+#define DDRC_SWSTAT(X)           (DDRC_IPS_BASE_ADDR(X) + 0x324)
+#define DDRC_PCTRL_0(X)          (DDRC_IPS_BASE_ADDR(X) + 0x490)
+
+#define IP2APB_DDRPHY_IPS_BASE_ADDR(X) (0x3c000000 + (X * 0x2000000))
+
+#endif
\ No newline at end of file
-- 
2.17.0


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

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

* [PATCH v6 05/10] ARM: Specify HAVE_PBL_IMAGE for CPU_64
  2018-06-14  6:27 [PATCH v6 00/10] ARM: i.MX8MQ and EVK support Andrey Smirnov
                   ` (3 preceding siblings ...)
  2018-06-14  6:27 ` [PATCH v6 04/10] ARM: i.MX8: Add DDRC PHY support code Andrey Smirnov
@ 2018-06-14  6:27 ` Andrey Smirnov
  2018-06-14  6:27 ` [PATCH v6 06/10] scripts: imx-image: Use a loop to create multiple header copies Andrey Smirnov
                   ` (4 subsequent siblings)
  9 siblings, 0 replies; 13+ messages in thread
From: Andrey Smirnov @ 2018-06-14  6:27 UTC (permalink / raw)
  To: barebox; +Cc: Andrey Smirnov

Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com>
---
 arch/arm/cpu/Kconfig | 1 +
 1 file changed, 1 insertion(+)

diff --git a/arch/arm/cpu/Kconfig b/arch/arm/cpu/Kconfig
index d889e9afb..2359c56b3 100644
--- a/arch/arm/cpu/Kconfig
+++ b/arch/arm/cpu/Kconfig
@@ -12,6 +12,7 @@ config CPU_32
 config CPU_64
 	bool
 	select PHYS_ADDR_T_64BIT
+	select HAVE_PBL_IMAGE
 
 # Select CPU types depending on the architecture selected. This selects
 # which CPUs we support in the kernel image, and the compiler instruction
-- 
2.17.0


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

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

* [PATCH v6 06/10] scripts: imx-image: Use a loop to create multiple header copies
  2018-06-14  6:27 [PATCH v6 00/10] ARM: i.MX8MQ and EVK support Andrey Smirnov
                   ` (4 preceding siblings ...)
  2018-06-14  6:27 ` [PATCH v6 05/10] ARM: Specify HAVE_PBL_IMAGE for CPU_64 Andrey Smirnov
@ 2018-06-14  6:27 ` Andrey Smirnov
  2018-06-14  6:27 ` [PATCH v6 07/10] scripts: imx-image: Share the code to write barebox header Andrey Smirnov
                   ` (3 subsequent siblings)
  9 siblings, 0 replies; 13+ messages in thread
From: Andrey Smirnov @ 2018-06-14  6:27 UTC (permalink / raw)
  To: barebox; +Cc: Andrey Smirnov

Use a loop to create multiple header copies on i.MX35 to avoid code
duplication.

Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com>
---
 scripts/imx/imx-image.c | 9 +++------
 1 file changed, 3 insertions(+), 6 deletions(-)

diff --git a/scripts/imx/imx-image.c b/scripts/imx/imx-image.c
index 294f51a90..bc1f821bd 100644
--- a/scripts/imx/imx-image.c
+++ b/scripts/imx/imx-image.c
@@ -679,6 +679,7 @@ int main(int argc, char *argv[])
 	int dcd_only = 0;
 	int now = 0;
 	int sign_image = 0;
+	int i, header_copies;
 	struct config_data data = {
 		.image_dcd_offset = 0xffffffff,
 		.write_mem = write_mem,
@@ -824,13 +825,9 @@ int main(int argc, char *argv[])
 		exit(1);
 	}
 
-	ret = xwrite(outfd, buf, HEADER_LEN);
-	if (ret < 0) {
-		perror("write");
-		exit(1);
-	}
+	header_copies = (data.cpu_type == IMX_CPU_IMX35) ? 2 : 1;
 
-	if (data.cpu_type == IMX_CPU_IMX35) {
+	for (i = 0; i < header_copies; i++) {
 		ret = xwrite(outfd, buf, HEADER_LEN);
 		if (ret < 0) {
 			perror("write");
-- 
2.17.0


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

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

* [PATCH v6 07/10] scripts: imx-image: Share the code to write barebox header
  2018-06-14  6:27 [PATCH v6 00/10] ARM: i.MX8MQ and EVK support Andrey Smirnov
                   ` (5 preceding siblings ...)
  2018-06-14  6:27 ` [PATCH v6 06/10] scripts: imx-image: Use a loop to create multiple header copies Andrey Smirnov
@ 2018-06-14  6:27 ` Andrey Smirnov
  2018-06-14  6:27 ` [PATCH v6 08/10] scripts: imx-image: Add i.MX8MQ support Andrey Smirnov
                   ` (2 subsequent siblings)
  9 siblings, 0 replies; 13+ messages in thread
From: Andrey Smirnov @ 2018-06-14  6:27 UTC (permalink / raw)
  To: barebox; +Cc: Andrey Smirnov

Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com>
---
 scripts/imx/imx-image.c | 42 ++++++++++++++++++++---------------------
 1 file changed, 20 insertions(+), 22 deletions(-)

diff --git a/scripts/imx/imx-image.c b/scripts/imx/imx-image.c
index bc1f821bd..4a08581fb 100644
--- a/scripts/imx/imx-image.c
+++ b/scripts/imx/imx-image.c
@@ -36,6 +36,7 @@
 #include <include/filetype.h>
 
 #define FLASH_HEADER_OFFSET 0x400
+#define ARM_HEAD_SIZE_INDEX	(ARM_HEAD_SIZE_OFFSET / sizeof(uint32_t))
 
 /*
  * Conservative DCD element limit set to restriction v2 header size to
@@ -46,7 +47,6 @@
 
 static uint32_t dcdtable[MAX_DCD];
 static int curdcd;
-static int add_barebox_header;
 static int create_usb_image;
 static char *prgname;
 
@@ -207,18 +207,14 @@ static int add_srk(void *buf, int offset, uint32_t loadaddr, const char *srkfile
 static int dcd_ptr_offset;
 static uint32_t dcd_ptr_content;
 
-static int add_header_v1(struct config_data *data, void *buf)
+static size_t add_header_v1(struct config_data *data, void *buf)
 {
 	struct imx_flash_header *hdr;
 	int dcdsize = curdcd * sizeof(uint32_t);
-	uint32_t *psize = buf + ARM_HEAD_SIZE_OFFSET;
 	int offset = data->image_dcd_offset;
 	uint32_t loadaddr = data->image_load_addr;
 	uint32_t imagesize = data->load_size;
 
-	if (add_barebox_header)
-		memcpy(buf, bb_header, sizeof(bb_header));
-
 	buf += offset;
 	hdr = buf;
 
@@ -250,12 +246,9 @@ static int add_header_v1(struct config_data *data, void *buf)
 		imagesize += CSF_LEN;
 	}
 
-	if (add_barebox_header)
-		*psize = imagesize;
-
 	*(uint32_t *)buf = imagesize;
 
-	return 0;
+	return imagesize;
 }
 
 static int write_mem_v1(uint32_t addr, uint32_t val, int width, int set_bits, int clear_bits)
@@ -283,18 +276,14 @@ static int write_mem_v1(uint32_t addr, uint32_t val, int width, int set_bits, in
  * ============================================================================
  */
 
-static int add_header_v2(const struct config_data *data, void *buf)
+static size_t add_header_v2(const struct config_data *data, void *buf)
 {
 	struct imx_flash_header_v2 *hdr;
 	int dcdsize = curdcd * sizeof(uint32_t);
-	uint32_t *psize = buf + ARM_HEAD_SIZE_OFFSET;
 	int offset = data->image_dcd_offset;
 	uint32_t loadaddr = data->image_load_addr;
 	uint32_t imagesize = data->load_size;
 
-	if (add_barebox_header)
-		memcpy(buf, bb_header, sizeof(bb_header));
-
 	buf += offset;
 	hdr = buf;
 
@@ -320,9 +309,6 @@ static int add_header_v2(const struct config_data *data, void *buf)
 		hdr->boot_data.size += CSF_LEN;
 	}
 
-	if (add_barebox_header)
-		*psize = hdr->boot_data.size;
-
 	hdr->dcd_header.tag	= TAG_DCD_HEADER;
 	hdr->dcd_header.length	= htobe16(sizeof(uint32_t) + dcdsize);
 	hdr->dcd_header.version	= DCD_VERSION;
@@ -331,7 +317,7 @@ static int add_header_v2(const struct config_data *data, void *buf)
 
 	memcpy(buf, dcdtable, dcdsize);
 
-	return 0;
+	return imagesize;
 }
 
 static void usage(const char *prgname)
@@ -680,6 +666,8 @@ int main(int argc, char *argv[])
 	int now = 0;
 	int sign_image = 0;
 	int i, header_copies;
+	int add_barebox_header;
+	uint32_t barebox_image_size;
 	struct config_data data = {
 		.image_dcd_offset = 0xffffffff,
 		.write_mem = write_mem,
@@ -792,7 +780,7 @@ int main(int argc, char *argv[])
 
 	switch (data.header_version) {
 	case 1:
-		add_header_v1(&data, buf);
+		barebox_image_size = add_header_v1(&data, buf);
 		if (data.srkfile) {
 			ret = add_srk(buf, data.image_dcd_offset, data.image_load_addr,
 				      data.srkfile);
@@ -807,7 +795,7 @@ int main(int argc, char *argv[])
 			exit(1);
 		}
 
-		add_header_v2(&data, buf);
+		barebox_image_size = add_header_v2(&data, buf);
 		break;
 	default:
 		fprintf(stderr, "Congratulations! You're welcome to implement header version %d\n",
@@ -815,6 +803,8 @@ int main(int argc, char *argv[])
 		exit(1);
 	}
 
+	bb_header[ARM_HEAD_SIZE_INDEX] = barebox_image_size;
+
 	infile = read_file(imagename, &insize);
 	if (!infile)
 		exit(1);
@@ -828,7 +818,15 @@ int main(int argc, char *argv[])
 	header_copies = (data.cpu_type == IMX_CPU_IMX35) ? 2 : 1;
 
 	for (i = 0; i < header_copies; i++) {
-		ret = xwrite(outfd, buf, HEADER_LEN);
+		ret = xwrite(outfd, add_barebox_header ? bb_header : buf,
+			     sizeof(bb_header));
+		if (ret < 0) {
+			perror("write");
+			exit(1);
+		}
+
+		ret = xwrite(outfd, buf + sizeof(bb_header),
+			     HEADER_LEN - sizeof(bb_header));
 		if (ret < 0) {
 			perror("write");
 			exit(1);
-- 
2.17.0


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

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

* [PATCH v6 08/10] scripts: imx-image: Add i.MX8MQ support
  2018-06-14  6:27 [PATCH v6 00/10] ARM: i.MX8MQ and EVK support Andrey Smirnov
                   ` (6 preceding siblings ...)
  2018-06-14  6:27 ` [PATCH v6 07/10] scripts: imx-image: Share the code to write barebox header Andrey Smirnov
@ 2018-06-14  6:27 ` Andrey Smirnov
  2018-06-14  6:27 ` [PATCH v6 09/10] ARM: i.MX8: Add i.MX8mq EVK support Andrey Smirnov
  2018-06-14  6:27 ` [PATCH v6 10/10] ARM: Introduce imx_v8_defconfig Andrey Smirnov
  9 siblings, 0 replies; 13+ messages in thread
From: Andrey Smirnov @ 2018-06-14  6:27 UTC (permalink / raw)
  To: barebox; +Cc: Andrey Smirnov

From: Sascha Hauer <s.hauer@pengutronix.de>

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com>
---
 scripts/imx/imx-image.c | 54 +++++++++++++++++++++++++++++++++++++----
 scripts/imx/imx.c       | 23 ++++++++++++------
 scripts/imx/imx.h       |  2 ++
 3 files changed, 66 insertions(+), 13 deletions(-)

diff --git a/scripts/imx/imx-image.c b/scripts/imx/imx-image.c
index 4a08581fb..6ebae2256 100644
--- a/scripts/imx/imx-image.c
+++ b/scripts/imx/imx-image.c
@@ -57,8 +57,7 @@ static char *prgname;
  */
 
 
-static uint32_t bb_header[] = {
-	0xea0003fe,	/* b 0x1000 */
+static uint32_t bb_header_aarch32[] = {
 	0xeafffffe,	/* 1: b 1b  */
 	0xeafffffe,	/* 1: b 1b  */
 	0xeafffffe,	/* 1: b 1b  */
@@ -66,6 +65,30 @@ static uint32_t bb_header[] = {
 	0xeafffffe,	/* 1: b 1b  */
 	0xeafffffe,	/* 1: b 1b  */
 	0xeafffffe,	/* 1: b 1b  */
+	0xeafffffe,	/* 1: b 1b  */
+	0x65726162,	/* 'bare'   */
+	0x00786f62,	/* 'box\0'  */
+	0x00000000,
+	0x00000000,
+	0x55555555,
+	0x55555555,
+	0x55555555,
+	0x55555555,
+	0x55555555,
+	0x55555555,
+	0x55555555,
+	0x55555555,
+};
+
+static uint32_t bb_header_aarch64[] = {
+	0x14000000,	/* 1: b 1b  */
+	0x14000000,	/* 1: b 1b  */
+	0x14000000,	/* 1: b 1b  */
+	0x14000000,	/* 1: b 1b  */
+	0x14000000,	/* 1: b 1b  */
+	0x14000000,	/* 1: b 1b  */
+	0x14000000,	/* 1: b 1b  */
+	0x14000000,	/* 1: b 1b  */
 	0x65726162,	/* 'bare'   */
 	0x00786f62,	/* 'box\0'  */
 	0x00000000,
@@ -652,6 +675,11 @@ static void *read_file(const char *filename, size_t *size)
 	return buf;
 }
 
+static bool cpu_is_aarch64(const struct config_data *data)
+{
+	return data->cpu_type == IMX_CPU_IMX8MQ;
+}
+
 int main(int argc, char *argv[])
 {
 	int opt, ret;
@@ -674,6 +702,8 @@ int main(int argc, char *argv[])
 		.check = check,
 		.nop = nop,
 	};
+	uint32_t *bb_header;
+	size_t sizeof_bb_header;
 
 	prgname = argv[0];
 
@@ -803,6 +833,15 @@ int main(int argc, char *argv[])
 		exit(1);
 	}
 
+	if (cpu_is_aarch64(&data)) {
+		bb_header = bb_header_aarch64;
+		sizeof_bb_header = sizeof(bb_header_aarch64);
+	} else {
+		bb_header = bb_header_aarch32;
+		sizeof_bb_header = sizeof(bb_header_aarch32);
+	}
+
+	bb_header[0] = data.first_opcode;
 	bb_header[ARM_HEAD_SIZE_INDEX] = barebox_image_size;
 
 	infile = read_file(imagename, &insize);
@@ -819,14 +858,19 @@ int main(int argc, char *argv[])
 
 	for (i = 0; i < header_copies; i++) {
 		ret = xwrite(outfd, add_barebox_header ? bb_header : buf,
-			     sizeof(bb_header));
+			     sizeof_bb_header);
 		if (ret < 0) {
 			perror("write");
 			exit(1);
 		}
 
-		ret = xwrite(outfd, buf + sizeof(bb_header),
-			     HEADER_LEN - sizeof(bb_header));
+		if (lseek(outfd, data.header_gap, SEEK_CUR) < 0) {
+			perror("lseek");
+			exit(1);
+		}
+
+		ret = xwrite(outfd, buf + sizeof_bb_header,
+			     HEADER_LEN - sizeof_bb_header);
 		if (ret < 0) {
 			perror("write");
 			exit(1);
diff --git a/scripts/imx/imx.c b/scripts/imx/imx.c
index fb6ac001e..d3786b6e1 100644
--- a/scripts/imx/imx.c
+++ b/scripts/imx/imx.c
@@ -222,17 +222,22 @@ struct soc_type {
 	char *name;
 	int header_version;
 	int cpu_type;
+	off_t header_gap;
+	uint32_t first_opcode;
 };
 
+#define SZ_32K	(32 * 1024)
+
 static struct soc_type socs[] = {
-	{ .name = "imx25", .header_version = 1, .cpu_type = IMX_CPU_IMX25 },
-	{ .name = "imx35", .header_version = 1, .cpu_type = IMX_CPU_IMX35 },
-	{ .name = "imx50", .header_version = 2, .cpu_type = IMX_CPU_IMX50 },
-	{ .name = "imx51", .header_version = 1, .cpu_type = IMX_CPU_IMX51 },
-	{ .name = "imx53", .header_version = 2, .cpu_type = IMX_CPU_IMX53 },
-	{ .name = "imx6", .header_version = 2, .cpu_type = IMX_CPU_IMX6 },
-	{ .name = "imx7", .header_version = 2, .cpu_type = IMX_CPU_IMX7 },
-	{ .name = "vf610", .header_version = 2, .cpu_type = IMX_CPU_VF610 },
+	{ .name = "imx25",  .header_version = 1, .cpu_type = IMX_CPU_IMX25,  .header_gap = 0,      .first_opcode = 0xea0003fe /* b 0x1000 */},
+	{ .name = "imx35",  .header_version = 1, .cpu_type = IMX_CPU_IMX35,  .header_gap = 0,      .first_opcode = 0xea0003fe /* b 0x1000 */},
+	{ .name = "imx50",  .header_version = 2, .cpu_type = IMX_CPU_IMX50,  .header_gap = 0,      .first_opcode = 0xea0003fe /* b 0x1000 */},
+	{ .name = "imx51",  .header_version = 1, .cpu_type = IMX_CPU_IMX51,  .header_gap = 0,      .first_opcode = 0xea0003fe /* b 0x1000 */},
+	{ .name = "imx53",  .header_version = 2, .cpu_type = IMX_CPU_IMX53,  .header_gap = 0,      .first_opcode = 0xea0003fe /* b 0x1000 */},
+	{ .name = "imx6",   .header_version = 2, .cpu_type = IMX_CPU_IMX6,   .header_gap = 0,      .first_opcode = 0xea0003fe /* b 0x1000 */},
+	{ .name = "imx7",   .header_version = 2, .cpu_type = IMX_CPU_IMX7,   .header_gap = 0,      .first_opcode = 0xea0003fe /* b 0x1000 */},
+	{ .name = "imx8mq", .header_version = 2, .cpu_type = IMX_CPU_IMX8MQ, .header_gap = SZ_32K, .first_opcode = 0x14009000 /* b 0x9000 */},
+	{ .name = "vf610",  .header_version = 2, .cpu_type = IMX_CPU_VF610,  .header_gap = 0,      .first_opcode = 0xea0003fe /* b 0x1000 */},
 };
 
 static int do_soc(struct config_data *data, int argc, char *argv[])
@@ -249,6 +254,8 @@ static int do_soc(struct config_data *data, int argc, char *argv[])
 		if (!strcmp(socs[i].name, soc)) {
 			data->header_version = socs[i].header_version;
 			data->cpu_type = socs[i].cpu_type;
+			data->header_gap = socs[i].header_gap;
+			data->first_opcode = socs[i].first_opcode;
 
 			if (data->cpu_type == IMX_CPU_IMX35)
 				data->load_size += HEADER_LEN;
diff --git a/scripts/imx/imx.h b/scripts/imx/imx.h
index c7677f81a..92a3fd316 100644
--- a/scripts/imx/imx.h
+++ b/scripts/imx/imx.h
@@ -72,6 +72,8 @@ struct config_data {
 	char *outfile;
 	char *srkfile;
 	int header_version;
+	off_t header_gap;
+	uint32_t first_opcode;
 	int cpu_type;
 	int (*check)(const struct config_data *data, uint32_t cmd,
 		     uint32_t addr, uint32_t mask);
-- 
2.17.0


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

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

* [PATCH v6 09/10] ARM: i.MX8: Add i.MX8mq EVK support
  2018-06-14  6:27 [PATCH v6 00/10] ARM: i.MX8MQ and EVK support Andrey Smirnov
                   ` (7 preceding siblings ...)
  2018-06-14  6:27 ` [PATCH v6 08/10] scripts: imx-image: Add i.MX8MQ support Andrey Smirnov
@ 2018-06-14  6:27 ` Andrey Smirnov
  2018-06-14  6:27 ` [PATCH v6 10/10] ARM: Introduce imx_v8_defconfig Andrey Smirnov
  9 siblings, 0 replies; 13+ messages in thread
From: Andrey Smirnov @ 2018-06-14  6:27 UTC (permalink / raw)
  To: barebox; +Cc: Andrey Smirnov

From: Sascha Hauer <s.hauer@pengutronix.de>

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com>
---
 Documentation/boards/imx.rst                  |   13 +-
 Documentation/boards/imx/nxp-imx8mq-evk.rst   |  116 ++
 arch/arm/boards/Makefile                      |    1 +
 arch/arm/boards/nxp-imx8mq-evk/.gitignore     |    1 +
 arch/arm/boards/nxp-imx8mq-evk/Makefile       |    4 +
 arch/arm/boards/nxp-imx8mq-evk/board.c        |   44 +
 arch/arm/boards/nxp-imx8mq-evk/ddr.h          |   28 +
 arch/arm/boards/nxp-imx8mq-evk/ddr_init.c     |  223 ++++
 arch/arm/boards/nxp-imx8mq-evk/ddrphy_train.c | 1026 +++++++++++++++++
 .../flash-header-imx8mq-evk.imxcfg            |    4 +
 arch/arm/boards/nxp-imx8mq-evk/lowlevel.c     |   81 ++
 arch/arm/dts/Makefile                         |    1 +
 arch/arm/dts/imx8mq-evk.dts                   |  444 +++++++
 arch/arm/mach-imx/Kconfig                     |    5 +
 firmware/Kconfig                              |    3 +
 firmware/Makefile                             |    6 +
 images/Makefile.imx                           |    7 +
 17 files changed, 2006 insertions(+), 1 deletion(-)
 create mode 100644 Documentation/boards/imx/nxp-imx8mq-evk.rst
 create mode 100644 arch/arm/boards/nxp-imx8mq-evk/.gitignore
 create mode 100644 arch/arm/boards/nxp-imx8mq-evk/Makefile
 create mode 100644 arch/arm/boards/nxp-imx8mq-evk/board.c
 create mode 100644 arch/arm/boards/nxp-imx8mq-evk/ddr.h
 create mode 100644 arch/arm/boards/nxp-imx8mq-evk/ddr_init.c
 create mode 100644 arch/arm/boards/nxp-imx8mq-evk/ddrphy_train.c
 create mode 100644 arch/arm/boards/nxp-imx8mq-evk/flash-header-imx8mq-evk.imxcfg
 create mode 100644 arch/arm/boards/nxp-imx8mq-evk/lowlevel.c
 create mode 100644 arch/arm/dts/imx8mq-evk.dts

diff --git a/Documentation/boards/imx.rst b/Documentation/boards/imx.rst
index b3002badf..db889ee70 100644
--- a/Documentation/boards/imx.rst
+++ b/Documentation/boards/imx.rst
@@ -21,6 +21,7 @@ The Internal Boot Mode is supported on:
 * i.MX53
 * i.MX6
 * i.MX7
+* i.MX8MQ
 
 With the Internal Boot Mode, the images contain a header which describes
 where the binary shall be loaded and started. These headers also contain
@@ -44,6 +45,15 @@ of the image to the card, use::
 
   dd if=images/barebox-freescale-imx51-babbage.img of=/dev/sdd bs=1024 skip=1 seek=1
 
+NOTE: MaskROM on i.MX8 expects image to start at +33KiB mark, so the
+following command has to be used instead:
+
+  dd if=images/barebox-nxp-imx8mq-evk.img of=/dev/sdd bs=1024 skip=33 seek=33
+
+Or, in case of NAND:
+
+  dd if=images/barebox-nxp-imx8mq-evk.img of=/dev/nand bs=1024 skip=33 seek=1
+
 The images can also always be started second stage::
 
   bootm /mnt/tftp/barebox-freescale-imx51-babbage.img
@@ -59,7 +69,8 @@ options in this file are:
 Header:
 
 +----------------+--------------------------------------------------------------+
-| soc <soctype>  | soctype can be one of imx35, imx51, imx53, imx6, imx7, vf610 |
+| soc <soctype>  |soctype can be one of imx35, imx51, imx53, imx6, imx7, vf610, |
+|                |                             imx8mq                           |
 +----------------+--------------------------------------------------------------+
 | loadaddr <adr> |     The address the binary is uploaded to                    |
 +----------------+--------------------------------------------------------------+
diff --git a/Documentation/boards/imx/nxp-imx8mq-evk.rst b/Documentation/boards/imx/nxp-imx8mq-evk.rst
new file mode 100644
index 000000000..9dfa911be
--- /dev/null
+++ b/Documentation/boards/imx/nxp-imx8mq-evk.rst
@@ -0,0 +1,116 @@
+NXP i.MX8MQ EVK Evaluation Board
+================================
+
+Board comes with:
+
+* 3GiB of LPDDR4 RAM
+* 16GiB eMMC
+
+Not including booting via serial, the device can boot from either SD or eMMC.
+
+Downloading DDR PHY Firmware
+----------------------------
+
+As a part of DDR intialization routine NXP i.MX8MQ EVK requires and
+uses several binary firmware blobs that are distributed under a
+separate EULA and cannot be included in Barebox. In order to obtain
+the do the following::
+
+ wget https://www.nxp.com/lgfiles/NMG/MAD/YOCTO/firmware-imx-7.2.bin
+ chmod +x firmware-imx-7.2.bin
+ ./firmware-imx-7.2.bin
+
+Executing that file should produce a EULA acceptance dialog as well as
+result in the following files:
+
+- lpddr4_pmu_train_1d_dmem.bin
+- lpddr4_pmu_train_1d_imem.bin
+- lpddr4_pmu_train_2d_dmem.bin
+- lpddr4_pmu_train_2d_imem.bin
+
+As a last step of this process those files need to be placed in
+"firmware/imx/"::
+
+  for f in lpddr4_pmu_train_1d_dmem.bin  \
+           lpddr4_pmu_train_1d_imem.bin  \
+	   lpddr4_pmu_train_2d_dmem.bin  \
+	   lpddr4_pmu_train_2d_imem.bin; \
+  do \
+	   cp firmware-imx-7.2/firmware/ddr/synopsys/${f} \
+	      firmware/imx/${f}; \
+  done
+
+DDR Configuration Code
+======================
+
+The following two files:
+
+  - ddr_init.c
+  - ddrphy_train.c
+
+were obtained by running i.MX 8M DDR Tool that can be found here:
+
+https://community.nxp.com/docs/DOC-340179
+
+Only minimal amount of necessary changes were made to those files.
+All of the "impedance matching" code is located in "ddr.h".
+
+Build Barebox
+=============
+
+ make imx_v8_defconfig
+ make
+
+Boot Configuration
+==================
+
+The NXM i.MX8MQ EVK Evaluation Board has two switches responsible for
+configuring bootsource/boot mode:
+
+ * SW802 for selecting appropriate BMOD
+ * SW801 for selecting appropriate boot medium
+
+In order to select internal boot set SW802 as follows::
+
+  +-----+
+  |     |
+  | O | | <--- on = high level
+  | | | |
+  | | O | <--- off = low level
+  |     |
+  | 1 2 |
+  +-----+
+
+Bootsource is the internal eMMC::
+
+  +---------+
+  |         |
+  | | | O | |
+  | | | | | |  <---- eMMC
+  | O O O O |
+  |         |
+  | 1 2 3 4 |
+  +---------+
+
+Bootsource is the SD2 slot::
+
+  +---------+
+  |         |
+  | O O | | |
+  | | | | | |  <---- SD2
+  | | | O O |
+  |         |
+  | 1 2 3 4 |
+  +---------+
+
+
+Serial boot SW802 setting needed for i.MX8 DDR Tool is as follows::
+
+  +-----+
+  |     |
+  | | O | <--- on = high level
+  | | | |
+  | O | | <--- off = low level
+  |     |
+  | 1 2 |
+  +-----+
\ No newline at end of file
diff --git a/arch/arm/boards/Makefile b/arch/arm/boards/Makefile
index b2fea4a40..711f9548f 100644
--- a/arch/arm/boards/Makefile
+++ b/arch/arm/boards/Makefile
@@ -80,6 +80,7 @@ obj-$(CONFIG_MACH_NVIDIA_BEAVER)		+= nvidia-beaver/
 obj-$(CONFIG_MACH_NVIDIA_JETSON)		+= nvidia-jetson-tk1/
 obj-$(CONFIG_MACH_NXDB500)			+= netx/
 obj-$(CONFIG_MACH_NXP_IMX6ULL_EVK)		+= nxp-imx6ull-evk/
+obj-$(CONFIG_MACH_NXP_IMX8MQ_EVK)		+= nxp-imx8mq-evk/
 obj-$(CONFIG_MACH_OMAP343xSDP)			+= omap343xdsp/
 obj-$(CONFIG_MACH_OMAP3EVM)			+= omap3evm/
 obj-$(CONFIG_MACH_PANDA)			+= panda/
diff --git a/arch/arm/boards/nxp-imx8mq-evk/.gitignore b/arch/arm/boards/nxp-imx8mq-evk/.gitignore
new file mode 100644
index 000000000..ef13747c9
--- /dev/null
+++ b/arch/arm/boards/nxp-imx8mq-evk/.gitignore
@@ -0,0 +1 @@
+*.ddr-phy-fw*
diff --git a/arch/arm/boards/nxp-imx8mq-evk/Makefile b/arch/arm/boards/nxp-imx8mq-evk/Makefile
new file mode 100644
index 000000000..0546b0b07
--- /dev/null
+++ b/arch/arm/boards/nxp-imx8mq-evk/Makefile
@@ -0,0 +1,4 @@
+obj-y += board.o
+lwl-y += lowlevel.o ddr_init.o ddrphy_train.o
+
+
diff --git a/arch/arm/boards/nxp-imx8mq-evk/board.c b/arch/arm/boards/nxp-imx8mq-evk/board.c
new file mode 100644
index 000000000..d93e21da1
--- /dev/null
+++ b/arch/arm/boards/nxp-imx8mq-evk/board.c
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2018 Sascha Hauer, Pengutronix
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation.
+ *
+ */
+
+#include <common.h>
+#include <init.h>
+#include <asm/memory.h>
+#include <linux/sizes.h>
+
+static int imx8mq_evk_mem_init(void)
+{
+	arm_add_mem_device("ram0", 0x40000000, SZ_2G);
+
+	request_sdram_region("ATF", 0x40000000, SZ_128K);
+
+	return 0;
+}
+mem_initcall(imx8mq_evk_mem_init);
+
+static int nxp_imx8mq_evk_init(void)
+{
+	if (!of_machine_is_compatible("fsl,imx8mq-evk"))
+		return 0;
+
+	barebox_set_hostname("imx8mq-evk");
+
+	return 0;
+}
+device_initcall(nxp_imx8mq_evk_init);
diff --git a/arch/arm/boards/nxp-imx8mq-evk/ddr.h b/arch/arm/boards/nxp-imx8mq-evk/ddr.h
new file mode 100644
index 000000000..2c25e3f98
--- /dev/null
+++ b/arch/arm/boards/nxp-imx8mq-evk/ddr.h
@@ -0,0 +1,28 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright (c) 2018 Zodiac Inflight Innovation
+ * Author: Andrey Smirnov <andrew.smirnov@gmail.com>
+ *
+ * Varios wrappers and macros needed to intgrate code generated by
+ * i.MX8M DDR Tool into rest of Barebox
+ */
+#include <common.h>
+#include <io.h>
+#include <mach/imx8-ddrc.h>
+
+/*
+ * Code generated by i.MX8 M DDR Tool doesn't have any prefixes in the
+ * global identifiers below, so in order to avoid symbol name
+ * collisions with other boards we re-name them via a #define
+ */
+#define ddr_init	nxp_imx8mq_evk_ddr_init
+#define ddr_cfg_phy	nxp_imx8mq_evk_ddr_cfg_phy
+
+void nxp_imx8mq_evk_ddr_init(void);
+
+#define FW_1D_IMAGE	imx_lpddr4_pmu_train_1d_imem_bin, \
+			imx_lpddr4_pmu_train_1d_dmem_bin
+#define FW_2D_IMAGE	imx_lpddr4_pmu_train_2d_imem_bin, \
+			imx_lpddr4_pmu_train_2d_dmem_bin
+
+
diff --git a/arch/arm/boards/nxp-imx8mq-evk/ddr_init.c b/arch/arm/boards/nxp-imx8mq-evk/ddr_init.c
new file mode 100644
index 000000000..81691b2fa
--- /dev/null
+++ b/arch/arm/boards/nxp-imx8mq-evk/ddr_init.c
@@ -0,0 +1,223 @@
+/*
+ * Copyright 2017 NXP
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ * Generated code from MX8_DDR_tool
+ */
+
+#include "ddr.h"
+
+void ddr_cfg_phy(void);
+void ddr_init(void)
+{
+	volatile unsigned int tmp, tmp_t;
+	
+	/** Initialize DDR clock and DDRC registers **/
+	reg32_write(0x3038a088,0x7070000);
+	reg32_write(0x3038a084,0x4030000);
+	reg32_write(0x303a00ec,0xffff);
+	tmp=reg32_read(0x303a00f8);
+	tmp |= 0x20;
+	reg32_write(0x303a00f8,tmp);
+	reg32_write(0x30391000,0x8f000000);
+	reg32_write(0x30391004,0x8f000000);
+	reg32_write(0x30360068,0xbbe580);
+	tmp=reg32_read(0x30360060);
+	tmp &= ~0x80;
+	reg32_write(0x30360060,tmp);
+	tmp=reg32_read(0x30360060);
+	tmp |= 0x200;
+	reg32_write(0x30360060,tmp);
+	tmp=reg32_read(0x30360060);
+	tmp &= ~0x20;
+	reg32_write(0x30360060,tmp);
+	tmp=reg32_read(0x30360060);
+	tmp &= ~0x10;
+	reg32_write(0x30360060,tmp);
+	do{
+		tmp=reg32_read(0x30360060);
+		if(tmp&0x80000000) break;
+	}while(1);
+	reg32_write(0x30391000,0x8f000006);
+	reg32_write(0x3d400304,0x1);
+	reg32_write(0x3d400030,0x1);
+	reg32_write(0x3d400000,0x83080020);
+	reg32_write(0x3d400064,0x6100e0);
+	reg32_write(0x3d4000d0,0xc003061c);
+	reg32_write(0x3d4000d4,0x9e0000);
+	reg32_write(0x3d4000dc,0xd4002d);
+	reg32_write(0x3d4000e0,0x310008);
+	reg32_write(0x3d4000e8,0x46004d);
+	reg32_write(0x3d4000ec,0x15004d);
+	reg32_write(0x3d4000f4,0x639);
+	reg32_write(0x3d400100,0x1a201b22);
+	reg32_write(0x3d400104,0x60633);
+	reg32_write(0x3d400108,0x70e1214);
+	reg32_write(0x3d40010c,0xc0c000);
+	reg32_write(0x3d400110,0xf04080f);
+	reg32_write(0x3d400114,0x2040c0c);
+	reg32_write(0x3d400118,0x1010007);
+	reg32_write(0x3d40011c,0x401);
+	reg32_write(0x3d400130,0x20600);
+	reg32_write(0x3d400134,0xc100002);
+	reg32_write(0x3d400138,0xe6);
+	reg32_write(0x3d400144,0xa00050);
+	reg32_write(0x3d400180,0x3200018);
+	reg32_write(0x3d400184,0x28061a8);
+	reg32_write(0x3d400190,0x497820a);
+	reg32_write(0x3d400194,0x80303);
+	reg32_write(0x3d4001b4,0x170a);
+	reg32_write(0x3d4001b0,0x11);
+	reg32_write(0x3d4001a0,0xe0400018);
+	reg32_write(0x3d4001a4,0xdf00e4);
+	reg32_write(0x3d4001a8,0x0);
+	reg32_write(0x3d4001c0,0x1);
+	reg32_write(0x3d4001c4,0x1);
+	reg32_write(0x3d400200,0x15);
+	reg32_write(0x3d40020c,0x0);
+	reg32_write(0x3d400210,0x1f1f);
+	reg32_write(0x3d400204,0x80808);
+	reg32_write(0x3d400214,0x7070707);
+	reg32_write(0x3d400218,0x48080707);
+	reg32_write(0x3d400244,0x0);
+	reg32_write(0x3d400490,0x1);
+	reg32_write(0x3d400250,0x29001f01);
+	reg32_write(0x3d400254,0x2c);
+	reg32_write(0x3d400264,0x900093e7);
+	reg32_write(0x3d40026c,0x2005574);
+	reg32_write(0x3d400400,0x400);
+	reg32_write(0x3d400408,0x72ff);
+	reg32_write(0x3d400494,0x10e00);
+	reg32_write(0x3d400498,0x620096);
+	reg32_write(0x3d40049c,0x10e00);
+	reg32_write(0x3d4004a0,0x12c);
+	reg32_write(0x30391000,0x8f000004);
+	reg32_write(0x30391000,0x8f000000);
+	reg32_write(0x3d400304,0x0);
+	reg32_write(0x3d400030,0xa8);
+	reg32_write(0x3d400320,0x0);
+	reg32_write(0x3d000000,0x1);
+	reg32_write(0x3d4001b0,0x10);
+	reg32_write(0x3d402100,0xa040305);
+	reg32_write(0x3d402104,0x30407);
+	reg32_write(0x3d402108,0x203060b);
+	reg32_write(0x3d40210c,0x505000);
+	reg32_write(0x3d402110,0x2040202);
+	reg32_write(0x3d402114,0x2030202);
+	reg32_write(0x3d402118,0x1010004);
+	reg32_write(0x3d40211c,0x301);
+	reg32_write(0x3d402138,0x1d);
+	reg32_write(0x3d402144,0x14000a);
+	reg32_write(0x3d403024,0x30d400);
+	reg32_write(0x3d402050,0x20d040);
+	reg32_write(0x3d402190,0x3818200);
+	reg32_write(0x3d4021b4,0x100);
+	reg32_write(0x3d402064,0xc001c);
+	reg32_write(0x3d4020dc,0x840000);
+	reg32_write(0x3d4020e8,0x46004d);
+	reg32_write(0x3d4020ec,0x15004d);
+	reg32_write(0x3d4020e0,0x310000);
+	reg32_write(0x3d403100,0x6010102);
+	reg32_write(0x3d403104,0x30404);
+	reg32_write(0x3d403108,0x203060b);
+	reg32_write(0x3d40310c,0x505000);
+	reg32_write(0x3d403110,0x2040202);
+	reg32_write(0x3d403114,0x2030202);
+	reg32_write(0x3d403118,0x1010004);
+	reg32_write(0x3d40311c,0x301);
+	reg32_write(0x3d403138,0x8);
+	reg32_write(0x3d403144,0x50003);
+	reg32_write(0x3d403024,0xc3500);
+	reg32_write(0x3d403050,0x20d040);
+	reg32_write(0x3d403190,0x3818200);
+	reg32_write(0x3d4031b4,0x100);
+	reg32_write(0x3d403064,0x30007);
+	reg32_write(0x3d4030dc,0x840000);
+	reg32_write(0x3d4030e8,0x46004d);
+	reg32_write(0x3d4030ec,0x15004d);
+	reg32_write(0x3d4030e0,0x310000);
+	reg32_write(0x3c040280,0x0);
+	reg32_write(0x3c040284,0x1);
+	reg32_write(0x3c040288,0x2);
+	reg32_write(0x3c04028c,0x3);
+	reg32_write(0x3c040290,0x4);
+	reg32_write(0x3c040294,0x5);
+	reg32_write(0x3c040298,0x6);
+	reg32_write(0x3c04029c,0x7);
+	reg32_write(0x3c044280,0x0);
+	reg32_write(0x3c044284,0x1);
+	reg32_write(0x3c044288,0x2);
+	reg32_write(0x3c04428c,0x3);
+	reg32_write(0x3c044290,0x4);
+	reg32_write(0x3c044294,0x5);
+	reg32_write(0x3c044298,0x6);
+	reg32_write(0x3c04429c,0x7);
+	reg32_write(0x3c048280,0x0);
+	reg32_write(0x3c048284,0x1);
+	reg32_write(0x3c048288,0x2);
+	reg32_write(0x3c04828c,0x3);
+	reg32_write(0x3c048290,0x4);
+	reg32_write(0x3c048294,0x5);
+	reg32_write(0x3c048298,0x6);
+	reg32_write(0x3c04829c,0x7);
+	reg32_write(0x3c04c280,0x0);
+	reg32_write(0x3c04c284,0x1);
+	reg32_write(0x3c04c288,0x2);
+	reg32_write(0x3c04c28c,0x3);
+	reg32_write(0x3c04c290,0x4);
+	reg32_write(0x3c04c294,0x5);
+	reg32_write(0x3c04c298,0x6);
+	reg32_write(0x3c04c29c,0x7);
+
+	/* Configure DDR PHY's registers */
+	ddr_cfg_phy();
+
+	reg32_write(DDRC_RFSHCTL3(0), 0x00000000);
+	reg32_write(DDRC_SWCTL(0), 0x0000);
+	/*
+	 * ------------------- 9 -------------------
+	 * Set DFIMISC.dfi_init_start to 1 
+	 *  -----------------------------------------
+	 */
+	reg32_write(DDRC_DFIMISC(0), 0x00000030);
+	reg32_write(DDRC_SWCTL(0), 0x0001);
+
+	/* wait DFISTAT.dfi_init_complete to 1 */
+	tmp_t = 0;
+	while(tmp_t==0){
+		tmp  = reg32_read(DDRC_DFISTAT(0));
+		tmp_t = tmp & 0x01;
+		tmp  = reg32_read(DDRC_MRSTAT(0));
+	}
+
+	reg32_write(DDRC_SWCTL(0), 0x0000);
+
+	/* clear DFIMISC.dfi_init_complete_en */
+	reg32_write(DDRC_DFIMISC(0), 0x00000010);
+	reg32_write(DDRC_DFIMISC(0), 0x00000011);
+	reg32_write(DDRC_PWRCTL(0), 0x00000088);
+
+	tmp = reg32_read(DDRC_CRCPARSTAT(0));
+	/*
+	 * set SWCTL.sw_done to enable quasi-dynamic register
+	 * programming outside reset.
+	 */
+	reg32_write(DDRC_SWCTL(0), 0x00000001);
+
+	/* wait SWSTAT.sw_done_ack to 1 */
+	while((reg32_read(DDRC_SWSTAT(0)) & 0x1) == 0)
+		;
+
+	/* wait STAT.operating_mode([1:0] for ddr3) to normal state */
+	while ((reg32_read(DDRC_STAT(0)) & 0x3) != 0x1)
+		;
+
+	reg32_write(DDRC_PWRCTL(0), 0x00000088);
+	/* reg32_write(DDRC_PWRCTL(0), 0x018a); */
+	tmp = reg32_read(DDRC_CRCPARSTAT(0));
+
+	/* enable port 0 */
+	reg32_write(DDRC_PCTRL_0(0), 0x00000001);
+	tmp = reg32_read(DDRC_CRCPARSTAT(0));
+	reg32_write(DDRC_RFSHCTL3(0), 0x00000000);
+}
\ No newline at end of file
diff --git a/arch/arm/boards/nxp-imx8mq-evk/ddrphy_train.c b/arch/arm/boards/nxp-imx8mq-evk/ddrphy_train.c
new file mode 100644
index 000000000..156d7cf87
--- /dev/null
+++ b/arch/arm/boards/nxp-imx8mq-evk/ddrphy_train.c
@@ -0,0 +1,1026 @@
+/*
+ * Copyright 2017 NXP
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include "ddr.h"
+
+void ddr_cfg_phy(void) {
+	unsigned int tmp, tmp_t;
+
+	//Init DDRPHY register...
+	reg32_write(0x3c080440,0x2);
+	reg32_write(0x3c080444,0x3);
+	reg32_write(0x3c080448,0x4);
+	reg32_write(0x3c08044c,0x5);
+	reg32_write(0x3c080450,0x0);
+	reg32_write(0x3c080454,0x1);
+	reg32_write(0x3c04017c,0x1ff);
+	reg32_write(0x3c04057c,0x1ff);
+	reg32_write(0x3c04417c,0x1ff);
+	reg32_write(0x3c04457c,0x1ff);
+	reg32_write(0x3c04817c,0x1ff);
+	reg32_write(0x3c04857c,0x1ff);
+	reg32_write(0x3c04c17c,0x1ff);
+	reg32_write(0x3c04c57c,0x1ff);
+	reg32_write(0x3c44017c,0x1ff);
+	reg32_write(0x3c44057c,0x1ff);
+	reg32_write(0x3c44417c,0x1ff);
+	reg32_write(0x3c44457c,0x1ff);
+	reg32_write(0x3c44817c,0x1ff);
+	reg32_write(0x3c44857c,0x1ff);
+	reg32_write(0x3c44c17c,0x1ff);
+	reg32_write(0x3c44c57c,0x1ff);
+	reg32_write(0x3c84017c,0x1ff);
+	reg32_write(0x3c84057c,0x1ff);
+	reg32_write(0x3c84417c,0x1ff);
+	reg32_write(0x3c84457c,0x1ff);
+	reg32_write(0x3c84817c,0x1ff);
+	reg32_write(0x3c84857c,0x1ff);
+	reg32_write(0x3c84c17c,0x1ff);
+	reg32_write(0x3c84c57c,0x1ff);
+	reg32_write(0x3c000154,0x1ff);
+	reg32_write(0x3c004154,0x1ff);
+	reg32_write(0x3c008154,0x1ff);
+	reg32_write(0x3c00c154,0x1ff);
+	reg32_write(0x3c010154,0x1ff);
+	reg32_write(0x3c014154,0x1ff);
+	reg32_write(0x3c018154,0x1ff);
+	reg32_write(0x3c01c154,0x1ff);
+	reg32_write(0x3c020154,0x1ff);
+	reg32_write(0x3c024154,0x1ff);
+	reg32_write(0x3c080314,0x19);
+	reg32_write(0x3c480314,0x7);
+	reg32_write(0x3c880314,0x7);
+	reg32_write(0x3c0800b8,0x2);
+	reg32_write(0x3c4800b8,0x2);
+	reg32_write(0x3c8800b8,0x2);
+	reg32_write(0x3c240810,0x0);
+	reg32_write(0x3c640810,0x0);
+	reg32_write(0x3ca40810,0x0);
+	reg32_write(0x3c080090,0xab);
+	reg32_write(0x3c0800e8,0x0);
+	reg32_write(0x3c480090,0xab);
+	reg32_write(0x3c0800e8,0x0);
+	reg32_write(0x3c880090,0xab);
+	reg32_write(0x3c0800e8,0x0);
+	reg32_write(0x3c080158,0x7);
+	reg32_write(0x3c480158,0xa);
+	reg32_write(0x3c880158,0xa);
+	reg32_write(0x3c040134,0xe00);
+	reg32_write(0x3c040534,0xe00);
+	reg32_write(0x3c044134,0xe00);
+	reg32_write(0x3c044534,0xe00);
+	reg32_write(0x3c048134,0xe00);
+	reg32_write(0x3c048534,0xe00);
+	reg32_write(0x3c04c134,0xe00);
+	reg32_write(0x3c04c534,0xe00);
+	reg32_write(0x3c440134,0xe00);
+	reg32_write(0x3c440534,0xe00);
+	reg32_write(0x3c444134,0xe00);
+	reg32_write(0x3c444534,0xe00);
+	reg32_write(0x3c448134,0xe00);
+	reg32_write(0x3c448534,0xe00);
+	reg32_write(0x3c44c134,0xe00);
+	reg32_write(0x3c44c534,0xe00);
+	reg32_write(0x3c840134,0xe00);
+	reg32_write(0x3c840534,0xe00);
+	reg32_write(0x3c844134,0xe00);
+	reg32_write(0x3c844534,0xe00);
+	reg32_write(0x3c848134,0xe00);
+	reg32_write(0x3c848534,0xe00);
+	reg32_write(0x3c84c134,0xe00);
+	reg32_write(0x3c84c534,0xe00);
+	reg32_write(0x3c040124,0xfbe);
+	reg32_write(0x3c040524,0xfbe);
+	reg32_write(0x3c044124,0xfbe);
+	reg32_write(0x3c044524,0xfbe);
+	reg32_write(0x3c048124,0xfbe);
+	reg32_write(0x3c048524,0xfbe);
+	reg32_write(0x3c04c124,0xfbe);
+	reg32_write(0x3c04c524,0xfbe);
+	reg32_write(0x3c440124,0xfbe);
+	reg32_write(0x3c440524,0xfbe);
+	reg32_write(0x3c444124,0xfbe);
+	reg32_write(0x3c444524,0xfbe);
+	reg32_write(0x3c448124,0xfbe);
+	reg32_write(0x3c448524,0xfbe);
+	reg32_write(0x3c44c124,0xfbe);
+	reg32_write(0x3c44c524,0xfbe);
+	reg32_write(0x3c840124,0xfbe);
+	reg32_write(0x3c840524,0xfbe);
+	reg32_write(0x3c844124,0xfbe);
+	reg32_write(0x3c844524,0xfbe);
+	reg32_write(0x3c848124,0xfbe);
+	reg32_write(0x3c848524,0xfbe);
+	reg32_write(0x3c84c124,0xfbe);
+	reg32_write(0x3c84c524,0xfbe);
+	reg32_write(0x3c00010c,0x63);
+	reg32_write(0x3c00410c,0x63);
+	reg32_write(0x3c00810c,0x63);
+	reg32_write(0x3c00c10c,0x63);
+	reg32_write(0x3c01010c,0x63);
+	reg32_write(0x3c01410c,0x63);
+	reg32_write(0x3c01810c,0x63);
+	reg32_write(0x3c01c10c,0x63);
+	reg32_write(0x3c02010c,0x63);
+	reg32_write(0x3c02410c,0x63);
+	reg32_write(0x3c080060,0x3);
+	reg32_write(0x3c0801d4,0x4);
+	reg32_write(0x3c080140,0x0);
+	reg32_write(0x3c080020,0x320);
+	reg32_write(0x3c480020,0x64);
+	reg32_write(0x3c880020,0x19);
+	reg32_write(0x3c080220,0x9);
+	reg32_write(0x3c0802c8,0xdc);
+	reg32_write(0x3c04010c,0x5a1);
+	reg32_write(0x3c04050c,0x5a1);
+	reg32_write(0x3c04410c,0x5a1);
+	reg32_write(0x3c04450c,0x5a1);
+	reg32_write(0x3c04810c,0x5a1);
+	reg32_write(0x3c04850c,0x5a1);
+	reg32_write(0x3c04c10c,0x5a1);
+	reg32_write(0x3c04c50c,0x5a1);
+	reg32_write(0x3c4802c8,0xdc);
+	reg32_write(0x3c44010c,0x5a1);
+	reg32_write(0x3c44050c,0x5a1);
+	reg32_write(0x3c44410c,0x5a1);
+	reg32_write(0x3c44450c,0x5a1);
+	reg32_write(0x3c44810c,0x5a1);
+	reg32_write(0x3c44850c,0x5a1);
+	reg32_write(0x3c44c10c,0x5a1);
+	reg32_write(0x3c44c50c,0x5a1);
+	reg32_write(0x3c8802c8,0xdc);
+	reg32_write(0x3c84010c,0x5a1);
+	reg32_write(0x3c84050c,0x5a1);
+	reg32_write(0x3c84410c,0x5a1);
+	reg32_write(0x3c84450c,0x5a1);
+	reg32_write(0x3c84810c,0x5a1);
+	reg32_write(0x3c84850c,0x5a1);
+	reg32_write(0x3c84c10c,0x5a1);
+	reg32_write(0x3c84c50c,0x5a1);
+	reg32_write(0x3c0803e8,0x1);
+	reg32_write(0x3c4803e8,0x1);
+	reg32_write(0x3c8803e8,0x1);
+	reg32_write(0x3c080064,0x1);
+	reg32_write(0x3c480064,0x1);
+	reg32_write(0x3c880064,0x1);
+	reg32_write(0x3c0803c0,0x660);
+	reg32_write(0x3c0803c4,0x0);
+	reg32_write(0x3c0803c8,0x4444);
+	reg32_write(0x3c0803cc,0x8888);
+	reg32_write(0x3c0803d0,0x5665);
+	reg32_write(0x3c0803d4,0x0);
+	reg32_write(0x3c0803d8,0x0);
+	reg32_write(0x3c0803dc,0xf000);
+	reg32_write(0x3c080094,0x0);
+	reg32_write(0x3c0800b4,0x0);
+	reg32_write(0x3c4800b4,0x0);
+	reg32_write(0x3c8800b4,0x0);
+	reg32_write(0x3c080180,0x2);
+
+	//enable APB bus to access DDRPHY RAM
+	reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0xd0000, 0x0);
+	//load the 1D training image
+	ddr_load_train_code(FW_1D_IMAGE);
+
+	//configure DDRPHY-FW DMEM structure @clock0...
+	reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0xd0099, 0x1);
+
+	//set the PHY input clock to the desired frequency for pstate 0
+	reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x54003,0xc80);
+	reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x54004,0x2);
+	reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x54006,0x11);
+	reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x54008,0x131f);
+	reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x54009,0xc8);
+	reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x5400b,0x2);
+	reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x54012,0x310);
+	reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x54019,0x2dd4);
+	reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x5401a,0x31);
+	reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x5401b,0x4d46);
+	reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x5401c,0x4d08);
+	reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x5401e,0x15);
+	reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x5401f,0x2dd4);
+	reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x54020,0x31);
+	reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x54021,0x4d46);
+	reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x54022,0x4d08);
+	reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x54024,0x15);
+	reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x5402b,0x1000);
+	reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x5402c,0x3);
+	reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x54032,0xd400);
+	reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x54033,0x312d);
+	reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x54034,0x4600);
+	reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x54035,0x84d);
+	reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x54036,0x4d);
+	reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x54037,0x1500);
+	reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x54038,0xd400);
+	reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x54039,0x312d);
+	reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x5403a,0x4600);
+	reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x5403b,0x84d);
+	reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x5403c,0x4d);
+	reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x5403d,0x1500);
+
+	//disable APB bus to access DDRPHY RAM
+	reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0xd0000, 0x1);
+	//Reset MPU and run
+	reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0xd0099, 0x9);
+	reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0xd0099, 0x1);
+	reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0xd0099, 0x0);
+	wait_ddrphy_training_complete();
+
+	//configure DDRPHY-FW DMEM structure @clock1...
+	reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0xd0099, 0x1);
+
+	//set the PHY input clock to the desired frequency for pstate 1
+	reg32_write(0x3038a008,0x7070000);
+	reg32_write(0x3038a004,0x5000000);
+	reg32_write(0x3038a088,0x7070000);
+	reg32_write(0x3038a084,0x2010000);
+	reg32_write(0x303a00ec,0xffff);
+	tmp=reg32_read(0x303a00f8);
+	tmp |= 0x20;
+	reg32_write(0x303a00f8,tmp);
+	reg32_write(0x30389804,0x1000000);
+
+	//enable APB bus to access DDRPHY RAM
+	reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0xd0000, 0x0);
+
+	reg32_write(0x3c150008,0x101);
+	reg32_write(0x3c15000c,0x190);
+	reg32_write(0x3c150020,0x121f);
+	reg32_write(0x3c150064,0x84);
+	reg32_write(0x3c150068,0x31);
+	reg32_write(0x3c15006c,0x4d46);
+	reg32_write(0x3c150070,0x4d08);
+	reg32_write(0x3c150074,0x0);
+	reg32_write(0x3c150078,0x15);
+	reg32_write(0x3c15007c,0x84);
+	reg32_write(0x3c150080,0x31);
+	reg32_write(0x3c150084,0x4d46);
+	reg32_write(0x3c150088,0x4d08);
+	reg32_write(0x3c15008c,0x0);
+	reg32_write(0x3c150090,0x15);
+	reg32_write(0x3c1500c8,0x8400);
+	reg32_write(0x3c1500cc,0x3100);
+	reg32_write(0x3c1500d0,0x4600);
+	reg32_write(0x3c1500d4,0x84d);
+	reg32_write(0x3c1500d8,0x4d);
+	reg32_write(0x3c1500dc,0x1500);
+	reg32_write(0x3c1500e0,0x8400);
+	reg32_write(0x3c1500e4,0x3100);
+	reg32_write(0x3c1500e8,0x4600);
+	reg32_write(0x3c1500ec,0x84d);
+	reg32_write(0x3c1500f0,0x4d);
+	reg32_write(0x3c1500f4,0x1500);
+	reg32_write(0x3c1500f8,0x0);
+
+	//disable APB bus to access DDRPHY RAM
+	reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0xd0000, 0x1);
+	//Reset MPU and run
+	reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0xd0099, 0x9);
+	reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0xd0099, 0x1);
+	reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0xd0099, 0x0);
+	wait_ddrphy_training_complete();
+
+	//configure DDRPHY-FW DMEM structure @clock2...
+	reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0xd0099, 0x1);
+
+	//set the PHY input clock to the desired frequency for pstate 2
+	reg32_write(0x3038a008,0x7070000);
+	reg32_write(0x3038a004,0x2000000);
+	reg32_write(0x3038a088,0x7070000);
+	reg32_write(0x3038a084,0x2010000);
+	reg32_write(0x303a00ec,0xffff);
+	tmp=reg32_read(0x303a00f8);
+	tmp |= 0x20;
+	reg32_write(0x303a00f8,tmp);
+	reg32_write(0x30389804,0x1000000);
+
+	//enable APB bus to access DDRPHY RAM
+	reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0xd0000, 0x0);
+
+	reg32_write(0x3c150008,0x102);
+	reg32_write(0x3c15000c,0x64);
+	reg32_write(0x3c150020,0x121f);
+	reg32_write(0x3c150064,0x84);
+	reg32_write(0x3c150068,0x31);
+	reg32_write(0x3c15006c,0x4d46);
+	reg32_write(0x3c150070,0x4d08);
+	reg32_write(0x3c150074,0x0);
+	reg32_write(0x3c150078,0x15);
+	reg32_write(0x3c15007c,0x84);
+	reg32_write(0x3c150080,0x31);
+	reg32_write(0x3c150084,0x4d46);
+	reg32_write(0x3c150088,0x4d08);
+	reg32_write(0x3c15008c,0x0);
+	reg32_write(0x3c150090,0x15);
+	reg32_write(0x3c1500c8,0x8400);
+	reg32_write(0x3c1500cc,0x3100);
+	reg32_write(0x3c1500d0,0x4600);
+	reg32_write(0x3c1500d4,0x84d);
+	reg32_write(0x3c1500d8,0x4d);
+	reg32_write(0x3c1500dc,0x1500);
+	reg32_write(0x3c1500e0,0x8400);
+	reg32_write(0x3c1500e4,0x3100);
+	reg32_write(0x3c1500e8,0x4600);
+	reg32_write(0x3c1500ec,0x84d);
+	reg32_write(0x3c1500f0,0x4d);
+	reg32_write(0x3c1500f4,0x1500);
+	reg32_write(0x3c1500f8,0x0);
+
+	//disable APB bus to access DDRPHY RAM
+	reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0xd0000, 0x1);
+	//Reset MPU and run
+	reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0xd0099, 0x9);
+	reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0xd0099, 0x1);
+	reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0xd0099, 0x0);
+	wait_ddrphy_training_complete();
+
+	//set the PHY input clock to the desired frequency for pstate 0
+	reg32_write(0x3038a088,0x7070000);
+	reg32_write(0x3038a084,0x4030000);
+	reg32_write(0x303a00ec,0xffff);
+	tmp=reg32_read(0x303a00f8);
+	tmp |= 0x20;
+	reg32_write(0x303a00f8,tmp);
+	reg32_write(0x30360068,0xbbe580);
+	tmp=reg32_read(0x30360060);
+	tmp &= ~0x80;
+	reg32_write(0x30360060,tmp);
+	tmp=reg32_read(0x30360060);
+	tmp |= 0x200;
+	reg32_write(0x30360060,tmp);
+	tmp=reg32_read(0x30360060);
+	tmp &= ~0x20;
+	reg32_write(0x30360060,tmp);
+	tmp=reg32_read(0x30360060);
+	tmp &= ~0x10;
+	reg32_write(0x30360060,tmp);
+	do{
+		tmp=reg32_read(0x30360060);
+		if(tmp&0x80000000) break;
+	}while(1);
+	reg32_write(0x30389808,0x1000000);
+	reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0xd0099, 0x1);
+
+
+	//enable APB bus to access DDRPHY RAM
+	reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0xd0000, 0x0);
+	//load the 2D training image
+	ddr_load_train_code(FW_2D_IMAGE);
+
+	reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x54003,0xc80);
+	reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x54006,0x11);
+	reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x54008,0x61);
+	reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x54009,0xc8);
+	reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x5400b,0x2);
+	reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x5400f,0x100);
+	reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x54010,0x1f7f);
+	reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x54012,0x310);
+	reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x54019,0x2dd4);
+	reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x5401a,0x31);
+	reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x5401b,0x4d46);
+	reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x5401c,0x4d08);
+	reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x5401e,0x15);
+	reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x5401f,0x2dd4);
+	reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x54020,0x31);
+	reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x54021,0x4d46);
+	reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x54022,0x4d08);
+	reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x54024,0x15);
+	reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x5402b,0x1000);
+	reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x5402c,0x3);
+	reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x54032,0xd400);
+	reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x54033,0x312d);
+	reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x54034,0x4600);
+	reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x54035,0x84d);
+	reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x54036,0x4d);
+	reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x54037,0x1500);
+	reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x54038,0xd400);
+	reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x54039,0x312d);
+	reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x5403a,0x4600);
+	reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x5403b,0x84d);
+	reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x5403c,0x4d);
+	reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x5403d,0x1500);
+
+	//disable APB bus to access DDRPHY RAM
+	reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0xd0000, 0x1);
+	//Reset MPU and run
+	reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0xd0099, 0x9);
+	reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0xd0099, 0x1);
+	reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0xd0099, 0x0);
+	wait_ddrphy_training_complete();
+
+	//Halt MPU
+	reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0xd0099, 0x1);
+	//enable APB bus to access DDRPHY RAM
+	reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0xd0000, 0x0);
+
+	//Load firmware PIE image
+	reg32_write(0x3c240000,0x10);
+	reg32_write(0x3c240004,0x400);
+	reg32_write(0x3c240008,0x10e);
+	reg32_write(0x3c24000c,0x0);
+	reg32_write(0x3c240010,0x0);
+	reg32_write(0x3c240014,0x8);
+	reg32_write(0x3c2400a4,0xb);
+	reg32_write(0x3c2400a8,0x480);
+	reg32_write(0x3c2400ac,0x109);
+	reg32_write(0x3c2400b0,0x8);
+	reg32_write(0x3c2400b4,0x448);
+	reg32_write(0x3c2400b8,0x139);
+	reg32_write(0x3c2400bc,0x8);
+	reg32_write(0x3c2400c0,0x478);
+	reg32_write(0x3c2400c4,0x109);
+	reg32_write(0x3c2400c8,0x0);
+	reg32_write(0x3c2400cc,0xe8);
+	reg32_write(0x3c2400d0,0x109);
+	reg32_write(0x3c2400d4,0x2);
+	reg32_write(0x3c2400d8,0x10);
+	reg32_write(0x3c2400dc,0x139);
+	reg32_write(0x3c2400e0,0xf);
+	reg32_write(0x3c2400e4,0x7c0);
+	reg32_write(0x3c2400e8,0x139);
+	reg32_write(0x3c2400ec,0x44);
+	reg32_write(0x3c2400f0,0x630);
+	reg32_write(0x3c2400f4,0x159);
+	reg32_write(0x3c2400f8,0x14f);
+	reg32_write(0x3c2400fc,0x630);
+	reg32_write(0x3c240100,0x159);
+	reg32_write(0x3c240104,0x47);
+	reg32_write(0x3c240108,0x630);
+	reg32_write(0x3c24010c,0x149);
+	reg32_write(0x3c240110,0x4f);
+	reg32_write(0x3c240114,0x630);
+	reg32_write(0x3c240118,0x179);
+	reg32_write(0x3c24011c,0x8);
+	reg32_write(0x3c240120,0xe0);
+	reg32_write(0x3c240124,0x109);
+	reg32_write(0x3c240128,0x0);
+	reg32_write(0x3c24012c,0x7c8);
+	reg32_write(0x3c240130,0x109);
+	reg32_write(0x3c240134,0x0);
+	reg32_write(0x3c240138,0x1);
+	reg32_write(0x3c24013c,0x8);
+	reg32_write(0x3c240140,0x0);
+	reg32_write(0x3c240144,0x45a);
+	reg32_write(0x3c240148,0x9);
+	reg32_write(0x3c24014c,0x0);
+	reg32_write(0x3c240150,0x448);
+	reg32_write(0x3c240154,0x109);
+	reg32_write(0x3c240158,0x40);
+	reg32_write(0x3c24015c,0x630);
+	reg32_write(0x3c240160,0x179);
+	reg32_write(0x3c240164,0x1);
+	reg32_write(0x3c240168,0x618);
+	reg32_write(0x3c24016c,0x109);
+	reg32_write(0x3c240170,0x40c0);
+	reg32_write(0x3c240174,0x630);
+	reg32_write(0x3c240178,0x149);
+	reg32_write(0x3c24017c,0x8);
+	reg32_write(0x3c240180,0x4);
+	reg32_write(0x3c240184,0x48);
+	reg32_write(0x3c240188,0x4040);
+	reg32_write(0x3c24018c,0x630);
+	reg32_write(0x3c240190,0x149);
+	reg32_write(0x3c240194,0x0);
+	reg32_write(0x3c240198,0x4);
+	reg32_write(0x3c24019c,0x48);
+	reg32_write(0x3c2401a0,0x40);
+	reg32_write(0x3c2401a4,0x630);
+	reg32_write(0x3c2401a8,0x149);
+	reg32_write(0x3c2401ac,0x10);
+	reg32_write(0x3c2401b0,0x4);
+	reg32_write(0x3c2401b4,0x18);
+	reg32_write(0x3c2401b8,0x0);
+	reg32_write(0x3c2401bc,0x4);
+	reg32_write(0x3c2401c0,0x78);
+	reg32_write(0x3c2401c4,0x549);
+	reg32_write(0x3c2401c8,0x630);
+	reg32_write(0x3c2401cc,0x159);
+	reg32_write(0x3c2401d0,0xd49);
+	reg32_write(0x3c2401d4,0x630);
+	reg32_write(0x3c2401d8,0x159);
+	reg32_write(0x3c2401dc,0x94a);
+	reg32_write(0x3c2401e0,0x630);
+	reg32_write(0x3c2401e4,0x159);
+	reg32_write(0x3c2401e8,0x441);
+	reg32_write(0x3c2401ec,0x630);
+	reg32_write(0x3c2401f0,0x149);
+	reg32_write(0x3c2401f4,0x42);
+	reg32_write(0x3c2401f8,0x630);
+	reg32_write(0x3c2401fc,0x149);
+	reg32_write(0x3c240200,0x1);
+	reg32_write(0x3c240204,0x630);
+	reg32_write(0x3c240208,0x149);
+	reg32_write(0x3c24020c,0x0);
+	reg32_write(0x3c240210,0xe0);
+	reg32_write(0x3c240214,0x109);
+	reg32_write(0x3c240218,0xa);
+	reg32_write(0x3c24021c,0x10);
+	reg32_write(0x3c240220,0x109);
+	reg32_write(0x3c240224,0x9);
+	reg32_write(0x3c240228,0x3c0);
+	reg32_write(0x3c24022c,0x149);
+	reg32_write(0x3c240230,0x9);
+	reg32_write(0x3c240234,0x3c0);
+	reg32_write(0x3c240238,0x159);
+	reg32_write(0x3c24023c,0x18);
+	reg32_write(0x3c240240,0x10);
+	reg32_write(0x3c240244,0x109);
+	reg32_write(0x3c240248,0x0);
+	reg32_write(0x3c24024c,0x3c0);
+	reg32_write(0x3c240250,0x109);
+	reg32_write(0x3c240254,0x18);
+	reg32_write(0x3c240258,0x4);
+	reg32_write(0x3c24025c,0x48);
+	reg32_write(0x3c240260,0x18);
+	reg32_write(0x3c240264,0x4);
+	reg32_write(0x3c240268,0x58);
+	reg32_write(0x3c24026c,0xa);
+	reg32_write(0x3c240270,0x10);
+	reg32_write(0x3c240274,0x109);
+	reg32_write(0x3c240278,0x2);
+	reg32_write(0x3c24027c,0x10);
+	reg32_write(0x3c240280,0x109);
+	reg32_write(0x3c240284,0x5);
+	reg32_write(0x3c240288,0x7c0);
+	reg32_write(0x3c24028c,0x109);
+	reg32_write(0x3c240290,0x10);
+	reg32_write(0x3c240294,0x10);
+	reg32_write(0x3c240298,0x109);
+	reg32_write(0x3c100000,0x811);
+	reg32_write(0x3c100080,0x880);
+	reg32_write(0x3c100100,0x0);
+	reg32_write(0x3c100180,0x0);
+	reg32_write(0x3c100004,0x4008);
+	reg32_write(0x3c100084,0x83);
+	reg32_write(0x3c100104,0x4f);
+	reg32_write(0x3c100184,0x0);
+	reg32_write(0x3c100008,0x4040);
+	reg32_write(0x3c100088,0x83);
+	reg32_write(0x3c100108,0x51);
+	reg32_write(0x3c100188,0x0);
+	reg32_write(0x3c10000c,0x811);
+	reg32_write(0x3c10008c,0x880);
+	reg32_write(0x3c10010c,0x0);
+	reg32_write(0x3c10018c,0x0);
+	reg32_write(0x3c100010,0x720);
+	reg32_write(0x3c100090,0xf);
+	reg32_write(0x3c100110,0x1740);
+	reg32_write(0x3c100190,0x0);
+	reg32_write(0x3c100014,0x16);
+	reg32_write(0x3c100094,0x83);
+	reg32_write(0x3c100114,0x4b);
+	reg32_write(0x3c100194,0x0);
+	reg32_write(0x3c100018,0x716);
+	reg32_write(0x3c100098,0xf);
+	reg32_write(0x3c100118,0x2001);
+	reg32_write(0x3c100198,0x0);
+	reg32_write(0x3c10001c,0x716);
+	reg32_write(0x3c10009c,0xf);
+	reg32_write(0x3c10011c,0x2800);
+	reg32_write(0x3c10019c,0x0);
+	reg32_write(0x3c100020,0x716);
+	reg32_write(0x3c1000a0,0xf);
+	reg32_write(0x3c100120,0xf00);
+	reg32_write(0x3c1001a0,0x0);
+	reg32_write(0x3c100024,0x720);
+	reg32_write(0x3c1000a4,0xf);
+	reg32_write(0x3c100124,0x1400);
+	reg32_write(0x3c1001a4,0x0);
+	reg32_write(0x3c100028,0xe08);
+	reg32_write(0x3c1000a8,0xc15);
+	reg32_write(0x3c100128,0x0);
+	reg32_write(0x3c1001a8,0x0);
+	reg32_write(0x3c10002c,0x623);
+	reg32_write(0x3c1000ac,0x15);
+	reg32_write(0x3c10012c,0x0);
+	reg32_write(0x3c1001ac,0x0);
+	reg32_write(0x3c100030,0x4028);
+	reg32_write(0x3c1000b0,0x80);
+	reg32_write(0x3c100130,0x0);
+	reg32_write(0x3c1001b0,0x0);
+	reg32_write(0x3c100034,0xe08);
+	reg32_write(0x3c1000b4,0xc1a);
+	reg32_write(0x3c100134,0x0);
+	reg32_write(0x3c1001b4,0x0);
+	reg32_write(0x3c100038,0x623);
+	reg32_write(0x3c1000b8,0x1a);
+	reg32_write(0x3c100138,0x0);
+	reg32_write(0x3c1001b8,0x0);
+	reg32_write(0x3c10003c,0x4040);
+	reg32_write(0x3c1000bc,0x80);
+	reg32_write(0x3c10013c,0x0);
+	reg32_write(0x3c1001bc,0x0);
+	reg32_write(0x3c100040,0x2604);
+	reg32_write(0x3c1000c0,0x15);
+	reg32_write(0x3c100140,0x0);
+	reg32_write(0x3c1001c0,0x0);
+	reg32_write(0x3c100044,0x708);
+	reg32_write(0x3c1000c4,0x5);
+	reg32_write(0x3c100144,0x0);
+	reg32_write(0x3c1001c4,0x2002);
+	reg32_write(0x3c100048,0x8);
+	reg32_write(0x3c1000c8,0x80);
+	reg32_write(0x3c100148,0x0);
+	reg32_write(0x3c1001c8,0x0);
+	reg32_write(0x3c10004c,0x2604);
+	reg32_write(0x3c1000cc,0x1a);
+	reg32_write(0x3c10014c,0x0);
+	reg32_write(0x3c1001cc,0x0);
+	reg32_write(0x3c100050,0x708);
+	reg32_write(0x3c1000d0,0xa);
+	reg32_write(0x3c100150,0x0);
+	reg32_write(0x3c1001d0,0x2002);
+	reg32_write(0x3c100054,0x4040);
+	reg32_write(0x3c1000d4,0x80);
+	reg32_write(0x3c100154,0x0);
+	reg32_write(0x3c1001d4,0x0);
+	reg32_write(0x3c100058,0x60a);
+	reg32_write(0x3c1000d8,0x15);
+	reg32_write(0x3c100158,0x1200);
+	reg32_write(0x3c1001d8,0x0);
+	reg32_write(0x3c10005c,0x61a);
+	reg32_write(0x3c1000dc,0x15);
+	reg32_write(0x3c10015c,0x1300);
+	reg32_write(0x3c1001dc,0x0);
+	reg32_write(0x3c100060,0x60a);
+	reg32_write(0x3c1000e0,0x1a);
+	reg32_write(0x3c100160,0x1200);
+	reg32_write(0x3c1001e0,0x0);
+	reg32_write(0x3c100064,0x642);
+	reg32_write(0x3c1000e4,0x1a);
+	reg32_write(0x3c100164,0x1300);
+	reg32_write(0x3c1001e4,0x0);
+	reg32_write(0x3c100068,0x4808);
+	reg32_write(0x3c1000e8,0x880);
+	reg32_write(0x3c100168,0x0);
+	reg32_write(0x3c1001e8,0x0);
+	reg32_write(0x3c24029c,0x0);
+	reg32_write(0x3c2402a0,0x790);
+	reg32_write(0x3c2402a4,0x11a);
+	reg32_write(0x3c2402a8,0x8);
+	reg32_write(0x3c2402ac,0x7aa);
+	reg32_write(0x3c2402b0,0x2a);
+	reg32_write(0x3c2402b4,0x10);
+	reg32_write(0x3c2402b8,0x7b2);
+	reg32_write(0x3c2402bc,0x2a);
+	reg32_write(0x3c2402c0,0x0);
+	reg32_write(0x3c2402c4,0x7c8);
+	reg32_write(0x3c2402c8,0x109);
+	reg32_write(0x3c2402cc,0x10);
+	reg32_write(0x3c2402d0,0x2a8);
+	reg32_write(0x3c2402d4,0x129);
+	reg32_write(0x3c2402d8,0x8);
+	reg32_write(0x3c2402dc,0x370);
+	reg32_write(0x3c2402e0,0x129);
+	reg32_write(0x3c2402e4,0xa);
+	reg32_write(0x3c2402e8,0x3c8);
+	reg32_write(0x3c2402ec,0x1a9);
+	reg32_write(0x3c2402f0,0xc);
+	reg32_write(0x3c2402f4,0x408);
+	reg32_write(0x3c2402f8,0x199);
+	reg32_write(0x3c2402fc,0x14);
+	reg32_write(0x3c240300,0x790);
+	reg32_write(0x3c240304,0x11a);
+	reg32_write(0x3c240308,0x8);
+	reg32_write(0x3c24030c,0x4);
+	reg32_write(0x3c240310,0x18);
+	reg32_write(0x3c240314,0xe);
+	reg32_write(0x3c240318,0x408);
+	reg32_write(0x3c24031c,0x199);
+	reg32_write(0x3c240320,0x8);
+	reg32_write(0x3c240324,0x8568);
+	reg32_write(0x3c240328,0x108);
+	reg32_write(0x3c24032c,0x18);
+	reg32_write(0x3c240330,0x790);
+	reg32_write(0x3c240334,0x16a);
+	reg32_write(0x3c240338,0x8);
+	reg32_write(0x3c24033c,0x1d8);
+	reg32_write(0x3c240340,0x169);
+	reg32_write(0x3c240344,0x10);
+	reg32_write(0x3c240348,0x8558);
+	reg32_write(0x3c24034c,0x168);
+	reg32_write(0x3c240350,0x70);
+	reg32_write(0x3c240354,0x788);
+	reg32_write(0x3c240358,0x16a);
+	reg32_write(0x3c24035c,0x1ff8);
+	reg32_write(0x3c240360,0x85a8);
+	reg32_write(0x3c240364,0x1e8);
+	reg32_write(0x3c240368,0x50);
+	reg32_write(0x3c24036c,0x798);
+	reg32_write(0x3c240370,0x16a);
+	reg32_write(0x3c240374,0x60);
+	reg32_write(0x3c240378,0x7a0);
+	reg32_write(0x3c24037c,0x16a);
+	reg32_write(0x3c240380,0x8);
+	reg32_write(0x3c240384,0x8310);
+	reg32_write(0x3c240388,0x168);
+	reg32_write(0x3c24038c,0x8);
+	reg32_write(0x3c240390,0xa310);
+	reg32_write(0x3c240394,0x168);
+	reg32_write(0x3c240398,0xa);
+	reg32_write(0x3c24039c,0x408);
+	reg32_write(0x3c2403a0,0x169);
+	reg32_write(0x3c2403a4,0x6e);
+	reg32_write(0x3c2403a8,0x0);
+	reg32_write(0x3c2403ac,0x68);
+	reg32_write(0x3c2403b0,0x0);
+	reg32_write(0x3c2403b4,0x408);
+	reg32_write(0x3c2403b8,0x169);
+	reg32_write(0x3c2403bc,0x0);
+	reg32_write(0x3c2403c0,0x8310);
+	reg32_write(0x3c2403c4,0x168);
+	reg32_write(0x3c2403c8,0x0);
+	reg32_write(0x3c2403cc,0xa310);
+	reg32_write(0x3c2403d0,0x168);
+	reg32_write(0x3c2403d4,0x1ff8);
+	reg32_write(0x3c2403d8,0x85a8);
+	reg32_write(0x3c2403dc,0x1e8);
+	reg32_write(0x3c2403e0,0x68);
+	reg32_write(0x3c2403e4,0x798);
+	reg32_write(0x3c2403e8,0x16a);
+	reg32_write(0x3c2403ec,0x78);
+	reg32_write(0x3c2403f0,0x7a0);
+	reg32_write(0x3c2403f4,0x16a);
+	reg32_write(0x3c2403f8,0x68);
+	reg32_write(0x3c2403fc,0x790);
+	reg32_write(0x3c240400,0x16a);
+	reg32_write(0x3c240404,0x8);
+	reg32_write(0x3c240408,0x8b10);
+	reg32_write(0x3c24040c,0x168);
+	reg32_write(0x3c240410,0x8);
+	reg32_write(0x3c240414,0xab10);
+	reg32_write(0x3c240418,0x168);
+	reg32_write(0x3c24041c,0xa);
+	reg32_write(0x3c240420,0x408);
+	reg32_write(0x3c240424,0x169);
+	reg32_write(0x3c240428,0x58);
+	reg32_write(0x3c24042c,0x0);
+	reg32_write(0x3c240430,0x68);
+	reg32_write(0x3c240434,0x0);
+	reg32_write(0x3c240438,0x408);
+	reg32_write(0x3c24043c,0x169);
+	reg32_write(0x3c240440,0x0);
+	reg32_write(0x3c240444,0x8b10);
+	reg32_write(0x3c240448,0x168);
+	reg32_write(0x3c24044c,0x0);
+	reg32_write(0x3c240450,0xab10);
+	reg32_write(0x3c240454,0x168);
+	reg32_write(0x3c240458,0x0);
+	reg32_write(0x3c24045c,0x1d8);
+	reg32_write(0x3c240460,0x169);
+	reg32_write(0x3c240464,0x80);
+	reg32_write(0x3c240468,0x790);
+	reg32_write(0x3c24046c,0x16a);
+	reg32_write(0x3c240470,0x18);
+	reg32_write(0x3c240474,0x7aa);
+	reg32_write(0x3c240478,0x6a);
+	reg32_write(0x3c24047c,0xa);
+	reg32_write(0x3c240480,0x0);
+	reg32_write(0x3c240484,0x1e9);
+	reg32_write(0x3c240488,0x8);
+	reg32_write(0x3c24048c,0x8080);
+	reg32_write(0x3c240490,0x108);
+	reg32_write(0x3c240494,0xf);
+	reg32_write(0x3c240498,0x408);
+	reg32_write(0x3c24049c,0x169);
+	reg32_write(0x3c2404a0,0xc);
+	reg32_write(0x3c2404a4,0x0);
+	reg32_write(0x3c2404a8,0x68);
+	reg32_write(0x3c2404ac,0x9);
+	reg32_write(0x3c2404b0,0x0);
+	reg32_write(0x3c2404b4,0x1a9);
+	reg32_write(0x3c2404b8,0x0);
+	reg32_write(0x3c2404bc,0x408);
+	reg32_write(0x3c2404c0,0x169);
+	reg32_write(0x3c2404c4,0x0);
+	reg32_write(0x3c2404c8,0x8080);
+	reg32_write(0x3c2404cc,0x108);
+	reg32_write(0x3c2404d0,0x8);
+	reg32_write(0x3c2404d4,0x7aa);
+	reg32_write(0x3c2404d8,0x6a);
+	reg32_write(0x3c2404dc,0x0);
+	reg32_write(0x3c2404e0,0x8568);
+	reg32_write(0x3c2404e4,0x108);
+	reg32_write(0x3c2404e8,0xb7);
+	reg32_write(0x3c2404ec,0x790);
+	reg32_write(0x3c2404f0,0x16a);
+	reg32_write(0x3c2404f4,0x1f);
+	reg32_write(0x3c2404f8,0x0);
+	reg32_write(0x3c2404fc,0x68);
+	reg32_write(0x3c240500,0x8);
+	reg32_write(0x3c240504,0x8558);
+	reg32_write(0x3c240508,0x168);
+	reg32_write(0x3c24050c,0xf);
+	reg32_write(0x3c240510,0x408);
+	reg32_write(0x3c240514,0x169);
+	reg32_write(0x3c240518,0xc);
+	reg32_write(0x3c24051c,0x0);
+	reg32_write(0x3c240520,0x68);
+	reg32_write(0x3c240524,0x0);
+	reg32_write(0x3c240528,0x408);
+	reg32_write(0x3c24052c,0x169);
+	reg32_write(0x3c240530,0x0);
+	reg32_write(0x3c240534,0x8558);
+	reg32_write(0x3c240538,0x168);
+	reg32_write(0x3c24053c,0x8);
+	reg32_write(0x3c240540,0x3c8);
+	reg32_write(0x3c240544,0x1a9);
+	reg32_write(0x3c240548,0x3);
+	reg32_write(0x3c24054c,0x370);
+	reg32_write(0x3c240550,0x129);
+	reg32_write(0x3c240554,0x20);
+	reg32_write(0x3c240558,0x2aa);
+	reg32_write(0x3c24055c,0x9);
+	reg32_write(0x3c240560,0x0);
+	reg32_write(0x3c240564,0x400);
+	reg32_write(0x3c240568,0x10e);
+	reg32_write(0x3c24056c,0x8);
+	reg32_write(0x3c240570,0xe8);
+	reg32_write(0x3c240574,0x109);
+	reg32_write(0x3c240578,0x0);
+	reg32_write(0x3c24057c,0x8140);
+	reg32_write(0x3c240580,0x10c);
+	reg32_write(0x3c240584,0x10);
+	reg32_write(0x3c240588,0x8138);
+	reg32_write(0x3c24058c,0x10c);
+	reg32_write(0x3c240590,0x8);
+	reg32_write(0x3c240594,0x7c8);
+	reg32_write(0x3c240598,0x101);
+	reg32_write(0x3c24059c,0x8);
+	reg32_write(0x3c2405a0,0x0);
+	reg32_write(0x3c2405a4,0x8);
+	reg32_write(0x3c2405a8,0x8);
+	reg32_write(0x3c2405ac,0x448);
+	reg32_write(0x3c2405b0,0x109);
+	reg32_write(0x3c2405b4,0xf);
+	reg32_write(0x3c2405b8,0x7c0);
+	reg32_write(0x3c2405bc,0x109);
+	reg32_write(0x3c2405c0,0x0);
+	reg32_write(0x3c2405c4,0xe8);
+	reg32_write(0x3c2405c8,0x109);
+	reg32_write(0x3c2405cc,0x47);
+	reg32_write(0x3c2405d0,0x630);
+	reg32_write(0x3c2405d4,0x109);
+	reg32_write(0x3c2405d8,0x8);
+	reg32_write(0x3c2405dc,0x618);
+	reg32_write(0x3c2405e0,0x109);
+	reg32_write(0x3c2405e4,0x8);
+	reg32_write(0x3c2405e8,0xe0);
+	reg32_write(0x3c2405ec,0x109);
+	reg32_write(0x3c2405f0,0x0);
+	reg32_write(0x3c2405f4,0x7c8);
+	reg32_write(0x3c2405f8,0x109);
+	reg32_write(0x3c2405fc,0x8);
+	reg32_write(0x3c240600,0x8140);
+	reg32_write(0x3c240604,0x10c);
+	reg32_write(0x3c240608,0x0);
+	reg32_write(0x3c24060c,0x1);
+	reg32_write(0x3c240610,0x8);
+	reg32_write(0x3c240614,0x8);
+	reg32_write(0x3c240618,0x4);
+	reg32_write(0x3c24061c,0x8);
+	reg32_write(0x3c240620,0x8);
+	reg32_write(0x3c240624,0x7c8);
+	reg32_write(0x3c240628,0x101);
+	reg32_write(0x3c240018,0x0);
+	reg32_write(0x3c24001c,0x0);
+	reg32_write(0x3c240020,0x8);
+	reg32_write(0x3c240024,0x0);
+	reg32_write(0x3c240028,0x0);
+	reg32_write(0x3c24002c,0x0);
+	reg32_write(0x3c34039c,0x400);
+	reg32_write(0x3c24005c,0x0);
+	reg32_write(0x3c24007c,0x2a);
+	reg32_write(0x3c240098,0x6a);
+	reg32_write(0x3c100340,0x0);
+	reg32_write(0x3c100344,0x101);
+	reg32_write(0x3c100348,0x105);
+	reg32_write(0x3c10034c,0x107);
+	reg32_write(0x3c100350,0x10f);
+	reg32_write(0x3c100354,0x202);
+	reg32_write(0x3c100358,0x20a);
+	reg32_write(0x3c10035c,0x20b);
+	reg32_write(0x3c0800e8,0x2);
+	reg32_write(0x3c08002c,0x65);
+	reg32_write(0x3c080030,0xc9);
+	reg32_write(0x3c080034,0x7d1);
+	reg32_write(0x3c080038,0x2c);
+	reg32_write(0x3c48002c,0x65);
+	reg32_write(0x3c480030,0xc9);
+	reg32_write(0x3c480034,0x7d1);
+	reg32_write(0x3c480038,0x2c);
+	reg32_write(0x3c88002c,0x65);
+	reg32_write(0x3c880030,0xc9);
+	reg32_write(0x3c880034,0x7d1);
+	reg32_write(0x3c880038,0x2c);
+	reg32_write(0x3c240030,0x0);
+	reg32_write(0x3c240034,0x173);
+	reg32_write(0x3c240038,0x60);
+	reg32_write(0x3c24003c,0x6110);
+	reg32_write(0x3c240040,0x2152);
+	reg32_write(0x3c240044,0xdfbd);
+	reg32_write(0x3c240048,0x60);
+	reg32_write(0x3c24004c,0x6152);
+	reg32_write(0x3c080040,0x5a);
+	reg32_write(0x3c080044,0x3);
+	reg32_write(0x3c480040,0x5a);
+	reg32_write(0x3c480044,0x3);
+	reg32_write(0x3c880040,0x5a);
+	reg32_write(0x3c880044,0x3);
+	reg32_write(0x3c100200,0xe0);
+	reg32_write(0x3c100204,0x12);
+	reg32_write(0x3c100208,0xe0);
+	reg32_write(0x3c10020c,0x12);
+	reg32_write(0x3c100210,0xe0);
+	reg32_write(0x3c100214,0x12);
+	reg32_write(0x3c500200,0xe0);
+	reg32_write(0x3c500204,0x12);
+	reg32_write(0x3c500208,0xe0);
+	reg32_write(0x3c50020c,0x12);
+	reg32_write(0x3c500210,0xe0);
+	reg32_write(0x3c500214,0x12);
+	reg32_write(0x3c900200,0xe0);
+	reg32_write(0x3c900204,0x12);
+	reg32_write(0x3c900208,0xe0);
+	reg32_write(0x3c90020c,0x12);
+	reg32_write(0x3c900210,0xe0);
+	reg32_write(0x3c900214,0x12);
+	reg32_write(0x3c1003f4,0xf);
+	reg32_write(0x3c040044,0x1);
+	reg32_write(0x3c040048,0x1);
+	reg32_write(0x3c04004c,0x180);
+	reg32_write(0x3c040060,0x1);
+	reg32_write(0x3c040008,0x6209);
+	reg32_write(0x3c0402c8,0x1);
+	reg32_write(0x3c0406d0,0x1);
+	reg32_write(0x3c040ad0,0x1);
+	reg32_write(0x3c040ed0,0x1);
+	reg32_write(0x3c0412d0,0x1);
+	reg32_write(0x3c0416d0,0x1);
+	reg32_write(0x3c041ad0,0x1);
+	reg32_write(0x3c041ed0,0x1);
+	reg32_write(0x3c0422d0,0x1);
+	reg32_write(0x3c044044,0x1);
+	reg32_write(0x3c044048,0x1);
+	reg32_write(0x3c04404c,0x180);
+	reg32_write(0x3c044060,0x1);
+	reg32_write(0x3c044008,0x6209);
+	reg32_write(0x3c0442c8,0x1);
+	reg32_write(0x3c0446d0,0x1);
+	reg32_write(0x3c044ad0,0x1);
+	reg32_write(0x3c044ed0,0x1);
+	reg32_write(0x3c0452d0,0x1);
+	reg32_write(0x3c0456d0,0x1);
+	reg32_write(0x3c045ad0,0x1);
+	reg32_write(0x3c045ed0,0x1);
+	reg32_write(0x3c0462d0,0x1);
+	reg32_write(0x3c048044,0x1);
+	reg32_write(0x3c048048,0x1);
+	reg32_write(0x3c04804c,0x180);
+	reg32_write(0x3c048060,0x1);
+	reg32_write(0x3c048008,0x6209);
+	reg32_write(0x3c0482c8,0x1);
+	reg32_write(0x3c0486d0,0x1);
+	reg32_write(0x3c048ad0,0x1);
+	reg32_write(0x3c048ed0,0x1);
+	reg32_write(0x3c0492d0,0x1);
+	reg32_write(0x3c0496d0,0x1);
+	reg32_write(0x3c049ad0,0x1);
+	reg32_write(0x3c049ed0,0x1);
+	reg32_write(0x3c04a2d0,0x1);
+	reg32_write(0x3c04c044,0x1);
+	reg32_write(0x3c04c048,0x1);
+	reg32_write(0x3c04c04c,0x180);
+	reg32_write(0x3c04c060,0x1);
+	reg32_write(0x3c04c008,0x6209);
+	reg32_write(0x3c04c2c8,0x1);
+	reg32_write(0x3c04c6d0,0x1);
+	reg32_write(0x3c04cad0,0x1);
+	reg32_write(0x3c04ced0,0x1);
+	reg32_write(0x3c04d2d0,0x1);
+	reg32_write(0x3c04d6d0,0x1);
+	reg32_write(0x3c04dad0,0x1);
+	reg32_write(0x3c04ded0,0x1);
+	reg32_write(0x3c04e2d0,0x1);
+	reg32_write(0x3c0800e8,0x2);
+	reg32_write(0x3c300200,0x2);
+	//customer Post Train
+	reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x00020010, 0x0000006a);
+	reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x0002001d, 0x00000001);
+	/*
+	 * CalBusy.0 =1, indicates the calibrator is actively calibrating.
+	 * Wait Calibrating done.
+	 */
+	tmp_t = 1;
+	while(tmp_t) {
+		tmp = reg32_read(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x20097);
+		tmp_t = tmp & 0x01;
+	}
+	reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0xd0000, 0x0);
+	reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x2006e, 0x0);
+	//disable APB bus to access DDRPHY RAM
+	reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0xd0000, 0x1);
+}
\ No newline at end of file
diff --git a/arch/arm/boards/nxp-imx8mq-evk/flash-header-imx8mq-evk.imxcfg b/arch/arm/boards/nxp-imx8mq-evk/flash-header-imx8mq-evk.imxcfg
new file mode 100644
index 000000000..a12c28fce
--- /dev/null
+++ b/arch/arm/boards/nxp-imx8mq-evk/flash-header-imx8mq-evk.imxcfg
@@ -0,0 +1,4 @@
+soc imx8mq
+
+loadaddr 0x007E1000
+dcdofs 0x400
diff --git a/arch/arm/boards/nxp-imx8mq-evk/lowlevel.c b/arch/arm/boards/nxp-imx8mq-evk/lowlevel.c
new file mode 100644
index 000000000..1ed918ee0
--- /dev/null
+++ b/arch/arm/boards/nxp-imx8mq-evk/lowlevel.c
@@ -0,0 +1,81 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; version 2.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+#include <common.h>
+#include <linux/sizes.h>
+#include <mach/generic.h>
+#include <asm/barebox-arm-head.h>
+#include <asm/barebox-arm.h>
+#include <mach/imx8-ccm-regs.h>
+#include <mach/iomux-mx8.h>
+#include <mach/imx8-ddrc.h>
+#include <mach/xload.h>
+#include <io.h>
+#include <debug_ll.h>
+#include <asm/cache.h>
+#include <asm/sections.h>
+#include <asm/mmu.h>
+
+#include "ddr.h"
+
+extern char __dtb_imx8mq_evk_start[];
+
+#define UART_PAD_CTRL	MUX_PAD_CTRL(PAD_CTL_DSE_3P3V_45_OHM)
+
+static void setup_uart(void)
+{
+	void __iomem *iomux = IOMEM(MX8MQ_IOMUXC_BASE_ADDR);
+	void __iomem *ccm   = IOMEM(MX8MQ_CCM_BASE_ADDR);
+
+	writel(CCM_CCGR_SETTINGn_NEEDED(0),
+	       ccm + CCM_CCGRn_CLR(CCM_CCGR_UART1));
+	writel(CCM_TARGET_ROOTn_ENABLE | UART1_CLK_ROOT__25M_REF_CLK,
+	       ccm + CCM_TARGET_ROOTn(UART1_CLK_ROOT));
+	writel(CCM_CCGR_SETTINGn_NEEDED(0),
+	       ccm + CCM_CCGRn_SET(CCM_CCGR_UART1));
+
+	imx_setup_pad(iomux, IMX8MQ_PAD_UART1_TXD__UART1_TX | UART_PAD_CTRL);
+
+	imx8_uart_setup_ll();
+
+	putc_ll('>');
+}
+
+static void nxp_imx8mq_evk_sram_setup(void)
+{
+	enum bootsource src = BOOTSOURCE_UNKNOWN;
+	int instance = BOOTSOURCE_INSTANCE_UNKNOWN;
+	int ret = -ENOTSUPP;
+
+	ddr_init();
+
+	imx8_get_boot_source(&src, &instance);
+
+	if (src == BOOTSOURCE_MMC)
+		ret = imx8_esdhc_start_image(instance);
+
+	BUG_ON(ret);
+}
+
+ENTRY_FUNCTION(start_nxp_imx8mq_evk, r0, r1, r2)
+{
+	arm_cpu_lowlevel_init();
+
+	if (IS_ENABLED(CONFIG_DEBUG_LL))
+		setup_uart();
+
+	if (get_pc() < MX8MQ_DDR_CSD1_BASE_ADDR)
+		nxp_imx8mq_evk_sram_setup();
+
+	barebox_arm_entry(MX8MQ_DDR_CSD1_BASE_ADDR,
+			  SZ_2G + SZ_1G, __dtb_imx8mq_evk_start);
+}
+
diff --git a/arch/arm/dts/Makefile b/arch/arm/dts/Makefile
index b69592e64..10fcfbf1f 100644
--- a/arch/arm/dts/Makefile
+++ b/arch/arm/dts/Makefile
@@ -86,6 +86,7 @@ pbl-dtb-$(CONFIG_MACH_SOLIDRUN_MICROSOM) += imx6dl-hummingboard.dtb.o imx6q-humm
 pbl-dtb-$(CONFIG_MACH_TECHNEXION_WANDBOARD) += imx6q-wandboard.dtb.o imx6dl-wandboard.dtb.o
 pbl-dtb-$(CONFIG_MACH_TECHNEXION_PICO_HOBBIT) += imx6ul-pico-hobbit.dtb.o
 pbl-dtb-$(CONFIG_MACH_NXP_IMX6ULL_EVK) += imx6ull-14x14-evk.dtb.o
+pbl-dtb-$(CONFIG_MACH_NXP_IMX8MQ_EVK) += imx8mq-evk.dtb.o
 pbl-dtb-$(CONFIG_MACH_TORADEX_COLIBRI_T20) += tegra20-colibri-iris.dtb.o
 pbl-dtb-$(CONFIG_MACH_TOSHIBA_AC100) += tegra20-paz00.dtb.o
 pbl-dtb-$(CONFIG_MACH_TQMA53) += imx53-mba53.dtb.o
diff --git a/arch/arm/dts/imx8mq-evk.dts b/arch/arm/dts/imx8mq-evk.dts
new file mode 100644
index 000000000..3ac13baa1
--- /dev/null
+++ b/arch/arm/dts/imx8mq-evk.dts
@@ -0,0 +1,444 @@
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
+/*
+ * Copyright 2017 NXP
+ * Copyright (C) 2017 Pengutronix, Lucas Stach <kernel@pengutronix.de>
+ */
+
+/dts-v1/;
+
+#include "imx8mq.dtsi"
+
+/ {
+	model = "NXP i.MX8MQ EVK";
+	compatible = "fsl,imx8mq-evk", "fsl,imx8mq";
+
+	chosen {
+		stdout-path = &uart1;
+	};
+
+	memory@40000000 {
+		device_type = "memory";
+		reg = <0x00000000 0x40000000 0 0xc0000000>;
+	};
+
+	reg_usdhc2_vmmc: regulator-vsd-3v3 {
+		pinctrl-names = "default";
+		pinctrl-0 = <&pinctrl_reg_usdhc2>;
+		compatible = "regulator-fixed";
+		regulator-name = "VSD_3V3";
+		regulator-min-microvolt = <3300000>;
+		regulator-max-microvolt = <3300000>;
+		gpio = <&gpio2 19 GPIO_ACTIVE_HIGH>;
+		enable-active-high;
+	};
+};
+
+&dcss {
+	status = "okay";
+};
+
+&fec1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_fec1_mdc>, <&pinctrl_fec1_mdio>,
+	            <&pinctrl_fec1_data_tx>, <&pinctrl_fec1_data_rx>,
+	            <&pinctrl_fec1_phy_reset>;
+	phy-mode = "rgmii-id";
+	status = "okay";
+};
+
+&hdmi {
+	status ="okay";
+};
+
+&i2c1 {
+	clock-frequency = <100000>;
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_i2c1>;
+	status = "okay";
+
+	pmic@8 {
+		compatible = "fsl,pfuze100";
+		reg = <0x8>;
+
+		regulators {
+			sw1a_reg: sw1ab {
+				regulator-min-microvolt = <825000>;
+				regulator-max-microvolt = <1100000>;
+			};
+
+			sw1c_reg: sw1c {
+				regulator-min-microvolt = <825000>;
+				regulator-max-microvolt = <1100000>;
+			};
+
+			sw2_reg: sw2 {
+				regulator-min-microvolt = <1100000>;
+				regulator-max-microvolt = <1100000>;
+				regulator-always-on;
+			};
+
+			sw3a_reg: sw3ab {
+				regulator-min-microvolt = <825000>;
+				regulator-max-microvolt = <1100000>;
+				regulator-always-on;
+			};
+
+			sw4_reg: sw4 {
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <1800000>;
+				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-always-on;
+			};
+
+			vref_reg: vrefddr {
+				regulator-always-on;
+			};
+
+			vgen1_reg: vgen1 {
+				regulator-min-microvolt = <800000>;
+				regulator-max-microvolt = <1550000>;
+			};
+
+			vgen2_reg: vgen2 {
+				regulator-min-microvolt = <850000>;
+				regulator-max-microvolt = <975000>;
+				regulator-always-on;
+			};
+
+			vgen3_reg: vgen3 {
+				regulator-min-microvolt = <1675000>;
+				regulator-max-microvolt = <1975000>;
+				regulator-always-on;
+			};
+
+			vgen4_reg: vgen4 {
+				regulator-min-microvolt = <1625000>;
+				regulator-max-microvolt = <1875000>;
+				regulator-always-on;
+			};
+
+			vgen5_reg: vgen5 {
+				regulator-min-microvolt = <3075000>;
+				regulator-max-microvolt = <3625000>;
+				regulator-always-on;
+			};
+
+			vgen6_reg: vgen6 {
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <3300000>;
+			};
+		};
+	};
+};
+
+&ocotp {
+	barebox,provide-mac-address = <&fec1 0x640>;
+};
+
+&uart1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_uart1>;
+	status = "okay";
+};
+
+&usb3_phy1 {
+	status = "okay";
+};
+
+&usb3_1 {
+	status = "okay";
+};
+
+&usb_dwc3_1 {
+	status = "okay";
+	dr_mode = "host";
+};
+
+&usdhc1 {
+	pinctrl-names = "default", "state_100mhz", "state_200mhz";
+	pinctrl-0 = <&pinctrl_usdhc1_cd_reset>, <&pinctrl_usdhc1_clk_strobe>,
+	            <&pinctrl_usdhc1_data>;
+	pinctrl-1 = <&pinctrl_usdhc1_cd_reset>,
+	            <&pinctrl_usdhc1_clk_strobe_100mhz>,
+	            <&pinctrl_usdhc1_data_100mhz>;
+	pinctrl-2 = <&pinctrl_usdhc1_cd_reset>,
+	            <&pinctrl_usdhc1_clk_strobe_200mhz>,
+	            <&pinctrl_usdhc1_data_200mhz>;
+	vqmmc-supply = <&sw4_reg>;
+	bus-width = <8>;
+	non-removable;
+	no-sd;
+	no-sdio;
+	status = "okay";
+};
+
+&usdhc2 {
+	pinctrl-names = "default", "state_100mhz", "state_200mhz";
+	pinctrl-0 = <&pinctrl_usdhc2_vselect>, <&pinctrl_usdhc2_clk>,
+	            <&pinctrl_usdhc2_data>;
+	pinctrl-1 = <&pinctrl_usdhc2_vselect>, <&pinctrl_usdhc2_clk_100mhz>,
+	            <&pinctrl_usdhc2_data_100mhz>;
+	pinctrl-2 = <&pinctrl_usdhc2_vselect>, <&pinctrl_usdhc2_clk_200mhz>,
+	            <&pinctrl_usdhc2_data_200mhz>;
+	cd-gpios = <&gpio2 12 GPIO_ACTIVE_LOW>;
+	vmmc-supply = <&reg_usdhc2_vmmc>;
+	status = "okay";
+};
+
+&wdog1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_wdog>;
+	fsl,ext-reset-output;
+	status = "okay";
+};
+
+&iomuxc {
+	pinctrl_fec1_mdc: fec1mdcgrp {
+		pinmux = <MX8MQ_IOMUXC_ENET_MDC_ENET1_MDC>;
+		drive-strength = <3>;
+		slew-rate = <0>;
+	};
+
+	pinctrl_fec1_mdio: fec1mdiogrp {
+		pinmux = <MX8MQ_IOMUXC_ENET_MDIO_ENET1_MDIO>;
+		drive-strength = <3>;
+		slew-rate = <0>;
+		drive-open-drain;
+	};
+
+	pinctrl_fec1_phy_reset: fec1phyresetgrp {
+		pinmux = <MX8MQ_IOMUXC_GPIO1_IO09_GPIO1_IO9>;
+		drive-strength = <1>;
+		slew-rate = <0>;
+	};
+
+	pinctrl_fec1_data_tx: fec1datatxgrp {
+		pinmux = <
+			MX8MQ_IOMUXC_ENET_TD3_ENET1_RGMII_TD3
+			MX8MQ_IOMUXC_ENET_TD2_ENET1_RGMII_TD2
+			MX8MQ_IOMUXC_ENET_TD1_ENET1_RGMII_TD1
+			MX8MQ_IOMUXC_ENET_TD0_ENET1_RGMII_TD0
+			MX8MQ_IOMUXC_ENET_TXC_ENET1_RGMII_TXC
+			MX8MQ_IOMUXC_ENET_TX_CTL_ENET1_RGMII_TX_CTL
+		>;
+		drive-strength = <7>;
+		slew-rate = <3>;
+	};
+
+	pinctrl_fec1_data_rx: fec1datarxgrp {
+		pinmux = <
+			MX8MQ_IOMUXC_ENET_RD3_ENET1_RGMII_RD3
+			MX8MQ_IOMUXC_ENET_RD2_ENET1_RGMII_RD2
+			MX8MQ_IOMUXC_ENET_RD1_ENET1_RGMII_RD1
+			MX8MQ_IOMUXC_ENET_RD0_ENET1_RGMII_RD0
+			MX8MQ_IOMUXC_ENET_RXC_ENET1_RGMII_RXC
+			MX8MQ_IOMUXC_ENET_RX_CTL_ENET1_RGMII_RX_CTL
+		>;
+		drive-strength = <1>;
+		slew-rate = <2>;
+		input-schmitt-enable;
+	};
+
+	pinctrl_i2c1: i2c1grp {
+		pinmux = <
+			MX8MQ_IOMUXC_I2C1_SCL_I2C1_SCL
+			MX8MQ_IOMUXC_I2C1_SDA_I2C1_SDA
+		>;
+		drive-strength = <7>;
+		slew-rate = <0>;
+		drive-open-drain;
+		input-enable;
+	};
+
+	pinctrl_reg_usdhc2: regusdhc2grpgpio {
+		pinmux = <MX8MQ_IOMUXC_SD2_RESET_B_GPIO2_IO19>;
+		drive-strength = <1>;
+		slew-rate = <0>;
+		bias-pull-up;
+	};
+
+	pinctrl_uart1: uart1grp {
+		pinmux = <
+			MX8MQ_IOMUXC_UART1_RXD_UART1_DCE_RX
+			MX8MQ_IOMUXC_UART1_TXD_UART1_DCE_TX
+		>;
+		drive-strength = <1>;
+		slew-rate = <0>;
+		bias-pull-up;
+	};
+
+	pinctrl_usdhc1_cd_reset: usdhc1cdgrp {
+		pinmux = <
+			MX8MQ_IOMUXC_SD2_CD_B_GPIO2_IO12
+			MX8MQ_IOMUXC_SD1_RESET_B_USDHC1_RESET_B
+			>;
+		drive-strength = <1>;
+		slew-rate = <0>;
+		bias-pull-up;
+	};
+
+	pinctrl_usdhc1_clk_strobe: usdhc1clkgrp {
+		pinmux = <
+			MX8MQ_IOMUXC_SD1_CLK_USDHC1_CLK
+			MX8MQ_IOMUXC_SD1_STROBE_USDHC1_STROBE
+			>;
+		drive-strength = <3>;
+		slew-rate = <0>;
+	};
+
+	pinctrl_usdhc1_data: usdhc1datagrp {
+		pinmux = <
+			MX8MQ_IOMUXC_SD1_CMD_USDHC1_CMD
+			MX8MQ_IOMUXC_SD1_DATA0_USDHC1_DATA0
+			MX8MQ_IOMUXC_SD1_DATA1_USDHC1_DATA1
+			MX8MQ_IOMUXC_SD1_DATA2_USDHC1_DATA2
+			MX8MQ_IOMUXC_SD1_DATA3_USDHC1_DATA3
+			MX8MQ_IOMUXC_SD1_DATA4_USDHC1_DATA4
+			MX8MQ_IOMUXC_SD1_DATA5_USDHC1_DATA5
+			MX8MQ_IOMUXC_SD1_DATA6_USDHC1_DATA6
+			MX8MQ_IOMUXC_SD1_DATA7_USDHC1_DATA7
+			>;
+		drive-strength = <3>;
+		slew-rate = <0>;
+		bias-pull-up;
+		input-schmitt-enable;
+	};
+
+	pinctrl_usdhc1_clk_strobe_100mhz: usdhc1clk100grp {
+		pinmux = <
+			MX8MQ_IOMUXC_SD1_CLK_USDHC1_CLK
+			MX8MQ_IOMUXC_SD1_STROBE_USDHC1_STROBE
+			>;
+		drive-strength = <3>;
+		slew-rate = <0>;
+	};
+
+	pinctrl_usdhc1_data_100mhz: usdhc1data100grp {
+		pinmux = <
+			MX8MQ_IOMUXC_SD1_CMD_USDHC1_CMD
+			MX8MQ_IOMUXC_SD1_DATA0_USDHC1_DATA0
+			MX8MQ_IOMUXC_SD1_DATA1_USDHC1_DATA1
+			MX8MQ_IOMUXC_SD1_DATA2_USDHC1_DATA2
+			MX8MQ_IOMUXC_SD1_DATA3_USDHC1_DATA3
+			MX8MQ_IOMUXC_SD1_DATA4_USDHC1_DATA4
+			MX8MQ_IOMUXC_SD1_DATA5_USDHC1_DATA5
+			MX8MQ_IOMUXC_SD1_DATA6_USDHC1_DATA6
+			MX8MQ_IOMUXC_SD1_DATA7_USDHC1_DATA7
+			>;
+		drive-strength = <5>;
+		slew-rate = <1>;
+		bias-pull-up;
+		input-schmitt-enable;
+	};
+
+	pinctrl_usdhc1_clk_strobe_200mhz: usdhc1clk200grp {
+		pinmux = <
+			MX8MQ_IOMUXC_SD1_CLK_USDHC1_CLK
+			MX8MQ_IOMUXC_SD1_STROBE_USDHC1_STROBE
+			>;
+		drive-strength = <7>;
+		slew-rate = <3>;
+	};
+
+	pinctrl_usdhc1_data_200mhz: usdhc1data200grp {
+		pinmux = <
+			MX8MQ_IOMUXC_SD1_CMD_USDHC1_CMD
+			MX8MQ_IOMUXC_SD1_DATA0_USDHC1_DATA0
+			MX8MQ_IOMUXC_SD1_DATA1_USDHC1_DATA1
+			MX8MQ_IOMUXC_SD1_DATA2_USDHC1_DATA2
+			MX8MQ_IOMUXC_SD1_DATA3_USDHC1_DATA3
+			MX8MQ_IOMUXC_SD1_DATA4_USDHC1_DATA4
+			MX8MQ_IOMUXC_SD1_DATA5_USDHC1_DATA5
+			MX8MQ_IOMUXC_SD1_DATA6_USDHC1_DATA6
+			MX8MQ_IOMUXC_SD1_DATA7_USDHC1_DATA7
+			>;
+		drive-strength = <7>;
+		slew-rate = <3>;
+		bias-pull-up;
+		input-schmitt-enable;
+	};
+
+	pinctrl_usdhc2_vselect: usdhc2vselectgrp {
+		pinmux = <MX8MQ_IOMUXC_GPIO1_IO04_USDHC2_VSELECT>;
+		drive-strength = <1>;
+		slew-rate = <0>;
+		bias-pull-up;
+	};
+
+	pinctrl_usdhc2_clk: usdhc2clkgrp {
+		pinmux = <MX8MQ_IOMUXC_SD2_CLK_USDHC2_CLK>;
+		drive-strength = <3>;
+		slew-rate = <0>;
+	};
+
+	pinctrl_usdhc2_data: usdhc2datagrp {
+		pinmux = <
+			MX8MQ_IOMUXC_SD2_CMD_USDHC2_CMD
+			MX8MQ_IOMUXC_SD2_DATA0_USDHC2_DATA0
+			MX8MQ_IOMUXC_SD2_DATA1_USDHC2_DATA1
+			MX8MQ_IOMUXC_SD2_DATA2_USDHC2_DATA2
+			MX8MQ_IOMUXC_SD2_DATA3_USDHC2_DATA3
+			>;
+		drive-strength = <3>;
+		slew-rate = <0>;
+		bias-pull-up;
+		input-schmitt-enable;
+	};
+
+	pinctrl_usdhc2_clk_100mhz: usdhc2clk100grp {
+		pinmux = <MX8MQ_IOMUXC_SD2_CLK_USDHC2_CLK>;
+		drive-strength = <5>;
+		slew-rate = <1>;
+	};
+
+	pinctrl_usdhc2_data_100mhz: usdhc2data100grp {
+		pinmux = <
+			MX8MQ_IOMUXC_SD2_CMD_USDHC2_CMD
+			MX8MQ_IOMUXC_SD2_DATA0_USDHC2_DATA0
+			MX8MQ_IOMUXC_SD2_DATA1_USDHC2_DATA1
+			MX8MQ_IOMUXC_SD2_DATA2_USDHC2_DATA2
+			MX8MQ_IOMUXC_SD2_DATA3_USDHC2_DATA3
+			>;
+		drive-strength = <5>;
+		slew-rate = <1>;
+		bias-pull-up;
+		input-schmitt-enable;
+	};
+
+	pinctrl_usdhc2_clk_200mhz: usdhc2clk200grp {
+		pinmux = <MX8MQ_IOMUXC_SD2_CLK_USDHC2_CLK>;
+		drive-strength = <7>;
+		slew-rate = <3>;
+	};
+
+	pinctrl_usdhc2_data_200mhz: usdhc2data200grp {
+		pinmux = <
+			MX8MQ_IOMUXC_SD2_CMD_USDHC2_CMD
+			MX8MQ_IOMUXC_SD2_DATA0_USDHC2_DATA0
+			MX8MQ_IOMUXC_SD2_DATA1_USDHC2_DATA1
+			MX8MQ_IOMUXC_SD2_DATA2_USDHC2_DATA2
+			MX8MQ_IOMUXC_SD2_DATA3_USDHC2_DATA3
+			>;
+		drive-strength = <7>;
+		slew-rate = <3>;
+		bias-pull-up;
+		input-schmitt-enable;
+	};
+
+	pinctrl_wdog: wdoggrp {
+		pinmux = <MX8MQ_IOMUXC_GPIO1_IO02_WDOG1_WDOG_B>;
+		drive-strength = <6>;
+		slew-rate = <0>;
+		bias-pull-up;
+	};
+};
diff --git a/arch/arm/mach-imx/Kconfig b/arch/arm/mach-imx/Kconfig
index dec5e387e..a743bbfda 100644
--- a/arch/arm/mach-imx/Kconfig
+++ b/arch/arm/mach-imx/Kconfig
@@ -445,6 +445,11 @@ config MACH_NXP_IMX6ULL_EVK
 	bool "NXP i.MX6ull EVK Board"
 	select ARCH_IMX6UL
 
+config MACH_NXP_IMX8MQ_EVK
+	bool "NXP i.MX8MQ EVK Board"
+	select ARCH_IMX8MQ
+	select FIRMWARE_IMX_LPDDR4_PMU_TRAIN
+
 endif
 
 # ----------------------------------------------------------
diff --git a/firmware/Kconfig b/firmware/Kconfig
index e0cc7abef..b6449644b 100644
--- a/firmware/Kconfig
+++ b/firmware/Kconfig
@@ -4,4 +4,7 @@ config EXTRA_FIRMWARE_DIR
 	string "Firmware blobs root directory"
 	default "firmware"
 
+config FIRMWARE_IMX_LPDDR4_PMU_TRAIN
+       	bool
+
 endmenu
diff --git a/firmware/Makefile b/firmware/Makefile
index 52984fd16..c82e81ae4 100644
--- a/firmware/Makefile
+++ b/firmware/Makefile
@@ -3,6 +3,12 @@
 # kbuild file for firmware/
 #
 
+firmware-$(CONFIG_FIRMWARE_IMX_LPDDR4_PMU_TRAIN) += \
+	imx/lpddr4_pmu_train_1d_dmem.bin \
+	imx/lpddr4_pmu_train_1d_imem.bin \
+	imx/lpddr4_pmu_train_2d_dmem.bin \
+	imx/lpddr4_pmu_train_2d_imem.bin
+
 # Create $(fwabs) from $(CONFIG_EXTRA_FIRMWARE_DIR) -- if it doesn't have a
 # leading /, it's relative to $(srctree).
 fwdir := $(subst $(quote),,$(CONFIG_EXTRA_FIRMWARE_DIR))
diff --git a/images/Makefile.imx b/images/Makefile.imx
index 43505b1ff..0550686a1 100644
--- a/images/Makefile.imx
+++ b/images/Makefile.imx
@@ -530,7 +530,14 @@ CFG_start_zii_vf610_dev.pblx.imximg = $(board)/zii-vf610-dev/flash-header-zii-vf
 FILE_barebox-zii-vf610-dev.img = start_zii_vf610_dev.pblx.imximg
 image-$(CONFIG_MACH_ZII_VF610_DEV) += barebox-zii-vf610-dev.img
 
+# ----------------------- i.MX7 based boards ---------------------------
 pblx-$(CONFIG_MACH_FREESCALE_MX7_SABRESD) += start_imx7d_sabresd
 CFG_start_imx7d_sabresd.pblx.imximg = $(board)/freescale-mx7-sabresd/flash-header-mx7-sabresd.imxcfg
 FILE_barebox-freescale-mx7-sabresd.img = start_imx7d_sabresd.pblx.imximg
 image-$(CONFIG_MACH_FREESCALE_MX7_SABRESD) += barebox-freescale-mx7-sabresd.img
+
+# ----------------------- i.MX8mq based boards --------------------------
+pblx-$(CONFIG_MACH_NXP_IMX8MQ_EVK) += start_nxp_imx8mq_evk
+CFG_start_nxp_imx8mq_evk.imx-sram-img = $(board)/nxp-imx8mq-evk/flash-header-imx8mq-evk.imxcfg
+FILE_barebox-nxp-imx8mq-evk.img = start_nxp_imx8mq_evk.imx-sram-img
+image-$(CONFIG_MACH_NXP_IMX8MQ_EVK) += barebox-nxp-imx8mq-evk.img
-- 
2.17.0


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

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

* [PATCH v6 10/10] ARM: Introduce imx_v8_defconfig
  2018-06-14  6:27 [PATCH v6 00/10] ARM: i.MX8MQ and EVK support Andrey Smirnov
                   ` (8 preceding siblings ...)
  2018-06-14  6:27 ` [PATCH v6 09/10] ARM: i.MX8: Add i.MX8mq EVK support Andrey Smirnov
@ 2018-06-14  6:27 ` Andrey Smirnov
  9 siblings, 0 replies; 13+ messages in thread
From: Andrey Smirnov @ 2018-06-14  6:27 UTC (permalink / raw)
  To: barebox; +Cc: Andrey Smirnov

Similar to imx_v7_defconfig, add imx_v8_defconfig as a default
configuration encompassing all ARMv8 based i.MX SoCs.

Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com>
---
 arch/arm/configs/imx_v8_defconfig | 107 ++++++++++++++++++++++++++++++
 1 file changed, 107 insertions(+)
 create mode 100644 arch/arm/configs/imx_v8_defconfig

diff --git a/arch/arm/configs/imx_v8_defconfig b/arch/arm/configs/imx_v8_defconfig
new file mode 100644
index 000000000..cc41f4975
--- /dev/null
+++ b/arch/arm/configs/imx_v8_defconfig
@@ -0,0 +1,107 @@
+CONFIG_ARCH_IMX=y
+CONFIG_IMX_MULTI_BOARDS=y
+CONFIG_MACH_NXP_IMX8MQ_EVK=y
+CONFIG_ARM_OPTIMZED_STRING_FUNCTIONS=y
+CONFIG_MMU=y
+CONFIG_MALLOC_SIZE=0x0
+CONFIG_MALLOC_TLSF=y
+CONFIG_KALLSYMS=y
+CONFIG_RELOCATABLE=y
+CONFIG_HUSH_FANCY_PROMPT=y
+CONFIG_CMDLINE_EDITING=y
+CONFIG_AUTO_COMPLETE=y
+CONFIG_MENU=y
+CONFIG_BOOTM_SHOW_TYPE=y
+CONFIG_BOOTM_VERBOSE=y
+CONFIG_BOOTM_INITRD=y
+CONFIG_BOOTM_OFTREE=y
+CONFIG_BOOTM_OFTREE_UIMAGE=y
+CONFIG_BLSPEC=y
+CONFIG_CONSOLE_ACTIVATE_NONE=y
+CONFIG_PARTITION_DISK_EFI=y
+CONFIG_DEFAULT_ENVIRONMENT_GENERIC_NEW=y
+CONFIG_RESET_SOURCE=y
+CONFIG_CMD_DMESG=y
+CONFIG_LONGHELP=y
+CONFIG_CMD_IOMEM=y
+CONFIG_CMD_IMD=y
+CONFIG_CMD_MEMINFO=y
+CONFIG_CMD_REGULATOR=y
+CONFIG_CMD_MMC_EXTCSD=y
+CONFIG_CMD_GO=y
+CONFIG_CMD_RESET=y
+CONFIG_CMD_UIMAGE=y
+CONFIG_CMD_PARTITION=y
+CONFIG_CMD_EXPORT=y
+CONFIG_CMD_LOADENV=y
+CONFIG_CMD_PRINTENV=y
+CONFIG_CMD_MAGICVAR=y
+CONFIG_CMD_MAGICVAR_HELP=y
+CONFIG_CMD_SAVEENV=y
+CONFIG_CMD_FILETYPE=y
+CONFIG_CMD_LN=y
+CONFIG_CMD_MD5SUM=y
+CONFIG_CMD_UNCOMPRESS=y
+CONFIG_CMD_LET=y
+CONFIG_CMD_MSLEEP=y
+CONFIG_CMD_READF=y
+CONFIG_CMD_SLEEP=y
+CONFIG_CMD_DHCP=y
+CONFIG_CMD_MIITOOL=y
+CONFIG_CMD_PING=y
+CONFIG_CMD_ECHO_E=y
+CONFIG_CMD_EDIT=y
+CONFIG_CMD_MENU=y
+CONFIG_CMD_MENU_MANAGEMENT=y
+CONFIG_CMD_MENUTREE=y
+CONFIG_CMD_READLINE=y
+CONFIG_CMD_TIMEOUT=y
+CONFIG_CMD_CRC=y
+CONFIG_CMD_CRC_CMP=y
+CONFIG_CMD_MEMTEST=y
+CONFIG_CMD_MM=y
+CONFIG_CMD_CLK=y
+CONFIG_CMD_DETECT=y
+CONFIG_CMD_FLASH=y
+CONFIG_CMD_GPIO=y
+CONFIG_CMD_I2C=y
+CONFIG_CMD_LED=y
+CONFIG_CMD_SPI=y
+CONFIG_CMD_LED_TRIGGER=y
+CONFIG_CMD_WD=y
+CONFIG_CMD_BAREBOX_UPDATE=y
+CONFIG_CMD_OF_NODE=y
+CONFIG_CMD_OF_PROPERTY=y
+CONFIG_CMD_OFTREE=y
+CONFIG_CMD_TIME=y
+CONFIG_NET=y
+CONFIG_NET_NETCONSOLE=y
+CONFIG_NET_RESOLV=y
+CONFIG_OFDEVICE=y
+CONFIG_OF_BAREBOX_DRIVERS=y
+CONFIG_DRIVER_NET_FEC_IMX=y
+CONFIG_DRIVER_SPI_IMX=y
+CONFIG_I2C=y
+CONFIG_I2C_IMX=y
+CONFIG_MCI=y
+CONFIG_MCI_MMC_BOOT_PARTITIONS=y
+CONFIG_MCI_IMX_ESDHC=y
+CONFIG_LED=y
+CONFIG_LED_GPIO=y
+CONFIG_LED_GPIO_OF=y
+CONFIG_LED_TRIGGERS=y
+CONFIG_EEPROM_AT25=y
+CONFIG_WATCHDOG=y
+CONFIG_WATCHDOG_IMX=y
+CONFIG_NVMEM=y
+CONFIG_IMX_OCOTP=y
+CONFIG_REGULATOR=y
+CONFIG_REGULATOR_FIXED=y
+CONFIG_FS_EXT4=y
+CONFIG_FS_TFTP=y
+CONFIG_FS_NFS=y
+CONFIG_FS_FAT=y
+CONFIG_FS_FAT_WRITE=y
+CONFIG_FS_FAT_LFN=y
+CONFIG_ZLIB=y
+CONFIG_LZO_DECOMPRESS=y
-- 
2.17.0


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

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

* Re: [PATCH v6 03/10] clock: Use udelay() to implement mdelay()
  2018-06-14  6:27 ` [PATCH v6 03/10] clock: Use udelay() to implement mdelay() Andrey Smirnov
@ 2018-06-14 10:04   ` Antony Pavlov
  2018-06-15  3:40     ` Andrey Smirnov
  0 siblings, 1 reply; 13+ messages in thread
From: Antony Pavlov @ 2018-06-14 10:04 UTC (permalink / raw)
  To: Andrey Smirnov; +Cc: barebox

On Wed, 13 Jun 2018 23:27:44 -0700
Andrey Smirnov <andrew.smirnov@gmail.com> wrote:

> Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com>
> ---
>  common/clock.c | 8 +++++---
>  1 file changed, 5 insertions(+), 3 deletions(-)
> 
> diff --git a/common/clock.c b/common/clock.c
> index f98176dd5..dab6e979f 100644
> --- a/common/clock.c
> +++ b/common/clock.c
> @@ -206,9 +206,11 @@ EXPORT_SYMBOL(udelay);
>  
>  void mdelay(unsigned long msecs)
>  {
> -	uint64_t start = get_time_ns();
> -
> -	while(!is_timeout(start, msecs * MSECOND));
> +	/*
> +	 * Parens around division below are needed to pervent ARM/EABI
                                                      ^^^^^^^  prevent?

> +	 * toolchain from emitting a call to __aeabi_uldivmod.
> +	 */
> +	udelay(msecs * (MSECOND / USECOND));
>  }
>  EXPORT_SYMBOL(mdelay);
>  
> -- 
> 2.17.0
> 
> 
> _______________________________________________
> barebox mailing list
> barebox@lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/barebox


-- 
Best regards,
  Antony Pavlov

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

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

* Re: [PATCH v6 03/10] clock: Use udelay() to implement mdelay()
  2018-06-14 10:04   ` Antony Pavlov
@ 2018-06-15  3:40     ` Andrey Smirnov
  0 siblings, 0 replies; 13+ messages in thread
From: Andrey Smirnov @ 2018-06-15  3:40 UTC (permalink / raw)
  To: Antony Pavlov; +Cc: Barebox List

On Thu, Jun 14, 2018 at 3:04 AM Antony Pavlov <antonynpavlov@gmail.com> wrote:
>
> On Wed, 13 Jun 2018 23:27:44 -0700
> Andrey Smirnov <andrew.smirnov@gmail.com> wrote:
>
> > Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com>
> > ---
> >  common/clock.c | 8 +++++---
> >  1 file changed, 5 insertions(+), 3 deletions(-)
> >
> > diff --git a/common/clock.c b/common/clock.c
> > index f98176dd5..dab6e979f 100644
> > --- a/common/clock.c
> > +++ b/common/clock.c
> > @@ -206,9 +206,11 @@ EXPORT_SYMBOL(udelay);
> >
> >  void mdelay(unsigned long msecs)
> >  {
> > -     uint64_t start = get_time_ns();
> > -
> > -     while(!is_timeout(start, msecs * MSECOND));
> > +     /*
> > +      * Parens around division below are needed to pervent ARM/EABI
>                                                       ^^^^^^^  prevent?
>

Yeah, will fix in v7.

Thanks,
Andrey Smirnov

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

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

end of thread, other threads:[~2018-06-15  3:41 UTC | newest]

Thread overview: 13+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-06-14  6:27 [PATCH v6 00/10] ARM: i.MX8MQ and EVK support Andrey Smirnov
2018-06-14  6:27 ` [PATCH v6 01/10] ARM: i.MX: ocotp: Provide missing .format_mac for i.MX8MQ Andrey Smirnov
2018-06-14  6:27 ` [PATCH v6 02/10] Port <linux/iopoll.h> from U-Boot Andrey Smirnov
2018-06-14  6:27 ` [PATCH v6 03/10] clock: Use udelay() to implement mdelay() Andrey Smirnov
2018-06-14 10:04   ` Antony Pavlov
2018-06-15  3:40     ` Andrey Smirnov
2018-06-14  6:27 ` [PATCH v6 04/10] ARM: i.MX8: Add DDRC PHY support code Andrey Smirnov
2018-06-14  6:27 ` [PATCH v6 05/10] ARM: Specify HAVE_PBL_IMAGE for CPU_64 Andrey Smirnov
2018-06-14  6:27 ` [PATCH v6 06/10] scripts: imx-image: Use a loop to create multiple header copies Andrey Smirnov
2018-06-14  6:27 ` [PATCH v6 07/10] scripts: imx-image: Share the code to write barebox header Andrey Smirnov
2018-06-14  6:27 ` [PATCH v6 08/10] scripts: imx-image: Add i.MX8MQ support Andrey Smirnov
2018-06-14  6:27 ` [PATCH v6 09/10] ARM: i.MX8: Add i.MX8mq EVK support Andrey Smirnov
2018-06-14  6:27 ` [PATCH v6 10/10] ARM: Introduce imx_v8_defconfig Andrey Smirnov

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