1*6fba6e04STony Xie /* 2*6fba6e04STony Xie * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved. 3*6fba6e04STony Xie * 4*6fba6e04STony Xie * Redistribution and use in source and binary forms, with or without 5*6fba6e04STony Xie * modification, are permitted provided that the following conditions are met: 6*6fba6e04STony Xie * 7*6fba6e04STony Xie * Redistributions of source code must retain the above copyright notice, this 8*6fba6e04STony Xie * list of conditions and the following disclaimer. 9*6fba6e04STony Xie * 10*6fba6e04STony Xie * Redistributions in binary form must reproduce the above copyright notice, 11*6fba6e04STony Xie * this list of conditions and the following disclaimer in the documentation 12*6fba6e04STony Xie * and/or other materials provided with the distribution. 13*6fba6e04STony Xie * 14*6fba6e04STony Xie * Neither the name of ARM nor the names of its contributors may be used 15*6fba6e04STony Xie * to endorse or promote products derived from this software without specific 16*6fba6e04STony Xie * prior written permission. 17*6fba6e04STony Xie * 18*6fba6e04STony Xie * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19*6fba6e04STony Xie * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20*6fba6e04STony Xie * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21*6fba6e04STony Xie * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 22*6fba6e04STony Xie * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23*6fba6e04STony Xie * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24*6fba6e04STony Xie * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25*6fba6e04STony Xie * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 26*6fba6e04STony Xie * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27*6fba6e04STony Xie * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28*6fba6e04STony Xie * POSSIBILITY OF SUCH DAMAGE. 29*6fba6e04STony Xie */ 30*6fba6e04STony Xie 31*6fba6e04STony Xie #include <arch_helpers.h> 32*6fba6e04STony Xie #include <assert.h> 33*6fba6e04STony Xie #include <bakery_lock.h> 34*6fba6e04STony Xie #include <debug.h> 35*6fba6e04STony Xie #include <delay_timer.h> 36*6fba6e04STony Xie #include <errno.h> 37*6fba6e04STony Xie #include <mmio.h> 38*6fba6e04STony Xie #include <platform.h> 39*6fba6e04STony Xie #include <platform_def.h> 40*6fba6e04STony Xie #include <plat_private.h> 41*6fba6e04STony Xie #include <rk3399_def.h> 42*6fba6e04STony Xie #include <pmu_sram.h> 43*6fba6e04STony Xie #include <soc.h> 44*6fba6e04STony Xie #include <pmu.h> 45*6fba6e04STony Xie #include <pmu_com.h> 46*6fba6e04STony Xie 47*6fba6e04STony Xie static struct psram_data_t *psram_sleep_cfg = 48*6fba6e04STony Xie (struct psram_data_t *)PSRAM_DT_BASE; 49*6fba6e04STony Xie 50*6fba6e04STony Xie /* 51*6fba6e04STony Xie * There are two ways to powering on or off on core. 52*6fba6e04STony Xie * 1) Control it power domain into on or off in PMU_PWRDN_CON reg, 53*6fba6e04STony Xie * it is core_pwr_pd mode 54*6fba6e04STony Xie * 2) Enable the core power manage in PMU_CORE_PM_CON reg, 55*6fba6e04STony Xie * then, if the core enter into wfi, it power domain will be 56*6fba6e04STony Xie * powered off automatically. it is core_pwr_wfi or core_pwr_wfi_int mode 57*6fba6e04STony Xie * so we need core_pm_cfg_info to distinguish which method be used now. 58*6fba6e04STony Xie */ 59*6fba6e04STony Xie 60*6fba6e04STony Xie static uint32_t core_pm_cfg_info[PLATFORM_CORE_COUNT] 61*6fba6e04STony Xie #if USE_COHERENT_MEM 62*6fba6e04STony Xie __attribute__ ((section("tzfw_coherent_mem"))) 63*6fba6e04STony Xie #endif 64*6fba6e04STony Xie ;/* coheront */ 65*6fba6e04STony Xie 66*6fba6e04STony Xie void plat_rockchip_pmusram_prepare(void) 67*6fba6e04STony Xie { 68*6fba6e04STony Xie uint32_t *sram_dst, *sram_src; 69*6fba6e04STony Xie size_t sram_size = 2; 70*6fba6e04STony Xie 71*6fba6e04STony Xie /* 72*6fba6e04STony Xie * pmu sram code and data prepare 73*6fba6e04STony Xie */ 74*6fba6e04STony Xie sram_dst = (uint32_t *)PMUSRAM_BASE; 75*6fba6e04STony Xie sram_src = (uint32_t *)&pmu_cpuson_entrypoint_start; 76*6fba6e04STony Xie sram_size = (uint32_t *)&pmu_cpuson_entrypoint_end - 77*6fba6e04STony Xie (uint32_t *)sram_src; 78*6fba6e04STony Xie 79*6fba6e04STony Xie u32_align_cpy(sram_dst, sram_src, sram_size); 80*6fba6e04STony Xie 81*6fba6e04STony Xie psram_sleep_cfg->sp = PSRAM_DT_BASE; 82*6fba6e04STony Xie } 83*6fba6e04STony Xie 84*6fba6e04STony Xie static inline uint32_t get_cpus_pwr_domain_cfg_info(uint32_t cpu_id) 85*6fba6e04STony Xie { 86*6fba6e04STony Xie return core_pm_cfg_info[cpu_id]; 87*6fba6e04STony Xie } 88*6fba6e04STony Xie 89*6fba6e04STony Xie static inline void set_cpus_pwr_domain_cfg_info(uint32_t cpu_id, uint32_t value) 90*6fba6e04STony Xie { 91*6fba6e04STony Xie core_pm_cfg_info[cpu_id] = value; 92*6fba6e04STony Xie #if !USE_COHERENT_MEM 93*6fba6e04STony Xie flush_dcache_range((uintptr_t)&core_pm_cfg_info[cpu_id], 94*6fba6e04STony Xie sizeof(uint32_t)); 95*6fba6e04STony Xie #endif 96*6fba6e04STony Xie } 97*6fba6e04STony Xie 98*6fba6e04STony Xie static int cpus_power_domain_on(uint32_t cpu_id) 99*6fba6e04STony Xie { 100*6fba6e04STony Xie uint32_t cfg_info; 101*6fba6e04STony Xie uint32_t cpu_pd = PD_CPUL0 + cpu_id; 102*6fba6e04STony Xie /* 103*6fba6e04STony Xie * There are two ways to powering on or off on core. 104*6fba6e04STony Xie * 1) Control it power domain into on or off in PMU_PWRDN_CON reg 105*6fba6e04STony Xie * 2) Enable the core power manage in PMU_CORE_PM_CON reg, 106*6fba6e04STony Xie * then, if the core enter into wfi, it power domain will be 107*6fba6e04STony Xie * powered off automatically. 108*6fba6e04STony Xie */ 109*6fba6e04STony Xie 110*6fba6e04STony Xie cfg_info = get_cpus_pwr_domain_cfg_info(cpu_id); 111*6fba6e04STony Xie 112*6fba6e04STony Xie if (cfg_info == core_pwr_pd) { 113*6fba6e04STony Xie /* disable core_pm cfg */ 114*6fba6e04STony Xie mmio_write_32(PMU_BASE + PMU_CORE_PM_CON(cpu_id), 115*6fba6e04STony Xie CORES_PM_DISABLE); 116*6fba6e04STony Xie /* if the cores have be on, power off it firstly */ 117*6fba6e04STony Xie if (pmu_power_domain_st(cpu_pd) == pmu_pd_on) { 118*6fba6e04STony Xie mmio_write_32(PMU_BASE + PMU_CORE_PM_CON(cpu_id), 0); 119*6fba6e04STony Xie pmu_power_domain_ctr(cpu_pd, pmu_pd_off); 120*6fba6e04STony Xie } 121*6fba6e04STony Xie 122*6fba6e04STony Xie pmu_power_domain_ctr(cpu_pd, pmu_pd_on); 123*6fba6e04STony Xie } else { 124*6fba6e04STony Xie if (pmu_power_domain_st(cpu_pd) == pmu_pd_on) { 125*6fba6e04STony Xie WARN("%s: cpu%d is not in off,!\n", __func__, cpu_id); 126*6fba6e04STony Xie return -EINVAL; 127*6fba6e04STony Xie } 128*6fba6e04STony Xie 129*6fba6e04STony Xie mmio_write_32(PMU_BASE + PMU_CORE_PM_CON(cpu_id), 130*6fba6e04STony Xie BIT(core_pm_sft_wakeup_en)); 131*6fba6e04STony Xie } 132*6fba6e04STony Xie 133*6fba6e04STony Xie return 0; 134*6fba6e04STony Xie } 135*6fba6e04STony Xie 136*6fba6e04STony Xie static int cpus_power_domain_off(uint32_t cpu_id, uint32_t pd_cfg) 137*6fba6e04STony Xie { 138*6fba6e04STony Xie uint32_t cpu_pd; 139*6fba6e04STony Xie uint32_t core_pm_value; 140*6fba6e04STony Xie 141*6fba6e04STony Xie cpu_pd = PD_CPUL0 + cpu_id; 142*6fba6e04STony Xie if (pmu_power_domain_st(cpu_pd) == pmu_pd_off) 143*6fba6e04STony Xie return 0; 144*6fba6e04STony Xie 145*6fba6e04STony Xie if (pd_cfg == core_pwr_pd) { 146*6fba6e04STony Xie if (check_cpu_wfie(cpu_id, CKECK_WFEI_MSK)) 147*6fba6e04STony Xie return -EINVAL; 148*6fba6e04STony Xie 149*6fba6e04STony Xie /* disable core_pm cfg */ 150*6fba6e04STony Xie mmio_write_32(PMU_BASE + PMU_CORE_PM_CON(cpu_id), 151*6fba6e04STony Xie CORES_PM_DISABLE); 152*6fba6e04STony Xie 153*6fba6e04STony Xie set_cpus_pwr_domain_cfg_info(cpu_id, pd_cfg); 154*6fba6e04STony Xie pmu_power_domain_ctr(cpu_pd, pmu_pd_off); 155*6fba6e04STony Xie } else { 156*6fba6e04STony Xie set_cpus_pwr_domain_cfg_info(cpu_id, pd_cfg); 157*6fba6e04STony Xie 158*6fba6e04STony Xie core_pm_value = BIT(core_pm_en); 159*6fba6e04STony Xie if (pd_cfg == core_pwr_wfi_int) 160*6fba6e04STony Xie core_pm_value |= BIT(core_pm_int_wakeup_en); 161*6fba6e04STony Xie mmio_write_32(PMU_BASE + PMU_CORE_PM_CON(cpu_id), 162*6fba6e04STony Xie core_pm_value); 163*6fba6e04STony Xie } 164*6fba6e04STony Xie 165*6fba6e04STony Xie return 0; 166*6fba6e04STony Xie } 167*6fba6e04STony Xie 168*6fba6e04STony Xie static void nonboot_cpus_off(void) 169*6fba6e04STony Xie { 170*6fba6e04STony Xie uint32_t boot_cpu, cpu; 171*6fba6e04STony Xie 172*6fba6e04STony Xie boot_cpu = plat_my_core_pos(); 173*6fba6e04STony Xie 174*6fba6e04STony Xie /* turn off noboot cpus */ 175*6fba6e04STony Xie for (cpu = 0; cpu < PLATFORM_CORE_COUNT; cpu++) { 176*6fba6e04STony Xie if (cpu == boot_cpu) 177*6fba6e04STony Xie continue; 178*6fba6e04STony Xie cpus_power_domain_off(cpu, core_pwr_pd); 179*6fba6e04STony Xie } 180*6fba6e04STony Xie } 181*6fba6e04STony Xie 182*6fba6e04STony Xie static int cores_pwr_domain_on(unsigned long mpidr, uint64_t entrypoint) 183*6fba6e04STony Xie { 184*6fba6e04STony Xie uint32_t cpu_id = plat_core_pos_by_mpidr(mpidr); 185*6fba6e04STony Xie 186*6fba6e04STony Xie assert(cpuson_flags[cpu_id] == 0); 187*6fba6e04STony Xie cpuson_flags[cpu_id] = PMU_CPU_HOTPLUG; 188*6fba6e04STony Xie cpuson_entry_point[cpu_id] = entrypoint; 189*6fba6e04STony Xie dsb(); 190*6fba6e04STony Xie 191*6fba6e04STony Xie cpus_power_domain_on(cpu_id); 192*6fba6e04STony Xie 193*6fba6e04STony Xie return 0; 194*6fba6e04STony Xie } 195*6fba6e04STony Xie 196*6fba6e04STony Xie static int cores_pwr_domain_off(void) 197*6fba6e04STony Xie { 198*6fba6e04STony Xie uint32_t cpu_id = plat_my_core_pos(); 199*6fba6e04STony Xie 200*6fba6e04STony Xie cpus_power_domain_off(cpu_id, core_pwr_wfi); 201*6fba6e04STony Xie 202*6fba6e04STony Xie return 0; 203*6fba6e04STony Xie } 204*6fba6e04STony Xie 205*6fba6e04STony Xie static int cores_pwr_domain_suspend(void) 206*6fba6e04STony Xie { 207*6fba6e04STony Xie uint32_t cpu_id = plat_my_core_pos(); 208*6fba6e04STony Xie 209*6fba6e04STony Xie assert(cpuson_flags[cpu_id] == 0); 210*6fba6e04STony Xie cpuson_flags[cpu_id] = PMU_CPU_AUTO_PWRDN; 211*6fba6e04STony Xie cpuson_entry_point[cpu_id] = (uintptr_t)psci_entrypoint; 212*6fba6e04STony Xie dsb(); 213*6fba6e04STony Xie 214*6fba6e04STony Xie cpus_power_domain_off(cpu_id, core_pwr_wfi_int); 215*6fba6e04STony Xie 216*6fba6e04STony Xie return 0; 217*6fba6e04STony Xie } 218*6fba6e04STony Xie 219*6fba6e04STony Xie static int cores_pwr_domain_on_finish(void) 220*6fba6e04STony Xie { 221*6fba6e04STony Xie uint32_t cpu_id = plat_my_core_pos(); 222*6fba6e04STony Xie 223*6fba6e04STony Xie cpuson_flags[cpu_id] = 0; 224*6fba6e04STony Xie cpuson_entry_point[cpu_id] = 0; 225*6fba6e04STony Xie 226*6fba6e04STony Xie /* Disable core_pm */ 227*6fba6e04STony Xie mmio_write_32(PMU_BASE + PMU_CORE_PM_CON(cpu_id), CORES_PM_DISABLE); 228*6fba6e04STony Xie 229*6fba6e04STony Xie return 0; 230*6fba6e04STony Xie } 231*6fba6e04STony Xie 232*6fba6e04STony Xie static int cores_pwr_domain_resume(void) 233*6fba6e04STony Xie { 234*6fba6e04STony Xie uint32_t cpu_id = plat_my_core_pos(); 235*6fba6e04STony Xie 236*6fba6e04STony Xie cpuson_flags[cpu_id] = 0; 237*6fba6e04STony Xie cpuson_entry_point[cpu_id] = 0; 238*6fba6e04STony Xie 239*6fba6e04STony Xie /* Disable core_pm */ 240*6fba6e04STony Xie mmio_write_32(PMU_BASE + PMU_CORE_PM_CON(cpu_id), CORES_PM_DISABLE); 241*6fba6e04STony Xie 242*6fba6e04STony Xie return 0; 243*6fba6e04STony Xie } 244*6fba6e04STony Xie 245*6fba6e04STony Xie static void sys_slp_config(void) 246*6fba6e04STony Xie { 247*6fba6e04STony Xie uint32_t slp_mode_cfg = 0; 248*6fba6e04STony Xie 249*6fba6e04STony Xie slp_mode_cfg = PMU_PWR_MODE_EN | 250*6fba6e04STony Xie PMU_CPU0_PD_EN | 251*6fba6e04STony Xie PMU_L2_FLUSH_EN | 252*6fba6e04STony Xie PMU_L2_IDLE_EN | 253*6fba6e04STony Xie PMU_SCU_PD_EN | 254*6fba6e04STony Xie PMU_CLK_CORE_SRC_GATE_EN; 255*6fba6e04STony Xie mmio_setbits_32(PMU_BASE + PMU_WKUP_CFG4, PMU_CLUSTER_L_WKUP_EN); 256*6fba6e04STony Xie mmio_setbits_32(PMU_BASE + PMU_WKUP_CFG4, PMU_CLUSTER_B_WKUP_EN); 257*6fba6e04STony Xie mmio_clrbits_32(PMU_BASE + PMU_WKUP_CFG4, PMU_GPIO_WKUP_EN); 258*6fba6e04STony Xie mmio_write_32(PMU_BASE + PMU_PWRMODE_CON, slp_mode_cfg); 259*6fba6e04STony Xie } 260*6fba6e04STony Xie 261*6fba6e04STony Xie static int sys_pwr_domain_suspend(void) 262*6fba6e04STony Xie { 263*6fba6e04STony Xie sys_slp_config(); 264*6fba6e04STony Xie plls_suspend(); 265*6fba6e04STony Xie psram_sleep_cfg->sys_mode = PMU_SYS_SLP_MODE; 266*6fba6e04STony Xie pmu_sgrf_rst_hld(); 267*6fba6e04STony Xie return 0; 268*6fba6e04STony Xie } 269*6fba6e04STony Xie 270*6fba6e04STony Xie static int sys_pwr_domain_resume(void) 271*6fba6e04STony Xie { 272*6fba6e04STony Xie pmu_sgrf_rst_hld_release(); 273*6fba6e04STony Xie psram_sleep_cfg->sys_mode = PMU_SYS_ON_MODE; 274*6fba6e04STony Xie plls_resume(); 275*6fba6e04STony Xie 276*6fba6e04STony Xie return 0; 277*6fba6e04STony Xie } 278*6fba6e04STony Xie 279*6fba6e04STony Xie static struct rockchip_pm_ops_cb pm_ops = { 280*6fba6e04STony Xie .cores_pwr_dm_on = cores_pwr_domain_on, 281*6fba6e04STony Xie .cores_pwr_dm_off = cores_pwr_domain_off, 282*6fba6e04STony Xie .cores_pwr_dm_on_finish = cores_pwr_domain_on_finish, 283*6fba6e04STony Xie .cores_pwr_dm_suspend = cores_pwr_domain_suspend, 284*6fba6e04STony Xie .cores_pwr_dm_resume = cores_pwr_domain_resume, 285*6fba6e04STony Xie .sys_pwr_dm_suspend = sys_pwr_domain_suspend, 286*6fba6e04STony Xie .sys_pwr_dm_resume = sys_pwr_domain_resume, 287*6fba6e04STony Xie .sys_gbl_soft_reset = soc_global_soft_reset, 288*6fba6e04STony Xie }; 289*6fba6e04STony Xie 290*6fba6e04STony Xie void plat_rockchip_pmu_init(void) 291*6fba6e04STony Xie { 292*6fba6e04STony Xie uint32_t cpu; 293*6fba6e04STony Xie 294*6fba6e04STony Xie rockchip_pd_lock_init(); 295*6fba6e04STony Xie plat_setup_rockchip_pm_ops(&pm_ops); 296*6fba6e04STony Xie 297*6fba6e04STony Xie for (cpu = 0; cpu < PLATFORM_CORE_COUNT; cpu++) 298*6fba6e04STony Xie cpuson_flags[cpu] = 0; 299*6fba6e04STony Xie 300*6fba6e04STony Xie psram_sleep_cfg->sys_mode = PMU_SYS_ON_MODE; 301*6fba6e04STony Xie 302*6fba6e04STony Xie psram_sleep_cfg->boot_mpidr = read_mpidr_el1() & 0xffff; 303*6fba6e04STony Xie 304*6fba6e04STony Xie /* cpu boot from pmusram */ 305*6fba6e04STony Xie mmio_write_32(SGRF_BASE + SGRF_SOC_CON0_1(1), 306*6fba6e04STony Xie (PMUSRAM_BASE >> CPU_BOOT_ADDR_ALIGN) | 307*6fba6e04STony Xie CPU_BOOT_ADDR_WMASK); 308*6fba6e04STony Xie 309*6fba6e04STony Xie nonboot_cpus_off(); 310*6fba6e04STony Xie INFO("%s(%d): pd status %x\n", __func__, __LINE__, 311*6fba6e04STony Xie mmio_read_32(PMU_BASE + PMU_PWRDN_ST)); 312*6fba6e04STony Xie } 313