blob: 9b38531129bdd3cd19e4dae2d110ca511b5a3b36 [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
145
146/*
147 * SMI
148 */
149
150/* Clear and return SMI status register */
151static u32 reset_smi_status(void)
152{
153 u32 smi_sts = inl(ACPI_BASE_ADDRESS + SMI_STS);
154 outl(smi_sts, ACPI_BASE_ADDRESS + SMI_STS);
155 return smi_sts;
156}
157
158/* Print SMI status bits */
159static u32 print_smi_status(u32 smi_sts)
160{
Lee Leahyf4c4ab92017-03-16 17:08:03 -0700161 static const char * const smi_sts_bits[] = {
Lee Leahyb0005132015-05-12 18:19:47 -0700162 [2] = "BIOS",
163 [3] = "LEGACY_USB",
164 [4] = "SLP_SMI",
165 [5] = "APM",
166 [6] = "SWSMI_TMR",
167 [8] = "PM1",
168 [9] = "GPE0",
169 [10] = "GPI",
170 [11] = "MCSMI",
171 [12] = "DEVMON",
172 [13] = "TCO",
173 [14] = "PERIODIC",
174 [15] = "SERIRQ_SMI",
175 [16] = "SMBUS_SMI",
176 [17] = "LEGACY_USB2",
177 [18] = "INTEL_USB2",
178 [20] = "PCI_EXP_SMI",
179 [21] = "MONITOR",
180 [26] = "SPI",
Duncan Laurie8d019022016-10-25 19:58:27 -0700181 [27] = "GPIO_UNLOCK",
182 [28] = "ESPI_SMI",
Lee Leahyb0005132015-05-12 18:19:47 -0700183 };
184
185 if (!smi_sts)
186 return 0;
187
188 printk(BIOS_DEBUG, "SMI_STS: ");
189 print_status_bits(smi_sts, smi_sts_bits);
190 printk(BIOS_DEBUG, "\n");
191
192 return smi_sts;
193}
194
195/* Print, clear, and return SMI status */
196u32 clear_smi_status(void)
197{
198 return print_smi_status(reset_smi_status());
199}
200
201/* Enable SMI event */
202void enable_smi(u32 mask)
203{
204 u32 smi_en = inl(ACPI_BASE_ADDRESS + SMI_EN);
205 smi_en |= mask;
206 outl(smi_en, ACPI_BASE_ADDRESS + SMI_EN);
207}
208
209/* Disable SMI event */
210void disable_smi(u32 mask)
211{
212 u32 smi_en = inl(ACPI_BASE_ADDRESS + SMI_EN);
213 smi_en &= ~mask;
214 outl(smi_en, ACPI_BASE_ADDRESS + SMI_EN);
215}
216
Lee Leahyb0005132015-05-12 18:19:47 -0700217/*
218 * TCO
219 */
220
221/* Clear TCO status and return events that are enabled and active */
222static u32 reset_tco_status(void)
223{
Lee Leahy1d14b3e2015-05-12 18:23:27 -0700224 u16 tco1_sts;
225 u16 tco2_sts;
226 u16 tcobase;
Lee Leahyb0005132015-05-12 18:19:47 -0700227
Barnali Sarkar49eca132016-08-12 00:05:27 +0530228 tcobase = smbus_tco_regs();
Lee Leahyb0005132015-05-12 18:19:47 -0700229
Lee Leahy1d14b3e2015-05-12 18:23:27 -0700230 /* TCO Status 2 register*/
231 tco2_sts = inw(tcobase + TCO2_STS);
232 tco2_sts |= (TCO2_STS_SECOND_TO | TCO2_STS_BOOT);
233 outw(tco2_sts, tcobase + TCO2_STS);
Lee Leahyb0005132015-05-12 18:19:47 -0700234
Lee Leahy1d14b3e2015-05-12 18:23:27 -0700235 /* TCO Status 1 register*/
236 tco1_sts = inw(tcobase + TCO1_STS);
237
238 /* Clear SECOND_TO_STS bit */
239 if (tco2_sts & TCO2_STS_SECOND_TO)
240 outw(tco2_sts & ~TCO2_STS_SECOND_TO, tcobase + TCO2_STS);
241
242 return (tco2_sts << 16) | tco1_sts;
Lee Leahyb0005132015-05-12 18:19:47 -0700243}
244
245/* Print TCO status bits */
246static u32 print_tco_status(u32 tco_sts)
247{
Lee Leahyf4c4ab92017-03-16 17:08:03 -0700248 static const char * const tco_sts_bits[] = {
Lee Leahyb0005132015-05-12 18:19:47 -0700249 [0] = "NMI2SMI",
250 [1] = "SW_TCO",
251 [2] = "TCO_INT",
252 [3] = "TIMEOUT",
253 [7] = "NEWCENTURY",
254 [8] = "BIOSWR",
255 [9] = "DMISCI",
256 [10] = "DMISMI",
257 [12] = "DMISERR",
258 [13] = "SLVSEL",
259 [16] = "INTRD_DET",
260 [17] = "SECOND_TO",
261 [18] = "BOOT",
262 [20] = "SMLINK_SLV"
263 };
264
265 if (!tco_sts)
266 return 0;
267
268 printk(BIOS_DEBUG, "TCO_STS: ");
269 print_status_bits(tco_sts, tco_sts_bits);
270 printk(BIOS_DEBUG, "\n");
271
272 return tco_sts;
273}
274
275/* Print, clear, and return TCO status */
276u32 clear_tco_status(void)
277{
278 return print_tco_status(reset_tco_status());
279}
280
281/* Enable TCO SCI */
282void enable_tco_sci(void)
283{
284 /* Clear pending events */
Lee Leahy1d14b3e2015-05-12 18:23:27 -0700285 outl(TCOSCI_STS, ACPI_BASE_ADDRESS + GPE0_STS(3));
Lee Leahyb0005132015-05-12 18:19:47 -0700286
287 /* Enable TCO SCI events */
288 enable_gpe(TCOSCI_EN);
289}
290
291
292/*
293 * GPE0
294 */
295
296/* Clear a GPE0 status and return events that are enabled and active */
297static u32 reset_gpe(u16 sts_reg, u16 en_reg)
298{
299 u32 gpe0_sts = inl(ACPI_BASE_ADDRESS + sts_reg);
300 u32 gpe0_en = inl(ACPI_BASE_ADDRESS + en_reg);
301
302 outl(gpe0_sts, ACPI_BASE_ADDRESS + sts_reg);
303
304 /* Only report enabled events */
305 return gpe0_sts & gpe0_en;
306}
307
308/* Print GPE0 status bits */
Lee Leahyf4c4ab92017-03-16 17:08:03 -0700309static u32 print_gpe_status(u32 gpe0_sts, const char * const bit_names[])
Lee Leahyb0005132015-05-12 18:19:47 -0700310{
311 if (!gpe0_sts)
312 return 0;
313
314 printk(BIOS_DEBUG, "GPE0_STS: ");
315 print_status_bits(gpe0_sts, bit_names);
316 printk(BIOS_DEBUG, "\n");
317
318 return gpe0_sts;
319}
320
321/* Print GPE0 GPIO status bits */
322static u32 print_gpe_gpio(u32 gpe0_sts, int start)
323{
324 if (!gpe0_sts)
325 return 0;
326
327 printk(BIOS_DEBUG, "GPE0_STS: ");
328 print_gpio_status(gpe0_sts, start);
329 printk(BIOS_DEBUG, "\n");
330
331 return gpe0_sts;
332}
333
334/* Clear all GPE status and return "standard" GPE event status */
335u32 clear_gpe_status(void)
336{
Lee Leahyf4c4ab92017-03-16 17:08:03 -0700337 static const char * const gpe0_sts_3_bits[] = {
Lee Leahyb0005132015-05-12 18:19:47 -0700338 [1] = "HOTPLUG",
339 [2] = "SWGPE",
340 [6] = "TCO_SCI",
341 [7] = "SMB_WAK",
342 [9] = "PCI_EXP",
343 [10] = "BATLOW",
344 [11] = "PME",
345 [12] = "ME",
346 [13] = "PME_B0",
Aaron Durbin7f788492015-07-24 17:10:31 -0500347 [14] = "eSPI",
348 [15] = "GPIO Tier-2",
349 [16] = "LAN_WAKE",
Lee Leahyb0005132015-05-12 18:19:47 -0700350 [18] = "WADT"
351 };
352
353 print_gpe_gpio(reset_gpe(GPE0_STS(GPE_31_0), GPE0_EN(GPE_31_0)), 0);
354 print_gpe_gpio(reset_gpe(GPE0_STS(GPE_63_32), GPE0_EN(GPE_63_32)), 32);
Aaron Durbin7f788492015-07-24 17:10:31 -0500355 print_gpe_gpio(reset_gpe(GPE0_STS(GPE_95_64), GPE0_EN(GPE_95_64)), 64);
Lee Leahyb0005132015-05-12 18:19:47 -0700356 return print_gpe_status(reset_gpe(GPE0_STS(GPE_STD), GPE0_EN(GPE_STD)),
357 gpe0_sts_3_bits);
358}
359
Duncan Laurie64ce1d12016-10-25 20:05:31 -0700360/* Read and clear GPE status (defined in arch/acpi.h) */
361int acpi_get_gpe(int gpe)
362{
363 int bank;
364 uint32_t mask, sts;
Duncan Laurie2f3736e2016-11-03 10:33:43 -0700365 struct stopwatch sw;
366 int rc = 0;
Duncan Laurie64ce1d12016-10-25 20:05:31 -0700367
368 if (gpe < 0 || gpe > GPE0_WADT)
369 return -1;
370
371 bank = gpe / 32;
372 mask = 1 << (gpe % 32);
373
Duncan Laurie2f3736e2016-11-03 10:33:43 -0700374 /* Wait up to 1ms for GPE status to clear */
375 stopwatch_init_msecs_expire(&sw, 1);
376 do {
377 if (stopwatch_expired(&sw))
378 return rc;
379
380 sts = inl(ACPI_BASE_ADDRESS + GPE0_STS(bank));
381 if (sts & mask) {
382 outl(mask, ACPI_BASE_ADDRESS + GPE0_STS(bank));
383 rc = 1;
384 }
385 } while (sts & mask);
386
387 return rc;
Duncan Laurie64ce1d12016-10-25 20:05:31 -0700388}
389
Lee Leahyb0005132015-05-12 18:19:47 -0700390/* Enable all requested GPE */
391void enable_all_gpe(u32 set1, u32 set2, u32 set3, u32 set4)
392{
393 outl(set1, ACPI_BASE_ADDRESS + GPE0_EN(GPE_31_0));
394 outl(set2, ACPI_BASE_ADDRESS + GPE0_EN(GPE_63_32));
Aaron Durbin7f788492015-07-24 17:10:31 -0500395 outl(set3, ACPI_BASE_ADDRESS + GPE0_EN(GPE_95_64));
Lee Leahyb0005132015-05-12 18:19:47 -0700396 outl(set4, ACPI_BASE_ADDRESS + GPE0_EN(GPE_STD));
397}
398
399/* Disable all GPE */
400void disable_all_gpe(void)
401{
402 enable_all_gpe(0, 0, 0, 0);
403}
404
405/* Enable a standard GPE */
406void enable_gpe(u32 mask)
407{
408 u32 gpe0_en = inl(ACPI_BASE_ADDRESS + GPE0_EN(GPE_STD));
409 gpe0_en |= mask;
410 outl(gpe0_en, ACPI_BASE_ADDRESS + GPE0_EN(GPE_STD));
411}
412
413/* Disable a standard GPE */
414void disable_gpe(u32 mask)
415{
416 u32 gpe0_en = inl(ACPI_BASE_ADDRESS + GPE0_EN(GPE_STD));
417 gpe0_en &= ~mask;
418 outl(gpe0_en, ACPI_BASE_ADDRESS + GPE0_EN(GPE_STD));
419}
420
421int acpi_sci_irq(void)
422{
Lee Leahy1d14b3e2015-05-12 18:23:27 -0700423 int scis = pci_read_config32(PCH_DEV_PMC, ACTL) & SCI_IRQ_SEL;
Lee Leahyb0005132015-05-12 18:19:47 -0700424 int sci_irq = 9;
425
426 /* Determine how SCI is routed. */
427 switch (scis) {
428 case SCIS_IRQ9:
429 case SCIS_IRQ10:
430 case SCIS_IRQ11:
431 sci_irq = scis - SCIS_IRQ9 + 9;
432 break;
433 case SCIS_IRQ20:
434 case SCIS_IRQ21:
435 case SCIS_IRQ22:
436 case SCIS_IRQ23:
437 sci_irq = scis - SCIS_IRQ20 + 20;
438 break;
439 default:
440 printk(BIOS_DEBUG, "Invalid SCI route! Defaulting to IRQ9.\n");
441 sci_irq = 9;
442 break;
443 }
444
445 printk(BIOS_DEBUG, "SCI is IRQ%d\n", sci_irq);
446 return sci_irq;
447}
Lee Leahy1d14b3e2015-05-12 18:23:27 -0700448
449uint8_t *pmc_mmio_regs(void)
450{
451 uint32_t reg32;
452
453 reg32 = pci_read_config32(PCH_DEV_PMC, PWRMBASE);
454
455 /* 4KiB alignment. */
456 reg32 &= ~0xfff;
457
458 return (void *)(uintptr_t)reg32;
459}
460
Barnali Sarkar49eca132016-08-12 00:05:27 +0530461uint16_t smbus_tco_regs(void)
Lee Leahy1d14b3e2015-05-12 18:23:27 -0700462{
463 uint16_t reg16;
464
465 reg16 = pci_read_config16(PCH_DEV_SMBUS, TCOBASE);
466
467 reg16 &= ~0x1f;
468
469 return reg16;
470}
Aaron Durbin38613d02016-07-14 00:56:58 -0500471
472void poweroff(void)
473{
474 enable_pm1_control(SLP_EN | (SLP_TYP_S5 << SLP_TYP_SHIFT));
Furquan Shaikh97e0a652016-08-18 21:42:36 -0700475
476 /*
477 * Setting SLP_TYP_S5 in PM1 triggers SLP_SMI, which is handled by SMM
478 * to transition to S5 state. If halt is called in SMM, then it prevents
479 * the SMI handler from being triggered and system never enters S5.
480 */
481 if (!ENV_SMM)
482 halt();
Aaron Durbin38613d02016-07-14 00:56:58 -0500483}
Duncan Laurief0ba2252016-10-25 20:03:56 -0700484
485void pmc_gpe_init(void)
486{
Aaron Durbine4d7abc2017-04-16 22:05:36 -0500487 DEVTREE_CONST struct soc_intel_skylake_config *config;
488 DEVTREE_CONST struct device *dev = dev_find_slot(0, PCH_DEVFN_PMC);
Duncan Laurief0ba2252016-10-25 20:03:56 -0700489 uint8_t *pmc_regs;
490 uint32_t gpio_cfg;
491 uint32_t gpio_cfg_reg;
492 const uint32_t gpio_cfg_mask =
493 (GPE0_DWX_MASK << GPE0_DW0_SHIFT) |
494 (GPE0_DWX_MASK << GPE0_DW1_SHIFT) |
495 (GPE0_DWX_MASK << GPE0_DW2_SHIFT);
496
497 /* Look up the device in devicetree */
498 if (!dev || !dev->chip_info) {
499 printk(BIOS_ERR, "BUG! Could not find SOC devicetree config\n");
500 return;
501 }
502 config = dev->chip_info;
503 pmc_regs = pmc_mmio_regs();
504
505 /* Route the GPIOs to the GPE0 block. Determine that all values
506 * are different, and if they aren't use the reset values. */
507 gpio_cfg = 0;
508 if (config->gpe0_dw0 == config->gpe0_dw1 ||
509 config->gpe0_dw1 == config->gpe0_dw2) {
510 printk(BIOS_INFO, "PMC: Using default GPE route.\n");
511 gpio_cfg = read32(pmc_regs + GPIO_CFG);
512 } else {
513 gpio_cfg |= (uint32_t)config->gpe0_dw0 << GPE0_DW0_SHIFT;
514 gpio_cfg |= (uint32_t)config->gpe0_dw1 << GPE0_DW1_SHIFT;
515 gpio_cfg |= (uint32_t)config->gpe0_dw2 << GPE0_DW2_SHIFT;
516 }
517 gpio_cfg_reg = read32(pmc_regs + GPIO_CFG) & ~gpio_cfg_mask;
518 gpio_cfg_reg |= gpio_cfg & gpio_cfg_mask;
519 write32(pmc_regs + GPIO_CFG, gpio_cfg_reg);
520
521 /* Set the routes in the GPIO communities as well. */
522 gpio_route_gpe(gpio_cfg_reg >> GPE0_DW0_SHIFT);
523
524 /* Set GPE enables based on devictree. */
525 enable_all_gpe(config->gpe0_en_1, config->gpe0_en_2,
526 config->gpe0_en_3, config->gpe0_en_4);
527}