2 * This file is part of the coreboot project.
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; version 2 of the License.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
15 #include <bootstate.h>
17 #include <console/console.h>
18 #include <device/pci_ops.h>
21 #include <intelblocks/pmclib.h>
22 #include <intelblocks/xhci.h>
23 #include <soc/pci_devs.h>
26 struct pme_status_info
{
27 #ifdef __SIMPLE_DEVICE__
36 #define PME_STS_BIT (1 << 15)
38 static void pch_log_add_elog_event(const struct pme_status_info
*info
)
41 * If wake source is XHCI, check for detailed wake source events on
44 if ((info
->dev
== PCH_DEV_XHCI
) &&
45 pch_xhci_update_wake_event(soc_get_xhci_usb_info()))
48 elog_add_event_wake(info
->elog_event
, 0);
51 static void pch_log_pme_internal_wake_source(void)
54 #ifdef __SIMPLE_DEVICE__
60 bool dev_found
= false;
62 struct pme_status_info pme_status_info
[] = {
63 { PCH_DEV_HDA
, 0x54, ELOG_WAKE_SOURCE_PME_HDA
},
64 { PCH_DEV_GBE
, 0xcc, ELOG_WAKE_SOURCE_PME_GBE
},
65 { PCH_DEV_SATA
, 0x74, ELOG_WAKE_SOURCE_PME_SATA
},
66 { PCH_DEV_CSE
, 0x54, ELOG_WAKE_SOURCE_PME_CSE
},
67 { PCH_DEV_XHCI
, 0x74, ELOG_WAKE_SOURCE_PME_XHCI
},
68 { PCH_DEV_USBOTG
, 0x84, ELOG_WAKE_SOURCE_PME_XDCI
},
70 * The power management control/status register is not
71 * listed in the cannonlake PCH EDS. We have been told
72 * that the PMCS register is at offset 0xCC.
74 { PCH_DEV_CNViWIFI
, 0xcc, ELOG_WAKE_SOURCE_PME_WIFI
},
77 for (i
= 0; i
< ARRAY_SIZE(pme_status_info
); i
++) {
78 dev
= pme_status_info
[i
].dev
;
82 val
= pci_read_config16(dev
, pme_status_info
[i
].reg_offset
);
84 if ((val
== 0xFFFF) || !(val
& PME_STS_BIT
))
87 pch_log_add_elog_event(&pme_status_info
[i
]);
92 * If device is still not found, but the wake source is internal PME,
93 * try probing XHCI ports to see if any of the USB2/3 ports indicate
94 * that it was the wake source. This path would be taken in case of GSMI
95 * logging with S0ix where the pci_pm_resume_noirq runs and clears the
96 * PME_STS_BIT in controller register.
99 dev_found
= pch_xhci_update_wake_event(soc_get_xhci_usb_info());
102 elog_add_event_wake(ELOG_WAKE_SOURCE_PME_INTERNAL
, 0);
105 static void pch_log_gpio_gpe(u32 gpe0_sts
, u32 gpe0_en
, int start
)
111 for (i
= 0; i
<= 31; i
++) {
112 if (gpe0_sts
& (1 << i
))
113 elog_add_event_wake(ELOG_WAKE_SOURCE_GPIO
, i
+ start
);
117 static void pch_log_wake_source(struct chipset_power_state
*ps
)
120 if (ps
->pm1_sts
& PWRBTN_STS
)
121 elog_add_event_wake(ELOG_WAKE_SOURCE_PWRBTN
, 0);
124 if (ps
->pm1_sts
& RTC_STS
)
125 elog_add_event_wake(ELOG_WAKE_SOURCE_RTC
, 0);
127 /* PCI Express (TODO: determine wake device) */
128 if (ps
->pm1_sts
& PCIEXPWAK_STS
)
129 elog_add_event_wake(ELOG_WAKE_SOURCE_PCIE
, 0);
131 /* PME (TODO: determine wake device) */
132 if (ps
->gpe0_sts
[GPE_STD
] & PME_STS
)
133 elog_add_event_wake(ELOG_WAKE_SOURCE_PME
, 0);
135 /* XHCI - "Power Management Event Bus 0" events include XHCI */
136 if (ps
->gpe0_sts
[GPE_STD
] & PME_B0_STS
)
137 pch_log_pme_internal_wake_source();
140 if (ps
->gpe0_sts
[GPE_STD
] & SMB_WAK_STS
)
141 elog_add_event_wake(ELOG_WAKE_SOURCE_SMBUS
, 0);
143 /* Log GPIO events in set 1-3 */
144 pch_log_gpio_gpe(ps
->gpe0_sts
[GPE_31_0
], ps
->gpe0_en
[GPE_31_0
], 0);
145 pch_log_gpio_gpe(ps
->gpe0_sts
[GPE_63_32
], ps
->gpe0_en
[GPE_63_32
], 32);
146 pch_log_gpio_gpe(ps
->gpe0_sts
[GPE_95_64
], ps
->gpe0_en
[GPE_95_64
], 64);
147 /* Treat the STD as an extension of GPIO to obtain visibility. */
148 pch_log_gpio_gpe(ps
->gpe0_sts
[GPE_STD
], ps
->gpe0_en
[GPE_STD
], 96);
151 static void pch_log_power_and_resets(struct chipset_power_state
*ps
)
154 if (ps
->gblrst_cause
[0] & GBLRST_CAUSE0_THERMTRIP
)
155 elog_add_event(ELOG_TYPE_THERM_TRIP
);
157 /* PWR_FLR Power Failure */
158 if (ps
->gen_pmcon_a
& PWR_FLR
)
159 elog_add_event(ELOG_TYPE_POWER_FAIL
);
161 /* SUS Well Power Failure */
162 if (ps
->gen_pmcon_a
& SUS_PWR_FLR
)
163 elog_add_event(ELOG_TYPE_SUS_POWER_FAIL
);
166 if (ps
->prev_sleep_state
!= ACPI_S3
&&
167 ps
->tco2_sts
& TCO_STS_SECOND_TO
)
168 elog_add_event(ELOG_TYPE_TCO_RESET
);
170 /* Power Button Override */
171 if (ps
->pm1_sts
& PRBTNOR_STS
)
172 elog_add_event(ELOG_TYPE_POWER_BUTTON_OVERRIDE
);
175 if (ps
->gen_pmcon_b
& RTC_BATTERY_DEAD
)
176 elog_add_event(ELOG_TYPE_RTC_RESET
);
178 /* Host Reset Status */
179 if (ps
->gen_pmcon_a
& HOST_RST_STS
)
180 elog_add_event(ELOG_TYPE_SYSTEM_RESET
);
182 /* ACPI Wake Event */
183 if (ps
->prev_sleep_state
!= ACPI_S0
)
184 elog_add_event_byte(ELOG_TYPE_ACPI_WAKE
, ps
->prev_sleep_state
);
187 static void pch_log_state(void *unused
)
189 struct chipset_power_state
*ps
= pmc_get_power_state();
192 printk(BIOS_ERR
, "chipset_power_state not found!\n");
196 /* Power and Reset */
197 pch_log_power_and_resets(ps
);
200 if (ps
->prev_sleep_state
> ACPI_S0
)
201 pch_log_wake_source(ps
);
204 BOOT_STATE_INIT_ENTRY(BS_DEV_INIT
, BS_ON_EXIT
, pch_log_state
, NULL
);
206 void elog_gsmi_cb_platform_log_wake_source(void)
208 struct chipset_power_state ps
;
209 pmc_fill_pm_reg_info(&ps
);
210 pch_log_wake_source(&ps
);