diff --git a/arch/arm/include/asm/arch-omap5/clock.h b/arch/arm/include/asm/arch-omap5/clock.h
index 87eb3f335ab0..a00626e357c9 100644
--- a/arch/arm/include/asm/arch-omap5/clock.h
+++ b/arch/arm/include/asm/arch-omap5/clock.h
@@ -135,6 +135,9 @@
 #define HSMMC_CLKCTRL_CLKSEL_MASK		(1 << 24)
 #define HSMMC_CLKCTRL_CLKSEL_DIV_MASK		(3 << 25)
 
+/* CM_IPU1_IPU1_CLKCTRL CLKSEL MASK */
+#define IPU1_CLKCTRL_CLKSEL_MASK		BIT(24)
+
 /* CM_L3INIT_SATA_CLKCTRL */
 #define SATA_CLKCTRL_OPTFCLKEN_MASK		(1 << 8)
 
diff --git a/arch/arm/include/asm/omap_common.h b/arch/arm/include/asm/omap_common.h
index de8fc99d0478..264a2e717a70 100644
--- a/arch/arm/include/asm/omap_common.h
+++ b/arch/arm/include/asm/omap_common.h
@@ -362,6 +362,10 @@ struct prcm_regs {
 	/* IPU */
 	u32 cm_ipu_clkstctrl;
 	u32 cm_ipu_i2c5_clkctrl;
+	u32 cm_ipu1_clkstctrl;
+	u32 cm_ipu1_ipu1_clkctrl;
+	u32 cm_ipu2_clkstctrl;
+	u32 cm_ipu2_ipu2_clkctrl;
 
 	/*l3main1 edma*/
 	u32 cm_l3main1_tptc1_clkctrl;
@@ -632,6 +636,12 @@ void do_disable_clocks(u32 const *clk_domains,
 		       u8 wait_for_disable);
 #endif /* CONFIG_OMAP44XX || CONFIG_OMAP54XX */
 
+void do_enable_ipu_clocks(u32 const *clk_domains,
+			  u32 const *clk_modules_hw_auto,
+			  u32 const *clk_modules_explicit_en,
+			  u8 wait_for_enable);
+void enable_ipu1_clocks(void);
+void enable_ipu2_clocks(void);
 void setup_post_dividers(u32 const base,
 			const struct dpll_params *params);
 u32 omap_ddr_clk(void);
diff --git a/arch/arm/mach-omap2/boot-common.c b/arch/arm/mach-omap2/boot-common.c
index fdb8b479ea01..afc358564191 100644
--- a/arch/arm/mach-omap2/boot-common.c
+++ b/arch/arm/mach-omap2/boot-common.c
@@ -10,6 +10,8 @@
 #include <common.h>
 #include <ahci.h>
 #include <log.h>
+#include <dm/uclass.h>
+#include <fs_loader.h>
 #include <spl.h>
 #include <asm/global_data.h>
 #include <asm/omap_common.h>
@@ -19,9 +21,14 @@
 #include <watchdog.h>
 #include <scsi.h>
 #include <i2c.h>
+#include <remoteproc.h>
 
 DECLARE_GLOBAL_DATA_PTR;
 
+#define IPU1_LOAD_ADDR         (0xa17ff000)
+#define MAX_REMOTECORE_BIN_SIZE (8 * 0x100000)
+#define IPU2_LOAD_ADDR         (IPU1_LOAD_ADDR + MAX_REMOTECORE_BIN_SIZE)
+
 __weak u32 omap_sys_boot_device(void)
 {
 	return BOOT_DEVICE_NONE;
@@ -194,6 +201,91 @@ u32 spl_mmc_boot_mode(const u32 boot_device)
 	return gd->arch.omap_boot_mode;
 }
 
+int load_firmware(char *name_fw, u32 *loadaddr)
+{
+	struct udevice *fsdev;
+	int size = 0;
+
+	if (!IS_ENABLED(CONFIG_FS_LOADER))
+		return 0;
+
+	if (!*loadaddr)
+		return 0;
+
+	if (!uclass_get_device(UCLASS_FS_FIRMWARE_LOADER, 0, &fsdev)) {
+		size = request_firmware_into_buf(fsdev, name_fw,
+						 (void *)*loadaddr, 0, 0);
+	}
+
+	return size;
+}
+
+void spl_boot_ipu(void)
+{
+	int ret, size;
+	u32 loadaddr = IPU1_LOAD_ADDR;
+
+	if (!IS_ENABLED(CONFIG_SPL_BUILD) ||
+	    !IS_ENABLED(CONFIG_REMOTEPROC_TI_IPU))
+		return;
+
+	size = load_firmware("dra7-ipu1-fw.xem4", &loadaddr);
+	if (size <= 0) {
+		pr_err("Firmware loading failed\n");
+		goto skip_ipu1;
+	}
+
+	enable_ipu1_clocks();
+	ret = rproc_dev_init(0);
+	if (ret) {
+		debug("%s: IPU1 failed to initialize on rproc (%d)\n",
+		      __func__, ret);
+		goto skip_ipu1;
+	}
+
+	ret = rproc_load(0, IPU1_LOAD_ADDR, 0x2000000);
+	if (ret) {
+		debug("%s: IPU1 failed to load on rproc (%d)\n", __func__,
+		      ret);
+		goto skip_ipu1;
+	}
+
+	debug("Starting IPU1...\n");
+
+	ret = rproc_start(0);
+	if (ret)
+		debug("%s: IPU1 failed to start (%d)\n", __func__, ret);
+
+skip_ipu1:
+	loadaddr = IPU2_LOAD_ADDR;
+	size = load_firmware("dra7-ipu2-fw.xem4", &loadaddr);
+	if (size <= 0) {
+		pr_err("Firmware loading failed for ipu2\n");
+		return;
+	}
+
+	enable_ipu2_clocks();
+	ret = rproc_dev_init(1);
+	if (ret) {
+		debug("%s: IPU2 failed to initialize on rproc (%d)\n", __func__,
+		      ret);
+		return;
+	}
+
+	ret = rproc_load(1, IPU2_LOAD_ADDR, 0x2000000);
+	if (ret) {
+		debug("%s: IPU2 failed to load on rproc (%d)\n", __func__,
+		      ret);
+		return;
+	}
+
+	debug("Starting IPU2...\n");
+
+	ret = rproc_start(1);
+	if (ret)
+		debug("%s: IPU2 failed to start (%d)\n", __func__, ret);
+}
+
 void spl_board_init(void)
 {
 	/* Prepare console output */
@@ -214,6 +306,9 @@ void spl_board_init(void)
 #ifdef CONFIG_AM33XX
 	am33xx_spl_board_init();
 #endif
+	if (IS_ENABLED(CONFIG_SPL_BUILD) &&
+	    IS_ENABLED(CONFIG_REMOTEPROC_TI_IPU))
+		spl_boot_ipu();
 }
 
 void __noreturn jump_to_image_no_args(struct spl_image_info *spl_image)
diff --git a/arch/arm/mach-omap2/clocks-common.c b/arch/arm/mach-omap2/clocks-common.c
index 1d8eab2dab50..390d1f2a649b 100644
--- a/arch/arm/mach-omap2/clocks-common.c
+++ b/arch/arm/mach-omap2/clocks-common.c
@@ -858,6 +858,39 @@ void do_enable_clocks(u32 const *clk_domains,
 	}
 }
 
+void do_enable_ipu_clocks(u32 const *clk_domains,
+			  u32 const *clk_modules_hw_auto,
+			  u32 const *clk_modules_explicit_en,
+			  u8 wait_for_enable)
+{
+	u32 i, max = 10;
+
+	if (!IS_ENABLED(CONFIG_REMOTEPROC_TI_IPU))
+		return;
+
+	/* Put the clock domains in SW_WKUP mode */
+	for (i = 0; (i < max) && clk_domains && clk_domains[i]; i++) {
+		enable_clock_domain(clk_domains[i],
+				    CD_CLKCTRL_CLKTRCTRL_SW_WKUP);
+	}
+
+	/* Clock modules that need to be put in HW_AUTO */
+	for (i = 0; (i < max) && clk_modules_hw_auto &&
+	     clk_modules_hw_auto[i]; i++) {
+		enable_clock_module(clk_modules_hw_auto[i],
+				    MODULE_CLKCTRL_MODULEMODE_HW_AUTO,
+				    wait_for_enable);
+	};
+
+	/* Clock modules that need to be put in SW_EXPLICIT_EN mode */
+	for (i = 0; (i < max) && clk_modules_explicit_en &&
+	     clk_modules_explicit_en[i]; i++) {
+		enable_clock_module(clk_modules_explicit_en[i],
+				    MODULE_CLKCTRL_MODULEMODE_SW_EXPLICIT_EN,
+				    wait_for_enable);
+	};
+}
+
 void do_disable_clocks(u32 const *clk_domains,
 			    u32 const *clk_modules_disable,
 			    u8 wait_for_disable)
diff --git a/arch/arm/mach-omap2/omap5/hw_data.c b/arch/arm/mach-omap2/omap5/hw_data.c
index fa4e27063c53..e6bee48dfcb3 100644
--- a/arch/arm/mach-omap2/omap5/hw_data.c
+++ b/arch/arm/mach-omap2/omap5/hw_data.c
@@ -376,6 +376,85 @@ struct vcores_data omap5430_volts_es2 = {
 	.mm.efuse.reg_bits	= OMAP5_ES2_PROD_REGBITS,
 };
 
+/*
+ * Enable IPU1 clock domains, modules and
+ * do some additional special settings needed
+ */
+void enable_ipu1_clocks(void)
+{
+	if (!IS_ENABLED(CONFIG_DRA7XX) ||
+	    !IS_ENABLED(CONFIG_REMOTEPROC_TI_IPU))
+		return;
+
+	u32 const clk_domains[] = {
+		(*prcm)->cm_ipu_clkstctrl,
+		(*prcm)->cm_ipu1_clkstctrl,
+		0
+	};
+
+	u32 const clk_modules_hw_auto_essential[] = {
+		(*prcm)->cm_ipu1_ipu1_clkctrl,
+		0
+	};
+
+	u32 const clk_modules_explicit_en_essential[] = {
+		(*prcm)->cm_l4per_gptimer11_clkctrl,
+		(*prcm)->cm1_abe_timer7_clkctrl,
+		(*prcm)->cm1_abe_timer8_clkctrl,
+		0
+	};
+	do_enable_ipu_clocks(clk_domains, clk_modules_hw_auto_essential,
+			     clk_modules_explicit_en_essential, 0);
+
+	/* Enable optional additional functional clock for IPU1 */
+	setbits_le32((*prcm)->cm_ipu1_ipu1_clkctrl,
+		     IPU1_CLKCTRL_CLKSEL_MASK);
+	/* Enable optional additional functional clock for IPU1 */
+	setbits_le32((*prcm)->cm1_abe_timer7_clkctrl,
+		     IPU1_CLKCTRL_CLKSEL_MASK);
+	/* Enable optional additional functional clock for IPU1 */
+	setbits_le32((*prcm)->cm1_abe_timer8_clkctrl,
+		     IPU1_CLKCTRL_CLKSEL_MASK);
+}
+
+/*
+ * Enable IPU2 clock domains, modules and
+ * do some additional special settings needed
+ */
+void enable_ipu2_clocks(void)
+{
+	if (!IS_ENABLED(CONFIG_DRA7XX) ||
+	    !IS_ENABLED(CONFIG_REMOTEPROC_TI_IPU))
+		return;
+
+	u32 const clk_domains[] = {
+		(*prcm)->cm_ipu_clkstctrl,
+		(*prcm)->cm_ipu2_clkstctrl,
+		0
+	};
+
+	u32 const clk_modules_hw_auto_essential[] = {
+		(*prcm)->cm_ipu2_ipu2_clkctrl,
+		0
+	};
+
+	u32 const clk_modules_explicit_en_essential[] = {
+		(*prcm)->cm_l4per_gptimer3_clkctrl,
+		(*prcm)->cm_l4per_gptimer4_clkctrl,
+		(*prcm)->cm_l4per_gptimer9_clkctrl,
+		0
+	};
+	do_enable_ipu_clocks(clk_domains, clk_modules_hw_auto_essential,
+			     clk_modules_explicit_en_essential, 0);
+
+	/* Enable optional additional functional clock for IPU2 */
+	setbits_le32((*prcm)->cm_l4per_gptimer4_clkctrl,
+		     IPU1_CLKCTRL_CLKSEL_MASK);
+	/* Enable optional additional functional clock for IPU2 */
+	setbits_le32((*prcm)->cm_l4per_gptimer9_clkctrl,
+		     IPU1_CLKCTRL_CLKSEL_MASK);
+}
+
 /*
  * Enable essential clock domains, modules and
  * do some additional special settings needed
@@ -478,12 +557,13 @@ void enable_basic_clocks(void)
 
 void enable_basic_uboot_clocks(void)
 {
-	u32 const clk_domains_essential[] = {
-#if defined(CONFIG_DRA7XX)
-		(*prcm)->cm_ipu_clkstctrl,
-#endif
-		0
-	};
+	u32 cm_ipu_clkstctrl = 0;
+
+	if (IS_ENABLED(CONFIG_DRA7XX) &&
+	    !IS_ENABLED(CONFIG_REMOTEPROC_TI_IPU))
+		cm_ipu_clkstctrl = (*prcm)->cm_ipu_clkstctrl;
+
+	u32 const clk_domains_essential[] = {cm_ipu_clkstctrl, 0};
 
 	u32 const clk_modules_hw_auto_essential[] = {
 		(*prcm)->cm_l3init_hsusbtll_clkctrl,
diff --git a/arch/arm/mach-omap2/omap5/prcm-regs.c b/arch/arm/mach-omap2/omap5/prcm-regs.c
index 28c4f4f73749..d7196a3156c9 100644
--- a/arch/arm/mach-omap2/omap5/prcm-regs.c
+++ b/arch/arm/mach-omap2/omap5/prcm-regs.c
@@ -832,7 +832,10 @@ struct prcm_regs const dra7xx_prcm = {
 	/* cm IPU */
 	.cm_ipu_clkstctrl			= 0x4a005540,
 	.cm_ipu_i2c5_clkctrl			= 0x4a005578,
-
+	.cm_ipu1_clkstctrl			= 0x4a005500,
+	.cm_ipu1_ipu1_clkctrl			= 0x4a005520,
+	.cm_ipu2_clkstctrl			= 0x4a008900,
+	.cm_ipu2_ipu2_clkctrl			= 0x4a008920,
 	/* prm irqstatus regs */
 	.prm_irqstatus_mpu			= 0x4ae06010,
 	.prm_irqstatus_mpu_2			= 0x4ae06014,
@@ -1013,6 +1016,10 @@ struct prcm_regs const dra7xx_prcm = {
 	/*l3main1 edma*/
 	.cm_l3main1_tptc1_clkctrl               = 0x4a008778,
 	.cm_l3main1_tptc2_clkctrl               = 0x4a008780,
+
+	/* cm1.abe */
+	.cm1_abe_timer7_clkctrl = 0x4a005568,
+	.cm1_abe_timer8_clkctrl = 0x4a005570,
 };
 
 void clrset_spare_register(u8 spare_type, u32 clear_bits, u32 set_bits)
