Files
system76-coreboot/src/soc/intel/cannonlake/elog.c
V Sowmya 91b027a351 soc/intel/cannonlake: Add support for logging wake source in SMM
This patch adds support for logging wake source information in gsmi
callbacks. With this change, all the elog logging infrastructure can
be used for S0ix as well as S3 on cannonlake.

BUG=b:124131938
BRANCH=none
TEST=Verified that the wake events are logged during the S0ix resume:
6 | 2019-03-04 17:03:13 | S0ix Enter
7 | 2019-03-04 17:03:17 | S0ix Exit
8 | 2019-03-04 17:03:17 | Wake Source | RTC Alarm | 0
9 | 2019-03-04 17:03:55 | S0ix Enter
10 | 2019-03-04 17:03:56 | S0ix Exit
11 | 2019-03-04 17:03:56 | Wake Source | GPE # | 21
12 | 2019-03-04 17:04:36 | S0ix Enter
13 | 2019-03-04 17:04:45 | S0ix Exit
14 | 2019-03-04 17:04:45 | Wake Source | GPE # | 112
15 | 2019-03-04 17:05:01 | S0ix Enter
16 | 2019-03-04 17:05:09 | S0ix Exit
17 | 2019-03-04 17:05:09 | Wake Source | Power Button | 0

Change-Id: Id627843e22c2524dfa94395b780cf2134f386137
Signed-off-by: V Sowmya <v.sowmya@intel.com>
Reviewed-on: https://review.coreboot.org/c/coreboot/+/31788
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Furquan Shaikh <furquan@google.com>
2019-03-07 17:25:25 +00:00

133 lines
3.6 KiB
C

/*
* This file is part of the coreboot project.
*
* Copyright 2015 Intel Corporation.
* Copyright 2019 Google LLC
*
* 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.
*/
#include <bootstate.h>
#include <cbmem.h>
#include <console/console.h>
#include <stdint.h>
#include <elog.h>
#include <intelblocks/pmclib.h>
#include <soc/pci_devs.h>
#include <soc/pm.h>
static void pch_log_gpio_gpe(u32 gpe0_sts, u32 gpe0_en, int start)
{
int i;
gpe0_sts &= gpe0_en;
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_wake_source(struct chipset_power_state *ps)
{
/* Power Button */
if (ps->pm1_sts & PWRBTN_STS)
elog_add_event_wake(ELOG_WAKE_SOURCE_PWRBTN, 0);
/* RTC */
if (ps->pm1_sts & RTC_STS)
elog_add_event_wake(ELOG_WAKE_SOURCE_RTC, 0);
/* PCI Express (TODO: determine wake device) */
if (ps->pm1_sts & PCIEXPWAK_STS)
elog_add_event_wake(ELOG_WAKE_SOURCE_PCIE, 0);
/* PME (TODO: determine wake device) */
if (ps->gpe0_sts[GPE_STD] & PME_STS)
elog_add_event_wake(ELOG_WAKE_SOURCE_PME, 0);
/* Internal PME (TODO: determine wake device) */
if (ps->gpe0_sts[GPE_STD] & PME_B0_STS)
elog_add_event_wake(ELOG_WAKE_SOURCE_PME_INTERNAL, 0);
/* SMBUS Wake */
if (ps->gpe0_sts[GPE_STD] & SMB_WAK_STS)
elog_add_event_wake(ELOG_WAKE_SOURCE_SMBUS, 0);
/* Log GPIO events in set 1-3 */
pch_log_gpio_gpe(ps->gpe0_sts[GPE_31_0], ps->gpe0_en[GPE_31_0], 0);
pch_log_gpio_gpe(ps->gpe0_sts[GPE_63_32], ps->gpe0_en[GPE_63_32], 32);
pch_log_gpio_gpe(ps->gpe0_sts[GPE_95_64], ps->gpe0_en[GPE_95_64], 64);
/* Treat the STD as an extension of GPIO to obtain visibility. */
pch_log_gpio_gpe(ps->gpe0_sts[GPE_STD], ps->gpe0_en[GPE_STD], 96);
}
static void pch_log_power_and_resets(struct chipset_power_state *ps)
{
/* Thermal Trip */
if (ps->gblrst_cause[0] & GBLRST_CAUSE0_THERMTRIP)
elog_add_event(ELOG_TYPE_THERM_TRIP);
/* PWR_FLR Power Failure */
if (ps->gen_pmcon_b & PWR_FLR)
elog_add_event(ELOG_TYPE_POWER_FAIL);
/* SUS Well Power Failure */
if (ps->gen_pmcon_b & SUS_PWR_FLR)
elog_add_event(ELOG_TYPE_SUS_POWER_FAIL);
/* TCO Timeout */
if (ps->prev_sleep_state != ACPI_S3 &&
ps->tco2_sts & TCO_STS_SECOND_TO)
elog_add_event(ELOG_TYPE_TCO_RESET);
/* Power Button Override */
if (ps->pm1_sts & PRBTNOR_STS)
elog_add_event(ELOG_TYPE_POWER_BUTTON_OVERRIDE);
/* RTC reset */
if (ps->gen_pmcon_b & RTC_BATTERY_DEAD)
elog_add_event(ELOG_TYPE_RTC_RESET);
/* Host Reset Status */
if (ps->gen_pmcon_b & HOST_RST_STS)
elog_add_event(ELOG_TYPE_SYSTEM_RESET);
/* ACPI Wake Event */
if (ps->prev_sleep_state != ACPI_S0)
elog_add_event_byte(ELOG_TYPE_ACPI_WAKE, ps->prev_sleep_state);
}
static void pch_log_state(void *unused)
{
struct chipset_power_state *ps = pmc_get_power_state();
if (!ps) {
printk(BIOS_ERR, "chipset_power_state not found!\n");
return;
}
/* Power and Reset */
pch_log_power_and_resets(ps);
/* Wake Sources */
if (ps->prev_sleep_state > ACPI_S0)
pch_log_wake_source(ps);
}
BOOT_STATE_INIT_ENTRY(BS_DEV_INIT, BS_ON_EXIT, pch_log_state, NULL);
void elog_gsmi_cb_platform_log_wake_source(void)
{
struct chipset_power_state ps;
pmc_fill_pm_reg_info(&ps);
pch_log_wake_source(&ps);
}