blob: 6ab949ba5755e0339e143c4dbdb3467928efa4e6 [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>
Furquan Shaikh97e0a652016-08-18 21:42:36 -070030#include <rules.h>
Lee Leahy1d14b3e2015-05-12 18:23:27 -070031#include <stdlib.h>
Duncan Laurief0ba2252016-10-25 20:03:56 -070032#include <soc/gpe.h>
Lee Leahy1d14b3e2015-05-12 18:23:27 -070033#include <soc/gpio.h>
Lee Leahyb0005132015-05-12 18:19:47 -070034#include <soc/iomap.h>
35#include <soc/lpc.h>
36#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>
Duncan Laurief0ba2252016-10-25 20:03:56 -070041#include "chip.h"
Lee Leahyb0005132015-05-12 18:19:47 -070042
43/* Print status bits with descriptive names */
Lee Leahyf4c4ab92017-03-16 17:08:03 -070044static void print_status_bits(u32 status, const char * const bit_names[])
Lee Leahyb0005132015-05-12 18:19:47 -070045{
46 int i;
47
48 if (!status)
49 return;
50
Lee Leahy1d14b3e2015-05-12 18:23:27 -070051 for (i = 31; i >= 0; i--) {
Lee Leahyb0005132015-05-12 18:19:47 -070052 if (status & (1 << i)) {
53 if (bit_names[i])
54 printk(BIOS_DEBUG, "%s ", bit_names[i]);
55 else
56 printk(BIOS_DEBUG, "BIT%d ", i);
57 }
58 }
59}
60
61/* Print status bits as GPIO numbers */
62static void print_gpio_status(u32 status, int start)
63{
64 int i;
65
66 if (!status)
67 return;
68
Lee Leahy1d14b3e2015-05-12 18:23:27 -070069 for (i = 31; i >= 0; i--) {
Lee Leahyb0005132015-05-12 18:19:47 -070070 if (status & (1 << i))
71 printk(BIOS_DEBUG, "GPIO%d ", start + i);
72 }
73}
74
75
76/*
77 * PM1_CNT
78 */
79
80/* Enable events in PM1 control register */
81void enable_pm1_control(u32 mask)
82{
83 u32 pm1_cnt = inl(ACPI_BASE_ADDRESS + PM1_CNT);
84 pm1_cnt |= mask;
85 outl(pm1_cnt, ACPI_BASE_ADDRESS + PM1_CNT);
86}
87
88/* Disable events in PM1 control register */
89void disable_pm1_control(u32 mask)
90{
91 u32 pm1_cnt = inl(ACPI_BASE_ADDRESS + PM1_CNT);
92 pm1_cnt &= ~mask;
93 outl(pm1_cnt, ACPI_BASE_ADDRESS + PM1_CNT);
94}
95
96
97/*
98 * PM1
99 */
100
101/* Clear and return PM1 status register */
102static u16 reset_pm1_status(void)
103{
104 u16 pm1_sts = inw(ACPI_BASE_ADDRESS + PM1_STS);
105 outw(pm1_sts, ACPI_BASE_ADDRESS + PM1_STS);
106 return pm1_sts;
107}
108
109/* Print PM1 status bits */
110static u16 print_pm1_status(u16 pm1_sts)
111{
Lee Leahyf4c4ab92017-03-16 17:08:03 -0700112 static const char * const pm1_sts_bits[] = {
Lee Leahyb0005132015-05-12 18:19:47 -0700113 [0] = "TMROF",
114 [4] = "BM",
115 [5] = "GBL",
116 [8] = "PWRBTN",
117 [10] = "RTC",
118 [11] = "PRBTNOR",
119 [14] = "PCIEXPWAK",
120 [15] = "WAK",
121 };
122
123 if (!pm1_sts)
124 return 0;
125
126 printk(BIOS_SPEW, "PM1_STS: ");
127 print_status_bits(pm1_sts, pm1_sts_bits);
128 printk(BIOS_SPEW, "\n");
129
130 return pm1_sts;
131}
132
133/* Print, clear, and return PM1 status */
134u16 clear_pm1_status(void)
135{
136 return print_pm1_status(reset_pm1_status());
137}
138
139/* Set the PM1 register to events */
140void enable_pm1(u16 events)
141{
142 outw(events, ACPI_BASE_ADDRESS + PM1_EN);
143}
144
Furquan Shaikhaeb2d642017-08-17 18:28:41 -0700145/*
146 * Update supplied events in PM1_EN register. This does not disable any already
147 * set events.
148 */
149void update_pm1_enable(u16 events)
150{
151 u16 pm1_en = read_pm1_enable();
152 pm1_en |= events;
153 enable_pm1(pm1_en);
154}
155
156/* Read events set in PM1_EN register. */
157uint16_t read_pm1_enable(void)
158{
159 return inw(ACPI_BASE_ADDRESS + PM1_EN);
160}
Lee Leahyb0005132015-05-12 18:19:47 -0700161
162/*
163 * SMI
164 */
165
166/* Clear and return SMI status register */
167static u32 reset_smi_status(void)
168{
169 u32 smi_sts = inl(ACPI_BASE_ADDRESS + SMI_STS);
170 outl(smi_sts, ACPI_BASE_ADDRESS + SMI_STS);
171 return smi_sts;
172}
173
174/* Print SMI status bits */
175static u32 print_smi_status(u32 smi_sts)
176{
Lee Leahyf4c4ab92017-03-16 17:08:03 -0700177 static const char * const smi_sts_bits[] = {
Lee Leahyb0005132015-05-12 18:19:47 -0700178 [2] = "BIOS",
179 [3] = "LEGACY_USB",
180 [4] = "SLP_SMI",
181 [5] = "APM",
182 [6] = "SWSMI_TMR",
183 [8] = "PM1",
184 [9] = "GPE0",
185 [10] = "GPI",
186 [11] = "MCSMI",
187 [12] = "DEVMON",
188 [13] = "TCO",
189 [14] = "PERIODIC",
190 [15] = "SERIRQ_SMI",
191 [16] = "SMBUS_SMI",
192 [17] = "LEGACY_USB2",
193 [18] = "INTEL_USB2",
194 [20] = "PCI_EXP_SMI",
195 [21] = "MONITOR",
196 [26] = "SPI",
Duncan Laurie8d019022016-10-25 19:58:27 -0700197 [27] = "GPIO_UNLOCK",
198 [28] = "ESPI_SMI",
Lee Leahyb0005132015-05-12 18:19:47 -0700199 };
200
201 if (!smi_sts)
202 return 0;
203
204 printk(BIOS_DEBUG, "SMI_STS: ");
205 print_status_bits(smi_sts, smi_sts_bits);
206 printk(BIOS_DEBUG, "\n");
207
208 return smi_sts;
209}
210
211/* Print, clear, and return SMI status */
212u32 clear_smi_status(void)
213{
214 return print_smi_status(reset_smi_status());
215}
216
217/* Enable SMI event */
218void enable_smi(u32 mask)
219{
220 u32 smi_en = inl(ACPI_BASE_ADDRESS + SMI_EN);
221 smi_en |= mask;
222 outl(smi_en, ACPI_BASE_ADDRESS + SMI_EN);
223}
224
225/* Disable SMI event */
226void disable_smi(u32 mask)
227{
228 u32 smi_en = inl(ACPI_BASE_ADDRESS + SMI_EN);
229 smi_en &= ~mask;
230 outl(smi_en, ACPI_BASE_ADDRESS + SMI_EN);
231}
232
Lee Leahyb0005132015-05-12 18:19:47 -0700233/*
234 * TCO
235 */
236
237/* Clear TCO status and return events that are enabled and active */
238static u32 reset_tco_status(void)
239{
Lee Leahy1d14b3e2015-05-12 18:23:27 -0700240 u16 tco1_sts;
241 u16 tco2_sts;
242 u16 tcobase;
Lee Leahyb0005132015-05-12 18:19:47 -0700243
Barnali Sarkar49eca132016-08-12 00:05:27 +0530244 tcobase = smbus_tco_regs();
Lee Leahyb0005132015-05-12 18:19:47 -0700245
Lee Leahy1d14b3e2015-05-12 18:23:27 -0700246 /* TCO Status 2 register*/
247 tco2_sts = inw(tcobase + TCO2_STS);
248 tco2_sts |= (TCO2_STS_SECOND_TO | TCO2_STS_BOOT);
249 outw(tco2_sts, tcobase + TCO2_STS);
Lee Leahyb0005132015-05-12 18:19:47 -0700250
Lee Leahy1d14b3e2015-05-12 18:23:27 -0700251 /* TCO Status 1 register*/
252 tco1_sts = inw(tcobase + TCO1_STS);
253
254 /* Clear SECOND_TO_STS bit */
255 if (tco2_sts & TCO2_STS_SECOND_TO)
256 outw(tco2_sts & ~TCO2_STS_SECOND_TO, tcobase + TCO2_STS);
257
258 return (tco2_sts << 16) | tco1_sts;
Lee Leahyb0005132015-05-12 18:19:47 -0700259}
260
261/* Print TCO status bits */
262static u32 print_tco_status(u32 tco_sts)
263{
Lee Leahyf4c4ab92017-03-16 17:08:03 -0700264 static const char * const tco_sts_bits[] = {
Lee Leahyb0005132015-05-12 18:19:47 -0700265 [0] = "NMI2SMI",
266 [1] = "SW_TCO",
267 [2] = "TCO_INT",
268 [3] = "TIMEOUT",
269 [7] = "NEWCENTURY",
270 [8] = "BIOSWR",
271 [9] = "DMISCI",
272 [10] = "DMISMI",
273 [12] = "DMISERR",
274 [13] = "SLVSEL",
275 [16] = "INTRD_DET",
276 [17] = "SECOND_TO",
277 [18] = "BOOT",
278 [20] = "SMLINK_SLV"
279 };
280
281 if (!tco_sts)
282 return 0;
283
284 printk(BIOS_DEBUG, "TCO_STS: ");
285 print_status_bits(tco_sts, tco_sts_bits);
286 printk(BIOS_DEBUG, "\n");
287
288 return tco_sts;
289}
290
291/* Print, clear, and return TCO status */
292u32 clear_tco_status(void)
293{
294 return print_tco_status(reset_tco_status());
295}
296
297/* Enable TCO SCI */
298void enable_tco_sci(void)
299{
300 /* Clear pending events */
Lee Leahy1d14b3e2015-05-12 18:23:27 -0700301 outl(TCOSCI_STS, ACPI_BASE_ADDRESS + GPE0_STS(3));
Lee Leahyb0005132015-05-12 18:19:47 -0700302
303 /* Enable TCO SCI events */
304 enable_gpe(TCOSCI_EN);
305}
306
307
308/*
309 * GPE0
310 */
311
312/* Clear a GPE0 status and return events that are enabled and active */
313static u32 reset_gpe(u16 sts_reg, u16 en_reg)
314{
315 u32 gpe0_sts = inl(ACPI_BASE_ADDRESS + sts_reg);
316 u32 gpe0_en = inl(ACPI_BASE_ADDRESS + en_reg);
317
318 outl(gpe0_sts, ACPI_BASE_ADDRESS + sts_reg);
319
320 /* Only report enabled events */
321 return gpe0_sts & gpe0_en;
322}
323
324/* Print GPE0 status bits */
Lee Leahyf4c4ab92017-03-16 17:08:03 -0700325static u32 print_gpe_status(u32 gpe0_sts, const char * const bit_names[])
Lee Leahyb0005132015-05-12 18:19:47 -0700326{
327 if (!gpe0_sts)
328 return 0;
329
330 printk(BIOS_DEBUG, "GPE0_STS: ");
331 print_status_bits(gpe0_sts, bit_names);
332 printk(BIOS_DEBUG, "\n");
333
334 return gpe0_sts;
335}
336
337/* Print GPE0 GPIO status bits */
338static u32 print_gpe_gpio(u32 gpe0_sts, int start)
339{
340 if (!gpe0_sts)
341 return 0;
342
343 printk(BIOS_DEBUG, "GPE0_STS: ");
344 print_gpio_status(gpe0_sts, start);
345 printk(BIOS_DEBUG, "\n");
346
347 return gpe0_sts;
348}
349
350/* Clear all GPE status and return "standard" GPE event status */
351u32 clear_gpe_status(void)
352{
Lee Leahyf4c4ab92017-03-16 17:08:03 -0700353 static const char * const gpe0_sts_3_bits[] = {
Lee Leahyb0005132015-05-12 18:19:47 -0700354 [1] = "HOTPLUG",
355 [2] = "SWGPE",
356 [6] = "TCO_SCI",
357 [7] = "SMB_WAK",
358 [9] = "PCI_EXP",
359 [10] = "BATLOW",
360 [11] = "PME",
361 [12] = "ME",
362 [13] = "PME_B0",
Aaron Durbin7f788492015-07-24 17:10:31 -0500363 [14] = "eSPI",
364 [15] = "GPIO Tier-2",
365 [16] = "LAN_WAKE",
Lee Leahyb0005132015-05-12 18:19:47 -0700366 [18] = "WADT"
367 };
368
369 print_gpe_gpio(reset_gpe(GPE0_STS(GPE_31_0), GPE0_EN(GPE_31_0)), 0);
370 print_gpe_gpio(reset_gpe(GPE0_STS(GPE_63_32), GPE0_EN(GPE_63_32)), 32);
Aaron Durbin7f788492015-07-24 17:10:31 -0500371 print_gpe_gpio(reset_gpe(GPE0_STS(GPE_95_64), GPE0_EN(GPE_95_64)), 64);
Lee Leahyb0005132015-05-12 18:19:47 -0700372 return print_gpe_status(reset_gpe(GPE0_STS(GPE_STD), GPE0_EN(GPE_STD)),
373 gpe0_sts_3_bits);
374}
375
Duncan Laurie64ce1d12016-10-25 20:05:31 -0700376/* Read and clear GPE status (defined in arch/acpi.h) */
377int acpi_get_gpe(int gpe)
378{
379 int bank;
380 uint32_t mask, sts;
Duncan Laurie2f3736e2016-11-03 10:33:43 -0700381 struct stopwatch sw;
382 int rc = 0;
Duncan Laurie64ce1d12016-10-25 20:05:31 -0700383
384 if (gpe < 0 || gpe > GPE0_WADT)
385 return -1;
386
387 bank = gpe / 32;
388 mask = 1 << (gpe % 32);
389
Duncan Laurie2f3736e2016-11-03 10:33:43 -0700390 /* Wait up to 1ms for GPE status to clear */
391 stopwatch_init_msecs_expire(&sw, 1);
392 do {
393 if (stopwatch_expired(&sw))
394 return rc;
395
396 sts = inl(ACPI_BASE_ADDRESS + GPE0_STS(bank));
397 if (sts & mask) {
398 outl(mask, ACPI_BASE_ADDRESS + GPE0_STS(bank));
399 rc = 1;
400 }
401 } while (sts & mask);
402
403 return rc;
Duncan Laurie64ce1d12016-10-25 20:05:31 -0700404}
405
Lee Leahyb0005132015-05-12 18:19:47 -0700406/* Enable all requested GPE */
407void enable_all_gpe(u32 set1, u32 set2, u32 set3, u32 set4)
408{
409 outl(set1, ACPI_BASE_ADDRESS + GPE0_EN(GPE_31_0));
410 outl(set2, ACPI_BASE_ADDRESS + GPE0_EN(GPE_63_32));
Aaron Durbin7f788492015-07-24 17:10:31 -0500411 outl(set3, ACPI_BASE_ADDRESS + GPE0_EN(GPE_95_64));
Lee Leahyb0005132015-05-12 18:19:47 -0700412 outl(set4, ACPI_BASE_ADDRESS + GPE0_EN(GPE_STD));
413}
414
415/* Disable all GPE */
416void disable_all_gpe(void)
417{
418 enable_all_gpe(0, 0, 0, 0);
419}
420
421/* Enable a standard GPE */
422void enable_gpe(u32 mask)
423{
424 u32 gpe0_en = inl(ACPI_BASE_ADDRESS + GPE0_EN(GPE_STD));
425 gpe0_en |= mask;
426 outl(gpe0_en, ACPI_BASE_ADDRESS + GPE0_EN(GPE_STD));
427}
428
429/* Disable a standard GPE */
430void disable_gpe(u32 mask)
431{
432 u32 gpe0_en = inl(ACPI_BASE_ADDRESS + GPE0_EN(GPE_STD));
433 gpe0_en &= ~mask;
434 outl(gpe0_en, ACPI_BASE_ADDRESS + GPE0_EN(GPE_STD));
435}
436
437int acpi_sci_irq(void)
438{
Lee Leahy1d14b3e2015-05-12 18:23:27 -0700439 int scis = pci_read_config32(PCH_DEV_PMC, ACTL) & SCI_IRQ_SEL;
Lee Leahyb0005132015-05-12 18:19:47 -0700440 int sci_irq = 9;
441
442 /* Determine how SCI is routed. */
443 switch (scis) {
444 case SCIS_IRQ9:
445 case SCIS_IRQ10:
446 case SCIS_IRQ11:
447 sci_irq = scis - SCIS_IRQ9 + 9;
448 break;
449 case SCIS_IRQ20:
450 case SCIS_IRQ21:
451 case SCIS_IRQ22:
452 case SCIS_IRQ23:
453 sci_irq = scis - SCIS_IRQ20 + 20;
454 break;
455 default:
456 printk(BIOS_DEBUG, "Invalid SCI route! Defaulting to IRQ9.\n");
457 sci_irq = 9;
458 break;
459 }
460
461 printk(BIOS_DEBUG, "SCI is IRQ%d\n", sci_irq);
462 return sci_irq;
463}
Lee Leahy1d14b3e2015-05-12 18:23:27 -0700464
465uint8_t *pmc_mmio_regs(void)
466{
467 uint32_t reg32;
468
469 reg32 = pci_read_config32(PCH_DEV_PMC, PWRMBASE);
470
471 /* 4KiB alignment. */
472 reg32 &= ~0xfff;
473
474 return (void *)(uintptr_t)reg32;
475}
476
Barnali Sarkar49eca132016-08-12 00:05:27 +0530477uint16_t smbus_tco_regs(void)
Lee Leahy1d14b3e2015-05-12 18:23:27 -0700478{
479 uint16_t reg16;
480
481 reg16 = pci_read_config16(PCH_DEV_SMBUS, TCOBASE);
482
483 reg16 &= ~0x1f;
484
485 return reg16;
486}
Aaron Durbin38613d02016-07-14 00:56:58 -0500487
488void poweroff(void)
489{
490 enable_pm1_control(SLP_EN | (SLP_TYP_S5 << SLP_TYP_SHIFT));
Furquan Shaikh97e0a652016-08-18 21:42:36 -0700491
492 /*
493 * Setting SLP_TYP_S5 in PM1 triggers SLP_SMI, which is handled by SMM
494 * to transition to S5 state. If halt is called in SMM, then it prevents
495 * the SMI handler from being triggered and system never enters S5.
496 */
497 if (!ENV_SMM)
498 halt();
Aaron Durbin38613d02016-07-14 00:56:58 -0500499}
Duncan Laurief0ba2252016-10-25 20:03:56 -0700500
501void pmc_gpe_init(void)
502{
Aaron Durbine4d7abc2017-04-16 22:05:36 -0500503 DEVTREE_CONST struct soc_intel_skylake_config *config;
504 DEVTREE_CONST struct device *dev = dev_find_slot(0, PCH_DEVFN_PMC);
Duncan Laurief0ba2252016-10-25 20:03:56 -0700505 uint8_t *pmc_regs;
506 uint32_t gpio_cfg;
507 uint32_t gpio_cfg_reg;
508 const uint32_t gpio_cfg_mask =
509 (GPE0_DWX_MASK << GPE0_DW0_SHIFT) |
510 (GPE0_DWX_MASK << GPE0_DW1_SHIFT) |
511 (GPE0_DWX_MASK << GPE0_DW2_SHIFT);
512
513 /* Look up the device in devicetree */
514 if (!dev || !dev->chip_info) {
515 printk(BIOS_ERR, "BUG! Could not find SOC devicetree config\n");
516 return;
517 }
518 config = dev->chip_info;
519 pmc_regs = pmc_mmio_regs();
520
521 /* Route the GPIOs to the GPE0 block. Determine that all values
522 * are different, and if they aren't use the reset values. */
523 gpio_cfg = 0;
524 if (config->gpe0_dw0 == config->gpe0_dw1 ||
525 config->gpe0_dw1 == config->gpe0_dw2) {
526 printk(BIOS_INFO, "PMC: Using default GPE route.\n");
527 gpio_cfg = read32(pmc_regs + GPIO_CFG);
528 } else {
529 gpio_cfg |= (uint32_t)config->gpe0_dw0 << GPE0_DW0_SHIFT;
530 gpio_cfg |= (uint32_t)config->gpe0_dw1 << GPE0_DW1_SHIFT;
531 gpio_cfg |= (uint32_t)config->gpe0_dw2 << GPE0_DW2_SHIFT;
532 }
533 gpio_cfg_reg = read32(pmc_regs + GPIO_CFG) & ~gpio_cfg_mask;
534 gpio_cfg_reg |= gpio_cfg & gpio_cfg_mask;
535 write32(pmc_regs + GPIO_CFG, gpio_cfg_reg);
536
537 /* Set the routes in the GPIO communities as well. */
538 gpio_route_gpe(gpio_cfg_reg >> GPE0_DW0_SHIFT);
539
540 /* Set GPE enables based on devictree. */
541 enable_all_gpe(config->gpe0_en_1, config->gpe0_en_2,
542 config->gpe0_en_3, config->gpe0_en_4);
543}
Aaron Durbind1fc8c12017-09-15 12:37:05 -0600544
545int rtc_failure(void)
546{
547 u8 reg8;
548 int rtc_failed;
549 /* PMC Controller Device 0x1F, Func 02 */
550 device_t dev = PCH_DEV_PMC;
551 reg8 = pci_read_config8(dev, GEN_PMCON_B);
552 rtc_failed = reg8 & RTC_BATTERY_DEAD;
553 if (rtc_failed) {
554 reg8 &= ~RTC_BATTERY_DEAD;
555 pci_write_config8(dev, GEN_PMCON_B, reg8);
556 printk(BIOS_DEBUG, "rtc_failed = 0x%x\n", rtc_failed);
557 }
558
559 return !!rtc_failed;
560}