pl011.cc revision 11793:ef606668d247
1/* 2 * Copyright (c) 2010, 2015 ARM Limited 3 * All rights reserved 4 * 5 * The license below extends only to copyright in the software and shall 6 * not be construed as granting a license to any other intellectual 7 * property including but not limited to intellectual property relating 8 * to a hardware implementation of the functionality of the software 9 * licensed hereunder. You may use the software subject to the license 10 * terms below provided that you ensure that this notice is replicated 11 * unmodified and in its entirety in all distributions of the software, 12 * modified or unmodified, in source code or in binary form. 13 * 14 * Copyright (c) 2005 The Regents of The University of Michigan 15 * All rights reserved. 16 * 17 * Redistribution and use in source and binary forms, with or without 18 * modification, are permitted provided that the following conditions are 19 * met: redistributions of source code must retain the above copyright 20 * notice, this list of conditions and the following disclaimer; 21 * redistributions in binary form must reproduce the above copyright 22 * notice, this list of conditions and the following disclaimer in the 23 * documentation and/or other materials provided with the distribution; 24 * neither the name of the copyright holders nor the names of its 25 * contributors may be used to endorse or promote products derived from 26 * this software without specific prior written permission. 27 * 28 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 29 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 30 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 31 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 32 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 33 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 34 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 35 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 36 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 37 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 38 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 39 * 40 * Authors: Ali Saidi 41 * Andreas Sandberg 42 */ 43 44#include "dev/arm/pl011.hh" 45 46#include "base/trace.hh" 47#include "debug/Checkpoint.hh" 48#include "debug/Uart.hh" 49#include "dev/arm/amba_device.hh" 50#include "dev/arm/base_gic.hh" 51#include "dev/terminal.hh" 52#include "mem/packet.hh" 53#include "mem/packet_access.hh" 54#include "params/Pl011.hh" 55#include "sim/sim_exit.hh" 56 57Pl011::Pl011(const Pl011Params *p) 58 : Uart(p, 0xfff), 59 intEvent(this), 60 control(0x300), fbrd(0), ibrd(0), lcrh(0), ifls(0x12), 61 imsc(0), rawInt(0), 62 gic(p->gic), endOnEOT(p->end_on_eot), intNum(p->int_num), 63 intDelay(p->int_delay) 64{ 65} 66 67Tick 68Pl011::read(PacketPtr pkt) 69{ 70 assert(pkt->getAddr() >= pioAddr && pkt->getAddr() < pioAddr + pioSize); 71 72 Addr daddr = pkt->getAddr() - pioAddr; 73 74 DPRINTF(Uart, " read register %#x size=%d\n", daddr, pkt->getSize()); 75 76 // use a temporary data since the uart registers are read/written with 77 // different size operations 78 // 79 uint32_t data = 0; 80 81 switch(daddr) { 82 case UART_DR: 83 data = 0; 84 if (term->dataAvailable()) { 85 data = term->in(); 86 // Since we don't simulate a FIFO for incoming data, we 87 // assume it's empty and clear RXINTR and RTINTR. 88 clearInterrupts(UART_RXINTR | UART_RTINTR); 89 if (term->dataAvailable()) { 90 DPRINTF(Uart, "Re-raising interrupt due to more data " 91 "after UART_DR read\n"); 92 dataAvailable(); 93 } 94 } 95 break; 96 case UART_FR: 97 data = 98 UART_FR_CTS | // Clear To Send 99 // Given we do not simulate a FIFO we are either empty or full. 100 (!term->dataAvailable() ? UART_FR_RXFE : UART_FR_RXFF) | 101 UART_FR_TXFE; // TX FIFO empty 102 103 DPRINTF(Uart, 104 "Reading FR register as %#x rawInt=0x%x " 105 "imsc=0x%x maskInt=0x%x\n", 106 data, rawInt, imsc, maskInt()); 107 break; 108 case UART_CR: 109 data = control; 110 break; 111 case UART_IBRD: 112 data = ibrd; 113 break; 114 case UART_FBRD: 115 data = fbrd; 116 break; 117 case UART_LCRH: 118 data = lcrh; 119 break; 120 case UART_IFLS: 121 data = ifls; 122 break; 123 case UART_IMSC: 124 data = imsc; 125 break; 126 case UART_RIS: 127 data = rawInt; 128 DPRINTF(Uart, "Reading Raw Int status as 0x%x\n", rawInt); 129 break; 130 case UART_MIS: 131 DPRINTF(Uart, "Reading Masked Int status as 0x%x\n", maskInt()); 132 data = maskInt(); 133 break; 134 default: 135 if (readId(pkt, AMBA_ID, pioAddr)) { 136 // Hack for variable size accesses 137 data = pkt->get<uint32_t>(); 138 break; 139 } 140 141 panic("Tried to read PL011 at offset %#x that doesn't exist\n", daddr); 142 break; 143 } 144 145 switch(pkt->getSize()) { 146 case 1: 147 pkt->set<uint8_t>(data); 148 break; 149 case 2: 150 pkt->set<uint16_t>(data); 151 break; 152 case 4: 153 pkt->set<uint32_t>(data); 154 break; 155 default: 156 panic("Uart read size too big?\n"); 157 break; 158 } 159 160 161 pkt->makeAtomicResponse(); 162 return pioDelay; 163} 164 165Tick 166Pl011::write(PacketPtr pkt) 167{ 168 169 assert(pkt->getAddr() >= pioAddr && pkt->getAddr() < pioAddr + pioSize); 170 171 Addr daddr = pkt->getAddr() - pioAddr; 172 173 DPRINTF(Uart, " write register %#x value %#x size=%d\n", daddr, 174 pkt->get<uint8_t>(), pkt->getSize()); 175 176 // use a temporary data since the uart registers are read/written with 177 // different size operations 178 // 179 uint32_t data = 0; 180 181 switch(pkt->getSize()) { 182 case 1: 183 data = pkt->get<uint8_t>(); 184 break; 185 case 2: 186 data = pkt->get<uint16_t>(); 187 break; 188 case 4: 189 data = pkt->get<uint32_t>(); 190 break; 191 default: 192 panic("Uart write size too big?\n"); 193 break; 194 } 195 196 197 switch (daddr) { 198 case UART_DR: 199 if ((data & 0xFF) == 0x04 && endOnEOT) 200 exitSimLoop("UART received EOT", 0); 201 202 term->out(data & 0xFF); 203 // We're supposed to clear TXINTR when this register is 204 // written to, however. since we're also infinitely fast, we 205 // need to immediately raise it again. 206 clearInterrupts(UART_TXINTR); 207 raiseInterrupts(UART_TXINTR); 208 break; 209 case UART_CR: 210 control = data; 211 break; 212 case UART_IBRD: 213 ibrd = data; 214 break; 215 case UART_FBRD: 216 fbrd = data; 217 break; 218 case UART_LCRH: 219 lcrh = data; 220 break; 221 case UART_IFLS: 222 ifls = data; 223 break; 224 case UART_IMSC: 225 DPRINTF(Uart, "Setting interrupt mask 0x%x\n", data); 226 setInterruptMask(data); 227 break; 228 229 case UART_ICR: 230 DPRINTF(Uart, "Clearing interrupts 0x%x\n", data); 231 clearInterrupts(data); 232 if (term->dataAvailable()) { 233 DPRINTF(Uart, "Re-raising interrupt due to more data after " 234 "UART_ICR write\n"); 235 dataAvailable(); 236 } 237 break; 238 default: 239 panic("Tried to write PL011 at offset %#x that doesn't exist\n", daddr); 240 break; 241 } 242 pkt->makeAtomicResponse(); 243 return pioDelay; 244} 245 246void 247Pl011::dataAvailable() 248{ 249 /*@todo ignore the fifo, just say we have data now 250 * We might want to fix this, or we might not care */ 251 DPRINTF(Uart, "Data available, scheduling interrupt\n"); 252 raiseInterrupts(UART_RXINTR | UART_RTINTR); 253} 254 255void 256Pl011::generateInterrupt() 257{ 258 DPRINTF(Uart, "Generate Interrupt: imsc=0x%x rawInt=0x%x maskInt=0x%x\n", 259 imsc, rawInt, maskInt()); 260 261 if (maskInt()) { 262 gic->sendInt(intNum); 263 DPRINTF(Uart, " -- Generated\n"); 264 } 265} 266 267void 268Pl011::setInterrupts(uint16_t ints, uint16_t mask) 269{ 270 const bool old_ints(!!maskInt()); 271 272 imsc = mask; 273 rawInt = ints; 274 275 if (!old_ints && maskInt()) { 276 if (!intEvent.scheduled()) 277 schedule(intEvent, curTick() + intDelay); 278 } else if (old_ints && !maskInt()) { 279 gic->clearInt(intNum); 280 } 281} 282 283 284 285void 286Pl011::serialize(CheckpointOut &cp) const 287{ 288 DPRINTF(Checkpoint, "Serializing Arm PL011\n"); 289 SERIALIZE_SCALAR(control); 290 SERIALIZE_SCALAR(fbrd); 291 SERIALIZE_SCALAR(ibrd); 292 SERIALIZE_SCALAR(lcrh); 293 SERIALIZE_SCALAR(ifls); 294 295 // Preserve backwards compatibility by giving these silly names. 296 paramOut(cp, "imsc_serial", imsc); 297 paramOut(cp, "rawInt_serial", rawInt); 298} 299 300void 301Pl011::unserialize(CheckpointIn &cp) 302{ 303 DPRINTF(Checkpoint, "Unserializing Arm PL011\n"); 304 305 UNSERIALIZE_SCALAR(control); 306 UNSERIALIZE_SCALAR(fbrd); 307 UNSERIALIZE_SCALAR(ibrd); 308 UNSERIALIZE_SCALAR(lcrh); 309 UNSERIALIZE_SCALAR(ifls); 310 311 // Preserve backwards compatibility by giving these silly names. 312 paramIn(cp, "imsc_serial", imsc); 313 paramIn(cp, "rawInt_serial", rawInt); 314} 315 316Pl011 * 317Pl011Params::create() 318{ 319 return new Pl011(this); 320} 321