blob: 7af138f17062047d2f28d578daef5e9dda78df87 [file] [log] [blame]
Lee Leahyb0005132015-05-12 18:19:47 -07001/*
2 * This file is part of the coreboot project.
3 *
4 * Copyright (C) 2014 Google Inc.
Lee Leahy1d14b3e2015-05-12 18:23:27 -07005 * Copyright (C) 2015 Intel Corporation.
Lee Leahyb0005132015-05-12 18:19:47 -07006 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; version 2 of 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.
Lee Leahyb0005132015-05-12 18:19:47 -070015 */
16
17/*
18 * Helper functions for dealing with power management registers
19 * and the differences between PCH variants.
20 */
21
Duncan Laurief0ba2252016-10-25 20:03:56 -070022#define __SIMPLE_DEVICE__
23
Lee Leahyb0005132015-05-12 18:19:47 -070024#include <arch/io.h>
25#include <device/device.h>
26#include <device/pci.h>
27#include <device/pci_def.h>
28#include <console/console.h>
Aaron Durbin38613d02016-07-14 00:56:58 -050029#include <halt.h>
Ravi Sarawadi1483d1f2017-09-28 17:06:01 -070030#include <intelblocks/lpc_lib.h>
Furquan Shaikh97e0a652016-08-18 21:42:36 -070031#include <rules.h>
Lee Leahy1d14b3e2015-05-12 18:23:27 -070032#include <stdlib.h>
Duncan Laurief0ba2252016-10-25 20:03:56 -070033#include <soc/gpe.h>
Lee Leahy1d14b3e2015-05-12 18:23:27 -070034#include <soc/gpio.h>
Lee Leahyb0005132015-05-12 18:19:47 -070035#include <soc/iomap.h>
Lee Leahyb0005132015-05-12 18:19:47 -070036#include <soc/pci_devs.h>
37#include <soc/pm.h>
Lee Leahy1d14b3e2015-05-12 18:23:27 -070038#include <soc/pmc.h>
39#include <soc/smbus.h>
Duncan Laurie2f3736e2016-11-03 10:33:43 -070040#include <timer.h>
Aaron Durbin0990fbf2017-09-15 15:23:04 -060041#include <vboot/vbnv.h>
Duncan Laurief0ba2252016-10-25 20:03:56 -070042#include "chip.h"
Lee Leahyb0005132015-05-12 18:19:47 -070043
44/* Print status bits with descriptive names */
Lee Leahyf4c4ab92017-03-16 17:08:03 -070045static void print_status_bits(u32 status, const char * const bit_names[])
Lee Leahyb0005132015-05-12 18:19:47 -070046{
47 int i;
48
49 if (!status)
50 return;
51
Lee Leahy1d14b3e2015-05-12 18:23:27 -070052 for (i = 31; i >= 0; i--) {
Lee Leahyb0005132015-05-12 18:19:47 -070053 if (status & (1 << i)) {
54 if (bit_names[i])
55 printk(BIOS_DEBUG, "%s ", bit_names[i]);
56 else
57 printk(BIOS_DEBUG, "BIT%d ", i);
58 }
59 }
60}
61
62/* Print status bits as GPIO numbers */
63static void print_gpio_status(u32 status, int start)
64{
65 int i;
66
67 if (!status)
68 return;
69
Lee Leahy1d14b3e2015-05-12 18:23:27 -070070 for (i = 31; i >= 0; i--) {
Lee Leahyb0005132015-05-12 18:19:47 -070071 if (status & (1 << i))
72 printk(BIOS_DEBUG, "GPIO%d ", start + i);
73 }
74}
75
76
77/*
78 * PM1_CNT
79 */
80
81/* Enable events in PM1 control register */
82void enable_pm1_control(u32 mask)
83{
84 u32 pm1_cnt = inl(ACPI_BASE_ADDRESS + PM1_CNT);
85 pm1_cnt |= mask;
86 outl(pm1_cnt, ACPI_BASE_ADDRESS + PM1_CNT);
87}
88
89/* Disable events in PM1 control register */
90void disable_pm1_control(u32 mask)
91{
92 u32 pm1_cnt = inl(ACPI_BASE_ADDRESS + PM1_CNT);
93 pm1_cnt &= ~mask;
94 outl(pm1_cnt, ACPI_BASE_ADDRESS + PM1_CNT);
95}
96
97
98/*
99 * PM1
100 */
101
102/* Clear and return PM1 status register */
103static u16 reset_pm1_status(void)
104{
105 u16 pm1_sts = inw(ACPI_BASE_ADDRESS + PM1_STS);
106 outw(pm1_sts, ACPI_BASE_ADDRESS + PM1_STS);
107 return pm1_sts;
108}
109
110/* Print PM1 status bits */
111static u16 print_pm1_status(u16 pm1_sts)
112{
Lee Leahyf4c4ab92017-03-16 17:08:03 -0700113 static const char * const pm1_sts_bits[] = {
Lee Leahyb0005132015-05-12 18:19:47 -0700114 [0] = "TMROF",
115 [4] = "BM",
116 [5] = "GBL",
117 [8] = "PWRBTN",
118 [10] = "RTC",
119 [11] = "PRBTNOR",
120 [14] = "PCIEXPWAK",
121 [15] = "WAK",
122 };
123
124 if (!pm1_sts)
125 return 0;
126
127 printk(BIOS_SPEW, "PM1_STS: ");
128 print_status_bits(pm1_sts, pm1_sts_bits);
129 printk(BIOS_SPEW, "\n");
130
131 return pm1_sts;
132}
133
134/* Print, clear, and return PM1 status */
135u16 clear_pm1_status(void)
136{
137 return print_pm1_status(reset_pm1_status());
138}
139
140/* Set the PM1 register to events */
141void enable_pm1(u16 events)
142{
143 outw(events, ACPI_BASE_ADDRESS + PM1_EN);
144}
145
Furquan Shaikhaeb2d642017-08-17 18:28:41 -0700146/*
147 * Update supplied events in PM1_EN register. This does not disable any already
148 * set events.
149 */
150void update_pm1_enable(u16 events)
151{
152 u16 pm1_en = read_pm1_enable();
153 pm1_en |= events;
154 enable_pm1(pm1_en);
155}
156
157/* Read events set in PM1_EN register. */
158uint16_t read_pm1_enable(void)
159{
160 return inw(ACPI_BASE_ADDRESS + PM1_EN);
161}
Lee Leahyb0005132015-05-12 18:19:47 -0700162
163/*
164 * SMI
165 */
166
167/* Clear and return SMI status register */
168static u32 reset_smi_status(void)
169{
170 u32 smi_sts = inl(ACPI_BASE_ADDRESS + SMI_STS);
171 outl(smi_sts, ACPI_BASE_ADDRESS + SMI_STS);
172 return smi_sts;
173}
174
175/* Print SMI status bits */
176static u32 print_smi_status(u32 smi_sts)
177{
Lee Leahyf4c4ab92017-03-16 17:08:03 -0700178 static const char * const smi_sts_bits[] = {
Lee Leahyb0005132015-05-12 18:19:47 -0700179 [2] = "BIOS",
180 [3] = "LEGACY_USB",
181 [4] = "SLP_SMI",
182 [5] = "APM",
183 [6] = "SWSMI_TMR",
184 [8] = "PM1",
185 [9] = "GPE0",
186 [10] = "GPI",
187 [11] = "MCSMI",
188 [12] = "DEVMON",
189 [13] = "TCO",
190 [14] = "PERIODIC",
191 [15] = "SERIRQ_SMI",
192 [16] = "SMBUS_SMI",
193 [17] = "LEGACY_USB2",
194 [18] = "INTEL_USB2",
195 [20] = "PCI_EXP_SMI",
196 [21] = "MONITOR",
197 [26] = "SPI",
Duncan Laurie8d019022016-10-25 19:58:27 -0700198 [27] = "GPIO_UNLOCK",
199 [28] = "ESPI_SMI",
Lee Leahyb0005132015-05-12 18:19:47 -0700200 };
201
202 if (!smi_sts)
203 return 0;
204
205 printk(BIOS_DEBUG, "SMI_STS: ");
206 print_status_bits(smi_sts, smi_sts_bits);
207 printk(BIOS_DEBUG, "\n");
208
209 return smi_sts;
210}
211
212/* Print, clear, and return SMI status */
213u32 clear_smi_status(void)
214{
215 return print_smi_status(reset_smi_status());
216}
217
218/* Enable SMI event */
219void enable_smi(u32 mask)
220{
221 u32 smi_en = inl(ACPI_BASE_ADDRESS + SMI_EN);
222 smi_en |= mask;
223 outl(smi_en, ACPI_BASE_ADDRESS + SMI_EN);
224}
225
226/* Disable SMI event */
227void disable_smi(u32 mask)
228{
229 u32 smi_en = inl(ACPI_BASE_ADDRESS + SMI_EN);
230 smi_en &= ~mask;
231 outl(smi_en, ACPI_BASE_ADDRESS + SMI_EN);
232}
233
Lee Leahyb0005132015-05-12 18:19:47 -0700234/*
235 * TCO
236 */
237
238/* Clear TCO status and return events that are enabled and active */
239static u32 reset_tco_status(void)
240{
Lee Leahy1d14b3e2015-05-12 18:23:27 -0700241 u16 tco1_sts;
242 u16 tco2_sts;
243 u16 tcobase;
Lee Leahyb0005132015-05-12 18:19:47 -0700244
Barnali Sarkar49eca132016-08-12 00:05:27 +0530245 tcobase = smbus_tco_regs();
Lee Leahyb0005132015-05-12 18:19:47 -0700246
Lee Leahy1d14b3e2015-05-12 18:23:27 -0700247 /* TCO Status 2 register*/
248 tco2_sts = inw(tcobase + TCO2_STS);
249 tco2_sts |= (TCO2_STS_SECOND_TO | TCO2_STS_BOOT);
250 outw(tco2_sts, tcobase + TCO2_STS);
Lee Leahyb0005132015-05-12 18:19:47 -0700251
Lee Leahy1d14b3e2015-05-12 18:23:27 -0700252 /* TCO Status 1 register*/
253 tco1_sts = inw(tcobase + TCO1_STS);
254
255 /* Clear SECOND_TO_STS bit */
256 if (tco2_sts & TCO2_STS_SECOND_TO)
257 outw(tco2_sts & ~TCO2_STS_SECOND_TO, tcobase + TCO2_STS);
258
259 return (tco2_sts << 16) | tco1_sts;
Lee Leahyb0005132015-05-12 18:19:47 -0700260}
261
262/* Print TCO status bits */
263static u32 print_tco_status(u32 tco_sts)
264{
Lee Leahyf4c4ab92017-03-16 17:08:03 -0700265 static const char * const tco_sts_bits[] = {
Lee Leahyb0005132015-05-12 18:19:47 -0700266 [0] = "NMI2SMI",
267 [1] = "SW_TCO",
268 [2] = "TCO_INT",
269 [3] = "TIMEOUT",
270 [7] = "NEWCENTURY",
271 [8] = "BIOSWR",
272 [9] = "DMISCI",
273 [10] = "DMISMI",
274 [12] = "DMISERR",
275 [13] = "SLVSEL",
276 [16] = "INTRD_DET",
277 [17] = "SECOND_TO",
278 [18] = "BOOT",
279 [20] = "SMLINK_SLV"
280 };
281
282 if (!tco_sts)
283 return 0;
284
285 printk(BIOS_DEBUG, "TCO_STS: ");
286 print_status_bits(tco_sts, tco_sts_bits);
287 printk(BIOS_DEBUG, "\n");
288
289 return tco_sts;
290}
291
292/* Print, clear, and return TCO status */
293u32 clear_tco_status(void)
294{
295 return print_tco_status(reset_tco_status());
296}
297
298/* Enable TCO SCI */
299void enable_tco_sci(void)
300{
301 /* Clear pending events */
Lee Leahy1d14b3e2015-05-12 18:23:27 -0700302 outl(TCOSCI_STS, ACPI_BASE_ADDRESS + GPE0_STS(3));
Lee Leahyb0005132015-05-12 18:19:47 -0700303
304 /* Enable TCO SCI events */
305 enable_gpe(TCOSCI_EN);
306}
307
308
309/*
310 * GPE0
311 */
312
313/* Clear a GPE0 status and return events that are enabled and active */
314static u32 reset_gpe(u16 sts_reg, u16 en_reg)
315{
316 u32 gpe0_sts = inl(ACPI_BASE_ADDRESS + sts_reg);
317 u32 gpe0_en = inl(ACPI_BASE_ADDRESS + en_reg);
318
319 outl(gpe0_sts, ACPI_BASE_ADDRESS + sts_reg);
320
321 /* Only report enabled events */
322 return gpe0_sts & gpe0_en;
323}
324
325/* Print GPE0 status bits */
Lee Leahyf4c4ab92017-03-16 17:08:03 -0700326static u32 print_gpe_status(u32 gpe0_sts, const char * const bit_names[])
Lee Leahyb0005132015-05-12 18:19:47 -0700327{
328 if (!gpe0_sts)
329 return 0;
330
331 printk(BIOS_DEBUG, "GPE0_STS: ");
332 print_status_bits(gpe0_sts, bit_names);
333 printk(BIOS_DEBUG, "\n");
334
335 return gpe0_sts;
336}
337
338/* Print GPE0 GPIO status bits */
339static u32 print_gpe_gpio(u32 gpe0_sts, int start)
340{
341 if (!gpe0_sts)
342 return 0;
343
344 printk(BIOS_DEBUG, "GPE0_STS: ");
345 print_gpio_status(gpe0_sts, start);
346 printk(BIOS_DEBUG, "\n");
347
348 return gpe0_sts;
349}
350
351/* Clear all GPE status and return "standard" GPE event status */
352u32 clear_gpe_status(void)
353{
Lee Leahyf4c4ab92017-03-16 17:08:03 -0700354 static const char * const gpe0_sts_3_bits[] = {
Lee Leahyb0005132015-05-12 18:19:47 -0700355 [1] = "HOTPLUG",
356 [2] = "SWGPE",
357 [6] = "TCO_SCI",
358 [7] = "SMB_WAK",
359 [9] = "PCI_EXP",
360 [10] = "BATLOW",
361 [11] = "PME",
362 [12] = "ME",
363 [13] = "PME_B0",
Aaron Durbin7f788492015-07-24 17:10:31 -0500364 [14] = "eSPI",
365 [15] = "GPIO Tier-2",
366 [16] = "LAN_WAKE",
Lee Leahyb0005132015-05-12 18:19:47 -0700367 [18] = "WADT"
368 };
369
370 print_gpe_gpio(reset_gpe(GPE0_STS(GPE_31_0), GPE0_EN(GPE_31_0)), 0);
371 print_gpe_gpio(reset_gpe(GPE0_STS(GPE_63_32), GPE0_EN(GPE_63_32)), 32);
Aaron Durbin7f788492015-07-24 17:10:31 -0500372 print_gpe_gpio(reset_gpe(GPE0_STS(GPE_95_64), GPE0_EN(GPE_95_64)), 64);
Lee Leahyb0005132015-05-12 18:19:47 -0700373 return print_gpe_status(reset_gpe(GPE0_STS(GPE_STD), GPE0_EN(GPE_STD)),
374 gpe0_sts_3_bits);
375}
376
Duncan Laurie64ce1d12016-10-25 20:05:31 -0700377/* Read and clear GPE status (defined in arch/acpi.h) */
378int acpi_get_gpe(int gpe)
379{
380 int bank;
381 uint32_t mask, sts;
Duncan Laurie2f3736e2016-11-03 10:33:43 -0700382 struct stopwatch sw;
383 int rc = 0;
Duncan Laurie64ce1d12016-10-25 20:05:31 -0700384
385 if (gpe < 0 || gpe > GPE0_WADT)
386 return -1;
387
388 bank = gpe / 32;
389 mask = 1 << (gpe % 32);
390
Duncan Laurie2f3736e2016-11-03 10:33:43 -0700391 /* Wait up to 1ms for GPE status to clear */
392 stopwatch_init_msecs_expire(&sw, 1);
393 do {
394 if (stopwatch_expired(&sw))
395 return rc;
396
397 sts = inl(ACPI_BASE_ADDRESS + GPE0_STS(bank));
398 if (sts & mask) {
399 outl(mask, ACPI_BASE_ADDRESS + GPE0_STS(bank));
400 rc = 1;
401 }
402 } while (sts & mask);
403
404 return rc;
Duncan Laurie64ce1d12016-10-25 20:05:31 -0700405}
406
Lee Leahyb0005132015-05-12 18:19:47 -0700407/* Enable all requested GPE */
408void enable_all_gpe(u32 set1, u32 set2, u32 set3, u32 set4)
409{
410 outl(set1, ACPI_BASE_ADDRESS + GPE0_EN(GPE_31_0));
411 outl(set2, ACPI_BASE_ADDRESS + GPE0_EN(GPE_63_32));
Aaron Durbin7f788492015-07-24 17:10:31 -0500412 outl(set3, ACPI_BASE_ADDRESS + GPE0_EN(GPE_95_64));
Lee Leahyb0005132015-05-12 18:19:47 -0700413 outl(set4, ACPI_BASE_ADDRESS + GPE0_EN(GPE_STD));
414}
415
416/* Disable all GPE */
417void disable_all_gpe(void)
418{
419 enable_all_gpe(0, 0, 0, 0);
420}
421
422/* Enable a standard GPE */
423void enable_gpe(u32 mask)
424{
425 u32 gpe0_en = inl(ACPI_BASE_ADDRESS + GPE0_EN(GPE_STD));
426 gpe0_en |= mask;
427 outl(gpe0_en, ACPI_BASE_ADDRESS + GPE0_EN(GPE_STD));
428}
429
430/* Disable a standard GPE */
431void disable_gpe(u32 mask)
432{
433 u32 gpe0_en = inl(ACPI_BASE_ADDRESS + GPE0_EN(GPE_STD));
434 gpe0_en &= ~mask;
435 outl(gpe0_en, ACPI_BASE_ADDRESS + GPE0_EN(GPE_STD));
436}
437
438int acpi_sci_irq(void)
439{
Lee Leahy1d14b3e2015-05-12 18:23:27 -0700440 int scis = pci_read_config32(PCH_DEV_PMC, ACTL) & SCI_IRQ_SEL;
Lee Leahyb0005132015-05-12 18:19:47 -0700441 int sci_irq = 9;
442
443 /* Determine how SCI is routed. */
444 switch (scis) {
445 case SCIS_IRQ9:
446 case SCIS_IRQ10:
447 case SCIS_IRQ11:
448 sci_irq = scis - SCIS_IRQ9 + 9;
449 break;
450 case SCIS_IRQ20:
451 case SCIS_IRQ21:
452 case SCIS_IRQ22:
453 case SCIS_IRQ23:
454 sci_irq = scis - SCIS_IRQ20 + 20;
455 break;
456 default:
457 printk(BIOS_DEBUG, "Invalid SCI route! Defaulting to IRQ9.\n");
458 sci_irq = 9;
459 break;
460 }
461
462 printk(BIOS_DEBUG, "SCI is IRQ%d\n", sci_irq);
463 return sci_irq;
464}
Lee Leahy1d14b3e2015-05-12 18:23:27 -0700465
466uint8_t *pmc_mmio_regs(void)
467{
468 uint32_t reg32;
469
470 reg32 = pci_read_config32(PCH_DEV_PMC, PWRMBASE);
471
472 /* 4KiB alignment. */
473 reg32 &= ~0xfff;
474
475 return (void *)(uintptr_t)reg32;
476}
477
Barnali Sarkar49eca132016-08-12 00:05:27 +0530478uint16_t smbus_tco_regs(void)
Lee Leahy1d14b3e2015-05-12 18:23:27 -0700479{
480 uint16_t reg16;
481
482 reg16 = pci_read_config16(PCH_DEV_SMBUS, TCOBASE);
483
484 reg16 &= ~0x1f;
485
486 return reg16;
487}
Aaron Durbin38613d02016-07-14 00:56:58 -0500488
489void poweroff(void)
490{
491 enable_pm1_control(SLP_EN | (SLP_TYP_S5 << SLP_TYP_SHIFT));
Furquan Shaikh97e0a652016-08-18 21:42:36 -0700492
493 /*
494 * Setting SLP_TYP_S5 in PM1 triggers SLP_SMI, which is handled by SMM
495 * to transition to S5 state. If halt is called in SMM, then it prevents
496 * the SMI handler from being triggered and system never enters S5.
497 */
498 if (!ENV_SMM)
499 halt();
Aaron Durbin38613d02016-07-14 00:56:58 -0500500}
Duncan Laurief0ba2252016-10-25 20:03:56 -0700501
502void pmc_gpe_init(void)
503{
Aaron Durbine4d7abc2017-04-16 22:05:36 -0500504 DEVTREE_CONST struct soc_intel_skylake_config *config;
505 DEVTREE_CONST struct device *dev = dev_find_slot(0, PCH_DEVFN_PMC);
Duncan Laurief0ba2252016-10-25 20:03:56 -0700506 uint8_t *pmc_regs;
507 uint32_t gpio_cfg;
508 uint32_t gpio_cfg_reg;
509 const uint32_t gpio_cfg_mask =
510 (GPE0_DWX_MASK << GPE0_DW0_SHIFT) |
511 (GPE0_DWX_MASK << GPE0_DW1_SHIFT) |
512 (GPE0_DWX_MASK << GPE0_DW2_SHIFT);
513
514 /* Look up the device in devicetree */
515 if (!dev || !dev->chip_info) {
516 printk(BIOS_ERR, "BUG! Could not find SOC devicetree config\n");
517 return;
518 }
519 config = dev->chip_info;
520 pmc_regs = pmc_mmio_regs();
521
522 /* Route the GPIOs to the GPE0 block. Determine that all values
523 * are different, and if they aren't use the reset values. */
524 gpio_cfg = 0;
525 if (config->gpe0_dw0 == config->gpe0_dw1 ||
526 config->gpe0_dw1 == config->gpe0_dw2) {
527 printk(BIOS_INFO, "PMC: Using default GPE route.\n");
528 gpio_cfg = read32(pmc_regs + GPIO_CFG);
529 } else {
530 gpio_cfg |= (uint32_t)config->gpe0_dw0 << GPE0_DW0_SHIFT;
531 gpio_cfg |= (uint32_t)config->gpe0_dw1 << GPE0_DW1_SHIFT;
532 gpio_cfg |= (uint32_t)config->gpe0_dw2 << GPE0_DW2_SHIFT;
533 }
534 gpio_cfg_reg = read32(pmc_regs + GPIO_CFG) & ~gpio_cfg_mask;
535 gpio_cfg_reg |= gpio_cfg & gpio_cfg_mask;
536 write32(pmc_regs + GPIO_CFG, gpio_cfg_reg);
537
538 /* Set the routes in the GPIO communities as well. */
Hannah Williams1760cd32017-04-06 20:54:11 -0700539 gpio_route_gpe((gpio_cfg_reg >> GPE0_DW0_SHIFT) & GPE0_DWX_MASK,
540 (gpio_cfg_reg >> GPE0_DW1_SHIFT) & GPE0_DWX_MASK,
541 (gpio_cfg_reg >> GPE0_DW2_SHIFT) & GPE0_DWX_MASK);
Duncan Laurief0ba2252016-10-25 20:03:56 -0700542
543 /* Set GPE enables based on devictree. */
544 enable_all_gpe(config->gpe0_en_1, config->gpe0_en_2,
545 config->gpe0_en_3, config->gpe0_en_4);
546}
Aaron Durbind1fc8c12017-09-15 12:37:05 -0600547
548int rtc_failure(void)
549{
550 u8 reg8;
551 int rtc_failed;
552 /* PMC Controller Device 0x1F, Func 02 */
553 device_t dev = PCH_DEV_PMC;
554 reg8 = pci_read_config8(dev, GEN_PMCON_B);
555 rtc_failed = reg8 & RTC_BATTERY_DEAD;
556 if (rtc_failed) {
557 reg8 &= ~RTC_BATTERY_DEAD;
558 pci_write_config8(dev, GEN_PMCON_B, reg8);
559 printk(BIOS_DEBUG, "rtc_failed = 0x%x\n", rtc_failed);
560 }
561
562 return !!rtc_failed;
563}
Aaron Durbin0990fbf2017-09-15 15:23:04 -0600564
565int vbnv_cmos_failed(void)
566{
567 return rtc_failure();
568}