[FREELDR][XBOXVMP] Retrieve screen resolution directly from NV2A GPU (#1962)
authorStanislav Motylkov <x86corez@gmail.com>
Wed, 9 Oct 2019 21:27:22 +0000 (00:27 +0300)
committerHermès BÉLUSCA - MAÏTO <hermes.belusca-maito@reactos.org>
Wed, 9 Oct 2019 21:27:22 +0000 (23:27 +0200)
CORE-16216

boot/freeldr/freeldr/arch/i386/xboxvideo.c
boot/freeldr/freeldr/include/arch/i386/machxbox.h
win32ss/drivers/miniport/CMakeLists.txt
win32ss/drivers/miniport/xboxvmp/CMakeLists.txt
win32ss/drivers/miniport/xboxvmp/xboxi2c.c [deleted file]
win32ss/drivers/miniport/xboxvmp/xboxvmp.c
win32ss/drivers/miniport/xboxvmp/xboxvmp.h

index c664eef..d583902 100644 (file)
@@ -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);
 }
 
index 393f3a9..31f8f7e 100644 (file)
 #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);
index 5289827..79b52e6 100644 (file)
@@ -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()
index 59941c7..e9d37f0 100644 (file)
@@ -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 (file)
index fc283af..0000000
+++ /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@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 */
index 5d6fc27..98f584e 100644 (file)
@@ -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;
 }
 
index 5742cef..6365c5c 100644 (file)
 #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
 {