GB20x (NVDisplay 5.0) reorganised the SF HDMI packet units and the
legacy VSI unit at 0x6f0100 no longer exists. Per NVIDIA's published
CA71 DISP_SF_USER class header, only three legacy units remain (AVI
at +0x000, GCP at +0x040, ACR at +0x080), and vendor infoframes must
instead be sent through the shared generic infoframe units at
+0x130, which feed a 9-dword data FIFO at +0x3f0/+0x3f4.

Add a VSI writer using the same programming sequence OpenRM uses on
these chips (nvhdmipkt_C971.c, programAdvancedInfoframeC971()): disable
the unit and wait for it to idle, clear the SENT status, write the packet
through the data FIFO with a zero HB3 inserted after the three header
bytes, then enable the unit for every-frame transmission during vblank.

Generic unit 1 is used for the VSI, matching the slot assignment in
NVIDIA's nvkms (NVHDMIPKT_TYPE_SHARED_GENERIC2, unit 0 is reserved
for extended metadata packets and unit 2 for the HDR DRM infoframe,
if those are wired up later).

Signed-off-by: Mohamed Ahmed <[email protected]>
---
 .../gpu/drm/nouveau/nvkm/engine/disp/Kbuild   |  1 +
 .../gpu/drm/nouveau/nvkm/engine/disp/gb202.c  | 62 +++++++++++++++++++
 .../gpu/drm/nouveau/nvkm/engine/disp/ior.h    |  2 +
 3 files changed, 65 insertions(+)
 create mode 100644 drivers/gpu/drm/nouveau/nvkm/engine/disp/gb202.c

diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/Kbuild 
b/drivers/gpu/drm/nouveau/nvkm/engine/disp/Kbuild
index e1aecd3fe96c..98d6ca5ac311 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/Kbuild
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/Kbuild
@@ -27,6 +27,7 @@ nvkm-y += nvkm/engine/disp/gp102.o
 nvkm-y += nvkm/engine/disp/gv100.o
 nvkm-y += nvkm/engine/disp/tu102.o
 nvkm-y += nvkm/engine/disp/ga102.o
+nvkm-y += nvkm/engine/disp/gb202.o
 
 nvkm-y += nvkm/engine/disp/udisp.o
 nvkm-y += nvkm/engine/disp/uconn.o
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gb202.c 
b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gb202.c
new file mode 100644
index 000000000000..8fd72bcb6f04
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gb202.c
@@ -0,0 +1,62 @@
+// SPDX-License-Identifier: MIT
+/*
+ * Copyright 2026 Valve Corp.
+ */
+#include "priv.h"
+#include "ior.h"
+
+#include <subdev/timer.h>
+
+/* GB20x (NVD5.0) reorganised the SF HDMI packet units. The AVI unit is
+ * unchanged from GV100, but the legacy VSI unit is gone. Vendor infoframes
+ * are sent through the shared generic infoframe units instead. Register
+ * layout per NVIDIA's clc971.h/clca71.h, programming sequence per
+ * nvhdmipkt_C971.c:programAdvancedInfoframeC971().
+ */
+void
+gb202_sor_hdmi_infoframe_vsi(struct nvkm_ior *ior, int head, void *data, u32 
size)
+{
+       struct nvkm_device *device = ior->disp->engine.subdev.device;
+       const u32 hoff = head * 0x400;
+       /* Generic infoframe unit 1, the slot NVIDIA's driver uses for the VSI. 
*/
+       const u32 ctrl = 0x6f0138 + hoff;
+       u8 buf[36] = {};
+       int i;
+
+       /* Disable the unit and wait for it to go idle. */
+       nvkm_mask(device, ctrl, 0x00000001, 0x00000000);
+       if (nvkm_msec(device, 2000,
+               if (!(nvkm_rd32(device, ctrl) & 0x00400000))
+                       break;
+       ) < 0)
+               return;
+
+       if (!size)
+               return;
+
+       /* Clear SENT status, and point the data FIFO at unit 1's slot. */
+       nvkm_mask(device, ctrl, 0x00800000, 0x00800000);
+       nvkm_wr32(device, 0x6f03f0 + hoff, 0x00000001);
+
+       /* The FIFO takes the raw packet, except that a zero HB3 is inserted
+        * after the three header bytes. A unit sends 36 bytes.
+        */
+       size = min_t(u32, size, 31);
+       memcpy(buf, data, min_t(u32, size, 3));
+       if (size > 3)
+               memcpy(&buf[4], (u8 *)data + 3, size - 3);
+
+       for (i = 0; i < 36; i += 4) {
+               nvkm_wr32(device, 0x6f03f4 + hoff, buf[i + 0] | buf[i + 1] << 8 
|
+                                                  buf[i + 2] << 16 | buf[i + 
3] << 24);
+       }
+
+       /* No flip ID or scanline matching. */
+       nvkm_wr32(device, 0x6f013c + hoff, 0x00000000);
+
+       /* ENABLE | RUN_MODE=ALWAYS | LOC=VBLANK | OFFSET=1 | SIZE=0. */
+       nvkm_wr32(device, ctrl, 0x00000041);
+
+       /* Audio priority low (the init value). */
+       nvkm_wr32(device, 0x6f03f8 + hoff, 0x00000002);
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/ior.h 
b/drivers/gpu/drm/nouveau/nvkm/engine/disp/ior.h
index 3ba04bead2f9..8906fe8ef404 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/ior.h
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/ior.h
@@ -196,6 +196,8 @@ extern const struct nvkm_ior_func_hda gv100_sor_hda;
 
 void tu102_sor_dp_vcpi(struct nvkm_ior *, int, u8, u8, u16, u16);
 
+void gb202_sor_hdmi_infoframe_vsi(struct nvkm_ior *, int, void *, u32);
+
 int nv50_pior_cnt(struct nvkm_disp *, unsigned long *);
 int nv50_pior_new(struct nvkm_disp *, int);
 void nv50_pior_depth(struct nvkm_ior *, struct nvkm_ior_state *, u32 ctrl);
-- 
2.55.0

Reply via email to