https://git.reactos.org/?p=reactos.git;a=commitdiff;h=297abde716495c13cfcaf…
commit 297abde716495c13cfcafac5c0dee867cfb4c7a3
Author: Stanislav Motylkov <x86corez(a)gmail.com>
AuthorDate: Thu Oct 10 00:27:22 2019 +0300
Commit: Hermès BÉLUSCA - MAÏTO <hermes.belusca-maito(a)reactos.org>
CommitDate: Wed Oct 9 23:27:22 2019 +0200
[FREELDR][XBOXVMP] Retrieve screen resolution directly from NV2A GPU (#1962)
CORE-16216
---
boot/freeldr/freeldr/arch/i386/xboxvideo.c | 57 +++++-----
boot/freeldr/freeldr/include/arch/i386/machxbox.h | 9 ++
win32ss/drivers/miniport/CMakeLists.txt | 5 +-
win32ss/drivers/miniport/xboxvmp/CMakeLists.txt | 1 -
win32ss/drivers/miniport/xboxvmp/xboxi2c.c | 123 ----------------------
win32ss/drivers/miniport/xboxvmp/xboxvmp.c | 98 +++++++++++------
win32ss/drivers/miniport/xboxvmp/xboxvmp.h | 13 ++-
7 files changed, 110 insertions(+), 196 deletions(-)
diff --git a/boot/freeldr/freeldr/arch/i386/xboxvideo.c
b/boot/freeldr/freeldr/arch/i386/xboxvideo.c
index c664eef5d3c..d5839024d43 100644
--- a/boot/freeldr/freeldr/arch/i386/xboxvideo.c
+++ b/boot/freeldr/freeldr/arch/i386/xboxvideo.c
@@ -40,8 +40,6 @@ static ULONG Delta;
#define MAKE_COLOR(Red, Green, Blue) (0xff000000 | (((Red) & 0xff) << 16) |
(((Green) & 0xff) << 8) | ((Blue) & 0xff))
-BOOLEAN I2CTransmitByteGetReturn(UCHAR bPicAddressI2cFormat, UCHAR bDataToWrite, ULONG
*Return);
-
static VOID
XboxVideoOutputChar(UCHAR Char, unsigned X, unsigned Y, ULONG FgColor, ULONG BgColor)
{
@@ -122,48 +120,45 @@ XboxVideoPutChar(int Ch, UCHAR Attr, unsigned X, unsigned Y)
XboxVideoOutputChar(Ch, X, Y, FgColor, BgColor);
}
+UCHAR
+NvGetCrtc(UCHAR Index)
+{
+ *((PUCHAR) NV2A_CRTC_REGISTER_INDEX) = Index;
+ return *((PUCHAR) NV2A_CRTC_REGISTER_VALUE);
+}
+
VOID
XboxVideoInit(VOID)
{
- ULONG AvMode;
-
/* Reuse framebuffer that was set up by firmware */
- FrameBuffer = (PVOID)*((PULONG) 0xfd600800);
+ FrameBuffer = (PVOID)*((PULONG) NV2A_CRTC_FRAMEBUFFER_START);
/* Verify that framebuffer address is page-aligned */
ASSERT((ULONG_PTR)FrameBuffer % PAGE_SIZE == 0);
/* FIXME: obtain fb size from firmware somehow (Cromwell reserves high 4 MB of RAM) */
FrameBufferSize = 4 * 1024 * 1024;
- /* FIXME: don't use SMBus, obtain current video resolution directly from NV2A */
- if (I2CTransmitByteGetReturn(0x10, 0x04, &AvMode))
- {
- if (1 == AvMode) /* HDTV */
- {
- ScreenWidth = 720;
- }
- else
- {
- /* FIXME Other possible values of AvMode:
- * 0 - AV_SCART_RGB
- * 2 - AV_VGA_SOG
- * 4 - AV_SVIDEO
- * 6 - AV_COMPOSITE
- * 7 - AV_VGA
- * other AV_COMPOSITE
- */
- ScreenWidth = 640;
- }
- }
+ ScreenWidth = *((PULONG) NV2A_RAMDAC_FP_HVALID_END) + 1;
+ ScreenHeight = *((PULONG) NV2A_RAMDAC_FP_VVALID_END) + 1;
+ /* Get BPP directly from NV2A CRTC (magic constants are from Cromwell) */
+ BytesPerPixel = 8 * (((NvGetCrtc(0x19) & 0xE0) << 3) | (NvGetCrtc(0x13) &
0xFF)) / ScreenWidth;
+ if (BytesPerPixel == 4)
+ {
+ ASSERT((NvGetCrtc(0x28) & 0xF) == BytesPerPixel - 1);
+ }
else
- {
- ScreenWidth = 640;
- }
-
- ScreenHeight = 480;
- BytesPerPixel = 4;
+ {
+ ASSERT((NvGetCrtc(0x28) & 0xF) == BytesPerPixel);
+ }
Delta = (ScreenWidth * BytesPerPixel + 3) & ~ 0x3;
+ /* Verify screen resolution */
+ ASSERT(ScreenWidth > 1);
+ ASSERT(ScreenHeight > 1);
+ ASSERT(BytesPerPixel >= 1 && BytesPerPixel <= 4);
+ /* Verify that screen fits framebuffer size */
+ ASSERT(ScreenWidth * ScreenHeight * BytesPerPixel <= FrameBufferSize);
+
XboxVideoClearScreenColor(MAKE_COLOR(0, 0, 0), TRUE);
}
diff --git a/boot/freeldr/freeldr/include/arch/i386/machxbox.h
b/boot/freeldr/freeldr/include/arch/i386/machxbox.h
index 393f3a900e2..31f8f7e996d 100644
--- a/boot/freeldr/freeldr/include/arch/i386/machxbox.h
+++ b/boot/freeldr/freeldr/include/arch/i386/machxbox.h
@@ -37,6 +37,15 @@
#define LPC_CONFIG_DEVICE_BASE_ADDRESS_LOW 0x61
#define LPC_CONFIG_DEVICE_INTERRUPT 0x70
+#define NV2A_CONTROL_OFFSET 0xFD000000
+#define NV2A_CRTC_OFFSET (0x600000 + NV2A_CONTROL_OFFSET)
+#define NV2A_CRTC_FRAMEBUFFER_START (0x800 + NV2A_CRTC_OFFSET)
+#define NV2A_CRTC_REGISTER_INDEX (0x13D4 + NV2A_CRTC_OFFSET)
+#define NV2A_CRTC_REGISTER_VALUE (0x13D5 + NV2A_CRTC_OFFSET)
+#define NV2A_RAMDAC_OFFSET (0x680000 + NV2A_CONTROL_OFFSET)
+#define NV2A_RAMDAC_FP_HVALID_END (0x838 + NV2A_RAMDAC_OFFSET)
+#define NV2A_RAMDAC_FP_VVALID_END (0x818 + NV2A_RAMDAC_OFFSET)
+
extern UCHAR XboxFont8x16[256 * 16];
VOID XboxMachInit(const char *CmdLine);
diff --git a/win32ss/drivers/miniport/CMakeLists.txt
b/win32ss/drivers/miniport/CMakeLists.txt
index 52898276311..79b52e628bb 100644
--- a/win32ss/drivers/miniport/CMakeLists.txt
+++ b/win32ss/drivers/miniport/CMakeLists.txt
@@ -3,4 +3,7 @@ add_subdirectory(vbe)
add_subdirectory(vga)
add_subdirectory(vga_new)
add_subdirectory(vmx_svga)
-add_subdirectory(xboxvmp)
+
+if(ARCH STREQUAL "i386")
+ add_subdirectory(xboxvmp)
+endif()
diff --git a/win32ss/drivers/miniport/xboxvmp/CMakeLists.txt
b/win32ss/drivers/miniport/xboxvmp/CMakeLists.txt
index 59941c74349..e9d37f0edee 100644
--- a/win32ss/drivers/miniport/xboxvmp/CMakeLists.txt
+++ b/win32ss/drivers/miniport/xboxvmp/CMakeLists.txt
@@ -1,6 +1,5 @@
list(APPEND SOURCE
- xboxi2c.c
xboxvmp.c
xboxvmp.h)
diff --git a/win32ss/drivers/miniport/xboxvmp/xboxi2c.c
b/win32ss/drivers/miniport/xboxvmp/xboxi2c.c
deleted file mode 100644
index fc283af7e98..00000000000
--- a/win32ss/drivers/miniport/xboxvmp/xboxi2c.c
+++ /dev/null
@@ -1,123 +0,0 @@
-/*
- * PROJECT: ReactOS Xbox miniport video driver
- * LICENSE: GPL-2.0-or-later (
https://spdx.org/licenses/GPL-2.0-or-later)
- * PURPOSE: I2C SMBus routines
- * COPYRIGHT: Copyright 2004 Gé van Geldorp
- * Copyright 2004 Filip Navara
- * Copyright 2019 Stanislav Motylkov (x86corez(a)gmail.com)
- */
-
-/* INCLUDES *******************************************************************/
-
-#include "xboxvmp.h"
-
-#include <debug.h>
-#include <dpfilter.h>
-
-/* PUBLIC AND PRIVATE FUNCTIONS ***********************************************/
-
-static
-BOOLEAN
-ReadfromSMBus(
- UCHAR Address,
- UCHAR bRegister,
- UCHAR Size,
- ULONG *Data_to_smbus)
-{
- int nRetriesToLive = 50;
-
- while ((VideoPortReadPortUshort((PUSHORT) (I2C_IO_BASE + 0)) & 0x0800) != 0)
- {
- ; /* Franz's spin while bus busy with any master traffic */
- }
-
- while (nRetriesToLive-- != 0)
- {
- UCHAR b;
- int temp;
-
- VideoPortWritePortUchar((PUCHAR) (I2C_IO_BASE + 4), (Address << 1) | 1);
- VideoPortWritePortUchar((PUCHAR) (I2C_IO_BASE + 8), bRegister);
-
- temp = VideoPortReadPortUshort((PUSHORT) (I2C_IO_BASE + 0));
- VideoPortWritePortUshort((PUSHORT) (I2C_IO_BASE + 0), temp); /* clear down all
preexisting errors */
-
- switch (Size)
- {
- case 4:
- {
- VideoPortWritePortUchar((PUCHAR) (I2C_IO_BASE + 2), 0x0d); /* DWORD modus
? */
- break;
- }
-
- case 2:
- {
- VideoPortWritePortUchar((PUCHAR) (I2C_IO_BASE + 2), 0x0b); /* WORD modus
*/
- break;
- }
-
- default:
- {
- VideoPortWritePortUchar((PUCHAR) (I2C_IO_BASE + 2), 0x0a); /* BYTE */
- }
- }
-
- b = 0;
-
- while ((b & 0x36) == 0)
- {
- b = VideoPortReadPortUchar((PUCHAR) (I2C_IO_BASE + 0));
- }
-
- if ((b & 0x24) != 0)
- {
- ERR_(IHVVIDEO, "I2CTransmitByteGetReturn error %x\n", b);
- }
-
- if ((b & 0x10) == 0)
- {
- ERR_(IHVVIDEO, "I2CTransmitByteGetReturn no complete, retry\n");
- }
- else
- {
- switch (Size)
- {
- case 4:
- {
- VideoPortReadPortUchar((PUCHAR) (I2C_IO_BASE + 6));
- VideoPortReadPortUchar((PUCHAR) (I2C_IO_BASE + 9));
- VideoPortReadPortUchar((PUCHAR) (I2C_IO_BASE + 9));
- VideoPortReadPortUchar((PUCHAR) (I2C_IO_BASE + 9));
- VideoPortReadPortUchar((PUCHAR) (I2C_IO_BASE + 9));
- break;
- }
-
- case 2:
- {
- *Data_to_smbus = VideoPortReadPortUshort((PUSHORT) (I2C_IO_BASE +
6));
- break;
- }
-
- default:
- {
- *Data_to_smbus = VideoPortReadPortUchar((PUCHAR) (I2C_IO_BASE + 6));
- }
- }
-
- return TRUE;
- }
- }
-
- return FALSE;
-}
-
-BOOLEAN
-I2CTransmitByteGetReturn(
- UCHAR bPicAddressI2cFormat,
- UCHAR bDataToWrite,
- ULONG *Return)
-{
- return ReadfromSMBus(bPicAddressI2cFormat, bDataToWrite, 1, Return);
-}
-
-/* EOF */
diff --git a/win32ss/drivers/miniport/xboxvmp/xboxvmp.c
b/win32ss/drivers/miniport/xboxvmp/xboxvmp.c
index 5d6fc275dac..98f584ec086 100644
--- a/win32ss/drivers/miniport/xboxvmp/xboxvmp.c
+++ b/win32ss/drivers/miniport/xboxvmp/xboxvmp.c
@@ -405,7 +405,7 @@ XboxVmpMapVideoMemory(
FrameBuffer.QuadPart += DeviceExtension->PhysFrameBufferStart.QuadPart;
MapInformation->VideoRamBase = RequestedAddress->RequestedVirtualAddress;
/* FIXME: obtain fb size from firmware somehow (Cromwell reserves high 4 MB of RAM)
*/
- MapInformation->VideoRamLength = 4 * 1024 * 1024;
+ MapInformation->VideoRamLength = NV2A_VIDEO_MEMORY_SIZE;
VideoPortMapMemory(
DeviceExtension,
@@ -485,6 +485,37 @@ XboxVmpQueryAvailModes(
return XboxVmpQueryCurrentMode(DeviceExtension, VideoMode, StatusBlock);
}
+UCHAR
+NvGetCrtc(
+ PXBOXVMP_DEVICE_EXTENSION DeviceExtension,
+ UCHAR Index)
+{
+ *((PUCHAR)((ULONG_PTR)DeviceExtension->VirtControlStart +
NV2A_CRTC_REGISTER_INDEX)) = Index;
+ return *((PUCHAR)((ULONG_PTR)DeviceExtension->VirtControlStart +
NV2A_CRTC_REGISTER_VALUE));
+}
+
+UCHAR
+NvGetBytesPerPixel(
+ PXBOXVMP_DEVICE_EXTENSION DeviceExtension,
+ ULONG ScreenWidth)
+{
+ UCHAR BytesPerPixel;
+
+ /* Get BPP directly from NV2A CRTC (magic constants are from Cromwell) */
+ BytesPerPixel = 8 * (((NvGetCrtc(DeviceExtension, 0x19) & 0xE0) << 3) |
(NvGetCrtc(DeviceExtension, 0x13) & 0xFF)) / ScreenWidth;
+
+ if (BytesPerPixel == 4)
+ {
+ ASSERT((NvGetCrtc(DeviceExtension, 0x28) & 0xF) == BytesPerPixel - 1);
+ }
+ else
+ {
+ ASSERT((NvGetCrtc(DeviceExtension, 0x28) & 0xF) == BytesPerPixel);
+ }
+
+ return BytesPerPixel;
+}
+
/*
* VBEQueryCurrentMode
*
@@ -498,49 +529,43 @@ XboxVmpQueryCurrentMode(
PVIDEO_MODE_INFORMATION VideoMode,
PSTATUS_BLOCK StatusBlock)
{
- ULONG AvMode = 0;
+ UCHAR BytesPerPixel;
VideoMode->Length = sizeof(VIDEO_MODE_INFORMATION);
VideoMode->ModeIndex = 0;
- /* FIXME: don't use SMBus, obtain current video resolution directly from NV2A */
- if (I2CTransmitByteGetReturn(0x10, 0x04, &AvMode))
- {
- if (AvMode == 1) /* HDTV */
- {
- VideoMode->VisScreenWidth = 720;
- }
- else
- {
- /* FIXME Other possible values of AvMode:
- * 0 - AV_SCART_RGB
- * 2 - AV_VGA_SOG
- * 4 - AV_SVIDEO
- * 6 - AV_COMPOSITE
- * 7 - AV_VGA
- * other AV_COMPOSITE
- */
- VideoMode->VisScreenWidth = 640;
- }
- }
- else
+ VideoMode->VisScreenWidth =
*((PULONG)((ULONG_PTR)DeviceExtension->VirtControlStart + NV2A_RAMDAC_FP_HVALID_END)) +
1;
+ VideoMode->VisScreenHeight =
*((PULONG)((ULONG_PTR)DeviceExtension->VirtControlStart + NV2A_RAMDAC_FP_VVALID_END)) +
1;
+
+ if (VideoMode->VisScreenWidth <= 1 || VideoMode->VisScreenHeight <= 1)
{
- VideoMode->VisScreenWidth = 640;
+ ERR_(IHVVIDEO, "Cannot obtain current screen resolution!\n");
+ return FALSE;
}
- VideoMode->VisScreenHeight = 480;
- VideoMode->ScreenStride = VideoMode->VisScreenWidth * 4;
+ BytesPerPixel = NvGetBytesPerPixel(DeviceExtension, VideoMode->VisScreenWidth);
+ ASSERT(BytesPerPixel >= 1 && BytesPerPixel <= 4);
+
+ VideoMode->ScreenStride = VideoMode->VisScreenWidth * BytesPerPixel;
VideoMode->NumberOfPlanes = 1;
- VideoMode->BitsPerPlane = 32;
+ VideoMode->BitsPerPlane = BytesPerPixel * 8;
VideoMode->Frequency = 1;
VideoMode->XMillimeter = 0; /* FIXME */
VideoMode->YMillimeter = 0; /* FIXME */
- VideoMode->NumberRedBits = 8;
- VideoMode->NumberGreenBits = 8;
- VideoMode->NumberBlueBits = 8;
- VideoMode->RedMask = 0xFF0000;
- VideoMode->GreenMask = 0x00FF00;
- VideoMode->BlueMask = 0x0000FF;
+ if (BytesPerPixel >= 3)
+ {
+ VideoMode->NumberRedBits = 8;
+ VideoMode->NumberGreenBits = 8;
+ VideoMode->NumberBlueBits = 8;
+ VideoMode->RedMask = 0xFF0000;
+ VideoMode->GreenMask = 0x00FF00;
+ VideoMode->BlueMask = 0x0000FF;
+ }
+ else
+ {
+ /* FIXME: not implemented */
+ WARN_(IHVVIDEO, "BytesPerPixel %d - not implemented\n",
BytesPerPixel);
+ }
VideoMode->VideoMemoryBitmapWidth = VideoMode->VisScreenWidth;
VideoMode->VideoMemoryBitmapHeight = VideoMode->VisScreenHeight;
VideoMode->AttributeFlags = VIDEO_MODE_GRAPHICS | VIDEO_MODE_COLOR |
@@ -549,6 +574,13 @@ XboxVmpQueryCurrentMode(
StatusBlock->Information = sizeof(VIDEO_MODE_INFORMATION);
+ /* Verify that screen fits framebuffer size */
+ if (VideoMode->VisScreenWidth * VideoMode->VisScreenHeight *
(VideoMode->BitsPerPlane / 8) > NV2A_VIDEO_MEMORY_SIZE)
+ {
+ ERR_(IHVVIDEO, "Current screen resolution exceeds video memory
bounds!\n");
+ return FALSE;
+ }
+
return TRUE;
}
diff --git a/win32ss/drivers/miniport/xboxvmp/xboxvmp.h
b/win32ss/drivers/miniport/xboxvmp/xboxvmp.h
index 5742cef3e29..6365c5c1092 100644
--- a/win32ss/drivers/miniport/xboxvmp/xboxvmp.h
+++ b/win32ss/drivers/miniport/xboxvmp/xboxvmp.h
@@ -22,14 +22,13 @@
#include "miniport.h"
#include "video.h"
-#define I2C_IO_BASE 0xC000
-#define NV2A_CONTROL_FRAMEBUFFER_ADDRESS_OFFSET 0x600800
+#define NV2A_VIDEO_MEMORY_SIZE (4 * 1024 * 1024)
-BOOLEAN
-I2CTransmitByteGetReturn(
- UCHAR bPicAddressI2cFormat,
- UCHAR bDataToWrite,
- ULONG *Return);
+#define NV2A_CONTROL_FRAMEBUFFER_ADDRESS_OFFSET 0x600800
+#define NV2A_CRTC_REGISTER_INDEX 0x6013D4
+#define NV2A_CRTC_REGISTER_VALUE 0x6013D5
+#define NV2A_RAMDAC_FP_HVALID_END 0x680838
+#define NV2A_RAMDAC_FP_VVALID_END 0x680818
typedef struct
{