The GSP path reads armed head state and the RG scanout position through
gv100_head_state() and gv100_head_rgpos() on every generation.
gv100_head_state() reads the core channel's state mirror at a 0x400
per-head stride, which NVD5.0 (GB20x) doubled. Per NVIDIA's published
CA7D class header every HEAD_SET method sits at 0x2000 + head * 0x800,
while the mirror bases are unchanged (assembly at 0x680000, armed at
+0x8000, per OpenRM's v03_00 channel-user-base HAL which is still used on
DISPv0502).

Add gb202_head_state(), the same readback at the 0x800 stride, and
supply it through gb202_gsp_disp.
gv100_head_rgpos() is kept. The RG registers keep their per-head 0x800
stride on NVD5.0, and OpenRM's kdispReadRgLineCountAndFrameCount_v03_00
still reads NV_PDISP_RG_DPCA on DISPv0502.

Signed-off-by: Mohamed Ahmed <[email protected]>
---
 .../gpu/drm/nouveau/nvkm/engine/disp/gb202.c  | 49 ++++++++++++++++++-
 1 file changed, 48 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gb202.c 
b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gb202.c
index 4863b2b36db0..a66c820be9fe 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gb202.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gb202.c
@@ -83,6 +83,53 @@ gb202_sor_hdmi_gcp(struct nvkm_ior *sor, int head, bool 
enable)
        nvkm_mask(device, 0x6f0040 + hdmi, 0x00000001, 0x00000001);
 }
 
+/* Same core-channel state mirror as gv100_head_state() (assembly at 0x680000,
+ * armed at +0x8000, per-head method offsets unchanged), but NVD5.0 spaces
+ * heads 0x800 apart (see NVCA7D_HEAD_SET_*(a) in clca7d.h).
+ */
+static void
+gb202_head_state(struct nvkm_head *head, struct nvkm_head_state *state)
+{
+       struct nvkm_device *device = head->disp->engine.subdev.device;
+       const u32 hoff = (state == &head->arm) * 0x8000 + head->id * 0x800;
+       u32 data;
+
+       data = nvkm_rd32(device, 0x682064 + hoff);
+       state->vtotal = (data & 0xffff0000) >> 16;
+       state->htotal = (data & 0x0000ffff);
+       data = nvkm_rd32(device, 0x682068 + hoff);
+       state->vsynce = (data & 0xffff0000) >> 16;
+       state->hsynce = (data & 0x0000ffff);
+       data = nvkm_rd32(device, 0x68206c + hoff);
+       state->vblanke = (data & 0xffff0000) >> 16;
+       state->hblanke = (data & 0x0000ffff);
+       data = nvkm_rd32(device, 0x682070 + hoff);
+       state->vblanks = (data & 0xffff0000) >> 16;
+       state->hblanks = (data & 0x0000ffff);
+       /* Bit 31 is ADJ1000DIV1001, not a HERTZ bit. We don't have enough bits
+        * to add the full clock in hz on Blackwell (35 bits), but state->hz
+        * is unused and obsolete under GSP so this is fine.
+        */
+       state->hz = nvkm_rd32(device, 0x68200c + hoff) & 0x7fffffff;
+
+       data = nvkm_rd32(device, 0x682004 + hoff);
+       switch ((data & 0x000000f0) >> 4) {
+       case 5:
+               state->or.depth = 30;
+               break;
+       case 4:
+               state->or.depth = 24;
+               break;
+       case 1:
+               state->or.depth = 18;
+               break;
+       default:
+               state->or.depth = 18;
+               WARN_ON(1);
+               break;
+       }
+}
+
 /* GB20x is GSP-only. This table supplies the register programming the
  * GSP-RM display path needs from the chip.
  */
@@ -91,7 +138,7 @@ gb202_gsp_disp = {
        .uevent = &gv100_disp_chan_uevent,
        .ramht_size = 0x2000,
        .gsp.intr = tu102_disp_intr,
-       .gsp.head_state = gv100_head_state,
+       .gsp.head_state = gb202_head_state,
        .gsp.head_rgpos = gv100_head_rgpos,
        .gsp.vblank_get = tu102_head_vblank_get,
        .gsp.vblank_put = tu102_head_vblank_put,
-- 
2.55.0

Reply via email to