blob: 14490a3a6d4ffa682668c1fa9d1f8fa50fdbf832 [file] [log] [blame]
Angel Pons182dbde2020-04-02 23:49:05 +02001/* SPDX-License-Identifier: GPL-2.0-only */
2/* This file is part of the coreboot project. */
Duncan Laurie55cdf552013-03-08 16:01:44 -08003
4/*
5 * Helper functions for dealing with power management registers
6 * and the differences between LynxPoint-H and LynxPoint-LP.
7 */
8
9#include <arch/io.h>
Duncan Laurie55cdf552013-03-08 16:01:44 -080010#include <device/device.h>
11#include <device/pci.h>
Stefan Reinauer5605f1b2013-03-21 18:43:51 -070012#include <device/pci_def.h>
Duncan Laurie55cdf552013-03-08 16:01:44 -080013#include <console/console.h>
Arthur Heymans77d5e742019-01-03 21:11:45 +010014#include <security/vboot/vbnv.h>
15#include <security/vboot/vboot_common.h>
16#include <southbridge/intel/common/rtc.h>
Duncan Laurie55cdf552013-03-08 16:01:44 -080017#include "pch.h"
18
Julius Wernercd49cce2019-03-05 16:53:33 -080019#if CONFIG(INTEL_LYNXPOINT_LP)
Duncan Laurie55cdf552013-03-08 16:01:44 -080020#include "lp_gpio.h"
21#endif
22
23/* These defines are here to handle the LP variant code dynamically. If these
24 * values are defined in lp_gpio.h but when a non-LP board is being built, the
25 * build will fail. */
26#define GPIO_ALT_GPI_SMI_STS 0x50
27#define GPIO_ALT_GPI_SMI_EN 0x54
28
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
37 for (i=31; i>=0; i--) {
Ryan Salsamendi0d9b3602017-06-30 17:15:57 -070038 if (status & (1UL << i)) {
Duncan Laurie55cdf552013-03-08 16:01:44 -080039 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
55 for (i=31; i>=0; i--) {
56 if (status & (1 << i))
57 printk(BIOS_DEBUG, "GPIO%d ", start + i);
58 }
59}
60
61
62/*
63 * PM1_CNT
64 */
65
66/* Enable events in PM1 control register */
67void enable_pm1_control(u32 mask)
68{
69 u32 pm1_cnt = inl(get_pmbase() + PM1_CNT);
70 pm1_cnt |= mask;
71 outl(pm1_cnt, get_pmbase() + PM1_CNT);
72}
73
74/* Disable events in PM1 control register */
75void disable_pm1_control(u32 mask)
76{
77 u32 pm1_cnt = inl(get_pmbase() + PM1_CNT);
78 pm1_cnt &= ~mask;
79 outl(pm1_cnt, get_pmbase() + PM1_CNT);
80}
81
82
83/*
84 * PM1
85 */
86
87/* Clear and return PM1 status register */
88static u16 reset_pm1_status(void)
89{
90 u16 pm1_sts = inw(get_pmbase() + PM1_STS);
91 outw(pm1_sts, get_pmbase() + PM1_STS);
92 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
Aaron Durbind6d6db32013-03-27 21:13:02 -0500125/* Set the PM1 register to events */
126void enable_pm1(u16 events)
Duncan Laurie55cdf552013-03-08 16:01:44 -0800127{
Aaron Durbind6d6db32013-03-27 21:13:02 -0500128 outw(events, get_pmbase() + PM1_EN);
Duncan Laurie55cdf552013-03-08 16:01:44 -0800129}
130
131
132/*
133 * SMI
134 */
135
136/* Clear and return SMI status register */
137static u32 reset_smi_status(void)
138{
139 u32 smi_sts = inl(get_pmbase() + SMI_STS);
140 outl(smi_sts, get_pmbase() + SMI_STS);
141 return smi_sts;
142}
143
144/* Print SMI status bits */
145static u32 print_smi_status(u32 smi_sts)
146{
147 const char *smi_sts_bits[] = {
148 [2] = "BIOS",
149 [3] = "LEGACY_USB",
150 [4] = "SLP_SMI",
151 [5] = "APM",
152 [6] = "SWSMI_TMR",
153 [8] = "PM1",
154 [9] = "GPE0",
155 [10] = "GPI",
156 [11] = "MCSMI",
157 [12] = "DEVMON",
158 [13] = "TCO",
159 [14] = "PERIODIC",
160 [15] = "SERIRQ_SMI",
161 [16] = "SMBUS_SMI",
162 [17] = "LEGACY_USB2",
163 [18] = "INTEL_USB2",
164 [20] = "PCI_EXP_SMI",
165 [21] = "MONITOR",
166 [26] = "SPI",
167 [27] = "GPIO_UNLOCK"
168 };
169
170 if (!smi_sts)
171 return 0;
172
173 printk(BIOS_DEBUG, "SMI_STS: ");
174 print_status_bits(smi_sts, smi_sts_bits);
175 printk(BIOS_DEBUG, "\n");
176
177 return smi_sts;
178}
179
180/* Print, clear, and return SMI status */
181u32 clear_smi_status(void)
182{
183 return print_smi_status(reset_smi_status());
184}
185
186/* Enable SMI event */
187void enable_smi(u32 mask)
188{
189 u32 smi_en = inl(get_pmbase() + SMI_EN);
190 smi_en |= mask;
191 outl(smi_en, get_pmbase() + SMI_EN);
192}
193
194/* Disable SMI event */
195void disable_smi(u32 mask)
196{
197 u32 smi_en = inl(get_pmbase() + SMI_EN);
198 smi_en &= ~mask;
199 outl(smi_en, get_pmbase() + SMI_EN);
200}
201
202
203/*
204 * ALT_GP_SMI
205 */
206
207/* Clear GPIO SMI status and return events that are enabled and active */
208static u32 reset_alt_smi_status(void)
209{
210 u32 alt_sts, alt_en;
211
212 if (pch_is_lp()) {
213 /* LynxPoint-LP moves this to GPIO region as dword */
214 alt_sts = inl(get_gpiobase() + GPIO_ALT_GPI_SMI_STS);
215 outl(alt_sts, get_gpiobase() + GPIO_ALT_GPI_SMI_STS);
216
217 alt_en = inl(get_gpiobase() + GPIO_ALT_GPI_SMI_EN);
218 } else {
219 u16 pmbase = get_pmbase();
220
221 /* LynxPoint-H adds a second enable/status word */
222 alt_sts = inw(pmbase + ALT_GP_SMI_STS2);
223 outw(alt_sts & 0xffff, pmbase + ALT_GP_SMI_STS2);
224
225 alt_sts <<= 16;
226 alt_sts |= inw(pmbase + ALT_GP_SMI_STS);
227 outw(alt_sts & 0xffff, pmbase + ALT_GP_SMI_STS);
228
229 alt_en = inw(pmbase + ALT_GP_SMI_EN2);
230 alt_en <<= 16;
231 alt_en |= inw(pmbase + ALT_GP_SMI_EN);
232 }
233
234 /* Only report enabled events */
235 return alt_sts & alt_en;
236}
237
238/* Print GPIO SMI status bits */
239static u32 print_alt_smi_status(u32 alt_sts)
240{
241 if (!alt_sts)
242 return 0;
243
244 printk(BIOS_DEBUG, "ALT_STS: ");
245
246 if (pch_is_lp()) {
247 /* First 16 events are GPIO 32-47 */
248 print_gpio_status(alt_sts & 0xffff, 32);
249 } else {
250 const char *alt_sts_bits_high[] = {
251 [0] = "GPIO17",
252 [1] = "GPIO19",
253 [2] = "GPIO21",
254 [3] = "GPIO22",
255 [4] = "GPIO43",
256 [5] = "GPIO56",
257 [6] = "GPIO57",
258 [7] = "GPIO60",
259 };
260
261 /* First 16 events are GPIO 0-15 */
262 print_gpio_status(alt_sts & 0xffff, 0);
263 print_status_bits(alt_sts >> 16, alt_sts_bits_high);
264 }
265
266 printk(BIOS_DEBUG, "\n");
267
268 return alt_sts;
269}
270
271/* Print, clear, and return GPIO SMI status */
272u32 clear_alt_smi_status(void)
273{
274 return print_alt_smi_status(reset_alt_smi_status());
275}
276
277/* Enable GPIO SMI events */
278void enable_alt_smi(u32 mask)
279{
280 if (pch_is_lp()) {
281 u32 alt_en;
282
283 alt_en = inl(get_gpiobase() + GPIO_ALT_GPI_SMI_EN);
284 alt_en |= mask;
285 outl(alt_en, get_gpiobase() + GPIO_ALT_GPI_SMI_EN);
286 } else {
287 u16 pmbase = get_pmbase();
288 u16 alt_en;
289
290 /* Lower enable register */
291 alt_en = inw(pmbase + ALT_GP_SMI_EN);
292 alt_en |= mask & 0xffff;
293 outw(alt_en, pmbase + ALT_GP_SMI_EN);
294
295 /* Upper enable register */
296 alt_en = inw(pmbase + ALT_GP_SMI_EN2);
297 alt_en |= (mask >> 16) & 0xffff;
298 outw(alt_en, pmbase + ALT_GP_SMI_EN2);
299 }
300}
301
302
303/*
304 * TCO
305 */
306
307/* Clear TCO status and return events that are enabled and active */
308static u32 reset_tco_status(void)
309{
310 u32 tcobase = get_pmbase() + 0x60;
311 u32 tco_sts = inl(tcobase + 0x04);
312 u32 tco_en = inl(get_pmbase() + 0x68);
313
314 /* Don't clear BOOT_STS before SECOND_TO_STS */
315 outl(tco_sts & ~(1 << 18), tcobase + 0x04);
316
317 /* Clear BOOT_STS */
318 if (tco_sts & (1 << 18))
319 outl(tco_sts & (1 << 18), tcobase + 0x04);
320
321 return tco_sts & tco_en;
322}
323
324/* Print TCO status bits */
325static u32 print_tco_status(u32 tco_sts)
326{
327 const char *tco_sts_bits[] = {
328 [0] = "NMI2SMI",
329 [1] = "SW_TCO",
330 [2] = "TCO_INT",
331 [3] = "TIMEOUT",
332 [7] = "NEWCENTURY",
333 [8] = "BIOSWR",
334 [9] = "DMISCI",
335 [10] = "DMISMI",
336 [12] = "DMISERR",
337 [13] = "SLVSEL",
338 [16] = "INTRD_DET",
339 [17] = "SECOND_TO",
340 [18] = "BOOT",
341 [20] = "SMLINK_SLV"
342 };
343
344 if (!tco_sts)
345 return 0;
346
347 printk(BIOS_DEBUG, "TCO_STS: ");
348 print_status_bits(tco_sts, tco_sts_bits);
349 printk(BIOS_DEBUG, "\n");
350
351 return tco_sts;
352}
353
354/* Print, clear, and return TCO status */
355u32 clear_tco_status(void)
356{
357 return print_tco_status(reset_tco_status());
358}
359
360/* Enable TCO SCI */
361void enable_tco_sci(void)
362{
363 u16 gpe0_sts = pch_is_lp() ? LP_GPE0_STS_4 : GPE0_STS;
364
365 /* Clear pending events */
366 outl(get_pmbase() + gpe0_sts, TCOSCI_STS);
367
368 /* Enable TCO SCI events */
369 enable_gpe(TCOSCI_EN);
370}
371
372
373/*
374 * GPE0
375 */
376
377/* Clear a GPE0 status and return events that are enabled and active */
378static u32 reset_gpe_status(u16 sts_reg, u16 en_reg)
379{
380 u32 gpe0_sts = inl(get_pmbase() + sts_reg);
381 u32 gpe0_en = inl(get_pmbase() + en_reg);
382
383 outl(gpe0_sts, get_pmbase() + sts_reg);
384
385 /* Only report enabled events */
386 return gpe0_sts & gpe0_en;
387}
388
389/* Print GPE0 status bits */
390static u32 print_gpe_status(u32 gpe0_sts, const char *bit_names[])
391{
392 if (!gpe0_sts)
393 return 0;
394
395 printk(BIOS_DEBUG, "GPE0_STS: ");
396 print_status_bits(gpe0_sts, bit_names);
397 printk(BIOS_DEBUG, "\n");
398
399 return gpe0_sts;
400}
401
402/* Print GPE0 GPIO status bits */
403static u32 print_gpe_gpio(u32 gpe0_sts, int start)
404{
405 if (!gpe0_sts)
406 return 0;
407
408 printk(BIOS_DEBUG, "GPE0_STS: ");
409 print_gpio_status(gpe0_sts, start);
410 printk(BIOS_DEBUG, "\n");
411
412 return gpe0_sts;
413}
414
415/* Print, clear, and return LynxPoint-H GPE0 status */
416static u32 clear_lpt_gpe_status(void)
417{
418 const char *gpe0_sts_bits_low[] = {
419 [1] = "HOTPLUG",
420 [2] = "SWGPE",
421 [6] = "TCO_SCI",
422 [7] = "SMB_WAK",
423 [8] = "RI",
424 [9] = "PCI_EXP",
425 [10] = "BATLOW",
426 [11] = "PME",
427 [13] = "PME_B0",
428 [16] = "GPIO0",
429 [17] = "GPIO1",
430 [18] = "GPIO2",
431 [19] = "GPIO3",
432 [20] = "GPIO4",
433 [21] = "GPIO5",
434 [22] = "GPIO6",
435 [23] = "GPIO7",
436 [24] = "GPIO8",
437 [25] = "GPIO9",
438 [26] = "GPIO10",
439 [27] = "GPIO11",
440 [28] = "GPIO12",
441 [29] = "GPIO13",
442 [30] = "GPIO14",
443 [31] = "GPIO15",
444 };
445 const char *gpe0_sts_bits_high[] = {
446 [3] = "GPIO27",
447 [6] = "WADT",
448 [24] = "GPIO17",
449 [25] = "GPIO19",
450 [26] = "GPIO21",
451 [27] = "GPIO22",
452 [28] = "GPIO43",
453 [29] = "GPIO56",
454 [30] = "GPIO57",
455 [31] = "GPIO60",
456 };
457
458 /* High bits */
459 print_gpe_status(reset_gpe_status(GPE0_STS_2, GPE0_EN_2),
460 gpe0_sts_bits_high);
461
462 /* Standard GPE and GPIO 0-31 */
463 return print_gpe_status(reset_gpe_status(GPE0_STS, GPE0_EN),
464 gpe0_sts_bits_low);
465}
466
467/* Print, clear, and return LynxPoint-LP GPE0 status */
468static u32 clear_lpt_lp_gpe_status(void)
469{
470 const char *gpe0_sts_4_bits[] = {
471 [1] = "HOTPLUG",
472 [2] = "SWGPE",
473 [6] = "TCO_SCI",
474 [7] = "SMB_WAK",
475 [9] = "PCI_EXP",
476 [10] = "BATLOW",
477 [11] = "PME",
478 [12] = "ME",
479 [13] = "PME_B0",
480 [16] = "GPIO27",
481 [18] = "WADT"
482 };
483
484 /* GPIO 0-31 */
485 print_gpe_gpio(reset_gpe_status(LP_GPE0_STS_1, LP_GPE0_EN_1), 0);
486
487 /* GPIO 32-63 */
488 print_gpe_gpio(reset_gpe_status(LP_GPE0_STS_2, LP_GPE0_EN_2), 32);
489
490 /* GPIO 64-94 */
491 print_gpe_gpio(reset_gpe_status(LP_GPE0_STS_3, LP_GPE0_EN_3), 64);
492
493 /* Standard GPE */
494 return print_gpe_status(reset_gpe_status(LP_GPE0_STS_4, LP_GPE0_EN_4),
495 gpe0_sts_4_bits);
496}
497
498/* Clear all GPE status and return "standard" GPE event status */
499u32 clear_gpe_status(void)
500{
501 if (pch_is_lp())
502 return clear_lpt_lp_gpe_status();
503 else
504 return clear_lpt_gpe_status();
505}
506
507/* Enable all requested GPE */
508void enable_all_gpe(u32 set1, u32 set2, u32 set3, u32 set4)
509{
510 u16 pmbase = get_pmbase();
511
512 if (pch_is_lp()) {
513 outl(set1, pmbase + LP_GPE0_EN_1);
514 outl(set2, pmbase + LP_GPE0_EN_2);
515 outl(set3, pmbase + LP_GPE0_EN_3);
516 outl(set4, pmbase + LP_GPE0_EN_4);
517 } else {
518 outl(set1, pmbase + GPE0_EN);
519 outl(set2, pmbase + GPE0_EN_2);
520 }
521}
522
523/* Disable all GPE */
524void disable_all_gpe(void)
525{
526 enable_all_gpe(0, 0, 0, 0);
527}
528
529/* Enable a standard GPE */
530void enable_gpe(u32 mask)
531{
532 u32 gpe0_reg = pch_is_lp() ? LP_GPE0_EN_4 : GPE0_EN;
533 u32 gpe0_en = inl(get_pmbase() + gpe0_reg);
534 gpe0_en |= mask;
535 outl(gpe0_en, get_pmbase() + gpe0_reg);
536}
537
538/* Disable a standard GPE */
539void disable_gpe(u32 mask)
540{
541 u32 gpe0_reg = pch_is_lp() ? LP_GPE0_EN_4 : GPE0_EN;
542 u32 gpe0_en = inl(get_pmbase() + gpe0_reg);
543 gpe0_en &= ~mask;
544 outl(gpe0_en, get_pmbase() + gpe0_reg);
545}