2 * ASPEED Real Time Clock
3 * Joel Stanley <joel@jms.id.au>
5 * Copyright 2019 IBM Corp
6 * SPDX-License-Identifier: GPL-2.0-or-later
9 #include "qemu/osdep.h"
10 #include "qemu-common.h"
11 #include "hw/timer/aspeed_rtc.h"
13 #include "qemu/timer.h"
17 #define COUNTER1 (0x00 / 4)
18 #define COUNTER2 (0x04 / 4)
19 #define ALARM (0x08 / 4)
20 #define CONTROL (0x10 / 4)
21 #define ALARM_STATUS (0x14 / 4)
23 #define RTC_UNLOCKED BIT(1)
24 #define RTC_ENABLED BIT(0)
26 static void aspeed_rtc_calc_offset(AspeedRtcState
*rtc
)
30 uint32_t reg1
= rtc
->reg
[COUNTER1
];
31 uint32_t reg2
= rtc
->reg
[COUNTER2
];
33 tm
.tm_mday
= (reg1
>> 24) & 0x1f;
34 tm
.tm_hour
= (reg1
>> 16) & 0x1f;
35 tm
.tm_min
= (reg1
>> 8) & 0x3f;
36 tm
.tm_sec
= (reg1
>> 0) & 0x3f;
38 cent
= (reg2
>> 16) & 0x1f;
39 year
= (reg2
>> 8) & 0x7f;
40 tm
.tm_mon
= ((reg2
>> 0) & 0x0f) - 1;
41 tm
.tm_year
= year
+ (cent
* 100) - 1900;
43 rtc
->offset
= qemu_timedate_diff(&tm
);
46 static uint32_t aspeed_rtc_get_counter(AspeedRtcState
*rtc
, int r
)
51 qemu_get_timedate(&now
, rtc
->offset
);
55 return (now
.tm_mday
<< 24) | (now
.tm_hour
<< 16) |
56 (now
.tm_min
<< 8) | now
.tm_sec
;
58 cent
= (now
.tm_year
+ 1900) / 100;
59 year
= now
.tm_year
% 100;
60 return ((cent
& 0x1f) << 16) | ((year
& 0x7f) << 8) |
61 ((now
.tm_mon
+ 1) & 0xf);
63 g_assert_not_reached();
67 static uint64_t aspeed_rtc_read(void *opaque
, hwaddr addr
,
70 AspeedRtcState
*rtc
= opaque
;
72 uint32_t r
= addr
>> 2;
77 if (rtc
->reg
[CONTROL
] & RTC_ENABLED
) {
78 rtc
->reg
[r
] = aspeed_rtc_get_counter(rtc
, r
);
87 qemu_log_mask(LOG_UNIMP
, "%s: 0x%" HWADDR_PRIx
"\n", __func__
, addr
);
91 trace_aspeed_rtc_read(addr
, val
);
96 static void aspeed_rtc_write(void *opaque
, hwaddr addr
,
97 uint64_t val
, unsigned size
)
99 AspeedRtcState
*rtc
= opaque
;
100 uint32_t r
= addr
>> 2;
105 if (!(rtc
->reg
[CONTROL
] & RTC_UNLOCKED
)) {
111 aspeed_rtc_calc_offset(rtc
);
116 qemu_log_mask(LOG_UNIMP
, "%s: 0x%" HWADDR_PRIx
"\n", __func__
, addr
);
119 trace_aspeed_rtc_write(addr
, val
);
122 static void aspeed_rtc_reset(DeviceState
*d
)
124 AspeedRtcState
*rtc
= ASPEED_RTC(d
);
127 memset(rtc
->reg
, 0, sizeof(rtc
->reg
));
130 static const MemoryRegionOps aspeed_rtc_ops
= {
131 .read
= aspeed_rtc_read
,
132 .write
= aspeed_rtc_write
,
133 .endianness
= DEVICE_NATIVE_ENDIAN
,
136 static const VMStateDescription vmstate_aspeed_rtc
= {
137 .name
= TYPE_ASPEED_RTC
,
139 .fields
= (VMStateField
[]) {
140 VMSTATE_UINT32_ARRAY(reg
, AspeedRtcState
, 0x18),
141 VMSTATE_INT32(offset
, AspeedRtcState
),
142 VMSTATE_INT32(offset
, AspeedRtcState
),
143 VMSTATE_END_OF_LIST()
147 static void aspeed_rtc_realize(DeviceState
*dev
, Error
**errp
)
149 SysBusDevice
*sbd
= SYS_BUS_DEVICE(dev
);
150 AspeedRtcState
*s
= ASPEED_RTC(dev
);
152 sysbus_init_irq(sbd
, &s
->irq
);
154 memory_region_init_io(&s
->iomem
, OBJECT(s
), &aspeed_rtc_ops
, s
,
155 "aspeed-rtc", 0x18ULL
);
156 sysbus_init_mmio(sbd
, &s
->iomem
);
159 static void aspeed_rtc_class_init(ObjectClass
*klass
, void *data
)
161 DeviceClass
*dc
= DEVICE_CLASS(klass
);
163 dc
->realize
= aspeed_rtc_realize
;
164 dc
->vmsd
= &vmstate_aspeed_rtc
;
165 dc
->reset
= aspeed_rtc_reset
;
168 static const TypeInfo aspeed_rtc_info
= {
169 .name
= TYPE_ASPEED_RTC
,
170 .parent
= TYPE_SYS_BUS_DEVICE
,
171 .instance_size
= sizeof(AspeedRtcState
),
172 .class_init
= aspeed_rtc_class_init
,
175 static void aspeed_rtc_register_types(void)
177 type_register_static(&aspeed_rtc_info
);
180 type_init(aspeed_rtc_register_types
)