hdlcd.cc revision 10839:10cac0f0f419
1/* 2 * Copyright (c) 2010-2013, 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 * Redistribution and use in source and binary forms, with or without 15 * modification, are permitted provided that the following conditions are 16 * met: redistributions of source code must retain the above copyright 17 * notice, this list of conditions and the following disclaimer; 18 * redistributions in binary form must reproduce the above copyright 19 * notice, this list of conditions and the following disclaimer in the 20 * documentation and/or other materials provided with the distribution; 21 * neither the name of the copyright holders nor the names of its 22 * contributors may be used to endorse or promote products derived from 23 * this software without specific prior written permission. 24 * 25 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 26 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 27 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 28 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 29 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 30 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 31 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 32 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 33 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 34 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 35 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 36 * 37 * Authors: Chris Emmons 38 */ 39 40#include "dev/arm/hdlcd.hh" 41 42#include "base/vnc/vncinput.hh" 43#include "base/output.hh" 44#include "base/trace.hh" 45#include "debug/HDLcd.hh" 46#include "debug/Uart.hh" 47#include "dev/arm/amba_device.hh" 48#include "dev/arm/base_gic.hh" 49#include "mem/packet.hh" 50#include "mem/packet_access.hh" 51#include "sim/system.hh" 52 53using std::vector; 54 55 56// initialize hdlcd registers 57HDLcd::HDLcd(const Params *p) 58 : AmbaDmaDevice(p), version(VERSION_RESETV), 59 int_rawstat(0), int_clear(0), int_mask(0), int_status(0), 60 fb_base(0), fb_line_length(0), fb_line_count(0), fb_line_pitch(0), 61 bus_options(BUS_OPTIONS_RESETV), 62 v_sync(0), v_back_porch(0), v_data(0), v_front_porch(0), 63 h_sync(0), h_back_porch(0), h_data(0), h_front_porch(0), 64 polarities(0), command(0), pixel_format(0), 65 red_select(0), green_select(0), blue_select(0), 66 pixelClock(p->pixel_clock), 67 fb(0, 0), vnc(p->vnc), bmp(&fb), pic(NULL), 68 frameReadStartTime(0), 69 dmaStartAddr(0), dmaCurAddr(0), dmaMaxAddr(0), dmaPendingNum(0), 70 frameUnderrun(false), pixelBufferSize(0), 71 pixelIndex(0), doUpdateParams(false), frameUnderway(false), 72 dmaBytesInFlight(0), 73 startFrameEvent(this), endFrameEvent(this), renderPixelEvent(this), 74 fillPixelBufferEvent(this), intEvent(this), 75 dmaDoneEventAll(MAX_OUTSTANDING_DMA_REQ_CAPACITY, this), 76 dmaDoneEventFree(MAX_OUTSTANDING_DMA_REQ_CAPACITY), 77 enableCapture(p->enable_capture) 78{ 79 pioSize = 0xFFFF; 80 81 for (int i = 0; i < MAX_OUTSTANDING_DMA_REQ_CAPACITY; ++i) 82 dmaDoneEventFree[i] = &dmaDoneEventAll[i]; 83 84 if (vnc) 85 vnc->setFrameBuffer(&fb); 86} 87 88HDLcd::~HDLcd() 89{ 90} 91 92// read registers and frame buffer 93Tick 94HDLcd::read(PacketPtr pkt) 95{ 96 uint32_t data = 0; 97 const Addr daddr = pkt->getAddr() - pioAddr; 98 99 DPRINTF(HDLcd, "read register BASE+0x%04x size=%d\n", daddr, 100 pkt->getSize()); 101 102 assert(pkt->getAddr() >= pioAddr && 103 pkt->getAddr() < pioAddr + pioSize && 104 pkt->getSize() == 4); 105 106 switch (daddr) { 107 case Version: 108 data = version; 109 break; 110 case Int_RawStat: 111 data = int_rawstat; 112 break; 113 case Int_Clear: 114 panic("HDLCD INT_CLEAR register is Write-Only\n"); 115 break; 116 case Int_Mask: 117 data = int_mask; 118 break; 119 case Int_Status: 120 data = int_status; 121 break; 122 case Fb_Base: 123 data = fb_base; 124 break; 125 case Fb_Line_Length: 126 data = fb_line_length; 127 break; 128 case Fb_Line_Count: 129 data = fb_line_count; 130 break; 131 case Fb_Line_Pitch: 132 data = fb_line_pitch; 133 break; 134 case Bus_Options: 135 data = bus_options; 136 break; 137 case V_Sync: 138 data = v_sync; 139 break; 140 case V_Back_Porch: 141 data = v_back_porch; 142 break; 143 case V_Data: 144 data = v_data; 145 break; 146 case V_Front_Porch: 147 data = v_front_porch; 148 break; 149 case H_Sync: 150 data = h_sync; 151 break; 152 case H_Back_Porch: 153 data = h_back_porch; 154 break; 155 case H_Data: 156 data = h_data; 157 break; 158 case H_Front_Porch: 159 data = h_front_porch; 160 break; 161 case Polarities: 162 data = polarities; 163 break; 164 case Command: 165 data = command; 166 break; 167 case Pixel_Format: 168 data = pixel_format; 169 break; 170 case Red_Select: 171 data = red_select; 172 break; 173 case Green_Select: 174 data = green_select; 175 break; 176 case Blue_Select: 177 data = blue_select; 178 break; 179 default: 180 panic("Tried to read HDLCD register that doesn't exist\n", daddr); 181 break; 182 } 183 184 pkt->set<uint32_t>(data); 185 pkt->makeAtomicResponse(); 186 return pioDelay; 187} 188 189// write registers and frame buffer 190Tick 191HDLcd::write(PacketPtr pkt) 192{ 193 assert(pkt->getAddr() >= pioAddr && 194 pkt->getAddr() < pioAddr + pioSize && 195 pkt->getSize() == 4); 196 197 const uint32_t data = pkt->get<uint32_t>(); 198 const Addr daddr = pkt->getAddr() - pioAddr; 199 200 DPRINTF(HDLcd, "write register BASE+%0x04x <= 0x%08x\n", daddr, 201 pkt->get<uint32_t>()); 202 203 switch (daddr) { 204 case Version: 205 panic("HDLCD VERSION register is read-Only\n"); 206 break; 207 case Int_RawStat: 208 int_rawstat = data; 209 break; 210 case Int_Clear: 211 int_clear = data; 212 break; 213 case Int_Mask: 214 int_mask = data; 215 break; 216 case Int_Status: 217 panic("HDLCD INT_STATUS register is read-Only\n"); 218 break; 219 case Fb_Base: 220 fb_base = data; 221 DPRINTF(HDLcd, "HDLCD Frame Buffer located at addr 0x%08x\n", fb_base); 222 break; 223 case Fb_Line_Length: 224 fb_line_length = data; 225 DPRINTF(HDLcd, "HDLCD res = %d x %d\n", width(), height()); 226 break; 227 case Fb_Line_Count: 228 fb_line_count = data; 229 DPRINTF(HDLcd, "HDLCD res = %d x %d\n", width(), height()); 230 break; 231 case Fb_Line_Pitch: 232 fb_line_pitch = data; 233 break; 234 case Bus_Options: { 235 BusOptsReg old_bus_options; 236 old_bus_options = bus_options; 237 bus_options = data; 238 if (bus_options.max_outstanding != old_bus_options.max_outstanding) 239 DPRINTF(HDLcd, 240 "Changing HDLcd outstanding dma transactions from %d to %d\n", 241 old_bus_options.max_outstanding, bus_options.max_outstanding); 242 if (bus_options.burst_len != old_bus_options.burst_len) 243 DPRINTF(HDLcd, 244 "Changing HDLcd dma burst length from %d bytes to %d bytes\n", 245 old_bus_options.burst_len, bus_options.burst_len); } 246 break; 247 case V_Sync: 248 v_sync = data; 249 break; 250 case V_Back_Porch: 251 v_back_porch = data; 252 break; 253 case V_Data: 254 v_data = data; 255 break; 256 case V_Front_Porch: 257 v_front_porch = data; 258 break; 259 case H_Sync: 260 h_sync = data; 261 break; 262 case H_Back_Porch: 263 h_back_porch = data; 264 break; 265 case H_Data: 266 h_data = data; 267 break; 268 case H_Front_Porch: 269 h_front_porch = data; 270 break; 271 case Polarities: 272 polarities = data; 273 break; 274 case Command: { 275 CommandReg new_command; 276 new_command = data; 277 if (new_command.enable != command.enable) { 278 DPRINTF(HDLcd, "HDLCD switched %s\n", 279 new_command.enable==0 ? "off" : "on"); 280 if (new_command.enable) { 281 doUpdateParams = true; 282 if (!frameUnderway) { 283 schedule(startFrameEvent, clockEdge()); 284 } 285 } 286 } 287 command = new_command; } 288 break; 289 case Pixel_Format: 290 pixel_format = data; 291 DPRINTF(HDLcd, "HDLCD res = %d x %d\n", width(), height()); 292 DPRINTF(HDLcd, "HDLCD bytes per pixel = %d\n", bytesPerPixel()); 293 DPRINTF(HDLcd, "HDLCD endianness = %s\n", 294 pixel_format.big_endian ? "big" : "little"); 295 break; 296 case Red_Select: 297 red_select = data; 298 break; 299 case Green_Select: 300 green_select = data; 301 break; 302 case Blue_Select: 303 blue_select = data; 304 break; 305 default: 306 panic("Tried to write HDLCD register that doesn't exist\n", daddr); 307 break; 308 } 309 310 pkt->makeAtomicResponse(); 311 return pioDelay; 312} 313 314void 315HDLcd::updateVideoParams(bool unserializing = false) 316{ 317 const uint16_t bpp M5_VAR_USED = bytesPerPixel() << 3; 318 319 // Workaround configuration bugs where multiple display 320 // controllers are attached to the same VNC server by reattaching 321 // enabled devices. This isn't ideal, but works as long as only 322 // one display controller is active at a time. 323 if (command.enable && vnc) 324 vnc->setFrameBuffer(&fb); 325 326 // updating these parameters while LCD is enabled is not supported 327 if (frameUnderway && !unserializing) 328 panic("Attempting to change some HDLCD parameters while the controller" 329 " is active is not allowed"); 330 331 // resize the virtualDisplayBuffer unless we are unserializing - it may 332 // have changed size 333 // there must be no outstanding DMA transactions for this to work 334 if (!unserializing) { 335 assert(dmaPendingNum == 0); 336 337 virtualDisplayBuffer.resize(bytesPerPixel() * area()); 338 fb.resize(width(), height()); 339 fb.clear(); 340 341 std::fill(virtualDisplayBuffer.begin(), virtualDisplayBuffer.end(), 342 0); 343 } 344 345 DPRINTF(HDLcd, "bpp = %d\n", bpp); 346 DPRINTF(HDLcd, "display size = %d x %d\n", width(), height()); 347#if TRACING_ON 348 const size_t totalLinesPerFrame = v_back_porch.val + 1 + 349 v_data.val + 1 + 350 v_front_porch.val + 1 + 351 v_sync.val + 1; 352 const double fps = (double)SimClock::Frequency / 353 (double)(PClksPerLine() * totalLinesPerFrame * pixelClock); 354#endif 355 DPRINTF(HDLcd, "simulated refresh rate ~ %.1ffps generating ~ %.1fMB/s " 356 "traffic ([%.1fMHz, T=%d sim clocks] pclk, %d bpp => %.1fMB/s peak requirement)\n", 357 fps, 358 fps * virtualDisplayBuffer.size() / 1024 / 1024, 359 (double)SimClock::Frequency / pixelClock / 1000000.0, 360 pixelClock, 361 bpp, 362 (double)(SimClock::Frequency / pixelClock * (bpp / 8)) / 1024 / 1024); 363} 364 365void 366HDLcd::startFrame() 367{ 368 // 0. Check that we are in the appropriate state 369 assert(!frameUnderway); 370 if (!command.enable) 371 return; 372 DPRINTF(HDLcd, "Frame read started\n"); 373 if (doUpdateParams) { 374 updateVideoParams(); 375 doUpdateParams = false; 376 } 377 frameUnderway = true; 378 assert(!virtualDisplayBuffer.empty()); 379 assert(pixelBufferSize == 0); 380 assert(dmaBytesInFlight == 0); 381 assert(dmaPendingNum == 0); 382 assert(dmaDoneEventFree.size() == dmaDoneEventAll.size()); 383 assert(!renderPixelEvent.scheduled()); 384 // currently only support positive line pitches equal to the line length 385 assert(width() * bytesPerPixel() == fb_line_pitch); 386 387 // 1. Start DMA'ing the frame; subsequent transactions created as we go 388 dmaCurAddr = dmaStartAddr = fb_base; 389 dmaMaxAddr = static_cast<Addr>(width() * height() * bytesPerPixel()) + 390 dmaCurAddr; 391 frameReadStartTime = curTick(); 392 pixelIndex = 0; 393 frameUnderrun = false; 394 fillPixelBuffer(); 395 396 // 2. Schedule first pixelclock read; subsequent reads generated as we go 397 Tick firstPixelReadTick = curTick() + pixelClock * ( 398 PClksPerLine() * (v_sync.val + 1 + 399 v_back_porch.val + 1) + 400 h_sync.val + 1 + 401 h_back_porch.val + 1); 402 schedule(renderPixelEvent, firstPixelReadTick); 403} 404 405void 406HDLcd::fillPixelBuffer() 407{ 408 // - am I under the LCD dma transaction total? 409 // - do I have more data to transfer? 410 // - have I not yet underrun for this frame? 411 // - is there room to put the data in the pixel buffer including any 412 // outstanding dma transfers in flight? 413 while ((dmaPendingNum < maxOutstandingDma()) && 414 (dmaMaxAddr > dmaCurAddr) && 415 !frameUnderrun && 416 bytesFreeInPixelBuffer() > dmaBurstLength() * AXI_PORT_WIDTH) { 417 // try largest transaction size allowed first but switch to smaller 418 // sizes for trailing bytes 419 size_t transaction_size = dmaBurstLength() * AXI_PORT_WIDTH; 420 while (transaction_size > (dmaMaxAddr - dmaCurAddr)) 421 transaction_size >>= 1; 422 assert(transaction_size > 0); 423 424 // concurrent dma reads need different dma done events 425 // due to assertion in scheduling state 426 ++dmaPendingNum; 427 428 assert(!dmaDoneEventFree.empty()); 429 DmaDoneEvent *event(dmaDoneEventFree.back()); 430 dmaDoneEventFree.pop_back(); 431 assert(event); 432 assert(!event->scheduled()); 433 434 // We use a uncachable request here because the requests from the CPU 435 // will be uncacheable as well. If we have uncacheable and cacheable 436 // requests in the memory system for the same address it won't be 437 // pleased 438 uint8_t *const dma_dst( 439 virtualDisplayBuffer.data() + dmaCurAddr - dmaStartAddr); 440 event->setTransactionSize(transaction_size); 441 dmaPort.dmaAction(MemCmd::ReadReq, dmaCurAddr, transaction_size, event, 442 dma_dst, 0, Request::UNCACHEABLE); 443 dmaCurAddr += transaction_size; 444 dmaBytesInFlight += transaction_size; 445 } 446} 447 448void 449HDLcd::renderPixel() 450{ 451 // try to handle multiple pixels at a time; doing so reduces the accuracy 452 // of the underrun detection but lowers simulation overhead 453 const size_t count = 32; 454 assert(width() % count == 0); // not set up to handle trailing pixels 455 456 // have we underrun on this frame anytime before? 457 if (frameUnderrun) { 458 // the LCD controller gives up on a frame if an underrun occurs and 459 // resumes regular operation on the next frame 460 pixelBufferSize = 0; 461 } else { 462 // did we underrun on this set of pixels? 463 if (pixelBufferSize < bytesPerPixel() * count) { 464 warn("HDLcd controller buffer underrun\n"); 465 frameUnderrun = true; 466 int_rawstat.underrun = 1; 467 if (!intEvent.scheduled()) 468 schedule(intEvent, clockEdge()); 469 } else { 470 // emulate the pixel read from the internal buffer 471 pixelBufferSize -= bytesPerPixel() * count; 472 } 473 } 474 475 // the DMA may have previously stalled due to the buffer being full; 476 // give it a kick; it knows not to fill if at end of frame, underrun, etc 477 if (!fillPixelBufferEvent.scheduled()) 478 schedule(fillPixelBufferEvent, clockEdge()); 479 480 // schedule the next pixel read according to where it is in the frame 481 pixelIndex += count; 482 assert(pixelIndex <= width() * height()); 483 size_t x = pixelIndex % width(); 484 Tick nextEventTick = curTick(); 485 if (x == 0) { 486 // start of new line 487 nextEventTick += pixelClock * ((h_front_porch.val + 1) + 488 (h_back_porch.val + 1) + 489 (h_sync.val + 1)); 490 if (pixelIndex == width() * height()) { 491 // end of frame 492 nextEventTick += PClksPerLine() * (v_front_porch.val + 1) * 493 pixelClock; 494 schedule(endFrameEvent, nextEventTick); 495 return; 496 } 497 } else { 498 nextEventTick += pixelClock * count; 499 } 500 501 schedule(renderPixelEvent, nextEventTick); 502} 503 504PixelConverter 505HDLcd::pixelConverter() const 506{ 507 return PixelConverter( 508 bytesPerPixel(), 509 red_select.offset, green_select.offset, blue_select.offset, 510 red_select.size, green_select.size, blue_select.size, 511 pixel_format.big_endian ? BigEndianByteOrder : LittleEndianByteOrder); 512} 513 514void 515HDLcd::endFrame() { 516 assert(pixelBufferSize == 0); 517 assert(dmaPendingNum == 0); 518 assert(dmaBytesInFlight == 0); 519 assert(dmaDoneEventFree.size() == dmaDoneEventAll.size()); 520 521 fb.copyIn(virtualDisplayBuffer, pixelConverter()); 522 523 if (vnc) 524 vnc->setDirty(); 525 526 if (enableCapture) { 527 if (!pic) 528 pic = simout.create(csprintf("%s.framebuffer.bmp", sys->name()), true); 529 530 assert(pic); 531 pic->seekp(0); 532 bmp.write(*pic); 533 } 534 535 // start the next frame 536 frameUnderway = false; 537 startFrame(); 538} 539 540void 541HDLcd::dmaDone(DmaDoneEvent *event) 542{ 543 const size_t transactionLength = event->getTransactionSize(); 544 assert(pixelBufferSize + transactionLength < PIXEL_BUFFER_CAPACITY); 545 assert(dmaCurAddr <= dmaMaxAddr); 546 547 dmaDoneEventFree.push_back(event); 548 --dmaPendingNum; 549 assert(MAX_OUTSTANDING_DMA_REQ_CAPACITY - dmaDoneEventFree.size() == 550 dmaPendingNum); 551 552 // add the data to the pixel buffer 553 dmaBytesInFlight -= transactionLength; 554 pixelBufferSize += transactionLength; 555 556 // schedule another dma transaction if: 557 // - we're not done reading the frame 558 // - there is sufficient room in the pixel buffer for another transaction 559 // - another fillPixelBufferEvent is not already scheduled 560 const size_t targetTransSize = dmaBurstLength() * AXI_PORT_WIDTH; 561 if ((dmaCurAddr < dmaMaxAddr) && 562 (bytesFreeInPixelBuffer() + targetTransSize < PIXEL_BUFFER_CAPACITY) && 563 !fillPixelBufferEvent.scheduled()) { 564 schedule(fillPixelBufferEvent, clockEdge()); 565 } 566} 567 568void 569HDLcd::serialize(std::ostream &os) 570{ 571 DPRINTF(HDLcd, "Serializing ARM HDLCD\n"); 572 573 const uint32_t version_serial = version; 574 SERIALIZE_SCALAR(version_serial); 575 const uint32_t int_rawstat_serial = int_rawstat; 576 SERIALIZE_SCALAR(int_rawstat_serial); 577 const uint32_t int_clear_serial = int_clear; 578 SERIALIZE_SCALAR(int_clear_serial); 579 const uint32_t int_mask_serial = int_mask; 580 SERIALIZE_SCALAR(int_mask_serial); 581 const uint32_t int_status_serial = int_status; 582 SERIALIZE_SCALAR(int_status_serial); 583 584 SERIALIZE_SCALAR(fb_base); 585 SERIALIZE_SCALAR(fb_line_length); 586 587 const uint32_t fb_line_count_serial = fb_line_count; 588 SERIALIZE_SCALAR(fb_line_count_serial); 589 590 SERIALIZE_SCALAR(fb_line_pitch); 591 592 const uint32_t bus_options_serial = bus_options; 593 SERIALIZE_SCALAR(bus_options_serial); 594 const uint32_t v_sync_serial = v_sync; 595 SERIALIZE_SCALAR(v_sync_serial); 596 const uint32_t v_back_porch_serial = v_back_porch; 597 SERIALIZE_SCALAR(v_back_porch_serial); 598 const uint32_t v_data_serial = v_data; 599 SERIALIZE_SCALAR(v_data_serial); 600 const uint32_t v_front_porch_serial = v_front_porch; 601 SERIALIZE_SCALAR(v_front_porch_serial); 602 const uint32_t h_sync_serial = h_sync; 603 SERIALIZE_SCALAR(h_sync_serial); 604 const uint32_t h_back_porch_serial = h_back_porch; 605 SERIALIZE_SCALAR(h_back_porch_serial); 606 const uint32_t h_data_serial = h_data; 607 SERIALIZE_SCALAR(h_data_serial); 608 const uint32_t h_front_porch_serial = h_front_porch; 609 SERIALIZE_SCALAR(h_front_porch_serial); 610 const uint32_t polarities_serial = polarities; 611 SERIALIZE_SCALAR(polarities_serial); 612 const uint32_t command_serial = command; 613 SERIALIZE_SCALAR(command_serial); 614 const uint32_t pixel_format_serial = pixel_format; 615 SERIALIZE_SCALAR(pixel_format_serial); 616 const uint32_t red_select_serial = red_select; 617 SERIALIZE_SCALAR(red_select_serial); 618 const uint32_t green_select_serial = green_select; 619 SERIALIZE_SCALAR(green_select_serial); 620 const uint32_t blue_select_serial = blue_select; 621 SERIALIZE_SCALAR(blue_select_serial); 622 623 SERIALIZE_SCALAR(frameReadStartTime); 624 SERIALIZE_SCALAR(dmaStartAddr); 625 SERIALIZE_SCALAR(dmaCurAddr); 626 SERIALIZE_SCALAR(dmaMaxAddr); 627 SERIALIZE_SCALAR(dmaPendingNum); 628 SERIALIZE_SCALAR(frameUnderrun); 629 630 arrayParamOut(os, "virtualDisplayBuffer", virtualDisplayBuffer); 631 632 SERIALIZE_SCALAR(pixelBufferSize); 633 SERIALIZE_SCALAR(pixelIndex); 634 SERIALIZE_SCALAR(doUpdateParams); 635 SERIALIZE_SCALAR(frameUnderway); 636 SERIALIZE_SCALAR(dmaBytesInFlight); 637 638 Tick start_event_time = 0; 639 Tick end_event_time = 0; 640 Tick render_pixel_event_time = 0; 641 Tick fill_pixel_buffer_event_time = 0; 642 Tick int_event_time = 0; 643 if (startFrameEvent.scheduled()) 644 start_event_time = startFrameEvent.when(); 645 if (endFrameEvent.scheduled()) 646 end_event_time = endFrameEvent.when(); 647 if (renderPixelEvent.scheduled()) 648 render_pixel_event_time = renderPixelEvent.when(); 649 if (fillPixelBufferEvent.scheduled()) 650 fill_pixel_buffer_event_time = fillPixelBufferEvent.when(); 651 if (intEvent.scheduled()) 652 int_event_time = intEvent.when(); 653 SERIALIZE_SCALAR(start_event_time); 654 SERIALIZE_SCALAR(end_event_time); 655 SERIALIZE_SCALAR(render_pixel_event_time); 656 SERIALIZE_SCALAR(fill_pixel_buffer_event_time); 657 SERIALIZE_SCALAR(int_event_time); 658 659 vector<Tick> dma_done_event_tick(MAX_OUTSTANDING_DMA_REQ_CAPACITY); 660 vector<size_t> dma_done_event_burst_len(MAX_OUTSTANDING_DMA_REQ_CAPACITY); 661 for (int x = 0; x < MAX_OUTSTANDING_DMA_REQ_CAPACITY; ++x) { 662 dma_done_event_tick[x] = dmaDoneEventAll[x].scheduled() ? 663 dmaDoneEventAll[x].when() : 0; 664 dma_done_event_burst_len[x] = dmaDoneEventAll[x].scheduled() ? 665 dmaDoneEventAll[x].getTransactionSize() : 0; 666 } 667 arrayParamOut(os, "dma_done_event_tick", dma_done_event_tick); 668 arrayParamOut(os, "dma_done_event_burst_length", dma_done_event_burst_len); 669} 670 671void 672HDLcd::unserialize(Checkpoint *cp, const std::string §ion) 673{ 674 uint32_t version_serial, int_rawstat_serial, int_clear_serial, 675 int_mask_serial, int_status_serial, fb_line_count_serial, 676 bus_options_serial, v_sync_serial, v_back_porch_serial, 677 v_data_serial, v_front_porch_serial, h_sync_serial, 678 h_back_porch_serial, h_data_serial, h_front_porch_serial, 679 polarities_serial, command_serial, pixel_format_serial, 680 red_select_serial, green_select_serial, blue_select_serial; 681 682 DPRINTF(HDLcd, "Unserializing ARM HDLCD\n"); 683 684 UNSERIALIZE_SCALAR(version_serial); 685 version = version_serial; 686 UNSERIALIZE_SCALAR(int_rawstat_serial); 687 int_rawstat = int_rawstat_serial; 688 UNSERIALIZE_SCALAR(int_clear_serial); 689 int_clear = int_clear_serial; 690 UNSERIALIZE_SCALAR(int_mask_serial); 691 int_mask = int_mask_serial; 692 UNSERIALIZE_SCALAR(int_status_serial); 693 int_status = int_status_serial; 694 695 UNSERIALIZE_SCALAR(fb_base); 696 UNSERIALIZE_SCALAR(fb_line_length); 697 698 UNSERIALIZE_SCALAR(fb_line_count_serial); 699 fb_line_count = fb_line_count_serial; 700 701 UNSERIALIZE_SCALAR(fb_line_pitch); 702 703 UNSERIALIZE_SCALAR(bus_options_serial); 704 bus_options = bus_options_serial; 705 UNSERIALIZE_SCALAR(v_sync_serial); 706 v_sync = v_sync_serial; 707 UNSERIALIZE_SCALAR(v_back_porch_serial); 708 v_back_porch = v_back_porch_serial; 709 UNSERIALIZE_SCALAR(v_data_serial); 710 v_data = v_data_serial; 711 UNSERIALIZE_SCALAR(v_front_porch_serial); 712 v_front_porch = v_front_porch_serial; 713 UNSERIALIZE_SCALAR(h_sync_serial); 714 h_sync = h_sync_serial; 715 UNSERIALIZE_SCALAR(h_back_porch_serial); 716 h_back_porch = h_back_porch_serial; 717 UNSERIALIZE_SCALAR(h_data_serial); 718 h_data = h_data_serial; 719 UNSERIALIZE_SCALAR(h_front_porch_serial); 720 h_front_porch = h_front_porch_serial; 721 UNSERIALIZE_SCALAR(polarities_serial); 722 polarities = polarities_serial; 723 UNSERIALIZE_SCALAR(command_serial); 724 command = command_serial; 725 UNSERIALIZE_SCALAR(pixel_format_serial); 726 pixel_format = pixel_format_serial; 727 UNSERIALIZE_SCALAR(red_select_serial); 728 red_select = red_select_serial; 729 UNSERIALIZE_SCALAR(green_select_serial); 730 green_select = green_select_serial; 731 UNSERIALIZE_SCALAR(blue_select_serial); 732 blue_select = blue_select_serial; 733 734 UNSERIALIZE_SCALAR(frameReadStartTime); 735 UNSERIALIZE_SCALAR(dmaStartAddr); 736 UNSERIALIZE_SCALAR(dmaCurAddr); 737 UNSERIALIZE_SCALAR(dmaMaxAddr); 738 UNSERIALIZE_SCALAR(dmaPendingNum); 739 UNSERIALIZE_SCALAR(frameUnderrun); 740 UNSERIALIZE_SCALAR(dmaBytesInFlight); 741 742 arrayParamIn(cp, section, "virtualDisplayBuffer", virtualDisplayBuffer); 743 744 UNSERIALIZE_SCALAR(pixelBufferSize); 745 UNSERIALIZE_SCALAR(pixelIndex); 746 UNSERIALIZE_SCALAR(doUpdateParams); 747 UNSERIALIZE_SCALAR(frameUnderway); 748 749 Tick start_event_time = 0; 750 Tick end_event_time = 0; 751 Tick render_pixel_event_time = 0; 752 Tick fill_pixel_buffer_event_time = 0; 753 Tick int_event_time = 0; 754 UNSERIALIZE_SCALAR(start_event_time); 755 UNSERIALIZE_SCALAR(end_event_time); 756 UNSERIALIZE_SCALAR(render_pixel_event_time); 757 UNSERIALIZE_SCALAR(fill_pixel_buffer_event_time); 758 UNSERIALIZE_SCALAR(int_event_time); 759 if (start_event_time) 760 schedule(startFrameEvent, start_event_time); 761 if (end_event_time) 762 schedule(endFrameEvent, end_event_time); 763 if (render_pixel_event_time) 764 schedule(renderPixelEvent, render_pixel_event_time); 765 if (fill_pixel_buffer_event_time) 766 schedule(fillPixelBufferEvent, fill_pixel_buffer_event_time); 767 if (int_event_time) 768 schedule(intEvent, int_event_time); 769 770 vector<Tick> dma_done_event_tick(MAX_OUTSTANDING_DMA_REQ_CAPACITY); 771 vector<Tick> dma_done_event_burst_len(MAX_OUTSTANDING_DMA_REQ_CAPACITY); 772 arrayParamIn(cp, section, "dma_done_event_tick", dma_done_event_tick); 773 arrayParamIn(cp, section, "dma_done_event_burst_length", dma_done_event_burst_len); 774 dmaDoneEventFree.clear(); 775 for (int x = 0; x < MAX_OUTSTANDING_DMA_REQ_CAPACITY; ++x) { 776 if (dma_done_event_tick[x]) { 777 dmaDoneEventAll[x].setTransactionSize(dma_done_event_burst_len[x]); 778 schedule(dmaDoneEventAll[x], dma_done_event_tick[x]); 779 } else 780 dmaDoneEventFree.push_back(&dmaDoneEventAll[x]); 781 } 782 assert(MAX_OUTSTANDING_DMA_REQ_CAPACITY - dmaDoneEventFree.size() == dmaPendingNum); 783 784 if (frameUnderway) { 785 updateVideoParams(true); 786 fb.resize(width(), height()); 787 fb.copyIn(virtualDisplayBuffer, pixelConverter()); 788 if (vnc) 789 vnc->setDirty(); 790 } 791} 792 793void 794HDLcd::generateInterrupt() 795{ 796 int_status = int_rawstat & int_mask; 797 DPRINTF(HDLcd, "Generate Interrupt: int_rawstat=0x%08x int_mask=0x%08x " 798 "int_status=0x%08x\n", 799 (uint32_t)int_rawstat, (uint32_t)int_mask, (uint32_t)int_status); 800 801 if (int_status != 0) { 802 gic->sendInt(intNum); 803 DPRINTF(HDLcd, " -- Generated\n"); 804 } 805} 806 807AddrRangeList 808HDLcd::getAddrRanges() const 809{ 810 AddrRangeList ranges; 811 ranges.push_back(RangeSize(pioAddr, pioSize)); 812 return ranges; 813} 814 815HDLcd * 816HDLcdParams::create() 817{ 818 return new HDLcd(this); 819} 820