device/pci_rom: Write _ROM method for VGA devices
Write _ROM method and store PCI Option ROM in CBMEM. Allows an EFI compatible OS to retrieve the Option ROM without the need to access the PCI BAR. As the Option ROM is no longer present in the legacy VGA area it's required for mobile platforms. On hybrid devices, like Lenovo Thinkpads supporting NVIDIA Optimus it's the only way to retrieve the Option ROM, even with legacy BIOS, as there's no PCI BAR to map. Tested on: * Lenovo T530 * Linux Kernel 4.13.7 * nouveau Change-Id: I548b730fb64833083cc05af5b21dd6959804224b Signed-off-by: Patrick Rudolph <siro@das-labor.org> Reviewed-on: https://review.coreboot.org/20548 Tested-by: build bot (Jenkins) <no-reply@coreboot.org> Reviewed-by: Aaron Durbin <adurbin@chromium.org>
This commit is contained in:
@@ -744,6 +744,7 @@ struct device_operations default_pci_ops_dev = {
|
||||
.enable_resources = pci_dev_enable_resources,
|
||||
#if IS_ENABLED(CONFIG_HAVE_ACPI_TABLES)
|
||||
.write_acpi_tables = pci_rom_write_acpi_tables,
|
||||
.acpi_fill_ssdt_generator = pci_rom_ssdt,
|
||||
#endif
|
||||
.init = pci_dev_init,
|
||||
.scan_bus = 0,
|
||||
|
@@ -25,6 +25,8 @@
|
||||
#include <device/pci_ops.h>
|
||||
#include <string.h>
|
||||
#include <cbfs.h>
|
||||
#include <cbmem.h>
|
||||
#include <arch/acpigen.h>
|
||||
|
||||
/* Rmodules don't like weak symbols. */
|
||||
u32 __attribute__((weak)) map_oprom_vendev(u32 vendev) { return vendev; }
|
||||
@@ -267,4 +269,61 @@ pci_rom_write_acpi_tables(struct device *device,
|
||||
|
||||
return current;
|
||||
}
|
||||
|
||||
void pci_rom_ssdt(struct device *device)
|
||||
{
|
||||
static size_t ngfx;
|
||||
|
||||
/* Only handle VGA devices */
|
||||
if ((device->class >> 8) != PCI_CLASS_DISPLAY_VGA)
|
||||
return;
|
||||
|
||||
/* Only handle enabled devices */
|
||||
if (!device->enabled)
|
||||
return;
|
||||
|
||||
/* Probe for option rom */
|
||||
const struct rom_header *rom = pci_rom_probe(device);
|
||||
if (!rom || !rom->size) {
|
||||
printk(BIOS_WARNING, "%s: Missing PCI Option ROM\n",
|
||||
dev_path(device));
|
||||
return;
|
||||
}
|
||||
|
||||
const char *scope = acpi_device_path(device);
|
||||
if (!scope) {
|
||||
printk(BIOS_ERR, "%s: Missing ACPI scope\n", dev_path(device));
|
||||
return;
|
||||
}
|
||||
|
||||
/* Supports up to four devices. */
|
||||
if ((CBMEM_ID_ROM0 + ngfx) > CBMEM_ID_ROM3) {
|
||||
printk(BIOS_ERR, "%s: Out of CBMEM IDs.\n", dev_path(device));
|
||||
return;
|
||||
}
|
||||
|
||||
/* Prepare memory */
|
||||
const size_t cbrom_length = rom->size * 512;
|
||||
if (!cbrom_length) {
|
||||
printk(BIOS_ERR, "%s: ROM has zero length!\n",
|
||||
dev_path(device));
|
||||
return;
|
||||
}
|
||||
|
||||
void *cbrom = cbmem_add(CBMEM_ID_ROM0 + ngfx, cbrom_length);
|
||||
if (!cbrom) {
|
||||
printk(BIOS_ERR, "%s: Failed to allocate CBMEM.\n",
|
||||
dev_path(device));
|
||||
return;
|
||||
}
|
||||
/* Increment CBMEM id for next device */
|
||||
ngfx++;
|
||||
|
||||
memcpy(cbrom, rom, cbrom_length);
|
||||
|
||||
/* write _ROM method */
|
||||
acpigen_write_scope(scope);
|
||||
acpigen_write_rom(cbrom, cbrom_length);
|
||||
acpigen_pop_len(); /* pop scope */
|
||||
}
|
||||
#endif
|
||||
|
Reference in New Issue
Block a user