diff --git a/arch/arm/cpu/armv7/socfpga/Makefile b/arch/arm/cpu/armv7/socfpga/Makefile
index 0859e44..10d20f2 100644
--- a/arch/arm/cpu/armv7/socfpga/Makefile
+++ b/arch/arm/cpu/armv7/socfpga/Makefile
@@ -14,7 +14,7 @@ LIB	=  $(obj)lib$(SOC).o
 
 SOBJS	:= lowlevel_init.o
 COBJS-y	:= misc.o timer.o reset_manager.o system_manager.o
-COBJS-$(CONFIG_SPL_BUILD) += spl.o
+COBJS-$(CONFIG_SPL_BUILD) += spl.o freeze_controller.o
 
 COBJS	:= $(COBJS-y)
 SRCS	:= $(SOBJS:.o=.S) $(COBJS:.o=.c)
diff --git a/arch/arm/cpu/armv7/socfpga/freeze_controller.c b/arch/arm/cpu/armv7/socfpga/freeze_controller.c
new file mode 100644
index 0000000..668c6d6
--- /dev/null
+++ b/arch/arm/cpu/armv7/socfpga/freeze_controller.c
@@ -0,0 +1,249 @@
+/*
+ *  Copyright (C) 2013 Altera Corporation <www.altera.com>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+
+#include <common.h>
+#include <asm/io.h>
+#include <asm/arch/freeze_controller.h>
+#include <asm/arch/timer.h>
+#include <asm/errno.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+
+
+static const struct socfpga_freeze_controller *freeze_controller_base =
+		(void *)(SOCFPGA_SYSMGR_ADDRESS + SYSMGR_FRZCTRL_ADDRESS);
+
+/*
+ * Default state from cold reset is FREEZE_ALL; the global
+ * flag is set to TRUE to indicate the IO banks are frozen
+ */
+static uint32_t frzctrl_channel_freeze[FREEZE_CHANNEL_NUM]
+	= { FREEZE_CTRL_FROZEN, FREEZE_CTRL_FROZEN,
+	FREEZE_CTRL_FROZEN, FREEZE_CTRL_FROZEN};
+
+
+/* Freeze HPS IOs */
+u32 sys_mgr_frzctrl_freeze_req(FreezeChannelSelect channel_id,
+			FreezeControllerFSMSelect fsm_select)
+{
+	u32 ioctrl_reg_offset;
+	u32 reg_value;
+	u32 reg_cfg_mask;
+
+	if (FREEZE_CONTROLLER_FSM_SW != fsm_select)
+		return -EINVAL;
+
+	/* select software FSM */
+	writel(SYSMGR_FRZCTRL_SRC_VIO1_ENUM_SW,	&freeze_controller_base->src);
+
+	/* Freeze channel ID checking and base address */
+	switch (channel_id) {
+	case FREEZE_CHANNEL_0:
+	case FREEZE_CHANNEL_1:
+	case FREEZE_CHANNEL_2:
+		ioctrl_reg_offset = (u32)(
+			&freeze_controller_base->vioctrl +
+			(channel_id << SYSMGR_FRZCTRL_VIOCTRL_SHIFT));
+
+		/*
+		 * Assert active low enrnsl, plniotri
+		 * and niotri signals
+		 */
+		reg_cfg_mask =
+			SYSMGR_FRZCTRL_VIOCTRL_SLEW_MASK
+			| SYSMGR_FRZCTRL_VIOCTRL_WKPULLUP_MASK
+			| SYSMGR_FRZCTRL_VIOCTRL_TRISTATE_MASK;
+		clrbits_le32(ioctrl_reg_offset,	reg_cfg_mask);
+
+		/*
+		 * Note: Delay for 20ns at min
+		 * Assert active low bhniotri signal and de-assert
+		 * active high csrdone
+		 */
+		reg_cfg_mask
+			= SYSMGR_FRZCTRL_VIOCTRL_BUSHOLD_MASK
+			| SYSMGR_FRZCTRL_VIOCTRL_CFG_MASK;
+		clrbits_le32(ioctrl_reg_offset,	reg_cfg_mask);
+
+		/* Set global flag to indicate channel is frozen */
+		frzctrl_channel_freeze[channel_id] = FREEZE_CTRL_FROZEN;
+		break;
+
+	case FREEZE_CHANNEL_3:
+		/*
+		 * Assert active low enrnsl, plniotri and
+		 * niotri signals
+		 */
+		reg_cfg_mask
+			= SYSMGR_FRZCTRL_HIOCTRL_SLEW_MASK
+			| SYSMGR_FRZCTRL_HIOCTRL_WKPULLUP_MASK
+			| SYSMGR_FRZCTRL_HIOCTRL_TRISTATE_MASK;
+		clrbits_le32(&freeze_controller_base->hioctrl, reg_cfg_mask);
+
+		/*
+		 * Note: Delay for 40ns at min
+		 * assert active low bhniotri & nfrzdrv signals,
+		 * de-assert active high csrdone and assert
+		 * active high frzreg and nfrzdrv signals
+		 */
+		reg_value = readl(&freeze_controller_base->hioctrl);
+		reg_cfg_mask
+			= SYSMGR_FRZCTRL_HIOCTRL_BUSHOLD_MASK
+			| SYSMGR_FRZCTRL_HIOCTRL_CFG_MASK;
+		reg_value
+			= (reg_value & ~reg_cfg_mask)
+			| SYSMGR_FRZCTRL_HIOCTRL_REGRST_MASK
+			| SYSMGR_FRZCTRL_HIOCTRL_OCTRST_MASK;
+		writel(reg_value, &freeze_controller_base->hioctrl);
+
+		/*
+		 * Note: Delay for 40ns at min
+		 * assert active high reinit signal and de-assert
+		 * active high pllbiasen signals
+		 */
+		reg_value = readl(&freeze_controller_base->hioctrl);
+		reg_value
+			= (reg_value &
+			~SYSMGR_FRZCTRL_HIOCTRL_OCT_CFGEN_CALSTART_MASK)
+			| SYSMGR_FRZCTRL_HIOCTRL_DLLRST_MASK;
+		writel(reg_value, &freeze_controller_base->hioctrl);
+
+		/* Set global flag to indicate channel is frozen */
+		frzctrl_channel_freeze[channel_id] = FREEZE_CTRL_FROZEN;
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+/* Unfreeze/Thaw HPS IOs */
+u32 sys_mgr_frzctrl_thaw_req(FreezeChannelSelect channel_id,
+			FreezeControllerFSMSelect fsm_select)
+{
+	u32 ioctrl_reg_offset;
+	u32 reg_cfg_mask;
+	u32 reg_value;
+
+	if (FREEZE_CONTROLLER_FSM_SW != fsm_select)
+		return -EINVAL;
+
+	/* select software FSM */
+	writel(SYSMGR_FRZCTRL_SRC_VIO1_ENUM_SW,	&freeze_controller_base->src);
+
+	/* Freeze channel ID checking and base address */
+	switch (channel_id) {
+	case FREEZE_CHANNEL_0:
+	case FREEZE_CHANNEL_1:
+	case FREEZE_CHANNEL_2:
+		ioctrl_reg_offset
+			= (u32)(&freeze_controller_base->vioctrl
+				+ (channel_id << SYSMGR_FRZCTRL_VIOCTRL_SHIFT));
+
+		/*
+		 * Assert active low bhniotri signal and
+		 * de-assert active high csrdone
+		 */
+		reg_cfg_mask
+			= SYSMGR_FRZCTRL_VIOCTRL_BUSHOLD_MASK
+			| SYSMGR_FRZCTRL_VIOCTRL_CFG_MASK;
+		setbits_le32(ioctrl_reg_offset,	reg_cfg_mask);
+
+		/*
+		 * Note: Delay for 20ns at min
+		 * de-assert active low plniotri and niotri signals
+		 */
+		reg_cfg_mask
+			= SYSMGR_FRZCTRL_VIOCTRL_WKPULLUP_MASK
+			| SYSMGR_FRZCTRL_VIOCTRL_TRISTATE_MASK;
+		setbits_le32(ioctrl_reg_offset,	reg_cfg_mask);
+
+		/*
+		 * Note: Delay for 20ns at min
+		 * de-assert active low enrnsl signal
+		 */
+		setbits_le32(ioctrl_reg_offset,
+			SYSMGR_FRZCTRL_VIOCTRL_SLEW_MASK);
+
+		/* Set global flag to indicate channel is thawed */
+		frzctrl_channel_freeze[channel_id] = FREEZE_CTRL_THAWED;
+
+		break;
+
+	case FREEZE_CHANNEL_3:
+		/* de-assert active high reinit signal */
+		clrbits_le32(&freeze_controller_base->hioctrl,
+			SYSMGR_FRZCTRL_HIOCTRL_DLLRST_MASK);
+
+		/*
+		 * Note: Delay for 40ns at min
+		 * assert active high pllbiasen signals
+		 */
+		setbits_le32(&freeze_controller_base->hioctrl,
+			SYSMGR_FRZCTRL_HIOCTRL_OCT_CFGEN_CALSTART_MASK);
+
+		/*
+		 * Delay 1000 intosc. intosc is based on eosc1
+		 * Use worst case which is fatest eosc1=50MHz, delay required
+		 * is 1/50MHz * 1000 = 20us
+		 */
+		udelay(20);
+
+		/*
+		 * de-assert active low bhniotri signals,
+		 * assert active high csrdone and nfrzdrv signal
+		 */
+		reg_value = readl(&freeze_controller_base->hioctrl);
+		reg_value = (reg_value
+			| SYSMGR_FRZCTRL_HIOCTRL_BUSHOLD_MASK
+			| SYSMGR_FRZCTRL_HIOCTRL_CFG_MASK)
+			& ~SYSMGR_FRZCTRL_HIOCTRL_OCTRST_MASK;
+		writel(reg_value, &freeze_controller_base->hioctrl);
+
+		/*
+		 * Delay 33 intosc
+		 * Use worst case which is fatest eosc1=50MHz, delay required
+		 * is 1/50MHz * 33 = 660ns ~= 1us
+		 */
+		udelay(1);
+
+		/* de-assert active low plniotri and niotri signals */
+		reg_cfg_mask
+			= SYSMGR_FRZCTRL_HIOCTRL_WKPULLUP_MASK
+			| SYSMGR_FRZCTRL_HIOCTRL_TRISTATE_MASK;
+
+		setbits_le32(&freeze_controller_base->hioctrl, reg_cfg_mask);
+
+		/*
+		 * Note: Delay for 40ns at min
+		 * de-assert active high frzreg signal
+		 */
+		clrbits_le32(&freeze_controller_base->hioctrl,
+			SYSMGR_FRZCTRL_HIOCTRL_REGRST_MASK);
+
+		/*
+		 * Note: Delay for 40ns at min
+		 * de-assert active low enrnsl signal
+		 */
+		setbits_le32(&freeze_controller_base->hioctrl,
+			SYSMGR_FRZCTRL_HIOCTRL_SLEW_MASK);
+
+		/* Set global flag to indicate channel is thawed */
+		frzctrl_channel_freeze[channel_id] = FREEZE_CTRL_THAWED;
+
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
diff --git a/arch/arm/cpu/armv7/socfpga/spl.c b/arch/arm/cpu/armv7/socfpga/spl.c
index 74bceab..5173c0d 100644
--- a/arch/arm/cpu/armv7/socfpga/spl.c
+++ b/arch/arm/cpu/armv7/socfpga/spl.c
@@ -13,6 +13,8 @@
 #include <asm/arch/reset_manager.h>
 #include <spl.h>
 #include <asm/arch/system_manager.h>
+#include <asm/arch/freeze_controller.h>
+
 
 DECLARE_GLOBAL_DATA_PTR;
 
@@ -27,6 +29,13 @@ u32 spl_boot_device(void)
 void spl_board_init(void)
 {
 #ifndef CONFIG_SOCFPGA_VIRTUAL_TARGET
+	debug("Freezing all I/O banks\n");
+	/* freeze all IO banks */
+	sys_mgr_frzctrl_freeze_req(FREEZE_CHANNEL_0, FREEZE_CONTROLLER_FSM_SW);
+	sys_mgr_frzctrl_freeze_req(FREEZE_CHANNEL_1, FREEZE_CONTROLLER_FSM_SW);
+	sys_mgr_frzctrl_freeze_req(FREEZE_CHANNEL_2, FREEZE_CONTROLLER_FSM_SW);
+	sys_mgr_frzctrl_freeze_req(FREEZE_CHANNEL_3, FREEZE_CONTROLLER_FSM_SW);
+
 	/* configure the pin muxing through system manager */
 	sysmgr_pinmux_init();
 #endif /* CONFIG_SOCFPGA_VIRTUAL_TARGET */
@@ -34,6 +43,13 @@ void spl_board_init(void)
 	/* de-assert reset for peripherals and bridges based on handoff */
 	reset_deassert_peripherals_handoff();
 
+	debug("Unfreezing/Thaw all I/O banks\n");
+	/* unfreeze / thaw all IO banks */
+	sys_mgr_frzctrl_thaw_req(FREEZE_CHANNEL_0, FREEZE_CONTROLLER_FSM_SW);
+	sys_mgr_frzctrl_thaw_req(FREEZE_CHANNEL_1, FREEZE_CONTROLLER_FSM_SW);
+	sys_mgr_frzctrl_thaw_req(FREEZE_CHANNEL_2, FREEZE_CONTROLLER_FSM_SW);
+	sys_mgr_frzctrl_thaw_req(FREEZE_CHANNEL_3, FREEZE_CONTROLLER_FSM_SW);
+
 	/* enable console uart printing */
 	preloader_console_init();
 }
diff --git a/arch/arm/include/asm/arch-socfpga/freeze_controller.h b/arch/arm/include/asm/arch-socfpga/freeze_controller.h
new file mode 100644
index 0000000..b25ff99
--- /dev/null
+++ b/arch/arm/include/asm/arch-socfpga/freeze_controller.h
@@ -0,0 +1,71 @@
+/*
+ *  Copyright (C) 2013 Altera Corporation <www.altera.com>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#ifndef	_FREEZE_CONTROLLER_H_
+#define	_FREEZE_CONTROLLER_H_
+
+struct socfpga_freeze_controller {
+	u32	vioctrl;
+	u32	padding[3];
+	u32	hioctrl;
+	u32	src;
+	u32	hwctrl;
+};
+
+#define SYSMGR_FRZCTRL_LOOP_PARAM       (1000)
+#define SYSMGR_FRZCTRL_DELAY_LOOP_PARAM (10)
+#define SYSMGR_FRZCTRL_INTOSC_33	(33)
+#define SYSMGR_FRZCTRL_INTOSC_1000	(1000)
+#define FREEZE_CHANNEL_NUM		(4)
+
+typedef enum {
+	FREEZE_CTRL_FROZEN = 0,
+	FREEZE_CTRL_THAWED = 1
+} FREEZE_CTRL_CHAN_STATE;
+
+typedef enum  {
+	FREEZE_CHANNEL_0 = 0,   /* EMAC_IO & MIXED2_IO */
+	FREEZE_CHANNEL_1,	/* MIXED1_IO and FLASH_IO */
+	FREEZE_CHANNEL_2,	/* General IO */
+	FREEZE_CHANNEL_3,	/* DDR IO */
+	FREEZE_CHANNEL_UNDEFINED
+} FreezeChannelSelect;
+
+typedef enum {
+	FREEZE_CONTROLLER_FSM_SW = 0,
+	FREEZE_CONTROLLER_FSM_HW,
+	FREEZE_CONTROLLER_FSM_UNDEFINED
+} FreezeControllerFSMSelect;
+
+#define SYSMGR_FRZCTRL_ADDRESS 0x40
+#define SYSMGR_FRZCTRL_SRC_VIO1_ENUM_SW 0x0
+#define SYSMGR_FRZCTRL_SRC_VIO1_ENUM_HW 0x1
+#define SYSMGR_FRZCTRL_VIOCTRL_SLEW_MASK 0x00000010
+#define SYSMGR_FRZCTRL_VIOCTRL_WKPULLUP_MASK 0x00000008
+#define SYSMGR_FRZCTRL_VIOCTRL_TRISTATE_MASK 0x00000004
+#define SYSMGR_FRZCTRL_VIOCTRL_BUSHOLD_MASK 0x00000002
+#define SYSMGR_FRZCTRL_VIOCTRL_CFG_MASK 0x00000001
+#define SYSMGR_FRZCTRL_HIOCTRL_SLEW_MASK 0x00000010
+#define SYSMGR_FRZCTRL_HIOCTRL_WKPULLUP_MASK 0x00000008
+#define SYSMGR_FRZCTRL_HIOCTRL_TRISTATE_MASK 0x00000004
+#define SYSMGR_FRZCTRL_HIOCTRL_BUSHOLD_MASK 0x00000002
+#define SYSMGR_FRZCTRL_HIOCTRL_CFG_MASK 0x00000001
+#define SYSMGR_FRZCTRL_HIOCTRL_REGRST_MASK 0x00000080
+#define SYSMGR_FRZCTRL_HIOCTRL_OCTRST_MASK 0x00000040
+#define SYSMGR_FRZCTRL_HIOCTRL_OCT_CFGEN_CALSTART_MASK 0x00000100
+#define SYSMGR_FRZCTRL_HIOCTRL_DLLRST_MASK 0x00000020
+#define SYSMGR_FRZCTRL_HWCTRL_VIO1REQ_MASK 0x00000001
+#define SYSMGR_FRZCTRL_HWCTRL_VIO1STATE_ENUM_FROZEN 0x2
+#define SYSMGR_FRZCTRL_HWCTRL_VIO1STATE_ENUM_THAWED 0x1
+#define SYSMGR_FRZCTRL_HWCTRL_VIO1STATE_GET(x) (((x) & 0x00000006) >> 1)
+#define SYSMGR_FRZCTRL_VIOCTRL_SHIFT 0x2
+
+u32 sys_mgr_frzctrl_freeze_req(FreezeChannelSelect channel_id,
+	FreezeControllerFSMSelect fsm_select);
+u32 sys_mgr_frzctrl_thaw_req(FreezeChannelSelect channel_id,
+	FreezeControllerFSMSelect fsm_select);
+
+#endif /* _FREEZE_CONTROLLER_H_ */
