0001
0002
0003
0004
0005
0006
0007
0008
0009 #include <linux/kernel.h>
0010 #include <linux/errno.h>
0011 #include <linux/err.h>
0012 #include <linux/time.h>
0013 #include <linux/delay.h>
0014 #include <linux/suspend.h>
0015 #include <linux/irq.h>
0016 #include <linux/io.h>
0017 #include <linux/interrupt.h>
0018 #include <asm/mach-types.h>
0019
0020 #include <linux/soc/mmp/cputype.h>
0021 #include "addr-map.h"
0022 #include "pm-mmp2.h"
0023 #include "regs-icu.h"
0024 #include "irqs.h"
0025
0026 int mmp2_set_wake(struct irq_data *d, unsigned int on)
0027 {
0028 unsigned long data = 0;
0029 int irq = d->irq;
0030
0031
0032 switch (irq) {
0033 case IRQ_MMP2_RTC:
0034 case IRQ_MMP2_RTC_ALARM:
0035 data = MPMU_WUCRM_PJ_WAKEUP(4) | MPMU_WUCRM_PJ_RTC_ALARM;
0036 break;
0037 case IRQ_MMP2_PMIC:
0038 data = MPMU_WUCRM_PJ_WAKEUP(7);
0039 break;
0040 case IRQ_MMP2_MMC2:
0041
0042 data = MPMU_WUCRM_PJ_WAKEUP(2);
0043 break;
0044 }
0045 if (on) {
0046 if (data) {
0047 data |= __raw_readl(MPMU_WUCRM_PJ);
0048 __raw_writel(data, MPMU_WUCRM_PJ);
0049 }
0050 } else {
0051 if (data) {
0052 data = ~data & __raw_readl(MPMU_WUCRM_PJ);
0053 __raw_writel(data, MPMU_WUCRM_PJ);
0054 }
0055 }
0056 return 0;
0057 }
0058
0059 static void pm_scu_clk_disable(void)
0060 {
0061 unsigned int val;
0062
0063
0064 __raw_writel(0x0, CIU_REG(0x64));
0065 __raw_writel(0x0, CIU_REG(0x68));
0066
0067
0068 val = __raw_readl(CIU_REG(0x1c));
0069 val |= 0xf0;
0070 __raw_writel(val, CIU_REG(0x1c));
0071
0072 return ;
0073 }
0074
0075 static void pm_scu_clk_enable(void)
0076 {
0077 unsigned int val;
0078
0079
0080 __raw_writel(0x03003003, CIU_REG(0x64));
0081 __raw_writel(0x00303030, CIU_REG(0x68));
0082
0083
0084 val = __raw_readl(CIU_REG(0x1c));
0085 val &= ~(0xf0);
0086 __raw_writel(val, CIU_REG(0x1c));
0087
0088 return ;
0089 }
0090
0091 static void pm_mpmu_clk_disable(void)
0092 {
0093
0094
0095
0096
0097 __raw_writel(0x0000a010, MPMU_CGR_PJ);
0098 }
0099
0100 static void pm_mpmu_clk_enable(void)
0101 {
0102 unsigned int val;
0103
0104 __raw_writel(0xdffefffe, MPMU_CGR_PJ);
0105 val = __raw_readl(MPMU_PLL2_CTRL1);
0106 val |= (1 << 29);
0107 __raw_writel(val, MPMU_PLL2_CTRL1);
0108
0109 return ;
0110 }
0111
0112 void mmp2_pm_enter_lowpower_mode(int state)
0113 {
0114 uint32_t idle_cfg, apcr;
0115
0116 idle_cfg = __raw_readl(APMU_PJ_IDLE_CFG);
0117 apcr = __raw_readl(MPMU_PCR_PJ);
0118 apcr &= ~(MPMU_PCR_PJ_SLPEN | MPMU_PCR_PJ_DDRCORSD | MPMU_PCR_PJ_APBSD
0119 | MPMU_PCR_PJ_AXISD | MPMU_PCR_PJ_VCTCXOSD | (1 << 13));
0120 idle_cfg &= ~APMU_PJ_IDLE_CFG_PJ_IDLE;
0121
0122 switch (state) {
0123 case POWER_MODE_SYS_SLEEP:
0124 apcr |= MPMU_PCR_PJ_SLPEN;
0125 apcr |= MPMU_PCR_PJ_VCTCXOSD;
0126 fallthrough;
0127 case POWER_MODE_CHIP_SLEEP:
0128 apcr |= MPMU_PCR_PJ_SLPEN;
0129 fallthrough;
0130 case POWER_MODE_APPS_SLEEP:
0131 apcr |= MPMU_PCR_PJ_APBSD;
0132 fallthrough;
0133 case POWER_MODE_APPS_IDLE:
0134 apcr |= MPMU_PCR_PJ_AXISD;
0135 apcr |= MPMU_PCR_PJ_DDRCORSD;
0136 idle_cfg |= APMU_PJ_IDLE_CFG_PJ_PWRDWN;
0137 apcr |= MPMU_PCR_PJ_SPSD;
0138 fallthrough;
0139 case POWER_MODE_CORE_EXTIDLE:
0140 idle_cfg |= APMU_PJ_IDLE_CFG_PJ_IDLE;
0141 idle_cfg &= ~APMU_PJ_IDLE_CFG_ISO_MODE_CNTRL_MASK;
0142 idle_cfg |= APMU_PJ_IDLE_CFG_PWR_SW(3)
0143 | APMU_PJ_IDLE_CFG_L2_PWR_SW;
0144 break;
0145 case POWER_MODE_CORE_INTIDLE:
0146 apcr &= ~MPMU_PCR_PJ_SPSD;
0147 break;
0148 }
0149
0150
0151 apcr |= (1 << 30) | (1 << 25);
0152
0153
0154 __raw_writel(idle_cfg, APMU_PJ_IDLE_CFG);
0155 __raw_writel(apcr, MPMU_PCR_PJ);
0156 }
0157
0158 static int mmp2_pm_enter(suspend_state_t state)
0159 {
0160 int temp;
0161
0162 temp = __raw_readl(MMP2_ICU_INT4_MASK);
0163 if (temp & (1 << 1)) {
0164 printk(KERN_ERR "%s: PMIC interrupt is handling\n", __func__);
0165 return -EAGAIN;
0166 }
0167
0168 temp = __raw_readl(APMU_SRAM_PWR_DWN);
0169 temp |= ((1 << 19) | (1 << 18));
0170 __raw_writel(temp, APMU_SRAM_PWR_DWN);
0171 pm_mpmu_clk_disable();
0172 pm_scu_clk_disable();
0173
0174 printk(KERN_INFO "%s: before suspend\n", __func__);
0175 cpu_do_idle();
0176 printk(KERN_INFO "%s: after suspend\n", __func__);
0177
0178 pm_mpmu_clk_enable();
0179 pm_scu_clk_enable();
0180
0181 return 0;
0182 }
0183
0184
0185
0186
0187 static int mmp2_pm_prepare(void)
0188 {
0189 mmp2_pm_enter_lowpower_mode(POWER_MODE_SYS_SLEEP);
0190
0191 return 0;
0192 }
0193
0194
0195
0196
0197 static void mmp2_pm_finish(void)
0198 {
0199 mmp2_pm_enter_lowpower_mode(POWER_MODE_CORE_INTIDLE);
0200 }
0201
0202 static int mmp2_pm_valid(suspend_state_t state)
0203 {
0204 return ((state == PM_SUSPEND_STANDBY) || (state == PM_SUSPEND_MEM));
0205 }
0206
0207
0208
0209
0210 static const struct platform_suspend_ops mmp2_pm_ops = {
0211 .valid = mmp2_pm_valid,
0212 .prepare = mmp2_pm_prepare,
0213 .enter = mmp2_pm_enter,
0214 .finish = mmp2_pm_finish,
0215 };
0216
0217 static int __init mmp2_pm_init(void)
0218 {
0219 uint32_t apcr;
0220
0221 if (!cpu_is_mmp2())
0222 return -EIO;
0223
0224 suspend_set_ops(&mmp2_pm_ops);
0225
0226
0227
0228
0229
0230 __raw_writel(0x5, MPMU_SCCR);
0231
0232
0233
0234
0235
0236
0237 __raw_writel(__raw_readl(CIU_REG(0x8)) & ~(0x1 << 23), CIU_REG(0x8));
0238
0239
0240 apcr = __raw_readl(MPMU_PCR_PJ);
0241 apcr &= ~(MPMU_PCR_PJ_SLPEN | MPMU_PCR_PJ_DDRCORSD
0242 | MPMU_PCR_PJ_APBSD | MPMU_PCR_PJ_AXISD | 1 << 13);
0243 __raw_writel(apcr, MPMU_PCR_PJ);
0244
0245 return 0;
0246 }
0247
0248 late_initcall(mmp2_pm_init);