The dw_hdmi-rockchip driver validates pixel clock rates against the
HDMI PHY's internal clock provider on certain SoCs like RK3328.
This is currently achieved by dereferencing hdmi->phy->dev.of_node
to obtain the provider node, which violates the Generic PHY API's
encapsulation (the goal is for struct phy to be an opaque pointer).

Refactor dw_hdmi_rockchip_bind() to perform a manual phandle lookup
on the "hdmi" PHY index within the controller's DT node. This provides
a parallel path to the clock provider's OF node without relying on the
internal structure of the struct phy handle.

Signed-off-by: Vladimir Oltean <[email protected]>
---
Cc: Sandy Huang <[email protected]>
Cc: "Heiko Stübner" <[email protected]>
Cc: Andy Yan <[email protected]>
Cc: Maarten Lankhorst <[email protected]>
Cc: Maxime Ripard <[email protected]>
Cc: Thomas Zimmermann <[email protected]>
Cc: David Airlie <[email protected]>
Cc: Simona Vetter <[email protected]>
---
 drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c | 25 ++++++++++++---------
 1 file changed, 15 insertions(+), 10 deletions(-)

diff --git a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c 
b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
index 0dc1eb5d2ae3..7abb42e486c0 100644
--- a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
+++ b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
@@ -537,21 +537,22 @@ static int dw_hdmi_rockchip_bind(struct device *dev, 
struct device *master,
                                 void *data)
 {
        struct platform_device *pdev = to_platform_device(dev);
+       struct device_node *np = dev_of_node(dev);
        struct dw_hdmi_plat_data *plat_data;
        const struct of_device_id *match;
        struct drm_device *drm = data;
        struct drm_encoder *encoder;
        struct rockchip_hdmi *hdmi;
-       int ret;
+       int ret, index;
 
-       if (!pdev->dev.of_node)
+       if (!np)
                return -ENODEV;
 
        hdmi = devm_kzalloc(&pdev->dev, sizeof(*hdmi), GFP_KERNEL);
        if (!hdmi)
                return -ENOMEM;
 
-       match = of_match_node(dw_hdmi_rockchip_dt_ids, pdev->dev.of_node);
+       match = of_match_node(dw_hdmi_rockchip_dt_ids, np);
        plat_data = devm_kmemdup(&pdev->dev, match->data,
                                             sizeof(*plat_data), GFP_KERNEL);
        if (!plat_data)
@@ -564,9 +565,9 @@ static int dw_hdmi_rockchip_bind(struct device *dev, struct 
device *master,
        plat_data->priv_data = hdmi;
        encoder = &hdmi->encoder.encoder;
 
-       encoder->possible_crtcs = drm_of_find_possible_crtcs(drm, dev->of_node);
+       encoder->possible_crtcs = drm_of_find_possible_crtcs(drm, np);
        rockchip_drm_encoder_set_crtc_endpoint_id(&hdmi->encoder,
-                                                 dev->of_node, 0, 0);
+                                                 np, 0, 0);
 
        /*
         * If we failed to find the CRTC(s) which this encoder is
@@ -588,13 +589,17 @@ static int dw_hdmi_rockchip_bind(struct device *dev, 
struct device *master,
                return dev_err_probe(hdmi->dev, ret, "failed to get phy\n");
        }
 
-       if (hdmi->phy) {
+       index = of_property_match_string(np, "phy-names", "hdmi");
+       if (index >= 0) {
                struct of_phandle_args clkspec;
 
-               clkspec.np = hdmi->phy->dev.of_node;
-               hdmi->hdmiphy_clk = of_clk_get_from_provider(&clkspec);
-               if (IS_ERR(hdmi->hdmiphy_clk))
-                       hdmi->hdmiphy_clk = NULL;
+               if (!of_parse_phandle_with_args(np, "phys", "#phy-cells", index,
+                                               &clkspec)) {
+                       hdmi->hdmiphy_clk = of_clk_get_from_provider(&clkspec);
+                       of_node_put(clkspec.np);
+                       if (IS_ERR(hdmi->hdmiphy_clk))
+                               hdmi->hdmiphy_clk = NULL;
+               }
        }
 
        if (hdmi->chip_data == &rk3568_chip_data) {
-- 
2.43.0

Reply via email to