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 2:55 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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox