msm: clock-8974: Add support for the HDMI PHY PLL
The mdss_extpclk clock is sourced from the HDMI PHY PLL, which
is programmed by the HDMI driver. Add support for this PLL, and
link up the PLL with the exptclk via the set_rate op in the RCG.
Change-Id: I32d31780bab32c4bef92dbe230014030f8dc9a06
Signed-off-by: Vikram Mulukutla <markivx@codeaurora.org>
Signed-off-by: Neha Pandey <nehap@codeaurora.org>
diff --git a/arch/arm/mach-msm/clock-8974.c b/arch/arm/mach-msm/clock-8974.c
index 5b39727..ce45008 100644
--- a/arch/arm/mach-msm/clock-8974.c
+++ b/arch/arm/mach-msm/clock-8974.c
@@ -521,7 +521,7 @@
#define dsipll_750_mm_source_val 1
#define dsipll0_byte_mm_source_val 1
#define dsipll0_pixel_mm_source_val 1
-#define hdmipll_297_mm_source_val 3
+#define hdmipll_mm_source_val 3
#define F(f, s, div, m, n) \
{ \
@@ -545,6 +545,17 @@
| BVAL(10, 8, s##_mm_source_val), \
}
+#define F_HDMI(f, s, div, m, n) \
+ { \
+ .freq_hz = (f), \
+ .src_clk = &s##_clk_src, \
+ .m_val = (m), \
+ .n_val = ~((n)-(m)) * !!(n), \
+ .d_val = ~(n),\
+ .div_src_val = BVAL(4, 0, (int)(2*(div) - 1)) \
+ | BVAL(10, 8, s##_mm_source_val), \
+ }
+
#define F_MDSS(f, s, div, m, n) \
{ \
.freq_hz = (f), \
@@ -2942,14 +2953,85 @@
},
};
+static int hdmi_pll_clk_enable(struct clk *c)
+{
+ int ret;
+ unsigned long flags;
+
+ spin_lock_irqsave(&local_clock_reg_lock, flags);
+ ret = hdmi_pll_enable();
+ spin_unlock_irqrestore(&local_clock_reg_lock, flags);
+ return ret;
+}
+
+static void hdmi_pll_clk_disable(struct clk *c)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&local_clock_reg_lock, flags);
+ hdmi_pll_disable();
+ spin_unlock_irqrestore(&local_clock_reg_lock, flags);
+}
+
+static int hdmi_pll_clk_set_rate(struct clk *c, unsigned long rate)
+{
+ unsigned long flags;
+ int rc;
+
+ spin_lock_irqsave(&local_clock_reg_lock, flags);
+ rc = hdmi_pll_set_rate(rate);
+ spin_unlock_irqrestore(&local_clock_reg_lock, flags);
+
+ return rc;
+}
+
+static struct clk *hdmi_pll_clk_get_parent(struct clk *c)
+{
+ return &cxo_clk_src.c;
+}
+
+static struct clk_ops clk_ops_hdmi_pll = {
+ .enable = hdmi_pll_clk_enable,
+ .disable = hdmi_pll_clk_disable,
+ .set_rate = hdmi_pll_clk_set_rate,
+ .get_parent = hdmi_pll_clk_get_parent,
+};
+
+static struct clk hdmipll_clk_src = {
+ .dbg_name = "hdmipll_clk_src",
+ .ops = &clk_ops_hdmi_pll,
+ CLK_INIT(hdmipll_clk_src),
+ .warned = true,
+};
+
static struct clk_freq_tbl ftbl_mdss_extpclk_clk[] = {
- F_MDSS(148500000, hdmipll_297, 2, 0, 0),
+ /*
+ * The zero rate is required since suspend/resume wipes out the HDMI PHY
+ * registers. This entry allows the HDMI driver to switch the cached
+ * rate to zero before suspend and back to the real rate after resume.
+ */
+ F_HDMI( 0, hdmipll, 1, 0, 0),
+ F_HDMI( 25200000, hdmipll, 1, 0, 0),
+ F_HDMI( 27030000, hdmipll, 1, 0, 0),
+ F_HDMI( 74250000, hdmipll, 1, 0, 0),
+ F_HDMI(148500000, hdmipll, 1, 0, 0),
+ F_HDMI(297000000, hdmipll, 1, 0, 0),
F_END
};
+/*
+ * Unlike other clocks, the HDMI rate is adjusted through PLL
+ * re-programming. It is also routed through an HID divider.
+ */
+static void set_rate_hdmi(struct rcg_clk *rcg, struct clk_freq_tbl *nf)
+{
+ clk_set_rate(nf->src_clk, nf->freq_hz);
+ set_rate_hid(rcg, nf);
+}
+
static struct rcg_clk extpclk_clk_src = {
.cmd_rcgr_reg = EXTPCLK_CMD_RCGR,
- .set_rate = set_rate_hid,
+ .set_rate = set_rate_hdmi,
.freq_tbl = ftbl_mdss_extpclk_clk,
.current_freq = &rcg_dummy_freq,
.base = &virt_bases[MMSS_BASE],