mc146818.cc revision 5392
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
385392Sgblack@eecs.umich.edu#include "base/time.hh"
395392Sgblack@eecs.umich.edu#include "base/trace.hh"
405392Sgblack@eecs.umich.edu#include "dev/mc146818.hh"
415392Sgblack@eecs.umich.edu#include "dev/rtcreg.h"
425392Sgblack@eecs.umich.edu
435392Sgblack@eecs.umich.eduusing namespace std;
445392Sgblack@eecs.umich.edu
455392Sgblack@eecs.umich.eduMC146818::MC146818(const string &n, const struct tm time,
465392Sgblack@eecs.umich.edu        bool bcd, Tick frequency)
475392Sgblack@eecs.umich.edu    : _name(n), event(this, frequency)
485392Sgblack@eecs.umich.edu{
495392Sgblack@eecs.umich.edu    memset(clock_data, 0, sizeof(clock_data));
505392Sgblack@eecs.umich.edu    stat_regA = RTCA_32768HZ | RTCA_1024HZ;
515392Sgblack@eecs.umich.edu    stat_regB = RTCB_PRDC_IE |RTCB_BIN | RTCB_24HR;
525392Sgblack@eecs.umich.edu
535392Sgblack@eecs.umich.edu    year = time.tm_year;
545392Sgblack@eecs.umich.edu
555392Sgblack@eecs.umich.edu    if (bcd) {
565392Sgblack@eecs.umich.edu        // The datasheet says that the year field can be either BCD or
575392Sgblack@eecs.umich.edu        // years since 1900.  Linux seems to be happy with years since
585392Sgblack@eecs.umich.edu        // 1900.
595392Sgblack@eecs.umich.edu        year = year % 100;
605392Sgblack@eecs.umich.edu        int tens = year / 10;
615392Sgblack@eecs.umich.edu        int ones = year % 10;
625392Sgblack@eecs.umich.edu        year = (tens << 4) + ones;
635392Sgblack@eecs.umich.edu    }
645392Sgblack@eecs.umich.edu
655392Sgblack@eecs.umich.edu    // Unix is 0-11 for month, data seet says start at 1
665392Sgblack@eecs.umich.edu    mon = time.tm_mon + 1;
675392Sgblack@eecs.umich.edu    mday = time.tm_mday;
685392Sgblack@eecs.umich.edu    hour = time.tm_hour;
695392Sgblack@eecs.umich.edu    min = time.tm_min;
705392Sgblack@eecs.umich.edu    sec = time.tm_sec;
715392Sgblack@eecs.umich.edu
725392Sgblack@eecs.umich.edu    // Datasheet says 1 is sunday
735392Sgblack@eecs.umich.edu    wday = time.tm_wday + 1;
745392Sgblack@eecs.umich.edu
755392Sgblack@eecs.umich.edu    DPRINTFN("Real-time clock set to %s", asctime(&time));
765392Sgblack@eecs.umich.edu}
775392Sgblack@eecs.umich.edu
785392Sgblack@eecs.umich.eduvoid
795392Sgblack@eecs.umich.eduMC146818::writeData(const uint8_t addr, const uint8_t data)
805392Sgblack@eecs.umich.edu{
815392Sgblack@eecs.umich.edu    if (addr < RTC_STAT_REGA)
825392Sgblack@eecs.umich.edu        clock_data[addr] = data;
835392Sgblack@eecs.umich.edu    else {
845392Sgblack@eecs.umich.edu        switch (addr) {
855392Sgblack@eecs.umich.edu          case RTC_STAT_REGA:
865392Sgblack@eecs.umich.edu            if (data != (RTCA_32768HZ | RTCA_1024HZ))
875392Sgblack@eecs.umich.edu                panic("Unimplemented RTC register A value write!\n");
885392Sgblack@eecs.umich.edu            stat_regA = data;
895392Sgblack@eecs.umich.edu            break;
905392Sgblack@eecs.umich.edu          case RTC_STAT_REGB:
915392Sgblack@eecs.umich.edu            if ((data & ~(RTCB_PRDC_IE | RTCB_SQWE)) != (RTCB_BIN | RTCB_24HR))
925392Sgblack@eecs.umich.edu                panic("Write to RTC reg B bits that are not implemented!\n");
935392Sgblack@eecs.umich.edu
945392Sgblack@eecs.umich.edu            if (data & RTCB_PRDC_IE) {
955392Sgblack@eecs.umich.edu                if (!event.scheduled())
965392Sgblack@eecs.umich.edu                    event.scheduleIntr();
975392Sgblack@eecs.umich.edu            } else {
985392Sgblack@eecs.umich.edu                if (event.scheduled())
995392Sgblack@eecs.umich.edu                    event.deschedule();
1005392Sgblack@eecs.umich.edu            }
1015392Sgblack@eecs.umich.edu            stat_regB = data;
1025392Sgblack@eecs.umich.edu            break;
1035392Sgblack@eecs.umich.edu          case RTC_STAT_REGC:
1045392Sgblack@eecs.umich.edu          case RTC_STAT_REGD:
1055392Sgblack@eecs.umich.edu            panic("RTC status registers C and D are not implemented.\n");
1065392Sgblack@eecs.umich.edu            break;
1075392Sgblack@eecs.umich.edu        }
1085392Sgblack@eecs.umich.edu    }
1095392Sgblack@eecs.umich.edu}
1105392Sgblack@eecs.umich.edu
1115392Sgblack@eecs.umich.eduuint8_t
1125392Sgblack@eecs.umich.eduMC146818::readData(uint8_t addr)
1135392Sgblack@eecs.umich.edu{
1145392Sgblack@eecs.umich.edu    if (addr < RTC_STAT_REGA)
1155392Sgblack@eecs.umich.edu        return clock_data[addr];
1165392Sgblack@eecs.umich.edu    else {
1175392Sgblack@eecs.umich.edu        switch (addr) {
1185392Sgblack@eecs.umich.edu          case RTC_STAT_REGA:
1195392Sgblack@eecs.umich.edu            // toggle UIP bit for linux
1205392Sgblack@eecs.umich.edu            stat_regA ^= RTCA_UIP;
1215392Sgblack@eecs.umich.edu            return stat_regA;
1225392Sgblack@eecs.umich.edu            break;
1235392Sgblack@eecs.umich.edu          case RTC_STAT_REGB:
1245392Sgblack@eecs.umich.edu            return stat_regB;
1255392Sgblack@eecs.umich.edu            break;
1265392Sgblack@eecs.umich.edu          case RTC_STAT_REGC:
1275392Sgblack@eecs.umich.edu          case RTC_STAT_REGD:
1285392Sgblack@eecs.umich.edu            return 0x00;
1295392Sgblack@eecs.umich.edu            break;
1305392Sgblack@eecs.umich.edu          default:
1315392Sgblack@eecs.umich.edu            panic("Shouldn't be here");
1325392Sgblack@eecs.umich.edu        }
1335392Sgblack@eecs.umich.edu    }
1345392Sgblack@eecs.umich.edu}
1355392Sgblack@eecs.umich.edu
1365392Sgblack@eecs.umich.eduvoid
1375392Sgblack@eecs.umich.eduMC146818::serialize(const string &base, ostream &os)
1385392Sgblack@eecs.umich.edu{
1395392Sgblack@eecs.umich.edu    arrayParamOut(os, base + ".clock_data", clock_data, sizeof(clock_data));
1405392Sgblack@eecs.umich.edu    paramOut(os, base + ".stat_regA", stat_regA);
1415392Sgblack@eecs.umich.edu    paramOut(os, base + ".stat_regB", stat_regB);
1425392Sgblack@eecs.umich.edu}
1435392Sgblack@eecs.umich.edu
1445392Sgblack@eecs.umich.eduvoid
1455392Sgblack@eecs.umich.eduMC146818::unserialize(const string &base, Checkpoint *cp,
1465392Sgblack@eecs.umich.edu                      const string &section)
1475392Sgblack@eecs.umich.edu{
1485392Sgblack@eecs.umich.edu    arrayParamIn(cp, section, base + ".clock_data", clock_data,
1495392Sgblack@eecs.umich.edu                 sizeof(clock_data));
1505392Sgblack@eecs.umich.edu    paramIn(cp, section, base + ".stat_regA", stat_regA);
1515392Sgblack@eecs.umich.edu    paramIn(cp, section, base + ".stat_regB", stat_regB);
1525392Sgblack@eecs.umich.edu
1535392Sgblack@eecs.umich.edu    // We're not unserializing the event here, but we need to
1545392Sgblack@eecs.umich.edu    // rescehedule the event since curTick was moved forward by the
1555392Sgblack@eecs.umich.edu    // checkpoint
1565392Sgblack@eecs.umich.edu    event.reschedule(curTick + event.interval);
1575392Sgblack@eecs.umich.edu}
1585392Sgblack@eecs.umich.edu
1595392Sgblack@eecs.umich.eduMC146818::RTCEvent::RTCEvent(MC146818 * _parent, Tick i)
1605392Sgblack@eecs.umich.edu    : Event(&mainEventQueue), parent(_parent), interval(i)
1615392Sgblack@eecs.umich.edu{
1625392Sgblack@eecs.umich.edu    DPRINTF(MC146818, "RTC Event Initilizing\n");
1635392Sgblack@eecs.umich.edu    schedule(curTick + interval);
1645392Sgblack@eecs.umich.edu}
1655392Sgblack@eecs.umich.edu
1665392Sgblack@eecs.umich.eduvoid
1675392Sgblack@eecs.umich.eduMC146818::RTCEvent::scheduleIntr()
1685392Sgblack@eecs.umich.edu{
1695392Sgblack@eecs.umich.edu  schedule(curTick + interval);
1705392Sgblack@eecs.umich.edu}
1715392Sgblack@eecs.umich.edu
1725392Sgblack@eecs.umich.eduvoid
1735392Sgblack@eecs.umich.eduMC146818::RTCEvent::process()
1745392Sgblack@eecs.umich.edu{
1755392Sgblack@eecs.umich.edu    DPRINTF(MC146818, "RTC Timer Interrupt\n");
1765392Sgblack@eecs.umich.edu    schedule(curTick + interval);
1775392Sgblack@eecs.umich.edu    parent->handleEvent();
1785392Sgblack@eecs.umich.edu}
1795392Sgblack@eecs.umich.edu
1805392Sgblack@eecs.umich.educonst char *
1815392Sgblack@eecs.umich.eduMC146818::RTCEvent::description() const
1825392Sgblack@eecs.umich.edu{
1835392Sgblack@eecs.umich.edu    return "RTC interrupt";
1845392Sgblack@eecs.umich.edu}
185