diff --git a/arch/arm/Makefile b/arch/arm/Makefile
index 28b523b37c..c68e598a67 100644
--- a/arch/arm/Makefile
+++ b/arch/arm/Makefile
@@ -107,11 +107,11 @@ libs-y += arch/arm/cpu/
 libs-y += arch/arm/lib/
 
 ifeq ($(CONFIG_SPL_BUILD),y)
-ifneq (,$(CONFIG_MX23)$(CONFIG_MX28)$(CONFIG_MX35)$(filter $(SOC), mx25 mx5 mx6 mx7 mx35 imx8m imx8 imxrt))
+ifneq (,$(CONFIG_MX23)$(CONFIG_MX28)$(CONFIG_MX35)$(filter $(SOC), mx25 mx5 mx6 mx7 mx35 imx8m imx8 imx8ulp imxrt))
 libs-y += arch/arm/mach-imx/
 endif
 else
-ifneq (,$(filter $(SOC), mx25 mx27 mx5 mx6 mx7 mx7ulp mx31 mx35 mxs imx8m imx8 imxrt vf610))
+ifneq (,$(filter $(SOC), mx25 mx27 mx5 mx6 mx7 mx7ulp mx31 mx35 mxs imx8m imx8 imx8ulp imxrt vf610))
 libs-y += arch/arm/mach-imx/
 endif
 endif
diff --git a/arch/arm/include/asm/arch-imx8ulp/clock.h b/arch/arm/include/asm/arch-imx8ulp/clock.h
new file mode 100644
index 0000000000..e145c33f01
--- /dev/null
+++ b/arch/arm/include/asm/arch-imx8ulp/clock.h
@@ -0,0 +1,34 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright 2020 NXP
+ */
+
+#ifndef _ASM_ARCH_IMX8ULP_CLOCK_H
+#define _ASM_ARCH_IMX8ULP_CLOCK_H
+
+/* Mainly for compatible to imx common code. */
+enum mxc_clock {
+	MXC_ARM_CLK = 0,
+	MXC_AHB_CLK,
+	MXC_IPG_CLK,
+	MXC_UART_CLK,
+	MXC_CSPI_CLK,
+	MXC_AXI_CLK,
+	MXC_DDR_CLK,
+	MXC_ESDHC_CLK,
+	MXC_ESDHC2_CLK,
+	MXC_I2C_CLK,
+};
+
+u32 mxc_get_clock(enum mxc_clock clk);
+u32 get_lpuart_clk(void);
+#ifdef CONFIG_SYS_I2C_IMX_LPI2C
+int enable_i2c_clk(unsigned char enable, unsigned int i2c_num);
+u32 imx_get_i2cclk(unsigned int i2c_num);
+#endif
+#ifdef CONFIG_MXC_OCOTP
+void enable_ocotp_clk(unsigned char enable);
+#endif
+void init_clk_usdhc(u32 index);
+void clock_init(void);
+#endif
diff --git a/arch/arm/include/asm/arch-imx8ulp/ddr.h b/arch/arm/include/asm/arch-imx8ulp/ddr.h
new file mode 100644
index 0000000000..4544431b05
--- /dev/null
+++ b/arch/arm/include/asm/arch-imx8ulp/ddr.h
@@ -0,0 +1,38 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright 2020 NXP
+ */
+
+#ifndef __ASM_ARCH_IMX8ULP_DDR_H
+#define __ASM_ARCH_IMX8ULP_DDR_H
+
+#include <asm/io.h>
+#include <asm/types.h>
+
+struct dram_cfg_param {
+	unsigned int reg;
+	unsigned int val;
+};
+
+struct dram_timing_info2 {
+	/* ddr controller config */
+	struct dram_cfg_param *ctl_cfg;
+	unsigned int ctl_cfg_num;
+	/* pi config */
+	struct dram_cfg_param *pi_cfg;
+	unsigned int pi_cfg_num;
+	/* phy freq1 config */
+	struct dram_cfg_param *phy_f1_cfg;
+	unsigned int phy_f1_cfg_num;
+	/* phy freq2 config */
+	struct dram_cfg_param *phy_f2_cfg;
+	unsigned int phy_f2_cfg_num;
+	/* initialized drate table */
+	unsigned int fsp_table[3];
+};
+
+extern struct dram_timing_info2 dram_timing;
+
+int ddr_init(struct dram_timing_info2 *dram_timing);
+
+#endif
diff --git a/arch/arm/include/asm/arch-imx8ulp/gpio.h b/arch/arm/include/asm/arch-imx8ulp/gpio.h
new file mode 100644
index 0000000000..b7563bb401
--- /dev/null
+++ b/arch/arm/include/asm/arch-imx8ulp/gpio.h
@@ -0,0 +1,20 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright 2020 NXP
+ */
+
+#ifndef __ASM_ARCH_IMX8ULP_GPIO_H
+#define __ASM_ARCH_IMX8ULP_GPIO_H
+
+struct gpio_regs {
+	u32 gpio_pdor;
+	u32 gpio_psor;
+	u32 gpio_pcor;
+	u32 gpio_ptor;
+	u32 gpio_pdir;
+	u32 gpio_pddr;
+	u32 gpio_pidr;
+	u8 gpio_pxdr[32];
+};
+
+#endif
diff --git a/arch/arm/include/asm/arch-imx8ulp/imx-regs.h b/arch/arm/include/asm/arch-imx8ulp/imx-regs.h
new file mode 100644
index 0000000000..52831d7262
--- /dev/null
+++ b/arch/arm/include/asm/arch-imx8ulp/imx-regs.h
@@ -0,0 +1,131 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright 2020 NXP
+ */
+
+#ifndef _IMX8ULP_REGS_H_
+#define _IMX8ULP_REGS_H_
+#define ARCH_MXC
+
+#include <linux/sizes.h>
+
+#define PBRIDGE0_BASE		0x28000000
+
+#define CMC0_RBASE		0x28025000
+
+#define CMC1_BASE_ADDR		0x29240000
+
+#define SIM1_BASE_ADDR		0x29290000
+
+#define WDG3_RBASE		0x292a0000UL
+
+#define CGC1_SOSCDIV_ADDR	0x292C0108
+#define CGC1_FRODIV_ADDR	0x292C0208
+
+#define CFG1_PLL2CSR_ADDR	0x292C0500
+#define CFG1_PLL2CFG_ADDR	0x292C0510
+
+#define PCC_XRDC_MGR_ADDR	0x292d00bc
+
+#define PCC3_RBASE		0x292d0000
+#define PCC4_RBASE		0x29800000
+#define PCC5_RBASE		0x2da70000
+
+#define IOMUXC_BASE_ADDR	0x298c0000
+
+#define LPUART4_RBASE		0x29390000
+#define LPUART5_RBASE		0x293a0000
+#define LPUART6_RBASE		0x29860000
+#define LPUART7_RBASE		0x29870000
+
+#define LPUART_BASE		LPUART5_RBASE
+
+#define FSB_BASE_ADDR		0x27010000
+
+#define USBOTG0_RBASE		0x29900000
+#define USB_PHY0_BASE_ADDR	0x29910000
+#define USBOTG1_RBASE		0x29920000
+#define USB_PHY1_BASE_ADDR	0x29930000
+#define USB_BASE_ADDR		USBOTG0_RBASE
+
+#define DDR_CTL_BASE_ADDR	0x2E060000
+#define DDR_PI_BASE_ADDR	0x2E062000
+#define DDR_PHY_BASE_ADDR	0x2E064000
+#define AVD_SIM_LPDDR_CTRL	0x2DA50014
+#define AVD_SIM_LPDDR_CTRL2	0x2DA50018
+
+#if !(defined(__KERNEL_STRICT_NAMES) || defined(__ASSEMBLY__))
+#include <asm/types.h>
+
+struct usbphy_regs {
+	u32	usbphy_pwd;			/* 0x000 */
+	u32	usbphy_pwd_set;			/* 0x004 */
+	u32	usbphy_pwd_clr;			/* 0x008 */
+	u32	usbphy_pwd_tog;			/* 0x00c */
+	u32	usbphy_tx;			/* 0x010 */
+	u32	usbphy_tx_set;			/* 0x014 */
+	u32	usbphy_tx_clr;			/* 0x018 */
+	u32	usbphy_tx_tog;			/* 0x01c */
+	u32	usbphy_rx;			/* 0x020 */
+	u32	usbphy_rx_set;			/* 0x024 */
+	u32	usbphy_rx_clr;			/* 0x028 */
+	u32	usbphy_rx_tog;			/* 0x02c */
+	u32	usbphy_ctrl;			/* 0x030 */
+	u32	usbphy_ctrl_set;		/* 0x034 */
+	u32	usbphy_ctrl_clr;		/* 0x038 */
+	u32	usbphy_ctrl_tog;		/* 0x03c */
+	u32	usbphy_status;			/* 0x040 */
+	u32	reserved0[3];
+	u32	usbphy_debug;			/* 0x050 */
+	u32	usbphy_debug_set;		/* 0x054 */
+	u32	usbphy_debug_clr;		/* 0x058 */
+	u32	usbphy_debug_tog;		/* 0x05c */
+	u32	usbphy_debug0_status;	/* 0x060 */
+	u32	reserved1[3];
+	u32	usbphy_debug1;			/* 0x070 */
+	u32	usbphy_debug1_set;		/* 0x074 */
+	u32	usbphy_debug1_clr;		/* 0x078 */
+	u32	usbphy_debug1_tog;		/* 0x07c */
+	u32	usbphy_version;			/* 0x080 */
+	u32	reserved2[7];
+	u32	usb1_pll_480_ctrl;		/* 0x0a0 */
+	u32	usb1_pll_480_ctrl_set;		/* 0x0a4 */
+	u32	usb1_pll_480_ctrl_clr;		/* 0x0a8 */
+	u32	usb1_pll_480_ctrl_tog;		/* 0x0ac */
+	u32	reserved3[4];
+	u32	usb1_vbus_detect;		/* 0xc0 */
+	u32	usb1_vbus_detect_set;		/* 0xc4 */
+	u32	usb1_vbus_detect_clr;		/* 0xc8 */
+	u32	usb1_vbus_detect_tog;		/* 0xcc */
+	u32	usb1_vbus_det_stat;		/* 0xd0 */
+	u32	reserved4[3];
+	u32	usb1_chrg_detect;		/* 0xe0 */
+	u32	usb1_chrg_detect_set;		/* 0xe4 */
+	u32	usb1_chrg_detect_clr;		/* 0xe8 */
+	u32	usb1_chrg_detect_tog;		/* 0xec */
+	u32	usb1_chrg_det_stat;		/* 0xf0 */
+	u32	reserved5[3];
+	u32	usbphy_anactrl;			/* 0x100 */
+	u32	usbphy_anactrl_set;		/* 0x104 */
+	u32	usbphy_anactrl_clr;		/* 0x108 */
+	u32	usbphy_anactrl_tog;		/* 0x10c */
+	u32	usb1_loopback;			/* 0x110 */
+	u32	usb1_loopback_set;		/* 0x114 */
+	u32	usb1_loopback_clr;		/* 0x118 */
+	u32	usb1_loopback_tog;		/* 0x11c */
+	u32	usb1_loopback_hsfscnt;		/* 0x120 */
+	u32	usb1_loopback_hsfscnt_set;	/* 0x124 */
+	u32	usb1_loopback_hsfscnt_clr;	/* 0x128 */
+	u32	usb1_loopback_hsfscnt_tog;	/* 0x12c */
+	u32	usphy_trim_override_en;		/* 0x130 */
+	u32	usphy_trim_override_en_set;	/* 0x134 */
+	u32	usphy_trim_override_en_clr;	/* 0x138 */
+	u32	usphy_trim_override_en_tog;	/* 0x13c */
+	u32	usb1_pfda_ctrl1;		/* 0x140 */
+	u32	usb1_pfda_ctrl1_set;		/* 0x144 */
+	u32	usb1_pfda_ctrl1_clr;		/* 0x148 */
+	u32	usb1_pfda_ctrl1_tog;		/* 0x14c */
+};
+#endif
+
+#endif
diff --git a/arch/arm/include/asm/arch-imx8ulp/imx8ulp-pins.h b/arch/arm/include/asm/arch-imx8ulp/imx8ulp-pins.h
new file mode 100644
index 0000000000..d7c07f41b3
--- /dev/null
+++ b/arch/arm/include/asm/arch-imx8ulp/imx8ulp-pins.h
@@ -0,0 +1,60 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright 2021 NXP
+ */
+
+#ifndef __ASM_ARCH_IMX8ULP_PINS_H__
+#define __ASM_ARCH_IMX8ULP_PINS_H__
+
+#include <asm/arch/iomux.h>
+
+enum {
+	IMX8ULP_PAD_PTB7__PMIC0_MODE2                       = IOMUX_PAD(0x009C, 0x009C, IOMUX_CONFIG_MPORTS | 0xA, 0x0000, 0x0, 0),
+	IMX8ULP_PAD_PTB8__PMIC0_MODE1                       = IOMUX_PAD(0x00A0, 0x00A0, IOMUX_CONFIG_MPORTS | 0xA, 0x0000, 0x0, 0),
+	IMX8ULP_PAD_PTB9__PMIC0_MODE0                       = IOMUX_PAD(0x00A4, 0x00A4, IOMUX_CONFIG_MPORTS | 0xA, 0x0000, 0x0, 0),
+	IMX8ULP_PAD_PTB10__PMIC0_SDA                        = IOMUX_PAD(0x00A8, 0x00A8, IOMUX_CONFIG_MPORTS | 0xA, 0x0804, 0x2, 0),
+	IMX8ULP_PAD_PTB11__PMIC0_SCL                        = IOMUX_PAD(0x00AC, 0x00AC, IOMUX_CONFIG_MPORTS | 0xA, 0x0800, 0x2, 0),
+
+	IMX8ULP_PAD_PTD0__SDHC0_RESET_b                     = IOMUX_PAD(0x0000, 0x0000, 0x8, 0x0000, 0x0, 0),
+	IMX8ULP_PAD_PTD1__SDHC0_CMD                         = IOMUX_PAD(0x0004, 0x0004, 0x8, 0x0000, 0x0, 0),
+	IMX8ULP_PAD_PTD2__SDHC0_CLK                         = IOMUX_PAD(0x0008, 0x0008, 0x8, 0x0000, 0x0, 0),
+	IMX8ULP_PAD_PTD3__SDHC0_D7                          = IOMUX_PAD(0x000C, 0x000C, 0x8, 0x0000, 0x0, 0),
+	IMX8ULP_PAD_PTD4__SDHC0_D6                          = IOMUX_PAD(0x0010, 0x0010, 0x8, 0x0000, 0x0, 0),
+	IMX8ULP_PAD_PTD5__SDHC0_D5                          = IOMUX_PAD(0x0014, 0x0014, 0x8, 0x0000, 0x0, 0),
+	IMX8ULP_PAD_PTD6__SDHC0_D4                          = IOMUX_PAD(0x0018, 0x0018, 0x8, 0x0000, 0x0, 0),
+	IMX8ULP_PAD_PTD7__SDHC0_D3                          = IOMUX_PAD(0x001C, 0x001C, 0x8, 0x0000, 0x0, 0),
+	IMX8ULP_PAD_PTD8__SDHC0_D2                          = IOMUX_PAD(0x0020, 0x0020, 0x8, 0x0000, 0x0, 0),
+	IMX8ULP_PAD_PTD9__SDHC0_D1                          = IOMUX_PAD(0x0024, 0x0024, 0x8, 0x0000, 0x0, 0),
+	IMX8ULP_PAD_PTD10__SDHC0_D0                         = IOMUX_PAD(0x0028, 0x0028, 0x8, 0x0000, 0x0, 0),
+	IMX8ULP_PAD_PTD11__SDHC0_DQS                        = IOMUX_PAD(0x002C, 0x002C, 0x8, 0x0000, 0x0, 0),
+
+	IMX8ULP_PAD_PTD11__FLEXSPI2_B_SS0_B                 = IOMUX_PAD(0x002C, 0x002C, 0x9, 0x0000, 0x0, 0),
+	IMX8ULP_PAD_PTD11__FLEXSPI2_A_SS1_B                 = IOMUX_PAD(0x002C, 0x002C, 0xa, 0x0000, 0x0, 0),
+	IMX8ULP_PAD_PTD12__FLEXSPI2_A_SS0_B                 = IOMUX_PAD(0x0030, 0x0030, 0x9, 0x0000, 0x0, 0),
+	IMX8ULP_PAD_PTD12__FLEXSPI2_B_SS1_B                 = IOMUX_PAD(0x0030, 0x0030, 0xa, 0x0000, 0x0, 0),
+	IMX8ULP_PAD_PTD13__FLEXSPI2_A_SCLK                  = IOMUX_PAD(0x0034, 0x0034, 0x9, 0x0000, 0x0, 0),
+	IMX8ULP_PAD_PTD14__FLEXSPI2_A_DATA3                 = IOMUX_PAD(0x0038, 0x0038, 0x9, 0x0000, 0x0, 0),
+	IMX8ULP_PAD_PTD15__FLEXSPI2_A_DATA2                 = IOMUX_PAD(0x003c, 0x003c, 0x9, 0x0000, 0x0, 0),
+	IMX8ULP_PAD_PTD16__FLEXSPI2_A_DATA1                 = IOMUX_PAD(0x0040, 0x0040, 0x9, 0x0000, 0x0, 0),
+	IMX8ULP_PAD_PTD17__FLEXSPI2_A_DATA0                 = IOMUX_PAD(0x0044, 0x0044, 0x9, 0x0000, 0x0, 0),
+	IMX8ULP_PAD_PTD18__FLEXSPI2_A_DQS                   = IOMUX_PAD(0x0048, 0x0048, 0x9, 0x0000, 0x0, 0),
+	IMX8ULP_PAD_PTD19__FLEXSPI2_A_DATA7                 = IOMUX_PAD(0x004c, 0x004c, 0x9, 0x0000, 0x0, 0),
+	IMX8ULP_PAD_PTD20__FLEXSPI2_A_DATA6                 = IOMUX_PAD(0x0050, 0x0050, 0x9, 0x0000, 0x0, 0),
+	IMX8ULP_PAD_PTD21__FLEXSPI2_A_DATA5                 = IOMUX_PAD(0x0054, 0x0054, 0x9, 0x0000, 0x0, 0),
+	IMX8ULP_PAD_PTD22__FLEXSPI2_A_DATA4                 = IOMUX_PAD(0x0058, 0x0058, 0x9, 0x0000, 0x0, 0),
+	IMX8ULP_PAD_PTD23__FLEXSPI2_A_SS0_B                 = IOMUX_PAD(0x005c, 0x005c, 0x9, 0x0000, 0x0, 0),
+	IMX8ULP_PAD_PTD23__FLEXSPI2_A_SCLK                  = IOMUX_PAD(0x005c, 0x005c, 0xa, 0x0000, 0x0, 0),
+
+	IMX8ULP_PAD_PTE19__ENET0_REFCLK                     = IOMUX_PAD(0x00CC, 0x00CC, 0xA, 0x0AF4, 0x1, 0),
+	IMX8ULP_PAD_PTF10__ENET0_1588_CLKIN                 = IOMUX_PAD(0x0128, 0x0128, 0x9, 0x0AD0, 0x2, 0),
+
+	IMX8ULP_PAD_PTF11__SDHC1_RESET_b                    = IOMUX_PAD(0x012C, 0x012C, 0x8, 0x0000, 0x0, 0),
+	IMX8ULP_PAD_PTF3__SDHC1_CMD                         = IOMUX_PAD(0x010C, 0x010C, 0x8, 0x0A60, 0x2, 0),
+	IMX8ULP_PAD_PTF2__SDHC1_CLK                         = IOMUX_PAD(0x0108, 0x0108, 0x8, 0x0A5C, 0x2, 0),
+	IMX8ULP_PAD_PTF4__SDHC1_D3                          = IOMUX_PAD(0x0110, 0x0110, 0x8, 0x0A70, 0x2, 0),
+	IMX8ULP_PAD_PTF5__SDHC1_D2                          = IOMUX_PAD(0x0114, 0x0114, 0x8, 0x0A6C, 0x2, 0),
+	IMX8ULP_PAD_PTF0__SDHC1_D1                          = IOMUX_PAD(0x0100, 0x0100, 0x8, 0x0A68, 0x2, 0),
+	IMX8ULP_PAD_PTF1__SDHC1_D0                          = IOMUX_PAD(0x0104, 0x0104, 0x8, 0x0A64, 0x2, 0),
+
+};
+#endif  /* __ASM_ARCH_IMX8ULP_PINS_H__ */
diff --git a/arch/arm/mach-imx/Makefile b/arch/arm/mach-imx/Makefile
index 82aa39dee7..36224d8db9 100644
--- a/arch/arm/mach-imx/Makefile
+++ b/arch/arm/mach-imx/Makefile
@@ -227,6 +227,7 @@ obj-$(CONFIG_MX5) += mx5/
 obj-$(CONFIG_MX6) += mx6/
 obj-$(CONFIG_MX7) += mx7/
 obj-$(CONFIG_ARCH_MX7ULP) += mx7ulp/
+obj-$(CONFIG_ARCH_IMX8ULP) += imx8ulp/
 obj-$(CONFIG_IMX8M) += imx8m/
 obj-$(CONFIG_ARCH_IMX8) += imx8/
 obj-$(CONFIG_ARCH_IMXRT) += imxrt/
diff --git a/arch/arm/mach-imx/imx8ulp/Makefile b/arch/arm/mach-imx/imx8ulp/Makefile
new file mode 100644
index 0000000000..e8970dc04f
--- /dev/null
+++ b/arch/arm/mach-imx/imx8ulp/Makefile
@@ -0,0 +1,7 @@
+# SPDX-License-Identifier: GPL-2.0+
+#
+# Copyright 2020 NXP
+#
+
+obj-y += lowlevel_init.o
+obj-y += soc.o clock.o iomux.o
diff --git a/arch/arm/mach-imx/imx8ulp/clock.c b/arch/arm/mach-imx/imx8ulp/clock.c
new file mode 100644
index 0000000000..f866809fc2
--- /dev/null
+++ b/arch/arm/mach-imx/imx8ulp/clock.c
@@ -0,0 +1,27 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2020 NXP
+ */
+
+#include <common.h>
+#include <div64.h>
+#include <asm/io.h>
+#include <errno.h>
+#include <asm/arch/clock.h>
+#include <asm/arch/sys_proto.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+void clock_init(void)
+{
+}
+
+unsigned int mxc_get_clock(enum mxc_clock clk)
+{
+	return 0;
+}
+
+u32 get_lpuart_clk(void)
+{
+	return 24000000;
+}
diff --git a/arch/arm/mach-imx/imx8ulp/iomux.c b/arch/arm/mach-imx/imx8ulp/iomux.c
new file mode 100644
index 0000000000..c52ccdeaea
--- /dev/null
+++ b/arch/arm/mach-imx/imx8ulp/iomux.c
@@ -0,0 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2020 NXP
+ */
diff --git a/arch/arm/mach-imx/imx8ulp/lowlevel_init.S b/arch/arm/mach-imx/imx8ulp/lowlevel_init.S
new file mode 100644
index 0000000000..7d81a75639
--- /dev/null
+++ b/arch/arm/mach-imx/imx8ulp/lowlevel_init.S
@@ -0,0 +1,32 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright 2020 NXP
+ */
+
+#include <config.h>
+
+.align 8
+.global rom_pointer
+rom_pointer:
+	.space 256
+
+/*
+ * Routine: save_boot_params (called after reset from start.S)
+ */
+
+.global save_boot_params
+save_boot_params:
+	/* The firmware provided ATAG/FDT address can be found in r2/x0 */
+	adr	x0, rom_pointer
+	stp	x1, x2, [x0], #16
+	stp	x3, x4, [x0], #16
+
+	/* Returns */
+	b	save_boot_params_ret
+
+.global restore_boot_params
+restore_boot_params:
+	adr	x0, rom_pointer
+	ldp	x1, x2, [x0], #16
+	ldp	x3, x4, [x0], #16
+	ret
diff --git a/arch/arm/mach-imx/imx8ulp/soc.c b/arch/arm/mach-imx/imx8ulp/soc.c
index 383dbe6000..92998e9146 100644
--- a/arch/arm/mach-imx/imx8ulp/soc.c
+++ b/arch/arm/mach-imx/imx8ulp/soc.c
@@ -7,8 +7,11 @@
 #include <asm/arch/clock.h>
 #include <asm/arch/imx-regs.h>
 #include <asm/arch/sys_proto.h>
+#include <asm/armv8/mmu.h>
 #include <asm/mach-imx/boot_mode.h>
 
+DECLARE_GLOBAL_DATA_PTR;
+
 u32 get_cpu_rev(void)
 {
 	return (MXC_CPU_IMX8ULP << 12) | CHIP_REV_1_0;
@@ -52,8 +55,8 @@ static u32 reset_cause = -1;
 static char *get_reset_cause(char *ret)
 {
 	u32 cause1, cause = 0, srs = 0;
-	void __iomem *reg_ssrs = (void __iomem *)(SRC_BASE_ADDR + 0x88);
-	void __iomem *reg_srs = (void __iomem *)(SRC_BASE_ADDR + 0x80);
+	void __iomem *reg_ssrs = (void __iomem *)(CMC1_BASE_ADDR + 0x88);
+	void __iomem *reg_srs = (void __iomem *)(CMC1_BASE_ADDR + 0x80);
 
 	if (!ret)
 		return "null";
@@ -137,3 +140,147 @@ int print_cpuinfo(void)
 }
 #endif
 
+void init_wdog(void)
+{
+	/* TODO */
+}
+
+void s_init(void)
+{
+	/* Disable wdog */
+	init_wdog();
+}
+
+static struct mm_region imx8ulp_arm64_mem_map[] = {
+	{
+		/* ROM */
+		.virt = 0x0,
+		.phys = 0x0,
+		.size = 0x40000UL,
+		.attrs = PTE_BLOCK_MEMTYPE(MT_NORMAL) |
+			 PTE_BLOCK_OUTER_SHARE
+	},
+	{
+		/* SSRAM (align with 2M) */
+		.virt = 0x1FE00000UL,
+		.phys = 0x1FE00000UL,
+		.size = 0x400000UL,
+		.attrs = PTE_BLOCK_MEMTYPE(MT_NORMAL) |
+			 PTE_BLOCK_OUTER_SHARE |
+			 PTE_BLOCK_PXN | PTE_BLOCK_UXN
+	}, {
+		/* SRAM1 (align with 2M) */
+		.virt = 0x21000000UL,
+		.phys = 0x21000000UL,
+		.size = 0x200000UL,
+		.attrs = PTE_BLOCK_MEMTYPE(MT_NORMAL) |
+			 PTE_BLOCK_OUTER_SHARE |
+			 PTE_BLOCK_PXN | PTE_BLOCK_UXN
+	}, {
+		/* SRAM0 (align with 2M) */
+		.virt = 0x22000000UL,
+		.phys = 0x22000000UL,
+		.size = 0x200000UL,
+		.attrs = PTE_BLOCK_MEMTYPE(MT_NORMAL) |
+			 PTE_BLOCK_OUTER_SHARE |
+			 PTE_BLOCK_PXN | PTE_BLOCK_UXN
+	}, {
+		/* Peripherals */
+		.virt = 0x27000000UL,
+		.phys = 0x27000000UL,
+		.size = 0x3000000UL,
+		.attrs = PTE_BLOCK_MEMTYPE(MT_DEVICE_NGNRNE) |
+			 PTE_BLOCK_NON_SHARE |
+			 PTE_BLOCK_PXN | PTE_BLOCK_UXN
+	}, {
+		/* Peripherals */
+		.virt = 0x2D000000UL,
+		.phys = 0x2D000000UL,
+		.size = 0x1600000UL,
+		.attrs = PTE_BLOCK_MEMTYPE(MT_DEVICE_NGNRNE) |
+			 PTE_BLOCK_NON_SHARE |
+			 PTE_BLOCK_PXN | PTE_BLOCK_UXN
+	}, {
+		/* FLEXSPI1-2 */
+		.virt = 0x40000000UL,
+		.phys = 0x40000000UL,
+		.size = 0x40000000UL,
+		.attrs = PTE_BLOCK_MEMTYPE(MT_DEVICE_NGNRNE) |
+			 PTE_BLOCK_NON_SHARE |
+			 PTE_BLOCK_PXN | PTE_BLOCK_UXN
+	}, {
+		/* DRAM1 */
+		.virt = 0x80000000UL,
+		.phys = 0x80000000UL,
+		.size = PHYS_SDRAM_SIZE,
+		.attrs = PTE_BLOCK_MEMTYPE(MT_NORMAL) |
+			 PTE_BLOCK_OUTER_SHARE
+	}, {
+		/*
+		 * empty entrie to split table entry 5
+		 * if needed when TEEs are used
+		 */
+		0,
+	}, {
+		/* List terminator */
+		0,
+	}
+};
+
+struct mm_region *mem_map = imx8ulp_arm64_mem_map;
+
+/* simplify the page table size to enhance boot speed */
+#define MAX_PTE_ENTRIES		512
+#define MAX_MEM_MAP_REGIONS	16
+u64 get_page_table_size(void)
+{
+	u64 one_pt = MAX_PTE_ENTRIES * sizeof(u64);
+	u64 size = 0;
+
+	/*
+	 * For each memory region, the max table size:
+	 * 2 level 3 tables + 2 level 2 tables + 1 level 1 table
+	 */
+	size = (2 + 2 + 1) * one_pt * MAX_MEM_MAP_REGIONS + one_pt;
+
+	/*
+	 * We need to duplicate our page table once to have an emergency pt to
+	 * resort to when splitting page tables later on
+	 */
+	size *= 2;
+
+	/*
+	 * We may need to split page tables later on if dcache settings change,
+	 * so reserve up to 4 (random pick) page tables for that.
+	 */
+	size += one_pt * 4;
+
+	return size;
+}
+
+void enable_caches(void)
+{
+	/* TODO: add TEE memmap region */
+
+	icache_enable();
+	dcache_enable();
+}
+
+int dram_init(void)
+{
+	gd->ram_size = PHYS_SDRAM_SIZE;
+
+	return 0;
+}
+
+#ifdef CONFIG_SERIAL_TAG
+void get_board_serial(struct tag_serialnr *serialnr)
+{
+	/* TODO */
+}
+#endif
+
+int arch_cpu_init(void)
+{
+	return 0;
+}
