From 97bb94f5c797101a0b3256db5098f240d944ec47 Mon Sep 17 00:00:00 2001 From: Zhanjun Dong Date: Mon, 4 Nov 2024 13:41:03 -0800 Subject: [PATCH 1/7] drm/i915/guc: Flush ct receive tasklet during reset preparation mainline inclusion from mainline-v6.14-rc1 category: bugfix GuC to host communication is interrupt driven, the handling has 3 parts: interrupt context, tasklet and request queue worker. During GuC reset prepare, interrupt is disabled before destroy contexts steps start. The IRQ and worker are flushed to finish any outstanding in-progress message handling. But, the tasklet flush is missing, it might causes 2 race conditions: 1. Tasklet runs after IRQ flushed, add request to queue after worker flush started, causes unexpected G2H message request processing, meanwhile, reset prepare code already get the context destroyed. This will causes error reported about bad context state. (https://gitlab.freedesktop.org/drm/i915/kernel/-/issues/11349 and https://gitlab.freedesktop.org/drm/i915/kernel/-/issues/12303) 2. Tasklet runs after intel_guc_submission_reset_prepare, ct_try_receive_message start to run, while intel_uc_reset_prepare already finished guc sanitize and set ct->enable to false. This will causes warning on incorrect ct->enable state. (https://gitlab.freedesktop.org/drm/i915/kernel/-/issues/12439) Add the missing tasklet flush to flush all 3 parts. Signed-off-by: Zhanjun Dong Reviewed-by: Alan Previn Signed-off-by: John Harrison Link: https://patchwork.freedesktop.org/patch/msgid/20241104214103.214702-1-zhanjun.dong@intel.com (cherry picked from commit b939a08bc378a7c716ad7a9486b48794b95d22f5) Signed-off-by: Wentao Guan --- drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c b/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c index 8fcb536f8720..67da4362622b 100644 --- a/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c +++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c @@ -1700,6 +1700,10 @@ void intel_guc_submission_reset_prepare(struct intel_guc *guc) spin_lock_irq(guc_to_gt(guc)->irq_lock); spin_unlock_irq(guc_to_gt(guc)->irq_lock); + /* Flush tasklet */ + tasklet_disable(&guc->ct.receive_tasklet); + tasklet_enable(&guc->ct.receive_tasklet); + guc_flush_submissions(guc); guc_flush_destroyed_contexts(guc); flush_work(&guc->ct.requests.worker); From 90722a9c29a070bc1ea94b2299ef309d62c9f1db Mon Sep 17 00:00:00 2001 From: Suraj Kandpal Date: Fri, 3 Jan 2025 14:15:17 +0530 Subject: [PATCH 2/7] Revert "drm/i915/hdcp: Don't enable HDCP1.4 directly from check_link" mainline inclusion from mainline-v6.14-rc1 category: bugfix This reverts commit 483f7d94a0453564ad9295288c0242136c5f36a0. This needs to be reverted since HDCP even after updating the connector state HDCP property we don't reenable HDCP until the next commit in which the CP Property is set causing compliance to fail. --v2 -Fix build issue [Dnyaneshwar] Signed-off-by: Suraj Kandpal Reviewed-by: Dnyaneshwar Bhadane Link: https://patchwork.freedesktop.org/patch/msgid/20250103084517.239998-1-suraj.kandpal@intel.com (cherry picked from commit fcf73e20cd1fe60c3ba5f9626f1e8f9cd4511edf) Signed-off-by: Wentao Guan --- drivers/gpu/drm/i915/display/intel_hdcp.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_hdcp.c b/drivers/gpu/drm/i915/display/intel_hdcp.c index 4904d7702ce5..f0c72c622def 100644 --- a/drivers/gpu/drm/i915/display/intel_hdcp.c +++ b/drivers/gpu/drm/i915/display/intel_hdcp.c @@ -1087,9 +1087,15 @@ static int intel_hdcp_check_link(struct intel_connector *connector) goto out; } - intel_hdcp_update_value(connector, - DRM_MODE_CONTENT_PROTECTION_DESIRED, - true); + ret = intel_hdcp1_enable(connector); + if (ret) { + drm_err(&i915->drm, "Failed to enable hdcp (%d)\n", ret); + intel_hdcp_update_value(connector, + DRM_MODE_CONTENT_PROTECTION_DESIRED, + true); + goto out; + } + out: mutex_unlock(&dig_port->hdcp_mutex); mutex_unlock(&hdcp->mutex); From 9dab522f4f159f9c42fd996a842a15304e9689d8 Mon Sep 17 00:00:00 2001 From: Suraj Kandpal Date: Tue, 17 Dec 2024 14:07:23 +0530 Subject: [PATCH 3/7] drm/i915/hdcp: Fix Repeater authentication during topology change mainline inclusion from mainline-v6.15-rc1 category: bugfix When topology changes, before beginning a new HDCP authentication by sending AKE_init message we need to first authenticate only the repeater. Only after repeater authentication failure, it makes sense to start a new HDCP authentication. Even though it made sense to not enable HDCP directly from check_link and schedule it for later, repeater authentication needs to be done immediately. --v2 -Fix comment grammatical errors [Ankit] Fixes: 47ef55a8b784 ("drm/i915/hdcp: Don't enable HDCP2.2 directly from check_link") Signed-off-by: Suraj Kandpal Reviewed-by: Ankit Nautiyal Link: https://patchwork.freedesktop.org/patch/msgid/20241217083723.2883317-1-suraj.kandpal@intel.com (cherry picked from commit 605a33e765890e4f1345315afc25268d4ae0fb7c) Signed-off-by: Wentao Guan --- drivers/gpu/drm/i915/display/intel_hdcp.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/drivers/gpu/drm/i915/display/intel_hdcp.c b/drivers/gpu/drm/i915/display/intel_hdcp.c index f0c72c622def..f9f3099bf92d 100644 --- a/drivers/gpu/drm/i915/display/intel_hdcp.c +++ b/drivers/gpu/drm/i915/display/intel_hdcp.c @@ -2062,6 +2062,19 @@ static int intel_hdcp2_check_link(struct intel_connector *connector) drm_dbg_kms(&i915->drm, "HDCP2.2 Downstream topology change\n"); + + ret = hdcp2_authenticate_repeater_topology(connector); + if (!ret) { + intel_hdcp_update_value(connector, + DRM_MODE_CONTENT_PROTECTION_ENABLED, + true); + goto out; + } + + drm_dbg_kms(&i915->drm, + "[%s:%d] Repeater topology auth failed.(%d)\n", + connector->base.name, connector->base.base.id, + ret); } else { drm_dbg_kms(&i915->drm, "[%s:%d] HDCP2.2 link failed, retrying auth\n", From ed342a36344c6df09ed4aed758ee957a62139c1c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Fri, 25 Aug 2023 16:44:27 +0300 Subject: [PATCH 4/7] drm/i915/sdvo: Initialize the encoder earlier MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit mainline inclusion from mainline-v6.7-rc1 category: bugfix Call drm_encoder_init() earlier so that we don't have to keep passing the i915/dev_priv around separately. v2: Reorder drm_encoder_cleanup() in the error path (Jani) Reviewed-by: Jani Nikula Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20230825134431.24391-3-ville.syrjala@linux.intel.com (cherry picked from commit 0eb8252a6f795a439ffca424d474f840a39a58d2) Signed-off-by: Wentao Guan --- drivers/gpu/drm/i915/display/intel_sdvo.c | 36 +++++++++++------------ 1 file changed, 17 insertions(+), 19 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_sdvo.c b/drivers/gpu/drm/i915/display/intel_sdvo.c index e761c99ce170..f11700731463 100644 --- a/drivers/gpu/drm/i915/display/intel_sdvo.c +++ b/drivers/gpu/drm/i915/display/intel_sdvo.c @@ -2589,9 +2589,9 @@ intel_sdvo_guess_ddc_bus(struct intel_sdvo *sdvo) * outputs, then LVDS outputs. */ static void -intel_sdvo_select_ddc_bus(struct drm_i915_private *dev_priv, - struct intel_sdvo *sdvo) +intel_sdvo_select_ddc_bus(struct intel_sdvo *sdvo) { + struct drm_i915_private *dev_priv = to_i915(sdvo->base.base.dev); struct sdvo_device_mapping *mapping; if (sdvo->base.port == PORT_B) @@ -2606,9 +2606,9 @@ intel_sdvo_select_ddc_bus(struct drm_i915_private *dev_priv, } static void -intel_sdvo_select_i2c_bus(struct drm_i915_private *dev_priv, - struct intel_sdvo *sdvo) +intel_sdvo_select_i2c_bus(struct intel_sdvo *sdvo) { + struct drm_i915_private *dev_priv = to_i915(sdvo->base.base.dev); struct sdvo_device_mapping *mapping; u8 pin; @@ -2647,9 +2647,9 @@ intel_sdvo_is_hdmi_connector(struct intel_sdvo *intel_sdvo) } static u8 -intel_sdvo_get_slave_addr(struct drm_i915_private *dev_priv, - struct intel_sdvo *sdvo) +intel_sdvo_get_slave_addr(struct intel_sdvo *sdvo) { + struct drm_i915_private *dev_priv = to_i915(sdvo->base.base.dev); struct sdvo_device_mapping *my_mapping, *other_mapping; if (sdvo->base.port == PORT_B) { @@ -2970,7 +2970,6 @@ intel_sdvo_output_setup(struct intel_sdvo *intel_sdvo) SDVO_OUTPUT_LVDS0, SDVO_OUTPUT_LVDS1, }; - struct drm_i915_private *i915 = to_i915(intel_sdvo->base.base.dev); u16 flags; int i; @@ -2984,7 +2983,7 @@ intel_sdvo_output_setup(struct intel_sdvo *intel_sdvo) intel_sdvo->controlled_output = flags; - intel_sdvo_select_ddc_bus(i915, intel_sdvo); + intel_sdvo_select_ddc_bus(intel_sdvo); for (i = 0; i < ARRAY_SIZE(probe_order); i++) { u16 type = flags & probe_order[i]; @@ -3285,9 +3284,9 @@ static const struct i2c_lock_operations proxy_lock_ops = { }; static bool -intel_sdvo_init_ddc_proxy(struct intel_sdvo *sdvo, - struct drm_i915_private *dev_priv) +intel_sdvo_init_ddc_proxy(struct intel_sdvo *sdvo) { + struct drm_i915_private *dev_priv = to_i915(sdvo->base.base.dev); struct pci_dev *pdev = to_pci_dev(dev_priv->drm.dev); sdvo->ddc.owner = THIS_MODULE; @@ -3333,23 +3332,22 @@ bool intel_sdvo_init(struct drm_i915_private *dev_priv, if (!intel_sdvo) return false; - intel_sdvo->sdvo_reg = sdvo_reg; - intel_sdvo->base.port = port; - intel_sdvo->slave_addr = - intel_sdvo_get_slave_addr(dev_priv, intel_sdvo) >> 1; - intel_sdvo_select_i2c_bus(dev_priv, intel_sdvo); - if (!intel_sdvo_init_ddc_proxy(intel_sdvo, dev_priv)) - goto err_i2c_bus; - /* encoder type will be decided later */ intel_encoder = &intel_sdvo->base; intel_encoder->type = INTEL_OUTPUT_SDVO; intel_encoder->power_domain = POWER_DOMAIN_PORT_OTHER; intel_encoder->port = port; + drm_encoder_init(&dev_priv->drm, &intel_encoder->base, &intel_sdvo_enc_funcs, 0, "SDVO %c", port_name(port)); + intel_sdvo->sdvo_reg = sdvo_reg; + intel_sdvo->slave_addr = intel_sdvo_get_slave_addr(intel_sdvo) >> 1; + intel_sdvo_select_i2c_bus(intel_sdvo); + if (!intel_sdvo_init_ddc_proxy(intel_sdvo)) + goto err_i2c_bus; + /* Read the regs to test if we can talk to the device */ for (i = 0; i < 0x40; i++) { u8 byte; @@ -3443,10 +3441,10 @@ bool intel_sdvo_init(struct drm_i915_private *dev_priv, intel_sdvo_output_cleanup(intel_sdvo); err: - drm_encoder_cleanup(&intel_encoder->base); i2c_del_adapter(&intel_sdvo->ddc); err_i2c_bus: intel_sdvo_unselect_i2c_bus(intel_sdvo); + drm_encoder_cleanup(&intel_encoder->base); kfree(intel_sdvo); return false; From 549c0baa2da3d96df46044671726c721107e6764 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Fri, 25 Aug 2023 16:44:30 +0300 Subject: [PATCH 5/7] drm/i915/sdvo: Rework DDC bus handling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit mainline inclusion from mainline-v6.7-rc1 category: bugfix Each SDVO device can have up to three sets of DDC pins. Currently we just register a single i2c_adapter for the entire SDVO device and semi-randomly pick the "correct" set of DDC pins during intel_sdvo_tmds_sink_detect(). This doesn't make any real sense especially if we have multiple outputs each with their own dedicated DDC bus. Let's clean up this mess and register a dedicated i2c_adapter for each of the possible pin pairs. Each output (ie. connector) can then pick the correct i2c_adapter to use for its DDC bus. And we can just switch over to drm_connector_init_with_ddc() to take care of the connector->ddc association, which also populates the "ddc" sysfs symlink as a bonus. And now that things are based on the actual connector we can also nuke the sketchy sdvo->controller_output thing. Reviewed-by: Jani Nikula Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20230825134431.24391-6-ville.syrjala@linux.intel.com (cherry picked from commit c0ff6c6e4c2486734d417a61355e1da5d8773039) Signed-off-by: Wentao Guan --- drivers/gpu/drm/i915/display/intel_sdvo.c | 205 ++++++++++++---------- 1 file changed, 114 insertions(+), 91 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_sdvo.c b/drivers/gpu/drm/i915/display/intel_sdvo.c index f11700731463..c467822111ab 100644 --- a/drivers/gpu/drm/i915/display/intel_sdvo.c +++ b/drivers/gpu/drm/i915/display/intel_sdvo.c @@ -65,6 +65,8 @@ #define IS_TV_OR_LVDS(c) ((c)->output_flag & (SDVO_TV_MASK | SDVO_LVDS_MASK)) #define IS_DIGITAL(c) ((c)->output_flag & (SDVO_TMDS_MASK | SDVO_LVDS_MASK)) +#define HAS_DDC(c) ((c)->output_flag & (SDVO_RGB_MASK | SDVO_TMDS_MASK | \ + SDVO_LVDS_MASK)) static const char * const tv_format_names[] = { "NTSC_M" , "NTSC_J" , "NTSC_443", @@ -78,20 +80,25 @@ static const char * const tv_format_names[] = { #define TV_FORMAT_NUM ARRAY_SIZE(tv_format_names) +struct intel_sdvo; + +struct intel_sdvo_ddc { + struct i2c_adapter ddc; + struct intel_sdvo *sdvo; + u8 ddc_bus; +}; + struct intel_sdvo { struct intel_encoder base; struct i2c_adapter *i2c; u8 slave_addr; - struct i2c_adapter ddc; + struct intel_sdvo_ddc ddc[3]; /* Register for the SDVO device: SDVOB or SDVOC */ i915_reg_t sdvo_reg; - /* Active outputs controlled by this SDVO output */ - u16 controlled_output; - /* * Capabilities of the SDVO device returned by * intel_sdvo_get_capabilities() @@ -108,9 +115,6 @@ struct intel_sdvo { */ u16 hotplug_active; - /* DDC bus used by this SDVO encoder */ - u8 ddc_bus; - /* * the sdvo flag gets lost in round trip: dtd->adjusted_mode->dtd */ @@ -2041,18 +2045,15 @@ intel_sdvo_hotplug(struct intel_encoder *encoder, return intel_encoder_hotplug(encoder, connector); } -static bool -intel_sdvo_multifunc_encoder(struct intel_sdvo *intel_sdvo) -{ - /* Is there more than one type of output? */ - return hweight16(intel_sdvo->caps.output_flags) > 1; -} - static const struct drm_edid * intel_sdvo_get_edid(struct drm_connector *connector) { - struct intel_sdvo *sdvo = intel_attached_sdvo(to_intel_connector(connector)); - return drm_edid_read_ddc(connector, &sdvo->ddc); + struct i2c_adapter *ddc = connector->ddc; + + if (!ddc) + return NULL; + + return drm_edid_read_ddc(connector, ddc); } /* Mac mini hack -- use the same DDC as the analog connector */ @@ -2060,43 +2061,23 @@ static const struct drm_edid * intel_sdvo_get_analog_edid(struct drm_connector *connector) { struct drm_i915_private *i915 = to_i915(connector->dev); - struct i2c_adapter *i2c; + struct i2c_adapter *ddc; - i2c = intel_gmbus_get_adapter(i915, i915->display.vbt.crt_ddc_pin); + ddc = intel_gmbus_get_adapter(i915, i915->display.vbt.crt_ddc_pin); + if (!ddc) + return NULL; - return drm_edid_read_ddc(connector, i2c); + return drm_edid_read_ddc(connector, ddc); } static enum drm_connector_status intel_sdvo_tmds_sink_detect(struct drm_connector *connector) { - struct intel_sdvo *intel_sdvo = intel_attached_sdvo(to_intel_connector(connector)); enum drm_connector_status status; const struct drm_edid *drm_edid; drm_edid = intel_sdvo_get_edid(connector); - if (!drm_edid && intel_sdvo_multifunc_encoder(intel_sdvo)) { - u8 ddc, saved_ddc = intel_sdvo->ddc_bus; - - /* - * Don't use the 1 as the argument of DDC bus switch to get - * the EDID. It is used for SDVO SPD ROM. - */ - for (ddc = intel_sdvo->ddc_bus >> 1; ddc > 1; ddc >>= 1) { - intel_sdvo->ddc_bus = ddc; - drm_edid = intel_sdvo_get_edid(connector); - if (drm_edid) - break; - } - /* - * If we found the EDID on the other bus, - * assume that is the correct DDC bus. - */ - if (!drm_edid) - intel_sdvo->ddc_bus = saved_ddc; - } - /* * When there is no edid and no monitor is connected with VGA * port, try to use the CRT ddc to read the EDID for DVI-connector. @@ -2527,29 +2508,37 @@ static const struct drm_connector_helper_funcs intel_sdvo_connector_helper_funcs .atomic_check = intel_sdvo_atomic_check, }; -static void intel_sdvo_enc_destroy(struct drm_encoder *encoder) +static void intel_sdvo_encoder_destroy(struct drm_encoder *_encoder) { - struct intel_sdvo *intel_sdvo = to_sdvo(to_intel_encoder(encoder)); + struct intel_encoder *encoder = to_intel_encoder(_encoder); + struct intel_sdvo *sdvo = to_sdvo(encoder); + int i; - i2c_del_adapter(&intel_sdvo->ddc); - intel_encoder_destroy(encoder); -} + for (i = 0; i < ARRAY_SIZE(sdvo->ddc); i++) { + if (sdvo->ddc[i].ddc_bus) + i2c_del_adapter(&sdvo->ddc[i].ddc); + } + + drm_encoder_cleanup(&encoder->base); + kfree(sdvo); +}; static const struct drm_encoder_funcs intel_sdvo_enc_funcs = { - .destroy = intel_sdvo_enc_destroy, + .destroy = intel_sdvo_encoder_destroy, }; -static void -intel_sdvo_guess_ddc_bus(struct intel_sdvo *sdvo) +static int +intel_sdvo_guess_ddc_bus(struct intel_sdvo *sdvo, + struct intel_sdvo_connector *connector) { u16 mask = 0; - unsigned int num_bits; + int num_bits; /* * Make a mask of outputs less than or equal to our own priority in the * list. */ - switch (sdvo->controlled_output) { + switch (connector->output_flag) { case SDVO_OUTPUT_LVDS1: mask |= SDVO_OUTPUT_LVDS1; fallthrough; @@ -2578,7 +2567,7 @@ intel_sdvo_guess_ddc_bus(struct intel_sdvo *sdvo) num_bits = 3; /* Corresponds to SDVO_CONTROL_BUS_DDCx */ - sdvo->ddc_bus = 1 << num_bits; + return num_bits; } /* @@ -2588,11 +2577,13 @@ intel_sdvo_guess_ddc_bus(struct intel_sdvo *sdvo) * DDC bus number assignment is in a priority order of RGB outputs, then TMDS * outputs, then LVDS outputs. */ -static void -intel_sdvo_select_ddc_bus(struct intel_sdvo *sdvo) +static struct intel_sdvo_ddc * +intel_sdvo_select_ddc_bus(struct intel_sdvo *sdvo, + struct intel_sdvo_connector *connector) { struct drm_i915_private *dev_priv = to_i915(sdvo->base.base.dev); struct sdvo_device_mapping *mapping; + int ddc_bus; if (sdvo->base.port == PORT_B) mapping = &dev_priv->display.vbt.sdvo_mappings[0]; @@ -2600,9 +2591,14 @@ intel_sdvo_select_ddc_bus(struct intel_sdvo *sdvo) mapping = &dev_priv->display.vbt.sdvo_mappings[1]; if (mapping->initialized) - sdvo->ddc_bus = 1 << ((mapping->ddc_pin & 0xf0) >> 4); + ddc_bus = (mapping->ddc_pin & 0xf0) >> 4; else - intel_sdvo_guess_ddc_bus(sdvo); + ddc_bus = intel_sdvo_guess_ddc_bus(sdvo, connector); + + if (ddc_bus < 1 || ddc_bus > 3) + return NULL; + + return &sdvo->ddc[ddc_bus - 1]; } static void @@ -2685,22 +2681,30 @@ intel_sdvo_get_slave_addr(struct intel_sdvo *sdvo) return 0x72; } +static int +intel_sdvo_init_ddc_proxy(struct intel_sdvo_ddc *ddc, + struct intel_sdvo *sdvo, int bit); + static int intel_sdvo_connector_init(struct intel_sdvo_connector *connector, struct intel_sdvo *encoder) { - struct drm_connector *drm_connector; + struct drm_i915_private *i915 = to_i915(encoder->base.base.dev); + struct intel_sdvo_ddc *ddc = NULL; int ret; - drm_connector = &connector->base.base; - ret = drm_connector_init(encoder->base.base.dev, - drm_connector, - &intel_sdvo_connector_funcs, - connector->base.base.connector_type); + if (HAS_DDC(connector)) + ddc = intel_sdvo_select_ddc_bus(encoder, connector); + + ret = drm_connector_init_with_ddc(encoder->base.base.dev, + &connector->base.base, + &intel_sdvo_connector_funcs, + connector->base.base.connector_type, + ddc ? &ddc->ddc : NULL); if (ret < 0) return ret; - drm_connector_helper_add(drm_connector, + drm_connector_helper_add(&connector->base.base, &intel_sdvo_connector_helper_funcs); connector->base.base.display_info.subpixel_order = SubPixelHorizontalRGB; @@ -2709,6 +2713,11 @@ intel_sdvo_connector_init(struct intel_sdvo_connector *connector, intel_connector_attach_encoder(&connector->base, &encoder->base); + if (ddc) + drm_dbg_kms(&i915->drm, "[CONNECTOR:%d:%s] using %s\n", + connector->base.base.base.id, connector->base.base.name, + ddc->ddc.name); + return 0; } @@ -2906,7 +2915,7 @@ intel_sdvo_lvds_init(struct intel_sdvo *intel_sdvo, u16 type) if (!intel_panel_preferred_fixed_mode(intel_connector)) { mutex_lock(&i915->drm.mode_config.mutex); - intel_ddc_get_modes(connector, &intel_sdvo->ddc); + intel_ddc_get_modes(connector, connector->ddc); intel_panel_add_edid_fixed_modes(intel_connector, false); mutex_unlock(&i915->drm.mode_config.mutex); @@ -2981,10 +2990,6 @@ intel_sdvo_output_setup(struct intel_sdvo *intel_sdvo) return false; } - intel_sdvo->controlled_output = flags; - - intel_sdvo_select_ddc_bus(intel_sdvo); - for (i = 0; i < ARRAY_SIZE(probe_order); i++) { u16 type = flags & probe_order[i]; @@ -3237,9 +3242,10 @@ static int intel_sdvo_ddc_proxy_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs, int num) { - struct intel_sdvo *sdvo = adapter->algo_data; + struct intel_sdvo_ddc *ddc = adapter->algo_data; + struct intel_sdvo *sdvo = ddc->sdvo; - if (!__intel_sdvo_set_control_bus_switch(sdvo, sdvo->ddc_bus)) + if (!__intel_sdvo_set_control_bus_switch(sdvo, 1 << ddc->ddc_bus)) return -EIO; return sdvo->i2c->algo->master_xfer(sdvo->i2c, msgs, num); @@ -3247,7 +3253,9 @@ static int intel_sdvo_ddc_proxy_xfer(struct i2c_adapter *adapter, static u32 intel_sdvo_ddc_proxy_func(struct i2c_adapter *adapter) { - struct intel_sdvo *sdvo = adapter->algo_data; + struct intel_sdvo_ddc *ddc = adapter->algo_data; + struct intel_sdvo *sdvo = ddc->sdvo; + return sdvo->i2c->algo->functionality(sdvo->i2c); } @@ -3259,21 +3267,27 @@ static const struct i2c_algorithm intel_sdvo_ddc_proxy = { static void proxy_lock_bus(struct i2c_adapter *adapter, unsigned int flags) { - struct intel_sdvo *sdvo = adapter->algo_data; + struct intel_sdvo_ddc *ddc = adapter->algo_data; + struct intel_sdvo *sdvo = ddc->sdvo; + sdvo->i2c->lock_ops->lock_bus(sdvo->i2c, flags); } static int proxy_trylock_bus(struct i2c_adapter *adapter, unsigned int flags) { - struct intel_sdvo *sdvo = adapter->algo_data; + struct intel_sdvo_ddc *ddc = adapter->algo_data; + struct intel_sdvo *sdvo = ddc->sdvo; + return sdvo->i2c->lock_ops->trylock_bus(sdvo->i2c, flags); } static void proxy_unlock_bus(struct i2c_adapter *adapter, unsigned int flags) { - struct intel_sdvo *sdvo = adapter->algo_data; + struct intel_sdvo_ddc *ddc = adapter->algo_data; + struct intel_sdvo *sdvo = ddc->sdvo; + sdvo->i2c->lock_ops->unlock_bus(sdvo->i2c, flags); } @@ -3283,21 +3297,26 @@ static const struct i2c_lock_operations proxy_lock_ops = { .unlock_bus = proxy_unlock_bus, }; -static bool -intel_sdvo_init_ddc_proxy(struct intel_sdvo *sdvo) +static int +intel_sdvo_init_ddc_proxy(struct intel_sdvo_ddc *ddc, + struct intel_sdvo *sdvo, int ddc_bus) { struct drm_i915_private *dev_priv = to_i915(sdvo->base.base.dev); struct pci_dev *pdev = to_pci_dev(dev_priv->drm.dev); - sdvo->ddc.owner = THIS_MODULE; - sdvo->ddc.class = I2C_CLASS_DDC; - snprintf(sdvo->ddc.name, I2C_NAME_SIZE, "SDVO DDC proxy"); - sdvo->ddc.dev.parent = &pdev->dev; - sdvo->ddc.algo_data = sdvo; - sdvo->ddc.algo = &intel_sdvo_ddc_proxy; - sdvo->ddc.lock_ops = &proxy_lock_ops; + ddc->sdvo = sdvo; + ddc->ddc_bus = ddc_bus; - return i2c_add_adapter(&sdvo->ddc) == 0; + ddc->ddc.owner = THIS_MODULE; + ddc->ddc.class = I2C_CLASS_DDC; + snprintf(ddc->ddc.name, I2C_NAME_SIZE, "SDVO %c DDC%d", + port_name(sdvo->base.port), ddc_bus); + ddc->ddc.dev.parent = &pdev->dev; + ddc->ddc.algo_data = ddc; + ddc->ddc.algo = &intel_sdvo_ddc_proxy; + ddc->ddc.lock_ops = &proxy_lock_ops; + + return i2c_add_adapter(&ddc->ddc); } static bool is_sdvo_port_valid(struct drm_i915_private *dev_priv, enum port port) @@ -3344,9 +3363,8 @@ bool intel_sdvo_init(struct drm_i915_private *dev_priv, intel_sdvo->sdvo_reg = sdvo_reg; intel_sdvo->slave_addr = intel_sdvo_get_slave_addr(intel_sdvo) >> 1; + intel_sdvo_select_i2c_bus(intel_sdvo); - if (!intel_sdvo_init_ddc_proxy(intel_sdvo)) - goto err_i2c_bus; /* Read the regs to test if we can talk to the device */ for (i = 0; i < 0x40; i++) { @@ -3379,6 +3397,15 @@ bool intel_sdvo_init(struct drm_i915_private *dev_priv, intel_sdvo->colorimetry_cap = intel_sdvo_get_colorimetry_cap(intel_sdvo); + for (i = 0; i < ARRAY_SIZE(intel_sdvo->ddc); i++) { + int ret; + + ret = intel_sdvo_init_ddc_proxy(&intel_sdvo->ddc[i], + intel_sdvo, i + 1); + if (ret) + goto err; + } + if (!intel_sdvo_output_setup(intel_sdvo)) { drm_dbg_kms(&dev_priv->drm, "SDVO output failed to setup on %s\n", @@ -3439,13 +3466,9 @@ bool intel_sdvo_init(struct drm_i915_private *dev_priv, err_output: intel_sdvo_output_cleanup(intel_sdvo); - err: - i2c_del_adapter(&intel_sdvo->ddc); -err_i2c_bus: intel_sdvo_unselect_i2c_bus(intel_sdvo); - drm_encoder_cleanup(&intel_encoder->base); - kfree(intel_sdvo); + intel_sdvo_encoder_destroy(&intel_encoder->base); return false; } From ce6cad03b4bb7266324b714714a2c05a8674a706 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Fri, 25 Aug 2023 16:44:31 +0300 Subject: [PATCH 6/7] drm/i915/sdvo: Print out the i2c pin and slave address MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit mainline inclusion from mainline-v6.7-rc1 category: bugfix To reduce the guesswork a bit let's print out the SDVO device i2c bus and slave address during init. Reviewed-by: Jani Nikula Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20230825134431.24391-7-ville.syrjala@linux.intel.com (cherry picked from commit 9c7e9db11aefd1099689a3519cdcf4b0945338ec) Signed-off-by: Wentao Guan --- drivers/gpu/drm/i915/display/intel_sdvo.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/gpu/drm/i915/display/intel_sdvo.c b/drivers/gpu/drm/i915/display/intel_sdvo.c index c467822111ab..533b51a29e1f 100644 --- a/drivers/gpu/drm/i915/display/intel_sdvo.c +++ b/drivers/gpu/drm/i915/display/intel_sdvo.c @@ -2619,6 +2619,10 @@ intel_sdvo_select_i2c_bus(struct intel_sdvo *sdvo) else pin = GMBUS_PIN_DPB; + drm_dbg_kms(&dev_priv->drm, "[ENCODER:%d:%s] I2C pin %d, slave addr 0x%x\n", + sdvo->base.base.base.id, sdvo->base.base.name, + pin, sdvo->slave_addr); + sdvo->i2c = intel_gmbus_get_adapter(dev_priv, pin); /* From 670a25713af26ed9f3e8a6246e30a726d7c80a3a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Tue, 29 Aug 2023 14:39:20 +0300 Subject: [PATCH 7/7] drm/i915/sdvo: Constify mapping structs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit mainline inclusion from mainline-v6.7-rc1 category: bugfix We aren't intending to mutate the SDVO device mapping structs, so make them const. Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20230829113920.13713-13-ville.syrjala@linux.intel.com Reviewed-by: Jani Nikula (cherry picked from commit 32c32155cab3512bf921cabfb7a58c5f314f6c07) Signed-off-by: Wentao Guan --- drivers/gpu/drm/i915/display/intel_sdvo.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_sdvo.c b/drivers/gpu/drm/i915/display/intel_sdvo.c index 533b51a29e1f..5c699bd5a87a 100644 --- a/drivers/gpu/drm/i915/display/intel_sdvo.c +++ b/drivers/gpu/drm/i915/display/intel_sdvo.c @@ -2582,7 +2582,7 @@ intel_sdvo_select_ddc_bus(struct intel_sdvo *sdvo, struct intel_sdvo_connector *connector) { struct drm_i915_private *dev_priv = to_i915(sdvo->base.base.dev); - struct sdvo_device_mapping *mapping; + const struct sdvo_device_mapping *mapping; int ddc_bus; if (sdvo->base.port == PORT_B) @@ -2605,7 +2605,7 @@ static void intel_sdvo_select_i2c_bus(struct intel_sdvo *sdvo) { struct drm_i915_private *dev_priv = to_i915(sdvo->base.base.dev); - struct sdvo_device_mapping *mapping; + const struct sdvo_device_mapping *mapping; u8 pin; if (sdvo->base.port == PORT_B) @@ -2650,7 +2650,7 @@ static u8 intel_sdvo_get_slave_addr(struct intel_sdvo *sdvo) { struct drm_i915_private *dev_priv = to_i915(sdvo->base.base.dev); - struct sdvo_device_mapping *my_mapping, *other_mapping; + const struct sdvo_device_mapping *my_mapping, *other_mapping; if (sdvo->base.port == PORT_B) { my_mapping = &dev_priv->display.vbt.sdvo_mappings[0];