blob: 0f747348a4305db69f0e59f69f90f1a6d376bcf8 [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
22#include <arch/io.h>
23#include <device/device.h>
24#include <device/pci.h>
25#include <device/pci_def.h>
26#include <console/console.h>
Aaron Durbin38613d02016-07-14 00:56:58 -050027#include <halt.h>
Lee Leahy1d14b3e2015-05-12 18:23:27 -070028#include <stdlib.h>
29#include <soc/gpio.h>
Lee Leahyb0005132015-05-12 18:19:47 -070030#include <soc/iomap.h>
31#include <soc/lpc.h>
32#include <soc/pci_devs.h>
33#include <soc/pm.h>
Lee Leahy1d14b3e2015-05-12 18:23:27 -070034#include <soc/pmc.h>
35#include <soc/smbus.h>
Lee Leahyb0005132015-05-12 18:19:47 -070036
37/* Print status bits with descriptive names */
38static void print_status_bits(u32 status, const char *bit_names[])
39{
40 int i;
41
42 if (!status)
43 return;
44
Lee Leahy1d14b3e2015-05-12 18:23:27 -070045 for (i = 31; i >= 0; i--) {
Lee Leahyb0005132015-05-12 18:19:47 -070046 if (status & (1 << i)) {
47 if (bit_names[i])
48 printk(BIOS_DEBUG, "%s ", bit_names[i]);
49 else
50 printk(BIOS_DEBUG, "BIT%d ", i);
51 }
52 }
53}
54
55/* Print status bits as GPIO numbers */
56static void print_gpio_status(u32 status, int start)
57{
58 int i;
59
60 if (!status)
61 return;
62
Lee Leahy1d14b3e2015-05-12 18:23:27 -070063 for (i = 31; i >= 0; i--) {
Lee Leahyb0005132015-05-12 18:19:47 -070064 if (status & (1 << i))
65 printk(BIOS_DEBUG, "GPIO%d ", start + i);
66 }
67}
68
69
70/*
71 * PM1_CNT
72 */
73
74/* Enable events in PM1 control register */
75void enable_pm1_control(u32 mask)
76{
77 u32 pm1_cnt = inl(ACPI_BASE_ADDRESS + PM1_CNT);
78 pm1_cnt |= mask;
79 outl(pm1_cnt, ACPI_BASE_ADDRESS + PM1_CNT);
80}
81
82/* Disable events in PM1 control register */
83void disable_pm1_control(u32 mask)
84{
85 u32 pm1_cnt = inl(ACPI_BASE_ADDRESS + PM1_CNT);
86 pm1_cnt &= ~mask;
87 outl(pm1_cnt, ACPI_BASE_ADDRESS + PM1_CNT);
88}
89
90
91/*
92 * PM1
93 */
94
95/* Clear and return PM1 status register */
96static u16 reset_pm1_status(void)
97{
98 u16 pm1_sts = inw(ACPI_BASE_ADDRESS + PM1_STS);
99 outw(pm1_sts, ACPI_BASE_ADDRESS + PM1_STS);
100 return pm1_sts;
101}
102
103/* Print PM1 status bits */
104static u16 print_pm1_status(u16 pm1_sts)
105{
106 const char *pm1_sts_bits[] = {
107 [0] = "TMROF",
108 [4] = "BM",
109 [5] = "GBL",
110 [8] = "PWRBTN",
111 [10] = "RTC",
112 [11] = "PRBTNOR",
113 [14] = "PCIEXPWAK",
114 [15] = "WAK",
115 };
116
117 if (!pm1_sts)
118 return 0;
119
120 printk(BIOS_SPEW, "PM1_STS: ");
121 print_status_bits(pm1_sts, pm1_sts_bits);
122 printk(BIOS_SPEW, "\n");
123
124 return pm1_sts;
125}
126
127/* Print, clear, and return PM1 status */
128u16 clear_pm1_status(void)
129{
130 return print_pm1_status(reset_pm1_status());
131}
132
133/* Set the PM1 register to events */
134void enable_pm1(u16 events)
135{
136 outw(events, ACPI_BASE_ADDRESS + PM1_EN);
137}
138
139
140/*
141 * SMI
142 */
143
144/* Clear and return SMI status register */
145static u32 reset_smi_status(void)
146{
147 u32 smi_sts = inl(ACPI_BASE_ADDRESS + SMI_STS);
148 outl(smi_sts, ACPI_BASE_ADDRESS + SMI_STS);
149 return smi_sts;
150}
151
152/* Print SMI status bits */
153static u32 print_smi_status(u32 smi_sts)
154{
155 const char *smi_sts_bits[] = {
156 [2] = "BIOS",
157 [3] = "LEGACY_USB",
158 [4] = "SLP_SMI",
159 [5] = "APM",
160 [6] = "SWSMI_TMR",
161 [8] = "PM1",
162 [9] = "GPE0",
163 [10] = "GPI",
164 [11] = "MCSMI",
165 [12] = "DEVMON",
166 [13] = "TCO",
167 [14] = "PERIODIC",
168 [15] = "SERIRQ_SMI",
169 [16] = "SMBUS_SMI",
170 [17] = "LEGACY_USB2",
171 [18] = "INTEL_USB2",
172 [20] = "PCI_EXP_SMI",
173 [21] = "MONITOR",
174 [26] = "SPI",
175 [27] = "GPIO_UNLOCK"
176 };
177
178 if (!smi_sts)
179 return 0;
180
181 printk(BIOS_DEBUG, "SMI_STS: ");
182 print_status_bits(smi_sts, smi_sts_bits);
183 printk(BIOS_DEBUG, "\n");
184
185 return smi_sts;
186}
187
188/* Print, clear, and return SMI status */
189u32 clear_smi_status(void)
190{
191 return print_smi_status(reset_smi_status());
192}
193
194/* Enable SMI event */
195void enable_smi(u32 mask)
196{
197 u32 smi_en = inl(ACPI_BASE_ADDRESS + SMI_EN);
198 smi_en |= mask;
199 outl(smi_en, ACPI_BASE_ADDRESS + SMI_EN);
200}
201
202/* Disable SMI event */
203void disable_smi(u32 mask)
204{
205 u32 smi_en = inl(ACPI_BASE_ADDRESS + SMI_EN);
206 smi_en &= ~mask;
207 outl(smi_en, ACPI_BASE_ADDRESS + SMI_EN);
208}
209
Lee Leahyb0005132015-05-12 18:19:47 -0700210/*
211 * TCO
212 */
213
214/* Clear TCO status and return events that are enabled and active */
215static u32 reset_tco_status(void)
216{
Lee Leahy1d14b3e2015-05-12 18:23:27 -0700217 u16 tco1_sts;
218 u16 tco2_sts;
219 u16 tcobase;
Lee Leahyb0005132015-05-12 18:19:47 -0700220
Lee Leahy1d14b3e2015-05-12 18:23:27 -0700221 tcobase = pmc_tco_regs();
Lee Leahyb0005132015-05-12 18:19:47 -0700222
Lee Leahy1d14b3e2015-05-12 18:23:27 -0700223 /* TCO Status 2 register*/
224 tco2_sts = inw(tcobase + TCO2_STS);
225 tco2_sts |= (TCO2_STS_SECOND_TO | TCO2_STS_BOOT);
226 outw(tco2_sts, tcobase + TCO2_STS);
Lee Leahyb0005132015-05-12 18:19:47 -0700227
Lee Leahy1d14b3e2015-05-12 18:23:27 -0700228 /* TCO Status 1 register*/
229 tco1_sts = inw(tcobase + TCO1_STS);
230
231 /* Clear SECOND_TO_STS bit */
232 if (tco2_sts & TCO2_STS_SECOND_TO)
233 outw(tco2_sts & ~TCO2_STS_SECOND_TO, tcobase + TCO2_STS);
234
235 return (tco2_sts << 16) | tco1_sts;
Lee Leahyb0005132015-05-12 18:19:47 -0700236}
237
238/* Print TCO status bits */
239static u32 print_tco_status(u32 tco_sts)
240{
241 const char *tco_sts_bits[] = {
242 [0] = "NMI2SMI",
243 [1] = "SW_TCO",
244 [2] = "TCO_INT",
245 [3] = "TIMEOUT",
246 [7] = "NEWCENTURY",
247 [8] = "BIOSWR",
248 [9] = "DMISCI",
249 [10] = "DMISMI",
250 [12] = "DMISERR",
251 [13] = "SLVSEL",
252 [16] = "INTRD_DET",
253 [17] = "SECOND_TO",
254 [18] = "BOOT",
255 [20] = "SMLINK_SLV"
256 };
257
258 if (!tco_sts)
259 return 0;
260
261 printk(BIOS_DEBUG, "TCO_STS: ");
262 print_status_bits(tco_sts, tco_sts_bits);
263 printk(BIOS_DEBUG, "\n");
264
265 return tco_sts;
266}
267
268/* Print, clear, and return TCO status */
269u32 clear_tco_status(void)
270{
271 return print_tco_status(reset_tco_status());
272}
273
274/* Enable TCO SCI */
275void enable_tco_sci(void)
276{
277 /* Clear pending events */
Lee Leahy1d14b3e2015-05-12 18:23:27 -0700278 outl(TCOSCI_STS, ACPI_BASE_ADDRESS + GPE0_STS(3));
Lee Leahyb0005132015-05-12 18:19:47 -0700279
280 /* Enable TCO SCI events */
281 enable_gpe(TCOSCI_EN);
282}
283
284
285/*
286 * GPE0
287 */
288
289/* Clear a GPE0 status and return events that are enabled and active */
290static u32 reset_gpe(u16 sts_reg, u16 en_reg)
291{
292 u32 gpe0_sts = inl(ACPI_BASE_ADDRESS + sts_reg);
293 u32 gpe0_en = inl(ACPI_BASE_ADDRESS + en_reg);
294
295 outl(gpe0_sts, ACPI_BASE_ADDRESS + sts_reg);
296
297 /* Only report enabled events */
298 return gpe0_sts & gpe0_en;
299}
300
301/* Print GPE0 status bits */
302static u32 print_gpe_status(u32 gpe0_sts, const char *bit_names[])
303{
304 if (!gpe0_sts)
305 return 0;
306
307 printk(BIOS_DEBUG, "GPE0_STS: ");
308 print_status_bits(gpe0_sts, bit_names);
309 printk(BIOS_DEBUG, "\n");
310
311 return gpe0_sts;
312}
313
314/* Print GPE0 GPIO status bits */
315static u32 print_gpe_gpio(u32 gpe0_sts, int start)
316{
317 if (!gpe0_sts)
318 return 0;
319
320 printk(BIOS_DEBUG, "GPE0_STS: ");
321 print_gpio_status(gpe0_sts, start);
322 printk(BIOS_DEBUG, "\n");
323
324 return gpe0_sts;
325}
326
327/* Clear all GPE status and return "standard" GPE event status */
328u32 clear_gpe_status(void)
329{
330 const char *gpe0_sts_3_bits[] = {
331 [1] = "HOTPLUG",
332 [2] = "SWGPE",
333 [6] = "TCO_SCI",
334 [7] = "SMB_WAK",
335 [9] = "PCI_EXP",
336 [10] = "BATLOW",
337 [11] = "PME",
338 [12] = "ME",
339 [13] = "PME_B0",
Aaron Durbin7f788492015-07-24 17:10:31 -0500340 [14] = "eSPI",
341 [15] = "GPIO Tier-2",
342 [16] = "LAN_WAKE",
Lee Leahyb0005132015-05-12 18:19:47 -0700343 [18] = "WADT"
344 };
345
346 print_gpe_gpio(reset_gpe(GPE0_STS(GPE_31_0), GPE0_EN(GPE_31_0)), 0);
347 print_gpe_gpio(reset_gpe(GPE0_STS(GPE_63_32), GPE0_EN(GPE_63_32)), 32);
Aaron Durbin7f788492015-07-24 17:10:31 -0500348 print_gpe_gpio(reset_gpe(GPE0_STS(GPE_95_64), GPE0_EN(GPE_95_64)), 64);
Lee Leahyb0005132015-05-12 18:19:47 -0700349 return print_gpe_status(reset_gpe(GPE0_STS(GPE_STD), GPE0_EN(GPE_STD)),
350 gpe0_sts_3_bits);
351}
352
353/* Enable all requested GPE */
354void enable_all_gpe(u32 set1, u32 set2, u32 set3, u32 set4)
355{
356 outl(set1, ACPI_BASE_ADDRESS + GPE0_EN(GPE_31_0));
357 outl(set2, ACPI_BASE_ADDRESS + GPE0_EN(GPE_63_32));
Aaron Durbin7f788492015-07-24 17:10:31 -0500358 outl(set3, ACPI_BASE_ADDRESS + GPE0_EN(GPE_95_64));
Lee Leahyb0005132015-05-12 18:19:47 -0700359 outl(set4, ACPI_BASE_ADDRESS + GPE0_EN(GPE_STD));
360}
361
362/* Disable all GPE */
363void disable_all_gpe(void)
364{
365 enable_all_gpe(0, 0, 0, 0);
366}
367
368/* Enable a standard GPE */
369void enable_gpe(u32 mask)
370{
371 u32 gpe0_en = inl(ACPI_BASE_ADDRESS + GPE0_EN(GPE_STD));
372 gpe0_en |= mask;
373 outl(gpe0_en, ACPI_BASE_ADDRESS + GPE0_EN(GPE_STD));
374}
375
376/* Disable a standard GPE */
377void disable_gpe(u32 mask)
378{
379 u32 gpe0_en = inl(ACPI_BASE_ADDRESS + GPE0_EN(GPE_STD));
380 gpe0_en &= ~mask;
381 outl(gpe0_en, ACPI_BASE_ADDRESS + GPE0_EN(GPE_STD));
382}
383
384int acpi_sci_irq(void)
385{
Lee Leahy1d14b3e2015-05-12 18:23:27 -0700386 int scis = pci_read_config32(PCH_DEV_PMC, ACTL) & SCI_IRQ_SEL;
Lee Leahyb0005132015-05-12 18:19:47 -0700387 int sci_irq = 9;
388
389 /* Determine how SCI is routed. */
390 switch (scis) {
391 case SCIS_IRQ9:
392 case SCIS_IRQ10:
393 case SCIS_IRQ11:
394 sci_irq = scis - SCIS_IRQ9 + 9;
395 break;
396 case SCIS_IRQ20:
397 case SCIS_IRQ21:
398 case SCIS_IRQ22:
399 case SCIS_IRQ23:
400 sci_irq = scis - SCIS_IRQ20 + 20;
401 break;
402 default:
403 printk(BIOS_DEBUG, "Invalid SCI route! Defaulting to IRQ9.\n");
404 sci_irq = 9;
405 break;
406 }
407
408 printk(BIOS_DEBUG, "SCI is IRQ%d\n", sci_irq);
409 return sci_irq;
410}
Lee Leahy1d14b3e2015-05-12 18:23:27 -0700411
412uint8_t *pmc_mmio_regs(void)
413{
414 uint32_t reg32;
415
416 reg32 = pci_read_config32(PCH_DEV_PMC, PWRMBASE);
417
418 /* 4KiB alignment. */
419 reg32 &= ~0xfff;
420
421 return (void *)(uintptr_t)reg32;
422}
423
424uint16_t pmc_tco_regs(void)
425{
426 uint16_t reg16;
427
428 reg16 = pci_read_config16(PCH_DEV_SMBUS, TCOBASE);
429
430 reg16 &= ~0x1f;
431
432 return reg16;
433}
Aaron Durbin38613d02016-07-14 00:56:58 -0500434
435void poweroff(void)
436{
437 enable_pm1_control(SLP_EN | (SLP_TYP_S5 << SLP_TYP_SHIFT));
438 halt();
439}