1 | /*␊ |
2 | * Copyright (c) 2009 Evan Lojewski. All rights reserved.␊ |
3 | *␊ |
4 | */␊ |
5 | ␊ |
6 | #include "libsaio.h"␊ |
7 | #include "modules.h"␊ |
8 | #include "bootstruct.h"␊ |
9 | #include "pci.h"␊ |
10 | #include "hpet.h"␊ |
11 | ␊ |
12 | #ifndef DEBUG_HPET␊ |
13 | #define DEBUG_HPET 0␊ |
14 | #endif␊ |
15 | ␊ |
16 | #if DEBUG_HPET␊ |
17 | #define DBG(x...) printf(x)␊ |
18 | #else␊ |
19 | #define DBG(x...)␊ |
20 | #endif␊ |
21 | ␊ |
22 | static void force_enable_hpet_intel(pci_dt_t *lpc_dev);␊ |
23 | static void force_enable_hpet_via(pci_dt_t *lpc_dev);␊ |
24 | static void force_enable_hpet(pci_dt_t *lpc_dev);␊ |
25 | void HPET_hook(void* arg1, void* arg2, void* arg3, void* arg4, void* arg5, void* arg6);␊ |
26 | ␊ |
27 | void HPET_hook(void* arg1, void* arg2, void* arg3, void* arg4, void* arg5, void* arg6)␊ |
28 | {␊ |
29 | ␉pci_dt_t* current = arg1;␊ |
30 | ␉␊ |
31 | ␉if(current->class_id != PCI_CLASS_BRIDGE_ISA) return;␊ |
32 | ␉␊ |
33 | ␉␊ |
34 | ␉force_enable_hpet(current);␊ |
35 | }␊ |
36 | ␊ |
37 | void HPET_start(void);␊ |
38 | void HPET_start(void)␊ |
39 | {␊ |
40 | ␉␊ |
41 | ␉register_hook_callback("PCIDevice", &HPET_hook);␊ |
42 | }␊ |
43 | ␊ |
44 | /*␊ |
45 | * Force HPET enabled␊ |
46 | *␊ |
47 | * via fix from http://forum.voodooprojects.org/index.php/topic,1596.0.html␊ |
48 | */␊ |
49 | ␊ |
50 | static struct lpc_controller_t lpc_controllers_intel[] = {␊ |
51 | ␉␊ |
52 | ␉// Default unknown chipset␊ |
53 | ␉{ 0, 0, "" },␊ |
54 | ␉␊ |
55 | ␉// Intel␊ |
56 | ␉{ 0x8086, 0x24dc, "ICH5" },␊ |
57 | ␉{ 0x8086, 0x2640, "ICH6" },␊ |
58 | ␉{ 0x8086, 0x2641, "ICH6M" },␊ |
59 | ␉␊ |
60 | ␉{ 0x8086, 0x27b0, "ICH7 DH" },␊ |
61 | ␉{ 0x8086, 0x27b8, "ICH7" },␊ |
62 | ␉{ 0x8086, 0x27b9, "ICH7M" },␊ |
63 | ␉{ 0x8086, 0x27bd, "ICH7M DH" },␊ |
64 | ␊ |
65 | ␉{ 0x8086, 0x27bc, "NM10" },␊ |
66 | ␊ |
67 | ␉{ 0x8086, 0x2810, "ICH8R" },␊ |
68 | ␉{ 0x8086, 0x2811, "ICH8M-E" },␊ |
69 | ␉{ 0x8086, 0x2812, "ICH8DH" },␊ |
70 | ␉{ 0x8086, 0x2814, "ICH8DO" },␊ |
71 | ␉{ 0x8086, 0x2815, "ICH8M" },␊ |
72 | ␉␊ |
73 | ␉{ 0x8086, 0x2912, "ICH9DH" },␊ |
74 | ␉{ 0x8086, 0x2914, "ICH9DO" },␊ |
75 | ␉{ 0x8086, 0x2916, "ICH9R" },␊ |
76 | ␉{ 0x8086, 0x2917, "ICH9M-E" },␊ |
77 | ␉{ 0x8086, 0x2918, "ICH9" },␊ |
78 | ␉{ 0x8086, 0x2919, "ICH9M" },␊ |
79 | ␉␊ |
80 | ␉{ 0x8086, 0x3a14, "ICH10DO" },␊ |
81 | ␉{ 0x8086, 0x3a16, "ICH10R" },␊ |
82 | ␉{ 0x8086, 0x3a18, "ICH10" },␊ |
83 | ␉{ 0x8086, 0x3a1a, "ICH10D" },␊ |
84 | };␊ |
85 | ␊ |
86 | static struct lpc_controller_t lpc_controllers_via[] = {␊ |
87 | ␉// Default unknown chipset␊ |
88 | ␉{ 0, 0, "" },␊ |
89 | ␉␊ |
90 | ␉{ 0x1106, 0x3372, "VT8237S" },␊ |
91 | };␊ |
92 | ␊ |
93 | ␊ |
94 | static void force_enable_hpet(pci_dt_t *lpc_dev)␊ |
95 | {␊ |
96 | ␉switch(lpc_dev->vendor_id)␊ |
97 | ␉{␊ |
98 | ␉␉case 0x8086:␊ |
99 | ␉␉␉force_enable_hpet_intel(lpc_dev);␊ |
100 | ␉␉␉break;␊ |
101 | ␉␉␉␊ |
102 | ␉␉case 0x1106:␊ |
103 | ␉␉␉force_enable_hpet_via(lpc_dev);␊ |
104 | ␉␉␉break;␊ |
105 | ␉␉default:␊ |
106 | ␉␉␉break;␊ |
107 | ␉}␊ |
108 | ␉␊ |
109 | ␉␊ |
110 | #if DEBUG_HPET␊ |
111 | ␉printf("Press [Enter] to continue...\n");␊ |
112 | ␉getc();␊ |
113 | #endif␊ |
114 | }␊ |
115 | ␊ |
116 | static void force_enable_hpet_via(pci_dt_t *lpc_dev)␊ |
117 | {␊ |
118 | ␉uint32_t␉val;␊ |
119 | #if DEBUG_HPET␊ |
120 | uint32_t hpet_address = 0xFED00000;␊ |
121 | #endif␊ |
122 | ␉unsigned int i;␊ |
123 | ␉␊ |
124 | ␉for(i = 1; i < sizeof(lpc_controllers_via) / sizeof(lpc_controllers_via[0]); i++)␊ |
125 | ␉{␊ |
126 | ␉␉if (␉(lpc_controllers_via[i].vendor == lpc_dev->vendor_id) ␊ |
127 | ␉␉␉&& (lpc_controllers_via[i].device == lpc_dev->device_id))␊ |
128 | ␉␉{␉␊ |
129 | ␉␉␉val = pci_config_read32(lpc_dev->dev.addr, 0x68);␊ |
130 | ␉␉␉␊ |
131 | ␉␉␉DBG("VIA %s LPC Interface [%04x:%04x], MMIO\n", ␊ |
132 | ␉␉␉␉lpc_controllers_via[i].name, lpc_dev->vendor_id, lpc_dev->device_id);␊ |
133 | ␉␉␉␊ |
134 | if (val & 0x80)␊ |
135 | ␉␉␉{␊ |
136 | #if DEBUG_HPET␊ |
137 | ␊ |
138 | ␉␉␉␉hpet_address = (val & ~0x3ff);␊ |
139 | ␉␉␉␉DBG("HPET at 0x%lx\n", hpet_address);␊ |
140 | #endif␊ |
141 | ␉␉␉}␊ |
142 | ␉␉␉else ␊ |
143 | ␉␉␉{␊ |
144 | ␉␉␉␉val = 0xfed00000 | 0x80;␊ |
145 | ␉␉␉␉pci_config_write32(lpc_dev->dev.addr, 0x68, val);␊ |
146 | #if DEBUG_HPET␊ |
147 | ␊ |
148 | ␉␉␉␉val = pci_config_read32(lpc_dev->dev.addr, 0x68);␊ |
149 | ␉␉␉␉if (val & 0x80)␊ |
150 | ␉␉␉␉{␊ |
151 | ␉␉␉␉␉hpet_address = (val & ~0x3ff);␊ |
152 | ␉␉␉␉␉DBG("Force enabled HPET at 0x%lx\n", hpet_address);␊ |
153 | ␉␉␉␉}␊ |
154 | ␉␉␉␉else␊ |
155 | ␉␉␉␉{␊ |
156 | ␉␉␉␉␉DBG("Unable to enable HPET");␊ |
157 | ␉␉␉␉}␊ |
158 | #endif␊ |
159 | ␉␉␉}␊ |
160 | ␉␉}␊ |
161 | ␉}␊ |
162 | }␊ |
163 | ␊ |
164 | ␊ |
165 | ␊ |
166 | static void force_enable_hpet_intel(pci_dt_t *lpc_dev)␊ |
167 | {␊ |
168 | ␉uint32_t␉val;␊ |
169 | #if DEBUG_HPET␊ |
170 | uint32_t hpet_address = 0xFED00000;␊ |
171 | #endif␊ |
172 | ␉unsigned int i;␊ |
173 | ␉void␉␉*rcba;␊ |
174 | ␉␊ |
175 | ␉/* LPC on Intel ICH is always (?) at 00:1f.0 */␊ |
176 | ␉for(i = 1; i < sizeof(lpc_controllers_intel) / sizeof(lpc_controllers_intel[0]); i++)␊ |
177 | ␉{␊ |
178 | ␉␉if (␉(lpc_controllers_intel[i].vendor == lpc_dev->vendor_id) ␊ |
179 | ␉␉␉&& (lpc_controllers_intel[i].device == lpc_dev->device_id))␊ |
180 | ␉␉{␉␊ |
181 | ␉␉␉␊ |
182 | ␉␉␉rcba = (void *)(pci_config_read32(lpc_dev->dev.addr, 0xF0) & 0xFFFFC000);␊ |
183 | ␉␉␉␊ |
184 | ␉␉␉DBG("Intel(R) %s LPC Interface [%04x:%04x], MMIO @ 0x%lx\n", ␊ |
185 | ␉␉␉␉lpc_controllers_intel[i].name, lpc_dev->vendor_id, lpc_dev->device_id, rcba);␊ |
186 | ␉␉␉␊ |
187 | ␉␉␉if (rcba == 0)␊ |
188 | ␉␉␉␉DBG(" RCBA disabled; cannot force enable HPET\n");␊ |
189 | ␉␉␉else␊ |
190 | ␉␉␉{␊ |
191 | ␉␉␉␉val = REG32(rcba, 0x3404);␊ |
192 | ␉␉␉␉if (val & 0x80)␊ |
193 | ␉␉␉␉{␊ |
194 | #if DEBUG_HPET␊ |
195 | ␉␉␉␉␉// HPET is enabled in HPTC. Just not reported by BIOS␊ |
196 | ␉␉␉␉␉DBG(" HPET is enabled in HPTC, just not reported by BIOS\n");␊ |
197 | ␉␉␉␉␉hpet_address |= (val & 3) << 12 ;␊ |
198 | ␉␉␉␉␉DBG(" HPET MMIO @ 0x%lx\n", hpet_address);␊ |
199 | #endif␊ |
200 | ␉␉␉␉}␊ |
201 | ␉␉␉␉else␊ |
202 | ␉␉␉␉{ ␊ |
203 | ␉␉␉␉␉// HPET disabled in HPTC. Trying to enable␊ |
204 | ␉␉␉␉␉DBG(" HPET is disabled in HPTC, trying to enable\n");␉␉␉␉␉␉␉␉␉␊ |
205 | ␉␉␉␉␉REG32(rcba, 0x3404) = val | 0x80;␊ |
206 | #if DEBUG_HPET␊ |
207 | ␊ |
208 | ␉␉␉␉␉hpet_address |= (val & 3) << 12 ;␊ |
209 | ␉␉␉␉␉DBG(" Force enabled HPET, MMIO @ 0x%lx\n", hpet_address);␊ |
210 | #endif␊ |
211 | ␉␉␉␉}␊ |
212 | ␉␉␉␉␊ |
213 | ␉␉␉␉␊ |
214 | #if DEBUG_HPET␉␊ |
215 | // verify if the job is done␊ |
216 | ␉␉␉␉val = REG32(rcba, 0x3404);␊ |
217 | ␊ |
218 | ␉␉␉␉if (!(val & 0x80))␊ |
219 | ␉␉␉␉␉printf(" Failed to force enable HPET\n");␊ |
220 | #endif␊ |
221 | /*␊ |
222 | #define HPET_CONFIG 0x10 // General configuration register ␊ |
223 | #define HPET_CNF_LEG_RT 0x00000002␊ |
224 | #define HPET_CNF_ENABLE 0x00000001␊ |
225 | ␊ |
226 | val = REG32(hpet_address, HPET_CONFIG);␊ |
227 | val &= ~HPET_CNF_LEG_RT;␊ |
228 | val |= HPET_CNF_ENABLE;␊ |
229 | REG32(hpet_address, HPET_CONFIG) = val;␊ |
230 | */␊ |
231 | ␉␉␉}␊ |
232 | ␉␉␉break;␊ |
233 | ␉␉␉␊ |
234 | ␉␉}␊ |
235 | ␉}␊ |
236 | } |