summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorArthur Hanson Rasmusson <arthur@vgpu.io>2026-10-24 22:04:33 -0400
committerArthur Hanson Rasmusson <arthur@vgpu.io>2026-10-24 22:04:33 -0400
commitade29f0c5df211ca9d32589196c8e59a2fd2ae76 (patch)
treeaa0a640973b237cb280a74a35a7392b69e6f3c11
parentc03b02ecad88465804a369ebdd19b7ff92d5e32c (diff)
downloadopen-iov-ade29f0c5df211ca9d32589196c8e59a2fd2ae76.tar.gz
open-iov-ade29f0c5df211ca9d32589196c8e59a2fd2ae76.zip
vgsp-rm r643/r644: NV0073 display-common shim for nvidia-modeset - report one head (GET_NUM_HEADS 0x730102, GET_ALL_HEAD_MASK 0x730287, flexible window assignment 0x7302ad) and one static TMDS/HDMI connector on display id 0 (GET_SUPPORTED 0x730107, OR_GET_INFO 0x73028b SOR+SOR_SINGLE_TMDS_A, GET_CONNECTOR_DATA 0x730250 HDMI_A, DFP_GET_INFO 0x731140); the generic all-zero replies made nvkms log 'No heads found on board!' and fail (killing Xorg ScreenInit and Vulkan vkCreateDevice), then fail NoValidDisplays() after the heads were added
-rw-r--r--kernel/gsp_rm_emulation.c109
1 files changed, 109 insertions, 0 deletions
diff --git a/kernel/gsp_rm_emulation.c b/kernel/gsp_rm_emulation.c
index 7011f77..ec6ca20 100644
--- a/kernel/gsp_rm_emulation.c
+++ b/kernel/gsp_rm_emulation.c
@@ -1959,6 +1959,103 @@ static void gsp_rm_handle_display_get_ip_version(struct gsp_emu_context *ctx,
}
/*
+ * NV0073 display-common heads + one static HDMI connector
+ * (0x730102 / 0x730287 / 0x7302ad / 0x730107 / 0x73028b / 0x730250 /
+ * 0x731140)
+ *
+ * nvidia-modeset's nvkms-rm.c ProbeHeadCountAndWindowAssignment asks the
+ * display-common object for the head count (NV0073_CTRL_CMD_SYSTEM_
+ * GET_NUM_HEADS = 0x730102) and a zero reply makes it log "No heads found on
+ * board!" and fail -- which kills Xorg's ScreenInit and every Vulkan
+ * vkCreateDevice (measured: the emulated device replies all-zero through the
+ * generic path, so nvkms never opens). The kernel driver already sees 1 head
+ * (DISPLAY_GET_STATIC_INFO reports numHeads=1); report the same 1 head here,
+ * a single-head mask for GET_ALL_HEAD_MASK (0x730287), and a fully-flexible
+ * window assignment for windows 0/1 (0xFF = FLEXIBLE; windows above the head
+ * count stay 0 = not present).
+ *
+ * The next wall after the heads (measured r643): nvRmAllocDisplays fails on
+ * NoValidDisplays() - nvkms requires at least one valid display. Report one
+ * static TMDS/HDMI connector on display id 0: GET_SUPPORTED (0x730107)
+ * displayMask=1|DDC=1, SPECIFIC_OR_GET_INFO (0x73028b) SOR /
+ * SOR_SINGLE_TMDS_A (TMDS avoids the whole DP-AUX lib), SPECIFIC_
+ * GET_CONNECTOR_DATA (0x730250) one HDMI_A entry, DFP_GET_INFO (0x731140)
+ * TMDS flags. Still a headless setup: no connect state or EDID is claimed
+ * (those are modeset-time queries).
+ */
+static void gsp_rm_handle_display_heads(struct gsp_emu_context *ctx, u32 cmd,
+ u32 req_size,
+ u32 *out_status, u8 *out_params,
+ u32 *out_params_size)
+{
+ u32 one = 1;
+ u32 sz = req_size ? req_size : 72;
+ u32 v;
+
+ memset(out_params, 0, sz);
+ switch (cmd) {
+ case 0x730102: /* SYSTEM_GET_NUM_HEADS: {subDev, flags, numHeads} */
+ if (sz >= 12)
+ memcpy(out_params + 8, &one, 4);
+ break;
+ case 0x730287: /* SPECIFIC_GET_ALL_HEAD_MASK: {subDev, headMask} */
+ if (sz >= 8)
+ memcpy(out_params + 4, &one, 4);
+ break;
+ case 0x7302ad: /* SPECIFIC_GET_VALID_HEAD_WINDOW_ASSIGNMENT:
+ * {subDev, windowHeadMask[32]} - windows 0 and 1
+ * flexible (0xFF), the rest absent (0). */
+ if (sz >= 36) {
+ out_params[4] = 0xff;
+ out_params[5] = 0xff;
+ }
+ break;
+ case 0x730107: /* SYSTEM_GET_SUPPORTED: {subDev, displayMask,
+ * displayMaskDDC} - display id 0 supported + DDC. */
+ if (sz >= 12) {
+ memcpy(out_params + 4, &one, 4);
+ memcpy(out_params + 8, &one, 4);
+ }
+ break;
+ case 0x73028b: /* SPECIFIC_OR_GET_INFO: {subDev, displayId, index,
+ * type, protocol, ditherType, ditherAlgo, location,
+ * rootPortId, dcbIndex, vbiosAddress, bIsLitByVbios,
+ * bIsDispDynamic} */
+ if (sz >= 52) {
+ v = 2; /* NV0073_CTRL_SPECIFIC_OR_TYPE_SOR */
+ memcpy(out_params + 12, &v, 4);
+ v = 1; /* SOR_SINGLE_TMDS_A (no DP aux) */
+ memcpy(out_params + 16, &v, 4);
+ /* location=0 (chip), remaining out-fields stay 0:
+ * not lit by vbios, not dynamic. */
+ }
+ break;
+ case 0x730250: /* SPECIFIC_GET_CONNECTOR_DATA: {subDev,
+ * displayId, flags, DDCPartners, count,
+ * data[4]{index,type,location}, platform} */
+ if (sz >= 72) {
+ v = 1; /* CONNECTOR_DATA_FLAGS_PRESENT_YES */
+ memcpy(out_params + 8, &v, 4);
+ v = 1; /* count */
+ memcpy(out_params + 16, &v, 4);
+ /* data[0].index = 0 */
+ v = 0x61; /* CONNECTOR_DATA_TYPE_HDMI_A */
+ memcpy(out_params + 24, &v, 4);
+ /* data[0].location = 0 */
+ }
+ break;
+ case 0x731140: /* DFP_GET_INFO: {subDev, displayId, flags,
+ * UHBRSupportedByDfp} - flags signal bits = TMDS(0) */
+ break; /* zeros are the TMDS signal value */
+ }
+ *out_params_size = sz;
+ *out_status = 0;
+ nv_vgpu_info(ctx->vgpu,
+ "vgsp-rm: DISPLAY shim cmd=0x%x -> 1 head / 1 HDMI connector (size %u)",
+ cmd, sz);
+}
+
+/*
* CE_GET_FAULT_METHOD_BUFFER_SIZE (0x20802a08)
*
* kchangrpInit allocates one fault method buffer per runqueue of this
@@ -3680,6 +3777,18 @@ static void gsp_rm_handle_rm_control(struct gsp_emu_context *ctx,
reply + GSP_RM_CTRL_HDR_SIZE, &out_params_size);
break;
+ case 0x730102: /* NV0073_CTRL_CMD_SYSTEM_GET_NUM_HEADS */
+ case 0x730287: /* NV0073_CTRL_CMD_SPECIFIC_GET_ALL_HEAD_MASK */
+ case 0x7302ad: /* NV0073_CTRL_CMD_SPECIFIC_GET_VALID_HEAD_WINDOW_ASSIGNMENT */
+ case 0x730107: /* NV0073_CTRL_CMD_SYSTEM_GET_SUPPORTED */
+ case 0x73028b: /* NV0073_CTRL_CMD_SPECIFIC_OR_GET_INFO */
+ case 0x730250: /* NV0073_CTRL_CMD_SPECIFIC_GET_CONNECTOR_DATA */
+ case 0x731140: /* NV0073_CTRL_CMD_DFP_GET_INFO */
+ gsp_rm_handle_display_heads(ctx, req.cmd, req.paramsSize,
+ &out_status,
+ reply + GSP_RM_CTRL_HDR_SIZE, &out_params_size);
+ break;
+
case TU104_CTRL_CE_GET_FAULT_METHOD_BUFFER_SIZE:
gsp_rm_handle_ce_get_fault_method_buffer_size(ctx, sequence,
&out_status,