Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * MMP2 Power Management Routines
0004  *
0005  * (C) Copyright 2012 Marvell International Ltd.
0006  * All Rights Reserved
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     /* enable wakeup sources */
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         /* mmc use WAKEUP2, same as GPIO wakeup source */
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     /* close AXI fabric clock gate */
0064     __raw_writel(0x0, CIU_REG(0x64));
0065     __raw_writel(0x0, CIU_REG(0x68));
0066 
0067     /* close MCB master clock gate */
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     /* open AXI fabric clock gate */
0080     __raw_writel(0x03003003, CIU_REG(0x64));
0081     __raw_writel(0x00303030, CIU_REG(0x68));
0082 
0083     /* open MCB master clock gate */
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      * disable clocks in MPMU_CGR_PJ register
0095      * except clock for APMU_PLL1, APMU_PLL1_2 and AP_26M
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;      /* set the SLPEN bit */
0125         apcr |= MPMU_PCR_PJ_VCTCXOSD;       /* set 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;      /* set APBSD */
0132         fallthrough;
0133     case POWER_MODE_APPS_IDLE:
0134         apcr |= MPMU_PCR_PJ_AXISD;      /* set AXISDD bit */
0135         apcr |= MPMU_PCR_PJ_DDRCORSD;       /* set DDRCORSD bit */
0136         idle_cfg |= APMU_PJ_IDLE_CFG_PJ_PWRDWN; /* PJ power down */
0137         apcr |= MPMU_PCR_PJ_SPSD;
0138         fallthrough;
0139     case POWER_MODE_CORE_EXTIDLE:
0140         idle_cfg |= APMU_PJ_IDLE_CFG_PJ_IDLE;   /* set the IDLE bit */
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     /* set reserve bits */
0151     apcr |= (1 << 30) | (1 << 25);
0152 
0153     /* finally write the registers back */
0154     __raw_writel(idle_cfg, APMU_PJ_IDLE_CFG);
0155     __raw_writel(apcr, MPMU_PCR_PJ);    /* 0xfe086000 */
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();       /* enable clocks in MPMU */
0179     pm_scu_clk_enable();        /* enable clocks in SCU */
0180 
0181     return 0;
0182 }
0183 
0184 /*
0185  * Called after processes are frozen, but before we shut down devices.
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  * Called after devices are re-setup, but before processes are thawed.
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  * Set to PM_DISK_FIRMWARE so we can quickly veto suspend-to-disk.
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      * Set bit 0, Slow clock Select 32K clock input instead of VCXO
0228      * VCXO is chosen by default, which would be disabled in suspend
0229      */
0230     __raw_writel(0x5, MPMU_SCCR);
0231 
0232     /*
0233      * Clear bit 23 of CIU_CPU_CONF
0234      * direct PJ4 to DDR access through Memory Controller slow queue
0235      * fast queue has issue and cause lcd will flick
0236      */
0237     __raw_writel(__raw_readl(CIU_REG(0x8)) & ~(0x1 << 23), CIU_REG(0x8));
0238 
0239     /* Clear default low power control bit */
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);