[SeaBIOS] (no subject)

Jason Baron jbaron at redhat.com
Thu Sep 13 22:12:16 CEST 2012


jan.kiszka at siemens.com, juzhang at redhat.com, agraf at suse.de, yamahata at valinux.co.jp, mkletzan at redhat.com, afaerber at suse.de, armbru at redhat.com, lcapitulino at redhat.com, alex.williamson at redhat.com
Message-Id: <3552c1f47b1af1abef3e4806935f19babab0ac7c.1347565443.git.jbaron at redhat.com>
In-Reply-To: <cover.1347565443.git.jbaron at redhat.com>
References: <cover.1347565443.git.jbaron at redhat.com>
Subject: [PATCH 5/9] seabios: add q35 initialization functions.

From: Isaku Yamahata <yamahata at valinux.co.jp>

add q35 initialization functions.

[jbaron at redhat.com: restructured to current seabios base]
Signed-off-by: Isaku Yamahata <yamahata at valinux.co.jp>
Signed-off-by: Jason Baron <jbaron at redhat.com>
---
 src/acpi.c    |   69 +++++++++++++++++++++++++++++++++++++++++++-
 src/dev-q35.h |   46 +++++++++++++++++++++++++++++
 src/pciinit.c |   89 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 src/shadow.c  |   13 ++++++++
 src/smm.c     |   37 +++++++++++++++++++++++
 5 files changed, 251 insertions(+), 3 deletions(-)
 create mode 100644 src/dev-q35.h

diff --git a/src/acpi.c b/src/acpi.c
index 3577c70..6cf345a 100644
--- a/src/acpi.c
+++ b/src/acpi.c
@@ -14,6 +14,7 @@
 #include "ioport.h" // inl
 #include "paravirt.h" // qemu_cfg_irq0_override
 #include "memmap.h"
+#include "dev-q35.h"
 
 /****************************************************/
 /* ACPI tables init */
@@ -261,11 +262,37 @@ static void piix4_fadt_init(struct pci_device *pci, void *arg)
                               (1 << 15));
 }
 
+/* PCI_VENDOR_ID_INTEL && PCI_DEVICE_ID_INTEL_ICH9_LPC */
+void ich9_lpc_fadt_init(struct pci_device *dev, void *arg)
+{
+    struct fadt_descriptor_rev1 *fadt = arg;
+
+    fadt->model = 1;
+    fadt->reserved1 = 0;
+    fadt->sci_int = cpu_to_le16(9);
+    fadt->smi_cmd = cpu_to_le32(PORT_SMI_CMD);
+    fadt->acpi_enable = ICH9_ACPI_ENABLE;
+    fadt->acpi_disable = ICH9_ACPI_DISABLE;
+    fadt->pm1a_evt_blk = cpu_to_le32(PORT_ACPI_PM_BASE);
+    fadt->pm1a_cnt_blk = cpu_to_le32(PORT_ACPI_PM_BASE + 0x04);
+    fadt->pm_tmr_blk = cpu_to_le32(PORT_ACPI_PM_BASE + 0x08);
+    fadt->gpe0_blk = cpu_to_le32(PORT_ACPI_PM_BASE + ICH9_PMIO_GPE0_STS);
+    fadt->pm1_evt_len = 4;
+    fadt->pm1_cnt_len = 2;
+    fadt->pm_tmr_len = 4;
+    fadt->gpe0_blk_len = ICH9_PMIO_GPE0_BLK_LEN;
+    fadt->plvl2_lat = cpu_to_le16(0xfff); // C2 state not supported
+    fadt->plvl3_lat = cpu_to_le16(0xfff); // C3 state not supported
+    /* WBINVD + PROC_C1 + SLP_BUTTON + FIX_RTC + RTC_S4 */
+    fadt->flags = cpu_to_le32((1 << 0) | (1 << 2) | (1 << 5) | (1 << 6) | (1 << 7));
+}
+
 static const struct pci_device_id fadt_init_tbl[] = {
     /* PIIX4 Power Management device (for ACPI) */
     PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_3,
                piix4_fadt_init),
-
+    PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH9_LPC,
+               ich9_lpc_fadt_init),
     PCI_DEVICE_END
 };
 
@@ -744,11 +771,49 @@ struct acpi_mcfg
     struct e820entry *e820;
 };
 
+/* PCI_VENDOR_ID_INTEL && DEVICE_ID_INTEL_Q35_MCH */
+void mch_mcfg_find(struct pci_device *dev, void *arg)
+{
+    struct acpi_mcfg *mcfg = arg;
+
+    mcfg->nr = 1;
+}
+
+/* PCI_VENDOR_ID_INTEL && DEVICE_ID_INTEL_Q35_MCH */
+void mch_mcfg_init(struct pci_device *dev, void *arg)
+{
+    u16 bdf = dev->bdf;
+
+    u64 addr = Q35_HOST_BRIDGE_PCIEXBAR_ADDR | Q35_HOST_BRIDGE_PCIEXBAREN;
+    u32 upper = addr >> 32;
+    u32 lower = addr & 0xffffffff;
+
+    /* at first disable the region. and then update/enable it. */
+    pci_config_writel(bdf, Q35_HOST_BRIDGE_PCIEXBAR, 0);
+    pci_config_writel(bdf, Q35_HOST_BRIDGE_PCIEXBAR + 4, upper);
+    pci_config_writel(bdf, Q35_HOST_BRIDGE_PCIEXBAR, lower);
+
+    struct acpi_mcfg *mcfg = arg;
+    struct acpi_mcfg_allocation *alloc = &mcfg->mcfg->allocation[0];
+    alloc->address = Q35_HOST_BRIDGE_PCIEXBAR_ADDR;
+    alloc->pci_segment = Q35_HOST_PCIE_PCI_SEGMENT;
+    alloc->start_bus_number = Q35_HOST_PCIE_START_BUS_NUMBER;
+    alloc->end_bus_number = Q35_HOST_PCIE_END_BUS_NUMBER;
+
+    mcfg->e820->start = Q35_HOST_BRIDGE_PCIEXBAR_ADDR;
+    mcfg->e820->size = Q35_HOST_BRIDGE_PCIEXBAR_SIZE;
+    mcfg->e820->type = E820_RESERVED;
+}
+
 static const struct pci_device_id mcfg_find_tbl[] = {
+    PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_Q35_MCH,
+               mch_mcfg_find),
     PCI_DEVICE_END,
 };
 
 static const struct pci_device_id mcfg_init_tbl[] = {
+    PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_Q35_MCH,
+               mch_mcfg_init),
     PCI_DEVICE_END,
 };
 
@@ -811,7 +876,7 @@ build_mcfg(void)
 static const struct pci_device_id acpi_find_tbl[] = {
     /* PIIX4 Power Management device. */
     PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_3, NULL),
-
+    PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH9_LPC, NULL),
     PCI_DEVICE_END,
 };
 
diff --git a/src/dev-q35.h b/src/dev-q35.h
new file mode 100644
index 0000000..91310b5
--- /dev/null
+++ b/src/dev-q35.h
@@ -0,0 +1,46 @@
+#ifndef __DEV_Q35_H
+#define __DEV_Q35_H
+
+#include "types.h"      // u16
+
+#define PCI_DEVICE_ID_INTEL_Q35_MCH     0x29c0
+#define  Q35_HOST_BRIDGE_PAM0           0x90
+#define  Q35_HOST_BRIDGE_SMRAM          0x9d
+#define Q35_HOST_BRIDGE_PCIEXBAR        0x60
+#define  Q35_HOST_BRIDGE_PCIEXBAR_SIZE  (256 * 1024 * 1024)
+#define  Q35_HOST_BRIDGE_PCIEXBAR_ADDR  0xe0000000
+#define  Q35_HOST_BRIDGE_PCIEXBAREN     ((u64)1)
+#define  Q35_HOST_PCIE_PCI_SEGMENT      0
+#define  Q35_HOST_PCIE_START_BUS_NUMBER 0
+#define  Q35_HOST_PCIE_END_BUS_NUMBER   255
+
+#define PCI_DEVICE_ID_INTEL_ICH9_LPC    0x2918
+#define  ICH9_LPC_PMBASE                0x40
+#define  ICH9_LPC_PMBASE_RTE            0x1
+
+#define  ICH9_LPC_ACPI_CTRL             0x44
+#define    ICH9_LPC_ACPI_CTRL_ACPI_EN   0x80
+#define  ICH9_LPC_PIRQA_ROUT            0x60
+#define  ICH9_LPC_PIRQE_ROUT            0x68
+#define   ICH9_LPC_PIRQ_ROUT_IRQEN	0x80
+#define  ICH9_LPC_PORT_ELCR1            0x4d0
+#define  ICH9_LPC_PORT_ELCR2            0x4d1
+#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
+
+/* ICH9 LPC PM I/O registers are 128 ports and 128-aligned */
+#define ICH9_PMIO_GPE0_STS              0x20
+#define  ICH9_PMIO_GPE0_BLK_LEN         0x10
+#define ICH9_PMIO_SMI_EN                0x30
+#define  ICH9_PMIO_SMI_EN_APMC_EN       (1 << 5)
+
+/* FADT ACPI_ENABLE/ACPI_DISABLE */
+#define ICH9_APM_ACPI_ENABLE            0x2
+#define ICH9_APM_ACPI_DISABLE           0x3
+
+#endif // dev-q35.h
diff --git a/src/pciinit.c b/src/pciinit.c
index 3b8525e..71256e4 100644
--- a/src/pciinit.c
+++ b/src/pciinit.c
@@ -12,6 +12,7 @@
 #include "ioport.h" // PORT_ATA1_CMD_BASE
 #include "config.h" // CONFIG_*
 #include "xen.h" // usingXen
+#include "dev-q35.h" // usingXen
 
 #define PCI_DEVICE_MEM_MIN     0x1000
 #define PCI_BRIDGE_IO_MIN      0x1000
@@ -119,12 +120,45 @@ static void piix_isa_bridge_init(struct pci_device *pci, void *arg)
     dprintf(1, "PIIX3/PIIX4 init: elcr=%02x %02x\n", elcr[0], elcr[1]);
 }
 
+/* ICH9 LPC PCI to ISA bridge */
+/* PCI_VENDOR_ID_INTEL && PCI_DEVICE_ID_INTEL_ICH9_LPC */
+void mch_isa_bridge_init(struct pci_device *dev, void *arg)
+{
+    u16 bdf = dev->bdf;
+    int i, irq;
+    u8 elcr[2];
+
+    elcr[0] = 0x00;
+    elcr[1] = 0x00;
+
+    for (i = 0; i < 4; i++) {
+        irq = pci_irqs[i];
+        /* set to trigger level */
+        elcr[irq >> 3] |= (1 << (irq & 7));
+
+        /* activate irq remapping in LPC */
+
+   /* PIRQ[A-D] routing */
+   pci_config_writeb(bdf, ICH9_LPC_PIRQA_ROUT + i,
+             irq | ICH9_LPC_PIRQ_ROUT_IRQEN);
+   /* PIRQ[E-H] routing */
+   pci_config_writeb(bdf, ICH9_LPC_PIRQE_ROUT + i,
+             irq | ICH9_LPC_PIRQ_ROUT_IRQEN);
+    }
+
+    outb(elcr[0], ICH9_LPC_PORT_ELCR1);
+    outb(elcr[1], ICH9_LPC_PORT_ELCR2);
+    dprintf(1, "Q35 LPC init: elcr=%02x %02x\n", elcr[0], elcr[1]);
+}
+
 static const struct pci_device_id pci_isa_bridge_tbl[] = {
     /* PIIX3/PIIX4 PCI to ISA bridge */
     PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371SB_0,
                piix_isa_bridge_init),
     PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_0,
                piix_isa_bridge_init),
+    PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH9_LPC,
+               mch_isa_bridge_init),
 
     PCI_DEVICE_END
 };
@@ -193,11 +227,40 @@ static void piix4_pm_init(struct pci_device *pci, void *arg)
     pci_config_writeb(bdf, 0xd2, 0x09); /* enable SMBus io space */
 }
 
+/* ICH9 LPC Power Management device (for ACPI) */
+/* PCI_VENDOR_ID_INTEL && PCI_DEVICE_ID_INTEL_ICH9_LPC */
+void ich9_lpc_pm_init(struct pci_device *dev, void *arg)
+{
+    u16 bdf = dev->bdf;
+    /* pm io base */
+    pci_config_writel(bdf, ICH9_LPC_PMBASE,
+                      PORT_ACPI_PM_BASE | ICH9_LPC_PMBASE_RTE);
+
+    /* acpi enable, SCI: IRQ9 000b = irq9*/
+    pci_config_writeb(bdf, ICH9_LPC_ACPI_CTRL, ICH9_LPC_ACPI_CTRL_ACPI_EN);
+}
+
+/* ICH9 SMBUS */
+/* PCI_VENDOR_ID_INTEL && PCI_DEVICE_ID_INTEL_ICH9_SMBUS */
+void ich9_smbus_init(struct pci_device *dev, void *arg)
+{
+    u16 bdf = dev->bdf;
+    /* map smbus into io space */
+    pci_config_writel(bdf, ICH9_SMB_SMB_BASE,
+                      PORT_SMB_BASE | PCI_BASE_ADDRESS_SPACE_IO);
+
+    /* enable SMBus */
+    pci_config_writeb(bdf, ICH9_SMB_HOSTC, ICH9_SMB_HOSTC_HST_EN);
+}
+
 static const struct pci_device_id pci_device_tbl[] = {
     /* PIIX4 Power Management device (for ACPI) */
     PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_3,
                piix4_pm_init),
-
+    PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH9_LPC,
+               ich9_lpc_pm_init),
+    PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH9_SMBUS,
+               ich9_smbus_init),
     PCI_DEVICE_END,
 };
 
@@ -647,9 +710,33 @@ void i440fx_mem_addr_init(struct pci_device *dev, void *arg)
 }
 
 
+void mch_mem_addr_init(struct pci_device *dev, void *arg)
+{
+    struct pci_mem_addr *addr = arg;
+    u64 s, e;
+
+#if BUILD_MAX_HIGHMEM != 0xe0000000
+# error "please adjust memory mapping area"
+#endif
+
+    /*
+     * BUILD_MAX_HIGHMEM == 0xe0000000
+     * [0xe000 0000, 0xf000 0000) for MCFG
+     *  4GB - 512MB, 4GB - 256MB
+     * [0xf000 0000, 0xfec0 0000) for DMI interface(subtractive decode)
+     *  4GB - 256MB, 4GB - 20MB
+     */
+    s = BUILD_MAX_HIGHMEM + 256 * 1024 * 1024;
+    e = s + 128 * 1024 * 1024 - 1;
+    *(addr->pcimem_start) = s;
+    *(addr->pcimem_end) = e;
+}
+
 static const struct pci_device_id pci_mem_addr_tbl[] = {
     PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82441,
               i440fx_mem_addr_init),
+    PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_Q35_MCH,
+               mch_mem_addr_init),
     PCI_DEVICE_END,
 };
 
diff --git a/src/shadow.c b/src/shadow.c
index 11c4d5e..a2195da 100644
--- a/src/shadow.c
+++ b/src/shadow.c
@@ -11,6 +11,7 @@
 #include "pci_ids.h" // PCI_VENDOR_ID_INTEL
 #include "pci_regs.h" // PCI_VENDOR_ID
 #include "xen.h" // usingXen
+#include "dev-q35.h" // PCI_VENDOR_ID_INTEL
 
 // On the emulators, the bios at 0xf0000 is also at 0xffff0000
 #define BIOS_SRC_OFFSET 0xfff00000
@@ -101,9 +102,16 @@ static void i440fx_bios_make_readonly(struct pci_device *pci, void *arg)
     make_bios_readonly_intel(pci->bdf, I440FX_PAM0);
 }
 
+void mch_bios_make_readonly(struct pci_device *pci, void *arg)
+{
+    make_bios_readonly_intel(pci->bdf, Q35_HOST_BRIDGE_PAM0);
+}
+
 static const struct pci_device_id dram_controller_make_readonly_tbl[] = {
     PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82441,
                i440fx_bios_make_readonly),
+    PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_Q35_MCH,
+               mch_bios_make_readonly),
     PCI_DEVICE_END
 };
 
@@ -127,6 +135,11 @@ make_bios_writable(void)
             make_bios_writable_intel(bdf, I440FX_PAM0);
             return;
         }
+        if (vendor == PCI_VENDOR_ID_INTEL
+            && device == PCI_DEVICE_ID_INTEL_Q35_MCH) {
+            make_bios_writable_intel(bdf, Q35_HOST_BRIDGE_PAM0);
+            return;
+        }
     }
     dprintf(1, "Unable to unlock ram - bridge not found\n");
 }
diff --git a/src/smm.c b/src/smm.c
index d0d1476..63fc242 100644
--- a/src/smm.c
+++ b/src/smm.c
@@ -11,6 +11,7 @@
 #include "ioport.h" // outb
 #include "pci_ids.h" // PCI_VENDOR_ID_INTEL
 #include "xen.h" // usingXen
+#include "dev-q35.h"
 
 ASM32FLAT(
     ".global smm_relocation_start\n"
@@ -137,9 +138,45 @@ static void piix4_apmc_smm_init(struct pci_device *pci, void *arg)
     pci_config_writeb(i440_pci->bdf, I440FX_SMRAM, 0x02 | 0x08);
 }
 
+/* PCI_VENDOR_ID_INTEL && PCI_DEVICE_ID_INTEL_ICH9_LPC */
+void ich9_lpc_apmc_smm_init(struct pci_device *dev, void *arg)
+{
+    struct pci_device *mch_dev;
+    int mch_bdf;
+
+    // This code is hardcoded for Q35 Power Management device.
+    mch_dev = pci_find_device(PCI_VENDOR_ID_INTEL,
+                              PCI_DEVICE_ID_INTEL_Q35_MCH);
+    mch_bdf = mch_dev->bdf;
+    
+    if (mch_bdf < 0)
+        return;
+
+    /* check if SMM init is already done */
+    u32 value = inl(PORT_ACPI_PM_BASE + ICH9_PMIO_SMI_EN);
+    if (value & ICH9_PMIO_SMI_EN_APMC_EN)
+        return;
+
+    /* enable the SMM memory window */
+    pci_config_writeb(mch_bdf, Q35_HOST_BRIDGE_SMRAM, 0x02 | 0x48);
+
+    smm_save_and_copy();
+
+    /* enable SMI generation when writing to the APMC register */
+    outl(value | ICH9_PMIO_SMI_EN_APMC_EN,
+         PORT_ACPI_PM_BASE + ICH9_PMIO_SMI_EN);
+
+    smm_relocate_and_restore();
+
+    /* close the SMM memory window and enable normal SMM */
+    pci_config_writeb(mch_bdf, Q35_HOST_BRIDGE_SMRAM, 0x02 | 0x08);
+}
+
 static const struct pci_device_id smm_init_tbl[] = {
     PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_3,
                piix4_apmc_smm_init),
+    PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH9_LPC,
+               ich9_lpc_apmc_smm_init),
 
     PCI_DEVICE_END,
 };
-- 
1.7.1




More information about the SeaBIOS mailing list