hdlcd.cc revision 9646
19646SChris.Emmons@arm.com/* 29646SChris.Emmons@arm.com * Copyright (c) 2010-2013 ARM Limited 39646SChris.Emmons@arm.com * All rights reserved 49646SChris.Emmons@arm.com * 59646SChris.Emmons@arm.com * The license below extends only to copyright in the software and shall 69646SChris.Emmons@arm.com * not be construed as granting a license to any other intellectual 79646SChris.Emmons@arm.com * property including but not limited to intellectual property relating 89646SChris.Emmons@arm.com * to a hardware implementation of the functionality of the software 99646SChris.Emmons@arm.com * licensed hereunder. You may use the software subject to the license 109646SChris.Emmons@arm.com * terms below provided that you ensure that this notice is replicated 119646SChris.Emmons@arm.com * unmodified and in its entirety in all distributions of the software, 129646SChris.Emmons@arm.com * modified or unmodified, in source code or in binary form. 139646SChris.Emmons@arm.com * 149646SChris.Emmons@arm.com * Redistribution and use in source and binary forms, with or without 159646SChris.Emmons@arm.com * modification, are permitted provided that the following conditions are 169646SChris.Emmons@arm.com * met: redistributions of source code must retain the above copyright 179646SChris.Emmons@arm.com * notice, this list of conditions and the following disclaimer; 189646SChris.Emmons@arm.com * redistributions in binary form must reproduce the above copyright 199646SChris.Emmons@arm.com * notice, this list of conditions and the following disclaimer in the 209646SChris.Emmons@arm.com * documentation and/or other materials provided with the distribution; 219646SChris.Emmons@arm.com * neither the name of the copyright holders nor the names of its 229646SChris.Emmons@arm.com * contributors may be used to endorse or promote products derived from 239646SChris.Emmons@arm.com * this software without specific prior written permission. 249646SChris.Emmons@arm.com * 259646SChris.Emmons@arm.com * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 269646SChris.Emmons@arm.com * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 279646SChris.Emmons@arm.com * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 289646SChris.Emmons@arm.com * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 299646SChris.Emmons@arm.com * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 309646SChris.Emmons@arm.com * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 319646SChris.Emmons@arm.com * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 329646SChris.Emmons@arm.com * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 339646SChris.Emmons@arm.com * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 349646SChris.Emmons@arm.com * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 359646SChris.Emmons@arm.com * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 369646SChris.Emmons@arm.com * 379646SChris.Emmons@arm.com * Authors: Chris Emmons 389646SChris.Emmons@arm.com */ 399646SChris.Emmons@arm.com 409646SChris.Emmons@arm.com#include "base/vnc/vncinput.hh" 419646SChris.Emmons@arm.com#include "base/bitmap.hh" 429646SChris.Emmons@arm.com#include "base/output.hh" 439646SChris.Emmons@arm.com#include "base/trace.hh" 449646SChris.Emmons@arm.com#include "debug/HDLcd.hh" 459646SChris.Emmons@arm.com#include "debug/Uart.hh" 469646SChris.Emmons@arm.com#include "dev/arm/amba_device.hh" 479646SChris.Emmons@arm.com#include "dev/arm/base_gic.hh" 489646SChris.Emmons@arm.com#include "dev/arm/hdlcd.hh" 499646SChris.Emmons@arm.com#include "mem/packet.hh" 509646SChris.Emmons@arm.com#include "mem/packet_access.hh" 519646SChris.Emmons@arm.com#include "sim/system.hh" 529646SChris.Emmons@arm.com 539646SChris.Emmons@arm.comusing std::vector; 549646SChris.Emmons@arm.com 559646SChris.Emmons@arm.com 569646SChris.Emmons@arm.com// initialize hdlcd registers 579646SChris.Emmons@arm.comHDLcd::HDLcd(const Params *p) 589646SChris.Emmons@arm.com : AmbaDmaDevice(p), version(VERSION_RESETV), 599646SChris.Emmons@arm.com int_rawstat(0), int_clear(0), int_mask(0), int_status(0), 609646SChris.Emmons@arm.com fb_base(0), fb_line_length(0), fb_line_count(0), fb_line_pitch(0), 619646SChris.Emmons@arm.com bus_options(BUS_OPTIONS_RESETV), 629646SChris.Emmons@arm.com v_sync(0), v_back_porch(0), v_data(0), v_front_porch(0), 639646SChris.Emmons@arm.com h_sync(0), h_back_porch(0), h_data(0), h_front_porch(0), 649646SChris.Emmons@arm.com polarities(0), command(0), pixel_format(0), 659646SChris.Emmons@arm.com red_select(0), green_select(0), blue_select(0), 669646SChris.Emmons@arm.com pixelClock(p->pixel_clock), vnc(p->vnc), bmp(NULL), pic(NULL), 679646SChris.Emmons@arm.com frameReadStartTime(0), 689646SChris.Emmons@arm.com dmaStartAddr(0), dmaCurAddr(0), dmaMaxAddr(0), dmaPendingNum(0), 699646SChris.Emmons@arm.com frameUnderrun(false), virtualDisplayBuffer(NULL), pixelBufferSize(0), 709646SChris.Emmons@arm.com pixelIndex(0), doUpdateParams(false), frameUnderway(false), 719646SChris.Emmons@arm.com dmaBytesInFlight(0), 729646SChris.Emmons@arm.com startFrameEvent(this), endFrameEvent(this), renderPixelEvent(this), 739646SChris.Emmons@arm.com fillPixelBufferEvent(this), intEvent(this), 749646SChris.Emmons@arm.com dmaDoneEventAll(MAX_OUTSTANDING_DMA_REQ_CAPACITY, this), 759646SChris.Emmons@arm.com dmaDoneEventFree(MAX_OUTSTANDING_DMA_REQ_CAPACITY) 769646SChris.Emmons@arm.com{ 779646SChris.Emmons@arm.com pioSize = 0xFFFF; 789646SChris.Emmons@arm.com 799646SChris.Emmons@arm.com for (int i = 0; i < MAX_OUTSTANDING_DMA_REQ_CAPACITY; ++i) 809646SChris.Emmons@arm.com dmaDoneEventFree[i] = &dmaDoneEventAll[i]; 819646SChris.Emmons@arm.com 829646SChris.Emmons@arm.com if (vnc) 839646SChris.Emmons@arm.com vnc->setFramebufferAddr(NULL); 849646SChris.Emmons@arm.com} 859646SChris.Emmons@arm.com 869646SChris.Emmons@arm.comHDLcd::~HDLcd() 879646SChris.Emmons@arm.com{ 889646SChris.Emmons@arm.com if (virtualDisplayBuffer) 899646SChris.Emmons@arm.com delete [] virtualDisplayBuffer; 909646SChris.Emmons@arm.com} 919646SChris.Emmons@arm.com 929646SChris.Emmons@arm.com// read registers and frame buffer 939646SChris.Emmons@arm.comTick 949646SChris.Emmons@arm.comHDLcd::read(PacketPtr pkt) 959646SChris.Emmons@arm.com{ 969646SChris.Emmons@arm.com uint32_t data = 0; 979646SChris.Emmons@arm.com const Addr daddr = pkt->getAddr() - pioAddr; 989646SChris.Emmons@arm.com 999646SChris.Emmons@arm.com DPRINTF(HDLcd, "read register BASE+0x%04x size=%d\n", daddr, 1009646SChris.Emmons@arm.com pkt->getSize()); 1019646SChris.Emmons@arm.com 1029646SChris.Emmons@arm.com assert(pkt->getAddr() >= pioAddr && 1039646SChris.Emmons@arm.com pkt->getAddr() < pioAddr + pioSize && 1049646SChris.Emmons@arm.com pkt->getSize() == 4); 1059646SChris.Emmons@arm.com 1069646SChris.Emmons@arm.com pkt->allocate(); 1079646SChris.Emmons@arm.com 1089646SChris.Emmons@arm.com switch (daddr) { 1099646SChris.Emmons@arm.com case Version: 1109646SChris.Emmons@arm.com data = version; 1119646SChris.Emmons@arm.com break; 1129646SChris.Emmons@arm.com case Int_RawStat: 1139646SChris.Emmons@arm.com data = int_rawstat; 1149646SChris.Emmons@arm.com break; 1159646SChris.Emmons@arm.com case Int_Clear: 1169646SChris.Emmons@arm.com panic("HDLCD INT_CLEAR register is Write-Only\n"); 1179646SChris.Emmons@arm.com break; 1189646SChris.Emmons@arm.com case Int_Mask: 1199646SChris.Emmons@arm.com data = int_mask; 1209646SChris.Emmons@arm.com break; 1219646SChris.Emmons@arm.com case Int_Status: 1229646SChris.Emmons@arm.com data = int_status; 1239646SChris.Emmons@arm.com break; 1249646SChris.Emmons@arm.com case Fb_Base: 1259646SChris.Emmons@arm.com data = fb_base; 1269646SChris.Emmons@arm.com break; 1279646SChris.Emmons@arm.com case Fb_Line_Length: 1289646SChris.Emmons@arm.com data = fb_line_length; 1299646SChris.Emmons@arm.com break; 1309646SChris.Emmons@arm.com case Fb_Line_Count: 1319646SChris.Emmons@arm.com data = fb_line_count; 1329646SChris.Emmons@arm.com break; 1339646SChris.Emmons@arm.com case Fb_Line_Pitch: 1349646SChris.Emmons@arm.com data = fb_line_pitch; 1359646SChris.Emmons@arm.com break; 1369646SChris.Emmons@arm.com case Bus_Options: 1379646SChris.Emmons@arm.com data = bus_options; 1389646SChris.Emmons@arm.com break; 1399646SChris.Emmons@arm.com case V_Sync: 1409646SChris.Emmons@arm.com data = v_sync; 1419646SChris.Emmons@arm.com break; 1429646SChris.Emmons@arm.com case V_Back_Porch: 1439646SChris.Emmons@arm.com data = v_back_porch; 1449646SChris.Emmons@arm.com break; 1459646SChris.Emmons@arm.com case V_Data: 1469646SChris.Emmons@arm.com data = v_data; 1479646SChris.Emmons@arm.com break; 1489646SChris.Emmons@arm.com case V_Front_Porch: 1499646SChris.Emmons@arm.com data = v_front_porch; 1509646SChris.Emmons@arm.com break; 1519646SChris.Emmons@arm.com case H_Sync: 1529646SChris.Emmons@arm.com data = h_sync; 1539646SChris.Emmons@arm.com break; 1549646SChris.Emmons@arm.com case H_Back_Porch: 1559646SChris.Emmons@arm.com data = h_back_porch; 1569646SChris.Emmons@arm.com break; 1579646SChris.Emmons@arm.com case H_Data: 1589646SChris.Emmons@arm.com data = h_data; 1599646SChris.Emmons@arm.com break; 1609646SChris.Emmons@arm.com case H_Front_Porch: 1619646SChris.Emmons@arm.com data = h_front_porch; 1629646SChris.Emmons@arm.com break; 1639646SChris.Emmons@arm.com case Polarities: 1649646SChris.Emmons@arm.com data = polarities; 1659646SChris.Emmons@arm.com break; 1669646SChris.Emmons@arm.com case Command: 1679646SChris.Emmons@arm.com data = command; 1689646SChris.Emmons@arm.com break; 1699646SChris.Emmons@arm.com case Pixel_Format: 1709646SChris.Emmons@arm.com data = pixel_format; 1719646SChris.Emmons@arm.com break; 1729646SChris.Emmons@arm.com case Red_Select: 1739646SChris.Emmons@arm.com data = red_select; 1749646SChris.Emmons@arm.com break; 1759646SChris.Emmons@arm.com case Green_Select: 1769646SChris.Emmons@arm.com data = green_select; 1779646SChris.Emmons@arm.com break; 1789646SChris.Emmons@arm.com case Blue_Select: 1799646SChris.Emmons@arm.com data = blue_select; 1809646SChris.Emmons@arm.com break; 1819646SChris.Emmons@arm.com default: 1829646SChris.Emmons@arm.com panic("Tried to read HDLCD register that doesn't exist\n", daddr); 1839646SChris.Emmons@arm.com break; 1849646SChris.Emmons@arm.com } 1859646SChris.Emmons@arm.com 1869646SChris.Emmons@arm.com pkt->set<uint32_t>(data); 1879646SChris.Emmons@arm.com pkt->makeAtomicResponse(); 1889646SChris.Emmons@arm.com return pioDelay; 1899646SChris.Emmons@arm.com} 1909646SChris.Emmons@arm.com 1919646SChris.Emmons@arm.com// write registers and frame buffer 1929646SChris.Emmons@arm.comTick 1939646SChris.Emmons@arm.comHDLcd::write(PacketPtr pkt) 1949646SChris.Emmons@arm.com{ 1959646SChris.Emmons@arm.com assert(pkt->getAddr() >= pioAddr && 1969646SChris.Emmons@arm.com pkt->getAddr() < pioAddr + pioSize && 1979646SChris.Emmons@arm.com pkt->getSize() == 4); 1989646SChris.Emmons@arm.com 1999646SChris.Emmons@arm.com const uint32_t data = pkt->get<uint32_t>(); 2009646SChris.Emmons@arm.com const Addr daddr = pkt->getAddr() - pioAddr; 2019646SChris.Emmons@arm.com 2029646SChris.Emmons@arm.com DPRINTF(HDLcd, "write register BASE+%0x04x <= 0x%08x\n", daddr, 2039646SChris.Emmons@arm.com pkt->get<uint32_t>()); 2049646SChris.Emmons@arm.com 2059646SChris.Emmons@arm.com switch (daddr) { 2069646SChris.Emmons@arm.com case Version: 2079646SChris.Emmons@arm.com panic("HDLCD VERSION register is read-Only\n"); 2089646SChris.Emmons@arm.com break; 2099646SChris.Emmons@arm.com case Int_RawStat: 2109646SChris.Emmons@arm.com int_rawstat = data; 2119646SChris.Emmons@arm.com break; 2129646SChris.Emmons@arm.com case Int_Clear: 2139646SChris.Emmons@arm.com int_clear = data; 2149646SChris.Emmons@arm.com break; 2159646SChris.Emmons@arm.com case Int_Mask: 2169646SChris.Emmons@arm.com int_mask = data; 2179646SChris.Emmons@arm.com break; 2189646SChris.Emmons@arm.com case Int_Status: 2199646SChris.Emmons@arm.com panic("HDLCD INT_STATUS register is read-Only\n"); 2209646SChris.Emmons@arm.com break; 2219646SChris.Emmons@arm.com case Fb_Base: 2229646SChris.Emmons@arm.com fb_base = data; 2239646SChris.Emmons@arm.com DPRINTF(HDLcd, "HDLCD Frame Buffer located at addr 0x%08x\n", fb_base); 2249646SChris.Emmons@arm.com break; 2259646SChris.Emmons@arm.com case Fb_Line_Length: 2269646SChris.Emmons@arm.com fb_line_length = data; 2279646SChris.Emmons@arm.com DPRINTF(HDLcd, "HDLCD res = %d x %d\n", width(), height()); 2289646SChris.Emmons@arm.com break; 2299646SChris.Emmons@arm.com case Fb_Line_Count: 2309646SChris.Emmons@arm.com fb_line_count = data; 2319646SChris.Emmons@arm.com DPRINTF(HDLcd, "HDLCD res = %d x %d\n", width(), height()); 2329646SChris.Emmons@arm.com break; 2339646SChris.Emmons@arm.com case Fb_Line_Pitch: 2349646SChris.Emmons@arm.com fb_line_pitch = data; 2359646SChris.Emmons@arm.com break; 2369646SChris.Emmons@arm.com case Bus_Options: { 2379646SChris.Emmons@arm.com BusOptsReg old_bus_options; 2389646SChris.Emmons@arm.com old_bus_options = bus_options; 2399646SChris.Emmons@arm.com bus_options = data; 2409646SChris.Emmons@arm.com if (bus_options.max_outstanding != old_bus_options.max_outstanding) 2419646SChris.Emmons@arm.com DPRINTF(HDLcd, 2429646SChris.Emmons@arm.com "Changing HDLcd outstanding dma transactions from %d to %d\n", 2439646SChris.Emmons@arm.com old_bus_options.max_outstanding, bus_options.max_outstanding); 2449646SChris.Emmons@arm.com if (bus_options.burst_len != old_bus_options.burst_len) 2459646SChris.Emmons@arm.com DPRINTF(HDLcd, 2469646SChris.Emmons@arm.com "Changing HDLcd dma burst length from %d bytes to %d bytes\n", 2479646SChris.Emmons@arm.com old_bus_options.burst_len, bus_options.burst_len); } 2489646SChris.Emmons@arm.com break; 2499646SChris.Emmons@arm.com case V_Sync: 2509646SChris.Emmons@arm.com v_sync = data; 2519646SChris.Emmons@arm.com break; 2529646SChris.Emmons@arm.com case V_Back_Porch: 2539646SChris.Emmons@arm.com v_back_porch = data; 2549646SChris.Emmons@arm.com break; 2559646SChris.Emmons@arm.com case V_Data: 2569646SChris.Emmons@arm.com v_data = data; 2579646SChris.Emmons@arm.com break; 2589646SChris.Emmons@arm.com case V_Front_Porch: 2599646SChris.Emmons@arm.com v_front_porch = data; 2609646SChris.Emmons@arm.com break; 2619646SChris.Emmons@arm.com case H_Sync: 2629646SChris.Emmons@arm.com h_sync = data; 2639646SChris.Emmons@arm.com break; 2649646SChris.Emmons@arm.com case H_Back_Porch: 2659646SChris.Emmons@arm.com h_back_porch = data; 2669646SChris.Emmons@arm.com break; 2679646SChris.Emmons@arm.com case H_Data: 2689646SChris.Emmons@arm.com h_data = data; 2699646SChris.Emmons@arm.com break; 2709646SChris.Emmons@arm.com case H_Front_Porch: 2719646SChris.Emmons@arm.com h_front_porch = data; 2729646SChris.Emmons@arm.com break; 2739646SChris.Emmons@arm.com case Polarities: 2749646SChris.Emmons@arm.com polarities = data; 2759646SChris.Emmons@arm.com break; 2769646SChris.Emmons@arm.com case Command: { 2779646SChris.Emmons@arm.com CommandReg new_command; 2789646SChris.Emmons@arm.com new_command = data; 2799646SChris.Emmons@arm.com if (new_command.enable != command.enable) { 2809646SChris.Emmons@arm.com DPRINTF(HDLcd, "HDLCD switched %s\n", 2819646SChris.Emmons@arm.com new_command.enable==0 ? "off" : "on"); 2829646SChris.Emmons@arm.com if (new_command.enable) { 2839646SChris.Emmons@arm.com doUpdateParams = true; 2849646SChris.Emmons@arm.com if (!frameUnderway) { 2859646SChris.Emmons@arm.com schedule(startFrameEvent, nextCycle()); 2869646SChris.Emmons@arm.com } 2879646SChris.Emmons@arm.com } 2889646SChris.Emmons@arm.com } 2899646SChris.Emmons@arm.com command = new_command; } 2909646SChris.Emmons@arm.com break; 2919646SChris.Emmons@arm.com case Pixel_Format: 2929646SChris.Emmons@arm.com pixel_format = data; 2939646SChris.Emmons@arm.com DPRINTF(HDLcd, "HDLCD res = %d x %d\n", width(), height()); 2949646SChris.Emmons@arm.com DPRINTF(HDLcd, "HDLCD bytes per pixel = %d\n", bytesPerPixel()); 2959646SChris.Emmons@arm.com DPRINTF(HDLcd, "HDLCD endianness = %s\n", 2969646SChris.Emmons@arm.com pixel_format.big_endian ? "big" : "little"); 2979646SChris.Emmons@arm.com break; 2989646SChris.Emmons@arm.com case Red_Select: 2999646SChris.Emmons@arm.com red_select = data; 3009646SChris.Emmons@arm.com break; 3019646SChris.Emmons@arm.com case Green_Select: 3029646SChris.Emmons@arm.com green_select = data; 3039646SChris.Emmons@arm.com break; 3049646SChris.Emmons@arm.com case Blue_Select: 3059646SChris.Emmons@arm.com blue_select = data; 3069646SChris.Emmons@arm.com break; 3079646SChris.Emmons@arm.com default: 3089646SChris.Emmons@arm.com panic("Tried to write HDLCD register that doesn't exist\n", daddr); 3099646SChris.Emmons@arm.com break; 3109646SChris.Emmons@arm.com } 3119646SChris.Emmons@arm.com 3129646SChris.Emmons@arm.com pkt->makeAtomicResponse(); 3139646SChris.Emmons@arm.com return pioDelay; 3149646SChris.Emmons@arm.com} 3159646SChris.Emmons@arm.com 3169646SChris.Emmons@arm.comvoid 3179646SChris.Emmons@arm.comHDLcd::updateVideoParams(bool unserializing = false) 3189646SChris.Emmons@arm.com{ 3199646SChris.Emmons@arm.com const uint16_t bpp = bytesPerPixel() << 3; 3209646SChris.Emmons@arm.com const size_t buffer_size = bytesPerPixel() * width() * height(); 3219646SChris.Emmons@arm.com 3229646SChris.Emmons@arm.com // updating these parameters while LCD is enabled is not supported 3239646SChris.Emmons@arm.com if (frameUnderway && !unserializing) 3249646SChris.Emmons@arm.com panic("Attempting to change some HDLCD parameters while the controller" 3259646SChris.Emmons@arm.com " is active is not allowed"); 3269646SChris.Emmons@arm.com 3279646SChris.Emmons@arm.com // resize the virtualDisplayBuffer unless we are unserializing - it may 3289646SChris.Emmons@arm.com // have changed size 3299646SChris.Emmons@arm.com // there must be no outstanding DMA transactions for this to work 3309646SChris.Emmons@arm.com if (!unserializing) { 3319646SChris.Emmons@arm.com assert(dmaPendingNum == 0); 3329646SChris.Emmons@arm.com if (virtualDisplayBuffer) 3339646SChris.Emmons@arm.com delete [] virtualDisplayBuffer; 3349646SChris.Emmons@arm.com virtualDisplayBuffer = new uint8_t[buffer_size]; 3359646SChris.Emmons@arm.com memset(virtualDisplayBuffer, 0, buffer_size); 3369646SChris.Emmons@arm.com } 3379646SChris.Emmons@arm.com 3389646SChris.Emmons@arm.com assert(virtualDisplayBuffer); 3399646SChris.Emmons@arm.com if (vnc) 3409646SChris.Emmons@arm.com vnc->setFramebufferAddr(virtualDisplayBuffer); 3419646SChris.Emmons@arm.com 3429646SChris.Emmons@arm.com if (bmp) 3439646SChris.Emmons@arm.com delete bmp; 3449646SChris.Emmons@arm.com 3459646SChris.Emmons@arm.com DPRINTF(HDLcd, "bpp = %d\n", bpp); 3469646SChris.Emmons@arm.com DPRINTF(HDLcd, "display size = %d x %d\n", width(), height()); 3479646SChris.Emmons@arm.com#if TRACING_ON 3489646SChris.Emmons@arm.com const size_t totalLinesPerFrame = v_back_porch.val + 1 + 3499646SChris.Emmons@arm.com v_data.val + 1 + 3509646SChris.Emmons@arm.com v_front_porch.val + 1 + 3519646SChris.Emmons@arm.com v_sync.val + 1; 3529646SChris.Emmons@arm.com const double fps = (double)SimClock::Frequency / 3539646SChris.Emmons@arm.com (double)(PClksPerLine() * totalLinesPerFrame * pixelClock); 3549646SChris.Emmons@arm.com#endif 3559646SChris.Emmons@arm.com DPRINTF(HDLcd, "simulated refresh rate ~ %.1ffps generating ~ %.1fMB/s " 3569646SChris.Emmons@arm.com "traffic ([%.1fMHz, T=%d sim clocks] pclk, %d bpp => %.1fMB/s peak requirement)\n", 3579646SChris.Emmons@arm.com fps, 3589646SChris.Emmons@arm.com fps * buffer_size / 1024 / 1024, 3599646SChris.Emmons@arm.com (double)SimClock::Frequency / pixelClock / 1000000.0, 3609646SChris.Emmons@arm.com pixelClock, 3619646SChris.Emmons@arm.com bpp, 3629646SChris.Emmons@arm.com (double)(SimClock::Frequency / pixelClock * (bpp / 8)) / 1024 / 1024); 3639646SChris.Emmons@arm.com 3649646SChris.Emmons@arm.com if (pixel_format.big_endian) 3659646SChris.Emmons@arm.com panic("Big Endian pixel format not implemented by HDLcd controller"); 3669646SChris.Emmons@arm.com 3679646SChris.Emmons@arm.com if (vnc) { 3689646SChris.Emmons@arm.com if ((bpp == 24) && 3699646SChris.Emmons@arm.com (red_select.size == 8) && 3709646SChris.Emmons@arm.com (blue_select.size == 8) && 3719646SChris.Emmons@arm.com (green_select.size == 8) && 3729646SChris.Emmons@arm.com (green_select.offset == 8)) { 3739646SChris.Emmons@arm.com if ((blue_select.offset == 0) && 3749646SChris.Emmons@arm.com (red_select.offset == 16)) { 3759646SChris.Emmons@arm.com vnc->setFrameBufferParams(VideoConvert::rgb8888, width(), 3769646SChris.Emmons@arm.com height()); 3779646SChris.Emmons@arm.com bmp = new Bitmap(VideoConvert::rgb8888, width(), height(), 3789646SChris.Emmons@arm.com virtualDisplayBuffer); 3799646SChris.Emmons@arm.com DPRINTF(HDLcd, "color mode: rgb888\n"); 3809646SChris.Emmons@arm.com } else if ((red_select.offset == 0) && 3819646SChris.Emmons@arm.com (blue_select.offset == 16)) { 3829646SChris.Emmons@arm.com vnc->setFrameBufferParams(VideoConvert::bgr8888, width(), 3839646SChris.Emmons@arm.com height()); 3849646SChris.Emmons@arm.com bmp = new Bitmap(VideoConvert::bgr8888, width(), height(), 3859646SChris.Emmons@arm.com virtualDisplayBuffer); 3869646SChris.Emmons@arm.com DPRINTF(HDLcd, "color mode: bgr888\n"); 3879646SChris.Emmons@arm.com } 3889646SChris.Emmons@arm.com } else if ((bpp == 16) && 3899646SChris.Emmons@arm.com (red_select.size == 5) && 3909646SChris.Emmons@arm.com (blue_select.size == 5) && 3919646SChris.Emmons@arm.com (green_select.size == 6) && 3929646SChris.Emmons@arm.com (green_select.offset == 5)) { 3939646SChris.Emmons@arm.com if ((blue_select.offset == 0) && 3949646SChris.Emmons@arm.com (red_select.offset == 11)) { 3959646SChris.Emmons@arm.com vnc->setFrameBufferParams(VideoConvert::rgb565, width(), 3969646SChris.Emmons@arm.com height()); 3979646SChris.Emmons@arm.com bmp = new Bitmap(VideoConvert::rgb565, width(), height(), 3989646SChris.Emmons@arm.com virtualDisplayBuffer); 3999646SChris.Emmons@arm.com DPRINTF(HDLcd, "color mode: rgb565\n"); 4009646SChris.Emmons@arm.com } else if ((red_select.offset == 0) && 4019646SChris.Emmons@arm.com (blue_select.offset == 11)) { 4029646SChris.Emmons@arm.com vnc->setFrameBufferParams(VideoConvert::bgr565, width(), 4039646SChris.Emmons@arm.com height()); 4049646SChris.Emmons@arm.com bmp = new Bitmap(VideoConvert::bgr565, width(), height(), 4059646SChris.Emmons@arm.com virtualDisplayBuffer); 4069646SChris.Emmons@arm.com DPRINTF(HDLcd, "color mode: bgr565\n"); 4079646SChris.Emmons@arm.com } 4089646SChris.Emmons@arm.com } else { 4099646SChris.Emmons@arm.com DPRINTF(HDLcd, "color mode: undefined\n"); 4109646SChris.Emmons@arm.com panic("Unimplemented video mode\n"); 4119646SChris.Emmons@arm.com } 4129646SChris.Emmons@arm.com } 4139646SChris.Emmons@arm.com} 4149646SChris.Emmons@arm.com 4159646SChris.Emmons@arm.comvoid 4169646SChris.Emmons@arm.comHDLcd::startFrame() 4179646SChris.Emmons@arm.com{ 4189646SChris.Emmons@arm.com // 0. Check that we are in the appropriate state 4199646SChris.Emmons@arm.com assert(!frameUnderway); 4209646SChris.Emmons@arm.com if (!command.enable) 4219646SChris.Emmons@arm.com return; 4229646SChris.Emmons@arm.com DPRINTF(HDLcd, "Frame read started\n"); 4239646SChris.Emmons@arm.com if (doUpdateParams) { 4249646SChris.Emmons@arm.com updateVideoParams(); 4259646SChris.Emmons@arm.com doUpdateParams = false; 4269646SChris.Emmons@arm.com } 4279646SChris.Emmons@arm.com frameUnderway = true; 4289646SChris.Emmons@arm.com assert(virtualDisplayBuffer); 4299646SChris.Emmons@arm.com assert(pixelBufferSize == 0); 4309646SChris.Emmons@arm.com assert(dmaBytesInFlight == 0); 4319646SChris.Emmons@arm.com assert(dmaPendingNum == 0); 4329646SChris.Emmons@arm.com assert(dmaDoneEventFree.size() == dmaDoneEventAll.size()); 4339646SChris.Emmons@arm.com assert(!renderPixelEvent.scheduled()); 4349646SChris.Emmons@arm.com // currently only support positive line pitches equal to the line length 4359646SChris.Emmons@arm.com assert(width() * bytesPerPixel() == fb_line_pitch); 4369646SChris.Emmons@arm.com 4379646SChris.Emmons@arm.com // 1. Start DMA'ing the frame; subsequent transactions created as we go 4389646SChris.Emmons@arm.com dmaCurAddr = dmaStartAddr = fb_base; 4399646SChris.Emmons@arm.com dmaMaxAddr = static_cast<Addr>(width() * height() * bytesPerPixel()) + 4409646SChris.Emmons@arm.com dmaCurAddr; 4419646SChris.Emmons@arm.com frameReadStartTime = curTick(); 4429646SChris.Emmons@arm.com pixelIndex = 0; 4439646SChris.Emmons@arm.com frameUnderrun = false; 4449646SChris.Emmons@arm.com fillPixelBuffer(); 4459646SChris.Emmons@arm.com 4469646SChris.Emmons@arm.com // 2. Schedule first pixelclock read; subsequent reads generated as we go 4479646SChris.Emmons@arm.com Tick firstPixelReadTick = curTick() + pixelClock * ( 4489646SChris.Emmons@arm.com PClksPerLine() * (v_sync.val + 1 + 4499646SChris.Emmons@arm.com v_back_porch.val + 1) + 4509646SChris.Emmons@arm.com h_sync.val + 1 + 4519646SChris.Emmons@arm.com h_back_porch.val + 1); 4529646SChris.Emmons@arm.com schedule(renderPixelEvent, firstPixelReadTick); 4539646SChris.Emmons@arm.com} 4549646SChris.Emmons@arm.com 4559646SChris.Emmons@arm.comvoid 4569646SChris.Emmons@arm.comHDLcd::fillPixelBuffer() 4579646SChris.Emmons@arm.com{ 4589646SChris.Emmons@arm.com // - am I under the LCD dma transaction total? 4599646SChris.Emmons@arm.com // - do I have more data to transfer? 4609646SChris.Emmons@arm.com // - have I not yet underrun for this frame? 4619646SChris.Emmons@arm.com // - is there room to put the data in the pixel buffer including any 4629646SChris.Emmons@arm.com // outstanding dma transfers in flight? 4639646SChris.Emmons@arm.com while ((dmaPendingNum < maxOutstandingDma()) && 4649646SChris.Emmons@arm.com (dmaMaxAddr > dmaCurAddr) && 4659646SChris.Emmons@arm.com !frameUnderrun && 4669646SChris.Emmons@arm.com bytesFreeInPixelBuffer() > dmaBurstLength() * AXI_PORT_WIDTH) { 4679646SChris.Emmons@arm.com // try largest transaction size allowed first but switch to smaller 4689646SChris.Emmons@arm.com // sizes for trailing bytes 4699646SChris.Emmons@arm.com size_t transaction_size = dmaBurstLength() * AXI_PORT_WIDTH; 4709646SChris.Emmons@arm.com while (transaction_size > (dmaMaxAddr - dmaCurAddr)) 4719646SChris.Emmons@arm.com transaction_size >>= 1; 4729646SChris.Emmons@arm.com assert(transaction_size > 0); 4739646SChris.Emmons@arm.com 4749646SChris.Emmons@arm.com // concurrent dma reads need different dma done events 4759646SChris.Emmons@arm.com // due to assertion in scheduling state 4769646SChris.Emmons@arm.com ++dmaPendingNum; 4779646SChris.Emmons@arm.com 4789646SChris.Emmons@arm.com assert(!dmaDoneEventFree.empty()); 4799646SChris.Emmons@arm.com DmaDoneEvent *event(dmaDoneEventFree.back()); 4809646SChris.Emmons@arm.com dmaDoneEventFree.pop_back(); 4819646SChris.Emmons@arm.com assert(event); 4829646SChris.Emmons@arm.com assert(!event->scheduled()); 4839646SChris.Emmons@arm.com 4849646SChris.Emmons@arm.com // We use a uncachable request here because the requests from the CPU 4859646SChris.Emmons@arm.com // will be uncacheable as well. If we have uncacheable and cacheable 4869646SChris.Emmons@arm.com // requests in the memory system for the same address it won't be 4879646SChris.Emmons@arm.com // pleased 4889646SChris.Emmons@arm.com event->setTransactionSize(transaction_size); 4899646SChris.Emmons@arm.com dmaPort.dmaAction(MemCmd::ReadReq, dmaCurAddr, transaction_size, event, 4909646SChris.Emmons@arm.com virtualDisplayBuffer + dmaCurAddr - dmaStartAddr, 4919646SChris.Emmons@arm.com 0, Request::UNCACHEABLE); 4929646SChris.Emmons@arm.com dmaCurAddr += transaction_size; 4939646SChris.Emmons@arm.com dmaBytesInFlight += transaction_size; 4949646SChris.Emmons@arm.com } 4959646SChris.Emmons@arm.com} 4969646SChris.Emmons@arm.com 4979646SChris.Emmons@arm.comvoid 4989646SChris.Emmons@arm.comHDLcd::renderPixel() 4999646SChris.Emmons@arm.com{ 5009646SChris.Emmons@arm.com // try to handle multiple pixels at a time; doing so reduces the accuracy 5019646SChris.Emmons@arm.com // of the underrun detection but lowers simulation overhead 5029646SChris.Emmons@arm.com const size_t count = 32; 5039646SChris.Emmons@arm.com assert(width() % count == 0); // not set up to handle trailing pixels 5049646SChris.Emmons@arm.com 5059646SChris.Emmons@arm.com // have we underrun on this frame anytime before? 5069646SChris.Emmons@arm.com if (frameUnderrun) { 5079646SChris.Emmons@arm.com // the LCD controller gives up on a frame if an underrun occurs and 5089646SChris.Emmons@arm.com // resumes regular operation on the next frame 5099646SChris.Emmons@arm.com pixelBufferSize = 0; 5109646SChris.Emmons@arm.com } else { 5119646SChris.Emmons@arm.com // did we underrun on this set of pixels? 5129646SChris.Emmons@arm.com if (pixelBufferSize < bytesPerPixel() * count) { 5139646SChris.Emmons@arm.com warn("HDLcd controller buffer underrun\n"); 5149646SChris.Emmons@arm.com frameUnderrun = true; 5159646SChris.Emmons@arm.com int_rawstat.underrun = 1; 5169646SChris.Emmons@arm.com if (!intEvent.scheduled()) 5179646SChris.Emmons@arm.com schedule(intEvent, nextCycle()); 5189646SChris.Emmons@arm.com } else { 5199646SChris.Emmons@arm.com // emulate the pixel read from the internal buffer 5209646SChris.Emmons@arm.com pixelBufferSize -= bytesPerPixel() * count; 5219646SChris.Emmons@arm.com } 5229646SChris.Emmons@arm.com } 5239646SChris.Emmons@arm.com 5249646SChris.Emmons@arm.com // the DMA may have previously stalled due to the buffer being full; 5259646SChris.Emmons@arm.com // give it a kick; it knows not to fill if at end of frame, underrun, etc 5269646SChris.Emmons@arm.com if (!fillPixelBufferEvent.scheduled()) 5279646SChris.Emmons@arm.com schedule(fillPixelBufferEvent, nextCycle()); 5289646SChris.Emmons@arm.com 5299646SChris.Emmons@arm.com // schedule the next pixel read according to where it is in the frame 5309646SChris.Emmons@arm.com pixelIndex += count; 5319646SChris.Emmons@arm.com assert(pixelIndex <= width() * height()); 5329646SChris.Emmons@arm.com size_t x = pixelIndex % width(); 5339646SChris.Emmons@arm.com Tick nextEventTick = curTick(); 5349646SChris.Emmons@arm.com if (x == 0) { 5359646SChris.Emmons@arm.com // start of new line 5369646SChris.Emmons@arm.com nextEventTick += pixelClock * ((h_front_porch.val + 1) + 5379646SChris.Emmons@arm.com (h_back_porch.val + 1) + 5389646SChris.Emmons@arm.com (h_sync.val + 1)); 5399646SChris.Emmons@arm.com if (pixelIndex == width() * height()) { 5409646SChris.Emmons@arm.com // end of frame 5419646SChris.Emmons@arm.com nextEventTick += PClksPerLine() * (v_front_porch.val + 1) * 5429646SChris.Emmons@arm.com pixelClock; 5439646SChris.Emmons@arm.com schedule(endFrameEvent, nextEventTick); 5449646SChris.Emmons@arm.com return; 5459646SChris.Emmons@arm.com } 5469646SChris.Emmons@arm.com } else { 5479646SChris.Emmons@arm.com nextEventTick += pixelClock * count; 5489646SChris.Emmons@arm.com } 5499646SChris.Emmons@arm.com 5509646SChris.Emmons@arm.com schedule(renderPixelEvent, nextEventTick); 5519646SChris.Emmons@arm.com} 5529646SChris.Emmons@arm.com 5539646SChris.Emmons@arm.comvoid 5549646SChris.Emmons@arm.comHDLcd::endFrame() { 5559646SChris.Emmons@arm.com assert(pixelBufferSize == 0); 5569646SChris.Emmons@arm.com assert(dmaPendingNum == 0); 5579646SChris.Emmons@arm.com assert(dmaBytesInFlight == 0); 5589646SChris.Emmons@arm.com assert(dmaDoneEventFree.size() == dmaDoneEventAll.size()); 5599646SChris.Emmons@arm.com 5609646SChris.Emmons@arm.com if (vnc) 5619646SChris.Emmons@arm.com vnc->setDirty(); 5629646SChris.Emmons@arm.com 5639646SChris.Emmons@arm.com if (!pic) 5649646SChris.Emmons@arm.com pic = simout.create(csprintf("%s.framebuffer.bmp", sys->name()), true); 5659646SChris.Emmons@arm.com 5669646SChris.Emmons@arm.com assert(bmp); 5679646SChris.Emmons@arm.com assert(pic); 5689646SChris.Emmons@arm.com pic->seekp(0); 5699646SChris.Emmons@arm.com bmp->write(pic); 5709646SChris.Emmons@arm.com 5719646SChris.Emmons@arm.com // start the next frame 5729646SChris.Emmons@arm.com frameUnderway = false; 5739646SChris.Emmons@arm.com startFrame(); 5749646SChris.Emmons@arm.com} 5759646SChris.Emmons@arm.com 5769646SChris.Emmons@arm.comvoid 5779646SChris.Emmons@arm.comHDLcd::dmaDone(DmaDoneEvent *event) 5789646SChris.Emmons@arm.com{ 5799646SChris.Emmons@arm.com const size_t transactionLength = event->getTransactionSize(); 5809646SChris.Emmons@arm.com assert(pixelBufferSize + transactionLength < PIXEL_BUFFER_CAPACITY); 5819646SChris.Emmons@arm.com assert(dmaCurAddr <= dmaMaxAddr); 5829646SChris.Emmons@arm.com 5839646SChris.Emmons@arm.com dmaDoneEventFree.push_back(event); 5849646SChris.Emmons@arm.com --dmaPendingNum; 5859646SChris.Emmons@arm.com assert(MAX_OUTSTANDING_DMA_REQ_CAPACITY - dmaDoneEventFree.size() == 5869646SChris.Emmons@arm.com dmaPendingNum); 5879646SChris.Emmons@arm.com 5889646SChris.Emmons@arm.com // add the data to the pixel buffer 5899646SChris.Emmons@arm.com dmaBytesInFlight -= transactionLength; 5909646SChris.Emmons@arm.com pixelBufferSize += transactionLength; 5919646SChris.Emmons@arm.com 5929646SChris.Emmons@arm.com // schedule another dma transaction if: 5939646SChris.Emmons@arm.com // - we're not done reading the frame 5949646SChris.Emmons@arm.com // - there is sufficient room in the pixel buffer for another transaction 5959646SChris.Emmons@arm.com // - another fillPixelBufferEvent is not already scheduled 5969646SChris.Emmons@arm.com const size_t targetTransSize = dmaBurstLength() * AXI_PORT_WIDTH; 5979646SChris.Emmons@arm.com if ((dmaCurAddr < dmaMaxAddr) && 5989646SChris.Emmons@arm.com (bytesFreeInPixelBuffer() + targetTransSize < PIXEL_BUFFER_CAPACITY) && 5999646SChris.Emmons@arm.com !fillPixelBufferEvent.scheduled()) { 6009646SChris.Emmons@arm.com schedule(fillPixelBufferEvent, nextCycle()); 6019646SChris.Emmons@arm.com } 6029646SChris.Emmons@arm.com} 6039646SChris.Emmons@arm.com 6049646SChris.Emmons@arm.comvoid 6059646SChris.Emmons@arm.comHDLcd::serialize(std::ostream &os) 6069646SChris.Emmons@arm.com{ 6079646SChris.Emmons@arm.com DPRINTF(HDLcd, "Serializing ARM HDLCD\n"); 6089646SChris.Emmons@arm.com 6099646SChris.Emmons@arm.com const uint32_t version_serial = version; 6109646SChris.Emmons@arm.com SERIALIZE_SCALAR(version_serial); 6119646SChris.Emmons@arm.com const uint32_t int_rawstat_serial = int_rawstat; 6129646SChris.Emmons@arm.com SERIALIZE_SCALAR(int_rawstat_serial); 6139646SChris.Emmons@arm.com const uint32_t int_clear_serial = int_clear; 6149646SChris.Emmons@arm.com SERIALIZE_SCALAR(int_clear_serial); 6159646SChris.Emmons@arm.com const uint32_t int_mask_serial = int_mask; 6169646SChris.Emmons@arm.com SERIALIZE_SCALAR(int_mask_serial); 6179646SChris.Emmons@arm.com const uint32_t int_status_serial = int_status; 6189646SChris.Emmons@arm.com SERIALIZE_SCALAR(int_status_serial); 6199646SChris.Emmons@arm.com 6209646SChris.Emmons@arm.com SERIALIZE_SCALAR(fb_base); 6219646SChris.Emmons@arm.com SERIALIZE_SCALAR(fb_line_length); 6229646SChris.Emmons@arm.com 6239646SChris.Emmons@arm.com const uint32_t fb_line_count_serial = fb_line_count; 6249646SChris.Emmons@arm.com SERIALIZE_SCALAR(fb_line_count_serial); 6259646SChris.Emmons@arm.com 6269646SChris.Emmons@arm.com SERIALIZE_SCALAR(fb_line_pitch); 6279646SChris.Emmons@arm.com 6289646SChris.Emmons@arm.com const uint32_t bus_options_serial = bus_options; 6299646SChris.Emmons@arm.com SERIALIZE_SCALAR(bus_options_serial); 6309646SChris.Emmons@arm.com const uint32_t v_sync_serial = v_sync; 6319646SChris.Emmons@arm.com SERIALIZE_SCALAR(v_sync_serial); 6329646SChris.Emmons@arm.com const uint32_t v_back_porch_serial = v_back_porch; 6339646SChris.Emmons@arm.com SERIALIZE_SCALAR(v_back_porch_serial); 6349646SChris.Emmons@arm.com const uint32_t v_data_serial = v_data; 6359646SChris.Emmons@arm.com SERIALIZE_SCALAR(v_data_serial); 6369646SChris.Emmons@arm.com const uint32_t v_front_porch_serial = v_front_porch; 6379646SChris.Emmons@arm.com SERIALIZE_SCALAR(v_front_porch_serial); 6389646SChris.Emmons@arm.com const uint32_t h_sync_serial = h_sync; 6399646SChris.Emmons@arm.com SERIALIZE_SCALAR(h_sync_serial); 6409646SChris.Emmons@arm.com const uint32_t h_back_porch_serial = h_back_porch; 6419646SChris.Emmons@arm.com SERIALIZE_SCALAR(h_back_porch_serial); 6429646SChris.Emmons@arm.com const uint32_t h_data_serial = h_data; 6439646SChris.Emmons@arm.com SERIALIZE_SCALAR(h_data_serial); 6449646SChris.Emmons@arm.com const uint32_t h_front_porch_serial = h_front_porch; 6459646SChris.Emmons@arm.com SERIALIZE_SCALAR(h_front_porch_serial); 6469646SChris.Emmons@arm.com const uint32_t polarities_serial = polarities; 6479646SChris.Emmons@arm.com SERIALIZE_SCALAR(polarities_serial); 6489646SChris.Emmons@arm.com const uint32_t command_serial = command; 6499646SChris.Emmons@arm.com SERIALIZE_SCALAR(command_serial); 6509646SChris.Emmons@arm.com const uint32_t pixel_format_serial = pixel_format; 6519646SChris.Emmons@arm.com SERIALIZE_SCALAR(pixel_format_serial); 6529646SChris.Emmons@arm.com const uint32_t red_select_serial = red_select; 6539646SChris.Emmons@arm.com SERIALIZE_SCALAR(red_select_serial); 6549646SChris.Emmons@arm.com const uint32_t green_select_serial = green_select; 6559646SChris.Emmons@arm.com SERIALIZE_SCALAR(green_select_serial); 6569646SChris.Emmons@arm.com const uint32_t blue_select_serial = blue_select; 6579646SChris.Emmons@arm.com SERIALIZE_SCALAR(blue_select_serial); 6589646SChris.Emmons@arm.com 6599646SChris.Emmons@arm.com SERIALIZE_SCALAR(frameReadStartTime); 6609646SChris.Emmons@arm.com SERIALIZE_SCALAR(dmaStartAddr); 6619646SChris.Emmons@arm.com SERIALIZE_SCALAR(dmaCurAddr); 6629646SChris.Emmons@arm.com SERIALIZE_SCALAR(dmaMaxAddr); 6639646SChris.Emmons@arm.com SERIALIZE_SCALAR(dmaPendingNum); 6649646SChris.Emmons@arm.com SERIALIZE_SCALAR(frameUnderrun); 6659646SChris.Emmons@arm.com 6669646SChris.Emmons@arm.com const size_t buffer_size = bytesPerPixel() * width() * height(); 6679646SChris.Emmons@arm.com SERIALIZE_ARRAY(virtualDisplayBuffer, buffer_size); 6689646SChris.Emmons@arm.com 6699646SChris.Emmons@arm.com SERIALIZE_SCALAR(pixelBufferSize); 6709646SChris.Emmons@arm.com SERIALIZE_SCALAR(pixelIndex); 6719646SChris.Emmons@arm.com SERIALIZE_SCALAR(doUpdateParams); 6729646SChris.Emmons@arm.com SERIALIZE_SCALAR(frameUnderway); 6739646SChris.Emmons@arm.com SERIALIZE_SCALAR(dmaBytesInFlight); 6749646SChris.Emmons@arm.com 6759646SChris.Emmons@arm.com Tick start_event_time = 0; 6769646SChris.Emmons@arm.com Tick end_event_time = 0; 6779646SChris.Emmons@arm.com Tick render_pixel_event_time = 0; 6789646SChris.Emmons@arm.com Tick fill_pixel_buffer_event_time = 0; 6799646SChris.Emmons@arm.com Tick int_event_time = 0; 6809646SChris.Emmons@arm.com if (startFrameEvent.scheduled()) 6819646SChris.Emmons@arm.com start_event_time = startFrameEvent.when(); 6829646SChris.Emmons@arm.com if (endFrameEvent.scheduled()) 6839646SChris.Emmons@arm.com end_event_time = endFrameEvent.when(); 6849646SChris.Emmons@arm.com if (renderPixelEvent.scheduled()) 6859646SChris.Emmons@arm.com render_pixel_event_time = renderPixelEvent.when(); 6869646SChris.Emmons@arm.com if (fillPixelBufferEvent.scheduled()) 6879646SChris.Emmons@arm.com fill_pixel_buffer_event_time = fillPixelBufferEvent.when(); 6889646SChris.Emmons@arm.com if (intEvent.scheduled()) 6899646SChris.Emmons@arm.com int_event_time = intEvent.when(); 6909646SChris.Emmons@arm.com SERIALIZE_SCALAR(start_event_time); 6919646SChris.Emmons@arm.com SERIALIZE_SCALAR(end_event_time); 6929646SChris.Emmons@arm.com SERIALIZE_SCALAR(render_pixel_event_time); 6939646SChris.Emmons@arm.com SERIALIZE_SCALAR(fill_pixel_buffer_event_time); 6949646SChris.Emmons@arm.com SERIALIZE_SCALAR(int_event_time); 6959646SChris.Emmons@arm.com 6969646SChris.Emmons@arm.com vector<Tick> dma_done_event_tick(MAX_OUTSTANDING_DMA_REQ_CAPACITY); 6979646SChris.Emmons@arm.com vector<size_t> dma_done_event_burst_len(MAX_OUTSTANDING_DMA_REQ_CAPACITY); 6989646SChris.Emmons@arm.com for (int x = 0; x < MAX_OUTSTANDING_DMA_REQ_CAPACITY; ++x) { 6999646SChris.Emmons@arm.com dma_done_event_tick[x] = dmaDoneEventAll[x].scheduled() ? 7009646SChris.Emmons@arm.com dmaDoneEventAll[x].when() : 0; 7019646SChris.Emmons@arm.com dma_done_event_burst_len[x] = dmaDoneEventAll[x].scheduled() ? 7029646SChris.Emmons@arm.com dmaDoneEventAll[x].getTransactionSize() : 0; 7039646SChris.Emmons@arm.com } 7049646SChris.Emmons@arm.com arrayParamOut(os, "dma_done_event_tick", dma_done_event_tick); 7059646SChris.Emmons@arm.com arrayParamOut(os, "dma_done_event_burst_length", dma_done_event_burst_len); 7069646SChris.Emmons@arm.com} 7079646SChris.Emmons@arm.com 7089646SChris.Emmons@arm.comvoid 7099646SChris.Emmons@arm.comHDLcd::unserialize(Checkpoint *cp, const std::string §ion) 7109646SChris.Emmons@arm.com{ 7119646SChris.Emmons@arm.com uint32_t version_serial, int_rawstat_serial, int_clear_serial, 7129646SChris.Emmons@arm.com int_mask_serial, int_status_serial, fb_line_count_serial, 7139646SChris.Emmons@arm.com bus_options_serial, v_sync_serial, v_back_porch_serial, 7149646SChris.Emmons@arm.com v_data_serial, v_front_porch_serial, h_sync_serial, 7159646SChris.Emmons@arm.com h_back_porch_serial, h_data_serial, h_front_porch_serial, 7169646SChris.Emmons@arm.com polarities_serial, command_serial, pixel_format_serial, 7179646SChris.Emmons@arm.com red_select_serial, green_select_serial, blue_select_serial; 7189646SChris.Emmons@arm.com 7199646SChris.Emmons@arm.com DPRINTF(HDLcd, "Unserializing ARM HDLCD\n"); 7209646SChris.Emmons@arm.com 7219646SChris.Emmons@arm.com UNSERIALIZE_SCALAR(version_serial); 7229646SChris.Emmons@arm.com version = version_serial; 7239646SChris.Emmons@arm.com UNSERIALIZE_SCALAR(int_rawstat_serial); 7249646SChris.Emmons@arm.com int_rawstat = int_rawstat_serial; 7259646SChris.Emmons@arm.com UNSERIALIZE_SCALAR(int_clear_serial); 7269646SChris.Emmons@arm.com int_clear = int_clear_serial; 7279646SChris.Emmons@arm.com UNSERIALIZE_SCALAR(int_mask_serial); 7289646SChris.Emmons@arm.com int_mask = int_mask_serial; 7299646SChris.Emmons@arm.com UNSERIALIZE_SCALAR(int_status_serial); 7309646SChris.Emmons@arm.com int_status = int_status_serial; 7319646SChris.Emmons@arm.com 7329646SChris.Emmons@arm.com UNSERIALIZE_SCALAR(fb_base); 7339646SChris.Emmons@arm.com UNSERIALIZE_SCALAR(fb_line_length); 7349646SChris.Emmons@arm.com 7359646SChris.Emmons@arm.com UNSERIALIZE_SCALAR(fb_line_count_serial); 7369646SChris.Emmons@arm.com fb_line_count = fb_line_count_serial; 7379646SChris.Emmons@arm.com 7389646SChris.Emmons@arm.com UNSERIALIZE_SCALAR(fb_line_pitch); 7399646SChris.Emmons@arm.com 7409646SChris.Emmons@arm.com UNSERIALIZE_SCALAR(bus_options_serial); 7419646SChris.Emmons@arm.com bus_options = bus_options_serial; 7429646SChris.Emmons@arm.com UNSERIALIZE_SCALAR(v_sync_serial); 7439646SChris.Emmons@arm.com v_sync = v_sync_serial; 7449646SChris.Emmons@arm.com UNSERIALIZE_SCALAR(v_back_porch_serial); 7459646SChris.Emmons@arm.com v_back_porch = v_back_porch_serial; 7469646SChris.Emmons@arm.com UNSERIALIZE_SCALAR(v_data_serial); 7479646SChris.Emmons@arm.com v_data = v_data_serial; 7489646SChris.Emmons@arm.com UNSERIALIZE_SCALAR(v_front_porch_serial); 7499646SChris.Emmons@arm.com v_front_porch = v_front_porch_serial; 7509646SChris.Emmons@arm.com UNSERIALIZE_SCALAR(h_sync_serial); 7519646SChris.Emmons@arm.com h_sync = h_sync_serial; 7529646SChris.Emmons@arm.com UNSERIALIZE_SCALAR(h_back_porch_serial); 7539646SChris.Emmons@arm.com h_back_porch = h_back_porch_serial; 7549646SChris.Emmons@arm.com UNSERIALIZE_SCALAR(h_data_serial); 7559646SChris.Emmons@arm.com h_data = h_data_serial; 7569646SChris.Emmons@arm.com UNSERIALIZE_SCALAR(h_front_porch_serial); 7579646SChris.Emmons@arm.com h_front_porch = h_front_porch_serial; 7589646SChris.Emmons@arm.com UNSERIALIZE_SCALAR(polarities_serial); 7599646SChris.Emmons@arm.com polarities = polarities_serial; 7609646SChris.Emmons@arm.com UNSERIALIZE_SCALAR(command_serial); 7619646SChris.Emmons@arm.com command = command_serial; 7629646SChris.Emmons@arm.com UNSERIALIZE_SCALAR(pixel_format_serial); 7639646SChris.Emmons@arm.com pixel_format = pixel_format_serial; 7649646SChris.Emmons@arm.com UNSERIALIZE_SCALAR(red_select_serial); 7659646SChris.Emmons@arm.com red_select = red_select_serial; 7669646SChris.Emmons@arm.com UNSERIALIZE_SCALAR(green_select_serial); 7679646SChris.Emmons@arm.com green_select = green_select_serial; 7689646SChris.Emmons@arm.com UNSERIALIZE_SCALAR(blue_select_serial); 7699646SChris.Emmons@arm.com blue_select = blue_select_serial; 7709646SChris.Emmons@arm.com 7719646SChris.Emmons@arm.com UNSERIALIZE_SCALAR(frameReadStartTime); 7729646SChris.Emmons@arm.com UNSERIALIZE_SCALAR(dmaStartAddr); 7739646SChris.Emmons@arm.com UNSERIALIZE_SCALAR(dmaCurAddr); 7749646SChris.Emmons@arm.com UNSERIALIZE_SCALAR(dmaMaxAddr); 7759646SChris.Emmons@arm.com UNSERIALIZE_SCALAR(dmaPendingNum); 7769646SChris.Emmons@arm.com UNSERIALIZE_SCALAR(frameUnderrun); 7779646SChris.Emmons@arm.com UNSERIALIZE_SCALAR(dmaBytesInFlight); 7789646SChris.Emmons@arm.com 7799646SChris.Emmons@arm.com const size_t buffer_size = bytesPerPixel() * width() * height(); 7809646SChris.Emmons@arm.com virtualDisplayBuffer = new uint8_t[buffer_size]; 7819646SChris.Emmons@arm.com UNSERIALIZE_ARRAY(virtualDisplayBuffer, buffer_size); 7829646SChris.Emmons@arm.com 7839646SChris.Emmons@arm.com UNSERIALIZE_SCALAR(pixelBufferSize); 7849646SChris.Emmons@arm.com UNSERIALIZE_SCALAR(pixelIndex); 7859646SChris.Emmons@arm.com UNSERIALIZE_SCALAR(doUpdateParams); 7869646SChris.Emmons@arm.com UNSERIALIZE_SCALAR(frameUnderway); 7879646SChris.Emmons@arm.com 7889646SChris.Emmons@arm.com Tick start_event_time = 0; 7899646SChris.Emmons@arm.com Tick end_event_time = 0; 7909646SChris.Emmons@arm.com Tick render_pixel_event_time = 0; 7919646SChris.Emmons@arm.com Tick fill_pixel_buffer_event_time = 0; 7929646SChris.Emmons@arm.com Tick int_event_time = 0; 7939646SChris.Emmons@arm.com UNSERIALIZE_SCALAR(start_event_time); 7949646SChris.Emmons@arm.com UNSERIALIZE_SCALAR(end_event_time); 7959646SChris.Emmons@arm.com UNSERIALIZE_SCALAR(render_pixel_event_time); 7969646SChris.Emmons@arm.com UNSERIALIZE_SCALAR(fill_pixel_buffer_event_time); 7979646SChris.Emmons@arm.com UNSERIALIZE_SCALAR(int_event_time); 7989646SChris.Emmons@arm.com if (start_event_time) 7999646SChris.Emmons@arm.com schedule(startFrameEvent, start_event_time); 8009646SChris.Emmons@arm.com if (end_event_time) 8019646SChris.Emmons@arm.com schedule(endFrameEvent, end_event_time); 8029646SChris.Emmons@arm.com if (render_pixel_event_time) 8039646SChris.Emmons@arm.com schedule(renderPixelEvent, render_pixel_event_time); 8049646SChris.Emmons@arm.com if (fill_pixel_buffer_event_time) 8059646SChris.Emmons@arm.com schedule(fillPixelBufferEvent, fill_pixel_buffer_event_time); 8069646SChris.Emmons@arm.com if (int_event_time) 8079646SChris.Emmons@arm.com schedule(intEvent, int_event_time); 8089646SChris.Emmons@arm.com 8099646SChris.Emmons@arm.com vector<Tick> dma_done_event_tick(MAX_OUTSTANDING_DMA_REQ_CAPACITY); 8109646SChris.Emmons@arm.com vector<Tick> dma_done_event_burst_len(MAX_OUTSTANDING_DMA_REQ_CAPACITY); 8119646SChris.Emmons@arm.com arrayParamIn(cp, section, "dma_done_event_tick", dma_done_event_tick); 8129646SChris.Emmons@arm.com arrayParamIn(cp, section, "dma_done_event_burst_length", dma_done_event_burst_len); 8139646SChris.Emmons@arm.com dmaDoneEventFree.clear(); 8149646SChris.Emmons@arm.com for (int x = 0; x < MAX_OUTSTANDING_DMA_REQ_CAPACITY; ++x) { 8159646SChris.Emmons@arm.com if (dma_done_event_tick[x]) { 8169646SChris.Emmons@arm.com dmaDoneEventAll[x].setTransactionSize(dma_done_event_burst_len[x]); 8179646SChris.Emmons@arm.com schedule(dmaDoneEventAll[x], dma_done_event_tick[x]); 8189646SChris.Emmons@arm.com } else 8199646SChris.Emmons@arm.com dmaDoneEventFree.push_back(&dmaDoneEventAll[x]); 8209646SChris.Emmons@arm.com } 8219646SChris.Emmons@arm.com assert(MAX_OUTSTANDING_DMA_REQ_CAPACITY - dmaDoneEventFree.size() == dmaPendingNum); 8229646SChris.Emmons@arm.com 8239646SChris.Emmons@arm.com if (frameUnderway) { 8249646SChris.Emmons@arm.com updateVideoParams(true); 8259646SChris.Emmons@arm.com if (vnc) 8269646SChris.Emmons@arm.com vnc->setDirty(); 8279646SChris.Emmons@arm.com } 8289646SChris.Emmons@arm.com} 8299646SChris.Emmons@arm.com 8309646SChris.Emmons@arm.comvoid 8319646SChris.Emmons@arm.comHDLcd::generateInterrupt() 8329646SChris.Emmons@arm.com{ 8339646SChris.Emmons@arm.com int_status = int_rawstat & int_mask; 8349646SChris.Emmons@arm.com DPRINTF(HDLcd, "Generate Interrupt: int_rawstat=0x%08x int_mask=0x%08x " 8359646SChris.Emmons@arm.com "int_status=0x%08x\n", 8369646SChris.Emmons@arm.com (uint32_t)int_rawstat, (uint32_t)int_mask, (uint32_t)int_status); 8379646SChris.Emmons@arm.com 8389646SChris.Emmons@arm.com if (int_status != 0) { 8399646SChris.Emmons@arm.com gic->sendInt(intNum); 8409646SChris.Emmons@arm.com DPRINTF(HDLcd, " -- Generated\n"); 8419646SChris.Emmons@arm.com } 8429646SChris.Emmons@arm.com} 8439646SChris.Emmons@arm.com 8449646SChris.Emmons@arm.comAddrRangeList 8459646SChris.Emmons@arm.comHDLcd::getAddrRanges() const 8469646SChris.Emmons@arm.com{ 8479646SChris.Emmons@arm.com AddrRangeList ranges; 8489646SChris.Emmons@arm.com ranges.push_back(RangeSize(pioAddr, pioSize)); 8499646SChris.Emmons@arm.com return ranges; 8509646SChris.Emmons@arm.com} 8519646SChris.Emmons@arm.com 8529646SChris.Emmons@arm.comHDLcd * 8539646SChris.Emmons@arm.comHDLcdParams::create() 8549646SChris.Emmons@arm.com{ 8559646SChris.Emmons@arm.com return new HDLcd(this); 8569646SChris.Emmons@arm.com} 857