diff --git a/src/include/elog.h b/src/include/elog.h index a5b5a77a60..a65893c1a6 100644 --- a/src/include/elog.h +++ b/src/include/elog.h @@ -113,6 +113,7 @@ #define ELOG_WAKE_SOURCE_RTC 0x03 #define ELOG_WAKE_SOURCE_GPIO 0x04 #define ELOG_WAKE_SOURCE_SMBUS 0x05 +#define ELOG_WAKE_SOURCE_PWRBTN 0x06 struct elog_event_data_wake { u8 source; u32 instance; diff --git a/src/southbridge/intel/lynxpoint/elog.c b/src/southbridge/intel/lynxpoint/elog.c index 09dfcdbc2c..9ba3a981d3 100644 --- a/src/southbridge/intel/lynxpoint/elog.c +++ b/src/southbridge/intel/lynxpoint/elog.c @@ -28,20 +28,101 @@ #include #include "pch.h" +static void pch_log_standard_gpe(u32 gpe0_sts_reg, u32 gpe0_en_reg) +{ + u32 gpe0_en = inl(get_pmbase() + gpe0_en_reg); + u32 gpe0_sts = inl(get_pmbase() + gpe0_sts_reg) & gpe0_en; + + /* PME (TODO: determine wake device) */ + if (gpe0_sts & (1 << 11)) + elog_add_event_wake(ELOG_WAKE_SOURCE_PME, 0); + + /* Internal PME (TODO: determine wake device) */ + if (gpe0_sts & (1 << 13)) + elog_add_event_wake(ELOG_WAKE_SOURCE_PME_INTERNAL, 0); + + /* SMBUS Wake */ + if (gpe0_sts & (1 << 7)) + elog_add_event_wake(ELOG_WAKE_SOURCE_SMBUS, 0); +} + +static void pch_log_gpio_gpe(u32 gpe0_sts_reg, u32 gpe0_en_reg, int start) +{ + /* GPE Bank 1 is GPIO 0-31 */ + u32 gpe0_en = inl(get_pmbase() + gpe0_en_reg); + u32 gpe0_sts = inl(get_pmbase() + gpe0_sts_reg) & gpe0_en; + int i; + + for (i = 0; i <= 31; i++) { + if (gpe0_sts & (1 << i)) + elog_add_event_wake(ELOG_WAKE_SOURCE_GPIO, i + start); + } +} + +static void pch_log_gpe(void) +{ + int i; + u16 pmbase = get_pmbase(); + u32 gpe0_sts, gpe0_en; + int gpe0_high_gpios[] = { + [0] = 27, + [24] = 17, + [25] = 19, + [26] = 21, + [27] = 22, + [28] = 43, + [29] = 56, + [30] = 57, + [31] = 60 + }; + + pch_log_standard_gpe(GPE0_EN, GPE0_STS); + + /* GPIO 0-15 */ + gpe0_en = inw(pmbase + GPE0_EN + 2); + gpe0_sts = inw(pmbase + GPE0_STS + 2) & gpe0_en; + for (i = 0; i <= 15; i++) { + if (gpe0_sts & (1 << i)) + elog_add_event_wake(ELOG_WAKE_SOURCE_GPIO, i); + } + + /* + * Now check and log upper status bits + */ + + gpe0_en = inl(pmbase + GPE0_EN_2); + gpe0_sts = inl(pmbase + GPE0_STS_2) & gpe0_en; + + for (i = 0; i <= 31; i++) { + if (!gpe0_high_gpios[i]) + continue; + if (gpe0_sts & (1 << i)) + elog_add_event_wake(ELOG_WAKE_SOURCE_GPIO, + gpe0_high_gpios[i]); + } +} + +static void pch_lp_log_gpe(void) +{ + /* Standard GPE are in GPE set 4 */ + pch_log_standard_gpe(LP_GPE0_STS_4, LP_GPE0_EN_4); + + /* Log GPIO events in set 1-3 */ + pch_log_gpio_gpe(LP_GPE0_STS_1, LP_GPE0_EN_1, 0); + pch_log_gpio_gpe(LP_GPE0_STS_2, LP_GPE0_EN_2, 32); + pch_log_gpio_gpe(LP_GPE0_STS_3, LP_GPE0_EN_3, 64); +} + void pch_log_state(void) { u16 pm1_sts, gen_pmcon_3, tco2_sts; - u32 gpe0_sts, gpe0_en; u8 gen_pmcon_2; - int i; struct device *lpc = dev_find_slot(0, PCI_DEVFN(0x1f, 0)); if (!lpc) return; - pm1_sts = inw(DEFAULT_PMBASE + PM1_STS); - gpe0_sts = inl(DEFAULT_PMBASE + GPE0_STS); - gpe0_en = inl(DEFAULT_PMBASE + GPE0_EN); - tco2_sts = inw(DEFAULT_PMBASE + TCO2_STS); + pm1_sts = inw(get_pmbase() + PM1_STS); + tco2_sts = inw(get_pmbase() + TCO2_STS); gen_pmcon_2 = pci_read_config8(lpc, GEN_PMCON_2); gen_pmcon_3 = pci_read_config16(lpc, GEN_PMCON_3); @@ -86,6 +167,10 @@ void pch_log_state(void) * Wake sources */ + /* Power Button */ + if (pm1_sts & (1 << 8)) + elog_add_event_wake(ELOG_WAKE_SOURCE_PWRBTN, 0); + /* RTC */ if (pm1_sts & (1 << 10)) elog_add_event_wake(ELOG_WAKE_SOURCE_RTC, 0); @@ -94,21 +179,9 @@ void pch_log_state(void) if (pm1_sts & (1 << 14)) elog_add_event_wake(ELOG_WAKE_SOURCE_PCIE, 0); - /* PME (TODO: determine wake device) */ - if (gpe0_sts & (1 << 13)) - elog_add_event_wake(ELOG_WAKE_SOURCE_PME, 0); - - /* Internal PME (TODO: determine wake device) */ - if (gpe0_sts & (1 << 13)) - elog_add_event_wake(ELOG_WAKE_SOURCE_PME_INTERNAL, 0); - - /* GPIO 0-15 */ - for (i = 0; i < 16; i++) { - if ((gpe0_sts & (1 << (16+i))) && (gpe0_en & (1 << (16+i)))) - elog_add_event_wake(ELOG_WAKE_SOURCE_GPIO, i); - } - - /* SMBUS Wake */ - if (gpe0_sts & (1 << 7)) - elog_add_event_wake(ELOG_WAKE_SOURCE_SMBUS, 0); + /* GPE */ + if (pch_is_lp()) + pch_lp_log_gpe(); + else + pch_log_gpe(); }