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
;
141 case S3C_RTC_ALMHOUR
:
143 case S3C_RTC_ALMDATE
:
147 case S3C_RTC_ALMYEAR
:
155 return to_bcd(s
->tm
.tm_sec
);
158 return to_bcd(s
->tm
.tm_min
);
159 case S3C_RTC_BCDHOUR
:
161 return to_bcd(s
->tm
.tm_hour
);
162 case S3C_RTC_BCDDATE
:
164 return to_bcd(s
->tm
.tm_mday
);
167 return s
->tm
.tm_wday
;
170 return to_bcd(s
->tm
.tm_mon
+ 1);
171 case S3C_RTC_BCDYEAR
:
173 return to_bcd(s
->tm
.tm_year
% 100);
175 printf("%s: Bad register 0x%lx\n", __FUNCTION__
, (unsigned long)addr
);
181 static void s3c_rtc_write(void *opaque
, target_phys_addr_t addr
,
184 struct s3c_rtc_state_s
*s
= (struct s3c_rtc_state_s
*) opaque
;
190 s
->control
= value
& 0xf;
191 s
->enable
= (s
->control
== 0x1);
196 if (s
->tick
& (1 << 7))
209 case S3C_RTC_ALMHOUR
:
212 case S3C_RTC_ALMDATE
:
218 case S3C_RTC_ALMYEAR
:
223 s
->reset
= value
& 0xf;
226 /* XXX This is not very exact time setting */
229 diff
= from_bcd(value
) - s
->tm
.tm_sec
;
234 diff
= from_bcd(value
) - s
->tm
.tm_min
;
237 case S3C_RTC_BCDHOUR
:
239 diff
= from_bcd(value
) - s
->tm
.tm_hour
;
240 s
->sec
+= diff
* 60 * 60;
242 case S3C_RTC_BCDDATE
:
244 diff
= from_bcd(value
) - s
->tm
.tm_mday
;
245 s
->sec
+= diff
* 60 * 60 * 24;
249 diff
= (value
& 7) - s
->tm
.tm_wday
;
250 s
->sec
+= diff
* 60 * 60 * 24;
254 diff
= from_bcd(value
) - s
->tm
.tm_mon
- 1;
255 s
->sec
+= diff
* 60 * 60 * 24 * 30;
257 case S3C_RTC_BCDYEAR
:
259 diff
= from_bcd(value
) - (s
->tm
.tm_year
% 100);
260 s
->sec
+= diff
* 60 * 60 * 24 * 365;
263 printf("%s: Bad register 0x%lx\n", __FUNCTION__
, (unsigned long)addr
);
267 static CPUReadMemoryFunc
*s3c_rtc_readfn
[] = {
273 static CPUWriteMemoryFunc
*s3c_rtc_writefn
[] = {
279 static void s3c_rtc_save(QEMUFile
*f
, void *opaque
)
281 struct s3c_rtc_state_s
*s
= (struct s3c_rtc_state_s
*) opaque
;
282 qemu_put_be64s(f
, &s
->next
);
283 qemu_put_8s(f
, &s
->control
);
284 qemu_put_8s(f
, &s
->tick
);
285 qemu_put_8s(f
, &s
->alarm
);
286 qemu_put_8s(f
, &s
->almsec
);
287 qemu_put_8s(f
, &s
->almmin
);
288 qemu_put_8s(f
, &s
->almday
);
289 qemu_put_8s(f
, &s
->almhour
);
290 qemu_put_8s(f
, &s
->almmon
);
291 qemu_put_8s(f
, &s
->almyear
);
292 qemu_put_8s(f
, &s
->reset
);
293 qemu_put_be32s(f
, &s
->sec
);
296 static int s3c_rtc_load(QEMUFile
*f
, void *opaque
, int version_id
)
298 struct s3c_rtc_state_s
*s
= (struct s3c_rtc_state_s
*) opaque
;
299 qemu_get_be64s(f
, &s
->next
);
300 qemu_get_8s(f
, &s
->control
);
301 qemu_get_8s(f
, &s
->tick
);
302 qemu_get_8s(f
, &s
->alarm
);
303 qemu_get_8s(f
, &s
->almsec
);
304 qemu_get_8s(f
, &s
->almmin
);
305 qemu_get_8s(f
, &s
->almday
);
306 qemu_get_8s(f
, &s
->almhour
);
307 qemu_get_8s(f
, &s
->almmon
);
308 qemu_get_8s(f
, &s
->almyear
);
309 qemu_get_8s(f
, &s
->reset
);
310 qemu_get_be32s(f
, &s
->sec
);
312 s
->enable
= (s
->control
== 0x1);
318 struct s3c_rtc_state_s
*s3c_rtc_init(target_phys_addr_t base
, qemu_irq irq
)
321 struct s3c_rtc_state_s
*s
= (struct s3c_rtc_state_s
*)
322 qemu_mallocz(sizeof(struct s3c_rtc_state_s
));
326 s
->timer
= qemu_new_timer(vm_clock
, s3c_rtc_tick
, s
);
327 s
->hz
= qemu_new_timer(rt_clock
, s3c_rtc_hz
, s
);
330 s
->next
= qemu_get_clock(rt_clock
) + 1000;
331 qemu_mod_timer(s
->hz
, s
->next
);
333 iomemtype
= cpu_register_io_memory(0, s3c_rtc_readfn
,
335 cpu_register_physical_memory(s
->base
, 0xffffff, iomemtype
);
337 register_savevm("s3c24xx_rtc", 0, 0, s3c_rtc_save
, s3c_rtc_load
, s
);