mc146818.cc revision 6772
15392Sgblack@eecs.umich.edu/* 25392Sgblack@eecs.umich.edu * Copyright (c) 2004-2005 The Regents of The University of Michigan 35392Sgblack@eecs.umich.edu * All rights reserved. 45392Sgblack@eecs.umich.edu * 55392Sgblack@eecs.umich.edu * Redistribution and use in source and binary forms, with or without 65392Sgblack@eecs.umich.edu * modification, are permitted provided that the following conditions are 75392Sgblack@eecs.umich.edu * met: redistributions of source code must retain the above copyright 85392Sgblack@eecs.umich.edu * notice, this list of conditions and the following disclaimer; 95392Sgblack@eecs.umich.edu * redistributions in binary form must reproduce the above copyright 105392Sgblack@eecs.umich.edu * notice, this list of conditions and the following disclaimer in the 115392Sgblack@eecs.umich.edu * documentation and/or other materials provided with the distribution; 125392Sgblack@eecs.umich.edu * neither the name of the copyright holders nor the names of its 135392Sgblack@eecs.umich.edu * contributors may be used to endorse or promote products derived from 145392Sgblack@eecs.umich.edu * this software without specific prior written permission. 155392Sgblack@eecs.umich.edu * 165392Sgblack@eecs.umich.edu * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 175392Sgblack@eecs.umich.edu * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 185392Sgblack@eecs.umich.edu * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 195392Sgblack@eecs.umich.edu * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 205392Sgblack@eecs.umich.edu * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 215392Sgblack@eecs.umich.edu * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 225392Sgblack@eecs.umich.edu * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 235392Sgblack@eecs.umich.edu * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 245392Sgblack@eecs.umich.edu * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 255392Sgblack@eecs.umich.edu * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 265392Sgblack@eecs.umich.edu * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 275392Sgblack@eecs.umich.edu * 285392Sgblack@eecs.umich.edu * Authors: Ali Saidi 295392Sgblack@eecs.umich.edu * Andrew Schultz 305392Sgblack@eecs.umich.edu * Miguel Serrano 315392Sgblack@eecs.umich.edu */ 325392Sgblack@eecs.umich.edu 335392Sgblack@eecs.umich.edu#include <sys/time.h> 345392Sgblack@eecs.umich.edu#include <time.h> 355392Sgblack@eecs.umich.edu 365392Sgblack@eecs.umich.edu#include <string> 375392Sgblack@eecs.umich.edu 385813Sgblack@eecs.umich.edu#include "base/bitfield.hh" 395392Sgblack@eecs.umich.edu#include "base/time.hh" 405392Sgblack@eecs.umich.edu#include "base/trace.hh" 415392Sgblack@eecs.umich.edu#include "dev/mc146818.hh" 425392Sgblack@eecs.umich.edu#include "dev/rtcreg.h" 435392Sgblack@eecs.umich.edu 445392Sgblack@eecs.umich.eduusing namespace std; 455392Sgblack@eecs.umich.edu 466620Sgblack@eecs.umich.edustatic uint8_t 476620Sgblack@eecs.umich.edubcdize(uint8_t val) 485392Sgblack@eecs.umich.edu{ 496620Sgblack@eecs.umich.edu uint8_t result; 506620Sgblack@eecs.umich.edu result = val % 10; 516620Sgblack@eecs.umich.edu result += (val / 10) << 4; 526620Sgblack@eecs.umich.edu return result; 536620Sgblack@eecs.umich.edu} 545392Sgblack@eecs.umich.edu 556621Sgblack@eecs.umich.edustatic uint8_t 566621Sgblack@eecs.umich.eduunbcdize(uint8_t val) 576621Sgblack@eecs.umich.edu{ 586621Sgblack@eecs.umich.edu uint8_t result; 596621Sgblack@eecs.umich.edu result = val & 0xf; 606621Sgblack@eecs.umich.edu result += (val >> 4) * 10; 616621Sgblack@eecs.umich.edu return result; 626621Sgblack@eecs.umich.edu} 636621Sgblack@eecs.umich.edu 646620Sgblack@eecs.umich.eduvoid 656620Sgblack@eecs.umich.eduMC146818::setTime(const struct tm time) 666620Sgblack@eecs.umich.edu{ 676620Sgblack@eecs.umich.edu curTime = time; 685392Sgblack@eecs.umich.edu year = time.tm_year; 695392Sgblack@eecs.umich.edu // Unix is 0-11 for month, data seet says start at 1 705392Sgblack@eecs.umich.edu mon = time.tm_mon + 1; 715392Sgblack@eecs.umich.edu mday = time.tm_mday; 725392Sgblack@eecs.umich.edu hour = time.tm_hour; 735392Sgblack@eecs.umich.edu min = time.tm_min; 745392Sgblack@eecs.umich.edu sec = time.tm_sec; 755392Sgblack@eecs.umich.edu 765392Sgblack@eecs.umich.edu // Datasheet says 1 is sunday 775392Sgblack@eecs.umich.edu wday = time.tm_wday + 1; 785392Sgblack@eecs.umich.edu 796620Sgblack@eecs.umich.edu if (!(stat_regB & RTCB_BIN)) { 806620Sgblack@eecs.umich.edu // The datasheet says that the year field can be either BCD or 816620Sgblack@eecs.umich.edu // years since 1900. Linux seems to be happy with years since 826620Sgblack@eecs.umich.edu // 1900. 836620Sgblack@eecs.umich.edu year = bcdize(year % 100); 846620Sgblack@eecs.umich.edu mon = bcdize(mon); 856620Sgblack@eecs.umich.edu mday = bcdize(mday); 866620Sgblack@eecs.umich.edu hour = bcdize(hour); 876620Sgblack@eecs.umich.edu min = bcdize(min); 886620Sgblack@eecs.umich.edu sec = bcdize(sec); 896620Sgblack@eecs.umich.edu } 906620Sgblack@eecs.umich.edu} 916620Sgblack@eecs.umich.edu 926620Sgblack@eecs.umich.eduMC146818::MC146818(EventManager *em, const string &n, const struct tm time, 936620Sgblack@eecs.umich.edu bool bcd, Tick frequency) 946620Sgblack@eecs.umich.edu : EventManager(em), _name(n), event(this, frequency), tickEvent(this) 956620Sgblack@eecs.umich.edu{ 966620Sgblack@eecs.umich.edu memset(clock_data, 0, sizeof(clock_data)); 976620Sgblack@eecs.umich.edu stat_regA = RTCA_32768HZ | RTCA_1024HZ; 986620Sgblack@eecs.umich.edu stat_regB = RTCB_PRDC_IE | RTCB_24HR; 996620Sgblack@eecs.umich.edu if (!bcd) 1006620Sgblack@eecs.umich.edu stat_regB |= RTCB_BIN; 1016620Sgblack@eecs.umich.edu 1026620Sgblack@eecs.umich.edu setTime(time); 1035392Sgblack@eecs.umich.edu DPRINTFN("Real-time clock set to %s", asctime(&time)); 1045392Sgblack@eecs.umich.edu} 1055392Sgblack@eecs.umich.edu 1065606Snate@binkert.orgMC146818::~MC146818() 1075606Snate@binkert.org{ 1086772SBrad.Beckmann@amd.com deschedule(tickEvent); 1096772SBrad.Beckmann@amd.com deschedule(event); 1105606Snate@binkert.org} 1115606Snate@binkert.org 1125392Sgblack@eecs.umich.eduvoid 1135392Sgblack@eecs.umich.eduMC146818::writeData(const uint8_t addr, const uint8_t data) 1145392Sgblack@eecs.umich.edu{ 1156621Sgblack@eecs.umich.edu if (addr < RTC_STAT_REGA) { 1165392Sgblack@eecs.umich.edu clock_data[addr] = data; 1176621Sgblack@eecs.umich.edu curTime.tm_sec = unbcdize(sec); 1186621Sgblack@eecs.umich.edu curTime.tm_min = unbcdize(min); 1196621Sgblack@eecs.umich.edu curTime.tm_hour = unbcdize(hour); 1206621Sgblack@eecs.umich.edu curTime.tm_mday = unbcdize(mday); 1216621Sgblack@eecs.umich.edu curTime.tm_mon = unbcdize(mon) - 1; 1226621Sgblack@eecs.umich.edu curTime.tm_year = ((unbcdize(year) + 50) % 100) + 1950; 1236621Sgblack@eecs.umich.edu curTime.tm_wday = unbcdize(wday) - 1; 1246621Sgblack@eecs.umich.edu } else { 1255392Sgblack@eecs.umich.edu switch (addr) { 1265392Sgblack@eecs.umich.edu case RTC_STAT_REGA: 1275813Sgblack@eecs.umich.edu // The "update in progress" bit is read only. 1285813Sgblack@eecs.umich.edu if ((data & ~RTCA_UIP) != (RTCA_32768HZ | RTCA_1024HZ)) 1295392Sgblack@eecs.umich.edu panic("Unimplemented RTC register A value write!\n"); 1305813Sgblack@eecs.umich.edu replaceBits(stat_regA, data, 6, 0); 1315392Sgblack@eecs.umich.edu break; 1325392Sgblack@eecs.umich.edu case RTC_STAT_REGB: 1336617Sgblack@eecs.umich.edu if ((data & ~(RTCB_PRDC_IE | RTCB_SQWE)) != RTCB_24HR) 1345392Sgblack@eecs.umich.edu panic("Write to RTC reg B bits that are not implemented!\n"); 1355392Sgblack@eecs.umich.edu 1365392Sgblack@eecs.umich.edu if (data & RTCB_PRDC_IE) { 1375392Sgblack@eecs.umich.edu if (!event.scheduled()) 1385392Sgblack@eecs.umich.edu event.scheduleIntr(); 1395392Sgblack@eecs.umich.edu } else { 1405392Sgblack@eecs.umich.edu if (event.scheduled()) 1415606Snate@binkert.org deschedule(event); 1425392Sgblack@eecs.umich.edu } 1435392Sgblack@eecs.umich.edu stat_regB = data; 1445392Sgblack@eecs.umich.edu break; 1455392Sgblack@eecs.umich.edu case RTC_STAT_REGC: 1465392Sgblack@eecs.umich.edu case RTC_STAT_REGD: 1475392Sgblack@eecs.umich.edu panic("RTC status registers C and D are not implemented.\n"); 1485392Sgblack@eecs.umich.edu break; 1495392Sgblack@eecs.umich.edu } 1505392Sgblack@eecs.umich.edu } 1515392Sgblack@eecs.umich.edu} 1525392Sgblack@eecs.umich.edu 1535392Sgblack@eecs.umich.eduuint8_t 1545392Sgblack@eecs.umich.eduMC146818::readData(uint8_t addr) 1555392Sgblack@eecs.umich.edu{ 1565392Sgblack@eecs.umich.edu if (addr < RTC_STAT_REGA) 1575392Sgblack@eecs.umich.edu return clock_data[addr]; 1585392Sgblack@eecs.umich.edu else { 1595392Sgblack@eecs.umich.edu switch (addr) { 1605392Sgblack@eecs.umich.edu case RTC_STAT_REGA: 1615392Sgblack@eecs.umich.edu // toggle UIP bit for linux 1625392Sgblack@eecs.umich.edu stat_regA ^= RTCA_UIP; 1635392Sgblack@eecs.umich.edu return stat_regA; 1645392Sgblack@eecs.umich.edu break; 1655392Sgblack@eecs.umich.edu case RTC_STAT_REGB: 1665392Sgblack@eecs.umich.edu return stat_regB; 1675392Sgblack@eecs.umich.edu break; 1685392Sgblack@eecs.umich.edu case RTC_STAT_REGC: 1695392Sgblack@eecs.umich.edu case RTC_STAT_REGD: 1705392Sgblack@eecs.umich.edu return 0x00; 1715392Sgblack@eecs.umich.edu break; 1725392Sgblack@eecs.umich.edu default: 1735392Sgblack@eecs.umich.edu panic("Shouldn't be here"); 1745392Sgblack@eecs.umich.edu } 1755392Sgblack@eecs.umich.edu } 1765392Sgblack@eecs.umich.edu} 1775392Sgblack@eecs.umich.edu 1786620Sgblack@eecs.umich.edustatic time_t 1796620Sgblack@eecs.umich.edumkutctime(struct tm *time) 1806620Sgblack@eecs.umich.edu{ 1816620Sgblack@eecs.umich.edu time_t ret; 1826620Sgblack@eecs.umich.edu char *tz; 1836620Sgblack@eecs.umich.edu 1846620Sgblack@eecs.umich.edu tz = getenv("TZ"); 1856620Sgblack@eecs.umich.edu setenv("TZ", "", 1); 1866620Sgblack@eecs.umich.edu tzset(); 1876620Sgblack@eecs.umich.edu ret = mktime(time); 1886620Sgblack@eecs.umich.edu if (tz) 1896620Sgblack@eecs.umich.edu setenv("TZ", tz, 1); 1906620Sgblack@eecs.umich.edu else 1916620Sgblack@eecs.umich.edu unsetenv("TZ"); 1926620Sgblack@eecs.umich.edu tzset(); 1936620Sgblack@eecs.umich.edu return ret; 1946620Sgblack@eecs.umich.edu} 1956620Sgblack@eecs.umich.edu 1966620Sgblack@eecs.umich.eduvoid 1976620Sgblack@eecs.umich.eduMC146818::tickClock() 1986620Sgblack@eecs.umich.edu{ 1996620Sgblack@eecs.umich.edu if (stat_regB & RTCB_NO_UPDT) 2006620Sgblack@eecs.umich.edu return; 2016620Sgblack@eecs.umich.edu time_t calTime = mkutctime(&curTime); 2026620Sgblack@eecs.umich.edu calTime++; 2036620Sgblack@eecs.umich.edu setTime(*gmtime(&calTime)); 2046620Sgblack@eecs.umich.edu} 2056620Sgblack@eecs.umich.edu 2065392Sgblack@eecs.umich.eduvoid 2075392Sgblack@eecs.umich.eduMC146818::serialize(const string &base, ostream &os) 2085392Sgblack@eecs.umich.edu{ 2095392Sgblack@eecs.umich.edu arrayParamOut(os, base + ".clock_data", clock_data, sizeof(clock_data)); 2105392Sgblack@eecs.umich.edu paramOut(os, base + ".stat_regA", stat_regA); 2115392Sgblack@eecs.umich.edu paramOut(os, base + ".stat_regB", stat_regB); 2126677SBrad.Beckmann@amd.com 2136677SBrad.Beckmann@amd.com // 2146677SBrad.Beckmann@amd.com // save the timer tick and rtc clock tick values to correctly reschedule 2156677SBrad.Beckmann@amd.com // them during unserialize 2166677SBrad.Beckmann@amd.com // 2176677SBrad.Beckmann@amd.com Tick rtcTimerInterruptTickOffset = event.when() - curTick; 2186677SBrad.Beckmann@amd.com SERIALIZE_SCALAR(rtcTimerInterruptTickOffset); 2196677SBrad.Beckmann@amd.com Tick rtcClockTickOffset = event.when() - curTick; 2206677SBrad.Beckmann@amd.com SERIALIZE_SCALAR(rtcClockTickOffset); 2215392Sgblack@eecs.umich.edu} 2225392Sgblack@eecs.umich.edu 2235392Sgblack@eecs.umich.eduvoid 2245392Sgblack@eecs.umich.eduMC146818::unserialize(const string &base, Checkpoint *cp, 2255392Sgblack@eecs.umich.edu const string §ion) 2265392Sgblack@eecs.umich.edu{ 2275392Sgblack@eecs.umich.edu arrayParamIn(cp, section, base + ".clock_data", clock_data, 2285392Sgblack@eecs.umich.edu sizeof(clock_data)); 2295392Sgblack@eecs.umich.edu paramIn(cp, section, base + ".stat_regA", stat_regA); 2305392Sgblack@eecs.umich.edu paramIn(cp, section, base + ".stat_regB", stat_regB); 2315392Sgblack@eecs.umich.edu 2326677SBrad.Beckmann@amd.com // 2336677SBrad.Beckmann@amd.com // properly schedule the timer and rtc clock events 2346677SBrad.Beckmann@amd.com // 2356677SBrad.Beckmann@amd.com Tick rtcTimerInterruptTickOffset; 2366677SBrad.Beckmann@amd.com UNSERIALIZE_SCALAR(rtcTimerInterruptTickOffset); 2376677SBrad.Beckmann@amd.com reschedule(event, curTick + rtcTimerInterruptTickOffset); 2386677SBrad.Beckmann@amd.com Tick rtcClockTickOffset; 2396677SBrad.Beckmann@amd.com UNSERIALIZE_SCALAR(rtcClockTickOffset); 2406677SBrad.Beckmann@amd.com reschedule(tickEvent, curTick + rtcClockTickOffset); 2415392Sgblack@eecs.umich.edu} 2425392Sgblack@eecs.umich.edu 2435392Sgblack@eecs.umich.eduMC146818::RTCEvent::RTCEvent(MC146818 * _parent, Tick i) 2445606Snate@binkert.org : parent(_parent), interval(i) 2455392Sgblack@eecs.umich.edu{ 2465392Sgblack@eecs.umich.edu DPRINTF(MC146818, "RTC Event Initilizing\n"); 2475606Snate@binkert.org parent->schedule(this, curTick + interval); 2485392Sgblack@eecs.umich.edu} 2495392Sgblack@eecs.umich.edu 2505392Sgblack@eecs.umich.eduvoid 2515392Sgblack@eecs.umich.eduMC146818::RTCEvent::scheduleIntr() 2525392Sgblack@eecs.umich.edu{ 2535606Snate@binkert.org parent->schedule(this, curTick + interval); 2545392Sgblack@eecs.umich.edu} 2555392Sgblack@eecs.umich.edu 2565392Sgblack@eecs.umich.eduvoid 2575392Sgblack@eecs.umich.eduMC146818::RTCEvent::process() 2585392Sgblack@eecs.umich.edu{ 2595392Sgblack@eecs.umich.edu DPRINTF(MC146818, "RTC Timer Interrupt\n"); 2605606Snate@binkert.org parent->schedule(this, curTick + interval); 2615392Sgblack@eecs.umich.edu parent->handleEvent(); 2625392Sgblack@eecs.umich.edu} 2635392Sgblack@eecs.umich.edu 2645392Sgblack@eecs.umich.educonst char * 2655392Sgblack@eecs.umich.eduMC146818::RTCEvent::description() const 2665392Sgblack@eecs.umich.edu{ 2675392Sgblack@eecs.umich.edu return "RTC interrupt"; 2685392Sgblack@eecs.umich.edu} 2696620Sgblack@eecs.umich.edu 2706620Sgblack@eecs.umich.eduvoid 2716620Sgblack@eecs.umich.eduMC146818::RTCTickEvent::process() 2726620Sgblack@eecs.umich.edu{ 2736620Sgblack@eecs.umich.edu DPRINTF(MC146818, "RTC clock tick\n"); 2746620Sgblack@eecs.umich.edu parent->schedule(this, curTick + Clock::Int::s); 2756620Sgblack@eecs.umich.edu parent->tickClock(); 2766620Sgblack@eecs.umich.edu} 2776620Sgblack@eecs.umich.edu 2786620Sgblack@eecs.umich.educonst char * 2796620Sgblack@eecs.umich.eduMC146818::RTCTickEvent::description() const 2806620Sgblack@eecs.umich.edu{ 2816620Sgblack@eecs.umich.edu return "RTC clock tick"; 2826620Sgblack@eecs.umich.edu} 283