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