diff options
Diffstat (limited to 'drivers/gpu/drm/i915/display/intel_bios.c')
-rw-r--r-- | drivers/gpu/drm/i915/display/intel_bios.c | 77 |
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; |