msm: clock-voter: Support default rate votes using the handoff feature
For some system clocks, it is necessary to enforce default rate votes
that persist until all drivers that will control these clocks have
initialized and made their initial requests.
Take, for example, a memory clock and the following sequence of events
that could occur during boot:
1) Bootloaders set the memory clock to 400MHz.
2) Driver A requires only 27MHz and asserts that as its vote. Since
this is the only vote, memory slows to 27MHz and system performance
slows to a crawl.
3) Driver A finishes its operation and decreases its vote to 0MHz.
Since it was the only voter, the memory clock turns off and the
system crashes.
All of this happens before Driver B, which is responsible for setting
the memory performance floor, has had a chance to initialize and assert
its own vote to keep the clock on at a decent rate.
In this simple example, the problem could be fixed by initializing
Driver B before Driver A, but such re-orderings are not always possible
due to boot dependencies.
The solution presented by this change is to allow default votes to be
associated with voter clocks. These will be asserted during clock
driver initialization using the handoff mechanism, and de-asserted
as part of the lateinit handoff mechanism or when a driver enables
the voter clock, whichever comes first.
Change-Id: I8de85d436ba18d7fe8088a7a489532e28de435a2
Signed-off-by: Matt Wagantall <mattw@codeaurora.org>
diff --git a/arch/arm/mach-msm/clock-7x30.c b/arch/arm/mach-msm/clock-7x30.c
index b161030..f9d8dbe 100644
--- a/arch/arm/mach-msm/clock-7x30.c
+++ b/arch/arm/mach-msm/clock-7x30.c
@@ -2415,15 +2415,15 @@
static DEFINE_CLK_PCOM(p_rotator_imem_clk, ROTATOR_IMEM_CLK, 0);
static DEFINE_CLK_PCOM(p_rotator_p_clk, ROTATOR_P_CLK, 0);
-static DEFINE_CLK_VOTER(ebi_dtv_clk, &ebi1_fixed_clk.c);
-static DEFINE_CLK_VOTER(ebi_grp_3d_clk, &ebi1_fixed_clk.c);
-static DEFINE_CLK_VOTER(ebi_grp_2d_clk, &ebi1_fixed_clk.c);
-static DEFINE_CLK_VOTER(ebi_lcdc_clk, &ebi1_fixed_clk.c);
-static DEFINE_CLK_VOTER(ebi_mddi_clk, &ebi1_fixed_clk.c);
-static DEFINE_CLK_VOTER(ebi_tv_clk, &ebi1_fixed_clk.c);
-static DEFINE_CLK_VOTER(ebi_vcd_clk, &ebi1_fixed_clk.c);
-static DEFINE_CLK_VOTER(ebi_vfe_clk, &ebi1_fixed_clk.c);
-static DEFINE_CLK_VOTER(ebi_adm_clk, &ebi1_fixed_clk.c);
+static DEFINE_CLK_VOTER(ebi_dtv_clk, &ebi1_fixed_clk.c, 0);
+static DEFINE_CLK_VOTER(ebi_grp_3d_clk, &ebi1_fixed_clk.c, 0);
+static DEFINE_CLK_VOTER(ebi_grp_2d_clk, &ebi1_fixed_clk.c, 0);
+static DEFINE_CLK_VOTER(ebi_lcdc_clk, &ebi1_fixed_clk.c, 0);
+static DEFINE_CLK_VOTER(ebi_mddi_clk, &ebi1_fixed_clk.c, 0);
+static DEFINE_CLK_VOTER(ebi_tv_clk, &ebi1_fixed_clk.c, 0);
+static DEFINE_CLK_VOTER(ebi_vcd_clk, &ebi1_fixed_clk.c, 0);
+static DEFINE_CLK_VOTER(ebi_vfe_clk, &ebi1_fixed_clk.c, 0);
+static DEFINE_CLK_VOTER(ebi_adm_clk, &ebi1_fixed_clk.c, 0);
#ifdef CONFIG_DEBUG_FS
diff --git a/arch/arm/mach-msm/clock-8960.c b/arch/arm/mach-msm/clock-8960.c
index 0eeaedb..03aad48 100644
--- a/arch/arm/mach-msm/clock-8960.c
+++ b/arch/arm/mach-msm/clock-8960.c
@@ -4476,28 +4476,28 @@
DEFINE_CLK_RPM(sfab_clk, sfab_a_clk, SYSTEM_FABRIC, NULL);
DEFINE_CLK_RPM(sfpb_clk, sfpb_a_clk, SFPB, NULL);
-static DEFINE_CLK_VOTER(sfab_msmbus_a_clk, &sfab_a_clk.c);
-static DEFINE_CLK_VOTER(sfab_tmr_a_clk, &sfab_a_clk.c);
+static DEFINE_CLK_VOTER(sfab_msmbus_a_clk, &sfab_a_clk.c, 0);
+static DEFINE_CLK_VOTER(sfab_tmr_a_clk, &sfab_a_clk.c, 0);
-static DEFINE_CLK_VOTER(dfab_dsps_clk, &dfab_clk.c);
-static DEFINE_CLK_VOTER(dfab_usb_hs_clk, &dfab_clk.c);
-static DEFINE_CLK_VOTER(dfab_usb_hs3_clk, &dfab_clk.c);
-static DEFINE_CLK_VOTER(dfab_usb_hs4_clk, &dfab_clk.c);
-static DEFINE_CLK_VOTER(dfab_sdc1_clk, &dfab_clk.c);
-static DEFINE_CLK_VOTER(dfab_sdc2_clk, &dfab_clk.c);
-static DEFINE_CLK_VOTER(dfab_sdc3_clk, &dfab_clk.c);
-static DEFINE_CLK_VOTER(dfab_sdc4_clk, &dfab_clk.c);
-static DEFINE_CLK_VOTER(dfab_sdc5_clk, &dfab_clk.c);
-static DEFINE_CLK_VOTER(dfab_sps_clk, &dfab_clk.c);
-static DEFINE_CLK_VOTER(dfab_bam_dmux_clk, &dfab_clk.c);
-static DEFINE_CLK_VOTER(dfab_scm_clk, &dfab_clk.c);
-static DEFINE_CLK_VOTER(dfab_qseecom_clk, &dfab_clk.c);
-static DEFINE_CLK_VOTER(dfab_tzcom_clk, &dfab_clk.c);
-static DEFINE_CLK_VOTER(dfab_msmbus_clk, &dfab_clk.c);
-static DEFINE_CLK_VOTER(dfab_msmbus_a_clk, &dfab_a_clk.c);
+static DEFINE_CLK_VOTER(dfab_dsps_clk, &dfab_clk.c, 0);
+static DEFINE_CLK_VOTER(dfab_usb_hs_clk, &dfab_clk.c, 0);
+static DEFINE_CLK_VOTER(dfab_usb_hs3_clk, &dfab_clk.c, 0);
+static DEFINE_CLK_VOTER(dfab_usb_hs4_clk, &dfab_clk.c, 0);
+static DEFINE_CLK_VOTER(dfab_sdc1_clk, &dfab_clk.c, 0);
+static DEFINE_CLK_VOTER(dfab_sdc2_clk, &dfab_clk.c, 0);
+static DEFINE_CLK_VOTER(dfab_sdc3_clk, &dfab_clk.c, 0);
+static DEFINE_CLK_VOTER(dfab_sdc4_clk, &dfab_clk.c, 0);
+static DEFINE_CLK_VOTER(dfab_sdc5_clk, &dfab_clk.c, 0);
+static DEFINE_CLK_VOTER(dfab_sps_clk, &dfab_clk.c, 0);
+static DEFINE_CLK_VOTER(dfab_bam_dmux_clk, &dfab_clk.c, 0);
+static DEFINE_CLK_VOTER(dfab_scm_clk, &dfab_clk.c, 0);
+static DEFINE_CLK_VOTER(dfab_qseecom_clk, &dfab_clk.c, 0);
+static DEFINE_CLK_VOTER(dfab_tzcom_clk, &dfab_clk.c, 0);
+static DEFINE_CLK_VOTER(dfab_msmbus_clk, &dfab_clk.c, 0);
+static DEFINE_CLK_VOTER(dfab_msmbus_a_clk, &dfab_a_clk.c, 0);
-static DEFINE_CLK_VOTER(ebi1_msmbus_clk, &ebi1_clk.c);
-static DEFINE_CLK_VOTER(ebi1_adm_clk, &ebi1_clk.c);
+static DEFINE_CLK_VOTER(ebi1_msmbus_clk, &ebi1_clk.c, 0);
+static DEFINE_CLK_VOTER(ebi1_adm_clk, &ebi1_clk.c, 0);
#ifdef CONFIG_DEBUG_FS
struct measure_sel {
diff --git a/arch/arm/mach-msm/clock-8x60.c b/arch/arm/mach-msm/clock-8x60.c
index 6716b44..2a1e068 100644
--- a/arch/arm/mach-msm/clock-8x60.c
+++ b/arch/arm/mach-msm/clock-8x60.c
@@ -3123,18 +3123,18 @@
DEFINE_CLK_RPM(sfpb_clk, sfpb_a_clk, SFPB, NULL);
DEFINE_CLK_RPM(smi_clk, smi_a_clk, SMI, &smi_2x_axi_clk.c);
-static DEFINE_CLK_VOTER(dfab_dsps_clk, &dfab_clk.c);
-static DEFINE_CLK_VOTER(dfab_usb_hs_clk, &dfab_clk.c);
-static DEFINE_CLK_VOTER(dfab_sdc1_clk, &dfab_clk.c);
-static DEFINE_CLK_VOTER(dfab_sdc2_clk, &dfab_clk.c);
-static DEFINE_CLK_VOTER(dfab_sdc3_clk, &dfab_clk.c);
-static DEFINE_CLK_VOTER(dfab_sdc4_clk, &dfab_clk.c);
-static DEFINE_CLK_VOTER(dfab_sdc5_clk, &dfab_clk.c);
-static DEFINE_CLK_VOTER(dfab_scm_clk, &dfab_clk.c);
+static DEFINE_CLK_VOTER(dfab_dsps_clk, &dfab_clk.c, 0);
+static DEFINE_CLK_VOTER(dfab_usb_hs_clk, &dfab_clk.c, 0);
+static DEFINE_CLK_VOTER(dfab_sdc1_clk, &dfab_clk.c, 0);
+static DEFINE_CLK_VOTER(dfab_sdc2_clk, &dfab_clk.c, 0);
+static DEFINE_CLK_VOTER(dfab_sdc3_clk, &dfab_clk.c, 0);
+static DEFINE_CLK_VOTER(dfab_sdc4_clk, &dfab_clk.c, 0);
+static DEFINE_CLK_VOTER(dfab_sdc5_clk, &dfab_clk.c, 0);
+static DEFINE_CLK_VOTER(dfab_scm_clk, &dfab_clk.c, 0);
-static DEFINE_CLK_VOTER(ebi1_msmbus_clk, &ebi1_clk.c);
-static DEFINE_CLK_VOTER(ebi1_adm0_clk, &ebi1_clk.c);
-static DEFINE_CLK_VOTER(ebi1_adm1_clk, &ebi1_clk.c);
+static DEFINE_CLK_VOTER(ebi1_msmbus_clk, &ebi1_clk.c, 0);
+static DEFINE_CLK_VOTER(ebi1_adm0_clk, &ebi1_clk.c, 0);
+static DEFINE_CLK_VOTER(ebi1_adm1_clk, &ebi1_clk.c, 0);
static DEFINE_CLK_MEASURE(sc0_m_clk);
static DEFINE_CLK_MEASURE(sc1_m_clk);
diff --git a/arch/arm/mach-msm/clock-9615.c b/arch/arm/mach-msm/clock-9615.c
index 89e3036..11ec487 100644
--- a/arch/arm/mach-msm/clock-9615.c
+++ b/arch/arm/mach-msm/clock-9615.c
@@ -1351,15 +1351,15 @@
DEFINE_CLK_RPM(sfab_clk, sfab_a_clk, SYSTEM_FABRIC, NULL);
DEFINE_CLK_RPM(sfpb_clk, sfpb_a_clk, SFPB, NULL);
-static DEFINE_CLK_VOTER(dfab_usb_hs_clk, &dfab_clk.c);
-static DEFINE_CLK_VOTER(dfab_sdc1_clk, &dfab_clk.c);
-static DEFINE_CLK_VOTER(dfab_sdc2_clk, &dfab_clk.c);
-static DEFINE_CLK_VOTER(dfab_sps_clk, &dfab_clk.c);
-static DEFINE_CLK_VOTER(dfab_bam_dmux_clk, &dfab_clk.c);
-static DEFINE_CLK_VOTER(dfab_msmbus_clk, &dfab_clk.c);
-static DEFINE_CLK_VOTER(dfab_msmbus_a_clk, &dfab_a_clk.c);
-static DEFINE_CLK_VOTER(ebi1_msmbus_clk, &ebi1_clk.c);
-static DEFINE_CLK_VOTER(ebi1_adm_clk, &ebi1_clk.c);
+static DEFINE_CLK_VOTER(dfab_usb_hs_clk, &dfab_clk.c, 0);
+static DEFINE_CLK_VOTER(dfab_sdc1_clk, &dfab_clk.c, 0);
+static DEFINE_CLK_VOTER(dfab_sdc2_clk, &dfab_clk.c, 0);
+static DEFINE_CLK_VOTER(dfab_sps_clk, &dfab_clk.c, 0);
+static DEFINE_CLK_VOTER(dfab_bam_dmux_clk, &dfab_clk.c, 0);
+static DEFINE_CLK_VOTER(dfab_msmbus_clk, &dfab_clk.c, 0);
+static DEFINE_CLK_VOTER(dfab_msmbus_a_clk, &dfab_a_clk.c, 0);
+static DEFINE_CLK_VOTER(ebi1_msmbus_clk, &ebi1_clk.c, 0);
+static DEFINE_CLK_VOTER(ebi1_adm_clk, &ebi1_clk.c, 0);
#ifdef CONFIG_DEBUG_FS
struct measure_sel {
diff --git a/arch/arm/mach-msm/clock-pcom-lookup.c b/arch/arm/mach-msm/clock-pcom-lookup.c
index 99b6501..2d98895 100644
--- a/arch/arm/mach-msm/clock-pcom-lookup.c
+++ b/arch/arm/mach-msm/clock-pcom-lookup.c
@@ -179,15 +179,15 @@
static DEFINE_CLK_PCOM(vfe_clk, VFE_CLK, 0);
static DEFINE_CLK_PCOM(vfe_mdc_clk, VFE_MDC_CLK, 0);
-static DEFINE_CLK_VOTER(ebi_acpu_clk, &ebi1_clk.c);
-static DEFINE_CLK_VOTER(ebi_grp_3d_clk, &ebi1_clk.c);
-static DEFINE_CLK_VOTER(ebi_grp_2d_clk, &ebi1_clk.c);
-static DEFINE_CLK_VOTER(ebi_lcdc_clk, &ebi1_clk.c);
-static DEFINE_CLK_VOTER(ebi_mddi_clk, &ebi1_clk.c);
-static DEFINE_CLK_VOTER(ebi_tv_clk, &ebi1_clk.c);
-static DEFINE_CLK_VOTER(ebi_usb_clk, &ebi1_clk.c);
-static DEFINE_CLK_VOTER(ebi_vfe_clk, &ebi1_clk.c);
-static DEFINE_CLK_VOTER(ebi_adm_clk, &ebi1_clk.c);
+static DEFINE_CLK_VOTER(ebi_acpu_clk, &ebi1_clk.c, 0);
+static DEFINE_CLK_VOTER(ebi_grp_3d_clk, &ebi1_clk.c, 0);
+static DEFINE_CLK_VOTER(ebi_grp_2d_clk, &ebi1_clk.c, 0);
+static DEFINE_CLK_VOTER(ebi_lcdc_clk, &ebi1_clk.c, 0);
+static DEFINE_CLK_VOTER(ebi_mddi_clk, &ebi1_clk.c, 0);
+static DEFINE_CLK_VOTER(ebi_tv_clk, &ebi1_clk.c, 0);
+static DEFINE_CLK_VOTER(ebi_usb_clk, &ebi1_clk.c, 0);
+static DEFINE_CLK_VOTER(ebi_vfe_clk, &ebi1_clk.c, 0);
+static DEFINE_CLK_VOTER(ebi_adm_clk, &ebi1_clk.c, 0);
static struct clk_lookup msm_clocks_7x01a[] = {
CLK_LOOKUP("core_clk", adm_clk.c, "msm_dmov"),
diff --git a/arch/arm/mach-msm/clock-voter.c b/arch/arm/mach-msm/clock-voter.c
index 8ff4878..177af8c 100644
--- a/arch/arm/mach-msm/clock-voter.c
+++ b/arch/arm/mach-msm/clock-voter.c
@@ -147,6 +147,15 @@
return true;
}
+enum handoff voter_clk_handoff(struct clk *clk)
+{
+ /* Apply default rate vote */
+ if (clk->rate)
+ return HANDOFF_ENABLED_CLK;
+
+ return HANDOFF_DISABLED_CLK;
+}
+
struct clk_ops clk_ops_voter = {
.enable = voter_clk_enable,
.disable = voter_clk_disable,
diff --git a/arch/arm/mach-msm/clock-voter.h b/arch/arm/mach-msm/clock-voter.h
index de17894..c9aebba 100644
--- a/arch/arm/mach-msm/clock-voter.h
+++ b/arch/arm/mach-msm/clock-voter.h
@@ -28,13 +28,14 @@
return container_of(clk, struct clk_voter, c);
}
-#define DEFINE_CLK_VOTER(clk_name, _parent) \
+#define DEFINE_CLK_VOTER(clk_name, _parent, _default_rate) \
struct clk_voter clk_name = { \
.parent = _parent, \
.c = { \
.dbg_name = #clk_name, \
.ops = &clk_ops_voter, \
.flags = CLKFLAG_SKIP_AUTO_OFF, \
+ .rate = _default_rate, \
CLK_INIT(clk_name.c), \
}, \
}