[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