dri-devel Archive on lore.kernel.org
 help / color / mirror / Atom feed
From: Daniel Campos Ramos <Capitain_Jack@yahoo.com>
To: dri-devel@lists.freedesktop.org
Cc: nouveau@lists.freedesktop.org, lyude@redhat.com, dakr@kernel.org,
	Daniel Campos Ramos <Capitain_Jack@yahoo.com>
Subject: [PATCH 2/3] drm/nouveau: pass HDMI GCP deep-color state through NVIF
Date: Tue, 22 Sep 2026 16:21:31 -0300	[thread overview]
Message-ID: <20260922192132.114546-3-Capitain_Jack@yahoo.com> (raw)
In-Reply-To: <20260922192132.114546-1-Capitain_Jack@yahoo.com>

The HDMI GCP carries color depth and pixel packing phase.  These fields
are required for 30-, 36- and 48-bpp RGB links.  Nouveau has no way to
pass them from the atomic state to the display engine.

Build CD and PP using NVIDIA NVKMS's 36-bpp rule and the HDMI 48-bpp
encoding.
Extend the internal HDMI NVIF method and cache the values in the armed TMDS
state.  The following change uses that state in the generation-specific GCP
writers.

Signed-off-by: Daniel Campos Ramos <Capitain_Jack@yahoo.com>
---
 drivers/gpu/drm/nouveau/dispnv50/disp.c       | 23 +++++++++++++++----
 drivers/gpu/drm/nouveau/include/nvif/if0012.h |  3 +++
 drivers/gpu/drm/nouveau/include/nvif/outp.h   |  2 +-
 drivers/gpu/drm/nouveau/nvif/outp.c           |  7 ++++--
 .../gpu/drm/nouveau/nvkm/engine/disp/ior.h    |  2 ++
 .../gpu/drm/nouveau/nvkm/engine/disp/uoutp.c  |  6 +++++
 6 files changed, 36 insertions(+), 7 deletions(-)

diff --git a/drivers/gpu/drm/nouveau/dispnv50/disp.c b/drivers/gpu/drm/nouveau/dispnv50/disp.c
index 6410b96b..6d8fee1b 100644
--- a/drivers/gpu/drm/nouveau/dispnv50/disp.c
+++ b/drivers/gpu/drm/nouveau/dispnv50/disp.c
@@ -809,13 +809,14 @@ nv50_audio_enable(struct drm_encoder *encoder, struct nouveau_crtc *nv_crtc,
 static void
 nv50_hdmi_enable(struct drm_encoder *encoder, struct nouveau_crtc *nv_crtc,
 		 struct nouveau_connector *nv_connector, struct drm_atomic_commit *state,
-		 struct drm_display_mode *mode, bool hda)
+		 struct drm_display_mode *mode, bool hda, u8 bpc)
 {
 	struct nouveau_drm *drm = nouveau_drm(encoder->dev);
 	struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
 	struct drm_hdmi_info *hdmi = &nv_connector->base.display_info.hdmi;
 	union hdmi_infoframe infoframe = { 0 };
 	const u8 rekey = 56; /* binary driver, and tegra, constant */
+	u8 gcp_cd = 0, gcp_pp = 0;
 	u32 max_ac_packet;
 	DEFINE_RAW_FLEX(struct nvif_outp_infoframe_v0, args, data, 17);
 	const u8 data_len = __member_size(args->data);
@@ -826,6 +827,19 @@ nv50_hdmi_enable(struct drm_encoder *encoder, struct nouveau_crtc *nv_crtc,
 	max_ac_packet -= 18; /* constant from tegra */
 	max_ac_packet /= 32;
 
+	/* Match NVIDIA's 36-bpp GCP construction and extend the same HDMI
+	 * color-depth encoding to 48-bpp.  48-bpp groups contain one pixel,
+	 * so their last packing phase is phase 4 (zero).
+	 */
+	if (bpc == 16) {
+		gcp_cd = 7;
+	} else if (bpc == 12) {
+		const u32 hbp = mode->crtc_hblank_end - mode->crtc_hsync_end;
+
+		gcp_cd = 6;
+		gcp_pp = ((mode->crtc_hdisplay + hbp) & 1) ? 1 : 2;
+	}
+
 	if (nv_encoder->i2c && hdmi->scdc.scrambling.supported) {
 		const bool high_tmds_clock_ratio = mode->clock > 340000;
 		u8 scdc;
@@ -850,7 +864,7 @@ nv50_hdmi_enable(struct drm_encoder *encoder, struct nouveau_crtc *nv_crtc,
 
 	ret = nvif_outp_hdmi(&nv_encoder->outp, nv_crtc->index, true, max_ac_packet, rekey,
 			     mode->clock, hdmi->scdc.supported, hdmi->scdc.scrambling.supported,
-			     hdmi->scdc.scrambling.low_rates);
+			     hdmi->scdc.scrambling.low_rates, gcp_cd, gcp_pp);
 	if (ret)
 		return;
 
@@ -1615,7 +1629,7 @@ nv50_sor_atomic_disable(struct drm_encoder *encoder, struct drm_atomic_commit *s
 
 	if (nv_encoder->dcb->type == DCB_OUTPUT_TMDS && nv_encoder->hdmi.enabled) {
 		nvif_outp_hdmi(&nv_encoder->outp, head->base.index,
-			       false, 0, 0, 0, false, false, false);
+			       false, 0, 0, 0, false, false, false, 0, 0);
 		nv_encoder->hdmi.enabled = false;
 	}
 
@@ -1831,7 +1845,8 @@ nv50_sor_atomic_enable(struct drm_encoder *encoder, struct drm_atomic_commit *st
 
 		if (disp->disp->object.oclass != NV50_DISP &&
 		    nv_connector->base.display_info.is_hdmi)
-			nv50_hdmi_enable(encoder, nv_crtc, nv_connector, state, mode, hda);
+			nv50_hdmi_enable(encoder, nv_crtc, nv_connector, state, mode, hda,
+					 asyh->or.bpc);
 
 		if (nv_encoder->outp.or.link & 1) {
 			proto = NV507D_SOR_SET_CONTROL_PROTOCOL_SINGLE_TMDS_A;
diff --git a/drivers/gpu/drm/nouveau/include/nvif/if0012.h b/drivers/gpu/drm/nouveau/include/nvif/if0012.h
index bde9bfae..ebfa60f9 100644
--- a/drivers/gpu/drm/nouveau/include/nvif/if0012.h
+++ b/drivers/gpu/drm/nouveau/include/nvif/if0012.h
@@ -176,6 +176,9 @@ union nvif_outp_hdmi_args {
 		__u8 scdc_scrambling;
 		__u8 scdc_low_rates;
 		__u32 khz;
+		__u8 gcp_cd;
+		__u8 gcp_pp;
+		__u8 pad14[2];
 	} v0;
 };
 
diff --git a/drivers/gpu/drm/nouveau/include/nvif/outp.h b/drivers/gpu/drm/nouveau/include/nvif/outp.h
index bc122a5b..3d5ed53f 100644
--- a/drivers/gpu/drm/nouveau/include/nvif/outp.h
+++ b/drivers/gpu/drm/nouveau/include/nvif/outp.h
@@ -90,7 +90,7 @@ int nvif_outp_bl_set(struct nvif_outp *, int level);
 int nvif_outp_lvds(struct nvif_outp *, bool dual, bool bpc8);
 
 int nvif_outp_hdmi(struct nvif_outp *, int head, bool enable, u8 max_ac_packet, u8 rekey, u32 khz,
-		   bool scdc, bool scdc_scrambling, bool scdc_low_rates);
+		   bool scdc, bool scdc_scrambling, bool scdc_low_rates, u8 gcp_cd, u8 gcp_pp);
 
 int nvif_outp_infoframe(struct nvif_outp *, u8 type, struct nvif_outp_infoframe_v0 *, u32 size);
 int nvif_outp_hda_eld(struct nvif_outp *, int head, void *data, u32 size);
diff --git a/drivers/gpu/drm/nouveau/nvif/outp.c b/drivers/gpu/drm/nouveau/nvif/outp.c
index 8cf4775a..44562645 100644
--- a/drivers/gpu/drm/nouveau/nvif/outp.c
+++ b/drivers/gpu/drm/nouveau/nvif/outp.c
@@ -224,9 +224,10 @@ nvif_outp_infoframe(struct nvif_outp *outp, u8 type, struct nvif_outp_infoframe_
 
 int
 nvif_outp_hdmi(struct nvif_outp *outp, int head, bool enable, u8 max_ac_packet, u8 rekey,
-	       u32 khz, bool scdc, bool scdc_scrambling, bool scdc_low_rates)
+	       u32 khz, bool scdc, bool scdc_scrambling, bool scdc_low_rates,
+	       u8 gcp_cd, u8 gcp_pp)
 {
-	struct nvif_outp_hdmi_v0 args;
+	struct nvif_outp_hdmi_v0 args = {};
 	int ret;
 
 	args.version = 0;
@@ -238,6 +239,8 @@ nvif_outp_hdmi(struct nvif_outp *outp, int head, bool enable, u8 max_ac_packet,
 	args.scdc = scdc;
 	args.scdc_scrambling = scdc_scrambling;
 	args.scdc_low_rates = scdc_low_rates;
+	args.gcp_cd = gcp_cd;
+	args.gcp_pp = gcp_pp;
 
 	ret = nvif_mthd(&outp->object, NVIF_OUTP_V0_HDMI, &args, sizeof(args));
 	NVIF_ERRON(ret, &outp->object,
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/ior.h b/drivers/gpu/drm/nouveau/nvkm/engine/disp/ior.h
index 5d682a77..fcf624cf 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/ior.h
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/ior.h
@@ -46,6 +46,8 @@ struct nvkm_ior {
 	/* Armed TMDS state. */
 	struct {
 		bool high_speed;
+		u8 gcp_cd;
+		u8 gcp_pp;
 	} tmds;
 };
 
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/uoutp.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/uoutp.c
index 377d0e0c..dff75d72 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/uoutp.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/uoutp.c
@@ -254,16 +254,22 @@ nvkm_uoutp_mthd_hdmi(struct nvkm_outp *outp, void *argv, u32 argc)
 	if (!ior->func->hdmi ||
 	    args->v0.max_ac_packet > 0x1f ||
 	    args->v0.rekey > 0x7f ||
+	    args->v0.gcp_cd > 0x0f ||
+	    args->v0.gcp_pp > 0x0f ||
 	    (args->v0.scdc && !ior->func->hdmi->scdc))
 		return -EINVAL;
 
 	if (!args->v0.enable) {
+		ior->tmds.gcp_cd = 0;
+		ior->tmds.gcp_pp = 0;
 		ior->func->hdmi->infoframe_avi(ior, args->v0.head, NULL, 0);
 		ior->func->hdmi->infoframe_vsi(ior, args->v0.head, NULL, 0);
 		ior->func->hdmi->ctrl(ior, args->v0.head, false, 0, 0);
 		return 0;
 	}
 
+	ior->tmds.gcp_cd = args->v0.gcp_cd;
+	ior->tmds.gcp_pp = args->v0.gcp_pp;
 	ior->func->hdmi->ctrl(ior, args->v0.head, args->v0.enable,
 			      args->v0.max_ac_packet, args->v0.rekey);
 	if (ior->func->hdmi->scdc)
-- 
2.53.0


  parent reply	other threads:[~2026-09-22 19:21 UTC|newest]

Thread overview: 10+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
     [not found] <20260922192132.114546-1-Capitain_Jack.ref@yahoo.com>
2026-09-22 19:21 ` [PATCH 0/3] drm/nouveau: HDMI Deep Color link depth (30/36/48 bpp) Daniel Campos Ramos
2026-09-22 19:21   ` [PATCH 1/3] drm/nouveau: select HDMI deep-color link depth Daniel Campos Ramos
2026-09-22 19:39     ` sashiko-bot
2026-09-22 22:26       ` Daniel Campos Ramos
2026-09-22 19:21   ` Daniel Campos Ramos [this message]
2026-09-22 19:29     ` [PATCH 2/3] drm/nouveau: pass HDMI GCP deep-color state through NVIF sashiko-bot
2026-09-22 19:21   ` [PATCH 3/3] drm/nouveau: program HDMI deep-color GCP fields Daniel Campos Ramos
2026-09-22 22:07   ` [PATCH 0/3] drm/nouveau: HDMI Deep Color link depth (30/36/48 bpp) Daniel Campos Ramos
2026-09-23 15:48   ` lyude
2026-09-23 16:33     ` Daniel Campos Ramos

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=20260922192132.114546-3-Capitain_Jack@yahoo.com \
    --to=capitain_jack@yahoo.com \
    --cc=dakr@kernel.org \
    --cc=dri-devel@lists.freedesktop.org \
    --cc=lyude@redhat.com \
    --cc=nouveau@lists.freedesktop.org \
    /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