summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKarthikeyan Ramasubramanian <kramasub@google.com>2020-11-04 17:05:35 -0700
committerPatrick Georgi <pgeorgi@google.com>2020-11-10 06:20:04 +0000
commitaf0d516bfa5497e84d18bdafbdec5f98ce4999a0 (patch)
tree9c5f02bddaa50df7e71877fc3009df155ffba92f
parente0af9fcb2d526ffd654d0bb573dd5333d0d76269 (diff)
soc/intel/jasperlake: Log PM event from an internal device
Add support to check for the Power Management (PM) Status bit for various internal devices like USB, CNVi etc. and log them into the event log for debugging purposes. BUG=b:172279037 TEST=Build and boot to OS in Drawlat. Ensure that the wake up event is logged into the event log for one of the internal devices eg. USB bluetooth. 8 | 2020-11-05 15:04:16 | S0ix Enter 9 | 2020-11-05 15:04:29 | S0ix Exit 10 | 2020-11-05 15:04:29 | Wake Source | PME - XHCI (USB 2.0 port) | 8 11 | 2020-11-05 15:04:29 | Wake Source | GPE # | 109 12 | 2020-11-05 15:05:08 | S0ix Enter 13 | 2020-11-05 15:05:14 | S0ix Exit 14 | 2020-11-05 15:05:14 | Wake Source | PME - XHCI (USB 2.0 port) | 8 15 | 2020-11-05 15:05:14 | Wake Source | GPE # | 109 Change-Id: I9f43675b698bf310f6b98b5e775d1259607abbcd Signed-off-by: Karthikeyan Ramasubramanian <kramasub@google.com> Reviewed-on: https://review.coreboot.org/c/coreboot/+/47226 Reviewed-by: Furquan Shaikh <furquan@google.com> Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
-rw-r--r--src/soc/intel/jasperlake/Kconfig1
-rw-r--r--src/soc/intel/jasperlake/Makefile.inc2
-rw-r--r--src/soc/intel/jasperlake/elog.c67
-rw-r--r--src/soc/intel/jasperlake/xhci.c20
4 files changed, 84 insertions, 6 deletions
diff --git a/src/soc/intel/jasperlake/Kconfig b/src/soc/intel/jasperlake/Kconfig
index e84add0644..294f19f87b 100644
--- a/src/soc/intel/jasperlake/Kconfig
+++ b/src/soc/intel/jasperlake/Kconfig
@@ -52,6 +52,7 @@ config CPU_SPECIFIC_OPTIONS
select SOC_INTEL_COMMON_BLOCK_SMM
select SOC_INTEL_COMMON_BLOCK_POWER_LIMIT
select SOC_INTEL_COMMON_BLOCK_SMM_IO_TRAP
+ select SOC_INTEL_COMMON_BLOCK_XHCI_ELOG
select SOC_INTEL_COMMON_FSP_RESET
select SOC_INTEL_COMMON_PCH_BASE
select SOC_INTEL_COMMON_RESET
diff --git a/src/soc/intel/jasperlake/Makefile.inc b/src/soc/intel/jasperlake/Makefile.inc
index 209d8a2661..677b5f3c52 100644
--- a/src/soc/intel/jasperlake/Makefile.inc
+++ b/src/soc/intel/jasperlake/Makefile.inc
@@ -44,6 +44,7 @@ ramstage-y += smmrelocate.c
ramstage-y += systemagent.c
ramstage-y += sd.c
ramstage-y += me.c
+ramstage-y += xhci.c
smm-y += gpio.c
smm-y += p2sb.c
@@ -52,6 +53,7 @@ smm-y += pmutil.c
smm-y += smihandler.c
smm-y += uart.c
smm-y += elog.c
+smm-y += xhci.c
verstage-y += gpio.c
diff --git a/src/soc/intel/jasperlake/elog.c b/src/soc/intel/jasperlake/elog.c
index 0546bb0215..5d3c69e3fe 100644
--- a/src/soc/intel/jasperlake/elog.c
+++ b/src/soc/intel/jasperlake/elog.c
@@ -5,11 +5,17 @@
#include <device/pci_ops.h>
#include <elog.h>
#include <intelblocks/pmclib.h>
+#include <intelblocks/xhci.h>
#include <soc/pci_devs.h>
#include <soc/pm.h>
#include <stdint.h>
#include <types.h>
+struct pme_map {
+ pci_devfn_t devfn;
+ unsigned int wake_source;
+};
+
static void pch_log_gpio_gpe(u32 gpe0_sts, u32 gpe0_en, int start)
{
int i;
@@ -25,10 +31,6 @@ static void pch_log_gpio_gpe(u32 gpe0_sts, u32 gpe0_en, int start)
static void pch_log_rp_wake_source(void)
{
size_t i;
- struct pme_map {
- pci_devfn_t devfn;
- unsigned int wake_source;
- };
const struct pme_map pme_map[] = {
{ PCH_DEVFN_PCIE1, ELOG_WAKE_SOURCE_PME_PCIE1 },
@@ -55,6 +57,59 @@ static void pch_log_rp_wake_source(void)
}
}
+static void pch_log_add_elog_event(const struct pme_map *ipme_map)
+{
+ /*
+ * If wake source is XHCI, check for detailed wake source events on
+ * USB2/3 ports.
+ */
+ if ((ipme_map->devfn == PCH_DEVFN_XHCI) &&
+ pch_xhci_update_wake_event(soc_get_xhci_usb_info()))
+ return;
+
+ elog_add_event_wake(ipme_map->wake_source, 0);
+}
+
+static void pch_log_pme_internal_wake_source(void)
+{
+ size_t i;
+ bool dev_found = false;
+
+ const struct pme_map ipme_map[] = {
+ { PCH_DEVFN_HDA, ELOG_WAKE_SOURCE_PME_HDA },
+ { PCH_DEVFN_GBE, ELOG_WAKE_SOURCE_PME_GBE },
+ { PCH_DEVFN_SATA, ELOG_WAKE_SOURCE_PME_SATA },
+ { PCH_DEVFN_CSE, ELOG_WAKE_SOURCE_PME_CSE },
+ { PCH_DEVFN_XHCI, ELOG_WAKE_SOURCE_PME_XHCI },
+ { PCH_DEVFN_USBOTG, ELOG_WAKE_SOURCE_PME_XDCI },
+ { PCH_DEVFN_CNVI_WIFI, ELOG_WAKE_SOURCE_PME_WIFI },
+ };
+
+ for (i = 0; i < ARRAY_SIZE(ipme_map); i++) {
+ const struct device *dev = pcidev_path_on_root(ipme_map[i].devfn);
+ if (!dev)
+ continue;
+
+ if (pci_dev_is_wake_source(dev)) {
+ pch_log_add_elog_event(&ipme_map[i]);
+ dev_found = true;
+ }
+ }
+
+ /*
+ * If device is still not found, but the wake source is internal PME,
+ * try probing XHCI ports to see if any of the USB2/3 ports indicate
+ * that it was the wake source. This path would be taken in case of GSMI
+ * logging with S0ix where the pci_pm_resume_noirq runs and clears the
+ * PME_STS_BIT in controller register.
+ */
+ if (!dev_found)
+ dev_found = pch_xhci_update_wake_event(soc_get_xhci_usb_info());
+
+ if (!dev_found)
+ elog_add_event_wake(ELOG_WAKE_SOURCE_PME_INTERNAL, 0);
+}
+
static void pch_log_wake_source(struct chipset_power_state *ps)
{
/* Power Button */
@@ -73,9 +128,9 @@ static void pch_log_wake_source(struct chipset_power_state *ps)
if (ps->gpe0_sts[GPE_STD] & PME_STS)
elog_add_event_wake(ELOG_WAKE_SOURCE_PME, 0);
- /* Internal PME (TODO: determine wake device) */
+ /* Internal PME */
if (ps->gpe0_sts[GPE_STD] & PME_B0_STS)
- elog_add_event_wake(ELOG_WAKE_SOURCE_PME_INTERNAL, 0);
+ pch_log_pme_internal_wake_source();
/* SMBUS Wake */
if (ps->gpe0_sts[GPE_STD] & SMB_WAK_STS)
diff --git a/src/soc/intel/jasperlake/xhci.c b/src/soc/intel/jasperlake/xhci.c
new file mode 100644
index 0000000000..424751e9d8
--- /dev/null
+++ b/src/soc/intel/jasperlake/xhci.c
@@ -0,0 +1,20 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#include <intelblocks/xhci.h>
+
+#define XHCI_USB2_PORT_STATUS_REG 0x480
+#define XHCI_USB3_PORT_STATUS_REG 0x500
+#define XHCI_USB2_PORT_NUM 8
+#define XHCI_USB3_PORT_NUM 6
+
+static const struct xhci_usb_info usb_info = {
+ .usb2_port_status_reg = XHCI_USB2_PORT_STATUS_REG,
+ .num_usb2_ports = XHCI_USB2_PORT_NUM,
+ .usb3_port_status_reg = XHCI_USB3_PORT_STATUS_REG,
+ .num_usb3_ports = XHCI_USB3_PORT_NUM,
+};
+
+const struct xhci_usb_info *soc_get_xhci_usb_info(void)
+{
+ return &usb_info;
+}