hdlcd.cc revision 11898
12SN/A/* 21762SN/A * Copyright (c) 2010-2013, 2015, 2017 ARM Limited 37897Shestness@cs.utexas.edu * All rights reserved 42SN/A * 52SN/A * The license below extends only to copyright in the software and shall 62SN/A * not be construed as granting a license to any other intellectual 72SN/A * property including but not limited to intellectual property relating 82SN/A * to a hardware implementation of the functionality of the software 92SN/A * licensed hereunder. You may use the software subject to the license 102SN/A * terms below provided that you ensure that this notice is replicated 112SN/A * unmodified and in its entirety in all distributions of the software, 122SN/A * modified or unmodified, in source code or in binary form. 132SN/A * 142SN/A * Redistribution and use in source and binary forms, with or without 152SN/A * modification, are permitted provided that the following conditions are 162SN/A * met: redistributions of source code must retain the above copyright 172SN/A * notice, this list of conditions and the following disclaimer; 182SN/A * redistributions in binary form must reproduce the above copyright 192SN/A * notice, this list of conditions and the following disclaimer in the 202SN/A * documentation and/or other materials provided with the distribution; 212SN/A * neither the name of the copyright holders nor the names of its 222SN/A * contributors may be used to endorse or promote products derived from 232SN/A * this software without specific prior written permission. 242SN/A * 252SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 262SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 272SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 282665Ssaidi@eecs.umich.edu * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 292665Ssaidi@eecs.umich.edu * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 302665Ssaidi@eecs.umich.edu * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 312665Ssaidi@eecs.umich.edu * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 327897Shestness@cs.utexas.edu * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 332SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 342SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 352SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 362SN/A * 372SN/A * Authors: Chris Emmons 382SN/A * Andreas Sandberg 3975SN/A */ 402SN/A 412439SN/A#include "dev/arm/hdlcd.hh" 422439SN/A 43603SN/A#include "base/output.hh" 442986Sgblack@eecs.umich.edu#include "base/trace.hh" 45603SN/A#include "base/vnc/vncinput.hh" 464762Snate@binkert.org#include "debug/Checkpoint.hh" 472520SN/A#include "debug/HDLcd.hh" 484762Snate@binkert.org#include "dev/arm/amba_device.hh" 492378SN/A#include "dev/arm/base_gic.hh" 506658Snate@binkert.org#include "mem/packet.hh" 512378SN/A#include "mem/packet_access.hh" 52722SN/A#include "params/HDLcd.hh" 532378SN/A#include "sim/system.hh" 54312SN/A 551634SN/Ausing std::vector; 562680Sktlim@umich.edu 571634SN/A 582521SN/A// initialize hdlcd registers 592378SN/AHDLcd::HDLcd(const HDLcdParams *p) 602378SN/A : AmbaDmaDevice(p, 0xFFFF), 61803SN/A // Parameters 627723SAli.Saidi@ARM.com vnc(p->vnc), 637723SAli.Saidi@ARM.com workaroundSwapRB(p->workaround_swap_rb), 643960Sgblack@eecs.umich.edu workaroundDmaLineCount(p->workaround_dma_line_count), 652378SN/A addrRanges{RangeSize(pioAddr, pioSize)}, 666658Snate@binkert.org enableCapture(p->enable_capture), 672SN/A pixelBufferSize(p->pixel_buffer_size), 682SN/A virtRefreshRate(p->virt_refresh_rate), 692SN/A 70603SN/A // Registers 712901Ssaidi@eecs.umich.edu version(VERSION_RESETV), 722902Ssaidi@eecs.umich.edu int_rawstat(0), int_mask(0), 732902Ssaidi@eecs.umich.edu 744762Snate@binkert.org fb_base(0), fb_line_length(0), fb_line_count(0), fb_line_pitch(0), 754762Snate@binkert.org bus_options(BUS_OPTIONS_RESETV), 764762Snate@binkert.org 774762Snate@binkert.org v_sync(0), v_back_porch(0), v_data(0), v_front_porch(0), 784762Snate@binkert.org h_sync(0), h_back_porch(0), h_data(0), h_front_porch(0), 794762Snate@binkert.org polarities(0), 802901Ssaidi@eecs.umich.edu 812901Ssaidi@eecs.umich.edu command(0), 822901Ssaidi@eecs.umich.edu 832901Ssaidi@eecs.umich.edu pixel_format(0), 842901Ssaidi@eecs.umich.edu red_select(0), green_select(0), blue_select(0), 854762Snate@binkert.org 862901Ssaidi@eecs.umich.edu virtRefreshEvent(this), 872521SN/A // Other 882SN/A bmp(&pixelPump.fb), pic(NULL), conv(PixelConverter::rgba8888_le), 892SN/A pixelPump(*this, *p->pxl_clk, p->pixel_chunk) 902680Sktlim@umich.edu{ 915714Shsul@eecs.umich.edu if (vnc) 921806SN/A vnc->setFrameBuffer(&pixelPump.fb); 936221Snate@binkert.org} 945713Shsul@eecs.umich.edu 955713Shsul@eecs.umich.eduHDLcd::~HDLcd() 965713Shsul@eecs.umich.edu{ 975713Shsul@eecs.umich.edu} 985714Shsul@eecs.umich.edu 991806SN/Avoid 1006227Snate@binkert.orgHDLcd::regStats() 1015714Shsul@eecs.umich.edu{ 1021806SN/A AmbaDmaDevice::regStats(); 103180SN/A 1046029Ssteve.reinhardt@amd.com using namespace Stats; 1056029Ssteve.reinhardt@amd.com 1066029Ssteve.reinhardt@amd.com stats.underruns 1076029Ssteve.reinhardt@amd.com .name(name() + ".underruns") 1088460SAli.Saidi@ARM.com .desc("number of buffer underruns") 1098460SAli.Saidi@ARM.com .flags(nozero) 1108460SAli.Saidi@ARM.com ; 1118460SAli.Saidi@ARM.com} 1128460SAli.Saidi@ARM.com 1138460SAli.Saidi@ARM.comvoid 1148460SAli.Saidi@ARM.comHDLcd::serialize(CheckpointOut &cp) const 1158460SAli.Saidi@ARM.com{ 1162378SN/A DPRINTF(Checkpoint, "Serializing ARM HDLCD\n"); 1172378SN/A 1182378SN/A SERIALIZE_SCALAR(int_rawstat); 1192378SN/A SERIALIZE_SCALAR(int_mask); 1202520SN/A 1212520SN/A SERIALIZE_SCALAR(fb_base); 1227723SAli.Saidi@ARM.com SERIALIZE_SCALAR(fb_line_length); 1237723SAli.Saidi@ARM.com SERIALIZE_SCALAR(fb_line_count); 1242520SN/A SERIALIZE_SCALAR(fb_line_pitch); 1251885SN/A SERIALIZE_SCALAR(bus_options); 1261070SN/A 127954SN/A SERIALIZE_SCALAR(v_sync); 1281070SN/A SERIALIZE_SCALAR(v_back_porch); 1291070SN/A SERIALIZE_SCALAR(v_data); 1301070SN/A SERIALIZE_SCALAR(v_front_porch); 1311070SN/A 1321070SN/A SERIALIZE_SCALAR(h_sync); 1331070SN/A SERIALIZE_SCALAR(h_back_porch); 1341070SN/A SERIALIZE_SCALAR(h_data); 1351070SN/A SERIALIZE_SCALAR(h_front_porch); 1361070SN/A 1371070SN/A SERIALIZE_SCALAR(polarities); 1381070SN/A 1391070SN/A SERIALIZE_SCALAR(command); 1407580SAli.Saidi@arm.com SERIALIZE_SCALAR(pixel_format); 1417580SAli.Saidi@arm.com SERIALIZE_SCALAR(red_select); 1427580SAli.Saidi@arm.com SERIALIZE_SCALAR(green_select); 1437580SAli.Saidi@arm.com SERIALIZE_SCALAR(blue_select); 1447580SAli.Saidi@arm.com 1457580SAli.Saidi@arm.com SERIALIZE_OBJ(pixelPump); 1467580SAli.Saidi@arm.com if (enabled()) 1477580SAli.Saidi@arm.com dmaEngine->serializeSection(cp, "dmaEngine"); 1482378SN/A} 1492378SN/A 1507770SAli.Saidi@ARM.comvoid 1512378SN/AHDLcd::unserialize(CheckpointIn &cp) 1524997Sgblack@eecs.umich.edu{ 1537770SAli.Saidi@ARM.com DPRINTF(Checkpoint, "Unserializing ARM HDLCD\n"); 1544997Sgblack@eecs.umich.edu 1554997Sgblack@eecs.umich.edu UNSERIALIZE_SCALAR(int_rawstat); 1564997Sgblack@eecs.umich.edu UNSERIALIZE_SCALAR(int_mask); 1574997Sgblack@eecs.umich.edu 1587770SAli.Saidi@ARM.com UNSERIALIZE_SCALAR(fb_base); 1594997Sgblack@eecs.umich.edu UNSERIALIZE_SCALAR(fb_line_length); 1604997Sgblack@eecs.umich.edu UNSERIALIZE_SCALAR(fb_line_count); 1615795Ssaidi@eecs.umich.edu UNSERIALIZE_SCALAR(fb_line_pitch); 1625795Ssaidi@eecs.umich.edu UNSERIALIZE_SCALAR(bus_options); 1635795Ssaidi@eecs.umich.edu 1645795Ssaidi@eecs.umich.edu UNSERIALIZE_SCALAR(v_sync); 1655795Ssaidi@eecs.umich.edu UNSERIALIZE_SCALAR(v_back_porch); 1665795Ssaidi@eecs.umich.edu UNSERIALIZE_SCALAR(v_data); 1672378SN/A UNSERIALIZE_SCALAR(v_front_porch); 1682378SN/A 1692378SN/A UNSERIALIZE_SCALAR(h_sync); 1701885SN/A UNSERIALIZE_SCALAR(h_back_porch); 1714762Snate@binkert.org UNSERIALIZE_SCALAR(h_data); 1727914SBrad.Beckmann@amd.com UNSERIALIZE_SCALAR(h_front_porch); 1737914SBrad.Beckmann@amd.com 1747914SBrad.Beckmann@amd.com UNSERIALIZE_SCALAR(polarities); 1757914SBrad.Beckmann@amd.com 1767914SBrad.Beckmann@amd.com UNSERIALIZE_SCALAR(command); 1777914SBrad.Beckmann@amd.com UNSERIALIZE_SCALAR(pixel_format); 1787914SBrad.Beckmann@amd.com UNSERIALIZE_SCALAR(red_select); 1797914SBrad.Beckmann@amd.com UNSERIALIZE_SCALAR(green_select); 1807914SBrad.Beckmann@amd.com UNSERIALIZE_SCALAR(blue_select); 1817914SBrad.Beckmann@amd.com 1827914SBrad.Beckmann@amd.com { 1837914SBrad.Beckmann@amd.com // Try to unserialize the pixel pump. It might not exist if 1847914SBrad.Beckmann@amd.com // we're unserializing an old checkpoint. 1857914SBrad.Beckmann@amd.com ScopedCheckpointSection sec(cp, "pixelPump"); 1867914SBrad.Beckmann@amd.com if (cp.sectionExists(Serializable::currentSection())) 1877914SBrad.Beckmann@amd.com pixelPump.unserialize(cp); 1887914SBrad.Beckmann@amd.com } 1897914SBrad.Beckmann@amd.com 1907914SBrad.Beckmann@amd.com if (enabled()) { 1917914SBrad.Beckmann@amd.com // Create the DMA engine and read its state from the 1927914SBrad.Beckmann@amd.com // checkpoint. We don't need to worry about the pixel pump as 1937914SBrad.Beckmann@amd.com // it is a proper SimObject. 1947914SBrad.Beckmann@amd.com createDmaEngine(); 1957914SBrad.Beckmann@amd.com dmaEngine->unserializeSection(cp, "dmaEngine"); 1967914SBrad.Beckmann@amd.com 1977914SBrad.Beckmann@amd.com conv = pixelConverter(); 1987914SBrad.Beckmann@amd.com } 1997914SBrad.Beckmann@amd.com} 2007914SBrad.Beckmann@amd.com 2017914SBrad.Beckmann@amd.comvoid 2027914SBrad.Beckmann@amd.comHDLcd::drainResume() 2037914SBrad.Beckmann@amd.com{ 2047914SBrad.Beckmann@amd.com AmbaDmaDevice::drainResume(); 2057914SBrad.Beckmann@amd.com 2067914SBrad.Beckmann@amd.com if (enabled()) { 2077914SBrad.Beckmann@amd.com if (sys->bypassCaches()) { 2087914SBrad.Beckmann@amd.com // We restart the HDLCD if we are in KVM mode. This 2097914SBrad.Beckmann@amd.com // ensures that we always use the fast refresh logic if we 2107914SBrad.Beckmann@amd.com // resume in KVM mode. 2117914SBrad.Beckmann@amd.com cmdDisable(); 2127914SBrad.Beckmann@amd.com cmdEnable(); 2137914SBrad.Beckmann@amd.com } else if (!pixelPump.active()) { 2142901Ssaidi@eecs.umich.edu // We restored from an old checkpoint without a pixel 2152424SN/A // pump, start an new refresh. This typically happens when 2161885SN/A // restoring from old checkpoints. 2171885SN/A cmdEnable(); 2181885SN/A } 2191885SN/A } 2201885SN/A 2212158SN/A // We restored from a checkpoint and need to update the VNC server 2221885SN/A if (pixelPump.active() && vnc) 2231885SN/A vnc->setDirty(); 2241885SN/A} 2251885SN/A 2261885SN/Avoid 2271885SN/AHDLcd::virtRefresh() 2282989Ssaidi@eecs.umich.edu{ 2291885SN/A pixelPump.renderFrame(); 2301913SN/A schedule(virtRefreshEvent, (curTick() + virtRefreshRate)); 2311885SN/A} 2321885SN/A 2331885SN/A// read registers and frame buffer 2341885SN/ATick 2351885SN/AHDLcd::read(PacketPtr pkt) 2361885SN/A{ 2371885SN/A assert(pkt->getAddr() >= pioAddr && 2381885SN/A pkt->getAddr() < pioAddr + pioSize); 2391885SN/A 2401885SN/A const Addr daddr(pkt->getAddr() - pioAddr); 2411885SN/A panic_if(pkt->getSize() != 4, 2422989Ssaidi@eecs.umich.edu "Unhandled read size (address: 0x.4x, size: %u)", 2431885SN/A daddr, pkt->getSize()); 2441885SN/A 2451885SN/A const uint32_t data(readReg(daddr)); 2461885SN/A DPRINTF(HDLcd, "read register 0x%04x: 0x%x\n", daddr, data); 2472378SN/A 24877SN/A pkt->set<uint32_t>(data); 2496658Snate@binkert.org pkt->makeAtomicResponse(); 2501070SN/A return pioDelay; 2513960Sgblack@eecs.umich.edu} 2521070SN/A 2531070SN/A// write registers and frame buffer 2544762Snate@binkert.orgTick 2551070SN/AHDLcd::write(PacketPtr pkt) 2562158SN/A{ 2572158SN/A assert(pkt->getAddr() >= pioAddr && 2581070SN/A pkt->getAddr() < pioAddr + pioSize); 2592158SN/A 2601070SN/A const Addr daddr(pkt->getAddr() - pioAddr); 2612SN/A panic_if(pkt->getSize() != 4, 2622SN/A "Unhandled read size (address: 0x.4x, size: %u)", 2637733SAli.Saidi@ARM.com daddr, pkt->getSize()); 2641129SN/A const uint32_t data(pkt->get<uint32_t>()); 2652158SN/A DPRINTF(HDLcd, "write register 0x%04x: 0x%x\n", daddr, data); 2662158SN/A 2671070SN/A writeReg(daddr, data); 2682378SN/A 2692378SN/A pkt->makeAtomicResponse(); 2701070SN/A return pioDelay; 2711070SN/A} 2721070SN/A 2731070SN/Auint32_t 2741070SN/AHDLcd::readReg(Addr offset) 2751070SN/A{ 2761070SN/A switch (offset) { 2771070SN/A case Version: return version; 2781070SN/A 2791070SN/A case Int_RawStat: return int_rawstat; 2801070SN/A case Int_Clear: 2811070SN/A panic("HDLCD INT_CLEAR register is Write-Only\n"); 2821070SN/A case Int_Mask: return int_mask; 2831070SN/A case Int_Status: return intStatus(); 2841070SN/A 2851070SN/A case Fb_Base: return fb_base; 2861070SN/A case Fb_Line_Length: return fb_line_length; 2871070SN/A case Fb_Line_Count: return fb_line_count; 2882378SN/A case Fb_Line_Pitch: return fb_line_pitch; 2892378SN/A case Bus_Options: return bus_options; 2902378SN/A 2912378SN/A case V_Sync: return v_sync; 2922378SN/A case V_Back_Porch: return v_back_porch; 2932378SN/A case V_Data: return v_data; 2945718Shsul@eecs.umich.edu case V_Front_Porch: return v_front_porch; 2955713Shsul@eecs.umich.edu case H_Sync: return h_sync; 2961070SN/A case H_Back_Porch: return h_back_porch; 2971070SN/A case H_Data: return h_data; 2981070SN/A case H_Front_Porch: return h_front_porch; 2997897Shestness@cs.utexas.edu case Polarities: return polarities; 3002SN/A 30177SN/A case Command: return command; 3027897Shestness@cs.utexas.edu case Pixel_Format: return pixel_format; 3037897Shestness@cs.utexas.edu case Red_Select: return red_select; 3047897Shestness@cs.utexas.edu case Green_Select: return green_select; 3052SN/A case Blue_Select: return blue_select; 3062SN/A 3072SN/A default: 3082SN/A panic("Tried to read HDLCD register that doesn't exist\n", offset); 3092SN/A } 3102SN/A} 3112SN/A 3122SN/Avoid 3132SN/AHDLcd::writeReg(Addr offset, uint32_t value) 3142SN/A{ 3152158SN/A switch (offset) { 3162158SN/A case Version: 3172SN/A panic("HDLCD VERSION register is read-Only\n"); 3182SN/A 3192SN/A case Int_RawStat: 320 intRaise(value); 321 return; 322 case Int_Clear: 323 intClear(value); 324 return; 325 case Int_Mask: 326 intMask(value); 327 return; 328 case Int_Status: 329 panic("HDLCD INT_STATUS register is read-Only\n"); 330 break; 331 332 case Fb_Base: 333 fb_base = value; 334 return; 335 336 case Fb_Line_Length: 337 fb_line_length = value; 338 return; 339 340 case Fb_Line_Count: 341 fb_line_count = value; 342 return; 343 344 case Fb_Line_Pitch: 345 fb_line_pitch = value; 346 return; 347 348 case Bus_Options: { 349 const BusOptsReg old_bus_options(bus_options); 350 bus_options = value; 351 352 if (bus_options.max_outstanding != old_bus_options.max_outstanding) { 353 DPRINTF(HDLcd, 354 "Changing HDLcd outstanding DMA transactions: %d -> %d\n", 355 old_bus_options.max_outstanding, 356 bus_options.max_outstanding); 357 358 } 359 360 if (bus_options.burst_len != old_bus_options.burst_len) { 361 DPRINTF(HDLcd, 362 "Changing HDLcd DMA burst flags: 0x%x -> 0x%x\n", 363 old_bus_options.burst_len, bus_options.burst_len); 364 } 365 } return; 366 367 case V_Sync: 368 v_sync = value; 369 return; 370 case V_Back_Porch: 371 v_back_porch = value; 372 return; 373 case V_Data: 374 v_data = value; 375 return; 376 case V_Front_Porch: 377 v_front_porch = value; 378 return; 379 380 case H_Sync: 381 h_sync = value; 382 return; 383 case H_Back_Porch: 384 h_back_porch = value; 385 return; 386 case H_Data: 387 h_data = value; 388 return; 389 case H_Front_Porch: 390 h_front_porch = value; 391 return; 392 393 case Polarities: 394 polarities = value; 395 return; 396 397 case Command: { 398 const CommandReg new_command(value); 399 400 if (new_command.enable != command.enable) { 401 DPRINTF(HDLcd, "HDLCD switched %s\n", 402 new_command.enable ? "on" : "off"); 403 404 if (new_command.enable) { 405 cmdEnable(); 406 } else { 407 cmdDisable(); 408 } 409 } 410 command = new_command; 411 } return; 412 413 case Pixel_Format: 414 pixel_format = value; 415 return; 416 417 case Red_Select: 418 red_select = value; 419 return; 420 case Green_Select: 421 green_select = value; 422 return; 423 case Blue_Select: 424 blue_select = value; 425 return; 426 427 default: 428 panic("Tried to write HDLCD register that doesn't exist\n", offset); 429 return; 430 } 431} 432 433PixelConverter 434HDLcd::pixelConverter() const 435{ 436 ByteOrder byte_order( 437 pixel_format.big_endian ? BigEndianByteOrder : LittleEndianByteOrder); 438 439 /* Some Linux kernels have a broken driver that swaps the red and 440 * blue color select registers. */ 441 if (!workaroundSwapRB) { 442 return PixelConverter( 443 pixel_format.bytes_per_pixel + 1, 444 red_select.offset, green_select.offset, blue_select.offset, 445 red_select.size, green_select.size, blue_select.size, 446 byte_order); 447 } else { 448 return PixelConverter( 449 pixel_format.bytes_per_pixel + 1, 450 blue_select.offset, green_select.offset, red_select.offset, 451 blue_select.size, green_select.size, red_select.size, 452 byte_order); 453 } 454} 455 456DisplayTimings 457HDLcd::displayTimings() const 458{ 459 return DisplayTimings( 460 h_data.val + 1, v_data.val + 1, 461 h_back_porch.val + 1, h_sync.val + 1, h_front_porch.val + 1, 462 v_back_porch.val + 1, v_sync.val + 1, v_front_porch.val + 1); 463} 464 465void 466HDLcd::createDmaEngine() 467{ 468 if (bus_options.max_outstanding == 0) { 469 warn("Maximum number of outstanding DMA transfers set to 0."); 470 return; 471 } 472 473 const uint32_t dma_burst_flags(bus_options.burst_len); 474 const uint32_t dma_burst_len( 475 dma_burst_flags ? 476 (1UL << (findMsbSet(dma_burst_flags) - 1)) : 477 MAX_BURST_LEN); 478 // Some drivers seem to set the DMA line count incorrectly. This 479 // could either be a driver bug or a specification bug. Unlike for 480 // timings, the specification does not require 1 to be added to 481 // the DMA engine's line count. 482 const uint32_t dma_lines( 483 fb_line_count + (workaroundDmaLineCount ? 1 : 0)); 484 485 dmaEngine.reset(new DmaEngine( 486 *this, pixelBufferSize, 487 AXI_PORT_WIDTH * dma_burst_len, 488 bus_options.max_outstanding, 489 fb_line_length, fb_line_pitch, dma_lines)); 490} 491 492void 493HDLcd::cmdEnable() 494{ 495 createDmaEngine(); 496 conv = pixelConverter(); 497 498 // Update timing parameter before rendering frames 499 pixelPump.updateTimings(displayTimings()); 500 501 if (sys->bypassCaches()) { 502 schedule(virtRefreshEvent, clockEdge()); 503 } else { 504 pixelPump.start(); 505 } 506} 507 508void 509HDLcd::cmdDisable() 510{ 511 pixelPump.stop(); 512 // Disable the virtual refresh event 513 if (virtRefreshEvent.scheduled()) { 514 assert(sys->bypassCaches()); 515 deschedule(virtRefreshEvent); 516 } 517 dmaEngine->abortFrame(); 518} 519 520bool 521HDLcd::pxlNext(Pixel &p) 522{ 523 uint8_t pixel_data[MAX_PIXEL_SIZE]; 524 assert(conv.length <= sizeof(pixel_data)); 525 if (dmaEngine->tryGet(pixel_data, conv.length)) { 526 p = conv.toPixel(pixel_data); 527 return true; 528 } else { 529 return false; 530 } 531} 532 533void 534HDLcd::pxlVSyncBegin() 535{ 536 DPRINTF(HDLcd, "Raising VSYNC interrupt.\n"); 537 intRaise(INT_VSYNC); 538} 539 540void 541HDLcd::pxlVSyncEnd() 542{ 543 DPRINTF(HDLcd, "End of VSYNC, starting DMA engine\n"); 544 dmaEngine->startFrame(fb_base); 545} 546 547void 548HDLcd::pxlUnderrun() 549{ 550 DPRINTF(HDLcd, "Buffer underrun, stopping DMA fill.\n"); 551 ++stats.underruns; 552 intRaise(INT_UNDERRUN); 553 dmaEngine->abortFrame(); 554} 555 556void 557HDLcd::pxlFrameDone() 558{ 559 DPRINTF(HDLcd, "Reached end of last visible line.\n"); 560 561 if (dmaEngine->size()) { 562 warn("HDLCD %u bytes still in FIFO after frame: Ensure that DMA " 563 "and PixelPump configuration is consistent\n", 564 dmaEngine->size()); 565 dmaEngine->dumpSettings(); 566 pixelPump.dumpSettings(); 567 } 568 569 if (vnc) 570 vnc->setDirty(); 571 572 if (enableCapture) { 573 if (!pic) { 574 pic = simout.create( 575 csprintf("%s.framebuffer.bmp", sys->name()), 576 true); 577 } 578 579 assert(pic); 580 pic->stream()->seekp(0); 581 bmp.write(*pic->stream()); 582 } 583} 584 585void 586HDLcd::setInterrupts(uint32_t ints, uint32_t mask) 587{ 588 const bool old_ints(intStatus()); 589 590 int_mask = mask; 591 int_rawstat = ints; 592 593 if (!old_ints && intStatus()) { 594 gic->sendInt(intNum); 595 } else if (old_ints && !intStatus()) { 596 gic->clearInt(intNum); 597 } 598} 599 600HDLcd::DmaEngine::DmaEngine(HDLcd &_parent, size_t size, 601 unsigned request_size, unsigned max_pending, 602 size_t line_size, ssize_t line_pitch, unsigned num_lines) 603 : DmaReadFifo( 604 _parent.dmaPort, size, request_size, max_pending, 605 Request::UNCACHEABLE), 606 parent(_parent), 607 lineSize(line_size), linePitch(line_pitch), numLines(num_lines), 608 nextLineAddr(0) 609{ 610} 611 612void 613HDLcd::DmaEngine::serialize(CheckpointOut &cp) const 614{ 615 DmaReadFifo::serialize(cp); 616 617 SERIALIZE_SCALAR(nextLineAddr); 618 SERIALIZE_SCALAR(frameEnd); 619} 620 621void 622HDLcd::DmaEngine::unserialize(CheckpointIn &cp) 623{ 624 DmaReadFifo::unserialize(cp); 625 626 UNSERIALIZE_SCALAR(nextLineAddr); 627 UNSERIALIZE_SCALAR(frameEnd); 628} 629 630void 631HDLcd::DmaEngine::startFrame(Addr fb_base) 632{ 633 nextLineAddr = fb_base; 634 frameEnd = fb_base + numLines * linePitch; 635 636 startFill(nextLineAddr, lineSize); 637} 638 639void 640HDLcd::DmaEngine::abortFrame() 641{ 642 nextLineAddr = frameEnd; 643 stopFill(); 644 flush(); 645} 646 647 648void 649HDLcd::DmaEngine::dumpSettings() 650{ 651 inform("DMA line size: %u bytes", lineSize); 652 inform("DMA line pitch: %i bytes", linePitch); 653 inform("DMA num lines: %u", numLines); 654} 655 656void 657HDLcd::DmaEngine::onEndOfBlock() 658{ 659 if (nextLineAddr == frameEnd) 660 // We're done with this frame. Ignore calls to this method 661 // until the next frame has been started. 662 return; 663 664 nextLineAddr += linePitch; 665 if (nextLineAddr != frameEnd) 666 startFill(nextLineAddr, lineSize); 667} 668 669void 670HDLcd::DmaEngine::onIdle() 671{ 672 parent.intRaise(INT_DMA_END); 673} 674 675void 676HDLcd::PixelPump::dumpSettings() 677{ 678 const DisplayTimings &t(timings()); 679 680 inform("PixelPump width: %u", t.width); 681 inform("PixelPump height: %u", t.height); 682 683 inform("PixelPump horizontal back porch: %u", t.hBackPorch); 684 inform("PixelPump horizontal fron porch: %u", t.hFrontPorch); 685 inform("PixelPump horizontal fron porch: %u", t.hSync); 686 687 inform("PixelPump vertical back porch: %u", t.vBackPorch); 688 inform("PixelPump vertical fron porch: %u", t.vFrontPorch); 689 inform("PixelPump vertical fron porch: %u", t.vSync); 690} 691 692 693HDLcd * 694HDLcdParams::create() 695{ 696 return new HDLcd(this); 697} 698