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
