[PATCH 3/4] drm/mediatek: Add mipi dsi driver for mt8196

CK Hu (胡俊光) ck.hu at mediatek.com
Tue Apr 8 06:10:50 UTC 2025


On Mon, 2025-04-07 at 21:31 +0800, Bincai Liu wrote:
> Add dsi and mipi phy driver for mt8196.
> 
> Signed-off-by: Bincai Liu <bincai.liu at mediatek.com>
> ---
>  drivers/gpu/drm/mediatek/mtk_drm_drv.c        |   2 +
>  drivers/gpu/drm/mediatek/mtk_dsi.c            | 248 +++++++++++-------
>  drivers/phy/mediatek/Makefile                 |   1 +
>  .../phy/mediatek/phy-mtk-mipi-dsi-mt8196.c    | 201 ++++++++++++++
>  drivers/phy/mediatek/phy-mtk-mipi-dsi.c       |   1 +
>  drivers/phy/mediatek/phy-mtk-mipi-dsi.h       |   1 +

Separate drm driver and phy driver to different patch.

>  6 files changed, 356 insertions(+), 98 deletions(-)
>  create mode 100644 drivers/phy/mediatek/phy-mtk-mipi-dsi-mt8196.c
> 
> diff --git a/drivers/gpu/drm/mediatek/mtk_drm_drv.c b/drivers/gpu/drm/mediatek/mtk_drm_drv.c
> index 74158b9d6503..ae859f20fab3 100644
> --- a/drivers/gpu/drm/mediatek/mtk_drm_drv.c
> +++ b/drivers/gpu/drm/mediatek/mtk_drm_drv.c
> @@ -830,6 +830,8 @@ static const struct of_device_id mtk_ddp_comp_dt_ids[] = {
>  	  .data = (void *)MTK_DSI },
>  	{ .compatible = "mediatek,mt8188-dsi",
>  	  .data = (void *)MTK_DSI },
> +	{ .compatible = "mediatek,mt8196-dsi",
> +	  .data = (void *)MTK_DSI },
>  	{ }
>  };
>  
> diff --git a/drivers/gpu/drm/mediatek/mtk_dsi.c b/drivers/gpu/drm/mediatek/mtk_dsi.c
> index d1f407fb7eb1..b1467d6bed06 100644
> --- a/drivers/gpu/drm/mediatek/mtk_dsi.c
> +++ b/drivers/gpu/drm/mediatek/mtk_dsi.c
> @@ -44,12 +44,12 @@
>  #define EXT_TE_RDY_INT_FLAG		BIT(4)
>  #define DSI_BUSY			BIT(31)
>  
> -#define DSI_CON_CTRL		0x10
> +#define DSI_CON_CTRL(data)		(0x10 + (data)->reg_20_ofs)

I do not like the term reg_20_ofs.
It limit that the offset should be zero or 20.
If a new SoC its offset is 30 for DSI_CON_CTRL, this code would be modified again.
May be reg_ctrl_off for all the register name has 'CTRL'.

>  #define DSI_RESET			BIT(0)
>  #define DSI_EN				BIT(1)
>  #define DPHY_RESET			BIT(2)
>  
> -#define DSI_MODE_CTRL		0x14
> +#define DSI_MODE_CTRL(data)		(0x14 + (data)->reg_20_ofs)
>  #define MODE				(3)
>  #define CMD_MODE			0
>  #define SYNC_PULSE_MODE			1
> @@ -58,7 +58,7 @@
>  #define FRM_MODE			BIT(16)
>  #define MIX_MODE			BIT(17)
>  
> -#define DSI_TXRX_CTRL		0x18
> +#define DSI_TXRX_CTRL(data)		(0x18 + (data)->reg_20_ofs)
>  #define VC_NUM				BIT(1)
>  #define LANE_NUM			GENMASK(5, 2)
>  #define DIS_EOT				BIT(6)
> @@ -69,81 +69,87 @@
>  #define MAX_RTN_SIZE			GENMASK(15, 12)
>  #define HSTX_CKLP_EN			BIT(16)
>  
> -#define DSI_PSCTRL		0x1c
> +#define DSI_PSCTRL(data)		(0x1c + (data)->reg_20_ofs)
>  #define DSI_PS_WC			GENMASK(13, 0)
> -#define DSI_PS_SEL			GENMASK(17, 16)
> +#define DSI_PS_SEL			GENMASK(19, 16)
>  #define PACKED_PS_16BIT_RGB565		0
>  #define PACKED_PS_18BIT_RGB666		1
>  #define LOOSELY_PS_24BIT_RGB666		2
>  #define PACKED_PS_24BIT_RGB888		3
>  
> -#define DSI_VSA_NL		0x20
> -#define DSI_VBP_NL		0x24
> -#define DSI_VFP_NL		0x28
> -#define DSI_VACT_NL		0x2C
> +#define DSI_VSA_NL(data)		(0x20 + (data)->reg_40_ofs)

reg_nl_off.

> +#define DSI_VBP_NL(data)		(0x24 + (data)->reg_40_ofs)
> +#define DSI_VFP_NL(data)		(0x28 + (data)->reg_40_ofs)
> +#define DSI_VACT_NL(data)		(0x2c + (data)->reg_40_ofs)
>  #define VACT_NL				GENMASK(14, 0)
> -#define DSI_SIZE_CON		0x38
> +#define DSI_SIZE_CON(data)		((data)->dsi_size_con ? \
> +					(data)->dsi_size_con : 0x38)
>  #define DSI_HEIGHT				GENMASK(30, 16)
>  #define DSI_WIDTH				GENMASK(14, 0)
> -#define DSI_HSA_WC		0x50
> -#define DSI_HBP_WC		0x54
> -#define DSI_HFP_WC		0x58
> +#define DSI_HSA_WC(data)		(0x50 + (data)->reg_30_ofs)

reg_wc_off.

> +#define DSI_HBP_WC(data)		(0x54 + (data)->reg_30_ofs)
> +#define DSI_HFP_WC(data)		(0x58 + (data)->reg_30_ofs)
>  #define HFP_HS_VB_PS_WC		GENMASK(30, 16)
>  #define HFP_HS_EN			BIT(31)
>  
> -#define DSI_CMDQ_SIZE		0x60
> +#define DSI_CMDQ_SIZE(data)		((data)->dsi_cmdq_con ? \
> +					(data)->dsi_cmdq_con : 0x60)
>  #define CMDQ_SIZE			0x3f
>  #define CMDQ_SIZE_SEL		BIT(15)
>  
> -#define DSI_HSTX_CKL_WC		0x64
> +#define DSI_HSTX_CKL_WC(data)		((data)->dsi_hstx_ckl_wc ? \
> +					(data)->dsi_hstx_ckl_wc : 0x64)
>  #define HSTX_CKL_WC			GENMASK(15, 2)
>  
> -#define DSI_RX_DATA0		0x74
> -#define DSI_RX_DATA1		0x78
> -#define DSI_RX_DATA2		0x7c
> -#define DSI_RX_DATA3		0x80
> +#define DSI_RX_DATA0(data)		(0x74 + (data)->reg_30_ofs)

reg_rx_off

> +#define DSI_RX_DATA1(data)		(0x78 + (data)->reg_30_ofs)
> +#define DSI_RX_DATA2(data)		(0x7c + (data)->reg_30_ofs)
> +#define DSI_RX_DATA3(data)		(0x80 + (data)->reg_30_ofs)
>  
> -#define DSI_RACK		0x84
> +#define DSI_RACK(data)			(0x84 + (data)->reg_30_ofs)
>  #define RACK				BIT(0)
>  
> -#define DSI_PHY_LCCON		0x104
> +#define DSI_PHY_LCCON(data)		((data)->reg_phy_base ? 0x1d0 : 0x104)
>  #define LC_HS_TX_EN			BIT(0)
>  #define LC_ULPM_EN			BIT(1)
>  #define LC_WAKEUP_EN			BIT(2)
>  
> -#define DSI_PHY_LD0CON		0x108
> +#define DSI_PHY_LD0CON(data)		((data)->reg_phy_base ? 0x1d4 : 0x108)
>  #define LD0_HS_TX_EN			BIT(0)
>  #define LD0_ULPM_EN			BIT(1)
>  #define LD0_WAKEUP_EN			BIT(2)
>  
> -#define DSI_PHY_TIMECON0	0x110
> -#define LPX				GENMASK(7, 0)
> -#define HS_PREP				GENMASK(15, 8)
> -#define HS_ZERO				GENMASK(23, 16)
> -#define HS_TRAIL			GENMASK(31, 24)
> -
> -#define DSI_PHY_TIMECON1	0x114
> -#define TA_GO				GENMASK(7, 0)
> -#define TA_SURE				GENMASK(15, 8)
> -#define TA_GET				GENMASK(23, 16)
> -#define DA_HS_EXIT			GENMASK(31, 24)
> -
> -#define DSI_PHY_TIMECON2	0x118
> -#define CONT_DET			GENMASK(7, 0)
> -#define DA_HS_SYNC			GENMASK(15, 8)
> -#define CLK_ZERO			GENMASK(23, 16)
> -#define CLK_TRAIL			GENMASK(31, 24)
> -
> -#define DSI_PHY_TIMECON3	0x11c
> -#define CLK_HS_PREP			GENMASK(7, 0)
> -#define CLK_HS_POST			GENMASK(15, 8)
> -#define CLK_HS_EXIT			GENMASK(23, 16)
> +#define DSI_PHY_TIMECON0(data)		((data)->reg_phy_base ? \
> +					(data)->reg_phy_base : 0x110)
> +#define LPX				(0xff << 0)

Keep GENMASK, do not modify this.

> +#define HS_PREP				(0xff << 8)
> +#define HS_ZERO				(0xff << 16)
> +#define HS_TRAIL			(0xff << 24)
> +
> +#define DSI_PHY_TIMECON1(data)		(DSI_PHY_TIMECON0(data) + 0x4)

Let all SoC has (data)->reg_phy_base value (0x110 for old SoC).
And this would be 

#define DSI_PHY_TIMECON0(data)		(data)->reg_phy_base
#define DSI_PHY_TIMECON1(data)		((data)->reg_phy_base + 0x4)

> +#define TA_GO				(0xff << 0)
> +#define TA_SURE				(0xff << 8)
> +#define TA_GET				(0xff << 16)
> +#define DA_HS_EXIT			(0xff << 24)
> +
> +#define DSI_PHY_TIMECON2(data)		(DSI_PHY_TIMECON0(data) + 0x8)
> +#define CONT_DET			(0xff << 0)
> +#define DA_HS_SYNC			(0xff << 8)
> +#define CLK_ZERO			(0xff << 16)
> +#define CLK_TRAIL			(0xff << 24)
> +
> +#define DSI_PHY_TIMECON3(data)		(DSI_PHY_TIMECON0(data) + 0xc)
> +#define CLK_HS_PREP			(0xff << 0)
> +#define CLK_HS_POST			(0xff << 8)
> +#define CLK_HS_EXIT			(0xff << 16)
>  
>  /* DSI_VM_CMD_CON */
>  #define VM_CMD_EN			BIT(0)
>  #define TS_VFP_EN			BIT(5)
>  
>  /* DSI_SHADOW_DEBUG */
> +#define DSI_SHADOW_DEBUG(data)		((data)->dsi_shadow_dbg ? \
> +					(data)->dsi_shadow_dbg : 0x190)
>  #define FORCE_COMMIT			BIT(0)
>  #define BYPASS_SHADOW			BIT(1)
>  
> @@ -193,6 +199,24 @@ struct mtk_dsi_driver_data {
>  	bool has_size_ctl;
>  	bool cmdq_long_packet_ctl;
>  	bool support_per_frame_lp;
> +	const u32 reg_phy_base;
> +	const u32 reg_20_ofs;
> +	const u32 reg_30_ofs;
> +	const u32 reg_40_ofs;
> +	const u32 reg_100_ofs;
> +	const u32 dsi_size_con;
> +	const u32 dsi_vfp_early_stop;

Useless, so drop it.

> +	const u32 dsi_lfr_con;

Ditto.

> +	const u32 dsi_cmdq_con;
> +	const u32 dsi_type1_hs;

Ditto.

> +	const u32 dsi_hstx_ckl_wc;
> +	const u32 dsi_mem_conti;

Ditto.

> +	const u32 dsi_time_con;

Ditto.

> +	const u32 dsi_reserved;

Ditto.

> +	const u32 dsi_state_dbg6;

Ditto.

> +	const u32 dsi_dbg_sel;

Ditto.

> +	const u32 dsi_shadow_dbg;

There is already reg_shadow_dbg_off.
Use reg_shadow_dbg_off for mt8196.
So drop this.

> +	const u32 dsi_vm_cmd_con;

There is already reg_vm_cmd_off.
Use reg_vm_cmd_off for mt8196.
So drop this.

>  };
>  
>  struct mtk_dsi {
> @@ -283,71 +307,71 @@ static void mtk_dsi_phy_timconfig(struct mtk_dsi *dsi)
>  		  FIELD_PREP(CLK_HS_POST, timing->clk_hs_post) |
>  		  FIELD_PREP(CLK_HS_EXIT, timing->clk_hs_exit);
>  
> -	writel(timcon0, dsi->regs + DSI_PHY_TIMECON0);
> -	writel(timcon1, dsi->regs + DSI_PHY_TIMECON1);
> -	writel(timcon2, dsi->regs + DSI_PHY_TIMECON2);
> -	writel(timcon3, dsi->regs + DSI_PHY_TIMECON3);
> +	writel(timcon0, dsi->regs + DSI_PHY_TIMECON0(dsi->driver_data));
> +	writel(timcon1, dsi->regs + DSI_PHY_TIMECON1(dsi->driver_data));
> +	writel(timcon2, dsi->regs + DSI_PHY_TIMECON2(dsi->driver_data));
> +	writel(timcon3, dsi->regs + DSI_PHY_TIMECON3(dsi->driver_data));
>  }
>  

[snip]

> +
> +static const struct mtk_dsi_driver_data mt8196_dsi_driver_data = {
> +	.reg_cmdq_off = 0x400,
> +	.has_shadow_ctl = true,
> +	.has_size_ctl = true,
> +	.cmdq_long_packet_ctl = true,
> +	.support_per_frame_lp = true,
> +	.reg_phy_base = 0x600,
> +	.reg_20_ofs = 0x020,
> +	.reg_30_ofs = 0x030,
> +	.reg_40_ofs = 0x040,
> +	.reg_100_ofs = 0x100,
> +	.dsi_size_con = 0x02c,
> +	.dsi_vfp_early_stop = 0x170,
> +	.dsi_lfr_con = 0x1a0,
> +	.dsi_cmdq_con = 0x44,
> +	.dsi_type1_hs = 0x50,
> +	.dsi_hstx_ckl_wc = 0x100,
> +	.dsi_mem_conti = 0x048,
> +	.dsi_time_con = 0x200,
> +	.dsi_reserved = 0x3f8,
> +	.dsi_state_dbg6 = 0x274,
> +	.dsi_dbg_sel = 0x274,
> +	.dsi_shadow_dbg = 0x0d0,
> +	.dsi_vm_cmd_con = 0x110,
>  };

Separate mt8196_dsi_driver_data to an independent patch which is adding mt8196 dsi support.
And the rest is a preparing patch which support variant register offset.

>  
>  static const struct of_device_id mtk_dsi_of_match[] = {
> @@ -1304,6 +1355,7 @@ static const struct of_device_id mtk_dsi_of_match[] = {
>  	{ .compatible = "mediatek,mt8183-dsi", .data = &mt8183_dsi_driver_data },
>  	{ .compatible = "mediatek,mt8186-dsi", .data = &mt8186_dsi_driver_data },
>  	{ .compatible = "mediatek,mt8188-dsi", .data = &mt8188_dsi_driver_data },
> +	{ .compatible = "mediatek,mt8196-dsi", .data = &mt8196_dsi_driver_data },
>  	{ /* sentinel */ }
>  };
>  MODULE_DEVICE_TABLE(of, mtk_dsi_of_match);
> diff --git a/drivers/phy/mediatek/Makefile b/drivers/phy/mediatek/Makefile
> index 1b8088df71e8..ed0da708759b 100644
> --- a/drivers/phy/mediatek/Makefile
> +++ b/drivers/phy/mediatek/Makefile
> @@ -21,4 +21,5 @@ obj-$(CONFIG_PHY_MTK_MIPI_CSI_0_5)	+= phy-mtk-mipi-csi-0-5.o
>  phy-mtk-mipi-dsi-drv-y			:= phy-mtk-mipi-dsi.o
>  phy-mtk-mipi-dsi-drv-y			+= phy-mtk-mipi-dsi-mt8173.o
>  phy-mtk-mipi-dsi-drv-y			+= phy-mtk-mipi-dsi-mt8183.o
> +phy-mtk-mipi-dsi-drv-y			+= phy-mtk-mipi-dsi-mt8196.o
>  obj-$(CONFIG_PHY_MTK_MIPI_DSI)		+= phy-mtk-mipi-dsi-drv.o
> diff --git a/drivers/phy/mediatek/phy-mtk-mipi-dsi-mt8196.c b/drivers/phy/mediatek/phy-mtk-mipi-dsi-mt8196.c
> new file mode 100644
> index 000000000000..09c7159748d7
> --- /dev/null
> +++ b/drivers/phy/mediatek/phy-mtk-mipi-dsi-mt8196.c
> @@ -0,0 +1,201 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Copyright (c) 2019 MediaTek Inc.
> + * Author: jitao.shi <jitao.shi at mediatek.com>
> + */
> +

[snip]

> +
> +static void mtk_mipi_tx_power_off_signal(struct phy *phy)
> +{
> +	struct mtk_mipi_tx *mipi_tx = phy_get_drvdata(phy);
> +	void __iomem *base = mipi_tx->regs;
> +
> +	/* Switch ON each Lane */
> +	mtk_phy_set_bits(base + MIPITX_D0_SW_CTL_EN, DSI_SW_CTL_EN);
> +	mtk_phy_set_bits(base + MIPITX_D1_SW_CTL_EN, DSI_SW_CTL_EN);
> +	mtk_phy_set_bits(base + MIPITX_D2_SW_CTL_EN, DSI_SW_CTL_EN);
> +	mtk_phy_set_bits(base + MIPITX_D3_SW_CTL_EN, DSI_SW_CTL_EN);
> +	mtk_phy_set_bits(base + MIPITX_CK_SW_CTL_EN, DSI_SW_CTL_EN);
> +
> +	writel(RG_DSI_PAD_TIEL_SEL | RG_DSI_BG_CORE_EN, base + MIPITX_LANE_CON);
> +	writel(RG_DSI_PAD_TIEL_SEL, base + MIPITX_LANE_CON);
> +}
> +
> +const struct mtk_mipitx_data mt8196_mipitx_data = {
> +	.mipi_tx_clk_ops = &mtk_mipi_tx_pll_ops,
> +	.mipi_tx_enable_signal = mtk_mipi_tx_power_on_signal,
> +	.mipi_tx_disable_signal = mtk_mipi_tx_power_off_signal,
> +};

phy-mtk-mipi-dsi-mt8196.c is almost the same as phy-mtk-mipi-dsi-mt8183.c
so merge these two files into one files.
You could reference phy-mtk-mipi-dsi-mt8173.c

Regards,
CK

> diff --git a/drivers/phy/mediatek/phy-mtk-mipi-dsi.c b/drivers/phy/mediatek/phy-mtk-mipi-dsi.c
> index 065ea626093a..46f0cb3ac096 100644
> --- a/drivers/phy/mediatek/phy-mtk-mipi-dsi.c
> +++ b/drivers/phy/mediatek/phy-mtk-mipi-dsi.c
> @@ -183,6 +183,7 @@ static const struct of_device_id mtk_mipi_tx_match[] = {
>  	{ .compatible = "mediatek,mt2701-mipi-tx", .data = &mt2701_mipitx_data },
>  	{ .compatible = "mediatek,mt8173-mipi-tx", .data = &mt8173_mipitx_data },
>  	{ .compatible = "mediatek,mt8183-mipi-tx", .data = &mt8183_mipitx_data },
> +	{ .compatible = "mediatek,mt8196-mipi-tx", .data = &mt8196_mipitx_data },
>  	{ /* sentinel */ }
>  };
>  MODULE_DEVICE_TABLE(of, mtk_mipi_tx_match);
> diff --git a/drivers/phy/mediatek/phy-mtk-mipi-dsi.h b/drivers/phy/mediatek/phy-mtk-mipi-dsi.h
> index 5d4876f1dc95..38f64e1c75aa 100644
> --- a/drivers/phy/mediatek/phy-mtk-mipi-dsi.h
> +++ b/drivers/phy/mediatek/phy-mtk-mipi-dsi.h
> @@ -42,5 +42,6 @@ unsigned long mtk_mipi_tx_pll_recalc_rate(struct clk_hw *hw,
>  extern const struct mtk_mipitx_data mt2701_mipitx_data;
>  extern const struct mtk_mipitx_data mt8173_mipitx_data;
>  extern const struct mtk_mipitx_data mt8183_mipitx_data;
> +extern const struct mtk_mipitx_data mt8196_mipitx_data;
>  
>  #endif

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.freedesktop.org/archives/dri-devel/attachments/20250408/a118f63e/attachment-0001.htm>


More information about the dri-devel mailing list