Shaunak Saha has uploaded a new change for review. ( https://review.coreboot.org/19375 )
Change subject: [WIP]soc/intel/apollolake: Add support in APL for PMC common code ......................................................................
[WIP]soc/intel/apollolake: Add support in APL for PMC common code
Change-Id: I322a25a8b608d7fe98bec626c6696e723357a9d2 Signed-off-by: Shaunak Saha shaunak.saha@intel.com --- M src/soc/intel/apollolake/Kconfig M src/soc/intel/apollolake/bootblock/bootblock.c M src/soc/intel/apollolake/chip.c A src/soc/intel/apollolake/include/soc/bit_def.h M src/soc/intel/apollolake/include/soc/gpe.h M src/soc/intel/apollolake/include/soc/pm.h M src/soc/intel/apollolake/pmc.c M src/soc/intel/apollolake/pmutil.c M src/soc/intel/apollolake/reset.c M src/soc/intel/apollolake/smi.c 10 files changed, 84 insertions(+), 396 deletions(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/75/19375/3
diff --git a/src/soc/intel/apollolake/Kconfig b/src/soc/intel/apollolake/Kconfig index d60f85e..892412d 100644 --- a/src/soc/intel/apollolake/Kconfig +++ b/src/soc/intel/apollolake/Kconfig @@ -56,6 +56,7 @@ select SOC_INTEL_COMMON_BLOCK select SOC_INTEL_COMMON_BLOCK_FAST_SPI select SOC_INTEL_COMMON_BLOCK_ITSS + select SOC_INTEL_COMMON_BLOCK_PMC select SOC_INTEL_COMMON_BLOCK_LPSS select SOC_INTEL_COMMON_BLOCK_PCR select SOC_INTEL_COMMON_BLOCK_SA diff --git a/src/soc/intel/apollolake/bootblock/bootblock.c b/src/soc/intel/apollolake/bootblock/bootblock.c index 2c98be4..23751b6 100644 --- a/src/soc/intel/apollolake/bootblock/bootblock.c +++ b/src/soc/intel/apollolake/bootblock/bootblock.c @@ -112,7 +112,7 @@ enable_pmcbar();
/* Clear global reset promotion bit */ - global_reset_enable(0); + pmc_global_reset_enable(0);
/* Prepare UART for serial console. */ if (IS_ENABLED(CONFIG_SOC_UART_DEBUG)) diff --git a/src/soc/intel/apollolake/chip.c b/src/soc/intel/apollolake/chip.c index 5211f84..4148d41 100644 --- a/src/soc/intel/apollolake/chip.c +++ b/src/soc/intel/apollolake/chip.c @@ -322,9 +322,9 @@ rdev_munmap(&vbt_rdev, vbt);
/* Disable global reset, just in case */ - global_reset_enable(0); + pmc_global_reset_enable(0); /* Make sure payload/OS can't trigger global reset */ - global_reset_lock(); + pmc_global_reset_lock(); }
static void disable_dev(struct device *dev, FSP_S_CONFIG *silconfig) diff --git a/src/soc/intel/apollolake/include/soc/bit_def.h b/src/soc/intel/apollolake/include/soc/bit_def.h new file mode 100644 index 0000000..44b0b13 --- /dev/null +++ b/src/soc/intel/apollolake/include/soc/bit_def.h @@ -0,0 +1,63 @@ +#ifndef _SOC_APOLLOLAKE_BIT_DEFS_H_ +#define _SOC_APOLLOLAKE_BIT_DEFS_H_ + +#ifdef SMI_STS_DEF +[BIOS_SMI_STS] = "BIOS", +[LEGACY_USB_SMI_STS] = "LEGACY USB", +[SLP_SMI_STS] = "SLP_SMI", +[APM_SMI_STS] = "APM", +[SWSMI_TMR_SMI_STS] = "SWSMI_TMR", +[FAKE_PM1_SMI_STS] = "PM1", +[GPIO_SMI_STS]= "GPIO_SMI", +[GPIO_UNLOCK_SMI_STS]= "GPIO_UNLOCK_SSMI", +[MC_SMI_STS] = "MCSMI", +[TCO_SMI_STS] = "TCO", +[PERIODIC_SMI_STS] = "PERIODIC", +[SERIRQ_SMI_STS] = "SERIRQ", +[SMBUS_SMI_STS] = "SMBUS_SMI", +[XHCI_SMI_STS] = "XHCI", +[HSMBUS_SMI_STS] = "HOST_SMBUS", +[SCS_SMI_STS] = "SCS", +[PCIE_SMI_STS] = "PCI_EXP_SMI", +[SCC2_SMI_STS] = "SCC2", +[SPI_SSMI_STS] = "SPI_SSMI", +[SPI_SMI_STS] = "SPI", +[PMC_OCP_SMI_STS] = "OCP_CSE", +#endif + +#ifdef PM1_STS_DEF +[0] = "TMROF", +[5] = "GBL", +[8] = "PWRBTN", +[10] = "RTC", +[11] = "PRBTNOR", +[13] = "USB", +[14] = "PCIEXPWAK", +[15] = "WAK", +#endif + +#ifdef GPE_STS_DEF +[0] = "PCIE_SCI", +[2] = "SWGPE", +[3] = "PCIE_WAKE0", +[4] = "PUNIT", +[6] = "PCIE_WAKE1", +[7] = "PCIE_WAKE2", +[8] = "PCIE_WAKE3", +[9] = "PCI_EXP", +[10] = "BATLOW", +[11] = "CSE_PME", +[12] = "XDCI_PME", +[13] = "XHCI_PME", +[14] = "AVS_PME", +[15] = "GPIO_TIER1_SCI", +[16] = "SMB_WAK", +[17] = "SATA_PME", +#endif + +#ifdef PM1_STS_DEF +[3] = "TIMEOUT", +[17] = "SECOND_TO", +#endif + +#endif //_SOC_APOLLOLAKE_BIT_DEFS_H_ diff --git a/src/soc/intel/apollolake/include/soc/gpe.h b/src/soc/intel/apollolake/include/soc/gpe.h index 5482ed3..7dfb6f5 100644 --- a/src/soc/intel/apollolake/include/soc/gpe.h +++ b/src/soc/intel/apollolake/include/soc/gpe.h @@ -136,4 +136,5 @@ #define GPE0_DW3_30 126 #define GPE0_DW3_31 127
+#define GPE_MAX GPE0_DW3_31 #endif diff --git a/src/soc/intel/apollolake/include/soc/pm.h b/src/soc/intel/apollolake/include/soc/pm.h index 7db63f6..7bad122 100644 --- a/src/soc/intel/apollolake/include/soc/pm.h +++ b/src/soc/intel/apollolake/include/soc/pm.h @@ -20,6 +20,7 @@
#include <stdint.h> #include <arch/acpi.h> +#include <intelblocks/pmc.h>
/* ACPI_BASE_ADDRESS */
@@ -195,26 +196,9 @@ void fixup_power_state(void);
/* Power Management Utility Functions. */ -uint32_t clear_smi_status(void); -uint16_t clear_pm1_status(void); -uint32_t clear_tco_status(void); -uint32_t clear_gpe_status(void); -void clear_pmc_status(void); -void clear_gpi_gpe_sts(void); -uint32_t get_smi_en(void); -void enable_smi(uint32_t mask); -void disable_smi(uint32_t mask); -void enable_pm1(uint16_t events); -void enable_pm1_control(uint32_t mask); -void disable_pm1_control(uint32_t mask); -void enable_gpe(uint32_t mask); -void disable_gpe(uint32_t mask); -void disable_all_gpe(void); +uintptr_t read_pmc_mmio_bar(void); uintptr_t get_pmc_mmio_bar(void); void pmc_gpe_init(void); - -void global_reset_enable(bool enable); -void global_reset_lock(void);
void pch_log_state(void);
diff --git a/src/soc/intel/apollolake/pmc.c b/src/soc/intel/apollolake/pmc.c index ef39630..1cbeb85 100644 --- a/src/soc/intel/apollolake/pmc.c +++ b/src/soc/intel/apollolake/pmc.c @@ -154,7 +154,7 @@ pch_log_state();
/* Now that things have been logged clear out the PMC state. */ - clear_pmc_status(); + pmc_clear_status(); }
static const struct device_operations device_ops = { diff --git a/src/soc/intel/apollolake/pmutil.c b/src/soc/intel/apollolake/pmutil.c index 9999913..5e0e80f 100644 --- a/src/soc/intel/apollolake/pmutil.c +++ b/src/soc/intel/apollolake/pmutil.c @@ -35,7 +35,7 @@ #include <vboot/vboot_common.h> #include "chip.h"
-static uintptr_t read_pmc_mmio_bar(void) +uintptr_t read_pmc_mmio_bar(void) { return PMC_BAR0; } @@ -43,309 +43,6 @@ uintptr_t get_pmc_mmio_bar(void) { return read_pmc_mmio_bar(); -} - -static void print_num_status_bits(int num_bits, uint32_t status, - const char * const bit_names[]) -{ - int i; - - if (!status) - return; - - for (i = num_bits - 1; 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); - } - } -} - -static uint32_t print_smi_status(uint32_t smi_sts) -{ - static const char * const smi_sts_bits[] = { - [BIOS_SMI_STS] = "BIOS", - [LEGACY_USB_SMI_STS] = "LEGACY USB", - [SLP_SMI_STS] = "SLP_SMI", - [APM_SMI_STS] = "APM", - [SWSMI_TMR_SMI_STS] = "SWSMI_TMR", - [FAKE_PM1_SMI_STS] = "PM1", - [GPIO_SMI_STS] = "GPIO_SMI", - [GPIO_UNLOCK_SMI_STS] = "GPIO_UNLOCK_SSMI", - [MC_SMI_STS] = "MCSMI", - [TCO_SMI_STS] = "TCO", - [PERIODIC_SMI_STS] = "PERIODIC", - [SERIRQ_SMI_STS] = "SERIRQ", - [SMBUS_SMI_STS] = "SMBUS_SMI", - [XHCI_SMI_STS] = "XHCI", - [HSMBUS_SMI_STS] = "HOST_SMBUS", - [SCS_SMI_STS] = "SCS", - [PCIE_SMI_STS] = "PCI_EXP_SMI", - [SCC2_SMI_STS] = "SCC2", - [SPI_SSMI_STS] = "SPI_SSMI", - [SPI_SMI_STS] = "SPI", - [PMC_OCP_SMI_STS] = "OCP_CSE", - }; - - if (!smi_sts) - return 0; - - printk(BIOS_DEBUG, "SMI_STS: "); - print_num_status_bits(ARRAY_SIZE(smi_sts_bits), smi_sts, smi_sts_bits); - printk(BIOS_DEBUG, "\n"); - - return smi_sts; -} - -static uint32_t reset_smi_status(void) -{ - uint32_t smi_sts = inl(ACPI_PMIO_BASE + SMI_STS); - outl(smi_sts, ACPI_PMIO_BASE + SMI_STS); - return smi_sts; -} - -uint32_t clear_smi_status(void) -{ - uint32_t sts = reset_smi_status(); - - /* - * Check for power button status if nothing else is indicating an SMI - * and SMIs aren't turned into SCIs. Apparently, there is no PM1 status - * bit in the SMI status register. That makes things difficult for - * determining if the power button caused an SMI. - */ - if (sts == 0 && !(inl(ACPI_PMIO_BASE + PM1_CNT) & SCI_EN)) { - uint16_t pm1_sts = inw(ACPI_PMIO_BASE + PM1_STS); - - /* Fake PM1 status bit if power button pressed. */ - if (pm1_sts & PWRBTN_STS) - sts |= (1 << FAKE_PM1_SMI_STS); - } - - return print_smi_status(sts); -} - -uint32_t get_smi_en(void) -{ - return inl(ACPI_PMIO_BASE + SMI_EN); -} - -void enable_smi(uint32_t mask) -{ - uint32_t smi_en = inl(ACPI_PMIO_BASE + SMI_EN); - smi_en |= mask; - outl(smi_en, ACPI_PMIO_BASE + SMI_EN); -} - -void disable_smi(uint32_t mask) -{ - uint32_t smi_en = inl(ACPI_PMIO_BASE + SMI_EN); - smi_en &= ~mask; - outl(smi_en, ACPI_PMIO_BASE + SMI_EN); -} - -void enable_pm1_control(uint32_t mask) -{ - uint32_t pm1_cnt = inl(ACPI_PMIO_BASE + PM1_CNT); - pm1_cnt |= mask; - outl(pm1_cnt, ACPI_PMIO_BASE + PM1_CNT); -} - -void disable_pm1_control(uint32_t mask) -{ - uint32_t pm1_cnt = inl(ACPI_PMIO_BASE + PM1_CNT); - pm1_cnt &= ~mask; - outl(pm1_cnt, ACPI_PMIO_BASE + PM1_CNT); -} - -static uint16_t reset_pm1_status(void) -{ - uint16_t pm1_sts = inw(ACPI_PMIO_BASE + PM1_STS); - outw(pm1_sts, ACPI_PMIO_BASE + PM1_STS); - return pm1_sts; -} - -static uint16_t print_pm1_status(uint16_t pm1_sts) -{ - static const char * const pm1_sts_bits[] = { - [0] = "TMROF", - [5] = "GBL", - [8] = "PWRBTN", - [10] = "RTC", - [11] = "PRBTNOR", - [13] = "USB", - [14] = "PCIEXPWAK", - [15] = "WAK", - }; - - if (!pm1_sts) - return 0; - - printk(BIOS_SPEW, "PM1_STS: "); - print_num_status_bits(ARRAY_SIZE(pm1_sts_bits), pm1_sts, pm1_sts_bits); - printk(BIOS_SPEW, "\n"); - - return pm1_sts; -} - -uint16_t clear_pm1_status(void) -{ - return print_pm1_status(reset_pm1_status()); -} - -void enable_pm1(uint16_t events) -{ - outw(events, ACPI_PMIO_BASE + PM1_EN); -} - -static uint32_t print_tco_status(uint32_t tco_sts) -{ - static const char * const tco_sts_bits[] = { - [3] = "TIMEOUT", - [17] = "SECOND_TO", - }; - - if (!tco_sts) - return 0; - - printk(BIOS_DEBUG, "TCO_STS: "); - print_num_status_bits(ARRAY_SIZE(tco_sts_bits), tco_sts, tco_sts_bits); - printk(BIOS_DEBUG, "\n"); - - return tco_sts; -} - -static uint32_t reset_tco_status(void) -{ - uint32_t tco_sts = inl(ACPI_PMIO_BASE + TCO_STS); - uint32_t tco_en = inl(ACPI_PMIO_BASE + TCO1_CNT); - - outl(tco_sts, ACPI_PMIO_BASE + TCO_STS); - return tco_sts & tco_en; -} - -uint32_t clear_tco_status(void) -{ - return print_tco_status(reset_tco_status()); -} - -void enable_gpe(uint32_t mask) -{ - uint32_t gpe0a_en = inl(ACPI_PMIO_BASE + GPE0_EN(0)); - gpe0a_en |= mask; - outl(gpe0a_en, ACPI_PMIO_BASE + GPE0_EN(0)); -} - -void disable_gpe(uint32_t mask) -{ - uint32_t gpe0a_en = inl(ACPI_PMIO_BASE + GPE0_EN(0)); - gpe0a_en &= ~mask; - outl(gpe0a_en, ACPI_PMIO_BASE + GPE0_EN(0)); -} - -void disable_all_gpe(void) -{ - disable_gpe(~0); -} - -/* Clear the gpio gpe0 status bits in ACPI registers */ -void clear_gpi_gpe_sts(void) -{ - int i; - - for (i = 1; i < GPE0_REG_MAX; i++) { - uint32_t gpe_sts = inl(ACPI_PMIO_BASE + GPE0_STS(i)); - outl(gpe_sts, ACPI_PMIO_BASE + GPE0_STS(i)); - } -} - -static uint32_t reset_gpe_status(void) -{ - uint32_t gpe_sts = inl(ACPI_PMIO_BASE + GPE0_STS(0)); - outl(gpe_sts, ACPI_PMIO_BASE + GPE0_STS(0)); - return gpe_sts; -} - -static uint32_t print_gpe_sts(uint32_t gpe_sts) -{ - static const char * const gpe_sts_bits[] = { - [0] = "PCIE_SCI", - [2] = "SWGPE", - [3] = "PCIE_WAKE0", - [4] = "PUNIT", - [6] = "PCIE_WAKE1", - [7] = "PCIE_WAKE2", - [8] = "PCIE_WAKE3", - [9] = "PCI_EXP", - [10] = "BATLOW", - [11] = "CSE_PME", - [12] = "XDCI_PME", - [13] = "XHCI_PME", - [14] = "AVS_PME", - [15] = "GPIO_TIER1_SCI", - [16] = "SMB_WAK", - [17] = "SATA_PME", - }; - - if (!gpe_sts) - return gpe_sts; - - printk(BIOS_DEBUG, "GPE0a_STS: "); - print_num_status_bits(ARRAY_SIZE(gpe_sts_bits), gpe_sts, gpe_sts_bits); - printk(BIOS_DEBUG, "\n"); - - return gpe_sts; -} - -uint32_t clear_gpe_status(void) -{ - return print_gpe_sts(reset_gpe_status()); -} - -/* 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_DW3_31) - 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_PMIO_BASE + GPE0_STS(bank)); - if (sts & mask) { - outl(mask, ACPI_PMIO_BASE + GPE0_STS(bank)); - rc = 1; - } - } while (sts & mask); - - return rc; -} - -void clear_pmc_status(void) -{ - uint32_t prsts; - uint32_t gen_pmcon1; - uintptr_t pmc_bar0 = read_pmc_mmio_bar(); - - prsts = read32((void *)(pmc_bar0 + PRSTS)); - gen_pmcon1 = read32((void *)(pmc_bar0 + GEN_PMCON1)); - - /* Clear the status bits. The RPS field is cleared on a 0 write. */ - write32((void *)(pmc_bar0 + GEN_PMCON1), gen_pmcon1 & ~RPS); - write32((void *)(pmc_bar0 + PRSTS), prsts); }
@@ -439,64 +136,6 @@
return acpi_sleep_from_pm1(inl(ACPI_PMIO_BASE + PM1_CNT)) == ACPI_S3; } - -/* - * If possible, lock 0xcf9. Once the register is locked, it can't be changed. - * This lock is reset on cold boot, hard reset, soft reset and Sx. - */ -void global_reset_lock(void) -{ - uintptr_t etr = read_pmc_mmio_bar() + ETR; - uint32_t reg; - - reg = read32((void *)etr); - if (reg & CF9_LOCK) - return; - reg |= CF9_LOCK; - write32((void *)etr, reg); -} - -/* - * Enable or disable global reset. If global reset is enabled, hard reset and - * soft reset will trigger global reset, where both host and TXE are reset. - * This is cleared on cold boot, hard reset, soft reset and Sx. - */ -void global_reset_enable(bool enable) -{ - uintptr_t etr = read_pmc_mmio_bar() + ETR; - uint32_t reg; - - reg = read32((void *)etr); - reg = enable ? reg | CF9_GLB_RST : reg & ~CF9_GLB_RST; - write32((void *)etr, reg); -} - -/* - * The PM1 control is set to S5 when vboot requests a reboot because the power - * state code above may not have collected its 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) -{ - const uint16_t port = ACPI_PMIO_BASE + PM1_CNT; - outl((inl(port) & ~(SLP_TYP)) | (SLP_TYP_S5 << SLP_TYP_SHIFT), port); -} - -void poweroff(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(); -} - void pmc_gpe_init(void) { uint32_t gpio_cfg = 0; diff --git a/src/soc/intel/apollolake/reset.c b/src/soc/intel/apollolake/reset.c index 56273cc..c5d815e 100644 --- a/src/soc/intel/apollolake/reset.c +++ b/src/soc/intel/apollolake/reset.c @@ -25,7 +25,7 @@
void global_reset(void) { - global_reset_enable(1); + pmc_global_reset_enable(1); hard_reset(); }
diff --git a/src/soc/intel/apollolake/smi.c b/src/soc/intel/apollolake/smi.c index 3ad33fd..227f2f0 100644 --- a/src/soc/intel/apollolake/smi.c +++ b/src/soc/intel/apollolake/smi.c @@ -30,7 +30,7 @@ { printk(BIOS_DEBUG, "Initializing Southbridge SMI...");
- if (get_smi_en() & APMC_EN) { + if (pmc_get_smi_en() & APMC_EN) { printk(BIOS_INFO, "SMI# handler already enabled?\n"); return; } @@ -38,33 +38,33 @@ printk(BIOS_DEBUG, "Done\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(PWRBTN_EN | GBL_EN); - disable_gpe(PME_B0_EN); + pmc_enable_pm1(PWRBTN_EN | GBL_EN); + pmc_disable_gpe(PME_B0_EN);
/* Enable SMI generation */ - enable_smi(APMC_EN | SLP_SMI_EN | GBL_SMI_EN | EOS | GPIO_EN); + pmc_enable_smi(APMC_EN | SLP_SMI_EN | GBL_SMI_EN | EOS | GPIO_EN); }
void southbridge_clear_smi_status(void) { /* Clear SMI status */ - clear_smi_status(); + pmc_clear_smi_status();
/* Clear PM1 status */ - clear_pm1_status(); + pmc_clear_pm1_status();
/* Set EOS bit so other SMIs can occur. */ - enable_smi(EOS); + pmc_enable_smi(EOS); }
void smm_setup_structures(void *gnvs, void *tcg, void *smi1)