186797937017f52bff088d02edf64fb931177a7eaJun Nakajima/*
286797937017f52bff088d02edf64fb931177a7eaJun Nakajima * QEMU MC146818 RTC emulation
386797937017f52bff088d02edf64fb931177a7eaJun Nakajima *
486797937017f52bff088d02edf64fb931177a7eaJun Nakajima * Copyright (c) 2003-2004 Fabrice Bellard
586797937017f52bff088d02edf64fb931177a7eaJun Nakajima *
686797937017f52bff088d02edf64fb931177a7eaJun Nakajima * Permission is hereby granted, free of charge, to any person obtaining a copy
786797937017f52bff088d02edf64fb931177a7eaJun Nakajima * of this software and associated documentation files (the "Software"), to deal
886797937017f52bff088d02edf64fb931177a7eaJun Nakajima * in the Software without restriction, including without limitation the rights
986797937017f52bff088d02edf64fb931177a7eaJun Nakajima * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
1086797937017f52bff088d02edf64fb931177a7eaJun Nakajima * copies of the Software, and to permit persons to whom the Software is
1186797937017f52bff088d02edf64fb931177a7eaJun Nakajima * furnished to do so, subject to the following conditions:
1286797937017f52bff088d02edf64fb931177a7eaJun Nakajima *
1386797937017f52bff088d02edf64fb931177a7eaJun Nakajima * The above copyright notice and this permission notice shall be included in
1486797937017f52bff088d02edf64fb931177a7eaJun Nakajima * all copies or substantial portions of the Software.
1586797937017f52bff088d02edf64fb931177a7eaJun Nakajima *
1686797937017f52bff088d02edf64fb931177a7eaJun Nakajima * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1786797937017f52bff088d02edf64fb931177a7eaJun Nakajima * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1886797937017f52bff088d02edf64fb931177a7eaJun Nakajima * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
1986797937017f52bff088d02edf64fb931177a7eaJun Nakajima * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
2086797937017f52bff088d02edf64fb931177a7eaJun Nakajima * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
2186797937017f52bff088d02edf64fb931177a7eaJun Nakajima * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
2286797937017f52bff088d02edf64fb931177a7eaJun Nakajima * THE SOFTWARE.
2386797937017f52bff088d02edf64fb931177a7eaJun Nakajima */
2486797937017f52bff088d02edf64fb931177a7eaJun Nakajima#include "hw.h"
2586797937017f52bff088d02edf64fb931177a7eaJun Nakajima#include "qemu-timer.h"
2686797937017f52bff088d02edf64fb931177a7eaJun Nakajima#include "sysemu.h"
2786797937017f52bff088d02edf64fb931177a7eaJun Nakajima#include "pc.h"
2886797937017f52bff088d02edf64fb931177a7eaJun Nakajima#include "isa.h"
2986797937017f52bff088d02edf64fb931177a7eaJun Nakajima//#include "hpet_emul.h"
3086797937017f52bff088d02edf64fb931177a7eaJun Nakajima
3186797937017f52bff088d02edf64fb931177a7eaJun Nakajima//#define DEBUG_CMOS
3286797937017f52bff088d02edf64fb931177a7eaJun Nakajima
3386797937017f52bff088d02edf64fb931177a7eaJun Nakajima#define RTC_SECONDS             0
3486797937017f52bff088d02edf64fb931177a7eaJun Nakajima#define RTC_SECONDS_ALARM       1
3586797937017f52bff088d02edf64fb931177a7eaJun Nakajima#define RTC_MINUTES             2
3686797937017f52bff088d02edf64fb931177a7eaJun Nakajima#define RTC_MINUTES_ALARM       3
3786797937017f52bff088d02edf64fb931177a7eaJun Nakajima#define RTC_HOURS               4
3886797937017f52bff088d02edf64fb931177a7eaJun Nakajima#define RTC_HOURS_ALARM         5
3986797937017f52bff088d02edf64fb931177a7eaJun Nakajima#define RTC_ALARM_DONT_CARE    0xC0
4086797937017f52bff088d02edf64fb931177a7eaJun Nakajima
4186797937017f52bff088d02edf64fb931177a7eaJun Nakajima#define RTC_DAY_OF_WEEK         6
4286797937017f52bff088d02edf64fb931177a7eaJun Nakajima#define RTC_DAY_OF_MONTH        7
4386797937017f52bff088d02edf64fb931177a7eaJun Nakajima#define RTC_MONTH               8
4486797937017f52bff088d02edf64fb931177a7eaJun Nakajima#define RTC_YEAR                9
4586797937017f52bff088d02edf64fb931177a7eaJun Nakajima
4686797937017f52bff088d02edf64fb931177a7eaJun Nakajima#define RTC_REG_A               10
4786797937017f52bff088d02edf64fb931177a7eaJun Nakajima#define RTC_REG_B               11
4886797937017f52bff088d02edf64fb931177a7eaJun Nakajima#define RTC_REG_C               12
4986797937017f52bff088d02edf64fb931177a7eaJun Nakajima#define RTC_REG_D               13
5086797937017f52bff088d02edf64fb931177a7eaJun Nakajima
5186797937017f52bff088d02edf64fb931177a7eaJun Nakajima#define REG_A_UIP 0x80
5286797937017f52bff088d02edf64fb931177a7eaJun Nakajima
5386797937017f52bff088d02edf64fb931177a7eaJun Nakajima#define REG_B_SET  0x80
5486797937017f52bff088d02edf64fb931177a7eaJun Nakajima#define REG_B_PIE  0x40
5586797937017f52bff088d02edf64fb931177a7eaJun Nakajima#define REG_B_AIE  0x20
5686797937017f52bff088d02edf64fb931177a7eaJun Nakajima#define REG_B_UIE  0x10
5786797937017f52bff088d02edf64fb931177a7eaJun Nakajima#define REG_B_SQWE 0x08
5886797937017f52bff088d02edf64fb931177a7eaJun Nakajima#define REG_B_DM   0x04
5986797937017f52bff088d02edf64fb931177a7eaJun Nakajima
6086797937017f52bff088d02edf64fb931177a7eaJun Nakajima#define REG_C_UF   0x10
6186797937017f52bff088d02edf64fb931177a7eaJun Nakajima#define REG_C_IRQF 0x80
6286797937017f52bff088d02edf64fb931177a7eaJun Nakajima#define REG_C_PF   0x40
6386797937017f52bff088d02edf64fb931177a7eaJun Nakajima#define REG_C_AF   0x20
6486797937017f52bff088d02edf64fb931177a7eaJun Nakajima
6586797937017f52bff088d02edf64fb931177a7eaJun Nakajimastruct RTCState {
6686797937017f52bff088d02edf64fb931177a7eaJun Nakajima    uint8_t cmos_data[128];
6786797937017f52bff088d02edf64fb931177a7eaJun Nakajima    uint8_t cmos_index;
6886797937017f52bff088d02edf64fb931177a7eaJun Nakajima    struct tm current_tm;
6986797937017f52bff088d02edf64fb931177a7eaJun Nakajima    int base_year;
7086797937017f52bff088d02edf64fb931177a7eaJun Nakajima    qemu_irq irq;
7186797937017f52bff088d02edf64fb931177a7eaJun Nakajima    qemu_irq sqw_irq;
7286797937017f52bff088d02edf64fb931177a7eaJun Nakajima    int it_shift;
7386797937017f52bff088d02edf64fb931177a7eaJun Nakajima    /* periodic timer */
7486797937017f52bff088d02edf64fb931177a7eaJun Nakajima    QEMUTimer *periodic_timer;
7586797937017f52bff088d02edf64fb931177a7eaJun Nakajima    int64_t next_periodic_time;
7686797937017f52bff088d02edf64fb931177a7eaJun Nakajima    /* second update */
7786797937017f52bff088d02edf64fb931177a7eaJun Nakajima    int64_t next_second_time;
7886797937017f52bff088d02edf64fb931177a7eaJun Nakajima#ifdef TARGET_I386
7986797937017f52bff088d02edf64fb931177a7eaJun Nakajima    uint32_t irq_coalesced;
8086797937017f52bff088d02edf64fb931177a7eaJun Nakajima    uint32_t period;
8186797937017f52bff088d02edf64fb931177a7eaJun Nakajima    QEMUTimer *coalesced_timer;
8286797937017f52bff088d02edf64fb931177a7eaJun Nakajima#endif
8386797937017f52bff088d02edf64fb931177a7eaJun Nakajima    QEMUTimer *second_timer;
8486797937017f52bff088d02edf64fb931177a7eaJun Nakajima    QEMUTimer *second_timer2;
8586797937017f52bff088d02edf64fb931177a7eaJun Nakajima};
8686797937017f52bff088d02edf64fb931177a7eaJun Nakajima
8786797937017f52bff088d02edf64fb931177a7eaJun Nakajimastatic void rtc_irq_raise(qemu_irq irq) {
8886797937017f52bff088d02edf64fb931177a7eaJun Nakajima    /* When HPET is operating in legacy mode, RTC interrupts are disabled
8986797937017f52bff088d02edf64fb931177a7eaJun Nakajima     * We block qemu_irq_raise, but not qemu_irq_lower, in case legacy
9086797937017f52bff088d02edf64fb931177a7eaJun Nakajima     * mode is established while interrupt is raised. We want it to
9186797937017f52bff088d02edf64fb931177a7eaJun Nakajima     * be lowered in any case
9286797937017f52bff088d02edf64fb931177a7eaJun Nakajima     */
9386797937017f52bff088d02edf64fb931177a7eaJun Nakajima#ifndef CONFIG_ANDROID
9486797937017f52bff088d02edf64fb931177a7eaJun Nakajima#if defined TARGET_I386 || defined TARGET_X86_64
9586797937017f52bff088d02edf64fb931177a7eaJun Nakajima    if (!hpet_in_legacy_mode())
9686797937017f52bff088d02edf64fb931177a7eaJun Nakajima#endif
9786797937017f52bff088d02edf64fb931177a7eaJun Nakajima#endif
9886797937017f52bff088d02edf64fb931177a7eaJun Nakajima        qemu_irq_raise(irq);
9986797937017f52bff088d02edf64fb931177a7eaJun Nakajima}
10086797937017f52bff088d02edf64fb931177a7eaJun Nakajima
10186797937017f52bff088d02edf64fb931177a7eaJun Nakajimastatic void rtc_set_time(RTCState *s);
10286797937017f52bff088d02edf64fb931177a7eaJun Nakajimastatic void rtc_copy_date(RTCState *s);
10386797937017f52bff088d02edf64fb931177a7eaJun Nakajima
10486797937017f52bff088d02edf64fb931177a7eaJun Nakajima#ifdef TARGET_I386
10586797937017f52bff088d02edf64fb931177a7eaJun Nakajimastatic void rtc_coalesced_timer_update(RTCState *s)
10686797937017f52bff088d02edf64fb931177a7eaJun Nakajima{
10786797937017f52bff088d02edf64fb931177a7eaJun Nakajima    if (s->irq_coalesced == 0) {
10886797937017f52bff088d02edf64fb931177a7eaJun Nakajima        qemu_del_timer(s->coalesced_timer);
10986797937017f52bff088d02edf64fb931177a7eaJun Nakajima    } else {
11086797937017f52bff088d02edf64fb931177a7eaJun Nakajima        /* divide each RTC interval to 2 - 8 smaller intervals */
1115973c775c853e26f684de58ad28c267281aaffd6David 'Digit' Turner        int c = MIN(s->irq_coalesced, 7) + 1;
1125973c775c853e26f684de58ad28c267281aaffd6David 'Digit' Turner        int64_t next_clock = qemu_get_clock_ns(vm_clock) +
11386797937017f52bff088d02edf64fb931177a7eaJun Nakajima		muldiv64(s->period / c, get_ticks_per_sec(), 32768);
11486797937017f52bff088d02edf64fb931177a7eaJun Nakajima        qemu_mod_timer(s->coalesced_timer, next_clock);
11586797937017f52bff088d02edf64fb931177a7eaJun Nakajima    }
11686797937017f52bff088d02edf64fb931177a7eaJun Nakajima}
11786797937017f52bff088d02edf64fb931177a7eaJun Nakajima
11886797937017f52bff088d02edf64fb931177a7eaJun Nakajimastatic void rtc_coalesced_timer(void *opaque)
11986797937017f52bff088d02edf64fb931177a7eaJun Nakajima{
12086797937017f52bff088d02edf64fb931177a7eaJun Nakajima    RTCState *s = opaque;
12186797937017f52bff088d02edf64fb931177a7eaJun Nakajima
12286797937017f52bff088d02edf64fb931177a7eaJun Nakajima    if (s->irq_coalesced != 0) {
12386797937017f52bff088d02edf64fb931177a7eaJun Nakajima        apic_reset_irq_delivered();
12486797937017f52bff088d02edf64fb931177a7eaJun Nakajima        s->cmos_data[RTC_REG_C] |= 0xc0;
12586797937017f52bff088d02edf64fb931177a7eaJun Nakajima        rtc_irq_raise(s->irq);
12686797937017f52bff088d02edf64fb931177a7eaJun Nakajima        if (apic_get_irq_delivered()) {
12786797937017f52bff088d02edf64fb931177a7eaJun Nakajima            s->irq_coalesced--;
12886797937017f52bff088d02edf64fb931177a7eaJun Nakajima        }
12986797937017f52bff088d02edf64fb931177a7eaJun Nakajima    }
13086797937017f52bff088d02edf64fb931177a7eaJun Nakajima
13186797937017f52bff088d02edf64fb931177a7eaJun Nakajima    rtc_coalesced_timer_update(s);
13286797937017f52bff088d02edf64fb931177a7eaJun Nakajima}
13386797937017f52bff088d02edf64fb931177a7eaJun Nakajima#endif
13486797937017f52bff088d02edf64fb931177a7eaJun Nakajima
13586797937017f52bff088d02edf64fb931177a7eaJun Nakajimastatic void rtc_timer_update(RTCState *s, int64_t current_time)
13686797937017f52bff088d02edf64fb931177a7eaJun Nakajima{
13786797937017f52bff088d02edf64fb931177a7eaJun Nakajima    int period_code, period;
13886797937017f52bff088d02edf64fb931177a7eaJun Nakajima    int64_t cur_clock, next_irq_clock;
13986797937017f52bff088d02edf64fb931177a7eaJun Nakajima    int enable_pie;
14086797937017f52bff088d02edf64fb931177a7eaJun Nakajima
14186797937017f52bff088d02edf64fb931177a7eaJun Nakajima    period_code = s->cmos_data[RTC_REG_A] & 0x0f;
14286797937017f52bff088d02edf64fb931177a7eaJun Nakajima#ifndef CONFIG_ANDROID
14386797937017f52bff088d02edf64fb931177a7eaJun Nakajima#if defined TARGET_I386 || defined TARGET_X86_64
14486797937017f52bff088d02edf64fb931177a7eaJun Nakajima    /* disable periodic timer if hpet is in legacy mode, since interrupts are
14586797937017f52bff088d02edf64fb931177a7eaJun Nakajima     * disabled anyway.
14686797937017f52bff088d02edf64fb931177a7eaJun Nakajima     */
14786797937017f52bff088d02edf64fb931177a7eaJun Nakajima    enable_pie = !hpet_in_legacy_mode();
14886797937017f52bff088d02edf64fb931177a7eaJun Nakajima#else
14986797937017f52bff088d02edf64fb931177a7eaJun Nakajima    enable_pie = 1;
15086797937017f52bff088d02edf64fb931177a7eaJun Nakajima#endif
15186797937017f52bff088d02edf64fb931177a7eaJun Nakajima#endif
15286797937017f52bff088d02edf64fb931177a7eaJun Nakajima    enable_pie = 1;
1535973c775c853e26f684de58ad28c267281aaffd6David 'Digit' Turner
15486797937017f52bff088d02edf64fb931177a7eaJun Nakajima    if (period_code != 0
15586797937017f52bff088d02edf64fb931177a7eaJun Nakajima        && (((s->cmos_data[RTC_REG_B] & REG_B_PIE) && enable_pie)
15686797937017f52bff088d02edf64fb931177a7eaJun Nakajima            || ((s->cmos_data[RTC_REG_B] & REG_B_SQWE) && s->sqw_irq))) {
15786797937017f52bff088d02edf64fb931177a7eaJun Nakajima        if (period_code <= 2)
15886797937017f52bff088d02edf64fb931177a7eaJun Nakajima            period_code += 7;
15986797937017f52bff088d02edf64fb931177a7eaJun Nakajima        /* period in 32 Khz cycles */
16086797937017f52bff088d02edf64fb931177a7eaJun Nakajima        period = 1 << (period_code - 1);
16186797937017f52bff088d02edf64fb931177a7eaJun Nakajima#ifdef TARGET_I386
16286797937017f52bff088d02edf64fb931177a7eaJun Nakajima        if(period != s->period)
16386797937017f52bff088d02edf64fb931177a7eaJun Nakajima            s->irq_coalesced = (s->irq_coalesced * s->period) / period;
16486797937017f52bff088d02edf64fb931177a7eaJun Nakajima        s->period = period;
16586797937017f52bff088d02edf64fb931177a7eaJun Nakajima#endif
16686797937017f52bff088d02edf64fb931177a7eaJun Nakajima        /* compute 32 khz clock */
16786797937017f52bff088d02edf64fb931177a7eaJun Nakajima        cur_clock = muldiv64(current_time, 32768, get_ticks_per_sec());
16886797937017f52bff088d02edf64fb931177a7eaJun Nakajima        next_irq_clock = (cur_clock & ~(period - 1)) + period;
16986797937017f52bff088d02edf64fb931177a7eaJun Nakajima        s->next_periodic_time = muldiv64(next_irq_clock, get_ticks_per_sec(), 32768) + 1;
17086797937017f52bff088d02edf64fb931177a7eaJun Nakajima        qemu_mod_timer(s->periodic_timer, s->next_periodic_time);
17186797937017f52bff088d02edf64fb931177a7eaJun Nakajima    } else {
17286797937017f52bff088d02edf64fb931177a7eaJun Nakajima#ifdef TARGET_I386
17386797937017f52bff088d02edf64fb931177a7eaJun Nakajima        s->irq_coalesced = 0;
17486797937017f52bff088d02edf64fb931177a7eaJun Nakajima#endif
17586797937017f52bff088d02edf64fb931177a7eaJun Nakajima        qemu_del_timer(s->periodic_timer);
17686797937017f52bff088d02edf64fb931177a7eaJun Nakajima    }
17786797937017f52bff088d02edf64fb931177a7eaJun Nakajima}
17886797937017f52bff088d02edf64fb931177a7eaJun Nakajima
17986797937017f52bff088d02edf64fb931177a7eaJun Nakajimastatic void rtc_periodic_timer(void *opaque)
18086797937017f52bff088d02edf64fb931177a7eaJun Nakajima{
18186797937017f52bff088d02edf64fb931177a7eaJun Nakajima    RTCState *s = opaque;
18286797937017f52bff088d02edf64fb931177a7eaJun Nakajima
18386797937017f52bff088d02edf64fb931177a7eaJun Nakajima    rtc_timer_update(s, s->next_periodic_time);
18486797937017f52bff088d02edf64fb931177a7eaJun Nakajima    if (s->cmos_data[RTC_REG_B] & REG_B_PIE) {
18586797937017f52bff088d02edf64fb931177a7eaJun Nakajima        s->cmos_data[RTC_REG_C] |= 0xc0;
18686797937017f52bff088d02edf64fb931177a7eaJun Nakajima#ifdef TARGET_I386
18786797937017f52bff088d02edf64fb931177a7eaJun Nakajima        if(rtc_td_hack) {
18886797937017f52bff088d02edf64fb931177a7eaJun Nakajima            apic_reset_irq_delivered();
18986797937017f52bff088d02edf64fb931177a7eaJun Nakajima            rtc_irq_raise(s->irq);
19086797937017f52bff088d02edf64fb931177a7eaJun Nakajima            if (!apic_get_irq_delivered()) {
19186797937017f52bff088d02edf64fb931177a7eaJun Nakajima                s->irq_coalesced++;
19286797937017f52bff088d02edf64fb931177a7eaJun Nakajima                rtc_coalesced_timer_update(s);
19386797937017f52bff088d02edf64fb931177a7eaJun Nakajima            }
19486797937017f52bff088d02edf64fb931177a7eaJun Nakajima        } else
19586797937017f52bff088d02edf64fb931177a7eaJun Nakajima#endif
19686797937017f52bff088d02edf64fb931177a7eaJun Nakajima        rtc_irq_raise(s->irq);
19786797937017f52bff088d02edf64fb931177a7eaJun Nakajima    }
19886797937017f52bff088d02edf64fb931177a7eaJun Nakajima    if (s->cmos_data[RTC_REG_B] & REG_B_SQWE) {
19986797937017f52bff088d02edf64fb931177a7eaJun Nakajima        /* Not square wave at all but we don't want 2048Hz interrupts!
20086797937017f52bff088d02edf64fb931177a7eaJun Nakajima           Must be seen as a pulse.  */
20186797937017f52bff088d02edf64fb931177a7eaJun Nakajima        qemu_irq_raise(s->sqw_irq);
20286797937017f52bff088d02edf64fb931177a7eaJun Nakajima    }
20386797937017f52bff088d02edf64fb931177a7eaJun Nakajima}
20486797937017f52bff088d02edf64fb931177a7eaJun Nakajima
20586797937017f52bff088d02edf64fb931177a7eaJun Nakajimastatic void cmos_ioport_write(void *opaque, uint32_t addr, uint32_t data)
20686797937017f52bff088d02edf64fb931177a7eaJun Nakajima{
20786797937017f52bff088d02edf64fb931177a7eaJun Nakajima    RTCState *s = opaque;
20886797937017f52bff088d02edf64fb931177a7eaJun Nakajima
20986797937017f52bff088d02edf64fb931177a7eaJun Nakajima    if ((addr & 1) == 0) {
21086797937017f52bff088d02edf64fb931177a7eaJun Nakajima        s->cmos_index = data & 0x7f;
21186797937017f52bff088d02edf64fb931177a7eaJun Nakajima    } else {
21286797937017f52bff088d02edf64fb931177a7eaJun Nakajima#ifdef DEBUG_CMOS
21386797937017f52bff088d02edf64fb931177a7eaJun Nakajima        printf("cmos: write index=0x%02x val=0x%02x\n",
21486797937017f52bff088d02edf64fb931177a7eaJun Nakajima               s->cmos_index, data);
21586797937017f52bff088d02edf64fb931177a7eaJun Nakajima#endif
21686797937017f52bff088d02edf64fb931177a7eaJun Nakajima        switch(s->cmos_index) {
21786797937017f52bff088d02edf64fb931177a7eaJun Nakajima        case RTC_SECONDS_ALARM:
21886797937017f52bff088d02edf64fb931177a7eaJun Nakajima        case RTC_MINUTES_ALARM:
21986797937017f52bff088d02edf64fb931177a7eaJun Nakajima        case RTC_HOURS_ALARM:
22086797937017f52bff088d02edf64fb931177a7eaJun Nakajima            /* XXX: not supported */
22186797937017f52bff088d02edf64fb931177a7eaJun Nakajima            s->cmos_data[s->cmos_index] = data;
22286797937017f52bff088d02edf64fb931177a7eaJun Nakajima            break;
22386797937017f52bff088d02edf64fb931177a7eaJun Nakajima        case RTC_SECONDS:
22486797937017f52bff088d02edf64fb931177a7eaJun Nakajima        case RTC_MINUTES:
22586797937017f52bff088d02edf64fb931177a7eaJun Nakajima        case RTC_HOURS:
22686797937017f52bff088d02edf64fb931177a7eaJun Nakajima        case RTC_DAY_OF_WEEK:
22786797937017f52bff088d02edf64fb931177a7eaJun Nakajima        case RTC_DAY_OF_MONTH:
22886797937017f52bff088d02edf64fb931177a7eaJun Nakajima        case RTC_MONTH:
22986797937017f52bff088d02edf64fb931177a7eaJun Nakajima        case RTC_YEAR:
23086797937017f52bff088d02edf64fb931177a7eaJun Nakajima            s->cmos_data[s->cmos_index] = data;
23186797937017f52bff088d02edf64fb931177a7eaJun Nakajima            /* if in set mode, do not update the time */
23286797937017f52bff088d02edf64fb931177a7eaJun Nakajima            if (!(s->cmos_data[RTC_REG_B] & REG_B_SET)) {
23386797937017f52bff088d02edf64fb931177a7eaJun Nakajima                rtc_set_time(s);
23486797937017f52bff088d02edf64fb931177a7eaJun Nakajima            }
23586797937017f52bff088d02edf64fb931177a7eaJun Nakajima            break;
23686797937017f52bff088d02edf64fb931177a7eaJun Nakajima        case RTC_REG_A:
23786797937017f52bff088d02edf64fb931177a7eaJun Nakajima            /* UIP bit is read only */
23886797937017f52bff088d02edf64fb931177a7eaJun Nakajima            s->cmos_data[RTC_REG_A] = (data & ~REG_A_UIP) |
23986797937017f52bff088d02edf64fb931177a7eaJun Nakajima                (s->cmos_data[RTC_REG_A] & REG_A_UIP);
2405973c775c853e26f684de58ad28c267281aaffd6David 'Digit' Turner            rtc_timer_update(s, qemu_get_clock_ns(vm_clock));
24186797937017f52bff088d02edf64fb931177a7eaJun Nakajima            break;
24286797937017f52bff088d02edf64fb931177a7eaJun Nakajima        case RTC_REG_B:
24386797937017f52bff088d02edf64fb931177a7eaJun Nakajima            if (data & REG_B_SET) {
24486797937017f52bff088d02edf64fb931177a7eaJun Nakajima                /* set mode: reset UIP mode */
24586797937017f52bff088d02edf64fb931177a7eaJun Nakajima                s->cmos_data[RTC_REG_A] &= ~REG_A_UIP;
24686797937017f52bff088d02edf64fb931177a7eaJun Nakajima                data &= ~REG_B_UIE;
24786797937017f52bff088d02edf64fb931177a7eaJun Nakajima            } else {
24886797937017f52bff088d02edf64fb931177a7eaJun Nakajima                /* if disabling set mode, update the time */
24986797937017f52bff088d02edf64fb931177a7eaJun Nakajima                if (s->cmos_data[RTC_REG_B] & REG_B_SET) {
25086797937017f52bff088d02edf64fb931177a7eaJun Nakajima                    rtc_set_time(s);
25186797937017f52bff088d02edf64fb931177a7eaJun Nakajima                }
25286797937017f52bff088d02edf64fb931177a7eaJun Nakajima            }
25386797937017f52bff088d02edf64fb931177a7eaJun Nakajima            s->cmos_data[RTC_REG_B] = data;
2545973c775c853e26f684de58ad28c267281aaffd6David 'Digit' Turner            rtc_timer_update(s, qemu_get_clock_ns(vm_clock));
25586797937017f52bff088d02edf64fb931177a7eaJun Nakajima            break;
25686797937017f52bff088d02edf64fb931177a7eaJun Nakajima        case RTC_REG_C:
25786797937017f52bff088d02edf64fb931177a7eaJun Nakajima        case RTC_REG_D:
25886797937017f52bff088d02edf64fb931177a7eaJun Nakajima            /* cannot write to them */
25986797937017f52bff088d02edf64fb931177a7eaJun Nakajima            break;
26086797937017f52bff088d02edf64fb931177a7eaJun Nakajima        default:
26186797937017f52bff088d02edf64fb931177a7eaJun Nakajima            s->cmos_data[s->cmos_index] = data;
26286797937017f52bff088d02edf64fb931177a7eaJun Nakajima            break;
26386797937017f52bff088d02edf64fb931177a7eaJun Nakajima        }
26486797937017f52bff088d02edf64fb931177a7eaJun Nakajima    }
26586797937017f52bff088d02edf64fb931177a7eaJun Nakajima}
26686797937017f52bff088d02edf64fb931177a7eaJun Nakajima
26786797937017f52bff088d02edf64fb931177a7eaJun Nakajimastatic inline int rtc_to_bcd(RTCState *s, int a)
26886797937017f52bff088d02edf64fb931177a7eaJun Nakajima{
26986797937017f52bff088d02edf64fb931177a7eaJun Nakajima    if (s->cmos_data[RTC_REG_B] & REG_B_DM) {
27086797937017f52bff088d02edf64fb931177a7eaJun Nakajima        return a;
27186797937017f52bff088d02edf64fb931177a7eaJun Nakajima    } else {
27286797937017f52bff088d02edf64fb931177a7eaJun Nakajima        return ((a / 10) << 4) | (a % 10);
27386797937017f52bff088d02edf64fb931177a7eaJun Nakajima    }
27486797937017f52bff088d02edf64fb931177a7eaJun Nakajima}
27586797937017f52bff088d02edf64fb931177a7eaJun Nakajima
27686797937017f52bff088d02edf64fb931177a7eaJun Nakajimastatic inline int rtc_from_bcd(RTCState *s, int a)
27786797937017f52bff088d02edf64fb931177a7eaJun Nakajima{
27886797937017f52bff088d02edf64fb931177a7eaJun Nakajima    if (s->cmos_data[RTC_REG_B] & REG_B_DM) {
27986797937017f52bff088d02edf64fb931177a7eaJun Nakajima        return a;
28086797937017f52bff088d02edf64fb931177a7eaJun Nakajima    } else {
28186797937017f52bff088d02edf64fb931177a7eaJun Nakajima        return ((a >> 4) * 10) + (a & 0x0f);
28286797937017f52bff088d02edf64fb931177a7eaJun Nakajima    }
28386797937017f52bff088d02edf64fb931177a7eaJun Nakajima}
28486797937017f52bff088d02edf64fb931177a7eaJun Nakajima
28586797937017f52bff088d02edf64fb931177a7eaJun Nakajimastatic void rtc_set_time(RTCState *s)
28686797937017f52bff088d02edf64fb931177a7eaJun Nakajima{
28786797937017f52bff088d02edf64fb931177a7eaJun Nakajima    struct tm *tm = &s->current_tm;
28886797937017f52bff088d02edf64fb931177a7eaJun Nakajima
28986797937017f52bff088d02edf64fb931177a7eaJun Nakajima    tm->tm_sec = rtc_from_bcd(s, s->cmos_data[RTC_SECONDS]);
29086797937017f52bff088d02edf64fb931177a7eaJun Nakajima    tm->tm_min = rtc_from_bcd(s, s->cmos_data[RTC_MINUTES]);
29186797937017f52bff088d02edf64fb931177a7eaJun Nakajima    tm->tm_hour = rtc_from_bcd(s, s->cmos_data[RTC_HOURS] & 0x7f);
29286797937017f52bff088d02edf64fb931177a7eaJun Nakajima    if (!(s->cmos_data[RTC_REG_B] & 0x02) &&
29386797937017f52bff088d02edf64fb931177a7eaJun Nakajima        (s->cmos_data[RTC_HOURS] & 0x80)) {
29486797937017f52bff088d02edf64fb931177a7eaJun Nakajima        tm->tm_hour += 12;
29586797937017f52bff088d02edf64fb931177a7eaJun Nakajima    }
29686797937017f52bff088d02edf64fb931177a7eaJun Nakajima    tm->tm_wday = rtc_from_bcd(s, s->cmos_data[RTC_DAY_OF_WEEK]) - 1;
29786797937017f52bff088d02edf64fb931177a7eaJun Nakajima    tm->tm_mday = rtc_from_bcd(s, s->cmos_data[RTC_DAY_OF_MONTH]);
29886797937017f52bff088d02edf64fb931177a7eaJun Nakajima    tm->tm_mon = rtc_from_bcd(s, s->cmos_data[RTC_MONTH]) - 1;
29986797937017f52bff088d02edf64fb931177a7eaJun Nakajima    tm->tm_year = rtc_from_bcd(s, s->cmos_data[RTC_YEAR]) + s->base_year - 1900;
30086797937017f52bff088d02edf64fb931177a7eaJun Nakajima}
30186797937017f52bff088d02edf64fb931177a7eaJun Nakajima
30286797937017f52bff088d02edf64fb931177a7eaJun Nakajimastatic void rtc_copy_date(RTCState *s)
30386797937017f52bff088d02edf64fb931177a7eaJun Nakajima{
30486797937017f52bff088d02edf64fb931177a7eaJun Nakajima    const struct tm *tm = &s->current_tm;
30586797937017f52bff088d02edf64fb931177a7eaJun Nakajima    int year;
30686797937017f52bff088d02edf64fb931177a7eaJun Nakajima
30786797937017f52bff088d02edf64fb931177a7eaJun Nakajima    s->cmos_data[RTC_SECONDS] = rtc_to_bcd(s, tm->tm_sec);
30886797937017f52bff088d02edf64fb931177a7eaJun Nakajima    s->cmos_data[RTC_MINUTES] = rtc_to_bcd(s, tm->tm_min);
30986797937017f52bff088d02edf64fb931177a7eaJun Nakajima    if (s->cmos_data[RTC_REG_B] & 0x02) {
31086797937017f52bff088d02edf64fb931177a7eaJun Nakajima        /* 24 hour format */
31186797937017f52bff088d02edf64fb931177a7eaJun Nakajima        s->cmos_data[RTC_HOURS] = rtc_to_bcd(s, tm->tm_hour);
31286797937017f52bff088d02edf64fb931177a7eaJun Nakajima    } else {
31386797937017f52bff088d02edf64fb931177a7eaJun Nakajima        /* 12 hour format */
31486797937017f52bff088d02edf64fb931177a7eaJun Nakajima        s->cmos_data[RTC_HOURS] = rtc_to_bcd(s, tm->tm_hour % 12);
31586797937017f52bff088d02edf64fb931177a7eaJun Nakajima        if (tm->tm_hour >= 12)
31686797937017f52bff088d02edf64fb931177a7eaJun Nakajima            s->cmos_data[RTC_HOURS] |= 0x80;
31786797937017f52bff088d02edf64fb931177a7eaJun Nakajima    }
31886797937017f52bff088d02edf64fb931177a7eaJun Nakajima    s->cmos_data[RTC_DAY_OF_WEEK] = rtc_to_bcd(s, tm->tm_wday + 1);
31986797937017f52bff088d02edf64fb931177a7eaJun Nakajima    s->cmos_data[RTC_DAY_OF_MONTH] = rtc_to_bcd(s, tm->tm_mday);
32086797937017f52bff088d02edf64fb931177a7eaJun Nakajima    s->cmos_data[RTC_MONTH] = rtc_to_bcd(s, tm->tm_mon + 1);
32186797937017f52bff088d02edf64fb931177a7eaJun Nakajima    year = (tm->tm_year - s->base_year) % 100;
32286797937017f52bff088d02edf64fb931177a7eaJun Nakajima    if (year < 0)
32386797937017f52bff088d02edf64fb931177a7eaJun Nakajima        year += 100;
32486797937017f52bff088d02edf64fb931177a7eaJun Nakajima    s->cmos_data[RTC_YEAR] = rtc_to_bcd(s, year);
32586797937017f52bff088d02edf64fb931177a7eaJun Nakajima}
32686797937017f52bff088d02edf64fb931177a7eaJun Nakajima
32786797937017f52bff088d02edf64fb931177a7eaJun Nakajima/* month is between 0 and 11. */
32886797937017f52bff088d02edf64fb931177a7eaJun Nakajimastatic int get_days_in_month(int month, int year)
32986797937017f52bff088d02edf64fb931177a7eaJun Nakajima{
33086797937017f52bff088d02edf64fb931177a7eaJun Nakajima    static const int days_tab[12] = {
33186797937017f52bff088d02edf64fb931177a7eaJun Nakajima        31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
33286797937017f52bff088d02edf64fb931177a7eaJun Nakajima    };
33386797937017f52bff088d02edf64fb931177a7eaJun Nakajima    int d;
33486797937017f52bff088d02edf64fb931177a7eaJun Nakajima    if ((unsigned )month >= 12)
33586797937017f52bff088d02edf64fb931177a7eaJun Nakajima        return 31;
33686797937017f52bff088d02edf64fb931177a7eaJun Nakajima    d = days_tab[month];
33786797937017f52bff088d02edf64fb931177a7eaJun Nakajima    if (month == 1) {
33886797937017f52bff088d02edf64fb931177a7eaJun Nakajima        if ((year % 4) == 0 && ((year % 100) != 0 || (year % 400) == 0))
33986797937017f52bff088d02edf64fb931177a7eaJun Nakajima            d++;
34086797937017f52bff088d02edf64fb931177a7eaJun Nakajima    }
34186797937017f52bff088d02edf64fb931177a7eaJun Nakajima    return d;
34286797937017f52bff088d02edf64fb931177a7eaJun Nakajima}
34386797937017f52bff088d02edf64fb931177a7eaJun Nakajima
34486797937017f52bff088d02edf64fb931177a7eaJun Nakajima/* update 'tm' to the next second */
34586797937017f52bff088d02edf64fb931177a7eaJun Nakajimastatic void rtc_next_second(struct tm *tm)
34686797937017f52bff088d02edf64fb931177a7eaJun Nakajima{
34786797937017f52bff088d02edf64fb931177a7eaJun Nakajima    int days_in_month;
34886797937017f52bff088d02edf64fb931177a7eaJun Nakajima
34986797937017f52bff088d02edf64fb931177a7eaJun Nakajima    tm->tm_sec++;
35086797937017f52bff088d02edf64fb931177a7eaJun Nakajima    if ((unsigned)tm->tm_sec >= 60) {
35186797937017f52bff088d02edf64fb931177a7eaJun Nakajima        tm->tm_sec = 0;
35286797937017f52bff088d02edf64fb931177a7eaJun Nakajima        tm->tm_min++;
35386797937017f52bff088d02edf64fb931177a7eaJun Nakajima        if ((unsigned)tm->tm_min >= 60) {
35486797937017f52bff088d02edf64fb931177a7eaJun Nakajima            tm->tm_min = 0;
35586797937017f52bff088d02edf64fb931177a7eaJun Nakajima            tm->tm_hour++;
35686797937017f52bff088d02edf64fb931177a7eaJun Nakajima            if ((unsigned)tm->tm_hour >= 24) {
35786797937017f52bff088d02edf64fb931177a7eaJun Nakajima                tm->tm_hour = 0;
35886797937017f52bff088d02edf64fb931177a7eaJun Nakajima                /* next day */
35986797937017f52bff088d02edf64fb931177a7eaJun Nakajima                tm->tm_wday++;
36086797937017f52bff088d02edf64fb931177a7eaJun Nakajima                if ((unsigned)tm->tm_wday >= 7)
36186797937017f52bff088d02edf64fb931177a7eaJun Nakajima                    tm->tm_wday = 0;
36286797937017f52bff088d02edf64fb931177a7eaJun Nakajima                days_in_month = get_days_in_month(tm->tm_mon,
36386797937017f52bff088d02edf64fb931177a7eaJun Nakajima                                                  tm->tm_year + 1900);
36486797937017f52bff088d02edf64fb931177a7eaJun Nakajima                tm->tm_mday++;
36586797937017f52bff088d02edf64fb931177a7eaJun Nakajima                if (tm->tm_mday < 1) {
36686797937017f52bff088d02edf64fb931177a7eaJun Nakajima                    tm->tm_mday = 1;
36786797937017f52bff088d02edf64fb931177a7eaJun Nakajima                } else if (tm->tm_mday > days_in_month) {
36886797937017f52bff088d02edf64fb931177a7eaJun Nakajima                    tm->tm_mday = 1;
36986797937017f52bff088d02edf64fb931177a7eaJun Nakajima                    tm->tm_mon++;
37086797937017f52bff088d02edf64fb931177a7eaJun Nakajima                    if (tm->tm_mon >= 12) {
37186797937017f52bff088d02edf64fb931177a7eaJun Nakajima                        tm->tm_mon = 0;
37286797937017f52bff088d02edf64fb931177a7eaJun Nakajima                        tm->tm_year++;
37386797937017f52bff088d02edf64fb931177a7eaJun Nakajima                    }
37486797937017f52bff088d02edf64fb931177a7eaJun Nakajima                }
37586797937017f52bff088d02edf64fb931177a7eaJun Nakajima            }
37686797937017f52bff088d02edf64fb931177a7eaJun Nakajima        }
37786797937017f52bff088d02edf64fb931177a7eaJun Nakajima    }
37886797937017f52bff088d02edf64fb931177a7eaJun Nakajima}
37986797937017f52bff088d02edf64fb931177a7eaJun Nakajima
38086797937017f52bff088d02edf64fb931177a7eaJun Nakajima
38186797937017f52bff088d02edf64fb931177a7eaJun Nakajimastatic void rtc_update_second(void *opaque)
38286797937017f52bff088d02edf64fb931177a7eaJun Nakajima{
38386797937017f52bff088d02edf64fb931177a7eaJun Nakajima    RTCState *s = opaque;
38486797937017f52bff088d02edf64fb931177a7eaJun Nakajima    int64_t delay;
38586797937017f52bff088d02edf64fb931177a7eaJun Nakajima
38686797937017f52bff088d02edf64fb931177a7eaJun Nakajima    /* if the oscillator is not in normal operation, we do not update */
38786797937017f52bff088d02edf64fb931177a7eaJun Nakajima    if ((s->cmos_data[RTC_REG_A] & 0x70) != 0x20) {
38886797937017f52bff088d02edf64fb931177a7eaJun Nakajima        s->next_second_time += get_ticks_per_sec();
38986797937017f52bff088d02edf64fb931177a7eaJun Nakajima        qemu_mod_timer(s->second_timer, s->next_second_time);
39086797937017f52bff088d02edf64fb931177a7eaJun Nakajima    } else {
39186797937017f52bff088d02edf64fb931177a7eaJun Nakajima        rtc_next_second(&s->current_tm);
39286797937017f52bff088d02edf64fb931177a7eaJun Nakajima
39386797937017f52bff088d02edf64fb931177a7eaJun Nakajima        if (!(s->cmos_data[RTC_REG_B] & REG_B_SET)) {
39486797937017f52bff088d02edf64fb931177a7eaJun Nakajima            /* update in progress bit */
39586797937017f52bff088d02edf64fb931177a7eaJun Nakajima            s->cmos_data[RTC_REG_A] |= REG_A_UIP;
39686797937017f52bff088d02edf64fb931177a7eaJun Nakajima        }
39786797937017f52bff088d02edf64fb931177a7eaJun Nakajima        /* should be 244 us = 8 / 32768 seconds, but currently the
39886797937017f52bff088d02edf64fb931177a7eaJun Nakajima           timers do not have the necessary resolution. */
39986797937017f52bff088d02edf64fb931177a7eaJun Nakajima        delay = (get_ticks_per_sec() * 1) / 100;
40086797937017f52bff088d02edf64fb931177a7eaJun Nakajima        if (delay < 1)
40186797937017f52bff088d02edf64fb931177a7eaJun Nakajima            delay = 1;
40286797937017f52bff088d02edf64fb931177a7eaJun Nakajima        qemu_mod_timer(s->second_timer2,
40386797937017f52bff088d02edf64fb931177a7eaJun Nakajima                       s->next_second_time + delay);
40486797937017f52bff088d02edf64fb931177a7eaJun Nakajima    }
40586797937017f52bff088d02edf64fb931177a7eaJun Nakajima}
40686797937017f52bff088d02edf64fb931177a7eaJun Nakajima
40786797937017f52bff088d02edf64fb931177a7eaJun Nakajimastatic void rtc_update_second2(void *opaque)
40886797937017f52bff088d02edf64fb931177a7eaJun Nakajima{
40986797937017f52bff088d02edf64fb931177a7eaJun Nakajima    RTCState *s = opaque;
41086797937017f52bff088d02edf64fb931177a7eaJun Nakajima
41186797937017f52bff088d02edf64fb931177a7eaJun Nakajima    if (!(s->cmos_data[RTC_REG_B] & REG_B_SET)) {
41286797937017f52bff088d02edf64fb931177a7eaJun Nakajima        rtc_copy_date(s);
41386797937017f52bff088d02edf64fb931177a7eaJun Nakajima    }
41486797937017f52bff088d02edf64fb931177a7eaJun Nakajima
41586797937017f52bff088d02edf64fb931177a7eaJun Nakajima    /* check alarm */
41686797937017f52bff088d02edf64fb931177a7eaJun Nakajima    if (s->cmos_data[RTC_REG_B] & REG_B_AIE) {
41786797937017f52bff088d02edf64fb931177a7eaJun Nakajima        if (((s->cmos_data[RTC_SECONDS_ALARM] & 0xc0) == 0xc0 ||
41886797937017f52bff088d02edf64fb931177a7eaJun Nakajima             s->cmos_data[RTC_SECONDS_ALARM] == s->current_tm.tm_sec) &&
41986797937017f52bff088d02edf64fb931177a7eaJun Nakajima            ((s->cmos_data[RTC_MINUTES_ALARM] & 0xc0) == 0xc0 ||
42086797937017f52bff088d02edf64fb931177a7eaJun Nakajima             s->cmos_data[RTC_MINUTES_ALARM] == s->current_tm.tm_mon) &&
42186797937017f52bff088d02edf64fb931177a7eaJun Nakajima            ((s->cmos_data[RTC_HOURS_ALARM] & 0xc0) == 0xc0 ||
42286797937017f52bff088d02edf64fb931177a7eaJun Nakajima             s->cmos_data[RTC_HOURS_ALARM] == s->current_tm.tm_hour)) {
42386797937017f52bff088d02edf64fb931177a7eaJun Nakajima
42486797937017f52bff088d02edf64fb931177a7eaJun Nakajima            s->cmos_data[RTC_REG_C] |= 0xa0;
42586797937017f52bff088d02edf64fb931177a7eaJun Nakajima            rtc_irq_raise(s->irq);
42686797937017f52bff088d02edf64fb931177a7eaJun Nakajima        }
42786797937017f52bff088d02edf64fb931177a7eaJun Nakajima    }
42886797937017f52bff088d02edf64fb931177a7eaJun Nakajima
42986797937017f52bff088d02edf64fb931177a7eaJun Nakajima    /* update ended interrupt */
43086797937017f52bff088d02edf64fb931177a7eaJun Nakajima    if (s->cmos_data[RTC_REG_B] & REG_B_UIE) {
43186797937017f52bff088d02edf64fb931177a7eaJun Nakajima        s->cmos_data[RTC_REG_C] |= 0x90;
43286797937017f52bff088d02edf64fb931177a7eaJun Nakajima        rtc_irq_raise(s->irq);
43386797937017f52bff088d02edf64fb931177a7eaJun Nakajima    }
43486797937017f52bff088d02edf64fb931177a7eaJun Nakajima
43586797937017f52bff088d02edf64fb931177a7eaJun Nakajima    /* clear update in progress bit */
43686797937017f52bff088d02edf64fb931177a7eaJun Nakajima    s->cmos_data[RTC_REG_A] &= ~REG_A_UIP;
43786797937017f52bff088d02edf64fb931177a7eaJun Nakajima
43886797937017f52bff088d02edf64fb931177a7eaJun Nakajima    s->next_second_time += get_ticks_per_sec();
43986797937017f52bff088d02edf64fb931177a7eaJun Nakajima    qemu_mod_timer(s->second_timer, s->next_second_time);
44086797937017f52bff088d02edf64fb931177a7eaJun Nakajima}
44186797937017f52bff088d02edf64fb931177a7eaJun Nakajima
44286797937017f52bff088d02edf64fb931177a7eaJun Nakajimastatic uint32_t cmos_ioport_read(void *opaque, uint32_t addr)
44386797937017f52bff088d02edf64fb931177a7eaJun Nakajima{
44486797937017f52bff088d02edf64fb931177a7eaJun Nakajima    RTCState *s = opaque;
44586797937017f52bff088d02edf64fb931177a7eaJun Nakajima    int ret;
44686797937017f52bff088d02edf64fb931177a7eaJun Nakajima    if ((addr & 1) == 0) {
44786797937017f52bff088d02edf64fb931177a7eaJun Nakajima        return 0xff;
44886797937017f52bff088d02edf64fb931177a7eaJun Nakajima    } else {
44986797937017f52bff088d02edf64fb931177a7eaJun Nakajima        switch(s->cmos_index) {
45086797937017f52bff088d02edf64fb931177a7eaJun Nakajima        case RTC_SECONDS:
45186797937017f52bff088d02edf64fb931177a7eaJun Nakajima        case RTC_MINUTES:
45286797937017f52bff088d02edf64fb931177a7eaJun Nakajima        case RTC_HOURS:
45386797937017f52bff088d02edf64fb931177a7eaJun Nakajima        case RTC_DAY_OF_WEEK:
45486797937017f52bff088d02edf64fb931177a7eaJun Nakajima        case RTC_DAY_OF_MONTH:
45586797937017f52bff088d02edf64fb931177a7eaJun Nakajima        case RTC_MONTH:
45686797937017f52bff088d02edf64fb931177a7eaJun Nakajima        case RTC_YEAR:
45786797937017f52bff088d02edf64fb931177a7eaJun Nakajima            ret = s->cmos_data[s->cmos_index];
45886797937017f52bff088d02edf64fb931177a7eaJun Nakajima            break;
45986797937017f52bff088d02edf64fb931177a7eaJun Nakajima        case RTC_REG_A:
46086797937017f52bff088d02edf64fb931177a7eaJun Nakajima            ret = s->cmos_data[s->cmos_index];
46186797937017f52bff088d02edf64fb931177a7eaJun Nakajima            break;
46286797937017f52bff088d02edf64fb931177a7eaJun Nakajima        case RTC_REG_C:
46386797937017f52bff088d02edf64fb931177a7eaJun Nakajima            ret = s->cmos_data[s->cmos_index];
46486797937017f52bff088d02edf64fb931177a7eaJun Nakajima            qemu_irq_lower(s->irq);
46586797937017f52bff088d02edf64fb931177a7eaJun Nakajima            s->cmos_data[RTC_REG_C] = 0x00;
46686797937017f52bff088d02edf64fb931177a7eaJun Nakajima            break;
46786797937017f52bff088d02edf64fb931177a7eaJun Nakajima        default:
46886797937017f52bff088d02edf64fb931177a7eaJun Nakajima            ret = s->cmos_data[s->cmos_index];
46986797937017f52bff088d02edf64fb931177a7eaJun Nakajima            break;
47086797937017f52bff088d02edf64fb931177a7eaJun Nakajima        }
47186797937017f52bff088d02edf64fb931177a7eaJun Nakajima#ifdef DEBUG_CMOS
47286797937017f52bff088d02edf64fb931177a7eaJun Nakajima        printf("cmos: read index=0x%02x val=0x%02x\n",
47386797937017f52bff088d02edf64fb931177a7eaJun Nakajima               s->cmos_index, ret);
47486797937017f52bff088d02edf64fb931177a7eaJun Nakajima#endif
47586797937017f52bff088d02edf64fb931177a7eaJun Nakajima        return ret;
47686797937017f52bff088d02edf64fb931177a7eaJun Nakajima    }
47786797937017f52bff088d02edf64fb931177a7eaJun Nakajima}
47886797937017f52bff088d02edf64fb931177a7eaJun Nakajima
47986797937017f52bff088d02edf64fb931177a7eaJun Nakajimavoid rtc_set_memory(RTCState *s, int addr, int val)
48086797937017f52bff088d02edf64fb931177a7eaJun Nakajima{
48186797937017f52bff088d02edf64fb931177a7eaJun Nakajima    if (addr >= 0 && addr <= 127)
48286797937017f52bff088d02edf64fb931177a7eaJun Nakajima        s->cmos_data[addr] = val;
48386797937017f52bff088d02edf64fb931177a7eaJun Nakajima}
48486797937017f52bff088d02edf64fb931177a7eaJun Nakajima
48586797937017f52bff088d02edf64fb931177a7eaJun Nakajimavoid rtc_set_date(RTCState *s, const struct tm *tm)
48686797937017f52bff088d02edf64fb931177a7eaJun Nakajima{
48786797937017f52bff088d02edf64fb931177a7eaJun Nakajima    s->current_tm = *tm;
48886797937017f52bff088d02edf64fb931177a7eaJun Nakajima    rtc_copy_date(s);
48986797937017f52bff088d02edf64fb931177a7eaJun Nakajima}
49086797937017f52bff088d02edf64fb931177a7eaJun Nakajima
49186797937017f52bff088d02edf64fb931177a7eaJun Nakajima/* PC cmos mappings */
49286797937017f52bff088d02edf64fb931177a7eaJun Nakajima#define REG_IBM_CENTURY_BYTE        0x32
49386797937017f52bff088d02edf64fb931177a7eaJun Nakajima#define REG_IBM_PS2_CENTURY_BYTE    0x37
49486797937017f52bff088d02edf64fb931177a7eaJun Nakajima
49586797937017f52bff088d02edf64fb931177a7eaJun Nakajimastatic void rtc_set_date_from_host(RTCState *s)
49686797937017f52bff088d02edf64fb931177a7eaJun Nakajima{
49786797937017f52bff088d02edf64fb931177a7eaJun Nakajima    struct tm tm;
49886797937017f52bff088d02edf64fb931177a7eaJun Nakajima    int val;
49986797937017f52bff088d02edf64fb931177a7eaJun Nakajima
50086797937017f52bff088d02edf64fb931177a7eaJun Nakajima    /* set the CMOS date */
50186797937017f52bff088d02edf64fb931177a7eaJun Nakajima    qemu_get_timedate(&tm, 0);
50286797937017f52bff088d02edf64fb931177a7eaJun Nakajima    rtc_set_date(s, &tm);
50386797937017f52bff088d02edf64fb931177a7eaJun Nakajima
50486797937017f52bff088d02edf64fb931177a7eaJun Nakajima    val = rtc_to_bcd(s, (tm.tm_year / 100) + 19);
50586797937017f52bff088d02edf64fb931177a7eaJun Nakajima    rtc_set_memory(s, REG_IBM_CENTURY_BYTE, val);
50686797937017f52bff088d02edf64fb931177a7eaJun Nakajima    rtc_set_memory(s, REG_IBM_PS2_CENTURY_BYTE, val);
50786797937017f52bff088d02edf64fb931177a7eaJun Nakajima}
50886797937017f52bff088d02edf64fb931177a7eaJun Nakajima
50986797937017f52bff088d02edf64fb931177a7eaJun Nakajimastatic void rtc_save(QEMUFile *f, void *opaque)
51086797937017f52bff088d02edf64fb931177a7eaJun Nakajima{
51186797937017f52bff088d02edf64fb931177a7eaJun Nakajima    RTCState *s = opaque;
51286797937017f52bff088d02edf64fb931177a7eaJun Nakajima
51386797937017f52bff088d02edf64fb931177a7eaJun Nakajima    qemu_put_buffer(f, s->cmos_data, 128);
51486797937017f52bff088d02edf64fb931177a7eaJun Nakajima    qemu_put_8s(f, &s->cmos_index);
51586797937017f52bff088d02edf64fb931177a7eaJun Nakajima
51686797937017f52bff088d02edf64fb931177a7eaJun Nakajima    qemu_put_be32(f, s->current_tm.tm_sec);
51786797937017f52bff088d02edf64fb931177a7eaJun Nakajima    qemu_put_be32(f, s->current_tm.tm_min);
51886797937017f52bff088d02edf64fb931177a7eaJun Nakajima    qemu_put_be32(f, s->current_tm.tm_hour);
51986797937017f52bff088d02edf64fb931177a7eaJun Nakajima    qemu_put_be32(f, s->current_tm.tm_wday);
52086797937017f52bff088d02edf64fb931177a7eaJun Nakajima    qemu_put_be32(f, s->current_tm.tm_mday);
52186797937017f52bff088d02edf64fb931177a7eaJun Nakajima    qemu_put_be32(f, s->current_tm.tm_mon);
52286797937017f52bff088d02edf64fb931177a7eaJun Nakajima    qemu_put_be32(f, s->current_tm.tm_year);
52386797937017f52bff088d02edf64fb931177a7eaJun Nakajima
52486797937017f52bff088d02edf64fb931177a7eaJun Nakajima    qemu_put_timer(f, s->periodic_timer);
52586797937017f52bff088d02edf64fb931177a7eaJun Nakajima    qemu_put_be64(f, s->next_periodic_time);
52686797937017f52bff088d02edf64fb931177a7eaJun Nakajima
52786797937017f52bff088d02edf64fb931177a7eaJun Nakajima    qemu_put_be64(f, s->next_second_time);
52886797937017f52bff088d02edf64fb931177a7eaJun Nakajima    qemu_put_timer(f, s->second_timer);
52986797937017f52bff088d02edf64fb931177a7eaJun Nakajima    qemu_put_timer(f, s->second_timer2);
53086797937017f52bff088d02edf64fb931177a7eaJun Nakajima}
53186797937017f52bff088d02edf64fb931177a7eaJun Nakajima
53286797937017f52bff088d02edf64fb931177a7eaJun Nakajimastatic int rtc_load(QEMUFile *f, void *opaque, int version_id)
53386797937017f52bff088d02edf64fb931177a7eaJun Nakajima{
53486797937017f52bff088d02edf64fb931177a7eaJun Nakajima    RTCState *s = opaque;
53586797937017f52bff088d02edf64fb931177a7eaJun Nakajima
53686797937017f52bff088d02edf64fb931177a7eaJun Nakajima    if (version_id != 1)
53786797937017f52bff088d02edf64fb931177a7eaJun Nakajima        return -EINVAL;
53886797937017f52bff088d02edf64fb931177a7eaJun Nakajima
53986797937017f52bff088d02edf64fb931177a7eaJun Nakajima    qemu_get_buffer(f, s->cmos_data, 128);
54086797937017f52bff088d02edf64fb931177a7eaJun Nakajima    qemu_get_8s(f, &s->cmos_index);
54186797937017f52bff088d02edf64fb931177a7eaJun Nakajima
54286797937017f52bff088d02edf64fb931177a7eaJun Nakajima    s->current_tm.tm_sec=qemu_get_be32(f);
54386797937017f52bff088d02edf64fb931177a7eaJun Nakajima    s->current_tm.tm_min=qemu_get_be32(f);
54486797937017f52bff088d02edf64fb931177a7eaJun Nakajima    s->current_tm.tm_hour=qemu_get_be32(f);
54586797937017f52bff088d02edf64fb931177a7eaJun Nakajima    s->current_tm.tm_wday=qemu_get_be32(f);
54686797937017f52bff088d02edf64fb931177a7eaJun Nakajima    s->current_tm.tm_mday=qemu_get_be32(f);
54786797937017f52bff088d02edf64fb931177a7eaJun Nakajima    s->current_tm.tm_mon=qemu_get_be32(f);
54886797937017f52bff088d02edf64fb931177a7eaJun Nakajima    s->current_tm.tm_year=qemu_get_be32(f);
54986797937017f52bff088d02edf64fb931177a7eaJun Nakajima
55086797937017f52bff088d02edf64fb931177a7eaJun Nakajima    qemu_get_timer(f, s->periodic_timer);
55186797937017f52bff088d02edf64fb931177a7eaJun Nakajima    s->next_periodic_time=qemu_get_be64(f);
55286797937017f52bff088d02edf64fb931177a7eaJun Nakajima
55386797937017f52bff088d02edf64fb931177a7eaJun Nakajima    s->next_second_time=qemu_get_be64(f);
55486797937017f52bff088d02edf64fb931177a7eaJun Nakajima    qemu_get_timer(f, s->second_timer);
55586797937017f52bff088d02edf64fb931177a7eaJun Nakajima    qemu_get_timer(f, s->second_timer2);
55686797937017f52bff088d02edf64fb931177a7eaJun Nakajima    return 0;
55786797937017f52bff088d02edf64fb931177a7eaJun Nakajima}
55886797937017f52bff088d02edf64fb931177a7eaJun Nakajima
55986797937017f52bff088d02edf64fb931177a7eaJun Nakajima#ifdef TARGET_I386
56086797937017f52bff088d02edf64fb931177a7eaJun Nakajimastatic void rtc_save_td(QEMUFile *f, void *opaque)
56186797937017f52bff088d02edf64fb931177a7eaJun Nakajima{
56286797937017f52bff088d02edf64fb931177a7eaJun Nakajima    RTCState *s = opaque;
56386797937017f52bff088d02edf64fb931177a7eaJun Nakajima
56486797937017f52bff088d02edf64fb931177a7eaJun Nakajima    qemu_put_be32(f, s->irq_coalesced);
56586797937017f52bff088d02edf64fb931177a7eaJun Nakajima    qemu_put_be32(f, s->period);
56686797937017f52bff088d02edf64fb931177a7eaJun Nakajima}
56786797937017f52bff088d02edf64fb931177a7eaJun Nakajima
56886797937017f52bff088d02edf64fb931177a7eaJun Nakajimastatic int rtc_load_td(QEMUFile *f, void *opaque, int version_id)
56986797937017f52bff088d02edf64fb931177a7eaJun Nakajima{
57086797937017f52bff088d02edf64fb931177a7eaJun Nakajima    RTCState *s = opaque;
57186797937017f52bff088d02edf64fb931177a7eaJun Nakajima
57286797937017f52bff088d02edf64fb931177a7eaJun Nakajima    if (version_id != 1)
57386797937017f52bff088d02edf64fb931177a7eaJun Nakajima        return -EINVAL;
57486797937017f52bff088d02edf64fb931177a7eaJun Nakajima
57586797937017f52bff088d02edf64fb931177a7eaJun Nakajima    s->irq_coalesced = qemu_get_be32(f);
57686797937017f52bff088d02edf64fb931177a7eaJun Nakajima    s->period = qemu_get_be32(f);
57786797937017f52bff088d02edf64fb931177a7eaJun Nakajima    rtc_coalesced_timer_update(s);
57886797937017f52bff088d02edf64fb931177a7eaJun Nakajima    return 0;
57986797937017f52bff088d02edf64fb931177a7eaJun Nakajima}
58086797937017f52bff088d02edf64fb931177a7eaJun Nakajima#endif
58186797937017f52bff088d02edf64fb931177a7eaJun Nakajima
58286797937017f52bff088d02edf64fb931177a7eaJun Nakajimastatic void rtc_reset(void *opaque)
58386797937017f52bff088d02edf64fb931177a7eaJun Nakajima{
58486797937017f52bff088d02edf64fb931177a7eaJun Nakajima    RTCState *s = opaque;
58586797937017f52bff088d02edf64fb931177a7eaJun Nakajima
58686797937017f52bff088d02edf64fb931177a7eaJun Nakajima    s->cmos_data[RTC_REG_B] &= ~(REG_B_PIE | REG_B_AIE | REG_B_SQWE);
58786797937017f52bff088d02edf64fb931177a7eaJun Nakajima    s->cmos_data[RTC_REG_C] &= ~(REG_C_UF | REG_C_IRQF | REG_C_PF | REG_C_AF);
58886797937017f52bff088d02edf64fb931177a7eaJun Nakajima
58986797937017f52bff088d02edf64fb931177a7eaJun Nakajima    qemu_irq_lower(s->irq);
59086797937017f52bff088d02edf64fb931177a7eaJun Nakajima
59186797937017f52bff088d02edf64fb931177a7eaJun Nakajima#ifdef TARGET_I386
59286797937017f52bff088d02edf64fb931177a7eaJun Nakajima    if (rtc_td_hack)
59386797937017f52bff088d02edf64fb931177a7eaJun Nakajima	    s->irq_coalesced = 0;
59486797937017f52bff088d02edf64fb931177a7eaJun Nakajima#endif
59586797937017f52bff088d02edf64fb931177a7eaJun Nakajima}
59686797937017f52bff088d02edf64fb931177a7eaJun Nakajima
59786797937017f52bff088d02edf64fb931177a7eaJun NakajimaRTCState *rtc_init_sqw(int base, qemu_irq irq, qemu_irq sqw_irq, int base_year)
59886797937017f52bff088d02edf64fb931177a7eaJun Nakajima{
59986797937017f52bff088d02edf64fb931177a7eaJun Nakajima    RTCState *s;
60086797937017f52bff088d02edf64fb931177a7eaJun Nakajima
60186797937017f52bff088d02edf64fb931177a7eaJun Nakajima    s = qemu_mallocz(sizeof(RTCState));
60286797937017f52bff088d02edf64fb931177a7eaJun Nakajima
60386797937017f52bff088d02edf64fb931177a7eaJun Nakajima    s->irq = irq;
60486797937017f52bff088d02edf64fb931177a7eaJun Nakajima    s->sqw_irq = sqw_irq;
60586797937017f52bff088d02edf64fb931177a7eaJun Nakajima    s->cmos_data[RTC_REG_A] = 0x26;
60686797937017f52bff088d02edf64fb931177a7eaJun Nakajima    s->cmos_data[RTC_REG_B] = 0x02;
60786797937017f52bff088d02edf64fb931177a7eaJun Nakajima    s->cmos_data[RTC_REG_C] = 0x00;
60886797937017f52bff088d02edf64fb931177a7eaJun Nakajima    s->cmos_data[RTC_REG_D] = 0x80;
60986797937017f52bff088d02edf64fb931177a7eaJun Nakajima
61086797937017f52bff088d02edf64fb931177a7eaJun Nakajima    s->base_year = base_year;
61186797937017f52bff088d02edf64fb931177a7eaJun Nakajima    rtc_set_date_from_host(s);
61286797937017f52bff088d02edf64fb931177a7eaJun Nakajima
6135973c775c853e26f684de58ad28c267281aaffd6David 'Digit' Turner    s->periodic_timer = qemu_new_timer_ns(vm_clock,
61486797937017f52bff088d02edf64fb931177a7eaJun Nakajima                                       rtc_periodic_timer, s);
61586797937017f52bff088d02edf64fb931177a7eaJun Nakajima#ifdef TARGET_I386
61686797937017f52bff088d02edf64fb931177a7eaJun Nakajima    if (rtc_td_hack)
6175973c775c853e26f684de58ad28c267281aaffd6David 'Digit' Turner        s->coalesced_timer = qemu_new_timer_ns(vm_clock, rtc_coalesced_timer, s);
61886797937017f52bff088d02edf64fb931177a7eaJun Nakajima#endif
6195973c775c853e26f684de58ad28c267281aaffd6David 'Digit' Turner    s->second_timer = qemu_new_timer_ns(vm_clock,
62086797937017f52bff088d02edf64fb931177a7eaJun Nakajima                                     rtc_update_second, s);
6215973c775c853e26f684de58ad28c267281aaffd6David 'Digit' Turner    s->second_timer2 = qemu_new_timer_ns(vm_clock,
62286797937017f52bff088d02edf64fb931177a7eaJun Nakajima                                      rtc_update_second2, s);
62386797937017f52bff088d02edf64fb931177a7eaJun Nakajima
6245973c775c853e26f684de58ad28c267281aaffd6David 'Digit' Turner    s->next_second_time = qemu_get_clock_ns(vm_clock) + (get_ticks_per_sec() * 99) / 100;
62586797937017f52bff088d02edf64fb931177a7eaJun Nakajima    qemu_mod_timer(s->second_timer2, s->next_second_time);
62686797937017f52bff088d02edf64fb931177a7eaJun Nakajima
62786797937017f52bff088d02edf64fb931177a7eaJun Nakajima    register_ioport_write(base, 2, 1, cmos_ioport_write, s);
62886797937017f52bff088d02edf64fb931177a7eaJun Nakajima    register_ioport_read(base, 2, 1, cmos_ioport_read, s);
62986797937017f52bff088d02edf64fb931177a7eaJun Nakajima
63086797937017f52bff088d02edf64fb931177a7eaJun Nakajima    register_savevm("mc146818rtc", base, 1, rtc_save, rtc_load, s);
63186797937017f52bff088d02edf64fb931177a7eaJun Nakajima#ifdef TARGET_I386
63286797937017f52bff088d02edf64fb931177a7eaJun Nakajima    if (rtc_td_hack)
63386797937017f52bff088d02edf64fb931177a7eaJun Nakajima        register_savevm("mc146818rtc-td", base, 1, rtc_save_td, rtc_load_td, s);
63486797937017f52bff088d02edf64fb931177a7eaJun Nakajima#endif
63586797937017f52bff088d02edf64fb931177a7eaJun Nakajima    qemu_register_reset(rtc_reset, 0, s);
63686797937017f52bff088d02edf64fb931177a7eaJun Nakajima
63786797937017f52bff088d02edf64fb931177a7eaJun Nakajima    return s;
63886797937017f52bff088d02edf64fb931177a7eaJun Nakajima}
63986797937017f52bff088d02edf64fb931177a7eaJun Nakajima
64086797937017f52bff088d02edf64fb931177a7eaJun NakajimaRTCState *rtc_init(int base, qemu_irq irq, int base_year)
64186797937017f52bff088d02edf64fb931177a7eaJun Nakajima{
64286797937017f52bff088d02edf64fb931177a7eaJun Nakajima    return rtc_init_sqw(base, irq, NULL, base_year);
64386797937017f52bff088d02edf64fb931177a7eaJun Nakajima}
64486797937017f52bff088d02edf64fb931177a7eaJun Nakajima
64586797937017f52bff088d02edf64fb931177a7eaJun Nakajima/* Memory mapped interface */
64686797937017f52bff088d02edf64fb931177a7eaJun Nakajimastatic uint32_t cmos_mm_readb (void *opaque, target_phys_addr_t addr)
64786797937017f52bff088d02edf64fb931177a7eaJun Nakajima{
64886797937017f52bff088d02edf64fb931177a7eaJun Nakajima    RTCState *s = opaque;
64986797937017f52bff088d02edf64fb931177a7eaJun Nakajima
65086797937017f52bff088d02edf64fb931177a7eaJun Nakajima    return cmos_ioport_read(s, addr >> s->it_shift) & 0xFF;
65186797937017f52bff088d02edf64fb931177a7eaJun Nakajima}
65286797937017f52bff088d02edf64fb931177a7eaJun Nakajima
65386797937017f52bff088d02edf64fb931177a7eaJun Nakajimastatic void cmos_mm_writeb (void *opaque,
65486797937017f52bff088d02edf64fb931177a7eaJun Nakajima                            target_phys_addr_t addr, uint32_t value)
65586797937017f52bff088d02edf64fb931177a7eaJun Nakajima{
65686797937017f52bff088d02edf64fb931177a7eaJun Nakajima    RTCState *s = opaque;
65786797937017f52bff088d02edf64fb931177a7eaJun Nakajima
65886797937017f52bff088d02edf64fb931177a7eaJun Nakajima    cmos_ioport_write(s, addr >> s->it_shift, value & 0xFF);
65986797937017f52bff088d02edf64fb931177a7eaJun Nakajima}
66086797937017f52bff088d02edf64fb931177a7eaJun Nakajima
66186797937017f52bff088d02edf64fb931177a7eaJun Nakajimastatic uint32_t cmos_mm_readw (void *opaque, target_phys_addr_t addr)
66286797937017f52bff088d02edf64fb931177a7eaJun Nakajima{
66386797937017f52bff088d02edf64fb931177a7eaJun Nakajima    RTCState *s = opaque;
66486797937017f52bff088d02edf64fb931177a7eaJun Nakajima    uint32_t val;
66586797937017f52bff088d02edf64fb931177a7eaJun Nakajima
66686797937017f52bff088d02edf64fb931177a7eaJun Nakajima    val = cmos_ioport_read(s, addr >> s->it_shift) & 0xFFFF;
66786797937017f52bff088d02edf64fb931177a7eaJun Nakajima#ifdef TARGET_WORDS_BIGENDIAN
66886797937017f52bff088d02edf64fb931177a7eaJun Nakajima    val = bswap16(val);
66986797937017f52bff088d02edf64fb931177a7eaJun Nakajima#endif
67086797937017f52bff088d02edf64fb931177a7eaJun Nakajima    return val;
67186797937017f52bff088d02edf64fb931177a7eaJun Nakajima}
67286797937017f52bff088d02edf64fb931177a7eaJun Nakajima
67386797937017f52bff088d02edf64fb931177a7eaJun Nakajimastatic void cmos_mm_writew (void *opaque,
67486797937017f52bff088d02edf64fb931177a7eaJun Nakajima                            target_phys_addr_t addr, uint32_t value)
67586797937017f52bff088d02edf64fb931177a7eaJun Nakajima{
67686797937017f52bff088d02edf64fb931177a7eaJun Nakajima    RTCState *s = opaque;
67786797937017f52bff088d02edf64fb931177a7eaJun Nakajima#ifdef TARGET_WORDS_BIGENDIAN
67886797937017f52bff088d02edf64fb931177a7eaJun Nakajima    value = bswap16(value);
67986797937017f52bff088d02edf64fb931177a7eaJun Nakajima#endif
68086797937017f52bff088d02edf64fb931177a7eaJun Nakajima    cmos_ioport_write(s, addr >> s->it_shift, value & 0xFFFF);
68186797937017f52bff088d02edf64fb931177a7eaJun Nakajima}
68286797937017f52bff088d02edf64fb931177a7eaJun Nakajima
68386797937017f52bff088d02edf64fb931177a7eaJun Nakajimastatic uint32_t cmos_mm_readl (void *opaque, target_phys_addr_t addr)
68486797937017f52bff088d02edf64fb931177a7eaJun Nakajima{
68586797937017f52bff088d02edf64fb931177a7eaJun Nakajima    RTCState *s = opaque;
68686797937017f52bff088d02edf64fb931177a7eaJun Nakajima    uint32_t val;
68786797937017f52bff088d02edf64fb931177a7eaJun Nakajima
68886797937017f52bff088d02edf64fb931177a7eaJun Nakajima    val = cmos_ioport_read(s, addr >> s->it_shift);
68986797937017f52bff088d02edf64fb931177a7eaJun Nakajima#ifdef TARGET_WORDS_BIGENDIAN
69086797937017f52bff088d02edf64fb931177a7eaJun Nakajima    val = bswap32(val);
69186797937017f52bff088d02edf64fb931177a7eaJun Nakajima#endif
69286797937017f52bff088d02edf64fb931177a7eaJun Nakajima    return val;
69386797937017f52bff088d02edf64fb931177a7eaJun Nakajima}
69486797937017f52bff088d02edf64fb931177a7eaJun Nakajima
69586797937017f52bff088d02edf64fb931177a7eaJun Nakajimastatic void cmos_mm_writel (void *opaque,
69686797937017f52bff088d02edf64fb931177a7eaJun Nakajima                            target_phys_addr_t addr, uint32_t value)
69786797937017f52bff088d02edf64fb931177a7eaJun Nakajima{
69886797937017f52bff088d02edf64fb931177a7eaJun Nakajima    RTCState *s = opaque;
69986797937017f52bff088d02edf64fb931177a7eaJun Nakajima#ifdef TARGET_WORDS_BIGENDIAN
70086797937017f52bff088d02edf64fb931177a7eaJun Nakajima    value = bswap32(value);
70186797937017f52bff088d02edf64fb931177a7eaJun Nakajima#endif
70286797937017f52bff088d02edf64fb931177a7eaJun Nakajima    cmos_ioport_write(s, addr >> s->it_shift, value);
70386797937017f52bff088d02edf64fb931177a7eaJun Nakajima}
70486797937017f52bff088d02edf64fb931177a7eaJun Nakajima
70586797937017f52bff088d02edf64fb931177a7eaJun Nakajimastatic CPUReadMemoryFunc *rtc_mm_read[] = {
70686797937017f52bff088d02edf64fb931177a7eaJun Nakajima    &cmos_mm_readb,
70786797937017f52bff088d02edf64fb931177a7eaJun Nakajima    &cmos_mm_readw,
70886797937017f52bff088d02edf64fb931177a7eaJun Nakajima    &cmos_mm_readl,
70986797937017f52bff088d02edf64fb931177a7eaJun Nakajima};
71086797937017f52bff088d02edf64fb931177a7eaJun Nakajima
71186797937017f52bff088d02edf64fb931177a7eaJun Nakajimastatic CPUWriteMemoryFunc *rtc_mm_write[] = {
71286797937017f52bff088d02edf64fb931177a7eaJun Nakajima    &cmos_mm_writeb,
71386797937017f52bff088d02edf64fb931177a7eaJun Nakajima    &cmos_mm_writew,
71486797937017f52bff088d02edf64fb931177a7eaJun Nakajima    &cmos_mm_writel,
71586797937017f52bff088d02edf64fb931177a7eaJun Nakajima};
71686797937017f52bff088d02edf64fb931177a7eaJun Nakajima
71786797937017f52bff088d02edf64fb931177a7eaJun NakajimaRTCState *rtc_mm_init(target_phys_addr_t base, int it_shift, qemu_irq irq,
71886797937017f52bff088d02edf64fb931177a7eaJun Nakajima                      int base_year)
71986797937017f52bff088d02edf64fb931177a7eaJun Nakajima{
72086797937017f52bff088d02edf64fb931177a7eaJun Nakajima    RTCState *s;
72186797937017f52bff088d02edf64fb931177a7eaJun Nakajima    int io_memory;
72286797937017f52bff088d02edf64fb931177a7eaJun Nakajima
72386797937017f52bff088d02edf64fb931177a7eaJun Nakajima    s = qemu_mallocz(sizeof(RTCState));
72486797937017f52bff088d02edf64fb931177a7eaJun Nakajima
72586797937017f52bff088d02edf64fb931177a7eaJun Nakajima    s->irq = irq;
72686797937017f52bff088d02edf64fb931177a7eaJun Nakajima    s->cmos_data[RTC_REG_A] = 0x26;
72786797937017f52bff088d02edf64fb931177a7eaJun Nakajima    s->cmos_data[RTC_REG_B] = 0x02;
72886797937017f52bff088d02edf64fb931177a7eaJun Nakajima    s->cmos_data[RTC_REG_C] = 0x00;
72986797937017f52bff088d02edf64fb931177a7eaJun Nakajima    s->cmos_data[RTC_REG_D] = 0x80;
73086797937017f52bff088d02edf64fb931177a7eaJun Nakajima
73186797937017f52bff088d02edf64fb931177a7eaJun Nakajima    s->base_year = base_year;
73286797937017f52bff088d02edf64fb931177a7eaJun Nakajima    rtc_set_date_from_host(s);
73386797937017f52bff088d02edf64fb931177a7eaJun Nakajima
7345973c775c853e26f684de58ad28c267281aaffd6David 'Digit' Turner    s->periodic_timer = qemu_new_timer_ns(vm_clock,
73586797937017f52bff088d02edf64fb931177a7eaJun Nakajima                                       rtc_periodic_timer, s);
7365973c775c853e26f684de58ad28c267281aaffd6David 'Digit' Turner    s->second_timer = qemu_new_timer_ns(vm_clock,
73786797937017f52bff088d02edf64fb931177a7eaJun Nakajima                                     rtc_update_second, s);
7385973c775c853e26f684de58ad28c267281aaffd6David 'Digit' Turner    s->second_timer2 = qemu_new_timer_ns(vm_clock,
73986797937017f52bff088d02edf64fb931177a7eaJun Nakajima                                      rtc_update_second2, s);
74086797937017f52bff088d02edf64fb931177a7eaJun Nakajima
7415973c775c853e26f684de58ad28c267281aaffd6David 'Digit' Turner    s->next_second_time = qemu_get_clock_ns(vm_clock) + (get_ticks_per_sec() * 99) / 100;
74286797937017f52bff088d02edf64fb931177a7eaJun Nakajima    qemu_mod_timer(s->second_timer2, s->next_second_time);
74386797937017f52bff088d02edf64fb931177a7eaJun Nakajima
74486797937017f52bff088d02edf64fb931177a7eaJun Nakajima    io_memory = cpu_register_io_memory(rtc_mm_read, rtc_mm_write, s);
74586797937017f52bff088d02edf64fb931177a7eaJun Nakajima    cpu_register_physical_memory(base, 2 << it_shift, io_memory);
74686797937017f52bff088d02edf64fb931177a7eaJun Nakajima
74786797937017f52bff088d02edf64fb931177a7eaJun Nakajima    register_savevm("mc146818rtc", base, 1, rtc_save, rtc_load, s);
74886797937017f52bff088d02edf64fb931177a7eaJun Nakajima#ifdef TARGET_I386
74986797937017f52bff088d02edf64fb931177a7eaJun Nakajima    if (rtc_td_hack)
75086797937017f52bff088d02edf64fb931177a7eaJun Nakajima        register_savevm("mc146818rtc-td", base, 1, rtc_save_td, rtc_load_td, s);
75186797937017f52bff088d02edf64fb931177a7eaJun Nakajima#endif
75286797937017f52bff088d02edf64fb931177a7eaJun Nakajima    qemu_register_reset(rtc_reset, 0, s);
75386797937017f52bff088d02edf64fb931177a7eaJun Nakajima    return s;
75486797937017f52bff088d02edf64fb931177a7eaJun Nakajima}
755