* [PATCH v4 01/12] dt-bindings: display: mediatek: dp: Deprecate nvmem efuse data
2026-07-09 11:31 [PATCH v4 00/12] drm: MediaTek DisplayPort cleanups and MT8196 eDP AngeloGioacchino Del Regno
@ 2026-07-09 11:31 ` AngeloGioacchino Del Regno
2026-07-09 11:31 ` [PATCH v4 02/12] dt-bindings: display: mediatek: dp: Add compatible for MT8196 eDP AngeloGioacchino Del Regno
` (10 subsequent siblings)
11 siblings, 0 replies; 22+ messages in thread
From: AngeloGioacchino Del Regno @ 2026-07-09 11:31 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] 22+ messages in thread* [PATCH v4 02/12] dt-bindings: display: mediatek: dp: Add compatible for MT8196 eDP
2026-07-09 11:31 [PATCH v4 00/12] drm: MediaTek DisplayPort cleanups and MT8196 eDP AngeloGioacchino Del Regno
2026-07-09 11:31 ` [PATCH v4 01/12] dt-bindings: display: mediatek: dp: Deprecate nvmem efuse data AngeloGioacchino Del Regno
@ 2026-07-09 11:31 ` AngeloGioacchino Del Regno
2026-07-09 11:31 ` [PATCH v4 03/12] drm/mediatek: mtk_dp: Call pm_runtime_put_sync() in removal path AngeloGioacchino Del Regno
` (9 subsequent siblings)
11 siblings, 0 replies; 22+ messages in thread
From: AngeloGioacchino Del Regno @ 2026-07-09 11:31 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] 22+ messages in thread* [PATCH v4 03/12] drm/mediatek: mtk_dp: Call pm_runtime_put_sync() in removal path
2026-07-09 11:31 [PATCH v4 00/12] drm: MediaTek DisplayPort cleanups and MT8196 eDP AngeloGioacchino Del Regno
2026-07-09 11:31 ` [PATCH v4 01/12] dt-bindings: display: mediatek: dp: Deprecate nvmem efuse data AngeloGioacchino Del Regno
2026-07-09 11:31 ` [PATCH v4 02/12] dt-bindings: display: mediatek: dp: Add compatible for MT8196 eDP AngeloGioacchino Del Regno
@ 2026-07-09 11:31 ` AngeloGioacchino Del Regno
2026-07-09 11:42 ` sashiko-bot
2026-07-09 11:31 ` [PATCH v4 04/12] drm/mediatek: mtk_dp: Fix hdmi codec and phy driver unregistration AngeloGioacchino Del Regno
` (8 subsequent siblings)
11 siblings, 1 reply; 22+ messages in thread
From: AngeloGioacchino Del Regno @ 2026-07-09 11:31 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
Since pm_runtime_put() queues an asynchronous suspend, calling
pm_runtime_disable() right after will cancel the pending suspend
work.
Call pm_runtime_put_sync() instead during mtk_dp_remove() to
overcome to this issue, making sure that the suspend ops execute
and that the hardware correctly powers off before module unload.
Fixes: f70ac097a2cf ("drm/mediatek: Add MT8195 Embedded DisplayPort driver")
Signed-off-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
---
drivers/gpu/drm/mediatek/mtk_dp.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/mediatek/mtk_dp.c b/drivers/gpu/drm/mediatek/mtk_dp.c
index f656b85b8421..0d0507890d99 100644
--- a/drivers/gpu/drm/mediatek/mtk_dp.c
+++ b/drivers/gpu/drm/mediatek/mtk_dp.c
@@ -2866,7 +2866,7 @@ static void mtk_dp_remove(struct platform_device *pdev)
{
struct mtk_dp *mtk_dp = platform_get_drvdata(pdev);
- pm_runtime_put(&pdev->dev);
+ pm_runtime_put_sync(&pdev->dev);
pm_runtime_disable(&pdev->dev);
if (mtk_dp->data->bridge_type != DRM_MODE_CONNECTOR_eDP)
timer_delete_sync(&mtk_dp->debounce_timer);
--
2.54.0
^ permalink raw reply related [flat|nested] 22+ messages in thread* Re: [PATCH v4 03/12] drm/mediatek: mtk_dp: Call pm_runtime_put_sync() in removal path
2026-07-09 11:31 ` [PATCH v4 03/12] drm/mediatek: mtk_dp: Call pm_runtime_put_sync() in removal path AngeloGioacchino Del Regno
@ 2026-07-09 11:42 ` sashiko-bot
0 siblings, 0 replies; 22+ messages in thread
From: sashiko-bot @ 2026-07-09 11:42 UTC (permalink / raw)
To: AngeloGioacchino Del Regno; +Cc: devicetree, robh, conor+dt, dri-devel
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
New issues:
- [Critical] Replacing `pm_runtime_put()` with `pm_runtime_put_sync()` synchronously powers off the hardware before tearing down child devices, DRM bridges, and IRQs, causing system crashes when they access unpowered registers.
Pre-existing issues:
- [High] Using `timer_delete_sync()` instead of `timer_shutdown_sync()` in the remove path allows the timer to be re-armed by the concurrently active IRQ thread, leading to a use-after-free.
--
--- Patch [3]: [PATCH v4 03/12] drm/mediatek: mtk_dp: Call pm_runtime_put_sync() in removal path ---
commit f976047da5b8089ab1d0475df94302360f23d7f2
Author: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
drm/mediatek: mtk_dp: Call pm_runtime_put_sync() in removal path
Since pm_runtime_put() queues an asynchronous suspend, calling
pm_runtime_disable() right after will cancel the pending suspend
work.
Call pm_runtime_put_sync() instead during mtk_dp_remove() to
overcome to this issue, making sure that the suspend ops execute
and that the hardware correctly powers off before module unload.
> diff --git a/drivers/gpu/drm/mediatek/mtk_dp.c b/drivers/gpu/drm/mediatek/mtk_dp.c
> index f656b85b84212..0d0507890d993 100644
> --- a/drivers/gpu/drm/mediatek/mtk_dp.c
> +++ b/drivers/gpu/drm/mediatek/mtk_dp.c
> @@ -2866,7 +2866,7 @@ static void mtk_dp_remove(struct platform_device *pdev)
> {
> struct mtk_dp *mtk_dp = platform_get_drvdata(pdev);
>
> - pm_runtime_put(&pdev->dev);
> + pm_runtime_put_sync(&pdev->dev);
[Severity: Critical]
Does changing this to a synchronous put cause a regression where the
hardware is powered off before child devices and IRQs are torn down?
Because the driver uses a devm-managed IRQ, the interrupt can still fire
and execute mtk_dp_hpd_event() which reads hardware registers:
mtk_dp_hpd_event() {
u32 irq_status = mtk_dp_swirq_get_clear(mtk_dp) |
mtk_dp_hwirq_get_clear(mtk_dp);
...
}
Additionally, child platform devices like the audio codec are still active.
If they are torn down later and trigger mtk_dp_audio_shutdown(), it also
accesses hardware:
mtk_dp_audio_shutdown() {
mtk_dp_audio_mute(mtk_dp, true);
...
}
Will accessing these registers after the PM domain is synchronously powered
down result in a bus fault or system crash? Should the PM operations be
moved to the end of the teardown process after explicitly disabling IRQs
and unregistering child devices?
> pm_runtime_disable(&pdev->dev);
> if (mtk_dp->data->bridge_type != DRM_MODE_CONNECTOR_eDP)
> - timer_delete_sync(&mtk_dp->debounce_timer);
> + timer_delete_sync(&mtk_dp->debounce_timer);
[Severity: High]
This is a pre-existing issue, but could this timer_delete_sync() result in
a use-after-free?
Since the hardware interrupt is managed by devres, it remains active
throughout mtk_dp_remove(). If the IRQ thread is executing concurrently,
it can unconditionally re-arm the timer:
mtk_dp_hpd_event_thread() {
...
mod_timer(&mtk_dp->debounce_timer,
jiffies + msecs_to_jiffies(100) - 1);
}
If mod_timer() is called right after timer_delete_sync() finishes, the
timer is successfully re-armed. Once mtk_dp_remove() returns, devres will
free the mtk_dp structure. When the timer expires, won't it access freed
memory?
Should this be updated to use timer_shutdown_sync() instead to permanently
prevent the timer from being re-armed?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260709113148.49090-1-angelogioacchino.delregno@collabora.com?part=3
^ permalink raw reply [flat|nested] 22+ messages in thread
* [PATCH v4 04/12] drm/mediatek: mtk_dp: Fix hdmi codec and phy driver unregistration
2026-07-09 11:31 [PATCH v4 00/12] drm: MediaTek DisplayPort cleanups and MT8196 eDP AngeloGioacchino Del Regno
` (2 preceding siblings ...)
2026-07-09 11:31 ` [PATCH v4 03/12] drm/mediatek: mtk_dp: Call pm_runtime_put_sync() in removal path AngeloGioacchino Del Regno
@ 2026-07-09 11:31 ` AngeloGioacchino Del Regno
2026-07-09 11:48 ` sashiko-bot
2026-07-09 11:31 ` [PATCH v4 05/12] drm/mediatek: mtk_dp: Clarify SMC eDP/DP video unmute commands AngeloGioacchino Del Regno
` (7 subsequent siblings)
11 siblings, 1 reply; 22+ messages in thread
From: AngeloGioacchino Del Regno @ 2026-07-09 11:31 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 | 31 ++++++++++++++++++++++++-------
1 file changed, 24 insertions(+), 7 deletions(-)
diff --git a/drivers/gpu/drm/mediatek/mtk_dp.c b/drivers/gpu/drm/mediatek/mtk_dp.c
index 0d0507890d99..8399a6b41168 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,28 @@ 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->audio_pdev);
+ if (ret)
+ 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,13 +2718,16 @@ 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)
+ 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");
- if (IS_ERR(mtk_dp->phy)) {
- platform_device_unregister(mtk_dp->phy_dev);
+ if (IS_ERR(mtk_dp->phy))
return dev_err_probe(dev, PTR_ERR(mtk_dp->phy), "Failed to get phy\n");
- }
return 0;
}
@@ -2870,9 +2890,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] 22+ messages in thread* Re: [PATCH v4 04/12] drm/mediatek: mtk_dp: Fix hdmi codec and phy driver unregistration
2026-07-09 11:31 ` [PATCH v4 04/12] drm/mediatek: mtk_dp: Fix hdmi codec and phy driver unregistration AngeloGioacchino Del Regno
@ 2026-07-09 11:48 ` sashiko-bot
0 siblings, 0 replies; 22+ messages in thread
From: sashiko-bot @ 2026-07-09 11:48 UTC (permalink / raw)
To: AngeloGioacchino Del Regno; +Cc: conor+dt, devicetree, robh, dri-devel
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
Pre-existing issues:
- [High] The hardware interrupt is not disabled during driver unbind (`mtk_dp_remove`), allowing the IRQ handler and thread to execute while resources are being destroyed, leading to use-after-free, timer re-arming, and bus errors.
- [High] The ALSA `get_eld` callback can dereference a NULL `mtk_dp->conn` if called between a hotplug event and a DRM modeset.
--
--- Patch [4]: [PATCH v4 04/12] drm/mediatek: mtk_dp: Fix hdmi codec and phy driver unregistration ---
commit 6ce33bac50c12bbd077cc2e659b77509b20cd720
Author: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
Subject: drm/mediatek: mtk_dp: Fix hdmi codec and phy driver unregistration
This commit converts the unregistration of the HDMI Codec and DisplayPort PHY
platform devices to use devm actions. This ensures they are properly cleaned
up even during probe deferrals or failures.
> diff --git a/drivers/gpu/drm/mediatek/mtk_dp.c b/drivers/gpu/drm/mediatek/mtk_dp.c
> index 0d0507890d993..8399a6b411689 100644
> --- a/drivers/gpu/drm/mediatek/mtk_dp.c
> +++ b/drivers/gpu/drm/mediatek/mtk_dp.c
[ ... ]
> @@ -2680,18 +2687,28 @@ 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));
[Severity: High]
This is a pre-existing issue, but does the ALSA get_eld callback have a
potential NULL pointer dereference race with hotplug events?
When a display is plugged in, mtk_dp_hpd_event_thread() unconditionally sets
the enabled flag before the DRM core populates mtk_dp->conn during a modeset:
mtk_dp_hpd_event_thread()
...
mtk_dp->enabled = true;
If userspace or the sound subsystem queries the ELD via mtk_dp_audio_get_eld()
in the window between the hotplug event and the DRM modeset, it seems we
dereference mtk_dp->conn without checking if it is NULL:
mtk_dp_audio_get_eld()
if (mtk_dp->enabled)
memcpy(buf, mtk_dp->conn->eld, len);
Could this lead to a crash if a local user probes ALSA mixers before the
modeset completes?
[ ... ]
> @@ -2870,9 +2890,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);
> }
[Severity: High]
This isn't a bug introduced by this patch, but since we are modifying driver
removal, is there a risk of the hardware interrupt firing during or after
mtk_dp_remove()?
The hardware interrupt is managed by devres and remains active until after
mtk_dp_remove() returns. Since pm_runtime_disable() is called here, the
device power domain might be turned off.
If a hotplug interrupt fires during this window, mtk_dp_hpd_event() will
attempt to read hardware registers:
mtk_dp_hpd_event()
u32 irq_status = mtk_dp_swirq_get_clear(mtk_dp) |
mtk_dp_hwirq_get_clear(mtk_dp);
Could this cause a bus error or crash if the power domain is already off?
Furthermore, if the interrupt handler schedules the IRQ thread,
mtk_dp_hpd_event_thread() could re-arm the debounce timer or attempt to
access the PHY during training after it has been unregistered by devres,
leading to a use-after-free:
mtk_dp_hpd_event_thread()
/* Training */
ret = mtk_dp_training(mtk_dp);
Should the IRQ be explicitly disabled in mtk_dp_remove() before deleting
the timers and disabling pm runtime?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260709113148.49090-1-angelogioacchino.delregno@collabora.com?part=4
^ permalink raw reply [flat|nested] 22+ messages in thread
* [PATCH v4 05/12] drm/mediatek: mtk_dp: Clarify SMC eDP/DP video unmute commands
2026-07-09 11:31 [PATCH v4 00/12] drm: MediaTek DisplayPort cleanups and MT8196 eDP AngeloGioacchino Del Regno
` (3 preceding siblings ...)
2026-07-09 11:31 ` [PATCH v4 04/12] drm/mediatek: mtk_dp: Fix hdmi codec and phy driver unregistration AngeloGioacchino Del Regno
@ 2026-07-09 11:31 ` AngeloGioacchino Del Regno
2026-07-09 11:31 ` [PATCH v4 06/12] drm/mediatek: mtk_dp: Rework register offsets for proper PHY usage AngeloGioacchino Del Regno
` (6 subsequent siblings)
11 siblings, 0 replies; 22+ messages in thread
From: AngeloGioacchino Del Regno @ 2026-07-09 11:31 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 8399a6b41168..b50264ca1f31 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] 22+ messages in thread* [PATCH v4 06/12] drm/mediatek: mtk_dp: Rework register offsets for proper PHY usage
2026-07-09 11:31 [PATCH v4 00/12] drm: MediaTek DisplayPort cleanups and MT8196 eDP AngeloGioacchino Del Regno
` (4 preceding siblings ...)
2026-07-09 11:31 ` [PATCH v4 05/12] drm/mediatek: mtk_dp: Clarify SMC eDP/DP video unmute commands AngeloGioacchino Del Regno
@ 2026-07-09 11:31 ` AngeloGioacchino Del Regno
2026-07-09 11:31 ` [PATCH v4 07/12] drm/mediatek: mtk_dp: Use PHY API for PHY power sequences AngeloGioacchino Del Regno
` (5 subsequent siblings)
11 siblings, 0 replies; 22+ messages in thread
From: AngeloGioacchino Del Regno @ 2026-07-09 11:31 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 | 101 +++++-----
drivers/gpu/drm/mediatek/mtk_dp_reg.h | 255 ++++++++++++--------------
2 files changed, 179 insertions(+), 177 deletions(-)
diff --git a/drivers/gpu/drm/mediatek/mtk_dp.c b/drivers/gpu/drm/mediatek/mtk_dp.c
index b50264ca1f31..b2e5fa0914bc 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,
@@ -566,7 +590,8 @@ static int mtk_dp_set_color_format(struct mtk_dp *mtk_dp,
DP_TEST_COLOR_FORMAT_MASK);
mtk_dp_update_bits(mtk_dp, MTK_DP_ENC0_P0_303C,
- val, PIXEL_ENCODE_FORMAT_DP_ENC0_P0_MASK);
+ FIELD_PREP(PIXEL_ENCODE_FORMAT_DP_ENC0_P0_MASK, val),
+ PIXEL_ENCODE_FORMAT_DP_ENC0_P0_MASK);
return 0;
}
@@ -1219,38 +1244,26 @@ static void mtk_dp_get_calibration_data(struct mtk_dp *mtk_dp)
static void mtk_dp_set_calibration_data(struct mtk_dp *mtk_dp)
{
+ const u32 impsel_mask = RG_XTP_LNx_TX_IMPSEL_PMOS | RG_XTP_LNx_TX_IMPSEL_NMOS;
u32 *cal_data = mtk_dp->cal_data;
- mtk_dp_update_bits(mtk_dp, DP_PHY_GLB_DPAUX_TX,
- cal_data[MTK_DP_CAL_CLKTX_IMPSE] << 20,
- RG_CKM_PT0_CKTX_IMPSEL);
- mtk_dp_update_bits(mtk_dp, DP_PHY_GLB_BIAS_GEN_00,
- cal_data[MTK_DP_CAL_GLB_BIAS_TRIM] << 16,
- 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);
- 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);
- 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);
- 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);
- 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);
- 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);
- 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);
- 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);
+ /* This avoids using mtk_dp_update_bits so that legacy_regoff is not added */
+ regmap_update_bits(mtk_dp->regs, DP_PHY_GLB_DPAUX_TX, RG_CKM_PT0_CKTX_IMPSEL,
+ cal_data[MTK_DP_CAL_CLKTX_IMPSE] << 20);
+ regmap_update_bits(mtk_dp->regs, DP_PHY_GLB_BIAS_GEN_00, RG_XTP_GLB_BIAS_INTR_CTRL,
+ cal_data[MTK_DP_CAL_GLB_BIAS_TRIM] << 16);
+ regmap_update_bits(mtk_dp->regs, DP_PHY_LANE_TX_0, impsel_mask,
+ (cal_data[MTK_DP_CAL_LN_TX_IMPSEL_PMOS_0] << 12) |
+ (cal_data[MTK_DP_CAL_LN_TX_IMPSEL_NMOS_0] << 16));
+ regmap_update_bits(mtk_dp->regs, DP_PHY_LANE_TX_1, impsel_mask,
+ (cal_data[MTK_DP_CAL_LN_TX_IMPSEL_PMOS_1] << 12) |
+ (cal_data[MTK_DP_CAL_LN_TX_IMPSEL_NMOS_1] << 16));
+ regmap_update_bits(mtk_dp->regs, DP_PHY_LANE_TX_2, impsel_mask,
+ (cal_data[MTK_DP_CAL_LN_TX_IMPSEL_PMOS_2] << 12) |
+ (cal_data[MTK_DP_CAL_LN_TX_IMPSEL_NMOS_2] << 16));
+ regmap_update_bits(mtk_dp->regs, DP_PHY_LANE_TX_3, impsel_mask,
+ (cal_data[MTK_DP_CAL_LN_TX_IMPSEL_PMOS_3] << 12) |
+ (cal_data[MTK_DP_CAL_LN_TX_IMPSEL_NMOS_3] << 16));
}
static int mtk_dp_phy_configure(struct mtk_dp *mtk_dp,
@@ -1401,21 +1414,21 @@ 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,
+ regmap_write(mtk_dp->regs, 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);
+ regmap_clear_bits(mtk_dp->regs, MTK_DP_0034, DA_CKM_CKTX0_EN_FORCE_EN);
}
static void mtk_dp_power_disable(struct mtk_dp *mtk_dp)
{
mtk_dp_write(mtk_dp, MTK_DP_TOP_PWR_STATE, 0);
- mtk_dp_update_bits(mtk_dp, MTK_DP_0034,
- DA_CKM_CKTX0_EN_FORCE_EN, DA_CKM_CKTX0_EN_FORCE_EN);
+ regmap_set_bits(mtk_dp->regs, MTK_DP_0034, DA_CKM_CKTX0_EN_FORCE_EN);
/* Disable RX */
- mtk_dp_write(mtk_dp, MTK_DP_1040, 0);
+ regmap_write(mtk_dp->regs, DP_PHY_AUX_RX_CTL, 0);
+
mtk_dp_write(mtk_dp, MTK_DP_TOP_MEM_PD,
0x550 | FUSE_SEL | MEM_ISO_EN);
}
@@ -2067,7 +2080,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 +2114,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);
@@ -2773,6 +2787,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] 22+ messages in thread* [PATCH v4 07/12] drm/mediatek: mtk_dp: Use PHY API for PHY power sequences
2026-07-09 11:31 [PATCH v4 00/12] drm: MediaTek DisplayPort cleanups and MT8196 eDP AngeloGioacchino Del Regno
` (5 preceding siblings ...)
2026-07-09 11:31 ` [PATCH v4 06/12] drm/mediatek: mtk_dp: Rework register offsets for proper PHY usage AngeloGioacchino Del Regno
@ 2026-07-09 11:31 ` AngeloGioacchino Del Regno
2026-07-09 11:53 ` sashiko-bot
2026-07-09 11:31 ` [PATCH v4 08/12] drm/mediatek: mtk_dp: Add support for PHY from devicetree AngeloGioacchino Del Regno
` (4 subsequent siblings)
11 siblings, 1 reply; 22+ messages in thread
From: AngeloGioacchino Del Regno @ 2026-07-09 11:31 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 | 31 ++++++++++++++++++++++++-------
1 file changed, 24 insertions(+), 7 deletions(-)
diff --git a/drivers/gpu/drm/mediatek/mtk_dp.c b/drivers/gpu/drm/mediatek/mtk_dp.c
index b2e5fa0914bc..383c8e66b527 100644
--- a/drivers/gpu/drm/mediatek/mtk_dp.c
+++ b/drivers/gpu/drm/mediatek/mtk_dp.c
@@ -1404,6 +1404,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);
@@ -1414,20 +1416,35 @@ 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);
- regmap_write(mtk_dp->regs, DP_PHY_AUX_RX_CTL,
- RG_DPAUX_RX_VALID_DEGLITCH_EN | RG_XTP_GLB_CKDET_EN |
- RG_DPAUX_RX_EN);
- regmap_clear_bits(mtk_dp->regs, MTK_DP_0034, DA_CKM_CKTX0_EN_FORCE_EN);
+
+ if (mtk_dp->phy_dev) {
+ regmap_write(mtk_dp->regs, DP_PHY_AUX_RX_CTL,
+ RG_DPAUX_RX_VALID_DEGLITCH_EN | RG_XTP_GLB_CKDET_EN |
+ RG_DPAUX_RX_EN);
+ regmap_clear_bits(mtk_dp->regs, MTK_DP_0034, 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);
- regmap_set_bits(mtk_dp->regs, MTK_DP_0034, DA_CKM_CKTX0_EN_FORCE_EN);
+ if (unlikely(mtk_dp->phy_dev)) {
+ regmap_set_bits(mtk_dp->regs, MTK_DP_0034, DA_CKM_CKTX0_EN_FORCE_EN);
- /* Disable RX */
- regmap_write(mtk_dp->regs, DP_PHY_AUX_RX_CTL, 0);
+ /* Disable RX */
+ regmap_write(mtk_dp->regs, 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] 22+ messages in thread* Re: [PATCH v4 07/12] drm/mediatek: mtk_dp: Use PHY API for PHY power sequences
2026-07-09 11:31 ` [PATCH v4 07/12] drm/mediatek: mtk_dp: Use PHY API for PHY power sequences AngeloGioacchino Del Regno
@ 2026-07-09 11:53 ` sashiko-bot
0 siblings, 0 replies; 22+ messages in thread
From: sashiko-bot @ 2026-07-09 11:53 UTC (permalink / raw)
To: AngeloGioacchino Del Regno; +Cc: conor+dt, robh, dri-devel, devicetree
Thank you for your contribution! Sashiko AI review found 4 potential issue(s) to consider:
New issues:
- [High] The newly added `phy_power_on()` and `phy_power_off()` calls are unreachable dead code, and if reached, would break the display because the PHY driver lacks the required callbacks.
- [High] Ignoring the return value of `phy_power_on()` leads to unbalanced `phy_power_off()` calls and PM/regulator underflows.
- [High] `phy_power_on()` is called before `phy_init()` in the eDP probe path, violating the PHY API contract.
Pre-existing issues:
- [High] The driver teardown leaves the hardware interrupt active after deleting its associated debounce timer, leading to a Use-After-Free and fatal bus errors.
--
--- Patch [7]: [PATCH v4 07/12] drm/mediatek: mtk_dp: Use PHY API for PHY power sequences ---
commit 4812fc369fed645130f58ff58a959cb198f9b227
Author: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
drm/mediatek: mtk_dp: Use PHY API for PHY power sequences
This commit introduces phy_power_on() and phy_power_off() calls to replace
direct PHY register writes in the mediatek DP driver.
> diff --git a/drivers/gpu/drm/mediatek/mtk_dp.c b/drivers/gpu/drm/mediatek/mtk_dp.c
> index b2e5fa0914bcb..383c8e66b5273 100644
> --- a/drivers/gpu/drm/mediatek/mtk_dp.c
> +++ b/drivers/gpu/drm/mediatek/mtk_dp.c
[ ... ]
> @@ -1414,20 +1416,35 @@ 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);
> - regmap_write(mtk_dp->regs, DP_PHY_AUX_RX_CTL,
> - RG_DPAUX_RX_VALID_DEGLITCH_EN | RG_XTP_GLB_CKDET_EN |
> - RG_DPAUX_RX_EN);
> - regmap_clear_bits(mtk_dp->regs, MTK_DP_0034, DA_CKM_CKTX0_EN_FORCE_EN);
> +
> + if (mtk_dp->phy_dev) {
[Severity: High]
Can this else branch ever be reached?
Looking at mtk_dp_probe(), it unconditionally calls mtk_dp_register_phy()
which creates the mediatek-dp-phy platform device and assigns it to
mtk_dp->phy_dev. Because this pointer seems to always be valid, this
condition would always evaluate to true, skipping the new PHY API calls.
Additionally, if this dead code were reached, would the PHY API calls work?
In drivers/phy/mediatek/phy-mtk-dp.c, mtk_dp_phy_dev_ops does not appear to
implement the .power_on and .power_off callbacks.
> + regmap_write(mtk_dp->regs, DP_PHY_AUX_RX_CTL,
> + RG_DPAUX_RX_VALID_DEGLITCH_EN | RG_XTP_GLB_CKDET_EN |
> + RG_DPAUX_RX_EN);
> + regmap_clear_bits(mtk_dp->regs, MTK_DP_0034, DA_CKM_CKTX0_EN_FORCE_EN);
> + } else {
> + ret = phy_power_on(mtk_dp->phy);
[Severity: High]
Is it safe to call phy_power_on() before phy_init()?
The Linux PHY API requires phy_init() to be called before phy_power_on().
Currently, phy_init() is only called within mtk_dp_poweron() during the
DRM bridge attach phase. However, for eDP panels, mtk_dp_probe() directly
invokes mtk_dp_power_enable() well before the bridge attach phase occurs.
> + 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 unbalanced power
states?
If phy_power_on() fails due to a regulator error, the generic PHY framework
leaves the power count at zero.
Because the failure is only logged and not propagated, the driver proceeds.
During teardown, mtk_dp_power_disable() unconditionally calls phy_power_off(),
which could drop the power count below zero and cause regulator usecount
underflows.
> + }
> }
>
> static void mtk_dp_power_disable(struct mtk_dp *mtk_dp)
> {
[ ... ]
[Severity: High]
This is a pre-existing issue, but does the driver teardown sequence leave
the hardware interrupt active after deleting its associated debounce timer?
In mtk_dp_remove(), the driver powers down the device via
pm_runtime_put_sync() and deletes the timer using timer_delete_sync().
However, it relies on devm_request_threaded_irq() for interrupt management
without explicitly calling devm_free_irq().
If a threaded IRQ fires in the window after timer_delete_sync(), the
threaded handler mtk_dp_hpd_event_thread() will run and call mod_timer().
This re-arms the deleted timer on memory that is about to be freed, which
might lead to a use-after-free. Additionally, accessing the DP MMIO
registers while the power domain is off could trigger fatal bus errors.
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260709113148.49090-1-angelogioacchino.delregno@collabora.com?part=7
^ permalink raw reply [flat|nested] 22+ messages in thread
* [PATCH v4 08/12] drm/mediatek: mtk_dp: Add support for PHY from devicetree
2026-07-09 11:31 [PATCH v4 00/12] drm: MediaTek DisplayPort cleanups and MT8196 eDP AngeloGioacchino Del Regno
` (6 preceding siblings ...)
2026-07-09 11:31 ` [PATCH v4 07/12] drm/mediatek: mtk_dp: Use PHY API for PHY power sequences AngeloGioacchino Del Regno
@ 2026-07-09 11:31 ` AngeloGioacchino Del Regno
2026-07-09 11:31 ` [PATCH v4 09/12] drm/mediatek: mtk_dp: Move max link rate to SoC specific data AngeloGioacchino Del Regno
` (3 subsequent siblings)
11 siblings, 0 replies; 22+ messages in thread
From: AngeloGioacchino Del Regno @ 2026-07-09 11:31 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 383c8e66b527..e2a6001fc0cc 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);
@@ -1287,7 +1296,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);
@@ -2120,8 +2135,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;
@@ -2131,7 +2147,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);
@@ -2754,6 +2775,7 @@ static int mtk_dp_register_phy(struct mtk_dp *mtk_dp)
return dev_err_probe(dev, ret,
"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");
@@ -2804,7 +2826,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)
@@ -2855,9 +2882,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] 22+ messages in thread* [PATCH v4 09/12] drm/mediatek: mtk_dp: Move max link rate to SoC specific data
2026-07-09 11:31 [PATCH v4 00/12] drm: MediaTek DisplayPort cleanups and MT8196 eDP AngeloGioacchino Del Regno
` (7 preceding siblings ...)
2026-07-09 11:31 ` [PATCH v4 08/12] drm/mediatek: mtk_dp: Add support for PHY from devicetree AngeloGioacchino Del Regno
@ 2026-07-09 11:31 ` AngeloGioacchino Del Regno
2026-07-09 11:53 ` sashiko-bot
2026-07-09 11:31 ` [PATCH v4 10/12] drm/mediatek: mtk_dp: Add support for HotPlug Detection in DP AUX AngeloGioacchino Del Regno
` (2 subsequent siblings)
11 siblings, 1 reply; 22+ messages in thread
From: AngeloGioacchino Del Regno @ 2026-07-09 11:31 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 e2a6001fc0cc..ea970a9bfe93 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] = {
@@ -1469,7 +1470,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;
@@ -2996,6 +2997,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 = {
@@ -3004,6 +3006,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 = {
@@ -3012,6 +3015,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] 22+ messages in thread* Re: [PATCH v4 09/12] drm/mediatek: mtk_dp: Move max link rate to SoC specific data
2026-07-09 11:31 ` [PATCH v4 09/12] drm/mediatek: mtk_dp: Move max link rate to SoC specific data AngeloGioacchino Del Regno
@ 2026-07-09 11:53 ` sashiko-bot
0 siblings, 0 replies; 22+ messages in thread
From: sashiko-bot @ 2026-07-09 11:53 UTC (permalink / raw)
To: AngeloGioacchino Del Regno; +Cc: conor+dt, devicetree, dri-devel, robh
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
Pre-existing issues:
- [High] For eDP, mode validation and bus format negotiation incorrectly use the SoC's hardware maximum link rate rather than considering the board's device tree limit and the sink's DPCD capabilities.
--
--- Patch [9]: [PATCH v4 09/12] drm/mediatek: mtk_dp: Move max link rate to SoC specific data ---
commit 77698e671819e17e65d99b3fb9908f2be60bc613
Author: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
drm/mediatek: mtk_dp: Move max link rate to SoC specific data
This commit moves the hardware maximum link rate from static initialization
to SoC-specific data to prepare for supporting MT8196 eDP IP which has a
higher maximum link rate.
> diff --git a/drivers/gpu/drm/mediatek/mtk_dp.c b/drivers/gpu/drm/mediatek/mtk_dp.c
> index e2a6001fc0ccc..ea970a9bfe936 100644
> --- a/drivers/gpu/drm/mediatek/mtk_dp.c
> +++ b/drivers/gpu/drm/mediatek/mtk_dp.c
[ ... ]
> @@ -1469,7 +1470,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 this blind initialization
cause mode validation to falsely accept unsupported high-bandwidth modes?
Because mtk_dp_bridge_mode_valid() and
mtk_dp_bridge_atomic_get_input_bus_fmts() are called before atomic_enable()
during mode enumeration, they evaluate available bandwidth using this
un-negotiated train_info.link_rate:
mtk_dp_bridge_mode_valid() {
...
u32 rate = drm_dp_bw_code_to_link_rate(mtk_dp->train_info.link_rate) *
lane_count_min;
...
}
For eDP connections, actual link training is deferred until
mtk_dp_bridge_atomic_enable(). Using the un-negotiated rate here ignores the
board's device tree limit (max-linkrate-mhz) and the sink's DPCD capabilities.
Can this result in configuring a display mode that exceeds the actual link
bandwidth, leading to link training failures or black screens, and failing
to fall back to bandwidth-saving formats like YUV422?
> 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/20260709113148.49090-1-angelogioacchino.delregno@collabora.com?part=9
^ permalink raw reply [flat|nested] 22+ messages in thread
* [PATCH v4 10/12] drm/mediatek: mtk_dp: Add support for HotPlug Detection in DP AUX
2026-07-09 11:31 [PATCH v4 00/12] drm: MediaTek DisplayPort cleanups and MT8196 eDP AngeloGioacchino Del Regno
` (8 preceding siblings ...)
2026-07-09 11:31 ` [PATCH v4 09/12] drm/mediatek: mtk_dp: Move max link rate to SoC specific data AngeloGioacchino Del Regno
@ 2026-07-09 11:31 ` AngeloGioacchino Del Regno
2026-07-09 12:00 ` sashiko-bot
2026-07-09 11:31 ` [PATCH v4 11/12] drm/mediatek: mtk_dp: Add support for eDP1.5 IPs and MT8196 SoC AngeloGioacchino Del Regno
2026-07-09 11:31 ` [PATCH v4 12/12] drm/mediatek: mtk_dp: Clarify XTAL freq and Debounce registers AngeloGioacchino Del Regno
11 siblings, 1 reply; 22+ messages in thread
From: AngeloGioacchino Del Regno @ 2026-07-09 11:31 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 | 105 +++++++++++++++++++++++---
drivers/gpu/drm/mediatek/mtk_dp_reg.h | 18 +++++
2 files changed, 112 insertions(+), 11 deletions(-)
diff --git a/drivers/gpu/drm/mediatek/mtk_dp.c b/drivers/gpu/drm/mediatek/mtk_dp.c
index ea970a9bfe93..772ba311a34a 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] = {
@@ -1047,7 +1048,30 @@ 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);
+ u32 ret = 0;
+
+ 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);
+ }
+
+ /* Map those to the transmitter hwirqs for simplicity */
+ if (irq_status & HPD_CONNECT_EVENT)
+ ret |= MTK_DP_HPD_CONNECT;
+ if (irq_status & HPD_INTERRUPT_EVENT)
+ ret |= MTK_DP_HPD_INTERRUPT;
+ if (irq_status & HPD_DISCONNECT_EVENT)
+ ret |= MTK_DP_HPD_DISCONNECT;
+
+ return ret;
+}
+
+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;
@@ -1062,8 +1086,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;
+
+ /* On SoCs with working AUX HPD, the transmitter HPD register is ignored by HW */
+ 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 |
@@ -1089,9 +1133,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);
@@ -2012,7 +2081,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);
}
@@ -2079,6 +2152,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;
@@ -2097,11 +2171,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;
@@ -2113,10 +2191,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] 22+ messages in thread* Re: [PATCH v4 10/12] drm/mediatek: mtk_dp: Add support for HotPlug Detection in DP AUX
2026-07-09 11:31 ` [PATCH v4 10/12] drm/mediatek: mtk_dp: Add support for HotPlug Detection in DP AUX AngeloGioacchino Del Regno
@ 2026-07-09 12:00 ` sashiko-bot
2026-07-09 12:05 ` AngeloGioacchino Del Regno
0 siblings, 1 reply; 22+ messages in thread
From: sashiko-bot @ 2026-07-09 12:00 UTC (permalink / raw)
To: AngeloGioacchino Del Regno; +Cc: conor+dt, dri-devel, robh, devicetree
Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:
- [High] Unhandled interrupt storm due to unconditional unmasking of AUX HPD interrupts on older SoCs.
- [High] Unsafe read-modify-write on the interrupt clear register `MTK_DP_AUX_TX_P0_INT_CLR` causes lost interrupts.
- [Medium] Missing `legacy_regoff` addition when polling the AUX HPD status register `MTK_DP_AUX_P0_364C`.
--
--- Patch [10]: [PATCH v4 10/12] drm/mediatek: mtk_dp: Add support for HotPlug Detection in DP AUX ---
commit d87425adb9b3f30b1f231894a984a344e048ae99
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 hotplug detection via DP AUX in MediaTek DP IP,
avoiding the need to power up the entire eDP/DP IP. It introduces a new
flag to select the HPD strategy.
> diff --git a/drivers/gpu/drm/mediatek/mtk_dp.c b/drivers/gpu/drm/mediatek/mtk_dp.c
> index ea970a9bfe936..772ba311a34a7 100644
> --- a/drivers/gpu/drm/mediatek/mtk_dp.c
> +++ b/drivers/gpu/drm/mediatek/mtk_dp.c
> @@ -1047,7 +1048,30 @@ 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);
> + u32 ret = 0;
> +
> + if (irq_status) {
> + mtk_dp_update_bits(mtk_dp, MTK_DP_AUX_TX_P0_INT_CLR,
> + irq_status, irq_status);
[Severity: High]
Can this read-modify-write operation drop newly arrived interrupts?
mtk_dp_update_bits() uses regmap_update_bits() which performs a
read-modify-write. By using irq_status as the mask, if the clear register
reads back with new interrupt bits set (that arrived after the INT_STA read),
the read-modify-write will preserve those new bits and write them back as 1s,
unintentionally clearing them before they are handled.
Should a full mask (like DP_TX_AUX_INT_MASK) be used here instead to ensure
non-target bits are zeroed out?
> + mtk_dp_update_bits(mtk_dp, MTK_DP_AUX_TX_P0_INT_CLR,
> + 0, irq_status);
> + }
> +
[ ... ]
> @@ -1062,8 +1086,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;
> +
> + /* On SoCs with working AUX HPD, the transmitter HPD register is ignored by HW */
> + 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);
> +
[Severity: High]
Does this code risk causing an unhandled interrupt storm on older SoCs?
Since MTK_DP_TX_AUX_INT_MASKING is updated unconditionally, the AUX HPD
interrupts are unmasked even if aux_hpd_supported is false.
If an older SoC triggers an AUX HPD interrupt, mtk_dp_hwirq_get_clear()
will branch to mtk_dp_trans_hwirq_get_clear() and ignore the AUX interrupt,
causing it to remain asserted and repeatedly trigger.
Should this unmasking be guarded by the aux_hpd_supported flag?
> mtk_dp_update_bits(mtk_dp, MTK_DP_TRANS_P0_3418,
> enable ? 0 :
> IRQ_MASK_DP_TRANS_P0_DISC_IRQ |
[ ... ]
> @@ -2113,10 +2191,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]
Is the register address missing the legacy_regoff addition here?
Unlike mtk_dp_read() which automatically adds mtk_dp->legacy_regoff,
regmap_read_poll_timeout() operates directly on the regmap.
If a platform with aux_hpd_supported also uses a non-zero legacy_regoff, this
will poll the wrong physical register address. The fallback path for older
SoCs correctly applies the offset manually.
> + 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);
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260709113148.49090-1-angelogioacchino.delregno@collabora.com?part=10
^ permalink raw reply [flat|nested] 22+ messages in thread* Re: [PATCH v4 10/12] drm/mediatek: mtk_dp: Add support for HotPlug Detection in DP AUX
2026-07-09 12:00 ` sashiko-bot
@ 2026-07-09 12:05 ` AngeloGioacchino Del Regno
0 siblings, 0 replies; 22+ messages in thread
From: AngeloGioacchino Del Regno @ 2026-07-09 12:05 UTC (permalink / raw)
To: sashiko-reviews; +Cc: conor+dt, dri-devel, robh, devicetree
On 7/9/26 14:00, sashiko-bot@kernel.org wrote:
> Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:
> - [High] Unhandled interrupt storm due to unconditional unmasking of AUX HPD interrupts on older SoCs.
Older SoCs can't trigger this path at all, as these have *non* functional AUX HPD
hence the AUX specific hpd interrupt can never be triggered.
> - [High] Unsafe read-modify-write on the interrupt clear register `MTK_DP_AUX_TX_P0_INT_CLR` causes lost interrupts.
No. That's the exact reason why MediaTek has a SETCLR strategy for many registers.
Interrupts can't be lost this way, and whatever I wrote there is indeed safe.
> - [Medium] Missing `legacy_regoff` addition when polling the AUX HPD status register `MTK_DP_AUX_P0_364C`.
It's missing on purpose. Old SoCs can't reach that code path.
> --
>
> --- Patch [10]: [PATCH v4 10/12] drm/mediatek: mtk_dp: Add support for HotPlug Detection in DP AUX ---
> commit d87425adb9b3f30b1f231894a984a344e048ae99
> 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 hotplug detection via DP AUX in MediaTek DP IP,
> avoiding the need to power up the entire eDP/DP IP. It introduces a new
> flag to select the HPD strategy.
>
>> diff --git a/drivers/gpu/drm/mediatek/mtk_dp.c b/drivers/gpu/drm/mediatek/mtk_dp.c
>> index ea970a9bfe936..772ba311a34a7 100644
>> --- a/drivers/gpu/drm/mediatek/mtk_dp.c
>> +++ b/drivers/gpu/drm/mediatek/mtk_dp.c
>> @@ -1047,7 +1048,30 @@ 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);
>> + u32 ret = 0;
>> +
>> + if (irq_status) {
>> + mtk_dp_update_bits(mtk_dp, MTK_DP_AUX_TX_P0_INT_CLR,
>> + irq_status, irq_status);
>
> [Severity: High]
> Can this read-modify-write operation drop newly arrived interrupts?
>
> mtk_dp_update_bits() uses regmap_update_bits() which performs a
> read-modify-write. By using irq_status as the mask, if the clear register
> reads back with new interrupt bits set (that arrived after the INT_STA read),
> the read-modify-write will preserve those new bits and write them back as 1s,
> unintentionally clearing them before they are handled.
>
> Should a full mask (like DP_TX_AUX_INT_MASK) be used here instead to ensure
> non-target bits are zeroed out?
>
>> + mtk_dp_update_bits(mtk_dp, MTK_DP_AUX_TX_P0_INT_CLR,
>> + 0, irq_status);
>> + }
>> +
>
> [ ... ]
>
>> @@ -1062,8 +1086,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;
>> +
>> + /* On SoCs with working AUX HPD, the transmitter HPD register is ignored by HW */
>> + 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);
>> +
>
> [Severity: High]
> Does this code risk causing an unhandled interrupt storm on older SoCs?
>
> Since MTK_DP_TX_AUX_INT_MASKING is updated unconditionally, the AUX HPD
> interrupts are unmasked even if aux_hpd_supported is false.
>
> If an older SoC triggers an AUX HPD interrupt, mtk_dp_hwirq_get_clear()
> will branch to mtk_dp_trans_hwirq_get_clear() and ignore the AUX interrupt,
> causing it to remain asserted and repeatedly trigger.
>
> Should this unmasking be guarded by the aux_hpd_supported flag?
>
>> mtk_dp_update_bits(mtk_dp, MTK_DP_TRANS_P0_3418,
>> enable ? 0 :
>> IRQ_MASK_DP_TRANS_P0_DISC_IRQ |
>
> [ ... ]
>
>> @@ -2113,10 +2191,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]
> Is the register address missing the legacy_regoff addition here?
>
> Unlike mtk_dp_read() which automatically adds mtk_dp->legacy_regoff,
> regmap_read_poll_timeout() operates directly on the regmap.
>
> If a platform with aux_hpd_supported also uses a non-zero legacy_regoff, this
> will poll the wrong physical register address. The fallback path for older
> SoCs correctly applies the offset manually.
>
>> + 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);
>
^ permalink raw reply [flat|nested] 22+ messages in thread
* [PATCH v4 11/12] drm/mediatek: mtk_dp: Add support for eDP1.5 IPs and MT8196 SoC
2026-07-09 11:31 [PATCH v4 00/12] drm: MediaTek DisplayPort cleanups and MT8196 eDP AngeloGioacchino Del Regno
` (9 preceding siblings ...)
2026-07-09 11:31 ` [PATCH v4 10/12] drm/mediatek: mtk_dp: Add support for HotPlug Detection in DP AUX AngeloGioacchino Del Regno
@ 2026-07-09 11:31 ` AngeloGioacchino Del Regno
2026-07-09 12:11 ` sashiko-bot
2026-07-09 11:31 ` [PATCH v4 12/12] drm/mediatek: mtk_dp: Clarify XTAL freq and Debounce registers AngeloGioacchino Del Regno
11 siblings, 1 reply; 22+ messages in thread
From: AngeloGioacchino Del Regno @ 2026-07-09 11:31 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 | 289 +++++++++++++++++++++++---
drivers/gpu/drm/mediatek/mtk_dp_reg.h | 61 +++++-
2 files changed, 315 insertions(+), 35 deletions(-)
diff --git a/drivers/gpu/drm/mediatek/mtk_dp.c b/drivers/gpu/drm/mediatek/mtk_dp.c
index 772ba311a34a..fe7e05e27f6f 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);
@@ -633,6 +652,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);
@@ -648,7 +669,18 @@ 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;
+
+ mask |= SDP_DP13_EN_DP_ENC1_P0;
+
+ 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)
@@ -1116,6 +1148,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,
@@ -1129,12 +1227,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) |
@@ -1161,6 +1262,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);
@@ -1210,24 +1315,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)
@@ -1240,6 +1408,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)
@@ -1256,6 +1444,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);
@@ -1359,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)
@@ -1373,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);
@@ -1422,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);
@@ -1520,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)) {
regmap_set_bits(mtk_dp->regs, MTK_DP_0034, DA_CKM_CKTX0_EN_FORCE_EN);
@@ -2078,7 +2286,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);
@@ -2580,6 +2795,10 @@ static void mtk_dp_bridge_atomic_disable(struct drm_bridge *bridge,
/* SDP path reset sw*/
mtk_dp_sdp_path_reset(mtk_dp);
+ /* Make sure BIAS is powered on after reset even when disabled */
+ if (mtk_dp->data->force_pwr_states)
+ mtk_dp_encoder_force_bias_power_on(mtk_dp);
+
/* Ensure the sink is muted */
msleep(20);
}
@@ -2860,7 +3079,8 @@ 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);
+ if (mtk_dp->data->efuse_fmt)
+ mtk_dp_get_calibration_data(mtk_dp);
mtk_dp->phy = devm_phy_get(&mtk_dp->phy_dev->dev, "dp");
if (IS_ERR(mtk_dp->phy))
@@ -3081,6 +3301,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 = {
@@ -3090,6 +3311,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 = {
@@ -3099,6 +3321,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[] = {
@@ -3118,6 +3353,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] 22+ messages in thread* Re: [PATCH v4 11/12] drm/mediatek: mtk_dp: Add support for eDP1.5 IPs and MT8196 SoC
2026-07-09 11:31 ` [PATCH v4 11/12] drm/mediatek: mtk_dp: Add support for eDP1.5 IPs and MT8196 SoC AngeloGioacchino Del Regno
@ 2026-07-09 12:11 ` sashiko-bot
2026-07-09 12:17 ` AngeloGioacchino Del Regno
0 siblings, 1 reply; 22+ messages in thread
From: sashiko-bot @ 2026-07-09 12:11 UTC (permalink / raw)
To: AngeloGioacchino Del Regno; +Cc: conor+dt, dri-devel, robh, devicetree
Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:
New issues:
- [High] Flawed hardware reset sequence and register mask conflict for the new IP (hwip_v1p4) in mtk_dp_encoder_reset().
- [High] Uninitialized calibration data is applied to PHY registers on MT8196 if a legacy device tree is used.
Pre-existing issues:
- [High] Sleeping functions called from atomic context in bridge atomic callbacks.
--
--- Patch [11]: [PATCH v4 11/12] drm/mediatek: mtk_dp: Add support for eDP1.5 IPs and MT8196 SoC ---
commit 21e6cb76ec5d736e41c62351d0dcc4f501bc644f
Author: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
drm/mediatek: mtk_dp: Add support for eDP1.5 IPs and MT8196 SoC
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.
> --- a/drivers/gpu/drm/mediatek/mtk_dp_reg.h
> +++ b/drivers/gpu/drm/mediatek/mtk_dp_reg.h
[ ... ]
> +#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)
[ ... ]
> --- a/drivers/gpu/drm/mediatek/mtk_dp.c
> +++ b/drivers/gpu/drm/mediatek/mtk_dp.c
[ ... ]
> +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);
> +}
[Severity: High]
Does ENC_PHY_STATE_RESET_ALL_MASK overlap with functional state bits
like PHY_STATE_W_1_DP_ENC_P0_3 and DP_ENCODER_DVO_ON_W_1 defined in
mtk_dp_reg.h?
Also, could the new hwip_v1p4 sequence in mtk_dp_encoder_reset() leave the
encoder PHY stuck in reset? The code asserts ENC_PHY_STATE_RESET_ALL_MASK
before the wait, but there does not appear to be a step to deassert it after
the sleep finishes.
> @@ -2860,7 +3079,8 @@ static int mtk_dp_register_phy(struct mtk_dp *mtk_dp)
[ ... ]
> /* PHY calibration data is in mtk_dp only for legacy devicetree */
> - mtk_dp_get_calibration_data(mtk_dp);
> + if (mtk_dp->data->efuse_fmt)
> + mtk_dp_get_calibration_data(mtk_dp);
>
> mtk_dp->phy = devm_phy_get(&mtk_dp->phy_dev->dev, "dp");
[ ... ]
> @@ -1359,8 +1550,10 @@ static int mtk_dp_phy_configure(struct mtk_dp *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);
[Severity: High]
If a legacy device tree is used on an MT8196 device, could this configuration
apply uninitialized zeros to the PHY hardware?
In mtk_dp_register_phy(), mtk_dp_get_calibration_data() is skipped because
efuse_fmt is NULL for mt8196_edp_data. However, mtk_dp_phy_configure() will
still call mtk_dp_set_calibration_data() if the legacy phy_dev was created,
potentially writing an unpopulated cal_data array directly to the registers.
> +static void mtk_dp_encoder_force_bias_power_on(struct mtk_dp *mtk_dp)
> +{
[ ... ]
> + /* Wait for the MCU to get LDO ready in PHYD */
> + msleep(50);
[ ... ]
> +}
[ ... ]
> @@ -2580,6 +2795,10 @@ static void mtk_dp_bridge_atomic_disable(struct drm_bridge *bridge,
[ ... ]
> /* SDP path reset sw*/
> mtk_dp_sdp_path_reset(mtk_dp);
>
> + /* Make sure BIAS is powered on after reset even when disabled */
> + 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 does this introduce an additional sleeping
function into an atomic context path?
Since mtk_dp_bridge_atomic_disable() operates in an atomic context during
modesetting, calling mtk_dp_encoder_force_bias_power_on() uses msleep(50),
which could result in kernel warnings or system instability.
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260709113148.49090-1-angelogioacchino.delregno@collabora.com?part=11
^ permalink raw reply [flat|nested] 22+ messages in thread* Re: [PATCH v4 11/12] drm/mediatek: mtk_dp: Add support for eDP1.5 IPs and MT8196 SoC
2026-07-09 12:11 ` sashiko-bot
@ 2026-07-09 12:17 ` AngeloGioacchino Del Regno
0 siblings, 0 replies; 22+ messages in thread
From: AngeloGioacchino Del Regno @ 2026-07-09 12:17 UTC (permalink / raw)
To: sashiko-reviews; +Cc: conor+dt, dri-devel, robh, devicetree
On 7/9/26 14:11, sashiko-bot@kernel.org wrote:
> Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:
>
> New issues:
> - [High] Flawed hardware reset sequence and register mask conflict for the new IP (hwip_v1p4) in mtk_dp_encoder_reset().
> - [High] Uninitialized calibration data is applied to PHY registers on MT8196 if a legacy device tree is used.
>
> Pre-existing issues:
> - [High] Sleeping functions called from atomic context in bridge atomic callbacks.
None of those are valid, if you want more context, check below.
> --
>
> --- Patch [11]: [PATCH v4 11/12] drm/mediatek: mtk_dp: Add support for eDP1.5 IPs and MT8196 SoC ---
> commit 21e6cb76ec5d736e41c62351d0dcc4f501bc644f
> Author: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
>
> drm/mediatek: mtk_dp: Add support for eDP1.5 IPs and MT8196 SoC
>
> 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.
>
>> --- a/drivers/gpu/drm/mediatek/mtk_dp_reg.h
>> +++ b/drivers/gpu/drm/mediatek/mtk_dp_reg.h
> [ ... ]
>> +#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)
>
> [ ... ]
>
>> --- a/drivers/gpu/drm/mediatek/mtk_dp.c
>> +++ b/drivers/gpu/drm/mediatek/mtk_dp.c
> [ ... ]
>> +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);
>> +}
>
> [Severity: High]
> Does ENC_PHY_STATE_RESET_ALL_MASK overlap with functional state bits
> like PHY_STATE_W_1_DP_ENC_P0_3 and DP_ENCODER_DVO_ON_W_1 defined in
> mtk_dp_reg.h?
>
That's trolling!!! :-P
Yes, and that's on purpose.
> Also, could the new hwip_v1p4 sequence in mtk_dp_encoder_reset() leave the
> encoder PHY stuck in reset? The code asserts ENC_PHY_STATE_RESET_ALL_MASK
> before the wait, but there does not appear to be a step to deassert it after
> the sleep finishes.
>
It's ok, because it's auto-cleared by HW.
>> @@ -2860,7 +3079,8 @@ static int mtk_dp_register_phy(struct mtk_dp *mtk_dp)
> [ ... ]
>> /* PHY calibration data is in mtk_dp only for legacy devicetree */
>> - mtk_dp_get_calibration_data(mtk_dp);
>> + if (mtk_dp->data->efuse_fmt)
>> + mtk_dp_get_calibration_data(mtk_dp);
>>
>> mtk_dp->phy = devm_phy_get(&mtk_dp->phy_dev->dev, "dp");
>
> [ ... ]
>
>> @@ -1359,8 +1550,10 @@ static int mtk_dp_phy_configure(struct mtk_dp *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);
>
> [Severity: High]
> If a legacy device tree is used on an MT8196 device, could this configuration
> apply uninitialized zeros to the PHY hardware?
If a legacy device tree is used on MT8196, this MediaTek maintainer (me) needs
a big vacation :-D
This is an impossible scenario.
>
> In mtk_dp_register_phy(), mtk_dp_get_calibration_data() is skipped because
> efuse_fmt is NULL for mt8196_edp_data. However, mtk_dp_phy_configure() will
> still call mtk_dp_set_calibration_data() if the legacy phy_dev was created,
> potentially writing an unpopulated cal_data array directly to the registers.
>
The legacy phy_dev can't be created, unless the DT is very-very-very wrong, and
if it is, this driver can't get a magic 8 ball.
>> +static void mtk_dp_encoder_force_bias_power_on(struct mtk_dp *mtk_dp)
>> +{
> [ ... ]
>> + /* Wait for the MCU to get LDO ready in PHYD */
>> + msleep(50);
> [ ... ]
>> +}
>
> [ ... ]
>
>> @@ -2580,6 +2795,10 @@ static void mtk_dp_bridge_atomic_disable(struct drm_bridge *bridge,
> [ ... ]
>> /* SDP path reset sw*/
>> mtk_dp_sdp_path_reset(mtk_dp);
>>
>> + /* Make sure BIAS is powered on after reset even when disabled */
>> + 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 does this introduce an additional sleeping
> function into an atomic context path?
>
> Since mtk_dp_bridge_atomic_disable() operates in an atomic context during
> modesetting, calling mtk_dp_encoder_force_bias_power_on() uses msleep(50),
> which could result in kernel warnings or system instability.
>
It's not atomic context....
^ permalink raw reply [flat|nested] 22+ messages in thread
* [PATCH v4 12/12] drm/mediatek: mtk_dp: Clarify XTAL freq and Debounce registers
2026-07-09 11:31 [PATCH v4 00/12] drm: MediaTek DisplayPort cleanups and MT8196 eDP AngeloGioacchino Del Regno
` (10 preceding siblings ...)
2026-07-09 11:31 ` [PATCH v4 11/12] drm/mediatek: mtk_dp: Add support for eDP1.5 IPs and MT8196 SoC AngeloGioacchino Del Regno
@ 2026-07-09 11:31 ` AngeloGioacchino Del Regno
2026-07-09 11:57 ` sashiko-bot
11 siblings, 1 reply; 22+ messages in thread
From: AngeloGioacchino Del Regno @ 2026-07-09 11:31 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 fe7e05e27f6f..1183738ab903 100644
--- a/drivers/gpu/drm/mediatek/mtk_dp.c
+++ b/drivers/gpu/drm/mediatek/mtk_dp.c
@@ -1216,9 +1216,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);
@@ -1260,28 +1266,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..ce47b99dddc4 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(7, 6)
+#define HPD_INT_LOW_THD_DP_TRANS_P0_MASK GENMASK(5, 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)
@@ -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] 22+ messages in thread* Re: [PATCH v4 12/12] drm/mediatek: mtk_dp: Clarify XTAL freq and Debounce registers
2026-07-09 11:31 ` [PATCH v4 12/12] drm/mediatek: mtk_dp: Clarify XTAL freq and Debounce registers AngeloGioacchino Del Regno
@ 2026-07-09 11:57 ` sashiko-bot
0 siblings, 0 replies; 22+ messages in thread
From: sashiko-bot @ 2026-07-09 11:57 UTC (permalink / raw)
To: AngeloGioacchino Del Regno; +Cc: conor+dt, dri-devel, robh, devicetree
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Medium] The patch silently fixes a pre-existing double-shift bug that was incorrectly writing 0 to the HPD interrupt debounce thresholds. This alters the hardware state, contradicting the commit message's claim that its 'only purpose [is] increasing human readability'.
--
--- Patch [12]: [PATCH v4 12/12] drm/mediatek: mtk_dp: Clarify XTAL freq and Debounce registers ---
commit 947b13de5fec9b2788067fcdae3f6c00732e0060
Author: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
drm/mediatek: mtk_dp: Clarify XTAL freq and Debounce registers
This patch clarifies the meaning of the sub-fields in the crystal frequency
and transmitter interrupt debounce registers for increased human readability.
> Clarify the meaning of the sub-fields in the crystal frequency and
> transmitter interrupt debounce registers, with the only purpose of
> increasing human readability.
[ ... ]
> --- a/drivers/gpu/drm/mediatek/mtk_dp.c
> +++ b/drivers/gpu/drm/mediatek/mtk_dp.c
> @@ -1260,28 +1266,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]
Does this patch silently fix a functional bug rather than just improving
readability?
In the original code, the LOWER_500US and UPPER_1100US macros were already
shifted by 4 and 6 respectively. Applying << 4 on top of them resulted in a
double shift, making val equal to 0xA00. When that was masked with
HPD_INT_THD_DP_TRANS_P0_MASK (which is 0xF0), it evaluated to 0, incorrectly
programming the hardware.
The new code using FIELD_PREP_CONST calculates 0xA0, correctly applying the
intended 500/1100uS thresholds.
Since the commit message states this has the only purpose of increasing human
readability, could this functional fix be overlooked for stable backports?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260709113148.49090-1-angelogioacchino.delregno@collabora.com?part=12
^ permalink raw reply [flat|nested] 22+ messages in thread