blob: c96ed18b8ac9d784f11cc425d56ee2139f1ea3fb [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>
Duncan Lauriec88c54c2014-04-30 16:36:13 -070022
23/* Print status bits with descriptive names */
24static void print_status_bits(u32 status, const char *bit_names[])
25{
26 int i;
27
28 if (!status)
29 return;
30
Lee Leahy26b7cd02017-03-16 18:47:55 -070031 for (i = 31; i >= 0; i--) {
Duncan Lauriec88c54c2014-04-30 16:36:13 -070032 if (status & (1 << i)) {
33 if (bit_names[i])
34 printk(BIOS_DEBUG, "%s ", bit_names[i]);
35 else
36 printk(BIOS_DEBUG, "BIT%d ", i);
37 }
38 }
39}
40
41/* Print status bits as GPIO numbers */
42static void print_gpio_status(u32 status, int start)
43{
44 int i;
45
46 if (!status)
47 return;
48
Lee Leahy26b7cd02017-03-16 18:47:55 -070049 for (i = 31; i >= 0; i--) {
Duncan Lauriec88c54c2014-04-30 16:36:13 -070050 if (status & (1 << i))
51 printk(BIOS_DEBUG, "GPIO%d ", start + i);
52 }
53}
54
Duncan Lauriec88c54c2014-04-30 16:36:13 -070055/*
56 * PM1_CNT
57 */
58
59/* Enable events in PM1 control register */
60void enable_pm1_control(u32 mask)
61{
62 u32 pm1_cnt = inl(ACPI_BASE_ADDRESS + PM1_CNT);
63 pm1_cnt |= mask;
64 outl(pm1_cnt, ACPI_BASE_ADDRESS + PM1_CNT);
65}
66
67/* Disable events in PM1 control register */
68void disable_pm1_control(u32 mask)
69{
70 u32 pm1_cnt = inl(ACPI_BASE_ADDRESS + PM1_CNT);
71 pm1_cnt &= ~mask;
72 outl(pm1_cnt, ACPI_BASE_ADDRESS + PM1_CNT);
73}
74
Duncan Lauriec88c54c2014-04-30 16:36:13 -070075/*
76 * PM1
77 */
78
79/* Clear and return PM1 status register */
80static u16 reset_pm1_status(void)
81{
82 u16 pm1_sts = inw(ACPI_BASE_ADDRESS + PM1_STS);
83 outw(pm1_sts, ACPI_BASE_ADDRESS + PM1_STS);
84 return pm1_sts;
85}
86
87/* Print PM1 status bits */
88static u16 print_pm1_status(u16 pm1_sts)
89{
90 const char *pm1_sts_bits[] = {
91 [0] = "TMROF",
92 [4] = "BM",
93 [5] = "GBL",
94 [8] = "PWRBTN",
95 [10] = "RTC",
96 [11] = "PRBTNOR",
97 [14] = "PCIEXPWAK",
98 [15] = "WAK",
99 };
100
101 if (!pm1_sts)
102 return 0;
103
104 printk(BIOS_SPEW, "PM1_STS: ");
105 print_status_bits(pm1_sts, pm1_sts_bits);
106 printk(BIOS_SPEW, "\n");
107
108 return pm1_sts;
109}
110
111/* Print, clear, and return PM1 status */
112u16 clear_pm1_status(void)
113{
114 return print_pm1_status(reset_pm1_status());
115}
116
117/* Set the PM1 register to events */
118void enable_pm1(u16 events)
119{
120 outw(events, ACPI_BASE_ADDRESS + PM1_EN);
121}
122
Duncan Lauriec88c54c2014-04-30 16:36:13 -0700123/*
124 * SMI
125 */
126
127/* Clear and return SMI status register */
128static u32 reset_smi_status(void)
129{
130 u32 smi_sts = inl(ACPI_BASE_ADDRESS + SMI_STS);
131 outl(smi_sts, ACPI_BASE_ADDRESS + SMI_STS);
132 return smi_sts;
133}
134
135/* Print SMI status bits */
136static u32 print_smi_status(u32 smi_sts)
137{
138 const char *smi_sts_bits[] = {
139 [2] = "BIOS",
140 [3] = "LEGACY_USB",
141 [4] = "SLP_SMI",
142 [5] = "APM",
143 [6] = "SWSMI_TMR",
144 [8] = "PM1",
145 [9] = "GPE0",
146 [10] = "GPI",
147 [11] = "MCSMI",
148 [12] = "DEVMON",
149 [13] = "TCO",
150 [14] = "PERIODIC",
151 [15] = "SERIRQ_SMI",
152 [16] = "SMBUS_SMI",
153 [17] = "LEGACY_USB2",
154 [18] = "INTEL_USB2",
155 [20] = "PCI_EXP_SMI",
156 [21] = "MONITOR",
157 [26] = "SPI",
158 [27] = "GPIO_UNLOCK"
159 };
160
161 if (!smi_sts)
162 return 0;
163
164 printk(BIOS_DEBUG, "SMI_STS: ");
165 print_status_bits(smi_sts, smi_sts_bits);
166 printk(BIOS_DEBUG, "\n");
167
168 return smi_sts;
169}
170
171/* Print, clear, and return SMI status */
172u32 clear_smi_status(void)
173{
174 return print_smi_status(reset_smi_status());
175}
176
177/* Enable SMI event */
178void enable_smi(u32 mask)
179{
180 u32 smi_en = inl(ACPI_BASE_ADDRESS + SMI_EN);
181 smi_en |= mask;
182 outl(smi_en, ACPI_BASE_ADDRESS + SMI_EN);
183}
184
185/* Disable SMI event */
186void disable_smi(u32 mask)
187{
188 u32 smi_en = inl(ACPI_BASE_ADDRESS + SMI_EN);
189 smi_en &= ~mask;
190 outl(smi_en, ACPI_BASE_ADDRESS + SMI_EN);
191}
192
Duncan Lauriec88c54c2014-04-30 16:36:13 -0700193/*
194 * ALT_GP_SMI
195 */
196
197/* Clear GPIO SMI status and return events that are enabled and active */
198static u32 reset_alt_smi_status(void)
199{
200 u32 alt_sts, alt_en;
201
202 /* Low Power variant moves this to GPIO region as dword */
203 alt_sts = inl(GPIO_BASE_ADDRESS + GPIO_ALT_GPI_SMI_STS);
204 outl(alt_sts, GPIO_BASE_ADDRESS + GPIO_ALT_GPI_SMI_STS);
205 alt_en = inl(GPIO_BASE_ADDRESS + GPIO_ALT_GPI_SMI_EN);
206
207 /* Only report enabled events */
208 return alt_sts & alt_en;
209}
210
211/* Print GPIO SMI status bits */
212static u32 print_alt_smi_status(u32 alt_sts)
213{
214 if (!alt_sts)
215 return 0;
216
217 printk(BIOS_DEBUG, "ALT_STS: ");
218
219 /* First 16 events are GPIO 32-47 */
220 print_gpio_status(alt_sts & 0xffff, 32);
221
222 printk(BIOS_DEBUG, "\n");
223
224 return alt_sts;
225}
226
227/* Print, clear, and return GPIO SMI status */
228u32 clear_alt_smi_status(void)
229{
230 return print_alt_smi_status(reset_alt_smi_status());
231}
232
233/* Enable GPIO SMI events */
234void enable_alt_smi(u32 mask)
235{
236 u32 alt_en;
237
238 alt_en = inl(GPIO_BASE_ADDRESS + GPIO_ALT_GPI_SMI_EN);
239 alt_en |= mask;
240 outl(alt_en, GPIO_BASE_ADDRESS + GPIO_ALT_GPI_SMI_EN);
241}
242
Duncan Lauriec88c54c2014-04-30 16:36:13 -0700243/*
244 * TCO
245 */
246
247/* Clear TCO status and return events that are enabled and active */
248static u32 reset_tco_status(void)
249{
250 u32 tcobase = ACPI_BASE_ADDRESS + 0x60;
251 u32 tco_sts = inl(tcobase + 0x04);
252 u32 tco_en = inl(ACPI_BASE_ADDRESS + 0x68);
253
254 /* Don't clear BOOT_STS before SECOND_TO_STS */
255 outl(tco_sts & ~(1 << 18), tcobase + 0x04);
256
257 /* Clear BOOT_STS */
258 if (tco_sts & (1 << 18))
259 outl(tco_sts & (1 << 18), tcobase + 0x04);
260
261 return tco_sts & tco_en;
262}
263
264/* Print TCO status bits */
265static u32 print_tco_status(u32 tco_sts)
266{
267 const char *tco_sts_bits[] = {
268 [0] = "NMI2SMI",
269 [1] = "SW_TCO",
270 [2] = "TCO_INT",
271 [3] = "TIMEOUT",
272 [7] = "NEWCENTURY",
273 [8] = "BIOSWR",
274 [9] = "DMISCI",
275 [10] = "DMISMI",
276 [12] = "DMISERR",
277 [13] = "SLVSEL",
278 [16] = "INTRD_DET",
279 [17] = "SECOND_TO",
280 [18] = "BOOT",
281 [20] = "SMLINK_SLV"
282 };
283
284 if (!tco_sts)
285 return 0;
286
287 printk(BIOS_DEBUG, "TCO_STS: ");
288 print_status_bits(tco_sts, tco_sts_bits);
289 printk(BIOS_DEBUG, "\n");
290
291 return tco_sts;
292}
293
294/* Print, clear, and return TCO status */
295u32 clear_tco_status(void)
296{
297 return print_tco_status(reset_tco_status());
298}
299
300/* Enable TCO SCI */
301void enable_tco_sci(void)
302{
303 /* Clear pending events */
304 outl(ACPI_BASE_ADDRESS + GPE0_STS(3), TCOSCI_STS);
305
306 /* Enable TCO SCI events */
307 enable_gpe(TCOSCI_EN);
308}
309
Duncan Lauriec88c54c2014-04-30 16:36:13 -0700310/*
311 * GPE0
312 */
313
314/* Clear a GPE0 status and return events that are enabled and active */
Angel Pons2ead3632020-09-24 16:50:05 +0200315static u32 reset_gpe_status(u16 sts_reg, u16 en_reg)
Duncan Lauriec88c54c2014-04-30 16:36:13 -0700316{
317 u32 gpe0_sts = inl(ACPI_BASE_ADDRESS + sts_reg);
318 u32 gpe0_en = inl(ACPI_BASE_ADDRESS + en_reg);
319
320 outl(gpe0_sts, ACPI_BASE_ADDRESS + sts_reg);
321
322 /* Only report enabled events */
323 return gpe0_sts & gpe0_en;
324}
325
326/* Print GPE0 status bits */
327static u32 print_gpe_status(u32 gpe0_sts, const char *bit_names[])
328{
329 if (!gpe0_sts)
330 return 0;
331
332 printk(BIOS_DEBUG, "GPE0_STS: ");
333 print_status_bits(gpe0_sts, bit_names);
334 printk(BIOS_DEBUG, "\n");
335
336 return gpe0_sts;
337}
338
339/* Print GPE0 GPIO status bits */
340static u32 print_gpe_gpio(u32 gpe0_sts, int start)
341{
342 if (!gpe0_sts)
343 return 0;
344
345 printk(BIOS_DEBUG, "GPE0_STS: ");
346 print_gpio_status(gpe0_sts, start);
347 printk(BIOS_DEBUG, "\n");
348
349 return gpe0_sts;
350}
351
352/* Clear all GPE status and return "standard" GPE event status */
353u32 clear_gpe_status(void)
354{
355 const char *gpe0_sts_3_bits[] = {
356 [1] = "HOTPLUG",
357 [2] = "SWGPE",
358 [6] = "TCO_SCI",
359 [7] = "SMB_WAK",
360 [9] = "PCI_EXP",
361 [10] = "BATLOW",
362 [11] = "PME",
363 [12] = "ME",
364 [13] = "PME_B0",
365 [16] = "GPIO27",
366 [18] = "WADT"
367 };
368
Angel Pons2ead3632020-09-24 16:50:05 +0200369 print_gpe_gpio(reset_gpe_status(GPE0_STS(GPE_31_0), GPE0_EN(GPE_31_0)), 0);
370 print_gpe_gpio(reset_gpe_status(GPE0_STS(GPE_63_32), GPE0_EN(GPE_63_32)), 32);
371 print_gpe_gpio(reset_gpe_status(GPE0_STS(GPE_94_64), GPE0_EN(GPE_94_64)), 64);
372 return print_gpe_status(reset_gpe_status(GPE0_STS(GPE_STD), GPE0_EN(GPE_STD)),
Duncan Lauriec88c54c2014-04-30 16:36:13 -0700373 gpe0_sts_3_bits);
374}
375
376/* Enable all requested GPE */
377void enable_all_gpe(u32 set1, u32 set2, u32 set3, u32 set4)
378{
379 outl(set1, ACPI_BASE_ADDRESS + GPE0_EN(GPE_31_0));
380 outl(set2, ACPI_BASE_ADDRESS + GPE0_EN(GPE_63_32));
381 outl(set3, ACPI_BASE_ADDRESS + GPE0_EN(GPE_94_64));
382 outl(set4, ACPI_BASE_ADDRESS + GPE0_EN(GPE_STD));
383}
384
385/* Disable all GPE */
386void disable_all_gpe(void)
387{
388 enable_all_gpe(0, 0, 0, 0);
389}
390
391/* Enable a standard GPE */
392void enable_gpe(u32 mask)
393{
394 u32 gpe0_en = inl(ACPI_BASE_ADDRESS + GPE0_EN(GPE_STD));
395 gpe0_en |= mask;
396 outl(gpe0_en, ACPI_BASE_ADDRESS + GPE0_EN(GPE_STD));
397}
398
399/* Disable a standard GPE */
400void disable_gpe(u32 mask)
401{
402 u32 gpe0_en = inl(ACPI_BASE_ADDRESS + GPE0_EN(GPE_STD));
403 gpe0_en &= ~mask;
404 outl(gpe0_en, ACPI_BASE_ADDRESS + GPE0_EN(GPE_STD));
405}
406
407int acpi_sci_irq(void)
408{
409 int scis = pci_read_config32(PCH_DEV_LPC, ACPI_CNTL) & SCI_IRQ_SEL;
410 int sci_irq = 9;
411
412 /* Determine how SCI is routed. */
413 switch (scis) {
414 case SCIS_IRQ9:
415 case SCIS_IRQ10:
416 case SCIS_IRQ11:
417 sci_irq = scis - SCIS_IRQ9 + 9;
418 break;
419 case SCIS_IRQ20:
420 case SCIS_IRQ21:
421 case SCIS_IRQ22:
422 case SCIS_IRQ23:
423 sci_irq = scis - SCIS_IRQ20 + 20;
424 break;
425 default:
426 printk(BIOS_DEBUG, "Invalid SCI route! Defaulting to IRQ9.\n");
427 sci_irq = 9;
428 break;
429 }
430
431 printk(BIOS_DEBUG, "SCI is IRQ%d\n", sci_irq);
432 return sci_irq;
433}
Aaron Durbinb9d9b792017-09-15 11:51:58 -0600434
Bill XIE516c0a52020-02-24 23:08:35 +0800435int platform_is_resuming(void)
Joel Kitching1d93b882018-09-26 17:58:14 +0800436{
437 if (!(inw(ACPI_BASE_ADDRESS + PM1_STS) & WAK_STS))
438 return 0;
439
440 return acpi_sleep_from_pm1(inl(ACPI_BASE_ADDRESS + PM1_CNT)) == ACPI_S3;
441}
Eugene Myersebc84232020-01-21 16:46:16 -0500442
443/* STM Support */
444uint16_t get_pmbase(void)
445{
446 return (uint16_t) ACPI_BASE_ADDRESS;
447}