summaryrefslogtreecommitdiff
path: root/drivers/clk
diff options
context:
space:
mode:
authorKuogee Hsieh <khsieh@codeaurora.org>2015-01-21 15:56:53 -0800
committerDavid Keitel <dkeitel@codeaurora.org>2016-03-23 20:41:39 -0700
commit21985f965e388080ec732c14e2b738484ca6736b (patch)
treec5d9809d829d6c27242cfdbbbf9454f4f1e6c907 /drivers/clk
parent92b7d7917b67c8deb51bcd5df7e3fa9dd6087176 (diff)
msm: mdss: add thulium dsi pll support
Implement dsi related clocks framework so that dsi vco pll related function be called to output correct vco rate base on byte clock rate. After that pixel clock rate can be achieved through MND setting. Change-Id: I819f9fcb8afd9430f131679434c4da34641ce3f8 [veeras@codeaurora.org: As part of 3.18 upgrade, remove all non-display related code from this commit include/dt-bindings/clock/msm-clocks-thulium.h] Signed-off-by: Kuogee Hsieh <khsieh@codeaurora.org> Signed-off-by: Veera Sundaram Sankaran <veeras@codeaurora.org>
Diffstat (limited to 'drivers/clk')
-rw-r--r--drivers/clk/msm/mdss/Makefile2
-rw-r--r--drivers/clk/msm/mdss/mdss-dsi-pll-thulium-util.c738
-rw-r--r--drivers/clk/msm/mdss/mdss-dsi-pll-thulium.c239
-rw-r--r--drivers/clk/msm/mdss/mdss-dsi-pll-thulium.h169
-rw-r--r--drivers/clk/msm/mdss/mdss-dsi-pll.h4
-rw-r--r--drivers/clk/msm/mdss/mdss-pll.c7
-rw-r--r--drivers/clk/msm/mdss/mdss-pll.h3
7 files changed, 1161 insertions, 1 deletions
diff --git a/drivers/clk/msm/mdss/Makefile b/drivers/clk/msm/mdss/Makefile
index 011f5e0ac214..d89b0ef74b85 100644
--- a/drivers/clk/msm/mdss/Makefile
+++ b/drivers/clk/msm/mdss/Makefile
@@ -4,6 +4,8 @@ obj-$(CONFIG_MSM_MDSS_PLL) += mdss-dsi-pll-util.o mdss-dsi-20nm-pll-util.o
obj-$(CONFIG_MSM_MDSS_PLL) += mdss-dsi-pll-28hpm.o
obj-$(CONFIG_MSM_MDSS_PLL) += mdss-dsi-pll-28lpm.o
obj-$(CONFIG_MSM_MDSS_PLL) += mdss-dsi-pll-20nm.o
+obj-$(CONFIG_MSM_MDSS_PLL) += mdss-dsi-pll-thulium.o
+obj-$(CONFIG_MSM_MDSS_PLL) += mdss-dsi-pll-thulium-util.o
obj-$(CONFIG_MSM_MDSS_PLL) += mdss-edp-pll-28hpm.o
obj-$(CONFIG_MSM_MDSS_PLL) += mdss-hdmi-pll-28hpm.o
obj-$(CONFIG_MSM_MDSS_PLL) += mdss-hdmi-pll-20nm.o
diff --git a/drivers/clk/msm/mdss/mdss-dsi-pll-thulium-util.c b/drivers/clk/msm/mdss/mdss-dsi-pll-thulium-util.c
new file mode 100644
index 000000000000..23226f1060b2
--- /dev/null
+++ b/drivers/clk/msm/mdss/mdss-dsi-pll-thulium-util.c
@@ -0,0 +1,738 @@
+/* Copyright (c) 2015, 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.
+ */
+
+#define pr_fmt(fmt) "%s: " fmt, __func__
+
+#include <linux/kernel.h>
+#include <linux/err.h>
+#include <linux/iopoll.h>
+#include <linux/delay.h>
+#include <linux/clk/msm-clock-generic.h>
+
+#include "mdss-pll.h"
+#include "mdss-dsi-pll.h"
+#include "mdss-dsi-pll-thulium.h"
+
+#define DSI_PLL_POLL_MAX_READS 15
+#define DSI_PLL_POLL_TIMEOUT_US 1000
+
+int set_mdss_byte_mux_sel_thulium(struct mux_clk *clk, int sel)
+{
+ return 0;
+}
+
+int get_mdss_byte_mux_sel_thulium(struct mux_clk *clk)
+{
+ return 0;
+}
+
+int set_mdss_pixel_mux_sel_thulium(struct mux_clk *clk, int sel)
+{
+ return 0;
+}
+
+int get_mdss_pixel_mux_sel_thulium(struct mux_clk *clk)
+{
+ return 0;
+}
+
+int post_n1_div_set_div(struct div_clk *clk, int div)
+{
+ struct mdss_pll_resources *pll = clk->priv;
+ struct dsi_pll_db *pdb;
+ struct dsi_pll_output *pout;
+
+ pdb = (struct dsi_pll_db *)pll->priv;
+ pout = &pdb->out;
+
+ /*
+ * postdiv = 1/2/4/8
+ * n1div = 1 - 15
+ * fot the time being, assume postdiv = 1
+ */
+
+ /* this is for vco/bit clock */
+ pout->pll_postdiv = 1; /* fixed, divided by 1 */
+ pout->pll_n1div = div;
+
+ pr_debug("div=%d postdiv=%x n1div=%x\n",
+ div, pout->pll_postdiv, pout->pll_n1div);
+
+ /* registers commited at pll_db_commit_thulium() */
+
+ return 0;
+}
+
+int post_n1_div_get_div(struct div_clk *clk)
+{
+ u32 div;
+ struct mdss_pll_resources *pll = clk->priv;
+ struct dsi_pll_db *pdb;
+ struct dsi_pll_output *pout;
+
+ pdb = (struct dsi_pll_db *)pll->priv;
+ pout = &pdb->out;
+
+ /*
+ * postdiv = 1/2/4/8
+ * n1div = 1 - 15
+ * fot the time being, assume postdiv = 1
+ */
+
+ div = pout->pll_postdiv * pout->pll_n1div;
+
+ pr_debug("div=%d postdiv=%x n1div=%x\n",
+ div, pout->pll_postdiv, pout->pll_n1div);
+
+ return div;
+}
+
+int n2_div_set_div(struct div_clk *clk, int div)
+{
+ int rc;
+ u32 n2div;
+ struct mdss_pll_resources *pll = clk->priv;
+ struct dsi_pll_db *pdb;
+ struct dsi_pll_output *pout;
+
+ rc = mdss_pll_resource_enable(pll, true);
+ if (rc) {
+ pr_err("Failed to enable mdss dsi pll resources\n");
+ return rc;
+ }
+
+ pdb = (struct dsi_pll_db *)pll->priv;
+ pout = &pdb->out;
+
+ /* this is for pixel clock */
+ n2div = MDSS_PLL_REG_R(pll->pll_base, DSIPHY_CMN_CLK_CFG0);
+ n2div &= ~0xf0; /* bits 4 to 7 */
+ n2div |= (div << 4);
+ MDSS_PLL_REG_W(pll->pll_base, DSIPHY_CMN_CLK_CFG0, n2div);
+
+ pout->pll_n2div = div;
+
+ /* set dsiclk_sel=1 so that n2div *= 2 */
+ MDSS_PLL_REG_W(pll->pll_base, DSIPHY_CMN_CLK_CFG1, 1);
+ pr_debug("div=%d n2div=%x\n", div, n2div);
+
+ mdss_pll_resource_enable(pll, false);
+
+ return rc;
+}
+
+int n2_div_get_div(struct div_clk *clk)
+{
+ int rc;
+ u32 n2div;
+ struct mdss_pll_resources *pll = clk->priv;
+
+ rc = mdss_pll_resource_enable(pll, true);
+ if (rc) {
+ pr_err("Failed to enable mdss dsi pll resources\n");
+ return rc;
+ }
+
+ n2div = MDSS_PLL_REG_R(pll->pll_base, DSIPHY_CMN_CLK_CFG0);
+ n2div >>= 4;
+ n2div &= 0x0f;
+
+ mdss_pll_resource_enable(pll, false);
+
+ pr_debug("div=%d\n", n2div);
+
+ return n2div;
+}
+
+static bool pll_is_pll_locked_thulium(struct mdss_pll_resources *pll)
+{
+ u32 status;
+ bool pll_locked;
+
+ /* poll for PLL ready status */
+ if (readl_poll_timeout_atomic((pll->pll_base +
+ DSIPHY_PLL_RESET_SM_READY_STATUS),
+ status,
+ ((status & BIT(5)) > 0),
+ DSI_PLL_POLL_MAX_READS,
+ DSI_PLL_POLL_TIMEOUT_US)) {
+ pr_debug("DSI PLL status=%x failed to Lock\n", status);
+ pll_locked = false;
+ } else if (readl_poll_timeout_atomic((pll->pll_base +
+ DSIPHY_PLL_RESET_SM_READY_STATUS),
+ status,
+ ((status & BIT(0)) > 0),
+ DSI_PLL_POLL_MAX_READS,
+ DSI_PLL_POLL_TIMEOUT_US)) {
+ pr_debug("DSI PLL status=%x PLl not ready\n", status);
+ pll_locked = false;
+ } else {
+ pll_locked = true;
+ }
+
+ return pll_locked;
+}
+
+static void dsi_pll_start_thulium(void __iomem *pll_base)
+{
+ pr_debug("start PLL at base=%p\n", pll_base);
+
+ MDSS_PLL_REG_W(pll_base, DSIPHY_CMN_PLL_CNTRL, 1);
+}
+
+static void dsi_pll_stop_thulium(void __iomem *pll_base)
+{
+ pr_debug("stop PLL at base=%p\n", pll_base);
+
+ MDSS_PLL_REG_W(pll_base, DSIPHY_CMN_PLL_CNTRL, 0);
+}
+
+int dsi_pll_enable_seq_thulium(struct mdss_pll_resources *pll)
+{
+ int rc = 0;
+
+ if (!pll) {
+ pr_err("Invalid PLL resources\n");
+ return -EINVAL;
+ }
+
+ dsi_pll_start_thulium(pll->pll_base);
+
+ /*
+ * both DSIPHY_PLL_CLKBUFLR_EN and DSIPHY_CMN_GLBL_TEST_CTRL
+ * enabled at mdss_dsi_thulium_phy_config()
+ */
+
+ if (!pll_is_pll_locked_thulium(pll)) {
+ pr_err("DSI PLL lock failed\n");
+ rc = -EINVAL;
+ goto init_lock_err;
+ }
+
+ pr_debug("DSI PLL Lock success\n");
+
+init_lock_err:
+ return rc;
+}
+
+static int dsi_pll_enable(struct clk *c)
+{
+ int i, rc;
+ struct dsi_pll_vco_clk *vco = to_vco_clk(c);
+ struct mdss_pll_resources *pll = vco->priv;
+
+ rc = mdss_pll_resource_enable(pll, true);
+ if (rc) {
+ pr_err("Failed to enable mdss dsi pll resources\n");
+ return rc;
+ }
+
+ /* Try all enable sequences until one succeeds */
+ for (i = 0; i < vco->pll_en_seq_cnt; i++) {
+ rc = vco->pll_enable_seqs[i](pll);
+ pr_debug("DSI PLL %s after sequence #%d\n",
+ rc ? "unlocked" : "locked", i + 1);
+ if (!rc)
+ break;
+ }
+
+ if (rc) {
+ mdss_pll_resource_enable(pll, false);
+ pr_err("DSI PLL failed to lock\n");
+ } else {
+ pll->pll_on = true;
+ }
+
+ return rc;
+}
+
+static void dsi_pll_disable(struct clk *c)
+{
+ struct dsi_pll_vco_clk *vco = to_vco_clk(c);
+ struct mdss_pll_resources *pll = vco->priv;
+
+ if (!pll->pll_on &&
+ mdss_pll_resource_enable(pll, true)) {
+ pr_err("Failed to enable mdss dsi pll resources\n");
+ return;
+ }
+
+ pll->handoff_resources = false;
+
+ dsi_pll_stop_thulium(pll->pll_base);
+
+ /* stop pll output */
+ MDSS_PLL_REG_W(pll->pll_base, DSIPHY_PLL_CLKBUFLR_EN, 0);
+
+ /* stop clk */
+ MDSS_PLL_REG_W(pll->pll_base, DSIPHY_CMN_GLBL_TEST_CTRL, 0);
+
+ mdss_pll_resource_enable(pll, false);
+
+ pll->pll_on = false;
+
+ pr_debug("DSI PLL Disabled\n");
+ return;
+}
+
+static void mdss_dsi_pll_thulium_input_init(struct dsi_pll_db *pdb)
+{
+ pdb->in.fref = 19200000; /* 19.2 Mhz*/
+ pdb->in.fdata = 0; /* bit clock rate */
+ pdb->in.dsiclk_sel = 1; /* 1, reg: 0x0014 */
+ pdb->in.ssc_en = 0; /* 1, reg: 0x0494, bit 0 */
+ pdb->in.ldo_en = 0; /* 0, reg: 0x004c, bit 0 */
+
+ /* fixed input */
+ pdb->in.refclk_dbler_en = 0; /* 0, reg: 0x04c0, bit 1 */
+ pdb->in.vco_measure_time = 5; /* 5, unknown */
+ pdb->in.kvco_measure_time = 5; /* 5, unknown */
+ pdb->in.bandgap_timer = 4; /* 4, reg: 0x0430, bit 3 - 5 */
+ pdb->in.pll_wakeup_timer = 5; /* 5, reg: 0x043c, bit 0 - 2 */
+ pdb->in.plllock_cnt = 1; /* 1, reg: 0x0488, bit 1 - 2 */
+ pdb->in.plllock_rng = 0; /* 0, reg: 0x0488, bit 3 - 4 */
+ pdb->in.ssc_center_spread = 0; /* 0, reg: 0x0494, bit 1 */
+ pdb->in.ssc_adj_per = 37; /* 37, reg: 0x498, bit 0 - 9 */
+ pdb->in.ssc_spread = 5; /* 0.005, 5kppm */
+ pdb->in.ssc_freq = 31500; /* 31.5 khz */
+
+ pdb->in.pll_ie_trim = 4; /* 4, reg: 0x0400 */
+ pdb->in.pll_ip_trim = 4; /* 4, reg: 0x0404 */
+ pdb->in.pll_cpcset_cur = 1; /* 1, reg: 0x04f0, bit 0 - 2 */
+ pdb->in.pll_cpmset_cur = 1; /* 1, reg: 0x04f0, bit 3 - 5 */
+ pdb->in.pll_icpmset = 4; /* 4, reg: 0x04fc, bit 3 - 5 */
+ pdb->in.pll_icpcset = 4; /* 4, reg: 0x04fc, bit 0 - 2 */
+ pdb->in.pll_icpmset_p = 0; /* 0, reg: 0x04f4, bit 0 - 2 */
+ pdb->in.pll_icpmset_m = 0; /* 0, reg: 0x04f4, bit 3 - 5 */
+ pdb->in.pll_icpcset_p = 0; /* 0, reg: 0x04f8, bit 0 - 2 */
+ pdb->in.pll_icpcset_m = 0; /* 0, reg: 0x04f8, bit 3 - 5 */
+ pdb->in.pll_lpf_res1 = 3; /* 3, reg: 0x0504, bit 0 - 3 */
+ pdb->in.pll_lpf_cap1 = 11; /* 11, reg: 0x0500, bit 0 - 3 */
+ pdb->in.pll_lpf_cap2 = 14; /* 14, reg: 0x0500, bit 4 - 7 */
+ pdb->in.pll_iptat_trim = 7;
+ pdb->in.pll_c3ctrl = 2; /* 2 */
+ pdb->in.pll_r3ctrl = 1; /* 1 */
+}
+
+static void pll_thulium_dec_frac_calc(struct dsi_pll_db *pdb,
+ s64 vco_clk_rate, s64 fref)
+{
+ struct dsi_pll_input *pin = &pdb->in;
+ struct dsi_pll_output *pout = &pdb->out;
+ s64 multiplier = BIT(20);
+ s64 dec_start_multiple, dec_start, pll_comp_val;
+ s32 duration, div_frac_start;
+
+ pr_debug("vco_clk_rate=%lld ref_clk_rate=%lld\n",
+ vco_clk_rate, fref);
+
+ dec_start_multiple = div_s64(vco_clk_rate * multiplier, fref);
+ div_s64_rem(dec_start_multiple, multiplier, &div_frac_start);
+
+ dec_start = div_s64(dec_start_multiple, multiplier);
+
+ pout->dec_start = (u32)dec_start;
+ pout->div_frac_start = div_frac_start;
+
+ if (pin->plllock_cnt == 0)
+ duration = 1024;
+ else if (pin->plllock_cnt == 1)
+ duration = 256;
+ else if (pin->plllock_cnt == 2)
+ duration = 128;
+ else
+ duration = 32;
+
+ pll_comp_val = duration * dec_start_multiple;
+ pll_comp_val = div_s64(pll_comp_val, multiplier);
+ pll_comp_val /= 10;
+
+ pout->plllock_cmp = (u32)pll_comp_val;
+
+ pout->pll_txclk_en = 1;
+ pout->pll_clkbuflr_en = 1; /* right output */
+ pout->cmn_ldo_cntrl = 0x1c;
+}
+
+static u32 pll_thulium_kvco_slop(u32 vrate)
+{
+ u32 slop = 0;
+
+ if (vrate > 1300000000 && vrate <= 1800000000)
+ slop = 600;
+ else if (vrate > 1800000000 && vrate < 2300000000)
+ slop = 400;
+ else if (vrate > 2300000000 && vrate < 2600000000)
+ slop = 280;
+
+ return slop;
+}
+
+static void pll_thulium_calc_vco_count(struct dsi_pll_db *pdb,
+ s64 vco_clk_rate, s64 fref)
+{
+ struct dsi_pll_input *pin = &pdb->in;
+ struct dsi_pll_output *pout = &pdb->out;
+ s64 data;
+ u32 cnt;
+
+ data = fref * pin->vco_measure_time;
+ data /= 1000000;
+ data &= 0x03ff; /* 10 bits */
+ data -= 2;
+ pout->pll_vco_div_ref = data;
+
+ data = vco_clk_rate / 1000000; /* unit is Mhz */
+ data *= pin->vco_measure_time;
+ data /= 10;
+ pout->pll_vco_count = data; /* reg: 0x0474, 0x0478 */
+
+ data = fref * pin->kvco_measure_time;
+ data /= 1000000;
+ data &= 0x03ff; /* 10 bits */
+ data -= 1;
+ pout->pll_kvco_div_ref = data;
+
+ cnt = pll_thulium_kvco_slop(vco_clk_rate);
+ cnt *= 2;
+ cnt /= 100;
+ cnt *= pin->kvco_measure_time;
+ pout->pll_kvco_count = cnt;
+
+ pout->pll_misc1 = 16;
+ pout->pll_resetsm_cntrl = 0;
+ pout->pll_resetsm_cntrl2 = pin->bandgap_timer << 3;
+ pout->pll_resetsm_cntrl5 = pin->pll_wakeup_timer;
+ pout->pll_kvco_code = 0;
+}
+
+static void pll_db_commit_common(void __iomem *pll_base,
+ struct dsi_pll_db *pdb)
+{
+ struct dsi_pll_input *pin = &pdb->in;
+ struct dsi_pll_output *pout = &pdb->out;
+ char data;
+
+ /* confgiure the non frequency dependent pll registers */
+ data = 0;
+ MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_SYSCLK_EN_RESET, data);
+
+ /* DSIPHY_PLL_CLKBUFLR_EN updated at dsi phy */
+
+ data = pout->pll_txclk_en;
+ MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_TXCLK_EN, data);
+
+ data = pout->pll_resetsm_cntrl;
+ MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_RESETSM_CNTRL, data);
+ data = pout->pll_resetsm_cntrl2;
+ MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_RESETSM_CNTRL2, data);
+ data = pout->pll_resetsm_cntrl5;
+ MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_RESETSM_CNTRL5, data);
+
+ data = pout->pll_vco_div_ref;
+ data &= 0x0ff;
+ MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_VCO_DIV_REF1, data);
+ data = (pout->pll_vco_div_ref >> 8);
+ data &= 0x03;
+ MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_VCO_DIV_REF2, data);
+
+ data = pout->pll_kvco_div_ref;
+ data &= 0x0ff;
+ MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_KVCO_DIV_REF1, data);
+ data = (pout->pll_kvco_div_ref >> 8);
+ data &= 0x03;
+ MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_KVCO_DIV_REF2, data);
+
+ data = pout->pll_misc1;
+ MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_PLL_MISC1, data);
+
+ data = pout->pll_ie_trim;
+ MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_IE_TRIM, data);
+
+ data = pout->pll_ip_trim;
+ MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_IP_TRIM, data);
+
+ data = ((pin->pll_cpmset_cur << 3) | pin->pll_cpcset_cur);
+ MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_CP_SET_CUR, data);
+
+ data = ((pin->pll_icpcset_p << 3) | pin->pll_icpcset_m);
+ MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_PLL_ICPCSET, data);
+
+ data = ((pin->pll_icpmset_p << 3) | pin->pll_icpcset_m);
+ MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_PLL_ICPMSET, data);
+
+ data = ((pin->pll_icpmset << 3) | pin->pll_icpcset);
+ MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_PLL_ICP_SET, data);
+
+ data = ((pdb->in.pll_lpf_cap2 << 4) | pdb->in.pll_lpf_cap1);
+ MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_PLL_LPF1, data);
+
+ data = pout->pll_iptat_trim;
+ MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_IPTAT_TRIM, data);
+
+ data = (pdb->in.pll_c3ctrl | (pdb->in.pll_r3ctrl << 4));
+ MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_PLL_CRCTRL, data);
+}
+
+static void pll_db_commit_thulium(void __iomem *pll_base,
+ struct dsi_pll_db *pdb)
+{
+ struct dsi_pll_input *pin = &pdb->in;
+ struct dsi_pll_output *pout = &pdb->out;
+ char data;
+
+ data = pout->cmn_ldo_cntrl;
+ MDSS_PLL_REG_W(pll_base, DSIPHY_CMN_LDO_CNTRL, data);
+
+ pll_db_commit_common(pll_base, pdb);
+
+ /* de assert pll start and apply pll sw reset */
+ /* stop pll */
+ MDSS_PLL_REG_W(pll_base, DSIPHY_CMN_PLL_CNTRL, 0);
+
+ /* pll sw reset */
+ MDSS_PLL_REG_W(pll_base, DSIPHY_CMN_CTRL_1, 0x20);
+ wmb(); /* make sure register committed */
+ udelay(10);
+
+ MDSS_PLL_REG_W(pll_base, DSIPHY_CMN_CTRL_1, 0);
+ wmb(); /* make sure register committed */
+
+ data = pdb->in.dsiclk_sel; /* set dsiclk_sel = 1 */
+ MDSS_PLL_REG_W(pll_base, DSIPHY_CMN_CLK_CFG1, data);
+
+ data = 0xff; /* data, clk, pll normal operation */
+ MDSS_PLL_REG_W(pll_base, DSIPHY_CMN_CTRL_0, data);
+
+ /* confgiure the frequency dependent pll registers */
+ data = pout->dec_start;
+ MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_DEC_START, data);
+
+ data = pout->div_frac_start;
+ MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_DIV_FRAC_START1, data);
+ data = (pout->div_frac_start >> 8);
+ MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_DIV_FRAC_START2, data);
+ data = (pout->div_frac_start >> 16);
+ MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_DIV_FRAC_START3, data);
+
+ data = pout->plllock_cmp;
+ data &= 0x0ff;
+ MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_PLLLOCK_CMP1, data);
+ data = (pout->plllock_cmp >> 8);
+ data &= 0x0ff;
+ MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_PLLLOCK_CMP2, data);
+ data = (pout->plllock_cmp >> 16);
+ data &= 0x03;
+ MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_PLLLOCK_CMP3, data);
+
+ data = ((pin->plllock_cnt << 1) | (pin->plllock_rng << 3));
+ MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_PLLLOCK_CMP_EN, data);
+
+ data = pout->pll_vco_count;
+ data &= 0x0ff;
+ MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_VCO_COUNT1, data);
+ data = (pout->pll_vco_count >> 8);
+ data &= 0x0ff;
+ MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_VCO_COUNT2, data);
+
+ data = pout->pll_kvco_count;
+ data &= 0x0ff;
+ MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_KVCO_COUNT1, data);
+ data = (pout->pll_kvco_count >> 8);
+ data &= 0x03;
+ MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_KVCO_COUNT2, data);
+
+ /*
+ * tx_band = pll_postdiv
+ * 0: divided by 1 <== for now
+ * 1: divided by 2
+ * 2: divided by 4
+ * 3: divided by 8
+ */
+ data = (((pout->pll_postdiv - 1) << 4) | pdb->in.pll_lpf_res1);
+ MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_PLL_LPF2_POSTDIV, data);
+
+ data = (pout->pll_n1div | (pout->pll_n2div << 4));
+ MDSS_PLL_REG_W(pll_base, DSIPHY_CMN_CLK_CFG0, data);
+
+ wmb(); /* make sure register committed */
+}
+
+int pll_vco_set_rate_thulium(struct clk *c, unsigned long rate)
+{
+ int rc;
+ struct dsi_pll_vco_clk *vco = to_vco_clk(c);
+ struct mdss_pll_resources *pll = vco->priv;
+ struct dsi_pll_db *pdb;
+
+ pdb = (struct dsi_pll_db *)pll->priv;
+ if (!pdb) {
+ pr_err("No prov found\n");
+ return -EINVAL;
+ }
+
+ rc = mdss_pll_resource_enable(pll, true);
+ if (rc) {
+ pr_err("Failed to enable mdss dsi pll resources\n");
+ return rc;
+ }
+
+ pr_debug("%s: rate=%lu\n", __func__, rate);
+
+ pll->vco_current_rate = rate;
+ pll->vco_ref_clk_rate = vco->ref_clk_rate;
+
+ mdss_dsi_pll_thulium_input_init(pdb);
+
+ pll_thulium_dec_frac_calc(pdb, pll->vco_current_rate,
+ pll->vco_ref_clk_rate);
+
+ pll_thulium_calc_vco_count(pdb, pll->vco_current_rate,
+ pll->vco_ref_clk_rate);
+
+ pll_db_commit_thulium(pll->pll_base, pdb);
+
+ mdss_pll_resource_enable(pll, false);
+
+ return rc;
+}
+
+unsigned long pll_vco_get_rate_thulium(struct clk *c)
+{
+ u64 vco_rate, multiplier = (1 << 20);
+ s32 div_frac_start;
+ u32 dec_start;
+ struct dsi_pll_vco_clk *vco = to_vco_clk(c);
+ u64 ref_clk = vco->ref_clk_rate;
+ int rc;
+ struct mdss_pll_resources *pll = vco->priv;
+
+ if (is_gdsc_disabled(pll))
+ return 0;
+
+ rc = mdss_pll_resource_enable(pll, true);
+ if (rc) {
+ pr_err("Failed to enable mdss dsi pll resources\n");
+ return rc;
+ }
+
+ dec_start = MDSS_PLL_REG_R(pll->pll_base,
+ DSIPHY_PLL_DEC_START);
+ dec_start &= 0x0ff;
+ pr_debug("dec_start = 0x%x\n", dec_start);
+
+ div_frac_start = (MDSS_PLL_REG_R(pll->pll_base,
+ DSIPHY_PLL_DIV_FRAC_START3) & 0x0ff) << 16;
+ div_frac_start |= (MDSS_PLL_REG_R(pll->pll_base,
+ DSIPHY_PLL_DIV_FRAC_START2) & 0x0ff) << 8;
+ div_frac_start |= MDSS_PLL_REG_R(pll->pll_base,
+ DSIPHY_PLL_DIV_FRAC_START1) & 0x0ff;
+ pr_debug("div_frac_start = 0x%x\n", div_frac_start);
+
+ vco_rate = ref_clk * 2 * dec_start;
+ vco_rate += ((ref_clk * div_frac_start) / multiplier);
+
+ pr_debug("returning vco rate = %lu\n", (unsigned long)vco_rate);
+
+ mdss_pll_resource_enable(pll, false);
+
+ return (unsigned long)vco_rate;
+}
+
+long pll_vco_round_rate_thulium(struct clk *c, unsigned long rate)
+{
+ unsigned long rrate = rate;
+ u32 div;
+ struct dsi_pll_vco_clk *vco = to_vco_clk(c);
+
+ div = vco->min_rate / rate;
+ if (div > 15) {
+ /* rate < 86.67 Mhz */
+ pr_err("rate=%lu NOT supportted\n", rate);
+ return -EINVAL;
+ }
+
+ if (rate < vco->min_rate)
+ rrate = vco->min_rate;
+ if (rate > vco->max_rate)
+ rrate = vco->max_rate;
+
+ return rrate;
+}
+
+enum handoff pll_vco_handoff_thulium(struct clk *c)
+{
+ int rc;
+ enum handoff ret = HANDOFF_DISABLED_CLK;
+ struct dsi_pll_vco_clk *vco = to_vco_clk(c);
+ struct mdss_pll_resources *pll = vco->priv;
+
+ if (is_gdsc_disabled(pll))
+ return HANDOFF_DISABLED_CLK;
+
+ rc = mdss_pll_resource_enable(pll, true);
+ if (rc) {
+ pr_err("Failed to enable mdss dsi pll resources\n");
+ return ret;
+ }
+
+ if (pll_is_pll_locked_thulium(pll)) {
+ pll->handoff_resources = true;
+ pll->pll_on = true;
+ c->rate = pll_vco_get_rate_thulium(c);
+ ret = HANDOFF_ENABLED_CLK;
+ } else {
+ mdss_pll_resource_enable(pll, false);
+ }
+
+ return ret;
+}
+
+int pll_vco_prepare_thulium(struct clk *c)
+{
+ int rc = 0;
+ struct dsi_pll_vco_clk *vco = to_vco_clk(c);
+ struct mdss_pll_resources *pll = vco->priv;
+
+ if (!pll) {
+ pr_err("Dsi pll resources are not available\n");
+ return -EINVAL;
+ }
+
+ if ((pll->vco_cached_rate != 0)
+ && (pll->vco_cached_rate == c->rate)) {
+ rc = c->ops->set_rate(c, pll->vco_cached_rate);
+ if (rc) {
+ pr_err("vco_set_rate failed. rc=%d\n", rc);
+ goto error;
+ }
+ }
+
+ rc = dsi_pll_enable(c);
+
+error:
+ return rc;
+}
+
+void pll_vco_unprepare_thulium(struct clk *c)
+{
+ struct dsi_pll_vco_clk *vco = to_vco_clk(c);
+ struct mdss_pll_resources *pll = vco->priv;
+
+ if (!pll) {
+ pr_err("Dsi pll resources are not available\n");
+ return;
+ }
+
+ pll->vco_cached_rate = c->rate;
+ dsi_pll_disable(c);
+}
diff --git a/drivers/clk/msm/mdss/mdss-dsi-pll-thulium.c b/drivers/clk/msm/mdss/mdss-dsi-pll-thulium.c
new file mode 100644
index 000000000000..6bb4e678916f
--- /dev/null
+++ b/drivers/clk/msm/mdss/mdss-dsi-pll-thulium.c
@@ -0,0 +1,239 @@
+/* Copyright (c) 2015, 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.
+ *
+ */
+
+#define pr_fmt(fmt) "%s: " fmt, __func__
+
+#include <linux/kernel.h>
+#include <linux/err.h>
+#include <linux/delay.h>
+#include <linux/clk/msm-clk-provider.h>
+#include <linux/clk/msm-clk.h>
+#include <linux/workqueue.h>
+#include <linux/clk/msm-clock-generic.h>
+#include <dt-bindings/clock/msm-clocks-thulium.h>
+
+#include "mdss-pll.h"
+#include "mdss-dsi-pll.h"
+#include "mdss-dsi-pll-thulium.h"
+
+#define VCO_DELAY_USEC 1
+
+static struct dsi_pll_db pll_db;
+
+static struct clk_ops n2_clk_src_ops;
+static struct clk_ops byte_clk_src_ops;
+static struct clk_ops post_n1_div_clk_src_ops;
+
+static struct clk_ops clk_ops_gen_mux_dsi;
+
+/* Op structures */
+static struct clk_ops clk_ops_dsi_vco = {
+ .set_rate = pll_vco_set_rate_thulium,
+ .round_rate = pll_vco_round_rate_thulium,
+ .handoff = pll_vco_handoff_thulium,
+ .prepare = pll_vco_prepare_thulium,
+ .unprepare = pll_vco_unprepare_thulium,
+};
+
+static struct clk_div_ops post_n1_div_ops = {
+ .set_div = post_n1_div_set_div,
+ .get_div = post_n1_div_get_div,
+};
+
+static struct clk_div_ops n2_div_ops = { /* hr_oclk3 */
+ .set_div = n2_div_set_div,
+ .get_div = n2_div_get_div,
+};
+
+static struct clk_mux_ops mdss_byte_mux_ops = {
+ .set_mux_sel = set_mdss_byte_mux_sel_thulium,
+ .get_mux_sel = get_mdss_byte_mux_sel_thulium,
+};
+
+static struct clk_mux_ops mdss_pixel_mux_ops = {
+ .set_mux_sel = set_mdss_pixel_mux_sel_thulium,
+ .get_mux_sel = get_mdss_pixel_mux_sel_thulium,
+};
+
+static struct dsi_pll_vco_clk dsi_vco_clk = {
+ .ref_clk_rate = 19200000,
+ .min_rate = 1300000000,
+ .max_rate = 2600000000,
+ .pll_en_seq_cnt = 1,
+ .pll_enable_seqs[0] = dsi_pll_enable_seq_thulium,
+ .c = {
+ .dbg_name = "dsi_vco_clk_thulium",
+ .ops = &clk_ops_dsi_vco,
+ CLK_INIT(dsi_vco_clk.c),
+ },
+};
+
+static struct div_clk post_n1_div_clk = {
+ .data = {
+ .max_div = 15,
+ .min_div = 1,
+ },
+ .ops = &post_n1_div_ops,
+ .c = {
+ .parent = &dsi_vco_clk.c,
+ .dbg_name = "post_n1_div_clk",
+ .ops = &post_n1_div_clk_src_ops,
+ .flags = CLKFLAG_NO_RATE_CACHE,
+ CLK_INIT(post_n1_div_clk.c),
+ },
+};
+
+static struct div_clk n2_div_clk = {
+ .data = {
+ .max_div = 15,
+ .min_div = 1,
+ },
+ .ops = &n2_div_ops,
+ .c = {
+ .parent = &post_n1_div_clk.c,
+ .dbg_name = "n2_div_clk",
+ .ops = &n2_clk_src_ops,
+ .flags = CLKFLAG_NO_RATE_CACHE,
+ CLK_INIT(n2_div_clk.c),
+ },
+};
+
+static struct div_clk pixel_clk_src = {
+ .data = {
+ .div = 2,
+ .min_div = 2,
+ .max_div = 2,
+ },
+ .c = {
+ .parent = &n2_div_clk.c,
+ .dbg_name = "pixel_clk_src",
+ .ops = &clk_ops_div,
+ .flags = CLKFLAG_NO_RATE_CACHE,
+ CLK_INIT(pixel_clk_src.c),
+ },
+};
+
+static struct mux_clk mdss_pixel_clk_mux = {
+ .num_parents = 1,
+ .parents = (struct clk_src[]) {
+ {&pixel_clk_src.c, 0},
+ },
+ .ops = &mdss_pixel_mux_ops,
+ .c = {
+ .parent = &pixel_clk_src.c,
+ .dbg_name = "mdss_pixel_clk_mux",
+ .ops = &clk_ops_gen_mux,
+ CLK_INIT(mdss_pixel_clk_mux.c),
+ }
+};
+
+static struct div_clk byte_clk_src = {
+ .data = {
+ .div = 8,
+ .min_div = 8,
+ .max_div = 8,
+ },
+ .c = {
+ .parent = &post_n1_div_clk.c,
+ .dbg_name = "byte_clk_src",
+ .ops = &clk_ops_div,
+ CLK_INIT(byte_clk_src.c),
+ },
+};
+
+static struct mux_clk mdss_byte_clk_mux = {
+ .num_parents = 1,
+ .parents = (struct clk_src[]) {
+ {&byte_clk_src.c, 0},
+ },
+ .ops = &mdss_byte_mux_ops,
+ .c = {
+ .parent = &byte_clk_src.c,
+ .dbg_name = "mdss_byte_clk_mux",
+ .ops = &clk_ops_gen_mux_dsi,
+ CLK_INIT(mdss_byte_clk_mux.c),
+ }
+};
+
+static struct clk_lookup mdss_dsi_pllcc_thulium[] = {
+ CLK_LIST(mdss_byte_clk_mux),
+ CLK_LIST(byte_clk_src),
+ CLK_LIST(mdss_pixel_clk_mux),
+ CLK_LIST(pixel_clk_src),
+ CLK_LIST(n2_div_clk),
+ CLK_LIST(post_n1_div_clk),
+ CLK_LIST(dsi_vco_clk),
+};
+
+int dsi_pll_clock_register_thulium(struct platform_device *pdev,
+ struct mdss_pll_resources *pll_res)
+{
+ int rc;
+
+ if (!pdev || !pdev->dev.of_node) {
+ pr_err("Invalid input parameters\n");
+ return -EINVAL;
+ }
+
+ if (!pll_res || !pll_res->pll_base) {
+ pr_err("Invalid PLL resources\n");
+ return -EPROBE_DEFER;
+ }
+
+ pll_res->priv = &pll_db;
+
+ /*
+ * Set client data to mux, div and vco clocks.
+ * This needs to be done only for PLL0 since, that is the one in
+ * use.
+ **/
+ byte_clk_src.priv = pll_res;
+ pixel_clk_src.priv = pll_res;
+ post_n1_div_clk.priv = pll_res;
+ n2_div_clk.priv = pll_res;
+ dsi_vco_clk.priv = pll_res;
+
+ pll_res->vco_delay = VCO_DELAY_USEC;
+
+ /* Set clock source operations */
+
+ /* hr_oclk3, pixel */
+ n2_clk_src_ops = clk_ops_slave_div;
+ n2_clk_src_ops.prepare = dsi_pll_div_prepare;
+
+ /* hr_ockl2, byte, vco pll */
+ post_n1_div_clk_src_ops = clk_ops_div;
+ post_n1_div_clk_src_ops.prepare = dsi_pll_div_prepare;
+
+ byte_clk_src_ops = clk_ops_div;
+ byte_clk_src_ops.prepare = dsi_pll_div_prepare;
+
+ clk_ops_gen_mux_dsi = clk_ops_gen_mux;
+ clk_ops_gen_mux_dsi.round_rate = parent_round_rate;
+ clk_ops_gen_mux_dsi.set_rate = parent_set_rate;
+
+ if (pll_res->target_id == MDSS_PLL_TARGET_THULIUM) {
+ rc = of_msm_clock_register(pdev->dev.of_node,
+ mdss_dsi_pllcc_thulium,
+ ARRAY_SIZE(mdss_dsi_pllcc_thulium));
+ if (rc) {
+ pr_err("Clock register failed\n");
+ rc = -EPROBE_DEFER;
+ }
+ }
+
+ if (!rc)
+ pr_info("Registered DSI PLL clocks successfully\n");
+
+ return rc;
+}
diff --git a/drivers/clk/msm/mdss/mdss-dsi-pll-thulium.h b/drivers/clk/msm/mdss/mdss-dsi-pll-thulium.h
new file mode 100644
index 000000000000..cdd49752d8cf
--- /dev/null
+++ b/drivers/clk/msm/mdss/mdss-dsi-pll-thulium.h
@@ -0,0 +1,169 @@
+/* Copyright (c) 2015, 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.
+ */
+
+#ifndef MDSS_DSI_PLL_THULIUM_H
+#define MDSS_DSI_PLL_THULIUM_H
+
+#define DSIPHY_CMN_CLK_CFG0 0x0010
+#define DSIPHY_CMN_CLK_CFG1 0x0014
+#define DSIPHY_CMN_GLBL_TEST_CTRL 0x0018
+
+#define DSIPHY_CMN_PLL_CNTRL 0x0048
+#define DSIPHY_CMN_CTRL_0 0x001c
+#define DSIPHY_CMN_CTRL_1 0x0020
+
+#define DSIPHY_CMN_LDO_CNTRL 0x004c
+
+#define DSIPHY_PLL_IE_TRIM 0x0400
+#define DSIPHY_PLL_IP_TRIM 0x0404
+
+#define DSIPHY_PLL_IPTAT_TRIM 0x0410
+
+#define DSIPHY_PLL_CLKBUFLR_EN 0x041c
+
+#define DSIPHY_PLL_SYSCLK_EN_RESET 0x0428
+#define DSIPHY_PLL_RESETSM_CNTRL 0x042c
+#define DSIPHY_PLL_RESETSM_CNTRL2 0x0430
+#define DSIPHY_PLL_RESETSM_CNTRL3 0x0434
+#define DSIPHY_PLL_RESETSM_CNTRL4 0x0438
+#define DSIPHY_PLL_RESETSM_CNTRL5 0x043c
+#define DSIPHY_PLL_KVCO_DIV_REF1 0x0440
+#define DSIPHY_PLL_KVCO_DIV_REF2 0x0444
+
+#define DSIPHY_PLL_KVCO_COUNT1 0x0448
+#define DSIPHY_PLL_KVCO_COUNT2 0x044c
+
+#define DSIPHY_PLL_VCO_DIV_REF1 0x046c
+#define DSIPHY_PLL_VCO_DIV_REF2 0x0470
+#define DSIPHY_PLL_VCO_COUNT1 0x0474
+#define DSIPHY_PLL_VCO_COUNT2 0x0478
+#define DSIPHY_PLL_PLLLOCK_CMP1 0x047c
+#define DSIPHY_PLL_PLLLOCK_CMP2 0x0480
+#define DSIPHY_PLL_PLLLOCK_CMP3 0x0484
+#define DSIPHY_PLL_PLLLOCK_CMP_EN 0x0488
+
+#define DSIPHY_PLL_DEC_START 0x0490
+#define DSIPHY_PLL_DIV_FRAC_START1 0x04b4
+#define DSIPHY_PLL_DIV_FRAC_START2 0x04b8
+#define DSIPHY_PLL_DIV_FRAC_START3 0x04bc
+#define DSIPHY_PLL_TXCLK_EN 0x04c0
+#define DSIPHY_PLL_PLL_CRCTRL 0x04c4
+
+#define DSIPHY_PLL_RESET_SM_READY_STATUS 0x04cc
+
+#define DSIPHY_PLL_PLL_MISC1 0x04e8
+
+#define DSIPHY_PLL_CP_SET_CUR 0x04f0
+#define DSIPHY_PLL_PLL_ICPMSET 0x04f4
+#define DSIPHY_PLL_PLL_ICPCSET 0x04f8
+#define DSIPHY_PLL_PLL_ICP_SET 0x04fc
+#define DSIPHY_PLL_PLL_LPF1 0x0500
+#define DSIPHY_PLL_PLL_LPF2_POSTDIV 0x0504
+
+struct dsi_pll_input {
+ u32 fref; /* 19.2 Mhz, reference clk */
+ u32 fdata; /* bit clock rate */
+ u32 dsiclk_sel; /* 1, reg: 0x0014 */
+ u32 n2div; /* 1, reg: 0x0010, bit 4-7 */
+ u32 ssc_en; /* 1, reg: 0x0494, bit 0 */
+ u32 ldo_en; /* 0, reg: 0x004c, bit 0 */
+
+ /* fixed */
+ u32 refclk_dbler_en; /* 0, reg: 0x04c0, bit 1 */
+ u32 vco_measure_time; /* 5, unknown */
+ u32 kvco_measure_time; /* 5, unknown */
+ u32 bandgap_timer; /* 4, reg: 0x0430, bit 3 - 5 */
+ u32 pll_wakeup_timer; /* 5, reg: 0x043c, bit 0 - 2 */
+ u32 plllock_cnt; /* 1, reg: 0x0488, bit 1 - 2 */
+ u32 plllock_rng; /* 1, reg: 0x0488, bit 3 - 4 */
+ u32 ssc_center_spread; /* 0, reg: 0x0494, bit 1 */
+ u32 ssc_adj_per; /* 37, reg: 0x498, bit 0 - 9 */
+ u32 ssc_spread; /* 0.005 */
+ u32 ssc_freq; /* unknown */
+ u32 pll_ie_trim; /* 4, reg: 0x0400 */
+ u32 pll_ip_trim; /* 4, reg: 0x0404 */
+ u32 pll_iptat_trim; /* reg: 0x0410 */
+ u32 pll_cpcset_cur; /* 1, reg: 0x04f0, bit 0 - 2 */
+ u32 pll_cpmset_cur; /* 1, reg: 0x04f0, bit 3 - 5 */
+
+ u32 pll_icpmset; /* 4, reg: 0x04fc, bit 3 - 5 */
+ u32 pll_icpcset; /* 4, reg: 0x04fc, bit 0 - 2 */
+
+ u32 pll_icpmset_p; /* 0, reg: 0x04f4, bit 0 - 2 */
+ u32 pll_icpmset_m; /* 0, reg: 0x04f4, bit 3 - 5 */
+
+ u32 pll_icpcset_p; /* 0, reg: 0x04f8, bit 0 - 2 */
+ u32 pll_icpcset_m; /* 0, reg: 0x04f8, bit 3 - 5 */
+
+ u32 pll_lpf_res1; /* 3, reg: 0x0504, bit 0 - 3 */
+ u32 pll_lpf_cap1; /* 11, reg: 0x0500, bit 0 - 3 */
+ u32 pll_lpf_cap2; /* 14, reg: 0x0500, bit 4 - 7 */
+ u32 pll_c3ctrl; /* 2, reg: 0x04c4 */
+ u32 pll_r3ctrl; /* 1, reg: 0x04c4 */
+};
+
+struct dsi_pll_output {
+ u32 clkbuflr_en; /* reg: 0x041c, unknown */
+ u32 pll_txclk_en; /* reg: 0x04c0 */
+ u32 dec_start; /* reg: 0x0490 */
+ u32 div_frac_start; /* reg: 0x04b4, 0x4b8, 0x04bc */
+ u32 ssc_per; /* reg: 0x04a0, 0x04a4 */
+ u32 ssc_step_size; /* reg: 0x04a8, 0x04ac */
+ u32 plllock_cmp; /* reg: 0x047c, 0x0480, 0x0484 */
+ u32 pll_vco_div_ref; /* reg: 0x046c, 0x0470 */
+ u32 pll_vco_count; /* reg: 0x0474, 0x0478 */
+ u32 pll_kvco_div_ref; /* reg: 0x0440, 0x0444 */
+ u32 pll_kvco_count; /* reg: 0x0448, 0x044c */
+ u32 pll_misc1; /* reg: 0x04e8 */
+ u32 pll_lpf2_postdiv; /* reg: 0x0504 */
+ u32 pll_resetsm_cntrl; /* reg: 0x042c */
+ u32 pll_resetsm_cntrl2; /* reg: 0x0430 */
+ u32 pll_resetsm_cntrl5; /* reg: 0x043c */
+ u32 pll_kvco_code; /* reg: 0x0458 */
+
+ u32 pll_ie_trim; /* reg: 0x0400 */
+ u32 pll_ip_trim; /* reg: 0x0404 */
+ u32 pll_iptat_trim; /* reg: 0x0410 */
+
+ u32 pll_clkbuflr_en; /* reg: 0x001c */
+
+ u32 cmn_clk_cfg0; /* reg: 0x0010 */
+ u32 cmn_clk_cfg1; /* reg: 0x0014 */
+ u32 cmn_ldo_cntrl; /* reg: 0x004c */
+
+ u32 pll_postdiv; /* vco */
+ u32 pll_n1div; /* vco */
+ u32 pll_n2div; /* hr_oclk3, pixel */
+ u32 fcvo;
+};
+
+struct dsi_pll_db {
+ struct dsi_pll_input in;
+ struct dsi_pll_output out;
+};
+
+int pll_vco_set_rate_thulium(struct clk *c, unsigned long rate);
+long pll_vco_round_rate_thulium(struct clk *c, unsigned long rate);
+enum handoff pll_vco_handoff_thulium(struct clk *c);
+int pll_vco_prepare_thulium(struct clk *c);
+void pll_vco_unprepare_thulium(struct clk *c);
+int set_mdss_byte_mux_sel_thulium(struct mux_clk *clk, int sel);
+int get_mdss_byte_mux_sel_thulium(struct mux_clk *clk);
+int set_mdss_pixel_mux_sel_thulium(struct mux_clk *clk, int sel);
+int get_mdss_pixel_mux_sel_thulium(struct mux_clk *clk);
+int post_n1_div_set_div(struct div_clk *clk, int div);
+int post_n1_div_get_div(struct div_clk *clk);
+int n2_div_set_div(struct div_clk *clk, int div);
+int n2_div_get_div(struct div_clk *clk);
+int dsi_pll_enable_seq_thulium(struct mdss_pll_resources *pll);
+
+#endif /* MDSS_DSI_PLL_THULIUM_H */
diff --git a/drivers/clk/msm/mdss/mdss-dsi-pll.h b/drivers/clk/msm/mdss/mdss-dsi-pll.h
index 67fcd4d35b59..0856109c5554 100644
--- a/drivers/clk/msm/mdss/mdss-dsi-pll.h
+++ b/drivers/clk/msm/mdss/mdss-dsi-pll.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2014, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2015, 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
@@ -56,6 +56,8 @@ int dsi_pll_clock_register_20nm(struct platform_device *pdev,
struct mdss_pll_resources *pll_res);
int dsi_pll_clock_register_lpm(struct platform_device *pdev,
struct mdss_pll_resources *pll_res);
+int dsi_pll_clock_register_thulium(struct platform_device *pdev,
+ struct mdss_pll_resources *pll_res);
int set_byte_mux_sel(struct mux_clk *clk, int sel);
int get_byte_mux_sel(struct mux_clk *clk);
diff --git a/drivers/clk/msm/mdss/mdss-pll.c b/drivers/clk/msm/mdss/mdss-pll.c
index 40e291bb60c6..6badaa48d4ba 100644
--- a/drivers/clk/msm/mdss/mdss-pll.c
+++ b/drivers/clk/msm/mdss/mdss-pll.c
@@ -145,6 +145,9 @@ static int mdss_pll_resource_parse(struct platform_device *pdev,
} else if (!strcmp(compatible_stream, "qcom,mdss_dsi_pll_8992")) {
pll_res->pll_interface_type = MDSS_DSI_PLL_20NM;
pll_res->target_id = MDSS_PLL_TARGET_8992;
+ } else if (!strcmp(compatible_stream, "qcom,mdss_dsi_pll_thulium")) {
+ pll_res->pll_interface_type = MDSS_DSI_PLL_THULIUM;
+ pll_res->target_id = MDSS_PLL_TARGET_THULIUM;
} else if (!strcmp(compatible_stream, "qcom,mdss_edp_pll")) {
pll_res->pll_interface_type = MDSS_EDP_PLL;
} else if (!strcmp(compatible_stream, "qcom,mdss_hdmi_pll")) {
@@ -187,6 +190,9 @@ static int mdss_pll_clock_register(struct platform_device *pdev,
case MDSS_DSI_PLL_20NM:
rc = dsi_pll_clock_register_20nm(pdev, pll_res);
break;
+ case MDSS_DSI_PLL_THULIUM:
+ rc = dsi_pll_clock_register_thulium(pdev, pll_res);
+ break;
case MDSS_EDP_PLL:
rc = edp_pll_clock_register(pdev, pll_res);
break;
@@ -396,6 +402,7 @@ static int mdss_pll_remove(struct platform_device *pdev)
static const struct of_device_id mdss_pll_dt_match[] = {
{.compatible = "qcom,mdss_dsi_pll_8974"},
{.compatible = "qcom,mdss_dsi_pll_8994"},
+ {.compatible = "qcom,mdss_dsi_pll_thulium"},
{.compatible = "qcom,mdss_hdmi_pll_8994"},
{.compatible = "qcom,mdss_dsi_pll_8992"},
{.compatible = "qcom,mdss_hdmi_pll_8992"},
diff --git a/drivers/clk/msm/mdss/mdss-pll.h b/drivers/clk/msm/mdss/mdss-pll.h
index 1e51e6ec4280..bc5ec139d79a 100644
--- a/drivers/clk/msm/mdss/mdss-pll.h
+++ b/drivers/clk/msm/mdss/mdss-pll.h
@@ -31,6 +31,7 @@ enum {
MDSS_DSI_PLL_LPM,
MDSS_DSI_PLL_HPM,
MDSS_DSI_PLL_20NM,
+ MDSS_DSI_PLL_THULIUM,
MDSS_EDP_PLL,
MDSS_HDMI_PLL,
MDSS_HDMI_PLL_20NM,
@@ -42,6 +43,7 @@ enum {
MDSS_PLL_TARGET_8974,
MDSS_PLL_TARGET_8994,
MDSS_PLL_TARGET_8992,
+ MDSS_PLL_TARGET_THULIUM,
MDSS_PLL_TARGET_8916,
MDSS_PLL_TARGET_8939,
MDSS_PLL_TARGET_8909,
@@ -134,6 +136,7 @@ struct mdss_pll_resources {
*/
uint32_t index;
+ void *priv;
};
struct mdss_pll_vco_calc {