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 "hw/rtc/aspeed_rtc.h"
11 #include "migration/vmstate.h"
13 #include "qemu/timer.h"
14 #include "sysemu/rtc.h"
18 #define COUNTER1 (0x00 / 4)
19 #define COUNTER2 (0x04 / 4)
20 #define ALARM (0x08 / 4)
21 #define CONTROL (0x10 / 4)
22 #define ALARM_STATUS (0x14 / 4)
24 #define RTC_UNLOCKED BIT(1)
25 #define RTC_ENABLED BIT(0)
27 static void aspeed_rtc_calc_offset(AspeedRtcState
*rtc
)
31 uint32_t reg1
= rtc
->reg
[COUNTER1
];
32 uint32_t reg2
= rtc
->reg
[COUNTER2
];
34 tm
.tm_mday
= (reg1
>> 24) & 0x1f;
35 tm
.tm_hour
= (reg1
>> 16) & 0x1f;
36 tm
.tm_min
= (reg1
>> 8) & 0x3f;
37 tm
.tm_sec
= (reg1
>> 0) & 0x3f;
39 cent
= (reg2
>> 16) & 0x1f;
40 year
= (reg2
>> 8) & 0x7f;
41 tm
.tm_mon
= ((reg2
>> 0) & 0x0f) - 1;
42 tm
.tm_year
= year
+ (cent
* 100) - 1900;
44 rtc
->offset
= qemu_timedate_diff(&tm
);
47 static uint32_t aspeed_rtc_get_counter(AspeedRtcState
*rtc
, int r
)
52 qemu_get_timedate(&now
, rtc
->offset
);
56 return (now
.tm_mday
<< 24) | (now
.tm_hour
<< 16) |
57 (now
.tm_min
<< 8) | now
.tm_sec
;
59 cent
= (now
.tm_year
+ 1900) / 100;
60 year
= now
.tm_year
% 100;
61 return ((cent
& 0x1f) << 16) | ((year
& 0x7f) << 8) |
62 ((now
.tm_mon
+ 1) & 0xf);
64 g_assert_not_reached();
68 static uint64_t aspeed_rtc_read(void *opaque
, hwaddr addr
,
71 AspeedRtcState
*rtc
= opaque
;
73 uint32_t r
= addr
>> 2;
78 if (rtc
->reg
[CONTROL
] & RTC_ENABLED
) {
79 rtc
->reg
[r
] = aspeed_rtc_get_counter(rtc
, r
);
88 qemu_log_mask(LOG_UNIMP
, "%s: 0x%" HWADDR_PRIx
"\n", __func__
, addr
);
92 trace_aspeed_rtc_read(addr
, val
);
97 static void aspeed_rtc_write(void *opaque
, hwaddr addr
,
98 uint64_t val
, unsigned size
)
100 AspeedRtcState
*rtc
= opaque
;
101 uint32_t r
= addr
>> 2;
106 if (!(rtc
->reg
[CONTROL
] & RTC_UNLOCKED
)) {
112 aspeed_rtc_calc_offset(rtc
);
117 qemu_log_mask(LOG_UNIMP
, "%s: 0x%" HWADDR_PRIx
"\n", __func__
, addr
);
120 trace_aspeed_rtc_write(addr
, val
);
123 static void aspeed_rtc_reset(DeviceState
*d
)
125 AspeedRtcState
*rtc
= ASPEED_RTC(d
);
128 memset(rtc
->reg
, 0, sizeof(rtc
->reg
));
131 static const MemoryRegionOps aspeed_rtc_ops
= {
132 .read
= aspeed_rtc_read
,
133 .write
= aspeed_rtc_write
,
134 .endianness
= DEVICE_NATIVE_ENDIAN
,
137 static const VMStateDescription vmstate_aspeed_rtc
= {
138 .name
= TYPE_ASPEED_RTC
,
140 .fields
= (const VMStateField
[]) {
141 VMSTATE_UINT32_ARRAY(reg
, AspeedRtcState
, 0x18),
142 VMSTATE_INT64(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
)