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
next prev 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