mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* [PATCH 2/3] drm/amd/display: unlock secondary tile on Apple 5K iMac panels
@ 2026-10-26 22:48 Richard Lane
  2026-10-27 17:13 ` Mario Limonciello
  0 siblings, 1 reply; 2+ messages in thread
From: Richard Lane @ 2026-10-26 22:48 UTC (permalink / raw)
  To: amd-gfx
  Cc: Alex Deucher, Christian König, Harry Wentland, Leo Li,
	Rodrigo Siqueira, Mario Limonciello, David Airlie, Simona Vetter,
	Richard Lane, dri-devel, linux-kernel

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:
- Pair the two internal dc_link instances during EDID quirk matching for
  DCE < 12 iMac15,1, iMac17,1, iMac18,3, and Polaris-based iMac19,1
  (identifying roles via 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.
- 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.
- Override the secondary tile's connector type to DRM_MODE_CONNECTOR_eDP
  so userspace compositors treat both tiles as a single built-in display.
- 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 | 31 +++++++++++++++++
 .../display/amdgpu_dm/amdgpu_dm_connector.c   |  6 ++++
 .../amd/display/amdgpu_dm/amdgpu_dm_helpers.c | 34 +++++++++++++++++++
 drivers/gpu/drm/amd/display/dc/dc.h           | 12 +++++++
 .../drm/amd/display/dc/link/link_detection.c  | 14 +++++++-
 .../dc/link/protocols/link_dp_capability.c    |  7 ++++
 .../display/dc/link/protocols/link_dp_phy.c   |  8 +++++
 7 files changed, 111 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..548f975c7324 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,35 @@ STATIC_IFN_KUNIT void dm_destroy_cached_state(struct amdgpu_device *adev)
 }
 EXPORT_IF_KUNIT(dm_destroy_cached_state);
 
+/*
+ * Unlatch Apple 5K panel tiles and reset DPCD state on suspend/shutdown.
+ * This returns the TCON to single-pipe mode so the EFI boot logo is not
+ * skewed on reboot.
+ */
+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 (dc_link_is_apple_5k_secondary(link)) {
+			/*
+			 * Clear Boot Camp source table (0x310), eDP config
+			 * (0x10A), and secondary tile latch (0x4F1).
+			 */
+			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);
+
+			/* Unlatch primary root tile */
+			core_link_write_dpcd(link->tiled_peer, 0x4F1, zeros, 1);
+
+			break;
+		}
+	}
+}
+
 static int dm_suspend(struct amdgpu_ip_block *ip_block)
 {
 	struct amdgpu_device *adev = ip_block->adev;
@@ -1674,6 +1703,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_connector.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.c
index ded8e21897f1..27de7965f366 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
@@ -3460,6 +3460,12 @@ int amdgpu_dm_connector_init(struct amdgpu_display_manager *dm,
 	}
 
 	connector_type = to_drm_connector_type(link->connector_signal, link->link_id.id);
+	/*
+	 * Override Apple 5K secondary tile to eDP so compositors treat it as
+	 * built-in.
+	 */
+	if (dc_link_is_apple_5k_secondary(link))
+		connector_type = DRM_MODE_CONNECTOR_eDP;
 
 	res = drm_connector_init_with_ddc(
 			dm->ddev,
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..db6ac803e14f 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
@@ -97,6 +97,21 @@ STATIC_IFN_KUNIT u32 edid_extract_panel_id(struct edid *edid)
 }
 EXPORT_IF_KUNIT(edid_extract_panel_id);
 
+/*
+ * Pairs the two internal hardware links driving the Apple 5K panel,
+ * allowing the driver to synchronize both tiles as a single display.
+ */
+static void dm_helpers_wire_tiled_peer(struct dc_link *link)
+{
+	u32 peer_index = link->link_index ^ 1;
+
+	if (link->ctx->dce_version < DCE_VERSION_12_0 &&
+	    peer_index < link->dc->link_count) {
+		link->tiled_peer = link->dc->links[peer_index];
+		link->tiled_peer->tiled_peer = link;
+	}
+}
+
 STATIC_IFN_KUNIT void apply_edid_quirks(struct dc_link *link, struct edid *edid,
 			      struct dc_edid_caps *edid_caps)
 {
@@ -173,6 +188,25 @@ 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. Wire the peer
+	 * links to latch and synchronize both tiles, using connector_signal
+	 * for role assignment 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 (AE25/26), 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):
+		dm_helpers_wire_tiled_peer(link);
+		break;
 	default:
 		return;
 	}
diff --git a/drivers/gpu/drm/amd/display/dc/dc.h b/drivers/gpu/drm/amd/display/dc/dc.h
index f4fefa7c9ab8..498c11c0616f 100644
--- a/drivers/gpu/drm/amd/display/dc/dc.h
+++ b/drivers/gpu/drm/amd/display/dc/dc.h
@@ -2003,6 +2003,12 @@ struct dc_scratch_space {
 	bool skip_implict_edp_power_control;
 	bool forced_psr_active;
 	enum backlight_control_type backlight_control_type;
+
+	/*
+	 * Partner link for dual-tile Apple 5K panels, wired during EDID quirk
+	 * matching.
+	 */
+	struct dc_link *tiled_peer;
 };
 
 struct dc {
@@ -3172,6 +3178,12 @@ struct dc_sink {
 
 void dc_sink_retain(struct dc_sink *sink);
 void dc_sink_release(struct dc_sink *sink);
+/* Helper to identify secondary (DP) tile of the Apple 5K panel. */
+static inline bool dc_link_is_apple_5k_secondary(const struct dc_link *link)
+{
+	return link && link->tiled_peer &&
+	       link->connector_signal == SIGNAL_TYPE_DISPLAY_PORT;
+}
 
 struct dc_sink_init_data {
 	enum signal_type sink_signal;
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..25662ed3e612 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,8 @@ 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 (!dc_link_is_apple_5k_secondary(link) &&
+			    !dm_helpers_is_dp_sink_present(link))
 				result = SIGNAL_TYPE_DVI_SINGLE_LINK;
 		}
 		break;
@@ -1625,6 +1626,17 @@ bool link_detect_connection_type(struct dc_link *link, enum dc_connection_type *
 		}
 	}
 
+	/*
+	 * Internal tiled DP secondary reports HPD low until latched. Latch
+	 * the secondary tile via the root eDP link's DPCD (0x4F1) and force a
+	 * single-sink connection.
+	 */
+	if (*type == dc_connection_none &&
+	    dc_link_is_apple_5k_secondary(link)) {
+		core_link_write_dpcd(link->tiled_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..15f223e48091 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,13 @@ void dpcd_set_source_specific_data(struct dc_link *link)
 				link->dc->vendor_signature.data.raw,
 				sizeof(link->dc->vendor_signature.data.raw));
 	}
+	/*
+	 * Write the 3-byte Boot Camp source table (0x310) required to unlock
+	 * the secondary tile.
+	 */
+	if (dc_link_is_apple_5k_secondary(link))
+		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..abac117d0514 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,14 @@ void dpcd_write_rx_power_ctrl(struct dc_link *link, bool on)
 	if (link->sync_lt_in_progress)
 		return;
 
+	/*
+	 * Prevent Apple 5K secondary tile from entering D3 power-down.
+	 * Powering it off causes the TCON to drop HPD and stop responding to
+	 * AUX.
+	 */
+	if (!on && dc_link_is_apple_5k_secondary(link))
+		return;
+
 	core_link_write_dpcd(link, DP_SET_POWER, &state,
 						 sizeof(state));
 
-- 
2.55.0

^ permalink raw reply	[flat|nested] 2+ messages in thread

* Re: [PATCH 2/3] drm/amd/display: unlock secondary tile on Apple 5K iMac panels
  2026-10-26 22:48 [PATCH 2/3] drm/amd/display: unlock secondary tile on Apple 5K iMac panels Richard Lane
@ 2026-10-27 17:13 ` Mario Limonciello
  0 siblings, 0 replies; 2+ messages in thread
From: Mario Limonciello @ 2026-10-27 17:13 UTC (permalink / raw)
  To: Richard Lane, amd-gfx
  Cc: Alex Deucher, Christian König, Harry Wentland, Leo Li,
	Rodrigo Siqueira, David Airlie, Simona Vetter, dri-devel,
	linux-kernel



On 10/26/26 17:48, 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:
> - Pair the two internal dc_link instances during EDID quirk matching for
>    DCE < 12 iMac15,1, iMac17,1, iMac18,3, and Polaris-based iMac19,1
>    (identifying roles via 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.
> - 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.
> - Override the secondary tile's connector type to DRM_MODE_CONNECTOR_eDP
>    so userspace compositors treat both tiles as a single built-in display.
> - 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 | 31 +++++++++++++++++
>   .../display/amdgpu_dm/amdgpu_dm_connector.c   |  6 ++++
>   .../amd/display/amdgpu_dm/amdgpu_dm_helpers.c | 34 +++++++++++++++++++
>   drivers/gpu/drm/amd/display/dc/dc.h           | 12 +++++++
>   .../drm/amd/display/dc/link/link_detection.c  | 14 +++++++-
>   .../dc/link/protocols/link_dp_capability.c    |  7 ++++
>   .../display/dc/link/protocols/link_dp_phy.c   |  8 +++++
>   7 files changed, 111 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..548f975c7324 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,35 @@ STATIC_IFN_KUNIT void dm_destroy_cached_state(struct amdgpu_device *adev)
>   }
>   EXPORT_IF_KUNIT(dm_destroy_cached_state);
>   
> +/*
> + * Unlatch Apple 5K panel tiles and reset DPCD state on suspend/shutdown.
> + * This returns the TCON to single-pipe mode so the EFI boot logo is not
> + * skewed on reboot.
> + */
> +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 (dc_link_is_apple_5k_secondary(link)) {
> +			/*
> +			 * Clear Boot Camp source table (0x310), eDP config
> +			 * (0x10A), and secondary tile latch (0x4F1).
> +			 */
> +			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);
> +
> +			/* Unlatch primary root tile */
> +			core_link_write_dpcd(link->tiled_peer, 0x4F1, zeros, 1);
> +
> +			break;
> +		}
> +	}
> +}
> +
>   static int dm_suspend(struct amdgpu_ip_block *ip_block)
>   {
>   	struct amdgpu_device *adev = ip_block->adev;
> @@ -1674,6 +1703,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_connector.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.c
> index ded8e21897f1..27de7965f366 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
> @@ -3460,6 +3460,12 @@ int amdgpu_dm_connector_init(struct amdgpu_display_manager *dm,
>   	}
>   
>   	connector_type = to_drm_connector_type(link->connector_signal, link->link_id.id);
> +	/*
> +	 * Override Apple 5K secondary tile to eDP so compositors treat it as
> +	 * built-in.
> +	 */
> +	if (dc_link_is_apple_5k_secondary(link))
> +		connector_type = DRM_MODE_CONNECTOR_eDP;
>   
>   	res = drm_connector_init_with_ddc(
>   			dm->ddev,
> 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..db6ac803e14f 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
> @@ -97,6 +97,21 @@ STATIC_IFN_KUNIT u32 edid_extract_panel_id(struct edid *edid)
>   }
>   EXPORT_IF_KUNIT(edid_extract_panel_id);
>   
> +/*
> + * Pairs the two internal hardware links driving the Apple 5K panel,
> + * allowing the driver to synchronize both tiles as a single display.
> + */
> +static void dm_helpers_wire_tiled_peer(struct dc_link *link)
> +{
> +	u32 peer_index = link->link_index ^ 1;
> +
> +	if (link->ctx->dce_version < DCE_VERSION_12_0 &&
> +	    peer_index < link->dc->link_count) {
> +		link->tiled_peer = link->dc->links[peer_index];
> +		link->tiled_peer->tiled_peer = link;
> +	}
> +}
> +
>   STATIC_IFN_KUNIT void apply_edid_quirks(struct dc_link *link, struct edid *edid,
>   			      struct dc_edid_caps *edid_caps)
>   {
> @@ -173,6 +188,25 @@ 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. Wire the peer
> +	 * links to latch and synchronize both tiles, using connector_signal
> +	 * for role assignment 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 (AE25/26), 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):
> +		dm_helpers_wire_tiled_peer(link);
> +		break;
>   	default:
>   		return;
>   	}
> diff --git a/drivers/gpu/drm/amd/display/dc/dc.h b/drivers/gpu/drm/amd/display/dc/dc.h
> index f4fefa7c9ab8..498c11c0616f 100644
> --- a/drivers/gpu/drm/amd/display/dc/dc.h
> +++ b/drivers/gpu/drm/amd/display/dc/dc.h
> @@ -2003,6 +2003,12 @@ struct dc_scratch_space {
>   	bool skip_implict_edp_power_control;
>   	bool forced_psr_active;
>   	enum backlight_control_type backlight_control_type;
> +
> +	/*
> +	 * Partner link for dual-tile Apple 5K panels, wired during EDID quirk
> +	 * matching.
> +	 */
> +	struct dc_link *tiled_peer;

This feels like it's re-inventing drm_connector's has_tile, and tile_group.

There is also a special "tile_is_single_monitor".

Can you use those instead?

>   };
>   
>   struct dc {
> @@ -3172,6 +3178,12 @@ struct dc_sink {
>   
>   void dc_sink_retain(struct dc_sink *sink);
>   void dc_sink_release(struct dc_sink *sink);
> +/* Helper to identify secondary (DP) tile of the Apple 5K panel. */
> +static inline bool dc_link_is_apple_5k_secondary(const struct dc_link *link)
> +{
> +	return link && link->tiled_peer &&
> +	       link->connector_signal == SIGNAL_TYPE_DISPLAY_PORT;
> +}
>   
>   struct dc_sink_init_data {
>   	enum signal_type sink_signal;
> 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..25662ed3e612 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,8 @@ 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 (!dc_link_is_apple_5k_secondary(link) &&
> +			    !dm_helpers_is_dp_sink_present(link))
>   				result = SIGNAL_TYPE_DVI_SINGLE_LINK;
>   		}
>   		break;
> @@ -1625,6 +1626,17 @@ bool link_detect_connection_type(struct dc_link *link, enum dc_connection_type *
>   		}
>   	}
>   
> +	/*
> +	 * Internal tiled DP secondary reports HPD low until latched. Latch
> +	 * the secondary tile via the root eDP link's DPCD (0x4F1) and force a
> +	 * single-sink connection.
> +	 */
> +	if (*type == dc_connection_none &&
> +	    dc_link_is_apple_5k_secondary(link)) {
> +		core_link_write_dpcd(link->tiled_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..15f223e48091 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,13 @@ void dpcd_set_source_specific_data(struct dc_link *link)
>   				link->dc->vendor_signature.data.raw,
>   				sizeof(link->dc->vendor_signature.data.raw));
>   	}
> +	/*
> +	 * Write the 3-byte Boot Camp source table (0x310) required to unlock
> +	 * the secondary tile.
> +	 */
> +	if (dc_link_is_apple_5k_secondary(link))
> +		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..abac117d0514 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,14 @@ void dpcd_write_rx_power_ctrl(struct dc_link *link, bool on)
>   	if (link->sync_lt_in_progress)
>   		return;
>   
> +	/*
> +	 * Prevent Apple 5K secondary tile from entering D3 power-down.
> +	 * Powering it off causes the TCON to drop HPD and stop responding to
> +	 * AUX.
> +	 */
> +	if (!on && dc_link_is_apple_5k_secondary(link))
> +		return;
> +
>   	core_link_write_dpcd(link, DP_SET_POWER, &state,
>   						 sizeof(state));
>   


^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2026-10-27 17:13 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-10-26 22:48 [PATCH 2/3] drm/amd/display: unlock secondary tile on Apple 5K iMac panels Richard Lane
2026-10-27 17:13 ` Mario Limonciello

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®