rockchip: add support for rk3288

The rk3288 is a 4-core Cortex-A12 SoC and shares a lot of features
with later SoCs.

Working features are general non-secure mode (the gic needs special
love for that), psci-based smp bringing cpu cores online and also
taking them offline again, psci-based suspend (the simpler variant
also included in the linux kernel, deeper suspend following later)
and I was also already able to test HYP-mode and was able to boot
a virtual kernel using kvm.

Signed-off-by: Heiko Stuebner <heiko@sntech.de>
Change-Id: Ibaaa583b2e78197591a91d254339706fe732476a
diff --git a/plat/rockchip/rk3288/drivers/pmu/plat_pmu_macros.S b/plat/rockchip/rk3288/drivers/pmu/plat_pmu_macros.S
new file mode 100644
index 0000000..2003749
--- /dev/null
+++ b/plat/rockchip/rk3288/drivers/pmu/plat_pmu_macros.S
@@ -0,0 +1,17 @@
+/*
+ * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <platform_def.h>
+
+.macro	func_rockchip_clst_warmboot
+	/* Nothing to do for rk3288 */
+.endm
+
+.macro rockchip_clst_warmboot_data
+	/* Nothing to do for rk3288 */
+.endm
diff --git a/plat/rockchip/rk3288/drivers/pmu/pmu.c b/plat/rockchip/rk3288/drivers/pmu/pmu.c
new file mode 100644
index 0000000..d6d7098
--- /dev/null
+++ b/plat/rockchip/rk3288/drivers/pmu/pmu.c
@@ -0,0 +1,391 @@
+/*
+ * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+
+#include <platform_def.h>
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <drivers/delay_timer.h>
+#include <lib/mmio.h>
+#include <plat/common/platform.h>
+
+#include <plat_private.h>
+#include <pmu.h>
+#include <pmu_com.h>
+#include <rk3288_def.h>
+#include <secure.h>
+#include <soc.h>
+
+DEFINE_BAKERY_LOCK(rockchip_pd_lock);
+
+static uint32_t cpu_warm_boot_addr;
+
+static uint32_t store_pmu_pwrmode_con;
+static uint32_t store_sgrf_soc_con0;
+static uint32_t store_sgrf_cpu_con0;
+
+/* These enum are variants of low power mode */
+enum {
+	ROCKCHIP_ARM_OFF_LOGIC_NORMAL = 0,
+	ROCKCHIP_ARM_OFF_LOGIC_DEEP = 1,
+};
+
+static inline int rk3288_pmu_bus_idle(uint32_t req, uint32_t idle)
+{
+	uint32_t mask = BIT(req);
+	uint32_t idle_mask = 0;
+	uint32_t idle_target = 0;
+	uint32_t val;
+	uint32_t wait_cnt = 0;
+
+	switch (req) {
+	case bus_ide_req_gpu:
+		idle_mask = BIT(pmu_idle_ack_gpu) | BIT(pmu_idle_gpu);
+		idle_target = (idle << pmu_idle_ack_gpu) |
+			      (idle << pmu_idle_gpu);
+		break;
+	case bus_ide_req_core:
+		idle_mask = BIT(pmu_idle_ack_core) | BIT(pmu_idle_core);
+		idle_target = (idle << pmu_idle_ack_core) |
+			      (idle << pmu_idle_core);
+		break;
+	case bus_ide_req_cpup:
+		idle_mask = BIT(pmu_idle_ack_cpup) | BIT(pmu_idle_cpup);
+		idle_target = (idle << pmu_idle_ack_cpup) |
+			      (idle << pmu_idle_cpup);
+		break;
+	case bus_ide_req_bus:
+		idle_mask = BIT(pmu_idle_ack_bus) | BIT(pmu_idle_bus);
+		idle_target = (idle << pmu_idle_ack_bus) |
+			      (idle << pmu_idle_bus);
+		break;
+	case bus_ide_req_dma:
+		idle_mask = BIT(pmu_idle_ack_dma) | BIT(pmu_idle_dma);
+		idle_target = (idle << pmu_idle_ack_dma) |
+			      (idle << pmu_idle_dma);
+		break;
+	case bus_ide_req_peri:
+		idle_mask = BIT(pmu_idle_ack_peri) | BIT(pmu_idle_peri);
+		idle_target = (idle << pmu_idle_ack_peri) |
+			      (idle << pmu_idle_peri);
+		break;
+	case bus_ide_req_video:
+		idle_mask = BIT(pmu_idle_ack_video) | BIT(pmu_idle_video);
+		idle_target = (idle << pmu_idle_ack_video) |
+			      (idle << pmu_idle_video);
+		break;
+	case bus_ide_req_hevc:
+		idle_mask = BIT(pmu_idle_ack_hevc) | BIT(pmu_idle_hevc);
+		idle_target = (idle << pmu_idle_ack_hevc) |
+			      (idle << pmu_idle_hevc);
+		break;
+	case bus_ide_req_vio:
+		idle_mask = BIT(pmu_idle_ack_vio) | BIT(pmu_idle_vio);
+		idle_target = (pmu_idle_ack_vio) |
+			      (idle << pmu_idle_vio);
+		break;
+	case bus_ide_req_alive:
+		idle_mask = BIT(pmu_idle_ack_alive) | BIT(pmu_idle_alive);
+		idle_target = (idle << pmu_idle_ack_alive) |
+			      (idle << pmu_idle_alive);
+		break;
+	default:
+		ERROR("%s: Unsupported the idle request\n", __func__);
+		break;
+	}
+
+	val = mmio_read_32(PMU_BASE + PMU_BUS_IDE_REQ);
+	if (idle)
+		val |= mask;
+	else
+		val &= ~mask;
+
+	mmio_write_32(PMU_BASE + PMU_BUS_IDE_REQ, val);
+
+	while ((mmio_read_32(PMU_BASE +
+	       PMU_BUS_IDE_ST) & idle_mask) != idle_target) {
+		wait_cnt++;
+		if (!(wait_cnt % MAX_WAIT_CONUT))
+			WARN("%s:st=%x(%x)\n", __func__,
+			     mmio_read_32(PMU_BASE + PMU_BUS_IDE_ST),
+			     idle_mask);
+	}
+
+	return 0;
+}
+
+static bool rk3288_sleep_disable_osc(void)
+{
+	static const uint32_t reg_offset[] = { GRF_UOC0_CON0, GRF_UOC1_CON0,
+					       GRF_UOC2_CON0 };
+	uint32_t reg, i;
+
+	/*
+	 * if any usb phy is still on(GRF_SIDDQ==0), that means we need the
+	 * function of usb wakeup, so do not switch to 32khz, since the usb phy
+	 * clk does not connect to 32khz osc
+	 */
+	for (i = 0; i < ARRAY_SIZE(reg_offset); i++) {
+		reg = mmio_read_32(GRF_BASE + reg_offset[i]);
+		if (!(reg & GRF_SIDDQ))
+			return false;
+	}
+
+	return true;
+}
+
+static void pmu_set_sleep_mode(int level)
+{
+	uint32_t mode_set, mode_set1;
+	bool osc_disable = rk3288_sleep_disable_osc();
+
+	mode_set = BIT(pmu_mode_glb_int_dis) | BIT(pmu_mode_l2_flush_en) |
+		   BIT(pmu_mode_sref0_enter) | BIT(pmu_mode_sref1_enter) |
+		   BIT(pmu_mode_ddrc0_gt) | BIT(pmu_mode_ddrc1_gt) |
+		   BIT(pmu_mode_en) | BIT(pmu_mode_chip_pd) |
+		   BIT(pmu_mode_scu_pd);
+
+	mode_set1 = BIT(pmu_mode_clr_core) | BIT(pmu_mode_clr_cpup);
+
+	if (level == ROCKCHIP_ARM_OFF_LOGIC_DEEP) {
+		/* arm off, logic deep sleep */
+		mode_set |= BIT(pmu_mode_bus_pd) | BIT(pmu_mode_pmu_use_lf) |
+			    BIT(pmu_mode_ddrio1_ret) |
+			    BIT(pmu_mode_ddrio0_ret) |
+			    BIT(pmu_mode_pmu_alive_use_lf) |
+			    BIT(pmu_mode_pll_pd);
+
+		if (osc_disable)
+			mode_set |= BIT(pmu_mode_osc_dis);
+
+		mode_set1 |= BIT(pmu_mode_clr_alive) | BIT(pmu_mode_clr_bus) |
+			     BIT(pmu_mode_clr_peri) | BIT(pmu_mode_clr_dma);
+
+		mmio_write_32(PMU_BASE + PMU_WAKEUP_CFG1,
+			      pmu_armint_wakeup_en);
+
+		/*
+		 * In deep suspend we use PMU_PMU_USE_LF to let the rk3288
+		 * switch its main clock supply to the alternative 32kHz
+		 * source. Therefore set 30ms on a 32kHz clock for pmic
+		 * stabilization. Similar 30ms on 24MHz for the other
+		 * mode below.
+		 */
+		mmio_write_32(PMU_BASE + PMU_STABL_CNT, 32 * 30);
+
+		/* only wait for stabilization, if we turned the osc off */
+		mmio_write_32(PMU_BASE + PMU_OSC_CNT,
+					 osc_disable ? 32 * 30 : 0);
+	} else {
+		/*
+		 * arm off, logic normal
+		 * if pmu_clk_core_src_gate_en is not set,
+		 * wakeup will be error
+		 */
+		mode_set |= BIT(pmu_mode_core_src_gt);
+
+		mmio_write_32(PMU_BASE + PMU_WAKEUP_CFG1,
+			      BIT(pmu_armint_wakeup_en) |
+			      BIT(pmu_gpioint_wakeup_en));
+
+		/* 30ms on a 24MHz clock for pmic stabilization */
+		mmio_write_32(PMU_BASE + PMU_STABL_CNT, 24000 * 30);
+
+		/* oscillator is still running, so no need to wait */
+		mmio_write_32(PMU_BASE + PMU_OSC_CNT, 0);
+	}
+
+	mmio_write_32(PMU_BASE + PMU_PWRMODE_CON, mode_set);
+	mmio_write_32(PMU_BASE + PMU_PWRMODE_CON1, mode_set1);
+}
+
+static int cpus_power_domain_on(uint32_t cpu_id)
+{
+	uint32_t cpu_pd;
+
+	cpu_pd = PD_CPU0 + cpu_id;
+
+	/* if the core has been on, power it off first */
+	if (pmu_power_domain_st(cpu_pd) == pmu_pd_on) {
+		/* put core in reset - some sort of A12/A17 bug */
+		mmio_write_32(CRU_BASE + CRU_SOFTRSTS_CON(0),
+			      BIT(cpu_id) | (BIT(cpu_id) << 16));
+
+		pmu_power_domain_ctr(cpu_pd, pmu_pd_off);
+	}
+
+	pmu_power_domain_ctr(cpu_pd, pmu_pd_on);
+
+	/* pull core out of reset */
+	mmio_write_32(CRU_BASE + CRU_SOFTRSTS_CON(0), BIT(cpu_id) << 16);
+
+	return 0;
+}
+
+static int cpus_power_domain_off(uint32_t cpu_id)
+{
+	uint32_t cpu_pd = PD_CPU0 + cpu_id;
+
+	if (pmu_power_domain_st(cpu_pd) == pmu_pd_off)
+		return 0;
+
+	if (check_cpu_wfie(cpu_id, CKECK_WFEI_MSK))
+		return -EINVAL;
+
+	/* put core in reset - some sort of A12/A17 bug */
+	mmio_write_32(CRU_BASE + CRU_SOFTRSTS_CON(0),
+		      BIT(cpu_id) | (BIT(cpu_id) << 16));
+
+	pmu_power_domain_ctr(cpu_pd, pmu_pd_off);
+
+	return 0;
+}
+
+static void nonboot_cpus_off(void)
+{
+	uint32_t boot_cpu, cpu;
+
+	boot_cpu = plat_my_core_pos();
+	boot_cpu = MPIDR_AFFLVL0_VAL(read_mpidr());
+
+	/* turn off noboot cpus */
+	for (cpu = 0; cpu < PLATFORM_CORE_COUNT; cpu++) {
+		if (cpu == boot_cpu)
+			continue;
+
+		cpus_power_domain_off(cpu);
+	}
+}
+
+void sram_save(void)
+{
+	/* TODO: support the sdram save for rk3288 SoCs*/
+}
+
+void sram_restore(void)
+{
+	/* TODO: support the sdram restore for rk3288 SoCs */
+}
+
+int rockchip_soc_cores_pwr_dm_on(unsigned long mpidr, uint64_t entrypoint)
+{
+	uint32_t cpu_id = plat_core_pos_by_mpidr(mpidr);
+
+	assert(cpu_id < PLATFORM_CORE_COUNT);
+	assert(cpuson_flags[cpu_id] == 0);
+	cpuson_flags[cpu_id] = PMU_CPU_HOTPLUG;
+	cpuson_entry_point[cpu_id] = entrypoint;
+	dsb();
+
+	cpus_power_domain_on(cpu_id);
+
+	/*
+	 * We communicate with the bootrom to active the cpus other
+	 * than cpu0, after a blob of initialize code, they will
+	 * stay at wfe state, once they are actived, they will check
+	 * the mailbox:
+	 * sram_base_addr + 4: 0xdeadbeaf
+	 * sram_base_addr + 8: start address for pc
+	 * The cpu0 need to wait the other cpus other than cpu0 entering
+	 * the wfe state.The wait time is affected by many aspects.
+	 * (e.g: cpu frequency, bootrom frequency, sram frequency, ...)
+	 */
+	mdelay(1); /* ensure the cpus other than cpu0 to startup */
+
+	/* tell the bootrom mailbox where to start from */
+	mmio_write_32(SRAM_BASE + 8, cpu_warm_boot_addr);
+	mmio_write_32(SRAM_BASE + 4, 0xDEADBEAF);
+	dsb();
+	sev();
+
+	return 0;
+}
+
+int rockchip_soc_cores_pwr_dm_on_finish(void)
+{
+	return 0;
+}
+
+int rockchip_soc_sys_pwr_dm_resume(void)
+{
+	mmio_write_32(PMU_BASE + PMU_PWRMODE_CON, store_pmu_pwrmode_con);
+	mmio_write_32(SGRF_BASE + SGRF_CPU_CON(0),
+		      store_sgrf_cpu_con0 | SGRF_DAPDEVICE_MSK);
+
+	/* disable fastboot mode */
+	mmio_write_32(SGRF_BASE + SGRF_SOC_CON(0),
+		      store_sgrf_soc_con0 | SGRF_FAST_BOOT_DIS);
+
+	secure_watchdog_ungate();
+	clk_gate_con_restore();
+	clk_sel_con_restore();
+	clk_plls_resume();
+
+	secure_gic_init();
+	plat_rockchip_gic_init();
+
+	return 0;
+}
+
+int rockchip_soc_sys_pwr_dm_suspend(void)
+{
+	nonboot_cpus_off();
+
+	store_sgrf_cpu_con0 = mmio_read_32(SGRF_BASE + SGRF_CPU_CON(0));
+	store_sgrf_soc_con0 = mmio_read_32(SGRF_BASE + SGRF_SOC_CON(0));
+	store_pmu_pwrmode_con = mmio_read_32(PMU_BASE + PMU_PWRMODE_CON);
+
+	/* save clk-gates and ungate all for suspend */
+	clk_gate_con_save();
+	clk_gate_con_disable();
+	clk_sel_con_save();
+
+	pmu_set_sleep_mode(ROCKCHIP_ARM_OFF_LOGIC_NORMAL);
+
+	clk_plls_suspend();
+	secure_watchdog_gate();
+
+	/*
+	 * The dapswjdp can not auto reset before resume, that cause it may
+	 * access some illegal address during resume. Let's disable it before
+	 * suspend, and the MASKROM will enable it back.
+	 */
+	mmio_write_32(SGRF_BASE + SGRF_CPU_CON(0), SGRF_DAPDEVICE_MSK);
+
+	/*
+	 * SGRF_FAST_BOOT_EN - system to boot from FAST_BOOT_ADDR
+	 */
+	mmio_write_32(SGRF_BASE + SGRF_SOC_CON(0), SGRF_FAST_BOOT_ENA);
+
+	/* boot-address of resuming system is from this register value */
+	mmio_write_32(SGRF_BASE + SGRF_FAST_BOOT_ADDR,
+		      (uint32_t)&pmu_cpuson_entrypoint);
+
+	/* flush all caches - otherwise we might loose the resume address */
+	dcsw_op_all(DC_OP_CISW);
+
+	return 0;
+}
+
+void rockchip_plat_mmu_svc_mon(void)
+{
+}
+
+void plat_rockchip_pmu_init(void)
+{
+	uint32_t cpu;
+
+	cpu_warm_boot_addr = (uint32_t)platform_cpu_warmboot;
+
+	/* on boot all power-domains are on */
+	for (cpu = 0; cpu < PLATFORM_CORE_COUNT; cpu++)
+		cpuson_flags[cpu] = pmu_pd_on;
+
+	nonboot_cpus_off();
+}
diff --git a/plat/rockchip/rk3288/drivers/pmu/pmu.h b/plat/rockchip/rk3288/drivers/pmu/pmu.h
new file mode 100644
index 0000000..06d5528
--- /dev/null
+++ b/plat/rockchip/rk3288/drivers/pmu/pmu.h
@@ -0,0 +1,151 @@
+/*
+ * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PMU_H
+#define PMU_H
+
+/* Allocate sp reginon in pmusram */
+#define PSRAM_SP_SIZE		0x80
+#define PSRAM_SP_BOTTOM		(PSRAM_SP_TOP - PSRAM_SP_SIZE)
+
+/*****************************************************************************
+ * pmu con,reg
+ *****************************************************************************/
+#define PMU_WAKEUP_CFG0		0x0
+#define PMU_WAKEUP_CFG1		0x4
+#define PMU_PWRDN_CON		0x8
+#define PMU_PWRDN_ST		0xc
+
+#define PMU_PWRMODE_CON		0x18
+#define PMU_BUS_IDE_REQ		0x10
+#define PMU_BUS_IDE_ST		0x14
+
+#define PMU_OSC_CNT		0x20
+#define PMU_PLL_CNT		0x24
+#define PMU_STABL_CNT		0x28
+#define PMU_DDRIO0_PWR_CNT	0x2c
+#define PMU_DDRIO1_PWR_CNT	0x30
+#define PMU_WKUPRST_CNT		0x44
+#define PMU_SFT_CON		0x48
+#define PMU_PWRMODE_CON1	0x90
+
+enum pmu_pdid {
+	PD_CPU0 = 0,
+	PD_CPU1,
+	PD_CPU2,
+	PD_CPU3,
+	PD_BUS = 5,
+	PD_PERI,
+	PD_VIO,
+	PD_VIDEO,
+	PD_GPU,
+	PD_SCU = 11,
+	PD_HEVC = 14,
+	PD_END
+};
+
+enum pmu_bus_ide {
+	bus_ide_req_bus = 0,
+	bus_ide_req_peri,
+	bus_ide_req_gpu,
+	bus_ide_req_video,
+	bus_ide_req_vio,
+	bus_ide_req_core,
+	bus_ide_req_alive,
+	bus_ide_req_dma,
+	bus_ide_req_cpup,
+	bus_ide_req_hevc,
+	bus_ide_req_end
+};
+
+enum pmu_pwrmode {
+	pmu_mode_en = 0,
+	pmu_mode_core_src_gt,
+	pmu_mode_glb_int_dis,
+	pmu_mode_l2_flush_en,
+	pmu_mode_bus_pd,
+	pmu_mode_cpu0_pd,
+	pmu_mode_scu_pd,
+	pmu_mode_pll_pd = 7,
+	pmu_mode_chip_pd,
+	pmu_mode_pwr_off_comb,
+	pmu_mode_pmu_alive_use_lf,
+	pmu_mode_pmu_use_lf,
+	pmu_mode_osc_dis = 12,
+	pmu_mode_input_clamp,
+	pmu_mode_wkup_rst,
+	pmu_mode_sref0_enter,
+	pmu_mode_sref1_enter,
+	pmu_mode_ddrio0_ret,
+	pmu_mode_ddrio1_ret,
+	pmu_mode_ddrc0_gt,
+	pmu_mode_ddrc1_gt,
+	pmu_mode_ddrio0_ret_deq,
+	pmu_mode_ddrio1_ret_deq,
+};
+
+enum pmu_pwrmode1 {
+	pmu_mode_clr_bus = 0,
+	pmu_mode_clr_core,
+	pmu_mode_clr_cpup,
+	pmu_mode_clr_alive,
+	pmu_mode_clr_dma,
+	pmu_mode_clr_peri,
+	pmu_mode_clr_gpu,
+	pmu_mode_clr_video,
+	pmu_mode_clr_hevc,
+	pmu_mode_clr_vio
+};
+
+enum pmu_sft_con {
+	pmu_sft_ddrio0_ret_cfg = 6,
+	pmu_sft_ddrio1_ret_cfg = 9,
+	pmu_sft_l2flsh = 15,
+};
+
+enum pmu_wakeup_cfg1 {
+	pmu_armint_wakeup_en = 0,
+	pmu_gpio_wakeup_negedge,
+	pmu_sdmmc0_wakeup_en,
+	pmu_gpioint_wakeup_en,
+};
+
+enum pmu_bus_idle_st {
+	pmu_idle_bus = 0,
+	pmu_idle_peri,
+	pmu_idle_gpu,
+	pmu_idle_video,
+	pmu_idle_vio,
+	pmu_idle_core,
+	pmu_idle_alive,
+	pmu_idle_dma,
+	pmu_idle_cpup,
+	pmu_idle_hevc,
+	pmu_idle_ack_bus = 16,
+	pmu_idle_ack_peri,
+	pmu_idle_ack_gpu,
+	pmu_idle_ack_video,
+	pmu_idle_ack_vio,
+	pmu_idle_ack_core,
+	pmu_idle_ack_alive,
+	pmu_idle_ack_dma,
+	pmu_idle_ack_cpup,
+	pmu_idle_ack_hevc,
+};
+
+#define CHECK_CPU_WFIE_BASE		(0)
+
+#define clstl_cpu_wfe		-1
+#define clstb_cpu_wfe		-1
+#define CKECK_WFEI_MSK		0
+
+
+#define PD_CTR_LOOP		500
+#define CHK_CPU_LOOP		500
+
+#define MAX_WAIT_CONUT 1000
+
+#endif /* PMU_H */
diff --git a/plat/rockchip/rk3288/drivers/secure/secure.c b/plat/rockchip/rk3288/drivers/secure/secure.c
new file mode 100644
index 0000000..68994e4
--- /dev/null
+++ b/plat/rockchip/rk3288/drivers/secure/secure.c
@@ -0,0 +1,162 @@
+/*
+ * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <drivers/delay_timer.h>
+
+#include <plat_private.h>
+#include <secure.h>
+#include <soc.h>
+
+static void sgrf_ddr_rgn_global_bypass(uint32_t bypass)
+{
+	if (bypass)
+		/* set bypass (non-secure regions) for whole ddr regions */
+		mmio_write_32(SGRF_BASE + SGRF_SOC_CON(21),
+			      SGRF_DDR_RGN_BYPS);
+	else
+		/* cancel bypass for whole ddr regions */
+		mmio_write_32(SGRF_BASE + SGRF_SOC_CON(21),
+			      SGRF_DDR_RGN_NO_BYPS);
+}
+
+/**
+ * There are 8 + 1 regions for DDR secure control:
+ * DDR_RGN_0 ~ DDR_RGN_7: Per DDR_RGNs grain size is 1MB
+ * DDR_RGN_X - the memories of exclude DDR_RGN_0 ~ DDR_RGN_7
+ *
+ * SGRF_SOC_CON6 - start address of RGN_0 + control
+ * SGRF_SOC_CON7 - end address of RGN_0
+ * ...
+ * SGRF_SOC_CON20 - start address of the RGN_7 + control
+ * SGRF_SOC_CON21 - end address of the RGN_7 + RGN_X control
+ *
+ * @rgn - the DDR regions 0 ~ 7 which are can be configured.
+ * The @st and @ed indicate the start and end addresses for which to set
+ * the security, and the unit is byte. When the st_mb == 0, ed_mb == 0, the
+ * address range 0x0 ~ 0xfffff is secure.
+ *
+ * For example, if we would like to set the range [0, 32MB) is security via
+ * DDR_RGN0, then rgn == 0, st_mb == 0, ed_mb == 31.
+ */
+static void sgrf_ddr_rgn_config(uint32_t rgn, uintptr_t st, uintptr_t ed)
+{
+	uintptr_t st_mb, ed_mb;
+
+	assert(rgn <= 7);
+	assert(st < ed);
+
+	/* check aligned 1MB */
+	assert(st % SIZE_M(1) == 0);
+	assert(ed % SIZE_M(1) == 0);
+
+	st_mb = st / SIZE_M(1);
+	ed_mb = ed / SIZE_M(1);
+
+	/* set ddr region addr start */
+	mmio_write_32(SGRF_BASE + SGRF_SOC_CON(6 + (rgn * 2)),
+		      BITS_WITH_WMASK(st_mb, SGRF_DDR_RGN_ADDR_WMSK, 0));
+
+	/* set ddr region addr end */
+	mmio_write_32(SGRF_BASE + SGRF_SOC_CON(6 + (rgn * 2) + 1),
+		      BITS_WITH_WMASK((ed_mb - 1), SGRF_DDR_RGN_ADDR_WMSK, 0));
+
+	/* select region security */
+	mmio_write_32(SGRF_BASE + SGRF_SOC_CON(6 + (rgn * 2)),
+		      SGRF_DDR_RGN_SECURE_SEL);
+
+	/* enable region security */
+	mmio_write_32(SGRF_BASE + SGRF_SOC_CON(6 + (rgn * 2)),
+		      SGRF_DDR_RGN_SECURE_EN);
+}
+
+void secure_watchdog_gate(void)
+{
+	mmio_write_32(SGRF_BASE + SGRF_SOC_CON(0), SGRF_PCLK_WDT_GATE);
+}
+
+void secure_watchdog_ungate(void)
+{
+	mmio_write_32(SGRF_BASE + SGRF_SOC_CON(0), SGRF_PCLK_WDT_UNGATE);
+}
+
+__pmusramfunc void sram_secure_timer_init(void)
+{
+	mmio_write_32(STIMER1_BASE + TIMER_CONTROL_REG, 0);
+
+	mmio_write_32(STIMER1_BASE + TIMER_LOAD_COUNT0, 0xffffffff);
+	mmio_write_32(STIMER1_BASE + TIMER_LOAD_COUNT1, 0xffffffff);
+
+	/* auto reload & enable the timer */
+	mmio_write_32(STIMER1_BASE + TIMER_CONTROL_REG, TIMER_EN);
+}
+
+void secure_gic_init(void)
+{
+	/* (re-)enable non-secure access to the gic*/
+	mmio_write_32(CORE_AXI_BUS_BASE + CORE_AXI_SECURITY0,
+		      AXI_SECURITY0_GIC);
+}
+
+void secure_timer_init(void)
+{
+	mmio_write_32(STIMER1_BASE + TIMER_CONTROL_REG, 0);
+
+	mmio_write_32(STIMER1_BASE + TIMER_LOAD_COUNT0, 0xffffffff);
+	mmio_write_32(STIMER1_BASE + TIMER_LOAD_COUNT1, 0xffffffff);
+
+	/* auto reload & enable the timer */
+	mmio_write_32(STIMER1_BASE + TIMER_CONTROL_REG, TIMER_EN);
+}
+
+void secure_sgrf_init(void)
+{
+	/*
+	 * We use the first sram part to talk to the bootrom,
+	 * so make it secure.
+	 */
+	mmio_write_32(TZPC_BASE + TZPC_R0SIZE, TZPC_SRAM_SECURE_4K(1));
+
+	secure_gic_init();
+
+	/* set all master ip to non-secure */
+	mmio_write_32(SGRF_BASE + SGRF_SOC_CON(2), SGRF_SOC_CON2_MST_NS);
+	mmio_write_32(SGRF_BASE + SGRF_SOC_CON(3), SGRF_SOC_CON3_MST_NS);
+
+	/* setting all configurable ip into non-secure */
+	mmio_write_32(SGRF_BASE + SGRF_SOC_CON(4),
+		      SGRF_SOC_CON4_SECURE_WMSK /*TODO:|SGRF_STIMER_SECURE*/);
+	mmio_write_32(SGRF_BASE + SGRF_SOC_CON(5), SGRF_SOC_CON5_SECURE_WMSK);
+
+	/* secure dma to non-secure */
+	mmio_write_32(TZPC_BASE + TZPC_DECPROT1SET, 0xff);
+	mmio_write_32(TZPC_BASE + TZPC_DECPROT2SET, 0xff);
+	mmio_write_32(SGRF_BASE + SGRF_BUSDMAC_CON(1), 0x3800);
+	dsb();
+
+	/* rst dma1 */
+	mmio_write_32(CRU_BASE + CRU_SOFTRSTS_CON(1),
+		      RST_DMA1_MSK | (RST_DMA1_MSK << 16));
+	/* rst dma2 */
+	mmio_write_32(CRU_BASE + CRU_SOFTRSTS_CON(4),
+		      RST_DMA2_MSK | (RST_DMA2_MSK << 16));
+
+	dsb();
+
+	/* release dma1 rst*/
+	mmio_write_32(CRU_BASE + CRU_SOFTRSTS_CON(1), (RST_DMA1_MSK << 16));
+	/* release dma2 rst*/
+	mmio_write_32(CRU_BASE + CRU_SOFTRSTS_CON(4), (RST_DMA2_MSK << 16));
+}
+
+void secure_sgrf_ddr_rgn_init(void)
+{
+	sgrf_ddr_rgn_config(0, TZRAM_BASE, TZRAM_SIZE);
+	sgrf_ddr_rgn_global_bypass(0);
+}
diff --git a/plat/rockchip/rk3288/drivers/secure/secure.h b/plat/rockchip/rk3288/drivers/secure/secure.h
new file mode 100644
index 0000000..6c0b2b7
--- /dev/null
+++ b/plat/rockchip/rk3288/drivers/secure/secure.h
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef SECURE_H
+#define SECURE_H
+
+/******************************************************************************
+ * TZPC TrustZone controller
+ ******************************************************************************/
+
+#define TZPC_R0SIZE			0x0
+#define TZPC_SRAM_SECURE_4K(n)		((n) > 0x200 ? 0x200 : (n))
+#define TZPC_DECPROT1STAT		0x80c
+#define TZPC_DECPROT1SET		0x810
+#define TZPC_DECPROT1CLR		0x814
+#define TZPC_DECPROT2STAT		0x818
+#define TZPC_DECPROT2SET		0x818
+#define TZPC_DECPROT2CLR		0x820
+
+/**************************************************
+ * sgrf reg, offset
+ **************************************************/
+/*
+ * soc_con0-5 start at 0x0, soc_con6-... start art 0x50
+ * adjusted for the 5 lower registers
+ */
+#define SGRF_SOC_CON(n)			((((n) < 6) ? 0x0 : 0x38) + (n) * 4)
+#define SGRF_BUSDMAC_CON(n)		(0x20 + (n) * 4)
+#define SGRF_CPU_CON(n)			(0x40 + (n) * 4)
+#define SGRF_SOC_STATUS(n)		(0x100 + (n) * 4)
+#define SGRF_FAST_BOOT_ADDR		0x120
+
+/* SGRF_SOC_CON0 */
+#define SGRF_FAST_BOOT_ENA		BIT_WITH_WMSK(8)
+#define SGRF_FAST_BOOT_DIS		WMSK_BIT(8)
+#define SGRF_PCLK_WDT_GATE		BIT_WITH_WMSK(6)
+#define SGRF_PCLK_WDT_UNGATE		WMSK_BIT(6)
+#define SGRF_PCLK_STIMER_GATE		BIT_WITH_WMSK(4)
+
+#define SGRF_SOC_CON2_MST_NS		0xffe0ffe0
+#define SGRF_SOC_CON3_MST_NS		0x003f003f
+
+/* SGRF_SOC_CON4 */
+#define SGRF_SOC_CON4_SECURE_WMSK	0xffff0000
+#define SGRF_DDRC1_SECURE		BIT_WITH_WMSK(12)
+#define SGRF_DDRC0_SECURE		BIT_WITH_WMSK(11)
+#define SGRF_PMUSRAM_SECURE		BIT_WITH_WMSK(8)
+#define SGRF_WDT_SECURE			BIT_WITH_WMSK(7)
+#define SGRF_STIMER_SECURE		BIT_WITH_WMSK(6)
+
+/* SGRF_SOC_CON5 */
+#define SGRF_SLV_SEC_BYPS		BIT_WITH_WMSK(15)
+#define SGRF_SLV_SEC_NO_BYPS		WMSK_BIT(15)
+#define SGRF_SOC_CON5_SECURE_WMSK	0x00ff0000
+
+/* ddr regions in SGRF_SOC_CON6 and following */
+#define SGRF_DDR_RGN_SECURE_SEL		BIT_WITH_WMSK(15)
+#define SGRF_DDR_RGN_SECURE_EN		BIT_WITH_WMSK(14)
+#define SGRF_DDR_RGN_ADDR_WMSK		0x0fff
+
+/* SGRF_SOC_CON21 */
+/* All security of the DDR RGNs are bypassed */
+#define SGRF_DDR_RGN_BYPS		BIT_WITH_WMSK(15)
+#define SGRF_DDR_RGN_NO_BYPS		WMSK_BIT(15)
+
+/* SGRF_CPU_CON0 */
+#define SGRF_DAPDEVICE_ENA		BIT_WITH_WMSK(0)
+#define SGRF_DAPDEVICE_MSK		WMSK_BIT(0)
+
+/*****************************************************************************
+ * core-axi
+ *****************************************************************************/
+#define CORE_AXI_SECURITY0		0x08
+#define AXI_SECURITY0_GIC		BIT(0)
+
+/*****************************************************************************
+ * secure timer
+ *****************************************************************************/
+#define TIMER_LOAD_COUNT0		0x00
+#define TIMER_LOAD_COUNT1		0x04
+#define TIMER_CURRENT_VALUE0		0x08
+#define TIMER_CURRENT_VALUE1		0x0C
+#define TIMER_CONTROL_REG		0x10
+#define TIMER_INTSTATUS			0x18
+
+#define TIMER_EN			0x1
+
+#define STIMER1_BASE			(STIME_BASE + 0x20)
+
+/* export secure operating APIs */
+void secure_watchdog_gate(void);
+void secure_watchdog_ungate(void);
+void secure_gic_init(void);
+void secure_timer_init(void);
+void secure_sgrf_init(void);
+void secure_sgrf_ddr_rgn_init(void);
+__pmusramfunc void sram_secure_timer_init(void);
+
+#endif /* SECURE_H */
diff --git a/plat/rockchip/rk3288/drivers/soc/soc.c b/plat/rockchip/rk3288/drivers/soc/soc.c
new file mode 100644
index 0000000..db90ae4
--- /dev/null
+++ b/plat/rockchip/rk3288/drivers/soc/soc.c
@@ -0,0 +1,215 @@
+/*
+ * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <platform_def.h>
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <lib/mmio.h>
+
+#include <plat_private.h>
+#include <rk3288_def.h>
+#include <soc.h>
+#include <secure.h>
+
+/* sleep data for pll suspend */
+static struct deepsleep_data_s slp_data;
+
+/* Table of regions to map using the MMU. */
+const mmap_region_t plat_rk_mmap[] = {
+	MAP_REGION_FLAT(GIC400_BASE, GIC400_SIZE,
+			MT_DEVICE | MT_RW | MT_SECURE),
+	MAP_REGION_FLAT(STIME_BASE, STIME_SIZE,
+			MT_DEVICE | MT_RW | MT_SECURE),
+	MAP_REGION_FLAT(SGRF_BASE, SGRF_SIZE,
+			MT_DEVICE | MT_RW | MT_SECURE),
+	MAP_REGION_FLAT(TZPC_BASE, TZPC_SIZE,
+			MT_DEVICE | MT_RW | MT_SECURE),
+	MAP_REGION_FLAT(PMUSRAM_BASE, PMUSRAM_SIZE,
+			MT_MEMORY | MT_RW | MT_SECURE),
+	MAP_REGION_FLAT(SRAM_BASE, SRAM_SIZE,
+			MT_DEVICE | MT_RW | MT_SECURE),
+	MAP_REGION_FLAT(PMU_BASE, PMU_SIZE,
+			MT_DEVICE | MT_RW | MT_SECURE),
+	MAP_REGION_FLAT(UART_DBG_BASE, UART_DBG_SIZE,
+			MT_DEVICE | MT_RW | MT_SECURE),
+	MAP_REGION_FLAT(CRU_BASE, CRU_SIZE,
+			MT_DEVICE | MT_RW | MT_SECURE),
+	MAP_REGION_FLAT(GRF_BASE, GRF_SIZE,
+			MT_DEVICE | MT_RW | MT_SECURE),
+	MAP_REGION_FLAT(DDR_PCTL0_BASE, DDR_PCTL0_SIZE,
+			MT_DEVICE | MT_RW | MT_SECURE),
+	MAP_REGION_FLAT(DDR_PHY0_BASE, DDR_PHY0_SIZE,
+			MT_DEVICE | MT_RW | MT_SECURE),
+	MAP_REGION_FLAT(DDR_PCTL1_BASE, DDR_PCTL1_SIZE,
+			MT_DEVICE | MT_RW | MT_SECURE),
+	MAP_REGION_FLAT(DDR_PHY1_BASE, DDR_PHY1_SIZE,
+			MT_DEVICE | MT_RW | MT_SECURE),
+	MAP_REGION_FLAT(SERVICE_BUS_BASE, SERVICE_BUS_SIZE,
+			MT_DEVICE | MT_RW | MT_SECURE),
+	MAP_REGION_FLAT(CORE_AXI_BUS_BASE, CORE_AXI_BUS_SIZE,
+			MT_DEVICE | MT_RW | MT_SECURE),
+	{ 0 }
+};
+
+/* The RockChip power domain tree descriptor */
+const unsigned char rockchip_power_domain_tree_desc[] = {
+	/* No of root nodes */
+	PLATFORM_SYSTEM_COUNT,
+	/* No of children for the root node */
+	PLATFORM_CLUSTER_COUNT,
+	/* No of children for the first cluster node */
+	PLATFORM_CLUSTER0_CORE_COUNT,
+};
+
+void plat_rockchip_soc_init(void)
+{
+	secure_timer_init();
+	secure_sgrf_init();
+	/*
+	 * We cannot enable ddr security at this point, as the kernel
+	 * seems to have an issue with it even living in the same 128MB
+	 * memory block. Only when moving the kernel to the second
+	 * 128MB block does it not conflict, but then we'd loose this
+	 * memory area for use. Late maybe enable
+	 * secure_sgrf_ddr_rgn_init();
+	 */
+}
+
+void regs_update_bits(uintptr_t addr, uint32_t val,
+		      uint32_t mask, uint32_t shift)
+{
+	uint32_t tmp, orig;
+
+	orig = mmio_read_32(addr);
+
+	tmp = orig & ~(mask << shift);
+	tmp |= (val & mask) << shift;
+
+	if (tmp != orig)
+		mmio_write_32(addr, tmp);
+	dsb();
+}
+
+static void pll_save(uint32_t pll_id)
+{
+	uint32_t *pll = slp_data.pll_con[pll_id];
+
+	pll[0] = mmio_read_32(CRU_BASE + PLL_CONS((pll_id), 0));
+	pll[1] = mmio_read_32(CRU_BASE + PLL_CONS((pll_id), 1));
+	pll[2] = mmio_read_32(CRU_BASE + PLL_CONS((pll_id), 2));
+	pll[3] = mmio_read_32(CRU_BASE + PLL_CONS((pll_id), 3));
+}
+
+void clk_plls_suspend(void)
+{
+	pll_save(NPLL_ID);
+	pll_save(CPLL_ID);
+	pll_save(GPLL_ID);
+	pll_save(APLL_ID);
+	slp_data.pll_mode = mmio_read_32(CRU_BASE + PLL_MODE_CON);
+
+	/*
+	 * Switch PLLs other than DPLL (for SDRAM) to slow mode to
+	 * avoid crashes on resume. The Mask ROM on the system will
+	 * put APLL, CPLL, and GPLL into slow mode at resume time
+	 * anyway (which is why we restore them), but we might not
+	 * even make it to the Mask ROM if this isn't done at suspend
+	 * time.
+	 *
+	 * NOTE: only APLL truly matters here, but we'll do them all.
+	 */
+	mmio_write_32(CRU_BASE + PLL_MODE_CON, 0xf3030000);
+}
+
+void clk_plls_resume(void)
+{
+	/* restore pll-modes */
+	mmio_write_32(CRU_BASE + PLL_MODE_CON,
+		      slp_data.pll_mode | REG_SOC_WMSK);
+}
+
+void clk_gate_con_save(void)
+{
+	uint32_t i = 0;
+
+	for (i = 0; i < CRU_CLKGATES_CON_CNT; i++)
+		slp_data.cru_gate_con[i] =
+			mmio_read_32(CRU_BASE + CRU_CLKGATES_CON(i));
+}
+
+void clk_gate_con_disable(void)
+{
+	uint32_t i;
+
+	for (i = 0; i < CRU_CLKGATES_CON_CNT; i++)
+		mmio_write_32(CRU_BASE + CRU_CLKGATES_CON(i), REG_SOC_WMSK);
+}
+
+void clk_gate_con_restore(void)
+{
+	uint32_t i;
+
+	for (i = 0; i < CRU_CLKGATES_CON_CNT; i++)
+		mmio_write_32(CRU_BASE + CRU_CLKGATES_CON(i),
+			      REG_SOC_WMSK | slp_data.cru_gate_con[i]);
+}
+
+void clk_sel_con_save(void)
+{
+	uint32_t i = 0;
+
+	for (i = 0; i < CRU_CLKSELS_CON_CNT; i++)
+		slp_data.cru_sel_con[i] =
+			mmio_read_32(CRU_BASE + CRU_CLKSELS_CON(i));
+}
+
+void clk_sel_con_restore(void)
+{
+	uint32_t i, val;
+
+	for (i = 0; i < CRU_CLKSELS_CON_CNT; i++) {
+		/* fractional dividers don't have write-masks */
+		if ((i >= 7 && i <= 9) ||
+		    (i >= 17 && i <= 20) ||
+		    (i == 23) || (i == 41))
+			val = slp_data.cru_sel_con[i];
+		else
+			val = slp_data.cru_sel_con[i] | REG_SOC_WMSK;
+
+		mmio_write_32(CRU_BASE + CRU_CLKSELS_CON(i), val);
+	}
+}
+
+void __dead2 rockchip_soc_soft_reset(void)
+{
+	uint32_t temp_val;
+
+	/*
+	 * Switch PLLs other than DPLL (for SDRAM) to slow mode to
+	 * avoid crashes on resume. The Mask ROM on the system will
+	 * put APLL, CPLL, and GPLL into slow mode at resume time
+	 * anyway (which is why we restore them), but we might not
+	 * even make it to the Mask ROM if this isn't done at suspend
+	 * time.
+	 *
+	 * NOTE: only APLL truly matters here, but we'll do them all.
+	 */
+	mmio_write_32(CRU_BASE + PLL_MODE_CON, 0xf3030000);
+
+	temp_val = mmio_read_32(CRU_BASE + CRU_GLB_RST_CON);
+	temp_val &= ~PMU_RST_MASK;
+	temp_val |= PMU_RST_BY_SECOND_SFT;
+	mmio_write_32(CRU_BASE + CRU_GLB_RST_CON, temp_val);
+	mmio_write_32(CRU_BASE + CRU_GLB_SRST_SND, 0xeca8);
+
+	/*
+	 * Maybe the HW needs some times to reset the system,
+	 * so we do not hope the core to excute valid codes.
+	 */
+	while (1)
+		;
+}
diff --git a/plat/rockchip/rk3288/drivers/soc/soc.h b/plat/rockchip/rk3288/drivers/soc/soc.h
new file mode 100644
index 0000000..b96c4dc
--- /dev/null
+++ b/plat/rockchip/rk3288/drivers/soc/soc.h
@@ -0,0 +1,110 @@
+/*
+ * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef SOC_H
+#define SOC_H
+
+enum plls_id {
+	APLL_ID = 0,
+	DPLL_ID,
+	CPLL_ID,
+	GPLL_ID,
+	NPLL_ID,
+	END_PLL_ID,
+};
+
+
+#define CYCL_24M_CNT_US(us)	(24 * (us))
+#define CYCL_24M_CNT_MS(ms)	((ms) * CYCL_24M_CNT_US(1000))
+
+/*****************************************************************************
+ * grf regs
+ *****************************************************************************/
+#define GRF_UOC0_CON0		0x320
+#define GRF_UOC1_CON0		0x334
+#define GRF_UOC2_CON0		0x348
+#define GRF_SIDDQ		BIT(13)
+
+/*****************************************************************************
+ * cru reg, offset
+ *****************************************************************************/
+#define CRU_SOFTRST_CON		0x1b8
+#define CRU_SOFTRSTS_CON(n)	(CRU_SOFTRST_CON + ((n) * 4))
+#define CRU_SOFTRSTS_CON_CNT	11
+
+#define RST_DMA1_MSK		0x4
+#define RST_DMA2_MSK		0x1
+
+#define CRU_CLKSEL_CON		0x60
+#define CRU_CLKSELS_CON(i)	(CRU_CLKSEL_CON + ((i) * 4))
+#define CRU_CLKSELS_CON_CNT	42
+
+#define CRU_CLKGATE_CON		0x160
+#define CRU_CLKGATES_CON(i)	(CRU_CLKGATE_CON + ((i) * 4))
+#define CRU_CLKGATES_CON_CNT	18
+
+#define CRU_GLB_SRST_FST	0x1b0
+#define CRU_GLB_SRST_SND	0x1b4
+#define CRU_GLB_RST_CON		0x1f0
+
+#define CRU_CONS_GATEID(i)	(16 * (i))
+#define GATE_ID(reg, bit)	(((reg) * 16) + (bit))
+
+#define PMU_RST_MASK		0x3
+#define PMU_RST_BY_FIRST_SFT	(0 << 2)
+#define PMU_RST_BY_SECOND_SFT	(1 << 2)
+#define PMU_RST_NOT_BY_SFT	(2 << 2)
+
+/***************************************************************************
+ * pll
+ ***************************************************************************/
+#define PLL_CON_COUNT		4
+#define PLL_CONS(id, i)		((id) * 0x10 + ((i) * 4))
+#define PLL_PWR_DN_MSK		BIT(1)
+#define PLL_PWR_DN		REG_WMSK_BITS(1, 1, 0x1)
+#define PLL_PWR_ON		REG_WMSK_BITS(0, 1, 0x1)
+#define PLL_RESET		REG_WMSK_BITS(1, 5, 0x1)
+#define PLL_RESET_RESUME	REG_WMSK_BITS(0, 5, 0x1)
+#define PLL_BYPASS_MSK		BIT(0)
+#define PLL_BYPASS_W_MSK	(PLL_BYPASS_MSK << 16)
+#define PLL_BYPASS		REG_WMSK_BITS(1, 0, 0x1)
+#define PLL_NO_BYPASS		REG_WMSK_BITS(0, 0, 0x1)
+
+#define PLL_MODE_CON		0x50
+
+struct deepsleep_data_s {
+	uint32_t pll_con[END_PLL_ID][PLL_CON_COUNT];
+	uint32_t pll_mode;
+	uint32_t cru_sel_con[CRU_CLKSELS_CON_CNT];
+	uint32_t cru_gate_con[CRU_CLKGATES_CON_CNT];
+};
+
+#define REG_W_MSK(bits_shift, msk) \
+		((msk) << ((bits_shift) + 16))
+#define REG_VAL_CLRBITS(val, bits_shift, msk) \
+		((val) & (~((msk) << bits_shift)))
+#define REG_SET_BITS(bits, bits_shift, msk) \
+		(((bits) & (msk)) << (bits_shift))
+#define REG_WMSK_BITS(bits, bits_shift, msk) \
+		(REG_W_MSK(bits_shift, msk) | \
+		REG_SET_BITS(bits, bits_shift, msk))
+#define REG_SOC_WMSK		0xffff0000
+
+#define regs_update_bit_set(addr, shift) \
+		regs_update_bits((addr), 0x1, 0x1, (shift))
+#define regs_update_bit_clr(addr, shift) \
+		regs_update_bits((addr), 0x0, 0x1, (shift))
+
+void regs_update_bits(uintptr_t addr, uint32_t val,
+		      uint32_t mask, uint32_t shift);
+void clk_plls_suspend(void);
+void clk_plls_resume(void);
+void clk_gate_con_save(void);
+void clk_gate_con_disable(void);
+void clk_gate_con_restore(void);
+void clk_sel_con_save(void);
+void clk_sel_con_restore(void);
+#endif /* SOC_H */