blob: 85dc1b3fda53ee75d557fdf32f112fd3361fe4c4 [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.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
Lee Leahy1d14b3e2015-05-12 18:23:27 -070018 * Foundation, Inc.
Lee Leahyb0005132015-05-12 18:19:47 -070019 */
20
21/*
22 * Helper functions for dealing with power management registers
23 * and the differences between PCH variants.
24 */
25
26#include <arch/io.h>
27#include <device/device.h>
28#include <device/pci.h>
29#include <device/pci_def.h>
30#include <console/console.h>
Lee Leahy1d14b3e2015-05-12 18:23:27 -070031#include <stdlib.h>
32#include <soc/gpio.h>
Lee Leahyb0005132015-05-12 18:19:47 -070033#include <soc/iomap.h>
34#include <soc/lpc.h>
35#include <soc/pci_devs.h>
36#include <soc/pm.h>
Lee Leahy1d14b3e2015-05-12 18:23:27 -070037#include <soc/pmc.h>
38#include <soc/smbus.h>
Lee Leahyb0005132015-05-12 18:19:47 -070039
40/* Print status bits with descriptive names */
41static void print_status_bits(u32 status, const char *bit_names[])
42{
43 int i;
44
45 if (!status)
46 return;
47
Lee Leahy1d14b3e2015-05-12 18:23:27 -070048 for (i = 31; i >= 0; i--) {
Lee Leahyb0005132015-05-12 18:19:47 -070049 if (status & (1 << i)) {
50 if (bit_names[i])
51 printk(BIOS_DEBUG, "%s ", bit_names[i]);
52 else
53 printk(BIOS_DEBUG, "BIT%d ", i);
54 }
55 }
56}
57
58/* Print status bits as GPIO numbers */
59static void print_gpio_status(u32 status, int start)
60{
61 int i;
62
63 if (!status)
64 return;
65
Lee Leahy1d14b3e2015-05-12 18:23:27 -070066 for (i = 31; i >= 0; i--) {
Lee Leahyb0005132015-05-12 18:19:47 -070067 if (status & (1 << i))
68 printk(BIOS_DEBUG, "GPIO%d ", start + i);
69 }
70}
71
72
73/*
74 * PM1_CNT
75 */
76
77/* Enable events in PM1 control register */
78void enable_pm1_control(u32 mask)
79{
80 u32 pm1_cnt = inl(ACPI_BASE_ADDRESS + PM1_CNT);
81 pm1_cnt |= mask;
82 outl(pm1_cnt, ACPI_BASE_ADDRESS + PM1_CNT);
83}
84
85/* Disable events in PM1 control register */
86void disable_pm1_control(u32 mask)
87{
88 u32 pm1_cnt = inl(ACPI_BASE_ADDRESS + PM1_CNT);
89 pm1_cnt &= ~mask;
90 outl(pm1_cnt, ACPI_BASE_ADDRESS + PM1_CNT);
91}
92
93
94/*
95 * PM1
96 */
97
98/* Clear and return PM1 status register */
99static u16 reset_pm1_status(void)
100{
101 u16 pm1_sts = inw(ACPI_BASE_ADDRESS + PM1_STS);
102 outw(pm1_sts, ACPI_BASE_ADDRESS + PM1_STS);
103 return pm1_sts;
104}
105
106/* Print PM1 status bits */
107static u16 print_pm1_status(u16 pm1_sts)
108{
109 const char *pm1_sts_bits[] = {
110 [0] = "TMROF",
111 [4] = "BM",
112 [5] = "GBL",
113 [8] = "PWRBTN",
114 [10] = "RTC",
115 [11] = "PRBTNOR",
116 [14] = "PCIEXPWAK",
117 [15] = "WAK",
118 };
119
120 if (!pm1_sts)
121 return 0;
122
123 printk(BIOS_SPEW, "PM1_STS: ");
124 print_status_bits(pm1_sts, pm1_sts_bits);
125 printk(BIOS_SPEW, "\n");
126
127 return pm1_sts;
128}
129
130/* Print, clear, and return PM1 status */
131u16 clear_pm1_status(void)
132{
133 return print_pm1_status(reset_pm1_status());
134}
135
136/* Set the PM1 register to events */
137void enable_pm1(u16 events)
138{
139 outw(events, ACPI_BASE_ADDRESS + PM1_EN);
140}
141
142
143/*
144 * SMI
145 */
146
147/* Clear and return SMI status register */
148static u32 reset_smi_status(void)
149{
150 u32 smi_sts = inl(ACPI_BASE_ADDRESS + SMI_STS);
151 outl(smi_sts, ACPI_BASE_ADDRESS + SMI_STS);
152 return smi_sts;
153}
154
155/* Print SMI status bits */
156static u32 print_smi_status(u32 smi_sts)
157{
158 const char *smi_sts_bits[] = {
159 [2] = "BIOS",
160 [3] = "LEGACY_USB",
161 [4] = "SLP_SMI",
162 [5] = "APM",
163 [6] = "SWSMI_TMR",
164 [8] = "PM1",
165 [9] = "GPE0",
166 [10] = "GPI",
167 [11] = "MCSMI",
168 [12] = "DEVMON",
169 [13] = "TCO",
170 [14] = "PERIODIC",
171 [15] = "SERIRQ_SMI",
172 [16] = "SMBUS_SMI",
173 [17] = "LEGACY_USB2",
174 [18] = "INTEL_USB2",
175 [20] = "PCI_EXP_SMI",
176 [21] = "MONITOR",
177 [26] = "SPI",
178 [27] = "GPIO_UNLOCK"
179 };
180
181 if (!smi_sts)
182 return 0;
183
184 printk(BIOS_DEBUG, "SMI_STS: ");
185 print_status_bits(smi_sts, smi_sts_bits);
186 printk(BIOS_DEBUG, "\n");
187
188 return smi_sts;
189}
190
191/* Print, clear, and return SMI status */
192u32 clear_smi_status(void)
193{
194 return print_smi_status(reset_smi_status());
195}
196
197/* Enable SMI event */
198void enable_smi(u32 mask)
199{
200 u32 smi_en = inl(ACPI_BASE_ADDRESS + SMI_EN);
201 smi_en |= mask;
202 outl(smi_en, ACPI_BASE_ADDRESS + SMI_EN);
203}
204
205/* Disable SMI event */
206void disable_smi(u32 mask)
207{
208 u32 smi_en = inl(ACPI_BASE_ADDRESS + SMI_EN);
209 smi_en &= ~mask;
210 outl(smi_en, ACPI_BASE_ADDRESS + SMI_EN);
211}
212
213
214/*
215 * ALT_GP_SMI
216 */
217
218/* Clear GPIO SMI status and return events that are enabled and active */
Lee Leahy1d14b3e2015-05-12 18:23:27 -0700219void reset_alt_smi_status(void)
Lee Leahyb0005132015-05-12 18:19:47 -0700220{
Lee Leahy1d14b3e2015-05-12 18:23:27 -0700221 /*Clear GPIO SMI Status*/
Aaron Durbin4f5efb62015-07-22 20:57:05 -0500222 gpio_clear_all_smi();
Lee Leahyb0005132015-05-12 18:19:47 -0700223}
224
225/* Print GPIO SMI status bits */
Lee Leahy1d14b3e2015-05-12 18:23:27 -0700226static u32 print_alt_smi_status(void)
Lee Leahyb0005132015-05-12 18:19:47 -0700227{
Lee Leahy1d14b3e2015-05-12 18:23:27 -0700228 u32 alt_sts[GPIO_COMMUNITY_MAX];
229 int gpio_index;
230 /* GPIO Communities GPP_A ~ E support SMI */
231 const char gpiowell[] = {
232 [0] = 'A',
233 [1] = 'B',
234 [2] = 'C',
235 [3] = 'D',
236 [4] = 'E'
237 };
Lee Leahyb0005132015-05-12 18:19:47 -0700238
239 printk(BIOS_DEBUG, "ALT_STS: ");
Aaron Durbin4f5efb62015-07-22 20:57:05 -0500240 gpio_get_smi_status(alt_sts);
Lee Leahy1d14b3e2015-05-12 18:23:27 -0700241 /* GPP_A to GPP_E GPIO has Status and Enable functionality*/
242 for (gpio_index = 0; gpio_index < ARRAY_SIZE(gpiowell);
243 gpio_index++) {
244 printk(BIOS_DEBUG, "GPIO Group_%c\n",
245 gpiowell[gpio_index]);
246 print_gpio_status(alt_sts[gpio_index], 0);
247 }
Lee Leahyb0005132015-05-12 18:19:47 -0700248
249 printk(BIOS_DEBUG, "\n");
250
Lee Leahy1d14b3e2015-05-12 18:23:27 -0700251 return 0;
Lee Leahyb0005132015-05-12 18:19:47 -0700252}
253
254/* Print, clear, and return GPIO SMI status */
255u32 clear_alt_smi_status(void)
256{
Lee Leahy1d14b3e2015-05-12 18:23:27 -0700257 reset_alt_smi_status();
258 return print_alt_smi_status();
Lee Leahyb0005132015-05-12 18:19:47 -0700259}
260
261/* Enable GPIO SMI events */
Lee Leahy1d14b3e2015-05-12 18:23:27 -0700262void enable_alt_smi(int gpionum, u32 mask)
Lee Leahyb0005132015-05-12 18:19:47 -0700263{
Lee Leahy1d14b3e2015-05-12 18:23:27 -0700264 /*Set GPIO EN Status*/
Aaron Durbin4f5efb62015-07-22 20:57:05 -0500265 gpio_enable_groupsmi(gpionum, mask);
Lee Leahyb0005132015-05-12 18:19:47 -0700266}
267
268
269/*
270 * TCO
271 */
272
273/* Clear TCO status and return events that are enabled and active */
274static u32 reset_tco_status(void)
275{
Lee Leahy1d14b3e2015-05-12 18:23:27 -0700276 u16 tco1_sts;
277 u16 tco2_sts;
278 u16 tcobase;
Lee Leahyb0005132015-05-12 18:19:47 -0700279
Lee Leahy1d14b3e2015-05-12 18:23:27 -0700280 tcobase = pmc_tco_regs();
Lee Leahyb0005132015-05-12 18:19:47 -0700281
Lee Leahy1d14b3e2015-05-12 18:23:27 -0700282 /* TCO Status 2 register*/
283 tco2_sts = inw(tcobase + TCO2_STS);
284 tco2_sts |= (TCO2_STS_SECOND_TO | TCO2_STS_BOOT);
285 outw(tco2_sts, tcobase + TCO2_STS);
Lee Leahyb0005132015-05-12 18:19:47 -0700286
Lee Leahy1d14b3e2015-05-12 18:23:27 -0700287 /* TCO Status 1 register*/
288 tco1_sts = inw(tcobase + TCO1_STS);
289
290 /* Clear SECOND_TO_STS bit */
291 if (tco2_sts & TCO2_STS_SECOND_TO)
292 outw(tco2_sts & ~TCO2_STS_SECOND_TO, tcobase + TCO2_STS);
293
294 return (tco2_sts << 16) | tco1_sts;
Lee Leahyb0005132015-05-12 18:19:47 -0700295}
296
297/* Print TCO status bits */
298static u32 print_tco_status(u32 tco_sts)
299{
300 const char *tco_sts_bits[] = {
301 [0] = "NMI2SMI",
302 [1] = "SW_TCO",
303 [2] = "TCO_INT",
304 [3] = "TIMEOUT",
305 [7] = "NEWCENTURY",
306 [8] = "BIOSWR",
307 [9] = "DMISCI",
308 [10] = "DMISMI",
309 [12] = "DMISERR",
310 [13] = "SLVSEL",
311 [16] = "INTRD_DET",
312 [17] = "SECOND_TO",
313 [18] = "BOOT",
314 [20] = "SMLINK_SLV"
315 };
316
317 if (!tco_sts)
318 return 0;
319
320 printk(BIOS_DEBUG, "TCO_STS: ");
321 print_status_bits(tco_sts, tco_sts_bits);
322 printk(BIOS_DEBUG, "\n");
323
324 return tco_sts;
325}
326
327/* Print, clear, and return TCO status */
328u32 clear_tco_status(void)
329{
330 return print_tco_status(reset_tco_status());
331}
332
333/* Enable TCO SCI */
334void enable_tco_sci(void)
335{
336 /* Clear pending events */
Lee Leahy1d14b3e2015-05-12 18:23:27 -0700337 outl(TCOSCI_STS, ACPI_BASE_ADDRESS + GPE0_STS(3));
Lee Leahyb0005132015-05-12 18:19:47 -0700338
339 /* Enable TCO SCI events */
340 enable_gpe(TCOSCI_EN);
341}
342
343
344/*
345 * GPE0
346 */
347
348/* Clear a GPE0 status and return events that are enabled and active */
349static u32 reset_gpe(u16 sts_reg, u16 en_reg)
350{
351 u32 gpe0_sts = inl(ACPI_BASE_ADDRESS + sts_reg);
352 u32 gpe0_en = inl(ACPI_BASE_ADDRESS + en_reg);
353
354 outl(gpe0_sts, ACPI_BASE_ADDRESS + sts_reg);
355
356 /* Only report enabled events */
357 return gpe0_sts & gpe0_en;
358}
359
360/* Print GPE0 status bits */
361static u32 print_gpe_status(u32 gpe0_sts, const char *bit_names[])
362{
363 if (!gpe0_sts)
364 return 0;
365
366 printk(BIOS_DEBUG, "GPE0_STS: ");
367 print_status_bits(gpe0_sts, bit_names);
368 printk(BIOS_DEBUG, "\n");
369
370 return gpe0_sts;
371}
372
373/* Print GPE0 GPIO status bits */
374static u32 print_gpe_gpio(u32 gpe0_sts, int start)
375{
376 if (!gpe0_sts)
377 return 0;
378
379 printk(BIOS_DEBUG, "GPE0_STS: ");
380 print_gpio_status(gpe0_sts, start);
381 printk(BIOS_DEBUG, "\n");
382
383 return gpe0_sts;
384}
385
386/* Clear all GPE status and return "standard" GPE event status */
387u32 clear_gpe_status(void)
388{
389 const char *gpe0_sts_3_bits[] = {
390 [1] = "HOTPLUG",
391 [2] = "SWGPE",
392 [6] = "TCO_SCI",
393 [7] = "SMB_WAK",
394 [9] = "PCI_EXP",
395 [10] = "BATLOW",
396 [11] = "PME",
397 [12] = "ME",
398 [13] = "PME_B0",
399 [16] = "GPIO27",
400 [18] = "WADT"
401 };
402
403 print_gpe_gpio(reset_gpe(GPE0_STS(GPE_31_0), GPE0_EN(GPE_31_0)), 0);
404 print_gpe_gpio(reset_gpe(GPE0_STS(GPE_63_32), GPE0_EN(GPE_63_32)), 32);
405 print_gpe_gpio(reset_gpe(GPE0_STS(GPE_94_64), GPE0_EN(GPE_94_64)), 64);
406 return print_gpe_status(reset_gpe(GPE0_STS(GPE_STD), GPE0_EN(GPE_STD)),
407 gpe0_sts_3_bits);
408}
409
410/* Enable all requested GPE */
411void enable_all_gpe(u32 set1, u32 set2, u32 set3, u32 set4)
412{
413 outl(set1, ACPI_BASE_ADDRESS + GPE0_EN(GPE_31_0));
414 outl(set2, ACPI_BASE_ADDRESS + GPE0_EN(GPE_63_32));
415 outl(set3, ACPI_BASE_ADDRESS + GPE0_EN(GPE_94_64));
416 outl(set4, ACPI_BASE_ADDRESS + GPE0_EN(GPE_STD));
417}
418
419/* Disable all GPE */
420void disable_all_gpe(void)
421{
422 enable_all_gpe(0, 0, 0, 0);
423}
424
425/* Enable a standard GPE */
426void enable_gpe(u32 mask)
427{
428 u32 gpe0_en = inl(ACPI_BASE_ADDRESS + GPE0_EN(GPE_STD));
429 gpe0_en |= mask;
430 outl(gpe0_en, ACPI_BASE_ADDRESS + GPE0_EN(GPE_STD));
431}
432
433/* Disable a standard GPE */
434void disable_gpe(u32 mask)
435{
436 u32 gpe0_en = inl(ACPI_BASE_ADDRESS + GPE0_EN(GPE_STD));
437 gpe0_en &= ~mask;
438 outl(gpe0_en, ACPI_BASE_ADDRESS + GPE0_EN(GPE_STD));
439}
440
441int acpi_sci_irq(void)
442{
Lee Leahy1d14b3e2015-05-12 18:23:27 -0700443 int scis = pci_read_config32(PCH_DEV_PMC, ACTL) & SCI_IRQ_SEL;
Lee Leahyb0005132015-05-12 18:19:47 -0700444 int sci_irq = 9;
445
446 /* Determine how SCI is routed. */
447 switch (scis) {
448 case SCIS_IRQ9:
449 case SCIS_IRQ10:
450 case SCIS_IRQ11:
451 sci_irq = scis - SCIS_IRQ9 + 9;
452 break;
453 case SCIS_IRQ20:
454 case SCIS_IRQ21:
455 case SCIS_IRQ22:
456 case SCIS_IRQ23:
457 sci_irq = scis - SCIS_IRQ20 + 20;
458 break;
459 default:
460 printk(BIOS_DEBUG, "Invalid SCI route! Defaulting to IRQ9.\n");
461 sci_irq = 9;
462 break;
463 }
464
465 printk(BIOS_DEBUG, "SCI is IRQ%d\n", sci_irq);
466 return sci_irq;
467}
Lee Leahy1d14b3e2015-05-12 18:23:27 -0700468
469uint8_t *pmc_mmio_regs(void)
470{
471 uint32_t reg32;
472
473 reg32 = pci_read_config32(PCH_DEV_PMC, PWRMBASE);
474
475 /* 4KiB alignment. */
476 reg32 &= ~0xfff;
477
478 return (void *)(uintptr_t)reg32;
479}
480
481uint16_t pmc_tco_regs(void)
482{
483 uint16_t reg16;
484
485 reg16 = pci_read_config16(PCH_DEV_SMBUS, TCOBASE);
486
487 reg16 &= ~0x1f;
488
489 return reg16;
490}