diff options
author | Alex Frid <afrid@nvidia.com> | 2010-06-09 19:33:57 -0700 |
---|---|---|
committer | Gary King <gking@nvidia.com> | 2010-07-02 07:15:44 -0700 |
commit | a3562cf11c826bc29e3f76ec6c31fa8376e88524 (patch) | |
tree | d4753cbb2c33bfd9feed26ec2dd3e05102956404 | |
parent | 3835a7b2eb6d95033c84c03d97c83958c491df59 (diff) |
[ARM/tegra] ODM: Resequenced USB_AVDD power control.
Attached USB_AVDD rail to PMU power enable input on entry to LP0, so
that it is guaranteed to be turned On in h/w before bootrom code starts.
Restored default USB_AVDD control configuration on LP0 exit, and keep it
enabled until USB driver takes over.
Since the USB_AVDD re-configuration must happen after USB driver suspend
during LP0 entry, and before USB driver resume during LP0 exit, moved RM
PMU-related operations from pm notifier callbacks to platform .prepare
method (called after all drivers are suspended, but before irqs are
disabled), and its .finish counterpart.
Bug 702919
Bug 691042
Change-Id: I98d48ae15e960f41dd441fe3c38337ac04649a5e
Reviewed-on: http://git-master.nvidia.com/r/2365
Tested-by: Aleksandr Frid <afrid@nvidia.com>
Reviewed-by: Gary King <gking@nvidia.com>
4 files changed, 60 insertions, 5 deletions
diff --git a/arch/arm/mach-tegra/nvrm_user.c b/arch/arm/mach-tegra/nvrm_user.c index 4125769b1e59..f5ab25bd5d3d 100644 --- a/arch/arm/mach-tegra/nvrm_user.c +++ b/arch/arm/mach-tegra/nvrm_user.c @@ -545,8 +545,6 @@ static void notify_daemon(const char* notice) int tegra_pm_notifier(struct notifier_block *nb, unsigned long event, void *nouse) { - NvOdmSocPowerState state = - NvOdmQueryLowestSocPowerState()->LowestPowerState; printk(KERN_INFO "%s: start processing event=%lx\n", __func__, event); // Notify the event to nvrm_daemon. @@ -556,11 +554,8 @@ int tegra_pm_notifier(struct notifier_block *nb, notify_daemon(STRING_PM_DISPLAY_OFF); #endif notify_daemon(STRING_PM_SUSPEND_PREPARE); - NvRmPrivDfsSuspend(state); - NvRmPrivPmuLPxStateConfig(s_hRmGlobal, state, NV_TRUE); break; case PM_POST_SUSPEND: - NvRmPrivPmuLPxStateConfig(s_hRmGlobal, state, NV_FALSE); notify_daemon(STRING_PM_POST_SUSPEND); #ifndef CONFIG_HAS_EARLYSUSPEND notify_daemon(STRING_PM_DISPLAY_ON); diff --git a/arch/arm/mach-tegra/odm_kit/adaptations/pmu/max8907b/max8907b.c b/arch/arm/mach-tegra/odm_kit/adaptations/pmu/max8907b/max8907b.c index fdd3b3eeffa1..d7f38d091b29 100644 --- a/arch/arm/mach-tegra/odm_kit/adaptations/pmu/max8907b/max8907b.c +++ b/arch/arm/mach-tegra/odm_kit/adaptations/pmu/max8907b/max8907b.c @@ -75,6 +75,12 @@ Max8907bPrivData *hMax8907bPmu; // sequencer 2 because of the bug in the silicon. #define MAX8907B_II2RR_PWREN_WAR (0x12) +// Power up AVDD_USB on exit from deep sleep mode together with core rail, +// before boot code starts, and keep it On during resume until USB driver +// takes over +#define WAR_AVDD_USB_EARLY_PWR_UP 1 +#define WAR_AVDD_USB_RESUME_KEEP_ON 1 + /** * The FAN5355 is used to scale the voltage of an external * DC/DC voltage rail (for PCIE). However, voltage scaling is @@ -1269,6 +1275,8 @@ Max8907bPwrEnAttach( Max8907bPmuSupply Supply, NvBool Attach) { + static NvU8 s_ResumeSeqSelLdo4 = MAX8907B_SEQSEL_DEFAULT_LDO4; + NvU8 CtlAddr, CtlData, CntAddr, CntData, SeqSel; switch (Supply) @@ -1290,12 +1298,25 @@ Max8907bPwrEnAttach( if (!Max8907bI2cWrite8(hDevice, CntAddr, CntData)) return NV_FALSE; +#if WAR_AVDD_USB_EARLY_PWR_UP + // Attach USB rail to sequencer 2 as well, when core is attached + // (= entry to LP0), and dettach it respectively. + if (!Max8907bPwrEnAttach(hDevice, Max8907bPmuSupply_LDO4, Attach)) + return NV_FALSE; +#endif CntData = Attach ? MAX8907B_SEQCNT_PWREN_LX_V2 : MAX8907B_SEQCNT_DEFAULT_LX_V2; SeqSel = Attach ? MAX8907B_SEQSEL_PWREN_LXX : MAX8907B_SEQSEL_DEFAULT_LX_V2; break; + case Max8907bPmuSupply_LDO4: // USB + CntData = Attach ? MAX8907B_SEQCNT_PWREN_LD04 : + MAX8907B_SEQCNT_DEFAULT_LDO4; + SeqSel = Attach ? MAX8907B_SEQSEL_PWREN_LXX : + s_ResumeSeqSelLdo4; + break; + default: NV_ASSERT(!"This supply must not be attached to PWREN"); return NV_FALSE; @@ -1306,6 +1327,18 @@ Max8907bPwrEnAttach( // Read control refgister, and select target sequencer if (!Max8907bI2cRead8(hDevice, CtlAddr, &CtlData)) return NV_FALSE; + + if (Supply == Max8907bPmuSupply_LDO4) + { + NvU8 seq = (CtlData >> MAX8907B_CTL_SEQ_SHIFT) & MAX8907B_CTL_SEQ_MASK; + NvOdmOsPrintf("[NVODM PMU] AVDD_USB switching sequencer from %d to %d," + " (control was = 0x%x)\n", seq, SeqSel, CtlData); +#if !WAR_AVDD_USB_RESUME_KEEP_ON + if (Attach) + s_ResumeSeqSelLdo4 = seq; // save to restore on LP0 resume +#endif + } + CtlData &= (~(MAX8907B_CTL_SEQ_MASK << MAX8907B_CTL_SEQ_SHIFT )); CtlData |= ((SeqSel & MAX8907B_CTL_SEQ_MASK) << MAX8907B_CTL_SEQ_SHIFT ); diff --git a/arch/arm/mach-tegra/odm_kit/adaptations/pmu/max8907b/max8907b_supply_info_table.h b/arch/arm/mach-tegra/odm_kit/adaptations/pmu/max8907b/max8907b_supply_info_table.h index 77cf70bc32b5..9ab16636f7b9 100644 --- a/arch/arm/mach-tegra/odm_kit/adaptations/pmu/max8907b/max8907b_supply_info_table.h +++ b/arch/arm/mach-tegra/odm_kit/adaptations/pmu/max8907b/max8907b_supply_info_table.h @@ -79,6 +79,7 @@ extern "C" // Defines default sequencer selection #define MAX8907B_SEQSEL_DEFAULT_LX_V1 0 /* SEQ1 (SYSEN) */ #define MAX8907B_SEQSEL_DEFAULT_LX_V2 0 /* SEQ1 (SYSEN) */ +#define MAX8907B_SEQSEL_DEFAULT_LDO4 0 /* SEQ1 (SYSEN) */ // Defines common for all supplies PWREN sequencer selection #define MAX8907B_SEQSEL_PWREN_LXX 1 /* SEQ2 (PWREN) */ @@ -89,6 +90,7 @@ extern "C" // Defines sequencer count default values #define MAX8907B_SEQCNT_DEFAULT_LX_V1 0x1C #define MAX8907B_SEQCNT_DEFAULT_LX_V2 0x1C +#define MAX8907B_SEQCNT_DEFAULT_LDO4 0x72 // Defines sequencer count PWREN control values (these settings applied // togeteher, when both CPU/V1 and CORE/V2 rails are attached to PWREN; @@ -97,6 +99,7 @@ extern "C" // B[3:0] - power down delay in 20us taps #define MAX8907B_SEQCNT_PWREN_LX_V1 0xC0 /* 240us up delay */ #define MAX8907B_SEQCNT_PWREN_LX_V2 0x00 /* no delay */ +#define MAX8907B_SEQCNT_PWREN_LD04 0x00 /* no delay */ // Defines PMU output timing parameters. Scaling up time is dynamically // calculated based on the slew rate maintained by MAX8907B. Turn On delay diff --git a/arch/arm/mach-tegra/suspend.c b/arch/arm/mach-tegra/suspend.c index 240ab30b1793..d40386313d01 100644 --- a/arch/arm/mach-tegra/suspend.c +++ b/arch/arm/mach-tegra/suspend.c @@ -414,6 +414,28 @@ static void tegra_suspend_dram(bool lp0_ok) wmb(); } +static int tegra_suspend_prepare(void) +{ +#ifdef CONFIG_TEGRA_NVRM + NvOdmSocPowerState state = + NvOdmQueryLowestSocPowerState()->LowestPowerState; + + NvRmPrivDfsSuspend(state); + NvRmPrivPmuLPxStateConfig(s_hRmGlobal, state, NV_TRUE); +#endif + return 0; +} + +static void tegra_suspend_finish(void) +{ +#ifdef CONFIG_TEGRA_NVRM + NvOdmSocPowerState state = + NvOdmQueryLowestSocPowerState()->LowestPowerState; + + NvRmPrivPmuLPxStateConfig(s_hRmGlobal, state, NV_FALSE); +#endif +} + static int tegra_suspend_prepare_late(void) { #ifdef CONFIG_TEGRA_NVRM @@ -610,6 +632,8 @@ static int tegra_suspend_enter(suspend_state_t state) static struct platform_suspend_ops tegra_suspend_ops = { .valid = suspend_valid_only_mem, + .prepare = tegra_suspend_prepare, + .finish = tegra_suspend_finish, .prepare_late = tegra_suspend_prepare_late, .wake = tegra_suspend_wake, .enter = tegra_suspend_enter, |