On Wed, Nov 4, 2026 at 2:46 PM Atharva Tiwari <[email protected]> wrote: > > This code adds support for 5K in iMac20,1 and iMac20,2 with > support of changing resolutions. >
Please give a better description of what has changed here. > Closes: https://gitlab.freedesktop.org/drm/amd/-/issues/4455 > Closes: https://gitlab.freedesktop.org/drm/amd/-/issues/4895 > > Signed-off-by: Atharva Tiwari <[email protected]> > --- > drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c | 32 ++++++++++++++-- > .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 26 +++++++++++++ > .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h | 7 ++++ > .../display/amdgpu_dm/amdgpu_dm_connector.c | 19 +++++++++- > .../amd/display/amdgpu_dm/amdgpu_dm_quirks.c | 29 ++++++++++++++- > .../gpu/drm/amd/display/dc/core/dc_resource.c | 8 ++++ > drivers/gpu/drm/amd/display/dc/dc.h | 2 + > .../amd/display/dc/hwss/dce110/dce110_hwseq.c | 37 +++++++++++++++++-- > .../drm/amd/display/dc/link/link_detection.c | 14 ++++++- > .../gpu/drm/amd/display/dc/link/link_dpms.c | 3 ++ > .../display/dc/link/protocols/link_dp_phy.c | 5 +++ > .../dc/link/protocols/link_dp_training.c | 9 ++++- > 12 files changed, 180 insertions(+), 11 deletions(-) > > diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c > b/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c > index 890792a94..fc107e4fa 100644 > --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c > +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c > @@ -21,6 +21,7 @@ > * > */ > > +#include <linux/dmi.h> > #include <linux/firmware.h> > #include <linux/kernfs.h> > > @@ -3412,6 +3413,22 @@ static int > amdgpu_discovery_set_ualink_ip_blocks(struct amdgpu_device *adev) > return 0; > } > > +static const struct dmi_system_id imac5k_table[] = { > + { > + .matches = { > + DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."), > + DMI_MATCH(DMI_PRODUCT_NAME, "iMac20,1"), > + }, > + }, > + { > + .matches = { > + DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."), > + DMI_MATCH(DMI_PRODUCT_NAME, "iMac20,2"), > + }, > + }, > + {} > +}; > + > int amdgpu_discovery_set_ip_blocks(struct amdgpu_device *adev) > { > int r; > @@ -4026,15 +4043,24 @@ int amdgpu_discovery_set_ip_blocks(struct > amdgpu_device *adev) > } > } > > + /* TODO: We should enable 5K in EFI and remove this quirk */ > + if (unlikely(dmi_check_system(imac5k_table))) { > + r = amdgpu_discovery_set_display_ip_blocks(adev); > + if (r) > + return r; > + } What's the reason for this change? > + > if (likely(adev->firmware.load_type == AMDGPU_FW_LOAD_PSP)) { > r = amdgpu_discovery_set_smu_ip_blocks(adev); > if (r) > return r; > } > > - r = amdgpu_discovery_set_display_ip_blocks(adev); > - if (r) > - return r; > + if (likely(!dmi_check_system(imac5k_table))) { > + r = amdgpu_discovery_set_display_ip_blocks(adev); > + if (r) > + return r; > + } > > r = amdgpu_discovery_set_gc_ip_blocks(adev); > if (r) > diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c > b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c > index 5b634ae07..a88c86051 100644 > --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c > +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c > @@ -639,6 +639,8 @@ static int amdgpu_dm_init(struct amdgpu_device *adev) > retrieve_dmi_info(&adev->dm); > if (adev->dm.edp0_on_dp1_quirk) > init_data.flags.support_edp0_on_dp1 = true; > + if (adev->dm.imac5K_support) > + init_data.flags.imac5K_support = true; > > if (adev->dm.bb_from_dmub) > init_data.bb_from_dmub = adev->dm.bb_from_dmub; > @@ -1967,6 +1969,11 @@ static int dm_resume(struct amdgpu_ip_block *ip_block) > dc_exit_ips_for_hw_access(dm->dc); > WARN_ON(!dc_commit_streams(dm->dc, &commit_params)); > > + if (dm->dc->config.imac5K_using_5K) { > + const u8 value = 1; > + > + core_link_write_dpcd(dm->dc->links[0], 0x4F1, &value, > 1); > + } > dm_gpureset_commit_state(dm->cached_dc_state, dm); > > dm_gpureset_toggle_interrupts(adev, dm->cached_dc_state, > true); > @@ -4739,6 +4746,25 @@ static void amdgpu_dm_commit_streams(struct > drm_atomic_commit *state, > dc_exit_ips_for_hw_access(dm->dc); > WARN_ON(!dc_commit_streams(dm->dc, ¶ms)); > > + if (dm->imac5K_support) { > + for_each_new_crtc_in_state(state, crtc, new_crtc_state, i) { > + dm_new_crtc_state = to_dm_crtc_state(new_crtc_state); > + > + if (!dm_new_crtc_state->stream) > + continue; > + > + if (dm_new_crtc_state->stream->signal != > SIGNAL_TYPE_EDP) > + continue; > + > + if (new_crtc_state->mode.vdisplay == 2880 && > new_crtc_state->mode.hdisplay == 2560) { > + u8 value = 1; > + > + core_link_write_dpcd(dm->dc->links[0], 0x4F1, > &value, 1); > + dm->dc->config.imac5K_using_5K = true; > + } else > + dm->dc->config.imac5K_using_5K = false; > + } > + } > bool frl_stream_found = false; > > for (i = 0; i < params.stream_count; i++) { > diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h > b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h > index 1b91fe4c3..65a2330c6 100644 > --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h > +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h > @@ -698,6 +698,13 @@ struct amdgpu_display_manager { > */ > bool edp0_on_dp1_quirk; > > + /** > + * @imac5K_support: > + * > + * quirk for iMac that support 5K > + */ > + bool imac5K_support; > + > /** > * @dpia_aux_lock: > * > diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.c > b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.c > index 2b81396bd..2269b91c3 100644 > --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.c > +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.c > @@ -123,6 +123,13 @@ STATIC_IFN_KUNIT int > dm_encoder_helper_atomic_check(struct drm_encoder *encoder, > drm_mode_vrefresh(adjusted_mode)); > dm_new_connector_state->scaling = RMX_ASPECT; > } > + > + if (aconnector->dc_link && > aconnector->dc_link->dc->config.imac5K_support) { > + if (crtc_state->mode.vdisplay != 2880) > + dm_new_connector_state->scaling = RMX_FULL; > + else > + dm_new_connector_state->scaling = RMX_OFF; > + } > return 0; > } > > @@ -3130,9 +3137,19 @@ STATIC_IFN_KUNIT int > amdgpu_dm_connector_get_modes(struct drm_connector *connect > const struct drm_edid *drm_edid = amdgpu_dm_connector->drm_edid; > struct dc_link_settings *verified_link_cap = > &dc_link->verified_link_cap; > const struct dc *dc = dc_link->dc; > + struct dc_sink *sink = amdgpu_dm_connector->dc_sink; > > encoder = amdgpu_dm_connector_to_encoder(connector); > > + if (dc->config.imac5K_support && sink && > + sink->link->link_index == 1 && !connector->edid_blob_ptr) { > + const struct drm_edid *kept = > drm_edid_alloc(sink->dc_edid.raw_edid, > + > sink->dc_edid.length); > + > + drm_edid_connector_update(connector, kept); > + drm_edid_free(kept); > + } > + > if (!drm_edid) { > amdgpu_dm_connector->num_modes = > drm_add_modes_noedid(connector, 640, 480); > @@ -3312,7 +3329,7 @@ void amdgpu_dm_connector_init_helper(struct > amdgpu_display_manager *dm, > adev->mode_info.underscan_vborder_property, > 0); > > - if (!aconnector->mst_root) > + if (!aconnector->mst_root && !(dm->imac5K_support && link_index <= 1)) > drm_connector_attach_max_bpc_property(&aconnector->base, 8, > 16); > > aconnector->base.state->max_bpc = 16; > diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_quirks.c > b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_quirks.c > index 259966703..8657dd972 100644 > --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_quirks.c > +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_quirks.c > @@ -33,11 +33,13 @@ > struct amdgpu_dm_quirks { > bool aux_hpd_discon; > bool support_edp0_on_dp1; > + bool imac5K_support; > }; > > static struct amdgpu_dm_quirks quirk_entries = { > .aux_hpd_discon = false, > - .support_edp0_on_dp1 = false > + .support_edp0_on_dp1 = false, > + .imac5K_support = false, > }; > > static int edp0_on_dp1_callback(const struct dmi_system_id *id) > @@ -52,6 +54,12 @@ static int aux_hpd_discon_callback(const struct > dmi_system_id *id) > return 0; > } > > +static int imac5K_support_callback(const struct dmi_system_id *id) > +{ > + quirk_entries.imac5K_support = true; > + return 0; > +} > + > static const struct dmi_system_id dmi_quirk_table[] = { > { > .callback = aux_hpd_discon_callback, > @@ -151,6 +159,20 @@ static const struct dmi_system_id dmi_quirk_table[] = { > DMI_MATCH(DMI_PRODUCT_NAME, "HP ProBook 465 16 inch > G11 Notebook PC"), > }, > }, > + { > + .callback = imac5K_support_callback, > + .matches = { > + DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."), > + DMI_MATCH(DMI_PRODUCT_NAME, "iMac20,1"), > + }, > + }, > + { > + .callback = imac5K_support_callback, > + .matches = { > + DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."), > + DMI_MATCH(DMI_PRODUCT_NAME, "iMac20,2"), > + }, > + }, > {} > /* TODO: refactor this from a fixed table to a dynamic option */ > }; > @@ -162,6 +184,7 @@ void retrieve_dmi_info(struct amdgpu_display_manager *dm) > > dm->aux_hpd_discon_quirk = false; > dm->edp0_on_dp1_quirk = false; > + dm->imac5K_support = false; > > dmi_id = dmi_check_system(dmi_quirk_table); > > @@ -176,6 +199,10 @@ void retrieve_dmi_info(struct amdgpu_display_manager *dm) > dm->edp0_on_dp1_quirk = true; > drm_info(dev, "support_edp0_on_dp1 attached\n"); > } > + if (quirk_entries.imac5K_support) { > + dm->imac5K_support = true; > + drm_info(dev, "imac5K_support attached\n"); > + } > } > EXPORT_IF_KUNIT(retrieve_dmi_info); > > diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c > b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c > index 187486d97..98f74ffc2 100644 > --- a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c > +++ b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c > @@ -689,6 +689,14 @@ bool resource_are_streams_timing_synchronizable( > struct dc_stream_state *stream1, > struct dc_stream_state *stream2) > { > + > + if (stream1->ctx->dc->config.imac5K_support && > + ((stream1->signal == SIGNAL_TYPE_EDP && stream2->signal == > SIGNAL_TYPE_DISPLAY_PORT && > + stream2->link->link_index == 1) || > + (stream2->signal == SIGNAL_TYPE_EDP && stream1->signal == > SIGNAL_TYPE_DISPLAY_PORT && > + stream1->link->link_index == 1))) > + return true; > + > if (stream1->timing.h_total != stream2->timing.h_total) > return false; > > diff --git a/drivers/gpu/drm/amd/display/dc/dc.h > b/drivers/gpu/drm/amd/display/dc/dc.h > index d3c484f45..a0b746250 100644 > --- a/drivers/gpu/drm/amd/display/dc/dc.h > +++ b/drivers/gpu/drm/amd/display/dc/dc.h > @@ -635,6 +635,8 @@ struct dc_config { > struct spl_sharpness_range dcn_sharpness_range; > struct spl_sharpness_range dcn_override_sharpness_range; > bool no_native422_support; > + bool imac5K_support; > + bool imac5K_using_5K; > }; > > enum visual_confirm { > diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dce110/dce110_hwseq.c > b/drivers/gpu/drm/amd/display/dc/hwss/dce110/dce110_hwseq.c > index 7b3aa02dd..aba1dc9b4 100644 > --- a/drivers/gpu/drm/amd/display/dc/hwss/dce110/dce110_hwseq.c > +++ b/drivers/gpu/drm/amd/display/dc/hwss/dce110/dce110_hwseq.c > @@ -2656,7 +2656,8 @@ enum dc_status dce110_apply_ctx_to_hw( > struct dce_hwseq *hws = dc->hwseq; > struct dc_bios *dcb = dc->ctx->dc_bios; > enum dc_status status; > - unsigned int i; > + unsigned int i, n, enable_order[MAX_PIPES]; > + int primary = -1, companion = -1; > bool was_hpo_acquired = resource_is_hpo_acquired(dc->current_state); > bool is_hpo_acquired = resource_is_hpo_acquired(context); > > @@ -2664,6 +2665,32 @@ enum dc_status dce110_apply_ctx_to_hw( > if (dc->config.use_pipe_ctx_sync_logic) > reset_syncd_pipes_from_disabled_pipes(dc, context); > > + for (i = 0; i < dc->res_pool->pipe_count; i++) { > + struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i]; > + > + enable_order[i] = i; > + if (!dc->config.imac5K_support || !pipe->stream || > + pipe->top_pipe || pipe->prev_odm_pipe) > + continue; > + if (pipe->stream->link->link_index == 0) > + primary = i; > + else if (pipe->stream->link->link_index == 1) > + companion = i; > + } > + if (companion >= 0 && primary > companion) { > + enable_order[companion] = primary; > + enable_order[primary] = companion; > + } > + > + if (primary >= 0 && companion >= 0) { > + struct pipe_ctx *old = > &dc->current_state->res_ctx.pipe_ctx[primary]; > + struct dc_link *right = > context->res_ctx.pipe_ctx[companion].stream->link; > + > + if (!old->stream || > + pipe_need_reprogram(old, > &context->res_ctx.pipe_ctx[primary])) > + right->link_state_valid = false; > + } > + > /* Reset old context */ > /* look up the targets that have been removed since last commit */ > hws->funcs.reset_hw_ctx_wrap(dc, context); > @@ -2705,10 +2732,12 @@ enum dc_status dce110_apply_ctx_to_hw( > dc->hwseq->funcs.setup_hpo_hw_control(dc->hwseq, > is_hpo_acquired); > } > > - for (i = 0; i < dc->res_pool->pipe_count; i++) { > + for (n = 0; n < dc->res_pool->pipe_count; n++) { > struct pipe_ctx *pipe_ctx_old = > - > &dc->current_state->res_ctx.pipe_ctx[i]; > - struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i]; > + &dc->current_state->res_ctx.pipe_ctx[enable_order[n]]; > + struct pipe_ctx *pipe_ctx = > &context->res_ctx.pipe_ctx[enable_order[n]]; > + > + i = enable_order[n]; > > if (pipe_ctx->stream == NULL) > continue; > diff --git a/drivers/gpu/drm/amd/display/dc/link/link_detection.c > b/drivers/gpu/drm/amd/display/dc/link/link_detection.c > index b4546f93a..a92399753 100644 > --- a/drivers/gpu/drm/amd/display/dc/link/link_detection.c > +++ b/drivers/gpu/drm/amd/display/dc/link/link_detection.c > @@ -1205,7 +1205,10 @@ static bool detect_link_and_local_sink(struct dc_link > *link, > if > (!link->dpcd_caps.set_power_state_capable_edp) > > link->wa_flags.dp_keep_receiver_powered = true; > } > - > + if (dc->config.imac5K_support) { > + const uint8_t val = 1; > + core_link_write_dpcd(link, 0x4F1, &val, 1); > + } > sink_caps.transaction_type = > DDC_TRANSACTION_TYPE_I2C_OVER_AUX; > sink_caps.signal = SIGNAL_TYPE_EDP; > break; > @@ -1634,6 +1637,15 @@ bool link_detect(struct dc_link *link, enum > dc_detect_reason reason) > bool is_delegated_to_mst_top_mgr = false; > enum dc_connection_type pre_link_type = link->type; > > + if (link->local_sink && > + link->dc->config.imac5K_support && > + link->local_sink->link->link_index == 1) > + return false; > + > + if (reason == DETECT_REASON_BOOT && link->dc->config.imac5K_support && > + link->link_index == 1) > + msleep(100); > + > is_local_sink_detect_success = detect_link_and_local_sink(link, > reason); > > if (is_local_sink_detect_success && link->local_sink) { > diff --git a/drivers/gpu/drm/amd/display/dc/link/link_dpms.c > b/drivers/gpu/drm/amd/display/dc/link/link_dpms.c > index 2aeb9a0e6..3d7d1ddc4 100644 > --- a/drivers/gpu/drm/amd/display/dc/link/link_dpms.c > +++ b/drivers/gpu/drm/amd/display/dc/link/link_dpms.c > @@ -2084,6 +2084,9 @@ static enum dc_status enable_link_dp(struct dc_state > *state, > !link->dc->config.enable_dpia_pre_training) > do_fallback = true; > > + if (link->dc->config.imac5K_support && link->link_index == 1) > + msleep(100); > + > /* > * Temporary w/a to get DP2.0 link rates to work with SST. > * TODO DP2.0 - Workaround: Remove w/a if and when the issue is > resolved. > diff --git a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_phy.c > b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_phy.c > index 49521ac4b..e90164a58 100644 > --- a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_phy.c > +++ b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_phy.c > @@ -53,6 +53,11 @@ void dpcd_write_rx_power_ctrl(struct dc_link *link, bool > on) > core_link_write_dpcd(link, DP_SET_POWER, &state, > sizeof(state)); > > + if (on && link->dc->config.imac5K_support && > + link->connector_signal == SIGNAL_TYPE_EDP) { > + state = 1; > + core_link_write_dpcd(link, 0x4F1, &state, sizeof(state)); > + } > } > > void dp_enable_link_phy( > diff --git a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training.c > b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training.c > index 3be36d106..4eca11169 100644 > --- a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training.c > +++ b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training.c > @@ -1540,8 +1540,15 @@ static enum link_training_result > dp_transition_to_video_idle( > */ > if (link->connector_signal != SIGNAL_TYPE_EDP && status == > LINK_TRAINING_SUCCESS) { > msleep(5); > - if (!link->skip_fallback_on_link_loss) > + if (link->dc->config.imac5K_support && > link->link_index == 1) { > + uint8_t lanes; > + > + if (core_link_read_dpcd(link, > DP_LANE0_1_STATUS, > + &lanes, 1) != DC_OK) > + status = LINK_TRAINING_LINK_LOSS; > + } else if (!link->skip_fallback_on_link_loss) { > status = dp_check_link_loss_status(link, > lt_settings); > + } > } > return status; > } I think the rest of this can be simplified quite a bit. I'd suggest rebasing this on the other 5K support patches and see how much of that code you can share. https://lists.freedesktop.org/archives/dri-devel/2026-November/610011.html Alex > -- > 2.55.0 >
