blob: 4ba30b4ec6efa913deea80480d02a1a70b980530 [file] [log] [blame]
Angel Ponsf94ac9a2020-04-05 15:46:48 +02001/* SPDX-License-Identifier: GPL-2.0-only */
Duncan Lauriec88c54c2014-04-30 16:36:13 -07002
3/*
4 * Helper functions for dealing with power management registers
5 * and the differences between PCH variants.
6 */
7
Furquan Shaikh76cedd22020-05-02 10:24:23 -07008#include <acpi/acpi.h>
Duncan Lauriec88c54c2014-04-30 16:36:13 -07009#include <arch/io.h>
Bill XIE516c0a52020-02-24 23:08:35 +080010#include <bootmode.h>
Kyösti Mälkkif1b58b72019-03-01 13:43:02 +020011#include <device/pci_ops.h>
Duncan Lauriec88c54c2014-04-30 16:36:13 -070012#include <device/device.h>
13#include <device/pci.h>
Duncan Lauriec88c54c2014-04-30 16:36:13 -070014#include <console/console.h>
Julius Werner4ee4bd52014-10-20 13:46:39 -070015#include <soc/iomap.h>
16#include <soc/lpc.h>
17#include <soc/pci_devs.h>
18#include <soc/pm.h>
Philipp Deppenwiesefea24292017-10-17 17:02:29 +020019#include <security/vboot/vbnv.h>
Angel Ponsf92f2732020-09-25 00:44:52 +020020#include <stdint.h>
21
Angel Pons733f03d2021-01-28 16:59:04 +010022#define GPIO_ALT_GPI_SMI_STS 0x50
23#define GPIO_ALT_GPI_SMI_EN 0x54
24
Angel Ponsf92f2732020-09-25 00:44:52 +020025static inline uint16_t get_gpiobase(void)
26{
27 return GPIO_BASE_ADDRESS;
28}
Duncan Lauriec88c54c2014-04-30 16:36:13 -070029
30/* Print status bits with descriptive names */
31static void print_status_bits(u32 status, const char *bit_names[])
32{
33 int i;
34
35 if (!status)
36 return;
37
Lee Leahy26b7cd02017-03-16 18:47:55 -070038 for (i = 31; i >= 0; i--) {
Duncan Lauriec88c54c2014-04-30 16:36:13 -070039 if (status & (1 << i)) {
40 if (bit_names[i])
41 printk(BIOS_DEBUG, "%s ", bit_names[i]);
42 else
43 printk(BIOS_DEBUG, "BIT%d ", i);
44 }
45 }
46}
47
48/* Print status bits as GPIO numbers */
49static void print_gpio_status(u32 status, int start)
50{
51 int i;
52
53 if (!status)
54 return;
55
Lee Leahy26b7cd02017-03-16 18:47:55 -070056 for (i = 31; i >= 0; i--) {
Duncan Lauriec88c54c2014-04-30 16:36:13 -070057 if (status & (1 << i))
58 printk(BIOS_DEBUG, "GPIO%d ", start + i);
59 }
60}
61
Duncan Lauriec88c54c2014-04-30 16:36:13 -070062/*
63 * PM1_CNT
64 */
65
66/* Enable events in PM1 control register */
67void enable_pm1_control(u32 mask)
68{
Angel Ponsf92f2732020-09-25 00:44:52 +020069 u32 pm1_cnt = inl(get_pmbase() + PM1_CNT);
Duncan Lauriec88c54c2014-04-30 16:36:13 -070070 pm1_cnt |= mask;
Angel Ponsf92f2732020-09-25 00:44:52 +020071 outl(pm1_cnt, get_pmbase() + PM1_CNT);
Duncan Lauriec88c54c2014-04-30 16:36:13 -070072}
73
74/* Disable events in PM1 control register */
75void disable_pm1_control(u32 mask)
76{
Angel Ponsf92f2732020-09-25 00:44:52 +020077 u32 pm1_cnt = inl(get_pmbase() + PM1_CNT);
Duncan Lauriec88c54c2014-04-30 16:36:13 -070078 pm1_cnt &= ~mask;
Angel Ponsf92f2732020-09-25 00:44:52 +020079 outl(pm1_cnt, get_pmbase() + PM1_CNT);
Duncan Lauriec88c54c2014-04-30 16:36:13 -070080}
81
Duncan Lauriec88c54c2014-04-30 16:36:13 -070082/*
83 * PM1
84 */
85
86/* Clear and return PM1 status register */
87static u16 reset_pm1_status(void)
88{
Angel Ponsf92f2732020-09-25 00:44:52 +020089 u16 pm1_sts = inw(get_pmbase() + PM1_STS);
90 outw(pm1_sts, get_pmbase() + PM1_STS);
Duncan Lauriec88c54c2014-04-30 16:36:13 -070091 return pm1_sts;
92}
93
94/* Print PM1 status bits */
95static u16 print_pm1_status(u16 pm1_sts)
96{
97 const char *pm1_sts_bits[] = {
98 [0] = "TMROF",
99 [4] = "BM",
100 [5] = "GBL",
101 [8] = "PWRBTN",
102 [10] = "RTC",
103 [11] = "PRBTNOR",
104 [14] = "PCIEXPWAK",
105 [15] = "WAK",
106 };
107
108 if (!pm1_sts)
109 return 0;
110
111 printk(BIOS_SPEW, "PM1_STS: ");
112 print_status_bits(pm1_sts, pm1_sts_bits);
113 printk(BIOS_SPEW, "\n");
114
115 return pm1_sts;
116}
117
118/* Print, clear, and return PM1 status */
119u16 clear_pm1_status(void)
120{
121 return print_pm1_status(reset_pm1_status());
122}
123
124/* Set the PM1 register to events */
125void enable_pm1(u16 events)
126{
Angel Ponsf92f2732020-09-25 00:44:52 +0200127 outw(events, get_pmbase() + PM1_EN);
Duncan Lauriec88c54c2014-04-30 16:36:13 -0700128}
129
Duncan Lauriec88c54c2014-04-30 16:36:13 -0700130/*
131 * SMI
132 */
133
134/* Clear and return SMI status register */
135static u32 reset_smi_status(void)
136{
Angel Ponsf92f2732020-09-25 00:44:52 +0200137 u32 smi_sts = inl(get_pmbase() + SMI_STS);
138 outl(smi_sts, get_pmbase() + SMI_STS);
Duncan Lauriec88c54c2014-04-30 16:36:13 -0700139 return smi_sts;
140}
141
142/* Print SMI status bits */
143static u32 print_smi_status(u32 smi_sts)
144{
145 const char *smi_sts_bits[] = {
146 [2] = "BIOS",
147 [3] = "LEGACY_USB",
148 [4] = "SLP_SMI",
149 [5] = "APM",
150 [6] = "SWSMI_TMR",
151 [8] = "PM1",
152 [9] = "GPE0",
153 [10] = "GPI",
154 [11] = "MCSMI",
155 [12] = "DEVMON",
156 [13] = "TCO",
157 [14] = "PERIODIC",
158 [15] = "SERIRQ_SMI",
159 [16] = "SMBUS_SMI",
160 [17] = "LEGACY_USB2",
161 [18] = "INTEL_USB2",
162 [20] = "PCI_EXP_SMI",
163 [21] = "MONITOR",
164 [26] = "SPI",
165 [27] = "GPIO_UNLOCK"
166 };
167
168 if (!smi_sts)
169 return 0;
170
171 printk(BIOS_DEBUG, "SMI_STS: ");
172 print_status_bits(smi_sts, smi_sts_bits);
173 printk(BIOS_DEBUG, "\n");
174
175 return smi_sts;
176}
177
178/* Print, clear, and return SMI status */
179u32 clear_smi_status(void)
180{
181 return print_smi_status(reset_smi_status());
182}
183
184/* Enable SMI event */
185void enable_smi(u32 mask)
186{
Angel Ponsf92f2732020-09-25 00:44:52 +0200187 u32 smi_en = inl(get_pmbase() + SMI_EN);
Duncan Lauriec88c54c2014-04-30 16:36:13 -0700188 smi_en |= mask;
Angel Ponsf92f2732020-09-25 00:44:52 +0200189 outl(smi_en, get_pmbase() + SMI_EN);
Duncan Lauriec88c54c2014-04-30 16:36:13 -0700190}
191
192/* Disable SMI event */
193void disable_smi(u32 mask)
194{
Angel Ponsf92f2732020-09-25 00:44:52 +0200195 u32 smi_en = inl(get_pmbase() + SMI_EN);
Duncan Lauriec88c54c2014-04-30 16:36:13 -0700196 smi_en &= ~mask;
Angel Ponsf92f2732020-09-25 00:44:52 +0200197 outl(smi_en, get_pmbase() + SMI_EN);
Duncan Lauriec88c54c2014-04-30 16:36:13 -0700198}
199
Duncan Lauriec88c54c2014-04-30 16:36:13 -0700200/*
201 * ALT_GP_SMI
202 */
203
204/* Clear GPIO SMI status and return events that are enabled and active */
205static u32 reset_alt_smi_status(void)
206{
207 u32 alt_sts, alt_en;
208
209 /* Low Power variant moves this to GPIO region as dword */
Angel Ponsf92f2732020-09-25 00:44:52 +0200210 alt_sts = inl(get_gpiobase() + GPIO_ALT_GPI_SMI_STS);
211 outl(alt_sts, get_gpiobase() + GPIO_ALT_GPI_SMI_STS);
212 alt_en = inl(get_gpiobase() + GPIO_ALT_GPI_SMI_EN);
Duncan Lauriec88c54c2014-04-30 16:36:13 -0700213
214 /* Only report enabled events */
215 return alt_sts & alt_en;
216}
217
218/* Print GPIO SMI status bits */
219static u32 print_alt_smi_status(u32 alt_sts)
220{
221 if (!alt_sts)
222 return 0;
223
224 printk(BIOS_DEBUG, "ALT_STS: ");
225
226 /* First 16 events are GPIO 32-47 */
227 print_gpio_status(alt_sts & 0xffff, 32);
228
229 printk(BIOS_DEBUG, "\n");
230
231 return alt_sts;
232}
233
234/* Print, clear, and return GPIO SMI status */
235u32 clear_alt_smi_status(void)
236{
237 return print_alt_smi_status(reset_alt_smi_status());
238}
239
240/* Enable GPIO SMI events */
241void enable_alt_smi(u32 mask)
242{
243 u32 alt_en;
244
Angel Ponsf92f2732020-09-25 00:44:52 +0200245 alt_en = inl(get_gpiobase() + GPIO_ALT_GPI_SMI_EN);
Duncan Lauriec88c54c2014-04-30 16:36:13 -0700246 alt_en |= mask;
Angel Ponsf92f2732020-09-25 00:44:52 +0200247 outl(alt_en, get_gpiobase() + GPIO_ALT_GPI_SMI_EN);
Duncan Lauriec88c54c2014-04-30 16:36:13 -0700248}
249
Duncan Lauriec88c54c2014-04-30 16:36:13 -0700250/*
251 * TCO
252 */
253
254/* Clear TCO status and return events that are enabled and active */
255static u32 reset_tco_status(void)
256{
Angel Ponsf92f2732020-09-25 00:44:52 +0200257 u32 tcobase = get_pmbase() + 0x60;
Duncan Lauriec88c54c2014-04-30 16:36:13 -0700258 u32 tco_sts = inl(tcobase + 0x04);
Angel Ponsf92f2732020-09-25 00:44:52 +0200259 u32 tco_en = inl(get_pmbase() + 0x68);
Duncan Lauriec88c54c2014-04-30 16:36:13 -0700260
261 /* Don't clear BOOT_STS before SECOND_TO_STS */
262 outl(tco_sts & ~(1 << 18), tcobase + 0x04);
263
264 /* Clear BOOT_STS */
265 if (tco_sts & (1 << 18))
266 outl(tco_sts & (1 << 18), tcobase + 0x04);
267
268 return tco_sts & tco_en;
269}
270
271/* Print TCO status bits */
272static u32 print_tco_status(u32 tco_sts)
273{
274 const char *tco_sts_bits[] = {
275 [0] = "NMI2SMI",
276 [1] = "SW_TCO",
277 [2] = "TCO_INT",
278 [3] = "TIMEOUT",
279 [7] = "NEWCENTURY",
280 [8] = "BIOSWR",
281 [9] = "DMISCI",
282 [10] = "DMISMI",
283 [12] = "DMISERR",
284 [13] = "SLVSEL",
285 [16] = "INTRD_DET",
286 [17] = "SECOND_TO",
287 [18] = "BOOT",
288 [20] = "SMLINK_SLV"
289 };
290
291 if (!tco_sts)
292 return 0;
293
294 printk(BIOS_DEBUG, "TCO_STS: ");
295 print_status_bits(tco_sts, tco_sts_bits);
296 printk(BIOS_DEBUG, "\n");
297
298 return tco_sts;
299}
300
301/* Print, clear, and return TCO status */
302u32 clear_tco_status(void)
303{
304 return print_tco_status(reset_tco_status());
305}
306
307/* Enable TCO SCI */
308void enable_tco_sci(void)
309{
310 /* Clear pending events */
Kyösti Mälkkie10bf582022-11-15 14:00:22 +0200311 outl(TCOSCI_STS, get_pmbase() + GPE0_STS(3));
Duncan Lauriec88c54c2014-04-30 16:36:13 -0700312
313 /* Enable TCO SCI events */
314 enable_gpe(TCOSCI_EN);
315}
316
Duncan Lauriec88c54c2014-04-30 16:36:13 -0700317/*
318 * GPE0
319 */
320
321/* Clear a GPE0 status and return events that are enabled and active */
Angel Pons2ead3632020-09-24 16:50:05 +0200322static u32 reset_gpe_status(u16 sts_reg, u16 en_reg)
Duncan Lauriec88c54c2014-04-30 16:36:13 -0700323{
Angel Ponsf92f2732020-09-25 00:44:52 +0200324 u32 gpe0_sts = inl(get_pmbase() + sts_reg);
325 u32 gpe0_en = inl(get_pmbase() + en_reg);
Duncan Lauriec88c54c2014-04-30 16:36:13 -0700326
Angel Ponsf92f2732020-09-25 00:44:52 +0200327 outl(gpe0_sts, get_pmbase() + sts_reg);
Duncan Lauriec88c54c2014-04-30 16:36:13 -0700328
329 /* Only report enabled events */
330 return gpe0_sts & gpe0_en;
331}
332
333/* Print GPE0 status bits */
334static u32 print_gpe_status(u32 gpe0_sts, const char *bit_names[])
335{
336 if (!gpe0_sts)
337 return 0;
338
339 printk(BIOS_DEBUG, "GPE0_STS: ");
340 print_status_bits(gpe0_sts, bit_names);
341 printk(BIOS_DEBUG, "\n");
342
343 return gpe0_sts;
344}
345
346/* Print GPE0 GPIO status bits */
347static u32 print_gpe_gpio(u32 gpe0_sts, int start)
348{
349 if (!gpe0_sts)
350 return 0;
351
352 printk(BIOS_DEBUG, "GPE0_STS: ");
353 print_gpio_status(gpe0_sts, start);
354 printk(BIOS_DEBUG, "\n");
355
356 return gpe0_sts;
357}
358
359/* Clear all GPE status and return "standard" GPE event status */
360u32 clear_gpe_status(void)
361{
362 const char *gpe0_sts_3_bits[] = {
363 [1] = "HOTPLUG",
364 [2] = "SWGPE",
365 [6] = "TCO_SCI",
366 [7] = "SMB_WAK",
367 [9] = "PCI_EXP",
368 [10] = "BATLOW",
369 [11] = "PME",
370 [12] = "ME",
371 [13] = "PME_B0",
372 [16] = "GPIO27",
373 [18] = "WADT"
374 };
375
Angel Pons2ead3632020-09-24 16:50:05 +0200376 print_gpe_gpio(reset_gpe_status(GPE0_STS(GPE_31_0), GPE0_EN(GPE_31_0)), 0);
377 print_gpe_gpio(reset_gpe_status(GPE0_STS(GPE_63_32), GPE0_EN(GPE_63_32)), 32);
378 print_gpe_gpio(reset_gpe_status(GPE0_STS(GPE_94_64), GPE0_EN(GPE_94_64)), 64);
379 return print_gpe_status(reset_gpe_status(GPE0_STS(GPE_STD), GPE0_EN(GPE_STD)),
Duncan Lauriec88c54c2014-04-30 16:36:13 -0700380 gpe0_sts_3_bits);
381}
382
383/* Enable all requested GPE */
384void enable_all_gpe(u32 set1, u32 set2, u32 set3, u32 set4)
385{
Angel Ponsf92f2732020-09-25 00:44:52 +0200386 u16 pmbase = get_pmbase();
387
388 outl(set1, pmbase + GPE0_EN(GPE_31_0));
389 outl(set2, pmbase + GPE0_EN(GPE_63_32));
390 outl(set3, pmbase + GPE0_EN(GPE_94_64));
391 outl(set4, pmbase + GPE0_EN(GPE_STD));
Duncan Lauriec88c54c2014-04-30 16:36:13 -0700392}
393
394/* Disable all GPE */
395void disable_all_gpe(void)
396{
397 enable_all_gpe(0, 0, 0, 0);
398}
399
400/* Enable a standard GPE */
401void enable_gpe(u32 mask)
402{
Angel Ponsf92f2732020-09-25 00:44:52 +0200403 u32 gpe0_en = inl(get_pmbase() + GPE0_EN(GPE_STD));
Duncan Lauriec88c54c2014-04-30 16:36:13 -0700404 gpe0_en |= mask;
Angel Ponsf92f2732020-09-25 00:44:52 +0200405 outl(gpe0_en, get_pmbase() + GPE0_EN(GPE_STD));
Duncan Lauriec88c54c2014-04-30 16:36:13 -0700406}
407
408/* Disable a standard GPE */
409void disable_gpe(u32 mask)
410{
Angel Ponsf92f2732020-09-25 00:44:52 +0200411 u32 gpe0_en = inl(get_pmbase() + GPE0_EN(GPE_STD));
Duncan Lauriec88c54c2014-04-30 16:36:13 -0700412 gpe0_en &= ~mask;
Angel Ponsf92f2732020-09-25 00:44:52 +0200413 outl(gpe0_en, get_pmbase() + GPE0_EN(GPE_STD));
Duncan Lauriec88c54c2014-04-30 16:36:13 -0700414}
415
Bill XIE516c0a52020-02-24 23:08:35 +0800416int platform_is_resuming(void)
Joel Kitching1d93b882018-09-26 17:58:14 +0800417{
Angel Ponsf92f2732020-09-25 00:44:52 +0200418 if (!(inw(get_pmbase() + PM1_STS) & WAK_STS))
Joel Kitching1d93b882018-09-26 17:58:14 +0800419 return 0;
420
Angel Ponsf92f2732020-09-25 00:44:52 +0200421 return acpi_sleep_from_pm1(inl(get_pmbase() + PM1_CNT)) == ACPI_S3;
Joel Kitching1d93b882018-09-26 17:58:14 +0800422}
Eugene Myersebc84232020-01-21 16:46:16 -0500423
424/* STM Support */
425uint16_t get_pmbase(void)
426{
Elyes Haouas9018dee2022-11-18 15:07:33 +0100427 return (uint16_t)ACPI_BASE_ADDRESS;
Eugene Myersebc84232020-01-21 16:46:16 -0500428}