From 9ce61ba4ead6428bd8b590fa84a2fc806f56ca5b Mon Sep 17 00:00:00 2001 From: Jay Chokshi Date: Thu, 6 Dec 2012 20:48:23 -0800 Subject: [PATCH] msm: Ensure droop detectors do not affect krait PLLs The Droop detector mechanism present in Glitch-Free (GFMUX) goes to nondeterministic state during frequent standalone power collapse operation. It affects Krait PLL output so that the PLL won't lock to required frequency. Since Droop detector isn't used, set sc_pdn (PLL_CLAMP) permanently high to ensure droop detector is off and it does not affect Krait PLL. CRs-Fixed: 381144 Conflicts: arch/arm/mach-msm/Kconfig arch/arm/mach-msm/Makefile Change-Id: I69a0dffeccaa3837302d6e3dd53f6b62fa683368 Signed-off-by: Jay Chokshi Signed-off-by: Neha Pandey --- arch/arm/mach-msm/Kconfig | 10 ++++ arch/arm/mach-msm/Makefile | 1 + arch/arm/mach-msm/msm_cpu_pwrctl.c | 93 ++++++++++++++++++++++++++++++ 3 files changed, 104 insertions(+) create mode 100644 arch/arm/mach-msm/msm_cpu_pwrctl.c diff --git a/arch/arm/mach-msm/Kconfig b/arch/arm/mach-msm/Kconfig index a1611807f25..82468c838d2 100644 --- a/arch/arm/mach-msm/Kconfig +++ b/arch/arm/mach-msm/Kconfig @@ -177,6 +177,7 @@ config ARCH_MSM8960 select ARM_HAS_SG_CHAIN select MSM_KRAIT_WFE_FIXUP select MSM_IOMMU_GPU_SYNC + select MSM_CPU_PWRCTL config ARCH_MSM8930 bool "MSM8930" @@ -210,6 +211,7 @@ config ARCH_MSM8930 select ARM_HAS_SG_CHAIN select MSM_KRAIT_WFE_FIXUP select MSM_IOMMU_GPU_SYNC + select MSM_CPU_PWRCTL config ARCH_APQ8064 bool "APQ8064" @@ -238,6 +240,7 @@ config ARCH_APQ8064 select ARM_HAS_SG_CHAIN select MSM_KRAIT_WFE_FIXUP select MSM_IOMMU_GPU_SYNC + select MSM_CPU_PWRCTL config ARCH_MSM8974 bool "MSM8974" @@ -2593,4 +2596,11 @@ config MSM_HSIC_SYSMON_TEST can be read and written to send character data to the sysmon port of the modem over USB. +config MSM_CPU_PWRCTL + bool "Ensures that krait droop detectors are always off" + help + Droop detector mechanism can adversely affect krait plls during + stand alone power collapse operation. Selecting this option + ensures that they are always off. + endif diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile index 492e30500ea..e496a9e95b6 100644 --- a/arch/arm/mach-msm/Makefile +++ b/arch/arm/mach-msm/Makefile @@ -389,3 +389,4 @@ obj-$(CONFIG_MSM_VP_REGULATOR) += msm_vp.o ifdef CONFIG_MSM_CPR obj-$(CONFIG_DEBUG_FS) += msm_cpr-debug.o endif +obj-$(CONFIG_MSM_CPU_PWRCTL) += msm_cpu_pwrctl.o diff --git a/arch/arm/mach-msm/msm_cpu_pwrctl.c b/arch/arm/mach-msm/msm_cpu_pwrctl.c new file mode 100644 index 00000000000..6e339dd0567 --- /dev/null +++ b/arch/arm/mach-msm/msm_cpu_pwrctl.c @@ -0,0 +1,93 @@ +/* Copyright (c) 2012, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define MSM_CPU_SECONDARY_CORE_OFFSET 0x10000 + +static const phys_addr_t primary_cpu_pwrctl_phys = 0x2088004; +static DEFINE_PER_CPU(int, pll_clamp_set); +static void msm_cpu_pwrctl_work_cb(struct work_struct *work); +static __cpuinitdata DECLARE_WORK(msm_cpu_pwrctl_work, msm_cpu_pwrctl_work_cb); +static int nr_cpus_done; +static int __cpuinit msm_cpu_pwrctl_cpu_callback(struct notifier_block *nfb, + unsigned long action, void *hcpu); +static struct notifier_block __cpuinitdata msm_cpu_pwrctl_cpu_notifier = { + .notifier_call = msm_cpu_pwrctl_cpu_callback, +}; + +static void __cpuinit msm_cpu_pwrctl_work_cb(struct work_struct *work) +{ + unregister_hotcpu_notifier(&msm_cpu_pwrctl_cpu_notifier); +} + +static int __cpuinit msm_cpu_pwrctl_cpu_callback(struct notifier_block *nfb, + unsigned long action, void *hcpu) +{ + int cpu = (int) hcpu; + int *pll_clamp; + void *pwrctl_ptr; + unsigned int value; + + switch (action & ~CPU_TASKS_FROZEN) { + case CPU_ONLINE: + pll_clamp = &per_cpu(pll_clamp_set, cpu); + if (likely(*pll_clamp)) + goto done; + + pwrctl_ptr = ioremap_nocache(primary_cpu_pwrctl_phys + + (cpu * MSM_CPU_SECONDARY_CORE_OFFSET), SZ_4K); + if (unlikely(!pwrctl_ptr)) + goto done; + + value = readl_relaxed(pwrctl_ptr); + value |= 0x100; + writel_relaxed(value, pwrctl_ptr); + *pll_clamp = 1; + iounmap(pwrctl_ptr); + + if (++nr_cpus_done == cpumask_weight(cpu_possible_mask)) + schedule_work(&msm_cpu_pwrctl_work); +done: + break; + default: + break; + } + + return NOTIFY_OK; + +} + +static int __init msm_cpu_pwrctl_init(void) +{ + int cpu = smp_processor_id(); + + /* We won't get cpu online notification for this CPU, + * so take this opportunity to process this CPU. + */ + msm_cpu_pwrctl_cpu_callback(&msm_cpu_pwrctl_cpu_notifier, + CPU_ONLINE, (void *) cpu); + + register_hotcpu_notifier(&msm_cpu_pwrctl_cpu_notifier); + return 0; +} + +early_initcall(msm_cpu_pwrctl_init);