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