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
;
392 SYSTEM_BASIC_INFORMATION BasicInfo
;
395 /* FIXME: this should probably be done differently, without native API */
396 StatusBlock
->Information
= sizeof(VIDEO_MEMORY_INFORMATION
);
398 FrameBuffer
.u
.HighPart
= 0;
399 if (ZwQuerySystemInformation(SystemBasicInformation
,
401 sizeof(SYSTEM_BASIC_INFORMATION
),
402 &Length
) == NO_ERROR
)
404 FrameBuffer
.u
.LowPart
= BasicInfo
.HighestPhysicalPageNumber
* PAGE_SIZE
;
408 ERR_(IHVVIDEO
, "ZwQueryBasicInformation failed, assuming 64MB total memory\n");
409 FrameBuffer
.u
.LowPart
= 60 * 1024 * 1024;
412 FrameBuffer
.QuadPart
+= DeviceExtension
->PhysFrameBufferStart
.QuadPart
;
413 MapInformation
->VideoRamBase
= RequestedAddress
->RequestedVirtualAddress
;
414 MapInformation
->VideoRamLength
= 4 * 1024 * 1024;
419 &MapInformation
->VideoRamLength
,
421 &MapInformation
->VideoRamBase
);
423 MapInformation
->FrameBufferBase
= MapInformation
->VideoRamBase
;
424 MapInformation
->FrameBufferLength
= MapInformation
->VideoRamLength
;
426 /* Tell the nVidia controller about the framebuffer */
427 *((PULONG
)((char *)DeviceExtension
->VirtControlStart
+ NV2A_CONTROL_FRAMEBUFFER_ADDRESS_OFFSET
)) = FrameBuffer
.u
.LowPart
;
429 INFO_(IHVVIDEO
, "Mapped 0x%x bytes of phys mem at 0x%lx to virt addr 0x%p\n",
430 MapInformation
->VideoRamLength
, FrameBuffer
.u
.LowPart
, MapInformation
->VideoRamBase
);
436 * VBEUnmapVideoMemory
438 * Releases a mapping between the virtual address space and the adapter's
439 * frame buffer and video RAM.
444 XboxVmpUnmapVideoMemory(
445 PXBOXVMP_DEVICE_EXTENSION DeviceExtension
,
446 PVIDEO_MEMORY VideoMemory
,
447 PSTATUS_BLOCK StatusBlock
)
449 VideoPortUnmapMemory(
451 VideoMemory
->RequestedVirtualAddress
,
458 * XboxVmpQueryNumAvailModes
460 * Returns the number of video modes supported by the adapter and the size
461 * in bytes of the video mode information, which can be used to allocate a
462 * buffer for an IOCTL_VIDEO_QUERY_AVAIL_MODES request.
467 XboxVmpQueryNumAvailModes(
468 PXBOXVMP_DEVICE_EXTENSION DeviceExtension
,
469 PVIDEO_NUM_MODES Modes
,
470 PSTATUS_BLOCK StatusBlock
)
473 Modes
->ModeInformationLength
= sizeof(VIDEO_MODE_INFORMATION
);
474 StatusBlock
->Information
= sizeof(VIDEO_NUM_MODES
);
484 ULONG
*Data_to_smbus
)
486 int nRetriesToLive
= 50;
488 while ((VideoPortReadPortUshort((PUSHORT
) (I2C_IO_BASE
+ 0)) & 0x0800) != 0)
490 ; /* Franz's spin while bus busy with any master traffic */
493 while (nRetriesToLive
-- != 0)
498 VideoPortWritePortUchar((PUCHAR
) (I2C_IO_BASE
+ 4), (Address
<< 1) | 1);
499 VideoPortWritePortUchar((PUCHAR
) (I2C_IO_BASE
+ 8), bRegister
);
501 temp
= VideoPortReadPortUshort((PUSHORT
) (I2C_IO_BASE
+ 0));
502 VideoPortWritePortUshort((PUSHORT
) (I2C_IO_BASE
+ 0), temp
); /* clear down all preexisting errors */
508 VideoPortWritePortUchar((PUCHAR
) (I2C_IO_BASE
+ 2), 0x0d); /* DWORD modus ? */
514 VideoPortWritePortUchar((PUCHAR
) (I2C_IO_BASE
+ 2), 0x0b); /* WORD modus */
520 VideoPortWritePortUchar((PUCHAR
) (I2C_IO_BASE
+ 2), 0x0a); /* BYTE */
526 while ((b
& 0x36) == 0)
528 b
= VideoPortReadPortUchar((PUCHAR
) (I2C_IO_BASE
+ 0));
533 ERR_(IHVVIDEO
, "I2CTransmitByteGetReturn error %x\n", b
);
538 ERR_(IHVVIDEO
, "I2CTransmitByteGetReturn no complete, retry\n");
546 VideoPortReadPortUchar((PUCHAR
) (I2C_IO_BASE
+ 6));
547 VideoPortReadPortUchar((PUCHAR
) (I2C_IO_BASE
+ 9));
548 VideoPortReadPortUchar((PUCHAR
) (I2C_IO_BASE
+ 9));
549 VideoPortReadPortUchar((PUCHAR
) (I2C_IO_BASE
+ 9));
550 VideoPortReadPortUchar((PUCHAR
) (I2C_IO_BASE
+ 9));
556 *Data_to_smbus
= VideoPortReadPortUshort((PUSHORT
) (I2C_IO_BASE
+ 6));
562 *Data_to_smbus
= VideoPortReadPortUchar((PUCHAR
) (I2C_IO_BASE
+ 6));
576 I2CTransmitByteGetReturn(
577 UCHAR bPicAddressI2cFormat
,
581 return ReadfromSMBus(bPicAddressI2cFormat
, bDataToWrite
, 1, Return
);
585 * XboxVmpQueryAvailModes
587 * Returns information about each video mode supported by the adapter.
592 XboxVmpQueryAvailModes(
593 PXBOXVMP_DEVICE_EXTENSION DeviceExtension
,
594 PVIDEO_MODE_INFORMATION VideoMode
,
595 PSTATUS_BLOCK StatusBlock
)
597 return XboxVmpQueryCurrentMode(DeviceExtension
, VideoMode
, StatusBlock
);
601 * VBEQueryCurrentMode
603 * Returns information about current video mode.
608 XboxVmpQueryCurrentMode(
609 PXBOXVMP_DEVICE_EXTENSION DeviceExtension
,
610 PVIDEO_MODE_INFORMATION VideoMode
,
611 PSTATUS_BLOCK StatusBlock
)
615 VideoMode
->Length
= sizeof(VIDEO_MODE_INFORMATION
);
616 VideoMode
->ModeIndex
= 0;
618 if (I2CTransmitByteGetReturn(0x10, 0x04, &AvMode
))
620 if (AvMode
== 1) /* HDTV */
622 VideoMode
->VisScreenWidth
= 720;
626 /* FIXME Other possible values of AvMode:
634 VideoMode
->VisScreenWidth
= 640;
639 VideoMode
->VisScreenWidth
= 640;
642 VideoMode
->VisScreenHeight
= 480;
643 VideoMode
->ScreenStride
= VideoMode
->VisScreenWidth
* 4;
644 VideoMode
->NumberOfPlanes
= 1;
645 VideoMode
->BitsPerPlane
= 32;
646 VideoMode
->Frequency
= 1;
647 VideoMode
->XMillimeter
= 0; /* FIXME */
648 VideoMode
->YMillimeter
= 0; /* FIXME */
649 VideoMode
->NumberRedBits
= 8;
650 VideoMode
->NumberGreenBits
= 8;
651 VideoMode
->NumberBlueBits
= 8;
652 VideoMode
->RedMask
= 0xFF0000;
653 VideoMode
->GreenMask
= 0x00FF00;
654 VideoMode
->BlueMask
= 0x0000FF;
655 VideoMode
->VideoMemoryBitmapWidth
= VideoMode
->VisScreenWidth
;
656 VideoMode
->VideoMemoryBitmapHeight
= VideoMode
->VisScreenHeight
;
657 VideoMode
->AttributeFlags
= VIDEO_MODE_GRAPHICS
| VIDEO_MODE_COLOR
|
658 VIDEO_MODE_NO_OFF_SCREEN
;
659 VideoMode
->DriverSpecificAttributeFlags
= 0;
661 StatusBlock
->Information
= sizeof(VIDEO_MODE_INFORMATION
);