summaryrefslogtreecommitdiff
path: root/src/device/pci_rom.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/device/pci_rom.c')
-rw-r--r--src/device/pci_rom.c59
1 files changed, 59 insertions, 0 deletions
diff --git a/src/device/pci_rom.c b/src/device/pci_rom.c
index a411f06acf..15b0c4c23f 100644
--- a/src/device/pci_rom.c
+++ b/src/device/pci_rom.c
@@ -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