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