GOP: Add option for 90-degree rotation

Swap the reported horizontal and vertical resolutions and rotate block
transfer operations. Also set PixelFormat to PixelBltOnly as we
shouldn't claim to support a framebuffer given the fake resolution.

This approach is flawed in multiple ways: slow perf, no framebuffer in
OS (or garbled up). But it is way more convenient on the Fydetab - and
realistically it's going to be fine for Linux boot as it has a native
display driver.

Signed-off-by: Mario Bălănică <mariobalanica02@gmail.com>
This commit is contained in:
Mario Bălănică
2025-03-15 01:45:07 +02:00
parent e9209cbaa6
commit 0e585c8a6e
11 changed files with 306 additions and 31 deletions

View File

@@ -103,6 +103,7 @@
VOP_OUTPUT_IF_DP0,
VOP_OUTPUT_IF_MIPI0
})}
gRK3588TokenSpaceGuid.PcdDisplayRotationDefault|90
################################################################################
#

View File

@@ -10,9 +10,9 @@
#include "LcdGraphicsOutputDxe.h"
STATIC
EFI_STATUS
EFIAPI
LcdGraphicsBlt (
LcdGraphicsBltCheckParameters (
IN EFI_GRAPHICS_OUTPUT_PROTOCOL *This,
IN OUT EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltBuffer OPTIONAL,
IN EFI_GRAPHICS_OUTPUT_BLT_OPERATION BltOperation,
@@ -25,18 +25,8 @@ LcdGraphicsBlt (
IN UINTN Delta OPTIONAL
)
{
UINT32 *FrameBuffer;
UINT32 HorizontalResolution;
UINT32 VerticalResolution;
UINTN WidthInBytes;
UINT32 *SourceBuffer;
UINT32 *DestinationBuffer;
UINTN Y;
FrameBuffer = (UINT32 *)This->Mode->FrameBufferBase;
HorizontalResolution = This->Mode->Info->HorizontalResolution;
VerticalResolution = This->Mode->Info->VerticalResolution;
WidthInBytes = Width * RK_BYTES_PER_PIXEL;
UINT32 HorizontalResolution = This->Mode->Info->HorizontalResolution;
UINT32 VerticalResolution = This->Mode->Info->VerticalResolution;
if ((Width == 0) || (Height == 0)) {
return EFI_INVALID_PARAMETER;
@@ -80,9 +70,52 @@ LcdGraphicsBlt (
}
}
//
// Perform the Block Transfer Operation
//
return EFI_SUCCESS;
}
EFI_STATUS
EFIAPI
LcdGraphicsBlt (
IN EFI_GRAPHICS_OUTPUT_PROTOCOL *This,
IN OUT EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltBuffer OPTIONAL,
IN EFI_GRAPHICS_OUTPUT_BLT_OPERATION BltOperation,
IN UINTN SourceX,
IN UINTN SourceY,
IN UINTN DestinationX,
IN UINTN DestinationY,
IN UINTN Width,
IN UINTN Height,
IN UINTN Delta OPTIONAL
)
{
EFI_STATUS Status;
UINT32 *FrameBuffer;
UINT32 HorizontalResolution;
UINTN WidthInBytes;
UINT32 *SourceBuffer;
UINT32 *DestinationBuffer;
UINTN Y;
FrameBuffer = (UINT32 *)This->Mode->FrameBufferBase;
HorizontalResolution = This->Mode->Info->HorizontalResolution;
WidthInBytes = Width * RK_BYTES_PER_PIXEL;
Status = LcdGraphicsBltCheckParameters (
This,
BltBuffer,
BltOperation,
SourceX,
SourceY,
DestinationX,
DestinationY,
Width,
Height,
Delta
);
if (EFI_ERROR (Status)) {
return Status;
}
switch (BltOperation) {
case EfiBltVideoFill:
SourceBuffer = (UINT32 *)BltBuffer;
@@ -170,3 +203,145 @@ LcdGraphicsBlt (
return EFI_SUCCESS;
}
EFI_STATUS
EFIAPI
LcdGraphicsBlt90 (
IN EFI_GRAPHICS_OUTPUT_PROTOCOL *This,
IN OUT EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltBuffer OPTIONAL,
IN EFI_GRAPHICS_OUTPUT_BLT_OPERATION BltOperation,
IN UINTN SourceX,
IN UINTN SourceY,
IN UINTN DestinationX,
IN UINTN DestinationY,
IN UINTN Width,
IN UINTN Height,
IN UINTN Delta OPTIONAL
)
{
EFI_STATUS Status;
UINT32 *FrameBuffer;
UINT32 HorizontalResolution;
UINTN WidthInBytes;
UINT32 *SourceBuffer;
UINT32 *DestinationBuffer;
UINTN Y;
UINTN X;
FrameBuffer = (UINT32 *)This->Mode->FrameBufferBase;
HorizontalResolution = This->Mode->Info->VerticalResolution;
WidthInBytes = Width * RK_BYTES_PER_PIXEL;
Status = LcdGraphicsBltCheckParameters (
This,
BltBuffer,
BltOperation,
SourceX,
SourceY,
DestinationX,
DestinationY,
Width,
Height,
Delta
);
if (EFI_ERROR (Status)) {
return Status;
}
switch (BltOperation) {
case EfiBltVideoFill:
SourceBuffer = (UINT32 *)BltBuffer;
for (Y = 0; Y < Height; Y++) {
for (X = 0; X < Width; X++) {
DestinationBuffer = FrameBuffer +
(HorizontalResolution - 1 - (DestinationY + Y)) +
(DestinationX + X) * HorizontalResolution;
*DestinationBuffer = *SourceBuffer;
}
}
break;
case EfiBltVideoToBltBuffer:
if (Delta == 0) {
Delta = WidthInBytes;
}
for (Y = 0; Y < Height; Y++) {
for (X = 0; X < Width; X++) {
SourceBuffer = FrameBuffer +
(HorizontalResolution - 1 - (SourceY + Y)) +
(SourceX + X) * HorizontalResolution;
DestinationBuffer = (UINT32 *)((UINTN)BltBuffer +
(DestinationY + Y) * Delta +
(DestinationX + X) * RK_BYTES_PER_PIXEL);
*DestinationBuffer = *SourceBuffer;
}
}
break;
case EfiBltBufferToVideo:
if (Delta == 0) {
Delta = WidthInBytes;
}
for (Y = 0; Y < Height; Y++) {
for (X = 0; X < Width; X++) {
SourceBuffer = (UINT32 *)((UINTN)BltBuffer +
(SourceY + Y) * Delta +
(SourceX + X) * RK_BYTES_PER_PIXEL);
DestinationBuffer = FrameBuffer +
(HorizontalResolution - 1 - (DestinationY + Y)) +
(DestinationX + X) * HorizontalResolution;
*DestinationBuffer = *SourceBuffer;
}
}
break;
case EfiBltVideoToVideo:
if (SourceY < DestinationY) {
for (Y = Height; Y-- > 0;) {
for (X = 0; X < Width; X++) {
SourceBuffer = FrameBuffer +
(HorizontalResolution - 1 - (SourceY + Y)) +
(SourceX + X) * HorizontalResolution;
DestinationBuffer = FrameBuffer +
(HorizontalResolution - 1 - (DestinationY + Y)) +
(DestinationX + X) * HorizontalResolution;
*DestinationBuffer = *SourceBuffer;
}
}
} else {
for (Y = 0; Y < Height; Y++) {
for (X = 0; X < Width; X++) {
SourceBuffer = FrameBuffer +
(HorizontalResolution - 1 - (SourceY + Y)) +
(SourceX + X) * HorizontalResolution;
DestinationBuffer = FrameBuffer +
(HorizontalResolution - 1 - (DestinationY + Y)) +
(DestinationX + X) * HorizontalResolution;
*DestinationBuffer = *SourceBuffer;
}
}
}
break;
default:
return EFI_INVALID_PARAMETER;
}
return EFI_SUCCESS;
}

View File

@@ -463,8 +463,6 @@ GetSupportedDisplayModes (
Instance->Gop.Mode->Mode = MAX_UINT32;
Instance->Mode.Info->PixelFormat = PixelBlueGreenRedReserved8BitPerColor;
Instance->DisplayModes = AllocateZeroPool (
sizeof (DISPLAY_MODE) *
Instance->Gop.Mode->MaxMode
@@ -716,6 +714,53 @@ LcdGraphicsOutputDxeInitialize (
return Status;
}
STATIC
VOID
LcdGraphicsSetModeInfo (
IN EFI_GRAPHICS_OUTPUT_PROTOCOL *This,
OUT EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *Info,
IN CONST DISPLAY_MODE *DisplayMode,
IN BOOLEAN Update
)
{
UINT16 Rotation = PcdGet16 (PcdDisplayRotation);
This->Mode->Info->Version = 0;
if ((Rotation == 90)) {
//
// Swap the reported resolution and only allow Blt operations.
//
Info->HorizontalResolution = DisplayMode->VActive;
Info->VerticalResolution = DisplayMode->HActive;
Info->PixelFormat = PixelBltOnly;
} else {
Info->HorizontalResolution = DisplayMode->HActive;
Info->VerticalResolution = DisplayMode->VActive;
Info->PixelFormat = PixelBlueGreenRedReserved8BitPerColor;
}
Info->PixelsPerScanLine = Info->HorizontalResolution;
if (Update) {
switch (Rotation) {
case 90:
This->Blt = LcdGraphicsBlt90;
break;
default:
This->Blt = LcdGraphicsBlt;
if (Rotation != 0) {
DEBUG ((DEBUG_ERROR, "%a: Unsupported rotation %u\n", __func__, Rotation));
ASSERT (FALSE);
}
break;
}
}
}
EFI_STATUS
EFIAPI
LcdGraphicsQueryMode (
@@ -753,11 +798,7 @@ LcdGraphicsQueryMode (
*SizeOfInfo = sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION);
(*Info)->Version = 0;
(*Info)->HorizontalResolution = Mode->HActive;
(*Info)->VerticalResolution = Mode->VActive;
(*Info)->PixelsPerScanLine = Mode->HActive;
(*Info)->PixelFormat = This->Mode->Info->PixelFormat;
LcdGraphicsSetModeInfo (This, *Info, Mode, FALSE);
return EFI_SUCCESS;
}
@@ -857,11 +898,9 @@ LcdGraphicsSetMode (
// Update the UEFI mode information
This->Mode->Mode = ModeNumber;
This->Mode->Info->Version = 0;
This->Mode->Info->HorizontalResolution = Mode->HActive;
This->Mode->Info->VerticalResolution = Mode->VActive;
This->Mode->Info->PixelsPerScanLine = Mode->HActive;
Instance->Mode.SizeOfInfo = sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION);
LcdGraphicsSetModeInfo (This, This->Mode->Info, Mode, TRUE);
Instance->Mode.SizeOfInfo = sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION);
This->Mode->FrameBufferBase = VramBaseAddress;
This->Mode->FrameBufferSize = VramSize;

View File

@@ -82,6 +82,21 @@ LcdGraphicsBlt (
IN UINTN Delta OPTIONAL
);
EFI_STATUS
EFIAPI
LcdGraphicsBlt90 (
IN EFI_GRAPHICS_OUTPUT_PROTOCOL *This,
IN OUT EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltBuffer OPTIONAL,
IN EFI_GRAPHICS_OUTPUT_BLT_OPERATION BltOperation,
IN UINTN SourceX,
IN UINTN SourceY,
IN UINTN DestinationX,
IN UINTN DestinationY,
IN UINTN Width,
IN UINTN Height,
IN UINTN Delta OPTIONAL
);
BOOLEAN
IsDisplayModeSupported (
IN CONNECTOR_STATE *ConnectorState,

View File

@@ -59,6 +59,7 @@
gRK3588TokenSpaceGuid.PcdDisplayConnectorsPriority
gRK3588TokenSpaceGuid.PcdDisplayForceOutput
gRK3588TokenSpaceGuid.PcdDisplayDuplicateOutput
gRK3588TokenSpaceGuid.PcdDisplayRotation
[Depex]
gEfiCpuArchProtocolGuid AND

View File

@@ -33,6 +33,7 @@ InitializeDisplayVariables (
UINT32 ConnectorsMask;
UINTN Size;
UINT8 Var8;
UINT16 Var16;
VOID *PcdData;
DISPLAY_MODE_PRESET_VARSTORE_DATA ModePreset;
DISPLAY_MODE ModeCustom;
@@ -164,6 +165,19 @@ InitializeDisplayVariables (
ASSERT_EFI_ERROR (Status);
}
Size = sizeof (Var16);
Status = !Reset ? gRT->GetVariable (
L"DisplayRotation",
&gRK3588DxeFormSetGuid,
NULL,
&Size,
&Var16
) : EFI_NOT_FOUND;
if (EFI_ERROR (Status)) {
Status = PcdSet16S (PcdDisplayRotation, FixedPcdGet16 (PcdDisplayRotationDefault));
ASSERT_EFI_ERROR (Status);
}
Size = sizeof (Var8);
Status = !Reset ? gRT->GetVariable (
L"HdmiSignalingMode",

View File

@@ -132,6 +132,8 @@
gRK3588TokenSpaceGuid.PcdDisplayForceOutput
gRK3588TokenSpaceGuid.PcdDisplayDuplicateOutputDefault
gRK3588TokenSpaceGuid.PcdDisplayDuplicateOutput
gRK3588TokenSpaceGuid.PcdDisplayRotationDefault
gRK3588TokenSpaceGuid.PcdDisplayRotation
gRK3588TokenSpaceGuid.PcdHdmiSignalingModeDefault
gRK3588TokenSpaceGuid.PcdHdmiSignalingMode

View File

@@ -91,6 +91,14 @@
#string STR_DISPLAY_DUPLICATE_OUTPUT_HELP #language en-US "Enable or disable duplication of the primary display output on other connected displays.\n"
"Note that this will use the same mode/resolution everywhere, even if it is not supported by the other displays."
#string STR_DISPLAY_ROTATION_PROMPT #language en-US "Rotation"
#string STR_DISPLAY_ROTATION_HELP #language en-US "Choose the display output rotation in degrees.\n\n"
"Note: This option only takes effect in the boot environment. If set to a value other than 0, the OS will be unable to use the UEFI GOP service and will require a native display driver."
#string STR_DISPLAY_ROTATION_0 #language en-US "0"
#string STR_DISPLAY_ROTATION_90 #language en-US "90"
#string STR_DISPLAY_ROTATION_180 #language en-US "180"
#string STR_DISPLAY_ROTATION_270 #language en-US "270"
#string STR_DISPLAY_CONNECTOR_TYPE_HDMI #language en-US "HDMI"
#string STR_HDMI_SIGNALING_MODE_PROMPT #language en-US "Signaling Mode"

View File

@@ -73,6 +73,11 @@ formset
name = DisplayDuplicateOutput,
guid = RK3588DXE_FORMSET_GUID;
efivarstore UINT16,
attribute = EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
name = DisplayRotation,
guid = RK3588DXE_FORMSET_GUID;
efivarstore UINT8,
attribute = EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
name = HdmiSignalingMode,
@@ -465,6 +470,17 @@ formset
option text = STRING_TOKEN(STR_ENABLED), value = TRUE, flags = 0;
endoneof;
subtitle text = STRING_TOKEN(STR_NULL_STRING);
oneof varid = DisplayRotation,
prompt = STRING_TOKEN(STR_DISPLAY_ROTATION_PROMPT),
help = STRING_TOKEN(STR_DISPLAY_ROTATION_HELP),
flags = NUMERIC_SIZE_2 | INTERACTIVE | RESET_REQUIRED,
default = FixedPcdGet16 (PcdDisplayRotationDefault),
option text = STRING_TOKEN(STR_DISPLAY_ROTATION_0), value = 0, flags = 0;
option text = STRING_TOKEN(STR_DISPLAY_ROTATION_90), value = 90, flags = 0;
endoneof;
suppressif (get(DisplayConnectorsMask) & (VOP_OUTPUT_IF_HDMI0 | VOP_OUTPUT_IF_HDMI1)) == 0;
subtitle text = STRING_TOKEN(STR_NULL_STRING);
subtitle text = STRING_TOKEN(STR_DISPLAY_CONNECTOR_TYPE_HDMI);

View File

@@ -91,7 +91,8 @@
}
gRK3588TokenSpaceGuid.PcdDisplayForceOutputDefault|FALSE|BOOLEAN|0x00010805
gRK3588TokenSpaceGuid.PcdDisplayDuplicateOutputDefault|FALSE|BOOLEAN|0x00010806
gRK3588TokenSpaceGuid.PcdHdmiSignalingModeDefault|0|UINT8|0x00010807
gRK3588TokenSpaceGuid.PcdDisplayRotationDefault|0|UINT16|0x00010807
gRK3588TokenSpaceGuid.PcdHdmiSignalingModeDefault|0|UINT8|0x00010808
[PcdsFixedAtBuild, PcdsPatchableInModule, PcdsDynamic, PcdsDynamicEx]
gRK3588TokenSpaceGuid.PcdCPULClusterClockPreset|0|UINT32|0x00000001
@@ -150,7 +151,8 @@
}
gRK3588TokenSpaceGuid.PcdDisplayForceOutput|FALSE|BOOLEAN|0x00000805
gRK3588TokenSpaceGuid.PcdDisplayDuplicateOutput|FALSE|BOOLEAN|0x00000806
gRK3588TokenSpaceGuid.PcdHdmiSignalingMode|0|UINT8|0x00000807
gRK3588TokenSpaceGuid.PcdDisplayRotation|0|UINT16|0x00000807
gRK3588TokenSpaceGuid.PcdHdmiSignalingMode|0|UINT8|0x00000808
[PcdsDynamicEx]
gRK3588TokenSpaceGuid.PcdPcieEcamCompliantSegmentsMask|0|UINT32|0x20000001

View File

@@ -309,6 +309,7 @@
})}
gRK3588TokenSpaceGuid.PcdDisplayForceOutputDefault|TRUE
gRK3588TokenSpaceGuid.PcdDisplayDuplicateOutputDefault|FALSE
gRK3588TokenSpaceGuid.PcdDisplayRotationDefault|0
gRK3588TokenSpaceGuid.PcdHdmiSignalingModeDefault|$(HDMI_SIGNALING_MODE_AUTO)
[PcdsPatchableInModule]
@@ -385,6 +386,7 @@
gRK3588TokenSpaceGuid.PcdDisplayConnectorsPriority|L"DisplayConnectorsPriority"|gRK3588DxeFormSetGuid|0x0|{ 0x0 }
gRK3588TokenSpaceGuid.PcdDisplayForceOutput|L"DisplayForceOutput"|gRK3588DxeFormSetGuid|0x0|gRK3588TokenSpaceGuid.PcdDisplayForceOutputDefault
gRK3588TokenSpaceGuid.PcdDisplayDuplicateOutput|L"DisplayDuplicateOutput"|gRK3588DxeFormSetGuid|0x0|gRK3588TokenSpaceGuid.PcdDisplayDuplicateOutputDefault
gRK3588TokenSpaceGuid.PcdDisplayRotation|L"DisplayRotation"|gRK3588DxeFormSetGuid|0x0|gRK3588TokenSpaceGuid.PcdDisplayRotationDefault
gRK3588TokenSpaceGuid.PcdHdmiSignalingMode|L"HdmiSignalingMode"|gRK3588DxeFormSetGuid|0x0|gRK3588TokenSpaceGuid.PcdHdmiSignalingModeDefault
################################################################################