Patrick Rudolph (siro@das-labor.org) just uploaded a new patch set to gerrit, which you can find at https://review.coreboot.org/14224
-gerrit
commit 8e4eeb51b2848f45d93663025df65b9aeadea0b8 Author: Patrick Rudolph siro@das-labor.org Date: Thu Mar 31 20:04:23 2016 +0200
device/pci_rom: Implement ACPI table VFCT
The ACPI table VFCT (VBIOS Fetch Table) is used by AMD to fetch the VBIOS.
Only fill VFCT for enabled AMD VGA devices.
Test system: * Gigabyte GA-B75M-D3H * Intel Pentium CPU G2130 * AMD Radeon HD4870
Change-Id: I3b4a587c71e7165338cad3aca77ed5afa085a63c Signed-off-by: Patrick Rudolph siro@das-labor.org --- src/arch/x86/acpi.c | 25 +++++++++++++++++ src/arch/x86/include/arch/acpi.h | 29 +++++++++++++++++++ src/device/pci_device.c | 1 + src/device/pci_rom.c | 60 ++++++++++++++++++++++++++++++++++++++++ src/include/device/pci_rom.h | 5 ++++ 5 files changed, 120 insertions(+)
diff --git a/src/arch/x86/acpi.c b/src/arch/x86/acpi.c index 5640ad0..206c4d6 100644 --- a/src/arch/x86/acpi.c +++ b/src/arch/x86/acpi.c @@ -536,6 +536,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 276ca52..eb2892c 100644 --- a/src/arch/x86/include/arch/acpi.h +++ b/src/arch/x86/include/arch/acpi.h @@ -192,6 +192,31 @@ typedef struct acpi_madt { u32 flags; /* Multiple APIC flags */ } __attribute__ ((packed)) acpi_madt_t;
+ +/* VFCT image header */ +struct acpi_vfct_image_hdr { + u32 PCIBus; //0x4C + u32 PCIDevice; //0x50 + u32 PCIFunction; //0x54 + u16 VendorID; //0x58 + u16 DeviceID; //0x5A + u16 SSVID; //0x5C + u16 SSID; //0x5E + u32 Revision; //0x60 + u32 ImageLength; //0x64 + u8 VbiosContent; // dummy - copy VBIOS here +} __attribute__ ((packed)); + +/* VFCT (VBIOS Fetch Table) */ +struct acpi_vfct { + struct acpi_table_header header; + u8 TableUUID[16]; //0x24 + u32 VBIOSImageOffset; //0x34. + u32 Lib1ImageOffset; //0x38. + u32 Reserved[4]; //0x3C + struct acpi_vfct_image_hdr image_hdr; +} __attribute__ ((packed)); + typedef struct acpi_ivrs_info { } __attribute__ ((packed)) acpi_ivrs_info_t;
@@ -565,6 +590,10 @@ 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 5f02955..b51e650 100644 --- a/src/device/pci_device.c +++ b/src/device/pci_device.c @@ -664,6 +664,7 @@ 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, + .write_acpi_tables = pci_rom_write_acpi_tables, .init = pci_dev_init, .scan_bus = 0, .enable = 0, diff --git a/src/device/pci_rom.c b/src/device/pci_rom.c index 288a5f0..0b3a6d8 100644 --- a/src/device/pci_rom.c +++ b/src/device/pci_rom.c @@ -251,3 +251,63 @@ void pci_rom_load_and_run(struct device *dev) printk(BIOS_DEBUG, "VGA Option ROM was run\n"); #endif /* CONFIG_VGA_ROM_RUN */ } + +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, *ram; + + vfct_struct->VBIOSImageOffset = (size_t)header - (size_t)vfct_struct; + + rom = pci_rom_probe(device); + if (!rom) { + printk(BIOS_DEBUG, "pci_rom_probe: %p\n", rom); + return current; + } + + ram = pci_rom_load(device, rom, (void *)&header->VbiosContent); + if (!ram) { + printk(BIOS_DEBUG, "pci_rom_load: %p\n", rom); + 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 = ram->size * 512; + + 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; + + /* only handle VGA devices */ + if ((device->class >> 8) != PCI_CLASS_DISPLAY_VGA) + return current; + + /* only handle enabled devices */ + if (!device->enabled) + 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; +} diff --git a/src/include/device/pci_rom.h b/src/include/device/pci_rom.h index 1dff9a7..ebda54c 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' ) @@ -37,6 +38,10 @@ struct rom_header *pci_rom_probe(struct device *dev); struct rom_header *pci_rom_load(struct device *dev, struct rom_header *rom_header, void *load_addr); +unsigned long +pci_rom_write_acpi_tables(struct device *device, + unsigned long current, + struct acpi_rsdp *rsdp); void pci_rom_load_and_run(struct device *dev); u32 map_oprom_vendev(u32 vendev);