aboutsummaryrefslogtreecommitdiff
path: root/src/soc/intel/xeon_sp/pmc.c
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/soc/intel/xeon_sp/pmc.c
parentbb25c59e90110f601291a281a5df8a70714399dc (diff)
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/soc/intel/xeon_sp/pmc.c')
-rw-r--r--src/soc/intel/xeon_sp/pmc.c195
1 files changed, 195 insertions, 0 deletions
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;
+}