blob: e63a981456a369b61521f93d17c475d47c774432 [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>
20#include <soc/gpio.h>
Philipp Deppenwiesefea24292017-10-17 17:02:29 +020021#include <security/vboot/vbnv.h>
Angel Ponsf92f2732020-09-25 00:44:52 +020022#include <stdint.h>
23
24static inline uint16_t get_gpiobase(void)
25{
26 return GPIO_BASE_ADDRESS;
27}
Duncan Lauriec88c54c2014-04-30 16:36:13 -070028
29/* Print status bits with descriptive names */
30static void print_status_bits(u32 status, const char *bit_names[])
31{
32 int i;
33
34 if (!status)
35 return;
36
Lee Leahy26b7cd02017-03-16 18:47:55 -070037 for (i = 31; i >= 0; i--) {
Duncan Lauriec88c54c2014-04-30 16:36:13 -070038 if (status & (1 << i)) {
39 if (bit_names[i])
40 printk(BIOS_DEBUG, "%s ", bit_names[i]);
41 else
42 printk(BIOS_DEBUG, "BIT%d ", i);
43 }
44 }
45}
46
47/* Print status bits as GPIO numbers */
48static void print_gpio_status(u32 status, int start)
49{
50 int i;
51
52 if (!status)
53 return;
54
Lee Leahy26b7cd02017-03-16 18:47:55 -070055 for (i = 31; i >= 0; i--) {
Duncan Lauriec88c54c2014-04-30 16:36:13 -070056 if (status & (1 << i))
57 printk(BIOS_DEBUG, "GPIO%d ", start + i);
58 }
59}
60
Duncan Lauriec88c54c2014-04-30 16:36:13 -070061/*
62 * PM1_CNT
63 */
64
65/* Enable events in PM1 control register */
66void enable_pm1_control(u32 mask)
67{
Angel Ponsf92f2732020-09-25 00:44:52 +020068 u32 pm1_cnt = inl(get_pmbase() + PM1_CNT);
Duncan Lauriec88c54c2014-04-30 16:36:13 -070069 pm1_cnt |= mask;
Angel Ponsf92f2732020-09-25 00:44:52 +020070 outl(pm1_cnt, get_pmbase() + PM1_CNT);
Duncan Lauriec88c54c2014-04-30 16:36:13 -070071}
72
73/* Disable events in PM1 control register */
74void disable_pm1_control(u32 mask)
75{
Angel Ponsf92f2732020-09-25 00:44:52 +020076 u32 pm1_cnt = inl(get_pmbase() + PM1_CNT);
Duncan Lauriec88c54c2014-04-30 16:36:13 -070077 pm1_cnt &= ~mask;
Angel Ponsf92f2732020-09-25 00:44:52 +020078 outl(pm1_cnt, get_pmbase() + PM1_CNT);
Duncan Lauriec88c54c2014-04-30 16:36:13 -070079}
80
Duncan Lauriec88c54c2014-04-30 16:36:13 -070081/*
82 * PM1
83 */
84
85/* Clear and return PM1 status register */
86static u16 reset_pm1_status(void)
87{
Angel Ponsf92f2732020-09-25 00:44:52 +020088 u16 pm1_sts = inw(get_pmbase() + PM1_STS);
89 outw(pm1_sts, get_pmbase() + PM1_STS);
Duncan Lauriec88c54c2014-04-30 16:36:13 -070090 return pm1_sts;
91}
92
93/* Print PM1 status bits */
94static u16 print_pm1_status(u16 pm1_sts)
95{
96 const char *pm1_sts_bits[] = {
97 [0] = "TMROF",
98 [4] = "BM",
99 [5] = "GBL",
100 [8] = "PWRBTN",
101 [10] = "RTC",
102 [11] = "PRBTNOR",
103 [14] = "PCIEXPWAK",
104 [15] = "WAK",
105 };
106
107 if (!pm1_sts)
108 return 0;
109
110 printk(BIOS_SPEW, "PM1_STS: ");
111 print_status_bits(pm1_sts, pm1_sts_bits);
112 printk(BIOS_SPEW, "\n");
113
114 return pm1_sts;
115}
116
117/* Print, clear, and return PM1 status */
118u16 clear_pm1_status(void)
119{
120 return print_pm1_status(reset_pm1_status());
121}
122
123/* Set the PM1 register to events */
124void enable_pm1(u16 events)
125{
Angel Ponsf92f2732020-09-25 00:44:52 +0200126 outw(events, get_pmbase() + PM1_EN);
Duncan Lauriec88c54c2014-04-30 16:36:13 -0700127}
128
Duncan Lauriec88c54c2014-04-30 16:36:13 -0700129/*
130 * SMI
131 */
132
133/* Clear and return SMI status register */
134static u32 reset_smi_status(void)
135{
Angel Ponsf92f2732020-09-25 00:44:52 +0200136 u32 smi_sts = inl(get_pmbase() + SMI_STS);
137 outl(smi_sts, get_pmbase() + SMI_STS);
Duncan Lauriec88c54c2014-04-30 16:36:13 -0700138 return smi_sts;
139}
140
141/* Print SMI status bits */
142static u32 print_smi_status(u32 smi_sts)
143{
144 const char *smi_sts_bits[] = {
145 [2] = "BIOS",
146 [3] = "LEGACY_USB",
147 [4] = "SLP_SMI",
148 [5] = "APM",
149 [6] = "SWSMI_TMR",
150 [8] = "PM1",
151 [9] = "GPE0",
152 [10] = "GPI",
153 [11] = "MCSMI",
154 [12] = "DEVMON",
155 [13] = "TCO",
156 [14] = "PERIODIC",
157 [15] = "SERIRQ_SMI",
158 [16] = "SMBUS_SMI",
159 [17] = "LEGACY_USB2",
160 [18] = "INTEL_USB2",
161 [20] = "PCI_EXP_SMI",
162 [21] = "MONITOR",
163 [26] = "SPI",
164 [27] = "GPIO_UNLOCK"
165 };
166
167 if (!smi_sts)
168 return 0;
169
170 printk(BIOS_DEBUG, "SMI_STS: ");
171 print_status_bits(smi_sts, smi_sts_bits);
172 printk(BIOS_DEBUG, "\n");
173
174 return smi_sts;
175}
176
177/* Print, clear, and return SMI status */
178u32 clear_smi_status(void)
179{
180 return print_smi_status(reset_smi_status());
181}
182
183/* Enable SMI event */
184void enable_smi(u32 mask)
185{
Angel Ponsf92f2732020-09-25 00:44:52 +0200186 u32 smi_en = inl(get_pmbase() + SMI_EN);
Duncan Lauriec88c54c2014-04-30 16:36:13 -0700187 smi_en |= mask;
Angel Ponsf92f2732020-09-25 00:44:52 +0200188 outl(smi_en, get_pmbase() + SMI_EN);
Duncan Lauriec88c54c2014-04-30 16:36:13 -0700189}
190
191/* Disable SMI event */
192void disable_smi(u32 mask)
193{
Angel Ponsf92f2732020-09-25 00:44:52 +0200194 u32 smi_en = inl(get_pmbase() + SMI_EN);
Duncan Lauriec88c54c2014-04-30 16:36:13 -0700195 smi_en &= ~mask;
Angel Ponsf92f2732020-09-25 00:44:52 +0200196 outl(smi_en, get_pmbase() + SMI_EN);
Duncan Lauriec88c54c2014-04-30 16:36:13 -0700197}
198
Duncan Lauriec88c54c2014-04-30 16:36:13 -0700199/*
200 * ALT_GP_SMI
201 */
202
203/* Clear GPIO SMI status and return events that are enabled and active */
204static u32 reset_alt_smi_status(void)
205{
206 u32 alt_sts, alt_en;
207
208 /* Low Power variant moves this to GPIO region as dword */
Angel Ponsf92f2732020-09-25 00:44:52 +0200209 alt_sts = inl(get_gpiobase() + GPIO_ALT_GPI_SMI_STS);
210 outl(alt_sts, get_gpiobase() + GPIO_ALT_GPI_SMI_STS);
211 alt_en = inl(get_gpiobase() + GPIO_ALT_GPI_SMI_EN);
Duncan Lauriec88c54c2014-04-30 16:36:13 -0700212
213 /* Only report enabled events */
214 return alt_sts & alt_en;
215}
216
217/* Print GPIO SMI status bits */
218static u32 print_alt_smi_status(u32 alt_sts)
219{
220 if (!alt_sts)
221 return 0;
222
223 printk(BIOS_DEBUG, "ALT_STS: ");
224
225 /* First 16 events are GPIO 32-47 */
226 print_gpio_status(alt_sts & 0xffff, 32);
227
228 printk(BIOS_DEBUG, "\n");
229
230 return alt_sts;
231}
232
233/* Print, clear, and return GPIO SMI status */
234u32 clear_alt_smi_status(void)
235{
236 return print_alt_smi_status(reset_alt_smi_status());
237}
238
239/* Enable GPIO SMI events */
240void enable_alt_smi(u32 mask)
241{
242 u32 alt_en;
243
Angel Ponsf92f2732020-09-25 00:44:52 +0200244 alt_en = inl(get_gpiobase() + GPIO_ALT_GPI_SMI_EN);
Duncan Lauriec88c54c2014-04-30 16:36:13 -0700245 alt_en |= mask;
Angel Ponsf92f2732020-09-25 00:44:52 +0200246 outl(alt_en, get_gpiobase() + GPIO_ALT_GPI_SMI_EN);
Duncan Lauriec88c54c2014-04-30 16:36:13 -0700247}
248
Duncan Lauriec88c54c2014-04-30 16:36:13 -0700249/*
250 * TCO
251 */
252
253/* Clear TCO status and return events that are enabled and active */
254static u32 reset_tco_status(void)
255{
Angel Ponsf92f2732020-09-25 00:44:52 +0200256 u32 tcobase = get_pmbase() + 0x60;
Duncan Lauriec88c54c2014-04-30 16:36:13 -0700257 u32 tco_sts = inl(tcobase + 0x04);
Angel Ponsf92f2732020-09-25 00:44:52 +0200258 u32 tco_en = inl(get_pmbase() + 0x68);
Duncan Lauriec88c54c2014-04-30 16:36:13 -0700259
260 /* Don't clear BOOT_STS before SECOND_TO_STS */
261 outl(tco_sts & ~(1 << 18), tcobase + 0x04);
262
263 /* Clear BOOT_STS */
264 if (tco_sts & (1 << 18))
265 outl(tco_sts & (1 << 18), tcobase + 0x04);
266
267 return tco_sts & tco_en;
268}
269
270/* Print TCO status bits */
271static u32 print_tco_status(u32 tco_sts)
272{
273 const char *tco_sts_bits[] = {
274 [0] = "NMI2SMI",
275 [1] = "SW_TCO",
276 [2] = "TCO_INT",
277 [3] = "TIMEOUT",
278 [7] = "NEWCENTURY",
279 [8] = "BIOSWR",
280 [9] = "DMISCI",
281 [10] = "DMISMI",
282 [12] = "DMISERR",
283 [13] = "SLVSEL",
284 [16] = "INTRD_DET",
285 [17] = "SECOND_TO",
286 [18] = "BOOT",
287 [20] = "SMLINK_SLV"
288 };
289
290 if (!tco_sts)
291 return 0;
292
293 printk(BIOS_DEBUG, "TCO_STS: ");
294 print_status_bits(tco_sts, tco_sts_bits);
295 printk(BIOS_DEBUG, "\n");
296
297 return tco_sts;
298}
299
300/* Print, clear, and return TCO status */
301u32 clear_tco_status(void)
302{
303 return print_tco_status(reset_tco_status());
304}
305
306/* Enable TCO SCI */
307void enable_tco_sci(void)
308{
309 /* Clear pending events */
Angel Ponsf92f2732020-09-25 00:44:52 +0200310 outl(get_pmbase() + GPE0_STS(3), TCOSCI_STS);
Duncan Lauriec88c54c2014-04-30 16:36:13 -0700311
312 /* Enable TCO SCI events */
313 enable_gpe(TCOSCI_EN);
314}
315
Duncan Lauriec88c54c2014-04-30 16:36:13 -0700316/*
317 * GPE0
318 */
319
320/* Clear a GPE0 status and return events that are enabled and active */
Angel Pons2ead3632020-09-24 16:50:05 +0200321static u32 reset_gpe_status(u16 sts_reg, u16 en_reg)
Duncan Lauriec88c54c2014-04-30 16:36:13 -0700322{
Angel Ponsf92f2732020-09-25 00:44:52 +0200323 u32 gpe0_sts = inl(get_pmbase() + sts_reg);
324 u32 gpe0_en = inl(get_pmbase() + en_reg);
Duncan Lauriec88c54c2014-04-30 16:36:13 -0700325
Angel Ponsf92f2732020-09-25 00:44:52 +0200326 outl(gpe0_sts, get_pmbase() + sts_reg);
Duncan Lauriec88c54c2014-04-30 16:36:13 -0700327
328 /* Only report enabled events */
329 return gpe0_sts & gpe0_en;
330}
331
332/* Print GPE0 status bits */
333static u32 print_gpe_status(u32 gpe0_sts, const char *bit_names[])
334{
335 if (!gpe0_sts)
336 return 0;
337
338 printk(BIOS_DEBUG, "GPE0_STS: ");
339 print_status_bits(gpe0_sts, bit_names);
340 printk(BIOS_DEBUG, "\n");
341
342 return gpe0_sts;
343}
344
345/* Print GPE0 GPIO status bits */
346static u32 print_gpe_gpio(u32 gpe0_sts, int start)
347{
348 if (!gpe0_sts)
349 return 0;
350
351 printk(BIOS_DEBUG, "GPE0_STS: ");
352 print_gpio_status(gpe0_sts, start);
353 printk(BIOS_DEBUG, "\n");
354
355 return gpe0_sts;
356}
357
358/* Clear all GPE status and return "standard" GPE event status */
359u32 clear_gpe_status(void)
360{
361 const char *gpe0_sts_3_bits[] = {
362 [1] = "HOTPLUG",
363 [2] = "SWGPE",
364 [6] = "TCO_SCI",
365 [7] = "SMB_WAK",
366 [9] = "PCI_EXP",
367 [10] = "BATLOW",
368 [11] = "PME",
369 [12] = "ME",
370 [13] = "PME_B0",
371 [16] = "GPIO27",
372 [18] = "WADT"
373 };
374
Angel Pons2ead3632020-09-24 16:50:05 +0200375 print_gpe_gpio(reset_gpe_status(GPE0_STS(GPE_31_0), GPE0_EN(GPE_31_0)), 0);
376 print_gpe_gpio(reset_gpe_status(GPE0_STS(GPE_63_32), GPE0_EN(GPE_63_32)), 32);
377 print_gpe_gpio(reset_gpe_status(GPE0_STS(GPE_94_64), GPE0_EN(GPE_94_64)), 64);
378 return print_gpe_status(reset_gpe_status(GPE0_STS(GPE_STD), GPE0_EN(GPE_STD)),
Duncan Lauriec88c54c2014-04-30 16:36:13 -0700379 gpe0_sts_3_bits);
380}
381
382/* Enable all requested GPE */
383void enable_all_gpe(u32 set1, u32 set2, u32 set3, u32 set4)
384{
Angel Ponsf92f2732020-09-25 00:44:52 +0200385 u16 pmbase = get_pmbase();
386
387 outl(set1, pmbase + GPE0_EN(GPE_31_0));
388 outl(set2, pmbase + GPE0_EN(GPE_63_32));
389 outl(set3, pmbase + GPE0_EN(GPE_94_64));
390 outl(set4, pmbase + GPE0_EN(GPE_STD));
Duncan Lauriec88c54c2014-04-30 16:36:13 -0700391}
392
393/* Disable all GPE */
394void disable_all_gpe(void)
395{
396 enable_all_gpe(0, 0, 0, 0);
397}
398
399/* Enable a standard GPE */
400void enable_gpe(u32 mask)
401{
Angel Ponsf92f2732020-09-25 00:44:52 +0200402 u32 gpe0_en = inl(get_pmbase() + GPE0_EN(GPE_STD));
Duncan Lauriec88c54c2014-04-30 16:36:13 -0700403 gpe0_en |= mask;
Angel Ponsf92f2732020-09-25 00:44:52 +0200404 outl(gpe0_en, get_pmbase() + GPE0_EN(GPE_STD));
Duncan Lauriec88c54c2014-04-30 16:36:13 -0700405}
406
407/* Disable a standard GPE */
408void disable_gpe(u32 mask)
409{
Angel Ponsf92f2732020-09-25 00:44:52 +0200410 u32 gpe0_en = inl(get_pmbase() + GPE0_EN(GPE_STD));
Duncan Lauriec88c54c2014-04-30 16:36:13 -0700411 gpe0_en &= ~mask;
Angel Ponsf92f2732020-09-25 00:44:52 +0200412 outl(gpe0_en, get_pmbase() + GPE0_EN(GPE_STD));
Duncan Lauriec88c54c2014-04-30 16:36:13 -0700413}
414
415int acpi_sci_irq(void)
416{
417 int scis = pci_read_config32(PCH_DEV_LPC, ACPI_CNTL) & SCI_IRQ_SEL;
418 int sci_irq = 9;
419
420 /* Determine how SCI is routed. */
421 switch (scis) {
422 case SCIS_IRQ9:
423 case SCIS_IRQ10:
424 case SCIS_IRQ11:
425 sci_irq = scis - SCIS_IRQ9 + 9;
426 break;
427 case SCIS_IRQ20:
428 case SCIS_IRQ21:
429 case SCIS_IRQ22:
430 case SCIS_IRQ23:
431 sci_irq = scis - SCIS_IRQ20 + 20;
432 break;
433 default:
434 printk(BIOS_DEBUG, "Invalid SCI route! Defaulting to IRQ9.\n");
435 sci_irq = 9;
436 break;
437 }
438
439 printk(BIOS_DEBUG, "SCI is IRQ%d\n", sci_irq);
440 return sci_irq;
441}
Aaron Durbinb9d9b792017-09-15 11:51:58 -0600442
Bill XIE516c0a52020-02-24 23:08:35 +0800443int platform_is_resuming(void)
Joel Kitching1d93b882018-09-26 17:58:14 +0800444{
Angel Ponsf92f2732020-09-25 00:44:52 +0200445 if (!(inw(get_pmbase() + PM1_STS) & WAK_STS))
Joel Kitching1d93b882018-09-26 17:58:14 +0800446 return 0;
447
Angel Ponsf92f2732020-09-25 00:44:52 +0200448 return acpi_sleep_from_pm1(inl(get_pmbase() + PM1_CNT)) == ACPI_S3;
Joel Kitching1d93b882018-09-26 17:58:14 +0800449}
Eugene Myersebc84232020-01-21 16:46:16 -0500450
451/* STM Support */
452uint16_t get_pmbase(void)
453{
454 return (uint16_t) ACPI_BASE_ADDRESS;
455}