qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Qemu-devel] [PATCH 08/14] pcibos: initialize q35 chipset.


From: Isaku Yamahata
Subject: [Qemu-devel] [PATCH 08/14] pcibos: initialize q35 chipset.
Date: Wed, 30 Sep 2009 19:18:43 +0900

teach pcbios q35 chipset to initialize it properly.

Signed-off-by: Isaku Yamahata <address@hidden>
---
 rombios32.c |  296 ++++++++++++++++++++++++++++++++++++++++++++++-------------
 1 files changed, 233 insertions(+), 63 deletions(-)

diff --git a/rombios32.c b/rombios32.c
index 725f206..f7e906f 100644
--- a/rombios32.c
+++ b/rombios32.c
@@ -449,6 +449,7 @@ uint64_t ram_end;
 unsigned long ebda_cur_addr;
 #endif
 int acpi_enabled;
+uint8_t acpi_enable, acpi_disable;
 uint32_t pm_io_base, smb_io_base;
 int pm_sci_int;
 unsigned long bios_table_cur_addr;
@@ -710,6 +711,24 @@ void smp_probe(void)
 #define PCI_DEVICE_ID_INTEL_82371AB     0x7111
 #define PCI_DEVICE_ID_INTEL_82371AB_3   0x7113
 
+#define PCI_DEVICE_ID_INTEL_Q35_MCH    0x29c0
+#define  Q35_HOST_BRIDGE_PAM0           0x90
+#define  Q35_HOST_BRDIGE_SMRAM          0x9d
+
+#define PCI_DEVICE_ID_INTEL_ICH9_LPC    0x2918
+#define  ICH9_LPC_PMBASE                0x40
+#define    ICH9_PMBASE_SMI_EN           0x30
+#define    ICH9_PMBASE_SMI_EN_APMC_EN   (1 << 5)
+#define  ICH9_LPC_ACPI_CTRL             0x44
+#define    ICH9_LPC_ACPI_CTRL_ACPI_EN   0x80
+#define PCI_DEVICE_ID_INTEL_ICH9_SMBUS  0x2930
+#define  ICH9_SMB_SMB_BASE              0x20
+#define  ICH9_SMB_HOSTC                 0x40
+#define    ICH9_SMB_HOSTC_HST_EN        0x01
+
+#define ICH9_ACPI_ENABLE                0x2
+#define ICH9_ACPI_DISABLE               0x3
+
 #define PCI_VENDOR_ID_IBM               0x1014
 #define PCI_VENDOR_ID_APPLE             0x106b
 
@@ -726,6 +745,9 @@ static uint32_t pci_bios_prefmem_addr;
 /* host irqs corresponding to PCI irqs A-D */
 static uint8_t pci_irqs[4] = { 10, 10, 11, 11 };
 static PCIDevice i440_pcidev;
+static int i440_found;
+static PCIDevice mch_pcidev;
+static int mch_found;
 
 static void pci_config_writel(PCIDevice *d, uint32_t addr, uint32_t val)
 {
@@ -815,7 +837,9 @@ static void find_bios_table_area(void)
     return;
 }
 
-static void bios_shadow_init(PCIDevice *d)
+/* i440 and mch have same pam0 register format with different offset */
+static void bios_shadow_init_common(PCIDevice *d, uint32_t pam0_addr,
+                                    PCIDevice *host_bridge, int *host_found)
 {
     int v;
 
@@ -824,43 +848,62 @@ static void bios_shadow_init(PCIDevice *d)
 
     /* remap the BIOS to shadow RAM an keep it read/write while we
        are writing tables */
-    v = pci_config_readb(d, 0x59);
+    v = pci_config_readb(d, pam0_addr);
     v &= 0xcf;
-    pci_config_writeb(d, 0x59, v);
+    pci_config_writeb(d, pam0_addr, v);
     memcpy((void *)BIOS_TMP_STORAGE, (void *)0x000f0000, 0x10000);
     v |= 0x30;
-    pci_config_writeb(d, 0x59, v);
+    pci_config_writeb(d, pam0_addr, v);
     memcpy((void *)0x000f0000, (void *)BIOS_TMP_STORAGE, 0x10000);
 
-    i440_pcidev = *d;
+    *host_bridge = *d;
+    *host_found = 1;
 }
 
-static void bios_lock_shadow_ram(void)
+static void bios_lock_shadow_ram_common(PCIDevice *d, uint32_t pam0_addr)
 {
-    PCIDevice *d = &i440_pcidev;
     int v;
 
     wbinvd();
-    v = pci_config_readb(d, 0x59);
+    v = pci_config_readb(d, pam0_addr);
     v = (v & 0x0f) | (0x10);
-    pci_config_writeb(d, 0x59, v);
+    pci_config_writeb(d, pam0_addr, v);
 }
 
-static void pci_bios_init_bridges(PCIDevice *d)
+static void i440_bios_shadow_init(PCIDevice *d)
 {
-    uint16_t vendor_id, device_id;
+    bios_shadow_init_common(d, 0x59, &i440_pcidev, &i440_found);
+}
 
-    vendor_id = pci_config_readw(d, PCI_VENDOR_ID);
-    device_id = pci_config_readw(d, PCI_DEVICE_ID);
+static void i440_bios_lock_shadow_ram(PCIDevice *d)
+{
+    bios_lock_shadow_ram_common(d, 0x59);
+}
 
-    if (vendor_id == PCI_VENDOR_ID_INTEL &&
-       (device_id == PCI_DEVICE_ID_INTEL_82371SB_0 ||
-        device_id == PCI_DEVICE_ID_INTEL_82371AB_0)) {
+static void mch_bios_shadow_init(PCIDevice *d)
+{
+    bios_shadow_init_common(d, Q35_HOST_BRIDGE_PAM0, &mch_pcidev, &mch_found);
+}
+
+static void mch_bios_lock_shadow_ram(PCIDevice *d)
+{
+    bios_lock_shadow_ram_common(d, Q35_HOST_BRIDGE_PAM0);
+}
+
+static void bios_lock_shadow_ram(void)
+{
+    if (i440_found)
+        i440_bios_lock_shadow_ram(&i440_pcidev);
+    if (mch_found)
+        mch_bios_lock_shadow_ram(&mch_pcidev);
+}
+
+/* piix and ich9 have same pirq a-d register format with different offset */
+static void pci_init_isa_bridge(PCIDevice *d, uint32_t addr, const char *name)
+{
         int i, irq;
         uint8_t elcr[2];
 
-        /* PIIX3/PIIX4 PCI to ISA bridge */
-
         elcr[0] = 0x00;
         elcr[1] = 0x00;
         for(i = 0; i < 4; i++) {
@@ -868,15 +911,37 @@ static void pci_bios_init_bridges(PCIDevice *d)
             /* set to trigger level */
             elcr[irq >> 3] |= (1 << (irq & 7));
             /* activate irq remapping in PIIX */
-            pci_config_writeb(d, 0x60 + i, irq);
+            pci_config_writeb(d, addr + i, irq);
         }
         outb(0x4d0, elcr[0]);
         outb(0x4d1, elcr[1]);
-        BX_INFO("PIIX3/PIIX4 init: elcr=%02x %02x\n",
-                elcr[0], elcr[1]);
-    } else if (vendor_id == PCI_VENDOR_ID_INTEL && device_id == 
PCI_DEVICE_ID_INTEL_82441) {
+        BX_INFO("%s init: elcr=%02x %02x\n", name, elcr[0], elcr[1]);
+}
+
+static void pci_bios_init_bridges(PCIDevice *d)
+{
+    uint16_t vendor_id, device_id;
+
+    vendor_id = pci_config_readw(d, PCI_VENDOR_ID);
+    device_id = pci_config_readw(d, PCI_DEVICE_ID);
+
+    if (vendor_id == PCI_VENDOR_ID_INTEL &&
+       (device_id == PCI_DEVICE_ID_INTEL_82371SB_0 ||
+        device_id == PCI_DEVICE_ID_INTEL_82371AB_0)) {
+        /* PIIX3/PIIX4 PCI to ISA bridge */
+        pci_init_isa_bridge(d, 0x60, "PIIX3/PIIX4");
+    } else if (vendor_id == PCI_VENDOR_ID_INTEL &&
+               device_id == PCI_DEVICE_ID_INTEL_ICH9_LPC) {
+        /* ICH9 LPC PCI to ISA bridge */
+        pci_init_isa_bridge(d, 0x60, "ICH9 LPC");
+    } else if (vendor_id == PCI_VENDOR_ID_INTEL &&
+               device_id == PCI_DEVICE_ID_INTEL_82441) {
         /* i440 PCI bridge */
-        bios_shadow_init(d);
+        i440_bios_shadow_init(d);
+    } else if (vendor_id == PCI_VENDOR_ID_INTEL &&
+               device_id == PCI_DEVICE_ID_INTEL_Q35_MCH) {
+        /* ich9 PCI host bridge */
+        mch_bios_shadow_init(d);
     }
 }
 
@@ -884,46 +949,64 @@ extern uint8_t smm_relocation_start, smm_relocation_end;
 extern uint8_t smm_code_start, smm_code_end;
 
 #ifdef BX_USE_SMM
-static void smm_init(PCIDevice *d)
+/* i440 and mch have same smram format with different offset
+ * and they have same 0xb2, 0xb3 io port
+ */
+static void smm_init(PCIDevice *d,
+                     PCIDevice *host_bridge, uint32_t smram_addr,
+                     void (*apmc_en)(PCIDevice *d))
 {
-    uint32_t value;
+    /* enable the SMM memory window */
+    pci_config_writeb(host_bridge, smram_addr, 0x02 | 0x48);
 
-    /* check if SMM init is already done */
-    value = pci_config_readl(d, 0x58);
-    if ((value & (1 << 25)) == 0) {
+    /* save original memory content */
+    memcpy((void *)0xa8000, (void *)0x38000, 0x8000);
+
+    /* copy the SMM relocation code */
+    memcpy((void *)0x38000, &smm_relocation_start,
+           &smm_relocation_end - &smm_relocation_start);
 
-        /* enable the SMM memory window */
-        pci_config_writeb(&i440_pcidev, 0x72, 0x02 | 0x48);
+    /* enable SMI generation when writing to the APMC register */
+    apmc_en(d);
 
-        /* save original memory content */
-        memcpy((void *)0xa8000, (void *)0x38000, 0x8000);
+    /* init APM status port */
+    outb(0xb3, 0x01);
 
-        /* copy the SMM relocation code */
-        memcpy((void *)0x38000, &smm_relocation_start,
-               &smm_relocation_end - &smm_relocation_start);
+    /* raise an SMI interrupt */
+    outb(0xb2, 0x00);
 
-        /* enable SMI generation when writing to the APMC register */
-        pci_config_writel(d, 0x58, value | (1 << 25));
+    /* wait until SMM code executed */
+    while (inb(0xb3) != 0x00);
 
-        /* init APM status port */
-        outb(0xb3, 0x01);
+    /* restore original memory content */
+    memcpy((void *)0x38000, (void *)0xa8000, 0x8000);
 
-        /* raise an SMI interrupt */
-        outb(0xb2, 0x00);
+    /* copy the SMM code */
+    memcpy((void *)0xa8000, &smm_code_start,
+           &smm_code_end - &smm_code_start);
+    wbinvd();
 
-        /* wait until SMM code executed */
-        while (inb(0xb3) != 0x00);
+    /* close the SMM memory window and enable normal SMM */
+    pci_config_writeb(host_bridge, smram_addr, 0x02 | 0x08);
+}
+#endif
 
-        /* restore original memory content */
-        memcpy((void *)0x38000, (void *)0xa8000, 0x8000);
+#ifdef BX_USE_SMM
+static void piix_apmc_enable(PCIDevice *d)
+{
+    uint32_t value;
+    value = pci_config_readl(d, 0x58);
+    pci_config_writel(d, 0x58, value | (1 << 25));
+}
 
-        /* copy the SMM code */
-        memcpy((void *)0xa8000, &smm_code_start,
-               &smm_code_end - &smm_code_start);
-        wbinvd();
+static void piix4_smm_init(PCIDevice *d)
+{
+    uint32_t value;
 
-        /* close the SMM memory window and enable normal SMM */
-        pci_config_writeb(&i440_pcidev, 0x72, 0x02 | 0x08);
+    /* check if SMM init is already done */
+    value = pci_config_readl(d, 0x58);
+    if ((value & (1 << 25)) == 0) {
+        smm_init(d, &i440_pcidev, 0x72, &piix_apmc_enable);
     }
 }
 #endif
@@ -931,15 +1014,61 @@ static void smm_init(PCIDevice *d)
 static void piix4_pm_enable(PCIDevice *d)
 {
         /* PIIX4 Power Management device (for ACPI) */
-        pci_config_writel(d, 0x40, PM_IO_BASE | 1);
+        pci_config_writel(d, 0x40, pm_io_base | 1);
         pci_config_writeb(d, 0x80, 0x01); /* enable PM io space */
-        pci_config_writel(d, 0x90, SMB_IO_BASE | 1);
+        pci_config_writel(d, 0x90, smb_io_base | 1);
         pci_config_writeb(d, 0xd2, 0x09); /* enable SMBus io space */
 #ifdef BX_USE_SMM
-        smm_init(d);
+        piix4_smm_init(d);
 #endif
 }
 
+#ifdef BX_USE_SMM
+static void ich9_apmc_enable(PCIDevice *d)
+{
+    uint32_t value;
+    value = inl(pm_io_base + ICH9_PMBASE_SMI_EN);
+    value |= ICH9_PMBASE_SMI_EN_APMC_EN;
+    outl(pm_io_base + ICH9_PMBASE_SMI_EN, value);
+}
+
+static void ich9_smm_init(PCIDevice *d)
+{
+    uint32_t value;
+
+    /* check if SMM init is already done */
+    value = inl(pm_io_base + ICH9_PMBASE_SMI_EN);
+    if ((value & ICH9_PMBASE_SMI_EN_APMC_EN) == 0) {
+        smm_init(d, &mch_pcidev,
+                 Q35_HOST_BRDIGE_SMRAM, &ich9_apmc_enable);
+    }
+}
+#endif
+
+static void ich9_lpc_pm_enable(PCIDevice *d)
+{
+    uint8_t v;
+
+    pci_config_writel(d, ICH9_LPC_PMBASE, pm_io_base | 1);
+
+    v = pci_config_readb(d, ICH9_LPC_ACPI_CTRL);
+    v |= ICH9_LPC_ACPI_CTRL_ACPI_EN;
+    pci_config_writeb(d, ICH9_LPC_ACPI_CTRL, v);
+#ifdef BX_USE_SMM
+    ich9_smm_init(d);
+#endif
+}
+
+static void ich9_smbus_enable(PCIDevice *d)
+{
+    /* map smbus into io space */
+    pci_config_writel(d, ICH9_SMB_SMB_BASE,
+                      smb_io_base | 1 /* 1 = io space */);
+
+    /* enable SMBus */
+    pci_config_writeb(d, ICH9_SMB_HOSTC, ICH9_SMB_HOSTC_HST_EN);
+}
+
 static void pci_align_addr(uint32_t *paddr, uint32_t size)
 {
     *paddr = (*paddr + size - 1) & ~(size - 1);
@@ -1052,6 +1181,24 @@ static void pci_bios_init_device(PCIDevice *d)
         pm_sci_int = pci_config_readb(d, PCI_INTERRUPT_LINE);
         piix4_pm_enable(d);
         acpi_enabled = 1;
+        acpi_enable = 0xf1;
+        acpi_disable = 0xf0;
+    } else if (vendor_id == PCI_VENDOR_ID_INTEL &&
+               device_id == PCI_DEVICE_ID_INTEL_ICH9_LPC) {
+        pm_io_base = PM_IO_BASE;
+
+        // acpi sci defaults to 9
+        pci_config_writeb(d, ICH9_LPC_ACPI_CTRL, 0 /* 000b = irq9 */);
+        pci_config_writeb(d, PCI_INTERRUPT_LINE, 9);
+        pm_sci_int = pci_config_readb(d, PCI_INTERRUPT_LINE);
+        ich9_lpc_pm_enable(d);
+        acpi_enabled = 1;
+        acpi_enable = ICH9_ACPI_ENABLE;
+        acpi_disable = ICH9_ACPI_DISABLE;
+    } else if (vendor_id == PCI_VENDOR_ID_INTEL &&
+               device_id == PCI_DEVICE_ID_INTEL_ICH9_SMBUS) {
+        smb_io_base = SMB_IO_BASE;
+        ich9_smbus_enable(d);
     }
 }
 
@@ -1789,19 +1936,28 @@ void acpi_bios_init(void)
     fadt->model = 1;
     fadt->reserved1 = 0;
     fadt->sci_int = cpu_to_le16(pm_sci_int);
+    /* both piix4 and ich9 user io port 0xb2 = SMI_CMD_IO_ADDR, 0xb3 */
     fadt->smi_cmd = cpu_to_le32(SMI_CMD_IO_ADDR);
-    fadt->acpi_enable = 0xf1;
-    fadt->acpi_disable = 0xf0;
+    fadt->acpi_enable = acpi_enable;
+    fadt->acpi_disable = acpi_disable;
+
+    /* both piix4 and ich9 have same offset from pm_io_base and length */
     fadt->pm1a_evt_blk = cpu_to_le32(pm_io_base);
     fadt->pm1a_cnt_blk = cpu_to_le32(pm_io_base + 0x04);
     fadt->pm_tmr_blk = cpu_to_le32(pm_io_base + 0x08);
     fadt->pm1_evt_len = 4;
     fadt->pm1_cnt_len = 2;
     fadt->pm_tmr_len = 4;
+
     fadt->plvl2_lat = cpu_to_le16(0xfff); // C2 state not supported
     fadt->plvl3_lat = cpu_to_le16(0xfff); // C3 state not supported
-    fadt->gpe0_blk = cpu_to_le32(0xafe0);
-    fadt->gpe0_blk_len = 4;
+    if (i440_found) {
+        fadt->gpe0_blk = cpu_to_le32(0xafe0);
+        fadt->gpe0_blk_len = 4;
+    } else if (mch_found) {
+        fadt->gpe0_blk = cpu_to_le32(pm_io_base + 0x20);
+        fadt->gpe0_blk_len = 0x10;
+    }
     /* WBINVD + PROC_C1 + SLP_BUTTON + FIX_RTC */
     fadt->flags = cpu_to_le32((1 << 0) | (1 << 2) | (1 << 5) | (1 << 6));
     acpi_build_table_header((struct acpi_table_header *)fadt, "FACP",
@@ -2715,18 +2871,24 @@ static uint32_t find_resume_vector(void)
     return 0;
 }
 
-static void find_440fx(PCIDevice *d)
+static void find_hostbridge(PCIDevice *d)
 {
     uint16_t vendor_id, device_id;
 
     vendor_id = pci_config_readw(d, PCI_VENDOR_ID);
     device_id = pci_config_readw(d, PCI_DEVICE_ID);
 
-    if (vendor_id == PCI_VENDOR_ID_INTEL && device_id == 
PCI_DEVICE_ID_INTEL_82441)
+    if (vendor_id == PCI_VENDOR_ID_INTEL && device_id == 
PCI_DEVICE_ID_INTEL_82441) {
         i440_pcidev = *d;
+        i440_found = 1;
+    }
+    if (vendor_id == PCI_VENDOR_ID_INTEL && device_id == 
PCI_DEVICE_ID_INTEL_Q35_MCH) {
+        mch_pcidev = *d;
+        mch_found = 1;
+    }
 }
 
-static void reinit_piix4_pm(PCIDevice *d)
+static void reinit_pm(PCIDevice *d)
 {
     uint16_t vendor_id, device_id;
 
@@ -2735,6 +2897,14 @@ static void reinit_piix4_pm(PCIDevice *d)
 
     if (vendor_id == PCI_VENDOR_ID_INTEL && device_id == 
PCI_DEVICE_ID_INTEL_82371AB_3)
         piix4_pm_enable(d);
+
+    if (vendor_id == PCI_VENDOR_ID_INTEL &&
+        device_id == PCI_DEVICE_ID_INTEL_ICH9_LPC)
+        ich9_lpc_pm_enable(d);
+
+    if (vendor_id == PCI_VENDOR_ID_INTEL &&
+        device_id == PCI_DEVICE_ID_INTEL_ICH9_SMBUS)
+        ich9_smbus_enable(d);
 }
 
 void rombios32_init(uint32_t *s3_resume_vector, uint8_t *shutdown_flag)
@@ -2764,14 +2934,14 @@ void rombios32_init(uint32_t *s3_resume_vector, uint8_t 
*shutdown_flag)
 
     if (*shutdown_flag == 0xfe) {
         /* redirect bios read access to RAM */
-        pci_for_each_device(find_440fx);
+        pci_for_each_device(find_hostbridge);
         bios_lock_shadow_ram(); /* bios is already copied */
         *s3_resume_vector = find_resume_vector();
         if (!*s3_resume_vector) {
             BX_INFO("This is S3 resume but wakeup vector is NULL\n");
         } else {
             BX_INFO("S3 resume vector %p\n", *s3_resume_vector);
-            pci_for_each_device(reinit_piix4_pm);
+            pci_for_each_device(reinit_pm);
         }
         return;
     }
-- 
1.6.0.2





reply via email to

[Prev in Thread] Current Thread [Next in Thread]