diff options
author | Alex Frid <afrid@nvidia.com> | 2010-07-13 23:34:15 -0700 |
---|---|---|
committer | Gary King <gking@nvidia.com> | 2010-07-31 13:33:07 -0700 |
commit | 4e481ff43ff51d1c00361231fc64f401da000f8a (patch) | |
tree | f4941740e87106f757c5fe4b8b36d99788e9b0d7 | |
parent | fcecf3fdc2f7a68f9ee7dac84cf0db03907da53f (diff) |
[ARM/tegra] power: Added run-time LP0/LP1 selection.
Added sysfs node /sys/power/nvrm/core_lock to dynamically select lowest
tegra power state in conjunction with static ODM query:
- if ODM query specifies DeepSleep as lowest power state and core_lock is
cleared, tegra platform enters DeepSleep (LP0) when system is suspended
- if ODM query specifies DeepSleep as lowest power state and core_lock is
set, tegra platform enters Suspend (LP1) when system is suspended
- if ODM query specifies any state other than DeepSleep as lowest power
state, core_lock is ignored (tegra platform follows ODM specification
in suspend)
Addresses bug 697619, facilitates LP0/LP1 testing.
Change-Id: Id2d046ba202cf7630cff5e9b524995ec5e867eaa
Reviewed-on: http://git-master/r/4127
Reviewed-by: Aleksandr Frid <afrid@nvidia.com>
Tested-by: Aleksandr Frid <afrid@nvidia.com>
Reviewed-by: Gary King <gking@nvidia.com>
-rw-r--r-- | arch/arm/mach-tegra/include/nvrm_power_private.h | 13 | ||||
-rw-r--r-- | arch/arm/mach-tegra/nvddk/nvddk_usbphy.c | 10 | ||||
-rw-r--r-- | arch/arm/mach-tegra/nvrm/core/common/nvrm_power.c | 6 | ||||
-rw-r--r-- | arch/arm/mach-tegra/nvrm_user.c | 28 | ||||
-rw-r--r-- | arch/arm/mach-tegra/suspend.c | 58 |
5 files changed, 82 insertions, 33 deletions
diff --git a/arch/arm/mach-tegra/include/nvrm_power_private.h b/arch/arm/mach-tegra/include/nvrm_power_private.h index a2663df8df6c..9ca3cee24e92 100644 --- a/arch/arm/mach-tegra/include/nvrm_power_private.h +++ b/arch/arm/mach-tegra/include/nvrm_power_private.h @@ -151,6 +151,19 @@ typedef enum extern NvRmLp2Policy g_Lp2Policy; /** + * Gets lowest power state, taking into the account run-time core lock. + */ +extern bool core_lock_on; +static inline NvOdmSocPowerState NvRmPowerLowestStateGet(void) +{ + NvOdmSocPowerState state = + NvOdmQueryLowestSocPowerState()->LowestPowerState; + if ((state == NvOdmSocPowerState_DeepSleep) && core_lock_on) + state = NvOdmSocPowerState_Suspend; + return state; +} + +/** * NVRM PM function called within OS shim high priority thread */ NvRmPmRequest NvRmPrivPmThread(void); diff --git a/arch/arm/mach-tegra/nvddk/nvddk_usbphy.c b/arch/arm/mach-tegra/nvddk/nvddk_usbphy.c index 55dc3ab0e1b7..aa80b2fa0eec 100644 --- a/arch/arm/mach-tegra/nvddk/nvddk_usbphy.c +++ b/arch/arm/mach-tegra/nvddk/nvddk_usbphy.c @@ -40,7 +40,7 @@ */ #include "nvrm_pinmux.h" -#include "nvrm_power.h" +#include "nvrm_power_private.h" #include "nvrm_pmu.h" #include "nvrm_hardware_access.h" #include "nvddk_usbphy_priv.h" @@ -634,7 +634,7 @@ NvDdkUsbPhyPowerUp( NvBool IsDpd) { NvError e = NvSuccess; - NvOdmSocPowerStateInfo *pLowPowerState = NvOdmQueryLowestSocPowerState(); + NvOdmSocPowerState state = NvRmPowerLowestStateGet(); NV_ASSERT(hUsbPhy); @@ -672,7 +672,7 @@ NvDdkUsbPhyPowerUp( /* Allow restoring register context for the USB host if it is a ULPI interface or if the lowest power state is LP1 */ if ((hUsbPhy->pProperty->UsbMode == NvOdmUsbModeType_Host) && - ((pLowPowerState->LowestPowerState != NvOdmSocPowerState_DeepSleep) || + ((state != NvOdmSocPowerState_DeepSleep) || (hUsbPhy->pProperty->UsbInterfaceType == NvOdmUsbInterfaceType_UlpiExternalPhy))) { hUsbPhy->RestoreContext(hUsbPhy); @@ -707,7 +707,7 @@ NvDdkUsbPhyPowerDown( NvError e = NvSuccess; NvDdkUsbPhyIoctl_VBusStatusOutputArgs VBusStatus; NvU32 TimeOut = USB_PHY_HW_TIMEOUT_US; - NvOdmSocPowerStateInfo *pLowPowerState = NvOdmQueryLowestSocPowerState(); + NvOdmSocPowerState state = NvRmPowerLowestStateGet(); NV_ASSERT(hUsbPhy); @@ -721,7 +721,7 @@ NvDdkUsbPhyPowerDown( /* Allow saving register context for the USB host if it is a ULPI interface or if the lowest power state is LP1 */ if ((hUsbPhy->pProperty->UsbMode == NvOdmUsbModeType_Host) && - ((pLowPowerState->LowestPowerState != NvOdmSocPowerState_DeepSleep) || + ((state != NvOdmSocPowerState_DeepSleep) || (hUsbPhy->pProperty->UsbInterfaceType == NvOdmUsbInterfaceType_UlpiExternalPhy))) { hUsbPhy->SaveContext(hUsbPhy); diff --git a/arch/arm/mach-tegra/nvrm/core/common/nvrm_power.c b/arch/arm/mach-tegra/nvrm/core/common/nvrm_power.c index cb6f9745a00a..4845def3123e 100644 --- a/arch/arm/mach-tegra/nvrm/core/common/nvrm_power.c +++ b/arch/arm/mach-tegra/nvrm/core/common/nvrm_power.c @@ -1515,8 +1515,7 @@ NvRmPowerActivityHint ( NvError NvRmKernelPowerSuspend( NvRmDeviceHandle hRmDeviceHandle ) { - NvOdmSocPowerState state = - NvOdmQueryLowestSocPowerState()->LowestPowerState; + NvOdmSocPowerState state = NvRmPowerLowestStateGet(); if (state == NvOdmSocPowerState_Suspend) NvRmPrivPowerGroupSuspend(hRmDeviceHandle); @@ -1565,8 +1564,7 @@ NvRmKernelPowerSuspend( NvRmDeviceHandle hRmDeviceHandle ) NvError NvRmKernelPowerResume( NvRmDeviceHandle hRmDeviceHandle ) { - NvOdmSocPowerState state = - NvOdmQueryLowestSocPowerState()->LowestPowerState; + NvOdmSocPowerState state = NvRmPowerLowestStateGet(); NvOsMutexLock(s_hPowerClientMutex); ReportRmPowerState(hRmDeviceHandle); diff --git a/arch/arm/mach-tegra/nvrm_user.c b/arch/arm/mach-tegra/nvrm_user.c index f5ab25bd5d3d..93603aa23bc3 100644 --- a/arch/arm/mach-tegra/nvrm_user.c +++ b/arch/arm/mach-tegra/nvrm_user.c @@ -616,6 +616,33 @@ nvrm_lp2policy_store(struct kobject *kobj, struct kobj_attribute *attr, static struct kobj_attribute nvrm_lp2policy_attribute = __ATTR(lp2policy, 0644, nvrm_lp2policy_show, nvrm_lp2policy_store); +/* + * NVRM lowest power state run-time selection + */ +static ssize_t +nvrm_core_lock_show(struct kobject *kobj, struct kobj_attribute *attr, + char *buf) +{ + return sprintf(buf, "%u\n", core_lock_on); +} + +static ssize_t +nvrm_core_lock_store(struct kobject *kobj, struct kobj_attribute *attr, + const char *buf, size_t count) +{ + unsigned int n, lock; + + n = sscanf(buf, "%u", &lock); + if (n != 1) + return -1; + + core_lock_on = (bool)lock; + return count; +} + +static struct kobj_attribute nvrm_core_lock_attribute = + __ATTR(core_lock, 0666, nvrm_core_lock_show, nvrm_core_lock_store); + #endif static int __init nvrm_init(void) @@ -635,6 +662,7 @@ static int __init nvrm_init(void) // Create /sys/power/nvrm/notifier. nvrm_kobj = kobject_create_and_add("nvrm", power_kobj); + sysfs_create_file(nvrm_kobj, &nvrm_core_lock_attribute.attr); sysfs_create_file(nvrm_kobj, &nvrm_lp2policy_attribute.attr); sysfs_create_file(nvrm_kobj, &nvrm_notifier_attribute.attr); sys_nvrm_notifier = NULL; diff --git a/arch/arm/mach-tegra/suspend.c b/arch/arm/mach-tegra/suspend.c index b0d84eee10ee..b2b461d8b0a6 100644 --- a/arch/arm/mach-tegra/suspend.c +++ b/arch/arm/mach-tegra/suspend.c @@ -66,6 +66,7 @@ struct suspend_context }; volatile struct suspend_context tegra_sctx; +bool core_lock_on = false; #ifdef CONFIG_HOTPLUG_CPU extern void tegra_board_nvodm_suspend(void); @@ -95,6 +96,7 @@ static void __iomem *tmrus = IO_ADDRESS(TEGRA_TMRUS_BASE); #define PMC_COREPWROFF_TIMER PMC_WAKE_DELAY #define PMC_SCRATCH38 0x134 #define PMC_SCRATCH39 0x138 +#define PMC_SCRATCH41 0x140 #define CLK_RESET_CCLK_BURST 0x20 #define CLK_RESET_CCLK_DIVIDER 0x24 @@ -341,24 +343,33 @@ static void pmc_32kwritel(u32 val, unsigned long offs) udelay(130); } -static void tegra_setup_warmboot(void) +static void tegra_setup_warmboot(bool lp0_ok) { - u32 scratch0; - - scratch0 = readl(pmc + PMC_SCRATCH0); - /* lp0 restore is broken in the ap20 a03 boot rom, so fake the - * bootrom into performing a regular boot, but pass a flag to the - * bootloader to bypass the kernel reload and jump to the lp0 - * restore sequence */ - if (tegra_is_ap20_a03()) - scratch0 |= (1<<5); - else - scratch0 |= 1; + if (lp0_ok) { + u32 scratch0; + + scratch0 = readl(pmc + PMC_SCRATCH0); + /* lp0 restore is broken in the ap20 a03 boot rom, so fake the + * bootrom into performing a regular boot, but pass a flag to the + * bootloader to bypass the kernel reload and jump to the lp0 + * restore sequence */ + if (tegra_is_ap20_a03()) + scratch0 |= (1<<5); + else + scratch0 |= 1; - pmc_32kwritel(scratch0, PMC_SCRATCH0); + pmc_32kwritel(scratch0, PMC_SCRATCH0); - /* Write the AVP warmboot entry address in SCRATCH1 */ - pmc_32kwritel(s_AvpWarmbootEntry, PMC_SCRATCH1); + /* Write the AVP warmboot entry address in SCRATCH1 */ + pmc_32kwritel(s_AvpWarmbootEntry, PMC_SCRATCH1); + + /* Write the CPU LP0 reset vector address in SCRATCH41 */ + writel(virt_to_phys(tegra_lp2_startup), pmc + PMC_SCRATCH41); + } else { + /* Setup LP1 start addresses */ + writel(TEGRA_IRAM_CODE_AREA, evp_reset); + writel(virt_to_phys(tegra_lp2_startup), pmc + PMC_SCRATCH1); + } } static void tegra_setup_wakepads(bool lp0_ok) @@ -434,7 +445,6 @@ static void tegra_suspend_dram(bool lp0_ok) mode |= ((reg >> TEGRA_POWER_PMC_SHIFT) & TEGRA_POWER_PMC_MASK); if (!lp0_ok) { - writel(TEGRA_IRAM_CODE_AREA, evp_reset); NvRmPrivPowerSetState(s_hRmGlobal, NvRmPowerState_LP1); mode |= TEGRA_POWER_CPU_PWRREQ_OE; @@ -445,7 +455,7 @@ static void tegra_suspend_dram(bool lp0_ok) mode &= ~TEGRA_POWER_EFFECT_LP0; } else { NvRmPrivPowerSetState(s_hRmGlobal, NvRmPowerState_LP0); - tegra_setup_warmboot(); + mode |= TEGRA_POWER_CPU_PWRREQ_OE; mode |= TEGRA_POWER_PWRREQ_OE; mode |= TEGRA_POWER_EFFECT_LP0; @@ -462,6 +472,7 @@ static void tegra_suspend_dram(bool lp0_ok) } } + tegra_setup_warmboot(lp0_ok); tegra_setup_wakepads(lp0_ok); suspend_cpu_complex(); flush_cache_all(); @@ -497,8 +508,7 @@ static void tegra_suspend_dram(bool lp0_ok) static int tegra_suspend_prepare(void) { #ifdef CONFIG_TEGRA_NVRM - NvOdmSocPowerState state = - NvOdmQueryLowestSocPowerState()->LowestPowerState; + NvOdmSocPowerState state = NvRmPowerLowestStateGet(); NvRmPrivDfsSuspend(state); NvRmPrivPmuLPxStateConfig(s_hRmGlobal, state, NV_TRUE); @@ -509,8 +519,7 @@ static int tegra_suspend_prepare(void) static void tegra_suspend_finish(void) { #ifdef CONFIG_TEGRA_NVRM - NvOdmSocPowerState state = - NvOdmQueryLowestSocPowerState()->LowestPowerState; + NvOdmSocPowerState state = NvRmPowerLowestStateGet(); NvRmPrivPmuLPxStateConfig(s_hRmGlobal, state, NV_FALSE); #endif @@ -665,10 +674,11 @@ static int tegra_suspend_enter(suspend_state_t state) unsigned long flags; u32 mc_data[2]; int irq; + bool lp0_ok = (pdata->core_off && (!core_lock_on)); local_irq_save(flags); - if (pdata->core_off) { + if (lp0_ok) { tegra_irq_suspend(); tegra_dma_suspend(); tegra_pinmux_suspend(); @@ -691,7 +701,7 @@ static int tegra_suspend_enter(suspend_state_t state) NvRmPrivPowerSetState(s_hRmGlobal, NvRmPowerState_LP1); tegra_suspend_lp2(0); } else - tegra_suspend_dram(pdata->core_off); + tegra_suspend_dram(lp0_ok); for_each_irq_desc(irq, desc) { if ((desc->status & IRQ_WAKEUP) && @@ -703,7 +713,7 @@ static int tegra_suspend_enter(suspend_state_t state) /* Clear DPD sample */ writel(0x0, pmc + PMC_DPD_SAMPLE); - if (pdata->core_off) { + if (lp0_ok) { writel(mc_data[0], mc + MC_SECURITY_START); writel(mc_data[1], mc + MC_SECURITY_SIZE); |