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@gmail.com) - */ - -/* INCLUDES *******************************************************************/ - -#include "xboxvmp.h" - -#include -#include - -/* 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)) + 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) { - 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 = 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 {