]> git.proxmox.com Git - qemu.git/blob - hw/hpet.c
i8254: Factor out interface header
[qemu.git] / hw / hpet.c
1 /*
2 * High Precisition Event Timer emulation
3 *
4 * Copyright (c) 2007 Alexander Graf
5 * Copyright (c) 2008 IBM Corporation
6 *
7 * Authors: Beth Kon <bkon@us.ibm.com>
8 *
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2 of the License, or (at your option) any later version.
13 *
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
18 *
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
21 *
22 * *****************************************************************
23 *
24 * This driver attempts to emulate an HPET device in software.
25 */
26
27 #include "hw.h"
28 #include "pc.h"
29 #include "console.h"
30 #include "qemu-timer.h"
31 #include "hpet_emul.h"
32 #include "sysbus.h"
33 #include "mc146818rtc.h"
34 #include "i8254.h"
35
36 //#define HPET_DEBUG
37 #ifdef HPET_DEBUG
38 #define DPRINTF printf
39 #else
40 #define DPRINTF(...)
41 #endif
42
43 #define HPET_MSI_SUPPORT 0
44
45 struct HPETState;
46 typedef struct HPETTimer { /* timers */
47 uint8_t tn; /*timer number*/
48 QEMUTimer *qemu_timer;
49 struct HPETState *state;
50 /* Memory-mapped, software visible timer registers */
51 uint64_t config; /* configuration/cap */
52 uint64_t cmp; /* comparator */
53 uint64_t fsb; /* FSB route */
54 /* Hidden register state */
55 uint64_t period; /* Last value written to comparator */
56 uint8_t wrap_flag; /* timer pop will indicate wrap for one-shot 32-bit
57 * mode. Next pop will be actual timer expiration.
58 */
59 } HPETTimer;
60
61 typedef struct HPETState {
62 SysBusDevice busdev;
63 MemoryRegion iomem;
64 uint64_t hpet_offset;
65 qemu_irq irqs[HPET_NUM_IRQ_ROUTES];
66 uint32_t flags;
67 uint8_t rtc_irq_level;
68 uint8_t num_timers;
69 HPETTimer timer[HPET_MAX_TIMERS];
70
71 /* Memory-mapped, software visible registers */
72 uint64_t capability; /* capabilities */
73 uint64_t config; /* configuration */
74 uint64_t isr; /* interrupt status reg */
75 uint64_t hpet_counter; /* main counter */
76 uint8_t hpet_id; /* instance id */
77 } HPETState;
78
79 static uint32_t hpet_in_legacy_mode(HPETState *s)
80 {
81 return s->config & HPET_CFG_LEGACY;
82 }
83
84 static uint32_t timer_int_route(struct HPETTimer *timer)
85 {
86 return (timer->config & HPET_TN_INT_ROUTE_MASK) >> HPET_TN_INT_ROUTE_SHIFT;
87 }
88
89 static uint32_t timer_fsb_route(HPETTimer *t)
90 {
91 return t->config & HPET_TN_FSB_ENABLE;
92 }
93
94 static uint32_t hpet_enabled(HPETState *s)
95 {
96 return s->config & HPET_CFG_ENABLE;
97 }
98
99 static uint32_t timer_is_periodic(HPETTimer *t)
100 {
101 return t->config & HPET_TN_PERIODIC;
102 }
103
104 static uint32_t timer_enabled(HPETTimer *t)
105 {
106 return t->config & HPET_TN_ENABLE;
107 }
108
109 static uint32_t hpet_time_after(uint64_t a, uint64_t b)
110 {
111 return ((int32_t)(b) - (int32_t)(a) < 0);
112 }
113
114 static uint32_t hpet_time_after64(uint64_t a, uint64_t b)
115 {
116 return ((int64_t)(b) - (int64_t)(a) < 0);
117 }
118
119 static uint64_t ticks_to_ns(uint64_t value)
120 {
121 return (muldiv64(value, HPET_CLK_PERIOD, FS_PER_NS));
122 }
123
124 static uint64_t ns_to_ticks(uint64_t value)
125 {
126 return (muldiv64(value, FS_PER_NS, HPET_CLK_PERIOD));
127 }
128
129 static uint64_t hpet_fixup_reg(uint64_t new, uint64_t old, uint64_t mask)
130 {
131 new &= mask;
132 new |= old & ~mask;
133 return new;
134 }
135
136 static int activating_bit(uint64_t old, uint64_t new, uint64_t mask)
137 {
138 return (!(old & mask) && (new & mask));
139 }
140
141 static int deactivating_bit(uint64_t old, uint64_t new, uint64_t mask)
142 {
143 return ((old & mask) && !(new & mask));
144 }
145
146 static uint64_t hpet_get_ticks(HPETState *s)
147 {
148 return ns_to_ticks(qemu_get_clock_ns(vm_clock) + s->hpet_offset);
149 }
150
151 /*
152 * calculate diff between comparator value and current ticks
153 */
154 static inline uint64_t hpet_calculate_diff(HPETTimer *t, uint64_t current)
155 {
156
157 if (t->config & HPET_TN_32BIT) {
158 uint32_t diff, cmp;
159
160 cmp = (uint32_t)t->cmp;
161 diff = cmp - (uint32_t)current;
162 diff = (int32_t)diff > 0 ? diff : (uint32_t)1;
163 return (uint64_t)diff;
164 } else {
165 uint64_t diff, cmp;
166
167 cmp = t->cmp;
168 diff = cmp - current;
169 diff = (int64_t)diff > 0 ? diff : (uint64_t)1;
170 return diff;
171 }
172 }
173
174 static void update_irq(struct HPETTimer *timer, int set)
175 {
176 uint64_t mask;
177 HPETState *s;
178 int route;
179
180 if (timer->tn <= 1 && hpet_in_legacy_mode(timer->state)) {
181 /* if LegacyReplacementRoute bit is set, HPET specification requires
182 * timer0 be routed to IRQ0 in NON-APIC or IRQ2 in the I/O APIC,
183 * timer1 be routed to IRQ8 in NON-APIC or IRQ8 in the I/O APIC.
184 */
185 route = (timer->tn == 0) ? 0 : RTC_ISA_IRQ;
186 } else {
187 route = timer_int_route(timer);
188 }
189 s = timer->state;
190 mask = 1 << timer->tn;
191 if (!set || !timer_enabled(timer) || !hpet_enabled(timer->state)) {
192 s->isr &= ~mask;
193 if (!timer_fsb_route(timer)) {
194 qemu_irq_lower(s->irqs[route]);
195 }
196 } else if (timer_fsb_route(timer)) {
197 stl_le_phys(timer->fsb >> 32, timer->fsb & 0xffffffff);
198 } else if (timer->config & HPET_TN_TYPE_LEVEL) {
199 s->isr |= mask;
200 qemu_irq_raise(s->irqs[route]);
201 } else {
202 s->isr &= ~mask;
203 qemu_irq_pulse(s->irqs[route]);
204 }
205 }
206
207 static void hpet_pre_save(void *opaque)
208 {
209 HPETState *s = opaque;
210
211 /* save current counter value */
212 s->hpet_counter = hpet_get_ticks(s);
213 }
214
215 static int hpet_pre_load(void *opaque)
216 {
217 HPETState *s = opaque;
218
219 /* version 1 only supports 3, later versions will load the actual value */
220 s->num_timers = HPET_MIN_TIMERS;
221 return 0;
222 }
223
224 static int hpet_post_load(void *opaque, int version_id)
225 {
226 HPETState *s = opaque;
227
228 /* Recalculate the offset between the main counter and guest time */
229 s->hpet_offset = ticks_to_ns(s->hpet_counter) - qemu_get_clock_ns(vm_clock);
230
231 /* Push number of timers into capability returned via HPET_ID */
232 s->capability &= ~HPET_ID_NUM_TIM_MASK;
233 s->capability |= (s->num_timers - 1) << HPET_ID_NUM_TIM_SHIFT;
234 hpet_cfg.hpet[s->hpet_id].event_timer_block_id = (uint32_t)s->capability;
235
236 /* Derive HPET_MSI_SUPPORT from the capability of the first timer. */
237 s->flags &= ~(1 << HPET_MSI_SUPPORT);
238 if (s->timer[0].config & HPET_TN_FSB_CAP) {
239 s->flags |= 1 << HPET_MSI_SUPPORT;
240 }
241 return 0;
242 }
243
244 static bool hpet_rtc_irq_level_needed(void *opaque)
245 {
246 HPETState *s = opaque;
247
248 return s->rtc_irq_level != 0;
249 }
250
251 static const VMStateDescription vmstate_hpet_rtc_irq_level = {
252 .name = "hpet/rtc_irq_level",
253 .version_id = 1,
254 .minimum_version_id = 1,
255 .minimum_version_id_old = 1,
256 .fields = (VMStateField[]) {
257 VMSTATE_UINT8(rtc_irq_level, HPETState),
258 VMSTATE_END_OF_LIST()
259 }
260 };
261
262 static const VMStateDescription vmstate_hpet_timer = {
263 .name = "hpet_timer",
264 .version_id = 1,
265 .minimum_version_id = 1,
266 .minimum_version_id_old = 1,
267 .fields = (VMStateField []) {
268 VMSTATE_UINT8(tn, HPETTimer),
269 VMSTATE_UINT64(config, HPETTimer),
270 VMSTATE_UINT64(cmp, HPETTimer),
271 VMSTATE_UINT64(fsb, HPETTimer),
272 VMSTATE_UINT64(period, HPETTimer),
273 VMSTATE_UINT8(wrap_flag, HPETTimer),
274 VMSTATE_TIMER(qemu_timer, HPETTimer),
275 VMSTATE_END_OF_LIST()
276 }
277 };
278
279 static const VMStateDescription vmstate_hpet = {
280 .name = "hpet",
281 .version_id = 2,
282 .minimum_version_id = 1,
283 .minimum_version_id_old = 1,
284 .pre_save = hpet_pre_save,
285 .pre_load = hpet_pre_load,
286 .post_load = hpet_post_load,
287 .fields = (VMStateField []) {
288 VMSTATE_UINT64(config, HPETState),
289 VMSTATE_UINT64(isr, HPETState),
290 VMSTATE_UINT64(hpet_counter, HPETState),
291 VMSTATE_UINT8_V(num_timers, HPETState, 2),
292 VMSTATE_STRUCT_VARRAY_UINT8(timer, HPETState, num_timers, 0,
293 vmstate_hpet_timer, HPETTimer),
294 VMSTATE_END_OF_LIST()
295 },
296 .subsections = (VMStateSubsection[]) {
297 {
298 .vmsd = &vmstate_hpet_rtc_irq_level,
299 .needed = hpet_rtc_irq_level_needed,
300 }, {
301 /* empty */
302 }
303 }
304 };
305
306 /*
307 * timer expiration callback
308 */
309 static void hpet_timer(void *opaque)
310 {
311 HPETTimer *t = opaque;
312 uint64_t diff;
313
314 uint64_t period = t->period;
315 uint64_t cur_tick = hpet_get_ticks(t->state);
316
317 if (timer_is_periodic(t) && period != 0) {
318 if (t->config & HPET_TN_32BIT) {
319 while (hpet_time_after(cur_tick, t->cmp)) {
320 t->cmp = (uint32_t)(t->cmp + t->period);
321 }
322 } else {
323 while (hpet_time_after64(cur_tick, t->cmp)) {
324 t->cmp += period;
325 }
326 }
327 diff = hpet_calculate_diff(t, cur_tick);
328 qemu_mod_timer(t->qemu_timer,
329 qemu_get_clock_ns(vm_clock) + (int64_t)ticks_to_ns(diff));
330 } else if (t->config & HPET_TN_32BIT && !timer_is_periodic(t)) {
331 if (t->wrap_flag) {
332 diff = hpet_calculate_diff(t, cur_tick);
333 qemu_mod_timer(t->qemu_timer, qemu_get_clock_ns(vm_clock) +
334 (int64_t)ticks_to_ns(diff));
335 t->wrap_flag = 0;
336 }
337 }
338 update_irq(t, 1);
339 }
340
341 static void hpet_set_timer(HPETTimer *t)
342 {
343 uint64_t diff;
344 uint32_t wrap_diff; /* how many ticks until we wrap? */
345 uint64_t cur_tick = hpet_get_ticks(t->state);
346
347 /* whenever new timer is being set up, make sure wrap_flag is 0 */
348 t->wrap_flag = 0;
349 diff = hpet_calculate_diff(t, cur_tick);
350
351 /* hpet spec says in one-shot 32-bit mode, generate an interrupt when
352 * counter wraps in addition to an interrupt with comparator match.
353 */
354 if (t->config & HPET_TN_32BIT && !timer_is_periodic(t)) {
355 wrap_diff = 0xffffffff - (uint32_t)cur_tick;
356 if (wrap_diff < (uint32_t)diff) {
357 diff = wrap_diff;
358 t->wrap_flag = 1;
359 }
360 }
361 qemu_mod_timer(t->qemu_timer,
362 qemu_get_clock_ns(vm_clock) + (int64_t)ticks_to_ns(diff));
363 }
364
365 static void hpet_del_timer(HPETTimer *t)
366 {
367 qemu_del_timer(t->qemu_timer);
368 update_irq(t, 0);
369 }
370
371 #ifdef HPET_DEBUG
372 static uint32_t hpet_ram_readb(void *opaque, target_phys_addr_t addr)
373 {
374 printf("qemu: hpet_read b at %" PRIx64 "\n", addr);
375 return 0;
376 }
377
378 static uint32_t hpet_ram_readw(void *opaque, target_phys_addr_t addr)
379 {
380 printf("qemu: hpet_read w at %" PRIx64 "\n", addr);
381 return 0;
382 }
383 #endif
384
385 static uint64_t hpet_ram_read(void *opaque, target_phys_addr_t addr,
386 unsigned size)
387 {
388 HPETState *s = opaque;
389 uint64_t cur_tick, index;
390
391 DPRINTF("qemu: Enter hpet_ram_readl at %" PRIx64 "\n", addr);
392 index = addr;
393 /*address range of all TN regs*/
394 if (index >= 0x100 && index <= 0x3ff) {
395 uint8_t timer_id = (addr - 0x100) / 0x20;
396 HPETTimer *timer = &s->timer[timer_id];
397
398 if (timer_id > s->num_timers) {
399 DPRINTF("qemu: timer id out of range\n");
400 return 0;
401 }
402
403 switch ((addr - 0x100) % 0x20) {
404 case HPET_TN_CFG:
405 return timer->config;
406 case HPET_TN_CFG + 4: // Interrupt capabilities
407 return timer->config >> 32;
408 case HPET_TN_CMP: // comparator register
409 return timer->cmp;
410 case HPET_TN_CMP + 4:
411 return timer->cmp >> 32;
412 case HPET_TN_ROUTE:
413 return timer->fsb;
414 case HPET_TN_ROUTE + 4:
415 return timer->fsb >> 32;
416 default:
417 DPRINTF("qemu: invalid hpet_ram_readl\n");
418 break;
419 }
420 } else {
421 switch (index) {
422 case HPET_ID:
423 return s->capability;
424 case HPET_PERIOD:
425 return s->capability >> 32;
426 case HPET_CFG:
427 return s->config;
428 case HPET_CFG + 4:
429 DPRINTF("qemu: invalid HPET_CFG + 4 hpet_ram_readl\n");
430 return 0;
431 case HPET_COUNTER:
432 if (hpet_enabled(s)) {
433 cur_tick = hpet_get_ticks(s);
434 } else {
435 cur_tick = s->hpet_counter;
436 }
437 DPRINTF("qemu: reading counter = %" PRIx64 "\n", cur_tick);
438 return cur_tick;
439 case HPET_COUNTER + 4:
440 if (hpet_enabled(s)) {
441 cur_tick = hpet_get_ticks(s);
442 } else {
443 cur_tick = s->hpet_counter;
444 }
445 DPRINTF("qemu: reading counter + 4 = %" PRIx64 "\n", cur_tick);
446 return cur_tick >> 32;
447 case HPET_STATUS:
448 return s->isr;
449 default:
450 DPRINTF("qemu: invalid hpet_ram_readl\n");
451 break;
452 }
453 }
454 return 0;
455 }
456
457 static void hpet_ram_write(void *opaque, target_phys_addr_t addr,
458 uint64_t value, unsigned size)
459 {
460 int i;
461 HPETState *s = opaque;
462 uint64_t old_val, new_val, val, index;
463
464 DPRINTF("qemu: Enter hpet_ram_writel at %" PRIx64 " = %#x\n", addr, value);
465 index = addr;
466 old_val = hpet_ram_read(opaque, addr, 4);
467 new_val = value;
468
469 /*address range of all TN regs*/
470 if (index >= 0x100 && index <= 0x3ff) {
471 uint8_t timer_id = (addr - 0x100) / 0x20;
472 HPETTimer *timer = &s->timer[timer_id];
473
474 DPRINTF("qemu: hpet_ram_writel timer_id = %#x\n", timer_id);
475 if (timer_id > s->num_timers) {
476 DPRINTF("qemu: timer id out of range\n");
477 return;
478 }
479 switch ((addr - 0x100) % 0x20) {
480 case HPET_TN_CFG:
481 DPRINTF("qemu: hpet_ram_writel HPET_TN_CFG\n");
482 if (activating_bit(old_val, new_val, HPET_TN_FSB_ENABLE)) {
483 update_irq(timer, 0);
484 }
485 val = hpet_fixup_reg(new_val, old_val, HPET_TN_CFG_WRITE_MASK);
486 timer->config = (timer->config & 0xffffffff00000000ULL) | val;
487 if (new_val & HPET_TN_32BIT) {
488 timer->cmp = (uint32_t)timer->cmp;
489 timer->period = (uint32_t)timer->period;
490 }
491 if (activating_bit(old_val, new_val, HPET_TN_ENABLE)) {
492 hpet_set_timer(timer);
493 } else if (deactivating_bit(old_val, new_val, HPET_TN_ENABLE)) {
494 hpet_del_timer(timer);
495 }
496 break;
497 case HPET_TN_CFG + 4: // Interrupt capabilities
498 DPRINTF("qemu: invalid HPET_TN_CFG+4 write\n");
499 break;
500 case HPET_TN_CMP: // comparator register
501 DPRINTF("qemu: hpet_ram_writel HPET_TN_CMP\n");
502 if (timer->config & HPET_TN_32BIT) {
503 new_val = (uint32_t)new_val;
504 }
505 if (!timer_is_periodic(timer)
506 || (timer->config & HPET_TN_SETVAL)) {
507 timer->cmp = (timer->cmp & 0xffffffff00000000ULL) | new_val;
508 }
509 if (timer_is_periodic(timer)) {
510 /*
511 * FIXME: Clamp period to reasonable min value?
512 * Clamp period to reasonable max value
513 */
514 new_val &= (timer->config & HPET_TN_32BIT ? ~0u : ~0ull) >> 1;
515 timer->period =
516 (timer->period & 0xffffffff00000000ULL) | new_val;
517 }
518 timer->config &= ~HPET_TN_SETVAL;
519 if (hpet_enabled(s)) {
520 hpet_set_timer(timer);
521 }
522 break;
523 case HPET_TN_CMP + 4: // comparator register high order
524 DPRINTF("qemu: hpet_ram_writel HPET_TN_CMP + 4\n");
525 if (!timer_is_periodic(timer)
526 || (timer->config & HPET_TN_SETVAL)) {
527 timer->cmp = (timer->cmp & 0xffffffffULL) | new_val << 32;
528 } else {
529 /*
530 * FIXME: Clamp period to reasonable min value?
531 * Clamp period to reasonable max value
532 */
533 new_val &= (timer->config & HPET_TN_32BIT ? ~0u : ~0ull) >> 1;
534 timer->period =
535 (timer->period & 0xffffffffULL) | new_val << 32;
536 }
537 timer->config &= ~HPET_TN_SETVAL;
538 if (hpet_enabled(s)) {
539 hpet_set_timer(timer);
540 }
541 break;
542 case HPET_TN_ROUTE:
543 timer->fsb = (timer->fsb & 0xffffffff00000000ULL) | new_val;
544 break;
545 case HPET_TN_ROUTE + 4:
546 timer->fsb = (new_val << 32) | (timer->fsb & 0xffffffff);
547 break;
548 default:
549 DPRINTF("qemu: invalid hpet_ram_writel\n");
550 break;
551 }
552 return;
553 } else {
554 switch (index) {
555 case HPET_ID:
556 return;
557 case HPET_CFG:
558 val = hpet_fixup_reg(new_val, old_val, HPET_CFG_WRITE_MASK);
559 s->config = (s->config & 0xffffffff00000000ULL) | val;
560 if (activating_bit(old_val, new_val, HPET_CFG_ENABLE)) {
561 /* Enable main counter and interrupt generation. */
562 s->hpet_offset =
563 ticks_to_ns(s->hpet_counter) - qemu_get_clock_ns(vm_clock);
564 for (i = 0; i < s->num_timers; i++) {
565 if ((&s->timer[i])->cmp != ~0ULL) {
566 hpet_set_timer(&s->timer[i]);
567 }
568 }
569 } else if (deactivating_bit(old_val, new_val, HPET_CFG_ENABLE)) {
570 /* Halt main counter and disable interrupt generation. */
571 s->hpet_counter = hpet_get_ticks(s);
572 for (i = 0; i < s->num_timers; i++) {
573 hpet_del_timer(&s->timer[i]);
574 }
575 }
576 /* i8254 and RTC are disabled when HPET is in legacy mode */
577 if (activating_bit(old_val, new_val, HPET_CFG_LEGACY)) {
578 hpet_pit_disable();
579 qemu_irq_lower(s->irqs[RTC_ISA_IRQ]);
580 } else if (deactivating_bit(old_val, new_val, HPET_CFG_LEGACY)) {
581 hpet_pit_enable();
582 qemu_set_irq(s->irqs[RTC_ISA_IRQ], s->rtc_irq_level);
583 }
584 break;
585 case HPET_CFG + 4:
586 DPRINTF("qemu: invalid HPET_CFG+4 write\n");
587 break;
588 case HPET_STATUS:
589 val = new_val & s->isr;
590 for (i = 0; i < s->num_timers; i++) {
591 if (val & (1 << i)) {
592 update_irq(&s->timer[i], 0);
593 }
594 }
595 break;
596 case HPET_COUNTER:
597 if (hpet_enabled(s)) {
598 DPRINTF("qemu: Writing counter while HPET enabled!\n");
599 }
600 s->hpet_counter =
601 (s->hpet_counter & 0xffffffff00000000ULL) | value;
602 DPRINTF("qemu: HPET counter written. ctr = %#x -> %" PRIx64 "\n",
603 value, s->hpet_counter);
604 break;
605 case HPET_COUNTER + 4:
606 if (hpet_enabled(s)) {
607 DPRINTF("qemu: Writing counter while HPET enabled!\n");
608 }
609 s->hpet_counter =
610 (s->hpet_counter & 0xffffffffULL) | (((uint64_t)value) << 32);
611 DPRINTF("qemu: HPET counter + 4 written. ctr = %#x -> %" PRIx64 "\n",
612 value, s->hpet_counter);
613 break;
614 default:
615 DPRINTF("qemu: invalid hpet_ram_writel\n");
616 break;
617 }
618 }
619 }
620
621 static const MemoryRegionOps hpet_ram_ops = {
622 .read = hpet_ram_read,
623 .write = hpet_ram_write,
624 .valid = {
625 .min_access_size = 4,
626 .max_access_size = 4,
627 },
628 .endianness = DEVICE_NATIVE_ENDIAN,
629 };
630
631 static void hpet_reset(DeviceState *d)
632 {
633 HPETState *s = FROM_SYSBUS(HPETState, sysbus_from_qdev(d));
634 int i;
635 static int count = 0;
636
637 for (i = 0; i < s->num_timers; i++) {
638 HPETTimer *timer = &s->timer[i];
639
640 hpet_del_timer(timer);
641 timer->cmp = ~0ULL;
642 timer->config = HPET_TN_PERIODIC_CAP | HPET_TN_SIZE_CAP;
643 if (s->flags & (1 << HPET_MSI_SUPPORT)) {
644 timer->config |= HPET_TN_FSB_CAP;
645 }
646 /* advertise availability of ioapic inti2 */
647 timer->config |= 0x00000004ULL << 32;
648 timer->period = 0ULL;
649 timer->wrap_flag = 0;
650 }
651
652 s->hpet_counter = 0ULL;
653 s->hpet_offset = 0ULL;
654 s->config = 0ULL;
655 if (count > 0) {
656 /* we don't enable pit when hpet_reset is first called (by hpet_init)
657 * because hpet is taking over for pit here. On subsequent invocations,
658 * hpet_reset is called due to system reset. At this point control must
659 * be returned to pit until SW reenables hpet.
660 */
661 hpet_pit_enable();
662 }
663 hpet_cfg.hpet[s->hpet_id].event_timer_block_id = (uint32_t)s->capability;
664 hpet_cfg.hpet[s->hpet_id].address = sysbus_from_qdev(d)->mmio[0].addr;
665 count = 1;
666
667 /* to document that the RTC lowers its output on reset as well */
668 s->rtc_irq_level = 0;
669 }
670
671 static void hpet_handle_rtc_irq(void *opaque, int n, int level)
672 {
673 HPETState *s = FROM_SYSBUS(HPETState, opaque);
674
675 s->rtc_irq_level = level;
676 if (!hpet_in_legacy_mode(s)) {
677 qemu_set_irq(s->irqs[RTC_ISA_IRQ], level);
678 }
679 }
680
681 static int hpet_init(SysBusDevice *dev)
682 {
683 HPETState *s = FROM_SYSBUS(HPETState, dev);
684 int i;
685 HPETTimer *timer;
686
687 if (hpet_cfg.count == UINT8_MAX) {
688 /* first instance */
689 hpet_cfg.count = 0;
690 }
691
692 if (hpet_cfg.count == 8) {
693 fprintf(stderr, "Only 8 instances of HPET is allowed\n");
694 return -1;
695 }
696
697 s->hpet_id = hpet_cfg.count++;
698
699 for (i = 0; i < HPET_NUM_IRQ_ROUTES; i++) {
700 sysbus_init_irq(dev, &s->irqs[i]);
701 }
702
703 if (s->num_timers < HPET_MIN_TIMERS) {
704 s->num_timers = HPET_MIN_TIMERS;
705 } else if (s->num_timers > HPET_MAX_TIMERS) {
706 s->num_timers = HPET_MAX_TIMERS;
707 }
708 for (i = 0; i < HPET_MAX_TIMERS; i++) {
709 timer = &s->timer[i];
710 timer->qemu_timer = qemu_new_timer_ns(vm_clock, hpet_timer, timer);
711 timer->tn = i;
712 timer->state = s;
713 }
714
715 /* 64-bit main counter; LegacyReplacementRoute. */
716 s->capability = 0x8086a001ULL;
717 s->capability |= (s->num_timers - 1) << HPET_ID_NUM_TIM_SHIFT;
718 s->capability |= ((HPET_CLK_PERIOD) << 32);
719
720 qdev_init_gpio_in(&dev->qdev, hpet_handle_rtc_irq, 1);
721
722 /* HPET Area */
723 memory_region_init_io(&s->iomem, &hpet_ram_ops, s, "hpet", 0x400);
724 sysbus_init_mmio(dev, &s->iomem);
725 return 0;
726 }
727
728 static Property hpet_device_properties[] = {
729 DEFINE_PROP_UINT8("timers", HPETState, num_timers, HPET_MIN_TIMERS),
730 DEFINE_PROP_BIT("msi", HPETState, flags, HPET_MSI_SUPPORT, false),
731 DEFINE_PROP_END_OF_LIST(),
732 };
733
734 static void hpet_device_class_init(ObjectClass *klass, void *data)
735 {
736 DeviceClass *dc = DEVICE_CLASS(klass);
737 SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
738
739 k->init = hpet_init;
740 dc->no_user = 1;
741 dc->reset = hpet_reset;
742 dc->vmsd = &vmstate_hpet;
743 dc->props = hpet_device_properties;
744 }
745
746 static TypeInfo hpet_device_info = {
747 .name = "hpet",
748 .parent = TYPE_SYS_BUS_DEVICE,
749 .instance_size = sizeof(HPETState),
750 .class_init = hpet_device_class_init,
751 };
752
753 static void hpet_register_types(void)
754 {
755 type_register_static(&hpet_device_info);
756 }
757
758 type_init(hpet_register_types)