drm/nouveau/disp: fix head state readback on GB20x

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 a
gb202_gsp_head table to supply it.
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.

Fixes: 6cc6e08d45 ("drm/nouveau/kms: add support for GB20x")
Cc: stable@vger.kernel.org
Signed-off-by: Mohamed Ahmed <mohamedahmedegypt2001@gmail.com>
Reviewed-by: Lyude Paul <lyude@redhat.com>
Signed-off-by: Lyude Paul <lyude@redhat.com>
Link: https://patch.msgid.link/20260825001408.14219-8-mohamedahmedegypt2001@gmail.com
This commit is contained in:
Mohamed Ahmed 2026-08-25 04:14:05 +04:00 committed by Lyude Paul
parent 39fd4b7427
commit 9421dfe912

View File

@ -83,6 +83,55 @@ 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;
}
}
static const struct nvkm_head_func
gb202_gsp_head = {
.state = gb202_head_state,
.rgpos = gv100_head_rgpos,
.vblank_get = tu102_head_vblank_get,
.vblank_put = tu102_head_vblank_put,
};
/* GB20x is GSP-only. This table supplies the register programming the
* GSP-RM display path needs from the chip.
*/
@ -91,7 +140,7 @@ gb202_gsp_disp = {
.uevent = &gv100_disp_chan_uevent,
.ramht_size = 0x2000,
.gsp.intr = tu102_disp_intr,
.gsp.head = &tu102_gsp_head,
.gsp.head = &gb202_gsp_head,
.gsp.hdmi_gcp = gb202_sor_hdmi_gcp,
/* The legacy AVI unit is unchanged on GB20x. */
.gsp.hdmi_infoframe_avi = gv100_sor_hdmi_infoframe_avi,