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