summaryrefslogtreecommitdiff
path: root/drivers/gpu/drm
diff options
context:
space:
mode:
authorHai Li <hali@codeaurora.org>2015-06-18 10:14:21 -0400
committerRob Clark <robdclark@gmail.com>2015-08-15 18:27:12 -0400
commitdcefc117cc192f215d04c4e7cbae6b76a9bafcf4 (patch)
treeb5e108bbf5348284be68c4495726f3dd9c577086 /drivers/gpu/drm
parentab8909b032ffccc15384879dd5798b8647d6ab8a (diff)
drm/msm/dsi: Add support for msm8x94
DSI controller on msm8x94 is version 1.3, which requires different power supplies and works with 20nm DSI PHY. This change is to add the basic support for this version. Signed-off-by: Hai Li <hali@codeaurora.org> Signed-off-by: Rob Clark <robdclark@gmail.com>
Diffstat (limited to 'drivers/gpu/drm')
-rw-r--r--drivers/gpu/drm/msm/dsi/dsi.h1
-rw-r--r--drivers/gpu/drm/msm/dsi/dsi_host.c18
-rw-r--r--drivers/gpu/drm/msm/dsi/dsi_phy.c131
3 files changed, 150 insertions, 0 deletions
diff --git a/drivers/gpu/drm/msm/dsi/dsi.h b/drivers/gpu/drm/msm/dsi/dsi.h
index 5e29aadc0bee..e18872a62806 100644
--- a/drivers/gpu/drm/msm/dsi/dsi.h
+++ b/drivers/gpu/drm/msm/dsi/dsi.h
@@ -30,6 +30,7 @@
enum msm_dsi_phy_type {
MSM_DSI_PHY_28NM_HPM,
MSM_DSI_PHY_28NM_LP,
+ MSM_DSI_PHY_20NM,
MSM_DSI_PHY_MAX
};
diff --git a/drivers/gpu/drm/msm/dsi/dsi_host.c b/drivers/gpu/drm/msm/dsi/dsi_host.c
index 69c13970a36c..2d8f19450788 100644
--- a/drivers/gpu/drm/msm/dsi/dsi_host.c
+++ b/drivers/gpu/drm/msm/dsi/dsi_host.c
@@ -34,6 +34,7 @@
#define MSM_DSI_6G_VER_MINOR_V1_1 0x10010000
#define MSM_DSI_6G_VER_MINOR_V1_1_1 0x10010001
#define MSM_DSI_6G_VER_MINOR_V1_2 0x10020000
+#define MSM_DSI_6G_VER_MINOR_V1_3 0x10030000
#define MSM_DSI_6G_VER_MINOR_V1_3_1 0x10030001
#define DSI_6G_REG_SHIFT 4
@@ -117,6 +118,23 @@ static const struct dsi_config dsi_cfgs[] = {
},
},
},
+ { /* 8x94 */
+ .major = MSM_DSI_VER_MAJOR_6G,
+ .minor = MSM_DSI_6G_VER_MINOR_V1_3,
+ .io_offset = DSI_6G_REG_SHIFT,
+ .reg_cfg = {
+ .num = 7,
+ .regs = {
+ {"gdsc", -1, -1, -1, -1},
+ {"vdda", 1250000, 1250000, 100000, 100},
+ {"vddio", 1800000, 1800000, 100000, 100},
+ {"vcca", 1000000, 1000000, 10000, 100},
+ {"vdd", 1800000, 1800000, 100000, 100},
+ {"lab_reg", -1, -1, -1, -1},
+ {"ibb_reg", -1, -1, -1, -1},
+ },
+ }
+ },
};
static int dsi_get_version(const void __iomem *base, u32 *major, u32 *minor)
diff --git a/drivers/gpu/drm/msm/dsi/dsi_phy.c b/drivers/gpu/drm/msm/dsi/dsi_phy.c
index 52b463e51202..bd37e61123bf 100644
--- a/drivers/gpu/drm/msm/dsi/dsi_phy.c
+++ b/drivers/gpu/drm/msm/dsi/dsi_phy.c
@@ -66,6 +66,8 @@ struct msm_dsi_phy {
struct dsi_dphy_timing timing;
const struct dsi_phy_cfg *cfg;
+ bool regulator_ldo_mode;
+
struct msm_dsi_pll *pll;
};
@@ -406,6 +408,115 @@ static int dsi_28nm_phy_disable(struct msm_dsi_phy *phy)
return 0;
}
+static void dsi_20nm_phy_regulator_ctrl(struct msm_dsi_phy *phy, bool enable)
+{
+ void __iomem *base = phy->reg_base;
+
+ if (!enable) {
+ dsi_phy_write(base + REG_DSI_20nm_PHY_REGULATOR_CAL_PWR_CFG, 0);
+ return;
+ }
+
+ if (phy->regulator_ldo_mode) {
+ dsi_phy_write(phy->base + REG_DSI_20nm_PHY_LDO_CNTRL, 0x1d);
+ return;
+ }
+
+ /* non LDO mode */
+ dsi_phy_write(base + REG_DSI_20nm_PHY_REGULATOR_CTRL_1, 0x03);
+ dsi_phy_write(base + REG_DSI_20nm_PHY_REGULATOR_CTRL_2, 0x03);
+ dsi_phy_write(base + REG_DSI_20nm_PHY_REGULATOR_CTRL_3, 0x00);
+ dsi_phy_write(base + REG_DSI_20nm_PHY_REGULATOR_CTRL_4, 0x20);
+ dsi_phy_write(base + REG_DSI_20nm_PHY_REGULATOR_CAL_PWR_CFG, 0x01);
+ dsi_phy_write(phy->base + REG_DSI_20nm_PHY_LDO_CNTRL, 0x00);
+ dsi_phy_write(base + REG_DSI_20nm_PHY_REGULATOR_CTRL_0, 0x03);
+}
+
+static int dsi_20nm_phy_enable(struct msm_dsi_phy *phy, int src_pll_id,
+ const unsigned long bit_rate, const unsigned long esc_rate)
+{
+ struct dsi_dphy_timing *timing = &phy->timing;
+ int i;
+ void __iomem *base = phy->base;
+ u32 cfg_4[4] = {0x20, 0x40, 0x20, 0x00};
+
+ DBG("");
+
+ if (dsi_dphy_timing_calc(timing, bit_rate, esc_rate)) {
+ pr_err("%s: D-PHY timing calculation failed\n", __func__);
+ return -EINVAL;
+ }
+
+ dsi_20nm_phy_regulator_ctrl(phy, true);
+
+ dsi_phy_write(base + REG_DSI_20nm_PHY_STRENGTH_0, 0xff);
+
+ dsi_phy_set_src_pll(phy, src_pll_id, REG_DSI_20nm_PHY_GLBL_TEST_CTRL);
+
+ for (i = 0; i < 4; i++) {
+ dsi_phy_write(base + REG_DSI_20nm_PHY_LN_CFG_3(i),
+ (i >> 1) * 0x40);
+ dsi_phy_write(base + REG_DSI_20nm_PHY_LN_TEST_STR_0(i), 0x01);
+ dsi_phy_write(base + REG_DSI_20nm_PHY_LN_TEST_STR_1(i), 0x46);
+ dsi_phy_write(base + REG_DSI_20nm_PHY_LN_CFG_0(i), 0x02);
+ dsi_phy_write(base + REG_DSI_20nm_PHY_LN_CFG_1(i), 0xa0);
+ dsi_phy_write(base + REG_DSI_20nm_PHY_LN_CFG_4(i), cfg_4[i]);
+ }
+
+ dsi_phy_write(base + REG_DSI_20nm_PHY_LNCK_CFG_3, 0x80);
+ dsi_phy_write(base + REG_DSI_20nm_PHY_LNCK_TEST_STR0, 0x01);
+ dsi_phy_write(base + REG_DSI_20nm_PHY_LNCK_TEST_STR1, 0x46);
+ dsi_phy_write(base + REG_DSI_20nm_PHY_LNCK_CFG_0, 0x00);
+ dsi_phy_write(base + REG_DSI_20nm_PHY_LNCK_CFG_1, 0xa0);
+ dsi_phy_write(base + REG_DSI_20nm_PHY_LNCK_CFG_2, 0x00);
+ dsi_phy_write(base + REG_DSI_20nm_PHY_LNCK_CFG_4, 0x00);
+
+ dsi_phy_write(base + REG_DSI_20nm_PHY_TIMING_CTRL_0,
+ DSI_20nm_PHY_TIMING_CTRL_0_CLK_ZERO(timing->clk_zero));
+ dsi_phy_write(base + REG_DSI_20nm_PHY_TIMING_CTRL_1,
+ DSI_20nm_PHY_TIMING_CTRL_1_CLK_TRAIL(timing->clk_trail));
+ dsi_phy_write(base + REG_DSI_20nm_PHY_TIMING_CTRL_2,
+ DSI_20nm_PHY_TIMING_CTRL_2_CLK_PREPARE(timing->clk_prepare));
+ if (timing->clk_zero & BIT(8))
+ dsi_phy_write(base + REG_DSI_20nm_PHY_TIMING_CTRL_3,
+ DSI_20nm_PHY_TIMING_CTRL_3_CLK_ZERO_8);
+ dsi_phy_write(base + REG_DSI_20nm_PHY_TIMING_CTRL_4,
+ DSI_20nm_PHY_TIMING_CTRL_4_HS_EXIT(timing->hs_exit));
+ dsi_phy_write(base + REG_DSI_20nm_PHY_TIMING_CTRL_5,
+ DSI_20nm_PHY_TIMING_CTRL_5_HS_ZERO(timing->hs_zero));
+ dsi_phy_write(base + REG_DSI_20nm_PHY_TIMING_CTRL_6,
+ DSI_20nm_PHY_TIMING_CTRL_6_HS_PREPARE(timing->hs_prepare));
+ dsi_phy_write(base + REG_DSI_20nm_PHY_TIMING_CTRL_7,
+ DSI_20nm_PHY_TIMING_CTRL_7_HS_TRAIL(timing->hs_trail));
+ dsi_phy_write(base + REG_DSI_20nm_PHY_TIMING_CTRL_8,
+ DSI_20nm_PHY_TIMING_CTRL_8_HS_RQST(timing->hs_rqst));
+ dsi_phy_write(base + REG_DSI_20nm_PHY_TIMING_CTRL_9,
+ DSI_20nm_PHY_TIMING_CTRL_9_TA_GO(timing->ta_go) |
+ DSI_20nm_PHY_TIMING_CTRL_9_TA_SURE(timing->ta_sure));
+ dsi_phy_write(base + REG_DSI_20nm_PHY_TIMING_CTRL_10,
+ DSI_20nm_PHY_TIMING_CTRL_10_TA_GET(timing->ta_get));
+ dsi_phy_write(base + REG_DSI_20nm_PHY_TIMING_CTRL_11,
+ DSI_20nm_PHY_TIMING_CTRL_11_TRIG3_CMD(0));
+
+ dsi_phy_write(base + REG_DSI_20nm_PHY_CTRL_1, 0x00);
+
+ dsi_phy_write(base + REG_DSI_20nm_PHY_STRENGTH_1, 0x06);
+
+ /* make sure everything is written before enable */
+ wmb();
+ dsi_phy_write(base + REG_DSI_20nm_PHY_CTRL_0, 0x7f);
+
+ return 0;
+}
+
+static int dsi_20nm_phy_disable(struct msm_dsi_phy *phy)
+{
+ dsi_phy_write(phy->base + REG_DSI_20nm_PHY_CTRL_0, 0);
+ dsi_20nm_phy_regulator_ctrl(phy, false);
+
+ return 0;
+}
+
static int dsi_phy_enable_resource(struct msm_dsi_phy *phy)
{
int ret;
@@ -456,6 +567,21 @@ static const struct dsi_phy_cfg dsi_phy_cfgs[MSM_DSI_PHY_MAX] = {
.disable = dsi_28nm_phy_disable,
}
},
+ [MSM_DSI_PHY_20NM] = {
+ .type = MSM_DSI_PHY_20NM,
+ .src_pll_truthtable = { {false, true}, {false, true} },
+ .reg_cfg = {
+ .num = 2,
+ .regs = {
+ {"vddio", 1800000, 1800000, 100000, 100},
+ {"vcca", 1000000, 1000000, 10000, 100},
+ },
+ },
+ .ops = {
+ .enable = dsi_20nm_phy_enable,
+ .disable = dsi_20nm_phy_disable,
+ }
+ },
};
static const struct of_device_id dsi_phy_dt_match[] = {
@@ -463,6 +589,8 @@ static const struct of_device_id dsi_phy_dt_match[] = {
.data = &dsi_phy_cfgs[MSM_DSI_PHY_28NM_HPM],},
{ .compatible = "qcom,dsi-phy-28nm-lp",
.data = &dsi_phy_cfgs[MSM_DSI_PHY_28NM_LP],},
+ { .compatible = "qcom,dsi-phy-20nm",
+ .data = &dsi_phy_cfgs[MSM_DSI_PHY_20NM],},
{}
};
@@ -492,6 +620,9 @@ static int dsi_phy_driver_probe(struct platform_device *pdev)
goto fail;
}
+ phy->regulator_ldo_mode = of_property_read_bool(pdev->dev.of_node,
+ "qcom,dsi-phy-regulator-ldo-mode");
+
phy->base = msm_ioremap(pdev, "dsi_phy", "DSI_PHY");
if (IS_ERR(phy->base)) {
dev_err(&pdev->dev, "%s: failed to map phy base\n", __func__);