blob: 203a430ffabb90fdcc7a80565a19f0ff0fb57612 [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 Laurief0ba2252016-10-25 20:03:56 -070040#include "chip.h"
Lee Leahyb0005132015-05-12 18:19:47 -070041
42/* Print status bits with descriptive names */
43static void print_status_bits(u32 status, const char *bit_names[])
44{
45 int i;
46
47 if (!status)
48 return;
49
Lee Leahy1d14b3e2015-05-12 18:23:27 -070050 for (i = 31; i >= 0; i--) {
Lee Leahyb0005132015-05-12 18:19:47 -070051 if (status & (1 << i)) {
52 if (bit_names[i])
53 printk(BIOS_DEBUG, "%s ", bit_names[i]);
54 else
55 printk(BIOS_DEBUG, "BIT%d ", i);
56 }
57 }
58}
59
60/* Print status bits as GPIO numbers */
61static void print_gpio_status(u32 status, int start)
62{
63 int i;
64
65 if (!status)
66 return;
67
Lee Leahy1d14b3e2015-05-12 18:23:27 -070068 for (i = 31; i >= 0; i--) {
Lee Leahyb0005132015-05-12 18:19:47 -070069 if (status & (1 << i))
70 printk(BIOS_DEBUG, "GPIO%d ", start + i);
71 }
72}
73
74
75/*
76 * PM1_CNT
77 */
78
79/* Enable events in PM1 control register */
80void enable_pm1_control(u32 mask)
81{
82 u32 pm1_cnt = inl(ACPI_BASE_ADDRESS + PM1_CNT);
83 pm1_cnt |= mask;
84 outl(pm1_cnt, ACPI_BASE_ADDRESS + PM1_CNT);
85}
86
87/* Disable events in PM1 control register */
88void disable_pm1_control(u32 mask)
89{
90 u32 pm1_cnt = inl(ACPI_BASE_ADDRESS + PM1_CNT);
91 pm1_cnt &= ~mask;
92 outl(pm1_cnt, ACPI_BASE_ADDRESS + PM1_CNT);
93}
94
95
96/*
97 * PM1
98 */
99
100/* Clear and return PM1 status register */
101static u16 reset_pm1_status(void)
102{
103 u16 pm1_sts = inw(ACPI_BASE_ADDRESS + PM1_STS);
104 outw(pm1_sts, ACPI_BASE_ADDRESS + PM1_STS);
105 return pm1_sts;
106}
107
108/* Print PM1 status bits */
109static u16 print_pm1_status(u16 pm1_sts)
110{
111 const char *pm1_sts_bits[] = {
112 [0] = "TMROF",
113 [4] = "BM",
114 [5] = "GBL",
115 [8] = "PWRBTN",
116 [10] = "RTC",
117 [11] = "PRBTNOR",
118 [14] = "PCIEXPWAK",
119 [15] = "WAK",
120 };
121
122 if (!pm1_sts)
123 return 0;
124
125 printk(BIOS_SPEW, "PM1_STS: ");
126 print_status_bits(pm1_sts, pm1_sts_bits);
127 printk(BIOS_SPEW, "\n");
128
129 return pm1_sts;
130}
131
132/* Print, clear, and return PM1 status */
133u16 clear_pm1_status(void)
134{
135 return print_pm1_status(reset_pm1_status());
136}
137
138/* Set the PM1 register to events */
139void enable_pm1(u16 events)
140{
141 outw(events, ACPI_BASE_ADDRESS + PM1_EN);
142}
143
144
145/*
146 * SMI
147 */
148
149/* Clear and return SMI status register */
150static u32 reset_smi_status(void)
151{
152 u32 smi_sts = inl(ACPI_BASE_ADDRESS + SMI_STS);
153 outl(smi_sts, ACPI_BASE_ADDRESS + SMI_STS);
154 return smi_sts;
155}
156
157/* Print SMI status bits */
158static u32 print_smi_status(u32 smi_sts)
159{
160 const char *smi_sts_bits[] = {
161 [2] = "BIOS",
162 [3] = "LEGACY_USB",
163 [4] = "SLP_SMI",
164 [5] = "APM",
165 [6] = "SWSMI_TMR",
166 [8] = "PM1",
167 [9] = "GPE0",
168 [10] = "GPI",
169 [11] = "MCSMI",
170 [12] = "DEVMON",
171 [13] = "TCO",
172 [14] = "PERIODIC",
173 [15] = "SERIRQ_SMI",
174 [16] = "SMBUS_SMI",
175 [17] = "LEGACY_USB2",
176 [18] = "INTEL_USB2",
177 [20] = "PCI_EXP_SMI",
178 [21] = "MONITOR",
179 [26] = "SPI",
Duncan Laurie8d019022016-10-25 19:58:27 -0700180 [27] = "GPIO_UNLOCK",
181 [28] = "ESPI_SMI",
Lee Leahyb0005132015-05-12 18:19:47 -0700182 };
183
184 if (!smi_sts)
185 return 0;
186
187 printk(BIOS_DEBUG, "SMI_STS: ");
188 print_status_bits(smi_sts, smi_sts_bits);
189 printk(BIOS_DEBUG, "\n");
190
191 return smi_sts;
192}
193
194/* Print, clear, and return SMI status */
195u32 clear_smi_status(void)
196{
197 return print_smi_status(reset_smi_status());
198}
199
200/* Enable SMI event */
201void enable_smi(u32 mask)
202{
203 u32 smi_en = inl(ACPI_BASE_ADDRESS + SMI_EN);
204 smi_en |= mask;
205 outl(smi_en, ACPI_BASE_ADDRESS + SMI_EN);
206}
207
208/* Disable SMI event */
209void disable_smi(u32 mask)
210{
211 u32 smi_en = inl(ACPI_BASE_ADDRESS + SMI_EN);
212 smi_en &= ~mask;
213 outl(smi_en, ACPI_BASE_ADDRESS + SMI_EN);
214}
215
Lee Leahyb0005132015-05-12 18:19:47 -0700216/*
217 * TCO
218 */
219
220/* Clear TCO status and return events that are enabled and active */
221static u32 reset_tco_status(void)
222{
Lee Leahy1d14b3e2015-05-12 18:23:27 -0700223 u16 tco1_sts;
224 u16 tco2_sts;
225 u16 tcobase;
Lee Leahyb0005132015-05-12 18:19:47 -0700226
Barnali Sarkar49eca132016-08-12 00:05:27 +0530227 tcobase = smbus_tco_regs();
Lee Leahyb0005132015-05-12 18:19:47 -0700228
Lee Leahy1d14b3e2015-05-12 18:23:27 -0700229 /* TCO Status 2 register*/
230 tco2_sts = inw(tcobase + TCO2_STS);
231 tco2_sts |= (TCO2_STS_SECOND_TO | TCO2_STS_BOOT);
232 outw(tco2_sts, tcobase + TCO2_STS);
Lee Leahyb0005132015-05-12 18:19:47 -0700233
Lee Leahy1d14b3e2015-05-12 18:23:27 -0700234 /* TCO Status 1 register*/
235 tco1_sts = inw(tcobase + TCO1_STS);
236
237 /* Clear SECOND_TO_STS bit */
238 if (tco2_sts & TCO2_STS_SECOND_TO)
239 outw(tco2_sts & ~TCO2_STS_SECOND_TO, tcobase + TCO2_STS);
240
241 return (tco2_sts << 16) | tco1_sts;
Lee Leahyb0005132015-05-12 18:19:47 -0700242}
243
244/* Print TCO status bits */
245static u32 print_tco_status(u32 tco_sts)
246{
247 const char *tco_sts_bits[] = {
248 [0] = "NMI2SMI",
249 [1] = "SW_TCO",
250 [2] = "TCO_INT",
251 [3] = "TIMEOUT",
252 [7] = "NEWCENTURY",
253 [8] = "BIOSWR",
254 [9] = "DMISCI",
255 [10] = "DMISMI",
256 [12] = "DMISERR",
257 [13] = "SLVSEL",
258 [16] = "INTRD_DET",
259 [17] = "SECOND_TO",
260 [18] = "BOOT",
261 [20] = "SMLINK_SLV"
262 };
263
264 if (!tco_sts)
265 return 0;
266
267 printk(BIOS_DEBUG, "TCO_STS: ");
268 print_status_bits(tco_sts, tco_sts_bits);
269 printk(BIOS_DEBUG, "\n");
270
271 return tco_sts;
272}
273
274/* Print, clear, and return TCO status */
275u32 clear_tco_status(void)
276{
277 return print_tco_status(reset_tco_status());
278}
279
280/* Enable TCO SCI */
281void enable_tco_sci(void)
282{
283 /* Clear pending events */
Lee Leahy1d14b3e2015-05-12 18:23:27 -0700284 outl(TCOSCI_STS, ACPI_BASE_ADDRESS + GPE0_STS(3));
Lee Leahyb0005132015-05-12 18:19:47 -0700285
286 /* Enable TCO SCI events */
287 enable_gpe(TCOSCI_EN);
288}
289
290
291/*
292 * GPE0
293 */
294
295/* Clear a GPE0 status and return events that are enabled and active */
296static u32 reset_gpe(u16 sts_reg, u16 en_reg)
297{
298 u32 gpe0_sts = inl(ACPI_BASE_ADDRESS + sts_reg);
299 u32 gpe0_en = inl(ACPI_BASE_ADDRESS + en_reg);
300
301 outl(gpe0_sts, ACPI_BASE_ADDRESS + sts_reg);
302
303 /* Only report enabled events */
304 return gpe0_sts & gpe0_en;
305}
306
307/* Print GPE0 status bits */
308static u32 print_gpe_status(u32 gpe0_sts, const char *bit_names[])
309{
310 if (!gpe0_sts)
311 return 0;
312
313 printk(BIOS_DEBUG, "GPE0_STS: ");
314 print_status_bits(gpe0_sts, bit_names);
315 printk(BIOS_DEBUG, "\n");
316
317 return gpe0_sts;
318}
319
320/* Print GPE0 GPIO status bits */
321static u32 print_gpe_gpio(u32 gpe0_sts, int start)
322{
323 if (!gpe0_sts)
324 return 0;
325
326 printk(BIOS_DEBUG, "GPE0_STS: ");
327 print_gpio_status(gpe0_sts, start);
328 printk(BIOS_DEBUG, "\n");
329
330 return gpe0_sts;
331}
332
333/* Clear all GPE status and return "standard" GPE event status */
334u32 clear_gpe_status(void)
335{
336 const char *gpe0_sts_3_bits[] = {
337 [1] = "HOTPLUG",
338 [2] = "SWGPE",
339 [6] = "TCO_SCI",
340 [7] = "SMB_WAK",
341 [9] = "PCI_EXP",
342 [10] = "BATLOW",
343 [11] = "PME",
344 [12] = "ME",
345 [13] = "PME_B0",
Aaron Durbin7f788492015-07-24 17:10:31 -0500346 [14] = "eSPI",
347 [15] = "GPIO Tier-2",
348 [16] = "LAN_WAKE",
Lee Leahyb0005132015-05-12 18:19:47 -0700349 [18] = "WADT"
350 };
351
352 print_gpe_gpio(reset_gpe(GPE0_STS(GPE_31_0), GPE0_EN(GPE_31_0)), 0);
353 print_gpe_gpio(reset_gpe(GPE0_STS(GPE_63_32), GPE0_EN(GPE_63_32)), 32);
Aaron Durbin7f788492015-07-24 17:10:31 -0500354 print_gpe_gpio(reset_gpe(GPE0_STS(GPE_95_64), GPE0_EN(GPE_95_64)), 64);
Lee Leahyb0005132015-05-12 18:19:47 -0700355 return print_gpe_status(reset_gpe(GPE0_STS(GPE_STD), GPE0_EN(GPE_STD)),
356 gpe0_sts_3_bits);
357}
358
Duncan Laurie64ce1d12016-10-25 20:05:31 -0700359/* Read and clear GPE status (defined in arch/acpi.h) */
360int acpi_get_gpe(int gpe)
361{
362 int bank;
363 uint32_t mask, sts;
364
365 if (gpe < 0 || gpe > GPE0_WADT)
366 return -1;
367
368 bank = gpe / 32;
369 mask = 1 << (gpe % 32);
370
371 sts = inl(ACPI_BASE_ADDRESS + GPE0_STS(bank));
372 if (sts & mask) {
373 outl(mask, ACPI_BASE_ADDRESS + GPE0_STS(bank));
374 return 1;
375 }
376 return 0;
377}
378
Lee Leahyb0005132015-05-12 18:19:47 -0700379/* Enable all requested GPE */
380void enable_all_gpe(u32 set1, u32 set2, u32 set3, u32 set4)
381{
382 outl(set1, ACPI_BASE_ADDRESS + GPE0_EN(GPE_31_0));
383 outl(set2, ACPI_BASE_ADDRESS + GPE0_EN(GPE_63_32));
Aaron Durbin7f788492015-07-24 17:10:31 -0500384 outl(set3, ACPI_BASE_ADDRESS + GPE0_EN(GPE_95_64));
Lee Leahyb0005132015-05-12 18:19:47 -0700385 outl(set4, ACPI_BASE_ADDRESS + GPE0_EN(GPE_STD));
386}
387
388/* Disable all GPE */
389void disable_all_gpe(void)
390{
391 enable_all_gpe(0, 0, 0, 0);
392}
393
394/* Enable a standard GPE */
395void enable_gpe(u32 mask)
396{
397 u32 gpe0_en = inl(ACPI_BASE_ADDRESS + GPE0_EN(GPE_STD));
398 gpe0_en |= mask;
399 outl(gpe0_en, ACPI_BASE_ADDRESS + GPE0_EN(GPE_STD));
400}
401
402/* Disable a standard GPE */
403void disable_gpe(u32 mask)
404{
405 u32 gpe0_en = inl(ACPI_BASE_ADDRESS + GPE0_EN(GPE_STD));
406 gpe0_en &= ~mask;
407 outl(gpe0_en, ACPI_BASE_ADDRESS + GPE0_EN(GPE_STD));
408}
409
410int acpi_sci_irq(void)
411{
Lee Leahy1d14b3e2015-05-12 18:23:27 -0700412 int scis = pci_read_config32(PCH_DEV_PMC, ACTL) & SCI_IRQ_SEL;
Lee Leahyb0005132015-05-12 18:19:47 -0700413 int sci_irq = 9;
414
415 /* Determine how SCI is routed. */
416 switch (scis) {
417 case SCIS_IRQ9:
418 case SCIS_IRQ10:
419 case SCIS_IRQ11:
420 sci_irq = scis - SCIS_IRQ9 + 9;
421 break;
422 case SCIS_IRQ20:
423 case SCIS_IRQ21:
424 case SCIS_IRQ22:
425 case SCIS_IRQ23:
426 sci_irq = scis - SCIS_IRQ20 + 20;
427 break;
428 default:
429 printk(BIOS_DEBUG, "Invalid SCI route! Defaulting to IRQ9.\n");
430 sci_irq = 9;
431 break;
432 }
433
434 printk(BIOS_DEBUG, "SCI is IRQ%d\n", sci_irq);
435 return sci_irq;
436}
Lee Leahy1d14b3e2015-05-12 18:23:27 -0700437
438uint8_t *pmc_mmio_regs(void)
439{
440 uint32_t reg32;
441
442 reg32 = pci_read_config32(PCH_DEV_PMC, PWRMBASE);
443
444 /* 4KiB alignment. */
445 reg32 &= ~0xfff;
446
447 return (void *)(uintptr_t)reg32;
448}
449
Barnali Sarkar49eca132016-08-12 00:05:27 +0530450uint16_t smbus_tco_regs(void)
Lee Leahy1d14b3e2015-05-12 18:23:27 -0700451{
452 uint16_t reg16;
453
454 reg16 = pci_read_config16(PCH_DEV_SMBUS, TCOBASE);
455
456 reg16 &= ~0x1f;
457
458 return reg16;
459}
Aaron Durbin38613d02016-07-14 00:56:58 -0500460
461void poweroff(void)
462{
463 enable_pm1_control(SLP_EN | (SLP_TYP_S5 << SLP_TYP_SHIFT));
Furquan Shaikh97e0a652016-08-18 21:42:36 -0700464
465 /*
466 * Setting SLP_TYP_S5 in PM1 triggers SLP_SMI, which is handled by SMM
467 * to transition to S5 state. If halt is called in SMM, then it prevents
468 * the SMI handler from being triggered and system never enters S5.
469 */
470 if (!ENV_SMM)
471 halt();
Aaron Durbin38613d02016-07-14 00:56:58 -0500472}
Duncan Laurief0ba2252016-10-25 20:03:56 -0700473
474void pmc_gpe_init(void)
475{
476 ROMSTAGE_CONST struct soc_intel_skylake_config *config;
477 ROMSTAGE_CONST struct device *dev = dev_find_slot(0, PCH_DEVFN_PMC);
478 uint8_t *pmc_regs;
479 uint32_t gpio_cfg;
480 uint32_t gpio_cfg_reg;
481 const uint32_t gpio_cfg_mask =
482 (GPE0_DWX_MASK << GPE0_DW0_SHIFT) |
483 (GPE0_DWX_MASK << GPE0_DW1_SHIFT) |
484 (GPE0_DWX_MASK << GPE0_DW2_SHIFT);
485
486 /* Look up the device in devicetree */
487 if (!dev || !dev->chip_info) {
488 printk(BIOS_ERR, "BUG! Could not find SOC devicetree config\n");
489 return;
490 }
491 config = dev->chip_info;
492 pmc_regs = pmc_mmio_regs();
493
494 /* Route the GPIOs to the GPE0 block. Determine that all values
495 * are different, and if they aren't use the reset values. */
496 gpio_cfg = 0;
497 if (config->gpe0_dw0 == config->gpe0_dw1 ||
498 config->gpe0_dw1 == config->gpe0_dw2) {
499 printk(BIOS_INFO, "PMC: Using default GPE route.\n");
500 gpio_cfg = read32(pmc_regs + GPIO_CFG);
501 } else {
502 gpio_cfg |= (uint32_t)config->gpe0_dw0 << GPE0_DW0_SHIFT;
503 gpio_cfg |= (uint32_t)config->gpe0_dw1 << GPE0_DW1_SHIFT;
504 gpio_cfg |= (uint32_t)config->gpe0_dw2 << GPE0_DW2_SHIFT;
505 }
506 gpio_cfg_reg = read32(pmc_regs + GPIO_CFG) & ~gpio_cfg_mask;
507 gpio_cfg_reg |= gpio_cfg & gpio_cfg_mask;
508 write32(pmc_regs + GPIO_CFG, gpio_cfg_reg);
509
510 /* Set the routes in the GPIO communities as well. */
511 gpio_route_gpe(gpio_cfg_reg >> GPE0_DW0_SHIFT);
512
513 /* Set GPE enables based on devictree. */
514 enable_all_gpe(config->gpe0_en_1, config->gpe0_en_2,
515 config->gpe0_en_3, config->gpe0_en_4);
516}