Devicetree
 help / color / mirror / Atom feed
* [PATCH 00/11] drm: MediaTek DisplayPort cleanups and MT8196 eDP
@ 2026-07-01 12:20 AngeloGioacchino Del Regno
  2026-07-01 12:20 ` [PATCH 01/11] dt-bindings: display: mediatek: dp: Deprecate nvmem efuse data AngeloGioacchino Del Regno
                   ` (10 more replies)
  0 siblings, 11 replies; 20+ messages in thread
From: AngeloGioacchino Del Regno @ 2026-07-01 12:20 UTC (permalink / raw)
  To: chunkuang.hu
  Cc: p.zabel, airlied, simona, maarten.lankhorst, mripard, tzimmermann,
	robh, krzk+dt, conor+dt, matthias.bgg, angelogioacchino.delregno,
	jitao.shi, granquet, rex-bc.chen, dmitry.osipenko, ck.hu,
	amergnat, justin.yeh, jason-jh.lin, dri-devel, linux-mediatek,
	devicetree, linux-kernel, linux-arm-kernel, kernel

This series performs some very much needed cleanups to the MediaTek
DisplayPort driver, including a fix for the audio codec and PHY driver
unregistration, a refactor to finally correctly use the PHY (!) and
introduces support for the Embedded DisplayPort (eDP) IP in MT8196.

Note that this deprecates the nvmem related properties in this driver
because those are NOT related to the DisplayPort IP, but rather to the
DisplayPort PHY, and were therefore transferred there instead (code in
a different series, updating the PHY driver).

On legacy devices, this driver was carefully tested with both NEW and
OLD devicetrees, so both with the new, proper PHY usage, and with the
old platform device registration strategy and eFuse retrieval from DP
instead of PHY driver.

This was also successfully (manually) tested in a kernel that misses
the PHY driver updates on devices using old devicetrees (mt8195/88)
and no regressions were experienced.

AngeloGioacchino Del Regno (11):
  dt-bindings: display: mediatek: dp: Deprecate nvmem efuse data
  dt-bindings: display: mediatek: dp: Add compatible for MT8196 eDP
  drm/mediatek: mtk_dp: Fix hdmi codec and phy driver unregistration
  drm/mediatek: mtk_dp: Clarify SMC eDP/DP video unmute commands
  drm/mediatek: mtk_dp: Rework register offsets for proper PHY usage
  drm/mediatek: mtk_dp: Use PHY API for PHY power sequences
  drm/mediatek: mtk_dp: Add support for PHY from devicetree
  drm/mediatek: mtk_dp: Move max link rate to SoC specific data
  drm/mediatek: mtk_dp: Add support for HotPlug Detection in DP AUX
  drm/mediatek: mtk_dp: Add support for eDP1.5 IPs and MT8196 SoC
  drm/mediatek: mtk_dp: Clarify XTAL freq and Debounce registers

 .../display/mediatek/mediatek,dp.yaml         |   5 +-
 drivers/gpu/drm/mediatek/mtk_dp.c             | 576 +++++++++++++++---
 drivers/gpu/drm/mediatek/mtk_dp_reg.h         | 328 +++++-----
 3 files changed, 691 insertions(+), 218 deletions(-)

-- 
2.54.0


^ permalink raw reply	[flat|nested] 20+ messages in thread

* [PATCH 01/11] dt-bindings: display: mediatek: dp: Deprecate nvmem efuse data
  2026-07-01 12:20 [PATCH 00/11] drm: MediaTek DisplayPort cleanups and MT8196 eDP AngeloGioacchino Del Regno
@ 2026-07-01 12:20 ` AngeloGioacchino Del Regno
  2026-07-01 12:20 ` [PATCH 02/11] dt-bindings: display: mediatek: dp: Add compatible for MT8196 eDP AngeloGioacchino Del Regno
                   ` (9 subsequent siblings)
  10 siblings, 0 replies; 20+ messages in thread
From: AngeloGioacchino Del Regno @ 2026-07-01 12:20 UTC (permalink / raw)
  To: chunkuang.hu
  Cc: p.zabel, airlied, simona, maarten.lankhorst, mripard, tzimmermann,
	robh, krzk+dt, conor+dt, matthias.bgg, angelogioacchino.delregno,
	jitao.shi, granquet, rex-bc.chen, dmitry.osipenko, ck.hu,
	amergnat, justin.yeh, jason-jh.lin, dri-devel, linux-mediatek,
	devicetree, linux-kernel, linux-arm-kernel, kernel

Deprecate nvmem-cells and nvmem-cell-names and clarify their
purpose, as those are for PHY calibration data, not for the DP
IP itself, and that data shall go in the PHY binding instead.

Signed-off-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
---
 .../devicetree/bindings/display/mediatek/mediatek,dp.yaml     | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/Documentation/devicetree/bindings/display/mediatek/mediatek,dp.yaml b/Documentation/devicetree/bindings/display/mediatek/mediatek,dp.yaml
index 8f4bd9fb560b..980f76667ada 100644
--- a/Documentation/devicetree/bindings/display/mediatek/mediatek,dp.yaml
+++ b/Documentation/devicetree/bindings/display/mediatek/mediatek,dp.yaml
@@ -30,10 +30,12 @@ properties:
     maxItems: 1
 
   nvmem-cells:
+    deprecated: true
     maxItems: 1
-    description: efuse data for display port calibration
+    description: efuse data for display port phy calibration
 
   nvmem-cell-names:
+    deprecated: true
     const: dp_calibration_data
 
   power-domains:
-- 
2.54.0


^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [PATCH 02/11] dt-bindings: display: mediatek: dp: Add compatible for MT8196 eDP
  2026-07-01 12:20 [PATCH 00/11] drm: MediaTek DisplayPort cleanups and MT8196 eDP AngeloGioacchino Del Regno
  2026-07-01 12:20 ` [PATCH 01/11] dt-bindings: display: mediatek: dp: Deprecate nvmem efuse data AngeloGioacchino Del Regno
@ 2026-07-01 12:20 ` AngeloGioacchino Del Regno
  2026-07-01 12:20 ` [PATCH 03/11] drm/mediatek: mtk_dp: Fix hdmi codec and phy driver unregistration AngeloGioacchino Del Regno
                   ` (8 subsequent siblings)
  10 siblings, 0 replies; 20+ messages in thread
From: AngeloGioacchino Del Regno @ 2026-07-01 12:20 UTC (permalink / raw)
  To: chunkuang.hu
  Cc: p.zabel, airlied, simona, maarten.lankhorst, mripard, tzimmermann,
	robh, krzk+dt, conor+dt, matthias.bgg, angelogioacchino.delregno,
	jitao.shi, granquet, rex-bc.chen, dmitry.osipenko, ck.hu,
	amergnat, justin.yeh, jason-jh.lin, dri-devel, linux-mediatek,
	devicetree, linux-kernel, linux-arm-kernel, kernel

Add a new compatible for the Embedded DisplayPort IP found in the
MT8196 SoC.

This IP is compatible with the previous ones, but not fully.

Signed-off-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
---
 .../devicetree/bindings/display/mediatek/mediatek,dp.yaml        | 1 +
 1 file changed, 1 insertion(+)

diff --git a/Documentation/devicetree/bindings/display/mediatek/mediatek,dp.yaml b/Documentation/devicetree/bindings/display/mediatek/mediatek,dp.yaml
index 980f76667ada..3a752a99949a 100644
--- a/Documentation/devicetree/bindings/display/mediatek/mediatek,dp.yaml
+++ b/Documentation/devicetree/bindings/display/mediatek/mediatek,dp.yaml
@@ -25,6 +25,7 @@ properties:
       - mediatek,mt8188-edp-tx
       - mediatek,mt8195-dp-tx
       - mediatek,mt8195-edp-tx
+      - mediatek,mt8196-edp-tx
 
   reg:
     maxItems: 1
-- 
2.54.0


^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [PATCH 03/11] drm/mediatek: mtk_dp: Fix hdmi codec and phy driver unregistration
  2026-07-01 12:20 [PATCH 00/11] drm: MediaTek DisplayPort cleanups and MT8196 eDP AngeloGioacchino Del Regno
  2026-07-01 12:20 ` [PATCH 01/11] dt-bindings: display: mediatek: dp: Deprecate nvmem efuse data AngeloGioacchino Del Regno
  2026-07-01 12:20 ` [PATCH 02/11] dt-bindings: display: mediatek: dp: Add compatible for MT8196 eDP AngeloGioacchino Del Regno
@ 2026-07-01 12:20 ` AngeloGioacchino Del Regno
  2026-07-01 12:32   ` sashiko-bot
  2026-07-01 12:20 ` [PATCH 04/11] drm/mediatek: mtk_dp: Clarify SMC eDP/DP video unmute commands AngeloGioacchino Del Regno
                   ` (7 subsequent siblings)
  10 siblings, 1 reply; 20+ messages in thread
From: AngeloGioacchino Del Regno @ 2026-07-01 12:20 UTC (permalink / raw)
  To: chunkuang.hu
  Cc: p.zabel, airlied, simona, maarten.lankhorst, mripard, tzimmermann,
	robh, krzk+dt, conor+dt, matthias.bgg, angelogioacchino.delregno,
	jitao.shi, granquet, rex-bc.chen, dmitry.osipenko, ck.hu,
	amergnat, justin.yeh, jason-jh.lin, dri-devel, linux-mediatek,
	devicetree, linux-kernel, linux-arm-kernel, kernel

During probe, this driver is registering two platform devices: one
for the HDMI Codec driver and one for the DisplayPort PHY driver.

In the probe function, none of the error cases are unregistering
any of the two platform devices and this may cause registration
of multiple instances of those in case this driver returns one or
more probe deferral(s) in the "wrong" spots.

In order to fix this, add devm actions to unregister those and
remove the manual calls to platform_device_unregister in the
mtk_dp_remove() function, as those would otherwise be redundant.

Fixes: e71a8ebbe086 ("drm/mediatek: dp: Audio support for MT8195")
Fixes: caf2ae486742 ("drm/mediatek: dp: Add support for embedded DisplayPort aux-bus")
Signed-off-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
---
 drivers/gpu/drm/mediatek/mtk_dp.c | 30 ++++++++++++++++++++++++++----
 1 file changed, 26 insertions(+), 4 deletions(-)

diff --git a/drivers/gpu/drm/mediatek/mtk_dp.c b/drivers/gpu/drm/mediatek/mtk_dp.c
index eefbc7e0f9c8..2c738c16dafa 100644
--- a/drivers/gpu/drm/mediatek/mtk_dp.c
+++ b/drivers/gpu/drm/mediatek/mtk_dp.c
@@ -2670,6 +2670,13 @@ static const struct hdmi_codec_ops mtk_dp_audio_codec_ops = {
 	.hook_plugged_cb = mtk_dp_audio_hook_plugged_cb,
 };
 
+static void mtk_dp_unregister_pdevs(void *data)
+{
+	struct platform_device *ext_pdev = data;
+
+	platform_device_unregister(ext_pdev);
+}
+
 static int mtk_dp_register_audio_driver(struct device *dev)
 {
 	struct mtk_dp *mtk_dp = dev_get_drvdata(dev);
@@ -2680,18 +2687,29 @@ static int mtk_dp_register_audio_driver(struct device *dev)
 		.data = mtk_dp,
 		.no_capture_mute = 1,
 	};
+	int ret;
 
 	mtk_dp->audio_pdev = platform_device_register_data(dev,
 							   HDMI_CODEC_DRV_NAME,
 							   PLATFORM_DEVID_AUTO,
 							   &codec_data,
 							   sizeof(codec_data));
-	return PTR_ERR_OR_ZERO(mtk_dp->audio_pdev);
+	if (IS_ERR(mtk_dp->audio_pdev))
+		return PTR_ERR(mtk_dp->audio_pdev);
+
+	ret = devm_add_action_or_reset(dev, mtk_dp_unregister_pdevs, mtk_dp->phy_dev);
+	if (ret) {
+		platform_device_unregister(mtk_dp->audio_pdev);
+		return dev_err_probe(dev, ret,
+				     "Failed to add codec unregister devm action");
+	}
+	return 0;
 }
 
 static int mtk_dp_register_phy(struct mtk_dp *mtk_dp)
 {
 	struct device *dev = mtk_dp->dev;
+	int ret;
 
 	mtk_dp->phy_dev = platform_device_register_data(dev, "mediatek-dp-phy",
 							PLATFORM_DEVID_AUTO,
@@ -2701,6 +2719,13 @@ static int mtk_dp_register_phy(struct mtk_dp *mtk_dp)
 		return dev_err_probe(dev, PTR_ERR(mtk_dp->phy_dev),
 				     "Failed to create device mediatek-dp-phy\n");
 
+	ret = devm_add_action_or_reset(dev, mtk_dp_unregister_pdevs, mtk_dp->phy_dev);
+	if (ret) {
+		platform_device_unregister(mtk_dp->phy_dev);
+		return dev_err_probe(dev, ret,
+				     "Failed to add phy unregister devm action");
+	}
+
 	mtk_dp_get_calibration_data(mtk_dp);
 
 	mtk_dp->phy = devm_phy_get(&mtk_dp->phy_dev->dev, "dp");
@@ -2870,9 +2895,6 @@ static void mtk_dp_remove(struct platform_device *pdev)
 	pm_runtime_disable(&pdev->dev);
 	if (mtk_dp->data->bridge_type != DRM_MODE_CONNECTOR_eDP)
 		timer_delete_sync(&mtk_dp->debounce_timer);
-	platform_device_unregister(mtk_dp->phy_dev);
-	if (mtk_dp->audio_pdev)
-		platform_device_unregister(mtk_dp->audio_pdev);
 }
 
 #ifdef CONFIG_PM_SLEEP
-- 
2.54.0


^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [PATCH 04/11] drm/mediatek: mtk_dp: Clarify SMC eDP/DP video unmute commands
  2026-07-01 12:20 [PATCH 00/11] drm: MediaTek DisplayPort cleanups and MT8196 eDP AngeloGioacchino Del Regno
                   ` (2 preceding siblings ...)
  2026-07-01 12:20 ` [PATCH 03/11] drm/mediatek: mtk_dp: Fix hdmi codec and phy driver unregistration AngeloGioacchino Del Regno
@ 2026-07-01 12:20 ` AngeloGioacchino Del Regno
  2026-07-01 12:20 ` [PATCH 05/11] drm/mediatek: mtk_dp: Rework register offsets for proper PHY usage AngeloGioacchino Del Regno
                   ` (6 subsequent siblings)
  10 siblings, 0 replies; 20+ messages in thread
From: AngeloGioacchino Del Regno @ 2026-07-01 12:20 UTC (permalink / raw)
  To: chunkuang.hu
  Cc: p.zabel, airlied, simona, maarten.lankhorst, mripard, tzimmermann,
	robh, krzk+dt, conor+dt, matthias.bgg, angelogioacchino.delregno,
	jitao.shi, granquet, rex-bc.chen, dmitry.osipenko, ck.hu,
	amergnat, justin.yeh, jason-jh.lin, dri-devel, linux-mediatek,
	devicetree, linux-kernel, linux-arm-kernel, kernel

The eDP/DP video unmute commands are not expressed as bits:
instead, in the firmware, those are defined as incremental
unsigned integer numbers: use the correct representation of
those to improve readability.

This commit brings no functional changes.

Signed-off-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
---
 drivers/gpu/drm/mediatek/mtk_dp.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/mediatek/mtk_dp.c b/drivers/gpu/drm/mediatek/mtk_dp.c
index 2c738c16dafa..f551c4543f4e 100644
--- a/drivers/gpu/drm/mediatek/mtk_dp.c
+++ b/drivers/gpu/drm/mediatek/mtk_dp.c
@@ -36,8 +36,8 @@
 #include "mtk_dp_reg.h"
 
 #define MTK_DP_SIP_CONTROL_AARCH32	MTK_SIP_SMC_CMD(0x523)
-#define MTK_DP_SIP_ATF_EDP_VIDEO_UNMUTE	(BIT(0) | BIT(5))
-#define MTK_DP_SIP_ATF_VIDEO_UNMUTE	BIT(5)
+#define MTK_DP_SIP_ATF_EDP_VIDEO_UNMUTE	33
+#define MTK_DP_SIP_ATF_VIDEO_UNMUTE	32
 
 #define MTK_DP_THREAD_CABLE_STATE_CHG	BIT(0)
 #define MTK_DP_THREAD_HPD_EVENT		BIT(1)
-- 
2.54.0


^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [PATCH 05/11] drm/mediatek: mtk_dp: Rework register offsets for proper PHY usage
  2026-07-01 12:20 [PATCH 00/11] drm: MediaTek DisplayPort cleanups and MT8196 eDP AngeloGioacchino Del Regno
                   ` (3 preceding siblings ...)
  2026-07-01 12:20 ` [PATCH 04/11] drm/mediatek: mtk_dp: Clarify SMC eDP/DP video unmute commands AngeloGioacchino Del Regno
@ 2026-07-01 12:20 ` AngeloGioacchino Del Regno
  2026-07-01 12:45   ` sashiko-bot
  2026-07-01 12:20 ` [PATCH 06/11] drm/mediatek: mtk_dp: Use PHY API for PHY power sequences AngeloGioacchino Del Regno
                   ` (5 subsequent siblings)
  10 siblings, 1 reply; 20+ messages in thread
From: AngeloGioacchino Del Regno @ 2026-07-01 12:20 UTC (permalink / raw)
  To: chunkuang.hu
  Cc: p.zabel, airlied, simona, maarten.lankhorst, mripard, tzimmermann,
	robh, krzk+dt, conor+dt, matthias.bgg, angelogioacchino.delregno,
	jitao.shi, granquet, rex-bc.chen, dmitry.osipenko, ck.hu,
	amergnat, justin.yeh, jason-jh.lin, dri-devel, linux-mediatek,
	devicetree, linux-kernel, linux-arm-kernel, kernel

Rework all of the register offsets to subtract the DP PHY register
range from the MediaTek DisplayPort IP register range which starts
from TOP_OFFSET instead.

This is done in preparation for adding support for registering the
PHY from devicetree, and also for properly handling PHY registers
in the PHY driver (instead of half and half...), which is also one
prerogative to add support for new IP versions in the future.

Note that the current regmap_config was renamed to make sure that
it being legacy is mentioned, as a new config will be required in
future changes.

Of course, with the TOP offset being related to hardware registers
this will never change for the currently supported SoCs, hence for
simplifying code, the MTK_DP_TOP_OFFSET_LEGACY is added statically
to the legacy regmap configuration while, on the other hand, it is
added dynamically to the mtk_dp structure, as the latter is used
to add an offset to every register write in the mtk_dp driver.

The regmap_config provided reg_base (which does exactly the same)
cannot be used here, because the PHY driver is using the very same
regmap pointer, and the offset shall not be taken into account in
writes performed by the PHY driver (only ones performed by mtk_dp!).

Signed-off-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
---
 drivers/gpu/drm/mediatek/mtk_dp.c     |  60 ++++--
 drivers/gpu/drm/mediatek/mtk_dp_reg.h | 255 ++++++++++++--------------
 2 files changed, 164 insertions(+), 151 deletions(-)

diff --git a/drivers/gpu/drm/mediatek/mtk_dp.c b/drivers/gpu/drm/mediatek/mtk_dp.c
index f551c4543f4e..97bce8966a1f 100644
--- a/drivers/gpu/drm/mediatek/mtk_dp.c
+++ b/drivers/gpu/drm/mediatek/mtk_dp.c
@@ -35,6 +35,27 @@
 
 #include "mtk_dp_reg.h"
 
+/* PHY Registers - for legacy only */
+#define DP_PHY_GLB_BIAS_GEN_00		0x0
+#  define RG_XTP_GLB_BIAS_INTR_CTRL	GENMASK(20, 16)
+#define DP_PHY_GLB_DPAUX_TX		0x8
+#  define RG_CKM_PT0_CKTX_IMPSEL	GENMASK(23, 20)
+#define MTK_DP_0034			0x34
+#  define DA_CKM_CKTX0_EN_FORCE_EN	BIT(10)
+#define DP_PHY_LANE_TX_0		0x104
+#define DP_PHY_LANE_TX_1		0x204
+#define DP_PHY_LANE_TX_2		0x304
+#define DP_PHY_LANE_TX_3		0x404
+#  define RG_XTP_LNx_TX_IMPSEL_PMOS	GENMASK(15, 12)
+#  define RG_XTP_LNx_TX_IMPSEL_NMOS	GENMASK(19, 16)
+#define DP_PHY_AUX_RX_CTL		0x1040
+#  define RG_DPAUX_RX_VALID_DEGLITCH_EN	BIT(2)
+#  define RG_XTP_GLB_CKDET_EN		BIT(1)
+#  define RG_DPAUX_RX_EN		BIT(0)
+
+/* TOP Register offset - for legacy only */
+#define MTK_DP_TOP_OFFSET_LEGACY	0x2000
+
 #define MTK_DP_SIP_CONTROL_AARCH32	MTK_SIP_SMC_CMD(0x523)
 #define MTK_DP_SIP_ATF_EDP_VIDEO_UNMUTE	33
 #define MTK_DP_SIP_ATF_VIDEO_UNMUTE	32
@@ -126,6 +147,9 @@ struct mtk_dp {
 	struct regmap *regs;
 	struct timer_list debounce_timer;
 
+	/* For legacy devicetree compatibility */
+	u16 legacy_regoff;
+
 	/* For audio */
 	bool audio_enable;
 	hdmi_codec_plugged_cb plugged_cb;
@@ -394,11 +418,11 @@ static const struct mtk_dp_efuse_fmt mt8195_dp_efuse_fmt[MTK_DP_CAL_MAX] = {
 	},
 };
 
-static const struct regmap_config mtk_dp_regmap_config = {
+static const struct regmap_config mtk_dp_regmap_legacy_config = {
 	.reg_bits = 32,
 	.val_bits = 32,
 	.reg_stride = 4,
-	.max_register = SEC_OFFSET + 0x90,
+	.max_register = MTK_DP_TOP_OFFSET_LEGACY + SEC_OFFSET + 0x90,
 	.name = "mtk-dp-registers",
 };
 
@@ -412,7 +436,7 @@ static u32 mtk_dp_read(struct mtk_dp *mtk_dp, u32 offset)
 	u32 read_val;
 	int ret;
 
-	ret = regmap_read(mtk_dp->regs, offset, &read_val);
+	ret = regmap_read(mtk_dp->regs, offset + mtk_dp->legacy_regoff, &read_val);
 	if (ret) {
 		dev_err(mtk_dp->dev, "Failed to read register 0x%x: %d\n",
 			offset, ret);
@@ -424,7 +448,7 @@ static u32 mtk_dp_read(struct mtk_dp *mtk_dp, u32 offset)
 
 static int mtk_dp_write(struct mtk_dp *mtk_dp, u32 offset, u32 val)
 {
-	int ret = regmap_write(mtk_dp->regs, offset, val);
+	int ret = regmap_write(mtk_dp->regs, offset + mtk_dp->legacy_regoff, val);
 
 	if (ret)
 		dev_err(mtk_dp->dev,
@@ -436,7 +460,7 @@ static int mtk_dp_write(struct mtk_dp *mtk_dp, u32 offset, u32 val)
 static int mtk_dp_update_bits(struct mtk_dp *mtk_dp, u32 offset,
 			      u32 val, u32 mask)
 {
-	int ret = regmap_update_bits(mtk_dp->regs, offset, mask, val);
+	int ret = regmap_update_bits(mtk_dp->regs, offset + mtk_dp->legacy_regoff, mask, val);
 
 	if (ret)
 		dev_err(mtk_dp->dev,
@@ -1229,28 +1253,28 @@ static void mtk_dp_set_calibration_data(struct mtk_dp *mtk_dp)
 			   RG_XTP_GLB_BIAS_INTR_CTRL);
 	mtk_dp_update_bits(mtk_dp, DP_PHY_LANE_TX_0,
 			   cal_data[MTK_DP_CAL_LN_TX_IMPSEL_PMOS_0] << 12,
-			   RG_XTP_LN0_TX_IMPSEL_PMOS);
+			   RG_XTP_LNx_TX_IMPSEL_PMOS);
 	mtk_dp_update_bits(mtk_dp, DP_PHY_LANE_TX_0,
 			   cal_data[MTK_DP_CAL_LN_TX_IMPSEL_NMOS_0] << 16,
-			   RG_XTP_LN0_TX_IMPSEL_NMOS);
+			   RG_XTP_LNx_TX_IMPSEL_NMOS);
 	mtk_dp_update_bits(mtk_dp, DP_PHY_LANE_TX_1,
 			   cal_data[MTK_DP_CAL_LN_TX_IMPSEL_PMOS_1] << 12,
-			   RG_XTP_LN1_TX_IMPSEL_PMOS);
+			   RG_XTP_LNx_TX_IMPSEL_PMOS);
 	mtk_dp_update_bits(mtk_dp, DP_PHY_LANE_TX_1,
 			   cal_data[MTK_DP_CAL_LN_TX_IMPSEL_NMOS_1] << 16,
-			   RG_XTP_LN1_TX_IMPSEL_NMOS);
+			   RG_XTP_LNx_TX_IMPSEL_NMOS);
 	mtk_dp_update_bits(mtk_dp, DP_PHY_LANE_TX_2,
 			   cal_data[MTK_DP_CAL_LN_TX_IMPSEL_PMOS_2] << 12,
-			   RG_XTP_LN2_TX_IMPSEL_PMOS);
+			   RG_XTP_LNx_TX_IMPSEL_PMOS);
 	mtk_dp_update_bits(mtk_dp, DP_PHY_LANE_TX_2,
 			   cal_data[MTK_DP_CAL_LN_TX_IMPSEL_NMOS_2] << 16,
-			   RG_XTP_LN2_TX_IMPSEL_NMOS);
+			   RG_XTP_LNx_TX_IMPSEL_NMOS);
 	mtk_dp_update_bits(mtk_dp, DP_PHY_LANE_TX_3,
 			   cal_data[MTK_DP_CAL_LN_TX_IMPSEL_PMOS_3] << 12,
-			   RG_XTP_LN3_TX_IMPSEL_PMOS);
+			   RG_XTP_LNx_TX_IMPSEL_PMOS);
 	mtk_dp_update_bits(mtk_dp, DP_PHY_LANE_TX_3,
 			   cal_data[MTK_DP_CAL_LN_TX_IMPSEL_NMOS_3] << 16,
-			   RG_XTP_LN3_TX_IMPSEL_NMOS);
+			   RG_XTP_LNx_TX_IMPSEL_NMOS);
 }
 
 static int mtk_dp_phy_configure(struct mtk_dp *mtk_dp,
@@ -1401,7 +1425,7 @@ static void mtk_dp_power_enable(struct mtk_dp *mtk_dp)
 			   SW_RST_B_PHYD, SW_RST_B_PHYD);
 	mtk_dp_update_bits(mtk_dp, MTK_DP_TOP_PWR_STATE,
 			   DP_PWR_STATE_BANDGAP_TPLL, DP_PWR_STATE_MASK);
-	mtk_dp_write(mtk_dp, MTK_DP_1040,
+	mtk_dp_write(mtk_dp, DP_PHY_AUX_RX_CTL,
 		     RG_DPAUX_RX_VALID_DEGLITCH_EN | RG_XTP_GLB_CKDET_EN |
 		     RG_DPAUX_RX_EN);
 	mtk_dp_update_bits(mtk_dp, MTK_DP_0034, 0, DA_CKM_CKTX0_EN_FORCE_EN);
@@ -1415,7 +1439,7 @@ static void mtk_dp_power_disable(struct mtk_dp *mtk_dp)
 			   DA_CKM_CKTX0_EN_FORCE_EN, DA_CKM_CKTX0_EN_FORCE_EN);
 
 	/* Disable RX */
-	mtk_dp_write(mtk_dp, MTK_DP_1040, 0);
+	mtk_dp_write(mtk_dp, DP_PHY_AUX_RX_CTL, 0);
 	mtk_dp_write(mtk_dp, MTK_DP_TOP_MEM_PD,
 		     0x550 | FUSE_SEL | MEM_ISO_EN);
 }
@@ -2067,7 +2091,8 @@ static int mtk_dp_wait_hpd_asserted(struct drm_dp_aux *mtk_aux, unsigned long wa
 	u32 val;
 	int ret;
 
-	ret = regmap_read_poll_timeout(mtk_dp->regs, MTK_DP_TRANS_P0_3414,
+	ret = regmap_read_poll_timeout(mtk_dp->regs,
+				       MTK_DP_TRANS_P0_3414 + mtk_dp->legacy_regoff,
 				       val, !!(val & HPD_DB_DP_TRANS_P0_MASK),
 				       wait_us / 100, wait_us);
 	if (ret) {
@@ -2100,7 +2125,7 @@ static int mtk_dp_dt_parse(struct mtk_dp *mtk_dp,
 	if (IS_ERR(base))
 		return PTR_ERR(base);
 
-	mtk_dp->regs = devm_regmap_init_mmio(dev, base, &mtk_dp_regmap_config);
+	mtk_dp->regs = devm_regmap_init_mmio(dev, base, &mtk_dp_regmap_legacy_config);
 	if (IS_ERR(mtk_dp->regs))
 		return PTR_ERR(mtk_dp->regs);
 
@@ -2778,6 +2803,7 @@ static int mtk_dp_probe(struct platform_device *pdev)
 
 	mtk_dp->dev = dev;
 	mtk_dp->data = (struct mtk_dp_data *)of_device_get_match_data(dev);
+	mtk_dp->legacy_regoff = MTK_DP_TOP_OFFSET_LEGACY;
 
 	ret = mtk_dp_dt_parse(mtk_dp, pdev);
 	if (ret)
diff --git a/drivers/gpu/drm/mediatek/mtk_dp_reg.h b/drivers/gpu/drm/mediatek/mtk_dp_reg.h
index 8ad7a9cc259e..616ea6440b08 100644
--- a/drivers/gpu/drm/mediatek/mtk_dp_reg.h
+++ b/drivers/gpu/drm/mediatek/mtk_dp_reg.h
@@ -2,62 +2,22 @@
 /*
  * Copyright (c) 2019-2022 MediaTek Inc.
  * Copyright (c) 2022 BayLibre
+ * Copyright (c) 2026 Collabora Ltd.
  */
 #ifndef _MTK_DP_REG_H_
 #define _MTK_DP_REG_H_
 
-#define SEC_OFFSET	0x4000
-
 #define MTK_DP_HPD_DISCONNECT		BIT(1)
 #define MTK_DP_HPD_CONNECT		BIT(2)
 #define MTK_DP_HPD_INTERRUPT		BIT(3)
 
-/* offset: 0x0 */
-#define DP_PHY_GLB_BIAS_GEN_00		0x0
-#define RG_XTP_GLB_BIAS_INTR_CTRL		GENMASK(20, 16)
-#define DP_PHY_GLB_DPAUX_TX		0x8
-#define RG_CKM_PT0_CKTX_IMPSEL			GENMASK(23, 20)
-#define MTK_DP_0034			0x34
-#define DA_XTP_GLB_CKDET_EN_FORCE_VAL		BIT(15)
-#define DA_XTP_GLB_CKDET_EN_FORCE_EN		BIT(14)
-#define DA_CKM_INTCKTX_EN_FORCE_VAL		BIT(13)
-#define DA_CKM_INTCKTX_EN_FORCE_EN		BIT(12)
-#define DA_CKM_CKTX0_EN_FORCE_VAL		BIT(11)
-#define DA_CKM_CKTX0_EN_FORCE_EN		BIT(10)
-#define DA_CKM_XTAL_CK_FORCE_VAL		BIT(9)
-#define DA_CKM_XTAL_CK_FORCE_EN			BIT(8)
-#define DA_CKM_BIAS_LPF_EN_FORCE_VAL		BIT(7)
-#define DA_CKM_BIAS_LPF_EN_FORCE_EN		BIT(6)
-#define DA_CKM_BIAS_EN_FORCE_VAL		BIT(5)
-#define DA_CKM_BIAS_EN_FORCE_EN			BIT(4)
-#define DA_XTP_GLB_AVD10_ON_FORCE_VAL		BIT(3)
-#define DA_XTP_GLB_AVD10_ON_FORCE		BIT(2)
-#define DA_XTP_GLB_LDO_EN_FORCE_VAL		BIT(1)
-#define DA_XTP_GLB_LDO_EN_FORCE_EN		BIT(0)
-#define DP_PHY_LANE_TX_0		0x104
-#define RG_XTP_LN0_TX_IMPSEL_PMOS		GENMASK(15, 12)
-#define RG_XTP_LN0_TX_IMPSEL_NMOS		GENMASK(19, 16)
-#define DP_PHY_LANE_TX_1		0x204
-#define RG_XTP_LN1_TX_IMPSEL_PMOS		GENMASK(15, 12)
-#define RG_XTP_LN1_TX_IMPSEL_NMOS		GENMASK(19, 16)
-#define DP_PHY_LANE_TX_2		0x304
-#define RG_XTP_LN2_TX_IMPSEL_PMOS		GENMASK(15, 12)
-#define RG_XTP_LN2_TX_IMPSEL_NMOS		GENMASK(19, 16)
-#define DP_PHY_LANE_TX_3		0x404
-#define RG_XTP_LN3_TX_IMPSEL_PMOS		GENMASK(15, 12)
-#define RG_XTP_LN3_TX_IMPSEL_NMOS		GENMASK(19, 16)
-#define MTK_DP_1040			0x1040
-#define RG_DPAUX_RX_VALID_DEGLITCH_EN		BIT(2)
-#define RG_XTP_GLB_CKDET_EN			BIT(1)
-#define RG_DPAUX_RX_EN				BIT(0)
-
-/* offset: TOP_OFFSET (0x2000) */
-#define MTK_DP_TOP_PWR_STATE		0x2000
+/* offset: TOP_OFFSET (0x0) */
+#define MTK_DP_TOP_PWR_STATE		0x0
 #define DP_PWR_STATE_MASK			GENMASK(1, 0)
 #define DP_PWR_STATE_BANDGAP			BIT(0)
 #define DP_PWR_STATE_BANDGAP_TPLL		BIT(1)
 #define DP_PWR_STATE_BANDGAP_TPLL_LANE		GENMASK(1, 0)
-#define MTK_DP_TOP_SWING_EMP		0x2004
+#define MTK_DP_TOP_SWING_EMP		0x4
 #define DP_TX0_VOLT_SWING_MASK			GENMASK(1, 0)
 #define DP_TX0_VOLT_SWING_SHIFT			0
 #define DP_TX0_PRE_EMPH_MASK			GENMASK(3, 2)
@@ -69,43 +29,59 @@
 #define DP_TX2_PRE_EMPH_MASK			GENMASK(19, 18)
 #define DP_TX3_VOLT_SWING_MASK			GENMASK(25, 24)
 #define DP_TX3_PRE_EMPH_MASK			GENMASK(27, 26)
-#define MTK_DP_TOP_RESET_AND_PROBE	0x2020
+#define MTK_DP_TOP_RESET_AND_PROBE	0x20
 #define SW_RST_B_PHYD				BIT(4)
-#define MTK_DP_TOP_IRQ_MASK		0x202c
+#define RG_SW_RST_MASK				GENMASK(7, 0)
+#define RG_SW_RST				0xff
+#define RG_PROBE_LOW_SEL_MASK			GENMASK(18, 16)
+#define RG_PROBE_LOW_SEL			BIT(16)
+#define RG_PROBE_LOW_HIGH_SWAP_MASK		BIT(23)
+#define RG_PROBE_LOW_HIGH_SWAP			BIT(23)
+
+#define MTK_DP_TOP_IRQ_MASK		0x2c
+#define ENCODER_IRQ_MSK				BIT(0)
+#define TRANS_IRQ_MSK				BIT(1)
 #define IRQ_MASK_AUX_TOP_IRQ			BIT(2)
-#define MTK_DP_TOP_MEM_PD		0x2038
+
+#define MTK_DP_TOP_MEM_PD		0x38
 #define MEM_ISO_EN				BIT(0)
 #define FUSE_SEL				BIT(2)
 
-/* offset: ENC0_OFFSET (0x3000) */
-#define MTK_DP_ENC0_P0_3000			0x3000
+#define EDP_TX_TOP_CLKGEN_0		0x74
+#define EDP_TX_TOP_CLKGEN_REST_MASK		0xf
+#define EDP_TX_TOP_CLKGEN_REST_VALUE		0xf
+
+/* offset: ENC0_OFFSET (0x1000) */
+#define MTK_DP_ENC0_P0_3000			0x1000
 #define LANE_NUM_DP_ENC0_P0_MASK			GENMASK(1, 0)
 #define VIDEO_MUTE_SW_DP_ENC0_P0			BIT(2)
 #define VIDEO_MUTE_SEL_DP_ENC0_P0			BIT(3)
 #define ENHANCED_FRAME_EN_DP_ENC0_P0			BIT(4)
-#define MTK_DP_ENC0_P0_3004			0x3004
+#define DP_I_MODE_ENABLE				BIT(6)
+#define REG_BS_SYMBOL_CNT_RESET				BIT(7)
+#define MTK_DP_ENC0_P0_3004			0x1004
 #define VIDEO_M_CODE_SEL_DP_ENC0_P0_MASK		BIT(8)
 #define DP_TX_ENCODER_4P_RESET_SW_DP_ENC0_P0		BIT(9)
 #define SDP_RESET_SW_DP_ENC0_P0				BIT(13)
-#define MTK_DP_ENC0_P0_3010			0x3010
+#define MTK_DP_ENC0_P0_3010			0x1010
 #define HTOTAL_SW_DP_ENC0_P0_MASK			GENMASK(15, 0)
-#define MTK_DP_ENC0_P0_3014			0x3014
+#define MTK_DP_ENC0_P0_3014			0x1014
 #define VTOTAL_SW_DP_ENC0_P0_MASK			GENMASK(15, 0)
-#define MTK_DP_ENC0_P0_3018			0x3018
+#define MTK_DP_ENC0_P0_3018			0x1018
 #define HSTART_SW_DP_ENC0_P0_MASK			GENMASK(15, 0)
-#define MTK_DP_ENC0_P0_301C			0x301c
+#define MTK_DP_ENC0_P0_301C			0x101c
 #define VSTART_SW_DP_ENC0_P0_MASK			GENMASK(15, 0)
-#define MTK_DP_ENC0_P0_3020			0x3020
+#define MTK_DP_ENC0_P0_3020			0x1020
 #define HWIDTH_SW_DP_ENC0_P0_MASK			GENMASK(15, 0)
-#define MTK_DP_ENC0_P0_3024			0x3024
+#define MTK_DP_ENC0_P0_3024			0x1024
 #define VHEIGHT_SW_DP_ENC0_P0_MASK			GENMASK(15, 0)
-#define MTK_DP_ENC0_P0_3028			0x3028
+#define MTK_DP_ENC0_P0_3028			0x1028
 #define HSW_SW_DP_ENC0_P0_MASK				GENMASK(14, 0)
 #define HSP_SW_DP_ENC0_P0_MASK				BIT(15)
-#define MTK_DP_ENC0_P0_302C			0x302c
+#define MTK_DP_ENC0_P0_302C			0x102c
 #define VSW_SW_DP_ENC0_P0_MASK				GENMASK(14, 0)
 #define VSP_SW_DP_ENC0_P0_MASK				BIT(15)
-#define MTK_DP_ENC0_P0_3030			0x3030
+#define MTK_DP_ENC0_P0_3030			0x1030
 #define HTOTAL_SEL_DP_ENC0_P0				BIT(0)
 #define VTOTAL_SEL_DP_ENC0_P0				BIT(1)
 #define HSTART_SEL_DP_ENC0_P0				BIT(2)
@@ -118,10 +94,10 @@
 #define VSW_SEL_DP_ENC0_P0				BIT(9)
 #define VBID_AUDIO_MUTE_FLAG_SW_DP_ENC0_P0		BIT(11)
 #define VBID_AUDIO_MUTE_FLAG_SEL_DP_ENC0_P0		BIT(12)
-#define MTK_DP_ENC0_P0_3034			0x3034
-#define MTK_DP_ENC0_P0_3038			0x3038
+#define MTK_DP_ENC0_P0_3034			0x1034
+#define MTK_DP_ENC0_P0_3038			0x1038
 #define VIDEO_SOURCE_SEL_DP_ENC0_P0_MASK		BIT(11)
-#define MTK_DP_ENC0_P0_303C			0x303c
+#define MTK_DP_ENC0_P0_303C			0x103c
 #define SRAM_START_READ_THRD_DP_ENC0_P0_MASK		GENMASK(5, 0)
 #define VIDEO_COLOR_DEPTH_DP_ENC0_P0_MASK		GENMASK(10, 8)
 #define VIDEO_COLOR_DEPTH_DP_ENC0_P0_16BIT		(0 << 8)
@@ -130,34 +106,36 @@
 #define VIDEO_COLOR_DEPTH_DP_ENC0_P0_8BIT		(3 << 8)
 #define VIDEO_COLOR_DEPTH_DP_ENC0_P0_6BIT		(4 << 8)
 #define PIXEL_ENCODE_FORMAT_DP_ENC0_P0_MASK		GENMASK(14, 12)
-#define PIXEL_ENCODE_FORMAT_DP_ENC0_P0_RGB		(0 << 12)
-#define PIXEL_ENCODE_FORMAT_DP_ENC0_P0_YCBCR422		(1 << 12)
-#define PIXEL_ENCODE_FORMAT_DP_ENC0_P0_YCBCR420		(2 << 12)
+#  define PIXEL_ENCODE_FORMAT_DP_ENC0_P0_RGB		0
+#  define PIXEL_ENCODE_FORMAT_DP_ENC0_P0_YCBCR422	1
+#  define PIXEL_ENCODE_FORMAT_DP_ENC0_P0_YCBCR420	2
+#  define PIXEL_ENCODE_FORMAT_DP_ENC0_P0_YONLY		3
+#  define PIXEL_ENCODE_FORMAT_DP_ENC0_P0_RAW		4
 #define VIDEO_MN_GEN_EN_DP_ENC0_P0			BIT(15)
-#define MTK_DP_ENC0_P0_3040			0x3040
+#define MTK_DP_ENC0_P0_3040			0x1040
 #define SDP_DOWN_CNT_DP_ENC0_P0_VAL			0x20
 #define SDP_DOWN_CNT_INIT_DP_ENC0_P0_MASK		GENMASK(11, 0)
-#define MTK_DP_ENC0_P0_304C			0x304c
+#define MTK_DP_ENC0_P0_304C			0x104c
 #define VBID_VIDEO_MUTE_DP_ENC0_P0_MASK			BIT(2)
 #define SDP_VSYNC_RISING_MASK_DP_ENC0_P0_MASK		BIT(8)
-#define MTK_DP_ENC0_P0_3064			0x3064
+#define MTK_DP_ENC0_P0_3064			0x1064
 #define HDE_NUM_LAST_DP_ENC0_P0_MASK			GENMASK(15, 0)
-#define MTK_DP_ENC0_P0_3088			0x3088
+#define MTK_DP_ENC0_P0_3088			0x1088
 #define AU_EN_DP_ENC0_P0				BIT(6)
 #define AUDIO_8CH_EN_DP_ENC0_P0_MASK			BIT(7)
 #define AUDIO_8CH_SEL_DP_ENC0_P0_MASK			BIT(8)
 #define AUDIO_2CH_EN_DP_ENC0_P0_MASK			BIT(14)
 #define AUDIO_2CH_SEL_DP_ENC0_P0_MASK			BIT(15)
-#define MTK_DP_ENC0_P0_308C			0x308c
+#define MTK_DP_ENC0_P0_308C			0x108c
 #define CH_STATUS_0_DP_ENC0_P0_MASK			GENMASK(15, 0)
-#define MTK_DP_ENC0_P0_3090			0x3090
+#define MTK_DP_ENC0_P0_3090			0x1090
 #define CH_STATUS_1_DP_ENC0_P0_MASK			GENMASK(15, 0)
-#define MTK_DP_ENC0_P0_3094			0x3094
+#define MTK_DP_ENC0_P0_3094			0x1094
 #define CH_STATUS_2_DP_ENC0_P0_MASK			GENMASK(7, 0)
-#define MTK_DP_ENC0_P0_30A4			0x30a4
+#define MTK_DP_ENC0_P0_30A4			0x10a4
 #define AU_TS_CFG_DP_ENC0_P0_MASK			GENMASK(7, 0)
-#define MTK_DP_ENC0_P0_30A8			0x30a8
-#define MTK_DP_ENC0_P0_30BC			0x30bc
+#define MTK_DP_ENC0_P0_30A8			0x10a8
+#define MTK_DP_ENC0_P0_30BC			0x10bc
 #define ISRC_CONT_DP_ENC0_P0				BIT(0)
 #define AUDIO_M_CODE_MULT_DIV_SEL_DP_ENC0_P0_MASK	GENMASK(10, 8)
 #define MT8195_AUDIO_M_CODE_MULT_DIV_SEL_DP_ENC0_P0_MUL_2	(1 << 8)
@@ -172,63 +150,65 @@
 #define MT8188_AUDIO_M_CODE_MULT_DIV_SEL_DP_ENC0_P0_DIV_2	(4 << 8)
 #define MT8188_AUDIO_M_CODE_MULT_DIV_SEL_DP_ENC0_P0_DIV_4	(5 << 8)
 #define MT8188_AUDIO_M_CODE_MULT_DIV_SEL_DP_ENC0_P0_DIV_8	(7 << 8)
-#define MTK_DP_ENC0_P0_30D8			0x30d8
-#define MTK_DP_ENC0_P0_312C			0x312c
+#define MTK_DP_ENC0_P0_30D8			0x10d8
+#define MTK_DP_ENC0_P0_312C			0x112c
 #define ASP_HB2_DP_ENC0_P0_MASK				GENMASK(7, 0)
 #define ASP_HB3_DP_ENC0_P0_MASK				GENMASK(15, 8)
-#define MTK_DP_ENC0_P0_3154			0x3154
+#define MTK_DP_ENC0_P0_3154			0x1154
 #define PGEN_HTOTAL_DP_ENC0_P0_MASK			GENMASK(13, 0)
-#define MTK_DP_ENC0_P0_3158			0x3158
+#define MTK_DP_ENC0_P0_3158			0x1158
 #define PGEN_HSYNC_RISING_DP_ENC0_P0_MASK		GENMASK(13, 0)
-#define MTK_DP_ENC0_P0_315C			0x315c
+#define MTK_DP_ENC0_P0_315C			0x115c
 #define PGEN_HSYNC_PULSE_WIDTH_DP_ENC0_P0_MASK		GENMASK(13, 0)
-#define MTK_DP_ENC0_P0_3160			0x3160
+#define MTK_DP_ENC0_P0_3160			0x1160
 #define PGEN_HFDE_START_DP_ENC0_P0_MASK			GENMASK(13, 0)
-#define MTK_DP_ENC0_P0_3164			0x3164
+#define MTK_DP_ENC0_P0_3164			0x1164
 #define PGEN_HFDE_ACTIVE_WIDTH_DP_ENC0_P0_MASK		GENMASK(13, 0)
-#define MTK_DP_ENC0_P0_3168			0x3168
+#define MTK_DP_ENC0_P0_3168			0x1168
 #define PGEN_VTOTAL_DP_ENC0_P0_MASK			GENMASK(12, 0)
-#define MTK_DP_ENC0_P0_316C			0x316c
+#define MTK_DP_ENC0_P0_316C			0x116c
 #define PGEN_VSYNC_RISING_DP_ENC0_P0_MASK		GENMASK(12, 0)
-#define MTK_DP_ENC0_P0_3170			0x3170
+#define MTK_DP_ENC0_P0_3170			0x1170
 #define PGEN_VSYNC_PULSE_WIDTH_DP_ENC0_P0_MASK		GENMASK(12, 0)
-#define MTK_DP_ENC0_P0_3174			0x3174
+#define MTK_DP_ENC0_P0_3174			0x1174
 #define PGEN_VFDE_START_DP_ENC0_P0_MASK			GENMASK(12, 0)
-#define MTK_DP_ENC0_P0_3178			0x3178
+#define MTK_DP_ENC0_P0_3178			0x1178
 #define PGEN_VFDE_ACTIVE_WIDTH_DP_ENC0_P0_MASK		GENMASK(12, 0)
-#define MTK_DP_ENC0_P0_31B0			0x31b0
+#define MTK_DP_ENC0_P0_31B0			0x11b0
 #define PGEN_PATTERN_SEL_VAL				4
 #define PGEN_PATTERN_SEL_MASK				GENMASK(6, 4)
-#define MTK_DP_ENC0_P0_31EC			0x31ec
+#define MTK_DP_ENC0_P0_31EC			0x11ec
 #define AUDIO_CH_SRC_SEL_DP_ENC0_P0			BIT(4)
 #define ISRC1_HB3_DP_ENC0_P0_MASK			GENMASK(15, 8)
 
-/* offset: ENC1_OFFSET (0x3200) */
-#define MTK_DP_ENC1_P0_3200			0x3200
-#define MTK_DP_ENC1_P0_3280			0x3280
+/* offset: ENC1_OFFSET (0x1200) */
+#define MTK_DP_ENC1_P0_3200			0x1200
+#define MTK_DP_ENC1_P0_3280			0x1280
 #define SDP_PACKET_TYPE_DP_ENC1_P0_MASK			GENMASK(4, 0)
 #define SDP_PACKET_W_DP_ENC1_P0				BIT(5)
 #define SDP_PACKET_W_DP_ENC1_P0_MASK			BIT(5)
-#define MTK_DP_ENC1_P0_3300			0x3300
+#define MTK_DP_ENC1_P0_3300			0x1300
 #define VIDEO_AFIFO_RDY_SEL_DP_ENC1_P0_VAL		2
 #define VIDEO_AFIFO_RDY_SEL_DP_ENC1_P0_MASK		GENMASK(9, 8)
-#define MTK_DP_ENC1_P0_3304			0x3304
+#define MTK_DP_ENC1_P0_3304			0x1304
 #define AU_PRTY_REGEN_DP_ENC1_P0_MASK			BIT(8)
 #define AU_CH_STS_REGEN_DP_ENC1_P0_MASK			BIT(9)
 #define AUDIO_SAMPLE_PRSENT_REGEN_DP_ENC1_P0_MASK	BIT(12)
-#define MTK_DP_ENC1_P0_3324			0x3324
+#define MTK_DP_ENC1_P0_3324			0x1324
 #define AUDIO_SOURCE_MUX_DP_ENC1_P0_MASK		GENMASK(9, 8)
 #define AUDIO_SOURCE_MUX_DP_ENC1_P0_DPRX		0
-#define MTK_DP_ENC1_P0_3364			0x3364
+#define MTK_DP_ENC1_P0_3364			0x1364
 #define SDP_DOWN_CNT_IN_HBLANK_DP_ENC1_P0_VAL		0x20
 #define SDP_DOWN_CNT_INIT_IN_HBLANK_DP_ENC1_P0_MASK	GENMASK(11, 0)
 #define FIFO_READ_START_POINT_DP_ENC1_P0_VAL		4
 #define FIFO_READ_START_POINT_DP_ENC1_P0_MASK		GENMASK(15, 12)
-#define MTK_DP_ENC1_P0_3368			0x3368
+#define MTK_DP_ENC1_P0_3368			0x1368
 #define VIDEO_SRAM_FIFO_CNT_RESET_SEL_DP_ENC1_P0	BIT(0)
+#define VIDEO_SRAM_FIFO_CNT_RESET_SEL_MASK		GENMASK(1, 0)
 #define VIDEO_STABLE_CNT_THRD_DP_ENC1_P0		BIT(4)
 #define SDP_DP13_EN_DP_ENC1_P0				BIT(8)
 #define BS2BS_MODE_DP_ENC1_P0				BIT(12)
+#define BS_FOLLOW_SEL_DP_ENC0_P0			BIT(15)
 #define BS2BS_MODE_DP_ENC1_P0_MASK			GENMASK(13, 12)
 #define BS2BS_MODE_DP_ENC1_P0_VAL			1
 #define DP_ENC1_P0_3368_VAL				(VIDEO_SRAM_FIFO_CNT_RESET_SEL_DP_ENC1_P0 | \
@@ -236,94 +216,94 @@
 							 SDP_DP13_EN_DP_ENC1_P0 | \
 							 BS2BS_MODE_DP_ENC1_P0)
 
-#define MTK_DP_ENC1_P0_3374			0x3374
+#define MTK_DP_ENC1_P0_3374			0x1374
 #define SDP_ASP_INSERT_IN_HBLANK_DP_ENC1_P0_MASK	BIT(12)
 #define SDP_DOWN_ASP_CNT_INIT_DP_ENC1_P0_MASK		GENMASK(11, 0)
 
-#define MTK_DP_ENC1_P0_33F4			0x33f4
+#define MTK_DP_ENC1_P0_33F4			0x13f4
 #define DP_ENC_DUMMY_RW_1_AUDIO_RST_EN			BIT(0)
 #define DP_ENC_DUMMY_RW_1				BIT(9)
 
-/* offset: TRANS_OFFSET (0x3400) */
-#define MTK_DP_TRANS_P0_3400				0x3400
+/* offset: TRANS_OFFSET (0x1400) */
+#define MTK_DP_TRANS_P0_3400				0x1400
 #define PATTERN1_EN_DP_TRANS_P0_MASK				BIT(12)
 #define PATTERN2_EN_DP_TRANS_P0_MASK				BIT(13)
 #define PATTERN3_EN_DP_TRANS_P0_MASK				BIT(14)
 #define PATTERN4_EN_DP_TRANS_P0_MASK				BIT(15)
-#define MTK_DP_TRANS_P0_3404				0x3404
+#define MTK_DP_TRANS_P0_3404				0x1404
 #define DP_SCR_EN_DP_TRANS_P0_MASK				BIT(0)
-#define MTK_DP_TRANS_P0_340C				0x340c
+#define MTK_DP_TRANS_P0_340C				0x140c
 #define DP_TX_TRANSMITTER_4P_RESET_SW_DP_TRANS_P0		BIT(13)
-#define MTK_DP_TRANS_P0_3410				0x3410
+#define MTK_DP_TRANS_P0_3410				0x1410
 #define HPD_DEB_THD_DP_TRANS_P0_MASK				GENMASK(3, 0)
 #define HPD_INT_THD_DP_TRANS_P0_MASK				GENMASK(7, 4)
 #define HPD_INT_THD_DP_TRANS_P0_LOWER_500US			(2 << 4)
 #define HPD_INT_THD_DP_TRANS_P0_UPPER_1100US			(2 << 6)
 #define HPD_DISC_THD_DP_TRANS_P0_MASK				GENMASK(11, 8)
 #define HPD_CONN_THD_DP_TRANS_P0_MASK				GENMASK(15, 12)
-#define MTK_DP_TRANS_P0_3414				0x3414
+#define MTK_DP_TRANS_P0_3414				0x1414
 #define HPD_DB_DP_TRANS_P0_MASK					BIT(2)
-#define MTK_DP_TRANS_P0_3418				0x3418
+#define MTK_DP_TRANS_P0_3418				0x1418
 #define IRQ_CLR_DP_TRANS_P0_MASK				GENMASK(3, 0)
 #define IRQ_MASK_DP_TRANS_P0_MASK				GENMASK(7, 4)
 #define IRQ_MASK_DP_TRANS_P0_DISC_IRQ				(BIT(1) << 4)
 #define IRQ_MASK_DP_TRANS_P0_CONN_IRQ				(BIT(2) << 4)
 #define IRQ_MASK_DP_TRANS_P0_INT_IRQ				(BIT(3) << 4)
 #define IRQ_STATUS_DP_TRANS_P0_MASK				GENMASK(15, 12)
-#define MTK_DP_TRANS_P0_342C				0x342c
+#define MTK_DP_TRANS_P0_342C				0x142c
 #define XTAL_FREQ_DP_TRANS_P0_DEFAULT				(BIT(0) | BIT(3) | BIT(5) | BIT(6))
 #define XTAL_FREQ_DP_TRANS_P0_MASK				GENMASK(7, 0)
-#define MTK_DP_TRANS_P0_3430				0x3430
+#define MTK_DP_TRANS_P0_3430				0x1430
 #define HPD_INT_THD_ECO_DP_TRANS_P0_MASK			GENMASK(1, 0)
 #define HPD_INT_THD_ECO_DP_TRANS_P0_HIGH_BOUND_EXT		BIT(1)
-#define MTK_DP_TRANS_P0_34A4				0x34a4
+#define MTK_DP_TRANS_P0_34A4				0x14a4
 #define LANE_NUM_DP_TRANS_P0_MASK				GENMASK(3, 2)
-#define MTK_DP_TRANS_P0_3540				0x3540
+#define MTK_DP_TRANS_P0_3540				0x1540
 #define FEC_EN_DP_TRANS_P0_MASK					BIT(0)
 #define FEC_CLOCK_EN_MODE_DP_TRANS_P0				BIT(3)
-#define MTK_DP_TRANS_P0_3580				0x3580
+#define MTK_DP_TRANS_P0_3580				0x1580
 #define POST_MISC_DATA_LANE0_OV_DP_TRANS_P0_MASK		BIT(8)
 #define POST_MISC_DATA_LANE1_OV_DP_TRANS_P0_MASK		BIT(9)
 #define POST_MISC_DATA_LANE2_OV_DP_TRANS_P0_MASK		BIT(10)
 #define POST_MISC_DATA_LANE3_OV_DP_TRANS_P0_MASK		BIT(11)
-#define MTK_DP_TRANS_P0_35C8				0x35c8
+#define MTK_DP_TRANS_P0_35C8				0x15c8
 #define SW_IRQ_CLR_DP_TRANS_P0_MASK				GENMASK(15, 0)
 #define SW_IRQ_STATUS_DP_TRANS_P0_MASK				GENMASK(15, 0)
-#define MTK_DP_TRANS_P0_35D0				0x35d0
+#define MTK_DP_TRANS_P0_35D0				0x15d0
 #define SW_IRQ_FINAL_STATUS_DP_TRANS_P0_MASK			GENMASK(15, 0)
-#define MTK_DP_TRANS_P0_35F0				0x35f0
+#define MTK_DP_TRANS_P0_35F0				0x15f0
 #define DP_TRANS_DUMMY_RW_0					BIT(3)
 #define DP_TRANS_DUMMY_RW_0_MASK				GENMASK(3, 2)
 
-/* offset: AUX_OFFSET (0x3600) */
-#define MTK_DP_AUX_P0_360C			0x360c
+/* offset: AUX_OFFSET (0x1600) */
+#define MTK_DP_AUX_P0_360C			0x160c
 #define AUX_TIMEOUT_THR_AUX_TX_P0_MASK			GENMASK(12, 0)
 #define AUX_TIMEOUT_THR_AUX_TX_P0_VAL			0x1595
-#define MTK_DP_AUX_P0_3614			0x3614
+#define MTK_DP_AUX_P0_3614			0x1614
 #define AUX_RX_UI_CNT_THR_AUX_TX_P0_MASK		GENMASK(6, 0)
 #define AUX_RX_UI_CNT_THR_AUX_FOR_26M			13
-#define MTK_DP_AUX_P0_3618			0x3618
+#define MTK_DP_AUX_P0_3618			0x1618
 #define AUX_RX_FIFO_FULL_AUX_TX_P0_MASK			BIT(9)
 #define AUX_RX_FIFO_WRITE_POINTER_AUX_TX_P0_MASK	GENMASK(3, 0)
-#define MTK_DP_AUX_P0_3620			0x3620
+#define MTK_DP_AUX_P0_3620			0x1620
 #define AUX_RD_MODE_AUX_TX_P0_MASK			BIT(9)
 #define AUX_RX_FIFO_READ_PULSE_TX_P0			BIT(8)
 #define AUX_RX_FIFO_READ_DATA_AUX_TX_P0_MASK		GENMASK(7, 0)
-#define MTK_DP_AUX_P0_3624			0x3624
+#define MTK_DP_AUX_P0_3624			0x1624
 #define AUX_RX_REPLY_COMMAND_AUX_TX_P0_MASK		GENMASK(3, 0)
-#define MTK_DP_AUX_P0_3628			0x3628
+#define MTK_DP_AUX_P0_3628			0x1628
 #define AUX_RX_PHY_STATE_AUX_TX_P0_MASK			GENMASK(9, 0)
 #define AUX_RX_PHY_STATE_AUX_TX_P0_RX_IDLE		BIT(0)
-#define MTK_DP_AUX_P0_362C			0x362c
+#define MTK_DP_AUX_P0_362C			0x162c
 #define AUX_NO_LENGTH_AUX_TX_P0				BIT(0)
 #define AUX_TX_AUXTX_OV_EN_AUX_TX_P0_MASK		BIT(1)
 #define AUX_RESERVED_RW_0_AUX_TX_P0_MASK		GENMASK(15, 2)
-#define MTK_DP_AUX_P0_3630			0x3630
+#define MTK_DP_AUX_P0_3630			0x1630
 #define AUX_TX_REQUEST_READY_AUX_TX_P0			BIT(3)
-#define MTK_DP_AUX_P0_3634			0x3634
+#define MTK_DP_AUX_P0_3634			0x1634
 #define AUX_TX_OVER_SAMPLE_RATE_AUX_TX_P0_MASK		GENMASK(15, 8)
 #define AUX_TX_OVER_SAMPLE_RATE_FOR_26M			25
-#define MTK_DP_AUX_P0_3640			0x3640
+#define MTK_DP_AUX_P0_3640			0x1640
 #define AUX_RX_AUX_RECV_COMPLETE_IRQ_AUX_TX_P0		BIT(6)
 #define AUX_RX_EDID_RECV_COMPLETE_IRQ_AUX_TX_P0		BIT(5)
 #define AUX_RX_MCCS_RECV_COMPLETE_IRQ_AUX_TX_P0		BIT(4)
@@ -338,25 +318,32 @@
 							 AUX_RX_MCCS_RECV_COMPLETE_IRQ_AUX_TX_P0 | \
 							 AUX_RX_EDID_RECV_COMPLETE_IRQ_AUX_TX_P0 | \
 							 AUX_RX_AUX_RECV_COMPLETE_IRQ_AUX_TX_P0)
-#define MTK_DP_AUX_P0_3644			0x3644
+#define MTK_DP_AUX_P0_3644			0x1644
 #define MCU_REQUEST_COMMAND_AUX_TX_P0_MASK		GENMASK(3, 0)
-#define MTK_DP_AUX_P0_3648			0x3648
+#define MTK_DP_AUX_P0_3648			0x1648
 #define MCU_REQUEST_ADDRESS_LSB_AUX_TX_P0_MASK		GENMASK(15, 0)
-#define MTK_DP_AUX_P0_364C			0x364c
+#define MTK_DP_AUX_P0_364C			0x164c
 #define MCU_REQUEST_ADDRESS_MSB_AUX_TX_P0_MASK		GENMASK(3, 0)
-#define MTK_DP_AUX_P0_3650			0x3650
+#define MTK_DP_AUX_P0_3650			0x1650
 #define MCU_REQ_DATA_NUM_AUX_TX_P0_MASK			GENMASK(15, 12)
 #define PHY_FIFO_RST_AUX_TX_P0_MASK			BIT(9)
 #define MCU_ACK_TRAN_COMPLETE_AUX_TX_P0			BIT(8)
-#define MTK_DP_AUX_P0_3658			0x3658
+#define MTK_DP_AUX_P0_3658			0x1658
 #define AUX_TX_OV_EN_AUX_TX_P0_MASK			BIT(0)
-#define MTK_DP_AUX_P0_3690			0x3690
+#define MTK_DP_AUX_P0_3690			0x1690
 #define RX_REPLY_COMPLETE_MODE_AUX_TX_P0		BIT(8)
-#define MTK_DP_AUX_P0_3704			0x3704
+
+#define REG_36A0_AUX_TX_P0			0x16a0
+#define DP_TX_INIT_MASK_15_TO_2				GENMASK(15, 2)
+
+#define MTK_DP_AUX_P0_3704			0x1704
 #define AUX_TX_FIFO_WDATA_NEW_MODE_T_AUX_TX_P0_MASK	BIT(1)
 #define AUX_TX_FIFO_NEW_MODE_EN_AUX_TX_P0		BIT(2)
-#define MTK_DP_AUX_P0_3708			0x3708
-#define MTK_DP_AUX_P0_37C8			0x37c8
+#define MTK_DP_AUX_P0_3708			0x1708
+#define MTK_DP_AUX_P0_37C8			0x17c8
 #define MTK_ATOP_EN_AUX_TX_P0				BIT(0)
 
+/* offset: SEC_OFFSET (0x2000) */
+#define SEC_OFFSET	0x2000
+
 #endif /*_MTK_DP_REG_H_*/
-- 
2.54.0


^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [PATCH 06/11] drm/mediatek: mtk_dp: Use PHY API for PHY power sequences
  2026-07-01 12:20 [PATCH 00/11] drm: MediaTek DisplayPort cleanups and MT8196 eDP AngeloGioacchino Del Regno
                   ` (4 preceding siblings ...)
  2026-07-01 12:20 ` [PATCH 05/11] drm/mediatek: mtk_dp: Rework register offsets for proper PHY usage AngeloGioacchino Del Regno
@ 2026-07-01 12:20 ` AngeloGioacchino Del Regno
  2026-07-01 13:05   ` sashiko-bot
  2026-07-01 12:20 ` [PATCH 07/11] drm/mediatek: mtk_dp: Add support for PHY from devicetree AngeloGioacchino Del Regno
                   ` (4 subsequent siblings)
  10 siblings, 1 reply; 20+ messages in thread
From: AngeloGioacchino Del Regno @ 2026-07-01 12:20 UTC (permalink / raw)
  To: chunkuang.hu
  Cc: p.zabel, airlied, simona, maarten.lankhorst, mripard, tzimmermann,
	robh, krzk+dt, conor+dt, matthias.bgg, angelogioacchino.delregno,
	jitao.shi, granquet, rex-bc.chen, dmitry.osipenko, ck.hu,
	amergnat, justin.yeh, jason-jh.lin, dri-devel, linux-mediatek,
	devicetree, linux-kernel, linux-arm-kernel, kernel

The PHY driver has gained support for .power_on() and .power_off()
callbacks: use the API provided phy_power_on(), phy_power_off()
functions instead of writing into PHY registers from this driver.

Signed-off-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
---
 drivers/gpu/drm/mediatek/mtk_dp.c | 32 ++++++++++++++++++++++++-------
 1 file changed, 25 insertions(+), 7 deletions(-)

diff --git a/drivers/gpu/drm/mediatek/mtk_dp.c b/drivers/gpu/drm/mediatek/mtk_dp.c
index 97bce8966a1f..3b5348ab487d 100644
--- a/drivers/gpu/drm/mediatek/mtk_dp.c
+++ b/drivers/gpu/drm/mediatek/mtk_dp.c
@@ -1415,6 +1415,8 @@ static void mtk_dp_aux_panel_poweron(struct mtk_dp *mtk_dp, bool pwron)
 
 static void mtk_dp_power_enable(struct mtk_dp *mtk_dp)
 {
+	int ret;
+
 	mtk_dp_update_bits(mtk_dp, MTK_DP_TOP_RESET_AND_PROBE,
 			   0, SW_RST_B_PHYD);
 
@@ -1425,21 +1427,37 @@ static void mtk_dp_power_enable(struct mtk_dp *mtk_dp)
 			   SW_RST_B_PHYD, SW_RST_B_PHYD);
 	mtk_dp_update_bits(mtk_dp, MTK_DP_TOP_PWR_STATE,
 			   DP_PWR_STATE_BANDGAP_TPLL, DP_PWR_STATE_MASK);
-	mtk_dp_write(mtk_dp, DP_PHY_AUX_RX_CTL,
-		     RG_DPAUX_RX_VALID_DEGLITCH_EN | RG_XTP_GLB_CKDET_EN |
-		     RG_DPAUX_RX_EN);
-	mtk_dp_update_bits(mtk_dp, MTK_DP_0034, 0, DA_CKM_CKTX0_EN_FORCE_EN);
+
+	if (mtk_dp->phy_dev) {
+		mtk_dp_write(mtk_dp, DP_PHY_AUX_RX_CTL,
+			     RG_DPAUX_RX_VALID_DEGLITCH_EN | RG_XTP_GLB_CKDET_EN |
+			     RG_DPAUX_RX_EN);
+		mtk_dp_update_bits(mtk_dp, MTK_DP_0034, 0, DA_CKM_CKTX0_EN_FORCE_EN);
+	} else {
+		ret = phy_power_on(mtk_dp->phy);
+		if (ret)
+			dev_warn(mtk_dp->dev, "Could not power on PHY!\n");
+	}
 }
 
 static void mtk_dp_power_disable(struct mtk_dp *mtk_dp)
 {
+	int ret;
+
 	mtk_dp_write(mtk_dp, MTK_DP_TOP_PWR_STATE, 0);
 
-	mtk_dp_update_bits(mtk_dp, MTK_DP_0034,
+	if (unlikely(mtk_dp->phy_dev)) {
+		mtk_dp_update_bits(mtk_dp, MTK_DP_0034,
 			   DA_CKM_CKTX0_EN_FORCE_EN, DA_CKM_CKTX0_EN_FORCE_EN);
 
-	/* Disable RX */
-	mtk_dp_write(mtk_dp, DP_PHY_AUX_RX_CTL, 0);
+		/* Disable RX */
+		mtk_dp_write(mtk_dp, DP_PHY_AUX_RX_CTL, 0);
+	} else {
+		ret = phy_power_off(mtk_dp->phy);
+		if (ret)
+			dev_warn(mtk_dp->dev, "Could not power off PHY!\n");
+	}
+
 	mtk_dp_write(mtk_dp, MTK_DP_TOP_MEM_PD,
 		     0x550 | FUSE_SEL | MEM_ISO_EN);
 }
-- 
2.54.0


^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [PATCH 07/11] drm/mediatek: mtk_dp: Add support for PHY from devicetree
  2026-07-01 12:20 [PATCH 00/11] drm: MediaTek DisplayPort cleanups and MT8196 eDP AngeloGioacchino Del Regno
                   ` (5 preceding siblings ...)
  2026-07-01 12:20 ` [PATCH 06/11] drm/mediatek: mtk_dp: Use PHY API for PHY power sequences AngeloGioacchino Del Regno
@ 2026-07-01 12:20 ` AngeloGioacchino Del Regno
  2026-07-01 13:23   ` sashiko-bot
  2026-07-01 12:20 ` [PATCH 08/11] drm/mediatek: mtk_dp: Move max link rate to SoC specific data AngeloGioacchino Del Regno
                   ` (3 subsequent siblings)
  10 siblings, 1 reply; 20+ messages in thread
From: AngeloGioacchino Del Regno @ 2026-07-01 12:20 UTC (permalink / raw)
  To: chunkuang.hu
  Cc: p.zabel, airlied, simona, maarten.lankhorst, mripard, tzimmermann,
	robh, krzk+dt, conor+dt, matthias.bgg, angelogioacchino.delregno,
	jitao.shi, granquet, rex-bc.chen, dmitry.osipenko, ck.hu,
	amergnat, justin.yeh, jason-jh.lin, dri-devel, linux-mediatek,
	devicetree, linux-kernel, linux-arm-kernel, kernel

Add support for specifying `phys` in devicetree to pass handle
to the DisplayPort PHY.

In order to retain compatibility with older devicetrees, check if
`phys` was specified: if not, initialize the regmap_mmio with the
legacy configuration and register the mediatek-dp-phy platform
device from this driver, and get the PHY calibration data.

Signed-off-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
---
 drivers/gpu/drm/mediatek/mtk_dp.c | 50 ++++++++++++++++++++++++++-----
 1 file changed, 43 insertions(+), 7 deletions(-)

diff --git a/drivers/gpu/drm/mediatek/mtk_dp.c b/drivers/gpu/drm/mediatek/mtk_dp.c
index 3b5348ab487d..bf3a4b15f3ec 100644
--- a/drivers/gpu/drm/mediatek/mtk_dp.c
+++ b/drivers/gpu/drm/mediatek/mtk_dp.c
@@ -426,6 +426,15 @@ static const struct regmap_config mtk_dp_regmap_legacy_config = {
 	.name = "mtk-dp-registers",
 };
 
+static const struct regmap_config mtk_dp_regmap_config = {
+	.reg_bits = 32,
+	.val_bits = 32,
+	.reg_stride = 4,
+	.max_register = SEC_OFFSET + 0x90,
+	.name = "mtk-dp-registers",
+};
+
+
 static struct mtk_dp *mtk_dp_from_bridge(struct drm_bridge *b)
 {
 	return container_of(b, struct mtk_dp, bridge);
@@ -1298,7 +1307,13 @@ static int mtk_dp_phy_configure(struct mtk_dp *mtk_dp,
 	if (ret)
 		return ret;
 
-	mtk_dp_set_calibration_data(mtk_dp);
+	/*
+	 * For legacy, deprecated strategy, set partial PHY calibration here.
+	 * New-style will set all PHY calibrations with phy ops instead.
+	 */
+	if (mtk_dp->phy_dev)
+		mtk_dp_set_calibration_data(mtk_dp);
+
 	mtk_dp_update_bits(mtk_dp, MTK_DP_TOP_PWR_STATE,
 			   DP_PWR_STATE_BANDGAP_TPLL_LANE, DP_PWR_STATE_MASK);
 
@@ -2132,8 +2147,9 @@ static int mtk_dp_wait_hpd_asserted(struct drm_dp_aux *mtk_aux, unsigned long wa
 static int mtk_dp_dt_parse(struct mtk_dp *mtk_dp,
 			   struct platform_device *pdev)
 {
-	struct device_node *endpoint;
+	const struct regmap_config *regmap_cfg;
 	struct device *dev = &pdev->dev;
+	struct device_node *endpoint;
 	int ret;
 	void __iomem *base;
 	u32 linkrate;
@@ -2143,7 +2159,12 @@ static int mtk_dp_dt_parse(struct mtk_dp *mtk_dp,
 	if (IS_ERR(base))
 		return PTR_ERR(base);
 
-	mtk_dp->regs = devm_regmap_init_mmio(dev, base, &mtk_dp_regmap_legacy_config);
+	if (!mtk_dp->legacy_regoff)
+		regmap_cfg = &mtk_dp_regmap_config;
+	else
+		regmap_cfg = &mtk_dp_regmap_legacy_config;
+
+	mtk_dp->regs = devm_regmap_init_mmio(dev, base, regmap_cfg);
 	if (IS_ERR(mtk_dp->regs))
 		return PTR_ERR(mtk_dp->regs);
 
@@ -2769,6 +2790,7 @@ static int mtk_dp_register_phy(struct mtk_dp *mtk_dp)
 				     "Failed to add phy unregister devm action");
 	}
 
+	/* PHY calibration data is in mtk_dp only for legacy devicetree */
 	mtk_dp_get_calibration_data(mtk_dp);
 
 	mtk_dp->phy = devm_phy_get(&mtk_dp->phy_dev->dev, "dp");
@@ -2821,7 +2843,12 @@ static int mtk_dp_probe(struct platform_device *pdev)
 
 	mtk_dp->dev = dev;
 	mtk_dp->data = (struct mtk_dp_data *)of_device_get_match_data(dev);
-	mtk_dp->legacy_regoff = MTK_DP_TOP_OFFSET_LEGACY;
+
+	/* Prefer PHY from devicetree - if not found, this is legacy */
+	if (of_property_present(dev->of_node, "phys"))
+		mtk_dp->legacy_regoff = 0;
+	else
+		mtk_dp->legacy_regoff = MTK_DP_TOP_OFFSET_LEGACY;
 
 	ret = mtk_dp_dt_parse(mtk_dp, pdev);
 	if (ret)
@@ -2872,9 +2899,18 @@ static int mtk_dp_probe(struct platform_device *pdev)
 					     "Failed to register audio driver\n");
 	}
 
-	ret = mtk_dp_register_phy(mtk_dp);
-	if (ret)
-		return ret;
+	if (!mtk_dp->legacy_regoff) {
+		mtk_dp->phy = devm_phy_get(dev, NULL);
+		if (IS_ERR(mtk_dp->phy))
+			return dev_err_probe(dev, PTR_ERR(mtk_dp->phy),
+					     "Failed to get phy\n");
+
+		mtk_dp->phy_dev = NULL;
+	} else {
+		ret = mtk_dp_register_phy(mtk_dp);
+		if (ret)
+			return ret;
+	}
 
 	mtk_dp->bridge.of_node = dev->of_node;
 	mtk_dp->bridge.type = mtk_dp->data->bridge_type;
-- 
2.54.0


^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [PATCH 08/11] drm/mediatek: mtk_dp: Move max link rate to SoC specific data
  2026-07-01 12:20 [PATCH 00/11] drm: MediaTek DisplayPort cleanups and MT8196 eDP AngeloGioacchino Del Regno
                   ` (6 preceding siblings ...)
  2026-07-01 12:20 ` [PATCH 07/11] drm/mediatek: mtk_dp: Add support for PHY from devicetree AngeloGioacchino Del Regno
@ 2026-07-01 12:20 ` AngeloGioacchino Del Regno
  2026-07-01 13:34   ` sashiko-bot
  2026-07-01 12:20 ` [PATCH 09/11] drm/mediatek: mtk_dp: Add support for HotPlug Detection in DP AUX AngeloGioacchino Del Regno
                   ` (2 subsequent siblings)
  10 siblings, 1 reply; 20+ messages in thread
From: AngeloGioacchino Del Regno @ 2026-07-01 12:20 UTC (permalink / raw)
  To: chunkuang.hu
  Cc: p.zabel, airlied, simona, maarten.lankhorst, mripard, tzimmermann,
	robh, krzk+dt, conor+dt, matthias.bgg, angelogioacchino.delregno,
	jitao.shi, granquet, rex-bc.chen, dmitry.osipenko, ck.hu,
	amergnat, justin.yeh, jason-jh.lin, dri-devel, linux-mediatek,
	devicetree, linux-kernel, linux-arm-kernel, kernel

In preparation for adding support for the eDP IP found in the
MT8196 SoC, having a higher supported maximum link rate, move
this parameter to SoC data instead of statically assigning it
to the training info during initialization.

Signed-off-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
---
 drivers/gpu/drm/mediatek/mtk_dp.c | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/mediatek/mtk_dp.c b/drivers/gpu/drm/mediatek/mtk_dp.c
index bf3a4b15f3ec..5272e717bfda 100644
--- a/drivers/gpu/drm/mediatek/mtk_dp.c
+++ b/drivers/gpu/drm/mediatek/mtk_dp.c
@@ -167,6 +167,7 @@ struct mtk_dp_data {
 	bool audio_supported;
 	bool audio_pkt_in_hblank_area;
 	u16 audio_m_div2_bit;
+	u8 hw_max_link_rate;
 };
 
 static const struct mtk_dp_efuse_fmt mt8188_dp_efuse_fmt[MTK_DP_CAL_MAX] = {
@@ -1481,7 +1482,7 @@ static void mtk_dp_initialize_priv_data(struct mtk_dp *mtk_dp)
 {
 	bool plugged_in = (mtk_dp->bridge.type == DRM_MODE_CONNECTOR_eDP);
 
-	mtk_dp->train_info.link_rate = DP_LINK_BW_5_4;
+	mtk_dp->train_info.link_rate = mtk_dp->data->hw_max_link_rate;
 	mtk_dp->train_info.lane_count = mtk_dp->max_lanes;
 	mtk_dp->train_info.cable_plugged_in = plugged_in;
 
@@ -3013,6 +3014,7 @@ static const struct mtk_dp_data mt8188_dp_data = {
 	.audio_supported = true,
 	.audio_pkt_in_hblank_area = true,
 	.audio_m_div2_bit = MT8188_AUDIO_M_CODE_MULT_DIV_SEL_DP_ENC0_P0_DIV_2,
+	.hw_max_link_rate = DP_LINK_BW_5_4,
 };
 
 static const struct mtk_dp_data mt8195_edp_data = {
@@ -3021,6 +3023,7 @@ static const struct mtk_dp_data mt8195_edp_data = {
 	.efuse_fmt = mt8195_edp_efuse_fmt,
 	.audio_supported = false,
 	.audio_m_div2_bit = MT8195_AUDIO_M_CODE_MULT_DIV_SEL_DP_ENC0_P0_DIV_2,
+	.hw_max_link_rate = DP_LINK_BW_5_4,
 };
 
 static const struct mtk_dp_data mt8195_dp_data = {
@@ -3029,6 +3032,7 @@ static const struct mtk_dp_data mt8195_dp_data = {
 	.efuse_fmt = mt8195_dp_efuse_fmt,
 	.audio_supported = true,
 	.audio_m_div2_bit = MT8195_AUDIO_M_CODE_MULT_DIV_SEL_DP_ENC0_P0_DIV_2,
+	.hw_max_link_rate = DP_LINK_BW_5_4,
 };
 
 static const struct of_device_id mtk_dp_of_match[] = {
-- 
2.54.0


^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [PATCH 09/11] drm/mediatek: mtk_dp: Add support for HotPlug Detection in DP AUX
  2026-07-01 12:20 [PATCH 00/11] drm: MediaTek DisplayPort cleanups and MT8196 eDP AngeloGioacchino Del Regno
                   ` (7 preceding siblings ...)
  2026-07-01 12:20 ` [PATCH 08/11] drm/mediatek: mtk_dp: Move max link rate to SoC specific data AngeloGioacchino Del Regno
@ 2026-07-01 12:20 ` AngeloGioacchino Del Regno
  2026-07-01 13:46   ` sashiko-bot
  2026-07-01 12:20 ` [PATCH 10/11] drm/mediatek: mtk_dp: Add support for eDP1.5 IPs and MT8196 SoC AngeloGioacchino Del Regno
  2026-07-01 12:20 ` [PATCH 11/11] drm/mediatek: mtk_dp: Clarify XTAL freq and Debounce registers AngeloGioacchino Del Regno
  10 siblings, 1 reply; 20+ messages in thread
From: AngeloGioacchino Del Regno @ 2026-07-01 12:20 UTC (permalink / raw)
  To: chunkuang.hu
  Cc: p.zabel, airlied, simona, maarten.lankhorst, mripard, tzimmermann,
	robh, krzk+dt, conor+dt, matthias.bgg, angelogioacchino.delregno,
	jitao.shi, granquet, rex-bc.chen, dmitry.osipenko, ck.hu,
	amergnat, justin.yeh, jason-jh.lin, dri-devel, linux-mediatek,
	devicetree, linux-kernel, linux-arm-kernel, kernel

Newer MediaTek DisplayPort IPs can finally use the AUX to perform
hotplug detection (HPD) without having to power up the entire eDP
or DP IP (transmitter, encoder, etc).

Enable support for configuring and performing HPD in AUX and check
the correct HPD strategy with a new platform data variable.
This is done in preparation for adding support for the embedded
DisplayPort (eDP) IP found in the MT8196 SoC.

Signed-off-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
---
 drivers/gpu/drm/mediatek/mtk_dp.c     | 96 ++++++++++++++++++++++++---
 drivers/gpu/drm/mediatek/mtk_dp_reg.h | 18 +++++
 2 files changed, 103 insertions(+), 11 deletions(-)

diff --git a/drivers/gpu/drm/mediatek/mtk_dp.c b/drivers/gpu/drm/mediatek/mtk_dp.c
index 5272e717bfda..2d58eacb3d3e 100644
--- a/drivers/gpu/drm/mediatek/mtk_dp.c
+++ b/drivers/gpu/drm/mediatek/mtk_dp.c
@@ -168,6 +168,7 @@ struct mtk_dp_data {
 	bool audio_pkt_in_hblank_area;
 	u16 audio_m_div2_bit;
 	u8 hw_max_link_rate;
+	bool aux_hpd_supported;
 };
 
 static const struct mtk_dp_efuse_fmt mt8188_dp_efuse_fmt[MTK_DP_CAL_MAX] = {
@@ -1046,7 +1047,21 @@ static u32 mtk_dp_swirq_get_clear(struct mtk_dp *mtk_dp)
 	return irq_status;
 }
 
-static u32 mtk_dp_hwirq_get_clear(struct mtk_dp *mtk_dp)
+static u32 mtk_dp_aux_hwirq_get_clear(struct mtk_dp *mtk_dp)
+{
+	u32 irq_status = mtk_dp_read(mtk_dp, MTK_DP_AUX_TX_P0_INT_STA);
+
+	if (irq_status) {
+		mtk_dp_update_bits(mtk_dp, MTK_DP_AUX_TX_P0_INT_CLR,
+				   irq_status, irq_status);
+		mtk_dp_update_bits(mtk_dp, MTK_DP_AUX_TX_P0_INT_CLR,
+				   0, irq_status);
+	}
+
+	return irq_status;
+}
+
+static u32 mtk_dp_trans_hwirq_get_clear(struct mtk_dp *mtk_dp)
 {
 	u32 irq_status = (mtk_dp_read(mtk_dp, MTK_DP_TRANS_P0_3418) &
 			  IRQ_STATUS_DP_TRANS_P0_MASK) >> 12;
@@ -1061,8 +1076,28 @@ static u32 mtk_dp_hwirq_get_clear(struct mtk_dp *mtk_dp)
 	return irq_status;
 }
 
+static inline u32 mtk_dp_hwirq_get_clear(struct mtk_dp *mtk_dp)
+{
+	if (mtk_dp->data->aux_hpd_supported)
+		return mtk_dp_aux_hwirq_get_clear(mtk_dp);
+
+	return mtk_dp_trans_hwirq_get_clear(mtk_dp);
+}
+
 static void mtk_dp_hwirq_enable(struct mtk_dp *mtk_dp, bool enable)
 {
+	u32 mask, val;
+
+	/* Valid only for SoCs with working AUX HPD, this register is ignored on the others */
+	if (enable) {
+		mask = HPD_CONNECT_EVENT | HPD_INTERRUPT_EVENT | HPD_DISCONNECT_EVENT;
+		val = 0;
+	} else {
+		mask = DP_TX_AUX_INT_MASK;
+		val = DP_TX_AUX_INT_MASK;
+	}
+	mtk_dp_update_bits(mtk_dp, MTK_DP_TX_AUX_INT_MASKING, val, mask);
+
 	mtk_dp_update_bits(mtk_dp, MTK_DP_TRANS_P0_3418,
 			   enable ? 0 :
 			   IRQ_MASK_DP_TRANS_P0_DISC_IRQ |
@@ -1088,9 +1123,34 @@ static void mtk_dp_initialize_settings(struct mtk_dp *mtk_dp)
 			   IRQ_MASK_AUX_TOP_IRQ, IRQ_MASK_AUX_TOP_IRQ);
 }
 
+static void mtk_dp_initialize_aux_hpd_detect_settings(struct mtk_dp *mtk_dp)
+{
+	/* Set interrupt debounce threshold time */
+	mtk_dp_update_bits(mtk_dp, MTK_DP_AUX_P0_364C,
+			   FIELD_PREP_CONST(HPD_INT_LOW_TIME_THD, 2) |
+			   FIELD_PREP_CONST(HPD_INT_HIGH_TIME_THD, 6),
+			   HPD_INT_LOW_TIME_THD | HPD_INT_HIGH_TIME_THD);
+
+	/* Connection detect threshold time: 1.5ms + (0.1 * (x)) ms*/
+	mtk_dp_update_bits(mtk_dp, MTK_DP_AUX_P0_367C,
+			   FIELD_PREP(HPD_CONN_THD_DP_TX_AUX_MASK, 5),
+			   HPD_CONN_THD_DP_TX_AUX_MASK);
+
+	/* Disconnection detect threshold and debounce time */
+	mtk_dp_write(mtk_dp, MTK_DP_AUX_P0_37A0,
+		     FIELD_PREP_CONST(HPD_DISC_THD_AUX_TX, 5) |
+		     FIELD_PREP_CONST(HPD_DISC_DEB_AUX_TX, 8));
+
+	/* Crystal frequency for 1us timing normalization: set to 26MHz */
+	mtk_dp_update_bits(mtk_dp, REG_366C_AUX_TX_P0,
+			   FIELD_PREP_CONST(XTAL_FREQ_DP_TX_AUX_MASK, XTAL_FREQ_DP_TX_AUX_VAL),
+			   XTAL_FREQ_DP_TX_AUX_MASK);
+}
+
 static void mtk_dp_initialize_hpd_detect_settings(struct mtk_dp *mtk_dp)
 {
 	u32 val;
+
 	/* Debounce threshold */
 	mtk_dp_update_bits(mtk_dp, MTK_DP_TRANS_P0_3410,
 			   8, HPD_DEB_THD_DP_TRANS_P0_MASK);
@@ -2024,7 +2084,11 @@ static void mtk_dp_init_port(struct mtk_dp *mtk_dp)
 	mtk_dp_initialize_settings(mtk_dp);
 	mtk_dp_initialize_aux_settings(mtk_dp);
 	mtk_dp_initialize_digital_settings(mtk_dp);
-	mtk_dp_initialize_hpd_detect_settings(mtk_dp);
+
+	if (mtk_dp->data->aux_hpd_supported)
+		mtk_dp_initialize_aux_hpd_detect_settings(mtk_dp);
+	else
+		mtk_dp_initialize_hpd_detect_settings(mtk_dp);
 
 	mtk_dp_digital_sw_reset(mtk_dp);
 }
@@ -2091,6 +2155,7 @@ static irqreturn_t mtk_dp_hpd_event(int hpd, void *dev)
 	unsigned long flags;
 	u32 irq_status = mtk_dp_swirq_get_clear(mtk_dp) |
 			 mtk_dp_hwirq_get_clear(mtk_dp);
+	u32 val;
 
 	if (!irq_status)
 		return IRQ_HANDLED;
@@ -2109,11 +2174,15 @@ static irqreturn_t mtk_dp_hpd_event(int hpd, void *dev)
 	spin_unlock_irqrestore(&mtk_dp->irq_thread_lock, flags);
 
 	if (cable_sta_chg) {
-		if (!!(mtk_dp_read(mtk_dp, MTK_DP_TRANS_P0_3414) &
-		       HPD_DB_DP_TRANS_P0_MASK))
-			mtk_dp->train_info.cable_plugged_in = true;
-		else
-			mtk_dp->train_info.cable_plugged_in = false;
+		if (mtk_dp->data->aux_hpd_supported) {
+			val = mtk_dp_read(mtk_dp, MTK_DP_AUX_P0_364C);
+			val &= HPD_STATUS_DP_AUX_TX_P0_MASK;
+		} else {
+			val = mtk_dp_read(mtk_dp, MTK_DP_TRANS_P0_3414);
+			val &= HPD_DB_DP_TRANS_P0_MASK;
+		}
+
+		mtk_dp->train_info.cable_plugged_in = val > 0;
 	}
 
 	return IRQ_WAKE_THREAD;
@@ -2125,10 +2194,15 @@ static int mtk_dp_wait_hpd_asserted(struct drm_dp_aux *mtk_aux, unsigned long wa
 	u32 val;
 	int ret;
 
-	ret = regmap_read_poll_timeout(mtk_dp->regs,
-				       MTK_DP_TRANS_P0_3414 + mtk_dp->legacy_regoff,
-				       val, !!(val & HPD_DB_DP_TRANS_P0_MASK),
-				       wait_us / 100, wait_us);
+	if (mtk_dp->data->aux_hpd_supported)
+		ret = regmap_read_poll_timeout(mtk_dp->regs, MTK_DP_AUX_P0_364C,
+					       val, !!(val & HPD_STATUS_DP_AUX_TX_P0_MASK),
+					       wait_us / 100, wait_us);
+	else
+		ret = regmap_read_poll_timeout(mtk_dp->regs,
+					       MTK_DP_TRANS_P0_3414 + mtk_dp->legacy_regoff,
+					       val, !!(val & HPD_DB_DP_TRANS_P0_MASK),
+					       wait_us / 100, wait_us);
 	if (ret) {
 		mtk_dp->train_info.cable_plugged_in = false;
 		return ret;
diff --git a/drivers/gpu/drm/mediatek/mtk_dp_reg.h b/drivers/gpu/drm/mediatek/mtk_dp_reg.h
index 616ea6440b08..5a3b3e2b4f49 100644
--- a/drivers/gpu/drm/mediatek/mtk_dp_reg.h
+++ b/drivers/gpu/drm/mediatek/mtk_dp_reg.h
@@ -276,6 +276,11 @@
 #define DP_TRANS_DUMMY_RW_0_MASK				GENMASK(3, 2)
 
 /* offset: AUX_OFFSET (0x1600) */
+#define MTK_DP_AUX_TX_P0_INT_STA			0x1608
+#define HPD_CONNECT_EVENT				BIT(0)
+#define HPD_INTERRUPT_EVENT				BIT(2)
+#define HPD_DISCONNECT_EVENT				BIT(10)
+#define DP_TX_AUX_INT_MASK				GENMASK(15, 0)
 #define MTK_DP_AUX_P0_360C			0x160c
 #define AUX_TIMEOUT_THR_AUX_TX_P0_MASK			GENMASK(12, 0)
 #define AUX_TIMEOUT_THR_AUX_TX_P0_VAL			0x1595
@@ -323,6 +328,9 @@
 #define MTK_DP_AUX_P0_3648			0x1648
 #define MCU_REQUEST_ADDRESS_LSB_AUX_TX_P0_MASK		GENMASK(15, 0)
 #define MTK_DP_AUX_P0_364C			0x164c
+#define HPD_STATUS_DP_AUX_TX_P0_MASK			BIT(15)
+#define HPD_INT_HIGH_TIME_THD				GENMASK(9, 7)
+#define HPD_INT_LOW_TIME_THD				GENMASK(6, 4)
 #define MCU_REQUEST_ADDRESS_MSB_AUX_TX_P0_MASK		GENMASK(3, 0)
 #define MTK_DP_AUX_P0_3650			0x1650
 #define MCU_REQ_DATA_NUM_AUX_TX_P0_MASK			GENMASK(15, 12)
@@ -330,6 +338,13 @@
 #define MCU_ACK_TRAN_COMPLETE_AUX_TX_P0			BIT(8)
 #define MTK_DP_AUX_P0_3658			0x1658
 #define AUX_TX_OV_EN_AUX_TX_P0_MASK			BIT(0)
+#define MTK_DP_TX_AUX_INT_MASKING		0x1660
+#define MTK_DP_AUX_TX_P0_INT_CLR		0x1668
+#define REG_366C_AUX_TX_P0			0x166c
+#define XTAL_FREQ_DP_TX_AUX_VAL				0x68
+#define XTAL_FREQ_DP_TX_AUX_MASK			GENMASK(15, 8)
+#define MTK_DP_AUX_P0_367C			0x167c
+#define HPD_CONN_THD_DP_TX_AUX_MASK			GENMASK(9, 6)
 #define MTK_DP_AUX_P0_3690			0x1690
 #define RX_REPLY_COMPLETE_MODE_AUX_TX_P0		BIT(8)
 
@@ -340,6 +355,9 @@
 #define AUX_TX_FIFO_WDATA_NEW_MODE_T_AUX_TX_P0_MASK	BIT(1)
 #define AUX_TX_FIFO_NEW_MODE_EN_AUX_TX_P0		BIT(2)
 #define MTK_DP_AUX_P0_3708			0x1708
+#define MTK_DP_AUX_P0_37A0			0x17a0
+#define HPD_DISC_THD_AUX_TX				GENMASK(7, 4)
+#define HPD_DISC_DEB_AUX_TX				GENMASK(3, 0)
 #define MTK_DP_AUX_P0_37C8			0x17c8
 #define MTK_ATOP_EN_AUX_TX_P0				BIT(0)
 
-- 
2.54.0


^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [PATCH 10/11] drm/mediatek: mtk_dp: Add support for eDP1.5 IPs and MT8196 SoC
  2026-07-01 12:20 [PATCH 00/11] drm: MediaTek DisplayPort cleanups and MT8196 eDP AngeloGioacchino Del Regno
                   ` (8 preceding siblings ...)
  2026-07-01 12:20 ` [PATCH 09/11] drm/mediatek: mtk_dp: Add support for HotPlug Detection in DP AUX AngeloGioacchino Del Regno
@ 2026-07-01 12:20 ` AngeloGioacchino Del Regno
  2026-07-01 14:03   ` sashiko-bot
  2026-07-01 12:20 ` [PATCH 11/11] drm/mediatek: mtk_dp: Clarify XTAL freq and Debounce registers AngeloGioacchino Del Regno
  10 siblings, 1 reply; 20+ messages in thread
From: AngeloGioacchino Del Regno @ 2026-07-01 12:20 UTC (permalink / raw)
  To: chunkuang.hu
  Cc: p.zabel, airlied, simona, maarten.lankhorst, mripard, tzimmermann,
	robh, krzk+dt, conor+dt, matthias.bgg, angelogioacchino.delregno,
	jitao.shi, granquet, rex-bc.chen, dmitry.osipenko, ck.hu,
	amergnat, justin.yeh, jason-jh.lin, dri-devel, linux-mediatek,
	devicetree, linux-kernel, linux-arm-kernel, kernel

Add support for MediaTek's Embedded DisplayPort (eDP) v1.5 IP as
found in the MT8196 SoC and other variants, and enclose some of
the new register writes in specific platform data booleans, as:
 - SDP on Encoder1 can be supported by both old and new IPs
   but it was chosen to use Encoder0 for SDP in the new ones
   in order to decrease the load on the secondary encoder;
 - PSR can be supported by older IPs as well, but was not tested
   on those yet (requires a display with PSR support connected
   to a device with older SoC, and I don't have it right now);
 - Power State forcing may not be needed on newer revisions of
   the eDP/DP IP (in SoCs newer than MT8196/MT6991).

As a note, even if this effectively adds some partial support for
the DisplayPort 1.4 IP from the same SoC (because the DP1.4 and
eDP1.5 IPs in this SoC have some little common parts in common),
there is still a long road ahead to actually enable support for
the DP1.4 IP itself.

Signed-off-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
---
 drivers/gpu/drm/mediatek/mtk_dp.c     | 283 +++++++++++++++++++++++---
 drivers/gpu/drm/mediatek/mtk_dp_reg.h |  61 +++++-
 2 files changed, 310 insertions(+), 34 deletions(-)

diff --git a/drivers/gpu/drm/mediatek/mtk_dp.c b/drivers/gpu/drm/mediatek/mtk_dp.c
index 2d58eacb3d3e..605ead7fa9bf 100644
--- a/drivers/gpu/drm/mediatek/mtk_dp.c
+++ b/drivers/gpu/drm/mediatek/mtk_dp.c
@@ -2,6 +2,8 @@
 /*
  * Copyright (c) 2019-2022 MediaTek Inc.
  * Copyright (c) 2022 BayLibre
+ * Copyright (c) 2026 Collabora Ltd
+ *                    AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
  */
 
 #include <drm/display/drm_dp_aux_bus.h>
@@ -57,6 +59,8 @@
 #define MTK_DP_TOP_OFFSET_LEGACY	0x2000
 
 #define MTK_DP_SIP_CONTROL_AARCH32	MTK_SIP_SMC_CMD(0x523)
+#define MTK_DP_SIP_ATF_EDP_SET_VID_MUTE	34
+#  define MTK_DP_SIP_REQ_VIDEO_UNMUTE	0xfefd
 #define MTK_DP_SIP_ATF_EDP_VIDEO_UNMUTE	33
 #define MTK_DP_SIP_ATF_VIDEO_UNMUTE	32
 
@@ -168,7 +172,11 @@ struct mtk_dp_data {
 	bool audio_pkt_in_hblank_area;
 	u16 audio_m_div2_bit;
 	u8 hw_max_link_rate;
+	bool hwip_v1p4;
 	bool aux_hpd_supported;
+	bool sdp_encoder1_enable;
+	bool force_pwr_states;
+	bool psr_supported;
 };
 
 static const struct mtk_dp_efuse_fmt mt8188_dp_efuse_fmt[MTK_DP_CAL_MAX] = {
@@ -507,6 +515,7 @@ static void mtk_dp_msa_bypass_enable(struct mtk_dp *mtk_dp, bool enable)
 
 static void mtk_dp_set_msa(struct mtk_dp *mtk_dp)
 {
+	u32 fde_start_val;
 	struct drm_display_mode mode;
 	struct videomode *vm = &mtk_dp->info.vm;
 
@@ -549,9 +558,14 @@ static void mtk_dp_set_msa(struct mtk_dp *mtk_dp)
 	mtk_dp_update_bits(mtk_dp, MTK_DP_ENC0_P0_315C,
 			   vm->hsync_len,
 			   PGEN_HSYNC_PULSE_WIDTH_DP_ENC0_P0_MASK);
+
+	fde_start_val = vm->hback_porch + vm->hsync_len;
+	if (mtk_dp->data->psr_supported)
+		fde_start_val += vm->hfront_porch;
+
 	mtk_dp_update_bits(mtk_dp, MTK_DP_ENC0_P0_3160,
-			   vm->hback_porch + vm->hsync_len,
-			   PGEN_HFDE_START_DP_ENC0_P0_MASK);
+			   fde_start_val, PGEN_HFDE_START_DP_ENC0_P0_MASK);
+
 	mtk_dp_update_bits(mtk_dp, MTK_DP_ENC0_P0_3164,
 			   vm->hactive,
 			   PGEN_HFDE_ACTIVE_WIDTH_DP_ENC0_P0_MASK);
@@ -566,9 +580,14 @@ static void mtk_dp_set_msa(struct mtk_dp *mtk_dp)
 	mtk_dp_update_bits(mtk_dp, MTK_DP_ENC0_P0_3170,
 			   vm->vsync_len,
 			   PGEN_VSYNC_PULSE_WIDTH_DP_ENC0_P0_MASK);
+
+	fde_start_val = vm->vback_porch + vm->vsync_len;
+	if (mtk_dp->data->psr_supported)
+		fde_start_val += vm->vfront_porch;
+
 	mtk_dp_update_bits(mtk_dp, MTK_DP_ENC0_P0_3174,
-			   vm->vback_porch + vm->vsync_len,
-			   PGEN_VFDE_START_DP_ENC0_P0_MASK);
+			   fde_start_val, PGEN_VFDE_START_DP_ENC0_P0_MASK);
+
 	mtk_dp_update_bits(mtk_dp, MTK_DP_ENC0_P0_3178,
 			   vm->vactive,
 			   PGEN_VFDE_ACTIVE_WIDTH_DP_ENC0_P0_MASK);
@@ -632,6 +651,8 @@ static void mtk_dp_set_sram_read_start(struct mtk_dp *mtk_dp, u32 val)
 
 static void mtk_dp_setup_encoder(struct mtk_dp *mtk_dp)
 {
+	u32 val, mask;
+
 	mtk_dp_update_bits(mtk_dp, MTK_DP_ENC0_P0_303C,
 			   VIDEO_MN_GEN_EN_DP_ENC0_P0,
 			   VIDEO_MN_GEN_EN_DP_ENC0_P0);
@@ -647,7 +668,16 @@ static void mtk_dp_setup_encoder(struct mtk_dp *mtk_dp)
 	mtk_dp_update_bits(mtk_dp, MTK_DP_ENC1_P0_3364,
 			   FIFO_READ_START_POINT_DP_ENC1_P0_VAL << 12,
 			   FIFO_READ_START_POINT_DP_ENC1_P0_MASK);
-	mtk_dp_write(mtk_dp, MTK_DP_ENC1_P0_3368, DP_ENC1_P0_3368_VAL);
+
+	mask = VIDEO_SRAM_FIFO_CNT_RESET_SEL_DP_ENC1_P0 | VIDEO_STABLE_CNT_THRD_DP_ENC1_P0;
+	mask |= BS2BS_MODE_DP_ENC1_P0;
+
+	val = mask;
+
+	if (mtk_dp->data->sdp_encoder1_enable)
+		val |= SDP_DP13_EN_DP_ENC1_P0;
+
+	mtk_dp_update_bits(mtk_dp, MTK_DP_ENC1_P0_3368, val, mask);
 }
 
 static void mtk_dp_pg_enable(struct mtk_dp *mtk_dp, bool enable)
@@ -1106,6 +1136,72 @@ static void mtk_dp_hwirq_enable(struct mtk_dp *mtk_dp, bool enable)
 			   IRQ_MASK_DP_TRANS_P0_MASK);
 }
 
+static void mtk_dp_encoder_force_bias_power_on(struct mtk_dp *mtk_dp)
+{
+	/* Force MCU to enable BIAS */
+	mtk_dp_update_bits(mtk_dp, REG_3F44_DP_ENC_P0_3,
+			   ENC_PHY_PWR_OVERWRITE_EN, ENC_PHY_PWR_OVERWRITE_EN);
+	mtk_dp_update_bits(mtk_dp, REG_3F44_DP_ENC_P0_3,
+			   FIELD_PREP_CONST(ENC_PHY_PWR_STATE_OVERWRITE_MASK,
+					    ENC_PHY_BIAS_PWR_ON),
+			   ENC_PHY_PWR_STATE_OVERWRITE_MASK);
+
+	/* Wait for the MCU to get LDO ready in PHYD */
+	msleep(50);
+
+	mtk_dp_update_bits(mtk_dp, REG_3F44_DP_ENC_P0_3,
+			   0, ENC_PHY_PWR_OVERWRITE_EN);
+}
+
+static void mtk_dp_encoder_force_bias_power_off(struct mtk_dp *mtk_dp)
+{
+	/* Force MCU to disable power */
+	mtk_dp_update_bits(mtk_dp, REG_3F44_DP_ENC_P0_3,
+			   ENC_PHY_PWR_OVERWRITE_EN, ENC_PHY_PWR_OVERWRITE_EN);
+	mtk_dp_update_bits(mtk_dp, REG_3F44_DP_ENC_P0_3,
+			   FIELD_PREP_CONST(ENC_PHY_PWR_STATE_OVERWRITE_MASK,
+					    ENC_PHY_ALL_PWR_OFF),
+			   ENC_PHY_PWR_STATE_OVERWRITE_MASK);
+	mtk_dp_update_bits(mtk_dp, REG_3F44_DP_ENC_P0_3,
+			   0, ENC_PHY_PWR_OVERWRITE_EN);
+}
+
+static void mtk_dp_initialize_psr_settings(struct mtk_dp *mtk_dp)
+{
+	mtk_dp_update_bits(mtk_dp, MTK_DP_PSR_FRAME_START_MARKER_0, 0,
+			   DP_ENC_P0_3_FRAME_MARKER_MASK);
+	mtk_dp_update_bits(mtk_dp, MTK_DP_PSR_FRAME_END_MARKER_0, 1,
+			   DP_ENC_P0_3_FRAME_MARKER_MASK);
+
+	mtk_dp_update_bits(mtk_dp, MTK_DP_PSR_FRAME_START_MARKER_1, 8,
+			   DP_ENC_P0_3_FRAME_MARKER_MASK);
+	mtk_dp_update_bits(mtk_dp, MTK_DP_PSR_FRAME_END_MARKER_1, 9,
+			   DP_ENC_P0_3_FRAME_MARKER_MASK);
+
+	mtk_dp_update_bits(mtk_dp, REG_33C0_DP_ENCODER1_P0, 0,
+			   SDP_TESTBUS_SEL_DP_ENC_MASK);
+	mtk_dp_update_bits(mtk_dp, REG_33C4_DP_ENCODER1_P0,
+			   DP_TX_ENCODER_TESTBUS_SEL_DP_ENC,
+			   DP_TX_ENCODER_TESTBUS_SEL_DP_ENC_MASK);
+	mtk_dp_update_bits(mtk_dp, REG_3F28_DP_ENC_P0_3,
+			   DP_TX_SDP_PSR_AS_TESTBUS << 2,
+			   DP_TX_SDP_PSR_AS_TESTBUS_MASK);
+}
+
+static void mtk_dp_initialize_settings_v2p1(struct mtk_dp *mtk_dp)
+{
+	/* For DP2.1 and eDP1.5 IPs, reset all and enable probing */
+	mtk_dp_update_bits(mtk_dp, MTK_DP_TOP_RESET_AND_PROBE,
+			   RG_SW_RST_ALL, RG_SW_RST_ALL);
+
+	mtk_dp_update_bits(mtk_dp, MTK_DP_TOP_RESET_AND_PROBE,
+			   FIELD_PREP_CONST(RG_PROBE_LOW_SEL_MASK, RG_PROBE_ENCODER0),
+			   RG_PROBE_LOW_SEL_MASK);
+
+	mtk_dp_update_bits(mtk_dp, MTK_DP_TOP_RESET_AND_PROBE,
+			   RG_PROBE_LOW_HIGH_SWAP, RG_PROBE_LOW_HIGH_SWAP);
+}
+
 static void mtk_dp_initialize_settings(struct mtk_dp *mtk_dp)
 {
 	mtk_dp_update_bits(mtk_dp, MTK_DP_TRANS_P0_342C,
@@ -1119,12 +1215,15 @@ static void mtk_dp_initialize_settings(struct mtk_dp *mtk_dp)
 			   AUDIO_CH_SRC_SEL_DP_ENC0_P0);
 	mtk_dp_update_bits(mtk_dp, MTK_DP_ENC0_P0_304C,
 			   0, SDP_VSYNC_RISING_MASK_DP_ENC0_P0_MASK);
-	mtk_dp_update_bits(mtk_dp, MTK_DP_TOP_IRQ_MASK,
-			   IRQ_MASK_AUX_TOP_IRQ, IRQ_MASK_AUX_TOP_IRQ);
 }
 
 static void mtk_dp_initialize_aux_hpd_detect_settings(struct mtk_dp *mtk_dp)
 {
+	/* Mask Encoder and Transmitter interrupts, unmask AUX TOP */
+	mtk_dp_update_bits(mtk_dp, MTK_DP_TOP_IRQ_MASK,
+			   ENCODER0_IRQ_MSK | TRANS_IRQ_MSK,
+			   ENCODER0_IRQ_MSK | TRANS_IRQ_MSK | AUX_TOP_IRQ_MSK);
+
 	/* Set interrupt debounce threshold time */
 	mtk_dp_update_bits(mtk_dp, MTK_DP_AUX_P0_364C,
 			   FIELD_PREP_CONST(HPD_INT_LOW_TIME_THD, 2) |
@@ -1151,6 +1250,10 @@ static void mtk_dp_initialize_hpd_detect_settings(struct mtk_dp *mtk_dp)
 {
 	u32 val;
 
+	/* Mask AUX TOP interrupt, as this uses transmitter for HPD */
+	mtk_dp_update_bits(mtk_dp, MTK_DP_TOP_IRQ_MASK,
+			   AUX_TOP_IRQ_MSK, AUX_TOP_IRQ_MSK);
+
 	/* Debounce threshold */
 	mtk_dp_update_bits(mtk_dp, MTK_DP_TRANS_P0_3410,
 			   8, HPD_DEB_THD_DP_TRANS_P0_MASK);
@@ -1200,24 +1303,87 @@ static void mtk_dp_initialize_aux_settings(struct mtk_dp *mtk_dp)
 			   RX_REPLY_COMPLETE_MODE_AUX_TX_P0);
 }
 
-static void mtk_dp_initialize_digital_settings(struct mtk_dp *mtk_dp)
+static void mtk_dp_initialize_common_digital_settings(struct mtk_dp *mtk_dp)
 {
 	mtk_dp_update_bits(mtk_dp, MTK_DP_ENC0_P0_304C,
 			   0, VBID_VIDEO_MUTE_DP_ENC0_P0_MASK);
 
 	mtk_dp_update_bits(mtk_dp, MTK_DP_ENC1_P0_3368,
-			   BS2BS_MODE_DP_ENC1_P0_VAL << 12,
-			   BS2BS_MODE_DP_ENC1_P0_MASK);
+			   BS2BS_MODE_DP_ENC1_P0, BS2BS_MODE_DP_ENC1_P0_MASK);
+}
+
+static void mtk_dp_initialize_digital_settings_v2p1(struct mtk_dp *mtk_dp)
+{
+	/* Set XTAL frequency for Panel Self Refresh (PSR) */
+	if (mtk_dp->data->psr_supported)
+		mtk_dp_update_bits(mtk_dp, REG_3FF8_DP_ENC_P0_3,
+				   FIELD_PREP(DP_ENCODER_PSR_XTAL_FREQ_MHZ_MASK, 25),
+				   DP_ENCODER_PSR_XTAL_FREQ_MHZ_MASK);
+
+	/* Enable I-Mode */
+	mtk_dp_update_bits(mtk_dp, MTK_DP_ENC0_P0_3000,
+			   DP_I_MODE_ENABLE, DP_I_MODE_ENABLE);
+
+	/* Reset Video SRAM and Symbol count */
+	mtk_dp_update_bits(mtk_dp, MTK_DP_ENC0_P0_3000,
+			   REG_BS_SYMBOL_CNT_RESET, REG_BS_SYMBOL_CNT_RESET);
+	mtk_dp_update_bits(mtk_dp, MTK_DP_ENC1_P0_3368,
+			   VIDEO_SRAM_FIFO_CNT_RESET_SEL_DP_ENC1_P0,
+			   VIDEO_SRAM_FIFO_CNT_RESET_SEL_MASK);
+	mtk_dp_update_bits(mtk_dp, MTK_DP_ENC1_P0_3368,
+			   BS_FOLLOW_SEL_DP_ENC0_P0, BS_FOLLOW_SEL_DP_ENC0_P0);
+
+	/* [5:0] Video SRAM start address */
+	mtk_dp_update_bits(mtk_dp, MTK_DP_ENC0_P0_303C,
+			   0x8, SRAM_START_READ_THRD_DP_ENC0_P0_MASK);
+
+	/* Disable Pattern Generator in Panel Self Refresh mode */
+	if (mtk_dp->data->psr_supported)
+		mtk_dp_update_bits(mtk_dp, REG_3F80_DP_ENC_P0_3,
+				   0, PSR_PATGEN_AVT_EN_FLDMASK);
+
+	/* Force MCU to enable BIAS and PLL */
+	mtk_dp_encoder_force_bias_power_on(mtk_dp);
+
+	mtk_dp_update_bits(mtk_dp, REG_3FF8_DP_ENC_P0_3,
+			   PHY_STATE_W_1_DP_ENC_P0_3, PHY_STATE_W_1_DP_ENC_P0_3);
 
+	/* Force enable Digital Video Output */
+	mtk_dp_update_bits(mtk_dp, REG_3FF8_DP_ENC_P0_3,
+			   DP_ENCODER_DVO_ON_W_1, DP_ENCODER_DVO_ON_W_1);
+}
+
+static void mtk_dp_encoder_reset(struct mtk_dp *mtk_dp)
+{
 	/* dp tx encoder reset all sw */
 	mtk_dp_update_bits(mtk_dp, MTK_DP_ENC0_P0_3004,
 			   DP_TX_ENCODER_4P_RESET_SW_DP_ENC0_P0,
 			   DP_TX_ENCODER_4P_RESET_SW_DP_ENC0_P0);
 
+	if (mtk_dp->data->hwip_v1p4) {
+		mtk_dp_update_bits(mtk_dp, MTK_DP_ENC0_P0_3004, 0,
+				   DP_TX_ENCODER_4P_RESET_SW_DP_ENC0_P0);
+		mtk_dp_update_bits(mtk_dp, REG_3FF8_DP_ENC_P0_3,
+				   ENC_PHY_STATE_RESET_ALL_MASK,
+				   ENC_PHY_STATE_RESET_ALL_MASK);
+	}
+
 	/* Wait for sw reset to complete */
 	usleep_range(1000, 5000);
-	mtk_dp_update_bits(mtk_dp, MTK_DP_ENC0_P0_3004,
-			   0, DP_TX_ENCODER_4P_RESET_SW_DP_ENC0_P0);
+
+	if (!mtk_dp->data->hwip_v1p4)
+		mtk_dp_update_bits(mtk_dp, MTK_DP_ENC0_P0_3004,
+				   0, DP_TX_ENCODER_4P_RESET_SW_DP_ENC0_P0);
+}
+
+static void mtk_dp_initialize_digital_settings(struct mtk_dp *mtk_dp)
+{
+	mtk_dp_initialize_common_digital_settings(mtk_dp);
+
+	if (mtk_dp->data->hwip_v1p4)
+		mtk_dp_initialize_digital_settings_v2p1(mtk_dp);
+
+	mtk_dp_encoder_reset(mtk_dp);
 }
 
 static void mtk_dp_digital_sw_reset(struct mtk_dp *mtk_dp)
@@ -1230,6 +1396,26 @@ static void mtk_dp_digital_sw_reset(struct mtk_dp *mtk_dp)
 	usleep_range(1000, 5000);
 	mtk_dp_update_bits(mtk_dp, MTK_DP_TRANS_P0_340C,
 			   0, DP_TX_TRANSMITTER_4P_RESET_SW_DP_TRANS_P0);
+
+	/* Only for the new eDP 1.5 IP, set the internal clock generators */
+	if (mtk_dp->data->hwip_v1p4 &&
+	    mtk_dp->data->bridge_type == DRM_MODE_CONNECTOR_eDP) {
+		u32 val;
+
+		/* Enable internal clock outputs for AUX TOP, DATA and MUX */
+		val = EDP_TX_TOP_CLKGEN_AUX_P0_EN | EDP_TX_TOP_CLKGEN_AUX_MUX_DATA_EN |
+		      EDP_TX_TOP_CLKGEN_AUX_MUX_VALID_EN;
+
+		/* Enable XTAL output */
+		val |= EDP_TX_TOP_CLKGEN_XTAL_P0_EN;
+
+		/* VSC and Encoders */
+		val |= EDP_TX_TOP_CLKGEN_LS_VSC_W_0_EN;
+		val |= EDP_TX_TOP_CLKGEN_LS_ENCODER_L0_EN | EDP_TX_TOP_CLKGEN_LS_ENCODER_L1_EN;
+		val |= EDP_TX_TOP_CLKGEN_LS_ENCODER_L2_EN | EDP_TX_TOP_CLKGEN_LS_ENCODER_L3_EN;
+
+		mtk_dp_update_bits(mtk_dp, EDP_TX_TOP_CLKGEN_0, val, val);
+	}
 }
 
 static void mtk_dp_sdp_path_reset(struct mtk_dp *mtk_dp)
@@ -1246,6 +1432,9 @@ static void mtk_dp_sdp_path_reset(struct mtk_dp *mtk_dp)
 
 static void mtk_dp_set_lanes(struct mtk_dp *mtk_dp, int lanes)
 {
+	if (mtk_dp->data->force_pwr_states)
+		mtk_dp_encoder_force_bias_power_on(mtk_dp);
+
 	mtk_dp_update_bits(mtk_dp, MTK_DP_TRANS_P0_35F0,
 			   lanes == 0 ? 0 : DP_TRANS_DUMMY_RW_0,
 			   DP_TRANS_DUMMY_RW_0_MASK);
@@ -1361,8 +1550,10 @@ static int mtk_dp_phy_configure(struct mtk_dp *mtk_dp,
 		}
 	};
 
-	mtk_dp_update_bits(mtk_dp, MTK_DP_TOP_PWR_STATE, DP_PWR_STATE_BANDGAP,
-			   DP_PWR_STATE_MASK);
+	/* Set power state requests only if power states are not forced */
+	if (!mtk_dp->data->force_pwr_states)
+		mtk_dp_update_bits(mtk_dp, MTK_DP_TOP_PWR_STATE, DP_PWR_STATE_BANDGAP,
+				   DP_PWR_STATE_MASK);
 
 	ret = phy_configure(mtk_dp->phy, &phy_opts);
 	if (ret)
@@ -1375,6 +1566,11 @@ static int mtk_dp_phy_configure(struct mtk_dp *mtk_dp,
 	if (mtk_dp->phy_dev)
 		mtk_dp_set_calibration_data(mtk_dp);
 
+	if (mtk_dp->data->force_pwr_states)
+		mtk_dp_update_bits(mtk_dp, REG_3FF8_DP_ENC_P0_3,
+				   PHY_STATE_W_1_DP_ENC_P0_3,
+				   PHY_STATE_W_1_DP_ENC_P0_3);
+
 	mtk_dp_update_bits(mtk_dp, MTK_DP_TOP_PWR_STATE,
 			   DP_PWR_STATE_BANDGAP_TPLL_LANE, DP_PWR_STATE_MASK);
 
@@ -1424,17 +1620,24 @@ static void mtk_dp_training_set_scramble(struct mtk_dp *mtk_dp, bool enable)
 static void mtk_dp_video_mute(struct mtk_dp *mtk_dp, bool enable)
 {
 	struct arm_smccc_res res;
-	u32 val = VIDEO_MUTE_SEL_DP_ENC0_P0 |
-		  (enable ? VIDEO_MUTE_SW_DP_ENC0_P0 : 0);
+	const u32 mask = VIDEO_MUTE_SEL_DP_ENC0_P0 | VIDEO_MUTE_SW_DP_ENC0_P0;
+	u32 val = VIDEO_MUTE_SEL_DP_ENC0_P0 | (enable ? VIDEO_MUTE_SW_DP_ENC0_P0 : 0);
+	u32 smc_para, smc_val;
 
-	mtk_dp_update_bits(mtk_dp, MTK_DP_ENC0_P0_3000,
-			   val,
-			   VIDEO_MUTE_SEL_DP_ENC0_P0 |
-			   VIDEO_MUTE_SW_DP_ENC0_P0);
+	/* Set VIDEO_MUTE in unsecured world... */
+	mtk_dp_update_bits(mtk_dp, MTK_DP_ENC0_P0_3000, val, mask);
+
+	/* ...and do the same in ATF as well */
+	if (mtk_dp->data->hwip_v1p4) {
+		smc_para = (mtk_dp->data->smc_cmd << 16) | enable;
+		smc_val = MTK_DP_SIP_REQ_VIDEO_UNMUTE;
+	} else {
+		smc_para = 0;
+		smc_val = 0;
+	}
 
-	arm_smccc_smc(MTK_DP_SIP_CONTROL_AARCH32,
-		      mtk_dp->data->smc_cmd, enable,
-		      0, 0, 0, 0, 0, &res);
+	arm_smccc_smc(MTK_DP_SIP_CONTROL_AARCH32, mtk_dp->data->smc_cmd, enable,
+		      smc_para, smc_val, 0, 0, 0, &res);
 
 	dev_dbg(mtk_dp->dev, "smc cmd: 0x%x, p1: %s, ret: 0x%lx-0x%lx\n",
 		mtk_dp->data->smc_cmd, enable ? "enable" : "disable", res.a0, res.a1);
@@ -1522,6 +1725,9 @@ static void mtk_dp_power_disable(struct mtk_dp *mtk_dp)
 
 	mtk_dp_write(mtk_dp, MTK_DP_TOP_PWR_STATE, 0);
 
+	if (mtk_dp->data->force_pwr_states)
+		mtk_dp_encoder_force_bias_power_off(mtk_dp);
+
 	if (unlikely(mtk_dp->phy_dev)) {
 		mtk_dp_update_bits(mtk_dp, MTK_DP_0034,
 			   DA_CKM_CKTX0_EN_FORCE_EN, DA_CKM_CKTX0_EN_FORCE_EN);
@@ -2081,7 +2287,14 @@ static void mtk_dp_init_port(struct mtk_dp *mtk_dp)
 	mtk_dp_set_idle_pattern(mtk_dp, true);
 	mtk_dp_initialize_priv_data(mtk_dp);
 
-	mtk_dp_initialize_settings(mtk_dp);
+	if (mtk_dp->data->psr_supported)
+		mtk_dp_initialize_psr_settings(mtk_dp);
+
+	if (mtk_dp->data->hwip_v1p4)
+		mtk_dp_initialize_settings_v2p1(mtk_dp);
+	else
+		mtk_dp_initialize_settings(mtk_dp);
+
 	mtk_dp_initialize_aux_settings(mtk_dp);
 	mtk_dp_initialize_digital_settings(mtk_dp);
 
@@ -2583,6 +2796,9 @@ static void mtk_dp_bridge_atomic_disable(struct drm_bridge *bridge,
 	/* SDP path reset sw*/
 	mtk_dp_sdp_path_reset(mtk_dp);
 
+	if (mtk_dp->data->force_pwr_states)
+		mtk_dp_encoder_force_bias_power_on(mtk_dp);
+
 	/* Ensure the sink is muted */
 	msleep(20);
 }
@@ -3089,6 +3305,7 @@ static const struct mtk_dp_data mt8188_dp_data = {
 	.audio_pkt_in_hblank_area = true,
 	.audio_m_div2_bit = MT8188_AUDIO_M_CODE_MULT_DIV_SEL_DP_ENC0_P0_DIV_2,
 	.hw_max_link_rate = DP_LINK_BW_5_4,
+	.sdp_encoder1_enable = true,
 };
 
 static const struct mtk_dp_data mt8195_edp_data = {
@@ -3098,6 +3315,7 @@ static const struct mtk_dp_data mt8195_edp_data = {
 	.audio_supported = false,
 	.audio_m_div2_bit = MT8195_AUDIO_M_CODE_MULT_DIV_SEL_DP_ENC0_P0_DIV_2,
 	.hw_max_link_rate = DP_LINK_BW_5_4,
+	.sdp_encoder1_enable = true,
 };
 
 static const struct mtk_dp_data mt8195_dp_data = {
@@ -3107,6 +3325,19 @@ static const struct mtk_dp_data mt8195_dp_data = {
 	.audio_supported = true,
 	.audio_m_div2_bit = MT8195_AUDIO_M_CODE_MULT_DIV_SEL_DP_ENC0_P0_DIV_2,
 	.hw_max_link_rate = DP_LINK_BW_5_4,
+	.sdp_encoder1_enable = true,
+};
+
+static const struct mtk_dp_data mt8196_edp_data = {
+	.bridge_type = DRM_MODE_CONNECTOR_eDP,
+	.smc_cmd = MTK_DP_SIP_ATF_EDP_SET_VID_MUTE,
+	.audio_supported = false,
+	.audio_m_div2_bit = MT8195_AUDIO_M_CODE_MULT_DIV_SEL_DP_ENC0_P0_DIV_2,
+	.hw_max_link_rate = DP_LINK_BW_8_1,
+	.hwip_v1p4 = true,
+	.aux_hpd_supported = true,
+	.force_pwr_states = true,
+	.psr_supported = true,
 };
 
 static const struct of_device_id mtk_dp_of_match[] = {
@@ -3126,6 +3357,10 @@ static const struct of_device_id mtk_dp_of_match[] = {
 		.compatible = "mediatek,mt8195-dp-tx",
 		.data = &mt8195_dp_data,
 	},
+	{
+		.compatible = "mediatek,mt8196-edp-tx",
+		.data = &mt8196_edp_data,
+	},
 	{},
 };
 MODULE_DEVICE_TABLE(of, mtk_dp_of_match);
diff --git a/drivers/gpu/drm/mediatek/mtk_dp_reg.h b/drivers/gpu/drm/mediatek/mtk_dp_reg.h
index 5a3b3e2b4f49..9caf743f4fe6 100644
--- a/drivers/gpu/drm/mediatek/mtk_dp_reg.h
+++ b/drivers/gpu/drm/mediatek/mtk_dp_reg.h
@@ -31,25 +31,38 @@
 #define DP_TX3_PRE_EMPH_MASK			GENMASK(27, 26)
 #define MTK_DP_TOP_RESET_AND_PROBE	0x20
 #define SW_RST_B_PHYD				BIT(4)
-#define RG_SW_RST_MASK				GENMASK(7, 0)
-#define RG_SW_RST				0xff
+#define RG_SW_RST_ALL				GENMASK(7, 0)
 #define RG_PROBE_LOW_SEL_MASK			GENMASK(18, 16)
+#  define RG_PROBE_SW				0
+#  define RG_PROBE_ENCODER0			1
+#  define RG_PROBE_TRANSMITTER			2
+#  define RG_PROBE_AUX_TOP			3
+#  define RG_PROBE_PHY				4
+#  define RG_PROBE_MST14			5
+#  define RG_PROBE_ENCODER1			6
 #define RG_PROBE_LOW_SEL			BIT(16)
-#define RG_PROBE_LOW_HIGH_SWAP_MASK		BIT(23)
 #define RG_PROBE_LOW_HIGH_SWAP			BIT(23)
 
 #define MTK_DP_TOP_IRQ_MASK		0x2c
-#define ENCODER_IRQ_MSK				BIT(0)
+#define ENCODER0_IRQ_MSK			BIT(0)
 #define TRANS_IRQ_MSK				BIT(1)
-#define IRQ_MASK_AUX_TOP_IRQ			BIT(2)
+#define AUX_TOP_IRQ_MSK				BIT(2)
+#define ENCODER1_IRQ_MSK			BIT(3)
 
 #define MTK_DP_TOP_MEM_PD		0x38
 #define MEM_ISO_EN				BIT(0)
 #define FUSE_SEL				BIT(2)
 
 #define EDP_TX_TOP_CLKGEN_0		0x74
-#define EDP_TX_TOP_CLKGEN_REST_MASK		0xf
-#define EDP_TX_TOP_CLKGEN_REST_VALUE		0xf
+#define EDP_TX_TOP_CLKGEN_AUX_P0_EN		BIT(0)
+#define EDP_TX_TOP_CLKGEN_AUX_MUX_DATA_EN	BIT(1)
+#define EDP_TX_TOP_CLKGEN_AUX_MUX_VALID_EN	BIT(2)
+#define EDP_TX_TOP_CLKGEN_XTAL_P0_EN		BIT(3)
+#define EDP_TX_TOP_CLKGEN_LS_VSC_W_0_EN		BIT(4)
+#define EDP_TX_TOP_CLKGEN_LS_ENCODER_L0_EN	BIT(5)
+#define EDP_TX_TOP_CLKGEN_LS_ENCODER_L1_EN	BIT(6)
+#define EDP_TX_TOP_CLKGEN_LS_ENCODER_L2_EN	BIT(7)
+#define EDP_TX_TOP_CLKGEN_LS_ENCODER_L3_EN	BIT(8)
 
 /* offset: ENC0_OFFSET (0x1000) */
 #define MTK_DP_ENC0_P0_3000			0x1000
@@ -210,16 +223,19 @@
 #define BS2BS_MODE_DP_ENC1_P0				BIT(12)
 #define BS_FOLLOW_SEL_DP_ENC0_P0			BIT(15)
 #define BS2BS_MODE_DP_ENC1_P0_MASK			GENMASK(13, 12)
-#define BS2BS_MODE_DP_ENC1_P0_VAL			1
 #define DP_ENC1_P0_3368_VAL				(VIDEO_SRAM_FIFO_CNT_RESET_SEL_DP_ENC1_P0 | \
 							 VIDEO_STABLE_CNT_THRD_DP_ENC1_P0 | \
 							 SDP_DP13_EN_DP_ENC1_P0 | \
 							 BS2BS_MODE_DP_ENC1_P0)
-
 #define MTK_DP_ENC1_P0_3374			0x1374
 #define SDP_ASP_INSERT_IN_HBLANK_DP_ENC1_P0_MASK	BIT(12)
 #define SDP_DOWN_ASP_CNT_INIT_DP_ENC1_P0_MASK		GENMASK(11, 0)
-
+#define REG_33C0_DP_ENCODER1_P0			0x13c0
+#define SDP_TESTBUS_SEL_DP_ENC_MASK			GENMASK(15, 12)
+#define SDP_TESTBUS_SEL_BIT_DP_ENC			BIT(7)
+#define REG_33C4_DP_ENCODER1_P0			0x13c4
+#define DP_TX_ENCODER_TESTBUS_SEL_DP_ENC_MASK		GENMASK(6, 5)
+#define DP_TX_ENCODER_TESTBUS_SEL_DP_ENC		BIT(5)
 #define MTK_DP_ENC1_P0_33F4			0x13f4
 #define DP_ENC_DUMMY_RW_1_AUDIO_RST_EN			BIT(0)
 #define DP_ENC_DUMMY_RW_1				BIT(9)
@@ -361,6 +377,31 @@
 #define MTK_DP_AUX_P0_37C8			0x17c8
 #define MTK_ATOP_EN_AUX_TX_P0				BIT(0)
 
+/* offset info queue */
+#define MTK_DP_PSR_FRAME_START_MARKER_0			0x1f04
+#define MTK_DP_PSR_FRAME_START_MARKER_1			0x1f08
+#define MTK_DP_PSR_FRAME_END_MARKER_0			0x1f0c
+#define MTK_DP_PSR_FRAME_END_MARKER_1			0x1f10
+#define DP_ENC_P0_3_FRAME_MARKER_MASK			GENMASK(15, 0)
+#define REG_3F28_DP_ENC_P0_3			0x1f28
+#define DP_TX_SDP_PSR_AS_TESTBUS_MASK			GENMASK(5, 2)
+#define DP_TX_SDP_PSR_AS_TESTBUS			10
+#define REG_3F40_DP_ENC_P0_3			0x1f40
+#define REG_3F44_DP_ENC_P0_3			0x1f44
+#define ENC_PHY_PWR_STATE_OVERWRITE_MASK		GENMASK(4, 3)
+#define ENC_PHY_ALL_PWR_OFF				0
+#define ENC_PHY_BIAS_PWR_ON				1
+#define ENC_PHY_BIAS_PLL_PWR_ON				2
+#define ENC_PHY_ALL_PWR_ON				3
+#define ENC_PHY_PWR_OVERWRITE_EN			BIT(2)
+#define REG_3F80_DP_ENC_P0_3			0x1f80
+#define PSR_PATGEN_AVT_EN_FLDMASK			0x20
+#define REG_3FF8_DP_ENC_P0_3			0x1ff8
+#define ENC_PHY_STATE_RESET_ALL_MASK			GENMASK(7, 0)
+#define PHY_STATE_W_1_DP_ENC_P0_3			BIT(6)
+#define DP_ENCODER_DVO_ON_W_1				BIT(5)
+#define DP_ENCODER_PSR_XTAL_FREQ_MHZ_MASK		GENMASK(13, 9)
+
 /* offset: SEC_OFFSET (0x2000) */
 #define SEC_OFFSET	0x2000
 
-- 
2.54.0


^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [PATCH 11/11] drm/mediatek: mtk_dp: Clarify XTAL freq and Debounce registers
  2026-07-01 12:20 [PATCH 00/11] drm: MediaTek DisplayPort cleanups and MT8196 eDP AngeloGioacchino Del Regno
                   ` (9 preceding siblings ...)
  2026-07-01 12:20 ` [PATCH 10/11] drm/mediatek: mtk_dp: Add support for eDP1.5 IPs and MT8196 SoC AngeloGioacchino Del Regno
@ 2026-07-01 12:20 ` AngeloGioacchino Del Regno
  2026-07-01 14:09   ` sashiko-bot
  10 siblings, 1 reply; 20+ messages in thread
From: AngeloGioacchino Del Regno @ 2026-07-01 12:20 UTC (permalink / raw)
  To: chunkuang.hu
  Cc: p.zabel, airlied, simona, maarten.lankhorst, mripard, tzimmermann,
	robh, krzk+dt, conor+dt, matthias.bgg, angelogioacchino.delregno,
	jitao.shi, granquet, rex-bc.chen, dmitry.osipenko, ck.hu,
	amergnat, justin.yeh, jason-jh.lin, dri-devel, linux-mediatek,
	devicetree, linux-kernel, linux-arm-kernel, kernel

Clarify the meaning of the sub-fields in the crystal frequency and
transmitter interrupt debounce registers, with the only purpose of
increasing human readability.

Signed-off-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
---
 drivers/gpu/drm/mediatek/mtk_dp.c     | 35 ++++++++++++++++-----------
 drivers/gpu/drm/mediatek/mtk_dp_reg.h |  6 +++--
 2 files changed, 25 insertions(+), 16 deletions(-)

diff --git a/drivers/gpu/drm/mediatek/mtk_dp.c b/drivers/gpu/drm/mediatek/mtk_dp.c
index 605ead7fa9bf..b861a5df9316 100644
--- a/drivers/gpu/drm/mediatek/mtk_dp.c
+++ b/drivers/gpu/drm/mediatek/mtk_dp.c
@@ -1204,9 +1204,15 @@ static void mtk_dp_initialize_settings_v2p1(struct mtk_dp *mtk_dp)
 
 static void mtk_dp_initialize_settings(struct mtk_dp *mtk_dp)
 {
+	/*
+	 * Set DP XTAL freq to 26MHz and accumulator to 1.
+	 * Valid values for XTAL freq are 12 and 26.
+	 */
 	mtk_dp_update_bits(mtk_dp, MTK_DP_TRANS_P0_342C,
-			   XTAL_FREQ_DP_TRANS_P0_DEFAULT,
-			   XTAL_FREQ_DP_TRANS_P0_MASK);
+			   FIELD_PREP_CONST(XTAL_FREQ_DP_ACCUM_NUM_MASK, 1) |
+			   FIELD_PREP_CONST(XTAL_FREQ_DP_CLOCK_MHZ_MASK, 26),
+			   XTAL_FREQ_DP_ACCUM_NUM_MASK | XTAL_FREQ_DP_CLOCK_MHZ_MASK);
+
 	mtk_dp_update_bits(mtk_dp, MTK_DP_TRANS_P0_3540,
 			   FEC_CLOCK_EN_MODE_DP_TRANS_P0,
 			   FEC_CLOCK_EN_MODE_DP_TRANS_P0);
@@ -1248,28 +1254,29 @@ static void mtk_dp_initialize_aux_hpd_detect_settings(struct mtk_dp *mtk_dp)
 
 static void mtk_dp_initialize_hpd_detect_settings(struct mtk_dp *mtk_dp)
 {
-	u32 val;
-
 	/* Mask AUX TOP interrupt, as this uses transmitter for HPD */
 	mtk_dp_update_bits(mtk_dp, MTK_DP_TOP_IRQ_MASK,
 			   AUX_TOP_IRQ_MSK, AUX_TOP_IRQ_MSK);
 
-	/* Debounce threshold */
+	/* Set Hotplug debounce threshold time: xtal_period * deb_thd */
 	mtk_dp_update_bits(mtk_dp, MTK_DP_TRANS_P0_3410,
 			   8, HPD_DEB_THD_DP_TRANS_P0_MASK);
 
-	val = (HPD_INT_THD_DP_TRANS_P0_LOWER_500US |
-	       HPD_INT_THD_DP_TRANS_P0_UPPER_1100US) << 4;
-	mtk_dp_update_bits(mtk_dp, MTK_DP_TRANS_P0_3410,
-			   val, HPD_INT_THD_DP_TRANS_P0_MASK);
-
 	/*
-	 * Connect threshold 1.5ms + 5 x 0.1ms = 2ms
-	 * Disconnect threshold 1.5ms + 5 x 0.1ms = 2ms
+	 * Set interrupt debounce threshold time
+	 * VAL  |  0     1     2     3  INT_THD
+	 * Low  | 100   300   500   700 uS
+	 * High | 700   900  1100  1300 uS
 	 */
-	val = (5 << 8) | (5 << 12);
 	mtk_dp_update_bits(mtk_dp, MTK_DP_TRANS_P0_3410,
-			   val,
+			   FIELD_PREP_CONST(HPD_INT_LOW_THD_DP_TRANS_P0_MASK, 2) |
+			   FIELD_PREP_CONST(HPD_INT_HIGH_THD_DP_TRANS_P0_MASK, 2),
+			   HPD_INT_THD_DP_TRANS_P0_MASK);
+
+	/* Connection and Disconnection thresholds: 1.5ms + (5 x 0.1) ms = 2ms */
+	mtk_dp_update_bits(mtk_dp, MTK_DP_TRANS_P0_3410,
+			   FIELD_PREP_CONST(HPD_DISC_THD_DP_TRANS_P0_MASK, 5) |
+			   FIELD_PREP_CONST(HPD_CONN_THD_DP_TRANS_P0_MASK, 5),
 			   HPD_DISC_THD_DP_TRANS_P0_MASK |
 			   HPD_CONN_THD_DP_TRANS_P0_MASK);
 	mtk_dp_update_bits(mtk_dp, MTK_DP_TRANS_P0_3430,
diff --git a/drivers/gpu/drm/mediatek/mtk_dp_reg.h b/drivers/gpu/drm/mediatek/mtk_dp_reg.h
index 9caf743f4fe6..418a2318c656 100644
--- a/drivers/gpu/drm/mediatek/mtk_dp_reg.h
+++ b/drivers/gpu/drm/mediatek/mtk_dp_reg.h
@@ -253,6 +253,8 @@
 #define MTK_DP_TRANS_P0_3410				0x1410
 #define HPD_DEB_THD_DP_TRANS_P0_MASK				GENMASK(3, 0)
 #define HPD_INT_THD_DP_TRANS_P0_MASK				GENMASK(7, 4)
+#define HPD_INT_HIGH_THD_DP_TRANS_P0_MASK			GENMASK(3, 2)
+#define HPD_INT_LOW_THD_DP_TRANS_P0_MASK			GENMASK(1, 0)
 #define HPD_INT_THD_DP_TRANS_P0_LOWER_500US			(2 << 4)
 #define HPD_INT_THD_DP_TRANS_P0_UPPER_1100US			(2 << 6)
 #define HPD_DISC_THD_DP_TRANS_P0_MASK				GENMASK(11, 8)
@@ -267,8 +269,8 @@
 #define IRQ_MASK_DP_TRANS_P0_INT_IRQ				(BIT(3) << 4)
 #define IRQ_STATUS_DP_TRANS_P0_MASK				GENMASK(15, 12)
 #define MTK_DP_TRANS_P0_342C				0x142c
-#define XTAL_FREQ_DP_TRANS_P0_DEFAULT				(BIT(0) | BIT(3) | BIT(5) | BIT(6))
-#define XTAL_FREQ_DP_TRANS_P0_MASK				GENMASK(7, 0)
+#define XTAL_FREQ_DP_ACCUM_NUM_MASK				GENMASK(1, 0)
+#define XTAL_FREQ_DP_CLOCK_MHZ_MASK				GENMASK(7, 2)
 #define MTK_DP_TRANS_P0_3430				0x1430
 #define HPD_INT_THD_ECO_DP_TRANS_P0_MASK			GENMASK(1, 0)
 #define HPD_INT_THD_ECO_DP_TRANS_P0_HIGH_BOUND_EXT		BIT(1)
-- 
2.54.0


^ permalink raw reply related	[flat|nested] 20+ messages in thread

* Re: [PATCH 03/11] drm/mediatek: mtk_dp: Fix hdmi codec and phy driver unregistration
  2026-07-01 12:20 ` [PATCH 03/11] drm/mediatek: mtk_dp: Fix hdmi codec and phy driver unregistration AngeloGioacchino Del Regno
@ 2026-07-01 12:32   ` sashiko-bot
  0 siblings, 0 replies; 20+ messages in thread
From: sashiko-bot @ 2026-07-01 12:32 UTC (permalink / raw)
  To: AngeloGioacchino Del Regno; +Cc: robh, conor+dt, devicetree, dri-devel

Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
- [High] Double unregister of platform device in error paths causes Use-After-Free
- [Medium] Incorrect pointer passed to devm_add_action_or_reset causes resource leak of audio platform device
--

commit 2bc8391d481088826fa13d96d05225e5c15e6457
Author: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>

drm/mediatek: mtk_dp: Fix hdmi codec and phy driver unregistration

This commit introduces devm actions to unregister the HDMI Codec and
DisplayPort PHY platform devices, preventing multiple instantiations
during probe deferrals.

> diff --git a/drivers/gpu/drm/mediatek/mtk_dp.c b/drivers/gpu/drm/mediatek/mtk_dp.c
> index eefbc7e0f9c8d..2c738c16dafab 100644
> --- a/drivers/gpu/drm/mediatek/mtk_dp.c
> +++ b/drivers/gpu/drm/mediatek/mtk_dp.c

[ ... ]

> @@ -2680,18 +2687,29 @@ static int mtk_dp_register_audio_driver(struct device *dev)
>  		.data = mtk_dp,
>  		.no_capture_mute = 1,
>  	};
> +	int ret;
>  
>  	mtk_dp->audio_pdev = platform_device_register_data(dev,
>  							   HDMI_CODEC_DRV_NAME,
>  							   PLATFORM_DEVID_AUTO,
>  							   &codec_data,
>  							   sizeof(codec_data));
> -	return PTR_ERR_OR_ZERO(mtk_dp->audio_pdev);
> +	if (IS_ERR(mtk_dp->audio_pdev))
> +		return PTR_ERR(mtk_dp->audio_pdev);
> +
> +	ret = devm_add_action_or_reset(dev, mtk_dp_unregister_pdevs, mtk_dp->phy_dev);

[Severity: Medium]
Is the correct platform device pointer being passed here?

This registers a cleanup action using mtk_dp->phy_dev rather than the
newly created mtk_dp->audio_pdev. This will likely leak the audio device on
probe deferral or driver unbind, and may attempt to unregister the PHY device
at the wrong time instead.

> +	if (ret) {
> +		platform_device_unregister(mtk_dp->audio_pdev);
> +		return dev_err_probe(dev, ret,
> +				     "Failed to add codec unregister devm action");
> +	}
> +	return 0;
>  }
>  
>  static int mtk_dp_register_phy(struct mtk_dp *mtk_dp)
>  {
>  	struct device *dev = mtk_dp->dev;
> +	int ret;
>  
>  	mtk_dp->phy_dev = platform_device_register_data(dev, "mediatek-dp-phy",
>  							PLATFORM_DEVID_AUTO,
> @@ -2701,6 +2719,13 @@ static int mtk_dp_register_phy(struct mtk_dp *mtk_dp)
>  		return dev_err_probe(dev, PTR_ERR(mtk_dp->phy_dev),
>  				     "Failed to create device mediatek-dp-phy\n");
>  
> +	ret = devm_add_action_or_reset(dev, mtk_dp_unregister_pdevs, mtk_dp->phy_dev);
> +	if (ret) {
> +		platform_device_unregister(mtk_dp->phy_dev);

[Severity: High]
Could this cause a use-after-free?

When devm_add_action_or_reset() fails, it automatically executes the cleanup
action, which calls platform_device_unregister() on mtk_dp->phy_dev. Calling
platform_device_unregister() a second time here would double-free the device.

> +		return dev_err_probe(dev, ret,
> +				     "Failed to add phy unregister devm action");
> +	}
> +
>  	mtk_dp_get_calibration_data(mtk_dp);
>  
>  	mtk_dp->phy = devm_phy_get(&mtk_dp->phy_dev->dev, "dp");

[Severity: High]
Can the error path for devm_phy_get() also trigger a double-free?

Looking at the rest of mtk_dp_register_phy() just below this diff:

mtk_dp_register_phy() {
    ...
    mtk_dp->phy = devm_phy_get(&mtk_dp->phy_dev->dev, "dp");
    if (IS_ERR(mtk_dp->phy)) {
        platform_device_unregister(mtk_dp->phy_dev);
        return dev_err_probe(dev, PTR_ERR(mtk_dp->phy), "Failed to get phy\n");
    }
    ...
}

Since the devm unregister action was successfully registered above, returning
an error here will trigger the devm unwind loop. That will unregister the
device a second time after this explicit platform_device_unregister() call.

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260701122024.19557-1-angelogioacchino.delregno@collabora.com?part=3

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH 05/11] drm/mediatek: mtk_dp: Rework register offsets for proper PHY usage
  2026-07-01 12:20 ` [PATCH 05/11] drm/mediatek: mtk_dp: Rework register offsets for proper PHY usage AngeloGioacchino Del Regno
@ 2026-07-01 12:45   ` sashiko-bot
  0 siblings, 0 replies; 20+ messages in thread
From: sashiko-bot @ 2026-07-01 12:45 UTC (permalink / raw)
  To: AngeloGioacchino Del Regno; +Cc: dri-devel, devicetree, conor+dt, robh

Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
- [High] Writes to PHY registers are incorrectly offset by `legacy_regoff` (0x2000), corrupting DP IP registers and breaking PHY configuration.
- [Medium] Removed bit shifts from PIXEL_ENCODE_FORMAT enums cause YCbCr color formats to silently fall back to RGB.
--

commit ef9afa51895ca44a0e35947eba008bc8a9868897
Author: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>

drm/mediatek: mtk_dp: Rework register offsets for proper PHY usage

This commit subtracts the DP PHY register range from the MediaTek DisplayPort
IP register range. It prepares the driver for PHY registration from devicetree
by moving the top offset into the driver structure and out of the legacy regmap
configuration.

> diff --git a/drivers/gpu/drm/mediatek/mtk_dp.c b/drivers/gpu/drm/mediatek/mtk_dp.c
> index f551c4543f4ee..97bce8966a1f3 100644
> --- a/drivers/gpu/drm/mediatek/mtk_dp.c
> +++ b/drivers/gpu/drm/mediatek/mtk_dp.c
[ ... ]
> @@ -424,7 +448,7 @@ static u32 mtk_dp_read(struct mtk_dp *mtk_dp, u32 offset)
>  
>  static int mtk_dp_write(struct mtk_dp *mtk_dp, u32 offset, u32 val)
>  {
> -	int ret = regmap_write(mtk_dp->regs, offset, val);
> +	int ret = regmap_write(mtk_dp->regs, offset + mtk_dp->legacy_regoff, val);
>  
>  	if (ret)
>  		dev_err(mtk_dp->dev,
> @@ -436,7 +460,7 @@ static int mtk_dp_write(struct mtk_dp *mtk_dp, u32 offset, u32 val)
>  static int mtk_dp_update_bits(struct mtk_dp *mtk_dp, u32 offset,
>  			      u32 val, u32 mask)
>  {
> -	int ret = regmap_update_bits(mtk_dp->regs, offset, mask, val);
> +	int ret = regmap_update_bits(mtk_dp->regs, offset + mtk_dp->legacy_regoff, mask, val);
[ ... ]
> @@ -1401,7 +1425,7 @@ static void mtk_dp_power_enable(struct mtk_dp *mtk_dp)
>  			   SW_RST_B_PHYD, SW_RST_B_PHYD);
>  	mtk_dp_update_bits(mtk_dp, MTK_DP_TOP_PWR_STATE,
>  			   DP_PWR_STATE_BANDGAP_TPLL, DP_PWR_STATE_MASK);
> -	mtk_dp_write(mtk_dp, MTK_DP_1040,
> +	mtk_dp_write(mtk_dp, DP_PHY_AUX_RX_CTL,
>  		     RG_DPAUX_RX_VALID_DEGLITCH_EN | RG_XTP_GLB_CKDET_EN |
>  		     RG_DPAUX_RX_EN);

[Severity: High]
Does this code inadvertently misdirect PHY register accesses and corrupt
encoder state?

When legacy devicetrees are used, mtk_dp->legacy_regoff is set to 0x2000.
Because the accessor functions like mtk_dp_write() and mtk_dp_update_bits()
now unconditionally add mtk_dp->legacy_regoff, calls using legacy PHY
registers will be offset incorrectly.

For example, when mtk_dp_power_enable() calls mtk_dp_write() with
DP_PHY_AUX_RX_CTL (which is 0x1040), the write will actually go to 0x3040.
This leaves the PHY unconfigured and silently overwrites the DP encoder
register MTK_DP_ENC0_P0_3040 instead.

[ ... ]
> diff --git a/drivers/gpu/drm/mediatek/mtk_dp_reg.h b/drivers/gpu/drm/mediatek/mtk_dp_reg.h
> index 8ad7a9cc259eb..616ea6440b08d 100644
> --- a/drivers/gpu/drm/mediatek/mtk_dp_reg.h
> +++ b/drivers/gpu/drm/mediatek/mtk_dp_reg.h
[ ... ]
> @@ -130,34 +106,36 @@
>  #define VIDEO_COLOR_DEPTH_DP_ENC0_P0_8BIT		(3 << 8)
>  #define VIDEO_COLOR_DEPTH_DP_ENC0_P0_6BIT		(4 << 8)
>  #define PIXEL_ENCODE_FORMAT_DP_ENC0_P0_MASK		GENMASK(14, 12)
> -#define PIXEL_ENCODE_FORMAT_DP_ENC0_P0_RGB		(0 << 12)
> -#define PIXEL_ENCODE_FORMAT_DP_ENC0_P0_YCBCR422		(1 << 12)
> -#define PIXEL_ENCODE_FORMAT_DP_ENC0_P0_YCBCR420		(2 << 12)
> +#  define PIXEL_ENCODE_FORMAT_DP_ENC0_P0_RGB		0
> +#  define PIXEL_ENCODE_FORMAT_DP_ENC0_P0_YCBCR422	1
> +#  define PIXEL_ENCODE_FORMAT_DP_ENC0_P0_YCBCR420	2
> +#  define PIXEL_ENCODE_FORMAT_DP_ENC0_P0_YONLY		3
> +#  define PIXEL_ENCODE_FORMAT_DP_ENC0_P0_RAW		4

[Severity: Medium]
Will this change cause YCbCr color formats to silently fall back to RGB?

The bit shifts were removed from these format definitions, but the usage
site in mtk_dp_set_color_format() passes these values directly to
mtk_dp_update_bits() alongside the PIXEL_ENCODE_FORMAT_DP_ENC0_P0_MASK,
which is GENMASK(14, 12).

Because regmap_update_bits() internally applies the mask to the value, an
unshifted value like PIXEL_ENCODE_FORMAT_DP_ENC0_P0_YCBCR422 (1) combined
with the mask (0x7000) evaluates to 0. This clears the color format bits
entirely and forces the hardware to output in RGB mode.

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260701122024.19557-1-angelogioacchino.delregno@collabora.com?part=5

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH 06/11] drm/mediatek: mtk_dp: Use PHY API for PHY power sequences
  2026-07-01 12:20 ` [PATCH 06/11] drm/mediatek: mtk_dp: Use PHY API for PHY power sequences AngeloGioacchino Del Regno
@ 2026-07-01 13:05   ` sashiko-bot
  0 siblings, 0 replies; 20+ messages in thread
From: sashiko-bot @ 2026-07-01 13:05 UTC (permalink / raw)
  To: AngeloGioacchino Del Regno; +Cc: robh, conor+dt, dri-devel, devicetree

Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:
- [High] Double unregister of the PHY platform device on error paths.
- [High] HDMI audio codec platform device is leaked due to a copy-paste error.
- [High] Ignoring the return value of phy_power_on() causes an unbalanced phy_power_off() call if power-on fails.
--

commit 6e6e078245707d85aa500b0a872e31948a456e4f
Author: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>

drm/mediatek: mtk_dp: Use PHY API for PHY power sequences
    
The PHY driver has gained support for .power_on() and .power_off()
callbacks: use the API provided phy_power_on(), phy_power_off()
functions instead of writing into PHY registers from this driver.

> diff --git a/drivers/gpu/drm/mediatek/mtk_dp.c b/drivers/gpu/drm/mediatek/mtk_dp.c
> index 97bce8966a1f3..3b5348ab487de 100644
> --- a/drivers/gpu/drm/mediatek/mtk_dp.c
> +++ b/drivers/gpu/drm/mediatek/mtk_dp.c
> @@ -1425,21 +1427,37 @@ static void mtk_dp_power_enable(struct mtk_dp *mtk_dp)
>  			   SW_RST_B_PHYD, SW_RST_B_PHYD);
>  	mtk_dp_update_bits(mtk_dp, MTK_DP_TOP_PWR_STATE,
>  			   DP_PWR_STATE_BANDGAP_TPLL, DP_PWR_STATE_MASK);
> -	mtk_dp_write(mtk_dp, DP_PHY_AUX_RX_CTL,
> -		     RG_DPAUX_RX_VALID_DEGLITCH_EN | RG_XTP_GLB_CKDET_EN |
> -		     RG_DPAUX_RX_EN);
> -	mtk_dp_update_bits(mtk_dp, MTK_DP_0034, 0, DA_CKM_CKTX0_EN_FORCE_EN);
> +
> +	if (mtk_dp->phy_dev) {
> +		mtk_dp_write(mtk_dp, DP_PHY_AUX_RX_CTL,
> +			     RG_DPAUX_RX_VALID_DEGLITCH_EN | RG_XTP_GLB_CKDET_EN |
> +			     RG_DPAUX_RX_EN);
> +		mtk_dp_update_bits(mtk_dp, MTK_DP_0034, 0, DA_CKM_CKTX0_EN_FORCE_EN);
> +	} else {
> +		ret = phy_power_on(mtk_dp->phy);
> +		if (ret)
> +			dev_warn(mtk_dp->dev, "Could not power on PHY!\n");

[Severity: High]
Does ignoring the return value of phy_power_on() cause an unbalanced
phy_power_off() call if power-on fails?

If phy_power_on() fails, the error is swallowed and only a warning is printed.
The function returns normally, leaving the PHY core's internal power_count at 0.

> +	}
>  }
>  
>  static void mtk_dp_power_disable(struct mtk_dp *mtk_dp)
>  {
> +	int ret;
> +
>  	mtk_dp_write(mtk_dp, MTK_DP_TOP_PWR_STATE, 0);
>  
> -	mtk_dp_update_bits(mtk_dp, MTK_DP_0034,
> +	if (unlikely(mtk_dp->phy_dev)) {
> +		mtk_dp_update_bits(mtk_dp, MTK_DP_0034,
>  			   DA_CKM_CKTX0_EN_FORCE_EN, DA_CKM_CKTX0_EN_FORCE_EN);
>  
> -	/* Disable RX */
> -	mtk_dp_write(mtk_dp, DP_PHY_AUX_RX_CTL, 0);
> +		/* Disable RX */
> +		mtk_dp_write(mtk_dp, DP_PHY_AUX_RX_CTL, 0);
> +	} else {
> +		ret = phy_power_off(mtk_dp->phy);

[Severity: High]
Can this unbalanced teardown lead to refcount underflows?

This function unconditionally calls phy_power_off() even if the initial
power-on failed. This decrements power_count to -1 and attempts to disable
regulators and release PM runtime references that were never actually acquired.

> +		if (ret)
> +			dev_warn(mtk_dp->dev, "Could not power off PHY!\n");
> +	}
> +
>  	mtk_dp_write(mtk_dp, MTK_DP_TOP_MEM_PD,
>  		     0x550 | FUSE_SEL | MEM_ISO_EN);
>  }

[ ... ]

The following issues were introduced earlier in this patch series in commit
"drm/mediatek: mtk_dp: Fix hdmi codec and phy driver unregistration":

> diff --git a/drivers/gpu/drm/mediatek/mtk_dp.c b/drivers/gpu/drm/mediatek/mtk_dp.c
> @@ -2680,18 +2687,29 @@ static int mtk_dp_register_audio_driver(struct device *dev)
>  		.data = mtk_dp,
>  		.no_capture_mute = 1,
>  	};
> +	int ret;
>  
>  	mtk_dp->audio_pdev = platform_device_register_data(dev,
>  							   HDMI_CODEC_DRV_NAME,
>  							   PLATFORM_DEVID_AUTO,
>  							   &codec_data,
>  							   sizeof(codec_data));
> -	return PTR_ERR_OR_ZERO(mtk_dp->audio_pdev);
> +	if (IS_ERR(mtk_dp->audio_pdev))
> +		return PTR_ERR(mtk_dp->audio_pdev);
> +
> +	ret = devm_add_action_or_reset(dev, mtk_dp_unregister_pdevs, mtk_dp->phy_dev);

[Severity: High]
Does this devm action incorrectly register mtk_dp->phy_dev for cleanup instead
of the newly created mtk_dp->audio_pdev?

Since this function is called before mtk_dp_register_phy(), mtk_dp->phy_dev is
NULL. When the driver is unbound, devres executes mtk_dp_unregister_pdevs(NULL),
and the actual audio_pdev is permanently leaked.

> +	if (ret) {
> +		platform_device_unregister(mtk_dp->audio_pdev);
> +		return dev_err_probe(dev, ret,
> +				     "Failed to add codec unregister devm action");
> +	}
> +	return 0;
>  }
>  
>  static int mtk_dp_register_phy(struct mtk_dp *mtk_dp)
>  {
>  	struct device *dev = mtk_dp->dev;
> +	int ret;
>  
>  	mtk_dp->phy_dev = platform_device_register_data(dev, "mediatek-dp-phy",
>  							PLATFORM_DEVID_AUTO,
> @@ -2701,6 +2719,13 @@ static int mtk_dp_register_phy(struct mtk_dp *mtk_dp)
>  		return dev_err_probe(dev, PTR_ERR(mtk_dp->phy_dev),
>  				     "Failed to create device mediatek-dp-phy\n");
>  
> +	ret = devm_add_action_or_reset(dev, mtk_dp_unregister_pdevs, mtk_dp->phy_dev);
> +	if (ret) {
> +		platform_device_unregister(mtk_dp->phy_dev);

[Severity: High]
Does this error path cause a double unregister of the PHY platform device?

If devm_add_action_or_reset() fails, it automatically executes the cleanup
action (mtk_dp_unregister_pdevs), which calls
platform_device_unregister(mtk_dp->phy_dev). The error handler then manually
calls platform_device_unregister(mtk_dp->phy_dev) a second time.

Alternatively, if devm_add_action_or_reset() succeeds but devm_phy_get() fails
later in the function, the error handler manually unregisters the device. The
probe then fails, and devres cleans up by executing the registered action,
unregistering the device a second time.

> +		return dev_err_probe(dev, ret,
> +				     "Failed to add phy unregister devm action");
> +	}
> +
>  	mtk_dp_get_calibration_data(mtk_dp);
>  
>  	mtk_dp->phy = devm_phy_get(&mtk_dp->phy_dev->dev, "dp");

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260701122024.19557-1-angelogioacchino.delregno@collabora.com?part=6

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH 07/11] drm/mediatek: mtk_dp: Add support for PHY from devicetree
  2026-07-01 12:20 ` [PATCH 07/11] drm/mediatek: mtk_dp: Add support for PHY from devicetree AngeloGioacchino Del Regno
@ 2026-07-01 13:23   ` sashiko-bot
  0 siblings, 0 replies; 20+ messages in thread
From: sashiko-bot @ 2026-07-01 13:23 UTC (permalink / raw)
  To: AngeloGioacchino Del Regno; +Cc: devicetree, robh, dri-devel, conor+dt

Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:
- [High] Double unregister of the mediatek-dp-phy platform device (`mtk_dp->phy_dev`) on error paths.
- [High] Legacy PHY registers are incorrectly offset by `mtk_dp->legacy_regoff`, corrupting DP TOP and ENC registers and breaking PHY initialization on legacy device trees.
- [Medium] The HDMI audio codec platform device (`mtk_dp->audio_pdev`) is leaked on driver removal or probe failure.
--

commit 60c3f9c6bb6ec600fc25d97fe75494a73e71c05b
Author: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>

    drm/mediatek: mtk_dp: Add support for PHY from devicetree
    
    Add support for specifying phys in devicetree to pass handle
    to the DisplayPort PHY.
    
    In order to retain compatibility with older devicetrees, check if
    phys was specified: if not, initialize the regmap_mmio with the
    legacy configuration and register the mediatek-dp-phy platform
    device from this driver, and get the PHY calibration data.

> diff --git a/drivers/gpu/drm/mediatek/mtk_dp.c b/drivers/gpu/drm/mediatek/mtk_dp.c
> index 3b5348ab487de..bf3a4b15f3ec0 100644
> --- a/drivers/gpu/drm/mediatek/mtk_dp.c
> +++ b/drivers/gpu/drm/mediatek/mtk_dp.c
[ ... ]
> @@ -2769,6 +2790,7 @@ static int mtk_dp_register_phy(struct mtk_dp *mtk_dp)
>  				     "Failed to add phy unregister devm action");
>  	}
>  
> +	/* PHY calibration data is in mtk_dp only for legacy devicetree */
>  	mtk_dp_get_calibration_data(mtk_dp);
>  
>  	mtk_dp->phy = devm_phy_get(&mtk_dp->phy_dev->dev, "dp");

[Severity: High]
Does this code double-unregister the mediatek-dp-phy platform device?

Earlier in mtk_dp_register_phy(), devm_add_action_or_reset() is called to
register mtk_dp_unregister_pdevs. If devm_phy_get() fails, this error path
explicitly calls platform_device_unregister().

When returning an error, devres will unwind and execute the previously
registered devm action (mtk_dp_unregister_pdevs), unregistering the device
a second time.

Similarly, the devm_add_action_or_reset() error path explicitly unregisters
the device, but devm_add_action_or_reset() automatically executes the cleanup
function if it fails, also resulting in an immediate double-unregister.

[ ... ]
> @@ -2821,7 +2843,12 @@ static int mtk_dp_probe(struct platform_device *pdev)
>  
>  	mtk_dp->dev = dev;
>  	mtk_dp->data = (struct mtk_dp_data *)of_device_get_match_data(dev);
> -	mtk_dp->legacy_regoff = MTK_DP_TOP_OFFSET_LEGACY;
> +
> +	/* Prefer PHY from devicetree - if not found, this is legacy */
> +	if (of_property_present(dev->of_node, "phys"))
> +		mtk_dp->legacy_regoff = 0;
> +	else
> +		mtk_dp->legacy_regoff = MTK_DP_TOP_OFFSET_LEGACY;

[Severity: High]
Does adding mtk_dp->legacy_regoff to all register accesses break legacy PHY
initialization?

The code relies on mtk_dp_update_bits() and mtk_dp_write() which unconditionally
add mtk_dp->legacy_regoff (0x2000 for legacy device trees) to all register
accesses:

	int ret = regmap_update_bits(mtk_dp->regs,
				     offset + mtk_dp->legacy_regoff,
				     mask, val);

While this is correct for DP TOP and DP ENC registers that were rebased to 0x0
in the new header, the legacy PHY registers (like DP_PHY_GLB_BIAS_GEN_00 and
DP_PHY_AUX_RX_CTL) still use their original absolute offsets starting at 0x0.

Writing to them now ends up at 0x0 + 0x2000 = 0x2000, overwriting
MTK_DP_TOP_PWR_STATE instead of the intended PHY calibration registers.
Writing to DP_PHY_AUX_RX_CTL (0x1040) writes to 0x3040, which corrupts the
ENC0 register space.

>  
>  	ret = mtk_dp_dt_parse(mtk_dp, pdev);
>  	if (ret)
[ ... ]
> @@ -2872,9 +2899,18 @@ static int mtk_dp_probe(struct platform_device *pdev)
>  					     "Failed to register audio driver\n");
>  	}
>  

[Severity: Medium]
Is the HDMI audio codec platform device (mtk_dp->audio_pdev) leaked on driver
removal or probe failure?

In mtk_dp_register_audio_driver(), a devm action is registered to clean up
mtk_dp->audio_pdev. However, it incorrectly passes mtk_dp->phy_dev as the data
argument:

	ret = devm_add_action_or_reset(dev, mtk_dp_unregister_pdevs,
				       mtk_dp->phy_dev);

Because mtk_dp_register_audio_driver() runs before mtk_dp_register_phy(),
mtk_dp->phy_dev is NULL here. When the driver is unbound or probe fails, devres
executes platform_device_unregister(NULL) which does nothing, but the actual
audio platform device remains registered and is leaked.

> -	ret = mtk_dp_register_phy(mtk_dp);
> -	if (ret)
> -		return ret;
> +	if (!mtk_dp->legacy_regoff) {
> +		mtk_dp->phy = devm_phy_get(dev, NULL);
> +		if (IS_ERR(mtk_dp->phy))
> +			return dev_err_probe(dev, PTR_ERR(mtk_dp->phy),
> +					     "Failed to get phy\n");
> +
> +		mtk_dp->phy_dev = NULL;
> +	} else {
> +		ret = mtk_dp_register_phy(mtk_dp);
> +		if (ret)
> +			return ret;
> +	}
>  
>  	mtk_dp->bridge.of_node = dev->of_node;
>  	mtk_dp->bridge.type = mtk_dp->data->bridge_type;

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260701122024.19557-1-angelogioacchino.delregno@collabora.com?part=7

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH 08/11] drm/mediatek: mtk_dp: Move max link rate to SoC specific data
  2026-07-01 12:20 ` [PATCH 08/11] drm/mediatek: mtk_dp: Move max link rate to SoC specific data AngeloGioacchino Del Regno
@ 2026-07-01 13:34   ` sashiko-bot
  0 siblings, 0 replies; 20+ messages in thread
From: sashiko-bot @ 2026-07-01 13:34 UTC (permalink / raw)
  To: AngeloGioacchino Del Regno; +Cc: devicetree, conor+dt, dri-devel, robh

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:

Pre-existing issues:
- [High] mode_valid and atomic_get_input_bus_fmts validate display modes against an unbounded, stale, or uninitialized link rate, bypassing Device Tree limits and DPCD capabilities.
--

commit 4683d3daece6ab3ba3c7c82ebff7364e878794fb
Author: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
Date:   Wed Jul 1 12:20:21 2026 +0000

drm/mediatek: mtk_dp: Move max link rate to SoC specific data

This patch moves the maximum link rate to the SoC specific data structure
instead of statically assigning it to DP_LINK_BW_5_4 during initialization.
This prepares the driver for the MT8196 SoC which supports higher link rates.

> diff --git a/drivers/gpu/drm/mediatek/mtk_dp.c b/drivers/gpu/drm/mediatek/mtk_dp.c
> index bf3a4b15f3ec0..5272e717bfda0 100644
> --- a/drivers/gpu/drm/mediatek/mtk_dp.c
> +++ b/drivers/gpu/drm/mediatek/mtk_dp.c
[ ... ]
> @@ -1481,7 +1482,7 @@ static void mtk_dp_initialize_priv_data(struct mtk_dp *mtk_dp)
>  {
>  	bool plugged_in = (mtk_dp->bridge.type == DRM_MODE_CONNECTOR_eDP);
>  
> -	mtk_dp->train_info.link_rate = DP_LINK_BW_5_4;
> +	mtk_dp->train_info.link_rate = mtk_dp->data->hw_max_link_rate;

[Severity: High]
This isn't a bug introduced by this patch, but does setting the link rate
here cause mode validation to falsely accept unsupported high-bandwidth modes?

Looking at mtk_dp_bridge_mode_valid() in drivers/gpu/drm/mediatek/mtk_dp.c,
it calculates available bandwidth using the unnegotiated train_info.link_rate:

	u32 rate = drm_dp_bw_code_to_link_rate(mtk_dp->train_info.link_rate) *
		   lane_count_min;

A similar calculation occurs in mtk_dp_bridge_atomic_get_input_bus_fmts().

Since train_info.link_rate is initialized here to the SoC's absolute maximum
(and previously statically to DP_LINK_BW_5_4), it bypasses the board-specific
Device Tree constraint mtk_dp->max_linkrate and the sink capabilities in rx_cap.

When the mode is actually committed, mtk_dp_training() properly limits the
link rate to mtk_dp->max_linkrate and trains at a lower bandwidth. Won't this
leave the hardware unable to sustain the falsely validated high-bandwidth
display mode, resulting in a blank screen or corrupted output due to bandwidth
exhaustion?

Because this patch will introduce even higher initial values for future SoCs
like MT8196, will this cause a wider range of unsupported modes to be falsely
validated?

>  	mtk_dp->train_info.lane_count = mtk_dp->max_lanes;
>  	mtk_dp->train_info.cable_plugged_in = plugged_in;
>

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260701122024.19557-1-angelogioacchino.delregno@collabora.com?part=8

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH 09/11] drm/mediatek: mtk_dp: Add support for HotPlug Detection in DP AUX
  2026-07-01 12:20 ` [PATCH 09/11] drm/mediatek: mtk_dp: Add support for HotPlug Detection in DP AUX AngeloGioacchino Del Regno
@ 2026-07-01 13:46   ` sashiko-bot
  0 siblings, 0 replies; 20+ messages in thread
From: sashiko-bot @ 2026-07-01 13:46 UTC (permalink / raw)
  To: AngeloGioacchino Del Regno; +Cc: devicetree, robh, dri-devel, conor+dt

Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
- [High] Unmapped hardware interrupt status bits from AUX HPD corrupt the HPD event handler logic, misclassifying interrupts.
- [Medium] Missing `legacy_regoff` when polling `MTK_DP_AUX_P0_364C` via `regmap_read_poll_timeout`.
--

commit 01574255cf70f390467f27095e6af27a1759e430
Author: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
drm/mediatek: mtk_dp: Add support for HotPlug Detection in DP AUX

This patch adds support for using the DP AUX channel to perform hotplug
detection (HPD) on newer MediaTek DisplayPort IPs. It enables configuring
and performing HPD in AUX, checking the correct HPD strategy with a new
platform data variable.

> diff --git a/drivers/gpu/drm/mediatek/mtk_dp.c b/drivers/gpu/drm/mediatek/mtk_dp.c
> index 5272e717bfda0..2d58eacb3d3e6 100644
> --- a/drivers/gpu/drm/mediatek/mtk_dp.c
> +++ b/drivers/gpu/drm/mediatek/mtk_dp.c

> [ ... ]

> @@ -1046,7 +1047,21 @@ static u32 mtk_dp_swirq_get_clear(struct mtk_dp *mtk_dp)
>  	return irq_status;
>  }
>  
> -static u32 mtk_dp_hwirq_get_clear(struct mtk_dp *mtk_dp)
> +static u32 mtk_dp_aux_hwirq_get_clear(struct mtk_dp *mtk_dp)
> +{
> +	u32 irq_status = mtk_dp_read(mtk_dp, MTK_DP_AUX_TX_P0_INT_STA);
> +
> +	if (irq_status) {
> +		mtk_dp_update_bits(mtk_dp, MTK_DP_AUX_TX_P0_INT_CLR,
> +				   irq_status, irq_status);
> +		mtk_dp_update_bits(mtk_dp, MTK_DP_AUX_TX_P0_INT_CLR,
> +				   0, irq_status);
> +	}
> +
> +	return irq_status;
> +}

[Severity: High]
Is it safe to return the raw hardware interrupt bits here without mapping them
to the expected software constants?

In mtk_dp_hpd_event(), the returned irq_status is checked against software
constants like MTK_DP_HPD_INTERRUPT, which is defined as BIT(3):

	if (irq_status & MTK_DP_HPD_INTERRUPT)
		mtk_dp->irq_thread_handle |= MTK_DP_THREAD_HPD_EVENT;

	/* Cable state is changed. */
	if (irq_status != MTK_DP_HPD_INTERRUPT) {
		mtk_dp->irq_thread_handle |= MTK_DP_THREAD_CABLE_STATE_CHG;
		cable_sta_chg = true;
	}

However, HPD_INTERRUPT_EVENT read from MTK_DP_AUX_TX_P0_INT_STA is BIT(2).

If we return the raw BIT(2) here, won't it fail the check for
MTK_DP_HPD_INTERRUPT and incorrectly fall into the cable state change path?
Could this misclassify short HPD pulses as cable state changes, potentially
causing spurious link teardowns?

> [ ... ]

> @@ -2125,10 +2194,15 @@ static int mtk_dp_wait_hpd_asserted(struct drm_dp_aux *mtk_aux, unsigned long wa
>  	u32 val;
>  	int ret;
>  
> -	ret = regmap_read_poll_timeout(mtk_dp->regs,
> -				       MTK_DP_TRANS_P0_3414 + mtk_dp->legacy_regoff,
> -				       val, !!(val & HPD_DB_DP_TRANS_P0_MASK),
> -				       wait_us / 100, wait_us);
> +	if (mtk_dp->data->aux_hpd_supported)
> +		ret = regmap_read_poll_timeout(mtk_dp->regs, MTK_DP_AUX_P0_364C,
> +					       val, !!(val & HPD_STATUS_DP_AUX_TX_P0_MASK),
> +					       wait_us / 100, wait_us);

[Severity: Medium]
Should this regmap_read_poll_timeout() call include mtk_dp->legacy_regoff?

The trans HPD path below adds mtk_dp->legacy_regoff to the register offset,
and standard mtk_dp_read() calls also apply it.

If a platform uses the legacy DT binding but has aux_hpd_supported enabled,
could omitting the offset cause reads from the wrong hardware address?

> +	else
> +		ret = regmap_read_poll_timeout(mtk_dp->regs,
> +					       MTK_DP_TRANS_P0_3414 + mtk_dp->legacy_regoff,
> +					       val, !!(val & HPD_DB_DP_TRANS_P0_MASK),
> +					       wait_us / 100, wait_us);
>  	if (ret) {
>  		mtk_dp->train_info.cable_plugged_in = false;
>  		return ret;

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260701122024.19557-1-angelogioacchino.delregno@collabora.com?part=9

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH 10/11] drm/mediatek: mtk_dp: Add support for eDP1.5 IPs and MT8196 SoC
  2026-07-01 12:20 ` [PATCH 10/11] drm/mediatek: mtk_dp: Add support for eDP1.5 IPs and MT8196 SoC AngeloGioacchino Del Regno
@ 2026-07-01 14:03   ` sashiko-bot
  0 siblings, 0 replies; 20+ messages in thread
From: sashiko-bot @ 2026-07-01 14:03 UTC (permalink / raw)
  To: AngeloGioacchino Del Regno; +Cc: dri-devel, conor+dt, devicetree, robh

Thank you for your contribution! Sashiko AI review found 4 potential issue(s) to consider:

New issues:
- [High] Newly introduced sleeping function msleep() is used in an atomic context path via bridge atomic_disable.
- [High] The SDP_DP13_EN_DP_ENC1_P0 bit is added to the value but omitted from the mask, preventing SDP from actually being enabled.
- [High] NULL pointer dereference when parsing calibration data due to missing efuse_fmt.

Pre-existing issues:
- [High] Preexisting sleeping functions used in atomic context via atomic enable/disable callbacks.
--

commit c515b507239926f8609226c47569e9b95e171972
Author: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>

drm/mediatek: mtk_dp: Add support for eDP1.5 IPs and MT8196 SoC

This commit adds support for MediaTek's Embedded DisplayPort (eDP) v1.5 IP as
found in the MT8196 SoC and other variants. It introduces new data structures,
modifies encoder paths, and encloses register writes in platform data booleans.

> diff --git a/drivers/gpu/drm/mediatek/mtk_dp.c b/drivers/gpu/drm/mediatek/mtk_dp.c
> index 2d58eacb3d3e6..605ead7fa9bf6 100644
> --- a/drivers/gpu/drm/mediatek/mtk_dp.c
> +++ b/drivers/gpu/drm/mediatek/mtk_dp.c

[ ... ]

> @@ -647,7 +668,16 @@ static void mtk_dp_setup_encoder(struct mtk_dp *mtk_dp)
>  	mtk_dp_update_bits(mtk_dp, MTK_DP_ENC1_P0_3364,
>  			   FIFO_READ_START_POINT_DP_ENC1_P0_VAL << 12,
>  			   FIFO_READ_START_POINT_DP_ENC1_P0_MASK);
> -	mtk_dp_write(mtk_dp, MTK_DP_ENC1_P0_3368, DP_ENC1_P0_3368_VAL);
> +
> +	mask = VIDEO_SRAM_FIFO_CNT_RESET_SEL_DP_ENC1_P0 | VIDEO_STABLE_CNT_THRD_DP_ENC1_P0;
> +	mask |= BS2BS_MODE_DP_ENC1_P0;
> +
> +	val = mask;
> +
> +	if (mtk_dp->data->sdp_encoder1_enable)
> +		val |= SDP_DP13_EN_DP_ENC1_P0;
> +
> +	mtk_dp_update_bits(mtk_dp, MTK_DP_ENC1_P0_3368, val, mask);
>  }

[Severity: High]
Does this code successfully enable the Secondary Data Packet (SDP)?

The SDP_DP13_EN_DP_ENC1_P0 bit is added to the val variable, but it does
not appear to be added to the mask. Since mtk_dp_update_bits() applies
the mask before writing, won't this omit the bit and prevent SDP from
actually being enabled?

[ ... ]

> @@ -1106,6 +1136,72 @@ static void mtk_dp_hwirq_enable(struct mtk_dp *mtk_dp, bool enable)
>  			   IRQ_MASK_DP_TRANS_P0_MASK);
>  }
>  
> +static void mtk_dp_encoder_force_bias_power_on(struct mtk_dp *mtk_dp)
> +{
> +	/* Force MCU to enable BIAS */
> +	mtk_dp_update_bits(mtk_dp, REG_3F44_DP_ENC_P0_3,
> +			   ENC_PHY_PWR_OVERWRITE_EN, ENC_PHY_PWR_OVERWRITE_EN);
> +	mtk_dp_update_bits(mtk_dp, REG_3F44_DP_ENC_P0_3,
> +			   FIELD_PREP_CONST(ENC_PHY_PWR_STATE_OVERWRITE_MASK,
> +					    ENC_PHY_BIAS_PWR_ON),
> +			   ENC_PHY_PWR_STATE_OVERWRITE_MASK);
> +
> +	/* Wait for the MCU to get LDO ready in PHYD */
> +	msleep(50);
> +
> +	mtk_dp_update_bits(mtk_dp, REG_3F44_DP_ENC_P0_3,
> +			   0, ENC_PHY_PWR_OVERWRITE_EN);
> +}

[Severity: High]
Is it safe to use msleep() in this context?

This function is called from mtk_dp_bridge_atomic_disable(), which runs as
part of the atomic commit tail. According to DRM subsystem guidelines,
atomic commit callbacks execute in an atomic context where sleeping
functions are unsafe and can lead to warnings or system instability.

[ ... ]

> @@ -2583,6 +2796,9 @@ static void mtk_dp_bridge_atomic_disable(struct drm_bridge *bridge,
>  	/* SDP path reset sw*/
>  	mtk_dp_sdp_path_reset(mtk_dp);
>  
> +	if (mtk_dp->data->force_pwr_states)
> +		mtk_dp_encoder_force_bias_power_on(mtk_dp);
> +
>  	/* Ensure the sink is muted */
>  	msleep(20);
>  }

[Severity: High]
This is a pre-existing issue, but is it safe to have msleep(20) here?

The mtk_dp_bridge_atomic_disable() callback executes in an atomic context
during display modeset or disable. Calling sleeping functions like msleep()
or usleep_range() (inside the preceding mtk_dp_sdp_path_reset() call) from
an atomic context violates core DRM atomic context rules and can cause
system instability.

[ ... ]

> @@ -3107,6 +3325,19 @@ static const struct mtk_dp_data mt8195_dp_data = {
>  	.audio_supported = true,
>  	.audio_m_div2_bit = MT8195_AUDIO_M_CODE_MULT_DIV_SEL_DP_ENC0_P0_DIV_2,
>  	.hw_max_link_rate = DP_LINK_BW_5_4,
> +	.sdp_encoder1_enable = true,
> +};
> +
> +static const struct mtk_dp_data mt8196_edp_data = {
> +	.bridge_type = DRM_MODE_CONNECTOR_eDP,
> +	.smc_cmd = MTK_DP_SIP_ATF_EDP_SET_VID_MUTE,
> +	.audio_supported = false,
> +	.audio_m_div2_bit = MT8195_AUDIO_M_CODE_MULT_DIV_SEL_DP_ENC0_P0_DIV_2,
> +	.hw_max_link_rate = DP_LINK_BW_8_1,
> +	.hwip_v1p4 = true,
> +	.aux_hpd_supported = true,
> +	.force_pwr_states = true,
> +	.psr_supported = true,
>  };

[Severity: High]
Can this structure lead to a NULL pointer dereference?

The mt8196_edp_data definition lacks the efuse_fmt field. If the devicetree
node for the MT8196 eDP lacks a phys property, the driver will fall back to
its legacy PHY registration path.

The legacy path calls mtk_dp_get_calibration_data() which attempts to
iterate over the array:

	for (i = 0; i < MTK_DP_CAL_MAX; i++) {
		fmt = &mtk_dp->data->efuse_fmt[i];
		...
	}

Because efuse_fmt is NULL, wouldn't this cause a kernel panic during probe?

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260701122024.19557-1-angelogioacchino.delregno@collabora.com?part=10

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH 11/11] drm/mediatek: mtk_dp: Clarify XTAL freq and Debounce registers
  2026-07-01 12:20 ` [PATCH 11/11] drm/mediatek: mtk_dp: Clarify XTAL freq and Debounce registers AngeloGioacchino Del Regno
@ 2026-07-01 14:09   ` sashiko-bot
  0 siblings, 0 replies; 20+ messages in thread
From: sashiko-bot @ 2026-07-01 14:09 UTC (permalink / raw)
  To: AngeloGioacchino Del Regno; +Cc: devicetree, conor+dt, dri-devel, robh

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Medium] Incorrect mask definitions for HPD interrupt thresholds causing them to evaluate to 0 and conceptually overlap with debounce thresholds.
--

commit 7214d6f29b496392f70fbd0b4f1b03755f68eecb
Author: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>

drm/mediatek: mtk_dp: Clarify XTAL freq and Debounce registers

This commit clarifies the meaning of the sub-fields in the crystal frequency
and transmitter interrupt debounce registers. The goal is to increase human
readability.

> diff --git a/drivers/gpu/drm/mediatek/mtk_dp.c b/drivers/gpu/drm/mediatek/mtk_dp.c
> index 605ead7fa9bf6..b861a5df93167 100644
> --- a/drivers/gpu/drm/mediatek/mtk_dp.c
> +++ b/drivers/gpu/drm/mediatek/mtk_dp.c

[ ... ]

> @@ -1248,28 +1254,29 @@ static void mtk_dp_initialize_aux_hpd_detect_settings(struct mtk_dp *mtk_dp)
>  
>  static void mtk_dp_initialize_hpd_detect_settings(struct mtk_dp *mtk_dp)
>  {
> -	u32 val;
> -
>  	/* Mask AUX TOP interrupt, as this uses transmitter for HPD */
>  	mtk_dp_update_bits(mtk_dp, MTK_DP_TOP_IRQ_MASK,
>  			   AUX_TOP_IRQ_MSK, AUX_TOP_IRQ_MSK);
>  
> -	/* Debounce threshold */
> +	/* Set Hotplug debounce threshold time: xtal_period * deb_thd */
>  	mtk_dp_update_bits(mtk_dp, MTK_DP_TRANS_P0_3410,
>  			   8, HPD_DEB_THD_DP_TRANS_P0_MASK);
>  
> -	val = (HPD_INT_THD_DP_TRANS_P0_LOWER_500US |
> -	       HPD_INT_THD_DP_TRANS_P0_UPPER_1100US) << 4;
> -	mtk_dp_update_bits(mtk_dp, MTK_DP_TRANS_P0_3410,
> -			   val, HPD_INT_THD_DP_TRANS_P0_MASK);
> -
>  	/*
> -	 * Connect threshold 1.5ms + 5 x 0.1ms = 2ms
> -	 * Disconnect threshold 1.5ms + 5 x 0.1ms = 2ms
> +	 * Set interrupt debounce threshold time
> +	 * VAL  |  0     1     2     3  INT_THD
> +	 * Low  | 100   300   500   700 uS
> +	 * High | 700   900  1100  1300 uS
>  	 */
> -	val = (5 << 8) | (5 << 12);
>  	mtk_dp_update_bits(mtk_dp, MTK_DP_TRANS_P0_3410,
> -			   val,
> +			   FIELD_PREP_CONST(HPD_INT_LOW_THD_DP_TRANS_P0_MASK, 2) |
> +			   FIELD_PREP_CONST(HPD_INT_HIGH_THD_DP_TRANS_P0_MASK, 2),
> +			   HPD_INT_THD_DP_TRANS_P0_MASK);

[Severity: Medium]
Will this result in setting the interrupt debounce thresholds to 0?

Because HPD_INT_LOW_THD_DP_TRANS_P0_MASK and HPD_INT_HIGH_THD_DP_TRANS_P0_MASK
are defined as GENMASK(1, 0) and GENMASK(3, 2) instead of their absolute
positions within HPD_INT_THD_DP_TRANS_P0_MASK (GENMASK(7, 4)), the values
produced by FIELD_PREP_CONST fall outside the update mask. 

The combined value evaluates to 0xA (bits 3:0), which means the 
regmap_update_bits() call will silently clear bits 4 through 7 instead of 
setting them.

[ ... ]

> diff --git a/drivers/gpu/drm/mediatek/mtk_dp_reg.h b/drivers/gpu/drm/mediatek/mtk_dp_reg.h
> index 9caf743f4fe61..418a2318c656e 100644
> --- a/drivers/gpu/drm/mediatek/mtk_dp_reg.h
> +++ b/drivers/gpu/drm/mediatek/mtk_dp_reg.h
> @@ -253,6 +253,8 @@
>  #define MTK_DP_TRANS_P0_3410				0x1410
>  #define HPD_DEB_THD_DP_TRANS_P0_MASK				GENMASK(3, 0)
>  #define HPD_INT_THD_DP_TRANS_P0_MASK				GENMASK(7, 4)
> +#define HPD_INT_HIGH_THD_DP_TRANS_P0_MASK			GENMASK(3, 2)
> +#define HPD_INT_LOW_THD_DP_TRANS_P0_MASK			GENMASK(1, 0)

[Severity: Medium]
Are these masks defined at the wrong bit positions?

They appear to overlap with HPD_DEB_THD_DP_TRANS_P0_MASK (bits 3:0). If they
are meant to be sub-fields of HPD_INT_THD_DP_TRANS_P0_MASK (bits 7:4), should
they be defined as GENMASK(7, 6) and GENMASK(5, 4) instead so they work
correctly with FIELD_PREP_CONST()?

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260701122024.19557-1-angelogioacchino.delregno@collabora.com?part=11

^ permalink raw reply	[flat|nested] 20+ messages in thread

end of thread, other threads:[~2026-07-01 14:09 UTC | newest]

Thread overview: 20+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-07-01 12:20 [PATCH 00/11] drm: MediaTek DisplayPort cleanups and MT8196 eDP AngeloGioacchino Del Regno
2026-07-01 12:20 ` [PATCH 01/11] dt-bindings: display: mediatek: dp: Deprecate nvmem efuse data AngeloGioacchino Del Regno
2026-07-01 12:20 ` [PATCH 02/11] dt-bindings: display: mediatek: dp: Add compatible for MT8196 eDP AngeloGioacchino Del Regno
2026-07-01 12:20 ` [PATCH 03/11] drm/mediatek: mtk_dp: Fix hdmi codec and phy driver unregistration AngeloGioacchino Del Regno
2026-07-01 12:32   ` sashiko-bot
2026-07-01 12:20 ` [PATCH 04/11] drm/mediatek: mtk_dp: Clarify SMC eDP/DP video unmute commands AngeloGioacchino Del Regno
2026-07-01 12:20 ` [PATCH 05/11] drm/mediatek: mtk_dp: Rework register offsets for proper PHY usage AngeloGioacchino Del Regno
2026-07-01 12:45   ` sashiko-bot
2026-07-01 12:20 ` [PATCH 06/11] drm/mediatek: mtk_dp: Use PHY API for PHY power sequences AngeloGioacchino Del Regno
2026-07-01 13:05   ` sashiko-bot
2026-07-01 12:20 ` [PATCH 07/11] drm/mediatek: mtk_dp: Add support for PHY from devicetree AngeloGioacchino Del Regno
2026-07-01 13:23   ` sashiko-bot
2026-07-01 12:20 ` [PATCH 08/11] drm/mediatek: mtk_dp: Move max link rate to SoC specific data AngeloGioacchino Del Regno
2026-07-01 13:34   ` sashiko-bot
2026-07-01 12:20 ` [PATCH 09/11] drm/mediatek: mtk_dp: Add support for HotPlug Detection in DP AUX AngeloGioacchino Del Regno
2026-07-01 13:46   ` sashiko-bot
2026-07-01 12:20 ` [PATCH 10/11] drm/mediatek: mtk_dp: Add support for eDP1.5 IPs and MT8196 SoC AngeloGioacchino Del Regno
2026-07-01 14:03   ` sashiko-bot
2026-07-01 12:20 ` [PATCH 11/11] drm/mediatek: mtk_dp: Clarify XTAL freq and Debounce registers AngeloGioacchino Del Regno
2026-07-01 14:09   ` sashiko-bot

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox