summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/gpu/drm/nouveau/include/nvkm/engine/disp.h1
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/device/base.c10
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/disp/Kbuild1
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/disp/gb202.c88
4 files changed, 95 insertions, 5 deletions
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/engine/disp.h b/drivers/gpu/drm/nouveau/include/nvkm/engine/disp.h
index 7903d7470d19..01145db32c53 100644
--- a/drivers/gpu/drm/nouveau/include/nvkm/engine/disp.h
+++ b/drivers/gpu/drm/nouveau/include/nvkm/engine/disp.h
@@ -87,4 +87,5 @@ int gp102_disp_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct
int gv100_disp_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct nvkm_disp **);
int tu102_disp_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct nvkm_disp **);
int ga102_disp_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct nvkm_disp **);
+int gb202_disp_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct nvkm_disp **);
#endif
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c
index ea62dc97f118..96c8a5b29999 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c
@@ -2846,7 +2846,7 @@ nv1b2_chipset = {
.pci = { 0x00000001, gh100_pci_new },
.timer = { 0x00000001, gk20a_timer_new },
.vfn = { 0x00000001, ga100_vfn_new },
- .disp = { 0x00000001, ga102_disp_new },
+ .disp = { 0x00000001, gb202_disp_new },
.fifo = { 0x00000001, ga102_fifo_new },
};
@@ -2862,7 +2862,7 @@ nv1b3_chipset = {
.pci = { 0x00000001, gh100_pci_new },
.timer = { 0x00000001, gk20a_timer_new },
.vfn = { 0x00000001, ga100_vfn_new },
- .disp = { 0x00000001, ga102_disp_new },
+ .disp = { 0x00000001, gb202_disp_new },
.fifo = { 0x00000001, ga102_fifo_new },
};
@@ -2878,7 +2878,7 @@ nv1b5_chipset = {
.pci = { 0x00000001, gh100_pci_new },
.timer = { 0x00000001, gk20a_timer_new },
.vfn = { 0x00000001, ga100_vfn_new },
- .disp = { 0x00000001, ga102_disp_new },
+ .disp = { 0x00000001, gb202_disp_new },
.fifo = { 0x00000001, ga102_fifo_new },
};
@@ -2894,7 +2894,7 @@ nv1b6_chipset = {
.pci = { 0x00000001, gh100_pci_new },
.timer = { 0x00000001, gk20a_timer_new },
.vfn = { 0x00000001, ga100_vfn_new },
- .disp = { 0x00000001, ga102_disp_new },
+ .disp = { 0x00000001, gb202_disp_new },
.fifo = { 0x00000001, ga102_fifo_new },
};
@@ -2910,7 +2910,7 @@ nv1b7_chipset = {
.pci = { 0x00000001, gh100_pci_new },
.timer = { 0x00000001, gk20a_timer_new },
.vfn = { 0x00000001, ga100_vfn_new },
- .disp = { 0x00000001, ga102_disp_new },
+ .disp = { 0x00000001, gb202_disp_new },
.fifo = { 0x00000001, ga102_fifo_new },
};
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..1e40de83e2bb
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gb202.c
@@ -0,0 +1,88 @@
+// SPDX-License-Identifier: MIT
+/*
+ * Copyright 2026 Valve Corp.
+ */
+#include "priv.h"
+#include "head.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().
+ */
+static 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 port at unit 1's slot. */
+ nvkm_mask(device, ctrl, 0x00800000, 0x00800000);
+ nvkm_wr32(device, 0x6f03f0 + hoff, 0x00000001);
+
+ /* The data port takes the raw packet, except that a zero is inserted
+ * in HB3 after the three header bytes. A slot is 9 dwords (HB0-3 plus
+ * up to 32 payload bytes). An HDMI infoframe carries at most PB0-27,
+ * so the tail stays zero, and we always write the whole slot.
+ */
+ 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 |
+ (u32)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);
+}
+
+/* GB20x is GSP-only. This table supplies the register programming the
+ * GSP-RM display path needs from the chip.
+ */
+static const struct nvkm_disp_func
+gb202_gsp_disp = {
+ .uevent = &gv100_disp_chan_uevent,
+ .ramht_size = 0x2000,
+ .gsp.intr = tu102_disp_intr,
+ .gsp.head = &tu102_gsp_head,
+ .gsp.hdmi_gcp = tu102_sor_hdmi_gcp,
+ /* The legacy AVI unit is unchanged on GB20x. */
+ .gsp.hdmi_infoframe_avi = gv100_sor_hdmi_infoframe_avi,
+ .gsp.hdmi_infoframe_vsi = gb202_sor_hdmi_infoframe_vsi,
+};
+
+int
+gb202_disp_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst,
+ struct nvkm_disp **pdisp)
+{
+ return r535_disp_new(&gb202_gsp_disp, device, type, inst, pdisp);
+}