QEMU emulates two common machines (Q35 and i440fx) which use mapping to
determine whether RAM is present below 1MB. In order to copy the video
BIOS to c0000 we need to flip this mapping over to RAM. This does not
happen automatically until SPL has finished running.

Switch in RAM at these address so that the video BIOS can be loaded and
run. This fix was found in the seabios code base.

Signed-off-by: Simon Glass <s...@chromium.org>
---

(no changes since v1)

 drivers/pci/pci_rom.c | 46 +++++++++++++++++++++++++++++++++++++++++++
 include/pci_ids.h     |  1 +
 2 files changed, 47 insertions(+)

diff --git a/drivers/pci/pci_rom.c b/drivers/pci/pci_rom.c
index f0dfe631490..0f44238bbbc 100644
--- a/drivers/pci/pci_rom.c
+++ b/drivers/pci/pci_rom.c
@@ -141,6 +141,49 @@ static int pci_rom_probe(struct udevice *dev, struct 
pci_rom_header **hdrp)
        return 0;
 }
 
+#define Q35_HOST_BRIDGE_PAM0   0x90
+#define I440FX_PAM0            0x59
+
+/**
+ * intel_set_writable_ram() - Set RAM to be writable
+ *
+ * This is needed for QEMU when using Q35 or I440FX emulation, since otherwise
+ * there is no RAM available at c0000
+ *
+ * See Intel 82945G/82945G/82945GC GMCH and 82945P/82945PL MCH Datasheet for
+ * information about the PAM0-PAM6 registers
+ */
+static void intel_set_writable_ram(void)
+{
+       struct udevice *dev;
+       int pam0 = -1;
+       int i;
+
+       for (pci_find_first_device(&dev); dev; pci_find_next_device(&dev)) {
+               const struct pci_child_plat *pdata = dev_get_parent_plat(dev);
+
+               if (pdata->vendor == PCI_VENDOR_ID_INTEL) {
+                       if (pdata->device == PCI_DEVICE_ID_INTEL_Q35_MCH) {
+                               pam0 = Q35_HOST_BRIDGE_PAM0;
+                               break;
+                       } else if (pdata->device == PCI_DEVICE_ID_INTEL_82441) {
+                               pam0 = I440FX_PAM0;
+                               break;
+                       }
+               }
+       }
+
+       if (!dev)
+               return;
+
+       // Adjust RAM to be writable from c0000 to f0000
+       for (i = 1; i <= 6; i++)
+               dm_pci_write_config8(dev, pam0 + i, 0x33);
+
+       // Also f0000-100000
+       dm_pci_write_config8(dev, pam0, 0x30);
+}
+
 /**
  * pci_rom_load() - Load a ROM image and return a pointer to it
  *
@@ -185,6 +228,9 @@ static int pci_rom_load(struct pci_rom_header *rom_header,
                return -ENOMEM;
        *allocedp = true;
 #endif
+       /* QEMU hacks */
+       intel_set_writable_ram();
+
        if (target != rom_header) {
                ulong start = get_timer(0);
 
diff --git a/include/pci_ids.h b/include/pci_ids.h
index 88b0a640458..856d5326411 100644
--- a/include/pci_ids.h
+++ b/include/pci_ids.h
@@ -2870,6 +2870,7 @@
 #define PCI_DEVICE_ID_INTEL_ICH9_7     0x2916
 #define PCI_DEVICE_ID_INTEL_ICH9_8     0x2918
 #define PCI_DEVICE_ID_INTEL_ICH9_AHCI  0x2922
+#define PCI_DEVICE_ID_INTEL_Q35_MCH    0x29c0
 #define PCI_DEVICE_ID_INTEL_I7_MCR     0x2c18
 #define PCI_DEVICE_ID_INTEL_I7_MC_TAD  0x2c19
 #define PCI_DEVICE_ID_INTEL_I7_MC_RAS  0x2c1a
-- 
2.40.1.521.gf1e218fcd8-goog

Reply via email to