From: Dave Airlie <airlied@gmail.com>
To: dri-devel@lists.freedesktop.org
Cc: nouveau@lists.freedesktop.org
Subject: [PATCH 2/4] nouveau: add FRL and DSC parameters to HDMI sink caps interface
Date: Thu, 23 Apr 2026 10:42:14 +1000 [thread overview]
Message-ID: <20260423004552.3289884-3-airlied@gmail.com> (raw)
In-Reply-To: <20260423004552.3289884-1-airlied@gmail.com>
From: Dave Airlie <airlied@redhat.com>
Extend the outp-level hdmi_sink_caps method with max_frl_rate and
dsc_1p2 parameters so GSP firmware can be informed about the sink's
HDMI 2.1 FRL and DSC capabilities at detect time.
Add nouveau_hdmi_get_frl_rate() helper to convert drm_hdmi_info
lane count and per-lane rate into the FRL rate index (1-6) expected
by the RM SET_HDMI_SINK_CAPS command.
This was claude code assisted.
Signed-off-by: Dave Airlie <airlied@redhat.com>
---
drivers/gpu/drm/nouveau/include/nvif/if0012.h | 4 +++-
drivers/gpu/drm/nouveau/include/nvif/outp.h | 2 +-
drivers/gpu/drm/nouveau/nouveau_connector.c | 24 ++++++++++++++++++-
drivers/gpu/drm/nouveau/nvif/outp.c | 9 ++++---
.../gpu/drm/nouveau/nvkm/engine/disp/outp.h | 2 +-
.../gpu/drm/nouveau/nvkm/engine/disp/uoutp.c | 3 ++-
.../nouveau/nvkm/subdev/gsp/rm/r535/disp.c | 22 ++++++++++++++++-
7 files changed, 57 insertions(+), 9 deletions(-)
diff --git a/drivers/gpu/drm/nouveau/include/nvif/if0012.h b/drivers/gpu/drm/nouveau/include/nvif/if0012.h
index 89cfac7ef3a54..dc0a5c372f511 100644
--- a/drivers/gpu/drm/nouveau/include/nvif/if0012.h
+++ b/drivers/gpu/drm/nouveau/include/nvif/if0012.h
@@ -172,7 +172,9 @@ union nvif_outp_hdmi_sink_caps_args {
__u8 scdc;
__u8 scdc_scrambling;
__u8 scdc_low_rates;
- __u8 pad04[4];
+ __u8 max_frl_rate;
+ __u8 dsc_1p2;
+ __u8 pad06[2];
} v0;
};
diff --git a/drivers/gpu/drm/nouveau/include/nvif/outp.h b/drivers/gpu/drm/nouveau/include/nvif/outp.h
index 240e1f80ed539..55c02a34f381e 100644
--- a/drivers/gpu/drm/nouveau/include/nvif/outp.h
+++ b/drivers/gpu/drm/nouveau/include/nvif/outp.h
@@ -67,7 +67,7 @@ enum nvif_outp_detect_status {
enum nvif_outp_detect_status nvif_outp_detect(struct nvif_outp *);
int nvif_outp_edid_get(struct nvif_outp *, u8 **pedid);
int nvif_outp_hdmi_sink_caps(struct nvif_outp *, bool scdc, bool scdc_scrambling,
- bool scdc_low_rates);
+ bool scdc_low_rates, int max_frl_rate, int dsc_1p2);
int nvif_outp_load_detect(struct nvif_outp *, u32 loadval);
int nvif_outp_acquire_dac(struct nvif_outp *);
diff --git a/drivers/gpu/drm/nouveau/nouveau_connector.c b/drivers/gpu/drm/nouveau/nouveau_connector.c
index eae37d938f3bc..870b467d35e17 100644
--- a/drivers/gpu/drm/nouveau/nouveau_connector.c
+++ b/drivers/gpu/drm/nouveau/nouveau_connector.c
@@ -560,6 +560,23 @@ nouveau_connector_set_edid(struct nouveau_connector *nv_connector,
}
}
+static int
+nouveau_hdmi_get_frl_rate(u8 max_frl_rate_per_lane, u8 max_lanes)
+{
+ switch (max_lanes) {
+ case 3:
+ switch (max_frl_rate_per_lane) {
+ case 3: return 1;
+ case 6: return 2;
+ }
+ return 0;
+ case 4:
+ return max_frl_rate_per_lane / 2;
+ default:
+ return 0;
+ }
+}
+
static enum drm_connector_status
nouveau_connector_detect(struct drm_connector *connector, bool force)
{
@@ -645,7 +662,12 @@ nouveau_connector_detect(struct drm_connector *connector, bool force)
nvif_outp_hdmi_sink_caps(&nv_encoder->outp,
hdmi->scdc.supported,
hdmi->scdc.scrambling.supported,
- hdmi->scdc.scrambling.low_rates);
+ hdmi->scdc.scrambling.low_rates,
+ nouveau_hdmi_get_frl_rate(hdmi->max_frl_rate_per_lane,
+ hdmi->max_lanes),
+ hdmi->dsc_cap.v_1p2 ?
+ nouveau_hdmi_get_frl_rate(hdmi->dsc_cap.max_frl_rate_per_lane,
+ hdmi->dsc_cap.max_lanes) : 0);
}
if (nv_encoder->dcb->type == DCB_OUTPUT_DP)
diff --git a/drivers/gpu/drm/nouveau/nvif/outp.c b/drivers/gpu/drm/nouveau/nvif/outp.c
index d66f437587ff3..60479c884b2dc 100644
--- a/drivers/gpu/drm/nouveau/nvif/outp.c
+++ b/drivers/gpu/drm/nouveau/nvif/outp.c
@@ -463,7 +463,7 @@ nvif_outp_edid_get(struct nvif_outp *outp, u8 **pedid)
int
nvif_outp_hdmi_sink_caps(struct nvif_outp *outp, bool scdc, bool scdc_scrambling,
- bool scdc_low_rates)
+ bool scdc_low_rates, int max_frl_rate, int dsc_1p2)
{
struct nvif_outp_hdmi_sink_caps_v0 args;
int ret;
@@ -472,11 +472,14 @@ nvif_outp_hdmi_sink_caps(struct nvif_outp *outp, bool scdc, bool scdc_scrambling
args.scdc = scdc;
args.scdc_scrambling = scdc_scrambling;
args.scdc_low_rates = scdc_low_rates;
+ args.max_frl_rate = max_frl_rate;
+ args.dsc_1p2 = dsc_1p2;
ret = nvif_mthd(&outp->object, NVIF_OUTP_V0_HDMI_SINK_CAPS, &args, sizeof(args));
NVIF_ERRON(ret, &outp->object,
- "[HDMI_SINK_CAPS scdc:%d scrambling:%d low_rates:%d]",
- args.scdc, args.scdc_scrambling, args.scdc_low_rates);
+ "[HDMI_SINK_CAPS scdc:%d scrambling:%d low_rates:%d max_frl_rate:%d dsc_1p2:%d]",
+ args.scdc, args.scdc_scrambling, args.scdc_low_rates,
+ args.max_frl_rate, args.dsc_1p2);
return ret;
}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.h b/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.h
index fd54c17ba4d6d..17698b9ea7186 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.h
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.h
@@ -96,7 +96,7 @@ struct nvkm_outp_func {
int (*detect)(struct nvkm_outp *);
int (*edid_get)(struct nvkm_outp *, u8 *data, u16 *size);
void (*hdmi_sink_caps)(struct nvkm_outp *, bool scdc, bool scrambling,
- bool low_rates);
+ bool low_rates, int max_frl_rate, int dsc_1p2);
struct nvkm_ior *(*inherit)(struct nvkm_outp *);
int (*acquire)(struct nvkm_outp *, bool hda);
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/uoutp.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/uoutp.c
index 84381ba71ebaf..202fdc73f7cab 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/uoutp.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/uoutp.c
@@ -483,7 +483,8 @@ nvkm_uoutp_mthd_hdmi_sink_caps(struct nvkm_outp *outp, void *argv, u32 argc)
return -EINVAL;
outp->func->hdmi_sink_caps(outp, args->v0.scdc, args->v0.scdc_scrambling,
- args->v0.scdc_low_rates);
+ args->v0.scdc_low_rates, args->v0.max_frl_rate,
+ args->v0.dsc_1p2);
return 0;
}
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/rm/r535/disp.c b/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/rm/r535/disp.c
index fa20a0c633653..2fb7cc83852f9 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/rm/r535/disp.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/rm/r535/disp.c
@@ -1218,7 +1218,7 @@ r535_tmds_edid_get(struct nvkm_outp *outp, u8 *data, u16 *psize)
static void
r535_outp_hdmi_sink_caps(struct nvkm_outp *outp, bool scdc, bool scrambling,
- bool low_rates)
+ bool low_rates, int max_frl_rate, int dsc_1p2)
{
struct nvkm_disp *disp = outp->disp;
NV0073_CTRL_SPECIFIC_SET_HDMI_SINK_CAPS_PARAMS *ctrl;
@@ -1236,7 +1236,27 @@ r535_outp_hdmi_sink_caps(struct nvkm_outp *outp, bool scdc, bool scrambling,
ctrl->caps |= NVDEF(NV0073_CTRL_CMD_SPECIFIC, SET_HDMI_SINK_CAPS, GT_340MHZ_CLOCK_SUPPORTED, TRUE);
if (low_rates)
ctrl->caps |= NVDEF(NV0073_CTRL_CMD_SPECIFIC, SET_HDMI_SINK_CAPS, LTE_340MHZ_SCRAMBLING_SUPPORTED, TRUE);
+ switch (max_frl_rate) {
+ case 1: ctrl->caps |= NVDEF(NV0073_CTRL_CMD_SPECIFIC, SET_HDMI_SINK_CAPS, MAX_FRL_RATE_SUPPORTED, 3LANES_3G); break;
+ case 2: ctrl->caps |= NVDEF(NV0073_CTRL_CMD_SPECIFIC, SET_HDMI_SINK_CAPS, MAX_FRL_RATE_SUPPORTED, 3LANES_6G); break;
+ case 3: ctrl->caps |= NVDEF(NV0073_CTRL_CMD_SPECIFIC, SET_HDMI_SINK_CAPS, MAX_FRL_RATE_SUPPORTED, 4LANES_6G); break;
+ case 4: ctrl->caps |= NVDEF(NV0073_CTRL_CMD_SPECIFIC, SET_HDMI_SINK_CAPS, MAX_FRL_RATE_SUPPORTED, 4LANES_8G); break;
+ case 5: ctrl->caps |= NVDEF(NV0073_CTRL_CMD_SPECIFIC, SET_HDMI_SINK_CAPS, MAX_FRL_RATE_SUPPORTED, 4LANES_10G); break;
+ case 6: ctrl->caps |= NVDEF(NV0073_CTRL_CMD_SPECIFIC, SET_HDMI_SINK_CAPS, MAX_FRL_RATE_SUPPORTED, 4LANES_12G); break;
+ default: break;
+ }
+ if (dsc_1p2) {
+ ctrl->caps |= NVDEF(NV0073_CTRL_CMD_SPECIFIC, SET_HDMI_SINK_CAPS, DSC_12_SUPPORTED, TRUE);
+ switch (dsc_1p2) {
+ case 1: ctrl->caps |= NVDEF(NV0073_CTRL_CMD_SPECIFIC, SET_HDMI_SINK_CAPS, DSC_MAX_FRL_RATE_SUPPORTED, 3LANES_3G); break;
+ case 2: ctrl->caps |= NVDEF(NV0073_CTRL_CMD_SPECIFIC, SET_HDMI_SINK_CAPS, DSC_MAX_FRL_RATE_SUPPORTED, 3LANES_6G); break;
+ case 3: ctrl->caps |= NVDEF(NV0073_CTRL_CMD_SPECIFIC, SET_HDMI_SINK_CAPS, DSC_MAX_FRL_RATE_SUPPORTED, 4LANES_6G); break;
+ case 4: ctrl->caps |= NVDEF(NV0073_CTRL_CMD_SPECIFIC, SET_HDMI_SINK_CAPS, DSC_MAX_FRL_RATE_SUPPORTED, 4LANES_8G); break;
+ case 5: ctrl->caps |= NVDEF(NV0073_CTRL_CMD_SPECIFIC, SET_HDMI_SINK_CAPS, DSC_MAX_FRL_RATE_SUPPORTED, 4LANES_10G); break;
+ case 6: ctrl->caps |= NVDEF(NV0073_CTRL_CMD_SPECIFIC, SET_HDMI_SINK_CAPS, DSC_MAX_FRL_RATE_SUPPORTED, 4LANES_12G); break;
+ }
+ }
WARN_ON(nvkm_gsp_rm_ctrl_wr(&disp->rm.objcom, ctrl));
}
--
2.53.0
next prev parent reply other threads:[~2026-04-23 0:52 UTC|newest]
Thread overview: 5+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-04-23 0:42 nouveau: add HDMI FRL support for GSP enabled GPUs Dave Airlie
2026-04-23 0:42 ` [PATCH 1/4] nouveau: move HDMI sink caps to outp level for GSP-RM Dave Airlie
2026-04-23 0:42 ` Dave Airlie [this message]
2026-04-23 0:42 ` [PATCH 3/4] nouveau: add HDMI FRL training API and retrain event handling Dave Airlie
2026-04-23 0:42 ` [PATCH 4/4] nouveau: wire up HDMI FRL in the display frontend Dave Airlie
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=20260423004552.3289884-3-airlied@gmail.com \
--to=airlied@gmail.com \
--cc=dri-devel@lists.freedesktop.org \
--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 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.