2 * QEMU ICH9 TCO emulation
4 * Copyright (c) 2015 Paulo Alcantara <pcacjr@zytor.com>
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.
9 #include "qemu/osdep.h"
10 #include "qemu-common.h"
11 #include "sysemu/watchdog.h"
12 #include "hw/i386/ich9.h"
14 #include "hw/acpi/tco.h"
20 #define TCO_DEBUG(fmt, ...) \
22 fprintf(stderr, "%s "fmt, __func__, ## __VA_ARGS__); \
25 #define TCO_DEBUG(fmt, ...) do { } while (0)
29 TCO_RLD_DEFAULT
= 0x0000,
30 TCO_DAT_IN_DEFAULT
= 0x00,
31 TCO_DAT_OUT_DEFAULT
= 0x00,
32 TCO1_STS_DEFAULT
= 0x0000,
33 TCO2_STS_DEFAULT
= 0x0000,
34 TCO1_CNT_DEFAULT
= 0x0000,
35 TCO2_CNT_DEFAULT
= 0x0008,
36 TCO_MESSAGE1_DEFAULT
= 0x00,
37 TCO_MESSAGE2_DEFAULT
= 0x00,
38 TCO_WDCNT_DEFAULT
= 0x00,
39 TCO_TMR_DEFAULT
= 0x0004,
40 SW_IRQ_GEN_DEFAULT
= 0x03,
43 static inline void tco_timer_reload(TCOIORegs
*tr
)
45 int ticks
= tr
->tco
.tmr
& TCO_TMR_MASK
;
46 int64_t nsec
= (int64_t)ticks
* TCO_TICK_NSEC
;
48 trace_tco_timer_reload(ticks
, nsec
/ 1000000);
49 tr
->expire_time
= qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL
) + nsec
;
50 timer_mod(tr
->tco_timer
, tr
->expire_time
);
53 static inline void tco_timer_stop(TCOIORegs
*tr
)
56 timer_del(tr
->tco_timer
);
59 static void tco_timer_expired(void *opaque
)
61 TCOIORegs
*tr
= opaque
;
62 ICH9LPCPMRegs
*pm
= container_of(tr
, ICH9LPCPMRegs
, tco_regs
);
63 ICH9LPCState
*lpc
= container_of(pm
, ICH9LPCState
, pm
);
64 uint32_t gcs
= pci_get_long(lpc
->chip_config
+ ICH9_CC_GCS
);
66 trace_tco_timer_expired(tr
->timeouts_no
,
67 lpc
->pin_strap
.spkr_hi
,
68 !!(gcs
& ICH9_CC_GCS_NO_REBOOT
));
70 tr
->tco
.sts1
|= TCO_TIMEOUT
;
71 if (++tr
->timeouts_no
== 2) {
72 tr
->tco
.sts2
|= TCO_SECOND_TO_STS
;
73 tr
->tco
.sts2
|= TCO_BOOT_STS
;
76 if (!lpc
->pin_strap
.spkr_hi
&& !(gcs
& ICH9_CC_GCS_NO_REBOOT
)) {
77 watchdog_perform_action();
83 if (pm
->smi_en
& ICH9_PMIO_SMI_EN_TCO_EN
) {
86 tr
->tco
.rld
= tr
->tco
.tmr
;
90 /* NOTE: values of 0 or 1 will be ignored by ICH */
91 static inline int can_start_tco_timer(TCOIORegs
*tr
)
93 return !(tr
->tco
.cnt1
& TCO_TMR_HLT
) && tr
->tco
.tmr
> 1;
96 static uint32_t tco_ioport_readw(TCOIORegs
*tr
, uint32_t addr
)
102 if (tr
->expire_time
!= -1) {
103 int64_t now
= qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL
);
104 int64_t elapsed
= (tr
->expire_time
- now
) / TCO_TICK_NSEC
;
105 rld
= (uint16_t)elapsed
| (tr
->tco
.rld
& ~TCO_RLD_MASK
);
127 return tr
->tco
.wdcnt
;
131 return tr
->sw_irq_gen
;
136 static void tco_ioport_writew(TCOIORegs
*tr
, uint32_t addr
, uint32_t val
)
141 if (can_start_tco_timer(tr
)) {
142 tr
->tco
.rld
= tr
->tco
.tmr
;
143 tco_timer_reload(tr
);
150 tr
->tco
.sts1
|= SW_TCO_SMI
;
155 tr
->tco
.sts1
|= TCO_INT_STS
;
156 /* TODO: cause an interrupt, as selected by the TCO_INT_SEL bits */
159 tr
->tco
.sts1
= val
& TCO1_STS_MASK
;
162 tr
->tco
.sts2
= val
& TCO2_STS_MASK
;
165 val
&= TCO1_CNT_MASK
;
167 * once TCO_LOCK bit is set, it can not be cleared by software. a reset
168 * is required to change this bit from 1 to 0 -- it defaults to 0.
170 tr
->tco
.cnt1
= val
| (tr
->tco
.cnt1
& TCO_LOCK
);
171 if (can_start_tco_timer(tr
)) {
172 tr
->tco
.rld
= tr
->tco
.tmr
;
173 tco_timer_reload(tr
);
194 tr
->sw_irq_gen
= val
;
199 static uint64_t tco_io_readw(void *opaque
, hwaddr addr
, unsigned width
)
201 TCOIORegs
*tr
= opaque
;
202 return tco_ioport_readw(tr
, addr
);
205 static void tco_io_writew(void *opaque
, hwaddr addr
, uint64_t val
,
208 TCOIORegs
*tr
= opaque
;
209 tco_ioport_writew(tr
, addr
, val
);
212 static const MemoryRegionOps tco_io_ops
= {
213 .read
= tco_io_readw
,
214 .write
= tco_io_writew
,
215 .valid
.min_access_size
= 1,
216 .valid
.max_access_size
= 4,
217 .impl
.min_access_size
= 1,
218 .impl
.max_access_size
= 2,
219 .endianness
= DEVICE_LITTLE_ENDIAN
,
222 void acpi_pm_tco_init(TCOIORegs
*tr
, MemoryRegion
*parent
)
226 .rld
= TCO_RLD_DEFAULT
,
227 .din
= TCO_DAT_IN_DEFAULT
,
228 .dout
= TCO_DAT_OUT_DEFAULT
,
229 .sts1
= TCO1_STS_DEFAULT
,
230 .sts2
= TCO2_STS_DEFAULT
,
231 .cnt1
= TCO1_CNT_DEFAULT
,
232 .cnt2
= TCO2_CNT_DEFAULT
,
233 .msg1
= TCO_MESSAGE1_DEFAULT
,
234 .msg2
= TCO_MESSAGE2_DEFAULT
,
235 .wdcnt
= TCO_WDCNT_DEFAULT
,
236 .tmr
= TCO_TMR_DEFAULT
,
238 .sw_irq_gen
= SW_IRQ_GEN_DEFAULT
,
239 .tco_timer
= timer_new_ns(QEMU_CLOCK_VIRTUAL
, tco_timer_expired
, tr
),
243 memory_region_init_io(&tr
->io
, memory_region_owner(parent
),
244 &tco_io_ops
, tr
, "sm-tco", ICH9_PMIO_TCO_LEN
);
245 memory_region_add_subregion(parent
, ICH9_PMIO_TCO_RLD
, &tr
->io
);
248 const VMStateDescription vmstate_tco_io_sts
= {
249 .name
= "tco io device status",
251 .minimum_version_id
= 1,
252 .minimum_version_id_old
= 1,
253 .fields
= (VMStateField
[]) {
254 VMSTATE_UINT16(tco
.rld
, TCOIORegs
),
255 VMSTATE_UINT8(tco
.din
, TCOIORegs
),
256 VMSTATE_UINT8(tco
.dout
, TCOIORegs
),
257 VMSTATE_UINT16(tco
.sts1
, TCOIORegs
),
258 VMSTATE_UINT16(tco
.sts2
, TCOIORegs
),
259 VMSTATE_UINT16(tco
.cnt1
, TCOIORegs
),
260 VMSTATE_UINT16(tco
.cnt2
, TCOIORegs
),
261 VMSTATE_UINT8(tco
.msg1
, TCOIORegs
),
262 VMSTATE_UINT8(tco
.msg2
, TCOIORegs
),
263 VMSTATE_UINT8(tco
.wdcnt
, TCOIORegs
),
264 VMSTATE_UINT16(tco
.tmr
, TCOIORegs
),
265 VMSTATE_UINT8(sw_irq_gen
, TCOIORegs
),
266 VMSTATE_TIMER_PTR(tco_timer
, TCOIORegs
),
267 VMSTATE_INT64(expire_time
, TCOIORegs
),
268 VMSTATE_UINT8(timeouts_no
, TCOIORegs
),
269 VMSTATE_END_OF_LIST()