intel_extreme: find VBT in OpRegion version 2.0 and from 2.1

we check the OpRegion version and use the rvda pointer when available.
from 2.1 the pointer is relative.

Change-Id: I64d8aea65368aa3c5597f63a2b96b6a430e04315
Reviewed-on: https://review.haiku-os.org/c/haiku/+/5109
Reviewed-by: Jérôme Duval <[email protected]>
Tested-by: Commit checker robot <[email protected]>
This commit is contained in:
Jérôme Duval
2022-03-17 07:24:11 +00:00
parent 8fed6717a7
commit d5137e7776
@@ -159,58 +159,136 @@ dumprom(void *rom, uint32 size, intel_info &info)
PROM-programmed timings info when compensation mode is off on your machine. PROM-programmed timings info when compensation mode is off on your machine.
*/ */
// outdated: https://01.org/sites/default/files/documentation/skl_opregion_rev0p5.pdf
#define ASLS 0xfc // ASL Storage. #define ASLS 0xfc // ASL Storage.
#define OPREGION_SIGNATURE "IntelGraphicsMem" #define OPREGION_SIGNATURE "IntelGraphicsMem"
#define OPREGION_ASLE_OFFSET 0x300
#define OPREGION_VBT_OFFSET 0x400
#define MBOX_ACPI (1 << 0)
#define MBOX_SWSCI (1 << 1)
#define MBOX_ASLE (1 << 2)
#define MBOX_ASLE_EXT (1 << 3)
struct opregion_header {
uint8 signature[16];
uint32 size;
uint8 reserved;
uint8 revision_version;
uint8 minor_version;
uint8 major_version;
uint8 sver[32];
uint8 vver[16];
uint8 gver[16];
uint32 mboxes;
uint32 driver_model;
uint32 platform_configuration;
uint8 gop_version[32];
uint8 rsvd[124];
} __attribute__((packed));
struct opregion_asle {
uint32 ardy;
uint32 aslc;
uint32 tche;
uint32 alsi;
uint32 bclp;
uint32 pfit;
uint32 cblv;
uint16 bclm[20];
uint32 cpfm;
uint32 epfm;
uint8 plut[74];
uint32 pfmb;
uint32 cddv;
uint32 pcft;
uint32 srot;
uint32 iuer;
uint64 fdss;
uint32 fdsp;
uint32 stat;
uint64 rvda;
uint32 rvds;
uint8 rsvd[58];
} __attribute__((packed));
static bool static bool
get_bios(int* vbtOffset) get_bios(int* vbtOffset)
{ {
intel_info &info = *gDeviceInfo[0]; STATIC_ASSERT(sizeof(opregion_header) == 0x100);
// first try to fetch Intel OpRegion which should be polulated by the BIOS at start STATIC_ASSERT(sizeof(opregion_asle) == 0x100);
uint64_t kVBIOSAddress = 0;
uint32 kVBIOSSize = 8 * 1024;
intel_info &info = *gDeviceInfo[0];
// first try to fetch Intel OpRegion which should be populated by the BIOS at start
uint32 kVBIOSSize;
for (uint32 romMethod = 0; romMethod < 2; romMethod++) {
switch(romMethod) {
case 0:
{
// get OpRegion - see Intel ACPI IGD info in acpi_igd_opregion_spec_0.pdf // get OpRegion - see Intel ACPI IGD info in acpi_igd_opregion_spec_0.pdf
kVBIOSAddress = get_pci_config(info.pci, ASLS, 4); uint64 kVBIOSAddress = get_pci_config(info.pci, ASLS, 4);
if (!kVBIOSAddress) { if (kVBIOSAddress == 0) {
TRACE((DEVICE_NAME ": ACPI OpRegion not supported!\n")); TRACE((DEVICE_NAME ": ACPI OpRegion not supported!\n"));
} else { continue;
}
kVBIOSSize = 8 * 1024;
TRACE((DEVICE_NAME ": Graphic OpRegion physical addr: 0x%" B_PRIx64 TRACE((DEVICE_NAME ": Graphic OpRegion physical addr: 0x%" B_PRIx64
"; size: 0x%" B_PRIx32 "\n", kVBIOSAddress, kVBIOSSize)); "; size: 0x%" B_PRIx32 "\n", kVBIOSAddress, kVBIOSSize));
vbios.area = map_physical_memory("ASLS mapping", kVBIOSAddress, vbios.area = map_physical_memory("ASLS mapping", kVBIOSAddress,
kVBIOSSize, B_ANY_KERNEL_ADDRESS, B_KERNEL_READ_AREA, (void **)&vbios.memory); kVBIOSSize, B_ANY_KERNEL_ADDRESS, B_KERNEL_READ_AREA, (void **)&vbios.memory);
if (vbios.area < 0)
if (vbios.area >= 0) { continue;
TRACE((DEVICE_NAME ": mapping ASLS: 0x%" B_PRIx64 " -> %p\n", TRACE((DEVICE_NAME ": mapping OpRegion: 0x%" B_PRIx64 " -> %p\n",
kVBIOSAddress, vbios.memory)); kVBIOSAddress, vbios.memory));
// check if we got the ASLS and signature // check if we got the OpRegion and signature
if (memcmp(vbios.memory, OPREGION_SIGNATURE, 16)) { if (memcmp(vbios.memory, OPREGION_SIGNATURE, 16) != 0) {
TRACE((DEVICE_NAME ": OpRegion signature mismatch\n")); TRACE((DEVICE_NAME ": OpRegion signature mismatch\n"));
delete_area(vbios.area); delete_area(vbios.area);
vbios.area = -1; vbios.area = -1;
// force using ISA legacy map as fall-back continue;
kVBIOSAddress = 0;
} }
} else { opregion_header* header = (opregion_header*)vbios.memory;
// mapping failed: force using ISA legacy map as fall-back opregion_asle* asle = (opregion_asle*)(vbios.memory + OPREGION_ASLE_OFFSET);
kVBIOSAddress = 0; if (header->major_version < 2 || (header->mboxes & MBOX_ASLE) == 0
|| asle->rvda == 0 || asle->rvds == 0) {
vbios.memory += OPREGION_VBT_OFFSET;
kVBIOSSize -= OPREGION_VBT_OFFSET;
break;
} }
uint64 rvda = asle->rvda;
kVBIOSSize = asle->rvds;
if (header->major_version > 3 || header->minor_version >= 1) {
rvda += kVBIOSAddress;
} }
TRACE((DEVICE_NAME ": RVDA physical addr: 0x%" B_PRIx64
if (!kVBIOSAddress) { "; size: 0x%" B_PRIx32 "\n", rvda, kVBIOSSize));
kVBIOSAddress = 0xc0000; delete_area(vbios.area);
vbios.area = map_physical_memory("RVDA mapping", rvda,
kVBIOSSize, B_ANY_KERNEL_ADDRESS, B_KERNEL_READ_AREA, (void **)&vbios.memory);
if (vbios.area < 0)
continue;
break;
}
case 1:
{
uint64 kVBIOSAddress = 0xc0000;
kVBIOSSize = 64 * 1024; kVBIOSSize = 64 * 1024;
/* !!!DANGER!!!: mapping of BIOS using legacy location as a fallback, /* !!!DANGER!!!: mapping of BIOS using legacy location as a fallback,
hence, if panel mode will be set using info from VBT this way, it will hence, if panel mode will be set using info from VBT this way, it will
be taken from primary card's VBIOS */ be taken from primary card's VBIOS */
vbios.area = map_physical_memory("VBIOS mapping", kVBIOSAddress, vbios.area = map_physical_memory("VBIOS mapping", kVBIOSAddress,
kVBIOSSize, B_ANY_KERNEL_ADDRESS, B_KERNEL_READ_AREA, (void**)&vbios.memory); kVBIOSSize, B_ANY_KERNEL_ADDRESS, B_KERNEL_READ_AREA, (void**)&vbios.memory);
if (vbios.area < 0) if (vbios.area < 0)
return false; continue;
TRACE((DEVICE_NAME ": mapping VBIOS: 0x%" B_PRIx64 " -> %p\n", TRACE((DEVICE_NAME ": mapping VBIOS: 0x%" B_PRIx64 " -> %p\n",
kVBIOSAddress, vbios.memory)); kVBIOSAddress, vbios.memory));
break;
}
} }
// dump ROM to file if selected in settings file // dump ROM to file if selected in settings file
@@ -222,25 +300,28 @@ get_bios(int* vbtOffset)
for (uint32 i = 0; i + 4 < kVBIOSSize; i += 4) { for (uint32 i = 0; i + 4 < kVBIOSSize; i += 4) {
if (memcmp(vbios.memory + i, "$VBT", 4) == 0) { if (memcmp(vbios.memory + i, "$VBT", 4) == 0) {
*vbtOffset = i; *vbtOffset = i;
continue; break;
} }
} }
if ((*vbtOffset + (uint32)sizeof(vbt_header)) >= kVBIOSSize) { if ((*vbtOffset + (uint32)sizeof(vbt_header)) >= kVBIOSSize) {
TRACE((DEVICE_NAME": bad VBT offset : 0x%x\n", *vbtOffset)); TRACE((DEVICE_NAME": bad VBT offset : 0x%x\n", *vbtOffset));
delete_area(vbios.area); delete_area(vbios.area);
return false; continue;
} }
struct vbt_header* vbt = (struct vbt_header*)(vbios.memory + *vbtOffset); struct vbt_header* vbt = (struct vbt_header*)(vbios.memory + *vbtOffset);
if (memcmp(vbt->signature, "$VBT", 4) != 0) { if (memcmp(vbt->signature, "$VBT", 4) != 0) {
TRACE((DEVICE_NAME": bad VBT signature: %20s\n", vbt->signature)); TRACE((DEVICE_NAME": bad VBT signature: %20s\n", vbt->signature));
delete_area(vbios.area); delete_area(vbios.area);
return false; continue;
} }
return true; return true;
} }
return false;
}
static void static void
sanitize_panel_timing(display_timing& timing) sanitize_panel_timing(display_timing& timing)