blob: 3759174346692e4f28ee6b52ee948a7cba00481b [file] [log] [blame]
Aaron Durbin7837be62013-10-21 22:32:00 -05001/*
2 * This file is part of the coreboot project.
3 *
4 * Copyright (C) 2013 Google Inc.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; version 2 of the License.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
Aaron Durbin7837be62013-10-21 22:32:00 -050014 */
15
16#include <stdint.h>
17#include <arch/io.h>
18#include <console/console.h>
19
Julius Werner18ea2d32014-10-07 16:42:17 -070020#include <soc/iomap.h>
21#include <soc/lpc.h>
22#include <soc/pci_devs.h>
23#include <soc/pmc.h>
Aaron Durbin7837be62013-10-21 22:32:00 -050024
25#if defined(__SMM__)
26
27static const device_t pcu_dev = PCI_DEV(0, PCU_DEV, 0);
28
29static inline device_t get_pcu_dev(void)
30{
31 return pcu_dev;
32}
33
34#else /* !__SMM__ */
35#include <device/device.h>
36#include <device/pci.h>
37
38static device_t pcu_dev;
39static device_t get_pcu_dev(void)
40{
41 if (pcu_dev == NULL)
42 pcu_dev = dev_find_slot(0, PCI_DEVFN(PCU_DEV, 0));
43 return pcu_dev;
44}
45#endif
46
47uint16_t get_pmbase(void)
48{
49 return pci_read_config16(get_pcu_dev(), ABASE) & 0xfff8;
50}
51
Aaron Durbin9f83e872013-11-11 14:45:27 -060052static void print_num_status_bits(int num_bits, uint32_t status,
53 const char *bit_names[])
Aaron Durbin7837be62013-10-21 22:32:00 -050054{
55 int i;
56
57 if (!status)
58 return;
59
Aaron Durbin9f83e872013-11-11 14:45:27 -060060 for (i = num_bits - 1; i >= 0; i--) {
Aaron Durbin7837be62013-10-21 22:32:00 -050061 if (status & (1 << i)) {
62 if (bit_names[i])
63 printk(BIOS_DEBUG, "%s ", bit_names[i]);
64 else
65 printk(BIOS_DEBUG, "BIT%d ", i);
66 }
67 }
68}
69
Aaron Durbin9f83e872013-11-11 14:45:27 -060070static void print_status_bits(uint32_t status, const char *bit_names[])
71{
72 print_num_status_bits(32, status, bit_names);
73}
74
Aaron Durbin7837be62013-10-21 22:32:00 -050075static uint32_t print_smi_status(uint32_t smi_sts)
76{
77 static const char *smi_sts_bits[] = {
78 [2] = "BIOS",
79 [4] = "SLP_SMI",
80 [5] = "APM",
81 [6] = "SWSMI_TMR",
82 [8] = "PM1",
83 [9] = "GPE0",
84 [12] = "DEVMON",
85 [13] = "TCO",
86 [14] = "PERIODIC",
87 [15] = "ILB",
88 [16] = "SMBUS_SMI",
89 [17] = "LEGACY_USB2",
90 [18] = "INTEL_USB2",
91 [20] = "PCI_EXP_SMI",
92 [26] = "SPI",
93 [28] = "PUNIT",
94 [29] = "GUNIT",
95 };
96
97 if (!smi_sts)
98 return 0;
99
100 printk(BIOS_DEBUG, "SMI_STS: ");
101 print_status_bits(smi_sts, smi_sts_bits);
102 printk(BIOS_DEBUG, "\n");
103
104 return smi_sts;
105}
106
107static uint32_t reset_smi_status(void)
108{
109 uint16_t pmbase = get_pmbase();
110 uint32_t smi_sts = inl(pmbase + SMI_STS);
111 outl(smi_sts, pmbase + SMI_STS);
112 return smi_sts;
113}
114
115uint32_t clear_smi_status(void)
116{
117 return print_smi_status(reset_smi_status());
118}
119
120void enable_smi(uint32_t mask)
121{
122 uint16_t pmbase = get_pmbase();
123 uint32_t smi_en = inl(pmbase + SMI_EN);
124 smi_en |= mask;
125 outl(smi_en, pmbase + SMI_EN);
126}
127
128void disable_smi(uint32_t mask)
129{
130 uint16_t pmbase = get_pmbase();
131 uint32_t smi_en = inl(pmbase + SMI_EN);
132 smi_en &= ~mask;
133 outl(smi_en, pmbase + SMI_EN);
134}
135
136void enable_pm1_control(uint32_t mask)
137{
138 uint16_t pmbase = get_pmbase();
139 uint32_t pm1_cnt = inl(pmbase + PM1_CNT);
140 pm1_cnt |= mask;
141 outl(pm1_cnt, pmbase + PM1_CNT);
142}
143
144void disable_pm1_control(uint32_t mask)
145{
146 uint16_t pmbase = get_pmbase();
147 uint32_t pm1_cnt = inl(pmbase + PM1_CNT);
148 pm1_cnt &= ~mask;
149 outl(pm1_cnt, pmbase + PM1_CNT);
150}
151
152static uint16_t reset_pm1_status(void)
153{
154 uint16_t pmbase = get_pmbase();
155 uint16_t pm1_sts = inw(pmbase + PM1_STS);
156 outw(pm1_sts, pmbase + PM1_STS);
157 return pm1_sts;
158}
159
160static uint16_t print_pm1_status(uint16_t pm1_sts)
161{
162 static const char *pm1_sts_bits[] = {
163 [0] = "TMROF",
164 [5] = "GBL",
165 [8] = "PWRBTN",
166 [10] = "RTC",
167 [11] = "PRBTNOR",
168 [13] = "USB",
169 [14] = "PCIEXPWAK",
170 [15] = "WAK",
171 };
172
173 if (!pm1_sts)
174 return 0;
175
176 printk(BIOS_SPEW, "PM1_STS: ");
177 print_status_bits(pm1_sts, pm1_sts_bits);
178 printk(BIOS_SPEW, "\n");
179
180 return pm1_sts;
181}
182
183uint16_t clear_pm1_status(void)
184{
185 return print_pm1_status(reset_pm1_status());
186}
187
188void enable_pm1(uint16_t events)
189{
190 outw(events, get_pmbase() + PM1_EN);
191}
192
193static uint32_t print_tco_status(uint32_t tco_sts)
194{
195 static const char *tco_sts_bits[] = {
196 [3] = "TIMEOUT",
197 [17] = "SECOND_TO",
198 };
199
200 if (!tco_sts)
201 return 0;
202
203 printk(BIOS_DEBUG, "TCO_STS: ");
204 print_status_bits(tco_sts, tco_sts_bits);
205 printk(BIOS_DEBUG, "\n");
206
207 return tco_sts;
208}
209
210static uint32_t reset_tco_status(void)
211{
212 uint16_t pmbase = get_pmbase();
213 uint32_t tco_sts = inl(pmbase + TCO_STS);
214 uint32_t tco_en = inl(pmbase + TCO1_CNT);
215
216 outl(tco_sts, pmbase + TCO_STS);
217 return tco_sts & tco_en;
218}
219
220uint32_t clear_tco_status(void)
221{
222 return print_tco_status(reset_tco_status());
223}
224
225void enable_gpe(uint32_t mask)
226{
227 uint16_t pmbase = get_pmbase();
228 uint32_t gpe0_en = inl(pmbase + GPE0_EN);
229 gpe0_en |= mask;
230 outl(gpe0_en, pmbase + GPE0_EN);
231}
232
233void disable_gpe(uint32_t mask)
234{
235 uint16_t pmbase = get_pmbase();
236 uint32_t gpe0_en = inl(pmbase + GPE0_EN);
237 gpe0_en &= ~mask;
238 outl(gpe0_en, pmbase + GPE0_EN);
239}
240
241void disable_all_gpe(void)
242{
243 disable_gpe(~0);
244}
245
246
247static uint32_t reset_gpe_status(void)
248{
249 uint16_t pmbase = get_pmbase();
250 uint32_t gpe_sts = inl(pmbase + GPE0_STS);
251 outl(gpe_sts, pmbase + GPE0_STS);
252 return gpe_sts;
253}
254
255static uint32_t print_gpe_sts(uint32_t gpe_sts)
256{
257 static const char *gpe_sts_bits[] = {
258 [1] = "HOTPLUG",
259 [2] = "SWGPE",
260 [3] = "PCIE_WAKE0",
261 [4] = "PUNIT",
262 [5] = "GUNIT",
263 [6] = "PCIE_WAKE1",
264 [7] = "PCIE_WAKE2",
265 [8] = "PCIE_WAKE3",
266 [9] = "PCI_EXP",
267 [10] = "BATLOW",
268 [13] = "PME_B0",
269 [16] = "SUS_GPIO_0",
270 [17] = "SUS_GPIO_1",
271 [18] = "SUS_GPIO_2",
272 [19] = "SUS_GPIO_3",
273 [20] = "SUS_GPIO_4",
274 [21] = "SUS_GPIO_5",
275 [22] = "SUS_GPIO_6",
276 [23] = "SUS_GPIO_7",
277 [24] = "CORE_GPIO_0",
278 [25] = "CORE_GPIO_1",
279 [26] = "CORE_GPIO_2",
280 [27] = "CORE_GPIO_3",
281 [28] = "CORE_GPIO_4",
282 [29] = "CORE_GPIO_5",
283 [30] = "CORE_GPIO_6",
284 [31] = "CORE_GPIO_7",
285 };
286
287 if (!gpe_sts)
288 return gpe_sts;
289
290 printk(BIOS_DEBUG, "GPE0a_STS: ");
291 print_status_bits(gpe_sts, gpe_sts_bits);
292 printk(BIOS_DEBUG, "\n");
293
294 return gpe_sts;
295}
296
297uint32_t clear_gpe_status(void)
298{
299 return print_gpe_sts(reset_gpe_status());
300}
Aaron Durbin9f83e872013-11-11 14:45:27 -0600301
302static uint32_t reset_alt_status(void)
303{
304 uint16_t pmbase = get_pmbase();
305 uint32_t alt_gpio_smi = inl(pmbase + ALT_GPIO_SMI);
306 outl(alt_gpio_smi, pmbase + ALT_GPIO_SMI);
307 return alt_gpio_smi;
308}
309
310static uint32_t print_alt_sts(uint32_t alt_gpio_smi)
311{
312 uint32_t alt_gpio_sts;
313 static const char *alt_gpio_smi_sts_bits[] = {
314 [0] = "SUS_GPIO_0",
315 [1] = "SUS_GPIO_1",
316 [2] = "SUS_GPIO_2",
317 [3] = "SUS_GPIO_3",
318 [4] = "SUS_GPIO_4",
319 [5] = "SUS_GPIO_5",
320 [6] = "SUS_GPIO_6",
321 [7] = "SUS_GPIO_7",
322 [8] = "CORE_GPIO_0",
323 [9] = "CORE_GPIO_1",
324 [10] = "CORE_GPIO_2",
325 [11] = "CORE_GPIO_3",
326 [12] = "CORE_GPIO_4",
327 [13] = "CORE_GPIO_5",
328 [14] = "CORE_GPIO_6",
329 [15] = "CORE_GPIO_7",
330 };
331
332 /* Status bits are in the upper 16 bits. */
333 alt_gpio_sts = alt_gpio_smi >> 16;
334 if (!alt_gpio_sts)
335 return alt_gpio_smi;
336
337 printk(BIOS_DEBUG, "ALT_GPIO_SMI: ");
338 print_num_status_bits(16, alt_gpio_sts, alt_gpio_smi_sts_bits);
339 printk(BIOS_DEBUG, "\n");
340
341 return alt_gpio_smi;
342}
343
344uint32_t clear_alt_status(void)
345{
346 return print_alt_sts(reset_alt_status());
347}
Aaron Durbin19edc3a2014-01-09 11:17:37 -0600348
349void clear_pmc_status(void)
350{
351 uint32_t prsts;
352 uint32_t gen_pmcon1;
353
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800354 prsts = read32((u32 *)(PMC_BASE_ADDRESS + PRSTS));
355 gen_pmcon1 = read32((u32 *)(PMC_BASE_ADDRESS + GEN_PMCON1));
Aaron Durbin19edc3a2014-01-09 11:17:37 -0600356
Shawn Nematbakhsh51d787a2014-01-16 17:52:21 -0800357 /* Clear the status bits. The RPS field is cleared on a 0 write. */
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800358 write32((u32 *)(PMC_BASE_ADDRESS + GEN_PMCON1), gen_pmcon1 & ~RPS);
359 write32((u32 *)(PMC_BASE_ADDRESS + PRSTS), prsts);
Aaron Durbin19edc3a2014-01-09 11:17:37 -0600360}