blob: dd7f1990b906a277c70f1fed7587ed35e5f53a88 [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
Angel Pons9382f0c2021-02-10 12:43:02 +0100301/* Clear TCO status and return events that are active */
Duncan Laurie55cdf552013-03-08 16:01:44 -0800302static u32 reset_tco_status(void)
303{
304 u32 tcobase = get_pmbase() + 0x60;
305 u32 tco_sts = inl(tcobase + 0x04);
Duncan Laurie55cdf552013-03-08 16:01:44 -0800306
307 /* Don't clear BOOT_STS before SECOND_TO_STS */
308 outl(tco_sts & ~(1 << 18), tcobase + 0x04);
309
310 /* Clear BOOT_STS */
311 if (tco_sts & (1 << 18))
312 outl(tco_sts & (1 << 18), tcobase + 0x04);
313
Angel Pons9382f0c2021-02-10 12:43:02 +0100314 return tco_sts;
Duncan Laurie55cdf552013-03-08 16:01:44 -0800315}
316
317/* Print TCO status bits */
318static u32 print_tco_status(u32 tco_sts)
319{
320 const char *tco_sts_bits[] = {
321 [0] = "NMI2SMI",
322 [1] = "SW_TCO",
323 [2] = "TCO_INT",
324 [3] = "TIMEOUT",
325 [7] = "NEWCENTURY",
326 [8] = "BIOSWR",
327 [9] = "DMISCI",
328 [10] = "DMISMI",
329 [12] = "DMISERR",
330 [13] = "SLVSEL",
331 [16] = "INTRD_DET",
332 [17] = "SECOND_TO",
333 [18] = "BOOT",
334 [20] = "SMLINK_SLV"
335 };
336
337 if (!tco_sts)
338 return 0;
339
340 printk(BIOS_DEBUG, "TCO_STS: ");
341 print_status_bits(tco_sts, tco_sts_bits);
342 printk(BIOS_DEBUG, "\n");
343
344 return tco_sts;
345}
346
347/* Print, clear, and return TCO status */
348u32 clear_tco_status(void)
349{
350 return print_tco_status(reset_tco_status());
351}
352
353/* Enable TCO SCI */
354void enable_tco_sci(void)
355{
356 u16 gpe0_sts = pch_is_lp() ? LP_GPE0_STS_4 : GPE0_STS;
357
358 /* Clear pending events */
Kyösti Mälkkiac435b42022-11-15 14:00:22 +0200359 outl(TCOSCI_STS, get_pmbase() + gpe0_sts);
Duncan Laurie55cdf552013-03-08 16:01:44 -0800360
361 /* Enable TCO SCI events */
362 enable_gpe(TCOSCI_EN);
363}
364
Duncan Laurie55cdf552013-03-08 16:01:44 -0800365/*
366 * GPE0
367 */
368
369/* Clear a GPE0 status and return events that are enabled and active */
370static u32 reset_gpe_status(u16 sts_reg, u16 en_reg)
371{
372 u32 gpe0_sts = inl(get_pmbase() + sts_reg);
373 u32 gpe0_en = inl(get_pmbase() + en_reg);
374
375 outl(gpe0_sts, get_pmbase() + sts_reg);
376
377 /* Only report enabled events */
378 return gpe0_sts & gpe0_en;
379}
380
381/* Print GPE0 status bits */
382static u32 print_gpe_status(u32 gpe0_sts, const char *bit_names[])
383{
384 if (!gpe0_sts)
385 return 0;
386
387 printk(BIOS_DEBUG, "GPE0_STS: ");
388 print_status_bits(gpe0_sts, bit_names);
389 printk(BIOS_DEBUG, "\n");
390
391 return gpe0_sts;
392}
393
394/* Print GPE0 GPIO status bits */
395static u32 print_gpe_gpio(u32 gpe0_sts, int start)
396{
397 if (!gpe0_sts)
398 return 0;
399
400 printk(BIOS_DEBUG, "GPE0_STS: ");
401 print_gpio_status(gpe0_sts, start);
402 printk(BIOS_DEBUG, "\n");
403
404 return gpe0_sts;
405}
406
407/* Print, clear, and return LynxPoint-H GPE0 status */
408static u32 clear_lpt_gpe_status(void)
409{
410 const char *gpe0_sts_bits_low[] = {
411 [1] = "HOTPLUG",
412 [2] = "SWGPE",
413 [6] = "TCO_SCI",
414 [7] = "SMB_WAK",
415 [8] = "RI",
416 [9] = "PCI_EXP",
417 [10] = "BATLOW",
418 [11] = "PME",
419 [13] = "PME_B0",
420 [16] = "GPIO0",
421 [17] = "GPIO1",
422 [18] = "GPIO2",
423 [19] = "GPIO3",
424 [20] = "GPIO4",
425 [21] = "GPIO5",
426 [22] = "GPIO6",
427 [23] = "GPIO7",
428 [24] = "GPIO8",
429 [25] = "GPIO9",
430 [26] = "GPIO10",
431 [27] = "GPIO11",
432 [28] = "GPIO12",
433 [29] = "GPIO13",
434 [30] = "GPIO14",
435 [31] = "GPIO15",
436 };
437 const char *gpe0_sts_bits_high[] = {
438 [3] = "GPIO27",
439 [6] = "WADT",
440 [24] = "GPIO17",
441 [25] = "GPIO19",
442 [26] = "GPIO21",
443 [27] = "GPIO22",
444 [28] = "GPIO43",
445 [29] = "GPIO56",
446 [30] = "GPIO57",
447 [31] = "GPIO60",
448 };
449
450 /* High bits */
451 print_gpe_status(reset_gpe_status(GPE0_STS_2, GPE0_EN_2),
452 gpe0_sts_bits_high);
453
454 /* Standard GPE and GPIO 0-31 */
455 return print_gpe_status(reset_gpe_status(GPE0_STS, GPE0_EN),
456 gpe0_sts_bits_low);
457}
458
459/* Print, clear, and return LynxPoint-LP GPE0 status */
460static u32 clear_lpt_lp_gpe_status(void)
461{
462 const char *gpe0_sts_4_bits[] = {
463 [1] = "HOTPLUG",
464 [2] = "SWGPE",
465 [6] = "TCO_SCI",
466 [7] = "SMB_WAK",
467 [9] = "PCI_EXP",
468 [10] = "BATLOW",
469 [11] = "PME",
470 [12] = "ME",
471 [13] = "PME_B0",
472 [16] = "GPIO27",
473 [18] = "WADT"
474 };
475
476 /* GPIO 0-31 */
477 print_gpe_gpio(reset_gpe_status(LP_GPE0_STS_1, LP_GPE0_EN_1), 0);
478
479 /* GPIO 32-63 */
480 print_gpe_gpio(reset_gpe_status(LP_GPE0_STS_2, LP_GPE0_EN_2), 32);
481
482 /* GPIO 64-94 */
483 print_gpe_gpio(reset_gpe_status(LP_GPE0_STS_3, LP_GPE0_EN_3), 64);
484
485 /* Standard GPE */
486 return print_gpe_status(reset_gpe_status(LP_GPE0_STS_4, LP_GPE0_EN_4),
487 gpe0_sts_4_bits);
488}
489
490/* Clear all GPE status and return "standard" GPE event status */
491u32 clear_gpe_status(void)
492{
493 if (pch_is_lp())
494 return clear_lpt_lp_gpe_status();
495 else
496 return clear_lpt_gpe_status();
497}
498
499/* Enable all requested GPE */
500void enable_all_gpe(u32 set1, u32 set2, u32 set3, u32 set4)
501{
502 u16 pmbase = get_pmbase();
503
504 if (pch_is_lp()) {
505 outl(set1, pmbase + LP_GPE0_EN_1);
506 outl(set2, pmbase + LP_GPE0_EN_2);
507 outl(set3, pmbase + LP_GPE0_EN_3);
508 outl(set4, pmbase + LP_GPE0_EN_4);
509 } else {
510 outl(set1, pmbase + GPE0_EN);
511 outl(set2, pmbase + GPE0_EN_2);
512 }
513}
514
515/* Disable all GPE */
516void disable_all_gpe(void)
517{
518 enable_all_gpe(0, 0, 0, 0);
519}
520
521/* Enable a standard GPE */
522void enable_gpe(u32 mask)
523{
524 u32 gpe0_reg = pch_is_lp() ? LP_GPE0_EN_4 : GPE0_EN;
525 u32 gpe0_en = inl(get_pmbase() + gpe0_reg);
526 gpe0_en |= mask;
527 outl(gpe0_en, get_pmbase() + gpe0_reg);
528}
529
530/* Disable a standard GPE */
531void disable_gpe(u32 mask)
532{
533 u32 gpe0_reg = pch_is_lp() ? LP_GPE0_EN_4 : GPE0_EN;
534 u32 gpe0_en = inl(get_pmbase() + gpe0_reg);
535 gpe0_en &= ~mask;
536 outl(gpe0_en, get_pmbase() + gpe0_reg);
537}