Matt DeVillier has uploaded this change for review. ( https://review.coreboot.org/20394
Change subject: [WIP] drv/intel/gma/opregion: Add common init_idg_opregion() ......................................................................
[WIP] drv/intel/gma/opregion: Add common init_idg_opregion()
Add a new common method to initialize ACPI OpRegion.
Change-Id: I2378043a82bdf785df10a702afef1123662e04d9 Signed-off-by: Matt DeVillier matt.devillier@gmail.com --- M src/drivers/intel/gma/Kconfig M src/drivers/intel/gma/Makefile.inc M src/drivers/intel/gma/opregion.c M src/drivers/intel/gma/opregion.h 4 files changed, 171 insertions(+), 1 deletion(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/94/20394/1
diff --git a/src/drivers/intel/gma/Kconfig b/src/drivers/intel/gma/Kconfig index 1e60a42..c3bb8e0 100644 --- a/src/drivers/intel/gma/Kconfig +++ b/src/drivers/intel/gma/Kconfig @@ -109,3 +109,21 @@ read over the I2C interface of the coupled digital port.
endif + +config INTEL_GMA_OPREGION + def_bool n + +config ADD_VBT_DATA_FILE + bool "Add a Video Bios Table (VBT) binary to CBFS" + depends on INTEL_GMA_OPREGION + default y if INTEL_GMA_OPREGION + help + Add a VBT file data file to CBFS. The VBT describes the integrated + GPU and connections, and can be used in leiu of a VBIOS in order to + populate the ACPI OpRegion VBT data. + +config VBT_FILE + string "VBT binary path and filename" + depends on ADD_VBT_DATA_FILE + help + The path and filename of the VBT binary. diff --git a/src/drivers/intel/gma/Makefile.inc b/src/drivers/intel/gma/Makefile.inc index 50494e1..ce81d37 100644 --- a/src/drivers/intel/gma/Makefile.inc +++ b/src/drivers/intel/gma/Makefile.inc @@ -19,8 +19,11 @@ ramstage-$(CONFIG_INTEL_INT15) += int15.c endif ramstage-$(CONFIG_INTEL_GMA_ACPI) += acpi.c -ramstage-$(CONFIG_INTEL_GMA_ACPI) += opregion.c +ramstage-$(CONFIG_INTEL_GMA_OPREGION) += opregion.c
+cbfs-files-$(CONFIG_ADD_VBT_DATA_FILE) += vbt.bin +vbt.bin-file := $(call strip_quotes,$(CONFIG_VBT_FILE)) +vbt.bin-type := raw
ifeq ($(CONFIG_MAINBOARD_USE_LIBGFXINIT),y)
diff --git a/src/drivers/intel/gma/opregion.c b/src/drivers/intel/gma/opregion.c index 5cd04ae..02563d0 100644 --- a/src/drivers/intel/gma/opregion.c +++ b/src/drivers/intel/gma/opregion.c @@ -14,10 +14,15 @@ * GNU General Public License for more details. */
+#include <cbfs.h> +#include <cbmem.h> +#include <console/console.h> #include <device/device.h> #include <device/pci.h> #include <device/pci_ids.h> #include <device/pci_ops.h> +#include <string.h> +#include "intel_bios.h" #include "opregion.h"
/* Write ASLS PCI register and enables SWSCI. */ @@ -39,3 +44,145 @@ reg16 |= SMISCISEL; pci_write_config16(igd, SWSCI, reg16); } + +void * __attribute__((weak))get_fake_vbt_signature(void) +{ + return NULL; +} + +static void +generate_vbt(struct vbt_header *const head, const char *const idstr) +{ + u8 *ptr; + + memset(head, 0, sizeof (*head)); + + memset(head->signature, ' ', sizeof (head->signature)); + memcpy(head->signature, idstr, + MIN(strlen(idstr), sizeof (head->signature))); + head->version = 100; + head->header_size = sizeof (*head); + head->bdb_offset = sizeof (*head); + + struct bdb_header *const bdb_head = (struct bdb_header *)(head + 1); + memset(bdb_head, 0, sizeof (*bdb_head)); + memcpy(bdb_head->signature, "BIOS_DATA_BLOCK ", 16); + bdb_head->version = 0xa8; + bdb_head->header_size = sizeof (*bdb_head); + + ptr = (u8 *)(bdb_head + 1); + + ptr[0] = BDB_GENERAL_FEATURES; + ptr[1] = sizeof (struct bdb_general_features); + ptr[2] = sizeof (struct bdb_general_features) >> 8; + ptr += 3; + + struct bdb_general_features *const genfeat = + (struct bdb_general_features *)ptr; + memset(genfeat, 0, sizeof (*genfeat)); + genfeat->panel_fitting = 3; + genfeat->flexaim = 1; + genfeat->download_ext_vbt = 1; + genfeat->enable_ssc = IS_ENABLED(CONFIG_INTEL_GMA_SSC_ALTERNATE_REF); + genfeat->ssc_freq = IS_ENABLED(CONFIG_INTEL_GMA_SSC_ALTERNATE_REF); + genfeat->rsvd10 = 0x4; + genfeat->legacy_monitor_detect = 1; + genfeat->int_crt_support = 1; + genfeat->dp_ssc_enb = 1; + + ptr += sizeof (*genfeat); + + bdb_head->bdb_size = ptr - (u8 *)bdb_head; + head->vbt_size = ptr - (u8 *)head; + head->vbt_checksum = 0; +} + +enum cb_err +init_igd_opregion(igd_opregion_t *opregion) +{ + struct region_device vbt_rdev; + optionrom_vbt_t *vbt = NULL; + optionrom_vbt_t *ext_vbt; + uint32_t vbtsig = 0; + struct cbfsf file_desc; + int need_unmap = 0; + + /* try to locate vbt.bin in CBFS */ + if (cbfs_boot_locate(&file_desc, "vbt.bin", NULL) == CB_SUCCESS) { + cbfs_file_data(&vbt_rdev, &file_desc); + vbt = rdev_mmap_full(&vbt_rdev); + if (vbt) { + /* Validate the vbt file */ + memcpy(&vbtsig, vbt, sizeof(uint32_t)); + if (vbtsig != VBT_SIGNATURE) { + printk(BIOS_ERR, "Invalid signature in VBT data file (vbt.bin)!\n"); + rdev_munmap(&vbt_rdev, vbt); + vbt = NULL; + } + need_unmap = 1; + } else { + printk(BIOS_ERR, "VBT couldn't be read\n"); + } + } else { + printk(BIOS_NOTICE, "Could not locate a VBT file in in CBFS\n"); + } + + /* If no vbt.bin, try to load from VBIOS in CBFS */ + if (!vbt) { + optionrom_header_t *oprom = (optionrom_header_t *) pci_rom_probe(dev_find_slot(0, PCI_DEVFN(0x2,0))); + if (oprom) { + printk(BIOS_DEBUG, "VBIOS found at %p\n", oprom); + vbt = (optionrom_vbt_t *)(oprom + oprom->vbt_offset); + if (read32(vbt->hdr_signature) != VBT_SIGNATURE) { + printk(BIOS_DEBUG, "VBIOS VBT not found!\n"); + vbt = NULL; + } + } else { + printk(BIOS_DEBUG, "VBIOS not found.\n"); + } + } + + /* TODO: 3rd option - generate fake VBT */ + if (!vbt) { + optionrom_vbt_t fake_vbt; + generate_vbt((struct vbt_header *)&fake_vbt, get_fake_vbt_signature()); + vbt = &fake_vbt; + } + + /* Ensure we have something to load into opregion */ + if (!vbt) + return CB_ERR; + + memset(opregion, 0, sizeof(igd_opregion_t)); + + memcpy(&opregion->header.signature, IGD_OPREGION_SIGNATURE, + sizeof(opregion->header.signature)); + memcpy(opregion->header.vbios_version, vbt->coreblock_biosbuild, + ARRAY_SIZE(vbt->coreblock_biosbuild)); + /* Extended VBT support */ + if (vbt->hdr_vbt_size > sizeof(opregion->vbt.gvd1)) { + ext_vbt = cbmem_add(CBMEM_ID_EXT_VBT, vbt->hdr_vbt_size); + + if (ext_vbt == NULL) { + printk(BIOS_ERR, "Unable to add Ext VBT to cbmem!\n"); + rdev_munmap(&vbt_rdev, vbt); + return CB_ERR; + } + + memcpy(ext_vbt, vbt, vbt->hdr_vbt_size); + opregion->mailbox3.rvda = (uintptr_t)ext_vbt; + opregion->mailbox3.rvds = vbt->hdr_vbt_size; + } else { + /* Raw VBT size which can fit in gvd1 */ + memcpy(opregion->vbt.gvd1, vbt, vbt->hdr_vbt_size); + } + + /* 8KiB */ + opregion->header.size = sizeof(igd_opregion_t) / KiB; + opregion->header.version = (IGD_OPREGION_VERSION << 24); + + if (need_unmap) + rdev_munmap(&vbt_rdev, vbt); + + return CB_SUCCESS; +} diff --git a/src/drivers/intel/gma/opregion.h b/src/drivers/intel/gma/opregion.h index c590805..85b54f1 100644 --- a/src/drivers/intel/gma/opregion.h +++ b/src/drivers/intel/gma/opregion.h @@ -246,5 +246,7 @@ } __attribute__((packed)) optionrom_vbt_t;
void intel_gma_opregion_register(uintptr_t opregion); +void * __attribute__((weak)) get_fake_vbt_signature(void); +enum cb_err init_igd_opregion(igd_opregion_t *opregion);
#endif /* _COMMON_GMA_H_ */