Merge branch '2019-07-26-ti-imports'

- Bring in the rest of the J271E platform
- Various OMAP3/AM3517, DA850 fixes
diff --git a/MAINTAINERS b/MAINTAINERS
index a72ccd0..4285d56 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -205,7 +205,7 @@
 F:	drivers/pinctrl/mediatek/
 F:	drivers/power/domain/mtk-power-domain.c
 F:	drivers/ram/mediatek/
-F:	drivers/spi/mtk_qspi.c
+F:	drivers/spi/mtk_snfi_spi.c
 F:	drivers/timer/mtk_timer.c
 F:	drivers/watchdog/mtk_wdt.c
 F:	drivers/net/mtk_eth.c
@@ -445,6 +445,13 @@
 F:	drivers/mtd/cfi_flash.c
 F:	drivers/mtd/jedec_flash.c
 
+CLOCK
+M:	Lukasz Majewski <lukma@denx.de>
+S:	Maintained
+T:	git git://git.denx.de/u-boot-dfu.git
+F:	drivers/clk/
+F:	drivers/clk/imx/
+
 COLDFIRE
 M:	Huan Wang <alison.wang@nxp.com>
 M:	Angelo Dureghello <angelo@sysam.it>
@@ -778,6 +785,11 @@
 F:	include/tee.h
 F:	include/tee/
 
+TEE-lib
+M:	Bryan O'Donoghue <bryan.odonoghue@linaro.org>
+S:	Maintained
+F:	lib/optee
+
 UBI
 M:	Kyungmin Park <kmpark@infradead.org>
 M:	Heiko Schocher <hs@denx.de>
diff --git a/README b/README
index 8f816ad..7e610a8 100644
--- a/README
+++ b/README
@@ -960,10 +960,6 @@
 			CONFIG_SH_ETHER_CACHE_WRITEBACK
 			If this option is set, the driver enables cache flush.
 
-- PWM Support:
-		CONFIG_PWM_IMX
-		Support for PWM module on the imx6.
-
 - TPM Support:
 		CONFIG_TPM
 		Support TPM devices.
diff --git a/arch/arm/dts/Makefile b/arch/arm/dts/Makefile
index 77d1b60..49d1fae 100644
--- a/arch/arm/dts/Makefile
+++ b/arch/arm/dts/Makefile
@@ -551,6 +551,7 @@
 	imx6q-tbs2910.dtb
 
 dtb-$(CONFIG_MX6QDL) += \
+	imx6dl-dhcom-pdk2.dtb \
 	imx6dl-icore.dtb \
 	imx6dl-icore-mipi.dtb \
 	imx6dl-icore-rqs.dtb \
@@ -559,6 +560,7 @@
 	imx6dl-sabresd.dtb \
 	imx6dl-wandboard-revb1.dtb \
 	imx6q-cm-fx6.dtb \
+	imx6q-dhcom-pdk2.dtb \
 	imx6q-icore.dtb \
 	imx6q-icore-mipi.dtb \
 	imx6q-icore-rqs.dtb \
@@ -599,8 +601,7 @@
 
 dtb-$(CONFIG_ARCH_MX6) += \
 	imx6-apalis.dtb \
-	imx6-colibri.dtb \
-	imx6q-dhcom-pdk2.dtb
+	imx6-colibri.dtb
 
 dtb-$(CONFIG_MX7) += imx7d-sdb.dtb \
 	imx7d-sdb-qspi.dtb \
diff --git a/arch/arm/dts/fsl-imx8dx.dtsi b/arch/arm/dts/fsl-imx8dx.dtsi
index 715abb4..0c33eee 100644
--- a/arch/arm/dts/fsl-imx8dx.dtsi
+++ b/arch/arm/dts/fsl-imx8dx.dtsi
@@ -11,6 +11,7 @@
 #include <dt-bindings/input/input.h>
 #include <dt-bindings/pinctrl/pads-imx8qxp.h>
 #include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/thermal/thermal.h>
 
 / {
 	model = "Freescale i.MX8DX";
@@ -30,6 +31,14 @@
 		i2c1 = &i2c1;
 		i2c2 = &i2c2;
 		i2c3 = &i2c3;
+		gpio0 = &gpio0;
+		gpio1 = &gpio1;
+		gpio2 = &gpio2;
+		gpio3 = &gpio3;
+		gpio4 = &gpio4;
+		gpio5 = &gpio5;
+		gpio6 = &gpio6;
+		gpio7 = &gpio7;
 	};
 
 	memory@80000000 {
@@ -543,6 +552,61 @@
 		power-domains = <&pd_conn_enet1>;
 		status = "disabled";
 	};
+
+	tsens: thermal-sensor {
+		compatible = "nxp,imx8qxp-sc-tsens";
+		/* number of the temp sensor on the chip */
+		tsens-num = <2>;
+		#thermal-sensor-cells = <1>;
+	};
+
+	thermal_zones: thermal-zones {
+		/* cpu thermal */
+		cpu-thermal0 {
+			polling-delay-passive = <250>;
+			polling-delay = <2000>;
+			/*the slope and offset of the temp sensor */
+			thermal-sensors = <&tsens 0>;
+			trips {
+				cpu_alert0: trip0 {
+					temperature = <107000>;
+					hysteresis = <2000>;
+					type = "passive";
+				};
+				cpu_crit0: trip1 {
+					temperature = <127000>;
+					hysteresis = <2000>;
+					type = "critical";
+				};
+			};
+			cooling-maps {
+				map0 {
+					trip = <&cpu_alert0>;
+					cooling-device =
+					<&A35_0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
+				};
+			};
+		};
+
+		drc-thermal0 {
+			polling-delay-passive = <250>;
+			polling-delay = <2000>;
+			thermal-sensors = <&tsens 1>;
+			status = "disabled";
+			trips {
+				drc_alert0: trip0 {
+					temperature = <107000>;
+					hysteresis = <2000>;
+					type = "passive";
+				};
+				drc_crit0: trip1 {
+					temperature = <127000>;
+					hysteresis = <2000>;
+					type = "critical";
+				};
+			};
+		};
+	};
 };
 
 &A35_0 {
diff --git a/arch/arm/dts/imx28-pinfunc.h b/arch/arm/dts/imx28-pinfunc.h
new file mode 100644
index 0000000..e11f69b
--- /dev/null
+++ b/arch/arm/dts/imx28-pinfunc.h
@@ -0,0 +1,506 @@
+/*
+ * Header providing constants for i.MX28 pinctrl bindings.
+ *
+ * Copyright (C) 2013 Lothar Waßmann <LW@KARO-electronics.de>
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+#ifndef __DT_BINDINGS_MX28_PINCTRL_H__
+#define __DT_BINDINGS_MX28_PINCTRL_H__
+
+#include "mxs-pinfunc.h"
+
+#define MX28_PAD_GPMI_D00__GPMI_D0			0x0000
+#define MX28_PAD_GPMI_D01__GPMI_D1			0x0010
+#define MX28_PAD_GPMI_D02__GPMI_D2			0x0020
+#define MX28_PAD_GPMI_D03__GPMI_D3			0x0030
+#define MX28_PAD_GPMI_D04__GPMI_D4			0x0040
+#define MX28_PAD_GPMI_D05__GPMI_D5			0x0050
+#define MX28_PAD_GPMI_D06__GPMI_D6			0x0060
+#define MX28_PAD_GPMI_D07__GPMI_D7			0x0070
+#define MX28_PAD_GPMI_CE0N__GPMI_CE0N			0x0100
+#define MX28_PAD_GPMI_CE1N__GPMI_CE1N			0x0110
+#define MX28_PAD_GPMI_CE2N__GPMI_CE2N			0x0120
+#define MX28_PAD_GPMI_CE3N__GPMI_CE3N			0x0130
+#define MX28_PAD_GPMI_RDY0__GPMI_READY0			0x0140
+#define MX28_PAD_GPMI_RDY1__GPMI_READY1			0x0150
+#define MX28_PAD_GPMI_RDY2__GPMI_READY2			0x0160
+#define MX28_PAD_GPMI_RDY3__GPMI_READY3			0x0170
+#define MX28_PAD_GPMI_RDN__GPMI_RDN			0x0180
+#define MX28_PAD_GPMI_WRN__GPMI_WRN			0x0190
+#define MX28_PAD_GPMI_ALE__GPMI_ALE			0x01a0
+#define MX28_PAD_GPMI_CLE__GPMI_CLE			0x01b0
+#define MX28_PAD_GPMI_RESETN__GPMI_RESETN		0x01c0
+#define MX28_PAD_LCD_D00__LCD_D0			0x1000
+#define MX28_PAD_LCD_D01__LCD_D1			0x1010
+#define MX28_PAD_LCD_D02__LCD_D2			0x1020
+#define MX28_PAD_LCD_D03__LCD_D3			0x1030
+#define MX28_PAD_LCD_D04__LCD_D4			0x1040
+#define MX28_PAD_LCD_D05__LCD_D5			0x1050
+#define MX28_PAD_LCD_D06__LCD_D6			0x1060
+#define MX28_PAD_LCD_D07__LCD_D7			0x1070
+#define MX28_PAD_LCD_D08__LCD_D8			0x1080
+#define MX28_PAD_LCD_D09__LCD_D9			0x1090
+#define MX28_PAD_LCD_D10__LCD_D10			0x10a0
+#define MX28_PAD_LCD_D11__LCD_D11			0x10b0
+#define MX28_PAD_LCD_D12__LCD_D12			0x10c0
+#define MX28_PAD_LCD_D13__LCD_D13			0x10d0
+#define MX28_PAD_LCD_D14__LCD_D14			0x10e0
+#define MX28_PAD_LCD_D15__LCD_D15			0x10f0
+#define MX28_PAD_LCD_D16__LCD_D16			0x1100
+#define MX28_PAD_LCD_D17__LCD_D17			0x1110
+#define MX28_PAD_LCD_D18__LCD_D18			0x1120
+#define MX28_PAD_LCD_D19__LCD_D19			0x1130
+#define MX28_PAD_LCD_D20__LCD_D20			0x1140
+#define MX28_PAD_LCD_D21__LCD_D21			0x1150
+#define MX28_PAD_LCD_D22__LCD_D22			0x1160
+#define MX28_PAD_LCD_D23__LCD_D23			0x1170
+#define MX28_PAD_LCD_RD_E__LCD_RD_E			0x1180
+#define MX28_PAD_LCD_WR_RWN__LCD_WR_RWN			0x1190
+#define MX28_PAD_LCD_RS__LCD_RS				0x11a0
+#define MX28_PAD_LCD_CS__LCD_CS				0x11b0
+#define MX28_PAD_LCD_VSYNC__LCD_VSYNC			0x11c0
+#define MX28_PAD_LCD_HSYNC__LCD_HSYNC			0x11d0
+#define MX28_PAD_LCD_DOTCLK__LCD_DOTCLK			0x11e0
+#define MX28_PAD_LCD_ENABLE__LCD_ENABLE			0x11f0
+#define MX28_PAD_SSP0_DATA0__SSP0_D0			0x2000
+#define MX28_PAD_SSP0_DATA1__SSP0_D1			0x2010
+#define MX28_PAD_SSP0_DATA2__SSP0_D2			0x2020
+#define MX28_PAD_SSP0_DATA3__SSP0_D3			0x2030
+#define MX28_PAD_SSP0_DATA4__SSP0_D4			0x2040
+#define MX28_PAD_SSP0_DATA5__SSP0_D5			0x2050
+#define MX28_PAD_SSP0_DATA6__SSP0_D6			0x2060
+#define MX28_PAD_SSP0_DATA7__SSP0_D7			0x2070
+#define MX28_PAD_SSP0_CMD__SSP0_CMD			0x2080
+#define MX28_PAD_SSP0_DETECT__SSP0_CARD_DETECT		0x2090
+#define MX28_PAD_SSP0_SCK__SSP0_SCK			0x20a0
+#define MX28_PAD_SSP1_SCK__SSP1_SCK			0x20c0
+#define MX28_PAD_SSP1_CMD__SSP1_CMD			0x20d0
+#define MX28_PAD_SSP1_DATA0__SSP1_D0			0x20e0
+#define MX28_PAD_SSP1_DATA3__SSP1_D3			0x20f0
+#define MX28_PAD_SSP2_SCK__SSP2_SCK			0x2100
+#define MX28_PAD_SSP2_MOSI__SSP2_CMD			0x2110
+#define MX28_PAD_SSP2_MISO__SSP2_D0			0x2120
+#define MX28_PAD_SSP2_SS0__SSP2_D3			0x2130
+#define MX28_PAD_SSP2_SS1__SSP2_D4			0x2140
+#define MX28_PAD_SSP2_SS2__SSP2_D5			0x2150
+#define MX28_PAD_SSP3_SCK__SSP3_SCK			0x2180
+#define MX28_PAD_SSP3_MOSI__SSP3_CMD			0x2190
+#define MX28_PAD_SSP3_MISO__SSP3_D0			0x21a0
+#define MX28_PAD_SSP3_SS0__SSP3_D3			0x21b0
+#define MX28_PAD_AUART0_RX__AUART0_RX			0x3000
+#define MX28_PAD_AUART0_TX__AUART0_TX			0x3010
+#define MX28_PAD_AUART0_CTS__AUART0_CTS			0x3020
+#define MX28_PAD_AUART0_RTS__AUART0_RTS			0x3030
+#define MX28_PAD_AUART1_RX__AUART1_RX			0x3040
+#define MX28_PAD_AUART1_TX__AUART1_TX			0x3050
+#define MX28_PAD_AUART1_CTS__AUART1_CTS			0x3060
+#define MX28_PAD_AUART1_RTS__AUART1_RTS			0x3070
+#define MX28_PAD_AUART2_RX__AUART2_RX			0x3080
+#define MX28_PAD_AUART2_TX__AUART2_TX			0x3090
+#define MX28_PAD_AUART2_CTS__AUART2_CTS			0x30a0
+#define MX28_PAD_AUART2_RTS__AUART2_RTS			0x30b0
+#define MX28_PAD_AUART3_RX__AUART3_RX			0x30c0
+#define MX28_PAD_AUART3_TX__AUART3_TX			0x30d0
+#define MX28_PAD_AUART3_CTS__AUART3_CTS			0x30e0
+#define MX28_PAD_AUART3_RTS__AUART3_RTS			0x30f0
+#define MX28_PAD_PWM0__PWM_0				0x3100
+#define MX28_PAD_PWM1__PWM_1				0x3110
+#define MX28_PAD_PWM2__PWM_2				0x3120
+#define MX28_PAD_SAIF0_MCLK__SAIF0_MCLK			0x3140
+#define MX28_PAD_SAIF0_LRCLK__SAIF0_LRCLK		0x3150
+#define MX28_PAD_SAIF0_BITCLK__SAIF0_BITCLK		0x3160
+#define MX28_PAD_SAIF0_SDATA0__SAIF0_SDATA0		0x3170
+#define MX28_PAD_I2C0_SCL__I2C0_SCL			0x3180
+#define MX28_PAD_I2C0_SDA__I2C0_SDA			0x3190
+#define MX28_PAD_SAIF1_SDATA0__SAIF1_SDATA0		0x31a0
+#define MX28_PAD_SPDIF__SPDIF_TX			0x31b0
+#define MX28_PAD_PWM3__PWM_3				0x31c0
+#define MX28_PAD_PWM4__PWM_4				0x31d0
+#define MX28_PAD_LCD_RESET__LCD_RESET			0x31e0
+#define MX28_PAD_ENET0_MDC__ENET0_MDC			0x4000
+#define MX28_PAD_ENET0_MDIO__ENET0_MDIO			0x4010
+#define MX28_PAD_ENET0_RX_EN__ENET0_RX_EN		0x4020
+#define MX28_PAD_ENET0_RXD0__ENET0_RXD0			0x4030
+#define MX28_PAD_ENET0_RXD1__ENET0_RXD1			0x4040
+#define MX28_PAD_ENET0_TX_CLK__ENET0_TX_CLK		0x4050
+#define MX28_PAD_ENET0_TX_EN__ENET0_TX_EN		0x4060
+#define MX28_PAD_ENET0_TXD0__ENET0_TXD0			0x4070
+#define MX28_PAD_ENET0_TXD1__ENET0_TXD1			0x4080
+#define MX28_PAD_ENET0_RXD2__ENET0_RXD2			0x4090
+#define MX28_PAD_ENET0_RXD3__ENET0_RXD3			0x40a0
+#define MX28_PAD_ENET0_TXD2__ENET0_TXD2			0x40b0
+#define MX28_PAD_ENET0_TXD3__ENET0_TXD3			0x40c0
+#define MX28_PAD_ENET0_RX_CLK__ENET0_RX_CLK		0x40d0
+#define MX28_PAD_ENET0_COL__ENET0_COL			0x40e0
+#define MX28_PAD_ENET0_CRS__ENET0_CRS			0x40f0
+#define MX28_PAD_ENET_CLK__CLKCTRL_ENET			0x4100
+#define MX28_PAD_JTAG_RTCK__JTAG_RTCK			0x4140
+#define MX28_PAD_EMI_D00__EMI_DATA0			0x5000
+#define MX28_PAD_EMI_D01__EMI_DATA1			0x5010
+#define MX28_PAD_EMI_D02__EMI_DATA2			0x5020
+#define MX28_PAD_EMI_D03__EMI_DATA3			0x5030
+#define MX28_PAD_EMI_D04__EMI_DATA4			0x5040
+#define MX28_PAD_EMI_D05__EMI_DATA5			0x5050
+#define MX28_PAD_EMI_D06__EMI_DATA6			0x5060
+#define MX28_PAD_EMI_D07__EMI_DATA7			0x5070
+#define MX28_PAD_EMI_D08__EMI_DATA8			0x5080
+#define MX28_PAD_EMI_D09__EMI_DATA9			0x5090
+#define MX28_PAD_EMI_D10__EMI_DATA10			0x50a0
+#define MX28_PAD_EMI_D11__EMI_DATA11			0x50b0
+#define MX28_PAD_EMI_D12__EMI_DATA12			0x50c0
+#define MX28_PAD_EMI_D13__EMI_DATA13			0x50d0
+#define MX28_PAD_EMI_D14__EMI_DATA14			0x50e0
+#define MX28_PAD_EMI_D15__EMI_DATA15			0x50f0
+#define MX28_PAD_EMI_ODT0__EMI_ODT0			0x5100
+#define MX28_PAD_EMI_DQM0__EMI_DQM0			0x5110
+#define MX28_PAD_EMI_ODT1__EMI_ODT1			0x5120
+#define MX28_PAD_EMI_DQM1__EMI_DQM1			0x5130
+#define MX28_PAD_EMI_DDR_OPEN_FB__EMI_DDR_OPEN_FEEDBACK	0x5140
+#define MX28_PAD_EMI_CLK__EMI_CLK			0x5150
+#define MX28_PAD_EMI_DQS0__EMI_DQS0			0x5160
+#define MX28_PAD_EMI_DQS1__EMI_DQS1			0x5170
+#define MX28_PAD_EMI_DDR_OPEN__EMI_DDR_OPEN		0x51a0
+#define MX28_PAD_EMI_A00__EMI_ADDR0			0x6000
+#define MX28_PAD_EMI_A01__EMI_ADDR1			0x6010
+#define MX28_PAD_EMI_A02__EMI_ADDR2			0x6020
+#define MX28_PAD_EMI_A03__EMI_ADDR3			0x6030
+#define MX28_PAD_EMI_A04__EMI_ADDR4			0x6040
+#define MX28_PAD_EMI_A05__EMI_ADDR5			0x6050
+#define MX28_PAD_EMI_A06__EMI_ADDR6			0x6060
+#define MX28_PAD_EMI_A07__EMI_ADDR7			0x6070
+#define MX28_PAD_EMI_A08__EMI_ADDR8			0x6080
+#define MX28_PAD_EMI_A09__EMI_ADDR9			0x6090
+#define MX28_PAD_EMI_A10__EMI_ADDR10			0x60a0
+#define MX28_PAD_EMI_A11__EMI_ADDR11			0x60b0
+#define MX28_PAD_EMI_A12__EMI_ADDR12			0x60c0
+#define MX28_PAD_EMI_A13__EMI_ADDR13			0x60d0
+#define MX28_PAD_EMI_A14__EMI_ADDR14			0x60e0
+#define MX28_PAD_EMI_BA0__EMI_BA0			0x6100
+#define MX28_PAD_EMI_BA1__EMI_BA1			0x6110
+#define MX28_PAD_EMI_BA2__EMI_BA2			0x6120
+#define MX28_PAD_EMI_CASN__EMI_CASN			0x6130
+#define MX28_PAD_EMI_RASN__EMI_RASN			0x6140
+#define MX28_PAD_EMI_WEN__EMI_WEN			0x6150
+#define MX28_PAD_EMI_CE0N__EMI_CE0N			0x6160
+#define MX28_PAD_EMI_CE1N__EMI_CE1N			0x6170
+#define MX28_PAD_EMI_CKE__EMI_CKE			0x6180
+#define MX28_PAD_GPMI_D00__SSP1_D0			0x0001
+#define MX28_PAD_GPMI_D01__SSP1_D1			0x0011
+#define MX28_PAD_GPMI_D02__SSP1_D2			0x0021
+#define MX28_PAD_GPMI_D03__SSP1_D3			0x0031
+#define MX28_PAD_GPMI_D04__SSP1_D4			0x0041
+#define MX28_PAD_GPMI_D05__SSP1_D5			0x0051
+#define MX28_PAD_GPMI_D06__SSP1_D6			0x0061
+#define MX28_PAD_GPMI_D07__SSP1_D7			0x0071
+#define MX28_PAD_GPMI_CE0N__SSP3_D0			0x0101
+#define MX28_PAD_GPMI_CE1N__SSP3_D3			0x0111
+#define MX28_PAD_GPMI_CE2N__CAN1_TX			0x0121
+#define MX28_PAD_GPMI_CE3N__CAN1_RX			0x0131
+#define MX28_PAD_GPMI_RDY0__SSP1_CARD_DETECT		0x0141
+#define MX28_PAD_GPMI_RDY1__SSP1_CMD			0x0151
+#define MX28_PAD_GPMI_RDY2__CAN0_TX			0x0161
+#define MX28_PAD_GPMI_RDY3__CAN0_RX			0x0171
+#define MX28_PAD_GPMI_RDN__SSP3_SCK			0x0181
+#define MX28_PAD_GPMI_WRN__SSP1_SCK			0x0191
+#define MX28_PAD_GPMI_ALE__SSP3_D1			0x01a1
+#define MX28_PAD_GPMI_CLE__SSP3_D2			0x01b1
+#define MX28_PAD_GPMI_RESETN__SSP3_CMD			0x01c1
+#define MX28_PAD_LCD_D03__ETM_DA8			0x1031
+#define MX28_PAD_LCD_D04__ETM_DA9			0x1041
+#define MX28_PAD_LCD_D08__ETM_DA3			0x1081
+#define MX28_PAD_LCD_D09__ETM_DA4			0x1091
+#define MX28_PAD_LCD_D20__ENET1_1588_EVENT2_OUT		0x1141
+#define MX28_PAD_LCD_D21__ENET1_1588_EVENT2_IN		0x1151
+#define MX28_PAD_LCD_D22__ENET1_1588_EVENT3_OUT		0x1161
+#define MX28_PAD_LCD_D23__ENET1_1588_EVENT3_IN		0x1171
+#define MX28_PAD_LCD_RD_E__LCD_VSYNC			0x1181
+#define MX28_PAD_LCD_WR_RWN__LCD_HSYNC			0x1191
+#define MX28_PAD_LCD_RS__LCD_DOTCLK			0x11a1
+#define MX28_PAD_LCD_CS__LCD_ENABLE			0x11b1
+#define MX28_PAD_LCD_VSYNC__SAIF1_SDATA0		0x11c1
+#define MX28_PAD_LCD_HSYNC__SAIF1_SDATA1		0x11d1
+#define MX28_PAD_LCD_DOTCLK__SAIF1_MCLK			0x11e1
+#define MX28_PAD_SSP0_DATA4__SSP2_D0			0x2041
+#define MX28_PAD_SSP0_DATA5__SSP2_D3			0x2051
+#define MX28_PAD_SSP0_DATA6__SSP2_CMD			0x2061
+#define MX28_PAD_SSP0_DATA7__SSP2_SCK			0x2071
+#define MX28_PAD_SSP1_SCK__SSP2_D1			0x20c1
+#define MX28_PAD_SSP1_CMD__SSP2_D2			0x20d1
+#define MX28_PAD_SSP1_DATA0__SSP2_D6			0x20e1
+#define MX28_PAD_SSP1_DATA3__SSP2_D7			0x20f1
+#define MX28_PAD_SSP2_SCK__AUART2_RX			0x2101
+#define MX28_PAD_SSP2_MOSI__AUART2_TX			0x2111
+#define MX28_PAD_SSP2_MISO__AUART3_RX			0x2121
+#define MX28_PAD_SSP2_SS0__AUART3_TX			0x2131
+#define MX28_PAD_SSP2_SS1__SSP2_D1			0x2141
+#define MX28_PAD_SSP2_SS2__SSP2_D2			0x2151
+#define MX28_PAD_SSP3_SCK__AUART4_TX			0x2181
+#define MX28_PAD_SSP3_MOSI__AUART4_RX			0x2191
+#define MX28_PAD_SSP3_MISO__AUART4_RTS			0x21a1
+#define MX28_PAD_SSP3_SS0__AUART4_CTS			0x21b1
+#define MX28_PAD_AUART0_RX__I2C0_SCL			0x3001
+#define MX28_PAD_AUART0_TX__I2C0_SDA			0x3011
+#define MX28_PAD_AUART0_CTS__AUART4_RX			0x3021
+#define MX28_PAD_AUART0_RTS__AUART4_TX			0x3031
+#define MX28_PAD_AUART1_RX__SSP2_CARD_DETECT		0x3041
+#define MX28_PAD_AUART1_TX__SSP3_CARD_DETECT		0x3051
+#define MX28_PAD_AUART1_CTS__USB0_OVERCURRENT		0x3061
+#define MX28_PAD_AUART1_RTS__USB0_ID			0x3071
+#define MX28_PAD_AUART2_RX__SSP3_D1			0x3081
+#define MX28_PAD_AUART2_TX__SSP3_D2			0x3091
+#define MX28_PAD_AUART2_CTS__I2C1_SCL			0x30a1
+#define MX28_PAD_AUART2_RTS__I2C1_SDA			0x30b1
+#define MX28_PAD_AUART3_RX__CAN0_TX			0x30c1
+#define MX28_PAD_AUART3_TX__CAN0_RX			0x30d1
+#define MX28_PAD_AUART3_CTS__CAN1_TX			0x30e1
+#define MX28_PAD_AUART3_RTS__CAN1_RX			0x30f1
+#define MX28_PAD_PWM0__I2C1_SCL				0x3101
+#define MX28_PAD_PWM1__I2C1_SDA				0x3111
+#define MX28_PAD_PWM2__USB0_ID				0x3121
+#define MX28_PAD_SAIF0_MCLK__PWM_3			0x3141
+#define MX28_PAD_SAIF0_LRCLK__PWM_4			0x3151
+#define MX28_PAD_SAIF0_BITCLK__PWM_5			0x3161
+#define MX28_PAD_SAIF0_SDATA0__PWM_6			0x3171
+#define MX28_PAD_I2C0_SCL__TIMROT_ROTARYA		0x3181
+#define MX28_PAD_I2C0_SDA__TIMROT_ROTARYB		0x3191
+#define MX28_PAD_SAIF1_SDATA0__PWM_7			0x31a1
+#define MX28_PAD_LCD_RESET__LCD_VSYNC			0x31e1
+#define MX28_PAD_ENET0_MDC__GPMI_CE4N			0x4001
+#define MX28_PAD_ENET0_MDIO__GPMI_CE5N			0x4011
+#define MX28_PAD_ENET0_RX_EN__GPMI_CE6N			0x4021
+#define MX28_PAD_ENET0_RXD0__GPMI_CE7N			0x4031
+#define MX28_PAD_ENET0_RXD1__GPMI_READY4		0x4041
+#define MX28_PAD_ENET0_TX_CLK__HSADC_TRIGGER		0x4051
+#define MX28_PAD_ENET0_TX_EN__GPMI_READY5		0x4061
+#define MX28_PAD_ENET0_TXD0__GPMI_READY6		0x4071
+#define MX28_PAD_ENET0_TXD1__GPMI_READY7		0x4081
+#define MX28_PAD_ENET0_RXD2__ENET1_RXD0			0x4091
+#define MX28_PAD_ENET0_RXD3__ENET1_RXD1			0x40a1
+#define MX28_PAD_ENET0_TXD2__ENET1_TXD0			0x40b1
+#define MX28_PAD_ENET0_TXD3__ENET1_TXD1			0x40c1
+#define MX28_PAD_ENET0_RX_CLK__ENET0_RX_ER		0x40d1
+#define MX28_PAD_ENET0_COL__ENET1_TX_EN			0x40e1
+#define MX28_PAD_ENET0_CRS__ENET1_RX_EN			0x40f1
+#define MX28_PAD_GPMI_CE2N__ENET0_RX_ER			0x0122
+#define MX28_PAD_GPMI_CE3N__SAIF1_MCLK			0x0132
+#define MX28_PAD_GPMI_RDY0__USB0_ID			0x0142
+#define MX28_PAD_GPMI_RDY2__ENET0_TX_ER			0x0162
+#define MX28_PAD_GPMI_RDY3__HSADC_TRIGGER		0x0172
+#define MX28_PAD_GPMI_ALE__SSP3_D4			0x01a2
+#define MX28_PAD_GPMI_CLE__SSP3_D5			0x01b2
+#define MX28_PAD_LCD_D00__ETM_DA0			0x1002
+#define MX28_PAD_LCD_D01__ETM_DA1			0x1012
+#define MX28_PAD_LCD_D02__ETM_DA2			0x1022
+#define MX28_PAD_LCD_D03__ETM_DA3			0x1032
+#define MX28_PAD_LCD_D04__ETM_DA4			0x1042
+#define MX28_PAD_LCD_D05__ETM_DA5			0x1052
+#define MX28_PAD_LCD_D06__ETM_DA6			0x1062
+#define MX28_PAD_LCD_D07__ETM_DA7			0x1072
+#define MX28_PAD_LCD_D08__ETM_DA8			0x1082
+#define MX28_PAD_LCD_D09__ETM_DA9			0x1092
+#define MX28_PAD_LCD_D10__ETM_DA10			0x10a2
+#define MX28_PAD_LCD_D11__ETM_DA11			0x10b2
+#define MX28_PAD_LCD_D12__ETM_DA12			0x10c2
+#define MX28_PAD_LCD_D13__ETM_DA13			0x10d2
+#define MX28_PAD_LCD_D14__ETM_DA14			0x10e2
+#define MX28_PAD_LCD_D15__ETM_DA15			0x10f2
+#define MX28_PAD_LCD_D16__ETM_DA7			0x1102
+#define MX28_PAD_LCD_D17__ETM_DA6			0x1112
+#define MX28_PAD_LCD_D18__ETM_DA5			0x1122
+#define MX28_PAD_LCD_D19__ETM_DA4			0x1132
+#define MX28_PAD_LCD_D20__ETM_DA3			0x1142
+#define MX28_PAD_LCD_D21__ETM_DA2			0x1152
+#define MX28_PAD_LCD_D22__ETM_DA1			0x1162
+#define MX28_PAD_LCD_D23__ETM_DA0			0x1172
+#define MX28_PAD_LCD_RD_E__ETM_TCTL			0x1182
+#define MX28_PAD_LCD_WR_RWN__ETM_TCLK			0x1192
+#define MX28_PAD_LCD_HSYNC__ETM_TCTL			0x11d2
+#define MX28_PAD_LCD_DOTCLK__ETM_TCLK			0x11e2
+#define MX28_PAD_SSP1_SCK__ENET0_1588_EVENT2_OUT	0x20c2
+#define MX28_PAD_SSP1_CMD__ENET0_1588_EVENT2_IN		0x20d2
+#define MX28_PAD_SSP1_DATA0__ENET0_1588_EVENT3_OUT	0x20e2
+#define MX28_PAD_SSP1_DATA3__ENET0_1588_EVENT3_IN	0x20f2
+#define MX28_PAD_SSP2_SCK__SAIF0_SDATA1			0x2102
+#define MX28_PAD_SSP2_MOSI__SAIF0_SDATA2		0x2112
+#define MX28_PAD_SSP2_MISO__SAIF1_SDATA1		0x2122
+#define MX28_PAD_SSP2_SS0__SAIF1_SDATA2			0x2132
+#define MX28_PAD_SSP2_SS1__USB1_OVERCURRENT		0x2142
+#define MX28_PAD_SSP2_SS2__USB0_OVERCURRENT		0x2152
+#define MX28_PAD_SSP3_SCK__ENET1_1588_EVENT0_OUT	0x2182
+#define MX28_PAD_SSP3_MOSI__ENET1_1588_EVENT0_IN	0x2192
+#define MX28_PAD_SSP3_MISO__ENET1_1588_EVENT1_OUT	0x21a2
+#define MX28_PAD_SSP3_SS0__ENET1_1588_EVENT1_IN		0x21b2
+#define MX28_PAD_AUART0_RX__DUART_CTS			0x3002
+#define MX28_PAD_AUART0_TX__DUART_RTS			0x3012
+#define MX28_PAD_AUART0_CTS__DUART_RX			0x3022
+#define MX28_PAD_AUART0_RTS__DUART_TX			0x3032
+#define MX28_PAD_AUART1_RX__PWM_0			0x3042
+#define MX28_PAD_AUART1_TX__PWM_1			0x3052
+#define MX28_PAD_AUART1_CTS__TIMROT_ROTARYA		0x3062
+#define MX28_PAD_AUART1_RTS__TIMROT_ROTARYB		0x3072
+#define MX28_PAD_AUART2_RX__SSP3_D4			0x3082
+#define MX28_PAD_AUART2_TX__SSP3_D5			0x3092
+#define MX28_PAD_AUART2_CTS__SAIF1_BITCLK		0x30a2
+#define MX28_PAD_AUART2_RTS__SAIF1_LRCLK		0x30b2
+#define MX28_PAD_AUART3_RX__ENET0_1588_EVENT0_OUT	0x30c2
+#define MX28_PAD_AUART3_TX__ENET0_1588_EVENT0_IN	0x30d2
+#define MX28_PAD_AUART3_CTS__ENET0_1588_EVENT1_OUT	0x30e2
+#define MX28_PAD_AUART3_RTS__ENET0_1588_EVENT1_IN	0x30f2
+#define MX28_PAD_PWM0__DUART_RX				0x3102
+#define MX28_PAD_PWM1__DUART_TX				0x3112
+#define MX28_PAD_PWM2__USB1_OVERCURRENT			0x3122
+#define MX28_PAD_SAIF0_MCLK__AUART4_CTS			0x3142
+#define MX28_PAD_SAIF0_LRCLK__AUART4_RTS		0x3152
+#define MX28_PAD_SAIF0_BITCLK__AUART4_RX		0x3162
+#define MX28_PAD_SAIF0_SDATA0__AUART4_TX		0x3172
+#define MX28_PAD_I2C0_SCL__DUART_RX			0x3182
+#define MX28_PAD_I2C0_SDA__DUART_TX			0x3192
+#define MX28_PAD_SAIF1_SDATA0__SAIF0_SDATA1		0x31a2
+#define MX28_PAD_SPDIF__ENET1_RX_ER			0x31b2
+#define MX28_PAD_ENET0_MDC__SAIF0_SDATA1		0x4002
+#define MX28_PAD_ENET0_MDIO__SAIF0_SDATA2		0x4012
+#define MX28_PAD_ENET0_RX_EN__SAIF1_SDATA1		0x4022
+#define MX28_PAD_ENET0_RXD0__SAIF1_SDATA2		0x4032
+#define MX28_PAD_ENET0_TX_CLK__ENET0_1588_EVENT2_OUT	0x4052
+#define MX28_PAD_ENET0_RXD2__ENET0_1588_EVENT0_OUT	0x4092
+#define MX28_PAD_ENET0_RXD3__ENET0_1588_EVENT0_IN	0x40a2
+#define MX28_PAD_ENET0_TXD2__ENET0_1588_EVENT1_OUT	0x40b2
+#define MX28_PAD_ENET0_TXD3__ENET0_1588_EVENT1_IN	0x40c2
+#define MX28_PAD_ENET0_RX_CLK__ENET0_1588_EVENT2_IN	0x40d2
+#define MX28_PAD_ENET0_COL__ENET0_1588_EVENT3_OUT	0x40e2
+#define MX28_PAD_ENET0_CRS__ENET0_1588_EVENT3_IN	0x40f2
+#define MX28_PAD_GPMI_D00__GPIO_0_0			0x0003
+#define MX28_PAD_GPMI_D01__GPIO_0_1			0x0013
+#define MX28_PAD_GPMI_D02__GPIO_0_2			0x0023
+#define MX28_PAD_GPMI_D03__GPIO_0_3			0x0033
+#define MX28_PAD_GPMI_D04__GPIO_0_4			0x0043
+#define MX28_PAD_GPMI_D05__GPIO_0_5			0x0053
+#define MX28_PAD_GPMI_D06__GPIO_0_6			0x0063
+#define MX28_PAD_GPMI_D07__GPIO_0_7			0x0073
+#define MX28_PAD_GPMI_CE0N__GPIO_0_16			0x0103
+#define MX28_PAD_GPMI_CE1N__GPIO_0_17			0x0113
+#define MX28_PAD_GPMI_CE2N__GPIO_0_18			0x0123
+#define MX28_PAD_GPMI_CE3N__GPIO_0_19			0x0133
+#define MX28_PAD_GPMI_RDY0__GPIO_0_20			0x0143
+#define MX28_PAD_GPMI_RDY1__GPIO_0_21			0x0153
+#define MX28_PAD_GPMI_RDY2__GPIO_0_22			0x0163
+#define MX28_PAD_GPMI_RDY3__GPIO_0_23			0x0173
+#define MX28_PAD_GPMI_RDN__GPIO_0_24			0x0183
+#define MX28_PAD_GPMI_WRN__GPIO_0_25			0x0193
+#define MX28_PAD_GPMI_ALE__GPIO_0_26			0x01a3
+#define MX28_PAD_GPMI_CLE__GPIO_0_27			0x01b3
+#define MX28_PAD_GPMI_RESETN__GPIO_0_28			0x01c3
+#define MX28_PAD_LCD_D00__GPIO_1_0			0x1003
+#define MX28_PAD_LCD_D01__GPIO_1_1			0x1013
+#define MX28_PAD_LCD_D02__GPIO_1_2			0x1023
+#define MX28_PAD_LCD_D03__GPIO_1_3			0x1033
+#define MX28_PAD_LCD_D04__GPIO_1_4			0x1043
+#define MX28_PAD_LCD_D05__GPIO_1_5			0x1053
+#define MX28_PAD_LCD_D06__GPIO_1_6			0x1063
+#define MX28_PAD_LCD_D07__GPIO_1_7			0x1073
+#define MX28_PAD_LCD_D08__GPIO_1_8			0x1083
+#define MX28_PAD_LCD_D09__GPIO_1_9			0x1093
+#define MX28_PAD_LCD_D10__GPIO_1_10			0x10a3
+#define MX28_PAD_LCD_D11__GPIO_1_11			0x10b3
+#define MX28_PAD_LCD_D12__GPIO_1_12			0x10c3
+#define MX28_PAD_LCD_D13__GPIO_1_13			0x10d3
+#define MX28_PAD_LCD_D14__GPIO_1_14			0x10e3
+#define MX28_PAD_LCD_D15__GPIO_1_15			0x10f3
+#define MX28_PAD_LCD_D16__GPIO_1_16			0x1103
+#define MX28_PAD_LCD_D17__GPIO_1_17			0x1113
+#define MX28_PAD_LCD_D18__GPIO_1_18			0x1123
+#define MX28_PAD_LCD_D19__GPIO_1_19			0x1133
+#define MX28_PAD_LCD_D20__GPIO_1_20			0x1143
+#define MX28_PAD_LCD_D21__GPIO_1_21			0x1153
+#define MX28_PAD_LCD_D22__GPIO_1_22			0x1163
+#define MX28_PAD_LCD_D23__GPIO_1_23			0x1173
+#define MX28_PAD_LCD_RD_E__GPIO_1_24			0x1183
+#define MX28_PAD_LCD_WR_RWN__GPIO_1_25			0x1193
+#define MX28_PAD_LCD_RS__GPIO_1_26			0x11a3
+#define MX28_PAD_LCD_CS__GPIO_1_27			0x11b3
+#define MX28_PAD_LCD_VSYNC__GPIO_1_28			0x11c3
+#define MX28_PAD_LCD_HSYNC__GPIO_1_29			0x11d3
+#define MX28_PAD_LCD_DOTCLK__GPIO_1_30			0x11e3
+#define MX28_PAD_LCD_ENABLE__GPIO_1_31			0x11f3
+#define MX28_PAD_SSP0_DATA0__GPIO_2_0			0x2003
+#define MX28_PAD_SSP0_DATA1__GPIO_2_1			0x2013
+#define MX28_PAD_SSP0_DATA2__GPIO_2_2			0x2023
+#define MX28_PAD_SSP0_DATA3__GPIO_2_3			0x2033
+#define MX28_PAD_SSP0_DATA4__GPIO_2_4			0x2043
+#define MX28_PAD_SSP0_DATA5__GPIO_2_5			0x2053
+#define MX28_PAD_SSP0_DATA6__GPIO_2_6			0x2063
+#define MX28_PAD_SSP0_DATA7__GPIO_2_7			0x2073
+#define MX28_PAD_SSP0_CMD__GPIO_2_8			0x2083
+#define MX28_PAD_SSP0_DETECT__GPIO_2_9			0x2093
+#define MX28_PAD_SSP0_SCK__GPIO_2_10			0x20a3
+#define MX28_PAD_SSP1_SCK__GPIO_2_12			0x20c3
+#define MX28_PAD_SSP1_CMD__GPIO_2_13			0x20d3
+#define MX28_PAD_SSP1_DATA0__GPIO_2_14			0x20e3
+#define MX28_PAD_SSP1_DATA3__GPIO_2_15			0x20f3
+#define MX28_PAD_SSP2_SCK__GPIO_2_16			0x2103
+#define MX28_PAD_SSP2_MOSI__GPIO_2_17			0x2113
+#define MX28_PAD_SSP2_MISO__GPIO_2_18			0x2123
+#define MX28_PAD_SSP2_SS0__GPIO_2_19			0x2133
+#define MX28_PAD_SSP2_SS1__GPIO_2_20			0x2143
+#define MX28_PAD_SSP2_SS2__GPIO_2_21			0x2153
+#define MX28_PAD_SSP3_SCK__GPIO_2_24			0x2183
+#define MX28_PAD_SSP3_MOSI__GPIO_2_25			0x2193
+#define MX28_PAD_SSP3_MISO__GPIO_2_26			0x21a3
+#define MX28_PAD_SSP3_SS0__GPIO_2_27			0x21b3
+#define MX28_PAD_AUART0_RX__GPIO_3_0			0x3003
+#define MX28_PAD_AUART0_TX__GPIO_3_1			0x3013
+#define MX28_PAD_AUART0_CTS__GPIO_3_2			0x3023
+#define MX28_PAD_AUART0_RTS__GPIO_3_3			0x3033
+#define MX28_PAD_AUART1_RX__GPIO_3_4			0x3043
+#define MX28_PAD_AUART1_TX__GPIO_3_5			0x3053
+#define MX28_PAD_AUART1_CTS__GPIO_3_6			0x3063
+#define MX28_PAD_AUART1_RTS__GPIO_3_7			0x3073
+#define MX28_PAD_AUART2_RX__GPIO_3_8			0x3083
+#define MX28_PAD_AUART2_TX__GPIO_3_9			0x3093
+#define MX28_PAD_AUART2_CTS__GPIO_3_10			0x30a3
+#define MX28_PAD_AUART2_RTS__GPIO_3_11			0x30b3
+#define MX28_PAD_AUART3_RX__GPIO_3_12			0x30c3
+#define MX28_PAD_AUART3_TX__GPIO_3_13			0x30d3
+#define MX28_PAD_AUART3_CTS__GPIO_3_14			0x30e3
+#define MX28_PAD_AUART3_RTS__GPIO_3_15			0x30f3
+#define MX28_PAD_PWM0__GPIO_3_16			0x3103
+#define MX28_PAD_PWM1__GPIO_3_17			0x3113
+#define MX28_PAD_PWM2__GPIO_3_18			0x3123
+#define MX28_PAD_SAIF0_MCLK__GPIO_3_20			0x3143
+#define MX28_PAD_SAIF0_LRCLK__GPIO_3_21			0x3153
+#define MX28_PAD_SAIF0_BITCLK__GPIO_3_22		0x3163
+#define MX28_PAD_SAIF0_SDATA0__GPIO_3_23		0x3173
+#define MX28_PAD_I2C0_SCL__GPIO_3_24			0x3183
+#define MX28_PAD_I2C0_SDA__GPIO_3_25			0x3193
+#define MX28_PAD_SAIF1_SDATA0__GPIO_3_26		0x31a3
+#define MX28_PAD_SPDIF__GPIO_3_27			0x31b3
+#define MX28_PAD_PWM3__GPIO_3_28			0x31c3
+#define MX28_PAD_PWM4__GPIO_3_29			0x31d3
+#define MX28_PAD_LCD_RESET__GPIO_3_30			0x31e3
+#define MX28_PAD_ENET0_MDC__GPIO_4_0			0x4003
+#define MX28_PAD_ENET0_MDIO__GPIO_4_1			0x4013
+#define MX28_PAD_ENET0_RX_EN__GPIO_4_2			0x4023
+#define MX28_PAD_ENET0_RXD0__GPIO_4_3			0x4033
+#define MX28_PAD_ENET0_RXD1__GPIO_4_4			0x4043
+#define MX28_PAD_ENET0_TX_CLK__GPIO_4_5			0x4053
+#define MX28_PAD_ENET0_TX_EN__GPIO_4_6			0x4063
+#define MX28_PAD_ENET0_TXD0__GPIO_4_7			0x4073
+#define MX28_PAD_ENET0_TXD1__GPIO_4_8			0x4083
+#define MX28_PAD_ENET0_RXD2__GPIO_4_9			0x4093
+#define MX28_PAD_ENET0_RXD3__GPIO_4_10			0x40a3
+#define MX28_PAD_ENET0_TXD2__GPIO_4_11			0x40b3
+#define MX28_PAD_ENET0_TXD3__GPIO_4_12			0x40c3
+#define MX28_PAD_ENET0_RX_CLK__GPIO_4_13		0x40d3
+#define MX28_PAD_ENET0_COL__GPIO_4_14			0x40e3
+#define MX28_PAD_ENET0_CRS__GPIO_4_15			0x40f3
+#define MX28_PAD_ENET_CLK__GPIO_4_16			0x4103
+#define MX28_PAD_JTAG_RTCK__GPIO_4_20			0x4143
+
+#endif /* __DT_BINDINGS_MX28_PINCTRL_H__ */
diff --git a/arch/arm/dts/imx28-u-boot.dtsi b/arch/arm/dts/imx28-u-boot.dtsi
new file mode 100644
index 0000000..d545b40
--- /dev/null
+++ b/arch/arm/dts/imx28-u-boot.dtsi
@@ -0,0 +1,28 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2019
+ * Lukasz Majewski, DENX Software Engineering, lukma@denx.de
+ *
+ * SPDX-License-Identifier:     GPL-2.0+ or X11
+ */
+#include "imx28.dtsi"
+
+&gpio0 {
+	gpio-ranges = <&pinctrl 0 0 29>;
+};
+
+&gpio1 {
+	gpio-ranges = <&pinctrl 0 29 32>;
+};
+
+&gpio2 {
+	gpio-ranges = <&pinctrl 0 61 28>;
+};
+
+&gpio3 {
+	gpio-ranges = <&pinctrl 0 89 31>;
+};
+
+&gpio4 {
+	gpio-ranges = <&pinctrl 0 120 21>;
+};
diff --git a/arch/arm/dts/imx28.dtsi b/arch/arm/dts/imx28.dtsi
new file mode 100644
index 0000000..e14d8ef
--- /dev/null
+++ b/arch/arm/dts/imx28.dtsi
@@ -0,0 +1,1330 @@
+// SPDX-License-Identifier: GPL-2.0+
+//
+// Copyright 2012 Freescale Semiconductor, Inc.
+
+#include <dt-bindings/gpio/gpio.h>
+#include "imx28-pinfunc.h"
+
+/ {
+	#address-cells = <1>;
+	#size-cells = <1>;
+
+	interrupt-parent = <&icoll>;
+	/*
+	 * The decompressor and also some bootloaders rely on a
+	 * pre-existing /chosen node to be available to insert the
+	 * command line and merge other ATAGS info.
+	 */
+	chosen {};
+
+	aliases {
+		ethernet0 = &mac0;
+		ethernet1 = &mac1;
+		gpio0 = &gpio0;
+		gpio1 = &gpio1;
+		gpio2 = &gpio2;
+		gpio3 = &gpio3;
+		gpio4 = &gpio4;
+		saif0 = &saif0;
+		saif1 = &saif1;
+		serial0 = &auart0;
+		serial1 = &auart1;
+		serial2 = &auart2;
+		serial3 = &auart3;
+		serial4 = &auart4;
+		spi0 = &ssp1;
+		spi1 = &ssp2;
+		usbphy0 = &usbphy0;
+		usbphy1 = &usbphy1;
+	};
+
+	cpus {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		cpu@0 {
+			compatible = "arm,arm926ej-s";
+			device_type = "cpu";
+			reg = <0>;
+		};
+	};
+
+	apb@80000000 {
+		compatible = "simple-bus";
+		#address-cells = <1>;
+		#size-cells = <1>;
+		reg = <0x80000000 0x80000>;
+		ranges;
+
+		apbh@80000000 {
+			compatible = "simple-bus";
+			#address-cells = <1>;
+			#size-cells = <1>;
+			reg = <0x80000000 0x3c900>;
+			ranges;
+
+			icoll: interrupt-controller@80000000 {
+				compatible = "fsl,imx28-icoll", "fsl,icoll";
+				interrupt-controller;
+				#interrupt-cells = <1>;
+				reg = <0x80000000 0x2000>;
+			};
+
+			hsadc: hsadc@80002000 {
+				reg = <0x80002000 0x2000>;
+				interrupts = <13>;
+				dmas = <&dma_apbh 12>;
+				dma-names = "rx";
+				status = "disabled";
+			};
+
+			dma_apbh: dma-apbh@80004000 {
+				compatible = "fsl,imx28-dma-apbh";
+				reg = <0x80004000 0x2000>;
+				interrupts = <82 83 84 85
+					      88 88 88 88
+					      88 88 88 88
+					      87 86 0 0>;
+				interrupt-names = "ssp0", "ssp1", "ssp2", "ssp3",
+						  "gpmi0", "gmpi1", "gpmi2", "gmpi3",
+						  "gpmi4", "gmpi5", "gpmi6", "gmpi7",
+						  "hsadc", "lcdif", "empty", "empty";
+				#dma-cells = <1>;
+				dma-channels = <16>;
+				clocks = <&clks 25>;
+			};
+
+			perfmon: perfmon@80006000 {
+				reg = <0x80006000 0x800>;
+				interrupts = <27>;
+				status = "disabled";
+			};
+
+			gpmi: gpmi-nand@8000c000 {
+				compatible = "fsl,imx28-gpmi-nand";
+				#address-cells = <1>;
+				#size-cells = <1>;
+				reg = <0x8000c000 0x2000>, <0x8000a000 0x2000>;
+				reg-names = "gpmi-nand", "bch";
+				interrupts = <41>;
+				interrupt-names = "bch";
+				clocks = <&clks 50>;
+				clock-names = "gpmi_io";
+				dmas = <&dma_apbh 4>;
+				dma-names = "rx-tx";
+				status = "disabled";
+			};
+
+			ssp0: spi@80010000 {
+				#address-cells = <1>;
+				#size-cells = <0>;
+				reg = <0x80010000 0x2000>;
+				interrupts = <96>;
+				clocks = <&clks 46>;
+				dmas = <&dma_apbh 0>;
+				dma-names = "rx-tx";
+				status = "disabled";
+			};
+
+			ssp1: spi@80012000 {
+				#address-cells = <1>;
+				#size-cells = <0>;
+				reg = <0x80012000 0x2000>;
+				interrupts = <97>;
+				clocks = <&clks 47>;
+				dmas = <&dma_apbh 1>;
+				dma-names = "rx-tx";
+				status = "disabled";
+			};
+
+			ssp2: spi@80014000 {
+				#address-cells = <1>;
+				#size-cells = <0>;
+				reg = <0x80014000 0x2000>;
+				interrupts = <98>;
+				clocks = <&clks 48>;
+				dmas = <&dma_apbh 2>;
+				dma-names = "rx-tx";
+				status = "disabled";
+			};
+
+			ssp3: spi@80016000 {
+				#address-cells = <1>;
+				#size-cells = <0>;
+				reg = <0x80016000 0x2000>;
+				interrupts = <99>;
+				clocks = <&clks 49>;
+				dmas = <&dma_apbh 3>;
+				dma-names = "rx-tx";
+				status = "disabled";
+			};
+
+			pinctrl: pinctrl@80018000 {
+				#address-cells = <1>;
+				#size-cells = <0>;
+				compatible = "fsl,imx28-pinctrl", "simple-bus";
+				reg = <0x80018000 0x2000>;
+
+				gpio0: gpio@0 {
+					compatible = "fsl,imx28-gpio", "fsl,mxs-gpio";
+					reg = <0>;
+					interrupts = <127>;
+					gpio-controller;
+					#gpio-cells = <2>;
+					interrupt-controller;
+					#interrupt-cells = <2>;
+				};
+
+				gpio1: gpio@1 {
+					compatible = "fsl,imx28-gpio", "fsl,mxs-gpio";
+					reg = <1>;
+					interrupts = <126>;
+					gpio-controller;
+					#gpio-cells = <2>;
+					interrupt-controller;
+					#interrupt-cells = <2>;
+				};
+
+				gpio2: gpio@2 {
+					compatible = "fsl,imx28-gpio", "fsl,mxs-gpio";
+					reg = <2>;
+					interrupts = <125>;
+					gpio-controller;
+					#gpio-cells = <2>;
+					interrupt-controller;
+					#interrupt-cells = <2>;
+				};
+
+				gpio3: gpio@3 {
+					compatible = "fsl,imx28-gpio", "fsl,mxs-gpio";
+					reg = <3>;
+					interrupts = <124>;
+					gpio-controller;
+					#gpio-cells = <2>;
+					interrupt-controller;
+					#interrupt-cells = <2>;
+				};
+
+				gpio4: gpio@4 {
+					compatible = "fsl,imx28-gpio", "fsl,mxs-gpio";
+					reg = <4>;
+					interrupts = <123>;
+					gpio-controller;
+					#gpio-cells = <2>;
+					interrupt-controller;
+					#interrupt-cells = <2>;
+				};
+
+				duart_pins_a: duart@0 {
+					reg = <0>;
+					fsl,pinmux-ids = <
+						MX28_PAD_PWM0__DUART_RX
+						MX28_PAD_PWM1__DUART_TX
+					>;
+					fsl,drive-strength = <MXS_DRIVE_4mA>;
+					fsl,voltage = <MXS_VOLTAGE_HIGH>;
+					fsl,pull-up = <MXS_PULL_DISABLE>;
+				};
+
+				duart_pins_b: duart@1 {
+					reg = <1>;
+					fsl,pinmux-ids = <
+						MX28_PAD_AUART0_CTS__DUART_RX
+						MX28_PAD_AUART0_RTS__DUART_TX
+					>;
+					fsl,drive-strength = <MXS_DRIVE_4mA>;
+					fsl,voltage = <MXS_VOLTAGE_HIGH>;
+					fsl,pull-up = <MXS_PULL_DISABLE>;
+				};
+
+				duart_4pins_a: duart-4pins@0 {
+					reg = <0>;
+					fsl,pinmux-ids = <
+						MX28_PAD_AUART0_CTS__DUART_RX
+						MX28_PAD_AUART0_RTS__DUART_TX
+						MX28_PAD_AUART0_RX__DUART_CTS
+						MX28_PAD_AUART0_TX__DUART_RTS
+					>;
+					fsl,drive-strength = <MXS_DRIVE_4mA>;
+					fsl,voltage = <MXS_VOLTAGE_HIGH>;
+					fsl,pull-up = <MXS_PULL_DISABLE>;
+				};
+
+				gpmi_pins_a: gpmi-nand@0 {
+					reg = <0>;
+					fsl,pinmux-ids = <
+						MX28_PAD_GPMI_D00__GPMI_D0
+						MX28_PAD_GPMI_D01__GPMI_D1
+						MX28_PAD_GPMI_D02__GPMI_D2
+						MX28_PAD_GPMI_D03__GPMI_D3
+						MX28_PAD_GPMI_D04__GPMI_D4
+						MX28_PAD_GPMI_D05__GPMI_D5
+						MX28_PAD_GPMI_D06__GPMI_D6
+						MX28_PAD_GPMI_D07__GPMI_D7
+						MX28_PAD_GPMI_CE0N__GPMI_CE0N
+						MX28_PAD_GPMI_RDY0__GPMI_READY0
+						MX28_PAD_GPMI_RDN__GPMI_RDN
+						MX28_PAD_GPMI_WRN__GPMI_WRN
+						MX28_PAD_GPMI_ALE__GPMI_ALE
+						MX28_PAD_GPMI_CLE__GPMI_CLE
+						MX28_PAD_GPMI_RESETN__GPMI_RESETN
+					>;
+					fsl,drive-strength = <MXS_DRIVE_4mA>;
+					fsl,voltage = <MXS_VOLTAGE_HIGH>;
+					fsl,pull-up = <MXS_PULL_DISABLE>;
+				};
+
+				gpmi_status_cfg: gpmi-status-cfg@0 {
+					reg = <0>;
+					fsl,pinmux-ids = <
+						MX28_PAD_GPMI_RDN__GPMI_RDN
+						MX28_PAD_GPMI_WRN__GPMI_WRN
+						MX28_PAD_GPMI_RESETN__GPMI_RESETN
+					>;
+					fsl,drive-strength = <MXS_DRIVE_12mA>;
+				};
+
+				auart0_pins_a: auart0@0 {
+					reg = <0>;
+					fsl,pinmux-ids = <
+						MX28_PAD_AUART0_RX__AUART0_RX
+						MX28_PAD_AUART0_TX__AUART0_TX
+						MX28_PAD_AUART0_CTS__AUART0_CTS
+						MX28_PAD_AUART0_RTS__AUART0_RTS
+					>;
+					fsl,drive-strength = <MXS_DRIVE_4mA>;
+					fsl,voltage = <MXS_VOLTAGE_HIGH>;
+					fsl,pull-up = <MXS_PULL_DISABLE>;
+				};
+
+				auart0_2pins_a: auart0-2pins@0 {
+					reg = <0>;
+					fsl,pinmux-ids = <
+						MX28_PAD_AUART0_RX__AUART0_RX
+						MX28_PAD_AUART0_TX__AUART0_TX
+					>;
+					fsl,drive-strength = <MXS_DRIVE_4mA>;
+					fsl,voltage = <MXS_VOLTAGE_HIGH>;
+					fsl,pull-up = <MXS_PULL_DISABLE>;
+				};
+
+				auart1_pins_a: auart1@0 {
+					reg = <0>;
+					fsl,pinmux-ids = <
+						MX28_PAD_AUART1_RX__AUART1_RX
+						MX28_PAD_AUART1_TX__AUART1_TX
+						MX28_PAD_AUART1_CTS__AUART1_CTS
+						MX28_PAD_AUART1_RTS__AUART1_RTS
+					>;
+					fsl,drive-strength = <MXS_DRIVE_4mA>;
+					fsl,voltage = <MXS_VOLTAGE_HIGH>;
+					fsl,pull-up = <MXS_PULL_DISABLE>;
+				};
+
+				auart1_2pins_a: auart1-2pins@0 {
+					reg = <0>;
+					fsl,pinmux-ids = <
+						MX28_PAD_AUART1_RX__AUART1_RX
+						MX28_PAD_AUART1_TX__AUART1_TX
+					>;
+					fsl,drive-strength = <MXS_DRIVE_4mA>;
+					fsl,voltage = <MXS_VOLTAGE_HIGH>;
+					fsl,pull-up = <MXS_PULL_DISABLE>;
+				};
+
+				auart2_2pins_a: auart2-2pins@0 {
+					reg = <0>;
+					fsl,pinmux-ids = <
+						MX28_PAD_SSP2_SCK__AUART2_RX
+						MX28_PAD_SSP2_MOSI__AUART2_TX
+					>;
+					fsl,drive-strength = <MXS_DRIVE_4mA>;
+					fsl,voltage = <MXS_VOLTAGE_HIGH>;
+					fsl,pull-up = <MXS_PULL_DISABLE>;
+				};
+
+				auart2_2pins_b: auart2-2pins@1 {
+					reg = <1>;
+					fsl,pinmux-ids = <
+						MX28_PAD_AUART2_RX__AUART2_RX
+						MX28_PAD_AUART2_TX__AUART2_TX
+					>;
+					fsl,drive-strength = <MXS_DRIVE_4mA>;
+					fsl,voltage = <MXS_VOLTAGE_HIGH>;
+					fsl,pull-up = <MXS_PULL_DISABLE>;
+				};
+
+				auart2_pins_a: auart2-pins@0 {
+					reg = <0>;
+					fsl,pinmux-ids = <
+						MX28_PAD_AUART2_RX__AUART2_RX
+						MX28_PAD_AUART2_TX__AUART2_TX
+						MX28_PAD_AUART2_CTS__AUART2_CTS
+						MX28_PAD_AUART2_RTS__AUART2_RTS
+					>;
+					fsl,drive-strength = <MXS_DRIVE_4mA>;
+					fsl,voltage = <MXS_VOLTAGE_HIGH>;
+					fsl,pull-up = <MXS_PULL_DISABLE>;
+				};
+
+				auart3_pins_a: auart3@0 {
+					reg = <0>;
+					fsl,pinmux-ids = <
+						MX28_PAD_AUART3_RX__AUART3_RX
+						MX28_PAD_AUART3_TX__AUART3_TX
+						MX28_PAD_AUART3_CTS__AUART3_CTS
+						MX28_PAD_AUART3_RTS__AUART3_RTS
+					>;
+					fsl,drive-strength = <MXS_DRIVE_4mA>;
+					fsl,voltage = <MXS_VOLTAGE_HIGH>;
+					fsl,pull-up = <MXS_PULL_DISABLE>;
+				};
+
+				auart3_2pins_a: auart3-2pins@0 {
+					reg = <0>;
+					fsl,pinmux-ids = <
+						MX28_PAD_SSP2_MISO__AUART3_RX
+						MX28_PAD_SSP2_SS0__AUART3_TX
+					>;
+					fsl,drive-strength = <MXS_DRIVE_4mA>;
+					fsl,voltage = <MXS_VOLTAGE_HIGH>;
+					fsl,pull-up = <MXS_PULL_DISABLE>;
+				};
+
+				auart3_2pins_b: auart3-2pins@1 {
+					reg = <1>;
+					fsl,pinmux-ids = <
+						MX28_PAD_AUART3_RX__AUART3_RX
+						MX28_PAD_AUART3_TX__AUART3_TX
+					>;
+					fsl,drive-strength = <MXS_DRIVE_4mA>;
+					fsl,voltage = <MXS_VOLTAGE_HIGH>;
+					fsl,pull-up = <MXS_PULL_DISABLE>;
+				};
+
+				auart4_2pins_a: auart4@0 {
+					reg = <0>;
+					fsl,pinmux-ids = <
+						MX28_PAD_SSP3_SCK__AUART4_TX
+						MX28_PAD_SSP3_MOSI__AUART4_RX
+					>;
+					fsl,drive-strength = <MXS_DRIVE_4mA>;
+					fsl,voltage = <MXS_VOLTAGE_HIGH>;
+					fsl,pull-up = <MXS_PULL_DISABLE>;
+				};
+
+				auart4_2pins_b: auart4@1 {
+					reg = <1>;
+					fsl,pinmux-ids = <
+						MX28_PAD_AUART0_CTS__AUART4_RX
+						MX28_PAD_AUART0_RTS__AUART4_TX
+					>;
+					fsl,drive-strength = <MXS_DRIVE_4mA>;
+					fsl,voltage = <MXS_VOLTAGE_HIGH>;
+					fsl,pull-up = <MXS_PULL_DISABLE>;
+				};
+
+				mac0_pins_a: mac0@0 {
+					reg = <0>;
+					fsl,pinmux-ids = <
+						MX28_PAD_ENET0_MDC__ENET0_MDC
+						MX28_PAD_ENET0_MDIO__ENET0_MDIO
+						MX28_PAD_ENET0_RX_EN__ENET0_RX_EN
+						MX28_PAD_ENET0_RXD0__ENET0_RXD0
+						MX28_PAD_ENET0_RXD1__ENET0_RXD1
+						MX28_PAD_ENET0_TX_EN__ENET0_TX_EN
+						MX28_PAD_ENET0_TXD0__ENET0_TXD0
+						MX28_PAD_ENET0_TXD1__ENET0_TXD1
+						MX28_PAD_ENET_CLK__CLKCTRL_ENET
+					>;
+					fsl,drive-strength = <MXS_DRIVE_8mA>;
+					fsl,voltage = <MXS_VOLTAGE_HIGH>;
+					fsl,pull-up = <MXS_PULL_ENABLE>;
+				};
+
+				mac0_pins_b: mac0@1 {
+					reg = <1>;
+					fsl,pinmux-ids = <
+						MX28_PAD_ENET0_MDC__ENET0_MDC
+						MX28_PAD_ENET0_MDIO__ENET0_MDIO
+						MX28_PAD_ENET0_RX_EN__ENET0_RX_EN
+						MX28_PAD_ENET0_RXD0__ENET0_RXD0
+						MX28_PAD_ENET0_RXD1__ENET0_RXD1
+						MX28_PAD_ENET0_RXD2__ENET0_RXD2
+						MX28_PAD_ENET0_RXD3__ENET0_RXD3
+						MX28_PAD_ENET0_TX_EN__ENET0_TX_EN
+						MX28_PAD_ENET0_TXD0__ENET0_TXD0
+						MX28_PAD_ENET0_TXD1__ENET0_TXD1
+						MX28_PAD_ENET0_TXD2__ENET0_TXD2
+						MX28_PAD_ENET0_TXD3__ENET0_TXD3
+						MX28_PAD_ENET_CLK__CLKCTRL_ENET
+						MX28_PAD_ENET0_COL__ENET0_COL
+						MX28_PAD_ENET0_CRS__ENET0_CRS
+						MX28_PAD_ENET0_TX_CLK__ENET0_TX_CLK
+						MX28_PAD_ENET0_RX_CLK__ENET0_RX_CLK
+						>;
+					fsl,drive-strength = <MXS_DRIVE_8mA>;
+					fsl,voltage = <MXS_VOLTAGE_HIGH>;
+					fsl,pull-up = <MXS_PULL_ENABLE>;
+				};
+
+				mac1_pins_a: mac1@0 {
+					reg = <0>;
+					fsl,pinmux-ids = <
+						MX28_PAD_ENET0_CRS__ENET1_RX_EN
+						MX28_PAD_ENET0_RXD2__ENET1_RXD0
+						MX28_PAD_ENET0_RXD3__ENET1_RXD1
+						MX28_PAD_ENET0_COL__ENET1_TX_EN
+						MX28_PAD_ENET0_TXD2__ENET1_TXD0
+						MX28_PAD_ENET0_TXD3__ENET1_TXD1
+					>;
+					fsl,drive-strength = <MXS_DRIVE_8mA>;
+					fsl,voltage = <MXS_VOLTAGE_HIGH>;
+					fsl,pull-up = <MXS_PULL_ENABLE>;
+				};
+
+				mmc0_8bit_pins_a: mmc0-8bit@0 {
+					reg = <0>;
+					fsl,pinmux-ids = <
+						MX28_PAD_SSP0_DATA0__SSP0_D0
+						MX28_PAD_SSP0_DATA1__SSP0_D1
+						MX28_PAD_SSP0_DATA2__SSP0_D2
+						MX28_PAD_SSP0_DATA3__SSP0_D3
+						MX28_PAD_SSP0_DATA4__SSP0_D4
+						MX28_PAD_SSP0_DATA5__SSP0_D5
+						MX28_PAD_SSP0_DATA6__SSP0_D6
+						MX28_PAD_SSP0_DATA7__SSP0_D7
+						MX28_PAD_SSP0_CMD__SSP0_CMD
+						MX28_PAD_SSP0_DETECT__SSP0_CARD_DETECT
+						MX28_PAD_SSP0_SCK__SSP0_SCK
+					>;
+					fsl,drive-strength = <MXS_DRIVE_8mA>;
+					fsl,voltage = <MXS_VOLTAGE_HIGH>;
+					fsl,pull-up = <MXS_PULL_ENABLE>;
+				};
+
+				mmc0_4bit_pins_a: mmc0-4bit@0 {
+					reg = <0>;
+					fsl,pinmux-ids = <
+						MX28_PAD_SSP0_DATA0__SSP0_D0
+						MX28_PAD_SSP0_DATA1__SSP0_D1
+						MX28_PAD_SSP0_DATA2__SSP0_D2
+						MX28_PAD_SSP0_DATA3__SSP0_D3
+						MX28_PAD_SSP0_CMD__SSP0_CMD
+						MX28_PAD_SSP0_DETECT__SSP0_CARD_DETECT
+						MX28_PAD_SSP0_SCK__SSP0_SCK
+					>;
+					fsl,drive-strength = <MXS_DRIVE_8mA>;
+					fsl,voltage = <MXS_VOLTAGE_HIGH>;
+					fsl,pull-up = <MXS_PULL_ENABLE>;
+				};
+
+				mmc0_cd_cfg: mmc0-cd-cfg@0 {
+					reg = <0>;
+					fsl,pinmux-ids = <
+						MX28_PAD_SSP0_DETECT__SSP0_CARD_DETECT
+					>;
+					fsl,pull-up = <MXS_PULL_DISABLE>;
+				};
+
+				mmc0_sck_cfg: mmc0-sck-cfg@0 {
+					reg = <0>;
+					fsl,pinmux-ids = <
+						MX28_PAD_SSP0_SCK__SSP0_SCK
+					>;
+					fsl,drive-strength = <MXS_DRIVE_12mA>;
+					fsl,pull-up = <MXS_PULL_DISABLE>;
+				};
+
+				mmc1_4bit_pins_a: mmc1-4bit@0 {
+					reg = <0>;
+					fsl,pinmux-ids = <
+						MX28_PAD_GPMI_D00__SSP1_D0
+						MX28_PAD_GPMI_D01__SSP1_D1
+						MX28_PAD_GPMI_D02__SSP1_D2
+						MX28_PAD_GPMI_D03__SSP1_D3
+						MX28_PAD_GPMI_RDY1__SSP1_CMD
+						MX28_PAD_GPMI_RDY0__SSP1_CARD_DETECT
+						MX28_PAD_GPMI_WRN__SSP1_SCK
+					>;
+					fsl,drive-strength = <MXS_DRIVE_8mA>;
+					fsl,voltage = <MXS_VOLTAGE_HIGH>;
+					fsl,pull-up = <MXS_PULL_ENABLE>;
+				};
+
+				mmc1_cd_cfg: mmc1-cd-cfg@0 {
+					reg = <0>;
+					fsl,pinmux-ids = <
+						MX28_PAD_GPMI_RDY0__SSP1_CARD_DETECT
+					>;
+					fsl,pull-up = <MXS_PULL_DISABLE>;
+				};
+
+				mmc1_sck_cfg: mmc1-sck-cfg@0 {
+					reg = <0>;
+					fsl,pinmux-ids = <
+						MX28_PAD_GPMI_WRN__SSP1_SCK
+					>;
+					fsl,drive-strength = <MXS_DRIVE_12mA>;
+					fsl,pull-up = <MXS_PULL_DISABLE>;
+				};
+
+
+				mmc2_4bit_pins_a: mmc2-4bit@0 {
+					reg = <0>;
+					fsl,pinmux-ids = <
+						MX28_PAD_SSP0_DATA4__SSP2_D0
+						MX28_PAD_SSP1_SCK__SSP2_D1
+						MX28_PAD_SSP1_CMD__SSP2_D2
+						MX28_PAD_SSP0_DATA5__SSP2_D3
+						MX28_PAD_SSP0_DATA6__SSP2_CMD
+						MX28_PAD_AUART1_RX__SSP2_CARD_DETECT
+						MX28_PAD_SSP0_DATA7__SSP2_SCK
+					>;
+					fsl,drive-strength = <MXS_DRIVE_8mA>;
+					fsl,voltage = <MXS_VOLTAGE_HIGH>;
+					fsl,pull-up = <MXS_PULL_ENABLE>;
+				};
+
+				mmc2_4bit_pins_b: mmc2-4bit@1 {
+					reg = <1>;
+					fsl,pinmux-ids = <
+						MX28_PAD_SSP2_SCK__SSP2_SCK
+						MX28_PAD_SSP2_MOSI__SSP2_CMD
+						MX28_PAD_SSP2_MISO__SSP2_D0
+						MX28_PAD_SSP2_SS0__SSP2_D3
+						MX28_PAD_SSP2_SS1__SSP2_D1
+						MX28_PAD_SSP2_SS2__SSP2_D2
+						MX28_PAD_AUART1_RX__SSP2_CARD_DETECT
+					>;
+					fsl,drive-strength = <MXS_DRIVE_8mA>;
+					fsl,voltage = <MXS_VOLTAGE_HIGH>;
+					fsl,pull-up = <MXS_PULL_ENABLE>;
+				};
+
+				mmc2_cd_cfg: mmc2-cd-cfg@0 {
+					reg = <0>;
+					fsl,pinmux-ids = <
+						MX28_PAD_AUART1_RX__SSP2_CARD_DETECT
+					>;
+					fsl,pull-up = <MXS_PULL_DISABLE>;
+				};
+
+				mmc2_sck_cfg_a: mmc2-sck-cfg@0 {
+					reg = <0>;
+					fsl,pinmux-ids = <
+						MX28_PAD_SSP0_DATA7__SSP2_SCK
+					>;
+					fsl,drive-strength = <MXS_DRIVE_12mA>;
+					fsl,pull-up = <MXS_PULL_DISABLE>;
+				};
+
+				mmc2_sck_cfg_b: mmc2-sck-cfg@1 {
+					reg = <1>;
+					fsl,pinmux-ids = <
+						MX28_PAD_SSP2_SCK__SSP2_SCK
+					>;
+					fsl,drive-strength = <MXS_DRIVE_12mA>;
+					fsl,pull-up = <MXS_PULL_DISABLE>;
+				};
+
+				i2c0_pins_a: i2c0@0 {
+					reg = <0>;
+					fsl,pinmux-ids = <
+						MX28_PAD_I2C0_SCL__I2C0_SCL
+						MX28_PAD_I2C0_SDA__I2C0_SDA
+					>;
+					fsl,drive-strength = <MXS_DRIVE_8mA>;
+					fsl,voltage = <MXS_VOLTAGE_HIGH>;
+					fsl,pull-up = <MXS_PULL_ENABLE>;
+				};
+
+				i2c0_pins_b: i2c0@1 {
+					reg = <1>;
+					fsl,pinmux-ids = <
+						MX28_PAD_AUART0_RX__I2C0_SCL
+						MX28_PAD_AUART0_TX__I2C0_SDA
+					>;
+					fsl,drive-strength = <MXS_DRIVE_8mA>;
+					fsl,voltage = <MXS_VOLTAGE_HIGH>;
+					fsl,pull-up = <MXS_PULL_ENABLE>;
+				};
+
+				i2c1_pins_a: i2c1@0 {
+					reg = <0>;
+					fsl,pinmux-ids = <
+						MX28_PAD_PWM0__I2C1_SCL
+						MX28_PAD_PWM1__I2C1_SDA
+					>;
+					fsl,drive-strength = <MXS_DRIVE_8mA>;
+					fsl,voltage = <MXS_VOLTAGE_HIGH>;
+					fsl,pull-up = <MXS_PULL_ENABLE>;
+				};
+
+				i2c1_pins_b: i2c1@1 {
+					reg = <1>;
+					fsl,pinmux-ids = <
+						MX28_PAD_AUART2_CTS__I2C1_SCL
+						MX28_PAD_AUART2_RTS__I2C1_SDA
+					>;
+					fsl,drive-strength = <MXS_DRIVE_8mA>;
+					fsl,voltage = <MXS_VOLTAGE_HIGH>;
+					fsl,pull-up = <MXS_PULL_ENABLE>;
+				};
+
+				saif0_pins_a: saif0@0 {
+					reg = <0>;
+					fsl,pinmux-ids = <
+						MX28_PAD_SAIF0_MCLK__SAIF0_MCLK
+						MX28_PAD_SAIF0_LRCLK__SAIF0_LRCLK
+						MX28_PAD_SAIF0_BITCLK__SAIF0_BITCLK
+						MX28_PAD_SAIF0_SDATA0__SAIF0_SDATA0
+					>;
+					fsl,drive-strength = <MXS_DRIVE_12mA>;
+					fsl,voltage = <MXS_VOLTAGE_HIGH>;
+					fsl,pull-up = <MXS_PULL_ENABLE>;
+				};
+
+				saif0_pins_b: saif0@1 {
+					reg = <1>;
+					fsl,pinmux-ids = <
+						MX28_PAD_SAIF0_LRCLK__SAIF0_LRCLK
+						MX28_PAD_SAIF0_BITCLK__SAIF0_BITCLK
+						MX28_PAD_SAIF0_SDATA0__SAIF0_SDATA0
+					>;
+					fsl,drive-strength = <MXS_DRIVE_12mA>;
+					fsl,voltage = <MXS_VOLTAGE_HIGH>;
+					fsl,pull-up = <MXS_PULL_ENABLE>;
+				};
+
+				saif1_pins_a: saif1@0 {
+					reg = <0>;
+					fsl,pinmux-ids = <
+						MX28_PAD_SAIF1_SDATA0__SAIF1_SDATA0
+					>;
+					fsl,drive-strength = <MXS_DRIVE_12mA>;
+					fsl,voltage = <MXS_VOLTAGE_HIGH>;
+					fsl,pull-up = <MXS_PULL_ENABLE>;
+				};
+
+				pwm0_pins_a: pwm0@0 {
+					reg = <0>;
+					fsl,pinmux-ids = <
+						MX28_PAD_PWM0__PWM_0
+					>;
+					fsl,drive-strength = <MXS_DRIVE_4mA>;
+					fsl,voltage = <MXS_VOLTAGE_HIGH>;
+					fsl,pull-up = <MXS_PULL_DISABLE>;
+				};
+
+				pwm2_pins_a: pwm2@0 {
+					reg = <0>;
+					fsl,pinmux-ids = <
+						MX28_PAD_PWM2__PWM_2
+					>;
+					fsl,drive-strength = <MXS_DRIVE_4mA>;
+					fsl,voltage = <MXS_VOLTAGE_HIGH>;
+					fsl,pull-up = <MXS_PULL_DISABLE>;
+				};
+
+				pwm3_pins_a: pwm3@0 {
+					reg = <0>;
+					fsl,pinmux-ids = <
+						MX28_PAD_PWM3__PWM_3
+					>;
+					fsl,drive-strength = <MXS_DRIVE_4mA>;
+					fsl,voltage = <MXS_VOLTAGE_HIGH>;
+					fsl,pull-up = <MXS_PULL_DISABLE>;
+				};
+
+				pwm3_pins_b: pwm3@1 {
+					reg = <1>;
+					fsl,pinmux-ids = <
+						MX28_PAD_SAIF0_MCLK__PWM_3
+					>;
+					fsl,drive-strength = <MXS_DRIVE_4mA>;
+					fsl,voltage = <MXS_VOLTAGE_HIGH>;
+					fsl,pull-up = <MXS_PULL_DISABLE>;
+				};
+
+				pwm4_pins_a: pwm4@0 {
+					reg = <0>;
+					fsl,pinmux-ids = <
+						MX28_PAD_PWM4__PWM_4
+					>;
+					fsl,drive-strength = <MXS_DRIVE_4mA>;
+					fsl,voltage = <MXS_VOLTAGE_HIGH>;
+					fsl,pull-up = <MXS_PULL_DISABLE>;
+				};
+
+				lcdif_24bit_pins_a: lcdif-24bit@0 {
+					reg = <0>;
+					fsl,pinmux-ids = <
+						MX28_PAD_LCD_D00__LCD_D0
+						MX28_PAD_LCD_D01__LCD_D1
+						MX28_PAD_LCD_D02__LCD_D2
+						MX28_PAD_LCD_D03__LCD_D3
+						MX28_PAD_LCD_D04__LCD_D4
+						MX28_PAD_LCD_D05__LCD_D5
+						MX28_PAD_LCD_D06__LCD_D6
+						MX28_PAD_LCD_D07__LCD_D7
+						MX28_PAD_LCD_D08__LCD_D8
+						MX28_PAD_LCD_D09__LCD_D9
+						MX28_PAD_LCD_D10__LCD_D10
+						MX28_PAD_LCD_D11__LCD_D11
+						MX28_PAD_LCD_D12__LCD_D12
+						MX28_PAD_LCD_D13__LCD_D13
+						MX28_PAD_LCD_D14__LCD_D14
+						MX28_PAD_LCD_D15__LCD_D15
+						MX28_PAD_LCD_D16__LCD_D16
+						MX28_PAD_LCD_D17__LCD_D17
+						MX28_PAD_LCD_D18__LCD_D18
+						MX28_PAD_LCD_D19__LCD_D19
+						MX28_PAD_LCD_D20__LCD_D20
+						MX28_PAD_LCD_D21__LCD_D21
+						MX28_PAD_LCD_D22__LCD_D22
+						MX28_PAD_LCD_D23__LCD_D23
+					>;
+					fsl,drive-strength = <MXS_DRIVE_4mA>;
+					fsl,voltage = <MXS_VOLTAGE_HIGH>;
+					fsl,pull-up = <MXS_PULL_DISABLE>;
+				};
+
+				lcdif_18bit_pins_a: lcdif-18bit@0 {
+					reg = <0>;
+					fsl,pinmux-ids = <
+						MX28_PAD_LCD_D00__LCD_D0
+						MX28_PAD_LCD_D01__LCD_D1
+						MX28_PAD_LCD_D02__LCD_D2
+						MX28_PAD_LCD_D03__LCD_D3
+						MX28_PAD_LCD_D04__LCD_D4
+						MX28_PAD_LCD_D05__LCD_D5
+						MX28_PAD_LCD_D06__LCD_D6
+						MX28_PAD_LCD_D07__LCD_D7
+						MX28_PAD_LCD_D08__LCD_D8
+						MX28_PAD_LCD_D09__LCD_D9
+						MX28_PAD_LCD_D10__LCD_D10
+						MX28_PAD_LCD_D11__LCD_D11
+						MX28_PAD_LCD_D12__LCD_D12
+						MX28_PAD_LCD_D13__LCD_D13
+						MX28_PAD_LCD_D14__LCD_D14
+						MX28_PAD_LCD_D15__LCD_D15
+						MX28_PAD_LCD_D16__LCD_D16
+						MX28_PAD_LCD_D17__LCD_D17
+					>;
+					fsl,drive-strength = <MXS_DRIVE_4mA>;
+					fsl,voltage = <MXS_VOLTAGE_HIGH>;
+					fsl,pull-up = <MXS_PULL_DISABLE>;
+				};
+
+				lcdif_16bit_pins_a: lcdif-16bit@0 {
+					reg = <0>;
+					fsl,pinmux-ids = <
+						MX28_PAD_LCD_D00__LCD_D0
+						MX28_PAD_LCD_D01__LCD_D1
+						MX28_PAD_LCD_D02__LCD_D2
+						MX28_PAD_LCD_D03__LCD_D3
+						MX28_PAD_LCD_D04__LCD_D4
+						MX28_PAD_LCD_D05__LCD_D5
+						MX28_PAD_LCD_D06__LCD_D6
+						MX28_PAD_LCD_D07__LCD_D7
+						MX28_PAD_LCD_D08__LCD_D8
+						MX28_PAD_LCD_D09__LCD_D9
+						MX28_PAD_LCD_D10__LCD_D10
+						MX28_PAD_LCD_D11__LCD_D11
+						MX28_PAD_LCD_D12__LCD_D12
+						MX28_PAD_LCD_D13__LCD_D13
+						MX28_PAD_LCD_D14__LCD_D14
+						MX28_PAD_LCD_D15__LCD_D15
+					>;
+					fsl,drive-strength = <MXS_DRIVE_4mA>;
+					fsl,voltage = <MXS_VOLTAGE_HIGH>;
+					fsl,pull-up = <MXS_PULL_DISABLE>;
+				};
+
+				lcdif_sync_pins_a: lcdif-sync@0 {
+					reg = <0>;
+					fsl,pinmux-ids = <
+						MX28_PAD_LCD_RS__LCD_DOTCLK
+						MX28_PAD_LCD_CS__LCD_ENABLE
+						MX28_PAD_LCD_RD_E__LCD_VSYNC
+						MX28_PAD_LCD_WR_RWN__LCD_HSYNC
+					>;
+					fsl,drive-strength = <MXS_DRIVE_4mA>;
+					fsl,voltage = <MXS_VOLTAGE_HIGH>;
+					fsl,pull-up = <MXS_PULL_DISABLE>;
+				};
+
+				can0_pins_a: can0@0 {
+					reg = <0>;
+					fsl,pinmux-ids = <
+						MX28_PAD_GPMI_RDY2__CAN0_TX
+						MX28_PAD_GPMI_RDY3__CAN0_RX
+					>;
+					fsl,drive-strength = <MXS_DRIVE_4mA>;
+					fsl,voltage = <MXS_VOLTAGE_HIGH>;
+					fsl,pull-up = <MXS_PULL_DISABLE>;
+				};
+
+				can1_pins_a: can1@0 {
+					reg = <0>;
+					fsl,pinmux-ids = <
+						MX28_PAD_GPMI_CE2N__CAN1_TX
+						MX28_PAD_GPMI_CE3N__CAN1_RX
+					>;
+					fsl,drive-strength = <MXS_DRIVE_4mA>;
+					fsl,voltage = <MXS_VOLTAGE_HIGH>;
+					fsl,pull-up = <MXS_PULL_DISABLE>;
+				};
+
+				spi2_pins_a: spi2@0 {
+					reg = <0>;
+					fsl,pinmux-ids = <
+						MX28_PAD_SSP2_SCK__SSP2_SCK
+						MX28_PAD_SSP2_MOSI__SSP2_CMD
+						MX28_PAD_SSP2_MISO__SSP2_D0
+						MX28_PAD_SSP2_SS0__SSP2_D3
+					>;
+					fsl,drive-strength = <MXS_DRIVE_8mA>;
+					fsl,voltage = <MXS_VOLTAGE_HIGH>;
+					fsl,pull-up = <MXS_PULL_ENABLE>;
+				};
+
+				spi3_pins_a: spi3@0 {
+					reg = <0>;
+					fsl,pinmux-ids = <
+						MX28_PAD_AUART2_RX__SSP3_D4
+						MX28_PAD_AUART2_TX__SSP3_D5
+						MX28_PAD_SSP3_SCK__SSP3_SCK
+						MX28_PAD_SSP3_MOSI__SSP3_CMD
+						MX28_PAD_SSP3_MISO__SSP3_D0
+						MX28_PAD_SSP3_SS0__SSP3_D3
+					>;
+					fsl,drive-strength = <MXS_DRIVE_8mA>;
+					fsl,voltage = <MXS_VOLTAGE_HIGH>;
+					fsl,pull-up = <MXS_PULL_DISABLE>;
+				};
+
+				spi3_pins_b: spi3@1 {
+					reg = <1>;
+					fsl,pinmux-ids = <
+						MX28_PAD_SSP3_SCK__SSP3_SCK
+						MX28_PAD_SSP3_MOSI__SSP3_CMD
+						MX28_PAD_SSP3_MISO__SSP3_D0
+						MX28_PAD_SSP3_SS0__SSP3_D3
+					>;
+					fsl,drive-strength = <MXS_DRIVE_8mA>;
+					fsl,voltage = <MXS_VOLTAGE_HIGH>;
+					fsl,pull-up = <MXS_PULL_ENABLE>;
+				};
+
+				usb0_pins_a: usb0@0 {
+					reg = <0>;
+					fsl,pinmux-ids = <
+						MX28_PAD_SSP2_SS2__USB0_OVERCURRENT
+					>;
+					fsl,drive-strength = <MXS_DRIVE_12mA>;
+					fsl,voltage = <MXS_VOLTAGE_HIGH>;
+					fsl,pull-up = <MXS_PULL_DISABLE>;
+				};
+
+				usb0_pins_b: usb0@1 {
+					reg = <1>;
+					fsl,pinmux-ids = <
+						MX28_PAD_AUART1_CTS__USB0_OVERCURRENT
+					>;
+					fsl,drive-strength = <MXS_DRIVE_12mA>;
+					fsl,voltage = <MXS_VOLTAGE_HIGH>;
+					fsl,pull-up = <MXS_PULL_DISABLE>;
+				};
+
+				usb1_pins_a: usb1@0 {
+					reg = <0>;
+					fsl,pinmux-ids = <
+						MX28_PAD_SSP2_SS1__USB1_OVERCURRENT
+					>;
+					fsl,drive-strength = <MXS_DRIVE_12mA>;
+					fsl,voltage = <MXS_VOLTAGE_HIGH>;
+					fsl,pull-up = <MXS_PULL_DISABLE>;
+				};
+
+				usb0_id_pins_a: usb0id@0 {
+					reg = <0>;
+					fsl,pinmux-ids = <
+						MX28_PAD_AUART1_RTS__USB0_ID
+					>;
+					fsl,drive-strength = <MXS_DRIVE_12mA>;
+					fsl,voltage = <MXS_VOLTAGE_HIGH>;
+					fsl,pull-up = <MXS_PULL_ENABLE>;
+				};
+
+				usb0_id_pins_b: usb0id1@0 {
+					reg = <0>;
+					fsl,pinmux-ids = <
+						MX28_PAD_PWM2__USB0_ID
+					>;
+					fsl,drive-strength = <MXS_DRIVE_12mA>;
+					fsl,voltage = <MXS_VOLTAGE_HIGH>;
+					fsl,pull-up = <MXS_PULL_ENABLE>;
+				};
+
+			};
+
+			digctl: digctl@8001c000 {
+				compatible = "fsl,imx28-digctl", "fsl,imx23-digctl";
+				reg = <0x8001c000 0x2000>;
+				interrupts = <89>;
+				status = "disabled";
+			};
+
+			etm: etm@80022000 {
+				reg = <0x80022000 0x2000>;
+				status = "disabled";
+			};
+
+			dma_apbx: dma-apbx@80024000 {
+				compatible = "fsl,imx28-dma-apbx";
+				reg = <0x80024000 0x2000>;
+				interrupts = <78 79 66 0
+					      80 81 68 69
+					      70 71 72 73
+					      74 75 76 77>;
+				interrupt-names = "auart4-rx", "auart4-tx", "spdif-tx", "empty",
+						  "saif0", "saif1", "i2c0", "i2c1",
+						  "auart0-rx", "auart0-tx", "auart1-rx", "auart1-tx",
+						  "auart2-rx", "auart2-tx", "auart3-rx", "auart3-tx";
+				#dma-cells = <1>;
+				dma-channels = <16>;
+				clocks = <&clks 26>;
+			};
+
+			dcp: dcp@80028000 {
+				compatible = "fsl,imx28-dcp", "fsl,imx23-dcp";
+				reg = <0x80028000 0x2000>;
+				interrupts = <52 53 54>;
+				status = "okay";
+			};
+
+			pxp: pxp@8002a000 {
+				reg = <0x8002a000 0x2000>;
+				interrupts = <39>;
+				status = "disabled";
+			};
+
+			ocotp: ocotp@8002c000 {
+				compatible = "fsl,imx28-ocotp", "fsl,ocotp";
+				#address-cells = <1>;
+				#size-cells = <1>;
+				reg = <0x8002c000 0x2000>;
+				clocks = <&clks 25>;
+			};
+
+			axi-ahb@8002e000 {
+				reg = <0x8002e000 0x2000>;
+				status = "disabled";
+			};
+
+			lcdif: lcdif@80030000 {
+				compatible = "fsl,imx28-lcdif";
+				reg = <0x80030000 0x2000>;
+				interrupts = <38>;
+				clocks = <&clks 55>;
+				dmas = <&dma_apbh 13>;
+				dma-names = "rx";
+				status = "disabled";
+			};
+
+			can0: can@80032000 {
+				compatible = "fsl,imx28-flexcan";
+				reg = <0x80032000 0x2000>;
+				interrupts = <8>;
+				clocks = <&clks 58>, <&clks 58>;
+				clock-names = "ipg", "per";
+				status = "disabled";
+			};
+
+			can1: can@80034000 {
+				compatible = "fsl,imx28-flexcan";
+				reg = <0x80034000 0x2000>;
+				interrupts = <9>;
+				clocks = <&clks 59>, <&clks 59>;
+				clock-names = "ipg", "per";
+				status = "disabled";
+			};
+
+			simdbg: simdbg@8003c000 {
+				reg = <0x8003c000 0x200>;
+				status = "disabled";
+			};
+
+			simgpmisel: simgpmisel@8003c200 {
+				reg = <0x8003c200 0x100>;
+				status = "disabled";
+			};
+
+			simsspsel: simsspsel@8003c300 {
+				reg = <0x8003c300 0x100>;
+				status = "disabled";
+			};
+
+			simmemsel: simmemsel@8003c400 {
+				reg = <0x8003c400 0x100>;
+				status = "disabled";
+			};
+
+			gpiomon: gpiomon@8003c500 {
+				reg = <0x8003c500 0x100>;
+				status = "disabled";
+			};
+
+			simenet: simenet@8003c700 {
+				reg = <0x8003c700 0x100>;
+				status = "disabled";
+			};
+
+			armjtag: armjtag@8003c800 {
+				reg = <0x8003c800 0x100>;
+				status = "disabled";
+			};
+		};
+
+		apbx@80040000 {
+			compatible = "simple-bus";
+			#address-cells = <1>;
+			#size-cells = <1>;
+			reg = <0x80040000 0x40000>;
+			ranges;
+
+			clks: clkctrl@80040000 {
+				compatible = "fsl,imx28-clkctrl", "fsl,clkctrl";
+				reg = <0x80040000 0x2000>;
+				#clock-cells = <1>;
+			};
+
+			saif0: saif@80042000 {
+				#sound-dai-cells = <0>;
+				compatible = "fsl,imx28-saif";
+				reg = <0x80042000 0x2000>;
+				interrupts = <59>;
+				#clock-cells = <0>;
+				clocks = <&clks 53>;
+				dmas = <&dma_apbx 4>;
+				dma-names = "rx-tx";
+				status = "disabled";
+			};
+
+			power: power@80044000 {
+				reg = <0x80044000 0x2000>;
+				status = "disabled";
+			};
+
+			saif1: saif@80046000 {
+				#sound-dai-cells = <0>;
+				compatible = "fsl,imx28-saif";
+				reg = <0x80046000 0x2000>;
+				interrupts = <58>;
+				clocks = <&clks 54>;
+				dmas = <&dma_apbx 5>;
+				dma-names = "rx-tx";
+				status = "disabled";
+			};
+
+			lradc: lradc@80050000 {
+				compatible = "fsl,imx28-lradc";
+				reg = <0x80050000 0x2000>;
+				interrupts = <10 14 15 16 17 18 19
+						20 21 22 23 24 25>;
+				status = "disabled";
+				clocks = <&clks 41>;
+				#io-channel-cells = <1>;
+			};
+
+			spdif: spdif@80054000 {
+				reg = <0x80054000 0x2000>;
+				interrupts = <45>;
+				dmas = <&dma_apbx 2>;
+				dma-names = "tx";
+				status = "disabled";
+			};
+
+			mxs_rtc: rtc@80056000 {
+				compatible = "fsl,imx28-rtc", "fsl,stmp3xxx-rtc";
+				reg = <0x80056000 0x2000>;
+				interrupts = <29>;
+			};
+
+			i2c0: i2c@80058000 {
+				#address-cells = <1>;
+				#size-cells = <0>;
+				compatible = "fsl,imx28-i2c";
+				reg = <0x80058000 0x2000>;
+				interrupts = <111>;
+				clock-frequency = <100000>;
+				dmas = <&dma_apbx 6>;
+				dma-names = "rx-tx";
+				status = "disabled";
+			};
+
+			i2c1: i2c@8005a000 {
+				#address-cells = <1>;
+				#size-cells = <0>;
+				compatible = "fsl,imx28-i2c";
+				reg = <0x8005a000 0x2000>;
+				interrupts = <110>;
+				clock-frequency = <100000>;
+				dmas = <&dma_apbx 7>;
+				dma-names = "rx-tx";
+				status = "disabled";
+			};
+
+			pwm: pwm@80064000 {
+				compatible = "fsl,imx28-pwm", "fsl,imx23-pwm";
+				reg = <0x80064000 0x2000>;
+				clocks = <&clks 44>;
+				#pwm-cells = <2>;
+				fsl,pwm-number = <8>;
+				status = "disabled";
+			};
+
+			timer: timrot@80068000 {
+				compatible = "fsl,imx28-timrot", "fsl,timrot";
+				reg = <0x80068000 0x2000>;
+				interrupts = <48 49 50 51>;
+				clocks = <&clks 26>;
+			};
+
+			auart0: serial@8006a000 {
+				compatible = "fsl,imx28-auart", "fsl,imx23-auart";
+				reg = <0x8006a000 0x2000>;
+				interrupts = <112>;
+				dmas = <&dma_apbx 8>, <&dma_apbx 9>;
+				dma-names = "rx", "tx";
+				clocks = <&clks 45>;
+				status = "disabled";
+			};
+
+			auart1: serial@8006c000 {
+				compatible = "fsl,imx28-auart", "fsl,imx23-auart";
+				reg = <0x8006c000 0x2000>;
+				interrupts = <113>;
+				dmas = <&dma_apbx 10>, <&dma_apbx 11>;
+				dma-names = "rx", "tx";
+				clocks = <&clks 45>;
+				status = "disabled";
+			};
+
+			auart2: serial@8006e000 {
+				compatible = "fsl,imx28-auart", "fsl,imx23-auart";
+				reg = <0x8006e000 0x2000>;
+				interrupts = <114>;
+				dmas = <&dma_apbx 12>, <&dma_apbx 13>;
+				dma-names = "rx", "tx";
+				clocks = <&clks 45>;
+				status = "disabled";
+			};
+
+			auart3: serial@80070000 {
+				compatible = "fsl,imx28-auart", "fsl,imx23-auart";
+				reg = <0x80070000 0x2000>;
+				interrupts = <115>;
+				dmas = <&dma_apbx 14>, <&dma_apbx 15>;
+				dma-names = "rx", "tx";
+				clocks = <&clks 45>;
+				status = "disabled";
+			};
+
+			auart4: serial@80072000 {
+				compatible = "fsl,imx28-auart", "fsl,imx23-auart";
+				reg = <0x80072000 0x2000>;
+				interrupts = <116>;
+				dmas = <&dma_apbx 0>, <&dma_apbx 1>;
+				dma-names = "rx", "tx";
+				clocks = <&clks 45>;
+				status = "disabled";
+			};
+
+			duart: serial@80074000 {
+				compatible = "arm,pl011", "arm,primecell";
+				reg = <0x80074000 0x1000>;
+				interrupts = <47>;
+				clocks = <&clks 45>, <&clks 26>;
+				clock-names = "uart", "apb_pclk";
+				status = "disabled";
+			};
+
+			usbphy0: usbphy@8007c000 {
+				compatible = "fsl,imx28-usbphy", "fsl,imx23-usbphy";
+				reg = <0x8007c000 0x2000>;
+				clocks = <&clks 62>;
+				status = "disabled";
+			};
+
+			usbphy1: usbphy@8007e000 {
+				compatible = "fsl,imx28-usbphy", "fsl,imx23-usbphy";
+				reg = <0x8007e000 0x2000>;
+				clocks = <&clks 63>;
+				status = "disabled";
+			};
+		};
+	};
+
+	ahb@80080000 {
+		compatible = "simple-bus";
+		#address-cells = <1>;
+		#size-cells = <1>;
+		reg = <0x80080000 0x80000>;
+		ranges;
+
+		usb0: usb@80080000 {
+			compatible = "fsl,imx28-usb", "fsl,imx27-usb";
+			reg = <0x80080000 0x10000>;
+			interrupts = <93>;
+			clocks = <&clks 60>;
+			fsl,usbphy = <&usbphy0>;
+			status = "disabled";
+		};
+
+		usb1: usb@80090000 {
+			compatible = "fsl,imx28-usb", "fsl,imx27-usb";
+			reg = <0x80090000 0x10000>;
+			interrupts = <92>;
+			clocks = <&clks 61>;
+			fsl,usbphy = <&usbphy1>;
+			dr_mode = "host";
+			status = "disabled";
+		};
+
+		dflpt: dflpt@800c0000 {
+			reg = <0x800c0000 0x10000>;
+			status = "disabled";
+		};
+
+		mac0: ethernet@800f0000 {
+			compatible = "fsl,imx28-fec";
+			reg = <0x800f0000 0x4000>;
+			interrupts = <101>;
+			clocks = <&clks 57>, <&clks 57>, <&clks 64>;
+			clock-names = "ipg", "ahb", "enet_out";
+			status = "disabled";
+		};
+
+		mac1: ethernet@800f4000 {
+			compatible = "fsl,imx28-fec";
+			reg = <0x800f4000 0x4000>;
+			interrupts = <102>;
+			clocks = <&clks 57>, <&clks 57>;
+			clock-names = "ipg", "ahb";
+			status = "disabled";
+		};
+
+		etn_switch: switch@800f8000 {
+			reg = <0x800f8000 0x8000>;
+			status = "disabled";
+		};
+	};
+
+	iio-hwmon {
+		compatible = "iio-hwmon";
+		io-channels = <&lradc 8>;
+	};
+};
diff --git a/arch/arm/dts/imx53-m53menlo-u-boot.dtsi b/arch/arm/dts/imx53-m53menlo-u-boot.dtsi
index 329fa3b..bc4b348 100644
--- a/arch/arm/dts/imx53-m53menlo-u-boot.dtsi
+++ b/arch/arm/dts/imx53-m53menlo-u-boot.dtsi
@@ -11,6 +11,11 @@
 			u-boot,dm-pre-reloc;
 		};
 	};
+
+	wdt-reboot {
+		compatible = "wdt-reboot";
+		wdt = <&wdog1>;
+	};
 };
 
 &gpio1 {
diff --git a/arch/arm/dts/imx6dl-dhcom-pdk2.dts b/arch/arm/dts/imx6dl-dhcom-pdk2.dts
new file mode 100644
index 0000000..a0b51bc
--- /dev/null
+++ b/arch/arm/dts/imx6dl-dhcom-pdk2.dts
@@ -0,0 +1,14 @@
+// SPDX-License-Identifier: (GPL-2.0+)
+/*
+ * Copyright (C) 2019 DH electronics GmbH
+ */
+
+/dts-v1/;
+
+#include "imx6dl.dtsi"
+#include "imx6qdl-dhcom-pdk2.dtsi"
+
+/ {
+	model = "Freescale i.MX6 Duallite/Solo DHCOM Premium Developer Kit (2)";
+	compatible = "dh,imx6dl-dhcom-pdk2", "dh,imx6dl-dhcom", "fsl,imx6dl";
+};
diff --git a/arch/arm/dts/imx6q-dhcom-pdk2.dts b/arch/arm/dts/imx6q-dhcom-pdk2.dts
index 9c61e3b..5bab2db 100644
--- a/arch/arm/dts/imx6q-dhcom-pdk2.dts
+++ b/arch/arm/dts/imx6q-dhcom-pdk2.dts
@@ -1,151 +1,20 @@
 // SPDX-License-Identifier: (GPL-2.0+)
 /*
- * Copyright (C) 2015 DH electronics GmbH
+ * Copyright (C) 2015-2019 DH electronics GmbH
  * Copyright (C) 2018 Marek Vasut <marex@denx.de>
  */
 
 /dts-v1/;
 
-#include "imx6q-dhcom-som.dtsi"
+#include "imx6q.dtsi"
+#include "imx6qdl-dhcom-pdk2.dtsi"
 
 / {
-	model = "Freescale i.MX6 Quad DHCOM Premium Developer Kit (2)";
-	compatible = "dh,imx6q-dhcom-pdk2", "dh,imx6q-dhcom-som", "fsl,imx6q";
-
-	chosen {
-		stdout-path = &uart1;
-	};
-
-	clk_ext_audio_codec: clock-codec {
-		compatible = "fixed-clock";
-		#clock-cells = <0>;
-		clock-frequency = <24000000>;
-	};
-
-	sound {
-		compatible = "fsl,imx-audio-sgtl5000";
-		model = "imx-sgtl5000";
-		ssi-controller = <&ssi1>;
-		audio-codec = <&sgtl5000>;
-		audio-routing =
-			"MIC_IN", "Mic Jack",
-			"Mic Jack", "Mic Bias",
-			"LINE_IN", "Line In Jack",
-			"Headphone Jack", "HP_OUT";
-		mux-int-port = <1>;
-		mux-ext-port = <3>;
-	};
+	model = "Freescale i.MX6 Quad/Dual DHCOM Premium Developer Kit (2)";
+	compatible = "dh,imx6q-dhcom-pdk2", "dh,imx6q-dhcom", "fsl,imx6q";
 };
 
-&audmux {
-	pinctrl-names = "default";
-	pinctrl-0 = <&pinctrl_audmux_ext>;
-	status = "okay";
-};
-
-&hdmi {
-	ddc-i2c-bus = <&i2c2>;
-	status = "okay";
-};
-
-&i2c2 {
-	sgtl5000: codec@a {
-		compatible = "fsl,sgtl5000";
-		reg = <0x0a>;
-		#sound-dai-cells = <0>;
-		clocks = <&clk_ext_audio_codec>;
-		VDDA-supply = <&reg_3p3v>;
-		VDDIO-supply = <&reg_3p3v>;
-	};
-};
-
-&iomuxc {
-	pinctrl-names = "default";
-	pinctrl-0 = <&pinctrl_hog_base &pinctrl_hog>;
-
-	pinctrl_hog: hog-grp {
-		fsl,pins = <
-			MX6QDL_PAD_GPIO_2__GPIO1_IO02		0x400120b0
-			MX6QDL_PAD_GPIO_4__GPIO1_IO04		0x400120b0
-			MX6QDL_PAD_GPIO_5__GPIO1_IO05		0x400120b0
-			MX6QDL_PAD_CSI0_DAT17__GPIO6_IO03	0x400120b0
-			MX6QDL_PAD_GPIO_19__GPIO4_IO05		0x120b0
-			MX6QDL_PAD_DI0_PIN4__GPIO4_IO20		0x400120b0
-			MX6QDL_PAD_EIM_D27__GPIO3_IO27		0x120b0
-			MX6QDL_PAD_KEY_ROW0__GPIO4_IO07		0x120b0
-			MX6QDL_PAD_KEY_COL1__GPIO4_IO08		0x400120b0
-			MX6QDL_PAD_NANDF_CS1__GPIO6_IO14	0x400120b0
-			MX6QDL_PAD_NANDF_CS2__GPIO6_IO15	0x400120b0
-			MX6QDL_PAD_KEY_ROW1__GPIO4_IO09		0x400120b0
-			MX6QDL_PAD_SD3_DAT5__GPIO7_IO00		0x400120b0
-			MX6QDL_PAD_SD3_DAT4__GPIO7_IO01		0x400120b0
-			MX6QDL_PAD_CSI0_VSYNC__GPIO5_IO21	0x400120b0
-			MX6QDL_PAD_GPIO_18__GPIO7_IO13		0x400120b0
-			MX6QDL_PAD_SD1_CMD__GPIO1_IO18		0x400120b0
-			MX6QDL_PAD_SD1_DAT0__GPIO1_IO16		0x400120b0
-			MX6QDL_PAD_SD1_DAT1__GPIO1_IO17		0x400120b0
-			MX6QDL_PAD_SD1_DAT2__GPIO1_IO19		0x400120b0
-			MX6QDL_PAD_SD1_CLK__GPIO1_IO20		0x400120b0
-			MX6QDL_PAD_CSI0_PIXCLK__GPIO5_IO18	0x400120b0
-			MX6QDL_PAD_CSI0_MCLK__GPIO5_IO19	0x400120b0
-			MX6QDL_PAD_KEY_COL0__GPIO4_IO06		0x400120b0
-		>;
-	};
-
-	pinctrl_audmux_ext: audmux-ext-grp {
-		fsl,pins = <
-			MX6QDL_PAD_CSI0_DAT7__AUD3_RXD		0x130b0
-			MX6QDL_PAD_CSI0_DAT4__AUD3_TXC		0x130b0
-			MX6QDL_PAD_CSI0_DAT5__AUD3_TXD		0x110b0
-			MX6QDL_PAD_CSI0_DAT6__AUD3_TXFS		0x130b0
-		>;
-	};
-
-	pinctrl_enet_1G: enet-1G-grp {
-		fsl,pins = <
-			MX6QDL_PAD_ENET_MDIO__ENET_MDIO		0x100b0
-			MX6QDL_PAD_ENET_MDC__ENET_MDC		0x100b0
-			MX6QDL_PAD_RGMII_TXC__RGMII_TXC		0x100b0
-			MX6QDL_PAD_RGMII_TD0__RGMII_TD0		0x100b0
-			MX6QDL_PAD_RGMII_TD1__RGMII_TD1		0x100b0
-			MX6QDL_PAD_RGMII_TD2__RGMII_TD2		0x100b0
-			MX6QDL_PAD_RGMII_TD3__RGMII_TD3		0x100b0
-			MX6QDL_PAD_RGMII_TX_CTL__RGMII_TX_CTL	0x100b0
-			MX6QDL_PAD_ENET_REF_CLK__ENET_TX_CLK	0x100b0
-			MX6QDL_PAD_RGMII_RXC__RGMII_RXC		0x1b0b0
-			MX6QDL_PAD_RGMII_RD0__RGMII_RD0		0x1b0b0
-			MX6QDL_PAD_RGMII_RD1__RGMII_RD1		0x1b0b0
-			MX6QDL_PAD_RGMII_RD2__RGMII_RD2		0x1b0b0
-			MX6QDL_PAD_RGMII_RD3__RGMII_RD3		0x1b0b0
-			MX6QDL_PAD_RGMII_RX_CTL__RGMII_RX_CTL	0x1b0b0
-			MX6QDL_PAD_EIM_D29__GPIO3_IO29		0x000b0
-			MX6QDL_PAD_GPIO_0__GPIO1_IO00		0x000b1
-			MX6QDL_PAD_EIM_D26__GPIO3_IO26		0x000b1
-		>;
-	};
-
-	pinctrl_pcie: pcie-grp {
-		fsl,pins = <
-			MX6QDL_PAD_CSI0_DATA_EN__GPIO5_IO20	0x1b0b1
-		>;
-	};
-};
-
-&pcie {
-	pinctrl-names = "default";
-	pinctrl-0 = <&pinctrl_pcie>;
-	reset-gpio = <&gpio6 14 GPIO_ACTIVE_LOW>;
-	status = "okay";
-};
-
-&ssi1 {
-	status = "okay";
-};
-
 &sata {
 	status = "okay";
 };
 
-&usdhc3 {
-	status = "okay";
-};
diff --git a/arch/arm/dts/imx6q-display5-u-boot.dtsi b/arch/arm/dts/imx6q-display5-u-boot.dtsi
new file mode 100644
index 0000000..b942218
--- /dev/null
+++ b/arch/arm/dts/imx6q-display5-u-boot.dtsi
@@ -0,0 +1,44 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2019
+ * Lukasz Majewski, DENX Software Engineering, lukma@denx.de
+ *
+ * SPDX-License-Identifier:     GPL-2.0+ or X11
+ */
+
+/*
+ * The minimal augmentation DTS U-Boot file to allow UART5
+ * configuration in the pre-relocation stage of U-Boot
+ * proper.
+ *
+ * As the same UART is already configured in SPL, we don't need
+ * setup pinmux for it again.
+ */
+
+/ {
+	aliases {
+		mmc0 = &usdhc4;
+	};
+
+	soc {
+		u-boot,dm-pre-reloc;
+
+		aips-bus@2100000 {
+			u-boot,dm-pre-reloc;
+		};
+	};
+
+	chosen {
+		stdout-path = &uart5;
+	};
+};
+
+&i2c3 {
+	at24@50 {
+		u-boot,i2c-offset-len = <2>;
+	};
+};
+
+&uart5 {
+	u-boot,dm-pre-reloc;
+};
diff --git a/arch/arm/dts/imx6q-display5.dts b/arch/arm/dts/imx6q-display5.dts
index 50347ff..4e2aa36 100644
--- a/arch/arm/dts/imx6q-display5.dts
+++ b/arch/arm/dts/imx6q-display5.dts
@@ -10,9 +10,361 @@
 
 /dts-v1/;
 
+#include <dt-bindings/gpio/gpio.h>
 #include "imx6q.dtsi"
 
 / {
 	model = "Liebherr (LWN) display5 i.MX6 Quad Board";
 	compatible = "lwn,display5", "fsl,imx6q";
+
+	memory@10000000 {
+		device_type = "memory";
+		reg = <0x10000000 0x40000000>;
+	};
+};
+
+&ecspi2 {
+	cs-gpios = <&gpio5 29 GPIO_ACTIVE_LOW>;
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_ecspi2 &pinctrl_ecspi2_cs &pinctrl_ecspi2_flwp>;
+	status = "okay";
+
+	s25fl256s: flash@0 {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		compatible = "jedec,spi-nor";
+		spi-max-frequency = <40000000>;
+		reg = <0>;
+
+		partition@0 {
+			label = "SPL (spi)";
+			reg = <0x0 0x20000>;
+			read-only;
+		};
+		partition@1 {
+			label = "u-boot (spi)";
+			reg = <0x20000 0x100000>;
+			read-only;
+		};
+		partition@2 {
+			label = "uboot-env (spi)";
+			reg = <0x120000 0x10000>;
+		};
+		partition@3 {
+			label = "uboot-envr (spi)";
+			reg = <0x130000 0x10000>;
+		};
+		partition@4 {
+			label = "linux-recovery (spi)";
+			reg = <0x140000 0x800000>;
+		};
+		partition@5 {
+			label = "swupdate-fitImg (spi)";
+			reg = <0x940000 0x400000>;
+		};
+		partition@6 {
+			label = "swupdate-initramfs (spi)";
+			reg = <0xD40000 0x800000>;
+		};
+	};
+};
+
+&ecspi3 {
+	cs-gpios = <&gpio4 24 GPIO_ACTIVE_LOW>;
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_ecspi3 &pinctrl_ecspi3_cs &pinctrl_ecspi3_flwp>;
+	status = "okay";
+};
+
+&fec {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_enet>;
+	phy-handle = <&ethernet_phy0>;
+	phy-mode = "rgmii-id";
+	status = "okay";
+
+	mdio {
+		#address-cells = <1>;
+		#size-cells = <0>;
+		ethernet_phy0: ethernet-phy@0 {
+			compatible = "marvell,88E1510";
+			device_type = "ethernet-phy";
+			/* Set LED0 control: */
+			/* On - Link, Blink - Activity, Off - No Link */
+			marvell,reg-init = <3 0x10 0 0x1011>;
+			max-speed = <100>;
+			reg = <0>;
+		};
+	};
+};
+
+&i2c1 {
+	clock-frequency = <400000>;
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_i2c1>;
+	status = "okay";
+
+	codec: tfa9879@6c {
+		#sound-dai-cells = <0>;
+		compatible = "nxp,tfa9879";
+		reg = <0x6C>;
+	};
+};
+
+&i2c2 {
+	clock-frequency = <400000>;
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_i2c2>;
+	status = "okay";
+};
+
+&i2c3 {
+	clock-frequency = <400000>;
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_i2c3>;
+	status = "okay";
+
+	at24@50 {
+		compatible = "atmel,24c256";
+		pagesize = <64>;
+		reg = <0x50>;
+	};
+
+	pfuze100: pmic@8 {
+		compatible = "fsl,pfuze100";
+		reg = <0x08>;
+
+		regulators {
+			sw1a_reg: sw1ab {
+				regulator-min-microvolt = <300000>;
+				regulator-max-microvolt = <1875000>;
+				regulator-boot-on;
+				regulator-always-on;
+				regulator-ramp-delay = <6250>;
+			};
+
+			sw1c_reg: sw1c {
+				regulator-min-microvolt = <300000>;
+				regulator-max-microvolt = <1875000>;
+				regulator-boot-on;
+				regulator-always-on;
+				regulator-ramp-delay = <6250>;
+			};
+
+			sw2_reg: sw2 {
+				regulator-min-microvolt = <800000>;
+				regulator-max-microvolt = <3950000>;
+				regulator-boot-on;
+				regulator-always-on;
+			};
+
+			sw3a_reg: sw3a {
+				regulator-min-microvolt = <400000>;
+				regulator-max-microvolt = <1975000>;
+				regulator-boot-on;
+				regulator-always-on;
+			};
+
+			sw3b_reg: sw3b {
+				regulator-min-microvolt = <400000>;
+				regulator-max-microvolt = <1975000>;
+				regulator-boot-on;
+				regulator-always-on;
+			};
+
+			sw4_reg: sw4 {
+				regulator-min-microvolt = <800000>;
+				regulator-max-microvolt = <3300000>;
+			};
+
+			swbst_reg: swbst {
+				regulator-min-microvolt = <5000000>;
+				regulator-max-microvolt = <5150000>;
+			};
+
+			snvs_reg: vsnvs {
+				regulator-min-microvolt = <1000000>;
+				regulator-max-microvolt = <3000000>;
+				regulator-boot-on;
+				regulator-always-on;
+			};
+
+			vref_reg: vrefddr {
+				regulator-boot-on;
+				regulator-always-on;
+			};
+
+			vgen1_reg: vgen1 {
+				regulator-min-microvolt = <800000>;
+				regulator-max-microvolt = <1550000>;
+			};
+
+			vgen2_reg: vgen2 {
+				regulator-min-microvolt = <800000>;
+				regulator-max-microvolt = <1550000>;
+			};
+
+			vgen3_reg: vgen3 {
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <3300000>;
+			};
+
+			vgen4_reg: vgen4 {
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <3300000>;
+				regulator-always-on;
+			};
+
+			vgen5_reg: vgen5 {
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <3300000>;
+				regulator-always-on;
+			};
+
+			vgen6_reg: vgen6 {
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <3300000>;
+				regulator-always-on;
+			};
+		};
+	};
+};
+
+&uart4 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_uart4>;
+	uart-has-rtscts;
+	status = "okay";
+};
+
+&uart5 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_uart5>;
+	status = "okay";
+};
+
+&usdhc4 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_usdhc4>;
+	bus-width = <8>;
+	non-removable;
+	status = "okay";
+};
+
+&iomuxc {
+	pinctrl_ecspi2: ecspi2grp {
+		fsl,pins = <
+			MX6QDL_PAD_CSI0_DAT10__ECSPI2_MISO	0x100b1
+			MX6QDL_PAD_CSI0_DAT9__ECSPI2_MOSI	0x100b1
+			MX6QDL_PAD_CSI0_DAT8__ECSPI2_SCLK	0x100b1
+		>;
+	};
+
+	pinctrl_ecspi2_cs: ecspi2csgrp {
+		fsl,pins = <
+			MX6QDL_PAD_CSI0_DAT11__GPIO5_IO29 0x100b1
+		>;
+	};
+
+	pinctrl_ecspi2_flwp: ecspi2flwpgrp {
+		fsl,pins = <
+			MX6QDL_PAD_SD3_DAT5__GPIO7_IO00 0x1b0b0
+		>;
+	};
+
+	pinctrl_ecspi3: ecspi3grp {
+		fsl,pins = <
+			MX6QDL_PAD_DISP0_DAT2__ECSPI3_MISO	0x100b1
+			MX6QDL_PAD_DISP0_DAT1__ECSPI3_MOSI	0x100b1
+			MX6QDL_PAD_DISP0_DAT0__ECSPI3_SCLK	0x100b1
+		>;
+	};
+
+	pinctrl_ecspi3_cs: ecspi3csgrp {
+		fsl,pins = <
+			MX6QDL_PAD_DISP0_DAT3__GPIO4_IO24 0x1b0b0
+		>;
+	};
+
+	pinctrl_ecspi3_flwp: ecspi3flwpgrp {
+		fsl,pins = <
+			MX6QDL_PAD_DISP0_DAT6__GPIO4_IO27 0x1b0b0
+		>;
+	};
+
+	pinctrl_enet: enetgrp {
+		fsl,pins = <
+			MX6QDL_PAD_ENET_MDIO__ENET_MDIO		0x1b0b0
+			MX6QDL_PAD_ENET_MDC__ENET_MDC		0x1b0b0
+			MX6QDL_PAD_RGMII_TXC__RGMII_TXC		0x1b0b0
+			MX6QDL_PAD_RGMII_TD0__RGMII_TD0		0x1b0b0
+			MX6QDL_PAD_RGMII_TD1__RGMII_TD1		0x1b0b0
+			MX6QDL_PAD_RGMII_TD2__RGMII_TD2		0x1b0b0
+			MX6QDL_PAD_RGMII_TD3__RGMII_TD3		0x1b0b0
+			MX6QDL_PAD_RGMII_TX_CTL__RGMII_TX_CTL	0x1b0b0
+			MX6QDL_PAD_ENET_REF_CLK__ENET_TX_CLK	0x1b0b0
+			MX6QDL_PAD_RGMII_RXC__RGMII_RXC		0x1b0b0
+			MX6QDL_PAD_RGMII_RD0__RGMII_RD0		0x1b0b0
+			MX6QDL_PAD_RGMII_RD1__RGMII_RD1		0x1b0b0
+			MX6QDL_PAD_RGMII_RD2__RGMII_RD2		0x1b0b0
+			MX6QDL_PAD_RGMII_RD3__RGMII_RD3		0x1b0b0
+			MX6QDL_PAD_RGMII_RX_CTL__RGMII_RX_CTL	0x1b0b0
+			MX6QDL_PAD_GPIO_16__ENET_REF_CLK 0x4001b0a8
+			MX6QDL_PAD_GPIO_6__ENET_IRQ		0x000b1
+			MX6QDL_PAD_ENET_RXD0__GPIO1_IO27        0x1b0b0
+		>;
+	};
+
+	pinctrl_i2c1: i2c1grp {
+		fsl,pins = <
+			MX6QDL_PAD_EIM_D21__I2C1_SCL	0x4001b8b1
+			MX6QDL_PAD_EIM_D28__I2C1_SDA	0x4001b8b1
+		>;
+	};
+
+	pinctrl_i2c2: i2c2grp {
+		fsl,pins = <
+			MX6QDL_PAD_EIM_EB2__I2C2_SCL	0x4001b8b1
+			MX6QDL_PAD_EIM_D16__I2C2_SDA	0x4001b8b1
+		>;
+	};
+
+	pinctrl_i2c3: i2c3grp {
+		fsl,pins = <
+			MX6QDL_PAD_EIM_D17__I2C3_SCL	0x4001b8b1
+			MX6QDL_PAD_EIM_D18__I2C3_SDA	0x4001b8b1
+		>;
+	};
+
+	pinctrl_uart4: uart4grp {
+		fsl,pins = <
+			MX6QDL_PAD_CSI0_DAT12__UART4_TX_DATA	0x1b0b1
+			MX6QDL_PAD_CSI0_DAT13__UART4_RX_DATA	0x1b0b1
+			MX6QDL_PAD_CSI0_DAT16__UART4_RTS_B	0x1b0b1
+			MX6QDL_PAD_CSI0_DAT17__UART4_CTS_B	0x1b0b1
+		>;
+	};
+
+	pinctrl_uart5: uart5grp {
+		fsl,pins = <
+			MX6QDL_PAD_CSI0_DAT14__UART5_TX_DATA	0x1b0b1
+			MX6QDL_PAD_CSI0_DAT15__UART5_RX_DATA    0x1b0b1
+		>;
+	};
+
+	pinctrl_usdhc4: usdhc4grp {
+		fsl,pins = <
+			MX6QDL_PAD_SD4_CMD__SD4_CMD		0x17059
+			MX6QDL_PAD_SD4_CLK__SD4_CLK		0x10059
+			MX6QDL_PAD_SD4_DAT0__SD4_DATA0		0x17059
+			MX6QDL_PAD_SD4_DAT1__SD4_DATA1		0x17059
+			MX6QDL_PAD_SD4_DAT2__SD4_DATA2		0x17059
+			MX6QDL_PAD_SD4_DAT3__SD4_DATA3		0x17059
+			MX6QDL_PAD_SD4_DAT4__SD4_DATA4		0x17059
+			MX6QDL_PAD_SD4_DAT5__SD4_DATA5		0x17059
+			MX6QDL_PAD_SD4_DAT6__SD4_DATA6		0x17059
+			MX6QDL_PAD_SD4_DAT7__SD4_DATA7		0x17059
+			MX6QDL_PAD_NANDF_ALE__SD4_RESET	0x17059
+		>;
+	};
 };
diff --git a/arch/arm/dts/imx6qdl-dhcom-pdk2.dtsi b/arch/arm/dts/imx6qdl-dhcom-pdk2.dtsi
new file mode 100644
index 0000000..af4719a
--- /dev/null
+++ b/arch/arm/dts/imx6qdl-dhcom-pdk2.dtsi
@@ -0,0 +1,142 @@
+// SPDX-License-Identifier: (GPL-2.0+)
+/*
+ * Copyright (C) 2015-2019 DH electronics GmbH
+ * Copyright (C) 2018 Marek Vasut <marex@denx.de>
+ */
+
+#include "imx6qdl-dhcom.dtsi"
+
+/ {
+	chosen {
+		stdout-path = &uart1;
+	};
+
+	clk_ext_audio_codec: clock-codec {
+		compatible = "fixed-clock";
+		#clock-cells = <0>;
+		clock-frequency = <24000000>;
+	};
+
+	sound {
+		compatible = "fsl,imx-audio-sgtl5000";
+		model = "imx-sgtl5000";
+		ssi-controller = <&ssi1>;
+		audio-codec = <&sgtl5000>;
+		audio-routing =
+			"MIC_IN", "Mic Jack",
+			"Mic Jack", "Mic Bias",
+			"LINE_IN", "Line In Jack",
+			"Headphone Jack", "HP_OUT";
+		mux-int-port = <1>;
+		mux-ext-port = <3>;
+	};
+};
+
+&audmux {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_audmux_ext>;
+	status = "okay";
+};
+
+&hdmi {
+	ddc-i2c-bus = <&i2c2>;
+	status = "okay";
+};
+
+&i2c2 {
+	sgtl5000: codec@a {
+		compatible = "fsl,sgtl5000";
+		reg = <0x0a>;
+		#sound-dai-cells = <0>;
+		clocks = <&clk_ext_audio_codec>;
+		VDDA-supply = <&reg_3p3v>;
+		VDDIO-supply = <&reg_3p3v>;
+	};
+};
+
+&iomuxc {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_hog_base &pinctrl_hog>;
+
+	pinctrl_hog: hog-grp {
+		fsl,pins = <
+			MX6QDL_PAD_GPIO_2__GPIO1_IO02		0x400120b0
+			MX6QDL_PAD_GPIO_4__GPIO1_IO04		0x400120b0
+			MX6QDL_PAD_GPIO_5__GPIO1_IO05		0x400120b0
+			MX6QDL_PAD_CSI0_DAT17__GPIO6_IO03	0x400120b0
+			MX6QDL_PAD_GPIO_19__GPIO4_IO05		0x120b0
+			MX6QDL_PAD_DI0_PIN4__GPIO4_IO20		0x400120b0
+			MX6QDL_PAD_EIM_D27__GPIO3_IO27		0x120b0
+			MX6QDL_PAD_KEY_ROW0__GPIO4_IO07		0x120b0
+			MX6QDL_PAD_KEY_COL1__GPIO4_IO08		0x400120b0
+			MX6QDL_PAD_NANDF_CS1__GPIO6_IO14	0x400120b0
+			MX6QDL_PAD_NANDF_CS2__GPIO6_IO15	0x400120b0
+			MX6QDL_PAD_KEY_ROW1__GPIO4_IO09		0x400120b0
+			MX6QDL_PAD_SD3_DAT5__GPIO7_IO00		0x400120b0
+			MX6QDL_PAD_SD3_DAT4__GPIO7_IO01		0x400120b0
+			MX6QDL_PAD_CSI0_VSYNC__GPIO5_IO21	0x400120b0
+			MX6QDL_PAD_GPIO_18__GPIO7_IO13		0x400120b0
+			MX6QDL_PAD_SD1_CMD__GPIO1_IO18		0x400120b0
+			MX6QDL_PAD_SD1_DAT0__GPIO1_IO16		0x400120b0
+			MX6QDL_PAD_SD1_DAT1__GPIO1_IO17		0x400120b0
+			MX6QDL_PAD_SD1_DAT2__GPIO1_IO19		0x400120b0
+			MX6QDL_PAD_SD1_CLK__GPIO1_IO20		0x400120b0
+			MX6QDL_PAD_CSI0_PIXCLK__GPIO5_IO18	0x400120b0
+			MX6QDL_PAD_CSI0_MCLK__GPIO5_IO19	0x400120b0
+			MX6QDL_PAD_KEY_COL0__GPIO4_IO06		0x400120b0
+		>;
+	};
+
+	pinctrl_audmux_ext: audmux-ext-grp {
+		fsl,pins = <
+			MX6QDL_PAD_CSI0_DAT7__AUD3_RXD		0x130b0
+			MX6QDL_PAD_CSI0_DAT4__AUD3_TXC		0x130b0
+			MX6QDL_PAD_CSI0_DAT5__AUD3_TXD		0x110b0
+			MX6QDL_PAD_CSI0_DAT6__AUD3_TXFS		0x130b0
+		>;
+	};
+
+	pinctrl_enet_1G: enet-1G-grp {
+		fsl,pins = <
+			MX6QDL_PAD_ENET_MDIO__ENET_MDIO		0x100b0
+			MX6QDL_PAD_ENET_MDC__ENET_MDC		0x100b0
+			MX6QDL_PAD_RGMII_TXC__RGMII_TXC		0x100b0
+			MX6QDL_PAD_RGMII_TD0__RGMII_TD0		0x100b0
+			MX6QDL_PAD_RGMII_TD1__RGMII_TD1		0x100b0
+			MX6QDL_PAD_RGMII_TD2__RGMII_TD2		0x100b0
+			MX6QDL_PAD_RGMII_TD3__RGMII_TD3		0x100b0
+			MX6QDL_PAD_RGMII_TX_CTL__RGMII_TX_CTL	0x100b0
+			MX6QDL_PAD_ENET_REF_CLK__ENET_TX_CLK	0x100b0
+			MX6QDL_PAD_RGMII_RXC__RGMII_RXC		0x1b0b0
+			MX6QDL_PAD_RGMII_RD0__RGMII_RD0		0x1b0b0
+			MX6QDL_PAD_RGMII_RD1__RGMII_RD1		0x1b0b0
+			MX6QDL_PAD_RGMII_RD2__RGMII_RD2		0x1b0b0
+			MX6QDL_PAD_RGMII_RD3__RGMII_RD3		0x1b0b0
+			MX6QDL_PAD_RGMII_RX_CTL__RGMII_RX_CTL	0x1b0b0
+			MX6QDL_PAD_EIM_D29__GPIO3_IO29		0x000b0
+			MX6QDL_PAD_GPIO_0__GPIO1_IO00		0x000b1
+			MX6QDL_PAD_EIM_D26__GPIO3_IO26		0x000b1
+		>;
+	};
+
+	pinctrl_pcie: pcie-grp {
+		fsl,pins = <
+			MX6QDL_PAD_CSI0_DATA_EN__GPIO5_IO20	0x1b0b1
+		>;
+	};
+};
+
+&pcie {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_pcie>;
+	reset-gpio = <&gpio6 14 GPIO_ACTIVE_LOW>;
+	status = "okay";
+};
+
+&ssi1 {
+	status = "okay";
+};
+
+&usdhc3 {
+	status = "okay";
+};
diff --git a/arch/arm/dts/imx6q-dhcom-som.dtsi b/arch/arm/dts/imx6qdl-dhcom.dtsi
similarity index 99%
rename from arch/arm/dts/imx6q-dhcom-som.dtsi
rename to arch/arm/dts/imx6qdl-dhcom.dtsi
index 524cd28..1141b6a 100644
--- a/arch/arm/dts/imx6q-dhcom-som.dtsi
+++ b/arch/arm/dts/imx6qdl-dhcom.dtsi
@@ -1,10 +1,9 @@
 // SPDX-License-Identifier: (GPL-2.0+)
 /*
- * Copyright (C) 2015 DH electronics GmbH
+ * Copyright (C) 2015-2019 DH electronics GmbH
  * Copyright (C) 2018 Marek Vasut <marex@denx.de>
  */
 
-#include "imx6q.dtsi"
 #include <dt-bindings/pwm/pwm.h>
 #include <dt-bindings/gpio/gpio.h>
 #include <dt-bindings/clock/imx6qdl-clock.h>
diff --git a/arch/arm/dts/imx7d-pico.dtsi b/arch/arm/dts/imx7d-pico.dtsi
index 9f1fe68..7cd8be2 100644
--- a/arch/arm/dts/imx7d-pico.dtsi
+++ b/arch/arm/dts/imx7d-pico.dtsi
@@ -10,6 +10,7 @@
 / {
 	aliases {
 		mmc0 = &usdhc3;
+		usb0 = &usbotg1;
 	};
 
 	/* Will be filled by the bootloader */
@@ -296,6 +297,7 @@
 
 &usbotg1 {
 	vbus-supply = <&reg_usb_otg1_vbus>;
+	dr_mode = "peripheral";
 	status = "okay";
 };
 
diff --git a/arch/arm/dts/mxs-pinfunc.h b/arch/arm/dts/mxs-pinfunc.h
new file mode 100644
index 0000000..c6da987
--- /dev/null
+++ b/arch/arm/dts/mxs-pinfunc.h
@@ -0,0 +1,31 @@
+/*
+ * Header providing constants for i.MX28 pinctrl bindings.
+ *
+ * Copyright (C) 2013 Lothar Waßmann <LW@KARO-electronics.de>
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+#ifndef __DT_BINDINGS_MXS_PINCTRL_H__
+#define __DT_BINDINGS_MXS_PINCTRL_H__
+
+/* fsl,drive-strength property */
+#define MXS_DRIVE_4mA		0
+#define MXS_DRIVE_8mA		1
+#define MXS_DRIVE_12mA		2
+#define MXS_DRIVE_16mA		3
+
+/* fsl,voltage property */
+#define MXS_VOLTAGE_LOW		0
+#define MXS_VOLTAGE_HIGH	1
+
+/* fsl,pull-up property */
+#define MXS_PULL_DISABLE	0
+#define MXS_PULL_ENABLE		1
+
+#endif /* __DT_BINDINGS_MXS_PINCTRL_H__ */
diff --git a/arch/arm/include/asm/arch-imx8/sci/sci.h b/arch/arm/include/asm/arch-imx8/sci/sci.h
index 9737769..901b90d 100644
--- a/arch/arm/include/asm/arch-imx8/sci/sci.h
+++ b/arch/arm/include/asm/arch-imx8/sci/sci.h
@@ -72,6 +72,8 @@
 void sc_misc_boot_status(sc_ipc_t ipc, sc_misc_boot_status_t status);
 void sc_misc_build_info(sc_ipc_t ipc, u32 *build, u32 *commit);
 int sc_misc_otp_fuse_read(sc_ipc_t ipc, u32 word, u32 *val);
+int sc_misc_get_temp(sc_ipc_t ipc, sc_rsrc_t resource, sc_misc_temp_t temp,
+		     s16 *celsius, s8 *tenths);
 
 /* RM API */
 sc_bool_t sc_rm_is_memreg_owned(sc_ipc_t ipc, sc_rm_mr_t mr);
diff --git a/arch/arm/include/asm/arch-imx8/sci/svc/misc/api.h b/arch/arm/include/asm/arch-imx8/sci/svc/misc/api.h
index 5d17b55..3629eb6 100644
--- a/arch/arm/include/asm/arch-imx8/sci/svc/misc/api.h
+++ b/arch/arm/include/asm/arch-imx8/sci/svc/misc/api.h
@@ -26,5 +26,6 @@
 #define SC_MISC_REL_CONTAINER	2U	/* Release container */
 
 typedef u8 sc_misc_boot_status_t;
+typedef u8 sc_misc_temp_t;
 
 #endif /* SC_MISC_API_H */
diff --git a/arch/arm/include/asm/arch-imx8/sys_proto.h b/arch/arm/include/asm/arch-imx8/sys_proto.h
index 73ffaba..b8d2a0b 100644
--- a/arch/arm/include/asm/arch-imx8/sys_proto.h
+++ b/arch/arm/include/asm/arch-imx8/sys_proto.h
@@ -3,6 +3,7 @@
  * Copyright 2018 NXP
  */
 
+#include <asm/arch/sci/sci.h>
 #include <asm/mach-imx/sys_proto.h>
 #include <linux/types.h>
 
@@ -15,5 +16,7 @@
 	u32 g_ap_mu;
 };
 
+void build_info(void);
 enum boot_device get_boot_device(void);
 int print_bootinfo(void);
+int sc_pm_setup_uart(sc_rsrc_t uart_rsrc, sc_pm_clock_rate_t clk_rate);
diff --git a/arch/arm/include/asm/mach-imx/imx-nandbcb.h b/arch/arm/include/asm/mach-imx/imx-nandbcb.h
new file mode 100644
index 0000000..033659a
--- /dev/null
+++ b/arch/arm/include/asm/mach-imx/imx-nandbcb.h
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2017 Jagan Teki <jagan@amarulasolutions.com>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#ifndef _IMX_NAND_BCB_H_
+#define _IMX_NAND_BCB_H_
+
+#define FCB_FINGERPRINT		0x20424346      /* 'FCB' */
+#define FCB_VERSION_1		0x01000000
+
+#define DBBT_FINGERPRINT2	0x54424244	/* 'DBBT' */
+#define DBBT_VERSION_1		0x01000000
+
+struct dbbt_block {
+	u32 checksum;	/* reserved on i.MX6 */
+	u32 fingerprint;
+	u32 version;
+	u32 numberbb;	/* reserved on i.MX6 */
+	u32 dbbtpages;
+};
+
+struct fcb_block {
+	u32 checksum;		/* First fingerprint in first byte */
+	u32 fingerprint;	/* 2nd fingerprint at byte 4 */
+	u32 version;		/* 3rd fingerprint at byte 8 */
+	u8 datasetup;
+	u8 datahold;
+	u8 addr_setup;
+	u8 dsample_time;
+
+	/* These are for application use only and not for ROM. */
+	u8 nandtiming;
+	u8 rea;
+	u8 rloh;
+	u8 rhoh;
+	u32 pagesize;		/* 2048 for 2K pages, 4096 for 4K pages */
+	u32 oob_pagesize;	/* 2112 for 2K pages, 4314 for 4K pages */
+	u32 sectors;		/* Number of 2K sections per block */
+	u32 nr_nand;		/* Total Number of NANDs - not used by ROM */
+	u32 nr_die;		/* Number of separate chips in this NAND */
+	u32 celltype;		/* MLC or SLC */
+	u32 ecc_type;		/* Type of ECC, can be one of BCH-0-20 */
+	u32 ecc_nr;		/* Number of bytes for Block0 - BCH */
+
+	/* Block size in bytes for all blocks other than Block0 - BCH */
+	u32 ecc_size;
+	u32 ecc_level;		/* Ecc level for Block 0 - BCH */
+	u32 meta_size;		/* Metadata size - BCH */
+	/* Number of blocks per page for ROM use - BCH */
+	u32 nr_blocks;
+	u32 ecc_type_sdk;	/* Type of ECC, can be one of BCH-0-20 */
+	u32 ecc_nr_sdk;		/* Number of bytes for Block0 - BCH */
+	/* Block size in bytes for all blocks other than Block0 - BCH */
+	u32 ecc_size_sdk;
+	u32 ecc_level_sdk;	/* Ecc level for Block 0 - BCH */
+	/* Number of blocks per page for SDK use - BCH */
+	u32 nr_blocks_sdk;
+	u32 meta_size_sdk;	/* Metadata size - BCH */
+	u32 erase_th;		/* To set into BCH_MODE register */
+
+	/*
+	 * 0: normal boot
+	 * 1: to load patch starting next to FCB
+	 */
+	u32 bootpatch;
+	u32 patch_size;	/* Size of patch in sectors */
+	u32 fw1_start;	/* Firmware image starts on this sector */
+	u32 fw2_start;	/* Secondary FW Image starting Sector */
+	u32 fw1_pages;	/* Number of sectors in firmware image */
+	u32 fw2_pages;	/* Number of sector in secondary FW image */
+	u32 dbbt_start; /* Page address where dbbt search area begins */
+
+	/*
+	 * Byte in page data that have manufacturer marked bad block marker,
+	 * this will be swapped with metadata[0] to complete page data.
+	 */
+	u32 bb_byte;
+
+	/*
+	 * For BCH ECC sizes other than 8 and 16 the bad block marker does not
+	 * start at 0th bit of bb_byte. This field is used to get to
+	 * the start bit of bad block marker byte with in bb_byte
+	 */
+	u32 bb_start_bit;
+
+	/*
+	 * FCB value that gives byte offset for
+	 * bad block marker on physical NAND page
+	 */
+	u32 phy_offset;
+	u32 bchtype;
+
+	u32 readlatency;
+	u32 predelay;
+	u32 cedelay;
+	u32 postdelay;
+	u32 cmdaddpause;
+	u32 datapause;
+	u32 tmspeed;
+	u32 busytimeout;
+
+	/* the flag to enable (1)/disable(0) bi swap */
+	u32 disbbm;
+
+	/* The swap position of main area in spare area */
+	u32 spare_offset;
+};
+
+#endif	/* _IMX_NAND_BCB_H_ */
diff --git a/arch/arm/mach-imx/Kconfig b/arch/arm/mach-imx/Kconfig
index b6fd159..aeb5493 100644
--- a/arch/arm/mach-imx/Kconfig
+++ b/arch/arm/mach-imx/Kconfig
@@ -71,6 +71,17 @@
 	  This enables the 'hdmidet' command which detects if an HDMI monitor
 	  is connected.
 
+config CMD_NANDBCB
+	bool "i.MX6 NAND Boot Control Block(BCB) command"
+	depends on NAND && CMD_MTDPARTS
+	default y if ARCH_MX6 && NAND_MXS
+	help
+	  Unlike normal 'nand write/erase' commands, this command update
+	  Boot Control Block(BCB) for i.MX6 platform NAND IP's.
+
+	  This is similar to kobs-ng, which is used in Linux as separate
+	  rootfs package.
+
 config NXP_BOARD_REVISION
 	bool "Read NXP board revision from fuses"
 	depends on ARCH_MX6 || ARCH_MX7
diff --git a/arch/arm/mach-imx/Makefile b/arch/arm/mach-imx/Makefile
index 898478f..08ee52e 100644
--- a/arch/arm/mach-imx/Makefile
+++ b/arch/arm/mach-imx/Makefile
@@ -59,6 +59,7 @@
 obj-$(CONFIG_CMD_BMODE) += cmd_bmode.o
 obj-$(CONFIG_CMD_HDMIDETECT) += cmd_hdmidet.o
 obj-$(CONFIG_CMD_DEKBLOB) += cmd_dek.o
+obj-$(CONFIG_CMD_NANDBCB) += cmd_nandbcb.o
 endif
 
 PLUGIN = board/$(BOARDDIR)/plugin
diff --git a/arch/arm/mach-imx/cmd_nandbcb.c b/arch/arm/mach-imx/cmd_nandbcb.c
new file mode 100644
index 0000000..065b814
--- /dev/null
+++ b/arch/arm/mach-imx/cmd_nandbcb.c
@@ -0,0 +1,369 @@
+/*
+ * i.MX6 nand boot control block(bcb).
+ *
+ * Based on the common/imx-bbu-nand-fcb.c from barebox and imx kobs-ng
+ *
+ * Copyright (C) 2017 Jagan Teki <jagan@amarulasolutions.com>
+ * Copyright (C) 2016 Sergey Kubushyn <ksi@koi8.net>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.h>
+#include <nand.h>
+
+#include <asm/io.h>
+#include <jffs2/jffs2.h>
+#include <linux/mtd/mtd.h>
+
+#include <asm/mach-imx/imx-nandbcb.h>
+#include <asm/mach-imx/imximage.cfg>
+#include <mxs_nand.h>
+#include <linux/mtd/mtd.h>
+#include <nand.h>
+
+#define BF_VAL(v, bf)		(((v) & bf##_MASK) >> bf##_OFFSET)
+#define GETBIT(v, n)		(((v) >> (n)) & 0x1)
+
+static u8 calculate_parity_13_8(u8 d)
+{
+	u8 p = 0;
+
+	p |= (GETBIT(d, 6) ^ GETBIT(d, 5) ^ GETBIT(d, 3) ^ GETBIT(d, 2)) << 0;
+	p |= (GETBIT(d, 7) ^ GETBIT(d, 5) ^ GETBIT(d, 4) ^ GETBIT(d, 2) ^
+	      GETBIT(d, 1)) << 1;
+	p |= (GETBIT(d, 7) ^ GETBIT(d, 6) ^ GETBIT(d, 5) ^ GETBIT(d, 1) ^
+	      GETBIT(d, 0)) << 2;
+	p |= (GETBIT(d, 7) ^ GETBIT(d, 4) ^ GETBIT(d, 3) ^ GETBIT(d, 0)) << 3;
+	p |= (GETBIT(d, 6) ^ GETBIT(d, 4) ^ GETBIT(d, 3) ^ GETBIT(d, 2) ^
+	      GETBIT(d, 1) ^ GETBIT(d, 0)) << 4;
+
+	return p;
+}
+
+static void encode_hamming_13_8(void *_src, void *_ecc, size_t size)
+{
+	int i;
+	u8 *src = _src;
+	u8 *ecc = _ecc;
+
+	for (i = 0; i < size; i++)
+		ecc[i] = calculate_parity_13_8(src[i]);
+}
+
+static u32 calc_chksum(void *buf, size_t size)
+{
+	u32 chksum = 0;
+	u8 *bp = buf;
+	size_t i;
+
+	for (i = 0; i < size; i++)
+		chksum += bp[i];
+
+	return ~chksum;
+}
+
+static void fill_fcb(struct fcb_block *fcb, struct mtd_info *mtd)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct mxs_nand_info *nand_info = nand_get_controller_data(chip);
+
+	fcb->fingerprint = FCB_FINGERPRINT;
+	fcb->version = FCB_VERSION_1;
+	fcb->pagesize = mtd->writesize;
+	fcb->oob_pagesize = mtd->writesize + mtd->oobsize;
+	fcb->sectors = mtd->erasesize / mtd->writesize;
+
+	/* Divide ECC strength by two and save the value into FCB structure. */
+	fcb->ecc_level = nand_info->bch_geometry.ecc_strength >> 1;
+
+	fcb->ecc_type = fcb->ecc_level;
+
+	/* Also hardcoded in kobs-ng */
+	fcb->ecc_nr = 0x00000200;
+	fcb->ecc_size = 0x00000200;
+	fcb->datasetup = 80;
+	fcb->datahold = 60;
+	fcb->addr_setup = 25;
+	fcb->dsample_time = 6;
+	fcb->meta_size = 10;
+
+	/* DBBT search area starts at second page on first block */
+	fcb->dbbt_start = 1;
+
+	fcb->bb_byte = nand_info->bch_geometry.block_mark_byte_offset;
+	fcb->bb_start_bit = nand_info->bch_geometry.block_mark_bit_offset;
+
+	fcb->phy_offset = mtd->writesize;
+
+	fcb->nr_blocks = mtd->writesize / fcb->ecc_nr - 1;
+
+	fcb->checksum = calc_chksum((void *)fcb + 4, sizeof(*fcb) - 4);
+}
+
+static int dbbt_fill_data(struct mtd_info *mtd, void *buf, int num_blocks)
+{
+	int n, n_bad_blocks = 0;
+	u32 *bb = buf + 0x8;
+	u32 *n_bad_blocksp = buf + 0x4;
+
+	for (n = 0; n < num_blocks; n++) {
+		loff_t offset = n * mtd->erasesize;
+			if (mtd_block_isbad(mtd, offset)) {
+				n_bad_blocks++;
+				*bb = n;
+				bb++;
+		}
+	}
+
+	*n_bad_blocksp = n_bad_blocks;
+
+	return n_bad_blocks;
+}
+
+static int nandbcb_update(struct mtd_info *mtd, loff_t off, size_t size,
+			  size_t maxsize, const u_char *buf)
+{
+	nand_erase_options_t opts;
+	struct fcb_block *fcb;
+	struct dbbt_block *dbbt;
+	loff_t fw1_off;
+	void *fwbuf, *fcb_raw_page, *dbbt_page, *dbbt_data_page;
+	int nr_blks, nr_blks_fcb, fw1_blk;
+	size_t fwsize, dummy;
+	int i, ret;
+
+	/* erase */
+	memset(&opts, 0, sizeof(opts));
+	opts.offset = off;
+	opts.length = maxsize - 1;
+	ret = nand_erase_opts(mtd, &opts);
+	if (ret) {
+		printf("%s: erase failed (ret = %d)\n", __func__, ret);
+		return ret;
+	}
+
+	/*
+	 * Reference documentation from i.MX6DQRM section 8.5.2.2
+	 *
+	 * Nand Boot Control Block(BCB) contains two data structures,
+	 * - Firmware Configuration Block(FCB)
+	 * - Discovered Bad Block Table(DBBT)
+	 *
+	 * FCB contains,
+	 * - nand timings
+	 * - DBBT search page address,
+	 * - start page address of primary firmware
+	 * - start page address of secondary firmware
+	 *
+	 * setup fcb:
+	 * - number of blocks = mtd partition size / mtd erasesize
+	 * - two firmware blocks, primary and secondary
+	 * - first 4 block for FCB/DBBT
+	 * - rest split in half for primary and secondary firmware
+	 * - same firmware will write two times
+	 */
+	nr_blks_fcb = 2;
+	nr_blks = maxsize / mtd->erasesize;
+	fw1_blk = nr_blks_fcb;
+
+	/* write fw */
+	fwsize = ALIGN(size + FLASH_OFFSET_STANDARD + mtd->writesize,
+		       mtd->writesize);
+	fwbuf = kzalloc(fwsize, GFP_KERNEL);
+	if (!fwbuf) {
+		debug("failed to allocate fwbuf\n");
+		ret = -ENOMEM;
+		goto err;
+	}
+
+	memcpy(fwbuf + FLASH_OFFSET_STANDARD, buf, size);
+	fw1_off = fw1_blk * mtd->erasesize;
+	ret = nand_write_skip_bad(mtd, fw1_off, &fwsize, NULL, maxsize,
+				  (u_char *)fwbuf, WITH_WR_VERIFY);
+	printf("NAND fw write: 0x%llx offset, 0x%x bytes written: %s\n",
+	       fw1_off, fwsize, ret ? "ERROR" : "OK");
+	if (ret)
+		goto fwbuf_err;
+
+	/* fill fcb */
+	fcb = kzalloc(sizeof(*fcb), GFP_KERNEL);
+	if (!fcb) {
+		debug("failed to allocate fcb\n");
+		ret = -ENOMEM;
+		goto fwbuf_err;
+	}
+
+	fcb->fw1_start = (fw1_blk * mtd->erasesize) / mtd->writesize;
+	fcb->fw1_pages = size / mtd->writesize + 1;
+	fill_fcb(fcb, mtd);
+
+	/* fill dbbt */
+	dbbt_page = kzalloc(mtd->writesize, GFP_KERNEL);
+	if (!dbbt_page) {
+		debug("failed to allocate dbbt_page\n");
+		ret = -ENOMEM;
+		goto fcb_err;
+	}
+
+	dbbt_data_page = kzalloc(mtd->writesize, GFP_KERNEL);
+	if (!dbbt_data_page) {
+		debug("failed to allocate dbbt_data_page\n");
+		ret = -ENOMEM;
+		goto dbbt_page_err;
+	}
+
+	dbbt = dbbt_page;
+	dbbt->checksum = 0;
+	dbbt->fingerprint = DBBT_FINGERPRINT2;
+	dbbt->version = DBBT_VERSION_1;
+	ret = dbbt_fill_data(mtd, dbbt_data_page, nr_blks);
+	if (ret < 0)
+		goto dbbt_data_page_err;
+	else if (ret > 0)
+		dbbt->dbbtpages = 1;
+
+	/* write fcb/dbbt */
+	fcb_raw_page = kzalloc(mtd->writesize + mtd->oobsize, GFP_KERNEL);
+	if (!fcb_raw_page) {
+		debug("failed to allocate fcb_raw_page\n");
+		ret = -ENOMEM;
+		goto dbbt_data_page_err;
+	}
+
+	memcpy(fcb_raw_page + 12, fcb, sizeof(struct fcb_block));
+	encode_hamming_13_8(fcb_raw_page + 12, fcb_raw_page + 12 + 512, 512);
+	/*
+	 * Set the first and second byte of OOB data to 0xFF, not 0x00. These
+	 * bytes are used as the Manufacturers Bad Block Marker (MBBM). Since
+	 * the FCB is mostly written to the first page in a block, a scan for
+	 * factory bad blocks will detect these blocks as bad, e.g. when
+	 * function nand_scan_bbt() is executed to build a new bad block table.
+	 */
+	memset(fcb_raw_page + mtd->writesize, 0xFF, 2);
+
+	for (i = 0; i < nr_blks_fcb; i++) {
+		if (mtd_block_isbad(mtd, off)) {
+			printf("Block %d is bad, skipped\n", i);
+			continue;
+		}
+
+		/* raw write */
+		mtd_oob_ops_t ops = {
+			.datbuf = (u8 *)fcb_raw_page,
+			.oobbuf = ((u8 *)fcb_raw_page) + mtd->writesize,
+			.len = mtd->writesize,
+			.ooblen = mtd->oobsize,
+			.mode = MTD_OPS_RAW
+		};
+
+		ret = mtd_write_oob(mtd, mtd->erasesize * i, &ops);
+		if (ret)
+			goto fcb_raw_page_err;
+		debug("NAND fcb write: 0x%x offset, 0x%x bytes written: %s\n",
+		      mtd->erasesize * i, ops.len, ret ? "ERROR" : "OK");
+
+		ret = mtd_write(mtd, mtd->erasesize * i + mtd->writesize,
+				mtd->writesize, &dummy, dbbt_page);
+		if (ret)
+			goto fcb_raw_page_err;
+		debug("NAND dbbt write: 0x%x offset, 0x%x bytes written: %s\n",
+		      mtd->erasesize * i + mtd->writesize, dummy,
+		      ret ? "ERROR" : "OK");
+
+		/* dbbtpages == 0 if no bad blocks */
+		if (dbbt->dbbtpages > 0) {
+			loff_t to = (mtd->erasesize * i + mtd->writesize * 5);
+
+			ret = mtd_write(mtd, to, mtd->writesize, &dummy,
+					dbbt_data_page);
+			if (ret)
+				goto fcb_raw_page_err;
+		}
+	}
+
+fcb_raw_page_err:
+	kfree(fcb_raw_page);
+dbbt_data_page_err:
+	kfree(dbbt_data_page);
+dbbt_page_err:
+	kfree(dbbt_page);
+fcb_err:
+	kfree(fcb);
+fwbuf_err:
+	kfree(fwbuf);
+err:
+	return ret;
+}
+
+static int do_nandbcb_update(int argc, char * const argv[])
+{
+	struct mtd_info *mtd;
+	loff_t addr, offset, size, maxsize;
+	char *endp;
+	u_char *buf;
+	int dev;
+	int ret;
+
+	if (argc != 4)
+		return CMD_RET_USAGE;
+
+	dev = nand_curr_device;
+	if (dev < 0) {
+		printf("failed to get nand_curr_device, run nand device");
+		return CMD_RET_FAILURE;
+	}
+
+	addr = simple_strtoul(argv[1], &endp, 16);
+	if (*argv[1] == 0 || *endp != 0)
+		return CMD_RET_FAILURE;
+
+	mtd = get_nand_dev_by_index(dev);
+	if (mtd_arg_off_size(argc - 2, argv + 2, &dev, &offset, &size,
+			     &maxsize, MTD_DEV_TYPE_NAND, mtd->size))
+		return CMD_RET_FAILURE;
+
+	buf = map_physmem(addr, size, MAP_WRBACK);
+	if (!buf) {
+		puts("failed to map physical memory\n");
+		return CMD_RET_FAILURE;
+	}
+
+	ret = nandbcb_update(mtd, offset, size, maxsize, buf);
+
+	return ret == 0 ? CMD_RET_SUCCESS : CMD_RET_FAILURE;
+}
+
+static int do_nandbcb(cmd_tbl_t *cmdtp, int flag, int argc,
+		      char * const argv[])
+{
+	const char *cmd;
+	int ret = 0;
+
+	if (argc < 5)
+		goto usage;
+
+	cmd = argv[1];
+	--argc;
+	++argv;
+
+	if (strcmp(cmd, "update") == 0) {
+		ret = do_nandbcb_update(argc, argv);
+		goto done;
+	}
+
+done:
+	if (ret != -1)
+		return ret;
+usage:
+	return CMD_RET_USAGE;
+}
+
+static char nandbcb_help_text[] =
+	"update addr off|partition len	- update 'len' bytes starting at\n"
+	"	'off|part' to memory address 'addr', skipping  bad blocks";
+
+U_BOOT_CMD(nandbcb, 5, 1, do_nandbcb,
+	   "i.MX6 Nand BCB",
+	   nandbcb_help_text
+);
diff --git a/arch/arm/mach-imx/cpu.c b/arch/arm/mach-imx/cpu.c
index 3a8cf30..6e9a175 100644
--- a/arch/arm/mach-imx/cpu.c
+++ b/arch/arm/mach-imx/cpu.c
@@ -289,10 +289,12 @@
 	imx_pcie_remove();
 #endif
 #if defined(CONFIG_SATA)
-	sata_remove(0);
+	if (!is_mx6sdl()) {
+		sata_remove(0);
 #if defined(CONFIG_MX6)
-	disable_sata_clock();
+		disable_sata_clock();
 #endif
+	}
 #endif
 #if defined(CONFIG_VIDEO_IPUV3)
 	/* disable video before launching O/S */
diff --git a/arch/arm/mach-imx/imx8/Makefile b/arch/arm/mach-imx/imx8/Makefile
index 31ad169..92b5c56 100644
--- a/arch/arm/mach-imx/imx8/Makefile
+++ b/arch/arm/mach-imx/imx8/Makefile
@@ -4,4 +4,4 @@
 # SPDX-License-Identifier:	GPL-2.0+
 #
 
-obj-y += cpu.o iomux.o
+obj-y += cpu.o iomux.o misc.o
diff --git a/arch/arm/mach-imx/imx8/misc.c b/arch/arm/mach-imx/imx8/misc.c
new file mode 100644
index 0000000..fe73e29
--- /dev/null
+++ b/arch/arm/mach-imx/imx8/misc.c
@@ -0,0 +1,39 @@
+// SPDX-License-Identifier: GPL-2.0+
+#include <common.h>
+#include <asm/arch/sci/sci.h>
+
+int sc_pm_setup_uart(sc_rsrc_t uart_rsrc, sc_pm_clock_rate_t clk_rate)
+{
+	sc_pm_clock_rate_t rate = clk_rate;
+	int ret;
+
+	/* Power up UARTn */
+	ret = sc_pm_set_resource_power_mode(-1, uart_rsrc, SC_PM_PW_MODE_ON);
+	if (ret)
+		return ret;
+
+	/* Set UARTn clock root to 'rate' MHz */
+	ret = sc_pm_set_clock_rate(-1, uart_rsrc, SC_PM_CLK_PER, &rate);
+	if (ret)
+		return ret;
+
+	/* Enable UARTn clock root */
+	ret = sc_pm_clock_enable(-1, uart_rsrc, SC_PM_CLK_PER, true, false);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+void build_info(void)
+{
+	u32 sc_build = 0, sc_commit = 0;
+
+	/* Get SCFW build and commit id */
+	sc_misc_build_info(-1, &sc_build, &sc_commit);
+	if (!sc_build) {
+		printf("SCFW does not support build info\n");
+		sc_commit = 0; /* Display 0 if build info not supported */
+	}
+	printf("Build: SCFW %x\n", sc_commit);
+}
diff --git a/arch/arm/mach-imx/mx6/soc.c b/arch/arm/mach-imx/mx6/soc.c
index e80f1d4..4084ab7 100644
--- a/arch/arm/mach-imx/mx6/soc.c
+++ b/arch/arm/mach-imx/mx6/soc.c
@@ -95,6 +95,11 @@
 			type = MXC_CPU_MX6DP;
 	}
 	reg &= 0xff;		/* mx6 silicon revision */
+
+	/* For 6DQ, the value 0x00630005 is Silicon revision 1.3*/
+	if (((type == MXC_CPU_MX6Q) || (type == MXC_CPU_MX6D)) && (reg == 0x5))
+		reg = 0x3;
+
 	return (type << 12) | (reg + (0x10 * (major + 1)));
 }
 
diff --git a/arch/arm/mach-imx/spl.c b/arch/arm/mach-imx/spl.c
index 9f1e0f6..1f230ac 100644
--- a/arch/arm/mach-imx/spl.c
+++ b/arch/arm/mach-imx/spl.c
@@ -24,6 +24,7 @@
 {
 	unsigned int bmode = readl(&src_base->sbmr2);
 	u32 reg = imx6_src_get_boot_mode();
+	u32 mmc_index = ((reg >> 11) & 0x03);
 
 	/*
 	 * Check for BMODE if serial downloader is enabled
@@ -84,11 +85,12 @@
 	/* SD/eSD: 8.5.3, Table 8-15  */
 	case IMX6_BMODE_SD:
 	case IMX6_BMODE_ESD:
-		return BOOT_DEVICE_MMC1;
-	/* MMC/eMMC: 8.5.3 */
 	case IMX6_BMODE_MMC:
 	case IMX6_BMODE_EMMC:
-		return BOOT_DEVICE_MMC1;
+		if (mmc_index == 1)
+			return BOOT_DEVICE_MMC2;
+		else
+			return BOOT_DEVICE_MMC1;
 	/* NAND Flash: 8.5.2, Table 8-10 */
 	case IMX6_BMODE_NAND_MIN ... IMX6_BMODE_NAND_MAX:
 		return BOOT_DEVICE_NAND;
diff --git a/arch/sandbox/dts/test.dts b/arch/sandbox/dts/test.dts
index a05414e..27b0baa 100644
--- a/arch/sandbox/dts/test.dts
+++ b/arch/sandbox/dts/test.dts
@@ -211,6 +211,12 @@
 			clock-mult = <2>;
 			clocks = <&clk_fixed>;
 		};
+
+		osc {
+			compatible = "fixed-clock";
+			#clock-cells = <0>;
+			clock-frequency = <20000000>;
+		};
 	};
 
 	clk_sandbox: clk-sbox {
@@ -226,6 +232,10 @@
 		clock-names = "fixed", "i2c", "spi";
 	};
 
+	ccf: clk-ccf {
+		compatible = "sandbox,clk-ccf";
+	};
+
 	eth@10002000 {
 		compatible = "sandbox,eth";
 		reg = <0x10002000 0x1000>;
diff --git a/board/armadeus/opos6uldev/board.c b/board/armadeus/opos6uldev/board.c
index aed334f..cbf40d5 100644
--- a/board/armadeus/opos6uldev/board.c
+++ b/board/armadeus/opos6uldev/board.c
@@ -70,27 +70,6 @@
 }
 #endif
 
-#ifdef CONFIG_USB_EHCI_MX6
-#define USB_OTHERREGS_OFFSET	0x800
-#define UCTRL_PWR_POL		(1 << 9)
-
-int board_ehci_hcd_init(int port)
-{
-	u32 *usbnc_usb_ctrl;
-
-	if (port > 1)
-		return -EINVAL;
-
-	usbnc_usb_ctrl = (u32 *)(USB_BASE_ADDR + USB_OTHERREGS_OFFSET +
-				 port * 4);
-
-	/* Set Power polarity */
-	setbits_le32(usbnc_usb_ctrl, UCTRL_PWR_POL);
-
-	return 0;
-}
-#endif
-
 int opos6ul_board_late_init(void)
 {
 #ifdef CONFIG_VIDEO_MXS
diff --git a/board/dhelectronics/dh_imx6/dh_imx6.c b/board/dhelectronics/dh_imx6/dh_imx6.c
index 1d41690..40cc2a8 100644
--- a/board/dhelectronics/dh_imx6/dh_imx6.c
+++ b/board/dhelectronics/dh_imx6/dh_imx6.c
@@ -18,7 +18,6 @@
 #include <asm/io.h>
 #include <asm/mach-imx/boot_mode.h>
 #include <asm/mach-imx/iomux-v3.h>
-#include <asm/mach-imx/mxc_i2c.h>
 #include <asm/mach-imx/sata.h>
 #include <ahci.h>
 #include <dwc_ahsata.h>
@@ -26,7 +25,7 @@
 #include <errno.h>
 #include <fsl_esdhc_imx.h>
 #include <fuse.h>
-#include <i2c.h>
+#include <i2c_eeprom.h>
 #include <miiphy.h>
 #include <mmc.h>
 #include <net.h>
@@ -36,92 +35,6 @@
 
 DECLARE_GLOBAL_DATA_PTR;
 
-#define I2C_PAD_CTRL							\
-	(PAD_CTL_PUS_100K_UP | PAD_CTL_SPEED_MED | PAD_CTL_DSE_40ohm |	\
-	PAD_CTL_HYS | PAD_CTL_ODE | PAD_CTL_SRE_FAST)
-
-#define EEPROM_I2C_ADDRESS	0x50
-
-#define PC			MUX_PAD_CTRL(I2C_PAD_CTRL)
-
-static struct i2c_pads_info dh6sdl_i2c_pad_info0 = {
-	.scl = {
-		.i2c_mode  = MX6DL_PAD_EIM_D21__I2C1_SCL | PC,
-		.gpio_mode = MX6DL_PAD_EIM_D21__GPIO3_IO21 | PC,
-		.gp = IMX_GPIO_NR(3, 21)
-	},
-	.sda = {
-		 .i2c_mode = MX6DL_PAD_EIM_D28__I2C1_SDA | PC,
-		 .gpio_mode = MX6DL_PAD_EIM_D28__GPIO3_IO28 | PC,
-		 .gp = IMX_GPIO_NR(3, 28)
-	 }
-};
-
-static struct i2c_pads_info dh6sdl_i2c_pad_info1 = {
-	.scl = {
-		.i2c_mode  = MX6DL_PAD_KEY_COL3__I2C2_SCL | PC,
-		.gpio_mode = MX6DL_PAD_KEY_COL3__GPIO4_IO12 | PC,
-		.gp = IMX_GPIO_NR(4, 12)
-	},
-	.sda = {
-		 .i2c_mode = MX6DL_PAD_KEY_ROW3__I2C2_SDA | PC,
-		 .gpio_mode = MX6DL_PAD_KEY_ROW3__GPIO4_IO13 | PC,
-		 .gp = IMX_GPIO_NR(4, 13)
-	 }
-};
-
-static struct i2c_pads_info dh6sdl_i2c_pad_info2 = {
-	.scl = {
-		.i2c_mode  = MX6DL_PAD_GPIO_3__I2C3_SCL | PC,
-		.gpio_mode = MX6DL_PAD_GPIO_3__GPIO1_IO03 | PC,
-		.gp = IMX_GPIO_NR(1, 3)
-	},
-	.sda = {
-		 .i2c_mode = MX6DL_PAD_GPIO_6__I2C3_SDA | PC,
-		 .gpio_mode = MX6DL_PAD_GPIO_6__GPIO1_IO06 | PC,
-		 .gp = IMX_GPIO_NR(1, 6)
-	 }
-};
-
-static struct i2c_pads_info dh6dq_i2c_pad_info0 = {
-	.scl = {
-		.i2c_mode  = MX6Q_PAD_EIM_D21__I2C1_SCL | PC,
-		.gpio_mode = MX6Q_PAD_EIM_D21__GPIO3_IO21 | PC,
-		.gp = IMX_GPIO_NR(3, 21)
-	},
-	.sda = {
-		 .i2c_mode = MX6Q_PAD_EIM_D28__I2C1_SDA | PC,
-		 .gpio_mode = MX6Q_PAD_EIM_D28__GPIO3_IO28 | PC,
-		 .gp = IMX_GPIO_NR(3, 28)
-	 }
-};
-
-static struct i2c_pads_info dh6dq_i2c_pad_info1 = {
-	.scl = {
-		.i2c_mode  = MX6Q_PAD_KEY_COL3__I2C2_SCL | PC,
-		.gpio_mode = MX6Q_PAD_KEY_COL3__GPIO4_IO12 | PC,
-		.gp = IMX_GPIO_NR(4, 12)
-	},
-	.sda = {
-		 .i2c_mode = MX6Q_PAD_KEY_ROW3__I2C2_SDA | PC,
-		 .gpio_mode = MX6Q_PAD_KEY_ROW3__GPIO4_IO13 | PC,
-		 .gp = IMX_GPIO_NR(4, 13)
-	 }
-};
-
-static struct i2c_pads_info dh6dq_i2c_pad_info2 = {
-	.scl = {
-		.i2c_mode  = MX6Q_PAD_GPIO_3__I2C3_SCL | PC,
-		.gpio_mode = MX6Q_PAD_GPIO_3__GPIO1_IO03 | PC,
-		.gp = IMX_GPIO_NR(1, 3)
-	},
-	.sda = {
-		 .i2c_mode = MX6Q_PAD_GPIO_6__I2C3_SDA | PC,
-		 .gpio_mode = MX6Q_PAD_GPIO_6__GPIO1_IO06 | PC,
-		 .gp = IMX_GPIO_NR(1, 6)
-	 }
-};
-
 int dram_init(void)
 {
 	gd->ram_size = imx_ddr_size();
@@ -196,7 +109,6 @@
 #ifdef CONFIG_USB_EHCI_MX6
 static void setup_usb(void)
 {
-	gpio_request(IMX_GPIO_NR(3, 31), "USB-VBUS");
 	/*
 	 * Set daisy chain for otg_pin_id on MX6Q.
 	 * For MX6DL, this bit is reserved.
@@ -211,26 +123,12 @@
 	else
 		return USB_INIT_DEVICE;
 }
-
-int board_ehci_power(int port, int on)
-{
-	switch (port) {
-	case 0:
-		break;
-	case 1:
-		gpio_direction_output(IMX_GPIO_NR(3, 31), !!on);
-		break;
-	default:
-		printf("MXC USB port %d not yet supported\n", port);
-		return -EINVAL;
-	}
-
-	return 0;
-}
 #endif
 
 static int setup_dhcom_mac_from_fuse(void)
 {
+	struct udevice *dev;
+	ofnode eeprom;
 	unsigned char enetaddr[6];
 	int ret;
 
@@ -245,13 +143,19 @@
 		return 0;
 	}
 
+	eeprom = ofnode_path("/soc/aips-bus@2100000/i2c@21a8000/eeprom@50");
+	if (!ofnode_valid(eeprom)) {
+		printf("Invalid hardware path to EEPROM!\n");
+		return -ENODEV;
+	}
+
-	ret = i2c_set_bus_num(2);
+	ret = uclass_get_device_by_ofnode(UCLASS_I2C_EEPROM, eeprom, &dev);
 	if (ret) {
-		printf("Error switching I2C bus!\n");
+		printf("Cannot find EEPROM!\n");
 		return ret;
 	}
 
-	ret = i2c_read(EEPROM_I2C_ADDRESS, 0xfa, 0x1, enetaddr, 0x6);
+	ret = i2c_eeprom_read(dev, 0xfa, enetaddr, 0x6);
 	if (ret) {
 		printf("Error reading configuration EEPROM!\n");
 		return ret;
@@ -282,18 +186,6 @@
 	/* Enable eim_slow clocks */
 	setbits_le32(&mxc_ccm->CCGR6, 0x1 << MXC_CCM_CCGR6_EMI_SLOW_OFFSET);
 
-#ifdef CONFIG_SYS_I2C_MXC
-	if (is_mx6dq()) {
-		setup_i2c(0, CONFIG_SYS_I2C_SPEED, 0x7f, &dh6dq_i2c_pad_info0);
-		setup_i2c(1, CONFIG_SYS_I2C_SPEED, 0x7f, &dh6dq_i2c_pad_info1);
-		setup_i2c(2, CONFIG_SYS_I2C_SPEED, 0x7f, &dh6dq_i2c_pad_info2);
-	} else {
-		setup_i2c(0, CONFIG_SYS_I2C_SPEED, 0x7f, &dh6sdl_i2c_pad_info0);
-		setup_i2c(1, CONFIG_SYS_I2C_SPEED, 0x7f, &dh6sdl_i2c_pad_info1);
-		setup_i2c(2, CONFIG_SYS_I2C_SPEED, 0x7f, &dh6sdl_i2c_pad_info2);
-	}
-#endif
-
 	setup_dhcom_mac_from_fuse();
 
 	return 0;
@@ -372,3 +264,18 @@
 	puts("Board: DHCOM i.MX6\n");
 	return 0;
 }
+
+#ifdef CONFIG_MULTI_DTB_FIT
+int board_fit_config_name_match(const char *name)
+{
+	if (is_mx6dq()) {
+		if (!strcmp(name, "imx6q-dhcom-pdk2"))
+			return 0;
+	} else if (is_mx6sdl()) {
+		if (!strcmp(name, "imx6dl-dhcom-pdk2"))
+			return 0;
+	}
+
+	return -1;
+}
+#endif
diff --git a/board/dhelectronics/dh_imx6/dh_imx6_spl.c b/board/dhelectronics/dh_imx6/dh_imx6_spl.c
index b492961..1b7acc8 100644
--- a/board/dhelectronics/dh_imx6/dh_imx6_spl.c
+++ b/board/dhelectronics/dh_imx6/dh_imx6_spl.c
@@ -440,8 +440,13 @@
 
 /* SPI */
 static iomux_v3_cfg_t const ecspi1_pads[] = {
-	/* SS0 */
-	IOMUX_PADS(PAD_EIM_EB2__GPIO2_IO30	| MUX_PAD_CTRL(SPI_PAD_CTRL)),
+	/* SS0 - SS of boot flash */
+	IOMUX_PADS(PAD_EIM_EB2__GPIO2_IO30	|
+		MUX_PAD_CTRL(SPI_PAD_CTRL | PAD_CTL_PUS_100K_UP)),
+	/* SS2 - SS of DHCOM SPI1 */
+	IOMUX_PADS(PAD_KEY_ROW2__GPIO4_IO11	|
+		MUX_PAD_CTRL(SPI_PAD_CTRL | PAD_CTL_PUS_100K_UP)),
+
 	IOMUX_PADS(PAD_EIM_D17__ECSPI1_MISO	| MUX_PAD_CTRL(SPI_PAD_CTRL)),
 	IOMUX_PADS(PAD_EIM_D18__ECSPI1_MOSI	| MUX_PAD_CTRL(SPI_PAD_CTRL)),
 	IOMUX_PADS(PAD_EIM_D16__ECSPI1_SCLK	| MUX_PAD_CTRL(SPI_PAD_CTRL)),
diff --git a/board/engicam/common/board.c b/board/engicam/common/board.c
index 7486f0a..567b9f6 100644
--- a/board/engicam/common/board.c
+++ b/board/engicam/common/board.c
@@ -53,8 +53,6 @@
 			env_set("fdt_file", "imx6dl-icore-rqs.dtb");
 	} else if (!strcmp(cmp_dtb, "imx6ul-geam"))
 		env_set("fdt_file", "imx6ul-geam.dtb");
-	else if (!strcmp(cmp_dtb, "imx6ul-isiot-mmc"))
-		env_set("fdt_file", "imx6ul-isiot-emmc.dtb");
 	else if (!strcmp(cmp_dtb, "imx6ul-isiot-emmc"))
 		env_set("fdt_file", "imx6ul-isiot-emmc.dtb");
 	else if (!strcmp(cmp_dtb, "imx6ul-isiot-nand"))
diff --git a/board/freescale/imx8qm_mek/imx8qm_mek.c b/board/freescale/imx8qm_mek/imx8qm_mek.c
index e69efc4..b7a609b 100644
--- a/board/freescale/imx8qm_mek/imx8qm_mek.c
+++ b/board/freescale/imx8qm_mek/imx8qm_mek.c
@@ -34,21 +34,11 @@
 
 int board_early_init_f(void)
 {
+	sc_pm_clock_rate_t rate = SC_80MHZ;
 	int ret;
-	/* Set UART0 clock root to 80 MHz */
-	sc_pm_clock_rate_t rate = 80000000;
-
-	/* Power up UART0 */
-	ret = sc_pm_set_resource_power_mode(-1, SC_R_UART_0, SC_PM_PW_MODE_ON);
-	if (ret)
-		return ret;
-
-	ret = sc_pm_set_clock_rate(-1, SC_R_UART_0, 2, &rate);
-	if (ret)
-		return ret;
 
-	/* Enable UART0 clock root */
-	ret = sc_pm_clock_enable(-1, SC_R_UART_0, 2, true, false);
+	/* Set UART0 clock root to 80 MHz */
+	ret = sc_pm_setup_uart(SC_R_UART_0, rate);
 	if (ret)
 		return ret;
 
@@ -88,19 +78,6 @@
 }
 #endif
 
-void build_info(void)
-{
-	u32 sc_build = 0, sc_commit = 0;
-
-	/* Get SCFW build and commit id */
-	sc_misc_build_info(-1, &sc_build, &sc_commit);
-	if (!sc_build) {
-		printf("SCFW does not support build info\n");
-		sc_commit = 0; /* Display 0 when the build info is not supported*/
-	}
-	printf("Build: SCFW %x\n", sc_commit);
-}
-
 int checkboard(void)
 {
 	puts("Board: iMX8QM MEK\n");
diff --git a/board/freescale/imx8qxp_mek/imx8qxp_mek.c b/board/freescale/imx8qxp_mek/imx8qxp_mek.c
index 1207314..3cf73e1 100644
--- a/board/freescale/imx8qxp_mek/imx8qxp_mek.c
+++ b/board/freescale/imx8qxp_mek/imx8qxp_mek.c
@@ -40,21 +40,11 @@
 
 int board_early_init_f(void)
 {
+	sc_pm_clock_rate_t rate = SC_80MHZ;
 	int ret;
-	/* Set UART0 clock root to 80 MHz */
-	sc_pm_clock_rate_t rate = 80000000;
-
-	/* Power up UART0 */
-	ret = sc_pm_set_resource_power_mode(-1, SC_R_UART_0, SC_PM_PW_MODE_ON);
-	if (ret)
-		return ret;
-
-	ret = sc_pm_set_clock_rate(-1, SC_R_UART_0, 2, &rate);
-	if (ret)
-		return ret;
 
-	/* Enable UART0 clock root */
-	ret = sc_pm_clock_enable(-1, SC_R_UART_0, 2, true, false);
+	/* Set UART0 clock root to 80 MHz */
+	ret = sc_pm_setup_uart(SC_R_UART_0, rate);
 	if (ret)
 		return ret;
 
@@ -104,19 +94,6 @@
 }
 #endif
 
-void build_info(void)
-{
-	u32 sc_build = 0, sc_commit = 0;
-
-	/* Get SCFW build and commit id */
-	sc_misc_build_info(-1, &sc_build, &sc_commit);
-	if (!sc_build) {
-		printf("SCFW does not support build info\n");
-		sc_commit = 0; /* Display 0 when the build info is not supported */
-	}
-	printf("Build: SCFW %x\n", sc_commit);
-}
-
 int checkboard(void)
 {
 	puts("Board: iMX8QXP MEK\n");
diff --git a/board/freescale/mx6sxsabresd/imximage.cfg b/board/freescale/mx6sxsabresd/imximage.cfg
index 3e94f6a..0354bb3 100644
--- a/board/freescale/mx6sxsabresd/imximage.cfg
+++ b/board/freescale/mx6sxsabresd/imximage.cfg
@@ -18,6 +18,13 @@
 BOOT_FROM	sd
 
 /*
+ * Secure boot support
+ */
+#ifdef CONFIG_SECURE_BOOT
+CSF CONFIG_CSF_SIZE
+#endif
+
+/*
  * Device Configuration Data (DCD)
  *
  * Each entry must have the format:
diff --git a/board/freescale/mx7ulp_evk/imximage.cfg b/board/freescale/mx7ulp_evk/imximage.cfg
index a6e18d9..43ebc23 100644
--- a/board/freescale/mx7ulp_evk/imximage.cfg
+++ b/board/freescale/mx7ulp_evk/imximage.cfg
@@ -45,12 +45,12 @@
 DATA 4   0x403e0040 0x01000020
 DATA 4   0x403e0500 0x01000000
 DATA 4   0x403e050c 0x80808080
-DATA 4   0x403e0508 0x00140000
-DATA 4   0x403E0510 0x00000004
-DATA 4   0x403E0514 0x00000002
+DATA 4   0x403e0508 0x00160002
+DATA 4   0x403E0510 0x00000001
+DATA 4   0x403E0514 0x00000014
 DATA 4   0x403e0500 0x00000001
 CHECK_BITS_SET 4 0x403e0500 0x01000000
-DATA 4   0x403e050c 0x8080801E
+DATA 4   0x403e050c 0x8080801B
 CHECK_BITS_SET 4 0x403e050c 0x00000040
 DATA 4   0x403E0030 0x00000001
 DATA 4   0x403e0040 0x11000020
@@ -94,11 +94,6 @@
 DATA 4   0x40AB0824 0x33333333
 DATA 4   0x40AB0828 0x33333333
 
-DATA 4   0x40AB082C 0xf3333333
-DATA 4   0x40AB0830 0xf3333333
-DATA 4   0x40AB0834 0xf3333333
-DATA 4   0x40AB0838 0xf3333333
-
 DATA 4   0x40AB08C0 0x24922492
 DATA 4   0x40AB08B8 0x00000800
 
@@ -113,8 +108,8 @@
 DATA 4   0x40AB0040 0x0000003F
 DATA 4   0x40AB0000 0xC3190000
 
-DATA 4   0x40AB001C 0x00008050
-DATA 4   0x40AB001C 0x00008058
+DATA 4   0x40AB001C 0x00008010
+DATA 4   0x40AB001C 0x00008018
 DATA 4   0x40AB001C 0x003F8030
 DATA 4   0x40AB001C 0x003F8038
 DATA 4   0x40AB001C 0xFF0A8030
diff --git a/board/freescale/mx7ulp_evk/plugin.S b/board/freescale/mx7ulp_evk/plugin.S
index 082b2be..2cc93db 100644
--- a/board/freescale/mx7ulp_evk/plugin.S
+++ b/board/freescale/mx7ulp_evk/plugin.S
@@ -1,6 +1,7 @@
 /* SPDX-License-Identifier: GPL-2.0+ */
 /*
  * Copyright (C) 2016 Freescale Semiconductor, Inc.
+ * Copyright 2019 NXP
  */
 
 #include <config.h>
@@ -15,13 +16,14 @@
 	str r3, [r2, #0x40]
 	ldr r3, =0x01000000
 	str r3, [r2, #0x500]
+
 	ldr r3, =0x80808080
 	str r3, [r2, #0x50c]
-	ldr r3, =0x00140000
+	ldr r3, =0x00160002
 	str r3, [r2, #0x508]
-	ldr r3, =0x00000004
+	ldr r3, =0x00000001
 	str r3, [r2, #0x510]
-	ldr r3, =0x00000002
+	ldr r3, =0x00000014
 	str r3, [r2, #0x514]
 	ldr r3, =0x00000001
 	str r3, [r2, #0x500]
@@ -33,7 +35,7 @@
 	cmp r4, r3
 	bne wait1
 
-	ldr r3, =0x8080801E
+	ldr r3, =0x8080801B
 	str r3, [r2, #0x50c]
 
 	ldr r3, =0x00000040
@@ -132,15 +134,6 @@
 	ldr r1, =0x33333333
 	str r1, [r0, #0x828]
 
-	ldr r1, =0xf3333333
-	str r1, [r0, #0x82c]
-	ldr r1, =0xf3333333
-	str r1, [r0, #0x830]
-	ldr r1, =0xf3333333
-	str r1, [r0, #0x834]
-	ldr r1, =0xf3333333
-	str r1, [r0, #0x838]
-
 	ldr r1, =0x24922492
 	str r1, [r0, #0x8c0]
 	ldr r1, =0x00000800
@@ -168,9 +161,9 @@
 	ldr r1, =0xC3190000
 	str r1, [r0, #0x0]
 
-	ldr r1, =0x00008050
+	ldr r1, =0x00008010
 	str r1, [r0, #0x1c]
-	ldr r1, =0x00008058
+	ldr r1, =0x00008018
 	str r1, [r0, #0x1c]
 	ldr r1, =0x003F8030
 	str r1, [r0, #0x1c]
diff --git a/board/liebherr/display5/common.c b/board/liebherr/display5/common.c
index 7b89d16..8390d9a 100644
--- a/board/liebherr/display5/common.c
+++ b/board/liebherr/display5/common.c
@@ -68,7 +68,7 @@
 
 int board_spi_cs_gpio(unsigned int bus, unsigned int cs)
 {
-	if (bus != 1 || cs != (IMX_GPIO_NR(5, 29) << 8))
+	if (bus != 1 || cs != 0)
 		return -EINVAL;
 
 	return IMX_GPIO_NR(5, 29);
diff --git a/board/liebherr/display5/display5.c b/board/liebherr/display5/display5.c
index 6b7ff0a..ea49b71 100644
--- a/board/liebherr/display5/display5.c
+++ b/board/liebherr/display5/display5.c
@@ -413,12 +413,3 @@
 
 	return 0;
 }
-
-static struct mxc_serial_platdata mxc_serial_plat = {
-	.reg = (struct mxc_uart *)UART5_BASE,
-};
-
-U_BOOT_DEVICE(mxc_serial) = {
-	.name = "serial_mxc",
-	.platdata = &mxc_serial_plat,
-};
diff --git a/board/logicpd/imx6/imx6logic.c b/board/logicpd/imx6/imx6logic.c
index e48b3be..6e3ffa7 100644
--- a/board/logicpd/imx6/imx6logic.c
+++ b/board/logicpd/imx6/imx6logic.c
@@ -223,25 +223,15 @@
 	switch (reg) {
 	case 0:
 		SETUP_IOMUX_PADS(usdhc1_pads);
-		usdhc_cfg[0].esdhc_base = USDHC1_BASE_ADDR;
-		usdhc_cfg[0].sdhc_clk = mxc_get_clock(MXC_ESDHC_CLK);
-		gd->arch.sdhc_clk = usdhc_cfg[0].sdhc_clk;
 		break;
 	case 1:
 		SETUP_IOMUX_PADS(usdhc2_pads);
-		usdhc_cfg[1].esdhc_base = USDHC2_BASE_ADDR;
-		usdhc_cfg[1].sdhc_clk = mxc_get_clock(MXC_ESDHC2_CLK);
-		gd->arch.sdhc_clk = usdhc_cfg[1].sdhc_clk;
 		break;
 	}
 
-	return fsl_esdhc_initialize(bis, &usdhc_cfg[reg]);
+	return 0;
 }
 
-int board_mmc_getcd(struct mmc *mmc)
-{
-	return 1;
-}
 #endif
 
 static void ccgr_init(void)
diff --git a/board/technexion/pico-imx7d/pico-imx7d.c b/board/technexion/pico-imx7d/pico-imx7d.c
index e3d75e5..216475c 100644
--- a/board/technexion/pico-imx7d/pico-imx7d.c
+++ b/board/technexion/pico-imx7d/pico-imx7d.c
@@ -16,7 +16,6 @@
 #include <i2c.h>
 #include <miiphy.h>
 #include <netdev.h>
-#include <usb.h>
 #include <power/pmic.h>
 #include <power/pfuze3000_pmic.h>
 #include "../../freescale/common/pfuze.h"
@@ -328,15 +327,3 @@
 	return 0;
 }
 
-int board_usb_phy_mode(int port)
-{
-	switch (port) {
-	case 0:
-		return USB_INIT_DEVICE;
-	case 1:
-		return USB_INIT_HOST;
-	default:
-		return -EINVAL;
-	}
-	return 0;
-}
diff --git a/board/toradex/apalis-imx8/apalis-imx8.c b/board/toradex/apalis-imx8/apalis-imx8.c
index f516e54..5433c75 100644
--- a/board/toradex/apalis-imx8/apalis-imx8.c
+++ b/board/toradex/apalis-imx8/apalis-imx8.c
@@ -37,25 +37,14 @@
 
 int board_early_init_f(void)
 {
-	sc_pm_clock_rate_t rate;
+	sc_pm_clock_rate_t rate = SC_80MHZ;
 	sc_err_t err = 0;
 
-	/* Power up UART1 */
-	err = sc_pm_set_resource_power_mode(-1, SC_R_UART_1, SC_PM_PW_MODE_ON);
+	/* Set UART1 clock root to 80 MHz and enable it */
+	err = sc_pm_setup_uart(SC_R_UART_1, rate);
 	if (err != SC_ERR_NONE)
 		return 0;
 
-	/* Set UART3 clock root to 80 MHz */
-	rate = 80000000;
-	err = sc_pm_set_clock_rate(-1, SC_R_UART_1, SC_PM_CLK_PER, &rate);
-	if (err != SC_ERR_NONE)
-		return 0;
-
-	/* Enable UART1 clock root */
-	err = sc_pm_clock_enable(-1, SC_R_UART_1, SC_PM_CLK_PER, true, false);
-	if (err != SC_ERR_NONE)
-		return 0;
-
 	setup_iomux_uart();
 
 	return 0;
@@ -82,19 +71,6 @@
 }
 #endif
 
-void build_info(void)
-{
-	u32 sc_build = 0, sc_commit = 0;
-
-	/* Get SCFW build and commit id */
-	sc_misc_build_info(-1, &sc_build, &sc_commit);
-	if (!sc_build) {
-		printf("SCFW does not support build info\n");
-		sc_commit = 0; /* Display 0 if build info not supported */
-	}
-	printf("Build: SCFW %x\n", sc_commit);
-}
-
 int checkboard(void)
 {
 	puts("Model: Toradex Apalis iMX8\n");
diff --git a/board/toradex/colibri-imx8x/colibri-imx8x.c b/board/toradex/colibri-imx8x/colibri-imx8x.c
index aa8eaa0..8c725b7 100644
--- a/board/toradex/colibri-imx8x/colibri-imx8x.c
+++ b/board/toradex/colibri-imx8x/colibri-imx8x.c
@@ -51,22 +51,12 @@
 	if (err != SC_ERR_NONE)
 		return 0;
 
-	/* Power up UART3 */
-	err = sc_pm_set_resource_power_mode(-1, SC_R_UART_3, SC_PM_PW_MODE_ON);
+	/* Set UART3 clock root to 80 MHz and enable it */
+	rate = SC_80MHZ;
+	err = sc_pm_setup_uart(SC_R_UART_3, rate);
 	if (err != SC_ERR_NONE)
 		return 0;
 
-	/* Set UART3 clock root to 80 MHz */
-	rate = 80000000;
-	err = sc_pm_set_clock_rate(-1, SC_R_UART_3, SC_PM_CLK_PER, &rate);
-	if (err != SC_ERR_NONE)
-		return 0;
-
-	/* Enable UART3 clock root */
-	err = sc_pm_clock_enable(-1, SC_R_UART_3, SC_PM_CLK_PER, true, false);
-	if (err != SC_ERR_NONE)
-		return 0;
-
 	setup_iomux_uart();
 
 	return 0;
@@ -93,19 +83,6 @@
 }
 #endif
 
-void build_info(void)
-{
-	u32 sc_build = 0, sc_commit = 0;
-
-	/* Get SCFW build and commit id */
-	sc_misc_build_info(-1, &sc_build, &sc_commit);
-	if (!sc_build) {
-		printf("SCFW does not support build info\n");
-		sc_commit = 0; /* Display 0 if build info not supported */
-	}
-	printf("Build: SCFW %x\n", sc_commit);
-}
-
 int checkboard(void)
 {
 	puts("Model: Toradex Colibri iMX8X\n");
diff --git a/board/toradex/common/tdx-cfg-block.c b/board/toradex/common/tdx-cfg-block.c
index f69c443..c19d761 100644
--- a/board/toradex/common/tdx-cfg-block.c
+++ b/board/toradex/common/tdx-cfg-block.c
@@ -7,8 +7,9 @@
 #include "tdx-cfg-block.h"
 
 #if defined(CONFIG_TARGET_APALIS_IMX6) || \
+	defined(CONFIG_TARGET_APALIS_IMX8) || \
 	defined(CONFIG_TARGET_COLIBRI_IMX6) || \
-	defined(CONFIG_TARGET_COLIBRI_IMX8QXP)
+	defined(CONFIG_TARGET_COLIBRI_IMX8X)
 #include <asm/arch/sys_proto.h>
 #else
 #define is_cpu_type(cpu) (0)
@@ -129,6 +130,10 @@
 		ret = -ENODEV;
 		goto out;
 	}
+	if (mmc_init(mmc)) {
+		puts("MMC init failed\n");
+		return -EINVAL;
+	}
 	if (part != mmc_get_blk_desc(mmc)->hwpart) {
 		if (blk_select_hwpart_devnum(IF_TYPE_MMC, dev, part)) {
 			puts("MMC partition switch failed\n");
@@ -287,6 +292,7 @@
 	char message[CONFIG_SYS_CBSIZE];
 	char *soc;
 	char it = 'n';
+	char wb = 'n';
 	int len;
 
 	/* Unknown module by default */
@@ -296,10 +302,17 @@
 		sprintf(message, "Is the module the 312 MHz version? [y/N] ");
 	else
 		sprintf(message, "Is the module an IT version? [y/N] ");
-
 	len = cli_readline(message);
 	it = console_buffer[0];
 
+#if defined(CONFIG_TARGET_APALIS_IMX8) || \
+		defined(CONFIG_TARGET_COLIBRI_IMX6ULL) || \
+		defined(CONFIG_TARGET_COLIBRI_IMX8X)
+	sprintf(message, "Does the module have Wi-Fi / Bluetooth? [y/N] ");
+	len = cli_readline(message);
+	wb = console_buffer[0];
+#endif
+
 	soc = env_get("soc");
 	if (!strcmp("mx6", soc)) {
 #ifdef CONFIG_TARGET_APALIS_IMX6
@@ -327,12 +340,6 @@
 				tdx_hw_tag.prodid = COLIBRI_IMX6S;
 		}
 #elif CONFIG_TARGET_COLIBRI_IMX6ULL
-		char wb = 'n';
-
-		sprintf(message, "Does the module have Wi-Fi / Bluetooth? " \
-				 "[y/N] ");
-		len = cli_readline(message);
-		wb = console_buffer[0];
 		if (it == 'y' || it == 'Y') {
 			if (wb == 'y' || wb == 'Y')
 				tdx_hw_tag.prodid = COLIBRI_IMX6ULL_WIFI_BT_IT;
@@ -349,9 +356,31 @@
 		tdx_hw_tag.prodid = COLIBRI_IMX7D;
 	else if (!strcmp("imx7s", soc))
 		tdx_hw_tag.prodid = COLIBRI_IMX7S;
-	else if (is_cpu_type(MXC_CPU_IMX8QXP))
-		tdx_hw_tag.prodid = COLIBRI_IMX8QXP_WIFI_BT_IT;
-	else if (!strcmp("tegra20", soc)) {
+	else if (is_cpu_type(MXC_CPU_IMX8QM)) {
+		if (it == 'y' || it == 'Y') {
+			if (wb == 'y' || wb == 'Y')
+				tdx_hw_tag.prodid = APALIS_IMX8QM_WIFI_BT_IT;
+			else
+				tdx_hw_tag.prodid = APALIS_IMX8QM_IT;
+		} else {
+			if (wb == 'y' || wb == 'Y')
+				tdx_hw_tag.prodid = APALIS_IMX8QP_WIFI_BT;
+			else
+				tdx_hw_tag.prodid = APALIS_IMX8QP;
+		}
+	} else if (is_cpu_type(MXC_CPU_IMX8QXP)) {
+		if (it == 'y' || it == 'Y') {
+			if (wb == 'y' || wb == 'Y')
+				tdx_hw_tag.prodid = COLIBRI_IMX8QXP_WIFI_BT_IT;
+			else
+				tdx_hw_tag.prodid = COLIBRI_IMX8QXP_IT;
+		} else {
+			if (wb == 'y' || wb == 'Y')
+				tdx_hw_tag.prodid = COLIBRI_IMX8DX_WIFI_BT;
+			else
+				tdx_hw_tag.prodid = COLIBRI_IMX8DX;
+		}
+	} else if (!strcmp("tegra20", soc)) {
 		if (it == 'y' || it == 'Y')
 			if (gd->ram_size == 0x10000000)
 				tdx_hw_tag.prodid = COLIBRI_T20_256MB_IT;
@@ -482,8 +511,7 @@
 		 * On NAND devices, recreation is only allowed if the page is
 		 * empty (config block invalid...)
 		 */
-		printf("NAND erase block %d need to be erased before creating" \
-		       " a Toradex config block\n",
+		printf("NAND erase block %d need to be erased before creating a Toradex config block\n",
 		       CONFIG_TDX_CFG_BLOCK_OFFSET /
 		       get_nand_dev_by_index(0)->erasesize);
 		goto out;
@@ -492,8 +520,7 @@
 		 * On NOR devices, recreation is only allowed if the sector is
 		 * empty and write protection is off (config block invalid...)
 		 */
-		printf("NOR sector at offset 0x%02x need to be erased and " \
-		       "unprotected before creating a Toradex config block\n",
+		printf("NOR sector at offset 0x%02x need to be erased and unprotected before creating a Toradex config block\n",
 		       CONFIG_TDX_CFG_BLOCK_OFFSET);
 		goto out;
 #else
@@ -604,9 +631,8 @@
 	return CMD_RET_USAGE;
 }
 
-U_BOOT_CMD(
-	cfgblock, 4, 0, do_cfgblock,
-	"Toradex config block handling commands",
-	"create [-y] [barcode] - (Re-)create Toradex config block\n"
-	"cfgblock reload - Reload Toradex config block from flash"
+U_BOOT_CMD(cfgblock, 4, 0, do_cfgblock,
+	   "Toradex config block handling commands",
+	   "create [-y] [barcode] - (Re-)create Toradex config block\n"
+	   "cfgblock reload - Reload Toradex config block from flash"
 );
diff --git a/cmd/Kconfig b/cmd/Kconfig
index 9e66cc1..16cb5c2 100644
--- a/cmd/Kconfig
+++ b/cmd/Kconfig
@@ -325,8 +325,8 @@
 	  command.
 
 config CMD_SPL_NAND_OFS
-	hex "Offset of OS command line args for Falcon-mode NAND boot"
-	depends on CMD_SPL
+	hex "Offset of OS args or dtb for Falcon-mode NAND boot"
+	depends on CMD_SPL && (TPL_NAND_SUPPORT || SPL_NAND_SUPPORT)
 	default 0
 	help
 	  This provides the offset of the command line arguments for Linux
@@ -334,6 +334,14 @@
 	  for full information about how to use this option (and also see
 	  board/gateworks/gw_ventana/README for an example).
 
+config CMD_SPL_NOR_OFS
+	hex "Offset of OS args or dtb for Falcon-mode NOR boot"
+	depends on CMD_SPL && SPL_NOR_SUPPORT
+	default 0
+	help
+	  This provides the offset of the command line arguments or dtb for
+	  Linux when booting from NOR in Falcon mode.
+
 config CMD_SPL_WRITE_SIZE
 	hex "Size of argument area"
 	depends on CMD_SPL
diff --git a/cmd/eeprom.c b/cmd/eeprom.c
index 7b1f814..19953df 100644
--- a/cmd/eeprom.c
+++ b/cmd/eeprom.c
@@ -108,7 +108,7 @@
 
 	/*
 	 * For a FRAM device there is no limit on the number of the
-	 * bytes that can be ccessed with the single read or write
+	 * bytes that can be accessed with the single read or write
 	 * operation.
 	 */
 #if !defined(CONFIG_SYS_I2C_FRAM)
diff --git a/common/board_r.c b/common/board_r.c
index abc31b1..ee4dced 100644
--- a/common/board_r.c
+++ b/common/board_r.c
@@ -700,7 +700,7 @@
 	stdio_init_tables,
 	initr_serial,
 	initr_announce,
-#if defined(CONFIG_WDT)
+#if CONFIG_IS_ENABLED(WDT)
 	initr_watchdog,
 #endif
 	INIT_FUNC_WATCHDOG_RESET
diff --git a/common/spl/Kconfig b/common/spl/Kconfig
index 5d6da5d..54154b9 100644
--- a/common/spl/Kconfig
+++ b/common/spl/Kconfig
@@ -1075,6 +1075,7 @@
 
 config SPL_WATCHDOG_SUPPORT
 	bool "Support watchdog drivers"
+	imply SPL_WDT if !HW_WATCHDOG
 	help
 	  Enable support for watchdog drivers in SPL. A watchdog is
 	  typically a hardware peripheral which can reset the system when it
diff --git a/common/spl/spl.c b/common/spl/spl.c
index d5e3f68..c182705 100644
--- a/common/spl/spl.c
+++ b/common/spl/spl.c
@@ -603,7 +603,7 @@
 	spl_board_init();
 #endif
 
-#if defined(CONFIG_SPL_WATCHDOG_SUPPORT) && defined(CONFIG_WDT)
+#if defined(CONFIG_SPL_WATCHDOG_SUPPORT) && CONFIG_IS_ENABLED(WDT)
 	initr_watchdog();
 #endif
 
diff --git a/configs/apalis_imx6_defconfig b/configs/apalis_imx6_defconfig
index cad3f1a..b76c4c1 100644
--- a/configs/apalis_imx6_defconfig
+++ b/configs/apalis_imx6_defconfig
@@ -37,7 +37,6 @@
 CONFIG_CRC32_VERIFY=y
 CONFIG_CMD_MEMTEST=y
 CONFIG_SYS_ALT_MEMTEST=y
-CONFIG_CMD_DFU=y
 CONFIG_CMD_GPIO=y
 CONFIG_CMD_GPT=y
 CONFIG_CMD_I2C=y
@@ -56,7 +55,6 @@
 CONFIG_IP_DEFRAG=y
 CONFIG_TFTP_BLOCKSIZE=4096
 CONFIG_DWC_AHSATA=y
-CONFIG_DFU_MMC=y
 CONFIG_DM_GPIO=y
 CONFIG_DM_I2C=y
 CONFIG_DM_MMC=y
diff --git a/configs/aristainetos2_defconfig b/configs/aristainetos2_defconfig
index 49dd9bb..33e40cd 100644
--- a/configs/aristainetos2_defconfig
+++ b/configs/aristainetos2_defconfig
@@ -50,6 +50,7 @@
 CONFIG_PHY_MICREL=y
 CONFIG_PHY_MICREL_KSZ90X1=y
 CONFIG_MII=y
+CONFIG_PWM_IMX=y
 CONFIG_SPI=y
 CONFIG_MXC_SPI=y
 CONFIG_USB=y
diff --git a/configs/aristainetos2b_defconfig b/configs/aristainetos2b_defconfig
index 06c05f7..34a6cde 100644
--- a/configs/aristainetos2b_defconfig
+++ b/configs/aristainetos2b_defconfig
@@ -48,6 +48,7 @@
 CONFIG_PHY_MICREL=y
 CONFIG_PHY_MICREL_KSZ90X1=y
 CONFIG_MII=y
+CONFIG_PWM_IMX=y
 CONFIG_SPI=y
 CONFIG_MXC_SPI=y
 CONFIG_USB=y
diff --git a/configs/aristainetos_defconfig b/configs/aristainetos_defconfig
index e645055..cb361da 100644
--- a/configs/aristainetos_defconfig
+++ b/configs/aristainetos_defconfig
@@ -49,6 +49,7 @@
 CONFIG_PHY_MICREL=y
 CONFIG_PHY_MICREL_KSZ8XXX=y
 CONFIG_MII=y
+CONFIG_PWM_IMX=y
 CONFIG_SPI=y
 CONFIG_MXC_SPI=y
 CONFIG_USB=y
diff --git a/configs/colibri-imx6ull_defconfig b/configs/colibri-imx6ull_defconfig
index c28a167..2b57b5e 100644
--- a/configs/colibri-imx6ull_defconfig
+++ b/configs/colibri-imx6ull_defconfig
@@ -47,7 +47,6 @@
 CONFIG_ENV_VARS_UBOOT_RUNTIME_CONFIG=y
 CONFIG_IP_DEFRAG=y
 CONFIG_TFTP_BLOCKSIZE=16352
-CONFIG_DFU_MMC=y
 CONFIG_DFU_NAND=y
 CONFIG_DM_GPIO=y
 CONFIG_DM_I2C=y
diff --git a/configs/colibri_imx6_defconfig b/configs/colibri_imx6_defconfig
index b343178..f792a9e 100644
--- a/configs/colibri_imx6_defconfig
+++ b/configs/colibri_imx6_defconfig
@@ -36,7 +36,6 @@
 CONFIG_CRC32_VERIFY=y
 CONFIG_CMD_MEMTEST=y
 CONFIG_SYS_ALT_MEMTEST=y
-CONFIG_CMD_DFU=y
 CONFIG_CMD_GPIO=y
 CONFIG_CMD_GPT=y
 CONFIG_CMD_I2C=y
@@ -55,7 +54,6 @@
 CONFIG_ENV_VARS_UBOOT_RUNTIME_CONFIG=y
 CONFIG_IP_DEFRAG=y
 CONFIG_TFTP_BLOCKSIZE=16352
-CONFIG_DFU_MMC=y
 CONFIG_DM_GPIO=y
 CONFIG_DM_I2C=y
 CONFIG_DM_MMC=y
diff --git a/configs/colibri_imx7_emmc_defconfig b/configs/colibri_imx7_emmc_defconfig
index aaab4c8..0c3a898 100644
--- a/configs/colibri_imx7_emmc_defconfig
+++ b/configs/colibri_imx7_emmc_defconfig
@@ -24,10 +24,9 @@
 CONFIG_CMD_ASKENV=y
 CONFIG_CRC32_VERIFY=y
 CONFIG_CMD_MEMTEST=y
-CONFIG_CMD_DFU=y
 CONFIG_CMD_GPIO=y
 CONFIG_CMD_GPT=y
-# CONFIG_RANDOM_UUID is not set
+CONFIG_RANDOM_UUID=y
 CONFIG_CMD_I2C=y
 CONFIG_CMD_MMC=y
 CONFIG_CMD_USB=y
@@ -43,13 +42,13 @@
 CONFIG_IP_DEFRAG=y
 CONFIG_TFTP_BLOCKSIZE=16352
 CONFIG_FSL_CAAM=y
-CONFIG_DFU_MMC=y
 CONFIG_USB_FUNCTION_FASTBOOT=y
 CONFIG_FASTBOOT_BUF_ADDR=0x82000000
 CONFIG_FASTBOOT_BUF_SIZE=0x10000000
 CONFIG_FASTBOOT_FLASH=y
 CONFIG_FASTBOOT_FLASH_MMC_DEV=0
 CONFIG_FASTBOOT_CMD_OEM_FORMAT=y
+CONFIG_ARMV7_BOOT_SEC_DEFAULT=y
 CONFIG_DM_GPIO=y
 CONFIG_DM_I2C=y
 CONFIG_DM_MMC=y
diff --git a/configs/dh_imx6_defconfig b/configs/dh_imx6_defconfig
index 3b24dd3..3022a187 100644
--- a/configs/dh_imx6_defconfig
+++ b/configs/dh_imx6_defconfig
@@ -16,13 +16,13 @@
 CONFIG_DISTRO_DEFAULTS=y
 # CONFIG_SYS_MALLOC_F is not set
 CONFIG_FIT=y
+CONFIG_SPL_FIT=y
 CONFIG_SYS_EXTRA_OPTIONS="IMX_CONFIG=arch/arm/mach-imx/spl_sd.cfg"
 CONFIG_BOOTDELAY=3
 # CONFIG_USE_BOOTCOMMAND is not set
 CONFIG_SYS_CONSOLE_OVERWRITE_ROUTINE=y
 CONFIG_BOUNCE_BUFFER=y
 CONFIG_SPL_TEXT_BASE=0x00908000
-CONFIG_SPL_I2C_SUPPORT=y
 CONFIG_SPL_SPI_LOAD=y
 CONFIG_SPL_WATCHDOG_SUPPORT=y
 CONFIG_CMD_MEMTEST=y
@@ -41,10 +41,16 @@
 CONFIG_CMD_EXT4_WRITE=y
 CONFIG_OF_CONTROL=y
 CONFIG_DEFAULT_DEVICE_TREE="imx6q-dhcom-pdk2"
+CONFIG_OF_LIST="imx6q-dhcom-pdk2 imx6dl-dhcom-pdk2"
+CONFIG_MULTI_DTB_FIT=y
 CONFIG_ENV_IS_IN_SPI_FLASH=y
 CONFIG_DWC_AHSATA=y
 CONFIG_BOOTCOUNT_LIMIT=y
 CONFIG_DM_GPIO=y
+CONFIG_DM_I2C=y
+CONFIG_SYS_I2C_MXC=y
+CONFIG_MISC=y
+CONFIG_I2C_EEPROM=y
 CONFIG_DM_MMC=y
 CONFIG_FSL_ESDHC_IMX=y
 CONFIG_DM_SPI_FLASH=y
@@ -64,6 +70,8 @@
 CONFIG_MII=y
 CONFIG_PINCTRL=y
 CONFIG_PINCTRL_IMX6=y
+CONFIG_DM_REGULATOR=y
+CONFIG_DM_REGULATOR_FIXED=y
 CONFIG_DM_SCSI=y
 CONFIG_SPI=y
 CONFIG_DM_SPI=y
diff --git a/configs/display5_defconfig b/configs/display5_defconfig
index 938414c..2275ee7 100644
--- a/configs/display5_defconfig
+++ b/configs/display5_defconfig
@@ -4,16 +4,19 @@
 CONFIG_SPL_GPIO_SUPPORT=y
 CONFIG_SPL_LIBCOMMON_SUPPORT=y
 CONFIG_SPL_LIBGENERIC_SUPPORT=y
+CONFIG_SYS_MALLOC_F_LEN=0x1000
 CONFIG_MX6_DDRCAL=y
 CONFIG_TARGET_DISPLAY5=y
 CONFIG_SPL_MMC_SUPPORT=y
 CONFIG_SPL_SERIAL_SUPPORT=y
+CONFIG_SPL_SYS_MALLOC_F_LEN=0x400
 CONFIG_NR_DRAM_BANKS=1
 CONFIG_SPL=y
 CONFIG_SYS_BOOTCOUNT_SINGLEWORD=y
 CONFIG_SYS_BOOTCOUNT_ADDR=0x020CC068
 CONFIG_SPL_SPI_FLASH_SUPPORT=y
 CONFIG_SPL_SPI_SUPPORT=y
+CONFIG_TPL_SYS_MALLOC_F_LEN=0x400
 CONFIG_FIT=y
 CONFIG_SPL_LOAD_FIT=y
 CONFIG_OF_BOARD_SETUP=y
diff --git a/configs/dms-ba16-1g_defconfig b/configs/dms-ba16-1g_defconfig
index 4231adb..91b6a74 100644
--- a/configs/dms-ba16-1g_defconfig
+++ b/configs/dms-ba16-1g_defconfig
@@ -41,6 +41,7 @@
 CONFIG_SPI_FLASH_WINBOND=y
 CONFIG_PHYLIB=y
 CONFIG_MII=y
+CONFIG_PWM_IMX=y
 CONFIG_SPI=y
 CONFIG_MXC_SPI=y
 CONFIG_USB=y
diff --git a/configs/dms-ba16_defconfig b/configs/dms-ba16_defconfig
index f98088d..fbf1f89 100644
--- a/configs/dms-ba16_defconfig
+++ b/configs/dms-ba16_defconfig
@@ -40,6 +40,7 @@
 CONFIG_SPI_FLASH_WINBOND=y
 CONFIG_PHYLIB=y
 CONFIG_MII=y
+CONFIG_PWM_IMX=y
 CONFIG_SPI=y
 CONFIG_MXC_SPI=y
 CONFIG_USB=y
diff --git a/configs/ge_bx50v3_defconfig b/configs/ge_bx50v3_defconfig
index 60bdcd6..54197f7 100644
--- a/configs/ge_bx50v3_defconfig
+++ b/configs/ge_bx50v3_defconfig
@@ -55,6 +55,7 @@
 CONFIG_MII=y
 CONFIG_PINCTRL=y
 CONFIG_PINCTRL_IMX6=y
+CONFIG_PWM_IMX=y
 CONFIG_SPI=y
 CONFIG_DM_SPI=y
 CONFIG_MXC_SPI=y
diff --git a/configs/imx6q_logic_defconfig b/configs/imx6q_logic_defconfig
index cf6964b..b95c978 100644
--- a/configs/imx6q_logic_defconfig
+++ b/configs/imx6q_logic_defconfig
@@ -4,6 +4,7 @@
 CONFIG_SPL_GPIO_SUPPORT=y
 CONFIG_SPL_LIBCOMMON_SUPPORT=y
 CONFIG_SPL_LIBGENERIC_SUPPORT=y
+CONFIG_SYS_MALLOC_F_LEN=0x2000
 CONFIG_TARGET_MX6LOGICPD=y
 CONFIG_SPL_MMC_SUPPORT=y
 CONFIG_SPL_SERIAL_SUPPORT=y
@@ -54,12 +55,16 @@
 CONFIG_MTDIDS_DEFAULT="nand0=gpmi-nand"
 CONFIG_MTDPARTS_DEFAULT="mtdparts=gpmi-nand:2m(spl),2m(uboot),1m(env),16m(kernel),1m(dtb),-(fs)"
 CONFIG_CMD_UBI=y
+CONFIG_SPL_OF_CONTROL=y
 CONFIG_DEFAULT_DEVICE_TREE="imx6q-logicpd"
 CONFIG_ENV_IS_IN_FAT=y
 CONFIG_ENV_IS_IN_NAND=y
 CONFIG_ENV_FAT_INTERFACE="mmc"
 CONFIG_ENV_FAT_DEVICE_AND_PART="0:1"
 CONFIG_ENV_VARS_UBOOT_RUNTIME_CONFIG=y
+CONFIG_SPL_DM=y
+CONFIG_SPL_DM_SEQ_ALIAS=y
+CONFIG_SPL_OF_TRANSLATE=y
 CONFIG_PCF8575_GPIO=y
 CONFIG_LED=y
 CONFIG_LED_GPIO=y
@@ -82,6 +87,7 @@
 CONFIG_MXC_UART=y
 CONFIG_USB=y
 CONFIG_DM_USB=y
+# CONFIG_SPL_DM_USB is not set
 CONFIG_USB_GADGET=y
 CONFIG_USB_GADGET_MANUFACTURER="FSL"
 CONFIG_USB_GADGET_VENDOR_NUM=0x0525
diff --git a/configs/imx6qdl_icore_mmc_defconfig b/configs/imx6qdl_icore_mmc_defconfig
index b15c547..353582a 100644
--- a/configs/imx6qdl_icore_mmc_defconfig
+++ b/configs/imx6qdl_icore_mmc_defconfig
@@ -14,6 +14,7 @@
 CONFIG_DEBUG_UART_CLOCK=24000000
 CONFIG_SPL_LIBDISK_SUPPORT=y
 # CONFIG_CMD_BMODE is not set
+CONFIG_CMD_NANDBCB=y
 CONFIG_DEBUG_UART=y
 CONFIG_FIT=y
 CONFIG_FIT_SIGNATURE=y
diff --git a/configs/imx6qdl_icore_nand_defconfig b/configs/imx6qdl_icore_nand_defconfig
index 4ea0803..4672563 100644
--- a/configs/imx6qdl_icore_nand_defconfig
+++ b/configs/imx6qdl_icore_nand_defconfig
@@ -8,6 +8,7 @@
 CONFIG_SPL_SERIAL_SUPPORT=y
 CONFIG_NR_DRAM_BANKS=1
 CONFIG_SPL=y
+CONFIG_SYS_MALLOC_F_LEN=0x2000
 # CONFIG_CMD_BMODE is not set
 CONFIG_FIT=y
 CONFIG_FIT_SIGNATURE=y
diff --git a/configs/imx8qxp_mek_defconfig b/configs/imx8qxp_mek_defconfig
index 39e5f5e..cf83a67 100644
--- a/configs/imx8qxp_mek_defconfig
+++ b/configs/imx8qxp_mek_defconfig
@@ -78,5 +78,7 @@
 CONFIG_SPL_DM_REGULATOR_GPIO=y
 CONFIG_DM_SERIAL=y
 CONFIG_FSL_LPUART=y
+CONFIG_DM_THERMAL=y
+CONFIG_IMX_SCU_THERMAL=y
 CONFIG_SPL_TINY_MEMSET=y
 # CONFIG_EFI_LOADER is not set
diff --git a/configs/kp_imx53_defconfig b/configs/kp_imx53_defconfig
index 86d6727..ea6f8f6 100644
--- a/configs/kp_imx53_defconfig
+++ b/configs/kp_imx53_defconfig
@@ -47,3 +47,5 @@
 CONFIG_USB=y
 CONFIG_USB_EHCI_MX5=y
 CONFIG_USB_STORAGE=y
+CONFIG_HEXDUMP=y
+# CONFIG_EFI_LOADER is not set
diff --git a/configs/m53menlo_defconfig b/configs/m53menlo_defconfig
index 3a5fa26..c551ea2 100644
--- a/configs/m53menlo_defconfig
+++ b/configs/m53menlo_defconfig
@@ -72,6 +72,8 @@
 CONFIG_DM_REGULATOR_FIXED=y
 CONFIG_DM_REGULATOR_GPIO=y
 CONFIG_RTC_M41T62=y
+CONFIG_SYSRESET=y
+CONFIG_SYSRESET_WATCHDOG=y
 CONFIG_USB=y
 CONFIG_DM_USB=y
 CONFIG_USB_EHCI_MX5=y
diff --git a/configs/mccmon6_nor_defconfig b/configs/mccmon6_nor_defconfig
index 7816200..cd78c5c 100644
--- a/configs/mccmon6_nor_defconfig
+++ b/configs/mccmon6_nor_defconfig
@@ -20,7 +20,6 @@
 CONFIG_CMD_I2C=y
 CONFIG_CMD_MMC=y
 CONFIG_CMD_SF=y
-CONFIG_CMD_USB=y
 CONFIG_CMD_CACHE=y
 CONFIG_CMD_EXT4_WRITE=y
 CONFIG_CMD_MTDPARTS=y
@@ -50,5 +49,4 @@
 CONFIG_SPI=y
 CONFIG_MXC_SPI=y
 CONFIG_DM_THERMAL=y
-CONFIG_USB=y
 CONFIG_OF_LIBFDT=y
diff --git a/configs/mccmon6_sd_defconfig b/configs/mccmon6_sd_defconfig
index 522207a..1794786 100644
--- a/configs/mccmon6_sd_defconfig
+++ b/configs/mccmon6_sd_defconfig
@@ -21,7 +21,6 @@
 CONFIG_CMD_I2C=y
 CONFIG_CMD_MMC=y
 CONFIG_CMD_SF=y
-CONFIG_CMD_USB=y
 CONFIG_CMD_CACHE=y
 CONFIG_CMD_EXT4_WRITE=y
 CONFIG_CMD_MTDPARTS=y
@@ -51,5 +50,4 @@
 CONFIG_SPI=y
 CONFIG_MXC_SPI=y
 CONFIG_DM_THERMAL=y
-CONFIG_USB=y
 CONFIG_OF_LIBFDT=y
diff --git a/configs/mt7629_rfb_defconfig b/configs/mt7629_rfb_defconfig
index d6a7c84..c0a586f 100644
--- a/configs/mt7629_rfb_defconfig
+++ b/configs/mt7629_rfb_defconfig
@@ -64,7 +64,7 @@
 CONFIG_MTK_SERIAL=y
 CONFIG_SPI=y
 CONFIG_DM_SPI=y
-CONFIG_MTK_QSPI=y
+CONFIG_MTK_SNFI_SPI=y
 CONFIG_SYSRESET=y
 CONFIG_SPL_SYSRESET=y
 CONFIG_SYSRESET_WATCHDOG=y
diff --git a/configs/mx53ppd_defconfig b/configs/mx53ppd_defconfig
index a88af15..cad798a 100644
--- a/configs/mx53ppd_defconfig
+++ b/configs/mx53ppd_defconfig
@@ -43,6 +43,7 @@
 CONFIG_MII=y
 CONFIG_PINCTRL=y
 CONFIG_PINCTRL_IMX5=y
+CONFIG_PWM_IMX=y
 CONFIG_RTC_S35392A=y
 CONFIG_USB=y
 CONFIG_USB_EHCI_MX5=y
diff --git a/configs/pico-hobbit-imx7d_defconfig b/configs/pico-hobbit-imx7d_defconfig
index bc34e99..263f8f2 100644
--- a/configs/pico-hobbit-imx7d_defconfig
+++ b/configs/pico-hobbit-imx7d_defconfig
@@ -51,6 +51,7 @@
 CONFIG_FASTBOOT_CMD_OEM_FORMAT=y
 CONFIG_DM_GPIO=y
 CONFIG_DM_MMC=y
+CONFIG_DM_USB=y
 CONFIG_SUPPORT_EMMC_BOOT=y
 CONFIG_FSL_ESDHC_IMX=y
 CONFIG_PHYLIB=y
diff --git a/configs/pico-imx7d_bl33_defconfig b/configs/pico-imx7d_bl33_defconfig
index b609b6d..7c559cf 100644
--- a/configs/pico-imx7d_bl33_defconfig
+++ b/configs/pico-imx7d_bl33_defconfig
@@ -43,6 +43,7 @@
 CONFIG_DFU_MMC=y
 CONFIG_DM_GPIO=y
 CONFIG_DM_MMC=y
+CONFIG_DM_USB=y
 CONFIG_FSL_ESDHC_IMX=y
 CONFIG_PHYLIB=y
 CONFIG_MII=y
diff --git a/configs/pico-imx7d_defconfig b/configs/pico-imx7d_defconfig
index f23bbf7..09b81e4 100644
--- a/configs/pico-imx7d_defconfig
+++ b/configs/pico-imx7d_defconfig
@@ -51,6 +51,7 @@
 CONFIG_FASTBOOT_CMD_OEM_FORMAT=y
 CONFIG_DM_GPIO=y
 CONFIG_DM_MMC=y
+CONFIG_DM_USB=y
 CONFIG_SUPPORT_EMMC_BOOT=y
 CONFIG_FSL_ESDHC_IMX=y
 CONFIG_PHYLIB=y
diff --git a/configs/pico-pi-imx7d_defconfig b/configs/pico-pi-imx7d_defconfig
index 14c0817..7689242 100644
--- a/configs/pico-pi-imx7d_defconfig
+++ b/configs/pico-pi-imx7d_defconfig
@@ -51,6 +51,7 @@
 CONFIG_FASTBOOT_CMD_OEM_FORMAT=y
 CONFIG_DM_GPIO=y
 CONFIG_DM_MMC=y
+CONFIG_DM_USB=y
 CONFIG_SUPPORT_EMMC_BOOT=y
 CONFIG_FSL_ESDHC_IMX=y
 CONFIG_PHYLIB=y
diff --git a/configs/sandbox_defconfig b/configs/sandbox_defconfig
index 11cc097..62594e3 100644
--- a/configs/sandbox_defconfig
+++ b/configs/sandbox_defconfig
@@ -93,6 +93,7 @@
 CONFIG_DM_BOOTCOUNT=y
 CONFIG_DM_BOOTCOUNT_RTC=y
 CONFIG_CLK=y
+CONFIG_SANDBOX_CLK_CCF=y
 CONFIG_CPU=y
 CONFIG_DM_DEMO=y
 CONFIG_DM_DEMO_SIMPLE=y
diff --git a/configs/sandbox_flattree_defconfig b/configs/sandbox_flattree_defconfig
index af33528..2429ae4 100644
--- a/configs/sandbox_flattree_defconfig
+++ b/configs/sandbox_flattree_defconfig
@@ -66,6 +66,7 @@
 CONFIG_ADC=y
 CONFIG_ADC_SANDBOX=y
 CONFIG_CLK=y
+CONFIG_SANDBOX_CLK_CCF=y
 CONFIG_CPU=y
 CONFIG_DM_DEMO=y
 CONFIG_DM_DEMO_SIMPLE=y
diff --git a/configs/vining_2000_defconfig b/configs/vining_2000_defconfig
index 7364c67..6b9691a 100644
--- a/configs/vining_2000_defconfig
+++ b/configs/vining_2000_defconfig
@@ -45,6 +45,7 @@
 CONFIG_FSL_ESDHC_IMX=y
 CONFIG_PHYLIB=y
 CONFIG_MII=y
+CONFIG_PWM_IMX=y
 CONFIG_PCI=y
 CONFIG_DM_PCI=y
 CONFIG_PINCTRL=y
diff --git a/configs/warp7_bl33_defconfig b/configs/warp7_bl33_defconfig
index 8a4e294..0f28d58 100644
--- a/configs/warp7_bl33_defconfig
+++ b/configs/warp7_bl33_defconfig
@@ -54,4 +54,11 @@
 CONFIG_USB_ETHER=y
 CONFIG_USB_ETH_CDC=y
 CONFIG_USBNET_HOST_ADDR="de:ad:be:af:00:00"
-CONFIG_OPTEE_TZDRAM_SIZE=0x2000000
+CONFIG_OPTEE=y
+CONFIG_OPTEE_TZDRAM_BASE=0x9e000000
+CONFIG_OPTEE_TZDRAM_SIZE=0x02000000
+CONFIG_FIT=y
+CONFIG_FIT_SIGNATURE=y
+CONFIG_FIT_VERBOSE=y
+CONFIG_OF_LIBFDT=y
+CONFIG_OF_LIBFDT_OVERLAY=y
diff --git a/doc/README.falcon b/doc/README.falcon
index 9a7f0bc..713d706 100644
--- a/doc/README.falcon
+++ b/doc/README.falcon
@@ -67,6 +67,8 @@
 
 CONFIG_CMD_SPL_NAND_OFS	Offset in NAND where the parameters area was saved.
 
+CONFIG_CMD_SPL_NOR_OFS	Offset in NOR where the parameters area was saved.
+
 CONFIG_CMD_SPL_WRITE_SIZE 	Size of the parameters area to be copied
 
 CONFIG_SPL_OS_BOOT	Activate Falcon Mode.
diff --git a/doc/imx/clk/ccf.txt b/doc/imx/clk/ccf.txt
new file mode 100644
index 0000000..36b60dc
--- /dev/null
+++ b/doc/imx/clk/ccf.txt
@@ -0,0 +1,101 @@
+Introduction:
+=============
+
+This documentation entry describes the Common Clock Framework [CCF]
+port from Linux kernel (v5.1.12) to U-Boot.
+
+This code is supposed to bring CCF to IMX based devices (imx6q, imx7
+imx8). Moreover, it also provides some common clock code, which would
+allow easy porting of CCF Linux code to other platforms.
+
+Design decisions:
+=================
+
+* U-Boot's driver model [DM] for clk differs from Linux CCF. The most
+  notably difference is the lack of support for hierarchical clocks and
+  "clock as a manager driver" (single clock DTS node acts as a starting
+  point for all other clocks).
+
+* The clk_get_rate() caches the previously read data if CLK_GET_RATE_NOCACHE
+  is not set (no need for recursive access).
+
+* On purpose the "manager" clk driver (clk-imx6q.c) is not using large
+  table to store pointers to clocks - e.g. clk[IMX6QDL_CLK_USDHC2_SEL] = ....
+  Instead we use udevice's linked list for the same class (UCLASS_CLK).
+
+  Rationale:
+  ----------
+    When porting the code as is from Linux, one would need ~1KiB of RAM to
+    store it. This is way too much if we do plan to use this driver in SPL.
+
+* The "central" structure of this patch series is struct udevice and its
+  uclass_priv field contains the struct clk pointer (to the originally created
+  one).
+
+* Up till now U-Boot's driver model (DM) CLK operates on udevice (main
+  access to clock is by udevice ops)
+  In the CCF the access to struct clk (embodying pointer to *dev) is
+  possible via dev_get_clk_ptr() (it is a wrapper on dev_get_uclass_priv()).
+
+* To keep things simple the struct udevice's uclass_priv pointer is used to
+  store back pointer to corresponding struct clk. However, it is possible to
+  modify clk-uclass.c file and add there struct uc_clk_priv, which would have
+  clock related members (like pointer to clk). As of this writing there is no
+  such need, so to avoid extra allocations (as it can be auto allocated by
+  setting .per_device_auto_alloc_size = sizeof(struct uc_clk_priv)) the
+  uclass_priv stores the pointer to struct clk.
+
+* It is advised to add common clock code (like already added rate and flags) to
+  the struct clk, which is a top level description of the clock.
+
+* U-Boot's driver model already provides the facility to automatically allocate
+  (via private_alloc_size) device private data (accessible via dev->priv).
+  It may look appealing to use this feature to allocate private structures for
+  CCF clk devices e.g. divider (struct clk_divider *divider) for IMX6Q clock.
+
+  The above feature had not been used for following reasons:
+  - The original CCF Linux kernel driver is the "manager" for clocks - it
+    decides when clock is instantiated (and when memory for it is allocated).
+
+  - Using it would change the original structure of the CCF code.
+
+  - To bind (via clk_register()) the clock device with U-Boot driver model we
+    first need udevice for it (the "chicken and egg problem").
+
+* I've added the clk_get_parent(), which reads parent's dev->uclass_priv to
+  provide parent's struct clk pointer. This seems the easiest way to get
+  child/parent relationship for struct clk in U-Boot's udevice based clocks.
+
+* Linux's CCF 'struct clk_core' corresponds to U-Boot's udevice in 'struct clk'.
+  Clock IP block agnostic flags from 'struct clk_core' (e.g. NOCACHE) have been
+  moved from this struct one level up to 'struct clk'.
+
+* For tests the new ./test/dm/clk_ccf.c and ./drivers/clk/clk_sandbox_ccf.c
+  files have been introduced. The latter setups the CCF clock structure for
+  sandbox by reusing, if possible, generic clock primitives - like divier
+  and mux. The former file provides code to tests this setup.
+
+  For sandbox new CONFIG_SANDBOX_CLK_CCF Kconfig define has been introduced.
+  All new primitives added for new architectures must have corresponding test
+  in the two aforementioned files.
+
+
+Testing (sandbox):
+==================
+
+make mrproper; make sandbox_defconfig; make -j4
+./u-boot -i -d arch/sandbox/dts/test.dtb
+=> ut dm clk
+
+or in a more "scriptable" way (with -v to print debug output):
+./u-boot --fdt arch/sandbox/dts/test.dtb --command "ut dm clk_ccf" -v
+
+To do:
+------
+
+* Use of OF_PLATDATA in the SPL setup for CCF - as it is now - the SPL grows
+  considerably and using CCF in boards with tiny resources (OCRAM) is
+  problematic.
+
+* On demand port other parts of CCF to U-Boot - as now only features _really_
+  needed by DM/DTS converted drivers are used.
diff --git a/doc/imx/common/imx6.txt b/doc/imx/common/imx6.txt
index eab8835..0b50611 100644
--- a/doc/imx/common/imx6.txt
+++ b/doc/imx/common/imx6.txt
@@ -88,3 +88,77 @@
 
 Word 0x00000002: 9f027772 00000004
 
+NAND Boot on i.MX6 with SPL support
+--------------------------------------
+
+Writing/updating boot image in nand device is not straight forward in
+i.MX6 platform and it requires boot control block(BCB) to be configured.
+
+BCB contains two data structures, Firmware Configuration Block(FCB) and
+Discovered Bad Block Table(DBBT). FCB has nand timings, DBBT search area,
+and firmware. See IMX6DQRM Section 8.5.2.2
+for more information.
+
+We can't use 'nand write' command to write SPL/firmware image directly
+like other platforms does. So we need special setup to write BCB block
+as per IMX6QDL reference manual 'nandbcb update' command do that job.
+
+for nand boot, up on reset bootrom look for FCB structure in
+first block's if FCB found the nand timings are loaded for
+further reads. once FCB read done, DTTB will be loaded and
+finally firmware will be loaded which is boot image.
+
+cmd_nandbcb will create FCB these structures
+by taking mtd partition as an example.
+- initial code will erase entire partition
+- followed by FCB setup, like first 2 blocks for FCB/DBBT write,
+  and next block for FW1/SPL
+- write firmware at FW1 block and
+- finally write fcb/dttb in first 2 block.
+
+Typical NAND BCB layout:
+=======================
+
+   no.of blocks = partition size / erasesize
+   no.of fcb/dbbt blocks = 2
+   FW1 offset = no.of fcb/dbbt
+
+block  0          1          2
+        -------------------------------
+       |FCB/DBBT 0|FCB/DBBT 1|  FW 1  |
+       --------------------------------
+
+On summary, nandbcb update will
+- erase the entire partition
+- create BCB by creating 2 FCB/BDDT block followed by
+  1 FW blocks based on partition size and erasesize.
+- fill FCB/DBBT structures
+- write FW/SPL in FW1
+- write FCB/DBBT in first 2 blocks
+
+step-1: write SPL
+
+icorem6qdl> ext4load mmc 0:1 $loadaddr SPL
+39936 bytes read in 10 ms (3.8 MiB/s)
+
+icorem6qdl> nandbcb update $loadaddr spl $filesize
+device 0 offset 0x0, size 0x9c00
+Erasing at 0x1c0000 -- 100% complete.
+NAND fw write: 0x80000 offset, 0xb000 bytes written: OK
+
+step-2: write u-boot-dtb.img
+
+icorem6qdl> nand erase.part uboot
+
+NAND erase.part: device 0 offset 0x200000, size 0x200000
+Erasing at 0x3c0000 -- 100% complete.
+OK
+
+icorem6qdl> ext4load mmc 0:1 $loadaddr u-boot-dtb.img
+589094 bytes read in 37 ms (15.2 MiB/s)
+
+icorem6qdl> nand write ${loadaddr} uboot ${filesize}
+
+NAND write: device 0 offset 0x200000, size 0x8fd26
+ 589094 bytes written: OK
+icorem6qdl>
diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig
index 7b81eac..5e92446 100644
--- a/drivers/clk/Kconfig
+++ b/drivers/clk/Kconfig
@@ -46,6 +46,20 @@
 	help
 	  Enable this to support the clocks
 
+config SPL_CLK_CCF
+	bool "SPL Common Clock Framework [CCF] support "
+	depends on SPL_CLK_IMX6Q
+	help
+	  Enable this option if you want to (re-)use the Linux kernel's Common
+	  Clock Framework [CCF] code in U-Boot's SPL.
+
+config CLK_CCF
+	bool "Common Clock Framework [CCF] support "
+	depends on CLK_IMX6Q || SANDBOX_CLK_CCF
+	help
+	  Enable this option if you want to (re-)use the Linux kernel's Common
+	  Clock Framework [CCF] code in U-Boot's clock driver.
+
 config CLK_STM32F
 	bool "Enable clock driver support for STM32F family"
 	depends on CLK && (STM32F7 || STM32F4)
@@ -125,4 +139,12 @@
 	help
 	  Support for the clock driver of the MPC83xx series of SoCs.
 
+config SANDBOX_CLK_CCF
+	bool "Sandbox Common Clock Framework [CCF] support "
+	depends on SANDBOX
+	select CLK_CCF
+	help
+	  Enable this option if you want to test the Linux kernel's Common
+	  Clock Framework [CCF] code in U-Boot's Sandbox clock driver.
+
 endmenu
diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
index f0ced49..b7fec60 100644
--- a/drivers/clk/Makefile
+++ b/drivers/clk/Makefile
@@ -7,6 +7,8 @@
 obj-$(CONFIG_$(SPL_TPL_)CLK) += clk-uclass.o
 obj-$(CONFIG_$(SPL_TPL_)CLK) += clk_fixed_rate.o
 obj-$(CONFIG_$(SPL_TPL_)CLK) += clk_fixed_factor.o
+obj-$(CONFIG_$(SPL_TPL_)CLK_CCF) += clk.o clk-divider.o clk-mux.o
+obj-$(CONFIG_$(SPL_TPL_)CLK_CCF) += clk-fixed-factor.o
 
 obj-y += analogbits/
 obj-y += imx/
@@ -37,5 +39,6 @@
 obj-$(CONFIG_MACH_PIC32) += clk_pic32.o
 obj-$(CONFIG_SANDBOX) += clk_sandbox.o
 obj-$(CONFIG_SANDBOX) += clk_sandbox_test.o
+obj-$(CONFIG_SANDBOX_CLK_CCF) += clk_sandbox_ccf.o
 obj-$(CONFIG_STM32H7) += clk_stm32h7.o
 obj-$(CONFIG_CLK_TI_SCI) += clk-ti-sci.o
diff --git a/drivers/clk/clk-divider.c b/drivers/clk/clk-divider.c
new file mode 100644
index 0000000..6921c76
--- /dev/null
+++ b/drivers/clk/clk-divider.c
@@ -0,0 +1,155 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2019 DENX Software Engineering
+ * Lukasz Majewski, DENX Software Engineering, lukma@denx.de
+ *
+ * Copyright (C) 2011 Sascha Hauer, Pengutronix <s.hauer@pengutronix.de>
+ * Copyright (C) 2011 Richard Zhao, Linaro <richard.zhao@linaro.org>
+ * Copyright (C) 2011-2012 Mike Turquette, Linaro Ltd <mturquette@linaro.org>
+ *
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <malloc.h>
+#include <clk-uclass.h>
+#include <dm/device.h>
+#include <dm/uclass.h>
+#include <dm/lists.h>
+#include <dm/device-internal.h>
+#include <linux/clk-provider.h>
+#include <div64.h>
+#include <clk.h>
+#include "clk.h"
+
+#define UBOOT_DM_CLK_CCF_DIVIDER "ccf_clk_divider"
+
+static unsigned int _get_table_div(const struct clk_div_table *table,
+				   unsigned int val)
+{
+	const struct clk_div_table *clkt;
+
+	for (clkt = table; clkt->div; clkt++)
+		if (clkt->val == val)
+			return clkt->div;
+	return 0;
+}
+
+static unsigned int _get_div(const struct clk_div_table *table,
+			     unsigned int val, unsigned long flags, u8 width)
+{
+	if (flags & CLK_DIVIDER_ONE_BASED)
+		return val;
+	if (flags & CLK_DIVIDER_POWER_OF_TWO)
+		return 1 << val;
+	if (flags & CLK_DIVIDER_MAX_AT_ZERO)
+		return val ? val : clk_div_mask(width) + 1;
+	if (table)
+		return _get_table_div(table, val);
+	return val + 1;
+}
+
+unsigned long divider_recalc_rate(struct clk *hw, unsigned long parent_rate,
+				  unsigned int val,
+				  const struct clk_div_table *table,
+				  unsigned long flags, unsigned long width)
+{
+	unsigned int div;
+
+	div = _get_div(table, val, flags, width);
+	if (!div) {
+		WARN(!(flags & CLK_DIVIDER_ALLOW_ZERO),
+		     "%s: Zero divisor and CLK_DIVIDER_ALLOW_ZERO not set\n",
+		     clk_hw_get_name(hw));
+		return parent_rate;
+	}
+
+	return DIV_ROUND_UP_ULL((u64)parent_rate, div);
+}
+
+static ulong clk_divider_recalc_rate(struct clk *clk)
+{
+	struct clk_divider *divider =
+		to_clk_divider(dev_get_clk_ptr(clk->dev));
+	unsigned long parent_rate = clk_get_parent_rate(clk);
+	unsigned int val;
+
+#if CONFIG_IS_ENABLED(SANDBOX_CLK_CCF)
+	val = divider->io_divider_val;
+#else
+	val = readl(divider->reg);
+#endif
+	val >>= divider->shift;
+	val &= clk_div_mask(divider->width);
+
+	return divider_recalc_rate(clk, parent_rate, val, divider->table,
+				   divider->flags, divider->width);
+}
+
+const struct clk_ops clk_divider_ops = {
+	.get_rate = clk_divider_recalc_rate,
+};
+
+static struct clk *_register_divider(struct device *dev, const char *name,
+		const char *parent_name, unsigned long flags,
+		void __iomem *reg, u8 shift, u8 width,
+		u8 clk_divider_flags, const struct clk_div_table *table)
+{
+	struct clk_divider *div;
+	struct clk *clk;
+	int ret;
+
+	if (clk_divider_flags & CLK_DIVIDER_HIWORD_MASK) {
+		if (width + shift > 16) {
+			pr_warn("divider value exceeds LOWORD field\n");
+			return ERR_PTR(-EINVAL);
+		}
+	}
+
+	/* allocate the divider */
+	div = kzalloc(sizeof(*div), GFP_KERNEL);
+	if (!div)
+		return ERR_PTR(-ENOMEM);
+
+	/* struct clk_divider assignments */
+	div->reg = reg;
+	div->shift = shift;
+	div->width = width;
+	div->flags = clk_divider_flags;
+	div->table = table;
+#if CONFIG_IS_ENABLED(SANDBOX_CLK_CCF)
+	div->io_divider_val = *(u32 *)reg;
+#endif
+
+	/* register the clock */
+	clk = &div->clk;
+
+	ret = clk_register(clk, UBOOT_DM_CLK_CCF_DIVIDER, name, parent_name);
+	if (ret) {
+		kfree(div);
+		return ERR_PTR(ret);
+	}
+
+	return clk;
+}
+
+struct clk *clk_register_divider(struct device *dev, const char *name,
+		const char *parent_name, unsigned long flags,
+		void __iomem *reg, u8 shift, u8 width,
+		u8 clk_divider_flags)
+{
+	struct clk *clk;
+
+	clk =  _register_divider(dev, name, parent_name, flags, reg, shift,
+				 width, clk_divider_flags, NULL);
+	if (IS_ERR(clk))
+		return ERR_CAST(clk);
+	return clk;
+}
+
+U_BOOT_DRIVER(ccf_clk_divider) = {
+	.name	= UBOOT_DM_CLK_CCF_DIVIDER,
+	.id	= UCLASS_CLK,
+	.ops	= &clk_divider_ops,
+	.flags = DM_FLAG_PRE_RELOC,
+};
diff --git a/drivers/clk/clk-fixed-factor.c b/drivers/clk/clk-fixed-factor.c
new file mode 100644
index 0000000..711b058
--- /dev/null
+++ b/drivers/clk/clk-fixed-factor.c
@@ -0,0 +1,80 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2019 DENX Software Engineering
+ * Lukasz Majewski, DENX Software Engineering, lukma@denx.de
+ *
+ * Copyright (C) 2011 Sascha Hauer, Pengutronix <s.hauer@pengutronix.de>
+ */
+#include <common.h>
+#include <malloc.h>
+#include <clk-uclass.h>
+#include <dm/device.h>
+#include <linux/clk-provider.h>
+#include <div64.h>
+#include <clk.h>
+#include "clk.h"
+
+#define UBOOT_DM_CLK_IMX_FIXED_FACTOR "ccf_clk_fixed_factor"
+
+static ulong clk_factor_recalc_rate(struct clk *clk)
+{
+	struct clk_fixed_factor *fix =
+		to_clk_fixed_factor(dev_get_clk_ptr(clk->dev));
+	unsigned long parent_rate = clk_get_parent_rate(clk);
+	unsigned long long int rate;
+
+	rate = (unsigned long long int)parent_rate * fix->mult;
+	do_div(rate, fix->div);
+	return (ulong)rate;
+}
+
+const struct clk_ops ccf_clk_fixed_factor_ops = {
+	.get_rate = clk_factor_recalc_rate,
+};
+
+struct clk *clk_hw_register_fixed_factor(struct device *dev,
+		const char *name, const char *parent_name, unsigned long flags,
+		unsigned int mult, unsigned int div)
+{
+	struct clk_fixed_factor *fix;
+	struct clk *clk;
+	int ret;
+
+	fix = kzalloc(sizeof(*fix), GFP_KERNEL);
+	if (!fix)
+		return ERR_PTR(-ENOMEM);
+
+	/* struct clk_fixed_factor assignments */
+	fix->mult = mult;
+	fix->div = div;
+	clk = &fix->clk;
+
+	ret = clk_register(clk, UBOOT_DM_CLK_IMX_FIXED_FACTOR, name,
+			   parent_name);
+	if (ret) {
+		kfree(fix);
+		return ERR_PTR(ret);
+	}
+
+	return clk;
+}
+
+struct clk *clk_register_fixed_factor(struct device *dev, const char *name,
+		const char *parent_name, unsigned long flags,
+		unsigned int mult, unsigned int div)
+{
+	struct clk *clk;
+
+	clk = clk_hw_register_fixed_factor(dev, name, parent_name, flags, mult,
+					  div);
+	if (IS_ERR(clk))
+		return ERR_CAST(clk);
+	return clk;
+}
+
+U_BOOT_DRIVER(imx_clk_fixed_factor) = {
+	.name	= UBOOT_DM_CLK_IMX_FIXED_FACTOR,
+	.id	= UCLASS_CLK,
+	.ops	= &ccf_clk_fixed_factor_ops,
+	.flags = DM_FLAG_PRE_RELOC,
+};
diff --git a/drivers/clk/clk-mux.c b/drivers/clk/clk-mux.c
new file mode 100644
index 0000000..3c075aa
--- /dev/null
+++ b/drivers/clk/clk-mux.c
@@ -0,0 +1,172 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2019 DENX Software Engineering
+ * Lukasz Majewski, DENX Software Engineering, lukma@denx.de
+ *
+ * Copyright (C) 2011 Sascha Hauer, Pengutronix <s.hauer@pengutronix.de>
+ * Copyright (C) 2011 Richard Zhao, Linaro <richard.zhao@linaro.org>
+ * Copyright (C) 2011-2012 Mike Turquette, Linaro Ltd <mturquette@linaro.org>
+ *
+ * Simple multiplexer clock implementation
+ */
+
+/*
+ * U-Boot CCF porting node:
+ *
+ * The Linux kernel - as of tag: 5.0-rc3 is using also the imx_clk_fixup_mux()
+ * version of CCF mux. It is used on e.g. imx6q to provide fixes (like
+ * imx_cscmr1_fixup) for broken HW.
+ *
+ * At least for IMX6Q (but NOT IMX6QP) it is important when we set the parent
+ * clock.
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <malloc.h>
+#include <clk-uclass.h>
+#include <dm/device.h>
+#include <linux/clk-provider.h>
+#include <clk.h>
+#include "clk.h"
+
+#define UBOOT_DM_CLK_CCF_MUX "ccf_clk_mux"
+
+int clk_mux_val_to_index(struct clk *clk, u32 *table, unsigned int flags,
+			 unsigned int val)
+{
+	struct clk_mux *mux = to_clk_mux(clk);
+	int num_parents = mux->num_parents;
+
+	if (table) {
+		int i;
+
+		for (i = 0; i < num_parents; i++)
+			if (table[i] == val)
+				return i;
+		return -EINVAL;
+	}
+
+	if (val && (flags & CLK_MUX_INDEX_BIT))
+		val = ffs(val) - 1;
+
+	if (val && (flags & CLK_MUX_INDEX_ONE))
+		val--;
+
+	if (val >= num_parents)
+		return -EINVAL;
+
+	return val;
+}
+
+static u8 clk_mux_get_parent(struct clk *clk)
+{
+	struct clk_mux *mux = to_clk_mux(clk);
+	u32 val;
+
+#if CONFIG_IS_ENABLED(SANDBOX_CLK_CCF)
+	val = mux->io_mux_val;
+#else
+	val = readl(mux->reg);
+#endif
+	val >>= mux->shift;
+	val &= mux->mask;
+
+	return clk_mux_val_to_index(clk, mux->table, mux->flags, val);
+}
+
+const struct clk_ops clk_mux_ops = {
+		.get_rate = clk_generic_get_rate,
+};
+
+struct clk *clk_hw_register_mux_table(struct device *dev, const char *name,
+		const char * const *parent_names, u8 num_parents,
+		unsigned long flags,
+		void __iomem *reg, u8 shift, u32 mask,
+		u8 clk_mux_flags, u32 *table)
+{
+	struct clk_mux *mux;
+	struct clk *clk;
+	u8 width = 0;
+	int ret;
+
+	if (clk_mux_flags & CLK_MUX_HIWORD_MASK) {
+		width = fls(mask) - ffs(mask) + 1;
+		if (width + shift > 16) {
+			pr_err("mux value exceeds LOWORD field\n");
+			return ERR_PTR(-EINVAL);
+		}
+	}
+
+	/* allocate the mux */
+	mux = kzalloc(sizeof(*mux), GFP_KERNEL);
+	if (!mux)
+		return ERR_PTR(-ENOMEM);
+
+	/* U-boot specific assignments */
+	mux->parent_names = parent_names;
+	mux->num_parents = num_parents;
+
+	/* struct clk_mux assignments */
+	mux->reg = reg;
+	mux->shift = shift;
+	mux->mask = mask;
+	mux->flags = clk_mux_flags;
+	mux->table = table;
+#if CONFIG_IS_ENABLED(SANDBOX_CLK_CCF)
+	mux->io_mux_val = *(u32 *)reg;
+#endif
+
+	clk = &mux->clk;
+
+	/*
+	 * Read the current mux setup - so we assign correct parent.
+	 *
+	 * Changing parent would require changing internals of udevice struct
+	 * for the corresponding clock (to do that define .set_parent() method.
+	 */
+	ret = clk_register(clk, UBOOT_DM_CLK_CCF_MUX, name,
+			   parent_names[clk_mux_get_parent(clk)]);
+	if (ret) {
+		kfree(mux);
+		return ERR_PTR(ret);
+	}
+
+	return clk;
+}
+
+struct clk *clk_register_mux_table(struct device *dev, const char *name,
+		const char * const *parent_names, u8 num_parents,
+		unsigned long flags,
+		void __iomem *reg, u8 shift, u32 mask,
+		u8 clk_mux_flags, u32 *table)
+{
+	struct clk *clk;
+
+	clk = clk_hw_register_mux_table(dev, name, parent_names, num_parents,
+				       flags, reg, shift, mask, clk_mux_flags,
+				       table);
+	if (IS_ERR(clk))
+		return ERR_CAST(clk);
+	return clk;
+}
+
+struct clk *clk_register_mux(struct device *dev, const char *name,
+		const char * const *parent_names, u8 num_parents,
+		unsigned long flags,
+		void __iomem *reg, u8 shift, u8 width,
+		u8 clk_mux_flags)
+{
+	u32 mask = BIT(width) - 1;
+
+	return clk_register_mux_table(dev, name, parent_names, num_parents,
+				      flags, reg, shift, mask, clk_mux_flags,
+				      NULL);
+}
+
+U_BOOT_DRIVER(ccf_clk_mux) = {
+	.name	= UBOOT_DM_CLK_CCF_MUX,
+	.id	= UCLASS_CLK,
+	.ops	= &clk_mux_ops,
+	.flags = DM_FLAG_PRE_RELOC,
+};
diff --git a/drivers/clk/clk-uclass.c b/drivers/clk/clk-uclass.c
index 06a8258..85dfe71 100644
--- a/drivers/clk/clk-uclass.c
+++ b/drivers/clk/clk-uclass.c
@@ -13,6 +13,7 @@
 #include <dm/read.h>
 #include <dt-structs.h>
 #include <errno.h>
+#include <linux/clk-provider.h>
 
 static inline const struct clk_ops *clk_dev_ops(struct udevice *dev)
 {
@@ -381,6 +382,43 @@
 	return ops->get_rate(clk);
 }
 
+struct clk *clk_get_parent(struct clk *clk)
+{
+	struct udevice *pdev;
+	struct clk *pclk;
+
+	debug("%s(clk=%p)\n", __func__, clk);
+
+	pdev = dev_get_parent(clk->dev);
+	pclk = dev_get_clk_ptr(pdev);
+	if (!pclk)
+		return ERR_PTR(-ENODEV);
+
+	return pclk;
+}
+
+long long clk_get_parent_rate(struct clk *clk)
+{
+	const struct clk_ops *ops;
+	struct clk *pclk;
+
+	debug("%s(clk=%p)\n", __func__, clk);
+
+	pclk = clk_get_parent(clk);
+	if (IS_ERR(pclk))
+		return -ENODEV;
+
+	ops = clk_dev_ops(pclk->dev);
+	if (!ops->get_rate)
+		return -ENOSYS;
+
+	/* Read the 'rate' if not already set or if proper flag set*/
+	if (!pclk->rate || pclk->flags & CLK_GET_RATE_NOCACHE)
+		pclk->rate = clk_get_rate(pclk);
+
+	return pclk->rate;
+}
+
 ulong clk_set_rate(struct clk *clk, ulong rate)
 {
 	const struct clk_ops *ops = clk_dev_ops(clk->dev);
@@ -455,6 +493,28 @@
 	return 0;
 }
 
+int clk_get_by_id(ulong id, struct clk **clkp)
+{
+	struct udevice *dev;
+	struct uclass *uc;
+	int ret;
+
+	ret = uclass_get(UCLASS_CLK, &uc);
+	if (ret)
+		return ret;
+
+	uclass_foreach_dev(dev, uc) {
+		struct clk *clk = dev_get_clk_ptr(dev);
+
+		if (clk && clk->id == id) {
+			*clkp = clk;
+			return 0;
+		}
+	}
+
+	return -ENOENT;
+}
+
 UCLASS_DRIVER(clk) = {
 	.id		= UCLASS_CLK,
 	.name		= "clk",
diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c
new file mode 100644
index 0000000..7d748c9
--- /dev/null
+++ b/drivers/clk/clk.c
@@ -0,0 +1,57 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2019 DENX Software Engineering
+ * Lukasz Majewski, DENX Software Engineering, lukma@denx.de
+ */
+
+#include <common.h>
+#include <clk-uclass.h>
+#include <dm/device.h>
+#include <dm/uclass.h>
+#include <dm/lists.h>
+#include <dm/device-internal.h>
+#include <clk.h>
+
+int clk_register(struct clk *clk, const char *drv_name,
+		 const char *name, const char *parent_name)
+{
+	struct udevice *parent;
+	struct driver *drv;
+	int ret;
+
+	ret = uclass_get_device_by_name(UCLASS_CLK, parent_name, &parent);
+	if (ret)
+		printf("%s: UCLASS parent: 0x%p\n", __func__, parent);
+
+	debug("%s: name: %s parent: %s [0x%p]\n", __func__, name, parent->name,
+	      parent);
+
+	drv = lists_driver_lookup_name(drv_name);
+	if (!drv) {
+		printf("%s: %s is not a valid driver name\n",
+		       __func__, drv_name);
+		return -ENOENT;
+	}
+
+	ret = device_bind(parent, drv, name, NULL, -1, &clk->dev);
+	if (ret) {
+		printf("%s: CLK: %s driver bind error [%d]!\n", __func__, name,
+		       ret);
+		return ret;
+	}
+
+	/* Store back pointer to clk from udevice */
+	clk->dev->uclass_priv = clk;
+
+	return 0;
+}
+
+ulong clk_generic_get_rate(struct clk *clk)
+{
+	return clk_get_parent_rate(clk);
+}
+
+const char *clk_hw_get_name(const struct clk *hw)
+{
+	return hw->dev->name;
+}
diff --git a/drivers/clk/clk_fixed_factor.c b/drivers/clk/clk_fixed_factor.c
index 5fa20a8..dcdb6dd 100644
--- a/drivers/clk/clk_fixed_factor.c
+++ b/drivers/clk/clk_fixed_factor.c
@@ -24,9 +24,6 @@
 	uint64_t rate;
 	struct clk_fixed_factor *ff = to_clk_fixed_factor(clk->dev);
 
-	if (clk->id != 0)
-		return -EINVAL;
-
 	rate = clk_get_rate(&ff->parent);
 	if (IS_ERR_VALUE(rate))
 		return rate;
diff --git a/drivers/clk/clk_fixed_rate.c b/drivers/clk/clk_fixed_rate.c
index d8d9f86..1fdf8c4 100644
--- a/drivers/clk/clk_fixed_rate.c
+++ b/drivers/clk/clk_fixed_rate.c
@@ -8,6 +8,7 @@
 #include <dm.h>
 
 struct clk_fixed_rate {
+	struct clk clk;
 	unsigned long fixed_rate;
 };
 
@@ -15,9 +16,6 @@
 
 static ulong clk_fixed_rate_get_rate(struct clk *clk)
 {
-	if (clk->id != 0)
-		return -EINVAL;
-
 	return to_clk_fixed_rate(clk->dev)->fixed_rate;
 }
 
@@ -27,10 +25,14 @@
 
 static int clk_fixed_rate_ofdata_to_platdata(struct udevice *dev)
 {
+	struct clk *clk = &to_clk_fixed_rate(dev)->clk;
 #if !CONFIG_IS_ENABLED(OF_PLATDATA)
 	to_clk_fixed_rate(dev)->fixed_rate =
 		dev_read_u32_default(dev, "clock-frequency", 0);
 #endif
+	/* Make fixed rate clock accessible from higher level struct clk */
+	dev->uclass_priv = clk;
+	clk->dev = dev;
 
 	return 0;
 }
diff --git a/drivers/clk/clk_sandbox_ccf.c b/drivers/clk/clk_sandbox_ccf.c
new file mode 100644
index 0000000..edeb0f2
--- /dev/null
+++ b/drivers/clk/clk_sandbox_ccf.c
@@ -0,0 +1,185 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2019
+ * Lukasz Majewski, DENX Software Engineering, lukma@denx.de
+ *
+ * Common Clock Framework [CCF] driver for Sandbox
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <clk.h>
+#include <asm/clk.h>
+#include <clk-uclass.h>
+#include <linux/clk-provider.h>
+#include <sandbox-clk.h>
+
+/*
+ * Sandbox implementation of CCF primitives necessary for clk-uclass testing
+ *
+ * --- Sandbox PLLv3 ---
+ */
+struct clk_pllv3 {
+	struct clk	clk;
+	u32		div_mask;
+	u32		div_shift;
+};
+
+static ulong clk_pllv3_get_rate(struct clk *clk)
+{
+	unsigned long parent_rate = clk_get_parent_rate(clk);
+
+	return parent_rate * 24;
+}
+
+static const struct clk_ops clk_pllv3_generic_ops = {
+	.get_rate       = clk_pllv3_get_rate,
+};
+
+struct clk *sandbox_clk_pllv3(enum sandbox_pllv3_type type, const char *name,
+			      const char *parent_name, void __iomem *base,
+			      u32 div_mask)
+{
+	struct clk_pllv3 *pll;
+	struct clk *clk;
+	char *drv_name = "sandbox_clk_pllv3";
+	int ret;
+
+	pll = kzalloc(sizeof(*pll), GFP_KERNEL);
+	if (!pll)
+		return ERR_PTR(-ENOMEM);
+
+	pll->div_mask = div_mask;
+	clk = &pll->clk;
+
+	ret = clk_register(clk, drv_name, name, parent_name);
+	if (ret) {
+		kfree(pll);
+		return ERR_PTR(ret);
+	}
+
+	return clk;
+}
+
+U_BOOT_DRIVER(sandbox_clk_pll_generic) = {
+	.name	= "sandbox_clk_pllv3",
+	.id	= UCLASS_CLK,
+	.ops	= &clk_pllv3_generic_ops,
+};
+
+/* --- Sandbox PLLv3 --- */
+/* --- Sandbox Gate  --- */
+struct clk_gate2 {
+	struct clk clk;
+	bool	state;
+};
+
+#define to_clk_gate2(_clk) container_of(_clk, struct clk_gate2, clk)
+
+static int clk_gate2_enable(struct clk *clk)
+{
+	struct clk_gate2 *gate = to_clk_gate2(dev_get_clk_ptr(clk->dev));
+
+	gate->state = 1;
+	return 0;
+}
+
+static int clk_gate2_disable(struct clk *clk)
+{
+	struct clk_gate2 *gate = to_clk_gate2(dev_get_clk_ptr(clk->dev));
+
+	gate->state = 0;
+	return 0;
+}
+
+static const struct clk_ops clk_gate2_ops = {
+	.enable = clk_gate2_enable,
+	.disable = clk_gate2_disable,
+	.get_rate = clk_generic_get_rate,
+};
+
+struct clk *sandbox_clk_register_gate2(struct device *dev, const char *name,
+				       const char *parent_name,
+				       unsigned long flags, void __iomem *reg,
+				       u8 bit_idx, u8 cgr_val,
+				       u8 clk_gate2_flags)
+{
+	struct clk_gate2 *gate;
+	struct clk *clk;
+	int ret;
+
+	gate = kzalloc(sizeof(*gate), GFP_KERNEL);
+	if (!gate)
+		return ERR_PTR(-ENOMEM);
+
+	gate->state = 0;
+	clk = &gate->clk;
+
+	ret = clk_register(clk, "sandbox_clk_gate2", name, parent_name);
+	if (ret) {
+		kfree(gate);
+		return ERR_PTR(ret);
+	}
+
+	return clk;
+}
+
+U_BOOT_DRIVER(sandbox_clk_gate2) = {
+	.name	= "sandbox_clk_gate2",
+	.id	= UCLASS_CLK,
+	.ops	= &clk_gate2_ops,
+};
+
+/* --- Sandbox Gate --- */
+/* The CCF core driver itself */
+static const struct udevice_id sandbox_clk_ccf_test_ids[] = {
+	{ .compatible = "sandbox,clk-ccf" },
+	{ }
+};
+
+static const char *const usdhc_sels[] = { "pll3_60m", "pll3_80m", };
+
+static int sandbox_clk_ccf_probe(struct udevice *dev)
+{
+	void *base = NULL;
+	u32 reg;
+
+	clk_dm(SANDBOX_CLK_PLL3,
+	       sandbox_clk_pllv3(SANDBOX_PLLV3_USB, "pll3_usb_otg", "osc",
+				 base + 0x10, 0x3));
+
+	clk_dm(SANDBOX_CLK_PLL3_60M,
+	       sandbox_clk_fixed_factor("pll3_60m",  "pll3_usb_otg",   1, 8));
+
+	clk_dm(SANDBOX_CLK_PLL3_80M,
+	       sandbox_clk_fixed_factor("pll3_80m",  "pll3_usb_otg",   1, 6));
+
+	/* The HW adds +1 to the divider value (2+1) is the divider */
+	reg = (2 << 19);
+	clk_dm(SANDBOX_CLK_ECSPI_ROOT,
+	       sandbox_clk_divider("ecspi_root", "pll3_60m", &reg, 19, 6));
+
+	clk_dm(SANDBOX_CLK_ECSPI1,
+	       sandbox_clk_gate2("ecspi1", "ecspi_root", base + 0x6c, 0));
+
+	/* Select 'pll3_60m' */
+	reg = 0;
+	clk_dm(SANDBOX_CLK_USDHC1_SEL,
+	       sandbox_clk_mux("usdhc1_sel", &reg, 16, 1, usdhc_sels,
+			       ARRAY_SIZE(usdhc_sels)));
+
+	/* Select 'pll3_80m' */
+	reg = BIT(17);
+	clk_dm(SANDBOX_CLK_USDHC2_SEL,
+	       sandbox_clk_mux("usdhc2_sel", &reg, 17, 1, usdhc_sels,
+			       ARRAY_SIZE(usdhc_sels)));
+
+	return 0;
+}
+
+U_BOOT_DRIVER(sandbox_clk_ccf) = {
+	.name = "sandbox_clk_ccf",
+	.id = UCLASS_CLK,
+	.probe = sandbox_clk_ccf_probe,
+	.of_match = sandbox_clk_ccf_test_ids,
+};
diff --git a/drivers/clk/imx/Kconfig b/drivers/clk/imx/Kconfig
index a6fb58d..3e6a980 100644
--- a/drivers/clk/imx/Kconfig
+++ b/drivers/clk/imx/Kconfig
@@ -1,3 +1,19 @@
+config SPL_CLK_IMX6Q
+	bool "SPL clock support for i.MX6Q"
+	depends on ARCH_MX6 && SPL
+	select SPL_CLK
+	select SPL_CLK_CCF
+	help
+	  This enables SPL DM/DTS support for clock driver in i.MX6Q platforms.
+
+config CLK_IMX6Q
+	bool "Clock support for i.MX6Q"
+	depends on ARCH_MX6
+	select CLK
+	select CLK_CCF
+	help
+	  This enables DM/DTS support for clock driver in i.MX6Q platforms.
+
 config CLK_IMX8
 	bool "Clock support for i.MX8"
 	depends on ARCH_IMX8
diff --git a/drivers/clk/imx/Makefile b/drivers/clk/imx/Makefile
index eb379c1..105a58c 100644
--- a/drivers/clk/imx/Makefile
+++ b/drivers/clk/imx/Makefile
@@ -2,6 +2,8 @@
 #
 # SPDX-License-Identifier: GPL-2.0
 
+obj-$(CONFIG_$(SPL_TPL_)CLK_CCF) += clk-gate2.o clk-pllv3.o clk-pfd.o
+obj-$(CONFIG_$(SPL_TPL_)CLK_IMX6Q) += clk-imx6q.o
 obj-$(CONFIG_CLK_IMX8) += clk-imx8.o
 
 ifdef CONFIG_CLK_IMX8
diff --git a/drivers/clk/imx/clk-gate2.c b/drivers/clk/imx/clk-gate2.c
new file mode 100644
index 0000000..571be32
--- /dev/null
+++ b/drivers/clk/imx/clk-gate2.c
@@ -0,0 +1,103 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2019 DENX Software Engineering
+ * Lukasz Majewski, DENX Software Engineering, lukma@denx.de
+ *
+ * Copyright (C) 2010-2011 Canonical Ltd <jeremy.kerr@canonical.com>
+ * Copyright (C) 2011-2012 Mike Turquette, Linaro Ltd <mturquette@linaro.org>
+ *
+ * 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.
+ *
+ * Gated clock implementation
+ *
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <malloc.h>
+#include <clk-uclass.h>
+#include <dm/device.h>
+#include <linux/clk-provider.h>
+#include <clk.h>
+#include "clk.h"
+
+#define UBOOT_DM_CLK_IMX_GATE2 "imx_clk_gate2"
+
+struct clk_gate2 {
+	struct clk clk;
+	void __iomem	*reg;
+	u8		bit_idx;
+	u8		cgr_val;
+	u8		flags;
+};
+
+#define to_clk_gate2(_clk) container_of(_clk, struct clk_gate2, clk)
+
+static int clk_gate2_enable(struct clk *clk)
+{
+	struct clk_gate2 *gate = to_clk_gate2(dev_get_clk_ptr(clk->dev));
+	u32 reg;
+
+	reg = readl(gate->reg);
+	reg &= ~(3 << gate->bit_idx);
+	reg |= gate->cgr_val << gate->bit_idx;
+	writel(reg, gate->reg);
+
+	return 0;
+}
+
+static int clk_gate2_disable(struct clk *clk)
+{
+	struct clk_gate2 *gate = to_clk_gate2(dev_get_clk_ptr(clk->dev));
+	u32 reg;
+
+	reg = readl(gate->reg);
+	reg &= ~(3 << gate->bit_idx);
+	writel(reg, gate->reg);
+
+	return 0;
+}
+
+static const struct clk_ops clk_gate2_ops = {
+	.enable = clk_gate2_enable,
+	.disable = clk_gate2_disable,
+	.get_rate = clk_generic_get_rate,
+};
+
+struct clk *clk_register_gate2(struct device *dev, const char *name,
+		const char *parent_name, unsigned long flags,
+		void __iomem *reg, u8 bit_idx, u8 cgr_val,
+		u8 clk_gate2_flags)
+{
+	struct clk_gate2 *gate;
+	struct clk *clk;
+	int ret;
+
+	gate = kzalloc(sizeof(*gate), GFP_KERNEL);
+	if (!gate)
+		return ERR_PTR(-ENOMEM);
+
+	gate->reg = reg;
+	gate->bit_idx = bit_idx;
+	gate->cgr_val = cgr_val;
+	gate->flags = clk_gate2_flags;
+
+	clk = &gate->clk;
+
+	ret = clk_register(clk, UBOOT_DM_CLK_IMX_GATE2, name, parent_name);
+	if (ret) {
+		kfree(gate);
+		return ERR_PTR(ret);
+	}
+
+	return clk;
+}
+
+U_BOOT_DRIVER(clk_gate2) = {
+	.name	= UBOOT_DM_CLK_IMX_GATE2,
+	.id	= UCLASS_CLK,
+	.ops	= &clk_gate2_ops,
+	.flags = DM_FLAG_PRE_RELOC,
+};
diff --git a/drivers/clk/imx/clk-imx6q.c b/drivers/clk/imx/clk-imx6q.c
new file mode 100644
index 0000000..92e9337
--- /dev/null
+++ b/drivers/clk/imx/clk-imx6q.c
@@ -0,0 +1,179 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2019 DENX Software Engineering
+ * Lukasz Majewski, DENX Software Engineering, lukma@denx.de
+ */
+
+#include <common.h>
+#include <clk-uclass.h>
+#include <dm.h>
+#include <asm/arch/clock.h>
+#include <asm/arch/imx-regs.h>
+#include <dt-bindings/clock/imx6qdl-clock.h>
+
+#include "clk.h"
+
+static int imx6q_check_id(ulong id)
+{
+	if (id < IMX6QDL_CLK_DUMMY || id >= IMX6QDL_CLK_END) {
+		printf("%s: Invalid clk ID #%lu\n", __func__, id);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static ulong imx6q_clk_get_rate(struct clk *clk)
+{
+	struct clk *c;
+	int ret;
+
+	debug("%s(#%lu)\n", __func__, clk->id);
+
+	ret = imx6q_check_id(clk->id);
+	if (ret)
+		return ret;
+
+	ret = clk_get_by_id(clk->id, &c);
+	if (ret)
+		return ret;
+
+	return clk_get_rate(c);
+}
+
+static ulong imx6q_clk_set_rate(struct clk *clk, unsigned long rate)
+{
+	debug("%s(#%lu), rate: %lu\n", __func__, clk->id, rate);
+
+	return rate;
+}
+
+static int __imx6q_clk_enable(struct clk *clk, bool enable)
+{
+	struct clk *c;
+	int ret = 0;
+
+	debug("%s(#%lu) en: %d\n", __func__, clk->id, enable);
+
+	ret = imx6q_check_id(clk->id);
+	if (ret)
+		return ret;
+
+	ret = clk_get_by_id(clk->id, &c);
+	if (ret)
+		return ret;
+
+	if (enable)
+		ret = clk_enable(c);
+	else
+		ret = clk_disable(c);
+
+	return ret;
+}
+
+static int imx6q_clk_disable(struct clk *clk)
+{
+	return __imx6q_clk_enable(clk, 0);
+}
+
+static int imx6q_clk_enable(struct clk *clk)
+{
+	return __imx6q_clk_enable(clk, 1);
+}
+
+static struct clk_ops imx6q_clk_ops = {
+	.set_rate = imx6q_clk_set_rate,
+	.get_rate = imx6q_clk_get_rate,
+	.enable = imx6q_clk_enable,
+	.disable = imx6q_clk_disable,
+};
+
+static const char *const usdhc_sels[] = { "pll2_pfd2_396m", "pll2_pfd0_352m", };
+
+static int imx6q_clk_probe(struct udevice *dev)
+{
+	void *base;
+
+	/* Anatop clocks */
+	base = (void *)ANATOP_BASE_ADDR;
+
+	clk_dm(IMX6QDL_CLK_PLL2,
+	       imx_clk_pllv3(IMX_PLLV3_GENERIC, "pll2_bus", "osc",
+			     base + 0x30, 0x1));
+	clk_dm(IMX6QDL_CLK_PLL3_USB_OTG,
+	       imx_clk_pllv3(IMX_PLLV3_USB, "pll3_usb_otg", "osc",
+			     base + 0x10, 0x3));
+	clk_dm(IMX6QDL_CLK_PLL3_60M,
+	       imx_clk_fixed_factor("pll3_60m",  "pll3_usb_otg",   1, 8));
+	clk_dm(IMX6QDL_CLK_PLL2_PFD0_352M,
+	       imx_clk_pfd("pll2_pfd0_352m", "pll2_bus", base + 0x100, 0));
+	clk_dm(IMX6QDL_CLK_PLL2_PFD2_396M,
+	       imx_clk_pfd("pll2_pfd2_396m", "pll2_bus", base + 0x100, 2));
+
+	/* CCM clocks */
+	base = dev_read_addr_ptr(dev);
+	if (base == (void *)FDT_ADDR_T_NONE)
+		return -EINVAL;
+
+	clk_dm(IMX6QDL_CLK_USDHC1_SEL,
+	       imx_clk_mux("usdhc1_sel", base + 0x1c, 16, 1,
+			   usdhc_sels, ARRAY_SIZE(usdhc_sels)));
+	clk_dm(IMX6QDL_CLK_USDHC2_SEL,
+	       imx_clk_mux("usdhc2_sel", base + 0x1c, 17, 1,
+			   usdhc_sels, ARRAY_SIZE(usdhc_sels)));
+	clk_dm(IMX6QDL_CLK_USDHC3_SEL,
+	       imx_clk_mux("usdhc3_sel", base + 0x1c, 18, 1,
+			   usdhc_sels, ARRAY_SIZE(usdhc_sels)));
+	clk_dm(IMX6QDL_CLK_USDHC4_SEL,
+	       imx_clk_mux("usdhc4_sel", base + 0x1c, 19, 1,
+			   usdhc_sels, ARRAY_SIZE(usdhc_sels)));
+
+	clk_dm(IMX6QDL_CLK_USDHC1_PODF,
+	       imx_clk_divider("usdhc1_podf", "usdhc1_sel",
+			       base + 0x24, 11, 3));
+	clk_dm(IMX6QDL_CLK_USDHC2_PODF,
+	       imx_clk_divider("usdhc2_podf", "usdhc2_sel",
+			       base + 0x24, 16, 3));
+	clk_dm(IMX6QDL_CLK_USDHC3_PODF,
+	       imx_clk_divider("usdhc3_podf", "usdhc3_sel",
+			       base + 0x24, 19, 3));
+	clk_dm(IMX6QDL_CLK_USDHC4_PODF,
+	       imx_clk_divider("usdhc4_podf", "usdhc4_sel",
+			       base + 0x24, 22, 3));
+
+	clk_dm(IMX6QDL_CLK_ECSPI_ROOT,
+	       imx_clk_divider("ecspi_root", "pll3_60m", base + 0x38, 19, 6));
+
+	clk_dm(IMX6QDL_CLK_ECSPI1,
+	       imx_clk_gate2("ecspi1", "ecspi_root", base + 0x6c, 0));
+	clk_dm(IMX6QDL_CLK_ECSPI2,
+	       imx_clk_gate2("ecspi2", "ecspi_root", base + 0x6c, 2));
+	clk_dm(IMX6QDL_CLK_ECSPI3,
+	       imx_clk_gate2("ecspi3", "ecspi_root", base + 0x6c, 4));
+	clk_dm(IMX6QDL_CLK_ECSPI4,
+	       imx_clk_gate2("ecspi4", "ecspi_root", base + 0x6c, 6));
+	clk_dm(IMX6QDL_CLK_USDHC1,
+	       imx_clk_gate2("usdhc1", "usdhc1_podf", base + 0x80, 2));
+	clk_dm(IMX6QDL_CLK_USDHC2,
+	       imx_clk_gate2("usdhc2", "usdhc2_podf", base + 0x80, 4));
+	clk_dm(IMX6QDL_CLK_USDHC3,
+	       imx_clk_gate2("usdhc3", "usdhc3_podf", base + 0x80, 6));
+	clk_dm(IMX6QDL_CLK_USDHC4,
+	       imx_clk_gate2("usdhc4", "usdhc4_podf", base + 0x80, 8));
+
+	return 0;
+}
+
+static const struct udevice_id imx6q_clk_ids[] = {
+	{ .compatible = "fsl,imx6q-ccm" },
+	{ },
+};
+
+U_BOOT_DRIVER(imx6q_clk) = {
+	.name = "clk_imx6q",
+	.id = UCLASS_CLK,
+	.of_match = imx6q_clk_ids,
+	.ops = &imx6q_clk_ops,
+	.probe = imx6q_clk_probe,
+	.flags = DM_FLAG_PRE_RELOC,
+};
diff --git a/drivers/clk/imx/clk-pfd.c b/drivers/clk/imx/clk-pfd.c
new file mode 100644
index 0000000..188b2b3
--- /dev/null
+++ b/drivers/clk/imx/clk-pfd.c
@@ -0,0 +1,90 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2019 DENX Software Engineering
+ * Lukasz Majewski, DENX Software Engineering, lukma@denx.de
+ *
+ * Copyright 2012 Freescale Semiconductor, Inc.
+ * Copyright 2012 Linaro Ltd.
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <malloc.h>
+#include <clk-uclass.h>
+#include <dm/device.h>
+#include <linux/clk-provider.h>
+#include <div64.h>
+#include <clk.h>
+#include "clk.h"
+
+#define UBOOT_DM_CLK_IMX_PFD "imx_clk_pfd"
+
+struct clk_pfd {
+	struct clk	clk;
+	void __iomem	*reg;
+	u8		idx;
+};
+
+#define to_clk_pfd(_clk) container_of(_clk, struct clk_pfd, clk)
+
+#define SET	0x4
+#define CLR	0x8
+#define OTG	0xc
+
+static unsigned long clk_pfd_recalc_rate(struct clk *clk)
+{
+	struct clk_pfd *pfd =
+		to_clk_pfd(dev_get_clk_ptr(clk->dev));
+	unsigned long parent_rate = clk_get_parent_rate(clk);
+	u64 tmp = parent_rate;
+	u8 frac = (readl(pfd->reg) >> (pfd->idx * 8)) & 0x3f;
+
+	tmp *= 18;
+	do_div(tmp, frac);
+
+	return tmp;
+}
+
+static const struct clk_ops clk_pfd_ops = {
+	.get_rate	= clk_pfd_recalc_rate,
+};
+
+struct clk *imx_clk_pfd(const char *name, const char *parent_name,
+			void __iomem *reg, u8 idx)
+{
+	struct clk_pfd *pfd;
+	struct clk *clk;
+	int ret;
+
+	pfd = kzalloc(sizeof(*pfd), GFP_KERNEL);
+	if (!pfd)
+		return ERR_PTR(-ENOMEM);
+
+	pfd->reg = reg;
+	pfd->idx = idx;
+
+	/* register the clock */
+	clk = &pfd->clk;
+
+	ret = clk_register(clk, UBOOT_DM_CLK_IMX_PFD, name, parent_name);
+	if (ret) {
+		kfree(pfd);
+		return ERR_PTR(ret);
+	}
+
+	return clk;
+}
+
+U_BOOT_DRIVER(clk_pfd) = {
+	.name	= UBOOT_DM_CLK_IMX_PFD,
+	.id	= UCLASS_CLK,
+	.ops	= &clk_pfd_ops,
+	.flags = DM_FLAG_PRE_RELOC,
+};
diff --git a/drivers/clk/imx/clk-pllv3.c b/drivers/clk/imx/clk-pllv3.c
new file mode 100644
index 0000000..fbb7b24
--- /dev/null
+++ b/drivers/clk/imx/clk-pllv3.c
@@ -0,0 +1,82 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2019 DENX Software Engineering
+ * Lukasz Majewski, DENX Software Engineering, lukma@denx.de
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <malloc.h>
+#include <clk-uclass.h>
+#include <dm/device.h>
+#include <dm/uclass.h>
+#include <clk.h>
+#include "clk.h"
+
+#define UBOOT_DM_CLK_IMX_PLLV3 "imx_clk_pllv3"
+
+struct clk_pllv3 {
+	struct clk	clk;
+	void __iomem	*base;
+	u32		div_mask;
+	u32		div_shift;
+};
+
+#define to_clk_pllv3(_clk) container_of(_clk, struct clk_pllv3, clk)
+
+static ulong clk_pllv3_get_rate(struct clk *clk)
+{
+	struct clk_pllv3 *pll = to_clk_pllv3(dev_get_clk_ptr(clk->dev));
+	unsigned long parent_rate = clk_get_parent_rate(clk);
+
+	u32 div = (readl(pll->base) >> pll->div_shift) & pll->div_mask;
+
+	return (div == 1) ? parent_rate * 22 : parent_rate * 20;
+}
+
+static const struct clk_ops clk_pllv3_generic_ops = {
+	.get_rate       = clk_pllv3_get_rate,
+};
+
+struct clk *imx_clk_pllv3(enum imx_pllv3_type type, const char *name,
+			  const char *parent_name, void __iomem *base,
+			  u32 div_mask)
+{
+	struct clk_pllv3 *pll;
+	struct clk *clk;
+	char *drv_name;
+	int ret;
+
+	pll = kzalloc(sizeof(*pll), GFP_KERNEL);
+	if (!pll)
+		return ERR_PTR(-ENOMEM);
+
+	switch (type) {
+	case IMX_PLLV3_GENERIC:
+	case IMX_PLLV3_USB:
+		drv_name = UBOOT_DM_CLK_IMX_PLLV3;
+		break;
+	default:
+		kfree(pll);
+		return ERR_PTR(-ENOTSUPP);
+	}
+
+	pll->base = base;
+	pll->div_mask = div_mask;
+	clk = &pll->clk;
+
+	ret = clk_register(clk, drv_name, name, parent_name);
+	if (ret) {
+		kfree(pll);
+		return ERR_PTR(ret);
+	}
+
+	return clk;
+}
+
+U_BOOT_DRIVER(clk_pllv3_generic) = {
+	.name	= UBOOT_DM_CLK_IMX_PLLV3,
+	.id	= UCLASS_CLK,
+	.ops	= &clk_pllv3_generic_ops,
+	.flags = DM_FLAG_PRE_RELOC,
+};
diff --git a/drivers/clk/imx/clk.h b/drivers/clk/imx/clk.h
new file mode 100644
index 0000000..e6d5183
--- /dev/null
+++ b/drivers/clk/imx/clk.h
@@ -0,0 +1,69 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2019 DENX Software Engineering
+ * Lukasz Majewski, DENX Software Engineering, lukma@denx.de
+ */
+#ifndef __MACH_IMX_CLK_H
+#define __MACH_IMX_CLK_H
+
+#include <linux/clk-provider.h>
+
+enum imx_pllv3_type {
+	IMX_PLLV3_GENERIC,
+	IMX_PLLV3_SYS,
+	IMX_PLLV3_USB,
+	IMX_PLLV3_USB_VF610,
+	IMX_PLLV3_AV,
+	IMX_PLLV3_ENET,
+	IMX_PLLV3_ENET_IMX7,
+	IMX_PLLV3_SYS_VF610,
+	IMX_PLLV3_DDR_IMX7,
+};
+
+struct clk *clk_register_gate2(struct device *dev, const char *name,
+		const char *parent_name, unsigned long flags,
+		void __iomem *reg, u8 bit_idx, u8 cgr_val,
+		u8 clk_gate_flags);
+
+struct clk *imx_clk_pllv3(enum imx_pllv3_type type, const char *name,
+			  const char *parent_name, void __iomem *base,
+			  u32 div_mask);
+
+static inline struct clk *imx_clk_gate2(const char *name, const char *parent,
+					void __iomem *reg, u8 shift)
+{
+	return clk_register_gate2(NULL, name, parent, CLK_SET_RATE_PARENT, reg,
+			shift, 0x3, 0);
+}
+
+static inline struct clk *imx_clk_fixed_factor(const char *name,
+		const char *parent, unsigned int mult, unsigned int div)
+{
+	return clk_register_fixed_factor(NULL, name, parent,
+			CLK_SET_RATE_PARENT, mult, div);
+}
+
+static inline struct clk *imx_clk_divider(const char *name, const char *parent,
+		void __iomem *reg, u8 shift, u8 width)
+{
+	return clk_register_divider(NULL, name, parent, CLK_SET_RATE_PARENT,
+			reg, shift, width, 0);
+}
+
+struct clk *imx_clk_pfd(const char *name, const char *parent_name,
+			void __iomem *reg, u8 idx);
+
+struct clk *imx_clk_fixup_mux(const char *name, void __iomem *reg,
+			      u8 shift, u8 width, const char * const *parents,
+			      int num_parents, void (*fixup)(u32 *val));
+
+static inline struct clk *imx_clk_mux(const char *name, void __iomem *reg,
+			u8 shift, u8 width, const char * const *parents,
+			int num_parents)
+{
+	return clk_register_mux(NULL, name, parents, num_parents,
+			CLK_SET_RATE_NO_REPARENT, reg, shift,
+			width, 0);
+}
+
+#endif /* __MACH_IMX_CLK_H */
diff --git a/drivers/gpio/mxc_gpio.c b/drivers/gpio/mxc_gpio.c
index 8bd30c7..64ab7a3 100644
--- a/drivers/gpio/mxc_gpio.c
+++ b/drivers/gpio/mxc_gpio.c
@@ -31,7 +31,7 @@
 };
 
 #ifndef CONFIG_DM_GPIO
-#define GPIO_TO_PORT(n)		(n / 32)
+#define GPIO_TO_PORT(n)		((n) / 32)
 
 /* GPIO port description */
 static unsigned long gpio_ports[] = {
diff --git a/drivers/gpio/mxs_gpio.c b/drivers/gpio/mxs_gpio.c
index c2c8a25..b2451fd 100644
--- a/drivers/gpio/mxs_gpio.c
+++ b/drivers/gpio/mxs_gpio.c
@@ -51,6 +51,7 @@
 	}
 }
 
+#if !CONFIG_IS_ENABLED(DM_GPIO)
 int gpio_get_value(unsigned gpio)
 {
 	uint32_t bank = PAD_BANK(gpio);
@@ -127,3 +128,150 @@
 
 	return (bank << MXS_PAD_BANK_SHIFT) | (pin << MXS_PAD_PIN_SHIFT);
 }
+#else /* CONFIG_DM_GPIO */
+#include <dm.h>
+#include <asm/gpio.h>
+#include <asm/arch/gpio.h>
+#define MXS_MAX_GPIO_PER_BANK		32
+
+DECLARE_GLOBAL_DATA_PTR;
+/*
+ * According to i.MX28 Reference Manual:
+ * 'i.MX28 Applications Processor Reference Manual, Rev. 1, 2010'
+ * The i.MX28 has following number of GPIOs available:
+ * Bank 0: 0-28 -> 29 PINS
+ * Bank 1: 0-31 -> 32 PINS
+ * Bank 2: 0-27 -> 28 PINS
+ * Bank 3: 0-30 -> 31 PINS
+ * Bank 4: 0-20 -> 21 PINS
+ */
+
+struct mxs_gpio_priv {
+	unsigned int bank;
+};
+
+static int mxs_gpio_get_value(struct udevice *dev, unsigned offset)
+{
+	struct mxs_gpio_priv *priv = dev_get_priv(dev);
+	struct mxs_register_32 *reg =
+		(struct mxs_register_32 *)(MXS_PINCTRL_BASE +
+					   PINCTRL_DIN(priv->bank));
+
+	return (readl(&reg->reg) >> offset) & 1;
+}
+
+static int mxs_gpio_set_value(struct udevice *dev, unsigned offset,
+			      int value)
+{
+	struct mxs_gpio_priv *priv = dev_get_priv(dev);
+	struct mxs_register_32 *reg =
+		(struct mxs_register_32 *)(MXS_PINCTRL_BASE +
+					   PINCTRL_DOUT(priv->bank));
+	if (value)
+		writel(BIT(offset), &reg->reg_set);
+	else
+		writel(BIT(offset), &reg->reg_clr);
+
+	return 0;
+}
+
+static int mxs_gpio_direction_input(struct udevice *dev, unsigned offset)
+{
+	struct mxs_gpio_priv *priv = dev_get_priv(dev);
+	struct mxs_register_32 *reg =
+		(struct mxs_register_32 *)(MXS_PINCTRL_BASE +
+					   PINCTRL_DOE(priv->bank));
+
+	writel(BIT(offset), &reg->reg_clr);
+
+	return 0;
+}
+
+static int mxs_gpio_direction_output(struct udevice *dev, unsigned offset,
+				     int value)
+{
+	struct mxs_gpio_priv *priv = dev_get_priv(dev);
+	struct mxs_register_32 *reg =
+		(struct mxs_register_32 *)(MXS_PINCTRL_BASE +
+					   PINCTRL_DOE(priv->bank));
+
+	mxs_gpio_set_value(dev, offset, value);
+
+	writel(BIT(offset), &reg->reg_set);
+
+	return 0;
+}
+
+static int mxs_gpio_get_function(struct udevice *dev, unsigned offset)
+{
+	struct mxs_gpio_priv *priv = dev_get_priv(dev);
+	struct mxs_register_32 *reg =
+		(struct mxs_register_32 *)(MXS_PINCTRL_BASE +
+					   PINCTRL_DOE(priv->bank));
+	bool is_output = !!(readl(&reg->reg) >> offset);
+
+	return is_output ? GPIOF_OUTPUT : GPIOF_INPUT;
+}
+
+static const struct dm_gpio_ops gpio_mxs_ops = {
+	.direction_input	= mxs_gpio_direction_input,
+	.direction_output	= mxs_gpio_direction_output,
+	.get_value		= mxs_gpio_get_value,
+	.set_value		= mxs_gpio_set_value,
+	.get_function		= mxs_gpio_get_function,
+};
+
+static int mxs_gpio_probe(struct udevice *dev)
+{
+	struct mxs_gpio_priv *priv = dev_get_priv(dev);
+	struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
+	struct fdtdec_phandle_args args;
+	int node = dev_of_offset(dev);
+	char name[16], *str;
+	fdt_addr_t addr;
+	int ret;
+
+	addr = devfdt_get_addr(dev);
+	if (addr == FDT_ADDR_T_NONE) {
+		printf("%s: No 'reg' property defined!\n", __func__);
+		return -EINVAL;
+	}
+
+	priv->bank = (unsigned int)addr;
+
+	snprintf(name, sizeof(name), "GPIO%d_", priv->bank);
+	str = strdup(name);
+	if (!str)
+		return -ENOMEM;
+
+	uc_priv->bank_name = str;
+
+	ret = fdtdec_parse_phandle_with_args(gd->fdt_blob, node, "gpio-ranges",
+					     NULL, 3, 0, &args);
+	if (ret)
+		printf("%s: 'gpio-ranges' not defined - using default!\n",
+		       __func__);
+
+	uc_priv->gpio_count = ret == 0 ? args.args[2] : MXS_MAX_GPIO_PER_BANK;
+
+	debug("%s: %s: %d pins\n", __func__, uc_priv->bank_name,
+	      uc_priv->gpio_count);
+
+	return 0;
+}
+
+static const struct udevice_id mxs_gpio_ids[] = {
+	{ .compatible = "fsl,imx23-gpio" },
+	{ .compatible = "fsl,imx28-gpio" },
+	{ }
+};
+
+U_BOOT_DRIVER(gpio_mxs) = {
+	.name	= "gpio_mxs",
+	.id	= UCLASS_GPIO,
+	.ops	= &gpio_mxs_ops,
+	.probe	= mxs_gpio_probe,
+	.priv_auto_alloc_size = sizeof(struct mxs_gpio_priv),
+	.of_match = mxs_gpio_ids,
+};
+#endif /* CONFIG_DM_GPIO */
diff --git a/drivers/misc/imx8/scu_api.c b/drivers/misc/imx8/scu_api.c
index d9c4d5d..031bc00 100644
--- a/drivers/misc/imx8/scu_api.c
+++ b/drivers/misc/imx8/scu_api.c
@@ -273,6 +273,34 @@
 	return 0;
 }
 
+int sc_misc_get_temp(sc_ipc_t ipc, sc_rsrc_t resource, sc_misc_temp_t temp,
+		     s16 *celsius, s8 *tenths)
+{
+	struct udevice *dev = gd->arch.scu_dev;
+	int size = sizeof(struct sc_rpc_msg_s);
+	struct sc_rpc_msg_s msg;
+	int ret;
+
+	RPC_VER(&msg) = SC_RPC_VERSION;
+	RPC_SVC(&msg) = (u8)SC_RPC_SVC_MISC;
+	RPC_FUNC(&msg) = (u8)MISC_FUNC_GET_TEMP;
+	RPC_U16(&msg, 0U) = (u16)resource;
+	RPC_U8(&msg, 2U) = (u8)temp;
+	RPC_SIZE(&msg) = 2U;
+
+	ret = misc_call(dev, SC_FALSE, &msg, size, &msg, size);
+	if (ret < 0)
+		return ret;
+
+	if (celsius)
+		*celsius = RPC_I16(&msg, 0U);
+
+	if (tenths)
+		*tenths = RPC_I8(&msg, 2U);
+
+	return 0;
+}
+
 /* RM */
 sc_bool_t sc_rm_is_memreg_owned(sc_ipc_t ipc, sc_rm_mr_t mr)
 {
diff --git a/drivers/mmc/mmc_spi.c b/drivers/mmc/mmc_spi.c
index f3d687a..350812a 100644
--- a/drivers/mmc/mmc_spi.c
+++ b/drivers/mmc/mmc_spi.c
@@ -84,7 +84,7 @@
 	cmdo[4] = cmdarg >> 8;
 	cmdo[5] = cmdarg;
 	cmdo[6] = (crc7(0, &cmdo[1], 5) << 1) | 0x01;
-	ret = dm_spi_xfer(dev, sizeof(cmdo) * 8, cmdo, NULL, 0);
+	ret = dm_spi_xfer(dev, sizeof(cmdo) * 8, cmdo, NULL, SPI_XFER_BEGIN);
 	if (ret)
 		return ret;
 
@@ -360,6 +360,8 @@
 	}
 
 done:
+	dm_spi_xfer(dev, 0, NULL, NULL, SPI_XFER_END);
+
 	dm_spi_release_bus(dev);
 
 	return ret;
diff --git a/drivers/mtd/nand/raw/mxs_nand.c b/drivers/mtd/nand/raw/mxs_nand.c
index b93d77a..a41b962 100644
--- a/drivers/mtd/nand/raw/mxs_nand.c
+++ b/drivers/mtd/nand/raw/mxs_nand.c
@@ -25,7 +25,7 @@
 #include <asm/mach-imx/regs-bch.h>
 #include <asm/mach-imx/regs-gpmi.h>
 #include <asm/arch/sys_proto.h>
-#include "mxs_nand.h"
+#include <mxs_nand.h>
 
 #define	MXS_NAND_DMA_DESCRIPTOR_COUNT		4
 
diff --git a/drivers/mtd/nand/raw/mxs_nand_dt.c b/drivers/mtd/nand/raw/mxs_nand_dt.c
index 44dec5d..8ad7d61 100644
--- a/drivers/mtd/nand/raw/mxs_nand_dt.c
+++ b/drivers/mtd/nand/raw/mxs_nand_dt.c
@@ -15,7 +15,7 @@
 #include <linux/ioport.h>
 #include <linux/printk.h>
 
-#include "mxs_nand.h"
+#include <mxs_nand.h>
 
 struct mxs_nand_dt_data {
 	unsigned int max_ecc_strength_supported;
diff --git a/drivers/mtd/nand/raw/mxs_nand_spl.c b/drivers/mtd/nand/raw/mxs_nand_spl.c
index ee7d9cb..975a91a 100644
--- a/drivers/mtd/nand/raw/mxs_nand_spl.c
+++ b/drivers/mtd/nand/raw/mxs_nand_spl.c
@@ -6,7 +6,7 @@
 #include <common.h>
 #include <nand.h>
 #include <malloc.h>
-#include "mxs_nand.h"
+#include <mxs_nand.h>
 
 static struct mtd_info *mtd;
 static struct nand_chip nand_chip;
diff --git a/drivers/mtd/spi/spi-nor-ids.c b/drivers/mtd/spi/spi-nor-ids.c
index ec92976..a3920ba 100644
--- a/drivers/mtd/spi/spi-nor-ids.c
+++ b/drivers/mtd/spi/spi-nor-ids.c
@@ -163,11 +163,15 @@
 	{ INFO("n25q128a13",  0x20ba18, 0, 64 * 1024,  256, SECT_4K | SPI_NOR_QUAD_READ) },
 	{ INFO("n25q256a",    0x20ba19, 0, 64 * 1024,  512, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) },
 	{ INFO("n25q256ax1",  0x20bb19, 0, 64 * 1024,  512, SECT_4K | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) },
+	{ INFO6("mt25qu512a",  0x20bb20, 0x104400, 64 * 1024, 1024,
+		 SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) },
 	{ INFO("n25q512a",    0x20bb20, 0, 64 * 1024, 1024, SECT_4K | USE_FSR | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) },
 	{ INFO("n25q512ax3",  0x20ba20, 0, 64 * 1024, 1024, SECT_4K | USE_FSR | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) },
 	{ INFO("n25q00",      0x20ba21, 0, 64 * 1024, 2048, SECT_4K | USE_FSR | SPI_NOR_QUAD_READ | NO_CHIP_ERASE) },
 	{ INFO("n25q00a",     0x20bb21, 0, 64 * 1024, 2048, SECT_4K | USE_FSR | SPI_NOR_QUAD_READ | NO_CHIP_ERASE) },
 	{ INFO("mt25qu02g",   0x20bb22, 0, 64 * 1024, 4096, SECT_4K | USE_FSR | SPI_NOR_QUAD_READ | NO_CHIP_ERASE) },
+	{ INFO("mt35xu512aba", 0x2c5b1a, 0,  128 * 1024,  512, USE_FSR | SPI_NOR_4B_OPCODES) },
+	{ INFO("mt35xu02g",  0x2c5b1c, 0, 128 * 1024,  2048, USE_FSR | SPI_NOR_4B_OPCODES) },
 #endif
 #ifdef CONFIG_SPI_FLASH_SPANSION	/* SPANSION */
 	/* Spansion/Cypress -- single (large) sector size only, at least
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index 883b849..0a1d228 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -235,7 +235,7 @@
 
 config FEC_MXC
 	bool "FEC Ethernet controller"
-	depends on MX5 || MX6 || MX7 || IMX8 || VF610
+	depends on MX28 || MX5 || MX6 || MX7 || IMX8 || VF610
 	help
 	  This driver supports the 10/100 Fast Ethernet controller for
 	  NXP i.MX processors.
diff --git a/drivers/net/fec_mxc.c b/drivers/net/fec_mxc.c
index d7c0809..96e3ad9 100644
--- a/drivers/net/fec_mxc.c
+++ b/drivers/net/fec_mxc.c
@@ -1485,6 +1485,7 @@
 }
 
 static const struct udevice_id fecmxc_ids[] = {
+	{ .compatible = "fsl,imx28-fec" },
 	{ .compatible = "fsl,imx6q-fec" },
 	{ .compatible = "fsl,imx6sl-fec" },
 	{ .compatible = "fsl,imx6sx-fec" },
diff --git a/drivers/pinctrl/nxp/Kconfig b/drivers/pinctrl/nxp/Kconfig
index 61f93be..f2e67ca 100644
--- a/drivers/pinctrl/nxp/Kconfig
+++ b/drivers/pinctrl/nxp/Kconfig
@@ -89,6 +89,16 @@
 	  only parses the 'fsl,pins' property and configure related
 	  registers.
 
+config PINCTRL_MXS
+	bool "NXP MXS pinctrl driver"
+	depends on ARCH_MX28 && PINCTRL_FULL
+	help
+	  Say Y here to enable the i.MX mxs pinctrl driver
+
+	  This option provides a simple pinctrl driver for i.MX mxs SoC
+	  familiy, e.g. i.MX28. This feature depends on device tree
+	  configuration.
+
 config PINCTRL_VYBRID
 	bool "Vybrid (vf610) pinctrl driver"
 	depends on ARCH_VF610 && PINCTRL_FULL
diff --git a/drivers/pinctrl/nxp/Makefile b/drivers/pinctrl/nxp/Makefile
index b340d94..b86448a 100644
--- a/drivers/pinctrl/nxp/Makefile
+++ b/drivers/pinctrl/nxp/Makefile
@@ -6,4 +6,5 @@
 obj-$(CONFIG_PINCTRL_IMX_SCU)		+= pinctrl-scu.o
 obj-$(CONFIG_PINCTRL_IMX8)		+= pinctrl-imx8.o
 obj-$(CONFIG_PINCTRL_IMX8M)		+= pinctrl-imx8m.o
+obj-$(CONFIG_PINCTRL_MXS)		+= pinctrl-mxs.o
 obj-$(CONFIG_PINCTRL_VYBRID)		+= pinctrl-vf610.o
diff --git a/drivers/pinctrl/nxp/pinctrl-mxs.c b/drivers/pinctrl/nxp/pinctrl-mxs.c
new file mode 100644
index 0000000..6f6ca84
--- /dev/null
+++ b/drivers/pinctrl/nxp/pinctrl-mxs.c
@@ -0,0 +1,190 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2019 DENX Software Engineering
+ * Lukasz Majewski, DENX Software Engineering, lukma@denx.de
+ */
+
+#include <common.h>
+#include <linux/io.h>
+#include <linux/err.h>
+#include <dm.h>
+#include <dm/pinctrl.h>
+#include <dm/read.h>
+#include "pinctrl-mxs.h"
+
+DECLARE_GLOBAL_DATA_PTR;
+
+struct mxs_pinctrl_priv {
+	void __iomem *base;
+	const struct mxs_regs *regs;
+};
+
+static unsigned long mxs_dt_node_to_map(struct udevice *conf)
+{
+	unsigned long config = 0;
+	int ret;
+	u32 val;
+
+	ret = dev_read_u32(conf, "fsl,drive-strength", &val);
+	if (!ret)
+		config = val | MA_PRESENT;
+
+	ret = dev_read_u32(conf, "fsl,voltage", &val);
+	if (!ret)
+		config |= val << VOL_SHIFT | VOL_PRESENT;
+
+	ret = dev_read_u32(conf, "fsl,pull-up", &val);
+	if (!ret)
+		config |= val << PULL_SHIFT | PULL_PRESENT;
+
+	return config;
+}
+
+static int mxs_pinctrl_set_mux(struct udevice *dev, u32 val, int bank, int pin)
+{
+	struct mxs_pinctrl_priv *iomux = dev_get_priv(dev);
+	int muxsel = MUXID_TO_MUXSEL(val), shift;
+	void __iomem *reg;
+
+	reg = iomux->base + iomux->regs->muxsel;
+	reg += bank * 0x20 + pin / 16 * 0x10;
+	shift = pin % 16 * 2;
+
+	mxs_pinctrl_rmwl(muxsel, 0x3, shift, reg);
+	debug(" mux %d,", muxsel);
+
+	return 0;
+}
+
+static int mxs_pinctrl_set_state(struct udevice *dev, struct udevice *conf)
+{
+	struct mxs_pinctrl_priv *iomux = dev_get_priv(dev);
+	u32 *pin_data, val, ma, vol, pull;
+	int npins, size, i, ret;
+	unsigned long config;
+
+	debug("\n%s: set state: %s\n", __func__, conf->name);
+
+	size = dev_read_size(conf, "fsl,pinmux-ids");
+	if (size < 0)
+		return size;
+
+	if (!size || size % sizeof(int)) {
+		dev_err(dev, "Invalid fsl,pinmux-ids property in %s\n",
+			conf->name);
+		return -EINVAL;
+	}
+
+	npins = size / sizeof(int);
+
+	pin_data = devm_kzalloc(dev, size, 0);
+	if (!pin_data)
+		return -ENOMEM;
+
+	ret = dev_read_u32_array(conf, "fsl,pinmux-ids", pin_data, npins);
+	if (ret) {
+		dev_err(dev, "Error reading pin data.\n");
+		devm_kfree(dev, pin_data);
+		return -EINVAL;
+	}
+
+	config = mxs_dt_node_to_map(conf);
+
+	ma = CONFIG_TO_MA(config);
+	vol = CONFIG_TO_VOL(config);
+	pull = CONFIG_TO_PULL(config);
+
+	for (i = 0; i < npins; i++) {
+		int pinid, bank, pin, shift;
+		void __iomem *reg;
+
+		val = pin_data[i];
+
+		pinid = MUXID_TO_PINID(val);
+		bank = PINID_TO_BANK(pinid);
+		pin = PINID_TO_PIN(pinid);
+
+		debug("(val: 0x%x) pin %d,", val, pinid);
+		/* Setup pinmux */
+		mxs_pinctrl_set_mux(dev, val, bank, pin);
+
+		debug(" ma: %d, vol: %d, pull: %d\n", ma, vol, pull);
+
+		/* drive */
+		reg = iomux->base + iomux->regs->drive;
+		reg += bank * 0x40 + pin / 8 * 0x10;
+
+		/* mA */
+		if (config & MA_PRESENT) {
+			shift = pin % 8 * 4;
+			mxs_pinctrl_rmwl(ma, 0x3, shift, reg);
+		}
+
+		/* vol */
+		if (config & VOL_PRESENT) {
+			shift = pin % 8 * 4 + 2;
+			if (vol)
+				writel(1 << shift, reg + SET);
+			else
+				writel(1 << shift, reg + CLR);
+		}
+
+		/* pull */
+		if (config & PULL_PRESENT) {
+			reg = iomux->base + iomux->regs->pull;
+			reg += bank * 0x10;
+			shift = pin;
+			if (pull)
+				writel(1 << shift, reg + SET);
+			else
+				writel(1 << shift, reg + CLR);
+		}
+	}
+
+	devm_kfree(dev, pin_data);
+	return 0;
+}
+
+static struct pinctrl_ops mxs_pinctrl_ops = {
+	.set_state = mxs_pinctrl_set_state,
+};
+
+static int mxs_pinctrl_probe(struct udevice *dev)
+{
+	struct mxs_pinctrl_priv *iomux = dev_get_priv(dev);
+
+	iomux->base = dev_read_addr_ptr(dev);
+	iomux->regs = (struct mxs_regs *)dev_get_driver_data(dev);
+
+	return 0;
+}
+
+static const struct mxs_regs imx23_regs = {
+	.muxsel = 0x100,
+	.drive = 0x200,
+	.pull = 0x400,
+};
+
+static const struct mxs_regs imx28_regs = {
+	.muxsel = 0x100,
+	.drive = 0x300,
+	.pull = 0x600,
+};
+
+static const struct udevice_id mxs_pinctrl_match[] = {
+	{ .compatible = "fsl,imx23-pinctrl", .data = (ulong)&imx23_regs },
+	{ .compatible = "fsl,imx28-pinctrl", .data = (ulong)&imx28_regs },
+	{ /* sentinel */ }
+};
+
+U_BOOT_DRIVER(mxs_pinctrl) = {
+	.name = "mxs-pinctrl",
+	.id = UCLASS_PINCTRL,
+	.of_match = of_match_ptr(mxs_pinctrl_match),
+	.probe = mxs_pinctrl_probe,
+#if !CONFIG_IS_ENABLED(OF_PLATDATA)
+	.bind		= dm_scan_fdt_dev,
+#endif
+	.priv_auto_alloc_size = sizeof(struct mxs_pinctrl_priv),
+	.ops = &mxs_pinctrl_ops,
+};
diff --git a/drivers/pinctrl/nxp/pinctrl-mxs.h b/drivers/pinctrl/nxp/pinctrl-mxs.h
new file mode 100644
index 0000000..a398e43
--- /dev/null
+++ b/drivers/pinctrl/nxp/pinctrl-mxs.h
@@ -0,0 +1,61 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2012 Freescale Semiconductor, Inc.
+ */
+
+#ifndef __PINCTRL_MXS_H
+#define __PINCTRL_MXS_H
+
+#include <dm/pinctrl.h>
+
+#define SET	0x4
+#define CLR	0x8
+#define TOG	0xc
+
+#define MXS_PINCTRL_PIN(pin)	PINCTRL_PIN(pin, #pin)
+#define PINID(bank, pin)	((bank) * 32 + (pin))
+
+/*
+ * pinmux-id bit field definitions
+ *
+ * bank:	15..12	(4)
+ * pin:		11..4	(8)
+ * muxsel:	3..0	(4)
+ */
+#define MUXID_TO_PINID(m)	PINID((m) >> 12 & 0xf, (m) >> 4 & 0xff)
+#define MUXID_TO_MUXSEL(m)	((m) & 0xf)
+
+#define PINID_TO_BANK(p)	((p) >> 5)
+#define PINID_TO_PIN(p)		((p) % 32)
+
+/*
+ * pin config bit field definitions
+ *
+ * pull-up:	6..5	(2)
+ * voltage:	4..3	(2)
+ * mA:		2..0	(3)
+ *
+ * MSB of each field is presence bit for the config.
+ */
+#define PULL_PRESENT		(1 << 6)
+#define PULL_SHIFT		5
+#define VOL_PRESENT		(1 << 4)
+#define VOL_SHIFT		3
+#define MA_PRESENT		(1 << 2)
+#define MA_SHIFT		0
+#define CONFIG_TO_PULL(c)	((c) >> PULL_SHIFT & 0x1)
+#define CONFIG_TO_VOL(c)	((c) >> VOL_SHIFT & 0x1)
+#define CONFIG_TO_MA(c)		((c) >> MA_SHIFT & 0x3)
+
+struct mxs_regs {
+	u16 muxsel;
+	u16 drive;
+	u16 pull;
+};
+
+static inline void mxs_pinctrl_rmwl(u32 value, u32 mask, u8 shift,
+				    void __iomem *reg)
+{
+	clrsetbits_le32(reg, mask << shift, value << shift);
+}
+#endif /* __PINCTRL_MXS_H */
diff --git a/drivers/power/pmic/bd71837.c b/drivers/power/pmic/bd71837.c
index 24d9f7f..e292d42 100644
--- a/drivers/power/pmic/bd71837.c
+++ b/drivers/power/pmic/bd71837.c
@@ -3,6 +3,8 @@
  * Copyright 2018 NXP
  */
 
+#define DEBUG
+
 #include <common.h>
 #include <errno.h>
 #include <dm.h>
@@ -15,15 +17,15 @@
 
 static const struct pmic_child_info pmic_children_info[] = {
 	/* buck */
-	{ .prefix = "b", .driver = BD71837_REGULATOR_DRIVER},
+	{ .prefix = "b", .driver = BD718XX_REGULATOR_DRIVER},
 	/* ldo */
-	{ .prefix = "l", .driver = BD71837_REGULATOR_DRIVER},
+	{ .prefix = "l", .driver = BD718XX_REGULATOR_DRIVER},
 	{ },
 };
 
 static int bd71837_reg_count(struct udevice *dev)
 {
-	return BD71837_REG_NUM;
+	return BD718XX_MAX_REGISTER - 1;
 }
 
 static int bd71837_write(struct udevice *dev, uint reg, const uint8_t *buff,
@@ -54,7 +56,7 @@
 
 	regulators_node = dev_read_subnode(dev, "regulators");
 	if (!ofnode_valid(regulators_node)) {
-		debug("%s: %s regulators subnode not found!", __func__,
+		debug("%s: %s regulators subnode not found!\n", __func__,
 		      dev->name);
 		return -ENXIO;
 	}
@@ -69,6 +71,24 @@
 	return 0;
 }
 
+static int bd718x7_probe(struct udevice *dev)
+{
+	int ret;
+	uint8_t mask = BD718XX_REGLOCK_PWRSEQ | BD718XX_REGLOCK_VREG;
+
+	/* Unlock the PMIC regulator control before probing the children */
+	ret = pmic_clrsetbits(dev, BD718XX_REGLOCK, mask, 0);
+	if (ret) {
+		debug("%s: %s Failed to unlock regulator control\n", __func__,
+		      dev->name);
+		return ret;
+	}
+	debug("%s: '%s' - BD718x7 PMIC registers unlocked\n", __func__,
+	      dev->name);
+
+	return 0;
+}
+
 static struct dm_pmic_ops bd71837_ops = {
 	.reg_count = bd71837_reg_count,
 	.read = bd71837_read,
@@ -76,7 +96,8 @@
 };
 
 static const struct udevice_id bd71837_ids[] = {
-	{ .compatible = "rohm,bd71837", .data = 0x4b, },
+	{ .compatible = "rohm,bd71837", .data = ROHM_CHIP_TYPE_BD71837, },
+	{ .compatible = "rohm,bd71847", .data = ROHM_CHIP_TYPE_BD71847, },
 	{ }
 };
 
@@ -85,5 +106,6 @@
 	.id = UCLASS_PMIC,
 	.of_match = bd71837_ids,
 	.bind = bd71837_bind,
+	.probe = bd718x7_probe,
 	.ops = &bd71837_ops,
 };
diff --git a/drivers/power/regulator/Kconfig b/drivers/power/regulator/Kconfig
index 337e9e7..9aa00fa 100644
--- a/drivers/power/regulator/Kconfig
+++ b/drivers/power/regulator/Kconfig
@@ -43,6 +43,23 @@
 	  but does not yet support change voltages. Currently this must be
 	  done using direct register writes to the PMIC.
 
+config DM_REGULATOR_BD71837
+	bool "Enable Driver Model for ROHM BD71837/BD71847 regulators"
+	depends on DM_REGULATOR && DM_PMIC_BD71837
+	help
+	This config enables implementation of driver-model regulator uclass
+	features for regulators on ROHM BD71837 and BD71847 PMICs.
+	BD71837 contains 8 bucks and 7 LDOS. BD71847 is reduced version
+	containing 6 bucks and 6 LDOs. The driver implements get/set api for
+	value and enable.
+
+config SPL_DM_REGULATOR_BD71837
+	bool "Enable Driver Model for ROHM BD71837/BD71847 regulators in SPL"
+	depends on DM_REGULATOR_BD71837
+	help
+	This config enables implementation of driver-model regulator uclass
+	features for regulators on ROHM BD71837 and BD71847 in SPL.
+
 config DM_REGULATOR_PFUZE100
 	bool "Enable Driver Model for REGULATOR PFUZE100"
 	depends on DM_REGULATOR && DM_PMIC_PFUZE100
diff --git a/drivers/power/regulator/Makefile b/drivers/power/regulator/Makefile
index e728b73..6a3d4bb 100644
--- a/drivers/power/regulator/Makefile
+++ b/drivers/power/regulator/Makefile
@@ -9,6 +9,7 @@
 obj-$(CONFIG_REGULATOR_AS3722)	+= as3722_regulator.o
 obj-$(CONFIG_DM_REGULATOR_MAX77686) += max77686.o
 obj-$(CONFIG_$(SPL_)DM_PMIC_PFUZE100) += pfuze100.o
+obj-$(CONFIG_$(SPL_)DM_REGULATOR_BD71837) += bd71837.o
 obj-$(CONFIG_$(SPL_)REGULATOR_PWM) += pwm_regulator.o
 obj-$(CONFIG_$(SPL_)DM_REGULATOR_FAN53555) += fan53555.o
 obj-$(CONFIG_$(SPL_)DM_REGULATOR_COMMON) += regulator_common.o
diff --git a/drivers/power/regulator/bd71837.c b/drivers/power/regulator/bd71837.c
new file mode 100644
index 0000000..575429a
--- /dev/null
+++ b/drivers/power/regulator/bd71837.c
@@ -0,0 +1,468 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) 2019 ROHM Semiconductors
+ *
+ * ROHM BD71837 regulator driver
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <power/bd71837.h>
+#include <power/pmic.h>
+#include <power/regulator.h>
+
+#define HW_STATE_CONTROL 0
+#define DEBUG
+
+/**
+ * struct bd71837_vrange - describe linear range of voltages
+ *
+ * @min_volt:	smallest voltage in range
+ * @step:	how much voltage changes at each selector step
+ * @min_sel:	smallest selector in the range
+ * @max_sel:	maximum selector in the range
+ * @rangeval:	register value used to select this range if selectible
+ *		ranges are supported
+ */
+struct bd71837_vrange {
+	unsigned int	min_volt;
+	unsigned int	step;
+	u8		min_sel;
+	u8		max_sel;
+	u8		rangeval;
+};
+
+/**
+ * struct bd71837_platdata - describe regulator control registers
+ *
+ * @name:	name of the regulator. Used for matching the dt-entry
+ * @enable_reg:	register address used to enable/disable regulator
+ * @enablemask:	register mask used to enable/disable regulator
+ * @volt_reg:	register address used to configure regulator voltage
+ * @volt_mask:	register mask used to configure regulator voltage
+ * @ranges:	pointer to ranges of regulator voltages and matching register
+ *		values
+ * @numranges:	number of voltage ranges pointed by ranges
+ * @rangemask:	mask for selecting used ranges if multiple ranges are supported
+ * @sel_mask:	bit to toggle in order to transfer the register control to SW
+ * @dvs:	whether the voltage can be changed when regulator is enabled
+ */
+struct bd71837_platdata {
+	const char		*name;
+	u8			enable_reg;
+	u8			enablemask;
+	u8			volt_reg;
+	u8			volt_mask;
+	struct bd71837_vrange	*ranges;
+	unsigned int		numranges;
+	u8			rangemask;
+	u8			sel_mask;
+	bool			dvs;
+};
+
+#define BD_RANGE(_min, _vstep, _sel_low, _sel_hi, _range_sel) \
+{ \
+	.min_volt = (_min), .step = (_vstep), .min_sel = (_sel_low), \
+	.max_sel = (_sel_hi), .rangeval = (_range_sel) \
+}
+
+#define BD_DATA(_name, enreg, enmask, vreg, vmask, _range, rmask, _dvs, sel) \
+{ \
+	.name = (_name), .enable_reg = (enreg), .enablemask = (enmask), \
+	.volt_reg = (vreg), .volt_mask = (vmask), .ranges = (_range), \
+	.numranges = ARRAY_SIZE(_range), .rangemask = (rmask), .dvs = (_dvs), \
+	.sel_mask = (sel) \
+}
+
+static struct bd71837_vrange dvs_buck_vranges[] = {
+	BD_RANGE(700000, 10000, 0, 0x3c, 0),
+	BD_RANGE(1300000, 0, 0x3d, 0x3f, 0),
+};
+
+static struct bd71837_vrange bd71847_buck3_vranges[] = {
+	BD_RANGE(700000, 100000, 0x00, 0x03, 0),
+	BD_RANGE(1050000, 50000, 0x04, 0x05, 0),
+	BD_RANGE(1200000, 150000, 0x06, 0x07, 0),
+	BD_RANGE(550000, 50000, 0x0, 0x7, 0x40),
+	BD_RANGE(675000, 100000, 0x0, 0x3, 0x80),
+	BD_RANGE(1025000, 50000, 0x4, 0x5, 0x80),
+	BD_RANGE(1175000, 150000, 0x6, 0x7, 0x80),
+};
+
+static struct bd71837_vrange bd71847_buck4_vranges[] = {
+	BD_RANGE(3000000, 100000, 0x00, 0x03, 0),
+	BD_RANGE(2600000, 100000, 0x00, 0x03, 40),
+};
+
+static struct bd71837_vrange bd71837_buck5_vranges[] = {
+	BD_RANGE(700000, 100000, 0, 0x3, 0),
+	BD_RANGE(1050000, 50000, 0x04, 0x05, 0),
+	BD_RANGE(1200000, 150000, 0x06, 0x07, 0),
+	BD_RANGE(675000, 100000, 0x0, 0x3, 0x80),
+	BD_RANGE(1025000, 50000, 0x04, 0x05, 0x80),
+	BD_RANGE(1175000, 150000, 0x06, 0x07, 0x80),
+};
+
+static struct bd71837_vrange bd71837_buck6_vranges[] = {
+	BD_RANGE(3000000, 100000, 0x00, 0x03, 0),
+};
+
+static struct bd71837_vrange nodvs_buck3_vranges[] = {
+	BD_RANGE(1605000, 90000, 0, 1, 0),
+	BD_RANGE(1755000, 45000, 2, 4, 0),
+	BD_RANGE(1905000, 45000, 5, 7, 0),
+};
+
+static struct bd71837_vrange nodvs_buck4_vranges[] = {
+	BD_RANGE(800000, 10000, 0x00, 0x3C, 0),
+};
+
+static struct bd71837_vrange ldo1_vranges[] = {
+	BD_RANGE(3000000, 100000, 0x00, 0x03, 0),
+	BD_RANGE(1600000, 100000, 0x00, 0x03, 0x20),
+};
+
+static struct bd71837_vrange ldo2_vranges[] = {
+	BD_RANGE(900000, 0, 0, 0, 0),
+	BD_RANGE(800000, 0, 1, 1, 0),
+};
+
+static struct bd71837_vrange ldo3_vranges[] = {
+	BD_RANGE(1800000, 100000, 0x00, 0x0f, 0),
+};
+
+static struct bd71837_vrange ldo4_vranges[] = {
+	BD_RANGE(900000, 100000, 0x00, 0x09, 0),
+};
+
+static struct bd71837_vrange bd71837_ldo5_vranges[] = {
+	BD_RANGE(1800000, 100000, 0x00, 0x0f, 0),
+};
+
+static struct bd71837_vrange bd71847_ldo5_vranges[] = {
+	BD_RANGE(1800000, 100000, 0x00, 0x0f, 0),
+	BD_RANGE(800000, 100000, 0x00, 0x0f, 0x20),
+};
+
+static struct bd71837_vrange ldo6_vranges[] = {
+	BD_RANGE(900000, 100000, 0x00, 0x09, 0),
+};
+
+static struct bd71837_vrange ldo7_vranges[] = {
+	BD_RANGE(1800000, 100000, 0x00, 0x0f, 0),
+};
+
+/*
+ * We use enable mask 'HW_STATE_CONTROL' to indicate that this regulator
+ * must not be enabled or disabled by SW. The typical use-case for BD71837
+ * is powering NXP i.MX8. In this use-case we (for now) only allow control
+ * for BUCK3 and BUCK4 which are not boot critical.
+ */
+static struct bd71837_platdata bd71837_reg_data[] = {
+/* Bucks 1-4 which support dynamic voltage scaling */
+	BD_DATA("BUCK1", BD718XX_BUCK1_CTRL, HW_STATE_CONTROL,
+		BD718XX_BUCK1_VOLT_RUN, DVS_BUCK_RUN_MASK, dvs_buck_vranges, 0,
+		true, BD718XX_BUCK_SEL),
+	BD_DATA("BUCK2", BD718XX_BUCK2_CTRL, HW_STATE_CONTROL,
+		BD718XX_BUCK2_VOLT_RUN, DVS_BUCK_RUN_MASK, dvs_buck_vranges, 0,
+		true, BD718XX_BUCK_SEL),
+	BD_DATA("BUCK3", BD71837_BUCK3_CTRL, BD718XX_BUCK_EN,
+		BD71837_BUCK3_VOLT_RUN, DVS_BUCK_RUN_MASK, dvs_buck_vranges, 0,
+		true, BD718XX_BUCK_SEL),
+	BD_DATA("BUCK4", BD71837_BUCK4_CTRL, BD718XX_BUCK_EN,
+		BD71837_BUCK4_VOLT_RUN, DVS_BUCK_RUN_MASK, dvs_buck_vranges, 0,
+		true, BD718XX_BUCK_SEL),
+/* Bucks 5-8 which do not support dynamic voltage scaling */
+	BD_DATA("BUCK5", BD718XX_1ST_NODVS_BUCK_CTRL, HW_STATE_CONTROL,
+		BD718XX_1ST_NODVS_BUCK_VOLT, BD718XX_1ST_NODVS_BUCK_MASK,
+		bd71837_buck5_vranges, 0x80, false, BD718XX_BUCK_SEL),
+	BD_DATA("BUCK6", BD718XX_2ND_NODVS_BUCK_CTRL, HW_STATE_CONTROL,
+		BD718XX_2ND_NODVS_BUCK_VOLT, BD71837_BUCK6_MASK,
+		bd71837_buck6_vranges, 0, false, BD718XX_BUCK_SEL),
+	BD_DATA("BUCK7", BD718XX_3RD_NODVS_BUCK_CTRL, HW_STATE_CONTROL,
+		BD718XX_3RD_NODVS_BUCK_VOLT, BD718XX_3RD_NODVS_BUCK_MASK,
+		nodvs_buck3_vranges, 0, false, BD718XX_BUCK_SEL),
+	BD_DATA("BUCK8", BD718XX_4TH_NODVS_BUCK_CTRL, HW_STATE_CONTROL,
+		BD718XX_4TH_NODVS_BUCK_VOLT, BD718XX_4TH_NODVS_BUCK_MASK,
+		nodvs_buck4_vranges, 0, false, BD718XX_BUCK_SEL),
+/* LDOs */
+	BD_DATA("LDO1", BD718XX_LDO1_VOLT, HW_STATE_CONTROL, BD718XX_LDO1_VOLT,
+		BD718XX_LDO1_MASK, ldo1_vranges, 0x20, false, BD718XX_LDO_SEL),
+	BD_DATA("LDO2", BD718XX_LDO2_VOLT, HW_STATE_CONTROL, BD718XX_LDO2_VOLT,
+		BD718XX_LDO2_MASK, ldo2_vranges, 0, false, BD718XX_LDO_SEL),
+	BD_DATA("LDO3", BD718XX_LDO3_VOLT, HW_STATE_CONTROL, BD718XX_LDO3_VOLT,
+		BD718XX_LDO3_MASK, ldo3_vranges, 0, false, BD718XX_LDO_SEL),
+	BD_DATA("LDO4", BD718XX_LDO4_VOLT, HW_STATE_CONTROL, BD718XX_LDO4_VOLT,
+		BD718XX_LDO4_MASK, ldo4_vranges, 0, false, BD718XX_LDO_SEL),
+	BD_DATA("LDO5", BD718XX_LDO5_VOLT, HW_STATE_CONTROL, BD718XX_LDO5_VOLT,
+		BD71837_LDO5_MASK, bd71837_ldo5_vranges, 0, false,
+		BD718XX_LDO_SEL),
+	BD_DATA("LDO6", BD718XX_LDO6_VOLT, HW_STATE_CONTROL, BD718XX_LDO6_VOLT,
+		BD718XX_LDO6_MASK, ldo6_vranges, 0, false, BD718XX_LDO_SEL),
+	BD_DATA("LDO7", BD71837_LDO7_VOLT, HW_STATE_CONTROL, BD71837_LDO7_VOLT,
+		BD71837_LDO7_MASK, ldo7_vranges, 0, false, BD718XX_LDO_SEL),
+};
+
+static struct bd71837_platdata bd71847_reg_data[] = {
+/* Bucks 1 and 2 which support dynamic voltage scaling */
+	BD_DATA("BUCK1", BD718XX_BUCK1_CTRL, HW_STATE_CONTROL,
+		BD718XX_BUCK1_VOLT_RUN, DVS_BUCK_RUN_MASK, dvs_buck_vranges, 0,
+		true, BD718XX_BUCK_SEL),
+	BD_DATA("BUCK2", BD718XX_BUCK2_CTRL, HW_STATE_CONTROL,
+		BD718XX_BUCK2_VOLT_RUN, DVS_BUCK_RUN_MASK, dvs_buck_vranges, 0,
+		true, BD718XX_BUCK_SEL),
+/* Bucks 3-6 which do not support dynamic voltage scaling */
+	BD_DATA("BUCK3", BD718XX_1ST_NODVS_BUCK_CTRL, HW_STATE_CONTROL,
+		BD718XX_1ST_NODVS_BUCK_VOLT, BD718XX_1ST_NODVS_BUCK_MASK,
+		bd71847_buck3_vranges, 0xc0, false, BD718XX_BUCK_SEL),
+	BD_DATA("BUCK4", BD718XX_2ND_NODVS_BUCK_CTRL, HW_STATE_CONTROL,
+		BD718XX_2ND_NODVS_BUCK_VOLT, BD71837_BUCK6_MASK,
+		bd71847_buck4_vranges, 0x40, false, BD718XX_BUCK_SEL),
+	BD_DATA("BUCK5", BD718XX_3RD_NODVS_BUCK_CTRL, HW_STATE_CONTROL,
+		BD718XX_3RD_NODVS_BUCK_VOLT, BD718XX_3RD_NODVS_BUCK_MASK,
+		nodvs_buck3_vranges, 0, false, BD718XX_BUCK_SEL),
+	BD_DATA("BUCK6", BD718XX_4TH_NODVS_BUCK_CTRL, HW_STATE_CONTROL,
+		BD718XX_4TH_NODVS_BUCK_VOLT, BD718XX_4TH_NODVS_BUCK_MASK,
+		nodvs_buck4_vranges, 0, false, BD718XX_BUCK_SEL),
+/* LDOs */
+	BD_DATA("LDO1", BD718XX_LDO1_VOLT, HW_STATE_CONTROL, BD718XX_LDO1_VOLT,
+		BD718XX_LDO1_MASK, ldo1_vranges, 0x20, false, BD718XX_LDO_SEL),
+	BD_DATA("LDO2", BD718XX_LDO2_VOLT, HW_STATE_CONTROL, BD718XX_LDO2_VOLT,
+		BD718XX_LDO2_MASK, ldo2_vranges, 0, false, BD718XX_LDO_SEL),
+	BD_DATA("LDO3", BD718XX_LDO3_VOLT, HW_STATE_CONTROL, BD718XX_LDO3_VOLT,
+		BD718XX_LDO3_MASK, ldo3_vranges, 0, false, BD718XX_LDO_SEL),
+	BD_DATA("LDO4", BD718XX_LDO4_VOLT, HW_STATE_CONTROL, BD718XX_LDO4_VOLT,
+		BD718XX_LDO4_MASK, ldo4_vranges, 0, false, BD718XX_LDO_SEL),
+	BD_DATA("LDO5", BD718XX_LDO5_VOLT, HW_STATE_CONTROL, BD718XX_LDO5_VOLT,
+		BD71847_LDO5_MASK, bd71847_ldo5_vranges, 0x20, false,
+		BD718XX_LDO_SEL),
+	BD_DATA("LDO6", BD718XX_LDO6_VOLT, HW_STATE_CONTROL, BD718XX_LDO6_VOLT,
+		BD718XX_LDO6_MASK, ldo6_vranges, 0, false, BD718XX_LDO_SEL),
+};
+
+static int vrange_find_value(struct bd71837_vrange *r, unsigned int sel,
+			     unsigned int *val)
+{
+	if (!val || sel < r->min_sel || sel > r->max_sel)
+		return -EINVAL;
+
+	*val = r->min_volt + r->step * (sel - r->min_sel);
+	return 0;
+}
+
+static int vrange_find_selector(struct bd71837_vrange *r, int val,
+				unsigned int *sel)
+{
+	int ret = -EINVAL;
+	int num_vals = r->max_sel - r->min_sel + 1;
+
+	if (val >= r->min_volt &&
+	    val <= r->min_volt + r->step * (num_vals - 1)) {
+		if (r->step) {
+			*sel = r->min_sel + ((val - r->min_volt) / r->step);
+			ret = 0;
+		} else {
+			*sel = r->min_sel;
+			ret = 0;
+		}
+	}
+	return ret;
+}
+
+static int bd71837_get_enable(struct udevice *dev)
+{
+	int val;
+	struct bd71837_platdata *plat = dev_get_platdata(dev);
+
+	/*
+	 * boot critical regulators on bd71837 must not be controlled by sw
+	 * due to the 'feature' which leaves power rails down if bd71837 is
+	 * reseted to snvs state. hence we can't get the state here.
+	 *
+	 * if we are alive it means we probably are on run state and
+	 * if the regulator can't be controlled we can assume it is
+	 * enabled.
+	 */
+	if (plat->enablemask == HW_STATE_CONTROL)
+		return 1;
+
+	val = pmic_reg_read(dev->parent, plat->enable_reg);
+	if (val < 0)
+		return val;
+
+	return (val & plat->enablemask);
+}
+
+static int bd71837_set_enable(struct udevice *dev, bool enable)
+{
+	int val = 0;
+	struct bd71837_platdata *plat = dev_get_platdata(dev);
+
+	/*
+	 * boot critical regulators on bd71837 must not be controlled by sw
+	 * due to the 'feature' which leaves power rails down if bd71837 is
+	 * reseted to snvs state. Hence we can't set the state here.
+	 */
+	if (plat->enablemask == HW_STATE_CONTROL)
+		return -EINVAL;
+
+	if (enable)
+		val = plat->enablemask;
+
+	return pmic_clrsetbits(dev->parent, plat->enable_reg, plat->enablemask,
+			       val);
+}
+
+static int bd71837_set_value(struct udevice *dev, int uvolt)
+{
+	unsigned int sel;
+	unsigned int range;
+	int i;
+	int found = 0;
+	struct bd71837_platdata *plat = dev_get_platdata(dev);
+
+	/*
+	 * An under/overshooting may occur if voltage is changed for other
+	 * regulators but buck 1,2,3 or 4 when regulator is enabled. Prevent
+	 * change to protect the HW
+	 */
+	if (!plat->dvs)
+		if (bd71837_get_enable(dev)) {
+			pr_err("Only DVS bucks can be changed when enabled\n");
+			return -EINVAL;
+		}
+
+	for (i = 0; i < plat->numranges; i++) {
+		struct bd71837_vrange *r = &plat->ranges[i];
+
+		found = !vrange_find_selector(r, uvolt, &sel);
+		if (found) {
+			unsigned int tmp;
+
+			/*
+			 * We require exactly the requested value to be
+			 * supported - this can be changed later if needed
+			 */
+			range = r->rangeval;
+			found = !vrange_find_value(r, sel, &tmp);
+			if (found && tmp == uvolt)
+				break;
+			found = 0;
+		}
+	}
+
+	if (!found)
+		return -EINVAL;
+
+	sel <<= ffs(plat->volt_mask) - 1;
+
+	if (plat->rangemask)
+		sel |= range;
+
+	return pmic_clrsetbits(dev->parent, plat->volt_reg, plat->volt_mask |
+			       plat->rangemask, sel);
+}
+
+static int bd71837_get_value(struct udevice *dev)
+{
+	unsigned int reg, range;
+	unsigned int tmp;
+	struct bd71837_platdata *plat = dev_get_platdata(dev);
+	int i;
+
+	reg = pmic_reg_read(dev->parent, plat->volt_reg);
+	if (((int)reg) < 0)
+		return reg;
+
+	range = reg & plat->rangemask;
+
+	reg &= plat->volt_mask;
+	reg >>= ffs(plat->volt_mask) - 1;
+
+	for (i = 0; i < plat->numranges; i++) {
+		struct bd71837_vrange *r = &plat->ranges[i];
+
+		if (plat->rangemask && ((plat->rangemask & range) !=
+		    r->rangeval))
+			continue;
+
+		if (!vrange_find_value(r, reg, &tmp))
+			return tmp;
+	}
+
+	pr_err("Unknown voltage value read from pmic\n");
+
+	return -EINVAL;
+}
+
+static int bd71837_regulator_probe(struct udevice *dev)
+{
+	struct bd71837_platdata *plat = dev_get_platdata(dev);
+	int i, ret;
+	struct dm_regulator_uclass_platdata *uc_pdata;
+	int type;
+	struct bd71837_platdata *init_data;
+	int data_amnt;
+
+	type = dev_get_driver_data(dev_get_parent(dev));
+
+	switch (type) {
+	case ROHM_CHIP_TYPE_BD71837:
+		init_data = bd71837_reg_data;
+		data_amnt = ARRAY_SIZE(bd71837_reg_data);
+		break;
+	case ROHM_CHIP_TYPE_BD71847:
+		init_data = bd71847_reg_data;
+		data_amnt = ARRAY_SIZE(bd71847_reg_data);
+		break;
+	default:
+		debug("Unknown PMIC type\n");
+		init_data = NULL;
+		data_amnt = 0;
+		break;
+	}
+
+	for (i = 0; i < data_amnt; i++) {
+		if (!strcmp(dev->name, init_data[i].name)) {
+			*plat = init_data[i];
+			if (plat->enablemask != HW_STATE_CONTROL) {
+				/*
+				 * Take the regulator under SW control. Ensure
+				 * the initial state matches dt flags and then
+				 * write the SEL bit
+				 */
+				uc_pdata = dev_get_uclass_platdata(dev);
+				ret = bd71837_set_enable(dev,
+							 !!(uc_pdata->boot_on ||
+							 uc_pdata->always_on));
+				if (ret)
+					return ret;
+
+				return pmic_clrsetbits(dev->parent,
+						      plat->enable_reg,
+						      plat->sel_mask,
+						      plat->sel_mask);
+			}
+			return 0;
+		}
+	}
+
+	pr_err("Unknown regulator '%s'\n", dev->name);
+
+	return -ENOENT;
+}
+
+static const struct dm_regulator_ops bd71837_regulator_ops = {
+	.get_value  = bd71837_get_value,
+	.set_value  = bd71837_set_value,
+	.get_enable = bd71837_get_enable,
+	.set_enable = bd71837_set_enable,
+};
+
+U_BOOT_DRIVER(bd71837_regulator) = {
+	.name = BD718XX_REGULATOR_DRIVER,
+	.id = UCLASS_REGULATOR,
+	.ops = &bd71837_regulator_ops,
+	.probe = bd71837_regulator_probe,
+	.platdata_auto_alloc_size = sizeof(struct bd71837_platdata),
+};
diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig
index 2984b79..1f36fc7 100644
--- a/drivers/pwm/Kconfig
+++ b/drivers/pwm/Kconfig
@@ -18,6 +18,11 @@
 	  used. It provides 5 channels which can be independently
 	  programmed. Channel 4 (the last) is normally used as a timer.
 
+config PWM_IMX
+	bool "Enable support for i.MX27 and later PWM"
+	help
+	  This PWM is found i.MX27 and later i.MX SoCs.
+
 config PWM_ROCKCHIP
 	bool "Enable support for the Rockchip PWM"
 	depends on DM_PWM
diff --git a/drivers/pwm/pwm-imx.c b/drivers/pwm/pwm-imx.c
index 83c1bfa..8d8f3e6 100644
--- a/drivers/pwm/pwm-imx.c
+++ b/drivers/pwm/pwm-imx.c
@@ -8,6 +8,7 @@
 
 #include <common.h>
 #include <div64.h>
+#include <dm.h>
 #include <pwm.h>
 #include <asm/arch/imx-regs.h>
 #include <asm/io.h>
@@ -24,18 +25,12 @@
 	return 0;
 }
 
-int pwm_config(int pwm_id, int duty_ns, int period_ns)
+int pwm_config_internal(struct pwm_regs *pwm, unsigned long period_cycles,
+			unsigned long duty_cycles, unsigned long prescale)
 {
-	struct pwm_regs *pwm = (struct pwm_regs *)pwm_id_to_reg(pwm_id);
-	unsigned long period_cycles, duty_cycles, prescale;
 	u32 cr;
 
-	if (!pwm)
-		return -1;
-
-	pwm_imx_get_parms(period_ns, duty_ns, &period_cycles, &duty_cycles,
-			  &prescale);
-
+	writel(0, &pwm->ir);
 	cr = PWMCR_PRESCALER(prescale) |
 		PWMCR_DOZEEN | PWMCR_WAITEN |
 		PWMCR_DBGEN | PWMCR_CLKSRC_IPG_HIGH;
@@ -48,6 +43,20 @@
 	return 0;
 }
 
+int pwm_config(int pwm_id, int duty_ns, int period_ns)
+{
+	struct pwm_regs *pwm = (struct pwm_regs *)pwm_id_to_reg(pwm_id);
+	unsigned long period_cycles, duty_cycles, prescale;
+
+	if (!pwm)
+		return -1;
+
+	pwm_imx_get_parms(period_ns, duty_ns, &period_cycles, &duty_cycles,
+			  &prescale);
+
+	return pwm_config_internal(pwm, period_cycles, duty_cycles, prescale);
+}
+
 int pwm_enable(int pwm_id)
 {
 	struct pwm_regs *pwm = (struct pwm_regs *)pwm_id_to_reg(pwm_id);
@@ -68,3 +77,86 @@
 
 	clrbits_le32(&pwm->cr, PWMCR_EN);
 }
+
+#if defined(CONFIG_DM_PWM)
+struct imx_pwm_priv {
+	struct pwm_regs *regs;
+	bool invert;
+};
+
+static int imx_pwm_set_invert(struct udevice *dev, uint channel,
+			      bool polarity)
+{
+	struct imx_pwm_priv *priv = dev_get_priv(dev);
+
+	debug("%s: polarity=%u\n", __func__, polarity);
+	priv->invert = polarity;
+
+	return 0;
+}
+
+static int imx_pwm_set_config(struct udevice *dev, uint channel,
+			      uint period_ns, uint duty_ns)
+{
+	struct imx_pwm_priv *priv = dev_get_priv(dev);
+	struct pwm_regs *regs = priv->regs;
+	unsigned long period_cycles, duty_cycles, prescale;
+
+	debug("%s: Config '%s' channel: %d\n", __func__, dev->name, channel);
+
+	pwm_imx_get_parms(period_ns, duty_ns, &period_cycles, &duty_cycles,
+			  &prescale);
+
+	return pwm_config_internal(regs, period_cycles, duty_cycles, prescale);
+};
+
+static int imx_pwm_set_enable(struct udevice *dev, uint channel, bool enable)
+{
+	struct imx_pwm_priv *priv = dev_get_priv(dev);
+	struct pwm_regs *regs = priv->regs;
+
+	debug("%s: Enable '%s' state: %d\n", __func__, dev->name, enable);
+
+	if (enable)
+		setbits_le32(&regs->cr, PWMCR_EN);
+	else
+		clrbits_le32(&regs->cr, PWMCR_EN);
+
+	return 0;
+};
+
+static int imx_pwm_ofdata_to_platdata(struct udevice *dev)
+{
+	struct imx_pwm_priv *priv = dev_get_priv(dev);
+
+	priv->regs = (struct pwm_regs *)devfdt_get_addr(dev);
+
+	return 0;
+}
+
+static int imx_pwm_probe(struct udevice *dev)
+{
+	return 0;
+}
+
+static const struct pwm_ops imx_pwm_ops = {
+	.set_invert	= imx_pwm_set_invert,
+	.set_config	= imx_pwm_set_config,
+	.set_enable	= imx_pwm_set_enable,
+};
+
+static const struct udevice_id imx_pwm_ids[] = {
+	{ .compatible = "fsl,imx27-pwm" },
+	{ }
+};
+
+U_BOOT_DRIVER(imx_pwm) = {
+	.name	= "imx_pwm",
+	.id	= UCLASS_PWM,
+	.of_match = imx_pwm_ids,
+	.ops	= &imx_pwm_ops,
+	.ofdata_to_platdata	= imx_pwm_ofdata_to_platdata,
+	.probe		= imx_pwm_probe,
+	.priv_auto_alloc_size	= sizeof(struct imx_pwm_priv),
+};
+#endif
diff --git a/drivers/serial/serial_mxc.c b/drivers/serial/serial_mxc.c
index a435e68..42abb96 100644
--- a/drivers/serial/serial_mxc.c
+++ b/drivers/serial/serial_mxc.c
@@ -342,6 +342,8 @@
 }
 
 static const struct udevice_id mxc_serial_ids[] = {
+	{ .compatible = "fsl,imx21-uart" },
+	{ .compatible = "fsl,imx53-uart" },
 	{ .compatible = "fsl,imx6sx-uart" },
 	{ .compatible = "fsl,imx6ul-uart" },
 	{ .compatible = "fsl,imx7d-uart" },
@@ -360,9 +362,7 @@
 #endif
 	.probe = mxc_serial_probe,
 	.ops	= &mxc_serial_ops,
-#if !CONFIG_IS_ENABLED(OF_CONTROL)
 	.flags = DM_FLAG_PRE_RELOC,
-#endif
 };
 #endif
 
diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
index cc174dd..f459c0a 100644
--- a/drivers/spi/Kconfig
+++ b/drivers/spi/Kconfig
@@ -158,13 +158,14 @@
 	  the SPI NOR flash on platforms embedding this Ralink / MediaTek
 	  SPI core, like MT7621/7628/7688.
 
-config MTK_QSPI
-	bool "Mediatek QSPI driver"
-	imply SPI_FLASH_BAR
+config MTK_SNFI_SPI
+	bool "Mediatek SPI memory controller driver"
+	depends on SPI_MEM
 	help
-	  Enable the Mediatek QSPI driver. This driver can be
-	  used to access the SPI NOR flash on platforms embedding this
-	  Mediatek QSPI IP core.
+	  Enable the Mediatek SPI memory controller driver. This driver is
+	  originally based on the MediaTek SNFI IP core. It can only be
+	  used to access SPI memory devices like SPI-NOR or SPI-NAND on
+	  platforms embedding this IP core, like MT7622/M7629.
 
 config MVEBU_A3700_SPI
 	bool "Marvell Armada 3700 SPI driver"
@@ -232,6 +233,14 @@
 		};
 	  };
 
+config SPI_SIFIVE
+	bool "SiFive SPI driver"
+	help
+	  This driver supports the SiFive SPI IP. If unsure say N.
+	  Enable the SiFive SPI controller driver.
+
+	  The SiFive SPI controller driver is found on various SiFive SoCs.
+
 config SPI_SUNXI
 	bool "Allwinner SoC SPI controllers"
 	help
diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
index ab84122..ae4f295 100644
--- a/drivers/spi/Makefile
+++ b/drivers/spi/Makefile
@@ -37,7 +37,7 @@
 obj-$(CONFIG_MESON_SPIFC) += meson_spifc.o
 obj-$(CONFIG_MPC8XX_SPI) += mpc8xx_spi.o
 obj-$(CONFIG_MPC8XXX_SPI) += mpc8xxx_spi.o
-obj-$(CONFIG_MTK_QSPI) += mtk_qspi.o
+obj-$(CONFIG_MTK_SNFI_SPI) += mtk_snfi_spi.o
 obj-$(CONFIG_MT7621_SPI) += mt7621_spi.o
 obj-$(CONFIG_MSCC_BB_SPI) += mscc_bb_spi.o
 obj-$(CONFIG_MVEBU_A3700_SPI) += mvebu_a3700_spi.o
@@ -50,6 +50,7 @@
 obj-$(CONFIG_RENESAS_RPC_SPI) += renesas_rpc_spi.o
 obj-$(CONFIG_ROCKCHIP_SPI) += rk_spi.o
 obj-$(CONFIG_SANDBOX_SPI) += sandbox_spi.o
+obj-$(CONFIG_SPI_SIFIVE) += spi-sifive.o
 obj-$(CONFIG_SPI_SUNXI) += spi-sunxi.o
 obj-$(CONFIG_SH_SPI) += sh_spi.o
 obj-$(CONFIG_SH_QSPI) += sh_qspi.o
diff --git a/drivers/spi/fsl_qspi.c b/drivers/spi/fsl_qspi.c
index 1598c4f..41abe19 100644
--- a/drivers/spi/fsl_qspi.c
+++ b/drivers/spi/fsl_qspi.c
@@ -10,6 +10,7 @@
 #include <spi.h>
 #include <asm/io.h>
 #include <linux/sizes.h>
+#include <linux/iopoll.h>
 #include <dm.h>
 #include <errno.h>
 #include <watchdog.h>
@@ -150,20 +151,13 @@
 static inline int is_controller_busy(const struct fsl_qspi_priv *priv)
 {
 	u32 val;
-	const u32 mask = QSPI_SR_BUSY_MASK | QSPI_SR_AHB_ACC_MASK |
-			 QSPI_SR_IP_ACC_MASK;
-	unsigned int retry = 5;
+	u32 mask = QSPI_SR_BUSY_MASK | QSPI_SR_AHB_ACC_MASK |
+		   QSPI_SR_IP_ACC_MASK;
 
-	do {
-		val = qspi_read32(priv->flags, &priv->regs->sr);
-
-		if ((~val & mask) == mask)
-			return 0;
-
-		udelay(1);
-	} while (--retry);
+	if (priv->flags & QSPI_FLAG_REGMAP_ENDIAN_BIG)
+		mask = (u32)cpu_to_be32(mask);
 
-	return -ETIMEDOUT;
+	return readl_poll_timeout(&priv->regs->sr, val, !(val & mask), 1000);
 }
 
 /* QSPI support swapping the flash read/write data
diff --git a/drivers/spi/mtk_qspi.c b/drivers/spi/mtk_qspi.c
deleted file mode 100644
index b510733..0000000
--- a/drivers/spi/mtk_qspi.c
+++ /dev/null
@@ -1,359 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Copyright (c) 2018  MediaTek, Inc.
- * Author : Guochun.Mao@mediatek.com
- */
-
-#include <common.h>
-#include <dm.h>
-#include <malloc.h>
-#include <spi.h>
-#include <asm/io.h>
-#include <linux/iopoll.h>
-#include <linux/ioport.h>
-
-/* Register Offset */
-struct mtk_qspi_regs {
-	u32 cmd;
-	u32 cnt;
-	u32 rdsr;
-	u32 rdata;
-	u32 radr[3];
-	u32 wdata;
-	u32 prgdata[6];
-	u32 shreg[10];
-	u32 cfg[2];
-	u32 shreg10;
-	u32 mode_mon;
-	u32 status[4];
-	u32 flash_time;
-	u32 flash_cfg;
-	u32 reserved_0[3];
-	u32 sf_time;
-	u32 pp_dw_data;
-	u32 reserved_1;
-	u32 delsel_0[2];
-	u32 intrstus;
-	u32 intren;
-	u32 reserved_2;
-	u32 cfg3;
-	u32 reserved_3;
-	u32 chksum;
-	u32 aaicmd;
-	u32 wrprot;
-	u32 radr3;
-	u32 dual;
-	u32 delsel_1[3];
-};
-
-struct mtk_qspi_platdata {
-	fdt_addr_t reg_base;
-	fdt_addr_t mem_base;
-};
-
-struct mtk_qspi_priv {
-	struct mtk_qspi_regs *regs;
-	unsigned long *mem_base;
-	u8 op;
-	u8 tx[3]; /* only record max 3 bytes paras, when it's address. */
-	u32 txlen; /* dout buffer length  - op code length */
-	u8 *rx;
-	u32 rxlen;
-};
-
-#define MTK_QSPI_CMD_POLLINGREG_US 500000
-#define MTK_QSPI_WRBUF_SIZE        256
-#define MTK_QSPI_COMMAND_ENABLE    0x30
-
-/* NOR flash controller commands */
-#define MTK_QSPI_RD_TRIGGER        BIT(0)
-#define MTK_QSPI_READSTATUS        BIT(1)
-#define MTK_QSPI_PRG_CMD           BIT(2)
-#define MTK_QSPI_WR_TRIGGER        BIT(4)
-#define MTK_QSPI_WRITESTATUS       BIT(5)
-#define MTK_QSPI_AUTOINC           BIT(7)
-
-#define MTK_QSPI_MAX_RX_TX_SHIFT   0x6
-#define MTK_QSPI_MAX_SHIFT         0x8
-
-#define MTK_QSPI_WR_BUF_ENABLE     0x1
-#define MTK_QSPI_WR_BUF_DISABLE    0x0
-
-static int mtk_qspi_execute_cmd(struct mtk_qspi_priv *priv, u8 cmd)
-{
-	u8 tmp;
-	u8 val = cmd & ~MTK_QSPI_AUTOINC;
-
-	writeb(cmd, &priv->regs->cmd);
-
-	return readb_poll_timeout(&priv->regs->cmd, tmp, !(val & tmp),
-				  MTK_QSPI_CMD_POLLINGREG_US);
-}
-
-static int mtk_qspi_tx_rx(struct mtk_qspi_priv *priv)
-{
-	int len = 1 + priv->txlen + priv->rxlen;
-	int i, ret, idx;
-
-	if (len > MTK_QSPI_MAX_SHIFT)
-		return -ERR_INVAL;
-
-	writeb(len * 8, &priv->regs->cnt);
-
-	/* start at PRGDATA5, go down to PRGDATA0 */
-	idx = MTK_QSPI_MAX_RX_TX_SHIFT - 1;
-
-	/* opcode */
-	writeb(priv->op, &priv->regs->prgdata[idx]);
-	idx--;
-
-	/* program TX data */
-	for (i = 0; i < priv->txlen; i++, idx--)
-		writeb(priv->tx[i], &priv->regs->prgdata[idx]);
-
-	/* clear out rest of TX registers */
-	while (idx >= 0) {
-		writeb(0, &priv->regs->prgdata[idx]);
-		idx--;
-	}
-
-	ret = mtk_qspi_execute_cmd(priv, MTK_QSPI_PRG_CMD);
-	if (ret)
-		return ret;
-
-	/* restart at first RX byte */
-	idx = priv->rxlen - 1;
-
-	/* read out RX data */
-	for (i = 0; i < priv->rxlen; i++, idx--)
-		priv->rx[i] = readb(&priv->regs->shreg[idx]);
-
-	return 0;
-}
-
-static int mtk_qspi_read(struct mtk_qspi_priv *priv,
-			 u32 addr, u8 *buf, u32 len)
-{
-	memcpy(buf, (u8 *)priv->mem_base + addr, len);
-	return 0;
-}
-
-static void mtk_qspi_set_addr(struct mtk_qspi_priv *priv, u32 addr)
-{
-	int i;
-
-	for (i = 0; i < 3; i++) {
-		writeb(addr & 0xff, &priv->regs->radr[i]);
-		addr >>= 8;
-	}
-}
-
-static int mtk_qspi_write_single_byte(struct mtk_qspi_priv *priv,
-				      u32 addr, u32 length, const u8 *data)
-{
-	int i, ret;
-
-	mtk_qspi_set_addr(priv, addr);
-
-	for (i = 0; i < length; i++) {
-		writeb(*data++, &priv->regs->wdata);
-		ret = mtk_qspi_execute_cmd(priv, MTK_QSPI_WR_TRIGGER);
-		if (ret < 0)
-			return ret;
-	}
-	return 0;
-}
-
-static int mtk_qspi_write_buffer(struct mtk_qspi_priv *priv, u32 addr,
-				 const u8 *buf)
-{
-	int i, data;
-
-	mtk_qspi_set_addr(priv, addr);
-
-	for (i = 0; i < MTK_QSPI_WRBUF_SIZE; i += 4) {
-		data = buf[i + 3] << 24 | buf[i + 2] << 16 |
-		       buf[i + 1] << 8 | buf[i];
-		writel(data, &priv->regs->pp_dw_data);
-	}
-
-	return mtk_qspi_execute_cmd(priv, MTK_QSPI_WR_TRIGGER);
-}
-
-static int mtk_qspi_write(struct mtk_qspi_priv *priv,
-			  u32 addr, const u8 *buf, u32 len)
-{
-	int ret;
-
-	/* setting pre-fetch buffer for page program */
-	writel(MTK_QSPI_WR_BUF_ENABLE, &priv->regs->cfg[1]);
-	while (len >= MTK_QSPI_WRBUF_SIZE) {
-		ret = mtk_qspi_write_buffer(priv, addr, buf);
-		if (ret < 0)
-			return ret;
-
-		len -= MTK_QSPI_WRBUF_SIZE;
-		addr += MTK_QSPI_WRBUF_SIZE;
-		buf += MTK_QSPI_WRBUF_SIZE;
-	}
-	/* disable pre-fetch buffer for page program */
-	writel(MTK_QSPI_WR_BUF_DISABLE, &priv->regs->cfg[1]);
-
-	if (len)
-		return mtk_qspi_write_single_byte(priv, addr, len, buf);
-
-	return 0;
-}
-
-static int mtk_qspi_claim_bus(struct udevice *dev)
-{
-	/* nothing to do */
-	return 0;
-}
-
-static int mtk_qspi_release_bus(struct udevice *dev)
-{
-	/* nothing to do */
-	return 0;
-}
-
-static int mtk_qspi_transfer(struct mtk_qspi_priv *priv, unsigned int bitlen,
-			     const void *dout, void *din, unsigned long flags)
-{
-	u32 bytes = DIV_ROUND_UP(bitlen, 8);
-	u32 addr;
-
-	if (!bytes)
-		return -ERR_INVAL;
-
-	if (dout) {
-		if (flags & SPI_XFER_BEGIN) {
-			/* parse op code and potential paras first */
-			priv->op = *(u8 *)dout;
-			if (bytes > 1)
-				memcpy(priv->tx, (u8 *)dout + 1,
-				       bytes <= 4 ? bytes - 1 : 3);
-			priv->txlen = bytes - 1;
-		}
-
-		if (flags == SPI_XFER_ONCE) {
-			/* operations without receiving or sending data.
-			 * for example: erase, write flash register or write
-			 * enable...
-			 */
-			priv->rx = NULL;
-			priv->rxlen = 0;
-			return mtk_qspi_tx_rx(priv);
-		}
-
-		if (flags & SPI_XFER_END) {
-			/* here, dout should be data to be written.
-			 * and priv->tx should be filled 3Bytes address.
-			 */
-			addr = priv->tx[0] << 16 | priv->tx[1] << 8 |
-			       priv->tx[2];
-			return mtk_qspi_write(priv, addr, (u8 *)dout, bytes);
-		}
-	}
-
-	if (din) {
-		if (priv->txlen >= 3) {
-			/* if run to here, priv->tx[] should be the address
-			 * where read data from,
-			 * and, din is the buf to receive data.
-			 */
-			addr = priv->tx[0] << 16 | priv->tx[1] << 8 |
-			       priv->tx[2];
-			return mtk_qspi_read(priv, addr, (u8 *)din, bytes);
-		}
-
-		/* should be reading flash's register */
-		priv->rx = (u8 *)din;
-		priv->rxlen = bytes;
-		return mtk_qspi_tx_rx(priv);
-	}
-
-	return 0;
-}
-
-static int mtk_qspi_xfer(struct udevice *dev, unsigned int bitlen,
-			 const void *dout, void *din, unsigned long flags)
-{
-	struct udevice *bus = dev->parent;
-	struct mtk_qspi_priv *priv = dev_get_priv(bus);
-
-	return  mtk_qspi_transfer(priv, bitlen, dout, din, flags);
-}
-
-static int mtk_qspi_set_speed(struct udevice *bus, uint speed)
-{
-	/* nothing to do */
-	return 0;
-}
-
-static int mtk_qspi_set_mode(struct udevice *bus, uint mode)
-{
-	/* nothing to do */
-	return 0;
-}
-
-static int mtk_qspi_ofdata_to_platdata(struct udevice *bus)
-{
-	struct resource res_reg, res_mem;
-	struct mtk_qspi_platdata *plat = bus->platdata;
-	int ret;
-
-	ret = dev_read_resource_byname(bus, "reg_base", &res_reg);
-	if (ret) {
-		debug("can't get reg_base resource(ret = %d)\n", ret);
-		return -ENOMEM;
-	}
-
-	ret = dev_read_resource_byname(bus, "mem_base", &res_mem);
-	if (ret) {
-		debug("can't get map_base resource(ret = %d)\n", ret);
-		return -ENOMEM;
-	}
-
-	plat->mem_base = res_mem.start;
-	plat->reg_base = res_reg.start;
-
-	return 0;
-}
-
-static int mtk_qspi_probe(struct udevice *bus)
-{
-	struct mtk_qspi_platdata *plat = dev_get_platdata(bus);
-	struct mtk_qspi_priv *priv = dev_get_priv(bus);
-
-	priv->regs = (struct mtk_qspi_regs *)plat->reg_base;
-	priv->mem_base = (unsigned long *)plat->mem_base;
-
-	writel(MTK_QSPI_COMMAND_ENABLE, &priv->regs->wrprot);
-
-	return 0;
-}
-
-static const struct dm_spi_ops mtk_qspi_ops = {
-	.claim_bus      = mtk_qspi_claim_bus,
-	.release_bus    = mtk_qspi_release_bus,
-	.xfer           = mtk_qspi_xfer,
-	.set_speed      = mtk_qspi_set_speed,
-	.set_mode       = mtk_qspi_set_mode,
-};
-
-static const struct udevice_id mtk_qspi_ids[] = {
-	{ .compatible = "mediatek,mt7629-qspi" },
-	{ }
-};
-
-U_BOOT_DRIVER(mtk_qspi) = {
-	.name     = "mtk_qspi",
-	.id       = UCLASS_SPI,
-	.of_match = mtk_qspi_ids,
-	.ops      = &mtk_qspi_ops,
-	.ofdata_to_platdata       = mtk_qspi_ofdata_to_platdata,
-	.platdata_auto_alloc_size = sizeof(struct mtk_qspi_platdata),
-	.priv_auto_alloc_size     = sizeof(struct mtk_qspi_priv),
-	.probe    = mtk_qspi_probe,
-};
diff --git a/drivers/spi/mtk_snfi_spi.c b/drivers/spi/mtk_snfi_spi.c
new file mode 100644
index 0000000..2a89476
--- /dev/null
+++ b/drivers/spi/mtk_snfi_spi.c
@@ -0,0 +1,318 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2019 MediaTek Inc. All Rights Reserved.
+ *
+ * Author: Weijie Gao <weijie.gao@mediatek.com>
+ */
+
+#include <common.h>
+#include <clk.h>
+#include <dm.h>
+#include <errno.h>
+#include <spi.h>
+#include <spi-mem.h>
+#include <stdbool.h>
+#include <watchdog.h>
+#include <dm/pinctrl.h>
+#include <linux/bitops.h>
+#include <linux/io.h>
+#include <linux/iopoll.h>
+
+#define SNFI_MAC_CTL			0x500
+#define MAC_XIO_SEL			BIT(4)
+#define SF_MAC_EN			BIT(3)
+#define SF_TRIG				BIT(2)
+#define WIP_READY			BIT(1)
+#define WIP				BIT(0)
+
+#define SNFI_MAC_OUTL			0x504
+#define SNFI_MAC_INL			0x508
+
+#define SNFI_MISC_CTL			0x538
+#define SW_RST				BIT(28)
+#define FIFO_RD_LTC_SHIFT		25
+#define FIFO_RD_LTC			GENMASK(26, 25)
+#define LATCH_LAT_SHIFT			8
+#define LATCH_LAT			GENMASK(9, 8)
+#define CS_DESELECT_CYC_SHIFT		0
+#define CS_DESELECT_CYC			GENMASK(4, 0)
+
+#define SNF_STA_CTL1			0x550
+#define SPI_STATE			GENMASK(3, 0)
+
+#define SNFI_GPRAM_OFFSET		0x800
+#define SNFI_GPRAM_SIZE			0x80
+
+#define SNFI_POLL_INTERVAL		500000
+#define SNFI_RST_POLL_INTERVAL		1000000
+
+struct mtk_snfi_priv {
+	void __iomem *base;
+
+	struct clk nfi_clk;
+	struct clk pad_clk;
+};
+
+static int mtk_snfi_adjust_op_size(struct spi_slave *slave,
+				   struct spi_mem_op *op)
+{
+	u32 nbytes;
+
+	/*
+	 * When there is input data, it will be appended after the output
+	 * data in the GPRAM. So the total size of either pure output data
+	 * or the output+input data must not exceed the GPRAM size.
+	 */
+
+	nbytes = sizeof(op->cmd.opcode) + op->addr.nbytes +
+		op->dummy.nbytes;
+
+	if (nbytes + op->data.nbytes <= SNFI_GPRAM_SIZE)
+		return 0;
+
+	if (nbytes >= SNFI_GPRAM_SIZE)
+		return -ENOTSUPP;
+
+	op->data.nbytes = SNFI_GPRAM_SIZE - nbytes;
+
+	return 0;
+}
+
+static bool mtk_snfi_supports_op(struct spi_slave *slave,
+				 const struct spi_mem_op *op)
+{
+	if (op->cmd.buswidth > 1 || op->addr.buswidth > 1 ||
+	    op->dummy.buswidth > 1 || op->data.buswidth > 1)
+		return false;
+
+	return true;
+}
+
+static int mtk_snfi_mac_trigger(struct mtk_snfi_priv *priv,
+				struct udevice *bus, u32 outlen, u32 inlen)
+{
+	int ret;
+	u32 val;
+
+#ifdef CONFIG_PINCTRL
+	pinctrl_select_state(bus, "snfi");
+#endif
+
+	writel(SF_MAC_EN, priv->base + SNFI_MAC_CTL);
+	writel(outlen, priv->base + SNFI_MAC_OUTL);
+	writel(inlen, priv->base + SNFI_MAC_INL);
+
+	writel(SF_MAC_EN | SF_TRIG, priv->base + SNFI_MAC_CTL);
+
+	ret = readl_poll_timeout(priv->base + SNFI_MAC_CTL, val,
+				 val & WIP_READY, SNFI_POLL_INTERVAL);
+	if (ret) {
+		printf("%s: timed out waiting for WIP_READY\n", __func__);
+		goto cleanup;
+	}
+
+	ret = readl_poll_timeout(priv->base + SNFI_MAC_CTL, val,
+				 !(val & WIP), SNFI_POLL_INTERVAL);
+	if (ret)
+		printf("%s: timed out waiting for WIP cleared\n", __func__);
+
+	writel(0, priv->base + SNFI_MAC_CTL);
+
+cleanup:
+#ifdef CONFIG_PINCTRL
+	pinctrl_select_state(bus, "default");
+#endif
+
+	return ret;
+}
+
+static int mtk_snfi_mac_reset(struct mtk_snfi_priv *priv)
+{
+	int ret;
+	u32 val;
+
+	setbits_32(priv->base + SNFI_MISC_CTL, SW_RST);
+
+	ret = readl_poll_timeout(priv->base + SNF_STA_CTL1, val,
+				 !(val & SPI_STATE), SNFI_POLL_INTERVAL);
+	if (ret)
+		printf("%s: failed to reset snfi mac\n", __func__);
+
+	writel((2 << FIFO_RD_LTC_SHIFT) |
+		(10 << CS_DESELECT_CYC_SHIFT),
+		priv->base + SNFI_MISC_CTL);
+
+	return ret;
+}
+
+static void mtk_snfi_copy_to_gpram(struct mtk_snfi_priv *priv,
+				   const void *data, size_t len)
+{
+	void __iomem *gpram = priv->base + SNFI_GPRAM_OFFSET;
+	size_t i, n = (len + sizeof(u32) - 1) / sizeof(u32);
+	const u32 *buff = data;
+
+	/*
+	 * The output data will always be copied to the beginning of
+	 * the GPRAM. Uses word write for better performace.
+	 *
+	 * Trailing bytes in the last word are not cared.
+	 */
+
+	for (i = 0; i < n; i++)
+		writel(buff[i], gpram + i * sizeof(u32));
+}
+
+static void mtk_snfi_copy_from_gpram(struct mtk_snfi_priv *priv, u8 *cache,
+				     void *data, size_t pos, size_t len)
+{
+	void __iomem *gpram = priv->base + SNFI_GPRAM_OFFSET;
+	u32 *buff = (u32 *)cache;
+	size_t i, off, end;
+
+	/* Start position in the buffer */
+	off = pos & (sizeof(u32) - 1);
+
+	/* End position for copy */
+	end = (len + pos + sizeof(u32) - 1) & (~(sizeof(u32) - 1));
+
+	/* Start position for copy */
+	pos &= ~(sizeof(u32) - 1);
+
+	/*
+	 * Read aligned data from GPRAM to buffer first.
+	 * Uses word read for better performace.
+	 */
+	i = 0;
+	while (pos < end) {
+		buff[i++] = readl(gpram + pos);
+		pos += sizeof(u32);
+	}
+
+	/* Copy rx data */
+	memcpy(data, cache + off, len);
+}
+
+static int mtk_snfi_exec_op(struct spi_slave *slave,
+			    const struct spi_mem_op *op)
+{
+	struct udevice *bus = dev_get_parent(slave->dev);
+	struct mtk_snfi_priv *priv = dev_get_priv(bus);
+	u8 gpram_cache[SNFI_GPRAM_SIZE];
+	u32 i, len = 0, inlen = 0;
+	int addr_sh;
+	int ret;
+
+	WATCHDOG_RESET();
+
+	ret = mtk_snfi_mac_reset(priv);
+	if (ret)
+		return ret;
+
+	/* Put opcode */
+	gpram_cache[len++] = op->cmd.opcode;
+
+	/* Put address */
+	addr_sh = (op->addr.nbytes - 1) * 8;
+	while (addr_sh >= 0) {
+		gpram_cache[len++] = (op->addr.val >> addr_sh) & 0xff;
+		addr_sh -= 8;
+	}
+
+	/* Put dummy bytes */
+	for (i = 0; i < op->dummy.nbytes; i++)
+		gpram_cache[len++] = 0;
+
+	/* Put output data */
+	if (op->data.nbytes && op->data.dir == SPI_MEM_DATA_OUT) {
+		memcpy(gpram_cache + len, op->data.buf.out, op->data.nbytes);
+		len += op->data.nbytes;
+	}
+
+	/* Copy final output data to GPRAM */
+	mtk_snfi_copy_to_gpram(priv, gpram_cache, len);
+
+	/* Start one SPI transaction */
+	if (op->data.nbytes && op->data.dir == SPI_MEM_DATA_IN)
+		inlen = op->data.nbytes;
+
+	ret = mtk_snfi_mac_trigger(priv, bus, len, inlen);
+	if (ret)
+		return ret;
+
+	/* Copy input data from GPRAM */
+	if (inlen)
+		mtk_snfi_copy_from_gpram(priv, gpram_cache, op->data.buf.in,
+					 len, inlen);
+
+	return 0;
+}
+
+static int mtk_snfi_spi_probe(struct udevice *bus)
+{
+	struct mtk_snfi_priv *priv = dev_get_priv(bus);
+	int ret;
+
+	priv->base = (void __iomem *)devfdt_get_addr(bus);
+	if (!priv->base)
+		return -EINVAL;
+
+	ret = clk_get_by_name(bus, "nfi_clk", &priv->nfi_clk);
+	if (ret < 0)
+		return ret;
+
+	ret = clk_get_by_name(bus, "pad_clk", &priv->pad_clk);
+	if (ret < 0)
+		return ret;
+
+	clk_enable(&priv->nfi_clk);
+	clk_enable(&priv->pad_clk);
+
+	return 0;
+}
+
+static int mtk_snfi_set_speed(struct udevice *bus, uint speed)
+{
+	/*
+	 * The SNFI does not have a bus clock divider.
+	 * The bus clock is set in dts (pad_clk, UNIVPLL2_D8 = 50MHz).
+	 */
+
+	return 0;
+}
+
+static int mtk_snfi_set_mode(struct udevice *bus, uint mode)
+{
+	/* The SNFI supports only mode 0 */
+
+	if (mode)
+		return -EINVAL;
+
+	return 0;
+}
+
+static const struct spi_controller_mem_ops mtk_snfi_mem_ops = {
+	.adjust_op_size = mtk_snfi_adjust_op_size,
+	.supports_op = mtk_snfi_supports_op,
+	.exec_op = mtk_snfi_exec_op,
+};
+
+static const struct dm_spi_ops mtk_snfi_spi_ops = {
+	.mem_ops	= &mtk_snfi_mem_ops,
+	.set_speed	= mtk_snfi_set_speed,
+	.set_mode	= mtk_snfi_set_mode,
+};
+
+static const struct udevice_id mtk_snfi_spi_ids[] = {
+	{ .compatible = "mediatek,mtk-snfi-spi" },
+	{ }
+};
+
+U_BOOT_DRIVER(mtk_snfi_spi) = {
+	.name			= "mtk_snfi_spi",
+	.id			= UCLASS_SPI,
+	.of_match		= mtk_snfi_spi_ids,
+	.ops			= &mtk_snfi_spi_ops,
+	.priv_auto_alloc_size	= sizeof(struct mtk_snfi_priv),
+	.probe			= mtk_snfi_spi_probe,
+};
diff --git a/drivers/spi/mxs_spi.c b/drivers/spi/mxs_spi.c
index 5065e40..3a9756f 100644
--- a/drivers/spi/mxs_spi.c
+++ b/drivers/spi/mxs_spi.c
@@ -2,6 +2,9 @@
 /*
  * Freescale i.MX28 SPI driver
  *
+ * Copyright (C) 2019 DENX Software Engineering
+ * Lukasz Majewski, DENX Software Engineering, lukma@denx.de
+ *
  * Copyright (C) 2011 Marek Vasut <marek.vasut@gmail.com>
  * on behalf of DENX Software Engineering GmbH
  *
@@ -27,6 +30,19 @@
 
 #define MXSSSP_SMALL_TRANSFER	512
 
+static void mxs_spi_start_xfer(struct mxs_ssp_regs *ssp_regs)
+{
+	writel(SSP_CTRL0_LOCK_CS, &ssp_regs->hw_ssp_ctrl0_set);
+	writel(SSP_CTRL0_IGNORE_CRC, &ssp_regs->hw_ssp_ctrl0_clr);
+}
+
+static void mxs_spi_end_xfer(struct mxs_ssp_regs *ssp_regs)
+{
+	writel(SSP_CTRL0_LOCK_CS, &ssp_regs->hw_ssp_ctrl0_clr);
+	writel(SSP_CTRL0_IGNORE_CRC, &ssp_regs->hw_ssp_ctrl0_set);
+}
+
+#if !CONFIG_IS_ENABLED(DM_SPI)
 struct mxs_spi_slave {
 	struct spi_slave	slave;
 	uint32_t		max_khz;
@@ -38,94 +54,38 @@
 {
 	return container_of(slave, struct mxs_spi_slave, slave);
 }
-
-int spi_cs_is_valid(unsigned int bus, unsigned int cs)
-{
-	/* MXS SPI: 4 ports and 3 chip selects maximum */
-	if (!mxs_ssp_bus_id_valid(bus) || cs > 2)
-		return 0;
-	else
-		return 1;
-}
-
-struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
-				  unsigned int max_hz, unsigned int mode)
-{
-	struct mxs_spi_slave *mxs_slave;
-
-	if (!spi_cs_is_valid(bus, cs)) {
-		printf("mxs_spi: invalid bus %d / chip select %d\n", bus, cs);
-		return NULL;
-	}
-
-	mxs_slave = spi_alloc_slave(struct mxs_spi_slave, bus, cs);
-	if (!mxs_slave)
-		return NULL;
-
-	if (mxs_dma_init_channel(MXS_DMA_CHANNEL_AHB_APBH_SSP0 + bus))
-		goto err_init;
-
-	mxs_slave->max_khz = max_hz / 1000;
-	mxs_slave->mode = mode;
-	mxs_slave->regs = mxs_ssp_regs_by_bus(bus);
-
-	return &mxs_slave->slave;
-
-err_init:
-	free(mxs_slave);
-	return NULL;
-}
-
-void spi_free_slave(struct spi_slave *slave)
-{
-	struct mxs_spi_slave *mxs_slave = to_mxs_slave(slave);
-	free(mxs_slave);
-}
-
-int spi_claim_bus(struct spi_slave *slave)
-{
-	struct mxs_spi_slave *mxs_slave = to_mxs_slave(slave);
-	struct mxs_ssp_regs *ssp_regs = mxs_slave->regs;
-	uint32_t reg = 0;
-
-	mxs_reset_block(&ssp_regs->hw_ssp_ctrl0_reg);
-
-	writel((slave->cs << MXS_SSP_CHIPSELECT_SHIFT) |
-	       SSP_CTRL0_BUS_WIDTH_ONE_BIT,
-	       &ssp_regs->hw_ssp_ctrl0);
-
-	reg = SSP_CTRL1_SSP_MODE_SPI | SSP_CTRL1_WORD_LENGTH_EIGHT_BITS;
-	reg |= (mxs_slave->mode & SPI_CPOL) ? SSP_CTRL1_POLARITY : 0;
-	reg |= (mxs_slave->mode & SPI_CPHA) ? SSP_CTRL1_PHASE : 0;
-	writel(reg, &ssp_regs->hw_ssp_ctrl1);
-
-	writel(0, &ssp_regs->hw_ssp_cmd0);
-
-	mxs_set_ssp_busclock(slave->bus, mxs_slave->max_khz);
-
-	return 0;
-}
-
-void spi_release_bus(struct spi_slave *slave)
-{
-}
-
-static void mxs_spi_start_xfer(struct mxs_ssp_regs *ssp_regs)
-{
-	writel(SSP_CTRL0_LOCK_CS, &ssp_regs->hw_ssp_ctrl0_set);
-	writel(SSP_CTRL0_IGNORE_CRC, &ssp_regs->hw_ssp_ctrl0_clr);
-}
+#else
+#include <dm.h>
+#include <errno.h>
+struct mxs_spi_platdata {
+	s32 frequency;		/* Default clock frequency, -1 for none */
+	fdt_addr_t base;        /* SPI IP block base address */
+	int num_cs;             /* Number of CSes supported */
+	int dma_id;             /* ID of the DMA channel */
+	int clk_id;             /* ID of the SSP clock */
+};
 
-static void mxs_spi_end_xfer(struct mxs_ssp_regs *ssp_regs)
-{
-	writel(SSP_CTRL0_LOCK_CS, &ssp_regs->hw_ssp_ctrl0_clr);
-	writel(SSP_CTRL0_IGNORE_CRC, &ssp_regs->hw_ssp_ctrl0_set);
-}
+struct mxs_spi_priv {
+	struct mxs_ssp_regs *regs;
+	unsigned int dma_channel;
+	unsigned int max_freq;
+	unsigned int clk_id;
+	unsigned int mode;
+};
+#endif
 
+#if !CONFIG_IS_ENABLED(DM_SPI)
 static int mxs_spi_xfer_pio(struct mxs_spi_slave *slave,
 			char *data, int length, int write, unsigned long flags)
 {
 	struct mxs_ssp_regs *ssp_regs = slave->regs;
+#else
+static int mxs_spi_xfer_pio(struct mxs_spi_priv *priv,
+			    char *data, int length, int write,
+			    unsigned long flags)
+{
+	struct mxs_ssp_regs *ssp_regs = priv->regs;
+#endif
 
 	if (flags & SPI_XFER_BEGIN)
 		mxs_spi_start_xfer(ssp_regs);
@@ -181,12 +141,19 @@
 	return 0;
 }
 
+#if !CONFIG_IS_ENABLED(DM_SPI)
 static int mxs_spi_xfer_dma(struct mxs_spi_slave *slave,
 			char *data, int length, int write, unsigned long flags)
 {
+	struct mxs_ssp_regs *ssp_regs = slave->regs;
+#else
+static int mxs_spi_xfer_dma(struct mxs_spi_priv *priv,
+			    char *data, int length, int write,
+			    unsigned long flags)
+{	struct mxs_ssp_regs *ssp_regs = priv->regs;
+#endif
 	const int xfer_max_sz = 0xff00;
 	const int desc_count = DIV_ROUND_UP(length, xfer_max_sz) + 1;
-	struct mxs_ssp_regs *ssp_regs = slave->regs;
 	struct mxs_dma_desc *dp;
 	uint32_t ctrl0;
 	uint32_t cache_data_count;
@@ -225,7 +192,11 @@
 	/* Invalidate the area, so no writeback into the RAM races with DMA */
 	invalidate_dcache_range(dstart, dstart + cache_data_count);
 
+#if !CONFIG_IS_ENABLED(DM_SPI)
 	dmach = MXS_DMA_CHANNEL_AHB_APBH_SSP0 + slave->slave.bus;
+#else
+	dmach = priv->dma_channel;
+#endif
 
 	dp = desc;
 	while (length) {
@@ -302,11 +273,20 @@
 	return ret;
 }
 
+#if !CONFIG_IS_ENABLED(DM_SPI)
 int spi_xfer(struct spi_slave *slave, unsigned int bitlen,
 		const void *dout, void *din, unsigned long flags)
 {
 	struct mxs_spi_slave *mxs_slave = to_mxs_slave(slave);
 	struct mxs_ssp_regs *ssp_regs = mxs_slave->regs;
+#else
+int mxs_spi_xfer(struct udevice *dev, unsigned int bitlen,
+		 const void *dout, void *din, unsigned long flags)
+{
+	struct udevice *bus = dev_get_parent(dev);
+	struct mxs_spi_priv *priv = dev_get_priv(bus);
+	struct mxs_ssp_regs *ssp_regs = priv->regs;
+#endif
 	int len = bitlen / 8;
 	char dummy;
 	int write = 0;
@@ -350,9 +330,263 @@
 
 	if (!dma || (len < MXSSSP_SMALL_TRANSFER)) {
 		writel(SSP_CTRL1_DMA_ENABLE, &ssp_regs->hw_ssp_ctrl1_clr);
+#if !CONFIG_IS_ENABLED(DM_SPI)
 		return mxs_spi_xfer_pio(mxs_slave, data, len, write, flags);
+#else
+		return mxs_spi_xfer_pio(priv, data, len, write, flags);
+#endif
 	} else {
 		writel(SSP_CTRL1_DMA_ENABLE, &ssp_regs->hw_ssp_ctrl1_set);
+#if !CONFIG_IS_ENABLED(DM_SPI)
 		return mxs_spi_xfer_dma(mxs_slave, data, len, write, flags);
+#else
+		return mxs_spi_xfer_dma(priv, data, len, write, flags);
+#endif
 	}
 }
+
+#if !CONFIG_IS_ENABLED(DM_SPI)
+int spi_cs_is_valid(unsigned int bus, unsigned int cs)
+{
+	/* MXS SPI: 4 ports and 3 chip selects maximum */
+	if (!mxs_ssp_bus_id_valid(bus) || cs > 2)
+		return 0;
+	else
+		return 1;
+}
+
+struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
+				  unsigned int max_hz, unsigned int mode)
+{
+	struct mxs_spi_slave *mxs_slave;
+
+	if (!spi_cs_is_valid(bus, cs)) {
+		printf("mxs_spi: invalid bus %d / chip select %d\n", bus, cs);
+		return NULL;
+	}
+
+	mxs_slave = spi_alloc_slave(struct mxs_spi_slave, bus, cs);
+	if (!mxs_slave)
+		return NULL;
+
+	if (mxs_dma_init_channel(MXS_DMA_CHANNEL_AHB_APBH_SSP0 + bus))
+		goto err_init;
+
+	mxs_slave->max_khz = max_hz / 1000;
+	mxs_slave->mode = mode;
+	mxs_slave->regs = mxs_ssp_regs_by_bus(bus);
+
+	return &mxs_slave->slave;
+
+err_init:
+	free(mxs_slave);
+	return NULL;
+}
+
+void spi_free_slave(struct spi_slave *slave)
+{
+	struct mxs_spi_slave *mxs_slave = to_mxs_slave(slave);
+
+	free(mxs_slave);
+}
+
+int spi_claim_bus(struct spi_slave *slave)
+{
+	struct mxs_spi_slave *mxs_slave = to_mxs_slave(slave);
+	struct mxs_ssp_regs *ssp_regs = mxs_slave->regs;
+	u32 reg = 0;
+
+	mxs_reset_block(&ssp_regs->hw_ssp_ctrl0_reg);
+
+	writel((slave->cs << MXS_SSP_CHIPSELECT_SHIFT) |
+	       SSP_CTRL0_BUS_WIDTH_ONE_BIT,
+	       &ssp_regs->hw_ssp_ctrl0);
+
+	reg = SSP_CTRL1_SSP_MODE_SPI | SSP_CTRL1_WORD_LENGTH_EIGHT_BITS;
+	reg |= (mxs_slave->mode & SPI_CPOL) ? SSP_CTRL1_POLARITY : 0;
+	reg |= (mxs_slave->mode & SPI_CPHA) ? SSP_CTRL1_PHASE : 0;
+	writel(reg, &ssp_regs->hw_ssp_ctrl1);
+
+	writel(0, &ssp_regs->hw_ssp_cmd0);
+
+	mxs_set_ssp_busclock(slave->bus, mxs_slave->max_khz);
+
+	return 0;
+}
+
+void spi_release_bus(struct spi_slave *slave)
+{
+}
+
+#else /* CONFIG_DM_SPI */
+/* Base numbers of i.MX2[38] clk for ssp0 IP block */
+#define MXS_SSP_IMX23_CLKID_SSP0 33
+#define MXS_SSP_IMX28_CLKID_SSP0 46
+
+static int mxs_spi_probe(struct udevice *bus)
+{
+	struct mxs_spi_platdata *plat = dev_get_platdata(bus);
+	struct mxs_spi_priv *priv = dev_get_priv(bus);
+	int ret;
+
+	debug("%s: probe\n", __func__);
+	priv->regs = (struct mxs_ssp_regs *)plat->base;
+	priv->max_freq = plat->frequency;
+
+	priv->dma_channel = plat->dma_id;
+	priv->clk_id = plat->clk_id;
+
+	ret = mxs_dma_init_channel(priv->dma_channel);
+	if (ret) {
+		printf("%s: DMA init channel error %d\n", __func__, ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+static int mxs_spi_claim_bus(struct udevice *dev)
+{
+	struct udevice *bus = dev_get_parent(dev);
+	struct mxs_spi_priv *priv = dev_get_priv(bus);
+	struct mxs_ssp_regs *ssp_regs = priv->regs;
+	int cs = spi_chip_select(dev);
+
+	/*
+	 * i.MX28 supports up to 3 CS (SSn0, SSn1, SSn2)
+	 * To set them it uses following tuple (WAIT_FOR_IRQ,WAIT_FOR_CMD),
+	 * where:
+	 *
+	 * WAIT_FOR_IRQ is bit 21 of HW_SSP_CTRL0
+	 * WAIT_FOR_CMD is bit 20 (#defined as MXS_SSP_CHIPSELECT_SHIFT here) of
+	 *                        HW_SSP_CTRL0
+	 * SSn0 b00
+	 * SSn1 b01
+	 * SSn2 b10 (which require setting WAIT_FOR_IRQ)
+	 *
+	 * However, for now i.MX28 SPI driver will support up till 2 CSes
+	 * (SSn0, and SSn1).
+	 */
+
+	/* Ungate SSP clock and set active CS */
+	clrsetbits_le32(&ssp_regs->hw_ssp_ctrl0,
+			BIT(MXS_SSP_CHIPSELECT_SHIFT) |
+			SSP_CTRL0_CLKGATE, (cs << MXS_SSP_CHIPSELECT_SHIFT));
+
+	return 0;
+}
+
+static int mxs_spi_release_bus(struct udevice *dev)
+{
+	struct udevice *bus = dev_get_parent(dev);
+	struct mxs_spi_priv *priv = dev_get_priv(bus);
+	struct mxs_ssp_regs *ssp_regs = priv->regs;
+
+	/* Gate SSP clock */
+	setbits_le32(&ssp_regs->hw_ssp_ctrl0, SSP_CTRL0_CLKGATE);
+
+	return 0;
+}
+
+static int mxs_spi_set_speed(struct udevice *bus, uint speed)
+{
+	struct mxs_spi_priv *priv = dev_get_priv(bus);
+#ifdef CONFIG_MX28
+	int clkid = priv->clk_id - MXS_SSP_IMX28_CLKID_SSP0;
+#else /* CONFIG_MX23 */
+	int clkid = priv->clk_id - MXS_SSP_IMX23_CLKID_SSP0;
+#endif
+	if (speed > priv->max_freq)
+		speed = priv->max_freq;
+
+	debug("%s speed: %u [Hz] clkid: %d\n", __func__, speed, clkid);
+	mxs_set_ssp_busclock(clkid, speed / 1000);
+
+	return 0;
+}
+
+static int mxs_spi_set_mode(struct udevice *bus, uint mode)
+{
+	struct mxs_spi_priv *priv = dev_get_priv(bus);
+	struct mxs_ssp_regs *ssp_regs = priv->regs;
+	u32 reg;
+
+	priv->mode = mode;
+	debug("%s: mode 0x%x\n", __func__, mode);
+
+	reg = SSP_CTRL1_SSP_MODE_SPI | SSP_CTRL1_WORD_LENGTH_EIGHT_BITS;
+	reg |= (priv->mode & SPI_CPOL) ? SSP_CTRL1_POLARITY : 0;
+	reg |= (priv->mode & SPI_CPHA) ? SSP_CTRL1_PHASE : 0;
+	writel(reg, &ssp_regs->hw_ssp_ctrl1);
+
+	/* Single bit SPI support */
+	writel(SSP_CTRL0_BUS_WIDTH_ONE_BIT, &ssp_regs->hw_ssp_ctrl0);
+
+	return 0;
+}
+
+static const struct dm_spi_ops mxs_spi_ops = {
+	.claim_bus	= mxs_spi_claim_bus,
+	.release_bus    = mxs_spi_release_bus,
+	.xfer		= mxs_spi_xfer,
+	.set_speed	= mxs_spi_set_speed,
+	.set_mode	= mxs_spi_set_mode,
+	/*
+	 * cs_info is not needed, since we require all chip selects to be
+	 * in the device tree explicitly
+	 */
+};
+
+#if CONFIG_IS_ENABLED(OF_CONTROL) && !CONFIG_IS_ENABLED(OF_PLATDATA)
+static int mxs_ofdata_to_platdata(struct udevice *bus)
+{
+	struct mxs_spi_platdata *plat = bus->platdata;
+	u32 prop[2];
+	int ret;
+
+	plat->base = dev_read_addr(bus);
+	plat->frequency =
+		dev_read_u32_default(bus, "spi-max-frequency", 40000000);
+	plat->num_cs = dev_read_u32_default(bus, "num-cs", 2);
+
+	ret = dev_read_u32_array(bus, "dmas", prop, ARRAY_SIZE(prop));
+	if (ret) {
+		printf("%s: Reading 'dmas' property failed!\n", __func__);
+		return ret;
+	}
+	plat->dma_id = prop[1];
+
+	ret = dev_read_u32_array(bus, "clocks", prop, ARRAY_SIZE(prop));
+	if (ret) {
+		printf("%s: Reading 'clocks' property failed!\n", __func__);
+		return ret;
+	}
+	plat->clk_id = prop[1];
+
+	debug("%s: base=0x%x, max-frequency=%d num-cs=%d dma_id=%d clk_id=%d\n",
+	      __func__, (uint)plat->base, plat->frequency, plat->num_cs,
+	      plat->dma_id, plat->clk_id);
+
+	return 0;
+}
+#endif
+
+static const struct udevice_id mxs_spi_ids[] = {
+	{ .compatible = "fsl,imx23-spi" },
+	{ .compatible = "fsl,imx28-spi" },
+	{ }
+};
+
+U_BOOT_DRIVER(mxs_spi) = {
+	.name	= "mxs_spi",
+	.id	= UCLASS_SPI,
+#if CONFIG_IS_ENABLED(OF_CONTROL) && !CONFIG_IS_ENABLED(OF_PLATDATA)
+	.of_match = mxs_spi_ids,
+	.ofdata_to_platdata = mxs_ofdata_to_platdata,
+#endif
+	.priv_auto_alloc_size = sizeof(struct mxs_spi_platdata),
+	.ops	= &mxs_spi_ops,
+	.priv_auto_alloc_size = sizeof(struct mxs_spi_priv),
+	.probe	= mxs_spi_probe,
+};
+#endif
diff --git a/drivers/spi/spi-mem.c b/drivers/spi/spi-mem.c
index 7aabebe..7788ab9 100644
--- a/drivers/spi/spi-mem.c
+++ b/drivers/spi/spi-mem.c
@@ -430,12 +430,14 @@
 		if (slave->max_write_size && len > slave->max_write_size)
 			return -EINVAL;
 
-		if (op->data.dir == SPI_MEM_DATA_IN && slave->max_read_size)
-			op->data.nbytes = min(op->data.nbytes,
+		if (op->data.dir == SPI_MEM_DATA_IN) {
+			if (slave->max_read_size)
+				op->data.nbytes = min(op->data.nbytes,
 					      slave->max_read_size);
-		else if (slave->max_write_size)
+		} else if (slave->max_write_size) {
 			op->data.nbytes = min(op->data.nbytes,
 					      slave->max_write_size - len);
+		}
 
 		if (!op->data.nbytes)
 			return -EINVAL;
diff --git a/drivers/spi/spi-sifive.c b/drivers/spi/spi-sifive.c
new file mode 100644
index 0000000..969bd4b
--- /dev/null
+++ b/drivers/spi/spi-sifive.c
@@ -0,0 +1,370 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2018 SiFive, Inc.
+ * Copyright 2019 Bhargav Shah <bhargavshah1988@gmail.com>
+ *
+ * SiFive SPI controller driver (master mode only)
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <malloc.h>
+#include <spi.h>
+#include <asm/io.h>
+#include <linux/log2.h>
+#include <clk.h>
+
+#define SIFIVE_SPI_MAX_CS		32
+
+#define SIFIVE_SPI_DEFAULT_DEPTH	8
+#define SIFIVE_SPI_DEFAULT_BITS		8
+
+/* register offsets */
+#define SIFIVE_SPI_REG_SCKDIV            0x00 /* Serial clock divisor */
+#define SIFIVE_SPI_REG_SCKMODE           0x04 /* Serial clock mode */
+#define SIFIVE_SPI_REG_CSID              0x10 /* Chip select ID */
+#define SIFIVE_SPI_REG_CSDEF             0x14 /* Chip select default */
+#define SIFIVE_SPI_REG_CSMODE            0x18 /* Chip select mode */
+#define SIFIVE_SPI_REG_DELAY0            0x28 /* Delay control 0 */
+#define SIFIVE_SPI_REG_DELAY1            0x2c /* Delay control 1 */
+#define SIFIVE_SPI_REG_FMT               0x40 /* Frame format */
+#define SIFIVE_SPI_REG_TXDATA            0x48 /* Tx FIFO data */
+#define SIFIVE_SPI_REG_RXDATA            0x4c /* Rx FIFO data */
+#define SIFIVE_SPI_REG_TXMARK            0x50 /* Tx FIFO watermark */
+#define SIFIVE_SPI_REG_RXMARK            0x54 /* Rx FIFO watermark */
+#define SIFIVE_SPI_REG_FCTRL             0x60 /* SPI flash interface control */
+#define SIFIVE_SPI_REG_FFMT              0x64 /* SPI flash instruction format */
+#define SIFIVE_SPI_REG_IE                0x70 /* Interrupt Enable Register */
+#define SIFIVE_SPI_REG_IP                0x74 /* Interrupt Pendings Register */
+
+/* sckdiv bits */
+#define SIFIVE_SPI_SCKDIV_DIV_MASK       0xfffU
+
+/* sckmode bits */
+#define SIFIVE_SPI_SCKMODE_PHA           BIT(0)
+#define SIFIVE_SPI_SCKMODE_POL           BIT(1)
+#define SIFIVE_SPI_SCKMODE_MODE_MASK     (SIFIVE_SPI_SCKMODE_PHA | \
+					  SIFIVE_SPI_SCKMODE_POL)
+
+/* csmode bits */
+#define SIFIVE_SPI_CSMODE_MODE_AUTO      0U
+#define SIFIVE_SPI_CSMODE_MODE_HOLD      2U
+#define SIFIVE_SPI_CSMODE_MODE_OFF       3U
+
+/* delay0 bits */
+#define SIFIVE_SPI_DELAY0_CSSCK(x)       ((u32)(x))
+#define SIFIVE_SPI_DELAY0_CSSCK_MASK     0xffU
+#define SIFIVE_SPI_DELAY0_SCKCS(x)       ((u32)(x) << 16)
+#define SIFIVE_SPI_DELAY0_SCKCS_MASK     (0xffU << 16)
+
+/* delay1 bits */
+#define SIFIVE_SPI_DELAY1_INTERCS(x)     ((u32)(x))
+#define SIFIVE_SPI_DELAY1_INTERCS_MASK   0xffU
+#define SIFIVE_SPI_DELAY1_INTERXFR(x)    ((u32)(x) << 16)
+#define SIFIVE_SPI_DELAY1_INTERXFR_MASK  (0xffU << 16)
+
+/* fmt bits */
+#define SIFIVE_SPI_FMT_PROTO_SINGLE      0U
+#define SIFIVE_SPI_FMT_PROTO_DUAL        1U
+#define SIFIVE_SPI_FMT_PROTO_QUAD        2U
+#define SIFIVE_SPI_FMT_PROTO_MASK        3U
+#define SIFIVE_SPI_FMT_ENDIAN            BIT(2)
+#define SIFIVE_SPI_FMT_DIR               BIT(3)
+#define SIFIVE_SPI_FMT_LEN(x)            ((u32)(x) << 16)
+#define SIFIVE_SPI_FMT_LEN_MASK          (0xfU << 16)
+
+/* txdata bits */
+#define SIFIVE_SPI_TXDATA_DATA_MASK      0xffU
+#define SIFIVE_SPI_TXDATA_FULL           BIT(31)
+
+/* rxdata bits */
+#define SIFIVE_SPI_RXDATA_DATA_MASK      0xffU
+#define SIFIVE_SPI_RXDATA_EMPTY          BIT(31)
+
+/* ie and ip bits */
+#define SIFIVE_SPI_IP_TXWM               BIT(0)
+#define SIFIVE_SPI_IP_RXWM               BIT(1)
+
+struct sifive_spi {
+	void		*regs;		/* base address of the registers */
+	u32		fifo_depth;
+	u32		bits_per_word;
+	u32		cs_inactive;	/* Level of the CS pins when inactive*/
+	u32		freq;
+	u32		num_cs;
+};
+
+static void sifive_spi_prep_device(struct sifive_spi *spi,
+				   struct dm_spi_slave_platdata *slave)
+{
+	/* Update the chip select polarity */
+	if (slave->mode & SPI_CS_HIGH)
+		spi->cs_inactive &= ~BIT(slave->cs);
+	else
+		spi->cs_inactive |= BIT(slave->cs);
+	writel(spi->cs_inactive, spi->regs + SIFIVE_SPI_REG_CSDEF);
+
+	/* Select the correct device */
+	writel(slave->cs, spi->regs + SIFIVE_SPI_REG_CSID);
+}
+
+static int sifive_spi_set_cs(struct sifive_spi *spi,
+			     struct dm_spi_slave_platdata *slave)
+{
+	u32 cs_mode = SIFIVE_SPI_CSMODE_MODE_HOLD;
+
+	if (slave->mode & SPI_CS_HIGH)
+		cs_mode = SIFIVE_SPI_CSMODE_MODE_AUTO;
+
+	writel(cs_mode, spi->regs + SIFIVE_SPI_REG_CSMODE);
+
+	return 0;
+}
+
+static void sifive_spi_clear_cs(struct sifive_spi *spi)
+{
+	writel(SIFIVE_SPI_CSMODE_MODE_AUTO, spi->regs + SIFIVE_SPI_REG_CSMODE);
+}
+
+static void sifive_spi_prep_transfer(struct sifive_spi *spi,
+				     bool is_rx_xfer,
+				     struct dm_spi_slave_platdata *slave)
+{
+	u32 cr;
+
+	/* Modify the SPI protocol mode */
+	cr = readl(spi->regs + SIFIVE_SPI_REG_FMT);
+
+	/* Bits per word ? */
+	cr &= ~SIFIVE_SPI_FMT_LEN_MASK;
+	cr |= SIFIVE_SPI_FMT_LEN(spi->bits_per_word);
+
+	/* LSB first? */
+	cr &= ~SIFIVE_SPI_FMT_ENDIAN;
+	if (slave->mode & SPI_LSB_FIRST)
+		cr |= SIFIVE_SPI_FMT_ENDIAN;
+
+	/* Number of wires ? */
+	cr &= ~SIFIVE_SPI_FMT_PROTO_MASK;
+	if ((slave->mode & SPI_TX_QUAD) || (slave->mode & SPI_RX_QUAD))
+		cr |= SIFIVE_SPI_FMT_PROTO_QUAD;
+	else if ((slave->mode & SPI_TX_DUAL) || (slave->mode & SPI_RX_DUAL))
+		cr |= SIFIVE_SPI_FMT_PROTO_DUAL;
+	else
+		cr |= SIFIVE_SPI_FMT_PROTO_SINGLE;
+
+	/* SPI direction in/out ? */
+	cr &= ~SIFIVE_SPI_FMT_DIR;
+	if (!is_rx_xfer)
+		cr |= SIFIVE_SPI_FMT_DIR;
+
+	writel(cr, spi->regs + SIFIVE_SPI_REG_FMT);
+}
+
+static void sifive_spi_rx(struct sifive_spi *spi, u8 *rx_ptr)
+{
+	u32 data;
+
+	do {
+		data = readl(spi->regs + SIFIVE_SPI_REG_RXDATA);
+	} while (data & SIFIVE_SPI_RXDATA_EMPTY);
+
+	if (rx_ptr)
+		*rx_ptr = data & SIFIVE_SPI_RXDATA_DATA_MASK;
+}
+
+static void sifive_spi_tx(struct sifive_spi *spi, const u8 *tx_ptr)
+{
+	u32 data;
+	u8 tx_data = (tx_ptr) ? *tx_ptr & SIFIVE_SPI_TXDATA_DATA_MASK :
+				SIFIVE_SPI_TXDATA_DATA_MASK;
+
+	do {
+		data = readl(spi->regs + SIFIVE_SPI_REG_TXDATA);
+	} while (data & SIFIVE_SPI_TXDATA_FULL);
+
+	writel(tx_data, spi->regs + SIFIVE_SPI_REG_TXDATA);
+}
+
+static int sifive_spi_xfer(struct udevice *dev, unsigned int bitlen,
+			   const void *dout, void *din, unsigned long flags)
+{
+	struct udevice *bus = dev->parent;
+	struct sifive_spi *spi = dev_get_priv(bus);
+	struct dm_spi_slave_platdata *slave = dev_get_parent_platdata(dev);
+	const unsigned char *tx_ptr = dout;
+	u8 *rx_ptr = din;
+	u32 remaining_len;
+	int ret;
+
+	if (flags & SPI_XFER_BEGIN) {
+		sifive_spi_prep_device(spi, slave);
+
+		ret = sifive_spi_set_cs(spi, slave);
+		if (ret)
+			return ret;
+	}
+
+	sifive_spi_prep_transfer(spi, true, slave);
+
+	remaining_len = bitlen / 8;
+
+	while (remaining_len) {
+		int n_words, tx_words, rx_words;
+
+		n_words = min(remaining_len, spi->fifo_depth);
+
+		/* Enqueue n_words for transmission */
+		if (tx_ptr) {
+			for (tx_words = 0; tx_words < n_words; ++tx_words) {
+				sifive_spi_tx(spi, tx_ptr);
+				sifive_spi_rx(spi, NULL);
+				tx_ptr++;
+			}
+		}
+
+		/* Read out all the data from the RX FIFO */
+		if (rx_ptr) {
+			for (rx_words = 0; rx_words < n_words; ++rx_words) {
+				sifive_spi_tx(spi, NULL);
+				sifive_spi_rx(spi, rx_ptr);
+				rx_ptr++;
+			}
+		}
+
+		remaining_len -= n_words;
+	}
+
+	if (flags & SPI_XFER_END)
+		sifive_spi_clear_cs(spi);
+
+	return 0;
+}
+
+static int sifive_spi_set_speed(struct udevice *bus, uint speed)
+{
+	struct sifive_spi *spi = dev_get_priv(bus);
+	u32 scale;
+
+	if (speed > spi->freq)
+		speed = spi->freq;
+
+	/* Cofigure max speed */
+	scale = (DIV_ROUND_UP(spi->freq >> 1, speed) - 1)
+					& SIFIVE_SPI_SCKDIV_DIV_MASK;
+	writel(scale, spi->regs + SIFIVE_SPI_REG_SCKDIV);
+
+	return 0;
+}
+
+static int sifive_spi_set_mode(struct udevice *bus, uint mode)
+{
+	struct sifive_spi *spi = dev_get_priv(bus);
+	u32 cr;
+
+	/* Switch clock mode bits */
+	cr = readl(spi->regs + SIFIVE_SPI_REG_SCKMODE) &
+				~SIFIVE_SPI_SCKMODE_MODE_MASK;
+	if (mode & SPI_CPHA)
+		cr |= SIFIVE_SPI_SCKMODE_PHA;
+	if (mode & SPI_CPOL)
+		cr |= SIFIVE_SPI_SCKMODE_POL;
+
+	writel(cr, spi->regs + SIFIVE_SPI_REG_SCKMODE);
+
+	return 0;
+}
+
+static int sifive_spi_cs_info(struct udevice *bus, uint cs,
+			      struct spi_cs_info *info)
+{
+	struct sifive_spi *spi = dev_get_priv(bus);
+
+	if (cs >= spi->num_cs)
+		return -EINVAL;
+
+	return 0;
+}
+
+static void sifive_spi_init_hw(struct sifive_spi *spi)
+{
+	u32 cs_bits;
+
+	/* probe the number of CS lines */
+	spi->cs_inactive = readl(spi->regs + SIFIVE_SPI_REG_CSDEF);
+	writel(0xffffffffU, spi->regs + SIFIVE_SPI_REG_CSDEF);
+	cs_bits = readl(spi->regs + SIFIVE_SPI_REG_CSDEF);
+	writel(spi->cs_inactive, spi->regs + SIFIVE_SPI_REG_CSDEF);
+	if (!cs_bits) {
+		printf("Could not auto probe CS lines\n");
+		return;
+	}
+
+	spi->num_cs = ilog2(cs_bits) + 1;
+	if (spi->num_cs > SIFIVE_SPI_MAX_CS) {
+		printf("Invalid number of spi slaves\n");
+		return;
+	}
+
+	/* Watermark interrupts are disabled by default */
+	writel(0, spi->regs + SIFIVE_SPI_REG_IE);
+
+	/* Set CS/SCK Delays and Inactive Time to defaults */
+	writel(SIFIVE_SPI_DELAY0_CSSCK(1) | SIFIVE_SPI_DELAY0_SCKCS(1),
+	       spi->regs + SIFIVE_SPI_REG_DELAY0);
+	writel(SIFIVE_SPI_DELAY1_INTERCS(1) | SIFIVE_SPI_DELAY1_INTERXFR(0),
+	       spi->regs + SIFIVE_SPI_REG_DELAY1);
+
+	/* Exit specialized memory-mapped SPI flash mode */
+	writel(0, spi->regs + SIFIVE_SPI_REG_FCTRL);
+}
+
+static int sifive_spi_probe(struct udevice *bus)
+{
+	struct sifive_spi *spi = dev_get_priv(bus);
+	struct clk clkdev;
+	int ret;
+
+	spi->regs = (void *)(ulong)dev_remap_addr(bus);
+	if (!spi->regs)
+		return -ENODEV;
+
+	spi->fifo_depth = dev_read_u32_default(bus,
+					       "sifive,fifo-depth",
+					       SIFIVE_SPI_DEFAULT_DEPTH);
+
+	spi->bits_per_word = dev_read_u32_default(bus,
+						  "sifive,max-bits-per-word",
+						  SIFIVE_SPI_DEFAULT_BITS);
+
+	ret = clk_get_by_index(bus, 0, &clkdev);
+	if (ret)
+		return ret;
+	spi->freq = clk_get_rate(&clkdev);
+
+	/* init the sifive spi hw */
+	sifive_spi_init_hw(spi);
+
+	return 0;
+}
+
+static const struct dm_spi_ops sifive_spi_ops = {
+	.xfer		= sifive_spi_xfer,
+	.set_speed	= sifive_spi_set_speed,
+	.set_mode	= sifive_spi_set_mode,
+	.cs_info        = sifive_spi_cs_info,
+};
+
+static const struct udevice_id sifive_spi_ids[] = {
+	{ .compatible = "sifive,spi0" },
+	{ }
+};
+
+U_BOOT_DRIVER(sifive_spi) = {
+	.name	= "sifive_spi",
+	.id	= UCLASS_SPI,
+	.of_match = sifive_spi_ids,
+	.ops	= &sifive_spi_ops,
+	.priv_auto_alloc_size = sizeof(struct sifive_spi),
+	.probe	= sifive_spi_probe,
+};
diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig
index a71b9be..bdf8dc6 100644
--- a/drivers/thermal/Kconfig
+++ b/drivers/thermal/Kconfig
@@ -17,6 +17,15 @@
           cpufreq is used as the cooling device to throttle CPUs when the
           passive trip is crossed.
 
+config IMX_SCU_THERMAL
+	bool "Temperature sensor driver for NXP i.MX8"
+	depends on ARCH_IMX8
+	help
+	  Support for Temperature sensors on NXP i.MX8.
+	  It supports one critical trip point and one passive trip point. The
+	  boot is hold to the cool device to throttle CPUs when the passive
+	  trip is crossed
+
 config TI_DRA7_THERMAL
         bool "Temperature sensor driver for TI dra7xx SOCs"
         help
diff --git a/drivers/thermal/Makefile b/drivers/thermal/Makefile
index cc75e38..ef2929d 100644
--- a/drivers/thermal/Makefile
+++ b/drivers/thermal/Makefile
@@ -5,4 +5,5 @@
 
 obj-$(CONFIG_DM_THERMAL) += thermal-uclass.o
 obj-$(CONFIG_IMX_THERMAL) += imx_thermal.o
+obj-$(CONFIG_IMX_SCU_THERMAL) += imx_scu_thermal.o
 obj-$(CONFIG_TI_DRA7_THERMAL) += ti-bandgap.o
diff --git a/drivers/thermal/imx_scu_thermal.c b/drivers/thermal/imx_scu_thermal.c
new file mode 100644
index 0000000..7e17377
--- /dev/null
+++ b/drivers/thermal/imx_scu_thermal.c
@@ -0,0 +1,203 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2019 NXP
+ */
+
+#include <config.h>
+#include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <thermal.h>
+#include <dm/device-internal.h>
+#include <dm/device.h>
+#include <asm/arch/sci/sci.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+struct imx_sc_thermal_plat {
+	int critical;
+	int alert;
+	int polling_delay;
+	int id;
+	bool zone_node;
+};
+
+static int read_temperature(struct udevice *dev, int *temp)
+{
+	s16 celsius;
+	s8 tenths;
+	int ret;
+
+	sc_rsrc_t *sensor_rsrc = (sc_rsrc_t *)dev_get_driver_data(dev);
+
+	struct imx_sc_thermal_plat *pdata = dev_get_platdata(dev);
+
+	if (!temp)
+		return -EINVAL;
+
+	ret = sc_misc_get_temp(-1, sensor_rsrc[pdata->id], SC_C_TEMP,
+			       &celsius, &tenths);
+	if (ret) {
+		printf("Error: get temperature failed! (error = %d)\n", ret);
+		return ret;
+	}
+
+	*temp = celsius * 1000 + tenths * 100;
+
+	return 0;
+}
+
+int imx_sc_thermal_get_temp(struct udevice *dev, int *temp)
+{
+	struct imx_sc_thermal_plat *pdata = dev_get_platdata(dev);
+	int cpu_temp = 0;
+	int ret;
+
+	ret = read_temperature(dev, &cpu_temp);
+	if (ret)
+		return ret;
+
+	while (cpu_temp >= pdata->alert) {
+		printf("CPU Temperature (%dC) has beyond alert (%dC), close to critical (%dC)",
+		       cpu_temp, pdata->alert, pdata->critical);
+		puts(" waiting...\n");
+		mdelay(pdata->polling_delay);
+		ret = read_temperature(dev, &cpu_temp);
+		if (ret)
+			return ret;
+	}
+
+	*temp = cpu_temp / 1000;
+
+	return 0;
+}
+
+static const struct dm_thermal_ops imx_sc_thermal_ops = {
+	.get_temp	= imx_sc_thermal_get_temp,
+};
+
+static int imx_sc_thermal_probe(struct udevice *dev)
+{
+	debug("%s dev name %s\n", __func__, dev->name);
+	return 0;
+}
+
+static int imx_sc_thermal_bind(struct udevice *dev)
+{
+	struct imx_sc_thermal_plat *pdata = dev_get_platdata(dev);
+	int reg, ret;
+	int offset;
+	const char *name;
+	const void *prop;
+
+	debug("%s dev name %s\n", __func__, dev->name);
+
+	prop = fdt_getprop(gd->fdt_blob, dev_of_offset(dev), "compatible",
+			   NULL);
+	if (!prop)
+		return 0;
+
+	pdata->zone_node = 1;
+
+	reg = fdtdec_get_int(gd->fdt_blob, dev_of_offset(dev), "tsens-num", 0);
+	if (reg == 0) {
+		printf("%s: no temp sensor number provided!\n", __func__);
+		return -EINVAL;
+	}
+
+	offset = fdt_subnode_offset(gd->fdt_blob, 0, "thermal-zones");
+	fdt_for_each_subnode(offset, gd->fdt_blob, offset) {
+		/* Bind the subnode to this driver */
+		name = fdt_get_name(gd->fdt_blob, offset, NULL);
+
+		ret = device_bind_with_driver_data(dev, dev->driver, name,
+						   dev->driver_data,
+						   offset_to_ofnode(offset),
+						   NULL);
+		if (ret)
+			printf("Error binding driver '%s': %d\n",
+			       dev->driver->name, ret);
+	}
+	return 0;
+}
+
+static int imx_sc_thermal_ofdata_to_platdata(struct udevice *dev)
+{
+	struct imx_sc_thermal_plat *pdata = dev_get_platdata(dev);
+	struct fdtdec_phandle_args args;
+	const char *type;
+	int ret;
+	int trips_np;
+
+	debug("%s dev name %s\n", __func__, dev->name);
+
+	if (pdata->zone_node)
+		return 0;
+
+	ret = fdtdec_parse_phandle_with_args(gd->fdt_blob, dev_of_offset(dev),
+					     "thermal-sensors",
+					     "#thermal-sensor-cells",
+					     0, 0, &args);
+	if (ret)
+		return ret;
+
+	if (args.node != dev_of_offset(dev->parent))
+		return -EFAULT;
+
+	if (args.args_count >= 1)
+		pdata->id = args.args[0];
+	else
+		pdata->id = 0;
+
+	debug("args.args_count %d, id %d\n", args.args_count, pdata->id);
+
+	pdata->polling_delay = fdtdec_get_int(gd->fdt_blob, dev_of_offset(dev),
+					      "polling-delay", 1000);
+
+	trips_np = fdt_subnode_offset(gd->fdt_blob, dev_of_offset(dev),
+				      "trips");
+	fdt_for_each_subnode(trips_np, gd->fdt_blob, trips_np) {
+		type = fdt_getprop(gd->fdt_blob, trips_np, "type", NULL);
+		if (type) {
+			if (strcmp(type, "critical") == 0) {
+				pdata->critical = fdtdec_get_int(gd->fdt_blob,
+								 trips_np,
+								 "temperature",
+								 85);
+			} else if (strcmp(type, "passive") == 0) {
+				pdata->alert = fdtdec_get_int(gd->fdt_blob,
+							      trips_np,
+							      "temperature",
+							      80);
+			}
+		}
+	}
+
+	debug("id %d polling_delay %d, critical %d, alert %d\n", pdata->id,
+	      pdata->polling_delay, pdata->critical, pdata->alert);
+
+	return 0;
+}
+
+static const sc_rsrc_t imx8qxp_sensor_rsrc[] = {
+	SC_R_SYSTEM, SC_R_DRC_0, SC_R_PMIC_0,
+	SC_R_PMIC_1, SC_R_PMIC_2,
+};
+
+static const struct udevice_id imx_sc_thermal_ids[] = {
+	{ .compatible = "nxp,imx8qxp-sc-tsens", .data =
+		(ulong)&imx8qxp_sensor_rsrc, },
+	{ }
+};
+
+U_BOOT_DRIVER(imx_sc_thermal) = {
+	.name	= "imx_sc_thermal",
+	.id	= UCLASS_THERMAL,
+	.ops	= &imx_sc_thermal_ops,
+	.of_match = imx_sc_thermal_ids,
+	.bind = imx_sc_thermal_bind,
+	.probe	= imx_sc_thermal_probe,
+	.ofdata_to_platdata = imx_sc_thermal_ofdata_to_platdata,
+	.platdata_auto_alloc_size = sizeof(struct imx_sc_thermal_plat),
+	.flags  = DM_FLAG_PRE_RELOC,
+};
diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig
index ee0ddff..ccda432 100644
--- a/drivers/watchdog/Kconfig
+++ b/drivers/watchdog/Kconfig
@@ -28,7 +28,7 @@
 
 config IMX_WATCHDOG
 	bool "Enable Watchdog Timer support for IMX and LSCH2 of NXP"
-	select HW_WATCHDOG
+	select HW_WATCHDOG if !WDT
 	help
 	   Select this to enable the IMX and LSCH2 of Layerscape watchdog
 	   driver.
@@ -169,4 +169,11 @@
 	  Intel Tangier SoC. If you're using a board with Intel Tangier
 	  SoC, say Y here.
 
+config SPL_WDT
+	bool "Enable driver model for watchdog timer drivers in SPL"
+	depends on SPL_DM
+	help
+	  Enable driver model for watchdog timer in SPL.
+	  This is similar to CONFIG_WDT in U-Boot.
+
 endmenu
diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile
index 68c989a..97aa6a8 100644
--- a/drivers/watchdog/Makefile
+++ b/drivers/watchdog/Makefile
@@ -15,7 +15,7 @@
 obj-$(CONFIG_OMAP_WATCHDOG) += omap_wdt.o
 obj-$(CONFIG_DESIGNWARE_WATCHDOG) += designware_wdt.o
 obj-$(CONFIG_ULP_WATCHDOG) += ulp_wdog.o
-obj-$(CONFIG_WDT) += wdt-uclass.o
+obj-$(CONFIG_$(SPL_TPL_)WDT) += wdt-uclass.o
 obj-$(CONFIG_WDT_SANDBOX) += sandbox_wdt.o
 obj-$(CONFIG_WDT_ARMADA_37XX) += armada-37xx-wdt.o
 obj-$(CONFIG_WDT_ASPEED) += ast_wdt.o
diff --git a/drivers/watchdog/imx_watchdog.c b/drivers/watchdog/imx_watchdog.c
index 14cc618..53a3e9f 100644
--- a/drivers/watchdog/imx_watchdog.c
+++ b/drivers/watchdog/imx_watchdog.c
@@ -5,7 +5,9 @@
  */
 
 #include <common.h>
+#include <dm.h>
 #include <asm/io.h>
+#include <wdt.h>
 #include <watchdog.h>
 #include <asm/arch/imx-regs.h>
 #ifdef CONFIG_FSL_LSCH2
@@ -13,20 +15,40 @@
 #endif
 #include <fsl_wdog.h>
 
-#ifdef CONFIG_IMX_WATCHDOG
-void hw_watchdog_reset(void)
+static void imx_watchdog_expire_now(struct watchdog_regs *wdog)
 {
-#ifndef CONFIG_WATCHDOG_RESET_DISABLE
+	clrsetbits_le16(&wdog->wcr, WCR_WT_MSK, WCR_WDE);
+
+	writew(0x5555, &wdog->wsr);
+	writew(0xaaaa, &wdog->wsr);	/* load minimum 1/2 second timeout */
+	while (1) {
+		/*
+		 * spin for .5 seconds before reset
+		 */
+	}
+}
+
+#if !defined(CONFIG_IMX_WATCHDOG) || \
+    (defined(CONFIG_IMX_WATCHDOG) && !CONFIG_IS_ENABLED(WDT))
+void __attribute__((weak)) reset_cpu(ulong addr)
+{
 	struct watchdog_regs *wdog = (struct watchdog_regs *)WDOG1_BASE_ADDR;
 
+	imx_watchdog_expire_now(wdog);
+}
+#endif
+
+#if defined(CONFIG_IMX_WATCHDOG)
+static void imx_watchdog_reset(struct watchdog_regs *wdog)
+{
+#ifndef CONFIG_WATCHDOG_RESET_DISABLE
 	writew(0x5555, &wdog->wsr);
 	writew(0xaaaa, &wdog->wsr);
 #endif /* CONFIG_WATCHDOG_RESET_DISABLE*/
 }
 
-void hw_watchdog_init(void)
+static void imx_watchdog_init(struct watchdog_regs *wdog)
 {
-	struct watchdog_regs *wdog = (struct watchdog_regs *)WDOG1_BASE_ADDR;
 	u16 timeout;
 
 	/*
@@ -44,21 +66,86 @@
 	writew(WCR_WDZST | WCR_WDBG | WCR_WDE | WCR_WDT | WCR_SRS |
 		WCR_WDA | SET_WCR_WT(timeout), &wdog->wcr);
 #endif /* CONFIG_FSL_LSCH2*/
-	hw_watchdog_reset();
+	imx_watchdog_reset(wdog);
 }
-#endif
 
-void __attribute__((weak)) reset_cpu(ulong addr)
+#if !CONFIG_IS_ENABLED(WDT)
+void hw_watchdog_reset(void)
 {
 	struct watchdog_regs *wdog = (struct watchdog_regs *)WDOG1_BASE_ADDR;
 
-	clrsetbits_le16(&wdog->wcr, WCR_WT_MSK, WCR_WDE);
+	imx_watchdog_reset(wdog);
+}
 
-	writew(0x5555, &wdog->wsr);
-	writew(0xaaaa, &wdog->wsr);	/* load minimum 1/2 second timeout */
-	while (1) {
-		/*
-		 * spin for .5 seconds before reset
-		 */
-	}
+void hw_watchdog_init(void)
+{
+	struct watchdog_regs *wdog = (struct watchdog_regs *)WDOG1_BASE_ADDR;
+
+	imx_watchdog_init(wdog);
+}
+#else
+struct imx_wdt_priv {
+	void __iomem *base;
+};
+
+static int imx_wdt_reset(struct udevice *dev)
+{
+	struct imx_wdt_priv *priv = dev_get_priv(dev);
+
+	imx_watchdog_reset(priv->base);
+
+	return 0;
+}
+
+static int imx_wdt_expire_now(struct udevice *dev, ulong flags)
+{
+	struct imx_wdt_priv *priv = dev_get_priv(dev);
+
+	imx_watchdog_expire_now(priv->base);
+	hang();
+
+	return 0;
+}
+
+static int imx_wdt_start(struct udevice *dev, u64 timeout, ulong flags)
+{
+	struct imx_wdt_priv *priv = dev_get_priv(dev);
+
+	imx_watchdog_init(priv->base);
+
+	return 0;
+}
+
+static int imx_wdt_probe(struct udevice *dev)
+{
+	struct imx_wdt_priv *priv = dev_get_priv(dev);
+
+	priv->base = dev_read_addr_ptr(dev);
+	if (!priv->base)
+		return -ENOENT;
+
+	return 0;
 }
+
+static const struct wdt_ops imx_wdt_ops = {
+	.start		= imx_wdt_start,
+	.reset		= imx_wdt_reset,
+	.expire_now	= imx_wdt_expire_now,
+};
+
+static const struct udevice_id imx_wdt_ids[] = {
+	{ .compatible = "fsl,imx21-wdt" },
+	{}
+};
+
+U_BOOT_DRIVER(imx_wdt) = {
+	.name		= "imx_wdt",
+	.id		= UCLASS_WDT,
+	.of_match	= imx_wdt_ids,
+	.probe		= imx_wdt_probe,
+	.ops		= &imx_wdt_ops,
+	.priv_auto_alloc_size = sizeof(struct imx_wdt_priv),
+	.flags		= DM_FLAG_PRE_RELOC,
+};
+#endif
+#endif
diff --git a/include/asm-generic/global_data.h b/include/asm-generic/global_data.h
index 02a3ed6..7c22206 100644
--- a/include/asm-generic/global_data.h
+++ b/include/asm-generic/global_data.h
@@ -137,7 +137,7 @@
 #if defined(CONFIG_TRANSLATION_OFFSET)
 	fdt_addr_t translation_offset;	/* optional translation offset */
 #endif
-#if defined(CONFIG_WDT)
+#if CONFIG_IS_ENABLED(WDT)
 	struct udevice *watchdog_dev;
 #endif
 } gd_t;
diff --git a/include/clk.h b/include/clk.h
index d24e997..f8f56d9 100644
--- a/include/clk.h
+++ b/include/clk.h
@@ -20,7 +20,7 @@
  * clock provider. This API provides a standard means for drivers to enable and
  * disable clocks, and to set the rate at which they oscillate.
  *
- * A driver that implements UCLASS_CLOCK is a clock provider. A provider will
+ * A driver that implements UCLASS_CLK is a clock provider. A provider will
  * often implement multiple separate clocks, since the hardware it manages
  * often has this capability. clk-uclass.h describes the interface which
  * clock providers must implement.
@@ -40,6 +40,10 @@
  * other clock APIs to identify which clock signal to operate upon.
  *
  * @dev: The device which implements the clock signal.
+ * @rate: The clock rate (in HZ).
+ * @flags: Flags used across common clock structure (e.g. CLK_)
+ *         Clock IP blocks specific flags (i.e. mux, div, gate, etc) are defined
+ *         in struct's for those devices (e.g. struct clk_mux).
  * @id: The clock signal ID within the provider.
  * @data: An optional data field for scenarios where a single integer ID is not
  *	  sufficient. If used, it can be populated through an .of_xlate op and
@@ -55,6 +59,8 @@
  */
 struct clk {
 	struct udevice *dev;
+	long long rate;	/* in HZ */
+	u32 flags;
 	/*
 	 * Written by of_xlate. In the future, we might add more fields here.
 	 */
@@ -253,6 +259,24 @@
 ulong clk_get_rate(struct clk *clk);
 
 /**
+ * clk_get_parent() - Get current clock's parent.
+ *
+ * @clk:	A clock struct that was previously successfully requested by
+ *		clk_request/get_by_*().
+ * @return pointer to parent's struct clk, or error code passed as pointer
+ */
+struct clk *clk_get_parent(struct clk *clk);
+
+/**
+ * clk_get_parent_rate() - Get parent of current clock rate.
+ *
+ * @clk:	A clock struct that was previously successfully requested by
+ *		clk_request/get_by_*().
+ * @return clock rate in Hz, or -ve error code.
+ */
+long long clk_get_parent_rate(struct clk *clk);
+
+/**
  * clk_set_rate() - Set current clock rate.
  *
  * @clk:	A clock struct that was previously successfully requested by
@@ -321,4 +345,15 @@
 {
 	return !!clk->dev;
 }
+
+/**
+ * clk_get_by_id() - Get the clock by its ID
+ *
+ * @id:	The clock ID to search for
+ *
+ * @clkp:	A pointer to clock struct that has been found among added clocks
+ *              to UCLASS_CLK
+ * @return zero on success, or -ENOENT on error
+ */
+int clk_get_by_id(ulong id, struct clk **clkp);
 #endif
diff --git a/include/configs/advantech_dms-ba16.h b/include/configs/advantech_dms-ba16.h
index 22d1e41..a037349 100644
--- a/include/configs/advantech_dms-ba16.h
+++ b/include/configs/advantech_dms-ba16.h
@@ -223,7 +223,6 @@
 #define CONFIG_IMX_VIDEO_SKIP
 #endif
 
-#define CONFIG_PWM_IMX
 #define CONFIG_IMX6_PWM_PER_CLK         66000000
 
 #ifdef CONFIG_CMD_PCI
diff --git a/include/configs/apalis_imx6.h b/include/configs/apalis_imx6.h
index db37fa7..974571d 100644
--- a/include/configs/apalis_imx6.h
+++ b/include/configs/apalis_imx6.h
@@ -176,27 +176,6 @@
 	"sdfinduuid=part uuid mmc ${sddev}:${sdrootpart} uuid\0" \
 	"sdrootpart=2\0"
 
-
-#define USB_BOOTCMD \
-	"set_usbargs=setenv usbargs ip=off root=PARTUUID=${uuid} ro,noatime " \
-		"rootfstype=ext4 rootwait\0" \
-	"usbboot=run setup; usb start; run usbfinduuid; run set_usbargs; " \
-		"setenv bootargs ${defargs} ${setupargs} " \
-		"${usbargs} ${vidargs}; echo Booting from USB stick...; " \
-		"run usbdtbload; load usb " \
-		"${usbdev}:${usbbootpart} ${kernel_addr_r} " \
-		"${boot_file} && run fdt_fixup && " \
-		"bootz ${kernel_addr_r} ${dtbparam}\0" \
-	"usbbootpart=1\0" \
-	"usbdev=0\0" \
-	"usbdtbload=setenv dtbparam; load usb ${usbdev}:${usbbootpart} "\
-		"${fdt_addr_r} " \
-		"${fdt_file} && setenv dtbparam \" - " \
-		"${fdt_addr_r}\" && true\0" \
-	"usbfinduuid=part uuid usb ${usbdev}:${usbrootpart} uuid\0" \
-	"usbrootpart=2\0"
-
-
 #ifndef CONFIG_TDX_APALIS_IMX6_V1_0
 #define FDT_FILE "imx6q-apalis-eval.dtb"
 #define FDT_FILE_V1_0 "imx6q-apalis_v1_0-eval.dtb"
@@ -219,7 +198,6 @@
 	MEM_LAYOUT_ENV_SETTINGS \
 	NFS_BOOTCMD \
 	SD_BOOTCMD \
-	USB_BOOTCMD \
 	"setethupdate=if env exists ethaddr; then; else setenv ethaddr " \
 		"00:14:2d:00:00:00; fi; tftpboot ${loadaddr} " \
 		"flash_eth.img && source ${loadaddr}\0" \
diff --git a/include/configs/aristainetos-common.h b/include/configs/aristainetos-common.h
index a248146..e998d9b 100644
--- a/include/configs/aristainetos-common.h
+++ b/include/configs/aristainetos-common.h
@@ -196,7 +196,6 @@
 #define CONFIG_VIDEO_BMP_LOGO
 #define CONFIG_IMX_VIDEO_SKIP
 
-#define CONFIG_PWM_IMX
 #define CONFIG_IMX6_PWM_PER_CLK	66000000
 
 #endif /* __ARISTAINETOS_COMMON_CONFIG_H */
diff --git a/include/configs/aristainetos2.h b/include/configs/aristainetos2.h
index 00e5667..361e6ac 100644
--- a/include/configs/aristainetos2.h
+++ b/include/configs/aristainetos2.h
@@ -45,9 +45,6 @@
 #define CONFIG_LG4573_BUS 0
 #define CONFIG_LG4573_CS 0
 
-#define CONFIG_PWM_IMX
-#define CONFIG_IMX6_PWM_PER_CLK	66000000
-
 #include "aristainetos-common.h"
 
 #endif                         /* __ARISTAINETOS2_CONFIG_H */
diff --git a/include/configs/aristainetos2b.h b/include/configs/aristainetos2b.h
index cfe0e05..cdeb7a3 100644
--- a/include/configs/aristainetos2b.h
+++ b/include/configs/aristainetos2b.h
@@ -45,9 +45,6 @@
 #define CONFIG_LG4573_BUS 0
 #define CONFIG_LG4573_CS 1
 
-#define CONFIG_PWM_IMX
-#define CONFIG_IMX6_PWM_PER_CLK	66000000
-
 #include "aristainetos-common.h"
 
 #endif                         /* __ARISTAINETOS2B_CONFIG_H */
diff --git a/include/configs/colibri-imx6ull.h b/include/configs/colibri-imx6ull.h
index 21d9a3d..2c43862 100644
--- a/include/configs/colibri-imx6ull.h
+++ b/include/configs/colibri-imx6ull.h
@@ -123,7 +123,7 @@
 		"${board}/flash_blk.img && source ${loadaddr}\0" \
 	"splashpos=m,m\0" \
 	"videomode=video=ctfb:x:640,y:480,depth:18,pclk:39722,le:48,ri:16,up:33,lo:10,hs:96,vs:2,sync:0,vmode:0\0" \
-	"vidargs=video=mxsfb:640x480-16@60"
+	"vidargs=video=mxsfb:640x480M-16@60"
 
 #define CONFIG_SYS_MEMTEST_START	0x80000000
 #define CONFIG_SYS_MEMTEST_END		(CONFIG_SYS_MEMTEST_START + 0x08000000)
diff --git a/include/configs/colibri_imx6.h b/include/configs/colibri_imx6.h
index 86f3f0d..147f801 100644
--- a/include/configs/colibri_imx6.h
+++ b/include/configs/colibri_imx6.h
@@ -165,25 +165,6 @@
 	"sdfinduuid=part uuid mmc ${sddev}:${sdrootpart} uuid\0" \
 	"sdrootpart=2\0"
 
-#define USB_BOOTCMD \
-	"set_usbargs=setenv usbargs ip=off root=PARTUUID=${uuid} rw,noatime " \
-		"rootfstype=ext4 rootwait\0" \
-	"usbboot=run setup; usb start; run usbfinduuid; run set_usbargs; " \
-		"setenv bootargs ${defargs} ${setupargs} " \
-		"${usbargs} ${vidargs}; echo Booting from USB stick...; " \
-		"run usbdtbload; " \
-		"load usb ${usbdev}:${usbbootpart} ${kernel_addr_r} " \
-		"${boot_file} && run fdt_fixup && " \
-		"bootz ${kernel_addr_r} ${dtbparam}\0" \
-	"usbbootpart=1\0" \
-	"usbdev=0\0" \
-	"usbdtbload=setenv dtbparam; load usb ${usbdev}:${usbbootpart} " \
-		"${fdt_addr_r} " \
-		"${fdt_file} && setenv dtbparam \" - ${fdt_addr_r}\" && " \
-		"true\0" \
-	"usbfinduuid=part uuid usb ${usbdev}:${usbrootpart} uuid\0" \
-	"usbrootpart=2\0"
-
 #define FDT_FILE "imx6dl-colibri-eval-v3.dtb"
 #define CONFIG_EXTRA_ENV_SETTINGS \
 	BOOTENV \
@@ -201,7 +182,6 @@
 	MEM_LAYOUT_ENV_SETTINGS \
 	NFS_BOOTCMD \
 	SD_BOOTCMD \
-	USB_BOOTCMD \
 	"setethupdate=if env exists ethaddr; then; else setenv ethaddr " \
 		"00:14:2d:00:00:00; fi; tftpboot ${loadaddr} " \
 		"flash_eth.img && source ${loadaddr}\0" \
diff --git a/include/configs/colibri_imx7.h b/include/configs/colibri_imx7.h
index 40173b1..49cdd61 100644
--- a/include/configs/colibri_imx7.h
+++ b/include/configs/colibri_imx7.h
@@ -46,6 +46,46 @@
 #define CONFIG_NETMASK			255.255.255.0
 #define CONFIG_SERVERIP			192.168.10.1
 
+#ifndef PARTS_DEFAULT
+/* Define the default GPT table for eMMC */
+#define PARTS_DEFAULT \
+	/* Android partitions */ \
+	"partitions_android=" \
+	"uuid_disk=${uuid_gpt_disk};" \
+	"name=boot,start=1M,size=32M,uuid=${uuid_gpt_boot};" \
+	"name=environment,size=4M,uuid=${uuid_gpt_environment};" \
+	"name=recovery,size=16M,uuid=${uuid_gpt_recovery};" \
+	"name=system,size=1536M,uuid=${uuid_gpt_system};" \
+	"name=cache,size=512M,uuid=${uuid_gpt_cache};" \
+	"name=device,size=8M,uuid=${uuid_gpt_device};" \
+	"name=misc,size=4M,uuid=${uuid_gpt_misc};" \
+	"name=datafooter,size=2M,uuid=${uuid_gpt_datafooter};" \
+	"name=metadata,size=2M,uuid=${uuid_gpt_metadata};" \
+	"name=persistdata,size=2M,uuid=${uuid_gpt_persistdata};" \
+	"name=userdata,size=128M,uuid=${uuid_gpt_userdata};" \
+	"name=fbmisc,size=-,uuid=${uuid_gpt_fbmisc}\0"
+#endif /* PARTS_DEFAULT */
+
+#define EMMC_ANDROID_BOOTCMD \
+	"android_args=androidboot.storage_type=emmc\0" \
+	PARTS_DEFAULT \
+	"android_fdt_addr=0x83700000\0" \
+	"android_mmc_dev=0\0" \
+	"m4binary=rpmsg_imu_freertos.elf\0" \
+	"androidboot=ext4load mmc 0:a ${loadaddr} media/0/${m4binary}; "\
+		"bootaux ${loadaddr}; " \
+		"setenv loadaddr 0x88000000; " \
+		"setenv bootm_boot_mode sec;" \
+		"setenv bootargs androidboot.serialno=${serial#} " \
+			"$android_args; " \
+		"part start mmc ${android_mmc_dev} boot boot_start; " \
+		"part size mmc ${android_mmc_dev} boot boot_size; " \
+		"mmc read ${loadaddr} ${boot_start} ${boot_size}; " \
+		"part start mmc ${android_mmc_dev} environment env_start; " \
+		"part size mmc ${android_mmc_dev} environment env_size; " \
+		"mmc read ${android_fdt_addr} ${env_start} ${env_size}; " \
+		"bootm ${loadaddr} ${loadaddr} ${android_fdt_addr}\0 "
+
 #define EMMC_BOOTCMD \
 	"set_emmcargs=setenv emmcargs ip=off root=PARTUUID=${uuid} ro " \
 		"rootfstype=ext4 rootwait\0" \
@@ -63,7 +103,6 @@
 	"emmcfinduuid=part uuid mmc ${emmcdev}:${emmcrootpart} uuid\0" \
 	"emmcrootpart=2\0"
 
-
 #define MEM_LAYOUT_ENV_SETTINGS \
 	"bootm_size=0x10000000\0" \
 	"fdt_addr_r=0x82000000\0" \
@@ -125,7 +164,8 @@
 	"setenv fdtfile ${soc}-colibri-emmc-${fdt_board}.dtb && run distro_bootcmd;"
 #define MODULE_EXTRA_ENV_SETTINGS \
 	"variant=-emmc\0" \
-	EMMC_BOOTCMD
+	EMMC_BOOTCMD \
+	EMMC_ANDROID_BOOTCMD
 #endif
 
 #if defined(CONFIG_TARGET_COLIBRI_IMX7_NAND)
diff --git a/include/configs/dh_imx6.h b/include/configs/dh_imx6.h
index 3b1d0a9..7d2e573 100644
--- a/include/configs/dh_imx6.h
+++ b/include/configs/dh_imx6.h
@@ -48,14 +48,6 @@
 #define CONFIG_FEC_MXC_PHYADDR		0
 #define CONFIG_ARP_TIMEOUT		200UL
 
-/* I2C Configs */
-#define CONFIG_SYS_I2C
-#define CONFIG_SYS_I2C_MXC
-#define CONFIG_SYS_I2C_MXC_I2C1		/* enable I2C bus 1 */
-#define CONFIG_SYS_I2C_MXC_I2C2		/* enable I2C bus 2 */
-#define CONFIG_SYS_I2C_MXC_I2C3		/* enable I2C bus 3 */
-#define CONFIG_SYS_I2C_SPEED		100000
-
 /* MMC Configs */
 #define CONFIG_FSL_USDHC
 #define CONFIG_SYS_FSL_ESDHC_ADDR	0
diff --git a/include/configs/display5.h b/include/configs/display5.h
index 8829cba..1d3334f 100644
--- a/include/configs/display5.h
+++ b/include/configs/display5.h
@@ -55,11 +55,8 @@
 /* Size of malloc() pool */
 #define CONFIG_SYS_MALLOC_LEN		(16 * 1024 * 1024)
 
-/*#define CONFIG_MXC_UART*/
 #define CONFIG_MXC_UART_BASE		UART5_BASE
 
-/* SPI NOR Flash */
-
 /* I2C Configs */
 #define CONFIG_SYS_I2C
 #define CONFIG_SYS_I2C_MXC
@@ -358,8 +355,6 @@
 #define CONFIG_SYS_INIT_SP_ADDR \
 	(CONFIG_SYS_INIT_RAM_ADDR + CONFIG_SYS_INIT_SP_OFFSET)
 
-/* Commands */
-
 /* Watchdog */
 #define CONFIG_WATCHDOG_TIMEOUT_MSECS   15000
 
diff --git a/include/configs/ge_bx50v3.h b/include/configs/ge_bx50v3.h
index 0481ed0..31214a6 100644
--- a/include/configs/ge_bx50v3.h
+++ b/include/configs/ge_bx50v3.h
@@ -198,7 +198,6 @@
 #define CONFIG_IMX_VIDEO_SKIP
 #define CONFIG_CMD_BMP
 
-#define CONFIG_PWM_IMX
 #define CONFIG_IMX6_PWM_PER_CLK	66000000
 
 #define CONFIG_PCI
diff --git a/include/configs/m53menlo.h b/include/configs/m53menlo.h
index 7b68c1c..e98dbfb 100644
--- a/include/configs/m53menlo.h
+++ b/include/configs/m53menlo.h
@@ -242,4 +242,9 @@
 		"fi ; "							\
 		"fi\0"
 
+#if defined(CONFIG_SPL_BUILD)
+#undef CONFIG_WATCHDOG
+#define CONFIG_HW_WATCHDOG
+#endif
+
 #endif	/* __M53MENLO_CONFIG_H__ */
diff --git a/include/configs/mccmon6.h b/include/configs/mccmon6.h
index a1774c0..667dac7 100644
--- a/include/configs/mccmon6.h
+++ b/include/configs/mccmon6.h
@@ -65,13 +65,6 @@
 #define CONFIG_SYS_FLASH_BANKS_LIST	{ (CONFIG_SYS_FLASH_BASE) }
 #define CONFIG_SYS_FLASH_BANKS_SIZES	{ (32 * SZ_1M) }
 
-/* MTD support */
-
-/* USB Configs */
-#define CONFIG_USB_MAX_CONTROLLER_COUNT	2
-#define CONFIG_MXC_USB_PORTSC		(PORT_PTS_UTMI | PORT_PTS_PTW)
-#define CONFIG_MXC_USB_FLAGS		0
-
 /* Ethernet Configuration */
 #define CONFIG_FEC_MXC
 #define IMX_FEC_BASE			ENET_BASE_ADDR
@@ -85,6 +78,7 @@
 	"fdt_high=0xffffffff\0" \
 	"initrd_high=0xffffffff\0" \
 	"boot_os=yes\0" \
+	"disable_giga=yes\0" \
 	"download_kernel=" \
 		"tftpboot ${kernel_addr} ${kernel_file};" \
 		"tftpboot ${fdt_addr} ${fdtfile};\0" \
diff --git a/include/configs/mx53ppd.h b/include/configs/mx53ppd.h
index 2d6715c..d5b54df 100644
--- a/include/configs/mx53ppd.h
+++ b/include/configs/mx53ppd.h
@@ -211,7 +211,6 @@
 #define CONFIG_BCH
 
 /* Backlight Control */
-#define CONFIG_PWM_IMX
 #define CONFIG_IMX6_PWM_PER_CLK 66666000
 
 #endif				/* __CONFIG_H */
diff --git a/include/configs/vining_2000.h b/include/configs/vining_2000.h
index d4db9b4..33f06c0 100644
--- a/include/configs/vining_2000.h
+++ b/include/configs/vining_2000.h
@@ -83,7 +83,6 @@
 
 #define CONFIG_IMX_THERMAL
 
-#define CONFIG_PWM_IMX
 #define CONFIG_IMX6_PWM_PER_CLK 66000000
 
 #define CONFIG_ENV_OFFSET		(8 * SZ_64K)
diff --git a/include/configs/warp7.h b/include/configs/warp7.h
index 8ceaa0c..73541fe 100644
--- a/include/configs/warp7.h
+++ b/include/configs/warp7.h
@@ -27,10 +27,23 @@
 #define CONFIG_DFU_ENV_SETTINGS \
 	"dfu_alt_info=boot raw 0x2 0x1000 mmcpart 1\0" \
 
+/* When booting with FIT specify the node entry containing boot.scr */
+#if defined(CONFIG_FIT)
+#define BOOT_SCR_STRING "source ${bootscriptaddr}:${bootscr_fitimage_name}\0"
+#else
+#define BOOT_SCR_STRING "source ${bootscriptaddr}\0"
+#endif
+
+#ifndef CONFIG_OPTEE_LOAD_ADDR
+#define CONFIG_OPTEE_LOAD_ADDR 0
+#endif
+
 #define CONFIG_EXTRA_ENV_SETTINGS \
 	CONFIG_DFU_ENV_SETTINGS \
 	"script=boot.scr\0" \
+	"bootscr_fitimage_name=bootscr\0" \
 	"script_signed=boot.scr.imx-signed\0" \
+	"bootscriptaddr=0x83200000\0" \
 	"image=zImage\0" \
 	"console=ttymxc0\0" \
 	"ethact=usb_ether\0" \
@@ -38,6 +51,7 @@
 	"initrd_high=0xffffffff\0" \
 	"fdt_file=imx7s-warp.dtb\0" \
 	"fdt_addr=" __stringify(CONFIG_SYS_FDT_ADDR)"\0" \
+	"fdtovaddr=0x83100000\0" \
 	"optee_addr=" __stringify(CONFIG_OPTEE_LOAD_ADDR)"\0" \
 	"boot_fdt=try\0" \
 	"ip_dyn=yes\0" \
@@ -51,16 +65,16 @@
 	"warp7_auth_or_fail=hab_auth_img_or_fail ${hab_ivt_addr} ${filesize} 0;\0" \
 	"do_bootscript_hab=" \
 		"if test ${hab_enabled} -eq 1; then " \
-			"setexpr hab_ivt_addr ${loadaddr} - ${ivt_offset}; " \
+			"setexpr hab_ivt_addr ${bootscriptaddr} - ${ivt_offset}; " \
 			"setenv script ${script_signed}; " \
 			"load mmc ${mmcdev}:${mmcpart} ${hab_ivt_addr} ${script}; " \
 			"run warp7_auth_or_fail; " \
 			"run bootscript; "\
 		"fi;\0" \
 	"loadbootscript=" \
-		"load mmc ${mmcdev}:${mmcpart} ${loadaddr} ${script};\0" \
+		"load mmc ${mmcdev}:${mmcpart} ${bootscriptaddr} ${script};\0" \
 	"bootscript=echo Running bootscript from mmc ...; " \
-		"source\0" \
+		BOOT_SCR_STRING \
 	"loadimage=load mmc ${mmcdev}:${mmcpart} ${loadaddr} ${image}\0" \
 	"loadfdt=load mmc ${mmcdev}:${mmcpart} ${fdt_addr} ${fdt_file}\0" \
 	"mmcboot=echo Booting from mmc ...; " \
diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h
new file mode 100644
index 0000000..43a25e9
--- /dev/null
+++ b/include/linux/clk-provider.h
@@ -0,0 +1,132 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright (C) 2019 DENX Software Engineering
+ * Lukasz Majewski, DENX Software Engineering, lukma@denx.de
+ *
+ * Copyright (c) 2010-2011 Jeremy Kerr <jeremy.kerr@canonical.com>
+ * Copyright (C) 2011-2012 Linaro Ltd <mturquette@linaro.org>
+ */
+#ifndef __LINUX_CLK_PROVIDER_H
+#define __LINUX_CLK_PROVIDER_H
+
+static inline void clk_dm(ulong id, struct clk *clk)
+{
+	if (!IS_ERR(clk))
+		clk->id = id;
+}
+
+/*
+ * flags used across common struct clk.  these flags should only affect the
+ * top-level framework.  custom flags for dealing with hardware specifics
+ * belong in struct clk_foo
+ *
+ * Please update clk_flags[] in drivers/clk/clk.c when making changes here!
+ */
+#define CLK_SET_RATE_GATE	BIT(0) /* must be gated across rate change */
+#define CLK_SET_PARENT_GATE	BIT(1) /* must be gated across re-parent */
+#define CLK_SET_RATE_PARENT	BIT(2) /* propagate rate change up one level */
+#define CLK_IGNORE_UNUSED	BIT(3) /* do not gate even if unused */
+				/* unused */
+#define CLK_IS_BASIC		BIT(5) /* Basic clk, can't do a to_clk_foo() */
+#define CLK_GET_RATE_NOCACHE	BIT(6) /* do not use the cached clk rate */
+#define CLK_SET_RATE_NO_REPARENT BIT(7) /* don't re-parent on rate change */
+#define CLK_GET_ACCURACY_NOCACHE BIT(8) /* do not use the cached clk accuracy */
+#define CLK_RECALC_NEW_RATES	BIT(9) /* recalc rates after notifications */
+#define CLK_SET_RATE_UNGATE	BIT(10) /* clock needs to run to set rate */
+#define CLK_IS_CRITICAL		BIT(11) /* do not gate, ever */
+/* parents need enable during gate/ungate, set rate and re-parent */
+#define CLK_OPS_PARENT_ENABLE	BIT(12)
+/* duty cycle call may be forwarded to the parent clock */
+#define CLK_DUTY_CYCLE_PARENT	BIT(13)
+
+#define CLK_MUX_INDEX_ONE		BIT(0)
+#define CLK_MUX_INDEX_BIT		BIT(1)
+#define CLK_MUX_HIWORD_MASK		BIT(2)
+#define CLK_MUX_READ_ONLY		BIT(3) /* mux can't be changed */
+#define CLK_MUX_ROUND_CLOSEST		BIT(4)
+
+struct clk_mux {
+	struct clk	clk;
+	void __iomem	*reg;
+	u32		*table;
+	u32		mask;
+	u8		shift;
+	u8		flags;
+
+	/*
+	 * Fields from struct clk_init_data - this struct has been
+	 * omitted to avoid too deep level of CCF for bootloader
+	 */
+	const char	* const *parent_names;
+	u8		num_parents;
+#if CONFIG_IS_ENABLED(SANDBOX_CLK_CCF)
+	u32             io_mux_val;
+#endif
+
+};
+
+#define to_clk_mux(_clk) container_of(_clk, struct clk_mux, clk)
+
+struct clk_div_table {
+	unsigned int	val;
+	unsigned int	div;
+};
+
+struct clk_divider {
+	struct clk	clk;
+	void __iomem	*reg;
+	u8		shift;
+	u8		width;
+	u8		flags;
+	const struct clk_div_table	*table;
+#if CONFIG_IS_ENABLED(SANDBOX_CLK_CCF)
+	u32             io_divider_val;
+#endif
+};
+
+#define clk_div_mask(width)	((1 << (width)) - 1)
+#define to_clk_divider(_clk) container_of(_clk, struct clk_divider, clk)
+
+#define CLK_DIVIDER_ONE_BASED		BIT(0)
+#define CLK_DIVIDER_POWER_OF_TWO	BIT(1)
+#define CLK_DIVIDER_ALLOW_ZERO		BIT(2)
+#define CLK_DIVIDER_HIWORD_MASK		BIT(3)
+#define CLK_DIVIDER_ROUND_CLOSEST	BIT(4)
+#define CLK_DIVIDER_READ_ONLY		BIT(5)
+#define CLK_DIVIDER_MAX_AT_ZERO		BIT(6)
+
+struct clk_fixed_factor {
+	struct clk	clk;
+	unsigned int	mult;
+	unsigned int	div;
+};
+
+#define to_clk_fixed_factor(_clk) container_of(_clk, struct clk_fixed_factor,\
+					       clk)
+
+int clk_register(struct clk *clk, const char *drv_name, const char *name,
+		 const char *parent_name);
+
+struct clk *clk_register_fixed_factor(struct device *dev, const char *name,
+		const char *parent_name, unsigned long flags,
+		unsigned int mult, unsigned int div);
+
+struct clk *clk_register_divider(struct device *dev, const char *name,
+		const char *parent_name, unsigned long flags,
+		void __iomem *reg, u8 shift, u8 width,
+		u8 clk_divider_flags);
+
+struct clk *clk_register_mux(struct device *dev, const char *name,
+		const char * const *parent_names, u8 num_parents,
+		unsigned long flags,
+		void __iomem *reg, u8 shift, u8 width,
+		u8 clk_mux_flags);
+
+const char *clk_hw_get_name(const struct clk *hw);
+ulong clk_generic_get_rate(struct clk *clk);
+
+static inline struct clk *dev_get_clk_ptr(struct udevice *dev)
+{
+	return (struct clk *)dev_get_uclass_priv(dev);
+}
+#endif /* __LINUX_CLK_PROVIDER_H */
diff --git a/drivers/mtd/nand/raw/mxs_nand.h b/include/mxs_nand.h
similarity index 100%
rename from drivers/mtd/nand/raw/mxs_nand.h
rename to include/mxs_nand.h
diff --git a/include/power/bd71837.h b/include/power/bd71837.h
index 38c69b2..75e07e1 100644
--- a/include/power/bd71837.h
+++ b/include/power/bd71837.h
@@ -1,62 +1,103 @@
 /* SPDX-License-Identifier: GPL-2.0-or-later */
 /* Copyright (C) 2018 ROHM Semiconductors */
 
-#ifndef BD71837_H_
-#define BD71837_H_
+#ifndef BD718XX_H_
+#define BD718XX_H_
 
-#define BD71837_REGULATOR_DRIVER "bd71837_regulator"
+#define BD718XX_REGULATOR_DRIVER "bd718x7_regulator"
 
 enum {
-	BD71837_REV		= 0x00,
-	BD71837_SWRESET		= 0x01,
-	BD71837_I2C_DEV		= 0x02,
-	BD71837_PWRCTRL0	= 0x03,
-	BD71837_PWRCTRL1	= 0x04,
-	BD71837_BUCK1_CTRL	= 0x05,
-	BD71837_BUCK2_CTRL	= 0x06,
-	BD71837_BUCK3_CTRL	= 0x07,
-	BD71837_BUCK4_CTRL	= 0x08,
-	BD71837_BUCK5_CTRL	= 0x09,
-	BD71837_BUCK6_CTRL	= 0x0a,
-	BD71837_BUCK7_CTRL	= 0x0b,
-	BD71837_BUCK8_CTRL	= 0x0c,
-	BD71837_BUCK1_VOLT_RUN	= 0x0d,
-	BD71837_BUCK1_VOLT_IDLE	= 0x0e,
-	BD71837_BUCK1_VOLT_SUSP	= 0x0f,
-	BD71837_BUCK2_VOLT_RUN	= 0x10,
-	BD71837_BUCK2_VOLT_IDLE	= 0x11,
-	BD71837_BUCK3_VOLT_RUN	= 0x12,
-	BD71837_BUCK4_VOLT_RUN	= 0x13,
-	BD71837_BUCK5_VOLT	= 0x14,
-	BD71837_BUCK6_VOLT	= 0x15,
-	BD71837_BUCK7_VOLT	= 0x16,
-	BD71837_BUCK8_VOLT	= 0x17,
-	BD71837_LDO1_VOLT	= 0x18,
-	BD71837_LDO2_VOLT	= 0x19,
-	BD71837_LDO3_VOLT	= 0x1a,
-	BD71837_LDO4_VOLT	= 0x1b,
-	BD71837_LDO5_VOLT	= 0x1c,
-	BD71837_LDO6_VOLT	= 0x1d,
-	BD71837_LDO7_VOLT	= 0x1e,
-	BD71837_TRANS_COND0	= 0x1f,
-	BD71837_TRANS_COND1	= 0x20,
-	BD71837_VRFAULTEN	= 0x21,
-	BD71837_MVRFLTMASK0	= 0x22,
-	BD71837_MVRFLTMASK1	= 0x23,
-	BD71837_MVRFLTMASK2	= 0x24,
-	BD71837_RCVCFG		= 0x25,
-	BD71837_RCVNUM		= 0x26,
-	BD71837_PWRONCONFIG0	= 0x27,
-	BD71837_PWRONCONFIG1	= 0x28,
-	BD71837_RESETSRC	= 0x29,
-	BD71837_MIRQ		= 0x2a,
-	BD71837_IRQ		= 0x2b,
-	BD71837_IN_MON		= 0x2c,
-	BD71837_POW_STATE	= 0x2d,
-	BD71837_OUT32K		= 0x2e,
-	BD71837_REGLOCK		= 0x2f,
-	BD71837_MUXSW_EN	= 0x30,
-	BD71837_REG_NUM,
+	ROHM_CHIP_TYPE_BD71837 = 0,
+	ROHM_CHIP_TYPE_BD71847,
+	ROHM_CHIP_TYPE_BD70528,
+	ROHM_CHIP_TYPE_AMOUNT
 };
 
+enum {
+	BD718XX_REV			= 0x00,
+	BD718XX_SWRESET			= 0x01,
+	BD718XX_I2C_DEV			= 0x02,
+	BD718XX_PWRCTRL0		= 0x03,
+	BD718XX_PWRCTRL1		= 0x04,
+	BD718XX_BUCK1_CTRL		= 0x05,
+	BD718XX_BUCK2_CTRL		= 0x06,
+	BD71837_BUCK3_CTRL		= 0x07,
+	BD71837_BUCK4_CTRL		= 0x08,
+	BD718XX_1ST_NODVS_BUCK_CTRL	= 0x09,
+	BD718XX_2ND_NODVS_BUCK_CTRL	= 0x0a,
+	BD718XX_3RD_NODVS_BUCK_CTRL	= 0x0b,
+	BD718XX_4TH_NODVS_BUCK_CTRL	= 0x0c,
+	BD718XX_BUCK1_VOLT_RUN		= 0x0d,
+	BD718XX_BUCK1_VOLT_IDLE		= 0x0e,
+	BD718XX_BUCK1_VOLT_SUSP		= 0x0f,
+	BD718XX_BUCK2_VOLT_RUN		= 0x10,
+	BD718XX_BUCK2_VOLT_IDLE		= 0x11,
+	BD71837_BUCK3_VOLT_RUN		= 0x12,
+	BD71837_BUCK4_VOLT_RUN		= 0x13,
+	BD718XX_1ST_NODVS_BUCK_VOLT	= 0x14,
+	BD718XX_2ND_NODVS_BUCK_VOLT	= 0x15,
+	BD718XX_3RD_NODVS_BUCK_VOLT	= 0x16,
+	BD718XX_4TH_NODVS_BUCK_VOLT	= 0x17,
+	BD718XX_LDO1_VOLT		= 0x18,
+	BD718XX_LDO2_VOLT		= 0x19,
+	BD718XX_LDO3_VOLT		= 0x1a,
+	BD718XX_LDO4_VOLT		= 0x1b,
+	BD718XX_LDO5_VOLT		= 0x1c,
+	BD718XX_LDO6_VOLT		= 0x1d,
+	BD71837_LDO7_VOLT		= 0x1e,
+	BD718XX_TRANS_COND0		= 0x1f,
+	BD718XX_TRANS_COND1		= 0x20,
+	BD718XX_VRFAULTEN		= 0x21,
+	BD718XX_MVRFLTMASK0		= 0x22,
+	BD718XX_MVRFLTMASK1		= 0x23,
+	BD718XX_MVRFLTMASK2		= 0x24,
+	BD718XX_RCVCFG			= 0x25,
+	BD718XX_RCVNUM			= 0x26,
+	BD718XX_PWRONCONFIG0		= 0x27,
+	BD718XX_PWRONCONFIG1		= 0x28,
+	BD718XX_RESETSRC		= 0x29,
+	BD718XX_MIRQ			= 0x2a,
+	BD718XX_IRQ			= 0x2b,
+	BD718XX_IN_MON			= 0x2c,
+	BD718XX_POW_STATE		= 0x2d,
+	BD718XX_OUT32K			= 0x2e,
+	BD718XX_REGLOCK			= 0x2f,
+	BD718XX_MUXSW_EN		= 0x30,
+	BD718XX_REG_OTPVER		= 0xff,
+	BD718XX_MAX_REGISTER		= 0x100,
+};
+
+#define BD718XX_REGLOCK_PWRSEQ		0x1
+#define BD718XX_REGLOCK_VREG		0x10
+
+#define BD718XX_BUCK_EN			0x01
+#define BD718XX_LDO_EN			0x40
+#define BD718XX_BUCK_SEL		0x02
+#define BD718XX_LDO_SEL			0x80
+
+#define DVS_BUCK_RUN_MASK		0x3f
+#define BD718XX_1ST_NODVS_BUCK_MASK	0x07
+#define BD718XX_3RD_NODVS_BUCK_MASK	0x07
+#define BD718XX_4TH_NODVS_BUCK_MASK	0x3f
+
+#define BD71847_BUCK3_MASK		0x07
+#define BD71847_BUCK3_RANGE_MASK	0xc0
+#define BD71847_BUCK4_MASK		0x03
+#define BD71847_BUCK4_RANGE_MASK	0x40
+
+#define BD71837_BUCK5_RANGE_MASK	0x80
+#define BD71837_BUCK6_MASK		0x03
+
+#define BD718XX_LDO1_MASK		0x03
+#define BD718XX_LDO1_RANGE_MASK		0x20
+#define BD718XX_LDO2_MASK		0x20
+#define BD718XX_LDO3_MASK		0x0f
+#define BD718XX_LDO4_MASK		0x0f
+#define BD718XX_LDO6_MASK		0x0f
+
+#define BD71837_LDO5_MASK		0x0f
+#define BD71847_LDO5_MASK		0x0f
+#define BD71847_LDO5_RANGE_MASK		0x20
+#define BD71837_LDO7_MASK		0x0f
+
 #endif
diff --git a/include/sandbox-clk.h b/include/sandbox-clk.h
new file mode 100644
index 0000000..37c9838
--- /dev/null
+++ b/include/sandbox-clk.h
@@ -0,0 +1,76 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright (C) 2019
+ * Lukasz Majewski, DENX Software Engineering, lukma@denx.de
+ */
+
+#ifndef __SANDBOX_CLK_H__
+#define __SANDBOX_CLK_H__
+
+#include <linux/clk-provider.h>
+
+enum {
+	SANDBOX_CLK_PLL2 = 1,
+	SANDBOX_CLK_PLL3,
+	SANDBOX_CLK_PLL3_60M,
+	SANDBOX_CLK_PLL3_80M,
+	SANDBOX_CLK_ECSPI_ROOT,
+	SANDBOX_CLK_ECSPI0,
+	SANDBOX_CLK_ECSPI1,
+	SANDBOX_CLK_USDHC1_SEL,
+	SANDBOX_CLK_USDHC2_SEL,
+};
+
+enum sandbox_pllv3_type {
+	SANDBOX_PLLV3_GENERIC,
+	SANDBOX_PLLV3_USB,
+};
+
+struct clk *sandbox_clk_pllv3(enum sandbox_pllv3_type type, const char *name,
+			      const char *parent_name, void __iomem *base,
+			      u32 div_mask);
+
+static inline struct clk *sandbox_clk_fixed_factor(const char *name,
+						   const char *parent,
+						   unsigned int mult,
+						   unsigned int div)
+{
+	return clk_register_fixed_factor(NULL, name, parent,
+			CLK_SET_RATE_PARENT, mult, div);
+}
+
+static inline struct clk *sandbox_clk_divider(const char *name,
+					      const char *parent,
+					      void __iomem *reg, u8 shift,
+					      u8 width)
+{
+	return clk_register_divider(NULL, name, parent, CLK_SET_RATE_PARENT,
+			reg, shift, width, 0);
+}
+
+struct clk *sandbox_clk_register_gate2(struct device *dev, const char *name,
+				       const char *parent_name,
+				       unsigned long flags,
+				       void __iomem *reg, u8 bit_idx,
+				       u8 cgr_val, u8 clk_gate_flags);
+
+static inline struct clk *sandbox_clk_gate2(const char *name,
+					    const char *parent,
+					    void __iomem *reg, u8 shift)
+{
+	return sandbox_clk_register_gate2(NULL, name, parent,
+					  CLK_SET_RATE_PARENT, reg, shift,
+					  0x3, 0);
+}
+
+static inline struct clk *sandbox_clk_mux(const char *name, void __iomem *reg,
+					  u8 shift, u8 width,
+					  const char * const *parents,
+					  int num_parents)
+{
+	return clk_register_mux(NULL, name, parents, num_parents,
+				CLK_SET_RATE_NO_REPARENT, reg, shift,
+				width, 0);
+}
+
+#endif /* __SANDBOX_CLK_H__ */
diff --git a/include/wdt.h b/include/wdt.h
index aa77d3e..5bcff24 100644
--- a/include/wdt.h
+++ b/include/wdt.h
@@ -106,7 +106,7 @@
 	int (*expire_now)(struct udevice *dev, ulong flags);
 };
 
-#if defined(CONFIG_WDT)
+#if CONFIG_IS_ENABLED(WDT)
 #ifndef CONFIG_WATCHDOG_TIMEOUT_MSECS
 #define CONFIG_WATCHDOG_TIMEOUT_MSECS	(60 * 1000)
 #endif
diff --git a/lib/optee/Kconfig b/lib/optee/Kconfig
index 3773d89..c398f9b 100644
--- a/lib/optee/Kconfig
+++ b/lib/optee/Kconfig
@@ -17,6 +17,7 @@
 config OPTEE_TZDRAM_SIZE
 	hex "Amount of Trust-Zone RAM for the OPTEE image"
 	default 0x0000000
+	depends on OPTEE
 	help
 	  The size of pre-allocated Trust Zone DRAM to allocate for the OPTEE
 	  runtime.
@@ -24,6 +25,7 @@
 config OPTEE_TZDRAM_BASE
 	hex "Base address of Trust-Zone RAM for the OPTEE image"
 	default 0x00000000
+	depends on OPTEE
 	help
 	  The base address of pre-allocated Trust Zone DRAM for
 	  the OPTEE runtime.
diff --git a/scripts/config_whitelist.txt b/scripts/config_whitelist.txt
index e616f72..495988c 100644
--- a/scripts/config_whitelist.txt
+++ b/scripts/config_whitelist.txt
@@ -1459,7 +1459,6 @@
 CONFIG_PRPMC_PCI_ALIAS
 CONFIG_PSRAM_SCFG
 CONFIG_PWM
-CONFIG_PWM_IMX
 CONFIG_PXA_LCD
 CONFIG_PXA_MMC_GENERIC
 CONFIG_PXA_PWR_I2C
diff --git a/test/dm/Makefile b/test/dm/Makefile
index 7b4dd6e..55a7940 100644
--- a/test/dm/Makefile
+++ b/test/dm/Makefile
@@ -17,7 +17,7 @@
 obj-$(CONFIG_BLK) += blk.o
 obj-$(CONFIG_BOARD) += board.o
 obj-$(CONFIG_DM_BOOTCOUNT) += bootcount.o
-obj-$(CONFIG_CLK) += clk.o
+obj-$(CONFIG_CLK) += clk.o clk_ccf.o
 obj-$(CONFIG_DM_ETH) += eth.o
 obj-$(CONFIG_FIRMWARE) += firmware.o
 obj-$(CONFIG_DM_GPIO) += gpio.o
diff --git a/test/dm/clk_ccf.c b/test/dm/clk_ccf.c
new file mode 100644
index 0000000..8d39759
--- /dev/null
+++ b/test/dm/clk_ccf.c
@@ -0,0 +1,62 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2019
+ * Lukasz Majewski, DENX Software Engineering, lukma@denx.de
+ */
+
+#include <common.h>
+#include <clk.h>
+#include <dm.h>
+#include <asm/clk.h>
+#include <dm/test.h>
+#include <dm/uclass.h>
+#include <linux/err.h>
+#include <test/ut.h>
+#include <sandbox-clk.h>
+
+/* Tests for Common Clock Framework driver */
+static int dm_test_clk_ccf(struct unit_test_state *uts)
+{
+	struct clk *clk, *pclk;
+	struct udevice *dev;
+	long long rate;
+	int ret;
+
+	/* Get the device using the clk device */
+	ut_assertok(uclass_get_device_by_name(UCLASS_CLK, "clk-ccf", &dev));
+
+	/* Test for clk_get_by_id() */
+	ret = clk_get_by_id(SANDBOX_CLK_ECSPI_ROOT, &clk);
+	ut_assertok(ret);
+	ut_asserteq_str("ecspi_root", clk->dev->name);
+
+	/* Test for clk_get_parent_rate() */
+	ret = clk_get_by_id(SANDBOX_CLK_ECSPI1, &clk);
+	ut_assertok(ret);
+	ut_asserteq_str("ecspi1", clk->dev->name);
+
+	rate = clk_get_parent_rate(clk);
+	ut_asserteq(rate, 20000000);
+
+	/* Test the mux of CCF */
+	ret = clk_get_by_id(SANDBOX_CLK_USDHC1_SEL, &clk);
+	ut_assertok(ret);
+	ut_asserteq_str("usdhc1_sel", clk->dev->name);
+
+	rate = clk_get_parent_rate(clk);
+	ut_asserteq(rate, 60000000);
+
+	ret = clk_get_by_id(SANDBOX_CLK_USDHC2_SEL, &clk);
+	ut_assertok(ret);
+	ut_asserteq_str("usdhc2_sel", clk->dev->name);
+
+	rate = clk_get_parent_rate(clk);
+	ut_asserteq(rate, 80000000);
+
+	pclk = clk_get_parent(clk);
+	ut_asserteq_str("pll3_80m", pclk->dev->name);
+
+	return 1;
+}
+
+DM_TEST(dm_test_clk_ccf, DM_TESTF_SCAN_FDT);