2 * PROJECT: ReactOS Xbox miniport video driver
3 * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
4 * PURPOSE: Simple framebuffer driver for NVIDIA NV2A XGPU
5 * COPYRIGHT: Copyright 2004 Gé van Geldorp
6 * Copyright 2004 Filip Navara
7 * Copyright 2019 Stanislav Motylkov (x86corez@gmail.com)
10 * - Check input parameters everywhere.
11 * - Call VideoPortVerifyAccessRanges to reserve the memory we're about
15 /* INCLUDES *******************************************************************/
22 /* PUBLIC AND PRIVATE FUNCTIONS ***********************************************/
30 VIDEO_HW_INITIALIZATION_DATA InitData
;
32 VideoPortZeroMemory(&InitData
, sizeof(InitData
));
33 InitData
.AdapterInterfaceType
= PCIBus
;
34 InitData
.HwInitDataSize
= sizeof(VIDEO_HW_INITIALIZATION_DATA
);
35 InitData
.HwFindAdapter
= XboxVmpFindAdapter
;
36 InitData
.HwInitialize
= XboxVmpInitialize
;
37 InitData
.HwStartIO
= XboxVmpStartIO
;
38 InitData
.HwResetHw
= XboxVmpResetHw
;
39 InitData
.HwGetPowerState
= XboxVmpGetPowerState
;
40 InitData
.HwSetPowerState
= XboxVmpSetPowerState
;
41 InitData
.HwDeviceExtensionSize
= sizeof(XBOXVMP_DEVICE_EXTENSION
);
43 return VideoPortInitialize(Context1
, Context2
, &InitData
, NULL
);
49 * Detects the Xbox Nvidia display adapter.
55 IN PVOID HwDeviceExtension
,
57 IN PWSTR ArgumentString
,
58 IN OUT PVIDEO_PORT_CONFIG_INFO ConfigInfo
,
61 PXBOXVMP_DEVICE_EXTENSION XboxVmpDeviceExtension
;
62 VIDEO_ACCESS_RANGE AccessRanges
[3];
64 USHORT VendorId
= 0x10DE; /* NVIDIA Corporation */
65 USHORT DeviceId
= 0x02A0; /* NV2A XGPU */
67 TRACE_(IHVVIDEO
, "XboxVmpFindAdapter\n");
69 XboxVmpDeviceExtension
= (PXBOXVMP_DEVICE_EXTENSION
)HwDeviceExtension
;
71 Status
= VideoPortGetAccessRanges(HwDeviceExtension
, 0, NULL
, 3, AccessRanges
,
72 &VendorId
, &DeviceId
, NULL
);
74 if (Status
== NO_ERROR
)
76 XboxVmpDeviceExtension
->PhysControlStart
= AccessRanges
[0].RangeStart
;
77 XboxVmpDeviceExtension
->ControlLength
= AccessRanges
[0].RangeLength
;
78 XboxVmpDeviceExtension
->PhysFrameBufferStart
= AccessRanges
[1].RangeStart
;
87 * Performs the first initialization of the adapter, after the HAL has given
88 * up control of the video hardware to the video port driver.
94 PVOID HwDeviceExtension
)
96 PXBOXVMP_DEVICE_EXTENSION XboxVmpDeviceExtension
;
97 ULONG inIoSpace
= VIDEO_MEMORY_SPACE_MEMORY
;
100 TRACE_(IHVVIDEO
, "XboxVmpInitialize\n");
102 XboxVmpDeviceExtension
= (PXBOXVMP_DEVICE_EXTENSION
)HwDeviceExtension
;
104 Length
= XboxVmpDeviceExtension
->ControlLength
;
105 XboxVmpDeviceExtension
->VirtControlStart
= NULL
;
107 if (VideoPortMapMemory(HwDeviceExtension
,
108 XboxVmpDeviceExtension
->PhysControlStart
,
111 &XboxVmpDeviceExtension
->VirtControlStart
) != NO_ERROR
)
113 ERR_(IHVVIDEO
, "Failed to map control memory\n");
117 INFO_(IHVVIDEO
, "Mapped 0x%x bytes of control mem at 0x%x to virt addr 0x%x\n",
118 XboxVmpDeviceExtension
->ControlLength
,
119 XboxVmpDeviceExtension
->PhysControlStart
.u
.LowPart
,
120 XboxVmpDeviceExtension
->VirtControlStart
);
128 * Processes the specified Video Request Packet.
134 PVOID HwDeviceExtension
,
135 PVIDEO_REQUEST_PACKET RequestPacket
)
139 RequestPacket
->StatusBlock
->Status
= ERROR_INVALID_PARAMETER
;
141 switch (RequestPacket
->IoControlCode
)
143 case IOCTL_VIDEO_SET_CURRENT_MODE
:
145 TRACE_(IHVVIDEO
, "XboxVmpStartIO IOCTL_VIDEO_SET_CURRENT_MODE\n");
147 if (RequestPacket
->InputBufferLength
< sizeof(VIDEO_MODE
))
149 RequestPacket
->StatusBlock
->Status
= ERROR_INSUFFICIENT_BUFFER
;
153 Result
= XboxVmpSetCurrentMode(
154 (PXBOXVMP_DEVICE_EXTENSION
)HwDeviceExtension
,
155 (PVIDEO_MODE
)RequestPacket
->InputBuffer
,
156 RequestPacket
->StatusBlock
);
160 case IOCTL_VIDEO_RESET_DEVICE
:
162 TRACE_(IHVVIDEO
, "XboxVmpStartIO IOCTL_VIDEO_RESET_DEVICE\n");
164 Result
= XboxVmpResetDevice(
165 (PXBOXVMP_DEVICE_EXTENSION
)HwDeviceExtension
,
166 RequestPacket
->StatusBlock
);
170 case IOCTL_VIDEO_MAP_VIDEO_MEMORY
:
172 TRACE_(IHVVIDEO
, "XboxVmpStartIO IOCTL_VIDEO_MAP_VIDEO_MEMORY\n");
174 if (RequestPacket
->OutputBufferLength
< sizeof(VIDEO_MEMORY_INFORMATION
) ||
175 RequestPacket
->InputBufferLength
< sizeof(VIDEO_MEMORY
))
177 RequestPacket
->StatusBlock
->Status
= ERROR_INSUFFICIENT_BUFFER
;
181 Result
= XboxVmpMapVideoMemory(
182 (PXBOXVMP_DEVICE_EXTENSION
)HwDeviceExtension
,
183 (PVIDEO_MEMORY
)RequestPacket
->InputBuffer
,
184 (PVIDEO_MEMORY_INFORMATION
)RequestPacket
->OutputBuffer
,
185 RequestPacket
->StatusBlock
);
189 case IOCTL_VIDEO_UNMAP_VIDEO_MEMORY
:
191 TRACE_(IHVVIDEO
, "XboxVmpStartIO IOCTL_VIDEO_UNMAP_VIDEO_MEMORY\n");
193 if (RequestPacket
->InputBufferLength
< sizeof(VIDEO_MEMORY
))
195 RequestPacket
->StatusBlock
->Status
= ERROR_INSUFFICIENT_BUFFER
;
199 Result
= XboxVmpUnmapVideoMemory(
200 (PXBOXVMP_DEVICE_EXTENSION
)HwDeviceExtension
,
201 (PVIDEO_MEMORY
)RequestPacket
->InputBuffer
,
202 RequestPacket
->StatusBlock
);
206 case IOCTL_VIDEO_QUERY_NUM_AVAIL_MODES
:
208 TRACE_(IHVVIDEO
, "XboxVmpStartIO IOCTL_VIDEO_QUERY_NUM_AVAIL_MODES\n");
210 if (RequestPacket
->OutputBufferLength
< sizeof(VIDEO_NUM_MODES
))
212 RequestPacket
->StatusBlock
->Status
= ERROR_INSUFFICIENT_BUFFER
;
216 Result
= XboxVmpQueryNumAvailModes(
217 (PXBOXVMP_DEVICE_EXTENSION
)HwDeviceExtension
,
218 (PVIDEO_NUM_MODES
)RequestPacket
->OutputBuffer
,
219 RequestPacket
->StatusBlock
);
223 case IOCTL_VIDEO_QUERY_AVAIL_MODES
:
225 TRACE_(IHVVIDEO
, "XboxVmpStartIO IOCTL_VIDEO_QUERY_AVAIL_MODES\n");
227 if (RequestPacket
->OutputBufferLength
< sizeof(VIDEO_MODE_INFORMATION
))
229 RequestPacket
->StatusBlock
->Status
= ERROR_INSUFFICIENT_BUFFER
;
233 Result
= XboxVmpQueryAvailModes(
234 (PXBOXVMP_DEVICE_EXTENSION
)HwDeviceExtension
,
235 (PVIDEO_MODE_INFORMATION
)RequestPacket
->OutputBuffer
,
236 RequestPacket
->StatusBlock
);
240 case IOCTL_VIDEO_QUERY_CURRENT_MODE
:
242 TRACE_(IHVVIDEO
, "XboxVmpStartIO IOCTL_VIDEO_QUERY_CURRENT_MODE\n");
244 if (RequestPacket
->OutputBufferLength
< sizeof(VIDEO_MODE_INFORMATION
))
246 RequestPacket
->StatusBlock
->Status
= ERROR_INSUFFICIENT_BUFFER
;
250 Result
= XboxVmpQueryCurrentMode(
251 (PXBOXVMP_DEVICE_EXTENSION
)HwDeviceExtension
,
252 (PVIDEO_MODE_INFORMATION
)RequestPacket
->OutputBuffer
,
253 RequestPacket
->StatusBlock
);
259 WARN_(IHVVIDEO
, "XboxVmpStartIO 0x%x not implemented\n", RequestPacket
->IoControlCode
);
261 RequestPacket
->StatusBlock
->Status
= ERROR_INVALID_FUNCTION
;
268 RequestPacket
->StatusBlock
->Status
= NO_ERROR
;
277 * This function is called to reset the hardware to a known state.
283 PVOID DeviceExtension
,
287 TRACE_(IHVVIDEO
, "XboxVmpResetHw\n");
289 if (!XboxVmpResetDevice((PXBOXVMP_DEVICE_EXTENSION
)DeviceExtension
, NULL
))
298 * XboxVmpGetPowerState
300 * Queries whether the device can support the requested power state.
305 XboxVmpGetPowerState(
306 PVOID HwDeviceExtension
,
308 PVIDEO_POWER_MANAGEMENT VideoPowerControl
)
310 ERR_(IHVVIDEO
, "XboxVmpGetPowerState is not supported\n");
312 return ERROR_INVALID_FUNCTION
;
316 * XboxVmpSetPowerState
318 * Sets the power state of the specified device
323 XboxVmpSetPowerState(
324 PVOID HwDeviceExtension
,
326 PVIDEO_POWER_MANAGEMENT VideoPowerControl
)
328 ERR_(IHVVIDEO
, "XboxVmpSetPowerState not supported\n");
330 return ERROR_INVALID_FUNCTION
;
336 * Sets the adapter to the specified operating mode.
341 XboxVmpSetCurrentMode(
342 PXBOXVMP_DEVICE_EXTENSION DeviceExtension
,
343 PVIDEO_MODE RequestedMode
,
344 PSTATUS_BLOCK StatusBlock
)
346 if (RequestedMode
->RequestedMode
!= 0)
351 /* Nothing to do, really. We only support a single mode and we're already
360 * Resets the video hardware to the default mode, to which it was initialized
367 PXBOXVMP_DEVICE_EXTENSION DeviceExtension
,
368 PSTATUS_BLOCK StatusBlock
)
370 /* There is nothing to be done here */
376 * XboxVmpMapVideoMemory
378 * Maps the video hardware frame buffer and video RAM into the virtual address
379 * space of the requestor.
384 XboxVmpMapVideoMemory(
385 PXBOXVMP_DEVICE_EXTENSION DeviceExtension
,
386 PVIDEO_MEMORY RequestedAddress
,
387 PVIDEO_MEMORY_INFORMATION MapInformation
,
388 PSTATUS_BLOCK StatusBlock
)
390 PHYSICAL_ADDRESS FrameBuffer
;
391 ULONG inIoSpace
= VIDEO_MEMORY_SPACE_MEMORY
;
393 StatusBlock
->Information
= sizeof(VIDEO_MEMORY_INFORMATION
);
395 /* Reuse framebuffer that was set up by firmware */
396 FrameBuffer
.QuadPart
= *((PULONG
)((ULONG_PTR
)DeviceExtension
->VirtControlStart
+ NV2A_CONTROL_FRAMEBUFFER_ADDRESS_OFFSET
));
397 if (FrameBuffer
.QuadPart
!= 0x3C00000 && FrameBuffer
.QuadPart
!= 0x7C00000)
399 /* Check framebuffer address (high 4 MB of either 64 or 128 MB RAM) */
400 WARN_(IHVVIDEO
, "Non-standard framebuffer address 0x%p\n", FrameBuffer
.QuadPart
);
402 /* Verify that framebuffer address is page-aligned */
403 ASSERT(FrameBuffer
.QuadPart
% PAGE_SIZE
== 0);
405 FrameBuffer
.QuadPart
+= DeviceExtension
->PhysFrameBufferStart
.QuadPart
;
406 MapInformation
->VideoRamBase
= RequestedAddress
->RequestedVirtualAddress
;
407 /* FIXME: obtain fb size from firmware somehow (Cromwell reserves high 4 MB of RAM) */
408 MapInformation
->VideoRamLength
= NV2A_VIDEO_MEMORY_SIZE
;
413 &MapInformation
->VideoRamLength
,
415 &MapInformation
->VideoRamBase
);
417 MapInformation
->FrameBufferBase
= MapInformation
->VideoRamBase
;
418 MapInformation
->FrameBufferLength
= MapInformation
->VideoRamLength
;
420 /* Tell the nVidia controller about the framebuffer */
421 *((PULONG
)((ULONG_PTR
)DeviceExtension
->VirtControlStart
+ NV2A_CONTROL_FRAMEBUFFER_ADDRESS_OFFSET
)) = FrameBuffer
.u
.LowPart
;
423 INFO_(IHVVIDEO
, "Mapped 0x%x bytes of phys mem at 0x%lx to virt addr 0x%p\n",
424 MapInformation
->VideoRamLength
, FrameBuffer
.u
.LowPart
, MapInformation
->VideoRamBase
);
430 * VBEUnmapVideoMemory
432 * Releases a mapping between the virtual address space and the adapter's
433 * frame buffer and video RAM.
438 XboxVmpUnmapVideoMemory(
439 PXBOXVMP_DEVICE_EXTENSION DeviceExtension
,
440 PVIDEO_MEMORY VideoMemory
,
441 PSTATUS_BLOCK StatusBlock
)
443 VideoPortUnmapMemory(
445 VideoMemory
->RequestedVirtualAddress
,
452 * XboxVmpQueryNumAvailModes
454 * Returns the number of video modes supported by the adapter and the size
455 * in bytes of the video mode information, which can be used to allocate a
456 * buffer for an IOCTL_VIDEO_QUERY_AVAIL_MODES request.
461 XboxVmpQueryNumAvailModes(
462 PXBOXVMP_DEVICE_EXTENSION DeviceExtension
,
463 PVIDEO_NUM_MODES Modes
,
464 PSTATUS_BLOCK StatusBlock
)
467 Modes
->ModeInformationLength
= sizeof(VIDEO_MODE_INFORMATION
);
468 StatusBlock
->Information
= sizeof(VIDEO_NUM_MODES
);
473 * XboxVmpQueryAvailModes
475 * Returns information about each video mode supported by the adapter.
480 XboxVmpQueryAvailModes(
481 PXBOXVMP_DEVICE_EXTENSION DeviceExtension
,
482 PVIDEO_MODE_INFORMATION VideoMode
,
483 PSTATUS_BLOCK StatusBlock
)
485 return XboxVmpQueryCurrentMode(DeviceExtension
, VideoMode
, StatusBlock
);
490 PXBOXVMP_DEVICE_EXTENSION DeviceExtension
,
493 *((PUCHAR
)((ULONG_PTR
)DeviceExtension
->VirtControlStart
+ NV2A_CRTC_REGISTER_INDEX
)) = Index
;
494 return *((PUCHAR
)((ULONG_PTR
)DeviceExtension
->VirtControlStart
+ NV2A_CRTC_REGISTER_VALUE
));
499 PXBOXVMP_DEVICE_EXTENSION DeviceExtension
,
504 /* Get BPP directly from NV2A CRTC (magic constants are from Cromwell) */
505 BytesPerPixel
= 8 * (((NvGetCrtc(DeviceExtension
, 0x19) & 0xE0) << 3) | (NvGetCrtc(DeviceExtension
, 0x13) & 0xFF)) / ScreenWidth
;
507 if (BytesPerPixel
== 4)
509 ASSERT((NvGetCrtc(DeviceExtension
, 0x28) & 0xF) == BytesPerPixel
- 1);
513 ASSERT((NvGetCrtc(DeviceExtension
, 0x28) & 0xF) == BytesPerPixel
);
516 return BytesPerPixel
;
520 * VBEQueryCurrentMode
522 * Returns information about current video mode.
527 XboxVmpQueryCurrentMode(
528 PXBOXVMP_DEVICE_EXTENSION DeviceExtension
,
529 PVIDEO_MODE_INFORMATION VideoMode
,
530 PSTATUS_BLOCK StatusBlock
)
534 VideoMode
->Length
= sizeof(VIDEO_MODE_INFORMATION
);
535 VideoMode
->ModeIndex
= 0;
537 VideoMode
->VisScreenWidth
= *((PULONG
)((ULONG_PTR
)DeviceExtension
->VirtControlStart
+ NV2A_RAMDAC_FP_HVALID_END
)) + 1;
538 VideoMode
->VisScreenHeight
= *((PULONG
)((ULONG_PTR
)DeviceExtension
->VirtControlStart
+ NV2A_RAMDAC_FP_VVALID_END
)) + 1;
540 if (VideoMode
->VisScreenWidth
<= 1 || VideoMode
->VisScreenHeight
<= 1)
542 ERR_(IHVVIDEO
, "Cannot obtain current screen resolution!\n");
546 BytesPerPixel
= NvGetBytesPerPixel(DeviceExtension
, VideoMode
->VisScreenWidth
);
547 ASSERT(BytesPerPixel
>= 1 && BytesPerPixel
<= 4);
549 VideoMode
->ScreenStride
= VideoMode
->VisScreenWidth
* BytesPerPixel
;
550 VideoMode
->NumberOfPlanes
= 1;
551 VideoMode
->BitsPerPlane
= BytesPerPixel
* 8;
552 VideoMode
->Frequency
= 1;
553 VideoMode
->XMillimeter
= 0; /* FIXME */
554 VideoMode
->YMillimeter
= 0; /* FIXME */
555 if (BytesPerPixel
>= 3)
557 VideoMode
->NumberRedBits
= 8;
558 VideoMode
->NumberGreenBits
= 8;
559 VideoMode
->NumberBlueBits
= 8;
560 VideoMode
->RedMask
= 0xFF0000;
561 VideoMode
->GreenMask
= 0x00FF00;
562 VideoMode
->BlueMask
= 0x0000FF;
566 /* FIXME: not implemented */
567 WARN_(IHVVIDEO
, "BytesPerPixel %d - not implemented\n", BytesPerPixel
);
569 VideoMode
->VideoMemoryBitmapWidth
= VideoMode
->VisScreenWidth
;
570 VideoMode
->VideoMemoryBitmapHeight
= VideoMode
->VisScreenHeight
;
571 VideoMode
->AttributeFlags
= VIDEO_MODE_GRAPHICS
| VIDEO_MODE_COLOR
|
572 VIDEO_MODE_NO_OFF_SCREEN
;
573 VideoMode
->DriverSpecificAttributeFlags
= 0;
575 StatusBlock
->Information
= sizeof(VIDEO_MODE_INFORMATION
);
577 /* Verify that screen fits framebuffer size */
578 if (VideoMode
->VisScreenWidth
* VideoMode
->VisScreenHeight
* (VideoMode
->BitsPerPlane
/ 8) > NV2A_VIDEO_MEMORY_SIZE
)
580 ERR_(IHVVIDEO
, "Current screen resolution exceeds video memory bounds!\n");