summaryrefslogtreecommitdiff
path: root/drivers/gpu/drm/i915/display/intel_bios.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/i915/display/intel_bios.c')
-rw-r--r--drivers/gpu/drm/i915/display/intel_bios.c77
1 files changed, 71 insertions, 6 deletions
diff --git a/drivers/gpu/drm/i915/display/intel_bios.c b/drivers/gpu/drm/i915/display/intel_bios.c
index 9d989c9f5da4..c7a8d517ce81 100644
--- a/drivers/gpu/drm/i915/display/intel_bios.c
+++ b/drivers/gpu/drm/i915/display/intel_bios.c
@@ -2335,6 +2335,63 @@ bool intel_bios_is_valid_vbt(const void *buf, size_t size)
return vbt;
}
+static struct vbt_header *spi_oprom_get_vbt(struct drm_i915_private *i915)
+{
+ u32 count, data, found, store = 0;
+ u32 static_region, oprom_offset;
+ u32 oprom_size = 0x200000;
+ u16 vbt_size;
+ u32 *vbt;
+
+ static_region = intel_uncore_read(&i915->uncore, SPI_STATIC_REGIONS);
+ static_region &= OPTIONROM_SPI_REGIONID_MASK;
+ intel_uncore_write(&i915->uncore, PRIMARY_SPI_REGIONID, static_region);
+
+ oprom_offset = intel_uncore_read(&i915->uncore, OROM_OFFSET);
+ oprom_offset &= OROM_OFFSET_MASK;
+
+ for (count = 0; count < oprom_size; count += 4) {
+ intel_uncore_write(&i915->uncore, PRIMARY_SPI_ADDRESS, oprom_offset + count);
+ data = intel_uncore_read(&i915->uncore, PRIMARY_SPI_TRIGGER);
+
+ if (data == *((const u32 *)"$VBT")) {
+ found = oprom_offset + count;
+ break;
+ }
+ }
+
+ if (count >= oprom_size)
+ goto err_not_found;
+
+ /* Get VBT size and allocate space for the VBT */
+ intel_uncore_write(&i915->uncore, PRIMARY_SPI_ADDRESS, found +
+ offsetof(struct vbt_header, vbt_size));
+ vbt_size = intel_uncore_read(&i915->uncore, PRIMARY_SPI_TRIGGER);
+ vbt_size &= 0xffff;
+
+ vbt = kzalloc(round_up(vbt_size, 4), GFP_KERNEL);
+ if (!vbt)
+ goto err_not_found;
+
+ for (count = 0; count < vbt_size; count += 4) {
+ intel_uncore_write(&i915->uncore, PRIMARY_SPI_ADDRESS, found + count);
+ data = intel_uncore_read(&i915->uncore, PRIMARY_SPI_TRIGGER);
+ *(vbt + store++) = data;
+ }
+
+ if (!intel_bios_is_valid_vbt(vbt, vbt_size))
+ goto err_free_vbt;
+
+ drm_dbg_kms(&i915->drm, "Found valid VBT in SPI flash\n");
+
+ return (struct vbt_header *)vbt;
+
+err_free_vbt:
+ kfree(vbt);
+err_not_found:
+ return NULL;
+}
+
static struct vbt_header *oprom_get_vbt(struct drm_i915_private *i915)
{
struct pci_dev *pdev = to_pci_dev(i915->drm.dev);
@@ -2384,6 +2441,8 @@ static struct vbt_header *oprom_get_vbt(struct drm_i915_private *i915)
pci_unmap_rom(pdev, oprom);
+ drm_dbg_kms(&i915->drm, "Found valid VBT in PCI ROM\n");
+
return vbt;
err_free_vbt:
@@ -2418,17 +2477,23 @@ void intel_bios_init(struct drm_i915_private *i915)
init_vbt_defaults(i915);
- /* If the OpRegion does not have VBT, look in PCI ROM. */
+ /*
+ * If the OpRegion does not have VBT, look in SPI flash through MMIO or
+ * PCI mapping
+ */
+ if (!vbt && IS_DGFX(i915)) {
+ oprom_vbt = spi_oprom_get_vbt(i915);
+ vbt = oprom_vbt;
+ }
+
if (!vbt) {
oprom_vbt = oprom_get_vbt(i915);
- if (!oprom_vbt)
- goto out;
-
vbt = oprom_vbt;
-
- drm_dbg_kms(&i915->drm, "Found valid VBT in PCI ROM\n");
}
+ if (!vbt)
+ goto out;
+
bdb = get_bdb_header(vbt);
i915->vbt.version = bdb->version;