blob: 3da6bcea3192349197015c6a2991c396e56770fc [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>
14#include <device/pci_def.h>
15#include <console/console.h>
Julius Werner4ee4bd52014-10-20 13:46:39 -070016#include <soc/iomap.h>
17#include <soc/lpc.h>
18#include <soc/pci_devs.h>
19#include <soc/pm.h>
Philipp Deppenwiesefea24292017-10-17 17:02:29 +020020#include <security/vboot/vbnv.h>
Angel Ponsf92f2732020-09-25 00:44:52 +020021#include <stdint.h>
22
Angel Pons733f03d2021-01-28 16:59:04 +010023#define GPIO_ALT_GPI_SMI_STS 0x50
24#define GPIO_ALT_GPI_SMI_EN 0x54
25
Angel Ponsf92f2732020-09-25 00:44:52 +020026static inline uint16_t get_gpiobase(void)
27{
28 return GPIO_BASE_ADDRESS;
29}
Duncan Lauriec88c54c2014-04-30 16:36:13 -070030
31/* Print status bits with descriptive names */
32static void print_status_bits(u32 status, const char *bit_names[])
33{
34 int i;
35
36 if (!status)
37 return;
38
Lee Leahy26b7cd02017-03-16 18:47:55 -070039 for (i = 31; i >= 0; i--) {
Duncan Lauriec88c54c2014-04-30 16:36:13 -070040 if (status & (1 << i)) {
41 if (bit_names[i])
42 printk(BIOS_DEBUG, "%s ", bit_names[i]);
43 else
44 printk(BIOS_DEBUG, "BIT%d ", i);
45 }
46 }
47}
48
49/* Print status bits as GPIO numbers */
50static void print_gpio_status(u32 status, int start)
51{
52 int i;
53
54 if (!status)
55 return;
56
Lee Leahy26b7cd02017-03-16 18:47:55 -070057 for (i = 31; i >= 0; i--) {
Duncan Lauriec88c54c2014-04-30 16:36:13 -070058 if (status & (1 << i))
59 printk(BIOS_DEBUG, "GPIO%d ", start + i);
60 }
61}
62
Duncan Lauriec88c54c2014-04-30 16:36:13 -070063/*
64 * PM1_CNT
65 */
66
67/* Enable events in PM1 control register */
68void enable_pm1_control(u32 mask)
69{
Angel Ponsf92f2732020-09-25 00:44:52 +020070 u32 pm1_cnt = inl(get_pmbase() + PM1_CNT);
Duncan Lauriec88c54c2014-04-30 16:36:13 -070071 pm1_cnt |= mask;
Angel Ponsf92f2732020-09-25 00:44:52 +020072 outl(pm1_cnt, get_pmbase() + PM1_CNT);
Duncan Lauriec88c54c2014-04-30 16:36:13 -070073}
74
75/* Disable events in PM1 control register */
76void disable_pm1_control(u32 mask)
77{
Angel Ponsf92f2732020-09-25 00:44:52 +020078 u32 pm1_cnt = inl(get_pmbase() + PM1_CNT);
Duncan Lauriec88c54c2014-04-30 16:36:13 -070079 pm1_cnt &= ~mask;
Angel Ponsf92f2732020-09-25 00:44:52 +020080 outl(pm1_cnt, get_pmbase() + PM1_CNT);
Duncan Lauriec88c54c2014-04-30 16:36:13 -070081}
82
Duncan Lauriec88c54c2014-04-30 16:36:13 -070083/*
84 * PM1
85 */
86
87/* Clear and return PM1 status register */
88static u16 reset_pm1_status(void)
89{
Angel Ponsf92f2732020-09-25 00:44:52 +020090 u16 pm1_sts = inw(get_pmbase() + PM1_STS);
91 outw(pm1_sts, get_pmbase() + PM1_STS);
Duncan Lauriec88c54c2014-04-30 16:36:13 -070092 return pm1_sts;
93}
94
95/* Print PM1 status bits */
96static u16 print_pm1_status(u16 pm1_sts)
97{
98 const char *pm1_sts_bits[] = {
99 [0] = "TMROF",
100 [4] = "BM",
101 [5] = "GBL",
102 [8] = "PWRBTN",
103 [10] = "RTC",
104 [11] = "PRBTNOR",
105 [14] = "PCIEXPWAK",
106 [15] = "WAK",
107 };
108
109 if (!pm1_sts)
110 return 0;
111
112 printk(BIOS_SPEW, "PM1_STS: ");
113 print_status_bits(pm1_sts, pm1_sts_bits);
114 printk(BIOS_SPEW, "\n");
115
116 return pm1_sts;
117}
118
119/* Print, clear, and return PM1 status */
120u16 clear_pm1_status(void)
121{
122 return print_pm1_status(reset_pm1_status());
123}
124
125/* Set the PM1 register to events */
126void enable_pm1(u16 events)
127{
Angel Ponsf92f2732020-09-25 00:44:52 +0200128 outw(events, get_pmbase() + PM1_EN);
Duncan Lauriec88c54c2014-04-30 16:36:13 -0700129}
130
Duncan Lauriec88c54c2014-04-30 16:36:13 -0700131/*
132 * SMI
133 */
134
135/* Clear and return SMI status register */
136static u32 reset_smi_status(void)
137{
Angel Ponsf92f2732020-09-25 00:44:52 +0200138 u32 smi_sts = inl(get_pmbase() + SMI_STS);
139 outl(smi_sts, get_pmbase() + SMI_STS);
Duncan Lauriec88c54c2014-04-30 16:36:13 -0700140 return smi_sts;
141}
142
143/* Print SMI status bits */
144static u32 print_smi_status(u32 smi_sts)
145{
146 const char *smi_sts_bits[] = {
147 [2] = "BIOS",
148 [3] = "LEGACY_USB",
149 [4] = "SLP_SMI",
150 [5] = "APM",
151 [6] = "SWSMI_TMR",
152 [8] = "PM1",
153 [9] = "GPE0",
154 [10] = "GPI",
155 [11] = "MCSMI",
156 [12] = "DEVMON",
157 [13] = "TCO",
158 [14] = "PERIODIC",
159 [15] = "SERIRQ_SMI",
160 [16] = "SMBUS_SMI",
161 [17] = "LEGACY_USB2",
162 [18] = "INTEL_USB2",
163 [20] = "PCI_EXP_SMI",
164 [21] = "MONITOR",
165 [26] = "SPI",
166 [27] = "GPIO_UNLOCK"
167 };
168
169 if (!smi_sts)
170 return 0;
171
172 printk(BIOS_DEBUG, "SMI_STS: ");
173 print_status_bits(smi_sts, smi_sts_bits);
174 printk(BIOS_DEBUG, "\n");
175
176 return smi_sts;
177}
178
179/* Print, clear, and return SMI status */
180u32 clear_smi_status(void)
181{
182 return print_smi_status(reset_smi_status());
183}
184
185/* Enable SMI event */
186void enable_smi(u32 mask)
187{
Angel Ponsf92f2732020-09-25 00:44:52 +0200188 u32 smi_en = inl(get_pmbase() + SMI_EN);
Duncan Lauriec88c54c2014-04-30 16:36:13 -0700189 smi_en |= mask;
Angel Ponsf92f2732020-09-25 00:44:52 +0200190 outl(smi_en, get_pmbase() + SMI_EN);
Duncan Lauriec88c54c2014-04-30 16:36:13 -0700191}
192
193/* Disable SMI event */
194void disable_smi(u32 mask)
195{
Angel Ponsf92f2732020-09-25 00:44:52 +0200196 u32 smi_en = inl(get_pmbase() + SMI_EN);
Duncan Lauriec88c54c2014-04-30 16:36:13 -0700197 smi_en &= ~mask;
Angel Ponsf92f2732020-09-25 00:44:52 +0200198 outl(smi_en, get_pmbase() + SMI_EN);
Duncan Lauriec88c54c2014-04-30 16:36:13 -0700199}
200
Duncan Lauriec88c54c2014-04-30 16:36:13 -0700201/*
202 * ALT_GP_SMI
203 */
204
205/* Clear GPIO SMI status and return events that are enabled and active */
206static u32 reset_alt_smi_status(void)
207{
208 u32 alt_sts, alt_en;
209
210 /* Low Power variant moves this to GPIO region as dword */
Angel Ponsf92f2732020-09-25 00:44:52 +0200211 alt_sts = inl(get_gpiobase() + GPIO_ALT_GPI_SMI_STS);
212 outl(alt_sts, get_gpiobase() + GPIO_ALT_GPI_SMI_STS);
213 alt_en = inl(get_gpiobase() + GPIO_ALT_GPI_SMI_EN);
Duncan Lauriec88c54c2014-04-30 16:36:13 -0700214
215 /* Only report enabled events */
216 return alt_sts & alt_en;
217}
218
219/* Print GPIO SMI status bits */
220static u32 print_alt_smi_status(u32 alt_sts)
221{
222 if (!alt_sts)
223 return 0;
224
225 printk(BIOS_DEBUG, "ALT_STS: ");
226
227 /* First 16 events are GPIO 32-47 */
228 print_gpio_status(alt_sts & 0xffff, 32);
229
230 printk(BIOS_DEBUG, "\n");
231
232 return alt_sts;
233}
234
235/* Print, clear, and return GPIO SMI status */
236u32 clear_alt_smi_status(void)
237{
238 return print_alt_smi_status(reset_alt_smi_status());
239}
240
241/* Enable GPIO SMI events */
242void enable_alt_smi(u32 mask)
243{
244 u32 alt_en;
245
Angel Ponsf92f2732020-09-25 00:44:52 +0200246 alt_en = inl(get_gpiobase() + GPIO_ALT_GPI_SMI_EN);
Duncan Lauriec88c54c2014-04-30 16:36:13 -0700247 alt_en |= mask;
Angel Ponsf92f2732020-09-25 00:44:52 +0200248 outl(alt_en, get_gpiobase() + GPIO_ALT_GPI_SMI_EN);
Duncan Lauriec88c54c2014-04-30 16:36:13 -0700249}
250
Duncan Lauriec88c54c2014-04-30 16:36:13 -0700251/*
252 * TCO
253 */
254
255/* Clear TCO status and return events that are enabled and active */
256static u32 reset_tco_status(void)
257{
Angel Ponsf92f2732020-09-25 00:44:52 +0200258 u32 tcobase = get_pmbase() + 0x60;
Duncan Lauriec88c54c2014-04-30 16:36:13 -0700259 u32 tco_sts = inl(tcobase + 0x04);
Angel Ponsf92f2732020-09-25 00:44:52 +0200260 u32 tco_en = inl(get_pmbase() + 0x68);
Duncan Lauriec88c54c2014-04-30 16:36:13 -0700261
262 /* Don't clear BOOT_STS before SECOND_TO_STS */
263 outl(tco_sts & ~(1 << 18), tcobase + 0x04);
264
265 /* Clear BOOT_STS */
266 if (tco_sts & (1 << 18))
267 outl(tco_sts & (1 << 18), tcobase + 0x04);
268
269 return tco_sts & tco_en;
270}
271
272/* Print TCO status bits */
273static u32 print_tco_status(u32 tco_sts)
274{
275 const char *tco_sts_bits[] = {
276 [0] = "NMI2SMI",
277 [1] = "SW_TCO",
278 [2] = "TCO_INT",
279 [3] = "TIMEOUT",
280 [7] = "NEWCENTURY",
281 [8] = "BIOSWR",
282 [9] = "DMISCI",
283 [10] = "DMISMI",
284 [12] = "DMISERR",
285 [13] = "SLVSEL",
286 [16] = "INTRD_DET",
287 [17] = "SECOND_TO",
288 [18] = "BOOT",
289 [20] = "SMLINK_SLV"
290 };
291
292 if (!tco_sts)
293 return 0;
294
295 printk(BIOS_DEBUG, "TCO_STS: ");
296 print_status_bits(tco_sts, tco_sts_bits);
297 printk(BIOS_DEBUG, "\n");
298
299 return tco_sts;
300}
301
302/* Print, clear, and return TCO status */
303u32 clear_tco_status(void)
304{
305 return print_tco_status(reset_tco_status());
306}
307
308/* Enable TCO SCI */
309void enable_tco_sci(void)
310{
311 /* Clear pending events */
Kyösti Mälkkie10bf582022-11-15 14:00:22 +0200312 outl(TCOSCI_STS, get_pmbase() + GPE0_STS(3));
Duncan Lauriec88c54c2014-04-30 16:36:13 -0700313
314 /* Enable TCO SCI events */
315 enable_gpe(TCOSCI_EN);
316}
317
Duncan Lauriec88c54c2014-04-30 16:36:13 -0700318/*
319 * GPE0
320 */
321
322/* Clear a GPE0 status and return events that are enabled and active */
Angel Pons2ead3632020-09-24 16:50:05 +0200323static u32 reset_gpe_status(u16 sts_reg, u16 en_reg)
Duncan Lauriec88c54c2014-04-30 16:36:13 -0700324{
Angel Ponsf92f2732020-09-25 00:44:52 +0200325 u32 gpe0_sts = inl(get_pmbase() + sts_reg);
326 u32 gpe0_en = inl(get_pmbase() + en_reg);
Duncan Lauriec88c54c2014-04-30 16:36:13 -0700327
Angel Ponsf92f2732020-09-25 00:44:52 +0200328 outl(gpe0_sts, get_pmbase() + sts_reg);
Duncan Lauriec88c54c2014-04-30 16:36:13 -0700329
330 /* Only report enabled events */
331 return gpe0_sts & gpe0_en;
332}
333
334/* Print GPE0 status bits */
335static u32 print_gpe_status(u32 gpe0_sts, const char *bit_names[])
336{
337 if (!gpe0_sts)
338 return 0;
339
340 printk(BIOS_DEBUG, "GPE0_STS: ");
341 print_status_bits(gpe0_sts, bit_names);
342 printk(BIOS_DEBUG, "\n");
343
344 return gpe0_sts;
345}
346
347/* Print GPE0 GPIO status bits */
348static u32 print_gpe_gpio(u32 gpe0_sts, int start)
349{
350 if (!gpe0_sts)
351 return 0;
352
353 printk(BIOS_DEBUG, "GPE0_STS: ");
354 print_gpio_status(gpe0_sts, start);
355 printk(BIOS_DEBUG, "\n");
356
357 return gpe0_sts;
358}
359
360/* Clear all GPE status and return "standard" GPE event status */
361u32 clear_gpe_status(void)
362{
363 const char *gpe0_sts_3_bits[] = {
364 [1] = "HOTPLUG",
365 [2] = "SWGPE",
366 [6] = "TCO_SCI",
367 [7] = "SMB_WAK",
368 [9] = "PCI_EXP",
369 [10] = "BATLOW",
370 [11] = "PME",
371 [12] = "ME",
372 [13] = "PME_B0",
373 [16] = "GPIO27",
374 [18] = "WADT"
375 };
376
Angel Pons2ead3632020-09-24 16:50:05 +0200377 print_gpe_gpio(reset_gpe_status(GPE0_STS(GPE_31_0), GPE0_EN(GPE_31_0)), 0);
378 print_gpe_gpio(reset_gpe_status(GPE0_STS(GPE_63_32), GPE0_EN(GPE_63_32)), 32);
379 print_gpe_gpio(reset_gpe_status(GPE0_STS(GPE_94_64), GPE0_EN(GPE_94_64)), 64);
380 return print_gpe_status(reset_gpe_status(GPE0_STS(GPE_STD), GPE0_EN(GPE_STD)),
Duncan Lauriec88c54c2014-04-30 16:36:13 -0700381 gpe0_sts_3_bits);
382}
383
384/* Enable all requested GPE */
385void enable_all_gpe(u32 set1, u32 set2, u32 set3, u32 set4)
386{
Angel Ponsf92f2732020-09-25 00:44:52 +0200387 u16 pmbase = get_pmbase();
388
389 outl(set1, pmbase + GPE0_EN(GPE_31_0));
390 outl(set2, pmbase + GPE0_EN(GPE_63_32));
391 outl(set3, pmbase + GPE0_EN(GPE_94_64));
392 outl(set4, pmbase + GPE0_EN(GPE_STD));
Duncan Lauriec88c54c2014-04-30 16:36:13 -0700393}
394
395/* Disable all GPE */
396void disable_all_gpe(void)
397{
398 enable_all_gpe(0, 0, 0, 0);
399}
400
401/* Enable a standard GPE */
402void enable_gpe(u32 mask)
403{
Angel Ponsf92f2732020-09-25 00:44:52 +0200404 u32 gpe0_en = inl(get_pmbase() + GPE0_EN(GPE_STD));
Duncan Lauriec88c54c2014-04-30 16:36:13 -0700405 gpe0_en |= mask;
Angel Ponsf92f2732020-09-25 00:44:52 +0200406 outl(gpe0_en, get_pmbase() + GPE0_EN(GPE_STD));
Duncan Lauriec88c54c2014-04-30 16:36:13 -0700407}
408
409/* Disable a standard GPE */
410void disable_gpe(u32 mask)
411{
Angel Ponsf92f2732020-09-25 00:44:52 +0200412 u32 gpe0_en = inl(get_pmbase() + GPE0_EN(GPE_STD));
Duncan Lauriec88c54c2014-04-30 16:36:13 -0700413 gpe0_en &= ~mask;
Angel Ponsf92f2732020-09-25 00:44:52 +0200414 outl(gpe0_en, get_pmbase() + GPE0_EN(GPE_STD));
Duncan Lauriec88c54c2014-04-30 16:36:13 -0700415}
416
Bill XIE516c0a52020-02-24 23:08:35 +0800417int platform_is_resuming(void)
Joel Kitching1d93b882018-09-26 17:58:14 +0800418{
Angel Ponsf92f2732020-09-25 00:44:52 +0200419 if (!(inw(get_pmbase() + PM1_STS) & WAK_STS))
Joel Kitching1d93b882018-09-26 17:58:14 +0800420 return 0;
421
Angel Ponsf92f2732020-09-25 00:44:52 +0200422 return acpi_sleep_from_pm1(inl(get_pmbase() + PM1_CNT)) == ACPI_S3;
Joel Kitching1d93b882018-09-26 17:58:14 +0800423}
Eugene Myersebc84232020-01-21 16:46:16 -0500424
425/* STM Support */
426uint16_t get_pmbase(void)
427{
428 return (uint16_t) ACPI_BASE_ADDRESS;
429}