2 * Real Time Clock for S5C110-based board emulation
4 * Copyright (c) 2009 Samsung Electronics.
5 * Contributed by Vladimir Monakhov <vladimir.monakhov@ispras.ru>
8 #include "qemu-common.h"
9 #include "qemu-timer.h"
12 /* Registers addresses */
14 #define INT_PEND 0x30 /* R/W Interrupt Pending Register */
15 #define RTC_CON 0x40 /* R/W RTC Control Register */
16 #define TIC_CNT 0x44 /* R/W Tick Time Count Register */
17 #define RTC_ALM 0x50 /* R/W RTC Alarm Control Register */
18 #define ALM_SEC 0x54 /* R/W Alarm Second Data Register */
19 #define ALM_MIN 0x58 /* R/W Alarm Minute Data Register */
20 #define ALM_HOUR 0x5C /* R/W Alarm Hour Data Register */
21 #define ALM_DAY 0x60 /* R/W Alarm Day of the month Data Register */
22 #define ALM_MON 0x64 /* R/W Alarm Month Data Register */
23 #define ALM_YEAR 0x68 /* R/W Alarm Year Data Register */
24 #define BCD_SEC 0x70 /* R/W BCD Second Register */
25 #define BCD_MIN 0x74 /* R/W BCD Minute Register */
26 #define BCD_HOUR 0x78 /* R/W BCD Hour Register */
27 #define BCD_DAY 0x7C /* R/W BCD value for a day of the month (1-31) */
28 #define BCD_WEEKDAY 0x80 /* R/W BCD value for a day of the week (1-7) */
29 #define BCD_MON 0x84 /* R/W BCD Month Register */
30 #define BCD_YEAR 0x88 /* R/W BCD Year Register */
31 #define CUR_TIC_CNT 0x90 /* R Current Tick Time Counter Register */
33 /* Bit mapping for INT_PEND register */
35 #define INT_ALM 0x02 /* Alarm interrupt pending bit */
36 #define INT_TIC 0x01 /* Time TIC interrupt pending bit */
38 /* Bit mapping for RTC_CON register */
40 #define TIC_EN 0x100 /* Tick timer enable */
41 #define TIC_CK_SEL_SHIFT (4)/* Tick timer sub clock selection */
42 #define CLK_RST 0x08 /* RTC clock count reset */
43 #define CNT_SEL 0x04 /* BCD count select */
44 #define CLK_SEL 0x02 /* BCD clock select */
45 #define RTC_EN 0x01 /* RTC control enable */
47 /* Bit mapping for RTC_ALM register */
49 #define ALM_EN 0x40 /* Alarm global enable */
50 #define YEAR_EN 0x20 /* Year alarm enable */
51 #define MON_EN 0x10 /* Month alarm enable */
52 #define DAY_EN 0x08 /* Day of the month alarm enable */
53 #define HOUR_EN 0x04 /* Hour alarm enable */
54 #define MIN_EN 0x02 /* Minute alarm enable */
55 #define SEC_EN 0x01 /* Second alarm enable */
57 #define S5PC1XX_RTC_REG_MEM_SIZE 0x94
60 typedef struct S5pc1xxRTCState {
63 uint32_t regs[BCD_YEAR + 1];
66 QEMUTimer *periodic_timer;
73 QEMUTimer *second_timer;
80 static void s5pc1xx_rtc_periodic_tick(void *opaque);
81 static void s5pc1xx_rtc_second_update(void *opaque);
83 static void s5pc1xx_rtc_set_time(S5pc1xxRTCState *s)
85 struct tm *tm = &(s->current_tm);
87 tm->tm_sec = from_bcd(s->regs[BCD_SEC] & 0x7F);
88 tm->tm_min = from_bcd(s->regs[BCD_MIN] & 0x7F);
89 tm->tm_hour = from_bcd(s->regs[BCD_HOUR] & 0x3F);
90 tm->tm_wday = from_bcd(s->regs[BCD_WEEKDAY] & 0x07);
91 tm->tm_mday = from_bcd(s->regs[BCD_DAY] & 0x3F);
92 /* month value in qemu is between 0 and 11 */
93 tm->tm_mon = from_bcd(s->regs[BCD_MON] & 0x1F) - 1;
94 /* year value is with base_year = 2000 (not 1900 as in qemu) */
95 tm->tm_year = 100 + from_bcd(s->regs[BCD_YEAR] & 0xFF) +
96 from_bcd((s->regs[BCD_YEAR] >> 8) & 0xF) * 100;
99 static void s5pc1xx_rtc_read_time(S5pc1xxRTCState *s)
101 const struct tm *tm = &(s->current_tm);
103 s->regs[BCD_SEC] = to_bcd(tm->tm_sec);
104 s->regs[BCD_MIN] = to_bcd(tm->tm_min);
105 s->regs[BCD_HOUR] = to_bcd(tm->tm_hour);
106 s->regs[BCD_WEEKDAY] = to_bcd(tm->tm_wday);
107 s->regs[BCD_DAY] = to_bcd(tm->tm_mday);
108 /* month value in qemu is between 0 and 11 */
109 s->regs[BCD_MON] = to_bcd(tm->tm_mon + 1);
110 /* year value is with base_year = 2000 (not 1900 as in qemu) */
111 s->regs[BCD_YEAR] = to_bcd((tm->tm_year - 100) % 100) |
112 (to_bcd((tm->tm_year - 100) % 1000 / 100) << 8);
115 /* set default values for all fields */
116 static void s5pc1xx_rtc_reset(S5pc1xxRTCState *s)
120 /* stop tick timer */
121 s->regs[RTC_CON] &= ~TIC_EN;
122 s5pc1xx_rtc_periodic_tick(s);
124 /* stop second timer */
125 s->regs[RTC_CON] &= ~RTC_EN;
126 s5pc1xx_rtc_second_update(s);
128 for (i = 0x30; i < 0x90; i += 0x4) {
136 /* Setup next timer tick */
137 static void s5pc1xx_rtc_periodic_update(S5pc1xxRTCState *s)
139 uint64_t next_periodic_time, last = qemu_get_clock(vm_clock);
142 last + muldiv64(s->regs[TIC_CNT], get_ticks_per_sec(), s->freq_out);
143 qemu_mod_timer(s->periodic_timer, next_periodic_time);
146 /* Send periodic interrupt */
147 static void s5pc1xx_rtc_periodic_tick(void *opaque)
149 S5pc1xxRTCState *s = (S5pc1xxRTCState *)opaque;
151 /* tick actually happens not every CUR_TIC_CNT but rather at irq time;
152 * if current ticnto value is needed it is calculated in s5pc1xx_rtc_read */
153 if (s->regs[RTC_CON] & TIC_EN) {
154 qemu_irq_raise(s->tick_irq);
155 s->regs[INT_PEND] |= INT_TIC;
156 s5pc1xx_rtc_periodic_update(s);
159 qemu_del_timer(s->periodic_timer);
163 /* Update tick timer frequency */
164 static void s5pc1xx_rtc_periodic_rate(S5pc1xxRTCState *s)
168 /* get four binary digits to determine the frequency */
169 freq_code = (s->regs[RTC_CON] >> TIC_CK_SEL_SHIFT) & 0xF;
171 /* tick timer frequency */
172 s->freq_out = 32768 / (1 << freq_code);
175 /* Month is between 0 and 11 */
176 static int get_days_in_month(int month, int year)
179 static const int days_tab[12] = {
180 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
183 if ((unsigned) month >= 12) {
188 if ((year % 4) == 0) {
195 /* Update 'tm' to the next second */
196 static void s5pc1xx_rtc_next_second(struct tm *tm)
201 if ((unsigned) tm->tm_sec >= 60) {
204 if ((unsigned) tm->tm_min >= 60) {
207 if ((unsigned) tm->tm_hour >= 24) {
211 /* TODO: check if wday value in qemu is between 1 and 7 */
212 if ((unsigned) tm->tm_wday >= 8) {
215 days_in_month = get_days_in_month(tm->tm_mon, tm->tm_year);
217 if (tm->tm_mday < 1) {
219 } else if (tm->tm_mday > days_in_month) {
222 if (tm->tm_mon >= 12) {
232 /* Working with up-to-date time and check alarm */
233 static void s5pc1xx_rtc_second_update(void *opaque)
235 S5pc1xxRTCState *s = (S5pc1xxRTCState *)opaque;
236 uint64_t next_second_time;
238 if (s->regs[RTC_CON] & RTC_EN) {
239 /* check if the alarm is generally enabled */
240 /* then check if an alarm of at least one kind is enabled */
241 if (s->regs[RTC_ALM] & ALM_EN &&
242 (s->regs[RTC_ALM] & SEC_EN ||
243 s->regs[RTC_ALM] & MIN_EN ||
244 s->regs[RTC_ALM] & HOUR_EN ||
245 s->regs[RTC_ALM] & DAY_EN ||
246 s->regs[RTC_ALM] & MON_EN ||
247 s->regs[RTC_ALM] & YEAR_EN)) {
249 /* check alarm values together with corresponding permissive bits */
250 if (((s->regs[ALM_SEC] & 0x7F) ==
251 to_bcd(s->current_tm.tm_sec) ||
252 !(s->regs[RTC_ALM] & SEC_EN)) &&
254 ((s->regs[ALM_MIN] & 0x7F) ==
255 to_bcd(s->current_tm.tm_min) ||
256 !(s->regs[RTC_ALM] & MIN_EN)) &&
258 ((s->regs[ALM_HOUR] & 0x3F) ==
259 to_bcd(s->current_tm.tm_hour) ||
260 !(s->regs[RTC_ALM] & HOUR_EN)) &&
262 ((s->regs[ALM_DAY] & 0x3F) ==
263 to_bcd(s->current_tm.tm_mday) ||
264 !(s->regs[RTC_ALM] & DAY_EN)) &&
266 ((s->regs[ALM_MON] & 0x1F) ==
267 to_bcd(s->current_tm.tm_mon) ||
268 !(s->regs[RTC_ALM] & MON_EN)) &&
270 (((s->regs[ALM_YEAR] & 0xFF) ==
271 to_bcd((s->current_tm.tm_year - 100) % 100) &&
272 ((s->regs[ALM_YEAR] >> 8) & 0xF) ==
273 to_bcd((s->current_tm.tm_year - 100) % 1000 / 100)) ||
274 !(s->regs[RTC_ALM] & YEAR_EN))) {
276 qemu_irq_raise(s->alm_irq);
277 s->regs[INT_PEND] |= INT_ALM;
281 s5pc1xx_rtc_next_second(&s->current_tm);
282 next_second_time = qemu_get_clock(vm_clock) + get_ticks_per_sec();
283 qemu_mod_timer(s->second_timer, next_second_time);
285 qemu_del_timer(s->second_timer);
289 static uint32_t s5pc1xx_rtc_read(void *opaque, target_phys_addr_t offset)
291 S5pc1xxRTCState *s = (S5pc1xxRTCState *)opaque;
301 s5pc1xx_rtc_read_time(s);
313 return s->regs[offset];
315 if (s->freq_out && s->last_tick && s->regs[TIC_CNT]) {
316 s->cur_tic_cnt = s->regs[TIC_CNT] -
317 muldiv64(qemu_get_clock(vm_clock) - s->last_tick,
318 s->freq_out, get_ticks_per_sec()) %
324 return s->cur_tic_cnt;
326 hw_error("s5pc1xx.rtc: bad read offset " TARGET_FMT_plx "\n",
331 static void s5pc1xx_rtc_write(void *opaque, target_phys_addr_t offset,
334 S5pc1xxRTCState *s = (S5pc1xxRTCState *)opaque;
338 /* lower interrupts if any */
339 if (value & INT_TIC) {
340 qemu_irq_lower(s->tick_irq);
342 if (value & INT_ALM) {
343 qemu_irq_lower(s->alm_irq);
346 /* clear INT_* bits if they are set in value */
347 s->regs[INT_PEND] &= ~(value & (INT_TIC | INT_ALM));
350 /* reset tick counter */
351 if (value & CLK_RST) {
352 s5pc1xx_rtc_reset(s);
355 /* start second timer */
356 if ((value & RTC_EN) > (s->regs[RTC_CON] & RTC_EN)) {
357 s->regs[RTC_CON] |= RTC_EN;
358 qemu_get_timedate(&s->current_tm, 0);
359 s5pc1xx_rtc_second_update(s);
361 /* start tick timer */
362 if ((value & TIC_EN) > (s->regs[RTC_CON] & TIC_EN)) {
363 s->regs[RTC_CON] = value;
364 s5pc1xx_rtc_periodic_rate(s);
365 s5pc1xx_rtc_periodic_update(s);
367 } else if ((value & TIC_EN) < (s->regs[RTC_CON] & TIC_EN)) {
368 qemu_del_timer(s->periodic_timer);
370 s->regs[RTC_CON] = value;
371 s5pc1xx_rtc_periodic_rate(s);
381 s->regs[offset] = value;
390 s->regs[offset] = value;
391 /* if in disabled mode, do not update the time */
392 if (s->regs[RTC_CON] & RTC_EN) {
393 s5pc1xx_rtc_set_time(s);
397 hw_error("s5pc1xx.rtc: bad write offset " TARGET_FMT_plx "\n",
402 /* Memory mapped interface */
403 static CPUReadMemoryFunc * const s5pc1xx_rtc_mm_read[] = {
409 static CPUWriteMemoryFunc * const s5pc1xx_rtc_mm_write[] = {
415 static void s5pc1xx_rtc_save(QEMUFile *f, void *opaque)
417 S5pc1xxRTCState *s = (S5pc1xxRTCState *)opaque;
420 s5pc1xx_rtc_read_time(s);
421 for (i = INT_PEND; i <= BCD_YEAR; i++) {
422 qemu_put_be32s(f, &s->regs[i]);
424 qemu_put_timer(f, s->second_timer);
426 qemu_put_be64s(f, &s->last_tick);
427 qemu_put_be32s(f, &s->freq_out);
428 qemu_put_timer(f, s->periodic_timer);
431 static int s5pc1xx_rtc_load(QEMUFile *f, void *opaque, int version_id)
433 S5pc1xxRTCState *s = (S5pc1xxRTCState *)opaque;
436 if (version_id != 1) {
440 for (i = INT_PEND; i <= BCD_YEAR; i++) {
441 qemu_get_be32s(f, &s->regs[i]);
444 //s5pc1xx_rtc_set_time(s);
445 qemu_get_timedate(&s->current_tm, 0);
446 s5pc1xx_rtc_read_time(s);
447 qemu_get_timer(f, s->second_timer);
449 qemu_get_be64s(f, &s->last_tick);
450 qemu_get_be32s(f, &s->freq_out);
451 qemu_get_timer(f, s->periodic_timer);
456 /* initialize and start timers */
457 static int s5pc1xx_rtc_init(SysBusDevice *dev)
460 S5pc1xxRTCState *s = FROM_SYSBUS(S5pc1xxRTCState, dev);
462 sysbus_init_irq(dev, &s->alm_irq);
463 sysbus_init_irq(dev, &s->tick_irq);
466 qemu_new_timer(vm_clock, s5pc1xx_rtc_periodic_tick, s);
468 qemu_new_timer(vm_clock, s5pc1xx_rtc_second_update, s);
471 cpu_register_io_memory(s5pc1xx_rtc_mm_read, s5pc1xx_rtc_mm_write, s, DEVICE_NATIVE_ENDIAN);
472 sysbus_init_mmio(dev, S5PC1XX_RTC_REG_MEM_SIZE, iomemory);
474 s5pc1xx_rtc_reset(s);
476 register_savevm(&dev->qdev, "s5pc1xx.rtc", -1, 1,
477 s5pc1xx_rtc_save, s5pc1xx_rtc_load, s);
482 static void s5pc1xx_rtc_register_devices(void)
484 sysbus_register_dev("s5pc1xx.rtc", sizeof(S5pc1xxRTCState),
488 device_init(s5pc1xx_rtc_register_devices)