@@ -2086,6 +2086,66 @@ 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 *dev_priv)
+{
+ u32 count, data, found, store = 0;
+ u32 static_region, oprom_offset;
+ u32 oprom_size = 0x200000;
+ u16 vbt_size;
+ u32 *vbt;
+
+ static_region = I915_READ(SPI_STATIC_REGIONS);
+ static_region &= OPTIONROM_SPI_REGIONID_MASK;
+ I915_WRITE(PRIMARY_SPI_REGIONID, static_region);
+
+ oprom_offset = I915_READ(OROM_OFFSET);
+ oprom_offset &= OROM_OFFSET_MASK;
+
+ for (count = 0; count < oprom_size; count += 4) {
+ I915_WRITE(PRIMARY_SPI_ADDRESS, oprom_offset + count);
+ data = I915_READ(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 */
+ I915_WRITE(PRIMARY_SPI_ADDRESS, found +
+ offsetof(struct vbt_header, vbt_size));
+ vbt_size = I915_READ(PRIMARY_SPI_TRIGGER);
+ vbt_size &= 0xffff;
+
+ vbt = kzalloc(vbt_size, GFP_KERNEL);
+ if (!vbt) {
+ DRM_ERROR("Unable to allocate %u bytes for VBT storage\n",
+ vbt_size);
+ goto err_not_found;
+ }
+
+ for (count = 0; count < vbt_size; count += 4) {
+ I915_WRITE(PRIMARY_SPI_ADDRESS, found + count);
+ data = I915_READ(PRIMARY_SPI_TRIGGER);
+ *(vbt + store++) = data;
+ }
+
+ if (!intel_bios_is_valid_vbt(vbt, vbt_size))
+ goto err_free_vbt;
+
+ DRM_DEBUG_KMS("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 *dev_priv)
{
struct pci_dev *pdev = dev_priv->drm.pdev;
@@ -2135,6 +2195,8 @@ static struct vbt_header *oprom_get_vbt(struct drm_i915_private *dev_priv)
pci_unmap_rom(pdev, oprom);
+ DRM_DEBUG_KMS("Found valid VBT in PCI ROM\n");
+
return vbt;
err_free_vbt:
@@ -2169,17 +2231,23 @@ void intel_bios_init(struct drm_i915_private *dev_priv)
init_vbt_defaults(dev_priv);
- /* 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(dev_priv)) {
+ oprom_vbt = spi_oprom_get_vbt(dev_priv);
+ vbt = oprom_vbt;
+ }
+
if (!vbt) {
oprom_vbt = oprom_get_vbt(dev_priv);
- if (!oprom_vbt)
- goto out;
-
vbt = oprom_vbt;
-
- drm_dbg_kms(&dev_priv->drm, "Found valid VBT in PCI ROM\n");
}
+ if (!vbt)
+ goto out;
+
bdb = get_bdb_header(vbt);
drm_dbg_kms(&dev_priv->drm,
@@ -12413,6 +12413,14 @@ enum skl_power_gate {
#define DP_PIN_ASSIGNMENT_MASK(idx) (0xf << ((idx) * 4))
#define DP_PIN_ASSIGNMENT(idx, x) ((x) << ((idx) * 4))
+#define PRIMARY_SPI_TRIGGER _MMIO(0x102040)
+#define PRIMARY_SPI_ADDRESS _MMIO(0x102080)
+#define PRIMARY_SPI_REGIONID _MMIO(0x102084)
+#define SPI_STATIC_REGIONS _MMIO(0x102090)
+#define OPTIONROM_SPI_REGIONID_MASK REG_GENMASK(7, 0)
+#define OROM_OFFSET _MMIO(0x1020c0)
+#define OROM_OFFSET_MASK REG_GENMASK(20, 16)
+
/* This register controls the Display State Buffer (DSB) engines. */
#define _DSBSL_INSTANCE_BASE 0x70B00
#define DSBSL_INSTANCE(pipe, id) (_DSBSL_INSTANCE_BASE + \