From d3476809955ffb69447cc02a5ea893ebd1da3eb3 Mon Sep 17 00:00:00 2001 From: Shaunak Saha Date: Sat, 8 Jul 2017 01:08:40 -0700 Subject: soc/intel/skylake: Add support in SKL for PMC common code Change-Id: I3742f9c22d990edd918713155ae0bb1853663b6f Signed-off-by: Shaunak Saha Reviewed-on: https://review.coreboot.org/20499 Reviewed-by: Aaron Durbin Tested-by: build bot (Jenkins) --- src/soc/intel/skylake/Kconfig | 1 + src/soc/intel/skylake/bootblock/pch.c | 1 + src/soc/intel/skylake/include/soc/gpe.h | 2 + src/soc/intel/skylake/include/soc/pm.h | 47 +-- src/soc/intel/skylake/include/soc/pmc.h | 6 +- src/soc/intel/skylake/pmc.c | 3 +- src/soc/intel/skylake/pmutil.c | 412 +++--------------------- src/soc/intel/skylake/reset.c | 10 +- src/soc/intel/skylake/romstage/power_state.c | 135 ++------ src/soc/intel/skylake/romstage/romstage.c | 11 + src/soc/intel/skylake/romstage/romstage_fsp20.c | 5 +- src/soc/intel/skylake/smi.c | 17 +- src/soc/intel/skylake/smihandler.c | 31 +- 13 files changed, 133 insertions(+), 548 deletions(-) diff --git a/src/soc/intel/skylake/Kconfig b/src/soc/intel/skylake/Kconfig index 3c676d8dc2..f830f540d5 100644 --- a/src/soc/intel/skylake/Kconfig +++ b/src/soc/intel/skylake/Kconfig @@ -65,6 +65,7 @@ config CPU_SPECIFIC_OPTIONS select SOC_INTEL_COMMON_BLOCK_LPC select SOC_INTEL_COMMON_BLOCK_LPSS select SOC_INTEL_COMMON_BLOCK_PCIE + select SOC_INTEL_COMMON_BLOCK_PMC select SOC_INTEL_COMMON_BLOCK_PCR select SOC_INTEL_COMMON_BLOCK_RTC select SOC_INTEL_COMMON_BLOCK_SA diff --git a/src/soc/intel/skylake/bootblock/pch.c b/src/soc/intel/skylake/bootblock/pch.c index 67951f6a5f..fdc88f5641 100644 --- a/src/soc/intel/skylake/bootblock/pch.c +++ b/src/soc/intel/skylake/bootblock/pch.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include diff --git a/src/soc/intel/skylake/include/soc/gpe.h b/src/soc/intel/skylake/include/soc/gpe.h index 655cc1127b..d0962b84d8 100644 --- a/src/soc/intel/skylake/include/soc/gpe.h +++ b/src/soc/intel/skylake/include/soc/gpe.h @@ -130,4 +130,6 @@ #define GPE0_LAN_WAK 112 #define GPE0_WADT 114 +#define GPE_MAX GPE0_WADT + #endif /* _SOC_GPE_H_ */ diff --git a/src/soc/intel/skylake/include/soc/pm.h b/src/soc/intel/skylake/include/soc/pm.h index a547094c37..00578180eb 100644 --- a/src/soc/intel/skylake/include/soc/pm.h +++ b/src/soc/intel/skylake/include/soc/pm.h @@ -20,6 +20,8 @@ #include #include #include +#include +#include #include /* ACPI_BASE_ADDRESS / PMBASE */ @@ -103,6 +105,7 @@ #define GPE_63_32 1 /* 0x84/0x94 = GPE[63:32] */ #define GPE_95_64 2 /* 0x88/0x98 = GPE[95:64] */ #define GPE_STD 3 /* 0x8c/0x9c = Standard GPE */ +#define GPE_STS_RSVD GPE_STD #define WADT_STS (1 << 18) #define LAN_WAK_STS (1 << 16) #define GPIO_T2_STS (1 << 15) @@ -136,6 +139,13 @@ #define MAINBOARD_POWER_ON 1 #define MAINBOARD_POWER_KEEP 2 +/* 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; @@ -150,49 +160,26 @@ struct chipset_power_state { uint32_t prev_sleep_state; } __packed; +/* + * This is used only in FSP1_1 as we wanted to keep the flow unchanged. + * Internally fill_power_state calls the new pmc_fill_power_state now + */ +#if IS_ENABLED(CONFIG_PLATFORM_USES_FSP1_1) struct chipset_power_state *fill_power_state(void); - -/* PM1_CNT */ -void enable_pm1_control(uint32_t mask); -void disable_pm1_control(uint32_t mask); - -/* PM1 */ -uint16_t clear_pm1_status(void); -void enable_pm1(uint16_t events); -void update_pm1_enable(uint16_t events); -uint16_t read_pm1_enable(void); -uint32_t clear_smi_status(void); - -/* SMI */ -void enable_smi(uint32_t mask); -void disable_smi(uint32_t mask); - -/* TCO */ -uint32_t clear_tco_status(void); -void enable_tco_sci(void); - -/* GPE0 */ -uint32_t clear_gpe_status(void); -void clear_gpe_enable(void); -void enable_all_gpe(uint32_t set1, uint32_t set2, uint32_t set3, uint32_t set4); -void disable_all_gpe(void); -void enable_gpe(uint32_t mask); -void disable_gpe(uint32_t mask); +#endif /* Return the selected ACPI SCI IRQ */ int acpi_sci_irq(void); /* Get base address PMC memory mapped registers. */ uint8_t *pmc_mmio_regs(void); + /* Get base address of TCO I/O registers. */ uint16_t smbus_tco_regs(void); /* Set the DISB after DRAM init */ void pmc_set_disb(void); -/* Initialize GPEs */ -void pmc_gpe_init(void); - /* Return non-zero when RTC failure happened. */ int rtc_failure(void); diff --git a/src/soc/intel/skylake/include/soc/pmc.h b/src/soc/intel/skylake/include/soc/pmc.h index 4a80917fe4..bd86f95e38 100644 --- a/src/soc/intel/skylake/include/soc/pmc.h +++ b/src/soc/intel/skylake/include/soc/pmc.h @@ -91,11 +91,9 @@ #define DSX_EN_LAN_WAKE_PIN (1 << 0) #define PMSYNC_TPR_CFG 0xc4 #define PMSYNC_LOCK (1 << 31) -#define GPIO_CFG 0x120 +#define GPIO_GPE_CFG 0x120 #define GPE0_DWX_MASK 0xf -#define GPE0_DW0_SHIFT 0 -#define GPE0_DW1_SHIFT 4 -#define GPE0_DW2_SHIFT 8 +#define GPE0_DW_SHIFT(x) (4*(x)) #define GBLRST_CAUSE0 0x124 #define GBLRST_CAUSE1 0x128 #define CIR31C 0x31c diff --git a/src/soc/intel/skylake/pmc.c b/src/soc/intel/skylake/pmc.c index 131b6af205..9c05ff6c27 100644 --- a/src/soc/intel/skylake/pmc.c +++ b/src/soc/intel/skylake/pmc.c @@ -25,14 +25,15 @@ #include #include #include +#include #include #include #include #include #include #include -#include #include +#include #include #include #include diff --git a/src/soc/intel/skylake/pmutil.c b/src/soc/intel/skylake/pmutil.c index 7af138f170..9dd22e9c7c 100644 --- a/src/soc/intel/skylake/pmutil.c +++ b/src/soc/intel/skylake/pmutil.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -41,141 +42,13 @@ #include #include "chip.h" -/* Print status bits with descriptive names */ -static void print_status_bits(u32 status, const char * const bit_names[]) -{ - int i; - - if (!status) - return; - - for (i = 31; i >= 0; i--) { - if (status & (1 << i)) { - if (bit_names[i]) - printk(BIOS_DEBUG, "%s ", bit_names[i]); - else - printk(BIOS_DEBUG, "BIT%d ", i); - } - } -} - -/* Print status bits as GPIO numbers */ -static void print_gpio_status(u32 status, int start) -{ - int i; - - if (!status) - return; - - for (i = 31; i >= 0; i--) { - if (status & (1 << i)) - printk(BIOS_DEBUG, "GPIO%d ", start + i); - } -} - - -/* - * PM1_CNT - */ - -/* Enable events in PM1 control register */ -void enable_pm1_control(u32 mask) -{ - u32 pm1_cnt = inl(ACPI_BASE_ADDRESS + PM1_CNT); - pm1_cnt |= mask; - outl(pm1_cnt, ACPI_BASE_ADDRESS + PM1_CNT); -} - -/* Disable events in PM1 control register */ -void disable_pm1_control(u32 mask) -{ - u32 pm1_cnt = inl(ACPI_BASE_ADDRESS + PM1_CNT); - pm1_cnt &= ~mask; - outl(pm1_cnt, ACPI_BASE_ADDRESS + PM1_CNT); -} - - -/* - * PM1 - */ - -/* Clear and return PM1 status register */ -static u16 reset_pm1_status(void) -{ - u16 pm1_sts = inw(ACPI_BASE_ADDRESS + PM1_STS); - outw(pm1_sts, ACPI_BASE_ADDRESS + PM1_STS); - return pm1_sts; -} - -/* Print PM1 status bits */ -static u16 print_pm1_status(u16 pm1_sts) -{ - static const char * const pm1_sts_bits[] = { - [0] = "TMROF", - [4] = "BM", - [5] = "GBL", - [8] = "PWRBTN", - [10] = "RTC", - [11] = "PRBTNOR", - [14] = "PCIEXPWAK", - [15] = "WAK", - }; - - if (!pm1_sts) - return 0; - - printk(BIOS_SPEW, "PM1_STS: "); - print_status_bits(pm1_sts, pm1_sts_bits); - printk(BIOS_SPEW, "\n"); - - return pm1_sts; -} - -/* Print, clear, and return PM1 status */ -u16 clear_pm1_status(void) -{ - return print_pm1_status(reset_pm1_status()); -} - -/* Set the PM1 register to events */ -void enable_pm1(u16 events) -{ - outw(events, ACPI_BASE_ADDRESS + PM1_EN); -} - -/* - * Update supplied events in PM1_EN register. This does not disable any already - * set events. - */ -void update_pm1_enable(u16 events) -{ - u16 pm1_en = read_pm1_enable(); - pm1_en |= events; - enable_pm1(pm1_en); -} - -/* Read events set in PM1_EN register. */ -uint16_t read_pm1_enable(void) -{ - return inw(ACPI_BASE_ADDRESS + PM1_EN); -} - /* * SMI */ -/* Clear and return SMI status register */ -static u32 reset_smi_status(void) -{ - u32 smi_sts = inl(ACPI_BASE_ADDRESS + SMI_STS); - outl(smi_sts, ACPI_BASE_ADDRESS + SMI_STS); - return smi_sts; -} - -/* Print SMI status bits */ -static u32 print_smi_status(u32 smi_sts) +const char *const *soc_smi_sts_array(size_t *smi_arr) { - static const char * const smi_sts_bits[] = { + static const char *const smi_sts_bits[] = { [2] = "BIOS", [3] = "LEGACY_USB", [4] = "SLP_SMI", @@ -199,70 +72,17 @@ static u32 print_smi_status(u32 smi_sts) [28] = "ESPI_SMI", }; - if (!smi_sts) - return 0; - - printk(BIOS_DEBUG, "SMI_STS: "); - print_status_bits(smi_sts, smi_sts_bits); - printk(BIOS_DEBUG, "\n"); - - return smi_sts; -} - -/* Print, clear, and return SMI status */ -u32 clear_smi_status(void) -{ - return print_smi_status(reset_smi_status()); -} - -/* Enable SMI event */ -void enable_smi(u32 mask) -{ - u32 smi_en = inl(ACPI_BASE_ADDRESS + SMI_EN); - smi_en |= mask; - outl(smi_en, ACPI_BASE_ADDRESS + SMI_EN); -} - -/* Disable SMI event */ -void disable_smi(u32 mask) -{ - u32 smi_en = inl(ACPI_BASE_ADDRESS + SMI_EN); - smi_en &= ~mask; - outl(smi_en, ACPI_BASE_ADDRESS + SMI_EN); + *smi_arr = ARRAY_SIZE(smi_sts_bits); + return smi_sts_bits; } /* * TCO */ -/* Clear TCO status and return events that are enabled and active */ -static u32 reset_tco_status(void) -{ - u16 tco1_sts; - u16 tco2_sts; - u16 tcobase; - - tcobase = smbus_tco_regs(); - - /* TCO Status 2 register*/ - tco2_sts = inw(tcobase + TCO2_STS); - tco2_sts |= (TCO2_STS_SECOND_TO | TCO2_STS_BOOT); - outw(tco2_sts, tcobase + TCO2_STS); - - /* TCO Status 1 register*/ - tco1_sts = inw(tcobase + TCO1_STS); - - /* Clear SECOND_TO_STS bit */ - if (tco2_sts & TCO2_STS_SECOND_TO) - outw(tco2_sts & ~TCO2_STS_SECOND_TO, tcobase + TCO2_STS); - - return (tco2_sts << 16) | tco1_sts; -} - -/* Print TCO status bits */ -static u32 print_tco_status(u32 tco_sts) +const char *const *soc_tco_sts_array(size_t *tco_arr) { - static const char * const tco_sts_bits[] = { + static const char *const tco_sts_bits[] = { [0] = "NMI2SMI", [1] = "SW_TCO", [2] = "TCO_INT", @@ -279,79 +99,17 @@ static u32 print_tco_status(u32 tco_sts) [20] = "SMLINK_SLV" }; - if (!tco_sts) - return 0; - - printk(BIOS_DEBUG, "TCO_STS: "); - print_status_bits(tco_sts, tco_sts_bits); - printk(BIOS_DEBUG, "\n"); - - return tco_sts; + *tco_arr = ARRAY_SIZE(tco_sts_bits); + return tco_sts_bits; } -/* Print, clear, and return TCO status */ -u32 clear_tco_status(void) -{ - return print_tco_status(reset_tco_status()); -} - -/* Enable TCO SCI */ -void enable_tco_sci(void) -{ - /* Clear pending events */ - outl(TCOSCI_STS, ACPI_BASE_ADDRESS + GPE0_STS(3)); - - /* Enable TCO SCI events */ - enable_gpe(TCOSCI_EN); -} - - /* * GPE0 */ -/* Clear a GPE0 status and return events that are enabled and active */ -static u32 reset_gpe(u16 sts_reg, u16 en_reg) +const char *const *soc_gpe_sts_array(size_t *gpe_arr) { - u32 gpe0_sts = inl(ACPI_BASE_ADDRESS + sts_reg); - u32 gpe0_en = inl(ACPI_BASE_ADDRESS + en_reg); - - outl(gpe0_sts, ACPI_BASE_ADDRESS + sts_reg); - - /* Only report enabled events */ - return gpe0_sts & gpe0_en; -} - -/* Print GPE0 status bits */ -static u32 print_gpe_status(u32 gpe0_sts, const char * const bit_names[]) -{ - if (!gpe0_sts) - return 0; - - printk(BIOS_DEBUG, "GPE0_STS: "); - print_status_bits(gpe0_sts, bit_names); - printk(BIOS_DEBUG, "\n"); - - return gpe0_sts; -} - -/* Print GPE0 GPIO status bits */ -static u32 print_gpe_gpio(u32 gpe0_sts, int start) -{ - if (!gpe0_sts) - return 0; - - printk(BIOS_DEBUG, "GPE0_STS: "); - print_gpio_status(gpe0_sts, start); - printk(BIOS_DEBUG, "\n"); - - return gpe0_sts; -} - -/* Clear all GPE status and return "standard" GPE event status */ -u32 clear_gpe_status(void) -{ - static const char * const gpe0_sts_3_bits[] = { + static const char *const gpe_sts_bits[] = { [1] = "HOTPLUG", [2] = "SWGPE", [6] = "TCO_SCI", @@ -367,72 +125,8 @@ u32 clear_gpe_status(void) [18] = "WADT" }; - print_gpe_gpio(reset_gpe(GPE0_STS(GPE_31_0), GPE0_EN(GPE_31_0)), 0); - print_gpe_gpio(reset_gpe(GPE0_STS(GPE_63_32), GPE0_EN(GPE_63_32)), 32); - print_gpe_gpio(reset_gpe(GPE0_STS(GPE_95_64), GPE0_EN(GPE_95_64)), 64); - return print_gpe_status(reset_gpe(GPE0_STS(GPE_STD), GPE0_EN(GPE_STD)), - gpe0_sts_3_bits); -} - -/* Read and clear GPE status (defined in arch/acpi.h) */ -int acpi_get_gpe(int gpe) -{ - int bank; - uint32_t mask, sts; - struct stopwatch sw; - int rc = 0; - - if (gpe < 0 || gpe > GPE0_WADT) - return -1; - - bank = gpe / 32; - mask = 1 << (gpe % 32); - - /* Wait up to 1ms for GPE status to clear */ - stopwatch_init_msecs_expire(&sw, 1); - do { - if (stopwatch_expired(&sw)) - return rc; - - sts = inl(ACPI_BASE_ADDRESS + GPE0_STS(bank)); - if (sts & mask) { - outl(mask, ACPI_BASE_ADDRESS + GPE0_STS(bank)); - rc = 1; - } - } while (sts & mask); - - return rc; -} - -/* Enable all requested GPE */ -void enable_all_gpe(u32 set1, u32 set2, u32 set3, u32 set4) -{ - outl(set1, ACPI_BASE_ADDRESS + GPE0_EN(GPE_31_0)); - outl(set2, ACPI_BASE_ADDRESS + GPE0_EN(GPE_63_32)); - outl(set3, ACPI_BASE_ADDRESS + GPE0_EN(GPE_95_64)); - outl(set4, ACPI_BASE_ADDRESS + GPE0_EN(GPE_STD)); -} - -/* Disable all GPE */ -void disable_all_gpe(void) -{ - enable_all_gpe(0, 0, 0, 0); -} - -/* Enable a standard GPE */ -void enable_gpe(u32 mask) -{ - u32 gpe0_en = inl(ACPI_BASE_ADDRESS + GPE0_EN(GPE_STD)); - gpe0_en |= mask; - outl(gpe0_en, ACPI_BASE_ADDRESS + GPE0_EN(GPE_STD)); -} - -/* Disable a standard GPE */ -void disable_gpe(u32 mask) -{ - u32 gpe0_en = inl(ACPI_BASE_ADDRESS + GPE0_EN(GPE_STD)); - gpe0_en &= ~mask; - outl(gpe0_en, ACPI_BASE_ADDRESS + GPE0_EN(GPE_STD)); + *gpe_arr = ARRAY_SIZE(gpe_sts_bits); + return gpe_sts_bits; } int acpi_sci_irq(void) @@ -472,7 +166,7 @@ uint8_t *pmc_mmio_regs(void) /* 4KiB alignment. */ reg32 &= ~0xfff; - return (void *)(uintptr_t)reg32; + return (void *)(uintptr_t) reg32; } uint16_t smbus_tco_regs(void) @@ -486,63 +180,49 @@ uint16_t smbus_tco_regs(void) return reg16; } -void poweroff(void) +uint32_t soc_reset_tco_status(void) +{ + u16 tco1_sts; + u16 tco2_sts; + u16 tcobase; + + tcobase = smbus_tco_regs(); + + /* TCO Status 2 register */ + tco2_sts = inw(tcobase + TCO2_STS); + tco2_sts |= (TCO2_STS_SECOND_TO | TCO2_STS_BOOT); + outw(tco2_sts, tcobase + TCO2_STS); + + /* TCO Status 1 register */ + tco1_sts = inw(tcobase + TCO1_STS); + + /* Clear SECOND_TO_STS bit */ + if (tco2_sts & TCO2_STS_SECOND_TO) + outw(tco2_sts & ~TCO2_STS_SECOND_TO, tcobase + TCO2_STS); + + return (tco2_sts << 16) | tco1_sts; +} + +uintptr_t soc_read_pmc_base(void) { - enable_pm1_control(SLP_EN | (SLP_TYP_S5 << SLP_TYP_SHIFT)); - - /* - * Setting SLP_TYP_S5 in PM1 triggers SLP_SMI, which is handled by SMM - * to transition to S5 state. If halt is called in SMM, then it prevents - * the SMI handler from being triggered and system never enters S5. - */ - if (!ENV_SMM) - halt(); + return (uintptr_t) (pmc_mmio_regs()); } -void pmc_gpe_init(void) +void soc_get_gpe_configs(uint8_t *dw0, uint8_t *dw1, uint8_t *dw2) { DEVTREE_CONST struct soc_intel_skylake_config *config; - DEVTREE_CONST struct device *dev = dev_find_slot(0, PCH_DEVFN_PMC); - uint8_t *pmc_regs; - uint32_t gpio_cfg; - uint32_t gpio_cfg_reg; - const uint32_t gpio_cfg_mask = - (GPE0_DWX_MASK << GPE0_DW0_SHIFT) | - (GPE0_DWX_MASK << GPE0_DW1_SHIFT) | - (GPE0_DWX_MASK << GPE0_DW2_SHIFT); /* Look up the device in devicetree */ + DEVTREE_CONST struct device *dev = dev_find_slot(0, PCH_DEVFN_PMC); if (!dev || !dev->chip_info) { printk(BIOS_ERR, "BUG! Could not find SOC devicetree config\n"); - return; } config = dev->chip_info; - pmc_regs = pmc_mmio_regs(); - - /* Route the GPIOs to the GPE0 block. Determine that all values - * are different, and if they aren't use the reset values. */ - gpio_cfg = 0; - if (config->gpe0_dw0 == config->gpe0_dw1 || - config->gpe0_dw1 == config->gpe0_dw2) { - printk(BIOS_INFO, "PMC: Using default GPE route.\n"); - gpio_cfg = read32(pmc_regs + GPIO_CFG); - } else { - gpio_cfg |= (uint32_t)config->gpe0_dw0 << GPE0_DW0_SHIFT; - gpio_cfg |= (uint32_t)config->gpe0_dw1 << GPE0_DW1_SHIFT; - gpio_cfg |= (uint32_t)config->gpe0_dw2 << GPE0_DW2_SHIFT; - } - gpio_cfg_reg = read32(pmc_regs + GPIO_CFG) & ~gpio_cfg_mask; - gpio_cfg_reg |= gpio_cfg & gpio_cfg_mask; - write32(pmc_regs + GPIO_CFG, gpio_cfg_reg); - - /* Set the routes in the GPIO communities as well. */ - gpio_route_gpe((gpio_cfg_reg >> GPE0_DW0_SHIFT) & GPE0_DWX_MASK, - (gpio_cfg_reg >> GPE0_DW1_SHIFT) & GPE0_DWX_MASK, - (gpio_cfg_reg >> GPE0_DW2_SHIFT) & GPE0_DWX_MASK); - - /* Set GPE enables based on devictree. */ - enable_all_gpe(config->gpe0_en_1, config->gpe0_en_2, - config->gpe0_en_3, config->gpe0_en_4); + + /* Assign to out variable */ + *dw0 = config->gpe0_dw0; + *dw1 = config->gpe0_dw1; + *dw2 = config->gpe0_dw2; } int rtc_failure(void) diff --git a/src/soc/intel/skylake/reset.c b/src/soc/intel/skylake/reset.c index dee98a4c1e..d9e3ea5062 100644 --- a/src/soc/intel/skylake/reset.c +++ b/src/soc/intel/skylake/reset.c @@ -15,6 +15,7 @@ #include #include +#include #include #include #include @@ -22,19 +23,12 @@ static void do_force_global_reset(void) { - u32 reg32; - /*PMC Controller Device 0x1F, Func 02*/ - uint8_t *pmc_regs; - /* * BIOS should ensure it does a global reset * to reset both host and Intel ME by setting * PCH PMC [B0:D31:F2 register offset 0x1048 bit 20] */ - pmc_regs = pmc_mmio_regs(); - reg32 = read32(pmc_regs + ETR3); - reg32 |= ETR3_CF9GR; - write32(pmc_regs + ETR3, reg32); + pmc_global_reset_enable(true); /* Now BIOS can write 0x06 or 0x0E to 0xCF9 port * to global reset platform */ diff --git a/src/soc/intel/skylake/romstage/power_state.c b/src/soc/intel/skylake/romstage/power_state.c index 19f43c3a93..78650fa590 100644 --- a/src/soc/intel/skylake/romstage/power_state.c +++ b/src/soc/intel/skylake/romstage/power_state.c @@ -15,7 +15,6 @@ */ #include -#include #include #include #include @@ -27,63 +26,26 @@ #include #include #include -#include #include #include #include +#include #include #include - -static struct chipset_power_state power_state CAR_GLOBAL; - -static struct chipset_power_state *get_power_state(void) -{ - return car_get_var_ptr(&power_state); -} - -static void migrate_power_state(int is_recovery) -{ - struct chipset_power_state *ps_cbmem; - struct chipset_power_state *ps_car; - - ps_car = get_power_state(); - ps_cbmem = cbmem_add(CBMEM_ID_POWER_STATE, sizeof(*ps_cbmem)); - - if (ps_cbmem == NULL) { - printk(BIOS_DEBUG, "Not adding power state to cbmem!\n"); - return; - } - memcpy(ps_cbmem, ps_car, sizeof(*ps_cbmem)); -} -ROMSTAGE_CBMEM_INIT_HOOK(migrate_power_state) +#include /* Return 0, 3, or 5 to indicate the previous sleep state. */ -static uint32_t prev_sleep_state(struct chipset_power_state *ps) +int soc_prev_sleep_state(const struct chipset_power_state *ps, + int prev_sleep_state) { - /* Default to S0. */ - uint32_t prev_sleep_state = ACPI_S0; - - if (ps->pm1_sts & WAK_STS) { - switch (acpi_sleep_from_pm1(ps->pm1_cnt)) { - case ACPI_S3: - if (IS_ENABLED(CONFIG_HAVE_ACPI_RESUME)) - prev_sleep_state = ACPI_S3; - break; - case ACPI_S5: - prev_sleep_state = ACPI_S5; - break; - } - /* Clear SLP_TYP. */ - outl(ps->pm1_cnt & ~(SLP_TYP), ACPI_BASE_ADDRESS + PM1_CNT); - } else { - /* - * 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->gen_pmcon_b & (PWR_FLR | SUS_PWR_FLR)) - prev_sleep_state = ACPI_S5; - } + + /* + * 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->gen_pmcon_b & (PWR_FLR | SUS_PWR_FLR)) + prev_sleep_state = ACPI_S5; /* * If waking from S3 determine if deep S3 is enabled. If not, @@ -101,57 +63,21 @@ static uint32_t prev_sleep_state(struct chipset_power_state *ps) if (ps->gen_pmcon_b & mask) prev_sleep_state = ACPI_S5; } - return prev_sleep_state; } -static void dump_power_state(struct chipset_power_state *ps) -{ - printk(BIOS_DEBUG, "PM1_STS: %04x\n", ps->pm1_sts); - printk(BIOS_DEBUG, "PM1_EN: %04x\n", ps->pm1_en); - printk(BIOS_DEBUG, "PM1_CNT: %08x\n", ps->pm1_cnt); - printk(BIOS_DEBUG, "TCO_STS: %04x %04x\n", - ps->tco1_sts, ps->tco2_sts); - - printk(BIOS_DEBUG, "GPE0_STS: %08x %08x %08x %08x\n", - ps->gpe0_sts[0], ps->gpe0_sts[1], - ps->gpe0_sts[2], ps->gpe0_sts[3]); - printk(BIOS_DEBUG, "GPE0_EN: %08x %08x %08x %08x\n", - ps->gpe0_en[0], ps->gpe0_en[1], - ps->gpe0_en[2], ps->gpe0_en[3]); - - 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]); - - printk(BIOS_DEBUG, "Previous Sleep State: S%d\n", - ps->prev_sleep_state); -} - -/* Fill power state structure from ACPI PM registers */ -struct chipset_power_state *fill_power_state(void) +void soc_fill_power_state(struct chipset_power_state *ps) { uint16_t tcobase; uint8_t *pmc; - struct chipset_power_state *ps = get_power_state(); tcobase = smbus_tco_regs(); - ps->pm1_sts = inw(ACPI_BASE_ADDRESS + PM1_STS); - ps->pm1_en = inw(ACPI_BASE_ADDRESS + PM1_EN); - ps->pm1_cnt = inl(ACPI_BASE_ADDRESS + PM1_CNT); ps->tco1_sts = inw(tcobase + TCO1_STS); ps->tco2_sts = inw(tcobase + TCO2_STS); - ps->gpe0_sts[0] = inl(ACPI_BASE_ADDRESS + GPE0_STS(0)); - ps->gpe0_sts[1] = inl(ACPI_BASE_ADDRESS + GPE0_STS(1)); - ps->gpe0_sts[2] = inl(ACPI_BASE_ADDRESS + GPE0_STS(2)); - ps->gpe0_sts[3] = inl(ACPI_BASE_ADDRESS + GPE0_STS(3)); - ps->gpe0_en[0] = inl(ACPI_BASE_ADDRESS + GPE0_EN(0)); - ps->gpe0_en[1] = inl(ACPI_BASE_ADDRESS + GPE0_EN(1)); - ps->gpe0_en[2] = inl(ACPI_BASE_ADDRESS + GPE0_EN(2)); - ps->gpe0_en[3] = inl(ACPI_BASE_ADDRESS + GPE0_EN(3)); + + printk(BIOS_DEBUG, "TCO_STS: %04x %04x\n", + ps->tco1_sts, ps->tco2_sts); 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); @@ -160,36 +86,17 @@ struct chipset_power_state *fill_power_state(void) ps->gblrst_cause[0] = read32(pmc + GBLRST_CAUSE0); ps->gblrst_cause[1] = read32(pmc + GBLRST_CAUSE1); - ps->prev_sleep_state = prev_sleep_state(ps); - - dump_power_state(ps); + printk(BIOS_DEBUG, "GEN_PMCON: %08x %08x\n", + ps->gen_pmcon_a, ps->gen_pmcon_b); - return ps; + printk(BIOS_DEBUG, "GBLRST_CAUSE: %08x %08x\n", + ps->gblrst_cause[0], ps->gblrst_cause[1]); } int acpi_get_sleep_type(void) { struct chipset_power_state *ps; - ps = get_power_state(); + ps = pmc_get_power_state(); return ps->prev_sleep_state; } - -int vboot_platform_is_resuming(void) -{ - return acpi_sleep_from_pm1(inl(ACPI_BASE_ADDRESS + PM1_CNT)) == ACPI_S3; -} - -/* - * The PM1 control is set to S5 when vboot requests a reboot because the power - * state code above may not have collected it's data yet. Therefore, set it to - * S5 when vboot requests a reboot. That's necessary if vboot fails in the - * resume path and requests a reboot. This prevents a reboot loop where the - * error is continually hit on the failing vboot resume path. - */ -void vboot_platform_prepare_reboot(void) -{ - uint16_t port = ACPI_BASE_ADDRESS + PM1_CNT; - - outl((inl(port) & ~(SLP_TYP)) | (SLP_TYP_S5 << SLP_TYP_SHIFT), port); -} diff --git a/src/soc/intel/skylake/romstage/romstage.c b/src/soc/intel/skylake/romstage/romstage.c index 50c050ef45..215b07c074 100644 --- a/src/soc/intel/skylake/romstage/romstage.c +++ b/src/soc/intel/skylake/romstage/romstage.c @@ -29,6 +29,7 @@ #include #include #include +#include #include #include #include @@ -256,3 +257,13 @@ void soc_after_ram_init(struct romstage_params *params) */ pmc_set_disb(); } + +struct chipset_power_state *fill_power_state(void) +{ + struct chipset_power_state *ps; + + ps = pmc_get_power_state(); + pmc_fill_power_state(ps); + + return ps; +} diff --git a/src/soc/intel/skylake/romstage/romstage_fsp20.c b/src/soc/intel/skylake/romstage/romstage_fsp20.c index cbf934e8bd..d4a5e34199 100644 --- a/src/soc/intel/skylake/romstage/romstage_fsp20.c +++ b/src/soc/intel/skylake/romstage/romstage_fsp20.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -119,9 +120,9 @@ asmlinkage void car_stage_entry(void) /* Program MCHBAR, DMIBAR, GDXBAR and EDRAMBAR */ systemagent_early_init(); - ps = fill_power_state(); + ps = pmc_get_power_state(); timestamp_add_now(TS_START_ROMSTAGE); - s3wake = ps->prev_sleep_state == ACPI_S3; + s3wake = pmc_fill_power_state(ps) == ACPI_S3; fsp_memory_init(s3wake); pmc_set_disb(); if (!s3wake) diff --git a/src/soc/intel/skylake/smi.c b/src/soc/intel/skylake/smi.c index feddf5084c..23b8ce8e0c 100644 --- a/src/soc/intel/skylake/smi.c +++ b/src/soc/intel/skylake/smi.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -45,18 +46,18 @@ void southbridge_smm_clear_state(void) printk(BIOS_DEBUG, "\n"); /* Dump and clear status registers */ - clear_smi_status(); - clear_pm1_status(); - clear_tco_status(); - clear_gpe_status(); + pmc_clear_smi_status(); + pmc_clear_pm1_status(); + pmc_clear_tco_status(); + pmc_clear_gpe_status(); } void southbridge_smm_enable_smi(void) { printk(BIOS_DEBUG, "Enabling SMIs.\n"); /* Configure events */ - enable_pm1(GBL_EN); - disable_gpe(PME_B0_EN); + pmc_enable_pm1(GBL_EN); + pmc_disable_gpe(PME_B0_EN); /* * Enable SMI generation: @@ -68,7 +69,7 @@ void southbridge_smm_enable_smi(void) * - on microcontroller writes (io 0x62/0x66) * - on TCO events */ - enable_smi(APMC_EN | SLP_SMI_EN | GBL_SMI_EN | ESPI_SMI_EN | EOS); + pmc_enable_smi(APMC_EN | SLP_SMI_EN | GBL_SMI_EN | ESPI_SMI_EN | EOS); } void smm_setup_structures(void *gnvs, void *tcg, void *smi1) @@ -100,7 +101,7 @@ static void pm1_enable_pwrbtn_smi(void *unused) * any shutdowns because of power button presses due to power button * press in resume path. */ - update_pm1_enable(PWRBTN_EN); + pmc_update_pm1_enable(PWRBTN_EN); } BOOT_STATE_INIT_ENTRY(BS_PAYLOAD_LOAD, BS_ON_EXIT, pm1_enable_pwrbtn_smi, NULL); diff --git a/src/soc/intel/skylake/smihandler.c b/src/soc/intel/skylake/smihandler.c index 32764c644a..dc4237ab6f 100644 --- a/src/soc/intel/skylake/smihandler.c +++ b/src/soc/intel/skylake/smihandler.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -81,7 +82,7 @@ int southbridge_io_trap_handler(int smif) /* Set the EOS bit */ void southbridge_smi_set_eos(void) { - enable_smi(EOS); + pmc_enable_smi(EOS); } static void busmaster_disable_on_bus(int bus) @@ -136,7 +137,7 @@ static void southbridge_smi_sleep(void) outb(tmp72, 0x72); /* First, disable further SMIs */ - disable_smi(SLP_SMI_EN); + pmc_disable_smi(SLP_SMI_EN); /* Figure out SLP_TYP */ reg32 = inl(ACPI_BASE_ADDRESS + PM1_CNT); @@ -152,7 +153,7 @@ static void southbridge_smi_sleep(void) elog_add_event_byte(ELOG_TYPE_ACPI_ENTER, slp_typ); /* Clear pending GPE events */ - clear_gpe_status(); + pmc_clear_gpe_status(); /* Next, do the deed. */ switch (slp_typ) { @@ -175,7 +176,7 @@ static void southbridge_smi_sleep(void) /*TODO: cmos_layout.bin need to verify; cause wrong CMOS setup*/ s5pwr = MAINBOARD_POWER_ON; /* Disable all GPE */ - disable_all_gpe(); + pmc_disable_all_gpe(); /* * Always set the flag in case CMOS was changed on runtime. For @@ -201,7 +202,7 @@ static void southbridge_smi_sleep(void) * event again. We need to set BIT13 (SLP_EN) though to make the * sleep happen. */ - enable_pm1_control(SLP_EN); + pmc_enable_pm1_control(SLP_EN); /* Make sure to stop executing code here for S3/S4/S5 */ if (slp_typ >= ACPI_S3) @@ -215,7 +216,7 @@ static void southbridge_smi_sleep(void) reg32 = inl(ACPI_BASE_ADDRESS + PM1_CNT); if (reg32 & SCI_EN) { /* The OS is not an ACPI OS, so we set the state to S0 */ - disable_pm1_control(SLP_EN | SLP_TYP); + pmc_disable_pm1_control(SLP_EN | SLP_TYP); } } @@ -306,11 +307,11 @@ static void southbridge_smi_apmc(void) printk(BIOS_DEBUG, "P-state control\n"); break; case APM_CNT_ACPI_DISABLE: - disable_pm1_control(SCI_EN); + pmc_disable_pm1_control(SCI_EN); printk(BIOS_DEBUG, "SMI#: ACPI disabled.\n"); break; case APM_CNT_ACPI_ENABLE: - enable_pm1_control(SCI_EN); + pmc_enable_pm1_control(SCI_EN); printk(BIOS_DEBUG, "SMI#: ACPI enabled.\n"); break; case APM_CNT_FINALIZE: @@ -341,8 +342,8 @@ static void southbridge_smi_apmc(void) static void southbridge_smi_pm1(void) { - u16 pm1_sts = clear_pm1_status(); - u16 pm1_en = read_pm1_enable(); + u16 pm1_sts = pmc_clear_pm1_status(); + u16 pm1_en = pmc_read_pm1_enable(); /* * While OSPM is not active, poweroff immediately on a power button @@ -352,14 +353,14 @@ static void southbridge_smi_pm1(void) /* power button pressed */ if (IS_ENABLED(CONFIG_ELOG_GSMI)) elog_add_event(ELOG_TYPE_POWER_BUTTON); - disable_pm1_control(-1UL); - enable_pm1_control(SLP_EN | (SLP_TYP_S5 << 10)); + pmc_disable_pm1_control(-1UL); + pmc_enable_pm1_control(SLP_EN | (SLP_TYP_S5 << 10)); } } static void southbridge_smi_gpe0(void) { - clear_gpe_status(); + pmc_clear_gpe_status(); } void __attribute__((weak)) @@ -395,7 +396,7 @@ static void southbridge_smi_mc(void) static void southbridge_smi_tco(void) { - u32 tco_sts = clear_tco_status(); + u32 tco_sts = pmc_clear_tco_status(); /* Any TCO event? */ if (!tco_sts) @@ -522,7 +523,7 @@ void southbridge_smi_handler(void) * We need to clear the SMI status registers, or we won't see what's * happening in the following calls. */ - smi_sts = clear_smi_status(); + smi_sts = pmc_clear_smi_status(); /* Call SMI sub handler for each of the status bits */ for (i = 0; i < ARRAY_SIZE(southbridge_smi); i++) { -- cgit v1.2.3