summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/commonlib/include/commonlib/cbmem_id.h10
-rw-r--r--src/device/pci_device.c1
-rw-r--r--src/device/pci_rom.c59
-rw-r--r--src/include/device/pci_rom.h2
4 files changed, 71 insertions, 1 deletions
diff --git a/src/commonlib/include/commonlib/cbmem_id.h b/src/commonlib/include/commonlib/cbmem_id.h
index 2595655b4d..9a66246001 100644
--- a/src/commonlib/include/commonlib/cbmem_id.h
+++ b/src/commonlib/include/commonlib/cbmem_id.h
@@ -71,6 +71,10 @@
#define CBMEM_ID_WIFI_CALIBRATION 0x57494649
#define CBMEM_ID_EC_HOSTEVENT 0x63ccbbc3
#define CBMEM_ID_EXT_VBT 0x69866684
+#define CBMEM_ID_ROM0 0x524f4d30
+#define CBMEM_ID_ROM1 0x524f4d31
+#define CBMEM_ID_ROM2 0x524f4d32
+#define CBMEM_ID_ROM3 0x524f4d33
#define CBMEM_ID_TO_NAME_TABLE \
{ CBMEM_ID_ACPI, "ACPI " }, \
@@ -122,5 +126,9 @@
{ CBMEM_ID_VPD, "VPD " }, \
{ CBMEM_ID_WIFI_CALIBRATION, "WIFI CLBR " }, \
{ CBMEM_ID_EC_HOSTEVENT, "EC HOSTEVENT"}, \
- { CBMEM_ID_EXT_VBT, "EXT VBT"},
+ { CBMEM_ID_EXT_VBT, "EXT VBT"}, \
+ { CBMEM_ID_ROM0, "VGA ROM #0 "}, \
+ { CBMEM_ID_ROM1, "VGA ROM #1 "}, \
+ { CBMEM_ID_ROM2, "VGA ROM #2 "}, \
+ { CBMEM_ID_ROM3, "VGA ROM #3 "},
#endif /* _CBMEM_ID_H_ */
diff --git a/src/device/pci_device.c b/src/device/pci_device.c
index ffc679facf..dbe76b54f5 100644
--- a/src/device/pci_device.c
+++ b/src/device/pci_device.c
@@ -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,
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
diff --git a/src/include/device/pci_rom.h b/src/include/device/pci_rom.h
index c5ace4c788..a4aa52aa09 100644
--- a/src/include/device/pci_rom.h
+++ b/src/include/device/pci_rom.h
@@ -43,6 +43,8 @@ pci_rom_write_acpi_tables(struct device *device,
unsigned long current,
struct acpi_rsdp *rsdp);
+void pci_rom_ssdt(struct device *device);
+
u32 map_oprom_vendev(u32 vendev);
#endif