diff options
author | Shaunak Saha <shaunak.saha@intel.com> | 2017-07-08 01:08:40 -0700 |
---|---|---|
committer | Aaron Durbin <adurbin@chromium.org> | 2017-10-05 21:11:39 +0000 |
commit | d3476809955ffb69447cc02a5ea893ebd1da3eb3 (patch) | |
tree | 9ba3421063935064df6974b4879af4dc1b64fe83 /src/soc/intel/skylake/pmutil.c | |
parent | f073872e22728fe8ade85022740af95cc129e9a5 (diff) | |
download | coreboot-d3476809955ffb69447cc02a5ea893ebd1da3eb3.tar.xz |
soc/intel/skylake: Add support in SKL for PMC common code
Change-Id: I3742f9c22d990edd918713155ae0bb1853663b6f
Signed-off-by: Shaunak Saha <shaunak.saha@intel.com>
Reviewed-on: https://review.coreboot.org/20499
Reviewed-by: Aaron Durbin <adurbin@chromium.org>
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Diffstat (limited to 'src/soc/intel/skylake/pmutil.c')
-rw-r--r-- | src/soc/intel/skylake/pmutil.c | 412 |
1 files changed, 46 insertions, 366 deletions
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 <device/pci.h> #include <device/pci_def.h> #include <console/console.h> +#include <intelblocks/pmclib.h> #include <halt.h> #include <intelblocks/lpc_lib.h> #include <rules.h> @@ -41,141 +42,13 @@ #include <vboot/vbnv.h> #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) |