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, 0x1c41, "Mobile SFF 6 Series" },␊ |
70 | ␉{ 0x8086, 0x1c42, "6 Series" },␊ |
71 | ␉{ 0x8086, 0x1c43, "Mobile 6 Series" },␊ |
72 | ␉{ 0x8086, 0x1c44, "Z68" },␊ |
73 | ␉{ 0x8086, 0x1c46, "UM67" },␊ |
74 | ␉{ 0x8086, 0x1c47, "UM67" },␊ |
75 | ␉{ 0x8086, 0x1c49, "HM65" },␊ |
76 | ␉{ 0x8086, 0x1c4a, "H67" },␊ |
77 | ␉{ 0x8086, 0x1c4b, "HM67" },␊ |
78 | ␉{ 0x8086, 0x1c4c, "Q65" },␊ |
79 | ␉{ 0x8086, 0x1c4d, "QS67" },␊ |
80 | ␉{ 0x8086, 0x1c4e, "Q67" },␊ |
81 | ␉{ 0x8086, 0x1c4f, "QM67" },␊ |
82 | ␉{ 0x8086, 0x1c50, "B65" },␊ |
83 | ␉{ 0x8086, 0x1c52, "C202" },␊ |
84 | ␉{ 0x8086, 0x1c54, "C204" },␊ |
85 | ␉{ 0x8086, 0x1c56, "C206" },␊ |
86 | ␉{ 0x8086, 0x1c5c, "H61" },␊ |
87 | ␊ |
88 | ␉{ 0x8086, 0x1c58, "B65" },␊ |
89 | ␉{ 0x8086, 0x1c59, "HM67" },␊ |
90 | ␉{ 0x8086, 0x1c5a, "Q67" },␊ |
91 | ␊ |
92 | //␉{ 0x8086, 0x1dc1, "PATSBURG" },␊ |
93 | ␊ |
94 | ␉{ 0x8086, 0x1e41, "Mobile C216/7 Series" },␊ |
95 | ␉{ 0x8086, 0x1e42, "Mobile 7 Series" },␊ |
96 | ␉{ 0x8086, 0x1e43, "Mobile 7 Series" },␊ |
97 | ␉{ 0x8086, 0x1e44, "Z77" },␊ |
98 | ␉{ 0x8086, 0x1e45, "H71" },␊ |
99 | ␉{ 0x8086, 0x1e46, "Z75" },␊ |
100 | ␉{ 0x8086, 0x1e47, "Q77" },␊ |
101 | ␉{ 0x8086, 0x1e48, "Q75" },␊ |
102 | ␉{ 0x8086, 0x1e49, "B75" },␊ |
103 | ␉{ 0x8086, 0x1e4a, "H77" },␊ |
104 | ␉{ 0x8086, 0x1e4b, "B75" },␊ |
105 | ␊ |
106 | ␉{ 0x8086, 0x8119, "SCH 8119" },␊ |
107 | ␊ |
108 | };␊ |
109 | ␊ |
110 | static struct lpc_controller_t lpc_controllers_nvidia[] = {␊ |
111 | ␊ |
112 | ␉// Default unknown chipset␊ |
113 | ␉{ 0, 0, "" },␊ |
114 | ␊ |
115 | ␉// nVidia␊ |
116 | ␉{ 0x10de, 0x0aac, "MCP79" },␊ |
117 | ␉{ 0x10de, 0x0aae, "MCP79" },␊ |
118 | ␉{ 0x10de, 0x0aaf, "MCP79" },␊ |
119 | ␉{ 0x10de, 0x0d80, "MCP89" },␊ |
120 | ␉{ 0x10de, 0x0d81, "MCP89" },␊ |
121 | ␉{ 0x10de, 0x0d82, "MCP89" },␊ |
122 | ␉{ 0x10de, 0x0d83, "MCP89" },␊ |
123 | ␊ |
124 | };␊ |
125 | ␊ |
126 | static struct lpc_controller_t lpc_controllers_via[] = {␊ |
127 | ␉// Default unknown chipset␊ |
128 | ␉{ 0, 0, "" },␊ |
129 | ␊ |
130 | ␉{ 0x1106, 0x3372, "VT8237S" },␊ |
131 | };␊ |
132 | ␊ |
133 | /* ErmaC add lpc for nVidia */␊ |
134 | void force_enable_hpet_nvidia(pci_dt_t *lpc_dev)␊ |
135 | {␊ |
136 | ␉uint32_t␉val, hpet_address = 0xFED00000;␊ |
137 | ␉int i;␊ |
138 | ␉void␉␉*rcba;␊ |
139 | ␊ |
140 | ␉for(i = 1; i < sizeof(lpc_controllers_nvidia) / sizeof(lpc_controllers_nvidia[0]); i++)␉{␊ |
141 | ␉␉if ((lpc_controllers_nvidia[i].vendor == lpc_dev->vendor_id) && (lpc_controllers_nvidia[i].device == lpc_dev->device_id)) {␊ |
142 | ␊ |
143 | ␉␉␉rcba = (void *)(pci_config_read32(lpc_dev->dev.addr, 0xF0) & 0xFFFFC000);␊ |
144 | ␊ |
145 | ␉␉␉DBG("nVidia(R) %s LPC Interface [%04x:%04x], MMIO @ 0x%lx\n", ␊ |
146 | ␉␉␉␉lpc_controllers_nvidia[i].name, lpc_dev->vendor_id, lpc_dev->device_id, rcba);␊ |
147 | ␊ |
148 | ␉␉␉if (rcba == 0) {␊ |
149 | ␉␉␉␉printf(" RCBA disabled; cannot force enable HPET\n");␊ |
150 | ␉␉␉} else {␊ |
151 | ␉␉␉␉val = REG32(rcba, 0x3404);␊ |
152 | ␉␉␉␉if (val & 0x80) {␊ |
153 | ␉␉␉␉␉// HPET is enabled in HPTC. Just not reported by BIOS␊ |
154 | ␉␉␉␉␉DBG(" HPET is enabled in HPTC, just not reported by BIOS\n");␊ |
155 | ␉␉␉␉␉hpet_address |= (val & 3) << 12 ;␊ |
156 | ␉␉␉␉␉DBG(" HPET MMIO @ 0x%lx\n", hpet_address);␊ |
157 | ␉␉␉␉} else {␊ |
158 | ␉␉␉␉␉// HPET disabled in HPTC. Trying to enable␊ |
159 | ␉␉␉␉␉DBG(" HPET is disabled in HPTC, trying to enable\n");␉␉␉␉␉␉␉␉␉␊ |
160 | ␉␉␉␉␉REG32(rcba, 0x3404) = val | 0x80;␊ |
161 | ␉␉␉␉␉hpet_address |= (val & 3) << 12 ;␊ |
162 | ␉␉␉␉␉DBG(" Force enabled HPET, MMIO @ 0x%lx\n", hpet_address);␊ |
163 | ␉␉␉␉}␊ |
164 | ␊ |
165 | ␉␉␉␉// verify if the job is done␊ |
166 | ␉␉␉␉val = REG32(rcba, 0x3404);␊ |
167 | ␉␉␉␉if (!(val & 0x80)) {␊ |
168 | ␉␉␉␉␉printf(" Failed to force enable HPET\n");␊ |
169 | ␉␉␉␉}␊ |
170 | ␉␉␉}␊ |
171 | ␉␉␉break;␊ |
172 | ␉␉}␊ |
173 | ␉}␊ |
174 | }␊ |
175 | ␊ |
176 | void force_enable_hpet_via(pci_dt_t *lpc_dev)␊ |
177 | {␊ |
178 | ␉uint32_t␉val, hpet_address = 0xFED00000;␊ |
179 | ␉int i;␊ |
180 | ␊ |
181 | ␉for(i = 1; i < sizeof(lpc_controllers_via) / sizeof(lpc_controllers_via[0]); i++) {␊ |
182 | ␉␉if ((lpc_controllers_via[i].vendor == lpc_dev->vendor_id) && (lpc_controllers_via[i].device == lpc_dev->device_id)) {␊ |
183 | ␉␉␉val = pci_config_read32(lpc_dev->dev.addr, 0x68);␊ |
184 | ␊ |
185 | ␉␉␉DBG("VIA %s LPC Interface [%04x:%04x], MMIO\n", ␊ |
186 | ␉␉␉␉lpc_controllers_via[i].name, lpc_dev->vendor_id, lpc_dev->device_id);␊ |
187 | ␊ |
188 | ␉␉␉if (val & 0x80) {␊ |
189 | ␉␉␉␉hpet_address = (val & ~0x3ff);␊ |
190 | ␉␉␉␉DBG("HPET at 0x%lx\n", hpet_address);␊ |
191 | ␉␉␉} else {␊ |
192 | ␉␉␉␉val = 0xfed00000 | 0x80;␊ |
193 | ␉␉␉␉pci_config_write32(lpc_dev->dev.addr, 0x68, val);␊ |
194 | ␉␉␉␉val = pci_config_read32(lpc_dev->dev.addr, 0x68);␊ |
195 | ␉␉␉␉if (val & 0x80) {␊ |
196 | ␉␉␉␉␉hpet_address = (val & ~0x3ff);␊ |
197 | ␉␉␉␉␉DBG("Force enabled HPET at 0x%lx\n", hpet_address);␊ |
198 | ␉␉␉␉} else {␊ |
199 | ␉␉␉␉␉DBG("Unable to enable HPET");␊ |
200 | ␉␉␉␉}␊ |
201 | ␉␉␉}␊ |
202 | ␉␉}␊ |
203 | ␉}␊ |
204 | }␊ |
205 | ␊ |
206 | void force_enable_hpet_intel(pci_dt_t *lpc_dev)␊ |
207 | {␊ |
208 | ␉uint32_t␉val, hpet_address = 0xFED00000;␊ |
209 | ␉int i;␊ |
210 | ␉void␉␉*rcba;␊ |
211 | ␊ |
212 | ␉/* LPC on Intel ICH is always (?) at 00:1f.0 */␊ |
213 | ␉for(i = 1; i < sizeof(lpc_controllers_intel) / sizeof(lpc_controllers_intel[0]); i++) {␊ |
214 | ␉␉if ((lpc_controllers_intel[i].vendor == lpc_dev->vendor_id) && (lpc_controllers_intel[i].device == lpc_dev->device_id)) {␊ |
215 | ␊ |
216 | ␉␉␉rcba = (void *)(pci_config_read32(lpc_dev->dev.addr, 0xF0) & 0xFFFFC000);␊ |
217 | ␊ |
218 | ␉␉␉DBG("Intel(R) %s LPC Interface [%04x:%04x], MMIO @ 0x%lx\n", ␊ |
219 | ␉␉␉␉lpc_controllers_intel[i].name, lpc_dev->vendor_id, lpc_dev->device_id, rcba);␊ |
220 | ␊ |
221 | ␉␉␉if (rcba == 0) {␊ |
222 | ␉␉␉␉printf(" RCBA disabled; cannot force enable HPET\n");␊ |
223 | ␉␉␉} else {␊ |
224 | ␉␉␉␉val = REG32(rcba, 0x3404);␊ |
225 | ␉␉␉␉if (val & 0x80) {␊ |
226 | ␉␉␉␉␉// HPET is enabled in HPTC. Just not reported by BIOS␊ |
227 | ␉␉␉␉␉DBG(" HPET is enabled in HPTC, just not reported by BIOS\n");␊ |
228 | ␉␉␉␉␉hpet_address |= (val & 3) << 12 ;␊ |
229 | ␉␉␉␉␉DBG(" HPET MMIO @ 0x%lx\n", hpet_address);␊ |
230 | ␉␉␉␉} else {␊ |
231 | ␉␉␉␉␉// HPET disabled in HPTC. Trying to enable␊ |
232 | ␉␉␉␉␉DBG(" HPET is disabled in HPTC, trying to enable\n");␉␉␉␉␉␉␉␉␉␊ |
233 | ␉␉␉␉␉REG32(rcba, 0x3404) = val | 0x80;␊ |
234 | ␉␉␉␉␉hpet_address |= (val & 3) << 12 ;␊ |
235 | ␉␉␉␉␉DBG(" Force enabled HPET, MMIO @ 0x%lx\n", hpet_address);␊ |
236 | ␉␉␉␉}␊ |
237 | ␊ |
238 | ␉␉␉␉// verify if the job is done␊ |
239 | ␉␉␉␉val = REG32(rcba, 0x3404);␊ |
240 | ␉␉␉␉if (!(val & 0x80)) {␊ |
241 | ␉␉␉␉␉printf(" Failed to force enable HPET\n");␊ |
242 | ␉␉␉␉}␊ |
243 | ␉␉␉}␊ |
244 | ␉␉␉break;␊ |
245 | ␉␉}␊ |
246 | ␉}␊ |
247 | }␊ |
248 | ␊ |
249 | void force_enable_hpet(pci_dt_t *lpc_dev)␊ |
250 | {␊ |
251 | ␉switch(lpc_dev->vendor_id) {␊ |
252 | ␉␉case 0x8086:␊ |
253 | ␉␉␉force_enable_hpet_intel(lpc_dev);␊ |
254 | ␉␉␉break;␊ |
255 | ␊ |
256 | ␉␉case 0x10de:␊ |
257 | ␉␉␉force_enable_hpet_nvidia(lpc_dev);␊ |
258 | ␉␉␉break;␊ |
259 | ␊ |
260 | ␉␉case 0x1106:␊ |
261 | ␉␉␉force_enable_hpet_via(lpc_dev);␊ |
262 | ␉␉␉break;␊ |
263 | ␉}␊ |
264 | ␊ |
265 | #if DEBUG_HPET␊ |
266 | ␉printf("Press [Enter] to continue...\n");␊ |
267 | ␉getchar();␊ |
268 | #endif␊ |
269 | ␊ |
270 | }␊ |
271 | |