1 | /*␊ |
2 | * Copyright (c) 2009 Evan Lojewski. All rights reserved.␊ |
3 | */␊ |
4 | ␊ |
5 | /*␊ |
6 | * High Precision Event Timer (HPET)␊ |
7 | */␊ |
8 | ␊ |
9 | #include "libsaio.h"␊ |
10 | #include "pci.h"␊ |
11 | #include "hpet.h"␊ |
12 | ␊ |
13 | #ifndef DEBUG_HPET␊ |
14 | #define DEBUG_HPET 0␊ |
15 | #endif␊ |
16 | ␊ |
17 | #if DEBUG_HPET␊ |
18 | #define DBG(x...) printf(x)␊ |
19 | #else␊ |
20 | #define DBG(x...)␊ |
21 | #endif␊ |
22 | ␊ |
23 | void force_enable_hpet_intel(pci_dt_t *lpc_dev);␊ |
24 | void force_enable_hpet_nvidia(pci_dt_t *lpc_dev);␊ |
25 | void force_enable_hpet_via(pci_dt_t *lpc_dev);␊ |
26 | ␊ |
27 | /*␊ |
28 | * Force HPET enabled␊ |
29 | *␊ |
30 | * VIA fix from http://forum.voodooprojects.org/index.php/topic,1596.0.html␊ |
31 | */␊ |
32 | ␊ |
33 | static struct lpc_controller_t lpc_controllers_intel[] = {␊ |
34 | ␊ |
35 | ␉// Default unknown chipset␊ |
36 | ␉{ 0, 0, "" },␊ |
37 | ␊ |
38 | ␉// Intel␊ |
39 | ␉{ 0x8086, 0x24dc, "ICH5" },␊ |
40 | ␉{ 0x8086, 0x2640, "ICH6" },␊ |
41 | ␉{ 0x8086, 0x2641, "ICH6M" },␊ |
42 | ␉{ 0x8086, 0x2670, "631xESB" },␊ |
43 | ␊ |
44 | ␉{ 0x8086, 0x27b0, "ICH7 DH" },␊ |
45 | ␉{ 0x8086, 0x27b8, "ICH7" },␊ |
46 | ␉{ 0x8086, 0x27b9, "ICH7M" },␊ |
47 | ␉{ 0x8086, 0x27bd, "ICH7M DH" },␊ |
48 | ␊ |
49 | ␉{ 0x8086, 0x27bc, "NM10" },␊ |
50 | ␊ |
51 | ␉{ 0x8086, 0x2810, "ICH8R" },␊ |
52 | ␉{ 0x8086, 0x2811, "ICH8M-E" },␊ |
53 | ␉{ 0x8086, 0x2812, "ICH8DH" },␊ |
54 | ␉{ 0x8086, 0x2814, "ICH8DO" },␊ |
55 | ␉{ 0x8086, 0x2815, "ICH8M" },␊ |
56 | ␊ |
57 | ␉{ 0x8086, 0x2912, "ICH9DH" },␊ |
58 | ␉{ 0x8086, 0x2914, "ICH9DO" },␊ |
59 | ␉{ 0x8086, 0x2916, "ICH9R" },␊ |
60 | ␉{ 0x8086, 0x2917, "ICH9M-E" },␊ |
61 | ␉{ 0x8086, 0x2918, "ICH9" },␊ |
62 | ␉{ 0x8086, 0x2919, "ICH9M" },␊ |
63 | ␊ |
64 | ␉{ 0x8086, 0x3a14, "ICH10DO" },␊ |
65 | ␉{ 0x8086, 0x3a16, "ICH10R" },␊ |
66 | ␉{ 0x8086, 0x3a18, "ICH10" },␊ |
67 | ␉{ 0x8086, 0x3a1a, "ICH10D" },␊ |
68 | ␉{ 0x8086, 0x3b00, "5 Series" },␊ |
69 | ␉{ 0x8086, 0x3b01, "Mobile 5 Series" },␊ |
70 | ␉{ 0x8086, 0x3b02, "5 Series" },␊ |
71 | ␉{ 0x8086, 0x3b09, "Mobile 5 Series" },␊ |
72 | ␊ |
73 | ␉{ 0x8086, 0x1c41, "Mobile SFF 6 Series" },␊ |
74 | ␉{ 0x8086, 0x1c42, "6 Series" },␊ |
75 | ␉{ 0x8086, 0x1c43, "Mobile 6 Series" },␊ |
76 | ␉{ 0x8086, 0x1c44, "Z68" },␊ |
77 | ␉{ 0x8086, 0x1c46, "UM67" },␊ |
78 | ␉{ 0x8086, 0x1c47, "UM67" },␊ |
79 | ␉{ 0x8086, 0x1c49, "HM65" },␊ |
80 | ␉{ 0x8086, 0x1c4a, "H67" },␊ |
81 | ␉{ 0x8086, 0x1c4b, "HM67" },␊ |
82 | ␉{ 0x8086, 0x1c4c, "Q65" },␊ |
83 | ␉{ 0x8086, 0x1c4d, "QS67" },␊ |
84 | ␉{ 0x8086, 0x1c4e, "Q67" },␊ |
85 | ␉{ 0x8086, 0x1c4f, "QM67" },␊ |
86 | ␉{ 0x8086, 0x1c50, "B65" },␊ |
87 | ␉{ 0x8086, 0x1c52, "C202" },␊ |
88 | ␉{ 0x8086, 0x1c54, "C204" },␊ |
89 | ␉{ 0x8086, 0x1c56, "C206" },␊ |
90 | ␉{ 0x8086, 0x1c5c, "H61" },␊ |
91 | ␊ |
92 | ␉{ 0x8086, 0x1c58, "B65" },␊ |
93 | ␉{ 0x8086, 0x1c59, "HM67" },␊ |
94 | ␉{ 0x8086, 0x1c5a, "Q67" },␊ |
95 | ␊ |
96 | //␉{ 0x8086, 0x1dc1, "PATSBURG" },␊ |
97 | ␊ |
98 | ␉{ 0x8086, 0x1e41, "Mobile C216/7 Series" },␊ |
99 | ␉{ 0x8086, 0x1e42, "Mobile 7 Series" },␊ |
100 | ␉{ 0x8086, 0x1e43, "Mobile 7 Series" },␊ |
101 | ␉{ 0x8086, 0x1e44, "Z77" },␊ |
102 | ␉{ 0x8086, 0x1e45, "H71" },␊ |
103 | ␉{ 0x8086, 0x1e46, "Z75" },␊ |
104 | ␉{ 0x8086, 0x1e47, "Q77" },␊ |
105 | ␉{ 0x8086, 0x1e48, "Q75" },␊ |
106 | ␉{ 0x8086, 0x1e49, "B75" },␊ |
107 | ␉{ 0x8086, 0x1e4a, "H77" },␊ |
108 | ␉{ 0x8086, 0x1e4b, "B75" },␊ |
109 | ␊ |
110 | ␉{ 0x8086, 0x8119, "SCH 8119" },␊ |
111 | ␊ |
112 | };␊ |
113 | ␊ |
114 | static struct lpc_controller_t lpc_controllers_nvidia[] = {␊ |
115 | ␊ |
116 | ␉// Default unknown chipset␊ |
117 | ␉{ 0, 0, "" },␊ |
118 | ␊ |
119 | ␉// nVidia␊ |
120 | ␉{ 0x10de, 0x0aac, "MCP79" },␊ |
121 | ␉{ 0x10de, 0x0aae, "MCP79" },␊ |
122 | ␉{ 0x10de, 0x0aaf, "MCP79" },␊ |
123 | ␉{ 0x10de, 0x0d80, "MCP89" },␊ |
124 | ␉{ 0x10de, 0x0d81, "MCP89" },␊ |
125 | ␉{ 0x10de, 0x0d82, "MCP89" },␊ |
126 | ␉{ 0x10de, 0x0d83, "MCP89" },␊ |
127 | ␊ |
128 | };␊ |
129 | ␊ |
130 | static struct lpc_controller_t lpc_controllers_via[] = {␊ |
131 | ␉// Default unknown chipset␊ |
132 | ␉{ 0, 0, "" },␊ |
133 | ␊ |
134 | ␉{ 0x1106, 0x3372, "VT8237S" },␊ |
135 | };␊ |
136 | ␊ |
137 | /* ErmaC add lpc for nVidia */␊ |
138 | void force_enable_hpet_nvidia(pci_dt_t *lpc_dev)␊ |
139 | {␊ |
140 | ␉uint32_t␉val, hpet_address = 0xFED00000;␊ |
141 | ␉int i;␊ |
142 | ␉void␉␉*rcba;␊ |
143 | ␊ |
144 | ␉for(i = 1; i < sizeof(lpc_controllers_nvidia) / sizeof(lpc_controllers_nvidia[0]); i++)␉{␊ |
145 | ␉␉if ((lpc_controllers_nvidia[i].vendor == lpc_dev->vendor_id) && (lpc_controllers_nvidia[i].device == lpc_dev->device_id)) {␊ |
146 | ␊ |
147 | ␉␉␉rcba = (void *)(pci_config_read32(lpc_dev->dev.addr, 0xF0) & 0xFFFFC000);␊ |
148 | ␊ |
149 | ␉␉␉DBG("nVidia(R) %s LPC Interface [%04x:%04x], MMIO @ 0x%lx\n", ␊ |
150 | ␉␉␉␉lpc_controllers_nvidia[i].name, lpc_dev->vendor_id, lpc_dev->device_id, rcba);␊ |
151 | ␊ |
152 | ␉␉␉if (rcba == 0) {␊ |
153 | ␉␉␉␉printf(" RCBA disabled; cannot force enable HPET\n");␊ |
154 | ␉␉␉} else {␊ |
155 | ␉␉␉␉val = REG32(rcba, 0x3404);␊ |
156 | ␉␉␉␉if (val & 0x80) {␊ |
157 | ␉␉␉␉␉// HPET is enabled in HPTC. Just not reported by BIOS␊ |
158 | ␉␉␉␉␉DBG(" HPET is enabled in HPTC, just not reported by BIOS\n");␊ |
159 | ␉␉␉␉␉hpet_address |= (val & 3) << 12 ;␊ |
160 | ␉␉␉␉␉DBG(" HPET MMIO @ 0x%lx\n", hpet_address);␊ |
161 | ␉␉␉␉} else {␊ |
162 | ␉␉␉␉␉// HPET disabled in HPTC. Trying to enable␊ |
163 | ␉␉␉␉␉DBG(" HPET is disabled in HPTC, trying to enable\n");␉␉␉␉␉␉␉␉␉␊ |
164 | ␉␉␉␉␉REG32(rcba, 0x3404) = val | 0x80;␊ |
165 | ␉␉␉␉␉hpet_address |= (val & 3) << 12 ;␊ |
166 | ␉␉␉␉␉DBG(" Force enabled HPET, MMIO @ 0x%lx\n", hpet_address);␊ |
167 | ␉␉␉␉}␊ |
168 | ␊ |
169 | ␉␉␉␉// verify if the job is done␊ |
170 | ␉␉␉␉val = REG32(rcba, 0x3404);␊ |
171 | ␉␉␉␉if (!(val & 0x80)) {␊ |
172 | ␉␉␉␉␉printf(" Failed to force enable HPET\n");␊ |
173 | ␉␉␉␉}␊ |
174 | ␉␉␉}␊ |
175 | ␉␉␉break;␊ |
176 | ␉␉}␊ |
177 | ␉}␊ |
178 | }␊ |
179 | ␊ |
180 | void force_enable_hpet_via(pci_dt_t *lpc_dev)␊ |
181 | {␊ |
182 | ␉uint32_t␉val, hpet_address = 0xFED00000;␊ |
183 | ␉int i;␊ |
184 | ␊ |
185 | ␉for(i = 1; i < sizeof(lpc_controllers_via) / sizeof(lpc_controllers_via[0]); i++) {␊ |
186 | ␉␉if ((lpc_controllers_via[i].vendor == lpc_dev->vendor_id) && (lpc_controllers_via[i].device == lpc_dev->device_id)) {␊ |
187 | ␉␉␉val = pci_config_read32(lpc_dev->dev.addr, 0x68);␊ |
188 | ␊ |
189 | ␉␉␉DBG("VIA %s LPC Interface [%04x:%04x], MMIO\n", ␊ |
190 | ␉␉␉␉lpc_controllers_via[i].name, lpc_dev->vendor_id, lpc_dev->device_id);␊ |
191 | ␊ |
192 | ␉␉␉if (val & 0x80) {␊ |
193 | ␉␉␉␉hpet_address = (val & ~0x3ff);␊ |
194 | ␉␉␉␉DBG("HPET at 0x%lx\n", hpet_address);␊ |
195 | ␉␉␉} else {␊ |
196 | ␉␉␉␉val = 0xfed00000 | 0x80;␊ |
197 | ␉␉␉␉pci_config_write32(lpc_dev->dev.addr, 0x68, val);␊ |
198 | ␉␉␉␉val = pci_config_read32(lpc_dev->dev.addr, 0x68);␊ |
199 | ␉␉␉␉if (val & 0x80) {␊ |
200 | ␉␉␉␉␉hpet_address = (val & ~0x3ff);␊ |
201 | ␉␉␉␉␉DBG("Force enabled HPET at 0x%lx\n", hpet_address);␊ |
202 | ␉␉␉␉} else {␊ |
203 | ␉␉␉␉␉DBG("Unable to enable HPET");␊ |
204 | ␉␉␉␉}␊ |
205 | ␉␉␉}␊ |
206 | ␉␉}␊ |
207 | ␉}␊ |
208 | }␊ |
209 | ␊ |
210 | void force_enable_hpet_intel(pci_dt_t *lpc_dev)␊ |
211 | {␊ |
212 | ␉uint32_t␉val, hpet_address = 0xFED00000;␊ |
213 | ␉int i;␊ |
214 | ␉void␉␉*rcba;␊ |
215 | ␊ |
216 | ␉/* LPC on Intel ICH is always (?) at 00:1f.0 */␊ |
217 | ␉for(i = 1; i < sizeof(lpc_controllers_intel) / sizeof(lpc_controllers_intel[0]); i++) {␊ |
218 | ␉␉if ((lpc_controllers_intel[i].vendor == lpc_dev->vendor_id) && (lpc_controllers_intel[i].device == lpc_dev->device_id)) {␊ |
219 | ␊ |
220 | ␉␉␉rcba = (void *)(pci_config_read32(lpc_dev->dev.addr, 0xF0) & 0xFFFFC000);␊ |
221 | ␊ |
222 | ␉␉␉DBG("Intel(R) %s LPC Interface [%04x:%04x], MMIO @ 0x%lx\n", ␊ |
223 | ␉␉␉␉lpc_controllers_intel[i].name, lpc_dev->vendor_id, lpc_dev->device_id, rcba);␊ |
224 | ␊ |
225 | ␉␉␉if (rcba == 0) {␊ |
226 | ␉␉␉␉printf(" RCBA disabled; cannot force enable HPET\n");␊ |
227 | ␉␉␉} else {␊ |
228 | ␉␉␉␉val = REG32(rcba, 0x3404);␊ |
229 | ␉␉␉␉if (val & 0x80) {␊ |
230 | ␉␉␉␉␉// HPET is enabled in HPTC. Just not reported by BIOS␊ |
231 | ␉␉␉␉␉DBG(" HPET is enabled in HPTC, just not reported by BIOS\n");␊ |
232 | ␉␉␉␉␉hpet_address |= (val & 3) << 12 ;␊ |
233 | ␉␉␉␉␉DBG(" HPET MMIO @ 0x%lx\n", hpet_address);␊ |
234 | ␉␉␉␉} else {␊ |
235 | ␉␉␉␉␉// HPET disabled in HPTC. Trying to enable␊ |
236 | ␉␉␉␉␉DBG(" HPET is disabled in HPTC, trying to enable\n");␉␉␉␉␉␉␉␉␉␊ |
237 | ␉␉␉␉␉REG32(rcba, 0x3404) = val | 0x80;␊ |
238 | ␉␉␉␉␉hpet_address |= (val & 3) << 12 ;␊ |
239 | ␉␉␉␉␉DBG(" Force enabled HPET, MMIO @ 0x%lx\n", hpet_address);␊ |
240 | ␉␉␉␉}␊ |
241 | ␊ |
242 | ␉␉␉␉// verify if the job is done␊ |
243 | ␉␉␉␉val = REG32(rcba, 0x3404);␊ |
244 | ␉␉␉␉if (!(val & 0x80)) {␊ |
245 | ␉␉␉␉␉printf(" Failed to force enable HPET\n");␊ |
246 | ␉␉␉␉}␊ |
247 | ␉␉␉}␊ |
248 | ␉␉␉break;␊ |
249 | ␉␉}␊ |
250 | ␉}␊ |
251 | }␊ |
252 | ␊ |
253 | void force_enable_hpet(pci_dt_t *lpc_dev)␊ |
254 | {␊ |
255 | ␉switch(lpc_dev->vendor_id) {␊ |
256 | ␉␉case 0x8086:␊ |
257 | ␉␉␉force_enable_hpet_intel(lpc_dev);␊ |
258 | ␉␉␉break;␊ |
259 | ␊ |
260 | ␉␉case 0x10de:␊ |
261 | ␉␉␉force_enable_hpet_nvidia(lpc_dev);␊ |
262 | ␉␉␉break;␊ |
263 | ␊ |
264 | ␉␉case 0x1106:␊ |
265 | ␉␉␉force_enable_hpet_via(lpc_dev);␊ |
266 | ␉␉␉break;␊ |
267 | ␉}␊ |
268 | ␊ |
269 | #if DEBUG_HPET␊ |
270 | ␉printf("Press [Enter] to continue...\n");␊ |
271 | ␉getchar();␊ |
272 | #endif␊ |
273 | ␊ |
274 | }␊ |
275 | |