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 1/3] drm/nouveau: select HDMI deep-color link depth
Date: Tue, 22 Sep 2026 16:21:30 -0300	[thread overview]
Message-ID: <20260922192132.114546-2-Capitain_Jack@yahoo.com> (raw)
In-Reply-To: <20260922192132.114546-1-Capitain_Jack@yahoo.com>

Nouveau currently initializes the output depth from the EDID basic display
parameters and does not expose a max bpc property on HDMI connectors.  As a
result, HDMI deep-color modes advertised by the VSDB are never selected.

Attach an 8..16 max bpc property.  Select 10, 12 or 16 bpc only when
the sink advertises the corresponding RGB 4:4:4 deep-color mode and the
resulting TMDS character rate fits the existing link limit.  Program the
matching head output-resource depth on NVDisplay.

Share the existing TMDS bandwidth helper with the atomic check so the depth
selection observes both sink and GPU limits.

Signed-off-by: Daniel Campos Ramos <Capitain_Jack@yahoo.com>
---
 drivers/gpu/drm/nouveau/dispnv50/disp.c     | 57 ++++++++++++++++++++-
 drivers/gpu/drm/nouveau/dispnv50/headc37d.c |  6 +++
 drivers/gpu/drm/nouveau/dispnv50/headc57d.c |  6 +++
 drivers/gpu/drm/nouveau/dispnv50/headca7d.c |  6 +++
 drivers/gpu/drm/nouveau/nouveau_connector.c |  9 ++--
 drivers/gpu/drm/nouveau/nouveau_connector.h |  1 +
 6 files changed, 80 insertions(+), 5 deletions(-)

diff --git a/drivers/gpu/drm/nouveau/dispnv50/disp.c b/drivers/gpu/drm/nouveau/dispnv50/disp.c
index add19d47..6410b96b 100644
--- a/drivers/gpu/drm/nouveau/dispnv50/disp.c
+++ b/drivers/gpu/drm/nouveau/dispnv50/disp.c
@@ -375,10 +375,12 @@ nv50_outp_atomic_check_view(struct drm_encoder *encoder,
 }
 
 static void
-nv50_outp_atomic_fix_depth(struct drm_encoder *encoder, struct drm_crtc_state *crtc_state)
+nv50_outp_atomic_fix_depth(struct drm_encoder *encoder, struct drm_crtc_state *crtc_state,
+			   struct drm_connector_state *conn_state)
 {
 	struct nv50_head_atom *asyh = nv50_head_atom(crtc_state);
 	struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
+	struct drm_connector *connector = conn_state->connector;
 	struct drm_display_mode *mode = &asyh->state.adjusted_mode;
 	unsigned int max_rate, mode_rate;
 
@@ -398,6 +400,36 @@ nv50_outp_atomic_fix_depth(struct drm_encoder *encoder, struct drm_crtc_state *c
 			asyh->or.bpc -= 2;
 		}
 		break;
+	case DCB_OUTPUT_TMDS:
+		if (!connector->display_info.is_hdmi)
+			break;
+
+		max_rate = nouveau_connector_get_tmds_link_bandwidth(connector);
+		asyh->or.bpc = 8;
+
+		if (conn_state->max_requested_bpc >= 16 &&
+		    connector->display_info.edid_hdmi_rgb444_dc_modes & DRM_EDID_HDMI_DC_48) {
+			mode_rate = DIV_ROUND_UP(mode->clock * 16, 8);
+			if (mode_rate <= max_rate)
+				asyh->or.bpc = 16;
+		}
+
+		if (asyh->or.bpc == 8 && conn_state->max_requested_bpc >= 12 &&
+		    connector->display_info.edid_hdmi_rgb444_dc_modes & DRM_EDID_HDMI_DC_36) {
+			mode_rate = DIV_ROUND_UP(mode->clock * 12, 8);
+			if (mode_rate <= max_rate)
+				asyh->or.bpc = 12;
+		}
+
+		if (asyh->or.bpc == 8 && conn_state->max_requested_bpc >= 10 &&
+		    connector->display_info.edid_hdmi_rgb444_dc_modes & DRM_EDID_HDMI_DC_30) {
+			mode_rate = DIV_ROUND_UP(mode->clock * 10, 8);
+			if (mode_rate <= max_rate)
+				asyh->or.bpc = 10;
+		}
+
+		conn_state->max_bpc = asyh->or.bpc;
+		break;
 	default:
 		break;
 	}
@@ -422,7 +454,7 @@ nv50_outp_atomic_check(struct drm_encoder *encoder,
 		asyh->or.bpc = connector->display_info.bpc;
 
 	/* We might have to reduce the bpc */
-	nv50_outp_atomic_fix_depth(encoder, crtc_state);
+	nv50_outp_atomic_fix_depth(encoder, crtc_state, conn_state);
 
 	return 0;
 }
@@ -1776,6 +1808,27 @@ nv50_sor_atomic_enable(struct drm_encoder *encoder, struct drm_atomic_commit *st
 
 	switch (nv_encoder->dcb->type) {
 	case DCB_OUTPUT_TMDS:
+		switch (asyh->or.bpc) {
+		case 16:
+			depth = NV837D_SOR_SET_CONTROL_PIXEL_DEPTH_BPP_48_444;
+			break;
+		case 12:
+			depth = NV837D_SOR_SET_CONTROL_PIXEL_DEPTH_BPP_36_444;
+			break;
+		case 10:
+			depth = NV837D_SOR_SET_CONTROL_PIXEL_DEPTH_BPP_30_444;
+			break;
+		case 8:
+			depth = NV837D_SOR_SET_CONTROL_PIXEL_DEPTH_BPP_24_444;
+			break;
+		case 6:
+			depth = NV837D_SOR_SET_CONTROL_PIXEL_DEPTH_BPP_18_444;
+			break;
+		default:
+			depth = NV837D_SOR_SET_CONTROL_PIXEL_DEPTH_DEFAULT;
+			break;
+		}
+
 		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);
diff --git a/drivers/gpu/drm/nouveau/dispnv50/headc37d.c b/drivers/gpu/drm/nouveau/dispnv50/headc37d.c
index 2bcb3790..f42d6642 100644
--- a/drivers/gpu/drm/nouveau/dispnv50/headc37d.c
+++ b/drivers/gpu/drm/nouveau/dispnv50/headc37d.c
@@ -39,6 +39,12 @@ headc37d_or(struct nv50_head *head, struct nv50_head_atom *asyh)
 	 *     improved later for deep colour etc.
 	 */
 	switch (asyh->or.depth) {
+	case 9:
+		depth = 8;
+		break;
+	case 8:
+		depth = 7;
+		break;
 	case 6: depth = 5; break;
 	case 5: depth = 4; break;
 	case 2: depth = 1; break;
diff --git a/drivers/gpu/drm/nouveau/dispnv50/headc57d.c b/drivers/gpu/drm/nouveau/dispnv50/headc57d.c
index 3f8ba495..f1e9f02d 100644
--- a/drivers/gpu/drm/nouveau/dispnv50/headc57d.c
+++ b/drivers/gpu/drm/nouveau/dispnv50/headc57d.c
@@ -52,6 +52,12 @@ headc57d_or(struct nv50_head *head, struct nv50_head_atom *asyh)
 	 *     improved later for deep colour etc.
 	 */
 	switch (asyh->or.depth) {
+	case 9:
+		depth = 8;
+		break;
+	case 8:
+		depth = 7;
+		break;
 	case 6: depth = 5; break;
 	case 5: depth = 4; break;
 	case 2: depth = 1; break;
diff --git a/drivers/gpu/drm/nouveau/dispnv50/headca7d.c b/drivers/gpu/drm/nouveau/dispnv50/headca7d.c
index 678cbc78..437633ff 100644
--- a/drivers/gpu/drm/nouveau/dispnv50/headca7d.c
+++ b/drivers/gpu/drm/nouveau/dispnv50/headca7d.c
@@ -35,6 +35,12 @@ headca7d_or(struct nv50_head *head, struct nv50_head_atom *asyh)
 	int ret;
 
 	switch (asyh->or.depth) {
+	case 9:
+		depth = NVCA7D_HEAD_SET_CONTROL_OUTPUT_RESOURCE_PIXEL_DEPTH_BPP_48_444;
+		break;
+	case 8:
+		depth = NVCA7D_HEAD_SET_CONTROL_OUTPUT_RESOURCE_PIXEL_DEPTH_BPP_36_444;
+		break;
 	case 6:
 		depth = NVCA7D_HEAD_SET_CONTROL_OUTPUT_RESOURCE_PIXEL_DEPTH_BPP_30_444;
 		break;
diff --git a/drivers/gpu/drm/nouveau/nouveau_connector.c b/drivers/gpu/drm/nouveau/nouveau_connector.c
index cc3caf8d..b452e73f 100644
--- a/drivers/gpu/drm/nouveau/nouveau_connector.c
+++ b/drivers/gpu/drm/nouveau/nouveau_connector.c
@@ -298,6 +298,9 @@ nouveau_conn_attach_properties(struct drm_connector *connector)
 		drm_object_attach_property(&connector->base, dev->mode_config.
 					   dvi_i_subconnector_property, 0);
 
+	if (connector->connector_type == DRM_MODE_CONNECTOR_HDMIA)
+		drm_connector_attach_max_bpc_property(connector, 8, 16);
+
 	/* Add overscan compensation options to digital outputs. */
 	if (disp->underscan_property &&
 	    (connector->connector_type == DRM_MODE_CONNECTOR_DVID ||
@@ -1101,8 +1104,8 @@ nouveau_connector_get_modes(struct drm_connector *connector)
 	return ret;
 }
 
-static unsigned
-get_tmds_link_bandwidth(struct drm_connector *connector)
+unsigned int
+nouveau_connector_get_tmds_link_bandwidth(struct drm_connector *connector)
 {
 	struct nouveau_connector *nv_connector = nouveau_connector(connector);
 	struct nouveau_encoder *nv_encoder = nv_connector->detected_encoder;
@@ -1168,7 +1171,7 @@ nouveau_connector_mode_valid(struct drm_connector *connector,
 		max_clock = 400000;
 		break;
 	case DCB_OUTPUT_TMDS:
-		max_clock = get_tmds_link_bandwidth(connector);
+		max_clock = nouveau_connector_get_tmds_link_bandwidth(connector);
 		break;
 	case DCB_OUTPUT_ANALOG:
 		max_clock = nv_encoder->dcb->crtconf.maxfreq;
diff --git a/drivers/gpu/drm/nouveau/nouveau_connector.h b/drivers/gpu/drm/nouveau/nouveau_connector.h
index eb292d2b..6623b5e1 100644
--- a/drivers/gpu/drm/nouveau/nouveau_connector.h
+++ b/drivers/gpu/drm/nouveau/nouveau_connector.h
@@ -216,6 +216,7 @@ extern int nouveau_duallink;
 extern int nouveau_hdmimhz;
 
 void nouveau_conn_attach_properties(struct drm_connector *);
+unsigned int nouveau_connector_get_tmds_link_bandwidth(struct drm_connector *connector);
 void nouveau_conn_reset(struct drm_connector *);
 struct drm_connector_state *
 nouveau_conn_atomic_duplicate_state(struct drm_connector *);
-- 
2.53.0


  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   ` Daniel Campos Ramos [this message]
2026-09-22 19:39     ` [PATCH 1/3] drm/nouveau: select HDMI deep-color link depth sashiko-bot
2026-09-22 22:26       ` Daniel Campos Ramos
2026-09-22 19:21   ` [PATCH 2/3] drm/nouveau: pass HDMI GCP deep-color state through NVIF Daniel Campos Ramos
2026-09-22 19:29     ` 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-2-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