summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorRocky Phagura <rphagura@fb.com>2020-06-11 11:18:02 -0700
committerPatrick Georgi <pgeorgi@google.com>2020-09-21 08:06:23 +0000
commitcced3469c54a778cfe3b1675a7f6c45beab9ab91 (patch)
tree432ac1a95ad3fe279de8e351c111dece481081d8 /src
parentbb25c59e90110f601291a281a5df8a70714399dc (diff)
downloadcoreboot-cced3469c54a778cfe3b1675a7f6c45beab9ab91.tar.xz
soc/intel/xeon_sp: Enable PMC support
PMC support was not enabled on Xeon_sp platforms. This involves turning on SOC_INTEL_COMMON_BLOCK_PMC and then adding the proper hooks in SOC specific code. This patch leverages code from the Skylake project and adds the bare minimum hooks to leverage PMC common code. Most importantly this enables power management registers located in the PMC device (under ACPI_BASE_ADDRESS). Access to this device is also needed for SMM setup and handling. TEST=build for Tiogapass and enable the following Kconfig options: select SOC_INTEL_COMMON_BLOCK_PMC select ACPI_INTEL_HARDWARE_SLEEP_VALUES select CPU_INTEL_COMMON_SMM Boot the system and ensure pmbase is programmed. (Look for pmbase in debug messages). Secondly check that SMIs are enabled by looking at the debug messages (search for "Enabling SMIs") and verifying in HW by reading IO port 0x530. Change-Id: I6d57a8282a8b6dc4314f156c39deb09535575cbd Signed-off-by: Rocky Phagura <rphagura@fb.com> Reviewed-on: https://review.coreboot.org/c/coreboot/+/42289 Tested-by: build bot (Jenkins) <no-reply@coreboot.org> Reviewed-by: Angel Pons <th3fanbus@gmail.com> Reviewed-by: Marc Jones <marc@marcjonesconsulting.com>
Diffstat (limited to 'src')
-rw-r--r--src/soc/intel/xeon_sp/Makefile.inc1
-rw-r--r--src/soc/intel/xeon_sp/include/soc/gpe.h11
-rw-r--r--src/soc/intel/xeon_sp/include/soc/iomap.h5
-rw-r--r--src/soc/intel/xeon_sp/include/soc/pm.h100
-rw-r--r--src/soc/intel/xeon_sp/include/soc/pmc.h12
-rw-r--r--src/soc/intel/xeon_sp/pmc.c195
-rw-r--r--src/soc/intel/xeon_sp/skx/chip.h1
7 files changed, 319 insertions, 6 deletions
diff --git a/src/soc/intel/xeon_sp/Makefile.inc b/src/soc/intel/xeon_sp/Makefile.inc
index 94c1764659..3bbf6b725e 100644
--- a/src/soc/intel/xeon_sp/Makefile.inc
+++ b/src/soc/intel/xeon_sp/Makefile.inc
@@ -8,6 +8,7 @@ subdirs-$(CONFIG_SOC_INTEL_COOPERLAKE_SP) += cpx
bootblock-y += bootblock.c spi.c lpc.c gpio.c pch.c
romstage-y += romstage.c reset.c util.c spi.c gpio.c pmutil.c
ramstage-y += uncore.c reset.c util.c lpc.c spi.c gpio.c
+ramstage-$(CONFIG_SOC_INTEL_COMMON_BLOCK_PMC) += pmc.c
postcar-y += spi.c
CPPFLAGS_common += -I$(src)/soc/intel/xeon_sp/include
diff --git a/src/soc/intel/xeon_sp/include/soc/gpe.h b/src/soc/intel/xeon_sp/include/soc/gpe.h
new file mode 100644
index 0000000000..c4acf1c1f3
--- /dev/null
+++ b/src/soc/intel/xeon_sp/include/soc/gpe.h
@@ -0,0 +1,11 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#ifndef _SOC_GPE_H_
+#define _SOC_GPE_H_
+
+/* GPE_31_0 */
+#define GPE0_DW0_00 0
+#define GPE0_DW0_01 1
+#define GPE0_DW0_02 2
+#define GPE_MAX GPE0_DW0_02
+#endif /* _SOC_GPE_H_ */
diff --git a/src/soc/intel/xeon_sp/include/soc/iomap.h b/src/soc/intel/xeon_sp/include/soc/iomap.h
index 68f6f558ae..f23f0ec9ae 100644
--- a/src/soc/intel/xeon_sp/include/soc/iomap.h
+++ b/src/soc/intel/xeon_sp/include/soc/iomap.h
@@ -19,7 +19,9 @@
#define SPI_BASE_ADDRESS 0xfe010000
#define SPI_BASE_SIZE 0x1000
+#define TCO_BASE_ADDRESS 0x400
#define ACPI_BASE_ADDRESS 0x500
+#define ACPI_BASE_SIZE 0x100
/* Video RAM */
#define VGA_BASE_ADDRESS 0xa0000
@@ -28,6 +30,9 @@
/* High Performance Event Timer */
#define HPET_BASE_ADDRESS 0xfed00000
+#define PCH_PWRM_BASE_ADDRESS 0xfe000000
+#define PCH_PWRM_BASE_SIZE 0x10000
+
#define P2SB_BAR CONFIG_PCR_BASE_ADDRESS
#endif /* _SOC_IOMAP_H_ */
diff --git a/src/soc/intel/xeon_sp/include/soc/pm.h b/src/soc/intel/xeon_sp/include/soc/pm.h
index c4c1a885bc..f5a45c6106 100644
--- a/src/soc/intel/xeon_sp/include/soc/pm.h
+++ b/src/soc/intel/xeon_sp/include/soc/pm.h
@@ -3,15 +3,103 @@
#ifndef _SOC_PM_H_
#define _SOC_PM_H_
+#include <acpi/acpi.h>
+#include <soc/gpe.h>
#include <soc/iomap.h>
#include <soc/pmc.h>
-#define PM1_CNT 0x04
-#define PM1_STS 0x00
-#define PM1_TMR 0x08
-#define PM2_CNT 0x50
+/* ACPI_BASE_ADDRESS / PMBASE */
+#define PM1_STS 0x00
+#define WAK_STS (1 << 15)
+#define PCIEXPWAK_STS (1 << 14)
+#define PRBTNOR_STS (1 << 11)
+#define RTC_STS (1 << 10)
+#define PWRBTN_STS (1 << 8)
+#define GBL_STS (1 << 5)
+#define PM1_EN 0x02
+#define RTC_EN (1 << 10)
+#define PWRBTN_EN (1 << 8)
+#define GBL_EN (1 << 5)
+#define TMROF_EN (1 << 0)
+#define PM1_CNT 0x04
+#define GBL_RLS (1 << 2)
+#define SCI_EN (1 << 0)
+#define PM1_TMR 0x08
+#define SMI_EN 0x30
+#define ESPI_SMI_EN (1 << 28)
+#define PERIODIC_EN (1 << 14)
+#define TCO_SMI_EN (1 << 13)
+#define APMC_EN (1 << 5)
+#define SLP_SMI_EN (1 << 4)
+#define BIOS_EN (1 << 2)
+#define EOS (1 << 1)
+#define GBL_SMI_EN (1 << 0)
+#define SMI_STS 0x34
+#define SMI_STS_BITS 32
+#define GPIO_UNLOCK_SMI_STS_BIT 27
+#define PERIODIC_STS_BIT 14
+#define TCO_STS_BIT 13
+#define PM1_STS_BIT 8
+#define APM_STS_BIT 5
+#define SMI_ON_SLP_EN_STS_BIT 4
+#define BIOS_STS_BIT 2
+#define GPE_CNTL 0x42
+#define SWGPE_CTRL (1 << 1)
+#define DEVACT_STS 0x44
+#define PM2_CNT 0x50
+#define GPE0_REG_MAX 4
+#define GPE0_REG_SIZE 32
+#define GPE0_STS(x) (0x80 + (x * 4))
+#define GPE0_EN(x) (0x90 + (x * 4))
+#define GPE_STD 3 /* 0x8c/0x9c = Standard GPE */
+#define GPE_STS_RSVD GPE_STD
+#define GPIO_T2_STS (1 << 15)
+#define PME_B0_STS (1 << 13)
+#define PME_STS (1 << 11)
+#define PCI_EXP_STS (1 << 9)
+#define SMB_WAK_STS (1 << 7)
+#define TCOSCI_STS (1 << 6)
+#define GPE0_EN(x) (0x90 + (x * 4))
+#define GPIO_T2_EN (1 << 15)
+#define ESPI_EN (1 << 14)
+#define PME_B0_EN (1 << 13)
+#define PME_EN (1 << 11)
+#define PCI_EXP_EN (1 << 9)
+#define TCOSCI_EN (1 << 6)
-#define GPE0_REG_MAX 4
-#define GPE0_STS(x) (0x80 + (x * 4))
+#define ENABLE_SMI_PARAMS \
+ (APMC_EN | GBL_SMI_EN | EOS)
+
+/* This is defined as ETR3 in EDS. We named it as ETR here for consistency */
+#define ETR 0xac
+#define CF9_LOCK (1 << 31)
+#define CF9_GLB_RST (1 << 20)
+
+#define PRSTS 0x10
+
+struct chipset_power_state {
+ uint16_t pm1_sts;
+ uint16_t pm1_en;
+ uint32_t pm1_cnt;
+ uint16_t tco1_sts;
+ uint16_t tco2_sts;
+ uint32_t gpe0_sts[4];
+ uint32_t gpe0_en[4];
+ uint32_t gen_pmcon_a;
+ uint32_t gen_pmcon_b;
+ uint32_t gblrst_cause[2];
+ uint32_t prev_sleep_state;
+} __packed;
+
+/* Get base address PMC memory mapped registers. */
+uint8_t *pmc_mmio_regs(void);
+
+/* Set the DISB after DRAM init */
+void pmc_set_disb(void);
+
+/* Return non-zero when RTC failure happened. */
+int rtc_failure(void);
+
+uint16_t get_pmbase(void);
#endif
diff --git a/src/soc/intel/xeon_sp/include/soc/pmc.h b/src/soc/intel/xeon_sp/include/soc/pmc.h
index 49e58d366a..40b41c7d59 100644
--- a/src/soc/intel/xeon_sp/include/soc/pmc.h
+++ b/src/soc/intel/xeon_sp/include/soc/pmc.h
@@ -21,10 +21,22 @@
#define SCIS_IRQ23 7
#define PWRMBASE 0x48
#define GEN_PMCON_A 0xa0
+#define DISB (1 << 23)
+#define GBL_RST_STS (1 << 16)
#define SMI_LOCK (1 << 4)
#define GEN_PMCON_B 0xa4
#define SLP_STR_POL_LOCK (1 << 18)
#define ACPI_BASE_LOCK (1 << 17)
#define RTC_BATTERY_DEAD (1 << 2)
+#define SUS_PWR_FLR (1 << 14)
+#define HOST_RST_STS (1 << 9)
+#define PWR_FLR (1 << 1)
+#define SLEEP_AFTER_POWER_FAIL (1 << 0)
+/* Memory mapped IO registers in PMC */
+#define GPIO_GPE_CFG 0x120
+#define GPE0_DWX_MASK 0xf
+#define GPE0_DW_SHIFT(x) (4 * (x))
+#define GBLRST_CAUSE0 0x124
+#define GBLRST_CAUSE1 0x128
#endif
diff --git a/src/soc/intel/xeon_sp/pmc.c b/src/soc/intel/xeon_sp/pmc.c
new file mode 100644
index 0000000000..a418ae5bab
--- /dev/null
+++ b/src/soc/intel/xeon_sp/pmc.c
@@ -0,0 +1,195 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#include "chip.h"
+#include <console/console.h>
+#include <device/device.h>
+#include <device/pci_ops.h>
+#include <intelblocks/pmc.h>
+#include <intelblocks/pmclib.h>
+#include <intelblocks/rtc.h>
+#include <reg_script.h>
+#include <soc/pci_devs.h>
+#include <soc/pm.h>
+
+/*
+ * Set which power state system will be after reapplying
+ * the power (from G3 State)
+ */
+void pmc_soc_set_afterg3_en(const bool on)
+{
+ uint8_t reg8;
+ reg8 = pci_read_config8(PCH_DEV_PMC, GEN_PMCON_B);
+ if (on)
+ reg8 &= ~SLEEP_AFTER_POWER_FAIL;
+ else
+ reg8 |= SLEEP_AFTER_POWER_FAIL;
+ pci_write_config8(PCH_DEV_PMC, GEN_PMCON_B, reg8);
+}
+
+#if ENV_RAMSTAGE
+/* Fill up PMC resource structure */
+int pmc_soc_get_resources(struct pmc_resource_config *cfg)
+{
+ cfg->pwrmbase_offset = PWRMBASE;
+ cfg->pwrmbase_addr = PCH_PWRM_BASE_ADDRESS;
+ cfg->pwrmbase_size = PCH_PWRM_BASE_SIZE;
+ cfg->abase_offset = ABASE;
+ cfg->abase_addr = ACPI_BASE_ADDRESS;
+ cfg->abase_size = ACPI_BASE_SIZE;
+
+ return 0;
+}
+
+static const struct reg_script pch_pmc_misc_init_script[] = {
+ /* Enable SCI and clear SLP requests. */
+ REG_IO_RMW32(ACPI_BASE_ADDRESS + PM1_CNT, ~SLP_TYP, SCI_EN),
+ REG_SCRIPT_END
+};
+
+static const struct reg_script pmc_write1_to_clear_script[] = {
+ REG_PCI_OR32(GEN_PMCON_A, 0),
+ REG_PCI_OR32(GEN_PMCON_B, 0),
+ REG_PCI_OR32(GEN_PMCON_B, 0),
+ REG_RES_OR32(PWRMBASE, GBLRST_CAUSE0, 0),
+ REG_RES_OR32(PWRMBASE, GBLRST_CAUSE1, 0),
+ REG_SCRIPT_END
+};
+
+void pmc_soc_init(struct device *dev)
+{
+ pmc_set_power_failure_state(true);
+ pmc_gpe_init();
+
+ /* Note that certain bits may be cleared from running script as
+ * certain bit fields are write 1 to clear. */
+ reg_script_run_on_dev(dev, pch_pmc_misc_init_script);
+ pmc_set_acpi_mode();
+
+ /* Clear registers that contain write-1-to-clear bits. */
+ reg_script_run_on_dev(dev, pmc_write1_to_clear_script);
+}
+#endif
+
+/*
+ * GPE0
+ */
+
+const char *const *soc_std_gpe_sts_array(size_t *gpe_arr)
+{
+ static const char *const gpe_sts_bits[] = {
+ };
+
+ *gpe_arr = ARRAY_SIZE(gpe_sts_bits);
+ return gpe_sts_bits;
+}
+
+uint8_t *pmc_mmio_regs(void)
+{
+ return (void *)(uintptr_t) pci_read_config32(PCH_DEV_PMC, PWRMBASE);
+}
+
+uintptr_t soc_read_pmc_base(void)
+{
+ return (uintptr_t) (pmc_mmio_regs());
+}
+
+uint32_t *soc_pmc_etr_addr(void)
+{
+ /*
+ * The pointer returned must not be cached, because the address depends on the
+ * MMCONF base address and the assigned PCI bus number, which both may change
+ * during the boot process!
+ */
+ return pci_mmio_config32_addr(PCH_DEVFN_PMC << 12, ETR);
+}
+
+void soc_get_gpi_gpe_configs(uint8_t *dw0, uint8_t *dw1, uint8_t *dw2)
+{
+ /* No functionality for this yet */
+}
+
+int rtc_failure(void)
+{
+ u8 reg8;
+ int rtc_failed;
+ /* PMC Controller Device 0x1F, Func 02 */
+ reg8 = pci_read_config8(PCH_DEV_PMC, GEN_PMCON_B);
+ rtc_failed = reg8 & RTC_BATTERY_DEAD;
+ if (rtc_failed) {
+ reg8 &= ~RTC_BATTERY_DEAD;
+ pci_write_config8(PCH_DEV_PMC, GEN_PMCON_B, reg8);
+ printk(BIOS_DEBUG, "rtc_failed = 0x%x\n", rtc_failed);
+ }
+
+ return !!rtc_failed;
+}
+
+/* Return 0, 3, or 5 to indicate the previous sleep state. */
+int soc_prev_sleep_state(const struct chipset_power_state *ps, int prev_sleep_state)
+{
+ /*
+ * Check for any power failure to determine if this a wake from
+ * S5 because the PCH does not set the WAK_STS bit when waking
+ * from a true G3 state.
+ */
+ if (!(ps->pm1_sts & WAK_STS) &&
+ (ps->gen_pmcon_b & (PWR_FLR | SUS_PWR_FLR)))
+ prev_sleep_state = ACPI_S5;
+
+ return prev_sleep_state;
+}
+
+void soc_fill_power_state(struct chipset_power_state *ps)
+{
+ uint8_t *pmc;
+
+ ps->gen_pmcon_a = pci_read_config32(PCH_DEV_PMC, GEN_PMCON_A);
+ ps->gen_pmcon_b = pci_read_config32(PCH_DEV_PMC, GEN_PMCON_B);
+
+ pmc = pmc_mmio_regs();
+ ps->gblrst_cause[0] = read32(pmc + GBLRST_CAUSE0);
+ ps->gblrst_cause[1] = read32(pmc + GBLRST_CAUSE1);
+
+ printk(BIOS_DEBUG, "GEN_PMCON: %08x %08x\n",
+ ps->gen_pmcon_a, ps->gen_pmcon_b);
+
+ printk(BIOS_DEBUG, "GBLRST_CAUSE: %08x %08x\n",
+ ps->gblrst_cause[0], ps->gblrst_cause[1]);
+}
+
+/* STM Support */
+uint16_t get_pmbase(void)
+{
+ return ACPI_BASE_ADDRESS;
+}
+
+const char *const *soc_smi_sts_array(size_t *smi_arr)
+{
+ static const char *const smi_sts_bits[] = {
+ [2] = "BIOS",
+ [3] = "LEGACY_USB",
+ [4] = "SLP_SMI",
+ [5] = "APM",
+ [6] = "SWSMI_TMR",
+ [7] = "BIOS_RLS",
+ [8] = "PM1",
+ [9] = "GPE0",
+ [10] = "GPI",
+ [11] = "MCSMI",
+ [12] = "DEVMON",
+ [13] = "TCO",
+ [14] = "PERIODIC",
+ [20] = "PCI_EXP_SMI",
+ [23] = "IE_SMI",
+ [25] = "SCC_SMI",
+ [26] = "SPI",
+ [27] = "GPIO_UNLOCK",
+ [28] = "ESPI_SMI",
+ [29] = "SERIAL_I/O",
+ [30] = "ME_SMI",
+ [31] = "XHCI",
+ };
+
+ *smi_arr = ARRAY_SIZE(smi_sts_bits);
+ return smi_sts_bits;
+}
diff --git a/src/soc/intel/xeon_sp/skx/chip.h b/src/soc/intel/xeon_sp/skx/chip.h
index 440fb40f3d..bb084f3d74 100644
--- a/src/soc/intel/xeon_sp/skx/chip.h
+++ b/src/soc/intel/xeon_sp/skx/chip.h
@@ -37,6 +37,7 @@ struct soc_intel_xeon_sp_skx_config {
* 6h = PIRQG#
* 7h = PIRQH#
*/
+
uint16_t ir00_routing;
uint16_t ir01_routing;
uint16_t ir02_routing;