* [PATCH RFC/DO NOT MERGE 00/12] drm/msm/hdmi: Add Eliza HDMI and HDMI PHY
@ 2026-08-28 14:04 ` Krzysztof Kozlowski
0 siblings, 0 replies; 38+ messages in thread
From: Krzysztof Kozlowski @ 2026-08-28 14:04 UTC (permalink / raw)
To: Rob Clark, Dmitry Baryshkov, Abhinav Kumar, Jessica Zhang,
Sean Paul, Marijn Suijten, David Airlie, Simona Vetter,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Vinod Koul, Neil Armstrong,
Manivannan Sadhasivam, Bjorn Andersson, Konrad Dybcio
Cc: linux-arm-msm, dri-devel, freedreno, linux-kernel, devicetree,
Krzysztof Kozlowski, Krzysztof Kozlowski, linux-phy
RFC
===
Posting to get some comments or just for reference if anyone wants to
build on top, because unfortunately HDMI does not work - no signal and
missing TX ACK on HDMI PHY (hdmi_eliza_phy_ready_poll). The TX ACK
appears for all four TX0-3 lanes only on the first boot configuration.
The MSM cleanups (first four patches) can be taken as is.
Best regards,
Krzysztof
---
Krzysztof Kozlowski (12):
drm/msm/hdmi_bridge: Drop redundant initialization in msm_hdmi_bridge_init()
drm/msm: Properly handle msm_ioremap() without name
drm/msm/dsi: Fix indentation of if block in dsi_mgr_bridge_mode_valid()
dt-bindings: display/msm: hdmi: Correct name of disallowed supplies
dt-bindings: display/msm: hdmi: Add Eliza HDMI TX
dt-bindings: display/msm: eliza-hdmi-phy: Add Eliza HDMI PHY
drm/msm/hdmi: Split PHY init from power up
drm/msm/hdmi: Add support for PM OPP table
drm/msm/hdmi: Add HDMI for Eliza SoC
drm/msm/hdmi_phy_eliza: Add support for Synopsys-based HDMI phy on Eliza
arm64: dts: qcom: eliza: Add HDMI display with HDMI PHY
arm64: dts: qcom: eliza-evk: Add native HDMI
.../devicetree/bindings/display/msm/hdmi.yaml | 71 +-
.../bindings/display/msm/qcom,eliza-mdss.yaml | 96 ++-
.../bindings/phy/qcom,eliza-hdmi-phy.yaml | 71 ++
arch/arm64/boot/dts/qcom/eliza-evk.dtsi | 103 +++
arch/arm64/boot/dts/qcom/eliza.dtsi | 94 ++-
drivers/gpu/drm/msm/Makefile | 1 +
.../gpu/drm/msm/disp/dpu1/catalog/dpu_12_4_eliza.h | 8 +
drivers/gpu/drm/msm/disp/dpu1/dpu_hw_interrupts.c | 15 +
drivers/gpu/drm/msm/disp/dpu1/dpu_hw_interrupts.h | 3 +
drivers/gpu/drm/msm/disp/dpu1/dpu_hw_mdss.h | 3 +
drivers/gpu/drm/msm/dsi/dsi_manager.c | 2 +-
drivers/gpu/drm/msm/hdmi/hdmi.c | 40 ++
drivers/gpu/drm/msm/hdmi/hdmi.h | 26 +
drivers/gpu/drm/msm/hdmi/hdmi_bridge.c | 117 +++-
drivers/gpu/drm/msm/hdmi/hdmi_phy.c | 28 +-
drivers/gpu/drm/msm/hdmi/hdmi_phy_eliza.c | 723 +++++++++++++++++++++
drivers/gpu/drm/msm/msm_drv.h | 5 +
drivers/gpu/drm/msm/msm_io_utils.c | 6 +-
drivers/gpu/drm/msm/registers/display/hdmi.xml | 140 ++++
19 files changed, 1520 insertions(+), 32 deletions(-)
---
base-commit: 448e60718f7b424994fe1a9013b5317e756e18eb
change-id: 20260824-drm-msm-hdmi-eliza-b3da5ff57851
Best regards,
--
Krzysztof Kozlowski <krzysztof.kozlowski@oss.qualcomm.com>
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply [flat|nested] 38+ messages in thread* [PATCH RFC/DO NOT MERGE 01/12] drm/msm/hdmi_bridge: Drop redundant initialization in msm_hdmi_bridge_init()
2026-08-28 14:04 ` Krzysztof Kozlowski
@ 2026-08-28 14:04 ` Krzysztof Kozlowski
-1 siblings, 0 replies; 38+ messages in thread
From: Krzysztof Kozlowski @ 2026-08-28 14:04 UTC (permalink / raw)
To: Rob Clark, Dmitry Baryshkov, Abhinav Kumar, Jessica Zhang,
Sean Paul, Marijn Suijten, David Airlie, Simona Vetter,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Vinod Koul, Neil Armstrong,
Manivannan Sadhasivam, Bjorn Andersson, Konrad Dybcio
Cc: linux-arm-msm, dri-devel, freedreno, linux-kernel, devicetree,
Krzysztof Kozlowski, Krzysztof Kozlowski, linux-phy
Local 'struct drm_bridge *bridge' variable is assigned in ~13th line of
the function, before any first use, thus explicit NULL initialization is
not necessary.
Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski@oss.qualcomm.com>
---
drivers/gpu/drm/msm/hdmi/hdmi_bridge.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c b/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c
index 157f19bd90b4..a5f891661ea3 100644
--- a/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c
+++ b/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c
@@ -472,7 +472,7 @@ msm_hdmi_hotplug_work(struct work_struct *work)
/* initialize bridge */
int msm_hdmi_bridge_init(struct hdmi *hdmi)
{
- struct drm_bridge *bridge = NULL;
+ struct drm_bridge *bridge;
struct hdmi_bridge *hdmi_bridge;
int ret;
--
2.53.0
^ permalink raw reply related [flat|nested] 38+ messages in thread* [PATCH RFC/DO NOT MERGE 01/12] drm/msm/hdmi_bridge: Drop redundant initialization in msm_hdmi_bridge_init()
@ 2026-08-28 14:04 ` Krzysztof Kozlowski
0 siblings, 0 replies; 38+ messages in thread
From: Krzysztof Kozlowski @ 2026-08-28 14:04 UTC (permalink / raw)
To: Rob Clark, Dmitry Baryshkov, Abhinav Kumar, Jessica Zhang,
Sean Paul, Marijn Suijten, David Airlie, Simona Vetter,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Vinod Koul, Neil Armstrong,
Manivannan Sadhasivam, Bjorn Andersson, Konrad Dybcio
Cc: linux-arm-msm, dri-devel, freedreno, linux-kernel, devicetree,
Krzysztof Kozlowski, Krzysztof Kozlowski, linux-phy
Local 'struct drm_bridge *bridge' variable is assigned in ~13th line of
the function, before any first use, thus explicit NULL initialization is
not necessary.
Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski@oss.qualcomm.com>
---
drivers/gpu/drm/msm/hdmi/hdmi_bridge.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c b/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c
index 157f19bd90b4..a5f891661ea3 100644
--- a/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c
+++ b/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c
@@ -472,7 +472,7 @@ msm_hdmi_hotplug_work(struct work_struct *work)
/* initialize bridge */
int msm_hdmi_bridge_init(struct hdmi *hdmi)
{
- struct drm_bridge *bridge = NULL;
+ struct drm_bridge *bridge;
struct hdmi_bridge *hdmi_bridge;
int ret;
--
2.53.0
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply related [flat|nested] 38+ messages in thread
* [PATCH RFC/DO NOT MERGE 02/12] drm/msm: Properly handle msm_ioremap() without name
2026-08-28 14:04 ` Krzysztof Kozlowski
@ 2026-08-28 14:05 ` Krzysztof Kozlowski
-1 siblings, 0 replies; 38+ messages in thread
From: Krzysztof Kozlowski @ 2026-08-28 14:05 UTC (permalink / raw)
To: Rob Clark, Dmitry Baryshkov, Abhinav Kumar, Jessica Zhang,
Sean Paul, Marijn Suijten, David Airlie, Simona Vetter,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Vinod Koul, Neil Armstrong,
Manivannan Sadhasivam, Bjorn Andersson, Konrad Dybcio
Cc: linux-arm-msm, dri-devel, freedreno, linux-kernel, devicetree,
Krzysztof Kozlowski, Krzysztof Kozlowski, linux-phy
msm_ioremap() accepts being called without name of the region to map and
in such case maps by index 0. However error paths still use the name in
error message.
Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski@oss.qualcomm.com>
---
drivers/gpu/drm/msm/msm_io_utils.c | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/drivers/gpu/drm/msm/msm_io_utils.c b/drivers/gpu/drm/msm/msm_io_utils.c
index a6efe1eac271..93b94e330cb8 100644
--- a/drivers/gpu/drm/msm/msm_io_utils.c
+++ b/drivers/gpu/drm/msm/msm_io_utils.c
@@ -77,7 +77,8 @@ static void __iomem *_msm_ioremap(struct platform_device *pdev, const char *name
if (!res) {
if (!quiet)
- DRM_DEV_ERROR(&pdev->dev, "failed to get memory resource: %s\n", name);
+ DRM_DEV_ERROR(&pdev->dev, "failed to get memory resource: %s\n",
+ (name ? name : "#0"));
return ERR_PTR(-EINVAL);
}
@@ -86,7 +87,8 @@ static void __iomem *_msm_ioremap(struct platform_device *pdev, const char *name
ptr = devm_ioremap(&pdev->dev, res->start, size);
if (!ptr) {
if (!quiet)
- DRM_DEV_ERROR(&pdev->dev, "failed to ioremap: %s\n", name);
+ DRM_DEV_ERROR(&pdev->dev, "failed to ioremap: %s\n",
+ (name ? name : "#0"));
return ERR_PTR(-ENOMEM);
}
--
2.53.0
^ permalink raw reply related [flat|nested] 38+ messages in thread* [PATCH RFC/DO NOT MERGE 02/12] drm/msm: Properly handle msm_ioremap() without name
@ 2026-08-28 14:05 ` Krzysztof Kozlowski
0 siblings, 0 replies; 38+ messages in thread
From: Krzysztof Kozlowski @ 2026-08-28 14:05 UTC (permalink / raw)
To: Rob Clark, Dmitry Baryshkov, Abhinav Kumar, Jessica Zhang,
Sean Paul, Marijn Suijten, David Airlie, Simona Vetter,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Vinod Koul, Neil Armstrong,
Manivannan Sadhasivam, Bjorn Andersson, Konrad Dybcio
Cc: linux-arm-msm, dri-devel, freedreno, linux-kernel, devicetree,
Krzysztof Kozlowski, Krzysztof Kozlowski, linux-phy
msm_ioremap() accepts being called without name of the region to map and
in such case maps by index 0. However error paths still use the name in
error message.
Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski@oss.qualcomm.com>
---
drivers/gpu/drm/msm/msm_io_utils.c | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/drivers/gpu/drm/msm/msm_io_utils.c b/drivers/gpu/drm/msm/msm_io_utils.c
index a6efe1eac271..93b94e330cb8 100644
--- a/drivers/gpu/drm/msm/msm_io_utils.c
+++ b/drivers/gpu/drm/msm/msm_io_utils.c
@@ -77,7 +77,8 @@ static void __iomem *_msm_ioremap(struct platform_device *pdev, const char *name
if (!res) {
if (!quiet)
- DRM_DEV_ERROR(&pdev->dev, "failed to get memory resource: %s\n", name);
+ DRM_DEV_ERROR(&pdev->dev, "failed to get memory resource: %s\n",
+ (name ? name : "#0"));
return ERR_PTR(-EINVAL);
}
@@ -86,7 +87,8 @@ static void __iomem *_msm_ioremap(struct platform_device *pdev, const char *name
ptr = devm_ioremap(&pdev->dev, res->start, size);
if (!ptr) {
if (!quiet)
- DRM_DEV_ERROR(&pdev->dev, "failed to ioremap: %s\n", name);
+ DRM_DEV_ERROR(&pdev->dev, "failed to ioremap: %s\n",
+ (name ? name : "#0"));
return ERR_PTR(-ENOMEM);
}
--
2.53.0
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply related [flat|nested] 38+ messages in thread
* [PATCH RFC/DO NOT MERGE 03/12] drm/msm/dsi: Fix indentation of if block in dsi_mgr_bridge_mode_valid()
2026-08-28 14:04 ` Krzysztof Kozlowski
@ 2026-08-28 14:05 ` Krzysztof Kozlowski
-1 siblings, 0 replies; 38+ messages in thread
From: Krzysztof Kozlowski @ 2026-08-28 14:05 UTC (permalink / raw)
To: Rob Clark, Dmitry Baryshkov, Abhinav Kumar, Jessica Zhang,
Sean Paul, Marijn Suijten, David Airlie, Simona Vetter,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Vinod Koul, Neil Armstrong,
Manivannan Sadhasivam, Bjorn Andersson, Konrad Dybcio
Cc: linux-arm-msm, dri-devel, freedreno, linux-kernel, devicetree,
Krzysztof Kozlowski, Krzysztof Kozlowski, linux-phy
Correct confusing indentation within else {} block in
dsi_mgr_bridge_mode_valid().
Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski@oss.qualcomm.com>
---
drivers/gpu/drm/msm/dsi/dsi_manager.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/msm/dsi/dsi_manager.c b/drivers/gpu/drm/msm/dsi/dsi_manager.c
index 959daa88b1d0..531d4ff78f56 100644
--- a/drivers/gpu/drm/msm/dsi/dsi_manager.c
+++ b/drivers/gpu/drm/msm/dsi/dsi_manager.c
@@ -429,7 +429,7 @@ static enum drm_mode_status dsi_mgr_bridge_mode_valid(struct drm_bridge *bridge,
if (dev_pm_opp_get_opp_count(&pdev->dev) != 0)
return MODE_CLOCK_RANGE;
} else {
- return MODE_ERROR;
+ return MODE_ERROR;
}
return msm_dsi_host_check_dsc(host, mode);
--
2.53.0
^ permalink raw reply related [flat|nested] 38+ messages in thread* [PATCH RFC/DO NOT MERGE 03/12] drm/msm/dsi: Fix indentation of if block in dsi_mgr_bridge_mode_valid()
@ 2026-08-28 14:05 ` Krzysztof Kozlowski
0 siblings, 0 replies; 38+ messages in thread
From: Krzysztof Kozlowski @ 2026-08-28 14:05 UTC (permalink / raw)
To: Rob Clark, Dmitry Baryshkov, Abhinav Kumar, Jessica Zhang,
Sean Paul, Marijn Suijten, David Airlie, Simona Vetter,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Vinod Koul, Neil Armstrong,
Manivannan Sadhasivam, Bjorn Andersson, Konrad Dybcio
Cc: linux-arm-msm, dri-devel, freedreno, linux-kernel, devicetree,
Krzysztof Kozlowski, Krzysztof Kozlowski, linux-phy
Correct confusing indentation within else {} block in
dsi_mgr_bridge_mode_valid().
Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski@oss.qualcomm.com>
---
drivers/gpu/drm/msm/dsi/dsi_manager.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/msm/dsi/dsi_manager.c b/drivers/gpu/drm/msm/dsi/dsi_manager.c
index 959daa88b1d0..531d4ff78f56 100644
--- a/drivers/gpu/drm/msm/dsi/dsi_manager.c
+++ b/drivers/gpu/drm/msm/dsi/dsi_manager.c
@@ -429,7 +429,7 @@ static enum drm_mode_status dsi_mgr_bridge_mode_valid(struct drm_bridge *bridge,
if (dev_pm_opp_get_opp_count(&pdev->dev) != 0)
return MODE_CLOCK_RANGE;
} else {
- return MODE_ERROR;
+ return MODE_ERROR;
}
return msm_dsi_host_check_dsc(host, mode);
--
2.53.0
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply related [flat|nested] 38+ messages in thread
* [PATCH RFC/DO NOT MERGE 04/12] dt-bindings: display/msm: hdmi: Correct name of disallowed supplies
2026-08-28 14:04 ` Krzysztof Kozlowski
@ 2026-08-28 14:05 ` Krzysztof Kozlowski
-1 siblings, 0 replies; 38+ messages in thread
From: Krzysztof Kozlowski @ 2026-08-28 14:05 UTC (permalink / raw)
To: Rob Clark, Dmitry Baryshkov, Abhinav Kumar, Jessica Zhang,
Sean Paul, Marijn Suijten, David Airlie, Simona Vetter,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Vinod Koul, Neil Armstrong,
Manivannan Sadhasivam, Bjorn Andersson, Konrad Dybcio
Cc: linux-arm-msm, dri-devel, freedreno, linux-kernel, devicetree,
Krzysztof Kozlowski, Krzysztof Kozlowski, linux-phy
There are no properties in DTS or Linux drivers called
"core-vcc-supplies" or "hdmi-mux-supplies", so the binding probably
wanted "-supply" properties instead.
Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski@oss.qualcomm.com>
---
Documentation/devicetree/bindings/display/msm/hdmi.yaml | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/Documentation/devicetree/bindings/display/msm/hdmi.yaml b/Documentation/devicetree/bindings/display/msm/hdmi.yaml
index dfec6c3480f3..02d27ccad024 100644
--- a/Documentation/devicetree/bindings/display/msm/hdmi.yaml
+++ b/Documentation/devicetree/bindings/display/msm/hdmi.yaml
@@ -113,7 +113,7 @@ allOf:
- const: core
- const: master_iface
- const: slave_iface
- core-vcc-supplies: false
+ core-vcc-supply: false
- if:
properties:
@@ -136,7 +136,7 @@ allOf:
- const: core
- const: alt_iface
- const: extp
- hdmi-mux-supplies: false
+ hdmi-mux-supply: false
- if:
properties:
--
2.53.0
^ permalink raw reply related [flat|nested] 38+ messages in thread* [PATCH RFC/DO NOT MERGE 04/12] dt-bindings: display/msm: hdmi: Correct name of disallowed supplies
@ 2026-08-28 14:05 ` Krzysztof Kozlowski
0 siblings, 0 replies; 38+ messages in thread
From: Krzysztof Kozlowski @ 2026-08-28 14:05 UTC (permalink / raw)
To: Rob Clark, Dmitry Baryshkov, Abhinav Kumar, Jessica Zhang,
Sean Paul, Marijn Suijten, David Airlie, Simona Vetter,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Vinod Koul, Neil Armstrong,
Manivannan Sadhasivam, Bjorn Andersson, Konrad Dybcio
Cc: linux-arm-msm, dri-devel, freedreno, linux-kernel, devicetree,
Krzysztof Kozlowski, Krzysztof Kozlowski, linux-phy
There are no properties in DTS or Linux drivers called
"core-vcc-supplies" or "hdmi-mux-supplies", so the binding probably
wanted "-supply" properties instead.
Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski@oss.qualcomm.com>
---
Documentation/devicetree/bindings/display/msm/hdmi.yaml | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/Documentation/devicetree/bindings/display/msm/hdmi.yaml b/Documentation/devicetree/bindings/display/msm/hdmi.yaml
index dfec6c3480f3..02d27ccad024 100644
--- a/Documentation/devicetree/bindings/display/msm/hdmi.yaml
+++ b/Documentation/devicetree/bindings/display/msm/hdmi.yaml
@@ -113,7 +113,7 @@ allOf:
- const: core
- const: master_iface
- const: slave_iface
- core-vcc-supplies: false
+ core-vcc-supply: false
- if:
properties:
@@ -136,7 +136,7 @@ allOf:
- const: core
- const: alt_iface
- const: extp
- hdmi-mux-supplies: false
+ hdmi-mux-supply: false
- if:
properties:
--
2.53.0
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply related [flat|nested] 38+ messages in thread
* [PATCH RFC/DO NOT MERGE 05/12] dt-bindings: display/msm: hdmi: Add Eliza HDMI TX
2026-08-28 14:04 ` Krzysztof Kozlowski
@ 2026-08-28 14:05 ` Krzysztof Kozlowski
-1 siblings, 0 replies; 38+ messages in thread
From: Krzysztof Kozlowski @ 2026-08-28 14:05 UTC (permalink / raw)
To: Rob Clark, Dmitry Baryshkov, Abhinav Kumar, Jessica Zhang,
Sean Paul, Marijn Suijten, David Airlie, Simona Vetter,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Vinod Koul, Neil Armstrong,
Manivannan Sadhasivam, Bjorn Andersson, Konrad Dybcio
Cc: linux-arm-msm, dri-devel, freedreno, linux-kernel, devicetree,
Krzysztof Kozlowski, Krzysztof Kozlowski, linux-phy
Qualcomm Eliza SoC comes with HDMI IP block, built on top of one
previously present in MSM8998. There are just a few differences in
hardware, mostly about handling clock reparenting, but more notable the
old binding looked incomplete, thus devices could not be considered
compatible. The QFPROM MMIO space is not really part of HDMI, thus do
not include it in the new device support.
Document also VDD IO supply, which is providing power to external 5V
elements, like HPD pull ups. This is not a suuply for internal HDMI
elements, thus it is valid for older variants as well.
Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski@oss.qualcomm.com>
---
.../devicetree/bindings/display/msm/hdmi.yaml | 67 ++++++++++++++-
.../bindings/display/msm/qcom,eliza-mdss.yaml | 96 +++++++++++++++++++++-
2 files changed, 158 insertions(+), 5 deletions(-)
diff --git a/Documentation/devicetree/bindings/display/msm/hdmi.yaml b/Documentation/devicetree/bindings/display/msm/hdmi.yaml
index 02d27ccad024..6adaa095b747 100644
--- a/Documentation/devicetree/bindings/display/msm/hdmi.yaml
+++ b/Documentation/devicetree/bindings/display/msm/hdmi.yaml
@@ -20,6 +20,7 @@ properties:
- qcom,hdmi-tx-8994
- qcom,hdmi-tx-8996
- qcom,hdmi-tx-8998
+ - qcom,eliza-hdmi-tx
clocks:
minItems: 1
@@ -35,10 +36,7 @@ properties:
reg-names:
minItems: 1
- items:
- - const: core_physical
- - const: qfprom_physical
- - const: hdcp_physical
+ maxItems: 3
interrupts:
maxItems: 1
@@ -62,10 +60,21 @@ properties:
core-vcc-supply:
description: phandle to VCC supply regulator
+ vddio-supply:
+ description: IO (e.g. HPD) supply
+
hpd-gpios:
maxItems: 1
description: hpd pin
+ operating-points-v2: true
+
+ opp-table:
+ type: object
+
+ power-domains:
+ maxItems: 1
+
'#sound-dai-cells':
const: 1
@@ -113,6 +122,12 @@ allOf:
- const: core
- const: master_iface
- const: slave_iface
+ reg-names:
+ minItems: 1
+ items:
+ - const: core_physical
+ - const: qfprom_physical
+ - const: hdcp_physical
core-vcc-supply: false
- if:
@@ -136,6 +151,12 @@ allOf:
- const: core
- const: alt_iface
- const: extp
+ reg-names:
+ minItems: 1
+ items:
+ - const: core_physical
+ - const: qfprom_physical
+ - const: hdcp_physical
hdmi-mux-supply: false
- if:
@@ -159,6 +180,44 @@ allOf:
- const: bus
- const: mnoc
- const: iface_mmss
+ reg-names:
+ minItems: 1
+ items:
+ - const: core_physical
+ - const: qfprom_physical
+ - const: hdcp_physical
+
+ - if:
+ properties:
+ compatible:
+ contains:
+ enum:
+ - qcom,qcom,eliza-hdmi-tx
+ then:
+ properties:
+ clocks:
+ minItems: 6
+ maxItems: 6
+ clock-names:
+ items:
+ - const: iface
+ - const: core
+ - const: extp
+ - const: phy_iface
+ - const: pll
+ - const: pixel_src
+ reg:
+ minItems: 2
+ maxItems: 2
+ reg-names:
+ items:
+ - const: core_physical
+ - const: hdcp_physical
+ hdmi-mux-supply: false
+
+ required:
+ - core-vcc-supply
+ - core-vdda-supply
additionalProperties: false
diff --git a/Documentation/devicetree/bindings/display/msm/qcom,eliza-mdss.yaml b/Documentation/devicetree/bindings/display/msm/qcom,eliza-mdss.yaml
index bd4ba91a171f..6f50f7106c8f 100644
--- a/Documentation/devicetree/bindings/display/msm/qcom,eliza-mdss.yaml
+++ b/Documentation/devicetree/bindings/display/msm/qcom,eliza-mdss.yaml
@@ -63,13 +63,22 @@ patternProperties:
contains:
const: qcom,eliza-dsi-ctrl
+ "^hdmi@[0-9a-f]+$":
+ type: object
+ additionalProperties: true
+ properties:
+ compatible:
+ const: qcom,eliza-hdmi-tx
+
"^phy@[0-9a-f]+$":
type: object
additionalProperties: true
properties:
compatible:
contains:
- const: qcom,eliza-dsi-phy-4nm
+ enum:
+ - qcom,eliza-dsi-phy-4nm
+ - qcom,eliza-hdmi-phy
required:
- compatible
@@ -79,6 +88,7 @@ unevaluatedProperties: false
examples:
- |
#include <dt-bindings/clock/qcom,dsi-phy-28nm.h>
+ #include <dt-bindings/clock/qcom,eliza-tcsr.h>
#include <dt-bindings/clock/qcom,rpmh.h>
#include <dt-bindings/interconnect/qcom,icc.h>
#include <dt-bindings/interrupt-controller/arm-gic.h>
@@ -405,6 +415,90 @@ examples:
vdds-supply = <&vreg_l2b>;
};
+ hdmi@aea0000 {
+ compatible = "qcom,eliza-hdmi-tx";
+ reg = <0x0aea0000 0x1000>,
+ <0x0aee0000 0x1000>;
+ reg-names = "core_physical",
+ "hdcp_physical";
+
+ interrupts-extended = <&mdss 8>;
+
+ clocks = <&disp_cc_mdss_hdmi_ahbm_clk>,
+ <&disp_cc_mdss_hdmi_app_clk>,
+ <&disp_cc_mdss_hdmi_pclk_clk>,
+ <&disp_cc_mdss_hdmi_intf_clk>,
+ <&mdss_hdmi_phy>,
+ <&disp_cc_mdss_hdmi_pclk_clk_src>;
+ clock-names = "iface",
+ "core",
+ "extp",
+ "phy_iface",
+ "pll",
+ "pixel_src";
+
+ operating-points-v2 = <&mdss_hdmi_opp_table>;
+
+ phys = <&mdss_hdmi_phy>;
+ power-domains = <&rpmhpd RPMHPD_CX>;
+ #sound-dai-cells = <1>;
+
+ core-vcc-supply = <&vreg_l2b>;
+ core-vdda-supply = <&vreg_l4b>;
+ vddio-supply = <&hdmi_5p0_reg>;
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ reg = <0>;
+
+ mdss_hdmi_in: endpoint {
+ remote-endpoint = <&dpu_intf4_out>;
+ };
+ };
+
+ port@1 {
+ reg = <1>;
+
+ mdss_hdmi_out: endpoint {
+ remote-endpoint = <&hdmi_0_connector_in>;
+ };
+ };
+ };
+
+ mdss_hdmi_opp_table: opp-table {
+ compatible = "operating-points-v2";
+
+ opp-150000000 {
+ opp-hz = /bits/ 64 <150000000>;
+ required-opps = <&rpmhpd_opp_low_svs_d1>;
+ };
+
+ opp-300000000 {
+ opp-hz = /bits/ 64 <300000000>;
+ required-opps = <&rpmhpd_opp_svs>;
+ };
+ };
+ };
+
+ mdss_hdmi_phy: phy@aea1000 {
+ compatible = "qcom,eliza-hdmi-phy";
+ reg = <0x0aea1000 0x1000>;
+
+ clocks = <&disp_cc_mdss_ahb_clk>,
+ <&tcsr TCSR_HDMI_CLKREF_EN>,
+ <&bi_tcxo_div2>;
+ clock-names = "iface",
+ "ref",
+ "xo";
+
+ #clock-cells = <0>;
+ #phy-cells = <0>;
+ power-domains = <&rpmhpd RPMHPD_CX>;
+ };
+
displayport-controller@af54000 {
compatible = "qcom,eliza-dp", "qcom,sm8650-dp";
reg = <0x0af54000 0x200>,
--
2.53.0
^ permalink raw reply related [flat|nested] 38+ messages in thread* [PATCH RFC/DO NOT MERGE 05/12] dt-bindings: display/msm: hdmi: Add Eliza HDMI TX
@ 2026-08-28 14:05 ` Krzysztof Kozlowski
0 siblings, 0 replies; 38+ messages in thread
From: Krzysztof Kozlowski @ 2026-08-28 14:05 UTC (permalink / raw)
To: Rob Clark, Dmitry Baryshkov, Abhinav Kumar, Jessica Zhang,
Sean Paul, Marijn Suijten, David Airlie, Simona Vetter,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Vinod Koul, Neil Armstrong,
Manivannan Sadhasivam, Bjorn Andersson, Konrad Dybcio
Cc: linux-arm-msm, dri-devel, freedreno, linux-kernel, devicetree,
Krzysztof Kozlowski, Krzysztof Kozlowski, linux-phy
Qualcomm Eliza SoC comes with HDMI IP block, built on top of one
previously present in MSM8998. There are just a few differences in
hardware, mostly about handling clock reparenting, but more notable the
old binding looked incomplete, thus devices could not be considered
compatible. The QFPROM MMIO space is not really part of HDMI, thus do
not include it in the new device support.
Document also VDD IO supply, which is providing power to external 5V
elements, like HPD pull ups. This is not a suuply for internal HDMI
elements, thus it is valid for older variants as well.
Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski@oss.qualcomm.com>
---
.../devicetree/bindings/display/msm/hdmi.yaml | 67 ++++++++++++++-
.../bindings/display/msm/qcom,eliza-mdss.yaml | 96 +++++++++++++++++++++-
2 files changed, 158 insertions(+), 5 deletions(-)
diff --git a/Documentation/devicetree/bindings/display/msm/hdmi.yaml b/Documentation/devicetree/bindings/display/msm/hdmi.yaml
index 02d27ccad024..6adaa095b747 100644
--- a/Documentation/devicetree/bindings/display/msm/hdmi.yaml
+++ b/Documentation/devicetree/bindings/display/msm/hdmi.yaml
@@ -20,6 +20,7 @@ properties:
- qcom,hdmi-tx-8994
- qcom,hdmi-tx-8996
- qcom,hdmi-tx-8998
+ - qcom,eliza-hdmi-tx
clocks:
minItems: 1
@@ -35,10 +36,7 @@ properties:
reg-names:
minItems: 1
- items:
- - const: core_physical
- - const: qfprom_physical
- - const: hdcp_physical
+ maxItems: 3
interrupts:
maxItems: 1
@@ -62,10 +60,21 @@ properties:
core-vcc-supply:
description: phandle to VCC supply regulator
+ vddio-supply:
+ description: IO (e.g. HPD) supply
+
hpd-gpios:
maxItems: 1
description: hpd pin
+ operating-points-v2: true
+
+ opp-table:
+ type: object
+
+ power-domains:
+ maxItems: 1
+
'#sound-dai-cells':
const: 1
@@ -113,6 +122,12 @@ allOf:
- const: core
- const: master_iface
- const: slave_iface
+ reg-names:
+ minItems: 1
+ items:
+ - const: core_physical
+ - const: qfprom_physical
+ - const: hdcp_physical
core-vcc-supply: false
- if:
@@ -136,6 +151,12 @@ allOf:
- const: core
- const: alt_iface
- const: extp
+ reg-names:
+ minItems: 1
+ items:
+ - const: core_physical
+ - const: qfprom_physical
+ - const: hdcp_physical
hdmi-mux-supply: false
- if:
@@ -159,6 +180,44 @@ allOf:
- const: bus
- const: mnoc
- const: iface_mmss
+ reg-names:
+ minItems: 1
+ items:
+ - const: core_physical
+ - const: qfprom_physical
+ - const: hdcp_physical
+
+ - if:
+ properties:
+ compatible:
+ contains:
+ enum:
+ - qcom,qcom,eliza-hdmi-tx
+ then:
+ properties:
+ clocks:
+ minItems: 6
+ maxItems: 6
+ clock-names:
+ items:
+ - const: iface
+ - const: core
+ - const: extp
+ - const: phy_iface
+ - const: pll
+ - const: pixel_src
+ reg:
+ minItems: 2
+ maxItems: 2
+ reg-names:
+ items:
+ - const: core_physical
+ - const: hdcp_physical
+ hdmi-mux-supply: false
+
+ required:
+ - core-vcc-supply
+ - core-vdda-supply
additionalProperties: false
diff --git a/Documentation/devicetree/bindings/display/msm/qcom,eliza-mdss.yaml b/Documentation/devicetree/bindings/display/msm/qcom,eliza-mdss.yaml
index bd4ba91a171f..6f50f7106c8f 100644
--- a/Documentation/devicetree/bindings/display/msm/qcom,eliza-mdss.yaml
+++ b/Documentation/devicetree/bindings/display/msm/qcom,eliza-mdss.yaml
@@ -63,13 +63,22 @@ patternProperties:
contains:
const: qcom,eliza-dsi-ctrl
+ "^hdmi@[0-9a-f]+$":
+ type: object
+ additionalProperties: true
+ properties:
+ compatible:
+ const: qcom,eliza-hdmi-tx
+
"^phy@[0-9a-f]+$":
type: object
additionalProperties: true
properties:
compatible:
contains:
- const: qcom,eliza-dsi-phy-4nm
+ enum:
+ - qcom,eliza-dsi-phy-4nm
+ - qcom,eliza-hdmi-phy
required:
- compatible
@@ -79,6 +88,7 @@ unevaluatedProperties: false
examples:
- |
#include <dt-bindings/clock/qcom,dsi-phy-28nm.h>
+ #include <dt-bindings/clock/qcom,eliza-tcsr.h>
#include <dt-bindings/clock/qcom,rpmh.h>
#include <dt-bindings/interconnect/qcom,icc.h>
#include <dt-bindings/interrupt-controller/arm-gic.h>
@@ -405,6 +415,90 @@ examples:
vdds-supply = <&vreg_l2b>;
};
+ hdmi@aea0000 {
+ compatible = "qcom,eliza-hdmi-tx";
+ reg = <0x0aea0000 0x1000>,
+ <0x0aee0000 0x1000>;
+ reg-names = "core_physical",
+ "hdcp_physical";
+
+ interrupts-extended = <&mdss 8>;
+
+ clocks = <&disp_cc_mdss_hdmi_ahbm_clk>,
+ <&disp_cc_mdss_hdmi_app_clk>,
+ <&disp_cc_mdss_hdmi_pclk_clk>,
+ <&disp_cc_mdss_hdmi_intf_clk>,
+ <&mdss_hdmi_phy>,
+ <&disp_cc_mdss_hdmi_pclk_clk_src>;
+ clock-names = "iface",
+ "core",
+ "extp",
+ "phy_iface",
+ "pll",
+ "pixel_src";
+
+ operating-points-v2 = <&mdss_hdmi_opp_table>;
+
+ phys = <&mdss_hdmi_phy>;
+ power-domains = <&rpmhpd RPMHPD_CX>;
+ #sound-dai-cells = <1>;
+
+ core-vcc-supply = <&vreg_l2b>;
+ core-vdda-supply = <&vreg_l4b>;
+ vddio-supply = <&hdmi_5p0_reg>;
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ reg = <0>;
+
+ mdss_hdmi_in: endpoint {
+ remote-endpoint = <&dpu_intf4_out>;
+ };
+ };
+
+ port@1 {
+ reg = <1>;
+
+ mdss_hdmi_out: endpoint {
+ remote-endpoint = <&hdmi_0_connector_in>;
+ };
+ };
+ };
+
+ mdss_hdmi_opp_table: opp-table {
+ compatible = "operating-points-v2";
+
+ opp-150000000 {
+ opp-hz = /bits/ 64 <150000000>;
+ required-opps = <&rpmhpd_opp_low_svs_d1>;
+ };
+
+ opp-300000000 {
+ opp-hz = /bits/ 64 <300000000>;
+ required-opps = <&rpmhpd_opp_svs>;
+ };
+ };
+ };
+
+ mdss_hdmi_phy: phy@aea1000 {
+ compatible = "qcom,eliza-hdmi-phy";
+ reg = <0x0aea1000 0x1000>;
+
+ clocks = <&disp_cc_mdss_ahb_clk>,
+ <&tcsr TCSR_HDMI_CLKREF_EN>,
+ <&bi_tcxo_div2>;
+ clock-names = "iface",
+ "ref",
+ "xo";
+
+ #clock-cells = <0>;
+ #phy-cells = <0>;
+ power-domains = <&rpmhpd RPMHPD_CX>;
+ };
+
displayport-controller@af54000 {
compatible = "qcom,eliza-dp", "qcom,sm8650-dp";
reg = <0x0af54000 0x200>,
--
2.53.0
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply related [flat|nested] 38+ messages in thread* Re: [PATCH RFC/DO NOT MERGE 05/12] dt-bindings: display/msm: hdmi: Add Eliza HDMI TX
2026-08-28 14:05 ` Krzysztof Kozlowski
@ 2026-08-28 14:12 ` sashiko-bot
-1 siblings, 0 replies; 38+ messages in thread
From: sashiko-bot @ 2026-08-28 14:12 UTC (permalink / raw)
To: Krzysztof Kozlowski
Cc: olteanv, robh, linux-phy, neil.armstrong, devicetree, dri-devel,
conor+dt, vkoul
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Medium] The conditional `if` block for the new Eliza HDMI TX device uses an incorrect compatible string with a duplicated vendor prefix ('qcom,qcom,eliza-hdmi-tx'), preventing the schema constraints from being applied.
--
commit 95836f68df5245b7dc121437b6c3df3442b5e4f8
Author: Krzysztof Kozlowski <krzysztof.kozlowski@oss.qualcomm.com>
dt-bindings: display/msm: hdmi: Add Eliza HDMI TX
Qualcomm Eliza SoC comes with HDMI IP block, built on top of one
previously present in MSM8998. There are just a few differences in
hardware, mostly about handling clock reparenting, but more notable the
old binding looked incomplete, thus devices could not be considered
compatible.
> diff --git a/Documentation/devicetree/bindings/display/msm/hdmi.yaml b/Documentation/devicetree/bindings/display/msm/hdmi.yaml
> index 02d27ccad0247..6adaa095b7473 100644
> --- a/Documentation/devicetree/bindings/display/msm/hdmi.yaml
> +++ b/Documentation/devicetree/bindings/display/msm/hdmi.yaml
[ ... ]
> @@ -159,6 +180,44 @@ allOf:
> - const: bus
> - const: mnoc
> - const: iface_mmss
> + reg-names:
> + minItems: 1
> + items:
> + - const: core_physical
> + - const: qfprom_physical
> + - const: hdcp_physical
> +
> + - if:
> + properties:
> + compatible:
> + contains:
> + enum:
> + - qcom,qcom,eliza-hdmi-tx
[Severity: Medium]
Does this compatible string contain a duplicated "qcom," vendor prefix?
It appears that this should be "qcom,eliza-hdmi-tx" to match the compatible
string defined in the properties section and the example. With the duplicated
prefix, this conditional block will not match, causing the constraints for the
clocks, reg, and required properties defined in the "then" block to be
bypassed during dtbs schema validation.
> + then:
> + properties:
> + clocks:
> + minItems: 6
> + maxItems: 6
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260828-drm-msm-hdmi-eliza-v1-0-67843277de17@oss.qualcomm.com?part=5
^ permalink raw reply [flat|nested] 38+ messages in thread* Re: [PATCH RFC/DO NOT MERGE 05/12] dt-bindings: display/msm: hdmi: Add Eliza HDMI TX
@ 2026-08-28 14:12 ` sashiko-bot
0 siblings, 0 replies; 38+ messages in thread
From: sashiko-bot @ 2026-08-28 14:12 UTC (permalink / raw)
To: Krzysztof Kozlowski
Cc: olteanv, robh, linux-phy, neil.armstrong, devicetree, dri-devel,
conor+dt, vkoul
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Medium] The conditional `if` block for the new Eliza HDMI TX device uses an incorrect compatible string with a duplicated vendor prefix ('qcom,qcom,eliza-hdmi-tx'), preventing the schema constraints from being applied.
--
commit 95836f68df5245b7dc121437b6c3df3442b5e4f8
Author: Krzysztof Kozlowski <krzysztof.kozlowski@oss.qualcomm.com>
dt-bindings: display/msm: hdmi: Add Eliza HDMI TX
Qualcomm Eliza SoC comes with HDMI IP block, built on top of one
previously present in MSM8998. There are just a few differences in
hardware, mostly about handling clock reparenting, but more notable the
old binding looked incomplete, thus devices could not be considered
compatible.
> diff --git a/Documentation/devicetree/bindings/display/msm/hdmi.yaml b/Documentation/devicetree/bindings/display/msm/hdmi.yaml
> index 02d27ccad0247..6adaa095b7473 100644
> --- a/Documentation/devicetree/bindings/display/msm/hdmi.yaml
> +++ b/Documentation/devicetree/bindings/display/msm/hdmi.yaml
[ ... ]
> @@ -159,6 +180,44 @@ allOf:
> - const: bus
> - const: mnoc
> - const: iface_mmss
> + reg-names:
> + minItems: 1
> + items:
> + - const: core_physical
> + - const: qfprom_physical
> + - const: hdcp_physical
> +
> + - if:
> + properties:
> + compatible:
> + contains:
> + enum:
> + - qcom,qcom,eliza-hdmi-tx
[Severity: Medium]
Does this compatible string contain a duplicated "qcom," vendor prefix?
It appears that this should be "qcom,eliza-hdmi-tx" to match the compatible
string defined in the properties section and the example. With the duplicated
prefix, this conditional block will not match, causing the constraints for the
clocks, reg, and required properties defined in the "then" block to be
bypassed during dtbs schema validation.
> + then:
> + properties:
> + clocks:
> + minItems: 6
> + maxItems: 6
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260828-drm-msm-hdmi-eliza-v1-0-67843277de17@oss.qualcomm.com?part=5
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply [flat|nested] 38+ messages in thread
* [PATCH RFC/DO NOT MERGE 06/12] dt-bindings: display/msm: eliza-hdmi-phy: Add Eliza HDMI PHY
2026-08-28 14:04 ` Krzysztof Kozlowski
@ 2026-08-28 14:05 ` Krzysztof Kozlowski
-1 siblings, 0 replies; 38+ messages in thread
From: Krzysztof Kozlowski @ 2026-08-28 14:05 UTC (permalink / raw)
To: Rob Clark, Dmitry Baryshkov, Abhinav Kumar, Jessica Zhang,
Sean Paul, Marijn Suijten, David Airlie, Simona Vetter,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Vinod Koul, Neil Armstrong,
Manivannan Sadhasivam, Bjorn Andersson, Konrad Dybcio
Cc: linux-arm-msm, dri-devel, freedreno, linux-kernel, devicetree,
Krzysztof Kozlowski, Krzysztof Kozlowski, linux-phy
Qualcomm Eliza SoC comes with an Synopsys HDMI phy, unlike previous
variants with HDMI support, thus no compatibility is expressed. There
is no documentation, except register list and register programming
sequence, and downstream sources do not point to any supplies.
Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski@oss.qualcomm.com>
---
.../bindings/phy/qcom,eliza-hdmi-phy.yaml | 71 ++++++++++++++++++++++
1 file changed, 71 insertions(+)
diff --git a/Documentation/devicetree/bindings/phy/qcom,eliza-hdmi-phy.yaml b/Documentation/devicetree/bindings/phy/qcom,eliza-hdmi-phy.yaml
new file mode 100644
index 000000000000..764fec0ef29b
--- /dev/null
+++ b/Documentation/devicetree/bindings/phy/qcom,eliza-hdmi-phy.yaml
@@ -0,0 +1,71 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+
+$id: http://devicetree.org/schemas/phy/qcom,eliza-hdmi-phy.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Qualcomm Eliza SoC HDMI phy (Synopsys)
+
+maintainers:
+ - Rob Clark <robdclark@gmail.com>
+ - Krzysztof Kozlowski <krzysztof.kozlowski@oss.qualcomm.com>
+
+properties:
+ compatible:
+ enum:
+ - qcom,eliza-hdmi-phy
+
+ reg:
+ maxItems: 1
+
+ clocks:
+ maxItems: 3
+
+ clock-names:
+ items:
+ - const: iface
+ - const: ref
+ - const: xo
+
+ power-domains:
+ maxItems: 1
+
+ '#clock-cells':
+ const: 0
+
+ '#phy-cells':
+ const: 0
+
+required:
+ - compatible
+ - reg
+ - clocks
+ - clock-names
+ - '#clock-cells'
+ - '#phy-cells'
+
+additionalProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/clock/qcom,eliza-dispcc.h>
+ #include <dt-bindings/clock/qcom,eliza-tcsr.h>
+ #include <dt-bindings/power/qcom,rpmhpd.h>
+
+ hdmi-phy@9a0600 {
+ compatible = "qcom,eliza-hdmi-phy";
+ reg = <0x0aea1000 0x1000>;
+
+ clocks = <&dispcc DISP_CC_MDSS_AHB_CLK>,
+ <&tcsr TCSR_HDMI_CLKREF_EN>,
+ <&bi_tcxo_div2>;
+ clock-names = "iface",
+ "ref",
+ "xo";
+
+ #clock-cells = <0>;
+ #phy-cells = <0>;
+
+ power-domains = <&rpmhpd RPMHPD_CX>;
+ };
--
2.53.0
^ permalink raw reply related [flat|nested] 38+ messages in thread* [PATCH RFC/DO NOT MERGE 06/12] dt-bindings: display/msm: eliza-hdmi-phy: Add Eliza HDMI PHY
@ 2026-08-28 14:05 ` Krzysztof Kozlowski
0 siblings, 0 replies; 38+ messages in thread
From: Krzysztof Kozlowski @ 2026-08-28 14:05 UTC (permalink / raw)
To: Rob Clark, Dmitry Baryshkov, Abhinav Kumar, Jessica Zhang,
Sean Paul, Marijn Suijten, David Airlie, Simona Vetter,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Vinod Koul, Neil Armstrong,
Manivannan Sadhasivam, Bjorn Andersson, Konrad Dybcio
Cc: linux-arm-msm, dri-devel, freedreno, linux-kernel, devicetree,
Krzysztof Kozlowski, Krzysztof Kozlowski, linux-phy
Qualcomm Eliza SoC comes with an Synopsys HDMI phy, unlike previous
variants with HDMI support, thus no compatibility is expressed. There
is no documentation, except register list and register programming
sequence, and downstream sources do not point to any supplies.
Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski@oss.qualcomm.com>
---
.../bindings/phy/qcom,eliza-hdmi-phy.yaml | 71 ++++++++++++++++++++++
1 file changed, 71 insertions(+)
diff --git a/Documentation/devicetree/bindings/phy/qcom,eliza-hdmi-phy.yaml b/Documentation/devicetree/bindings/phy/qcom,eliza-hdmi-phy.yaml
new file mode 100644
index 000000000000..764fec0ef29b
--- /dev/null
+++ b/Documentation/devicetree/bindings/phy/qcom,eliza-hdmi-phy.yaml
@@ -0,0 +1,71 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+
+$id: http://devicetree.org/schemas/phy/qcom,eliza-hdmi-phy.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Qualcomm Eliza SoC HDMI phy (Synopsys)
+
+maintainers:
+ - Rob Clark <robdclark@gmail.com>
+ - Krzysztof Kozlowski <krzysztof.kozlowski@oss.qualcomm.com>
+
+properties:
+ compatible:
+ enum:
+ - qcom,eliza-hdmi-phy
+
+ reg:
+ maxItems: 1
+
+ clocks:
+ maxItems: 3
+
+ clock-names:
+ items:
+ - const: iface
+ - const: ref
+ - const: xo
+
+ power-domains:
+ maxItems: 1
+
+ '#clock-cells':
+ const: 0
+
+ '#phy-cells':
+ const: 0
+
+required:
+ - compatible
+ - reg
+ - clocks
+ - clock-names
+ - '#clock-cells'
+ - '#phy-cells'
+
+additionalProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/clock/qcom,eliza-dispcc.h>
+ #include <dt-bindings/clock/qcom,eliza-tcsr.h>
+ #include <dt-bindings/power/qcom,rpmhpd.h>
+
+ hdmi-phy@9a0600 {
+ compatible = "qcom,eliza-hdmi-phy";
+ reg = <0x0aea1000 0x1000>;
+
+ clocks = <&dispcc DISP_CC_MDSS_AHB_CLK>,
+ <&tcsr TCSR_HDMI_CLKREF_EN>,
+ <&bi_tcxo_div2>;
+ clock-names = "iface",
+ "ref",
+ "xo";
+
+ #clock-cells = <0>;
+ #phy-cells = <0>;
+
+ power-domains = <&rpmhpd RPMHPD_CX>;
+ };
--
2.53.0
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply related [flat|nested] 38+ messages in thread* Re: [PATCH RFC/DO NOT MERGE 06/12] dt-bindings: display/msm: eliza-hdmi-phy: Add Eliza HDMI PHY
2026-08-28 14:05 ` Krzysztof Kozlowski
@ 2026-08-28 14:10 ` sashiko-bot
-1 siblings, 0 replies; 38+ messages in thread
From: sashiko-bot @ 2026-08-28 14:10 UTC (permalink / raw)
To: Krzysztof Kozlowski
Cc: robh, vkoul, conor+dt, devicetree, olteanv, dri-devel,
neil.armstrong, linux-phy
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Low] Devicetree unit address mismatch in schema example.
--
commit 2063c7e805b5b72143440af38f64d666c647dad5
Author: Krzysztof Kozlowski <krzysztof.kozlowski@oss.qualcomm.com>
dt-bindings: display/msm: eliza-hdmi-phy: Add Eliza HDMI PHY
This commit adds the device tree binding for the Synopsys HDMI PHY found on
the Qualcomm Eliza SoC. It documents the required properties and provides an
example device node.
> diff --git a/Documentation/devicetree/bindings/phy/qcom,eliza-hdmi-phy.yaml b/Documentation/devicetree/bindings/phy/qcom,eliza-hdmi-phy.yaml
> new file mode 100644
> index 0000000000000..764fec0ef29bf
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/phy/qcom,eliza-hdmi-phy.yaml
[ ... ]
> +examples:
> + - |
> + #include <dt-bindings/clock/qcom,eliza-dispcc.h>
> + #include <dt-bindings/clock/qcom,eliza-tcsr.h>
> + #include <dt-bindings/power/qcom,rpmhpd.h>
> +
> + hdmi-phy@9a0600 {
> + compatible = "qcom,eliza-hdmi-phy";
> + reg = <0x0aea1000 0x1000>;
[Severity: Low]
Does this unit address in the node name mismatch the first address in the
reg property?
Running make dt_binding_check will likely trigger a unit_address_vs_reg
warning regression because the node is named hdmi-phy@9a0600 but its reg
property sets the base address to 0x0aea1000.
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260828-drm-msm-hdmi-eliza-v1-0-67843277de17@oss.qualcomm.com?part=6
^ permalink raw reply [flat|nested] 38+ messages in thread* Re: [PATCH RFC/DO NOT MERGE 06/12] dt-bindings: display/msm: eliza-hdmi-phy: Add Eliza HDMI PHY
@ 2026-08-28 14:10 ` sashiko-bot
0 siblings, 0 replies; 38+ messages in thread
From: sashiko-bot @ 2026-08-28 14:10 UTC (permalink / raw)
To: Krzysztof Kozlowski
Cc: robh, vkoul, conor+dt, devicetree, olteanv, dri-devel,
neil.armstrong, linux-phy
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Low] Devicetree unit address mismatch in schema example.
--
commit 2063c7e805b5b72143440af38f64d666c647dad5
Author: Krzysztof Kozlowski <krzysztof.kozlowski@oss.qualcomm.com>
dt-bindings: display/msm: eliza-hdmi-phy: Add Eliza HDMI PHY
This commit adds the device tree binding for the Synopsys HDMI PHY found on
the Qualcomm Eliza SoC. It documents the required properties and provides an
example device node.
> diff --git a/Documentation/devicetree/bindings/phy/qcom,eliza-hdmi-phy.yaml b/Documentation/devicetree/bindings/phy/qcom,eliza-hdmi-phy.yaml
> new file mode 100644
> index 0000000000000..764fec0ef29bf
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/phy/qcom,eliza-hdmi-phy.yaml
[ ... ]
> +examples:
> + - |
> + #include <dt-bindings/clock/qcom,eliza-dispcc.h>
> + #include <dt-bindings/clock/qcom,eliza-tcsr.h>
> + #include <dt-bindings/power/qcom,rpmhpd.h>
> +
> + hdmi-phy@9a0600 {
> + compatible = "qcom,eliza-hdmi-phy";
> + reg = <0x0aea1000 0x1000>;
[Severity: Low]
Does this unit address in the node name mismatch the first address in the
reg property?
Running make dt_binding_check will likely trigger a unit_address_vs_reg
warning regression because the node is named hdmi-phy@9a0600 but its reg
property sets the base address to 0x0aea1000.
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260828-drm-msm-hdmi-eliza-v1-0-67843277de17@oss.qualcomm.com?part=6
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply [flat|nested] 38+ messages in thread
* [PATCH RFC/DO NOT MERGE 07/12] drm/msm/hdmi: Split PHY init from power up
2026-08-28 14:04 ` Krzysztof Kozlowski
@ 2026-08-28 14:05 ` Krzysztof Kozlowski
-1 siblings, 0 replies; 38+ messages in thread
From: Krzysztof Kozlowski @ 2026-08-28 14:05 UTC (permalink / raw)
To: Rob Clark, Dmitry Baryshkov, Abhinav Kumar, Jessica Zhang,
Sean Paul, Marijn Suijten, David Airlie, Simona Vetter,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Vinod Koul, Neil Armstrong,
Manivannan Sadhasivam, Bjorn Andersson, Konrad Dybcio
Cc: linux-arm-msm, dri-devel, freedreno, linux-kernel, devicetree,
Krzysztof Kozlowski, Krzysztof Kozlowski, linux-phy
Future Eliza SoC HDMI PHY and HDMI block require certain clock
operations, like reparenting pixclok to HDMI PHY PLL, once PHY is
initialized. Similarly to what is happening on Qualcomm MSM DSI blocks
since SM8750.
Rework and split the HDMI msm_hdmi_power_on() into smaller steps:
1. Leave untouched logic related to runtime PM (power on the domain).
This is done only once, guarded by "if (hdmi->power_on) {" condition,
2. During every msm_hdmi_bridge_atomic_pre_enable(), initialize the HDMI
PHY with new msm_hdmi_phy_init() as it was previously powered down.
Currently no-op for all the PHYs,
3. Similarly, for every enable prepare and set rate of HDMI pixclock
(extp_clk). This will also reparent the pixclock to HDMI PHY PLL
later and should happen after the HDMI PHY is initialized (point 2
above).
Commit should have no practical impact on existing devices.
Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski@oss.qualcomm.com>
---
drivers/gpu/drm/msm/hdmi/hdmi.h | 4 ++++
drivers/gpu/drm/msm/hdmi/hdmi_bridge.c | 30 +++++++++++++++++++++++++-----
drivers/gpu/drm/msm/hdmi/hdmi_phy.c | 16 ++++++++++++++++
3 files changed, 45 insertions(+), 5 deletions(-)
diff --git a/drivers/gpu/drm/msm/hdmi/hdmi.h b/drivers/gpu/drm/msm/hdmi/hdmi.h
index 436d4f9fe346..306b988bca72 100644
--- a/drivers/gpu/drm/msm/hdmi/hdmi.h
+++ b/drivers/gpu/drm/msm/hdmi/hdmi.h
@@ -151,6 +151,8 @@ enum hdmi_phy_type {
struct hdmi_phy_cfg {
enum hdmi_phy_type type;
+ void (*init)(struct hdmi_phy *phy, unsigned long pixclock);
+ void (*deinit)(struct hdmi_phy *phy);
void (*powerup)(struct hdmi_phy *phy, unsigned long pixclock);
void (*powerdown)(struct hdmi_phy *phy);
const char * const *reg_names;
@@ -186,6 +188,8 @@ static inline u32 hdmi_phy_read(struct hdmi_phy *phy, u32 reg)
int msm_hdmi_phy_resource_enable(struct hdmi_phy *phy);
void msm_hdmi_phy_resource_disable(struct hdmi_phy *phy);
+void msm_hdmi_phy_init(struct hdmi_phy *phy, unsigned long pixclock);
+void msm_hdmi_phy_deinit(struct hdmi_phy *phy);
void msm_hdmi_phy_powerup(struct hdmi_phy *phy, unsigned long pixclock);
void msm_hdmi_phy_powerdown(struct hdmi_phy *phy);
void __init msm_hdmi_phy_driver_register(void);
diff --git a/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c b/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c
index a5f891661ea3..d0e3b27644fe 100644
--- a/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c
+++ b/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c
@@ -14,14 +14,20 @@
#include "hdmi.h"
static void msm_hdmi_power_on(struct drm_bridge *bridge)
+{
+ struct hdmi_bridge *hdmi_bridge = to_hdmi_bridge(bridge);
+ struct hdmi *hdmi = hdmi_bridge->hdmi;
+
+ pm_runtime_resume_and_get(&hdmi->pdev->dev);
+}
+
+static void msm_hdmi_clk_prepare(struct drm_bridge *bridge)
{
struct drm_device *dev = bridge->dev;
struct hdmi_bridge *hdmi_bridge = to_hdmi_bridge(bridge);
struct hdmi *hdmi = hdmi_bridge->hdmi;
int ret;
- pm_runtime_resume_and_get(&hdmi->pdev->dev);
-
if (hdmi->extp_clk) {
DBG("pixclock: %lu", hdmi->pixclock);
ret = clk_set_rate(hdmi->extp_clk, hdmi->pixclock);
@@ -44,10 +50,16 @@ static void power_off(struct drm_bridge *bridge)
*/
mdelay(16 + 4);
+ pm_runtime_put(&hdmi->pdev->dev);
+}
+
+static void msm_hdmi_clk_unprepare(struct drm_bridge *bridge)
+{
+ struct hdmi_bridge *hdmi_bridge = to_hdmi_bridge(bridge);
+ struct hdmi *hdmi = hdmi_bridge->hdmi;
+
if (hdmi->extp_clk)
clk_disable_unprepare(hdmi->extp_clk);
-
- pm_runtime_put(&hdmi->pdev->dev);
}
#define AVI_IFRAME_LINE_NUMBER 1
@@ -300,8 +312,14 @@ static void msm_hdmi_bridge_atomic_pre_enable(struct drm_bridge *bridge,
drm_atomic_helper_connector_hdmi_update_infoframes(connector, state);
+ msm_hdmi_phy_init(phy, hdmi->pixclock);
+ /*
+ * Re-parent clocks and set rates once phy is properly initialized.
+ * OTOH, TX DATA on the phy should not be enabled before clocks are
+ * configured.
+ */
+ msm_hdmi_clk_prepare(bridge);
msm_hdmi_phy_powerup(phy, hdmi->pixclock);
-
msm_hdmi_set_mode(hdmi, true);
if (hdmi->hdcp_ctrl)
@@ -325,6 +343,8 @@ static void msm_hdmi_bridge_atomic_post_disable(struct drm_bridge *bridge,
msm_hdmi_set_mode(hdmi, hdmi->hpd_enabled);
msm_hdmi_phy_powerdown(phy);
+ msm_hdmi_clk_unprepare(bridge);
+ msm_hdmi_phy_deinit(phy);
if (hdmi->power_on) {
power_off(bridge);
diff --git a/drivers/gpu/drm/msm/hdmi/hdmi_phy.c b/drivers/gpu/drm/msm/hdmi/hdmi_phy.c
index eb1088755cb3..8ce87d9adf74 100644
--- a/drivers/gpu/drm/msm/hdmi/hdmi_phy.c
+++ b/drivers/gpu/drm/msm/hdmi/hdmi_phy.c
@@ -94,6 +94,22 @@ void msm_hdmi_phy_resource_disable(struct hdmi_phy *phy)
pm_runtime_put_sync(dev);
}
+void msm_hdmi_phy_init(struct hdmi_phy *phy, unsigned long pixclock)
+{
+ if (!phy || !phy->cfg->init)
+ return;
+
+ phy->cfg->init(phy, pixclock);
+}
+
+void msm_hdmi_phy_deinit(struct hdmi_phy *phy)
+{
+ if (!phy || !phy->cfg->deinit)
+ return;
+
+ phy->cfg->deinit(phy);
+}
+
void msm_hdmi_phy_powerup(struct hdmi_phy *phy, unsigned long pixclock)
{
if (!phy || !phy->cfg->powerup)
--
2.53.0
^ permalink raw reply related [flat|nested] 38+ messages in thread* [PATCH RFC/DO NOT MERGE 07/12] drm/msm/hdmi: Split PHY init from power up
@ 2026-08-28 14:05 ` Krzysztof Kozlowski
0 siblings, 0 replies; 38+ messages in thread
From: Krzysztof Kozlowski @ 2026-08-28 14:05 UTC (permalink / raw)
To: Rob Clark, Dmitry Baryshkov, Abhinav Kumar, Jessica Zhang,
Sean Paul, Marijn Suijten, David Airlie, Simona Vetter,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Vinod Koul, Neil Armstrong,
Manivannan Sadhasivam, Bjorn Andersson, Konrad Dybcio
Cc: linux-arm-msm, dri-devel, freedreno, linux-kernel, devicetree,
Krzysztof Kozlowski, Krzysztof Kozlowski, linux-phy
Future Eliza SoC HDMI PHY and HDMI block require certain clock
operations, like reparenting pixclok to HDMI PHY PLL, once PHY is
initialized. Similarly to what is happening on Qualcomm MSM DSI blocks
since SM8750.
Rework and split the HDMI msm_hdmi_power_on() into smaller steps:
1. Leave untouched logic related to runtime PM (power on the domain).
This is done only once, guarded by "if (hdmi->power_on) {" condition,
2. During every msm_hdmi_bridge_atomic_pre_enable(), initialize the HDMI
PHY with new msm_hdmi_phy_init() as it was previously powered down.
Currently no-op for all the PHYs,
3. Similarly, for every enable prepare and set rate of HDMI pixclock
(extp_clk). This will also reparent the pixclock to HDMI PHY PLL
later and should happen after the HDMI PHY is initialized (point 2
above).
Commit should have no practical impact on existing devices.
Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski@oss.qualcomm.com>
---
drivers/gpu/drm/msm/hdmi/hdmi.h | 4 ++++
drivers/gpu/drm/msm/hdmi/hdmi_bridge.c | 30 +++++++++++++++++++++++++-----
drivers/gpu/drm/msm/hdmi/hdmi_phy.c | 16 ++++++++++++++++
3 files changed, 45 insertions(+), 5 deletions(-)
diff --git a/drivers/gpu/drm/msm/hdmi/hdmi.h b/drivers/gpu/drm/msm/hdmi/hdmi.h
index 436d4f9fe346..306b988bca72 100644
--- a/drivers/gpu/drm/msm/hdmi/hdmi.h
+++ b/drivers/gpu/drm/msm/hdmi/hdmi.h
@@ -151,6 +151,8 @@ enum hdmi_phy_type {
struct hdmi_phy_cfg {
enum hdmi_phy_type type;
+ void (*init)(struct hdmi_phy *phy, unsigned long pixclock);
+ void (*deinit)(struct hdmi_phy *phy);
void (*powerup)(struct hdmi_phy *phy, unsigned long pixclock);
void (*powerdown)(struct hdmi_phy *phy);
const char * const *reg_names;
@@ -186,6 +188,8 @@ static inline u32 hdmi_phy_read(struct hdmi_phy *phy, u32 reg)
int msm_hdmi_phy_resource_enable(struct hdmi_phy *phy);
void msm_hdmi_phy_resource_disable(struct hdmi_phy *phy);
+void msm_hdmi_phy_init(struct hdmi_phy *phy, unsigned long pixclock);
+void msm_hdmi_phy_deinit(struct hdmi_phy *phy);
void msm_hdmi_phy_powerup(struct hdmi_phy *phy, unsigned long pixclock);
void msm_hdmi_phy_powerdown(struct hdmi_phy *phy);
void __init msm_hdmi_phy_driver_register(void);
diff --git a/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c b/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c
index a5f891661ea3..d0e3b27644fe 100644
--- a/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c
+++ b/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c
@@ -14,14 +14,20 @@
#include "hdmi.h"
static void msm_hdmi_power_on(struct drm_bridge *bridge)
+{
+ struct hdmi_bridge *hdmi_bridge = to_hdmi_bridge(bridge);
+ struct hdmi *hdmi = hdmi_bridge->hdmi;
+
+ pm_runtime_resume_and_get(&hdmi->pdev->dev);
+}
+
+static void msm_hdmi_clk_prepare(struct drm_bridge *bridge)
{
struct drm_device *dev = bridge->dev;
struct hdmi_bridge *hdmi_bridge = to_hdmi_bridge(bridge);
struct hdmi *hdmi = hdmi_bridge->hdmi;
int ret;
- pm_runtime_resume_and_get(&hdmi->pdev->dev);
-
if (hdmi->extp_clk) {
DBG("pixclock: %lu", hdmi->pixclock);
ret = clk_set_rate(hdmi->extp_clk, hdmi->pixclock);
@@ -44,10 +50,16 @@ static void power_off(struct drm_bridge *bridge)
*/
mdelay(16 + 4);
+ pm_runtime_put(&hdmi->pdev->dev);
+}
+
+static void msm_hdmi_clk_unprepare(struct drm_bridge *bridge)
+{
+ struct hdmi_bridge *hdmi_bridge = to_hdmi_bridge(bridge);
+ struct hdmi *hdmi = hdmi_bridge->hdmi;
+
if (hdmi->extp_clk)
clk_disable_unprepare(hdmi->extp_clk);
-
- pm_runtime_put(&hdmi->pdev->dev);
}
#define AVI_IFRAME_LINE_NUMBER 1
@@ -300,8 +312,14 @@ static void msm_hdmi_bridge_atomic_pre_enable(struct drm_bridge *bridge,
drm_atomic_helper_connector_hdmi_update_infoframes(connector, state);
+ msm_hdmi_phy_init(phy, hdmi->pixclock);
+ /*
+ * Re-parent clocks and set rates once phy is properly initialized.
+ * OTOH, TX DATA on the phy should not be enabled before clocks are
+ * configured.
+ */
+ msm_hdmi_clk_prepare(bridge);
msm_hdmi_phy_powerup(phy, hdmi->pixclock);
-
msm_hdmi_set_mode(hdmi, true);
if (hdmi->hdcp_ctrl)
@@ -325,6 +343,8 @@ static void msm_hdmi_bridge_atomic_post_disable(struct drm_bridge *bridge,
msm_hdmi_set_mode(hdmi, hdmi->hpd_enabled);
msm_hdmi_phy_powerdown(phy);
+ msm_hdmi_clk_unprepare(bridge);
+ msm_hdmi_phy_deinit(phy);
if (hdmi->power_on) {
power_off(bridge);
diff --git a/drivers/gpu/drm/msm/hdmi/hdmi_phy.c b/drivers/gpu/drm/msm/hdmi/hdmi_phy.c
index eb1088755cb3..8ce87d9adf74 100644
--- a/drivers/gpu/drm/msm/hdmi/hdmi_phy.c
+++ b/drivers/gpu/drm/msm/hdmi/hdmi_phy.c
@@ -94,6 +94,22 @@ void msm_hdmi_phy_resource_disable(struct hdmi_phy *phy)
pm_runtime_put_sync(dev);
}
+void msm_hdmi_phy_init(struct hdmi_phy *phy, unsigned long pixclock)
+{
+ if (!phy || !phy->cfg->init)
+ return;
+
+ phy->cfg->init(phy, pixclock);
+}
+
+void msm_hdmi_phy_deinit(struct hdmi_phy *phy)
+{
+ if (!phy || !phy->cfg->deinit)
+ return;
+
+ phy->cfg->deinit(phy);
+}
+
void msm_hdmi_phy_powerup(struct hdmi_phy *phy, unsigned long pixclock)
{
if (!phy || !phy->cfg->powerup)
--
2.53.0
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply related [flat|nested] 38+ messages in thread* Re: [PATCH RFC/DO NOT MERGE 07/12] drm/msm/hdmi: Split PHY init from power up
2026-08-28 14:05 ` Krzysztof Kozlowski
@ 2026-08-28 14:22 ` sashiko-bot
-1 siblings, 0 replies; 38+ messages in thread
From: sashiko-bot @ 2026-08-28 14:22 UTC (permalink / raw)
To: Krzysztof Kozlowski
Cc: robh, devicetree, dri-devel, olteanv, vkoul, conor+dt,
neil.armstrong, linux-phy
Thank you for your contribution! Sashiko AI review found 4 potential issue(s) to consider:
New issues:
- [High] The HDMI pixel clock is disabled before the 20ms vblank delay, breaking the intended shutdown sequence and risking hardware hangs.
- [Medium] Unconditional clock disable and PHY deinitialization can cause unbalanced clock teardown or CCF warnings.
Pre-existing issues:
- [High] Hardware registers are accessed after dropping the runtime PM reference.
- [High] Missing return value checks for hardware initialization functions, such as `pm_runtime_resume_and_get()` and `msm_hdmi_phy_resource_enable()`.
--
commit 821f230494b55344c7aaf6bb73ba3e416ff8cb25
Author: Krzysztof Kozlowski <krzysztof.kozlowski@oss.qualcomm.com>
Subject: drm/msm/hdmi: Split PHY init from power up
This commit reworks and splits the msm_hdmi_power_on() sequence into
smaller steps. It separates out runtime PM enablement, introduces a new
msm_hdmi_phy_init() step, and splits clock preparation and reparenting into
msm_hdmi_clk_prepare() which runs after PHY initialization.
> diff --git a/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c b/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c
> index 9d027f96ae243..ead6ba3b8192a 100644
> --- a/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c
> +++ b/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c
> @@ -15,12 +15,18 @@
>
> static void msm_hdmi_power_on(struct drm_bridge *bridge)
> {
> - struct drm_device *dev = bridge->dev;
> struct hdmi_bridge *hdmi_bridge = to_hdmi_bridge(bridge);
> struct hdmi *hdmi = hdmi_bridge->hdmi;
> - int ret;
>
> pm_runtime_resume_and_get(&hdmi->pdev->dev);
[Severity: High]
This is a pre-existing issue, but is it safe to ignore the return value of
pm_runtime_resume_and_get() here?
If it fails, the power domain is not enabled and the PM usage count is not
incremented. Proceeding to access hardware registers will cause an SError
or panic, and the subsequent pm_runtime_put() in the disable path will
underflow the usage count.
> +}
[ ... ]
> @@ -341,6 +359,8 @@ static void msm_hdmi_bridge_atomic_post_disable(struct drm_bridge *bridge,
> msm_hdmi_set_mode(hdmi, hdmi->hpd_enabled);
>
> msm_hdmi_phy_powerdown(phy);
> + msm_hdmi_clk_unprepare(bridge);
> + msm_hdmi_phy_deinit(phy);
>
> if (hdmi->power_on) {
[Severity: Medium]
Can this unconditional clock disable and PHY deinitialization cause
unbalanced clock teardown or Common Clock Framework warnings?
If atomic_post_disable() is called to sanitize the hardware during initial
modeset (where hdmi->power_on is false), msm_hdmi_clk_unprepare() will be
called without a matching prior enable. This bypasses the state tracking
guard and triggers a WARN in the CCF.
[Severity: High]
Does this code disable the HDMI pixel clock before the 20ms vblank delay
inside power_off()?
Because msm_hdmi_clk_unprepare() is called before power_off(), the
pipeline is frozen mid-frame before the delay executes. Powering down a
frozen display controller mid-frame frequently causes system-wide bus hangs
(AXI bus stalls) on ARM SoCs.
> power_off(bridge);
[Severity: High]
This is a pre-existing issue, but can the code following power_off() access
hardware registers after the runtime PM reference has been dropped?
The power_off() function drops the runtime PM reference via
pm_runtime_put(). Immediately after, msm_hdmi_bridge_atomic_post_disable()
calls msm_hdmi_audio_update() if the display info is HDMI.
This accesses MMIO registers via hdmi_read() and hdmi_write(). It risks an
asynchronous SError (kernel panic) if the power domain is turned off in the
background before the accesses complete.
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260828-drm-msm-hdmi-eliza-v1-0-67843277de17@oss.qualcomm.com?part=7
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply [flat|nested] 38+ messages in thread* Re: [PATCH RFC/DO NOT MERGE 07/12] drm/msm/hdmi: Split PHY init from power up
@ 2026-08-28 14:22 ` sashiko-bot
0 siblings, 0 replies; 38+ messages in thread
From: sashiko-bot @ 2026-08-28 14:22 UTC (permalink / raw)
To: Krzysztof Kozlowski
Cc: robh, devicetree, dri-devel, olteanv, vkoul, conor+dt,
neil.armstrong, linux-phy
Thank you for your contribution! Sashiko AI review found 4 potential issue(s) to consider:
New issues:
- [High] The HDMI pixel clock is disabled before the 20ms vblank delay, breaking the intended shutdown sequence and risking hardware hangs.
- [Medium] Unconditional clock disable and PHY deinitialization can cause unbalanced clock teardown or CCF warnings.
Pre-existing issues:
- [High] Hardware registers are accessed after dropping the runtime PM reference.
- [High] Missing return value checks for hardware initialization functions, such as `pm_runtime_resume_and_get()` and `msm_hdmi_phy_resource_enable()`.
--
commit 821f230494b55344c7aaf6bb73ba3e416ff8cb25
Author: Krzysztof Kozlowski <krzysztof.kozlowski@oss.qualcomm.com>
Subject: drm/msm/hdmi: Split PHY init from power up
This commit reworks and splits the msm_hdmi_power_on() sequence into
smaller steps. It separates out runtime PM enablement, introduces a new
msm_hdmi_phy_init() step, and splits clock preparation and reparenting into
msm_hdmi_clk_prepare() which runs after PHY initialization.
> diff --git a/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c b/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c
> index 9d027f96ae243..ead6ba3b8192a 100644
> --- a/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c
> +++ b/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c
> @@ -15,12 +15,18 @@
>
> static void msm_hdmi_power_on(struct drm_bridge *bridge)
> {
> - struct drm_device *dev = bridge->dev;
> struct hdmi_bridge *hdmi_bridge = to_hdmi_bridge(bridge);
> struct hdmi *hdmi = hdmi_bridge->hdmi;
> - int ret;
>
> pm_runtime_resume_and_get(&hdmi->pdev->dev);
[Severity: High]
This is a pre-existing issue, but is it safe to ignore the return value of
pm_runtime_resume_and_get() here?
If it fails, the power domain is not enabled and the PM usage count is not
incremented. Proceeding to access hardware registers will cause an SError
or panic, and the subsequent pm_runtime_put() in the disable path will
underflow the usage count.
> +}
[ ... ]
> @@ -341,6 +359,8 @@ static void msm_hdmi_bridge_atomic_post_disable(struct drm_bridge *bridge,
> msm_hdmi_set_mode(hdmi, hdmi->hpd_enabled);
>
> msm_hdmi_phy_powerdown(phy);
> + msm_hdmi_clk_unprepare(bridge);
> + msm_hdmi_phy_deinit(phy);
>
> if (hdmi->power_on) {
[Severity: Medium]
Can this unconditional clock disable and PHY deinitialization cause
unbalanced clock teardown or Common Clock Framework warnings?
If atomic_post_disable() is called to sanitize the hardware during initial
modeset (where hdmi->power_on is false), msm_hdmi_clk_unprepare() will be
called without a matching prior enable. This bypasses the state tracking
guard and triggers a WARN in the CCF.
[Severity: High]
Does this code disable the HDMI pixel clock before the 20ms vblank delay
inside power_off()?
Because msm_hdmi_clk_unprepare() is called before power_off(), the
pipeline is frozen mid-frame before the delay executes. Powering down a
frozen display controller mid-frame frequently causes system-wide bus hangs
(AXI bus stalls) on ARM SoCs.
> power_off(bridge);
[Severity: High]
This is a pre-existing issue, but can the code following power_off() access
hardware registers after the runtime PM reference has been dropped?
The power_off() function drops the runtime PM reference via
pm_runtime_put(). Immediately after, msm_hdmi_bridge_atomic_post_disable()
calls msm_hdmi_audio_update() if the display info is HDMI.
This accesses MMIO registers via hdmi_read() and hdmi_write(). It risks an
asynchronous SError (kernel panic) if the power domain is turned off in the
background before the accesses complete.
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260828-drm-msm-hdmi-eliza-v1-0-67843277de17@oss.qualcomm.com?part=7
^ permalink raw reply [flat|nested] 38+ messages in thread
* [PATCH RFC/DO NOT MERGE 08/12] drm/msm/hdmi: Add support for PM OPP table
2026-08-28 14:04 ` Krzysztof Kozlowski
@ 2026-08-28 14:05 ` Krzysztof Kozlowski
-1 siblings, 0 replies; 38+ messages in thread
From: Krzysztof Kozlowski @ 2026-08-28 14:05 UTC (permalink / raw)
To: Rob Clark, Dmitry Baryshkov, Abhinav Kumar, Jessica Zhang,
Sean Paul, Marijn Suijten, David Airlie, Simona Vetter,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Vinod Koul, Neil Armstrong,
Manivannan Sadhasivam, Bjorn Andersson, Konrad Dybcio
Cc: linux-arm-msm, dri-devel, freedreno, linux-kernel, devicetree,
Krzysztof Kozlowski, Krzysztof Kozlowski, linux-phy
Allow scaling the domain rails with PM OPP, which uses the pixclock
("extp"). This allows proper votes depending on requested HDMI pixel
rate.
Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski@oss.qualcomm.com>
---
drivers/gpu/drm/msm/hdmi/hdmi.c | 8 ++++++++
drivers/gpu/drm/msm/hdmi/hdmi_bridge.c | 10 +++++++---
2 files changed, 15 insertions(+), 3 deletions(-)
diff --git a/drivers/gpu/drm/msm/hdmi/hdmi.c b/drivers/gpu/drm/msm/hdmi/hdmi.c
index 474006084633..c46f30063f14 100644
--- a/drivers/gpu/drm/msm/hdmi/hdmi.c
+++ b/drivers/gpu/drm/msm/hdmi/hdmi.c
@@ -368,6 +368,14 @@ static int msm_hdmi_dev_probe(struct platform_device *pdev)
goto err_put_bridge;
}
+ ret = devm_pm_opp_set_clkname(dev, "extp");
+ if (ret)
+ return ret;
+
+ ret = devm_pm_opp_of_add_table(dev);
+ if (ret && ret != -ENODEV)
+ return dev_err_probe(dev, ret, "invalid OPP table in device tree\n");
+
if (!hdmi->hpd_gpiod)
DBG("failed to get HPD gpio");
diff --git a/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c b/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c
index d0e3b27644fe..621083a97b37 100644
--- a/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c
+++ b/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c
@@ -5,6 +5,7 @@
*/
#include <linux/delay.h>
+#include <linux/pm_opp.h>
#include <drm/drm_bridge_connector.h>
#include <drm/drm_edid.h>
#include <drm/display/drm_hdmi_helper.h>
@@ -30,9 +31,10 @@ static void msm_hdmi_clk_prepare(struct drm_bridge *bridge)
if (hdmi->extp_clk) {
DBG("pixclock: %lu", hdmi->pixclock);
- ret = clk_set_rate(hdmi->extp_clk, hdmi->pixclock);
+
+ ret = dev_pm_opp_set_rate(&hdmi->pdev->dev, hdmi->pixclock);
if (ret)
- DRM_DEV_ERROR(dev->dev, "failed to set extp clk rate: %d\n", ret);
+ DRM_DEV_ERROR(dev->dev, "failed to set OPP rate: %d\n", ret);
ret = clk_prepare_enable(hdmi->extp_clk);
if (ret)
@@ -58,8 +60,10 @@ static void msm_hdmi_clk_unprepare(struct drm_bridge *bridge)
struct hdmi_bridge *hdmi_bridge = to_hdmi_bridge(bridge);
struct hdmi *hdmi = hdmi_bridge->hdmi;
- if (hdmi->extp_clk)
+ if (hdmi->extp_clk) {
clk_disable_unprepare(hdmi->extp_clk);
+ dev_pm_opp_set_rate(&hdmi->pdev->dev, 0);
+ }
}
#define AVI_IFRAME_LINE_NUMBER 1
--
2.53.0
^ permalink raw reply related [flat|nested] 38+ messages in thread* [PATCH RFC/DO NOT MERGE 08/12] drm/msm/hdmi: Add support for PM OPP table
@ 2026-08-28 14:05 ` Krzysztof Kozlowski
0 siblings, 0 replies; 38+ messages in thread
From: Krzysztof Kozlowski @ 2026-08-28 14:05 UTC (permalink / raw)
To: Rob Clark, Dmitry Baryshkov, Abhinav Kumar, Jessica Zhang,
Sean Paul, Marijn Suijten, David Airlie, Simona Vetter,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Vinod Koul, Neil Armstrong,
Manivannan Sadhasivam, Bjorn Andersson, Konrad Dybcio
Cc: linux-arm-msm, dri-devel, freedreno, linux-kernel, devicetree,
Krzysztof Kozlowski, Krzysztof Kozlowski, linux-phy
Allow scaling the domain rails with PM OPP, which uses the pixclock
("extp"). This allows proper votes depending on requested HDMI pixel
rate.
Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski@oss.qualcomm.com>
---
drivers/gpu/drm/msm/hdmi/hdmi.c | 8 ++++++++
drivers/gpu/drm/msm/hdmi/hdmi_bridge.c | 10 +++++++---
2 files changed, 15 insertions(+), 3 deletions(-)
diff --git a/drivers/gpu/drm/msm/hdmi/hdmi.c b/drivers/gpu/drm/msm/hdmi/hdmi.c
index 474006084633..c46f30063f14 100644
--- a/drivers/gpu/drm/msm/hdmi/hdmi.c
+++ b/drivers/gpu/drm/msm/hdmi/hdmi.c
@@ -368,6 +368,14 @@ static int msm_hdmi_dev_probe(struct platform_device *pdev)
goto err_put_bridge;
}
+ ret = devm_pm_opp_set_clkname(dev, "extp");
+ if (ret)
+ return ret;
+
+ ret = devm_pm_opp_of_add_table(dev);
+ if (ret && ret != -ENODEV)
+ return dev_err_probe(dev, ret, "invalid OPP table in device tree\n");
+
if (!hdmi->hpd_gpiod)
DBG("failed to get HPD gpio");
diff --git a/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c b/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c
index d0e3b27644fe..621083a97b37 100644
--- a/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c
+++ b/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c
@@ -5,6 +5,7 @@
*/
#include <linux/delay.h>
+#include <linux/pm_opp.h>
#include <drm/drm_bridge_connector.h>
#include <drm/drm_edid.h>
#include <drm/display/drm_hdmi_helper.h>
@@ -30,9 +31,10 @@ static void msm_hdmi_clk_prepare(struct drm_bridge *bridge)
if (hdmi->extp_clk) {
DBG("pixclock: %lu", hdmi->pixclock);
- ret = clk_set_rate(hdmi->extp_clk, hdmi->pixclock);
+
+ ret = dev_pm_opp_set_rate(&hdmi->pdev->dev, hdmi->pixclock);
if (ret)
- DRM_DEV_ERROR(dev->dev, "failed to set extp clk rate: %d\n", ret);
+ DRM_DEV_ERROR(dev->dev, "failed to set OPP rate: %d\n", ret);
ret = clk_prepare_enable(hdmi->extp_clk);
if (ret)
@@ -58,8 +60,10 @@ static void msm_hdmi_clk_unprepare(struct drm_bridge *bridge)
struct hdmi_bridge *hdmi_bridge = to_hdmi_bridge(bridge);
struct hdmi *hdmi = hdmi_bridge->hdmi;
- if (hdmi->extp_clk)
+ if (hdmi->extp_clk) {
clk_disable_unprepare(hdmi->extp_clk);
+ dev_pm_opp_set_rate(&hdmi->pdev->dev, 0);
+ }
}
#define AVI_IFRAME_LINE_NUMBER 1
--
2.53.0
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply related [flat|nested] 38+ messages in thread* Re: [PATCH RFC/DO NOT MERGE 08/12] drm/msm/hdmi: Add support for PM OPP table
2026-08-28 14:05 ` Krzysztof Kozlowski
@ 2026-08-28 14:16 ` sashiko-bot
-1 siblings, 0 replies; 38+ messages in thread
From: sashiko-bot @ 2026-08-28 14:16 UTC (permalink / raw)
To: Krzysztof Kozlowski
Cc: conor+dt, dri-devel, vkoul, robh, linux-phy, devicetree,
neil.armstrong, olteanv
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
- [High] Unconditional call to `devm_pm_opp_set_clkname()` causes probe failure on platforms without the optional "extp" clock.
- [Medium] Memory and reference leak of `hdmi->next_bridge` on error paths in probe due to bypassed cleanup.
--
commit 44f5c22fff51888fa0578000b738b8abea1a33b0
Author: Krzysztof Kozlowski <krzysztof.kozlowski@oss.qualcomm.com>
drm/msm/hdmi: Add support for PM OPP table
This commit adds PM OPP table support to allow scaling domain rails
using the pixel clock ("extp"). This enables proper votes depending
on the requested HDMI pixel rate.
> diff --git a/drivers/gpu/drm/msm/hdmi/hdmi.c b/drivers/gpu/drm/msm/hdmi/hdmi.c
> index 4740060846335..c46f30063f142 100644
> --- a/drivers/gpu/drm/msm/hdmi/hdmi.c
> +++ b/drivers/gpu/drm/msm/hdmi/hdmi.c
[ ... ]
> @@ -368,6 +368,14 @@ static int msm_hdmi_dev_probe(struct platform_device *pdev)
> goto err_put_bridge;
> }
>
> + ret = devm_pm_opp_set_clkname(dev, "extp");
> + if (ret)
> + return ret;
[Severity: High]
Does this code cause a probe failure on platforms without the "extp" clock?
Earlier in msm_hdmi_dev_probe(), the "extp" clock is fetched using
devm_clk_get_optional():
hdmi->extp_clk = devm_clk_get_optional(dev, "extp");
If the platform does not provide this clock, devm_pm_opp_set_clkname()
will return an error (such as -ENOENT). Returning that error here will
unconditionally abort the probe, preventing display output on hardware
where this clock is legitimately absent.
[Severity: Medium]
Also, does this code leak the hdmi->next_bridge reference by returning
directly?
If devm_pm_opp_set_clkname() fails, returning the error directly skips the
goto err_put_bridge; label. This bypasses the cleanup of hdmi->next_bridge,
which was acquired earlier in msm_hdmi_dev_probe() via
of_drm_get_bridge_by_endpoint().
> +
> + ret = devm_pm_opp_of_add_table(dev);
> + if (ret && ret != -ENODEV)
> + return dev_err_probe(dev, ret, "invalid OPP table in device tree\n");
[Severity: Medium]
Similarly, does this direct return also leak the hdmi->next_bridge reference
if devm_pm_opp_of_add_table() fails?
Using the goto err_put_bridge; path instead of returning directly would
ensure the bridge reference is correctly dropped.
> +
> if (!hdmi->hpd_gpiod)
> DBG("failed to get HPD gpio");
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260828-drm-msm-hdmi-eliza-v1-0-67843277de17@oss.qualcomm.com?part=8
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply [flat|nested] 38+ messages in thread* Re: [PATCH RFC/DO NOT MERGE 08/12] drm/msm/hdmi: Add support for PM OPP table
@ 2026-08-28 14:16 ` sashiko-bot
0 siblings, 0 replies; 38+ messages in thread
From: sashiko-bot @ 2026-08-28 14:16 UTC (permalink / raw)
To: Krzysztof Kozlowski
Cc: conor+dt, dri-devel, vkoul, robh, linux-phy, devicetree,
neil.armstrong, olteanv
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
- [High] Unconditional call to `devm_pm_opp_set_clkname()` causes probe failure on platforms without the optional "extp" clock.
- [Medium] Memory and reference leak of `hdmi->next_bridge` on error paths in probe due to bypassed cleanup.
--
commit 44f5c22fff51888fa0578000b738b8abea1a33b0
Author: Krzysztof Kozlowski <krzysztof.kozlowski@oss.qualcomm.com>
drm/msm/hdmi: Add support for PM OPP table
This commit adds PM OPP table support to allow scaling domain rails
using the pixel clock ("extp"). This enables proper votes depending
on the requested HDMI pixel rate.
> diff --git a/drivers/gpu/drm/msm/hdmi/hdmi.c b/drivers/gpu/drm/msm/hdmi/hdmi.c
> index 4740060846335..c46f30063f142 100644
> --- a/drivers/gpu/drm/msm/hdmi/hdmi.c
> +++ b/drivers/gpu/drm/msm/hdmi/hdmi.c
[ ... ]
> @@ -368,6 +368,14 @@ static int msm_hdmi_dev_probe(struct platform_device *pdev)
> goto err_put_bridge;
> }
>
> + ret = devm_pm_opp_set_clkname(dev, "extp");
> + if (ret)
> + return ret;
[Severity: High]
Does this code cause a probe failure on platforms without the "extp" clock?
Earlier in msm_hdmi_dev_probe(), the "extp" clock is fetched using
devm_clk_get_optional():
hdmi->extp_clk = devm_clk_get_optional(dev, "extp");
If the platform does not provide this clock, devm_pm_opp_set_clkname()
will return an error (such as -ENOENT). Returning that error here will
unconditionally abort the probe, preventing display output on hardware
where this clock is legitimately absent.
[Severity: Medium]
Also, does this code leak the hdmi->next_bridge reference by returning
directly?
If devm_pm_opp_set_clkname() fails, returning the error directly skips the
goto err_put_bridge; label. This bypasses the cleanup of hdmi->next_bridge,
which was acquired earlier in msm_hdmi_dev_probe() via
of_drm_get_bridge_by_endpoint().
> +
> + ret = devm_pm_opp_of_add_table(dev);
> + if (ret && ret != -ENODEV)
> + return dev_err_probe(dev, ret, "invalid OPP table in device tree\n");
[Severity: Medium]
Similarly, does this direct return also leak the hdmi->next_bridge reference
if devm_pm_opp_of_add_table() fails?
Using the goto err_put_bridge; path instead of returning directly would
ensure the bridge reference is correctly dropped.
> +
> if (!hdmi->hpd_gpiod)
> DBG("failed to get HPD gpio");
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260828-drm-msm-hdmi-eliza-v1-0-67843277de17@oss.qualcomm.com?part=8
^ permalink raw reply [flat|nested] 38+ messages in thread
* [PATCH RFC/DO NOT MERGE 09/12] drm/msm/hdmi: Add HDMI for Eliza SoC
2026-08-28 14:04 ` Krzysztof Kozlowski
@ 2026-08-28 14:05 ` Krzysztof Kozlowski
-1 siblings, 0 replies; 38+ messages in thread
From: Krzysztof Kozlowski @ 2026-08-28 14:05 UTC (permalink / raw)
To: Rob Clark, Dmitry Baryshkov, Abhinav Kumar, Jessica Zhang,
Sean Paul, Marijn Suijten, David Airlie, Simona Vetter,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Vinod Koul, Neil Armstrong,
Manivannan Sadhasivam, Bjorn Andersson, Konrad Dybcio
Cc: linux-arm-msm, dri-devel, freedreno, linux-kernel, devicetree,
Krzysztof Kozlowski, Krzysztof Kozlowski, linux-phy
Qualcomm Eliza SoC with DPU v12.4 comes with HDMI on INTF_11 with
additional INTR registers. The device clocks look different comparing
to last variant of HDMI from MSM8998.
Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski@oss.qualcomm.com>
---
.../gpu/drm/msm/disp/dpu1/catalog/dpu_12_4_eliza.h | 8 +++
drivers/gpu/drm/msm/disp/dpu1/dpu_hw_interrupts.c | 15 +++++
drivers/gpu/drm/msm/disp/dpu1/dpu_hw_interrupts.h | 3 +
drivers/gpu/drm/msm/disp/dpu1/dpu_hw_mdss.h | 3 +
drivers/gpu/drm/msm/hdmi/hdmi.c | 32 +++++++++
drivers/gpu/drm/msm/hdmi/hdmi.h | 4 ++
drivers/gpu/drm/msm/hdmi/hdmi_bridge.c | 75 +++++++++++++++++++---
drivers/gpu/drm/msm/msm_drv.h | 5 ++
8 files changed, 136 insertions(+), 9 deletions(-)
diff --git a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_12_4_eliza.h b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_12_4_eliza.h
index b93d32888972..c95cf4e38c12 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_12_4_eliza.h
+++ b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_12_4_eliza.h
@@ -294,6 +294,14 @@ static const struct dpu_intf_cfg eliza_intf[] = {
.prog_fetch_lines_worst_case = 24,
.intr_underrun = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 30),
.intr_vsync = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 31),
+ }, {
+ .name = "intf_11", .id = INTF_11,
+ .base = 0x3f000, .len = 0x4bc,
+ .type = INTF_HDMI,
+ .controller_id = MSM_HDMI_CONTROLLER_0,
+ .prog_fetch_lines_worst_case = 24,
+ .intr_underrun = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 14),
+ .intr_vsync = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 15),
}
};
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_interrupts.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_interrupts.c
index 5b7cd5241f45..f6d1f944f4ba 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_interrupts.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_interrupts.c
@@ -206,6 +206,21 @@ static const struct dpu_intr_reg dpu_intr_set_7xxx[] = {
MDP_INTF_REV_7xxx_INTR_EN(8),
MDP_INTF_REV_7xxx_INTR_STATUS(8)
},
+ [MDP_INTF9_INTR] = {
+ MDP_INTF_REV_7xxx_INTR_CLEAR(9),
+ MDP_INTF_REV_7xxx_INTR_EN(9),
+ MDP_INTF_REV_7xxx_INTR_STATUS(9)
+ },
+ [MDP_INTF10_INTR] = {
+ MDP_INTF_REV_7xxx_INTR_CLEAR(10),
+ MDP_INTF_REV_7xxx_INTR_EN(10),
+ MDP_INTF_REV_7xxx_INTR_STATUS(10)
+ },
+ [MDP_INTF11_INTR] = {
+ MDP_INTF_REV_7xxx_INTR_CLEAR(11),
+ MDP_INTF_REV_7xxx_INTR_EN(11),
+ MDP_INTF_REV_7xxx_INTR_STATUS(11)
+ },
};
/*
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_interrupts.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_interrupts.h
index 142358a105c5..231809607be1 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_interrupts.h
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_interrupts.h
@@ -27,6 +27,9 @@ enum dpu_hw_intr_reg {
MDP_INTF6_INTR,
MDP_INTF7_INTR,
MDP_INTF8_INTR,
+ MDP_INTF9_INTR,
+ MDP_INTF10_INTR,
+ MDP_INTF11_INTR,
MDP_INTF1_TEAR_INTR,
MDP_INTF2_TEAR_INTR,
MDP_AD4_0_INTR,
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_mdss.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_mdss.h
index 0e65bf5ddc4a..bdcc0caa4e4f 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_mdss.h
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_mdss.h
@@ -226,6 +226,9 @@ enum dpu_intf {
INTF_6,
INTF_7,
INTF_8,
+ INTF_9,
+ INTF_10,
+ INTF_11,
INTF_MAX
};
diff --git a/drivers/gpu/drm/msm/hdmi/hdmi.c b/drivers/gpu/drm/msm/hdmi/hdmi.c
index c46f30063f14..b769780cd5dd 100644
--- a/drivers/gpu/drm/msm/hdmi/hdmi.c
+++ b/drivers/gpu/drm/msm/hdmi/hdmi.c
@@ -234,6 +234,16 @@ static const struct hdmi_platform_config hdmi_tx_8974_config = {
.pwr_clk_cnt = ARRAY_SIZE(pwr_clk_names_8x74),
};
+static const char * const pwr_reg_names_eliza[] = {"core-vdda", "core-vcc", "vddio"};
+static const char * const pwr_clk_names_eliza[] = {"iface", "core"};
+
+static const struct hdmi_platform_config hdmi_tx_eliza_config = {
+ .pwr_reg_names = pwr_reg_names_eliza,
+ .pwr_reg_cnt = ARRAY_SIZE(pwr_reg_names_eliza),
+ .pwr_clk_names = pwr_clk_names_eliza,
+ .pwr_clk_cnt = ARRAY_SIZE(pwr_clk_names_eliza),
+};
+
static int msm_hdmi_bind(struct device *dev, struct device *master, void *data)
{
struct msm_drm_private *priv = dev_get_drvdata(master);
@@ -360,6 +370,27 @@ static int msm_hdmi_dev_probe(struct platform_device *pdev)
goto err_put_bridge;
}
+ hdmi->phy_iface_clk = devm_clk_get_optional(dev, "phy_iface");
+ if (IS_ERR(hdmi->phy_iface_clk)) {
+ ret = dev_err_probe(dev, PTR_ERR(hdmi->phy_iface_clk),
+ "failed to get phy iface clock\n");
+ goto err_put_bridge;
+ }
+
+ hdmi->pixel_src_clk = devm_clk_get_optional(dev, "pixel_src");
+ if (IS_ERR(hdmi->pixel_src_clk)) {
+ ret = dev_err_probe(dev, PTR_ERR(hdmi->pixel_src_clk),
+ "failed to get pixel src clock\n");
+ goto err_put_bridge;
+ }
+
+ hdmi->pll_clk = devm_clk_get_optional(dev, "pll");
+ if (IS_ERR(hdmi->pll_clk)) {
+ ret = dev_err_probe(dev, PTR_ERR(hdmi->pll_clk),
+ "failed to get pll clock\n");
+ goto err_put_bridge;
+ }
+
hdmi->hpd_gpiod = devm_gpiod_get_optional(dev, "hpd", GPIOD_IN);
/* This will catch e.g. -EPROBE_DEFER */
if (IS_ERR(hdmi->hpd_gpiod)) {
@@ -458,6 +489,7 @@ static int msm_hdmi_runtime_resume(struct device *dev)
static DEFINE_RUNTIME_DEV_PM_OPS(msm_hdmi_pm_ops, msm_hdmi_runtime_suspend, msm_hdmi_runtime_resume, NULL);
static const struct of_device_id msm_hdmi_dt_match[] = {
+ { .compatible = "qcom,eliza-hdmi-tx", .data = &hdmi_tx_eliza_config },
{ .compatible = "qcom,hdmi-tx-8998", .data = &hdmi_tx_8974_config },
{ .compatible = "qcom,hdmi-tx-8996", .data = &hdmi_tx_8974_config },
{ .compatible = "qcom,hdmi-tx-8994", .data = &hdmi_tx_8974_config },
diff --git a/drivers/gpu/drm/msm/hdmi/hdmi.h b/drivers/gpu/drm/msm/hdmi/hdmi.h
index 306b988bca72..2fa9bec455b4 100644
--- a/drivers/gpu/drm/msm/hdmi/hdmi.h
+++ b/drivers/gpu/drm/msm/hdmi/hdmi.h
@@ -52,6 +52,9 @@ struct hdmi {
struct regulator_bulk_data *pwr_regs;
struct clk_bulk_data *pwr_clks;
struct clk *extp_clk;
+ struct clk *phy_iface_clk;
+ struct clk *pixel_src_clk;
+ struct clk *pll_clk;
struct gpio_desc *hpd_gpiod;
@@ -171,6 +174,7 @@ struct hdmi_phy {
struct platform_device *pdev;
void __iomem *mmio;
struct hdmi_phy_cfg *cfg;
+ void *pll;
const struct hdmi_phy_funcs *funcs;
struct regulator_bulk_data *regs;
struct clk **clks;
diff --git a/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c b/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c
index 621083a97b37..c6a75f653915 100644
--- a/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c
+++ b/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c
@@ -14,6 +14,18 @@
#include "msm_kms.h"
#include "hdmi.h"
+static void msm_hdmi_clk_reparent(struct hdmi *hdmi)
+{
+ int ret;
+
+ if (hdmi->pixel_src_clk && hdmi->pll_clk) {
+ ret = clk_set_parent(hdmi->pixel_src_clk, hdmi->pll_clk);
+ if (ret)
+ DRM_DEV_ERROR(hdmi->dev->dev, "failed to set reparent pixel src clock rate: %d\n",
+ ret);
+ }
+}
+
static void msm_hdmi_power_on(struct drm_bridge *bridge)
{
struct hdmi_bridge *hdmi_bridge = to_hdmi_bridge(bridge);
@@ -29,16 +41,34 @@ static void msm_hdmi_clk_prepare(struct drm_bridge *bridge)
struct hdmi *hdmi = hdmi_bridge->hdmi;
int ret;
+ msm_hdmi_clk_reparent(hdmi);
if (hdmi->extp_clk) {
+ /*
+ * Set rate to hdmi->pixclock: PCLK_CLK_SRC and PCLK_CLK
+ * Set rate to hdmi->pixclock/2: INTF_CLK and PCLK_DIV_CLK_SRC
+ * Set rate to hdmi->pixclock: HDMI PHY PLL
+ */
DBG("pixclock: %lu", hdmi->pixclock);
ret = dev_pm_opp_set_rate(&hdmi->pdev->dev, hdmi->pixclock);
if (ret)
DRM_DEV_ERROR(dev->dev, "failed to set OPP rate: %d\n", ret);
+ ret = clk_set_rate(hdmi->pixel_src_clk, hdmi->pixclock);
+ if (ret)
+ DRM_DEV_ERROR(dev->dev, "failed to set pixel src clk rate: %d\n", ret);
+
+ ret = clk_set_rate(hdmi->phy_iface_clk, hdmi->pixclock / 2);
+ if (ret)
+ DRM_DEV_ERROR(dev->dev, "failed to set pixel iface clk rate: %d\n", ret);
+
ret = clk_prepare_enable(hdmi->extp_clk);
if (ret)
DRM_DEV_ERROR(dev->dev, "failed to enable extp clk: %d\n", ret);
+
+ ret = clk_prepare_enable(hdmi->phy_iface_clk);
+ if (ret)
+ DRM_DEV_ERROR(dev->dev, "failed to enable phy iface clk: %d\n", ret);
}
}
@@ -61,6 +91,7 @@ static void msm_hdmi_clk_unprepare(struct drm_bridge *bridge)
struct hdmi *hdmi = hdmi_bridge->hdmi;
if (hdmi->extp_clk) {
+ clk_disable_unprepare(hdmi->phy_iface_clk);
clk_disable_unprepare(hdmi->extp_clk);
dev_pm_opp_set_rate(&hdmi->pdev->dev, 0);
}
@@ -443,21 +474,47 @@ static enum drm_mode_status msm_hdmi_bridge_tmds_char_rate_valid(const struct dr
* mdp4/dtv stuff where pixel clk is assigned to mdp/encoder
* instead):
*/
- if (kms->funcs->round_pixclk)
+ if (kms->funcs->round_pixclk) {
actual = kms->funcs->round_pixclk(kms,
tmds_rate,
hdmi_bridge->hdmi->encoder);
- else if (hdmi->extp_clk)
- actual = clk_round_rate(hdmi->extp_clk, tmds_rate);
- else
- actual = tmds_rate;
+ DBG("requested=%lld, actual=%ld", tmds_rate, actual);
- DBG("requested=%lld, actual=%ld", tmds_rate, actual);
+ if (actual != tmds_rate)
+ return MODE_CLOCK_RANGE;
+ return MODE_OK;
+ } else if (!dev_pm_opp_get_opp_count(&hdmi->pdev->dev)) {
+ if (hdmi->extp_clk)
+ actual = clk_round_rate(hdmi->extp_clk, tmds_rate);
+ else
+ actual = tmds_rate;
- if (actual != tmds_rate)
- return MODE_CLOCK_RANGE;
+ if (actual != tmds_rate)
+ return MODE_CLOCK_RANGE;
+ return MODE_OK;
+ } else {
+ struct dev_pm_opp *opp;
+ unsigned long pclk_rate = tmds_rate;
- return 0;
+ if (mode->clock > 600000)
+ return MODE_CLOCK_HIGH;
+
+ opp = dev_pm_opp_find_freq_ceil(&hdmi->pdev->dev, &pclk_rate);
+ if (!IS_ERR(opp)) {
+ dev_pm_opp_put(opp);
+ } else if (PTR_ERR(opp) == -ERANGE) {
+ /*
+ * An empty table is created by devm_pm_opp_set_clkname() even
+ * if there is none. Thus find_freq_ceil will still return
+ * -ERANGE in such case.
+ */
+ return MODE_CLOCK_RANGE;
+ } else {
+ return MODE_ERROR;
+ }
+
+ return MODE_OK;
+ }
}
static const struct drm_bridge_funcs msm_hdmi_bridge_funcs = {
diff --git a/drivers/gpu/drm/msm/msm_drv.h b/drivers/gpu/drm/msm/msm_drv.h
index eb4bbae8557b..e63c63ae7d6f 100644
--- a/drivers/gpu/drm/msm/msm_drv.h
+++ b/drivers/gpu/drm/msm/msm_drv.h
@@ -67,6 +67,11 @@ enum msm_dsi_controller {
MSM_DSI_CONTROLLER_COUNT,
};
+enum msm_hdmi_controller {
+ MSM_HDMI_CONTROLLER_0,
+ MSM_HDMI_CONTROLLER_COUNT,
+};
+
#define MSM_GPU_MAX_RINGS 4
struct msm_drm_private {
--
2.53.0
^ permalink raw reply related [flat|nested] 38+ messages in thread* [PATCH RFC/DO NOT MERGE 09/12] drm/msm/hdmi: Add HDMI for Eliza SoC
@ 2026-08-28 14:05 ` Krzysztof Kozlowski
0 siblings, 0 replies; 38+ messages in thread
From: Krzysztof Kozlowski @ 2026-08-28 14:05 UTC (permalink / raw)
To: Rob Clark, Dmitry Baryshkov, Abhinav Kumar, Jessica Zhang,
Sean Paul, Marijn Suijten, David Airlie, Simona Vetter,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Vinod Koul, Neil Armstrong,
Manivannan Sadhasivam, Bjorn Andersson, Konrad Dybcio
Cc: linux-arm-msm, dri-devel, freedreno, linux-kernel, devicetree,
Krzysztof Kozlowski, Krzysztof Kozlowski, linux-phy
Qualcomm Eliza SoC with DPU v12.4 comes with HDMI on INTF_11 with
additional INTR registers. The device clocks look different comparing
to last variant of HDMI from MSM8998.
Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski@oss.qualcomm.com>
---
.../gpu/drm/msm/disp/dpu1/catalog/dpu_12_4_eliza.h | 8 +++
drivers/gpu/drm/msm/disp/dpu1/dpu_hw_interrupts.c | 15 +++++
drivers/gpu/drm/msm/disp/dpu1/dpu_hw_interrupts.h | 3 +
drivers/gpu/drm/msm/disp/dpu1/dpu_hw_mdss.h | 3 +
drivers/gpu/drm/msm/hdmi/hdmi.c | 32 +++++++++
drivers/gpu/drm/msm/hdmi/hdmi.h | 4 ++
drivers/gpu/drm/msm/hdmi/hdmi_bridge.c | 75 +++++++++++++++++++---
drivers/gpu/drm/msm/msm_drv.h | 5 ++
8 files changed, 136 insertions(+), 9 deletions(-)
diff --git a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_12_4_eliza.h b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_12_4_eliza.h
index b93d32888972..c95cf4e38c12 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_12_4_eliza.h
+++ b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_12_4_eliza.h
@@ -294,6 +294,14 @@ static const struct dpu_intf_cfg eliza_intf[] = {
.prog_fetch_lines_worst_case = 24,
.intr_underrun = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 30),
.intr_vsync = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 31),
+ }, {
+ .name = "intf_11", .id = INTF_11,
+ .base = 0x3f000, .len = 0x4bc,
+ .type = INTF_HDMI,
+ .controller_id = MSM_HDMI_CONTROLLER_0,
+ .prog_fetch_lines_worst_case = 24,
+ .intr_underrun = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 14),
+ .intr_vsync = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 15),
}
};
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_interrupts.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_interrupts.c
index 5b7cd5241f45..f6d1f944f4ba 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_interrupts.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_interrupts.c
@@ -206,6 +206,21 @@ static const struct dpu_intr_reg dpu_intr_set_7xxx[] = {
MDP_INTF_REV_7xxx_INTR_EN(8),
MDP_INTF_REV_7xxx_INTR_STATUS(8)
},
+ [MDP_INTF9_INTR] = {
+ MDP_INTF_REV_7xxx_INTR_CLEAR(9),
+ MDP_INTF_REV_7xxx_INTR_EN(9),
+ MDP_INTF_REV_7xxx_INTR_STATUS(9)
+ },
+ [MDP_INTF10_INTR] = {
+ MDP_INTF_REV_7xxx_INTR_CLEAR(10),
+ MDP_INTF_REV_7xxx_INTR_EN(10),
+ MDP_INTF_REV_7xxx_INTR_STATUS(10)
+ },
+ [MDP_INTF11_INTR] = {
+ MDP_INTF_REV_7xxx_INTR_CLEAR(11),
+ MDP_INTF_REV_7xxx_INTR_EN(11),
+ MDP_INTF_REV_7xxx_INTR_STATUS(11)
+ },
};
/*
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_interrupts.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_interrupts.h
index 142358a105c5..231809607be1 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_interrupts.h
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_interrupts.h
@@ -27,6 +27,9 @@ enum dpu_hw_intr_reg {
MDP_INTF6_INTR,
MDP_INTF7_INTR,
MDP_INTF8_INTR,
+ MDP_INTF9_INTR,
+ MDP_INTF10_INTR,
+ MDP_INTF11_INTR,
MDP_INTF1_TEAR_INTR,
MDP_INTF2_TEAR_INTR,
MDP_AD4_0_INTR,
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_mdss.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_mdss.h
index 0e65bf5ddc4a..bdcc0caa4e4f 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_mdss.h
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_mdss.h
@@ -226,6 +226,9 @@ enum dpu_intf {
INTF_6,
INTF_7,
INTF_8,
+ INTF_9,
+ INTF_10,
+ INTF_11,
INTF_MAX
};
diff --git a/drivers/gpu/drm/msm/hdmi/hdmi.c b/drivers/gpu/drm/msm/hdmi/hdmi.c
index c46f30063f14..b769780cd5dd 100644
--- a/drivers/gpu/drm/msm/hdmi/hdmi.c
+++ b/drivers/gpu/drm/msm/hdmi/hdmi.c
@@ -234,6 +234,16 @@ static const struct hdmi_platform_config hdmi_tx_8974_config = {
.pwr_clk_cnt = ARRAY_SIZE(pwr_clk_names_8x74),
};
+static const char * const pwr_reg_names_eliza[] = {"core-vdda", "core-vcc", "vddio"};
+static const char * const pwr_clk_names_eliza[] = {"iface", "core"};
+
+static const struct hdmi_platform_config hdmi_tx_eliza_config = {
+ .pwr_reg_names = pwr_reg_names_eliza,
+ .pwr_reg_cnt = ARRAY_SIZE(pwr_reg_names_eliza),
+ .pwr_clk_names = pwr_clk_names_eliza,
+ .pwr_clk_cnt = ARRAY_SIZE(pwr_clk_names_eliza),
+};
+
static int msm_hdmi_bind(struct device *dev, struct device *master, void *data)
{
struct msm_drm_private *priv = dev_get_drvdata(master);
@@ -360,6 +370,27 @@ static int msm_hdmi_dev_probe(struct platform_device *pdev)
goto err_put_bridge;
}
+ hdmi->phy_iface_clk = devm_clk_get_optional(dev, "phy_iface");
+ if (IS_ERR(hdmi->phy_iface_clk)) {
+ ret = dev_err_probe(dev, PTR_ERR(hdmi->phy_iface_clk),
+ "failed to get phy iface clock\n");
+ goto err_put_bridge;
+ }
+
+ hdmi->pixel_src_clk = devm_clk_get_optional(dev, "pixel_src");
+ if (IS_ERR(hdmi->pixel_src_clk)) {
+ ret = dev_err_probe(dev, PTR_ERR(hdmi->pixel_src_clk),
+ "failed to get pixel src clock\n");
+ goto err_put_bridge;
+ }
+
+ hdmi->pll_clk = devm_clk_get_optional(dev, "pll");
+ if (IS_ERR(hdmi->pll_clk)) {
+ ret = dev_err_probe(dev, PTR_ERR(hdmi->pll_clk),
+ "failed to get pll clock\n");
+ goto err_put_bridge;
+ }
+
hdmi->hpd_gpiod = devm_gpiod_get_optional(dev, "hpd", GPIOD_IN);
/* This will catch e.g. -EPROBE_DEFER */
if (IS_ERR(hdmi->hpd_gpiod)) {
@@ -458,6 +489,7 @@ static int msm_hdmi_runtime_resume(struct device *dev)
static DEFINE_RUNTIME_DEV_PM_OPS(msm_hdmi_pm_ops, msm_hdmi_runtime_suspend, msm_hdmi_runtime_resume, NULL);
static const struct of_device_id msm_hdmi_dt_match[] = {
+ { .compatible = "qcom,eliza-hdmi-tx", .data = &hdmi_tx_eliza_config },
{ .compatible = "qcom,hdmi-tx-8998", .data = &hdmi_tx_8974_config },
{ .compatible = "qcom,hdmi-tx-8996", .data = &hdmi_tx_8974_config },
{ .compatible = "qcom,hdmi-tx-8994", .data = &hdmi_tx_8974_config },
diff --git a/drivers/gpu/drm/msm/hdmi/hdmi.h b/drivers/gpu/drm/msm/hdmi/hdmi.h
index 306b988bca72..2fa9bec455b4 100644
--- a/drivers/gpu/drm/msm/hdmi/hdmi.h
+++ b/drivers/gpu/drm/msm/hdmi/hdmi.h
@@ -52,6 +52,9 @@ struct hdmi {
struct regulator_bulk_data *pwr_regs;
struct clk_bulk_data *pwr_clks;
struct clk *extp_clk;
+ struct clk *phy_iface_clk;
+ struct clk *pixel_src_clk;
+ struct clk *pll_clk;
struct gpio_desc *hpd_gpiod;
@@ -171,6 +174,7 @@ struct hdmi_phy {
struct platform_device *pdev;
void __iomem *mmio;
struct hdmi_phy_cfg *cfg;
+ void *pll;
const struct hdmi_phy_funcs *funcs;
struct regulator_bulk_data *regs;
struct clk **clks;
diff --git a/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c b/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c
index 621083a97b37..c6a75f653915 100644
--- a/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c
+++ b/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c
@@ -14,6 +14,18 @@
#include "msm_kms.h"
#include "hdmi.h"
+static void msm_hdmi_clk_reparent(struct hdmi *hdmi)
+{
+ int ret;
+
+ if (hdmi->pixel_src_clk && hdmi->pll_clk) {
+ ret = clk_set_parent(hdmi->pixel_src_clk, hdmi->pll_clk);
+ if (ret)
+ DRM_DEV_ERROR(hdmi->dev->dev, "failed to set reparent pixel src clock rate: %d\n",
+ ret);
+ }
+}
+
static void msm_hdmi_power_on(struct drm_bridge *bridge)
{
struct hdmi_bridge *hdmi_bridge = to_hdmi_bridge(bridge);
@@ -29,16 +41,34 @@ static void msm_hdmi_clk_prepare(struct drm_bridge *bridge)
struct hdmi *hdmi = hdmi_bridge->hdmi;
int ret;
+ msm_hdmi_clk_reparent(hdmi);
if (hdmi->extp_clk) {
+ /*
+ * Set rate to hdmi->pixclock: PCLK_CLK_SRC and PCLK_CLK
+ * Set rate to hdmi->pixclock/2: INTF_CLK and PCLK_DIV_CLK_SRC
+ * Set rate to hdmi->pixclock: HDMI PHY PLL
+ */
DBG("pixclock: %lu", hdmi->pixclock);
ret = dev_pm_opp_set_rate(&hdmi->pdev->dev, hdmi->pixclock);
if (ret)
DRM_DEV_ERROR(dev->dev, "failed to set OPP rate: %d\n", ret);
+ ret = clk_set_rate(hdmi->pixel_src_clk, hdmi->pixclock);
+ if (ret)
+ DRM_DEV_ERROR(dev->dev, "failed to set pixel src clk rate: %d\n", ret);
+
+ ret = clk_set_rate(hdmi->phy_iface_clk, hdmi->pixclock / 2);
+ if (ret)
+ DRM_DEV_ERROR(dev->dev, "failed to set pixel iface clk rate: %d\n", ret);
+
ret = clk_prepare_enable(hdmi->extp_clk);
if (ret)
DRM_DEV_ERROR(dev->dev, "failed to enable extp clk: %d\n", ret);
+
+ ret = clk_prepare_enable(hdmi->phy_iface_clk);
+ if (ret)
+ DRM_DEV_ERROR(dev->dev, "failed to enable phy iface clk: %d\n", ret);
}
}
@@ -61,6 +91,7 @@ static void msm_hdmi_clk_unprepare(struct drm_bridge *bridge)
struct hdmi *hdmi = hdmi_bridge->hdmi;
if (hdmi->extp_clk) {
+ clk_disable_unprepare(hdmi->phy_iface_clk);
clk_disable_unprepare(hdmi->extp_clk);
dev_pm_opp_set_rate(&hdmi->pdev->dev, 0);
}
@@ -443,21 +474,47 @@ static enum drm_mode_status msm_hdmi_bridge_tmds_char_rate_valid(const struct dr
* mdp4/dtv stuff where pixel clk is assigned to mdp/encoder
* instead):
*/
- if (kms->funcs->round_pixclk)
+ if (kms->funcs->round_pixclk) {
actual = kms->funcs->round_pixclk(kms,
tmds_rate,
hdmi_bridge->hdmi->encoder);
- else if (hdmi->extp_clk)
- actual = clk_round_rate(hdmi->extp_clk, tmds_rate);
- else
- actual = tmds_rate;
+ DBG("requested=%lld, actual=%ld", tmds_rate, actual);
- DBG("requested=%lld, actual=%ld", tmds_rate, actual);
+ if (actual != tmds_rate)
+ return MODE_CLOCK_RANGE;
+ return MODE_OK;
+ } else if (!dev_pm_opp_get_opp_count(&hdmi->pdev->dev)) {
+ if (hdmi->extp_clk)
+ actual = clk_round_rate(hdmi->extp_clk, tmds_rate);
+ else
+ actual = tmds_rate;
- if (actual != tmds_rate)
- return MODE_CLOCK_RANGE;
+ if (actual != tmds_rate)
+ return MODE_CLOCK_RANGE;
+ return MODE_OK;
+ } else {
+ struct dev_pm_opp *opp;
+ unsigned long pclk_rate = tmds_rate;
- return 0;
+ if (mode->clock > 600000)
+ return MODE_CLOCK_HIGH;
+
+ opp = dev_pm_opp_find_freq_ceil(&hdmi->pdev->dev, &pclk_rate);
+ if (!IS_ERR(opp)) {
+ dev_pm_opp_put(opp);
+ } else if (PTR_ERR(opp) == -ERANGE) {
+ /*
+ * An empty table is created by devm_pm_opp_set_clkname() even
+ * if there is none. Thus find_freq_ceil will still return
+ * -ERANGE in such case.
+ */
+ return MODE_CLOCK_RANGE;
+ } else {
+ return MODE_ERROR;
+ }
+
+ return MODE_OK;
+ }
}
static const struct drm_bridge_funcs msm_hdmi_bridge_funcs = {
diff --git a/drivers/gpu/drm/msm/msm_drv.h b/drivers/gpu/drm/msm/msm_drv.h
index eb4bbae8557b..e63c63ae7d6f 100644
--- a/drivers/gpu/drm/msm/msm_drv.h
+++ b/drivers/gpu/drm/msm/msm_drv.h
@@ -67,6 +67,11 @@ enum msm_dsi_controller {
MSM_DSI_CONTROLLER_COUNT,
};
+enum msm_hdmi_controller {
+ MSM_HDMI_CONTROLLER_0,
+ MSM_HDMI_CONTROLLER_COUNT,
+};
+
#define MSM_GPU_MAX_RINGS 4
struct msm_drm_private {
--
2.53.0
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply related [flat|nested] 38+ messages in thread* Re: [PATCH RFC/DO NOT MERGE 09/12] drm/msm/hdmi: Add HDMI for Eliza SoC
2026-08-28 14:05 ` Krzysztof Kozlowski
@ 2026-08-28 14:22 ` sashiko-bot
-1 siblings, 0 replies; 38+ messages in thread
From: sashiko-bot @ 2026-08-28 14:22 UTC (permalink / raw)
To: Krzysztof Kozlowski
Cc: vkoul, dri-devel, devicetree, neil.armstrong, linux-phy, olteanv,
robh, conor+dt
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [High] The TMDS rate validation for platforms with OPP tables accepts inexact pixel clocks by skipping clock synthesizability checks.
--
commit e2e2d112c3fa04206001b8a9cc56acdda995a731
Author: Krzysztof Kozlowski <krzysztof.kozlowski@oss.qualcomm.com>
drm/msm/hdmi: Add HDMI for Eliza SoC
This commit adds HDMI support for the Qualcomm Eliza SoC (DPU v12.4). It
introduces configuration for INTF_11 with new interrupt registers and handles
Eliza's distinct clock and power requirements.
> diff --git a/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c b/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c
> index 17e81628525a9..b5353a1688ddf 100644
> --- a/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c
> +++ b/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c
[ ... ]
> @@ -459,21 +490,47 @@ static enum drm_mode_status msm_hdmi_bridge_tmds_char_rate_valid(const struct dr
> * mdp4/dtv stuff where pixel clk is assigned to mdp/encoder
> * instead):
> */
> - if (kms->funcs->round_pixclk)
> + if (kms->funcs->round_pixclk) {
> actual = kms->funcs->round_pixclk(kms,
> tmds_rate,
> hdmi_bridge->hdmi->encoder);
> - else if (hdmi->extp_clk)
> - actual = clk_round_rate(hdmi->extp_clk, tmds_rate);
> - else
> - actual = tmds_rate;
> -
> - DBG("requested=%lld, actual=%ld", tmds_rate, actual);
> -
> - if (actual != tmds_rate)
> - return MODE_CLOCK_RANGE;
> -
> - return 0;
> + DBG("requested=%lld, actual=%ld", tmds_rate, actual);
> +
> + if (actual != tmds_rate)
> + return MODE_CLOCK_RANGE;
> + return MODE_OK;
> + } else if (!dev_pm_opp_get_opp_count(&hdmi->pdev->dev)) {
> + if (hdmi->extp_clk)
> + actual = clk_round_rate(hdmi->extp_clk, tmds_rate);
> + else
> + actual = tmds_rate;
> +
> + if (actual != tmds_rate)
> + return MODE_CLOCK_RANGE;
> + return MODE_OK;
> + } else {
> + struct dev_pm_opp *opp;
> + unsigned long pclk_rate = tmds_rate;
> +
> + if (mode->clock > 600000)
> + return MODE_CLOCK_HIGH;
> +
> + opp = dev_pm_opp_find_freq_ceil(&hdmi->pdev->dev, &pclk_rate);
> + if (!IS_ERR(opp)) {
> + dev_pm_opp_put(opp);
> + } else if (PTR_ERR(opp) == -ERANGE) {
> + /*
> + * An empty table is created by devm_pm_opp_set_clkname() even
> + * if there is none. Thus find_freq_ceil will still return
> + * -ERANGE in such case.
> + */
> + return MODE_CLOCK_RANGE;
> + } else {
> + return MODE_ERROR;
> + }
> +
> + return MODE_OK;
[Severity: High]
Does this bypass clock synthesizability checks for platforms with OPP tables?
The TMDS rate validation here accepts inexact pixel clocks because it skips
the exact match check that is enforced in the non-OPP path:
if (hdmi->extp_clk)
actual = clk_round_rate(hdmi->extp_clk, tmds_rate);
...
if (actual != tmds_rate)
return MODE_CLOCK_RANGE;
When msm_hdmi_bridge_tmds_char_rate_valid() searches for an OPP entry, it
uses dev_pm_opp_find_freq_ceil() which finds a ceiling rather than an exact
match. Because it returns MODE_OK unconditionally upon finding a ceiling,
it can accept display modes that the hardware clock generator cannot
exactly synthesize.
Could this result in configuring an inaccurate pixel clock for the display,
leading to Out of Range errors or visual corruption?
> + }
> }
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260828-drm-msm-hdmi-eliza-v1-0-67843277de17@oss.qualcomm.com?part=9
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply [flat|nested] 38+ messages in thread* Re: [PATCH RFC/DO NOT MERGE 09/12] drm/msm/hdmi: Add HDMI for Eliza SoC
@ 2026-08-28 14:22 ` sashiko-bot
0 siblings, 0 replies; 38+ messages in thread
From: sashiko-bot @ 2026-08-28 14:22 UTC (permalink / raw)
To: Krzysztof Kozlowski
Cc: vkoul, dri-devel, devicetree, neil.armstrong, linux-phy, olteanv,
robh, conor+dt
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [High] The TMDS rate validation for platforms with OPP tables accepts inexact pixel clocks by skipping clock synthesizability checks.
--
commit e2e2d112c3fa04206001b8a9cc56acdda995a731
Author: Krzysztof Kozlowski <krzysztof.kozlowski@oss.qualcomm.com>
drm/msm/hdmi: Add HDMI for Eliza SoC
This commit adds HDMI support for the Qualcomm Eliza SoC (DPU v12.4). It
introduces configuration for INTF_11 with new interrupt registers and handles
Eliza's distinct clock and power requirements.
> diff --git a/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c b/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c
> index 17e81628525a9..b5353a1688ddf 100644
> --- a/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c
> +++ b/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c
[ ... ]
> @@ -459,21 +490,47 @@ static enum drm_mode_status msm_hdmi_bridge_tmds_char_rate_valid(const struct dr
> * mdp4/dtv stuff where pixel clk is assigned to mdp/encoder
> * instead):
> */
> - if (kms->funcs->round_pixclk)
> + if (kms->funcs->round_pixclk) {
> actual = kms->funcs->round_pixclk(kms,
> tmds_rate,
> hdmi_bridge->hdmi->encoder);
> - else if (hdmi->extp_clk)
> - actual = clk_round_rate(hdmi->extp_clk, tmds_rate);
> - else
> - actual = tmds_rate;
> -
> - DBG("requested=%lld, actual=%ld", tmds_rate, actual);
> -
> - if (actual != tmds_rate)
> - return MODE_CLOCK_RANGE;
> -
> - return 0;
> + DBG("requested=%lld, actual=%ld", tmds_rate, actual);
> +
> + if (actual != tmds_rate)
> + return MODE_CLOCK_RANGE;
> + return MODE_OK;
> + } else if (!dev_pm_opp_get_opp_count(&hdmi->pdev->dev)) {
> + if (hdmi->extp_clk)
> + actual = clk_round_rate(hdmi->extp_clk, tmds_rate);
> + else
> + actual = tmds_rate;
> +
> + if (actual != tmds_rate)
> + return MODE_CLOCK_RANGE;
> + return MODE_OK;
> + } else {
> + struct dev_pm_opp *opp;
> + unsigned long pclk_rate = tmds_rate;
> +
> + if (mode->clock > 600000)
> + return MODE_CLOCK_HIGH;
> +
> + opp = dev_pm_opp_find_freq_ceil(&hdmi->pdev->dev, &pclk_rate);
> + if (!IS_ERR(opp)) {
> + dev_pm_opp_put(opp);
> + } else if (PTR_ERR(opp) == -ERANGE) {
> + /*
> + * An empty table is created by devm_pm_opp_set_clkname() even
> + * if there is none. Thus find_freq_ceil will still return
> + * -ERANGE in such case.
> + */
> + return MODE_CLOCK_RANGE;
> + } else {
> + return MODE_ERROR;
> + }
> +
> + return MODE_OK;
[Severity: High]
Does this bypass clock synthesizability checks for platforms with OPP tables?
The TMDS rate validation here accepts inexact pixel clocks because it skips
the exact match check that is enforced in the non-OPP path:
if (hdmi->extp_clk)
actual = clk_round_rate(hdmi->extp_clk, tmds_rate);
...
if (actual != tmds_rate)
return MODE_CLOCK_RANGE;
When msm_hdmi_bridge_tmds_char_rate_valid() searches for an OPP entry, it
uses dev_pm_opp_find_freq_ceil() which finds a ceiling rather than an exact
match. Because it returns MODE_OK unconditionally upon finding a ceiling,
it can accept display modes that the hardware clock generator cannot
exactly synthesize.
Could this result in configuring an inaccurate pixel clock for the display,
leading to Out of Range errors or visual corruption?
> + }
> }
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260828-drm-msm-hdmi-eliza-v1-0-67843277de17@oss.qualcomm.com?part=9
^ permalink raw reply [flat|nested] 38+ messages in thread
* [PATCH RFC/DO NOT MERGE 10/12] drm/msm/hdmi_phy_eliza: Add support for Synopsys-based HDMI phy on Eliza
2026-08-28 14:04 ` Krzysztof Kozlowski
@ 2026-08-28 14:05 ` Krzysztof Kozlowski
-1 siblings, 0 replies; 38+ messages in thread
From: Krzysztof Kozlowski @ 2026-08-28 14:05 UTC (permalink / raw)
To: Rob Clark, Dmitry Baryshkov, Abhinav Kumar, Jessica Zhang,
Sean Paul, Marijn Suijten, David Airlie, Simona Vetter,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Vinod Koul, Neil Armstrong,
Manivannan Sadhasivam, Bjorn Andersson, Konrad Dybcio
Cc: linux-arm-msm, dri-devel, freedreno, linux-kernel, devicetree,
Krzysztof Kozlowski, Krzysztof Kozlowski, linux-phy
Add driver for HDMI phy block from Synopsys used on Eliza SoC. There is
no similarity regarding older HDMI phys.
Core parts for handling HDMI phy needs some adjustments as well, because
according to programming sequence:
1. The HDMI PHY should be initialized before preparing its PLL.
2. Final power up - enabling the TX lanes - should be performed after
PLL is prepared.
Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski@oss.qualcomm.com>
---
drivers/gpu/drm/msm/Makefile | 1 +
drivers/gpu/drm/msm/hdmi/hdmi.h | 18 +
drivers/gpu/drm/msm/hdmi/hdmi_phy.c | 12 +-
drivers/gpu/drm/msm/hdmi/hdmi_phy_eliza.c | 723 +++++++++++++++++++++++++
drivers/gpu/drm/msm/registers/display/hdmi.xml | 140 +++++
5 files changed, 892 insertions(+), 2 deletions(-)
diff --git a/drivers/gpu/drm/msm/Makefile b/drivers/gpu/drm/msm/Makefile
index d0c3a4c6703b..ae343a250bb0 100644
--- a/drivers/gpu/drm/msm/Makefile
+++ b/drivers/gpu/drm/msm/Makefile
@@ -43,6 +43,7 @@ msm-display-$(CONFIG_DRM_MSM_HDMI) += \
hdmi/hdmi_phy_8998.o \
hdmi/hdmi_phy_8x60.o \
hdmi/hdmi_phy_8x74.o \
+ hdmi/hdmi_phy_eliza.o \
hdmi/hdmi_pll_8960.o \
msm-display-$(CONFIG_DRM_MSM_MDP4) += \
diff --git a/drivers/gpu/drm/msm/hdmi/hdmi.h b/drivers/gpu/drm/msm/hdmi/hdmi.h
index 2fa9bec455b4..945fbb4d9888 100644
--- a/drivers/gpu/drm/msm/hdmi/hdmi.h
+++ b/drivers/gpu/drm/msm/hdmi/hdmi.h
@@ -149,6 +149,7 @@ enum hdmi_phy_type {
MSM_HDMI_PHY_8x74,
MSM_HDMI_PHY_8996,
MSM_HDMI_PHY_8998,
+ MSM_HDMI_PHY_ELIZA,
MSM_HDMI_PHY_MAX,
};
@@ -169,6 +170,7 @@ extern const struct hdmi_phy_cfg msm_hdmi_phy_8960_cfg;
extern const struct hdmi_phy_cfg msm_hdmi_phy_8x74_cfg;
extern const struct hdmi_phy_cfg msm_hdmi_phy_8996_cfg;
extern const struct hdmi_phy_cfg msm_hdmi_phy_8998_cfg;
+extern const struct hdmi_phy_cfg msm_hdmi_phy_eliza_cfg;
struct hdmi_phy {
struct platform_device *pdev;
@@ -190,6 +192,16 @@ static inline u32 hdmi_phy_read(struct hdmi_phy *phy, u32 reg)
return readl(phy->mmio + reg);
}
+static inline void hdmi_phy_update_bits(struct hdmi_phy *phy, u32 reg, u32 mask, u32 data)
+{
+ u32 val;
+
+ val = hdmi_phy_read(phy, reg);
+ val &= ~mask;
+ val |= data & mask;
+ hdmi_phy_write(phy, reg, val);
+}
+
int msm_hdmi_phy_resource_enable(struct hdmi_phy *phy);
void msm_hdmi_phy_resource_disable(struct hdmi_phy *phy);
void msm_hdmi_phy_init(struct hdmi_phy *phy, unsigned long pixclock);
@@ -203,6 +215,7 @@ void __exit msm_hdmi_phy_driver_unregister(void);
int msm_hdmi_pll_8960_init(struct platform_device *pdev);
int msm_hdmi_pll_8996_init(struct platform_device *pdev);
int msm_hdmi_pll_8998_init(struct platform_device *pdev);
+int msm_hdmi_pll_eliza_init(struct platform_device *pdev);
#else
static inline int msm_hdmi_pll_8960_init(struct platform_device *pdev)
{
@@ -218,6 +231,11 @@ static inline int msm_hdmi_pll_8998_init(struct platform_device *pdev)
{
return -ENODEV;
}
+
+static inline int msm_hdmi_pll_eliza_init(struct platform_device *pdev)
+{
+ return -ENODEV;
+}
#endif
/*
diff --git a/drivers/gpu/drm/msm/hdmi/hdmi_phy.c b/drivers/gpu/drm/msm/hdmi/hdmi_phy.c
index 8ce87d9adf74..94dc0e5c5c3e 100644
--- a/drivers/gpu/drm/msm/hdmi/hdmi_phy.c
+++ b/drivers/gpu/drm/msm/hdmi/hdmi_phy.c
@@ -141,6 +141,9 @@ static int msm_hdmi_phy_pll_init(struct platform_device *pdev,
case MSM_HDMI_PHY_8998:
ret = msm_hdmi_pll_8998_init(pdev);
break;
+ case MSM_HDMI_PHY_ELIZA:
+ ret = msm_hdmi_pll_eliza_init(pdev);
+ break;
/*
* we don't have PLL support for these, don't report an error for now
*/
@@ -168,13 +171,17 @@ static int msm_hdmi_phy_probe(struct platform_device *pdev)
if (!phy->cfg)
return -ENODEV;
- phy->mmio = msm_ioremap(pdev, "hdmi_phy");
+ if (phy->cfg->num_regs)
+ phy->mmio = msm_ioremap(pdev, "hdmi_phy");
+ else
+ phy->mmio = msm_ioremap(pdev, NULL);
if (IS_ERR(phy->mmio)) {
DRM_DEV_ERROR(dev, "%s: failed to map phy base\n", __func__);
return -ENOMEM;
}
phy->pdev = pdev;
+ platform_set_drvdata(pdev, phy);
ret = msm_hdmi_phy_resource_init(phy);
if (ret)
@@ -195,7 +202,6 @@ static int msm_hdmi_phy_probe(struct platform_device *pdev)
msm_hdmi_phy_resource_disable(phy);
- platform_set_drvdata(pdev, phy);
return 0;
}
@@ -218,6 +224,8 @@ static const struct of_device_id msm_hdmi_phy_dt_match[] = {
.data = &msm_hdmi_phy_8996_cfg },
{ .compatible = "qcom,hdmi-phy-8998",
.data = &msm_hdmi_phy_8998_cfg },
+ { .compatible = "qcom,eliza-hdmi-phy",
+ .data = &msm_hdmi_phy_eliza_cfg },
{}
};
MODULE_DEVICE_TABLE(of, msm_hdmi_phy_dt_match);
diff --git a/drivers/gpu/drm/msm/hdmi/hdmi_phy_eliza.c b/drivers/gpu/drm/msm/hdmi/hdmi_phy_eliza.c
new file mode 100644
index 000000000000..fad4e828154e
--- /dev/null
+++ b/drivers/gpu/drm/msm/hdmi/hdmi_phy_eliza.c
@@ -0,0 +1,723 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+#include <linux/array_size.h>
+#include <linux/bitfield.h>
+#include <linux/clk-provider.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/gcd.h>
+#include <linux/iopoll.h>
+#include <linux/minmax.h>
+#include <linux/types.h>
+
+#include "hdmi.h"
+
+#define REF_CLK_HZ 38400000 /* 38.4 MHz */
+#define HDMI_PLL_MAX_FREQ 600000000 /* 600 MHz */
+/* Unscrambled clock freq threshold */
+#define HDMI_PLL_HIGH_FREQ 340000000 /* 340 Mhz */
+#define HDMI_PLL_MIN_FREQ 25000000
+
+#define HDMI_PHY_MAX_BIT_RATE 2500000000 /* 2.5 Gbps */
+
+/* Number of TX lanes */
+#define HDMI_PHY_TXN_CONTROL 4
+
+#define MPLL(mul, qut, rem, den, clkd, vcof, pat, rxv, in, prop) \
+ .multiplier = (mul), \
+ .quotient = (qut), \
+ .remainder = (rem), \
+ .denominator = (den), \
+ .tx_clk_div = (clkd), \
+ .vco_freq = (vcof), \
+ .clk_pat = (pat), \
+ .rxvcosel = (rxv), \
+ .cp_int_holder = (in), \
+ .cp_prop_holder = (prop)
+
+struct hdmi_eliza_phy_pll_reg_cfg {
+ u32 vco_freq;
+ u32 rxvcosel;
+ u32 tx_clk_div;
+ u32 cp_int_holder;
+ u32 cp_prop_holder;
+ u32 quotient;
+ u32 remainder;
+ u32 multiplier;
+ u32 denominator;
+ u32 clk_pat;
+};
+
+struct hdmi_pll_eliza {
+ struct device *dev;
+ struct clk_hw clk_hw;
+ unsigned long rate;
+ struct hdmi_eliza_phy_pll_reg_cfg cfg;
+};
+
+
+struct hdmi_pll_eliza_mpll {
+ unsigned long rate;
+ struct hdmi_eliza_phy_pll_reg_cfg cfg;
+};
+
+static const struct hdmi_pll_eliza_mpll mpll_lut[] = {
+ { 25200000, { MPLL(0xb0, 0xe525, 0, 1, 5, 2, 0, 3, 0xc, 0x11) }, },
+ { 27000000, { MPLL(0xc0, 0x8000, 0, 1, 5, 2, 0, 3, 0xc, 0x11) }, },
+ { 27027000, { MPLL(0xc0, 0x9ccc, 4, 1, 5, 2, 0, 3, 0xb, 0x12) }, },
+ { 54000000, { MPLL(0xc0, 0x8000, 0, 1, 4, 2, 0, 3, 0xb, 0x11) }, },
+ { 59400000, { MPLL(0xd6, 0xc000, 0, 1, 4, 2, 0, 3, 0xb, 0x12) }, },
+ { 72000000, { MPLL(0x76, 0x0000, 0, 1, 3, 3, 0, 4, 0xc, 0x10) }, },
+ { 74250000, { MPLL(0x7a, 0x5800, 0, 1, 3, 3, 0, 4, 0xb, 0x12) }, },
+ { 82500000, { MPLL(0x8a, 0xf000, 0, 1, 3, 3, 0, 4, 0xb, 0x11) }, },
+ { 90000000, { MPLL(0x9a, 0xc000, 0, 1, 3, 2, 0, 4, 0xd, 0x11) }, },
+ { 99000000, { MPLL(0xae, 0x2000, 0, 1, 3, 2, 0, 4, 0xc, 0x11) }, },
+ { 108000000, { MPLL(0xc0, 0x8000, 0, 1, 3, 2, 0, 3, 0xb, 0x11) }, },
+ { 118800000, { MPLL(0xd6, 0xc000, 0, 1, 3, 2, 0, 3, 0xb, 0x12) }, },
+ { 148500000, { MPLL(0x7a, 0x5800, 0, 1, 2, 3, 0, 4, 0xc, 0x11) }, },
+ { 165000000, { MPLL(0x8a, 0xf000, 0, 1, 2, 3, 0, 4, 0xb, 0x11) }, },
+ { 185625000, { MPLL(0xa0, 0xae00, 0, 1, 2, 2, 0, 4, 0xc, 0x11) }, },
+ { 198000000, { MPLL(0xae, 0x2000, 0, 1, 2, 2, 0, 4, 0xc, 0x11) }, },
+ { 297000000, { MPLL(0x7a, 0x5800, 0, 1, 1, 3, 0, 4, 0xc, 0x11) }, },
+ { 371250000, { MPLL(0xa0, 0xae00, 0, 1, 1, 2, 1, 4, 0xc, 0x11) }, },
+ { 396000000, { MPLL(0xae, 0x2000, 0, 1, 1, 2, 1, 4, 0xc, 0x11) }, },
+ { 495000000, { MPLL(0xe0, 0xe800, 0, 1, 1, 2, 1, 3, 0xb, 0x12) }, },
+ { 594000000, { MPLL(0x7a, 0x5800, 0, 1, 0, 3, 1, 4, 0xc, 0x11) }, },
+};
+
+#define hw_clk_to_pll(x) container_of(x, struct hdmi_pll_eliza, clk_hw)
+
+static struct hdmi_phy *pll_get_phy(struct hdmi_pll_eliza *pll)
+{
+ return dev_get_drvdata(pll->dev);
+}
+
+static const struct hdmi_eliza_phy_pll_reg_cfg *
+hdmi_pll_eliza_mpll_lut_decoder(unsigned long rate)
+{
+ const struct hdmi_eliza_phy_pll_reg_cfg *cfg = NULL;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(mpll_lut); i++) {
+ if (rate == mpll_lut[i].rate) {
+ cfg = &mpll_lut[i].cfg;
+ break;
+ }
+ }
+
+ return cfg;
+}
+
+static int hdmi_eliza_pll_calculator(struct hdmi_pll_eliza *pll,
+ unsigned long rate,
+ unsigned long parent_rate,
+ struct hdmi_eliza_phy_pll_reg_cfg *cfg)
+{
+ const s64 bit_rate_multiplier = 1000;
+ const s64 bit_rate_divider = 1000;
+ const s64 cp_int_param[3] = {4524, -679588, 30860643};
+ const s64 cp_prop_param[3] = {8023, -1160252, 51717042};
+ const u64 gmult = 1e4;
+ s64 expon, base_rate, bit_rate;
+ s64 ref_clk_int, ref_clk_div;
+ u64 aux0, aux1, aux2, vco_freq;
+ u64 utemp, utemp2, multiplier, f_rx_vco;
+ s64 stemp, stemp2, stemp3;
+ s32 choice1, ref_ana_mpll_div;
+ s64 precision3 = 1e3;
+ s64 precision6 = 1e6;
+
+ if (rate > HDMI_PLL_HIGH_FREQ)
+ cfg->clk_pat = 1;
+ else
+ cfg->clk_pat = 0;
+
+ /*
+ * base_rate = clock_khz * bit_rate_multiplier / 1000
+ * Division by 1000, nullifies the conversion from KHz to Hz.
+ */
+ base_rate = rate / 1000 * gmult;
+
+ /* bit_rate = clock_khz * bit_rate_multiplier/bit_rate_divider. */
+ utemp = DIV_ROUND_UP(bit_rate_multiplier, bit_rate_divider);
+
+ bit_rate = base_rate * utemp;
+
+ /*
+ * REF_CLK_HZ: 38.4 MHz
+ * min_ref_clk: 50
+ * choice1 = floor(log2(REF_CLK_HZ/min_ref_clk))
+ * choice1 = floor(-0.38)
+ */
+ choice1 = -1;
+ ref_ana_mpll_div = max_t(s32, choice1, 0);
+
+ /* ref_clk_div = 2**ref_ana_mpll_div; */
+ ref_clk_div = 1UL << ref_ana_mpll_div;
+ ref_clk_int = DIV_ROUND_UP(REF_CLK_HZ, ref_clk_div);
+
+ /* expon = floor(log2(4.999999e9/base_rate)) */
+ utemp = 4.999999e9;
+
+ expon = fls64(utemp / base_rate) - 1;
+ if (expon >= 0)
+ vco_freq = base_rate * (1UL << expon);
+ else
+ vco_freq = base_rate >> 1;
+
+ /* multiplier = 2*(floor(bit_rate) * 2**expon / ref_clk_int) -16) */
+ multiplier = DIV_ROUND_UP(vco_freq, ref_clk_int);
+ multiplier = 2 * (multiplier - 16 - 1);
+ cfg->multiplier = multiplier;
+
+ /* f_rx_vco = bit_rate * 2**floor(log2(6e9/bit_rate)); */
+ utemp = 6e9;
+ f_rx_vco = DIV_ROUND_UP(utemp, bit_rate);
+ f_rx_vco = ilog2(f_rx_vco);
+ f_rx_vco = bit_rate * (1UL << f_rx_vco);
+
+ utemp = 4e9;
+ if (f_rx_vco < utemp)
+ f_rx_vco *= 2;
+
+ utemp = 5e9;
+ if (f_rx_vco > utemp)
+ cfg->rxvcosel = 4;
+ else
+ cfg->rxvcosel = 3;
+
+ /*
+ * aux0 = (bit_rate * 2**expon / ref_clk_int - (multiplier/2 + 16);
+ * aux0 = aux0 * 2** 16;
+ */
+ if (expon >= 0)
+ utemp = bit_rate * (1UL << expon);
+ else
+ utemp = bit_rate >> 1;
+
+ /*
+ * Need to store the floating-point values as they are
+ * essential for precise computations; thus, increasing
+ * the precision by 10^6.
+ */
+
+ utemp *= precision6;
+ utemp = DIV_ROUND_UP(utemp, ref_clk_int);
+ aux0 = utemp - (((multiplier >> 1) + 16)) * precision6;
+ cfg->quotient = (aux0 * (1UL << 16)) / precision6;
+
+ /* aux1 = ref_clk_int * bit_rate_divider */
+ aux1 = ref_clk_int * bit_rate_divider;
+
+ /*
+ * aux2 = bit_rate * bit_rate_divider * 2**expon;
+ * aux2 = aux2 - ((multiplier/2 + 16) * aux1 * 2**16);
+ * aux2 = aux2 - aux1 *aux0;
+ */
+
+ if (expon >= 0)
+ aux2 = bit_rate * (1UL << expon);
+ else
+ aux2 = bit_rate >> 1;
+
+ aux2 *= bit_rate_divider;
+ utemp = ((multiplier >> 1) + 16) * aux1;
+ aux2 = ((aux2 - utemp) * (1UL << 16)) - (cfg->quotient * aux1);
+
+ if (aux2 == 0) {
+ cfg->remainder = 0;
+ cfg->denominator = 1;
+ } else {
+ cfg->remainder = DIV_ROUND_UP(aux2, gcd(aux1, aux2));
+ cfg->denominator = DIV_ROUND_UP(aux1, gcd(aux1, aux2));
+ }
+
+ /* tx_clk_div = log2(round(vco_freq/base_rate) * 2) */
+ utemp = DIV_ROUND_UP(vco_freq, base_rate);
+ cfg->tx_clk_div = ilog2(utemp * 2);
+
+ /*
+ * FIXME: For rate 198000000, LUT has vco_freq 2 but calculator gives 3
+ * FIXME: For rate 198000000 and many others, LUT has cp_prop_holder 11,
+ * but calculator gives 12
+ */
+ utemp = 3.389e9;
+ utemp2 = 5e9;
+ if (vco_freq <= utemp) {
+ cfg->vco_freq = 2;
+ } else if (vco_freq < utemp2) {
+ cfg->vco_freq = 3;
+ } else {
+ DRM_DEV_ERROR(pll->dev, "bit_rate and vco_freq combination not supported: %llu",
+ vco_freq);
+ return -EINVAL;
+ }
+
+ /* stemp = (REF_CLK_MHZ/2**ref_ana_mpll_div) */
+ stemp = (REF_CLK_HZ / 1000000) * precision3;
+ stemp = DIV_ROUND_CLOSEST(stemp, 1UL << ref_ana_mpll_div);
+
+ /* stemp2 = cp_int_param[0] * stemp**2; */
+ stemp2 = stemp * stemp * cp_int_param[0];
+ stemp2 = DIV_ROUND_CLOSEST(stemp2, precision6);
+
+ /* stemp3 = cp_int_param[1] * stemp; */
+ stemp3 = stemp * cp_int_param[1];
+ stemp3 /= precision3;
+
+ /*
+ * cp_int_holder = floor(cp_int_param[0]*(stemp)**2
+ * + cp_int_param[1] * stemp
+ * + cp_int_param[2])
+ */
+ stemp3 += cp_int_param[2];
+ stemp3 += stemp2;
+
+ cfg->cp_int_holder = DIV_ROUND_CLOSEST(stemp3, precision6);
+
+ /* stemp2 = cp_prop_param[0] * stemp**2; */
+ stemp2 = stemp * stemp * cp_prop_param[0];
+ stemp2 = DIV_ROUND_CLOSEST(stemp2, precision6);
+
+ /* stemp3 = cp_prop_param[1] * stemp; */
+ stemp3 = (stemp * cp_prop_param[1]) / precision3;
+
+ /*
+ * cp_int_holder = floor(cp_prop_param[0]*(stemp)**2
+ * + cp_prop_param[1] * stemp
+ * + cp_prop_param[2])
+ */
+ stemp3 += stemp2 + cp_prop_param[2];
+
+ cfg->cp_prop_holder = DIV_ROUND_CLOSEST(stemp3, precision6) - 1;
+
+ return 0;
+}
+
+static int hdmi_eliza_pll_configure_pll(struct hdmi_pll_eliza *pll,
+ unsigned long rate,
+ unsigned long parent_rate)
+{
+ struct hdmi_phy *phy = pll_get_phy(pll);
+ const struct hdmi_eliza_phy_pll_reg_cfg *cfg;
+ struct hdmi_eliza_phy_pll_reg_cfg cfg_calc = {};
+ int ret;
+ u32 val;
+
+ cfg = hdmi_pll_eliza_mpll_lut_decoder(rate);
+ if (!cfg) {
+ DRM_INFO("no valid mpll entry fall back to calculator");
+
+ ret = hdmi_eliza_pll_calculator(pll, rate, parent_rate, &cfg_calc);
+ if (ret) {
+ DRM_ERROR("PLL calculation failed for rate %lu\n", rate);
+ return ret;
+ }
+ cfg = &cfg_calc;
+ }
+
+ hdmi_phy_update_bits(phy, REG_HDMI_ELIZA_PHY_CLOCK_PATTERN_CONFIG_0, BIT(0), cfg->clk_pat);
+
+ hdmi_phy_update_bits(phy, REG_HDMI_ELIZA_PHY_MISC_CONTROL_2, GENMASK(6, 4), cfg->rxvcosel << 4);
+ hdmi_phy_update_bits(phy, REG_HDMI_ELIZA_PHY_MISC_CONTROL_1, GENMASK(7, 2), 0x11 << 2);
+
+ hdmi_phy_write(phy, REG_HDMI_ELIZA_PHY_MISC_CONTROL_0, 0);
+ hdmi_phy_write(phy, REG_HDMI_ELIZA_PHY_MPLLB_CONTROL_10,
+ cfg->cp_int_holder & 0xff);
+ hdmi_phy_write(phy, REG_HDMI_ELIZA_PHY_MPLLB_CONTROL_12,
+ cfg->cp_prop_holder & 0xff);
+
+ hdmi_phy_update_bits(phy, REG_HDMI_ELIZA_PHY_MPLLB_CONTROL_0, BIT(0), BIT(0));
+ hdmi_phy_write(phy, REG_HDMI_ELIZA_PHY_MPLLB_CONTROL_2,
+ cfg->multiplier & 0xff);
+ hdmi_phy_write(phy, REG_HDMI_ELIZA_PHY_MPLLB_CONTROL_3,
+ (cfg->multiplier >> 8) & 0xff);
+
+ hdmi_phy_update_bits(phy, REG_HDMI_ELIZA_PHY_MPLLB_CONTROL_0, BIT(2), BIT(2));
+ hdmi_phy_write(phy, REG_HDMI_ELIZA_PHY_MPLLB_CONTROL_6, cfg->quotient & 0xff);
+ hdmi_phy_write(phy, REG_HDMI_ELIZA_PHY_MPLLB_CONTROL_7,
+ (cfg->quotient >> 8) & 0xff);
+ hdmi_phy_write(phy, REG_HDMI_ELIZA_PHY_MPLLB_CONTROL_8, cfg->remainder & 0xff);
+ hdmi_phy_write(phy, REG_HDMI_ELIZA_PHY_MPLLB_CONTROL_9,
+ (cfg->remainder >> 8) & 0xff);
+ hdmi_phy_write(phy, REG_HDMI_ELIZA_PHY_MPLLB_CONTROL_4, cfg->denominator & 0xff);
+ hdmi_phy_write(phy, REG_HDMI_ELIZA_PHY_MPLLB_CONTROL_5,
+ (cfg->denominator >> 8) & 0xff);
+ hdmi_phy_write(phy, REG_HDMI_ELIZA_PHY_MPLLB_CONTROL_1,
+ cfg->tx_clk_div & 0x7);
+ hdmi_phy_write(phy, REG_HDMI_ELIZA_PHY_MPLLB_CONTROL_14, 0x82);
+
+ val = hdmi_phy_read(phy, REG_HDMI_ELIZA_PHY_MPLLB_CONTROL_0);
+ val &= ~BIT(6);
+ val &= ~(0x3 << 3);
+ val |= (cfg->vco_freq & 0x3) << 3;
+ hdmi_phy_write(phy, REG_HDMI_ELIZA_PHY_MPLLB_CONTROL_0, val);
+
+ /*
+ * Ensure that vco configuration gets flushed to hardware before
+ * enabling the PLL
+ */
+ wmb();
+
+ pll->rate = rate;
+ pll->cfg = *cfg;
+
+ return 0;
+}
+
+static int hdmi_eliza_pll_set_clk_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long parent_rate)
+{
+ struct hdmi_pll_eliza *pll = hw_clk_to_pll(hw);
+
+ return hdmi_eliza_pll_configure_pll(pll, rate, parent_rate);
+};
+
+static int hdmi_eliza_pll_prepare(struct clk_hw *hw)
+{
+ struct hdmi_pll_eliza *pll = hw_clk_to_pll(hw);
+ struct hdmi_phy *phy = pll_get_phy(pll);
+
+ hdmi_phy_update_bits(phy, REG_HDMI_ELIZA_PHY_CLOCK_PATTERN_CONFIG_0, BIT(1), BIT(1));
+
+ /*
+ * This Synopsys PLL does not have a PLL lock-like register, thus there
+ * is no way to tell when the PLL actually locked.
+ * Returning now, would lead to stuck pclk or iface RCG clocks at off
+ * (disp_cc_mdss_hdmi_pclk_clk status stuck at 'off'),
+ * thus obviously the professional solution is to delay.
+ * 8 ms was figured out during tests, not based on any datasheet.
+ */
+ mdelay(8);
+
+ return 0;
+}
+
+static int hdmi_eliza_pll_determine_rate(struct clk_hw *hw,
+ struct clk_rate_request *req)
+{
+ req->rate = clamp_t(unsigned long, req->rate, HDMI_PLL_MIN_FREQ, HDMI_PLL_MAX_FREQ);
+
+ return 0;
+}
+
+static u64 hdmi_eliza_pll_vco_freq(u64 ref_clk_hz, u32 multiplier, u32 frac_quot,
+ u32 frac_rem, u32 frac_den)
+{
+ u64 num;
+ u64 den;
+
+ num = 32ULL * 65536ULL * frac_den +
+ (u64)multiplier * 65536ULL * frac_den +
+ 2ULL * ((u64)frac_quot * frac_den + frac_rem);
+
+ den = 2ULL * 65536ULL * frac_den;
+
+ return mul_u64_u64_div_u64(ref_clk_hz, num, den);
+}
+
+static unsigned long hdmi_eliza_pll_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct hdmi_pll_eliza *pll = hw_clk_to_pll(hw);
+ u64 rate;
+
+ rate = hdmi_eliza_pll_vco_freq(REF_CLK_HZ, pll->cfg.multiplier,
+ pll->cfg.quotient, pll->cfg.remainder,
+ pll->cfg.denominator);
+
+ /* rate = vco_freq * 2 / (10 * 2^tx_clk_div) */
+ rate *= 2;
+ do_div(rate, 10);
+ rate >>= pll->cfg.tx_clk_div;
+
+ return rate;
+}
+
+
+static void hdmi_eliza_pll_unprepare(struct clk_hw *hw)
+{
+ struct hdmi_pll_eliza *pll = hw_clk_to_pll(hw);
+ struct hdmi_phy *phy = pll_get_phy(pll);
+
+ hdmi_phy_update_bits(phy, REG_HDMI_ELIZA_PHY_CLOCK_PATTERN_CONFIG_0, BIT(1), 0);
+}
+
+static const struct clk_ops hdmi_eliza_pll_ops = {
+ .set_rate = hdmi_eliza_pll_set_clk_rate,
+ .determine_rate = hdmi_eliza_pll_determine_rate,
+ .recalc_rate = hdmi_eliza_pll_recalc_rate,
+ .prepare = hdmi_eliza_pll_prepare,
+ .unprepare = hdmi_eliza_pll_unprepare,
+};
+
+static const struct clk_init_data pll_init = {
+ .name = "hdmipll",
+ .ops = &hdmi_eliza_pll_ops,
+ .parent_data = (const struct clk_parent_data[]) {
+ { .fw_name = "xo", .name = "xo_board" },
+ },
+ .num_parents = 1,
+};
+
+int msm_hdmi_pll_eliza_init(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct hdmi_pll_eliza *pll;
+ struct hdmi_phy *phy;
+ int ret;
+
+ pll = devm_kzalloc(dev, sizeof(*pll), GFP_KERNEL);
+ if (!pll)
+ return -ENOMEM;
+
+ pll->dev = dev;
+ pll->clk_hw.init = &pll_init;
+
+ ret = devm_clk_hw_register(dev, &pll->clk_hw);
+ if (ret) {
+ DRM_DEV_ERROR(dev, "failed to register pll clock\n");
+ return ret;
+ }
+
+ ret = devm_of_clk_add_hw_provider(dev, of_clk_hw_simple_get, &pll->clk_hw);
+ if (ret) {
+ DRM_DEV_ERROR(dev, "failed to register clk provider: %d\n", ret);
+ return ret;
+ }
+
+ phy = dev_get_drvdata(dev);
+ phy->pll = pll;
+
+ return 0;
+}
+
+static const char * const hdmi_phy_eliza_clk_names[] = {
+ "iface",
+ "ref",
+ "xo",
+};
+
+static void hdmi_eliza_phy_txn_write(struct hdmi_phy *phy, u32 reg, u32 value)
+{
+ const int phy_txn_offset = REG_HDMI_ELIZA_PHY_TX1_CONTROL_0 - REG_HDMI_ELIZA_PHY_TX0_CONTROL_0;
+ int i;
+
+ for (i = 0; i < HDMI_PHY_TXN_CONTROL; i++)
+ hdmi_phy_write(phy, reg + i * phy_txn_offset, value);
+}
+
+static void hdmi_eliza_phy_txn_update(struct hdmi_phy *phy, u32 reg, u32 mask, u32 value)
+{
+ const int phy_txn_offset = REG_HDMI_ELIZA_PHY_TX1_CONTROL_0 - REG_HDMI_ELIZA_PHY_TX0_CONTROL_0;
+ int i;
+
+ for (i = 0; i < HDMI_PHY_TXN_CONTROL; i++)
+ hdmi_phy_update_bits(phy, reg + i * phy_txn_offset, mask, value);
+}
+
+static void hdmi_eliza_phy_configure(struct hdmi_phy *phy)
+{
+ hdmi_eliza_phy_txn_update(phy, REG_HDMI_ELIZA_PHY_TX0_CONTROL_8, BIT(2), BIT(2));
+ hdmi_phy_update_bits(phy, REG_HDMI_ELIZA_PHY_TX_COMMON_CONTROL_0, BIT(0), BIT(0));
+
+ usleep_range(5, 5000);
+
+ hdmi_phy_update_bits(phy, REG_HDMI_ELIZA_PHY_REFCLK_CONTROL_0, BIT(0), BIT(0));
+ hdmi_phy_update_bits(phy, REG_HDMI_ELIZA_PHY_REFCLK_CONTROL_1, GENMASK(2, 0), 0x1);
+ /* Select MPLLB */
+ hdmi_phy_update_bits(phy, REG_HDMI_ELIZA_PHY_MISC_CONTROL_3, BIT(0), 0);
+
+ hdmi_phy_write(phy, REG_HDMI_ELIZA_PHY_MPLLB_CONTROL_11, 0x18);
+ /*
+ * MPLLB_CONTROL_12: missing in programming sequence, but present in
+ * downstream
+ */
+ hdmi_phy_write(phy, REG_HDMI_ELIZA_PHY_MPLLB_CONTROL_12, 0x12);
+ hdmi_phy_write(phy, REG_HDMI_ELIZA_PHY_MPLLB_CONTROL_13, 0x18);
+ hdmi_phy_update_bits(phy, REG_HDMI_ELIZA_PHY_MPLLB_CONTROL_16, BIT(1), BIT(1));
+ /*
+ * MISC_CONTROL_2: missing in programming sequence, but present in
+ * downstream
+ */
+ hdmi_phy_write(phy, REG_HDMI_ELIZA_PHY_MISC_CONTROL_2, 0x4d);
+}
+
+static void hdmi_eliza_phy_tx_lane_config(struct hdmi_phy *phy,
+ unsigned long pixclock)
+{
+ const unsigned int bpp = 24;
+
+ /* Set BIT(3) for MPLLB and clear BIT(0) */
+ hdmi_eliza_phy_txn_update(phy, REG_HDMI_ELIZA_PHY_TX0_CONTROL_8, BIT(0) | BIT(3), BIT(3));
+ hdmi_eliza_phy_txn_update(phy, REG_HDMI_ELIZA_PHY_TX0_CONTROL_9, BIT(0) | BIT(1) | BIT(2), 0);
+ hdmi_eliza_phy_txn_update(phy, REG_HDMI_ELIZA_PHY_TX0_CONTROL_10, BIT(4) | BIT(5), BIT(4) | BIT(5));
+
+ hdmi_eliza_phy_txn_write(phy, REG_HDMI_ELIZA_PHY_TX0_CONTROL_7, 0);
+ hdmi_eliza_phy_txn_write(phy, REG_HDMI_ELIZA_PHY_TX0_CONTROL_6, 0);
+ hdmi_eliza_phy_txn_write(phy, REG_HDMI_ELIZA_PHY_TX0_CONTROL_5, 0x3e);
+
+ hdmi_eliza_phy_txn_update(phy, REG_HDMI_ELIZA_PHY_TX0_CONTROL_10, BIT(3), 0);
+
+ if (pixclock * bpp >= HDMI_PHY_MAX_BIT_RATE)
+ hdmi_phy_update_bits(phy, REG_HDMI_ELIZA_PHY_TX_COMMON_CONTROL_0, BIT(2), 0);
+ else
+ hdmi_phy_update_bits(phy, REG_HDMI_ELIZA_PHY_TX_COMMON_CONTROL_0, BIT(2), BIT(2));
+
+ hdmi_eliza_phy_txn_update(phy, REG_HDMI_ELIZA_PHY_TX0_CONTROL_9, BIT(3) | BIT(4), BIT(3) | BIT(4));
+}
+
+static void hdmi_eliza_phy_disable_hstx_reset(struct hdmi_phy *phy)
+{
+ hdmi_eliza_phy_txn_write(phy, REG_HDMI_ELIZA_PHY_TX0_CONTROL_0, 0);
+
+ hdmi_phy_write(phy, REG_HDMI_ELIZA_PHY_RX1_CONFIG_15, 0);
+ hdmi_phy_write(phy, REG_HDMI_ELIZA_PHY_RX2_CONFIG_15, 0);
+ hdmi_phy_write(phy, REG_HDMI_ELIZA_PHY_REXT_CONTROL_2, 0);
+}
+
+static int hdmi_eliza_phy_ready_poll(struct hdmi_phy *phy, u32 reg, u32 mask, u32 val)
+{
+ u32 state;
+ const u32 sleep_us = 2000;
+ const u32 timeout_us = 3000000;
+
+ if (readl_poll_timeout_atomic((phy->mmio + reg), state,
+ ((state & mask) == val),
+ sleep_us, timeout_us)) {
+ DRM_ERROR("poll timeout, reg: 0x%x status=0x%x", reg, state);
+
+ return -ETIMEDOUT;
+ }
+
+ return 0;
+}
+
+static int hdmi_eliza_phy_tx_ready_poll(struct hdmi_phy *phy)
+{
+ const int phy_txn_offset = REG_HDMI_ELIZA_PHY_TX1_CONTROL_0 - REG_HDMI_ELIZA_PHY_TX0_CONTROL_0;
+ int ret = 0;
+
+ /* Poll until TXn_ACK==0, downstream is wrong here */
+ for (int i = 0; i < HDMI_PHY_TXN_CONTROL; i++) {
+ ret |= hdmi_eliza_phy_ready_poll(phy,
+ REG_HDMI_ELIZA_PHY_TX0_CONTROL_2 + i * phy_txn_offset,
+ BIT(0), 0x0);
+ if (ret)
+ break;
+ }
+
+ return ret;
+}
+
+static int hdmi_eliza_phy_sram_init(struct hdmi_phy *phy)
+{
+ int ret;
+
+ ret = hdmi_eliza_phy_ready_poll(phy, REG_HDMI_ELIZA_PHY_SRAM_CONTROL_1, BIT(0), BIT(0));
+ if (ret)
+ return ret;
+
+ hdmi_phy_write(phy, REG_HDMI_ELIZA_PHY_CR_ADDRESS_LSB, 0x3);
+ hdmi_phy_write(phy, REG_HDMI_ELIZA_PHY_CR_ADDRESS_MSB, 0xe0);
+ hdmi_phy_write(phy, REG_HDMI_ELIZA_PHY_CR_WRDATA_LSB, 0x18);
+ hdmi_phy_write(phy, REG_HDMI_ELIZA_PHY_CR_WRDATA_MSB, 0);
+ hdmi_phy_write(phy, REG_HDMI_ELIZA_PHY_CR_ACCESS_CMD, 0x3);
+ ndelay(400);
+ hdmi_phy_write(phy, REG_HDMI_ELIZA_PHY_CR_ACCESS_CMD, 0);
+ hdmi_phy_write(phy, REG_HDMI_ELIZA_PHY_CR_ADDRESS_LSB, 0x5);
+ hdmi_phy_write(phy, REG_HDMI_ELIZA_PHY_CR_ADDRESS_MSB, 0x90);
+ hdmi_phy_write(phy, REG_HDMI_ELIZA_PHY_CR_WRDATA_LSB, 0xc);
+ hdmi_phy_write(phy, REG_HDMI_ELIZA_PHY_CR_WRDATA_MSB, 0);
+ hdmi_phy_write(phy, REG_HDMI_ELIZA_PHY_CR_ACCESS_CMD, 0x3);
+ ndelay(400);
+ hdmi_phy_write(phy, REG_HDMI_ELIZA_PHY_CR_ACCESS_CMD, 0x0);
+ hdmi_phy_write(phy, REG_HDMI_ELIZA_PHY_MISC_CONTROL_0, 0x7);
+ hdmi_phy_write(phy, REG_HDMI_ELIZA_PHY_CR_ADDRESS_LSB, 0x1a);
+ hdmi_phy_write(phy, REG_HDMI_ELIZA_PHY_CR_ADDRESS_MSB, 0xe0);
+ hdmi_phy_write(phy, REG_HDMI_ELIZA_PHY_CR_WRDATA_LSB, 0xa0);
+ hdmi_phy_write(phy, REG_HDMI_ELIZA_PHY_CR_WRDATA_MSB, 0);
+ hdmi_phy_write(phy, REG_HDMI_ELIZA_PHY_CR_ACCESS_CMD, 0x3);
+ ndelay(400);
+ hdmi_phy_write(phy, REG_HDMI_ELIZA_PHY_CR_ACCESS_CMD, 0);
+
+ hdmi_phy_update_bits(phy, REG_HDMI_ELIZA_PHY_SRAM_CONTROL_0,
+ BIT(1), BIT(1));
+
+ return 0;
+}
+
+static void hdmi_eliza_phy_init(struct hdmi_phy *phy,
+ unsigned long pixclock)
+{
+
+ /* pa_iso_disable() */
+ hdmi_phy_update_bits(phy, REG_HDMI_ELIZA_PHY_MISC_CONTROL_3,
+ BIT(1) | BIT(2) | BIT(3), 0);
+
+ /* sw_reset() */
+ hdmi_phy_write(phy, REG_HDMI_ELIZA_PHY_RESET_CONTROL_0, 0x1);
+
+ /* assert_tx_lane_reset() */
+ hdmi_eliza_phy_txn_update(phy, REG_HDMI_ELIZA_PHY_TX0_CONTROL_9, BIT(5), BIT(5));
+
+ /* phy_init_config() */
+ hdmi_eliza_phy_configure(phy);
+
+ hdmi_eliza_phy_tx_lane_config(phy, pixclock);
+
+ hdmi_eliza_pll_configure_pll(phy->pll, 396000000, 19200000);
+
+ /* sram_mode() (with SRAM init) */
+ hdmi_phy_update_bits(phy, REG_HDMI_ELIZA_PHY_SRAM_CONTROL_0,
+ BIT(0) | BIT(1), 0);
+ /* qcsram_init() */
+ hdmi_phy_write(phy, REG_HDMI_ELIZA_PHY_QCSRAM_CONFIG_3, BIT(0));
+ usleep_range(5, 5000);
+ hdmi_phy_write(phy, REG_HDMI_ELIZA_PHY_QCSRAM_CONFIG_3, 0);
+
+ /* deassert_tx_lane_reset() */
+ hdmi_eliza_phy_txn_update(phy, REG_HDMI_ELIZA_PHY_TX0_CONTROL_9, BIT(5), 0);
+
+ hdmi_eliza_phy_disable_hstx_reset(phy);
+ hdmi_phy_write(phy, REG_HDMI_ELIZA_PHY_RESET_CONTROL_0, 0);
+
+ if (hdmi_eliza_phy_sram_init(phy))
+ return;
+
+ if (hdmi_eliza_phy_tx_ready_poll(phy))
+ return;
+};
+
+static void hdmi_eliza_phy_powerup(struct hdmi_phy *phy,
+ unsigned long pixclock)
+{
+ hdmi_phy_update_bits(phy, REG_HDMI_ELIZA_PHY_TX_COMMON_CONTROL_0, BIT(1), BIT(1));
+}
+
+static void hdmi_eliza_phy_deinit(struct hdmi_phy *phy)
+{
+ /* sw_reset() */
+ hdmi_phy_write(phy, REG_HDMI_ELIZA_PHY_RESET_CONTROL_0, 1);
+ hdmi_eliza_phy_txn_write(phy, REG_HDMI_ELIZA_PHY_TX0_CONTROL_0, 1);
+ /* assert_tx_lane_reset() */
+ hdmi_eliza_phy_txn_update(phy, REG_HDMI_ELIZA_PHY_TX0_CONTROL_9, BIT(5), BIT(5));
+ /* pa_iso_enable() */
+ hdmi_phy_update_bits(phy, REG_HDMI_ELIZA_PHY_MISC_CONTROL_3,
+ BIT(1) | BIT(2) | BIT(3), BIT(1) | BIT(2) | BIT(3));
+}
+
+static void hdmi_eliza_phy_powerdown(struct hdmi_phy *phy)
+{
+ hdmi_phy_update_bits(phy, REG_HDMI_ELIZA_PHY_TX_COMMON_CONTROL_0, BIT(1), 0);
+}
+
+const struct hdmi_phy_cfg msm_hdmi_phy_eliza_cfg = {
+ .type = MSM_HDMI_PHY_ELIZA,
+ .init = hdmi_eliza_phy_init,
+ .deinit = hdmi_eliza_phy_deinit,
+ .powerup = hdmi_eliza_phy_powerup,
+ .powerdown = hdmi_eliza_phy_powerdown,
+ .clk_names = hdmi_phy_eliza_clk_names,
+ .num_clks = ARRAY_SIZE(hdmi_phy_eliza_clk_names),
+};
diff --git a/drivers/gpu/drm/msm/registers/display/hdmi.xml b/drivers/gpu/drm/msm/registers/display/hdmi.xml
index 0ebb96297dae..4afc36fef172 100644
--- a/drivers/gpu/drm/msm/registers/display/hdmi.xml
+++ b/drivers/gpu/drm/msm/registers/display/hdmi.xml
@@ -1101,4 +1101,144 @@ xsi:schemaLocation="https://gitlab.freedesktop.org/freedreno/ rules-fd.xsd">
<reg32 offset="0x002C" name="LANE_MODE"/>
</domain>
+<domain name="HDMI_ELIZA_PHY" width="32">
+ <reg32 offset="0x0014" name="RESET_CONTROL_0"/>
+ <reg32 offset="0x0018" name="MISC_CONTROL_0"/>
+ <reg32 offset="0x001c" name="MISC_CONTROL_1"/>
+ <reg32 offset="0x0020" name="MISC_CONTROL_2"/>
+ <reg32 offset="0x0024" name="MISC_CONTROL_3"/>
+ <reg32 offset="0x0028" name="SRAM_CONTROL_0"/>
+ <reg32 offset="0x002c" name="SRAM_CONTROL_1"/>
+ <reg32 offset="0x0038" name="CR_ACCESS_CMD"/>
+ <reg32 offset="0x0040" name="CR_ADDRESS_LSB"/>
+ <reg32 offset="0x0044" name="CR_ADDRESS_MSB"/>
+ <reg32 offset="0x0048" name="CR_WRDATA_LSB"/>
+ <reg32 offset="0x004c" name="CR_WRDATA_MSB"/>
+
+ <reg32 offset="0x0060" name="REXT_CONTROL_2"/>
+ <reg32 offset="0x006c" name="REFCLK_CONTROL_0"/>
+ <reg32 offset="0x0070" name="REFCLK_CONTROL_1"/>
+ <reg32 offset="0x0074" name="REFCLK_CONTROL_2"/>
+
+ <reg32 offset="0x0078" name="MPLLA_CONTROL_0"/>
+ <reg32 offset="0x007c" name="MPLLA_CONTROL_1"/>
+ <reg32 offset="0x0080" name="MPLLA_CONTROL_2"/>
+ <reg32 offset="0x0084" name="MPLLA_CONTROL_3"/>
+ <reg32 offset="0x0088" name="MPLLA_CONTROL_4"/>
+ <reg32 offset="0x008c" name="MPLLA_CONTROL_5"/>
+ <reg32 offset="0x0090" name="MPLLA_CONTROL_6"/>
+ <reg32 offset="0x0094" name="MPLLA_CONTROL_7"/>
+ <reg32 offset="0x0098" name="MPLLA_CONTROL_8"/>
+ <reg32 offset="0x009c" name="MPLLA_CONTROL_9"/>
+ <reg32 offset="0x00a0" name="MPLLA_CONTROL_10"/>
+ <reg32 offset="0x00a4" name="MPLLA_CONTROL_11"/>
+ <reg32 offset="0x00a8" name="MPLLA_CONTROL_12"/>
+ <reg32 offset="0x00ac" name="MPLLA_CONTROL_13"/>
+ <reg32 offset="0x00b0" name="MPLLA_CONTROL_14"/>
+ <reg32 offset="0x00b4" name="MPLLA_CONTROL_15"/>
+ <reg32 offset="0x00b8" name="MPLLA_CONTROL_16"/>
+ <reg32 offset="0x00bc" name="MPLLA_CONTROL_17"/>
+ <reg32 offset="0x00c0" name="MPLLA_CONTROL_18"/>
+ <reg32 offset="0x00c4" name="MPLLA_CONTROL_19"/>
+ <reg32 offset="0x00c8" name="MPLLA_CONTROL_20"/>
+ <reg32 offset="0x00cc" name="MPLLA_CONTROL_21"/>
+ <reg32 offset="0x00d0" name="MPLLA_CONTROL_22"/>
+ <reg32 offset="0x00d4" name="MPLLA_CONTROL_23"/>
+ <reg32 offset="0x00d8" name="MPLLA_CONTROL_24"/>
+
+ <reg32 offset="0x00dc" name="MPLLB_CONTROL_0"/>
+ <reg32 offset="0x00e0" name="MPLLB_CONTROL_1"/>
+ <reg32 offset="0x00e4" name="MPLLB_CONTROL_2"/>
+ <reg32 offset="0x00e8" name="MPLLB_CONTROL_3"/>
+ <reg32 offset="0x00ec" name="MPLLB_CONTROL_4"/>
+ <reg32 offset="0x00f0" name="MPLLB_CONTROL_5"/>
+ <reg32 offset="0x00f4" name="MPLLB_CONTROL_6"/>
+ <reg32 offset="0x00f8" name="MPLLB_CONTROL_7"/>
+ <reg32 offset="0x00fc" name="MPLLB_CONTROL_8"/>
+ <reg32 offset="0x0100" name="MPLLB_CONTROL_9"/>
+ <reg32 offset="0x0104" name="MPLLB_CONTROL_10"/>
+ <reg32 offset="0x0108" name="MPLLB_CONTROL_11"/>
+ <reg32 offset="0x010c" name="MPLLB_CONTROL_12"/>
+ <reg32 offset="0x0110" name="MPLLB_CONTROL_13"/>
+ <reg32 offset="0x0114" name="MPLLB_CONTROL_14"/>
+ <reg32 offset="0x0118" name="MPLLB_CONTROL_15"/>
+ <reg32 offset="0x011c" name="MPLLB_CONTROL_16"/>
+ <reg32 offset="0x0120" name="MPLLB_CONTROL_17"/>
+ <reg32 offset="0x0124" name="MPLLB_CONTROL_18"/>
+ <reg32 offset="0x0128" name="MPLLB_CONTROL_19"/>
+ <reg32 offset="0x012c" name="MPLLB_CONTROL_20"/>
+ <reg32 offset="0x0130" name="MPLLB_CONTROL_21"/>
+ <reg32 offset="0x0134" name="MPLLB_CONTROL_22"/>
+ <reg32 offset="0x0138" name="MPLLB_CONTROL_23"/>
+ <reg32 offset="0x013c" name="MPLLB_CONTROL_24"/>
+
+ <reg32 offset="0x0140" name="TX_COMMON_CONTROL_0"/>
+ <reg32 offset="0x0144" name="TX_COMMON_CONTROL_1"/>
+
+ <reg32 offset="0x0148" name="TX0_CONTROL_0"/>
+ <reg32 offset="0x014c" name="TX0_CONTROL_1"/>
+ <reg32 offset="0x0150" name="TX0_CONTROL_2"/>
+ <reg32 offset="0x0154" name="TX0_CONTROL_3"/>
+ <reg32 offset="0x0158" name="TX0_CONTROL_4"/>
+ <reg32 offset="0x015c" name="TX0_CONTROL_5"/>
+ <reg32 offset="0x0160" name="TX0_CONTROL_6"/>
+ <reg32 offset="0x0164" name="TX0_CONTROL_7"/>
+ <reg32 offset="0x0168" name="TX0_CONTROL_8"/>
+ <reg32 offset="0x016c" name="TX0_CONTROL_9"/>
+ <reg32 offset="0x0170" name="TX0_CONTROL_10"/>
+ <reg32 offset="0x0174" name="TX0_CONTROL_11"/>
+ <reg32 offset="0x0178" name="TX0_CONTROL_12"/>
+
+ <reg32 offset="0x017c" name="TX1_CONTROL_0"/>
+ <reg32 offset="0x0180" name="TX1_CONTROL_1"/>
+ <reg32 offset="0x0184" name="TX1_CONTROL_2"/>
+ <reg32 offset="0x0188" name="TX1_CONTROL_3"/>
+ <reg32 offset="0x018c" name="TX1_CONTROL_4"/>
+ <reg32 offset="0x0190" name="TX1_CONTROL_5"/>
+ <reg32 offset="0x0194" name="TX1_CONTROL_6"/>
+ <reg32 offset="0x0198" name="TX1_CONTROL_7"/>
+ <reg32 offset="0x019c" name="TX1_CONTROL_8"/>
+ <reg32 offset="0x01a0" name="TX1_CONTROL_9"/>
+ <reg32 offset="0x01a4" name="TX1_CONTROL_10"/>
+ <reg32 offset="0x01a8" name="TX1_CONTROL_11"/>
+ <reg32 offset="0x01ac" name="TX1_CONTROL_12"/>
+
+ <reg32 offset="0x01b0" name="TX2_CONTROL_0"/>
+ <reg32 offset="0x01b4" name="TX2_CONTROL_1"/>
+ <reg32 offset="0x01b8" name="TX2_CONTROL_2"/>
+ <reg32 offset="0x01bc" name="TX2_CONTROL_3"/>
+ <reg32 offset="0x01c0" name="TX2_CONTROL_4"/>
+ <reg32 offset="0x01c4" name="TX2_CONTROL_5"/>
+ <reg32 offset="0x01c8" name="TX2_CONTROL_6"/>
+ <reg32 offset="0x01cc" name="TX2_CONTROL_7"/>
+ <reg32 offset="0x01d0" name="TX2_CONTROL_8"/>
+ <reg32 offset="0x01d4" name="TX2_CONTROL_9"/>
+ <reg32 offset="0x01d8" name="TX2_CONTROL_10"/>
+ <reg32 offset="0x01dc" name="TX2_CONTROL_11"/>
+ <reg32 offset="0x01e0" name="TX2_CONTROL_12"/>
+
+ <reg32 offset="0x01e4" name="TX3_CONTROL_0"/>
+ <reg32 offset="0x01e8" name="TX3_CONTROL_1"/>
+ <reg32 offset="0x01ec" name="TX3_CONTROL_2"/>
+ <reg32 offset="0x01f0" name="TX3_CONTROL_3"/>
+ <reg32 offset="0x01f4" name="TX3_CONTROL_4"/>
+ <reg32 offset="0x01f8" name="TX3_CONTROL_5"/>
+ <reg32 offset="0x01fc" name="TX3_CONTROL_6"/>
+ <reg32 offset="0x0200" name="TX3_CONTROL_7"/>
+ <reg32 offset="0x0204" name="TX3_CONTROL_8"/>
+ <reg32 offset="0x0208" name="TX3_CONTROL_9"/>
+ <reg32 offset="0x020c" name="TX3_CONTROL_10"/>
+ <reg32 offset="0x0210" name="TX3_CONTROL_11"/>
+ <reg32 offset="0x0214" name="TX3_CONTROL_12"/>
+
+ <reg32 offset="0x0218" name="QCSRAM_CONFIG_0"/>
+ <reg32 offset="0x021c" name="QCSRAM_CONFIG_1"/>
+ <reg32 offset="0x0220" name="QCSRAM_CONFIG_2"/>
+ <reg32 offset="0x0224" name="QCSRAM_CONFIG_3"/>
+ <reg32 offset="0x0228" name="CLOCK_PATTERN_CONFIG_0"/>
+
+ <reg32 offset="0x0270" name="RX1_CONFIG_15"/>
+ <reg32 offset="0x02b4" name="RX2_CONFIG_15"/>
+</domain>
+
</database>
--
2.53.0
^ permalink raw reply related [flat|nested] 38+ messages in thread* [PATCH RFC/DO NOT MERGE 10/12] drm/msm/hdmi_phy_eliza: Add support for Synopsys-based HDMI phy on Eliza
@ 2026-08-28 14:05 ` Krzysztof Kozlowski
0 siblings, 0 replies; 38+ messages in thread
From: Krzysztof Kozlowski @ 2026-08-28 14:05 UTC (permalink / raw)
To: Rob Clark, Dmitry Baryshkov, Abhinav Kumar, Jessica Zhang,
Sean Paul, Marijn Suijten, David Airlie, Simona Vetter,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Vinod Koul, Neil Armstrong,
Manivannan Sadhasivam, Bjorn Andersson, Konrad Dybcio
Cc: linux-arm-msm, dri-devel, freedreno, linux-kernel, devicetree,
Krzysztof Kozlowski, Krzysztof Kozlowski, linux-phy
Add driver for HDMI phy block from Synopsys used on Eliza SoC. There is
no similarity regarding older HDMI phys.
Core parts for handling HDMI phy needs some adjustments as well, because
according to programming sequence:
1. The HDMI PHY should be initialized before preparing its PLL.
2. Final power up - enabling the TX lanes - should be performed after
PLL is prepared.
Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski@oss.qualcomm.com>
---
drivers/gpu/drm/msm/Makefile | 1 +
drivers/gpu/drm/msm/hdmi/hdmi.h | 18 +
drivers/gpu/drm/msm/hdmi/hdmi_phy.c | 12 +-
drivers/gpu/drm/msm/hdmi/hdmi_phy_eliza.c | 723 +++++++++++++++++++++++++
drivers/gpu/drm/msm/registers/display/hdmi.xml | 140 +++++
5 files changed, 892 insertions(+), 2 deletions(-)
diff --git a/drivers/gpu/drm/msm/Makefile b/drivers/gpu/drm/msm/Makefile
index d0c3a4c6703b..ae343a250bb0 100644
--- a/drivers/gpu/drm/msm/Makefile
+++ b/drivers/gpu/drm/msm/Makefile
@@ -43,6 +43,7 @@ msm-display-$(CONFIG_DRM_MSM_HDMI) += \
hdmi/hdmi_phy_8998.o \
hdmi/hdmi_phy_8x60.o \
hdmi/hdmi_phy_8x74.o \
+ hdmi/hdmi_phy_eliza.o \
hdmi/hdmi_pll_8960.o \
msm-display-$(CONFIG_DRM_MSM_MDP4) += \
diff --git a/drivers/gpu/drm/msm/hdmi/hdmi.h b/drivers/gpu/drm/msm/hdmi/hdmi.h
index 2fa9bec455b4..945fbb4d9888 100644
--- a/drivers/gpu/drm/msm/hdmi/hdmi.h
+++ b/drivers/gpu/drm/msm/hdmi/hdmi.h
@@ -149,6 +149,7 @@ enum hdmi_phy_type {
MSM_HDMI_PHY_8x74,
MSM_HDMI_PHY_8996,
MSM_HDMI_PHY_8998,
+ MSM_HDMI_PHY_ELIZA,
MSM_HDMI_PHY_MAX,
};
@@ -169,6 +170,7 @@ extern const struct hdmi_phy_cfg msm_hdmi_phy_8960_cfg;
extern const struct hdmi_phy_cfg msm_hdmi_phy_8x74_cfg;
extern const struct hdmi_phy_cfg msm_hdmi_phy_8996_cfg;
extern const struct hdmi_phy_cfg msm_hdmi_phy_8998_cfg;
+extern const struct hdmi_phy_cfg msm_hdmi_phy_eliza_cfg;
struct hdmi_phy {
struct platform_device *pdev;
@@ -190,6 +192,16 @@ static inline u32 hdmi_phy_read(struct hdmi_phy *phy, u32 reg)
return readl(phy->mmio + reg);
}
+static inline void hdmi_phy_update_bits(struct hdmi_phy *phy, u32 reg, u32 mask, u32 data)
+{
+ u32 val;
+
+ val = hdmi_phy_read(phy, reg);
+ val &= ~mask;
+ val |= data & mask;
+ hdmi_phy_write(phy, reg, val);
+}
+
int msm_hdmi_phy_resource_enable(struct hdmi_phy *phy);
void msm_hdmi_phy_resource_disable(struct hdmi_phy *phy);
void msm_hdmi_phy_init(struct hdmi_phy *phy, unsigned long pixclock);
@@ -203,6 +215,7 @@ void __exit msm_hdmi_phy_driver_unregister(void);
int msm_hdmi_pll_8960_init(struct platform_device *pdev);
int msm_hdmi_pll_8996_init(struct platform_device *pdev);
int msm_hdmi_pll_8998_init(struct platform_device *pdev);
+int msm_hdmi_pll_eliza_init(struct platform_device *pdev);
#else
static inline int msm_hdmi_pll_8960_init(struct platform_device *pdev)
{
@@ -218,6 +231,11 @@ static inline int msm_hdmi_pll_8998_init(struct platform_device *pdev)
{
return -ENODEV;
}
+
+static inline int msm_hdmi_pll_eliza_init(struct platform_device *pdev)
+{
+ return -ENODEV;
+}
#endif
/*
diff --git a/drivers/gpu/drm/msm/hdmi/hdmi_phy.c b/drivers/gpu/drm/msm/hdmi/hdmi_phy.c
index 8ce87d9adf74..94dc0e5c5c3e 100644
--- a/drivers/gpu/drm/msm/hdmi/hdmi_phy.c
+++ b/drivers/gpu/drm/msm/hdmi/hdmi_phy.c
@@ -141,6 +141,9 @@ static int msm_hdmi_phy_pll_init(struct platform_device *pdev,
case MSM_HDMI_PHY_8998:
ret = msm_hdmi_pll_8998_init(pdev);
break;
+ case MSM_HDMI_PHY_ELIZA:
+ ret = msm_hdmi_pll_eliza_init(pdev);
+ break;
/*
* we don't have PLL support for these, don't report an error for now
*/
@@ -168,13 +171,17 @@ static int msm_hdmi_phy_probe(struct platform_device *pdev)
if (!phy->cfg)
return -ENODEV;
- phy->mmio = msm_ioremap(pdev, "hdmi_phy");
+ if (phy->cfg->num_regs)
+ phy->mmio = msm_ioremap(pdev, "hdmi_phy");
+ else
+ phy->mmio = msm_ioremap(pdev, NULL);
if (IS_ERR(phy->mmio)) {
DRM_DEV_ERROR(dev, "%s: failed to map phy base\n", __func__);
return -ENOMEM;
}
phy->pdev = pdev;
+ platform_set_drvdata(pdev, phy);
ret = msm_hdmi_phy_resource_init(phy);
if (ret)
@@ -195,7 +202,6 @@ static int msm_hdmi_phy_probe(struct platform_device *pdev)
msm_hdmi_phy_resource_disable(phy);
- platform_set_drvdata(pdev, phy);
return 0;
}
@@ -218,6 +224,8 @@ static const struct of_device_id msm_hdmi_phy_dt_match[] = {
.data = &msm_hdmi_phy_8996_cfg },
{ .compatible = "qcom,hdmi-phy-8998",
.data = &msm_hdmi_phy_8998_cfg },
+ { .compatible = "qcom,eliza-hdmi-phy",
+ .data = &msm_hdmi_phy_eliza_cfg },
{}
};
MODULE_DEVICE_TABLE(of, msm_hdmi_phy_dt_match);
diff --git a/drivers/gpu/drm/msm/hdmi/hdmi_phy_eliza.c b/drivers/gpu/drm/msm/hdmi/hdmi_phy_eliza.c
new file mode 100644
index 000000000000..fad4e828154e
--- /dev/null
+++ b/drivers/gpu/drm/msm/hdmi/hdmi_phy_eliza.c
@@ -0,0 +1,723 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+#include <linux/array_size.h>
+#include <linux/bitfield.h>
+#include <linux/clk-provider.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/gcd.h>
+#include <linux/iopoll.h>
+#include <linux/minmax.h>
+#include <linux/types.h>
+
+#include "hdmi.h"
+
+#define REF_CLK_HZ 38400000 /* 38.4 MHz */
+#define HDMI_PLL_MAX_FREQ 600000000 /* 600 MHz */
+/* Unscrambled clock freq threshold */
+#define HDMI_PLL_HIGH_FREQ 340000000 /* 340 Mhz */
+#define HDMI_PLL_MIN_FREQ 25000000
+
+#define HDMI_PHY_MAX_BIT_RATE 2500000000 /* 2.5 Gbps */
+
+/* Number of TX lanes */
+#define HDMI_PHY_TXN_CONTROL 4
+
+#define MPLL(mul, qut, rem, den, clkd, vcof, pat, rxv, in, prop) \
+ .multiplier = (mul), \
+ .quotient = (qut), \
+ .remainder = (rem), \
+ .denominator = (den), \
+ .tx_clk_div = (clkd), \
+ .vco_freq = (vcof), \
+ .clk_pat = (pat), \
+ .rxvcosel = (rxv), \
+ .cp_int_holder = (in), \
+ .cp_prop_holder = (prop)
+
+struct hdmi_eliza_phy_pll_reg_cfg {
+ u32 vco_freq;
+ u32 rxvcosel;
+ u32 tx_clk_div;
+ u32 cp_int_holder;
+ u32 cp_prop_holder;
+ u32 quotient;
+ u32 remainder;
+ u32 multiplier;
+ u32 denominator;
+ u32 clk_pat;
+};
+
+struct hdmi_pll_eliza {
+ struct device *dev;
+ struct clk_hw clk_hw;
+ unsigned long rate;
+ struct hdmi_eliza_phy_pll_reg_cfg cfg;
+};
+
+
+struct hdmi_pll_eliza_mpll {
+ unsigned long rate;
+ struct hdmi_eliza_phy_pll_reg_cfg cfg;
+};
+
+static const struct hdmi_pll_eliza_mpll mpll_lut[] = {
+ { 25200000, { MPLL(0xb0, 0xe525, 0, 1, 5, 2, 0, 3, 0xc, 0x11) }, },
+ { 27000000, { MPLL(0xc0, 0x8000, 0, 1, 5, 2, 0, 3, 0xc, 0x11) }, },
+ { 27027000, { MPLL(0xc0, 0x9ccc, 4, 1, 5, 2, 0, 3, 0xb, 0x12) }, },
+ { 54000000, { MPLL(0xc0, 0x8000, 0, 1, 4, 2, 0, 3, 0xb, 0x11) }, },
+ { 59400000, { MPLL(0xd6, 0xc000, 0, 1, 4, 2, 0, 3, 0xb, 0x12) }, },
+ { 72000000, { MPLL(0x76, 0x0000, 0, 1, 3, 3, 0, 4, 0xc, 0x10) }, },
+ { 74250000, { MPLL(0x7a, 0x5800, 0, 1, 3, 3, 0, 4, 0xb, 0x12) }, },
+ { 82500000, { MPLL(0x8a, 0xf000, 0, 1, 3, 3, 0, 4, 0xb, 0x11) }, },
+ { 90000000, { MPLL(0x9a, 0xc000, 0, 1, 3, 2, 0, 4, 0xd, 0x11) }, },
+ { 99000000, { MPLL(0xae, 0x2000, 0, 1, 3, 2, 0, 4, 0xc, 0x11) }, },
+ { 108000000, { MPLL(0xc0, 0x8000, 0, 1, 3, 2, 0, 3, 0xb, 0x11) }, },
+ { 118800000, { MPLL(0xd6, 0xc000, 0, 1, 3, 2, 0, 3, 0xb, 0x12) }, },
+ { 148500000, { MPLL(0x7a, 0x5800, 0, 1, 2, 3, 0, 4, 0xc, 0x11) }, },
+ { 165000000, { MPLL(0x8a, 0xf000, 0, 1, 2, 3, 0, 4, 0xb, 0x11) }, },
+ { 185625000, { MPLL(0xa0, 0xae00, 0, 1, 2, 2, 0, 4, 0xc, 0x11) }, },
+ { 198000000, { MPLL(0xae, 0x2000, 0, 1, 2, 2, 0, 4, 0xc, 0x11) }, },
+ { 297000000, { MPLL(0x7a, 0x5800, 0, 1, 1, 3, 0, 4, 0xc, 0x11) }, },
+ { 371250000, { MPLL(0xa0, 0xae00, 0, 1, 1, 2, 1, 4, 0xc, 0x11) }, },
+ { 396000000, { MPLL(0xae, 0x2000, 0, 1, 1, 2, 1, 4, 0xc, 0x11) }, },
+ { 495000000, { MPLL(0xe0, 0xe800, 0, 1, 1, 2, 1, 3, 0xb, 0x12) }, },
+ { 594000000, { MPLL(0x7a, 0x5800, 0, 1, 0, 3, 1, 4, 0xc, 0x11) }, },
+};
+
+#define hw_clk_to_pll(x) container_of(x, struct hdmi_pll_eliza, clk_hw)
+
+static struct hdmi_phy *pll_get_phy(struct hdmi_pll_eliza *pll)
+{
+ return dev_get_drvdata(pll->dev);
+}
+
+static const struct hdmi_eliza_phy_pll_reg_cfg *
+hdmi_pll_eliza_mpll_lut_decoder(unsigned long rate)
+{
+ const struct hdmi_eliza_phy_pll_reg_cfg *cfg = NULL;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(mpll_lut); i++) {
+ if (rate == mpll_lut[i].rate) {
+ cfg = &mpll_lut[i].cfg;
+ break;
+ }
+ }
+
+ return cfg;
+}
+
+static int hdmi_eliza_pll_calculator(struct hdmi_pll_eliza *pll,
+ unsigned long rate,
+ unsigned long parent_rate,
+ struct hdmi_eliza_phy_pll_reg_cfg *cfg)
+{
+ const s64 bit_rate_multiplier = 1000;
+ const s64 bit_rate_divider = 1000;
+ const s64 cp_int_param[3] = {4524, -679588, 30860643};
+ const s64 cp_prop_param[3] = {8023, -1160252, 51717042};
+ const u64 gmult = 1e4;
+ s64 expon, base_rate, bit_rate;
+ s64 ref_clk_int, ref_clk_div;
+ u64 aux0, aux1, aux2, vco_freq;
+ u64 utemp, utemp2, multiplier, f_rx_vco;
+ s64 stemp, stemp2, stemp3;
+ s32 choice1, ref_ana_mpll_div;
+ s64 precision3 = 1e3;
+ s64 precision6 = 1e6;
+
+ if (rate > HDMI_PLL_HIGH_FREQ)
+ cfg->clk_pat = 1;
+ else
+ cfg->clk_pat = 0;
+
+ /*
+ * base_rate = clock_khz * bit_rate_multiplier / 1000
+ * Division by 1000, nullifies the conversion from KHz to Hz.
+ */
+ base_rate = rate / 1000 * gmult;
+
+ /* bit_rate = clock_khz * bit_rate_multiplier/bit_rate_divider. */
+ utemp = DIV_ROUND_UP(bit_rate_multiplier, bit_rate_divider);
+
+ bit_rate = base_rate * utemp;
+
+ /*
+ * REF_CLK_HZ: 38.4 MHz
+ * min_ref_clk: 50
+ * choice1 = floor(log2(REF_CLK_HZ/min_ref_clk))
+ * choice1 = floor(-0.38)
+ */
+ choice1 = -1;
+ ref_ana_mpll_div = max_t(s32, choice1, 0);
+
+ /* ref_clk_div = 2**ref_ana_mpll_div; */
+ ref_clk_div = 1UL << ref_ana_mpll_div;
+ ref_clk_int = DIV_ROUND_UP(REF_CLK_HZ, ref_clk_div);
+
+ /* expon = floor(log2(4.999999e9/base_rate)) */
+ utemp = 4.999999e9;
+
+ expon = fls64(utemp / base_rate) - 1;
+ if (expon >= 0)
+ vco_freq = base_rate * (1UL << expon);
+ else
+ vco_freq = base_rate >> 1;
+
+ /* multiplier = 2*(floor(bit_rate) * 2**expon / ref_clk_int) -16) */
+ multiplier = DIV_ROUND_UP(vco_freq, ref_clk_int);
+ multiplier = 2 * (multiplier - 16 - 1);
+ cfg->multiplier = multiplier;
+
+ /* f_rx_vco = bit_rate * 2**floor(log2(6e9/bit_rate)); */
+ utemp = 6e9;
+ f_rx_vco = DIV_ROUND_UP(utemp, bit_rate);
+ f_rx_vco = ilog2(f_rx_vco);
+ f_rx_vco = bit_rate * (1UL << f_rx_vco);
+
+ utemp = 4e9;
+ if (f_rx_vco < utemp)
+ f_rx_vco *= 2;
+
+ utemp = 5e9;
+ if (f_rx_vco > utemp)
+ cfg->rxvcosel = 4;
+ else
+ cfg->rxvcosel = 3;
+
+ /*
+ * aux0 = (bit_rate * 2**expon / ref_clk_int - (multiplier/2 + 16);
+ * aux0 = aux0 * 2** 16;
+ */
+ if (expon >= 0)
+ utemp = bit_rate * (1UL << expon);
+ else
+ utemp = bit_rate >> 1;
+
+ /*
+ * Need to store the floating-point values as they are
+ * essential for precise computations; thus, increasing
+ * the precision by 10^6.
+ */
+
+ utemp *= precision6;
+ utemp = DIV_ROUND_UP(utemp, ref_clk_int);
+ aux0 = utemp - (((multiplier >> 1) + 16)) * precision6;
+ cfg->quotient = (aux0 * (1UL << 16)) / precision6;
+
+ /* aux1 = ref_clk_int * bit_rate_divider */
+ aux1 = ref_clk_int * bit_rate_divider;
+
+ /*
+ * aux2 = bit_rate * bit_rate_divider * 2**expon;
+ * aux2 = aux2 - ((multiplier/2 + 16) * aux1 * 2**16);
+ * aux2 = aux2 - aux1 *aux0;
+ */
+
+ if (expon >= 0)
+ aux2 = bit_rate * (1UL << expon);
+ else
+ aux2 = bit_rate >> 1;
+
+ aux2 *= bit_rate_divider;
+ utemp = ((multiplier >> 1) + 16) * aux1;
+ aux2 = ((aux2 - utemp) * (1UL << 16)) - (cfg->quotient * aux1);
+
+ if (aux2 == 0) {
+ cfg->remainder = 0;
+ cfg->denominator = 1;
+ } else {
+ cfg->remainder = DIV_ROUND_UP(aux2, gcd(aux1, aux2));
+ cfg->denominator = DIV_ROUND_UP(aux1, gcd(aux1, aux2));
+ }
+
+ /* tx_clk_div = log2(round(vco_freq/base_rate) * 2) */
+ utemp = DIV_ROUND_UP(vco_freq, base_rate);
+ cfg->tx_clk_div = ilog2(utemp * 2);
+
+ /*
+ * FIXME: For rate 198000000, LUT has vco_freq 2 but calculator gives 3
+ * FIXME: For rate 198000000 and many others, LUT has cp_prop_holder 11,
+ * but calculator gives 12
+ */
+ utemp = 3.389e9;
+ utemp2 = 5e9;
+ if (vco_freq <= utemp) {
+ cfg->vco_freq = 2;
+ } else if (vco_freq < utemp2) {
+ cfg->vco_freq = 3;
+ } else {
+ DRM_DEV_ERROR(pll->dev, "bit_rate and vco_freq combination not supported: %llu",
+ vco_freq);
+ return -EINVAL;
+ }
+
+ /* stemp = (REF_CLK_MHZ/2**ref_ana_mpll_div) */
+ stemp = (REF_CLK_HZ / 1000000) * precision3;
+ stemp = DIV_ROUND_CLOSEST(stemp, 1UL << ref_ana_mpll_div);
+
+ /* stemp2 = cp_int_param[0] * stemp**2; */
+ stemp2 = stemp * stemp * cp_int_param[0];
+ stemp2 = DIV_ROUND_CLOSEST(stemp2, precision6);
+
+ /* stemp3 = cp_int_param[1] * stemp; */
+ stemp3 = stemp * cp_int_param[1];
+ stemp3 /= precision3;
+
+ /*
+ * cp_int_holder = floor(cp_int_param[0]*(stemp)**2
+ * + cp_int_param[1] * stemp
+ * + cp_int_param[2])
+ */
+ stemp3 += cp_int_param[2];
+ stemp3 += stemp2;
+
+ cfg->cp_int_holder = DIV_ROUND_CLOSEST(stemp3, precision6);
+
+ /* stemp2 = cp_prop_param[0] * stemp**2; */
+ stemp2 = stemp * stemp * cp_prop_param[0];
+ stemp2 = DIV_ROUND_CLOSEST(stemp2, precision6);
+
+ /* stemp3 = cp_prop_param[1] * stemp; */
+ stemp3 = (stemp * cp_prop_param[1]) / precision3;
+
+ /*
+ * cp_int_holder = floor(cp_prop_param[0]*(stemp)**2
+ * + cp_prop_param[1] * stemp
+ * + cp_prop_param[2])
+ */
+ stemp3 += stemp2 + cp_prop_param[2];
+
+ cfg->cp_prop_holder = DIV_ROUND_CLOSEST(stemp3, precision6) - 1;
+
+ return 0;
+}
+
+static int hdmi_eliza_pll_configure_pll(struct hdmi_pll_eliza *pll,
+ unsigned long rate,
+ unsigned long parent_rate)
+{
+ struct hdmi_phy *phy = pll_get_phy(pll);
+ const struct hdmi_eliza_phy_pll_reg_cfg *cfg;
+ struct hdmi_eliza_phy_pll_reg_cfg cfg_calc = {};
+ int ret;
+ u32 val;
+
+ cfg = hdmi_pll_eliza_mpll_lut_decoder(rate);
+ if (!cfg) {
+ DRM_INFO("no valid mpll entry fall back to calculator");
+
+ ret = hdmi_eliza_pll_calculator(pll, rate, parent_rate, &cfg_calc);
+ if (ret) {
+ DRM_ERROR("PLL calculation failed for rate %lu\n", rate);
+ return ret;
+ }
+ cfg = &cfg_calc;
+ }
+
+ hdmi_phy_update_bits(phy, REG_HDMI_ELIZA_PHY_CLOCK_PATTERN_CONFIG_0, BIT(0), cfg->clk_pat);
+
+ hdmi_phy_update_bits(phy, REG_HDMI_ELIZA_PHY_MISC_CONTROL_2, GENMASK(6, 4), cfg->rxvcosel << 4);
+ hdmi_phy_update_bits(phy, REG_HDMI_ELIZA_PHY_MISC_CONTROL_1, GENMASK(7, 2), 0x11 << 2);
+
+ hdmi_phy_write(phy, REG_HDMI_ELIZA_PHY_MISC_CONTROL_0, 0);
+ hdmi_phy_write(phy, REG_HDMI_ELIZA_PHY_MPLLB_CONTROL_10,
+ cfg->cp_int_holder & 0xff);
+ hdmi_phy_write(phy, REG_HDMI_ELIZA_PHY_MPLLB_CONTROL_12,
+ cfg->cp_prop_holder & 0xff);
+
+ hdmi_phy_update_bits(phy, REG_HDMI_ELIZA_PHY_MPLLB_CONTROL_0, BIT(0), BIT(0));
+ hdmi_phy_write(phy, REG_HDMI_ELIZA_PHY_MPLLB_CONTROL_2,
+ cfg->multiplier & 0xff);
+ hdmi_phy_write(phy, REG_HDMI_ELIZA_PHY_MPLLB_CONTROL_3,
+ (cfg->multiplier >> 8) & 0xff);
+
+ hdmi_phy_update_bits(phy, REG_HDMI_ELIZA_PHY_MPLLB_CONTROL_0, BIT(2), BIT(2));
+ hdmi_phy_write(phy, REG_HDMI_ELIZA_PHY_MPLLB_CONTROL_6, cfg->quotient & 0xff);
+ hdmi_phy_write(phy, REG_HDMI_ELIZA_PHY_MPLLB_CONTROL_7,
+ (cfg->quotient >> 8) & 0xff);
+ hdmi_phy_write(phy, REG_HDMI_ELIZA_PHY_MPLLB_CONTROL_8, cfg->remainder & 0xff);
+ hdmi_phy_write(phy, REG_HDMI_ELIZA_PHY_MPLLB_CONTROL_9,
+ (cfg->remainder >> 8) & 0xff);
+ hdmi_phy_write(phy, REG_HDMI_ELIZA_PHY_MPLLB_CONTROL_4, cfg->denominator & 0xff);
+ hdmi_phy_write(phy, REG_HDMI_ELIZA_PHY_MPLLB_CONTROL_5,
+ (cfg->denominator >> 8) & 0xff);
+ hdmi_phy_write(phy, REG_HDMI_ELIZA_PHY_MPLLB_CONTROL_1,
+ cfg->tx_clk_div & 0x7);
+ hdmi_phy_write(phy, REG_HDMI_ELIZA_PHY_MPLLB_CONTROL_14, 0x82);
+
+ val = hdmi_phy_read(phy, REG_HDMI_ELIZA_PHY_MPLLB_CONTROL_0);
+ val &= ~BIT(6);
+ val &= ~(0x3 << 3);
+ val |= (cfg->vco_freq & 0x3) << 3;
+ hdmi_phy_write(phy, REG_HDMI_ELIZA_PHY_MPLLB_CONTROL_0, val);
+
+ /*
+ * Ensure that vco configuration gets flushed to hardware before
+ * enabling the PLL
+ */
+ wmb();
+
+ pll->rate = rate;
+ pll->cfg = *cfg;
+
+ return 0;
+}
+
+static int hdmi_eliza_pll_set_clk_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long parent_rate)
+{
+ struct hdmi_pll_eliza *pll = hw_clk_to_pll(hw);
+
+ return hdmi_eliza_pll_configure_pll(pll, rate, parent_rate);
+};
+
+static int hdmi_eliza_pll_prepare(struct clk_hw *hw)
+{
+ struct hdmi_pll_eliza *pll = hw_clk_to_pll(hw);
+ struct hdmi_phy *phy = pll_get_phy(pll);
+
+ hdmi_phy_update_bits(phy, REG_HDMI_ELIZA_PHY_CLOCK_PATTERN_CONFIG_0, BIT(1), BIT(1));
+
+ /*
+ * This Synopsys PLL does not have a PLL lock-like register, thus there
+ * is no way to tell when the PLL actually locked.
+ * Returning now, would lead to stuck pclk or iface RCG clocks at off
+ * (disp_cc_mdss_hdmi_pclk_clk status stuck at 'off'),
+ * thus obviously the professional solution is to delay.
+ * 8 ms was figured out during tests, not based on any datasheet.
+ */
+ mdelay(8);
+
+ return 0;
+}
+
+static int hdmi_eliza_pll_determine_rate(struct clk_hw *hw,
+ struct clk_rate_request *req)
+{
+ req->rate = clamp_t(unsigned long, req->rate, HDMI_PLL_MIN_FREQ, HDMI_PLL_MAX_FREQ);
+
+ return 0;
+}
+
+static u64 hdmi_eliza_pll_vco_freq(u64 ref_clk_hz, u32 multiplier, u32 frac_quot,
+ u32 frac_rem, u32 frac_den)
+{
+ u64 num;
+ u64 den;
+
+ num = 32ULL * 65536ULL * frac_den +
+ (u64)multiplier * 65536ULL * frac_den +
+ 2ULL * ((u64)frac_quot * frac_den + frac_rem);
+
+ den = 2ULL * 65536ULL * frac_den;
+
+ return mul_u64_u64_div_u64(ref_clk_hz, num, den);
+}
+
+static unsigned long hdmi_eliza_pll_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct hdmi_pll_eliza *pll = hw_clk_to_pll(hw);
+ u64 rate;
+
+ rate = hdmi_eliza_pll_vco_freq(REF_CLK_HZ, pll->cfg.multiplier,
+ pll->cfg.quotient, pll->cfg.remainder,
+ pll->cfg.denominator);
+
+ /* rate = vco_freq * 2 / (10 * 2^tx_clk_div) */
+ rate *= 2;
+ do_div(rate, 10);
+ rate >>= pll->cfg.tx_clk_div;
+
+ return rate;
+}
+
+
+static void hdmi_eliza_pll_unprepare(struct clk_hw *hw)
+{
+ struct hdmi_pll_eliza *pll = hw_clk_to_pll(hw);
+ struct hdmi_phy *phy = pll_get_phy(pll);
+
+ hdmi_phy_update_bits(phy, REG_HDMI_ELIZA_PHY_CLOCK_PATTERN_CONFIG_0, BIT(1), 0);
+}
+
+static const struct clk_ops hdmi_eliza_pll_ops = {
+ .set_rate = hdmi_eliza_pll_set_clk_rate,
+ .determine_rate = hdmi_eliza_pll_determine_rate,
+ .recalc_rate = hdmi_eliza_pll_recalc_rate,
+ .prepare = hdmi_eliza_pll_prepare,
+ .unprepare = hdmi_eliza_pll_unprepare,
+};
+
+static const struct clk_init_data pll_init = {
+ .name = "hdmipll",
+ .ops = &hdmi_eliza_pll_ops,
+ .parent_data = (const struct clk_parent_data[]) {
+ { .fw_name = "xo", .name = "xo_board" },
+ },
+ .num_parents = 1,
+};
+
+int msm_hdmi_pll_eliza_init(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct hdmi_pll_eliza *pll;
+ struct hdmi_phy *phy;
+ int ret;
+
+ pll = devm_kzalloc(dev, sizeof(*pll), GFP_KERNEL);
+ if (!pll)
+ return -ENOMEM;
+
+ pll->dev = dev;
+ pll->clk_hw.init = &pll_init;
+
+ ret = devm_clk_hw_register(dev, &pll->clk_hw);
+ if (ret) {
+ DRM_DEV_ERROR(dev, "failed to register pll clock\n");
+ return ret;
+ }
+
+ ret = devm_of_clk_add_hw_provider(dev, of_clk_hw_simple_get, &pll->clk_hw);
+ if (ret) {
+ DRM_DEV_ERROR(dev, "failed to register clk provider: %d\n", ret);
+ return ret;
+ }
+
+ phy = dev_get_drvdata(dev);
+ phy->pll = pll;
+
+ return 0;
+}
+
+static const char * const hdmi_phy_eliza_clk_names[] = {
+ "iface",
+ "ref",
+ "xo",
+};
+
+static void hdmi_eliza_phy_txn_write(struct hdmi_phy *phy, u32 reg, u32 value)
+{
+ const int phy_txn_offset = REG_HDMI_ELIZA_PHY_TX1_CONTROL_0 - REG_HDMI_ELIZA_PHY_TX0_CONTROL_0;
+ int i;
+
+ for (i = 0; i < HDMI_PHY_TXN_CONTROL; i++)
+ hdmi_phy_write(phy, reg + i * phy_txn_offset, value);
+}
+
+static void hdmi_eliza_phy_txn_update(struct hdmi_phy *phy, u32 reg, u32 mask, u32 value)
+{
+ const int phy_txn_offset = REG_HDMI_ELIZA_PHY_TX1_CONTROL_0 - REG_HDMI_ELIZA_PHY_TX0_CONTROL_0;
+ int i;
+
+ for (i = 0; i < HDMI_PHY_TXN_CONTROL; i++)
+ hdmi_phy_update_bits(phy, reg + i * phy_txn_offset, mask, value);
+}
+
+static void hdmi_eliza_phy_configure(struct hdmi_phy *phy)
+{
+ hdmi_eliza_phy_txn_update(phy, REG_HDMI_ELIZA_PHY_TX0_CONTROL_8, BIT(2), BIT(2));
+ hdmi_phy_update_bits(phy, REG_HDMI_ELIZA_PHY_TX_COMMON_CONTROL_0, BIT(0), BIT(0));
+
+ usleep_range(5, 5000);
+
+ hdmi_phy_update_bits(phy, REG_HDMI_ELIZA_PHY_REFCLK_CONTROL_0, BIT(0), BIT(0));
+ hdmi_phy_update_bits(phy, REG_HDMI_ELIZA_PHY_REFCLK_CONTROL_1, GENMASK(2, 0), 0x1);
+ /* Select MPLLB */
+ hdmi_phy_update_bits(phy, REG_HDMI_ELIZA_PHY_MISC_CONTROL_3, BIT(0), 0);
+
+ hdmi_phy_write(phy, REG_HDMI_ELIZA_PHY_MPLLB_CONTROL_11, 0x18);
+ /*
+ * MPLLB_CONTROL_12: missing in programming sequence, but present in
+ * downstream
+ */
+ hdmi_phy_write(phy, REG_HDMI_ELIZA_PHY_MPLLB_CONTROL_12, 0x12);
+ hdmi_phy_write(phy, REG_HDMI_ELIZA_PHY_MPLLB_CONTROL_13, 0x18);
+ hdmi_phy_update_bits(phy, REG_HDMI_ELIZA_PHY_MPLLB_CONTROL_16, BIT(1), BIT(1));
+ /*
+ * MISC_CONTROL_2: missing in programming sequence, but present in
+ * downstream
+ */
+ hdmi_phy_write(phy, REG_HDMI_ELIZA_PHY_MISC_CONTROL_2, 0x4d);
+}
+
+static void hdmi_eliza_phy_tx_lane_config(struct hdmi_phy *phy,
+ unsigned long pixclock)
+{
+ const unsigned int bpp = 24;
+
+ /* Set BIT(3) for MPLLB and clear BIT(0) */
+ hdmi_eliza_phy_txn_update(phy, REG_HDMI_ELIZA_PHY_TX0_CONTROL_8, BIT(0) | BIT(3), BIT(3));
+ hdmi_eliza_phy_txn_update(phy, REG_HDMI_ELIZA_PHY_TX0_CONTROL_9, BIT(0) | BIT(1) | BIT(2), 0);
+ hdmi_eliza_phy_txn_update(phy, REG_HDMI_ELIZA_PHY_TX0_CONTROL_10, BIT(4) | BIT(5), BIT(4) | BIT(5));
+
+ hdmi_eliza_phy_txn_write(phy, REG_HDMI_ELIZA_PHY_TX0_CONTROL_7, 0);
+ hdmi_eliza_phy_txn_write(phy, REG_HDMI_ELIZA_PHY_TX0_CONTROL_6, 0);
+ hdmi_eliza_phy_txn_write(phy, REG_HDMI_ELIZA_PHY_TX0_CONTROL_5, 0x3e);
+
+ hdmi_eliza_phy_txn_update(phy, REG_HDMI_ELIZA_PHY_TX0_CONTROL_10, BIT(3), 0);
+
+ if (pixclock * bpp >= HDMI_PHY_MAX_BIT_RATE)
+ hdmi_phy_update_bits(phy, REG_HDMI_ELIZA_PHY_TX_COMMON_CONTROL_0, BIT(2), 0);
+ else
+ hdmi_phy_update_bits(phy, REG_HDMI_ELIZA_PHY_TX_COMMON_CONTROL_0, BIT(2), BIT(2));
+
+ hdmi_eliza_phy_txn_update(phy, REG_HDMI_ELIZA_PHY_TX0_CONTROL_9, BIT(3) | BIT(4), BIT(3) | BIT(4));
+}
+
+static void hdmi_eliza_phy_disable_hstx_reset(struct hdmi_phy *phy)
+{
+ hdmi_eliza_phy_txn_write(phy, REG_HDMI_ELIZA_PHY_TX0_CONTROL_0, 0);
+
+ hdmi_phy_write(phy, REG_HDMI_ELIZA_PHY_RX1_CONFIG_15, 0);
+ hdmi_phy_write(phy, REG_HDMI_ELIZA_PHY_RX2_CONFIG_15, 0);
+ hdmi_phy_write(phy, REG_HDMI_ELIZA_PHY_REXT_CONTROL_2, 0);
+}
+
+static int hdmi_eliza_phy_ready_poll(struct hdmi_phy *phy, u32 reg, u32 mask, u32 val)
+{
+ u32 state;
+ const u32 sleep_us = 2000;
+ const u32 timeout_us = 3000000;
+
+ if (readl_poll_timeout_atomic((phy->mmio + reg), state,
+ ((state & mask) == val),
+ sleep_us, timeout_us)) {
+ DRM_ERROR("poll timeout, reg: 0x%x status=0x%x", reg, state);
+
+ return -ETIMEDOUT;
+ }
+
+ return 0;
+}
+
+static int hdmi_eliza_phy_tx_ready_poll(struct hdmi_phy *phy)
+{
+ const int phy_txn_offset = REG_HDMI_ELIZA_PHY_TX1_CONTROL_0 - REG_HDMI_ELIZA_PHY_TX0_CONTROL_0;
+ int ret = 0;
+
+ /* Poll until TXn_ACK==0, downstream is wrong here */
+ for (int i = 0; i < HDMI_PHY_TXN_CONTROL; i++) {
+ ret |= hdmi_eliza_phy_ready_poll(phy,
+ REG_HDMI_ELIZA_PHY_TX0_CONTROL_2 + i * phy_txn_offset,
+ BIT(0), 0x0);
+ if (ret)
+ break;
+ }
+
+ return ret;
+}
+
+static int hdmi_eliza_phy_sram_init(struct hdmi_phy *phy)
+{
+ int ret;
+
+ ret = hdmi_eliza_phy_ready_poll(phy, REG_HDMI_ELIZA_PHY_SRAM_CONTROL_1, BIT(0), BIT(0));
+ if (ret)
+ return ret;
+
+ hdmi_phy_write(phy, REG_HDMI_ELIZA_PHY_CR_ADDRESS_LSB, 0x3);
+ hdmi_phy_write(phy, REG_HDMI_ELIZA_PHY_CR_ADDRESS_MSB, 0xe0);
+ hdmi_phy_write(phy, REG_HDMI_ELIZA_PHY_CR_WRDATA_LSB, 0x18);
+ hdmi_phy_write(phy, REG_HDMI_ELIZA_PHY_CR_WRDATA_MSB, 0);
+ hdmi_phy_write(phy, REG_HDMI_ELIZA_PHY_CR_ACCESS_CMD, 0x3);
+ ndelay(400);
+ hdmi_phy_write(phy, REG_HDMI_ELIZA_PHY_CR_ACCESS_CMD, 0);
+ hdmi_phy_write(phy, REG_HDMI_ELIZA_PHY_CR_ADDRESS_LSB, 0x5);
+ hdmi_phy_write(phy, REG_HDMI_ELIZA_PHY_CR_ADDRESS_MSB, 0x90);
+ hdmi_phy_write(phy, REG_HDMI_ELIZA_PHY_CR_WRDATA_LSB, 0xc);
+ hdmi_phy_write(phy, REG_HDMI_ELIZA_PHY_CR_WRDATA_MSB, 0);
+ hdmi_phy_write(phy, REG_HDMI_ELIZA_PHY_CR_ACCESS_CMD, 0x3);
+ ndelay(400);
+ hdmi_phy_write(phy, REG_HDMI_ELIZA_PHY_CR_ACCESS_CMD, 0x0);
+ hdmi_phy_write(phy, REG_HDMI_ELIZA_PHY_MISC_CONTROL_0, 0x7);
+ hdmi_phy_write(phy, REG_HDMI_ELIZA_PHY_CR_ADDRESS_LSB, 0x1a);
+ hdmi_phy_write(phy, REG_HDMI_ELIZA_PHY_CR_ADDRESS_MSB, 0xe0);
+ hdmi_phy_write(phy, REG_HDMI_ELIZA_PHY_CR_WRDATA_LSB, 0xa0);
+ hdmi_phy_write(phy, REG_HDMI_ELIZA_PHY_CR_WRDATA_MSB, 0);
+ hdmi_phy_write(phy, REG_HDMI_ELIZA_PHY_CR_ACCESS_CMD, 0x3);
+ ndelay(400);
+ hdmi_phy_write(phy, REG_HDMI_ELIZA_PHY_CR_ACCESS_CMD, 0);
+
+ hdmi_phy_update_bits(phy, REG_HDMI_ELIZA_PHY_SRAM_CONTROL_0,
+ BIT(1), BIT(1));
+
+ return 0;
+}
+
+static void hdmi_eliza_phy_init(struct hdmi_phy *phy,
+ unsigned long pixclock)
+{
+
+ /* pa_iso_disable() */
+ hdmi_phy_update_bits(phy, REG_HDMI_ELIZA_PHY_MISC_CONTROL_3,
+ BIT(1) | BIT(2) | BIT(3), 0);
+
+ /* sw_reset() */
+ hdmi_phy_write(phy, REG_HDMI_ELIZA_PHY_RESET_CONTROL_0, 0x1);
+
+ /* assert_tx_lane_reset() */
+ hdmi_eliza_phy_txn_update(phy, REG_HDMI_ELIZA_PHY_TX0_CONTROL_9, BIT(5), BIT(5));
+
+ /* phy_init_config() */
+ hdmi_eliza_phy_configure(phy);
+
+ hdmi_eliza_phy_tx_lane_config(phy, pixclock);
+
+ hdmi_eliza_pll_configure_pll(phy->pll, 396000000, 19200000);
+
+ /* sram_mode() (with SRAM init) */
+ hdmi_phy_update_bits(phy, REG_HDMI_ELIZA_PHY_SRAM_CONTROL_0,
+ BIT(0) | BIT(1), 0);
+ /* qcsram_init() */
+ hdmi_phy_write(phy, REG_HDMI_ELIZA_PHY_QCSRAM_CONFIG_3, BIT(0));
+ usleep_range(5, 5000);
+ hdmi_phy_write(phy, REG_HDMI_ELIZA_PHY_QCSRAM_CONFIG_3, 0);
+
+ /* deassert_tx_lane_reset() */
+ hdmi_eliza_phy_txn_update(phy, REG_HDMI_ELIZA_PHY_TX0_CONTROL_9, BIT(5), 0);
+
+ hdmi_eliza_phy_disable_hstx_reset(phy);
+ hdmi_phy_write(phy, REG_HDMI_ELIZA_PHY_RESET_CONTROL_0, 0);
+
+ if (hdmi_eliza_phy_sram_init(phy))
+ return;
+
+ if (hdmi_eliza_phy_tx_ready_poll(phy))
+ return;
+};
+
+static void hdmi_eliza_phy_powerup(struct hdmi_phy *phy,
+ unsigned long pixclock)
+{
+ hdmi_phy_update_bits(phy, REG_HDMI_ELIZA_PHY_TX_COMMON_CONTROL_0, BIT(1), BIT(1));
+}
+
+static void hdmi_eliza_phy_deinit(struct hdmi_phy *phy)
+{
+ /* sw_reset() */
+ hdmi_phy_write(phy, REG_HDMI_ELIZA_PHY_RESET_CONTROL_0, 1);
+ hdmi_eliza_phy_txn_write(phy, REG_HDMI_ELIZA_PHY_TX0_CONTROL_0, 1);
+ /* assert_tx_lane_reset() */
+ hdmi_eliza_phy_txn_update(phy, REG_HDMI_ELIZA_PHY_TX0_CONTROL_9, BIT(5), BIT(5));
+ /* pa_iso_enable() */
+ hdmi_phy_update_bits(phy, REG_HDMI_ELIZA_PHY_MISC_CONTROL_3,
+ BIT(1) | BIT(2) | BIT(3), BIT(1) | BIT(2) | BIT(3));
+}
+
+static void hdmi_eliza_phy_powerdown(struct hdmi_phy *phy)
+{
+ hdmi_phy_update_bits(phy, REG_HDMI_ELIZA_PHY_TX_COMMON_CONTROL_0, BIT(1), 0);
+}
+
+const struct hdmi_phy_cfg msm_hdmi_phy_eliza_cfg = {
+ .type = MSM_HDMI_PHY_ELIZA,
+ .init = hdmi_eliza_phy_init,
+ .deinit = hdmi_eliza_phy_deinit,
+ .powerup = hdmi_eliza_phy_powerup,
+ .powerdown = hdmi_eliza_phy_powerdown,
+ .clk_names = hdmi_phy_eliza_clk_names,
+ .num_clks = ARRAY_SIZE(hdmi_phy_eliza_clk_names),
+};
diff --git a/drivers/gpu/drm/msm/registers/display/hdmi.xml b/drivers/gpu/drm/msm/registers/display/hdmi.xml
index 0ebb96297dae..4afc36fef172 100644
--- a/drivers/gpu/drm/msm/registers/display/hdmi.xml
+++ b/drivers/gpu/drm/msm/registers/display/hdmi.xml
@@ -1101,4 +1101,144 @@ xsi:schemaLocation="https://gitlab.freedesktop.org/freedreno/ rules-fd.xsd">
<reg32 offset="0x002C" name="LANE_MODE"/>
</domain>
+<domain name="HDMI_ELIZA_PHY" width="32">
+ <reg32 offset="0x0014" name="RESET_CONTROL_0"/>
+ <reg32 offset="0x0018" name="MISC_CONTROL_0"/>
+ <reg32 offset="0x001c" name="MISC_CONTROL_1"/>
+ <reg32 offset="0x0020" name="MISC_CONTROL_2"/>
+ <reg32 offset="0x0024" name="MISC_CONTROL_3"/>
+ <reg32 offset="0x0028" name="SRAM_CONTROL_0"/>
+ <reg32 offset="0x002c" name="SRAM_CONTROL_1"/>
+ <reg32 offset="0x0038" name="CR_ACCESS_CMD"/>
+ <reg32 offset="0x0040" name="CR_ADDRESS_LSB"/>
+ <reg32 offset="0x0044" name="CR_ADDRESS_MSB"/>
+ <reg32 offset="0x0048" name="CR_WRDATA_LSB"/>
+ <reg32 offset="0x004c" name="CR_WRDATA_MSB"/>
+
+ <reg32 offset="0x0060" name="REXT_CONTROL_2"/>
+ <reg32 offset="0x006c" name="REFCLK_CONTROL_0"/>
+ <reg32 offset="0x0070" name="REFCLK_CONTROL_1"/>
+ <reg32 offset="0x0074" name="REFCLK_CONTROL_2"/>
+
+ <reg32 offset="0x0078" name="MPLLA_CONTROL_0"/>
+ <reg32 offset="0x007c" name="MPLLA_CONTROL_1"/>
+ <reg32 offset="0x0080" name="MPLLA_CONTROL_2"/>
+ <reg32 offset="0x0084" name="MPLLA_CONTROL_3"/>
+ <reg32 offset="0x0088" name="MPLLA_CONTROL_4"/>
+ <reg32 offset="0x008c" name="MPLLA_CONTROL_5"/>
+ <reg32 offset="0x0090" name="MPLLA_CONTROL_6"/>
+ <reg32 offset="0x0094" name="MPLLA_CONTROL_7"/>
+ <reg32 offset="0x0098" name="MPLLA_CONTROL_8"/>
+ <reg32 offset="0x009c" name="MPLLA_CONTROL_9"/>
+ <reg32 offset="0x00a0" name="MPLLA_CONTROL_10"/>
+ <reg32 offset="0x00a4" name="MPLLA_CONTROL_11"/>
+ <reg32 offset="0x00a8" name="MPLLA_CONTROL_12"/>
+ <reg32 offset="0x00ac" name="MPLLA_CONTROL_13"/>
+ <reg32 offset="0x00b0" name="MPLLA_CONTROL_14"/>
+ <reg32 offset="0x00b4" name="MPLLA_CONTROL_15"/>
+ <reg32 offset="0x00b8" name="MPLLA_CONTROL_16"/>
+ <reg32 offset="0x00bc" name="MPLLA_CONTROL_17"/>
+ <reg32 offset="0x00c0" name="MPLLA_CONTROL_18"/>
+ <reg32 offset="0x00c4" name="MPLLA_CONTROL_19"/>
+ <reg32 offset="0x00c8" name="MPLLA_CONTROL_20"/>
+ <reg32 offset="0x00cc" name="MPLLA_CONTROL_21"/>
+ <reg32 offset="0x00d0" name="MPLLA_CONTROL_22"/>
+ <reg32 offset="0x00d4" name="MPLLA_CONTROL_23"/>
+ <reg32 offset="0x00d8" name="MPLLA_CONTROL_24"/>
+
+ <reg32 offset="0x00dc" name="MPLLB_CONTROL_0"/>
+ <reg32 offset="0x00e0" name="MPLLB_CONTROL_1"/>
+ <reg32 offset="0x00e4" name="MPLLB_CONTROL_2"/>
+ <reg32 offset="0x00e8" name="MPLLB_CONTROL_3"/>
+ <reg32 offset="0x00ec" name="MPLLB_CONTROL_4"/>
+ <reg32 offset="0x00f0" name="MPLLB_CONTROL_5"/>
+ <reg32 offset="0x00f4" name="MPLLB_CONTROL_6"/>
+ <reg32 offset="0x00f8" name="MPLLB_CONTROL_7"/>
+ <reg32 offset="0x00fc" name="MPLLB_CONTROL_8"/>
+ <reg32 offset="0x0100" name="MPLLB_CONTROL_9"/>
+ <reg32 offset="0x0104" name="MPLLB_CONTROL_10"/>
+ <reg32 offset="0x0108" name="MPLLB_CONTROL_11"/>
+ <reg32 offset="0x010c" name="MPLLB_CONTROL_12"/>
+ <reg32 offset="0x0110" name="MPLLB_CONTROL_13"/>
+ <reg32 offset="0x0114" name="MPLLB_CONTROL_14"/>
+ <reg32 offset="0x0118" name="MPLLB_CONTROL_15"/>
+ <reg32 offset="0x011c" name="MPLLB_CONTROL_16"/>
+ <reg32 offset="0x0120" name="MPLLB_CONTROL_17"/>
+ <reg32 offset="0x0124" name="MPLLB_CONTROL_18"/>
+ <reg32 offset="0x0128" name="MPLLB_CONTROL_19"/>
+ <reg32 offset="0x012c" name="MPLLB_CONTROL_20"/>
+ <reg32 offset="0x0130" name="MPLLB_CONTROL_21"/>
+ <reg32 offset="0x0134" name="MPLLB_CONTROL_22"/>
+ <reg32 offset="0x0138" name="MPLLB_CONTROL_23"/>
+ <reg32 offset="0x013c" name="MPLLB_CONTROL_24"/>
+
+ <reg32 offset="0x0140" name="TX_COMMON_CONTROL_0"/>
+ <reg32 offset="0x0144" name="TX_COMMON_CONTROL_1"/>
+
+ <reg32 offset="0x0148" name="TX0_CONTROL_0"/>
+ <reg32 offset="0x014c" name="TX0_CONTROL_1"/>
+ <reg32 offset="0x0150" name="TX0_CONTROL_2"/>
+ <reg32 offset="0x0154" name="TX0_CONTROL_3"/>
+ <reg32 offset="0x0158" name="TX0_CONTROL_4"/>
+ <reg32 offset="0x015c" name="TX0_CONTROL_5"/>
+ <reg32 offset="0x0160" name="TX0_CONTROL_6"/>
+ <reg32 offset="0x0164" name="TX0_CONTROL_7"/>
+ <reg32 offset="0x0168" name="TX0_CONTROL_8"/>
+ <reg32 offset="0x016c" name="TX0_CONTROL_9"/>
+ <reg32 offset="0x0170" name="TX0_CONTROL_10"/>
+ <reg32 offset="0x0174" name="TX0_CONTROL_11"/>
+ <reg32 offset="0x0178" name="TX0_CONTROL_12"/>
+
+ <reg32 offset="0x017c" name="TX1_CONTROL_0"/>
+ <reg32 offset="0x0180" name="TX1_CONTROL_1"/>
+ <reg32 offset="0x0184" name="TX1_CONTROL_2"/>
+ <reg32 offset="0x0188" name="TX1_CONTROL_3"/>
+ <reg32 offset="0x018c" name="TX1_CONTROL_4"/>
+ <reg32 offset="0x0190" name="TX1_CONTROL_5"/>
+ <reg32 offset="0x0194" name="TX1_CONTROL_6"/>
+ <reg32 offset="0x0198" name="TX1_CONTROL_7"/>
+ <reg32 offset="0x019c" name="TX1_CONTROL_8"/>
+ <reg32 offset="0x01a0" name="TX1_CONTROL_9"/>
+ <reg32 offset="0x01a4" name="TX1_CONTROL_10"/>
+ <reg32 offset="0x01a8" name="TX1_CONTROL_11"/>
+ <reg32 offset="0x01ac" name="TX1_CONTROL_12"/>
+
+ <reg32 offset="0x01b0" name="TX2_CONTROL_0"/>
+ <reg32 offset="0x01b4" name="TX2_CONTROL_1"/>
+ <reg32 offset="0x01b8" name="TX2_CONTROL_2"/>
+ <reg32 offset="0x01bc" name="TX2_CONTROL_3"/>
+ <reg32 offset="0x01c0" name="TX2_CONTROL_4"/>
+ <reg32 offset="0x01c4" name="TX2_CONTROL_5"/>
+ <reg32 offset="0x01c8" name="TX2_CONTROL_6"/>
+ <reg32 offset="0x01cc" name="TX2_CONTROL_7"/>
+ <reg32 offset="0x01d0" name="TX2_CONTROL_8"/>
+ <reg32 offset="0x01d4" name="TX2_CONTROL_9"/>
+ <reg32 offset="0x01d8" name="TX2_CONTROL_10"/>
+ <reg32 offset="0x01dc" name="TX2_CONTROL_11"/>
+ <reg32 offset="0x01e0" name="TX2_CONTROL_12"/>
+
+ <reg32 offset="0x01e4" name="TX3_CONTROL_0"/>
+ <reg32 offset="0x01e8" name="TX3_CONTROL_1"/>
+ <reg32 offset="0x01ec" name="TX3_CONTROL_2"/>
+ <reg32 offset="0x01f0" name="TX3_CONTROL_3"/>
+ <reg32 offset="0x01f4" name="TX3_CONTROL_4"/>
+ <reg32 offset="0x01f8" name="TX3_CONTROL_5"/>
+ <reg32 offset="0x01fc" name="TX3_CONTROL_6"/>
+ <reg32 offset="0x0200" name="TX3_CONTROL_7"/>
+ <reg32 offset="0x0204" name="TX3_CONTROL_8"/>
+ <reg32 offset="0x0208" name="TX3_CONTROL_9"/>
+ <reg32 offset="0x020c" name="TX3_CONTROL_10"/>
+ <reg32 offset="0x0210" name="TX3_CONTROL_11"/>
+ <reg32 offset="0x0214" name="TX3_CONTROL_12"/>
+
+ <reg32 offset="0x0218" name="QCSRAM_CONFIG_0"/>
+ <reg32 offset="0x021c" name="QCSRAM_CONFIG_1"/>
+ <reg32 offset="0x0220" name="QCSRAM_CONFIG_2"/>
+ <reg32 offset="0x0224" name="QCSRAM_CONFIG_3"/>
+ <reg32 offset="0x0228" name="CLOCK_PATTERN_CONFIG_0"/>
+
+ <reg32 offset="0x0270" name="RX1_CONFIG_15"/>
+ <reg32 offset="0x02b4" name="RX2_CONFIG_15"/>
+</domain>
+
</database>
--
2.53.0
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply related [flat|nested] 38+ messages in thread* Re: [PATCH RFC/DO NOT MERGE 10/12] drm/msm/hdmi_phy_eliza: Add support for Synopsys-based HDMI phy on Eliza
2026-08-28 14:05 ` Krzysztof Kozlowski
@ 2026-08-28 14:19 ` sashiko-bot
-1 siblings, 0 replies; 38+ messages in thread
From: sashiko-bot @ 2026-08-28 14:19 UTC (permalink / raw)
To: Krzysztof Kozlowski
Cc: dri-devel, neil.armstrong, robh, devicetree, linux-phy, olteanv,
vkoul, conor+dt
Thank you for your contribution! Sashiko AI review found 10 potential issue(s) to consider:
- [High] Silent truncation of 64-bit integers passed to `gcd()` on 32-bit architectures leads to incorrect clock calculations.
- [High] 32-bit integer overflow during PHY bit rate calculation causes incorrect hardware configuration for high-bandwidth displays.
- [High] Deterministic division by zero during CCF clock registration due to uninitialized configuration.
- [High] Severe CPU soft lockup risk due to excessive 3-second busy-wait loop using `readl_poll_timeout_atomic`.
- [High] Premature integer division causes precision loss yielding incorrect hardware PLL parameters.
- [Medium] Data race on PLL configuration state by bypassing Common Clock Framework (CCF) synchronization.
- [Low] 64-bit division using '/' and standard division macros causes build failure on 32-bit platforms.
- [Low] Unsupported floating-point literals used in integer calculations.
- [Low] Use of `mdelay(8)` wastes CPU resources in a sleepable context.
- [Low] Fragile design conflates the presence of PHY regulators with the name format of device tree memory resources.
--
commit 9c53defce3c459b1740fbff4f2434baad5c70aee
Author: Krzysztof Kozlowski <krzysztof.kozlowski@oss.qualcomm.com>
Subject: drm/msm/hdmi_phy_eliza: Add support for Synopsys-based HDMI phy on Eliza
Add driver for HDMI phy block from Synopsys used on Eliza SoC. Adjust core
parts for handling HDMI phy initialization sequence.
> diff --git a/drivers/gpu/drm/msm/hdmi/hdmi_phy.c b/drivers/gpu/drm/msm/hdmi/hdmi_phy.c
> --- a/drivers/gpu/drm/msm/hdmi/hdmi_phy.c
> +++ b/drivers/gpu/drm/msm/hdmi/hdmi_phy.c
> @@ -168,13 +171,17 @@ static int msm_hdmi_phy_probe(struct platform_device *pdev)
> if (!phy->cfg)
> return -ENODEV;
>
> - phy->mmio = msm_ioremap(pdev, "hdmi_phy");
> + if (phy->cfg->num_regs)
> + phy->mmio = msm_ioremap(pdev, "hdmi_phy");
> + else
> + phy->mmio = msm_ioremap(pdev, NULL);
[Severity: Low]
Does this use a fragile heuristic? This logic overloads the presence of
power regulators (num_regs) to guess the format of device tree memory
resources. These two hardware properties are orthogonal, which could break
if future device tree bindings diverge.
> diff --git a/drivers/gpu/drm/msm/hdmi/hdmi_phy_eliza.c b/drivers/gpu/drm/msm/hdmi/hdmi_phy_eliza.c
> --- /dev/null
> +++ b/drivers/gpu/drm/msm/hdmi/hdmi_phy_eliza.c
[ ... ]
> +static int hdmi_eliza_pll_calculator(struct hdmi_pll_eliza *pll,
> + unsigned long rate,
> + unsigned long parent_rate,
> + struct hdmi_eliza_phy_pll_reg_cfg *cfg)
> +{
[ ... ]
> + s64 precision3 = 1e3;
> + s64 precision6 = 1e6;
[Severity: Low]
Are these floating-point literals supported? Scientific notation defaults
to double literals, which relies on compiler implicit conversion to integers.
The kernel strictly prohibits floating-point types.
[ ... ]
> + /* expon = floor(log2(4.999999e9/base_rate)) */
> + utemp = 4.999999e9;
[Severity: Low]
Are these floating-point literals supported? This is another instance where
scientific notation will evaluate as a double literal.
> +
> + expon = fls64(utemp / base_rate) - 1;
[Severity: Low]
Can this cause a build failure on 32-bit platforms? The direct 64-bit
division operator triggers a dependency on __udivdi3, which is unresolved
on 32-bit architectures. do_div or div64_u64 should be used instead.
[ ... ]
> + /* multiplier = 2*(floor(bit_rate) * 2**expon / ref_clk_int) -16) */
> + multiplier = DIV_ROUND_UP(vco_freq, ref_clk_int);
[Severity: Low]
Could this also trigger a 32-bit build failure? DIV_ROUND_UP performs a
native division, and since vco_freq is a 64-bit value, this requires a 64-bit
division routine that is unavailable on 32-bit builds.
[ ... ]
> + if (aux2 == 0) {
> + cfg->remainder = 0;
> + cfg->denominator = 1;
> + } else {
> + cfg->remainder = DIV_ROUND_UP(aux2, gcd(aux1, aux2));
> + cfg->denominator = DIV_ROUND_UP(aux1, gcd(aux1, aux2));
[Severity: High]
Does this truncate 64-bit values on 32-bit architectures? The gcd function
takes unsigned long parameters, which are 32-bit on 32-bit kernels. Since
aux1 and aux2 can hold values requiring up to 36 bits, they will be silently
truncated when passed into gcd, feeding incorrect fractions into the PLL
configuration.
[ ... ]
> + /* stemp = (REF_CLK_MHZ/2**ref_ana_mpll_div) */
> + stemp = (REF_CLK_HZ / 1000000) * precision3;
[Severity: High]
Does this premature division cause a loss of precision? REF_CLK_HZ is
divided by 1,000,000 first, which drops the remainder before scaling. With
REF_CLK_HZ at 38,400,000, the result truncates to 38 instead of preserving
the 0.4 MHz. The error is then squared later, propagating significant drift
into the PLL analog parameters.
[ ... ]
> + cfg->cp_int_holder = DIV_ROUND_CLOSEST(stemp3, precision6);
[Severity: Low]
Can this result in a build failure on 32-bit architectures?
DIV_ROUND_CLOSEST triggers native division on s64 variables, which will fail
to link without __divdi3.
[ ... ]
> +static int hdmi_eliza_pll_prepare(struct clk_hw *hw)
> +{
[ ... ]
> + /*
> + * This Synopsys PLL does not have a PLL lock-like register, thus there
> + * is no way to tell when the PLL actually locked.
> + * Returning now, would lead to stuck pclk or iface RCG clocks at off
> + * (disp_cc_mdss_hdmi_pclk_clk status stuck at 'off'),
> + * thus obviously the professional solution is to delay.
> + * 8 ms was figured out during tests, not based on any datasheet.
> + */
> + mdelay(8);
> +
> + return 0;
> +}
[Severity: Low]
Is mdelay strictly necessary here? Busy-waiting the CPU for 8 milliseconds
wastes resources in a context where sleeping is fully permitted. The prepare
callback can safely yield the CPU using msleep or usleep_range.
[ ... ]
> +static u64 hdmi_eliza_pll_vco_freq(u64 ref_clk_hz, u32 multiplier, u32 frac_quot,
> + u32 frac_rem, u32 frac_den)
> +{
> + u64 num;
> + u64 den;
> +
> + num = 32ULL * 65536ULL * frac_den +
> + (u64)multiplier * 65536ULL * frac_den +
> + 2ULL * ((u64)frac_quot * frac_den + frac_rem);
> +
> + den = 2ULL * 65536ULL * frac_den;
> +
> + return mul_u64_u64_div_u64(ref_clk_hz, num, den);
> +}
> +
> +static unsigned long hdmi_eliza_pll_recalc_rate(struct clk_hw *hw,
> + unsigned long parent_rate)
> +{
> + struct hdmi_pll_eliza *pll = hw_clk_to_pll(hw);
> + u64 rate;
> +
> + rate = hdmi_eliza_pll_vco_freq(REF_CLK_HZ, pll->cfg.multiplier,
> + pll->cfg.quotient, pll->cfg.remainder,
> + pll->cfg.denominator);
[ ... ]
> +int msm_hdmi_pll_eliza_init(struct platform_device *pdev)
> +{
[ ... ]
> + pll = devm_kzalloc(dev, sizeof(*pll), GFP_KERNEL);
[ ... ]
> + ret = devm_clk_hw_register(dev, &pll->clk_hw);
[Severity: High]
Can this lead to a division by zero during probe?
When devm_clk_hw_register is called, the Common Clock Framework immediately
invokes recalc_rate. Because the pll structure is zero-allocated,
pll->cfg.denominator is zero. This zero is passed into
hdmi_eliza_pll_vco_freq, which results in den evaluating to 0 and
triggering a kernel panic in mul_u64_u64_div_u64.
[ ... ]
> +static void hdmi_eliza_phy_tx_lane_config(struct hdmi_phy *phy,
> + unsigned long pixclock)
> +{
> + const unsigned int bpp = 24;
[ ... ]
> + if (pixclock * bpp >= HDMI_PHY_MAX_BIT_RATE)
> + hdmi_phy_update_bits(phy, REG_HDMI_ELIZA_PHY_TX_COMMON_CONTROL_0, BIT(2), 0);
> + else
[Severity: High]
Will this calculation overflow 32-bit bounds before the comparison?
The pixclock parameter is typed as unsigned long, which is 32-bit on 32-bit
kernels. For high bandwidth displays, multiplying a high pixclock by 24 will
exceed the 32-bit integer maximum of 4.29 billion. This overflow will result
in a smaller wrapped value, breaking the conditional check and incorrectly
programming the PHY for high-resolution displays.
[ ... ]
> +static int hdmi_eliza_phy_ready_poll(struct hdmi_phy *phy, u32 reg, u32 mask, u32 val)
> +{
> + u32 state;
> + const u32 sleep_us = 2000;
> + const u32 timeout_us = 3000000;
> +
> + if (readl_poll_timeout_atomic((phy->mmio + reg), state,
> + ((state & mask) == val),
> + sleep_us, timeout_us)) {
[Severity: High]
Does this present a severe CPU soft lockup risk?
The readl_poll_timeout_atomic macro disables preemption and spins using a
udelay. Looping a 2000 microsecond delay for up to 3,000,000 microseconds
(3 seconds) violates scheduling rules and is very likely to trigger watchdog
lockups if the hardware fails to respond.
[ ... ]
> +static void hdmi_eliza_phy_init(struct hdmi_phy *phy,
> + unsigned long pixclock)
> +{
[ ... ]
> + hdmi_eliza_pll_configure_pll(phy->pll, 396000000, 19200000);
[Severity: Medium]
Does this bypass the Common Clock Framework synchronization?
Directly invoking hdmi_eliza_pll_configure_pll here forcefully mutates the
shared pll->cfg state locklessly. CCF invariants generally mandate that
clock state modifications are protected by prepare_lock. Concurrently
reading the clock state from sysfs or debugfs could hit a data race.
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260828-drm-msm-hdmi-eliza-v1-0-67843277de17@oss.qualcomm.com?part=10
^ permalink raw reply [flat|nested] 38+ messages in thread* Re: [PATCH RFC/DO NOT MERGE 10/12] drm/msm/hdmi_phy_eliza: Add support for Synopsys-based HDMI phy on Eliza
@ 2026-08-28 14:19 ` sashiko-bot
0 siblings, 0 replies; 38+ messages in thread
From: sashiko-bot @ 2026-08-28 14:19 UTC (permalink / raw)
To: Krzysztof Kozlowski
Cc: dri-devel, neil.armstrong, robh, devicetree, linux-phy, olteanv,
vkoul, conor+dt
Thank you for your contribution! Sashiko AI review found 10 potential issue(s) to consider:
- [High] Silent truncation of 64-bit integers passed to `gcd()` on 32-bit architectures leads to incorrect clock calculations.
- [High] 32-bit integer overflow during PHY bit rate calculation causes incorrect hardware configuration for high-bandwidth displays.
- [High] Deterministic division by zero during CCF clock registration due to uninitialized configuration.
- [High] Severe CPU soft lockup risk due to excessive 3-second busy-wait loop using `readl_poll_timeout_atomic`.
- [High] Premature integer division causes precision loss yielding incorrect hardware PLL parameters.
- [Medium] Data race on PLL configuration state by bypassing Common Clock Framework (CCF) synchronization.
- [Low] 64-bit division using '/' and standard division macros causes build failure on 32-bit platforms.
- [Low] Unsupported floating-point literals used in integer calculations.
- [Low] Use of `mdelay(8)` wastes CPU resources in a sleepable context.
- [Low] Fragile design conflates the presence of PHY regulators with the name format of device tree memory resources.
--
commit 9c53defce3c459b1740fbff4f2434baad5c70aee
Author: Krzysztof Kozlowski <krzysztof.kozlowski@oss.qualcomm.com>
Subject: drm/msm/hdmi_phy_eliza: Add support for Synopsys-based HDMI phy on Eliza
Add driver for HDMI phy block from Synopsys used on Eliza SoC. Adjust core
parts for handling HDMI phy initialization sequence.
> diff --git a/drivers/gpu/drm/msm/hdmi/hdmi_phy.c b/drivers/gpu/drm/msm/hdmi/hdmi_phy.c
> --- a/drivers/gpu/drm/msm/hdmi/hdmi_phy.c
> +++ b/drivers/gpu/drm/msm/hdmi/hdmi_phy.c
> @@ -168,13 +171,17 @@ static int msm_hdmi_phy_probe(struct platform_device *pdev)
> if (!phy->cfg)
> return -ENODEV;
>
> - phy->mmio = msm_ioremap(pdev, "hdmi_phy");
> + if (phy->cfg->num_regs)
> + phy->mmio = msm_ioremap(pdev, "hdmi_phy");
> + else
> + phy->mmio = msm_ioremap(pdev, NULL);
[Severity: Low]
Does this use a fragile heuristic? This logic overloads the presence of
power regulators (num_regs) to guess the format of device tree memory
resources. These two hardware properties are orthogonal, which could break
if future device tree bindings diverge.
> diff --git a/drivers/gpu/drm/msm/hdmi/hdmi_phy_eliza.c b/drivers/gpu/drm/msm/hdmi/hdmi_phy_eliza.c
> --- /dev/null
> +++ b/drivers/gpu/drm/msm/hdmi/hdmi_phy_eliza.c
[ ... ]
> +static int hdmi_eliza_pll_calculator(struct hdmi_pll_eliza *pll,
> + unsigned long rate,
> + unsigned long parent_rate,
> + struct hdmi_eliza_phy_pll_reg_cfg *cfg)
> +{
[ ... ]
> + s64 precision3 = 1e3;
> + s64 precision6 = 1e6;
[Severity: Low]
Are these floating-point literals supported? Scientific notation defaults
to double literals, which relies on compiler implicit conversion to integers.
The kernel strictly prohibits floating-point types.
[ ... ]
> + /* expon = floor(log2(4.999999e9/base_rate)) */
> + utemp = 4.999999e9;
[Severity: Low]
Are these floating-point literals supported? This is another instance where
scientific notation will evaluate as a double literal.
> +
> + expon = fls64(utemp / base_rate) - 1;
[Severity: Low]
Can this cause a build failure on 32-bit platforms? The direct 64-bit
division operator triggers a dependency on __udivdi3, which is unresolved
on 32-bit architectures. do_div or div64_u64 should be used instead.
[ ... ]
> + /* multiplier = 2*(floor(bit_rate) * 2**expon / ref_clk_int) -16) */
> + multiplier = DIV_ROUND_UP(vco_freq, ref_clk_int);
[Severity: Low]
Could this also trigger a 32-bit build failure? DIV_ROUND_UP performs a
native division, and since vco_freq is a 64-bit value, this requires a 64-bit
division routine that is unavailable on 32-bit builds.
[ ... ]
> + if (aux2 == 0) {
> + cfg->remainder = 0;
> + cfg->denominator = 1;
> + } else {
> + cfg->remainder = DIV_ROUND_UP(aux2, gcd(aux1, aux2));
> + cfg->denominator = DIV_ROUND_UP(aux1, gcd(aux1, aux2));
[Severity: High]
Does this truncate 64-bit values on 32-bit architectures? The gcd function
takes unsigned long parameters, which are 32-bit on 32-bit kernels. Since
aux1 and aux2 can hold values requiring up to 36 bits, they will be silently
truncated when passed into gcd, feeding incorrect fractions into the PLL
configuration.
[ ... ]
> + /* stemp = (REF_CLK_MHZ/2**ref_ana_mpll_div) */
> + stemp = (REF_CLK_HZ / 1000000) * precision3;
[Severity: High]
Does this premature division cause a loss of precision? REF_CLK_HZ is
divided by 1,000,000 first, which drops the remainder before scaling. With
REF_CLK_HZ at 38,400,000, the result truncates to 38 instead of preserving
the 0.4 MHz. The error is then squared later, propagating significant drift
into the PLL analog parameters.
[ ... ]
> + cfg->cp_int_holder = DIV_ROUND_CLOSEST(stemp3, precision6);
[Severity: Low]
Can this result in a build failure on 32-bit architectures?
DIV_ROUND_CLOSEST triggers native division on s64 variables, which will fail
to link without __divdi3.
[ ... ]
> +static int hdmi_eliza_pll_prepare(struct clk_hw *hw)
> +{
[ ... ]
> + /*
> + * This Synopsys PLL does not have a PLL lock-like register, thus there
> + * is no way to tell when the PLL actually locked.
> + * Returning now, would lead to stuck pclk or iface RCG clocks at off
> + * (disp_cc_mdss_hdmi_pclk_clk status stuck at 'off'),
> + * thus obviously the professional solution is to delay.
> + * 8 ms was figured out during tests, not based on any datasheet.
> + */
> + mdelay(8);
> +
> + return 0;
> +}
[Severity: Low]
Is mdelay strictly necessary here? Busy-waiting the CPU for 8 milliseconds
wastes resources in a context where sleeping is fully permitted. The prepare
callback can safely yield the CPU using msleep or usleep_range.
[ ... ]
> +static u64 hdmi_eliza_pll_vco_freq(u64 ref_clk_hz, u32 multiplier, u32 frac_quot,
> + u32 frac_rem, u32 frac_den)
> +{
> + u64 num;
> + u64 den;
> +
> + num = 32ULL * 65536ULL * frac_den +
> + (u64)multiplier * 65536ULL * frac_den +
> + 2ULL * ((u64)frac_quot * frac_den + frac_rem);
> +
> + den = 2ULL * 65536ULL * frac_den;
> +
> + return mul_u64_u64_div_u64(ref_clk_hz, num, den);
> +}
> +
> +static unsigned long hdmi_eliza_pll_recalc_rate(struct clk_hw *hw,
> + unsigned long parent_rate)
> +{
> + struct hdmi_pll_eliza *pll = hw_clk_to_pll(hw);
> + u64 rate;
> +
> + rate = hdmi_eliza_pll_vco_freq(REF_CLK_HZ, pll->cfg.multiplier,
> + pll->cfg.quotient, pll->cfg.remainder,
> + pll->cfg.denominator);
[ ... ]
> +int msm_hdmi_pll_eliza_init(struct platform_device *pdev)
> +{
[ ... ]
> + pll = devm_kzalloc(dev, sizeof(*pll), GFP_KERNEL);
[ ... ]
> + ret = devm_clk_hw_register(dev, &pll->clk_hw);
[Severity: High]
Can this lead to a division by zero during probe?
When devm_clk_hw_register is called, the Common Clock Framework immediately
invokes recalc_rate. Because the pll structure is zero-allocated,
pll->cfg.denominator is zero. This zero is passed into
hdmi_eliza_pll_vco_freq, which results in den evaluating to 0 and
triggering a kernel panic in mul_u64_u64_div_u64.
[ ... ]
> +static void hdmi_eliza_phy_tx_lane_config(struct hdmi_phy *phy,
> + unsigned long pixclock)
> +{
> + const unsigned int bpp = 24;
[ ... ]
> + if (pixclock * bpp >= HDMI_PHY_MAX_BIT_RATE)
> + hdmi_phy_update_bits(phy, REG_HDMI_ELIZA_PHY_TX_COMMON_CONTROL_0, BIT(2), 0);
> + else
[Severity: High]
Will this calculation overflow 32-bit bounds before the comparison?
The pixclock parameter is typed as unsigned long, which is 32-bit on 32-bit
kernels. For high bandwidth displays, multiplying a high pixclock by 24 will
exceed the 32-bit integer maximum of 4.29 billion. This overflow will result
in a smaller wrapped value, breaking the conditional check and incorrectly
programming the PHY for high-resolution displays.
[ ... ]
> +static int hdmi_eliza_phy_ready_poll(struct hdmi_phy *phy, u32 reg, u32 mask, u32 val)
> +{
> + u32 state;
> + const u32 sleep_us = 2000;
> + const u32 timeout_us = 3000000;
> +
> + if (readl_poll_timeout_atomic((phy->mmio + reg), state,
> + ((state & mask) == val),
> + sleep_us, timeout_us)) {
[Severity: High]
Does this present a severe CPU soft lockup risk?
The readl_poll_timeout_atomic macro disables preemption and spins using a
udelay. Looping a 2000 microsecond delay for up to 3,000,000 microseconds
(3 seconds) violates scheduling rules and is very likely to trigger watchdog
lockups if the hardware fails to respond.
[ ... ]
> +static void hdmi_eliza_phy_init(struct hdmi_phy *phy,
> + unsigned long pixclock)
> +{
[ ... ]
> + hdmi_eliza_pll_configure_pll(phy->pll, 396000000, 19200000);
[Severity: Medium]
Does this bypass the Common Clock Framework synchronization?
Directly invoking hdmi_eliza_pll_configure_pll here forcefully mutates the
shared pll->cfg state locklessly. CCF invariants generally mandate that
clock state modifications are protected by prepare_lock. Concurrently
reading the clock state from sysfs or debugfs could hit a data race.
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260828-drm-msm-hdmi-eliza-v1-0-67843277de17@oss.qualcomm.com?part=10
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply [flat|nested] 38+ messages in thread
* [PATCH RFC/DO NOT MERGE 11/12] arm64: dts: qcom: eliza: Add HDMI display with HDMI PHY
2026-08-28 14:04 ` Krzysztof Kozlowski
@ 2026-08-28 14:05 ` Krzysztof Kozlowski
-1 siblings, 0 replies; 38+ messages in thread
From: Krzysztof Kozlowski @ 2026-08-28 14:05 UTC (permalink / raw)
To: Rob Clark, Dmitry Baryshkov, Abhinav Kumar, Jessica Zhang,
Sean Paul, Marijn Suijten, David Airlie, Simona Vetter,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Vinod Koul, Neil Armstrong,
Manivannan Sadhasivam, Bjorn Andersson, Konrad Dybcio
Cc: linux-arm-msm, dri-devel, freedreno, linux-kernel, devicetree,
Krzysztof Kozlowski, Krzysztof Kozlowski, linux-phy
Add device nodes for HDMI (similar to previous one in MSM8998) and HDMI
PHY (new Synopsys-based block).
Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski@oss.qualcomm.com>
---
arch/arm64/boot/dts/qcom/eliza.dtsi | 94 ++++++++++++++++++++++++++++++++++++-
1 file changed, 92 insertions(+), 2 deletions(-)
diff --git a/arch/arm64/boot/dts/qcom/eliza.dtsi b/arch/arm64/boot/dts/qcom/eliza.dtsi
index 66ea4aaafd73..27dd15766f51 100644
--- a/arch/arm64/boot/dts/qcom/eliza.dtsi
+++ b/arch/arm64/boot/dts/qcom/eliza.dtsi
@@ -2570,7 +2570,14 @@ dpu_intf0_out: endpoint {
remote-endpoint = <&mdss_dp0_in>;
};
};
- /* TODO: HDMI */
+
+ port@3 {
+ reg = <3>;
+
+ dpu_intf4_out: endpoint {
+ remote-endpoint = <&mdss_hdmi_in>;
+ };
+ };
};
mdp_opp_table: opp-table {
@@ -2805,6 +2812,89 @@ mdss_dsi1_phy: phy@ae97000 {
status = "disabled";
};
+ mdss_hdmi: hdmi@aea0000 {
+ compatible = "qcom,eliza-hdmi-tx";
+ reg = <0x0 0x0aea0000 0x0 0x1000>,
+ <0x0 0x0aee0000 0x0 0x1000>;
+ reg-names = "core_physical",
+ "hdcp_physical";
+
+ interrupts-extended = <&mdss 8>;
+
+ clocks = <&dispcc DISP_CC_MDSS_HDMI_AHBM_CLK>,
+ <&dispcc DISP_CC_MDSS_HDMI_APP_CLK>,
+ <&dispcc DISP_CC_MDSS_HDMI_PCLK_CLK>,
+ <&dispcc DISP_CC_MDSS_HDMI_INTF_CLK>,
+ <&mdss_hdmi_phy>,
+ <&dispcc DISP_CC_MDSS_HDMI_PCLK_CLK_SRC>;
+ clock-names = "iface",
+ "core",
+ "extp",
+ "phy_iface",
+ "pll",
+ "pixel_src";
+
+ operating-points-v2 = <&mdss_hdmi_opp_table>;
+
+ phys = <&mdss_hdmi_phy>;
+ power-domains = <&rpmhpd RPMHPD_CX>;
+ #sound-dai-cells = <1>;
+
+ status = "disabled";
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ reg = <0>;
+
+ mdss_hdmi_in: endpoint {
+ remote-endpoint = <&dpu_intf4_out>;
+ };
+ };
+
+ port@1 {
+ reg = <1>;
+
+ mdss_hdmi_out: endpoint {
+ };
+ };
+ };
+
+ mdss_hdmi_opp_table: opp-table {
+ compatible = "operating-points-v2";
+
+ opp-150000000 {
+ opp-hz = /bits/ 64 <150000000>;
+ required-opps = <&rpmhpd_opp_low_svs_d1>;
+ };
+
+ opp-300000000 {
+ opp-hz = /bits/ 64 <300000000>;
+ required-opps = <&rpmhpd_opp_svs>;
+ };
+ };
+ };
+
+ mdss_hdmi_phy: phy@aea1000 {
+ compatible = "qcom,eliza-hdmi-phy";
+ reg = <0x0 0x0aea1000 0x0 0x1000>;
+
+ clocks = <&dispcc DISP_CC_MDSS_AHB_CLK>,
+ <&tcsr TCSR_HDMI_CLKREF_EN>,
+ <&bi_tcxo_div2>;
+ clock-names = "iface",
+ "ref",
+ "xo";
+
+ #clock-cells = <0>;
+ #phy-cells = <0>;
+ power-domains = <&rpmhpd RPMHPD_CX>;
+
+ status = "disabled";
+ };
+
mdss_dp0: displayport-controller@af54000 {
compatible = "qcom,eliza-dp", "qcom,sm8650-dp";
reg = <0x0 0x0af54000 0x0 0x200>,
@@ -2913,7 +3003,7 @@ dispcc: clock-controller@af00000 {
<0>,
<0>, /* dp3 */
<0>,
- <0>; /* HDMI phy */
+ <&mdss_hdmi_phy>; /* HDMI phy */
power-domains = <&rpmhpd RPMHPD_MX>;
required-opps = <&rpmhpd_opp_low_svs>;
--
2.53.0
^ permalink raw reply related [flat|nested] 38+ messages in thread* [PATCH RFC/DO NOT MERGE 11/12] arm64: dts: qcom: eliza: Add HDMI display with HDMI PHY
@ 2026-08-28 14:05 ` Krzysztof Kozlowski
0 siblings, 0 replies; 38+ messages in thread
From: Krzysztof Kozlowski @ 2026-08-28 14:05 UTC (permalink / raw)
To: Rob Clark, Dmitry Baryshkov, Abhinav Kumar, Jessica Zhang,
Sean Paul, Marijn Suijten, David Airlie, Simona Vetter,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Vinod Koul, Neil Armstrong,
Manivannan Sadhasivam, Bjorn Andersson, Konrad Dybcio
Cc: linux-arm-msm, dri-devel, freedreno, linux-kernel, devicetree,
Krzysztof Kozlowski, Krzysztof Kozlowski, linux-phy
Add device nodes for HDMI (similar to previous one in MSM8998) and HDMI
PHY (new Synopsys-based block).
Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski@oss.qualcomm.com>
---
arch/arm64/boot/dts/qcom/eliza.dtsi | 94 ++++++++++++++++++++++++++++++++++++-
1 file changed, 92 insertions(+), 2 deletions(-)
diff --git a/arch/arm64/boot/dts/qcom/eliza.dtsi b/arch/arm64/boot/dts/qcom/eliza.dtsi
index 66ea4aaafd73..27dd15766f51 100644
--- a/arch/arm64/boot/dts/qcom/eliza.dtsi
+++ b/arch/arm64/boot/dts/qcom/eliza.dtsi
@@ -2570,7 +2570,14 @@ dpu_intf0_out: endpoint {
remote-endpoint = <&mdss_dp0_in>;
};
};
- /* TODO: HDMI */
+
+ port@3 {
+ reg = <3>;
+
+ dpu_intf4_out: endpoint {
+ remote-endpoint = <&mdss_hdmi_in>;
+ };
+ };
};
mdp_opp_table: opp-table {
@@ -2805,6 +2812,89 @@ mdss_dsi1_phy: phy@ae97000 {
status = "disabled";
};
+ mdss_hdmi: hdmi@aea0000 {
+ compatible = "qcom,eliza-hdmi-tx";
+ reg = <0x0 0x0aea0000 0x0 0x1000>,
+ <0x0 0x0aee0000 0x0 0x1000>;
+ reg-names = "core_physical",
+ "hdcp_physical";
+
+ interrupts-extended = <&mdss 8>;
+
+ clocks = <&dispcc DISP_CC_MDSS_HDMI_AHBM_CLK>,
+ <&dispcc DISP_CC_MDSS_HDMI_APP_CLK>,
+ <&dispcc DISP_CC_MDSS_HDMI_PCLK_CLK>,
+ <&dispcc DISP_CC_MDSS_HDMI_INTF_CLK>,
+ <&mdss_hdmi_phy>,
+ <&dispcc DISP_CC_MDSS_HDMI_PCLK_CLK_SRC>;
+ clock-names = "iface",
+ "core",
+ "extp",
+ "phy_iface",
+ "pll",
+ "pixel_src";
+
+ operating-points-v2 = <&mdss_hdmi_opp_table>;
+
+ phys = <&mdss_hdmi_phy>;
+ power-domains = <&rpmhpd RPMHPD_CX>;
+ #sound-dai-cells = <1>;
+
+ status = "disabled";
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ reg = <0>;
+
+ mdss_hdmi_in: endpoint {
+ remote-endpoint = <&dpu_intf4_out>;
+ };
+ };
+
+ port@1 {
+ reg = <1>;
+
+ mdss_hdmi_out: endpoint {
+ };
+ };
+ };
+
+ mdss_hdmi_opp_table: opp-table {
+ compatible = "operating-points-v2";
+
+ opp-150000000 {
+ opp-hz = /bits/ 64 <150000000>;
+ required-opps = <&rpmhpd_opp_low_svs_d1>;
+ };
+
+ opp-300000000 {
+ opp-hz = /bits/ 64 <300000000>;
+ required-opps = <&rpmhpd_opp_svs>;
+ };
+ };
+ };
+
+ mdss_hdmi_phy: phy@aea1000 {
+ compatible = "qcom,eliza-hdmi-phy";
+ reg = <0x0 0x0aea1000 0x0 0x1000>;
+
+ clocks = <&dispcc DISP_CC_MDSS_AHB_CLK>,
+ <&tcsr TCSR_HDMI_CLKREF_EN>,
+ <&bi_tcxo_div2>;
+ clock-names = "iface",
+ "ref",
+ "xo";
+
+ #clock-cells = <0>;
+ #phy-cells = <0>;
+ power-domains = <&rpmhpd RPMHPD_CX>;
+
+ status = "disabled";
+ };
+
mdss_dp0: displayport-controller@af54000 {
compatible = "qcom,eliza-dp", "qcom,sm8650-dp";
reg = <0x0 0x0af54000 0x0 0x200>,
@@ -2913,7 +3003,7 @@ dispcc: clock-controller@af00000 {
<0>,
<0>, /* dp3 */
<0>,
- <0>; /* HDMI phy */
+ <&mdss_hdmi_phy>; /* HDMI phy */
power-domains = <&rpmhpd RPMHPD_MX>;
required-opps = <&rpmhpd_opp_low_svs>;
--
2.53.0
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply related [flat|nested] 38+ messages in thread
* [PATCH RFC/DO NOT MERGE 12/12] arm64: dts: qcom: eliza-evk: Add native HDMI
2026-08-28 14:04 ` Krzysztof Kozlowski
@ 2026-08-28 14:05 ` Krzysztof Kozlowski
-1 siblings, 0 replies; 38+ messages in thread
From: Krzysztof Kozlowski @ 2026-08-28 14:05 UTC (permalink / raw)
To: Rob Clark, Dmitry Baryshkov, Abhinav Kumar, Jessica Zhang,
Sean Paul, Marijn Suijten, David Airlie, Simona Vetter,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Vinod Koul, Neil Armstrong,
Manivannan Sadhasivam, Bjorn Andersson, Konrad Dybcio
Cc: linux-arm-msm, dri-devel, freedreno, linux-kernel, devicetree,
Krzysztof Kozlowski, Krzysztof Kozlowski, linux-phy
Eliza EVK comes with two HDMI outputs: native eARC and via Lontium
DSI2HDMI converter. Add the first one, with the 5V power supply.
Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski@oss.qualcomm.com>
---
arch/arm64/boot/dts/qcom/eliza-evk.dtsi | 103 ++++++++++++++++++++++++++++++++
1 file changed, 103 insertions(+)
diff --git a/arch/arm64/boot/dts/qcom/eliza-evk.dtsi b/arch/arm64/boot/dts/qcom/eliza-evk.dtsi
index 2fc945658300..533d52ecaacb 100644
--- a/arch/arm64/boot/dts/qcom/eliza-evk.dtsi
+++ b/arch/arm64/boot/dts/qcom/eliza-evk.dtsi
@@ -12,6 +12,29 @@ chosen {
stdout-path = "serial0:115200n8";
};
+ hdmi_5p0_reg: regulator-hdmi-5v0 {
+ compatible = "regulator-fixed";
+ regulator-name = "hdmi_5p0";
+
+ regulator-min-microvolt = <5000000>;
+ regulator-max-microvolt = <5000000>;
+ gpio = <&tlmm 184 GPIO_ACTIVE_HIGH>;
+ enable-active-high;
+ pinctrl-0 = <&hdmi_5p0_state>;
+ pinctrl-names = "default";
+ };
+
+ hdmi-0-connector {
+ compatible = "hdmi-connector";
+ type = "a";
+
+ port {
+ hdmi_0_connector_in: endpoint {
+ remote-endpoint = <&mdss_hdmi_out>;
+ };
+ };
+ };
+
pmic-glink {
compatible = "qcom,eliza-pmic-glink",
"qcom,sm8550-pmic-glink",
@@ -51,6 +74,34 @@ pmic_glink_ss_in: endpoint {
};
};
+&mdss {
+ status = "okay";
+};
+
+&mdss_hdmi {
+ pinctrl-0 = <&hdmi_ddc_default>,
+ <&hdmi_cec_active>,
+ <&hdmi_hpd_active>;
+ pinctrl-1 = <&hdmi_ddc_default>,
+ <&hdmi_cec_sleep>,
+ <&hdmi_hpd_sleep>;
+ pinctrl-names = "default", "sleep";
+
+ core-vcc-supply = <&vreg_l2b>;
+ core-vdda-supply = <&vreg_l4b>;
+ vddio-supply = <&hdmi_5p0_reg>;
+
+ status = "okay";
+};
+
+&mdss_hdmi_out {
+ remote-endpoint = <&hdmi_0_connector_in>;
+};
+
+&mdss_hdmi_phy {
+ status = "okay";
+};
+
&pm7550ba_eusb2_repeater {
vdd18-supply = <&vreg_l7b>;
vdd3-supply = <&vreg_l17b>;
@@ -70,11 +121,63 @@ &sdhc_2 {
};
&tlmm {
+ hdmi_ddc_default: hdmi-ddc-state {
+ hdmi-ddc-scl-pins {
+ pins = "gpio6";
+ function = "hdmi_ddc_scl";
+ drive-strength = <2>;
+ bias-pull-up;
+ };
+
+ hdmi-ddc-sda-pins {
+ pins = "gpio7";
+ function = "hdmi_ddc_sda";
+ drive-strength = <2>;
+ bias-pull-up;
+ };
+ };
+
+ hdmi_cec_active: hdmi-cec-active-state {
+ pins = "gpio46";
+ function = "hdmi_tx_cec";
+ drive-strength = <16>;
+ bias-pull-up;
+ };
+
+ hdmi_cec_sleep: hdmi-cec-sleep-state {
+ pins = "gpio46";
+ function = "hdmi_tx_cec";
+ drive-strength = <2>;
+ bias-pull-up;
+ };
+
+ hdmi_hpd_active: hdmi-hpd-active-state {
+ pins = "gpio47";
+ function = "hdmi_hot_plug";
+ drive-strength = <16>;
+ bias-pull-down;
+ };
+
+ hdmi_hpd_sleep: hdmi-hpd-sleep-state {
+ pins = "gpio47";
+ function = "hdmi_hot_plug";
+ drive-strength = <2>;
+ bias-pull-down;
+ };
+
sd_cd: sd-cd-state {
pins = "gpio58";
function = "gpio";
bias-pull-up;
};
+
+ hdmi_5p0_state: hdmi-5p0-state {
+ pins = "gpio184";
+ function = "gpio";
+ drive-strength = <8>;
+ bias-disable;
+ output-low;
+ };
};
&uart13 {
--
2.53.0
^ permalink raw reply related [flat|nested] 38+ messages in thread* [PATCH RFC/DO NOT MERGE 12/12] arm64: dts: qcom: eliza-evk: Add native HDMI
@ 2026-08-28 14:05 ` Krzysztof Kozlowski
0 siblings, 0 replies; 38+ messages in thread
From: Krzysztof Kozlowski @ 2026-08-28 14:05 UTC (permalink / raw)
To: Rob Clark, Dmitry Baryshkov, Abhinav Kumar, Jessica Zhang,
Sean Paul, Marijn Suijten, David Airlie, Simona Vetter,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Vinod Koul, Neil Armstrong,
Manivannan Sadhasivam, Bjorn Andersson, Konrad Dybcio
Cc: linux-arm-msm, dri-devel, freedreno, linux-kernel, devicetree,
Krzysztof Kozlowski, Krzysztof Kozlowski, linux-phy
Eliza EVK comes with two HDMI outputs: native eARC and via Lontium
DSI2HDMI converter. Add the first one, with the 5V power supply.
Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski@oss.qualcomm.com>
---
arch/arm64/boot/dts/qcom/eliza-evk.dtsi | 103 ++++++++++++++++++++++++++++++++
1 file changed, 103 insertions(+)
diff --git a/arch/arm64/boot/dts/qcom/eliza-evk.dtsi b/arch/arm64/boot/dts/qcom/eliza-evk.dtsi
index 2fc945658300..533d52ecaacb 100644
--- a/arch/arm64/boot/dts/qcom/eliza-evk.dtsi
+++ b/arch/arm64/boot/dts/qcom/eliza-evk.dtsi
@@ -12,6 +12,29 @@ chosen {
stdout-path = "serial0:115200n8";
};
+ hdmi_5p0_reg: regulator-hdmi-5v0 {
+ compatible = "regulator-fixed";
+ regulator-name = "hdmi_5p0";
+
+ regulator-min-microvolt = <5000000>;
+ regulator-max-microvolt = <5000000>;
+ gpio = <&tlmm 184 GPIO_ACTIVE_HIGH>;
+ enable-active-high;
+ pinctrl-0 = <&hdmi_5p0_state>;
+ pinctrl-names = "default";
+ };
+
+ hdmi-0-connector {
+ compatible = "hdmi-connector";
+ type = "a";
+
+ port {
+ hdmi_0_connector_in: endpoint {
+ remote-endpoint = <&mdss_hdmi_out>;
+ };
+ };
+ };
+
pmic-glink {
compatible = "qcom,eliza-pmic-glink",
"qcom,sm8550-pmic-glink",
@@ -51,6 +74,34 @@ pmic_glink_ss_in: endpoint {
};
};
+&mdss {
+ status = "okay";
+};
+
+&mdss_hdmi {
+ pinctrl-0 = <&hdmi_ddc_default>,
+ <&hdmi_cec_active>,
+ <&hdmi_hpd_active>;
+ pinctrl-1 = <&hdmi_ddc_default>,
+ <&hdmi_cec_sleep>,
+ <&hdmi_hpd_sleep>;
+ pinctrl-names = "default", "sleep";
+
+ core-vcc-supply = <&vreg_l2b>;
+ core-vdda-supply = <&vreg_l4b>;
+ vddio-supply = <&hdmi_5p0_reg>;
+
+ status = "okay";
+};
+
+&mdss_hdmi_out {
+ remote-endpoint = <&hdmi_0_connector_in>;
+};
+
+&mdss_hdmi_phy {
+ status = "okay";
+};
+
&pm7550ba_eusb2_repeater {
vdd18-supply = <&vreg_l7b>;
vdd3-supply = <&vreg_l17b>;
@@ -70,11 +121,63 @@ &sdhc_2 {
};
&tlmm {
+ hdmi_ddc_default: hdmi-ddc-state {
+ hdmi-ddc-scl-pins {
+ pins = "gpio6";
+ function = "hdmi_ddc_scl";
+ drive-strength = <2>;
+ bias-pull-up;
+ };
+
+ hdmi-ddc-sda-pins {
+ pins = "gpio7";
+ function = "hdmi_ddc_sda";
+ drive-strength = <2>;
+ bias-pull-up;
+ };
+ };
+
+ hdmi_cec_active: hdmi-cec-active-state {
+ pins = "gpio46";
+ function = "hdmi_tx_cec";
+ drive-strength = <16>;
+ bias-pull-up;
+ };
+
+ hdmi_cec_sleep: hdmi-cec-sleep-state {
+ pins = "gpio46";
+ function = "hdmi_tx_cec";
+ drive-strength = <2>;
+ bias-pull-up;
+ };
+
+ hdmi_hpd_active: hdmi-hpd-active-state {
+ pins = "gpio47";
+ function = "hdmi_hot_plug";
+ drive-strength = <16>;
+ bias-pull-down;
+ };
+
+ hdmi_hpd_sleep: hdmi-hpd-sleep-state {
+ pins = "gpio47";
+ function = "hdmi_hot_plug";
+ drive-strength = <2>;
+ bias-pull-down;
+ };
+
sd_cd: sd-cd-state {
pins = "gpio58";
function = "gpio";
bias-pull-up;
};
+
+ hdmi_5p0_state: hdmi-5p0-state {
+ pins = "gpio184";
+ function = "gpio";
+ drive-strength = <8>;
+ bias-disable;
+ output-low;
+ };
};
&uart13 {
--
2.53.0
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply related [flat|nested] 38+ messages in thread