summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChandan Uddaraju <chandanu@codeaurora.org>2014-05-19 12:23:43 -0700
committerDavid Keitel <dkeitel@codeaurora.org>2016-03-23 20:41:17 -0700
commitf4ab33c242ca3ea9173c6331eb0888587e0f5979 (patch)
tree1490b188d53574842ba3fe74c9723fb75064d898
parentb5a85b47aef32cbdee68932378da6cf949348470 (diff)
clk: qcom: mdss: add mdss 20nm pll clock driver support
Add support for new 20nm PLL clock driver to handle different DSI panel resolutions. Add seperate files to support this new 20nm PHY PLL block. Change-Id: I4ee5309449f317daddba7106cb8e1829fd6e76cf [veeras@codeaurora.org: As part of the 3.18 upgrade, removing all the msm/mdss display related changes from this commit as it was already updated during that msm/mdss folder update] Signed-off-by: Chandan Uddaraju <chandanu@codeaurora.org> Signed-off-by: Veera Sundaram Sankaran <veeras@codeaurora.org> Signed-off-by: Veera Sundaram Sankaran <veeras@codeaurora.org>
-rw-r--r--Documentation/devicetree/bindings/fb/mdss-pll.txt2
-rw-r--r--drivers/clk/msm/mdss/Makefile3
-rw-r--r--drivers/clk/msm/mdss/mdss-dsi-20nm-pll-util.c652
-rw-r--r--drivers/clk/msm/mdss/mdss-dsi-pll-20nm.c293
-rw-r--r--drivers/clk/msm/mdss/mdss-dsi-pll.h27
-rw-r--r--drivers/clk/msm/mdss/mdss-pll.c7
-rw-r--r--drivers/clk/msm/mdss/mdss-pll.h2
7 files changed, 985 insertions, 1 deletions
diff --git a/Documentation/devicetree/bindings/fb/mdss-pll.txt b/Documentation/devicetree/bindings/fb/mdss-pll.txt
index 96f1aeed47f5..fbb18c638ea9 100644
--- a/Documentation/devicetree/bindings/fb/mdss-pll.txt
+++ b/Documentation/devicetree/bindings/fb/mdss-pll.txt
@@ -16,6 +16,7 @@ Required properties:
Optional properties:
- label: A string used to describe the driver used.
+- vcca-supply: Phandle for vcca regulator device node.
- qcom,platform-supply-entries: A node that lists the elements of the supply. There
can be more than one instance of this binding,
@@ -43,6 +44,7 @@ Example:
reg-names = "pll_base";
gdsc-supply = <&gdsc_mdss>;
vddio-supply = <&pm8941_l12>;
+ vcca-supply = <&pm8941_l28>;
clock-names = "mdp_core_clk", "iface_clk", "bus_clk";
clock-rate = <0>, <0>, <0>;
diff --git a/drivers/clk/msm/mdss/Makefile b/drivers/clk/msm/mdss/Makefile
index f18ee98410f8..696c91d26617 100644
--- a/drivers/clk/msm/mdss/Makefile
+++ b/drivers/clk/msm/mdss/Makefile
@@ -1,7 +1,8 @@
obj-$(CONFIG_MSM_MDSS_PLL) += mdss-pll-util.o
obj-$(CONFIG_MSM_MDSS_PLL) += mdss-pll.o
-obj-$(CONFIG_MSM_MDSS_PLL) += mdss-dsi-pll-util.o
+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-edp-pll-28hpm.o
obj-$(CONFIG_MSM_MDSS_PLL) += mdss-hdmi-pll-28hpm.o
diff --git a/drivers/clk/msm/mdss/mdss-dsi-20nm-pll-util.c b/drivers/clk/msm/mdss/mdss-dsi-20nm-pll-util.c
new file mode 100644
index 000000000000..bc17bd2fd0d4
--- /dev/null
+++ b/drivers/clk/msm/mdss/mdss-dsi-20nm-pll-util.c
@@ -0,0 +1,652 @@
+/* Copyright (c) 2014, 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"
+
+#define MMSS_DSI_PHY_PLL_SYS_CLK_CTRL 0x0000
+#define MMSS_DSI_PHY_PLL_PLL_VCOTAIL_EN 0x0004
+#define MMSS_DSI_PHY_PLL_CMN_MODE 0x0008
+#define MMSS_DSI_PHY_PLL_IE_TRIM 0x000C
+#define MMSS_DSI_PHY_PLL_IP_TRIM 0x0010
+
+#define MMSS_DSI_PHY_PLL_PLL_PHSEL_CONTROL 0x0018
+#define MMSS_DSI_PHY_PLL_IPTAT_TRIM_VCCA_TX_SEL 0x001C
+#define MMSS_DSI_PHY_PLL_PLL_PHSEL_DC 0x0020
+#define MMSS_DSI_PHY_PLL_PLL_IP_SETI 0x0024
+#define MMSS_DSI_PHY_PLL_CORE_CLK_IN_SYNC_SEL 0x0028
+
+#define MMSS_DSI_PHY_PLL_BIAS_EN_CLKBUFLR_EN 0x0030
+#define MMSS_DSI_PHY_PLL_PLL_CP_SETI 0x0034
+#define MMSS_DSI_PHY_PLL_PLL_IP_SETP 0x0038
+#define MMSS_DSI_PHY_PLL_PLL_CP_SETP 0x003C
+#define MMSS_DSI_PHY_PLL_ATB_SEL1 0x0040
+#define MMSS_DSI_PHY_PLL_ATB_SEL2 0x0044
+#define MMSS_DSI_PHY_PLL_SYSCLK_EN_SEL_TXBAND 0x0048
+#define MMSS_DSI_PHY_PLL_RESETSM_CNTRL 0x004C
+#define MMSS_DSI_PHY_PLL_RESETSM_CNTRL2 0x0050
+#define MMSS_DSI_PHY_PLL_RESETSM_CNTRL3 0x0054
+#define MMSS_DSI_PHY_PLL_RESETSM_PLL_CAL_COUNT1 0x0058
+#define MMSS_DSI_PHY_PLL_RESETSM_PLL_CAL_COUNT2 0x005C
+#define MMSS_DSI_PHY_PLL_DIV_REF1 0x0060
+#define MMSS_DSI_PHY_PLL_DIV_REF2 0x0064
+#define MMSS_DSI_PHY_PLL_KVCO_COUNT1 0x0068
+#define MMSS_DSI_PHY_PLL_KVCO_COUNT2 0x006C
+#define MMSS_DSI_PHY_PLL_KVCO_CAL_CNTRL 0x0070
+#define MMSS_DSI_PHY_PLL_KVCO_CODE 0x0074
+#define MMSS_DSI_PHY_PLL_VREF_CFG1 0x0078
+#define MMSS_DSI_PHY_PLL_VREF_CFG2 0x007C
+#define MMSS_DSI_PHY_PLL_VREF_CFG3 0x0000
+#define MMSS_DSI_PHY_PLL_VREF_CFG4 0x0084
+#define MMSS_DSI_PHY_PLL_VREF_CFG5 0x0088
+#define MMSS_DSI_PHY_PLL_VREF_CFG6 0x008C
+#define MMSS_DSI_PHY_PLL_PLLLOCK_CMP1 0x0090
+#define MMSS_DSI_PHY_PLL_PLLLOCK_CMP2 0x0094
+#define MMSS_DSI_PHY_PLL_PLLLOCK_CMP3 0x0098
+
+#define MMSS_DSI_PHY_PLL_BGTC 0x00A0
+#define MMSS_DSI_PHY_PLL_PLL_TEST_UPDN 0x00A4
+#define MMSS_DSI_PHY_PLL_PLL_VCO_TUNE 0x00A8
+#define MMSS_DSI_PHY_PLL_DEC_START1 0x00AC
+#define MMSS_DSI_PHY_PLL_PLL_AMP_OS 0x00B0
+#define MMSS_DSI_PHY_PLL_SSC_EN_CENTER 0x00B4
+#define MMSS_DSI_PHY_PLL_SSC_ADJ_PER1 0x00B8
+#define MMSS_DSI_PHY_PLL_SSC_ADJ_PER2 0x00BC
+#define MMSS_DSI_PHY_PLL_SSC_PER1 0x00C0
+#define MMSS_DSI_PHY_PLL_SSC_PER2 0x00C4
+#define MMSS_DSI_PHY_PLL_SSC_STEP_SIZE1 0x00C8
+#define MMSS_DSI_PHY_PLL_SSC_STEP_SIZE2 0x00CC
+#define MMSS_DSI_PHY_PLL_RES_CODE_UP 0x00D0
+#define MMSS_DSI_PHY_PLL_RES_CODE_DN 0x00D4
+#define MMSS_DSI_PHY_PLL_RES_CODE_UP_OFFSET 0x00D8
+#define MMSS_DSI_PHY_PLL_RES_CODE_DN_OFFSET 0x00DC
+#define MMSS_DSI_PHY_PLL_RES_CODE_START_SEG1 0x00E0
+#define MMSS_DSI_PHY_PLL_RES_CODE_START_SEG2 0x00E4
+#define MMSS_DSI_PHY_PLL_RES_CODE_CAL_CSR 0x00E8
+#define MMSS_DSI_PHY_PLL_RES_CODE 0x00EC
+#define MMSS_DSI_PHY_PLL_RES_TRIM_CONTROL 0x00F0
+#define MMSS_DSI_PHY_PLL_RES_TRIM_CONTROL2 0x00F4
+#define MMSS_DSI_PHY_PLL_RES_TRIM_EN_VCOCALDONE 0x00F8
+#define MMSS_DSI_PHY_PLL_FAUX_EN 0x00FC
+
+#define MMSS_DSI_PHY_PLL_DIV_FRAC_START1 0x0100
+#define MMSS_DSI_PHY_PLL_DIV_FRAC_START2 0x0104
+#define MMSS_DSI_PHY_PLL_DIV_FRAC_START3 0x0108
+#define MMSS_DSI_PHY_PLL_DEC_START2 0x010C
+#define MMSS_DSI_PHY_PLL_PLL_RXTXEPCLK_EN 0x0110
+#define MMSS_DSI_PHY_PLL_PLL_CRCTRL 0x0114
+#define MMSS_DSI_PHY_PLL_LOW_POWER_RO_CONTROL 0x013C
+#define MMSS_DSI_PHY_PLL_POST_DIVIDER_CONTROL 0x0140
+#define MMSS_DSI_PHY_PLL_HR_OCLK2_DIVIDER 0x0144
+#define MMSS_DSI_PHY_PLL_HR_OCLK3_DIVIDER 0x0148
+#define MMSS_DSI_PHY_PLL_PLL_VCO_HIGH 0x014C
+#define MMSS_DSI_PHY_PLL_RESET_SM 0x0150
+
+#define DSI_PLL_POLL_MAX_READS 10
+#define DSI_PLL_POLL_TIMEOUT_US 500
+
+
+int set_bypass_lp_div_mux_sel(struct mux_clk *clk, int sel)
+{
+ struct mdss_pll_resources *dsi_pll_res = clk->priv;
+ int reg_data;
+
+ pr_debug("bypass_lp_div mux set to %s mode\n",
+ sel ? "indirect" : "direct");
+
+ reg_data = MDSS_PLL_REG_R(dsi_pll_res->pll_base,
+ MMSS_DSI_PHY_PLL_POST_DIVIDER_CONTROL);
+ reg_data |= BIT(7);
+ MDSS_PLL_REG_W(dsi_pll_res->pll_base,
+ MMSS_DSI_PHY_PLL_POST_DIVIDER_CONTROL,
+ reg_data | (sel << 5));
+
+ return 0;
+}
+
+int get_bypass_lp_div_mux_sel(struct mux_clk *clk)
+{
+ int mux_mode, rc;
+ struct mdss_pll_resources *dsi_pll_res = clk->priv;
+
+ rc = mdss_pll_resource_enable(dsi_pll_res, true);
+ if (rc) {
+ pr_err("Failed to enable mdss dsi pll resources\n");
+ return rc;
+ }
+
+ mux_mode = MDSS_PLL_REG_R(dsi_pll_res->pll_base,
+ MMSS_DSI_PHY_PLL_POST_DIVIDER_CONTROL) & BIT(5);
+
+ pr_debug("bypass_lp_div mux mode = %s",
+ mux_mode ? "indirect" : "direct");
+ mdss_pll_resource_enable(dsi_pll_res, false);
+
+ return !!mux_mode;
+}
+
+int ndiv_set_div(struct div_clk *clk, int div)
+{
+ int rc, reg_data;
+ struct mdss_pll_resources *dsi_pll_res = clk->priv;
+
+ rc = mdss_pll_resource_enable(dsi_pll_res, true);
+ if (rc) {
+ pr_err("Failed to enable mdss dsi pll resources\n");
+ return rc;
+ }
+
+ reg_data = MDSS_PLL_REG_R(dsi_pll_res->pll_base,
+ MMSS_DSI_PHY_PLL_POST_DIVIDER_CONTROL);
+ MDSS_PLL_REG_W(dsi_pll_res->pll_base,
+ MMSS_DSI_PHY_PLL_POST_DIVIDER_CONTROL,
+ reg_data | div);
+
+ mdss_pll_resource_enable(dsi_pll_res, false);
+ return rc;
+}
+
+int ndiv_get_div(struct div_clk *clk)
+{
+ int div = 0, rc;
+ struct mdss_pll_resources *dsi_pll_res = clk->priv;
+
+ rc = mdss_pll_resource_enable(clk->priv, true);
+ if (rc) {
+ pr_err("Failed to enable mdss dsi pll resources\n");
+ return rc;
+ }
+
+ div = MDSS_PLL_REG_R(dsi_pll_res->pll_base,
+ MMSS_DSI_PHY_PLL_POST_DIVIDER_CONTROL) & 0x0F;
+
+ mdss_pll_resource_enable(dsi_pll_res, false);
+
+ return div;
+}
+
+int fixed_hr_oclk2_set_div(struct div_clk *clk, int div)
+{
+ int rc;
+ struct mdss_pll_resources *dsi_pll_res = clk->priv;
+
+ rc = mdss_pll_resource_enable(dsi_pll_res, true);
+ if (rc) {
+ pr_err("Failed to enable mdss dsi pll resources\n");
+ return rc;
+ }
+
+ MDSS_PLL_REG_W(dsi_pll_res->pll_base,
+ MMSS_DSI_PHY_PLL_HR_OCLK2_DIVIDER,
+ (div - 1));
+
+ mdss_pll_resource_enable(dsi_pll_res, false);
+ return rc;
+}
+
+int fixed_hr_oclk2_get_div(struct div_clk *clk)
+{
+ int div = 0, rc;
+ struct mdss_pll_resources *dsi_pll_res = clk->priv;
+
+ rc = mdss_pll_resource_enable(dsi_pll_res, true);
+ if (rc) {
+ pr_err("Failed to enable mdss dsi pll resources\n");
+ return rc;
+ }
+
+ div = MDSS_PLL_REG_R(dsi_pll_res->pll_base,
+ MMSS_DSI_PHY_PLL_HR_OCLK2_DIVIDER);
+
+ mdss_pll_resource_enable(dsi_pll_res, false);
+ return div + 1;
+}
+
+int hr_oclk3_set_div(struct div_clk *clk, int div)
+{
+ int rc;
+ struct mdss_pll_resources *dsi_pll_res = clk->priv;
+
+ rc = mdss_pll_resource_enable(dsi_pll_res, true);
+ if (rc) {
+ pr_err("Failed to enable mdss dsi pll resources\n");
+ return rc;
+ }
+
+ MDSS_PLL_REG_W(dsi_pll_res->pll_base,
+ MMSS_DSI_PHY_PLL_HR_OCLK3_DIVIDER,
+ (div - 1));
+
+ mdss_pll_resource_enable(dsi_pll_res, false);
+ return rc;
+}
+
+int hr_oclk3_get_div(struct div_clk *clk)
+{
+ int div = 0, rc;
+ struct mdss_pll_resources *dsi_pll_res = clk->priv;
+
+ rc = mdss_pll_resource_enable(dsi_pll_res, true);
+ if (rc) {
+ pr_err("Failed to enable mdss dsi pll resources\n");
+ return rc;
+ }
+
+ div = MDSS_PLL_REG_R(dsi_pll_res->pll_base,
+ MMSS_DSI_PHY_PLL_HR_OCLK3_DIVIDER);
+
+ mdss_pll_resource_enable(dsi_pll_res, false);
+ return div + 1;
+}
+
+int dsi_20nm_pll_lock_status(struct mdss_pll_resources *dsi_pll_res)
+{
+ u32 status;
+ int pll_locked;
+
+ /* poll for PLL ready status */
+ if (readl_poll_timeout_noirq((dsi_pll_res->pll_base +
+ MMSS_DSI_PHY_PLL_RESET_SM),
+ 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 = 0;
+ } else if (readl_poll_timeout_noirq((dsi_pll_res->pll_base +
+ MMSS_DSI_PHY_PLL_RESET_SM),
+ status,
+ ((status & BIT(6)) > 0),
+ DSI_PLL_POLL_MAX_READS,
+ DSI_PLL_POLL_TIMEOUT_US)) {
+ pr_debug("DSI PLL status=%x PLl not ready\n", status);
+ pll_locked = 0;
+ } else {
+ pll_locked = 1;
+ }
+
+ return pll_locked;
+}
+
+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 *dsi_pll_res = vco->priv;
+
+ rc = mdss_pll_resource_enable(dsi_pll_res, 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](dsi_pll_res);
+ pr_debug("DSI PLL %s after sequence #%d\n",
+ rc ? "unlocked" : "locked", i + 1);
+ if (!rc)
+ break;
+ }
+
+ if (rc) {
+ mdss_pll_resource_enable(dsi_pll_res, false);
+ pr_err("DSI PLL failed to lock\n");
+ }
+ dsi_pll_res->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 *dsi_pll_res = vco->priv;
+
+ if (!dsi_pll_res->pll_on &&
+ mdss_pll_resource_enable(dsi_pll_res, true)) {
+ pr_err("Failed to enable mdss dsi pll resources\n");
+ return;
+ }
+
+ dsi_pll_res->handoff_resources = false;
+
+ MDSS_PLL_REG_W(dsi_pll_res->pll_base,
+ MMSS_DSI_PHY_PLL_PLL_VCOTAIL_EN, 0x00);
+
+ mdss_pll_resource_enable(dsi_pll_res, false);
+ dsi_pll_res->pll_on = false;
+
+ pr_debug("DSI PLL Disabled\n");
+ return;
+}
+
+void pll_20nm_dsi_phy_ctrl_config(struct mdss_pll_resources *dsi_pll_res,
+ int off)
+{
+ /* MMSS_DSI_0_PHY_DSIPHY_CTRL_1 */
+ MDSS_PLL_REG_W(dsi_pll_res->pll_base, off + 0x0174, 0x80);
+ wmb();
+
+ /* MMSS_DSI_0_PHY_DSIPHY_CTRL_1 */
+ MDSS_PLL_REG_W(dsi_pll_res->pll_base, off + 0x0174, 0x00);
+ /* Strength ctrl 0 */
+ MDSS_PLL_REG_W(dsi_pll_res->pll_base, off + 0x0184, 0x77);
+ /* MMSS_DSI_0_PHY_DSIPHY_CTRL_0 */
+ MDSS_PLL_REG_W(dsi_pll_res->pll_base, off + 0x0170, 0x7f);
+ wmb();
+
+ /* DSI_0_PHY_DSIPHY_GLBL_TEST_CTRL */
+ MDSS_PLL_REG_W(dsi_pll_res->pll_base, off + 0x01d4, 0x00);
+
+ /* MMSS_DSI_0_PHY_DSIPHY_CTRL_2 */
+ MDSS_PLL_REG_W(dsi_pll_res->pll_base, off + 0x0178, 0x00);
+ MDSS_PLL_REG_W(dsi_pll_res->pll_base, off + 0x0178, 0x02);
+ MDSS_PLL_REG_W(dsi_pll_res->pll_base, off + 0x0178, 0x03);
+}
+
+static void pll_20nm_phy_kvco_config(struct dsi_pll_vco_clk *vco)
+{
+ struct mdss_pll_resources *dsi_pll_res = vco->priv;
+
+ MDSS_PLL_REG_W(dsi_pll_res->pll_base, MMSS_DSI_PHY_PLL_DIV_REF1, 0x00);
+ MDSS_PLL_REG_W(dsi_pll_res->pll_base, MMSS_DSI_PHY_PLL_DIV_REF2, 0x00);
+ MDSS_PLL_REG_W(dsi_pll_res->pll_base,
+ MMSS_DSI_PHY_PLL_KVCO_COUNT1, 0x00);
+ MDSS_PLL_REG_W(dsi_pll_res->pll_base,
+ MMSS_DSI_PHY_PLL_KVCO_CAL_CNTRL, 0x00);
+ MDSS_PLL_REG_W(dsi_pll_res->pll_base,
+ MMSS_DSI_PHY_PLL_KVCO_CODE, 0x2A);
+}
+
+static void pll_20nm_phy_loop_bw_config(struct mdss_pll_resources *dsi_pll_res)
+{
+ MDSS_PLL_REG_W(dsi_pll_res->pll_base,
+ MMSS_DSI_PHY_PLL_PLL_IP_SETI, 0x01);
+ MDSS_PLL_REG_W(dsi_pll_res->pll_base,
+ MMSS_DSI_PHY_PLL_PLL_CP_SETI, 0x2F);
+ MDSS_PLL_REG_W(dsi_pll_res->pll_base,
+ MMSS_DSI_PHY_PLL_PLL_IP_SETP, 0x13);
+ MDSS_PLL_REG_W(dsi_pll_res->pll_base,
+ MMSS_DSI_PHY_PLL_PLL_CP_SETP, 0x0F);
+ MDSS_PLL_REG_W(dsi_pll_res->pll_base,
+ MMSS_DSI_PHY_PLL_PLL_CRCTRL, 0x24);
+}
+
+static void pll_20nm_phy_reset_st_machine_ctrl
+ (struct mdss_pll_resources *dsi_pll_res)
+{
+ MDSS_PLL_REG_W(dsi_pll_res->pll_base,
+ MMSS_DSI_PHY_PLL_RES_CODE_START_SEG1, 0x64);
+ MDSS_PLL_REG_W(dsi_pll_res->pll_base,
+ MMSS_DSI_PHY_PLL_RES_CODE_START_SEG2, 0x64);
+ MDSS_PLL_REG_W(dsi_pll_res->pll_base,
+ MMSS_DSI_PHY_PLL_RES_TRIM_CONTROL, 0x15);
+
+ MDSS_PLL_REG_W(dsi_pll_res->pll_base,
+ MMSS_DSI_PHY_PLL_RESETSM_CNTRL, 0xf4);
+ MDSS_PLL_REG_W(dsi_pll_res->pll_base,
+ MMSS_DSI_PHY_PLL_RESETSM_CNTRL2, 0x0f);
+ MDSS_PLL_REG_W(dsi_pll_res->pll_base,
+ MMSS_DSI_PHY_PLL_RESETSM_CNTRL3, 0x02);
+ MDSS_PLL_REG_W(dsi_pll_res->pll_base,
+ MMSS_DSI_PHY_PLL_RESETSM_CNTRL3, 0x03);
+}
+
+static void pll_20nm_phy_config(struct dsi_pll_vco_clk *vco)
+{
+ struct mdss_pll_resources *dsi_pll_res = vco->priv;
+
+ MDSS_PLL_REG_W(dsi_pll_res->pll_base,
+ MMSS_DSI_PHY_PLL_SYS_CLK_CTRL, 0x40);
+ MDSS_PLL_REG_W(dsi_pll_res->pll_base,
+ MMSS_DSI_PHY_PLL_PLL_VCOTAIL_EN, 0x00);
+ MDSS_PLL_REG_W(dsi_pll_res->pll_base, MMSS_DSI_PHY_PLL_CMN_MODE, 0x00);
+ MDSS_PLL_REG_W(dsi_pll_res->pll_base, MMSS_DSI_PHY_PLL_IE_TRIM, 0x0F);
+ MDSS_PLL_REG_W(dsi_pll_res->pll_base, MMSS_DSI_PHY_PLL_IP_TRIM, 0x0F);
+ MDSS_PLL_REG_W(dsi_pll_res->pll_base,
+ MMSS_DSI_PHY_PLL_PLL_PHSEL_CONTROL, 0x08);
+ MDSS_PLL_REG_W(dsi_pll_res->pll_base,
+ MMSS_DSI_PHY_PLL_IPTAT_TRIM_VCCA_TX_SEL, 0x0E);
+ MDSS_PLL_REG_W(dsi_pll_res->pll_base,
+ MMSS_DSI_PHY_PLL_PLL_PHSEL_DC, 0x00);
+ MDSS_PLL_REG_W(dsi_pll_res->pll_base,
+ MMSS_DSI_PHY_PLL_CORE_CLK_IN_SYNC_SEL, 0x00);
+ MDSS_PLL_REG_W(dsi_pll_res->pll_base,
+ MMSS_DSI_PHY_PLL_PLL_BKG_KVCO_CAL_EN, 0x08);
+ MDSS_PLL_REG_W(dsi_pll_res->pll_base,
+ MMSS_DSI_PHY_PLL_BIAS_EN_CLKBUFLR_EN, 0x3F);
+ MDSS_PLL_REG_W(dsi_pll_res->pll_base,
+ MMSS_DSI_PHY_PLL_ATB_SEL1, 0x00);
+ MDSS_PLL_REG_W(dsi_pll_res->pll_base,
+ MMSS_DSI_PHY_PLL_ATB_SEL2, 0x00);
+ MDSS_PLL_REG_W(dsi_pll_res->pll_base,
+ MMSS_DSI_PHY_PLL_SYSCLK_EN_SEL_TXBAND, 0x4B);
+ udelay(1000);
+ pll_20nm_phy_kvco_config(vco);
+
+ MDSS_PLL_REG_W(dsi_pll_res->pll_base,
+ MMSS_DSI_PHY_PLL_VREF_CFG1, 0x00);
+ MDSS_PLL_REG_W(dsi_pll_res->pll_base,
+ MMSS_DSI_PHY_PLL_VREF_CFG2, 0x00);
+ MDSS_PLL_REG_W(dsi_pll_res->pll_base,
+ MMSS_DSI_PHY_PLL_BGTC, 0x0F);
+ MDSS_PLL_REG_W(dsi_pll_res->pll_base,
+ MMSS_DSI_PHY_PLL_PLL_TEST_UPDN, 0x00);
+ MDSS_PLL_REG_W(dsi_pll_res->pll_base,
+ MMSS_DSI_PHY_PLL_PLL_VCO_TUNE, 0x01);
+ MDSS_PLL_REG_W(dsi_pll_res->pll_base,
+ MMSS_DSI_PHY_PLL_PLL_AMP_OS, 0x00);
+ MDSS_PLL_REG_W(dsi_pll_res->pll_base,
+ MMSS_DSI_PHY_PLL_SSC_EN_CENTER, 0x00);
+ MDSS_PLL_REG_W(dsi_pll_res->pll_base,
+ MMSS_DSI_PHY_PLL_RES_CODE_UP, 0x00);
+ MDSS_PLL_REG_W(dsi_pll_res->pll_base,
+ MMSS_DSI_PHY_PLL_RES_CODE_DN, 0x00);
+ MDSS_PLL_REG_W(dsi_pll_res->pll_base,
+ MMSS_DSI_PHY_PLL_RES_CODE_CAL_CSR, 0x77);
+ MDSS_PLL_REG_W(dsi_pll_res->pll_base,
+ MMSS_DSI_PHY_PLL_RES_TRIM_EN_VCOCALDONE, 0x0);
+ MDSS_PLL_REG_W(dsi_pll_res->pll_base,
+ MMSS_DSI_PHY_PLL_FAUX_EN, 0x0C);
+ MDSS_PLL_REG_W(dsi_pll_res->pll_base,
+ MMSS_DSI_PHY_PLL_PLL_RXTXEPCLK_EN, 0x0F);
+
+ MDSS_PLL_REG_W(dsi_pll_res->pll_base,
+ MMSS_DSI_PHY_PLL_LOW_POWER_RO_CONTROL, 0x0F);
+ udelay(1000);
+ pll_20nm_phy_loop_bw_config(dsi_pll_res);
+}
+
+int pll_20nm_vco_set_rate(struct dsi_pll_vco_clk *vco, unsigned long rate)
+{
+ s64 vco_clk_rate = rate;
+ s32 div_frac_start, frac_act_div;
+ s64 dec_start;
+ s64 duration, pll_comp_val;
+ struct mdss_pll_resources *dsi_pll_res = vco->priv;
+
+ pr_debug("%s: vco set rate: %ld\n", __func__, rate);
+ pll_20nm_phy_config(vco);
+
+ dec_start = div_s64(vco_clk_rate, 2 * vco->ref_clk_rate);
+ div_s64_rem(vco_clk_rate,
+ 2 * vco->ref_clk_rate, &frac_act_div);
+ div_frac_start = frac_act_div << 18;
+
+ MDSS_PLL_REG_W(dsi_pll_res->pll_base,
+ MMSS_DSI_PHY_PLL_DIV_FRAC_START1, 0xd5);
+
+ MDSS_PLL_REG_W(dsi_pll_res->pll_base,
+ MMSS_DSI_PHY_PLL_DIV_FRAC_START2, 0xaa);
+
+ MDSS_PLL_REG_W(dsi_pll_res->pll_base,
+ MMSS_DSI_PHY_PLL_DIV_FRAC_START3, 0x79);
+
+ MDSS_PLL_REG_W(dsi_pll_res->pll_base,
+ MMSS_DSI_PHY_PLL_DEC_START1, 0xac);
+
+ MDSS_PLL_REG_W(dsi_pll_res->pll_base,
+ MMSS_DSI_PHY_PLL_DEC_START2, 0x2);
+
+ duration = 128;
+ pll_comp_val = div_s64(div_s64(vco_clk_rate,
+ 2 * vco->ref_clk_rate)
+ * (duration - 1), 10);
+
+ MDSS_PLL_REG_W(dsi_pll_res->pll_base,
+ MMSS_DSI_PHY_PLL_PLLLOCK_CMP1, 0x74);
+
+ MDSS_PLL_REG_W(dsi_pll_res->pll_base,
+ MMSS_DSI_PHY_PLL_PLLLOCK_CMP2, 0x04);
+
+ MDSS_PLL_REG_W(dsi_pll_res->pll_base,
+ MMSS_DSI_PHY_PLL_PLLLOCK_CMP3, 0x00);
+
+ /*
+ * Make sure that PLL vco configuration is complete
+ * before controlling the state machine.
+ */
+ mb();
+ udelay(1000);
+ pll_20nm_phy_reset_st_machine_ctrl(dsi_pll_res);
+ return 0;
+}
+
+unsigned long pll_20nm_vco_get_rate(struct clk *c)
+{
+ u64 vco_rate;
+ 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 *dsi_pll_res = vco->priv;
+
+ rc = mdss_pll_resource_enable(dsi_pll_res, true);
+ if (rc) {
+ pr_err("Failed to enable mdss dsi pll resources\n");
+ return rc;
+ }
+
+ dec_start = MDSS_PLL_REG_R(dsi_pll_res->pll_base,
+ MMSS_DSI_PHY_PLL_DEC_START2) << 7;
+ dec_start |= MDSS_PLL_REG_R(dsi_pll_res->pll_base,
+ MMSS_DSI_PHY_PLL_DEC_START1);
+
+ div_frac_start = MDSS_PLL_REG_R(dsi_pll_res->pll_base,
+ MMSS_DSI_PHY_PLL_DIV_FRAC_START3) << 14;
+ div_frac_start |= (MDSS_PLL_REG_R(dsi_pll_res->pll_base,
+ MMSS_DSI_PHY_PLL_DIV_FRAC_START2) << 7);
+ div_frac_start |= MDSS_PLL_REG_R(dsi_pll_res->pll_base,
+ MMSS_DSI_PHY_PLL_DIV_FRAC_START1);
+
+ vco_rate = ref_clk * 2 * (dec_start + (div_frac_start >> 18));
+ pr_debug("vco rate = %lld", vco_rate);
+
+ /*
+ * TODO: Currently, the dyanmic vco calculator is not finalized.
+ * Hardcoding the vco_rate for now.
+ */
+ vco_rate = 1708439040;
+ pr_debug("returning vco rate = %lu\n", (unsigned long)vco_rate);
+
+ mdss_pll_resource_enable(dsi_pll_res, false);
+
+ return (unsigned long)vco_rate;
+}
+long pll_20nm_vco_round_rate(struct clk *c, unsigned long rate)
+{
+ unsigned long rrate = rate;
+ struct dsi_pll_vco_clk *vco = to_vco_clk(c);
+
+ if (rate < vco->min_rate)
+ rrate = vco->min_rate;
+ if (rate > vco->max_rate)
+ rrate = vco->max_rate;
+
+ return rrate;
+}
+
+enum handoff pll_20nm_vco_handoff(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 *dsi_pll_res = vco->priv;
+
+ rc = mdss_pll_resource_enable(dsi_pll_res, true);
+ if (rc) {
+ pr_err("Failed to enable mdss dsi pll resources\n");
+ return ret;
+ }
+
+ if (dsi_20nm_pll_lock_status(dsi_pll_res)) {
+ dsi_pll_res->handoff_resources = true;
+ dsi_pll_res->pll_on = true;
+ c->rate = pll_20nm_vco_get_rate(c);
+ ret = HANDOFF_ENABLED_CLK;
+ } else {
+ mdss_pll_resource_enable(dsi_pll_res, false);
+ }
+
+ return ret;
+}
+
+int pll_20nm_vco_prepare(struct clk *c)
+{
+ int rc = 0;
+ struct dsi_pll_vco_clk *vco = to_vco_clk(c);
+ struct mdss_pll_resources *dsi_pll_res = vco->priv;
+
+ if (!dsi_pll_res) {
+ pr_err("Dsi pll resources are not available\n");
+ return -EINVAL;
+ }
+
+ if ((dsi_pll_res->vco_cached_rate != 0)
+ && (dsi_pll_res->vco_cached_rate == c->rate)) {
+ rc = c->ops->set_rate(c, dsi_pll_res->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_20nm_vco_unprepare(struct clk *c)
+{
+ struct dsi_pll_vco_clk *vco = to_vco_clk(c);
+ struct mdss_pll_resources *dsi_pll_res = vco->priv;
+
+ if (!dsi_pll_res) {
+ pr_err("Dsi pll resources are not available\n");
+ return;
+ }
+
+ dsi_pll_res->vco_cached_rate = c->rate;
+ dsi_pll_disable(c);
+}
+
diff --git a/drivers/clk/msm/mdss/mdss-dsi-pll-20nm.c b/drivers/clk/msm/mdss/mdss-dsi-pll-20nm.c
new file mode 100644
index 000000000000..3d206706318e
--- /dev/null
+++ b/drivers/clk/msm/mdss/mdss-dsi-pll-20nm.c
@@ -0,0 +1,293 @@
+/* Copyright (c) 2014, 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/clk/msm-clock-generic.h>
+#include <dt-bindings/clock/msm-clocks-8994.h>
+
+#include "mdss-pll.h"
+#include "mdss-dsi-pll.h"
+
+#define VCO_DELAY_USEC 1
+
+static struct clk_ops bypass_lp_div_mux_clk_ops;
+static struct clk_ops pixel_clk_src_ops;
+static struct clk_ops byte_clk_src_ops;
+static struct clk_ops ndiv_clk_ops;
+
+static int vco_set_rate_20nm(struct clk *c, unsigned long rate)
+{
+ int rc;
+ struct dsi_pll_vco_clk *vco = to_vco_clk(c);
+ struct mdss_pll_resources *dsi_pll_res = vco->priv;
+
+ rc = mdss_pll_resource_enable(dsi_pll_res, true);
+ if (rc) {
+ pr_err("Failed to enable mdss dsi pll resources\n");
+ return rc;
+ }
+
+ rc = pll_20nm_vco_set_rate(vco, rate);
+
+ mdss_pll_resource_enable(dsi_pll_res, false);
+ return rc;
+}
+
+static int dsi_pll_enable_seq_8994(struct mdss_pll_resources *dsi_pll_res)
+{
+ int rc = 0;
+ int pll_locked;
+
+ /*
+ * PLL power up sequence.
+ * Add necessary delays recommeded by hardware.
+ */
+ MDSS_PLL_REG_W(dsi_pll_res->pll_base,
+ MMSS_DSI_PHY_PLL_PLLLOCK_CMP_EN, 0x0D);
+ MDSS_PLL_REG_W(dsi_pll_res->pll_base,
+ MMSS_DSI_PHY_PLL_PLL_CNTRL, 0x07);
+ MDSS_PLL_REG_W(dsi_pll_res->pll_base,
+ MMSS_DSI_PHY_PLL_PLL_BKG_KVCO_CAL_EN, 0x00);
+ udelay(500);
+ pll_20nm_dsi_phy_ctrl_config(dsi_pll_res, 0x200); /* Ctrl 0 */
+ pll_locked = dsi_20nm_pll_lock_status(dsi_pll_res);
+ if (!pll_locked) {
+ pr_err("DSI PLL lock failed\n");
+ rc = -EINVAL;
+ } else {
+ pr_debug("DSI PLL Lock success\n");
+ }
+
+ return rc;
+}
+
+/* Op structures */
+
+static struct clk_ops clk_ops_dsi_vco = {
+ .set_rate = vco_set_rate_20nm,
+ .round_rate = pll_20nm_vco_round_rate,
+ .handoff = pll_20nm_vco_handoff,
+ .prepare = pll_20nm_vco_prepare,
+ .unprepare = pll_20nm_vco_unprepare,
+};
+
+
+static struct clk_div_ops fixed_hr_oclk2_div_ops = {
+ .set_div = fixed_hr_oclk2_set_div,
+ .get_div = fixed_hr_oclk2_get_div,
+};
+
+static struct clk_div_ops ndiv_ops = {
+ .set_div = ndiv_set_div,
+ .get_div = ndiv_get_div,
+};
+
+static struct clk_div_ops hr_oclk3_div_ops = {
+ .set_div = hr_oclk3_set_div,
+ .get_div = hr_oclk3_get_div,
+};
+
+static struct clk_mux_ops bypass_lp_div_mux_ops = {
+ .set_mux_sel = set_bypass_lp_div_mux_sel,
+ .get_mux_sel = get_bypass_lp_div_mux_sel,
+};
+
+static struct dsi_pll_vco_clk dsi_vco_clk_8994 = {
+ .ref_clk_rate = 19200000,
+ .min_rate = 1000000000,
+ .max_rate = 2000000000,
+ .pll_en_seq_cnt = 1,
+ .pll_enable_seqs[0] = dsi_pll_enable_seq_8994,
+ .c = {
+ .dbg_name = "dsi_vco_clk_8994",
+ .ops = &clk_ops_dsi_vco,
+ CLK_INIT(dsi_vco_clk_8994.c),
+ },
+};
+
+static struct div_clk ndiv_clk_8994 = {
+ .data = {
+ .max_div = 15,
+ .min_div = 1,
+ },
+ .ops = &ndiv_ops,
+ .c = {
+ .parent = &dsi_vco_clk_8994.c,
+ .dbg_name = "ndiv_clk",
+ .ops = &ndiv_clk_ops,
+ .flags = CLKFLAG_NO_RATE_CACHE,
+ CLK_INIT(ndiv_clk_8994.c),
+ },
+};
+
+static struct div_clk indirect_path_div2_clk_8994 = {
+ .data = {
+ .div = 2,
+ .min_div = 2,
+ .max_div = 2,
+ },
+ .c = {
+ .parent = &ndiv_clk_8994.c,
+ .dbg_name = "indirect_path_div2_clk",
+ .ops = &clk_ops_div,
+ .flags = CLKFLAG_NO_RATE_CACHE,
+ CLK_INIT(indirect_path_div2_clk_8994.c),
+ },
+};
+
+static struct div_clk hr_oclk3_div_clk_8994 = {
+ .data = {
+ .max_div = 255,
+ .min_div = 1,
+ },
+ .ops = &hr_oclk3_div_ops,
+ .c = {
+ .parent = &dsi_vco_clk_8994.c,
+ .dbg_name = "hr_oclk3_div_clk_8994",
+ .ops = &pixel_clk_src_ops,
+ .flags = CLKFLAG_NO_RATE_CACHE,
+ CLK_INIT(hr_oclk3_div_clk_8994.c),
+ },
+};
+
+static struct div_clk pixel_clk_src = {
+ .data = {
+ .div = 2,
+ .min_div = 2,
+ .max_div = 2,
+ },
+ .c = {
+ .parent = &hr_oclk3_div_clk_8994.c,
+ .dbg_name = "pixel_clk_src_8994",
+ .ops = &clk_ops_div,
+ .flags = CLKFLAG_NO_RATE_CACHE,
+ CLK_INIT(pixel_clk_src.c),
+ },
+};
+
+static struct mux_clk bypass_lp_div_mux_8994 = {
+ .num_parents = 2,
+ .parents = (struct clk_src[]){
+ {&dsi_vco_clk_8994.c, 0},
+ {&indirect_path_div2_clk_8994.c, 1},
+ },
+ .ops = &bypass_lp_div_mux_ops,
+ .c = {
+ .parent = &dsi_vco_clk_8994.c,
+ .dbg_name = "bypass_lp_div_mux_8994",
+ .ops = &bypass_lp_div_mux_clk_ops,
+ CLK_INIT(bypass_lp_div_mux_8994.c),
+ },
+};
+
+static struct div_clk fixed_hr_oclk2_div_clk_8994 = {
+ .ops = &fixed_hr_oclk2_div_ops,
+ .data = {
+ .min_div = 4,
+ .max_div = 4,
+ },
+ .c = {
+ .parent = &bypass_lp_div_mux_8994.c,
+ .dbg_name = "fixed_hr_oclk2_div_clk",
+ .ops = &byte_clk_src_ops,
+ CLK_INIT(fixed_hr_oclk2_div_clk_8994.c),
+ },
+};
+
+static struct div_clk byte_clk_src = {
+ .data = {
+ .div = 2,
+ .min_div = 2,
+ .max_div = 2,
+ },
+ .c = {
+ .parent = &fixed_hr_oclk2_div_clk_8994.c,
+ .dbg_name = "byte_clk_src_8994",
+ .ops = &clk_ops_div,
+ CLK_INIT(byte_clk_src.c),
+ },
+};
+
+static struct clk_lookup mdss_dsi_pllcc_8994[] = {
+ CLK_LIST(pixel_clk_src),
+ CLK_LIST(byte_clk_src),
+ CLK_LIST(fixed_hr_oclk2_div_clk_8994),
+ CLK_LIST(bypass_lp_div_mux_8994),
+ CLK_LIST(hr_oclk3_div_clk_8994),
+ CLK_LIST(indirect_path_div2_clk_8994),
+ CLK_LIST(ndiv_clk_8994),
+ CLK_LIST(dsi_vco_clk_8994),
+};
+
+int dsi_pll_clock_register_20nm(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;
+ }
+
+ /* Set client data to mux, div and vco clocks */
+ byte_clk_src.priv = pll_res;
+ pixel_clk_src.priv = pll_res;
+ bypass_lp_div_mux_8994.priv = pll_res;
+ indirect_path_div2_clk_8994.priv = pll_res;
+ ndiv_clk_8994.priv = pll_res;
+ fixed_hr_oclk2_div_clk_8994.priv = pll_res;
+ hr_oclk3_div_clk_8994.priv = pll_res;
+ dsi_vco_clk_8994.priv = pll_res;
+ pll_res->vco_delay = VCO_DELAY_USEC;
+
+ /* Set clock source operations */
+ pixel_clk_src_ops = clk_ops_slave_div;
+ pixel_clk_src_ops.prepare = dsi_pll_div_prepare;
+
+ ndiv_clk_ops = clk_ops_div;
+ ndiv_clk_ops.prepare = dsi_pll_div_prepare;
+
+ byte_clk_src_ops = clk_ops_div;
+ byte_clk_src_ops.prepare = dsi_pll_div_prepare;
+
+ bypass_lp_div_mux_clk_ops = clk_ops_gen_mux;
+ bypass_lp_div_mux_clk_ops.prepare = dsi_pll_mux_prepare;
+
+ if (pll_res->target_id == MDSS_PLL_TARGET_8994) {
+ rc = of_msm_clock_register(pdev->dev.of_node,
+ mdss_dsi_pllcc_8994, ARRAY_SIZE(mdss_dsi_pllcc_8994));
+ if (rc) {
+ pr_err("Clock register failed\n");
+ rc = -EPROBE_DEFER;
+ }
+ } else {
+ pr_err("Invalid target ID\n");
+ rc = -EINVAL;
+ }
+
+ if (!rc)
+ pr_info("Registered DSI PLL clocks successfully\n");
+
+ return rc;
+}
diff --git a/drivers/clk/msm/mdss/mdss-dsi-pll.h b/drivers/clk/msm/mdss/mdss-dsi-pll.h
index 53a6afac2cc6..b0135dc0109b 100644
--- a/drivers/clk/msm/mdss/mdss-dsi-pll.h
+++ b/drivers/clk/msm/mdss/mdss-dsi-pll.h
@@ -20,6 +20,11 @@
#define DSI_PHY_PLL_UNIPHY_PLL_TEST_CFG (0x0068)
#define DSI_PHY_PLL_UNIPHY_PLL_CAL_CFG1 (0x0070)
+/* Register offsets for 20nm PHY PLL */
+#define MMSS_DSI_PHY_PLL_PLL_CNTRL (0x0014)
+#define MMSS_DSI_PHY_PLL_PLL_BKG_KVCO_CAL_EN (0x002C)
+#define MMSS_DSI_PHY_PLL_PLLLOCK_CMP_EN (0x009C)
+
struct lpfr_cfg {
unsigned long vco_rate;
u32 r;
@@ -47,6 +52,8 @@ static inline struct dsi_pll_vco_clk *to_vco_clk(struct clk *clk)
int dsi_pll_clock_register_hpm(struct platform_device *pdev,
struct mdss_pll_resources *pll_res);
+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);
@@ -61,10 +68,30 @@ int digital_get_div(struct div_clk *clk);
int analog_set_div(struct div_clk *clk, int div);
int analog_get_div(struct div_clk *clk);
int dsi_pll_lock_status(struct mdss_pll_resources *dsi_pll_res);
+void pll_20nm_dsi_phy_ctrl_config
+ (struct mdss_pll_resources *dsi_pll_res, int off);
int vco_set_rate(struct dsi_pll_vco_clk *vco, unsigned long rate);
unsigned long vco_get_rate(struct clk *c);
long vco_round_rate(struct clk *c, unsigned long rate);
enum handoff vco_handoff(struct clk *c);
int vco_prepare(struct clk *c);
void vco_unprepare(struct clk *c);
+
+/* APIs for 20nm PHY PLL */
+int pll_20nm_vco_set_rate(struct dsi_pll_vco_clk *vco, unsigned long rate);
+long pll_20nm_vco_round_rate(struct clk *c, unsigned long rate);
+enum handoff pll_20nm_vco_handoff(struct clk *c);
+int pll_20nm_vco_prepare(struct clk *c);
+void pll_20nm_vco_unprepare(struct clk *c);
+int dsi_20nm_pll_lock_status(struct mdss_pll_resources *dsi_pll_res);
+
+int set_bypass_lp_div_mux_sel(struct mux_clk *clk, int sel);
+int get_bypass_lp_div_mux_sel(struct mux_clk *clk);
+int fixed_hr_oclk2_set_div(struct div_clk *clk, int div);
+int fixed_hr_oclk2_get_div(struct div_clk *clk);
+int hr_oclk3_set_div(struct div_clk *clk, int div);
+int hr_oclk3_get_div(struct div_clk *clk);
+int ndiv_set_div(struct div_clk *clk, int div);
+int ndiv_get_div(struct div_clk *clk);
+
#endif
diff --git a/drivers/clk/msm/mdss/mdss-pll.c b/drivers/clk/msm/mdss/mdss-pll.c
index 1754b5179b55..13732eb5c638 100644
--- a/drivers/clk/msm/mdss/mdss-pll.c
+++ b/drivers/clk/msm/mdss/mdss-pll.c
@@ -136,6 +136,9 @@ static int mdss_pll_resource_parse(struct platform_device *pdev,
} else if (!strcmp(compatible_stream, "qcom,mdss_dsi_pll_8974")) {
pll_res->pll_interface_type = MDSS_DSI_PLL_HPM;
pll_res->target_id = MDSS_PLL_TARGET_8974;
+ } else if (!strcmp(compatible_stream, "qcom,mdss_dsi_pll_8994")) {
+ pll_res->pll_interface_type = MDSS_DSI_PLL_20NM;
+ pll_res->target_id = MDSS_PLL_TARGET_8994;
} 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")) {
@@ -169,6 +172,9 @@ static int mdss_pll_clock_register(struct platform_device *pdev,
case MDSS_DSI_PLL_HPM:
rc = dsi_pll_clock_register_hpm(pdev, pll_res);
break;
+ case MDSS_DSI_PLL_20NM:
+ rc = dsi_pll_clock_register_20nm(pdev, pll_res);
+ break;
case MDSS_EDP_PLL:
rc = edp_pll_clock_register(pdev, pll_res);
break;
@@ -307,6 +313,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_8916"},
{.compatible = "qcom,mdss_dsi_pll_8939"},
{.compatible = "qcom,mdss_edp_pll"},
diff --git a/drivers/clk/msm/mdss/mdss-pll.h b/drivers/clk/msm/mdss/mdss-pll.h
index 06bdb2fdccfb..715cd4ad30a0 100644
--- a/drivers/clk/msm/mdss/mdss-pll.h
+++ b/drivers/clk/msm/mdss/mdss-pll.h
@@ -23,6 +23,7 @@
enum {
MDSS_DSI_PLL_LPM,
MDSS_DSI_PLL_HPM,
+ MDSS_DSI_PLL_20NM,
MDSS_EDP_PLL,
MDSS_HDMI_PLL,
MDSS_UNKNOWN_PLL,
@@ -30,6 +31,7 @@ enum {
enum {
MDSS_PLL_TARGET_8974,
+ MDSS_PLL_TARGET_8994,
MDSS_PLL_TARGET_8916,
MDSS_PLL_TARGET_8939,
};