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 | ␉{␊ |
146 | ␉␉if ((lpc_controllers_nvidia[i].vendor == lpc_dev->vendor_id) && (lpc_controllers_nvidia[i].device == lpc_dev->device_id))␊ |
147 | ␉␉{␊ |
148 | ␊ |
149 | ␉␉␉rcba = (void *)(pci_config_read32(lpc_dev->dev.addr, 0xF0) & 0xFFFFC000);␊ |
150 | ␊ |
151 | ␉␉␉DBG("nVidia(R) %s LPC Interface [%04x:%04x], MMIO @ 0x%lx\n", ␊ |
152 | ␉␉␉␉lpc_controllers_nvidia[i].name, lpc_dev->vendor_id, lpc_dev->device_id, rcba);␊ |
153 | ␊ |
154 | ␉␉␉if (rcba == 0)␊ |
155 | ␉␉␉{␊ |
156 | ␉␉␉␉printf(" RCBA disabled; cannot force enable HPET\n");␊ |
157 | ␉␉␉}␊ |
158 | ␉␉␉else␊ |
159 | ␉␉␉{␊ |
160 | ␉␉␉␉val = REG32(rcba, 0x3404);␊ |
161 | ␉␉␉␉if (val & 0x80)␊ |
162 | ␉␉␉␉{␊ |
163 | ␉␉␉␉␉// HPET is enabled in HPTC. Just not reported by BIOS␊ |
164 | ␉␉␉␉␉DBG(" HPET is enabled in HPTC, just not reported by BIOS\n");␊ |
165 | ␉␉␉␉␉hpet_address |= (val & 3) << 12 ;␊ |
166 | ␉␉␉␉␉DBG(" HPET MMIO @ 0x%lx\n", hpet_address);␊ |
167 | ␉␉␉␉}␊ |
168 | ␉␉␉␉else␊ |
169 | ␉␉␉␉{␊ |
170 | ␉␉␉␉␉// HPET disabled in HPTC. Trying to enable␊ |
171 | ␉␉␉␉␉DBG(" HPET is disabled in HPTC, trying to enable\n");␉␉␉␉␉␉␉␉␉␊ |
172 | ␉␉␉␉␉REG32(rcba, 0x3404) = val | 0x80;␊ |
173 | ␉␉␉␉␉hpet_address |= (val & 3) << 12 ;␊ |
174 | ␉␉␉␉␉DBG(" Force enabled HPET, MMIO @ 0x%lx\n", hpet_address);␊ |
175 | ␉␉␉␉}␊ |
176 | ␊ |
177 | ␉␉␉␉// verify if the job is done␊ |
178 | ␉␉␉␉val = REG32(rcba, 0x3404);␊ |
179 | ␉␉␉␉if (!(val & 0x80))␊ |
180 | ␉␉␉␉{␊ |
181 | ␉␉␉␉␉printf(" Failed to force enable HPET\n");␊ |
182 | ␉␉␉␉}␊ |
183 | ␉␉␉}␊ |
184 | ␉␉␉break;␊ |
185 | ␉␉}␊ |
186 | ␉}␊ |
187 | }␊ |
188 | ␊ |
189 | void force_enable_hpet_via(pci_dt_t *lpc_dev)␊ |
190 | {␊ |
191 | ␉uint32_t␉val, hpet_address = 0xFED00000;␊ |
192 | ␉int i;␊ |
193 | ␊ |
194 | ␉for(i = 1; i < sizeof(lpc_controllers_via) / sizeof(lpc_controllers_via[0]); i++)␊ |
195 | ␉{␊ |
196 | ␉␉if ((lpc_controllers_via[i].vendor == lpc_dev->vendor_id) && (lpc_controllers_via[i].device == lpc_dev->device_id))␊ |
197 | ␉␉{␊ |
198 | ␉␉␉val = pci_config_read32(lpc_dev->dev.addr, 0x68);␊ |
199 | ␊ |
200 | ␉␉␉DBG("VIA %s LPC Interface [%04x:%04x], MMIO\n", ␊ |
201 | ␉␉␉␉lpc_controllers_via[i].name, lpc_dev->vendor_id, lpc_dev->device_id);␊ |
202 | ␊ |
203 | ␉␉␉if (val & 0x80)␊ |
204 | ␉␉␉{␊ |
205 | ␉␉␉␉hpet_address = (val & ~0x3ff);␊ |
206 | ␉␉␉␉DBG("HPET at 0x%lx\n", hpet_address);␊ |
207 | ␉␉␉}␊ |
208 | ␉␉␉else␊ |
209 | ␉␉␉{␊ |
210 | ␉␉␉␉val = 0xfed00000 | 0x80;␊ |
211 | ␉␉␉␉pci_config_write32(lpc_dev->dev.addr, 0x68, val);␊ |
212 | ␉␉␉␉val = pci_config_read32(lpc_dev->dev.addr, 0x68);␊ |
213 | ␉␉␉␉if (val & 0x80)␊ |
214 | ␉␉␉␉{␊ |
215 | ␉␉␉␉␉hpet_address = (val & ~0x3ff);␊ |
216 | ␉␉␉␉␉DBG("Force enabled HPET at 0x%lx\n", hpet_address);␊ |
217 | ␉␉␉␉}␊ |
218 | ␉␉␉␉else␊ |
219 | ␉␉␉␉{␊ |
220 | ␉␉␉␉␉DBG("Unable to enable HPET");␊ |
221 | ␉␉␉␉}␊ |
222 | ␉␉␉}␊ |
223 | ␉␉}␊ |
224 | ␉}␊ |
225 | }␊ |
226 | ␊ |
227 | void force_enable_hpet_intel(pci_dt_t *lpc_dev)␊ |
228 | {␊ |
229 | ␉uint32_t␉val, hpet_address = 0xFED00000;␊ |
230 | ␉int i;␊ |
231 | ␉void␉␉*rcba;␊ |
232 | ␊ |
233 | ␉/* LPC on Intel ICH is always (?) at 00:1f.0 */␊ |
234 | ␉for(i = 1; i < sizeof(lpc_controllers_intel) / sizeof(lpc_controllers_intel[0]); i++)␊ |
235 | ␉{␊ |
236 | ␉␉if ((lpc_controllers_intel[i].vendor == lpc_dev->vendor_id) && (lpc_controllers_intel[i].device == lpc_dev->device_id))␊ |
237 | ␉␉{␊ |
238 | ␊ |
239 | ␉␉␉rcba = (void *)(pci_config_read32(lpc_dev->dev.addr, 0xF0) & 0xFFFFC000);␊ |
240 | ␊ |
241 | ␉␉␉DBG("Intel(R) %s LPC Interface [%04x:%04x], MMIO @ 0x%lx\n", ␊ |
242 | ␉␉␉␉lpc_controllers_intel[i].name, lpc_dev->vendor_id, lpc_dev->device_id, rcba);␊ |
243 | ␊ |
244 | ␉␉␉if (rcba == 0)␊ |
245 | ␉␉␉{␊ |
246 | ␉␉␉␉printf(" RCBA disabled; cannot force enable HPET\n");␊ |
247 | ␉␉␉}␊ |
248 | ␉␉␉else␊ |
249 | ␉␉␉{␊ |
250 | ␉␉␉␉val = REG32(rcba, 0x3404);␊ |
251 | ␉␉␉␉if (val & 0x80)␊ |
252 | ␉␉␉␉{␊ |
253 | ␉␉␉␉␉// HPET is enabled in HPTC. Just not reported by BIOS␊ |
254 | ␉␉␉␉␉DBG(" HPET is enabled in HPTC, just not reported by BIOS\n");␊ |
255 | ␉␉␉␉␉hpet_address |= (val & 3) << 12 ;␊ |
256 | ␉␉␉␉␉DBG(" HPET MMIO @ 0x%lx\n", hpet_address);␊ |
257 | ␉␉␉␉}␊ |
258 | ␉␉␉␉else␊ |
259 | ␉␉␉␉{␊ |
260 | ␉␉␉␉␉// HPET disabled in HPTC. Trying to enable␊ |
261 | ␉␉␉␉␉DBG(" HPET is disabled in HPTC, trying to enable\n");␉␉␉␉␉␉␉␉␉␊ |
262 | ␉␉␉␉␉REG32(rcba, 0x3404) = val | 0x80;␊ |
263 | ␉␉␉␉␉hpet_address |= (val & 3) << 12 ;␊ |
264 | ␉␉␉␉␉DBG(" Force enabled HPET, MMIO @ 0x%lx\n", hpet_address);␊ |
265 | ␉␉␉␉}␊ |
266 | ␊ |
267 | ␉␉␉␉// verify if the job is done␊ |
268 | ␉␉␉␉val = REG32(rcba, 0x3404);␊ |
269 | ␉␉␉␉if (!(val & 0x80))␊ |
270 | ␉␉␉␉{␊ |
271 | ␉␉␉␉␉printf(" Failed to force enable HPET\n");␊ |
272 | ␉␉␉␉}␊ |
273 | ␉␉␉}␊ |
274 | ␉␉␉break;␊ |
275 | ␉␉}␊ |
276 | ␉}␊ |
277 | }␊ |
278 | ␊ |
279 | void force_enable_hpet(pci_dt_t *lpc_dev)␊ |
280 | {␊ |
281 | ␉switch(lpc_dev->vendor_id)␊ |
282 | ␉{␊ |
283 | ␉␉case 0x8086:␊ |
284 | ␉␉␉force_enable_hpet_intel(lpc_dev);␊ |
285 | ␉␉␉break;␊ |
286 | ␊ |
287 | ␉␉case 0x10de:␊ |
288 | ␉␉␉force_enable_hpet_nvidia(lpc_dev);␊ |
289 | ␉␉␉break;␊ |
290 | ␊ |
291 | ␉␉case 0x1106:␊ |
292 | ␉␉␉force_enable_hpet_via(lpc_dev);␊ |
293 | ␉␉␉break;␊ |
294 | ␉}␊ |
295 | ␊ |
296 | #if DEBUG_HPET␊ |
297 | ␉printf("Press [Enter] to continue...\n");␊ |
298 | ␉getchar();␊ |
299 | #endif␊ |
300 | ␊ |
301 | }␊ |
302 | |