linux/arch/arm/mach-omap2/pm24xx.c
<<
>>
Prefs
   1/*
   2 * OMAP2 Power Management Routines
   3 *
   4 * Copyright (C) 2005 Texas Instruments, Inc.
   5 * Copyright (C) 2006-2008 Nokia Corporation
   6 *
   7 * Written by:
   8 * Richard Woodruff <r-woodruff2@ti.com>
   9 * Tony Lindgren
  10 * Juha Yrjola
  11 * Amit Kucheria <amit.kucheria@nokia.com>
  12 * Igor Stoppa <igor.stoppa@nokia.com>
  13 *
  14 * Based on pm.c for omap1
  15 *
  16 * This program is free software; you can redistribute it and/or modify
  17 * it under the terms of the GNU General Public License version 2 as
  18 * published by the Free Software Foundation.
  19 */
  20
  21#include <linux/suspend.h>
  22#include <linux/sched.h>
  23#include <linux/proc_fs.h>
  24#include <linux/interrupt.h>
  25#include <linux/sysfs.h>
  26#include <linux/module.h>
  27#include <linux/delay.h>
  28#include <linux/clk.h>
  29#include <linux/clk-provider.h>
  30#include <linux/irq.h>
  31#include <linux/time.h>
  32#include <linux/gpio.h>
  33#include <linux/platform_data/gpio-omap.h>
  34
  35#include <asm/fncpy.h>
  36
  37#include <asm/mach/time.h>
  38#include <asm/mach/irq.h>
  39#include <asm/mach-types.h>
  40#include <asm/system_misc.h>
  41
  42#include <linux/omap-dma.h>
  43
  44#include "soc.h"
  45#include "common.h"
  46#include "clock.h"
  47#include "prm2xxx.h"
  48#include "prm-regbits-24xx.h"
  49#include "cm2xxx.h"
  50#include "cm-regbits-24xx.h"
  51#include "sdrc.h"
  52#include "sram.h"
  53#include "pm.h"
  54#include "control.h"
  55#include "powerdomain.h"
  56#include "clockdomain.h"
  57
  58static void (*omap2_sram_suspend)(u32 dllctrl, void __iomem *sdrc_dlla_ctrl,
  59                                  void __iomem *sdrc_power);
  60
  61static struct powerdomain *mpu_pwrdm, *core_pwrdm;
  62static struct clockdomain *dsp_clkdm, *mpu_clkdm, *wkup_clkdm, *gfx_clkdm;
  63
  64static struct clk *osc_ck, *emul_ck;
  65
  66static int omap2_enter_full_retention(void)
  67{
  68        u32 l;
  69
  70        /* There is 1 reference hold for all children of the oscillator
  71         * clock, the following will remove it. If no one else uses the
  72         * oscillator itself it will be disabled if/when we enter retention
  73         * mode.
  74         */
  75        clk_disable(osc_ck);
  76
  77        /* Clear old wake-up events */
  78        /* REVISIT: These write to reserved bits? */
  79        omap_prm_clear_mod_irqs(CORE_MOD, PM_WKST1, ~0);
  80        omap_prm_clear_mod_irqs(CORE_MOD, OMAP24XX_PM_WKST2, ~0);
  81        omap_prm_clear_mod_irqs(WKUP_MOD, PM_WKST, ~0);
  82
  83        pwrdm_set_next_pwrst(core_pwrdm, PWRDM_POWER_RET);
  84        pwrdm_set_next_pwrst(mpu_pwrdm, PWRDM_POWER_RET);
  85
  86        /* Workaround to kill USB */
  87        l = omap_ctrl_readl(OMAP2_CONTROL_DEVCONF0) | OMAP24XX_USBSTANDBYCTRL;
  88        omap_ctrl_writel(l, OMAP2_CONTROL_DEVCONF0);
  89
  90        omap2_gpio_prepare_for_idle(0);
  91
  92        /* One last check for pending IRQs to avoid extra latency due
  93         * to sleeping unnecessarily. */
  94        if (omap_irq_pending())
  95                goto no_sleep;
  96
  97        /* Jump to SRAM suspend code */
  98        omap2_sram_suspend(sdrc_read_reg(SDRC_DLLA_CTRL),
  99                           OMAP_SDRC_REGADDR(SDRC_DLLA_CTRL),
 100                           OMAP_SDRC_REGADDR(SDRC_POWER));
 101
 102no_sleep:
 103        omap2_gpio_resume_after_idle();
 104
 105        clk_enable(osc_ck);
 106
 107        /* clear CORE wake-up events */
 108        omap_prm_clear_mod_irqs(CORE_MOD, PM_WKST1, ~0);
 109        omap_prm_clear_mod_irqs(CORE_MOD, OMAP24XX_PM_WKST2, ~0);
 110
 111        /* wakeup domain events - bit 1: GPT1, bit5 GPIO */
 112        omap_prm_clear_mod_irqs(WKUP_MOD, PM_WKST, 0x4 | 0x1);
 113
 114        /* MPU domain wake events */
 115        omap_prm_clear_mod_irqs(OCP_MOD, OMAP2_PRCM_IRQSTATUS_MPU_OFFSET, 0x1);
 116
 117        omap_prm_clear_mod_irqs(OCP_MOD, OMAP2_PRCM_IRQSTATUS_MPU_OFFSET, 0x20);
 118
 119        pwrdm_set_next_pwrst(mpu_pwrdm, PWRDM_POWER_ON);
 120        pwrdm_set_next_pwrst(core_pwrdm, PWRDM_POWER_ON);
 121
 122        return 0;
 123}
 124
 125static int sti_console_enabled;
 126
 127static int omap2_allow_mpu_retention(void)
 128{
 129        if (!omap2xxx_cm_mpu_retention_allowed())
 130                return 0;
 131        if (sti_console_enabled)
 132                return 0;
 133
 134        return 1;
 135}
 136
 137static void omap2_enter_mpu_retention(void)
 138{
 139        const int zero = 0;
 140
 141        /* The peripherals seem not to be able to wake up the MPU when
 142         * it is in retention mode. */
 143        if (omap2_allow_mpu_retention()) {
 144                /* REVISIT: These write to reserved bits? */
 145                omap_prm_clear_mod_irqs(CORE_MOD, PM_WKST1, ~0);
 146                omap_prm_clear_mod_irqs(CORE_MOD, OMAP24XX_PM_WKST2, ~0);
 147                omap_prm_clear_mod_irqs(WKUP_MOD, PM_WKST, ~0);
 148
 149                /* Try to enter MPU retention */
 150                pwrdm_set_next_pwrst(mpu_pwrdm, PWRDM_POWER_RET);
 151
 152        } else {
 153                /* Block MPU retention */
 154                pwrdm_set_next_pwrst(mpu_pwrdm, PWRDM_POWER_ON);
 155        }
 156
 157        /* WFI */
 158        asm("mcr p15, 0, %0, c7, c0, 4" : : "r" (zero) : "memory", "cc");
 159
 160        pwrdm_set_next_pwrst(mpu_pwrdm, PWRDM_POWER_ON);
 161}
 162
 163static int omap2_can_sleep(void)
 164{
 165        if (omap2xxx_cm_fclks_active())
 166                return 0;
 167        if (__clk_is_enabled(osc_ck))
 168                return 0;
 169        if (omap_dma_running())
 170                return 0;
 171
 172        return 1;
 173}
 174
 175static void omap2_pm_idle(void)
 176{
 177        if (!omap2_can_sleep()) {
 178                if (omap_irq_pending())
 179                        return;
 180                omap2_enter_mpu_retention();
 181                return;
 182        }
 183
 184        if (omap_irq_pending())
 185                return;
 186
 187        omap2_enter_full_retention();
 188}
 189
 190static void __init prcm_setup_regs(void)
 191{
 192        int i, num_mem_banks;
 193        struct powerdomain *pwrdm;
 194
 195        /*
 196         * Enable autoidle
 197         * XXX This should be handled by hwmod code or PRCM init code
 198         */
 199        omap2_prm_write_mod_reg(OMAP24XX_AUTOIDLE_MASK, OCP_MOD,
 200                          OMAP2_PRCM_SYSCONFIG_OFFSET);
 201
 202        /*
 203         * Set CORE powerdomain memory banks to retain their contents
 204         * during RETENTION
 205         */
 206        num_mem_banks = pwrdm_get_mem_bank_count(core_pwrdm);
 207        for (i = 0; i < num_mem_banks; i++)
 208                pwrdm_set_mem_retst(core_pwrdm, i, PWRDM_POWER_RET);
 209
 210        pwrdm_set_logic_retst(core_pwrdm, PWRDM_POWER_RET);
 211
 212        pwrdm_set_logic_retst(mpu_pwrdm, PWRDM_POWER_RET);
 213
 214        /* Force-power down DSP, GFX powerdomains */
 215
 216        pwrdm = clkdm_get_pwrdm(dsp_clkdm);
 217        pwrdm_set_next_pwrst(pwrdm, PWRDM_POWER_OFF);
 218
 219        pwrdm = clkdm_get_pwrdm(gfx_clkdm);
 220        pwrdm_set_next_pwrst(pwrdm, PWRDM_POWER_OFF);
 221
 222        /* Enable hardware-supervised idle for all clkdms */
 223        clkdm_for_each(omap_pm_clkdms_setup, NULL);
 224        clkdm_add_wkdep(mpu_clkdm, wkup_clkdm);
 225
 226        omap_common_suspend_init(omap2_enter_full_retention);
 227
 228        /* REVISIT: Configure number of 32 kHz clock cycles for sys_clk
 229         * stabilisation */
 230        omap2_prm_write_mod_reg(15 << OMAP_SETUP_TIME_SHIFT, OMAP24XX_GR_MOD,
 231                                OMAP2_PRCM_CLKSSETUP_OFFSET);
 232
 233        /* Configure automatic voltage transition */
 234        omap2_prm_write_mod_reg(2 << OMAP_SETUP_TIME_SHIFT, OMAP24XX_GR_MOD,
 235                                OMAP2_PRCM_VOLTSETUP_OFFSET);
 236        omap2_prm_write_mod_reg(OMAP24XX_AUTO_EXTVOLT_MASK |
 237                                (0x1 << OMAP24XX_SETOFF_LEVEL_SHIFT) |
 238                                OMAP24XX_MEMRETCTRL_MASK |
 239                                (0x1 << OMAP24XX_SETRET_LEVEL_SHIFT) |
 240                                (0x0 << OMAP24XX_VOLT_LEVEL_SHIFT),
 241                                OMAP24XX_GR_MOD, OMAP2_PRCM_VOLTCTRL_OFFSET);
 242
 243        /* Enable wake-up events */
 244        omap2_prm_write_mod_reg(OMAP24XX_EN_GPIOS_MASK | OMAP24XX_EN_GPT1_MASK,
 245                                WKUP_MOD, PM_WKEN);
 246
 247        /* Enable SYS_CLKEN control when all domains idle */
 248        omap2_prm_set_mod_reg_bits(OMAP_AUTOEXTCLKMODE_MASK, OMAP24XX_GR_MOD,
 249                                   OMAP2_PRCM_CLKSRC_CTRL_OFFSET);
 250}
 251
 252int __init omap2_pm_init(void)
 253{
 254        u32 l;
 255
 256        printk(KERN_INFO "Power Management for OMAP2 initializing\n");
 257        l = omap2_prm_read_mod_reg(OCP_MOD, OMAP2_PRCM_REVISION_OFFSET);
 258        printk(KERN_INFO "PRCM revision %d.%d\n", (l >> 4) & 0x0f, l & 0x0f);
 259
 260        /* Look up important powerdomains */
 261
 262        mpu_pwrdm = pwrdm_lookup("mpu_pwrdm");
 263        if (!mpu_pwrdm)
 264                pr_err("PM: mpu_pwrdm not found\n");
 265
 266        core_pwrdm = pwrdm_lookup("core_pwrdm");
 267        if (!core_pwrdm)
 268                pr_err("PM: core_pwrdm not found\n");
 269
 270        /* Look up important clockdomains */
 271
 272        mpu_clkdm = clkdm_lookup("mpu_clkdm");
 273        if (!mpu_clkdm)
 274                pr_err("PM: mpu_clkdm not found\n");
 275
 276        wkup_clkdm = clkdm_lookup("wkup_clkdm");
 277        if (!wkup_clkdm)
 278                pr_err("PM: wkup_clkdm not found\n");
 279
 280        dsp_clkdm = clkdm_lookup("dsp_clkdm");
 281        if (!dsp_clkdm)
 282                pr_err("PM: dsp_clkdm not found\n");
 283
 284        gfx_clkdm = clkdm_lookup("gfx_clkdm");
 285        if (!gfx_clkdm)
 286                pr_err("PM: gfx_clkdm not found\n");
 287
 288
 289        osc_ck = clk_get(NULL, "osc_ck");
 290        if (IS_ERR(osc_ck)) {
 291                printk(KERN_ERR "could not get osc_ck\n");
 292                return -ENODEV;
 293        }
 294
 295        if (cpu_is_omap242x()) {
 296                emul_ck = clk_get(NULL, "emul_ck");
 297                if (IS_ERR(emul_ck)) {
 298                        printk(KERN_ERR "could not get emul_ck\n");
 299                        clk_put(osc_ck);
 300                        return -ENODEV;
 301                }
 302        }
 303
 304        prcm_setup_regs();
 305
 306        /*
 307         * We copy the assembler sleep/wakeup routines to SRAM.
 308         * These routines need to be in SRAM as that's the only
 309         * memory the MPU can see when it wakes up after the entire
 310         * chip enters idle.
 311         */
 312        omap2_sram_suspend = omap_sram_push(omap24xx_cpu_suspend,
 313                                            omap24xx_cpu_suspend_sz);
 314
 315        arm_pm_idle = omap2_pm_idle;
 316
 317        return 0;
 318}
 319