hdlcd.cc revision 11091
17405SAli.Saidi@ARM.com/* 27405SAli.Saidi@ARM.com * Copyright (c) 2010-2013, 2015 ARM Limited 37405SAli.Saidi@ARM.com * All rights reserved 47405SAli.Saidi@ARM.com * 57405SAli.Saidi@ARM.com * The license below extends only to copyright in the software and shall 67405SAli.Saidi@ARM.com * not be construed as granting a license to any other intellectual 77405SAli.Saidi@ARM.com * property including but not limited to intellectual property relating 87405SAli.Saidi@ARM.com * to a hardware implementation of the functionality of the software 97405SAli.Saidi@ARM.com * licensed hereunder. You may use the software subject to the license 107405SAli.Saidi@ARM.com * terms below provided that you ensure that this notice is replicated 117405SAli.Saidi@ARM.com * unmodified and in its entirety in all distributions of the software, 127405SAli.Saidi@ARM.com * modified or unmodified, in source code or in binary form. 137405SAli.Saidi@ARM.com * 147405SAli.Saidi@ARM.com * Redistribution and use in source and binary forms, with or without 157405SAli.Saidi@ARM.com * modification, are permitted provided that the following conditions are 167405SAli.Saidi@ARM.com * met: redistributions of source code must retain the above copyright 177405SAli.Saidi@ARM.com * notice, this list of conditions and the following disclaimer; 187405SAli.Saidi@ARM.com * redistributions in binary form must reproduce the above copyright 197405SAli.Saidi@ARM.com * notice, this list of conditions and the following disclaimer in the 207405SAli.Saidi@ARM.com * documentation and/or other materials provided with the distribution; 217405SAli.Saidi@ARM.com * neither the name of the copyright holders nor the names of its 227405SAli.Saidi@ARM.com * contributors may be used to endorse or promote products derived from 237405SAli.Saidi@ARM.com * this software without specific prior written permission. 247405SAli.Saidi@ARM.com * 257405SAli.Saidi@ARM.com * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 267405SAli.Saidi@ARM.com * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 277405SAli.Saidi@ARM.com * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 287405SAli.Saidi@ARM.com * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 297405SAli.Saidi@ARM.com * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 307405SAli.Saidi@ARM.com * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 317405SAli.Saidi@ARM.com * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 327405SAli.Saidi@ARM.com * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 337405SAli.Saidi@ARM.com * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 347405SAli.Saidi@ARM.com * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 357405SAli.Saidi@ARM.com * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 367405SAli.Saidi@ARM.com * 377405SAli.Saidi@ARM.com * Authors: Chris Emmons 387405SAli.Saidi@ARM.com * Andreas Sandberg 397405SAli.Saidi@ARM.com */ 407405SAli.Saidi@ARM.com 417405SAli.Saidi@ARM.com#include "dev/arm/hdlcd.hh" 427678Sgblack@eecs.umich.edu 437405SAli.Saidi@ARM.com#include "base/vnc/vncinput.hh" 447405SAli.Saidi@ARM.com#include "base/output.hh" 457405SAli.Saidi@ARM.com#include "base/trace.hh" 467405SAli.Saidi@ARM.com#include "debug/Checkpoint.hh" 477427Sgblack@eecs.umich.edu#include "debug/HDLcd.hh" 487427Sgblack@eecs.umich.edu#include "dev/arm/amba_device.hh" 497427Sgblack@eecs.umich.edu#include "dev/arm/base_gic.hh" 507427Sgblack@eecs.umich.edu#include "mem/packet.hh" 517427Sgblack@eecs.umich.edu#include "mem/packet_access.hh" 527427Sgblack@eecs.umich.edu#include "params/HDLcd.hh" 537427Sgblack@eecs.umich.edu#include "sim/system.hh" 547427Sgblack@eecs.umich.edu 557427Sgblack@eecs.umich.eduusing std::vector; 567427Sgblack@eecs.umich.edu 577427Sgblack@eecs.umich.edu 587427Sgblack@eecs.umich.edu// initialize hdlcd registers 597604SGene.Wu@arm.comHDLcd::HDLcd(const HDLcdParams *p) 607427Sgblack@eecs.umich.edu : AmbaDmaDevice(p, 0xFFFF), 617427Sgblack@eecs.umich.edu // Parameters 627427Sgblack@eecs.umich.edu vnc(p->vnc), 637427Sgblack@eecs.umich.edu workaroundSwapRB(p->workaround_swap_rb), 647427Sgblack@eecs.umich.edu workaroundDmaLineCount(p->workaround_dma_line_count), 657427Sgblack@eecs.umich.edu addrRanges{RangeSize(pioAddr, pioSize)}, 667427Sgblack@eecs.umich.edu enableCapture(p->enable_capture), 677427Sgblack@eecs.umich.edu pixelBufferSize(p->pixel_buffer_size), 687427Sgblack@eecs.umich.edu 697427Sgblack@eecs.umich.edu // Registers 707427Sgblack@eecs.umich.edu version(VERSION_RESETV), 717427Sgblack@eecs.umich.edu int_rawstat(0), int_mask(0), 727427Sgblack@eecs.umich.edu 737427Sgblack@eecs.umich.edu fb_base(0), fb_line_length(0), fb_line_count(0), fb_line_pitch(0), 747427Sgblack@eecs.umich.edu bus_options(BUS_OPTIONS_RESETV), 757427Sgblack@eecs.umich.edu 767427Sgblack@eecs.umich.edu v_sync(0), v_back_porch(0), v_data(0), v_front_porch(0), 777427Sgblack@eecs.umich.edu h_sync(0), h_back_porch(0), h_data(0), h_front_porch(0), 787645Sali.saidi@arm.com polarities(0), 797645Sali.saidi@arm.com 807645Sali.saidi@arm.com command(0), 817645Sali.saidi@arm.com 827645Sali.saidi@arm.com pixel_format(0), 837427Sgblack@eecs.umich.edu red_select(0), green_select(0), blue_select(0), 847427Sgblack@eecs.umich.edu 857427Sgblack@eecs.umich.edu // Other 867427Sgblack@eecs.umich.edu bmp(&pixelPump.fb), pic(NULL), conv(PixelConverter::rgba8888_le), 877427Sgblack@eecs.umich.edu pixelPump(*this, *p->pxl_clk, p->pixel_chunk) 887427Sgblack@eecs.umich.edu{ 897427Sgblack@eecs.umich.edu if (vnc) 907427Sgblack@eecs.umich.edu vnc->setFrameBuffer(&pixelPump.fb); 917427Sgblack@eecs.umich.edu} 927427Sgblack@eecs.umich.edu 937427Sgblack@eecs.umich.eduHDLcd::~HDLcd() 947427Sgblack@eecs.umich.edu{ 957427Sgblack@eecs.umich.edu} 967427Sgblack@eecs.umich.edu 977427Sgblack@eecs.umich.eduvoid 987427Sgblack@eecs.umich.eduHDLcd::regStats() 997427Sgblack@eecs.umich.edu{ 1007427Sgblack@eecs.umich.edu using namespace Stats; 1017427Sgblack@eecs.umich.edu 1027427Sgblack@eecs.umich.edu stats.underruns 1037427Sgblack@eecs.umich.edu .name(name() + ".underruns") 1047427Sgblack@eecs.umich.edu .desc("number of buffer underruns") 1057427Sgblack@eecs.umich.edu .flags(nozero) 1067427Sgblack@eecs.umich.edu ; 1077427Sgblack@eecs.umich.edu} 1087427Sgblack@eecs.umich.edu 1097427Sgblack@eecs.umich.eduvoid 1107427Sgblack@eecs.umich.eduHDLcd::serialize(CheckpointOut &cp) const 1117436Sdam.sunwoo@arm.com{ 1127436Sdam.sunwoo@arm.com DPRINTF(Checkpoint, "Serializing ARM HDLCD\n"); 1137436Sdam.sunwoo@arm.com 1147436Sdam.sunwoo@arm.com SERIALIZE_SCALAR(int_rawstat); 1157436Sdam.sunwoo@arm.com SERIALIZE_SCALAR(int_mask); 1167436Sdam.sunwoo@arm.com 1177436Sdam.sunwoo@arm.com SERIALIZE_SCALAR(fb_base); 1187436Sdam.sunwoo@arm.com SERIALIZE_SCALAR(fb_line_length); 1197436Sdam.sunwoo@arm.com SERIALIZE_SCALAR(fb_line_count); 1207436Sdam.sunwoo@arm.com SERIALIZE_SCALAR(fb_line_pitch); 1217436Sdam.sunwoo@arm.com SERIALIZE_SCALAR(bus_options); 1227436Sdam.sunwoo@arm.com 1237436Sdam.sunwoo@arm.com SERIALIZE_SCALAR(v_sync); 1247436Sdam.sunwoo@arm.com SERIALIZE_SCALAR(v_back_porch); 1257436Sdam.sunwoo@arm.com SERIALIZE_SCALAR(v_data); 1267436Sdam.sunwoo@arm.com SERIALIZE_SCALAR(v_front_porch); 1277436Sdam.sunwoo@arm.com 1287436Sdam.sunwoo@arm.com SERIALIZE_SCALAR(h_sync); 1297436Sdam.sunwoo@arm.com SERIALIZE_SCALAR(h_back_porch); 1307436Sdam.sunwoo@arm.com SERIALIZE_SCALAR(h_data); 1317436Sdam.sunwoo@arm.com SERIALIZE_SCALAR(h_front_porch); 1327436Sdam.sunwoo@arm.com 1337436Sdam.sunwoo@arm.com SERIALIZE_SCALAR(polarities); 1347436Sdam.sunwoo@arm.com 1357436Sdam.sunwoo@arm.com SERIALIZE_SCALAR(command); 1367436Sdam.sunwoo@arm.com SERIALIZE_SCALAR(pixel_format); 1377436Sdam.sunwoo@arm.com SERIALIZE_SCALAR(red_select); 1387436Sdam.sunwoo@arm.com SERIALIZE_SCALAR(green_select); 1397436Sdam.sunwoo@arm.com SERIALIZE_SCALAR(blue_select); 1407436Sdam.sunwoo@arm.com 1417436Sdam.sunwoo@arm.com SERIALIZE_OBJ(pixelPump); 1427436Sdam.sunwoo@arm.com if (enabled()) 1437644Sali.saidi@arm.com dmaEngine->serializeSection(cp, "dmaEngine"); 1447644Sali.saidi@arm.com} 1457427Sgblack@eecs.umich.edu 1467427Sgblack@eecs.umich.eduvoid 1477427Sgblack@eecs.umich.eduHDLcd::unserialize(CheckpointIn &cp) 1487405SAli.Saidi@ARM.com{ 1497405SAli.Saidi@ARM.com DPRINTF(Checkpoint, "Unserializing ARM HDLCD\n"); 1507405SAli.Saidi@ARM.com 1517405SAli.Saidi@ARM.com UNSERIALIZE_SCALAR(int_rawstat); 1527614Sminkyu.jeong@arm.com UNSERIALIZE_SCALAR(int_mask); 1537614Sminkyu.jeong@arm.com 1547614Sminkyu.jeong@arm.com UNSERIALIZE_SCALAR(fb_base); 1557614Sminkyu.jeong@arm.com UNSERIALIZE_SCALAR(fb_line_length); 1567614Sminkyu.jeong@arm.com UNSERIALIZE_SCALAR(fb_line_count); 1577614Sminkyu.jeong@arm.com UNSERIALIZE_SCALAR(fb_line_pitch); 1587614Sminkyu.jeong@arm.com UNSERIALIZE_SCALAR(bus_options); 1597614Sminkyu.jeong@arm.com 1607614Sminkyu.jeong@arm.com UNSERIALIZE_SCALAR(v_sync); 1617614Sminkyu.jeong@arm.com UNSERIALIZE_SCALAR(v_back_porch); 1627614Sminkyu.jeong@arm.com UNSERIALIZE_SCALAR(v_data); 1637405SAli.Saidi@ARM.com UNSERIALIZE_SCALAR(v_front_porch); 1647405SAli.Saidi@ARM.com 1657405SAli.Saidi@ARM.com UNSERIALIZE_SCALAR(h_sync); 1667405SAli.Saidi@ARM.com UNSERIALIZE_SCALAR(h_back_porch); 1677405SAli.Saidi@ARM.com UNSERIALIZE_SCALAR(h_data); 1687405SAli.Saidi@ARM.com UNSERIALIZE_SCALAR(h_front_porch); 1697405SAli.Saidi@ARM.com 1707405SAli.Saidi@ARM.com UNSERIALIZE_SCALAR(polarities); 1717720Sgblack@eecs.umich.edu 1727720Sgblack@eecs.umich.edu UNSERIALIZE_SCALAR(command); 1737720Sgblack@eecs.umich.edu UNSERIALIZE_SCALAR(pixel_format); 1747405SAli.Saidi@ARM.com UNSERIALIZE_SCALAR(red_select); 1757405SAli.Saidi@ARM.com UNSERIALIZE_SCALAR(green_select); 1767757SAli.Saidi@ARM.com UNSERIALIZE_SCALAR(blue_select); 1777405SAli.Saidi@ARM.com 1787405SAli.Saidi@ARM.com { 1797757SAli.Saidi@ARM.com // Try to unserialize the pixel pump. It might not exist if 1807405SAli.Saidi@ARM.com // we're unserializing an old checkpoint. 1817405SAli.Saidi@ARM.com ScopedCheckpointSection sec(cp, "pixelPump"); 1827731SAli.Saidi@ARM.com if (cp.sectionExists(Serializable::currentSection())) 1837405SAli.Saidi@ARM.com pixelPump.unserialize(cp); 1847405SAli.Saidi@ARM.com } 1857731SAli.Saidi@ARM.com 1867405SAli.Saidi@ARM.com if (enabled()) { 1877405SAli.Saidi@ARM.com // Create the DMA engine and read its state from the 1887405SAli.Saidi@ARM.com // checkpoint. We don't need to worry about the pixel pump as 1897588SAli.Saidi@arm.com // it is a proper SimObject. 1907588SAli.Saidi@arm.com createDmaEngine(); 1917588SAli.Saidi@arm.com dmaEngine->unserializeSection(cp, "dmaEngine"); 1927583SAli.Saidi@arm.com 1937583SAli.Saidi@arm.com conv = pixelConverter(); 1947583SAli.Saidi@arm.com } 1957583SAli.Saidi@arm.com} 1967583SAli.Saidi@arm.com 1977583SAli.Saidi@arm.comvoid 1987583SAli.Saidi@arm.comHDLcd::drainResume() 1997583SAli.Saidi@arm.com{ 2007583SAli.Saidi@arm.com AmbaDmaDevice::drainResume(); 2017583SAli.Saidi@arm.com 2027583SAli.Saidi@arm.com // We restored from an old checkpoint without a pixel pump, start 2037583SAli.Saidi@arm.com // an new refresh. This typically happens when restoring from old 2047583SAli.Saidi@arm.com // checkpoints. 2057583SAli.Saidi@arm.com if (enabled() && !pixelPump.active()) 2067405SAli.Saidi@ARM.com pixelPump.start(displayTimings()); 2077405SAli.Saidi@ARM.com 2087405SAli.Saidi@ARM.com // We restored from a checkpoint and need to update the VNC server 2097405SAli.Saidi@ARM.com if (pixelPump.active() && vnc) 2107405SAli.Saidi@ARM.com vnc->setDirty(); 2117405SAli.Saidi@ARM.com} 2127405SAli.Saidi@ARM.com 2137405SAli.Saidi@ARM.com// read registers and frame buffer 2147614Sminkyu.jeong@arm.comTick 2157614Sminkyu.jeong@arm.comHDLcd::read(PacketPtr pkt) 2167614Sminkyu.jeong@arm.com{ 2177614Sminkyu.jeong@arm.com assert(pkt->getAddr() >= pioAddr && 2187614Sminkyu.jeong@arm.com pkt->getAddr() < pioAddr + pioSize); 2197614Sminkyu.jeong@arm.com 2207614Sminkyu.jeong@arm.com const Addr daddr(pkt->getAddr() - pioAddr); 2217614Sminkyu.jeong@arm.com panic_if(pkt->getSize() != 4, 2227614Sminkyu.jeong@arm.com "Unhandled read size (address: 0x.4x, size: %u)", 2237614Sminkyu.jeong@arm.com daddr, pkt->getSize()); 2247405SAli.Saidi@ARM.com 2257405SAli.Saidi@ARM.com const uint32_t data(readReg(daddr)); 2267405SAli.Saidi@ARM.com DPRINTF(HDLcd, "read register 0x%04x: 0x%x\n", daddr, data); 2277405SAli.Saidi@ARM.com 2287405SAli.Saidi@ARM.com pkt->set<uint32_t>(data); 2297749SAli.Saidi@ARM.com pkt->makeAtomicResponse(); 2307405SAli.Saidi@ARM.com return pioDelay; 2317405SAli.Saidi@ARM.com} 2327405SAli.Saidi@ARM.com 2337749SAli.Saidi@ARM.com// write registers and frame buffer 2347749SAli.Saidi@ARM.comTick 2357749SAli.Saidi@ARM.comHDLcd::write(PacketPtr pkt) 2367749SAli.Saidi@ARM.com{ 2377405SAli.Saidi@ARM.com assert(pkt->getAddr() >= pioAddr && 2387749SAli.Saidi@ARM.com pkt->getAddr() < pioAddr + pioSize); 2397749SAli.Saidi@ARM.com 2407749SAli.Saidi@ARM.com const Addr daddr(pkt->getAddr() - pioAddr); 2417749SAli.Saidi@ARM.com panic_if(pkt->getSize() != 4, 2427749SAli.Saidi@ARM.com "Unhandled read size (address: 0x.4x, size: %u)", 2437614Sminkyu.jeong@arm.com daddr, pkt->getSize()); 2447614Sminkyu.jeong@arm.com const uint32_t data(pkt->get<uint32_t>()); 2457720Sgblack@eecs.umich.edu DPRINTF(HDLcd, "write register 0x%04x: 0x%x\n", daddr, data); 2467720Sgblack@eecs.umich.edu 2477720Sgblack@eecs.umich.edu writeReg(daddr, data); 2487720Sgblack@eecs.umich.edu 2497408Sgblack@eecs.umich.edu pkt->makeAtomicResponse(); 2507405SAli.Saidi@ARM.com return pioDelay; 2517405SAli.Saidi@ARM.com} 2527405SAli.Saidi@ARM.com 2537408Sgblack@eecs.umich.eduuint32_t 2547408Sgblack@eecs.umich.eduHDLcd::readReg(Addr offset) 2557408Sgblack@eecs.umich.edu{ 2567408Sgblack@eecs.umich.edu switch (offset) { 2577408Sgblack@eecs.umich.edu case Version: return version; 2587408Sgblack@eecs.umich.edu 2597408Sgblack@eecs.umich.edu case Int_RawStat: return int_rawstat; 2607408Sgblack@eecs.umich.edu case Int_Clear: 2617408Sgblack@eecs.umich.edu panic("HDLCD INT_CLEAR register is Write-Only\n"); 2627408Sgblack@eecs.umich.edu case Int_Mask: return int_mask; 2637408Sgblack@eecs.umich.edu case Int_Status: return intStatus(); 2647408Sgblack@eecs.umich.edu 2657405SAli.Saidi@ARM.com case Fb_Base: return fb_base; 2667408Sgblack@eecs.umich.edu case Fb_Line_Length: return fb_line_length; 2677408Sgblack@eecs.umich.edu case Fb_Line_Count: return fb_line_count; 2687408Sgblack@eecs.umich.edu case Fb_Line_Pitch: return fb_line_pitch; 2697408Sgblack@eecs.umich.edu case Bus_Options: return bus_options; 2707408Sgblack@eecs.umich.edu 2717408Sgblack@eecs.umich.edu case V_Sync: return v_sync; 2727408Sgblack@eecs.umich.edu case V_Back_Porch: return v_back_porch; 2737640Sgblack@eecs.umich.edu case V_Data: return v_data; 2747640Sgblack@eecs.umich.edu case V_Front_Porch: return v_front_porch; 2757640Sgblack@eecs.umich.edu case H_Sync: return h_sync; 2767408Sgblack@eecs.umich.edu case H_Back_Porch: return h_back_porch; 2777408Sgblack@eecs.umich.edu case H_Data: return h_data; 2787408Sgblack@eecs.umich.edu case H_Front_Porch: return h_front_porch; 2797408Sgblack@eecs.umich.edu case Polarities: return polarities; 2807731SAli.Saidi@ARM.com 2817408Sgblack@eecs.umich.edu case Command: return command; 2827408Sgblack@eecs.umich.edu case Pixel_Format: return pixel_format; 2837408Sgblack@eecs.umich.edu case Red_Select: return red_select; 2847408Sgblack@eecs.umich.edu case Green_Select: return green_select; 2857408Sgblack@eecs.umich.edu case Blue_Select: return blue_select; 2867408Sgblack@eecs.umich.edu 2877408Sgblack@eecs.umich.edu default: 2887408Sgblack@eecs.umich.edu panic("Tried to read HDLCD register that doesn't exist\n", offset); 2897408Sgblack@eecs.umich.edu } 2907408Sgblack@eecs.umich.edu} 2917408Sgblack@eecs.umich.edu 2927408Sgblack@eecs.umich.eduvoid 2937408Sgblack@eecs.umich.eduHDLcd::writeReg(Addr offset, uint32_t value) 2947408Sgblack@eecs.umich.edu{ 2957408Sgblack@eecs.umich.edu switch (offset) { 2967408Sgblack@eecs.umich.edu case Version: 2977408Sgblack@eecs.umich.edu panic("HDLCD VERSION register is read-Only\n"); 2987408Sgblack@eecs.umich.edu 2997408Sgblack@eecs.umich.edu case Int_RawStat: 3007408Sgblack@eecs.umich.edu intRaise(value); 3017408Sgblack@eecs.umich.edu return; 3027408Sgblack@eecs.umich.edu case Int_Clear: 3037408Sgblack@eecs.umich.edu intClear(value); 3047408Sgblack@eecs.umich.edu return; 3057408Sgblack@eecs.umich.edu case Int_Mask: 3067408Sgblack@eecs.umich.edu intMask(value); 3077408Sgblack@eecs.umich.edu return; 3087408Sgblack@eecs.umich.edu case Int_Status: 3097408Sgblack@eecs.umich.edu panic("HDLCD INT_STATUS register is read-Only\n"); 3107408Sgblack@eecs.umich.edu break; 3117408Sgblack@eecs.umich.edu 3127408Sgblack@eecs.umich.edu case Fb_Base: 3137408Sgblack@eecs.umich.edu fb_base = value; 3147408Sgblack@eecs.umich.edu return; 3157408Sgblack@eecs.umich.edu 3167408Sgblack@eecs.umich.edu case Fb_Line_Length: 3177408Sgblack@eecs.umich.edu fb_line_length = value; 3187408Sgblack@eecs.umich.edu return; 3197408Sgblack@eecs.umich.edu 3207408Sgblack@eecs.umich.edu case Fb_Line_Count: 3217749SAli.Saidi@ARM.com fb_line_count = value; 3227749SAli.Saidi@ARM.com return; 3237408Sgblack@eecs.umich.edu 3247408Sgblack@eecs.umich.edu case Fb_Line_Pitch: 3257408Sgblack@eecs.umich.edu fb_line_pitch = value; 3267408Sgblack@eecs.umich.edu return; 3277408Sgblack@eecs.umich.edu 3287408Sgblack@eecs.umich.edu case Bus_Options: { 3297408Sgblack@eecs.umich.edu const BusOptsReg old_bus_options(bus_options); 3307408Sgblack@eecs.umich.edu bus_options = value; 3317408Sgblack@eecs.umich.edu 3327408Sgblack@eecs.umich.edu if (bus_options.max_outstanding != old_bus_options.max_outstanding) { 3337731SAli.Saidi@ARM.com DPRINTF(HDLcd, 3347408Sgblack@eecs.umich.edu "Changing HDLcd outstanding DMA transactions: %d -> %d\n", 3357408Sgblack@eecs.umich.edu old_bus_options.max_outstanding, 3367408Sgblack@eecs.umich.edu bus_options.max_outstanding); 3377408Sgblack@eecs.umich.edu 3387408Sgblack@eecs.umich.edu } 3397408Sgblack@eecs.umich.edu 3407408Sgblack@eecs.umich.edu if (bus_options.burst_len != old_bus_options.burst_len) { 3417408Sgblack@eecs.umich.edu DPRINTF(HDLcd, 3427408Sgblack@eecs.umich.edu "Changing HDLcd DMA burst flags: 0x%x -> 0x%x\n", 3437408Sgblack@eecs.umich.edu old_bus_options.burst_len, bus_options.burst_len); 3447408Sgblack@eecs.umich.edu } 3457731SAli.Saidi@ARM.com } return; 3467408Sgblack@eecs.umich.edu 3477408Sgblack@eecs.umich.edu case V_Sync: 3487408Sgblack@eecs.umich.edu v_sync = value; 3497408Sgblack@eecs.umich.edu return; 3507408Sgblack@eecs.umich.edu case V_Back_Porch: 3517408Sgblack@eecs.umich.edu v_back_porch = value; 3527408Sgblack@eecs.umich.edu return; 3537731SAli.Saidi@ARM.com case V_Data: 3547408Sgblack@eecs.umich.edu v_data = value; 3557408Sgblack@eecs.umich.edu return; 3567408Sgblack@eecs.umich.edu case V_Front_Porch: 3577408Sgblack@eecs.umich.edu v_front_porch = value; 3587408Sgblack@eecs.umich.edu return; 3597731SAli.Saidi@ARM.com 3607408Sgblack@eecs.umich.edu case H_Sync: 3617408Sgblack@eecs.umich.edu h_sync = value; 3627408Sgblack@eecs.umich.edu return; 3637408Sgblack@eecs.umich.edu case H_Back_Porch: 3647408Sgblack@eecs.umich.edu h_back_porch = value; 3657408Sgblack@eecs.umich.edu return; 3667408Sgblack@eecs.umich.edu case H_Data: 3677408Sgblack@eecs.umich.edu h_data = value; 3687408Sgblack@eecs.umich.edu return; 3697408Sgblack@eecs.umich.edu case H_Front_Porch: 3707408Sgblack@eecs.umich.edu h_front_porch = value; 3717408Sgblack@eecs.umich.edu return; 3727408Sgblack@eecs.umich.edu 3737408Sgblack@eecs.umich.edu case Polarities: 3747408Sgblack@eecs.umich.edu polarities = value; 3757408Sgblack@eecs.umich.edu return; 3767405SAli.Saidi@ARM.com 3777583SAli.Saidi@arm.com case Command: { 3787583SAli.Saidi@arm.com const CommandReg new_command(value); 3797583SAli.Saidi@arm.com 3807583SAli.Saidi@arm.com if (new_command.enable != command.enable) { 3817583SAli.Saidi@arm.com DPRINTF(HDLcd, "HDLCD switched %s\n", 3827583SAli.Saidi@arm.com new_command.enable ? "on" : "off"); 3837583SAli.Saidi@arm.com 3847583SAli.Saidi@arm.com if (new_command.enable) { 3857583SAli.Saidi@arm.com cmdEnable(); 3867436Sdam.sunwoo@arm.com } else { 3877436Sdam.sunwoo@arm.com cmdDisable(); 3887436Sdam.sunwoo@arm.com } 3897436Sdam.sunwoo@arm.com } 3907436Sdam.sunwoo@arm.com command = new_command; 3917436Sdam.sunwoo@arm.com } return; 3927436Sdam.sunwoo@arm.com 3937436Sdam.sunwoo@arm.com case Pixel_Format: 3947436Sdam.sunwoo@arm.com pixel_format = value; 3957436Sdam.sunwoo@arm.com return; 3967436Sdam.sunwoo@arm.com 3977436Sdam.sunwoo@arm.com case Red_Select: 3987436Sdam.sunwoo@arm.com red_select = value; 3997436Sdam.sunwoo@arm.com return; 4007436Sdam.sunwoo@arm.com case Green_Select: 4017436Sdam.sunwoo@arm.com green_select = value; 4027436Sdam.sunwoo@arm.com return; 4037436Sdam.sunwoo@arm.com case Blue_Select: 4047436Sdam.sunwoo@arm.com blue_select = value; 4057436Sdam.sunwoo@arm.com return; 4067436Sdam.sunwoo@arm.com 4077436Sdam.sunwoo@arm.com default: 4087436Sdam.sunwoo@arm.com panic("Tried to write HDLCD register that doesn't exist\n", offset); 4097436Sdam.sunwoo@arm.com return; 4107436Sdam.sunwoo@arm.com } 4117436Sdam.sunwoo@arm.com} 4127436Sdam.sunwoo@arm.com 4137436Sdam.sunwoo@arm.comPixelConverter 4147436Sdam.sunwoo@arm.comHDLcd::pixelConverter() const 4157436Sdam.sunwoo@arm.com{ 4167442Ssaidi@eecs.umich.edu ByteOrder byte_order( 4177436Sdam.sunwoo@arm.com pixel_format.big_endian ? BigEndianByteOrder : LittleEndianByteOrder); 4187436Sdam.sunwoo@arm.com 4197720Sgblack@eecs.umich.edu /* Some Linux kernels have a broken driver that swaps the red and 4207436Sdam.sunwoo@arm.com * blue color select registers. */ 4217436Sdam.sunwoo@arm.com if (!workaroundSwapRB) { 4227436Sdam.sunwoo@arm.com return PixelConverter( 4237436Sdam.sunwoo@arm.com pixel_format.bytes_per_pixel + 1, 4247436Sdam.sunwoo@arm.com red_select.offset, green_select.offset, blue_select.offset, 4257436Sdam.sunwoo@arm.com red_select.size, green_select.size, blue_select.size, 4267436Sdam.sunwoo@arm.com byte_order); 4277436Sdam.sunwoo@arm.com } else { 4287436Sdam.sunwoo@arm.com return PixelConverter( 4297436Sdam.sunwoo@arm.com pixel_format.bytes_per_pixel + 1, 4307436Sdam.sunwoo@arm.com blue_select.offset, green_select.offset, red_select.offset, 4317436Sdam.sunwoo@arm.com blue_select.size, green_select.size, red_select.size, 4327436Sdam.sunwoo@arm.com byte_order); 4337436Sdam.sunwoo@arm.com } 4347436Sdam.sunwoo@arm.com} 4357436Sdam.sunwoo@arm.com 4367436Sdam.sunwoo@arm.comDisplayTimings 4377436Sdam.sunwoo@arm.comHDLcd::displayTimings() const 4387436Sdam.sunwoo@arm.com{ 4397436Sdam.sunwoo@arm.com return DisplayTimings( 4407749SAli.Saidi@ARM.com h_data.val + 1, v_data.val + 1, 4417749SAli.Saidi@ARM.com h_back_porch.val + 1, h_sync.val + 1, h_front_porch.val + 1, 4427749SAli.Saidi@ARM.com v_back_porch.val + 1, v_sync.val + 1, v_front_porch.val + 1); 4437749SAli.Saidi@ARM.com} 4447749SAli.Saidi@ARM.com 4457749SAli.Saidi@ARM.comvoid 4467749SAli.Saidi@ARM.comHDLcd::createDmaEngine() 4477749SAli.Saidi@ARM.com{ 4487405SAli.Saidi@ARM.com if (bus_options.max_outstanding == 0) { 4497405SAli.Saidi@ARM.com warn("Maximum number of outstanding DMA transfers set to 0."); 4507405SAli.Saidi@ARM.com return; 4517405SAli.Saidi@ARM.com } 4527405SAli.Saidi@ARM.com 4537405SAli.Saidi@ARM.com const uint32_t dma_burst_flags(bus_options.burst_len); 454 const uint32_t dma_burst_len( 455 dma_burst_flags ? 456 (1UL << (findMsbSet(dma_burst_flags) - 1)) : 457 MAX_BURST_LEN); 458 // Some drivers seem to set the DMA line count incorrectly. This 459 // could either be a driver bug or a specification bug. Unlike for 460 // timings, the specification does not require 1 to be added to 461 // the DMA engine's line count. 462 const uint32_t dma_lines( 463 fb_line_count + (workaroundDmaLineCount ? 1 : 0)); 464 465 dmaEngine.reset(new DmaEngine( 466 *this, pixelBufferSize, 467 AXI_PORT_WIDTH * dma_burst_len, 468 bus_options.max_outstanding, 469 fb_line_length, fb_line_pitch, dma_lines)); 470} 471 472void 473HDLcd::cmdEnable() 474{ 475 createDmaEngine(); 476 conv = pixelConverter(); 477 pixelPump.start(displayTimings()); 478} 479 480void 481HDLcd::cmdDisable() 482{ 483 pixelPump.stop(); 484 dmaEngine->abortFrame(); 485} 486 487bool 488HDLcd::pxlNext(Pixel &p) 489{ 490 uint8_t pixel_data[MAX_PIXEL_SIZE]; 491 assert(conv.length <= sizeof(pixel_data)); 492 if (dmaEngine->tryGet(pixel_data, conv.length)) { 493 p = conv.toPixel(pixel_data); 494 return true; 495 } else { 496 return false; 497 } 498} 499 500void 501HDLcd::pxlVSyncBegin() 502{ 503 DPRINTF(HDLcd, "Raising VSYNC interrupt.\n"); 504 intRaise(INT_VSYNC); 505} 506 507void 508HDLcd::pxlVSyncEnd() 509{ 510 DPRINTF(HDLcd, "End of VSYNC, starting DMA engine\n"); 511 dmaEngine->startFrame(fb_base); 512} 513 514void 515HDLcd::pxlUnderrun() 516{ 517 DPRINTF(HDLcd, "Buffer underrun, stopping DMA fill.\n"); 518 ++stats.underruns; 519 intRaise(INT_UNDERRUN); 520 dmaEngine->abortFrame(); 521} 522 523void 524HDLcd::pxlFrameDone() 525{ 526 DPRINTF(HDLcd, "Reached end of last visible line.\n"); 527 528 if (dmaEngine->size()) { 529 warn("HDLCD %u bytes still in FIFO after frame: Ensure that DMA " 530 "and PixelPump configuration is consistent\n", 531 dmaEngine->size()); 532 dmaEngine->dumpSettings(); 533 pixelPump.dumpSettings(); 534 } 535 536 if (vnc) 537 vnc->setDirty(); 538 539 if (enableCapture) { 540 if (!pic) { 541 pic = simout.create( 542 csprintf("%s.framebuffer.bmp", sys->name()), 543 true); 544 } 545 546 assert(pic); 547 pic->seekp(0); 548 bmp.write(*pic); 549 } 550} 551 552void 553HDLcd::setInterrupts(uint32_t ints, uint32_t mask) 554{ 555 const bool old_ints(intStatus()); 556 557 int_mask = mask; 558 int_rawstat = ints; 559 560 if (!old_ints && intStatus()) { 561 gic->sendInt(intNum); 562 } else if (old_ints && !intStatus()) { 563 gic->clearInt(intNum); 564 } 565} 566 567HDLcd::DmaEngine::DmaEngine(HDLcd &_parent, size_t size, 568 unsigned request_size, unsigned max_pending, 569 size_t line_size, ssize_t line_pitch, unsigned num_lines) 570 : DmaReadFifo( 571 _parent.dmaPort, size, request_size, max_pending, 572 Request::UNCACHEABLE), 573 parent(_parent), 574 lineSize(line_size), linePitch(line_pitch), numLines(num_lines), 575 nextLineAddr(0) 576{ 577} 578 579void 580HDLcd::DmaEngine::serialize(CheckpointOut &cp) const 581{ 582 DmaReadFifo::serialize(cp); 583 584 SERIALIZE_SCALAR(nextLineAddr); 585 SERIALIZE_SCALAR(frameEnd); 586} 587 588void 589HDLcd::DmaEngine::unserialize(CheckpointIn &cp) 590{ 591 DmaReadFifo::unserialize(cp); 592 593 UNSERIALIZE_SCALAR(nextLineAddr); 594 UNSERIALIZE_SCALAR(frameEnd); 595} 596 597void 598HDLcd::DmaEngine::startFrame(Addr fb_base) 599{ 600 nextLineAddr = fb_base; 601 frameEnd = fb_base + numLines * linePitch; 602 603 startFill(nextLineAddr, lineSize); 604} 605 606void 607HDLcd::DmaEngine::abortFrame() 608{ 609 nextLineAddr = frameEnd; 610 stopFill(); 611 flush(); 612} 613 614 615void 616HDLcd::DmaEngine::dumpSettings() 617{ 618 inform("DMA line size: %u bytes", lineSize); 619 inform("DMA line pitch: %i bytes", linePitch); 620 inform("DMA num lines: %u", numLines); 621} 622 623void 624HDLcd::DmaEngine::onEndOfBlock() 625{ 626 if (nextLineAddr == frameEnd) 627 // We're done with this frame. Ignore calls to this method 628 // until the next frame has been started. 629 return; 630 631 nextLineAddr += linePitch; 632 if (nextLineAddr != frameEnd) 633 startFill(nextLineAddr, lineSize); 634} 635 636void 637HDLcd::DmaEngine::onIdle() 638{ 639 parent.intRaise(INT_DMA_END); 640} 641 642void 643HDLcd::PixelPump::dumpSettings() 644{ 645 const DisplayTimings &t(timings()); 646 647 inform("PixelPump width: %u", t.width); 648 inform("PixelPump height: %u", t.height); 649 650 inform("PixelPump horizontal back porch: %u", t.hBackPorch); 651 inform("PixelPump horizontal fron porch: %u", t.hFrontPorch); 652 inform("PixelPump horizontal fron porch: %u", t.hSync); 653 654 inform("PixelPump vertical back porch: %u", t.vBackPorch); 655 inform("PixelPump vertical fron porch: %u", t.vFrontPorch); 656 inform("PixelPump vertical fron porch: %u", t.vSync); 657} 658 659 660HDLcd * 661HDLcdParams::create() 662{ 663 return new HDLcd(this); 664} 665