coreboot
coreboot is an Open Source project aimed at replacing the proprietary BIOS found in most computers.
pmutil.c
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-only */
2 
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>
9 #include <device/device.h>
10 #include <device/pci.h>
11 #include <device/pci_def.h>
12 #include <console/console.h>
13 #include <security/vboot/vbnv.h>
16 #include "pch.h"
17 
18 #if CONFIG(INTEL_LYNXPOINT_LP)
19 #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 */
29 static void print_status_bits(u32 status, const char *bit_names[])
30 {
31  int i;
32 
33  if (!status)
34  return;
35 
36  for (i = 31; i >= 0; i--) {
37  if (status & (1 << i)) {
38  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 */
47 static void print_gpio_status(u32 status, int start)
48 {
49  int i;
50 
51  if (!status)
52  return;
53 
54  for (i = 31; i >= 0; i--) {
55  if (status & (1 << i))
56  printk(BIOS_DEBUG, "GPIO%d ", start + i);
57  }
58 }
59 
60 /*
61  * PM1_CNT
62  */
63 
64 /* Enable events in PM1 control register */
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 */
74 {
75  u32 pm1_cnt = inl(get_pmbase() + PM1_CNT);
76  pm1_cnt &= ~mask;
77  outl(pm1_cnt, get_pmbase() + PM1_CNT);
78 }
79 
80 /*
81  * PM1
82  */
83 
84 /* Clear and return PM1 status register */
85 static 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 */
93 static 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 */
118 {
120 }
121 
122 /* Set the PM1 register to events */
123 void enable_pm1(u16 events)
124 {
125  outw(events, get_pmbase() + PM1_EN);
126 }
127 
128 /*
129  * SMI
130  */
131 
132 /* Clear and return SMI status register */
133 static 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 */
141 static 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 */
178 {
180 }
181 
182 /* Enable SMI event */
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 */
192 {
193  u32 smi_en = inl(get_pmbase() + SMI_EN);
194  smi_en &= ~mask;
195  outl(smi_en, get_pmbase() + SMI_EN);
196 }
197 
198 /*
199  * ALT_GP_SMI
200  */
201 
202 /* Clear GPIO SMI status and return events that are enabled and active */
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 */
234 static 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 */
268 {
270 }
271 
272 /* Enable GPIO SMI events */
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;
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 
297 /*
298  * TCO
299  */
300 
301 /* Clear TCO status and return events that are active */
302 static u32 reset_tco_status(void)
303 {
304  u32 tcobase = get_pmbase() + 0x60;
305  u32 tco_sts = inl(tcobase + 0x04);
306 
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 
314  return tco_sts;
315 }
316 
317 /* Print TCO status bits */
318 static 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 */
349 {
351 }
352 
353 /* Enable TCO SCI */
354 void enable_tco_sci(void)
355 {
356  u16 gpe0_sts = pch_is_lp() ? LP_GPE0_STS_4 : GPE0_STS;
357 
358  /* Clear pending events */
359  outl(get_pmbase() + gpe0_sts, TCOSCI_STS);
360 
361  /* Enable TCO SCI events */
363 }
364 
365 /*
366  * GPE0
367  */
368 
369 /* Clear a GPE0 status and return events that are enabled and active */
370 static 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 */
382 static 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 */
395 static 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 */
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 */
452  gpe0_sts_bits_high);
453 
454  /* Standard GPE and GPIO 0-31 */
456  gpe0_sts_bits_low);
457 }
458 
459 /* Print, clear, and return LynxPoint-LP GPE0 status */
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 */
478 
479  /* GPIO 32-63 */
481 
482  /* GPIO 64-94 */
484 
485  /* Standard GPE */
487  gpe0_sts_4_bits);
488 }
489 
490 /* Clear all GPE status and return "standard" GPE event status */
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 */
500 void 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 */
516 void disable_all_gpe(void)
517 {
518  enable_all_gpe(0, 0, 0, 0);
519 }
520 
521 /* Enable a standard GPE */
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 */
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 }
#define PM1_EN
Definition: pm.h:21
#define SMI_STS
Definition: pm.h:50
#define GPE0_STS(x)
Definition: pm.h:81
#define PM1_STS
Definition: pm.h:12
#define GPE0_EN(x)
Definition: pm.h:99
#define TCOSCI_STS
Definition: pm.h:96
#define PM1_CNT
Definition: pm.h:27
#define SMI_EN
Definition: pm.h:32
#define TCOSCI_EN
Definition: pm.h:109
#define printk(level,...)
Definition: stdlib.h:16
u16 inw(u16 port)
u32 inl(u16 port)
void outl(u32 val, u16 port)
void outw(u16 val, u16 port)
#define BIOS_DEBUG
BIOS_DEBUG - Verbose output.
Definition: loglevel.h:128
#define BIOS_SPEW
BIOS_SPEW - Excessively verbose output.
Definition: loglevel.h:142
uint16_t get_pmbase(void)
Definition: pmutil.c:254
void enable_pm1(uint16_t events)
Definition: pmutil.c:157
uint16_t clear_pm1_status(void)
Definition: pmutil.c:152
void enable_pm1_control(uint32_t mask)
Definition: pmutil.c:105
void disable_smi(uint32_t mask)
Definition: pmutil.c:97
void enable_smi(uint32_t mask)
Definition: pmutil.c:89
void enable_gpe(uint32_t mask)
Definition: pmutil.c:194
uint32_t clear_gpe_status(void)
Definition: pmutil.c:265
void disable_pm1_control(uint32_t mask)
Definition: pmutil.c:113
void disable_all_gpe(void)
Definition: pmutil.c:210
uint32_t clear_tco_status(void)
Definition: pmutil.c:189
uint32_t clear_smi_status(void)
Definition: pmutil.c:84
void disable_gpe(uint32_t mask)
Definition: pmutil.c:202
static uint16_t get_gpiobase(void)
Definition: pmutil.c:26
void enable_tco_sci(void)
Definition: pmutil.c:309
u32 clear_alt_smi_status(void)
Definition: pmutil.c:236
void enable_alt_smi(u32 mask)
Definition: pmutil.c:242
void enable_all_gpe(u32 set1, u32 set2, u32 set3, u32 set4)
Definition: pmutil.c:385
static const int mask[4]
Definition: gpio.c:308
#define ALT_GP_SMI_STS
Definition: pch.h:462
#define ALT_GP_SMI_EN
Definition: pch.h:461
u32 reset_smi_status(void)
read and clear SMI_STS
Definition: pmutil.c:61
u16 reset_pm1_status(void)
read and clear PM1_STS
Definition: pmutil.c:31
u32 reset_tco_status(void)
read and clear TCOx_STS
Definition: pmutil.c:144
static u16 pmbase
Definition: smi.c:27
static int pch_is_lp(void)
Definition: pch.h:104
#define ALT_GP_SMI_EN2
Definition: pch.h:627
#define LP_GPE0_EN_2
Definition: pch.h:636
#define LP_GPE0_EN_4
Definition: pch.h:638
#define GPE0_EN_2
Definition: pch.h:601
#define LP_GPE0_STS_1
Definition: pch.h:631
#define LP_GPE0_STS_4
Definition: pch.h:634
#define LP_GPE0_STS_2
Definition: pch.h:632
#define LP_GPE0_EN_3
Definition: pch.h:637
#define LP_GPE0_STS_3
Definition: pch.h:633
#define LP_GPE0_EN_1
Definition: pch.h:635
#define GPE0_STS_2
Definition: pch.h:596
#define ALT_GP_SMI_STS2
Definition: pch.h:628
#define GPIO_ALT_GPI_SMI_STS
Definition: pmutil.c:25
static u32 clear_lpt_gpe_status(void)
Definition: pmutil.c:408
static u32 print_tco_status(u32 tco_sts)
Definition: pmutil.c:318
static u32 print_smi_status(u32 smi_sts)
Definition: pmutil.c:141
static u16 print_pm1_status(u16 pm1_sts)
Definition: pmutil.c:93
#define GPIO_ALT_GPI_SMI_EN
Definition: pmutil.c:26
static void print_status_bits(u32 status, const char *bit_names[])
Definition: pmutil.c:29
static u32 print_gpe_status(u32 gpe0_sts, const char *bit_names[])
Definition: pmutil.c:382
static u32 clear_lpt_lp_gpe_status(void)
Definition: pmutil.c:460
static u32 print_alt_smi_status(u32 alt_sts)
Definition: pmutil.c:234
static void print_gpio_status(u32 status, int start)
Definition: pmutil.c:47
static u32 print_gpe_gpio(u32 gpe0_sts, int start)
Definition: pmutil.c:395
static u32 reset_gpe_status(u16 sts_reg, u16 en_reg)
Definition: pmutil.c:370
static u32 reset_alt_smi_status(void)
Definition: pmutil.c:203
uint32_t u32
Definition: stdint.h:51
uint16_t u16
Definition: stdint.h:48