Commit 670c104ae8e7bcc28be0289a16dac2ddfb88b285

Authored by Tony Lindgren
Committed by Russell King
1 parent 6e60e79a1d

[ARM] 3430/1: ARM: OMAP: 5/8 Update PM

Patch from Tony Lindgren

Update OMAP PM code from linux-omap tree:

- Move PM code from plat-omap to mach-omap1 and mach-omap2
  by Tony Lindgren
- Add minimal PM support for omap24xx by Tony Lindgren and
  Richard Woodruff
- Misc updates to omap1 PM code by Tuukka Tikkanen et al
- Updates to the SRAM code needed for PM and FB by Imre Deak

Signed-off-by: Tony Lindgren <tony@atomide.com>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>

Showing 10 changed files with 1787 additions and 484 deletions Side-by-side Diff

arch/arm/mach-omap1/pm.c
  1 +/*
  2 + * linux/arch/arm/mach-omap1/pm.c
  3 + *
  4 + * OMAP Power Management Routines
  5 + *
  6 + * Original code for the SA11x0:
  7 + * Copyright (c) 2001 Cliff Brake <cbrake@accelent.com>
  8 + *
  9 + * Modified for the PXA250 by Nicolas Pitre:
  10 + * Copyright (c) 2002 Monta Vista Software, Inc.
  11 + *
  12 + * Modified for the OMAP1510 by David Singleton:
  13 + * Copyright (c) 2002 Monta Vista Software, Inc.
  14 + *
  15 + * Cleanup 2004 for OMAP1510/1610 by Dirk Behme <dirk.behme@de.bosch.com>
  16 + *
  17 + * This program is free software; you can redistribute it and/or modify it
  18 + * under the terms of the GNU General Public License as published by the
  19 + * Free Software Foundation; either version 2 of the License, or (at your
  20 + * option) any later version.
  21 + *
  22 + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
  23 + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
  24 + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
  25 + * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
  26 + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  27 + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
  28 + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
  29 + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  30 + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  31 + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  32 + *
  33 + * You should have received a copy of the GNU General Public License along
  34 + * with this program; if not, write to the Free Software Foundation, Inc.,
  35 + * 675 Mass Ave, Cambridge, MA 02139, USA.
  36 + */
  37 +
  38 +#include <linux/pm.h>
  39 +#include <linux/sched.h>
  40 +#include <linux/proc_fs.h>
  41 +#include <linux/pm.h>
  42 +#include <linux/interrupt.h>
  43 +#include <linux/sysfs.h>
  44 +#include <linux/module.h>
  45 +
  46 +#include <asm/io.h>
  47 +#include <asm/irq.h>
  48 +#include <asm/atomic.h>
  49 +#include <asm/mach/time.h>
  50 +#include <asm/mach/irq.h>
  51 +#include <asm/mach-types.h>
  52 +
  53 +#include <asm/arch/irqs.h>
  54 +#include <asm/arch/clock.h>
  55 +#include <asm/arch/sram.h>
  56 +#include <asm/arch/tc.h>
  57 +#include <asm/arch/pm.h>
  58 +#include <asm/arch/mux.h>
  59 +#include <asm/arch/tps65010.h>
  60 +#include <asm/arch/dma.h>
  61 +#include <asm/arch/dsp_common.h>
  62 +#include <asm/arch/dmtimer.h>
  63 +
  64 +static unsigned int arm_sleep_save[ARM_SLEEP_SAVE_SIZE];
  65 +static unsigned short dsp_sleep_save[DSP_SLEEP_SAVE_SIZE];
  66 +static unsigned short ulpd_sleep_save[ULPD_SLEEP_SAVE_SIZE];
  67 +static unsigned int mpui730_sleep_save[MPUI730_SLEEP_SAVE_SIZE];
  68 +static unsigned int mpui1510_sleep_save[MPUI1510_SLEEP_SAVE_SIZE];
  69 +static unsigned int mpui1610_sleep_save[MPUI1610_SLEEP_SAVE_SIZE];
  70 +
  71 +static unsigned short enable_dyn_sleep = 1;
  72 +
  73 +static ssize_t omap_pm_sleep_while_idle_show(struct subsystem * subsys, char *buf)
  74 +{
  75 + return sprintf(buf, "%hu\n", enable_dyn_sleep);
  76 +}
  77 +
  78 +static ssize_t omap_pm_sleep_while_idle_store(struct subsystem * subsys,
  79 + const char * buf,
  80 + size_t n)
  81 +{
  82 + unsigned short value;
  83 + if (sscanf(buf, "%hu", &value) != 1 ||
  84 + (value != 0 && value != 1)) {
  85 + printk(KERN_ERR "idle_sleep_store: Invalid value\n");
  86 + return -EINVAL;
  87 + }
  88 + enable_dyn_sleep = value;
  89 + return n;
  90 +}
  91 +
  92 +static struct subsys_attribute sleep_while_idle_attr = {
  93 + .attr = {
  94 + .name = __stringify(sleep_while_idle),
  95 + .mode = 0644,
  96 + },
  97 + .show = omap_pm_sleep_while_idle_show,
  98 + .store = omap_pm_sleep_while_idle_store,
  99 +};
  100 +
  101 +extern struct subsystem power_subsys;
  102 +static void (*omap_sram_idle)(void) = NULL;
  103 +static void (*omap_sram_suspend)(unsigned long r0, unsigned long r1) = NULL;
  104 +
  105 +/*
  106 + * Let's power down on idle, but only if we are really
  107 + * idle, because once we start down the path of
  108 + * going idle we continue to do idle even if we get
  109 + * a clock tick interrupt . .
  110 + */
  111 +void omap_pm_idle(void)
  112 +{
  113 + extern __u32 arm_idlect1_mask;
  114 + __u32 use_idlect1 = arm_idlect1_mask;
  115 +#ifndef CONFIG_OMAP_MPU_TIMER
  116 + int do_sleep;
  117 +#endif
  118 +
  119 + local_irq_disable();
  120 + local_fiq_disable();
  121 + if (need_resched()) {
  122 + local_fiq_enable();
  123 + local_irq_enable();
  124 + return;
  125 + }
  126 +
  127 + /*
  128 + * Since an interrupt may set up a timer, we don't want to
  129 + * reprogram the hardware timer with interrupts enabled.
  130 + * Re-enable interrupts only after returning from idle.
  131 + */
  132 + timer_dyn_reprogram();
  133 +
  134 +#ifdef CONFIG_OMAP_MPU_TIMER
  135 +#warning Enable 32kHz OS timer in order to allow sleep states in idle
  136 + use_idlect1 = use_idlect1 & ~(1 << 9);
  137 +#else
  138 +
  139 + do_sleep = 0;
  140 + while (enable_dyn_sleep) {
  141 +
  142 +#ifdef CONFIG_CBUS_TAHVO_USB
  143 + extern int vbus_active;
  144 + /* Clock requirements? */
  145 + if (vbus_active)
  146 + break;
  147 +#endif
  148 + do_sleep = 1;
  149 + break;
  150 + }
  151 +
  152 +#ifdef CONFIG_OMAP_DM_TIMER
  153 + use_idlect1 = omap_dm_timer_modify_idlect_mask(use_idlect1);
  154 +#endif
  155 +
  156 + if (omap_dma_running()) {
  157 + use_idlect1 &= ~(1 << 6);
  158 + if (omap_lcd_dma_ext_running())
  159 + use_idlect1 &= ~(1 << 12);
  160 + }
  161 +
  162 + /* We should be able to remove the do_sleep variable and multiple
  163 + * tests above as soon as drivers, timer and DMA code have been fixed.
  164 + * Even the sleep block count should become obsolete. */
  165 + if ((use_idlect1 != ~0) || !do_sleep) {
  166 +
  167 + __u32 saved_idlect1 = omap_readl(ARM_IDLECT1);
  168 + if (cpu_is_omap15xx())
  169 + use_idlect1 &= OMAP1510_BIG_SLEEP_REQUEST;
  170 + else
  171 + use_idlect1 &= OMAP1610_IDLECT1_SLEEP_VAL;
  172 + omap_writel(use_idlect1, ARM_IDLECT1);
  173 + __asm__ volatile ("mcr p15, 0, r0, c7, c0, 4");
  174 + omap_writel(saved_idlect1, ARM_IDLECT1);
  175 +
  176 + local_fiq_enable();
  177 + local_irq_enable();
  178 + return;
  179 + }
  180 + omap_sram_suspend(omap_readl(ARM_IDLECT1),
  181 + omap_readl(ARM_IDLECT2));
  182 +#endif
  183 +
  184 + local_fiq_enable();
  185 + local_irq_enable();
  186 +}
  187 +
  188 +/*
  189 + * Configuration of the wakeup event is board specific. For the
  190 + * moment we put it into this helper function. Later it may move
  191 + * to board specific files.
  192 + */
  193 +static void omap_pm_wakeup_setup(void)
  194 +{
  195 + u32 level1_wake = 0;
  196 + u32 level2_wake = OMAP_IRQ_BIT(INT_UART2);
  197 +
  198 + /*
  199 + * Turn off all interrupts except GPIO bank 1, L1-2nd level cascade,
  200 + * and the L2 wakeup interrupts: keypad and UART2. Note that the
  201 + * drivers must still separately call omap_set_gpio_wakeup() to
  202 + * wake up to a GPIO interrupt.
  203 + */
  204 + if (cpu_is_omap730())
  205 + level1_wake = OMAP_IRQ_BIT(INT_730_GPIO_BANK1) |
  206 + OMAP_IRQ_BIT(INT_730_IH2_IRQ);
  207 + else if (cpu_is_omap15xx())
  208 + level1_wake = OMAP_IRQ_BIT(INT_GPIO_BANK1) |
  209 + OMAP_IRQ_BIT(INT_1510_IH2_IRQ);
  210 + else if (cpu_is_omap16xx())
  211 + level1_wake = OMAP_IRQ_BIT(INT_GPIO_BANK1) |
  212 + OMAP_IRQ_BIT(INT_1610_IH2_IRQ);
  213 +
  214 + omap_writel(~level1_wake, OMAP_IH1_MIR);
  215 +
  216 + if (cpu_is_omap730()) {
  217 + omap_writel(~level2_wake, OMAP_IH2_0_MIR);
  218 + omap_writel(~(OMAP_IRQ_BIT(INT_730_WAKE_UP_REQ) |
  219 + OMAP_IRQ_BIT(INT_730_MPUIO_KEYPAD)),
  220 + OMAP_IH2_1_MIR);
  221 + } else if (cpu_is_omap15xx()) {
  222 + level2_wake |= OMAP_IRQ_BIT(INT_KEYBOARD);
  223 + omap_writel(~level2_wake, OMAP_IH2_MIR);
  224 + } else if (cpu_is_omap16xx()) {
  225 + level2_wake |= OMAP_IRQ_BIT(INT_KEYBOARD);
  226 + omap_writel(~level2_wake, OMAP_IH2_0_MIR);
  227 +
  228 + /* INT_1610_WAKE_UP_REQ is needed for GPIO wakeup... */
  229 + omap_writel(~OMAP_IRQ_BIT(INT_1610_WAKE_UP_REQ),
  230 + OMAP_IH2_1_MIR);
  231 + omap_writel(~0x0, OMAP_IH2_2_MIR);
  232 + omap_writel(~0x0, OMAP_IH2_3_MIR);
  233 + }
  234 +
  235 + /* New IRQ agreement, recalculate in cascade order */
  236 + omap_writel(1, OMAP_IH2_CONTROL);
  237 + omap_writel(1, OMAP_IH1_CONTROL);
  238 +}
  239 +
  240 +#define EN_DSPCK 13 /* ARM_CKCTL */
  241 +#define EN_APICK 6 /* ARM_IDLECT2 */
  242 +#define DSP_EN 1 /* ARM_RSTCT1 */
  243 +
  244 +void omap_pm_suspend(void)
  245 +{
  246 + unsigned long arg0 = 0, arg1 = 0;
  247 +
  248 + printk("PM: OMAP%x is trying to enter deep sleep...\n", system_rev);
  249 +
  250 + omap_serial_wake_trigger(1);
  251 +
  252 + if (machine_is_omap_osk()) {
  253 + /* Stop LED1 (D9) blink */
  254 + tps65010_set_led(LED1, OFF);
  255 + }
  256 +
  257 + omap_writew(0xffff, ULPD_SOFT_DISABLE_REQ_REG);
  258 +
  259 + /*
  260 + * Step 1: turn off interrupts (FIXME: NOTE: already disabled)
  261 + */
  262 +
  263 + local_irq_disable();
  264 + local_fiq_disable();
  265 +
  266 + /*
  267 + * Step 2: save registers
  268 + *
  269 + * The omap is a strange/beautiful device. The caches, memory
  270 + * and register state are preserved across power saves.
  271 + * We have to save and restore very little register state to
  272 + * idle the omap.
  273 + *
  274 + * Save interrupt, MPUI, ARM and UPLD control registers.
  275 + */
  276 +
  277 + if (cpu_is_omap730()) {
  278 + MPUI730_SAVE(OMAP_IH1_MIR);
  279 + MPUI730_SAVE(OMAP_IH2_0_MIR);
  280 + MPUI730_SAVE(OMAP_IH2_1_MIR);
  281 + MPUI730_SAVE(MPUI_CTRL);
  282 + MPUI730_SAVE(MPUI_DSP_BOOT_CONFIG);
  283 + MPUI730_SAVE(MPUI_DSP_API_CONFIG);
  284 + MPUI730_SAVE(EMIFS_CONFIG);
  285 + MPUI730_SAVE(EMIFF_SDRAM_CONFIG);
  286 +
  287 + } else if (cpu_is_omap15xx()) {
  288 + MPUI1510_SAVE(OMAP_IH1_MIR);
  289 + MPUI1510_SAVE(OMAP_IH2_MIR);
  290 + MPUI1510_SAVE(MPUI_CTRL);
  291 + MPUI1510_SAVE(MPUI_DSP_BOOT_CONFIG);
  292 + MPUI1510_SAVE(MPUI_DSP_API_CONFIG);
  293 + MPUI1510_SAVE(EMIFS_CONFIG);
  294 + MPUI1510_SAVE(EMIFF_SDRAM_CONFIG);
  295 + } else if (cpu_is_omap16xx()) {
  296 + MPUI1610_SAVE(OMAP_IH1_MIR);
  297 + MPUI1610_SAVE(OMAP_IH2_0_MIR);
  298 + MPUI1610_SAVE(OMAP_IH2_1_MIR);
  299 + MPUI1610_SAVE(OMAP_IH2_2_MIR);
  300 + MPUI1610_SAVE(OMAP_IH2_3_MIR);
  301 + MPUI1610_SAVE(MPUI_CTRL);
  302 + MPUI1610_SAVE(MPUI_DSP_BOOT_CONFIG);
  303 + MPUI1610_SAVE(MPUI_DSP_API_CONFIG);
  304 + MPUI1610_SAVE(EMIFS_CONFIG);
  305 + MPUI1610_SAVE(EMIFF_SDRAM_CONFIG);
  306 + }
  307 +
  308 + ARM_SAVE(ARM_CKCTL);
  309 + ARM_SAVE(ARM_IDLECT1);
  310 + ARM_SAVE(ARM_IDLECT2);
  311 + if (!(cpu_is_omap15xx()))
  312 + ARM_SAVE(ARM_IDLECT3);
  313 + ARM_SAVE(ARM_EWUPCT);
  314 + ARM_SAVE(ARM_RSTCT1);
  315 + ARM_SAVE(ARM_RSTCT2);
  316 + ARM_SAVE(ARM_SYSST);
  317 + ULPD_SAVE(ULPD_CLOCK_CTRL);
  318 + ULPD_SAVE(ULPD_STATUS_REQ);
  319 +
  320 + /* (Step 3 removed - we now allow deep sleep by default) */
  321 +
  322 + /*
  323 + * Step 4: OMAP DSP Shutdown
  324 + */
  325 +
  326 + /* stop DSP */
  327 + omap_writew(omap_readw(ARM_RSTCT1) & ~(1 << DSP_EN), ARM_RSTCT1);
  328 +
  329 + /* shut down dsp_ck */
  330 + omap_writew(omap_readw(ARM_CKCTL) & ~(1 << EN_DSPCK), ARM_CKCTL);
  331 +
  332 + /* temporarily enabling api_ck to access DSP registers */
  333 + omap_writew(omap_readw(ARM_IDLECT2) | 1 << EN_APICK, ARM_IDLECT2);
  334 +
  335 + /* save DSP registers */
  336 + DSP_SAVE(DSP_IDLECT2);
  337 +
  338 + /* Stop all DSP domain clocks */
  339 + __raw_writew(0, DSP_IDLECT2);
  340 +
  341 + /*
  342 + * Step 5: Wakeup Event Setup
  343 + */
  344 +
  345 + omap_pm_wakeup_setup();
  346 +
  347 + /*
  348 + * Step 6: ARM and Traffic controller shutdown
  349 + */
  350 +
  351 + /* disable ARM watchdog */
  352 + omap_writel(0x00F5, OMAP_WDT_TIMER_MODE);
  353 + omap_writel(0x00A0, OMAP_WDT_TIMER_MODE);
  354 +
  355 + /*
  356 + * Step 6b: ARM and Traffic controller shutdown
  357 + *
  358 + * Step 6 continues here. Prepare jump to power management
  359 + * assembly code in internal SRAM.
  360 + *
  361 + * Since the omap_cpu_suspend routine has been copied to
  362 + * SRAM, we'll do an indirect procedure call to it and pass the
  363 + * contents of arm_idlect1 and arm_idlect2 so it can restore
  364 + * them when it wakes up and it will return.
  365 + */
  366 +
  367 + arg0 = arm_sleep_save[ARM_SLEEP_SAVE_ARM_IDLECT1];
  368 + arg1 = arm_sleep_save[ARM_SLEEP_SAVE_ARM_IDLECT2];
  369 +
  370 + /*
  371 + * Step 6c: ARM and Traffic controller shutdown
  372 + *
  373 + * Jump to assembly code. The processor will stay there
  374 + * until wake up.
  375 + */
  376 + omap_sram_suspend(arg0, arg1);
  377 +
  378 + /*
  379 + * If we are here, processor is woken up!
  380 + */
  381 +
  382 + /*
  383 + * Restore DSP clocks
  384 + */
  385 +
  386 + /* again temporarily enabling api_ck to access DSP registers */
  387 + omap_writew(omap_readw(ARM_IDLECT2) | 1 << EN_APICK, ARM_IDLECT2);
  388 +
  389 + /* Restore DSP domain clocks */
  390 + DSP_RESTORE(DSP_IDLECT2);
  391 +
  392 + /*
  393 + * Restore ARM state, except ARM_IDLECT1/2 which omap_cpu_suspend did
  394 + */
  395 +
  396 + if (!(cpu_is_omap15xx()))
  397 + ARM_RESTORE(ARM_IDLECT3);
  398 + ARM_RESTORE(ARM_CKCTL);
  399 + ARM_RESTORE(ARM_EWUPCT);
  400 + ARM_RESTORE(ARM_RSTCT1);
  401 + ARM_RESTORE(ARM_RSTCT2);
  402 + ARM_RESTORE(ARM_SYSST);
  403 + ULPD_RESTORE(ULPD_CLOCK_CTRL);
  404 + ULPD_RESTORE(ULPD_STATUS_REQ);
  405 +
  406 + if (cpu_is_omap730()) {
  407 + MPUI730_RESTORE(EMIFS_CONFIG);
  408 + MPUI730_RESTORE(EMIFF_SDRAM_CONFIG);
  409 + MPUI730_RESTORE(OMAP_IH1_MIR);
  410 + MPUI730_RESTORE(OMAP_IH2_0_MIR);
  411 + MPUI730_RESTORE(OMAP_IH2_1_MIR);
  412 + } else if (cpu_is_omap15xx()) {
  413 + MPUI1510_RESTORE(MPUI_CTRL);
  414 + MPUI1510_RESTORE(MPUI_DSP_BOOT_CONFIG);
  415 + MPUI1510_RESTORE(MPUI_DSP_API_CONFIG);
  416 + MPUI1510_RESTORE(EMIFS_CONFIG);
  417 + MPUI1510_RESTORE(EMIFF_SDRAM_CONFIG);
  418 + MPUI1510_RESTORE(OMAP_IH1_MIR);
  419 + MPUI1510_RESTORE(OMAP_IH2_MIR);
  420 + } else if (cpu_is_omap16xx()) {
  421 + MPUI1610_RESTORE(MPUI_CTRL);
  422 + MPUI1610_RESTORE(MPUI_DSP_BOOT_CONFIG);
  423 + MPUI1610_RESTORE(MPUI_DSP_API_CONFIG);
  424 + MPUI1610_RESTORE(EMIFS_CONFIG);
  425 + MPUI1610_RESTORE(EMIFF_SDRAM_CONFIG);
  426 +
  427 + MPUI1610_RESTORE(OMAP_IH1_MIR);
  428 + MPUI1610_RESTORE(OMAP_IH2_0_MIR);
  429 + MPUI1610_RESTORE(OMAP_IH2_1_MIR);
  430 + MPUI1610_RESTORE(OMAP_IH2_2_MIR);
  431 + MPUI1610_RESTORE(OMAP_IH2_3_MIR);
  432 + }
  433 +
  434 + omap_writew(0, ULPD_SOFT_DISABLE_REQ_REG);
  435 +
  436 + /*
  437 + * Reenable interrupts
  438 + */
  439 +
  440 + local_irq_enable();
  441 + local_fiq_enable();
  442 +
  443 + omap_serial_wake_trigger(0);
  444 +
  445 + printk("PM: OMAP%x is re-starting from deep sleep...\n", system_rev);
  446 +
  447 + if (machine_is_omap_osk()) {
  448 + /* Let LED1 (D9) blink again */
  449 + tps65010_set_led(LED1, BLINK);
  450 + }
  451 +}
  452 +
  453 +#if defined(DEBUG) && defined(CONFIG_PROC_FS)
  454 +static int g_read_completed;
  455 +
  456 +/*
  457 + * Read system PM registers for debugging
  458 + */
  459 +static int omap_pm_read_proc(
  460 + char *page_buffer,
  461 + char **my_first_byte,
  462 + off_t virtual_start,
  463 + int length,
  464 + int *eof,
  465 + void *data)
  466 +{
  467 + int my_buffer_offset = 0;
  468 + char * const my_base = page_buffer;
  469 +
  470 + ARM_SAVE(ARM_CKCTL);
  471 + ARM_SAVE(ARM_IDLECT1);
  472 + ARM_SAVE(ARM_IDLECT2);
  473 + if (!(cpu_is_omap15xx()))
  474 + ARM_SAVE(ARM_IDLECT3);
  475 + ARM_SAVE(ARM_EWUPCT);
  476 + ARM_SAVE(ARM_RSTCT1);
  477 + ARM_SAVE(ARM_RSTCT2);
  478 + ARM_SAVE(ARM_SYSST);
  479 +
  480 + ULPD_SAVE(ULPD_IT_STATUS);
  481 + ULPD_SAVE(ULPD_CLOCK_CTRL);
  482 + ULPD_SAVE(ULPD_SOFT_REQ);
  483 + ULPD_SAVE(ULPD_STATUS_REQ);
  484 + ULPD_SAVE(ULPD_DPLL_CTRL);
  485 + ULPD_SAVE(ULPD_POWER_CTRL);
  486 +
  487 + if (cpu_is_omap730()) {
  488 + MPUI730_SAVE(MPUI_CTRL);
  489 + MPUI730_SAVE(MPUI_DSP_STATUS);
  490 + MPUI730_SAVE(MPUI_DSP_BOOT_CONFIG);
  491 + MPUI730_SAVE(MPUI_DSP_API_CONFIG);
  492 + MPUI730_SAVE(EMIFF_SDRAM_CONFIG);
  493 + MPUI730_SAVE(EMIFS_CONFIG);
  494 + } else if (cpu_is_omap15xx()) {
  495 + MPUI1510_SAVE(MPUI_CTRL);
  496 + MPUI1510_SAVE(MPUI_DSP_STATUS);
  497 + MPUI1510_SAVE(MPUI_DSP_BOOT_CONFIG);
  498 + MPUI1510_SAVE(MPUI_DSP_API_CONFIG);
  499 + MPUI1510_SAVE(EMIFF_SDRAM_CONFIG);
  500 + MPUI1510_SAVE(EMIFS_CONFIG);
  501 + } else if (cpu_is_omap16xx()) {
  502 + MPUI1610_SAVE(MPUI_CTRL);
  503 + MPUI1610_SAVE(MPUI_DSP_STATUS);
  504 + MPUI1610_SAVE(MPUI_DSP_BOOT_CONFIG);
  505 + MPUI1610_SAVE(MPUI_DSP_API_CONFIG);
  506 + MPUI1610_SAVE(EMIFF_SDRAM_CONFIG);
  507 + MPUI1610_SAVE(EMIFS_CONFIG);
  508 + }
  509 +
  510 + if (virtual_start == 0) {
  511 + g_read_completed = 0;
  512 +
  513 + my_buffer_offset += sprintf(my_base + my_buffer_offset,
  514 + "ARM_CKCTL_REG: 0x%-8x \n"
  515 + "ARM_IDLECT1_REG: 0x%-8x \n"
  516 + "ARM_IDLECT2_REG: 0x%-8x \n"
  517 + "ARM_IDLECT3_REG: 0x%-8x \n"
  518 + "ARM_EWUPCT_REG: 0x%-8x \n"
  519 + "ARM_RSTCT1_REG: 0x%-8x \n"
  520 + "ARM_RSTCT2_REG: 0x%-8x \n"
  521 + "ARM_SYSST_REG: 0x%-8x \n"
  522 + "ULPD_IT_STATUS_REG: 0x%-4x \n"
  523 + "ULPD_CLOCK_CTRL_REG: 0x%-4x \n"
  524 + "ULPD_SOFT_REQ_REG: 0x%-4x \n"
  525 + "ULPD_DPLL_CTRL_REG: 0x%-4x \n"
  526 + "ULPD_STATUS_REQ_REG: 0x%-4x \n"
  527 + "ULPD_POWER_CTRL_REG: 0x%-4x \n",
  528 + ARM_SHOW(ARM_CKCTL),
  529 + ARM_SHOW(ARM_IDLECT1),
  530 + ARM_SHOW(ARM_IDLECT2),
  531 + ARM_SHOW(ARM_IDLECT3),
  532 + ARM_SHOW(ARM_EWUPCT),
  533 + ARM_SHOW(ARM_RSTCT1),
  534 + ARM_SHOW(ARM_RSTCT2),
  535 + ARM_SHOW(ARM_SYSST),
  536 + ULPD_SHOW(ULPD_IT_STATUS),
  537 + ULPD_SHOW(ULPD_CLOCK_CTRL),
  538 + ULPD_SHOW(ULPD_SOFT_REQ),
  539 + ULPD_SHOW(ULPD_DPLL_CTRL),
  540 + ULPD_SHOW(ULPD_STATUS_REQ),
  541 + ULPD_SHOW(ULPD_POWER_CTRL));
  542 +
  543 + if (cpu_is_omap730()) {
  544 + my_buffer_offset += sprintf(my_base + my_buffer_offset,
  545 + "MPUI730_CTRL_REG 0x%-8x \n"
  546 + "MPUI730_DSP_STATUS_REG: 0x%-8x \n"
  547 + "MPUI730_DSP_BOOT_CONFIG_REG: 0x%-8x \n"
  548 + "MPUI730_DSP_API_CONFIG_REG: 0x%-8x \n"
  549 + "MPUI730_SDRAM_CONFIG_REG: 0x%-8x \n"
  550 + "MPUI730_EMIFS_CONFIG_REG: 0x%-8x \n",
  551 + MPUI730_SHOW(MPUI_CTRL),
  552 + MPUI730_SHOW(MPUI_DSP_STATUS),
  553 + MPUI730_SHOW(MPUI_DSP_BOOT_CONFIG),
  554 + MPUI730_SHOW(MPUI_DSP_API_CONFIG),
  555 + MPUI730_SHOW(EMIFF_SDRAM_CONFIG),
  556 + MPUI730_SHOW(EMIFS_CONFIG));
  557 + } else if (cpu_is_omap15xx()) {
  558 + my_buffer_offset += sprintf(my_base + my_buffer_offset,
  559 + "MPUI1510_CTRL_REG 0x%-8x \n"
  560 + "MPUI1510_DSP_STATUS_REG: 0x%-8x \n"
  561 + "MPUI1510_DSP_BOOT_CONFIG_REG: 0x%-8x \n"
  562 + "MPUI1510_DSP_API_CONFIG_REG: 0x%-8x \n"
  563 + "MPUI1510_SDRAM_CONFIG_REG: 0x%-8x \n"
  564 + "MPUI1510_EMIFS_CONFIG_REG: 0x%-8x \n",
  565 + MPUI1510_SHOW(MPUI_CTRL),
  566 + MPUI1510_SHOW(MPUI_DSP_STATUS),
  567 + MPUI1510_SHOW(MPUI_DSP_BOOT_CONFIG),
  568 + MPUI1510_SHOW(MPUI_DSP_API_CONFIG),
  569 + MPUI1510_SHOW(EMIFF_SDRAM_CONFIG),
  570 + MPUI1510_SHOW(EMIFS_CONFIG));
  571 + } else if (cpu_is_omap16xx()) {
  572 + my_buffer_offset += sprintf(my_base + my_buffer_offset,
  573 + "MPUI1610_CTRL_REG 0x%-8x \n"
  574 + "MPUI1610_DSP_STATUS_REG: 0x%-8x \n"
  575 + "MPUI1610_DSP_BOOT_CONFIG_REG: 0x%-8x \n"
  576 + "MPUI1610_DSP_API_CONFIG_REG: 0x%-8x \n"
  577 + "MPUI1610_SDRAM_CONFIG_REG: 0x%-8x \n"
  578 + "MPUI1610_EMIFS_CONFIG_REG: 0x%-8x \n",
  579 + MPUI1610_SHOW(MPUI_CTRL),
  580 + MPUI1610_SHOW(MPUI_DSP_STATUS),
  581 + MPUI1610_SHOW(MPUI_DSP_BOOT_CONFIG),
  582 + MPUI1610_SHOW(MPUI_DSP_API_CONFIG),
  583 + MPUI1610_SHOW(EMIFF_SDRAM_CONFIG),
  584 + MPUI1610_SHOW(EMIFS_CONFIG));
  585 + }
  586 +
  587 + g_read_completed++;
  588 + } else if (g_read_completed >= 1) {
  589 + *eof = 1;
  590 + return 0;
  591 + }
  592 + g_read_completed++;
  593 +
  594 + *my_first_byte = page_buffer;
  595 + return my_buffer_offset;
  596 +}
  597 +
  598 +static void omap_pm_init_proc(void)
  599 +{
  600 + struct proc_dir_entry *entry;
  601 +
  602 + entry = create_proc_read_entry("driver/omap_pm",
  603 + S_IWUSR | S_IRUGO, NULL,
  604 + omap_pm_read_proc, NULL);
  605 +}
  606 +
  607 +#endif /* DEBUG && CONFIG_PROC_FS */
  608 +
  609 +static void (*saved_idle)(void) = NULL;
  610 +
  611 +/*
  612 + * omap_pm_prepare - Do preliminary suspend work.
  613 + * @state: suspend state we're entering.
  614 + *
  615 + */
  616 +static int omap_pm_prepare(suspend_state_t state)
  617 +{
  618 + int error = 0;
  619 +
  620 + /* We cannot sleep in idle until we have resumed */
  621 + saved_idle = pm_idle;
  622 + pm_idle = NULL;
  623 +
  624 + switch (state)
  625 + {
  626 + case PM_SUSPEND_STANDBY:
  627 + case PM_SUSPEND_MEM:
  628 + break;
  629 +
  630 + case PM_SUSPEND_DISK:
  631 + return -ENOTSUPP;
  632 +
  633 + default:
  634 + return -EINVAL;
  635 + }
  636 +
  637 + return error;
  638 +}
  639 +
  640 +
  641 +/*
  642 + * omap_pm_enter - Actually enter a sleep state.
  643 + * @state: State we're entering.
  644 + *
  645 + */
  646 +
  647 +static int omap_pm_enter(suspend_state_t state)
  648 +{
  649 + switch (state)
  650 + {
  651 + case PM_SUSPEND_STANDBY:
  652 + case PM_SUSPEND_MEM:
  653 + omap_pm_suspend();
  654 + break;
  655 +
  656 + case PM_SUSPEND_DISK:
  657 + return -ENOTSUPP;
  658 +
  659 + default:
  660 + return -EINVAL;
  661 + }
  662 +
  663 + return 0;
  664 +}
  665 +
  666 +
  667 +/**
  668 + * omap_pm_finish - Finish up suspend sequence.
  669 + * @state: State we're coming out of.
  670 + *
  671 + * This is called after we wake back up (or if entering the sleep state
  672 + * failed).
  673 + */
  674 +
  675 +static int omap_pm_finish(suspend_state_t state)
  676 +{
  677 + pm_idle = saved_idle;
  678 + return 0;
  679 +}
  680 +
  681 +
  682 +static irqreturn_t omap_wakeup_interrupt(int irq, void * dev,
  683 + struct pt_regs * regs)
  684 +{
  685 + return IRQ_HANDLED;
  686 +}
  687 +
  688 +static struct irqaction omap_wakeup_irq = {
  689 + .name = "peripheral wakeup",
  690 + .flags = SA_INTERRUPT,
  691 + .handler = omap_wakeup_interrupt
  692 +};
  693 +
  694 +
  695 +
  696 +static struct pm_ops omap_pm_ops ={
  697 + .pm_disk_mode = 0,
  698 + .prepare = omap_pm_prepare,
  699 + .enter = omap_pm_enter,
  700 + .finish = omap_pm_finish,
  701 +};
  702 +
  703 +static int __init omap_pm_init(void)
  704 +{
  705 + printk("Power Management for TI OMAP.\n");
  706 +
  707 + /*
  708 + * We copy the assembler sleep/wakeup routines to SRAM.
  709 + * These routines need to be in SRAM as that's the only
  710 + * memory the MPU can see when it wakes up.
  711 + */
  712 + if (cpu_is_omap730()) {
  713 + omap_sram_idle = omap_sram_push(omap730_idle_loop_suspend,
  714 + omap730_idle_loop_suspend_sz);
  715 + omap_sram_suspend = omap_sram_push(omap730_cpu_suspend,
  716 + omap730_cpu_suspend_sz);
  717 + } else if (cpu_is_omap15xx()) {
  718 + omap_sram_idle = omap_sram_push(omap1510_idle_loop_suspend,
  719 + omap1510_idle_loop_suspend_sz);
  720 + omap_sram_suspend = omap_sram_push(omap1510_cpu_suspend,
  721 + omap1510_cpu_suspend_sz);
  722 + } else if (cpu_is_omap16xx()) {
  723 + omap_sram_idle = omap_sram_push(omap1610_idle_loop_suspend,
  724 + omap1610_idle_loop_suspend_sz);
  725 + omap_sram_suspend = omap_sram_push(omap1610_cpu_suspend,
  726 + omap1610_cpu_suspend_sz);
  727 + }
  728 +
  729 + if (omap_sram_idle == NULL || omap_sram_suspend == NULL) {
  730 + printk(KERN_ERR "PM not initialized: Missing SRAM support\n");
  731 + return -ENODEV;
  732 + }
  733 +
  734 + pm_idle = omap_pm_idle;
  735 +
  736 + if (cpu_is_omap730())
  737 + setup_irq(INT_730_WAKE_UP_REQ, &omap_wakeup_irq);
  738 + else if (cpu_is_omap16xx())
  739 + setup_irq(INT_1610_WAKE_UP_REQ, &omap_wakeup_irq);
  740 +
  741 + /* Program new power ramp-up time
  742 + * (0 for most boards since we don't lower voltage when in deep sleep)
  743 + */
  744 + omap_writew(ULPD_SETUP_ANALOG_CELL_3_VAL, ULPD_SETUP_ANALOG_CELL_3);
  745 +
  746 + /* Setup ULPD POWER_CTRL_REG - enter deep sleep whenever possible */
  747 + omap_writew(ULPD_POWER_CTRL_REG_VAL, ULPD_POWER_CTRL);
  748 +
  749 + /* Configure IDLECT3 */
  750 + if (cpu_is_omap730())
  751 + omap_writel(OMAP730_IDLECT3_VAL, OMAP730_IDLECT3);
  752 + else if (cpu_is_omap16xx())
  753 + omap_writel(OMAP1610_IDLECT3_VAL, OMAP1610_IDLECT3);
  754 +
  755 + pm_set_ops(&omap_pm_ops);
  756 +
  757 +#if defined(DEBUG) && defined(CONFIG_PROC_FS)
  758 + omap_pm_init_proc();
  759 +#endif
  760 +
  761 + subsys_create_file(&power_subsys, &sleep_while_idle_attr);
  762 +
  763 + if (cpu_is_omap16xx()) {
  764 + /* configure LOW_PWR pin */
  765 + omap_cfg_reg(T20_1610_LOW_PWR);
  766 + }
  767 +
  768 + return 0;
  769 +}
  770 +__initcall(omap_pm_init);
arch/arm/mach-omap1/sleep.S
  1 +/*
  2 + * linux/arch/arm/mach-omap1/sleep.S
  3 + *
  4 + * Low-level OMAP730/1510/1610 sleep/wakeUp support
  5 + *
  6 + * Initial SA1110 code:
  7 + * Copyright (c) 2001 Cliff Brake <cbrake@accelent.com>
  8 + *
  9 + * Adapted for PXA by Nicolas Pitre:
  10 + * Copyright (c) 2002 Monta Vista Software, Inc.
  11 + *
  12 + * Support for OMAP1510/1610 by Dirk Behme <dirk.behme@de.bosch.com>
  13 + *
  14 + * This program is free software; you can redistribute it and/or modify it
  15 + * under the terms of the GNU General Public License as published by the
  16 + * Free Software Foundation; either version 2 of the License, or (at your
  17 + * option) any later version.
  18 + *
  19 + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
  20 + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
  21 + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
  22 + * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
  23 + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  24 + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
  25 + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
  26 + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  27 + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  28 + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  29 + *
  30 + * You should have received a copy of the GNU General Public License along
  31 + * with this program; if not, write to the Free Software Foundation, Inc.,
  32 + * 675 Mass Ave, Cambridge, MA 02139, USA.
  33 + */
  34 +
  35 +#include <linux/config.h>
  36 +#include <linux/linkage.h>
  37 +#include <asm/assembler.h>
  38 +#include <asm/arch/io.h>
  39 +#include <asm/arch/pm.h>
  40 +
  41 + .text
  42 +
  43 +/*
  44 + * Forces OMAP into idle state
  45 + *
  46 + * omapXXXX_idle_loop_suspend()
  47 + *
  48 + * Note: This code get's copied to internal SRAM at boot. When the OMAP
  49 + * wakes up it continues execution at the point it went to sleep.
  50 + *
  51 + * Note: Because of slightly different configuration values we have
  52 + * processor specific functions here.
  53 + */
  54 +
  55 +#if defined(CONFIG_ARCH_OMAP730)
  56 +ENTRY(omap730_idle_loop_suspend)
  57 +
  58 + stmfd sp!, {r0 - r12, lr} @ save registers on stack
  59 +
  60 + @ load base address of ARM_IDLECT1 and ARM_IDLECT2
  61 + mov r4, #CLKGEN_REG_ASM_BASE & 0xff000000
  62 + orr r4, r4, #CLKGEN_REG_ASM_BASE & 0x00ff0000
  63 + orr r4, r4, #CLKGEN_REG_ASM_BASE & 0x0000ff00
  64 +
  65 + @ turn off clock domains
  66 + @ get ARM_IDLECT2 into r2
  67 + ldrh r2, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff]
  68 + mov r5, #OMAP730_IDLECT2_SLEEP_VAL & 0xff
  69 + orr r5, r5, #OMAP730_IDLECT2_SLEEP_VAL & 0xff00
  70 + strh r5, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff]
  71 +
  72 + @ request ARM idle
  73 + @ get ARM_IDLECT1 into r1
  74 + ldrh r1, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff]
  75 + orr r3, r1, #OMAP730_IDLE_LOOP_REQUEST & 0xffff
  76 + strh r3, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff]
  77 +
  78 + mov r5, #IDLE_WAIT_CYCLES & 0xff
  79 + orr r5, r5, #IDLE_WAIT_CYCLES & 0xff00
  80 +l_730: subs r5, r5, #1
  81 + bne l_730
  82 +/*
  83 + * Let's wait for the next clock tick to wake us up.
  84 + */
  85 + mov r0, #0
  86 + mcr p15, 0, r0, c7, c0, 4 @ wait for interrupt
  87 +/*
  88 + * omap730_idle_loop_suspend()'s resume point.
  89 + *
  90 + * It will just start executing here, so we'll restore stuff from the
  91 + * stack, reset the ARM_IDLECT1 and ARM_IDLECT2.
  92 + */
  93 +
  94 + @ restore ARM_IDLECT1 and ARM_IDLECT2 and return
  95 + @ r1 has ARM_IDLECT1 and r2 still has ARM_IDLECT2
  96 + strh r2, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff]
  97 + strh r1, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff]
  98 +
  99 + ldmfd sp!, {r0 - r12, pc} @ restore regs and return
  100 +
  101 +ENTRY(omap730_idle_loop_suspend_sz)
  102 + .word . - omap730_idle_loop_suspend
  103 +#endif /* CONFIG_ARCH_OMAP730 */
  104 +
  105 +#ifdef CONFIG_ARCH_OMAP15XX
  106 +ENTRY(omap1510_idle_loop_suspend)
  107 +
  108 + stmfd sp!, {r0 - r12, lr} @ save registers on stack
  109 +
  110 + @ load base address of ARM_IDLECT1 and ARM_IDLECT2
  111 + mov r4, #CLKGEN_REG_ASM_BASE & 0xff000000
  112 + orr r4, r4, #CLKGEN_REG_ASM_BASE & 0x00ff0000
  113 + orr r4, r4, #CLKGEN_REG_ASM_BASE & 0x0000ff00
  114 +
  115 + @ turn off clock domains
  116 + @ get ARM_IDLECT2 into r2
  117 + ldrh r2, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff]
  118 + mov r5, #OMAP1510_IDLE_CLOCK_DOMAINS & 0xff
  119 + orr r5, r5, #OMAP1510_IDLE_CLOCK_DOMAINS & 0xff00
  120 + strh r5, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff]
  121 +
  122 + @ request ARM idle
  123 + @ get ARM_IDLECT1 into r1
  124 + ldrh r1, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff]
  125 + orr r3, r1, #OMAP1510_IDLE_LOOP_REQUEST & 0xffff
  126 + strh r3, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff]
  127 +
  128 + mov r5, #IDLE_WAIT_CYCLES & 0xff
  129 + orr r5, r5, #IDLE_WAIT_CYCLES & 0xff00
  130 +l_1510: subs r5, r5, #1
  131 + bne l_1510
  132 +/*
  133 + * Let's wait for the next clock tick to wake us up.
  134 + */
  135 + mov r0, #0
  136 + mcr p15, 0, r0, c7, c0, 4 @ wait for interrupt
  137 +/*
  138 + * omap1510_idle_loop_suspend()'s resume point.
  139 + *
  140 + * It will just start executing here, so we'll restore stuff from the
  141 + * stack, reset the ARM_IDLECT1 and ARM_IDLECT2.
  142 + */
  143 +
  144 + @ restore ARM_IDLECT1 and ARM_IDLECT2 and return
  145 + @ r1 has ARM_IDLECT1 and r2 still has ARM_IDLECT2
  146 + strh r2, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff]
  147 + strh r1, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff]
  148 +
  149 + ldmfd sp!, {r0 - r12, pc} @ restore regs and return
  150 +
  151 +ENTRY(omap1510_idle_loop_suspend_sz)
  152 + .word . - omap1510_idle_loop_suspend
  153 +#endif /* CONFIG_ARCH_OMAP15XX */
  154 +
  155 +#if defined(CONFIG_ARCH_OMAP16XX)
  156 +ENTRY(omap1610_idle_loop_suspend)
  157 +
  158 + stmfd sp!, {r0 - r12, lr} @ save registers on stack
  159 +
  160 + @ load base address of ARM_IDLECT1 and ARM_IDLECT2
  161 + mov r4, #CLKGEN_REG_ASM_BASE & 0xff000000
  162 + orr r4, r4, #CLKGEN_REG_ASM_BASE & 0x00ff0000
  163 + orr r4, r4, #CLKGEN_REG_ASM_BASE & 0x0000ff00
  164 +
  165 + @ turn off clock domains
  166 + @ get ARM_IDLECT2 into r2
  167 + ldrh r2, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff]
  168 + mov r5, #OMAP1610_IDLECT2_SLEEP_VAL & 0xff
  169 + orr r5, r5, #OMAP1610_IDLECT2_SLEEP_VAL & 0xff00
  170 + strh r5, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff]
  171 +
  172 + @ request ARM idle
  173 + @ get ARM_IDLECT1 into r1
  174 + ldrh r1, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff]
  175 + orr r3, r1, #OMAP1610_IDLE_LOOP_REQUEST & 0xffff
  176 + strh r3, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff]
  177 +
  178 + mov r5, #IDLE_WAIT_CYCLES & 0xff
  179 + orr r5, r5, #IDLE_WAIT_CYCLES & 0xff00
  180 +l_1610: subs r5, r5, #1
  181 + bne l_1610
  182 +/*
  183 + * Let's wait for the next clock tick to wake us up.
  184 + */
  185 + mov r0, #0
  186 + mcr p15, 0, r0, c7, c0, 4 @ wait for interrupt
  187 +/*
  188 + * omap1610_idle_loop_suspend()'s resume point.
  189 + *
  190 + * It will just start executing here, so we'll restore stuff from the
  191 + * stack, reset the ARM_IDLECT1 and ARM_IDLECT2.
  192 + */
  193 +
  194 + @ restore ARM_IDLECT1 and ARM_IDLECT2 and return
  195 + @ r1 has ARM_IDLECT1 and r2 still has ARM_IDLECT2
  196 + strh r2, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff]
  197 + strh r1, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff]
  198 +
  199 + ldmfd sp!, {r0 - r12, pc} @ restore regs and return
  200 +
  201 +ENTRY(omap1610_idle_loop_suspend_sz)
  202 + .word . - omap1610_idle_loop_suspend
  203 +#endif /* CONFIG_ARCH_OMAP16XX */
  204 +
  205 +/*
  206 + * Forces OMAP into deep sleep state
  207 + *
  208 + * omapXXXX_cpu_suspend()
  209 + *
  210 + * The values of the registers ARM_IDLECT1 and ARM_IDLECT2 are passed
  211 + * as arg0 and arg1 from caller. arg0 is stored in register r0 and arg1
  212 + * in register r1.
  213 + *
  214 + * Note: This code get's copied to internal SRAM at boot. When the OMAP
  215 + * wakes up it continues execution at the point it went to sleep.
  216 + *
  217 + * Note: Because of errata work arounds we have processor specific functions
  218 + * here. They are mostly the same, but slightly different.
  219 + *
  220 + */
  221 +
  222 +#if defined(CONFIG_ARCH_OMAP730)
  223 +ENTRY(omap730_cpu_suspend)
  224 +
  225 + @ save registers on stack
  226 + stmfd sp!, {r0 - r12, lr}
  227 +
  228 + @ Drain write cache
  229 + mov r4, #0
  230 + mcr p15, 0, r0, c7, c10, 4
  231 + nop
  232 +
  233 + @ load base address of Traffic Controller
  234 + mov r6, #TCMIF_ASM_BASE & 0xff000000
  235 + orr r6, r6, #TCMIF_ASM_BASE & 0x00ff0000
  236 + orr r6, r6, #TCMIF_ASM_BASE & 0x0000ff00
  237 +
  238 + @ prepare to put SDRAM into self-refresh manually
  239 + ldr r7, [r6, #EMIFF_SDRAM_CONFIG_ASM_OFFSET & 0xff]
  240 + orr r9, r7, #SELF_REFRESH_MODE & 0xff000000
  241 + orr r9, r9, #SELF_REFRESH_MODE & 0x000000ff
  242 + str r9, [r6, #EMIFF_SDRAM_CONFIG_ASM_OFFSET & 0xff]
  243 +
  244 + @ prepare to put EMIFS to Sleep
  245 + ldr r8, [r6, #EMIFS_CONFIG_ASM_OFFSET & 0xff]
  246 + orr r9, r8, #IDLE_EMIFS_REQUEST & 0xff
  247 + str r9, [r6, #EMIFS_CONFIG_ASM_OFFSET & 0xff]
  248 +
  249 + @ load base address of ARM_IDLECT1 and ARM_IDLECT2
  250 + mov r4, #CLKGEN_REG_ASM_BASE & 0xff000000
  251 + orr r4, r4, #CLKGEN_REG_ASM_BASE & 0x00ff0000
  252 + orr r4, r4, #CLKGEN_REG_ASM_BASE & 0x0000ff00
  253 +
  254 + @ turn off clock domains
  255 + @ do not disable PERCK (0x04)
  256 + mov r5, #OMAP730_IDLECT2_SLEEP_VAL & 0xff
  257 + orr r5, r5, #OMAP730_IDLECT2_SLEEP_VAL & 0xff00
  258 + strh r5, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff]
  259 +
  260 + @ request ARM idle
  261 + mov r3, #OMAP730_IDLECT1_SLEEP_VAL & 0xff
  262 + orr r3, r3, #OMAP730_IDLECT1_SLEEP_VAL & 0xff00
  263 + strh r3, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff]
  264 +
  265 + @ disable instruction cache
  266 + mrc p15, 0, r9, c1, c0, 0
  267 + bic r2, r9, #0x1000
  268 + mcr p15, 0, r2, c1, c0, 0
  269 + nop
  270 +
  271 +/*
  272 + * Let's wait for the next wake up event to wake us up. r0 can't be
  273 + * used here because r0 holds ARM_IDLECT1
  274 + */
  275 + mov r2, #0
  276 + mcr p15, 0, r2, c7, c0, 4 @ wait for interrupt
  277 +/*
  278 + * omap730_cpu_suspend()'s resume point.
  279 + *
  280 + * It will just start executing here, so we'll restore stuff from the
  281 + * stack.
  282 + */
  283 + @ re-enable Icache
  284 + mcr p15, 0, r9, c1, c0, 0
  285 +
  286 + @ reset the ARM_IDLECT1 and ARM_IDLECT2.
  287 + strh r1, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff]
  288 + strh r0, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff]
  289 +
  290 + @ Restore EMIFF controls
  291 + str r7, [r6, #EMIFF_SDRAM_CONFIG_ASM_OFFSET & 0xff]
  292 + str r8, [r6, #EMIFS_CONFIG_ASM_OFFSET & 0xff]
  293 +
  294 + @ restore regs and return
  295 + ldmfd sp!, {r0 - r12, pc}
  296 +
  297 +ENTRY(omap730_cpu_suspend_sz)
  298 + .word . - omap730_cpu_suspend
  299 +#endif /* CONFIG_ARCH_OMAP730 */
  300 +
  301 +#ifdef CONFIG_ARCH_OMAP15XX
  302 +ENTRY(omap1510_cpu_suspend)
  303 +
  304 + @ save registers on stack
  305 + stmfd sp!, {r0 - r12, lr}
  306 +
  307 + @ load base address of Traffic Controller
  308 + mov r4, #TCMIF_ASM_BASE & 0xff000000
  309 + orr r4, r4, #TCMIF_ASM_BASE & 0x00ff0000
  310 + orr r4, r4, #TCMIF_ASM_BASE & 0x0000ff00
  311 +
  312 + @ work around errata of OMAP1510 PDE bit for TC shut down
  313 + @ clear PDE bit
  314 + ldr r5, [r4, #EMIFS_CONFIG_ASM_OFFSET & 0xff]
  315 + bic r5, r5, #PDE_BIT & 0xff
  316 + str r5, [r4, #EMIFS_CONFIG_ASM_OFFSET & 0xff]
  317 +
  318 + @ set PWD_EN bit
  319 + and r5, r5, #PWD_EN_BIT & 0xff
  320 + str r5, [r4, #EMIFS_CONFIG_ASM_OFFSET & 0xff]
  321 +
  322 + @ prepare to put SDRAM into self-refresh manually
  323 + ldr r5, [r4, #EMIFF_SDRAM_CONFIG_ASM_OFFSET & 0xff]
  324 + orr r5, r5, #SELF_REFRESH_MODE & 0xff000000
  325 + orr r5, r5, #SELF_REFRESH_MODE & 0x000000ff
  326 + str r5, [r4, #EMIFF_SDRAM_CONFIG_ASM_OFFSET & 0xff]
  327 +
  328 + @ prepare to put EMIFS to Sleep
  329 + ldr r5, [r4, #EMIFS_CONFIG_ASM_OFFSET & 0xff]
  330 + orr r5, r5, #IDLE_EMIFS_REQUEST & 0xff
  331 + str r5, [r4, #EMIFS_CONFIG_ASM_OFFSET & 0xff]
  332 +
  333 + @ load base address of ARM_IDLECT1 and ARM_IDLECT2
  334 + mov r4, #CLKGEN_REG_ASM_BASE & 0xff000000
  335 + orr r4, r4, #CLKGEN_REG_ASM_BASE & 0x00ff0000
  336 + orr r4, r4, #CLKGEN_REG_ASM_BASE & 0x0000ff00
  337 +
  338 + @ turn off clock domains
  339 + mov r5, #OMAP1510_IDLE_CLOCK_DOMAINS & 0xff
  340 + orr r5, r5, #OMAP1510_IDLE_CLOCK_DOMAINS & 0xff00
  341 + strh r5, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff]
  342 +
  343 + @ request ARM idle
  344 + mov r3, #OMAP1510_DEEP_SLEEP_REQUEST & 0xff
  345 + orr r3, r3, #OMAP1510_DEEP_SLEEP_REQUEST & 0xff00
  346 + strh r3, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff]
  347 +
  348 + mov r5, #IDLE_WAIT_CYCLES & 0xff
  349 + orr r5, r5, #IDLE_WAIT_CYCLES & 0xff00
  350 +l_1510_2:
  351 + subs r5, r5, #1
  352 + bne l_1510_2
  353 +/*
  354 + * Let's wait for the next wake up event to wake us up. r0 can't be
  355 + * used here because r0 holds ARM_IDLECT1
  356 + */
  357 + mov r2, #0
  358 + mcr p15, 0, r2, c7, c0, 4 @ wait for interrupt
  359 +/*
  360 + * omap1510_cpu_suspend()'s resume point.
  361 + *
  362 + * It will just start executing here, so we'll restore stuff from the
  363 + * stack, reset the ARM_IDLECT1 and ARM_IDLECT2.
  364 + */
  365 + strh r1, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff]
  366 + strh r0, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff]
  367 +
  368 + @ restore regs and return
  369 + ldmfd sp!, {r0 - r12, pc}
  370 +
  371 +ENTRY(omap1510_cpu_suspend_sz)
  372 + .word . - omap1510_cpu_suspend
  373 +#endif /* CONFIG_ARCH_OMAP15XX */
  374 +
  375 +#if defined(CONFIG_ARCH_OMAP16XX)
  376 +ENTRY(omap1610_cpu_suspend)
  377 +
  378 + @ save registers on stack
  379 + stmfd sp!, {r0 - r12, lr}
  380 +
  381 + @ Drain write cache
  382 + mov r4, #0
  383 + mcr p15, 0, r0, c7, c10, 4
  384 + nop
  385 +
  386 + @ Load base address of Traffic Controller
  387 + mov r6, #TCMIF_ASM_BASE & 0xff000000
  388 + orr r6, r6, #TCMIF_ASM_BASE & 0x00ff0000
  389 + orr r6, r6, #TCMIF_ASM_BASE & 0x0000ff00
  390 +
  391 + @ Prepare to put SDRAM into self-refresh manually
  392 + ldr r7, [r6, #EMIFF_SDRAM_CONFIG_ASM_OFFSET & 0xff]
  393 + orr r9, r7, #SELF_REFRESH_MODE & 0xff000000
  394 + orr r9, r9, #SELF_REFRESH_MODE & 0x000000ff
  395 + str r9, [r6, #EMIFF_SDRAM_CONFIG_ASM_OFFSET & 0xff]
  396 +
  397 + @ Prepare to put EMIFS to Sleep
  398 + ldr r8, [r6, #EMIFS_CONFIG_ASM_OFFSET & 0xff]
  399 + orr r9, r8, #IDLE_EMIFS_REQUEST & 0xff
  400 + str r9, [r6, #EMIFS_CONFIG_ASM_OFFSET & 0xff]
  401 +
  402 + @ Load base address of ARM_IDLECT1 and ARM_IDLECT2
  403 + mov r4, #CLKGEN_REG_ASM_BASE & 0xff000000
  404 + orr r4, r4, #CLKGEN_REG_ASM_BASE & 0x00ff0000
  405 + orr r4, r4, #CLKGEN_REG_ASM_BASE & 0x0000ff00
  406 +
  407 + @ Turn off clock domains
  408 + @ Do not disable PERCK (0x04)
  409 + mov r5, #OMAP1610_IDLECT2_SLEEP_VAL & 0xff
  410 + orr r5, r5, #OMAP1610_IDLECT2_SLEEP_VAL & 0xff00
  411 + strh r5, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff]
  412 +
  413 + @ Request ARM idle
  414 + mov r3, #OMAP1610_IDLECT1_SLEEP_VAL & 0xff
  415 + orr r3, r3, #OMAP1610_IDLECT1_SLEEP_VAL & 0xff00
  416 + strh r3, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff]
  417 +
  418 +/*
  419 + * Let's wait for the next wake up event to wake us up. r0 can't be
  420 + * used here because r0 holds ARM_IDLECT1
  421 + */
  422 + mov r2, #0
  423 + mcr p15, 0, r2, c7, c0, 4 @ wait for interrupt
  424 +
  425 + @ Errata (HEL3SU467, section 1.4.4) specifies nop-instructions
  426 + @ according to this formula:
  427 + @ 2 + (4*DPLL_MULT)/DPLL_DIV/ARMDIV
  428 + @ Max DPLL_MULT = 18
  429 + @ DPLL_DIV = 1
  430 + @ ARMDIV = 1
  431 + @ => 74 nop-instructions
  432 + nop
  433 + nop
  434 + nop
  435 + nop
  436 + nop
  437 + nop
  438 + nop
  439 + nop
  440 + nop
  441 + nop @10
  442 + nop
  443 + nop
  444 + nop
  445 + nop
  446 + nop
  447 + nop
  448 + nop
  449 + nop
  450 + nop
  451 + nop @20
  452 + nop
  453 + nop
  454 + nop
  455 + nop
  456 + nop
  457 + nop
  458 + nop
  459 + nop
  460 + nop
  461 + nop @30
  462 + nop
  463 + nop
  464 + nop
  465 + nop
  466 + nop
  467 + nop
  468 + nop
  469 + nop
  470 + nop
  471 + nop @40
  472 + nop
  473 + nop
  474 + nop
  475 + nop
  476 + nop
  477 + nop
  478 + nop
  479 + nop
  480 + nop
  481 + nop @50
  482 + nop
  483 + nop
  484 + nop
  485 + nop
  486 + nop
  487 + nop
  488 + nop
  489 + nop
  490 + nop
  491 + nop @60
  492 + nop
  493 + nop
  494 + nop
  495 + nop
  496 + nop
  497 + nop
  498 + nop
  499 + nop
  500 + nop
  501 + nop @70
  502 + nop
  503 + nop
  504 + nop
  505 + nop @74
  506 +/*
  507 + * omap1610_cpu_suspend()'s resume point.
  508 + *
  509 + * It will just start executing here, so we'll restore stuff from the
  510 + * stack.
  511 + */
  512 + @ Restore the ARM_IDLECT1 and ARM_IDLECT2.
  513 + strh r1, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff]
  514 + strh r0, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff]
  515 +
  516 + @ Restore EMIFF controls
  517 + str r7, [r6, #EMIFF_SDRAM_CONFIG_ASM_OFFSET & 0xff]
  518 + str r8, [r6, #EMIFS_CONFIG_ASM_OFFSET & 0xff]
  519 +
  520 + @ Restore regs and return
  521 + ldmfd sp!, {r0 - r12, pc}
  522 +
  523 +ENTRY(omap1610_cpu_suspend_sz)
  524 + .word . - omap1610_cpu_suspend
  525 +#endif /* CONFIG_ARCH_OMAP16XX */
arch/arm/mach-omap2/pm.c
  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 +
  27 +#include <asm/io.h>
  28 +#include <asm/irq.h>
  29 +#include <asm/atomic.h>
  30 +#include <asm/mach/time.h>
  31 +#include <asm/mach/irq.h>
  32 +#include <asm/mach-types.h>
  33 +
  34 +#include <asm/arch/irqs.h>
  35 +#include <asm/arch/clock.h>
  36 +#include <asm/arch/sram.h>
  37 +#include <asm/arch/pm.h>
  38 +
  39 +static struct clk *vclk;
  40 +static void (*omap2_sram_idle)(void);
  41 +static void (*omap2_sram_suspend)(int dllctrl, int cpu_rev);
  42 +static void (*saved_idle)(void);
  43 +
  44 +void omap2_pm_idle(void)
  45 +{
  46 + local_irq_disable();
  47 + local_fiq_disable();
  48 + if (need_resched()) {
  49 + local_fiq_enable();
  50 + local_irq_enable();
  51 + return;
  52 + }
  53 +
  54 + /*
  55 + * Since an interrupt may set up a timer, we don't want to
  56 + * reprogram the hardware timer with interrupts enabled.
  57 + * Re-enable interrupts only after returning from idle.
  58 + */
  59 + timer_dyn_reprogram();
  60 +
  61 + omap2_sram_idle();
  62 + local_fiq_enable();
  63 + local_irq_enable();
  64 +}
  65 +
  66 +static int omap2_pm_prepare(suspend_state_t state)
  67 +{
  68 + int error = 0;
  69 +
  70 + /* We cannot sleep in idle until we have resumed */
  71 + saved_idle = pm_idle;
  72 + pm_idle = NULL;
  73 +
  74 + switch (state)
  75 + {
  76 + case PM_SUSPEND_STANDBY:
  77 + case PM_SUSPEND_MEM:
  78 + break;
  79 +
  80 + case PM_SUSPEND_DISK:
  81 + return -ENOTSUPP;
  82 +
  83 + default:
  84 + return -EINVAL;
  85 + }
  86 +
  87 + return error;
  88 +}
  89 +
  90 +static int omap2_pm_enter(suspend_state_t state)
  91 +{
  92 + switch (state)
  93 + {
  94 + case PM_SUSPEND_STANDBY:
  95 + case PM_SUSPEND_MEM:
  96 + /* FIXME: Add suspend */
  97 + break;
  98 +
  99 + case PM_SUSPEND_DISK:
  100 + return -ENOTSUPP;
  101 +
  102 + default:
  103 + return -EINVAL;
  104 + }
  105 +
  106 + return 0;
  107 +}
  108 +
  109 +static int omap2_pm_finish(suspend_state_t state)
  110 +{
  111 + pm_idle = saved_idle;
  112 + return 0;
  113 +}
  114 +
  115 +static struct pm_ops omap_pm_ops = {
  116 + .pm_disk_mode = 0,
  117 + .prepare = omap2_pm_prepare,
  118 + .enter = omap2_pm_enter,
  119 + .finish = omap2_pm_finish,
  120 +};
  121 +
  122 +int __init omap2_pm_init(void)
  123 +{
  124 + printk("Power Management for TI OMAP.\n");
  125 +
  126 + vclk = clk_get(NULL, "virt_prcm_set");
  127 + if (IS_ERR(vclk)) {
  128 + printk(KERN_ERR "Could not get PM vclk\n");
  129 + return -ENODEV;
  130 + }
  131 +
  132 + /*
  133 + * We copy the assembler sleep/wakeup routines to SRAM.
  134 + * These routines need to be in SRAM as that's the only
  135 + * memory the MPU can see when it wakes up.
  136 + */
  137 + omap2_sram_idle = omap_sram_push(omap24xx_idle_loop_suspend,
  138 + omap24xx_idle_loop_suspend_sz);
  139 +
  140 + omap2_sram_suspend = omap_sram_push(omap24xx_cpu_suspend,
  141 + omap24xx_cpu_suspend_sz);
  142 +
  143 + pm_set_ops(&omap_pm_ops);
  144 + pm_idle = omap2_pm_idle;
  145 +
  146 + return 0;
  147 +}
  148 +
  149 +__initcall(omap2_pm_init);
arch/arm/mach-omap2/sleep.S
  1 +/*
  2 + * linux/arch/arm/mach-omap2/sleep.S
  3 + *
  4 + * (C) Copyright 2004
  5 + * Texas Instruments, <www.ti.com>
  6 + * Richard Woodruff <r-woodruff2@ti.com>
  7 + *
  8 + * This program is free software; you can redistribute it and/or
  9 + * modify it under the terms of the GNU General Public License as
  10 + * published by the Free Software Foundation; either version 2 of
  11 + * the License, or (at your option) any later version.
  12 + *
  13 + * This program is distributed in the hope that it will be useful,
  14 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR /PURPOSE. See the
  16 + * GNU General Public License for more details.
  17 + *
  18 + * You should have received a copy of the GNU General Public License
  19 + * along with this program; if not, write to the Free Software
  20 + * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
  21 + * MA 02111-1307 USA
  22 + */
  23 +
  24 +#include <linux/config.h>
  25 +#include <linux/linkage.h>
  26 +#include <asm/assembler.h>
  27 +#include <asm/arch/io.h>
  28 +#include <asm/arch/pm.h>
  29 +
  30 +#define A_32KSYNC_CR_V IO_ADDRESS(OMAP_TIMER32K_BASE+0x10)
  31 +#define A_PRCM_VOLTCTRL_V IO_ADDRESS(OMAP24XX_PRCM_BASE+0x50)
  32 +#define A_PRCM_CLKCFG_CTRL_V IO_ADDRESS(OMAP24XX_PRCM_BASE+0x80)
  33 +#define A_CM_CLKEN_PLL_V IO_ADDRESS(OMAP24XX_PRCM_BASE+0x500)
  34 +#define A_CM_IDLEST_CKGEN_V IO_ADDRESS(OMAP24XX_PRCM_BASE+0x520)
  35 +#define A_CM_CLKSEL1_PLL_V IO_ADDRESS(OMAP24XX_PRCM_BASE+0x540)
  36 +#define A_CM_CLKSEL2_PLL_V IO_ADDRESS(OMAP24XX_PRCM_BASE+0x544)
  37 +
  38 +#define A_SDRC_DLLA_CTRL_V IO_ADDRESS(OMAP24XX_SDRC_BASE+0x60)
  39 +#define A_SDRC_POWER_V IO_ADDRESS(OMAP24XX_SDRC_BASE+0x70)
  40 +#define A_SDRC_RFR_CTRL_V IO_ADDRESS(OMAP24XX_SDRC_BASE+0xA4)
  41 +#define A_SDRC0_V (0xC0000000)
  42 +#define A_SDRC_MANUAL_V IO_ADDRESS(OMAP24XX_SDRC_BASE+0xA8)
  43 +
  44 + .text
  45 +
  46 +/*
  47 + * Forces OMAP into idle state
  48 + *
  49 + * omap24xx_idle_loop_suspend() - This bit of code just executes the WFI
  50 + * for normal idles.
  51 + *
  52 + * Note: This code get's copied to internal SRAM at boot. When the OMAP
  53 + * wakes up it continues execution at the point it went to sleep.
  54 + */
  55 +ENTRY(omap24xx_idle_loop_suspend)
  56 + stmfd sp!, {r0, lr} @ save registers on stack
  57 + mov r0, #0 @ clear for mcr setup
  58 + mcr p15, 0, r0, c7, c0, 4 @ wait for interrupt
  59 + ldmfd sp!, {r0, pc} @ restore regs and return
  60 +
  61 +ENTRY(omap24xx_idle_loop_suspend_sz)
  62 + .word . - omap24xx_idle_loop_suspend
  63 +
  64 +/*
  65 + * omap242x_cpu_suspend() - Forces OMAP into deep sleep state by completing
  66 + * SDRC shutdown then ARM shutdown. Upon wake MPU is back on so just restore
  67 + * SDRC.
  68 + *
  69 + * Input:
  70 + * R0 : DLL ctrl value pre-Sleep
  71 + * R1 : Processor+Revision
  72 + * 2420: 0x21 = 242xES1, 0x26 = 242xES2.2
  73 + * 2430: 0x31 = 2430ES1, 0x32 = 2430ES2
  74 + *
  75 + * The if the DPLL is going to AutoIdle. It seems like the DPLL may be back on
  76 + * when we get called, but the DLL probably isn't. We will wait a bit more in
  77 + * case the DPLL isn't quite there yet. The code will wait on DLL for DDR even
  78 + * if in unlocked mode.
  79 + *
  80 + * For less than 242x-ES2.2 upon wake from a sleep mode where the external
  81 + * oscillator was stopped, a timing bug exists where a non-stabilized 12MHz
  82 + * clock can pass into the PRCM can cause problems at DSP and IVA.
  83 + * To work around this the code will switch to the 32kHz source prior to sleep.
  84 + * Post sleep we will shift back to using the DPLL. Apparently,
  85 + * CM_IDLEST_CLKGEN does not reflect the full clock change so you need to wait
  86 + * 3x12MHz + 3x32kHz clocks for a full switch.
  87 + *
  88 + * The DLL load value is not kept in RETENTION or OFF. It needs to be restored
  89 + * at wake
  90 + */
  91 +ENTRY(omap24xx_cpu_suspend)
  92 + stmfd sp!, {r0 - r12, lr} @ save registers on stack
  93 + mov r3, #0x0 @ clear for mrc call
  94 + mcr p15, 0, r3, c7, c10, 4 @ memory barrier, hope SDR/DDR finished
  95 + nop
  96 + nop
  97 + ldr r3, A_SDRC_POWER @ addr of sdrc power
  98 + ldr r4, [r3] @ value of sdrc power
  99 + orr r4, r4, #0x40 @ enable self refresh on idle req
  100 + mov r5, #0x2000 @ set delay (DPLL relock + DLL relock)
  101 + str r4, [r3] @ make it so
  102 + mov r2, #0
  103 + nop
  104 + mcr p15, 0, r2, c7, c0, 4 @ wait for interrupt
  105 + nop
  106 +loop:
  107 + subs r5, r5, #0x1 @ awake, wait just a bit
  108 + bne loop
  109 +
  110 + /* The DPLL has on before we take the DDR out of self refresh */
  111 + bic r4, r4, #0x40 @ now clear self refresh bit.
  112 + str r4, [r3] @ put vlaue back.
  113 + ldr r4, A_SDRC0 @ make a clock happen
  114 + ldr r4, [r4]
  115 + nop @ start auto refresh only after clk ok
  116 + movs r0, r0 @ see if DDR or SDR
  117 + ldrne r1, A_SDRC_DLLA_CTRL_S @ get addr of DLL ctrl
  118 + strne r0, [r1] @ rewrite DLLA to force DLL reload
  119 + addne r1, r1, #0x8 @ move to DLLB
  120 + strne r0, [r1] @ rewrite DLLB to force DLL reload
  121 +
  122 + mov r5, #0x1000
  123 +loop2:
  124 + subs r5, r5, #0x1
  125 + bne loop2
  126 + /* resume*/
  127 + ldmfd sp!, {r0 - r12, pc} @ restore regs and return
  128 +
  129 +A_SDRC_POWER:
  130 + .word A_SDRC_POWER_V
  131 +A_SDRC0:
  132 + .word A_SDRC0_V
  133 +A_CM_CLKSEL2_PLL_S:
  134 + .word A_CM_CLKSEL2_PLL_V
  135 +A_CM_CLKEN_PLL:
  136 + .word A_CM_CLKEN_PLL_V
  137 +A_SDRC_DLLA_CTRL_S:
  138 + .word A_SDRC_DLLA_CTRL_V
  139 +A_SDRC_MANUAL_S:
  140 + .word A_SDRC_MANUAL_V
  141 +
  142 +ENTRY(omap24xx_cpu_suspend_sz)
  143 + .word . - omap24xx_cpu_suspend
arch/arm/mach-omap2/sram-fn.S
1 1 /*
2   - * linux/arch/arm/mach-omap1/sram.S
  2 + * linux/arch/arm/mach-omap2/sram.S
3 3 *
4 4 * Omap2 specific functions that need to be run in internal SRAM
5 5 *
... ... @@ -28,7 +28,7 @@
28 28 #include <asm/arch/io.h>
29 29 #include <asm/hardware.h>
30 30  
31   -#include <asm/arch/prcm.h>
  31 +#include "prcm-regs.h"
32 32  
33 33 #define TIMER_32KSYNCT_CR_V IO_ADDRESS(OMAP24XX_32KSYNCT_BASE + 0x010)
34 34  
arch/arm/plat-omap/pm.c
... ... @@ -38,6 +38,7 @@
38 38 #include <linux/pm.h>
39 39 #include <linux/sched.h>
40 40 #include <linux/proc_fs.h>
  41 +#include <linux/pm.h>
41 42 #include <linux/interrupt.h>
42 43  
43 44 #include <asm/io.h>
arch/arm/plat-omap/sleep.S
1   -/*
2   - * linux/arch/arm/plat-omap/sleep.S
3   - *
4   - * Low-level OMAP730/1510/1610 sleep/wakeUp support
5   - *
6   - * Initial SA1110 code:
7   - * Copyright (c) 2001 Cliff Brake <cbrake@accelent.com>
8   - *
9   - * Adapted for PXA by Nicolas Pitre:
10   - * Copyright (c) 2002 Monta Vista Software, Inc.
11   - *
12   - * Support for OMAP1510/1610 by Dirk Behme <dirk.behme@de.bosch.com>
13   - *
14   - * This program is free software; you can redistribute it and/or modify it
15   - * under the terms of the GNU General Public License as published by the
16   - * Free Software Foundation; either version 2 of the License, or (at your
17   - * option) any later version.
18   - *
19   - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
20   - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
21   - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
22   - * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
23   - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
24   - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
25   - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
26   - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27   - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28   - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29   - *
30   - * You should have received a copy of the GNU General Public License along
31   - * with this program; if not, write to the Free Software Foundation, Inc.,
32   - * 675 Mass Ave, Cambridge, MA 02139, USA.
33   - */
34   -
35   -#include <linux/config.h>
36   -#include <linux/linkage.h>
37   -#include <asm/assembler.h>
38   -#include <asm/arch/io.h>
39   -#include <asm/arch/pm.h>
40   -
41   - .text
42   -
43   -/*
44   - * Forces OMAP into idle state
45   - *
46   - * omapXXXX_idle_loop_suspend()
47   - *
48   - * Note: This code get's copied to internal SRAM at boot. When the OMAP
49   - * wakes up it continues execution at the point it went to sleep.
50   - *
51   - * Note: Because of slightly different configuration values we have
52   - * processor specific functions here.
53   - */
54   -
55   -#if defined(CONFIG_ARCH_OMAP730)
56   -ENTRY(omap730_idle_loop_suspend)
57   -
58   - stmfd sp!, {r0 - r12, lr} @ save registers on stack
59   -
60   - @ load base address of ARM_IDLECT1 and ARM_IDLECT2
61   - mov r4, #CLKGEN_REG_ASM_BASE & 0xff000000
62   - orr r4, r4, #CLKGEN_REG_ASM_BASE & 0x00ff0000
63   - orr r4, r4, #CLKGEN_REG_ASM_BASE & 0x0000ff00
64   -
65   - @ turn off clock domains
66   - @ get ARM_IDLECT2 into r2
67   - ldrh r2, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff]
68   - mov r5, #OMAP730_IDLECT2_SLEEP_VAL & 0xff
69   - orr r5, r5, #OMAP730_IDLECT2_SLEEP_VAL & 0xff00
70   - strh r5, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff]
71   -
72   - @ request ARM idle
73   - @ get ARM_IDLECT1 into r1
74   - ldrh r1, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff]
75   - orr r3, r1, #OMAP730_IDLE_LOOP_REQUEST & 0xffff
76   - strh r3, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff]
77   -
78   - mov r5, #IDLE_WAIT_CYCLES & 0xff
79   - orr r5, r5, #IDLE_WAIT_CYCLES & 0xff00
80   -l_730: subs r5, r5, #1
81   - bne l_730
82   -/*
83   - * Let's wait for the next clock tick to wake us up.
84   - */
85   - mov r0, #0
86   - mcr p15, 0, r0, c7, c0, 4 @ wait for interrupt
87   -/*
88   - * omap730_idle_loop_suspend()'s resume point.
89   - *
90   - * It will just start executing here, so we'll restore stuff from the
91   - * stack, reset the ARM_IDLECT1 and ARM_IDLECT2.
92   - */
93   -
94   - @ restore ARM_IDLECT1 and ARM_IDLECT2 and return
95   - @ r1 has ARM_IDLECT1 and r2 still has ARM_IDLECT2
96   - strh r2, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff]
97   - strh r1, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff]
98   -
99   - ldmfd sp!, {r0 - r12, pc} @ restore regs and return
100   -
101   -ENTRY(omap730_idle_loop_suspend_sz)
102   - .word . - omap730_idle_loop_suspend
103   -#endif /* CONFIG_ARCH_OMAP730 */
104   -
105   -#ifdef CONFIG_ARCH_OMAP15XX
106   -ENTRY(omap1510_idle_loop_suspend)
107   -
108   - stmfd sp!, {r0 - r12, lr} @ save registers on stack
109   -
110   - @ load base address of ARM_IDLECT1 and ARM_IDLECT2
111   - mov r4, #CLKGEN_REG_ASM_BASE & 0xff000000
112   - orr r4, r4, #CLKGEN_REG_ASM_BASE & 0x00ff0000
113   - orr r4, r4, #CLKGEN_REG_ASM_BASE & 0x0000ff00
114   -
115   - @ turn off clock domains
116   - @ get ARM_IDLECT2 into r2
117   - ldrh r2, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff]
118   - mov r5, #OMAP1510_IDLE_CLOCK_DOMAINS & 0xff
119   - orr r5, r5, #OMAP1510_IDLE_CLOCK_DOMAINS & 0xff00
120   - strh r5, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff]
121   -
122   - @ request ARM idle
123   - @ get ARM_IDLECT1 into r1
124   - ldrh r1, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff]
125   - orr r3, r1, #OMAP1510_IDLE_LOOP_REQUEST & 0xffff
126   - strh r3, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff]
127   -
128   - mov r5, #IDLE_WAIT_CYCLES & 0xff
129   - orr r5, r5, #IDLE_WAIT_CYCLES & 0xff00
130   -l_1510: subs r5, r5, #1
131   - bne l_1510
132   -/*
133   - * Let's wait for the next clock tick to wake us up.
134   - */
135   - mov r0, #0
136   - mcr p15, 0, r0, c7, c0, 4 @ wait for interrupt
137   -/*
138   - * omap1510_idle_loop_suspend()'s resume point.
139   - *
140   - * It will just start executing here, so we'll restore stuff from the
141   - * stack, reset the ARM_IDLECT1 and ARM_IDLECT2.
142   - */
143   -
144   - @ restore ARM_IDLECT1 and ARM_IDLECT2 and return
145   - @ r1 has ARM_IDLECT1 and r2 still has ARM_IDLECT2
146   - strh r2, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff]
147   - strh r1, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff]
148   -
149   - ldmfd sp!, {r0 - r12, pc} @ restore regs and return
150   -
151   -ENTRY(omap1510_idle_loop_suspend_sz)
152   - .word . - omap1510_idle_loop_suspend
153   -#endif /* CONFIG_ARCH_OMAP15XX */
154   -
155   -#if defined(CONFIG_ARCH_OMAP16XX)
156   -ENTRY(omap1610_idle_loop_suspend)
157   -
158   - stmfd sp!, {r0 - r12, lr} @ save registers on stack
159   -
160   - @ load base address of ARM_IDLECT1 and ARM_IDLECT2
161   - mov r4, #CLKGEN_REG_ASM_BASE & 0xff000000
162   - orr r4, r4, #CLKGEN_REG_ASM_BASE & 0x00ff0000
163   - orr r4, r4, #CLKGEN_REG_ASM_BASE & 0x0000ff00
164   -
165   - @ turn off clock domains
166   - @ get ARM_IDLECT2 into r2
167   - ldrh r2, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff]
168   - mov r5, #OMAP1610_IDLECT2_SLEEP_VAL & 0xff
169   - orr r5, r5, #OMAP1610_IDLECT2_SLEEP_VAL & 0xff00
170   - strh r5, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff]
171   -
172   - @ request ARM idle
173   - @ get ARM_IDLECT1 into r1
174   - ldrh r1, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff]
175   - orr r3, r1, #OMAP1610_IDLE_LOOP_REQUEST & 0xffff
176   - strh r3, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff]
177   -
178   - mov r5, #IDLE_WAIT_CYCLES & 0xff
179   - orr r5, r5, #IDLE_WAIT_CYCLES & 0xff00
180   -l_1610: subs r5, r5, #1
181   - bne l_1610
182   -/*
183   - * Let's wait for the next clock tick to wake us up.
184   - */
185   - mov r0, #0
186   - mcr p15, 0, r0, c7, c0, 4 @ wait for interrupt
187   -/*
188   - * omap1610_idle_loop_suspend()'s resume point.
189   - *
190   - * It will just start executing here, so we'll restore stuff from the
191   - * stack, reset the ARM_IDLECT1 and ARM_IDLECT2.
192   - */
193   -
194   - @ restore ARM_IDLECT1 and ARM_IDLECT2 and return
195   - @ r1 has ARM_IDLECT1 and r2 still has ARM_IDLECT2
196   - strh r2, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff]
197   - strh r1, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff]
198   -
199   - ldmfd sp!, {r0 - r12, pc} @ restore regs and return
200   -
201   -ENTRY(omap1610_idle_loop_suspend_sz)
202   - .word . - omap1610_idle_loop_suspend
203   -#endif /* CONFIG_ARCH_OMAP16XX */
204   -
205   -/*
206   - * Forces OMAP into deep sleep state
207   - *
208   - * omapXXXX_cpu_suspend()
209   - *
210   - * The values of the registers ARM_IDLECT1 and ARM_IDLECT2 are passed
211   - * as arg0 and arg1 from caller. arg0 is stored in register r0 and arg1
212   - * in register r1.
213   - *
214   - * Note: This code get's copied to internal SRAM at boot. When the OMAP
215   - * wakes up it continues execution at the point it went to sleep.
216   - *
217   - * Note: Because of errata work arounds we have processor specific functions
218   - * here. They are mostly the same, but slightly different.
219   - *
220   - */
221   -
222   -#if defined(CONFIG_ARCH_OMAP730)
223   -ENTRY(omap730_cpu_suspend)
224   -
225   - @ save registers on stack
226   - stmfd sp!, {r0 - r12, lr}
227   -
228   - @ Drain write cache
229   - mov r4, #0
230   - mcr p15, 0, r0, c7, c10, 4
231   - nop
232   -
233   - @ load base address of Traffic Controller
234   - mov r6, #TCMIF_ASM_BASE & 0xff000000
235   - orr r6, r6, #TCMIF_ASM_BASE & 0x00ff0000
236   - orr r6, r6, #TCMIF_ASM_BASE & 0x0000ff00
237   -
238   - @ prepare to put SDRAM into self-refresh manually
239   - ldr r7, [r6, #EMIFF_SDRAM_CONFIG_ASM_OFFSET & 0xff]
240   - orr r9, r7, #SELF_REFRESH_MODE & 0xff000000
241   - orr r9, r9, #SELF_REFRESH_MODE & 0x000000ff
242   - str r9, [r6, #EMIFF_SDRAM_CONFIG_ASM_OFFSET & 0xff]
243   -
244   - @ prepare to put EMIFS to Sleep
245   - ldr r8, [r6, #EMIFS_CONFIG_ASM_OFFSET & 0xff]
246   - orr r9, r8, #IDLE_EMIFS_REQUEST & 0xff
247   - str r9, [r6, #EMIFS_CONFIG_ASM_OFFSET & 0xff]
248   -
249   - @ load base address of ARM_IDLECT1 and ARM_IDLECT2
250   - mov r4, #CLKGEN_REG_ASM_BASE & 0xff000000
251   - orr r4, r4, #CLKGEN_REG_ASM_BASE & 0x00ff0000
252   - orr r4, r4, #CLKGEN_REG_ASM_BASE & 0x0000ff00
253   -
254   - @ turn off clock domains
255   - @ do not disable PERCK (0x04)
256   - mov r5, #OMAP730_IDLECT2_SLEEP_VAL & 0xff
257   - orr r5, r5, #OMAP730_IDLECT2_SLEEP_VAL & 0xff00
258   - strh r5, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff]
259   -
260   - @ request ARM idle
261   - mov r3, #OMAP730_IDLECT1_SLEEP_VAL & 0xff
262   - orr r3, r3, #OMAP730_IDLECT1_SLEEP_VAL & 0xff00
263   - strh r3, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff]
264   -
265   - @ disable instruction cache
266   - mrc p15, 0, r9, c1, c0, 0
267   - bic r2, r9, #0x1000
268   - mcr p15, 0, r2, c1, c0, 0
269   - nop
270   -
271   -/*
272   - * Let's wait for the next wake up event to wake us up. r0 can't be
273   - * used here because r0 holds ARM_IDLECT1
274   - */
275   - mov r2, #0
276   - mcr p15, 0, r2, c7, c0, 4 @ wait for interrupt
277   -/*
278   - * omap730_cpu_suspend()'s resume point.
279   - *
280   - * It will just start executing here, so we'll restore stuff from the
281   - * stack.
282   - */
283   - @ re-enable Icache
284   - mcr p15, 0, r9, c1, c0, 0
285   -
286   - @ reset the ARM_IDLECT1 and ARM_IDLECT2.
287   - strh r1, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff]
288   - strh r0, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff]
289   -
290   - @ Restore EMIFF controls
291   - str r7, [r6, #EMIFF_SDRAM_CONFIG_ASM_OFFSET & 0xff]
292   - str r8, [r6, #EMIFS_CONFIG_ASM_OFFSET & 0xff]
293   -
294   - @ restore regs and return
295   - ldmfd sp!, {r0 - r12, pc}
296   -
297   -ENTRY(omap730_cpu_suspend_sz)
298   - .word . - omap730_cpu_suspend
299   -#endif /* CONFIG_ARCH_OMAP730 */
300   -
301   -#ifdef CONFIG_ARCH_OMAP15XX
302   -ENTRY(omap1510_cpu_suspend)
303   -
304   - @ save registers on stack
305   - stmfd sp!, {r0 - r12, lr}
306   -
307   - @ load base address of Traffic Controller
308   - mov r4, #TCMIF_ASM_BASE & 0xff000000
309   - orr r4, r4, #TCMIF_ASM_BASE & 0x00ff0000
310   - orr r4, r4, #TCMIF_ASM_BASE & 0x0000ff00
311   -
312   - @ work around errata of OMAP1510 PDE bit for TC shut down
313   - @ clear PDE bit
314   - ldr r5, [r4, #EMIFS_CONFIG_ASM_OFFSET & 0xff]
315   - bic r5, r5, #PDE_BIT & 0xff
316   - str r5, [r4, #EMIFS_CONFIG_ASM_OFFSET & 0xff]
317   -
318   - @ set PWD_EN bit
319   - and r5, r5, #PWD_EN_BIT & 0xff
320   - str r5, [r4, #EMIFS_CONFIG_ASM_OFFSET & 0xff]
321   -
322   - @ prepare to put SDRAM into self-refresh manually
323   - ldr r5, [r4, #EMIFF_SDRAM_CONFIG_ASM_OFFSET & 0xff]
324   - orr r5, r5, #SELF_REFRESH_MODE & 0xff000000
325   - orr r5, r5, #SELF_REFRESH_MODE & 0x000000ff
326   - str r5, [r4, #EMIFF_SDRAM_CONFIG_ASM_OFFSET & 0xff]
327   -
328   - @ prepare to put EMIFS to Sleep
329   - ldr r5, [r4, #EMIFS_CONFIG_ASM_OFFSET & 0xff]
330   - orr r5, r5, #IDLE_EMIFS_REQUEST & 0xff
331   - str r5, [r4, #EMIFS_CONFIG_ASM_OFFSET & 0xff]
332   -
333   - @ load base address of ARM_IDLECT1 and ARM_IDLECT2
334   - mov r4, #CLKGEN_REG_ASM_BASE & 0xff000000
335   - orr r4, r4, #CLKGEN_REG_ASM_BASE & 0x00ff0000
336   - orr r4, r4, #CLKGEN_REG_ASM_BASE & 0x0000ff00
337   -
338   - @ turn off clock domains
339   - mov r5, #OMAP1510_IDLE_CLOCK_DOMAINS & 0xff
340   - orr r5, r5, #OMAP1510_IDLE_CLOCK_DOMAINS & 0xff00
341   - strh r5, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff]
342   -
343   - @ request ARM idle
344   - mov r3, #OMAP1510_DEEP_SLEEP_REQUEST & 0xff
345   - orr r3, r3, #OMAP1510_DEEP_SLEEP_REQUEST & 0xff00
346   - strh r3, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff]
347   -
348   - mov r5, #IDLE_WAIT_CYCLES & 0xff
349   - orr r5, r5, #IDLE_WAIT_CYCLES & 0xff00
350   -l_1510_2:
351   - subs r5, r5, #1
352   - bne l_1510_2
353   -/*
354   - * Let's wait for the next wake up event to wake us up. r0 can't be
355   - * used here because r0 holds ARM_IDLECT1
356   - */
357   - mov r2, #0
358   - mcr p15, 0, r2, c7, c0, 4 @ wait for interrupt
359   -/*
360   - * omap1510_cpu_suspend()'s resume point.
361   - *
362   - * It will just start executing here, so we'll restore stuff from the
363   - * stack, reset the ARM_IDLECT1 and ARM_IDLECT2.
364   - */
365   - strh r1, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff]
366   - strh r0, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff]
367   -
368   - @ restore regs and return
369   - ldmfd sp!, {r0 - r12, pc}
370   -
371   -ENTRY(omap1510_cpu_suspend_sz)
372   - .word . - omap1510_cpu_suspend
373   -#endif /* CONFIG_ARCH_OMAP15XX */
374   -
375   -#if defined(CONFIG_ARCH_OMAP16XX)
376   -ENTRY(omap1610_cpu_suspend)
377   -
378   - @ save registers on stack
379   - stmfd sp!, {r0 - r12, lr}
380   -
381   - @ Drain write cache
382   - mov r4, #0
383   - mcr p15, 0, r0, c7, c10, 4
384   - nop
385   -
386   - @ load base address of Traffic Controller
387   - mov r6, #TCMIF_ASM_BASE & 0xff000000
388   - orr r6, r6, #TCMIF_ASM_BASE & 0x00ff0000
389   - orr r6, r6, #TCMIF_ASM_BASE & 0x0000ff00
390   -
391   - @ prepare to put SDRAM into self-refresh manually
392   - ldr r7, [r6, #EMIFF_SDRAM_CONFIG_ASM_OFFSET & 0xff]
393   - orr r9, r7, #SELF_REFRESH_MODE & 0xff000000
394   - orr r9, r9, #SELF_REFRESH_MODE & 0x000000ff
395   - str r9, [r6, #EMIFF_SDRAM_CONFIG_ASM_OFFSET & 0xff]
396   -
397   - @ prepare to put EMIFS to Sleep
398   - ldr r8, [r6, #EMIFS_CONFIG_ASM_OFFSET & 0xff]
399   - orr r9, r8, #IDLE_EMIFS_REQUEST & 0xff
400   - str r9, [r6, #EMIFS_CONFIG_ASM_OFFSET & 0xff]
401   -
402   - @ load base address of ARM_IDLECT1 and ARM_IDLECT2
403   - mov r4, #CLKGEN_REG_ASM_BASE & 0xff000000
404   - orr r4, r4, #CLKGEN_REG_ASM_BASE & 0x00ff0000
405   - orr r4, r4, #CLKGEN_REG_ASM_BASE & 0x0000ff00
406   -
407   - @ turn off clock domains
408   - @ do not disable PERCK (0x04)
409   - mov r5, #OMAP1610_IDLECT2_SLEEP_VAL & 0xff
410   - orr r5, r5, #OMAP1610_IDLECT2_SLEEP_VAL & 0xff00
411   - strh r5, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff]
412   -
413   - @ request ARM idle
414   - mov r3, #OMAP1610_IDLECT1_SLEEP_VAL & 0xff
415   - orr r3, r3, #OMAP1610_IDLECT1_SLEEP_VAL & 0xff00
416   - strh r3, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff]
417   -
418   - @ disable instruction cache
419   - mrc p15, 0, r9, c1, c0, 0
420   - bic r2, r9, #0x1000
421   - mcr p15, 0, r2, c1, c0, 0
422   - nop
423   -
424   -/*
425   - * Let's wait for the next wake up event to wake us up. r0 can't be
426   - * used here because r0 holds ARM_IDLECT1
427   - */
428   - mov r2, #0
429   - mcr p15, 0, r2, c7, c0, 4 @ wait for interrupt
430   -/*
431   - * omap1610_cpu_suspend()'s resume point.
432   - *
433   - * It will just start executing here, so we'll restore stuff from the
434   - * stack.
435   - */
436   - @ re-enable Icache
437   - mcr p15, 0, r9, c1, c0, 0
438   -
439   - @ reset the ARM_IDLECT1 and ARM_IDLECT2.
440   - strh r1, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff]
441   - strh r0, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff]
442   -
443   - @ Restore EMIFF controls
444   - str r7, [r6, #EMIFF_SDRAM_CONFIG_ASM_OFFSET & 0xff]
445   - str r8, [r6, #EMIFS_CONFIG_ASM_OFFSET & 0xff]
446   -
447   - @ restore regs and return
448   - ldmfd sp!, {r0 - r12, pc}
449   -
450   -ENTRY(omap1610_cpu_suspend_sz)
451   - .word . - omap1610_cpu_suspend
452   -#endif /* CONFIG_ARCH_OMAP16XX */
arch/arm/plat-omap/sram.c
... ... @@ -16,24 +16,94 @@
16 16 #include <linux/kernel.h>
17 17 #include <linux/init.h>
18 18  
19   -#include <asm/mach/map.h>
20 19 #include <asm/tlb.h>
21 20 #include <asm/io.h>
22 21 #include <asm/cacheflush.h>
23 22  
  23 +#include <asm/mach/map.h>
  24 +
24 25 #include <asm/arch/sram.h>
  26 +#include <asm/arch/board.h>
25 27  
26 28 #define OMAP1_SRAM_PA 0x20000000
27 29 #define OMAP1_SRAM_VA 0xd0000000
28 30 #define OMAP2_SRAM_PA 0x40200000
  31 +#define OMAP2_SRAM_PUB_PA 0x4020f800
29 32 #define OMAP2_SRAM_VA 0xd0000000
  33 +#define OMAP2_SRAM_PUB_VA 0xd0000800
30 34  
  35 +#if defined(CONFIG_ARCH_OMAP24XX)
  36 +#define SRAM_BOOTLOADER_SZ 0x00
  37 +#else
31 38 #define SRAM_BOOTLOADER_SZ 0x80
  39 +#endif
32 40  
  41 +#define VA_REQINFOPERM0 IO_ADDRESS(0x68005048)
  42 +#define VA_READPERM0 IO_ADDRESS(0x68005050)
  43 +#define VA_WRITEPERM0 IO_ADDRESS(0x68005058)
  44 +#define VA_CONTROL_STAT IO_ADDRESS(0x480002F8)
  45 +#define GP_DEVICE 0x300
  46 +#define TYPE_MASK 0x700
  47 +
  48 +#define ROUND_DOWN(value,boundary) ((value) & (~((boundary)-1)))
  49 +
33 50 static unsigned long omap_sram_base;
34 51 static unsigned long omap_sram_size;
35 52 static unsigned long omap_sram_ceil;
36 53  
  54 +unsigned long omap_fb_sram_start;
  55 +unsigned long omap_fb_sram_size;
  56 +
  57 +/* Depending on the target RAMFS firewall setup, the public usable amount of
  58 + * SRAM varies. The default accessable size for all device types is 2k. A GP
  59 + * device allows ARM11 but not other initators for full size. This
  60 + * functionality seems ok until some nice security API happens.
  61 + */
  62 +static int is_sram_locked(void)
  63 +{
  64 + int type = 0;
  65 +
  66 + if (cpu_is_omap242x())
  67 + type = __raw_readl(VA_CONTROL_STAT) & TYPE_MASK;
  68 +
  69 + if (type == GP_DEVICE) {
  70 + /* RAMFW: R/W access to all initators for all qualifier sets */
  71 + if (cpu_is_omap242x()) {
  72 + __raw_writel(0xFF, VA_REQINFOPERM0); /* all q-vects */
  73 + __raw_writel(0xCFDE, VA_READPERM0); /* all i-read */
  74 + __raw_writel(0xCFDE, VA_WRITEPERM0); /* all i-write */
  75 + }
  76 + return 0;
  77 + } else
  78 + return 1; /* assume locked with no PPA or security driver */
  79 +}
  80 +
  81 +void get_fb_sram_conf(unsigned long start_avail, unsigned size_avail,
  82 + unsigned long *start, unsigned long *size)
  83 +{
  84 + const struct omap_fbmem_config *fbmem_conf;
  85 +
  86 + fbmem_conf = omap_get_config(OMAP_TAG_FBMEM, struct omap_fbmem_config);
  87 + if (fbmem_conf != NULL) {
  88 + *start = fbmem_conf->fb_sram_start;
  89 + *size = fbmem_conf->fb_sram_size;
  90 + } else {
  91 + *size = 0;
  92 + *start = 0;
  93 + }
  94 +
  95 + if (*size && (
  96 + *start < start_avail ||
  97 + *start + *size > start_avail + size_avail)) {
  98 + printk(KERN_ERR "invalid FB SRAM configuration\n");
  99 + *start = start_avail;
  100 + *size = size_avail;
  101 + }
  102 +
  103 + if (*size)
  104 + pr_info("Reserving %lu bytes SRAM for frame buffer\n", *size);
  105 +}
  106 +
37 107 /*
38 108 * The amount of SRAM depends on the core type.
39 109 * Note that we cannot try to test for SRAM here because writes
40 110  
41 111  
42 112  
... ... @@ -42,26 +112,45 @@
42 112 */
43 113 void __init omap_detect_sram(void)
44 114 {
45   - if (!cpu_is_omap24xx())
  115 + unsigned long sram_start;
  116 +
  117 + if (cpu_is_omap24xx()) {
  118 + if (is_sram_locked()) {
  119 + omap_sram_base = OMAP2_SRAM_PUB_VA;
  120 + sram_start = OMAP2_SRAM_PUB_PA;
  121 + omap_sram_size = 0x800; /* 2K */
  122 + } else {
  123 + omap_sram_base = OMAP2_SRAM_VA;
  124 + sram_start = OMAP2_SRAM_PA;
  125 + if (cpu_is_omap242x())
  126 + omap_sram_size = 0xa0000; /* 640K */
  127 + else if (cpu_is_omap243x())
  128 + omap_sram_size = 0x10000; /* 64K */
  129 + }
  130 + } else {
46 131 omap_sram_base = OMAP1_SRAM_VA;
47   - else
48   - omap_sram_base = OMAP2_SRAM_VA;
  132 + sram_start = OMAP1_SRAM_PA;
49 133  
50   - if (cpu_is_omap730())
51   - omap_sram_size = 0x32000; /* 200K */
52   - else if (cpu_is_omap15xx())
53   - omap_sram_size = 0x30000; /* 192K */
54   - else if (cpu_is_omap1610() || cpu_is_omap1621() || cpu_is_omap1710())
55   - omap_sram_size = 0x4000; /* 16K */
56   - else if (cpu_is_omap1611())
57   - omap_sram_size = 0x3e800; /* 250K */
58   - else if (cpu_is_omap2420())
59   - omap_sram_size = 0xa0014; /* 640K */
60   - else {
61   - printk(KERN_ERR "Could not detect SRAM size\n");
62   - omap_sram_size = 0x4000;
  134 + if (cpu_is_omap730())
  135 + omap_sram_size = 0x32000; /* 200K */
  136 + else if (cpu_is_omap15xx())
  137 + omap_sram_size = 0x30000; /* 192K */
  138 + else if (cpu_is_omap1610() || cpu_is_omap1621() ||
  139 + cpu_is_omap1710())
  140 + omap_sram_size = 0x4000; /* 16K */
  141 + else if (cpu_is_omap1611())
  142 + omap_sram_size = 0x3e800; /* 250K */
  143 + else {
  144 + printk(KERN_ERR "Could not detect SRAM size\n");
  145 + omap_sram_size = 0x4000;
  146 + }
63 147 }
64   -
  148 + get_fb_sram_conf(sram_start + SRAM_BOOTLOADER_SZ,
  149 + omap_sram_size - SRAM_BOOTLOADER_SZ,
  150 + &omap_fb_sram_start, &omap_fb_sram_size);
  151 + if (omap_fb_sram_size)
  152 + omap_sram_size -= sram_start + omap_sram_size -
  153 + omap_fb_sram_start;
65 154 omap_sram_ceil = omap_sram_base + omap_sram_size;
66 155 }
67 156  
68 157  
... ... @@ -80,12 +169,20 @@
80 169 */
81 170 void __init omap_map_sram(void)
82 171 {
  172 + unsigned long base;
  173 +
83 174 if (omap_sram_size == 0)
84 175 return;
85 176  
86 177 if (cpu_is_omap24xx()) {
87 178 omap_sram_io_desc[0].virtual = OMAP2_SRAM_VA;
88   - omap_sram_io_desc[0].pfn = __phys_to_pfn(OMAP2_SRAM_PA);
  179 +
  180 + if (is_sram_locked())
  181 + base = OMAP2_SRAM_PUB_PA;
  182 + else
  183 + base = OMAP2_SRAM_PA;
  184 + base = ROUND_DOWN(base, PAGE_SIZE);
  185 + omap_sram_io_desc[0].pfn = __phys_to_pfn(base);
89 186 }
90 187  
91 188 omap_sram_io_desc[0].length = (omap_sram_size + PAGE_SIZE-1)/PAGE_SIZE;
... ... @@ -93,7 +190,8 @@
93 190 iotable_init(omap_sram_io_desc, ARRAY_SIZE(omap_sram_io_desc));
94 191  
95 192 printk(KERN_INFO "SRAM: Mapped pa 0x%08lx to va 0x%08lx size: 0x%lx\n",
96   - omap_sram_io_desc[0].pfn, omap_sram_io_desc[0].virtual,
  193 + __pfn_to_phys(omap_sram_io_desc[0].pfn),
  194 + omap_sram_io_desc[0].virtual,
97 195 omap_sram_io_desc[0].length);
98 196  
99 197 /*
100 198  
... ... @@ -118,8 +216,9 @@
118 216 printk(KERN_ERR "Not enough space in SRAM\n");
119 217 return NULL;
120 218 }
  219 +
121 220 omap_sram_ceil -= size;
122   - omap_sram_ceil &= ~0x3;
  221 + omap_sram_ceil = ROUND_DOWN(omap_sram_ceil, sizeof(void *));
123 222 memcpy((void *)omap_sram_ceil, start, size);
124 223  
125 224 return (void *)omap_sram_ceil;
include/asm-arm/arch-omap/pm.h
... ... @@ -49,7 +49,7 @@
49 49  
50 50 /*
51 51 * ----------------------------------------------------------------------------
52   - * Powermanagement bitmasks
  52 + * Power management bitmasks
53 53 * ----------------------------------------------------------------------------
54 54 */
55 55 #define IDLE_WAIT_CYCLES 0x00000fff
56 56  
57 57  
58 58  
59 59  
60 60  
61 61  
... ... @@ -112,32 +112,59 @@
112 112 #endif
113 113  
114 114 #ifndef __ASSEMBLER__
  115 +
  116 +#include <linux/clk.h>
  117 +
  118 +extern void prevent_idle_sleep(void);
  119 +extern void allow_idle_sleep(void);
  120 +
  121 +/**
  122 + * clk_deny_idle - Prevents the clock from being idled during MPU idle
  123 + * @clk: clock signal handle
  124 + */
  125 +void clk_deny_idle(struct clk *clk);
  126 +
  127 +/**
  128 + * clk_allow_idle - Counters previous clk_deny_idle
  129 + * @clk: clock signal handle
  130 + */
  131 +void clk_deny_idle(struct clk *clk);
  132 +
115 133 extern void omap_pm_idle(void);
116 134 extern void omap_pm_suspend(void);
117 135 extern void omap730_cpu_suspend(unsigned short, unsigned short);
118 136 extern void omap1510_cpu_suspend(unsigned short, unsigned short);
119 137 extern void omap1610_cpu_suspend(unsigned short, unsigned short);
  138 +extern void omap24xx_cpu_suspend(u32 dll_ctrl, u32 cpu_revision);
120 139 extern void omap730_idle_loop_suspend(void);
121 140 extern void omap1510_idle_loop_suspend(void);
122 141 extern void omap1610_idle_loop_suspend(void);
  142 +extern void omap24xx_idle_loop_suspend(void);
123 143  
  144 +extern unsigned int omap730_cpu_suspend_sz;
  145 +extern unsigned int omap1510_cpu_suspend_sz;
  146 +extern unsigned int omap1610_cpu_suspend_sz;
  147 +extern unsigned int omap24xx_cpu_suspend_sz;
  148 +extern unsigned int omap730_idle_loop_suspend_sz;
  149 +extern unsigned int omap1510_idle_loop_suspend_sz;
  150 +extern unsigned int omap1610_idle_loop_suspend_sz;
  151 +extern unsigned int omap24xx_idle_loop_suspend_sz;
  152 +
124 153 #ifdef CONFIG_OMAP_SERIAL_WAKE
125 154 extern void omap_serial_wake_trigger(int enable);
126 155 #else
  156 +#define omap_serial_wakeup_init() {}
127 157 #define omap_serial_wake_trigger(x) {}
128 158 #endif /* CONFIG_OMAP_SERIAL_WAKE */
129 159  
130   -extern unsigned int omap730_cpu_suspend_sz;
131   -extern unsigned int omap730_idle_loop_suspend_sz;
132   -extern unsigned int omap1510_cpu_suspend_sz;
133   -extern unsigned int omap1510_idle_loop_suspend_sz;
134   -extern unsigned int omap1610_cpu_suspend_sz;
135   -extern unsigned int omap1610_idle_loop_suspend_sz;
136   -
137 160 #define ARM_SAVE(x) arm_sleep_save[ARM_SLEEP_SAVE_##x] = omap_readl(x)
138 161 #define ARM_RESTORE(x) omap_writel((arm_sleep_save[ARM_SLEEP_SAVE_##x]), (x))
139 162 #define ARM_SHOW(x) arm_sleep_save[ARM_SLEEP_SAVE_##x]
140 163  
  164 +#define DSP_SAVE(x) dsp_sleep_save[DSP_SLEEP_SAVE_##x] = __raw_readw(x)
  165 +#define DSP_RESTORE(x) __raw_writew((dsp_sleep_save[DSP_SLEEP_SAVE_##x]), (x))
  166 +#define DSP_SHOW(x) dsp_sleep_save[DSP_SLEEP_SAVE_##x]
  167 +
141 168 #define ULPD_SAVE(x) ulpd_sleep_save[ULPD_SLEEP_SAVE_##x] = omap_readw(x)
142 169 #define ULPD_RESTORE(x) omap_writew((ulpd_sleep_save[ULPD_SLEEP_SAVE_##x]), (x))
143 170 #define ULPD_SHOW(x) ulpd_sleep_save[ULPD_SLEEP_SAVE_##x]
... ... @@ -154,6 +181,10 @@
154 181 #define MPUI1610_RESTORE(x) omap_writel((mpui1610_sleep_save[MPUI1610_SLEEP_SAVE_##x]), (x))
155 182 #define MPUI1610_SHOW(x) mpui1610_sleep_save[MPUI1610_SLEEP_SAVE_##x]
156 183  
  184 +#define OMAP24XX_SAVE(x) omap24xx_sleep_save[OMAP24XX_SLEEP_SAVE_##x] = x
  185 +#define OMAP24XX_RESTORE(x) x = omap24xx_sleep_save[OMAP24XX_SLEEP_SAVE_##x]
  186 +#define OMAP24XX_SHOW(x) omap24xx_sleep_save[OMAP24XX_SLEEP_SAVE_##x]
  187 +
157 188 /*
158 189 * List of global OMAP registers to preserve.
159 190 * More ones like CP and general purpose register values are preserved
... ... @@ -176,6 +207,15 @@
176 207 ARM_SLEEP_SAVE_SIZE
177 208 };
178 209  
  210 +enum dsp_save_state {
  211 + DSP_SLEEP_SAVE_START = 0,
  212 + /*
  213 + * DSP registers 16 bits
  214 + */
  215 + DSP_SLEEP_SAVE_DSP_IDLECT2,
  216 + DSP_SLEEP_SAVE_SIZE
  217 +};
  218 +
179 219 enum ulpd_save_state {
180 220 ULPD_SLEEP_SAVE_START = 0,
181 221 /*
... ... @@ -252,6 +292,31 @@
252 292 #else
253 293 MPUI1610_SLEEP_SAVE_SIZE = 0
254 294 #endif
  295 +};
  296 +
  297 +enum omap24xx_save_state {
  298 + OMAP24XX_SLEEP_SAVE_START = 0,
  299 + OMAP24XX_SLEEP_SAVE_INTC_MIR0,
  300 + OMAP24XX_SLEEP_SAVE_INTC_MIR1,
  301 + OMAP24XX_SLEEP_SAVE_INTC_MIR2,
  302 + OMAP24XX_SLEEP_SAVE_CM_FCLKEN1_CORE,
  303 + OMAP24XX_SLEEP_SAVE_CM_FCLKEN2_CORE,
  304 + OMAP24XX_SLEEP_SAVE_CM_ICLKEN1_CORE,
  305 + OMAP24XX_SLEEP_SAVE_CM_ICLKEN2_CORE,
  306 + OMAP24XX_SLEEP_SAVE_CM_ICLKEN4_CORE,
  307 + OMAP24XX_SLEEP_SAVE_GPIO1_IRQENABLE1,
  308 + OMAP24XX_SLEEP_SAVE_GPIO2_IRQENABLE1,
  309 + OMAP24XX_SLEEP_SAVE_GPIO3_IRQENABLE1,
  310 + OMAP24XX_SLEEP_SAVE_GPIO4_IRQENABLE1,
  311 + OMAP24XX_SLEEP_SAVE_GPIO3_OE,
  312 + OMAP24XX_SLEEP_SAVE_GPIO4_OE,
  313 + OMAP24XX_SLEEP_SAVE_GPIO3_RISINGDETECT,
  314 + OMAP24XX_SLEEP_SAVE_GPIO3_FALLINGDETECT,
  315 + OMAP24XX_SLEEP_SAVE_CONTROL_PADCONF_SPI1_NCS2,
  316 + OMAP24XX_SLEEP_SAVE_CONTROL_PADCONF_MCBSP1_DX,
  317 + OMAP24XX_SLEEP_SAVE_CONTROL_PADCONF_SSI1_FLAG_TX,
  318 + OMAP24XX_SLEEP_SAVE_CONTROL_PADCONF_SYS_NIRQW0,
  319 + OMAP24XX_SLEEP_SAVE_SIZE
255 320 };
256 321  
257 322 #endif /* ASSEMBLER */
include/asm-arm/arch-omap/sram.h
... ... @@ -20,6 +20,8 @@
20 20 u32 mem_type);
21 21 extern u32 omap2_set_prcm(u32 dpll_ctrl_val, u32 sdrc_rfr_val, int bypass);
22 22  
  23 +extern unsigned long omap_fb_sram_start;
  24 +extern unsigned long omap_fb_sram_size;
23 25  
24 26 /* Do not use these */
25 27 extern void sram_reprogram_clock(u32 ckctl, u32 dpllctl);