2 * Samsung S3C24xx series Real-Time Clock.
4 * Copyright (c) 2007 OpenMoko, Inc.
5 * Author: Andrzej Zaborowski <andrew@openedhand.com>
7 * This code is licenced under the GNU GPL v2.
11 #include "qemu-timer.h"
15 struct s3c_rtc_state_s
{
16 target_phys_addr_t base
;
37 void s3c_rtc_reset(struct s3c_rtc_state_s
*s
)
55 static void s3c_rtc_tick_mod(struct s3c_rtc_state_s
*s
)
57 qemu_mod_timer(s
->timer
,
58 qemu_get_clock(vm_clock
) + muldiv64((s
->tick
& 0x7f) + 1,
59 ticks_per_sec
, S3C_XTAL_FREQ
));
62 static void s3c_rtc_tick(void *opaque
)
64 struct s3c_rtc_state_s
*s
= (struct s3c_rtc_state_s
*) opaque
;
65 if (!(s
->tick
& (1 << 7)))
67 qemu_irq_raise(s
->irq
);
72 static void s3c_rtc_hz(void *opaque
)
74 struct s3c_rtc_state_s
*s
= (struct s3c_rtc_state_s
*) opaque
;
78 qemu_mod_timer(s
->hz
, s
->next
);
81 static void s3c_rtc_update(struct s3c_rtc_state_s
*s
)
84 qemu_get_timedate(&s
->tm
, 0);
89 ret
= gmtime_r(&ti
, &s
->tm
);
91 ret
= localtime_r(&ti
, &s
->tm
);
95 static inline uint32_t to_bcd(int val
)
97 return ((val
/ 10) << 4) | (val
% 10);
100 static inline int from_bcd(uint32_t val
)
102 return ((val
>> 4) * 10) + (val
& 0x0f);
105 #define S3C_RTC_CON 0x40 /* RTC Control register */
106 #define S3C_RTC_TICNT 0x44 /* Tick Time Count register */
107 #define S3C_RTC_ALM 0x50 /* RTC Alarm Control register */
108 #define S3C_RTC_ALMSEC 0x54 /* Alarm Second Data register */
109 #define S3C_RTC_ALMMIN 0x58 /* Alarm Minute Data register */
110 #define S3C_RTC_ALMHOUR 0x5c /* Alarm Hour Data register */
111 #define S3C_RTC_ALMDATE 0x60 /* Alarm Date Data register */
112 #define S3C_RTC_ALMMON 0x64 /* Alarm Month Data register */
113 #define S3C_RTC_ALMYEAR 0x68 /* Alarm Year Data register */
114 #define S3C_RTC_RST 0x6c /* RTC Round Reset register */
115 #define S3C_RTC_BCDSEC 0x70 /* RTC BCD Second register */
116 #define S3C_RTC_BCDMIN 0x74 /* RTC BCD Minute register */
117 #define S3C_RTC_BCDHOUR 0x78 /* RTC BCD Hour register */
118 #define S3C_RTC_BCDDATE 0x7c /* RTC BCD Day register */
119 #define S3C_RTC_BCDDAY 0x80 /* RTC BCD Day register */
120 #define S3C_RTC_BCDMON 0x84 /* RTC BCD Month register */
121 #define S3C_RTC_BCDYEAR 0x88 /* RTC BCD Year register */
123 static uint32_t s3c_rtc_read(void *opaque
, target_phys_addr_t addr
)
125 struct s3c_rtc_state_s
*s
= (struct s3c_rtc_state_s
*) opaque
;
140 case S3C_RTC_ALMHOUR
:
142 case S3C_RTC_ALMDATE
:
146 case S3C_RTC_ALMYEAR
:
154 return to_bcd(s
->tm
.tm_sec
);
157 return to_bcd(s
->tm
.tm_min
);
158 case S3C_RTC_BCDHOUR
:
160 return to_bcd(s
->tm
.tm_hour
);
161 case S3C_RTC_BCDDATE
:
163 return to_bcd(s
->tm
.tm_mday
);
166 return s
->tm
.tm_wday
;
169 return to_bcd(s
->tm
.tm_mon
+ 1);
170 case S3C_RTC_BCDYEAR
:
172 return to_bcd(s
->tm
.tm_year
% 100);
174 printf("%s: Bad register 0x%lx\n", __FUNCTION__
, (unsigned long)addr
);
180 static void s3c_rtc_write(void *opaque
, target_phys_addr_t addr
,
183 struct s3c_rtc_state_s
*s
= (struct s3c_rtc_state_s
*) opaque
;
188 s
->control
= value
& 0xf;
189 s
->enable
= (s
->control
== 0x1);
194 if (s
->tick
& (1 << 7))
207 case S3C_RTC_ALMHOUR
:
210 case S3C_RTC_ALMDATE
:
216 case S3C_RTC_ALMYEAR
:
221 s
->reset
= value
& 0xf;
224 /* XXX This is not very exact time setting */
227 diff
= from_bcd(value
) - s
->tm
.tm_sec
;
232 diff
= from_bcd(value
) - s
->tm
.tm_min
;
235 case S3C_RTC_BCDHOUR
:
237 diff
= from_bcd(value
) - s
->tm
.tm_hour
;
238 s
->sec
+= diff
* 60 * 60;
240 case S3C_RTC_BCDDATE
:
242 diff
= from_bcd(value
) - s
->tm
.tm_mday
;
243 s
->sec
+= diff
* 60 * 60 * 24;
247 diff
= (value
& 7) - s
->tm
.tm_wday
;
248 s
->sec
+= diff
* 60 * 60 * 24;
252 diff
= from_bcd(value
) - s
->tm
.tm_mon
- 1;
253 s
->sec
+= diff
* 60 * 60 * 24 * 30;
255 case S3C_RTC_BCDYEAR
:
257 diff
= from_bcd(value
) - (s
->tm
.tm_year
% 100);
258 s
->sec
+= diff
* 60 * 60 * 24 * 365;
261 printf("%s: Bad register 0x%lx\n", __FUNCTION__
, (unsigned long)addr
);
265 static CPUReadMemoryFunc
*s3c_rtc_readfn
[] = {
271 static CPUWriteMemoryFunc
*s3c_rtc_writefn
[] = {
277 static void s3c_rtc_save(QEMUFile
*f
, void *opaque
)
279 struct s3c_rtc_state_s
*s
= (struct s3c_rtc_state_s
*) opaque
;
280 qemu_put_be64s(f
, &s
->next
);
281 qemu_put_8s(f
, &s
->control
);
282 qemu_put_8s(f
, &s
->tick
);
283 qemu_put_8s(f
, &s
->alarm
);
284 qemu_put_8s(f
, &s
->almsec
);
285 qemu_put_8s(f
, &s
->almmin
);
286 qemu_put_8s(f
, &s
->almday
);
287 qemu_put_8s(f
, &s
->almhour
);
288 qemu_put_8s(f
, &s
->almmon
);
289 qemu_put_8s(f
, &s
->almyear
);
290 qemu_put_8s(f
, &s
->reset
);
291 qemu_put_be32s(f
, &s
->sec
);
294 static int s3c_rtc_load(QEMUFile
*f
, void *opaque
, int version_id
)
296 struct s3c_rtc_state_s
*s
= (struct s3c_rtc_state_s
*) opaque
;
297 qemu_get_be64s(f
, &s
->next
);
298 qemu_get_8s(f
, &s
->control
);
299 qemu_get_8s(f
, &s
->tick
);
300 qemu_get_8s(f
, &s
->alarm
);
301 qemu_get_8s(f
, &s
->almsec
);
302 qemu_get_8s(f
, &s
->almmin
);
303 qemu_get_8s(f
, &s
->almday
);
304 qemu_get_8s(f
, &s
->almhour
);
305 qemu_get_8s(f
, &s
->almmon
);
306 qemu_get_8s(f
, &s
->almyear
);
307 qemu_get_8s(f
, &s
->reset
);
308 qemu_get_be32s(f
, &s
->sec
);
310 s
->enable
= (s
->control
== 0x1);
316 struct s3c_rtc_state_s
*s3c_rtc_init(target_phys_addr_t base
, qemu_irq irq
)
319 struct s3c_rtc_state_s
*s
= (struct s3c_rtc_state_s
*)
320 qemu_mallocz(sizeof(struct s3c_rtc_state_s
));
324 s
->timer
= qemu_new_timer(vm_clock
, s3c_rtc_tick
, s
);
325 s
->hz
= qemu_new_timer(rt_clock
, s3c_rtc_hz
, s
);
328 s
->next
= qemu_get_clock(rt_clock
) + 1000;
329 qemu_mod_timer(s
->hz
, s
->next
);
331 iomemtype
= cpu_register_io_memory(0, s3c_rtc_readfn
,
333 cpu_register_physical_memory(s
->base
, 0xffffff, iomemtype
);
335 register_savevm("s3c24xx_rtc", 0, 0, s3c_rtc_save
, s3c_rtc_load
, s
);