linux/arch/arm/mach-mmp/pm-pxa910.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * PXA910 Power Management Routines
   4 *
   5 * (C) Copyright 2009 Marvell International Ltd.
   6 * All Rights Reserved
   7 */
   8
   9#include <linux/kernel.h>
  10#include <linux/errno.h>
  11#include <linux/err.h>
  12#include <linux/time.h>
  13#include <linux/delay.h>
  14#include <linux/suspend.h>
  15#include <linux/interrupt.h>
  16#include <linux/io.h>
  17#include <linux/irq.h>
  18#include <asm/mach-types.h>
  19#include <asm/outercache.h>
  20
  21#include <linux/soc/mmp/cputype.h>
  22#include "addr-map.h"
  23#include "pm-pxa910.h"
  24#include "regs-icu.h"
  25#include "irqs.h"
  26
  27int pxa910_set_wake(struct irq_data *data, unsigned int on)
  28{
  29        uint32_t awucrm = 0, apcr = 0;
  30        int irq = data->irq;
  31
  32        /* setting wakeup sources */
  33        switch (irq) {
  34        /* wakeup line 2 */
  35        case IRQ_PXA910_AP_GPIO:
  36                awucrm = MPMU_AWUCRM_WAKEUP(2);
  37                apcr |= MPMU_APCR_SLPWP2;
  38                break;
  39        /* wakeup line 3 */
  40        case IRQ_PXA910_KEYPAD:
  41                awucrm = MPMU_AWUCRM_WAKEUP(3) | MPMU_AWUCRM_KEYPRESS;
  42                apcr |= MPMU_APCR_SLPWP3;
  43                break;
  44        case IRQ_PXA910_ROTARY:
  45                awucrm = MPMU_AWUCRM_WAKEUP(3) | MPMU_AWUCRM_NEWROTARY;
  46                apcr |= MPMU_APCR_SLPWP3;
  47                break;
  48        case IRQ_PXA910_TRACKBALL:
  49                awucrm = MPMU_AWUCRM_WAKEUP(3) | MPMU_AWUCRM_TRACKBALL;
  50                apcr |= MPMU_APCR_SLPWP3;
  51                break;
  52        /* wakeup line 4 */
  53        case IRQ_PXA910_AP1_TIMER1:
  54                awucrm = MPMU_AWUCRM_WAKEUP(4) | MPMU_AWUCRM_AP1_TIMER_1;
  55                apcr |= MPMU_APCR_SLPWP4;
  56                break;
  57        case IRQ_PXA910_AP1_TIMER2:
  58                awucrm = MPMU_AWUCRM_WAKEUP(4) | MPMU_AWUCRM_AP1_TIMER_2;
  59                apcr |= MPMU_APCR_SLPWP4;
  60                break;
  61        case IRQ_PXA910_AP1_TIMER3:
  62                awucrm = MPMU_AWUCRM_WAKEUP(4) | MPMU_AWUCRM_AP1_TIMER_3;
  63                apcr |= MPMU_APCR_SLPWP4;
  64                break;
  65        case IRQ_PXA910_AP2_TIMER1:
  66                awucrm = MPMU_AWUCRM_WAKEUP(4) | MPMU_AWUCRM_AP2_TIMER_1;
  67                apcr |= MPMU_APCR_SLPWP4;
  68                break;
  69        case IRQ_PXA910_AP2_TIMER2:
  70                awucrm = MPMU_AWUCRM_WAKEUP(4) | MPMU_AWUCRM_AP2_TIMER_2;
  71                apcr |= MPMU_APCR_SLPWP4;
  72                break;
  73        case IRQ_PXA910_AP2_TIMER3:
  74                awucrm = MPMU_AWUCRM_WAKEUP(4) | MPMU_AWUCRM_AP2_TIMER_3;
  75                apcr |= MPMU_APCR_SLPWP4;
  76                break;
  77        case IRQ_PXA910_RTC_ALARM:
  78                awucrm = MPMU_AWUCRM_WAKEUP(4) | MPMU_AWUCRM_RTC_ALARM;
  79                apcr |= MPMU_APCR_SLPWP4;
  80                break;
  81        /* wakeup line 5 */
  82        case IRQ_PXA910_USB1:
  83        case IRQ_PXA910_USB2:
  84                awucrm = MPMU_AWUCRM_WAKEUP(5);
  85                apcr |= MPMU_APCR_SLPWP5;
  86                break;
  87        /* wakeup line 6 */
  88        case IRQ_PXA910_MMC:
  89                awucrm = MPMU_AWUCRM_WAKEUP(6)
  90                        | MPMU_AWUCRM_SDH1
  91                        | MPMU_AWUCRM_SDH2;
  92                apcr |= MPMU_APCR_SLPWP6;
  93                break;
  94        /* wakeup line 7 */
  95        case IRQ_PXA910_PMIC_INT:
  96                awucrm = MPMU_AWUCRM_WAKEUP(7);
  97                apcr |= MPMU_APCR_SLPWP7;
  98                break;
  99        default:
 100                if (irq >= IRQ_GPIO_START && irq < IRQ_BOARD_START) {
 101                        awucrm = MPMU_AWUCRM_WAKEUP(2);
 102                        apcr |= MPMU_APCR_SLPWP2;
 103                } else {
 104                        /* FIXME: This should return a proper error code ! */
 105                        printk(KERN_ERR "Error: no defined wake up source irq: %d\n",
 106                                irq);
 107                }
 108        }
 109
 110        if (on) {
 111                if (awucrm) {
 112                        awucrm |= __raw_readl(MPMU_AWUCRM);
 113                        __raw_writel(awucrm, MPMU_AWUCRM);
 114                }
 115                if (apcr) {
 116                        apcr = ~apcr & __raw_readl(MPMU_APCR);
 117                        __raw_writel(apcr, MPMU_APCR);
 118                }
 119        } else {
 120                if (awucrm) {
 121                        awucrm = ~awucrm & __raw_readl(MPMU_AWUCRM);
 122                        __raw_writel(awucrm, MPMU_AWUCRM);
 123                }
 124                if (apcr) {
 125                        apcr |= __raw_readl(MPMU_APCR);
 126                        __raw_writel(apcr, MPMU_APCR);
 127                }
 128        }
 129        return 0;
 130}
 131
 132void pxa910_pm_enter_lowpower_mode(int state)
 133{
 134        uint32_t idle_cfg, apcr;
 135
 136        idle_cfg = __raw_readl(APMU_MOH_IDLE_CFG);
 137        apcr = __raw_readl(MPMU_APCR);
 138
 139        apcr &= ~(MPMU_APCR_DDRCORSD | MPMU_APCR_APBSD | MPMU_APCR_AXISD
 140                | MPMU_APCR_VCTCXOSD | MPMU_APCR_STBYEN);
 141        idle_cfg &= ~(APMU_MOH_IDLE_CFG_MOH_IDLE
 142                | APMU_MOH_IDLE_CFG_MOH_PWRDWN);
 143
 144        switch (state) {
 145        case POWER_MODE_UDR:
 146                /* only shutdown APB in UDR */
 147                apcr |= MPMU_APCR_STBYEN | MPMU_APCR_APBSD;
 148                fallthrough;
 149        case POWER_MODE_SYS_SLEEP:
 150                apcr |= MPMU_APCR_SLPEN;                /* set the SLPEN bit */
 151                apcr |= MPMU_APCR_VCTCXOSD;             /* set VCTCXOSD */
 152                fallthrough;
 153        case POWER_MODE_APPS_SLEEP:
 154                apcr |= MPMU_APCR_DDRCORSD;             /* set DDRCORSD */
 155                fallthrough;
 156        case POWER_MODE_APPS_IDLE:
 157                apcr |= MPMU_APCR_AXISD;                /* set AXISDD bit */
 158                fallthrough;
 159        case POWER_MODE_CORE_EXTIDLE:
 160                idle_cfg |= APMU_MOH_IDLE_CFG_MOH_IDLE;
 161                idle_cfg |= APMU_MOH_IDLE_CFG_MOH_PWRDWN;
 162                idle_cfg |= APMU_MOH_IDLE_CFG_MOH_PWR_SW(3)
 163                        | APMU_MOH_IDLE_CFG_MOH_L2_PWR_SW(3);
 164                fallthrough;
 165        case POWER_MODE_CORE_INTIDLE:
 166                break;
 167        }
 168
 169        /* program the memory controller hardware sleep type and auto wakeup */
 170        idle_cfg |= APMU_MOH_IDLE_CFG_MOH_DIS_MC_SW_REQ;
 171        idle_cfg |= APMU_MOH_IDLE_CFG_MOH_MC_WAKE_EN;
 172        __raw_writel(0x0, APMU_MC_HW_SLP_TYPE);         /* auto refresh */
 173
 174        /* set DSPSD, DTCMSD, BBSD, MSASLPEN */
 175        apcr |= MPMU_APCR_DSPSD | MPMU_APCR_DTCMSD | MPMU_APCR_BBSD
 176                | MPMU_APCR_MSASLPEN;
 177
 178        /*always set SLEPEN bit mainly for MSA*/
 179        apcr |= MPMU_APCR_SLPEN;
 180
 181        /* finally write the registers back */
 182        __raw_writel(idle_cfg, APMU_MOH_IDLE_CFG);
 183        __raw_writel(apcr, MPMU_APCR);
 184
 185}
 186
 187static int pxa910_pm_enter(suspend_state_t state)
 188{
 189        unsigned int idle_cfg, reg = 0;
 190
 191        /*pmic thread not completed,exit;otherwise system can't be waked up*/
 192        reg = __raw_readl(ICU_INT_CONF(IRQ_PXA910_PMIC_INT));
 193        if ((reg & 0x3) == 0)
 194                return -EAGAIN;
 195
 196        idle_cfg = __raw_readl(APMU_MOH_IDLE_CFG);
 197        idle_cfg |= APMU_MOH_IDLE_CFG_MOH_PWRDWN
 198                | APMU_MOH_IDLE_CFG_MOH_SRAM_PWRDWN;
 199        __raw_writel(idle_cfg, APMU_MOH_IDLE_CFG);
 200
 201        /* disable L2 */
 202        outer_disable();
 203        /* wait for l2 idle */
 204        while (!(readl(CIU_REG(0x8)) & (1 << 16)))
 205                udelay(1);
 206
 207        cpu_do_idle();
 208
 209        /* enable L2 */
 210        outer_resume();
 211        /* wait for l2 idle */
 212        while (!(readl(CIU_REG(0x8)) & (1 << 16)))
 213                udelay(1);
 214
 215        idle_cfg = __raw_readl(APMU_MOH_IDLE_CFG);
 216        idle_cfg &= ~(APMU_MOH_IDLE_CFG_MOH_PWRDWN
 217                | APMU_MOH_IDLE_CFG_MOH_SRAM_PWRDWN);
 218        __raw_writel(idle_cfg, APMU_MOH_IDLE_CFG);
 219
 220        return 0;
 221}
 222
 223/*
 224 * Called after processes are frozen, but before we shut down devices.
 225 */
 226static int pxa910_pm_prepare(void)
 227{
 228        pxa910_pm_enter_lowpower_mode(POWER_MODE_UDR);
 229        return 0;
 230}
 231
 232/*
 233 * Called after devices are re-setup, but before processes are thawed.
 234 */
 235static void pxa910_pm_finish(void)
 236{
 237        pxa910_pm_enter_lowpower_mode(POWER_MODE_CORE_INTIDLE);
 238}
 239
 240static int pxa910_pm_valid(suspend_state_t state)
 241{
 242        return ((state == PM_SUSPEND_STANDBY) || (state == PM_SUSPEND_MEM));
 243}
 244
 245static const struct platform_suspend_ops pxa910_pm_ops = {
 246        .valid          = pxa910_pm_valid,
 247        .prepare        = pxa910_pm_prepare,
 248        .enter          = pxa910_pm_enter,
 249        .finish         = pxa910_pm_finish,
 250};
 251
 252static int __init pxa910_pm_init(void)
 253{
 254        uint32_t awucrm = 0;
 255
 256        if (!cpu_is_pxa910())
 257                return -EIO;
 258
 259        suspend_set_ops(&pxa910_pm_ops);
 260
 261        /* Set the following bits for MMP3 playback with VCTXO on */
 262        __raw_writel(__raw_readl(APMU_SQU_CLK_GATE_CTRL) | (1 << 30),
 263                APMU_SQU_CLK_GATE_CTRL);
 264        __raw_writel(__raw_readl(MPMU_FCCR) | (1 << 28), MPMU_FCCR);
 265
 266        awucrm |= MPMU_AWUCRM_AP_ASYNC_INT | MPMU_AWUCRM_AP_FULL_IDLE;
 267        __raw_writel(awucrm, MPMU_AWUCRM);
 268
 269        return 0;
 270}
 271
 272late_initcall(pxa910_pm_init);
 273