2 * QEMU ICH9 Timer emulation
4 * Copyright (c) 2024 Dominic Prinz <git@dprinz.de>
6 * This work is licensed under the terms of the GNU GPL, version 2 or later.
7 * See the COPYING file in the top-level directory.
10 #include "qemu/osdep.h"
11 #include "hw/core/cpu.h"
12 #include "hw/pci/pci.h"
13 #include "hw/southbridge/ich9.h"
14 #include "qemu/timer.h"
16 #include "hw/acpi/ich9_timer.h"
18 void ich9_pm_update_swsmi_timer(ICH9LPCPMRegs
*pm
, bool enable
)
20 uint16_t swsmi_rate_sel
;
25 lpc
= container_of(pm
, ICH9LPCState
, pm
);
27 (pci_get_word(lpc
->d
.config
+ ICH9_LPC_GEN_PMCON_3
) & 0xc0) >> 6;
29 if (swsmi_rate_sel
== 0) {
30 expire_time
= qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL
) + 1500000LL;
32 expire_time
= qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL
) +
33 8 * (1 << swsmi_rate_sel
) * 1000000LL;
36 timer_mod(pm
->swsmi_timer
, expire_time
);
38 timer_del(pm
->swsmi_timer
);
42 static void ich9_pm_swsmi_timer_expired(void *opaque
)
44 ICH9LPCPMRegs
*pm
= opaque
;
46 pm
->smi_sts
|= ICH9_PMIO_SMI_STS_SWSMI_STS
;
49 ich9_pm_update_swsmi_timer(pm
, pm
->smi_en
& ICH9_PMIO_SMI_EN_SWSMI_EN
);
52 void ich9_pm_swsmi_timer_init(ICH9LPCPMRegs
*pm
)
54 pm
->smi_sts_wmask
|= ICH9_PMIO_SMI_STS_SWSMI_STS
;
56 timer_new_ns(QEMU_CLOCK_VIRTUAL
, ich9_pm_swsmi_timer_expired
, pm
);
59 void ich9_pm_update_periodic_timer(ICH9LPCPMRegs
*pm
, bool enable
)
66 lpc
= container_of(pm
, ICH9LPCState
, pm
);
67 per_smi_sel
= pci_get_word(lpc
->d
.config
+ ICH9_LPC_GEN_PMCON_1
) & 3;
68 expire_time
= qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL
) +
69 8 * (1 << (3 - per_smi_sel
)) * NANOSECONDS_PER_SECOND
;
71 timer_mod(pm
->periodic_timer
, expire_time
);
73 timer_del(pm
->periodic_timer
);
77 static void ich9_pm_periodic_timer_expired(void *opaque
)
79 ICH9LPCPMRegs
*pm
= opaque
;
81 pm
->smi_sts
= ICH9_PMIO_SMI_STS_PERIODIC_STS
;
84 ich9_pm_update_periodic_timer(pm
,
85 pm
->smi_en
& ICH9_PMIO_SMI_EN_PERIODIC_EN
);
88 void ich9_pm_periodic_timer_init(ICH9LPCPMRegs
*pm
)
90 pm
->smi_sts_wmask
|= ICH9_PMIO_SMI_STS_PERIODIC_STS
;
92 timer_new_ns(QEMU_CLOCK_VIRTUAL
, ich9_pm_periodic_timer_expired
, pm
);