Commit 1337d7eb authored by Krzysztof Kozlowski's avatar Krzysztof Kozlowski Committed by Dmitry Baryshkov
Browse files

drm/msm/dsi/phy: Add support for SM8750



Add support for DSI PHY v7.0 on Qualcomm SM8750 SoC which comes with an
incompatible hardware interface change:

ICODE_ACCUM_STATUS_LOW and ALOG_OBSV_BUS_STATUS_1 registers - their
offsets were just switched.  Currently these registers are not used in
the driver, so the easiest is to document both but keep them commented
out to avoid conflict.

Reviewed-by: default avatarDmitry Baryshkov <dmitry.baryshkov@linaro.org>
Signed-off-by: default avatarKrzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
Patchwork: https://patchwork.freedesktop.org/patch/659616/
Link: https://lore.kernel.org/r/20250618-b4-sm8750-display-v7-6-a591c609743d@linaro.org


Signed-off-by: default avatarDmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
parent 6b938401
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -597,6 +597,8 @@ static const struct of_device_id dsi_phy_dt_match[] = {
	  .data = &dsi_phy_4nm_8550_cfgs },
	{ .compatible = "qcom,sm8650-dsi-phy-4nm",
	  .data = &dsi_phy_4nm_8650_cfgs },
	{ .compatible = "qcom,sm8750-dsi-phy-3nm",
	  .data = &dsi_phy_3nm_8750_cfgs },
#endif
	{}
};
+1 −0
Original line number Diff line number Diff line
@@ -63,6 +63,7 @@ extern const struct msm_dsi_phy_cfg dsi_phy_5nm_8775p_cfgs;
extern const struct msm_dsi_phy_cfg dsi_phy_5nm_sar2130p_cfgs;
extern const struct msm_dsi_phy_cfg dsi_phy_4nm_8550_cfgs;
extern const struct msm_dsi_phy_cfg dsi_phy_4nm_8650_cfgs;
extern const struct msm_dsi_phy_cfg dsi_phy_3nm_8750_cfgs;

struct msm_dsi_dphy_timing {
	u32 clk_zero;
+73 −6
Original line number Diff line number Diff line
@@ -51,6 +51,8 @@
#define DSI_PHY_7NM_QUIRK_V4_3		BIT(3)
/* Hardware is V5.2 */
#define DSI_PHY_7NM_QUIRK_V5_2		BIT(4)
/* Hardware is V7.0 */
#define DSI_PHY_7NM_QUIRK_V7_0		BIT(5)

struct dsi_pll_config {
	bool enable_ssc;
@@ -129,9 +131,30 @@ static void dsi_pll_calc_dec_frac(struct dsi_pll_7nm *pll, struct dsi_pll_config
	dec_multiple = div_u64(pll_freq * multiplier, divider);
	dec = div_u64_rem(dec_multiple, multiplier, &frac);

	if (pll->phy->cfg->quirks & DSI_PHY_7NM_QUIRK_PRE_V4_1)
	if (pll->phy->cfg->quirks & DSI_PHY_7NM_QUIRK_PRE_V4_1) {
		config->pll_clock_inverters = 0x28;
	else if ((pll->phy->cfg->quirks & DSI_PHY_7NM_QUIRK_V5_2)) {
	} else if ((pll->phy->cfg->quirks & DSI_PHY_7NM_QUIRK_V7_0)) {
		if (pll_freq < 163000000ULL)
			config->pll_clock_inverters = 0xa0;
		else if (pll_freq < 175000000ULL)
			config->pll_clock_inverters = 0x20;
		else if (pll_freq < 325000000ULL)
			config->pll_clock_inverters = 0xa0;
		else if (pll_freq < 350000000ULL)
			config->pll_clock_inverters = 0x20;
		else if (pll_freq < 650000000ULL)
			config->pll_clock_inverters = 0xa0;
		else if (pll_freq < 700000000ULL)
			config->pll_clock_inverters = 0x20;
		else if (pll_freq < 1300000000ULL)
			config->pll_clock_inverters = 0xa0;
		else if (pll_freq < 2500000000ULL)
			config->pll_clock_inverters = 0x20;
		else if (pll_freq < 4000000000ULL)
			config->pll_clock_inverters = 0x00;
		else
			config->pll_clock_inverters = 0x40;
	} else if ((pll->phy->cfg->quirks & DSI_PHY_7NM_QUIRK_V5_2)) {
		if (pll_freq <= 1300000000ULL)
			config->pll_clock_inverters = 0xa0;
		else if (pll_freq <= 2500000000ULL)
@@ -250,7 +273,8 @@ static void dsi_pll_config_hzindep_reg(struct dsi_pll_7nm *pll)
			vco_config_1 = 0x01;
	}

	if ((pll->phy->cfg->quirks & DSI_PHY_7NM_QUIRK_V5_2)) {
	if ((pll->phy->cfg->quirks & DSI_PHY_7NM_QUIRK_V5_2) ||
	    (pll->phy->cfg->quirks & DSI_PHY_7NM_QUIRK_V7_0)) {
		if (pll->vco_current_rate < 1557000000ULL)
			vco_config_1 = 0x08;
		else
@@ -620,6 +644,7 @@ static int dsi_7nm_pll_restore_state(struct msm_dsi_phy *phy)
static int dsi_7nm_set_usecase(struct msm_dsi_phy *phy)
{
	struct dsi_pll_7nm *pll_7nm = to_pll_7nm(phy->vco_hw);
	void __iomem *base = phy->base;
	u32 data = 0x0;	/* internal PLL */

	DBG("DSI PLL%d", pll_7nm->phy->id);
@@ -629,6 +654,9 @@ static int dsi_7nm_set_usecase(struct msm_dsi_phy *phy)
		break;
	case MSM_DSI_PHY_MASTER:
		pll_7nm->slave = pll_7nm_list[(pll_7nm->phy->id + 1) % DSI_MAX];
		/* v7.0: Enable ATB_EN0 and alternate clock output to external phy */
		if (phy->cfg->quirks & DSI_PHY_7NM_QUIRK_V7_0)
			writel(0x07, base + REG_DSI_7nm_PHY_CMN_CTRL_5);
		break;
	case MSM_DSI_PHY_SLAVE:
		data = 0x1; /* external PLL */
@@ -907,7 +935,8 @@ static int dsi_7nm_phy_enable(struct msm_dsi_phy *phy,

	/* Request for REFGEN READY */
	if ((phy->cfg->quirks & DSI_PHY_7NM_QUIRK_V4_3) ||
	    (phy->cfg->quirks & DSI_PHY_7NM_QUIRK_V5_2)) {
	    (phy->cfg->quirks & DSI_PHY_7NM_QUIRK_V5_2) ||
	    (phy->cfg->quirks & DSI_PHY_7NM_QUIRK_V7_0)) {
		writel(0x1, phy->base + REG_DSI_7nm_PHY_CMN_GLBL_DIGTOP_SPARE10);
		udelay(500);
	}
@@ -941,7 +970,20 @@ static int dsi_7nm_phy_enable(struct msm_dsi_phy *phy,
		lane_ctrl0 = 0x1f;
	}

	if ((phy->cfg->quirks & DSI_PHY_7NM_QUIRK_V5_2)) {
	if ((phy->cfg->quirks & DSI_PHY_7NM_QUIRK_V7_0)) {
		if (phy->cphy_mode) {
			/* TODO: different for second phy */
			vreg_ctrl_0 = 0x57;
			vreg_ctrl_1 = 0x41;
			glbl_rescode_top_ctrl = 0x3d;
			glbl_rescode_bot_ctrl = 0x38;
		} else {
			vreg_ctrl_0 = 0x56;
			vreg_ctrl_1 = 0x19;
			glbl_rescode_top_ctrl = less_than_1500_mhz ? 0x3c :  0x03;
			glbl_rescode_bot_ctrl = less_than_1500_mhz ? 0x38 :  0x3c;
		}
	} else if ((phy->cfg->quirks & DSI_PHY_7NM_QUIRK_V5_2)) {
		if (phy->cphy_mode) {
			vreg_ctrl_0 = 0x45;
			vreg_ctrl_1 = 0x41;
@@ -1003,6 +1045,7 @@ static int dsi_7nm_phy_enable(struct msm_dsi_phy *phy,

	/* program CMN_CTRL_4 for minor_ver 2 chipsets*/
	if ((phy->cfg->quirks & DSI_PHY_7NM_QUIRK_V5_2) ||
	    (phy->cfg->quirks & DSI_PHY_7NM_QUIRK_V7_0) ||
	    (readl(base + REG_DSI_7nm_PHY_CMN_REVISION_ID0) & (0xf0)) == 0x20)
		writel(0x04, base + REG_DSI_7nm_PHY_CMN_CTRL_4);

@@ -1117,7 +1160,8 @@ static void dsi_7nm_phy_disable(struct msm_dsi_phy *phy)

	/* Turn off REFGEN Vote */
	if ((phy->cfg->quirks & DSI_PHY_7NM_QUIRK_V4_3) ||
	    (phy->cfg->quirks & DSI_PHY_7NM_QUIRK_V5_2)) {
	    (phy->cfg->quirks & DSI_PHY_7NM_QUIRK_V5_2) ||
	    (phy->cfg->quirks & DSI_PHY_7NM_QUIRK_V7_0)) {
		writel(0x0, base + REG_DSI_7nm_PHY_CMN_GLBL_DIGTOP_SPARE10);
		wmb();
		/* Delay to ensure HW removes vote before PHY shut down */
@@ -1384,3 +1428,26 @@ const struct msm_dsi_phy_cfg dsi_phy_4nm_8650_cfgs = {
	.num_dsi_phy = 2,
	.quirks = DSI_PHY_7NM_QUIRK_V5_2,
};

const struct msm_dsi_phy_cfg dsi_phy_3nm_8750_cfgs = {
	.has_phy_lane = true,
	.regulator_data = dsi_phy_7nm_98000uA_regulators,
	.num_regulators = ARRAY_SIZE(dsi_phy_7nm_98000uA_regulators),
	.ops = {
		.enable = dsi_7nm_phy_enable,
		.disable = dsi_7nm_phy_disable,
		.pll_init = dsi_pll_7nm_init,
		.save_pll_state = dsi_7nm_pll_save_state,
		.restore_pll_state = dsi_7nm_pll_restore_state,
		.set_continuous_clock = dsi_7nm_set_continuous_clock,
	},
	.min_pll_rate = 600000000UL,
#ifdef CONFIG_64BIT
	.max_pll_rate = 5000000000UL,
#else
	.max_pll_rate = ULONG_MAX,
#endif
	.io_start = { 0xae95000, 0xae97000 },
	.num_dsi_phy = 2,
	.quirks = DSI_PHY_7NM_QUIRK_V7_0,
};
+14 −0
Original line number Diff line number Diff line
@@ -26,6 +26,7 @@ xsi:schemaLocation="https://gitlab.freedesktop.org/freedreno/ rules-fd.xsd">
	<reg32 offset="0x00028" name="CTRL_1"/>
	<reg32 offset="0x0002c" name="CTRL_2"/>
	<reg32 offset="0x00030" name="CTRL_3"/>
	<reg32 offset="0x001b0" name="CTRL_5"/>
	<reg32 offset="0x00034" name="LANE_CFG0"/>
	<reg32 offset="0x00038" name="LANE_CFG1"/>
	<reg32 offset="0x0003c" name="PLL_CNTRL"/>
@@ -191,11 +192,24 @@ xsi:schemaLocation="https://gitlab.freedesktop.org/freedreno/ rules-fd.xsd">
	<reg32 offset="0x01b0" name="COMMON_STATUS_ONE"/>
	<reg32 offset="0x01b4" name="COMMON_STATUS_TWO"/>
	<reg32 offset="0x01b8" name="BAND_SEL_CAL"/>
	<!--
	Starting with SM8750, offset moved from 0x01bc to 0x01cc, however
	we keep only one register map.  That's not a problem, so far,
	because this register is not used.  The register map should be split
	once it is going to be used.  Comment out the code to prevent
	any misuse due to the change in the offset.
	<reg32 offset="0x01bc" name="ICODE_ACCUM_STATUS_LOW"/>
	<reg32 offset="0x01cc" name="ICODE_ACCUM_STATUS_LOW"/>
	-->
	<reg32 offset="0x01c0" name="ICODE_ACCUM_STATUS_HIGH"/>
	<reg32 offset="0x01c4" name="FD_OUT_LOW"/>
	<reg32 offset="0x01c8" name="FD_OUT_HIGH"/>
	<!--
	Starting with SM8750, offset moved from 0x01cc to 0x01bc, however
	we keep only one register map.  See above comment.
	<reg32 offset="0x01cc" name="ALOG_OBSV_BUS_STATUS_1"/>
	<reg32 offset="0x01bc" name="ALOG_OBSV_BUS_STATUS_1"/>
	-->
	<reg32 offset="0x01d0" name="PLL_MISC_CONFIG"/>
	<reg32 offset="0x01d4" name="FLL_CONFIG"/>
	<reg32 offset="0x01d8" name="FLL_FREQ_ACQ_TIME"/>