* [PATCH 1/9] 24XX: PM: Move pm.c to pm24xx.c and sleep.S to sleep24xx.S
2008-05-16 10:53 [PATCH 0/9] 34XX: PM: Support for retention on suspend and idle Högander Jouni
@ 2008-05-16 10:57 ` Jouni Hogander
2008-05-16 10:57 ` [PATCH 2/9] 24XX: PM: Move debugging related code to pm-debug.c Jouni Hogander
` (8 subsequent siblings)
9 siblings, 0 replies; 16+ messages in thread
From: Jouni Hogander @ 2008-05-16 10:57 UTC (permalink / raw)
To: linux-omap; +Cc: jouni.hogander
Rename filenames to prepare 34XX additions.
Compile omap2 code only if CONFIG_ARCH_OMAP2 is defined.
Signed-off-by: Jouni Hogander <jouni.hogander@nokia.com>
---
arch/arm/mach-omap2/Makefile | 4 +-
arch/arm/mach-omap2/pm.c | 845 ---------------------------------------
arch/arm/mach-omap2/pm24xx.c | 845 +++++++++++++++++++++++++++++++++++++++
arch/arm/mach-omap2/sleep.S | 133 ------
arch/arm/mach-omap2/sleep24xx.S | 133 ++++++
5 files changed, 981 insertions(+), 979 deletions(-)
delete mode 100644 arch/arm/mach-omap2/pm.c
create mode 100644 arch/arm/mach-omap2/pm24xx.c
delete mode 100644 arch/arm/mach-omap2/sleep.S
create mode 100644 arch/arm/mach-omap2/sleep24xx.S
diff --git a/arch/arm/mach-omap2/Makefile b/arch/arm/mach-omap2/Makefile
index ea0cf43..462f685 100644
--- a/arch/arm/mach-omap2/Makefile
+++ b/arch/arm/mach-omap2/Makefile
@@ -12,7 +12,9 @@ obj-$(CONFIG_ARCH_OMAP2) += sram24xx.o
obj-$(CONFIG_ARCH_OMAP3) += sram34xx.o
# Power Management
-obj-$(CONFIG_PM) += pm.o sleep.o
+ifeq ($(CONFIG_ARCH_OMAP2),y)
+obj-$(CONFIG_PM) += pm24xx.o sleep24xx.o
+endif
# Clock framework
obj-$(CONFIG_ARCH_OMAP2) += clock24xx.o
diff --git a/arch/arm/mach-omap2/pm.c b/arch/arm/mach-omap2/pm.c
deleted file mode 100644
index b627fe5..0000000
--- a/arch/arm/mach-omap2/pm.c
+++ /dev/null
@@ -1,845 +0,0 @@
-/*
- * linux/arch/arm/mach-omap2/pm.c
- *
- * OMAP2 Power Management Routines
- *
- * Copyright (C) 2005 Texas Instruments, Inc.
- * Copyright (C) 2006-2008 Nokia Corporation
- *
- * Written by:
- * Richard Woodruff <r-woodruff2@ti.com>
- * Tony Lindgren
- * Juha Yrjola
- * Amit Kucheria <amit.kucheria@nokia.com>
- * Igor Stoppa <igor.stoppa@nokia.com>
- *
- * Based on pm.c for omap1
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#include <linux/suspend.h>
-#include <linux/sched.h>
-#include <linux/proc_fs.h>
-#include <linux/interrupt.h>
-#include <linux/sysfs.h>
-#include <linux/module.h>
-#include <linux/delay.h>
-#include <linux/clk.h>
-#include <linux/io.h>
-#include <linux/irq.h>
-
-#include <asm/atomic.h>
-#include <asm/mach/time.h>
-#include <asm/mach/irq.h>
-#include <asm/mach-types.h>
-
-#include <asm/arch/irqs.h>
-#include <asm/arch/clock.h>
-#include <asm/arch/sram.h>
-#include <asm/arch/control.h>
-#include <asm/arch/gpio.h>
-#include <asm/arch/pm.h>
-#include <asm/arch/mux.h>
-#include <asm/arch/dma.h>
-#include <asm/arch/board.h>
-
-#include "prm.h"
-#include "prm-regbits-24xx.h"
-#include "cm.h"
-#include "cm-regbits-24xx.h"
-#include "sdrc.h"
-
-/* These addrs are in assembly language code to be patched at runtime */
-extern void *omap2_ocs_sdrc_power;
-extern void *omap2_ocs_sdrc_dlla_ctrl;
-
-static void (*omap2_sram_idle)(void);
-static void (*omap2_sram_suspend)(void __iomem *dllctrl);
-static void (*saved_idle)(void);
-
-static u32 omap2_read_32k_sync_counter(void)
-{
- return omap_readl(OMAP2_32KSYNCT_BASE + 0x0010);
-}
-
-#ifdef CONFIG_PM_DEBUG
-int omap2_pm_debug = 0;
-
-static int serial_console_clock_disabled;
-static int serial_console_uart;
-static unsigned int serial_console_next_disable;
-
-static struct clk *console_iclk, *console_fclk;
-
-static void serial_console_kick(void)
-{
- serial_console_next_disable = omap2_read_32k_sync_counter();
- /* Keep the clocks on for 4 secs */
- serial_console_next_disable += 4 * 32768;
-}
-
-static void serial_wait_tx(void)
-{
- static const unsigned long uart_bases[3] = {
- 0x4806a000, 0x4806c000, 0x4806e000
- };
- unsigned long lsr_reg;
- int looped = 0;
-
- /* Wait for TX FIFO and THR to get empty */
- lsr_reg = IO_ADDRESS(uart_bases[serial_console_uart - 1] + (5 << 2));
- while ((__raw_readb(lsr_reg) & 0x60) != 0x60)
- looped = 1;
- if (looped)
- serial_console_kick();
-}
-
-static void serial_console_fclk_mask(u32 *f1, u32 *f2)
-{
- switch (serial_console_uart) {
- case 1:
- *f1 &= ~(1 << 21);
- break;
- case 2:
- *f1 &= ~(1 << 22);
- break;
- case 3:
- *f2 &= ~(1 << 2);
- break;
- }
-}
-
-static void serial_console_sleep(int enable)
-{
- if (console_iclk == NULL || console_fclk == NULL)
- return;
-
- if (enable) {
- BUG_ON(serial_console_clock_disabled);
- if (clk_get_usecount(console_fclk) == 0)
- return;
- if ((int) serial_console_next_disable -
- (int) omap2_read_32k_sync_counter() >= 0)
- return;
- serial_wait_tx();
- clk_disable(console_iclk);
- clk_disable(console_fclk);
- serial_console_clock_disabled = 1;
- } else {
- int serial_wakeup = 0;
- u32 l;
-
- switch (serial_console_uart) {
- case 1:
- l = prm_read_mod_reg(CORE_MOD, PM_WKST1);
- if (l & OMAP24XX_ST_UART1)
- serial_wakeup = 1;
- break;
- case 2:
- l = prm_read_mod_reg(CORE_MOD, PM_WKST1);
- if (l & OMAP24XX_ST_UART2)
- serial_wakeup = 1;
- break;
- case 3:
- l = prm_read_mod_reg(CORE_MOD, OMAP24XX_PM_WKST2);
- if (l & OMAP24XX_ST_UART3)
- serial_wakeup = 1;
- break;
- }
- if (serial_wakeup)
- serial_console_kick();
- if (!serial_console_clock_disabled)
- return;
- clk_enable(console_iclk);
- clk_enable(console_fclk);
- serial_console_clock_disabled = 0;
- }
-}
-
-static void pm_init_serial_console(void)
-{
- const struct omap_serial_console_config *conf;
- char name[16];
-
- conf = omap_get_config(OMAP_TAG_SERIAL_CONSOLE,
- struct omap_serial_console_config);
- if (conf == NULL)
- return;
- if (conf->console_uart > 3 || conf->console_uart < 1)
- return;
- serial_console_uart = conf->console_uart;
- sprintf(name, "uart%d_fck", conf->console_uart);
- console_fclk = clk_get(NULL, name);
- if (IS_ERR(console_fclk))
- console_fclk = NULL;
- name[6] = 'i';
- console_iclk = clk_get(NULL, name);
- if (IS_ERR(console_fclk))
- console_iclk = NULL;
- if (console_fclk == NULL || console_iclk == NULL) {
- serial_console_uart = 0;
- return;
- }
- switch (serial_console_uart) {
- case 1:
- prm_set_mod_reg_bits(OMAP24XX_ST_UART1, CORE_MOD, PM_WKEN1);
- break;
- case 2:
- prm_set_mod_reg_bits(OMAP24XX_ST_UART2, CORE_MOD, PM_WKEN1);
- break;
- case 3:
- prm_set_mod_reg_bits(OMAP24XX_ST_UART3, CORE_MOD,
- OMAP24XX_PM_WKEN2);
- break;
- }
-}
-
-#define DUMP_PRM_MOD_REG(mod, reg) \
- regs[reg_count].name = #mod "." #reg; \
- regs[reg_count++].val = prm_read_mod_reg(mod, reg)
-#define DUMP_CM_MOD_REG(mod, reg) \
- regs[reg_count].name = #mod "." #reg; \
- regs[reg_count++].val = cm_read_mod_reg(mod, reg)
-#define DUMP_PRM_REG(reg) \
- regs[reg_count].name = #reg; \
- regs[reg_count++].val = __raw_readl(reg)
-#define DUMP_CM_REG(reg) \
- regs[reg_count].name = #reg; \
- regs[reg_count++].val = __raw_readl(reg)
-#define DUMP_INTC_REG(reg, off) \
- regs[reg_count].name = #reg; \
- regs[reg_count++].val = __raw_readl(IO_ADDRESS(0x480fe000 + (off)))
-
-static void omap2_pm_dump(int mode, int resume, unsigned int us)
-{
- struct reg {
- const char *name;
- u32 val;
- } regs[32];
- int reg_count = 0, i;
- const char *s1 = NULL, *s2 = NULL;
-
- if (!resume) {
-#if 0
- /* MPU */
- DUMP_PRM_REG(OMAP24XX_PRCM_IRQENABLE_MPU);
- DUMP_CM_MOD_REG(MPU_MOD, CM_CLKSTCTRL);
- DUMP_PRM_MOD_REG(MPU_MOD, PM_PWSTCTRL);
- DUMP_PRM_MOD_REG(MPU_MOD, PM_PWSTST);
- DUMP_PRM_MOD_REG(MPU_MOD, PM_WKDEP);
-#endif
-#if 0
- /* INTC */
- DUMP_INTC_REG(INTC_MIR0, 0x0084);
- DUMP_INTC_REG(INTC_MIR1, 0x00a4);
- DUMP_INTC_REG(INTC_MIR2, 0x00c4);
-#endif
-#if 0
- DUMP_CM_MOD_REG(CORE_MOD, CM_FCLKEN1);
- DUMP_CM_MOD_REG(CORE_MOD, OMAP24XX_CM_FCLKEN2);
- DUMP_CM_MOD_REG(WKUP_MOD, CM_FCLKEN);
- DUMP_CM_MOD_REG(CORE_MOD, CM_ICLKEN1);
- DUMP_CM_MOD_REG(CORE_MOD, CM_ICLKEN2);
- DUMP_CM_MOD_REG(WKUP_MOD, CM_ICLKEN);
- DUMP_CM_MOD_REG(PLL_MOD, CM_CLKEN);
- DUMP_PRM_REG(OMAP24XX_PRCM_CLKEMUL_CTRL);
- DUMP_CM_MOD_REG(PLL_MOD, CM_AUTOIDLE);
- DUMP_PRM_MOD_REG(CORE_MOD, PM_PWSTST);
- DUMP_PRM_REG(OMAP24XX_PRCM_CLKSRC_CTRL);
-#endif
-#if 0
- /* DSP */
- DUMP_CM_MOD_REG(OMAP24XX_DSP_MOD, CM_FCLKEN);
- DUMP_CM_MOD_REG(OMAP24XX_DSP_MOD, CM_ICLKEN);
- DUMP_CM_MOD_REG(OMAP24XX_DSP_MOD, CM_IDLEST);
- DUMP_CM_MOD_REG(OMAP24XX_DSP_MOD, CM_AUTOIDLE);
- DUMP_CM_MOD_REG(OMAP24XX_DSP_MOD, CM_CLKSEL);
- DUMP_CM_MOD_REG(OMAP24XX_DSP_MOD, CM_CLKSTCTRL);
- DUMP_PRM_MOD_REG(OMAP24XX_DSP_MOD, RM_RSTCTRL);
- DUMP_PRM_MOD_REG(OMAP24XX_DSP_MOD, RM_RSTST);
- DUMP_PRM_MOD_REG(OMAP24XX_DSP_MOD, PM_PWSTCTRL);
- DUMP_PRM_MOD_REG(OMAP24XX_DSP_MOD, PM_PWSTST);
-#endif
- } else {
- DUMP_PRM_MOD_REG(CORE_MOD, PM_WKST1);
- DUMP_PRM_MOD_REG(CORE_MOD, OMAP24XX_PM_WKST2);
- DUMP_PRM_MOD_REG(WKUP_MOD, PM_WKST);
- DUMP_PRM_REG(OMAP24XX_PRCM_IRQSTATUS_MPU);
-#if 1
- DUMP_INTC_REG(INTC_PENDING_IRQ0, 0x0098);
- DUMP_INTC_REG(INTC_PENDING_IRQ1, 0x00b8);
- DUMP_INTC_REG(INTC_PENDING_IRQ2, 0x00d8);
-#endif
- }
-
- switch (mode) {
- case 0:
- s1 = "full";
- s2 = "retention";
- break;
- case 1:
- s1 = "MPU";
- s2 = "retention";
- break;
- case 2:
- s1 = "MPU";
- s2 = "idle";
- break;
- }
-
- if (!resume)
-#if defined(CONFIG_NO_IDLE_HZ) || defined(CONFIG_NO_HZ)
- pr_debug("--- Going to %s %s (next timer after %u ms)\n", s1,
- s2,
- jiffies_to_msecs(get_next_timer_interrupt(jiffies) -
- jiffies));
-#else
- pr_debug("--- Going to %s %s\n", s1, s2);
-#endif
- else
- pr_debug("--- Woke up (slept for %u.%03u ms)\n", us / 1000,
- us % 1000);
-
- for (i = 0; i < reg_count; i++)
- pr_debug("%-20s: 0x%08x\n", regs[i].name, regs[i].val);
-}
-
-#else
-static inline void serial_console_sleep(int enable) {}
-static inline void pm_init_serial_console(void) {}
-static inline void omap2_pm_dump(int mode, int resume, unsigned int us) {}
-static inline void serial_console_fclk_mask(u32 *f1, u32 *f2) {}
-
-#define omap2_pm_debug 0
-
-#endif
-
-static unsigned short enable_dyn_sleep = 0; /* disabled till drivers are fixed */
-
-static ssize_t idle_show(struct kobject *kobj, struct kobj_attribute *attr,
- char *buf)
-{
- return sprintf(buf, "%hu\n", enable_dyn_sleep);
-}
-
-static ssize_t idle_store(struct kobject *kobj, struct kobj_attribute *attr,
- const char *buf, size_t n)
-{
- unsigned short value;
- if (sscanf(buf, "%hu", &value) != 1 ||
- (value != 0 && value != 1)) {
- printk(KERN_ERR "idle_sleep_store: Invalid value\n");
- return -EINVAL;
- }
- enable_dyn_sleep = value;
- return n;
-}
-
-static struct kobj_attribute sleep_while_idle_attr =
- __ATTR(sleep_while_idle, 0644, idle_show, idle_store);
-
-static struct clk *osc_ck, *emul_ck;
-
-static int omap2_fclks_active(void)
-{
- u32 f1, f2;
-
- f1 = cm_read_mod_reg(CORE_MOD, CM_FCLKEN1);
- f2 = cm_read_mod_reg(CORE_MOD, OMAP24XX_CM_FCLKEN2);
- serial_console_fclk_mask(&f1, &f2);
- if (f1 | f2)
- return 1;
- return 0;
-}
-
-static int omap2_irq_pending(void)
-{
- u32 pending_reg = 0x480fe098;
- int i;
-
- for (i = 0; i < 4; i++) {
- if (omap_readl(pending_reg))
- return 1;
- pending_reg += 0x20;
- }
- return 0;
-}
-
-static atomic_t sleep_block = ATOMIC_INIT(0);
-
-void omap2_block_sleep(void)
-{
- atomic_inc(&sleep_block);
-}
-
-void omap2_allow_sleep(void)
-{
- int i;
-
- i = atomic_dec_return(&sleep_block);
- BUG_ON(i < 0);
-}
-
-static void omap2_enter_full_retention(void)
-{
- u32 l, sleep_time = 0;
-
- /* There is 1 reference hold for all children of the oscillator
- * clock, the following will remove it. If no one else uses the
- * oscillator itself it will be disabled if/when we enter retention
- * mode.
- */
- clk_disable(osc_ck);
-
- /* Clear old wake-up events */
- /* REVISIT: These write to reserved bits? */
- prm_write_mod_reg(0xffffffff, CORE_MOD, PM_WKST1);
- prm_write_mod_reg(0xffffffff, CORE_MOD, OMAP24XX_PM_WKST2);
- prm_write_mod_reg(0xffffffff, WKUP_MOD, PM_WKST);
-
- /* Try to enter retention */
- prm_write_mod_reg((0x01 << OMAP_POWERSTATE_SHIFT) | OMAP_LOGICRETSTATE,
- MPU_MOD, PM_PWSTCTRL);
-
- /* Workaround to kill USB */
- l = omap_ctrl_readl(OMAP2_CONTROL_DEVCONF0) | OMAP24XX_USBSTANDBYCTRL;
- omap_ctrl_writel(l, OMAP2_CONTROL_DEVCONF0);
-
- omap2_gpio_prepare_for_retention();
-
- if (omap2_pm_debug) {
- omap2_pm_dump(0, 0, 0);
- sleep_time = omap2_read_32k_sync_counter();
- }
-
- /* One last check for pending IRQs to avoid extra latency due
- * to sleeping unnecessarily. */
- if (omap2_irq_pending())
- goto no_sleep;
-
- serial_console_sleep(1);
- /* Jump to SRAM suspend code */
- omap2_sram_suspend(OMAP_SDRC_REGADDR(SDRC_DLLA_CTRL));
-no_sleep:
- serial_console_sleep(0);
-
- if (omap2_pm_debug) {
- unsigned long long tmp;
- u32 resume_time;
-
- resume_time = omap2_read_32k_sync_counter();
- tmp = resume_time - sleep_time;
- tmp *= 1000000;
- omap2_pm_dump(0, 1, tmp / 32768);
- }
- omap2_gpio_resume_after_retention();
-
- clk_enable(osc_ck);
-
- /* clear CORE wake-up events */
- prm_write_mod_reg(0xffffffff, CORE_MOD, PM_WKST1);
- prm_write_mod_reg(0xffffffff, CORE_MOD, OMAP24XX_PM_WKST2);
-
- /* wakeup domain events - bit 1: GPT1, bit5 GPIO */
- prm_clear_mod_reg_bits(0x4 | 0x1, WKUP_MOD, PM_WKST);
-
- /* MPU domain wake events */
- l = __raw_readl(OMAP24XX_PRCM_IRQSTATUS_MPU);
- if (l & 0x01)
- __raw_writel(0x01, OMAP24XX_PRCM_IRQSTATUS_MPU);
- if (l & 0x20)
- __raw_writel(0x20, OMAP24XX_PRCM_IRQSTATUS_MPU);
-
- /* Mask future PRCM-to-MPU interrupts */
- __raw_writel(0x0, OMAP24XX_PRCM_IRQSTATUS_MPU);
-}
-
-static int omap2_i2c_active(void)
-{
- u32 l;
-
- l = cm_read_mod_reg(CORE_MOD, CM_FCLKEN1);
- return l & (OMAP2420_EN_I2C2 | OMAP2420_EN_I2C1);
-}
-
-static int sti_console_enabled;
-
-static int omap2_allow_mpu_retention(void)
-{
- u32 l;
-
- if (atomic_read(&sleep_block))
- return 0;
-
- /* Check for MMC, UART2, UART1, McSPI2, McSPI1 and DSS1. */
- l = cm_read_mod_reg(CORE_MOD, CM_FCLKEN1);
- if (l & (OMAP2420_EN_MMC | OMAP24XX_EN_UART2 |
- OMAP24XX_EN_UART1 | OMAP24XX_EN_MCSPI2 |
- OMAP24XX_EN_MCSPI1 | OMAP24XX_EN_DSS1))
- return 0;
- /* Check for UART3. */
- l = cm_read_mod_reg(CORE_MOD, OMAP24XX_CM_FCLKEN2);
- if (l & OMAP24XX_EN_UART3)
- return 0;
- if (sti_console_enabled)
- return 0;
-
- return 1;
-}
-
-static void omap2_enter_mpu_retention(void)
-{
- u32 sleep_time = 0;
- int only_idle = 0;
-
- /* Putting MPU into the WFI state while a transfer is active
- * seems to cause the I2C block to timeout. Why? Good question. */
- if (omap2_i2c_active())
- return;
-
- /* The peripherals seem not to be able to wake up the MPU when
- * it is in retention mode. */
- if (omap2_allow_mpu_retention()) {
- /* REVISIT: These write to reserved bits? */
- prm_write_mod_reg(0xffffffff, CORE_MOD, PM_WKST1);
- prm_write_mod_reg(0xffffffff, CORE_MOD, OMAP24XX_PM_WKST2);
- prm_write_mod_reg(0xffffffff, WKUP_MOD, PM_WKST);
-
- /* Try to enter MPU retention */
- prm_write_mod_reg((0x01 << OMAP_POWERSTATE_SHIFT) |
- OMAP_LOGICRETSTATE,
- MPU_MOD, PM_PWSTCTRL);
- } else {
- /* Block MPU retention */
-
- prm_write_mod_reg(OMAP_LOGICRETSTATE, MPU_MOD, PM_PWSTCTRL);
- only_idle = 1;
- }
-
- if (omap2_pm_debug) {
- omap2_pm_dump(only_idle ? 2 : 1, 0, 0);
- sleep_time = omap2_read_32k_sync_counter();
- }
-
- omap2_sram_idle();
-
- if (omap2_pm_debug) {
- unsigned long long tmp;
- u32 resume_time;
-
- resume_time = omap2_read_32k_sync_counter();
- tmp = resume_time - sleep_time;
- tmp *= 1000000;
- omap2_pm_dump(only_idle ? 2 : 1, 1, tmp / 32768);
- }
-}
-
-static int omap2_can_sleep(void)
-{
- if (!enable_dyn_sleep)
- return 0;
- if (omap2_fclks_active())
- return 0;
- if (atomic_read(&sleep_block) > 0)
- return 0;
- if (clk_get_usecount(osc_ck) > 1)
- return 0;
- if (omap_dma_running())
- return 0;
-
- return 1;
-}
-
-static void omap2_pm_idle(void)
-{
- local_irq_disable();
- local_fiq_disable();
-
- if (!omap2_can_sleep()) {
- /* timer_dyn_reprogram() takes about 100-200 us to complete.
- * In some contexts (e.g. when waiting for a GPMC-SDRAM DMA
- * transfer to complete), the increased latency is too much.
- *
- * omap2_block_sleep() and omap2_allow_sleep() can be used
- * to indicate this.
- */
- if (atomic_read(&sleep_block) == 0) {
- timer_dyn_reprogram();
- if (omap2_irq_pending())
- goto out;
- }
- omap2_enter_mpu_retention();
- goto out;
- }
-
- /*
- * Since an interrupt may set up a timer, we don't want to
- * reprogram the hardware timer with interrupts enabled.
- * Re-enable interrupts only after returning from idle.
- */
- timer_dyn_reprogram();
-
- if (omap2_irq_pending())
- goto out;
-
- omap2_enter_full_retention();
-
-out:
- local_fiq_enable();
- local_irq_enable();
-}
-
-static int omap2_pm_prepare(void)
-{
- /* We cannot sleep in idle until we have resumed */
- saved_idle = pm_idle;
- pm_idle = NULL;
-
- return 0;
-}
-
-static int omap2_pm_suspend(void)
-{
- u32 wken_wkup, mir1;
-
- wken_wkup = prm_read_mod_reg(WKUP_MOD, PM_WKEN);
- prm_write_mod_reg(wken_wkup & ~OMAP24XX_EN_GPT1, WKUP_MOD, PM_WKEN);
-
- /* Mask GPT1 */
- mir1 = omap_readl(0x480fe0a4);
- omap_writel(1 << 5, 0x480fe0ac);
-
- omap2_enter_full_retention();
-
- omap_writel(mir1, 0x480fe0a4);
- prm_write_mod_reg(wken_wkup, WKUP_MOD, PM_WKEN);
-
- return 0;
-}
-
-static int omap2_pm_enter(suspend_state_t state)
-{
- int ret = 0;
-
- switch (state) {
- case PM_SUSPEND_STANDBY:
- case PM_SUSPEND_MEM:
- ret = omap2_pm_suspend();
- break;
- default:
- ret = -EINVAL;
- }
-
- return ret;
-}
-
-static void omap2_pm_finish(void)
-{
- pm_idle = saved_idle;
-}
-
-static struct platform_suspend_ops omap_pm_ops = {
- .prepare = omap2_pm_prepare,
- .enter = omap2_pm_enter,
- .finish = omap2_pm_finish,
- .valid = suspend_valid_only_mem,
-};
-
-static void __init prcm_setup_regs(void)
-{
- u32 l;
-
- /* Enable autoidle */
- __raw_writel(OMAP24XX_AUTOIDLE, OMAP24XX_PRCM_SYSCONFIG);
-
- /* Set all domain wakeup dependencies */
- prm_write_mod_reg(OMAP_EN_WKUP_MASK, MPU_MOD, PM_WKDEP);
- prm_write_mod_reg(0, OMAP24XX_DSP_MOD, PM_WKDEP);
- prm_write_mod_reg(0, GFX_MOD, PM_WKDEP);
- prm_write_mod_reg(0, CORE_MOD, PM_WKDEP);
- if (cpu_is_omap2430())
- prm_write_mod_reg(0, OMAP2430_MDM_MOD, PM_WKDEP);
-
- l = prm_read_mod_reg(CORE_MOD, PM_PWSTCTRL);
- /* Enable retention for all memory blocks */
- l |= OMAP24XX_MEM3RETSTATE | OMAP24XX_MEM2RETSTATE |
- OMAP24XX_MEM1RETSTATE;
-
- /* Set power state to RETENTION */
- l &= ~OMAP_POWERSTATE_MASK;
- l |= 0x01 << OMAP_POWERSTATE_SHIFT;
- prm_write_mod_reg(l, CORE_MOD, PM_PWSTCTRL);
-
- prm_write_mod_reg((0x01 << OMAP_POWERSTATE_SHIFT) |
- OMAP_LOGICRETSTATE,
- MPU_MOD, PM_PWSTCTRL);
-
- /* Power down DSP and GFX */
- prm_write_mod_reg(OMAP24XX_FORCESTATE | (0x3 << OMAP_POWERSTATE_SHIFT),
- OMAP24XX_DSP_MOD, PM_PWSTCTRL);
- prm_write_mod_reg(OMAP24XX_FORCESTATE | (0x3 << OMAP_POWERSTATE_SHIFT),
- GFX_MOD, PM_PWSTCTRL);
-
- /* Enable clock auto control for all domains */
- cm_write_mod_reg(OMAP24XX_AUTOSTATE_MPU_MASK, MPU_MOD, CM_CLKSTCTRL);
- cm_write_mod_reg(OMAP24XX_AUTOSTATE_DSS_MASK |
- OMAP24XX_AUTOSTATE_L4_MASK |
- OMAP24XX_AUTOSTATE_L3_MASK,
- CORE_MOD, CM_CLKSTCTRL);
- cm_write_mod_reg(OMAP24XX_AUTOSTATE_GFX_MASK, GFX_MOD, CM_CLKSTCTRL);
- cm_write_mod_reg(OMAP2420_AUTOSTATE_IVA_MASK |
- OMAP24XX_AUTOSTATE_DSP_MASK,
- OMAP24XX_DSP_MOD, CM_CLKSTCTRL);
-
- /* Enable clock autoidle for all domains */
- cm_write_mod_reg(OMAP24XX_AUTO_CAM |
- OMAP24XX_AUTO_MAILBOXES |
- OMAP24XX_AUTO_WDT4 |
- OMAP2420_AUTO_WDT3 |
- OMAP24XX_AUTO_MSPRO |
- OMAP2420_AUTO_MMC |
- OMAP24XX_AUTO_FAC |
- OMAP2420_AUTO_EAC |
- OMAP24XX_AUTO_HDQ |
- OMAP24XX_AUTO_UART2 |
- OMAP24XX_AUTO_UART1 |
- OMAP24XX_AUTO_I2C2 |
- OMAP24XX_AUTO_I2C1 |
- OMAP24XX_AUTO_MCSPI2 |
- OMAP24XX_AUTO_MCSPI1 |
- OMAP24XX_AUTO_MCBSP2 |
- OMAP24XX_AUTO_MCBSP1 |
- OMAP24XX_AUTO_GPT12 |
- OMAP24XX_AUTO_GPT11 |
- OMAP24XX_AUTO_GPT10 |
- OMAP24XX_AUTO_GPT9 |
- OMAP24XX_AUTO_GPT8 |
- OMAP24XX_AUTO_GPT7 |
- OMAP24XX_AUTO_GPT6 |
- OMAP24XX_AUTO_GPT5 |
- OMAP24XX_AUTO_GPT4 |
- OMAP24XX_AUTO_GPT3 |
- OMAP24XX_AUTO_GPT2 |
- OMAP2420_AUTO_VLYNQ |
- OMAP24XX_AUTO_DSS,
- CORE_MOD, CM_AUTOIDLE1);
- cm_write_mod_reg(OMAP24XX_AUTO_UART3 |
- OMAP24XX_AUTO_SSI |
- OMAP24XX_AUTO_USB,
- CORE_MOD, CM_AUTOIDLE2);
- cm_write_mod_reg(OMAP24XX_AUTO_SDRC |
- OMAP24XX_AUTO_GPMC |
- OMAP24XX_AUTO_SDMA,
- CORE_MOD, CM_AUTOIDLE3);
- cm_write_mod_reg(OMAP24XX_AUTO_PKA |
- OMAP24XX_AUTO_AES |
- OMAP24XX_AUTO_RNG |
- OMAP24XX_AUTO_SHA |
- OMAP24XX_AUTO_DES,
- CORE_MOD, OMAP24XX_CM_AUTOIDLE4);
-
- cm_write_mod_reg(OMAP2420_AUTO_DSP_IPI, OMAP24XX_DSP_MOD, CM_AUTOIDLE);
-
- /* Put DPLL and both APLLs into autoidle mode */
- cm_write_mod_reg((0x03 << OMAP24XX_AUTO_DPLL_SHIFT) |
- (0x03 << OMAP24XX_AUTO_96M_SHIFT) |
- (0x03 << OMAP24XX_AUTO_54M_SHIFT),
- PLL_MOD, CM_AUTOIDLE);
-
- cm_write_mod_reg(OMAP24XX_AUTO_OMAPCTRL |
- OMAP24XX_AUTO_WDT1 |
- OMAP24XX_AUTO_MPU_WDT |
- OMAP24XX_AUTO_GPIOS |
- OMAP24XX_AUTO_32KSYNC |
- OMAP24XX_AUTO_GPT1,
- WKUP_MOD, CM_AUTOIDLE);
-
- /* REVISIT: Configure number of 32 kHz clock cycles for sys_clk
- * stabilisation */
- __raw_writel(15 << OMAP_SETUP_TIME_SHIFT, OMAP24XX_PRCM_CLKSSETUP);
-
- /* Configure automatic voltage transition */
- __raw_writel(2 << OMAP_SETUP_TIME_SHIFT, OMAP24XX_PRCM_VOLTSETUP);
- __raw_writel(OMAP24XX_AUTO_EXTVOLT |
- (0x1 << OMAP24XX_SETOFF_LEVEL_SHIFT) |
- OMAP24XX_MEMRETCTRL |
- (0x1 << OMAP24XX_SETRET_LEVEL_SHIFT) |
- (0x0 << OMAP24XX_VOLT_LEVEL_SHIFT),
- OMAP24XX_PRCM_VOLTCTRL);
-
- /* Enable wake-up events */
- prm_write_mod_reg(OMAP24XX_EN_GPIOS | OMAP24XX_EN_GPT1,
- WKUP_MOD, PM_WKEN);
-}
-
-static int __init omap2_pm_init(void)
-{
- u32 l;
- int error;
-
- printk(KERN_INFO "Power Management for OMAP2 initializing\n");
- l = __raw_readl(OMAP24XX_PRCM_REVISION);
- printk(KERN_INFO "PRCM revision %d.%d\n", (l >> 4) & 0x0f, l & 0x0f);
-
- osc_ck = clk_get(NULL, "osc_ck");
- if (IS_ERR(osc_ck)) {
- printk(KERN_ERR "could not get osc_ck\n");
- return -ENODEV;
- }
-
- if (cpu_is_omap242x()) {
- emul_ck = clk_get(NULL, "emul_ck");
- if (IS_ERR(emul_ck)) {
- printk(KERN_ERR "could not get emul_ck\n");
- clk_put(osc_ck);
- return -ENODEV;
- }
- }
-
- prcm_setup_regs();
-
- pm_init_serial_console();
-
- /* Hack to prevent MPU retention when STI console is enabled. */
- {
- const struct omap_sti_console_config *sti;
-
- sti = omap_get_config(OMAP_TAG_STI_CONSOLE,
- struct omap_sti_console_config);
- if (sti != NULL && sti->enable)
- sti_console_enabled = 1;
- }
-
- /*
- * We copy the assembler sleep/wakeup routines to SRAM.
- * These routines need to be in SRAM as that's the only
- * memory the MPU can see when it wakes up.
- */
- omap2_sram_idle = omap_sram_push(omap24xx_idle_loop_suspend,
- omap24xx_idle_loop_suspend_sz);
-
- omap2_sram_suspend = omap_sram_push(omap24xx_cpu_suspend,
- omap24xx_cpu_suspend_sz);
-
- /* Patch in the correct register addresses for multiboot */
- omap_sram_patch_va(omap24xx_cpu_suspend, &omap2_ocs_sdrc_power,
- omap2_sram_suspend,
- OMAP_SDRC_REGADDR(SDRC_POWER));
- omap_sram_patch_va(omap24xx_cpu_suspend, &omap2_ocs_sdrc_dlla_ctrl,
- omap2_sram_suspend,
- OMAP_SDRC_REGADDR(SDRC_DLLA_CTRL));
-
- suspend_set_ops(&omap_pm_ops);
- pm_idle = omap2_pm_idle;
-
- error = sysfs_create_file(power_kobj, &sleep_while_idle_attr.attr);
- if (error)
- printk(KERN_ERR "sysfs_create_file failed: %d\n", error);
-
- return 0;
-}
-
-late_initcall(omap2_pm_init);
diff --git a/arch/arm/mach-omap2/pm24xx.c b/arch/arm/mach-omap2/pm24xx.c
new file mode 100644
index 0000000..b627fe5
--- /dev/null
+++ b/arch/arm/mach-omap2/pm24xx.c
@@ -0,0 +1,845 @@
+/*
+ * linux/arch/arm/mach-omap2/pm.c
+ *
+ * OMAP2 Power Management Routines
+ *
+ * Copyright (C) 2005 Texas Instruments, Inc.
+ * Copyright (C) 2006-2008 Nokia Corporation
+ *
+ * Written by:
+ * Richard Woodruff <r-woodruff2@ti.com>
+ * Tony Lindgren
+ * Juha Yrjola
+ * Amit Kucheria <amit.kucheria@nokia.com>
+ * Igor Stoppa <igor.stoppa@nokia.com>
+ *
+ * Based on pm.c for omap1
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/suspend.h>
+#include <linux/sched.h>
+#include <linux/proc_fs.h>
+#include <linux/interrupt.h>
+#include <linux/sysfs.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+
+#include <asm/atomic.h>
+#include <asm/mach/time.h>
+#include <asm/mach/irq.h>
+#include <asm/mach-types.h>
+
+#include <asm/arch/irqs.h>
+#include <asm/arch/clock.h>
+#include <asm/arch/sram.h>
+#include <asm/arch/control.h>
+#include <asm/arch/gpio.h>
+#include <asm/arch/pm.h>
+#include <asm/arch/mux.h>
+#include <asm/arch/dma.h>
+#include <asm/arch/board.h>
+
+#include "prm.h"
+#include "prm-regbits-24xx.h"
+#include "cm.h"
+#include "cm-regbits-24xx.h"
+#include "sdrc.h"
+
+/* These addrs are in assembly language code to be patched at runtime */
+extern void *omap2_ocs_sdrc_power;
+extern void *omap2_ocs_sdrc_dlla_ctrl;
+
+static void (*omap2_sram_idle)(void);
+static void (*omap2_sram_suspend)(void __iomem *dllctrl);
+static void (*saved_idle)(void);
+
+static u32 omap2_read_32k_sync_counter(void)
+{
+ return omap_readl(OMAP2_32KSYNCT_BASE + 0x0010);
+}
+
+#ifdef CONFIG_PM_DEBUG
+int omap2_pm_debug = 0;
+
+static int serial_console_clock_disabled;
+static int serial_console_uart;
+static unsigned int serial_console_next_disable;
+
+static struct clk *console_iclk, *console_fclk;
+
+static void serial_console_kick(void)
+{
+ serial_console_next_disable = omap2_read_32k_sync_counter();
+ /* Keep the clocks on for 4 secs */
+ serial_console_next_disable += 4 * 32768;
+}
+
+static void serial_wait_tx(void)
+{
+ static const unsigned long uart_bases[3] = {
+ 0x4806a000, 0x4806c000, 0x4806e000
+ };
+ unsigned long lsr_reg;
+ int looped = 0;
+
+ /* Wait for TX FIFO and THR to get empty */
+ lsr_reg = IO_ADDRESS(uart_bases[serial_console_uart - 1] + (5 << 2));
+ while ((__raw_readb(lsr_reg) & 0x60) != 0x60)
+ looped = 1;
+ if (looped)
+ serial_console_kick();
+}
+
+static void serial_console_fclk_mask(u32 *f1, u32 *f2)
+{
+ switch (serial_console_uart) {
+ case 1:
+ *f1 &= ~(1 << 21);
+ break;
+ case 2:
+ *f1 &= ~(1 << 22);
+ break;
+ case 3:
+ *f2 &= ~(1 << 2);
+ break;
+ }
+}
+
+static void serial_console_sleep(int enable)
+{
+ if (console_iclk == NULL || console_fclk == NULL)
+ return;
+
+ if (enable) {
+ BUG_ON(serial_console_clock_disabled);
+ if (clk_get_usecount(console_fclk) == 0)
+ return;
+ if ((int) serial_console_next_disable -
+ (int) omap2_read_32k_sync_counter() >= 0)
+ return;
+ serial_wait_tx();
+ clk_disable(console_iclk);
+ clk_disable(console_fclk);
+ serial_console_clock_disabled = 1;
+ } else {
+ int serial_wakeup = 0;
+ u32 l;
+
+ switch (serial_console_uart) {
+ case 1:
+ l = prm_read_mod_reg(CORE_MOD, PM_WKST1);
+ if (l & OMAP24XX_ST_UART1)
+ serial_wakeup = 1;
+ break;
+ case 2:
+ l = prm_read_mod_reg(CORE_MOD, PM_WKST1);
+ if (l & OMAP24XX_ST_UART2)
+ serial_wakeup = 1;
+ break;
+ case 3:
+ l = prm_read_mod_reg(CORE_MOD, OMAP24XX_PM_WKST2);
+ if (l & OMAP24XX_ST_UART3)
+ serial_wakeup = 1;
+ break;
+ }
+ if (serial_wakeup)
+ serial_console_kick();
+ if (!serial_console_clock_disabled)
+ return;
+ clk_enable(console_iclk);
+ clk_enable(console_fclk);
+ serial_console_clock_disabled = 0;
+ }
+}
+
+static void pm_init_serial_console(void)
+{
+ const struct omap_serial_console_config *conf;
+ char name[16];
+
+ conf = omap_get_config(OMAP_TAG_SERIAL_CONSOLE,
+ struct omap_serial_console_config);
+ if (conf == NULL)
+ return;
+ if (conf->console_uart > 3 || conf->console_uart < 1)
+ return;
+ serial_console_uart = conf->console_uart;
+ sprintf(name, "uart%d_fck", conf->console_uart);
+ console_fclk = clk_get(NULL, name);
+ if (IS_ERR(console_fclk))
+ console_fclk = NULL;
+ name[6] = 'i';
+ console_iclk = clk_get(NULL, name);
+ if (IS_ERR(console_fclk))
+ console_iclk = NULL;
+ if (console_fclk == NULL || console_iclk == NULL) {
+ serial_console_uart = 0;
+ return;
+ }
+ switch (serial_console_uart) {
+ case 1:
+ prm_set_mod_reg_bits(OMAP24XX_ST_UART1, CORE_MOD, PM_WKEN1);
+ break;
+ case 2:
+ prm_set_mod_reg_bits(OMAP24XX_ST_UART2, CORE_MOD, PM_WKEN1);
+ break;
+ case 3:
+ prm_set_mod_reg_bits(OMAP24XX_ST_UART3, CORE_MOD,
+ OMAP24XX_PM_WKEN2);
+ break;
+ }
+}
+
+#define DUMP_PRM_MOD_REG(mod, reg) \
+ regs[reg_count].name = #mod "." #reg; \
+ regs[reg_count++].val = prm_read_mod_reg(mod, reg)
+#define DUMP_CM_MOD_REG(mod, reg) \
+ regs[reg_count].name = #mod "." #reg; \
+ regs[reg_count++].val = cm_read_mod_reg(mod, reg)
+#define DUMP_PRM_REG(reg) \
+ regs[reg_count].name = #reg; \
+ regs[reg_count++].val = __raw_readl(reg)
+#define DUMP_CM_REG(reg) \
+ regs[reg_count].name = #reg; \
+ regs[reg_count++].val = __raw_readl(reg)
+#define DUMP_INTC_REG(reg, off) \
+ regs[reg_count].name = #reg; \
+ regs[reg_count++].val = __raw_readl(IO_ADDRESS(0x480fe000 + (off)))
+
+static void omap2_pm_dump(int mode, int resume, unsigned int us)
+{
+ struct reg {
+ const char *name;
+ u32 val;
+ } regs[32];
+ int reg_count = 0, i;
+ const char *s1 = NULL, *s2 = NULL;
+
+ if (!resume) {
+#if 0
+ /* MPU */
+ DUMP_PRM_REG(OMAP24XX_PRCM_IRQENABLE_MPU);
+ DUMP_CM_MOD_REG(MPU_MOD, CM_CLKSTCTRL);
+ DUMP_PRM_MOD_REG(MPU_MOD, PM_PWSTCTRL);
+ DUMP_PRM_MOD_REG(MPU_MOD, PM_PWSTST);
+ DUMP_PRM_MOD_REG(MPU_MOD, PM_WKDEP);
+#endif
+#if 0
+ /* INTC */
+ DUMP_INTC_REG(INTC_MIR0, 0x0084);
+ DUMP_INTC_REG(INTC_MIR1, 0x00a4);
+ DUMP_INTC_REG(INTC_MIR2, 0x00c4);
+#endif
+#if 0
+ DUMP_CM_MOD_REG(CORE_MOD, CM_FCLKEN1);
+ DUMP_CM_MOD_REG(CORE_MOD, OMAP24XX_CM_FCLKEN2);
+ DUMP_CM_MOD_REG(WKUP_MOD, CM_FCLKEN);
+ DUMP_CM_MOD_REG(CORE_MOD, CM_ICLKEN1);
+ DUMP_CM_MOD_REG(CORE_MOD, CM_ICLKEN2);
+ DUMP_CM_MOD_REG(WKUP_MOD, CM_ICLKEN);
+ DUMP_CM_MOD_REG(PLL_MOD, CM_CLKEN);
+ DUMP_PRM_REG(OMAP24XX_PRCM_CLKEMUL_CTRL);
+ DUMP_CM_MOD_REG(PLL_MOD, CM_AUTOIDLE);
+ DUMP_PRM_MOD_REG(CORE_MOD, PM_PWSTST);
+ DUMP_PRM_REG(OMAP24XX_PRCM_CLKSRC_CTRL);
+#endif
+#if 0
+ /* DSP */
+ DUMP_CM_MOD_REG(OMAP24XX_DSP_MOD, CM_FCLKEN);
+ DUMP_CM_MOD_REG(OMAP24XX_DSP_MOD, CM_ICLKEN);
+ DUMP_CM_MOD_REG(OMAP24XX_DSP_MOD, CM_IDLEST);
+ DUMP_CM_MOD_REG(OMAP24XX_DSP_MOD, CM_AUTOIDLE);
+ DUMP_CM_MOD_REG(OMAP24XX_DSP_MOD, CM_CLKSEL);
+ DUMP_CM_MOD_REG(OMAP24XX_DSP_MOD, CM_CLKSTCTRL);
+ DUMP_PRM_MOD_REG(OMAP24XX_DSP_MOD, RM_RSTCTRL);
+ DUMP_PRM_MOD_REG(OMAP24XX_DSP_MOD, RM_RSTST);
+ DUMP_PRM_MOD_REG(OMAP24XX_DSP_MOD, PM_PWSTCTRL);
+ DUMP_PRM_MOD_REG(OMAP24XX_DSP_MOD, PM_PWSTST);
+#endif
+ } else {
+ DUMP_PRM_MOD_REG(CORE_MOD, PM_WKST1);
+ DUMP_PRM_MOD_REG(CORE_MOD, OMAP24XX_PM_WKST2);
+ DUMP_PRM_MOD_REG(WKUP_MOD, PM_WKST);
+ DUMP_PRM_REG(OMAP24XX_PRCM_IRQSTATUS_MPU);
+#if 1
+ DUMP_INTC_REG(INTC_PENDING_IRQ0, 0x0098);
+ DUMP_INTC_REG(INTC_PENDING_IRQ1, 0x00b8);
+ DUMP_INTC_REG(INTC_PENDING_IRQ2, 0x00d8);
+#endif
+ }
+
+ switch (mode) {
+ case 0:
+ s1 = "full";
+ s2 = "retention";
+ break;
+ case 1:
+ s1 = "MPU";
+ s2 = "retention";
+ break;
+ case 2:
+ s1 = "MPU";
+ s2 = "idle";
+ break;
+ }
+
+ if (!resume)
+#if defined(CONFIG_NO_IDLE_HZ) || defined(CONFIG_NO_HZ)
+ pr_debug("--- Going to %s %s (next timer after %u ms)\n", s1,
+ s2,
+ jiffies_to_msecs(get_next_timer_interrupt(jiffies) -
+ jiffies));
+#else
+ pr_debug("--- Going to %s %s\n", s1, s2);
+#endif
+ else
+ pr_debug("--- Woke up (slept for %u.%03u ms)\n", us / 1000,
+ us % 1000);
+
+ for (i = 0; i < reg_count; i++)
+ pr_debug("%-20s: 0x%08x\n", regs[i].name, regs[i].val);
+}
+
+#else
+static inline void serial_console_sleep(int enable) {}
+static inline void pm_init_serial_console(void) {}
+static inline void omap2_pm_dump(int mode, int resume, unsigned int us) {}
+static inline void serial_console_fclk_mask(u32 *f1, u32 *f2) {}
+
+#define omap2_pm_debug 0
+
+#endif
+
+static unsigned short enable_dyn_sleep = 0; /* disabled till drivers are fixed */
+
+static ssize_t idle_show(struct kobject *kobj, struct kobj_attribute *attr,
+ char *buf)
+{
+ return sprintf(buf, "%hu\n", enable_dyn_sleep);
+}
+
+static ssize_t idle_store(struct kobject *kobj, struct kobj_attribute *attr,
+ const char *buf, size_t n)
+{
+ unsigned short value;
+ if (sscanf(buf, "%hu", &value) != 1 ||
+ (value != 0 && value != 1)) {
+ printk(KERN_ERR "idle_sleep_store: Invalid value\n");
+ return -EINVAL;
+ }
+ enable_dyn_sleep = value;
+ return n;
+}
+
+static struct kobj_attribute sleep_while_idle_attr =
+ __ATTR(sleep_while_idle, 0644, idle_show, idle_store);
+
+static struct clk *osc_ck, *emul_ck;
+
+static int omap2_fclks_active(void)
+{
+ u32 f1, f2;
+
+ f1 = cm_read_mod_reg(CORE_MOD, CM_FCLKEN1);
+ f2 = cm_read_mod_reg(CORE_MOD, OMAP24XX_CM_FCLKEN2);
+ serial_console_fclk_mask(&f1, &f2);
+ if (f1 | f2)
+ return 1;
+ return 0;
+}
+
+static int omap2_irq_pending(void)
+{
+ u32 pending_reg = 0x480fe098;
+ int i;
+
+ for (i = 0; i < 4; i++) {
+ if (omap_readl(pending_reg))
+ return 1;
+ pending_reg += 0x20;
+ }
+ return 0;
+}
+
+static atomic_t sleep_block = ATOMIC_INIT(0);
+
+void omap2_block_sleep(void)
+{
+ atomic_inc(&sleep_block);
+}
+
+void omap2_allow_sleep(void)
+{
+ int i;
+
+ i = atomic_dec_return(&sleep_block);
+ BUG_ON(i < 0);
+}
+
+static void omap2_enter_full_retention(void)
+{
+ u32 l, sleep_time = 0;
+
+ /* There is 1 reference hold for all children of the oscillator
+ * clock, the following will remove it. If no one else uses the
+ * oscillator itself it will be disabled if/when we enter retention
+ * mode.
+ */
+ clk_disable(osc_ck);
+
+ /* Clear old wake-up events */
+ /* REVISIT: These write to reserved bits? */
+ prm_write_mod_reg(0xffffffff, CORE_MOD, PM_WKST1);
+ prm_write_mod_reg(0xffffffff, CORE_MOD, OMAP24XX_PM_WKST2);
+ prm_write_mod_reg(0xffffffff, WKUP_MOD, PM_WKST);
+
+ /* Try to enter retention */
+ prm_write_mod_reg((0x01 << OMAP_POWERSTATE_SHIFT) | OMAP_LOGICRETSTATE,
+ MPU_MOD, PM_PWSTCTRL);
+
+ /* Workaround to kill USB */
+ l = omap_ctrl_readl(OMAP2_CONTROL_DEVCONF0) | OMAP24XX_USBSTANDBYCTRL;
+ omap_ctrl_writel(l, OMAP2_CONTROL_DEVCONF0);
+
+ omap2_gpio_prepare_for_retention();
+
+ if (omap2_pm_debug) {
+ omap2_pm_dump(0, 0, 0);
+ sleep_time = omap2_read_32k_sync_counter();
+ }
+
+ /* One last check for pending IRQs to avoid extra latency due
+ * to sleeping unnecessarily. */
+ if (omap2_irq_pending())
+ goto no_sleep;
+
+ serial_console_sleep(1);
+ /* Jump to SRAM suspend code */
+ omap2_sram_suspend(OMAP_SDRC_REGADDR(SDRC_DLLA_CTRL));
+no_sleep:
+ serial_console_sleep(0);
+
+ if (omap2_pm_debug) {
+ unsigned long long tmp;
+ u32 resume_time;
+
+ resume_time = omap2_read_32k_sync_counter();
+ tmp = resume_time - sleep_time;
+ tmp *= 1000000;
+ omap2_pm_dump(0, 1, tmp / 32768);
+ }
+ omap2_gpio_resume_after_retention();
+
+ clk_enable(osc_ck);
+
+ /* clear CORE wake-up events */
+ prm_write_mod_reg(0xffffffff, CORE_MOD, PM_WKST1);
+ prm_write_mod_reg(0xffffffff, CORE_MOD, OMAP24XX_PM_WKST2);
+
+ /* wakeup domain events - bit 1: GPT1, bit5 GPIO */
+ prm_clear_mod_reg_bits(0x4 | 0x1, WKUP_MOD, PM_WKST);
+
+ /* MPU domain wake events */
+ l = __raw_readl(OMAP24XX_PRCM_IRQSTATUS_MPU);
+ if (l & 0x01)
+ __raw_writel(0x01, OMAP24XX_PRCM_IRQSTATUS_MPU);
+ if (l & 0x20)
+ __raw_writel(0x20, OMAP24XX_PRCM_IRQSTATUS_MPU);
+
+ /* Mask future PRCM-to-MPU interrupts */
+ __raw_writel(0x0, OMAP24XX_PRCM_IRQSTATUS_MPU);
+}
+
+static int omap2_i2c_active(void)
+{
+ u32 l;
+
+ l = cm_read_mod_reg(CORE_MOD, CM_FCLKEN1);
+ return l & (OMAP2420_EN_I2C2 | OMAP2420_EN_I2C1);
+}
+
+static int sti_console_enabled;
+
+static int omap2_allow_mpu_retention(void)
+{
+ u32 l;
+
+ if (atomic_read(&sleep_block))
+ return 0;
+
+ /* Check for MMC, UART2, UART1, McSPI2, McSPI1 and DSS1. */
+ l = cm_read_mod_reg(CORE_MOD, CM_FCLKEN1);
+ if (l & (OMAP2420_EN_MMC | OMAP24XX_EN_UART2 |
+ OMAP24XX_EN_UART1 | OMAP24XX_EN_MCSPI2 |
+ OMAP24XX_EN_MCSPI1 | OMAP24XX_EN_DSS1))
+ return 0;
+ /* Check for UART3. */
+ l = cm_read_mod_reg(CORE_MOD, OMAP24XX_CM_FCLKEN2);
+ if (l & OMAP24XX_EN_UART3)
+ return 0;
+ if (sti_console_enabled)
+ return 0;
+
+ return 1;
+}
+
+static void omap2_enter_mpu_retention(void)
+{
+ u32 sleep_time = 0;
+ int only_idle = 0;
+
+ /* Putting MPU into the WFI state while a transfer is active
+ * seems to cause the I2C block to timeout. Why? Good question. */
+ if (omap2_i2c_active())
+ return;
+
+ /* The peripherals seem not to be able to wake up the MPU when
+ * it is in retention mode. */
+ if (omap2_allow_mpu_retention()) {
+ /* REVISIT: These write to reserved bits? */
+ prm_write_mod_reg(0xffffffff, CORE_MOD, PM_WKST1);
+ prm_write_mod_reg(0xffffffff, CORE_MOD, OMAP24XX_PM_WKST2);
+ prm_write_mod_reg(0xffffffff, WKUP_MOD, PM_WKST);
+
+ /* Try to enter MPU retention */
+ prm_write_mod_reg((0x01 << OMAP_POWERSTATE_SHIFT) |
+ OMAP_LOGICRETSTATE,
+ MPU_MOD, PM_PWSTCTRL);
+ } else {
+ /* Block MPU retention */
+
+ prm_write_mod_reg(OMAP_LOGICRETSTATE, MPU_MOD, PM_PWSTCTRL);
+ only_idle = 1;
+ }
+
+ if (omap2_pm_debug) {
+ omap2_pm_dump(only_idle ? 2 : 1, 0, 0);
+ sleep_time = omap2_read_32k_sync_counter();
+ }
+
+ omap2_sram_idle();
+
+ if (omap2_pm_debug) {
+ unsigned long long tmp;
+ u32 resume_time;
+
+ resume_time = omap2_read_32k_sync_counter();
+ tmp = resume_time - sleep_time;
+ tmp *= 1000000;
+ omap2_pm_dump(only_idle ? 2 : 1, 1, tmp / 32768);
+ }
+}
+
+static int omap2_can_sleep(void)
+{
+ if (!enable_dyn_sleep)
+ return 0;
+ if (omap2_fclks_active())
+ return 0;
+ if (atomic_read(&sleep_block) > 0)
+ return 0;
+ if (clk_get_usecount(osc_ck) > 1)
+ return 0;
+ if (omap_dma_running())
+ return 0;
+
+ return 1;
+}
+
+static void omap2_pm_idle(void)
+{
+ local_irq_disable();
+ local_fiq_disable();
+
+ if (!omap2_can_sleep()) {
+ /* timer_dyn_reprogram() takes about 100-200 us to complete.
+ * In some contexts (e.g. when waiting for a GPMC-SDRAM DMA
+ * transfer to complete), the increased latency is too much.
+ *
+ * omap2_block_sleep() and omap2_allow_sleep() can be used
+ * to indicate this.
+ */
+ if (atomic_read(&sleep_block) == 0) {
+ timer_dyn_reprogram();
+ if (omap2_irq_pending())
+ goto out;
+ }
+ omap2_enter_mpu_retention();
+ goto out;
+ }
+
+ /*
+ * Since an interrupt may set up a timer, we don't want to
+ * reprogram the hardware timer with interrupts enabled.
+ * Re-enable interrupts only after returning from idle.
+ */
+ timer_dyn_reprogram();
+
+ if (omap2_irq_pending())
+ goto out;
+
+ omap2_enter_full_retention();
+
+out:
+ local_fiq_enable();
+ local_irq_enable();
+}
+
+static int omap2_pm_prepare(void)
+{
+ /* We cannot sleep in idle until we have resumed */
+ saved_idle = pm_idle;
+ pm_idle = NULL;
+
+ return 0;
+}
+
+static int omap2_pm_suspend(void)
+{
+ u32 wken_wkup, mir1;
+
+ wken_wkup = prm_read_mod_reg(WKUP_MOD, PM_WKEN);
+ prm_write_mod_reg(wken_wkup & ~OMAP24XX_EN_GPT1, WKUP_MOD, PM_WKEN);
+
+ /* Mask GPT1 */
+ mir1 = omap_readl(0x480fe0a4);
+ omap_writel(1 << 5, 0x480fe0ac);
+
+ omap2_enter_full_retention();
+
+ omap_writel(mir1, 0x480fe0a4);
+ prm_write_mod_reg(wken_wkup, WKUP_MOD, PM_WKEN);
+
+ return 0;
+}
+
+static int omap2_pm_enter(suspend_state_t state)
+{
+ int ret = 0;
+
+ switch (state) {
+ case PM_SUSPEND_STANDBY:
+ case PM_SUSPEND_MEM:
+ ret = omap2_pm_suspend();
+ break;
+ default:
+ ret = -EINVAL;
+ }
+
+ return ret;
+}
+
+static void omap2_pm_finish(void)
+{
+ pm_idle = saved_idle;
+}
+
+static struct platform_suspend_ops omap_pm_ops = {
+ .prepare = omap2_pm_prepare,
+ .enter = omap2_pm_enter,
+ .finish = omap2_pm_finish,
+ .valid = suspend_valid_only_mem,
+};
+
+static void __init prcm_setup_regs(void)
+{
+ u32 l;
+
+ /* Enable autoidle */
+ __raw_writel(OMAP24XX_AUTOIDLE, OMAP24XX_PRCM_SYSCONFIG);
+
+ /* Set all domain wakeup dependencies */
+ prm_write_mod_reg(OMAP_EN_WKUP_MASK, MPU_MOD, PM_WKDEP);
+ prm_write_mod_reg(0, OMAP24XX_DSP_MOD, PM_WKDEP);
+ prm_write_mod_reg(0, GFX_MOD, PM_WKDEP);
+ prm_write_mod_reg(0, CORE_MOD, PM_WKDEP);
+ if (cpu_is_omap2430())
+ prm_write_mod_reg(0, OMAP2430_MDM_MOD, PM_WKDEP);
+
+ l = prm_read_mod_reg(CORE_MOD, PM_PWSTCTRL);
+ /* Enable retention for all memory blocks */
+ l |= OMAP24XX_MEM3RETSTATE | OMAP24XX_MEM2RETSTATE |
+ OMAP24XX_MEM1RETSTATE;
+
+ /* Set power state to RETENTION */
+ l &= ~OMAP_POWERSTATE_MASK;
+ l |= 0x01 << OMAP_POWERSTATE_SHIFT;
+ prm_write_mod_reg(l, CORE_MOD, PM_PWSTCTRL);
+
+ prm_write_mod_reg((0x01 << OMAP_POWERSTATE_SHIFT) |
+ OMAP_LOGICRETSTATE,
+ MPU_MOD, PM_PWSTCTRL);
+
+ /* Power down DSP and GFX */
+ prm_write_mod_reg(OMAP24XX_FORCESTATE | (0x3 << OMAP_POWERSTATE_SHIFT),
+ OMAP24XX_DSP_MOD, PM_PWSTCTRL);
+ prm_write_mod_reg(OMAP24XX_FORCESTATE | (0x3 << OMAP_POWERSTATE_SHIFT),
+ GFX_MOD, PM_PWSTCTRL);
+
+ /* Enable clock auto control for all domains */
+ cm_write_mod_reg(OMAP24XX_AUTOSTATE_MPU_MASK, MPU_MOD, CM_CLKSTCTRL);
+ cm_write_mod_reg(OMAP24XX_AUTOSTATE_DSS_MASK |
+ OMAP24XX_AUTOSTATE_L4_MASK |
+ OMAP24XX_AUTOSTATE_L3_MASK,
+ CORE_MOD, CM_CLKSTCTRL);
+ cm_write_mod_reg(OMAP24XX_AUTOSTATE_GFX_MASK, GFX_MOD, CM_CLKSTCTRL);
+ cm_write_mod_reg(OMAP2420_AUTOSTATE_IVA_MASK |
+ OMAP24XX_AUTOSTATE_DSP_MASK,
+ OMAP24XX_DSP_MOD, CM_CLKSTCTRL);
+
+ /* Enable clock autoidle for all domains */
+ cm_write_mod_reg(OMAP24XX_AUTO_CAM |
+ OMAP24XX_AUTO_MAILBOXES |
+ OMAP24XX_AUTO_WDT4 |
+ OMAP2420_AUTO_WDT3 |
+ OMAP24XX_AUTO_MSPRO |
+ OMAP2420_AUTO_MMC |
+ OMAP24XX_AUTO_FAC |
+ OMAP2420_AUTO_EAC |
+ OMAP24XX_AUTO_HDQ |
+ OMAP24XX_AUTO_UART2 |
+ OMAP24XX_AUTO_UART1 |
+ OMAP24XX_AUTO_I2C2 |
+ OMAP24XX_AUTO_I2C1 |
+ OMAP24XX_AUTO_MCSPI2 |
+ OMAP24XX_AUTO_MCSPI1 |
+ OMAP24XX_AUTO_MCBSP2 |
+ OMAP24XX_AUTO_MCBSP1 |
+ OMAP24XX_AUTO_GPT12 |
+ OMAP24XX_AUTO_GPT11 |
+ OMAP24XX_AUTO_GPT10 |
+ OMAP24XX_AUTO_GPT9 |
+ OMAP24XX_AUTO_GPT8 |
+ OMAP24XX_AUTO_GPT7 |
+ OMAP24XX_AUTO_GPT6 |
+ OMAP24XX_AUTO_GPT5 |
+ OMAP24XX_AUTO_GPT4 |
+ OMAP24XX_AUTO_GPT3 |
+ OMAP24XX_AUTO_GPT2 |
+ OMAP2420_AUTO_VLYNQ |
+ OMAP24XX_AUTO_DSS,
+ CORE_MOD, CM_AUTOIDLE1);
+ cm_write_mod_reg(OMAP24XX_AUTO_UART3 |
+ OMAP24XX_AUTO_SSI |
+ OMAP24XX_AUTO_USB,
+ CORE_MOD, CM_AUTOIDLE2);
+ cm_write_mod_reg(OMAP24XX_AUTO_SDRC |
+ OMAP24XX_AUTO_GPMC |
+ OMAP24XX_AUTO_SDMA,
+ CORE_MOD, CM_AUTOIDLE3);
+ cm_write_mod_reg(OMAP24XX_AUTO_PKA |
+ OMAP24XX_AUTO_AES |
+ OMAP24XX_AUTO_RNG |
+ OMAP24XX_AUTO_SHA |
+ OMAP24XX_AUTO_DES,
+ CORE_MOD, OMAP24XX_CM_AUTOIDLE4);
+
+ cm_write_mod_reg(OMAP2420_AUTO_DSP_IPI, OMAP24XX_DSP_MOD, CM_AUTOIDLE);
+
+ /* Put DPLL and both APLLs into autoidle mode */
+ cm_write_mod_reg((0x03 << OMAP24XX_AUTO_DPLL_SHIFT) |
+ (0x03 << OMAP24XX_AUTO_96M_SHIFT) |
+ (0x03 << OMAP24XX_AUTO_54M_SHIFT),
+ PLL_MOD, CM_AUTOIDLE);
+
+ cm_write_mod_reg(OMAP24XX_AUTO_OMAPCTRL |
+ OMAP24XX_AUTO_WDT1 |
+ OMAP24XX_AUTO_MPU_WDT |
+ OMAP24XX_AUTO_GPIOS |
+ OMAP24XX_AUTO_32KSYNC |
+ OMAP24XX_AUTO_GPT1,
+ WKUP_MOD, CM_AUTOIDLE);
+
+ /* REVISIT: Configure number of 32 kHz clock cycles for sys_clk
+ * stabilisation */
+ __raw_writel(15 << OMAP_SETUP_TIME_SHIFT, OMAP24XX_PRCM_CLKSSETUP);
+
+ /* Configure automatic voltage transition */
+ __raw_writel(2 << OMAP_SETUP_TIME_SHIFT, OMAP24XX_PRCM_VOLTSETUP);
+ __raw_writel(OMAP24XX_AUTO_EXTVOLT |
+ (0x1 << OMAP24XX_SETOFF_LEVEL_SHIFT) |
+ OMAP24XX_MEMRETCTRL |
+ (0x1 << OMAP24XX_SETRET_LEVEL_SHIFT) |
+ (0x0 << OMAP24XX_VOLT_LEVEL_SHIFT),
+ OMAP24XX_PRCM_VOLTCTRL);
+
+ /* Enable wake-up events */
+ prm_write_mod_reg(OMAP24XX_EN_GPIOS | OMAP24XX_EN_GPT1,
+ WKUP_MOD, PM_WKEN);
+}
+
+static int __init omap2_pm_init(void)
+{
+ u32 l;
+ int error;
+
+ printk(KERN_INFO "Power Management for OMAP2 initializing\n");
+ l = __raw_readl(OMAP24XX_PRCM_REVISION);
+ printk(KERN_INFO "PRCM revision %d.%d\n", (l >> 4) & 0x0f, l & 0x0f);
+
+ osc_ck = clk_get(NULL, "osc_ck");
+ if (IS_ERR(osc_ck)) {
+ printk(KERN_ERR "could not get osc_ck\n");
+ return -ENODEV;
+ }
+
+ if (cpu_is_omap242x()) {
+ emul_ck = clk_get(NULL, "emul_ck");
+ if (IS_ERR(emul_ck)) {
+ printk(KERN_ERR "could not get emul_ck\n");
+ clk_put(osc_ck);
+ return -ENODEV;
+ }
+ }
+
+ prcm_setup_regs();
+
+ pm_init_serial_console();
+
+ /* Hack to prevent MPU retention when STI console is enabled. */
+ {
+ const struct omap_sti_console_config *sti;
+
+ sti = omap_get_config(OMAP_TAG_STI_CONSOLE,
+ struct omap_sti_console_config);
+ if (sti != NULL && sti->enable)
+ sti_console_enabled = 1;
+ }
+
+ /*
+ * We copy the assembler sleep/wakeup routines to SRAM.
+ * These routines need to be in SRAM as that's the only
+ * memory the MPU can see when it wakes up.
+ */
+ omap2_sram_idle = omap_sram_push(omap24xx_idle_loop_suspend,
+ omap24xx_idle_loop_suspend_sz);
+
+ omap2_sram_suspend = omap_sram_push(omap24xx_cpu_suspend,
+ omap24xx_cpu_suspend_sz);
+
+ /* Patch in the correct register addresses for multiboot */
+ omap_sram_patch_va(omap24xx_cpu_suspend, &omap2_ocs_sdrc_power,
+ omap2_sram_suspend,
+ OMAP_SDRC_REGADDR(SDRC_POWER));
+ omap_sram_patch_va(omap24xx_cpu_suspend, &omap2_ocs_sdrc_dlla_ctrl,
+ omap2_sram_suspend,
+ OMAP_SDRC_REGADDR(SDRC_DLLA_CTRL));
+
+ suspend_set_ops(&omap_pm_ops);
+ pm_idle = omap2_pm_idle;
+
+ error = sysfs_create_file(power_kobj, &sleep_while_idle_attr.attr);
+ if (error)
+ printk(KERN_ERR "sysfs_create_file failed: %d\n", error);
+
+ return 0;
+}
+
+late_initcall(omap2_pm_init);
diff --git a/arch/arm/mach-omap2/sleep.S b/arch/arm/mach-omap2/sleep.S
deleted file mode 100644
index 3e0a7dc..0000000
--- a/arch/arm/mach-omap2/sleep.S
+++ /dev/null
@@ -1,133 +0,0 @@
-/*
- * linux/arch/arm/mach-omap2/sleep.S
- *
- * (C) Copyright 2004
- * Texas Instruments, <www.ti.com>
- * Richard Woodruff <r-woodruff2@ti.com>
- *
- * (C) Copyright 2006 Nokia Corporation
- * Fixed idle loop sleep
- * Igor Stoppa <igor.stoppa@nokia.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR /PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
- * MA 02111-1307 USA
- */
-
-#include <linux/linkage.h>
-#include <linux/poison.h> /* for SRAM_VA_MAGIC */
-#include <asm/assembler.h>
-#include <asm/arch/io.h>
-#include <asm/arch/pm.h>
-
-#include <asm/arch/omap24xx.h>
-
-/* First address of reserved address space? apparently valid for OMAP2 & 3 */
-#define A_SDRC0_V (0xC0000000)
-
- .text
-
-/*
- * Forces OMAP into idle state
- *
- * omap24xx_idle_loop_suspend() - This bit of code just executes the WFI
- * for normal idles.
- *
- * Note: This code get's copied to internal SRAM at boot. When the OMAP
- * wakes up it continues execution at the point it went to sleep.
- */
-ENTRY(omap24xx_idle_loop_suspend)
- stmfd sp!, {r0, lr} @ save registers on stack
- mov r0, #0x0 @ clear for mrc call
- mcr p15, 0, r0, c7, c0, 4 @ wait for interrupt
- ldmfd sp!, {r0, pc} @ restore regs and return
-
-ENTRY(omap24xx_idle_loop_suspend_sz)
- .word . - omap24xx_idle_loop_suspend
-
-/*
- * omap242x_cpu_suspend() - Forces OMAP into deep sleep state by completing
- * SDRC shutdown then ARM shutdown. Upon wake MPU is back on so just restore
- * SDRC.
- *
- * Input:
- * R0 : DLL ctrl value pre-Sleep
- *
- * The if the DPLL is going to AutoIdle. It seems like the DPLL may be back on
- * when we get called, but the DLL probably isn't. We will wait a bit more in
- * case the DPLL isn't quite there yet. The code will wait on DLL for DDR even
- * if in unlocked mode.
- *
- * For less than 242x-ES2.2 upon wake from a sleep mode where the external
- * oscillator was stopped, a timing bug exists where a non-stabilized 12MHz
- * clock can pass into the PRCM can cause problems at DSP and IVA.
- * To work around this the code will switch to the 32kHz source prior to sleep.
- * Post sleep we will shift back to using the DPLL. Apparently,
- * CM_IDLEST_CLKGEN does not reflect the full clock change so you need to wait
- * 3x12MHz + 3x32kHz clocks for a full switch.
- *
- * The DLL load value is not kept in RETENTION or OFF. It needs to be restored
- * at wake
- */
-ENTRY(omap24xx_cpu_suspend)
- stmfd sp!, {r0 - r12, lr} @ save registers on stack
- mov r3, #0x0 @ clear for mrc call
- mcr p15, 0, r3, c7, c10, 4 @ memory barrier, hope SDR/DDR finished
- nop
- nop
- ldr r3, omap2_ocs_sdrc_power @ addr of sdrc power
- ldr r4, [r3] @ value of sdrc power
- orr r4, r4, #0x40 @ enable self refresh on idle req
- mov r5, #0x2000 @ set delay (DPLL relock + DLL relock)
- str r4, [r3] @ make it so
- mov r2, #0
- nop
- mcr p15, 0, r2, c7, c0, 4 @ wait for interrupt
- nop
-loop:
- subs r5, r5, #0x1 @ awake, wait just a bit
- bne loop
-
- /* The DPLL has on before we take the DDR out of self refresh */
- bic r4, r4, #0x40 @ now clear self refresh bit.
- str r4, [r3] @ put vlaue back.
- ldr r4, A_SDRC0 @ make a clock happen
- ldr r4, [r4]
- nop @ start auto refresh only after clk ok
- movs r0, r0 @ see if DDR or SDR
- ldrne r1, omap2_ocs_sdrc_dlla_ctrl @ get addr of DLL ctrl
- strne r0, [r1] @ rewrite DLLA to force DLL reload
- addne r1, r1, #0x8 @ move to DLLB
- strne r0, [r1] @ rewrite DLLB to force DLL reload
-
- mov r5, #0x1000
-loop2:
- subs r5, r5, #0x1
- bne loop2
- /* resume*/
- ldmfd sp!, {r0 - r12, pc} @ restore regs and return
-
- .globl omap2_ocs_sdrc_power
- .globl omap2_ocs_sdrc_dlla_ctrl
-
-omap2_ocs_sdrc_power:
- .word SRAM_VA_MAGIC
-A_SDRC0:
- .word A_SDRC0_V
-omap2_ocs_sdrc_dlla_ctrl:
- .word SRAM_VA_MAGIC
-
-ENTRY(omap24xx_cpu_suspend_sz)
- .word . - omap24xx_cpu_suspend
-
diff --git a/arch/arm/mach-omap2/sleep24xx.S b/arch/arm/mach-omap2/sleep24xx.S
new file mode 100644
index 0000000..3e0a7dc
--- /dev/null
+++ b/arch/arm/mach-omap2/sleep24xx.S
@@ -0,0 +1,133 @@
+/*
+ * linux/arch/arm/mach-omap2/sleep.S
+ *
+ * (C) Copyright 2004
+ * Texas Instruments, <www.ti.com>
+ * Richard Woodruff <r-woodruff2@ti.com>
+ *
+ * (C) Copyright 2006 Nokia Corporation
+ * Fixed idle loop sleep
+ * Igor Stoppa <igor.stoppa@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR /PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <linux/linkage.h>
+#include <linux/poison.h> /* for SRAM_VA_MAGIC */
+#include <asm/assembler.h>
+#include <asm/arch/io.h>
+#include <asm/arch/pm.h>
+
+#include <asm/arch/omap24xx.h>
+
+/* First address of reserved address space? apparently valid for OMAP2 & 3 */
+#define A_SDRC0_V (0xC0000000)
+
+ .text
+
+/*
+ * Forces OMAP into idle state
+ *
+ * omap24xx_idle_loop_suspend() - This bit of code just executes the WFI
+ * for normal idles.
+ *
+ * Note: This code get's copied to internal SRAM at boot. When the OMAP
+ * wakes up it continues execution at the point it went to sleep.
+ */
+ENTRY(omap24xx_idle_loop_suspend)
+ stmfd sp!, {r0, lr} @ save registers on stack
+ mov r0, #0x0 @ clear for mrc call
+ mcr p15, 0, r0, c7, c0, 4 @ wait for interrupt
+ ldmfd sp!, {r0, pc} @ restore regs and return
+
+ENTRY(omap24xx_idle_loop_suspend_sz)
+ .word . - omap24xx_idle_loop_suspend
+
+/*
+ * omap242x_cpu_suspend() - Forces OMAP into deep sleep state by completing
+ * SDRC shutdown then ARM shutdown. Upon wake MPU is back on so just restore
+ * SDRC.
+ *
+ * Input:
+ * R0 : DLL ctrl value pre-Sleep
+ *
+ * The if the DPLL is going to AutoIdle. It seems like the DPLL may be back on
+ * when we get called, but the DLL probably isn't. We will wait a bit more in
+ * case the DPLL isn't quite there yet. The code will wait on DLL for DDR even
+ * if in unlocked mode.
+ *
+ * For less than 242x-ES2.2 upon wake from a sleep mode where the external
+ * oscillator was stopped, a timing bug exists where a non-stabilized 12MHz
+ * clock can pass into the PRCM can cause problems at DSP and IVA.
+ * To work around this the code will switch to the 32kHz source prior to sleep.
+ * Post sleep we will shift back to using the DPLL. Apparently,
+ * CM_IDLEST_CLKGEN does not reflect the full clock change so you need to wait
+ * 3x12MHz + 3x32kHz clocks for a full switch.
+ *
+ * The DLL load value is not kept in RETENTION or OFF. It needs to be restored
+ * at wake
+ */
+ENTRY(omap24xx_cpu_suspend)
+ stmfd sp!, {r0 - r12, lr} @ save registers on stack
+ mov r3, #0x0 @ clear for mrc call
+ mcr p15, 0, r3, c7, c10, 4 @ memory barrier, hope SDR/DDR finished
+ nop
+ nop
+ ldr r3, omap2_ocs_sdrc_power @ addr of sdrc power
+ ldr r4, [r3] @ value of sdrc power
+ orr r4, r4, #0x40 @ enable self refresh on idle req
+ mov r5, #0x2000 @ set delay (DPLL relock + DLL relock)
+ str r4, [r3] @ make it so
+ mov r2, #0
+ nop
+ mcr p15, 0, r2, c7, c0, 4 @ wait for interrupt
+ nop
+loop:
+ subs r5, r5, #0x1 @ awake, wait just a bit
+ bne loop
+
+ /* The DPLL has on before we take the DDR out of self refresh */
+ bic r4, r4, #0x40 @ now clear self refresh bit.
+ str r4, [r3] @ put vlaue back.
+ ldr r4, A_SDRC0 @ make a clock happen
+ ldr r4, [r4]
+ nop @ start auto refresh only after clk ok
+ movs r0, r0 @ see if DDR or SDR
+ ldrne r1, omap2_ocs_sdrc_dlla_ctrl @ get addr of DLL ctrl
+ strne r0, [r1] @ rewrite DLLA to force DLL reload
+ addne r1, r1, #0x8 @ move to DLLB
+ strne r0, [r1] @ rewrite DLLB to force DLL reload
+
+ mov r5, #0x1000
+loop2:
+ subs r5, r5, #0x1
+ bne loop2
+ /* resume*/
+ ldmfd sp!, {r0 - r12, pc} @ restore regs and return
+
+ .globl omap2_ocs_sdrc_power
+ .globl omap2_ocs_sdrc_dlla_ctrl
+
+omap2_ocs_sdrc_power:
+ .word SRAM_VA_MAGIC
+A_SDRC0:
+ .word A_SDRC0_V
+omap2_ocs_sdrc_dlla_ctrl:
+ .word SRAM_VA_MAGIC
+
+ENTRY(omap24xx_cpu_suspend_sz)
+ .word . - omap24xx_cpu_suspend
+
--
1.5.5
^ permalink raw reply related [flat|nested] 16+ messages in thread* [PATCH 2/9] 24XX: PM: Move debugging related code to pm-debug.c
2008-05-16 10:53 [PATCH 0/9] 34XX: PM: Support for retention on suspend and idle Högander Jouni
2008-05-16 10:57 ` [PATCH 1/9] 24XX: PM: Move pm.c to pm24xx.c and sleep.S to sleep24xx.S Jouni Hogander
@ 2008-05-16 10:57 ` Jouni Hogander
2008-05-16 10:57 ` [PATCH 3/9] PM: Add pm.c file for omap2 and omap3 common code Jouni Hogander
` (7 subsequent siblings)
9 siblings, 0 replies; 16+ messages in thread
From: Jouni Hogander @ 2008-05-16 10:57 UTC (permalink / raw)
To: linux-omap; +Cc: jouni.hogander
Move debugging and serial console handling to pm-debug.c.
Signed-off-by: Jouni Hogander <jouni.hogander@nokia.com>
---
arch/arm/mach-omap2/Makefile | 2 +
arch/arm/mach-omap2/pm-debug.c | 275 ++++++++++++++++++++++++++++++++++++++++
arch/arm/mach-omap2/pm.h | 31 +++++
arch/arm/mach-omap2/pm24xx.c | 258 +-------------------------------------
4 files changed, 309 insertions(+), 257 deletions(-)
create mode 100644 arch/arm/mach-omap2/pm-debug.c
create mode 100644 arch/arm/mach-omap2/pm.h
diff --git a/arch/arm/mach-omap2/Makefile b/arch/arm/mach-omap2/Makefile
index 462f685..8f80382 100644
--- a/arch/arm/mach-omap2/Makefile
+++ b/arch/arm/mach-omap2/Makefile
@@ -16,6 +16,8 @@ ifeq ($(CONFIG_ARCH_OMAP2),y)
obj-$(CONFIG_PM) += pm24xx.o sleep24xx.o
endif
+obj-$(CONFIG_PM_DEBUG) += pm-debug.o
+
# Clock framework
obj-$(CONFIG_ARCH_OMAP2) += clock24xx.o
obj-$(CONFIG_ARCH_OMAP3) += clock34xx.o
diff --git a/arch/arm/mach-omap2/pm-debug.c b/arch/arm/mach-omap2/pm-debug.c
new file mode 100644
index 0000000..361e52b
--- /dev/null
+++ b/arch/arm/mach-omap2/pm-debug.c
@@ -0,0 +1,275 @@
+/*
+ * linux/arch/arm/mach-omap2/pm_debug.c
+ *
+ * OMAP Power Management debug routines
+ *
+ * Copyright (C) 2005 Texas Instruments, Inc.
+ * Copyright (C) 2006-2008 Nokia Corporation
+ *
+ * Written by:
+ * Richard Woodruff <r-woodruff2@ti.com>
+ * Tony Lindgren
+ * Juha Yrjola
+ * Amit Kucheria <amit.kucheria@nokia.com>
+ * Igor Stoppa <igor.stoppa@nokia.com>
+ * Jouni Hogander
+ *
+ * Based on pm.c for omap2
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/clk.h>
+#include <linux/err.h>
+
+#include <asm/arch/clock.h>
+#include <asm/arch/board.h>
+
+#include "prm.h"
+#include "pm.h"
+
+#ifdef CONFIG_PM_DEBUG
+int omap2_pm_debug = 0;
+
+static int serial_console_clock_disabled;
+static int serial_console_uart;
+static unsigned int serial_console_next_disable;
+
+static struct clk *console_iclk, *console_fclk;
+
+static void serial_console_kick(void)
+{
+ serial_console_next_disable = omap2_read_32k_sync_counter();
+ /* Keep the clocks on for 4 secs */
+ serial_console_next_disable += 4 * 32768;
+}
+
+static void serial_wait_tx(void)
+{
+ static const unsigned long uart_bases[3] = {
+ 0x4806a000, 0x4806c000, 0x4806e000
+ };
+ unsigned long lsr_reg;
+ int looped = 0;
+
+ /* Wait for TX FIFO and THR to get empty */
+ lsr_reg = IO_ADDRESS(uart_bases[serial_console_uart - 1] + (5 << 2));
+ while ((__raw_readb(lsr_reg) & 0x60) != 0x60)
+ looped = 1;
+ if (looped)
+ serial_console_kick();
+}
+
+u32 omap2_read_32k_sync_counter(void)
+{
+ return omap_readl(OMAP2_32KSYNCT_BASE + 0x0010);
+}
+
+void serial_console_fclk_mask(u32 *f1, u32 *f2)
+{
+ switch (serial_console_uart) {
+ case 1:
+ *f1 &= ~(1 << 21);
+ break;
+ case 2:
+ *f1 &= ~(1 << 22);
+ break;
+ case 3:
+ *f2 &= ~(1 << 2);
+ break;
+ }
+}
+
+void serial_console_sleep(int enable)
+{
+ if (console_iclk == NULL || console_fclk == NULL)
+ return;
+
+ if (enable) {
+ BUG_ON(serial_console_clock_disabled);
+ if (clk_get_usecount(console_fclk) == 0)
+ return;
+ if ((int) serial_console_next_disable - (int) omap2_read_32k_sync_counter() >= 0)
+ return;
+ serial_wait_tx();
+ clk_disable(console_iclk);
+ clk_disable(console_fclk);
+ serial_console_clock_disabled = 1;
+ } else {
+ int serial_wakeup = 0;
+ u32 l;
+
+ switch (serial_console_uart) {
+ case 1:
+ l = prm_read_mod_reg(CORE_MOD, PM_WKST1);
+ if (l & OMAP24XX_ST_UART1)
+ serial_wakeup = 1;
+ break;
+ case 2:
+ l = prm_read_mod_reg(CORE_MOD, PM_WKST1);
+ if (l & OMAP24XX_ST_UART2)
+ serial_wakeup = 1;
+ break;
+ case 3:
+ l = prm_read_mod_reg(CORE_MOD, OMAP24XX_PM_WKST2);
+ if (l & OMAP24XX_ST_UART3)
+ serial_wakeup = 1;
+ break;
+ }
+ if (serial_wakeup)
+ serial_console_kick();
+ if (!serial_console_clock_disabled)
+ return;
+ clk_enable(console_iclk);
+ clk_enable(console_fclk);
+ serial_console_clock_disabled = 0;
+ }
+}
+
+void pm_init_serial_console(void)
+{
+ const struct omap_serial_console_config *conf;
+ char name[16];
+
+ conf = omap_get_config(OMAP_TAG_SERIAL_CONSOLE,
+ struct omap_serial_console_config);
+ if (conf == NULL)
+ return;
+ if (conf->console_uart > 3 || conf->console_uart < 1)
+ return;
+ serial_console_uart = conf->console_uart;
+ sprintf(name, "uart%d_fck", conf->console_uart);
+ console_fclk = clk_get(NULL, name);
+ if (IS_ERR(console_fclk))
+ console_fclk = NULL;
+ name[6] = 'i';
+ console_iclk = clk_get(NULL, name);
+ if (IS_ERR(console_fclk))
+ console_iclk = NULL;
+ if (console_fclk == NULL || console_iclk == NULL) {
+ serial_console_uart = 0;
+ return;
+ }
+ switch (serial_console_uart) {
+ case 1:
+ prm_set_mod_reg_bits(OMAP24XX_ST_UART1, CORE_MOD, PM_WKEN1);
+ break;
+ case 2:
+ prm_set_mod_reg_bits(OMAP24XX_ST_UART2, CORE_MOD, PM_WKEN1);
+ break;
+ case 3:
+ prm_set_mod_reg_bits(OMAP24XX_ST_UART3, CORE_MOD, OMAP24XX_PM_WKEN2);
+ break;
+ }
+}
+
+#define DUMP_PRM_MOD_REG(mod, reg) \
+ regs[reg_count].name = #mod "." #reg; \
+ regs[reg_count++].val = prm_read_mod_reg(mod, reg)
+#define DUMP_CM_MOD_REG(mod, reg) \
+ regs[reg_count].name = #mod "." #reg; \
+ regs[reg_count++].val = cm_read_mod_reg(mod, reg)
+#define DUMP_PRM_REG(reg) \
+ regs[reg_count].name = #reg; \
+ regs[reg_count++].val = __raw_readl(reg)
+#define DUMP_CM_REG(reg) \
+ regs[reg_count].name = #reg; \
+ regs[reg_count++].val = __raw_readl(reg)
+#define DUMP_INTC_REG(reg, off) \
+ regs[reg_count].name = #reg; \
+ regs[reg_count++].val = __raw_readl(IO_ADDRESS(0x480fe000 + (off)))
+
+void omap2_pm_dump(int mode, int resume, unsigned int us)
+{
+ struct reg {
+ const char *name;
+ u32 val;
+ } regs[32];
+ int reg_count = 0, i;
+ const char *s1 = NULL, *s2 = NULL;
+
+ if (!resume) {
+#if 0
+ /* MPU */
+ DUMP_PRM_REG(OMAP24XX_PRCM_IRQENABLE_MPU);
+ DUMP_CM_MOD_REG(MPU_MOD, CM_CLKSTCTRL);
+ DUMP_PRM_MOD_REG(MPU_MOD, PM_PWSTCTRL);
+ DUMP_PRM_MOD_REG(MPU_MOD, PM_PWSTST);
+ DUMP_PRM_MOD_REG(MPU_MOD, PM_WKDEP);
+#endif
+#if 0
+ /* INTC */
+ DUMP_INTC_REG(INTC_MIR0, 0x0084);
+ DUMP_INTC_REG(INTC_MIR1, 0x00a4);
+ DUMP_INTC_REG(INTC_MIR2, 0x00c4);
+#endif
+#if 0
+ DUMP_CM_MOD_REG(CORE_MOD, CM_FCLKEN1);
+ DUMP_CM_MOD_REG(CORE_MOD, OMAP24XX_CM_FCLKEN2);
+ DUMP_CM_MOD_REG(WKUP_MOD, CM_FCLKEN);
+ DUMP_CM_MOD_REG(CORE_MOD, CM_ICLKEN1);
+ DUMP_CM_MOD_REG(CORE_MOD, CM_ICLKEN2);
+ DUMP_CM_MOD_REG(WKUP_MOD, CM_ICLKEN);
+ DUMP_CM_MOD_REG(PLL_MOD, CM_CLKEN);
+ DUMP_PRM_REG(OMAP24XX_PRCM_CLKEMUL_CTRL);
+ DUMP_CM_MOD_REG(PLL_MOD, CM_AUTOIDLE);
+ DUMP_PRM_MOD_REG(CORE_MOD, PM_PWSTST);
+ DUMP_PRM_REG(OMAP24XX_PRCM_CLKSRC_CTRL);
+#endif
+#if 0
+ /* DSP */
+ DUMP_CM_MOD_REG(OMAP24XX_DSP_MOD, CM_FCLKEN);
+ DUMP_CM_MOD_REG(OMAP24XX_DSP_MOD, CM_ICLKEN);
+ DUMP_CM_MOD_REG(OMAP24XX_DSP_MOD, CM_IDLEST);
+ DUMP_CM_MOD_REG(OMAP24XX_DSP_MOD, CM_AUTOIDLE);
+ DUMP_CM_MOD_REG(OMAP24XX_DSP_MOD, CM_CLKSEL);
+ DUMP_CM_MOD_REG(OMAP24XX_DSP_MOD, CM_CLKSTCTRL);
+ DUMP_PRM_MOD_REG(OMAP24XX_DSP_MOD, RM_RSTCTRL);
+ DUMP_PRM_MOD_REG(OMAP24XX_DSP_MOD, RM_RSTST);
+ DUMP_PRM_MOD_REG(OMAP24XX_DSP_MOD, PM_PWSTCTRL);
+ DUMP_PRM_MOD_REG(OMAP24XX_DSP_MOD, PM_PWSTST);
+#endif
+ } else {
+ DUMP_PRM_MOD_REG(CORE_MOD, PM_WKST1);
+ DUMP_PRM_MOD_REG(CORE_MOD, OMAP24XX_PM_WKST2);
+ DUMP_PRM_MOD_REG(WKUP_MOD, PM_WKST);
+ DUMP_PRM_REG(OMAP24XX_PRCM_IRQSTATUS_MPU);
+#if 1
+ DUMP_INTC_REG(INTC_PENDING_IRQ0, 0x0098);
+ DUMP_INTC_REG(INTC_PENDING_IRQ1, 0x00b8);
+ DUMP_INTC_REG(INTC_PENDING_IRQ2, 0x00d8);
+#endif
+ }
+
+ switch (mode) {
+ case 0:
+ s1 = "full";
+ s2 = "retention";
+ break;
+ case 1:
+ s1 = "MPU";
+ s2 = "retention";
+ break;
+ case 2:
+ s1 = "MPU";
+ s2 = "idle";
+ break;
+ }
+
+ if (!resume)
+#if defined(CONFIG_NO_IDLE_HZ) || defined(CONFIG_NO_HZ)
+ printk("--- Going to %s %s (next timer after %u ms)\n", s1, s2,
+ jiffies_to_msecs(get_next_timer_interrupt(jiffies) -
+ jiffies));
+#else
+ printk("--- Going to %s %s\n", s1, s2);
+#endif
+ else
+ printk("--- Woke up (slept for %u.%03u ms)\n", us / 1000, us % 1000);
+ for (i = 0; i < reg_count; i++)
+ printk("%-20s: 0x%08x\n", regs[i].name, regs[i].val);
+}
+
+#endif
diff --git a/arch/arm/mach-omap2/pm.h b/arch/arm/mach-omap2/pm.h
new file mode 100644
index 0000000..541bf90
--- /dev/null
+++ b/arch/arm/mach-omap2/pm.h
@@ -0,0 +1,31 @@
+#ifndef __ARCH_ARM_MACH_OMAP2_PM_H
+#define __ARCH_ARM_MACH_OMAP2_PM_H
+/*
+ * linux/arch/arm/mach-omap2/pm.h
+ *
+ * OMAP Power Management Routines
+ *
+ * Copyright (C) 2008 Nokia Corporation
+ * Jouni Hogander
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifdef CONFIG_PM_DEBUG
+extern u32 omap2_read_32k_sync_counter(void);
+extern void omap2_pm_dump(int mode, int resume, unsigned int us);
+extern void serial_console_fclk_mask(u32 *f1, u32 *f2);
+extern void pm_init_serial_console(void);
+extern void serial_console_sleep(int enable);
+extern int omap2_pm_debug;
+#else
+#define omap2_read_32k_sync_counter() 0;
+#define serial_console_sleep(enable) do; while(0)
+#define pm_init_serial_console() do; while(0)
+#define omap2_pm_dump(mode,resume,us) do; while(0)
+#define serial_console_fclk_mask(f1,f2) do; while(0)
+#define omap2_pm_debug 0
+#endif /* CONFIG_PM_DEBUG */
+#endif
diff --git a/arch/arm/mach-omap2/pm24xx.c b/arch/arm/mach-omap2/pm24xx.c
index b627fe5..593f629 100644
--- a/arch/arm/mach-omap2/pm24xx.c
+++ b/arch/arm/mach-omap2/pm24xx.c
@@ -51,6 +51,7 @@
#include "cm.h"
#include "cm-regbits-24xx.h"
#include "sdrc.h"
+#include "pm.h"
/* These addrs are in assembly language code to be patched at runtime */
extern void *omap2_ocs_sdrc_power;
@@ -60,263 +61,6 @@ static void (*omap2_sram_idle)(void);
static void (*omap2_sram_suspend)(void __iomem *dllctrl);
static void (*saved_idle)(void);
-static u32 omap2_read_32k_sync_counter(void)
-{
- return omap_readl(OMAP2_32KSYNCT_BASE + 0x0010);
-}
-
-#ifdef CONFIG_PM_DEBUG
-int omap2_pm_debug = 0;
-
-static int serial_console_clock_disabled;
-static int serial_console_uart;
-static unsigned int serial_console_next_disable;
-
-static struct clk *console_iclk, *console_fclk;
-
-static void serial_console_kick(void)
-{
- serial_console_next_disable = omap2_read_32k_sync_counter();
- /* Keep the clocks on for 4 secs */
- serial_console_next_disable += 4 * 32768;
-}
-
-static void serial_wait_tx(void)
-{
- static const unsigned long uart_bases[3] = {
- 0x4806a000, 0x4806c000, 0x4806e000
- };
- unsigned long lsr_reg;
- int looped = 0;
-
- /* Wait for TX FIFO and THR to get empty */
- lsr_reg = IO_ADDRESS(uart_bases[serial_console_uart - 1] + (5 << 2));
- while ((__raw_readb(lsr_reg) & 0x60) != 0x60)
- looped = 1;
- if (looped)
- serial_console_kick();
-}
-
-static void serial_console_fclk_mask(u32 *f1, u32 *f2)
-{
- switch (serial_console_uart) {
- case 1:
- *f1 &= ~(1 << 21);
- break;
- case 2:
- *f1 &= ~(1 << 22);
- break;
- case 3:
- *f2 &= ~(1 << 2);
- break;
- }
-}
-
-static void serial_console_sleep(int enable)
-{
- if (console_iclk == NULL || console_fclk == NULL)
- return;
-
- if (enable) {
- BUG_ON(serial_console_clock_disabled);
- if (clk_get_usecount(console_fclk) == 0)
- return;
- if ((int) serial_console_next_disable -
- (int) omap2_read_32k_sync_counter() >= 0)
- return;
- serial_wait_tx();
- clk_disable(console_iclk);
- clk_disable(console_fclk);
- serial_console_clock_disabled = 1;
- } else {
- int serial_wakeup = 0;
- u32 l;
-
- switch (serial_console_uart) {
- case 1:
- l = prm_read_mod_reg(CORE_MOD, PM_WKST1);
- if (l & OMAP24XX_ST_UART1)
- serial_wakeup = 1;
- break;
- case 2:
- l = prm_read_mod_reg(CORE_MOD, PM_WKST1);
- if (l & OMAP24XX_ST_UART2)
- serial_wakeup = 1;
- break;
- case 3:
- l = prm_read_mod_reg(CORE_MOD, OMAP24XX_PM_WKST2);
- if (l & OMAP24XX_ST_UART3)
- serial_wakeup = 1;
- break;
- }
- if (serial_wakeup)
- serial_console_kick();
- if (!serial_console_clock_disabled)
- return;
- clk_enable(console_iclk);
- clk_enable(console_fclk);
- serial_console_clock_disabled = 0;
- }
-}
-
-static void pm_init_serial_console(void)
-{
- const struct omap_serial_console_config *conf;
- char name[16];
-
- conf = omap_get_config(OMAP_TAG_SERIAL_CONSOLE,
- struct omap_serial_console_config);
- if (conf == NULL)
- return;
- if (conf->console_uart > 3 || conf->console_uart < 1)
- return;
- serial_console_uart = conf->console_uart;
- sprintf(name, "uart%d_fck", conf->console_uart);
- console_fclk = clk_get(NULL, name);
- if (IS_ERR(console_fclk))
- console_fclk = NULL;
- name[6] = 'i';
- console_iclk = clk_get(NULL, name);
- if (IS_ERR(console_fclk))
- console_iclk = NULL;
- if (console_fclk == NULL || console_iclk == NULL) {
- serial_console_uart = 0;
- return;
- }
- switch (serial_console_uart) {
- case 1:
- prm_set_mod_reg_bits(OMAP24XX_ST_UART1, CORE_MOD, PM_WKEN1);
- break;
- case 2:
- prm_set_mod_reg_bits(OMAP24XX_ST_UART2, CORE_MOD, PM_WKEN1);
- break;
- case 3:
- prm_set_mod_reg_bits(OMAP24XX_ST_UART3, CORE_MOD,
- OMAP24XX_PM_WKEN2);
- break;
- }
-}
-
-#define DUMP_PRM_MOD_REG(mod, reg) \
- regs[reg_count].name = #mod "." #reg; \
- regs[reg_count++].val = prm_read_mod_reg(mod, reg)
-#define DUMP_CM_MOD_REG(mod, reg) \
- regs[reg_count].name = #mod "." #reg; \
- regs[reg_count++].val = cm_read_mod_reg(mod, reg)
-#define DUMP_PRM_REG(reg) \
- regs[reg_count].name = #reg; \
- regs[reg_count++].val = __raw_readl(reg)
-#define DUMP_CM_REG(reg) \
- regs[reg_count].name = #reg; \
- regs[reg_count++].val = __raw_readl(reg)
-#define DUMP_INTC_REG(reg, off) \
- regs[reg_count].name = #reg; \
- regs[reg_count++].val = __raw_readl(IO_ADDRESS(0x480fe000 + (off)))
-
-static void omap2_pm_dump(int mode, int resume, unsigned int us)
-{
- struct reg {
- const char *name;
- u32 val;
- } regs[32];
- int reg_count = 0, i;
- const char *s1 = NULL, *s2 = NULL;
-
- if (!resume) {
-#if 0
- /* MPU */
- DUMP_PRM_REG(OMAP24XX_PRCM_IRQENABLE_MPU);
- DUMP_CM_MOD_REG(MPU_MOD, CM_CLKSTCTRL);
- DUMP_PRM_MOD_REG(MPU_MOD, PM_PWSTCTRL);
- DUMP_PRM_MOD_REG(MPU_MOD, PM_PWSTST);
- DUMP_PRM_MOD_REG(MPU_MOD, PM_WKDEP);
-#endif
-#if 0
- /* INTC */
- DUMP_INTC_REG(INTC_MIR0, 0x0084);
- DUMP_INTC_REG(INTC_MIR1, 0x00a4);
- DUMP_INTC_REG(INTC_MIR2, 0x00c4);
-#endif
-#if 0
- DUMP_CM_MOD_REG(CORE_MOD, CM_FCLKEN1);
- DUMP_CM_MOD_REG(CORE_MOD, OMAP24XX_CM_FCLKEN2);
- DUMP_CM_MOD_REG(WKUP_MOD, CM_FCLKEN);
- DUMP_CM_MOD_REG(CORE_MOD, CM_ICLKEN1);
- DUMP_CM_MOD_REG(CORE_MOD, CM_ICLKEN2);
- DUMP_CM_MOD_REG(WKUP_MOD, CM_ICLKEN);
- DUMP_CM_MOD_REG(PLL_MOD, CM_CLKEN);
- DUMP_PRM_REG(OMAP24XX_PRCM_CLKEMUL_CTRL);
- DUMP_CM_MOD_REG(PLL_MOD, CM_AUTOIDLE);
- DUMP_PRM_MOD_REG(CORE_MOD, PM_PWSTST);
- DUMP_PRM_REG(OMAP24XX_PRCM_CLKSRC_CTRL);
-#endif
-#if 0
- /* DSP */
- DUMP_CM_MOD_REG(OMAP24XX_DSP_MOD, CM_FCLKEN);
- DUMP_CM_MOD_REG(OMAP24XX_DSP_MOD, CM_ICLKEN);
- DUMP_CM_MOD_REG(OMAP24XX_DSP_MOD, CM_IDLEST);
- DUMP_CM_MOD_REG(OMAP24XX_DSP_MOD, CM_AUTOIDLE);
- DUMP_CM_MOD_REG(OMAP24XX_DSP_MOD, CM_CLKSEL);
- DUMP_CM_MOD_REG(OMAP24XX_DSP_MOD, CM_CLKSTCTRL);
- DUMP_PRM_MOD_REG(OMAP24XX_DSP_MOD, RM_RSTCTRL);
- DUMP_PRM_MOD_REG(OMAP24XX_DSP_MOD, RM_RSTST);
- DUMP_PRM_MOD_REG(OMAP24XX_DSP_MOD, PM_PWSTCTRL);
- DUMP_PRM_MOD_REG(OMAP24XX_DSP_MOD, PM_PWSTST);
-#endif
- } else {
- DUMP_PRM_MOD_REG(CORE_MOD, PM_WKST1);
- DUMP_PRM_MOD_REG(CORE_MOD, OMAP24XX_PM_WKST2);
- DUMP_PRM_MOD_REG(WKUP_MOD, PM_WKST);
- DUMP_PRM_REG(OMAP24XX_PRCM_IRQSTATUS_MPU);
-#if 1
- DUMP_INTC_REG(INTC_PENDING_IRQ0, 0x0098);
- DUMP_INTC_REG(INTC_PENDING_IRQ1, 0x00b8);
- DUMP_INTC_REG(INTC_PENDING_IRQ2, 0x00d8);
-#endif
- }
-
- switch (mode) {
- case 0:
- s1 = "full";
- s2 = "retention";
- break;
- case 1:
- s1 = "MPU";
- s2 = "retention";
- break;
- case 2:
- s1 = "MPU";
- s2 = "idle";
- break;
- }
-
- if (!resume)
-#if defined(CONFIG_NO_IDLE_HZ) || defined(CONFIG_NO_HZ)
- pr_debug("--- Going to %s %s (next timer after %u ms)\n", s1,
- s2,
- jiffies_to_msecs(get_next_timer_interrupt(jiffies) -
- jiffies));
-#else
- pr_debug("--- Going to %s %s\n", s1, s2);
-#endif
- else
- pr_debug("--- Woke up (slept for %u.%03u ms)\n", us / 1000,
- us % 1000);
-
- for (i = 0; i < reg_count; i++)
- pr_debug("%-20s: 0x%08x\n", regs[i].name, regs[i].val);
-}
-
-#else
-static inline void serial_console_sleep(int enable) {}
-static inline void pm_init_serial_console(void) {}
-static inline void omap2_pm_dump(int mode, int resume, unsigned int us) {}
-static inline void serial_console_fclk_mask(u32 *f1, u32 *f2) {}
-
-#define omap2_pm_debug 0
-
-#endif
-
static unsigned short enable_dyn_sleep = 0; /* disabled till drivers are fixed */
static ssize_t idle_show(struct kobject *kobj, struct kobj_attribute *attr,
--
1.5.5
^ permalink raw reply related [flat|nested] 16+ messages in thread* [PATCH 3/9] PM: Add pm.c file for omap2 and omap3 common code
2008-05-16 10:53 [PATCH 0/9] 34XX: PM: Support for retention on suspend and idle Högander Jouni
2008-05-16 10:57 ` [PATCH 1/9] 24XX: PM: Move pm.c to pm24xx.c and sleep.S to sleep24xx.S Jouni Hogander
2008-05-16 10:57 ` [PATCH 2/9] 24XX: PM: Move debugging related code to pm-debug.c Jouni Hogander
@ 2008-05-16 10:57 ` Jouni Hogander
2008-05-16 10:57 ` [PATCH 4/9] OMAP: Add new function to check wether there is irq pending Jouni Hogander
` (6 subsequent siblings)
9 siblings, 0 replies; 16+ messages in thread
From: Jouni Hogander @ 2008-05-16 10:57 UTC (permalink / raw)
To: linux-omap; +Cc: jouni.hogander
Add pm.c file for common code and move handling of sleep_while_idle
attribute and sleep_block to it.
Signed-off-by: Jouni Hogander <jouni.hogander@nokia.com>
---
arch/arm/mach-omap2/Makefile | 2 +
arch/arm/mach-omap2/pm.c | 91 ++++++++++++++++++++++++++++++++++++++++++
arch/arm/mach-omap2/pm.h | 4 ++
arch/arm/mach-omap2/pm24xx.c | 49 +----------------------
4 files changed, 98 insertions(+), 48 deletions(-)
create mode 100644 arch/arm/mach-omap2/pm.c
diff --git a/arch/arm/mach-omap2/Makefile b/arch/arm/mach-omap2/Makefile
index 8f80382..12f6a6f 100644
--- a/arch/arm/mach-omap2/Makefile
+++ b/arch/arm/mach-omap2/Makefile
@@ -12,6 +12,8 @@ obj-$(CONFIG_ARCH_OMAP2) += sram24xx.o
obj-$(CONFIG_ARCH_OMAP3) += sram34xx.o
# Power Management
+obj-$(CONFIG_PM) += pm.o
+
ifeq ($(CONFIG_ARCH_OMAP2),y)
obj-$(CONFIG_PM) += pm24xx.o sleep24xx.o
endif
diff --git a/arch/arm/mach-omap2/pm.c b/arch/arm/mach-omap2/pm.c
new file mode 100644
index 0000000..55ed75b
--- /dev/null
+++ b/arch/arm/mach-omap2/pm.c
@@ -0,0 +1,91 @@
+/*
+ * linux/arch/arm/mach-omap2/pm.c
+ *
+ * OMAP Power Management Common Routines
+ *
+ * Copyright (C) 2005 Texas Instruments, Inc.
+ * Copyright (C) 2006-2008 Nokia Corporation
+ *
+ * Written by:
+ * Richard Woodruff <r-woodruff2@ti.com>
+ * Tony Lindgren
+ * Juha Yrjola
+ * Amit Kucheria <amit.kucheria@nokia.com>
+ * Igor Stoppa <igor.stoppa@nokia.com>
+ * Jouni Hogander
+ *
+ * Based on pm.c for omap1
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/suspend.h>
+#include <linux/time.h>
+
+#include <asm/arch/cpu.h>
+#include <asm/mach/time.h>
+#include <asm/atomic.h>
+
+#include "pm.h"
+
+unsigned short enable_dyn_sleep;
+atomic_t sleep_block = ATOMIC_INIT(0);
+
+static ssize_t idle_show(struct kobject *kobj, struct kobj_attribute *attr,
+ char *buf)
+{
+ return sprintf(buf, "%hu\n", enable_dyn_sleep);
+}
+
+static ssize_t idle_store(struct kobject *kobj, struct kobj_attribute *attr,
+ const char *buf, size_t n)
+{
+ unsigned short value;
+ if (sscanf(buf, "%hu", &value) != 1 ||
+ (value != 0 && value != 1)) {
+ printk(KERN_ERR "idle_sleep_store: Invalid value\n");
+ return -EINVAL;
+ }
+ enable_dyn_sleep = value;
+ return n;
+}
+
+static struct kobj_attribute sleep_while_idle_attr =
+ __ATTR(sleep_while_idle, 0644, idle_show, idle_store);
+
+void omap2_block_sleep(void)
+{
+ atomic_inc(&sleep_block);
+}
+
+void omap2_allow_sleep(void)
+{
+ int i;
+
+ i = atomic_dec_return(&sleep_block);
+ BUG_ON(i < 0);
+}
+
+int __init omap_pm_init(void)
+{
+ int error = -1;
+
+ if (cpu_is_omap24xx())
+ error = omap2_pm_init();
+ if (error) {
+ printk(KERN_ERR "omap2_pm_init failed: %d\n", error);
+ return error;
+ }
+
+ /* disabled till drivers are fixed */
+ enable_dyn_sleep = 0;
+ error = sysfs_create_file(power_kobj, &sleep_while_idle_attr.attr);
+ if (error)
+ printk(KERN_ERR "sysfs_create_file failed: %d\n", error);
+
+ return error;
+}
+
+late_initcall(omap_pm_init);
diff --git a/arch/arm/mach-omap2/pm.h b/arch/arm/mach-omap2/pm.h
index 541bf90..15482ba 100644
--- a/arch/arm/mach-omap2/pm.h
+++ b/arch/arm/mach-omap2/pm.h
@@ -13,6 +13,10 @@
* published by the Free Software Foundation.
*/
+extern int omap2_pm_init(void);
+extern unsigned short enable_dyn_sleep;
+extern atomic_t sleep_block;
+
#ifdef CONFIG_PM_DEBUG
extern u32 omap2_read_32k_sync_counter(void);
extern void omap2_pm_dump(int mode, int resume, unsigned int us);
diff --git a/arch/arm/mach-omap2/pm24xx.c b/arch/arm/mach-omap2/pm24xx.c
index 593f629..7bb654f 100644
--- a/arch/arm/mach-omap2/pm24xx.c
+++ b/arch/arm/mach-omap2/pm24xx.c
@@ -31,7 +31,6 @@
#include <linux/io.h>
#include <linux/irq.h>
-#include <asm/atomic.h>
#include <asm/mach/time.h>
#include <asm/mach/irq.h>
#include <asm/mach-types.h>
@@ -61,30 +60,6 @@ static void (*omap2_sram_idle)(void);
static void (*omap2_sram_suspend)(void __iomem *dllctrl);
static void (*saved_idle)(void);
-static unsigned short enable_dyn_sleep = 0; /* disabled till drivers are fixed */
-
-static ssize_t idle_show(struct kobject *kobj, struct kobj_attribute *attr,
- char *buf)
-{
- return sprintf(buf, "%hu\n", enable_dyn_sleep);
-}
-
-static ssize_t idle_store(struct kobject *kobj, struct kobj_attribute *attr,
- const char *buf, size_t n)
-{
- unsigned short value;
- if (sscanf(buf, "%hu", &value) != 1 ||
- (value != 0 && value != 1)) {
- printk(KERN_ERR "idle_sleep_store: Invalid value\n");
- return -EINVAL;
- }
- enable_dyn_sleep = value;
- return n;
-}
-
-static struct kobj_attribute sleep_while_idle_attr =
- __ATTR(sleep_while_idle, 0644, idle_show, idle_store);
-
static struct clk *osc_ck, *emul_ck;
static int omap2_fclks_active(void)
@@ -112,21 +87,6 @@ static int omap2_irq_pending(void)
return 0;
}
-static atomic_t sleep_block = ATOMIC_INIT(0);
-
-void omap2_block_sleep(void)
-{
- atomic_inc(&sleep_block);
-}
-
-void omap2_allow_sleep(void)
-{
- int i;
-
- i = atomic_dec_return(&sleep_block);
- BUG_ON(i < 0);
-}
-
static void omap2_enter_full_retention(void)
{
u32 l, sleep_time = 0;
@@ -519,10 +479,9 @@ static void __init prcm_setup_regs(void)
WKUP_MOD, PM_WKEN);
}
-static int __init omap2_pm_init(void)
+int __init omap2_pm_init(void)
{
u32 l;
- int error;
printk(KERN_INFO "Power Management for OMAP2 initializing\n");
l = __raw_readl(OMAP24XX_PRCM_REVISION);
@@ -579,11 +538,5 @@ static int __init omap2_pm_init(void)
suspend_set_ops(&omap_pm_ops);
pm_idle = omap2_pm_idle;
- error = sysfs_create_file(power_kobj, &sleep_while_idle_attr.attr);
- if (error)
- printk(KERN_ERR "sysfs_create_file failed: %d\n", error);
-
return 0;
}
-
-late_initcall(omap2_pm_init);
--
1.5.5
^ permalink raw reply related [flat|nested] 16+ messages in thread* [PATCH 4/9] OMAP: Add new function to check wether there is irq pending
2008-05-16 10:53 [PATCH 0/9] 34XX: PM: Support for retention on suspend and idle Högander Jouni
` (2 preceding siblings ...)
2008-05-16 10:57 ` [PATCH 3/9] PM: Add pm.c file for omap2 and omap3 common code Jouni Hogander
@ 2008-05-16 10:57 ` Jouni Hogander
2008-05-16 15:44 ` Tony Lindgren
2008-05-16 10:57 ` [PATCH 5/9] 34XX: Suspend: Take suspend sram code from ti cdp kernel Jouni Hogander
` (5 subsequent siblings)
9 siblings, 1 reply; 16+ messages in thread
From: Jouni Hogander @ 2008-05-16 10:57 UTC (permalink / raw)
To: linux-omap; +Cc: jouni.hogander
Add common omap2/3 function to check wether there is irq pending.
Switch to use it in omap2 pm code instead of its own.
Signed-off-by: Jouni Hogander <jouni.hogander@nokia.com>
---
arch/arm/mach-omap2/irq.c | 29 +++++++++++++++++++++++------
arch/arm/mach-omap2/pm24xx.c | 19 +++----------------
include/asm-arm/arch-omap/irqs.h | 1 +
3 files changed, 27 insertions(+), 22 deletions(-)
diff --git a/arch/arm/mach-omap2/irq.c b/arch/arm/mach-omap2/irq.c
index ac062ee..f1e1e2e 100644
--- a/arch/arm/mach-omap2/irq.c
+++ b/arch/arm/mach-omap2/irq.c
@@ -20,12 +20,13 @@
/* selected INTC register offsets */
-#define INTC_REVISION 0x0000
-#define INTC_SYSCONFIG 0x0010
-#define INTC_SYSSTATUS 0x0014
-#define INTC_CONTROL 0x0048
-#define INTC_MIR_CLEAR0 0x0088
-#define INTC_MIR_SET0 0x008c
+#define INTC_REVISION 0x0000
+#define INTC_SYSCONFIG 0x0010
+#define INTC_SYSSTATUS 0x0014
+#define INTC_CONTROL 0x0048
+#define INTC_MIR_CLEAR0 0x0088
+#define INTC_MIR_SET0 0x008c
+#define INTC_PENDING_IRQ0 0x0098
/*
* OMAP2 has a number of different interrupt controllers, each interrupt
@@ -122,6 +123,22 @@ static void __init omap_irq_bank_init_one(struct omap_irq_bank *bank)
intc_bank_write_reg(1 << 0, bank, INTC_SYSCONFIG);
}
+int omap_irq_pending(void)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(irq_banks); i++) {
+ struct omap_irq_bank *bank = irq_banks + i;
+ int irq;
+
+ for (irq = 0; irq < bank->nr_irqs; irq += 32)
+ if (intc_bank_read_reg(bank, INTC_PENDING_IRQ0 +
+ ((irq >> 5) << 5)))
+ return 1;
+ }
+ return 0;
+}
+
void __init omap_init_irq(void)
{
unsigned long nr_irqs = 0;
diff --git a/arch/arm/mach-omap2/pm24xx.c b/arch/arm/mach-omap2/pm24xx.c
index 7bb654f..8636f1c 100644
--- a/arch/arm/mach-omap2/pm24xx.c
+++ b/arch/arm/mach-omap2/pm24xx.c
@@ -74,19 +74,6 @@ static int omap2_fclks_active(void)
return 0;
}
-static int omap2_irq_pending(void)
-{
- u32 pending_reg = 0x480fe098;
- int i;
-
- for (i = 0; i < 4; i++) {
- if (omap_readl(pending_reg))
- return 1;
- pending_reg += 0x20;
- }
- return 0;
-}
-
static void omap2_enter_full_retention(void)
{
u32 l, sleep_time = 0;
@@ -121,7 +108,7 @@ static void omap2_enter_full_retention(void)
/* One last check for pending IRQs to avoid extra latency due
* to sleeping unnecessarily. */
- if (omap2_irq_pending())
+ if (omap_irq_pending())
goto no_sleep;
serial_console_sleep(1);
@@ -272,7 +259,7 @@ static void omap2_pm_idle(void)
*/
if (atomic_read(&sleep_block) == 0) {
timer_dyn_reprogram();
- if (omap2_irq_pending())
+ if (omap_irq_pending())
goto out;
}
omap2_enter_mpu_retention();
@@ -286,7 +273,7 @@ static void omap2_pm_idle(void)
*/
timer_dyn_reprogram();
- if (omap2_irq_pending())
+ if (omap_irq_pending())
goto out;
omap2_enter_full_retention();
diff --git a/include/asm-arm/arch-omap/irqs.h b/include/asm-arm/arch-omap/irqs.h
index c80e160..343e93e 100644
--- a/include/asm-arm/arch-omap/irqs.h
+++ b/include/asm-arm/arch-omap/irqs.h
@@ -368,6 +368,7 @@
#ifndef __ASSEMBLY__
extern void omap_init_irq(void);
+extern int omap_irq_pending(void);
#endif
#include <asm/hardware.h>
--
1.5.5
^ permalink raw reply related [flat|nested] 16+ messages in thread* Re: [PATCH 4/9] OMAP: Add new function to check wether there is irq pending
2008-05-16 10:57 ` [PATCH 4/9] OMAP: Add new function to check wether there is irq pending Jouni Hogander
@ 2008-05-16 15:44 ` Tony Lindgren
2008-05-19 8:04 ` Högander Jouni
0 siblings, 1 reply; 16+ messages in thread
From: Tony Lindgren @ 2008-05-16 15:44 UTC (permalink / raw)
To: Jouni Hogander; +Cc: linux-omap
Hi,
* Jouni Hogander <jouni.hogander@nokia.com> [080516 03:57]:
> Add common omap2/3 function to check wether there is irq pending.
> Switch to use it in omap2 pm code instead of its own.
>
> Signed-off-by: Jouni Hogander <jouni.hogander@nokia.com>
> ---
> arch/arm/mach-omap2/irq.c | 29 +++++++++++++++++++++++------
> arch/arm/mach-omap2/pm24xx.c | 19 +++----------------
> include/asm-arm/arch-omap/irqs.h | 1 +
> 3 files changed, 27 insertions(+), 22 deletions(-)
>
> diff --git a/arch/arm/mach-omap2/irq.c b/arch/arm/mach-omap2/irq.c
> index ac062ee..f1e1e2e 100644
> --- a/arch/arm/mach-omap2/irq.c
> +++ b/arch/arm/mach-omap2/irq.c
> @@ -20,12 +20,13 @@
>
> /* selected INTC register offsets */
>
> -#define INTC_REVISION 0x0000
> -#define INTC_SYSCONFIG 0x0010
> -#define INTC_SYSSTATUS 0x0014
> -#define INTC_CONTROL 0x0048
> -#define INTC_MIR_CLEAR0 0x0088
> -#define INTC_MIR_SET0 0x008c
> +#define INTC_REVISION 0x0000
> +#define INTC_SYSCONFIG 0x0010
> +#define INTC_SYSSTATUS 0x0014
> +#define INTC_CONTROL 0x0048
> +#define INTC_MIR_CLEAR0 0x0088
> +#define INTC_MIR_SET0 0x008c
> +#define INTC_PENDING_IRQ0 0x0098
>
> /*
> * OMAP2 has a number of different interrupt controllers, each interrupt
> @@ -122,6 +123,22 @@ static void __init omap_irq_bank_init_one(struct omap_irq_bank *bank)
> intc_bank_write_reg(1 << 0, bank, INTC_SYSCONFIG);
> }
>
> +int omap_irq_pending(void)
> +{
> + int i;
> +
> + for (i = 0; i < ARRAY_SIZE(irq_banks); i++) {
> + struct omap_irq_bank *bank = irq_banks + i;
> + int irq;
> +
> + for (irq = 0; irq < bank->nr_irqs; irq += 32)
> + if (intc_bank_read_reg(bank, INTC_PENDING_IRQ0 +
> + ((irq >> 5) << 5)))
> + return 1;
> + }
> + return 0;
> +}
> +
In this case it should be enough to know if anything is set in the
bank registers, so you should be able to leave out the second for loop.
At most you need to read only the four bank registers. No need to check
for individual interrupts.
> void __init omap_init_irq(void)
> {
> unsigned long nr_irqs = 0;
> diff --git a/arch/arm/mach-omap2/pm24xx.c b/arch/arm/mach-omap2/pm24xx.c
> index 7bb654f..8636f1c 100644
> --- a/arch/arm/mach-omap2/pm24xx.c
> +++ b/arch/arm/mach-omap2/pm24xx.c
> @@ -74,19 +74,6 @@ static int omap2_fclks_active(void)
> return 0;
> }
>
> -static int omap2_irq_pending(void)
> -{
> - u32 pending_reg = 0x480fe098;
> - int i;
> -
> - for (i = 0; i < 4; i++) {
> - if (omap_readl(pending_reg))
> - return 1;
> - pending_reg += 0x20;
> - }
> - return 0;
> -}
> -
> static void omap2_enter_full_retention(void)
> {
> u32 l, sleep_time = 0;
> @@ -121,7 +108,7 @@ static void omap2_enter_full_retention(void)
>
> /* One last check for pending IRQs to avoid extra latency due
> * to sleeping unnecessarily. */
> - if (omap2_irq_pending())
> + if (omap_irq_pending())
> goto no_sleep;
>
> serial_console_sleep(1);
> @@ -272,7 +259,7 @@ static void omap2_pm_idle(void)
> */
> if (atomic_read(&sleep_block) == 0) {
> timer_dyn_reprogram();
> - if (omap2_irq_pending())
> + if (omap_irq_pending())
> goto out;
> }
> omap2_enter_mpu_retention();
> @@ -286,7 +273,7 @@ static void omap2_pm_idle(void)
> */
> timer_dyn_reprogram();
>
> - if (omap2_irq_pending())
> + if (omap_irq_pending())
> goto out;
>
> omap2_enter_full_retention();
> diff --git a/include/asm-arm/arch-omap/irqs.h b/include/asm-arm/arch-omap/irqs.h
> index c80e160..343e93e 100644
> --- a/include/asm-arm/arch-omap/irqs.h
> +++ b/include/asm-arm/arch-omap/irqs.h
> @@ -368,6 +368,7 @@
>
> #ifndef __ASSEMBLY__
> extern void omap_init_irq(void);
> +extern int omap_irq_pending(void);
> #endif
>
> #include <asm/hardware.h>
> --
> 1.5.5
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-omap" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 16+ messages in thread* Re: [PATCH 4/9] OMAP: Add new function to check wether there is irq pending
2008-05-16 15:44 ` Tony Lindgren
@ 2008-05-19 8:04 ` Högander Jouni
2008-05-19 18:54 ` Tony Lindgren
0 siblings, 1 reply; 16+ messages in thread
From: Högander Jouni @ 2008-05-19 8:04 UTC (permalink / raw)
To: ext Tony Lindgren; +Cc: linux-omap
"ext Tony Lindgren" <tony@atomide.com> writes:
> Hi,
>
> * Jouni Hogander <jouni.hogander@nokia.com> [080516 03:57]:
>> Add common omap2/3 function to check wether there is irq pending.
>> Switch to use it in omap2 pm code instead of its own.
>>
>> Signed-off-by: Jouni Hogander <jouni.hogander@nokia.com>
>> ---
>> arch/arm/mach-omap2/irq.c | 29 +++++++++++++++++++++++------
>> arch/arm/mach-omap2/pm24xx.c | 19 +++----------------
>> include/asm-arm/arch-omap/irqs.h | 1 +
>> 3 files changed, 27 insertions(+), 22 deletions(-)
>>
>> diff --git a/arch/arm/mach-omap2/irq.c b/arch/arm/mach-omap2/irq.c
>> index ac062ee..f1e1e2e 100644
>> --- a/arch/arm/mach-omap2/irq.c
>> +++ b/arch/arm/mach-omap2/irq.c
>> @@ -20,12 +20,13 @@
>>
>> /* selected INTC register offsets */
>>
>> -#define INTC_REVISION 0x0000
>> -#define INTC_SYSCONFIG 0x0010
>> -#define INTC_SYSSTATUS 0x0014
>> -#define INTC_CONTROL 0x0048
>> -#define INTC_MIR_CLEAR0 0x0088
>> -#define INTC_MIR_SET0 0x008c
>> +#define INTC_REVISION 0x0000
>> +#define INTC_SYSCONFIG 0x0010
>> +#define INTC_SYSSTATUS 0x0014
>> +#define INTC_CONTROL 0x0048
>> +#define INTC_MIR_CLEAR0 0x0088
>> +#define INTC_MIR_SET0 0x008c
>> +#define INTC_PENDING_IRQ0 0x0098
>>
>> /*
>> * OMAP2 has a number of different interrupt controllers, each interrupt
>> @@ -122,6 +123,22 @@ static void __init omap_irq_bank_init_one(struct omap_irq_bank *bank)
>> intc_bank_write_reg(1 << 0, bank, INTC_SYSCONFIG);
>> }
>>
>> +int omap_irq_pending(void)
>> +{
>> + int i;
>> +
>> + for (i = 0; i < ARRAY_SIZE(irq_banks); i++) {
>> + struct omap_irq_bank *bank = irq_banks + i;
>> + int irq;
>> +
>> + for (irq = 0; irq < bank->nr_irqs; irq += 32)
>> + if (intc_bank_read_reg(bank, INTC_PENDING_IRQ0 +
>> + ((irq >> 5) << 5)))
>> + return 1;
>> + }
>> + return 0;
>> +}
>> +
>
> In this case it should be enough to know if anything is set in the
> bank registers, so you should be able to leave out the second for loop.
> At most you need to read only the four bank registers. No need to check
> for individual interrupts.
Current code is presenting each interrupt controller as a bank. I
think in TRM they are talking about banks in each controller. So there
is three banks in mpu intc 0..2. This is in arch/arm/mach-omap2/irq.c:
* OMAP2 has a number of different interrupt controllers, each interrupt
* controller is identified as its own "bank". Register definitions are
* fairly consistent for each bank, but not all registers are implemented
* for each bank.. when in doubt, consult the TRM.
*/
So the first loop is going through controllers which is only mpu
intc. Second loop is going through bank registers. I'm using irq only
for finding out right offset for bank register. This is another
implementation. Which does exactly same thing:
int omap_irq_pending(void)
{
int i, j;
for (i = 0; i < ARRAY_SIZE(irq_banks); i++) {
struct omap_irq_bank *bank = irq_banks + i;
for (j = 0; j < 3; j++)
if (intc_bank_read_reg(bank, INTC_PENDING_IRQ0 +
0x20 * j))
return 1;
}
return 0;
}
If you think this is better I can change it. In first version I was
just trying to follow practices used in irq.c for finding out offsets.
--
Jouni Högander
--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 16+ messages in thread* Re: [PATCH 4/9] OMAP: Add new function to check wether there is irq pending
2008-05-19 8:04 ` Högander Jouni
@ 2008-05-19 18:54 ` Tony Lindgren
2008-05-20 6:27 ` Högander Jouni
0 siblings, 1 reply; 16+ messages in thread
From: Tony Lindgren @ 2008-05-19 18:54 UTC (permalink / raw)
To: Högander Jouni; +Cc: linux-omap
[-- Attachment #1: Type: text/plain, Size: 3708 bytes --]
* Högander Jouni <jouni.hogander@nokia.com> [080519 01:05]:
> "ext Tony Lindgren" <tony@atomide.com> writes:
>
> > Hi,
> >
> > * Jouni Hogander <jouni.hogander@nokia.com> [080516 03:57]:
> >> Add common omap2/3 function to check wether there is irq pending.
> >> Switch to use it in omap2 pm code instead of its own.
> >>
> >> Signed-off-by: Jouni Hogander <jouni.hogander@nokia.com>
> >> ---
> >> arch/arm/mach-omap2/irq.c | 29 +++++++++++++++++++++++------
> >> arch/arm/mach-omap2/pm24xx.c | 19 +++----------------
> >> include/asm-arm/arch-omap/irqs.h | 1 +
> >> 3 files changed, 27 insertions(+), 22 deletions(-)
> >>
> >> diff --git a/arch/arm/mach-omap2/irq.c b/arch/arm/mach-omap2/irq.c
> >> index ac062ee..f1e1e2e 100644
> >> --- a/arch/arm/mach-omap2/irq.c
> >> +++ b/arch/arm/mach-omap2/irq.c
> >> @@ -20,12 +20,13 @@
> >>
> >> /* selected INTC register offsets */
> >>
> >> -#define INTC_REVISION 0x0000
> >> -#define INTC_SYSCONFIG 0x0010
> >> -#define INTC_SYSSTATUS 0x0014
> >> -#define INTC_CONTROL 0x0048
> >> -#define INTC_MIR_CLEAR0 0x0088
> >> -#define INTC_MIR_SET0 0x008c
> >> +#define INTC_REVISION 0x0000
> >> +#define INTC_SYSCONFIG 0x0010
> >> +#define INTC_SYSSTATUS 0x0014
> >> +#define INTC_CONTROL 0x0048
> >> +#define INTC_MIR_CLEAR0 0x0088
> >> +#define INTC_MIR_SET0 0x008c
> >> +#define INTC_PENDING_IRQ0 0x0098
> >>
> >> /*
> >> * OMAP2 has a number of different interrupt controllers, each interrupt
> >> @@ -122,6 +123,22 @@ static void __init omap_irq_bank_init_one(struct omap_irq_bank *bank)
> >> intc_bank_write_reg(1 << 0, bank, INTC_SYSCONFIG);
> >> }
> >>
> >> +int omap_irq_pending(void)
> >> +{
> >> + int i;
> >> +
> >> + for (i = 0; i < ARRAY_SIZE(irq_banks); i++) {
> >> + struct omap_irq_bank *bank = irq_banks + i;
> >> + int irq;
> >> +
> >> + for (irq = 0; irq < bank->nr_irqs; irq += 32)
> >> + if (intc_bank_read_reg(bank, INTC_PENDING_IRQ0 +
> >> + ((irq >> 5) << 5)))
> >> + return 1;
> >> + }
> >> + return 0;
> >> +}
> >> +
> >
> > In this case it should be enough to know if anything is set in the
> > bank registers, so you should be able to leave out the second for loop.
> > At most you need to read only the four bank registers. No need to check
> > for individual interrupts.
>
> Current code is presenting each interrupt controller as a bank. I
> think in TRM they are talking about banks in each controller. So there
> is three banks in mpu intc 0..2. This is in arch/arm/mach-omap2/irq.c:
>
> * OMAP2 has a number of different interrupt controllers, each interrupt
> * controller is identified as its own "bank". Register definitions are
> * fairly consistent for each bank, but not all registers are implemented
> * for each bank.. when in doubt, consult the TRM.
> */
>
> So the first loop is going through controllers which is only mpu
> intc. Second loop is going through bank registers. I'm using irq only
> for finding out right offset for bank register. This is another
> implementation. Which does exactly same thing:
>
> int omap_irq_pending(void)
> {
> int i, j;
>
> for (i = 0; i < ARRAY_SIZE(irq_banks); i++) {
> struct omap_irq_bank *bank = irq_banks + i;
>
> for (j = 0; j < 3; j++)
> if (intc_bank_read_reg(bank, INTC_PENDING_IRQ0 +
> 0x20 * j))
> return 1;
> }
> return 0;
> }
>
> If you think this is better I can change it. In first version I was
> just trying to follow practices used in irq.c for finding out offsets.
Hmm, AFAIK, something like below should be enough to see if any interrupts
are pending (patch untested). See also include/asm-arm/arch-omap/entry-macro.S
and what pm.c was doing.
Regards,
Tony
[-- Attachment #2: irq-pending.patch --]
[-- Type: text/x-diff, Size: 816 bytes --]
diff --git a/arch/arm/mach-omap2/irq.c b/arch/arm/mach-omap2/irq.c
index ac062ee..aef28ab 100644
--- a/arch/arm/mach-omap2/irq.c
+++ b/arch/arm/mach-omap2/irq.c
@@ -26,6 +26,7 @@
#define INTC_CONTROL 0x0048
#define INTC_MIR_CLEAR0 0x0088
#define INTC_MIR_SET0 0x008c
+#define INTC_PENDING 0x0098
/*
* OMAP2 has a number of different interrupt controllers, each interrupt
@@ -122,6 +123,20 @@ static void __init omap_irq_bank_init_one(struct omap_irq_bank *bank)
intc_bank_write_reg(1 << 0, bank, INTC_SYSCONFIG);
}
+int omap_irq_pending(void)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(irq_banks); i++) {
+ struct omap_irq_bank *bank = irq_banks + i;
+
+ if (intc_bank_read_reg(bank, INTC_PENDING))
+ return 1;
+ }
+
+ return 0;
+}
+
void __init omap_init_irq(void)
{
unsigned long nr_irqs = 0;
^ permalink raw reply related [flat|nested] 16+ messages in thread* Re: [PATCH 4/9] OMAP: Add new function to check wether there is irq pending
2008-05-19 18:54 ` Tony Lindgren
@ 2008-05-20 6:27 ` Högander Jouni
2008-05-20 14:47 ` Tony Lindgren
0 siblings, 1 reply; 16+ messages in thread
From: Högander Jouni @ 2008-05-20 6:27 UTC (permalink / raw)
To: ext Tony Lindgren; +Cc: linux-omap
"ext Tony Lindgren" <tony@atomide.com> writes:
> * Högander Jouni <jouni.hogander@nokia.com> [080519 01:05]:
>> "ext Tony Lindgren" <tony@atomide.com> writes:
>>
>> > Hi,
>> >
>> > * Jouni Hogander <jouni.hogander@nokia.com> [080516 03:57]:
>> >> Add common omap2/3 function to check wether there is irq pending.
>> >> Switch to use it in omap2 pm code instead of its own.
>> >>
>> >> Signed-off-by: Jouni Hogander <jouni.hogander@nokia.com>
>> >> ---
>> >> arch/arm/mach-omap2/irq.c | 29 +++++++++++++++++++++++------
>> >> arch/arm/mach-omap2/pm24xx.c | 19 +++----------------
>> >> include/asm-arm/arch-omap/irqs.h | 1 +
>> >> 3 files changed, 27 insertions(+), 22 deletions(-)
>> >>
>> >> diff --git a/arch/arm/mach-omap2/irq.c b/arch/arm/mach-omap2/irq.c
>> >> index ac062ee..f1e1e2e 100644
>> >> --- a/arch/arm/mach-omap2/irq.c
>> >> +++ b/arch/arm/mach-omap2/irq.c
>> >> @@ -20,12 +20,13 @@
>> >>
>> >> /* selected INTC register offsets */
>> >>
>> >> -#define INTC_REVISION 0x0000
>> >> -#define INTC_SYSCONFIG 0x0010
>> >> -#define INTC_SYSSTATUS 0x0014
>> >> -#define INTC_CONTROL 0x0048
>> >> -#define INTC_MIR_CLEAR0 0x0088
>> >> -#define INTC_MIR_SET0 0x008c
>> >> +#define INTC_REVISION 0x0000
>> >> +#define INTC_SYSCONFIG 0x0010
>> >> +#define INTC_SYSSTATUS 0x0014
>> >> +#define INTC_CONTROL 0x0048
>> >> +#define INTC_MIR_CLEAR0 0x0088
>> >> +#define INTC_MIR_SET0 0x008c
>> >> +#define INTC_PENDING_IRQ0 0x0098
>> >>
>> >> /*
>> >> * OMAP2 has a number of different interrupt controllers, each interrupt
>> >> @@ -122,6 +123,22 @@ static void __init omap_irq_bank_init_one(struct omap_irq_bank *bank)
>> >> intc_bank_write_reg(1 << 0, bank, INTC_SYSCONFIG);
>> >> }
>> >>
>> >> +int omap_irq_pending(void)
>> >> +{
>> >> + int i;
>> >> +
>> >> + for (i = 0; i < ARRAY_SIZE(irq_banks); i++) {
>> >> + struct omap_irq_bank *bank = irq_banks + i;
>> >> + int irq;
>> >> +
>> >> + for (irq = 0; irq < bank->nr_irqs; irq += 32)
>> >> + if (intc_bank_read_reg(bank, INTC_PENDING_IRQ0 +
>> >> + ((irq >> 5) << 5)))
>> >> + return 1;
>> >> + }
>> >> + return 0;
>> >> +}
>> >> +
>> >
>> > In this case it should be enough to know if anything is set in the
>> > bank registers, so you should be able to leave out the second for loop.
>> > At most you need to read only the four bank registers. No need to check
>> > for individual interrupts.
>>
>> Current code is presenting each interrupt controller as a bank. I
>> think in TRM they are talking about banks in each controller. So there
>> is three banks in mpu intc 0..2. This is in arch/arm/mach-omap2/irq.c:
>>
>> * OMAP2 has a number of different interrupt controllers, each interrupt
>> * controller is identified as its own "bank". Register definitions are
>> * fairly consistent for each bank, but not all registers are implemented
>> * for each bank.. when in doubt, consult the TRM.
>> */
>>
>> So the first loop is going through controllers which is only mpu
>> intc. Second loop is going through bank registers. I'm using irq only
>> for finding out right offset for bank register. This is another
>> implementation. Which does exactly same thing:
>>
>> int omap_irq_pending(void)
>> {
>> int i, j;
>>
>> for (i = 0; i < ARRAY_SIZE(irq_banks); i++) {
>> struct omap_irq_bank *bank = irq_banks + i;
>>
>> for (j = 0; j < 3; j++)
>> if (intc_bank_read_reg(bank, INTC_PENDING_IRQ0 +
>> 0x20 * j))
>> return 1;
>> }
>> return 0;
>> }
>>
>> If you think this is better I can change it. In first version I was
>> just trying to follow practices used in irq.c for finding out offsets.
>
> Hmm, AFAIK, something like below should be enough to see if any interrupts
> are pending (patch untested). See also
> include/asm-arm/arch-omap/entry-macro.S> and what pm.c was doing.
No it doesn't work. It would work if irq_banks were presenting banks
instead of controllers. See my comments below.
>
> Regards,
>
> Tony
>
>
>
> diff --git a/arch/arm/mach-omap2/irq.c b/arch/arm/mach-omap2/irq.c
> index ac062ee..aef28ab 100644
> --- a/arch/arm/mach-omap2/irq.c
> +++ b/arch/arm/mach-omap2/irq.c
> @@ -26,6 +26,7 @@
> #define INTC_CONTROL 0x0048
> #define INTC_MIR_CLEAR0 0x0088
> #define INTC_MIR_SET0 0x008c
> +#define INTC_PENDING 0x0098
>
> /*
> * OMAP2 has a number of different interrupt controllers, each interrupt
> @@ -122,6 +123,20 @@ static void __init omap_irq_bank_init_one(struct omap_irq_bank *bank)
> intc_bank_write_reg(1 << 0, bank, INTC_SYSCONFIG);
> }
>
> +int omap_irq_pending(void)
> +{
> + int i;
> +
> + for (i = 0; i < ARRAY_SIZE(irq_banks); i++) {
ARRAY_SIZE(irq_banks) == 1, because there is only mpu intc in
irq_banks. irq_banks contains interrupt controllers, so we need to
loop through them and loop each pending (bank) register inside these
controllers.
> + struct omap_irq_bank *bank = irq_banks + i;
> +
> + if (intc_bank_read_reg(bank, INTC_PENDING))
> + return 1;
> + }
> +
> + return 0;
> +}
Your function reads only first INTC_PENDING register. There are three
of them in mpu intc.
> +
> void __init omap_init_irq(void)
> {
> unsigned long nr_irqs = 0;
>
--
Jouni Högander
--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 16+ messages in thread* Re: [PATCH 4/9] OMAP: Add new function to check wether there is irq pending
2008-05-20 6:27 ` Högander Jouni
@ 2008-05-20 14:47 ` Tony Lindgren
0 siblings, 0 replies; 16+ messages in thread
From: Tony Lindgren @ 2008-05-20 14:47 UTC (permalink / raw)
To: Högander Jouni; +Cc: linux-omap
* Högander Jouni <jouni.hogander@nokia.com> [080519 23:27]:
> "ext Tony Lindgren" <tony@atomide.com> writes:
>
> > * Högander Jouni <jouni.hogander@nokia.com> [080519 01:05]:
> >> "ext Tony Lindgren" <tony@atomide.com> writes:
> >>
> >> > Hi,
> >> >
> >> > * Jouni Hogander <jouni.hogander@nokia.com> [080516 03:57]:
> >> >> Add common omap2/3 function to check wether there is irq pending.
> >> >> Switch to use it in omap2 pm code instead of its own.
> >> >>
> >> >> Signed-off-by: Jouni Hogander <jouni.hogander@nokia.com>
> >> >> ---
> >> >> arch/arm/mach-omap2/irq.c | 29 +++++++++++++++++++++++------
> >> >> arch/arm/mach-omap2/pm24xx.c | 19 +++----------------
> >> >> include/asm-arm/arch-omap/irqs.h | 1 +
> >> >> 3 files changed, 27 insertions(+), 22 deletions(-)
> >> >>
> >> >> diff --git a/arch/arm/mach-omap2/irq.c b/arch/arm/mach-omap2/irq.c
> >> >> index ac062ee..f1e1e2e 100644
> >> >> --- a/arch/arm/mach-omap2/irq.c
> >> >> +++ b/arch/arm/mach-omap2/irq.c
> >> >> @@ -20,12 +20,13 @@
> >> >>
> >> >> /* selected INTC register offsets */
> >> >>
> >> >> -#define INTC_REVISION 0x0000
> >> >> -#define INTC_SYSCONFIG 0x0010
> >> >> -#define INTC_SYSSTATUS 0x0014
> >> >> -#define INTC_CONTROL 0x0048
> >> >> -#define INTC_MIR_CLEAR0 0x0088
> >> >> -#define INTC_MIR_SET0 0x008c
> >> >> +#define INTC_REVISION 0x0000
> >> >> +#define INTC_SYSCONFIG 0x0010
> >> >> +#define INTC_SYSSTATUS 0x0014
> >> >> +#define INTC_CONTROL 0x0048
> >> >> +#define INTC_MIR_CLEAR0 0x0088
> >> >> +#define INTC_MIR_SET0 0x008c
> >> >> +#define INTC_PENDING_IRQ0 0x0098
> >> >>
> >> >> /*
> >> >> * OMAP2 has a number of different interrupt controllers, each interrupt
> >> >> @@ -122,6 +123,22 @@ static void __init omap_irq_bank_init_one(struct omap_irq_bank *bank)
> >> >> intc_bank_write_reg(1 << 0, bank, INTC_SYSCONFIG);
> >> >> }
> >> >>
> >> >> +int omap_irq_pending(void)
> >> >> +{
> >> >> + int i;
> >> >> +
> >> >> + for (i = 0; i < ARRAY_SIZE(irq_banks); i++) {
> >> >> + struct omap_irq_bank *bank = irq_banks + i;
> >> >> + int irq;
> >> >> +
> >> >> + for (irq = 0; irq < bank->nr_irqs; irq += 32)
> >> >> + if (intc_bank_read_reg(bank, INTC_PENDING_IRQ0 +
> >> >> + ((irq >> 5) << 5)))
> >> >> + return 1;
> >> >> + }
> >> >> + return 0;
> >> >> +}
> >> >> +
> >> >
> >> > In this case it should be enough to know if anything is set in the
> >> > bank registers, so you should be able to leave out the second for loop.
> >> > At most you need to read only the four bank registers. No need to check
> >> > for individual interrupts.
> >>
> >> Current code is presenting each interrupt controller as a bank. I
> >> think in TRM they are talking about banks in each controller. So there
> >> is three banks in mpu intc 0..2. This is in arch/arm/mach-omap2/irq.c:
> >>
> >> * OMAP2 has a number of different interrupt controllers, each interrupt
> >> * controller is identified as its own "bank". Register definitions are
> >> * fairly consistent for each bank, but not all registers are implemented
> >> * for each bank.. when in doubt, consult the TRM.
> >> */
> >>
> >> So the first loop is going through controllers which is only mpu
> >> intc. Second loop is going through bank registers. I'm using irq only
> >> for finding out right offset for bank register. This is another
> >> implementation. Which does exactly same thing:
> >>
> >> int omap_irq_pending(void)
> >> {
> >> int i, j;
> >>
> >> for (i = 0; i < ARRAY_SIZE(irq_banks); i++) {
> >> struct omap_irq_bank *bank = irq_banks + i;
> >>
> >> for (j = 0; j < 3; j++)
> >> if (intc_bank_read_reg(bank, INTC_PENDING_IRQ0 +
> >> 0x20 * j))
> >> return 1;
> >> }
> >> return 0;
> >> }
> >>
> >> If you think this is better I can change it. In first version I was
> >> just trying to follow practices used in irq.c for finding out offsets.
> >
> > Hmm, AFAIK, something like below should be enough to see if any interrupts
> > are pending (patch untested). See also
> > include/asm-arm/arch-omap/entry-macro.S> and what pm.c was doing.
>
> No it doesn't work. It would work if irq_banks were presenting banks
> instead of controllers. See my comments below.
>
> >
> > Regards,
> >
> > Tony
> >
> >
> >
> > diff --git a/arch/arm/mach-omap2/irq.c b/arch/arm/mach-omap2/irq.c
> > index ac062ee..aef28ab 100644
> > --- a/arch/arm/mach-omap2/irq.c
> > +++ b/arch/arm/mach-omap2/irq.c
> > @@ -26,6 +26,7 @@
> > #define INTC_CONTROL 0x0048
> > #define INTC_MIR_CLEAR0 0x0088
> > #define INTC_MIR_SET0 0x008c
> > +#define INTC_PENDING 0x0098
> >
> > /*
> > * OMAP2 has a number of different interrupt controllers, each interrupt
> > @@ -122,6 +123,20 @@ static void __init omap_irq_bank_init_one(struct omap_irq_bank *bank)
> > intc_bank_write_reg(1 << 0, bank, INTC_SYSCONFIG);
> > }
> >
> > +int omap_irq_pending(void)
> > +{
> > + int i;
> > +
> > + for (i = 0; i < ARRAY_SIZE(irq_banks); i++) {
>
> ARRAY_SIZE(irq_banks) == 1, because there is only mpu intc in
> irq_banks. irq_banks contains interrupt controllers, so we need to
> loop through them and loop each pending (bank) register inside these
> controllers.
Ah, OK. Yes you're right there is only one bank in irq_banks. And that's
why you still need to calculate the register offset with (i >> 5) << 5.
And you're increasing the for loop by 32, not by 1, I guess that's
where I originally misread your patch and got confused.
Let's just use your original patch then.
Tony
>
> > + struct omap_irq_bank *bank = irq_banks + i;
> > +
> > + if (intc_bank_read_reg(bank, INTC_PENDING))
> > + return 1;
> > + }
> > +
> > + return 0;
> > +}
>
> Your function reads only first INTC_PENDING register. There are three
> of them in mpu intc.
>
> > +
> > void __init omap_init_irq(void)
> > {
> > unsigned long nr_irqs = 0;
> >
>
> --
> Jouni Högander
>
--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 16+ messages in thread
* [PATCH 5/9] 34XX: Suspend: Take suspend sram code from ti cdp kernel
2008-05-16 10:53 [PATCH 0/9] 34XX: PM: Support for retention on suspend and idle Högander Jouni
` (3 preceding siblings ...)
2008-05-16 10:57 ` [PATCH 4/9] OMAP: Add new function to check wether there is irq pending Jouni Hogander
@ 2008-05-16 10:57 ` Jouni Hogander
2008-05-16 10:57 ` [PATCH 6/9] 34XX: Suspend: Use same naming convention in sleep34xx.S as in sleep24XX.S Jouni Hogander
` (4 subsequent siblings)
9 siblings, 0 replies; 16+ messages in thread
From: Jouni Hogander @ 2008-05-16 10:57 UTC (permalink / raw)
To: linux-omap; +Cc: jouni.hogander, Karthik Dasu
From: Karthik Dasu <karthik-dp@ti.com>
Take sram code from ti cdp kernel for 34XX suspend.
Signed-off-by: Jouni Hogander <jouni.hogander@nokia.com>
---
arch/arm/mach-omap2/sleep34xx.S | 534 +++++++++++++++++++++++++++++++++++++++
1 files changed, 534 insertions(+), 0 deletions(-)
create mode 100644 arch/arm/mach-omap2/sleep34xx.S
diff --git a/arch/arm/mach-omap2/sleep34xx.S b/arch/arm/mach-omap2/sleep34xx.S
new file mode 100644
index 0000000..c9db507
--- /dev/null
+++ b/arch/arm/mach-omap2/sleep34xx.S
@@ -0,0 +1,534 @@
+/*
+ * linux/arch/arm/mach-omap2/sleep.S
+ *
+ * (C) Copyright 2007
+ * Texas Instruments
+ * Karthik Dasu <karthik-dp@ti.com>
+ *
+ * (C) Copyright 2004
+ * Texas Instruments, <www.ti.com>
+ * Richard Woodruff <r-woodruff2@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR /PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+#include <linux/linkage.h>
+#include <asm/assembler.h>
+#include <asm/arch/io.h>
+#include <asm/arch/pm.h>
+
+#define PM_PREPWSTST_CORE_V IO_ADDRESS(PRM_BASE + 0xAE8)
+#define PM_PREPWSTST_MPU_V IO_ADDRESS(PRM_BASE + 0x9E8)
+#define PM_PWSTCTRL_MPU_P (PRM_BASE + 0x9E0)
+#define SCRATCHPAD_BASE_P 0x48002910
+#define SDRC_POWER_V IO_ADDRESS(SDRC_BASE + 0x070)
+
+ .text
+/* Function call to get the restore pointer for resume from OFF */
+ENTRY(get_restore_pointer)
+ stmfd sp!, {lr} @ save registers on stack
+ adr r0, restore
+ ldmfd sp!, {pc} @ restore regs and return
+ENTRY(get_restore_pointer_sz)
+ .word . - get_restore_pointer_sz
+/*
+ * Forces OMAP into idle state
+ *
+ * omap34xx_suspend() - This bit of code just executes the WFI
+ * for normal idles.
+ *
+ * Note: This code get's copied to internal SRAM at boot. When the OMAP
+ * wakes up it continues execution at the point it went to sleep.
+ */
+ENTRY(omap34xx_suspend)
+ stmfd sp!, {r0-r12, lr} @ save registers on stack
+loop:
+ /*b loop*/ @Enable to debug by stepping through code
+ /* r0 contains restore pointer in sdram */
+ /* r1 contains information about saving context */
+ ldr r4, sdrc_power @ read the SDRC_POWER register
+ ldr r5, [r4] @ read the contents of SDRC_POWER
+ orr r5, r5, #0x40 @ enable self refresh on idle req
+ str r5, [r4] @ write back to SDRC_POWER register
+
+ cmp r1, #0x0
+ /* If context save is required, do that and execute wfi */
+ bne save_context_wfi
+ /* Data memory barrier and Data sync barrier */
+ mov r1, #0
+ mcr p15, 0, r1, c7, c10, 4
+ mcr p15, 0, r1, c7, c10, 5
+
+ wfi @ wait for interrupt
+
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ bl i_dll_wait
+
+ ldmfd sp!, {r0-r12, pc} @ restore regs and return
+restore:
+ /* b restore*/ @ Enable to debug restore code
+ /* Check what was the reason for mpu reset and store the reason in r9*/
+ /* 1 - Only L1 and logic lost */
+ /* 2 - Only L2 lost - In this case, we wont be here */
+ /* 3 - Both L1 and L2 lost */
+ ldr r1, pm_pwstctrl_mpu
+ ldr r2, [r1]
+ and r2, r2, #0x3
+ cmp r2, #0x0 @ Check if target power state was OFF or RET
+ moveq r9, #0x3 @ MPU OFF => L1 and L2 lost
+ movne r9, #0x1 @ Only L1 and L2 lost => avoid L2 invalidation
+ bne logic_l1_restore
+ /* Execute smi to invalidate L2 cache */
+ mov r12, #0x1 @ set up to invalide L2
+smi: .word 0xE1600070 @ Call SMI monitor (smieq)
+logic_l1_restore:
+ mov r1, #0
+ /* Invalidate all instruction caches to PoU
+ * and flush branch target cache */
+ mcr p15, 0, r1, c7, c5, 0
+
+ ldr r4, scratchpad_base
+ ldr r3, [r4,#0xBC]
+ ldmia r3!, {r4-r6}
+ mov sp, r4
+ msr spsr_cxsf, r5
+ mov lr, r6
+
+ ldmia r3!, {r4-r9}
+ /* Coprocessor access Control Register */
+ mcr p15, 0, r4, c1, c0, 2
+
+ /* TTBR0 */
+ MCR p15, 0, r5, c2, c0, 0
+ /* TTBR1 */
+ MCR p15, 0, r6, c2, c0, 1
+ /* Translation table base control register */
+ MCR p15, 0, r7, c2, c0, 2
+ /*domain access Control Register */
+ MCR p15, 0, r8, c3, c0, 0
+ /* data fault status Register */
+ MCR p15, 0, r9, c5, c0, 0
+
+ ldmia r3!,{r4-r8}
+ /* instruction fault status Register */
+ MCR p15, 0, r4, c5, c0, 1
+ /*Data Auxiliary Fault Status Register */
+ MCR p15, 0, r5, c5, c1, 0
+ /*Instruction Auxiliary Fault Status Register*/
+ MCR p15, 0, r6, c5, c1, 1
+ /*Data Fault Address Register */
+ MCR p15, 0, r7, c6, c0, 0
+ /*Instruction Fault Address Register*/
+ MCR p15, 0, r8, c6, c0, 2
+ ldmia r3!,{r4-r7}
+
+ /* user r/w thread and process ID */
+ MCR p15, 0, r4, c13, c0, 2
+ /* user ro thread and process ID */
+ MCR p15, 0, r5, c13, c0, 3
+ /*Privileged only thread and process ID */
+ MCR p15, 0, r6, c13, c0, 4
+ /* cache size selection */
+ MCR p15, 2, r7, c0, c0, 0
+ ldmia r3!,{r4-r8}
+ /* Data TLB lockdown registers */
+ MCR p15, 0, r4, c10, c0, 0
+ /* Instruction TLB lockdown registers */
+ MCR p15, 0, r5, c10, c0, 1
+ /* Secure or Nonsecure Vector Base Address */
+ MCR p15, 0, r6, c12, c0, 0
+ /* FCSE PID */
+ MCR p15, 0, r7, c13, c0, 0
+ /* Context PID */
+ MCR p15, 0, r8, c13, c0, 1
+
+ ldmia r3!,{r4-r5}
+ /* primary memory remap register */
+ MCR p15, 0, r4, c10, c2, 0
+ /*normal memory remap register */
+ MCR p15, 0, r5, c10, c2, 1
+
+ /* Restore registers for other modes from SDRAM */
+ /* Save current mode */
+ mrs r7, cpsr
+
+ /* FIQ mode */
+ bic r0, r7, #0x1F
+ orr r0, r0, #0x11
+ msr cpsr, r0
+ ldmia r3!, {r8-r12}
+ /* load the SP and LR from SDRAM */
+ ldmia r3!,{r4-r6}
+ mov sp, r4 /*update the SP */
+ mov lr, r5 /*update the LR */
+ msr spsr, r6 /*update the SPSR*/
+
+ /* IRQ mode */
+ bic r0, r7, #0x1F
+ orr r0, r0, #0x12
+ msr cpsr, r0 /*go into IRQ mode*/
+ ldmia r3!,{r4-r6} /*load the SP and LR from SDRAM*/
+ mov sp, r4 /*update the SP */
+ mov lr, r5 /*update the LR */
+ msr spsr, r6 /*update the SPSR */
+
+ /* ABORT mode */
+ bic r0, r7, #0x1F
+ orr r0, r0, #0x17
+ msr cpsr, r0 /* go into ABORT mode */
+ ldmia r3!,{r4-r6} /*load the SP and LR from SDRAM */
+ mov sp, r4 /*update the SP */
+ mov lr, r5 /*update the LR */
+ msr spsr, r6 /*update the SPSR */
+
+ /* UNDEEF mode */
+ bic r0, r7, #0x1F
+ orr r0, r0, #0x1B
+ msr cpsr, r0 /*go into UNDEF mode */
+ ldmia r3!,{r4-r6} /*load the SP and LR from SDRAM */
+ mov sp, r4 /*update the SP*/
+ mov lr, r5 /*update the LR*/
+ msr spsr, r6 /*update the SPSR*/
+
+ /* SYSTEM (USER) mode */
+ bic r0, r7, #0x1F
+ orr r0, r0, #0x1F
+ msr cpsr, r0 /*go into USR mode */
+ ldmia r3!,{r4-r6} /*load the SP and LR from SDRAM*/
+ mov sp, r4 /*update the SP */
+ mov lr, r5 /*update the LR */
+ msr spsr, r6 /*update the SPSR */
+ msr cpsr, r7 /*back to original mode*/
+
+ /* Restore cpsr */
+ ldmia r3!,{r4} /*load CPSR from SDRAM*/
+ msr cpsr, r4 /*store cpsr */
+
+ /* Enabling MMU here */
+ mrc p15, 0, r7, c2, c0, 2 /* Read TTBRControl */
+ /* Extract N (0:2) bits and decide whether to use TTBR0 or TTBR1*/
+ and r7, #0x7
+ cmp r7, #0x0
+ beq usettbr0
+ttbr_error:
+ /* More work needs to be done to support N[0:2] value other than 0
+ * So looping here so that the error can be detected
+ */
+ b ttbr_error
+usettbr0:
+ mrc p15, 0, r2, c2, c0, 0
+ ldr r5, ttbrbit_mask
+ and r2, r5
+ mov r4, pc
+ ldr r5, table_index_mask
+ and r4, r5 /* r4 = 31 to 20 bits of pc */
+ /* Extract the value to be written to table entry */
+ ldr r1, table_entry
+ add r1, r1, r4 /* r1 has value to be written to table entry*/
+ /* Getting the address of table entry to modify */
+ lsr r4, #18
+ add r2, r4 /* r2 has the location which needs to be modified */
+ /* Storing previous entry of location being modified */
+ ldr r5, scratchpad_base
+ ldr r4, [r2]
+ str r4, [r5, #0xC0]
+ /* Modify the table entry */
+ str r1, [r2]
+ /* Storing address of entry being modified
+ * - will be restored after enabling MMU */
+ ldr r5, scratchpad_base
+ str r2, [r5, #0xC4]
+
+ mov r0, #0
+ mcr p15, 0, r0, c7, c5, 4 @ Flush prefetch buffer
+ mcr p15, 0, r0, c7, c5, 6 @ Invalidate branch predictor array
+ mcr p15, 0, r0, c8, c5, 0 @ Invalidate instruction TLB
+ mcr p15, 0, r0, c8, c6, 0 @ Invalidate data TLB
+ /* Restore control register but dont enable caches here*/
+ /* Caches will be enabled after restoring MMU table entry */
+ ldmia r3!, {r4}
+ /* Store previous value of control register in scratchpad */
+ str r4, [r5, #0xC8]
+ ldr r2, cache_pred_disable_mask
+ and r4, r2
+ mcr p15, 0, r4, c1, c0, 0
+
+ ldmfd sp!, {r0-r12, pc} @ restore regs and return
+save_context_wfi:
+ /*b save_context_wfi*/ @ enable to debug save code
+ mov r8, r0 /* Store SDRAM address in r8 */
+ /* Check what that target sleep state is:stored in r1*/
+ /* 1 - Only L1 and logic lost */
+ /* 2 - Only L2 lost */
+ /* 3 - Both L1 and L2 lost */
+ cmp r1, #0x2 /* Only L2 lost */
+ beq clean_l2
+ cmp r1, #0x1 /* L2 retained */
+ /* r9 stores whether to clean L2 or not*/
+ moveq r9, #0x0 /* Dont Clean L2 */
+ movne r9, #0x1 /* Clean L2 */
+l1_logic_lost:
+ /* Store sp and spsr to SDRAM */
+ mov r4, sp
+ mrs r5, spsr
+ mov r6, lr
+ stmia r8!, {r4-r6}
+ /* Save all ARM registers */
+ /* Coprocessor access control register */
+ mrc p15, 0, r6, c1, c0, 2
+ stmia r8!, {r6}
+ /* TTBR0, TTBR1 and Translation table base control */
+ mrc p15, 0, r4, c2, c0, 0
+ mrc p15, 0, r5, c2, c0, 1
+ mrc p15, 0, r6, c2, c0, 2
+ stmia r8!, {r4-r6}
+ /* Domain access control register, data fault status register,
+ and instruction fault status register */
+ mrc p15, 0, r4, c3, c0, 0
+ mrc p15, 0, r5, c5, c0, 0
+ mrc p15, 0, r6, c5, c0, 1
+ stmia r8!, {r4-r6}
+ /* Data aux fault status register, instruction aux fault status,
+ datat fault address register and instruction fault address register*/
+ mrc p15, 0, r4, c5, c1, 0
+ mrc p15, 0, r5, c5, c1, 1
+ mrc p15, 0, r6, c6, c0, 0
+ mrc p15, 0, r7, c6, c0, 2
+ stmia r8!, {r4-r7}
+ /* user r/w thread and process ID, user r/o thread and process ID,
+ priv only thread and process ID, cache size selection */
+ mrc p15, 0, r4, c13, c0, 2
+ mrc p15, 0, r5, c13, c0, 3
+ mrc p15, 0, r6, c13, c0, 4
+ mrc p15, 2, r7, c0, c0, 0
+ stmia r8!, {r4-r7}
+ /* Data TLB lockdown, instruction TLB lockdown registers */
+ mrc p15, 0, r5, c10, c0, 0
+ mrc p15, 0, r6, c10, c0, 1
+ stmia r8!, {r5-r6}
+ /* Secure or non secure vector base address, FCSE PID, Context PID*/
+ mrc p15, 0, r4, c12, c0, 0
+ mrc p15, 0, r5, c13, c0, 0
+ mrc p15, 0, r6, c13, c0, 1
+ stmia r8!, {r4-r6}
+ /* Primary remap, normal remap registers */
+ mrc p15, 0, r4, c10, c2, 0
+ mrc p15, 0, r5, c10, c2, 1
+ stmia r8!,{r4-r5}
+ /* Store SP, LR, SPSR registers for SUP, FIQ, IRQ, ABORT and USER
+ modes into SDRAM */
+
+ /* move SDRAM address to r7 as r8 is banked in FIQ*/
+ mov r7, r8
+
+ /* Save current mode */
+ mrs r2, cpsr
+ /* FIQ mode */
+ bic r0, r2, #0x1F
+ orr r0, r0, #0x11
+ msr cpsr, r0 /* go to FIQ mode */
+ stmia r7!, {r8-r12}
+ mov r4, r13 /* move SP into r4*/
+ mov r5, r14
+ mrs r6, spsr
+ stmia r7!, {r4-r6}
+
+ /* IRQ mode */
+ bic r0, r2, #0x1F
+ orr r0, r0, #0x12
+ msr cpsr, r0
+ mov r4, r13
+ mov r5, r14
+ mrs r6, spsr
+ stmia r7!, {r4-r6}
+
+ /* Abort mode */
+ bic r0, r2, #0x1F
+ orr r0, r0, #0x17
+ msr cpsr, r0
+ mov r4, r13
+ mov r5, r14
+ mrs r6, spsr
+ stmia r7!, {r4-r6}
+
+ /* UNDEF mode */
+ bic r0, r2, #0x1F
+ orr r0, r0, #0x1B
+ msr cpsr, r0
+ mov r4, r13
+ mov r5, r14
+ mrs r6, spsr
+ stmia r7!, {r4-r6}
+
+ /* System (USER mode) */
+ bic r0, r2, #0x1F
+ orr r0, r0, #0x1F
+ msr cpsr, r0
+ mov r4, r13
+ mov r5, r14
+ mrs r6, spsr
+ stmia r7!, {r4-r6}
+
+ /* Back to original mode */
+ msr cpsr, r2
+
+ /* Store current cpsr*/
+ stmia r7!, {r2}
+
+ mrc p15, 0, r4, c1, c0, 0
+ /* save control register */
+ stmia r7!, {r4}
+clean_caches:
+ /* Clean Data or unified cache to POU*/
+ /* How to invalidate only L1 cache???? - #FIX_ME# */
+ /* mcr p15, 0, r11, c7, c11, 1 */
+ cmp r9, #1 /* Check whether L2 inval is required or not*/
+ bne skip_l2_inval
+clean_l2:
+ /* read clidr */
+ mrc p15, 1, r0, c0, c0, 1
+ /* extract loc from clidr */
+ ands r3, r0, #0x7000000
+ /* left align loc bit field */
+ mov r3, r3, lsr #23
+ /* if loc is 0, then no need to clean */
+ beq finished
+ /* start clean at cache level 0 */
+ mov r10, #0
+loop1:
+ /* work out 3x current cache level */
+ add r2, r10, r10, lsr #1
+ /* extract cache type bits from clidr*/
+ mov r1, r0, lsr r2
+ /* mask of the bits for current cache only */
+ and r1, r1, #7
+ /* see what cache we have at this level */
+ cmp r1, #2
+ /* skip if no cache, or just i-cache */
+ blt skip
+ /* select current cache level in cssr */
+ mcr p15, 2, r10, c0, c0, 0
+ /* isb to sych the new cssr&csidr */
+ isb
+ /* read the new csidr */
+ mrc p15, 1, r1, c0, c0, 0
+ /* extract the length of the cache lines */
+ and r2, r1, #7
+ /* add 4 (line length offset) */
+ add r2, r2, #4
+ ldr r4, assoc_mask
+ /* find maximum number on the way size */
+ ands r4, r4, r1, lsr #3
+ /* find bit position of way size increment */
+ clz r5, r4
+ ldr r7, numset_mask
+ /* extract max number of the index size*/
+ ands r7, r7, r1, lsr #13
+loop2:
+ mov r9, r4
+ /* create working copy of max way size*/
+loop3:
+ /* factor way and cache number into r11 */
+ orr r11, r10, r9, lsl r5
+ /* factor index number into r11 */
+ orr r11, r11, r7, lsl r2
+ /*clean & invalidate by set/way */
+ mcr p15, 0, r11, c7, c10, 2
+ /* decrement the way*/
+ subs r9, r9, #1
+ bge loop3
+ /*decrement the index */
+ subs r7, r7, #1
+ bge loop2
+skip:
+ add r10, r10, #2
+ /* increment cache number */
+ cmp r3, r10
+ bgt loop1
+finished:
+ /*swith back to cache level 0 */
+ mov r10, #0
+ /* select current cache level in cssr */
+ mcr p15, 2, r10, c0, c0, 0
+ isb
+skip_l2_inval:
+ /* Data memory barrier and Data sync barrier */
+ mov r1, #0
+ mcr p15, 0, r1, c7, c10, 4
+ mcr p15, 0, r1, c7, c10, 5
+
+ wfi @ wait for interrupt
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ bl i_dll_wait
+ /* restore regs and return */
+ ldmfd sp!, {r0-r12, pc}
+
+i_dll_wait:
+ ldr r4, clk_stabilize_delay
+
+i_dll_delay:
+ subs r4, r4, #0x1
+ bne i_dll_delay
+ ldr r4, sdrc_power
+ ldr r5, [r4]
+ bic r5, r5, #0x40
+ str r5, [r4]
+ bx lr
+pm_prepwstst_core:
+ .word PM_PREPWSTST_CORE_V
+pm_prepwstst_mpu:
+ .word PM_PREPWSTST_MPU_V
+pm_pwstctrl_mpu:
+ .word PM_PWSTCTRL_MPU_P
+scratchpad_base:
+ .word SCRATCHPAD_BASE_P
+sdrc_power:
+ .word SDRC_POWER_V
+context_mem:
+ .word 0x803E3E14
+clk_stabilize_delay:
+ .word 0x000001FF
+assoc_mask:
+ .word 0x3ff
+numset_mask:
+ .word 0x7fff
+ttbrbit_mask:
+ .word 0xFFFFC000
+table_index_mask:
+ .word 0xFFF00000
+table_entry:
+ .word 0x00000C02
+cache_pred_disable_mask:
+ .word 0xFFFFE7FB
+ENTRY(omap34xx_suspend_sz)
+ .word . - omap34xx_suspend
--
1.5.5
^ permalink raw reply related [flat|nested] 16+ messages in thread* [PATCH 6/9] 34XX: Suspend: Use same naming convention in sleep34xx.S as in sleep24XX.S
2008-05-16 10:53 [PATCH 0/9] 34XX: PM: Support for retention on suspend and idle Högander Jouni
` (4 preceding siblings ...)
2008-05-16 10:57 ` [PATCH 5/9] 34XX: Suspend: Take suspend sram code from ti cdp kernel Jouni Hogander
@ 2008-05-16 10:57 ` Jouni Hogander
2008-05-16 10:58 ` [PATCH 7/9] 34XX: Add miscellaneous definitions related to 34xx Jouni Hogander
` (3 subsequent siblings)
9 siblings, 0 replies; 16+ messages in thread
From: Jouni Hogander @ 2008-05-16 10:57 UTC (permalink / raw)
To: linux-omap; +Cc: jouni.hogander
Change omap34xx_suspend to omap34xx_cpu_suspend and
omap34xx_suspend_sz to omap34xx_cpu_suspend_sz.
Do not use PRM_BASE in sleep34xx.S because it is not defined in
linux-omap tree.
Use OMAP343X_SDRC_BASE in sleep34xx.S instead of SDRC_BASE.
Convert all IO_ADDRESS style definitions to OMAP34XX_PRM_REGADDR style
definitions.
Add omap34xx_cpu_suspend and omap34xx_cpu_suspend_sz to
include/asm-arm/arch-omap/pm.h
Do necessary modifications to be able to use arch/arm/mach-omap2/prm.h
and include/asm-arm/arch-omap/control.h ins asm files.
Signed-off-by: Jouni Hogander <jouni.hogander@nokia.com>
---
arch/arm/mach-omap2/prm.h | 7 ++-----
arch/arm/mach-omap2/sleep34xx.S | 28 +++++++++++++++++++---------
include/asm-arm/arch-omap/control.h | 6 ++++++
include/asm-arm/arch-omap/pm.h | 3 +++
4 files changed, 30 insertions(+), 14 deletions(-)
diff --git a/arch/arm/mach-omap2/prm.h b/arch/arm/mach-omap2/prm.h
index e1ce33e..f816165 100644
--- a/arch/arm/mach-omap2/prm.h
+++ b/arch/arm/mach-omap2/prm.h
@@ -14,9 +14,6 @@
* published by the Free Software Foundation.
*/
-#include <linux/io.h>
-#include <linux/bitops.h>
-
#include "prcm-common.h"
#ifndef __ASSEMBLER__
@@ -156,6 +153,8 @@ static __inline__ u32 __attribute__((unused)) prm_rmw_reg_bits(u32 mask,
#define OMAP3430_PRM_IRQSTATUS_IVA2 0x00f8
#define OMAP3430_PRM_IRQENABLE_IVA2 0x00fc
+#ifndef __ASSEMBLER__
+
/* Read-modify-write bits in a PRM register (by domain) */
static u32 __attribute__((unused)) prm_rmw_mod_reg_bits(u32 mask, u32 bits,
s16 module, s16 idx)
@@ -183,8 +182,6 @@ static u32 __attribute__((unused)) prm_clear_mod_reg_bits(u32 bits, s16 module,
#define OMAP24XX_PRCM_IRQSTATUS_IVA 0x00f8
#define OMAP24XX_PRCM_IRQENABLE_IVA 0x00fc
-#ifndef __ASSEMBLER__
-
/* Power/reset management domain register get/set */
static __inline__ void __attribute__((unused)) prm_write_mod_reg(u32 val,
diff --git a/arch/arm/mach-omap2/sleep34xx.S b/arch/arm/mach-omap2/sleep34xx.S
index c9db507..ebc7eb3 100644
--- a/arch/arm/mach-omap2/sleep34xx.S
+++ b/arch/arm/mach-omap2/sleep34xx.S
@@ -28,12 +28,22 @@
#include <asm/assembler.h>
#include <asm/arch/io.h>
#include <asm/arch/pm.h>
-
-#define PM_PREPWSTST_CORE_V IO_ADDRESS(PRM_BASE + 0xAE8)
-#define PM_PREPWSTST_MPU_V IO_ADDRESS(PRM_BASE + 0x9E8)
-#define PM_PWSTCTRL_MPU_P (PRM_BASE + 0x9E0)
-#define SCRATCHPAD_BASE_P 0x48002910
-#define SDRC_POWER_V IO_ADDRESS(SDRC_BASE + 0x070)
+#include <asm/arch/control.h>
+
+#include "prm.h"
+#include "sdrc.h"
+
+#define PM_PREPWSTST_CORE_V OMAP34XX_PRM_REGADDR(CORE_MOD, \
+ OMAP3430_PM_PREPWSTST)
+#define PM_PREPWSTST_MPU_V OMAP34XX_PRM_REGADDR(MPU_MOD, \
+ OMAP3430_PM_PREPWSTST)
+#define PM_PWSTCTRL_MPU_P OMAP34XX_PRM_REGADDR(MPU_MOD, PM_PWSTCTRL)
+#define SCRATCHPAD_MEM_OFFS 0x310 /* Move this as correct place is
+ * available */
+#define SCRATCHPAD_BASE_P OMAP343X_CTRL_REGADDR(\
+ OMAP343X_CONTROL_MEM_WKUP +\
+ SCRATCHPAD_MEM_OFFS)
+#define SDRC_POWER_V OMAP34XX_SDRC_REGADDR(SDRC_POWER)
.text
/* Function call to get the restore pointer for resume from OFF */
@@ -52,7 +62,7 @@ ENTRY(get_restore_pointer_sz)
* Note: This code get's copied to internal SRAM at boot. When the OMAP
* wakes up it continues execution at the point it went to sleep.
*/
-ENTRY(omap34xx_suspend)
+ENTRY(omap34xx_cpu_suspend)
stmfd sp!, {r0-r12, lr} @ save registers on stack
loop:
/*b loop*/ @Enable to debug by stepping through code
@@ -530,5 +540,5 @@ table_entry:
.word 0x00000C02
cache_pred_disable_mask:
.word 0xFFFFE7FB
-ENTRY(omap34xx_suspend_sz)
- .word . - omap34xx_suspend
+ENTRY(omap34xx_cpu_suspend_sz)
+ .word . - omap34xx_cpu_suspend
diff --git a/include/asm-arm/arch-omap/control.h b/include/asm-arm/arch-omap/control.h
index 0832348..1d95cc2 100644
--- a/include/asm-arm/arch-omap/control.h
+++ b/include/asm-arm/arch-omap/control.h
@@ -18,12 +18,18 @@
#include <asm/arch/io.h>
+#ifndef __ASSEMBLY__
#define OMAP242X_CTRL_REGADDR(reg) \
(__force void __iomem *)IO_ADDRESS(OMAP242X_CTRL_BASE + (reg))
#define OMAP243X_CTRL_REGADDR(reg) \
(__force void __iomem *)IO_ADDRESS(OMAP243X_CTRL_BASE + (reg))
#define OMAP343X_CTRL_REGADDR(reg) \
(__force void __iomem *)IO_ADDRESS(OMAP343X_CTRL_BASE + (reg))
+#else
+#define OMAP242X_CTRL_REGADDR(reg) IO_ADDRESS(OMAP242X_CTRL_BASE + (reg))
+#define OMAP243X_CTRL_REGADDR(reg) IO_ADDRESS(OMAP243X_CTRL_BASE + (reg))
+#define OMAP343X_CTRL_REGADDR(reg) IO_ADDRESS(OMAP343X_CTRL_BASE + (reg))
+#endif /* __ASSEMBLY__ */
/*
* As elsewhere, the "OMAP2_" prefix indicates that the macro is valid for
diff --git a/include/asm-arm/arch-omap/pm.h b/include/asm-arm/arch-omap/pm.h
index 0ce03fd..d0c7d4d 100644
--- a/include/asm-arm/arch-omap/pm.h
+++ b/include/asm-arm/arch-omap/pm.h
@@ -146,6 +146,7 @@ extern void omap730_cpu_suspend(unsigned short, unsigned short);
extern void omap1510_cpu_suspend(unsigned short, unsigned short);
extern void omap1610_cpu_suspend(unsigned short, unsigned short);
extern void omap24xx_cpu_suspend(u32 dll_ctrl, u32 cpu_revision);
+extern void omap34xx_cpu_suspend(u32 *addr, int save_state);
extern void omap730_idle_loop_suspend(void);
extern void omap1510_idle_loop_suspend(void);
extern void omap1610_idle_loop_suspend(void);
@@ -155,10 +156,12 @@ extern unsigned int omap730_cpu_suspend_sz;
extern unsigned int omap1510_cpu_suspend_sz;
extern unsigned int omap1610_cpu_suspend_sz;
extern unsigned int omap24xx_cpu_suspend_sz;
+extern unsigned int omap34xx_cpu_suspend_sz;
extern unsigned int omap730_idle_loop_suspend_sz;
extern unsigned int omap1510_idle_loop_suspend_sz;
extern unsigned int omap1610_idle_loop_suspend_sz;
extern unsigned int omap24xx_idle_loop_suspend_sz;
+extern unsigned int omap34xx_suspend_sz;
#ifdef CONFIG_OMAP_SERIAL_WAKE
extern void omap_serial_wake_trigger(int enable);
--
1.5.5
^ permalink raw reply related [flat|nested] 16+ messages in thread* [PATCH 7/9] 34XX: Add miscellaneous definitions related to 34xx
2008-05-16 10:53 [PATCH 0/9] 34XX: PM: Support for retention on suspend and idle Högander Jouni
` (5 preceding siblings ...)
2008-05-16 10:57 ` [PATCH 6/9] 34XX: Suspend: Use same naming convention in sleep34xx.S as in sleep24XX.S Jouni Hogander
@ 2008-05-16 10:58 ` Jouni Hogander
2008-05-16 10:58 ` [PATCH 8/9] 34XX: PM: Initial version of suspend and dynamic retention Jouni Hogander
` (2 subsequent siblings)
9 siblings, 0 replies; 16+ messages in thread
From: Jouni Hogander @ 2008-05-16 10:58 UTC (permalink / raw)
To: linux-omap; +Cc: jouni.hogander
Signed-off-by: Jouni Hogander <jouni.hogander@nokia.com>
---
arch/arm/mach-omap2/cm-regbits-34xx.h | 7 +++++++
arch/arm/mach-omap2/prm-regbits-34xx.h | 9 +++++++++
arch/arm/mach-omap2/prm.h | 24 +++++++++++++-----------
include/asm-arm/arch-omap/irqs.h | 1 +
4 files changed, 30 insertions(+), 11 deletions(-)
diff --git a/arch/arm/mach-omap2/cm-regbits-34xx.h b/arch/arm/mach-omap2/cm-regbits-34xx.h
index 219f5c8..6ec66f4 100644
--- a/arch/arm/mach-omap2/cm-regbits-34xx.h
+++ b/arch/arm/mach-omap2/cm-regbits-34xx.h
@@ -208,6 +208,10 @@
#define OMAP3430ES2_ST_USBTLL_MASK (1 << 2)
/* CM_AUTOIDLE1_CORE */
+#define OMAP3430ES2_AUTO_MMC3 (1 << 30)
+#define OMAP3430ES2_AUTO_MMC3_SHIFT 30
+#define OMAP3430ES2_AUTO_ICR (1 << 29)
+#define OMAP3430ES2_AUTO_ICR_SHIFT 29
#define OMAP3430_AUTO_AES2 (1 << 28)
#define OMAP3430_AUTO_AES2_SHIFT 28
#define OMAP3430_AUTO_SHA12 (1 << 27)
@@ -276,6 +280,9 @@
#define OMAP3430_AUTO_DES1_SHIFT 0
/* CM_AUTOIDLE3_CORE */
+#define OMAP3430ES2_AUTO_USBHOST (1 << 0)
+#define OMAP3430ES2_AUTO_USBHOST_SHIFT 0
+#define OMAP3430ES2_AUTO_USBTLL (1 << 2)
#define OMAP3430ES2_AUTO_USBTLL_SHIFT 2
#define OMAP3430ES2_AUTO_USBTLL_MASK (1 << 2)
diff --git a/arch/arm/mach-omap2/prm-regbits-34xx.h b/arch/arm/mach-omap2/prm-regbits-34xx.h
index 5b5ecfe..c6a7940 100644
--- a/arch/arm/mach-omap2/prm-regbits-34xx.h
+++ b/arch/arm/mach-omap2/prm-regbits-34xx.h
@@ -366,6 +366,7 @@
/* PM_WKEN_WKUP specific bits */
#define OMAP3430_EN_IO (1 << 8)
+#define OMAP3430_EN_GPIO1 (1 << 3)
/* PM_MPUGRPSEL_WKUP specific bits */
@@ -452,6 +453,14 @@
#define OMAP3430_CMDRA0_MASK (0xff << 0)
/* PRM_VC_CMD_VAL_0 specific bits */
+#define OMAP3430_VC_CMD_ON_SHIFT 24
+#define OMAP3430_VC_CMD_ON_MASK (0xFF << 24)
+#define OMAP3430_VC_CMD_ONLP_SHIFT 16
+#define OMAP3430_VC_CMD_ONLP_MASK (0xFF << 16)
+#define OMAP3430_VC_CMD_RET_SHIFT 8
+#define OMAP3430_VC_CMD_RET_MASK (0xFF << 8)
+#define OMAP3430_VC_CMD_OFF_SHIFT 0
+#define OMAP3430_VC_CMD_OFF_MASK (0xFF << 0)
/* PRM_VC_CMD_VAL_1 specific bits */
diff --git a/arch/arm/mach-omap2/prm.h b/arch/arm/mach-omap2/prm.h
index f816165..27d44e2 100644
--- a/arch/arm/mach-omap2/prm.h
+++ b/arch/arm/mach-omap2/prm.h
@@ -142,6 +142,19 @@ static __inline__ u32 __attribute__((unused)) prm_rmw_reg_bits(u32 mask,
#define PM_PWSTCTRL 0x00e0
#define PM_PWSTST 0x00e4
+/* Omap2 specific registers */
+#define OMAP24XX_PM_WKEN2 0x00a4
+#define OMAP24XX_PM_WKST2 0x00b4
+
+#define OMAP24XX_PRCM_IRQSTATUS_DSP 0x00f0 /* IVA mod */
+#define OMAP24XX_PRCM_IRQENABLE_DSP 0x00f4 /* IVA mod */
+#define OMAP24XX_PRCM_IRQSTATUS_IVA 0x00f8
+#define OMAP24XX_PRCM_IRQENABLE_IVA 0x00fc
+
+/* Omap3 specific registers */
+#define OMAP3430ES2_PM_WKEN3 0x00f0
+#define OMAP3430ES2_PM_WKST3 0x00b8
+
#define OMAP3430_PM_MPUGRPSEL 0x00a4
#define OMAP3430_PM_MPUGRPSEL1 OMAP3430_PM_MPUGRPSEL
@@ -172,16 +185,6 @@ static u32 __attribute__((unused)) prm_clear_mod_reg_bits(u32 bits, s16 module,
return prm_rmw_mod_reg_bits(bits, 0x0, module, idx);
}
-/* Architecture-specific registers */
-
-#define OMAP24XX_PM_WKEN2 0x00a4
-#define OMAP24XX_PM_WKST2 0x00b4
-
-#define OMAP24XX_PRCM_IRQSTATUS_DSP 0x00f0 /* IVA mod */
-#define OMAP24XX_PRCM_IRQENABLE_DSP 0x00f4 /* IVA mod */
-#define OMAP24XX_PRCM_IRQSTATUS_IVA 0x00f8
-#define OMAP24XX_PRCM_IRQENABLE_IVA 0x00fc
-
/* Power/reset management domain register get/set */
static __inline__ void __attribute__((unused)) prm_write_mod_reg(u32 val,
@@ -243,7 +246,6 @@ static __inline__ u32 __attribute__((unused)) prm_read_mod_reg(s16 module,
#define OMAP_RSTTIME1_SHIFT 0
#define OMAP_RSTTIME1_MASK (0xff << 0)
-
/* PRM_RSTCTRL */
/* Named RM_RSTCTRL_WKUP on the 24xx */
/* 2420 calls RST_DPLL3 'RST_DPLL' */
diff --git a/include/asm-arm/arch-omap/irqs.h b/include/asm-arm/arch-omap/irqs.h
index 343e93e..f901e8b 100644
--- a/include/asm-arm/arch-omap/irqs.h
+++ b/include/asm-arm/arch-omap/irqs.h
@@ -300,6 +300,7 @@
#define INT_34XX_ST_MCBSP2_IRQ 4
#define INT_34XX_ST_MCBSP3_IRQ 5
#define INT_34XX_SYS_NIRQ 7
+#define INT_34XX_PRCM_MPU_IRQ 11
#define INT_34XX_MCBSP1_IRQ 16
#define INT_34XX_MCBSP2_IRQ 17
#define INT_34XX_MCBSP3_IRQ 22
--
1.5.5
^ permalink raw reply related [flat|nested] 16+ messages in thread* [PATCH 8/9] 34XX: PM: Initial version of suspend and dynamic retention
2008-05-16 10:53 [PATCH 0/9] 34XX: PM: Support for retention on suspend and idle Högander Jouni
` (6 preceding siblings ...)
2008-05-16 10:58 ` [PATCH 7/9] 34XX: Add miscellaneous definitions related to 34xx Jouni Hogander
@ 2008-05-16 10:58 ` Jouni Hogander
2008-05-16 10:58 ` [PATCH 9/9] OMAP3430SDP: Enable config options CONFIG_OMAP_RESET_CLOCKS and CONFIG_SUSPEND Jouni Hogander
2008-05-20 22:13 ` [PATCH 0/9] 34XX: PM: Support for retention on suspend and idle Tony Lindgren
9 siblings, 0 replies; 16+ messages in thread
From: Jouni Hogander @ 2008-05-16 10:58 UTC (permalink / raw)
To: linux-omap; +Cc: jouni.hogander
This is initial version of suspend and dynamic retention for
34xx. Omap is tried to put to full retention on suspend and pm_idle.
Signed-off-by: Jouni Hogander <jouni.hogander@nokia.com>
---
arch/arm/mach-omap2/Makefile | 3 +
arch/arm/mach-omap2/pm.c | 4 +-
arch/arm/mach-omap2/pm.h | 2 +
arch/arm/mach-omap2/pm34xx.c | 386 ++++++++++++++++++++++++++++++++++++++++++
4 files changed, 394 insertions(+), 1 deletions(-)
create mode 100644 arch/arm/mach-omap2/pm34xx.c
diff --git a/arch/arm/mach-omap2/Makefile b/arch/arm/mach-omap2/Makefile
index 12f6a6f..6168aa4 100644
--- a/arch/arm/mach-omap2/Makefile
+++ b/arch/arm/mach-omap2/Makefile
@@ -18,6 +18,9 @@ ifeq ($(CONFIG_ARCH_OMAP2),y)
obj-$(CONFIG_PM) += pm24xx.o sleep24xx.o
endif
+ifeq ($(CONFIG_ARCH_OMAP3),y)
+obj-$(CONFIG_PM) += pm34xx.o sleep34xx.o
+endif
obj-$(CONFIG_PM_DEBUG) += pm-debug.o
# Clock framework
diff --git a/arch/arm/mach-omap2/pm.c b/arch/arm/mach-omap2/pm.c
index 55ed75b..bef58d7 100644
--- a/arch/arm/mach-omap2/pm.c
+++ b/arch/arm/mach-omap2/pm.c
@@ -74,8 +74,10 @@ int __init omap_pm_init(void)
if (cpu_is_omap24xx())
error = omap2_pm_init();
+ if (cpu_is_omap34xx())
+ error = omap3_pm_init();
if (error) {
- printk(KERN_ERR "omap2_pm_init failed: %d\n", error);
+ printk(KERN_ERR "omap2|3_pm_init failed: %d\n", error);
return error;
}
diff --git a/arch/arm/mach-omap2/pm.h b/arch/arm/mach-omap2/pm.h
index 15482ba..351456e 100644
--- a/arch/arm/mach-omap2/pm.h
+++ b/arch/arm/mach-omap2/pm.h
@@ -14,6 +14,8 @@
*/
extern int omap2_pm_init(void);
+extern int omap3_pm_init(void);
+
extern unsigned short enable_dyn_sleep;
extern atomic_t sleep_block;
diff --git a/arch/arm/mach-omap2/pm34xx.c b/arch/arm/mach-omap2/pm34xx.c
new file mode 100644
index 0000000..a1bfb30
--- /dev/null
+++ b/arch/arm/mach-omap2/pm34xx.c
@@ -0,0 +1,386 @@
+/*
+ * linux/arch/arm/mach-omap2/pm34xx.c
+ *
+ * OMAP3 Power Management Routines
+ *
+ * Copyright (C) 2006-2008 Nokia Corporation
+ * Tony Lindgren <tony@atomide.com>
+ * Jouni Hogander
+ *
+ * Copyright (C) 2005 Texas Instruments, Inc.
+ * Richard Woodruff <r-woodruff2@ti.com>
+ *
+ * Based on pm.c for omap1
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/pm.h>
+#include <linux/suspend.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/list.h>
+#include <linux/err.h>
+
+#include <asm/arch/gpio.h>
+#include <asm/arch/sram.h>
+#include <asm/arch/pm.h>
+#include <asm/arch/clockdomain.h>
+#include <asm/arch/powerdomain.h>
+
+#include "cm.h"
+#include "cm-regbits-34xx.h"
+#include "prm-regbits-34xx.h"
+
+#include "prm.h"
+#include "pm.h"
+
+struct power_state {
+ struct powerdomain *pwrdm;
+ u32 next_state;
+ u32 saved_state;
+ struct list_head node;
+};
+
+static LIST_HEAD(pwrst_list);
+
+void (*_omap_sram_idle)(u32 *addr, int save_state);
+
+static void (*saved_idle)(void);
+
+static struct powerdomain *mpu_pwrdm;
+
+/* PRCM Interrupt Handler for wakeups */
+static irqreturn_t prcm_interrupt_handler (int irq, void *dev_id)
+{
+ u32 wkst, irqstatus_mpu;
+ u32 fclk, iclk;
+
+ /* WKUP */
+ wkst = prm_read_mod_reg(WKUP_MOD, PM_WKST);
+ if (wkst) {
+ iclk = cm_read_mod_reg(WKUP_MOD, CM_ICLKEN);
+ fclk = cm_read_mod_reg(WKUP_MOD, CM_FCLKEN);
+ cm_set_mod_reg_bits(wkst, WKUP_MOD, CM_ICLKEN);
+ cm_set_mod_reg_bits(wkst, WKUP_MOD, CM_FCLKEN);
+ prm_write_mod_reg(wkst, WKUP_MOD, PM_WKST);
+ while (prm_read_mod_reg(WKUP_MOD, PM_WKST));
+ cm_write_mod_reg(iclk, WKUP_MOD, CM_ICLKEN);
+ cm_write_mod_reg(fclk, WKUP_MOD, CM_FCLKEN);
+ }
+
+ /* CORE */
+ wkst = prm_read_mod_reg(CORE_MOD, PM_WKST1);
+ if (wkst) {
+ iclk = cm_read_mod_reg(CORE_MOD, CM_ICLKEN1);
+ fclk = cm_read_mod_reg(CORE_MOD, CM_FCLKEN1);
+ cm_set_mod_reg_bits(wkst, CORE_MOD, CM_ICLKEN1);
+ cm_set_mod_reg_bits(wkst, CORE_MOD, CM_FCLKEN1);
+ prm_write_mod_reg(wkst, CORE_MOD, PM_WKST1);
+ while (prm_read_mod_reg(CORE_MOD, PM_WKST1));
+ cm_write_mod_reg(iclk, CORE_MOD, CM_ICLKEN1);
+ cm_write_mod_reg(fclk, CORE_MOD, CM_FCLKEN1);
+ }
+ wkst = prm_read_mod_reg(CORE_MOD, OMAP3430ES2_PM_WKST3);
+ if (wkst) {
+ iclk = cm_read_mod_reg(CORE_MOD, CM_ICLKEN3);
+ fclk = cm_read_mod_reg(CORE_MOD, OMAP3430ES2_CM_FCLKEN3);
+ cm_set_mod_reg_bits(wkst, CORE_MOD, CM_ICLKEN3);
+ cm_set_mod_reg_bits(wkst, CORE_MOD, OMAP3430ES2_CM_FCLKEN3);
+ prm_write_mod_reg(wkst, CORE_MOD, OMAP3430ES2_PM_WKST3);
+ while (prm_read_mod_reg(CORE_MOD, OMAP3430ES2_PM_WKST3));
+ cm_write_mod_reg(iclk, CORE_MOD, CM_ICLKEN3);
+ cm_write_mod_reg(fclk, CORE_MOD, OMAP3430ES2_CM_FCLKEN3);
+ }
+
+ /* PER */
+ wkst = prm_read_mod_reg(OMAP3430_PER_MOD, PM_WKST);
+ if (wkst) {
+ iclk = cm_read_mod_reg(OMAP3430_PER_MOD, CM_ICLKEN);
+ fclk = cm_read_mod_reg(OMAP3430_PER_MOD, CM_FCLKEN);
+ cm_set_mod_reg_bits(wkst, OMAP3430_PER_MOD, CM_ICLKEN);
+ cm_set_mod_reg_bits(wkst, OMAP3430_PER_MOD, CM_FCLKEN);
+ prm_write_mod_reg(wkst, OMAP3430_PER_MOD, PM_WKST);
+ while (prm_read_mod_reg(OMAP3430_PER_MOD, PM_WKST));
+ cm_write_mod_reg(iclk, OMAP3430_PER_MOD, CM_ICLKEN);
+ cm_write_mod_reg(fclk, OMAP3430_PER_MOD, CM_FCLKEN);
+ }
+
+ if (is_sil_rev_greater_than(OMAP3430_REV_ES1_0)) {
+ /* USBHOST */
+ wkst = prm_read_mod_reg(OMAP3430ES2_USBHOST_MOD, PM_WKST);
+ if (wkst) {
+ iclk = cm_read_mod_reg(OMAP3430ES2_USBHOST_MOD,
+ CM_ICLKEN);
+ fclk = cm_read_mod_reg(OMAP3430ES2_USBHOST_MOD,
+ CM_FCLKEN);
+ cm_set_mod_reg_bits(wkst, OMAP3430ES2_USBHOST_MOD,
+ CM_ICLKEN);
+ cm_set_mod_reg_bits(wkst, OMAP3430ES2_USBHOST_MOD,
+ CM_FCLKEN);
+ prm_write_mod_reg(wkst, OMAP3430ES2_USBHOST_MOD,
+ PM_WKST);
+ while (prm_read_mod_reg(OMAP3430ES2_USBHOST_MOD,
+ PM_WKST));
+ cm_write_mod_reg(iclk, OMAP3430ES2_USBHOST_MOD,
+ CM_ICLKEN);
+ cm_write_mod_reg(fclk, OMAP3430ES2_USBHOST_MOD,
+ CM_FCLKEN);
+ }
+ }
+
+ irqstatus_mpu = __raw_readl(OMAP3430_PRM_IRQSTATUS_MPU);
+ __raw_writel(irqstatus_mpu, OMAP3430_PRM_IRQSTATUS_MPU);
+ while (__raw_readl(OMAP3430_PRM_IRQSTATUS_MPU));
+
+ return IRQ_HANDLED;
+}
+
+static void omap_sram_idle(void)
+{
+ /* Variable to tell what needs to be saved and restored
+ * in omap_sram_idle*/
+ /* save_state = 0 => Nothing to save and restored */
+ /* save_state = 1 => Only L1 and logic lost */
+ /* save_state = 2 => Only L2 lost */
+ /* save_state = 3 => L1, L2 and logic lost */
+ int save_state = 0, mpu_next_state;
+
+ if (!_omap_sram_idle)
+ return;
+
+ mpu_next_state = pwrdm_read_next_pwrst(mpu_pwrdm);
+ switch (mpu_next_state) {
+ case PWRDM_POWER_RET:
+ /* No need to save context */
+ save_state = 0;
+ break;
+ default:
+ /* Invalid state */
+ printk(KERN_ERR "Invalid mpu state in sram_idle\n");
+ return;
+ }
+
+ omap2_gpio_prepare_for_retention();
+
+ _omap_sram_idle(NULL, save_state);
+
+ omap2_gpio_resume_after_retention();
+}
+
+static int omap3_can_sleep(void)
+{
+ if (!enable_dyn_sleep)
+ return 0;
+ if (atomic_read(&sleep_block) > 0)
+ return 0;
+ return 1;
+}
+
+/* This sets pwrdm state (other than mpu & core. Currently only ON &
+ * RET are supported. Function is assuming that clkdm doesn't have
+ * hw_sup mode enabled. */
+static int set_pwrdm_state(struct powerdomain *pwrdm, u32 state)
+{
+ u32 cur_state;
+ int ret = 0;
+ int i = 0;
+
+ if (pwrdm == NULL || IS_ERR(pwrdm))
+ return -EINVAL;
+
+ cur_state = pwrdm_read_next_pwrst(pwrdm);
+
+ if (cur_state == state)
+ return ret;
+
+ for (i = 0; pwrdm->pwrdm_clkdms[i]; i++)
+ omap2_clkdm_deny_idle(pwrdm->pwrdm_clkdms[i]);
+
+ ret = pwrdm_set_next_pwrst(pwrdm, state);
+ if (ret) {
+ printk(KERN_ERR "Unable to set state of powerdomain: %s\n",
+ pwrdm->name);
+ goto err;
+ }
+
+ for (i = 0; pwrdm->pwrdm_clkdms[i]; i++)
+ omap2_clkdm_allow_idle(pwrdm->pwrdm_clkdms[i]);
+
+err:
+ return ret;
+}
+
+static void omap3_pm_idle(void)
+{
+ local_irq_disable();
+ local_fiq_disable();
+
+ if (!omap3_can_sleep())
+ goto out;
+
+ if (omap_irq_pending())
+ goto out;
+
+ omap_sram_idle();
+
+out:
+ local_fiq_enable();
+ local_irq_enable();
+}
+
+static int omap3_pm_prepare(void)
+{
+ saved_idle = pm_idle;
+ pm_idle = NULL;
+ return 0;
+}
+
+static int omap3_pm_suspend(void)
+{
+ struct power_state *pwrst;
+ int state, ret = 0;
+
+ /* Read current next_pwrsts */
+ list_for_each_entry(pwrst, &pwrst_list, node)
+ pwrst->saved_state = pwrdm_read_next_pwrst(pwrst->pwrdm);
+ /* Set ones wanted by suspend */
+ list_for_each_entry(pwrst, &pwrst_list, node) {
+ if (set_pwrdm_state(pwrst->pwrdm, pwrst->next_state))
+ goto restore;
+ if (pwrdm_clear_all_prev_pwrst(pwrst->pwrdm))
+ goto restore;
+ }
+
+ omap_sram_idle();
+
+restore:
+ /* Restore next_pwrsts */
+ list_for_each_entry(pwrst, &pwrst_list, node) {
+ set_pwrdm_state(pwrst->pwrdm, pwrst->saved_state);
+ state = pwrdm_read_prev_pwrst(pwrst->pwrdm);
+ if (state != pwrst->next_state) {
+ printk(KERN_INFO "Powerdomain (%s) didn't enter "
+ "target state %d\n",
+ pwrst->pwrdm->name, pwrst->next_state);
+ ret = -1;
+ }
+ }
+ if (ret)
+ printk(KERN_ERR "Could not enter target state in pm_suspend\n");
+ else
+ printk(KERN_INFO "Successfully put all powerdomains "
+ "to target state\n");
+
+ return ret;
+}
+
+static int omap3_pm_enter(suspend_state_t state)
+{
+ int ret = 0;
+
+ switch (state) {
+ case PM_SUSPEND_STANDBY:
+ case PM_SUSPEND_MEM:
+ ret = omap3_pm_suspend();
+ break;
+ default:
+ ret = -EINVAL;
+ }
+
+ return ret;
+}
+
+static void omap3_pm_finish(void)
+{
+ pm_idle = saved_idle;
+}
+
+static struct platform_suspend_ops omap_pm_ops = {
+ .prepare = omap3_pm_prepare,
+ .enter = omap3_pm_enter,
+ .finish = omap3_pm_finish,
+ .valid = suspend_valid_only_mem,
+};
+
+static void __init prcm_setup_regs(void)
+{
+ u32 v;
+
+ /* setup wakup source */
+ prm_write_mod_reg(OMAP3430_EN_IO | OMAP3430_EN_GPIO1 | OMAP3430_EN_GPT1,
+ WKUP_MOD, PM_WKEN);
+ /* No need to write EN_IO, that is always enabled */
+ prm_write_mod_reg(OMAP3430_EN_GPIO1 | OMAP3430_EN_GPT1,
+ WKUP_MOD, OMAP3430_PM_MPUGRPSEL);
+ /* For some reason IO doesn't generate wakeup event even if
+ * it is selected to mpu wakeup goup */
+ __raw_writel(OMAP3430_IO_EN | OMAP3430_WKUP_EN,
+ OMAP3430_PRM_IRQENABLE_MPU);
+}
+
+static int __init pwrdms_setup(struct powerdomain *pwrdm)
+{
+ struct power_state *pwrst;
+
+ if (!pwrdm->pwrsts)
+ return 0;
+
+ pwrst = kmalloc(sizeof(struct power_state), GFP_KERNEL);
+ if (!pwrst)
+ return -ENOMEM;
+ pwrst->pwrdm = pwrdm;
+ pwrst->next_state = PWRDM_POWER_RET;
+ list_add(&pwrst->node, &pwrst_list);
+ return set_pwrdm_state(pwrst->pwrdm, pwrst->next_state);
+}
+
+int __init omap3_pm_init(void)
+{
+ struct power_state *pwrst;
+ int ret;
+
+ printk(KERN_ERR "Power Management for TI OMAP3.\n");
+
+ ret = request_irq(INT_34XX_PRCM_MPU_IRQ,
+ (irq_handler_t)prcm_interrupt_handler,
+ IRQF_DISABLED, "prcm", NULL);
+ if (ret) {
+ printk(KERN_ERR "request_irq failed to register for 0x%x\n",
+ INT_34XX_PRCM_MPU_IRQ);
+ goto err1;
+ }
+
+ ret = pwrdm_for_each(pwrdms_setup);
+ if (ret) {
+ printk(KERN_ERR "Failed to setup powerdomains\n");
+ goto err2;
+ }
+
+ mpu_pwrdm = pwrdm_lookup("mpu_pwrdm");
+ if (mpu_pwrdm == NULL) {
+ printk(KERN_ERR "Failed to get mpu_pwrdm\n");
+ goto err2;
+ }
+
+ _omap_sram_idle = omap_sram_push(omap34xx_cpu_suspend,
+ omap34xx_cpu_suspend_sz);
+
+ suspend_set_ops(&omap_pm_ops);
+
+ prcm_setup_regs();
+
+ pm_idle = omap3_pm_idle;
+
+err1:
+ return ret;
+err2:
+ free_irq(INT_34XX_PRCM_MPU_IRQ, NULL);
+ list_for_each_entry(pwrst, &pwrst_list, node) {
+ list_del(&pwrst->node);
+ kfree(pwrst);
+ }
+ return ret;
+}
--
1.5.5
^ permalink raw reply related [flat|nested] 16+ messages in thread* [PATCH 9/9] OMAP3430SDP: Enable config options CONFIG_OMAP_RESET_CLOCKS and CONFIG_SUSPEND
2008-05-16 10:53 [PATCH 0/9] 34XX: PM: Support for retention on suspend and idle Högander Jouni
` (7 preceding siblings ...)
2008-05-16 10:58 ` [PATCH 8/9] 34XX: PM: Initial version of suspend and dynamic retention Jouni Hogander
@ 2008-05-16 10:58 ` Jouni Hogander
2008-05-20 22:13 ` [PATCH 0/9] 34XX: PM: Support for retention on suspend and idle Tony Lindgren
9 siblings, 0 replies; 16+ messages in thread
From: Jouni Hogander @ 2008-05-16 10:58 UTC (permalink / raw)
To: linux-omap; +Cc: jouni.hogander
Signed-off-by: Jouni Hogander <jouni.hogander@nokia.com>
---
arch/arm/configs/omap_3430sdp_defconfig | 4 ++--
1 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/arch/arm/configs/omap_3430sdp_defconfig b/arch/arm/configs/omap_3430sdp_defconfig
index 0fef29d..9e4af26 100644
--- a/arch/arm/configs/omap_3430sdp_defconfig
+++ b/arch/arm/configs/omap_3430sdp_defconfig
@@ -168,7 +168,7 @@ CONFIG_ARCH_OMAP3=y
# OMAP Feature Selections
#
CONFIG_OMAP_DEBUG_SRAM_PATCH=y
-# CONFIG_OMAP_RESET_CLOCKS is not set
+CONFIG_OMAP_RESET_CLOCKS=y
CONFIG_OMAP_BOOT_TAG=y
CONFIG_OMAP_BOOT_REASON=y
# CONFIG_OMAP_COMPONENT_VERSION is not set
@@ -308,7 +308,7 @@ CONFIG_BINFMT_MISC=y
CONFIG_PM=y
# CONFIG_PM_LEGACY is not set
# CONFIG_PM_DEBUG is not set
-# CONFIG_SUSPEND is not set
+CONFIG_SUSPEND=y
# CONFIG_APM_EMULATION is not set
CONFIG_ARCH_SUSPEND_POSSIBLE=y
--
1.5.5
^ permalink raw reply related [flat|nested] 16+ messages in thread* Re: [PATCH 0/9] 34XX: PM: Support for retention on suspend and idle
2008-05-16 10:53 [PATCH 0/9] 34XX: PM: Support for retention on suspend and idle Högander Jouni
` (8 preceding siblings ...)
2008-05-16 10:58 ` [PATCH 9/9] OMAP3430SDP: Enable config options CONFIG_OMAP_RESET_CLOCKS and CONFIG_SUSPEND Jouni Hogander
@ 2008-05-20 22:13 ` Tony Lindgren
9 siblings, 0 replies; 16+ messages in thread
From: Tony Lindgren @ 2008-05-20 22:13 UTC (permalink / raw)
To: Högander Jouni; +Cc: linux-omap, paul
* Högander Jouni <jouni.hogander@nokia.com> [080516 03:54]:
> This patch set adds suspend and pm idle support for omap3. There are
> still lots of missing stuff so omap doesn't enter full retention
> without workaround patches. Workaround patches are sent in separate
> set.
>
> You can try these by applying this set and workaround set. Then boot
> the device and do "echo mem > /sys/power/state". Dynamic retention can
> be tried by "echo 1 > /sys/power/sleep_while_idle". There is one
> pending patch by Felipe Balbi (ARCH: OMAP: MUSB: Do not block sleep)
> addition to this and workaround set which is needed dynamic idle to
> work. Enabling dynamic idle has nasty side effect that serial console
> stops to work. This happens only if you enable it by "echo 1 >
> /sys/power/sleep_while_idle"
>
> I have tested these patches on TI 3430 SDP ES2.0 board.
Pushing this series today.
Tony
--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 16+ messages in thread