Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit dcefc117 authored by Hai Li's avatar Hai Li Committed by Rob Clark
Browse files

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: default avatarHai Li <hali@codeaurora.org>
Signed-off-by: default avatarRob Clark <robdclark@gmail.com>
parent ab8909b0
Loading
Loading
Loading
Loading
+7 −0
Original line number Original line Diff line number Diff line
@@ -47,6 +47,7 @@ Required properties:
- compatible: Could be the following
- compatible: Could be the following
  * "qcom,dsi-phy-28nm-hpm"
  * "qcom,dsi-phy-28nm-hpm"
  * "qcom,dsi-phy-28nm-lp"
  * "qcom,dsi-phy-28nm-lp"
  * "qcom,dsi-phy-20nm"
- reg: Physical base address and length of the registers of PLL, PHY and PHY
- reg: Physical base address and length of the registers of PLL, PHY and PHY
  regulator
  regulator
- reg-names: The names of register regions. The following regions are required:
- reg-names: The names of register regions. The following regions are required:
@@ -62,6 +63,10 @@ Required properties:
  * "iface_clk"
  * "iface_clk"
- vddio-supply: phandle to vdd-io regulator device node
- vddio-supply: phandle to vdd-io regulator device node


Optional properties:
- qcom,dsi-phy-regulator-ldo-mode: Boolean value indicating if the LDO mode PHY
  regulator is wanted.

Example:
Example:
	mdss_dsi0: qcom,mdss_dsi@fd922800 {
	mdss_dsi0: qcom,mdss_dsi@fd922800 {
		compatible = "qcom,mdss-dsi-ctrl";
		compatible = "qcom,mdss-dsi-ctrl";
@@ -124,4 +129,6 @@ Example:
		clock-names = "iface_clk";
		clock-names = "iface_clk";
		clocks = <&mmcc MDSS_AHB_CLK>;
		clocks = <&mmcc MDSS_AHB_CLK>;
		vddio-supply = <&pma8084_l12>;
		vddio-supply = <&pma8084_l12>;

		qcom,dsi-phy-regulator-ldo-mode;
	};
	};
+1 −0
Original line number Original line Diff line number Diff line
@@ -30,6 +30,7 @@
enum msm_dsi_phy_type {
enum msm_dsi_phy_type {
	MSM_DSI_PHY_28NM_HPM,
	MSM_DSI_PHY_28NM_HPM,
	MSM_DSI_PHY_28NM_LP,
	MSM_DSI_PHY_28NM_LP,
	MSM_DSI_PHY_20NM,
	MSM_DSI_PHY_MAX
	MSM_DSI_PHY_MAX
};
};


+18 −0
Original line number Original line Diff line number Diff line
@@ -34,6 +34,7 @@
#define MSM_DSI_6G_VER_MINOR_V1_1	0x10010000
#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_1_1	0x10010001
#define MSM_DSI_6G_VER_MINOR_V1_2	0x10020000
#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 MSM_DSI_6G_VER_MINOR_V1_3_1	0x10030001


#define DSI_6G_REG_SHIFT	4
#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)
static int dsi_get_version(const void __iomem *base, u32 *major, u32 *minor)
+131 −0
Original line number Original line Diff line number Diff line
@@ -66,6 +66,8 @@ struct msm_dsi_phy {
	struct dsi_dphy_timing timing;
	struct dsi_dphy_timing timing;
	const struct dsi_phy_cfg *cfg;
	const struct dsi_phy_cfg *cfg;


	bool regulator_ldo_mode;

	struct msm_dsi_pll *pll;
	struct msm_dsi_pll *pll;
};
};


@@ -406,6 +408,115 @@ static int dsi_28nm_phy_disable(struct msm_dsi_phy *phy)
	return 0;
	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)
static int dsi_phy_enable_resource(struct msm_dsi_phy *phy)
{
{
	int ret;
	int ret;
@@ -456,6 +567,21 @@ static const struct dsi_phy_cfg dsi_phy_cfgs[MSM_DSI_PHY_MAX] = {
			.disable = dsi_28nm_phy_disable,
			.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[] = {
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],},
	  .data = &dsi_phy_cfgs[MSM_DSI_PHY_28NM_HPM],},
	{ .compatible = "qcom,dsi-phy-28nm-lp",
	{ .compatible = "qcom,dsi-phy-28nm-lp",
	  .data = &dsi_phy_cfgs[MSM_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;
		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");
	phy->base = msm_ioremap(pdev, "dsi_phy", "DSI_PHY");
	if (IS_ERR(phy->base)) {
	if (IS_ERR(phy->base)) {
		dev_err(&pdev->dev, "%s: failed to map phy base\n", __func__);
		dev_err(&pdev->dev, "%s: failed to map phy base\n", __func__);