]> git.proxmox.com Git - qemu.git/blame - hw/mc146818rtc.c
sun4u: give ISA bus to ISA methods
[qemu.git] / hw / mc146818rtc.c
CommitLineData
80cabfad
FB
1/*
2 * QEMU MC146818 RTC emulation
5fafdf24 3 *
80cabfad 4 * Copyright (c) 2003-2004 Fabrice Bellard
5fafdf24 5 *
80cabfad
FB
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 * THE SOFTWARE.
23 */
87ecb68b
PB
24#include "hw.h"
25#include "qemu-timer.h"
26#include "sysemu.h"
27#include "pc.h"
aa28b9bf 28#include "apic.h"
87ecb68b 29#include "isa.h"
1d914fa0 30#include "mc146818rtc.h"
80cabfad
FB
31
32//#define DEBUG_CMOS
aa6f63ff 33//#define DEBUG_COALESCED
80cabfad 34
ec51e364
IY
35#ifdef DEBUG_CMOS
36# define CMOS_DPRINTF(format, ...) printf(format, ## __VA_ARGS__)
37#else
38# define CMOS_DPRINTF(format, ...) do { } while (0)
39#endif
40
aa6f63ff
BS
41#ifdef DEBUG_COALESCED
42# define DPRINTF_C(format, ...) printf(format, ## __VA_ARGS__)
43#else
44# define DPRINTF_C(format, ...) do { } while (0)
45#endif
46
dd17765b 47#define RTC_REINJECT_ON_ACK_COUNT 20
ba32edab 48
80cabfad
FB
49#define RTC_SECONDS 0
50#define RTC_SECONDS_ALARM 1
51#define RTC_MINUTES 2
52#define RTC_MINUTES_ALARM 3
53#define RTC_HOURS 4
54#define RTC_HOURS_ALARM 5
55#define RTC_ALARM_DONT_CARE 0xC0
56
57#define RTC_DAY_OF_WEEK 6
58#define RTC_DAY_OF_MONTH 7
59#define RTC_MONTH 8
60#define RTC_YEAR 9
61
62#define RTC_REG_A 10
63#define RTC_REG_B 11
64#define RTC_REG_C 12
65#define RTC_REG_D 13
66
dff38e7b 67#define REG_A_UIP 0x80
80cabfad 68
100d9891
AJ
69#define REG_B_SET 0x80
70#define REG_B_PIE 0x40
71#define REG_B_AIE 0x20
72#define REG_B_UIE 0x10
73#define REG_B_SQWE 0x08
74#define REG_B_DM 0x04
c29cd656 75#define REG_B_24H 0x02
dff38e7b 76
72716184
AL
77#define REG_C_UF 0x10
78#define REG_C_IRQF 0x80
79#define REG_C_PF 0x40
80#define REG_C_AF 0x20
81
1d914fa0 82typedef struct RTCState {
32e0c826 83 ISADevice dev;
b2c5009b 84 MemoryRegion io;
dff38e7b
FB
85 uint8_t cmos_data[128];
86 uint8_t cmos_index;
43f493af 87 struct tm current_tm;
32e0c826 88 int32_t base_year;
d537cf6c 89 qemu_irq irq;
100d9891 90 qemu_irq sqw_irq;
18c6e2ff 91 int it_shift;
dff38e7b
FB
92 /* periodic timer */
93 QEMUTimer *periodic_timer;
94 int64_t next_periodic_time;
95 /* second update */
96 int64_t next_second_time;
ba32edab 97 uint16_t irq_reinject_on_ack_count;
73822ec8
AL
98 uint32_t irq_coalesced;
99 uint32_t period;
93b66569 100 QEMUTimer *coalesced_timer;
dff38e7b
FB
101 QEMUTimer *second_timer;
102 QEMUTimer *second_timer2;
17604dac 103 Notifier clock_reset_notifier;
1d914fa0 104} RTCState;
dff38e7b
FB
105
106static void rtc_set_time(RTCState *s);
dff38e7b
FB
107static void rtc_copy_date(RTCState *s);
108
93b66569
AL
109#ifdef TARGET_I386
110static void rtc_coalesced_timer_update(RTCState *s)
111{
112 if (s->irq_coalesced == 0) {
113 qemu_del_timer(s->coalesced_timer);
114 } else {
115 /* divide each RTC interval to 2 - 8 smaller intervals */
116 int c = MIN(s->irq_coalesced, 7) + 1;
74475455 117 int64_t next_clock = qemu_get_clock_ns(rtc_clock) +
6875204c 118 muldiv64(s->period / c, get_ticks_per_sec(), 32768);
93b66569
AL
119 qemu_mod_timer(s->coalesced_timer, next_clock);
120 }
121}
122
123static void rtc_coalesced_timer(void *opaque)
124{
125 RTCState *s = opaque;
126
127 if (s->irq_coalesced != 0) {
128 apic_reset_irq_delivered();
129 s->cmos_data[RTC_REG_C] |= 0xc0;
aa6f63ff 130 DPRINTF_C("cmos: injecting from timer\n");
7d932dfd 131 qemu_irq_raise(s->irq);
93b66569
AL
132 if (apic_get_irq_delivered()) {
133 s->irq_coalesced--;
aa6f63ff
BS
134 DPRINTF_C("cmos: coalesced irqs decreased to %d\n",
135 s->irq_coalesced);
93b66569
AL
136 }
137 }
138
139 rtc_coalesced_timer_update(s);
140}
141#endif
142
dff38e7b
FB
143static void rtc_timer_update(RTCState *s, int64_t current_time)
144{
145 int period_code, period;
146 int64_t cur_clock, next_irq_clock;
147
148 period_code = s->cmos_data[RTC_REG_A] & 0x0f;
100d9891 149 if (period_code != 0
7d932dfd 150 && ((s->cmos_data[RTC_REG_B] & REG_B_PIE)
100d9891 151 || ((s->cmos_data[RTC_REG_B] & REG_B_SQWE) && s->sqw_irq))) {
dff38e7b
FB
152 if (period_code <= 2)
153 period_code += 7;
154 /* period in 32 Khz cycles */
155 period = 1 << (period_code - 1);
73822ec8 156#ifdef TARGET_I386
aa6f63ff 157 if (period != s->period) {
73822ec8 158 s->irq_coalesced = (s->irq_coalesced * s->period) / period;
aa6f63ff
BS
159 DPRINTF_C("cmos: coalesced irqs scaled to %d\n", s->irq_coalesced);
160 }
73822ec8
AL
161 s->period = period;
162#endif
dff38e7b 163 /* compute 32 khz clock */
6ee093c9 164 cur_clock = muldiv64(current_time, 32768, get_ticks_per_sec());
dff38e7b 165 next_irq_clock = (cur_clock & ~(period - 1)) + period;
6875204c
JK
166 s->next_periodic_time =
167 muldiv64(next_irq_clock, get_ticks_per_sec(), 32768) + 1;
dff38e7b
FB
168 qemu_mod_timer(s->periodic_timer, s->next_periodic_time);
169 } else {
73822ec8
AL
170#ifdef TARGET_I386
171 s->irq_coalesced = 0;
172#endif
dff38e7b
FB
173 qemu_del_timer(s->periodic_timer);
174 }
175}
176
177static void rtc_periodic_timer(void *opaque)
178{
179 RTCState *s = opaque;
180
181 rtc_timer_update(s, s->next_periodic_time);
100d9891
AJ
182 if (s->cmos_data[RTC_REG_B] & REG_B_PIE) {
183 s->cmos_data[RTC_REG_C] |= 0xc0;
93b66569
AL
184#ifdef TARGET_I386
185 if(rtc_td_hack) {
ba32edab
GN
186 if (s->irq_reinject_on_ack_count >= RTC_REINJECT_ON_ACK_COUNT)
187 s->irq_reinject_on_ack_count = 0;
93b66569 188 apic_reset_irq_delivered();
7d932dfd 189 qemu_irq_raise(s->irq);
93b66569
AL
190 if (!apic_get_irq_delivered()) {
191 s->irq_coalesced++;
192 rtc_coalesced_timer_update(s);
aa6f63ff
BS
193 DPRINTF_C("cmos: coalesced irqs increased to %d\n",
194 s->irq_coalesced);
93b66569
AL
195 }
196 } else
197#endif
7d932dfd 198 qemu_irq_raise(s->irq);
100d9891
AJ
199 }
200 if (s->cmos_data[RTC_REG_B] & REG_B_SQWE) {
201 /* Not square wave at all but we don't want 2048Hz interrupts!
202 Must be seen as a pulse. */
203 qemu_irq_raise(s->sqw_irq);
204 }
dff38e7b 205}
80cabfad 206
b41a2cd1 207static void cmos_ioport_write(void *opaque, uint32_t addr, uint32_t data)
80cabfad 208{
b41a2cd1 209 RTCState *s = opaque;
80cabfad
FB
210
211 if ((addr & 1) == 0) {
212 s->cmos_index = data & 0x7f;
213 } else {
ec51e364
IY
214 CMOS_DPRINTF("cmos: write index=0x%02x val=0x%02x\n",
215 s->cmos_index, data);
dff38e7b 216 switch(s->cmos_index) {
80cabfad
FB
217 case RTC_SECONDS_ALARM:
218 case RTC_MINUTES_ALARM:
219 case RTC_HOURS_ALARM:
80cabfad
FB
220 s->cmos_data[s->cmos_index] = data;
221 break;
222 case RTC_SECONDS:
223 case RTC_MINUTES:
224 case RTC_HOURS:
225 case RTC_DAY_OF_WEEK:
226 case RTC_DAY_OF_MONTH:
227 case RTC_MONTH:
228 case RTC_YEAR:
229 s->cmos_data[s->cmos_index] = data;
dff38e7b
FB
230 /* if in set mode, do not update the time */
231 if (!(s->cmos_data[RTC_REG_B] & REG_B_SET)) {
232 rtc_set_time(s);
233 }
80cabfad
FB
234 break;
235 case RTC_REG_A:
dff38e7b
FB
236 /* UIP bit is read only */
237 s->cmos_data[RTC_REG_A] = (data & ~REG_A_UIP) |
238 (s->cmos_data[RTC_REG_A] & REG_A_UIP);
74475455 239 rtc_timer_update(s, qemu_get_clock_ns(rtc_clock));
dff38e7b 240 break;
80cabfad 241 case RTC_REG_B:
dff38e7b
FB
242 if (data & REG_B_SET) {
243 /* set mode: reset UIP mode */
244 s->cmos_data[RTC_REG_A] &= ~REG_A_UIP;
245 data &= ~REG_B_UIE;
246 } else {
247 /* if disabling set mode, update the time */
248 if (s->cmos_data[RTC_REG_B] & REG_B_SET) {
249 rtc_set_time(s);
250 }
251 }
51e08f3e
AJ
252 if (((s->cmos_data[RTC_REG_B] ^ data) & (REG_B_DM | REG_B_24H)) &&
253 !(data & REG_B_SET)) {
254 /* If the time format has changed and not in set mode,
255 update the registers immediately. */
256 s->cmos_data[RTC_REG_B] = data;
257 rtc_copy_date(s);
258 } else {
259 s->cmos_data[RTC_REG_B] = data;
260 }
74475455 261 rtc_timer_update(s, qemu_get_clock_ns(rtc_clock));
80cabfad
FB
262 break;
263 case RTC_REG_C:
264 case RTC_REG_D:
265 /* cannot write to them */
266 break;
267 default:
268 s->cmos_data[s->cmos_index] = data;
269 break;
270 }
271 }
272}
273
abd0c6bd 274static inline int rtc_to_bcd(RTCState *s, int a)
80cabfad 275{
6f1bf24d 276 if (s->cmos_data[RTC_REG_B] & REG_B_DM) {
dff38e7b
FB
277 return a;
278 } else {
279 return ((a / 10) << 4) | (a % 10);
280 }
80cabfad
FB
281}
282
abd0c6bd 283static inline int rtc_from_bcd(RTCState *s, int a)
80cabfad 284{
6f1bf24d 285 if (s->cmos_data[RTC_REG_B] & REG_B_DM) {
dff38e7b
FB
286 return a;
287 } else {
288 return ((a >> 4) * 10) + (a & 0x0f);
289 }
290}
291
292static void rtc_set_time(RTCState *s)
293{
43f493af 294 struct tm *tm = &s->current_tm;
dff38e7b 295
abd0c6bd
PB
296 tm->tm_sec = rtc_from_bcd(s, s->cmos_data[RTC_SECONDS]);
297 tm->tm_min = rtc_from_bcd(s, s->cmos_data[RTC_MINUTES]);
298 tm->tm_hour = rtc_from_bcd(s, s->cmos_data[RTC_HOURS] & 0x7f);
c29cd656 299 if (!(s->cmos_data[RTC_REG_B] & REG_B_24H) &&
43f493af
FB
300 (s->cmos_data[RTC_HOURS] & 0x80)) {
301 tm->tm_hour += 12;
302 }
abd0c6bd
PB
303 tm->tm_wday = rtc_from_bcd(s, s->cmos_data[RTC_DAY_OF_WEEK]) - 1;
304 tm->tm_mday = rtc_from_bcd(s, s->cmos_data[RTC_DAY_OF_MONTH]);
305 tm->tm_mon = rtc_from_bcd(s, s->cmos_data[RTC_MONTH]) - 1;
306 tm->tm_year = rtc_from_bcd(s, s->cmos_data[RTC_YEAR]) + s->base_year - 1900;
80cd3478
LC
307
308 rtc_change_mon_event(tm);
43f493af
FB
309}
310
311static void rtc_copy_date(RTCState *s)
312{
313 const struct tm *tm = &s->current_tm;
42fc73a1 314 int year;
dff38e7b 315
abd0c6bd
PB
316 s->cmos_data[RTC_SECONDS] = rtc_to_bcd(s, tm->tm_sec);
317 s->cmos_data[RTC_MINUTES] = rtc_to_bcd(s, tm->tm_min);
c29cd656 318 if (s->cmos_data[RTC_REG_B] & REG_B_24H) {
43f493af 319 /* 24 hour format */
abd0c6bd 320 s->cmos_data[RTC_HOURS] = rtc_to_bcd(s, tm->tm_hour);
43f493af
FB
321 } else {
322 /* 12 hour format */
abd0c6bd 323 s->cmos_data[RTC_HOURS] = rtc_to_bcd(s, tm->tm_hour % 12);
43f493af
FB
324 if (tm->tm_hour >= 12)
325 s->cmos_data[RTC_HOURS] |= 0x80;
326 }
abd0c6bd
PB
327 s->cmos_data[RTC_DAY_OF_WEEK] = rtc_to_bcd(s, tm->tm_wday + 1);
328 s->cmos_data[RTC_DAY_OF_MONTH] = rtc_to_bcd(s, tm->tm_mday);
329 s->cmos_data[RTC_MONTH] = rtc_to_bcd(s, tm->tm_mon + 1);
42fc73a1
AJ
330 year = (tm->tm_year - s->base_year) % 100;
331 if (year < 0)
332 year += 100;
abd0c6bd 333 s->cmos_data[RTC_YEAR] = rtc_to_bcd(s, year);
43f493af
FB
334}
335
336/* month is between 0 and 11. */
337static int get_days_in_month(int month, int year)
338{
5fafdf24
TS
339 static const int days_tab[12] = {
340 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
43f493af
FB
341 };
342 int d;
343 if ((unsigned )month >= 12)
344 return 31;
345 d = days_tab[month];
346 if (month == 1) {
347 if ((year % 4) == 0 && ((year % 100) != 0 || (year % 400) == 0))
348 d++;
349 }
350 return d;
351}
352
353/* update 'tm' to the next second */
354static void rtc_next_second(struct tm *tm)
355{
356 int days_in_month;
357
358 tm->tm_sec++;
359 if ((unsigned)tm->tm_sec >= 60) {
360 tm->tm_sec = 0;
361 tm->tm_min++;
362 if ((unsigned)tm->tm_min >= 60) {
363 tm->tm_min = 0;
364 tm->tm_hour++;
365 if ((unsigned)tm->tm_hour >= 24) {
366 tm->tm_hour = 0;
367 /* next day */
368 tm->tm_wday++;
369 if ((unsigned)tm->tm_wday >= 7)
370 tm->tm_wday = 0;
5fafdf24 371 days_in_month = get_days_in_month(tm->tm_mon,
43f493af
FB
372 tm->tm_year + 1900);
373 tm->tm_mday++;
374 if (tm->tm_mday < 1) {
375 tm->tm_mday = 1;
376 } else if (tm->tm_mday > days_in_month) {
377 tm->tm_mday = 1;
378 tm->tm_mon++;
379 if (tm->tm_mon >= 12) {
380 tm->tm_mon = 0;
381 tm->tm_year++;
382 }
383 }
384 }
385 }
386 }
dff38e7b
FB
387}
388
43f493af 389
dff38e7b
FB
390static void rtc_update_second(void *opaque)
391{
392 RTCState *s = opaque;
4721c457 393 int64_t delay;
dff38e7b
FB
394
395 /* if the oscillator is not in normal operation, we do not update */
396 if ((s->cmos_data[RTC_REG_A] & 0x70) != 0x20) {
6ee093c9 397 s->next_second_time += get_ticks_per_sec();
dff38e7b
FB
398 qemu_mod_timer(s->second_timer, s->next_second_time);
399 } else {
43f493af 400 rtc_next_second(&s->current_tm);
3b46e624 401
dff38e7b
FB
402 if (!(s->cmos_data[RTC_REG_B] & REG_B_SET)) {
403 /* update in progress bit */
404 s->cmos_data[RTC_REG_A] |= REG_A_UIP;
405 }
4721c457
FB
406 /* should be 244 us = 8 / 32768 seconds, but currently the
407 timers do not have the necessary resolution. */
6ee093c9 408 delay = (get_ticks_per_sec() * 1) / 100;
4721c457
FB
409 if (delay < 1)
410 delay = 1;
5fafdf24 411 qemu_mod_timer(s->second_timer2,
4721c457 412 s->next_second_time + delay);
dff38e7b
FB
413 }
414}
415
416static void rtc_update_second2(void *opaque)
417{
418 RTCState *s = opaque;
dff38e7b
FB
419
420 if (!(s->cmos_data[RTC_REG_B] & REG_B_SET)) {
421 rtc_copy_date(s);
422 }
423
424 /* check alarm */
425 if (s->cmos_data[RTC_REG_B] & REG_B_AIE) {
426 if (((s->cmos_data[RTC_SECONDS_ALARM] & 0xc0) == 0xc0 ||
f292787d 427 rtc_from_bcd(s, s->cmos_data[RTC_SECONDS_ALARM]) == s->current_tm.tm_sec) &&
dff38e7b 428 ((s->cmos_data[RTC_MINUTES_ALARM] & 0xc0) == 0xc0 ||
f292787d 429 rtc_from_bcd(s, s->cmos_data[RTC_MINUTES_ALARM]) == s->current_tm.tm_min) &&
dff38e7b 430 ((s->cmos_data[RTC_HOURS_ALARM] & 0xc0) == 0xc0 ||
f292787d 431 rtc_from_bcd(s, s->cmos_data[RTC_HOURS_ALARM]) == s->current_tm.tm_hour)) {
dff38e7b 432
5fafdf24 433 s->cmos_data[RTC_REG_C] |= 0xa0;
7d932dfd 434 qemu_irq_raise(s->irq);
dff38e7b
FB
435 }
436 }
437
438 /* update ended interrupt */
98815437 439 s->cmos_data[RTC_REG_C] |= REG_C_UF;
dff38e7b 440 if (s->cmos_data[RTC_REG_B] & REG_B_UIE) {
7d932dfd
JK
441 s->cmos_data[RTC_REG_C] |= REG_C_IRQF;
442 qemu_irq_raise(s->irq);
dff38e7b
FB
443 }
444
445 /* clear update in progress bit */
446 s->cmos_data[RTC_REG_A] &= ~REG_A_UIP;
447
6ee093c9 448 s->next_second_time += get_ticks_per_sec();
dff38e7b 449 qemu_mod_timer(s->second_timer, s->next_second_time);
80cabfad
FB
450}
451
b41a2cd1 452static uint32_t cmos_ioport_read(void *opaque, uint32_t addr)
80cabfad 453{
b41a2cd1 454 RTCState *s = opaque;
80cabfad
FB
455 int ret;
456 if ((addr & 1) == 0) {
457 return 0xff;
458 } else {
459 switch(s->cmos_index) {
460 case RTC_SECONDS:
461 case RTC_MINUTES:
462 case RTC_HOURS:
463 case RTC_DAY_OF_WEEK:
464 case RTC_DAY_OF_MONTH:
465 case RTC_MONTH:
466 case RTC_YEAR:
80cabfad
FB
467 ret = s->cmos_data[s->cmos_index];
468 break;
469 case RTC_REG_A:
470 ret = s->cmos_data[s->cmos_index];
80cabfad
FB
471 break;
472 case RTC_REG_C:
473 ret = s->cmos_data[s->cmos_index];
d537cf6c 474 qemu_irq_lower(s->irq);
ba32edab
GN
475#ifdef TARGET_I386
476 if(s->irq_coalesced &&
477 s->irq_reinject_on_ack_count < RTC_REINJECT_ON_ACK_COUNT) {
478 s->irq_reinject_on_ack_count++;
479 apic_reset_irq_delivered();
aa6f63ff 480 DPRINTF_C("cmos: injecting on ack\n");
ba32edab 481 qemu_irq_raise(s->irq);
aa6f63ff 482 if (apic_get_irq_delivered()) {
ba32edab 483 s->irq_coalesced--;
aa6f63ff
BS
484 DPRINTF_C("cmos: coalesced irqs decreased to %d\n",
485 s->irq_coalesced);
486 }
ba32edab
GN
487 break;
488 }
489#endif
490
5fafdf24 491 s->cmos_data[RTC_REG_C] = 0x00;
80cabfad
FB
492 break;
493 default:
494 ret = s->cmos_data[s->cmos_index];
495 break;
496 }
ec51e364
IY
497 CMOS_DPRINTF("cmos: read index=0x%02x val=0x%02x\n",
498 s->cmos_index, ret);
80cabfad
FB
499 return ret;
500 }
501}
502
1d914fa0 503void rtc_set_memory(ISADevice *dev, int addr, int val)
dff38e7b 504{
1d914fa0 505 RTCState *s = DO_UPCAST(RTCState, dev, dev);
dff38e7b
FB
506 if (addr >= 0 && addr <= 127)
507 s->cmos_data[addr] = val;
508}
509
1d914fa0 510void rtc_set_date(ISADevice *dev, const struct tm *tm)
dff38e7b 511{
1d914fa0 512 RTCState *s = DO_UPCAST(RTCState, dev, dev);
43f493af 513 s->current_tm = *tm;
dff38e7b
FB
514 rtc_copy_date(s);
515}
516
ea55ffb3
TS
517/* PC cmos mappings */
518#define REG_IBM_CENTURY_BYTE 0x32
519#define REG_IBM_PS2_CENTURY_BYTE 0x37
520
1d914fa0 521static void rtc_set_date_from_host(ISADevice *dev)
ea55ffb3 522{
1d914fa0 523 RTCState *s = DO_UPCAST(RTCState, dev, dev);
f6503059 524 struct tm tm;
ea55ffb3
TS
525 int val;
526
527 /* set the CMOS date */
f6503059 528 qemu_get_timedate(&tm, 0);
1d914fa0 529 rtc_set_date(dev, &tm);
ea55ffb3 530
abd0c6bd 531 val = rtc_to_bcd(s, (tm.tm_year / 100) + 19);
1d914fa0
IY
532 rtc_set_memory(dev, REG_IBM_CENTURY_BYTE, val);
533 rtc_set_memory(dev, REG_IBM_PS2_CENTURY_BYTE, val);
ea55ffb3
TS
534}
535
6b075b8a 536static int rtc_post_load(void *opaque, int version_id)
80cabfad 537{
6b075b8a 538#ifdef TARGET_I386
dff38e7b
FB
539 RTCState *s = opaque;
540
048c74c4 541 if (version_id >= 2) {
048c74c4
JQ
542 if (rtc_td_hack) {
543 rtc_coalesced_timer_update(s);
544 }
048c74c4 545 }
6b075b8a 546#endif
73822ec8
AL
547 return 0;
548}
73822ec8 549
6b075b8a
JQ
550static const VMStateDescription vmstate_rtc = {
551 .name = "mc146818rtc",
552 .version_id = 2,
553 .minimum_version_id = 1,
554 .minimum_version_id_old = 1,
555 .post_load = rtc_post_load,
556 .fields = (VMStateField []) {
557 VMSTATE_BUFFER(cmos_data, RTCState),
558 VMSTATE_UINT8(cmos_index, RTCState),
559 VMSTATE_INT32(current_tm.tm_sec, RTCState),
560 VMSTATE_INT32(current_tm.tm_min, RTCState),
561 VMSTATE_INT32(current_tm.tm_hour, RTCState),
562 VMSTATE_INT32(current_tm.tm_wday, RTCState),
563 VMSTATE_INT32(current_tm.tm_mday, RTCState),
564 VMSTATE_INT32(current_tm.tm_mon, RTCState),
565 VMSTATE_INT32(current_tm.tm_year, RTCState),
566 VMSTATE_TIMER(periodic_timer, RTCState),
567 VMSTATE_INT64(next_periodic_time, RTCState),
568 VMSTATE_INT64(next_second_time, RTCState),
569 VMSTATE_TIMER(second_timer, RTCState),
570 VMSTATE_TIMER(second_timer2, RTCState),
571 VMSTATE_UINT32_V(irq_coalesced, RTCState, 2),
572 VMSTATE_UINT32_V(period, RTCState, 2),
573 VMSTATE_END_OF_LIST()
574 }
575};
576
17604dac
JK
577static void rtc_notify_clock_reset(Notifier *notifier, void *data)
578{
579 RTCState *s = container_of(notifier, RTCState, clock_reset_notifier);
580 int64_t now = *(int64_t *)data;
581
582 rtc_set_date_from_host(&s->dev);
583 s->next_second_time = now + (get_ticks_per_sec() * 99) / 100;
584 qemu_mod_timer(s->second_timer2, s->next_second_time);
585 rtc_timer_update(s, now);
586#ifdef TARGET_I386
587 if (rtc_td_hack) {
588 rtc_coalesced_timer_update(s);
589 }
590#endif
591}
592
eeb7c03c
GN
593static void rtc_reset(void *opaque)
594{
595 RTCState *s = opaque;
596
72716184
AL
597 s->cmos_data[RTC_REG_B] &= ~(REG_B_PIE | REG_B_AIE | REG_B_SQWE);
598 s->cmos_data[RTC_REG_C] &= ~(REG_C_UF | REG_C_IRQF | REG_C_PF | REG_C_AF);
eeb7c03c 599
72716184 600 qemu_irq_lower(s->irq);
eeb7c03c
GN
601
602#ifdef TARGET_I386
603 if (rtc_td_hack)
604 s->irq_coalesced = 0;
605#endif
606}
607
b2c5009b
RH
608static const MemoryRegionPortio cmos_portio[] = {
609 {0, 2, 1, .read = cmos_ioport_read, .write = cmos_ioport_write },
610 PORTIO_END_OF_LIST(),
611};
612
613static const MemoryRegionOps cmos_ops = {
614 .old_portio = cmos_portio
615};
616
18297050
AL
617// FIXME add int32 visitor
618static void visit_type_int32(Visitor *v, int *value, const char *name, Error **errp)
619{
620 int64_t val = *value;
621 visit_type_int(v, &val, name, errp);
622}
623
624static void rtc_get_date(DeviceState *dev, Visitor *v, void *opaque,
625 const char *name, Error **errp)
626{
627 ISADevice *isa = DO_UPCAST(ISADevice, qdev, dev);
628 RTCState *s = DO_UPCAST(RTCState, dev, isa);
629
630 visit_start_struct(v, NULL, "struct tm", name, 0, errp);
631 visit_type_int32(v, &s->current_tm.tm_year, "tm_year", errp);
632 visit_type_int32(v, &s->current_tm.tm_mon, "tm_mon", errp);
633 visit_type_int32(v, &s->current_tm.tm_mday, "tm_mday", errp);
634 visit_type_int32(v, &s->current_tm.tm_hour, "tm_hour", errp);
635 visit_type_int32(v, &s->current_tm.tm_min, "tm_min", errp);
636 visit_type_int32(v, &s->current_tm.tm_sec, "tm_sec", errp);
637 visit_end_struct(v, errp);
638}
639
32e0c826 640static int rtc_initfn(ISADevice *dev)
dff38e7b 641{
32e0c826
GH
642 RTCState *s = DO_UPCAST(RTCState, dev, dev);
643 int base = 0x70;
80cabfad 644
80cabfad
FB
645 s->cmos_data[RTC_REG_A] = 0x26;
646 s->cmos_data[RTC_REG_B] = 0x02;
647 s->cmos_data[RTC_REG_C] = 0x00;
648 s->cmos_data[RTC_REG_D] = 0x80;
649
1d914fa0 650 rtc_set_date_from_host(dev);
ea55ffb3 651
74475455 652 s->periodic_timer = qemu_new_timer_ns(rtc_clock, rtc_periodic_timer, s);
93b66569
AL
653#ifdef TARGET_I386
654 if (rtc_td_hack)
6875204c 655 s->coalesced_timer =
74475455 656 qemu_new_timer_ns(rtc_clock, rtc_coalesced_timer, s);
93b66569 657#endif
74475455
PB
658 s->second_timer = qemu_new_timer_ns(rtc_clock, rtc_update_second, s);
659 s->second_timer2 = qemu_new_timer_ns(rtc_clock, rtc_update_second2, s);
dff38e7b 660
17604dac
JK
661 s->clock_reset_notifier.notify = rtc_notify_clock_reset;
662 qemu_register_clock_reset_notifier(rtc_clock, &s->clock_reset_notifier);
663
6875204c 664 s->next_second_time =
74475455 665 qemu_get_clock_ns(rtc_clock) + (get_ticks_per_sec() * 99) / 100;
dff38e7b
FB
666 qemu_mod_timer(s->second_timer2, s->next_second_time);
667
b2c5009b
RH
668 memory_region_init_io(&s->io, &cmos_ops, s, "rtc", 2);
669 isa_register_ioport(dev, &s->io, base);
dff38e7b 670
dc683910 671 qdev_set_legacy_instance_id(&dev->qdev, base, 2);
a08d4367 672 qemu_register_reset(rtc_reset, s);
18297050
AL
673
674 qdev_property_add(&s->dev.qdev, "date", "struct tm",
675 rtc_get_date, NULL, NULL, s, NULL);
676
32e0c826
GH
677 return 0;
678}
679
48a18b3c 680ISADevice *rtc_init(ISABus *bus, int base_year, qemu_irq intercept_irq)
32e0c826
GH
681{
682 ISADevice *dev;
7d932dfd 683 RTCState *s;
eeb7c03c 684
48a18b3c 685 dev = isa_create(bus, "mc146818rtc");
7d932dfd 686 s = DO_UPCAST(RTCState, dev, dev);
32e0c826 687 qdev_prop_set_int32(&dev->qdev, "base_year", base_year);
e23a1b33 688 qdev_init_nofail(&dev->qdev);
7d932dfd
JK
689 if (intercept_irq) {
690 s->irq = intercept_irq;
691 } else {
692 isa_init_irq(dev, &s->irq, RTC_ISA_IRQ);
693 }
1d914fa0 694 return dev;
80cabfad
FB
695}
696
32e0c826
GH
697static ISADeviceInfo mc146818rtc_info = {
698 .qdev.name = "mc146818rtc",
699 .qdev.size = sizeof(RTCState),
700 .qdev.no_user = 1,
dc683910 701 .qdev.vmsd = &vmstate_rtc,
32e0c826
GH
702 .init = rtc_initfn,
703 .qdev.props = (Property[]) {
704 DEFINE_PROP_INT32("base_year", RTCState, base_year, 1980),
705 DEFINE_PROP_END_OF_LIST(),
706 }
707};
708
709static void mc146818rtc_register(void)
100d9891 710{
32e0c826 711 isa_qdev_register(&mc146818rtc_info);
100d9891 712}
32e0c826 713device_init(mc146818rtc_register)