162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci// 362306a36Sopenharmony_ci// Copyright (c) 2011-2014 Samsung Electronics Co., Ltd. 462306a36Sopenharmony_ci// http://www.samsung.com 562306a36Sopenharmony_ci// 662306a36Sopenharmony_ci// Exynos - Suspend support 762306a36Sopenharmony_ci// 862306a36Sopenharmony_ci// Based on arch/arm/mach-s3c2410/pm.c 962306a36Sopenharmony_ci// Copyright (c) 2006 Simtec Electronics 1062306a36Sopenharmony_ci// Ben Dooks <ben@simtec.co.uk> 1162306a36Sopenharmony_ci 1262306a36Sopenharmony_ci#include <linux/init.h> 1362306a36Sopenharmony_ci#include <linux/suspend.h> 1462306a36Sopenharmony_ci#include <linux/syscore_ops.h> 1562306a36Sopenharmony_ci#include <linux/cpu_pm.h> 1662306a36Sopenharmony_ci#include <linux/io.h> 1762306a36Sopenharmony_ci#include <linux/irq.h> 1862306a36Sopenharmony_ci#include <linux/irqchip.h> 1962306a36Sopenharmony_ci#include <linux/irqdomain.h> 2062306a36Sopenharmony_ci#include <linux/of_address.h> 2162306a36Sopenharmony_ci#include <linux/err.h> 2262306a36Sopenharmony_ci#include <linux/regulator/machine.h> 2362306a36Sopenharmony_ci#include <linux/soc/samsung/exynos-pmu.h> 2462306a36Sopenharmony_ci#include <linux/soc/samsung/exynos-regs-pmu.h> 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_ci#include <asm/cacheflush.h> 2762306a36Sopenharmony_ci#include <asm/hardware/cache-l2x0.h> 2862306a36Sopenharmony_ci#include <asm/firmware.h> 2962306a36Sopenharmony_ci#include <asm/mcpm.h> 3062306a36Sopenharmony_ci#include <asm/smp_scu.h> 3162306a36Sopenharmony_ci#include <asm/suspend.h> 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_ci#include "common.h" 3462306a36Sopenharmony_ci#include "smc.h" 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_ci#define REG_TABLE_END (-1U) 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_ci#define EXYNOS5420_CPU_STATE 0x28 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_ci/** 4162306a36Sopenharmony_ci * struct exynos_wkup_irq - PMU IRQ to mask mapping 4262306a36Sopenharmony_ci * @hwirq: Hardware IRQ signal of the PMU 4362306a36Sopenharmony_ci * @mask: Mask in PMU wake-up mask register 4462306a36Sopenharmony_ci */ 4562306a36Sopenharmony_cistruct exynos_wkup_irq { 4662306a36Sopenharmony_ci unsigned int hwirq; 4762306a36Sopenharmony_ci u32 mask; 4862306a36Sopenharmony_ci}; 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_cistruct exynos_pm_data { 5162306a36Sopenharmony_ci const struct exynos_wkup_irq *wkup_irq; 5262306a36Sopenharmony_ci unsigned int wake_disable_mask; 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ci void (*pm_prepare)(void); 5562306a36Sopenharmony_ci void (*pm_resume_prepare)(void); 5662306a36Sopenharmony_ci void (*pm_resume)(void); 5762306a36Sopenharmony_ci int (*pm_suspend)(void); 5862306a36Sopenharmony_ci int (*cpu_suspend)(unsigned long); 5962306a36Sopenharmony_ci}; 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ci/* Used only on Exynos542x/5800 */ 6262306a36Sopenharmony_cistruct exynos_pm_state { 6362306a36Sopenharmony_ci int cpu_state; 6462306a36Sopenharmony_ci unsigned int pmu_spare3; 6562306a36Sopenharmony_ci void __iomem *sysram_base; 6662306a36Sopenharmony_ci phys_addr_t sysram_phys; 6762306a36Sopenharmony_ci bool secure_firmware; 6862306a36Sopenharmony_ci}; 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_cistatic const struct exynos_pm_data *pm_data __ro_after_init; 7162306a36Sopenharmony_cistatic struct exynos_pm_state pm_state; 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_ci/* 7462306a36Sopenharmony_ci * GIC wake-up support 7562306a36Sopenharmony_ci */ 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_cistatic u32 exynos_irqwake_intmask = 0xffffffff; 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_cistatic const struct exynos_wkup_irq exynos3250_wkup_irq[] = { 8062306a36Sopenharmony_ci { 73, BIT(1) }, /* RTC alarm */ 8162306a36Sopenharmony_ci { 74, BIT(2) }, /* RTC tick */ 8262306a36Sopenharmony_ci { /* sentinel */ }, 8362306a36Sopenharmony_ci}; 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_cistatic const struct exynos_wkup_irq exynos4_wkup_irq[] = { 8662306a36Sopenharmony_ci { 44, BIT(1) }, /* RTC alarm */ 8762306a36Sopenharmony_ci { 45, BIT(2) }, /* RTC tick */ 8862306a36Sopenharmony_ci { /* sentinel */ }, 8962306a36Sopenharmony_ci}; 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_cistatic const struct exynos_wkup_irq exynos5250_wkup_irq[] = { 9262306a36Sopenharmony_ci { 43, BIT(1) }, /* RTC alarm */ 9362306a36Sopenharmony_ci { 44, BIT(2) }, /* RTC tick */ 9462306a36Sopenharmony_ci { /* sentinel */ }, 9562306a36Sopenharmony_ci}; 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_cistatic u32 exynos_read_eint_wakeup_mask(void) 9862306a36Sopenharmony_ci{ 9962306a36Sopenharmony_ci return pmu_raw_readl(EXYNOS_EINT_WAKEUP_MASK); 10062306a36Sopenharmony_ci} 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_cistatic int exynos_irq_set_wake(struct irq_data *data, unsigned int state) 10362306a36Sopenharmony_ci{ 10462306a36Sopenharmony_ci const struct exynos_wkup_irq *wkup_irq; 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_ci if (!pm_data->wkup_irq) 10762306a36Sopenharmony_ci return -ENOENT; 10862306a36Sopenharmony_ci wkup_irq = pm_data->wkup_irq; 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_ci while (wkup_irq->mask) { 11162306a36Sopenharmony_ci if (wkup_irq->hwirq == data->hwirq) { 11262306a36Sopenharmony_ci if (!state) 11362306a36Sopenharmony_ci exynos_irqwake_intmask |= wkup_irq->mask; 11462306a36Sopenharmony_ci else 11562306a36Sopenharmony_ci exynos_irqwake_intmask &= ~wkup_irq->mask; 11662306a36Sopenharmony_ci return 0; 11762306a36Sopenharmony_ci } 11862306a36Sopenharmony_ci ++wkup_irq; 11962306a36Sopenharmony_ci } 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_ci return -ENOENT; 12262306a36Sopenharmony_ci} 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_cistatic struct irq_chip exynos_pmu_chip = { 12562306a36Sopenharmony_ci .name = "PMU", 12662306a36Sopenharmony_ci .irq_eoi = irq_chip_eoi_parent, 12762306a36Sopenharmony_ci .irq_mask = irq_chip_mask_parent, 12862306a36Sopenharmony_ci .irq_unmask = irq_chip_unmask_parent, 12962306a36Sopenharmony_ci .irq_retrigger = irq_chip_retrigger_hierarchy, 13062306a36Sopenharmony_ci .irq_set_wake = exynos_irq_set_wake, 13162306a36Sopenharmony_ci#ifdef CONFIG_SMP 13262306a36Sopenharmony_ci .irq_set_affinity = irq_chip_set_affinity_parent, 13362306a36Sopenharmony_ci#endif 13462306a36Sopenharmony_ci}; 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_cistatic int exynos_pmu_domain_translate(struct irq_domain *d, 13762306a36Sopenharmony_ci struct irq_fwspec *fwspec, 13862306a36Sopenharmony_ci unsigned long *hwirq, 13962306a36Sopenharmony_ci unsigned int *type) 14062306a36Sopenharmony_ci{ 14162306a36Sopenharmony_ci if (is_of_node(fwspec->fwnode)) { 14262306a36Sopenharmony_ci if (fwspec->param_count != 3) 14362306a36Sopenharmony_ci return -EINVAL; 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_ci /* No PPI should point to this domain */ 14662306a36Sopenharmony_ci if (fwspec->param[0] != 0) 14762306a36Sopenharmony_ci return -EINVAL; 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_ci *hwirq = fwspec->param[1]; 15062306a36Sopenharmony_ci *type = fwspec->param[2]; 15162306a36Sopenharmony_ci return 0; 15262306a36Sopenharmony_ci } 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_ci return -EINVAL; 15562306a36Sopenharmony_ci} 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_cistatic int exynos_pmu_domain_alloc(struct irq_domain *domain, 15862306a36Sopenharmony_ci unsigned int virq, 15962306a36Sopenharmony_ci unsigned int nr_irqs, void *data) 16062306a36Sopenharmony_ci{ 16162306a36Sopenharmony_ci struct irq_fwspec *fwspec = data; 16262306a36Sopenharmony_ci struct irq_fwspec parent_fwspec; 16362306a36Sopenharmony_ci irq_hw_number_t hwirq; 16462306a36Sopenharmony_ci int i; 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_ci if (fwspec->param_count != 3) 16762306a36Sopenharmony_ci return -EINVAL; /* Not GIC compliant */ 16862306a36Sopenharmony_ci if (fwspec->param[0] != 0) 16962306a36Sopenharmony_ci return -EINVAL; /* No PPI should point to this domain */ 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_ci hwirq = fwspec->param[1]; 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_ci for (i = 0; i < nr_irqs; i++) 17462306a36Sopenharmony_ci irq_domain_set_hwirq_and_chip(domain, virq + i, hwirq + i, 17562306a36Sopenharmony_ci &exynos_pmu_chip, NULL); 17662306a36Sopenharmony_ci 17762306a36Sopenharmony_ci parent_fwspec = *fwspec; 17862306a36Sopenharmony_ci parent_fwspec.fwnode = domain->parent->fwnode; 17962306a36Sopenharmony_ci return irq_domain_alloc_irqs_parent(domain, virq, nr_irqs, 18062306a36Sopenharmony_ci &parent_fwspec); 18162306a36Sopenharmony_ci} 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_cistatic const struct irq_domain_ops exynos_pmu_domain_ops = { 18462306a36Sopenharmony_ci .translate = exynos_pmu_domain_translate, 18562306a36Sopenharmony_ci .alloc = exynos_pmu_domain_alloc, 18662306a36Sopenharmony_ci .free = irq_domain_free_irqs_common, 18762306a36Sopenharmony_ci}; 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_cistatic int __init exynos_pmu_irq_init(struct device_node *node, 19062306a36Sopenharmony_ci struct device_node *parent) 19162306a36Sopenharmony_ci{ 19262306a36Sopenharmony_ci struct irq_domain *parent_domain, *domain; 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_ci if (!parent) { 19562306a36Sopenharmony_ci pr_err("%pOF: no parent, giving up\n", node); 19662306a36Sopenharmony_ci return -ENODEV; 19762306a36Sopenharmony_ci } 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_ci parent_domain = irq_find_host(parent); 20062306a36Sopenharmony_ci if (!parent_domain) { 20162306a36Sopenharmony_ci pr_err("%pOF: unable to obtain parent domain\n", node); 20262306a36Sopenharmony_ci return -ENXIO; 20362306a36Sopenharmony_ci } 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_ci pmu_base_addr = of_iomap(node, 0); 20662306a36Sopenharmony_ci 20762306a36Sopenharmony_ci if (!pmu_base_addr) { 20862306a36Sopenharmony_ci pr_err("%pOF: failed to find exynos pmu register\n", node); 20962306a36Sopenharmony_ci return -ENOMEM; 21062306a36Sopenharmony_ci } 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_ci domain = irq_domain_add_hierarchy(parent_domain, 0, 0, 21362306a36Sopenharmony_ci node, &exynos_pmu_domain_ops, 21462306a36Sopenharmony_ci NULL); 21562306a36Sopenharmony_ci if (!domain) { 21662306a36Sopenharmony_ci iounmap(pmu_base_addr); 21762306a36Sopenharmony_ci pmu_base_addr = NULL; 21862306a36Sopenharmony_ci return -ENOMEM; 21962306a36Sopenharmony_ci } 22062306a36Sopenharmony_ci 22162306a36Sopenharmony_ci /* 22262306a36Sopenharmony_ci * Clear the OF_POPULATED flag set in of_irq_init so that 22362306a36Sopenharmony_ci * later the Exynos PMU platform device won't be skipped. 22462306a36Sopenharmony_ci */ 22562306a36Sopenharmony_ci of_node_clear_flag(node, OF_POPULATED); 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_ci return 0; 22862306a36Sopenharmony_ci} 22962306a36Sopenharmony_ci 23062306a36Sopenharmony_ci#define EXYNOS_PMU_IRQ(symbol, name) IRQCHIP_DECLARE(symbol, name, exynos_pmu_irq_init) 23162306a36Sopenharmony_ci 23262306a36Sopenharmony_ciEXYNOS_PMU_IRQ(exynos3250_pmu_irq, "samsung,exynos3250-pmu"); 23362306a36Sopenharmony_ciEXYNOS_PMU_IRQ(exynos4210_pmu_irq, "samsung,exynos4210-pmu"); 23462306a36Sopenharmony_ciEXYNOS_PMU_IRQ(exynos4212_pmu_irq, "samsung,exynos4212-pmu"); 23562306a36Sopenharmony_ciEXYNOS_PMU_IRQ(exynos4412_pmu_irq, "samsung,exynos4412-pmu"); 23662306a36Sopenharmony_ciEXYNOS_PMU_IRQ(exynos5250_pmu_irq, "samsung,exynos5250-pmu"); 23762306a36Sopenharmony_ciEXYNOS_PMU_IRQ(exynos5420_pmu_irq, "samsung,exynos5420-pmu"); 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_cistatic int exynos_cpu_do_idle(void) 24062306a36Sopenharmony_ci{ 24162306a36Sopenharmony_ci /* issue the standby signal into the pm unit. */ 24262306a36Sopenharmony_ci cpu_do_idle(); 24362306a36Sopenharmony_ci 24462306a36Sopenharmony_ci pr_info("Failed to suspend the system\n"); 24562306a36Sopenharmony_ci return 1; /* Aborting suspend */ 24662306a36Sopenharmony_ci} 24762306a36Sopenharmony_cistatic void exynos_flush_cache_all(void) 24862306a36Sopenharmony_ci{ 24962306a36Sopenharmony_ci flush_cache_all(); 25062306a36Sopenharmony_ci outer_flush_all(); 25162306a36Sopenharmony_ci} 25262306a36Sopenharmony_ci 25362306a36Sopenharmony_cistatic int exynos_cpu_suspend(unsigned long arg) 25462306a36Sopenharmony_ci{ 25562306a36Sopenharmony_ci exynos_flush_cache_all(); 25662306a36Sopenharmony_ci return exynos_cpu_do_idle(); 25762306a36Sopenharmony_ci} 25862306a36Sopenharmony_ci 25962306a36Sopenharmony_cistatic int exynos3250_cpu_suspend(unsigned long arg) 26062306a36Sopenharmony_ci{ 26162306a36Sopenharmony_ci flush_cache_all(); 26262306a36Sopenharmony_ci return exynos_cpu_do_idle(); 26362306a36Sopenharmony_ci} 26462306a36Sopenharmony_ci 26562306a36Sopenharmony_cistatic int exynos5420_cpu_suspend(unsigned long arg) 26662306a36Sopenharmony_ci{ 26762306a36Sopenharmony_ci /* MCPM works with HW CPU identifiers */ 26862306a36Sopenharmony_ci unsigned int mpidr = read_cpuid_mpidr(); 26962306a36Sopenharmony_ci unsigned int cluster = MPIDR_AFFINITY_LEVEL(mpidr, 1); 27062306a36Sopenharmony_ci unsigned int cpu = MPIDR_AFFINITY_LEVEL(mpidr, 0); 27162306a36Sopenharmony_ci 27262306a36Sopenharmony_ci if (IS_ENABLED(CONFIG_EXYNOS_MCPM)) { 27362306a36Sopenharmony_ci mcpm_set_entry_vector(cpu, cluster, exynos_cpu_resume); 27462306a36Sopenharmony_ci mcpm_cpu_suspend(); 27562306a36Sopenharmony_ci } 27662306a36Sopenharmony_ci 27762306a36Sopenharmony_ci pr_info("Failed to suspend the system\n"); 27862306a36Sopenharmony_ci 27962306a36Sopenharmony_ci /* return value != 0 means failure */ 28062306a36Sopenharmony_ci return 1; 28162306a36Sopenharmony_ci} 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_cistatic void exynos_pm_set_wakeup_mask(void) 28462306a36Sopenharmony_ci{ 28562306a36Sopenharmony_ci /* 28662306a36Sopenharmony_ci * Set wake-up mask registers 28762306a36Sopenharmony_ci * EXYNOS_EINT_WAKEUP_MASK is set by pinctrl driver in late suspend. 28862306a36Sopenharmony_ci */ 28962306a36Sopenharmony_ci pmu_raw_writel(exynos_irqwake_intmask & ~BIT(31), S5P_WAKEUP_MASK); 29062306a36Sopenharmony_ci} 29162306a36Sopenharmony_ci 29262306a36Sopenharmony_cistatic void exynos_pm_enter_sleep_mode(void) 29362306a36Sopenharmony_ci{ 29462306a36Sopenharmony_ci /* Set value of power down register for sleep mode */ 29562306a36Sopenharmony_ci exynos_sys_powerdown_conf(SYS_SLEEP); 29662306a36Sopenharmony_ci pmu_raw_writel(EXYNOS_SLEEP_MAGIC, S5P_INFORM1); 29762306a36Sopenharmony_ci} 29862306a36Sopenharmony_ci 29962306a36Sopenharmony_cistatic void exynos_pm_prepare(void) 30062306a36Sopenharmony_ci{ 30162306a36Sopenharmony_ci exynos_set_delayed_reset_assertion(false); 30262306a36Sopenharmony_ci 30362306a36Sopenharmony_ci /* Set wake-up mask registers */ 30462306a36Sopenharmony_ci exynos_pm_set_wakeup_mask(); 30562306a36Sopenharmony_ci 30662306a36Sopenharmony_ci exynos_pm_enter_sleep_mode(); 30762306a36Sopenharmony_ci 30862306a36Sopenharmony_ci /* ensure at least INFORM0 has the resume address */ 30962306a36Sopenharmony_ci pmu_raw_writel(__pa_symbol(exynos_cpu_resume), S5P_INFORM0); 31062306a36Sopenharmony_ci} 31162306a36Sopenharmony_ci 31262306a36Sopenharmony_cistatic void exynos3250_pm_prepare(void) 31362306a36Sopenharmony_ci{ 31462306a36Sopenharmony_ci unsigned int tmp; 31562306a36Sopenharmony_ci 31662306a36Sopenharmony_ci /* Set wake-up mask registers */ 31762306a36Sopenharmony_ci exynos_pm_set_wakeup_mask(); 31862306a36Sopenharmony_ci 31962306a36Sopenharmony_ci tmp = pmu_raw_readl(EXYNOS3_ARM_L2_OPTION); 32062306a36Sopenharmony_ci tmp &= ~EXYNOS5_OPTION_USE_RETENTION; 32162306a36Sopenharmony_ci pmu_raw_writel(tmp, EXYNOS3_ARM_L2_OPTION); 32262306a36Sopenharmony_ci 32362306a36Sopenharmony_ci exynos_pm_enter_sleep_mode(); 32462306a36Sopenharmony_ci 32562306a36Sopenharmony_ci /* ensure at least INFORM0 has the resume address */ 32662306a36Sopenharmony_ci pmu_raw_writel(__pa_symbol(exynos_cpu_resume), S5P_INFORM0); 32762306a36Sopenharmony_ci} 32862306a36Sopenharmony_ci 32962306a36Sopenharmony_cistatic void exynos5420_pm_prepare(void) 33062306a36Sopenharmony_ci{ 33162306a36Sopenharmony_ci unsigned int tmp; 33262306a36Sopenharmony_ci 33362306a36Sopenharmony_ci /* Set wake-up mask registers */ 33462306a36Sopenharmony_ci exynos_pm_set_wakeup_mask(); 33562306a36Sopenharmony_ci 33662306a36Sopenharmony_ci pm_state.pmu_spare3 = pmu_raw_readl(S5P_PMU_SPARE3); 33762306a36Sopenharmony_ci /* 33862306a36Sopenharmony_ci * The cpu state needs to be saved and restored so that the 33962306a36Sopenharmony_ci * secondary CPUs will enter low power start. Though the U-Boot 34062306a36Sopenharmony_ci * is setting the cpu state with low power flag, the kernel 34162306a36Sopenharmony_ci * needs to restore it back in case, the primary cpu fails to 34262306a36Sopenharmony_ci * suspend for any reason. 34362306a36Sopenharmony_ci */ 34462306a36Sopenharmony_ci pm_state.cpu_state = readl_relaxed(pm_state.sysram_base + 34562306a36Sopenharmony_ci EXYNOS5420_CPU_STATE); 34662306a36Sopenharmony_ci writel_relaxed(0x0, pm_state.sysram_base + EXYNOS5420_CPU_STATE); 34762306a36Sopenharmony_ci if (pm_state.secure_firmware) 34862306a36Sopenharmony_ci exynos_smc(SMC_CMD_REG, SMC_REG_ID_SFR_W(pm_state.sysram_phys + 34962306a36Sopenharmony_ci EXYNOS5420_CPU_STATE), 35062306a36Sopenharmony_ci 0, 0); 35162306a36Sopenharmony_ci 35262306a36Sopenharmony_ci exynos_pm_enter_sleep_mode(); 35362306a36Sopenharmony_ci 35462306a36Sopenharmony_ci /* ensure at least INFORM0 has the resume address */ 35562306a36Sopenharmony_ci if (IS_ENABLED(CONFIG_EXYNOS_MCPM)) 35662306a36Sopenharmony_ci pmu_raw_writel(__pa_symbol(mcpm_entry_point), S5P_INFORM0); 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_ci tmp = pmu_raw_readl(EXYNOS_L2_OPTION(0)); 35962306a36Sopenharmony_ci tmp &= ~EXYNOS_L2_USE_RETENTION; 36062306a36Sopenharmony_ci pmu_raw_writel(tmp, EXYNOS_L2_OPTION(0)); 36162306a36Sopenharmony_ci 36262306a36Sopenharmony_ci tmp = pmu_raw_readl(EXYNOS5420_SFR_AXI_CGDIS1); 36362306a36Sopenharmony_ci tmp |= EXYNOS5420_UFS; 36462306a36Sopenharmony_ci pmu_raw_writel(tmp, EXYNOS5420_SFR_AXI_CGDIS1); 36562306a36Sopenharmony_ci 36662306a36Sopenharmony_ci tmp = pmu_raw_readl(EXYNOS5420_ARM_COMMON_OPTION); 36762306a36Sopenharmony_ci tmp &= ~EXYNOS5420_L2RSTDISABLE_VALUE; 36862306a36Sopenharmony_ci pmu_raw_writel(tmp, EXYNOS5420_ARM_COMMON_OPTION); 36962306a36Sopenharmony_ci 37062306a36Sopenharmony_ci tmp = pmu_raw_readl(EXYNOS5420_FSYS2_OPTION); 37162306a36Sopenharmony_ci tmp |= EXYNOS5420_EMULATION; 37262306a36Sopenharmony_ci pmu_raw_writel(tmp, EXYNOS5420_FSYS2_OPTION); 37362306a36Sopenharmony_ci 37462306a36Sopenharmony_ci tmp = pmu_raw_readl(EXYNOS5420_PSGEN_OPTION); 37562306a36Sopenharmony_ci tmp |= EXYNOS5420_EMULATION; 37662306a36Sopenharmony_ci pmu_raw_writel(tmp, EXYNOS5420_PSGEN_OPTION); 37762306a36Sopenharmony_ci} 37862306a36Sopenharmony_ci 37962306a36Sopenharmony_ci 38062306a36Sopenharmony_cistatic int exynos_pm_suspend(void) 38162306a36Sopenharmony_ci{ 38262306a36Sopenharmony_ci exynos_pm_central_suspend(); 38362306a36Sopenharmony_ci 38462306a36Sopenharmony_ci /* Setting SEQ_OPTION register */ 38562306a36Sopenharmony_ci pmu_raw_writel(S5P_USE_STANDBY_WFI0 | S5P_USE_STANDBY_WFE0, 38662306a36Sopenharmony_ci S5P_CENTRAL_SEQ_OPTION); 38762306a36Sopenharmony_ci 38862306a36Sopenharmony_ci if (read_cpuid_part() == ARM_CPU_PART_CORTEX_A9) 38962306a36Sopenharmony_ci exynos_cpu_save_register(); 39062306a36Sopenharmony_ci 39162306a36Sopenharmony_ci return 0; 39262306a36Sopenharmony_ci} 39362306a36Sopenharmony_ci 39462306a36Sopenharmony_cistatic int exynos5420_pm_suspend(void) 39562306a36Sopenharmony_ci{ 39662306a36Sopenharmony_ci u32 this_cluster; 39762306a36Sopenharmony_ci 39862306a36Sopenharmony_ci exynos_pm_central_suspend(); 39962306a36Sopenharmony_ci 40062306a36Sopenharmony_ci /* Setting SEQ_OPTION register */ 40162306a36Sopenharmony_ci 40262306a36Sopenharmony_ci this_cluster = MPIDR_AFFINITY_LEVEL(read_cpuid_mpidr(), 1); 40362306a36Sopenharmony_ci if (!this_cluster) 40462306a36Sopenharmony_ci pmu_raw_writel(EXYNOS5420_ARM_USE_STANDBY_WFI0, 40562306a36Sopenharmony_ci S5P_CENTRAL_SEQ_OPTION); 40662306a36Sopenharmony_ci else 40762306a36Sopenharmony_ci pmu_raw_writel(EXYNOS5420_KFC_USE_STANDBY_WFI0, 40862306a36Sopenharmony_ci S5P_CENTRAL_SEQ_OPTION); 40962306a36Sopenharmony_ci return 0; 41062306a36Sopenharmony_ci} 41162306a36Sopenharmony_ci 41262306a36Sopenharmony_cistatic void exynos_pm_resume(void) 41362306a36Sopenharmony_ci{ 41462306a36Sopenharmony_ci u32 cpuid = read_cpuid_part(); 41562306a36Sopenharmony_ci 41662306a36Sopenharmony_ci if (exynos_pm_central_resume()) 41762306a36Sopenharmony_ci goto early_wakeup; 41862306a36Sopenharmony_ci 41962306a36Sopenharmony_ci if (cpuid == ARM_CPU_PART_CORTEX_A9) 42062306a36Sopenharmony_ci exynos_scu_enable(); 42162306a36Sopenharmony_ci 42262306a36Sopenharmony_ci if (call_firmware_op(resume) == -ENOSYS 42362306a36Sopenharmony_ci && cpuid == ARM_CPU_PART_CORTEX_A9) 42462306a36Sopenharmony_ci exynos_cpu_restore_register(); 42562306a36Sopenharmony_ci 42662306a36Sopenharmony_ciearly_wakeup: 42762306a36Sopenharmony_ci 42862306a36Sopenharmony_ci /* Clear SLEEP mode set in INFORM1 */ 42962306a36Sopenharmony_ci pmu_raw_writel(0x0, S5P_INFORM1); 43062306a36Sopenharmony_ci exynos_set_delayed_reset_assertion(true); 43162306a36Sopenharmony_ci} 43262306a36Sopenharmony_ci 43362306a36Sopenharmony_cistatic void exynos3250_pm_resume(void) 43462306a36Sopenharmony_ci{ 43562306a36Sopenharmony_ci u32 cpuid = read_cpuid_part(); 43662306a36Sopenharmony_ci 43762306a36Sopenharmony_ci if (exynos_pm_central_resume()) 43862306a36Sopenharmony_ci goto early_wakeup; 43962306a36Sopenharmony_ci 44062306a36Sopenharmony_ci pmu_raw_writel(S5P_USE_STANDBY_WFI_ALL, S5P_CENTRAL_SEQ_OPTION); 44162306a36Sopenharmony_ci 44262306a36Sopenharmony_ci if (call_firmware_op(resume) == -ENOSYS 44362306a36Sopenharmony_ci && cpuid == ARM_CPU_PART_CORTEX_A9) 44462306a36Sopenharmony_ci exynos_cpu_restore_register(); 44562306a36Sopenharmony_ci 44662306a36Sopenharmony_ciearly_wakeup: 44762306a36Sopenharmony_ci 44862306a36Sopenharmony_ci /* Clear SLEEP mode set in INFORM1 */ 44962306a36Sopenharmony_ci pmu_raw_writel(0x0, S5P_INFORM1); 45062306a36Sopenharmony_ci} 45162306a36Sopenharmony_ci 45262306a36Sopenharmony_cistatic void exynos5420_prepare_pm_resume(void) 45362306a36Sopenharmony_ci{ 45462306a36Sopenharmony_ci unsigned int mpidr, cluster; 45562306a36Sopenharmony_ci 45662306a36Sopenharmony_ci mpidr = read_cpuid_mpidr(); 45762306a36Sopenharmony_ci cluster = MPIDR_AFFINITY_LEVEL(mpidr, 1); 45862306a36Sopenharmony_ci 45962306a36Sopenharmony_ci if (IS_ENABLED(CONFIG_EXYNOS_MCPM)) 46062306a36Sopenharmony_ci WARN_ON(mcpm_cpu_powered_up()); 46162306a36Sopenharmony_ci 46262306a36Sopenharmony_ci if (IS_ENABLED(CONFIG_HW_PERF_EVENTS) && cluster != 0) { 46362306a36Sopenharmony_ci /* 46462306a36Sopenharmony_ci * When system is resumed on the LITTLE/KFC core (cluster 1), 46562306a36Sopenharmony_ci * the DSCR is not properly updated until the power is turned 46662306a36Sopenharmony_ci * on also for the cluster 0. Enable it for a while to 46762306a36Sopenharmony_ci * propagate the SPNIDEN and SPIDEN signals from Secure JTAG 46862306a36Sopenharmony_ci * block and avoid undefined instruction issue on CP14 reset. 46962306a36Sopenharmony_ci */ 47062306a36Sopenharmony_ci pmu_raw_writel(S5P_CORE_LOCAL_PWR_EN, 47162306a36Sopenharmony_ci EXYNOS_COMMON_CONFIGURATION(0)); 47262306a36Sopenharmony_ci pmu_raw_writel(0, 47362306a36Sopenharmony_ci EXYNOS_COMMON_CONFIGURATION(0)); 47462306a36Sopenharmony_ci } 47562306a36Sopenharmony_ci} 47662306a36Sopenharmony_ci 47762306a36Sopenharmony_cistatic void exynos5420_pm_resume(void) 47862306a36Sopenharmony_ci{ 47962306a36Sopenharmony_ci unsigned long tmp; 48062306a36Sopenharmony_ci 48162306a36Sopenharmony_ci /* Restore the CPU0 low power state register */ 48262306a36Sopenharmony_ci tmp = pmu_raw_readl(EXYNOS5_ARM_CORE0_SYS_PWR_REG); 48362306a36Sopenharmony_ci pmu_raw_writel(tmp | S5P_CORE_LOCAL_PWR_EN, 48462306a36Sopenharmony_ci EXYNOS5_ARM_CORE0_SYS_PWR_REG); 48562306a36Sopenharmony_ci 48662306a36Sopenharmony_ci /* Restore the sysram cpu state register */ 48762306a36Sopenharmony_ci writel_relaxed(pm_state.cpu_state, 48862306a36Sopenharmony_ci pm_state.sysram_base + EXYNOS5420_CPU_STATE); 48962306a36Sopenharmony_ci if (pm_state.secure_firmware) 49062306a36Sopenharmony_ci exynos_smc(SMC_CMD_REG, 49162306a36Sopenharmony_ci SMC_REG_ID_SFR_W(pm_state.sysram_phys + 49262306a36Sopenharmony_ci EXYNOS5420_CPU_STATE), 49362306a36Sopenharmony_ci EXYNOS_AFTR_MAGIC, 0); 49462306a36Sopenharmony_ci 49562306a36Sopenharmony_ci pmu_raw_writel(EXYNOS5420_USE_STANDBY_WFI_ALL, 49662306a36Sopenharmony_ci S5P_CENTRAL_SEQ_OPTION); 49762306a36Sopenharmony_ci 49862306a36Sopenharmony_ci if (exynos_pm_central_resume()) 49962306a36Sopenharmony_ci goto early_wakeup; 50062306a36Sopenharmony_ci 50162306a36Sopenharmony_ci pmu_raw_writel(pm_state.pmu_spare3, S5P_PMU_SPARE3); 50262306a36Sopenharmony_ci 50362306a36Sopenharmony_ciearly_wakeup: 50462306a36Sopenharmony_ci 50562306a36Sopenharmony_ci tmp = pmu_raw_readl(EXYNOS5420_SFR_AXI_CGDIS1); 50662306a36Sopenharmony_ci tmp &= ~EXYNOS5420_UFS; 50762306a36Sopenharmony_ci pmu_raw_writel(tmp, EXYNOS5420_SFR_AXI_CGDIS1); 50862306a36Sopenharmony_ci 50962306a36Sopenharmony_ci tmp = pmu_raw_readl(EXYNOS5420_FSYS2_OPTION); 51062306a36Sopenharmony_ci tmp &= ~EXYNOS5420_EMULATION; 51162306a36Sopenharmony_ci pmu_raw_writel(tmp, EXYNOS5420_FSYS2_OPTION); 51262306a36Sopenharmony_ci 51362306a36Sopenharmony_ci tmp = pmu_raw_readl(EXYNOS5420_PSGEN_OPTION); 51462306a36Sopenharmony_ci tmp &= ~EXYNOS5420_EMULATION; 51562306a36Sopenharmony_ci pmu_raw_writel(tmp, EXYNOS5420_PSGEN_OPTION); 51662306a36Sopenharmony_ci 51762306a36Sopenharmony_ci /* Clear SLEEP mode set in INFORM1 */ 51862306a36Sopenharmony_ci pmu_raw_writel(0x0, S5P_INFORM1); 51962306a36Sopenharmony_ci} 52062306a36Sopenharmony_ci 52162306a36Sopenharmony_ci/* 52262306a36Sopenharmony_ci * Suspend Ops 52362306a36Sopenharmony_ci */ 52462306a36Sopenharmony_ci 52562306a36Sopenharmony_cistatic int exynos_suspend_enter(suspend_state_t state) 52662306a36Sopenharmony_ci{ 52762306a36Sopenharmony_ci u32 eint_wakeup_mask = exynos_read_eint_wakeup_mask(); 52862306a36Sopenharmony_ci int ret; 52962306a36Sopenharmony_ci 53062306a36Sopenharmony_ci pr_debug("%s: suspending the system...\n", __func__); 53162306a36Sopenharmony_ci 53262306a36Sopenharmony_ci pr_debug("%s: wakeup masks: %08x,%08x\n", __func__, 53362306a36Sopenharmony_ci exynos_irqwake_intmask, eint_wakeup_mask); 53462306a36Sopenharmony_ci 53562306a36Sopenharmony_ci if (exynos_irqwake_intmask == -1U 53662306a36Sopenharmony_ci && eint_wakeup_mask == EXYNOS_EINT_WAKEUP_MASK_DISABLED) { 53762306a36Sopenharmony_ci pr_err("%s: No wake-up sources!\n", __func__); 53862306a36Sopenharmony_ci pr_err("%s: Aborting sleep\n", __func__); 53962306a36Sopenharmony_ci return -EINVAL; 54062306a36Sopenharmony_ci } 54162306a36Sopenharmony_ci 54262306a36Sopenharmony_ci if (pm_data->pm_prepare) 54362306a36Sopenharmony_ci pm_data->pm_prepare(); 54462306a36Sopenharmony_ci flush_cache_all(); 54562306a36Sopenharmony_ci 54662306a36Sopenharmony_ci ret = call_firmware_op(suspend); 54762306a36Sopenharmony_ci if (ret == -ENOSYS) 54862306a36Sopenharmony_ci ret = cpu_suspend(0, pm_data->cpu_suspend); 54962306a36Sopenharmony_ci if (ret) 55062306a36Sopenharmony_ci return ret; 55162306a36Sopenharmony_ci 55262306a36Sopenharmony_ci if (pm_data->pm_resume_prepare) 55362306a36Sopenharmony_ci pm_data->pm_resume_prepare(); 55462306a36Sopenharmony_ci 55562306a36Sopenharmony_ci pr_debug("%s: wakeup stat: %08x\n", __func__, 55662306a36Sopenharmony_ci pmu_raw_readl(S5P_WAKEUP_STAT)); 55762306a36Sopenharmony_ci 55862306a36Sopenharmony_ci pr_debug("%s: resuming the system...\n", __func__); 55962306a36Sopenharmony_ci 56062306a36Sopenharmony_ci return 0; 56162306a36Sopenharmony_ci} 56262306a36Sopenharmony_ci 56362306a36Sopenharmony_cistatic int exynos_suspend_prepare(void) 56462306a36Sopenharmony_ci{ 56562306a36Sopenharmony_ci int ret; 56662306a36Sopenharmony_ci 56762306a36Sopenharmony_ci /* 56862306a36Sopenharmony_ci * REVISIT: It would be better if struct platform_suspend_ops 56962306a36Sopenharmony_ci * .prepare handler get the suspend_state_t as a parameter to 57062306a36Sopenharmony_ci * avoid hard-coding the suspend to mem state. It's safe to do 57162306a36Sopenharmony_ci * it now only because the suspend_valid_only_mem function is 57262306a36Sopenharmony_ci * used as the .valid callback used to check if a given state 57362306a36Sopenharmony_ci * is supported by the platform anyways. 57462306a36Sopenharmony_ci */ 57562306a36Sopenharmony_ci ret = regulator_suspend_prepare(PM_SUSPEND_MEM); 57662306a36Sopenharmony_ci if (ret) { 57762306a36Sopenharmony_ci pr_err("Failed to prepare regulators for suspend (%d)\n", ret); 57862306a36Sopenharmony_ci return ret; 57962306a36Sopenharmony_ci } 58062306a36Sopenharmony_ci 58162306a36Sopenharmony_ci return 0; 58262306a36Sopenharmony_ci} 58362306a36Sopenharmony_ci 58462306a36Sopenharmony_cistatic void exynos_suspend_finish(void) 58562306a36Sopenharmony_ci{ 58662306a36Sopenharmony_ci int ret; 58762306a36Sopenharmony_ci 58862306a36Sopenharmony_ci ret = regulator_suspend_finish(); 58962306a36Sopenharmony_ci if (ret) 59062306a36Sopenharmony_ci pr_warn("Failed to resume regulators from suspend (%d)\n", ret); 59162306a36Sopenharmony_ci} 59262306a36Sopenharmony_ci 59362306a36Sopenharmony_cistatic const struct platform_suspend_ops exynos_suspend_ops = { 59462306a36Sopenharmony_ci .enter = exynos_suspend_enter, 59562306a36Sopenharmony_ci .prepare = exynos_suspend_prepare, 59662306a36Sopenharmony_ci .finish = exynos_suspend_finish, 59762306a36Sopenharmony_ci .valid = suspend_valid_only_mem, 59862306a36Sopenharmony_ci}; 59962306a36Sopenharmony_ci 60062306a36Sopenharmony_cistatic const struct exynos_pm_data exynos3250_pm_data = { 60162306a36Sopenharmony_ci .wkup_irq = exynos3250_wkup_irq, 60262306a36Sopenharmony_ci .wake_disable_mask = ((0xFF << 8) | (0x1F << 1)), 60362306a36Sopenharmony_ci .pm_suspend = exynos_pm_suspend, 60462306a36Sopenharmony_ci .pm_resume = exynos3250_pm_resume, 60562306a36Sopenharmony_ci .pm_prepare = exynos3250_pm_prepare, 60662306a36Sopenharmony_ci .cpu_suspend = exynos3250_cpu_suspend, 60762306a36Sopenharmony_ci}; 60862306a36Sopenharmony_ci 60962306a36Sopenharmony_cistatic const struct exynos_pm_data exynos4_pm_data = { 61062306a36Sopenharmony_ci .wkup_irq = exynos4_wkup_irq, 61162306a36Sopenharmony_ci .wake_disable_mask = ((0xFF << 8) | (0x1F << 1)), 61262306a36Sopenharmony_ci .pm_suspend = exynos_pm_suspend, 61362306a36Sopenharmony_ci .pm_resume = exynos_pm_resume, 61462306a36Sopenharmony_ci .pm_prepare = exynos_pm_prepare, 61562306a36Sopenharmony_ci .cpu_suspend = exynos_cpu_suspend, 61662306a36Sopenharmony_ci}; 61762306a36Sopenharmony_ci 61862306a36Sopenharmony_cistatic const struct exynos_pm_data exynos5250_pm_data = { 61962306a36Sopenharmony_ci .wkup_irq = exynos5250_wkup_irq, 62062306a36Sopenharmony_ci .wake_disable_mask = ((0xFF << 8) | (0x1F << 1)), 62162306a36Sopenharmony_ci .pm_suspend = exynos_pm_suspend, 62262306a36Sopenharmony_ci .pm_resume = exynos_pm_resume, 62362306a36Sopenharmony_ci .pm_prepare = exynos_pm_prepare, 62462306a36Sopenharmony_ci .cpu_suspend = exynos_cpu_suspend, 62562306a36Sopenharmony_ci}; 62662306a36Sopenharmony_ci 62762306a36Sopenharmony_cistatic const struct exynos_pm_data exynos5420_pm_data = { 62862306a36Sopenharmony_ci .wkup_irq = exynos5250_wkup_irq, 62962306a36Sopenharmony_ci .wake_disable_mask = (0x7F << 7) | (0x1F << 1), 63062306a36Sopenharmony_ci .pm_resume_prepare = exynos5420_prepare_pm_resume, 63162306a36Sopenharmony_ci .pm_resume = exynos5420_pm_resume, 63262306a36Sopenharmony_ci .pm_suspend = exynos5420_pm_suspend, 63362306a36Sopenharmony_ci .pm_prepare = exynos5420_pm_prepare, 63462306a36Sopenharmony_ci .cpu_suspend = exynos5420_cpu_suspend, 63562306a36Sopenharmony_ci}; 63662306a36Sopenharmony_ci 63762306a36Sopenharmony_cistatic const struct of_device_id exynos_pmu_of_device_ids[] __initconst = { 63862306a36Sopenharmony_ci { 63962306a36Sopenharmony_ci .compatible = "samsung,exynos3250-pmu", 64062306a36Sopenharmony_ci .data = &exynos3250_pm_data, 64162306a36Sopenharmony_ci }, { 64262306a36Sopenharmony_ci .compatible = "samsung,exynos4210-pmu", 64362306a36Sopenharmony_ci .data = &exynos4_pm_data, 64462306a36Sopenharmony_ci }, { 64562306a36Sopenharmony_ci .compatible = "samsung,exynos4212-pmu", 64662306a36Sopenharmony_ci .data = &exynos4_pm_data, 64762306a36Sopenharmony_ci }, { 64862306a36Sopenharmony_ci .compatible = "samsung,exynos4412-pmu", 64962306a36Sopenharmony_ci .data = &exynos4_pm_data, 65062306a36Sopenharmony_ci }, { 65162306a36Sopenharmony_ci .compatible = "samsung,exynos5250-pmu", 65262306a36Sopenharmony_ci .data = &exynos5250_pm_data, 65362306a36Sopenharmony_ci }, { 65462306a36Sopenharmony_ci .compatible = "samsung,exynos5420-pmu", 65562306a36Sopenharmony_ci .data = &exynos5420_pm_data, 65662306a36Sopenharmony_ci }, 65762306a36Sopenharmony_ci { /*sentinel*/ }, 65862306a36Sopenharmony_ci}; 65962306a36Sopenharmony_ci 66062306a36Sopenharmony_cistatic struct syscore_ops exynos_pm_syscore_ops; 66162306a36Sopenharmony_ci 66262306a36Sopenharmony_civoid __init exynos_pm_init(void) 66362306a36Sopenharmony_ci{ 66462306a36Sopenharmony_ci const struct of_device_id *match; 66562306a36Sopenharmony_ci struct device_node *np; 66662306a36Sopenharmony_ci u32 tmp; 66762306a36Sopenharmony_ci 66862306a36Sopenharmony_ci np = of_find_matching_node_and_match(NULL, exynos_pmu_of_device_ids, &match); 66962306a36Sopenharmony_ci if (!np) { 67062306a36Sopenharmony_ci pr_err("Failed to find PMU node\n"); 67162306a36Sopenharmony_ci return; 67262306a36Sopenharmony_ci } 67362306a36Sopenharmony_ci 67462306a36Sopenharmony_ci if (WARN_ON(!of_property_read_bool(np, "interrupt-controller"))) { 67562306a36Sopenharmony_ci pr_warn("Outdated DT detected, suspend/resume will NOT work\n"); 67662306a36Sopenharmony_ci of_node_put(np); 67762306a36Sopenharmony_ci return; 67862306a36Sopenharmony_ci } 67962306a36Sopenharmony_ci of_node_put(np); 68062306a36Sopenharmony_ci 68162306a36Sopenharmony_ci pm_data = (const struct exynos_pm_data *) match->data; 68262306a36Sopenharmony_ci 68362306a36Sopenharmony_ci /* All wakeup disable */ 68462306a36Sopenharmony_ci tmp = pmu_raw_readl(S5P_WAKEUP_MASK); 68562306a36Sopenharmony_ci tmp |= pm_data->wake_disable_mask; 68662306a36Sopenharmony_ci pmu_raw_writel(tmp, S5P_WAKEUP_MASK); 68762306a36Sopenharmony_ci 68862306a36Sopenharmony_ci exynos_pm_syscore_ops.suspend = pm_data->pm_suspend; 68962306a36Sopenharmony_ci exynos_pm_syscore_ops.resume = pm_data->pm_resume; 69062306a36Sopenharmony_ci 69162306a36Sopenharmony_ci register_syscore_ops(&exynos_pm_syscore_ops); 69262306a36Sopenharmony_ci suspend_set_ops(&exynos_suspend_ops); 69362306a36Sopenharmony_ci 69462306a36Sopenharmony_ci /* 69562306a36Sopenharmony_ci * Applicable as of now only to Exynos542x. If booted under secure 69662306a36Sopenharmony_ci * firmware, the non-secure region of sysram should be used. 69762306a36Sopenharmony_ci */ 69862306a36Sopenharmony_ci if (exynos_secure_firmware_available()) { 69962306a36Sopenharmony_ci pm_state.sysram_phys = sysram_base_phys; 70062306a36Sopenharmony_ci pm_state.sysram_base = sysram_ns_base_addr; 70162306a36Sopenharmony_ci pm_state.secure_firmware = true; 70262306a36Sopenharmony_ci } else { 70362306a36Sopenharmony_ci pm_state.sysram_base = sysram_base_addr; 70462306a36Sopenharmony_ci } 70562306a36Sopenharmony_ci} 706