diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-21 17:43:51 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-21 17:43:51 +0000 |
commit | be58c81aff4cd4c0ccf43dbd7998da4a6a08c03b (patch) | |
tree | 779c248fb61c83f65d1f0dc867f2053d76b4e03a /plat/rockchip/px30/drivers | |
parent | Initial commit. (diff) | |
download | arm-trusted-firmware-be58c81aff4cd4c0ccf43dbd7998da4a6a08c03b.tar.xz arm-trusted-firmware-be58c81aff4cd4c0ccf43dbd7998da4a6a08c03b.zip |
Adding upstream version 2.10.0+dfsg.upstream/2.10.0+dfsgupstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'plat/rockchip/px30/drivers')
-rw-r--r-- | plat/rockchip/px30/drivers/pmu/plat_pmu_macros.S | 21 | ||||
-rw-r--r-- | plat/rockchip/px30/drivers/pmu/pmu.c | 1071 | ||||
-rw-r--r-- | plat/rockchip/px30/drivers/pmu/pmu.h | 331 | ||||
-rw-r--r-- | plat/rockchip/px30/drivers/secure/secure.c | 103 | ||||
-rw-r--r-- | plat/rockchip/px30/drivers/secure/secure.h | 65 | ||||
-rw-r--r-- | plat/rockchip/px30/drivers/soc/soc.c | 134 | ||||
-rw-r--r-- | plat/rockchip/px30/drivers/soc/soc.h | 118 |
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__ */ |