blob: 609cde70125ae5a906118abdee47ff17d92d87c0 [file] [log] [blame]
b.liue9582032025-04-17 19:18:16 +08001#include <linux/cpuidle.h>
2#include <linux/cpu_pm.h>
3#include <linux/clk/dvfs-dvc.h>
4#include <linux/kernel.h>
5#include <linux/errno.h>
6#include <linux/err.h>
7#include <linux/io.h>
8#include <linux/edge_wakeup_mmp.h>
9#include <linux/slab.h>
10#include <soc/asr/regs-addr.h>
11#include <linux/cputype.h>
12#include <asm/cpuidle.h>
13#include <asm/mach/map.h>
14#include <asm/mcpm.h>
15#include <soc/asr/mmp_cpuidle.h>
16#ifdef CONFIG_CPU_ASR1901
17#include <soc/asr/asr1901_lowpower.h>
18#else
19#include <soc/asr/asr18xx_lowpower.h>
20#endif
21#include "addr-map.h"
22#include <linux/arm-smccc.h>
23#include <linux/of_address.h>
24#include <linux/asr_tee_sip.h>
25
26extern int __init asr_platform_power_register(struct platform_idle *idle);
27
28
29#ifdef CONFIG_CPU_ASR1901
30#define ASR_CPUIDLE_FLAG CPUIDLE_FLAG_NONE
31#else
32#define ASR_CPUIDLE_FLAG CPUIDLE_FLAG_TIMER_STOP
33#endif
34
35static struct cpuidle_state asr_modes[] = {
36 [0] = {
37 .exit_latency = 18,
38 .target_residency = 36,
39 /*
40 * Use CPUIDLE_FLAG_TIMER_STOP flag to let the cpuidle
41 * framework handle the CLOCK_EVENT_NOTIFY_BROADCAST_
42 * ENTER/EXIT when entering idle states.
43 */
44 .flags = /* CPUIDLE_FLAG_TIME_VALID */0,
45 .name = "C1",
46 .desc = "C1: Core internal clock gated",
47 .enter = arm_cpuidle_simple_enter,
48 },
49 [1] = {
50 .exit_latency = 350,
51 .target_residency = 700,
52 .flags = ASR_CPUIDLE_FLAG,
53 .name = "C2",
54 .desc = "C2: Core power down",
55 },
56 [2] = {
57 .exit_latency = 500,
58 .target_residency = 1000,
59 .flags = ASR_CPUIDLE_FLAG,
60 .name = "D1p",
61 .desc = "D1p: AP idle state",
62 },
63 [3] = {
64 .exit_latency = 600,
65 .target_residency = 1200,
66 .flags = ASR_CPUIDLE_FLAG,
67 .name = "D1",
68 .desc = "D1: Chip idle state",
69 },
70
71
72};
73
74static int need_restore_pad_wakeup;
75
76#ifdef CONFIG_CPU_ASR1901
77#define EDGE_WAKEUP_GIC 39 /* GIC interrupt num for edge wakeup */
78
79extern void extern_gic_mask_unmask_irq(int irq_num, bool mask);
80
81static void edge_wakeup_gic_enable(void)
82{
83 extern_gic_mask_unmask_irq(EDGE_WAKEUP_GIC, 0);
84}
85
86static void edge_wakeup_gic_disable(void)
87{
88 extern_gic_mask_unmask_irq(EDGE_WAKEUP_GIC, 1);
89}
90#endif
91
92void asr_set_pmu(u32 cpu, u32 power_mode)
93{
94 (void)cpu;
95
96 /* TODO: move to TOS next step */
97 if(power_mode > POWER_MODE_CORE_POWERDOWN) {
98 edge_wakeup_mfp_enable();
99#ifdef CONFIG_CPU_ASR1901
100 edge_wakeup_gic_enable();
101#endif
102 need_restore_pad_wakeup = 1;
103 }
104}
105
106void asr_clr_pmu(u32 cpu)
107{
108 /* TODO: move to TOS next step */
109 if(need_restore_pad_wakeup) {
110 edge_wakeup_mfp_disable();
111#ifdef CONFIG_CPU_ASR1901
112 edge_wakeup_gic_disable();
113#endif
114 need_restore_pad_wakeup = 0;
115 }
116}
117
118static struct platform_power_ops asr_power_ops = {
119 .set_pmu = asr_set_pmu,
120 .clr_pmu = asr_clr_pmu,
121 .save_wakeup = NULL,
122 .restore_wakeup = NULL,
123 .power_up_setup = ca7_power_up_setup,
124 .cpu_power_status = NULL,
125};
126
127static struct platform_idle asr_idle = {
128 .cpudown_state = POWER_MODE_CORE_POWERDOWN,
129 .wakeup_state = POWER_MODE_SYS_SLEEP,
130 .hotplug_state = POWER_MODE_UDR,
131 .l2_flush_state = POWER_MODE_UDR,
132 .ops = &asr_power_ops,
133 .states = asr_modes,
134 .state_count = ARRAY_SIZE(asr_modes),
135};
136
137static int __init asr_lowpower_init(void)
138{
139
140 asr_platform_power_register(&asr_idle);
141
142#ifdef CONFIG_ARM_ERRATA_802022
143 {
144 u32 mp_idle_cfg;
145 int i;
146
147 for_each_possible_cpu(i) {
148 mp_idle_cfg = __raw_readl(APMU_MP_IDLE_CFG[i]);
149 mp_idle_cfg |= (PMUA_DIS_MP_SLP);
150 __raw_writel(mp_idle_cfg, APMU_MP_IDLE_CFG[i]);
151 }
152 }
153#endif
154
155 return 0;
156}
157early_initcall(asr_lowpower_init);