summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/arch/x86/acpi.c25
-rw-r--r--src/arch/x86/include/arch/acpi.h29
-rw-r--r--src/device/pci_device.c3
-rw-r--r--src/device/pci_rom.c65
-rw-r--r--src/include/device/pci_rom.h7
5 files changed, 129 insertions, 0 deletions
diff --git a/src/arch/x86/acpi.c b/src/arch/x86/acpi.c
index 53c41359d6..703bfa1e9b 100644
--- a/src/arch/x86/acpi.c
+++ b/src/arch/x86/acpi.c
@@ -589,6 +589,31 @@ void acpi_create_hpet(acpi_hpet_t *hpet)
header->checksum = acpi_checksum((void *)hpet, sizeof(acpi_hpet_t));
}
+void acpi_create_vfct(struct device *device,
+ struct acpi_vfct *vfct,
+ unsigned long (*acpi_fill_vfct)(struct device *device, struct acpi_vfct *vfct_struct, unsigned long current))
+{
+ acpi_header_t *header = &(vfct->header);
+ unsigned long current = (unsigned long)vfct + sizeof(struct acpi_vfct);
+
+ memset((void *)vfct, 0, sizeof(struct acpi_vfct));
+
+ /* Fill out header fields. */
+ memcpy(header->signature, "VFCT", 4);
+ memcpy(header->oem_id, OEM_ID, 6);
+ memcpy(header->oem_table_id, ACPI_TABLE_CREATOR, 8);
+ memcpy(header->asl_compiler_id, ASLC, 4);
+
+ header->length = sizeof(struct acpi_vfct);
+ header->revision = 1; /* ACPI 1.0: N/A, ACPI 2.0/3.0/4.0: 1 */
+
+ current = acpi_fill_vfct(device, vfct, current);
+
+ /* (Re)calculate length and checksum. */
+ header->length = current - (unsigned long)vfct;
+ header->checksum = acpi_checksum((void *)vfct, header->length);
+}
+
void acpi_create_ivrs(acpi_ivrs_t *ivrs,
unsigned long (*acpi_fill_ivrs)(acpi_ivrs_t* ivrs_struct, unsigned long current))
{
diff --git a/src/arch/x86/include/arch/acpi.h b/src/arch/x86/include/arch/acpi.h
index 6854573d8c..9dfbe2f6c0 100644
--- a/src/arch/x86/include/arch/acpi.h
+++ b/src/arch/x86/include/arch/acpi.h
@@ -220,6 +220,30 @@ typedef struct acpi_madt {
u32 flags; /* Multiple APIC flags */
} __attribute__ ((packed)) acpi_madt_t;
+/* VFCT image header */
+struct acpi_vfct_image_hdr {
+ u32 PCIBus;
+ u32 PCIDevice;
+ u32 PCIFunction;
+ u16 VendorID;
+ u16 DeviceID;
+ u16 SSVID;
+ u16 SSID;
+ u32 Revision;
+ u32 ImageLength;
+ u8 VbiosContent; // dummy - copy VBIOS here
+} __attribute__ ((packed));
+
+/* VFCT (VBIOS Fetch Table) */
+struct acpi_vfct {
+ struct acpi_table_header header;
+ u8 TableUUID[16];
+ u32 VBIOSImageOffset;
+ u32 Lib1ImageOffset;
+ u32 Reserved[4];
+ struct acpi_vfct_image_hdr image_hdr;
+} __attribute__ ((packed));
+
typedef struct acpi_ivrs_info {
} __attribute__ ((packed)) acpi_ivrs_info_t;
@@ -601,6 +625,11 @@ void acpi_create_srat(acpi_srat_t *srat,
void acpi_create_slit(acpi_slit_t *slit,
unsigned long (*acpi_fill_slit)(unsigned long current));
+void acpi_create_vfct(struct device *device,
+ struct acpi_vfct *vfct,
+ unsigned long (*acpi_fill_vfct)(struct device *device,
+ struct acpi_vfct *vfct_struct, unsigned long current));
+
void acpi_create_ivrs(acpi_ivrs_t *ivrs,
unsigned long (*acpi_fill_ivrs)(acpi_ivrs_t* ivrs_struct, unsigned long current));
diff --git a/src/device/pci_device.c b/src/device/pci_device.c
index 06294d00c7..b2e3c9ac64 100644
--- a/src/device/pci_device.c
+++ b/src/device/pci_device.c
@@ -735,6 +735,9 @@ struct device_operations default_pci_ops_dev = {
.read_resources = pci_dev_read_resources,
.set_resources = pci_dev_set_resources,
.enable_resources = pci_dev_enable_resources,
+#if IS_ENABLED(CONFIG_HAVE_ACPI_TABLES)
+ .write_acpi_tables = pci_rom_write_acpi_tables,
+#endif
.init = pci_dev_init,
.scan_bus = 0,
.enable = 0,
diff --git a/src/device/pci_rom.c b/src/device/pci_rom.c
index 8366fea357..20621d36b2 100644
--- a/src/device/pci_rom.c
+++ b/src/device/pci_rom.c
@@ -169,3 +169,68 @@ struct rom_header *pci_rom_load(struct device *dev,
pci_ram_image_start += rom_size;
return (struct rom_header *) (pci_ram_image_start-rom_size);
}
+
+/* ACPI */
+#if IS_ENABLED(CONFIG_HAVE_ACPI_TABLES)
+static unsigned long
+pci_rom_acpi_fill_vfct(struct device *device,
+ struct acpi_vfct *vfct_struct,
+ unsigned long current)
+{
+ struct acpi_vfct_image_hdr *header = &vfct_struct->image_hdr;
+ struct rom_header *rom;
+
+ vfct_struct->VBIOSImageOffset = (size_t)header - (size_t)vfct_struct;
+
+ rom = pci_rom_probe(device);
+ if (!rom) {
+ printk(BIOS_ERR, "pci_rom_acpi_fill_vfct failed\n");
+ return current;
+ }
+
+ header->DeviceID = device->device;
+ header->VendorID = device->vendor;
+ header->PCIBus = device->bus->secondary;
+ header->PCIFunction = PCI_FUNC(device->path.pci.devfn);
+ header->PCIDevice = PCI_SLOT(device->path.pci.devfn);
+ header->ImageLength = rom->size * 512;
+ memcpy((void *)&header->VbiosContent, rom, header->ImageLength);
+
+ current += header->ImageLength;
+ return current;
+}
+
+unsigned long
+pci_rom_write_acpi_tables(struct device *device,
+ unsigned long current,
+ struct acpi_rsdp *rsdp)
+{
+ struct acpi_vfct *vfct;
+ struct rom_header *rom;
+
+ /* Only handle VGA devices */
+ if ((device->class >> 8) != PCI_CLASS_DISPLAY_VGA)
+ return current;
+
+ /* Only handle enabled devices */
+ if (!device->enabled)
+ return current;
+
+ /* Probe for option rom */
+ rom = pci_rom_probe(device);
+ if (!rom)
+ return current;
+
+ /* AMD/ATI uses VFCT */
+ if (device->vendor == PCI_VENDOR_ID_ATI) {
+ current = ALIGN(current, 8);
+ printk(BIOS_DEBUG, "ACPI: * VFCT at %lx\n", current);
+ vfct = (struct acpi_vfct *)current;
+ acpi_create_vfct(device, vfct, pci_rom_acpi_fill_vfct);
+ current += vfct->header.length;
+ acpi_add_table(rsdp, vfct);
+ }
+
+ return current;
+}
+#endif
diff --git a/src/include/device/pci_rom.h b/src/include/device/pci_rom.h
index 2fb2f7a8d5..3f09778e4b 100644
--- a/src/include/device/pci_rom.h
+++ b/src/include/device/pci_rom.h
@@ -2,6 +2,7 @@
#define PCI_ROM_H
#include <endian.h>
#include <stddef.h>
+#include <arch/acpi.h>
#define PCI_ROM_HDR 0xAA55
#define PCI_DATA_HDR (uint32_t) ( ('R' << 24) | ('I' << 16) | ('C' << 8) | 'P' )
@@ -35,6 +36,12 @@ struct pci_data {
struct rom_header *pci_rom_probe(struct device *dev);
struct rom_header *pci_rom_load(struct device *dev, struct rom_header *rom_header);
+
+unsigned long
+pci_rom_write_acpi_tables(struct device *device,
+ unsigned long current,
+ struct acpi_rsdp *rsdp);
+
u32 map_oprom_vendev(u32 vendev);
#endif