msm: acpuclock-krait: Don't vote for PLL regulators in power-collapse paths.
The HFPLL regulator votes are active-set-only votes. This allows
us to get away with not voting for the HFPLL regulators in the
power collapse path by allowing the sleep-set <-> active-set
transition in the RPM to take care of this for us. Thus:
1. In the power-collapse path, if a CPU or the L2 switches from
an HFPLL source to a non HFPLL source, the regulator votes
remain in place, but will be removed once apps transitions
to its sleep set.
2. In the power-collapse path, if a CPU or the L2 switches from
a non HFPLL source to a non HFPLL source, the regulator votes
are already not present.
3. In the resume path, when apps transitions to its active set,
the HFPLL regulators would be turned back on before the HFPLL
source is reselected.
Change-Id: Ifc66aaf23d601654367792ff2fb2cc35580db241
Signed-off-by: Vikram Mulukutla <markivx@codeaurora.org>
(cherry picked from commit 3a78830598a34f67b48780b7e9e0f25f4448fd66)
diff --git a/arch/arm/mach-msm/acpuclock-krait.c b/arch/arm/mach-msm/acpuclock-krait.c
index bfb3df3..b3e6145 100644
--- a/arch/arm/mach-msm/acpuclock-krait.c
+++ b/arch/arm/mach-msm/acpuclock-krait.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2011-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
@@ -219,7 +219,8 @@
}
/* Set the CPU or L2 clock speed. */
-static void set_speed(struct scalable *sc, const struct core_speed *tgt_s)
+static void set_speed(struct scalable *sc, const struct core_speed *tgt_s,
+ bool skip_regulators)
{
const struct core_speed *strt_s = sc->cur_speed;
@@ -242,10 +243,10 @@
set_pri_clk_src(sc, tgt_s->pri_src_sel);
} else if (strt_s->src == HFPLL && tgt_s->src != HFPLL) {
set_pri_clk_src(sc, tgt_s->pri_src_sel);
- hfpll_disable(sc, false);
+ hfpll_disable(sc, skip_regulators);
} else if (strt_s->src != HFPLL && tgt_s->src == HFPLL) {
hfpll_set_rate(sc, tgt_s);
- hfpll_enable(sc, false);
+ hfpll_enable(sc, skip_regulators);
set_pri_clk_src(sc, tgt_s->pri_src_sel);
}
@@ -445,6 +446,7 @@
int tgt_l2_l;
struct vdd_data vdd_data;
unsigned long flags;
+ bool skip_regulators;
int rc = 0;
if (cpu > num_possible_cpus())
@@ -493,8 +495,17 @@
dev_dbg(drv.dev, "Switching from ACPU%d rate %lu KHz -> %lu KHz\n",
cpu, strt_acpu_s->khz, tgt_acpu_s->khz);
+ /*
+ * If we are setting the rate as part of power collapse or in the resume
+ * path after power collapse, skip the vote for the HFPLL regulators,
+ * which are active-set-only votes that will be removed when apps enters
+ * its sleep set. This is needed to avoid voting for regulators with
+ * sleeping APIs from an atomic context.
+ */
+ skip_regulators = (reason == SETRATE_PC);
+
/* Set the new CPU speed. */
- set_speed(&drv.scalable[cpu], tgt_acpu_s);
+ set_speed(&drv.scalable[cpu], tgt_acpu_s, skip_regulators);
/*
* Update the L2 vote and apply the rate change. A spinlock is
@@ -505,7 +516,8 @@
*/
spin_lock_irqsave(&l2_lock, flags);
tgt_l2_l = compute_l2_level(&drv.scalable[cpu], tgt->l2_level);
- set_speed(&drv.scalable[L2], &drv.l2_freq_tbl[tgt_l2_l].speed);
+ set_speed(&drv.scalable[L2], &drv.l2_freq_tbl[tgt_l2_l].speed,
+ skip_regulators);
spin_unlock_irqrestore(&l2_lock, flags);
/* Nothing else to do for power collapse or SWFI. */