summaryrefslogtreecommitdiffstats
path: root/plat/rockchip/px30/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'plat/rockchip/px30/drivers')
-rw-r--r--plat/rockchip/px30/drivers/pmu/plat_pmu_macros.S21
-rw-r--r--plat/rockchip/px30/drivers/pmu/pmu.c1071
-rw-r--r--plat/rockchip/px30/drivers/pmu/pmu.h331
-rw-r--r--plat/rockchip/px30/drivers/secure/secure.c103
-rw-r--r--plat/rockchip/px30/drivers/secure/secure.h65
-rw-r--r--plat/rockchip/px30/drivers/soc/soc.c134
-rw-r--r--plat/rockchip/px30/drivers/soc/soc.h118
7 files changed, 1843 insertions, 0 deletions
diff --git a/plat/rockchip/px30/drivers/pmu/plat_pmu_macros.S b/plat/rockchip/px30/drivers/pmu/plat_pmu_macros.S
new file mode 100644
index 0000000..a757621
--- /dev/null
+++ b/plat/rockchip/px30/drivers/pmu/plat_pmu_macros.S
@@ -0,0 +1,21 @@
+/*
+ * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <platform_def.h>
+
+.globl clst_warmboot_data
+
+.macro func_rockchip_clst_warmboot
+.endm
+
+.macro rockchip_clst_warmboot_data
+clst_warmboot_data:
+ .rept PLATFORM_CLUSTER_COUNT
+ .word 0
+ .endr
+.endm
diff --git a/plat/rockchip/px30/drivers/pmu/pmu.c b/plat/rockchip/px30/drivers/pmu/pmu.c
new file mode 100644
index 0000000..8770b2e
--- /dev/null
+++ b/plat/rockchip/px30/drivers/pmu/pmu.c
@@ -0,0 +1,1071 @@
+/*
+ * Copyright (c) 2019, 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 <bl31/bl31.h>
+#include <common/debug.h>
+#include <drivers/console.h>
+#include <drivers/delay_timer.h>
+#include <lib/bakery_lock.h>
+#include <lib/mmio.h>
+#include <plat/common/platform.h>
+
+#include <cpus_on_fixed_addr.h>
+#include <plat_private.h>
+#include <pmu.h>
+#include <px30_def.h>
+#include <secure.h>
+#include <soc.h>
+
+DEFINE_BAKERY_LOCK(rockchip_pd_lock);
+#define rockchip_pd_lock_init() bakery_lock_init(&rockchip_pd_lock)
+#define rockchip_pd_lock_get() bakery_lock_get(&rockchip_pd_lock)
+#define rockchip_pd_lock_rls() bakery_lock_release(&rockchip_pd_lock)
+
+static struct psram_data_t *psram_boot_cfg =
+ (struct psram_data_t *)&sys_sleep_flag_sram;
+
+/*
+ * There are two ways to powering on or off on core.
+ * 1) Control it power domain into on or off in PMU_PWRDN_CON reg,
+ * it is core_pwr_pd mode
+ * 2) Enable the core power manage in PMU_CORE_PM_CON reg,
+ * then, if the core enter into wfi, it power domain will be
+ * powered off automatically. it is core_pwr_wfi or core_pwr_wfi_int mode
+ * so we need core_pm_cfg_info to distinguish which method be used now.
+ */
+
+static uint32_t cores_pd_cfg_info[PLATFORM_CORE_COUNT]
+#if USE_COHERENT_MEM
+__attribute__ ((section(".tzfw_coherent_mem")))
+#endif
+;
+
+struct px30_sleep_ddr_data {
+ uint32_t clk_sel0;
+ uint32_t cru_mode_save;
+ uint32_t cru_pmu_mode_save;
+ uint32_t ddrc_hwlpctl;
+ uint32_t ddrc_pwrctrl;
+ uint32_t ddrgrf_con0;
+ uint32_t ddrgrf_con1;
+ uint32_t ddrstdby_con0;
+ uint32_t gpio0b_iomux;
+ uint32_t gpio0c_iomux;
+ uint32_t pmu_pwrmd_core_l;
+ uint32_t pmu_pwrmd_core_h;
+ uint32_t pmu_pwrmd_cmm_l;
+ uint32_t pmu_pwrmd_cmm_h;
+ uint32_t pmu_wkup_cfg2_l;
+ uint32_t pmu_cru_clksel_con0;
+ uint32_t pmugrf_soc_con0;
+ uint32_t pmusgrf_soc_con0;
+ uint32_t pmic_slp_iomux;
+ uint32_t pgrf_pvtm_con[2];
+ uint32_t cru_clk_gate[CRU_CLKGATES_CON_CNT];
+ uint32_t cru_pmu_clk_gate[CRU_PMU_CLKGATE_CON_CNT];
+ uint32_t cru_plls_con_save[END_PLL_ID][PLL_CON_CNT];
+ uint32_t cpu_qos[CPU_AXI_QOS_NUM_REGS];
+ uint32_t gpu_qos[CPU_AXI_QOS_NUM_REGS];
+ uint32_t isp_128m_qos[CPU_AXI_QOS_NUM_REGS];
+ uint32_t isp_rd_qos[CPU_AXI_QOS_NUM_REGS];
+ uint32_t isp_wr_qos[CPU_AXI_QOS_NUM_REGS];
+ uint32_t isp_m1_qos[CPU_AXI_QOS_NUM_REGS];
+ uint32_t vip_qos[CPU_AXI_QOS_NUM_REGS];
+ uint32_t rga_rd_qos[CPU_AXI_QOS_NUM_REGS];
+ uint32_t rga_wr_qos[CPU_AXI_QOS_NUM_REGS];
+ uint32_t vop_m0_qos[CPU_AXI_QOS_NUM_REGS];
+ uint32_t vop_m1_qos[CPU_AXI_QOS_NUM_REGS];
+ uint32_t vpu_qos[CPU_AXI_QOS_NUM_REGS];
+ uint32_t vpu_r128_qos[CPU_AXI_QOS_NUM_REGS];
+ uint32_t dcf_qos[CPU_AXI_QOS_NUM_REGS];
+ uint32_t dmac_qos[CPU_AXI_QOS_NUM_REGS];
+ uint32_t crypto_qos[CPU_AXI_QOS_NUM_REGS];
+ uint32_t gmac_qos[CPU_AXI_QOS_NUM_REGS];
+ uint32_t emmc_qos[CPU_AXI_QOS_NUM_REGS];
+ uint32_t nand_qos[CPU_AXI_QOS_NUM_REGS];
+ uint32_t sdio_qos[CPU_AXI_QOS_NUM_REGS];
+ uint32_t sfc_qos[CPU_AXI_QOS_NUM_REGS];
+ uint32_t sdmmc_qos[CPU_AXI_QOS_NUM_REGS];
+ uint32_t usb_host_qos[CPU_AXI_QOS_NUM_REGS];
+ uint32_t usb_otg_qos[CPU_AXI_QOS_NUM_REGS];
+};
+
+static struct px30_sleep_ddr_data ddr_data
+#if USE_COHERENT_MEM
+__attribute__ ((section(".tzfw_coherent_mem")))
+#endif
+;
+
+static inline uint32_t get_cpus_pwr_domain_cfg_info(uint32_t cpu_id)
+{
+ assert(cpu_id < PLATFORM_CORE_COUNT);
+ return cores_pd_cfg_info[cpu_id];
+}
+
+static inline void set_cpus_pwr_domain_cfg_info(uint32_t cpu_id, uint32_t value)
+{
+ assert(cpu_id < PLATFORM_CORE_COUNT);
+ cores_pd_cfg_info[cpu_id] = value;
+#if !USE_COHERENT_MEM
+ flush_dcache_range((uintptr_t)&cores_pd_cfg_info[cpu_id],
+ sizeof(uint32_t));
+#endif
+}
+
+static inline uint32_t pmu_power_domain_st(uint32_t pd)
+{
+ return mmio_read_32(PMU_BASE + PMU_PWRDN_ST) & BIT(pd) ?
+ pmu_pd_off :
+ pmu_pd_on;
+}
+
+static int pmu_power_domain_ctr(uint32_t pd, uint32_t pd_state)
+{
+ uint32_t loop = 0;
+ int ret = 0;
+
+ rockchip_pd_lock_get();
+
+ mmio_write_32(PMU_BASE + PMU_PWRDN_CON,
+ BITS_WITH_WMASK(pd_state, 0x1, pd));
+ dsb();
+
+ while ((pmu_power_domain_st(pd) != pd_state) && (loop < PD_CTR_LOOP)) {
+ udelay(1);
+ loop++;
+ }
+
+ if (pmu_power_domain_st(pd) != pd_state) {
+ WARN("%s: %d, %d, error!\n", __func__, pd, pd_state);
+ ret = -EINVAL;
+ }
+
+ rockchip_pd_lock_rls();
+
+ return ret;
+}
+
+static inline uint32_t pmu_bus_idle_st(uint32_t bus)
+{
+ return !!((mmio_read_32(PMU_BASE + PMU_BUS_IDLE_ST) & BIT(bus)) &&
+ (mmio_read_32(PMU_BASE + PMU_BUS_IDLE_ST) & BIT(bus + 16)));
+}
+
+static void pmu_bus_idle_req(uint32_t bus, uint32_t state)
+{
+ uint32_t wait_cnt = 0;
+
+ mmio_write_32(PMU_BASE + PMU_BUS_IDLE_REQ,
+ BITS_WITH_WMASK(state, 0x1, bus));
+
+ while (pmu_bus_idle_st(bus) != state &&
+ wait_cnt < BUS_IDLE_LOOP) {
+ udelay(1);
+ wait_cnt++;
+ }
+
+ if (pmu_bus_idle_st(bus) != state)
+ WARN("%s:idle_st=0x%x, bus_id=%d\n",
+ __func__, mmio_read_32(PMU_BASE + PMU_BUS_IDLE_ST), bus);
+}
+
+static void qos_save(void)
+{
+ /* scu powerdomain will power off, so cpu qos should be saved */
+ SAVE_QOS(ddr_data.cpu_qos, CPU);
+
+ if (pmu_power_domain_st(PD_GPU) == pmu_pd_on)
+ SAVE_QOS(ddr_data.gpu_qos, GPU);
+ if (pmu_power_domain_st(PD_VI) == pmu_pd_on) {
+ SAVE_QOS(ddr_data.isp_128m_qos, ISP_128M);
+ SAVE_QOS(ddr_data.isp_rd_qos, ISP_RD);
+ SAVE_QOS(ddr_data.isp_wr_qos, ISP_WR);
+ SAVE_QOS(ddr_data.isp_m1_qos, ISP_M1);
+ SAVE_QOS(ddr_data.vip_qos, VIP);
+ }
+ if (pmu_power_domain_st(PD_VO) == pmu_pd_on) {
+ SAVE_QOS(ddr_data.rga_rd_qos, RGA_RD);
+ SAVE_QOS(ddr_data.rga_wr_qos, RGA_WR);
+ SAVE_QOS(ddr_data.vop_m0_qos, VOP_M0);
+ SAVE_QOS(ddr_data.vop_m1_qos, VOP_M1);
+ }
+ if (pmu_power_domain_st(PD_VPU) == pmu_pd_on) {
+ SAVE_QOS(ddr_data.vpu_qos, VPU);
+ SAVE_QOS(ddr_data.vpu_r128_qos, VPU_R128);
+ }
+ if (pmu_power_domain_st(PD_MMC_NAND) == pmu_pd_on) {
+ SAVE_QOS(ddr_data.emmc_qos, EMMC);
+ SAVE_QOS(ddr_data.nand_qos, NAND);
+ SAVE_QOS(ddr_data.sdio_qos, SDIO);
+ SAVE_QOS(ddr_data.sfc_qos, SFC);
+ }
+ if (pmu_power_domain_st(PD_GMAC) == pmu_pd_on)
+ SAVE_QOS(ddr_data.gmac_qos, GMAC);
+ if (pmu_power_domain_st(PD_CRYPTO) == pmu_pd_on)
+ SAVE_QOS(ddr_data.crypto_qos, CRYPTO);
+ if (pmu_power_domain_st(PD_SDCARD) == pmu_pd_on)
+ SAVE_QOS(ddr_data.sdmmc_qos, SDMMC);
+ if (pmu_power_domain_st(PD_USB) == pmu_pd_on) {
+ SAVE_QOS(ddr_data.usb_host_qos, USB_HOST);
+ SAVE_QOS(ddr_data.usb_otg_qos, USB_OTG);
+ }
+}
+
+static void qos_restore(void)
+{
+ RESTORE_QOS(ddr_data.cpu_qos, CPU);
+
+ if (pmu_power_domain_st(PD_GPU) == pmu_pd_on)
+ RESTORE_QOS(ddr_data.gpu_qos, GPU);
+ if (pmu_power_domain_st(PD_VI) == pmu_pd_on) {
+ RESTORE_QOS(ddr_data.isp_128m_qos, ISP_128M);
+ RESTORE_QOS(ddr_data.isp_rd_qos, ISP_RD);
+ RESTORE_QOS(ddr_data.isp_wr_qos, ISP_WR);
+ RESTORE_QOS(ddr_data.isp_m1_qos, ISP_M1);
+ RESTORE_QOS(ddr_data.vip_qos, VIP);
+ }
+ if (pmu_power_domain_st(PD_VO) == pmu_pd_on) {
+ RESTORE_QOS(ddr_data.rga_rd_qos, RGA_RD);
+ RESTORE_QOS(ddr_data.rga_wr_qos, RGA_WR);
+ RESTORE_QOS(ddr_data.vop_m0_qos, VOP_M0);
+ RESTORE_QOS(ddr_data.vop_m1_qos, VOP_M1);
+ }
+ if (pmu_power_domain_st(PD_VPU) == pmu_pd_on) {
+ RESTORE_QOS(ddr_data.vpu_qos, VPU);
+ RESTORE_QOS(ddr_data.vpu_r128_qos, VPU_R128);
+ }
+ if (pmu_power_domain_st(PD_MMC_NAND) == pmu_pd_on) {
+ RESTORE_QOS(ddr_data.emmc_qos, EMMC);
+ RESTORE_QOS(ddr_data.nand_qos, NAND);
+ RESTORE_QOS(ddr_data.sdio_qos, SDIO);
+ RESTORE_QOS(ddr_data.sfc_qos, SFC);
+ }
+ if (pmu_power_domain_st(PD_GMAC) == pmu_pd_on)
+ RESTORE_QOS(ddr_data.gmac_qos, GMAC);
+ if (pmu_power_domain_st(PD_CRYPTO) == pmu_pd_on)
+ RESTORE_QOS(ddr_data.crypto_qos, CRYPTO);
+ if (pmu_power_domain_st(PD_SDCARD) == pmu_pd_on)
+ RESTORE_QOS(ddr_data.sdmmc_qos, SDMMC);
+ if (pmu_power_domain_st(PD_USB) == pmu_pd_on) {
+ RESTORE_QOS(ddr_data.usb_host_qos, USB_HOST);
+ RESTORE_QOS(ddr_data.usb_otg_qos, USB_OTG);
+ }
+}
+
+static int pmu_set_power_domain(uint32_t pd_id, uint32_t pd_state)
+{
+ uint32_t state;
+
+ if (pmu_power_domain_st(pd_id) == pd_state)
+ goto out;
+
+ if (pd_state == pmu_pd_on)
+ pmu_power_domain_ctr(pd_id, pd_state);
+
+ state = (pd_state == pmu_pd_off) ? bus_idle : bus_active;
+
+ switch (pd_id) {
+ case PD_GPU:
+ pmu_bus_idle_req(BUS_ID_GPU, state);
+ break;
+ case PD_VI:
+ pmu_bus_idle_req(BUS_ID_VI, state);
+ break;
+ case PD_VO:
+ pmu_bus_idle_req(BUS_ID_VO, state);
+ break;
+ case PD_VPU:
+ pmu_bus_idle_req(BUS_ID_VPU, state);
+ break;
+ case PD_MMC_NAND:
+ pmu_bus_idle_req(BUS_ID_MMC, state);
+ break;
+ case PD_GMAC:
+ pmu_bus_idle_req(BUS_ID_GMAC, state);
+ break;
+ case PD_CRYPTO:
+ pmu_bus_idle_req(BUS_ID_CRYPTO, state);
+ break;
+ case PD_SDCARD:
+ pmu_bus_idle_req(BUS_ID_SDCARD, state);
+ break;
+ case PD_USB:
+ pmu_bus_idle_req(BUS_ID_USB, state);
+ break;
+ default:
+ break;
+ }
+
+ if (pd_state == pmu_pd_off)
+ pmu_power_domain_ctr(pd_id, pd_state);
+
+out:
+ return 0;
+}
+
+static uint32_t pmu_powerdomain_state;
+
+static void pmu_power_domains_suspend(void)
+{
+ uint32_t clkgt_save[CRU_CLKGATES_CON_CNT + CRU_PMU_CLKGATE_CON_CNT];
+
+ clk_gate_con_save(clkgt_save);
+ clk_gate_con_disable();
+ qos_save();
+
+ pmu_powerdomain_state = mmio_read_32(PMU_BASE + PMU_PWRDN_ST);
+ pmu_set_power_domain(PD_GPU, pmu_pd_off);
+ pmu_set_power_domain(PD_VI, pmu_pd_off);
+ pmu_set_power_domain(PD_VO, pmu_pd_off);
+ pmu_set_power_domain(PD_VPU, pmu_pd_off);
+ pmu_set_power_domain(PD_MMC_NAND, pmu_pd_off);
+ pmu_set_power_domain(PD_GMAC, pmu_pd_off);
+ pmu_set_power_domain(PD_CRYPTO, pmu_pd_off);
+ pmu_set_power_domain(PD_SDCARD, pmu_pd_off);
+ pmu_set_power_domain(PD_USB, pmu_pd_off);
+
+ clk_gate_con_restore(clkgt_save);
+}
+
+static void pmu_power_domains_resume(void)
+{
+ uint32_t clkgt_save[CRU_CLKGATES_CON_CNT + CRU_PMU_CLKGATE_CON_CNT];
+
+ clk_gate_con_save(clkgt_save);
+ clk_gate_con_disable();
+
+ if (!(pmu_powerdomain_state & BIT(PD_USB)))
+ pmu_set_power_domain(PD_USB, pmu_pd_on);
+ if (!(pmu_powerdomain_state & BIT(PD_SDCARD)))
+ pmu_set_power_domain(PD_SDCARD, pmu_pd_on);
+ if (!(pmu_powerdomain_state & BIT(PD_CRYPTO)))
+ pmu_set_power_domain(PD_CRYPTO, pmu_pd_on);
+ if (!(pmu_powerdomain_state & BIT(PD_GMAC)))
+ pmu_set_power_domain(PD_GMAC, pmu_pd_on);
+ if (!(pmu_powerdomain_state & BIT(PD_MMC_NAND)))
+ pmu_set_power_domain(PD_MMC_NAND, pmu_pd_on);
+ if (!(pmu_powerdomain_state & BIT(PD_VPU)))
+ pmu_set_power_domain(PD_VPU, pmu_pd_on);
+ if (!(pmu_powerdomain_state & BIT(PD_VO)))
+ pmu_set_power_domain(PD_VO, pmu_pd_on);
+ if (!(pmu_powerdomain_state & BIT(PD_VI)))
+ pmu_set_power_domain(PD_VI, pmu_pd_on);
+ if (!(pmu_powerdomain_state & BIT(PD_GPU)))
+ pmu_set_power_domain(PD_GPU, pmu_pd_on);
+
+ qos_restore();
+ clk_gate_con_restore(clkgt_save);
+}
+
+static int check_cpu_wfie(uint32_t cpu)
+{
+ uint32_t loop = 0, wfie_msk = CKECK_WFEI_MSK << cpu;
+
+ while (!(mmio_read_32(GRF_BASE + GRF_CPU_STATUS1) & wfie_msk) &&
+ (loop < WFEI_CHECK_LOOP)) {
+ udelay(1);
+ loop++;
+ }
+
+ if ((mmio_read_32(GRF_BASE + GRF_CPU_STATUS1) & wfie_msk) == 0) {
+ WARN("%s: %d, %d, error!\n", __func__, cpu, wfie_msk);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int cpus_power_domain_on(uint32_t cpu_id)
+{
+ uint32_t cpu_pd, apm_value, cfg_info, loop = 0;
+
+ cpu_pd = PD_CPU0 + cpu_id;
+ cfg_info = get_cpus_pwr_domain_cfg_info(cpu_id);
+
+ if (cfg_info == core_pwr_pd) {
+ /* disable apm cfg */
+ mmio_write_32(PMU_BASE + PMU_CPUAPM_CON(cpu_id),
+ WITH_16BITS_WMSK(CORES_PM_DISABLE));
+ if (pmu_power_domain_st(cpu_pd) == pmu_pd_on) {
+ mmio_write_32(PMU_BASE + PMU_CPUAPM_CON(cpu_id),
+ WITH_16BITS_WMSK(CORES_PM_DISABLE));
+ pmu_power_domain_ctr(cpu_pd, pmu_pd_off);
+ }
+ pmu_power_domain_ctr(cpu_pd, pmu_pd_on);
+ } else {
+ /* wait cpu down */
+ while (pmu_power_domain_st(cpu_pd) == pmu_pd_on && loop < 100) {
+ udelay(2);
+ loop++;
+ }
+
+ /* return error if can't wait cpu down */
+ if (pmu_power_domain_st(cpu_pd) == pmu_pd_on) {
+ WARN("%s:can't wait cpu down\n", __func__);
+ return -EINVAL;
+ }
+
+ /* power up cpu in power down state */
+ apm_value = BIT(core_pm_sft_wakeup_en);
+ mmio_write_32(PMU_BASE + PMU_CPUAPM_CON(cpu_id),
+ WITH_16BITS_WMSK(apm_value));
+ }
+
+ return 0;
+}
+
+static int cpus_power_domain_off(uint32_t cpu_id, uint32_t pd_cfg)
+{
+ uint32_t cpu_pd, apm_value;
+
+ cpu_pd = PD_CPU0 + cpu_id;
+ if (pmu_power_domain_st(cpu_pd) == pmu_pd_off)
+ return 0;
+
+ if (pd_cfg == core_pwr_pd) {
+ if (check_cpu_wfie(cpu_id))
+ return -EINVAL;
+ /* disable apm cfg */
+ mmio_write_32(PMU_BASE + PMU_CPUAPM_CON(cpu_id),
+ WITH_16BITS_WMSK(CORES_PM_DISABLE));
+ set_cpus_pwr_domain_cfg_info(cpu_id, pd_cfg);
+ pmu_power_domain_ctr(cpu_pd, pmu_pd_off);
+ } else {
+ set_cpus_pwr_domain_cfg_info(cpu_id, pd_cfg);
+ apm_value = BIT(core_pm_en) | BIT(core_pm_dis_int);
+ if (pd_cfg == core_pwr_wfi_int)
+ apm_value |= BIT(core_pm_int_wakeup_en);
+ mmio_write_32(PMU_BASE + PMU_CPUAPM_CON(cpu_id),
+ WITH_16BITS_WMSK(apm_value));
+ }
+
+ return 0;
+}
+
+static void nonboot_cpus_off(void)
+{
+ uint32_t boot_cpu, cpu;
+
+ boot_cpu = plat_my_core_pos();
+
+ for (cpu = 0; cpu < PLATFORM_CORE_COUNT; cpu++) {
+ if (cpu == boot_cpu)
+ continue;
+ cpus_power_domain_off(cpu, core_pwr_pd);
+ }
+}
+
+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);
+
+ return PSCI_E_SUCCESS;
+}
+
+int rockchip_soc_cores_pwr_dm_on_finish(void)
+{
+ uint32_t cpu_id = plat_my_core_pos();
+
+ mmio_write_32(PMU_BASE + PMU_CPUAPM_CON(cpu_id),
+ WITH_16BITS_WMSK(CORES_PM_DISABLE));
+ return PSCI_E_SUCCESS;
+}
+
+int rockchip_soc_cores_pwr_dm_off(void)
+{
+ uint32_t cpu_id = plat_my_core_pos();
+
+ cpus_power_domain_off(cpu_id, core_pwr_wfi);
+
+ return PSCI_E_SUCCESS;
+}
+
+int rockchip_soc_cores_pwr_dm_suspend(void)
+{
+ uint32_t cpu_id = plat_my_core_pos();
+
+ assert(cpu_id < PLATFORM_CORE_COUNT);
+ assert(cpuson_flags[cpu_id] == 0);
+ cpuson_flags[cpu_id] = PMU_CPU_AUTO_PWRDN;
+ cpuson_entry_point[cpu_id] = plat_get_sec_entrypoint();
+ dsb();
+
+ cpus_power_domain_off(cpu_id, core_pwr_wfi_int);
+
+ return PSCI_E_SUCCESS;
+}
+
+int rockchip_soc_cores_pwr_dm_resume(void)
+{
+ uint32_t cpu_id = plat_my_core_pos();
+
+ /* Disable core_pm */
+ mmio_write_32(PMU_BASE + PMU_CPUAPM_CON(cpu_id),
+ WITH_16BITS_WMSK(CORES_PM_DISABLE));
+
+ return PSCI_E_SUCCESS;
+}
+
+#define CLK_MSK_GATING(msk, con) \
+ mmio_write_32(CRU_BASE + (con), ((msk) << 16) | 0xffff)
+#define CLK_MSK_UNGATING(msk, con) \
+ mmio_write_32(CRU_BASE + (con), ((~(msk)) << 16) | 0xffff)
+
+static uint32_t clk_ungt_msk[CRU_CLKGATES_CON_CNT] = {
+ 0xe0ff, 0xffff, 0x0000, 0x0000,
+ 0x0000, 0x0380, 0x0000, 0x0000,
+ 0x07c0, 0x0000, 0x0000, 0x000f,
+ 0x0061, 0x1f02, 0x0440, 0x1801,
+ 0x004b, 0x0000
+};
+
+static uint32_t clk_pmu_ungt_msk[CRU_PMU_CLKGATE_CON_CNT] = {
+ 0xf1ff, 0x0310
+};
+
+void clk_gate_suspend(void)
+{
+ int i;
+
+ for (i = 0; i < CRU_CLKGATES_CON_CNT; i++) {
+ ddr_data.cru_clk_gate[i] =
+ mmio_read_32(CRU_BASE + CRU_CLKGATES_CON(i));
+ mmio_write_32(CRU_BASE + CRU_CLKGATES_CON(i),
+ WITH_16BITS_WMSK(~clk_ungt_msk[i]));
+ }
+
+ for (i = 0; i < CRU_PMU_CLKGATE_CON_CNT; i++) {
+ ddr_data.cru_pmu_clk_gate[i] =
+ mmio_read_32(PMUCRU_BASE + CRU_PMU_CLKGATES_CON(i));
+ mmio_write_32(PMUCRU_BASE + CRU_PMU_CLKGATES_CON(i),
+ WITH_16BITS_WMSK(~clk_pmu_ungt_msk[i]));
+ }
+}
+
+void clk_gate_resume(void)
+{
+ int i;
+
+ for (i = 0; i < CRU_PMU_CLKGATE_CON_CNT; i++)
+ mmio_write_32(PMUCRU_BASE + CRU_PMU_CLKGATES_CON(i),
+ WITH_16BITS_WMSK(ddr_data.cru_pmu_clk_gate[i]));
+
+ for (i = 0; i < CRU_CLKGATES_CON_CNT; i++)
+ mmio_write_32(CRU_BASE + CRU_CLKGATES_CON(i),
+ WITH_16BITS_WMSK(ddr_data.cru_clk_gate[i]));
+}
+
+static void pvtm_32k_config(void)
+{
+ uint32_t pvtm_freq_khz, pvtm_div;
+
+ ddr_data.pmu_cru_clksel_con0 =
+ mmio_read_32(PMUCRU_BASE + CRU_PMU_CLKSELS_CON(0));
+
+ ddr_data.pgrf_pvtm_con[0] =
+ mmio_read_32(PMUGRF_BASE + PMUGRF_PVTM_CON0);
+ ddr_data.pgrf_pvtm_con[1] =
+ mmio_read_32(PMUGRF_BASE + PMUGRF_PVTM_CON1);
+
+ mmio_write_32(PMUGRF_BASE + PMUGRF_PVTM_CON0,
+ BITS_WITH_WMASK(0, 0x3, pgrf_pvtm_st));
+ dsb();
+ mmio_write_32(PMUGRF_BASE + PMUGRF_PVTM_CON0,
+ BITS_WITH_WMASK(1, 0x1, pgrf_pvtm_en));
+ dsb();
+ mmio_write_32(PMUGRF_BASE + PMUGRF_PVTM_CON1, PVTM_CALC_CNT);
+ dsb();
+
+ mmio_write_32(PMUGRF_BASE + PMUGRF_PVTM_CON0,
+ BITS_WITH_WMASK(1, 0x1, pgrf_pvtm_st));
+
+ /* pmugrf_pvtm_st0 will be clear after PVTM start,
+ * which will cost about 6 cycles of pvtm at least.
+ * So we wait 30 cycles of pvtm for security.
+ */
+ while (mmio_read_32(PMUGRF_BASE + PMUGRF_PVTM_ST1) < 30)
+ ;
+
+ dsb();
+ while (!(mmio_read_32(PMUGRF_BASE + PMUGRF_PVTM_ST0) & 0x1))
+ ;
+
+ pvtm_freq_khz =
+ (mmio_read_32(PMUGRF_BASE + PMUGRF_PVTM_ST1) * 24000 +
+ PVTM_CALC_CNT / 2) / PVTM_CALC_CNT;
+ pvtm_div = (pvtm_freq_khz + 16) / 32;
+
+ /* pvtm_div = div_factor << 2 + 1,
+ * so div_factor = (pvtm_div - 1) >> 2.
+ * But the operation ">> 2" will clear the low bit of pvtm_div,
+ * so we don't have to do "- 1" for compasation
+ */
+ pvtm_div = pvtm_div >> 2;
+ if (pvtm_div > 0x3f)
+ pvtm_div = 0x3f;
+
+ mmio_write_32(PMUGRF_BASE + PMUGRF_PVTM_CON0,
+ BITS_WITH_WMASK(pvtm_div, 0x3f, pgrf_pvtm_div));
+
+ /* select pvtm as 32k source */
+ mmio_write_32(PMUCRU_BASE + CRU_PMU_CLKSELS_CON(0),
+ BITS_WITH_WMASK(1, 0x3U, 14));
+}
+
+static void pvtm_32k_config_restore(void)
+{
+ mmio_write_32(PMUCRU_BASE + CRU_PMU_CLKSELS_CON(0),
+ ddr_data.pmu_cru_clksel_con0 | BITS_WMSK(0x3U, 14));
+
+ mmio_write_32(PMUGRF_BASE + PMUGRF_PVTM_CON0,
+ WITH_16BITS_WMSK(ddr_data.pgrf_pvtm_con[0]));
+ mmio_write_32(PMUGRF_BASE + PMUGRF_PVTM_CON1,
+ ddr_data.pgrf_pvtm_con[1]);
+}
+
+static void ddr_sleep_config(void)
+{
+ /* disable ddr pd, sr */
+ ddr_data.ddrc_pwrctrl = mmio_read_32(DDR_UPCTL_BASE + 0x30);
+ mmio_write_32(DDR_UPCTL_BASE + 0x30, BITS_WITH_WMASK(0x0, 0x3, 0));
+
+ /* disable ddr auto gt */
+ ddr_data.ddrgrf_con1 = mmio_read_32(DDRGRF_BASE + 0x4);
+ mmio_write_32(DDRGRF_BASE + 0x4, BITS_WITH_WMASK(0x0, 0x1f, 0));
+
+ /* disable ddr standby */
+ ddr_data.ddrstdby_con0 = mmio_read_32(DDR_STDBY_BASE + 0x0);
+ mmio_write_32(DDR_STDBY_BASE + 0x0, BITS_WITH_WMASK(0x0, 0x1, 0));
+ while ((mmio_read_32(DDR_UPCTL_BASE + 0x4) & 0x7) != 1)
+ ;
+
+ /* ddr pmu ctrl */
+ ddr_data.ddrgrf_con0 = mmio_read_32(DDRGRF_BASE + 0x0);
+ mmio_write_32(DDRGRF_BASE + 0x0, BITS_WITH_WMASK(0x0, 0x1, 5));
+ dsb();
+ mmio_write_32(DDRGRF_BASE + 0x0, BITS_WITH_WMASK(0x1, 0x1, 4));
+
+ /* ddr ret sel */
+ ddr_data.pmugrf_soc_con0 =
+ mmio_read_32(PMUGRF_BASE + PMUGRF_SOC_CON(0));
+ mmio_write_32(PMUGRF_BASE + PMUGRF_SOC_CON(0),
+ BITS_WITH_WMASK(0x0, 0x1, 12));
+}
+
+static void ddr_sleep_config_restore(void)
+{
+ /* restore ddr ret sel */
+ mmio_write_32(PMUGRF_BASE + PMUGRF_SOC_CON(0),
+ ddr_data.pmugrf_soc_con0 | BITS_WMSK(0x1, 12));
+
+ /* restore ddr pmu ctrl */
+ mmio_write_32(DDRGRF_BASE + 0x0,
+ ddr_data.ddrgrf_con0 | BITS_WMSK(0x1, 4));
+ dsb();
+ mmio_write_32(DDRGRF_BASE + 0x0,
+ ddr_data.ddrgrf_con0 | BITS_WMSK(0x1, 5));
+
+ /* restore ddr standby */
+ mmio_write_32(DDR_STDBY_BASE + 0x0,
+ ddr_data.ddrstdby_con0 | BITS_WMSK(0x1, 0));
+
+ /* restore ddr auto gt */
+ mmio_write_32(DDRGRF_BASE + 0x4,
+ ddr_data.ddrgrf_con1 | BITS_WMSK(0x1f, 0));
+
+ /* restore ddr pd, sr */
+ mmio_write_32(DDR_UPCTL_BASE + 0x30,
+ ddr_data.ddrc_pwrctrl | BITS_WMSK(0x3, 0));
+}
+
+static void pmu_sleep_config(void)
+{
+ uint32_t pwrmd_core_lo, pwrmd_core_hi, pwrmd_com_lo, pwrmd_com_hi;
+ uint32_t pmu_wkup_cfg2_lo;
+ uint32_t clk_freq_khz;
+
+ /* save pmic_sleep iomux gpio0_a4 */
+ ddr_data.pmic_slp_iomux = mmio_read_32(PMUGRF_BASE + GPIO0A_IOMUX);
+
+ ddr_data.pmu_pwrmd_core_l =
+ mmio_read_32(PMU_BASE + PMU_PWRMODE_CORE_LO);
+ ddr_data.pmu_pwrmd_core_h =
+ mmio_read_32(PMU_BASE + PMU_PWRMODE_CORE_HI);
+ ddr_data.pmu_pwrmd_cmm_l =
+ mmio_read_32(PMU_BASE + PMU_PWRMODE_COMMON_CON_LO);
+ ddr_data.pmu_pwrmd_cmm_h =
+ mmio_read_32(PMU_BASE + PMU_PWRMODE_COMMON_CON_HI);
+ ddr_data.pmu_wkup_cfg2_l = mmio_read_32(PMU_BASE + PMU_WKUP_CFG2_LO);
+
+ pwrmd_core_lo = BIT(pmu_global_int_dis) |
+ BIT(pmu_core_src_gt) |
+ BIT(pmu_cpu0_pd) |
+ BIT(pmu_clr_core) |
+ BIT(pmu_scu_pd) |
+ BIT(pmu_l2_idle) |
+ BIT(pmu_l2_flush) |
+ BIT(pmu_clr_bus2main) |
+ BIT(pmu_clr_peri2msch);
+
+ pwrmd_core_hi = BIT(pmu_dpll_pd_en) |
+ BIT(pmu_apll_pd_en) |
+ BIT(pmu_cpll_pd_en) |
+ BIT(pmu_gpll_pd_en) |
+ BIT(pmu_npll_pd_en);
+
+ pwrmd_com_lo = BIT(pmu_mode_en) |
+ BIT(pmu_pll_pd) |
+ BIT(pmu_pmu_use_if) |
+ BIT(pmu_alive_use_if) |
+ BIT(pmu_osc_dis) |
+ BIT(pmu_sref_enter) |
+ BIT(pmu_ddrc_gt) |
+ BIT(pmu_clr_pmu) |
+ BIT(pmu_clr_peri_pmu);
+
+ pwrmd_com_hi = BIT(pmu_clr_bus) |
+ BIT(pmu_clr_msch) |
+ BIT(pmu_wakeup_begin_cfg);
+
+ pmu_wkup_cfg2_lo = BIT(pmu_cluster_wkup_en) |
+ BIT(pmu_gpio_wkup_en) |
+ BIT(pmu_timer_wkup_en);
+
+ /* set pmic_sleep iomux gpio0_a4 */
+ mmio_write_32(PMUGRF_BASE + GPIO0A_IOMUX,
+ BITS_WITH_WMASK(1, 0x3, 8));
+
+ clk_freq_khz = 32;
+
+ mmio_write_32(PMU_BASE + PMU_OSC_CNT_LO,
+ WITH_16BITS_WMSK(clk_freq_khz * 32 & 0xffff));
+ mmio_write_32(PMU_BASE + PMU_OSC_CNT_HI,
+ WITH_16BITS_WMSK(clk_freq_khz * 32 >> 16));
+
+ mmio_write_32(PMU_BASE + PMU_STABLE_CNT_LO,
+ WITH_16BITS_WMSK(clk_freq_khz * 32 & 0xffff));
+ mmio_write_32(PMU_BASE + PMU_STABLE_CNT_HI,
+ WITH_16BITS_WMSK(clk_freq_khz * 32 >> 16));
+
+ mmio_write_32(PMU_BASE + PMU_WAKEUP_RST_CLR_LO,
+ WITH_16BITS_WMSK(clk_freq_khz * 2 & 0xffff));
+ mmio_write_32(PMU_BASE + PMU_WAKEUP_RST_CLR_HI,
+ WITH_16BITS_WMSK(clk_freq_khz * 2 >> 16));
+
+ /* Pmu's clk has switched to 24M back When pmu FSM counts
+ * the follow counters, so we should use 24M to calculate
+ * these counters.
+ */
+ mmio_write_32(PMU_BASE + PMU_SCU_PWRDN_CNT_LO,
+ WITH_16BITS_WMSK(24000 * 2 & 0xffff));
+ mmio_write_32(PMU_BASE + PMU_SCU_PWRDN_CNT_HI,
+ WITH_16BITS_WMSK(24000 * 2 >> 16));
+
+ mmio_write_32(PMU_BASE + PMU_SCU_PWRUP_CNT_LO,
+ WITH_16BITS_WMSK(24000 * 2 & 0xffff));
+ mmio_write_32(PMU_BASE + PMU_SCU_PWRUP_CNT_HI,
+ WITH_16BITS_WMSK(24000 * 2 >> 16));
+
+ mmio_write_32(PMU_BASE + PMU_PLLLOCK_CNT_LO,
+ WITH_16BITS_WMSK(24000 * 5 & 0xffff));
+ mmio_write_32(PMU_BASE + PMU_PLLLOCK_CNT_HI,
+ WITH_16BITS_WMSK(24000 * 5 >> 16));
+
+ mmio_write_32(PMU_BASE + PMU_PLLRST_CNT_LO,
+ WITH_16BITS_WMSK(24000 * 2 & 0xffff));
+ mmio_write_32(PMU_BASE + PMU_PLLRST_CNT_HI,
+ WITH_16BITS_WMSK(24000 * 2 >> 16));
+
+ /* Config pmu power mode and pmu wakeup source */
+ mmio_write_32(PMU_BASE + PMU_PWRMODE_CORE_LO,
+ WITH_16BITS_WMSK(pwrmd_core_lo));
+ mmio_write_32(PMU_BASE + PMU_PWRMODE_CORE_HI,
+ WITH_16BITS_WMSK(pwrmd_core_hi));
+
+ mmio_write_32(PMU_BASE + PMU_PWRMODE_COMMON_CON_LO,
+ WITH_16BITS_WMSK(pwrmd_com_lo));
+ mmio_write_32(PMU_BASE + PMU_PWRMODE_COMMON_CON_HI,
+ WITH_16BITS_WMSK(pwrmd_com_hi));
+
+ mmio_write_32(PMU_BASE + PMU_WKUP_CFG2_LO,
+ WITH_16BITS_WMSK(pmu_wkup_cfg2_lo));
+}
+
+static void pmu_sleep_restore(void)
+{
+ mmio_write_32(PMU_BASE + PMU_PWRMODE_CORE_LO,
+ WITH_16BITS_WMSK(ddr_data.pmu_pwrmd_core_l));
+ mmio_write_32(PMU_BASE + PMU_PWRMODE_CORE_HI,
+ WITH_16BITS_WMSK(ddr_data.pmu_pwrmd_core_h));
+ mmio_write_32(PMU_BASE + PMU_PWRMODE_COMMON_CON_LO,
+ WITH_16BITS_WMSK(ddr_data.pmu_pwrmd_cmm_l));
+ mmio_write_32(PMU_BASE + PMU_PWRMODE_COMMON_CON_HI,
+ WITH_16BITS_WMSK(ddr_data.pmu_pwrmd_cmm_h));
+ mmio_write_32(PMU_BASE + PMU_WKUP_CFG2_LO,
+ WITH_16BITS_WMSK(ddr_data.pmu_wkup_cfg2_l));
+
+ /* restore pmic_sleep iomux */
+ mmio_write_32(PMUGRF_BASE + GPIO0A_IOMUX,
+ WITH_16BITS_WMSK(ddr_data.pmic_slp_iomux));
+}
+
+static void soc_sleep_config(void)
+{
+ ddr_data.gpio0c_iomux = mmio_read_32(PMUGRF_BASE + GPIO0C_IOMUX);
+
+ pmu_sleep_config();
+
+ ddr_sleep_config();
+
+ pvtm_32k_config();
+}
+
+static void soc_sleep_restore(void)
+{
+ secure_timer_init();
+
+ pvtm_32k_config_restore();
+
+ ddr_sleep_config_restore();
+
+ pmu_sleep_restore();
+
+ mmio_write_32(PMUGRF_BASE + GPIO0C_IOMUX,
+ WITH_16BITS_WMSK(ddr_data.gpio0c_iomux));
+}
+
+static inline void pm_pll_wait_lock(uint32_t pll_base, uint32_t pll_id)
+{
+ uint32_t delay = PLL_LOCKED_TIMEOUT;
+
+ while (delay > 0) {
+ if (mmio_read_32(pll_base + PLL_CON(1)) &
+ PLL_LOCK_MSK)
+ break;
+ delay--;
+ }
+
+ if (delay == 0)
+ ERROR("Can't wait pll:%d lock\n", pll_id);
+}
+
+static inline void pll_pwr_ctr(uint32_t pll_base, uint32_t pll_id, uint32_t pd)
+{
+ mmio_write_32(pll_base + PLL_CON(1),
+ BITS_WITH_WMASK(1, 1U, 15));
+ if (pd)
+ mmio_write_32(pll_base + PLL_CON(1),
+ BITS_WITH_WMASK(1, 1, 14));
+ else
+ mmio_write_32(pll_base + PLL_CON(1),
+ BITS_WITH_WMASK(0, 1, 14));
+}
+
+static inline void pll_set_mode(uint32_t pll_id, uint32_t mode)
+{
+ uint32_t val = BITS_WITH_WMASK(mode, 0x3, PLL_MODE_SHIFT(pll_id));
+
+ if (pll_id != GPLL_ID)
+ mmio_write_32(CRU_BASE + CRU_MODE, val);
+ else
+ mmio_write_32(PMUCRU_BASE + CRU_PMU_MODE,
+ BITS_WITH_WMASK(mode, 0x3, 0));
+}
+
+static inline void pll_suspend(uint32_t pll_id)
+{
+ int i;
+ uint32_t pll_base;
+
+ if (pll_id != GPLL_ID)
+ pll_base = CRU_BASE + CRU_PLL_CONS(pll_id, 0);
+ else
+ pll_base = PMUCRU_BASE + CRU_PLL_CONS(0, 0);
+
+ /* save pll con */
+ for (i = 0; i < PLL_CON_CNT; i++)
+ ddr_data.cru_plls_con_save[pll_id][i] =
+ mmio_read_32(pll_base + PLL_CON(i));
+
+ /* slow mode */
+ pll_set_mode(pll_id, SLOW_MODE);
+}
+
+static inline void pll_resume(uint32_t pll_id)
+{
+ uint32_t mode, pll_base;
+
+ if (pll_id != GPLL_ID) {
+ pll_base = CRU_BASE + CRU_PLL_CONS(pll_id, 0);
+ mode = (ddr_data.cru_mode_save >> PLL_MODE_SHIFT(pll_id)) & 0x3;
+ } else {
+ pll_base = PMUCRU_BASE + CRU_PLL_CONS(0, 0);
+ mode = ddr_data.cru_pmu_mode_save & 0x3;
+ }
+
+ /* if pll locked before suspend, we should wait atfer resume */
+ if (ddr_data.cru_plls_con_save[pll_id][1] & PLL_LOCK_MSK)
+ pm_pll_wait_lock(pll_base, pll_id);
+
+ pll_set_mode(pll_id, mode);
+}
+
+static void pm_plls_suspend(void)
+{
+ ddr_data.cru_mode_save = mmio_read_32(CRU_BASE + CRU_MODE);
+ ddr_data.cru_pmu_mode_save = mmio_read_32(PMUCRU_BASE + CRU_PMU_MODE);
+ ddr_data.clk_sel0 = mmio_read_32(CRU_BASE + CRU_CLKSELS_CON(0));
+
+ pll_suspend(GPLL_ID);
+ pll_suspend(NPLL_ID);
+ pll_suspend(CPLL_ID);
+ pll_suspend(APLL_ID);
+
+ /* core */
+ mmio_write_32(CRU_BASE + CRU_CLKSELS_CON(0),
+ BITS_WITH_WMASK(0, 0xf, 0));
+
+ /* pclk_dbg */
+ mmio_write_32(CRU_BASE + CRU_CLKSELS_CON(0),
+ BITS_WITH_WMASK(0, 0xf, 8));
+}
+
+static void pm_plls_resume(void)
+{
+ /* pclk_dbg */
+ mmio_write_32(CRU_BASE + CRU_CLKSELS_CON(0),
+ ddr_data.clk_sel0 | BITS_WMSK(0xf, 8));
+
+ /* core */
+ mmio_write_32(CRU_BASE + CRU_CLKSELS_CON(0),
+ ddr_data.clk_sel0 | BITS_WMSK(0xf, 0));
+
+ pll_resume(APLL_ID);
+ pll_resume(CPLL_ID);
+ pll_resume(NPLL_ID);
+ pll_resume(GPLL_ID);
+}
+
+int rockchip_soc_sys_pwr_dm_suspend(void)
+{
+ pmu_power_domains_suspend();
+
+ clk_gate_suspend();
+
+ soc_sleep_config();
+
+ pm_plls_suspend();
+
+ psram_boot_cfg->pm_flag &= ~PM_WARM_BOOT_BIT;
+
+ return 0;
+}
+
+int rockchip_soc_sys_pwr_dm_resume(void)
+{
+ psram_boot_cfg->pm_flag |= PM_WARM_BOOT_BIT;
+
+ pm_plls_resume();
+
+ soc_sleep_restore();
+
+ clk_gate_resume();
+
+ pmu_power_domains_resume();
+
+ plat_rockchip_gic_cpuif_enable();
+
+ return 0;
+}
+
+void __dead2 rockchip_soc_soft_reset(void)
+{
+ pll_set_mode(GPLL_ID, SLOW_MODE);
+ pll_set_mode(CPLL_ID, SLOW_MODE);
+ pll_set_mode(NPLL_ID, SLOW_MODE);
+ pll_set_mode(APLL_ID, SLOW_MODE);
+ dsb();
+
+ mmio_write_32(CRU_BASE + CRU_GLB_SRST_FST, CRU_GLB_SRST_FST_VALUE);
+ dsb();
+
+ /*
+ * Maybe the HW needs some times to reset the system,
+ * so we do not hope the core to execute valid codes.
+ */
+ psci_power_down_wfi();
+}
+
+void __dead2 rockchip_soc_system_off(void)
+{
+ uint32_t val;
+
+ /* set pmic_sleep pin(gpio0_a4) to gpio mode */
+ mmio_write_32(PMUGRF_BASE + GPIO0A_IOMUX, BITS_WITH_WMASK(0, 0x3, 8));
+
+ /* config output */
+ val = mmio_read_32(GPIO0_BASE + SWPORTA_DDR);
+ val |= BIT(4);
+ mmio_write_32(GPIO0_BASE + SWPORTA_DDR, val);
+
+ /* config output high level */
+ val = mmio_read_32(GPIO0_BASE);
+ val |= BIT(4);
+ mmio_write_32(GPIO0_BASE, val);
+ dsb();
+
+ /*
+ * Maybe the HW needs some times to reset the system,
+ * so we do not hope the core to execute valid codes.
+ */
+ psci_power_down_wfi();
+}
+
+void rockchip_plat_mmu_el3(void)
+{
+ /* TODO: support the el3 for px30 SoCs */
+}
+
+void plat_rockchip_pmu_init(void)
+{
+ uint32_t cpu;
+
+ rockchip_pd_lock_init();
+
+ for (cpu = 0; cpu < PLATFORM_CORE_COUNT; cpu++)
+ cpuson_flags[cpu] = 0;
+
+ psram_boot_cfg->ddr_func = (uint64_t)0;
+ psram_boot_cfg->ddr_data = (uint64_t)0;
+ psram_boot_cfg->sp = PSRAM_SP_TOP;
+ psram_boot_cfg->ddr_flag = 0x0;
+ psram_boot_cfg->boot_mpidr = read_mpidr_el1() & 0xffff;
+ psram_boot_cfg->pm_flag = PM_WARM_BOOT_BIT;
+
+ nonboot_cpus_off();
+
+ /* Remap pmu_sram's base address to boot address */
+ mmio_write_32(PMUSGRF_BASE + PMUSGRF_SOC_CON(0),
+ BITS_WITH_WMASK(1, 0x1, 13));
+
+ INFO("%s: pd status %x\n",
+ __func__, mmio_read_32(PMU_BASE + PMU_PWRDN_ST));
+}
diff --git a/plat/rockchip/px30/drivers/pmu/pmu.h b/plat/rockchip/px30/drivers/pmu/pmu.h
new file mode 100644
index 0000000..416d1c1
--- /dev/null
+++ b/plat/rockchip/px30/drivers/pmu/pmu.h
@@ -0,0 +1,331 @@
+/*
+ * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef __PMU_H__
+#define __PMU_H__
+
+/* Needed aligned 16 bytes for sp stack top */
+#define PSRAM_SP_TOP ((PMUSRAM_BASE + PMUSRAM_RSIZE) & ~0xf)
+
+/*****************************************************************************
+ * pmu con,reg
+ *****************************************************************************/
+#define PMU_WKUP_CFG0_LO 0x00
+#define PMU_WKUP_CFG0_HI 0x04
+#define PMU_WKUP_CFG1_LO 0x08
+#define PMU_WKUP_CFG1_HI 0x0c
+#define PMU_WKUP_CFG2_LO 0x10
+
+#define PMU_PWRDN_CON 0x18
+#define PMU_PWRDN_ST 0x20
+
+#define PMU_PWRMODE_CORE_LO 0x24
+#define PMU_PWRMODE_CORE_HI 0x28
+#define PMU_PWRMODE_COMMON_CON_LO 0x2c
+#define PMU_PWRMODE_COMMON_CON_HI 0x30
+
+#define PMU_SFT_CON 0x34
+#define PMU_INT_ST 0x44
+#define PMU_BUS_IDLE_REQ 0x64
+#define PMU_BUS_IDLE_ST 0x6c
+
+#define PMU_OSC_CNT_LO 0x74
+#define PMU_OSC_CNT_HI 0x78
+#define PMU_PLLLOCK_CNT_LO 0x7c
+#define PMU_PLLLOCK_CNT_HI 0x80
+#define PMU_PLLRST_CNT_LO 0x84
+#define PMU_PLLRST_CNT_HI 0x88
+#define PMU_STABLE_CNT_LO 0x8c
+#define PMU_STABLE_CNT_HI 0x90
+#define PMU_WAKEUP_RST_CLR_LO 0x9c
+#define PMU_WAKEUP_RST_CLR_HI 0xa0
+
+#define PMU_DDR_SREF_ST 0xa4
+
+#define PMU_SYS_REG0_LO 0xa8
+#define PMU_SYS_REG0_HI 0xac
+#define PMU_SYS_REG1_LO 0xb0
+#define PMU_SYS_REG1_HI 0xb4
+#define PMU_SYS_REG2_LO 0xb8
+#define PMU_SYS_REG2_HI 0xbc
+#define PMU_SYS_REG3_LO 0xc0
+#define PMU_SYS_REG3_HI 0xc4
+
+#define PMU_SCU_PWRDN_CNT_LO 0xc8
+#define PMU_SCU_PWRDN_CNT_HI 0xcc
+#define PMU_SCU_PWRUP_CNT_LO 0xd0
+#define PMU_SCU_PWRUP_CNT_HI 0xd4
+
+#define PMU_TIMEOUT_CNT_LO 0xd8
+#define PMU_TIMEOUT_CNT_HI 0xdc
+
+#define PMU_CPUAPM_CON(cpu) (0xe0 + (cpu) * 0x4)
+
+#define CORES_PM_DISABLE 0x0
+#define CLST_CPUS_MSK 0xf
+
+#define PD_CTR_LOOP 500
+#define PD_CHECK_LOOP 500
+#define WFEI_CHECK_LOOP 500
+#define BUS_IDLE_LOOP 1000
+
+enum pmu_wkup_cfg2 {
+ pmu_cluster_wkup_en = 0,
+ pmu_gpio_wkup_en = 2,
+ pmu_sdio_wkup_en = 3,
+ pmu_sdmmc_wkup_en = 4,
+ pmu_uart0_wkup_en = 5,
+ pmu_timer_wkup_en = 6,
+ pmu_usbdev_wkup_en = 7,
+ pmu_sft_wkup_en = 8,
+ pmu_timeout_wkup_en = 10,
+};
+
+enum pmu_powermode_core_lo {
+ pmu_global_int_dis = 0,
+ pmu_core_src_gt = 1,
+ pmu_cpu0_pd = 3,
+ pmu_clr_core = 5,
+ pmu_scu_pd = 6,
+ pmu_l2_idle = 8,
+ pmu_l2_flush = 9,
+ pmu_clr_bus2main = 10,
+ pmu_clr_peri2msch = 11,
+};
+
+enum pmu_powermode_core_hi {
+ pmu_apll_pd_en = 3,
+ pmu_dpll_pd_en = 4,
+ pmu_cpll_pd_en = 5,
+ pmu_gpll_pd_en = 6,
+ pmu_npll_pd_en = 7,
+};
+
+enum pmu_powermode_common_lo {
+ pmu_mode_en = 0,
+ pmu_ddr_pd_en = 1,
+ pmu_wkup_rst = 3,
+ pmu_pll_pd = 4,
+ pmu_pmu_use_if = 6,
+ pmu_alive_use_if = 7,
+ pmu_osc_dis = 8,
+ pmu_input_clamp = 9,
+ pmu_sref_enter = 10,
+ pmu_ddrc_gt = 11,
+ pmu_ddrio_ret = 12,
+ pmu_ddrio_ret_deq = 13,
+ pmu_clr_pmu = 14,
+ pmu_clr_peri_pmu = 15,
+};
+
+enum pmu_powermode_common_hi {
+ pmu_clr_bus = 0,
+ pmu_clr_mmc = 1,
+ pmu_clr_msch = 2,
+ pmu_clr_nandc = 3,
+ pmu_clr_gmac = 4,
+ pmu_clr_vo = 5,
+ pmu_clr_vi = 6,
+ pmu_clr_gpu = 7,
+ pmu_clr_usb = 8,
+ pmu_clr_vpu = 9,
+ pmu_clr_crypto = 10,
+ pmu_wakeup_begin_cfg = 11,
+ pmu_peri_clk_src_gt = 12,
+ pmu_bus_clk_src_gt = 13,
+};
+
+enum pmu_pd_id {
+ PD_CPU0 = 0,
+ PD_CPU1 = 1,
+ PD_CPU2 = 2,
+ PD_CPU3 = 3,
+ PD_SCU = 4,
+ PD_USB = 5,
+ PD_DDR = 6,
+ PD_SDCARD = 8,
+ PD_CRYPTO = 9,
+ PD_GMAC = 10,
+ PD_MMC_NAND = 11,
+ PD_VPU = 12,
+ PD_VO = 13,
+ PD_VI = 14,
+ PD_GPU = 15,
+ PD_END = 16,
+};
+
+enum pmu_bus_id {
+ BUS_ID_BUS = 0,
+ BUS_ID_BUS2MAIN = 1,
+ BUS_ID_GPU = 2,
+ BUS_ID_CORE = 3,
+ BUS_ID_CRYPTO = 4,
+ BUS_ID_MMC = 5,
+ BUS_ID_GMAC = 6,
+ BUS_ID_VO = 7,
+ BUS_ID_VI = 8,
+ BUS_ID_SDCARD = 9,
+ BUS_ID_USB = 10,
+ BUS_ID_MSCH = 11,
+ BUS_ID_PERI = 12,
+ BUS_ID_PMU = 13,
+ BUS_ID_VPU = 14,
+ BUS_ID_PERI2MSCH = 15,
+};
+
+enum pmu_pd_state {
+ pmu_pd_on = 0,
+ pmu_pd_off = 1
+};
+
+enum pmu_bus_state {
+ bus_active = 0,
+ bus_idle = 1,
+};
+
+enum cores_pm_ctr_mode {
+ core_pwr_pd = 0,
+ core_pwr_wfi = 1,
+ core_pwr_wfi_int = 2
+};
+
+enum pmu_cores_pm_by_wfi {
+ core_pm_en = 0,
+ core_pm_int_wakeup_en,
+ core_pm_dis_int,
+ core_pm_sft_wakeup_en
+};
+
+/*****************************************************************************
+ * pmu_sgrf
+ *****************************************************************************/
+#define PMUSGRF_SOC_CON(i) ((i) * 0x4)
+
+/*****************************************************************************
+ * pmu_grf
+ *****************************************************************************/
+#define GPIO0A_IOMUX 0x0
+#define GPIO0B_IOMUX 0x4
+#define GPIO0C_IOMUX 0x8
+#define GPIO0A_PULL 0x10
+
+#define GPIO0L_SMT 0x38
+#define GPIO0H_SMT 0x3c
+
+#define PMUGRF_SOC_CON(i) (0x100 + (i) * 4)
+
+#define PMUGRF_PVTM_CON0 0x180
+#define PMUGRF_PVTM_CON1 0x184
+#define PMUGRF_PVTM_ST0 0x190
+#define PMUGRF_PVTM_ST1 0x194
+
+#define PVTM_CALC_CNT 0x200
+
+#define PMUGRF_OS_REG(n) (0x200 + (n) * 4)
+
+#define GPIO0A6_IOMUX_MSK (0x3 << 12)
+#define GPIO0A6_IOMUX_GPIO (0x0 << 12)
+#define GPIO0A6_IOMUX_RSTOUT (0x1 << 12)
+#define GPIO0A6_IOMUX_SHTDN (0x2 << 12)
+
+enum px30_pmugrf_pvtm_con0 {
+ pgrf_pvtm_st = 0,
+ pgrf_pvtm_en = 1,
+ pgrf_pvtm_div = 2,
+};
+
+/*****************************************************************************
+ * pmu_cru
+ *****************************************************************************/
+#define CRU_PMU_MODE 0x20
+#define CRU_PMU_CLKSEL_CON 0x40
+#define CRU_PMU_CLKSELS_CON(i) (CRU_PMU_CLKSEL_CON + (i) * 4)
+#define CRU_PMU_CLKSEL_CON_CNT 5
+#define CRU_PMU_CLKGATE_CON 0x80
+#define CRU_PMU_CLKGATES_CON(i) (CRU_PMU_CLKGATE_CON + (i) * 4)
+#define CRU_PMU_CLKGATE_CON_CNT 2
+#define CRU_PMU_ATCS_CON 0xc0
+#define CRU_PMU_ATCSS_CON(i) (CRU_PMU_ATCS_CON + (i) * 4)
+#define CRU_PMU_ATCS_CON_CNT 2
+
+/*****************************************************************************
+ * pmusgrf
+ *****************************************************************************/
+#define PMUSGRF_RSTOUT_EN (0x7 << 10)
+#define PMUSGRF_RSTOUT_FST 10
+#define PMUSGRF_RSTOUT_TSADC 11
+#define PMUSGRF_RSTOUT_WDT 12
+
+#define PMUGRF_SOC_CON2_US_WMSK (0x1fff << 16)
+#define PMUGRF_SOC_CON2_MAX_341US 0x1fff
+#define PMUGRF_SOC_CON2_200US 0x12c0
+
+#define PMUGRF_FAILSAFE_SHTDN_TSADC BIT(0)
+#define PMUGRF_FAILSAFE_SHTDN_WDT BIT(1)
+
+/*****************************************************************************
+ * QOS
+ *****************************************************************************/
+#define CPU_AXI_QOS_ID_COREID 0x00
+#define CPU_AXI_QOS_REVISIONID 0x04
+#define CPU_AXI_QOS_PRIORITY 0x08
+#define CPU_AXI_QOS_MODE 0x0c
+#define CPU_AXI_QOS_BANDWIDTH 0x10
+#define CPU_AXI_QOS_SATURATION 0x14
+#define CPU_AXI_QOS_EXTCONTROL 0x18
+#define CPU_AXI_QOS_NUM_REGS 0x07
+
+#define CPU_AXI_CPU_QOS_BASE 0xff508000
+#define CPU_AXI_GPU_QOS_BASE 0xff520000
+#define CPU_AXI_ISP_128M_QOS_BASE 0xff548000
+#define CPU_AXI_ISP_RD_QOS_BASE 0xff548080
+#define CPU_AXI_ISP_WR_QOS_BASE 0xff548100
+#define CPU_AXI_ISP_M1_QOS_BASE 0xff548180
+#define CPU_AXI_VIP_QOS_BASE 0xff548200
+#define CPU_AXI_RGA_RD_QOS_BASE 0xff550000
+#define CPU_AXI_RGA_WR_QOS_BASE 0xff550080
+#define CPU_AXI_VOP_M0_QOS_BASE 0xff550100
+#define CPU_AXI_VOP_M1_QOS_BASE 0xff550180
+#define CPU_AXI_VPU_QOS_BASE 0xff558000
+#define CPU_AXI_VPU_R128_QOS_BASE 0xff558080
+#define CPU_AXI_DCF_QOS_BASE 0xff500000
+#define CPU_AXI_DMAC_QOS_BASE 0xff500080
+#define CPU_AXI_CRYPTO_QOS_BASE 0xff510000
+#define CPU_AXI_GMAC_QOS_BASE 0xff518000
+#define CPU_AXI_EMMC_QOS_BASE 0xff538000
+#define CPU_AXI_NAND_QOS_BASE 0xff538080
+#define CPU_AXI_SDIO_QOS_BASE 0xff538100
+#define CPU_AXI_SFC_QOS_BASE 0xff538180
+#define CPU_AXI_SDMMC_QOS_BASE 0xff52c000
+#define CPU_AXI_USB_HOST_QOS_BASE 0xff540000
+#define CPU_AXI_USB_OTG_QOS_BASE 0xff540080
+
+#define PX30_CPU_AXI_SAVE_QOS(array, base) do { \
+ array[0] = mmio_read_32(base + CPU_AXI_QOS_ID_COREID); \
+ array[1] = mmio_read_32(base + CPU_AXI_QOS_REVISIONID); \
+ array[2] = mmio_read_32(base + CPU_AXI_QOS_PRIORITY); \
+ array[3] = mmio_read_32(base + CPU_AXI_QOS_MODE); \
+ array[4] = mmio_read_32(base + CPU_AXI_QOS_BANDWIDTH); \
+ array[5] = mmio_read_32(base + CPU_AXI_QOS_SATURATION); \
+ array[6] = mmio_read_32(base + CPU_AXI_QOS_EXTCONTROL); \
+} while (0)
+
+#define PX30_CPU_AXI_RESTORE_QOS(array, base) do { \
+ mmio_write_32(base + CPU_AXI_QOS_ID_COREID, array[0]); \
+ mmio_write_32(base + CPU_AXI_QOS_REVISIONID, array[1]); \
+ mmio_write_32(base + CPU_AXI_QOS_PRIORITY, array[2]); \
+ mmio_write_32(base + CPU_AXI_QOS_MODE, array[3]); \
+ mmio_write_32(base + CPU_AXI_QOS_BANDWIDTH, array[4]); \
+ mmio_write_32(base + CPU_AXI_QOS_SATURATION, array[5]); \
+ mmio_write_32(base + CPU_AXI_QOS_EXTCONTROL, array[6]); \
+} while (0)
+
+#define SAVE_QOS(array, NAME) \
+ PX30_CPU_AXI_SAVE_QOS(array, CPU_AXI_##NAME##_QOS_BASE)
+#define RESTORE_QOS(array, NAME) \
+ PX30_CPU_AXI_RESTORE_QOS(array, CPU_AXI_##NAME##_QOS_BASE)
+
+#endif /* __PMU_H__ */
diff --git a/plat/rockchip/px30/drivers/secure/secure.c b/plat/rockchip/px30/drivers/secure/secure.c
new file mode 100644
index 0000000..144f945
--- /dev/null
+++ b/plat/rockchip/px30/drivers/secure/secure.c
@@ -0,0 +1,103 @@
+/*
+ * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <ddr_parameter.h>
+#include <plat_private.h>
+#include <secure.h>
+#include <px30_def.h>
+
+/**
+ * There are 8 regions for DDR security control
+ * @rgn - the DDR regions 0 ~ 7 which are can be configured.
+ * @st - start address to set as secure
+ * @sz - length of area to set as secure
+ * The internal unit is megabytes, so memory areas need to be aligned
+ * to megabyte borders.
+ */
+static void secure_ddr_region(uint32_t rgn,
+ uintptr_t st, size_t sz)
+{
+ uintptr_t ed = st + sz;
+ uintptr_t st_mb, ed_mb;
+ uint32_t val;
+
+ 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);
+
+ /* map top and base */
+ mmio_write_32(FIREWALL_DDR_BASE +
+ FIREWALL_DDR_FW_DDR_RGN(rgn),
+ RG_MAP_SECURE(ed_mb, st_mb));
+
+ /* enable secure */
+ val = mmio_read_32(FIREWALL_DDR_BASE + FIREWALL_DDR_FW_DDR_CON_REG);
+ val |= BIT(rgn);
+ mmio_write_32(FIREWALL_DDR_BASE +
+ FIREWALL_DDR_FW_DDR_CON_REG, val);
+}
+
+void secure_timer_init(void)
+{
+ mmio_write_32(STIMER_CHN_BASE(1) + TIMER_CONTROL_REG,
+ TIMER_DIS);
+
+ mmio_write_32(STIMER_CHN_BASE(1) + TIMER_LOAD_COUNT0, 0xffffffff);
+ mmio_write_32(STIMER_CHN_BASE(1) + TIMER_LOAD_COUNT1, 0xffffffff);
+
+ /* auto reload & enable the timer */
+ mmio_write_32(STIMER_CHN_BASE(1) + TIMER_CONTROL_REG,
+ TIMER_EN | TIMER_FMODE);
+}
+
+void sgrf_init(void)
+{
+#ifdef PLAT_RK_SECURE_DDR_MINILOADER
+ uint32_t i;
+ struct param_ddr_usage usg;
+
+ /* general secure regions */
+ usg = ddr_region_usage_parse(DDR_PARAM_BASE,
+ PLAT_MAX_DDR_CAPACITY_MB);
+
+ /* region-0 for TF-A, region-1 for optional OP-TEE */
+ assert(usg.s_nr < 7);
+
+ for (i = 0; i < usg.s_nr; i++)
+ secure_ddr_region(7 - i, usg.s_top[i], usg.s_base[i]);
+#endif
+
+ /* secure the trustzone ram */
+ secure_ddr_region(0, TZRAM_BASE, TZRAM_SIZE);
+
+ /* set all slave ip into no-secure, except stimer */
+ mmio_write_32(SGRF_BASE + SGRF_SOC_CON(4), SGRF_SLV_S_ALL_NS);
+ mmio_write_32(SGRF_BASE + SGRF_SOC_CON(5), SGRF_SLV_S_ALL_NS);
+ mmio_write_32(SGRF_BASE + SGRF_SOC_CON(6), SGRF_SLV_S_ALL_NS);
+ mmio_write_32(SGRF_BASE + SGRF_SOC_CON(7), SGRF_SLV_S_ALL_NS);
+ mmio_write_32(SGRF_BASE + SGRF_SOC_CON(8), 0x00030000);
+
+ /* set master crypto to no-secure, dcf to secure */
+ mmio_write_32(SGRF_BASE + SGRF_SOC_CON(3), 0x000f0003);
+
+ /* set DMAC into no-secure */
+ mmio_write_32(SGRF_BASE + SGRF_DMAC_CON(0), DMA_IRQ_BOOT_NS);
+ mmio_write_32(SGRF_BASE + SGRF_DMAC_CON(1), DMA_PERI_CH_NS_15_0);
+ mmio_write_32(SGRF_BASE + SGRF_DMAC_CON(2), DMA_PERI_CH_NS_19_16);
+ mmio_write_32(SGRF_BASE + SGRF_DMAC_CON(3), DMA_MANAGER_BOOT_NS);
+
+ /* soft reset dma before use */
+ mmio_write_32(SGRF_BASE + SGRF_SOC_CON(1), DMA_SOFTRST_REQ);
+ udelay(5);
+ mmio_write_32(SGRF_BASE + SGRF_SOC_CON(1), DMA_SOFTRST_RLS);
+}
diff --git a/plat/rockchip/px30/drivers/secure/secure.h b/plat/rockchip/px30/drivers/secure/secure.h
new file mode 100644
index 0000000..498027d
--- /dev/null
+++ b/plat/rockchip/px30/drivers/secure/secure.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef SECURE_H
+#define SECURE_H
+
+/***************************************************************************
+ * SGRF
+ ***************************************************************************/
+#define SGRF_SOC_CON(i) ((i) * 0x4)
+#define SGRF_DMAC_CON(i) (0x30 + (i) * 0x4)
+
+#define SGRF_MST_S_ALL_NS 0xffffffff
+#define SGRF_SLV_S_ALL_NS 0xffff0000
+#define DMA_IRQ_BOOT_NS 0xffffffff
+#define DMA_PERI_CH_NS_15_0 0xffffffff
+#define DMA_PERI_CH_NS_19_16 0x000f000f
+#define DMA_MANAGER_BOOT_NS 0x00010001
+#define DMA_SOFTRST_REQ BITS_WITH_WMASK(1, 0x1, 12)
+#define DMA_SOFTRST_RLS BITS_WITH_WMASK(0, 0x1, 12)
+
+/***************************************************************************
+ * DDR FIREWALL
+ ***************************************************************************/
+#define FIREWALL_DDR_FW_DDR_RGN(i) ((i) * 0x4)
+#define FIREWALL_DDR_FW_DDR_MST(i) (0x20 + (i) * 0x4)
+#define FIREWALL_DDR_FW_DDR_CON_REG 0x40
+#define FIREWALL_DDR_FW_DDR_RGN_NUM 8
+#define FIREWALL_DDR_FW_DDR_MST_NUM 6
+
+#define PLAT_MAX_DDR_CAPACITY_MB 4096
+#define RG_MAP_SECURE(top, base) ((((top) - 1) << 16) | (base))
+
+/**************************************************
+ * secure timer
+ **************************************************/
+
+/* chanal0~5 */
+#define STIMER_CHN_BASE(n) (STIME_BASE + 0x20 * (n))
+
+#define TIMER_LOAD_COUNT0 0x0
+#define TIMER_LOAD_COUNT1 0x4
+
+#define TIMER_CUR_VALUE0 0x8
+#define TIMER_CUR_VALUE1 0xc
+
+#define TIMER_CONTROL_REG 0x10
+#define TIMER_INTSTATUS 0x18
+
+#define TIMER_DIS 0x0
+#define TIMER_EN 0x1
+
+#define TIMER_FMODE (0x0 << 1)
+#define TIMER_RMODE (0x1 << 1)
+
+#define TIMER_LOAD_COUNT0_MSK (0xffffffff)
+#define TIMER_LOAD_COUNT1_MSK (0xffffffff00000000)
+
+void secure_timer_init(void);
+void sgrf_init(void);
+
+#endif /* SECURE_H */
diff --git a/plat/rockchip/px30/drivers/soc/soc.c b/plat/rockchip/px30/drivers/soc/soc.c
new file mode 100644
index 0000000..200563d
--- /dev/null
+++ b/plat/rockchip/px30/drivers/soc/soc.c
@@ -0,0 +1,134 @@
+/*
+ * Copyright (c) 2019, 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 <drivers/console.h>
+#include <drivers/delay_timer.h>
+#include <lib/mmio.h>
+
+#include <platform_def.h>
+#include <pmu.h>
+#include <px30_def.h>
+#include <secure.h>
+#include <soc.h>
+#include <rockchip_sip_svc.h>
+
+/* Aggregate of all devices in the first GB */
+#define PX30_DEV_RNG0_BASE 0xff000000
+#define PX30_DEV_RNG0_SIZE 0x00ff0000
+
+const mmap_region_t plat_rk_mmap[] = {
+ MAP_REGION_FLAT(PX30_DEV_RNG0_BASE, PX30_DEV_RNG0_SIZE,
+ MT_DEVICE | MT_RW | MT_SECURE),
+ MAP_REGION_FLAT(SHARE_MEM_BASE, SHARE_MEM_SIZE,
+ MT_DEVICE | MT_RW | MT_SECURE),
+ MAP_REGION_FLAT(DDR_PARAM_BASE, DDR_PARAM_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 clk_gate_con_save(uint32_t *clkgt_save)
+{
+ uint32_t i, j;
+
+ for (i = 0; i < CRU_CLKGATES_CON_CNT; i++)
+ clkgt_save[i] =
+ mmio_read_32(CRU_BASE + CRU_CLKGATES_CON(i));
+ j = i;
+ for (i = 0; i < CRU_PMU_CLKGATE_CON_CNT; i++, j++)
+ clkgt_save[j] =
+ mmio_read_32(PMUCRU_BASE + CRU_PMU_CLKGATES_CON(i));
+}
+
+void clk_gate_con_restore(uint32_t *clkgt_save)
+{
+ uint32_t i, j;
+
+ for (i = 0; i < CRU_CLKGATES_CON_CNT; i++)
+ mmio_write_32(CRU_BASE + CRU_CLKGATES_CON(i),
+ WITH_16BITS_WMSK(clkgt_save[i]));
+
+ j = i;
+ for (i = 0; i < CRU_PMU_CLKGATE_CON_CNT; i++, j++)
+ mmio_write_32(PMUCRU_BASE + CRU_PMU_CLKGATES_CON(i),
+ WITH_16BITS_WMSK(clkgt_save[j]));
+}
+
+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),
+ 0xffff0000);
+
+ for (i = 0; i < CRU_PMU_CLKGATE_CON_CNT; i++)
+ mmio_write_32(PMUCRU_BASE + CRU_PMU_CLKGATES_CON(i),
+ 0xffff0000);
+}
+
+static void soc_reset_config_all(void)
+{
+ uint32_t tmp;
+
+ /* tsadc and wdt can trigger a first rst */
+ tmp = mmio_read_32(CRU_BASE + CRU_GLB_RST_CON);
+ tmp |= CRU_GLB_RST_TSADC_FST | CRU_GLB_RST_WDT_FST;
+ mmio_write_32(CRU_BASE + CRU_GLB_RST_CON, tmp);
+ return;
+ tmp = mmio_read_32(PMUGRF_BASE + PMUGRF_SOC_CON(3));
+ tmp &= ~(PMUGRF_FAILSAFE_SHTDN_TSADC | PMUGRF_FAILSAFE_SHTDN_WDT);
+ mmio_write_32(PMUGRF_BASE + PMUGRF_SOC_CON(3), tmp);
+
+ /* wdt pin rst eable */
+ mmio_write_32(GRF_BASE + GRF_SOC_CON(2),
+ BIT_WITH_WMSK(GRF_SOC_CON2_NSWDT_RST_EN));
+}
+
+void px30_soc_reset_config(void)
+{
+ uint32_t tmp;
+
+ /* enable soc ip rst hold time cfg */
+ tmp = mmio_read_32(CRU_BASE + CRU_GLB_RST_CON);
+ tmp |= BIT(CRU_GLB_RST_TSADC_EXT) | BIT(CRU_GLB_RST_WDT_EXT);
+ mmio_write_32(CRU_BASE + CRU_GLB_RST_CON, tmp);
+ /* soc ip rst hold time, 24m */
+ tmp = mmio_read_32(CRU_BASE + CRU_GLB_CNT_TH);
+ tmp &= ~CRU_GLB_CNT_RST_MSK;
+ tmp |= (CRU_GLB_CNT_RST_1MS / 2);
+ mmio_write_32(CRU_BASE + CRU_GLB_CNT_TH, tmp);
+
+ mmio_write_32(PMUSGRF_BASE + PMUSGRF_SOC_CON(0),
+ BIT_WITH_WMSK(PMUSGRF_RSTOUT_FST) |
+ BIT_WITH_WMSK(PMUSGRF_RSTOUT_TSADC) |
+ BIT_WITH_WMSK(PMUSGRF_RSTOUT_WDT));
+
+ /* rst_out pulse time */
+ mmio_write_32(PMUGRF_BASE + PMUGRF_SOC_CON(2),
+ PMUGRF_SOC_CON2_MAX_341US | PMUGRF_SOC_CON2_US_WMSK);
+
+ soc_reset_config_all();
+}
+
+void plat_rockchip_soc_init(void)
+{
+ secure_timer_init();
+ sgrf_init();
+}
diff --git a/plat/rockchip/px30/drivers/soc/soc.h b/plat/rockchip/px30/drivers/soc/soc.h
new file mode 100644
index 0000000..648d18b
--- /dev/null
+++ b/plat/rockchip/px30/drivers/soc/soc.h
@@ -0,0 +1,118 @@
+/*
+ * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef __SOC_H__
+#define __SOC_H__
+
+#include <plat_private.h>
+
+#ifndef BITS_WMSK
+#define BITS_WMSK(msk, shift) ((msk) << (shift + REG_MSK_SHIFT))
+#endif
+
+enum plls_id {
+ APLL_ID = 0,
+ DPLL_ID,
+ CPLL_ID,
+ NPLL_ID,
+ GPLL_ID,
+ END_PLL_ID,
+};
+
+enum pll_mode {
+ SLOW_MODE,
+ NORM_MODE,
+ DEEP_SLOW_MODE,
+};
+
+/***************************************************************************
+ * GRF
+ ***************************************************************************/
+#define GRF_SOC_CON(i) (0x0400 + (i) * 4)
+#define GRF_PD_VO_CON0 0x0434
+#define GRF_SOC_STATUS0 0x0480
+#define GRF_CPU_STATUS0 0x0520
+#define GRF_CPU_STATUS1 0x0524
+#define GRF_SOC_NOC_CON0 0x0530
+#define GRF_SOC_NOC_CON1 0x0534
+
+#define CKECK_WFE_MSK 0x1
+#define CKECK_WFI_MSK 0x10
+#define CKECK_WFEI_MSK 0x11
+
+#define GRF_SOC_CON2_NSWDT_RST_EN 12
+
+/***************************************************************************
+ * cru
+ ***************************************************************************/
+#define CRU_MODE 0xa0
+#define CRU_MISC 0xa4
+#define CRU_GLB_CNT_TH 0xb0
+#define CRU_GLB_RST_ST 0xb4
+#define CRU_GLB_SRST_FST 0xb8
+#define CRU_GLB_SRST_SND 0xbc
+#define CRU_GLB_RST_CON 0xc0
+
+#define CRU_CLKSEL_CON 0x100
+#define CRU_CLKSELS_CON(i) (CRU_CLKSEL_CON + (i) * 4)
+#define CRU_CLKSEL_CON_CNT 60
+
+#define CRU_CLKGATE_CON 0x200
+#define CRU_CLKGATES_CON(i) (CRU_CLKGATE_CON + (i) * 4)
+#define CRU_CLKGATES_CON_CNT 18
+
+#define CRU_SOFTRST_CON 0x300
+#define CRU_SOFTRSTS_CON(n) (CRU_SOFTRST_CON + ((n) * 4))
+#define CRU_SOFTRSTS_CON_CNT 12
+
+#define CRU_AUTOCS_CON0(id) (0x400 + (id) * 8)
+#define CRU_AUTOCS_CON1(id) (0x404 + (id) * 8)
+
+#define CRU_CONS_GATEID(i) (16 * (i))
+#define GATE_ID(reg, bit) ((reg) * 16 + (bit))
+
+#define CRU_GLB_SRST_FST_VALUE 0xfdb9
+#define CRU_GLB_SRST_SND_VALUE 0xeca8
+
+#define CRU_GLB_RST_TSADC_EXT 6
+#define CRU_GLB_RST_WDT_EXT 7
+
+#define CRU_GLB_CNT_RST_MSK 0xffff
+#define CRU_GLB_CNT_RST_1MS 0x5DC0
+
+#define CRU_GLB_RST_TSADC_FST BIT(0)
+#define CRU_GLB_RST_WDT_FST BIT(1)
+
+/***************************************************************************
+ * pll
+ ***************************************************************************/
+#define CRU_PLL_CONS(id, i) ((id) * 0x20 + (i) * 4)
+#define PLL_CON(i) ((i) * 4)
+#define PLL_CON_CNT 5
+#define PLL_LOCK_MSK BIT(10)
+#define PLL_MODE_SHIFT(id) ((id) == CPLL_ID ? \
+ 2 : \
+ ((id) == DPLL_ID ? 4 : 2 * (id)))
+#define PLL_MODE_MSK(id) (0x3 << PLL_MODE_SHIFT(id))
+
+#define PLL_LOCKED_TIMEOUT 600000U
+
+/***************************************************************************
+ * GPIO
+ ***************************************************************************/
+#define SWPORTA_DR 0x00
+#define SWPORTA_DDR 0x04
+#define GPIO_INTEN 0x30
+#define GPIO_INT_STATUS 0x40
+#define GPIO_NUMS 4
+
+void clk_gate_con_save(uint32_t *clkgt_save);
+void clk_gate_con_restore(uint32_t *clkgt_save);
+void clk_gate_con_disable(void);
+
+void px30_soc_reset_config(void);
+
+#endif /* __SOC_H__ */