Commit 6ec4c57d authored by Tony Lindgren's avatar Tony Lindgren

ARM: OMAP: Add minimal PM support for omap2

This patch adds minimal pm.c and sleep.S for omap2.

Please note that it does not contain suspend or voltage scaling yet.
parent 165e0bcd
No related merge requests found
......@@ -7,6 +7,9 @@ obj-y := irq.o id.o io.o sram-fn.o memory.o prcm.o clock.o mux.o devices.o seria
obj-$(CONFIG_OMAP_MPU_TIMER) += timer-gp.o
# Power Management
obj-$(CONFIG_PM) += pm.o sleep.o
# Specific board support
obj-$(CONFIG_MACH_OMAP_GENERIC) += board-generic.o
obj-$(CONFIG_MACH_OMAP_H4) += board-h4.o
......
/*
* linux/arch/arm/mach-omap2/pm.c
*
* OMAP2 Power Management Routines
*
* Copyright (C) 2006 Nokia Corporation
* Tony Lindgren <tony@atomide.com>
*
* 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/sched.h>
#include <linux/proc_fs.h>
#include <linux/pm.h>
#include <linux/interrupt.h>
#include <linux/sysfs.h>
#include <linux/module.h>
#include <asm/io.h>
#include <asm/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/pm.h>
static struct clk *vclk;
static void (*omap2_sram_idle)(void);
static void (*omap2_sram_suspend)(int dllctrl, int cpu_rev);
static void (*saved_idle)(void);
void omap2_pm_idle(void)
{
local_irq_disable();
local_fiq_disable();
if (need_resched()) {
local_fiq_enable();
local_irq_enable();
return;
}
/*
* 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();
omap2_sram_idle();
local_fiq_enable();
local_irq_enable();
}
static int omap2_pm_prepare(suspend_state_t state)
{
int error = 0;
/* We cannot sleep in idle until we have resumed */
saved_idle = pm_idle;
pm_idle = NULL;
switch (state)
{
case PM_SUSPEND_STANDBY:
case PM_SUSPEND_MEM:
break;
case PM_SUSPEND_DISK:
return -ENOTSUPP;
default:
return -EINVAL;
}
return error;
}
static int omap2_pm_enter(suspend_state_t state)
{
switch (state)
{
case PM_SUSPEND_STANDBY:
case PM_SUSPEND_MEM:
/* FIXME: Add suspend */
break;
case PM_SUSPEND_DISK:
return -ENOTSUPP;
default:
return -EINVAL;
}
return 0;
}
static int omap2_pm_finish(suspend_state_t state)
{
pm_idle = saved_idle;
return 0;
}
static struct pm_ops omap_pm_ops = {
.pm_disk_mode = 0,
.prepare = omap2_pm_prepare,
.enter = omap2_pm_enter,
.finish = omap2_pm_finish,
};
int __init omap2_pm_init(void)
{
printk("Power Management for TI OMAP.\n");
vclk = clk_get(NULL, "virt_prcm_set");
if (IS_ERR(vclk)) {
printk(KERN_ERR "Could not get PM vclk\n");
return -ENODEV;
}
/*
* 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);
pm_set_ops(&omap_pm_ops);
pm_idle = omap2_pm_idle;
return 0;
}
__initcall(omap2_pm_init);
This diff is collapsed.
/*
* linux/arch/arm/mach-omap2/sleep.S
*
* (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/config.h>
#include <linux/linkage.h>
#include <asm/assembler.h>
#include <asm/arch/io.h>
#include <asm/arch/pm.h>
#define A_32KSYNC_CR_V IO_ADDRESS(OMAP_TIMER32K_BASE+0x10)
#define A_PRCM_VOLTCTRL_V IO_ADDRESS(OMAP24XX_PRCM_BASE+0x50)
#define A_PRCM_CLKCFG_CTRL_V IO_ADDRESS(OMAP24XX_PRCM_BASE+0x80)
#define A_CM_CLKEN_PLL_V IO_ADDRESS(OMAP24XX_PRCM_BASE+0x500)
#define A_CM_IDLEST_CKGEN_V IO_ADDRESS(OMAP24XX_PRCM_BASE+0x520)
#define A_CM_CLKSEL1_PLL_V IO_ADDRESS(OMAP24XX_PRCM_BASE+0x540)
#define A_CM_CLKSEL2_PLL_V IO_ADDRESS(OMAP24XX_PRCM_BASE+0x544)
#define A_SDRC_DLLA_CTRL_V IO_ADDRESS(OMAP24XX_SDRC_BASE+0x60)
#define A_SDRC_POWER_V IO_ADDRESS(OMAP24XX_SDRC_BASE+0x70)
#define A_SDRC_RFR_CTRL_V IO_ADDRESS(OMAP24XX_SDRC_BASE+0xA4)
#define A_SDRC0_V (0xC0000000)
#define A_SDRC_MANUAL_V IO_ADDRESS(OMAP24XX_SDRC_BASE+0xA8)
.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, #0 @ clear for mcr setup
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
* R1 : Processor+Revision
* 2420: 0x21 = 242xES1, 0x26 = 242xES2.2
* 2430: 0x31 = 2430ES1, 0x32 = 2430ES2
*
* 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, A_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, A_SDRC_DLLA_CTRL_S @ 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
A_SDRC_POWER:
.word A_SDRC_POWER_V
A_SDRC0:
.word A_SDRC0_V
A_CM_CLKSEL2_PLL_S:
.word A_CM_CLKSEL2_PLL_V
A_CM_CLKEN_PLL:
.word A_CM_CLKEN_PLL_V
A_SDRC_DLLA_CTRL_S:
.word A_SDRC_DLLA_CTRL_V
A_SDRC_MANUAL_S:
.word A_SDRC_MANUAL_V
ENTRY(omap24xx_cpu_suspend_sz)
.word . - omap24xx_cpu_suspend
......@@ -49,7 +49,7 @@
/*
* ----------------------------------------------------------------------------
* Powermanagement bitmasks
* Power management bitmasks
* ----------------------------------------------------------------------------
*/
#define IDLE_WAIT_CYCLES 0x00000fff
......@@ -135,9 +135,20 @@ extern void omap_pm_suspend(void);
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 omap730_idle_loop_suspend(void);
extern void omap1510_idle_loop_suspend(void);
extern void omap1610_idle_loop_suspend(void);
extern void omap24xx_idle_loop_suspend(void);
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 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;
#ifdef CONFIG_OMAP_SERIAL_WAKE
extern void omap_serial_wake_trigger(int enable);
......@@ -146,13 +157,6 @@ extern void omap_serial_wake_trigger(int enable);
#define omap_serial_wake_trigger(x) {}
#endif /* CONFIG_OMAP_SERIAL_WAKE */
extern unsigned int omap730_cpu_suspend_sz;
extern unsigned int omap730_idle_loop_suspend_sz;
extern unsigned int omap1510_cpu_suspend_sz;
extern unsigned int omap1510_idle_loop_suspend_sz;
extern unsigned int omap1610_cpu_suspend_sz;
extern unsigned int omap1610_idle_loop_suspend_sz;
#define ARM_SAVE(x) arm_sleep_save[ARM_SLEEP_SAVE_##x] = omap_readl(x)
#define ARM_RESTORE(x) omap_writel((arm_sleep_save[ARM_SLEEP_SAVE_##x]), (x))
#define ARM_SHOW(x) arm_sleep_save[ARM_SLEEP_SAVE_##x]
......@@ -173,6 +177,10 @@ extern unsigned int omap1610_idle_loop_suspend_sz;
#define MPUI1610_RESTORE(x) omap_writel((mpui1610_sleep_save[MPUI1610_SLEEP_SAVE_##x]), (x))
#define MPUI1610_SHOW(x) mpui1610_sleep_save[MPUI1610_SLEEP_SAVE_##x]
#define OMAP24XX_SAVE(x) omap24xx_sleep_save[OMAP24XX_SLEEP_SAVE_##x] = x
#define OMAP24XX_RESTORE(x) x = omap24xx_sleep_save[OMAP24XX_SLEEP_SAVE_##x]
#define OMAP24XX_SHOW(x) omap24xx_sleep_save[OMAP24XX_SLEEP_SAVE_##x]
/*
* List of global OMAP registers to preserve.
* More ones like CP and general purpose register values are preserved
......@@ -273,5 +281,30 @@ enum mpui1610_save_state {
#endif
};
enum omap24xx_save_state {
OMAP24XX_SLEEP_SAVE_START = 0,
OMAP24XX_SLEEP_SAVE_INTC_MIR0,
OMAP24XX_SLEEP_SAVE_INTC_MIR1,
OMAP24XX_SLEEP_SAVE_INTC_MIR2,
OMAP24XX_SLEEP_SAVE_CM_FCLKEN1_CORE,
OMAP24XX_SLEEP_SAVE_CM_FCLKEN2_CORE,
OMAP24XX_SLEEP_SAVE_CM_ICLKEN1_CORE,
OMAP24XX_SLEEP_SAVE_CM_ICLKEN2_CORE,
OMAP24XX_SLEEP_SAVE_CM_ICLKEN4_CORE,
OMAP24XX_SLEEP_SAVE_GPIO1_IRQENABLE1,
OMAP24XX_SLEEP_SAVE_GPIO2_IRQENABLE1,
OMAP24XX_SLEEP_SAVE_GPIO3_IRQENABLE1,
OMAP24XX_SLEEP_SAVE_GPIO4_IRQENABLE1,
OMAP24XX_SLEEP_SAVE_GPIO3_OE,
OMAP24XX_SLEEP_SAVE_GPIO4_OE,
OMAP24XX_SLEEP_SAVE_GPIO3_RISINGDETECT,
OMAP24XX_SLEEP_SAVE_GPIO3_FALLINGDETECT,
OMAP24XX_SLEEP_SAVE_CONTROL_PADCONF_SPI1_NCS2,
OMAP24XX_SLEEP_SAVE_CONTROL_PADCONF_MCBSP1_DX,
OMAP24XX_SLEEP_SAVE_CONTROL_PADCONF_SSI1_FLAG_TX,
OMAP24XX_SLEEP_SAVE_CONTROL_PADCONF_SYS_NIRQW0,
OMAP24XX_SLEEP_SAVE_SIZE
};
#endif /* ASSEMBLER */
#endif /* __ASM_ARCH_OMAP_PM_H */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment