static void exynos3250_pmu_init(void) { unsigned int value; /* * To prevent from issuing new bus request form L2 memory system * If core status is power down, should be set '1' to L2 power down */ value = pmu_raw_readl(EXYNOS3_ARM_COMMON_OPTION); value |= EXYNOS3_OPTION_SKIP_DEACTIVATE_ACEACP_IN_PWDN; pmu_raw_writel(value, EXYNOS3_ARM_COMMON_OPTION); /* Enable USE_STANDBY_WFI for all CORE */ pmu_raw_writel(S5P_USE_STANDBY_WFI_ALL, S5P_CENTRAL_SEQ_OPTION); /* * Set PSHOLD port for output high */ value = pmu_raw_readl(S5P_PS_HOLD_CONTROL); value |= S5P_PS_HOLD_OUTPUT_HIGH; pmu_raw_writel(value, S5P_PS_HOLD_CONTROL); /* * Enable signal for PSHOLD port */ value = pmu_raw_readl(S5P_PS_HOLD_CONTROL); value |= S5P_PS_HOLD_EN; pmu_raw_writel(value, S5P_PS_HOLD_CONTROL); }
static void exynos5_powerdown_conf(enum sys_powerdown mode) { unsigned int i; unsigned int tmp; /* * Enable both SC_FEEDBACK and SC_COUNTER */ for (i = 0; i < ARRAY_SIZE(exynos5_list_both_cnt_feed); i++) { tmp = pmu_raw_readl(exynos5_list_both_cnt_feed[i]); tmp |= (EXYNOS5_USE_SC_FEEDBACK | EXYNOS5_USE_SC_COUNTER); pmu_raw_writel(tmp, exynos5_list_both_cnt_feed[i]); } /* * SKIP_DEACTIVATE_ACEACP_IN_PWDN_BITFIELD Enable */ tmp = pmu_raw_readl(EXYNOS5_ARM_COMMON_OPTION); tmp |= EXYNOS5_SKIP_DEACTIVATE_ACEACP_IN_PWDN; pmu_raw_writel(tmp, EXYNOS5_ARM_COMMON_OPTION); /* * Disable WFI/WFE on XXX_OPTION */ for (i = 0; i < ARRAY_SIZE(exynos5_list_disable_wfi_wfe); i++) { tmp = pmu_raw_readl(exynos5_list_disable_wfi_wfe[i]); tmp &= ~(EXYNOS5_OPTION_USE_STANDBYWFE | EXYNOS5_OPTION_USE_STANDBYWFI); pmu_raw_writel(tmp, exynos5_list_disable_wfi_wfe[i]); } }
void exynos_sys_powerdown_conf(enum sys_powerdown mode) { unsigned int i; const struct exynos_pmu_data *pmu_data; if (!pmu_context) return; pmu_data = pmu_context->pmu_data; if (pmu_data->powerdown_conf) pmu_data->powerdown_conf(mode); if (pmu_data->pmu_config) { for (i = 0; (pmu_data->pmu_config[i].offset != PMU_TABLE_END); i++) pmu_raw_writel(pmu_data->pmu_config[i].val[mode], pmu_data->pmu_config[i].offset); } if (pmu_data->powerdown_conf_extra) pmu_data->powerdown_conf_extra(mode); if (pmu_data->pmu_config_extra) { for (i = 0; pmu_data->pmu_config_extra[i].offset != PMU_TABLE_END; i++) pmu_raw_writel(pmu_data->pmu_config_extra[i].val[mode], pmu_data->pmu_config_extra[i].offset); } }
static void exynos5250_pmu_init(void) { unsigned int value; /* * When SYS_WDTRESET is set, watchdog timer reset request * is ignored by power management unit. */ value = pmu_raw_readl(EXYNOS5_AUTO_WDTRESET_DISABLE); value &= ~EXYNOS5_SYS_WDTRESET; pmu_raw_writel(value, EXYNOS5_AUTO_WDTRESET_DISABLE); value = pmu_raw_readl(EXYNOS5_MASK_WDTRESET_REQUEST); value &= ~EXYNOS5_SYS_WDTRESET; pmu_raw_writel(value, EXYNOS5_MASK_WDTRESET_REQUEST); }
static void exynos_pm_resume(void) { u32 cpuid = read_cpuid_part(); if (exynos_pm_central_resume()) goto early_wakeup; /* For release retention */ exynos_pm_release_retention(); s3c_pm_do_restore_core(exynos_core_save, ARRAY_SIZE(exynos_core_save)); if (cpuid == ARM_CPU_PART_CORTEX_A9) scu_enable(S5P_VA_SCU); if (call_firmware_op(resume) == -ENOSYS && cpuid == ARM_CPU_PART_CORTEX_A9) exynos_cpu_restore_register(); early_wakeup: /* Clear SLEEP mode set in INFORM1 */ pmu_raw_writel(0x0, S5P_INFORM1); exynos_set_delayed_reset_assertion(true); }
static void exynos3250_pm_prepare(void) { unsigned int tmp; /* Set wake-up mask registers */ exynos_pm_set_wakeup_mask(); tmp = pmu_raw_readl(EXYNOS3_ARM_L2_OPTION); tmp &= ~EXYNOS5_OPTION_USE_RETENTION; pmu_raw_writel(tmp, EXYNOS3_ARM_L2_OPTION); exynos_pm_enter_sleep_mode(); /* ensure at least INFORM0 has the resume address */ pmu_raw_writel(virt_to_phys(exynos_cpu_resume), S5P_INFORM0); }
void __init exynos_pm_init(void) { const struct of_device_id *match; struct device_node *np; u32 tmp; np = of_find_matching_node_and_match(NULL, exynos_pmu_of_device_ids, &match); if (!np) { pr_err("Failed to find PMU node\n"); return; } if (WARN_ON(!of_find_property(np, "interrupt-controller", NULL))) { pr_warn("Outdated DT detected, suspend/resume will NOT work\n"); return; } pm_data = (const struct exynos_pm_data *) match->data; /* All wakeup disable */ tmp = pmu_raw_readl(S5P_WAKEUP_MASK); tmp |= pm_data->wake_disable_mask; pmu_raw_writel(tmp, S5P_WAKEUP_MASK); exynos_pm_syscore_ops.suspend = pm_data->pm_suspend; exynos_pm_syscore_ops.resume = pm_data->pm_resume; register_syscore_ops(&exynos_pm_syscore_ops); suspend_set_ops(&exynos_suspend_ops); }
void __init exynos_pm_init(void) { const struct of_device_id *match; u32 tmp; of_find_matching_node_and_match(NULL, exynos_pmu_of_device_ids, &match); if (!match) { pr_err("Failed to find PMU node\n"); return; } pm_data = (struct exynos_pm_data *) match->data; /* Platform-specific GIC callback */ gic_arch_extn.irq_set_wake = exynos_irq_set_wake; /* All wakeup disable */ tmp = pmu_raw_readl(S5P_WAKEUP_MASK); tmp |= pm_data->wake_disable_mask; pmu_raw_writel(tmp, S5P_WAKEUP_MASK); exynos_pm_syscore_ops.suspend = pm_data->pm_suspend; exynos_pm_syscore_ops.resume = pm_data->pm_resume; register_syscore_ops(&exynos_pm_syscore_ops); suspend_set_ops(&exynos_suspend_ops); }
static void exynos_pm_release_retention(void) { unsigned int i; for (i = 0; (pm_data->release_ret_regs[i] != REG_TABLE_END); i++) pmu_raw_writel(EXYNOS_WAKEUP_FROM_LOWPWR, pm_data->release_ret_regs[i]); }
static int exynos5420_pm_suspend(void) { u32 this_cluster; exynos_pm_central_suspend(); /* Setting SEQ_OPTION register */ this_cluster = MPIDR_AFFINITY_LEVEL(read_cpuid_mpidr(), 1); if (!this_cluster) pmu_raw_writel(EXYNOS5420_ARM_USE_STANDBY_WFI0, S5P_CENTRAL_SEQ_OPTION); else pmu_raw_writel(EXYNOS5420_KFC_USE_STANDBY_WFI0, S5P_CENTRAL_SEQ_OPTION); return 0; }
static void exynos3250_pm_resume(void) { u32 cpuid = read_cpuid_part(); if (exynos_pm_central_resume()) goto early_wakeup; /* For release retention */ exynos_pm_release_retention(); pmu_raw_writel(S5P_USE_STANDBY_WFI_ALL, S5P_CENTRAL_SEQ_OPTION); if (call_firmware_op(resume) == -ENOSYS && cpuid == ARM_CPU_PART_CORTEX_A9) exynos_cpu_restore_register(); early_wakeup: /* Clear SLEEP mode set in INFORM1 */ pmu_raw_writel(0x0, S5P_INFORM1); }
static void exynos5420_powerdown_conf(enum sys_powerdown mode) { u32 this_cluster; this_cluster = MPIDR_AFFINITY_LEVEL(read_cpuid_mpidr(), 1); /* * set the cluster id to IROM register to ensure that we wake * up with the current cluster. */ pmu_raw_writel(this_cluster, EXYNOS_IROM_DATA2); }
static void exynos_pm_prepare(void) { exynos_set_delayed_reset_assertion(false); /* Set wake-up mask registers */ exynos_pm_set_wakeup_mask(); exynos_pm_enter_sleep_mode(); /* ensure at least INFORM0 has the resume address */ pmu_raw_writel(virt_to_phys(exynos_cpu_resume), S5P_INFORM0); }
static void exynos3250_powerdown_conf_extra(enum sys_powerdown mode) { unsigned int i; unsigned int tmp; /* Enable only SC_FEEDBACK */ for (i = 0; i < ARRAY_SIZE(exynos3250_list_feed); i++) { tmp = pmu_raw_readl(exynos3250_list_feed[i]); tmp &= ~(EXYNOS3_OPTION_USE_SC_COUNTER); tmp |= EXYNOS3_OPTION_USE_SC_FEEDBACK; pmu_raw_writel(tmp, exynos3250_list_feed[i]); } if (mode != SYS_SLEEP) return; pmu_raw_writel(XUSBXTI_DURATION, EXYNOS3_XUSBXTI_DURATION); pmu_raw_writel(XXTI_DURATION, EXYNOS3_XXTI_DURATION); pmu_raw_writel(EXT_REGULATOR_DURATION, EXYNOS3_EXT_REGULATOR_DURATION); pmu_raw_writel(EXT_REGULATOR_COREBLK_DURATION, EXYNOS3_EXT_REGULATOR_COREBLK_DURATION); }
static int exynos_pm_suspend(void) { exynos_pm_central_suspend(); /* Setting SEQ_OPTION register */ pmu_raw_writel(S5P_USE_STANDBY_WFI0 | S5P_USE_STANDBY_WFE0, S5P_CENTRAL_SEQ_OPTION); if (read_cpuid_part() == ARM_CPU_PART_CORTEX_A9) exynos_cpu_save_register(); return 0; }
static void exynos5_power_off(void) { unsigned int tmp; pr_info("Power down.\n"); tmp = pmu_raw_readl(EXYNOS_PS_HOLD_CONTROL); tmp ^= (1 << 8); pmu_raw_writel(tmp, EXYNOS_PS_HOLD_CONTROL); /* Wait a little so we don't give a false warning below */ mdelay(100); pr_err("Power down failed, please power off system manually.\n"); while (1) ; }
static void exynos_pm_prepare(void) { exynos_set_delayed_reset_assertion(false); /* Set wake-up mask registers */ exynos_pm_set_wakeup_mask(); s3c_pm_do_save(exynos_core_save, ARRAY_SIZE(exynos_core_save)); if (pm_data->extra_save) s3c_pm_do_save(pm_data->extra_save, pm_data->num_extra_save); exynos_pm_enter_sleep_mode(); /* ensure at least INFORM0 has the resume address */ pmu_raw_writel(virt_to_phys(exynos_cpu_resume), S5P_INFORM0); }
static void exynos5420_pm_resume(void) { unsigned long tmp; /* Restore the CPU0 low power state register */ tmp = pmu_raw_readl(EXYNOS5_ARM_CORE0_SYS_PWR_REG); pmu_raw_writel(tmp | S5P_CORE_LOCAL_PWR_EN, EXYNOS5_ARM_CORE0_SYS_PWR_REG); /* Restore the sysram cpu state register */ __raw_writel(exynos5420_cpu_state, sysram_base_addr + EXYNOS5420_CPU_STATE); pmu_raw_writel(EXYNOS5420_USE_STANDBY_WFI_ALL, S5P_CENTRAL_SEQ_OPTION); if (exynos_pm_central_resume()) goto early_wakeup; /* For release retention */ exynos_pm_release_retention(); pmu_raw_writel(exynos_pmu_spare3, S5P_PMU_SPARE3); s3c_pm_do_restore_core(exynos_core_save, ARRAY_SIZE(exynos_core_save)); early_wakeup: tmp = pmu_raw_readl(EXYNOS5420_SFR_AXI_CGDIS1); tmp &= ~EXYNOS5420_UFS; pmu_raw_writel(tmp, EXYNOS5420_SFR_AXI_CGDIS1); tmp = pmu_raw_readl(EXYNOS5420_FSYS2_OPTION); tmp &= ~EXYNOS5420_EMULATION; pmu_raw_writel(tmp, EXYNOS5420_FSYS2_OPTION); tmp = pmu_raw_readl(EXYNOS5420_PSGEN_OPTION); tmp &= ~EXYNOS5420_EMULATION; pmu_raw_writel(tmp, EXYNOS5420_PSGEN_OPTION); /* Clear SLEEP mode set in INFORM1 */ pmu_raw_writel(0x0, S5P_INFORM1); }
static void exynos5420_pm_prepare(void) { unsigned int tmp; /* Set wake-up mask registers */ exynos_pm_set_wakeup_mask(); s3c_pm_do_save(exynos_core_save, ARRAY_SIZE(exynos_core_save)); exynos_pmu_spare3 = pmu_raw_readl(S5P_PMU_SPARE3); /* * The cpu state needs to be saved and restored so that the * secondary CPUs will enter low power start. Though the U-Boot * is setting the cpu state with low power flag, the kernel * needs to restore it back in case, the primary cpu fails to * suspend for any reason. */ exynos5420_cpu_state = __raw_readl(sysram_base_addr + EXYNOS5420_CPU_STATE); exynos_pm_enter_sleep_mode(); /* ensure at least INFORM0 has the resume address */ if (IS_ENABLED(CONFIG_EXYNOS5420_MCPM)) pmu_raw_writel(virt_to_phys(mcpm_entry_point), S5P_INFORM0); tmp = pmu_raw_readl(EXYNOS5_ARM_L2_OPTION); tmp &= ~EXYNOS5_USE_RETENTION; pmu_raw_writel(tmp, EXYNOS5_ARM_L2_OPTION); tmp = pmu_raw_readl(EXYNOS5420_SFR_AXI_CGDIS1); tmp |= EXYNOS5420_UFS; pmu_raw_writel(tmp, EXYNOS5420_SFR_AXI_CGDIS1); tmp = pmu_raw_readl(EXYNOS5420_ARM_COMMON_OPTION); tmp &= ~EXYNOS5420_L2RSTDISABLE_VALUE; pmu_raw_writel(tmp, EXYNOS5420_ARM_COMMON_OPTION); tmp = pmu_raw_readl(EXYNOS5420_FSYS2_OPTION); tmp |= EXYNOS5420_EMULATION; pmu_raw_writel(tmp, EXYNOS5420_FSYS2_OPTION); tmp = pmu_raw_readl(EXYNOS5420_PSGEN_OPTION); tmp |= EXYNOS5420_EMULATION; pmu_raw_writel(tmp, EXYNOS5420_PSGEN_OPTION); }
static void exynos5420_pmu_init(void) { unsigned int value; int i; /* * Set the CMU_RESET, CMU_SYSCLK and CMU_CLKSTOP registers * for local power blocks to Low initially as per Table 8-4: * "System-Level Power-Down Configuration Registers". */ for (i = 0; i < ARRAY_SIZE(exynos5420_list_disable_pmu_reg); i++) pmu_raw_writel(0, exynos5420_list_disable_pmu_reg[i]); /* Enable USE_STANDBY_WFI for all CORE */ pmu_raw_writel(EXYNOS5420_USE_STANDBY_WFI_ALL, S5P_CENTRAL_SEQ_OPTION); value = pmu_raw_readl(EXYNOS_L2_OPTION(0)); value &= ~EXYNOS5_USE_RETENTION; pmu_raw_writel(value, EXYNOS_L2_OPTION(0)); value = pmu_raw_readl(EXYNOS_L2_OPTION(1)); value &= ~EXYNOS5_USE_RETENTION; pmu_raw_writel(value, EXYNOS_L2_OPTION(1)); /* * If L2_COMMON is turned off, clocks related to ATB async * bridge are gated. Thus, when ISP power is gated, LPI * may get stuck. */ value = pmu_raw_readl(EXYNOS5420_LPI_MASK); value |= EXYNOS5420_ATB_ISP_ARM; pmu_raw_writel(value, EXYNOS5420_LPI_MASK); value = pmu_raw_readl(EXYNOS5420_LPI_MASK1); value |= EXYNOS5420_ATB_KFC; pmu_raw_writel(value, EXYNOS5420_LPI_MASK1); /* Prevent issue of new bus request from L2 memory */ value = pmu_raw_readl(EXYNOS5420_ARM_COMMON_OPTION); value |= EXYNOS5_SKIP_DEACTIVATE_ACEACP_IN_PWDN; pmu_raw_writel(value, EXYNOS5420_ARM_COMMON_OPTION); value = pmu_raw_readl(EXYNOS5420_KFC_COMMON_OPTION); value |= EXYNOS5_SKIP_DEACTIVATE_ACEACP_IN_PWDN; pmu_raw_writel(value, EXYNOS5420_KFC_COMMON_OPTION); /* This setting is to reduce suspend/resume time */ pmu_raw_writel(DUR_WAIT_RESET, EXYNOS5420_LOGIC_RESET_DURATION3); /* Serialized CPU wakeup of Eagle */ pmu_raw_writel(SPREAD_ENABLE, EXYNOS5420_ARM_INTR_SPREAD_ENABLE); pmu_raw_writel(SPREAD_USE_STANDWFI, EXYNOS5420_ARM_INTR_SPREAD_USE_STANDBYWFI); pmu_raw_writel(0x1, EXYNOS5420_UP_SCHEDULER); pr_info("EXYNOS5420 PMU initialized\n"); }
/** * exynos_cluster_power_up : power up the specified cluster * @cluster : the cluster to power up */ void exynos_cluster_power_up(int cluster) { pmu_raw_writel(S5P_CORE_LOCAL_PWR_EN, EXYNOS_COMMON_CONFIGURATION(cluster)); }
/** * exynos_cluster_power_down : power down the specified cluster * @cluster : the cluster to power down */ void exynos_cluster_power_down(int cluster) { pmu_raw_writel(0, EXYNOS_COMMON_CONFIGURATION(cluster)); }
/** * exynos_cpu_power_up : power up the specified cpu * @cpu : the cpu to power up * * Power up the specified cpu */ void exynos_cpu_power_up(int cpu) { pmu_raw_writel(S5P_CORE_LOCAL_PWR_EN, EXYNOS_ARM_CORE_CONFIGURATION(cpu)); }
/** * exynos_core_power_down : power down the specified cpu * @cpu : the cpu to power down * * Power down the specified cpu. The sequence must be finished by a * call to cpu_do_idle() * */ void exynos_cpu_power_down(int cpu) { pmu_raw_writel(0, EXYNOS_ARM_CORE_CONFIGURATION(cpu)); }
static void exynos_pm_set_wakeup_mask(void) { /* Set wake-up mask registers */ pmu_raw_writel(exynos_get_eint_wake_mask(), S5P_EINT_WAKEUP_MASK); pmu_raw_writel(exynos_irqwake_intmask & ~(1 << 31), S5P_WAKEUP_MASK); }
static void exynos_pm_enter_sleep_mode(void) { /* Set value of power down register for sleep mode */ exynos_sys_powerdown_conf(SYS_SLEEP); pmu_raw_writel(S5P_CHECK_SLEEP, S5P_INFORM1); }