1/* 2 * linux/arch/arm/mach-omap2/pm.c 3 * 4 * OMAP2 Power Management Routines 5 * 6 * Copyright (C) 2006 Nokia Corporation 7 * Tony Lindgren <tony@atomide.com> 8 * 9 * Copyright (C) 2005 Texas Instruments, Inc. 10 * Richard Woodruff <r-woodruff2@ti.com> 11 * 12 * Based on pm.c for omap1 13 * 14 * This program is free software; you can redistribute it and/or modify 15 * it under the terms of the GNU General Public License version 2 as 16 * published by the Free Software Foundation. 17 */ 18 19#include <linux/pm.h> 20#include <linux/sched.h> 21#include <linux/proc_fs.h> 22#include <linux/pm.h> 23#include <linux/interrupt.h> 24#include <linux/sysfs.h> 25#include <linux/module.h> 26#include <linux/delay.h> 27 28#include <asm/io.h> 29#include <asm/irq.h> 30#include <asm/atomic.h> 31#include <asm/mach/time.h> 32#include <asm/mach/irq.h> 33#include <asm/mach-types.h> 34 35#include <asm/arch/irqs.h> 36#include <asm/arch/clock.h> 37#include <asm/arch/sram.h> 38#include <asm/arch/pm.h> 39 40#include "prcm-regs.h" 41 42static struct clk *vclk; 43static void (*omap2_sram_idle)(void); 44static void (*omap2_sram_suspend)(int dllctrl, int cpu_rev); 45static void (*saved_idle)(void); 46 47extern void __init pmdomain_init(void); 48extern void pmdomain_set_autoidle(void); 49 50static unsigned int omap24xx_sleep_save[OMAP24XX_SLEEP_SAVE_SIZE]; 51 52void omap2_pm_idle(void) 53{ 54 local_irq_disable(); 55 local_fiq_disable(); 56 if (need_resched()) { 57 local_fiq_enable(); 58 local_irq_enable(); 59 return; 60 } 61 62 /* 63 * Since an interrupt may set up a timer, we don't want to 64 * reprogram the hardware timer with interrupts enabled. 65 * Re-enable interrupts only after returning from idle. 66 */ 67 timer_dyn_reprogram(); 68 69 omap2_sram_idle(); 70 local_fiq_enable(); 71 local_irq_enable(); 72} 73 74static int omap2_pm_prepare(suspend_state_t state) 75{ 76 int error = 0; 77 78 /* We cannot sleep in idle until we have resumed */ 79 saved_idle = pm_idle; 80 pm_idle = NULL; 81 82 switch (state) 83 { 84 case PM_SUSPEND_STANDBY: 85 case PM_SUSPEND_MEM: 86 break; 87 88 case PM_SUSPEND_DISK: 89 return -ENOTSUPP; 90 91 default: 92 return -EINVAL; 93 } 94 95 return error; 96} 97 98#define INT0_WAKE_MASK (OMAP_IRQ_BIT(INT_24XX_GPIO_BANK1) | \ 99 OMAP_IRQ_BIT(INT_24XX_GPIO_BANK2) | \ 100 OMAP_IRQ_BIT(INT_24XX_GPIO_BANK3)) 101 102#define INT1_WAKE_MASK (OMAP_IRQ_BIT(INT_24XX_GPIO_BANK4)) 103 104#define INT2_WAKE_MASK (OMAP_IRQ_BIT(INT_24XX_UART1_IRQ) | \ 105 OMAP_IRQ_BIT(INT_24XX_UART2_IRQ) | \ 106 OMAP_IRQ_BIT(INT_24XX_UART3_IRQ)) 107 108#define preg(reg) printk("%s\t(0x%p):\t0x%08x\n", #reg, ®, reg); 109 110static void omap2_pm_debug(char * desc) 111{ 112 printk("%s:\n", desc); 113 114 preg(CM_CLKSTCTRL_MPU); 115 preg(CM_CLKSTCTRL_CORE); 116 preg(CM_CLKSTCTRL_GFX); 117 preg(CM_CLKSTCTRL_DSP); 118 preg(CM_CLKSTCTRL_MDM); 119 120 preg(PM_PWSTCTRL_MPU); 121 preg(PM_PWSTCTRL_CORE); 122 preg(PM_PWSTCTRL_GFX); 123 preg(PM_PWSTCTRL_DSP); 124 preg(PM_PWSTCTRL_MDM); 125 126 preg(PM_PWSTST_MPU); 127 preg(PM_PWSTST_CORE); 128 preg(PM_PWSTST_GFX); 129 preg(PM_PWSTST_DSP); 130 preg(PM_PWSTST_MDM); 131 132 preg(CM_AUTOIDLE1_CORE); 133 preg(CM_AUTOIDLE2_CORE); 134 preg(CM_AUTOIDLE3_CORE); 135 preg(CM_AUTOIDLE4_CORE); 136 preg(CM_AUTOIDLE_WKUP); 137 preg(CM_AUTOIDLE_PLL); 138 preg(CM_AUTOIDLE_DSP); 139 preg(CM_AUTOIDLE_MDM); 140 141 preg(CM_ICLKEN1_CORE); 142 preg(CM_ICLKEN2_CORE); 143 preg(CM_ICLKEN3_CORE); 144 preg(CM_ICLKEN4_CORE); 145 preg(CM_ICLKEN_GFX); 146 preg(CM_ICLKEN_WKUP); 147 preg(CM_ICLKEN_DSP); 148 preg(CM_ICLKEN_MDM); 149 150 preg(CM_IDLEST1_CORE); 151 preg(CM_IDLEST2_CORE); 152 preg(CM_IDLEST3_CORE); 153 preg(CM_IDLEST4_CORE); 154 preg(CM_IDLEST_GFX); 155 preg(CM_IDLEST_WKUP); 156 preg(CM_IDLEST_CKGEN); 157 preg(CM_IDLEST_DSP); 158 preg(CM_IDLEST_MDM); 159 160 preg(RM_RSTST_MPU); 161 preg(RM_RSTST_GFX); 162 preg(RM_RSTST_WKUP); 163 preg(RM_RSTST_DSP); 164 preg(RM_RSTST_MDM); 165 166 preg(PM_WKDEP_MPU); 167 preg(PM_WKDEP_CORE); 168 preg(PM_WKDEP_GFX); 169 preg(PM_WKDEP_DSP); 170 preg(PM_WKDEP_MDM); 171 172 preg(CM_FCLKEN_WKUP); 173 preg(CM_ICLKEN_WKUP); 174 preg(CM_IDLEST_WKUP); 175 preg(CM_AUTOIDLE_WKUP); 176 preg(CM_CLKSEL_WKUP); 177 178 preg(PM_WKEN_WKUP); 179 preg(PM_WKST_WKUP); 180} 181 182static inline void omap2_pm_save_registers(void) 183{ 184 /* Save interrupt registers */ 185 OMAP24XX_SAVE(INTC_MIR0); 186 OMAP24XX_SAVE(INTC_MIR1); 187 OMAP24XX_SAVE(INTC_MIR2); 188 189 /* Save power control registers */ 190 OMAP24XX_SAVE(CM_CLKSTCTRL_MPU); 191 OMAP24XX_SAVE(CM_CLKSTCTRL_CORE); 192 OMAP24XX_SAVE(CM_CLKSTCTRL_GFX); 193 OMAP24XX_SAVE(CM_CLKSTCTRL_DSP); 194 OMAP24XX_SAVE(CM_CLKSTCTRL_MDM); 195 196 /* Save power state registers */ 197 OMAP24XX_SAVE(PM_PWSTCTRL_MPU); 198 OMAP24XX_SAVE(PM_PWSTCTRL_CORE); 199 OMAP24XX_SAVE(PM_PWSTCTRL_GFX); 200 OMAP24XX_SAVE(PM_PWSTCTRL_DSP); 201 OMAP24XX_SAVE(PM_PWSTCTRL_MDM); 202 203 /* Save autoidle registers */ 204 OMAP24XX_SAVE(CM_AUTOIDLE1_CORE); 205 OMAP24XX_SAVE(CM_AUTOIDLE2_CORE); 206 OMAP24XX_SAVE(CM_AUTOIDLE3_CORE); 207 OMAP24XX_SAVE(CM_AUTOIDLE4_CORE); 208 OMAP24XX_SAVE(CM_AUTOIDLE_WKUP); 209 OMAP24XX_SAVE(CM_AUTOIDLE_PLL); 210 OMAP24XX_SAVE(CM_AUTOIDLE_DSP); 211 OMAP24XX_SAVE(CM_AUTOIDLE_MDM); 212 213 /* Save idle state registers */ 214 OMAP24XX_SAVE(CM_IDLEST1_CORE); 215 OMAP24XX_SAVE(CM_IDLEST2_CORE); 216 OMAP24XX_SAVE(CM_IDLEST3_CORE); 217 OMAP24XX_SAVE(CM_IDLEST4_CORE); 218 OMAP24XX_SAVE(CM_IDLEST_GFX); 219 OMAP24XX_SAVE(CM_IDLEST_WKUP); 220 OMAP24XX_SAVE(CM_IDLEST_CKGEN); 221 OMAP24XX_SAVE(CM_IDLEST_DSP); 222 OMAP24XX_SAVE(CM_IDLEST_MDM); 223 224 /* Save clock registers */ 225 OMAP24XX_SAVE(CM_FCLKEN1_CORE); 226 OMAP24XX_SAVE(CM_FCLKEN2_CORE); 227 OMAP24XX_SAVE(CM_ICLKEN1_CORE); 228 OMAP24XX_SAVE(CM_ICLKEN2_CORE); 229 OMAP24XX_SAVE(CM_ICLKEN3_CORE); 230 OMAP24XX_SAVE(CM_ICLKEN4_CORE); 231} 232 233static inline void omap2_pm_restore_registers(void) 234{ 235 /* Restore clock state registers */ 236 OMAP24XX_RESTORE(CM_CLKSTCTRL_MPU); 237 OMAP24XX_RESTORE(CM_CLKSTCTRL_CORE); 238 OMAP24XX_RESTORE(CM_CLKSTCTRL_GFX); 239 OMAP24XX_RESTORE(CM_CLKSTCTRL_DSP); 240 OMAP24XX_RESTORE(CM_CLKSTCTRL_MDM); 241 242 /* Restore power state registers */ 243 OMAP24XX_RESTORE(PM_PWSTCTRL_MPU); 244 OMAP24XX_RESTORE(PM_PWSTCTRL_CORE); 245 OMAP24XX_RESTORE(PM_PWSTCTRL_GFX); 246 OMAP24XX_RESTORE(PM_PWSTCTRL_DSP); 247 OMAP24XX_RESTORE(PM_PWSTCTRL_MDM); 248 249 /* Restore idle state registers */ 250 OMAP24XX_RESTORE(CM_IDLEST1_CORE); 251 OMAP24XX_RESTORE(CM_IDLEST2_CORE); 252 OMAP24XX_RESTORE(CM_IDLEST3_CORE); 253 OMAP24XX_RESTORE(CM_IDLEST4_CORE); 254 OMAP24XX_RESTORE(CM_IDLEST_GFX); 255 OMAP24XX_RESTORE(CM_IDLEST_WKUP); 256 OMAP24XX_RESTORE(CM_IDLEST_CKGEN); 257 OMAP24XX_RESTORE(CM_IDLEST_DSP); 258 OMAP24XX_RESTORE(CM_IDLEST_MDM); 259 260 /* Restore autoidle registers */ 261 OMAP24XX_RESTORE(CM_AUTOIDLE1_CORE); 262 OMAP24XX_RESTORE(CM_AUTOIDLE2_CORE); 263 OMAP24XX_RESTORE(CM_AUTOIDLE3_CORE); 264 OMAP24XX_RESTORE(CM_AUTOIDLE4_CORE); 265 OMAP24XX_RESTORE(CM_AUTOIDLE_WKUP); 266 OMAP24XX_RESTORE(CM_AUTOIDLE_PLL); 267 OMAP24XX_RESTORE(CM_AUTOIDLE_DSP); 268 OMAP24XX_RESTORE(CM_AUTOIDLE_MDM); 269 270 /* Restore clock registers */ 271 OMAP24XX_RESTORE(CM_FCLKEN1_CORE); 272 OMAP24XX_RESTORE(CM_FCLKEN2_CORE); 273 OMAP24XX_RESTORE(CM_ICLKEN1_CORE); 274 OMAP24XX_RESTORE(CM_ICLKEN2_CORE); 275 OMAP24XX_RESTORE(CM_ICLKEN3_CORE); 276 OMAP24XX_RESTORE(CM_ICLKEN4_CORE); 277 278 /* REVISIT: Clear interrupts here */ 279 280 /* Restore interrupt registers */ 281 OMAP24XX_RESTORE(INTC_MIR0); 282 OMAP24XX_RESTORE(INTC_MIR1); 283 OMAP24XX_RESTORE(INTC_MIR2); 284} 285 286static int omap2_pm_suspend(void) 287{ 288 int processor_type = 0; 289 290 /* REVISIT: 0x21 or 0x26? */ 291 if (cpu_is_omap2420()) 292 processor_type = 0x21; 293 294 if (!processor_type) 295 return -ENOTSUPP; 296 297 local_irq_disable(); 298 local_fiq_disable(); 299 300 omap2_pm_save_registers(); 301 302 /* Disable interrupts except for the wake events */ 303 INTC_MIR_SET0 = 0xffffffff & ~INT0_WAKE_MASK; 304 INTC_MIR_SET1 = 0xffffffff & ~INT1_WAKE_MASK; 305 INTC_MIR_SET2 = 0xffffffff & ~INT2_WAKE_MASK; 306 307 pmdomain_set_autoidle(); 308 309 /* Clear old wake-up events */ 310 PM_WKST1_CORE = 0; 311 PM_WKST2_CORE = 0; 312 PM_WKST_WKUP = 0; 313 314 /* Enable wake-up events */ 315 PM_WKEN1_CORE = (1 << 22) | (1 << 21); /* UART1 & 2 */ 316 PM_WKEN2_CORE = (1 << 2); /* UART3 */ 317 PM_WKEN_WKUP = (1 << 2) | (1 << 0); /* GPIO & GPT1 */ 318 319 /* Disable clocks except for CM_ICLKEN2_CORE. It gets disabled 320 * in the SRAM suspend code */ 321 CM_FCLKEN1_CORE = 0; 322 CM_FCLKEN2_CORE = 0; 323 CM_ICLKEN1_CORE = 0; 324 CM_ICLKEN3_CORE = 0; 325 CM_ICLKEN4_CORE = 0; 326 327 omap2_pm_debug("Status before suspend"); 328 329 /* Must wait for serial buffers to clear */ 330 mdelay(200); 331 332 /* Jump to SRAM suspend code 333 * REVISIT: When is this SDRC_DLLB_CTRL? 334 */ 335 omap2_sram_suspend(SDRC_DLLA_CTRL, processor_type); 336 337 /* Back from sleep */ 338 omap2_pm_restore_registers(); 339 340 local_fiq_enable(); 341 local_irq_enable(); 342 343 return 0; 344} 345 346static int omap2_pm_enter(suspend_state_t state) 347{ 348 int ret = 0; 349 350 switch (state) 351 { 352 case PM_SUSPEND_STANDBY: 353 case PM_SUSPEND_MEM: 354 ret = omap2_pm_suspend(); 355 break; 356 case PM_SUSPEND_DISK: 357 ret = -ENOTSUPP; 358 break; 359 default: 360 ret = -EINVAL; 361 } 362 363 return ret; 364} 365 366static int omap2_pm_finish(suspend_state_t state) 367{ 368 pm_idle = saved_idle; 369 return 0; 370} 371 372static struct pm_ops omap_pm_ops = { 373 .prepare = omap2_pm_prepare, 374 .enter = omap2_pm_enter, 375 .finish = omap2_pm_finish, 376 .valid = pm_valid_only_mem, 377}; 378 379int __init omap2_pm_init(void) 380{ 381 printk("Power Management for TI OMAP.\n"); 382 383 vclk = clk_get(NULL, "virt_prcm_set"); 384 if (IS_ERR(vclk)) { 385 printk(KERN_ERR "Could not get PM vclk\n"); 386 return -ENODEV; 387 } 388 389 /* 390 * We copy the assembler sleep/wakeup routines to SRAM. 391 * These routines need to be in SRAM as that's the only 392 * memory the MPU can see when it wakes up. 393 */ 394 omap2_sram_idle = omap_sram_push(omap24xx_idle_loop_suspend, 395 omap24xx_idle_loop_suspend_sz); 396 397 omap2_sram_suspend = omap_sram_push(omap24xx_cpu_suspend, 398 omap24xx_cpu_suspend_sz); 399 400 pm_set_ops(&omap_pm_ops); 401 pm_idle = omap2_pm_idle; 402 403 pmdomain_init(); 404 405 return 0; 406} 407 408__initcall(omap2_pm_init); 409