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