mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
From: Richard Lane <richardlanedev@gmail.com>
To: amd-gfx@lists.freedesktop.org
Cc: "Alex Deucher" <alexander.deucher@amd.com>,
	"Christian König" <christian.koenig@amd.com>,
	"David Airlie" <airlied@gmail.com>,
	"Simona Vetter" <simona@ffwll.ch>,
	"Harry Wentland" <harry.wentland@amd.com>,
	"Leo Li" <sunpeng.li@amd.com>,
	"Rodrigo Siqueira" <siqueira@igalia.com>,
	"Mario Limonciello" <mario.limonciello@amd.com>,
	dri-devel@lists.freedesktop.org, linux-kernel@vger.kernel.org
Subject: Re: [PATCH v2 2/3] drm/amd/display: unlock secondary tile on Apple 5K, iMac panels
Date: Sat, 14 Nov 2026 18:52:01 +0000	[thread overview]
Message-ID: <5e30862a-5161-49d7-8713-2da9dec4356d@gmail.com> (raw)
In-Reply-To: <94672259-c526-4ec7-a69c-7dda8d934593@gmail.com>

On 01/11/2026 23:24, Richard Lane wrote:
> Apple 27" 5K iMacs (2014-2019, iMac15,1 through Polaris-based iMac19,1)
> expose their internal 5120x2880 panel as a 2x1 tiled display over an eDP
> root link and a secondary DP link. At boot, the panel TCON operates in
> single-pipe mode and holds the secondary DP link's HPD line low until
> unlocked via DPCD registers.
> 
> Enable native tiled detection and link training for DCE < 12 Apple 5K
> panels:
> - Point the secondary DP dc_link to the root eDP dc_link (apple_5k_peer)
>   during EDID quirk matching on DCE < 12 iMac15,1, iMac17,1, iMac18,3,
>   and Polaris-based iMac19,1 (checking connector_signal since panel IDs
>   can flip across the two links after S3 wake). DCE >= 12 support for
>   Vega-based iMac19,1, iMacPro1,1, and iMac20,x is documented as TODO.
> - Avoid falling back to DVI and latch the secondary tile via DPCD 0x4F1
>   on the root eDP link when probing the secondary link, allowing the
>   secondary link to read its EDID and populate DRM's DisplayID tile
>   properties (has_tile, tile_group, and tile_is_single_monitor).
> - Write the 3-byte Boot Camp source table (0x04, 0x1d, 0x03) to DPCD
>   0x310 in dpcd_set_source_specific_data() to unlock the secondary tile.
> - Prevent the secondary tile from entering DP_SET_POWER D3, which causes
>   the TCON to drop HPD and stop responding to AUX transactions.
> - Unlatch both tiles (0x4F1) and clear DP_SOURCE_TABLE_REVISION (0x310)
>   and DP_EDP_CONFIGURATION_SET (0x10A) in dm_suspend() so the TCON
>   returns to single-pipe mode for the EFI boot screen across reboots.
> 
> Signed-off-by: Richard Lane <richardlanedev@gmail.com>
> ---
>  .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 19 ++++++++++++++++
>  .../amd/display/amdgpu_dm/amdgpu_dm_helpers.c | 22 +++++++++++++++++++
>  drivers/gpu/drm/amd/display/dc/dc.h           |  1 +
>  .../drm/amd/display/dc/link/link_detection.c  |  7 +++++-
>  .../dc/link/protocols/link_dp_capability.c    |  4 ++++
>  .../display/dc/link/protocols/link_dp_phy.c   |  3 +++
>  6 files changed, 55 insertions(+), 1 deletion(-)
> 
> 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 bdabb4bf14da..74cd88d8d580 100644
> --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
> +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
> @@ -1607,6 +1607,23 @@ STATIC_IFN_KUNIT void dm_destroy_cached_state(struct amdgpu_device *adev)
>  }
>  EXPORT_IF_KUNIT(dm_destroy_cached_state);
>  
> +static void amdgpu_dm_apple5k_unlatch(struct dc *dc)
> +{
> +	const u8 zeros[3] = { 0 };
> +
> +	for (int i = 0; i < dc->link_count; i++) {
> +		struct dc_link *link = dc->links[i];
> +
> +		if (link->apple_5k_peer) {
> +			core_link_write_dpcd(link, DP_SOURCE_TABLE_REVISION, zeros, 3);
> +			core_link_write_dpcd(link, DP_EDP_CONFIGURATION_SET, zeros, 1);
> +			core_link_write_dpcd(link, 0x4F1, zeros, 1);
> +			core_link_write_dpcd(link->apple_5k_peer, 0x4F1, zeros, 1);
> +			break;
> +		}
> +	}
> +}
> +
>  static int dm_suspend(struct amdgpu_ip_block *ip_block)
>  {
>  	struct amdgpu_device *adev = ip_block->adev;
> @@ -1674,6 +1691,8 @@ static int dm_suspend(struct amdgpu_ip_block *ip_block)
>  
>  	amdgpu_dm_hpd_rx_irq_work_suspend(dm);
>  
> +	amdgpu_dm_apple5k_unlatch(dm->dc);
> +
>  	dc_set_power_state(dm->dc, DC_ACPI_CM_POWER_STATE_D3);
>  
>  	if (dm->dc->caps.ips_support && adev->in_s0ix)
> diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c
> index 9774ea33272d..532748127f72 100644
> --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c
> +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c
> @@ -173,6 +173,28 @@ STATIC_IFN_KUNIT void apply_edid_quirks(struct dc_link *link, struct edid *edid,
>  		drm_dbg_driver(dev, "Force FreeSync min to 60 Hz on panel id %X\n", panel_id);
>  		edid_caps->panel_patch.force_freesync_min_hz = 60;
>  		break;
> +	/*
> +	 * Workaround for Apple 27" 5K iMacs which expose a 2x1 tiled internal
> +	 * panel over an eDP root link and a secondary DP link. Point the
> +	 * secondary link to the root link to latch/unlatch the TCON via DPCD,
> +	 * checking connector_signal as panel IDs can flip after wake.
> +	 * IDs (Root/Tile): iMac15,1 (AE01/02), iMac17,1 (AE05/06),
> +	 * iMac18,3 (AE11/12), iMac19,1 (AE25/26); TODO (DCE >= 12): iMac19,1
> +	 * Vega, iMacPro1,1 (AE1D/1E), iMac20,x (AE31/32).
> +	 */
> +	case drm_edid_encode_panel_id('A', 'P', 'P', 0xAE01):
> +	case drm_edid_encode_panel_id('A', 'P', 'P', 0xAE02):
> +	case drm_edid_encode_panel_id('A', 'P', 'P', 0xAE05):
> +	case drm_edid_encode_panel_id('A', 'P', 'P', 0xAE06):
> +	case drm_edid_encode_panel_id('A', 'P', 'P', 0xAE11):
> +	case drm_edid_encode_panel_id('A', 'P', 'P', 0xAE12):
> +	case drm_edid_encode_panel_id('A', 'P', 'P', 0xAE25):
> +	case drm_edid_encode_panel_id('A', 'P', 'P', 0xAE26):
> +		if (link->connector_signal == SIGNAL_TYPE_EDP &&
> +		    link->ctx->dce_version < DCE_VERSION_12_0 &&
> +		    (link->link_index ^ 1) < link->dc->link_count)
> +			link->dc->links[link->link_index ^ 1]->apple_5k_peer = link;
> +		break;
>  	default:
>  		return;
>  	}

For machines with both the Apple and OCLP (OpenCore Legacy Patcher) folders
deleted from the EFI partion, an additional 5 lines are required in
amdgpu_dm_helpers.c to latch the root tile. This works consistently across
multiple reboots. It also works with the Apple and OCLP folders in place.
I can add this to v3 of the patch.

@@ -26,6 +26,7 @@
 #include <linux/string.h>
 #include <linux/acpi.h>
 #include <linux/i2c.h>
+#include <linux/dmi.h>
 
 #include <drm/drm_atomic.h>
 #include <drm/drm_probe_helper.h>

@@ -1265,6 +1288,11 @@
 	if (link->dc->hwss.prepare_ddc)
 		link->dc->hwss.prepare_ddc(link);
 
+	if (link->connector_signal == SIGNAL_TYPE_EDP &&
+	    link->ctx->dce_version < DCE_VERSION_12_0 &&
+	    dmi_match(DMI_SYS_VENDOR, "Apple Inc."))
+		dm_helpers_dp_write_dpcd(ctx, link, 0x4F1, &(const uint8_t){1}, 1);
+
 	/* some dongles read edid incorrectly the first time,
 	 * do check sum and retry to make sure read correct edid.
 	 */

Richard
> diff --git a/drivers/gpu/drm/amd/display/dc/dc.h b/drivers/gpu/drm/amd/display/dc/dc.h
> index f4fefa7c9ab8..aa1a9eea99d1 100644
> --- a/drivers/gpu/drm/amd/display/dc/dc.h
> +++ b/drivers/gpu/drm/amd/display/dc/dc.h
> @@ -2003,6 +2003,7 @@ struct dc_scratch_space {
>  	bool skip_implict_edp_power_control;
>  	bool forced_psr_active;
>  	enum backlight_control_type backlight_control_type;
> +	struct dc_link *apple_5k_peer;
>  };
>  
>  struct dc {
> 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 b4546f93af0c..47755f8b9c3e 100644
> --- a/drivers/gpu/drm/amd/display/dc/link/link_detection.c
> +++ b/drivers/gpu/drm/amd/display/dc/link/link_detection.c
> @@ -218,7 +218,7 @@ static enum signal_type link_detect_sink_signal_type(struct dc_link *link,
>  			 * we assume signal is DVI; it could be corrected
>  			 * to HDMI after dongle detection
>  			 */
> -			if (!dm_helpers_is_dp_sink_present(link))
> +			if (!link->apple_5k_peer && !dm_helpers_is_dp_sink_present(link))
>  				result = SIGNAL_TYPE_DVI_SINGLE_LINK;
>  		}
>  		break;
> @@ -1625,6 +1625,11 @@ bool link_detect_connection_type(struct dc_link *link, enum dc_connection_type *
>  		}
>  	}
>  
> +	if (*type == dc_connection_none && link->apple_5k_peer) {
> +		core_link_write_dpcd(link->apple_5k_peer, 0x4F1, &(const uint8_t){1}, 1);
> +		*type = dc_connection_single;
> +	}
> +
>  	return true;
>  }
>  
> diff --git a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_capability.c b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_capability.c
> index ad1a499b0d9d..d646b156c90b 100644
> --- a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_capability.c
> +++ b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_capability.c
> @@ -1496,6 +1496,10 @@ void dpcd_set_source_specific_data(struct dc_link *link)
>  				link->dc->vendor_signature.data.raw,
>  				sizeof(link->dc->vendor_signature.data.raw));
>  	}
> +
> +	if (link->apple_5k_peer)
> +		core_link_write_dpcd(link, DP_SOURCE_TABLE_REVISION,
> +				     (const uint8_t[]){0x04, 0x1d, 0x03}, 3);
>  }
>  
>  void dpcd_write_cable_id_to_dprx(struct dc_link *link)
> 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 49521ac4b0e8..56fe2710ee2c 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
> @@ -50,6 +50,9 @@ void dpcd_write_rx_power_ctrl(struct dc_link *link, bool on)
>  	if (link->sync_lt_in_progress)
>  		return;
>  
> +	if (!on && link->apple_5k_peer)
> +		return;
> +
>  	core_link_write_dpcd(link, DP_SET_POWER, &state,
>  						 sizeof(state));
>  


      reply	other threads:[~2026-11-14 18:52 UTC|newest]

Thread overview: 2+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-11-01 23:24 Richard Lane
2026-11-14 18:52 ` Richard Lane [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=5e30862a-5161-49d7-8713-2da9dec4356d@gmail.com \
    --to=richardlanedev@gmail.com \
    --cc=airlied@gmail.com \
    --cc=alexander.deucher@amd.com \
    --cc=amd-gfx@lists.freedesktop.org \
    --cc=christian.koenig@amd.com \
    --cc=dri-devel@lists.freedesktop.org \
    --cc=harry.wentland@amd.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=mario.limonciello@amd.com \
    --cc=simona@ffwll.ch \
    --cc=siqueira@igalia.com \
    --cc=sunpeng.li@amd.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®