blob: 437c3d8e87ebd80211b0fca6b0724b0ae53dab6b [file] [log] [blame]
b.liue9582032025-04-17 19:18:16 +08001/*
2 * linux/arch/arm/mach-mmp/pm.c
3 *
4 * Author: Fan Wu <fwu@marvell.com>
5 * Copyright: (C) 2012 Marvell International Ltd.
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 */
12
13#include <asm/cputype.h>
14#include <linux/irq.h>
15#include <linux/interrupt.h>
16#include <asm/mcpm.h>
17#include <linux/suspend.h>
18#include <asm/suspend.h>
19#include <soc/asr/asr18xx_lowpower.h>
20#include <linux/irqchip/arm-gic.h>
21#include <linux/irqchip/mmp.h>
22#include <linux/cpu_pm.h>
23#include "irqs.h"
24#include "pm.h"
25#include <soc/asr/mmp_cpuidle.h>
26
27struct platform_suspend *mmp_suspend;
28u32 detect_wakeup_status = 0;
29EXPORT_SYMBOL(detect_wakeup_status);
30
31#if !defined(CONFIG_CPU_ASR18XX)
32static int notrace mcpm_powerdown_finisher(unsigned long arg)
33{
34 u32 mpidr = read_cpuid_mpidr();
35 u32 cpu = MPIDR_AFFINITY_LEVEL(mpidr, 0);
36 u32 this_cluster = MPIDR_AFFINITY_LEVEL(mpidr, 1);
37
38 mcpm_set_entry_vector(cpu, this_cluster, cpu_resume);
39
40 asr_set_target_lpm_state(cpu, this_cluster, *((int *)arg), (int *)arg);
41
42 mcpm_cpu_suspend();
43 return 1;
44}
45#endif
46
47#if defined(CONFIG_CPU_ASR18XX)
48extern void asr18xx_pm_power_down(void);
49extern void asr18xx_pm_powered_up(void);
50extern void asr18xx_dcstat(unsigned long addr, unsigned int flag);
51extern int asr18xx_pm_check_constraint(void);
52static int notrace mmp_suspend_finish(unsigned long val)
53{
54 asr18xx_pm_power_down();
55 return 1;
56}
57#endif
58
59static int mmp_pm_enter(suspend_state_t state)
60{
61 unsigned int real_idx = mmp_suspend->suspend_state;
62
63 if (mmp_suspend->ops->pre_suspend_check) {
64 if (mmp_suspend->ops->pre_suspend_check())
65 return -EAGAIN;
66 }
67#if !defined(CONFIG_CPU_ASR18XX)
68 cpu_suspend((unsigned long)&real_idx, mcpm_powerdown_finisher);
69#else
70 cpu_suspend((unsigned long)&real_idx, mmp_suspend_finish);
71#endif
72 if (mmp_suspend->ops->post_chk_wakeup)
73 detect_wakeup_status = mmp_suspend->ops->post_chk_wakeup();
74
75 if (mmp_suspend->ops->post_clr_wakeup)
76 mmp_suspend->ops->post_clr_wakeup(detect_wakeup_status);
77
78 if (real_idx != mmp_suspend->suspend_state)
79 pr_info("WARNING!!! "
80 "Suspend Didn't enter the Expected Low power mode\n");
81#if !defined(CONFIG_CPU_ASR18XX)
82 mcpm_cpu_powered_up();
83#else
84 asr18xx_pm_powered_up();
85#endif
86 return 0;
87}
88
89static int mmp_pm_valid(suspend_state_t state)
90{
91 return ((state == PM_SUSPEND_STANDBY) || (state == PM_SUSPEND_MEM));
92}
93
94extern void asr_clear_wakeup_event_idx(void);
95/* Called after devices suspend, before noirq devices suspend */
96static int mmp_pm_prepare(void)
97{
98#ifdef CONFIG_CPU_ASR18XX
99 asr18xx_dcstat(0, 0);
100#endif
101 asr_clear_wakeup_event_idx();
102 return 0;
103}
104
105/* Called after noirq devices resume, before devices resume */
106static void mmp_pm_finish(void)
107{
108}
109
110/* Called after Non-boot CPUs have been Hotplug in if necessary */
111static void mmp_pm_wake(void)
112{
113}
114
115static const struct platform_suspend_ops mmp_pm_ops = {
116 .valid = mmp_pm_valid,
117 .prepare = mmp_pm_prepare,
118 .enter = mmp_pm_enter,
119 .finish = mmp_pm_finish,
120 .wake = mmp_pm_wake,
121};
122
123int mmp_set_wake(struct irq_data *data, unsigned int on)
124{
125 int irq = (int)data->hwirq;
126 struct irq_desc *desc = irq_to_desc(data->irq);
127
128 if (!mmp_suspend->ops->set_wake) {
129 WARN_ON("Platform set_wake function is not Existed!!");
130 return -EINVAL;
131 }
132 if (!desc) {
133 pr_err("irq_desc is NULL\n");
134 return -EINVAL;
135 }
136 if (on) {
137 if (desc->action)
138 desc->action->flags |= IRQF_NO_SUSPEND;
139 } else {
140 if (desc->action)
141 desc->action->flags &= ~IRQF_NO_SUSPEND;
142 }
143
144 mmp_suspend->ops->set_wake(irq, on);
145
146 return 0;
147}
148
149int __init mmp_platform_suspend_register(struct platform_suspend *plt_suspend)
150{
151 if (mmp_suspend)
152 return -EBUSY;
153
154 mmp_suspend = plt_suspend;
155
156 suspend_set_ops(&mmp_pm_ops);
157#ifndef CONFIG_CPU_ASR18XX
158 gic_arch_extn.irq_set_wake = mmp_set_wake;
159#else
160 icu_irq_chip.irq_set_wake = mmp_set_wake;
161#endif
162 if (mmp_suspend->ops->plt_suspend_init)
163 mmp_suspend->ops->plt_suspend_init();
164
165 return 0;
166}