blob: 55559315c69708a723e40f58a6c9464cb76780d8 [file] [log] [blame]
Aaron Durbin76c37002012-10-30 09:03:43 -05001/*
2 * This file is part of the coreboot project.
3 *
4 * Copyright (C) 2012 The ChromiumOS Authors. All rights reserved.
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 Durbin76c37002012-10-30 09:03:43 -050014 */
15
16#include <arch/io.h>
17#include <arch/acpi.h>
18#include <console/console.h>
19#include <device/device.h>
20#include <device/pci.h>
21#include <device/pci_ops.h>
22#include <stdint.h>
23#include <string.h>
24#include <elog.h>
25#include "pch.h"
26
Duncan Lauried6040902013-03-08 17:16:37 -080027static void pch_log_standard_gpe(u32 gpe0_sts_reg, u32 gpe0_en_reg)
28{
29 u32 gpe0_en = inl(get_pmbase() + gpe0_en_reg);
30 u32 gpe0_sts = inl(get_pmbase() + gpe0_sts_reg) & gpe0_en;
31
32 /* PME (TODO: determine wake device) */
33 if (gpe0_sts & (1 << 11))
34 elog_add_event_wake(ELOG_WAKE_SOURCE_PME, 0);
35
36 /* Internal PME (TODO: determine wake device) */
37 if (gpe0_sts & (1 << 13))
38 elog_add_event_wake(ELOG_WAKE_SOURCE_PME_INTERNAL, 0);
39
40 /* SMBUS Wake */
41 if (gpe0_sts & (1 << 7))
42 elog_add_event_wake(ELOG_WAKE_SOURCE_SMBUS, 0);
43}
44
45static void pch_log_gpio_gpe(u32 gpe0_sts_reg, u32 gpe0_en_reg, int start)
46{
47 /* GPE Bank 1 is GPIO 0-31 */
48 u32 gpe0_en = inl(get_pmbase() + gpe0_en_reg);
49 u32 gpe0_sts = inl(get_pmbase() + gpe0_sts_reg) & gpe0_en;
50 int i;
51
52 for (i = 0; i <= 31; i++) {
53 if (gpe0_sts & (1 << i))
54 elog_add_event_wake(ELOG_WAKE_SOURCE_GPIO, i + start);
55 }
56}
57
58static void pch_log_gpe(void)
59{
60 int i;
61 u16 pmbase = get_pmbase();
62 u32 gpe0_sts, gpe0_en;
63 int gpe0_high_gpios[] = {
64 [0] = 27,
65 [24] = 17,
66 [25] = 19,
67 [26] = 21,
68 [27] = 22,
69 [28] = 43,
70 [29] = 56,
71 [30] = 57,
72 [31] = 60
73 };
74
75 pch_log_standard_gpe(GPE0_EN, GPE0_STS);
76
77 /* GPIO 0-15 */
78 gpe0_en = inw(pmbase + GPE0_EN + 2);
79 gpe0_sts = inw(pmbase + GPE0_STS + 2) & gpe0_en;
80 for (i = 0; i <= 15; i++) {
81 if (gpe0_sts & (1 << i))
82 elog_add_event_wake(ELOG_WAKE_SOURCE_GPIO, i);
83 }
84
85 /*
86 * Now check and log upper status bits
87 */
88
89 gpe0_en = inl(pmbase + GPE0_EN_2);
90 gpe0_sts = inl(pmbase + GPE0_STS_2) & gpe0_en;
91
92 for (i = 0; i <= 31; i++) {
93 if (!gpe0_high_gpios[i])
94 continue;
95 if (gpe0_sts & (1 << i))
96 elog_add_event_wake(ELOG_WAKE_SOURCE_GPIO,
97 gpe0_high_gpios[i]);
98 }
99}
100
101static void pch_lp_log_gpe(void)
102{
103 /* Standard GPE are in GPE set 4 */
104 pch_log_standard_gpe(LP_GPE0_STS_4, LP_GPE0_EN_4);
105
106 /* Log GPIO events in set 1-3 */
107 pch_log_gpio_gpe(LP_GPE0_STS_1, LP_GPE0_EN_1, 0);
108 pch_log_gpio_gpe(LP_GPE0_STS_2, LP_GPE0_EN_2, 32);
109 pch_log_gpio_gpe(LP_GPE0_STS_3, LP_GPE0_EN_3, 64);
110}
111
Aaron Durbin76c37002012-10-30 09:03:43 -0500112void pch_log_state(void)
113{
114 u16 pm1_sts, gen_pmcon_3, tco2_sts;
Aaron Durbin76c37002012-10-30 09:03:43 -0500115 u8 gen_pmcon_2;
Aaron Durbin76c37002012-10-30 09:03:43 -0500116 struct device *lpc = dev_find_slot(0, PCI_DEVFN(0x1f, 0));
117 if (!lpc)
118 return;
119
Duncan Lauried6040902013-03-08 17:16:37 -0800120 pm1_sts = inw(get_pmbase() + PM1_STS);
121 tco2_sts = inw(get_pmbase() + TCO2_STS);
Aaron Durbin76c37002012-10-30 09:03:43 -0500122 gen_pmcon_2 = pci_read_config8(lpc, GEN_PMCON_2);
123 gen_pmcon_3 = pci_read_config16(lpc, GEN_PMCON_3);
124
125 /* PWR_FLR Power Failure */
126 if (gen_pmcon_2 & (1 << 0))
127 elog_add_event(ELOG_TYPE_POWER_FAIL);
128
129 /* SUS Well Power Failure */
130 if (gen_pmcon_3 & (1 << 14))
131 elog_add_event(ELOG_TYPE_SUS_POWER_FAIL);
132
133 /* SYS_PWROK Failure */
134 if (gen_pmcon_2 & (1 << 1))
135 elog_add_event(ELOG_TYPE_SYS_PWROK_FAIL);
136
137 /* PWROK Failure */
138 if (gen_pmcon_2 & (1 << 0))
139 elog_add_event(ELOG_TYPE_PWROK_FAIL);
140
141 /* Second TCO Timeout */
142 if (tco2_sts & (1 << 1))
143 elog_add_event(ELOG_TYPE_TCO_RESET);
144
145 /* Power Button Override */
146 if (pm1_sts & (1 << 11))
147 elog_add_event(ELOG_TYPE_POWER_BUTTON_OVERRIDE);
148
149 /* System Reset Status (reset button pushed) */
150 if (gen_pmcon_2 & (1 << 4))
151 elog_add_event(ELOG_TYPE_RESET_BUTTON);
152
153 /* General Reset Status */
154 if (gen_pmcon_3 & (1 << 9))
155 elog_add_event(ELOG_TYPE_SYSTEM_RESET);
156
157 /* ACPI Wake */
158 if (pm1_sts & (1 << 15))
159 elog_add_event_byte(ELOG_TYPE_ACPI_WAKE,
Kyösti Mälkkic3ed8862014-06-19 19:50:51 +0300160 acpi_is_wakeup_s3() ? 3 : 5);
Aaron Durbin76c37002012-10-30 09:03:43 -0500161
162 /*
163 * Wake sources
164 */
165
Duncan Lauried6040902013-03-08 17:16:37 -0800166 /* Power Button */
167 if (pm1_sts & (1 << 8))
168 elog_add_event_wake(ELOG_WAKE_SOURCE_PWRBTN, 0);
169
Aaron Durbin76c37002012-10-30 09:03:43 -0500170 /* RTC */
171 if (pm1_sts & (1 << 10))
172 elog_add_event_wake(ELOG_WAKE_SOURCE_RTC, 0);
173
174 /* PCI Express (TODO: determine wake device) */
175 if (pm1_sts & (1 << 14))
176 elog_add_event_wake(ELOG_WAKE_SOURCE_PCIE, 0);
177
Duncan Lauried6040902013-03-08 17:16:37 -0800178 /* GPE */
179 if (pch_is_lp())
180 pch_lp_log_gpe();
181 else
182 pch_log_gpe();
Aaron Durbin76c37002012-10-30 09:03:43 -0500183}