From 00bf3dbf350b48e78aab413958ec83692d8fa263 Mon Sep 17 00:00:00 2001 From: Aaron Durbin Date: Thu, 9 Jan 2014 10:33:23 -0600 Subject: baytrail: snapshot power state in romstage MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The memory reference code doesn't maintain some of the registers which contain valuable information in order to log correct reset and wake events in the eventlog. Therefore snapshot the registers which matter in this area so that they can be consumed by ramstage. BUG=chrome-os-partner:24907 BRANCH=rambi,squawks TEST=Did various resets/wakes with logging patch which consumes this structure. Eventlog can pick up reset events and power failures. Change-Id: Id8d2d782dd4e1133113f5308c4ccfe79bc6d3e03 Signed-off-by: Aaron Durbin Reviewed-on: https://chromium-review.googlesource.com/181982 Reviewed-by: Duncan Laurie Reviewed-on: http://review.coreboot.org/5032 Tested-by: build bot (Jenkins) Reviewed-by: Kyösti Mälkki --- src/soc/intel/baytrail/baytrail/pmc.h | 66 +++++++++++++++++++++++++- src/soc/intel/baytrail/romstage/romstage.c | 76 +++++++++++++++++++++--------- 2 files changed, 119 insertions(+), 23 deletions(-) (limited to 'src/soc/intel') diff --git a/src/soc/intel/baytrail/baytrail/pmc.h b/src/soc/intel/baytrail/baytrail/pmc.h index ab2e169243..5013db8b08 100644 --- a/src/soc/intel/baytrail/baytrail/pmc.h +++ b/src/soc/intel/baytrail/baytrail/pmc.h @@ -24,11 +24,51 @@ #define IOCOM1 0x3f8 /* Memory mapped IO registers behind PMC_BASE_ADDRESS */ +#define PRSTS 0x00 +# define PMC_WDT_STS (1 << 15) +# define SEC_GBLRST_STS (1 << 7) +# define SEC_WDT_STS (1 << 6) +# define WOL_OVR_WK_STS (1 << 5) +# define PMC_WAKE_STS (1 << 4) +#define PMC_CFG 0x08 +# define SPS (1 << 5) +# define NO_REBOOT (1 << 4) +# define SX_ENT_TO_EN (1 << 3) +# define TIMING_T581_SHIFT (0) +# define TIMING_T581_MASK (3 << TIMING_T581_SHIFT) +# define TIMING_T581_10uS (0 << TIMING_T581_SHIFT) +# define TIMING_T581_100uS (1 << TIMING_T581_SHIFT) +# define TIMING_T581_1mS (2 << TIMING_T581_SHIFT) +# define TIMING_T581_10mS (3 << TIMING_T581_SHIFT) +#define VLV_PM_STS 0x0c +# define PMC_MSG_FULL_STS (1 << 24) +# define PMC_MSG_4_FULL_STS (1 << 23) +# define PMC_MSG_3_FULL_STS (1 << 22) +# define PMC_MSG_2_FULL_STS (1 << 21) +# define PMC_MSG_1_FULL_STS (1 << 20) +# define CODE_REQ (1 << 8) +# define HPR_ENT_TO (1 << 2) +# define SX_ENT_TO (1 << 1) #define GEN_PMCON1 0x20 -# define AFTERG3_EN (1 << 0) # define UART_EN (1 << 24) +# define DISB (1 << 23) +# define MEM_SR (1 << 21) +# define SRS (1 << 20) +# define CTS (1 << 19) +# define MS4V (1 << 18) # define PWR_FLR (1 << 16) +# define PME_B0_S5_DIS (1 << 15) # define SUS_PWR_FLR (1 << 14) +# define WOL_EN_OVRD (1 << 13) +# define DIS_SLP_X_STRCH_SUS_UP (1 << 12) +# define GEN_RST_STS (1 << 9) +# define RPS (1 << 2) +# define AFTERG3_EN (1 << 0) +#define GEN_PMCON2 0x24 +# define SLPSX_STR_POL_LOCK (1 << 18) +# define BIOS_PCI_EXP_EN (1 << 10) +# define PWRBTN_LVL (1 << 9) +# define SMI_LOCK (1 << 4) #define ETR 0x48 # define CF9LOCK (1 << 31) # define LTR_DEF (1 << 22) @@ -84,6 +124,14 @@ # define CLK_CTL_D3_LPE (0x0 << 0) # define CLK_CTL_ON (0x1 << 0) # define CLK_CTL_OFF (0x2 << 0) +#define PME_STS 0xc0 +#define GPE_LEVEL_EDGE 0xc4 +# define GPE_EDGE 0 +# define GPE_LEVEL 1 +#define GPE_POLARITY 0xc8 +# define GPE_ACTIVE_HIGH 1 +# define GPE_ACTIVE_LOW 0 +#define LOCK 0xcc /* IO Mapped registers behind ACPI_BASE_ADDRESS */ #define PM1_STS 0x00 @@ -202,6 +250,18 @@ # define RST_CPU (1 << 2) # define SYS_RST (1 << 1) +/* Track power state from reset to log events. */ +struct chipset_power_state { + uint16_t pm1_sts; + uint16_t pm1_en; + uint32_t pm1_cnt; + uint32_t gpe0_sts; + uint32_t gpe0_en; + uint32_t tco_sts; + uint32_t prsts; + uint32_t gen_pmcon1; + uint32_t gen_pmcon2; +} __attribute__((packed)); /* Power Management Utility Functions. */ uint16_t get_pmbase(void); @@ -219,6 +279,10 @@ void enable_gpe(uint32_t mask); void disable_gpe(uint32_t mask); void disable_all_gpe(void); +#if CONFIG_ELOG +void southcluster_log_state(void); +#else static inline void southcluster_log_state(void) {} +#endif #endif /* _BAYTRAIL_PMC_H_ */ diff --git a/src/soc/intel/baytrail/romstage/romstage.c b/src/soc/intel/baytrail/romstage/romstage.c index cb884bd0f1..baa62a595e 100644 --- a/src/soc/intel/baytrail/romstage/romstage.c +++ b/src/soc/intel/baytrail/romstage/romstage.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -151,20 +152,56 @@ void * asmlinkage romstage_main(unsigned long bist, return setup_stack_and_mttrs(); } +static struct chipset_power_state power_state CAR_GLOBAL; + +static void migrate_power_state(void) +{ + struct chipset_power_state *ps_cbmem; + struct chipset_power_state *ps_car; + + 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)); +} +CAR_MIGRATE(migrate_power_state); + +static struct chipset_power_state *fill_power_state(void) +{ + struct chipset_power_state *ps = car_get_var_ptr(&power_state); + + 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->gpe0_sts = inl(ACPI_BASE_ADDRESS + GPE0_STS); + ps->gpe0_en = inl(ACPI_BASE_ADDRESS + GPE0_EN); + ps->tco_sts = inl(ACPI_BASE_ADDRESS + TCO_STS); + ps->prsts = read32(PMC_BASE_ADDRESS + PRSTS); + ps->gen_pmcon1 = read32(PMC_BASE_ADDRESS + GEN_PMCON1); + ps->gen_pmcon2 = read32(PMC_BASE_ADDRESS + GEN_PMCON2); + + printk(BIOS_DEBUG, "pm1_sts: %04x pm1_en: %04x pm1_cnt: %08x\n", + ps->pm1_sts, ps->pm1_en, ps->pm1_cnt); + printk(BIOS_DEBUG, "gpe0_sts: %08x gpe0_en: %08x tco_sts: %08x\n", + ps->gpe0_sts, ps->gpe0_en, ps->tco_sts); + printk(BIOS_DEBUG, "prsts: %08x gen_pmcon1: %08x gen_pmcon2: %08x\n", + ps->prsts, ps->gen_pmcon1, ps->gen_pmcon2); + + return ps; +} + /* Return 0, 3, or 5 to indicate the previous sleep state. */ -static int chipset_prev_sleep_state(void) +static int chipset_prev_sleep_state(struct chipset_power_state *ps) { - uint16_t pm1_sts; - uint32_t pm1_cnt; - uint32_t gen_pmcon1; /* Default to S0. */ int prev_sleep_state = 0; - pm1_sts = inw(ACPI_BASE_ADDRESS + PM1_STS); - pm1_cnt = inl(ACPI_BASE_ADDRESS + PM1_CNT); - - if (pm1_sts & WAK_STS) { - switch ((pm1_cnt & SLP_TYP) >> SLP_TYP_SHIFT) { + if (ps->pm1_sts & WAK_STS) { + switch ((ps->pm1_cnt & SLP_TYP) >> SLP_TYP_SHIFT) { #if CONFIG_HAVE_ACPI_RESUME case SLP_TYP_S3: prev_sleep_state = 3; @@ -172,38 +209,32 @@ static int chipset_prev_sleep_state(void) #endif case SLP_TYP_S5: prev_sleep_state = 5; + break; } /* Clear SLP_TYP. */ - outl(pm1_cnt & ~(SLP_TYP), ACPI_BASE_ADDRESS + PM1_CNT); + outl(ps->pm1_cnt & ~(SLP_TYP), ACPI_BASE_ADDRESS + PM1_CNT); } - gen_pmcon1 = read32(PMC_BASE_ADDRESS + GEN_PMCON1); - if (gen_pmcon1 & (PWR_FLR | SUS_PWR_FLR)) { - /* Clear power failure bits. */ - write32(PMC_BASE_ADDRESS + GEN_PMCON1, gen_pmcon1); + if (ps->gen_pmcon1 & (PWR_FLR | SUS_PWR_FLR)) { prev_sleep_state = 5; } - printk(BIOS_DEBUG, "pm1_sts = %04x pm1_cnt = %08x gen_pmcon1 = %08x\n", - pm1_sts, pm1_cnt, gen_pmcon1); - return prev_sleep_state; } -#if CONFIG_CHROMEOS static inline void chromeos_init(int prev_sleep_state) { +#if CONFIG_CHROMEOS /* Normalize the sleep state to what init_chromeos() wants for S3: 2. */ init_chromeos(prev_sleep_state == 3 ? 2 : 0); -} -#else -static inline void chromeos_init(int prev_sleep_state) {} #endif +} /* Entry from the mainboard. */ void romstage_common(struct romstage_params *params) { struct romstage_handoff *handoff; + struct chipset_power_state *ps; int prev_sleep_state; mark_ts(params, timestamp_get()); @@ -212,7 +243,8 @@ void romstage_common(struct romstage_params *params) boot_count_increment(); #endif - prev_sleep_state = chipset_prev_sleep_state(); + ps = fill_power_state(); + prev_sleep_state = chipset_prev_sleep_state(ps); printk(BIOS_DEBUG, "prev_sleep_state = S%d\n", prev_sleep_state); -- cgit v1.2.3