The HDMI driver stored the drm_connector in struct hdmi solely so that a
handful of call sites could consult connector->display_info.is_hdmi, and
so that the hotplug work could hand a connector to drm_bridge_detect().

Several of those call sites run outside of an atomic commit (the HPD
enable/disable paths in msm_hdmi_set_mode(), and the audio update path),
so they have no drm_atomic_state to derive the connector from and thus
relied on the stored pointer.

The only information actually consumed is the is_hdmi boolean. Cache it
in struct hdmi and refresh it from a new .hpd_notify bridge callback:
drm_bridge_connector_detect() updates the connector's EDID (and hence
display_info.is_hdmi) via drm_atomic_helper_connector_hdmi_hotplug()
before invoking .hpd_notify, so the cached value is always up to date.

With that, the stored connector becomes local to msm_hdmi_modeset_init():
the connector object is owned by the DRM core after creation, so there is
no need to keep a driver-side reference. The hotplug work now calls
msm_hdmi_bridge_detect() directly, which ignores its connector argument
anyway.

Assisted-by: Claude:claude-opus-4-8
Signed-off-by: Dmitry Baryshkov <[email protected]>
---
 drivers/gpu/drm/msm/hdmi/hdmi.c        | 17 ++++++++---------
 drivers/gpu/drm/msm/hdmi/hdmi.h        |  4 +++-
 drivers/gpu/drm/msm/hdmi/hdmi_audio.c  |  2 +-
 drivers/gpu/drm/msm/hdmi/hdmi_bridge.c | 16 ++++++++++++++--
 4 files changed, 26 insertions(+), 13 deletions(-)

diff --git a/drivers/gpu/drm/msm/hdmi/hdmi.c b/drivers/gpu/drm/msm/hdmi/hdmi.c
index 1d5a4b63f3c8..62961dddd8f5 100644
--- a/drivers/gpu/drm/msm/hdmi/hdmi.c
+++ b/drivers/gpu/drm/msm/hdmi/hdmi.c
@@ -27,7 +27,7 @@ void msm_hdmi_set_mode(struct hdmi *hdmi, bool power_on)
        spin_lock_irqsave(&hdmi->reg_lock, flags);
        if (power_on) {
                ctrl |= HDMI_CTRL_ENABLE;
-               if (!hdmi->connector->display_info.is_hdmi) {
+               if (!hdmi->is_hdmi) {
                        ctrl |= HDMI_CTRL_HDMI;
                        hdmi_write(hdmi, REG_HDMI_CTRL, ctrl);
                        ctrl &= ~HDMI_CTRL_HDMI;
@@ -164,6 +164,7 @@ static int msm_hdmi_modeset_init(struct msm_display 
*display,
                struct drm_device *dev, struct drm_encoder *encoder)
 {
        struct hdmi *hdmi = container_of(display, struct hdmi, display);
+       struct drm_connector *connector = NULL;
        int ret;
 
        hdmi->dev = dev;
@@ -184,11 +185,11 @@ static int msm_hdmi_modeset_init(struct msm_display 
*display,
                }
        }
 
-       hdmi->connector = drm_bridge_connector_init(hdmi->dev, encoder);
-       if (IS_ERR(hdmi->connector)) {
-               ret = PTR_ERR(hdmi->connector);
+       connector = drm_bridge_connector_init(hdmi->dev, encoder);
+       if (IS_ERR(connector)) {
+               ret = PTR_ERR(connector);
                DRM_DEV_ERROR(dev->dev, "failed to create HDMI connector: 
%d\n", ret);
-               hdmi->connector = NULL;
+               connector = NULL;
                goto fail;
        }
 
@@ -204,10 +205,8 @@ static int msm_hdmi_modeset_init(struct msm_display 
*display,
        return 0;
 
 fail:
-       if (hdmi->connector) {
-               hdmi->connector->funcs->destroy(hdmi->connector);
-               hdmi->connector = NULL;
-       }
+       if (connector)
+               connector->funcs->destroy(connector);
 
        return ret;
 }
diff --git a/drivers/gpu/drm/msm/hdmi/hdmi.h b/drivers/gpu/drm/msm/hdmi/hdmi.h
index 869f55d4704a..d4adaa6ccdd5 100644
--- a/drivers/gpu/drm/msm/hdmi/hdmi.h
+++ b/drivers/gpu/drm/msm/hdmi/hdmi.h
@@ -47,6 +47,9 @@ struct hdmi {
        struct mutex state_mutex; /* protects two booleans */
        unsigned long pixclock;
 
+       /* cached from the connector's EDID, updated on hotplug */
+       bool is_hdmi;
+
        void __iomem *mmio;
        phys_addr_t mmio_size;
        void __iomem *qfprom_mmio;
@@ -62,7 +65,6 @@ struct hdmi {
        struct device *phy_dev;
 
        struct i2c_adapter *i2c;
-       struct drm_connector *connector;
        struct drm_bridge *bridge;
 
        struct drm_bridge *next_bridge;
diff --git a/drivers/gpu/drm/msm/hdmi/hdmi_audio.c 
b/drivers/gpu/drm/msm/hdmi/hdmi_audio.c
index 249c167ab04d..ce1864f3f659 100644
--- a/drivers/gpu/drm/msm/hdmi/hdmi_audio.c
+++ b/drivers/gpu/drm/msm/hdmi/hdmi_audio.c
@@ -19,7 +19,7 @@ int msm_hdmi_audio_update(struct hdmi *hdmi)
        bool enabled = audio->enabled;
        u32 acr_pkt_ctrl, vbi_pkt_ctrl, aud_pkt_ctrl, audio_config;
 
-       if (!hdmi->connector->display_info.is_hdmi)
+       if (!hdmi->is_hdmi)
                return -EINVAL;
 
        DBG("audio: enabled=%d, channels=%d, rate=%d",
diff --git a/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c 
b/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c
index 7abb9243dba5..84a423af73e9 100644
--- a/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c
+++ b/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c
@@ -345,7 +345,7 @@ static void msm_hdmi_bridge_atomic_post_disable(struct 
drm_bridge *bridge,
        if (hdmi->power_on) {
                power_off(bridge);
                hdmi->power_on = false;
-               if (hdmi->connector->display_info.is_hdmi)
+               if (hdmi->is_hdmi)
                        msm_hdmi_audio_update(hdmi);
                msm_hdmi_phy_resource_disable(phy);
        }
@@ -452,6 +452,17 @@ static enum drm_mode_status 
msm_hdmi_bridge_tmds_char_rate_valid(const struct dr
        return 0;
 }
 
+static void msm_hdmi_bridge_hpd_notify(struct drm_bridge *bridge,
+                                      struct drm_connector *connector,
+                                      enum drm_connector_status status)
+{
+       struct hdmi_bridge *hdmi_bridge = to_hdmi_bridge(bridge);
+       struct hdmi *hdmi = hdmi_bridge->hdmi;
+
+       /* called after the EDID update, so display_info is up to date */
+       hdmi->is_hdmi = connector->display_info.is_hdmi;
+}
+
 static const struct drm_bridge_funcs msm_hdmi_bridge_funcs = {
        .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
        .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state,
@@ -460,6 +471,7 @@ static const struct drm_bridge_funcs msm_hdmi_bridge_funcs 
= {
        .atomic_post_disable = msm_hdmi_bridge_atomic_post_disable,
        .edid_read = msm_hdmi_bridge_edid_read,
        .detect = msm_hdmi_bridge_detect,
+       .hpd_notify = msm_hdmi_bridge_hpd_notify,
        .hpd_enable = msm_hdmi_hpd_enable,
        .hpd_disable = msm_hdmi_hpd_disable,
        .hdmi_tmds_char_rate_valid = msm_hdmi_bridge_tmds_char_rate_valid,
@@ -482,7 +494,7 @@ msm_hdmi_hotplug_work(struct work_struct *work)
                container_of(work, struct hdmi_bridge, hpd_work);
        struct drm_bridge *bridge = &hdmi_bridge->base;
 
-       drm_bridge_hpd_notify(bridge, drm_bridge_detect(bridge, 
hdmi_bridge->hdmi->connector));
+       drm_bridge_hpd_notify(bridge, msm_hdmi_bridge_detect(bridge, NULL));
 }
 
 /* initialize bridge */

-- 
2.47.3

Reply via email to