19fd9f1d0Sshengfei Xu /* 2*4e1ccc60SShengfei Xu * Copyright (c) 2023-2025, ARM Limited and Contributors. All rights reserved. 39fd9f1d0Sshengfei Xu * 49fd9f1d0Sshengfei Xu * The power management unit (PMU) is designed for controlling power resources. 59fd9f1d0Sshengfei Xu * The PMU is dedicated for managing the power of the whole chip. 69fd9f1d0Sshengfei Xu * 79fd9f1d0Sshengfei Xu * SPDX-License-Identifier: BSD-3-Clause 89fd9f1d0Sshengfei Xu */ 99fd9f1d0Sshengfei Xu 109fd9f1d0Sshengfei Xu #include <assert.h> 119fd9f1d0Sshengfei Xu #include <errno.h> 129fd9f1d0Sshengfei Xu 139fd9f1d0Sshengfei Xu #include <bakery_lock.h> 149fd9f1d0Sshengfei Xu #include <cortex_a55.h> 159fd9f1d0Sshengfei Xu #include <dsu_def.h> 169fd9f1d0Sshengfei Xu #include <mmio.h> 179fd9f1d0Sshengfei Xu #include <platform.h> 189fd9f1d0Sshengfei Xu #include <platform_def.h> 199fd9f1d0Sshengfei Xu #include <pmu.h> 209fd9f1d0Sshengfei Xu 219fd9f1d0Sshengfei Xu #include <cpus_on_fixed_addr.h> 229fd9f1d0Sshengfei Xu #include <plat_private.h> 23*4e1ccc60SShengfei Xu #include <rk3568_clk.h> 249fd9f1d0Sshengfei Xu #include <soc.h> 259fd9f1d0Sshengfei Xu 269fd9f1d0Sshengfei Xu /* 279fd9f1d0Sshengfei Xu * Use this macro to instantiate lock before it is used in below 289fd9f1d0Sshengfei Xu * rockchip_pd_lock_xxx() macros 299fd9f1d0Sshengfei Xu */ 309fd9f1d0Sshengfei Xu DECLARE_BAKERY_LOCK(rockchip_pd_lock); 319fd9f1d0Sshengfei Xu 329fd9f1d0Sshengfei Xu static uint32_t grf_ddr_con3; 339fd9f1d0Sshengfei Xu static struct psram_data_t *psram_sleep_cfg = 349fd9f1d0Sshengfei Xu (struct psram_data_t *)&sys_sleep_flag_sram; 359fd9f1d0Sshengfei Xu 369fd9f1d0Sshengfei Xu /* 379fd9f1d0Sshengfei Xu * These are wrapper macros to the powe domain Bakery Lock API. 389fd9f1d0Sshengfei Xu */ 399fd9f1d0Sshengfei Xu #define rockchip_pd_lock_init() bakery_lock_init(&rockchip_pd_lock) 409fd9f1d0Sshengfei Xu #define rockchip_pd_lock_get() bakery_lock_get(&rockchip_pd_lock) 419fd9f1d0Sshengfei Xu #define rockchip_pd_lock_rls() bakery_lock_release(&rockchip_pd_lock) 429fd9f1d0Sshengfei Xu 439fd9f1d0Sshengfei Xu void __dead2 rockchip_soc_sys_pd_pwr_dn_wfi(void) 449fd9f1d0Sshengfei Xu { 459fd9f1d0Sshengfei Xu uint64_t ctrl; 469fd9f1d0Sshengfei Xu 479fd9f1d0Sshengfei Xu __asm__ volatile ("mrs %0, " __XSTRING(CORTEX_A55_CPUPWRCTLR_EL1) : "=r" (ctrl)); 489fd9f1d0Sshengfei Xu ctrl |= 0x01; 499fd9f1d0Sshengfei Xu __asm__ volatile ("msr " __XSTRING(CORTEX_A55_CPUPWRCTLR_EL1) ", %0" : : "r" (ctrl)); 509fd9f1d0Sshengfei Xu isb(); 519fd9f1d0Sshengfei Xu 529fd9f1d0Sshengfei Xu while (1) 539fd9f1d0Sshengfei Xu wfi(); 549fd9f1d0Sshengfei Xu } 559fd9f1d0Sshengfei Xu 569fd9f1d0Sshengfei Xu static void pmu_pmic_sleep_mode_config(void) 579fd9f1d0Sshengfei Xu { 589fd9f1d0Sshengfei Xu /* pmic sleep function selection 599fd9f1d0Sshengfei Xu * 1'b0: From reset pulse generator, can reset external PMIC 609fd9f1d0Sshengfei Xu * 1'b1: From pmu block, only support sleep function for external PMIC 619fd9f1d0Sshengfei Xu */ 629fd9f1d0Sshengfei Xu mmio_write_32(PMUGRF_BASE + PMU_GRF_SOC_CON(0), WRITE_MASK_SET(BIT(7))); 639fd9f1d0Sshengfei Xu mmio_write_32(PMUGRF_BASE + PMU_GRF_GPIO0A_IOMUX_L, PMIC_SLEEP_FUN); 649fd9f1d0Sshengfei Xu } 659fd9f1d0Sshengfei Xu 669fd9f1d0Sshengfei Xu static void pmu_wakeup_source_config(void) 679fd9f1d0Sshengfei Xu { 689fd9f1d0Sshengfei Xu /* config wakeup source */ 699fd9f1d0Sshengfei Xu mmio_write_32(PMU_BASE + PMU_WAKEUP_INT_CON, WRITE_MASK_SET(BIT(WAKEUP_GPIO0_INT_EN))); 709fd9f1d0Sshengfei Xu 719fd9f1d0Sshengfei Xu INFO("WAKEUP: PMU_WAKEUP_INT_CON:0x%x, reg: 0x%x\n", 729fd9f1d0Sshengfei Xu mmio_read_32(PMU_BASE + PMU_WAKEUP_INT_CON), PMU_WAKEUP_INT_CON); 739fd9f1d0Sshengfei Xu } 749fd9f1d0Sshengfei Xu 759fd9f1d0Sshengfei Xu static void pmu_pll_powerdown_config(void) 769fd9f1d0Sshengfei Xu { 779fd9f1d0Sshengfei Xu uint32_t pll_id; 789fd9f1d0Sshengfei Xu 799fd9f1d0Sshengfei Xu /* PLL power down by PMU */ 809fd9f1d0Sshengfei Xu pll_id = BIT(APLL_PD_ENA) | 819fd9f1d0Sshengfei Xu BIT(CPLL_PD_ENA) | 829fd9f1d0Sshengfei Xu BIT(GPLL_PD_ENA) | 839fd9f1d0Sshengfei Xu BIT(MPLL_PD_ENA) | 849fd9f1d0Sshengfei Xu BIT(NPLL_PD_ENA) | 859fd9f1d0Sshengfei Xu BIT(HPLL_PD_ENA) | 869fd9f1d0Sshengfei Xu BIT(PPLL_PD_ENA) | 879fd9f1d0Sshengfei Xu BIT(VPLL_PD_ENA); 889fd9f1d0Sshengfei Xu mmio_write_32(PMU_BASE + PMU_PLLPD_CON, WRITE_MASK_SET(pll_id)); 899fd9f1d0Sshengfei Xu INFO("PLL: PMU_PLLPD_CON(0x%x):0x%x\n", 909fd9f1d0Sshengfei Xu PMU_PLLPD_CON, mmio_read_32(PMU_BASE + PMU_PLLPD_CON)); 919fd9f1d0Sshengfei Xu } 929fd9f1d0Sshengfei Xu 939fd9f1d0Sshengfei Xu static void pmu_stable_count_config(void) 949fd9f1d0Sshengfei Xu { 959fd9f1d0Sshengfei Xu mmio_write_32(PMU_BASE + PMU_DSU_STABLE_CNT, 0x180); 969fd9f1d0Sshengfei Xu mmio_write_32(PMU_BASE + PMU_PMIC_STABLE_CNT, 0x180); 979fd9f1d0Sshengfei Xu mmio_write_32(PMU_BASE + PMU_OSC_STABLE_CNT, 0x180); 989fd9f1d0Sshengfei Xu mmio_write_32(PMU_BASE + PMU_WAKEUP_RSTCLR_CNT, 0x180); 999fd9f1d0Sshengfei Xu mmio_write_32(PMU_BASE + PMU_PLL_LOCK_CNT, 0x180); 1009fd9f1d0Sshengfei Xu mmio_write_32(PMU_BASE + PMU_DSU_PWRUP_CNT, 0x180); 1019fd9f1d0Sshengfei Xu mmio_write_32(PMU_BASE + PMU_DSU_PWRDN_CNT, 0x180); 1029fd9f1d0Sshengfei Xu mmio_write_32(PMU_BASE + PMU_GPU_VOLUP_CNT, 0x180); 1039fd9f1d0Sshengfei Xu mmio_write_32(PMU_BASE + PMU_GPU_VOLDN_CNT, 0x180); 1049fd9f1d0Sshengfei Xu mmio_write_32(PMU_BASE + PMU_WAKEUP_TIMEOUT_CNT, 0x180); 1059fd9f1d0Sshengfei Xu mmio_write_32(PMU_BASE + PMU_PWM_SWITCH_CNT, 0x180); 1069fd9f1d0Sshengfei Xu mmio_write_32(PMU_BASE + PMU_DBG_RST_CNT, 0x180); 1079fd9f1d0Sshengfei Xu } 1089fd9f1d0Sshengfei Xu 1099fd9f1d0Sshengfei Xu static void pmu_pd_powerdown_config(void) 1109fd9f1d0Sshengfei Xu { 1119fd9f1d0Sshengfei Xu uint32_t pwr_gate_con, pwr_dwn_st, pmu_bus_idle_con0 = 0; 1129fd9f1d0Sshengfei Xu uint32_t pmu_bus_idle_con1; 1139fd9f1d0Sshengfei Xu 1149fd9f1d0Sshengfei Xu /* Pd power down by PMU */ 1159fd9f1d0Sshengfei Xu pwr_dwn_st = mmio_read_32(PMU_BASE + PMU_PWR_DWN_ST); 1169fd9f1d0Sshengfei Xu pwr_gate_con = ~pwr_dwn_st & 0x3ff; 1179fd9f1d0Sshengfei Xu 1189fd9f1d0Sshengfei Xu if (pwr_gate_con & BIT(PD_GPU_DWN_ENA)) { 1199fd9f1d0Sshengfei Xu pmu_bus_idle_con0 |= BIT(IDLE_REQ_GPU); 1209fd9f1d0Sshengfei Xu } 1219fd9f1d0Sshengfei Xu 1229fd9f1d0Sshengfei Xu if (pwr_gate_con & BIT(PD_NPU_DWN_ENA)) { 1239fd9f1d0Sshengfei Xu pmu_bus_idle_con0 |= BIT(IDLE_REQ_NPU); 1249fd9f1d0Sshengfei Xu } 1259fd9f1d0Sshengfei Xu 1269fd9f1d0Sshengfei Xu if (pwr_gate_con & BIT(PD_RKVENC_DWN_ENA)) { 1279fd9f1d0Sshengfei Xu pmu_bus_idle_con0 |= BIT(IDLE_REQ_RKVENC); 1289fd9f1d0Sshengfei Xu } 1299fd9f1d0Sshengfei Xu 1309fd9f1d0Sshengfei Xu if (pwr_gate_con & BIT(PD_RKVDEC_DWN_ENA)) { 1319fd9f1d0Sshengfei Xu pmu_bus_idle_con0 |= BIT(IDLE_REQ_RKVDEC); 1329fd9f1d0Sshengfei Xu } 1339fd9f1d0Sshengfei Xu 1349fd9f1d0Sshengfei Xu if (pwr_gate_con & BIT(PD_RGA_DWN_ENA)) { 1359fd9f1d0Sshengfei Xu pmu_bus_idle_con0 |= BIT(IDLE_REQ_RGA); 1369fd9f1d0Sshengfei Xu } 1379fd9f1d0Sshengfei Xu 1389fd9f1d0Sshengfei Xu if (pwr_gate_con & BIT(PD_VI_DWN_ENA)) { 1399fd9f1d0Sshengfei Xu pmu_bus_idle_con0 |= BIT(IDLE_REQ_VI); 1409fd9f1d0Sshengfei Xu } 1419fd9f1d0Sshengfei Xu 1429fd9f1d0Sshengfei Xu if (pwr_gate_con & BIT(PD_VO_DWN_ENA)) { 1439fd9f1d0Sshengfei Xu pmu_bus_idle_con0 |= BIT(IDLE_REQ_VO); 1449fd9f1d0Sshengfei Xu } 1459fd9f1d0Sshengfei Xu 1469fd9f1d0Sshengfei Xu if (pwr_gate_con & BIT(PD_PIPE_DWN_ENA)) { 1479fd9f1d0Sshengfei Xu pmu_bus_idle_con0 |= BIT(IDLE_REQ_PIPE); 1489fd9f1d0Sshengfei Xu } 1499fd9f1d0Sshengfei Xu 1509fd9f1d0Sshengfei Xu pmu_bus_idle_con0 |= BIT(IDLE_REQ_GIC_AUDIO) | 1519fd9f1d0Sshengfei Xu BIT(IDLE_REQ_MSCH) | 1529fd9f1d0Sshengfei Xu BIT(IDLE_REQ_PHP) | 1539fd9f1d0Sshengfei Xu BIT(IDLE_REQ_SECURE_FLASH) | 1549fd9f1d0Sshengfei Xu BIT(IDLE_REQ_PERIMID) | 1559fd9f1d0Sshengfei Xu BIT(IDLE_REQ_USB) | 1569fd9f1d0Sshengfei Xu BIT(IDLE_REQ_BUS); 1579fd9f1d0Sshengfei Xu 1589fd9f1d0Sshengfei Xu /* Enable power down PD by PMU automatically */ 1599fd9f1d0Sshengfei Xu pwr_gate_con |= (BIT(PD_GPU_DWN_ENA) | 1609fd9f1d0Sshengfei Xu BIT(PD_NPU_DWN_ENA) | 1619fd9f1d0Sshengfei Xu BIT(PD_VPU_DWN_ENA) | 1629fd9f1d0Sshengfei Xu BIT(PD_RKVENC_DWN_ENA) | 1639fd9f1d0Sshengfei Xu BIT(PD_RKVDEC_DWN_ENA) | 1649fd9f1d0Sshengfei Xu BIT(PD_RGA_DWN_ENA) | 1659fd9f1d0Sshengfei Xu BIT(PD_VI_DWN_ENA) | 1669fd9f1d0Sshengfei Xu BIT(PD_VO_DWN_ENA) | 1679fd9f1d0Sshengfei Xu BIT(PD_PIPE_DWN_ENA)) << 16; 1689fd9f1d0Sshengfei Xu 1699fd9f1d0Sshengfei Xu pmu_bus_idle_con1 = 0; 1709fd9f1d0Sshengfei Xu 1719fd9f1d0Sshengfei Xu mmio_write_32(PMU_BASE + PMU_PWR_GATE_CON, pwr_gate_con); 1729fd9f1d0Sshengfei Xu mmio_write_32(PMU_BASE + PMU_BUS_IDLE_CON0, WRITE_MASK_SET(pmu_bus_idle_con0)); 1739fd9f1d0Sshengfei Xu mmio_write_32(PMU_BASE + PMU_BUS_IDLE_CON1, WRITE_MASK_SET(pmu_bus_idle_con1)); 1749fd9f1d0Sshengfei Xu 1759fd9f1d0Sshengfei Xu /* When perform idle operation, 1769fd9f1d0Sshengfei Xu * corresponding clock can be opened or gated automatically 1779fd9f1d0Sshengfei Xu */ 1789fd9f1d0Sshengfei Xu mmio_write_32(PMU_BASE + PMU_NOC_AUTO_CON0, 0xffffffff); 1799fd9f1d0Sshengfei Xu mmio_write_32(PMU_BASE + PMU_NOC_AUTO_CON1, 0x00070007); 1809fd9f1d0Sshengfei Xu 1819fd9f1d0Sshengfei Xu mmio_write_32(PMU_BASE + PMU_VOL_GATE_SFTCON, WRITE_MASK_SET(BIT(VD_NPU_ENA))); 1829fd9f1d0Sshengfei Xu 1839fd9f1d0Sshengfei Xu mmio_write_32(PMU_BASE + PMU_PWR_CON, WRITE_MASK_CLR(BIT(PWRDN_BYPASS))); 1849fd9f1d0Sshengfei Xu mmio_write_32(PMU_BASE + PMU_PWR_CON, WRITE_MASK_CLR(BIT(BUS_BYPASS))); 1859fd9f1d0Sshengfei Xu 1869fd9f1d0Sshengfei Xu INFO("PD & BUS:PMU_PWR_DWN_ST(0x%x):0x%x\n", 1879fd9f1d0Sshengfei Xu PMU_PWR_DWN_ST, mmio_read_32(PMU_BASE + PMU_PWR_DWN_ST)); 1889fd9f1d0Sshengfei Xu INFO("PD & BUS:PMU_PWR_GATE_CON(0x%x):0x%x\n", 1899fd9f1d0Sshengfei Xu PMU_PWR_GATE_CON, mmio_read_32(PMU_BASE + PMU_PWR_GATE_CON)); 1909fd9f1d0Sshengfei Xu INFO("PD & BUS:PMU_BUS_IDLE_CON0(0x%x):0x%x\n", 1919fd9f1d0Sshengfei Xu PMU_BUS_IDLE_CON0, mmio_read_32(PMU_BASE + PMU_BUS_IDLE_CON0)); 1929fd9f1d0Sshengfei Xu INFO("PD & BUS:PMU_BUS_IDLE_CON1(0x%x):0x%x\n", 1939fd9f1d0Sshengfei Xu PMU_BUS_IDLE_CON1, mmio_read_32(PMU_BASE + PMU_BUS_IDLE_CON1)); 1949fd9f1d0Sshengfei Xu INFO("PD & BUS:PMU_PWR_CON(0x%x):0x%x\n", 1959fd9f1d0Sshengfei Xu PMU_PWR_CON, mmio_read_32(PMU_BASE + PMU_PWR_CON)); 1969fd9f1d0Sshengfei Xu } 1979fd9f1d0Sshengfei Xu 1989fd9f1d0Sshengfei Xu static void pmu_ddr_suspend_config(void) 1999fd9f1d0Sshengfei Xu { 2009fd9f1d0Sshengfei Xu uint32_t pmu_ddr_pwr_con; 2019fd9f1d0Sshengfei Xu 2029fd9f1d0Sshengfei Xu pmu_ddr_pwr_con = BIT(DDR_SREF_ENA) | 2039fd9f1d0Sshengfei Xu BIT(DDRIO_RET_ENTER_ENA) | 2049fd9f1d0Sshengfei Xu BIT(DDRIO_RET_EXIT_ENA) | 2059fd9f1d0Sshengfei Xu BIT(DDRPHY_AUTO_GATING_ENA); 2069fd9f1d0Sshengfei Xu 2079fd9f1d0Sshengfei Xu mmio_write_32(PMU_BASE + PMU_DDR_PWR_CON, WRITE_MASK_SET(pmu_ddr_pwr_con)); 2089fd9f1d0Sshengfei Xu /* DPLL power down by PMU */ 2099fd9f1d0Sshengfei Xu mmio_write_32(PMU_BASE + PMU_PLLPD_CON, WRITE_MASK_SET(BIT(DPLL_PD_ENA))); 2109fd9f1d0Sshengfei Xu mmio_write_32(PMU_BASE + PMU_PWR_CON, WRITE_MASK_CLR(BIT(DDR_BYPASS))); 2119fd9f1d0Sshengfei Xu 2129fd9f1d0Sshengfei Xu grf_ddr_con3 = mmio_read_32(DDRGRF_BASE + GRF_DDR_CON3); 2139fd9f1d0Sshengfei Xu 2149fd9f1d0Sshengfei Xu mmio_write_32(DDRGRF_BASE + GRF_DDR_CON3, 0x00600020); 2159fd9f1d0Sshengfei Xu 2169fd9f1d0Sshengfei Xu pmu_ddr_pwr_con = mmio_read_32(PMU_BASE + PMU_DDR_PWR_CON); 2179fd9f1d0Sshengfei Xu 2189fd9f1d0Sshengfei Xu INFO("DDR: PMU_PLLPD_CON(0x%x):0x%x\n", 2199fd9f1d0Sshengfei Xu PMU_PLLPD_CON, mmio_read_32(PMU_BASE + PMU_PLLPD_CON)); 2209fd9f1d0Sshengfei Xu INFO("DDR: PMU_DDR_PWR_CON(0x%x):\t0x%x\n", 2219fd9f1d0Sshengfei Xu PMU_DDR_PWR_CON, pmu_ddr_pwr_con); 2229fd9f1d0Sshengfei Xu 2239fd9f1d0Sshengfei Xu if (pmu_ddr_pwr_con & BIT(DDR_SREF_ENA)) { 2249fd9f1d0Sshengfei Xu INFO("\t DDR_SREF_ENA\n"); 2259fd9f1d0Sshengfei Xu } 2269fd9f1d0Sshengfei Xu 2279fd9f1d0Sshengfei Xu if (pmu_ddr_pwr_con & BIT(DDRIO_RET_ENTER_ENA)) { 2289fd9f1d0Sshengfei Xu INFO("\t DDRIO_RET_ENTER_ENA\n"); 2299fd9f1d0Sshengfei Xu } 2309fd9f1d0Sshengfei Xu 2319fd9f1d0Sshengfei Xu if (pmu_ddr_pwr_con & BIT(DDRIO_RET_EXIT_ENA)) { 2329fd9f1d0Sshengfei Xu INFO("\t DDRIO_RET_EXIT_ENA\n"); 2339fd9f1d0Sshengfei Xu } 2349fd9f1d0Sshengfei Xu 2359fd9f1d0Sshengfei Xu if (pmu_ddr_pwr_con & BIT(DDRPHY_AUTO_GATING_ENA)) { 2369fd9f1d0Sshengfei Xu INFO("\t DDRPHY_AUTO_GATING_ENA\n"); 2379fd9f1d0Sshengfei Xu } 2389fd9f1d0Sshengfei Xu } 2399fd9f1d0Sshengfei Xu 2409fd9f1d0Sshengfei Xu static void pmu_dsu_suspend_config(void) 2419fd9f1d0Sshengfei Xu { 2429fd9f1d0Sshengfei Xu uint32_t pmu_dsu_pwr_con; 2439fd9f1d0Sshengfei Xu 2449fd9f1d0Sshengfei Xu pmu_dsu_pwr_con = BIT(DSU_PWRDN_ENA); 2459fd9f1d0Sshengfei Xu 2469fd9f1d0Sshengfei Xu mmio_write_32(PMU_BASE + PMU_CLUSTER_IDLE_CON, 0x000f000f); 2479fd9f1d0Sshengfei Xu mmio_write_32(PMU_BASE + PMU_DSU_PWR_CON, WRITE_MASK_SET(pmu_dsu_pwr_con)); 2489fd9f1d0Sshengfei Xu mmio_write_32(PMU_BASE + PMU_PWR_CON, WRITE_MASK_CLR(BIT(DSU_BYPASS))); 2499fd9f1d0Sshengfei Xu dsu_pwr_dwn(); 2509fd9f1d0Sshengfei Xu 2519fd9f1d0Sshengfei Xu INFO("DSU: PMU_DSU_PWR_CON(0x%x): 0x%x\n", 2529fd9f1d0Sshengfei Xu PMU_DSU_PWR_CON, mmio_read_32(PMU_BASE + PMU_DSU_PWR_CON)); 2539fd9f1d0Sshengfei Xu INFO("DSU: PMU_CLUSTER_IDLE_CON(0x%x),: 0x%x\n", 2549fd9f1d0Sshengfei Xu PMU_CLUSTER_IDLE_CON, mmio_read_32(PMU_BASE + PMU_CLUSTER_IDLE_CON)); 2559fd9f1d0Sshengfei Xu INFO("DSU: PMU_PWR_CON(0x%x),: 0x%x\n", 2569fd9f1d0Sshengfei Xu PMU_PWR_CON, mmio_read_32(PMU_BASE + PMU_PWR_CON)); 2579fd9f1d0Sshengfei Xu } 2589fd9f1d0Sshengfei Xu 2599fd9f1d0Sshengfei Xu static void pmu_cpu_powerdown_config(void) 2609fd9f1d0Sshengfei Xu { 2619fd9f1d0Sshengfei Xu uint32_t pmu_cluster_pwr_st, cpus_state, cpus_bypass; 2629fd9f1d0Sshengfei Xu 2639fd9f1d0Sshengfei Xu pmu_cluster_pwr_st = mmio_read_32(PMU_BASE + PMU_CLUSTER_PWR_ST); 2649fd9f1d0Sshengfei Xu cpus_state = pmu_cluster_pwr_st & 0x0f; 2659fd9f1d0Sshengfei Xu 2669fd9f1d0Sshengfei Xu cpus_bypass = cpus_state << CPU0_BYPASS; 2679fd9f1d0Sshengfei Xu 2689fd9f1d0Sshengfei Xu INFO("CPU: PMU_CLUSTER_PWR_ST(0x%x):0x%x\n", 2699fd9f1d0Sshengfei Xu PMU_CLUSTER_PWR_ST, mmio_read_32(PMU_BASE + PMU_CLUSTER_PWR_ST)); 2709fd9f1d0Sshengfei Xu mmio_write_32(PMU_BASE + PMU_PWR_CON, (0xf << (16 + CPU0_BYPASS)) | cpus_bypass); 2719fd9f1d0Sshengfei Xu 2729fd9f1d0Sshengfei Xu INFO("CPU: PMU_PWR_CON(0x%x), 0x%x\n", 2739fd9f1d0Sshengfei Xu PMU_PWR_CON, mmio_read_32(PMU_BASE + PMU_PWR_CON)); 2749fd9f1d0Sshengfei Xu } 2759fd9f1d0Sshengfei Xu 2769fd9f1d0Sshengfei Xu static void pvtm_32k_config(void) 2779fd9f1d0Sshengfei Xu { 2789fd9f1d0Sshengfei Xu uint32_t pmu_cru_pwr_con; 2799fd9f1d0Sshengfei Xu uint32_t pvtm_freq_khz, pvtm_div; 2809fd9f1d0Sshengfei Xu 2819fd9f1d0Sshengfei Xu mmio_write_32(PMUCRU_BASE + PMUCRU_PMUGATE_CON01, 0x38000000); 2829fd9f1d0Sshengfei Xu mmio_write_32(PMUPVTM_BASE + PVTM_CON0, 0x00020002); 2839fd9f1d0Sshengfei Xu dsb(); 2849fd9f1d0Sshengfei Xu 2859fd9f1d0Sshengfei Xu mmio_write_32(PMUPVTM_BASE + PVTM_CON0, 0x001c0000); 2869fd9f1d0Sshengfei Xu 2879fd9f1d0Sshengfei Xu mmio_write_32(PMUPVTM_BASE + PVTM_CON1, PVTM_CALC_CNT); 2889fd9f1d0Sshengfei Xu dsb(); 2899fd9f1d0Sshengfei Xu 2909fd9f1d0Sshengfei Xu mmio_write_32(PMUPVTM_BASE + PVTM_CON0, 0x00010001); 2919fd9f1d0Sshengfei Xu dsb(); 2929fd9f1d0Sshengfei Xu 2939fd9f1d0Sshengfei Xu while (mmio_read_32(PMUPVTM_BASE + PVTM_STATUS1) < 30) { 2949fd9f1d0Sshengfei Xu ; 2959fd9f1d0Sshengfei Xu } 2969fd9f1d0Sshengfei Xu 2979fd9f1d0Sshengfei Xu dsb(); 2989fd9f1d0Sshengfei Xu while (!(mmio_read_32(PMUPVTM_BASE + PVTM_STATUS0) & 0x1)) { 2999fd9f1d0Sshengfei Xu ; 3009fd9f1d0Sshengfei Xu } 3019fd9f1d0Sshengfei Xu 3029fd9f1d0Sshengfei Xu pvtm_freq_khz = (mmio_read_32(PMUPVTM_BASE + PVTM_STATUS1) * 24000 + 3039fd9f1d0Sshengfei Xu PVTM_CALC_CNT / 2) / PVTM_CALC_CNT; 3049fd9f1d0Sshengfei Xu pvtm_div = (pvtm_freq_khz + 16) / 32; 3059fd9f1d0Sshengfei Xu 3069fd9f1d0Sshengfei Xu mmio_write_32(PMUGRF_BASE + PMU_GRF_DLL_CON0, pvtm_div); 3079fd9f1d0Sshengfei Xu 3089fd9f1d0Sshengfei Xu mmio_write_32(PMUCRU_BASE + PMUCRU_PMUCLKSEL_CON00, 0x00c00000); 3099fd9f1d0Sshengfei Xu 3109fd9f1d0Sshengfei Xu pmu_cru_pwr_con = BIT(ALIVE_32K_ENA) | BIT(OSC_DIS_ENA); 3119fd9f1d0Sshengfei Xu 3129fd9f1d0Sshengfei Xu mmio_write_32(PMU_BASE + PMU_WAKEUP_TIMEOUT_CNT, 32000 * 10); 3139fd9f1d0Sshengfei Xu 3149fd9f1d0Sshengfei Xu mmio_write_32(PMU_BASE + PMU_CRU_PWR_CON, WRITE_MASK_SET(pmu_cru_pwr_con)); 3159fd9f1d0Sshengfei Xu INFO("PVTM: PMU_CRU_PWR_CON(0x0%x): 0x%x\n", 3169fd9f1d0Sshengfei Xu PMU_CRU_PWR_CON, mmio_read_32(PMU_BASE + PMU_CRU_PWR_CON)); 3179fd9f1d0Sshengfei Xu } 3189fd9f1d0Sshengfei Xu 3199fd9f1d0Sshengfei Xu static void pmu_cru_suspendmode_config(void) 3209fd9f1d0Sshengfei Xu { 3219fd9f1d0Sshengfei Xu uint32_t pmu_cru_pwr_con; 3229fd9f1d0Sshengfei Xu 3239fd9f1d0Sshengfei Xu pmu_cru_pwr_con = BIT(ALIVE_OSC_ENA); 3249fd9f1d0Sshengfei Xu 3259fd9f1d0Sshengfei Xu mmio_write_32(PMU_BASE + PMU_CRU_PWR_CON, WRITE_MASK_SET(pmu_cru_pwr_con)); 3269fd9f1d0Sshengfei Xu INFO("CRU: PMU_CRU_PWR_CON(0x0%x): 0x%x\n", 3279fd9f1d0Sshengfei Xu PMU_CRU_PWR_CON, mmio_read_32(PMU_BASE + PMU_CRU_PWR_CON)); 3289fd9f1d0Sshengfei Xu } 3299fd9f1d0Sshengfei Xu 3309fd9f1d0Sshengfei Xu static void pmu_suspend_cru_fsm(void) 3319fd9f1d0Sshengfei Xu { 3329fd9f1d0Sshengfei Xu pmu_pmic_sleep_mode_config(); 3339fd9f1d0Sshengfei Xu 3349fd9f1d0Sshengfei Xu /* Global interrupt disable */ 3359fd9f1d0Sshengfei Xu mmio_write_32(PMU_BASE + PMU_INT_MASK_CON, CLB_INT_DISABLE); 3369fd9f1d0Sshengfei Xu mmio_write_32(PMU_BASE + PMU_PWR_CON, CPUS_BYPASS); 3379fd9f1d0Sshengfei Xu 3389fd9f1d0Sshengfei Xu pmu_stable_count_config(); 3399fd9f1d0Sshengfei Xu pmu_wakeup_source_config(); 3409fd9f1d0Sshengfei Xu mmio_write_32(PMU_BASE + PMU_WAKEUP_TIMEOUT_CNT, 0x5dc0 * 20000); 3419fd9f1d0Sshengfei Xu /* default cru config */ 3429fd9f1d0Sshengfei Xu mmio_write_32(PMU_BASE + PMU_CRU_PWR_CON, WRITE_MASK_SET(BIT(ALIVE_OSC_ENA))); 3439fd9f1d0Sshengfei Xu 3449fd9f1d0Sshengfei Xu pmu_cru_suspendmode_config(); 3459fd9f1d0Sshengfei Xu pmu_cpu_powerdown_config(); 3469fd9f1d0Sshengfei Xu pmu_pll_powerdown_config(); 3479fd9f1d0Sshengfei Xu pmu_pd_powerdown_config(); 3489fd9f1d0Sshengfei Xu pmu_ddr_suspend_config(); 3499fd9f1d0Sshengfei Xu pmu_dsu_suspend_config(); 3509fd9f1d0Sshengfei Xu pvtm_32k_config(); 3519fd9f1d0Sshengfei Xu mmio_write_32(PMU_BASE + PMU_PWR_CON, 0x00010001); 3529fd9f1d0Sshengfei Xu } 3539fd9f1d0Sshengfei Xu 3549fd9f1d0Sshengfei Xu static void pmu_reinit(void) 3559fd9f1d0Sshengfei Xu { 3569fd9f1d0Sshengfei Xu mmio_write_32(DDRGRF_BASE + GRF_DDR_CON3, grf_ddr_con3 | 0xffff0000); 3579fd9f1d0Sshengfei Xu mmio_write_32(PMU_BASE + PMU_PWR_CON, 0xffff0000); 3589fd9f1d0Sshengfei Xu mmio_write_32(PMU_BASE + PMU_INT_MASK_CON, 0xffff0000); 3599fd9f1d0Sshengfei Xu mmio_write_32(PMU_BASE + PMU_WAKEUP_INT_CON, 0xffff0000); 3609fd9f1d0Sshengfei Xu mmio_write_32(PMU_BASE + PMU_BUS_IDLE_CON0, 0xffff0000); 3619fd9f1d0Sshengfei Xu mmio_write_32(PMU_BASE + PMU_DDR_PWR_CON, 0xffff0000); 3629fd9f1d0Sshengfei Xu mmio_write_32(PMU_BASE + PMU_BUS_IDLE_CON1, 0xffff0000); 3639fd9f1d0Sshengfei Xu 3649fd9f1d0Sshengfei Xu mmio_write_32(PMU_BASE + PMU_PWR_GATE_CON, 0xffff0000); 3659fd9f1d0Sshengfei Xu mmio_write_32(PMU_BASE + PMU_VOL_GATE_SFTCON, 0xffff0000); 3669fd9f1d0Sshengfei Xu mmio_write_32(PMU_BASE + PMU_CRU_PWR_CON, 0xffff0000); 3679fd9f1d0Sshengfei Xu 3689fd9f1d0Sshengfei Xu mmio_write_32(PMU_BASE + PMU_PLLPD_CON, 0xffff0000); 3699fd9f1d0Sshengfei Xu mmio_write_32(PMU_BASE + PMU_INFO_TX_CON, 0xffff0000); 3709fd9f1d0Sshengfei Xu mmio_write_32(PMU_BASE + PMU_DSU_PWR_CON, 0xffff0000); 3719fd9f1d0Sshengfei Xu mmio_write_32(PMU_BASE + PMU_CLUSTER_IDLE_CON, 0xffff0000); 3729fd9f1d0Sshengfei Xu } 3739fd9f1d0Sshengfei Xu 3749fd9f1d0Sshengfei Xu void rockchip_plat_mmu_el3(void) 3759fd9f1d0Sshengfei Xu { 3769fd9f1d0Sshengfei Xu } 3779fd9f1d0Sshengfei Xu 3789fd9f1d0Sshengfei Xu int rockchip_soc_cores_pwr_dm_suspend(void) 3799fd9f1d0Sshengfei Xu { 3809fd9f1d0Sshengfei Xu return 0; 3819fd9f1d0Sshengfei Xu } 3829fd9f1d0Sshengfei Xu 3839fd9f1d0Sshengfei Xu int rockchip_soc_cores_pwr_dm_resume(void) 3849fd9f1d0Sshengfei Xu { 3859fd9f1d0Sshengfei Xu return 0; 3869fd9f1d0Sshengfei Xu } 3879fd9f1d0Sshengfei Xu 3889fd9f1d0Sshengfei Xu int rockchip_soc_sys_pwr_dm_suspend(void) 3899fd9f1d0Sshengfei Xu { 390*4e1ccc60SShengfei Xu pvtplls_suspend(); 3919fd9f1d0Sshengfei Xu psram_sleep_cfg->pm_flag = 0; 3929fd9f1d0Sshengfei Xu flush_dcache_range((uintptr_t)&(psram_sleep_cfg->pm_flag), 3939fd9f1d0Sshengfei Xu sizeof(uint32_t)); 3949fd9f1d0Sshengfei Xu pmu_suspend_cru_fsm(); 3959fd9f1d0Sshengfei Xu 3969fd9f1d0Sshengfei Xu return 0; 3979fd9f1d0Sshengfei Xu } 3989fd9f1d0Sshengfei Xu 3999fd9f1d0Sshengfei Xu int rockchip_soc_sys_pwr_dm_resume(void) 4009fd9f1d0Sshengfei Xu { 401*4e1ccc60SShengfei Xu pvtplls_resume(); 4029fd9f1d0Sshengfei Xu pmu_reinit(); 4039fd9f1d0Sshengfei Xu plat_rockchip_gic_cpuif_enable(); 4049fd9f1d0Sshengfei Xu psram_sleep_cfg->pm_flag = PM_WARM_BOOT_BIT; 4059fd9f1d0Sshengfei Xu flush_dcache_range((uintptr_t)&(psram_sleep_cfg->pm_flag), 4069fd9f1d0Sshengfei Xu sizeof(uint32_t)); 4079fd9f1d0Sshengfei Xu 4089fd9f1d0Sshengfei Xu return 0; 4099fd9f1d0Sshengfei Xu } 4109fd9f1d0Sshengfei Xu 4119fd9f1d0Sshengfei Xu static int cpus_power_domain_off(uint32_t cpu_id, uint32_t pd_cfg) 4129fd9f1d0Sshengfei Xu { 4139fd9f1d0Sshengfei Xu uint32_t apm_value, offset, idx; 4149fd9f1d0Sshengfei Xu 4159fd9f1d0Sshengfei Xu apm_value = BIT(core_pm_en) | BIT(core_pm_int_wakeup_glb_msk); 4169fd9f1d0Sshengfei Xu 4179fd9f1d0Sshengfei Xu if (pd_cfg == core_pwr_wfi_int) { 4189fd9f1d0Sshengfei Xu apm_value |= BIT(core_pm_int_wakeup_en); 4199fd9f1d0Sshengfei Xu } 4209fd9f1d0Sshengfei Xu 4219fd9f1d0Sshengfei Xu idx = cpu_id / 2; 4229fd9f1d0Sshengfei Xu offset = (cpu_id % 2) << 3; 4239fd9f1d0Sshengfei Xu 4249fd9f1d0Sshengfei Xu mmio_write_32(PMU_BASE + PMU_CPUAPM_CON(idx), 4259fd9f1d0Sshengfei Xu BITS_WITH_WMASK(apm_value, 0xf, offset)); 4269fd9f1d0Sshengfei Xu dsb(); 4279fd9f1d0Sshengfei Xu 4289fd9f1d0Sshengfei Xu return 0; 4299fd9f1d0Sshengfei Xu } 4309fd9f1d0Sshengfei Xu 4319fd9f1d0Sshengfei Xu static int cpus_power_domain_on(uint32_t cpu_id) 4329fd9f1d0Sshengfei Xu { 4339fd9f1d0Sshengfei Xu uint32_t offset, idx; 4349fd9f1d0Sshengfei Xu 4359fd9f1d0Sshengfei Xu idx = cpu_id / 2; 4369fd9f1d0Sshengfei Xu offset = (cpu_id % 2) << 3; 4379fd9f1d0Sshengfei Xu 4389fd9f1d0Sshengfei Xu mmio_write_32(PMU_BASE + PMU_CPUAPM_CON(idx), 4399fd9f1d0Sshengfei Xu WMSK_BIT(core_pm_en + offset)); 4409fd9f1d0Sshengfei Xu mmio_write_32(PMU_BASE + PMU_CPUAPM_CON(idx), 4419fd9f1d0Sshengfei Xu BIT_WITH_WMSK(core_pm_sft_wakeup_en + offset)); 4429fd9f1d0Sshengfei Xu dsb(); 4439fd9f1d0Sshengfei Xu 4449fd9f1d0Sshengfei Xu return 0; 4459fd9f1d0Sshengfei Xu } 4469fd9f1d0Sshengfei Xu 4479fd9f1d0Sshengfei Xu int rockchip_soc_cores_pwr_dm_on(unsigned long mpidr, uint64_t entrypoint) 4489fd9f1d0Sshengfei Xu { 4499fd9f1d0Sshengfei Xu uint32_t cpu_id = plat_core_pos_by_mpidr(mpidr); 4509fd9f1d0Sshengfei Xu 4519fd9f1d0Sshengfei Xu assert(cpu_id < PLATFORM_CORE_COUNT); 4529fd9f1d0Sshengfei Xu 4539fd9f1d0Sshengfei Xu cpuson_flags[cpu_id] = PMU_CPU_HOTPLUG; 4549fd9f1d0Sshengfei Xu cpuson_entry_point[cpu_id] = entrypoint; 4559fd9f1d0Sshengfei Xu flush_dcache_range((uintptr_t)cpuson_flags, sizeof(cpuson_flags)); 4569fd9f1d0Sshengfei Xu flush_dcache_range((uintptr_t)cpuson_entry_point, 4579fd9f1d0Sshengfei Xu sizeof(cpuson_entry_point)); 4589fd9f1d0Sshengfei Xu 4599fd9f1d0Sshengfei Xu cpus_power_domain_on(cpu_id); 4609fd9f1d0Sshengfei Xu return 0; 4619fd9f1d0Sshengfei Xu } 4629fd9f1d0Sshengfei Xu 4639fd9f1d0Sshengfei Xu int rockchip_soc_cores_pwr_dm_off(void) 4649fd9f1d0Sshengfei Xu { 4659fd9f1d0Sshengfei Xu uint32_t cpu_id = plat_my_core_pos(); 4669fd9f1d0Sshengfei Xu 4679fd9f1d0Sshengfei Xu cpus_power_domain_off(cpu_id, 4689fd9f1d0Sshengfei Xu core_pwr_wfi); 4699fd9f1d0Sshengfei Xu return 0; 4709fd9f1d0Sshengfei Xu } 4719fd9f1d0Sshengfei Xu 4729fd9f1d0Sshengfei Xu int rockchip_soc_cores_pwr_dm_on_finish(void) 4739fd9f1d0Sshengfei Xu { 4749fd9f1d0Sshengfei Xu uint32_t cpu_id = plat_my_core_pos(); 4759fd9f1d0Sshengfei Xu uint32_t offset, idx; 4769fd9f1d0Sshengfei Xu 4779fd9f1d0Sshengfei Xu /* Disable core_pm */ 4789fd9f1d0Sshengfei Xu idx = cpu_id / 2; 4799fd9f1d0Sshengfei Xu offset = (cpu_id % 2) << 3; 4809fd9f1d0Sshengfei Xu mmio_write_32(PMU_BASE + PMU_CPUAPM_CON(idx), 4819fd9f1d0Sshengfei Xu BITS_WITH_WMASK(0, 0xf, offset)); 4829fd9f1d0Sshengfei Xu 4839fd9f1d0Sshengfei Xu return 0; 4849fd9f1d0Sshengfei Xu } 4859fd9f1d0Sshengfei Xu 4869fd9f1d0Sshengfei Xu static void nonboot_cpus_off(void) 4879fd9f1d0Sshengfei Xu { 4889fd9f1d0Sshengfei Xu uint32_t tmp; 4899fd9f1d0Sshengfei Xu 4909fd9f1d0Sshengfei Xu cpus_power_domain_off(1, 0); 4919fd9f1d0Sshengfei Xu cpus_power_domain_off(2, 0); 4929fd9f1d0Sshengfei Xu cpus_power_domain_off(3, 0); 4939fd9f1d0Sshengfei Xu 4949fd9f1d0Sshengfei Xu mmio_write_32(SYSSRAM_BASE + 0x04, 0xdeadbeaf); 4959fd9f1d0Sshengfei Xu mmio_write_32(SYSSRAM_BASE + 0x08, (uintptr_t)&rockchip_soc_sys_pd_pwr_dn_wfi); 4969fd9f1d0Sshengfei Xu sev(); 4979fd9f1d0Sshengfei Xu 4989fd9f1d0Sshengfei Xu do { 4999fd9f1d0Sshengfei Xu tmp = mmio_read_32(PMU_BASE + PMU_CLUSTER_PWR_ST); 5009fd9f1d0Sshengfei Xu } while ((tmp & 0xe) != 0xe); 5019fd9f1d0Sshengfei Xu } 5029fd9f1d0Sshengfei Xu 5039fd9f1d0Sshengfei Xu void plat_rockchip_pmu_init(void) 5049fd9f1d0Sshengfei Xu { 5059fd9f1d0Sshengfei Xu uint32_t cpu; 5069fd9f1d0Sshengfei Xu 5079fd9f1d0Sshengfei Xu rockchip_pd_lock_init(); 5089fd9f1d0Sshengfei Xu nonboot_cpus_off(); 5099fd9f1d0Sshengfei Xu for (cpu = 0; cpu < PLATFORM_CORE_COUNT; cpu++) 5109fd9f1d0Sshengfei Xu cpuson_flags[cpu] = PMU_CPU_HOTPLUG; 5119fd9f1d0Sshengfei Xu 5129fd9f1d0Sshengfei Xu psram_sleep_cfg->ddr_data = (uint64_t)0; 5139fd9f1d0Sshengfei Xu psram_sleep_cfg->sp = PSRAM_SP_TOP; 5149fd9f1d0Sshengfei Xu psram_sleep_cfg->ddr_flag = 0x00; 5159fd9f1d0Sshengfei Xu psram_sleep_cfg->boot_mpidr = read_mpidr_el1() & 0xffff; 5169fd9f1d0Sshengfei Xu psram_sleep_cfg->pm_flag = PM_WARM_BOOT_BIT; 5179fd9f1d0Sshengfei Xu 5189fd9f1d0Sshengfei Xu /* 5199fd9f1d0Sshengfei Xu * When perform idle operation, corresponding clock can be 5209fd9f1d0Sshengfei Xu * opened or gated automatically. 5219fd9f1d0Sshengfei Xu */ 5229fd9f1d0Sshengfei Xu mmio_write_32(PMU_BASE + PMU_NOC_AUTO_CON0, 0xffffffff); 5239fd9f1d0Sshengfei Xu mmio_write_32(PMU_BASE + PMU_NOC_AUTO_CON1, 0x00070007); 5249fd9f1d0Sshengfei Xu 5259fd9f1d0Sshengfei Xu /* grf_con_pmic_sleep_sel 5269fd9f1d0Sshengfei Xu * pmic sleep function selection 5279fd9f1d0Sshengfei Xu * 1'b0: From reset pulse generator, can reset external PMIC 5289fd9f1d0Sshengfei Xu * 1'b1: From pmu block, only support sleep function for external PMIC 5299fd9f1d0Sshengfei Xu */ 5309fd9f1d0Sshengfei Xu mmio_write_32(PMUGRF_BASE + PMU_GRF_SOC_CON(0), 0x00800080); 5319fd9f1d0Sshengfei Xu 5329fd9f1d0Sshengfei Xu /* 5339fd9f1d0Sshengfei Xu * force jtag control 5349fd9f1d0Sshengfei Xu * 1'b0: CPU debug port IO mux is controlled by sdmmc_detect_en status 5359fd9f1d0Sshengfei Xu * 1'b0: CPU debug port IO mux IS controlled by GRF 5369fd9f1d0Sshengfei Xu */ 5379fd9f1d0Sshengfei Xu mmio_write_32(SGRF_BASE + 0x008, 0x00100000); 5389fd9f1d0Sshengfei Xu 5399fd9f1d0Sshengfei Xu /* 5409fd9f1d0Sshengfei Xu * remap 5419fd9f1d0Sshengfei Xu * 2'b00: Boot from boot-rom. 5429fd9f1d0Sshengfei Xu * 2'b01: Boot from pmu mem. 5439fd9f1d0Sshengfei Xu * 2'b10: Boot from sys mem. 5449fd9f1d0Sshengfei Xu */ 5459fd9f1d0Sshengfei Xu mmio_write_32(PMUSGRF_BASE + PMU_SGRF_SOC_CON1, 0x18000800); 5469fd9f1d0Sshengfei Xu } 547