kmi.cc revision 13230
12068SN/A/*
22068SN/A * Copyright (c) 2010, 2017-2018 ARM Limited
32188SN/A * All rights reserved
42068SN/A *
52068SN/A * The license below extends only to copyright in the software and shall
62068SN/A * not be construed as granting a license to any other intellectual
72068SN/A * property including but not limited to intellectual property relating
82068SN/A * to a hardware implementation of the functionality of the software
92068SN/A * licensed hereunder.  You may use the software subject to the license
102068SN/A * terms below provided that you ensure that this notice is replicated
112068SN/A * unmodified and in its entirety in all distributions of the software,
122068SN/A * modified or unmodified, in source code or in binary form.
132068SN/A *
142068SN/A * Copyright (c) 2005 The Regents of The University of Michigan
152068SN/A * All rights reserved.
162068SN/A *
172068SN/A * Redistribution and use in source and binary forms, with or without
182068SN/A * modification, are permitted provided that the following conditions are
192068SN/A * met: redistributions of source code must retain the above copyright
202068SN/A * notice, this list of conditions and the following disclaimer;
212068SN/A * redistributions in binary form must reproduce the above copyright
222068SN/A * notice, this list of conditions and the following disclaimer in the
232068SN/A * documentation and/or other materials provided with the distribution;
242068SN/A * neither the name of the copyright holders nor the names of its
252068SN/A * contributors may be used to endorse or promote products derived from
262068SN/A * this software without specific prior written permission.
272068SN/A *
282665Ssaidi@eecs.umich.edu * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
292665Ssaidi@eecs.umich.edu * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
302068SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
312649Ssaidi@eecs.umich.edu * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
322649Ssaidi@eecs.umich.edu * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
332649Ssaidi@eecs.umich.edu * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
342649Ssaidi@eecs.umich.edu * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
352649Ssaidi@eecs.umich.edu * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
362068SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
372068SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
382068SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
392068SN/A *
402068SN/A * Authors: Ali Saidi
412068SN/A *          William Wang
422068SN/A */
432068SN/A
442075SN/A#include "dev/arm/kmi.hh"
452075SN/A
462075SN/A#include "base/trace.hh"
472075SN/A#include "base/vnc/vncinput.hh"
482075SN/A#include "debug/Pl050.hh"
492075SN/A#include "dev/arm/amba_device.hh"
502735Sktlim@umich.edu#include "dev/ps2/device.hh"
512069SN/A#include "mem/packet.hh"
522069SN/A#include "mem/packet_access.hh"
532075SN/A
542735Sktlim@umich.eduPl050::Pl050(const Pl050Params *p)
552068SN/A    : AmbaIntDevice(p, 0x1000), control(0), status(0x43), clkdiv(0),
562068SN/A      rawInterrupts(0),
572068SN/A      ps2(p->ps2)
582075SN/A{
592075SN/A    ps2->hostRegDataAvailable([this]() { this->updateRxInt(); });
602068SN/A}
612068SN/A
622075SN/ATick
632075SN/APl050::read(PacketPtr pkt)
642068SN/A{
652068SN/A    assert(pkt->getAddr() >= pioAddr && pkt->getAddr() < pioAddr + pioSize);
662068SN/A
672075SN/A    Addr daddr = pkt->getAddr() - pioAddr;
682075SN/A
692075SN/A    uint32_t data = 0;
702075SN/A
712075SN/A    switch (daddr) {
722075SN/A      case kmiCr:
732075SN/A        DPRINTF(Pl050, "Read Commmand: %#x\n", (uint32_t)control);
742735Sktlim@umich.edu        data = control;
752069SN/A        break;
762069SN/A
772075SN/A      case kmiStat:
782735Sktlim@umich.edu        status.rxfull = ps2->hostDataAvailable() ? 1 : 0;
792068SN/A        DPRINTF(Pl050, "Read Status: %#x\n", (uint32_t)status);
802068SN/A        data = status;
812068SN/A        break;
822075SN/A
832068SN/A      case kmiData:
842069SN/A        data = ps2->hostDataAvailable() ? ps2->hostRead() : 0;
852068SN/A        updateRxInt();
862068SN/A        DPRINTF(Pl050, "Read Data: %#x\n", (uint32_t)data);
874027Sstever@eecs.umich.edu        break;
884027Sstever@eecs.umich.edu
894027Sstever@eecs.umich.edu      case kmiClkDiv:
902336SN/A        data = clkdiv;
912075SN/A        break;
922068SN/A
932069SN/A      case kmiISR:
942068SN/A        data = getInterrupt();
952068SN/A        DPRINTF(Pl050, "Read Interrupts: %#x\n", getInterrupt());
962068SN/A        break;
972068SN/A
982068SN/A      default:
992068SN/A        if (readId(pkt, ambaId, pioAddr)) {
1002068SN/A            // Hack for variable size accesses
1012068SN/A            data = pkt->getLE<uint32_t>();
1024027Sstever@eecs.umich.edu            break;
1034027Sstever@eecs.umich.edu        }
1044027Sstever@eecs.umich.edu
1054027Sstever@eecs.umich.edu        warn("Tried to read PL050 at offset %#x that doesn't exist\n", daddr);
1064027Sstever@eecs.umich.edu        break;
1074027Sstever@eecs.umich.edu    }
1082336SN/A
1092068SN/A    pkt->setUintX(data, LittleEndianByteOrder);
1102068SN/A    pkt->makeAtomicResponse();
1112068SN/A    return pioDelay;
1122068SN/A}
1132068SN/A
1142068SN/ATick
1152068SN/APl050::write(PacketPtr pkt)
1162068SN/A{
1172068SN/A
1182068SN/A    assert(pkt->getAddr() >= pioAddr && pkt->getAddr() < pioAddr + pioSize);
1192068SN/A
1202068SN/A    Addr daddr = pkt->getAddr() - pioAddr;
1212147SN/A    const uint32_t data = pkt->getUintX(LittleEndianByteOrder);
1222068SN/A
1232068SN/A    panic_if(pkt->getSize() != 1,
1242068SN/A             "PL050: Unexpected write size "
1252068SN/A             "(offset: %#x, data: %#x, size: %u)\n",
1262068SN/A             daddr, data, pkt->getSize());
1272068SN/A
1282068SN/A    switch (daddr) {
1292068SN/A      case kmiCr:
1302068SN/A        DPRINTF(Pl050, "Write Commmand: %#x\n", data);
1312068SN/A        // Use the update interrupts helper to make sure any interrupt
1322068SN/A        // mask changes are handled correctly.
1332147SN/A        setControl((uint8_t)data);
1342068SN/A        break;
1352068SN/A
1362068SN/A      case kmiData:
1372068SN/A        DPRINTF(Pl050, "Write Data: %#x\n", data);
1382068SN/A        // Clear the TX interrupt before writing new data.
1392068SN/A        setTxInt(false);
1402068SN/A        ps2->hostWrite((uint8_t)data);
1412068SN/A        // Data is written in 0 time, so raise the TX interrupt again.
1422068SN/A        setTxInt(true);
1432068SN/A        break;
1442068SN/A
1452068SN/A      case kmiClkDiv:
1462068SN/A        clkdiv = (uint8_t)data;
1472147SN/A        break;
1482068SN/A
1492068SN/A      default:
1502068SN/A        warn("PL050: Unhandled write of %#x to offset %#x\n", data, daddr);
1512068SN/A        break;
1522068SN/A    }
1532068SN/A
1542068SN/A    pkt->makeAtomicResponse();
1552068SN/A    return pioDelay;
1562068SN/A}
1572068SN/A
1582068SN/Avoid
1592068SN/APl050::setTxInt(bool value)
1602068SN/A{
1612147SN/A    InterruptReg ints = rawInterrupts;
1622068SN/A
1632068SN/A    ints.tx = value ? 1 : 0;
1642068SN/A
1652068SN/A    setInterrupts(ints);
1662068SN/A}
1672068SN/A
1682068SN/Avoid
1692068SN/APl050::updateRxInt()
1702068SN/A{
1712068SN/A    InterruptReg ints = rawInterrupts;
1722068SN/A
1732068SN/A    ints.rx = ps2->hostDataAvailable() ? 1 : 0;
1742068SN/A
1752068SN/A    setInterrupts(ints);
1762068SN/A}
1772068SN/A
1782068SN/Avoid
1792068SN/APl050::updateIntCtrl(InterruptReg ints, ControlReg ctrl)
1802068SN/A{
1812068SN/A    const bool old_pending(getInterrupt());
1822068SN/A    control = ctrl;
1832068SN/A    rawInterrupts = ints;
1842068SN/A    const bool new_pending(getInterrupt());
1852068SN/A
1862068SN/A    if (!old_pending && new_pending) {
1872068SN/A        DPRINTF(Pl050, "Generate interrupt: rawInt=%#x ctrl=%#x int=%#x\n",
1882068SN/A                rawInterrupts, control, getInterrupt());
1892068SN/A        gic->sendInt(intNum);
1902068SN/A    } else if (old_pending && !new_pending) {
1912068SN/A        DPRINTF(Pl050, "Clear interrupt: rawInt=%#x ctrl=%#x int=%#x\n",
1922068SN/A                rawInterrupts, control, getInterrupt());
1932068SN/A        gic->clearInt(intNum);
1942068SN/A    }
1952068SN/A}
1962068SN/A
1972068SN/APl050::InterruptReg
1982068SN/APl050::getInterrupt() const
1992068SN/A{
2002068SN/A    InterruptReg tmp_interrupt(0);
2012068SN/A
2022068SN/A    tmp_interrupt.tx = rawInterrupts.tx & control.txint_enable;
2032068SN/A    tmp_interrupt.rx = rawInterrupts.rx & control.rxint_enable;
2042068SN/A
2052068SN/A    return tmp_interrupt;
2062068SN/A}
2072068SN/A
2082068SN/Avoid
2092068SN/APl050::serialize(CheckpointOut &cp) const
2102068SN/A{
2112068SN/A    paramOut(cp, "ctrlreg", control);
2122068SN/A    paramOut(cp, "stsreg", status);
2132068SN/A    SERIALIZE_SCALAR(clkdiv);
2142068SN/A    paramOut(cp, "raw_ints", rawInterrupts);
2152068SN/A}
2162068SN/A
2172068SN/Avoid
2182068SN/APl050::unserialize(CheckpointIn &cp)
2192068SN/A{
2202068SN/A    paramIn(cp, "ctrlreg", control);
2212068SN/A    paramIn(cp, "stsreg", status);
2222068SN/A    UNSERIALIZE_SCALAR(clkdiv);
2232068SN/A    paramIn(cp, "raw_ints", rawInterrupts);
2242068SN/A}
2252068SN/A
2262068SN/APl050 *
2272068SN/APl050Params::create()
2282068SN/A{
2292068SN/A    return new Pl050(this);
2302068SN/A}
2312068SN/A