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