Omap PM changes via Kevin Hilman <khilman@linaro.org>:

OMAP PM cleanups for v3.10
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v1.4.12 (GNU/Linux)
 
 iQIcBAABAgAGBQJRuLeiAAoJEBvUPslcq6Vz2HMP/1PPRVv0KK7ErdVAyYlR82Qq
 TQgYbu2601z77gNLVWT2QOf8vlSFcutiEMJ/pdEblvWeQoehdFKU0FZTvZwD1Fwp
 qXu/BdKqlmk/EmmIWHG6wix9yeQiH/Ee6hPDCTMT8z4nVPISg2R1e125j2Zr1gs1
 F+ilhuFcCsmJVB6uu4yU2D0fdwFvh6MArAwryQv5iGyHJo9r5ZC90hZ1a/0fWeVH
 7OdOesPEhTHXdxvMb4JpQsBBVB5ajBfej/5qiRXckvbaS2ADnVJBfCdvky5lCo2u
 Da9Ln+xA2XfdqO30HJFfVBAkS1T4d191oaDM+v/pQxEcMyHPHm76gwoQ4am8ZKgv
 cLYwZddtvwtGAOK8FlgFU+YSbvoSzyWAdGo89dtC4fcFLXhwHfABHBwHHBmVmvm2
 IiBcsg7iIZCQuAplmTOrgEPAnkgOJOMLOvRJEX9FVvj9mVUA0TNJSMt7w4sj4fEf
 UIUXXCI/cbLjl//puuZf3wvq/VxrymYlxPyiVlr3f/aZ21XBYzyqp1L4z2tjwLt3
 vtNVXxc4OEGflF+k52qOp5xbGrqDUBumtlRyePmXM6u9/y3MsN+TZrlSuiG4Ig5d
 r5PfHXWEe/eFjqjSUZXiEvEwYHV92Q7GpwBXOVGhFOaDpROA1pKB4jMATj9/bjKR
 745XKPPscKG3AtsnK60q
 =9SyZ
 -----END PGP SIGNATURE-----

Merge tag 'omap-for-v3.11/pm-signed' of git://git.kernel.org/pub/scm/linux/kernel/git/tmlind/linux-omap into next/soc

From Tony Lindgren:
Omap PM changes via Kevin Hilman <khilman@linaro.org>:

OMAP PM cleanups for v3.10

* tag 'omap-for-v3.11/pm-signed' of git://git.kernel.org/pub/scm/linux/kernel/git/tmlind/linux-omap:
  ARM: OMAP4+: PM: Consolidate OMAP4 PM code to re-use it for OMAP5
  ARM: OMAP4+: Make secondary_startup function name more consistent
  ARM: OMAP4+: PM: Consolidate MPU subsystem PM code for re-use
  ARM: OMAP4: PM: Avoid expensive cpu_suspend() path for all CPU power states except off
This commit is contained in:
Olof Johansson 2013-06-14 14:30:23 -07:00
commit eb25862dee
5 changed files with 113 additions and 32 deletions

View File

@ -237,8 +237,8 @@ extern void omap_do_wfi(void);
#ifdef CONFIG_SMP
/* Needed for secondary core boot */
extern void omap_secondary_startup(void);
extern void omap_secondary_startup_4460(void);
extern void omap4_secondary_startup(void);
extern void omap4460_secondary_startup(void);
extern u32 omap_modify_auxcoreboot0(u32 set_mask, u32 clear_mask);
extern void omap_auxcoreboot_addr(u32 cpu_addr);
extern u32 omap_read_auxcoreboot0(void);

View File

@ -49,7 +49,7 @@ END(omap5_secondary_startup)
* The primary core will update this flag using a hardware
* register AuxCoreBoot0.
*/
ENTRY(omap_secondary_startup)
ENTRY(omap4_secondary_startup)
hold: ldr r12,=0x103
dsb
smc #0 @ read from AuxCoreBoot0
@ -64,9 +64,9 @@ hold: ldr r12,=0x103
* should now contain the SVC stack for this core
*/
b secondary_startup
ENDPROC(omap_secondary_startup)
ENDPROC(omap4_secondary_startup)
ENTRY(omap_secondary_startup_4460)
ENTRY(omap4460_secondary_startup)
hold_2: ldr r12,=0x103
dsb
smc #0 @ read from AuxCoreBoot0
@ -101,4 +101,4 @@ hold_2: ldr r12,=0x103
* should now contain the SVC stack for this core
*/
b secondary_startup
ENDPROC(omap_secondary_startup_4460)
ENDPROC(omap4460_secondary_startup)

View File

@ -71,10 +71,43 @@ struct omap4_cpu_pm_info {
void (*secondary_startup)(void);
};
/**
* struct cpu_pm_ops - CPU pm operations
* @finish_suspend: CPU suspend finisher function pointer
* @resume: CPU resume function pointer
* @scu_prepare: CPU Snoop Control program function pointer
*
* Structure holds functions pointer for CPU low power operations like
* suspend, resume and scu programming.
*/
struct cpu_pm_ops {
int (*finish_suspend)(unsigned long cpu_state);
void (*resume)(void);
void (*scu_prepare)(unsigned int cpu_id, unsigned int cpu_state);
};
static DEFINE_PER_CPU(struct omap4_cpu_pm_info, omap4_pm_info);
static struct powerdomain *mpuss_pd;
static void __iomem *sar_base;
static int default_finish_suspend(unsigned long cpu_state)
{
omap_do_wfi();
return 0;
}
static void dummy_cpu_resume(void)
{}
static void dummy_scu_prepare(unsigned int cpu_id, unsigned int cpu_state)
{}
struct cpu_pm_ops omap_pm_ops = {
.finish_suspend = default_finish_suspend,
.resume = dummy_cpu_resume,
.scu_prepare = dummy_scu_prepare,
};
/*
* Program the wakeup routine address for the CPU0 and CPU1
* used for OFF or DORMANT wakeup.
@ -158,11 +191,12 @@ static void save_l2x0_context(void)
{
u32 val;
void __iomem *l2x0_base = omap4_get_l2cache_base();
val = __raw_readl(l2x0_base + L2X0_AUX_CTRL);
__raw_writel(val, sar_base + L2X0_AUXCTRL_OFFSET);
val = __raw_readl(l2x0_base + L2X0_PREFETCH_CTRL);
__raw_writel(val, sar_base + L2X0_PREFETCH_CTRL_OFFSET);
if (l2x0_base) {
val = __raw_readl(l2x0_base + L2X0_AUX_CTRL);
__raw_writel(val, sar_base + L2X0_AUXCTRL_OFFSET);
val = __raw_readl(l2x0_base + L2X0_PREFETCH_CTRL);
__raw_writel(val, sar_base + L2X0_PREFETCH_CTRL_OFFSET);
}
}
#else
static void save_l2x0_context(void)
@ -225,14 +259,17 @@ int omap4_enter_lowpower(unsigned int cpu, unsigned int power_state)
cpu_clear_prev_logic_pwrst(cpu);
pwrdm_set_next_pwrst(pm_info->pwrdm, power_state);
set_cpu_wakeup_addr(cpu, virt_to_phys(omap4_cpu_resume));
scu_pwrst_prepare(cpu, power_state);
set_cpu_wakeup_addr(cpu, virt_to_phys(omap_pm_ops.resume));
omap_pm_ops.scu_prepare(cpu, power_state);
l2x0_pwrst_prepare(cpu, save_state);
/*
* Call low level function with targeted low power state.
*/
cpu_suspend(save_state, omap4_finish_suspend);
if (save_state)
cpu_suspend(save_state, omap_pm_ops.finish_suspend);
else
omap_pm_ops.finish_suspend(save_state);
/*
* Restore the CPUx power state to ON otherwise CPUx
@ -268,14 +305,14 @@ int __cpuinit omap4_hotplug_cpu(unsigned int cpu, unsigned int power_state)
pwrdm_clear_all_prev_pwrst(pm_info->pwrdm);
pwrdm_set_next_pwrst(pm_info->pwrdm, power_state);
set_cpu_wakeup_addr(cpu, virt_to_phys(pm_info->secondary_startup));
scu_pwrst_prepare(cpu, power_state);
omap_pm_ops.scu_prepare(cpu, power_state);
/*
* CPU never retuns back if targeted power state is OFF mode.
* CPU ONLINE follows normal CPU ONLINE ptah via
* omap_secondary_startup().
* omap4_secondary_startup().
*/
omap4_finish_suspend(cpu_state);
omap_pm_ops.finish_suspend(cpu_state);
pwrdm_set_next_pwrst(pm_info->pwrdm, PWRDM_POWER_ON);
return 0;
@ -319,9 +356,9 @@ int __init omap4_mpuss_init(void)
pm_info->wkup_sar_addr = sar_base + CPU1_WAKEUP_NS_PA_ADDR_OFFSET;
pm_info->l2x0_sar_addr = sar_base + L2X0_SAVE_OFFSET1;
if (cpu_is_omap446x())
pm_info->secondary_startup = omap_secondary_startup_4460;
pm_info->secondary_startup = omap4460_secondary_startup;
else
pm_info->secondary_startup = omap_secondary_startup;
pm_info->secondary_startup = omap4_secondary_startup;
pm_info->pwrdm = pwrdm_lookup("cpu1_pwrdm");
if (!pm_info->pwrdm) {
@ -352,6 +389,12 @@ int __init omap4_mpuss_init(void)
save_l2x0_context();
if (cpu_is_omap44xx()) {
omap_pm_ops.finish_suspend = omap4_finish_suspend;
omap_pm_ops.resume = omap4_cpu_resume;
omap_pm_ops.scu_prepare = scu_pwrst_prepare;
}
return 0;
}

View File

@ -87,7 +87,7 @@ static int __cpuinit omap4_boot_secondary(unsigned int cpu, struct task_struct *
/*
* Update the AuxCoreBoot0 with boot state for secondary core.
* omap_secondary_startup() routine will hold the secondary core till
* omap4_secondary_startup() routine will hold the secondary core till
* the AuxCoreBoot1 register is updated with cpu state
* A barrier is added to ensure that write buffer is drained
*/
@ -200,7 +200,7 @@ static void __init omap4_smp_init_cpus(void)
static void __init omap4_smp_prepare_cpus(unsigned int max_cpus)
{
void *startup_addr = omap_secondary_startup;
void *startup_addr = omap4_secondary_startup;
void __iomem *base = omap_get_wakeupgen_base();
/*
@ -211,7 +211,7 @@ static void __init omap4_smp_prepare_cpus(unsigned int max_cpus)
scu_enable(scu_base);
if (cpu_is_omap446x()) {
startup_addr = omap_secondary_startup_4460;
startup_addr = omap4460_secondary_startup;
pm44xx_errata |= PM_OMAP4_ROM_SMP_BOOT_ERRATUM_GICD;
}

View File

@ -1,7 +1,7 @@
/*
* OMAP4 Power Management Routines
* OMAP4+ Power Management Routines
*
* Copyright (C) 2010-2011 Texas Instruments, Inc.
* Copyright (C) 2010-2013 Texas Instruments, Inc.
* Rajendra Nayak <rnayak@ti.com>
* Santosh Shilimkar <santosh.shilimkar@ti.com>
*
@ -135,16 +135,16 @@ static void omap_default_idle(void)
}
/**
* omap4_pm_init - Init routine for OMAP4 PM
* omap4_init_static_deps - Add OMAP4 static dependencies
*
* Initializes all powerdomain and clockdomain target states
* and all PRCM settings.
* Add needed static clockdomain dependencies on OMAP4 devices.
* Return: 0 on success or 'err' on failures
*/
int __init omap4_pm_init(void)
static inline int omap4_init_static_deps(void)
{
int ret;
struct clockdomain *emif_clkdm, *mpuss_clkdm, *l3_1_clkdm;
struct clockdomain *ducati_clkdm, *l3_2_clkdm;
int ret = 0;
if (omap_rev() == OMAP4430_REV_ES1_0) {
WARN(1, "Power Management not supported on OMAP4430 ES1.0\n");
@ -163,7 +163,7 @@ int __init omap4_pm_init(void)
ret = pwrdm_for_each(pwrdms_setup, NULL);
if (ret) {
pr_err("Failed to setup powerdomains\n");
goto err2;
return ret;
}
/*
@ -171,6 +171,10 @@ int __init omap4_pm_init(void)
* MPUSS -> L4_PER/L3_* and DUCATI -> L3_* doesn't work as
* expected. The hardware recommendation is to enable static
* dependencies for these to avoid system lock ups or random crashes.
* The L4 wakeup depedency is added to workaround the OCP sync hardware
* BUG with 32K synctimer which lead to incorrect timer value read
* from the 32K counter. The BUG applies for GPTIMER1 and WDT2 which
* are part of L4 wakeup clockdomain.
*/
mpuss_clkdm = clkdm_lookup("mpuss_clkdm");
emif_clkdm = clkdm_lookup("l3_emif_clkdm");
@ -179,7 +183,7 @@ int __init omap4_pm_init(void)
ducati_clkdm = clkdm_lookup("ducati_clkdm");
if ((!mpuss_clkdm) || (!emif_clkdm) || (!l3_1_clkdm) ||
(!l3_2_clkdm) || (!ducati_clkdm))
goto err2;
return -EINVAL;
ret = clkdm_add_wkdep(mpuss_clkdm, emif_clkdm);
ret |= clkdm_add_wkdep(mpuss_clkdm, l3_1_clkdm);
@ -188,9 +192,42 @@ int __init omap4_pm_init(void)
ret |= clkdm_add_wkdep(ducati_clkdm, l3_2_clkdm);
if (ret) {
pr_err("Failed to add MPUSS -> L3/EMIF/L4PER, DUCATI -> L3 wakeup dependency\n");
return -EINVAL;
}
return ret;
}
/**
* omap4_pm_init - Init routine for OMAP4+ devices
*
* Initializes all powerdomain and clockdomain target states
* and all PRCM settings.
* Return: Returns the error code returned by called functions.
*/
int __init omap4_pm_init(void)
{
int ret = 0;
if (omap_rev() == OMAP4430_REV_ES1_0) {
WARN(1, "Power Management not supported on OMAP4430 ES1.0\n");
return -ENODEV;
}
pr_info("Power Management for TI OMAP4+ devices.\n");
ret = pwrdm_for_each(pwrdms_setup, NULL);
if (ret) {
pr_err("Failed to setup powerdomains.\n");
goto err2;
}
if (cpu_is_omap44xx()) {
ret = omap4_init_static_deps();
if (ret)
goto err2;
}
ret = omap4_mpuss_init();
if (ret) {
pr_err("Failed to initialise OMAP4 MPUSS\n");
@ -206,7 +243,8 @@ int __init omap4_pm_init(void)
/* Overwrite the default cpu_do_idle() */
arm_pm_idle = omap_default_idle;
omap4_idle_init();
if (cpu_is_omap44xx())
omap4_idle_init();
err2:
return ret;