OvmfPkg/QemuVideoDxe: parse edid blob, detect display resolution

Check whenever an EDID blob is present.  In case it is get the display
resolution from it.  Unless PcdVideoResolutionSource indicates the
display resolution has been set already, update
PcdVideoHorizontalResolution and PcdVideoVerticalResolution accordingly.
Also add the resolution to the mode list.

This will make OVMF boot up with the display resolution configured by
QEMU, which is 1280x800 by default.  The resolution can be set using the
xres and yres properties.  Here is an example for FullHD:

qemu-system-x86_64 -device VGA,xres=1920,yres=1080

Ref: https://bugzilla.tianocore.org/show_bug.cgi?id=3778
Ref: https://bugzilla.redhat.com/show_bug.cgi?id=1749250
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
Acked-by: Ard Biesheuvel <ardb@kernel.org>
This commit is contained in:
Gerd Hoffmann 2022-01-17 10:58:17 +01:00 committed by mergify[bot]
parent 55c05427b9
commit 49a2d8cbf5
3 changed files with 105 additions and 2 deletions

View File

@ -284,6 +284,88 @@ QemuVideoBochsAddMode (
Private->MaxMode++;
}
STATIC
VOID
QemuVideoBochsEdid (
QEMU_VIDEO_PRIVATE_DATA *Private,
UINT32 *XRes,
UINT32 *YRes
)
{
EFI_STATUS Status;
if (Private->Variant != QEMU_VIDEO_BOCHS_MMIO) {
return;
}
Status = Private->PciIo->Mem.Read (
Private->PciIo,
EfiPciIoWidthUint8,
PCI_BAR_IDX2,
0,
sizeof (Private->Edid),
Private->Edid
);
if (Status != EFI_SUCCESS) {
DEBUG ((
DEBUG_INFO,
"%a: mmio read failed\n",
__FUNCTION__
));
return;
}
if ((Private->Edid[0] != 0x00) ||
(Private->Edid[1] != 0xff))
{
DEBUG ((
DEBUG_INFO,
"%a: magic check failed\n",
__FUNCTION__
));
return;
}
DEBUG ((
DEBUG_INFO,
"%a: blob found (extensions: %d)\n",
__FUNCTION__,
Private->Edid[126]
));
if ((Private->Edid[54] == 0x00) &&
(Private->Edid[55] == 0x00))
{
DEBUG ((
DEBUG_INFO,
"%a: no detailed timing descriptor\n",
__FUNCTION__
));
return;
}
*XRes = Private->Edid[56] | ((Private->Edid[58] & 0xf0) << 4);
*YRes = Private->Edid[59] | ((Private->Edid[61] & 0xf0) << 4);
DEBUG ((
DEBUG_INFO,
"%a: default resolution: %dx%d\n",
__FUNCTION__,
*XRes,
*YRes
));
if (PcdGet8 (PcdVideoResolutionSource) == 0) {
Status = PcdSet32S (PcdVideoHorizontalResolution, *XRes);
ASSERT_RETURN_ERROR (Status);
Status = PcdSet32S (PcdVideoVerticalResolution, *YRes);
ASSERT_RETURN_ERROR (Status);
Status = PcdSet8S (PcdVideoResolutionSource, 2);
ASSERT_RETURN_ERROR (Status);
}
// TODO: register edid as gEfiEdidDiscoveredProtocolGuid ?
}
EFI_STATUS
QemuVideoBochsModeSetup (
QEMU_VIDEO_PRIVATE_DATA *Private,
@ -291,7 +373,7 @@ QemuVideoBochsModeSetup (
)
{
UINT32 AvailableFbSize;
UINT32 Index;
UINT32 Index, XRes = 0, YRes = 0;
//
// Fetch the available framebuffer size.
@ -374,13 +456,29 @@ QemuVideoBochsModeSetup (
// Setup Video Modes
//
Private->ModeData = AllocatePool (
sizeof (Private->ModeData[0]) * QEMU_VIDEO_BOCHS_MODE_COUNT
sizeof (Private->ModeData[0]) * (QEMU_VIDEO_BOCHS_MODE_COUNT+1)
);
if (Private->ModeData == NULL) {
return EFI_OUT_OF_RESOURCES;
}
QemuVideoBochsEdid (Private, &XRes, &YRes);
if (XRes && YRes) {
QemuVideoBochsAddMode (
Private,
AvailableFbSize,
XRes,
YRes
);
}
for (Index = 0; Index < QEMU_VIDEO_BOCHS_MODE_COUNT; Index++) {
if ((QemuVideoBochsModes[Index].Width == XRes) &&
(QemuVideoBochsModes[Index].Height == YRes))
{
continue; // duplicate with edid resolution
}
QemuVideoBochsAddMode (
Private,
AvailableFbSize,

View File

@ -115,6 +115,8 @@ typedef struct {
FRAME_BUFFER_CONFIGURE *FrameBufferBltConfigure;
UINTN FrameBufferBltConfigureSize;
UINT8 FrameBufferVramBarIndex;
UINT8 Edid[128];
} QEMU_VIDEO_PRIVATE_DATA;
///

View File

@ -63,4 +63,7 @@
[Pcd]
gUefiOvmfPkgTokenSpaceGuid.PcdOvmfHostBridgePciDevId
gUefiOvmfPkgTokenSpaceGuid.PcdVideoResolutionSource
gEfiMdeModulePkgTokenSpaceGuid.PcdNullPointerDetectionPropertyMask
gEfiMdeModulePkgTokenSpaceGuid.PcdVideoHorizontalResolution
gEfiMdeModulePkgTokenSpaceGuid.PcdVideoVerticalResolution