blob: ce822ffa191639eded4a454e5e28b03ca8b00dea [file] [log] [blame]
Hannah Williams01bc8972016-02-04 20:13:34 -08001/*
2 * This file is part of the coreboot project.
3 *
4 * Copyright (C) 2013 Google Inc.
5 * Copyright (C) 2015-2016 Intel Corp.
6 *
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, or (at your option)
10 * any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 */
17
18#include <arch/io.h>
19#include <console/console.h>
20#include <rules.h>
21#include <device/pci_def.h>
22#include <soc/iomap.h>
23#include <soc/pm.h>
24#include <device/device.h>
25#include <device/pci.h>
26
27
28static void print_num_status_bits(int num_bits, uint32_t status,
29 const char * const bit_names[])
30{
31 int i;
32
33 if (!status)
34 return;
35
36 for (i = num_bits - 1; i >= 0; i--) {
37 if (status & (1 << i)) {
38 if (bit_names[i])
39 printk(BIOS_DEBUG, "%s ", bit_names[i]);
40 else
41 printk(BIOS_DEBUG, "BIT%d ", i);
42 }
43 }
44}
45
46static uint32_t print_smi_status(uint32_t smi_sts)
47{
48 static const char * const smi_sts_bits[] = {
49 [2] = "BIOS",
50 [3] = "LEGACY USB",
51 [4] = "SLP_SMI",
52 [5] = "APM",
53 [6] = "SWSMI_TMR",
54 [10]= "GPIO_SMI",
55 [11]= "GPIO_UNLOCK_SSMI",
56 [12] = "MCSMI",
57 [13] = "TCO",
58 [14] = "PERIODIC",
59 [15] = "SERIRQ",
60 [16] = "SMBUS_SMI",
61 [17] = "XHCI",
62 [18] = "HOST_SMBUS",
63 [19] = "SCS",
64 [20] = "PCI_EXP_SMI",
65 [21] = "SCC2",
66 [25] = "SPI_SSMI",
67 [26] = "SPI",
68 [27] = "OCP_CSE",
69 };
70
71 if (!smi_sts)
72 return 0;
73
74 printk(BIOS_DEBUG, "SMI_STS: ");
75 print_num_status_bits(ARRAY_SIZE(smi_sts_bits), smi_sts, smi_sts_bits);
76 printk(BIOS_DEBUG, "\n");
77
78 return smi_sts;
79}
80
81static uint32_t reset_smi_status(void)
82{
83 uint32_t smi_sts = inl(ACPI_PMIO_BASE + SMI_STS);
84 outl(smi_sts, ACPI_PMIO_BASE + SMI_STS);
85 return smi_sts;
86}
87
88uint32_t clear_smi_status(void)
89{
90 return print_smi_status(reset_smi_status());
91}
92
93uint32_t get_smi_en(void)
94{
95 return inl(ACPI_PMIO_BASE + SMI_EN);
96}
97
98void enable_smi(uint32_t mask)
99{
100 uint32_t smi_en = inl(ACPI_PMIO_BASE + SMI_EN);
101 smi_en |= mask;
102 outl(smi_en, ACPI_PMIO_BASE + SMI_EN);
103}
104
105void disable_smi(uint32_t mask)
106{
107 uint32_t smi_en = inl(ACPI_PMIO_BASE + SMI_EN);
108 smi_en &= ~mask;
109 outl(smi_en, ACPI_PMIO_BASE + SMI_EN);
110}
111
112void enable_pm1_control(uint32_t mask)
113{
114 uint32_t pm1_cnt = inl(ACPI_PMIO_BASE + PM1_CNT);
115 pm1_cnt |= mask;
116 outl(pm1_cnt, ACPI_PMIO_BASE + PM1_CNT);
117}
118
119void disable_pm1_control(uint32_t mask)
120{
121 uint32_t pm1_cnt = inl(ACPI_PMIO_BASE + PM1_CNT);
122 pm1_cnt &= ~mask;
123 outl(pm1_cnt, ACPI_PMIO_BASE + PM1_CNT);
124}
125
126static uint16_t reset_pm1_status(void)
127{
128 uint16_t pm1_sts = inw(ACPI_PMIO_BASE + PM1_STS);
129 outw(pm1_sts, ACPI_PMIO_BASE + PM1_STS);
130 return pm1_sts;
131}
132
133static uint16_t print_pm1_status(uint16_t pm1_sts)
134{
135 static const char * const pm1_sts_bits[] = {
136 [0] = "TMROF",
137 [5] = "GBL",
138 [8] = "PWRBTN",
139 [10] = "RTC",
140 [11] = "PRBTNOR",
141 [13] = "USB",
142 [14] = "PCIEXPWAK",
143 [15] = "WAK",
144 };
145
146 if (!pm1_sts)
147 return 0;
148
149 printk(BIOS_SPEW, "PM1_STS: ");
150 print_num_status_bits(ARRAY_SIZE(pm1_sts_bits), pm1_sts, pm1_sts_bits);
151 printk(BIOS_SPEW, "\n");
152
153 return pm1_sts;
154}
155
156uint16_t clear_pm1_status(void)
157{
158 return print_pm1_status(reset_pm1_status());
159}
160
161void enable_pm1(uint16_t events)
162{
163 outw(events, ACPI_PMIO_BASE + PM1_EN);
164}
165
166static uint32_t print_tco_status(uint32_t tco_sts)
167{
168 static const char * const tco_sts_bits[] = {
169 [3] = "TIMEOUT",
170 [17] = "SECOND_TO",
171 };
172
173 if (!tco_sts)
174 return 0;
175
176 printk(BIOS_DEBUG, "TCO_STS: ");
177 print_num_status_bits(ARRAY_SIZE(tco_sts_bits), tco_sts, tco_sts_bits);
178 printk(BIOS_DEBUG, "\n");
179
180 return tco_sts;
181}
182
183static uint32_t reset_tco_status(void)
184{
185 uint32_t tco_sts = inl(ACPI_PMIO_BASE + TCO_STS);
186 uint32_t tco_en = inl(ACPI_PMIO_BASE + TCO1_CNT);
187
188 outl(tco_sts, ACPI_PMIO_BASE + TCO_STS);
189 return tco_sts & tco_en;
190}
191
192uint32_t clear_tco_status(void)
193{
194 return print_tco_status(reset_tco_status());
195}
196
197void enable_gpe(uint32_t mask)
198{
199 uint32_t gpe0a_en = inl(ACPI_PMIO_BASE + GPE0_EN(0));
200 gpe0a_en |= mask;
201 outl(gpe0a_en, ACPI_PMIO_BASE + GPE0_EN(0));
202}
203
204void disable_gpe(uint32_t mask)
205{
206 uint32_t gpe0a_en = inl(ACPI_PMIO_BASE + GPE0_EN(0));
207 gpe0a_en &= ~mask;
208 outl(gpe0a_en, ACPI_PMIO_BASE + GPE0_EN(0));
209}
210
211void disable_all_gpe(void)
212{
213 disable_gpe(~0);
214}
215
216
217static uint32_t reset_gpe_status(void)
218{
219 uint32_t gpe_sts = inl(ACPI_PMIO_BASE + GPE0_STS(0));
220 outl(gpe_sts, ACPI_PMIO_BASE + GPE0_STS(0));
221 return gpe_sts;
222}
223
224static uint32_t print_gpe_sts(uint32_t gpe_sts)
225{
226 static const char * const gpe_sts_bits[] = {
227 [0] = "PCIE_SCI",
228 [2] = "SWGPE",
229 [3] = "PCIE_WAKE0",
230 [4] = "PUNIT",
231 [6] = "PCIE_WAKE1",
232 [7] = "PCIE_WAKE2",
233 [8] = "PCIE_WAKE3",
234 [9] = "PCI_EXP",
235 [10] = "BATLOW",
236 [11] = "CSE_PME",
237 [12] = "XDCI_PME",
238 [13] = "XHCI_PME",
239 [14] = "AVS_PME",
240 [15] = "GPIO_TIER1_SCI",
241 [16] = "SMB_WAK",
242 [17] = "SATA_PME",
243 };
244
245 if (!gpe_sts)
246 return gpe_sts;
247
248 printk(BIOS_DEBUG, "GPE0a_STS: ");
249 print_num_status_bits(ARRAY_SIZE(gpe_sts_bits), gpe_sts, gpe_sts_bits);
250 printk(BIOS_DEBUG, "\n");
251
252 return gpe_sts;
253}
254
255uint32_t clear_gpe_status(void)
256{
257 return print_gpe_sts(reset_gpe_status());
258}
259
260void clear_pmc_status(void)
261{
262 uint32_t prsts;
263 uint32_t gen_pmcon1;
264
265 prsts = read32((void *)(PMC_BAR0 + PRSTS));
266 gen_pmcon1 = read32((void *)(PMC_BAR0 + GEN_PMCON1));
267
268 /* Clear the status bits. The RPS field is cleared on a 0 write. */
269 write32((void *)(PMC_BAR0 + GEN_PMCON1), gen_pmcon1 & ~RPS);
270 write32((void *)(PMC_BAR0 + PRSTS), prsts);
271}
272
273
274/* Return 0, 3, or 5 to indicate the previous sleep state. */
275int chipset_prev_sleep_state(struct chipset_power_state *ps)
276{
277 /* Default to S0. */
278 int prev_sleep_state = SLEEP_STATE_S0;
279
280 if (ps->pm1_sts & WAK_STS) {
281 switch ((ps->pm1_cnt & SLP_TYP) >> SLP_TYP_SHIFT) {
282#if IS_ENABLED(CONFIG_HAVE_ACPI_RESUME)
283 case SLP_TYP_S3:
284 prev_sleep_state = SLEEP_STATE_S3;
285 break;
286#endif
287 case SLP_TYP_S5:
288 prev_sleep_state = SLEEP_STATE_S5;
289 break;
290 }
291 }
292 return prev_sleep_state;
293}
294
295/* returns prev_sleep_state */
296int fill_power_state(struct chipset_power_state *ps)
297{
298 int i;
299 ps->pm1_sts = inw(ACPI_PMIO_BASE + PM1_STS);
300 ps->pm1_en = inw(ACPI_PMIO_BASE + PM1_EN);
301 ps->pm1_cnt = inl(ACPI_PMIO_BASE + PM1_CNT);
302 ps->tco_sts = inl(ACPI_PMIO_BASE + TCO_STS);
303 ps->prsts = read32((void *)(PMC_BAR0 + PRSTS));
304 ps->gen_pmcon1 =read32((void *)(PMC_BAR0 + GEN_PMCON1));
305 ps->gen_pmcon2 = read32((void *)(PMC_BAR0 + GEN_PMCON2));
306 ps->gen_pmcon3 = read32((void *)(PMC_BAR0 + GEN_PMCON3));
307
308 ps->prev_sleep_state = chipset_prev_sleep_state(ps);
309
310 printk(BIOS_DEBUG, "pm1_sts: %04x pm1_en: %04x pm1_cnt: %08x\n",
311 ps->pm1_sts, ps->pm1_en, ps->pm1_cnt);
312 printk(BIOS_DEBUG, "prsts: %08x tco_sts: %08x\n",
313 ps->prsts, ps->tco_sts);
314 printk(BIOS_DEBUG,
315 "gen_pmcon1: %08x gen_pmcon2: %08x gen_pmcon3: %08x\n",
316 ps->gen_pmcon1, ps->gen_pmcon2, ps->gen_pmcon3);
317 printk(BIOS_DEBUG, "smi_en: %08x smi_sts: %08x\n",
318 inl(ACPI_PMIO_BASE + SMI_EN), inl(ACPI_PMIO_BASE + SMI_STS));
319 for (i=0; i < GPE0_REG_MAX; i++) {
320 ps->gpe0_sts[i] = inl(ACPI_PMIO_BASE + GPE0_STS(i));
321 ps->gpe0_en[i] = inl(ACPI_PMIO_BASE + GPE0_EN(i));
322 printk(BIOS_DEBUG, "gpe0_sts[%d]: %08x gpe0_en[%d]: %08x\n",
323 i, ps->gpe0_sts[i], i, ps->gpe0_en[i]);
324 }
325 printk(BIOS_DEBUG, "prev_sleep_state %d\n", ps->prev_sleep_state);
326 return ps->prev_sleep_state;
327}