Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
6084 | serge | 1 | #include |
2 | #include |
||
3 | |||
4 | typedef unsigned int addr_t; |
||
5 | |||
6 | #define ACPI_NAME_SIZE 4 |
||
7 | #define ACPI_OEM_ID_SIZE 6 |
||
8 | #define ACPI_OEM_TABLE_ID_SIZE 8 |
||
9 | |||
10 | #define ACPI_RSDP_CHECKSUM_LENGTH 20 |
||
11 | #define ACPI_RSDP_XCHECKSUM_LENGTH 36 |
||
12 | |||
13 | typedef struct __attribute__((packed)) |
||
14 | { |
||
15 | u32 sig; |
||
16 | u32 len; |
||
17 | u8 rev; |
||
18 | u8 csum; |
||
19 | char oem_id[ACPI_OEM_ID_SIZE]; |
||
20 | char oem_tid[ACPI_OEM_TABLE_ID_SIZE]; |
||
21 | u32 oem_rev; |
||
22 | u32 creator_id; |
||
23 | u32 creator_rev; |
||
24 | }acpi_thead_t; |
||
25 | |||
26 | typedef struct __attribute__((packed)) |
||
27 | { |
||
28 | u8 space_id; /* Address space where struct or register exists */ |
||
29 | u8 bit_width; /* Size in bits of given register */ |
||
30 | u8 bit_offset; /* Bit offset within the register */ |
||
31 | u8 access_width; /* Minimum Access size (ACPI 3.0) */ |
||
32 | u64 address; /* 64-bit address of struct or register */ |
||
33 | }acpi_address_t; |
||
34 | |||
35 | |||
36 | typedef struct __attribute__((packed)) |
||
37 | { |
||
38 | acpi_thead_t header; /* Common ACPI table header */ |
||
39 | u32 id; /* Hardware ID of event timer block */ |
||
40 | acpi_address_t address; /* Address of event timer block */ |
||
41 | u8 sequence; /* HPET sequence number */ |
||
42 | u16 minimum_tick; /* Main counter min tick, periodic mode */ |
||
43 | u8 flags; |
||
44 | }acpi_hpet_t; |
||
45 | |||
46 | typedef struct __attribute__((packed)) |
||
47 | { |
||
48 | acpi_thead_t header; |
||
49 | u32 ptrs[0]; |
||
50 | }acpi_rsdt_t; |
||
51 | |||
52 | typedef struct __attribute__((packed)) |
||
53 | { |
||
54 | acpi_thead_t header; |
||
55 | u64 ptrs[0]; |
||
56 | }acpi_xsdt_t; |
||
57 | |||
58 | typedef struct __attribute__((packed)) |
||
59 | { |
||
60 | u64 sig; |
||
61 | u8 csum; |
||
62 | char oemid[6]; |
||
63 | u8 rev; |
||
64 | u32 rsdt_ptr; |
||
65 | u32 rsdt_len; |
||
66 | u64 xsdt_ptr; |
||
67 | u8 xcsum; |
||
68 | u8 _rsvd_33[3]; |
||
69 | }acpi_rsdp_t; |
||
70 | |||
71 | #define OS_BASE 0x80000000 |
||
72 | #define ACPI20_PC99_RSDP_START (OS_BASE + 0x0e0000) |
||
73 | #define ACPI20_PC99_RSDP_END (OS_BASE + 0x100000) |
||
74 | #define ACPI20_PC99_RSDP_SIZE (ACPI20_PC99_RSDP_END - ACPI20_PC99_RSDP_START) |
||
75 | |||
76 | static acpi_thead_t* (*sdt_find)(void *sdt, u32 sig); |
||
77 | |||
78 | static u8 acpi_tb_checksum (u8 *buffer, u32 len) |
||
79 | { |
||
80 | u8 sum = 0; |
||
81 | u8 *end = buffer + len; |
||
82 | |||
83 | while (buffer < end) |
||
84 | { |
||
85 | sum = (u8)(sum + *(buffer++)); |
||
86 | } |
||
87 | |||
88 | return sum; |
||
89 | } |
||
90 | |||
91 | static acpi_rsdp_t* acpi_locate() |
||
92 | { |
||
93 | addr_t p; |
||
94 | |||
95 | for (p = ACPI20_PC99_RSDP_START; p < ACPI20_PC99_RSDP_END; p+=16) |
||
96 | { |
||
97 | acpi_rsdp_t* r = (acpi_rsdp_t*) p; |
||
98 | if (r->sig != 0x2052545020445352 ) |
||
99 | continue; |
||
100 | |||
101 | if (acpi_tb_checksum ((u8*)r, ACPI_RSDP_CHECKSUM_LENGTH) != 0) |
||
102 | continue; |
||
103 | |||
104 | if ((r->rev >= 2) && |
||
105 | (acpi_tb_checksum ((u8*)r, ACPI_RSDP_XCHECKSUM_LENGTH) != 0)) |
||
106 | continue; |
||
107 | |||
108 | return r; |
||
109 | }; |
||
110 | |||
111 | return NULL; |
||
112 | }; |
||
113 | |||
114 | acpi_thead_t* rsdt_find(acpi_rsdt_t *rsdt, u32 sig) |
||
115 | { |
||
116 | acpi_thead_t *head = NULL; |
||
117 | u32 i; |
||
118 | |||
119 | for (i = 0; i < ((rsdt->header.len-sizeof(acpi_thead_t))/ |
||
120 | sizeof(rsdt->ptrs[0])); i++) |
||
121 | { |
||
122 | u32 ptr = rsdt->ptrs[i]; |
||
123 | |||
124 | acpi_thead_t* t = (acpi_thead_t*)MapIoMem(ptr, 8192, PG_SW); |
||
125 | |||
126 | if (t->sig == sig) |
||
127 | { |
||
128 | head = t; |
||
129 | break; |
||
130 | }; |
||
131 | FreeKernelSpace(t); |
||
132 | } |
||
133 | return head; |
||
134 | }; |
||
135 | |||
136 | acpi_thead_t* xsdt_find(acpi_xsdt_t *xsdt, u32 sig) |
||
137 | { |
||
138 | acpi_thead_t *head = NULL; |
||
139 | u32 i; |
||
140 | |||
141 | for (i = 0; i < ((xsdt->header.len-sizeof(acpi_thead_t))/ |
||
142 | sizeof(xsdt->ptrs[0])); i++) |
||
143 | { |
||
144 | u32 ptr = xsdt->ptrs[i]; |
||
145 | |||
146 | acpi_thead_t* t = (acpi_thead_t*)MapIoMem(ptr, 8192, PG_SW); |
||
147 | |||
148 | if (t->sig == sig) |
||
149 | { |
||
150 | head = t; |
||
151 | break; |
||
152 | }; |
||
153 | FreeKernelSpace(t); |
||
154 | } |
||
155 | return head; |
||
156 | }; |
||
157 | |||
158 | static void dump_rsdt(acpi_rsdt_t *rsdt) |
||
159 | { |
||
160 | int i; |
||
161 | |||
162 | for (i = 0; i < ((rsdt->header.len-sizeof(acpi_thead_t))/ |
||
163 | sizeof(rsdt->ptrs[0])); i++) |
||
164 | { |
||
165 | u32 ptr = rsdt->ptrs[i]; |
||
166 | dbgprintf("%s ptr= %p\n", __FUNCTION__, ptr); |
||
167 | |||
168 | acpi_thead_t* t = (acpi_thead_t*)MapIoMem(ptr, 8192, PG_SW); |
||
169 | dbgprintf("%s t= %x\n", __FUNCTION__, t); |
||
170 | |||
171 | char *p = (char*)&t->sig; |
||
172 | printf("sig %d: %x %c%c%c%c base %p\n", i, t->sig, |
||
173 | p[0],p[1],p[2],p[3],rsdt->ptrs[i]); |
||
174 | FreeKernelSpace(t); |
||
175 | }; |
||
176 | }; |
||
177 | |||
178 | typedef struct |
||
179 | { |
||
180 | u64 hpet_cap; /* capabilities */ |
||
181 | u64 res0; /* reserved */ |
||
182 | u64 hpet_config; /* configuration */ |
||
183 | u64 res1; /* reserved */ |
||
184 | u64 hpet_isr; /* interrupt status reg */ |
||
185 | u64 res2[25]; /* reserved */ |
||
186 | union { /* main counter */ |
||
187 | volatile u64 _hpet_mc64; |
||
188 | u32 _hpet_mc32; |
||
189 | unsigned long _hpet_mc; |
||
190 | } _u0; |
||
191 | u64 res3; /* reserved */ |
||
192 | struct hpet_timer { |
||
193 | u64 hpet_config; /* configuration/cap */ |
||
194 | union { /* timer compare register */ |
||
195 | u64 _hpet_hc64; |
||
196 | u32 _hpet_hc32; |
||
197 | unsigned long _hpet_compare; |
||
198 | } _u1; |
||
199 | u64 hpet_fsb[2]; /* FSB route */ |
||
200 | } hpet_timers[1]; |
||
201 | }hpet_t; |
||
202 | |||
203 | #define HPET_ID 0x000 |
||
204 | #define HPET_PERIOD 0x004 |
||
205 | #define HPET_CFG 0x010 |
||
206 | #define HPET_STATUS 0x020 |
||
207 | #define HPET_COUNTER 0x0f0 |
||
208 | |||
209 | #define HPET_ID_NUMBER 0x00001f00 |
||
210 | #define HPET_ID_NUMBER_SHIFT 8 |
||
211 | |||
212 | #define HPET_CFG_ENABLE 0x001 |
||
213 | |||
214 | static void *hpet_virt_address; |
||
215 | |||
216 | inline unsigned int hpet_readl(unsigned int a) |
||
217 | { |
||
218 | return readl(hpet_virt_address + a); |
||
219 | } |
||
220 | |||
221 | static inline void hpet_writel(unsigned int d, unsigned int a) |
||
222 | { |
||
223 | writel(d, hpet_virt_address + a); |
||
224 | } |
||
225 | |||
226 | static void hpet_start_counter(void) |
||
227 | { |
||
228 | unsigned int cfg = hpet_readl(HPET_CFG); |
||
229 | cfg |= HPET_CFG_ENABLE; |
||
230 | hpet_writel(cfg, HPET_CFG); |
||
231 | } |
||
232 | |||
233 | |||
234 | u64 read_htime() |
||
235 | { |
||
236 | u32 eflags; |
||
237 | u64 val; |
||
238 | |||
239 | eflags = safe_cli(); |
||
240 | asm volatile( |
||
241 | "1:\n" |
||
242 | "mov 0xf4(%%ebx), %%edx\n" |
||
243 | "mov 0xf0(%%ebx), %%eax\n" |
||
244 | "mov 0xf4(%%ebx), %%ecx\n" |
||
245 | "cmpl %%edx, %%ecx\n" |
||
246 | "jnz 1b\n" |
||
247 | :"=A"(val) |
||
248 | :"b" (hpet_virt_address) |
||
249 | :"ecx"); |
||
250 | safe_sti(eflags); |
||
251 | return val; |
||
252 | } |
||
253 | |||
254 | static u32 period; |
||
255 | |||
256 | void init_hpet() |
||
257 | { |
||
258 | void *sdt = NULL; |
||
259 | |||
260 | acpi_rsdp_t *rsdp = acpi_locate(); |
||
261 | |||
262 | if (unlikely(rsdp == NULL)) |
||
263 | { |
||
264 | printf("No ACPI RSD table\n"); |
||
265 | return ; |
||
266 | }; |
||
267 | |||
268 | printf("rsd base address %p\n", rsdp); |
||
269 | |||
270 | if(rsdp->rev > 1) |
||
271 | { |
||
272 | sdt = (void*)(u32)rsdp->xsdt_ptr; |
||
273 | sdt_find = xsdt_find; |
||
274 | } |
||
275 | else |
||
276 | { |
||
277 | sdt = (void*)rsdp->rsdt_ptr; |
||
278 | sdt_find = rsdt_find; |
||
279 | }; |
||
280 | |||
281 | printf("sdt address %p\n", sdt); |
||
282 | |||
283 | if (sdt == NULL) |
||
284 | { |
||
285 | printf("Invalid ACPI RSD table\n"); |
||
286 | return ; |
||
287 | }; |
||
288 | |||
289 | sdt = MapIoMem(sdt, 128*1024, PG_SW); |
||
290 | |||
291 | printf("sdt mapped address %x\n", sdt); |
||
292 | |||
293 | acpi_hpet_t *tbl = (acpi_hpet_t*)sdt_find(sdt, 0x54455048); |
||
294 | |||
295 | u32 hpet_address = tbl->address.address; |
||
296 | |||
297 | hpet_virt_address = (void*)MapIoMem(hpet_address,1024, PG_SW|0x18); |
||
298 | |||
299 | printf("hpet address %x mapped at %x\n", hpet_address, hpet_virt_address); |
||
300 | |||
301 | u32 timers, l, h; |
||
302 | |||
303 | l = hpet_readl(HPET_ID); |
||
304 | h = hpet_readl(HPET_PERIOD); |
||
305 | period = h / 1000000; |
||
306 | |||
307 | timers = ((l & HPET_ID_NUMBER) >> HPET_ID_NUMBER_SHIFT) + 1; |
||
308 | printk(KERN_INFO "hpet: ID: 0x%x, PERIOD: 0x%x\n", l, h); |
||
309 | l = hpet_readl(HPET_CFG); |
||
310 | h = hpet_readl(HPET_STATUS); |
||
311 | printk(KERN_INFO "hpet: CFG: 0x%x, STATUS: 0x%x\n", l, h); |
||
312 | l = hpet_readl(HPET_COUNTER); |
||
313 | h = hpet_readl(HPET_COUNTER+4); |
||
314 | printk(KERN_INFO "hpet: COUNTER_l: 0x%x, COUNTER_h: 0x%x\n", l, h); |
||
315 | |||
316 | hpet_start_counter(); |
||
317 | |||
318 | }>>>>> |
||
319 |