blob: 018915c92bd1a7b2d39169f4a8971d9499f59256 [file] [log] [blame]
Lee Leahy77ff0b12015-05-05 15:07:29 -07001/*
2 * This file is part of the coreboot project.
3 *
4 * Copyright (C) 2013 Google Inc.
Lee Leahy32471722015-04-20 15:20:28 -07005 * Copyright (C) 2015 Intel Corp.
Lee Leahy77ff0b12015-05-05 15:07:29 -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 Leahy77ff0b12015-05-05 15:07:29 -070015 */
16
Lee Leahy77ff0b12015-05-05 15:07:29 -070017#include <arch/io.h>
18#include <console/console.h>
Lee Leahyacb9c0b2015-07-02 11:55:18 -070019#include <rules.h>
Lee Leahy77ff0b12015-05-05 15:07:29 -070020#include <soc/iomap.h>
21#include <soc/lpc.h>
22#include <soc/pci_devs.h>
Lee Leahy32471722015-04-20 15:20:28 -070023#include <soc/pm.h>
24#include <stdint.h>
Lee Leahy77ff0b12015-05-05 15:07:29 -070025
Lee Leahyacb9c0b2015-07-02 11:55:18 -070026#if ENV_SMM
Lee Leahy77ff0b12015-05-05 15:07:29 -070027
28static const device_t pcu_dev = PCI_DEV(0, PCU_DEV, 0);
29
30static inline device_t get_pcu_dev(void)
31{
32 return pcu_dev;
33}
34
Lee Leahyacb9c0b2015-07-02 11:55:18 -070035#else /* ENV_SMM */
Lee Leahy77ff0b12015-05-05 15:07:29 -070036#include <device/device.h>
37#include <device/pci.h>
38
39static device_t pcu_dev;
40static device_t get_pcu_dev(void)
41{
42 if (pcu_dev == NULL)
43 pcu_dev = dev_find_slot(0, PCI_DEVFN(PCU_DEV, 0));
44 return pcu_dev;
45}
Lee Leahyacb9c0b2015-07-02 11:55:18 -070046#endif /* ENV_SMM */
Lee Leahy77ff0b12015-05-05 15:07:29 -070047
48uint16_t get_pmbase(void)
49{
50 return pci_read_config16(get_pcu_dev(), ABASE) & 0xfff8;
51}
52
53static void print_num_status_bits(int num_bits, uint32_t status,
Lee Leahy32471722015-04-20 15:20:28 -070054 const char * const bit_names[])
Lee Leahy77ff0b12015-05-05 15:07:29 -070055{
56 int i;
57
58 if (!status)
59 return;
60
61 for (i = num_bits - 1; i >= 0; i--) {
62 if (status & (1 << i)) {
63 if (bit_names[i])
64 printk(BIOS_DEBUG, "%s ", bit_names[i]);
65 else
66 printk(BIOS_DEBUG, "BIT%d ", i);
67 }
68 }
69}
70
Lee Leahy77ff0b12015-05-05 15:07:29 -070071static uint32_t print_smi_status(uint32_t smi_sts)
72{
Lee Leahy32471722015-04-20 15:20:28 -070073 static const char * const smi_sts_bits[] = {
Lee Leahy77ff0b12015-05-05 15:07:29 -070074 [2] = "BIOS",
75 [4] = "SLP_SMI",
76 [5] = "APM",
77 [6] = "SWSMI_TMR",
78 [8] = "PM1",
79 [9] = "GPE0",
80 [12] = "DEVMON",
81 [13] = "TCO",
82 [14] = "PERIODIC",
83 [15] = "ILB",
84 [16] = "SMBUS_SMI",
85 [17] = "LEGACY_USB2",
86 [18] = "INTEL_USB2",
87 [20] = "PCI_EXP_SMI",
88 [26] = "SPI",
89 [28] = "PUNIT",
90 [29] = "GUNIT",
91 };
92
93 if (!smi_sts)
94 return 0;
95
96 printk(BIOS_DEBUG, "SMI_STS: ");
Ravi Sarawadid077b582015-09-09 14:12:16 -070097 print_num_status_bits(30, smi_sts, smi_sts_bits);
Lee Leahy77ff0b12015-05-05 15:07:29 -070098 printk(BIOS_DEBUG, "\n");
99
100 return smi_sts;
101}
102
103static uint32_t reset_smi_status(void)
104{
105 uint16_t pmbase = get_pmbase();
106 uint32_t smi_sts = inl(pmbase + SMI_STS);
107 outl(smi_sts, pmbase + SMI_STS);
108 return smi_sts;
109}
110
111uint32_t clear_smi_status(void)
112{
113 return print_smi_status(reset_smi_status());
114}
115
116void enable_smi(uint32_t mask)
117{
118 uint16_t pmbase = get_pmbase();
119 uint32_t smi_en = inl(pmbase + SMI_EN);
120 smi_en |= mask;
121 outl(smi_en, pmbase + SMI_EN);
122}
123
124void disable_smi(uint32_t mask)
125{
126 uint16_t pmbase = get_pmbase();
127 uint32_t smi_en = inl(pmbase + SMI_EN);
128 smi_en &= ~mask;
129 outl(smi_en, pmbase + SMI_EN);
130}
131
132void enable_pm1_control(uint32_t mask)
133{
134 uint16_t pmbase = get_pmbase();
135 uint32_t pm1_cnt = inl(pmbase + PM1_CNT);
136 pm1_cnt |= mask;
137 outl(pm1_cnt, pmbase + PM1_CNT);
138}
139
140void disable_pm1_control(uint32_t mask)
141{
142 uint16_t pmbase = get_pmbase();
143 uint32_t pm1_cnt = inl(pmbase + PM1_CNT);
144 pm1_cnt &= ~mask;
145 outl(pm1_cnt, pmbase + PM1_CNT);
146}
147
148static uint16_t reset_pm1_status(void)
149{
150 uint16_t pmbase = get_pmbase();
151 uint16_t pm1_sts = inw(pmbase + PM1_STS);
152 outw(pm1_sts, pmbase + PM1_STS);
153 return pm1_sts;
154}
155
156static uint16_t print_pm1_status(uint16_t pm1_sts)
157{
Lee Leahy32471722015-04-20 15:20:28 -0700158 static const char * const pm1_sts_bits[] = {
Lee Leahy77ff0b12015-05-05 15:07:29 -0700159 [0] = "TMROF",
160 [5] = "GBL",
161 [8] = "PWRBTN",
162 [10] = "RTC",
163 [11] = "PRBTNOR",
164 [13] = "USB",
165 [14] = "PCIEXPWAK",
166 [15] = "WAK",
167 };
168
169 if (!pm1_sts)
170 return 0;
171
172 printk(BIOS_SPEW, "PM1_STS: ");
Ravi Sarawadid077b582015-09-09 14:12:16 -0700173 print_num_status_bits(16, pm1_sts, pm1_sts_bits);
Lee Leahy77ff0b12015-05-05 15:07:29 -0700174 printk(BIOS_SPEW, "\n");
175
176 return pm1_sts;
177}
178
179uint16_t clear_pm1_status(void)
180{
181 return print_pm1_status(reset_pm1_status());
182}
183
184void enable_pm1(uint16_t events)
185{
186 outw(events, get_pmbase() + PM1_EN);
187}
188
189static uint32_t print_tco_status(uint32_t tco_sts)
190{
Lee Leahy32471722015-04-20 15:20:28 -0700191 static const char * const tco_sts_bits[] = {
Lee Leahy77ff0b12015-05-05 15:07:29 -0700192 [3] = "TIMEOUT",
193 [17] = "SECOND_TO",
194 };
195
196 if (!tco_sts)
197 return 0;
198
199 printk(BIOS_DEBUG, "TCO_STS: ");
Ravi Sarawadid077b582015-09-09 14:12:16 -0700200 print_num_status_bits(18, tco_sts, tco_sts_bits);
Lee Leahy77ff0b12015-05-05 15:07:29 -0700201 printk(BIOS_DEBUG, "\n");
202
203 return tco_sts;
204}
205
206static uint32_t reset_tco_status(void)
207{
208 uint16_t pmbase = get_pmbase();
209 uint32_t tco_sts = inl(pmbase + TCO_STS);
210 uint32_t tco_en = inl(pmbase + TCO1_CNT);
211
212 outl(tco_sts, pmbase + TCO_STS);
213 return tco_sts & tco_en;
214}
215
216uint32_t clear_tco_status(void)
217{
218 return print_tco_status(reset_tco_status());
219}
220
221void enable_gpe(uint32_t mask)
222{
223 uint16_t pmbase = get_pmbase();
224 uint32_t gpe0_en = inl(pmbase + GPE0_EN);
225 gpe0_en |= mask;
226 outl(gpe0_en, pmbase + GPE0_EN);
227}
228
229void disable_gpe(uint32_t mask)
230{
231 uint16_t pmbase = get_pmbase();
232 uint32_t gpe0_en = inl(pmbase + GPE0_EN);
233 gpe0_en &= ~mask;
234 outl(gpe0_en, pmbase + GPE0_EN);
235}
236
237void disable_all_gpe(void)
238{
239 disable_gpe(~0);
240}
241
242
243static uint32_t reset_gpe_status(void)
244{
245 uint16_t pmbase = get_pmbase();
246 uint32_t gpe_sts = inl(pmbase + GPE0_STS);
247 outl(gpe_sts, pmbase + GPE0_STS);
248 return gpe_sts;
249}
250
251static uint32_t print_gpe_sts(uint32_t gpe_sts)
252{
Lee Leahy32471722015-04-20 15:20:28 -0700253 static const char * const gpe_sts_bits[] = {
Lee Leahy77ff0b12015-05-05 15:07:29 -0700254 [1] = "HOTPLUG",
255 [2] = "SWGPE",
256 [3] = "PCIE_WAKE0",
257 [4] = "PUNIT",
258 [5] = "GUNIT",
259 [6] = "PCIE_WAKE1",
260 [7] = "PCIE_WAKE2",
261 [8] = "PCIE_WAKE3",
262 [9] = "PCI_EXP",
263 [10] = "BATLOW",
264 [13] = "PME_B0",
265 [16] = "SUS_GPIO_0",
266 [17] = "SUS_GPIO_1",
267 [18] = "SUS_GPIO_2",
268 [19] = "SUS_GPIO_3",
269 [20] = "SUS_GPIO_4",
270 [21] = "SUS_GPIO_5",
271 [22] = "SUS_GPIO_6",
272 [23] = "SUS_GPIO_7",
273 [24] = "CORE_GPIO_0",
274 [25] = "CORE_GPIO_1",
275 [26] = "CORE_GPIO_2",
276 [27] = "CORE_GPIO_3",
277 [28] = "CORE_GPIO_4",
278 [29] = "CORE_GPIO_5",
279 [30] = "CORE_GPIO_6",
280 [31] = "CORE_GPIO_7",
281 };
282
283 if (!gpe_sts)
284 return gpe_sts;
285
286 printk(BIOS_DEBUG, "GPE0a_STS: ");
Ravi Sarawadid077b582015-09-09 14:12:16 -0700287 print_num_status_bits(32, gpe_sts, gpe_sts_bits);
Lee Leahy77ff0b12015-05-05 15:07:29 -0700288 printk(BIOS_DEBUG, "\n");
289
290 return gpe_sts;
291}
292
293uint32_t clear_gpe_status(void)
294{
295 return print_gpe_sts(reset_gpe_status());
296}
297
298static uint32_t reset_alt_status(void)
299{
300 uint16_t pmbase = get_pmbase();
301 uint32_t alt_gpio_smi = inl(pmbase + ALT_GPIO_SMI);
302 outl(alt_gpio_smi, pmbase + ALT_GPIO_SMI);
303 return alt_gpio_smi;
304}
305
306static uint32_t print_alt_sts(uint32_t alt_gpio_smi)
307{
308 uint32_t alt_gpio_sts;
Lee Leahy32471722015-04-20 15:20:28 -0700309 static const char * const alt_gpio_smi_sts_bits[] = {
Lee Leahy77ff0b12015-05-05 15:07:29 -0700310 [0] = "SUS_GPIO_0",
311 [1] = "SUS_GPIO_1",
312 [2] = "SUS_GPIO_2",
313 [3] = "SUS_GPIO_3",
314 [4] = "SUS_GPIO_4",
315 [5] = "SUS_GPIO_5",
316 [6] = "SUS_GPIO_6",
317 [7] = "SUS_GPIO_7",
318 [8] = "CORE_GPIO_0",
319 [9] = "CORE_GPIO_1",
320 [10] = "CORE_GPIO_2",
321 [11] = "CORE_GPIO_3",
322 [12] = "CORE_GPIO_4",
323 [13] = "CORE_GPIO_5",
324 [14] = "CORE_GPIO_6",
325 [15] = "CORE_GPIO_7",
326 };
327
328 /* Status bits are in the upper 16 bits. */
329 alt_gpio_sts = alt_gpio_smi >> 16;
330 if (!alt_gpio_sts)
331 return alt_gpio_smi;
332
333 printk(BIOS_DEBUG, "ALT_GPIO_SMI: ");
334 print_num_status_bits(16, alt_gpio_sts, alt_gpio_smi_sts_bits);
335 printk(BIOS_DEBUG, "\n");
336
337 return alt_gpio_smi;
338}
339
340uint32_t clear_alt_status(void)
341{
342 return print_alt_sts(reset_alt_status());
343}
344
345void clear_pmc_status(void)
346{
347 uint32_t prsts;
348 uint32_t gen_pmcon1;
349
Lee Leahy32471722015-04-20 15:20:28 -0700350 prsts = read32((void *)(PMC_BASE_ADDRESS + PRSTS));
351 gen_pmcon1 = read32((void *)(PMC_BASE_ADDRESS + GEN_PMCON1));
Lee Leahy77ff0b12015-05-05 15:07:29 -0700352
353 /* Clear the status bits. The RPS field is cleared on a 0 write. */
Lee Leahy32471722015-04-20 15:20:28 -0700354 write32((void *)(PMC_BASE_ADDRESS + GEN_PMCON1), gen_pmcon1 & ~RPS);
355 write32((void *)(PMC_BASE_ADDRESS + PRSTS), prsts);
Lee Leahy77ff0b12015-05-05 15:07:29 -0700356}