Commit 72682844 authored by Kai Svahn's avatar Kai Svahn Committed by Tony Lindgren

ARM: OMAP: Merge PM code from N800 tree

This patch merges omap2 PM code from N800 tree.

Patch adds support for sleep while idle for omap2
and handy serial console debbugging code. It also
moves code from pm-domain.c to pm.c.

This code can be used as a base for developing
power management for all omap24xx boards.
Signed-off-by: default avatarKai Svahn <kai.svahn@nokia.com>
Signed-off-by: default avatarTony Lindgren <tony@atomide.com>
parent c884dc21
......@@ -9,7 +9,7 @@ obj-y := irq.o id.o io.o sram-fn.o memory.o prcm.o clock.o mux.o devices.o \
obj-$(CONFIG_OMAP_MPU_TIMER) += timer-gp.o
# Power Management
obj-$(CONFIG_PM) += pm.o pm-domain.o sleep.o
obj-$(CONFIG_PM) += pm.o sleep.o
# Specific board support
obj-$(CONFIG_MACH_OMAP_GENERIC) += board-generic.o
......
/*
* linux/arch/arm/mach-omap2/pm-domain.c
*
* Power domain functions for OMAP2
*
* Copyright (C) 2006 Nokia Corporation
* Tony Lindgren <tony@atomide.com>
*
* Some code based on earlier OMAP2 sample PM code
* Copyright (C) 2005 Texas Instruments, Inc.
* 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 version 2 as
* published by the Free Software Foundation.
*/
#include <linux/module.h>
#include <linux/init.h>
#include <linux/clk.h>
#include <asm/io.h>
#include "prcm-regs.h"
/* Power domain offsets */
#define PM_MPU_OFFSET 0x100
#define PM_CORE_OFFSET 0x200
#define PM_GFX_OFFSET 0x300
#define PM_WKUP_OFFSET 0x400 /* Autoidle only */
#define PM_PLL_OFFSET 0x500 /* Autoidle only */
#define PM_DSP_OFFSET 0x800
#define PM_MDM_OFFSET 0xc00
/* Power domain wake-up dependency control register */
#define PM_WKDEP_OFFSET 0xc8
#define EN_MDM (1 << 5)
#define EN_WKUP (1 << 4)
#define EN_GFX (1 << 3)
#define EN_DSP (1 << 2)
#define EN_MPU (1 << 1)
#define EN_CORE (1 << 0)
/* Core power domain state transition control register */
#define PM_PWSTCTRL_OFFSET 0xe0
#define FORCESTATE (1 << 18) /* Only for DSP & GFX */
#define MEM4RETSTATE (1 << 6)
#define MEM3RETSTATE (1 << 5)
#define MEM2RETSTATE (1 << 4)
#define MEM1RETSTATE (1 << 3)
#define LOGICRETSTATE (1 << 2) /* Logic is retained */
#define POWERSTATE_OFF 0x3
#define POWERSTATE_RETENTION 0x1
#define POWERSTATE_ON 0x0
/* Power domain state register */
#define PM_PWSTST_OFFSET 0xe4
/* Hardware supervised state transition control register */
#define CM_CLKSTCTRL_OFFSET 0x48
#define AUTOSTAT_MPU (1 << 0) /* MPU */
#define AUTOSTAT_DSS (1 << 2) /* Core */
#define AUTOSTAT_L4 (1 << 1) /* Core */
#define AUTOSTAT_L3 (1 << 0) /* Core */
#define AUTOSTAT_GFX (1 << 0) /* GFX */
#define AUTOSTAT_IVA (1 << 8) /* 2420 IVA in DSP domain */
#define AUTOSTAT_DSP (1 << 0) /* DSP */
#define AUTOSTAT_MDM (1 << 0) /* MDM */
/* Automatic control of interface clock idling */
#define CM_AUTOIDLE1_OFFSET 0x30
#define CM_AUTOIDLE2_OFFSET 0x34 /* Core only */
#define CM_AUTOIDLE3_OFFSET 0x38 /* Core only */
#define CM_AUTOIDLE4_OFFSET 0x3c /* Core only */
#define AUTO_54M(x) (((x) & 0x3) << 6)
#define AUTO_96M(x) (((x) & 0x3) << 2)
#define AUTO_DPLL(x) (((x) & 0x3) << 0)
#define AUTO_STOPPED 0x3
#define AUTO_BYPASS_FAST 0x2 /* DPLL only */
#define AUTO_BYPASS_LOW_POWER 0x1 /* DPLL only */
#define AUTO_DISABLED 0x0
/* Voltage control PRCM_VOLTCTRL bits */
#define AUTO_EXTVOLT (1 << 15)
#define FORCE_EXTVOLT (1 << 14)
#define SETOFF_LEVEL(x) (((x) & 0x3) << 12)
#define MEMRETCTRL (1 << 8)
#define SETRET_LEVEL(x) (((x) & 0x3) << 6)
#define VOLT_LEVEL(x) (((x) & 0x3) << 0)
#define OMAP24XX_PRCM_VBASE IO_ADDRESS(OMAP24XX_PRCM_BASE)
#define prcm_readl(r) __raw_readl(OMAP24XX_PRCM_VBASE + (r))
#define prcm_writel(v, r) __raw_writel((v), OMAP24XX_PRCM_VBASE + (r))
static u32 pmdomain_get_wakeup_dependencies(int domain_offset)
{
return prcm_readl(domain_offset + PM_WKDEP_OFFSET);
}
static void pmdomain_set_wakeup_dependencies(u32 state, int domain_offset)
{
prcm_writel(state, domain_offset + PM_WKDEP_OFFSET);
}
static u32 pmdomain_get_powerstate(int domain_offset)
{
return prcm_readl(domain_offset + PM_PWSTCTRL_OFFSET);
}
static void pmdomain_set_powerstate(u32 state, int domain_offset)
{
prcm_writel(state, domain_offset + PM_PWSTCTRL_OFFSET);
}
static u32 pmdomain_get_clock_autocontrol(int domain_offset)
{
return prcm_readl(domain_offset + CM_CLKSTCTRL_OFFSET);
}
static void pmdomain_set_clock_autocontrol(u32 state, int domain_offset)
{
prcm_writel(state, domain_offset + CM_CLKSTCTRL_OFFSET);
}
static u32 pmdomain_get_clock_autoidle1(int domain_offset)
{
return prcm_readl(domain_offset + CM_AUTOIDLE1_OFFSET);
}
/* Core domain only */
static u32 pmdomain_get_clock_autoidle2(int domain_offset)
{
return prcm_readl(domain_offset + CM_AUTOIDLE2_OFFSET);
}
/* Core domain only */
static u32 pmdomain_get_clock_autoidle3(int domain_offset)
{
return prcm_readl(domain_offset + CM_AUTOIDLE3_OFFSET);
}
/* Core domain only */
static u32 pmdomain_get_clock_autoidle4(int domain_offset)
{
return prcm_readl(domain_offset + CM_AUTOIDLE4_OFFSET);
}
static void pmdomain_set_clock_autoidle1(u32 state, int domain_offset)
{
prcm_writel(state, CM_AUTOIDLE1_OFFSET + domain_offset);
}
/* Core domain only */
static void pmdomain_set_clock_autoidle2(u32 state, int domain_offset)
{
prcm_writel(state, CM_AUTOIDLE2_OFFSET + domain_offset);
}
/* Core domain only */
static void pmdomain_set_clock_autoidle3(u32 state, int domain_offset)
{
prcm_writel(state, CM_AUTOIDLE3_OFFSET + domain_offset);
}
/* Core domain only */
static void pmdomain_set_clock_autoidle4(u32 state, int domain_offset)
{
prcm_writel(state, CM_AUTOIDLE4_OFFSET + domain_offset);
}
/*
* Configures power management domains to idle clocks automatically.
*/
void pmdomain_set_autoidle(void)
{
u32 val;
/* Set PLL auto stop for 54M, 96M & DPLL */
pmdomain_set_clock_autoidle1(AUTO_54M(AUTO_STOPPED) |
AUTO_96M(AUTO_STOPPED) |
AUTO_DPLL(AUTO_STOPPED), PM_PLL_OFFSET);
/* External clock input control
* REVISIT: Should this be in clock framework?
*/
PRCM_CLKSRC_CTRL |= (0x3 << 3);
/* Configure number of 32KHz clock cycles for sys_clk */
PRCM_CLKSSETUP = 0x00ff;
/* Configure automatic voltage transition */
PRCM_VOLTSETUP = 0;
val = PRCM_VOLTCTRL;
val &= ~(SETOFF_LEVEL(0x3) | VOLT_LEVEL(0x3));
val |= SETOFF_LEVEL(1) | VOLT_LEVEL(1) | AUTO_EXTVOLT;
PRCM_VOLTCTRL = val;
/* Disable emulation tools functional clock */
PRCM_CLKEMUL_CTRL = 0x0;
/* Set core memory retention state */
val = pmdomain_get_powerstate(PM_CORE_OFFSET);
if (cpu_is_omap2420()) {
val &= ~(0x7 << 3);
val |= (MEM3RETSTATE | MEM2RETSTATE | MEM1RETSTATE);
} else {
val &= ~(0xf << 3);
val |= (MEM4RETSTATE | MEM3RETSTATE | MEM2RETSTATE |
MEM1RETSTATE);
}
pmdomain_set_powerstate(val, PM_CORE_OFFSET);
/* OCP interface smart idle. REVISIT: Enable autoidle bit0 ? */
val = SMS_SYSCONFIG;
val &= ~(0x3 << 3);
val |= (0x2 << 3) | (1 << 0);
SMS_SYSCONFIG |= val;
val = SDRC_SYSCONFIG;
val &= ~(0x3 << 3);
val |= (0x2 << 3);
SDRC_SYSCONFIG = val;
/* Configure L3 interface for smart idle.
* REVISIT: Enable autoidle bit0 ?
*/
val = GPMC_SYSCONFIG;
val &= ~(0x3 << 3);
val |= (0x2 << 3) | (1 << 0);
GPMC_SYSCONFIG = val;
pmdomain_set_powerstate(LOGICRETSTATE | POWERSTATE_RETENTION,
PM_MPU_OFFSET);
pmdomain_set_powerstate(POWERSTATE_RETENTION, PM_CORE_OFFSET);
if (!cpu_is_omap2420())
pmdomain_set_powerstate(POWERSTATE_RETENTION, PM_MDM_OFFSET);
/* Assume suspend function has saved the state for DSP and GFX */
pmdomain_set_powerstate(FORCESTATE | POWERSTATE_OFF, PM_DSP_OFFSET);
pmdomain_set_powerstate(FORCESTATE | POWERSTATE_OFF, PM_GFX_OFFSET);
#if 0
/* REVISIT: Internal USB needs special handling */
force_standby_usb();
if (cpu_is_omap2430())
force_hsmmc();
sdram_self_refresh_on_idle_req(1);
#endif
/* Enable clock auto control for all domains.
* Note that CORE domain includes also DSS, L4 & L3.
*/
pmdomain_set_clock_autocontrol(AUTOSTAT_MPU, PM_MPU_OFFSET);
pmdomain_set_clock_autocontrol(AUTOSTAT_GFX, PM_GFX_OFFSET);
pmdomain_set_clock_autocontrol(AUTOSTAT_DSS | AUTOSTAT_L4 | AUTOSTAT_L3,
PM_CORE_OFFSET);
if (cpu_is_omap2420())
pmdomain_set_clock_autocontrol(AUTOSTAT_IVA | AUTOSTAT_DSP,
PM_DSP_OFFSET);
else {
pmdomain_set_clock_autocontrol(AUTOSTAT_DSP, PM_DSP_OFFSET);
pmdomain_set_clock_autocontrol(AUTOSTAT_MDM, PM_MDM_OFFSET);
}
/* Enable clock autoidle for all domains */
pmdomain_set_clock_autoidle1(0x2, PM_DSP_OFFSET);
if (cpu_is_omap2420()) {
pmdomain_set_clock_autoidle1(0xfffffff9, PM_CORE_OFFSET);
pmdomain_set_clock_autoidle2(0x7, PM_CORE_OFFSET);
pmdomain_set_clock_autoidle1(0x3f, PM_WKUP_OFFSET);
} else {
pmdomain_set_clock_autoidle1(0xeafffff1, PM_CORE_OFFSET);
pmdomain_set_clock_autoidle2(0xfff, PM_CORE_OFFSET);
pmdomain_set_clock_autoidle1(0x7f, PM_WKUP_OFFSET);
pmdomain_set_clock_autoidle1(0x3, PM_MDM_OFFSET);
}
pmdomain_set_clock_autoidle3(0x7, PM_CORE_OFFSET);
pmdomain_set_clock_autoidle4(0x1f, PM_CORE_OFFSET);
}
/*
* Initializes power domains by removing wake-up dependencies and powering
* down DSP and GFX. Gets called from PM init. Note that DSP and IVA code
* must re-enable DSP and GFX when used.
*/
void __init pmdomain_init(void)
{
/* Remove all domain wakeup dependencies */
pmdomain_set_wakeup_dependencies(EN_WKUP | EN_CORE, PM_MPU_OFFSET);
pmdomain_set_wakeup_dependencies(0, PM_DSP_OFFSET);
pmdomain_set_wakeup_dependencies(0, PM_GFX_OFFSET);
pmdomain_set_wakeup_dependencies(EN_WKUP | EN_MPU, PM_CORE_OFFSET);
if (cpu_is_omap2430())
pmdomain_set_wakeup_dependencies(0, PM_MDM_OFFSET);
/* Power down DSP and GFX */
pmdomain_set_powerstate(POWERSTATE_OFF | FORCESTATE, PM_DSP_OFFSET);
pmdomain_set_powerstate(POWERSTATE_OFF | FORCESTATE, PM_GFX_OFFSET);
}
This diff is collapsed.
......@@ -5,6 +5,10 @@
* 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
......@@ -26,14 +30,6 @@
#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)
......@@ -53,7 +49,7 @@
*/
ENTRY(omap24xx_idle_loop_suspend)
stmfd sp!, {r0, lr} @ save registers on stack
mov r0, #0 @ clear for mcr setup
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
......@@ -67,9 +63,6 @@ ENTRY(omap24xx_idle_loop_suspend_sz)
*
* 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
......@@ -129,14 +122,8 @@ 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
......
......@@ -75,6 +75,8 @@ extern void omap_free_gpio(int gpio);
extern void omap_set_gpio_direction(int gpio, int is_input);
extern void omap_set_gpio_dataout(int gpio, int enable);
extern int omap_get_gpio_datain(int gpio);
extern void omap2_gpio_prepare_for_retention(void);
extern void omap2_gpio_resume_after_retention(void);
/*-------------------------------------------------------------------------*/
......
/*
* linux/include/asm-arm/arch-omap/pm.h
* linux/include/asm/arch-omap/pm.h
*
* Header file for OMAP Power Management Routines
*
......@@ -115,6 +115,8 @@
#include <linux/clk.h>
extern struct subsystem power_subsys;
extern void prevent_idle_sleep(void);
extern void allow_idle_sleep(void);
......@@ -132,6 +134,8 @@ void clk_deny_idle(struct clk *clk);
extern void omap_pm_idle(void);
extern void omap_pm_suspend(void);
extern void omap2_block_sleep(void);
extern void omap2_allow_sleep(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);
......@@ -181,10 +185,6 @@ extern void omap_serial_wake_trigger(int enable);
#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
......@@ -294,63 +294,5 @@ 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_CLKSTCTRL_MPU,
OMAP24XX_SLEEP_SAVE_CM_CLKSTCTRL_CORE,
OMAP24XX_SLEEP_SAVE_CM_CLKSTCTRL_GFX,
OMAP24XX_SLEEP_SAVE_CM_CLKSTCTRL_DSP,
OMAP24XX_SLEEP_SAVE_CM_CLKSTCTRL_MDM,
OMAP24XX_SLEEP_SAVE_PM_PWSTCTRL_MPU,
OMAP24XX_SLEEP_SAVE_PM_PWSTCTRL_CORE,
OMAP24XX_SLEEP_SAVE_PM_PWSTCTRL_GFX,
OMAP24XX_SLEEP_SAVE_PM_PWSTCTRL_DSP,
OMAP24XX_SLEEP_SAVE_PM_PWSTCTRL_MDM,
OMAP24XX_SLEEP_SAVE_CM_IDLEST1_CORE,
OMAP24XX_SLEEP_SAVE_CM_IDLEST2_CORE,
OMAP24XX_SLEEP_SAVE_CM_IDLEST3_CORE,
OMAP24XX_SLEEP_SAVE_CM_IDLEST4_CORE,
OMAP24XX_SLEEP_SAVE_CM_IDLEST_GFX,
OMAP24XX_SLEEP_SAVE_CM_IDLEST_WKUP,
OMAP24XX_SLEEP_SAVE_CM_IDLEST_CKGEN,
OMAP24XX_SLEEP_SAVE_CM_IDLEST_DSP,
OMAP24XX_SLEEP_SAVE_CM_IDLEST_MDM,
OMAP24XX_SLEEP_SAVE_CM_AUTOIDLE1_CORE,
OMAP24XX_SLEEP_SAVE_CM_AUTOIDLE2_CORE,
OMAP24XX_SLEEP_SAVE_CM_AUTOIDLE3_CORE,
OMAP24XX_SLEEP_SAVE_CM_AUTOIDLE4_CORE,
OMAP24XX_SLEEP_SAVE_CM_AUTOIDLE_WKUP,
OMAP24XX_SLEEP_SAVE_CM_AUTOIDLE_PLL,
OMAP24XX_SLEEP_SAVE_CM_AUTOIDLE_DSP,
OMAP24XX_SLEEP_SAVE_CM_AUTOIDLE_MDM,
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_ICLKEN3_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