From b3dfcb863cdc62cd2cb65e97e0043311b151c558 Mon Sep 17 00:00:00 2001 From: Lijian Zhao Date: Wed, 16 Aug 2017 22:18:52 -0700 Subject: [PATCH] soc/intel/cannonlake: Enable common PMC code for CNL This update changes Cannonlake to use the new common PMC code. This will help to reduce code duplication and streamline code bring up. Change-Id: Ia69fee8985e1c39b0e4b104c51439bca1a5493ac Signed-off-by: Lijian Zhao Reviewed-on: https://review.coreboot.org/21062 Tested-by: build bot (Jenkins) Reviewed-by: Aaron Durbin --- src/soc/intel/cannonlake/Kconfig | 2 + src/soc/intel/cannonlake/Makefile.inc | 4 + src/soc/intel/cannonlake/bootblock/pch.c | 2 +- src/soc/intel/cannonlake/chip.h | 7 + src/soc/intel/cannonlake/include/soc/gpe.h | 134 +++++++++++ src/soc/intel/cannonlake/include/soc/pm.h | 118 +++++++++- src/soc/intel/cannonlake/include/soc/pmc.h | 16 +- src/soc/intel/cannonlake/include/soc/smbus.h | 4 +- src/soc/intel/cannonlake/pmutil.c | 217 ++++++++++++++++++ .../intel/cannonlake/romstage/power_state.c | 88 ++++++- src/soc/intel/cannonlake/romstage/romstage.c | 9 +- 11 files changed, 580 insertions(+), 21 deletions(-) create mode 100644 src/soc/intel/cannonlake/include/soc/gpe.h create mode 100644 src/soc/intel/cannonlake/pmutil.c diff --git a/src/soc/intel/cannonlake/Kconfig b/src/soc/intel/cannonlake/Kconfig index fb2ed69794..4267ba95d5 100644 --- a/src/soc/intel/cannonlake/Kconfig +++ b/src/soc/intel/cannonlake/Kconfig @@ -7,6 +7,7 @@ if SOC_INTEL_CANNONLAKE config CPU_SPECIFIC_OPTIONS def_bool y + select ACPI_INTEL_HARDWARE_SLEEP_VALUES select ARCH_BOOTBLOCK_X86_32 select ARCH_RAMSTAGE_X86_32 select ARCH_ROMSTAGE_X86_32 @@ -34,6 +35,7 @@ config CPU_SPECIFIC_OPTIONS select SOC_INTEL_COMMON_BLOCK_GSPI select SOC_INTEL_COMMON_BLOCK_LPSS select SOC_INTEL_COMMON_BLOCK_PCR + select SOC_INTEL_COMMON_BLOCK_PMC select SOC_INTEL_COMMON_BLOCK_RTC select SOC_INTEL_COMMON_BLOCK_SA select SOC_INTEL_COMMON_BLOCK_SMBUS diff --git a/src/soc/intel/cannonlake/Makefile.inc b/src/soc/intel/cannonlake/Makefile.inc index 8a83eb0578..10d444be4b 100644 --- a/src/soc/intel/cannonlake/Makefile.inc +++ b/src/soc/intel/cannonlake/Makefile.inc @@ -9,6 +9,7 @@ bootblock-$(CONFIG_DRIVERS_UART_8250MEM) += uart.c bootblock-y += bootblock/bootblock.c bootblock-y += bootblock/cpu.c bootblock-y += bootblock/pch.c +bootblock-y += pmutil.c bootblock-y += bootblock/report_platform.c bootblock-y += gpio.c bootblock-y += gspi.c @@ -18,6 +19,7 @@ bootblock-$(CONFIG_UART_DEBUG) += uart.c romstage-y += gspi.c romstage-y += memmap.c +romstage-y += pmutil.c romstage-y += reset.c romstage-y += spi.c romstage-$(CONFIG_UART_DEBUG) += uart.c @@ -25,12 +27,14 @@ romstage-$(CONFIG_UART_DEBUG) += uart.c ramstage-y += chip.c ramstage-y += gspi.c ramstage-y += memmap.c +ramstage-y += pmutil.c ramstage-$(CONFIG_PLATFORM_USES_FSP2_0) += reset.c ramstage-y += spi.c ramstage-y += systemagent.c ramstage-$(CONFIG_UART_DEBUG) += uart.c postcar-y += memmap.c +postcar-y += pmutil.c postcar-y += spi.c postcar-$(CONFIG_UART_DEBUG) += uart.c diff --git a/src/soc/intel/cannonlake/bootblock/pch.c b/src/soc/intel/cannonlake/bootblock/pch.c index 21a06e4ff5..0062c0d61c 100644 --- a/src/soc/intel/cannonlake/bootblock/pch.c +++ b/src/soc/intel/cannonlake/bootblock/pch.c @@ -26,7 +26,7 @@ #include #include #include -#include +#include #include #define PCR_PSF3_TO_SHDW_PMC_REG_BASE 0x1400 diff --git a/src/soc/intel/cannonlake/chip.h b/src/soc/intel/cannonlake/chip.h index 67be85dd25..38f9a1ff7b 100644 --- a/src/soc/intel/cannonlake/chip.h +++ b/src/soc/intel/cannonlake/chip.h @@ -24,6 +24,13 @@ struct soc_intel_cannonlake_config { /* GSPI */ struct gspi_cfg gspi[CONFIG_SOC_INTEL_COMMON_BLOCK_GSPI_MAX]; + + /* Gpio group routed to each dword of the GPE0 block. Values are + * of the form GPP_[A:G] or GPD. */ + uint8_t gpe0_dw0; /* GPE0_31_0 STS/EN */ + uint8_t gpe0_dw1; /* GPE0_63_32 STS/EN */ + uint8_t gpe0_dw2; /* GPE0_95_64 STS/EN */ + }; typedef struct soc_intel_cannonlake_config config_t; diff --git a/src/soc/intel/cannonlake/include/soc/gpe.h b/src/soc/intel/cannonlake/include/soc/gpe.h new file mode 100644 index 0000000000..521d523746 --- /dev/null +++ b/src/soc/intel/cannonlake/include/soc/gpe.h @@ -0,0 +1,134 @@ +/* + * This file is part of the coreboot project. + * + * Copyright 2015 Google Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#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 GPE0_DW0_03 3 +#define GPE0_DW0_04 4 +#define GPE0_DW0_05 5 +#define GPE0_DW0_06 6 +#define GPE0_DW0_07 7 +#define GPE0_DW0_08 8 +#define GPE0_DW0_09 9 +#define GPE0_DW0_10 10 +#define GPE0_DW0_11 11 +#define GPE0_DW0_12 12 +#define GPE0_DW0_13 13 +#define GPE0_DW0_14 14 +#define GPE0_DW0_15 15 +#define GPE0_DW0_16 16 +#define GPE0_DW0_17 17 +#define GPE0_DW0_18 18 +#define GPE0_DW0_19 19 +#define GPE0_DW0_20 20 +#define GPE0_DW0_21 21 +#define GPE0_DW0_22 22 +#define GPE0_DW0_23 23 +#define GPE0_DW0_24 24 +#define GPE0_DW0_25 25 +#define GPE0_DW0_26 26 +#define GPE0_DW0_27 27 +#define GPE0_DW0_28 28 +#define GPE0_DW0_29 29 +#define GPE0_DW0_30 30 +#define GPE0_DW0_31 31 +/* GPE_63_32 */ +#define GPE0_DW1_00 32 +#define GPE0_DW1_01 33 +#define GPE0_DW1_02 34 +#define GPE0_DW1_03 36 +#define GPE0_DW1_04 36 +#define GPE0_DW1_05 37 +#define GPE0_DW1_06 38 +#define GPE0_DW1_07 39 +#define GPE0_DW1_08 40 +#define GPE0_DW1_09 41 +#define GPE0_DW1_10 42 +#define GPE0_DW1_11 43 +#define GPE0_DW1_12 44 +#define GPE0_DW1_13 45 +#define GPE0_DW1_14 46 +#define GPE0_DW1_15 47 +#define GPE0_DW1_16 48 +#define GPE0_DW1_17 49 +#define GPE0_DW1_18 50 +#define GPE0_DW1_19 51 +#define GPE0_DW1_20 52 +#define GPE0_DW1_21 53 +#define GPE0_DW1_22 54 +#define GPE0_DW1_23 55 +#define GPE0_DW1_24 56 +#define GPE0_DW1_25 57 +#define GPE0_DW1_26 58 +#define GPE0_DW1_27 59 +#define GPE0_DW1_28 60 +#define GPE0_DW1_29 61 +#define GPE0_DW1_30 62 +#define GPE0_DW1_31 63 +/* GPE_95_64 */ +#define GPE0_DW2_00 64 +#define GPE0_DW2_01 65 +#define GPE0_DW2_02 66 +#define GPE0_DW2_03 67 +#define GPE0_DW2_04 68 +#define GPE0_DW2_05 69 +#define GPE0_DW2_06 70 +#define GPE0_DW2_07 71 +#define GPE0_DW2_08 72 +#define GPE0_DW2_09 73 +#define GPE0_DW2_10 74 +#define GPE0_DW2_11 75 +#define GPE0_DW2_12 76 +#define GPE0_DW2_13 77 +#define GPE0_DW2_14 78 +#define GPE0_DW2_15 79 +#define GPE0_DW2_16 80 +#define GPE0_DW2_17 81 +#define GPE0_DW2_18 82 +#define GPE0_DW2_19 83 +#define GPE0_DW2_20 84 +#define GPE0_DW2_21 85 +#define GPE0_DW2_22 86 +#define GPE0_DW2_23 87 +#define GPE0_DW2_24 88 +#define GPE0_DW2_25 89 +#define GPE0_DW2_26 90 +#define GPE0_DW2_27 91 +#define GPE0_DW2_28 92 +#define GPE0_DW2_29 93 +#define GPE0_DW2_30 94 +#define GPE0_DW2_31 95 +/* GPE_STD */ +#define GPE0_HOT_PLUG 97 +#define GPE0_SWGPE 98 +#define GPE0_TCOSCI 102 +#define GPE0_SMB_WAK 103 +#define GPE0_PCI_EXP 105 +#define GPE0_BATLOW 106 +#define GPE0_PME 107 +#define GPE0_ME_SCI 108 +#define GPE0_PME_B0 109 +#define GPE0_ESPI 110 +#define GPE0_GPIO_T2 111 +#define GPE0_LAN_WAK 112 +#define GPE0_WADT 114 + +#define GPE_MAX GPE0_WADT +#endif /* _SOC_GPE_H_ */ diff --git a/src/soc/intel/cannonlake/include/soc/pm.h b/src/soc/intel/cannonlake/include/soc/pm.h index 66541228fe..abf7db9b32 100644 --- a/src/soc/intel/cannonlake/include/soc/pm.h +++ b/src/soc/intel/cannonlake/include/soc/pm.h @@ -18,22 +18,124 @@ #define _SOC_PM_H_ #include +#include +#include +#include +#include #include +#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 BM_STS (1 << 4) +#define TMROF_STS (1 << 0) #define PM1_EN 0x02 +#define PCIEXPWAK_DIS (1 << 14) +#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 BM_RLD (1 << 1) +#define SCI_EN (1 << 0) +#define PM1_TMR 0x08 #define SMI_EN 0x30 +#define XHCI_SMI_EN (1 << 31) +#define ME_SMI_EN (1 << 30) #define ESPI_SMI_EN (1 << 28) +#define GPIO_UNLOCK_SMI_EN (1 << 27) +#define INTEL_USB2_EN (1 << 18) +#define LEGACY_USB2_EN (1 << 17) +#define PERIODIC_EN (1 << 14) +#define TCO_SMI_EN (1 << 13) +#define MCSMI_EN (1 << 11) +#define BIOS_RLS (1 << 7) +#define SWSMI_TMR_EN (1 << 6) #define APMC_EN (1 << 5) #define SLP_SMI_EN (1 << 4) +#define LEGACY_USB_EN (1 << 3) +#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 XHCI_SMI_STS_BIT 31 +#define ME_SMI_STS_BIT 30 +#define ESPI_SMI_STS_BIT 28 +#define GPIO_UNLOCK_SMI_STS_BIT 27 +#define SPI_SMI_STS_BIT 26 +#define SCC_SMI_STS_BIT 25 +#define MONITOR_STS_BIT 21 +#define PCI_EXP_SMI_STS_BIT 20 +#define SMBUS_SMI_STS_BIT 16 +#define SERIRQ_SMI_STS_BIT 15 +#define PERIODIC_STS_BIT 14 +#define TCO_STS_BIT 13 +#define DEVMON_STS_BIT 12 +#define MCSMI_STS_BIT 11 +#define GPIO_STS_BIT 10 +#define GPE0_STS_BIT 9 +#define PM1_STS_BIT 8 +#define SWSMI_TMR_STS_BIT 6 +#define APM_STS_BIT 5 +#define SMI_ON_SLP_EN_STS_BIT 4 +#define LEGACY_USB_STS_BIT 3 +#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) (0x60 + ((x) * 4)) +#define GPE_31_0 0 /* 0x60/0x70 = GPE[31:0] */ +#define GPE_63_32 1 /* 0x64/0x74 = GPE[63:32] */ +#define GPE_95_64 2 /* 0x68/0x78 = GPE[95:64] */ +#define GPE_STD 3 /* 0x6c/0x7c = Standard GPE */ +#define GPE_STS_RSVD GPE_STD +#define WADT_STS (1 << 18) +#define GPIO_T2_STS (1 << 15) +#define ESPI_STS (1 << 14) +#define PME_B0_STS (1 << 13) +#define ME_SCI_STS (1 << 12) +#define PME_STS (1 << 11) +#define BATLOW_STS (1 << 10) +#define PCI_EXP_STS (1 << 9) +#define SMB_WAK_STS (1 << 7) +#define TCOSCI_STS (1 << 6) +#define SWGPE_STS (1 << 2) +#define HOT_PLUG_STS (1 << 1) #define GPE0_EN(x) (0x70 + ((x) * 4)) -#define PME_B0_EN (1 << 13) +#define WADT_EN (1 << 18) +#define GPIO_T2_EN (1 << 15) +#define ESPI_EN (1 << 14) +#define PME_B0_EN (1 << 13) +#define ME_SCI_EN (1 << 12) +#define PME_EN (1 << 11) +#define BATLOW_EN (1 << 10) +#define PCI_EXP_EN (1 << 9) +#define TCOSCI_EN (1 << 6) +#define SWGPE_EN (1 << 2) +#define HOT_PLUG_EN (1 << 1) +#define EN_BLOCK 3 + +/* + * Enable SMI generation: + * - on APMC writes (io 0xb2) + * - on writes to SLP_EN (sleep states) + * - on writes to GBL_RLS (bios commands) + * - on eSPI events (does nothing on LPC systems) + * No SMIs: + * - on microcontroller writes (io 0x62/0x66) + * - on TCO events + */ #define ENABLE_SMI_PARAMS \ (APMC_EN | SLP_SMI_EN | GBL_SMI_EN | ESPI_SMI_EN | EOS) @@ -51,6 +153,16 @@ struct chipset_power_state { uint32_t prev_sleep_state; } __attribute__ ((packed)); -struct chipset_power_state *fill_power_state(void); +/* 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); #endif diff --git a/src/soc/intel/cannonlake/include/soc/pmc.h b/src/soc/intel/cannonlake/include/soc/pmc.h index 0bca332ac5..b8e49c2286 100644 --- a/src/soc/intel/cannonlake/include/soc/pmc.h +++ b/src/soc/intel/cannonlake/include/soc/pmc.h @@ -71,9 +71,9 @@ #define SMI_LOCK (1 << 4) #define RTC_BATTERY_DEAD (1 << 2) -#define ETR3 0x1048 -#define ETR3_CF9LOCK (1 << 31) -#define ETR3_CF9GR (1 << 20) +#define ETR 0x1048 +#define CF9_LOCK (1 << 31) +#define CF9_GLB_RST (1 << 20) #define SSML 0x104C #define SSML_SSL_DS (0 << 0) @@ -85,6 +85,8 @@ #define SSMD 0x1054 #define SSMD_SSD_MASK (0xffff << 0) +#define PRSTS 0x1810 + #define S3_PWRGATE_POL 0x1828 #define S3DC_GATE_SUS (1 << 1) #define S3AC_GATE_SUS (1 << 0) @@ -109,11 +111,9 @@ #define PCH2CPU_TT_EN (1 << 26) #define PCH_PWRM_ACPI_TMR_CTL 0x18FC -#define GPIO_CFG 0x1920 -#define GPE0_DWX_MASK 0xf -#define GPE0_DW0_SHIFT 0 -#define GPE0_DW1_SHIFT 4 -#define GPE0_DW2_SHIFT 8 +#define GPIO_GPE_CFG 0x1920 +#define GPE0_DWX_MASK 0xf +#define GPE0_DW_SHIFT(x) (4*(x)) #define GBLRST_CAUSE0 0x1924 #define GBLRST_CAUSE0_THERMTRIP (1 << 5) diff --git a/src/soc/intel/cannonlake/include/soc/smbus.h b/src/soc/intel/cannonlake/include/soc/smbus.h index 9de6981d5a..9f1cf34862 100644 --- a/src/soc/intel/cannonlake/include/soc/smbus.h +++ b/src/soc/intel/cannonlake/include/soc/smbus.h @@ -30,9 +30,9 @@ /* TCO registers and fields live behind TCOBASE I/O bar in SMBus device. */ #define TCO1_STS 0x04 +#define TCO_TIMEOUT (1 << 3) #define TCO2_STS 0x06 -#define TCO2_STS_SECOND_TO 0x02 -#define TCO2_STS_BOOT 0x04 +#define TCO2_STS_SECOND_TO (1 << 1) #define TCO1_CNT 0x08 #define TCO_LOCK (1 << 12) #define TCO_TMR_HLT (1 << 11) diff --git a/src/soc/intel/cannonlake/pmutil.c b/src/soc/intel/cannonlake/pmutil.c new file mode 100644 index 0000000000..455c9692ed --- /dev/null +++ b/src/soc/intel/cannonlake/pmutil.c @@ -0,0 +1,217 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2014 Google Inc. + * Copyright (C) 2015 Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +/* + * Helper functions for dealing with power management registers + * and the differences between PCH variants. + */ + +#define __SIMPLE_DEVICE__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "chip.h" + +/* + * SMI + */ + +const char *const *soc_smi_sts_array(size_t *a) +{ + static const char *const smi_sts_bits[] = { + [BIOS_STS_BIT] = "BIOS", + [LEGACY_USB_STS_BIT] = "LEGACY_USB", + [SMI_ON_SLP_EN_STS_BIT] = "SLP_SMI", + [APM_STS_BIT] = "APM", + [SWSMI_TMR_STS_BIT] = "SWSMI_TMR", + [PM1_STS_BIT] = "PM1", + [GPE0_STS_BIT] = "GPE0", + [GPIO_STS_BIT] = "GPI", + [MCSMI_STS_BIT] = "MCSMI", + [DEVMON_STS_BIT] = "DEVMON", + [TCO_STS_BIT] = "TCO", + [PERIODIC_STS_BIT] = "PERIODIC", + [SERIRQ_SMI_STS_BIT] = "SERIRQ_SMI", + [SMBUS_SMI_STS_BIT] = "SMBUS_SMI", + [PCI_EXP_SMI_STS_BIT] = "PCI_EXP_SMI", + [MONITOR_STS_BIT] = "MONITOR", + [SPI_SMI_STS_BIT] = "SPI", + [GPIO_UNLOCK_SMI_STS_BIT] = "GPIO_UNLOCK", + [ESPI_SMI_STS_BIT] = "ESPI_SMI", + }; + + *a = ARRAY_SIZE(smi_sts_bits); + return smi_sts_bits; +} + +/* + * TCO + */ + +const char *const *soc_tco_sts_array(size_t *a) +{ + static const char *const tco_sts_bits[] = { + [0] = "NMI2SMI", + [1] = "SW_TCO", + [2] = "TCO_INT", + [3] = "TIMEOUT", + [7] = "NEWCENTURY", + [8] = "BIOSWR", + [9] = "DMISCI", + [10] = "DMISMI", + [12] = "DMISERR", + [13] = "SLVSEL", + [16] = "INTRD_DET", + [17] = "SECOND_TO", + [18] = "BOOT", + [20] = "SMLINK_SLV" + }; + + *a = ARRAY_SIZE(tco_sts_bits); + return tco_sts_bits; +} + +/* + * GPE0 + */ + +const char *const *soc_gpe_sts_array(size_t *a) +{ + static const char *const gpe_sts_bits[] = { + [1] = "HOTPLUG", + [2] = "SWGPE", + [6] = "TCO_SCI", + [7] = "SMB_WAK", + [9] = "PCI_EXP", + [10] = "BATLOW", + [11] = "PME", + [12] = "ME", + [13] = "PME_B0", + [14] = "eSPI", + [15] = "GPIO Tier-2", + [16] = "LAN_WAKE", + [18] = "WADT" + }; + + *a = ARRAY_SIZE(gpe_sts_bits); + return gpe_sts_bits; +} + +int acpi_sci_irq(void) +{ + int scis = pci_read_config32(PCH_DEV_PMC, ACTL) & SCI_IRQ_SEL; + int sci_irq = 9; + + /* Determine how SCI is routed. */ + switch (scis) { + case SCIS_IRQ9: + case SCIS_IRQ10: + case SCIS_IRQ11: + sci_irq = scis - SCIS_IRQ9 + 9; + break; + case SCIS_IRQ20: + case SCIS_IRQ21: + case SCIS_IRQ22: + case SCIS_IRQ23: + sci_irq = scis - SCIS_IRQ20 + 20; + break; + default: + printk(BIOS_DEBUG, "Invalid SCI route! Defaulting to IRQ9.\n"); + sci_irq = 9; + break; + } + + printk(BIOS_DEBUG, "SCI is IRQ%d\n", sci_irq); + return sci_irq; +} + +uint8_t *pmc_mmio_regs(void) +{ + uint32_t reg32; + + reg32 = pci_read_config32(PCH_DEV_PMC, PWRMBASE); + + return (void *)(uintptr_t)ALIGN_DOWN(reg32, 4 * KiB); +} + +uint16_t smbus_tco_regs(void) +{ + uint16_t reg16; + + reg16 = pci_read_config16(PCH_DEV_SMBUS, TCOBASE); + + return ALIGN_DOWN(reg16, 0x20); +} + +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; + 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) +{ + return (uintptr_t)pmc_mmio_regs(); +} + +void soc_get_gpe_configs(uint8_t *dw0, uint8_t *dw1, uint8_t *dw2) +{ + DEVTREE_CONST struct soc_intel_cannonlake_config *config; + + /* 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"); + } + config = dev->chip_info; + + /* Assign to out variable */ + *dw0 = config->gpe0_dw0; + *dw1 = config->gpe0_dw1; + *dw2 = config->gpe0_dw2; +} diff --git a/src/soc/intel/cannonlake/romstage/power_state.c b/src/soc/intel/cannonlake/romstage/power_state.c index 2c45ad9354..46048db75b 100644 --- a/src/soc/intel/cannonlake/romstage/power_state.c +++ b/src/soc/intel/cannonlake/romstage/power_state.c @@ -18,14 +18,94 @@ #include #include #include +#include +#include +#include +#include #include static struct chipset_power_state power_state CAR_GLOBAL; -/* Fill power state structure from ACPI PM registers */ -struct chipset_power_state *fill_power_state(void) +static void migrate_power_state(int is_recovery) { - struct chipset_power_state *ps = car_get_var_ptr(&power_state); + struct chipset_power_state *ps_cbmem; + struct chipset_power_state *ps_car; - return ps; + ps_car = car_get_var_ptr(&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) + +static inline int deep_s3_enabled(void) +{ + uint32_t deep_s3_pol; + + deep_s3_pol = read32(pmc_mmio_regs() + S3_PWRGATE_POL); + return !!(deep_s3_pol & (S3DC_GATE_SUS | S3AC_GATE_SUS)); +} + +/* 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->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, + * need to check both deep sleep well and normal suspend well. + * Otherwise just check deep sleep well. + */ + if (prev_sleep_state == ACPI_S3) { + /* PWR_FLR represents deep sleep power well loss. */ + uint32_t mask = PWR_FLR; + + /* If deep s3 isn't enabled check the suspend well too. */ + if (!deep_s3_enabled()) + mask |= SUS_PWR_FLR; + + if (ps->gen_pmcon_b & mask) + prev_sleep_state = ACPI_S5; + } + + return prev_sleep_state; +} + +void soc_fill_power_state(struct chipset_power_state *ps) +{ + uint16_t tcobase; + uint8_t *pmc; + + tcobase = smbus_tco_regs(); + + ps->tco1_sts = inw(tcobase + TCO1_STS); + ps->tco2_sts = inw(tcobase + TCO2_STS); + + printk(BIOS_DEBUG, "TCO_STS: %04x %04x\n", + ps->tco1_sts, ps->tco2_sts); + + pmc = pmc_mmio_regs(); + ps->gen_pmcon_a = read32(pmc + GEN_PMCON_A); + ps->gen_pmcon_b = read32(pmc + GEN_PMCON_B); + 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]); } diff --git a/src/soc/intel/cannonlake/romstage/romstage.c b/src/soc/intel/cannonlake/romstage/romstage.c index 2f8617e4cf..ab0e19bdc6 100644 --- a/src/soc/intel/cannonlake/romstage/romstage.c +++ b/src/soc/intel/cannonlake/romstage/romstage.c @@ -14,30 +14,33 @@ */ #include +#include #include #include #include #include +#include #include #include #include #include +static struct chipset_power_state power_state CAR_GLOBAL; + asmlinkage void car_stage_entry(void) { bool s3wake; struct postcar_frame pcf; uintptr_t top_of_ram; - struct chipset_power_state *ps; + struct chipset_power_state *ps = car_get_var_ptr(&power_state); console_init(); /* Program MCHBAR, DMIBAR, GDXBAR and EDRAMBAR */ systemagent_early_init(); - ps = fill_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); if (postcar_frame_init(&pcf, 1 * KiB)) die("Unable to initialize postcar frame.\n");