All of lore.kernel.org
 help / color / mirror / Atom feed
From: "Timur Kristóf" <timur.kristof@gmail.com>
To: amd-gfx@lists.freedesktop.org, Alexander.Deucher@amd.com,
	Christian.Koenig@amd.com,
	Mario Limonciello <mario.limonciello@amd.com>,
	Ivan Lipski <ivan.lipski@amd.com>, Alex Hung <alex.hung@amd.com>,
	Prike Liang <Prike.Liang@amd.com>, Leo Li <sunpeng.li@amd.com>,
	Ray Wu <Ray.Wu@amd.com>,
	siqueira@igalia.com
Cc: "Timur Kristóf" <timur.kristof@gmail.com>
Subject: [PATCH 10/14] drm/amd/display: Add DCE HWSS support for external DP bridge encoders
Date: Mon, 26 Jan 2026 22:08:33 +0100	[thread overview]
Message-ID: <20260126210837.21885-11-timur.kristof@gmail.com> (raw)
In-Reply-To: <20260126210837.21885-1-timur.kristof@gmail.com>

Some GPUs use external DP bridge encoders NUTMEG and TRAVIS
to implement analog and/or LVDS connections. Typically found in
CIK APU based laptops or on FM2 motherboards that have analog
connectors. These were necessary at the time because Kaveri
didn't have a built-in DAC nor LVDS support.

These devices sadly don't work transparently and need to be
controlled by the driver. Implement the necessary control for
the NUTMEG and TRAVIS encoders in the DCE HWSS.

For reference, see the legacy non-DC amdgpu display code:
amdgpu_atombios_encoder_setup_external_encoder()
amdgpu_atombios_encoder_setup_dig()
amdgpu_atombios_encoder_setup_ext_encoder_ddc()

- Prepare DDC before using it:
  Call the EXTERNAL_ENCODER_CONTROL_DDC_SETUP action so that
  the encoder knows to set up DDC over the AUX channel.

- When a stream is enabled or disabled:
  Call the EXTERNAL_ENCODER_CONTROL_ENABLE/DISABLE actions.

- Before enabling the DP link:
  Call the EXTERNAL_ENCODER_CONTROL_SETUP action.

This commit just hooks up the HWSS support.
Detecting the external DP bridge encoders will be done in
a subsequent commit.

Signed-off-by: Timur Kristóf <timur.kristof@gmail.com>
---
 drivers/gpu/drm/amd/display/dc/dc.h           |  4 ++
 .../amd/display/dc/hwss/dce110/dce110_hwseq.c | 54 +++++++++++++++++++
 2 files changed, 58 insertions(+)

diff --git a/drivers/gpu/drm/amd/display/dc/dc.h b/drivers/gpu/drm/amd/display/dc/dc.h
index ff15e5990ec0..11c0fa317f88 100644
--- a/drivers/gpu/drm/amd/display/dc/dc.h
+++ b/drivers/gpu/drm/amd/display/dc/dc.h
@@ -1681,6 +1681,10 @@ struct dc_scratch_space {
 	struct panel_cntl *panel_cntl;
 	struct link_encoder *link_enc;
 	struct graphics_object_id link_id;
+
+	/* External encoder eg. NUTMEG or TRAVIS used on CIK APUs. */
+	struct graphics_object_id ext_enc_id;
+
 	/* Endpoint type distinguishes display endpoints which do not have entries
 	 * in the BIOS connector table from those that do. Helps when tracking link
 	 * encoder to display endpoint assignments.
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 4e820020252b..3f5c833ce18a 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
@@ -660,6 +660,48 @@ void dce110_update_info_frame(struct pipe_ctx *pipe_ctx)
 	}
 }
 
+static void
+dce110_external_encoder_control(enum bp_external_encoder_control_action action,
+				struct dc_link *link,
+				struct dc_crtc_timing *timing)
+{
+	struct dc *dc = link->ctx->dc;
+	struct dc_bios *bios = link->ctx->dc_bios;
+	const struct dc_link_settings *link_settings = &link->cur_link_settings;
+	enum bp_result bp_result = BP_RESULT_OK;
+	struct bp_external_encoder_control ext_cntl = {
+		.action = action,
+		.connector_obj_id = link->link_enc->connector,
+		.encoder_id = link->ext_enc_id,
+		.lanes_number = link_settings->lane_count,
+		.link_rate = link_settings->link_rate,
+
+		/* Use signal type of the real link encoder, ie. DP */
+		.signal = link->connector_signal,
+
+		/* We don't know the timing yet when executing the SETUP action,
+		 * so use a reasonably high default value. It seems that ENABLE
+		 * can change the actual pixel clock but doesn't work with higher
+		 * pixel clocks than what SETUP was called with.
+		 */
+		.pixel_clock = timing ? timing->pix_clk_100hz / 10 : 300000,
+		.color_depth = timing ? timing->display_color_depth : COLOR_DEPTH_888,
+	};
+	DC_LOGGER_INIT();
+
+	bp_result = bios->funcs->external_encoder_control(bios, &ext_cntl);
+
+	if (bp_result != BP_RESULT_OK)
+		DC_LOG_ERROR("Failed to execute external encoder action: 0x%x\n", action);
+}
+
+static void
+dce110_prepare_ddc(struct dc_link *link)
+{
+	if (link->ext_enc_id.id)
+		dce110_external_encoder_control(EXTERNAL_ENCODER_CONTROL_DDC_SETUP, link, NULL);
+}
+
 static void
 dce110_dac_encoder_control(struct pipe_ctx *pipe_ctx, bool enable)
 {
@@ -717,6 +759,9 @@ void dce110_enable_stream(struct pipe_ctx *pipe_ctx)
 
 	if (dc_is_rgb_signal(pipe_ctx->stream->signal))
 		dce110_dac_encoder_control(pipe_ctx, true);
+
+	if (link->ext_enc_id.id)
+		dce110_external_encoder_control(EXTERNAL_ENCODER_CONTROL_ENABLE, link, timing);
 }
 
 static enum bp_result link_transmitter_control(
@@ -1213,6 +1258,9 @@ void dce110_disable_stream(struct pipe_ctx *pipe_ctx)
 
 	if (dc_is_rgb_signal(pipe_ctx->stream->signal))
 		dce110_dac_encoder_control(pipe_ctx, false);
+
+	if (link->ext_enc_id.id)
+		dce110_external_encoder_control(EXTERNAL_ENCODER_CONTROL_DISABLE, link, NULL);
 }
 
 void dce110_unblank_stream(struct pipe_ctx *pipe_ctx,
@@ -3362,6 +3410,11 @@ void dce110_enable_dp_link_output(
 		}
 	}
 
+	if (link->ext_enc_id.id) {
+		dce110_external_encoder_control(EXTERNAL_ENCODER_CONTROL_INIT, link, NULL);
+		dce110_external_encoder_control(EXTERNAL_ENCODER_CONTROL_SETUP, link, NULL);
+	}
+
 	if (dc->link_srv->dp_get_encoding_format(link_settings) == DP_8b_10b_ENCODING) {
 		if (dc->clk_mgr->funcs->notify_link_rate_change)
 			dc->clk_mgr->funcs->notify_link_rate_change(dc->clk_mgr, link);
@@ -3454,6 +3507,7 @@ static const struct hw_sequencer_funcs dce110_funcs = {
 	.enable_dp_link_output = dce110_enable_dp_link_output,
 	.disable_link_output = dce110_disable_link_output,
 	.dac_load_detect = dce110_dac_load_detect,
+	.prepare_ddc = dce110_prepare_ddc,
 };
 
 static const struct hwseq_private_funcs dce110_private_funcs = {
-- 
2.52.0


  parent reply	other threads:[~2026-01-26 21:08 UTC|newest]

Thread overview: 22+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-01-26 21:08 [PATCH 00/14] drm/amd/display: Add support for external DP bridge encoders in DC Timur Kristóf
2026-01-26 21:08 ` [PATCH 01/14] drm/amd/display: Use DCE 6 link encoder for DCE 6 analog connectors Timur Kristóf
2026-01-26 21:08 ` [PATCH 02/14] drm/amd/display: Only use analog link encoder with analog engine Timur Kristóf
2026-01-26 21:08 ` [PATCH 03/14] drm/amd/display: Only use analog stream " Timur Kristóf
2026-01-26 21:08 ` [PATCH 04/14] drm/amd/display: Add color depth helper function to BIOS parser Timur Kristóf
2026-01-26 21:08 ` [PATCH 05/14] drm/amd/display: Refactor DAC load detection, move to HWSS Timur Kristóf
2026-01-30 20:00   ` Alex Hung
2026-01-26 21:08 ` [PATCH 06/14] drm/amd/display: Implement BIOS parser external encoder control Timur Kristóf
2026-01-26 21:08 ` [PATCH 07/14] drm/amd/display: Implement DDC probe over AUX channel Timur Kristóf
2026-01-30 19:53   ` Alex Hung
2026-01-26 21:08 ` [PATCH 08/14] drm/amd/display: Add ability for HWSS to prepare the DDC before use Timur Kristóf
2026-01-26 21:08 ` [PATCH 09/14] drm/amd/display: Use preferred DP link rate if specified Timur Kristóf
2026-01-26 21:08 ` Timur Kristóf [this message]
2026-01-26 21:08 ` [PATCH 11/14] drm/amd/display: Link detection for external DP bridge encoders Timur Kristóf
2026-01-26 21:08 ` [PATCH 12/14] drm/amd/display: Use " Timur Kristóf
2026-01-26 21:08 ` [PATCH 13/14] drm/amd/display: Implement DAC load detection on " Timur Kristóf
2026-01-26 21:08 ` [PATCH 14/14] drm/amdgpu: Use DC by default on CIK APUs Timur Kristóf
2026-02-09 15:35 ` [PATCH 00/14] drm/amd/display: Add support for external DP bridge encoders in DC Rodrigo Siqueira
2026-02-09 18:12   ` Alex Hung
2026-02-09 22:10     ` Timur Kristóf
2026-02-09 23:14       ` Alex Hung
2026-02-16  4:33         ` Alex Hung

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=20260126210837.21885-11-timur.kristof@gmail.com \
    --to=timur.kristof@gmail.com \
    --cc=Alexander.Deucher@amd.com \
    --cc=Christian.Koenig@amd.com \
    --cc=Prike.Liang@amd.com \
    --cc=Ray.Wu@amd.com \
    --cc=alex.hung@amd.com \
    --cc=amd-gfx@lists.freedesktop.org \
    --cc=ivan.lipski@amd.com \
    --cc=mario.limonciello@amd.com \
    --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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.