blob: 9340ba53d28ff3460c035dbec42dac209121b7a7 [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
Alexandru Gagniuca6339802016-04-05 12:40:24 -070018#define __SIMPLE_DEVICE__
19
Hannah Williams01bc8972016-02-04 20:13:34 -080020#include <arch/io.h>
21#include <console/console.h>
22#include <rules.h>
23#include <device/pci_def.h>
24#include <soc/iomap.h>
Alexandru Gagniuca6339802016-04-05 12:40:24 -070025#include <soc/pci_devs.h>
Hannah Williams01bc8972016-02-04 20:13:34 -080026#include <soc/pm.h>
27#include <device/device.h>
28#include <device/pci.h>
Aaron Durbinbef75e72016-05-26 11:00:44 -050029#include <vendorcode/google/chromeos/vboot_common.h>
Hannah Williams01bc8972016-02-04 20:13:34 -080030
Alexandru Gagniuca6339802016-04-05 12:40:24 -070031static uintptr_t read_pmc_mmio_bar(void)
32{
33 uint32_t bar = pci_read_config32(PMC_DEV, PCI_BASE_ADDRESS_0);
34 return bar & ~PCI_BASE_ADDRESS_MEM_ATTR_MASK;
35}
Hannah Williams01bc8972016-02-04 20:13:34 -080036
37static void print_num_status_bits(int num_bits, uint32_t status,
38 const char * const bit_names[])
39{
40 int i;
41
42 if (!status)
43 return;
44
45 for (i = num_bits - 1; i >= 0; i--) {
46 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
55static uint32_t print_smi_status(uint32_t smi_sts)
56{
57 static const char * const smi_sts_bits[] = {
58 [2] = "BIOS",
59 [3] = "LEGACY USB",
60 [4] = "SLP_SMI",
61 [5] = "APM",
62 [6] = "SWSMI_TMR",
63 [10]= "GPIO_SMI",
64 [11]= "GPIO_UNLOCK_SSMI",
65 [12] = "MCSMI",
66 [13] = "TCO",
67 [14] = "PERIODIC",
68 [15] = "SERIRQ",
69 [16] = "SMBUS_SMI",
70 [17] = "XHCI",
71 [18] = "HOST_SMBUS",
72 [19] = "SCS",
73 [20] = "PCI_EXP_SMI",
74 [21] = "SCC2",
75 [25] = "SPI_SSMI",
76 [26] = "SPI",
77 [27] = "OCP_CSE",
78 };
79
80 if (!smi_sts)
81 return 0;
82
83 printk(BIOS_DEBUG, "SMI_STS: ");
84 print_num_status_bits(ARRAY_SIZE(smi_sts_bits), smi_sts, smi_sts_bits);
85 printk(BIOS_DEBUG, "\n");
86
87 return smi_sts;
88}
89
90static uint32_t reset_smi_status(void)
91{
92 uint32_t smi_sts = inl(ACPI_PMIO_BASE + SMI_STS);
93 outl(smi_sts, ACPI_PMIO_BASE + SMI_STS);
94 return smi_sts;
95}
96
97uint32_t clear_smi_status(void)
98{
99 return print_smi_status(reset_smi_status());
100}
101
102uint32_t get_smi_en(void)
103{
104 return inl(ACPI_PMIO_BASE + SMI_EN);
105}
106
107void enable_smi(uint32_t mask)
108{
109 uint32_t smi_en = inl(ACPI_PMIO_BASE + SMI_EN);
110 smi_en |= mask;
111 outl(smi_en, ACPI_PMIO_BASE + SMI_EN);
112}
113
114void disable_smi(uint32_t mask)
115{
116 uint32_t smi_en = inl(ACPI_PMIO_BASE + SMI_EN);
117 smi_en &= ~mask;
118 outl(smi_en, ACPI_PMIO_BASE + SMI_EN);
119}
120
121void enable_pm1_control(uint32_t mask)
122{
123 uint32_t pm1_cnt = inl(ACPI_PMIO_BASE + PM1_CNT);
124 pm1_cnt |= mask;
125 outl(pm1_cnt, ACPI_PMIO_BASE + PM1_CNT);
126}
127
128void disable_pm1_control(uint32_t mask)
129{
130 uint32_t pm1_cnt = inl(ACPI_PMIO_BASE + PM1_CNT);
131 pm1_cnt &= ~mask;
132 outl(pm1_cnt, ACPI_PMIO_BASE + PM1_CNT);
133}
134
135static uint16_t reset_pm1_status(void)
136{
137 uint16_t pm1_sts = inw(ACPI_PMIO_BASE + PM1_STS);
138 outw(pm1_sts, ACPI_PMIO_BASE + PM1_STS);
139 return pm1_sts;
140}
141
142static uint16_t print_pm1_status(uint16_t pm1_sts)
143{
144 static const char * const pm1_sts_bits[] = {
145 [0] = "TMROF",
146 [5] = "GBL",
147 [8] = "PWRBTN",
148 [10] = "RTC",
149 [11] = "PRBTNOR",
150 [13] = "USB",
151 [14] = "PCIEXPWAK",
152 [15] = "WAK",
153 };
154
155 if (!pm1_sts)
156 return 0;
157
158 printk(BIOS_SPEW, "PM1_STS: ");
159 print_num_status_bits(ARRAY_SIZE(pm1_sts_bits), pm1_sts, pm1_sts_bits);
160 printk(BIOS_SPEW, "\n");
161
162 return pm1_sts;
163}
164
165uint16_t clear_pm1_status(void)
166{
167 return print_pm1_status(reset_pm1_status());
168}
169
170void enable_pm1(uint16_t events)
171{
172 outw(events, ACPI_PMIO_BASE + PM1_EN);
173}
174
175static uint32_t print_tco_status(uint32_t tco_sts)
176{
177 static const char * const tco_sts_bits[] = {
178 [3] = "TIMEOUT",
179 [17] = "SECOND_TO",
180 };
181
182 if (!tco_sts)
183 return 0;
184
185 printk(BIOS_DEBUG, "TCO_STS: ");
186 print_num_status_bits(ARRAY_SIZE(tco_sts_bits), tco_sts, tco_sts_bits);
187 printk(BIOS_DEBUG, "\n");
188
189 return tco_sts;
190}
191
192static uint32_t reset_tco_status(void)
193{
194 uint32_t tco_sts = inl(ACPI_PMIO_BASE + TCO_STS);
195 uint32_t tco_en = inl(ACPI_PMIO_BASE + TCO1_CNT);
196
197 outl(tco_sts, ACPI_PMIO_BASE + TCO_STS);
198 return tco_sts & tco_en;
199}
200
201uint32_t clear_tco_status(void)
202{
203 return print_tco_status(reset_tco_status());
204}
205
206void enable_gpe(uint32_t mask)
207{
208 uint32_t gpe0a_en = inl(ACPI_PMIO_BASE + GPE0_EN(0));
209 gpe0a_en |= mask;
210 outl(gpe0a_en, ACPI_PMIO_BASE + GPE0_EN(0));
211}
212
213void disable_gpe(uint32_t mask)
214{
215 uint32_t gpe0a_en = inl(ACPI_PMIO_BASE + GPE0_EN(0));
216 gpe0a_en &= ~mask;
217 outl(gpe0a_en, ACPI_PMIO_BASE + GPE0_EN(0));
218}
219
220void disable_all_gpe(void)
221{
222 disable_gpe(~0);
223}
224
225
226static uint32_t reset_gpe_status(void)
227{
228 uint32_t gpe_sts = inl(ACPI_PMIO_BASE + GPE0_STS(0));
229 outl(gpe_sts, ACPI_PMIO_BASE + GPE0_STS(0));
230 return gpe_sts;
231}
232
233static uint32_t print_gpe_sts(uint32_t gpe_sts)
234{
235 static const char * const gpe_sts_bits[] = {
236 [0] = "PCIE_SCI",
237 [2] = "SWGPE",
238 [3] = "PCIE_WAKE0",
239 [4] = "PUNIT",
240 [6] = "PCIE_WAKE1",
241 [7] = "PCIE_WAKE2",
242 [8] = "PCIE_WAKE3",
243 [9] = "PCI_EXP",
244 [10] = "BATLOW",
245 [11] = "CSE_PME",
246 [12] = "XDCI_PME",
247 [13] = "XHCI_PME",
248 [14] = "AVS_PME",
249 [15] = "GPIO_TIER1_SCI",
250 [16] = "SMB_WAK",
251 [17] = "SATA_PME",
252 };
253
254 if (!gpe_sts)
255 return gpe_sts;
256
257 printk(BIOS_DEBUG, "GPE0a_STS: ");
258 print_num_status_bits(ARRAY_SIZE(gpe_sts_bits), gpe_sts, gpe_sts_bits);
259 printk(BIOS_DEBUG, "\n");
260
261 return gpe_sts;
262}
263
264uint32_t clear_gpe_status(void)
265{
266 return print_gpe_sts(reset_gpe_status());
267}
268
269void clear_pmc_status(void)
270{
271 uint32_t prsts;
272 uint32_t gen_pmcon1;
Alexandru Gagniuca6339802016-04-05 12:40:24 -0700273 uintptr_t pmc_bar0 = read_pmc_mmio_bar();
Hannah Williams01bc8972016-02-04 20:13:34 -0800274
Alexandru Gagniuca6339802016-04-05 12:40:24 -0700275 prsts = read32((void *)(pmc_bar0 + PRSTS));
276 gen_pmcon1 = read32((void *)(pmc_bar0 + GEN_PMCON1));
Hannah Williams01bc8972016-02-04 20:13:34 -0800277
278 /* Clear the status bits. The RPS field is cleared on a 0 write. */
Alexandru Gagniuca6339802016-04-05 12:40:24 -0700279 write32((void *)(pmc_bar0 + GEN_PMCON1), gen_pmcon1 & ~RPS);
280 write32((void *)(pmc_bar0 + PRSTS), prsts);
Hannah Williams01bc8972016-02-04 20:13:34 -0800281}
282
283
284/* Return 0, 3, or 5 to indicate the previous sleep state. */
285int chipset_prev_sleep_state(struct chipset_power_state *ps)
286{
287 /* Default to S0. */
288 int prev_sleep_state = SLEEP_STATE_S0;
289
290 if (ps->pm1_sts & WAK_STS) {
291 switch ((ps->pm1_cnt & SLP_TYP) >> SLP_TYP_SHIFT) {
292#if IS_ENABLED(CONFIG_HAVE_ACPI_RESUME)
293 case SLP_TYP_S3:
294 prev_sleep_state = SLEEP_STATE_S3;
295 break;
296#endif
297 case SLP_TYP_S5:
298 prev_sleep_state = SLEEP_STATE_S5;
299 break;
300 }
301 }
302 return prev_sleep_state;
303}
304
305/* returns prev_sleep_state */
306int fill_power_state(struct chipset_power_state *ps)
307{
308 int i;
Alexandru Gagniuca6339802016-04-05 12:40:24 -0700309 uintptr_t pmc_bar0 = read_pmc_mmio_bar();
310
Hannah Williams01bc8972016-02-04 20:13:34 -0800311 ps->pm1_sts = inw(ACPI_PMIO_BASE + PM1_STS);
312 ps->pm1_en = inw(ACPI_PMIO_BASE + PM1_EN);
313 ps->pm1_cnt = inl(ACPI_PMIO_BASE + PM1_CNT);
314 ps->tco_sts = inl(ACPI_PMIO_BASE + TCO_STS);
Alexandru Gagniuca6339802016-04-05 12:40:24 -0700315 ps->prsts = read32((void *)(pmc_bar0 + PRSTS));
316 ps->gen_pmcon1 =read32((void *)(pmc_bar0 + GEN_PMCON1));
317 ps->gen_pmcon2 = read32((void *)(pmc_bar0 + GEN_PMCON2));
318 ps->gen_pmcon3 = read32((void *)(pmc_bar0 + GEN_PMCON3));
Hannah Williams01bc8972016-02-04 20:13:34 -0800319
320 ps->prev_sleep_state = chipset_prev_sleep_state(ps);
321
322 printk(BIOS_DEBUG, "pm1_sts: %04x pm1_en: %04x pm1_cnt: %08x\n",
323 ps->pm1_sts, ps->pm1_en, ps->pm1_cnt);
324 printk(BIOS_DEBUG, "prsts: %08x tco_sts: %08x\n",
325 ps->prsts, ps->tco_sts);
326 printk(BIOS_DEBUG,
327 "gen_pmcon1: %08x gen_pmcon2: %08x gen_pmcon3: %08x\n",
328 ps->gen_pmcon1, ps->gen_pmcon2, ps->gen_pmcon3);
329 printk(BIOS_DEBUG, "smi_en: %08x smi_sts: %08x\n",
330 inl(ACPI_PMIO_BASE + SMI_EN), inl(ACPI_PMIO_BASE + SMI_STS));
331 for (i=0; i < GPE0_REG_MAX; i++) {
332 ps->gpe0_sts[i] = inl(ACPI_PMIO_BASE + GPE0_STS(i));
333 ps->gpe0_en[i] = inl(ACPI_PMIO_BASE + GPE0_EN(i));
334 printk(BIOS_DEBUG, "gpe0_sts[%d]: %08x gpe0_en[%d]: %08x\n",
335 i, ps->gpe0_sts[i], i, ps->gpe0_en[i]);
336 }
337 printk(BIOS_DEBUG, "prev_sleep_state %d\n", ps->prev_sleep_state);
338 return ps->prev_sleep_state;
339}
Aaron Durbinbef75e72016-05-26 11:00:44 -0500340
341int vboot_platform_is_resuming(void)
342{
343 int typ;
344
345 if (!(inw(ACPI_PMIO_BASE + PM1_STS) & WAK_STS))
346 return 0;
347
348 typ = (inl(ACPI_PMIO_BASE + PM1_CNT) & SLP_TYP) >> SLP_TYP_SHIFT;
349 return typ == SLP_TYP_S3;
350}