Merge "msm: mdss: add support to program of HSTX drivers for DSI 12nm PHY"
diff --git a/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt b/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt
index 7bcb2dc..b8cb903 100644
--- a/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt
+++ b/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt
@@ -40,6 +40,8 @@
timing settings for the panel.
- qcom,mdss-dsi-panel-timings-phy-v2: An array of length 40 char that specifies the PHY version 2
lane timing settings for the panel.
+- qcom,mdss-dsi-panel-timings-phy-12nm: An array of length 8 char that specifies the 12nm DSI PHY
+ lane timing settings for the panel.
- qcom,mdss-dsi-on-command: A byte stream formed by multiple dcs packets base on
qcom dsi controller protocol.
byte 0: dcs data type
@@ -631,6 +633,8 @@
23 20 06 09 05 03 04 a0
23 20 06 09 05 03 04 a0
23 2e 06 08 05 03 04 a0];
+ qcom,mdss-dsi-panel-timings-phy-12nm =
+ [a9 4e 56 0b 8a 4d 0b d6];
qcom,mdss-dsi-on-command = [32 01 00 00 00 00 02 00 00
29 01 00 00 10 00 02 FF 99];
qcom,mdss-dsi-on-command-state = "dsi_lp_mode";
diff --git a/drivers/video/fbdev/msm/Makefile b/drivers/video/fbdev/msm/Makefile
index 4ee7f4a..81d4953 100644
--- a/drivers/video/fbdev/msm/Makefile
+++ b/drivers/video/fbdev/msm/Makefile
@@ -41,6 +41,7 @@
mdss-dsi-objs += mdss_dsi_panel.o
mdss-dsi-objs += msm_mdss_io_8974.o
mdss-dsi-objs += mdss_dsi_phy.o
+mdss-dsi-objs += mdss_dsi_phy_12nm.o
mdss-dsi-objs += mdss_dsi_clk.o
obj-$(CONFIG_FB_MSM_MDSS) += mdss-dsi.o
obj-$(CONFIG_FB_MSM_MDSS) += mdss_panel.o
diff --git a/drivers/video/fbdev/msm/mdss_dsi.c b/drivers/video/fbdev/msm/mdss_dsi.c
index 6bb0960..cad1387 100644
--- a/drivers/video/fbdev/msm/mdss_dsi.c
+++ b/drivers/video/fbdev/msm/mdss_dsi.c
@@ -2989,9 +2989,9 @@
info.core_clks.mmss_misc_ahb_clk =
ctrl_pdata->shared_data->mmss_misc_ahb_clk;
- info.link_clks.esc_clk = ctrl_pdata->esc_clk;
- info.link_clks.byte_clk = ctrl_pdata->byte_clk;
- info.link_clks.pixel_clk = ctrl_pdata->pixel_clk;
+ info.link_lp_clks.esc_clk = ctrl_pdata->esc_clk;
+ info.link_hs_clks.byte_clk = ctrl_pdata->byte_clk;
+ info.link_hs_clks.pixel_clk = ctrl_pdata->pixel_clk;
info.pre_clkoff_cb = mdss_dsi_pre_clkoff_cb;
info.post_clkon_cb = mdss_dsi_post_clkon_cb;
@@ -3976,13 +3976,12 @@
if (!data) {
pr_err("%s:%d, Unable to read Phy Strength ctrl settings\n",
__func__, __LINE__);
- return -EINVAL;
+ } else {
+ pinfo->mipi.dsi_phy_db.strength_len = len;
+ for (i = 0; i < len; i++)
+ pinfo->mipi.dsi_phy_db.strength[i] = data[i];
}
- pinfo->mipi.dsi_phy_db.strength_len = len;
- for (i = 0; i < len; i++)
- pinfo->mipi.dsi_phy_db.strength[i] = data[i];
-
pinfo->mipi.dsi_phy_db.reg_ldo_mode = of_property_read_bool(
ctrl_pdev->dev.of_node, "qcom,regulator-ldo-mode");
@@ -3991,13 +3990,12 @@
if (!data) {
pr_err("%s:%d, Unable to read Phy regulator settings\n",
__func__, __LINE__);
- return -EINVAL;
+ } else {
+ pinfo->mipi.dsi_phy_db.regulator_len = len;
+ for (i = 0; i < len; i++)
+ pinfo->mipi.dsi_phy_db.regulator[i] = data[i];
}
- pinfo->mipi.dsi_phy_db.regulator_len = len;
- for (i = 0; i < len; i++)
- pinfo->mipi.dsi_phy_db.regulator[i] = data[i];
-
data = of_get_property(ctrl_pdev->dev.of_node,
"qcom,platform-bist-ctrl", &len);
if ((!data) || (len != 6))
@@ -4012,13 +4010,12 @@
if (!data) {
pr_err("%s:%d, Unable to read Phy lane configure settings\n",
__func__, __LINE__);
- return -EINVAL;
+ } else {
+ pinfo->mipi.dsi_phy_db.lanecfg_len = len;
+ for (i = 0; i < len; i++)
+ pinfo->mipi.dsi_phy_db.lanecfg[i] = data[i];
}
- pinfo->mipi.dsi_phy_db.lanecfg_len = len;
- for (i = 0; i < len; i++)
- pinfo->mipi.dsi_phy_db.lanecfg[i] = data[i];
-
ctrl_pdata->timing_db_mode = of_property_read_bool(
ctrl_pdev->dev.of_node, "qcom,timing-db-mode");
diff --git a/drivers/video/fbdev/msm/mdss_dsi.h b/drivers/video/fbdev/msm/mdss_dsi.h
index 60bc455..058c27a 100644
--- a/drivers/video/fbdev/msm/mdss_dsi.h
+++ b/drivers/video/fbdev/msm/mdss_dsi.h
@@ -337,6 +337,7 @@
struct mdss_panel_timing timing;
uint32_t phy_timing[12];
uint32_t phy_timing_8996[40];
+ uint32_t phy_timing_12nm[8];
/* DSI_CLKOUT_TIMING_CTRL */
char t_clk_post;
char t_clk_pre;
@@ -616,15 +617,19 @@
struct mdss_dsi_ctrl_pdata *ctrl_pdata);
int mdss_dsi_pre_clkoff_cb(void *priv,
enum mdss_dsi_clk_type clk_type,
+ enum mdss_dsi_lclk_type l_type,
enum mdss_dsi_clk_state new_state);
int mdss_dsi_post_clkoff_cb(void *priv,
enum mdss_dsi_clk_type clk_type,
+ enum mdss_dsi_lclk_type l_type,
enum mdss_dsi_clk_state curr_state);
int mdss_dsi_post_clkon_cb(void *priv,
enum mdss_dsi_clk_type clk_type,
+ enum mdss_dsi_lclk_type l_type,
enum mdss_dsi_clk_state curr_state);
int mdss_dsi_pre_clkon_cb(void *priv,
enum mdss_dsi_clk_type clk_type,
+ enum mdss_dsi_lclk_type l_type,
enum mdss_dsi_clk_state new_state);
int mdss_dsi_panel_reset(struct mdss_panel_data *pdata, int enable);
void mdss_dsi_phy_disable(struct mdss_dsi_ctrl_pdata *ctrl);
diff --git a/drivers/video/fbdev/msm/mdss_dsi_clk.c b/drivers/video/fbdev/msm/mdss_dsi_clk.c
index 372c93e..779e847 100644
--- a/drivers/video/fbdev/msm/mdss_dsi_clk.c
+++ b/drivers/video/fbdev/msm/mdss_dsi_clk.c
@@ -27,11 +27,9 @@
};
struct dsi_link_clks {
- struct mdss_dsi_link_clk_info clks;
+ struct mdss_dsi_link_hs_clk_info hs_clks;
+ struct mdss_dsi_link_lp_clk_info lp_clks;
u32 current_clk_state;
- u32 byte_clk_rate;
- u32 pix_clk_rate;
- u32 esc_clk_rate;
};
struct mdss_dsi_clk_mngr {
@@ -73,28 +71,27 @@
rc = clk_prepare_enable(c_clks->clks.mdp_core_clk);
if (rc) {
- pr_err("%s: failed to enable mdp_core_clock. rc=%d\n",
- __func__, rc);
+ pr_err("failed to enable mdp_core_clock. rc=%d\n", rc);
goto error;
}
rc = clk_prepare_enable(c_clks->clks.ahb_clk);
if (rc) {
- pr_err("%s: failed to enable ahb clock. rc=%d\n", __func__, rc);
+ pr_err("failed to enable ahb clock. rc=%d\n", rc);
goto disable_core_clk;
}
rc = clk_prepare_enable(c_clks->clks.axi_clk);
if (rc) {
- pr_err("%s: failed to enable ahb clock. rc=%d\n", __func__, rc);
+ pr_err("failed to enable ahb clock. rc=%d\n", rc);
goto disable_ahb_clk;
}
if (c_clks->clks.mmss_misc_ahb_clk) {
rc = clk_prepare_enable(c_clks->clks.mmss_misc_ahb_clk);
if (rc) {
- pr_err("%s: failed to enable mmss misc ahb clk.rc=%d\n",
- __func__, rc);
+ pr_err("failed to enable mmss misc ahb clk.rc=%d\n",
+ rc);
goto disable_axi_clk;
}
}
@@ -140,12 +137,15 @@
return rc;
}
-static int dsi_link_clk_set_rate(struct dsi_link_clks *l_clks)
+static int dsi_link_hs_clk_set_rate(
+ struct mdss_dsi_link_hs_clk_info *link_hs_clks)
{
int rc = 0;
struct mdss_dsi_clk_mngr *mngr;
+ struct dsi_link_clks *l_clks;
struct mdss_dsi_ctrl_pdata *ctrl;
+ l_clks = container_of(link_hs_clks, struct dsi_link_clks, hs_clks);
mngr = container_of(l_clks, struct mdss_dsi_clk_mngr, link_clks);
/*
@@ -160,19 +160,13 @@
if (ctrl->panel_data.panel_info.cont_splash_enabled)
return 0;
- rc = clk_set_rate(l_clks->clks.esc_clk, l_clks->esc_clk_rate);
- if (rc) {
- pr_err("clk_set_rate failed for esc_clk rc = %d\n", rc);
- goto error;
- }
-
- rc = clk_set_rate(l_clks->clks.byte_clk, l_clks->byte_clk_rate);
+ rc = clk_set_rate(link_hs_clks->byte_clk, link_hs_clks->byte_clk_rate);
if (rc) {
pr_err("clk_set_rate failed for byte_clk rc = %d\n", rc);
goto error;
}
- rc = clk_set_rate(l_clks->clks.pixel_clk, l_clks->pix_clk_rate);
+ rc = clk_set_rate(link_hs_clks->pixel_clk, link_hs_clks->pix_clk_rate);
if (rc) {
pr_err("clk_set_rate failed for pixel_clk rc = %d\n", rc);
goto error;
@@ -182,141 +176,203 @@
return rc;
}
-static int dsi_link_clk_prepare(struct dsi_link_clks *l_clks)
+static int dsi_link_hs_clk_prepare(
+ struct mdss_dsi_link_hs_clk_info *link_hs_clks)
{
int rc = 0;
- rc = clk_prepare(l_clks->clks.esc_clk);
+ rc = clk_prepare(link_hs_clks->byte_clk);
if (rc) {
- pr_err("%s: Failed to prepare dsi esc clk\n", __func__);
- goto esc_clk_err;
- }
-
- rc = clk_prepare(l_clks->clks.byte_clk);
- if (rc) {
- pr_err("%s: Failed to prepare dsi byte clk\n", __func__);
+ pr_err("Failed to prepare dsi byte clk\n");
goto byte_clk_err;
}
- rc = clk_prepare(l_clks->clks.pixel_clk);
+ rc = clk_prepare(link_hs_clks->pixel_clk);
if (rc) {
- pr_err("%s: Failed to prepare dsi pixel clk\n", __func__);
+ pr_err("Failed to prepare dsi pixel_clk\n");
goto pixel_clk_err;
}
return rc;
pixel_clk_err:
- clk_unprepare(l_clks->clks.byte_clk);
+ clk_unprepare(link_hs_clks->byte_clk);
byte_clk_err:
- clk_unprepare(l_clks->clks.esc_clk);
-esc_clk_err:
return rc;
}
-static int dsi_link_clk_unprepare(struct dsi_link_clks *l_clks)
+static int dsi_link_hs_clk_unprepare(
+ struct mdss_dsi_link_hs_clk_info *link_hs_clks)
{
int rc = 0;
- clk_unprepare(l_clks->clks.pixel_clk);
- clk_unprepare(l_clks->clks.byte_clk);
- clk_unprepare(l_clks->clks.esc_clk);
+ clk_unprepare(link_hs_clks->pixel_clk);
+ clk_unprepare(link_hs_clks->byte_clk);
return rc;
}
-static int dsi_link_clk_enable(struct dsi_link_clks *l_clks)
+static int dsi_link_hs_clk_enable(
+ struct mdss_dsi_link_hs_clk_info *link_hs_clks)
{
int rc = 0;
- rc = clk_enable(l_clks->clks.esc_clk);
+ rc = clk_enable(link_hs_clks->byte_clk);
if (rc) {
- pr_err("%s: Failed to enable dsi esc clk\n", __func__);
- goto esc_clk_err;
- }
-
- rc = clk_enable(l_clks->clks.byte_clk);
- if (rc) {
- pr_err("%s: Failed to enable dsi byte clk\n", __func__);
+ pr_err("Failed to enable dsi byte clk\n");
goto byte_clk_err;
}
- rc = clk_enable(l_clks->clks.pixel_clk);
+ rc = clk_enable(link_hs_clks->pixel_clk);
if (rc) {
- pr_err("%s: Failed to enable dsi pixel clk\n", __func__);
+ pr_err("Failed to enable dsi pixel_clk\n");
goto pixel_clk_err;
}
return rc;
pixel_clk_err:
- clk_disable(l_clks->clks.byte_clk);
+ clk_disable(link_hs_clks->byte_clk);
byte_clk_err:
- clk_disable(l_clks->clks.esc_clk);
-esc_clk_err:
return rc;
}
-static int dsi_link_clk_disable(struct dsi_link_clks *l_clks)
+static int dsi_link_hs_clk_disable(
+ struct mdss_dsi_link_hs_clk_info *link_hs_clks)
{
int rc = 0;
- clk_disable(l_clks->clks.esc_clk);
- clk_disable(l_clks->clks.pixel_clk);
- clk_disable(l_clks->clks.byte_clk);
+ clk_disable(link_hs_clks->pixel_clk);
+ clk_disable(link_hs_clks->byte_clk);
return rc;
}
-static int dsi_link_clk_start(struct dsi_link_clks *l_clks)
+static int dsi_link_hs_clk_start(
+ struct mdss_dsi_link_hs_clk_info *link_hs_clks,
+ enum mdss_dsi_link_clk_op_type op_type)
{
int rc = 0;
+ struct dsi_link_clks *l_clks;
struct mdss_dsi_clk_mngr *mngr;
+ l_clks = container_of(link_hs_clks, struct dsi_link_clks, hs_clks);
mngr = container_of(l_clks, struct mdss_dsi_clk_mngr, link_clks);
- rc = dsi_link_clk_set_rate(l_clks);
- if (rc) {
- pr_err("failed to set clk rates, rc = %d\n", rc);
- goto error;
+ if (op_type & MDSS_DSI_LINK_CLK_SET_RATE) {
+ rc = dsi_link_hs_clk_set_rate(link_hs_clks);
+ if (rc) {
+ pr_err("failed to set HS clk rates, rc = %d\n", rc);
+ goto error;
+ }
}
- rc = dsi_link_clk_prepare(l_clks);
- if (rc) {
- pr_err("failed to prepare link clks, rc = %d\n", rc);
- goto error;
+ if (op_type & MDSS_DSI_LINK_CLK_PREPARE) {
+ rc = dsi_link_hs_clk_prepare(link_hs_clks);
+ if (rc) {
+ pr_err("failed to prepare link HS clks, rc = %d\n", rc);
+ goto error;
+ }
}
- rc = dsi_link_clk_enable(l_clks);
- if (rc) {
- pr_err("failed to enable link clks, rc = %d\n", rc);
- goto error_unprepare;
+ if (op_type & MDSS_DSI_LINK_CLK_ENABLE) {
+ rc = dsi_link_hs_clk_enable(link_hs_clks);
+ if (rc) {
+ pr_err("failed to enable link HS clks, rc = %d\n", rc);
+ goto error_unprepare;
+ }
}
- pr_debug("%s: LINK CLOCK IS ON\n", mngr->name);
+ pr_debug("%s: LINK HS CLOCK IS ON\n", mngr->name);
return rc;
error_unprepare:
- dsi_link_clk_unprepare(l_clks);
+ dsi_link_hs_clk_unprepare(link_hs_clks);
error:
return rc;
}
-static int dsi_link_clk_stop(struct dsi_link_clks *l_clks)
+static int dsi_link_lp_clk_start(
+ struct mdss_dsi_link_lp_clk_info *link_lp_clks)
{
int rc = 0;
struct mdss_dsi_clk_mngr *mngr;
+ struct dsi_link_clks *l_clks;
+ struct mdss_dsi_ctrl_pdata *ctrl;
+ l_clks = container_of(link_lp_clks, struct dsi_link_clks, lp_clks);
+ mngr = container_of(l_clks, struct mdss_dsi_clk_mngr, link_clks);
+ /*
+ * In an ideal world, cont_splash_enabled should not be required inside
+ * the clock manager. But, in the current driver cont_splash_enabled
+ * flag is set inside mdp driver and there is no interface event
+ * associated with this flag setting. Also, set rate for clock need not
+ * be called for every enable call. It should be done only once when
+ * coming out of suspend.
+ */
+ ctrl = mngr->priv_data;
+ if (ctrl->panel_data.panel_info.cont_splash_enabled)
+ goto prepare;
+
+ rc = clk_set_rate(link_lp_clks->esc_clk, link_lp_clks->esc_clk_rate);
+ if (rc) {
+ pr_err("clk_set_rate failed for esc_clk rc = %d\n", rc);
+ goto error;
+ }
+
+prepare:
+ rc = clk_prepare(link_lp_clks->esc_clk);
+ if (rc) {
+ pr_err("Failed to prepare dsi esc clk\n");
+ goto error;
+ }
+
+ rc = clk_enable(link_lp_clks->esc_clk);
+ if (rc) {
+ pr_err("Failed to enable dsi esc clk\n");
+ clk_unprepare(l_clks->lp_clks.esc_clk);
+ goto error;
+ }
+error:
+ pr_debug("%s: LINK LP CLOCK IS ON\n", mngr->name);
+ return rc;
+}
+
+static int dsi_link_hs_clk_stop(
+ struct mdss_dsi_link_hs_clk_info *link_hs_clks)
+{
+ int rc = 0;
+ struct dsi_link_clks *l_clks;
+ struct mdss_dsi_clk_mngr *mngr;
+
+ l_clks = container_of(link_hs_clks, struct dsi_link_clks, hs_clks);
mngr = container_of(l_clks, struct mdss_dsi_clk_mngr, link_clks);
- (void)dsi_link_clk_disable(l_clks);
+ (void)dsi_link_hs_clk_disable(link_hs_clks);
- (void)dsi_link_clk_unprepare(l_clks);
- pr_debug("%s: LINK CLOCK IS OFF\n", mngr->name);
+ (void)dsi_link_hs_clk_unprepare(link_hs_clks);
+ pr_debug("%s: LINK HS CLOCK IS OFF\n", mngr->name);
return rc;
}
+static int dsi_link_lp_clk_stop(
+ struct mdss_dsi_link_lp_clk_info *link_lp_clks)
+{
+ struct dsi_link_clks *l_clks;
+ struct mdss_dsi_clk_mngr *mngr;
+
+ l_clks = container_of(link_lp_clks, struct dsi_link_clks, lp_clks);
+ mngr = container_of(l_clks, struct mdss_dsi_clk_mngr, link_clks);
+
+ clk_disable(l_clks->lp_clks.esc_clk);
+ clk_unprepare(l_clks->lp_clks.esc_clk);
+
+ pr_debug("%s: LINK LP CLOCK IS OFF\n", mngr->name);
+ return 0;
+}
+
+
static int dsi_update_clk_state(struct dsi_core_clks *c_clks, u32 c_state,
struct dsi_link_clks *l_clks, u32 l_state)
{
@@ -347,8 +403,8 @@
if (c_clks && (c_state == MDSS_DSI_CLK_ON)) {
if (c_clks->current_clk_state == MDSS_DSI_CLK_OFF) {
rc = mngr->pre_clkon_cb(mngr->priv_data,
- MDSS_DSI_CORE_CLK,
- MDSS_DSI_CLK_ON);
+ MDSS_DSI_CORE_CLK, MDSS_DSI_LINK_NONE,
+ MDSS_DSI_CLK_ON);
if (rc) {
pr_err("failed to turn on MDP FS rc= %d\n", rc);
goto error;
@@ -362,8 +418,8 @@
if (mngr->post_clkon_cb) {
rc = mngr->post_clkon_cb(mngr->priv_data,
- MDSS_DSI_CORE_CLK,
- MDSS_DSI_CLK_ON);
+ MDSS_DSI_CORE_CLK, MDSS_DSI_LINK_NONE,
+ MDSS_DSI_CLK_ON);
if (rc)
pr_err("post clk on cb failed, rc = %d\n", rc);
}
@@ -375,21 +431,50 @@
if (l_state == MDSS_DSI_CLK_ON) {
if (mngr->pre_clkon_cb) {
rc = mngr->pre_clkon_cb(mngr->priv_data,
- MDSS_DSI_LINK_CLK, l_state);
+ MDSS_DSI_LINK_CLK, MDSS_DSI_LINK_LP_CLK,
+ l_state);
if (rc)
- pr_err("pre link clk on cb failed\n");
+ pr_err("pre link LP clk on cb failed\n");
}
- rc = dsi_link_clk_start(l_clks);
+ rc = dsi_link_lp_clk_start(&l_clks->lp_clks);
if (rc) {
- pr_err("failed to start link clk rc= %d\n", rc);
+ pr_err("failed to start LP link clk clk\n");
goto error;
}
if (mngr->post_clkon_cb) {
rc = mngr->post_clkon_cb(mngr->priv_data,
- MDSS_DSI_LINK_CLK,
- l_state);
+ MDSS_DSI_LINK_CLK, MDSS_DSI_LINK_LP_CLK,
+ l_state);
if (rc)
- pr_err("post link clk on cb failed\n");
+ pr_err("post LP clk on cb failed\n");
+ }
+
+ if (mngr->pre_clkon_cb) {
+ rc = mngr->pre_clkon_cb(mngr->priv_data,
+ MDSS_DSI_LINK_CLK, MDSS_DSI_LINK_HS_CLK,
+ l_state);
+ if (rc)
+ pr_err("pre HS clk on cb failed\n");
+ }
+ rc = dsi_link_hs_clk_start(&l_clks->hs_clks,
+ (MDSS_DSI_LINK_CLK_SET_RATE |
+ MDSS_DSI_LINK_CLK_PREPARE));
+ if (rc) {
+ pr_err("failed to prepare HS clk rc= %d\n", rc);
+ goto error;
+ }
+ if (mngr->post_clkon_cb) {
+ rc = mngr->post_clkon_cb(mngr->priv_data,
+ MDSS_DSI_LINK_CLK, MDSS_DSI_LINK_HS_CLK,
+ l_state);
+ if (rc)
+ pr_err("post HS clk on cb failed\n");
+ }
+ rc = dsi_link_hs_clk_start(&l_clks->hs_clks,
+ MDSS_DSI_LINK_CLK_ENABLE);
+ if (rc) {
+ pr_err("failed to enable HS clk rc= %d\n", rc);
+ goto error;
}
} else {
/*
@@ -418,9 +503,16 @@
goto error;
}
- rc = dsi_link_clk_start(l_clks);
+ rc = dsi_link_lp_clk_start(&l_clks->lp_clks);
if (rc) {
- pr_err("Link clks did not start\n");
+ pr_err("LP Link clks did not start\n");
+ goto error;
+ }
+
+ rc = dsi_link_hs_clk_start(&l_clks->hs_clks,
+ MDSS_DSI_LINK_CLK_START);
+ if (rc) {
+ pr_err("HS Link clks did not start\n");
goto error;
}
l_c_on = true;
@@ -429,24 +521,50 @@
if (mngr->pre_clkoff_cb) {
rc = mngr->pre_clkoff_cb(mngr->priv_data,
- MDSS_DSI_LINK_CLK, l_state);
+ MDSS_DSI_LINK_CLK, MDSS_DSI_LINK_HS_CLK,
+ l_state);
if (rc)
- pr_err("pre link clk off cb failed\n");
+ pr_err("pre HS clk off cb failed\n");
}
- rc = dsi_link_clk_stop(l_clks);
+ rc = dsi_link_hs_clk_stop(&l_clks->hs_clks);
if (rc) {
- pr_err("failed to stop link clk, rc = %d\n",
+ pr_err("failed to stop HS clk, rc = %d\n",
rc);
goto error;
}
if (mngr->post_clkoff_cb) {
rc = mngr->post_clkoff_cb(mngr->priv_data,
- MDSS_DSI_LINK_CLK, l_state);
+ MDSS_DSI_LINK_CLK, MDSS_DSI_LINK_HS_CLK,
+ l_state);
if (rc)
- pr_err("post link clk off cb failed\n");
+ pr_err("post HS clk off cb failed\n");
}
+
+ if (mngr->pre_clkoff_cb) {
+ rc = mngr->pre_clkoff_cb(mngr->priv_data,
+ MDSS_DSI_LINK_CLK, MDSS_DSI_LINK_LP_CLK,
+ l_state);
+ if (rc)
+ pr_err("pre LP clk off cb failed\n");
+ }
+
+ rc = dsi_link_lp_clk_stop(&l_clks->lp_clks);
+ if (rc) {
+ pr_err("failed to stop LP link clk, rc = %d\n",
+ rc);
+ goto error;
+ }
+
+ if (mngr->post_clkoff_cb) {
+ rc = mngr->post_clkoff_cb(mngr->priv_data,
+ MDSS_DSI_LINK_CLK, MDSS_DSI_LINK_LP_CLK,
+ l_state);
+ if (rc)
+ pr_err("post LP clk off cb failed\n");
+ }
+
/*
* This check is to save unnecessary clock state
* change when going from EARLY_GATE to OFF. In the
@@ -502,8 +620,8 @@
if (mngr->pre_clkoff_cb) {
rc = mngr->pre_clkoff_cb(mngr->priv_data,
- MDSS_DSI_CORE_CLK,
- c_state);
+ MDSS_DSI_CORE_CLK, MDSS_DSI_LINK_NONE,
+ c_state);
if (rc)
pr_err("pre core clk off cb failed\n");
}
@@ -517,7 +635,7 @@
if (c_state == MDSS_DSI_CLK_OFF) {
if (mngr->post_clkoff_cb) {
rc = mngr->post_clkoff_cb(mngr->priv_data,
- MDSS_DSI_CORE_CLK,
+ MDSS_DSI_CORE_CLK, MDSS_DSI_LINK_NONE,
MDSS_DSI_CLK_OFF);
if (rc)
pr_err("post clkoff cb fail, rc = %d\n",
@@ -610,27 +728,30 @@
MDSS_XLOG(clk, rate, flags);
switch (clk) {
case MDSS_DSI_LINK_ESC_CLK:
- mngr->link_clks.esc_clk_rate = rate;
+ mngr->link_clks.lp_clks.esc_clk_rate = rate;
if (!flags) {
- rc = clk_set_rate(mngr->link_clks.clks.esc_clk, rate);
+ rc = clk_set_rate(mngr->link_clks.lp_clks.esc_clk,
+ rate);
if (rc)
pr_err("set rate failed for esc clk rc=%d\n",
rc);
}
break;
case MDSS_DSI_LINK_BYTE_CLK:
- mngr->link_clks.byte_clk_rate = rate;
+ mngr->link_clks.hs_clks.byte_clk_rate = rate;
if (!flags) {
- rc = clk_set_rate(mngr->link_clks.clks.byte_clk, rate);
+ rc = clk_set_rate(mngr->link_clks.hs_clks.byte_clk,
+ rate);
if (rc)
pr_err("set rate failed for byte clk rc=%d\n",
rc);
}
break;
case MDSS_DSI_LINK_PIX_CLK:
- mngr->link_clks.pix_clk_rate = rate;
+ mngr->link_clks.hs_clks.pix_clk_rate = rate;
if (!flags) {
- rc = clk_set_rate(mngr->link_clks.clks.pixel_clk, rate);
+ rc = clk_set_rate(mngr->link_clks.hs_clks.pixel_clk,
+ rate);
if (rc)
pr_err("failed to set rate for pix clk rc=%d\n",
rc);
@@ -888,8 +1009,10 @@
mutex_init(&mngr->clk_mutex);
memcpy(&mngr->core_clks.clks, &info->core_clks, sizeof(struct
mdss_dsi_core_clk_info));
- memcpy(&mngr->link_clks.clks, &info->link_clks, sizeof(struct
- mdss_dsi_link_clk_info));
+ memcpy(&mngr->link_clks.hs_clks, &info->link_hs_clks, sizeof(struct
+ mdss_dsi_link_hs_clk_info));
+ memcpy(&mngr->link_clks.lp_clks, &info->link_lp_clks, sizeof(struct
+ mdss_dsi_link_lp_clk_info));
INIT_LIST_HEAD(&mngr->client_list);
mngr->pre_clkon_cb = info->pre_clkon_cb;
@@ -981,15 +1104,26 @@
if ((clk & MDSS_DSI_LINK_CLK) &&
(mngr->link_clks.current_clk_state == MDSS_DSI_CLK_ON)) {
- rc = dsi_link_clk_stop(&mngr->link_clks);
+ rc = dsi_link_hs_clk_stop(&mngr->link_clks.hs_clks);
if (rc) {
- pr_err("failed to stop link clks\n");
+ pr_err("failed to stop HS link clks\n");
goto error;
}
- rc = dsi_link_clk_start(&mngr->link_clks);
+ rc = dsi_link_lp_clk_stop(&mngr->link_clks.lp_clks);
+ if (rc) {
+ pr_err("failed to stop LP link clks\n");
+ goto error;
+ }
+
+ rc = dsi_link_lp_clk_start(&mngr->link_clks.lp_clks);
if (rc)
- pr_err("failed to start link clks\n");
+ pr_err("failed to start LP link clks\n");
+
+ rc = dsi_link_hs_clk_start(&mngr->link_clks.hs_clks,
+ MDSS_DSI_LINK_CLK_START);
+ if (rc)
+ pr_err("failed to start HS link clks\n");
} else if (clk & MDSS_DSI_LINK_CLK) {
pr_err("cannot reset, link clock is off\n");
diff --git a/drivers/video/fbdev/msm/mdss_dsi_clk.h b/drivers/video/fbdev/msm/mdss_dsi_clk.h
index 837f2f6..5f000f9 100644
--- a/drivers/video/fbdev/msm/mdss_dsi_clk.h
+++ b/drivers/video/fbdev/msm/mdss_dsi_clk.h
@@ -39,6 +39,13 @@
MDSS_DSI_LINK_CLK_MAX,
};
+enum mdss_dsi_link_clk_op_type {
+ MDSS_DSI_LINK_CLK_SET_RATE = BIT(0),
+ MDSS_DSI_LINK_CLK_PREPARE = BIT(1),
+ MDSS_DSI_LINK_CLK_ENABLE = BIT(2),
+ MDSS_DSI_LINK_CLK_START = BIT(0) | BIT(1) | BIT(2),
+};
+
enum mdss_dsi_clk_type {
MDSS_DSI_CORE_CLK = BIT(0),
MDSS_DSI_LINK_CLK = BIT(1),
@@ -46,53 +53,67 @@
MDSS_DSI_CLKS_MAX = BIT(2),
};
+enum mdss_dsi_lclk_type {
+ MDSS_DSI_LINK_NONE = 0,
+ MDSS_DSI_LINK_LP_CLK = BIT(0),
+ MDSS_DSI_LINK_HS_CLK = BIT(1),
+};
+
/**
* typedef *pre_clockoff_cb() - Callback before clock is turned off
* @priv: private data pointer.
* @clk_type: clock which is being turned off.
+ * @l_type: specifies if the clock is HS or LP type. Valid only for link clocks.
* @new_state: next state for the clock.
*
* @return: error code.
*/
typedef int (*pre_clockoff_cb)(void *priv,
- enum mdss_dsi_clk_type clk_type,
- enum mdss_dsi_clk_state new_state);
+ enum mdss_dsi_clk_type clk_type,
+ enum mdss_dsi_lclk_type l_type,
+ enum mdss_dsi_clk_state new_state);
/**
* typedef *post_clockoff_cb() - Callback after clock is turned off
* @priv: private data pointer.
* @clk_type: clock which was turned off.
+ * @l_type: specifies if the clock is HS or LP type. Valid only for link clocks.
* @curr_state: current state for the clock.
*
* @return: error code.
*/
typedef int (*post_clockoff_cb)(void *priv,
enum mdss_dsi_clk_type clk_type,
+ enum mdss_dsi_lclk_type l_type,
enum mdss_dsi_clk_state curr_state);
/**
* typedef *post_clockon_cb() - Callback after clock is turned on
* @priv: private data pointer.
* @clk_type: clock which was turned on.
+ * @l_type: specifies if the clock is HS or LP type. Valid only for link clocks.
* @curr_state: current state for the clock.
*
* @return: error code.
*/
typedef int (*post_clockon_cb)(void *priv,
- enum mdss_dsi_clk_type clk_type,
- enum mdss_dsi_clk_state curr_state);
+ enum mdss_dsi_clk_type clk_type,
+ enum mdss_dsi_lclk_type l_type,
+ enum mdss_dsi_clk_state curr_state);
/**
* typedef *pre_clockon_cb() - Callback before clock is turned on
* @priv: private data pointer.
* @clk_type: clock which is being turned on.
+ * @l_type: specifies if the clock is HS or LP type. Valid only for link clocks.
* @new_state: next state for the clock.
*
* @return: error code.
*/
typedef int (*pre_clockon_cb)(void *priv,
- enum mdss_dsi_clk_type clk_type,
- enum mdss_dsi_clk_state new_state);
+ enum mdss_dsi_clk_type clk_type,
+ enum mdss_dsi_lclk_type l_type,
+ enum mdss_dsi_clk_state new_state);
struct mdss_dsi_core_clk_info {
struct clk *mdp_core_clk;
@@ -101,10 +122,16 @@
struct clk *mmss_misc_ahb_clk;
};
-struct mdss_dsi_link_clk_info {
- struct clk *esc_clk;
+struct mdss_dsi_link_hs_clk_info {
struct clk *byte_clk;
struct clk *pixel_clk;
+ u32 byte_clk_rate;
+ u32 pix_clk_rate;
+};
+
+struct mdss_dsi_link_lp_clk_info {
+ struct clk *esc_clk;
+ u32 esc_clk_rate;
};
struct dsi_panel_clk_ctrl {
@@ -126,7 +153,8 @@
struct mdss_dsi_clk_info {
char name[DSI_CLK_NAME_LEN];
struct mdss_dsi_core_clk_info core_clks;
- struct mdss_dsi_link_clk_info link_clks;
+ struct mdss_dsi_link_hs_clk_info link_hs_clks;
+ struct mdss_dsi_link_lp_clk_info link_lp_clks;
pre_clockoff_cb pre_clkoff_cb;
post_clockoff_cb post_clkoff_cb;
post_clockon_cb post_clkon_cb;
diff --git a/drivers/video/fbdev/msm/mdss_dsi_host.c b/drivers/video/fbdev/msm/mdss_dsi_host.c
index 988c7a9..d76be70 100644
--- a/drivers/video/fbdev/msm/mdss_dsi_host.c
+++ b/drivers/video/fbdev/msm/mdss_dsi_host.c
@@ -303,6 +303,20 @@
*/
reg_val = MIPI_INP(ctrl->phy_io.base + 0x20c);
reg_val = reg_val >> 4;
+ if (!reg_val) {
+ /*
+ * DSI_0_PHY_DSIPHY_REVISION_ID3 for 12nm PHY
+ * reset value = 0x20
+ * 7:4 Major
+ * 3:0 Minor
+ */
+ reg_val = MIPI_INP(ctrl->phy_io.base + 0x3dc);
+ reg_val = reg_val >> 4;
+ if (reg_val == 0x2) {
+ ctrl->shared_data->phy_rev = DSI_PHY_REV_12NM;
+ return;
+ }
+ }
}
if (reg_val == DSI_PHY_REV_20)
@@ -413,6 +427,9 @@
/* DSI_LAN_SWAP_CTRL */
MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x00b0, ctrl_pdata->dlane_swap);
+ if (ctrl_pdata->shared_data->phy_rev == DSI_PHY_REV_12NM)
+ goto next;
+
/* clock out ctrl */
data = pinfo->t_clk_post & 0x3f; /* 6 bits */
data <<= 8;
@@ -420,6 +437,7 @@
/* DSI_CLKOUT_TIMING_CTRL */
MIPI_OUTP((ctrl_pdata->ctrl_base) + 0xc4, data);
+next:
data = 0;
if (pinfo->rx_eot_ignore)
data |= BIT(4);
diff --git a/drivers/video/fbdev/msm/mdss_dsi_panel.c b/drivers/video/fbdev/msm/mdss_dsi_panel.c
index 1cbaa44..2ef1695 100644
--- a/drivers/video/fbdev/msm/mdss_dsi_panel.c
+++ b/drivers/video/fbdev/msm/mdss_dsi_panel.c
@@ -2309,6 +2309,9 @@
for (i = 0; i < ARRAY_SIZE(pt->phy_timing_8996); i++)
pinfo->mipi.dsi_phy_db.timing_8996[i] = pt->phy_timing_8996[i];
+ for (i = 0; i < ARRAY_SIZE(pt->phy_timing_12nm); i++)
+ pinfo->mipi.dsi_phy_db.timing_12nm[i] = pt->phy_timing_12nm[i];
+
ctrl->on_cmds = pt->on_cmds;
ctrl->post_panel_on_cmds = pt->post_panel_on_cmds;
@@ -2421,6 +2424,18 @@
pt->phy_timing_8996[i] = data[i];
phy_timings_present = true;
}
+
+ data = of_get_property(np,
+ "qcom,mdss-dsi-panel-timings-phy-12nm", &len);
+ if ((!data) || (len != 8)) {
+ pr_debug("%s:%d, Unable to read 12nm Phy lane timing settings",
+ __func__, __LINE__);
+ } else {
+ for (i = 0; i < len; i++)
+ pt->phy_timing_12nm[i] = data[i];
+ phy_timings_present = true;
+ }
+
if (!phy_timings_present) {
pr_err("%s: phy timing settings not present\n", __func__);
return -EINVAL;
diff --git a/drivers/video/fbdev/msm/mdss_dsi_phy.h b/drivers/video/fbdev/msm/mdss_dsi_phy.h
index aea42e8..108e26e 100644
--- a/drivers/video/fbdev/msm/mdss_dsi_phy.h
+++ b/drivers/video/fbdev/msm/mdss_dsi_phy.h
@@ -16,11 +16,13 @@
#include <linux/types.h>
#include "mdss_panel.h"
+#include "mdss_dsi.h"
enum phy_rev {
DSI_PHY_REV_UNKNOWN = 0x00,
DSI_PHY_REV_10 = 0x01, /* REV 1.0 - 20nm, 28nm */
DSI_PHY_REV_20 = 0x02, /* REV 2.0 - 14nm */
+ DSI_PHY_REV_12NM = 0x03, /* 12nm PHY */
DSI_PHY_REV_MAX,
};
@@ -36,4 +38,53 @@
int mdss_dsi_phy_calc_timing_param(struct mdss_panel_info *pinfo, u32 phy_rev,
u32 frate_hz);
+/*
+ * mdss_dsi_12nm_phy_regulator_enable() - enable lane reg for DSI 12nm PHY
+ *
+ * @ctrl: pointer to DSI controller structure
+ */
+int mdss_dsi_12nm_phy_regulator_enable(struct mdss_dsi_ctrl_pdata *ctrl);
+
+/*
+ * mdss_dsi_12nm_phy_regulator_disable() - disable lane reg for DSI 12nm PHY
+ *
+ * @ctrl: pointer to DSI controller structure
+ */
+int mdss_dsi_12nm_phy_regulator_disable(struct mdss_dsi_ctrl_pdata *ctrl);
+
+/*
+ * mdss_dsi_12nm_phy_config() - initialization sequence for DSI 12nm PHY
+ *
+ * @ctrl: pointer to DSI controller structure
+ *
+ * This function performs a sequence of register writes to initialize DSI
+ * 12nm phy. This function assumes that the DSI bus clocks are turned on.
+ * This function should only be called prior to enabling the DSI link clocks.
+ */
+int mdss_dsi_12nm_phy_config(struct mdss_dsi_ctrl_pdata *ctrl);
+
+/*
+ * mdss_dsi_12nm_phy_shutdown() - shutdown sequence for DSI 12nm PHY
+ *
+ * @ctrl: pointer to DSI controller structure
+ *
+ * Perform a sequence of register writes to completely shut down DSI 12nm PHY.
+ * This function assumes that the DSI bus clocks are turned on.
+ */
+int mdss_dsi_12nm_phy_shutdown(struct mdss_dsi_ctrl_pdata *ctrl);
+
+/*
+ * mdss_dsi_12nm_phy_hstx_drv_ctrl() - enable/disable HSTX drivers
+ *
+ * @ctrl: pointer to DSI controller structure
+ * @enable: boolean to specify enable/disable the HSTX drivers
+ *
+ * Perform a sequence of register writes to enable/disable HSTX drivers.
+ * This function assumes that the DSI bus clocks are turned on.
+ */
+
+void mdss_dsi_12nm_phy_hstx_drv_ctrl(
+ struct mdss_dsi_ctrl_pdata *ctrl, bool enable);
+
+
#endif /* MDSS_DSI_PHY_H */
diff --git a/drivers/video/fbdev/msm/mdss_dsi_phy_12nm.c b/drivers/video/fbdev/msm/mdss_dsi_phy_12nm.c
new file mode 100644
index 0000000..7b9a536
--- /dev/null
+++ b/drivers/video/fbdev/msm/mdss_dsi_phy_12nm.c
@@ -0,0 +1,124 @@
+/* Copyright (c) 2018, 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.
+ *
+ */
+
+#include <linux/iopoll.h>
+#include "mdss_dsi_phy.h"
+
+#define T_TA_GO_TIM_COUNT 0x014
+#define T_TA_SURE_TIM_COUNT 0x018
+#define HSTX_DRIV_INDATA_CTRL_CLKLANE 0x0c0
+#define HSTX_DATAREV_CTRL_CLKLANE 0x0d4
+#define HSTX_DRIV_INDATA_CTRL_LANE0 0x100
+#define HSTX_READY_DLY_DATA_REV_CTRL_LANE0 0x114
+#define HSTX_DRIV_INDATA_CTRL_LANE1 0x140
+#define HSTX_READY_DLY_DATA_REV_CTRL_LANE1 0x154
+#define HSTX_CLKLANE_REQSTATE_TIM_CTRL 0x180
+#define HSTX_CLKLANE_HS0STATE_TIM_CTRL 0x188
+#define HSTX_CLKLANE_TRALSTATE_TIM_CTRL 0x18c
+#define HSTX_CLKLANE_CLKPOSTSTATE_TIM_CTRL 0x194
+#define HSTX_DATALANE_REQSTATE_TIM_CTRL 0x1c0
+#define HSTX_DATALANE_HS0STATE_TIM_CTRL 0x1c8
+#define HSTX_DATALANE_TRAILSTATE_TIM_CTRL 0x1cc
+#define HSTX_DATALANE_EXITSTATE_TIM_CTRL 0x1d0
+#define HSTX_DRIV_INDATA_CTRL_LANE2 0x200
+#define HSTX_READY_DLY_DATA_REV_CTRL_LANE2 0x214
+#define HSTX_READY_DLY_DATA_REV_CTRL_LANE3 0x254
+#define HSTX_DRIV_INDATA_CTRL_LANE3 0x240
+#define CTRL0 0x3e8
+#define SYS_CTRL 0x3f0
+#define REQ_DLY 0x3fc
+
+#define DSI_PHY_W32(b, off, val) MIPI_OUTP((b) + (off), (val))
+#define DSI_PHY_R32(b, off) MIPI_INP((b) + (off))
+
+int mdss_dsi_12nm_phy_regulator_enable(struct mdss_dsi_ctrl_pdata *ctrl)
+{
+ /* Nothing to be done for 12nm PHY */
+ return 0;
+}
+
+int mdss_dsi_12nm_phy_regulator_disable(struct mdss_dsi_ctrl_pdata *ctrl)
+{
+ /* Nothing to be done for 12nm PHY */
+ return 0;
+}
+
+int mdss_dsi_12nm_phy_config(struct mdss_dsi_ctrl_pdata *ctrl)
+{
+ struct mdss_dsi_phy_ctrl *pd =
+ &(((ctrl->panel_data).panel_info.mipi).dsi_phy_db);
+
+ /* CTRL0: CFG_CLK_EN */
+ DSI_PHY_W32(ctrl->phy_io.base, CTRL0, BIT(0));
+
+ /* DSI PHY clock lane timings */
+ DSI_PHY_W32(ctrl->phy_io.base, HSTX_CLKLANE_HS0STATE_TIM_CTRL,
+ (pd->timing_12nm[0] | BIT(7)));
+ DSI_PHY_W32(ctrl->phy_io.base, HSTX_CLKLANE_TRALSTATE_TIM_CTRL,
+ (pd->timing_12nm[1] | BIT(6)));
+ DSI_PHY_W32(ctrl->phy_io.base, HSTX_CLKLANE_CLKPOSTSTATE_TIM_CTRL,
+ (pd->timing_12nm[2] | BIT(6)));
+ DSI_PHY_W32(ctrl->phy_io.base, HSTX_CLKLANE_REQSTATE_TIM_CTRL,
+ pd->timing_12nm[3]);
+
+ /* DSI PHY data lane timings */
+ DSI_PHY_W32(ctrl->phy_io.base, HSTX_DATALANE_HS0STATE_TIM_CTRL,
+ (pd->timing_12nm[4] | BIT(7)));
+ DSI_PHY_W32(ctrl->phy_io.base, HSTX_DATALANE_TRAILSTATE_TIM_CTRL,
+ (pd->timing_12nm[5] | BIT(6)));
+ DSI_PHY_W32(ctrl->phy_io.base, HSTX_DATALANE_REQSTATE_TIM_CTRL,
+ pd->timing_12nm[6]);
+ DSI_PHY_W32(ctrl->phy_io.base, HSTX_DATALANE_EXITSTATE_TIM_CTRL,
+ (pd->timing_12nm[7] | BIT(6) | BIT(7)));
+
+ DSI_PHY_W32(ctrl->phy_io.base, T_TA_GO_TIM_COUNT, 0x03);
+ DSI_PHY_W32(ctrl->phy_io.base, T_TA_SURE_TIM_COUNT, 0x01);
+ DSI_PHY_W32(ctrl->phy_io.base, REQ_DLY, 0x85);
+
+ /* DSI lane control registers */
+ DSI_PHY_W32(ctrl->phy_io.base,
+ HSTX_READY_DLY_DATA_REV_CTRL_LANE0, 0x00);
+ DSI_PHY_W32(ctrl->phy_io.base,
+ HSTX_READY_DLY_DATA_REV_CTRL_LANE1, 0x00);
+ DSI_PHY_W32(ctrl->phy_io.base,
+ HSTX_READY_DLY_DATA_REV_CTRL_LANE2, 0x00);
+ DSI_PHY_W32(ctrl->phy_io.base,
+ HSTX_READY_DLY_DATA_REV_CTRL_LANE3, 0x00);
+ DSI_PHY_W32(ctrl->phy_io.base, HSTX_DATAREV_CTRL_CLKLANE, 0x00);
+ wmb(); /* make sure DSI PHY registers are programmed */
+
+ return 0;
+}
+
+int mdss_dsi_12nm_phy_shutdown(struct mdss_dsi_ctrl_pdata *ctrl)
+{
+ DSI_PHY_W32(ctrl->phy_io.base, SYS_CTRL, BIT(0) | BIT(3));
+ wmb(); /* make sure DSI PHY is disabled */
+ return 0;
+}
+
+void mdss_dsi_12nm_phy_hstx_drv_ctrl(
+ struct mdss_dsi_ctrl_pdata *ctrl, bool enable)
+{
+ u32 data = 0;
+
+ if (enable)
+ data = BIT(2) | BIT(3);
+
+ DSI_PHY_W32(ctrl->phy_io.base, HSTX_DRIV_INDATA_CTRL_CLKLANE, data);
+ DSI_PHY_W32(ctrl->phy_io.base, HSTX_DRIV_INDATA_CTRL_LANE0, data);
+ DSI_PHY_W32(ctrl->phy_io.base, HSTX_DRIV_INDATA_CTRL_LANE1, data);
+ DSI_PHY_W32(ctrl->phy_io.base, HSTX_DRIV_INDATA_CTRL_LANE2, data);
+ DSI_PHY_W32(ctrl->phy_io.base, HSTX_DRIV_INDATA_CTRL_LANE3, data);
+ wmb(); /* make sure DSI PHY registers are programmed */
+}
diff --git a/drivers/video/fbdev/msm/mdss_panel.h b/drivers/video/fbdev/msm/mdss_panel.h
index 53db752..a3f9349 100644
--- a/drivers/video/fbdev/msm/mdss_panel.h
+++ b/drivers/video/fbdev/msm/mdss_panel.h
@@ -308,6 +308,7 @@
bool reg_ldo_mode;
char timing_8996[40];/* 8996, 8 * 5 */
+ char timing_12nm[14]; /* 12nm PHY */
char regulator_len;
char strength_len;
char lanecfg_len;
diff --git a/drivers/video/fbdev/msm/msm_mdss_io_8974.c b/drivers/video/fbdev/msm/msm_mdss_io_8974.c
index ec1ee60..f0e46f7 100644
--- a/drivers/video/fbdev/msm/msm_mdss_io_8974.c
+++ b/drivers/video/fbdev/msm/msm_mdss_io_8974.c
@@ -519,7 +519,8 @@
* is only done from the clock master. This will ensure that the PLL is
* off when PHY reset is called.
*/
- if (mdss_dsi_is_ctrl_clk_slave(ctrl))
+ if (mdss_dsi_is_ctrl_clk_slave(ctrl) ||
+ (ctrl->shared_data->phy_rev == DSI_PHY_REV_12NM))
return;
mdss_dsi_phy_sw_reset_sub(ctrl);
@@ -561,6 +562,9 @@
if (ctrl->shared_data->phy_rev == DSI_PHY_REV_20)
return;
+ if (ctrl->shared_data->phy_rev == DSI_PHY_REV_12NM)
+ return;
+
MIPI_OUTP(ctrl->phy_regulator_io.base + 0x018, 0x000);
}
@@ -575,6 +579,8 @@
MIPI_OUTP(ctrl->phy_io.base + DSIPHY_PLL_CLKBUFLR_EN, 0);
MIPI_OUTP(ctrl->phy_io.base + DSIPHY_CMN_GLBL_TEST_CTRL, 0);
MIPI_OUTP(ctrl->phy_io.base + DSIPHY_CMN_CTRL_0, 0);
+ } else if (ctrl->shared_data->phy_rev == DSI_PHY_REV_12NM) {
+ mdss_dsi_12nm_phy_shutdown(ctrl);
} else {
MIPI_OUTP(ctrl->phy_io.base + MDSS_DSI_DSIPHY_CTRL_0, 0x000);
}
@@ -596,7 +602,8 @@
return;
}
- if (ctrl->shared_data->phy_rev == DSI_PHY_REV_20)
+ if ((ctrl->shared_data->phy_rev == DSI_PHY_REV_20) ||
+ (ctrl->shared_data->phy_rev == DSI_PHY_REV_12NM))
return;
pd = &(((ctrl->panel_data).panel_info.mipi).dsi_phy_db);
@@ -1144,6 +1151,8 @@
if (enable) {
if (ctrl->shared_data->phy_rev == DSI_PHY_REV_20) {
mdss_dsi_8996_phy_regulator_enable(ctrl);
+ } else if (ctrl->shared_data->phy_rev == DSI_PHY_REV_12NM) {
+ mdss_dsi_12nm_phy_regulator_enable(ctrl);
} else {
switch (ctrl->shared_data->hw_rev) {
case MDSS_DSI_HW_REV_103:
@@ -1194,6 +1203,8 @@
if (ctrl->shared_data->phy_rev == DSI_PHY_REV_20) {
mdss_dsi_8996_phy_config(ctrl);
+ } else if (ctrl->shared_data->phy_rev == DSI_PHY_REV_12NM) {
+ mdss_dsi_12nm_phy_config(ctrl);
} else {
switch (ctrl->shared_data->hw_rev) {
case MDSS_DSI_HW_REV_103:
@@ -1269,6 +1280,13 @@
}
}
+static void mdss_dsi_phy_hstx_drv_ctrl(
+ struct mdss_dsi_ctrl_pdata *ctrl, bool enable)
+{
+ if (ctrl->shared_data->phy_rev == DSI_PHY_REV_12NM)
+ mdss_dsi_12nm_phy_hstx_drv_ctrl(ctrl, enable);
+}
+
void mdss_dsi_core_clk_deinit(struct device *dev, struct dsi_shared_data *sdata)
{
if (sdata->mmss_misc_ahb_clk)
@@ -1688,7 +1706,7 @@
}
static bool mdss_dsi_is_ulps_req_valid(struct mdss_dsi_ctrl_pdata *ctrl,
- int enable)
+ int enable, bool reconfig)
{
struct mdss_dsi_ctrl_pdata *octrl = NULL;
struct mdss_panel_data *pdata = &ctrl->panel_data;
@@ -1719,11 +1737,11 @@
* However, this should be allowed in following usecases:
* 1. If ULPS during suspend feature is enabled, where we
* configure the lanes in ULPS after turning off the panel.
- * 2. When coming out of idle PC with clamps enabled, where we
- * transition the controller HW state back to ULPS prior to
+ * 2. When coming out of idle PC with ULPS enabled, where we need to
+ * reconfigure the controller HW state again to ULPS prior to
* disabling ULPS.
*/
- if (enable && !ctrl->mmss_clamp &&
+ if (enable && !reconfig &&
!(ctrl->ctrl_state & CTRL_STATE_PANEL_INIT) &&
!pdata->panel_info.ulps_suspend_enabled) {
pr_debug("%s: panel not yet initialized\n", __func__);
@@ -1752,13 +1770,14 @@
* mdss_dsi_ulps_config() - Program DSI lanes to enter/exit ULPS mode
* @ctrl: pointer to DSI controller structure
* @enable: 1 to enter ULPS, 0 to exit ULPS
+ * @reconfig: boolean to specify if DSI controller is reconfigured to enter ULPS
*
* This function executes the necessary programming sequence to enter/exit
* DSI Ultra-Low Power State (ULPS). This function assumes that the link and
* core clocks are already on.
*/
static int mdss_dsi_ulps_config(struct mdss_dsi_ctrl_pdata *ctrl,
- int enable)
+ int enable, bool reconfig)
{
int ret = 0;
struct mdss_panel_data *pdata = NULL;
@@ -1780,7 +1799,7 @@
pinfo = &pdata->panel_info;
mipi = &pinfo->mipi;
- if (!mdss_dsi_is_ulps_req_valid(ctrl, enable)) {
+ if (!mdss_dsi_is_ulps_req_valid(ctrl, enable, reconfig)) {
pr_debug("%s: skiping ULPS config for ctrl%d, enable=%d\n",
__func__, ctrl->ndx, enable);
return 0;
@@ -1801,9 +1820,9 @@
if (mipi->data_lane3)
active_lanes |= BIT(3);
- pr_debug("%s: configuring ulps (%s) for ctrl%d, active lanes=0x%08x,clamps=%s\n",
+ pr_debug("%s: configuring ulps (%s) for ctrl%d, active lanes=0x%08x,reconfig=%s\n",
__func__, (enable ? "on" : "off"), ctrl->ndx,
- active_lanes, ctrl->mmss_clamp ? "enabled" : "disabled");
+ active_lanes, reconfig ? "true" : "false");
if (enable && !ctrl->ulps) {
/*
@@ -1816,7 +1835,7 @@
* power collapse and just restoring the controller state to
* ULPS with the clamps still in place.
*/
- if (!ctrl->mmss_clamp) {
+ if (!reconfig) {
ret = mdss_dsi_wait_for_lane_idle(ctrl);
if (ret) {
pr_warn("%s: lanes not idle, skip ulps\n",
@@ -2165,6 +2184,7 @@
int mdss_dsi_pre_clkoff_cb(void *priv,
enum mdss_dsi_clk_type clk,
+ enum mdss_dsi_lclk_type l_type,
enum mdss_dsi_clk_state new_state)
{
int rc = 0;
@@ -2173,7 +2193,14 @@
pdata = &ctrl->panel_data;
- if ((clk & MDSS_DSI_LINK_CLK) && (new_state == MDSS_DSI_CLK_OFF)) {
+ if ((clk & MDSS_DSI_LINK_CLK) && (l_type == MDSS_DSI_LINK_HS_CLK) &&
+ (new_state == MDSS_DSI_CLK_OFF)) {
+ /* Disable HS TX driver in DSI PHY if applicable */
+ mdss_dsi_phy_hstx_drv_ctrl(ctrl, false);
+ }
+
+ if ((clk & MDSS_DSI_LINK_CLK) && (l_type == MDSS_DSI_LINK_LP_CLK) &&
+ (new_state == MDSS_DSI_CLK_OFF)) {
/*
* If ULPS feature is enabled, enter ULPS first.
* However, when blanking the panel, we should enter ULPS
@@ -2181,9 +2208,9 @@
*/
if (!(ctrl->ctrl_state & CTRL_STATE_PANEL_INIT)) {
if (pdata->panel_info.ulps_suspend_enabled)
- mdss_dsi_ulps_config(ctrl, 1);
+ mdss_dsi_ulps_config(ctrl, 1, false);
} else if (mdss_dsi_ulps_feature_enabled(pdata)) {
- rc = mdss_dsi_ulps_config(ctrl, 1);
+ rc = mdss_dsi_ulps_config(ctrl, 1, false);
}
if (rc) {
pr_err("%s: failed enable ulps, rc = %d\n",
@@ -2208,7 +2235,7 @@
* Make sure that controller is not in ULPS state when
* the DSI link is not active.
*/
- rc = mdss_dsi_ulps_config(ctrl, 0);
+ rc = mdss_dsi_ulps_config(ctrl, 0, false);
if (rc)
pr_err("%s: failed to disable ulps. rc=%d\n",
__func__, rc);
@@ -2220,6 +2247,7 @@
int mdss_dsi_post_clkon_cb(void *priv,
enum mdss_dsi_clk_type clk,
+ enum mdss_dsi_lclk_type l_type,
enum mdss_dsi_clk_state curr_state)
{
int rc = 0;
@@ -2238,6 +2266,21 @@
if (mmss_clamp)
mdss_dsi_ctrl_setup(ctrl);
+ rc = mdss_dsi_clamp_ctrl(ctrl, 0);
+ if (rc) {
+ pr_err("%s: Failed to disable dsi clamps. rc=%d\n",
+ __func__, rc);
+ goto error;
+ }
+
+ /*
+ * Phy setup is needed if coming out of idle
+ * power collapse with clamps enabled.
+ */
+ if (ctrl->phy_power_off || mmss_clamp)
+ mdss_dsi_phy_power_on(ctrl, mmss_clamp);
+ }
+ if ((clk & MDSS_DSI_LINK_CLK) && (l_type == MDSS_DSI_LINK_HS_CLK)) {
if (ctrl->ulps) {
/*
* ULPS Entry Request. This is needed if the lanes were
@@ -2254,37 +2297,22 @@
* ULPS.
*/
ctrl->ulps = false;
- rc = mdss_dsi_ulps_config(ctrl, 1);
+ rc = mdss_dsi_ulps_config(ctrl, 1, true);
if (rc) {
pr_err("%s: Failed to enter ULPS. rc=%d\n",
__func__, rc);
goto error;
}
- }
- rc = mdss_dsi_clamp_ctrl(ctrl, 0);
- if (rc) {
- pr_err("%s: Failed to disable dsi clamps. rc=%d\n",
- __func__, rc);
- goto error;
- }
-
- /*
- * Phy setup is needed if coming out of idle
- * power collapse with clamps enabled.
- */
- if (ctrl->phy_power_off || mmss_clamp)
- mdss_dsi_phy_power_on(ctrl, mmss_clamp);
- }
- if (clk & MDSS_DSI_LINK_CLK) {
- if (ctrl->ulps) {
- rc = mdss_dsi_ulps_config(ctrl, 0);
+ rc = mdss_dsi_ulps_config(ctrl, 0, false);
if (rc) {
pr_err("%s: failed to disable ulps, rc= %d\n",
__func__, rc);
goto error;
}
}
+ /* Enable HS TX driver in DSI PHY if applicable */
+ mdss_dsi_phy_hstx_drv_ctrl(ctrl, true);
}
error:
return rc;
@@ -2292,6 +2320,7 @@
int mdss_dsi_post_clkoff_cb(void *priv,
enum mdss_dsi_clk_type clk_type,
+ enum mdss_dsi_lclk_type l_type,
enum mdss_dsi_clk_state curr_state)
{
int rc = 0;
@@ -2342,6 +2371,7 @@
int mdss_dsi_pre_clkon_cb(void *priv,
enum mdss_dsi_clk_type clk_type,
+ enum mdss_dsi_lclk_type l_type,
enum mdss_dsi_clk_state new_state)
{
int rc = 0;