summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDuncan Laurie <dlaurie@chromium.org>2013-03-08 17:16:37 -0800
committerRonald G. Minnich <rminnich@gmail.com>2013-03-21 23:12:11 +0100
commitd604090b2866f4d8526731034e55e2ea65a305c6 (patch)
treefa8518a02e7991c1eaa925b9474a467d868de4d5
parent467f31de92ca2ed9df1530270e9aabdd69fe8f88 (diff)
downloadcoreboot-d604090b2866f4d8526731034e55e2ea65a305c6.tar.xz
lynxpoint: Fix ELOG logging of power management events
This is updated to handle LynxPoint-H and LynxPoint-LP and a new wake event is added for the power button. Boot, suspend/resume, reboot, etc on WTM2 and then check the event log to see if expected events have been added. Change-Id: I15cbc3901d81f4fd77cc04de37ff5fa048f9d3e8 Signed-off-by: Duncan Laurie <dlaurie@chromium.org> Reviewed-on: http://review.coreboot.org/2817 Tested-by: build bot (Jenkins) Reviewed-by: Ronald G. Minnich <rminnich@gmail.com>
-rw-r--r--src/include/elog.h1
-rw-r--r--src/southbridge/intel/lynxpoint/elog.c119
2 files changed, 97 insertions, 23 deletions
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 <elog.h>
#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();
}