summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/boards/imx.rst3
-rw-r--r--Documentation/boards/imx/nxp-imx8mq-evk.rst24
-rw-r--r--Documentation/boards/imx/zii-imx8mq-dev/openocd.cfg86
-rw-r--r--Documentation/boards/imx/zii-imx8mq-dev/readme.rst24
-rw-r--r--arch/arm/boards/Makefile2
-rw-r--r--arch/arm/boards/nxp-imx8mq-evk/ddr.h8
-rw-r--r--arch/arm/boards/nxp-imx8mq-evk/lowlevel.c2
-rw-r--r--arch/arm/boards/udoo-neo/Makefile2
-rw-r--r--arch/arm/boards/udoo-neo/board.c27
-rw-r--r--arch/arm/boards/udoo-neo/flash-header-mx6sx-udoo-neo_full.imxcfg131
-rw-r--r--arch/arm/boards/udoo-neo/lowlevel.c39
-rw-r--r--arch/arm/boards/zii-imx8mq-dev/Makefile2
-rw-r--r--arch/arm/boards/zii-imx8mq-dev/board.c24
-rw-r--r--arch/arm/boards/zii-imx8mq-dev/ddr.h29
-rw-r--r--arch/arm/boards/zii-imx8mq-dev/ddr_init.c225
-rw-r--r--arch/arm/boards/zii-imx8mq-dev/ddrphy_train.c935
-rw-r--r--arch/arm/boards/zii-imx8mq-dev/flash-header-zii-imx8mq-dev.imxcfg5
-rw-r--r--arch/arm/boards/zii-imx8mq-dev/lowlevel.c211
-rw-r--r--arch/arm/configs/imx_v8_defconfig20
-rw-r--r--arch/arm/dts/Makefile4
-rw-r--r--arch/arm/dts/imx6sx-udoo-neo-full.dts4
-rw-r--r--arch/arm/dts/imx8mq-zii-ultra-rmb3.dts39
-rw-r--r--arch/arm/dts/imx8mq-zii-ultra-zest.dts13
-rw-r--r--arch/arm/dts/imx8mq-zii-ultra.dtsi453
-rw-r--r--arch/arm/lib64/barebox.lds.S12
-rw-r--r--arch/arm/mach-imx/Kconfig13
-rw-r--r--arch/arm/mach-imx/imx-bbu-internal.c5
-rw-r--r--arch/arm/mach-imx/include/mach/bbu.h9
-rw-r--r--arch/arm/mach-imx/include/mach/esdctl.h1
-rw-r--r--arch/arm/mach-imx/include/mach/imx8mq.h35
-rw-r--r--drivers/Kconfig2
-rw-r--r--drivers/Makefile1
-rw-r--r--drivers/base/Kconfig3
-rw-r--r--drivers/base/Makefile4
-rw-r--r--drivers/base/driver.c5
-rw-r--r--drivers/base/platform.c7
-rw-r--r--drivers/base/power.c249
-rw-r--r--drivers/net/fec_imx.c7
-rw-r--r--drivers/pci/Kconfig4
-rw-r--r--drivers/pci/pci-imx6.c382
-rw-r--r--drivers/pci/pcie-designware-host.c6
-rw-r--r--drivers/regulator/Kconfig8
-rw-r--r--drivers/regulator/Makefile5
-rw-r--r--drivers/regulator/anatop-regulator.c162
-rw-r--r--drivers/regulator/bcm2835.c6
-rw-r--r--drivers/regulator/core.c59
-rw-r--r--drivers/regulator/fixed.c6
-rw-r--r--drivers/regulator/helpers.c186
-rw-r--r--drivers/reset/Kconfig11
-rw-r--r--drivers/reset/Makefile1
-rw-r--r--drivers/reset/core.c8
-rw-r--r--drivers/reset/reset-imx7.c295
-rw-r--r--drivers/reset/reset-socfpga.c2
-rw-r--r--drivers/soc/imx/Kconfig9
-rw-r--r--drivers/soc/imx/Makefile1
-rw-r--r--drivers/soc/imx/gpcv2.c498
-rw-r--r--firmware/Makefile10
-rw-r--r--firmware/README7
-rwxr-xr-xfirmware/imx/imx8m-bl31.binbin46744 -> 0 bytes
-rw-r--r--images/Makefile.imx10
-rw-r--r--include/dt-bindings/reset/imx8mq-reset.h64
-rw-r--r--include/linux/reset-controller.h2
-rw-r--r--include/pm_domain.h82
-rw-r--r--include/regulator.h41
-rw-r--r--scripts/imx/imx-image.c40
65 files changed, 4403 insertions, 167 deletions
diff --git a/Documentation/boards/imx.rst b/Documentation/boards/imx.rst
index 2e6a30fd2f..27d0123c87 100644
--- a/Documentation/boards/imx.rst
+++ b/Documentation/boards/imx.rst
@@ -201,6 +201,7 @@ or ``imx_defconfig`` instead.
.. toctree::
:glob:
- :maxdepth: 1
+ :maxdepth: 2
imx/*
+ imx/*/*
diff --git a/Documentation/boards/imx/nxp-imx8mq-evk.rst b/Documentation/boards/imx/nxp-imx8mq-evk.rst
index dfe004e0e4..8bad9455a5 100644
--- a/Documentation/boards/imx/nxp-imx8mq-evk.rst
+++ b/Documentation/boards/imx/nxp-imx8mq-evk.rst
@@ -8,17 +8,17 @@ Board comes with:
Not including booting via serial, the device can boot from either SD or eMMC.
-Downloading DDR PHY Firmware
-----------------------------
+Downloading DDR PHY and HDMI/eDP 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
them 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
+ wget https://www.nxp.com/lgfiles/NMG/MAD/YOCTO/firmware-imx-8.0.bin
+ chmod +x firmware-imx-8.0.bin
+ ./firmware-imx-8.0.bin
Executing that file should produce a EULA acceptance dialog as well as
result in the following files:
@@ -36,8 +36,18 @@ As a last step of this process those files need to be placed in
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}; \
+ cp firmware-imx-8.0/firmware/ddr/synopsys/${f} \
+ firmware/${f}; \
+ done
+
+You will also need to copy the HDMITX controller firmware in order to
+use the HDMI and/or eDP display output::
+
+ for f in signed_dp_imx8m.bin \
+ signed_hdmi_imx8m.bin; \
+ do \
+ cp firmware-imx-8.0/firmware/hdmi/cadence/${f} \
+ firmware/${f}; \
done
DDR Configuration Code
diff --git a/Documentation/boards/imx/zii-imx8mq-dev/openocd.cfg b/Documentation/boards/imx/zii-imx8mq-dev/openocd.cfg
new file mode 100644
index 0000000000..31f94227e6
--- /dev/null
+++ b/Documentation/boards/imx/zii-imx8mq-dev/openocd.cfg
@@ -0,0 +1,86 @@
+interface ftdi
+ftdi_vid_pid 0x0403 0x6011
+
+ftdi_layout_init 0x0038 0x003b
+ftdi_layout_signal nSRST -data 0x0010
+ftdi_layout_signal LED -data 0x0020
+
+# Board has a standard ARM-20 JTAG connector with
+# nSRST available.
+reset_config srst_only srst_push_pull connect_deassert_srst
+
+# select JTAG
+transport select jtag
+
+# set a slow default JTAG clock, can be overridden later
+adapter_khz 1000
+
+# delay after SRST goes inactive
+adapter_nsrst_delay 70
+
+# board has an i.MX8MQ with 4 Cortex-A53 cores
+set CHIPNAME imx8mq
+set CHIPCORES 4
+
+# source SoC configuration
+source [find target/imx8m.cfg]
+source [find mem_helper.tcl]
+
+proc ddr_init { } {
+ #
+ # We use the same start address as is configured in our i.MX boot
+ # header (address originally taken from U-Boot).
+ #
+ set IMX8MQ_TCM_BASE_ADDR 0x007e1000
+ set IMX8MQ_TCM_MAX_SIZE 0x3f000
+ #
+ # Header word at offset 0x28 is not used on AArch64 and is just
+ # filled with placeholder value 0xffff_ffff, see
+ # arch/arm/include/asm/barebox-arm-head.h for more details
+ #
+ set RDU3_TCM_MAIC_LOCATION [expr $IMX8MQ_TCM_BASE_ADDR + 0x28]
+ set RDU3_TCM_MAGIC_REQUEST 0xdeadbeef
+ set RDU3_TCM_MAGIC_REPLY 0xbaadf00d
+
+ echo "==== Uploading DDR helper ===="
+
+ halt
+ load_image images/start_zii_imx8mq_dev.pblb \
+ $IMX8MQ_TCM_BASE_ADDR \
+ bin \
+ $IMX8MQ_TCM_BASE_ADDR \
+ $IMX8MQ_TCM_MAX_SIZE
+
+ echo "==== Running DDR helper ===="
+
+ mww phys $RDU3_TCM_MAIC_LOCATION $RDU3_TCM_MAGIC_REQUEST
+ resume $IMX8MQ_TCM_BASE_ADDR
+
+ echo "==== Waiting for DDR helper to finish ===="
+
+ if {[catch {wait_halt} errmsg] ||
+ [mrw $RDU3_TCM_MAIC_LOCATION] != $RDU3_TCM_MAGIC_REPLY} {
+ echo "==== DDR initialization FAILED ===="
+ } else {
+ echo "==== DDR is ready ===="
+ }
+}
+
+proc start_barebox {} {
+ #
+ # We have to place our image at MX8MQ_ATF_BL33_BASE_ADDR in order
+ # to be able to initialize ATF firmware since that's where it
+ # expects entry point to BL33 would be
+ #
+ set MX8MQ_ATF_BL33_BASE_ADDR 0x40200000
+
+ echo "==== Starting Barebox ===="
+ load_image images/start_zii_imx8mq_dev.pblb $MX8MQ_ATF_BL33_BASE_ADDR bin
+ resume $MX8MQ_ATF_BL33_BASE_ADDR
+}
+
+# proc board_init { } {
+# ddr_init
+# }
+
+# ${_TARGETNAME}.0 configure -event reset-init { board_init }
diff --git a/Documentation/boards/imx/zii-imx8mq-dev/readme.rst b/Documentation/boards/imx/zii-imx8mq-dev/readme.rst
new file mode 100644
index 0000000000..dc031e4af4
--- /dev/null
+++ b/Documentation/boards/imx/zii-imx8mq-dev/readme.rst
@@ -0,0 +1,24 @@
+ZII i.MX8MQ Based Boards
+========================
+
+Building Barebox
+----------------
+
+To build Barebox of ZII i.MX8MQ based board do the following:
+
+.. code-block:: sh
+
+ make ARCH=arm CROSS_COMPILE=<AArch64 toolchain prefix> mrproper
+ make ARCH=arm CROSS_COMPILE=<AArch64 toolchain prefix> imx_v8_defconfig
+ make ARCH=arm CROSS_COMPILE=<AArch64 toolchain prefix>
+
+Uploading Barebox via JTAG
+--------------------------
+
+Barebox can be bootstrapped via JTAG using OpenOCD (latest master) as
+follows:
+
+.. code-block:: sh
+
+ cd barebox
+ openocd -f Documentation/boards/imx/zii-imx8mq-dev/openocd.cfg --command "init; ddr_init; start_barebox"
diff --git a/arch/arm/boards/Makefile b/arch/arm/boards/Makefile
index ab5191fe04..3cea2e0e5d 100644
--- a/arch/arm/boards/Makefile
+++ b/arch/arm/boards/Makefile
@@ -139,6 +139,7 @@ obj-$(CONFIG_MACH_TX51) += karo-tx51/
obj-$(CONFIG_MACH_TX53) += karo-tx53/
obj-$(CONFIG_MACH_TX6X) += karo-tx6x/
obj-$(CONFIG_MACH_UDOO) += udoo/
+obj-$(CONFIG_MACH_UDOO_NEO) += udoo-neo/
obj-$(CONFIG_MACH_USB_A9260) += usb-a926x/
obj-$(CONFIG_MACH_USB_A9263) += usb-a926x/
obj-$(CONFIG_MACH_USB_A9G20) += usb-a926x/
@@ -156,6 +157,7 @@ obj-$(CONFIG_MACH_VF610_TWR) += freescale-vf610-twr/
obj-$(CONFIG_MACH_XILINX_ZCU104) += xilinx-zcu104/
obj-$(CONFIG_MACH_ZII_RDU1) += zii-imx51-rdu1/
obj-$(CONFIG_MACH_ZII_RDU2) += zii-imx6q-rdu2/
+obj-$(CONFIG_MACH_ZII_IMX8MQ_DEV) += zii-imx8mq-dev/
obj-$(CONFIG_MACH_ZII_VF610_DEV) += zii-vf610-dev/
obj-$(CONFIG_MACH_ZII_IMX7D_RPU2) += zii-imx7d-rpu2/
obj-$(CONFIG_MACH_WAGO_PFC_AM35XX) += wago-pfc-am35xx/
diff --git a/arch/arm/boards/nxp-imx8mq-evk/ddr.h b/arch/arm/boards/nxp-imx8mq-evk/ddr.h
index 8f494ae7a2..65115dba1e 100644
--- a/arch/arm/boards/nxp-imx8mq-evk/ddr.h
+++ b/arch/arm/boards/nxp-imx8mq-evk/ddr.h
@@ -21,9 +21,9 @@
void nxp_imx8mq_evk_ddr_init(void);
void nxp_imx8mq_evk_ddr_cfg_phy(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
+#define FW_1D_IMAGE lpddr4_pmu_train_1d_imem_bin, \
+ lpddr4_pmu_train_1d_dmem_bin
+#define FW_2D_IMAGE lpddr4_pmu_train_2d_imem_bin, \
+ lpddr4_pmu_train_2d_dmem_bin
diff --git a/arch/arm/boards/nxp-imx8mq-evk/lowlevel.c b/arch/arm/boards/nxp-imx8mq-evk/lowlevel.c
index 1dff4b4d31..ffbe14836f 100644
--- a/arch/arm/boards/nxp-imx8mq-evk/lowlevel.c
+++ b/arch/arm/boards/nxp-imx8mq-evk/lowlevel.c
@@ -115,7 +115,7 @@ ENTRY_FUNCTION(start_nxp_imx8mq_evk, r0, r1, r2)
const u8 *bl31;
size_t bl31_size;
- get_builtin_firmware(imx_imx8m_bl31_bin, &bl31, &bl31_size);
+ get_builtin_firmware(imx8mq_bl31_bin, &bl31, &bl31_size);
imx8mq_atf_load_bl31(bl31, bl31_size);
}
diff --git a/arch/arm/boards/udoo-neo/Makefile b/arch/arm/boards/udoo-neo/Makefile
new file mode 100644
index 0000000000..01c7a259e9
--- /dev/null
+++ b/arch/arm/boards/udoo-neo/Makefile
@@ -0,0 +1,2 @@
+obj-y += board.o
+lwl-y += lowlevel.o
diff --git a/arch/arm/boards/udoo-neo/board.c b/arch/arm/boards/udoo-neo/board.c
new file mode 100644
index 0000000000..9bf480305d
--- /dev/null
+++ b/arch/arm/boards/udoo-neo/board.c
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2014 Pengutronix, Sascha Hauer
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2, as published by the Free Software Foundation.
+ *
+ * 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 <init.h>
+#include <linux/clk.h>
+
+static int imx6sx_udoneo_coredevices_init(void)
+{
+ if (!of_machine_is_compatible("fsl,imx6sx-udoo-neo"))
+ return 0;
+
+ barebox_set_hostname("mx6sx-udooneo");
+
+ return 0;
+}
+coredevice_initcall(imx6sx_udoneo_coredevices_init);
diff --git a/arch/arm/boards/udoo-neo/flash-header-mx6sx-udoo-neo_full.imxcfg b/arch/arm/boards/udoo-neo/flash-header-mx6sx-udoo-neo_full.imxcfg
new file mode 100644
index 0000000000..39f2a8a221
--- /dev/null
+++ b/arch/arm/boards/udoo-neo/flash-header-mx6sx-udoo-neo_full.imxcfg
@@ -0,0 +1,131 @@
+/*
+ * These values are taken from:
+ * repository: https://github.com/UDOOboard/uboot-imx
+ * branch: udoo/2015.04.imx
+ * file: board/udoo/udoo_neo/udoo_neo.cfg
+ */
+
+loadaddr 0x80000000
+soc imx6
+dcdofs 0x400
+
+/* Enable all clocks */
+wm 32 0x020c4068 0xffffffff
+wm 32 0x020c406c 0xffffffff
+wm 32 0x020c4070 0xffffffff
+wm 32 0x020c4074 0xffffffff
+wm 32 0x020c4078 0xffffffff
+wm 32 0x020c407c 0xffffffff
+wm 32 0x020c4080 0xffffffff
+wm 32 0x020c4084 0xffffffff
+/********************************************/
+
+/* IOMUX */
+/* DDR IO TYPE */
+wm 32 0x020e0618 0x000c0000
+wm 32 0x020e05fc 0x00000000
+/********************************************/
+
+/* CLOCK */
+wm 32 0x020e032c 0x00000030
+/********************************************/
+
+/* ADDRESS */
+wm 32 0x020e0300 0x00000020
+wm 32 0x020e02fc 0x00000020
+wm 32 0x020e05f4 0x00000020
+/********************************************/
+
+/* CONTROL */
+wm 32 0x020e0340 0x00000020
+
+wm 32 0x020e0320 0x00000000
+wm 32 0x020e0310 0x00000020
+wm 32 0x020e0314 0x00000020
+wm 32 0x020e0614 0x00000020
+/********************************************/
+
+/* DATA STROBE */
+wm 32 0x020e05f8 0x00020000
+wm 32 0x020e0330 0x00000028
+wm 32 0x020e0334 0x00000028
+wm 32 0x020e0338 0x00000028
+wm 32 0x020e033c 0x00000028
+/********************************************/
+
+/* DATA */
+wm 32 0x020e0608 0x00020000
+wm 32 0x020e060c 0x00000028
+wm 32 0x020e0610 0x00000028
+wm 32 0x020e061c 0x00000028
+wm 32 0x020e0620 0x00000028
+wm 32 0x020e02ec 0x00000028
+wm 32 0x020e02f0 0x00000028
+wm 32 0x020e02f4 0x00000028
+wm 32 0x020e02f8 0x00000028
+/********************************************/
+
+/* Calibrations */
+/* ZQ */
+wm 32 0x021b0800 0xa1390003
+/********************************************/
+
+/* write leveling */
+wm 32 0x021b080c 0x000E000B
+wm 32 0x021b0810 0x000E0010
+/********************************************/
+
+/* DQS Read Gate */
+wm 32 0x021b083c 0x41600158
+wm 32 0x021b0840 0x01500140
+/********************************************/
+
+/* Read/Write Delay */
+wm 32 0x021b0848 0x3A383E3E
+wm 32 0x021b0850 0x3A383C38
+/********************************************/
+
+/* read data bit delay */
+wm 32 0x021b081c 0x33333333
+wm 32 0x021b0820 0x33333333
+wm 32 0x021b0824 0x33333333
+wm 32 0x021b0828 0x33333333
+/********************************************/
+
+/* Complete calibration by forced measurment */
+wm 32 0x021b08b8 0x00000800
+/********************************************/
+
+/* MMDC init */
+/* in DDR3, 64-bit mode, only MMDC0 is initiated */
+wm 32 0x021b0004 0x0002002d
+wm 32 0x021b0008 0x00333030
+wm 32 0x021b000c 0x676b52f3
+wm 32 0x021b0010 0xb66d8b63
+wm 32 0x021b0014 0x01ff00db
+wm 32 0x021b0018 0x00011740
+wm 32 0x021b001c 0x00008000
+wm 32 0x021b002c 0x000026d2
+wm 32 0x021b0030 0x006b1023
+wm 32 0x021b0040 0x0000005f
+wm 32 0x021b0000 0x83190000
+/********************************************/
+
+/* Initialize MT41K256M16HA-125 */
+/* MR2 */
+wm 32 0x021b001c 0x04008032
+/* MR3 */
+wm 32 0x021b001c 0x00008033
+/* MR1 */
+wm 32 0x021b001c 0x00048031
+/* MR0 */
+wm 32 0x021b001c 0x05208030
+/* DDR device ZQ calibration */
+wm 32 0x021b001c 0x04008040
+/********************************************/
+
+/* final DDR setup, before operation start */
+wm 32 0x021b0020 0x00000800
+wm 32 0x021b0818 0x00011117
+wm 32 0x021b001c 0x00000000
+/********************************************/
diff --git a/arch/arm/boards/udoo-neo/lowlevel.c b/arch/arm/boards/udoo-neo/lowlevel.c
new file mode 100644
index 0000000000..bb6b7d8332
--- /dev/null
+++ b/arch/arm/boards/udoo-neo/lowlevel.c
@@ -0,0 +1,39 @@
+#include <debug_ll.h>
+#include <common.h>
+#include <linux/sizes.h>
+#include <mach/generic.h>
+#include <asm/barebox-arm-head.h>
+#include <asm/barebox-arm.h>
+#include <mach/esdctl.h>
+
+static inline void setup_uart(void)
+{
+ void __iomem *iomuxbase = (void *)MX6_IOMUXC_BASE_ADDR;
+
+ imx6_ungate_all_peripherals();
+
+ writel(0x0, iomuxbase + 0x24);
+ writel(0x1b0b1, iomuxbase + 0x036C);
+ writel(0x0, iomuxbase + 0x28);
+ writel(0x1b0b1, iomuxbase + 0x0370);
+
+ imx6_uart_setup_ll();
+
+ putc_ll('>');
+}
+
+extern char __dtb_imx6sx_udoo_neo_full_start[];
+
+ENTRY_FUNCTION(start_imx6sx_udoo_neo, r0, r1, r2)
+{
+ void *fdt;
+
+ imx6_cpu_lowlevel_init();
+
+ if (IS_ENABLED(CONFIG_DEBUG_LL))
+ setup_uart();
+
+ fdt = __dtb_imx6sx_udoo_neo_full_start + get_runtime_offset();
+
+ imx6sx_barebox_entry(fdt);
+}
diff --git a/arch/arm/boards/zii-imx8mq-dev/Makefile b/arch/arm/boards/zii-imx8mq-dev/Makefile
new file mode 100644
index 0000000000..2995f06f0f
--- /dev/null
+++ b/arch/arm/boards/zii-imx8mq-dev/Makefile
@@ -0,0 +1,2 @@
+obj-y += board.o
+lwl-y += lowlevel.o ddr_init.o ddrphy_train.o
diff --git a/arch/arm/boards/zii-imx8mq-dev/board.c b/arch/arm/boards/zii-imx8mq-dev/board.c
new file mode 100644
index 0000000000..94e71f58ce
--- /dev/null
+++ b/arch/arm/boards/zii-imx8mq-dev/board.c
@@ -0,0 +1,24 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2019 Zodiac Inflight Innovation
+ * Author: Andrey Smirnov <andrew.smirnov@gmail.com>
+ */
+
+#include <common.h>
+#include <init.h>
+#include <asm/memory.h>
+#include <linux/sizes.h>
+#include <mach/bbu.h>
+
+static int zii_imx8mq_dev_init(void)
+{
+ if (!of_machine_is_compatible("zii,imx8mq-ultra"))
+ return 0;
+
+ barebox_set_hostname("imx8mq-zii-rdu3");
+
+ imx8mq_bbu_internal_mmcboot_register_handler("eMMC", "/dev/mmc0", 0);
+
+ return 0;
+}
+device_initcall(zii_imx8mq_dev_init);
diff --git a/arch/arm/boards/zii-imx8mq-dev/ddr.h b/arch/arm/boards/zii-imx8mq-dev/ddr.h
new file mode 100644
index 0000000000..1293ad3f34
--- /dev/null
+++ b/arch/arm/boards/zii-imx8mq-dev/ddr.h
@@ -0,0 +1,29 @@
+/* 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 zii_imx8mq_rdu3_ddr_init
+#define ddr_cfg_phy zii_imx8mq_rdu3_ddr_cfg_phy
+
+void zii_imx8mq_rdu3_ddr_init(void);
+void zii_imx8mq_rdu3_ddr_cfg_phy(void);
+
+#define FW_1D_IMAGE lpddr4_pmu_train_1d_imem_bin, \
+ lpddr4_pmu_train_1d_dmem_bin
+#define FW_2D_IMAGE lpddr4_pmu_train_2d_imem_bin, \
+ lpddr4_pmu_train_2d_dmem_bin
+
+
diff --git a/arch/arm/boards/zii-imx8mq-dev/ddr_init.c b/arch/arm/boards/zii-imx8mq-dev/ddr_init.c
new file mode 100644
index 0000000000..7a955193fd
--- /dev/null
+++ b/arch/arm/boards/zii-imx8mq-dev/ddr_init.c
@@ -0,0 +1,225 @@
+/*
+ * Copyright 2017 NXP
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ *
+ * Generated code from MX8M_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,0xece580);
+ 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,0xa3080020);
+ reg32_write(0x3d400028,0x0);
+ reg32_write(0x3d400020,0x203);
+ reg32_write(0x3d400024,0x186a000);
+ reg32_write(0x3d400064,0x6100e0);
+ reg32_write(0x3d4000d0,0xc003061c);
+ reg32_write(0x3d4000d4,0x9e0000);
+ reg32_write(0x3d4000dc,0xd4002d);
+ reg32_write(0x3d4000e0,0x310008);
+ reg32_write(0x3d4000e8,0x66004a);
+ reg32_write(0x3d4000ec,0x16004a);
+ reg32_write(0x3d400100,0x1a201b22);
+ reg32_write(0x3d400104,0x60633);
+ 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(0x3d400188,0x0);
+ reg32_write(0x3d400190,0x497820a);
+ reg32_write(0x3d400194,0x80303);
+ reg32_write(0x3d4001a0,0xe0400018);
+ reg32_write(0x3d4001a4,0xdf00e4);
+ reg32_write(0x3d4001a8,0x80000000);
+ reg32_write(0x3d4001b0,0x11);
+ reg32_write(0x3d4001b4,0x170a);
+ reg32_write(0x3d4001c0,0x1);
+ reg32_write(0x3d4001c4,0x1);
+ reg32_write(0x3d4000f4,0x639);
+ reg32_write(0x3d400108,0x70e1214);
+ reg32_write(0x3d400200,0x17);
+ reg32_write(0x3d40020c,0x0);
+ reg32_write(0x3d400210,0x1f1f);
+ reg32_write(0x3d400204,0x80808);
+ reg32_write(0x3d400214,0x7070707);
+ reg32_write(0x3d400218,0x7070707);
+ reg32_write(0x3d402020,0x1);
+ reg32_write(0x3d402024,0x518b00);
+ reg32_write(0x3d402050,0x20d040);
+ reg32_write(0x3d402064,0x14002f);
+ reg32_write(0x3d4020dc,0x940009);
+ reg32_write(0x3d4020e0,0x310000);
+ reg32_write(0x3d4020e8,0x66004a);
+ reg32_write(0x3d4020ec,0x16004a);
+ reg32_write(0x3d402100,0xb070508);
+ reg32_write(0x3d402104,0x3040b);
+ reg32_write(0x3d402108,0x305090c);
+ reg32_write(0x3d40210c,0x505000);
+ reg32_write(0x3d402110,0x4040204);
+ reg32_write(0x3d402114,0x2030303);
+ reg32_write(0x3d402118,0x1010004);
+ reg32_write(0x3d40211c,0x301);
+ reg32_write(0x3d402130,0x20300);
+ reg32_write(0x3d402134,0xa100002);
+ reg32_write(0x3d402138,0x31);
+ reg32_write(0x3d402144,0x220011);
+ reg32_write(0x3d402180,0xa70006);
+ reg32_write(0x3d402190,0x3858202);
+ reg32_write(0x3d402194,0x80303);
+ reg32_write(0x3d4021b4,0x502);
+ reg32_write(0x3d400244,0x0);
+ reg32_write(0x3d400250,0x29001505);
+ reg32_write(0x3d400254,0x2c);
+ reg32_write(0x3d40025c,0x5900575b);
+ reg32_write(0x3d400264,0x9);
+ reg32_write(0x3d40026c,0x2005574);
+ reg32_write(0x3d400300,0x16);
+ reg32_write(0x3d400304,0x0);
+ reg32_write(0x3d40030c,0x0);
+ reg32_write(0x3d400320,0x1);
+ reg32_write(0x3d40036c,0x11);
+ reg32_write(0x3d400400,0x111);
+ reg32_write(0x3d400404,0x10f3);
+ reg32_write(0x3d400408,0x72ff);
+ reg32_write(0x3d400490,0x1);
+ reg32_write(0x3d400494,0x1110d00);
+ reg32_write(0x3d400498,0x620790);
+ reg32_write(0x3d40049c,0x100001);
+ reg32_write(0x3d4004a0,0x41f);
+ reg32_write(0x30391000,0x8f000004);
+ reg32_write(0x30391000,0x8f000000);
+ reg32_write(0x3d400030,0xa8);
+ do{
+ tmp=reg32_read(0x3d400004);
+ if(tmp&0x223) break;
+ }while(1);
+ reg32_write(0x3d400320,0x0);
+ reg32_write(0x3d000000,0x1);
+ reg32_write(0x3d4001b0,0x10);
+ 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);
+ /* enable DDR auto-refresh mode */
+ tmp = reg32_read(DDRC_RFSHCTL3(0)) & ~0x1;
+ reg32_write(DDRC_RFSHCTL3(0), tmp);
+} \ No newline at end of file
diff --git a/arch/arm/boards/zii-imx8mq-dev/ddrphy_train.c b/arch/arm/boards/zii-imx8mq-dev/ddrphy_train.c
new file mode 100644
index 0000000000..1b30ff7257
--- /dev/null
+++ b/arch/arm/boards/zii-imx8mq-dev/ddrphy_train.c
@@ -0,0 +1,935 @@
+/*
+ * Copyright 2017 NXP
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ *
+ * Generated code from MX8M_DDR_tool
+ */
+
+#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(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(0x3c0800b8,0x2);
+ reg32_write(0x3c4800b8,0x1);
+ reg32_write(0x3c240810,0x0);
+ reg32_write(0x3c640810,0x0);
+ reg32_write(0x3c080090,0xab);
+ reg32_write(0x3c0800e8,0x0);
+ reg32_write(0x3c480090,0xab);
+ reg32_write(0x3c0800e8,0x0);
+ reg32_write(0x3c080158,0x3);
+ reg32_write(0x3c480158,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(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(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,0xa7);
+ 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(0x3c0803e8,0x1);
+ reg32_write(0x3c4803e8,0x1);
+ reg32_write(0x3c080064,0x1);
+ reg32_write(0x3c480064,0x1);
+ reg32_write(0x3c0803c0,0x0);
+ reg32_write(0x3c0803c4,0x0);
+ reg32_write(0x3c0803c8,0x4444);
+ reg32_write(0x3c0803cc,0x8888);
+ reg32_write(0x3c0803d0,0x5555);
+ 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(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 * 0x5400d,0x100);
+ 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,0x4a66);
+ reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x5401c,0x4a08);
+ reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x5401e,0x16);
+ 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,0x4a66);
+ reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x54022,0x4a08);
+ reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x54024,0x16);
+ 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,0x6600);
+ reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x54035,0x84a);
+ reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x54036,0x4a);
+ reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x54037,0x1600);
+ 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,0x6600);
+ reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x5403b,0x84a);
+ reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x5403c,0x4a);
+ reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x5403d,0x1600);
+
+ //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(0x3038a088,0x7070000);
+ reg32_write(0x3038a084,0x4030000);
+ reg32_write(0x303a00ec,0xffff);
+ tmp=reg32_read(0x303a00f8);
+ tmp |= 0x20;
+ reg32_write(0x303a00f8,tmp);
+ reg32_write(0x30360068,0xf5a406);
+ 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);
+
+ //enable APB bus to access DDRPHY RAM
+ reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0xd0000, 0x0);
+
+ reg32_write(0x3c150008,0x1);
+ reg32_write(0x3c15000c,0x29c);
+ reg32_write(0x3c150020,0x121f);
+ reg32_write(0x3c150064,0x994);
+ reg32_write(0x3c150068,0x31);
+ reg32_write(0x3c15006c,0x4d46);
+ reg32_write(0x3c150070,0x4d08);
+ reg32_write(0x3c150074,0x0);
+ reg32_write(0x3c150078,0x15);
+ reg32_write(0x3c15007c,0x994);
+ reg32_write(0x3c150080,0x31);
+ reg32_write(0x3c150084,0x4d46);
+ reg32_write(0x3c150088,0x4d08);
+ reg32_write(0x3c15008c,0x0);
+ reg32_write(0x3c150090,0x15);
+ reg32_write(0x3c1500c8,0x9400);
+ reg32_write(0x3c1500cc,0x3109);
+ reg32_write(0x3c1500d0,0x4600);
+ reg32_write(0x3c1500d4,0x84d);
+ reg32_write(0x3c1500d8,0x4d);
+ reg32_write(0x3c1500dc,0x1500);
+ reg32_write(0x3c1500e0,0x9400);
+ reg32_write(0x3c1500e4,0x3109);
+ 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,0xece580);
+ 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,0x4a66);
+ reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x5401c,0x4a08);
+ reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x5401e,0x16);
+ 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,0x4a66);
+ reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x54022,0x4a08);
+ reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x54024,0x16);
+ 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,0x6600);
+ reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x54035,0x84a);
+ reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x54036,0x4a);
+ reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x54037,0x1600);
+ 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,0x6600);
+ reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x5403b,0x84a);
+ reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x5403c,0x4a);
+ reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x5403d,0x1600);
+
+ //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(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(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(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/zii-imx8mq-dev/flash-header-zii-imx8mq-dev.imxcfg b/arch/arm/boards/zii-imx8mq-dev/flash-header-zii-imx8mq-dev.imxcfg
new file mode 100644
index 0000000000..aff8321b9a
--- /dev/null
+++ b/arch/arm/boards/zii-imx8mq-dev/flash-header-zii-imx8mq-dev.imxcfg
@@ -0,0 +1,5 @@
+soc imx8mq
+
+loadaddr 0x007E1000
+max_load_size 0x3F000
+dcdofs 0x400
diff --git a/arch/arm/boards/zii-imx8mq-dev/lowlevel.c b/arch/arm/boards/zii-imx8mq-dev/lowlevel.c
new file mode 100644
index 0000000000..059e4c9efd
--- /dev/null
+++ b/arch/arm/boards/zii-imx8mq-dev/lowlevel.c
@@ -0,0 +1,211 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2019 Zodiac Inflight Innovation
+ * Author: Andrey Smirnov <andrew.smirnov@gmail.com>
+ */
+
+#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 <mach/atf.h>
+#include <mach/esdctl.h>
+
+#include "ddr.h"
+
+#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('>');
+}
+
+/*
+ * Two functions below are used when Barebox is used as a DDR
+ * initializing payload for OpenOCD
+ */
+#define RDU3_TCM_MAGIC_LOCATION 0x007e1028
+#define RDU3_TCM_MAGIC_REQUEST 0xdeadbeef
+#define RDU3_TCM_MAGIC_REPLY 0xbaadf00d
+
+static bool running_as_ddr_helper(void)
+{
+ return readl(RDU3_TCM_MAGIC_LOCATION) == RDU3_TCM_MAGIC_REQUEST;
+}
+
+static __noreturn void ddr_helper_halt(void)
+{
+ writel(RDU3_TCM_MAGIC_REPLY, RDU3_TCM_MAGIC_LOCATION);
+ asm volatile("hlt 0");
+ BUG(); /* To prevent noreturn warnings */
+}
+
+static void zii_imx8mq_dev_sram_setup(void)
+{
+ enum bootsource src = BOOTSOURCE_UNKNOWN;
+ int instance = BOOTSOURCE_INSTANCE_UNKNOWN;
+ int ret = -ENOTSUPP;
+
+ ddr_init();
+
+ if (running_as_ddr_helper())
+ ddr_helper_halt();
+
+ imx8_get_boot_source(&src, &instance);
+
+ if (src == BOOTSOURCE_MMC)
+ ret = imx8_esdhc_start_image(instance);
+
+ BUG_ON(ret);
+}
+
+enum zii_platform_imx8mq_type {
+ ZII_PLATFORM_IMX8MQ_ULTRA_RMB3 = 0b0000,
+ ZII_PLATFORM_IMX8MQ_ULTRA_ZEST = 0b1000,
+};
+
+static unsigned int get_system_type(void)
+{
+#define GPIO_DR 0x000
+#define GPIO_GDIR 0x004
+#define SYSTEM_TYPE GENMASK(24, 21)
+
+ u32 gdir, dr;
+ void __iomem *gpio3 = IOMEM(MX8MQ_GPIO3_BASE_ADDR);
+ void __iomem *iomuxbase = IOMEM(MX8MQ_IOMUXC_BASE_ADDR);
+
+ /*
+ * System type is encoded as a 4-bit number specified by the
+ * following pins (pulled up or down with resistors on the
+ * board).
+ */
+ imx_setup_pad(iomuxbase, IMX8MQ_PAD_SAI5_RXD0__GPIO3_IO21);
+ imx_setup_pad(iomuxbase, IMX8MQ_PAD_SAI5_RXD1__GPIO3_IO22);
+ imx_setup_pad(iomuxbase, IMX8MQ_PAD_SAI5_RXD2__GPIO3_IO23);
+ imx_setup_pad(iomuxbase, IMX8MQ_PAD_SAI5_RXD3__GPIO3_IO24);
+
+ gdir = readl(gpio3 + GPIO_GDIR);
+ gdir &= ~SYSTEM_TYPE;
+ writel(gdir, gpio3 + GPIO_GDIR);
+
+ dr = readl(gpio3 + GPIO_DR);
+
+ return FIELD_GET(SYSTEM_TYPE, dr);
+}
+
+extern char __dtb_imx8mq_zii_ultra_rmb3_start[];
+extern char __dtb_imx8mq_zii_ultra_zest_start[];
+
+/*
+ * Power-on execution flow of start_zii_imx8mq_dev() might not be
+ * obvious for a very frist read, so here's, hopefully helpful,
+ * summary:
+ *
+ * 1. MaskROM uploads PBL into OCRAM and that's where this function is
+ * executed for the first time
+ *
+ * 2. DDR is initialized and full i.MX image is loaded to the
+ * beginning of RAM
+ *
+ * 3. start_nxp_imx8mq_evk, now in RAM, is executed again
+ *
+ * 4. BL31 blob is uploaded to OCRAM and the control is transfer to it
+ *
+ * 5. BL31 exits EL3 into EL2 at address MX8MQ_ATF_BL33_BASE_ADDR,
+ * executing start_nxp_imx8mq_evk() the third time
+ *
+ * 6. Standard barebox boot flow continues
+ */
+ENTRY_FUNCTION(start_zii_imx8mq_dev, r0, r1, r2)
+{
+ unsigned int system_type;
+ void *fdt;
+
+ arm_cpu_lowlevel_init();
+
+ if (IS_ENABLED(CONFIG_DEBUG_LL))
+ setup_uart();
+
+ if (get_pc() < MX8MQ_DDR_CSD1_BASE_ADDR) {
+ /*
+ * We assume that we were just loaded by MaskROM into
+ * SRAM if we are not running from DDR. We also assume
+ * that means DDR needs to be initialized for the
+ * first time.
+ */
+ zii_imx8mq_dev_sram_setup();
+ }
+ /*
+ * Straight from the power-on we are at EL3, so the following
+ * code _will_ load and jump to ATF.
+ *
+ * However when we are re-executed upon exit from ATF's
+ * initialization routine, it is EL2 which means we'll skip
+ * loadting ATF blob again
+ */
+ if (current_el() == 3) {
+ const u8 *bl31;
+ size_t bl31_size;
+
+ get_builtin_firmware(imx8mq_bl31_bin, &bl31, &bl31_size);
+ imx8mq_atf_load_bl31(bl31, bl31_size);
+ }
+
+ system_type = get_system_type();
+
+ switch (system_type) {
+ default:
+ /*
+ * see similar code in
+ * arch/arm/boards/zii-vf610-dev/lowlevel.c for
+ * reasoning for placing barrier() below.
+ */
+ barrier();
+
+ if (IS_ENABLED(CONFIG_DEBUG_LL)) {
+ relocate_to_current_adr();
+ setup_c();
+ puts_ll("\n*********************************\n");
+ puts_ll("* Unknown system type: ");
+ puthex_ll(system_type);
+ puts_ll("\n* Assuming Ultra RMB3\n");
+ puts_ll("*********************************\n");
+ }
+ /* FALLTHROUGH */
+ case ZII_PLATFORM_IMX8MQ_ULTRA_RMB3:
+ fdt = __dtb_imx8mq_zii_ultra_rmb3_start;
+ break;
+ case ZII_PLATFORM_IMX8MQ_ULTRA_ZEST:
+ fdt = __dtb_imx8mq_zii_ultra_zest_start;
+ break;
+ }
+
+ /*
+ * Standard entry we hit once we initialized both DDR and ATF
+ */
+ imx8mq_barebox_entry(fdt);
+}
diff --git a/arch/arm/configs/imx_v8_defconfig b/arch/arm/configs/imx_v8_defconfig
index cc41f49754..aa0a78ad93 100644
--- a/arch/arm/configs/imx_v8_defconfig
+++ b/arch/arm/configs/imx_v8_defconfig
@@ -1,5 +1,6 @@
CONFIG_ARCH_IMX=y
CONFIG_IMX_MULTI_BOARDS=y
+CONFIG_MACH_ZII_IMX8MQ_DEV=y
CONFIG_MACH_NXP_IMX8MQ_EVK=y
CONFIG_ARM_OPTIMZED_STRING_FUNCTIONS=y
CONFIG_MMU=y
@@ -8,7 +9,6 @@ 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
@@ -18,6 +18,7 @@ CONFIG_BOOTM_OFTREE=y
CONFIG_BOOTM_OFTREE_UIMAGE=y
CONFIG_BLSPEC=y
CONFIG_CONSOLE_ACTIVATE_NONE=y
+CONFIG_CONSOLE_RATP=y
CONFIG_PARTITION_DISK_EFI=y
CONFIG_DEFAULT_ENVIRONMENT_GENERIC_NEW=y
CONFIG_RESET_SOURCE=y
@@ -76,32 +77,47 @@ 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_SERIAL_DEV_BUS=y
CONFIG_DRIVER_NET_FEC_IMX=y
+CONFIG_MICREL_PHY=y
+CONFIG_NET_DSA_MV88E6XXX=y
+CONFIG_MDIO_BITBANG=y
+CONFIG_MDIO_GPIO=y
+CONFIG_MDIO_BUS_MUX_GPIO=y
CONFIG_DRIVER_SPI_IMX=y
CONFIG_I2C=y
CONFIG_I2C_IMX=y
+CONFIG_MTD=y
+CONFIG_MTD_DATAFLASH=y
+CONFIG_MTD_M25P80=y
CONFIG_MCI=y
CONFIG_MCI_MMC_BOOT_PARTITIONS=y
CONFIG_MCI_IMX_ESDHC=y
+CONFIG_RAVE_SP_CORE=y
CONFIG_LED=y
CONFIG_LED_GPIO=y
CONFIG_LED_GPIO_OF=y
CONFIG_LED_TRIGGERS=y
CONFIG_EEPROM_AT25=y
+CONFIG_EEPROM_AT24=y
CONFIG_WATCHDOG=y
CONFIG_WATCHDOG_IMX=y
+CONFIG_RAVE_SP_WATCHDOG=y
CONFIG_NVMEM=y
CONFIG_IMX_OCOTP=y
+CONFIG_RAVE_SP_EEPROM=y
CONFIG_REGULATOR=y
CONFIG_REGULATOR_FIXED=y
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_DRV_DS1307=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_FS_RATP=y
CONFIG_ZLIB=y
CONFIG_LZO_DECOMPRESS=y
diff --git a/arch/arm/dts/Makefile b/arch/arm/dts/Makefile
index caa97e7137..3cdee1ffb7 100644
--- a/arch/arm/dts/Makefile
+++ b/arch/arm/dts/Makefile
@@ -100,6 +100,7 @@ pbl-dtb-$(CONFIG_MACH_TX6X) += imx6dl-tx6u.dtb.o
pbl-dtb-$(CONFIG_MACH_TX6X) += imx6q-tx6q.dtb.o
pbl-dtb-$(CONFIG_MACH_TURRIS_OMNIA) += armada-385-turris-omnia-bb.dtb.o
pbl-dtb-$(CONFIG_MACH_UDOO) += imx6q-udoo.dtb.o
+pbl-dtb-$(CONFIG_MACH_UDOO_NEO) += imx6sx-udoo-neo-full.dtb.o
pbl-dtb-$(CONFIG_MACH_USI_TOPKICK) += kirkwood-topkick-bb.dtb.o
pbl-dtb-$(CONFIG_MACH_VARISCITE_MX6) += imx6q-var-custom.dtb.o
pbl-dtb-$(CONFIG_MACH_VEXPRESS) += vexpress-v2p-ca9.dtb.o
@@ -112,6 +113,9 @@ pbl-dtb-$(CONFIG_MACH_ZII_RDU1) += \
imx51-zii-scu2-mezz.dtb.o \
imx51-zii-scu3-esb.dtb.o
pbl-dtb-$(CONFIG_MACH_ZII_RDU2) += imx6q-zii-rdu2.dtb.o imx6qp-zii-rdu2.dtb.o
+pbl-dtb-$(CONFIG_MACH_ZII_IMX8MQ_DEV) += \
+ imx8mq-zii-ultra-rmb3.dtb.o \
+ imx8mq-zii-ultra-zest.dtb.o
pbl-dtb-$(CONFIG_MACH_ZII_VF610_DEV) += \
vf610-zii-dev-rev-b.dtb.o \
vf610-zii-dev-rev-c.dtb.o \
diff --git a/arch/arm/dts/imx6sx-udoo-neo-full.dts b/arch/arm/dts/imx6sx-udoo-neo-full.dts
new file mode 100644
index 0000000000..9203d40207
--- /dev/null
+++ b/arch/arm/dts/imx6sx-udoo-neo-full.dts
@@ -0,0 +1,4 @@
+#include <arm/imx6sx-udoo-neo-full.dts>
+
+/{
+};
diff --git a/arch/arm/dts/imx8mq-zii-ultra-rmb3.dts b/arch/arm/dts/imx8mq-zii-ultra-rmb3.dts
new file mode 100644
index 0000000000..b2b3a560b5
--- /dev/null
+++ b/arch/arm/dts/imx8mq-zii-ultra-rmb3.dts
@@ -0,0 +1,39 @@
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
+/*
+ * Copyright (C) 2019 Zodiac Inflight Innovations
+ */
+
+/dts-v1/;
+
+#include "imx8mq-zii-ultra.dtsi"
+
+/ {
+ model = "ZII i.MX8MQ Ultra RMB3 Board";
+ compatible = "zii,imx8mq-ultra-rmb3", "zii,imx8mq-ultra", "fsl,imx8mq";
+};
+
+&ecspi1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_ecspi1>;
+ cs-gpios = <&gpio5 9 GPIO_ACTIVE_HIGH>;
+ status = "okay";
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ nor_flash: flash@0 {
+ compatible = "st,m25p128", "jedec,spi-nor";
+ spi-max-frequency = <20000000>;
+ reg = <0>;
+ };
+};
+
+&iomuxc {
+ pinctrl_ecspi1: ecspi1grp {
+ fsl,pins = <
+ MX8MQ_IOMUXC_ECSPI1_SS0_GPIO5_IO9 0x19
+ MX8MQ_IOMUXC_ECSPI1_SCLK_ECSPI1_SCLK 0x82
+ MX8MQ_IOMUXC_ECSPI1_MISO_ECSPI1_MISO 0x82
+ MX8MQ_IOMUXC_ECSPI1_MOSI_ECSPI1_MOSI 0x82
+ >;
+ };
+};
diff --git a/arch/arm/dts/imx8mq-zii-ultra-zest.dts b/arch/arm/dts/imx8mq-zii-ultra-zest.dts
new file mode 100644
index 0000000000..c2ac05d8e8
--- /dev/null
+++ b/arch/arm/dts/imx8mq-zii-ultra-zest.dts
@@ -0,0 +1,13 @@
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
+/*
+ * Copyright (C) 2019 Zodiac Inflight Innovations
+ */
+
+/dts-v1/;
+
+#include "imx8mq-zii-ultra.dtsi"
+
+/ {
+ model = "ZII i.MX8MQ Ultra Zest Board";
+ compatible = "zii,imx8mq-ultra-zest", "zii,imx8mq-ultra", "fsl,imx8mq";
+};
diff --git a/arch/arm/dts/imx8mq-zii-ultra.dtsi b/arch/arm/dts/imx8mq-zii-ultra.dtsi
new file mode 100644
index 0000000000..a6b2b89662
--- /dev/null
+++ b/arch/arm/dts/imx8mq-zii-ultra.dtsi
@@ -0,0 +1,453 @@
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
+/*
+ * Copyright (C) 2019 Zodiac Inflight Innovations
+ */
+
+#include <arm64/freescale/imx8mq.dtsi>
+#include "imx8mq.dtsi"
+#include "imx8mq-ddrc.dtsi"
+
+/ {
+ chosen {
+ stdout-path = &uart1;
+ };
+
+ mdio0: bitbang-mdio {
+ compatible = "virtual,mdio-gpio";
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_mdio_bitbang>, <&pinctrl_fec1_phy_reset>;
+ gpios = <&gpio1 13 GPIO_ACTIVE_HIGH>, /* MDC */
+ <&gpio1 14 GPIO_ACTIVE_HIGH>; /* MDIO */
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ phy0: ethernet-phy@0 {
+ reg = <0>;
+ reset-gpios = <&gpio1 29 GPIO_ACTIVE_LOW>;
+ };
+ };
+
+ 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;
+ };
+};
+
+&fec1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_fec1>;
+
+ phy-handle = <&phy0>;
+ phy-mode = "rmii";
+ status = "okay";
+
+ mdio {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "okay";
+
+ switch: switch@0 {
+ compatible = "marvell,mv88e6085";
+ reg = <0>;
+ dsa,member = <0 0>;
+ eeprom-length = <512>;
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ reg = <0>;
+ label = "gigabit_proc";
+ };
+
+ port@1 {
+ reg = <1>;
+ label = "netaux";
+ };
+
+ port@2 {
+ reg = <2>;
+ label = "cpu";
+
+ fixed-link {
+ speed = <100>;
+ full-duplex;
+ };
+ };
+
+ port@3 {
+ reg = <3>;
+ label = "netright";
+ };
+
+ port@4 {
+ reg = <4>;
+ label = "netleft";
+ };
+ };
+ };
+ };
+};
+
+&i2c1 {
+ clock-frequency = <100000>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_i2c1>;
+ status = "okay";
+};
+
+&i2c2 {
+ clock-frequency = <100000>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_i2c2>;
+ 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>;
+ };
+ };
+ };
+
+ temp-sense@48 {
+ compatible = "national,lm75";
+ reg = <0x48>;
+ };
+
+ eeprom@54 {
+ compatible = "atmel,24c128";
+ reg = <0x54>;
+ };
+
+ ds1341: rtc@68 {
+ compatible = "dallas,ds1341";
+ reg = <0x68>;
+ };
+};
+
+&i2c3 {
+ clock-frequency = <100000>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_i2c3>;
+ status = "okay";
+};
+
+&i2c4 {
+ clock-frequency = <400000>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_i2c4>;
+ status = "okay";
+};
+
+&ocotp {
+ barebox,provide-mac-address = <&fec1 0x640>;
+};
+
+&uart1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_uart1>;
+ status = "okay";
+};
+
+&uart2 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_uart2>;
+ status = "okay";
+
+ rave-sp {
+ compatible = "zii,rave-sp-rdu2";
+ current-speed = <1000000>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ watchdog {
+ compatible = "zii,rave-sp-watchdog";
+ };
+
+ main_eeprom: eeprom@a4 {
+ compatible = "zii,rave-sp-eeprom";
+ reg = <0xa4 0x4000>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ zii,eeprom-name = "main-eeprom";
+ };
+
+ eeprom@a3 {
+ compatible = "zii,rave-sp-eeprom";
+ reg = <0xa3 0x4000>;
+ zii,eeprom-name = "dds-eeprom";
+ };
+ };
+};
+
+&usdhc1 {
+ pinctrl-names = "default", "state_100mhz", "state_200mhz";
+ pinctrl-0 = <&pinctrl_usdhc1>;
+ pinctrl-1 = <&pinctrl_usdhc1_100mhz>;
+ pinctrl-2 = <&pinctrl_usdhc1_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>;
+ pinctrl-1 = <&pinctrl_usdhc2_100mhz>;
+ pinctrl-2 = <&pinctrl_usdhc2_200mhz>;
+ cd-gpios = <&gpio2 12 GPIO_ACTIVE_LOW>;
+ vmmc-supply = <&reg_usdhc2_vmmc>;
+ status = "okay";
+};
+
+&iomuxc {
+ pinctrl_mdio_bitbang: bitbangmdiogrp {
+ fsl,pins = <
+ MX8MQ_IOMUXC_GPIO1_IO13_GPIO1_IO13 0x44
+ MX8MQ_IOMUXC_GPIO1_IO14_GPIO1_IO14 0x64
+ >;
+ };
+
+ pinctrl_fec1: fec1grp {
+ fsl,pins = <
+ MX8MQ_IOMUXC_ENET_MDC_ENET1_MDC 0x3
+ MX8MQ_IOMUXC_ENET_MDIO_ENET1_MDIO 0x23
+ MX8MQ_IOMUXC_ENET_TD1_ENET1_RGMII_TD1 0x1f
+ MX8MQ_IOMUXC_ENET_TD0_ENET1_RGMII_TD0 0x1f
+ MX8MQ_IOMUXC_ENET_RD1_ENET1_RGMII_RD1 0x91
+ MX8MQ_IOMUXC_ENET_RD0_ENET1_RGMII_RD0 0x91
+ MX8MQ_IOMUXC_ENET_TD2_ENET1_TX_CLK 0x1f
+ MX8MQ_IOMUXC_ENET_RXC_ENET1_RX_ER 0x91
+ MX8MQ_IOMUXC_ENET_RX_CTL_ENET1_RGMII_RX_CTL 0x91
+ MX8MQ_IOMUXC_ENET_TX_CTL_ENET1_RGMII_TX_CTL 0x1f
+ >;
+ };
+
+ pinctrl_fec1_phy_reset: fec1phyresetgrp {
+ fsl,pins = <
+ MX8MQ_IOMUXC_ENET_RD3_GPIO1_IO29 0x11
+ >;
+ };
+
+ pinctrl_i2c1: i2c1grp {
+ fsl,pins = <
+ MX8MQ_IOMUXC_I2C1_SCL_I2C1_SCL 0x4000007f
+ MX8MQ_IOMUXC_I2C1_SDA_I2C1_SDA 0x4000007f
+ >;
+ };
+
+ pinctrl_i2c2: i2c2grp {
+ fsl,pins = <
+ MX8MQ_IOMUXC_I2C2_SCL_I2C2_SCL 0x4000007f
+ MX8MQ_IOMUXC_I2C2_SDA_I2C2_SDA 0x4000007f
+ >;
+ };
+
+ pinctrl_i2c3: i2c3grp {
+ fsl,pins = <
+ MX8MQ_IOMUXC_I2C3_SCL_I2C3_SCL 0x4000007f
+ MX8MQ_IOMUXC_I2C3_SDA_I2C3_SDA 0x4000007f
+ >;
+ };
+
+ pinctrl_i2c4: i2c4grp {
+ fsl,pins = <
+ MX8MQ_IOMUXC_I2C4_SCL_I2C4_SCL 0x4000007f
+ MX8MQ_IOMUXC_I2C4_SDA_I2C4_SDA 0x4000007f
+ >;
+ };
+
+ pinctrl_reg_usdhc2: regusdhc2grpgpio {
+ fsl,pins = <
+ MX8MQ_IOMUXC_SD2_RESET_B_GPIO2_IO19 0x41
+ >;
+ };
+
+ pinctrl_uart1: uart1grp {
+ fsl,pins = <
+ MX8MQ_IOMUXC_UART1_RXD_UART1_DCE_RX 0x49
+ MX8MQ_IOMUXC_UART1_TXD_UART1_DCE_TX 0x49
+ >;
+ };
+
+ pinctrl_uart2: uart2grp {
+ fsl,pins = <
+ MX8MQ_IOMUXC_UART2_RXD_UART2_DCE_RX 0x49
+ MX8MQ_IOMUXC_UART2_TXD_UART2_DCE_TX 0x49
+ >;
+ };
+
+ pinctrl_usdhc1: usdhc1grp {
+ fsl,pins = <
+ MX8MQ_IOMUXC_SD1_CLK_USDHC1_CLK 0x83
+ MX8MQ_IOMUXC_SD1_CMD_USDHC1_CMD 0xc3
+ MX8MQ_IOMUXC_SD1_DATA0_USDHC1_DATA0 0xc3
+ MX8MQ_IOMUXC_SD1_DATA1_USDHC1_DATA1 0xc3
+ MX8MQ_IOMUXC_SD1_DATA2_USDHC1_DATA2 0xc3
+ MX8MQ_IOMUXC_SD1_DATA3_USDHC1_DATA3 0xc3
+ MX8MQ_IOMUXC_SD1_DATA4_USDHC1_DATA4 0xc3
+ MX8MQ_IOMUXC_SD1_DATA5_USDHC1_DATA5 0xc3
+ MX8MQ_IOMUXC_SD1_DATA6_USDHC1_DATA6 0xc3
+ MX8MQ_IOMUXC_SD1_DATA7_USDHC1_DATA7 0xc3
+ MX8MQ_IOMUXC_SD1_STROBE_USDHC1_STROBE 0x83
+ MX8MQ_IOMUXC_SD1_RESET_B_USDHC1_RESET_B 0xc1
+ >;
+ };
+
+ pinctrl_usdhc1_100mhz: usdhc1-100grp {
+ fsl,pins = <
+ MX8MQ_IOMUXC_SD1_CLK_USDHC1_CLK 0x85
+ MX8MQ_IOMUXC_SD1_CMD_USDHC1_CMD 0xc5
+ MX8MQ_IOMUXC_SD1_DATA0_USDHC1_DATA0 0xc5
+ MX8MQ_IOMUXC_SD1_DATA1_USDHC1_DATA1 0xc5
+ MX8MQ_IOMUXC_SD1_DATA2_USDHC1_DATA2 0xc5
+ MX8MQ_IOMUXC_SD1_DATA3_USDHC1_DATA3 0xc5
+ MX8MQ_IOMUXC_SD1_DATA4_USDHC1_DATA4 0xc5
+ MX8MQ_IOMUXC_SD1_DATA5_USDHC1_DATA5 0xc5
+ MX8MQ_IOMUXC_SD1_DATA6_USDHC1_DATA6 0xc5
+ MX8MQ_IOMUXC_SD1_DATA7_USDHC1_DATA7 0xc5
+ MX8MQ_IOMUXC_SD1_STROBE_USDHC1_STROBE 0x85
+ MX8MQ_IOMUXC_SD1_RESET_B_USDHC1_RESET_B 0xc1
+ >;
+ };
+
+ pinctrl_usdhc1_200mhz: usdhc1-200grp {
+ fsl,pins = <
+ MX8MQ_IOMUXC_SD1_CLK_USDHC1_CLK 0x87
+ MX8MQ_IOMUXC_SD1_CMD_USDHC1_CMD 0xc7
+ MX8MQ_IOMUXC_SD1_DATA0_USDHC1_DATA0 0xc7
+ MX8MQ_IOMUXC_SD1_DATA1_USDHC1_DATA1 0xc7
+ MX8MQ_IOMUXC_SD1_DATA2_USDHC1_DATA2 0xc7
+ MX8MQ_IOMUXC_SD1_DATA3_USDHC1_DATA3 0xc7
+ MX8MQ_IOMUXC_SD1_DATA4_USDHC1_DATA4 0xc7
+ MX8MQ_IOMUXC_SD1_DATA5_USDHC1_DATA5 0xc7
+ MX8MQ_IOMUXC_SD1_DATA6_USDHC1_DATA6 0xc7
+ MX8MQ_IOMUXC_SD1_DATA7_USDHC1_DATA7 0xc7
+ MX8MQ_IOMUXC_SD1_STROBE_USDHC1_STROBE 0x87
+ MX8MQ_IOMUXC_SD1_RESET_B_USDHC1_RESET_B 0xc1
+ >;
+ };
+
+ pinctrl_usdhc2: usdhc2grp {
+ fsl,pins = <
+ MX8MQ_IOMUXC_SD2_CLK_USDHC2_CLK 0x83
+ MX8MQ_IOMUXC_SD2_CMD_USDHC2_CMD 0xc3
+ MX8MQ_IOMUXC_SD2_DATA0_USDHC2_DATA0 0xc3
+ MX8MQ_IOMUXC_SD2_DATA1_USDHC2_DATA1 0xc3
+ MX8MQ_IOMUXC_SD2_DATA2_USDHC2_DATA2 0xc3
+ MX8MQ_IOMUXC_SD2_DATA3_USDHC2_DATA3 0xc3
+ MX8MQ_IOMUXC_GPIO1_IO04_USDHC2_VSELECT 0xc1
+ >;
+ };
+
+ pinctrl_usdhc2_100mhz: usdhc2-100grp {
+ fsl,pins = <
+ MX8MQ_IOMUXC_SD2_CLK_USDHC2_CLK 0x85
+ MX8MQ_IOMUXC_SD2_CMD_USDHC2_CMD 0xc5
+ MX8MQ_IOMUXC_SD2_DATA0_USDHC2_DATA0 0xc5
+ MX8MQ_IOMUXC_SD2_DATA1_USDHC2_DATA1 0xc5
+ MX8MQ_IOMUXC_SD2_DATA2_USDHC2_DATA2 0xc5
+ MX8MQ_IOMUXC_SD2_DATA3_USDHC2_DATA3 0xc5
+ MX8MQ_IOMUXC_GPIO1_IO04_USDHC2_VSELECT 0xc1
+ >;
+ };
+
+ pinctrl_usdhc2_200mhz: usdhc2-200grp {
+ fsl,pins = <
+ MX8MQ_IOMUXC_SD2_CLK_USDHC2_CLK 0x87
+ MX8MQ_IOMUXC_SD2_CMD_USDHC2_CMD 0xc7
+ MX8MQ_IOMUXC_SD2_DATA0_USDHC2_DATA0 0xc7
+ MX8MQ_IOMUXC_SD2_DATA1_USDHC2_DATA1 0xc7
+ MX8MQ_IOMUXC_SD2_DATA2_USDHC2_DATA2 0xc7
+ MX8MQ_IOMUXC_SD2_DATA3_USDHC2_DATA3 0xc7
+ MX8MQ_IOMUXC_GPIO1_IO04_USDHC2_VSELECT 0xc1
+ >;
+ };
+}; \ No newline at end of file
diff --git a/arch/arm/lib64/barebox.lds.S b/arch/arm/lib64/barebox.lds.S
index 08adc44e86..b3e6843a15 100644
--- a/arch/arm/lib64/barebox.lds.S
+++ b/arch/arm/lib64/barebox.lds.S
@@ -86,6 +86,18 @@ SECTIONS
__usymtab : { BAREBOX_SYMS }
__usymtab_end = .;
+#ifdef CONFIG_PCI
+ __start_pci_fixups_early = .;
+ .pci_fixup_early : { KEEP(*(.pci_fixup_early)) }
+ __end_pci_fixups_early = .;
+ __start_pci_fixups_header = .;
+ .pci_fixup_header : { KEEP(*(.pci_fixup_header)) }
+ __end_pci_fixups_header = .;
+ __start_pci_fixups_enable = .;
+ .pci_fixup_enable : { KEEP(*(.pci_fixup_enable)) }
+ __end_pci_fixups_enable = .;
+#endif
+
.oftables : { BAREBOX_CLK_TABLE() }
.dtb : { BAREBOX_DTB() }
diff --git a/arch/arm/mach-imx/Kconfig b/arch/arm/mach-imx/Kconfig
index 44ca27096b..8b859ab2f6 100644
--- a/arch/arm/mach-imx/Kconfig
+++ b/arch/arm/mach-imx/Kconfig
@@ -173,6 +173,7 @@ config ARCH_IMX7
select COMMON_CLK_OF_PROVIDER
select ARCH_HAS_FEC_IMX
select ARCH_HAS_IMX_GPT
+ select HW_HAS_PCI
config ARCH_IMX8MQ
bool
@@ -182,6 +183,7 @@ config ARCH_IMX8MQ
select SYS_SUPPORTS_64BIT_KERNEL
select COMMON_CLK_OF_PROVIDER
select ARCH_HAS_FEC_IMX
+ select HW_HAS_PCI
config ARCH_VF610
bool
@@ -395,6 +397,10 @@ config MACH_UDOO
bool "Freescale i.MX6 UDOO Board"
select ARCH_IMX6
+config MACH_UDOO_NEO
+ bool "i.MX6 UDOO Neo Board (full variant)"
+ select ARCH_IMX6SX
+
config MACH_VARISCITE_MX6
bool "Variscite i.MX6 Quad SOM"
select ARCH_IMX6
@@ -434,6 +440,13 @@ config MACH_ZII_RDU2
bool "ZII i.MX6Q(+) RDU2"
select ARCH_IMX6
+config MACH_ZII_IMX8MQ_DEV
+ bool "ZII i.MX8MQ based devices"
+ select ARCH_IMX8MQ
+ select FIRMWARE_IMX_LPDDR4_PMU_TRAIN
+ select FIRMWARE_IMX8MQ_ATF
+ select ARM_SMCCC
+
config MACH_ZII_VF610_DEV
bool "ZII VF610 Dev Family"
select ARCH_VF610
diff --git a/arch/arm/mach-imx/imx-bbu-internal.c b/arch/arm/mach-imx/imx-bbu-internal.c
index 5f85b13dca..188369fe34 100644
--- a/arch/arm/mach-imx/imx-bbu-internal.c
+++ b/arch/arm/mach-imx/imx-bbu-internal.c
@@ -629,6 +629,11 @@ int imx7_bbu_internal_mmcboot_register_handler(const char *name,
unsigned long flags)
__alias(imx_bbu_internal_mmcboot_register_handler);
+int imx8mq_bbu_internal_mmcboot_register_handler(const char *name,
+ const char *devicefile,
+ unsigned long flags)
+ __alias(imx_bbu_internal_mmcboot_register_handler);
+
/*
* Register an i.MX53 internal boot update handler for i2c/spi
* EEPROMs / flashes. Nearly the same as MMC/SD, but we do not need to
diff --git a/arch/arm/mach-imx/include/mach/bbu.h b/arch/arm/mach-imx/include/mach/bbu.h
index c8223c8405..10638a7fc7 100644
--- a/arch/arm/mach-imx/include/mach/bbu.h
+++ b/arch/arm/mach-imx/include/mach/bbu.h
@@ -76,6 +76,8 @@ int imx7_bbu_internal_spi_i2c_register_handler(const char *name, const char *dev
int imx8mq_bbu_internal_mmc_register_handler(const char *name, const char *devicefile,
unsigned long flags);
+int imx8mq_bbu_internal_mmcboot_register_handler(const char *name, const char *devicefile,
+ unsigned long flags);
int imx_bbu_external_nor_register_handler(const char *name, const char *devicefile,
unsigned long flags);
@@ -165,6 +167,13 @@ static inline int imx8mq_bbu_internal_mmc_register_handler(const char *name, con
return -ENOSYS;
}
+static inline int imx8mq_bbu_internal_mmcboot_register_handler(const char *name,
+ const char *devicefile,
+ unsigned long flags)
+{
+ return -ENOSYS;
+}
+
static inline int imx_bbu_external_nor_register_handler(const char *name, const char *devicefile,
unsigned long flags)
{
diff --git a/arch/arm/mach-imx/include/mach/esdctl.h b/arch/arm/mach-imx/include/mach/esdctl.h
index bc6c733953..18c4a28360 100644
--- a/arch/arm/mach-imx/include/mach/esdctl.h
+++ b/arch/arm/mach-imx/include/mach/esdctl.h
@@ -141,6 +141,7 @@ void __noreturn imx6ul_barebox_entry(void *boarddata);
void __noreturn vf610_barebox_entry(void *boarddata);
void __noreturn imx8mq_barebox_entry(void *boarddata);
void __noreturn imx7d_barebox_entry(void *boarddata);
+#define imx6sx_barebox_entry(boarddata) imx6ul_barebox_entry(boarddata)
void imx_esdctl_disable(void);
#endif
diff --git a/arch/arm/mach-imx/include/mach/imx8mq.h b/arch/arm/mach-imx/include/mach/imx8mq.h
index f4a537d2b1..08dc06fdb4 100644
--- a/arch/arm/mach-imx/include/mach/imx8mq.h
+++ b/arch/arm/mach-imx/include/mach/imx8mq.h
@@ -9,6 +9,8 @@
#define IMX8MQ_ROM_VERSION_A0 0x800
#define IMX8MQ_ROM_VERSION_B0 0x83C
+#define IMX8MQ_OCOTP_VERSION_B1 0x40
+#define IMX8MQ_OCOTP_VERSION_B1_MAGIC 0xff0055aa
#define MX8MQ_ANATOP_DIGPROG 0x6c
@@ -20,21 +22,28 @@
static inline int imx8mq_cpu_revision(void)
{
void __iomem *anatop = IOMEM(MX8MQ_ANATOP_BASE_ADDR);
+ void __iomem *ocotp = IOMEM(MX8MQ_OCOTP_BASE_ADDR);
uint32_t revision = FIELD_GET(DIGPROG_MINOR,
readl(anatop + MX8MQ_ANATOP_DIGPROG));
-
- if (revision == IMX_CHIP_REV_1_0) {
- uint32_t rom_version;
- /*
- * For B0 chip, the DIGPROG is not updated, still TO1.0.
- * we have to check ROM version further
- */
- rom_version = readl(IOMEM(IMX8MQ_ROM_VERSION_A0));
- if (rom_version != IMX_CHIP_REV_1_0) {
- rom_version = readl(IOMEM(IMX8MQ_ROM_VERSION_B0));
- if (rom_version >= IMX_CHIP_REV_2_0)
- revision = IMX_CHIP_REV_2_0;
- }
+ uint32_t rom_version;
+
+ if (revision != IMX_CHIP_REV_1_0)
+ return revision;
+ /*
+ * For B1 chip we need to check OCOTP
+ */
+ if (readl(ocotp + IMX8MQ_OCOTP_VERSION_B1) ==
+ IMX8MQ_OCOTP_VERSION_B1_MAGIC)
+ return IMX_CHIP_REV_2_1;
+ /*
+ * For B0 chip, the DIGPROG is not updated, still TO1.0.
+ * we have to check ROM version further
+ */
+ rom_version = readb(IOMEM(IMX8MQ_ROM_VERSION_A0));
+ if (rom_version != IMX_CHIP_REV_1_0) {
+ rom_version = readb(IOMEM(IMX8MQ_ROM_VERSION_B0));
+ if (rom_version >= IMX_CHIP_REV_2_0)
+ revision = IMX_CHIP_REV_2_0;
}
return revision;
diff --git a/drivers/Kconfig b/drivers/Kconfig
index 1e0246da6d..c6c2eb14db 100644
--- a/drivers/Kconfig
+++ b/drivers/Kconfig
@@ -1,5 +1,6 @@
menu "Drivers"
+source "drivers/base/Kconfig"
source "drivers/efi/Kconfig"
source "drivers/of/Kconfig"
source "drivers/aiodev/Kconfig"
@@ -37,5 +38,6 @@ source "drivers/firmware/Kconfig"
source "drivers/phy/Kconfig"
source "drivers/crypto/Kconfig"
source "drivers/memory/Kconfig"
+source "drivers/soc/imx/Kconfig"
endmenu
diff --git a/drivers/Makefile b/drivers/Makefile
index 767789d541..752fd66242 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -38,3 +38,4 @@ obj-$(CONFIG_HAB) += hab/
obj-$(CONFIG_CRYPTO_HW) += crypto/
obj-$(CONFIG_AIODEV) += aiodev/
obj-y += memory/
+obj-y += soc/imx/
diff --git a/drivers/base/Kconfig b/drivers/base/Kconfig
new file mode 100644
index 0000000000..1e13e5ed9d
--- /dev/null
+++ b/drivers/base/Kconfig
@@ -0,0 +1,3 @@
+
+config PM_GENERIC_DOMAINS
+ bool
diff --git a/drivers/base/Makefile b/drivers/base/Makefile
index 4bd4217745..6d2cef8e1a 100644
--- a/drivers/base/Makefile
+++ b/drivers/base/Makefile
@@ -2,4 +2,6 @@ obj-y += bus.o
obj-y += driver.o
obj-y += platform.o
obj-y += resource.o
-obj-y += regmap/ \ No newline at end of file
+obj-y += regmap/
+
+obj-$(CONFIG_PM_GENERIC_DOMAINS) += power.o
diff --git a/drivers/base/driver.c b/drivers/base/driver.c
index 1fd890542e..1fd6bbc014 100644
--- a/drivers/base/driver.c
+++ b/drivers/base/driver.c
@@ -269,7 +269,7 @@ static int device_probe_deferred(void)
success = false;
if (list_empty(&deferred))
- break;
+ return 0;
list_for_each_entry_safe(dev, tmp, &deferred, active) {
list_del(&dev->active);
@@ -285,9 +285,6 @@ static int device_probe_deferred(void)
}
} while (success);
- if (list_empty(&deferred))
- return 0;
-
list_for_each_entry(dev, &deferred, active)
dev_err(dev, "probe permanently deferred\n");
diff --git a/drivers/base/platform.c b/drivers/base/platform.c
index 85bdfb0149..1d3fa2eb44 100644
--- a/drivers/base/platform.c
+++ b/drivers/base/platform.c
@@ -21,9 +21,16 @@
#include <errno.h>
#include <init.h>
#include <of.h>
+#include <pm_domain.h>
static int platform_probe(struct device_d *dev)
{
+ int ret;
+
+ ret = genpd_dev_pm_attach(dev);
+ if (ret < 0)
+ return ret;
+
return dev->driver->probe(dev);
}
diff --git a/drivers/base/power.c b/drivers/base/power.c
new file mode 100644
index 0000000000..12674ca7d9
--- /dev/null
+++ b/drivers/base/power.c
@@ -0,0 +1,249 @@
+#include <common.h>
+#include <driver.h>
+#include <errno.h>
+#include <of.h>
+
+#include <pm_domain.h>
+
+#define genpd_status_on(genpd) (genpd->status == GPD_STATE_ACTIVE)
+
+static LIST_HEAD(gpd_list);
+
+/**
+ * pm_genpd_init - Initialize a generic I/O PM domain object.
+ * @genpd: PM domain object to initialize.
+ * @gov: PM domain governor to associate with the domain (may be NULL).
+ * @is_off: Initial value of the domain's power_is_off field.
+ *
+ * Returns 0 on successful initialization, else a negative error code.
+ */
+int pm_genpd_init(struct generic_pm_domain *genpd, void *gov, bool is_off)
+{
+ if (IS_ERR_OR_NULL(genpd))
+ return -EINVAL;
+
+ genpd->status = is_off ? GPD_STATE_POWER_OFF : GPD_STATE_ACTIVE;
+
+ list_add(&genpd->gpd_list_node, &gpd_list);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(pm_genpd_init);
+
+/**
+ * struct of_genpd_provider - PM domain provider registration structure
+ * @link: Entry in global list of PM domain providers
+ * @node: Pointer to device tree node of PM domain provider
+ * @xlate: Provider-specific xlate callback mapping a set of specifier cells
+ * into a PM domain.
+ * @data: context pointer to be passed into @xlate callback
+ */
+struct of_genpd_provider {
+ struct list_head link;
+ struct device_node *node;
+ genpd_xlate_t xlate;
+ void *data;
+};
+
+/* List of registered PM domain providers. */
+static LIST_HEAD(of_genpd_providers);
+
+static bool genpd_present(const struct generic_pm_domain *genpd)
+{
+ const struct generic_pm_domain *gpd;
+
+ if (IS_ERR_OR_NULL(genpd))
+ return false;
+
+ list_for_each_entry(gpd, &gpd_list, gpd_list_node)
+ if (gpd == genpd)
+ return true;
+
+ return false;
+}
+
+/**
+ * genpd_xlate_simple() - Xlate function for direct node-domain mapping
+ * @genpdspec: OF phandle args to map into a PM domain
+ * @data: xlate function private data - pointer to struct generic_pm_domain
+ *
+ * This is a generic xlate function that can be used to model PM domains that
+ * have their own device tree nodes. The private data of xlate function needs
+ * to be a valid pointer to struct generic_pm_domain.
+ */
+static struct generic_pm_domain *genpd_xlate_simple(
+ struct of_phandle_args *genpdspec,
+ void *data)
+{
+ return data;
+}
+
+/**
+ * genpd_add_provider() - Register a PM domain provider for a node
+ * @np: Device node pointer associated with the PM domain provider.
+ * @xlate: Callback for decoding PM domain from phandle arguments.
+ * @data: Context pointer for @xlate callback.
+ */
+static int genpd_add_provider(struct device_node *np, genpd_xlate_t xlate,
+ void *data)
+{
+ struct of_genpd_provider *cp;
+
+ cp = kzalloc(sizeof(*cp), GFP_KERNEL);
+ if (!cp)
+ return -ENOMEM;
+
+ cp->node = np;
+ cp->data = data;
+ cp->xlate = xlate;
+
+ list_add(&cp->link, &of_genpd_providers);
+ pr_debug("Added domain provider from %pOF\n", np);
+
+ return 0;
+}
+
+/**
+ * of_genpd_add_provider_simple() - Register a simple PM domain provider
+ * @np: Device node pointer associated with the PM domain provider.
+ * @genpd: Pointer to PM domain associated with the PM domain provider.
+ */
+int of_genpd_add_provider_simple(struct device_node *np,
+ struct generic_pm_domain *genpd)
+{
+ int ret = -EINVAL;
+
+ if (!np || !genpd)
+ return -EINVAL;
+
+ if (genpd_present(genpd))
+ ret = genpd_add_provider(np, genpd_xlate_simple, genpd);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(of_genpd_add_provider_simple);
+
+/**
+ * genpd_get_from_provider() - Look-up PM domain
+ * @genpdspec: OF phandle args to use for look-up
+ *
+ * Looks for a PM domain provider under the node specified by @genpdspec and if
+ * found, uses xlate function of the provider to map phandle args to a PM
+ * domain.
+ *
+ * Returns a valid pointer to struct generic_pm_domain on success or ERR_PTR()
+ * on failure.
+ */
+static struct generic_pm_domain *genpd_get_from_provider(
+ struct of_phandle_args *genpdspec)
+{
+ struct generic_pm_domain *genpd = ERR_PTR(-ENOENT);
+ struct of_genpd_provider *provider;
+
+ if (!genpdspec)
+ return ERR_PTR(-EINVAL);
+
+ /* Check if we have such a provider in our array */
+ list_for_each_entry(provider, &of_genpd_providers, link) {
+ if (provider->node == genpdspec->np)
+ genpd = provider->xlate(genpdspec, provider->data);
+ if (!IS_ERR(genpd))
+ break;
+ }
+
+ return genpd;
+}
+
+static int _genpd_power_on(struct generic_pm_domain *genpd, bool timed)
+{
+ if (!genpd->power_on)
+ return 0;
+
+ return genpd->power_on(genpd);
+}
+
+/**
+ * genpd_power_on - Restore power to a given PM domain and its masters.
+ * @genpd: PM domain to power up.
+ * @depth: nesting count for lockdep.
+ *
+ * Restore power to @genpd and all of its masters so that it is possible to
+ * resume a device belonging to it.
+ */
+static int genpd_power_on(struct generic_pm_domain *genpd, unsigned int depth)
+{
+ int ret;
+
+ if (genpd_status_on(genpd))
+ return 0;
+
+ ret = _genpd_power_on(genpd, true);
+ if (ret)
+ return ret;
+
+ genpd->status = GPD_STATE_ACTIVE;
+
+ return 0;
+}
+
+static int __genpd_dev_pm_attach(struct device_d *dev, struct device_node *np,
+ unsigned int index, bool power_on)
+{
+ struct of_phandle_args pd_args;
+ struct generic_pm_domain *pd;
+ int ret;
+
+ ret = of_parse_phandle_with_args(np, "power-domains",
+ "#power-domain-cells", index, &pd_args);
+ if (ret < 0)
+ return ret;
+
+ pd = genpd_get_from_provider(&pd_args);
+ if (IS_ERR(pd)) {
+ ret = PTR_ERR(pd);
+ dev_dbg(dev, "%s() failed to find PM domain: %d\n",
+ __func__, ret);
+ /*
+ * Assume that missing genpds are unresolved
+ * dependency are report them as deferred
+ */
+ return (ret == -ENOENT) ? -EPROBE_DEFER : ret;
+ }
+
+ dev_dbg(dev, "adding to PM domain %s\n", pd->name);
+
+ if (power_on)
+ ret = genpd_power_on(pd, 0);
+
+ return ret ?: 1;
+}
+
+/**
+ * genpd_dev_pm_attach - Attach a device to its PM domain using DT.
+ * @dev: Device to attach.
+ *
+ * Parse device's OF node to find a PM domain specifier. If such is found,
+ * attaches the device to retrieved pm_domain ops.
+ *
+ * Returns 1 on successfully attached PM domain, 0 when the device don't need a
+ * PM domain or when multiple power-domains exists for it, else a negative error
+ * code. Note that if a power-domain exists for the device, but it cannot be
+ * found or turned on, then return -EPROBE_DEFER to ensure that the device is
+ * not probed and to re-try again later.
+ */
+int genpd_dev_pm_attach(struct device_d *dev)
+{
+ if (!dev->device_node)
+ return 0;
+
+ /*
+ * Devices with multiple PM domains must be attached separately, as we
+ * can only attach one PM domain per device.
+ */
+ if (of_count_phandle_with_args(dev->device_node, "power-domains",
+ "#power-domain-cells") != 1)
+ return 0;
+
+ return __genpd_dev_pm_attach(dev, dev->device_node, 0, true);
+}
+EXPORT_SYMBOL_GPL(genpd_dev_pm_attach);
diff --git a/drivers/net/fec_imx.c b/drivers/net/fec_imx.c
index 4823b08340..38a29fc83e 100644
--- a/drivers/net/fec_imx.c
+++ b/drivers/net/fec_imx.c
@@ -395,6 +395,13 @@ static void fec_halt(struct eth_device *dev)
struct fec_priv *fec = (struct fec_priv *)dev->priv;
uint32_t reg;
+ /*
+ * Only halt if fec has been started. Otherwise we would have to wait
+ * for the timeout below.
+ */
+ if (!(readl(fec->regs + FEC_ECNTRL) & FEC_ECNTRL_ETHER_EN))
+ return;
+
/* issue graceful stop command to the FEC transmitter if necessary */
writel(readl(fec->regs + FEC_X_CNTRL) | FEC_ECNTRL_RESET,
fec->regs + FEC_X_CNTRL);
diff --git a/drivers/pci/Kconfig b/drivers/pci/Kconfig
index 1c45a1c225..44a89d005f 100644
--- a/drivers/pci/Kconfig
+++ b/drivers/pci/Kconfig
@@ -41,8 +41,8 @@ config PCI_TEGRA
select PCI
config PCI_IMX6
- bool "Freescale i.MX6 PCIe controller"
- depends on ARCH_IMX6
+ bool "Freescale i.MX6/7/8 PCIe controller"
+ depends on ARCH_IMX6 || ARCH_IMX7 || ARCH_IMX8MQ
select PCIE_DW
select OF_PCI
select PCI
diff --git a/drivers/pci/pci-imx6.c b/drivers/pci/pci-imx6.c
index 38e002a1c6..138b4ca8b3 100644
--- a/drivers/pci/pci-imx6.c
+++ b/drivers/pci/pci-imx6.c
@@ -26,17 +26,37 @@
#include <linux/phy/phy.h>
#include <linux/reset.h>
#include <linux/sizes.h>
+#include <linux/bitfield.h>
#include <mfd/imx6q-iomuxc-gpr.h>
+#include <mfd/imx7-iomuxc-gpr.h>
#include <mach/imx6-regs.h>
+#include <mach/imx7-regs.h>
+#include <mach/imx8mq-regs.h>
#include "pcie-designware.h"
+#define IMX8MQ_GPR_PCIE_REF_USE_PAD BIT(9)
+#define IMX8MQ_GPR_PCIE_CLK_REQ_OVERRIDE_EN BIT(10)
+#define IMX8MQ_GPR_PCIE_CLK_REQ_OVERRIDE BIT(11)
+#define IMX8MQ_GPR12_PCIE2_CTRL_DEVICE_TYPE GENMASK(11, 8)
+#define IMX8MQ_PCIE2_BASE_ADDR 0x33c00000
+
#define to_imx6_pcie(x) ((x)->dev->priv)
enum imx6_pcie_variants {
IMX6Q,
IMX6QP,
+ IMX7D,
+ IMX8MQ,
+};
+
+#define IMX6_PCIE_FLAG_IMX6_PHY BIT(0)
+#define IMX6_PCIE_FLAG_IMX6_SPEED_CHANGE BIT(1)
+
+struct imx6_pcie_drvdata {
+ enum imx6_pcie_variants variant;
+ u32 flags;
};
struct imx6_pcie {
@@ -46,15 +66,23 @@ struct imx6_pcie {
struct clk *pcie_phy;
struct clk *pcie;
void __iomem *iomuxc_gpr;
- enum imx6_pcie_variants variant;
+ u32 controller_id;
+ struct reset_control *pciephy_reset;
+ struct reset_control *apps_reset;
u32 tx_deemph_gen1;
u32 tx_deemph_gen2_3p5db;
u32 tx_deemph_gen2_6db;
u32 tx_swing_full;
u32 tx_swing_low;
int link_gen;
+ const struct imx6_pcie_drvdata *drvdata;
};
+/* Parameters for the waiting for PCIe PHY PLL to lock on i.MX7 */
+#define PHY_PLL_LOCK_WAIT_MAX_RETRIES 2000
+#define PHY_PLL_LOCK_WAIT_USLEEP_MIN 50
+#define PHY_PLL_LOCK_WAIT_USLEEP_MAX 200
+
/* PCIe Root Complex registers (memory-mapped) */
#define PCIE_RC_LCR 0x7c
#define PCIE_RC_LCR_MAX_LINK_SPEEDS_GEN1 0x1
@@ -221,6 +249,9 @@ static void imx6_pcie_reset_phy(struct imx6_pcie *imx6_pcie)
{
uint32_t temp;
+ if (!(imx6_pcie->drvdata->flags & IMX6_PCIE_FLAG_IMX6_PHY))
+ return;
+
pcie_phy_read(imx6_pcie, PHY_RX_OVRD_IN_LO, &temp);
temp |= (PHY_RX_OVRD_IN_LO_RX_DATA_EN |
PHY_RX_OVRD_IN_LO_RX_PLL_EN);
@@ -238,7 +269,12 @@ static void imx6_pcie_assert_core_reset(struct imx6_pcie *imx6_pcie)
{
u32 gpr1;
- switch (imx6_pcie->variant) {
+ switch (imx6_pcie->drvdata->variant) {
+ case IMX7D:
+ case IMX8MQ:
+ reset_control_assert(imx6_pcie->pciephy_reset);
+ reset_control_assert(imx6_pcie->apps_reset);
+ break;
case IMX6QP:
gpr1 = readl(imx6_pcie->iomuxc_gpr + IOMUXC_GPR1);
gpr1 |= IMX6Q_GPR1_PCIE_SW_RST;
@@ -255,28 +291,74 @@ static void imx6_pcie_assert_core_reset(struct imx6_pcie *imx6_pcie)
}
}
+static unsigned int imx6_pcie_grp_offset(const struct imx6_pcie *imx6_pcie)
+{
+ WARN_ON(imx6_pcie->drvdata->variant != IMX8MQ);
+ return imx6_pcie->controller_id == 1 ? IOMUXC_GPR16 : IOMUXC_GPR14;
+}
+
static int imx6_pcie_enable_ref_clk(struct imx6_pcie *imx6_pcie)
{
- u32 gpr1;
+ u32 gpr1, gpr1x;
+ unsigned int offset;
- /* power up core phy and enable ref clock */
- gpr1 = readl(imx6_pcie->iomuxc_gpr + IOMUXC_GPR1);
- gpr1 &= ~IMX6Q_GPR1_PCIE_TEST_PD;
- writel(gpr1, imx6_pcie->iomuxc_gpr + IOMUXC_GPR1);
- /*
- * the async reset input need ref clock to sync internally,
- * when the ref clock comes after reset, internal synced
- * reset time is too short, cannot meet the requirement.
- * add one ~10us delay here.
- */
- udelay(10);
- gpr1 = readl(imx6_pcie->iomuxc_gpr + IOMUXC_GPR1);
- gpr1 |= IMX6Q_GPR1_PCIE_REF_CLK_EN;
- writel(gpr1, imx6_pcie->iomuxc_gpr + IOMUXC_GPR1);
+ switch (imx6_pcie->drvdata->variant) {
+ case IMX6QP:
+ case IMX6Q: /* FALLTHROUGH */
+ /* power up core phy and enable ref clock */
+ gpr1 = readl(imx6_pcie->iomuxc_gpr + IOMUXC_GPR1);
+ gpr1 &= ~IMX6Q_GPR1_PCIE_TEST_PD;
+ writel(gpr1, imx6_pcie->iomuxc_gpr + IOMUXC_GPR1);
+ /*
+ * the async reset input need ref clock to sync
+ * internally, when the ref clock comes after reset,
+ * internal synced reset time is too short, cannot
+ * meet the requirement. add one ~10us delay here.
+ */
+ udelay(10);
+ gpr1 = readl(imx6_pcie->iomuxc_gpr + IOMUXC_GPR1);
+ gpr1 |= IMX6Q_GPR1_PCIE_REF_CLK_EN;
+ writel(gpr1, imx6_pcie->iomuxc_gpr + IOMUXC_GPR1);
+ break;
+ case IMX7D:
+ break;
+ case IMX8MQ:
+ offset = imx6_pcie_grp_offset(imx6_pcie);
+ /*
+ * Set the over ride low and enabled
+ * make sure that REF_CLK is turned on.
+ */
+ gpr1x = readl(imx6_pcie->iomuxc_gpr + offset);
+ gpr1x &= ~IMX8MQ_GPR_PCIE_CLK_REQ_OVERRIDE;
+ writel(gpr1x, imx6_pcie->iomuxc_gpr + offset);
+
+ gpr1x = readl(imx6_pcie->iomuxc_gpr + offset);
+ gpr1x |= IMX8MQ_GPR_PCIE_CLK_REQ_OVERRIDE_EN;
+ writel(gpr1x, imx6_pcie->iomuxc_gpr + offset);
+ break;
+ }
return 0;
}
+static void imx7d_pcie_wait_for_phy_pll_lock(struct imx6_pcie *imx6_pcie)
+{
+ u32 val;
+ unsigned int retries;
+ struct device_d *dev = imx6_pcie->pci->dev;
+
+ for (retries = 0; retries < PHY_PLL_LOCK_WAIT_MAX_RETRIES; retries++) {
+ val = readl(imx6_pcie->iomuxc_gpr + IOMUXC_GPR22);
+
+ if (val & IMX7D_GPR22_PCIE_PHY_PLL_LOCKED)
+ return;
+
+ udelay(PHY_PLL_LOCK_WAIT_USLEEP_MAX);
+ }
+
+ dev_err(dev, "PCIe PLL lock timeout\n");
+}
+
static void imx6_pcie_deassert_core_reset(struct imx6_pcie *imx6_pcie)
{
struct device_d *dev = imx6_pcie->pci->dev;
@@ -320,7 +402,14 @@ static void imx6_pcie_deassert_core_reset(struct imx6_pcie *imx6_pcie)
/*
* Release the PCIe PHY reset here
*/
- switch (imx6_pcie->variant) {
+ switch (imx6_pcie->drvdata->variant) {
+ case IMX8MQ:
+ reset_control_deassert(imx6_pcie->pciephy_reset);
+ break;
+ case IMX7D:
+ reset_control_deassert(imx6_pcie->pciephy_reset);
+ imx7d_pcie_wait_for_phy_pll_lock(imx6_pcie);
+ break;
case IMX6QP:
gpr1 = readl(imx6_pcie->iomuxc_gpr + IOMUXC_GPR1);
gpr1 &= ~IMX6Q_GPR1_PCIE_SW_RST;
@@ -342,43 +431,84 @@ err_pcie_bus:
clk_disable(imx6_pcie->pcie_phy);
}
-static void imx6_pcie_init_phy(struct imx6_pcie *imx6_pcie)
+static void imx6_pcie_configure_type(struct imx6_pcie *imx6_pcie)
{
- u32 gpr12, gpr8;
+ unsigned int mask, val;
+ u32 gpr12;
- gpr12 = readl(imx6_pcie->iomuxc_gpr + IOMUXC_GPR12);
- gpr12 &= ~IMX6Q_GPR12_PCIE_CTL_2;
- writel(gpr12, imx6_pcie->iomuxc_gpr + IOMUXC_GPR12);
+ if (imx6_pcie->drvdata->variant == IMX8MQ &&
+ imx6_pcie->controller_id == 1) {
+ mask = IMX8MQ_GPR12_PCIE2_CTRL_DEVICE_TYPE;
+ val = FIELD_PREP(IMX8MQ_GPR12_PCIE2_CTRL_DEVICE_TYPE,
+ PCI_EXP_TYPE_ROOT_PORT);
+ } else {
+ mask = IMX6Q_GPR12_DEVICE_TYPE;
+ val = FIELD_PREP(IMX6Q_GPR12_DEVICE_TYPE,
+ PCI_EXP_TYPE_ROOT_PORT);
+ }
- /* configure constant input signal to the pcie ctrl and phy */
- gpr12 &= ~IMX6Q_GPR12_DEVICE_TYPE;
- gpr12 |= PCI_EXP_TYPE_ROOT_PORT << 12;
+ gpr12 = readl(imx6_pcie->iomuxc_gpr + IOMUXC_GPR12);
+ gpr12 &= ~mask;
+ gpr12 |= val;
writel(gpr12, imx6_pcie->iomuxc_gpr + IOMUXC_GPR12);
+}
- gpr12 &= ~IMX6Q_GPR12_LOS_LEVEL;
- gpr12 |= 9 << 4;
- writel(gpr12, imx6_pcie->iomuxc_gpr + IOMUXC_GPR12);
+static void imx6_pcie_init_phy(struct imx6_pcie *imx6_pcie)
+{
+ u32 gpr12, gpr8, gpr1x;
+ unsigned int offset;
- gpr8 = readl(imx6_pcie->iomuxc_gpr + IOMUXC_GPR8);
- gpr8 &= ~IMX6Q_GPR8_TX_DEEMPH_GEN1;
- gpr8 |= imx6_pcie->tx_deemph_gen1 << 0;
- writel(gpr8, imx6_pcie->iomuxc_gpr + IOMUXC_GPR8);
+ switch (imx6_pcie->drvdata->variant) {
+ case IMX8MQ:
+ offset = imx6_pcie_grp_offset(imx6_pcie);
+ /*
+ * TODO: Currently this code assumes external
+ * oscillator is being used
+ */
+ gpr1x = readl(imx6_pcie->iomuxc_gpr + offset);
+ gpr1x |= IMX8MQ_GPR_PCIE_REF_USE_PAD;
+ writel(gpr1x, imx6_pcie->iomuxc_gpr + offset);
+ break;
+ case IMX7D:
+ gpr12 = readl(imx6_pcie->iomuxc_gpr + IOMUXC_GPR12);
+ gpr12 &= ~IMX7D_GPR12_PCIE_PHY_REFCLK_SEL;
+ writel(gpr12, imx6_pcie->iomuxc_gpr + IOMUXC_GPR12);
+ break;
+ case IMX6QP:
+ case IMX6Q: /* FALLTHROUGH */
+ gpr12 = readl(imx6_pcie->iomuxc_gpr + IOMUXC_GPR12);
+ gpr12 &= ~IMX6Q_GPR12_PCIE_CTL_2;
+ writel(gpr12, imx6_pcie->iomuxc_gpr + IOMUXC_GPR12);
- gpr8 &= ~IMX6Q_GPR8_TX_DEEMPH_GEN2_3P5DB;
- gpr8 |= imx6_pcie->tx_deemph_gen2_3p5db << 6;
- writel(gpr8, imx6_pcie->iomuxc_gpr + IOMUXC_GPR8);
+ /* configure constant input signal to the pcie ctrl and phy */
+ gpr12 &= ~IMX6Q_GPR12_LOS_LEVEL;
+ gpr12 |= 9 << 4;
+ writel(gpr12, imx6_pcie->iomuxc_gpr + IOMUXC_GPR12);
- gpr8 &= ~IMX6Q_GPR8_TX_DEEMPH_GEN2_6DB;
- gpr8 |= imx6_pcie->tx_deemph_gen2_6db << 12;
- writel(gpr8, imx6_pcie->iomuxc_gpr + IOMUXC_GPR8);
+ gpr8 = readl(imx6_pcie->iomuxc_gpr + IOMUXC_GPR8);
+ gpr8 &= ~IMX6Q_GPR8_TX_DEEMPH_GEN1;
+ gpr8 |= imx6_pcie->tx_deemph_gen1 << 0;
+ writel(gpr8, imx6_pcie->iomuxc_gpr + IOMUXC_GPR8);
- gpr8 &= ~IMX6Q_GPR8_TX_SWING_FULL;
- gpr8 |= imx6_pcie->tx_swing_full << 18;
- writel(gpr8, imx6_pcie->iomuxc_gpr + IOMUXC_GPR8);
+ gpr8 &= ~IMX6Q_GPR8_TX_DEEMPH_GEN2_3P5DB;
+ gpr8 |= imx6_pcie->tx_deemph_gen2_3p5db << 6;
+ writel(gpr8, imx6_pcie->iomuxc_gpr + IOMUXC_GPR8);
- gpr8 &= ~IMX6Q_GPR8_TX_SWING_LOW;
- gpr8 |= imx6_pcie->tx_swing_low << 25;
- writel(gpr8, imx6_pcie->iomuxc_gpr + IOMUXC_GPR8);
+ gpr8 &= ~IMX6Q_GPR8_TX_DEEMPH_GEN2_6DB;
+ gpr8 |= imx6_pcie->tx_deemph_gen2_6db << 12;
+ writel(gpr8, imx6_pcie->iomuxc_gpr + IOMUXC_GPR8);
+
+ gpr8 &= ~IMX6Q_GPR8_TX_SWING_FULL;
+ gpr8 |= imx6_pcie->tx_swing_full << 18;
+ writel(gpr8, imx6_pcie->iomuxc_gpr + IOMUXC_GPR8);
+
+ gpr8 &= ~IMX6Q_GPR8_TX_SWING_LOW;
+ gpr8 |= imx6_pcie->tx_swing_low << 25;
+ writel(gpr8, imx6_pcie->iomuxc_gpr + IOMUXC_GPR8);
+ break;
+ }
+
+ imx6_pcie_configure_type(imx6_pcie);
}
static int imx6_pcie_wait_for_link(struct imx6_pcie *imx6_pcie)
@@ -404,6 +534,24 @@ static int imx6_pcie_wait_for_speed_change(struct imx6_pcie *imx6_pcie)
return -EINVAL;
}
+static void imx6_pcie_ltssm_enable(struct device_d *dev)
+{
+ struct imx6_pcie *imx6_pcie = dev->priv;
+ u32 gpr12;
+
+ switch (imx6_pcie->drvdata->variant) {
+ case IMX6Q:
+ case IMX6QP:
+ gpr12 = readl(imx6_pcie->iomuxc_gpr + IOMUXC_GPR12);
+ gpr12 |= IMX6Q_GPR12_PCIE_CTL_2;
+ writel(gpr12, imx6_pcie->iomuxc_gpr + IOMUXC_GPR12);
+ break;
+ case IMX7D:
+ case IMX8MQ:
+ reset_control_deassert(imx6_pcie->apps_reset);
+ break;
+ }
+}
static int imx6_pcie_establish_link(struct imx6_pcie *imx6_pcie)
{
@@ -411,7 +559,6 @@ static int imx6_pcie_establish_link(struct imx6_pcie *imx6_pcie)
struct device_d *dev = pci->dev;
uint32_t tmp;
int ret;
- u32 gpr12;
/*
* Force Gen1 operation when starting the link. In case the link is
@@ -423,10 +570,7 @@ static int imx6_pcie_establish_link(struct imx6_pcie *imx6_pcie)
tmp |= PCIE_RC_LCR_MAX_LINK_SPEEDS_GEN1;
dw_pcie_writel_dbi(pci, PCIE_RC_LCR, tmp);
- /* Start LTSSM. */
- gpr12 = readl(imx6_pcie->iomuxc_gpr + IOMUXC_GPR12);
- gpr12 |= IMX6Q_GPR12_PCIE_CTL_2;
- writel(gpr12, imx6_pcie->iomuxc_gpr + IOMUXC_GPR12);
+ imx6_pcie_ltssm_enable(dev);
ret = imx6_pcie_wait_for_link(imx6_pcie);
if (ret)
@@ -439,30 +583,43 @@ static int imx6_pcie_establish_link(struct imx6_pcie *imx6_pcie)
tmp &= ~PCIE_RC_LCR_MAX_LINK_SPEEDS_MASK;
tmp |= PCIE_RC_LCR_MAX_LINK_SPEEDS_GEN2;
dw_pcie_writel_dbi(pci, PCIE_RC_LCR, tmp);
- } else {
- dev_info(dev, "Link: Gen2 disabled\n");
- }
- /*
- * Start Directed Speed Change so the best possible speed both link
- * partners support can be negotiated.
- */
- tmp = dw_pcie_readl_dbi(pci, PCIE_LINK_WIDTH_SPEED_CONTROL);
- tmp |= PORT_LOGIC_SPEED_CHANGE;
- dw_pcie_writel_dbi(pci, PCIE_LINK_WIDTH_SPEED_CONTROL, tmp);
-
- ret = imx6_pcie_wait_for_speed_change(imx6_pcie);
- if (ret) {
- dev_err(dev, "Failed to bring link up!\n");
- goto err_reset_phy;
- }
+ /*
+ * Start Directed Speed Change so the best possible
+ * speed both link partners support can be negotiated.
+ */
+ tmp = dw_pcie_readl_dbi(pci, PCIE_LINK_WIDTH_SPEED_CONTROL);
+ tmp |= PORT_LOGIC_SPEED_CHANGE;
+ dw_pcie_writel_dbi(pci, PCIE_LINK_WIDTH_SPEED_CONTROL, tmp);
+
+ if (imx6_pcie->drvdata->flags &
+ IMX6_PCIE_FLAG_IMX6_SPEED_CHANGE) {
+ /*
+ * On i.MX7, DIRECT_SPEED_CHANGE behaves
+ * differently from i.MX6 family when no link
+ * speed transition occurs and we go Gen1 ->
+ * yep, Gen1. The difference is that, in such
+ * case, it will not be cleared by HW which
+ * will cause the following code to report
+ * false failure.
+ */
+
+ ret = imx6_pcie_wait_for_speed_change(imx6_pcie);
+ if (ret) {
+ dev_err(dev, "Failed to bring link up!\n");
+ goto err_reset_phy;
+ }
+ }
- /* Make sure link training is finished as well! */
- ret = imx6_pcie_wait_for_link(imx6_pcie);
- if (ret) {
- dev_err(dev, "Failed to bring link up!\n");
- goto err_reset_phy;
- }
+ /* Make sure link training is finished as well! */
+ ret = imx6_pcie_wait_for_link(imx6_pcie);
+ if (ret) {
+ dev_err(dev, "Failed to bring link up!\n");
+ goto err_reset_phy;
+ }
+ } else {
+ dev_info(dev, "Link: Gen2 disabled\n");
+ }
tmp = dw_pcie_readl_dbi(pci, PCIE_RC_LCSR);
dev_info(dev, "Link up, Gen%i\n", (tmp >> 16) & 0xf);
@@ -505,14 +662,13 @@ static const struct dw_pcie_host_ops imx6_pcie_host_ops = {
.host_init = imx6_pcie_host_init,
};
-static int __init imx6_add_pcie_port(struct imx6_pcie *imx6_pcie,
- struct device_d *dev)
+static int imx6_add_pcie_port(struct imx6_pcie *imx6_pcie,
+ struct device_d *dev)
{
struct dw_pcie *pci = imx6_pcie->pci;
struct pcie_port *pp = &pci->pp;
int ret;
- pp->root_bus_nr = -1;
pp->ops = &imx6_pcie_host_ops;
ret = dw_pcie_host_init(pp);
@@ -524,7 +680,7 @@ static int __init imx6_add_pcie_port(struct imx6_pcie *imx6_pcie,
return 0;
}
-static int __init imx6_pcie_probe(struct device_d *dev)
+static int imx6_pcie_probe(struct device_d *dev)
{
struct resource *iores;
struct dw_pcie *pci;
@@ -539,16 +695,13 @@ static int __init imx6_pcie_probe(struct device_d *dev)
pci->ops = &dw_pcie_ops;
imx6_pcie->pci = pci;
- imx6_pcie->variant =
- (enum imx6_pcie_variants)of_device_get_match_data(dev);
-
- iores = dev_request_mem_resource(dev, 0);
- if (IS_ERR(iores))
- return PTR_ERR(iores);
- pci->dbi_base = IOMEM(iores->start);
+ imx6_pcie->drvdata = of_device_get_match_data(dev);
/* Fetch GPIOs */
imx6_pcie->reset_gpio = of_get_named_gpio(np, "reset-gpio", 0);
+ if (imx6_pcie->reset_gpio == -EPROBE_DEFER)
+ return imx6_pcie->reset_gpio;
+
if (gpio_is_valid(imx6_pcie->reset_gpio)) {
ret = gpio_request_one(imx6_pcie->reset_gpio,
GPIOF_OUT_INIT_LOW, "PCIe reset");
@@ -558,6 +711,11 @@ static int __init imx6_pcie_probe(struct device_d *dev)
}
}
+ iores = dev_request_mem_resource(dev, 0);
+ if (IS_ERR(iores))
+ return PTR_ERR(iores);
+ pci->dbi_base = IOMEM(iores->start);
+
/* Fetch clocks */
imx6_pcie->pcie_phy = clk_get(dev, "pcie_phy");
if (IS_ERR(imx6_pcie->pcie_phy)) {
@@ -577,8 +735,35 @@ static int __init imx6_pcie_probe(struct device_d *dev)
return PTR_ERR(imx6_pcie->pcie);
}
- /* Grab GPR config register range */
- imx6_pcie->iomuxc_gpr = IOMEM(MX6_IOMUXC_BASE_ADDR);
+
+ switch (imx6_pcie->drvdata->variant) {
+ case IMX8MQ:
+ imx6_pcie->iomuxc_gpr = IOMEM(MX8MQ_IOMUXC_GPR_BASE_ADDR);
+ if (iores->start == IMX8MQ_PCIE2_BASE_ADDR)
+ imx6_pcie->controller_id = 1;
+
+ goto imx7d_init;
+ case IMX7D:
+ imx6_pcie->iomuxc_gpr = IOMEM(MX7_IOMUXC_GPR_BASE_ADDR);
+ imx7d_init:
+ imx6_pcie->pciephy_reset = reset_control_get(dev, "pciephy");
+ if (IS_ERR(imx6_pcie->pciephy_reset)) {
+ dev_err(dev, "Failed to get PCIEPHY reset control\n");
+ return PTR_ERR(imx6_pcie->pciephy_reset);
+ }
+
+ imx6_pcie->apps_reset = reset_control_get(dev, "apps");
+ if (IS_ERR(imx6_pcie->apps_reset)) {
+ dev_err(dev, "Failed to get PCIE APPS reset control\n");
+ return PTR_ERR(imx6_pcie->apps_reset);
+ }
+ break;
+ default:
+ /* Grab GPR config register range */
+ imx6_pcie->iomuxc_gpr = IOMEM(MX6_IOMUXC_BASE_ADDR);
+ break;
+ }
+
/* Grab PCIe PHY Tx Settings */
if (of_property_read_u32(np, "fsl,tx-deemph-gen1",
@@ -620,7 +805,7 @@ static void imx6_pcie_remove(struct device_d *dev)
{
struct imx6_pcie *imx6_pcie = dev->priv;
- if (imx6_pcie->variant == IMX6Q) {
+ if (imx6_pcie->drvdata->variant == IMX6Q) {
/*
* If the bootloader already enabled the link we need
* some special handling to get the core back into a
@@ -650,9 +835,30 @@ static void imx6_pcie_remove(struct device_d *dev)
imx6_pcie_assert_core_reset(imx6_pcie);
}
+static const struct imx6_pcie_drvdata drvdata[] = {
+ [IMX6Q] = {
+ .variant = IMX6Q,
+ .flags = IMX6_PCIE_FLAG_IMX6_PHY |
+ IMX6_PCIE_FLAG_IMX6_SPEED_CHANGE,
+ },
+ [IMX6QP] = {
+ .variant = IMX6QP,
+ .flags = IMX6_PCIE_FLAG_IMX6_PHY |
+ IMX6_PCIE_FLAG_IMX6_SPEED_CHANGE,
+ },
+ [IMX7D] = {
+ .variant = IMX7D,
+ },
+ [IMX8MQ] = {
+ .variant = IMX8MQ,
+ },
+};
+
static struct of_device_id imx6_pcie_of_match[] = {
- { .compatible = "fsl,imx6q-pcie", .data = (void *)IMX6Q, },
- { .compatible = "fsl,imx6qp-pcie", .data = (void *)IMX6QP, },
+ { .compatible = "fsl,imx6q-pcie", .data = &drvdata[IMX6Q], },
+ { .compatible = "fsl,imx6qp-pcie", .data = &drvdata[IMX6QP], },
+ { .compatible = "fsl,imx7d-pcie", .data = &drvdata[IMX7D], },
+ { .compatible = "fsl,imx8mq-pcie", .data = &drvdata[IMX8MQ], } ,
{},
};
diff --git a/drivers/pci/pcie-designware-host.c b/drivers/pci/pcie-designware-host.c
index 6cc4b93a31..dc38cdc8f6 100644
--- a/drivers/pci/pcie-designware-host.c
+++ b/drivers/pci/pcie-designware-host.c
@@ -150,15 +150,15 @@ int __init dw_pcie_host_init(struct pcie_port *pp)
}
if (!pci->dbi_base)
- pci->dbi_base = (void __force *)pp->cfg.start;
+ pci->dbi_base = IOMEM(pp->cfg.start);
pp->mem_base = pp->mem.start;
if (!pp->va_cfg0_base)
- pp->va_cfg0_base = (void __force *)(u32)pp->cfg0_base;
+ pp->va_cfg0_base = IOMEM((unsigned long)pp->cfg0_base);
if (!pp->va_cfg1_base)
- pp->va_cfg1_base = (void __force *)(u32)pp->cfg1_base;
+ pp->va_cfg1_base = IOMEM((unsigned long)pp->cfg1_base);
ret = of_property_read_u32(np, "num-viewport", &pci->num_viewport);
if (ret)
diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig
index 92db8dc0e0..c734ef5ef9 100644
--- a/drivers/regulator/Kconfig
+++ b/drivers/regulator/Kconfig
@@ -21,4 +21,12 @@ config REGULATOR_PFUZE
depends on I2C
depends on ARCH_IMX6
+config REGULATOR_ANATOP
+ tristate "Freescale i.MX on-chip ANATOP LDO regulators"
+ depends on MFD_SYSCON
+ help
+ Say y here to support Freescale i.MX on-chip ANATOP LDOs
+ regulators. It is recommended that this option be
+ enabled on i.MX6 platform.
+
endif
diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile
index ff5daf9a7d..b2fc5b79b6 100644
--- a/drivers/regulator/Makefile
+++ b/drivers/regulator/Makefile
@@ -1,4 +1,5 @@
-obj-$(CONFIG_REGULATOR) += core.o
+obj-$(CONFIG_REGULATOR) += core.o helpers.o
obj-$(CONFIG_REGULATOR_FIXED) += fixed.o
obj-$(CONFIG_REGULATOR_BCM283X) += bcm2835.o
-obj-$(CONFIG_REGULATOR_PFUZE) += pfuze.o \ No newline at end of file
+obj-$(CONFIG_REGULATOR_PFUZE) += pfuze.o
+obj-$(CONFIG_REGULATOR_ANATOP) += anatop-regulator.o \ No newline at end of file
diff --git a/drivers/regulator/anatop-regulator.c b/drivers/regulator/anatop-regulator.c
new file mode 100644
index 0000000000..7ec9446a0a
--- /dev/null
+++ b/drivers/regulator/anatop-regulator.c
@@ -0,0 +1,162 @@
+/*
+ * Copyright (C) 2011 Freescale Semiconductor, Inc. All Rights Reserved.
+ */
+
+/*
+ * 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, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <common.h>
+#include <init.h>
+#include <mfd/syscon.h>
+#include <regmap.h>
+#include <regulator.h>
+
+struct anatop_regulator {
+ u32 control_reg;
+ struct regmap *anatop;
+ int vol_bit_shift;
+ int vol_bit_width;
+ u32 delay_reg;
+ int delay_bit_shift;
+ int delay_bit_width;
+ int min_bit_val;
+ int min_voltage;
+ int max_voltage;
+
+ struct regulator_dev rdev;
+ struct regulator_desc rdesc;
+
+ bool bypass;
+ int sel;
+};
+
+static struct regulator_ops anatop_rops = {
+ .set_voltage_sel = regulator_set_voltage_sel_regmap,
+ .list_voltage = regulator_list_voltage_linear,
+};
+
+static int anatop_regulator_probe(struct device_d *dev)
+{
+ struct device_node *np = dev->device_node;
+ struct device_node *anatop_np;
+ struct regulator_desc *rdesc;
+ struct regulator_dev *rdev;
+ struct anatop_regulator *sreg;
+ int ret = 0;
+
+ sreg = xzalloc(sizeof(*sreg));
+ rdesc = &sreg->rdesc;
+ rdev = &sreg->rdev;
+
+ anatop_np = of_get_parent(np);
+ if (!anatop_np)
+ return -ENODEV;
+
+ rdev->desc = rdesc;
+ rdev->regmap = syscon_node_to_regmap(anatop_np);
+ if (IS_ERR(rdev->regmap))
+ return PTR_ERR(rdev->regmap);
+
+ ret = of_property_read_u32(np, "anatop-reg-offset",
+ &sreg->control_reg);
+ if (ret) {
+ dev_err(dev, "no anatop-reg-offset property set\n");
+ return ret;
+ }
+ ret = of_property_read_u32(np, "anatop-vol-bit-width",
+ &sreg->vol_bit_width);
+ if (ret) {
+ dev_err(dev, "no anatop-vol-bit-width property set\n");
+ return ret;
+ }
+ ret = of_property_read_u32(np, "anatop-vol-bit-shift",
+ &sreg->vol_bit_shift);
+ if (ret) {
+ dev_err(dev, "no anatop-vol-bit-shift property set\n");
+ return ret;
+ }
+ ret = of_property_read_u32(np, "anatop-min-bit-val",
+ &sreg->min_bit_val);
+ if (ret) {
+ dev_err(dev, "no anatop-min-bit-val property set\n");
+ return ret;
+ }
+ ret = of_property_read_u32(np, "anatop-min-voltage",
+ &sreg->min_voltage);
+ if (ret) {
+ dev_err(dev, "no anatop-min-voltage property set\n");
+ return ret;
+ }
+ ret = of_property_read_u32(np, "anatop-max-voltage",
+ &sreg->max_voltage);
+ if (ret) {
+ dev_err(dev, "no anatop-max-voltage property set\n");
+ return ret;
+ }
+
+ /* read LDO ramp up setting, only for core reg */
+ of_property_read_u32(np, "anatop-delay-reg-offset",
+ &sreg->delay_reg);
+ of_property_read_u32(np, "anatop-delay-bit-width",
+ &sreg->delay_bit_width);
+ of_property_read_u32(np, "anatop-delay-bit-shift",
+ &sreg->delay_bit_shift);
+
+ rdesc->n_voltages = (sreg->max_voltage - sreg->min_voltage) / 25000 + 1
+ + sreg->min_bit_val;
+ rdesc->min_uV = sreg->min_voltage;
+ rdesc->uV_step = 25000;
+ rdesc->linear_min_sel = sreg->min_bit_val;
+ rdesc->vsel_reg = sreg->control_reg;
+ rdesc->vsel_mask = GENMASK(sreg->vol_bit_width + sreg->vol_bit_shift,
+ sreg->vol_bit_shift);
+
+ /* Only core regulators have the ramp up delay configuration. */
+ if (sreg->control_reg && sreg->delay_bit_width) {
+ free(sreg);
+ /* FIXME: This case is not supported */
+ return 0;
+ } else {
+ u32 enable_bit;
+
+ rdesc->ops = &anatop_rops;
+
+ if (!of_property_read_u32(np, "anatop-enable-bit",
+ &enable_bit)) {
+ anatop_rops.enable = regulator_enable_regmap;
+ anatop_rops.disable = regulator_disable_regmap;
+ anatop_rops.is_enabled = regulator_is_enabled_regmap;
+
+ rdesc->enable_reg = sreg->control_reg;
+ rdesc->enable_mask = BIT(enable_bit);
+ }
+ }
+
+ return of_regulator_register(rdev, dev->device_node);
+}
+
+static const struct of_device_id of_anatop_regulator_match_tbl[] = {
+ { .compatible = "fsl,anatop-regulator", },
+ { /* end */ }
+};
+
+static struct driver_d anatop_regulator_driver = {
+ .name = "anatop_regulator",
+ .probe = anatop_regulator_probe,
+ .of_compatible = DRV_OF_COMPAT(of_anatop_regulator_match_tbl),
+};
+device_platform_driver(anatop_regulator_driver);
+
diff --git a/drivers/regulator/bcm2835.c b/drivers/regulator/bcm2835.c
index 0ada05db16..ea7cf7fe1e 100644
--- a/drivers/regulator/bcm2835.c
+++ b/drivers/regulator/bcm2835.c
@@ -24,6 +24,7 @@ static struct regulator_bcm2835 {
struct device_d *dev;
struct regulator_dev rdev;
+ struct regulator_desc rdesc;
} regs[] = {
REG_DEV(BCM2835_MBOX_POWER_DEVID_SDHCI, "bcm2835_mci0"),
REG_DEV(BCM2835_MBOX_POWER_DEVID_UART0, "uart0-pl0110"),
@@ -108,7 +109,7 @@ static int regulator_bcm2835_is_enabled(struct regulator_dev *rdev)
return msg_pwr->get_power_state.body.resp.state;
}
-static struct regulator_ops bcm2835_ops = {
+const static struct regulator_ops bcm2835_ops = {
.enable = regulator_bcm2835_enable,
.disable = regulator_bcm2835_disable,
.is_enabled = regulator_bcm2835_is_enabled,
@@ -122,7 +123,8 @@ static int regulator_bcm2835_probe(struct device_d *dev)
for (i = 0; i < ARRAY_SIZE(regs); i++) {
rb = &regs[i];
- rb->rdev.ops = &bcm2835_ops;
+ rb->rdesc.ops = &bcm2835_ops;
+ rb->rdev.desc = &rb->rdesc;
rb->dev = dev;
ret = dev_regulator_register(&rb->rdev, rb->devname, NULL);
diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c
index 39df980dcb..4ca035ae94 100644
--- a/drivers/regulator/core.c
+++ b/drivers/regulator/core.c
@@ -43,6 +43,15 @@ struct regulator {
struct device_d *dev;
};
+static int regulator_map_voltage(struct regulator_dev *rdev, int min_uV,
+ int max_uV)
+{
+ if (rdev->desc->ops->list_voltage == regulator_list_voltage_linear)
+ return regulator_map_voltage_linear(rdev, min_uV, max_uV);
+
+ return -ENOSYS;
+}
+
static int regulator_enable_internal(struct regulator_internal *ri)
{
int ret;
@@ -52,10 +61,10 @@ static int regulator_enable_internal(struct regulator_internal *ri)
return 0;
}
- if (!ri->rdev->ops->enable)
+ if (!ri->rdev->desc->ops->enable)
return -ENOSYS;
- ret = ri->rdev->ops->enable(ri->rdev);
+ ret = ri->rdev->desc->ops->enable(ri->rdev);
if (ret)
return ret;
@@ -74,10 +83,10 @@ static int regulator_disable_internal(struct regulator_internal *ri)
if (!ri->enable_count)
return -EINVAL;
- if (!ri->rdev->ops->disable)
+ if (!ri->rdev->desc->ops->disable)
return -ENOSYS;
- ret = ri->rdev->ops->disable(ri->rdev);
+ ret = ri->rdev->desc->ops->disable(ri->rdev);
if (ret)
return ret;
@@ -86,6 +95,33 @@ static int regulator_disable_internal(struct regulator_internal *ri)
return 0;
}
+static int regulator_set_voltage_internal(struct regulator_internal *ri,
+ int min_uV, int max_uV)
+{
+ struct regulator_dev *rdev = ri->rdev;
+ const struct regulator_ops *ops = rdev->desc->ops;
+ unsigned int selector;
+ int best_val = 0;
+ int ret;
+
+ if (ops->set_voltage_sel) {
+ ret = regulator_map_voltage(rdev, min_uV, max_uV);
+ if (ret >= 0) {
+ best_val = ops->list_voltage(rdev, ret);
+ if (min_uV <= best_val && max_uV >= best_val) {
+ selector = ret;
+ ret = ops->set_voltage_sel(rdev, selector);
+ } else {
+ ret = -EINVAL;
+ }
+ }
+
+ return ret;
+ }
+
+ return -ENOSYS;
+}
+
static struct regulator_internal * __regulator_register(struct regulator_dev *rd, const char *name)
{
struct regulator_internal *ri;
@@ -191,7 +227,12 @@ static struct regulator_internal *of_regulator_get(struct device_d *dev, const c
}
}
- ri = ERR_PTR(-ENODEV);
+ /*
+ * It is possible that regulator we are looking for will be
+ * added in future initcalls, so, instead of reporting a
+ * complete failure report probe deferral
+ */
+ ri = ERR_PTR(-EPROBE_DEFER);
out:
free(propname);
@@ -320,6 +361,14 @@ int regulator_disable(struct regulator *r)
return regulator_disable_internal(r->ri);
}
+int regulator_set_voltage(struct regulator *r, int min_uV, int max_uV)
+{
+ if (!r)
+ return 0;
+
+ return regulator_set_voltage_internal(r->ri, min_uV, max_uV);
+}
+
static void regulator_print_one(struct regulator_internal *ri)
{
struct regulator *r;
diff --git a/drivers/regulator/fixed.c b/drivers/regulator/fixed.c
index 87554d22e3..cb5d785817 100644
--- a/drivers/regulator/fixed.c
+++ b/drivers/regulator/fixed.c
@@ -29,6 +29,7 @@ struct regulator_fixed {
int active_low;
int always_on;
struct regulator_dev rdev;
+ struct regulator_desc rdesc;
};
static int regulator_fixed_enable(struct regulator_dev *rdev)
@@ -54,7 +55,7 @@ static int regulator_fixed_disable(struct regulator_dev *rdev)
return gpio_direction_output(fix->gpio, fix->active_low);
}
-static struct regulator_ops fixed_ops = {
+const static struct regulator_ops fixed_ops = {
.enable = regulator_fixed_enable,
.disable = regulator_fixed_disable,
};
@@ -82,7 +83,8 @@ static int regulator_fixed_probe(struct device_d *dev)
fix->active_low = 1;
}
- fix->rdev.ops = &fixed_ops;
+ fix->rdesc.ops = &fixed_ops;
+ fix->rdev.desc = &fix->rdesc;
if (of_find_property(dev->device_node, "regulator-always-on", NULL)) {
fix->always_on = 1;
diff --git a/drivers/regulator/helpers.c b/drivers/regulator/helpers.c
new file mode 100644
index 0000000000..f22d21b35d
--- /dev/null
+++ b/drivers/regulator/helpers.c
@@ -0,0 +1,186 @@
+#include <common.h>
+#include <regmap.h>
+#include <regulator.h>
+
+/**
+ * regulator_is_enabled_regmap - standard is_enabled() for regmap users
+ *
+ * @rdev: regulator to operate on
+ *
+ * Regulators that use regmap for their register I/O can set the
+ * enable_reg and enable_mask fields in their descriptor and then use
+ * this as their is_enabled operation, saving some code.
+ */
+int regulator_is_enabled_regmap(struct regulator_dev *rdev)
+{
+ unsigned int val;
+ int ret;
+
+ ret = regmap_read(rdev->regmap, rdev->desc->enable_reg, &val);
+ if (ret != 0)
+ return ret;
+
+ val &= rdev->desc->enable_mask;
+
+ if (rdev->desc->enable_is_inverted) {
+ if (rdev->desc->enable_val)
+ return val != rdev->desc->enable_val;
+ return val == 0;
+ } else {
+ if (rdev->desc->enable_val)
+ return val == rdev->desc->enable_val;
+ return val != 0;
+ }
+}
+EXPORT_SYMBOL_GPL(regulator_is_enabled_regmap);
+
+/**
+ * regulator_enable_regmap - standard enable() for regmap users
+ *
+ * @rdev: regulator to operate on
+ *
+ * Regulators that use regmap for their register I/O can set the
+ * enable_reg and enable_mask fields in their descriptor and then use
+ * this as their enable() operation, saving some code.
+ */
+int regulator_enable_regmap(struct regulator_dev *rdev)
+{
+ unsigned int val;
+
+ if (rdev->desc->enable_is_inverted) {
+ val = rdev->desc->disable_val;
+ } else {
+ val = rdev->desc->enable_val;
+ if (!val)
+ val = rdev->desc->enable_mask;
+ }
+
+ return regmap_update_bits(rdev->regmap, rdev->desc->enable_reg,
+ rdev->desc->enable_mask, val);
+}
+EXPORT_SYMBOL_GPL(regulator_enable_regmap);
+
+/**
+ * regulator_disable_regmap - standard disable() for regmap users
+ *
+ * @rdev: regulator to operate on
+ *
+ * Regulators that use regmap for their register I/O can set the
+ * enable_reg and enable_mask fields in their descriptor and then use
+ * this as their disable() operation, saving some code.
+ */
+int regulator_disable_regmap(struct regulator_dev *rdev)
+{
+ unsigned int val;
+
+ if (rdev->desc->enable_is_inverted) {
+ val = rdev->desc->enable_val;
+ if (!val)
+ val = rdev->desc->enable_mask;
+ } else {
+ val = rdev->desc->disable_val;
+ }
+
+ return regmap_update_bits(rdev->regmap, rdev->desc->enable_reg,
+ rdev->desc->enable_mask, val);
+}
+EXPORT_SYMBOL_GPL(regulator_disable_regmap);
+
+/**
+ * regulator_set_voltage_sel_regmap - standard set_voltage_sel for regmap users
+ *
+ * @rdev: regulator to operate on
+ * @sel: Selector to set
+ *
+ * Regulators that use regmap for their register I/O can set the
+ * vsel_reg and vsel_mask fields in their descriptor and then use this
+ * as their set_voltage_vsel operation, saving some code.
+ */
+int regulator_set_voltage_sel_regmap(struct regulator_dev *rdev, unsigned sel)
+{
+ int ret;
+
+ sel <<= ffs(rdev->desc->vsel_mask) - 1;
+
+ ret = regmap_update_bits(rdev->regmap, rdev->desc->vsel_reg,
+ rdev->desc->vsel_mask, sel);
+ if (ret)
+ return ret;
+
+ if (rdev->desc->apply_bit)
+ ret = regmap_update_bits(rdev->regmap, rdev->desc->apply_reg,
+ rdev->desc->apply_bit,
+ rdev->desc->apply_bit);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(regulator_set_voltage_sel_regmap);
+
+/**
+ * regulator_map_voltage_linear - map_voltage() for simple linear mappings
+ *
+ * @rdev: Regulator to operate on
+ * @min_uV: Lower bound for voltage
+ * @max_uV: Upper bound for voltage
+ *
+ * Drivers providing min_uV and uV_step in their regulator_desc can
+ * use this as their map_voltage() operation.
+ */
+int regulator_map_voltage_linear(struct regulator_dev *rdev,
+ int min_uV, int max_uV)
+{
+ int ret, voltage;
+
+ /* Allow uV_step to be 0 for fixed voltage */
+ if (rdev->desc->n_voltages == 1 && rdev->desc->uV_step == 0) {
+ if (min_uV <= rdev->desc->min_uV && rdev->desc->min_uV <= max_uV)
+ return 0;
+ else
+ return -EINVAL;
+ }
+
+ if (!rdev->desc->uV_step) {
+ BUG_ON(!rdev->desc->uV_step);
+ return -EINVAL;
+ }
+
+ if (min_uV < rdev->desc->min_uV)
+ min_uV = rdev->desc->min_uV;
+
+ ret = DIV_ROUND_UP(min_uV - rdev->desc->min_uV, rdev->desc->uV_step);
+ if (ret < 0)
+ return ret;
+
+ ret += rdev->desc->linear_min_sel;
+
+ /* Map back into a voltage to verify we're still in bounds */
+ voltage = rdev->desc->ops->list_voltage(rdev, ret);
+ if (voltage < min_uV || voltage > max_uV)
+ return -EINVAL;
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(regulator_map_voltage_linear);
+
+/**
+ * regulator_list_voltage_linear - List voltages with simple calculation
+ *
+ * @rdev: Regulator device
+ * @selector: Selector to convert into a voltage
+ *
+ * Regulators with a simple linear mapping between voltages and
+ * selectors can set min_uV and uV_step in the regulator descriptor
+ * and then use this function as their list_voltage() operation,
+ */
+int regulator_list_voltage_linear(struct regulator_dev *rdev,
+ unsigned int selector)
+{
+ if (selector >= rdev->desc->n_voltages)
+ return -EINVAL;
+ if (selector < rdev->desc->linear_min_sel)
+ return 0;
+
+ selector -= rdev->desc->linear_min_sel;
+
+ return rdev->desc->min_uV + (rdev->desc->uV_step * selector);
+}
+EXPORT_SYMBOL_GPL(regulator_list_voltage_linear);
diff --git a/drivers/reset/Kconfig b/drivers/reset/Kconfig
index c9d04f7978..caf1dc9acb 100644
--- a/drivers/reset/Kconfig
+++ b/drivers/reset/Kconfig
@@ -11,3 +11,14 @@ menuconfig RESET_CONTROLLER
via GPIOs or SoC-internal reset controller modules.
If unsure, say no.
+
+if RESET_CONTROLLER
+
+config RESET_IMX7
+ bool "i.MX7 Reset Driver"
+ default SOC_IMX7D
+ select MFD_SYSCON
+ help
+ This enables the reset controller driver for i.MX7 SoCs.
+
+endif
diff --git a/drivers/reset/Makefile b/drivers/reset/Makefile
index 52b10cd480..0b55caa204 100644
--- a/drivers/reset/Makefile
+++ b/drivers/reset/Makefile
@@ -1,2 +1,3 @@
obj-$(CONFIG_RESET_CONTROLLER) += core.o
obj-$(CONFIG_ARCH_SOCFPGA) += reset-socfpga.o
+obj-$(CONFIG_RESET_IMX7) += reset-imx7.o
diff --git a/drivers/reset/core.c b/drivers/reset/core.c
index 59f75ca475..99b9c80655 100644
--- a/drivers/reset/core.c
+++ b/drivers/reset/core.c
@@ -147,8 +147,8 @@ EXPORT_SYMBOL_GPL(reset_control_deassert);
*
* Use of id names is optional.
*/
-struct reset_control *of_reset_control_get(struct device_node *node,
- const char *id)
+static struct reset_control *of_reset_control_get(struct device_node *node,
+ const char *id)
{
struct reset_control *rstc = ERR_PTR(-ENODEV);
struct reset_controller_dev *r, *rcdev;
@@ -194,9 +194,9 @@ struct reset_control *of_reset_control_get(struct device_node *node,
return rstc;
}
-EXPORT_SYMBOL_GPL(of_reset_control_get);
-struct reset_control *gpio_reset_control_get(struct device_d *dev, const char *id)
+static struct reset_control *
+gpio_reset_control_get(struct device_d *dev, const char *id)
{
struct reset_control *rc;
int gpio;
diff --git a/drivers/reset/reset-imx7.c b/drivers/reset/reset-imx7.c
new file mode 100644
index 0000000000..9d4344a94c
--- /dev/null
+++ b/drivers/reset/reset-imx7.c
@@ -0,0 +1,295 @@
+/*
+ * Copyright (c) 2017, Impinj, Inc.
+ *
+ * i.MX7 System Reset Controller (SRC) driver
+ *
+ * Author: Andrey Smirnov <andrew.smirnov@gmail.com>
+ *
+ * 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 of the License.
+ *
+ * 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 <dt-bindings/reset/imx7-reset.h>
+#include <dt-bindings/reset/imx8mq-reset.h>
+#include <init.h>
+#include <linux/err.h>
+#include <linux/reset-controller.h>
+#include <mfd/syscon.h>
+#include <regmap.h>
+#include <of_device.h>
+
+struct imx7_src_signal {
+ unsigned int offset, bit;
+};
+
+struct imx7_src_variant {
+ const struct imx7_src_signal *signals;
+ unsigned int signals_num;
+ struct reset_control_ops ops;
+};
+
+struct imx7_src {
+ struct reset_controller_dev rcdev;
+ struct regmap *regmap;
+ const struct imx7_src_signal *signals;
+};
+
+enum imx7_src_registers {
+ SRC_A7RCR0 = 0x0004,
+ SRC_M4RCR = 0x000c,
+ SRC_ERCR = 0x0014,
+ SRC_HSICPHY_RCR = 0x001c,
+ SRC_USBOPHY1_RCR = 0x0020,
+ SRC_USBOPHY2_RCR = 0x0024,
+ SRC_MIPIPHY_RCR = 0x0028,
+ SRC_PCIEPHY_RCR = 0x002c,
+ SRC_DDRC_RCR = 0x1000,
+};
+
+static int imx7_reset_update(struct imx7_src *imx7src,
+ unsigned long id, unsigned int value)
+{
+ const struct imx7_src_signal *signal = &imx7src->signals[id];
+
+ return regmap_update_bits(imx7src->regmap,
+ signal->offset, signal->bit, value);
+}
+
+static const struct imx7_src_signal imx7_src_signals[IMX7_RESET_NUM] = {
+ [IMX7_RESET_A7_CORE_POR_RESET0] = { SRC_A7RCR0, BIT(0) },
+ [IMX7_RESET_A7_CORE_POR_RESET1] = { SRC_A7RCR0, BIT(1) },
+ [IMX7_RESET_A7_CORE_RESET0] = { SRC_A7RCR0, BIT(4) },
+ [IMX7_RESET_A7_CORE_RESET1] = { SRC_A7RCR0, BIT(5) },
+ [IMX7_RESET_A7_DBG_RESET0] = { SRC_A7RCR0, BIT(8) },
+ [IMX7_RESET_A7_DBG_RESET1] = { SRC_A7RCR0, BIT(9) },
+ [IMX7_RESET_A7_ETM_RESET0] = { SRC_A7RCR0, BIT(12) },
+ [IMX7_RESET_A7_ETM_RESET1] = { SRC_A7RCR0, BIT(13) },
+ [IMX7_RESET_A7_SOC_DBG_RESET] = { SRC_A7RCR0, BIT(20) },
+ [IMX7_RESET_A7_L2RESET] = { SRC_A7RCR0, BIT(21) },
+ [IMX7_RESET_SW_M4C_RST] = { SRC_M4RCR, BIT(1) },
+ [IMX7_RESET_SW_M4P_RST] = { SRC_M4RCR, BIT(2) },
+ [IMX7_RESET_EIM_RST] = { SRC_ERCR, BIT(0) },
+ [IMX7_RESET_HSICPHY_PORT_RST] = { SRC_HSICPHY_RCR, BIT(1) },
+ [IMX7_RESET_USBPHY1_POR] = { SRC_USBOPHY1_RCR, BIT(0) },
+ [IMX7_RESET_USBPHY1_PORT_RST] = { SRC_USBOPHY1_RCR, BIT(1) },
+ [IMX7_RESET_USBPHY2_POR] = { SRC_USBOPHY2_RCR, BIT(0) },
+ [IMX7_RESET_USBPHY2_PORT_RST] = { SRC_USBOPHY2_RCR, BIT(1) },
+ [IMX7_RESET_MIPI_PHY_MRST] = { SRC_MIPIPHY_RCR, BIT(1) },
+ [IMX7_RESET_MIPI_PHY_SRST] = { SRC_MIPIPHY_RCR, BIT(2) },
+ [IMX7_RESET_PCIEPHY] = { SRC_PCIEPHY_RCR, BIT(2) | BIT(1) },
+ [IMX7_RESET_PCIEPHY_PERST] = { SRC_PCIEPHY_RCR, BIT(3) },
+ [IMX7_RESET_PCIE_CTRL_APPS_EN] = { SRC_PCIEPHY_RCR, BIT(6) },
+ [IMX7_RESET_DDRC_PRST] = { SRC_DDRC_RCR, BIT(0) },
+ [IMX7_RESET_DDRC_CORE_RST] = { SRC_DDRC_RCR, BIT(1) },
+};
+
+static struct imx7_src *to_imx7_src(struct reset_controller_dev *rcdev)
+{
+ return container_of(rcdev, struct imx7_src, rcdev);
+}
+
+static int imx7_reset_set(struct reset_controller_dev *rcdev,
+ unsigned long id, bool assert)
+{
+ struct imx7_src *imx7src = to_imx7_src(rcdev);
+ const unsigned int bit = imx7src->signals[id].bit;
+ unsigned int value = assert ? bit : 0;
+
+ switch (id) {
+ case IMX7_RESET_PCIEPHY:
+ /*
+ * wait for more than 10us to release phy g_rst and
+ * btnrst
+ */
+ if (!assert)
+ udelay(10);
+ break;
+
+ case IMX7_RESET_PCIE_CTRL_APPS_EN:
+ value = assert ? 0 : bit;
+ break;
+ }
+
+ return imx7_reset_update(imx7src, id, value);
+}
+
+static int imx7_reset_assert(struct reset_controller_dev *rcdev,
+ unsigned long id)
+{
+ return imx7_reset_set(rcdev, id, true);
+}
+
+static int imx7_reset_deassert(struct reset_controller_dev *rcdev,
+ unsigned long id)
+{
+ return imx7_reset_set(rcdev, id, false);
+}
+
+static const struct imx7_src_variant variant_imx7 = {
+ .signals = imx7_src_signals,
+ .signals_num = ARRAY_SIZE(imx7_src_signals),
+ .ops = {
+ .assert = imx7_reset_assert,
+ .deassert = imx7_reset_deassert,
+ },
+};
+
+enum imx8mq_src_registers {
+ SRC_A53RCR0 = 0x0004,
+ SRC_HDMI_RCR = 0x0030,
+ SRC_DISP_RCR = 0x0034,
+ SRC_GPU_RCR = 0x0040,
+ SRC_VPU_RCR = 0x0044,
+ SRC_PCIE2_RCR = 0x0048,
+ SRC_MIPIPHY1_RCR = 0x004c,
+ SRC_MIPIPHY2_RCR = 0x0050,
+ SRC_DDRC2_RCR = 0x1004,
+};
+
+static const struct imx7_src_signal imx8mq_src_signals[IMX8MQ_RESET_NUM] = {
+ [IMX8MQ_RESET_A53_CORE_POR_RESET0] = { SRC_A53RCR0, BIT(0) },
+ [IMX8MQ_RESET_A53_CORE_POR_RESET1] = { SRC_A53RCR0, BIT(1) },
+ [IMX8MQ_RESET_A53_CORE_POR_RESET2] = { SRC_A53RCR0, BIT(2) },
+ [IMX8MQ_RESET_A53_CORE_POR_RESET3] = { SRC_A53RCR0, BIT(3) },
+ [IMX8MQ_RESET_A53_CORE_RESET0] = { SRC_A53RCR0, BIT(4) },
+ [IMX8MQ_RESET_A53_CORE_RESET1] = { SRC_A53RCR0, BIT(5) },
+ [IMX8MQ_RESET_A53_CORE_RESET2] = { SRC_A53RCR0, BIT(6) },
+ [IMX8MQ_RESET_A53_CORE_RESET3] = { SRC_A53RCR0, BIT(7) },
+ [IMX8MQ_RESET_A53_DBG_RESET0] = { SRC_A53RCR0, BIT(8) },
+ [IMX8MQ_RESET_A53_DBG_RESET1] = { SRC_A53RCR0, BIT(9) },
+ [IMX8MQ_RESET_A53_DBG_RESET2] = { SRC_A53RCR0, BIT(10) },
+ [IMX8MQ_RESET_A53_DBG_RESET3] = { SRC_A53RCR0, BIT(11) },
+ [IMX8MQ_RESET_A53_ETM_RESET0] = { SRC_A53RCR0, BIT(12) },
+ [IMX8MQ_RESET_A53_ETM_RESET1] = { SRC_A53RCR0, BIT(13) },
+ [IMX8MQ_RESET_A53_ETM_RESET2] = { SRC_A53RCR0, BIT(14) },
+ [IMX8MQ_RESET_A53_ETM_RESET3] = { SRC_A53RCR0, BIT(15) },
+ [IMX8MQ_RESET_A53_SOC_DBG_RESET] = { SRC_A53RCR0, BIT(20) },
+ [IMX8MQ_RESET_A53_L2RESET] = { SRC_A53RCR0, BIT(21) },
+ [IMX8MQ_RESET_SW_NON_SCLR_M4C_RST] = { SRC_M4RCR, BIT(0) },
+ [IMX8MQ_RESET_OTG1_PHY_RESET] = { SRC_USBOPHY1_RCR, BIT(0) },
+ [IMX8MQ_RESET_OTG2_PHY_RESET] = { SRC_USBOPHY2_RCR, BIT(0) },
+ [IMX8MQ_RESET_MIPI_DSI_RESET_BYTE_N] = { SRC_MIPIPHY_RCR, BIT(1) },
+ [IMX8MQ_RESET_MIPI_DSI_RESET_N] = { SRC_MIPIPHY_RCR, BIT(2) },
+ [IMX8MQ_RESET_MIPI_DIS_DPI_RESET_N] = { SRC_MIPIPHY_RCR, BIT(3) },
+ [IMX8MQ_RESET_MIPI_DIS_ESC_RESET_N] = { SRC_MIPIPHY_RCR, BIT(4) },
+ [IMX8MQ_RESET_MIPI_DIS_PCLK_RESET_N] = { SRC_MIPIPHY_RCR, BIT(5) },
+ [IMX8MQ_RESET_PCIEPHY] = { SRC_PCIEPHY_RCR,
+ BIT(2) | BIT(1) },
+ [IMX8MQ_RESET_PCIEPHY_PERST] = { SRC_PCIEPHY_RCR, BIT(3) },
+ [IMX8MQ_RESET_PCIE_CTRL_APPS_EN] = { SRC_PCIEPHY_RCR, BIT(6) },
+ [IMX8MQ_RESET_PCIE_CTRL_APPS_TURNOFF] = { SRC_PCIEPHY_RCR, BIT(11) },
+ [IMX8MQ_RESET_HDMI_PHY_APB_RESET] = { SRC_HDMI_RCR, BIT(0) },
+ [IMX8MQ_RESET_DISP_RESET] = { SRC_DISP_RCR, BIT(0) },
+ [IMX8MQ_RESET_GPU_RESET] = { SRC_GPU_RCR, BIT(0) },
+ [IMX8MQ_RESET_VPU_RESET] = { SRC_VPU_RCR, BIT(0) },
+ [IMX8MQ_RESET_PCIEPHY2] = { SRC_PCIE2_RCR,
+ BIT(2) | BIT(1) },
+ [IMX8MQ_RESET_PCIEPHY2_PERST] = { SRC_PCIE2_RCR, BIT(3) },
+ [IMX8MQ_RESET_PCIE2_CTRL_APPS_EN] = { SRC_PCIE2_RCR, BIT(6) },
+ [IMX8MQ_RESET_PCIE2_CTRL_APPS_TURNOFF] = { SRC_PCIE2_RCR, BIT(11) },
+ [IMX8MQ_RESET_MIPI_CSI1_CORE_RESET] = { SRC_MIPIPHY1_RCR, BIT(0) },
+ [IMX8MQ_RESET_MIPI_CSI1_PHY_REF_RESET] = { SRC_MIPIPHY1_RCR, BIT(1) },
+ [IMX8MQ_RESET_MIPI_CSI1_ESC_RESET] = { SRC_MIPIPHY1_RCR, BIT(2) },
+ [IMX8MQ_RESET_MIPI_CSI2_CORE_RESET] = { SRC_MIPIPHY2_RCR, BIT(0) },
+ [IMX8MQ_RESET_MIPI_CSI2_PHY_REF_RESET] = { SRC_MIPIPHY2_RCR, BIT(1) },
+ [IMX8MQ_RESET_MIPI_CSI2_ESC_RESET] = { SRC_MIPIPHY2_RCR, BIT(2) },
+ [IMX8MQ_RESET_DDRC1_PRST] = { SRC_DDRC_RCR, BIT(0) },
+ [IMX8MQ_RESET_DDRC1_CORE_RESET] = { SRC_DDRC_RCR, BIT(1) },
+ [IMX8MQ_RESET_DDRC1_PHY_RESET] = { SRC_DDRC_RCR, BIT(2) },
+ [IMX8MQ_RESET_DDRC2_PHY_RESET] = { SRC_DDRC2_RCR, BIT(0) },
+ [IMX8MQ_RESET_DDRC2_CORE_RESET] = { SRC_DDRC2_RCR, BIT(1) },
+ [IMX8MQ_RESET_DDRC2_PRST] = { SRC_DDRC2_RCR, BIT(2) },
+};
+
+static int imx8mq_reset_set(struct reset_controller_dev *rcdev,
+ unsigned long id, bool assert)
+{
+ struct imx7_src *imx7src = to_imx7_src(rcdev);
+ const unsigned int bit = imx7src->signals[id].bit;
+ unsigned int value = assert ? bit : 0;
+
+ switch (id) {
+ case IMX8MQ_RESET_PCIEPHY:
+ case IMX8MQ_RESET_PCIEPHY2: /* fallthrough */
+ /*
+ * wait for more than 10us to release phy g_rst and
+ * btnrst
+ */
+ if (!assert)
+ udelay(10);
+ break;
+
+ case IMX8MQ_RESET_PCIE_CTRL_APPS_EN:
+ case IMX8MQ_RESET_PCIE2_CTRL_APPS_EN: /* fallthrough */
+ case IMX8MQ_RESET_MIPI_DIS_PCLK_RESET_N: /* fallthrough */
+ case IMX8MQ_RESET_MIPI_DIS_ESC_RESET_N: /* fallthrough */
+ case IMX8MQ_RESET_MIPI_DIS_DPI_RESET_N: /* fallthrough */
+ case IMX8MQ_RESET_MIPI_DSI_RESET_N: /* fallthrough */
+ case IMX8MQ_RESET_MIPI_DSI_RESET_BYTE_N: /* fallthrough */
+ value = assert ? 0 : bit;
+ break;
+ }
+
+ return imx7_reset_update(imx7src, id, value);
+}
+
+static int imx8mq_reset_assert(struct reset_controller_dev *rcdev,
+ unsigned long id)
+{
+ return imx8mq_reset_set(rcdev, id, true);
+}
+
+static int imx8mq_reset_deassert(struct reset_controller_dev *rcdev,
+ unsigned long id)
+{
+ return imx8mq_reset_set(rcdev, id, false);
+}
+
+static const struct imx7_src_variant variant_imx8mq = {
+ .signals = imx8mq_src_signals,
+ .signals_num = ARRAY_SIZE(imx8mq_src_signals),
+ .ops = {
+ .assert = imx8mq_reset_assert,
+ .deassert = imx8mq_reset_deassert,
+ },
+};
+
+static int imx7_reset_probe(struct device_d *dev)
+{
+ struct imx7_src *imx7src;
+ const struct imx7_src_variant *variant = of_device_get_match_data(dev);
+
+ imx7src = xzalloc(sizeof(*imx7src));
+ imx7src->signals = variant->signals;
+ imx7src->regmap = syscon_node_to_regmap(dev->device_node);
+ if (IS_ERR(imx7src->regmap)) {
+ dev_err(dev, "Unable to get imx7-src regmap");
+ return PTR_ERR(imx7src->regmap);
+ }
+
+ imx7src->rcdev.nr_resets = variant->signals_num;
+ imx7src->rcdev.ops = &variant->ops;
+ imx7src->rcdev.of_node = dev->device_node;
+
+ return reset_controller_register(&imx7src->rcdev);
+}
+
+static const struct of_device_id imx7_reset_dt_ids[] = {
+ { .compatible = "fsl,imx7d-src", .data = &variant_imx7 },
+ { .compatible = "fsl,imx8mq-src", .data = &variant_imx8mq },
+ { /* sentinel */ },
+};
+
+static struct driver_d imx7_reset_driver = {
+ .name = "imx7d-src",
+ .probe = imx7_reset_probe,
+ .of_compatible = DRV_OF_COMPAT(imx7_reset_dt_ids),
+};
+device_platform_driver(imx7_reset_driver);
diff --git a/drivers/reset/reset-socfpga.c b/drivers/reset/reset-socfpga.c
index b6faa0217e..9b499f23c5 100644
--- a/drivers/reset/reset-socfpga.c
+++ b/drivers/reset/reset-socfpga.c
@@ -73,7 +73,7 @@ static int socfpga_reset_deassert(struct reset_controller_dev *rcdev,
return 0;
}
-static struct reset_control_ops socfpga_reset_ops = {
+static const struct reset_control_ops socfpga_reset_ops = {
.assert = socfpga_reset_assert,
.deassert = socfpga_reset_deassert,
};
diff --git a/drivers/soc/imx/Kconfig b/drivers/soc/imx/Kconfig
new file mode 100644
index 0000000000..32ec76feaf
--- /dev/null
+++ b/drivers/soc/imx/Kconfig
@@ -0,0 +1,9 @@
+menu "i.MX SoC drivers"
+
+config IMX_GPCV2_PM_DOMAINS
+ bool "i.MX GPCv2 PM domains"
+ depends on ARCH_IMX7 || ARCH_IMX8MQ
+ select PM_GENERIC_DOMAINS
+ default y if ARCH_IMX7 || ARCH_IMX8MQ
+
+endmenu
diff --git a/drivers/soc/imx/Makefile b/drivers/soc/imx/Makefile
new file mode 100644
index 0000000000..d60056c7b6
--- /dev/null
+++ b/drivers/soc/imx/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_IMX_GPCV2_PM_DOMAINS) += gpcv2.o
diff --git a/drivers/soc/imx/gpcv2.c b/drivers/soc/imx/gpcv2.c
new file mode 100644
index 0000000000..bc373ecf40
--- /dev/null
+++ b/drivers/soc/imx/gpcv2.c
@@ -0,0 +1,498 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2017 Impinj, Inc
+ * Author: Andrey Smirnov <andrew.smirnov@gmail.com>
+ *
+ * Based on the code of analogus driver:
+ *
+ * Copyright 2015-2017 Pengutronix, Lucas Stach <kernel@pengutronix.de>
+ */
+
+#include <of_device.h>
+#include <common.h>
+#include <clock.h>
+#include <abort.h>
+#include <malloc.h>
+#include <io.h>
+#include <init.h>
+#include <linux/iopoll.h>
+
+#include <pm_domain.h>
+#include <regulator.h>
+#include <dt-bindings/power/imx7-power.h>
+
+#include <dt-bindings/power/imx8mq-power.h>
+
+#define GPC_LPCR_A_BSC 0x000
+
+#define GPC_PGC_CPU_MAPPING 0x0ec
+
+#define IMX7_USB_HSIC_PHY_A_DOMAIN BIT(6)
+#define IMX7_USB_OTG2_PHY_A_DOMAIN BIT(5)
+#define IMX7_USB_OTG1_PHY_A_DOMAIN BIT(4)
+#define IMX7_PCIE_PHY_A_DOMAIN BIT(3)
+#define IMX7_MIPI_PHY_A_DOMAIN BIT(2)
+
+#define IMX8M_PCIE2_A53_DOMAIN BIT(15)
+#define IMX8M_MIPI_CSI2_A53_DOMAIN BIT(14)
+#define IMX8M_MIPI_CSI1_A53_DOMAIN BIT(13)
+#define IMX8M_DISP_A53_DOMAIN BIT(12)
+#define IMX8M_HDMI_A53_DOMAIN BIT(11)
+#define IMX8M_VPU_A53_DOMAIN BIT(10)
+#define IMX8M_GPU_A53_DOMAIN BIT(9)
+#define IMX8M_DDR2_A53_DOMAIN BIT(8)
+#define IMX8M_DDR1_A53_DOMAIN BIT(7)
+#define IMX8M_OTG2_A53_DOMAIN BIT(5)
+#define IMX8M_OTG1_A53_DOMAIN BIT(4)
+#define IMX8M_PCIE1_A53_DOMAIN BIT(3)
+#define IMX8M_MIPI_A53_DOMAIN BIT(2)
+
+#define GPC_PU_PGC_SW_PUP_REQ 0x0f8
+#define GPC_PU_PGC_SW_PDN_REQ 0x104
+
+#define IMX7_USB_HSIC_PHY_SW_Pxx_REQ BIT(4)
+#define IMX7_USB_OTG2_PHY_SW_Pxx_REQ BIT(3)
+#define IMX7_USB_OTG1_PHY_SW_Pxx_REQ BIT(2)
+#define IMX7_PCIE_PHY_SW_Pxx_REQ BIT(1)
+#define IMX7_MIPI_PHY_SW_Pxx_REQ BIT(0)
+
+#define IMX8M_PCIE2_SW_Pxx_REQ BIT(13)
+#define IMX8M_MIPI_CSI2_SW_Pxx_REQ BIT(12)
+#define IMX8M_MIPI_CSI1_SW_Pxx_REQ BIT(11)
+#define IMX8M_DISP_SW_Pxx_REQ BIT(10)
+#define IMX8M_HDMI_SW_Pxx_REQ BIT(9)
+#define IMX8M_VPU_SW_Pxx_REQ BIT(8)
+#define IMX8M_GPU_SW_Pxx_REQ BIT(7)
+#define IMX8M_DDR2_SW_Pxx_REQ BIT(6)
+#define IMX8M_DDR1_SW_Pxx_REQ BIT(5)
+#define IMX8M_OTG2_SW_Pxx_REQ BIT(3)
+#define IMX8M_OTG1_SW_Pxx_REQ BIT(2)
+#define IMX8M_PCIE1_SW_Pxx_REQ BIT(1)
+#define IMX8M_MIPI_SW_Pxx_REQ BIT(0)
+
+#define GPC_M4_PU_PDN_FLG 0x1bc
+
+/*
+ * The PGC offset values in Reference Manual
+ * (Rev. 1, 01/2018 and the older ones) GPC chapter's
+ * GPC_PGC memory map are incorrect, below offset
+ * values are from design RTL.
+ */
+#define IMX7_PGC_MIPI 16
+#define IMX7_PGC_PCIE 17
+#define IMX7_PGC_USB_HSIC 20
+
+
+#define IMX8M_PGC_MIPI 16
+#define IMX8M_PGC_PCIE1 17
+#define IMX8M_PGC_OTG1 18
+#define IMX8M_PGC_OTG2 19
+#define IMX8M_PGC_DDR1 21
+#define IMX8M_PGC_GPU 23
+#define IMX8M_PGC_VPU 24
+#define IMX8M_PGC_DISP 26
+#define IMX8M_PGC_MIPI_CSI1 27
+#define IMX8M_PGC_MIPI_CSI2 28
+#define IMX8M_PGC_PCIE2 29
+
+#define GPC_PGC_CTRL(n) (0x800 + (n) * 0x40)
+#define GPC_PGC_SR(n) (GPC_PGC_CTRL(n) + 0xc)
+
+#define GPC_PGC_CTRL_PCR BIT(0)
+
+struct imx_pgc_domain {
+ struct generic_pm_domain genpd;
+ void __iomem *base;
+ struct regulator *regulator;
+
+ unsigned int pgc;
+
+ const struct {
+ u32 pxx;
+ u32 map;
+ } bits;
+
+ const int voltage;
+ struct device_d *dev;
+};
+
+struct imx_pgc_domain_data {
+ const struct imx_pgc_domain *domains;
+ size_t domains_num;
+};
+
+static int imx_gpc_pu_pgc_sw_pxx_req(struct generic_pm_domain *genpd,
+ bool on)
+{
+ struct imx_pgc_domain *domain = container_of(genpd,
+ struct imx_pgc_domain,
+ genpd);
+ unsigned int offset = on ?
+ GPC_PU_PGC_SW_PUP_REQ : GPC_PU_PGC_SW_PDN_REQ;
+ const bool enable_power_control = !on;
+ const bool has_regulator = !IS_ERR(domain->regulator);
+ int ret = 0;
+ unsigned int mapping, ctrl = 0, pxx;
+
+ mapping = readl(domain->base + GPC_PGC_CPU_MAPPING);
+ mapping |= domain->bits.map;
+ writel(mapping, domain->base + GPC_PGC_CPU_MAPPING);
+
+ if (has_regulator && on) {
+ ret = regulator_enable(domain->regulator);
+ if (ret) {
+ dev_err(domain->dev, "failed to enable regulator\n");
+ goto unmap;
+ }
+ }
+
+ if (enable_power_control) {
+ ctrl = readl(domain->base + GPC_PGC_CTRL(domain->pgc));
+ ctrl |= GPC_PGC_CTRL_PCR;
+ writel(ctrl, domain->base + GPC_PGC_CTRL(domain->pgc));
+ }
+
+ pxx = readl(domain->base + offset);
+ pxx |= domain->bits.pxx;
+ writel(pxx, domain->base + offset);
+
+ /*
+ * As per "5.5.9.4 Example Code 4" in IMX7DRM.pdf wait
+ * for PUP_REQ/PDN_REQ bit to be cleared
+ */
+ ret = readl_poll_timeout(domain->base + offset, pxx,
+ !(pxx & domain->bits.pxx), MSECOND);
+ if (ret < 0) {
+ dev_err(domain->dev, "falied to command PGC\n");
+ /*
+ * If we were in a process of enabling a
+ * domain and failed we might as well disable
+ * the regulator we just enabled. And if it
+ * was the opposite situation and we failed to
+ * power down -- keep the regulator on
+ */
+ on = !on;
+ }
+
+ if (enable_power_control) {
+ ctrl &= ~GPC_PGC_CTRL_PCR;
+ writel(ctrl, domain->base + GPC_PGC_CTRL(domain->pgc));
+ }
+
+ if (has_regulator && !on) {
+ int err;
+
+ err = regulator_disable(domain->regulator);
+ if (err)
+ dev_err(domain->dev,
+ "failed to disable regulator: %d\n", ret);
+ /* Preserve earlier error code */
+ ret = ret ?: err;
+ }
+unmap:
+ mapping &= ~domain->bits.map;
+ writel(mapping, domain->base + GPC_PGC_CPU_MAPPING);
+
+ return ret;
+}
+
+static int imx_gpc_pu_pgc_sw_pup_req(struct generic_pm_domain *genpd)
+{
+ return imx_gpc_pu_pgc_sw_pxx_req(genpd, true);
+}
+
+static int imx_gpc_pu_pgc_sw_pdn_req(struct generic_pm_domain *genpd)
+{
+ return imx_gpc_pu_pgc_sw_pxx_req(genpd, false);
+}
+
+static const struct imx_pgc_domain imx7_pgc_domains[] = {
+ [IMX7_POWER_DOMAIN_MIPI_PHY] = {
+ .genpd = {
+ .name = "mipi-phy",
+ },
+ .bits = {
+ .pxx = IMX7_MIPI_PHY_SW_Pxx_REQ,
+ .map = IMX7_MIPI_PHY_A_DOMAIN,
+ },
+ .voltage = 1000000,
+ .pgc = IMX7_PGC_MIPI,
+ },
+
+ [IMX7_POWER_DOMAIN_PCIE_PHY] = {
+ .genpd = {
+ .name = "pcie-phy",
+ },
+ .bits = {
+ .pxx = IMX7_PCIE_PHY_SW_Pxx_REQ,
+ .map = IMX7_PCIE_PHY_A_DOMAIN,
+ },
+ .voltage = 1000000,
+ .pgc = IMX7_PGC_PCIE,
+ },
+
+ [IMX7_POWER_DOMAIN_USB_HSIC_PHY] = {
+ .genpd = {
+ .name = "usb-hsic-phy",
+ },
+ .bits = {
+ .pxx = IMX7_USB_HSIC_PHY_SW_Pxx_REQ,
+ .map = IMX7_USB_HSIC_PHY_A_DOMAIN,
+ },
+ .voltage = 1200000,
+ .pgc = IMX7_PGC_USB_HSIC,
+ },
+};
+
+static const struct imx_pgc_domain_data imx7_pgc_domain_data = {
+ .domains = imx7_pgc_domains,
+ .domains_num = ARRAY_SIZE(imx7_pgc_domains),
+};
+
+static const struct imx_pgc_domain imx8m_pgc_domains[] = {
+ [IMX8M_POWER_DOMAIN_MIPI] = {
+ .genpd = {
+ .name = "mipi",
+ },
+ .bits = {
+ .pxx = IMX8M_MIPI_SW_Pxx_REQ,
+ .map = IMX8M_MIPI_A53_DOMAIN,
+ },
+ .pgc = IMX8M_PGC_MIPI,
+ },
+
+ [IMX8M_POWER_DOMAIN_PCIE1] = {
+ .genpd = {
+ .name = "pcie1",
+ },
+ .bits = {
+ .pxx = IMX8M_PCIE1_SW_Pxx_REQ,
+ .map = IMX8M_PCIE1_A53_DOMAIN,
+ },
+ .pgc = IMX8M_PGC_PCIE1,
+ },
+
+ [IMX8M_POWER_DOMAIN_USB_OTG1] = {
+ .genpd = {
+ .name = "usb-otg1",
+ },
+ .bits = {
+ .pxx = IMX8M_OTG1_SW_Pxx_REQ,
+ .map = IMX8M_OTG1_A53_DOMAIN,
+ },
+ .pgc = IMX8M_PGC_OTG1,
+ },
+
+ [IMX8M_POWER_DOMAIN_USB_OTG2] = {
+ .genpd = {
+ .name = "usb-otg2",
+ },
+ .bits = {
+ .pxx = IMX8M_OTG2_SW_Pxx_REQ,
+ .map = IMX8M_OTG2_A53_DOMAIN,
+ },
+ .pgc = IMX8M_PGC_OTG2,
+ },
+
+ [IMX8M_POWER_DOMAIN_DDR1] = {
+ .genpd = {
+ .name = "ddr1",
+ },
+ .bits = {
+ .pxx = IMX8M_DDR1_SW_Pxx_REQ,
+ .map = IMX8M_DDR2_A53_DOMAIN,
+ },
+ .pgc = IMX8M_PGC_DDR1,
+ },
+
+ [IMX8M_POWER_DOMAIN_GPU] = {
+ .genpd = {
+ .name = "gpu",
+ },
+ .bits = {
+ .pxx = IMX8M_GPU_SW_Pxx_REQ,
+ .map = IMX8M_GPU_A53_DOMAIN,
+ },
+ .pgc = IMX8M_PGC_GPU,
+ },
+
+ [IMX8M_POWER_DOMAIN_VPU] = {
+ .genpd = {
+ .name = "vpu",
+ },
+ .bits = {
+ .pxx = IMX8M_VPU_SW_Pxx_REQ,
+ .map = IMX8M_VPU_A53_DOMAIN,
+ },
+ .pgc = IMX8M_PGC_VPU,
+ },
+
+ [IMX8M_POWER_DOMAIN_DISP] = {
+ .genpd = {
+ .name = "disp",
+ },
+ .bits = {
+ .pxx = IMX8M_DISP_SW_Pxx_REQ,
+ .map = IMX8M_DISP_A53_DOMAIN,
+ },
+ .pgc = IMX8M_PGC_DISP,
+ },
+
+ [IMX8M_POWER_DOMAIN_MIPI_CSI1] = {
+ .genpd = {
+ .name = "mipi-csi1",
+ },
+ .bits = {
+ .pxx = IMX8M_MIPI_CSI1_SW_Pxx_REQ,
+ .map = IMX8M_MIPI_CSI1_A53_DOMAIN,
+ },
+ .pgc = IMX8M_PGC_MIPI_CSI1,
+ },
+
+ [IMX8M_POWER_DOMAIN_MIPI_CSI2] = {
+ .genpd = {
+ .name = "mipi-csi2",
+ },
+ .bits = {
+ .pxx = IMX8M_MIPI_CSI2_SW_Pxx_REQ,
+ .map = IMX8M_MIPI_CSI2_A53_DOMAIN,
+ },
+ .pgc = IMX8M_PGC_MIPI_CSI2,
+ },
+
+ [IMX8M_POWER_DOMAIN_PCIE2] = {
+ .genpd = {
+ .name = "pcie2",
+ },
+ .bits = {
+ .pxx = IMX8M_PCIE2_SW_Pxx_REQ,
+ .map = IMX8M_PCIE2_A53_DOMAIN,
+ },
+ .pgc = IMX8M_PGC_PCIE2,
+ },
+};
+
+static const struct imx_pgc_domain_data imx8m_pgc_domain_data = {
+ .domains = imx8m_pgc_domains,
+ .domains_num = ARRAY_SIZE(imx8m_pgc_domains),
+};
+
+static int imx_pgc_domain_probe(struct device_d *dev)
+{
+ struct imx_pgc_domain *domain = dev->priv;
+ int ret;
+
+ domain->dev = dev;
+
+ domain->regulator = regulator_get(domain->dev, "power");
+ if (IS_ERR(domain->regulator)) {
+ if (PTR_ERR(domain->regulator) != -ENODEV) {
+ if (PTR_ERR(domain->regulator) != -EPROBE_DEFER)
+ dev_err(domain->dev, "Failed to get domain's regulator\n");
+ return PTR_ERR(domain->regulator);
+ }
+ } else {
+ regulator_set_voltage(domain->regulator,
+ domain->voltage, domain->voltage);
+ }
+
+ ret = pm_genpd_init(&domain->genpd, NULL, true);
+ if (ret) {
+ dev_err(domain->dev, "Failed to init power domain\n");
+ return ret;
+ }
+
+ ret = of_genpd_add_provider_simple(domain->dev->device_node,
+ &domain->genpd);
+ if (ret) {
+ dev_err(domain->dev, "Failed to add genpd provider\n");
+ }
+
+ return ret;
+}
+
+static const struct platform_device_id imx_pgc_domain_id[] = {
+ { "imx-pgc-domain", },
+ { },
+};
+
+static struct driver_d imx_pgc_domain_driver = {
+ .name = "imx-pgc",
+ .probe = imx_pgc_domain_probe,
+ .id_table = imx_pgc_domain_id,
+};
+coredevice_platform_driver(imx_pgc_domain_driver);
+
+static int imx_gpcv2_probe(struct device_d *dev)
+{
+ static const struct imx_pgc_domain_data *domain_data;
+ struct device_node *pgc_np, *np;
+ struct resource *res;
+ void __iomem *base;
+ int ret;
+
+ pgc_np = of_get_child_by_name(dev->device_node, "pgc");
+ if (!pgc_np) {
+ dev_err(dev, "No power domains specified in DT\n");
+ return -EINVAL;
+ }
+
+ res = dev_request_mem_resource(dev, 0);
+ if (IS_ERR(res))
+ return PTR_ERR(res);
+
+ base = IOMEM(res->start);
+
+ domain_data = of_device_get_match_data(dev);
+
+ for_each_child_of_node(pgc_np, np) {
+ struct device_d *pd_dev;
+ struct imx_pgc_domain *domain;
+ u32 domain_index;
+ ret = of_property_read_u32(np, "reg", &domain_index);
+ if (ret) {
+ dev_err(dev, "Failed to read 'reg' property\n");
+ return ret;
+ }
+
+ if (domain_index >= domain_data->domains_num) {
+ dev_warn(dev,
+ "Domain index %d is out of bounds\n",
+ domain_index);
+ continue;
+ }
+
+ domain = xmemdup(&domain_data->domains[domain_index],
+ sizeof(domain_data->domains[domain_index]));
+ domain->base = base;
+ domain->genpd.power_on = imx_gpc_pu_pgc_sw_pup_req;
+ domain->genpd.power_off = imx_gpc_pu_pgc_sw_pdn_req;
+
+ pd_dev = xzalloc(sizeof(*pd_dev));
+ pd_dev->device_node = np;
+ pd_dev->id = domain_index;
+ pd_dev->parent = dev;
+ pd_dev->priv = domain;
+ pd_dev->device_node = np;
+ dev_set_name(pd_dev, imx_pgc_domain_id[0].name);
+
+ ret = platform_device_register(pd_dev);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static const struct of_device_id imx_gpcv2_dt_ids[] = {
+ { .compatible = "fsl,imx7d-gpc", .data = &imx7_pgc_domain_data },
+ { .compatible = "fsl,imx8mq-gpc", .data = &imx8m_pgc_domain_data, },
+ { }
+};
+
+static struct driver_d imx_gpcv2_driver = {
+ .name = "imx7d-gpc",
+ .probe = imx_gpcv2_probe,
+ .of_compatible = DRV_OF_COMPAT(imx_gpcv2_dt_ids),
+};
+coredevice_platform_driver(imx_gpcv2_driver);
diff --git a/firmware/Makefile b/firmware/Makefile
index 7f4dc49326..f238ce2538 100644
--- a/firmware/Makefile
+++ b/firmware/Makefile
@@ -4,12 +4,12 @@
#
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
+ lpddr4_pmu_train_1d_dmem.bin \
+ lpddr4_pmu_train_1d_imem.bin \
+ lpddr4_pmu_train_2d_dmem.bin \
+ lpddr4_pmu_train_2d_imem.bin
-firmware-$(CONFIG_FIRMWARE_IMX8MQ_ATF) += imx/imx8m-bl31.bin
+firmware-$(CONFIG_FIRMWARE_IMX8MQ_ATF) += imx8mq-bl31.bin
# Create $(fwabs) from $(CONFIG_EXTRA_FIRMWARE_DIR) -- if it doesn't have a
# leading /, it's relative to $(srctree).
diff --git a/firmware/README b/firmware/README
new file mode 100644
index 0000000000..1150a5cb0b
--- /dev/null
+++ b/firmware/README
@@ -0,0 +1,7 @@
+This is where you need to place any firmware files that need to be built
+into the boot image.
+
+Note that if you need to place any files here, the resulting boot image
+is not completely governed by the GPLv2, as used for the Barebox binary,
+but will be subject to additional terms of use imposed by the various
+licenses that apply to the firmware files.
diff --git a/firmware/imx/imx8m-bl31.bin b/firmware/imx/imx8m-bl31.bin
deleted file mode 100755
index b2310e4334..0000000000
--- a/firmware/imx/imx8m-bl31.bin
+++ /dev/null
Binary files differ
diff --git a/images/Makefile.imx b/images/Makefile.imx
index 3d2e352a39..f9432015d5 100644
--- a/images/Makefile.imx
+++ b/images/Makefile.imx
@@ -263,6 +263,11 @@ CFG_start_imx6q_sabresd.pblb.imximg = $(board)/freescale-mx6-sabresd/flash-heade
FILE_barebox-freescale-imx6q-sabresd.img = start_imx6q_sabresd.pblb.imximg
image-$(CONFIG_MACH_SABRESD) += barebox-freescale-imx6q-sabresd.img
+pblb-$(CONFIG_MACH_UDOO_NEO) += start_imx6sx_udoo_neo
+CFG_start_imx6sx_udoo_neo.pblb.imximg = $(board)/udoo-neo/flash-header-mx6sx-udoo-neo_full.imxcfg
+FILE_barebox-udoo-neo.img = start_imx6sx_udoo_neo.pblb.imximg
+image-$(CONFIG_MACH_UDOO_NEO) += barebox-udoo-neo.img
+
pblb-$(CONFIG_MACH_FREESCALE_IMX6SX_SABRESDB) += start_imx6sx_sabresdb
CFG_start_imx6sx_sabresdb.pblb.imximg = $(board)/freescale-mx6sx-sabresdb/flash-header-mx6sx-sabresdb.imxcfg
FILE_barebox-freescale-imx6sx-sabresdb.img = start_imx6sx_sabresdb.pblb.imximg
@@ -549,3 +554,8 @@ pblb-$(CONFIG_MACH_NXP_IMX8MQ_EVK) += start_nxp_imx8mq_evk
CFG_start_nxp_imx8mq_evk.pblb.imximg = $(board)/nxp-imx8mq-evk/flash-header-imx8mq-evk.imxcfg
FILE_barebox-nxp-imx8mq-evk.img = start_nxp_imx8mq_evk.pblb.imximg
image-$(CONFIG_MACH_NXP_IMX8MQ_EVK) += barebox-nxp-imx8mq-evk.img
+
+pblb-$(CONFIG_MACH_ZII_IMX8MQ_DEV) += start_zii_imx8mq_dev
+CFG_start_zii_imx8mq_dev.pblb.imximg = $(board)/zii-imx8mq-dev/flash-header-zii-imx8mq-dev.imxcfg
+FILE_barebox-zii-imx8mq-dev.img = start_zii_imx8mq_dev.pblb.imximg
+image-$(CONFIG_MACH_ZII_IMX8MQ_DEV) += barebox-zii-imx8mq-dev.img
diff --git a/include/dt-bindings/reset/imx8mq-reset.h b/include/dt-bindings/reset/imx8mq-reset.h
new file mode 100644
index 0000000000..57c592498a
--- /dev/null
+++ b/include/dt-bindings/reset/imx8mq-reset.h
@@ -0,0 +1,64 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2018 Zodiac Inflight Innovations
+ *
+ * Author: Andrey Smirnov <andrew.smirnov@gmail.com>
+ */
+
+#ifndef DT_BINDING_RESET_IMX8MQ_H
+#define DT_BINDING_RESET_IMX8MQ_H
+
+#define IMX8MQ_RESET_A53_CORE_POR_RESET0 0
+#define IMX8MQ_RESET_A53_CORE_POR_RESET1 1
+#define IMX8MQ_RESET_A53_CORE_POR_RESET2 2
+#define IMX8MQ_RESET_A53_CORE_POR_RESET3 3
+#define IMX8MQ_RESET_A53_CORE_RESET0 4
+#define IMX8MQ_RESET_A53_CORE_RESET1 5
+#define IMX8MQ_RESET_A53_CORE_RESET2 6
+#define IMX8MQ_RESET_A53_CORE_RESET3 7
+#define IMX8MQ_RESET_A53_DBG_RESET0 8
+#define IMX8MQ_RESET_A53_DBG_RESET1 9
+#define IMX8MQ_RESET_A53_DBG_RESET2 10
+#define IMX8MQ_RESET_A53_DBG_RESET3 11
+#define IMX8MQ_RESET_A53_ETM_RESET0 12
+#define IMX8MQ_RESET_A53_ETM_RESET1 13
+#define IMX8MQ_RESET_A53_ETM_RESET2 14
+#define IMX8MQ_RESET_A53_ETM_RESET3 15
+#define IMX8MQ_RESET_A53_SOC_DBG_RESET 16
+#define IMX8MQ_RESET_A53_L2RESET 17
+#define IMX8MQ_RESET_SW_NON_SCLR_M4C_RST 18
+#define IMX8MQ_RESET_OTG1_PHY_RESET 19
+#define IMX8MQ_RESET_OTG2_PHY_RESET 20
+#define IMX8MQ_RESET_MIPI_DSI_RESET_BYTE_N 21
+#define IMX8MQ_RESET_MIPI_DSI_RESET_N 22
+#define IMX8MQ_RESET_MIPI_DIS_DPI_RESET_N 23
+#define IMX8MQ_RESET_MIPI_DIS_ESC_RESET_N 24
+#define IMX8MQ_RESET_MIPI_DIS_PCLK_RESET_N 25
+#define IMX8MQ_RESET_PCIEPHY 26
+#define IMX8MQ_RESET_PCIEPHY_PERST 27
+#define IMX8MQ_RESET_PCIE_CTRL_APPS_EN 28
+#define IMX8MQ_RESET_PCIE_CTRL_APPS_TURNOFF 29
+#define IMX8MQ_RESET_HDMI_PHY_APB_RESET 30
+#define IMX8MQ_RESET_DISP_RESET 31
+#define IMX8MQ_RESET_GPU_RESET 32
+#define IMX8MQ_RESET_VPU_RESET 33
+#define IMX8MQ_RESET_PCIEPHY2 34
+#define IMX8MQ_RESET_PCIEPHY2_PERST 35
+#define IMX8MQ_RESET_PCIE2_CTRL_APPS_EN 36
+#define IMX8MQ_RESET_PCIE2_CTRL_APPS_TURNOFF 37
+#define IMX8MQ_RESET_MIPI_CSI1_CORE_RESET 38
+#define IMX8MQ_RESET_MIPI_CSI1_PHY_REF_RESET 39
+#define IMX8MQ_RESET_MIPI_CSI1_ESC_RESET 40
+#define IMX8MQ_RESET_MIPI_CSI2_CORE_RESET 41
+#define IMX8MQ_RESET_MIPI_CSI2_PHY_REF_RESET 42
+#define IMX8MQ_RESET_MIPI_CSI2_ESC_RESET 43
+#define IMX8MQ_RESET_DDRC1_PRST 44
+#define IMX8MQ_RESET_DDRC1_CORE_RESET 45
+#define IMX8MQ_RESET_DDRC1_PHY_RESET 46
+#define IMX8MQ_RESET_DDRC2_PRST 47
+#define IMX8MQ_RESET_DDRC2_CORE_RESET 48
+#define IMX8MQ_RESET_DDRC2_PHY_RESET 49
+
+#define IMX8MQ_RESET_NUM 50
+
+#endif
diff --git a/include/linux/reset-controller.h b/include/linux/reset-controller.h
index d8265486a0..aff03a9c62 100644
--- a/include/linux/reset-controller.h
+++ b/include/linux/reset-controller.h
@@ -35,7 +35,7 @@ struct of_phandle_args;
* @nr_resets: number of reset controls in this reset controller device
*/
struct reset_controller_dev {
- struct reset_control_ops *ops;
+ const struct reset_control_ops *ops;
struct list_head list;
struct device_node *of_node;
int of_reset_n_cells;
diff --git a/include/pm_domain.h b/include/pm_domain.h
new file mode 100644
index 0000000000..6d59587ece
--- /dev/null
+++ b/include/pm_domain.h
@@ -0,0 +1,82 @@
+#ifndef _PM_DOMAIN_H
+#define _PM_DOMAIN_H
+
+enum gpd_status {
+ GPD_STATE_ACTIVE = 0, /* PM domain is active */
+ GPD_STATE_POWER_OFF, /* PM domain is off */
+};
+
+struct generic_pm_domain {
+ const char *name;
+ struct list_head gpd_list_node; /* Node in the global PM domains list */
+
+ enum gpd_status status; /* Current state of the domain */
+
+ int (*power_off)(struct generic_pm_domain *domain);
+ int (*power_on)(struct generic_pm_domain *domain);
+};
+
+typedef struct generic_pm_domain *(*genpd_xlate_t)(struct of_phandle_args *args,
+ void *data);
+
+#ifdef CONFIG_PM_GENERIC_DOMAINS
+
+int genpd_dev_pm_attach(struct device_d *dev);
+
+/**
+ * dev_pm_domain_attach - Attach a device to its PM domain.
+ * @dev: Device to attach.
+ * @power_on: Used to indicate whether we should power on the device.
+ *
+ * The @dev may only be attached to a single PM domain. By iterating through
+ * the available alternatives we try to find a valid PM domain for the device.
+ * As attachment succeeds, the ->detach() callback in the struct dev_pm_domain
+ * should be assigned by the corresponding attach function.
+ *
+ * This function should typically be invoked from subsystem level code during
+ * the probe phase. Especially for those that holds devices which requires
+ * power management through PM domains.
+ *
+ * Callers must ensure proper synchronization of this function with power
+ * management callbacks.
+ *
+ * Returns 0 on successfully attached PM domain or negative error code.
+ */
+static inline int dev_pm_domain_attach(struct device_d *dev, bool power_on)
+{
+ return genpd_dev_pm_attach(dev);
+}
+
+int pm_genpd_init(struct generic_pm_domain *genpd, void *gov, bool is_off);
+
+int of_genpd_add_provider_simple(struct device_node *np,
+ struct generic_pm_domain *genpd);
+
+#else
+
+static inline int pm_genpd_init(struct generic_pm_domain *genpd,
+ void *gov, bool is_off)
+{
+ return -ENOSYS;
+}
+
+static inline int genpd_dev_pm_attach(struct device_d *dev)
+{
+ return 0;
+}
+
+static inline int dev_pm_domain_attach(struct device_d *dev, bool power_on)
+{
+ return 0;
+}
+
+static inline int
+of_genpd_add_provider_simple(struct device_node *np,
+ struct generic_pm_domain *genpd)
+{
+ return -ENOTSUPP;
+}
+
+#endif
+
+#endif \ No newline at end of file
diff --git a/include/regulator.h b/include/regulator.h
index 367e13f05b..cd1d3ccf55 100644
--- a/include/regulator.h
+++ b/include/regulator.h
@@ -4,8 +4,28 @@
/* struct regulator is an opaque object for consumers */
struct regulator;
+struct regulator_desc {
+ unsigned n_voltages;
+ const struct regulator_ops *ops;
+
+ unsigned int min_uV;
+ unsigned int uV_step;
+ unsigned int linear_min_sel;
+
+ unsigned int vsel_reg;
+ unsigned int vsel_mask;
+ unsigned int apply_reg;
+ unsigned int apply_bit;
+ unsigned int enable_reg;
+ unsigned int enable_mask;
+ unsigned int enable_val;
+ unsigned int disable_val;
+ bool enable_is_inverted;
+};
+
struct regulator_dev {
- struct regulator_ops *ops;
+ const struct regulator_desc *desc;
+ struct regmap *regmap;
int boot_on;
};
@@ -14,6 +34,9 @@ struct regulator_ops {
int (*enable) (struct regulator_dev *);
int (*disable) (struct regulator_dev *);
int (*is_enabled) (struct regulator_dev *);
+
+ int (*list_voltage) (struct regulator_dev *, unsigned int);
+ int (*set_voltage_sel) (struct regulator_dev *, unsigned int);
};
#ifdef CONFIG_OFDEVICE
@@ -35,7 +58,15 @@ void regulators_print(void);
struct regulator *regulator_get(struct device_d *, const char *);
int regulator_enable(struct regulator *);
int regulator_disable(struct regulator *);
-
+int regulator_is_enabled_regmap(struct regulator_dev *);
+int regulator_enable_regmap(struct regulator_dev *);
+int regulator_disable_regmap(struct regulator_dev *);
+int regulator_set_voltage_sel_regmap(struct regulator_dev *, unsigned);
+int regulator_set_voltage(struct regulator *regulator, int min_uV, int max_uV);
+int regulator_map_voltage_linear(struct regulator_dev *rdev,
+ int min_uV, int max_uV);
+int regulator_list_voltage_linear(struct regulator_dev *rdev,
+ unsigned int selector);
#else
static inline struct regulator *regulator_get(struct device_d *dev, const char *id)
@@ -53,6 +84,12 @@ static inline int regulator_disable(struct regulator *r)
return 0;
}
+static inline int regulator_set_voltage(struct regulator *regulator,
+ int min_uV, int max_uV)
+{
+ return 0;
+}
+
#endif
#endif /* __REGULATOR_H */
diff --git a/scripts/imx/imx-image.c b/scripts/imx/imx-image.c
index 34a072039d..a7f1421fa3 100644
--- a/scripts/imx/imx-image.c
+++ b/scripts/imx/imx-image.c
@@ -153,7 +153,8 @@ static int extract_key(const char *certfile, uint8_t **modulus, int *modulus_len
fp = fopen(certfile, "r");
if (!fp) {
- fprintf(stderr, "unable to open certfile: %s\n", certfile);
+ fprintf(stderr, "unable to open certfile %s: %s\n", certfile,
+ strerror(errno));
return -errno;
}
@@ -458,7 +459,8 @@ static void write_dcd(const char *outfile)
outfd = open(outfile, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);
if (outfd < 0) {
- perror("open");
+ fprintf(stderr, "Cannot open %s for wrinting: %s\n", outfile,
+ strerror(errno));
exit(1);
}
@@ -671,6 +673,11 @@ static int hab_sign(struct config_data *data)
}
outfd = open(data->outfile, O_WRONLY | O_APPEND);
+ if (outfd < 0) {
+ fprintf(stderr, "Cannot open %s for writing: %s\n", data->outfile,
+ strerror(errno));
+ exit(1);
+ }
ret = xwrite(outfd, buf, csf_space);
if (ret < 0) {
@@ -687,7 +694,7 @@ static int hab_sign(struct config_data *data)
return 0;
}
-static void *read_file(const char *filename, size_t *size)
+static void *xread_file(const char *filename, size_t *size)
{
int fd, ret;
void *buf;
@@ -695,18 +702,22 @@ static void *read_file(const char *filename, size_t *size)
fd = open(filename, O_RDONLY);
if (fd < 0) {
- perror("open");
+ fprintf(stderr, "Cannot open %s: %s\n", filename, strerror(errno));
exit(1);
}
ret = fstat(fd, &s);
- if (ret)
- return NULL;
+ if (ret) {
+ fprintf(stderr, "Cannot stat %s: %s\n", filename, strerror(errno));
+ exit(1);
+ }
*size = s.st_size;
buf = malloc(*size);
- if (!buf)
+ if (!buf) {
+ perror("malloc");
exit(1);
+ }
xread(fd, buf, *size);
@@ -877,12 +888,8 @@ int main(int argc, char *argv[])
if (data.signed_hdmi_firmware_file) {
free(buf);
- buf = read_file(data.signed_hdmi_firmware_file,
+ buf = xread_file(data.signed_hdmi_firmware_file,
&signed_hdmi_firmware_size);
- if (!buf) {
- perror("read_file");
- exit(1);
- }
signed_hdmi_firmware_size =
roundup(signed_hdmi_firmware_size,
@@ -924,13 +931,12 @@ int main(int argc, char *argv[])
bb_header[0] = data.first_opcode;
bb_header[ARM_HEAD_SIZE_INDEX] = barebox_image_size;
- infile = read_file(imagename, &insize);
- if (!infile)
- exit(1);
+ infile = xread_file(imagename, &insize);
outfd = open(data.outfile, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);
if (outfd < 0) {
- perror("open");
+ fprintf(stderr, "Cannot open %s for writing: %s\n", data.outfile,
+ strerror(errno));
exit(1);
}
@@ -990,7 +996,7 @@ int main(int argc, char *argv[])
if (create_usb_image) {
uint32_t *dcd;
- infile = read_file(data.outfile, &insize);
+ infile = xread_file(data.outfile, &insize);
dcd = infile + dcd_ptr_offset;
*dcd = dcd_ptr_content;