blob: 325bacb0f3639c339fd9f7fe250ed960171866bc [file] [log] [blame]
Angel Pons3bd1e3d2020-04-05 15:47:17 +02001/* SPDX-License-Identifier: GPL-2.0-only */
Lee Leahyb0005132015-05-12 18:19:47 -07002
Kyösti Mälkki27872372021-01-21 16:05:26 +02003#include <acpi/acpi_pm.h>
Lee Leahyb0005132015-05-12 18:19:47 -07004#include <bootstate.h>
Elyes HAOUASf97c1c92019-12-03 18:22:06 +01005#include <commonlib/helpers.h>
Kyösti Mälkki13f66502019-03-03 08:01:05 +02006#include <device/mmio.h>
Furquan Shaikhef8bb912017-05-25 00:16:15 -07007#include <device/pci_ops.h>
Lee Leahyb0005132015-05-12 18:19:47 -07008#include <stdint.h>
9#include <elog.h>
Furquan Shaikhc565bd42017-10-14 19:25:30 -070010#include <intelblocks/pmclib.h>
Karthikeyan Ramasubramaniancc7cdb12019-03-20 11:38:01 -060011#include <intelblocks/xhci.h>
Furquan Shaikhef8bb912017-05-25 00:16:15 -070012#include <soc/pci_devs.h>
Lee Leahyb0005132015-05-12 18:19:47 -070013#include <soc/pm.h>
Barnali Sarkar0dddcd72016-08-02 17:49:56 +053014#include <soc/smbus.h>
Lee Leahyb0005132015-05-12 18:19:47 -070015
16static void pch_log_gpio_gpe(u32 gpe0_sts, u32 gpe0_en, int start)
17{
18 int i;
19
20 gpe0_sts &= gpe0_en;
21
22 for (i = 0; i <= 31; i++) {
23 if (gpe0_sts & (1 << i))
Aaron Durbinaa902032020-08-17 09:37:13 -060024 elog_add_event_wake(ELOG_WAKE_SOURCE_GPE, i + start);
Lee Leahyb0005132015-05-12 18:19:47 -070025 }
26}
27
Furquan Shaikhef8bb912017-05-25 00:16:15 -070028struct pme_status_info {
Tim Wawrzynczakb1623f22021-04-30 13:47:04 -060029 unsigned int devfn;
Furquan Shaikhef8bb912017-05-25 00:16:15 -070030 uint8_t reg_offset;
31 uint32_t elog_event;
32};
33
34#define PME_STS_BIT (1 << 15)
35
36static void pch_log_pme_internal_wake_source(void)
37{
38 size_t i;
Furquan Shaikhef8bb912017-05-25 00:16:15 -070039 uint16_t val;
40 bool dev_found = false;
41
Tim Wawrzynczak56fcfb52020-11-10 13:39:37 -070042 const struct pme_status_info pme_status_info[] = {
Michael Niewöhnerf3161df2020-02-23 13:23:04 +010043 { PCH_DEVFN_HDA, 0x54, ELOG_WAKE_SOURCE_PME_HDA },
44 { PCH_DEVFN_GBE, 0xcc, ELOG_WAKE_SOURCE_PME_GBE },
45 { PCH_DEVFN_SATA, 0x74, ELOG_WAKE_SOURCE_PME_SATA },
46 { PCH_DEVFN_CSE, 0x54, ELOG_WAKE_SOURCE_PME_CSE },
Michael Niewöhnerf3161df2020-02-23 13:23:04 +010047 { PCH_DEVFN_USBOTG, 0x84, ELOG_WAKE_SOURCE_PME_XDCI },
Furquan Shaikhef8bb912017-05-25 00:16:15 -070048 };
Tim Wawrzynczak56fcfb52020-11-10 13:39:37 -070049 const struct xhci_wake_info xhci_wake_info[] = {
50 { PCH_DEVFN_XHCI, ELOG_WAKE_SOURCE_PME_XHCI },
51 };
Furquan Shaikhef8bb912017-05-25 00:16:15 -070052
53 for (i = 0; i < ARRAY_SIZE(pme_status_info); i++) {
Michael Niewöhnerf3161df2020-02-23 13:23:04 +010054 pci_devfn_t dev = PCI_DEV(0, PCI_SLOT(pme_status_info[i].devfn),
55 PCI_FUNC(pme_status_info[i].devfn));
Furquan Shaikhef8bb912017-05-25 00:16:15 -070056
Michael Niewöhnerf3161df2020-02-23 13:23:04 +010057 val = pci_s_read_config16(dev, pme_status_info[i].reg_offset);
Furquan Shaikhef8bb912017-05-25 00:16:15 -070058
59 if ((val == 0xFFFF) || !(val & PME_STS_BIT))
60 continue;
61
Tim Wawrzynczak56fcfb52020-11-10 13:39:37 -070062 elog_add_event_wake(pme_status_info[i].elog_event, 0);
Furquan Shaikhef8bb912017-05-25 00:16:15 -070063 dev_found = true;
64 }
65
Furquan Shaikhdd825fe2017-10-17 15:06:37 -070066 /*
Tim Wawrzynczak56fcfb52020-11-10 13:39:37 -070067 * Check the XHCI controllers' USB2 & USB3 ports for wake events. There
68 * are cases (GSMI logging for S0ix clears PME_STS_BIT) where the XHCI
69 * controller's PME_STS_BIT may have already been cleared, so the host
70 * controller wake wouldn't get logged here; therefore, the host
71 * controller wake event is logged before its corresponding port wake
72 * event is logged.
Furquan Shaikhdd825fe2017-10-17 15:06:37 -070073 */
Tim Wawrzynczak56fcfb52020-11-10 13:39:37 -070074 dev_found |= xhci_update_wake_event(xhci_wake_info,
75 ARRAY_SIZE(xhci_wake_info));
Furquan Shaikhdd825fe2017-10-17 15:06:37 -070076
Furquan Shaikhef8bb912017-05-25 00:16:15 -070077 if (!dev_found)
78 elog_add_event_wake(ELOG_WAKE_SOURCE_PME_INTERNAL, 0);
79}
80
Naresh G Solanki2991f3c2017-07-11 17:01:28 +053081#define RP_PME_STS_BIT (1 << 16)
82static void pch_log_rp_wake_source(void)
83{
Michael Niewöhnerbc36e292019-10-02 20:07:16 +020084 size_t i, maxports;
Naresh G Solanki2991f3c2017-07-11 17:01:28 +053085 uint32_t val;
86
Furquan Shaikh2ce4ec02017-10-14 19:17:31 -070087 struct pme_status_info pme_status_info[] = {
Michael Niewöhnerf3161df2020-02-23 13:23:04 +010088 { PCH_DEVFN_PCIE1, 0x60, ELOG_WAKE_SOURCE_PME_PCIE1 },
89 { PCH_DEVFN_PCIE2, 0x60, ELOG_WAKE_SOURCE_PME_PCIE2 },
90 { PCH_DEVFN_PCIE3, 0x60, ELOG_WAKE_SOURCE_PME_PCIE3 },
91 { PCH_DEVFN_PCIE4, 0x60, ELOG_WAKE_SOURCE_PME_PCIE4 },
92 { PCH_DEVFN_PCIE5, 0x60, ELOG_WAKE_SOURCE_PME_PCIE5 },
93 { PCH_DEVFN_PCIE6, 0x60, ELOG_WAKE_SOURCE_PME_PCIE6 },
94 { PCH_DEVFN_PCIE7, 0x60, ELOG_WAKE_SOURCE_PME_PCIE7 },
95 { PCH_DEVFN_PCIE8, 0x60, ELOG_WAKE_SOURCE_PME_PCIE8 },
96 { PCH_DEVFN_PCIE9, 0x60, ELOG_WAKE_SOURCE_PME_PCIE9 },
97 { PCH_DEVFN_PCIE10, 0x60, ELOG_WAKE_SOURCE_PME_PCIE10 },
98 { PCH_DEVFN_PCIE11, 0x60, ELOG_WAKE_SOURCE_PME_PCIE11 },
99 { PCH_DEVFN_PCIE12, 0x60, ELOG_WAKE_SOURCE_PME_PCIE12 },
100 { PCH_DEVFN_PCIE13, 0x60, ELOG_WAKE_SOURCE_PME_PCIE13 },
101 { PCH_DEVFN_PCIE14, 0x60, ELOG_WAKE_SOURCE_PME_PCIE14 },
102 { PCH_DEVFN_PCIE15, 0x60, ELOG_WAKE_SOURCE_PME_PCIE15 },
103 { PCH_DEVFN_PCIE16, 0x60, ELOG_WAKE_SOURCE_PME_PCIE16 },
104 { PCH_DEVFN_PCIE17, 0x60, ELOG_WAKE_SOURCE_PME_PCIE17 },
105 { PCH_DEVFN_PCIE18, 0x60, ELOG_WAKE_SOURCE_PME_PCIE18 },
106 { PCH_DEVFN_PCIE19, 0x60, ELOG_WAKE_SOURCE_PME_PCIE19 },
107 { PCH_DEVFN_PCIE20, 0x60, ELOG_WAKE_SOURCE_PME_PCIE20 },
108 { PCH_DEVFN_PCIE21, 0x60, ELOG_WAKE_SOURCE_PME_PCIE21 },
109 { PCH_DEVFN_PCIE22, 0x60, ELOG_WAKE_SOURCE_PME_PCIE22 },
110 { PCH_DEVFN_PCIE23, 0x60, ELOG_WAKE_SOURCE_PME_PCIE23 },
111 { PCH_DEVFN_PCIE24, 0x60, ELOG_WAKE_SOURCE_PME_PCIE24 },
Naresh G Solanki2991f3c2017-07-11 17:01:28 +0530112 };
113
Elyes HAOUASf97c1c92019-12-03 18:22:06 +0100114 maxports = MIN(CONFIG_MAX_ROOT_PORTS, ARRAY_SIZE(pme_status_info));
Michael Niewöhnerbc36e292019-10-02 20:07:16 +0200115
116 for (i = 0; i < maxports; i++) {
Michael Niewöhnerf3161df2020-02-23 13:23:04 +0100117 pci_devfn_t dev = PCI_DEV(0, PCI_SLOT(pme_status_info[i].devfn),
118 PCI_FUNC(pme_status_info[i].devfn));
Naresh G Solanki2991f3c2017-07-11 17:01:28 +0530119
Michael Niewöhnerf3161df2020-02-23 13:23:04 +0100120 val = pci_s_read_config32(dev, pme_status_info[i].reg_offset);
Naresh G Solanki2991f3c2017-07-11 17:01:28 +0530121
122 if ((val == 0xFFFFFFFF) || !(val & RP_PME_STS_BIT))
123 continue;
124
125 /*
126 * Linux kernel uses PME STS bit information. So do not clear
127 * this bit.
128 */
Tim Wawrzynczak56fcfb52020-11-10 13:39:37 -0700129 elog_add_event_wake(pme_status_info[i].elog_event, 0);
Naresh G Solanki2991f3c2017-07-11 17:01:28 +0530130 }
131}
132
Kyösti Mälkki6b430552021-01-22 07:52:43 +0200133static void pch_log_wake_source(const struct chipset_power_state *ps)
Lee Leahyb0005132015-05-12 18:19:47 -0700134{
135 /* Power Button */
136 if (ps->pm1_sts & PWRBTN_STS)
137 elog_add_event_wake(ELOG_WAKE_SOURCE_PWRBTN, 0);
138
139 /* RTC */
140 if (ps->pm1_sts & RTC_STS)
141 elog_add_event_wake(ELOG_WAKE_SOURCE_RTC, 0);
142
143 /* PCI Express (TODO: determine wake device) */
144 if (ps->pm1_sts & PCIEXPWAK_STS)
145 elog_add_event_wake(ELOG_WAKE_SOURCE_PCIE, 0);
146
Naresh G Solanki2991f3c2017-07-11 17:01:28 +0530147 /*
148 * PCIE Root Port .
149 * This should be done when PCIEXPWAK_STS bit is set.
150 * In SPT, this bit isn't getting set due to known bug.
151 * So scan all PCIe RP for PME status bit.
152 */
153 pch_log_rp_wake_source();
154
Lee Leahyb0005132015-05-12 18:19:47 -0700155 /* PME (TODO: determine wake device) */
156 if (ps->gpe0_sts[GPE_STD] & PME_STS)
157 elog_add_event_wake(ELOG_WAKE_SOURCE_PME, 0);
158
159 /* Internal PME (TODO: determine wake device) */
160 if (ps->gpe0_sts[GPE_STD] & PME_B0_STS)
Furquan Shaikhef8bb912017-05-25 00:16:15 -0700161 pch_log_pme_internal_wake_source();
Lee Leahyb0005132015-05-12 18:19:47 -0700162
163 /* SMBUS Wake */
164 if (ps->gpe0_sts[GPE_STD] & SMB_WAK_STS)
165 elog_add_event_wake(ELOG_WAKE_SOURCE_SMBUS, 0);
166
Lee Leahyb0005132015-05-12 18:19:47 -0700167 /* Log GPIO events in set 1-3 */
168 pch_log_gpio_gpe(ps->gpe0_sts[GPE_31_0], ps->gpe0_en[GPE_31_0], 0);
169 pch_log_gpio_gpe(ps->gpe0_sts[GPE_63_32], ps->gpe0_en[GPE_63_32], 32);
Aaron Durbin7f788492015-07-24 17:10:31 -0500170 pch_log_gpio_gpe(ps->gpe0_sts[GPE_95_64], ps->gpe0_en[GPE_95_64], 64);
171 /* Treat the STD as an extension of GPIO to obtain visibility. */
172 pch_log_gpio_gpe(ps->gpe0_sts[GPE_STD], ps->gpe0_en[GPE_STD], 96);
Lee Leahyb0005132015-05-12 18:19:47 -0700173}
174
Kyösti Mälkki6b430552021-01-22 07:52:43 +0200175static void pch_log_power_and_resets(const struct chipset_power_state *ps)
Lee Leahyb0005132015-05-12 18:19:47 -0700176{
Furquan Shaikh7941c962017-05-19 10:54:30 -0700177 bool deep_sx;
178
179 /*
180 * Platform entered deep Sx if:
181 * 1. Prev sleep state was Sx and deep_sx_enabled() is true
182 * 2. SUS well power was lost
183 */
184 deep_sx = ((((ps->prev_sleep_state == ACPI_S3) && deep_s3_enabled()) ||
185 ((ps->prev_sleep_state == ACPI_S5) && deep_s5_enabled())) &&
186 (ps->gen_pmcon_b & SUS_PWR_FLR));
187
Duncan Laurie63f8c0a2015-12-10 01:00:54 -0800188 /* Thermal Trip */
189 if (ps->gblrst_cause[0] & GBLRST_CAUSE0_THERMTRIP)
190 elog_add_event(ELOG_TYPE_THERM_TRIP);
Lee Leahyb0005132015-05-12 18:19:47 -0700191
192 /* PWR_FLR Power Failure */
Lee Leahy1d14b3e2015-05-12 18:23:27 -0700193 if (ps->gen_pmcon_b & PWR_FLR)
Lee Leahyb0005132015-05-12 18:19:47 -0700194 elog_add_event(ELOG_TYPE_POWER_FAIL);
195
196 /* SUS Well Power Failure */
Duncan Laurieac2cbd02017-03-07 19:22:24 -0800197 if (ps->gen_pmcon_b & SUS_PWR_FLR) {
198 /* Do not log SUS_PWR_FLR if waking from deep Sx */
Furquan Shaikh7941c962017-05-19 10:54:30 -0700199 if (!deep_sx)
Duncan Laurieac2cbd02017-03-07 19:22:24 -0800200 elog_add_event(ELOG_TYPE_SUS_POWER_FAIL);
201 }
Lee Leahyb0005132015-05-12 18:19:47 -0700202
Lee Leahyb0005132015-05-12 18:19:47 -0700203 /* TCO Timeout */
Aaron Durbine0a49142016-07-13 23:20:51 -0500204 if (ps->prev_sleep_state != ACPI_S3 &&
Kyösti Mälkki307320c2022-11-21 17:27:07 +0200205 ps->tco2_sts & TCO2_STS_SECOND_TO)
Lee Leahyb0005132015-05-12 18:19:47 -0700206 elog_add_event(ELOG_TYPE_TCO_RESET);
207
208 /* Power Button Override */
209 if (ps->pm1_sts & PRBTNOR_STS)
210 elog_add_event(ELOG_TYPE_POWER_BUTTON_OVERRIDE);
211
212 /* RTC reset */
Lee Leahy1d14b3e2015-05-12 18:23:27 -0700213 if (ps->gen_pmcon_b & RTC_BATTERY_DEAD)
Lee Leahyb0005132015-05-12 18:19:47 -0700214 elog_add_event(ELOG_TYPE_RTC_RESET);
215
Lee Leahy1d14b3e2015-05-12 18:23:27 -0700216 /* Host Reset Status */
217 if (ps->gen_pmcon_b & HOST_RST_STS)
Lee Leahyb0005132015-05-12 18:19:47 -0700218 elog_add_event(ELOG_TYPE_SYSTEM_RESET);
219
220 /* ACPI Wake Event */
Furquan Shaikh7941c962017-05-19 10:54:30 -0700221 if (ps->prev_sleep_state != ACPI_S0) {
222 if (deep_sx)
223 elog_add_event_byte(ELOG_TYPE_ACPI_DEEP_WAKE,
224 ps->prev_sleep_state);
225 else
226 elog_add_event_byte(ELOG_TYPE_ACPI_WAKE,
227 ps->prev_sleep_state);
228 }
Lee Leahyb0005132015-05-12 18:19:47 -0700229}
230
231static void pch_log_state(void *unused)
232{
Kyösti Mälkki27872372021-01-21 16:05:26 +0200233 const struct chipset_power_state *ps;
Lee Leahyb0005132015-05-12 18:19:47 -0700234
Fabio Aiutofdcf6982022-09-11 12:25:13 +0200235 if (acpi_fetch_pm_state(&ps, PS_CLAIMER_ELOG) < 0)
Lee Leahyb0005132015-05-12 18:19:47 -0700236 return;
Lee Leahyb0005132015-05-12 18:19:47 -0700237
238 /* Power and Reset */
239 pch_log_power_and_resets(ps);
240
241 /* Wake Sources */
Duncan Lauried68e0472016-03-01 17:01:35 -0800242 if (ps->prev_sleep_state > 0)
243 pch_log_wake_source(ps);
Lee Leahyb0005132015-05-12 18:19:47 -0700244}
245
Duncan Laurieac2cbd02017-03-07 19:22:24 -0800246BOOT_STATE_INIT_ENTRY(BS_DEV_INIT, BS_ON_EXIT, pch_log_state, NULL);
Furquan Shaikhc565bd42017-10-14 19:25:30 -0700247
248void elog_gsmi_cb_platform_log_wake_source(void)
249{
250 struct chipset_power_state ps;
251 pmc_fill_pm_reg_info(&ps);
252 pch_log_wake_source(&ps);
253}