hdlcd.cc revision 12086
11060SN/A/* 27944SGiacomo.Gabrielli@arm.com * Copyright (c) 2010-2013, 2015, 2017 ARM Limited 37944SGiacomo.Gabrielli@arm.com * All rights reserved 47944SGiacomo.Gabrielli@arm.com * 57944SGiacomo.Gabrielli@arm.com * The license below extends only to copyright in the software and shall 67944SGiacomo.Gabrielli@arm.com * not be construed as granting a license to any other intellectual 77944SGiacomo.Gabrielli@arm.com * property including but not limited to intellectual property relating 87944SGiacomo.Gabrielli@arm.com * to a hardware implementation of the functionality of the software 97944SGiacomo.Gabrielli@arm.com * licensed hereunder. You may use the software subject to the license 107944SGiacomo.Gabrielli@arm.com * terms below provided that you ensure that this notice is replicated 117944SGiacomo.Gabrielli@arm.com * unmodified and in its entirety in all distributions of the software, 127944SGiacomo.Gabrielli@arm.com * modified or unmodified, in source code or in binary form. 137944SGiacomo.Gabrielli@arm.com * 142702Sktlim@umich.edu * Redistribution and use in source and binary forms, with or without 156973Stjones1@inf.ed.ac.uk * modification, are permitted provided that the following conditions are 161060SN/A * met: redistributions of source code must retain the above copyright 171060SN/A * notice, this list of conditions and the following disclaimer; 181060SN/A * redistributions in binary form must reproduce the above copyright 191060SN/A * notice, this list of conditions and the following disclaimer in the 201060SN/A * documentation and/or other materials provided with the distribution; 211060SN/A * neither the name of the copyright holders nor the names of its 221060SN/A * contributors may be used to endorse or promote products derived from 231060SN/A * this software without specific prior written permission. 241060SN/A * 251060SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 261060SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 271060SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 281060SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 291060SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 301060SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 311060SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 321060SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 331060SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 341060SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 351060SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 361060SN/A * 371060SN/A * Authors: Chris Emmons 381060SN/A * Andreas Sandberg 391060SN/A */ 402665Ssaidi@eecs.umich.edu 412665Ssaidi@eecs.umich.edu#include "dev/arm/hdlcd.hh" 426973Stjones1@inf.ed.ac.uk 431060SN/A#include "base/output.hh" 441060SN/A#include "base/trace.hh" 451464SN/A#include "base/vnc/vncinput.hh" 461464SN/A#include "debug/Checkpoint.hh" 471060SN/A#include "debug/HDLcd.hh" 482731Sktlim@umich.edu#include "dev/arm/amba_device.hh" 492292SN/A#include "dev/arm/base_gic.hh" 501464SN/A#include "mem/packet.hh" 511060SN/A#include "mem/packet_access.hh" 522669Sktlim@umich.edu#include "params/HDLcd.hh" 537720Sgblack@eecs.umich.edu#include "sim/system.hh" 541060SN/A 551060SN/Ausing std::vector; 561858SN/A 576658Snate@binkert.org 583770Sgblack@eecs.umich.edu// initialize hdlcd registers 591464SN/AHDLcd::HDLcd(const HDLcdParams *p) 601464SN/A : AmbaDmaDevice(p, 0xFFFF), 612669Sktlim@umich.edu // Parameters 621060SN/A vnc(p->vnc), 636973Stjones1@inf.ed.ac.uk workaroundSwapRB(p->workaround_swap_rb), 642669Sktlim@umich.edu workaroundDmaLineCount(p->workaround_dma_line_count), 657678Sgblack@eecs.umich.edu addrRanges{RangeSize(pioAddr, pioSize)}, 662292SN/A enableCapture(p->enable_capture), 676023Snate@binkert.org pixelBufferSize(p->pixel_buffer_size), 681060SN/A virtRefreshRate(p->virt_refresh_rate), 691060SN/A 701060SN/A // Registers 711060SN/A version(VERSION_RESETV), 721060SN/A int_rawstat(0), int_mask(0), 731060SN/A 741060SN/A fb_base(0), fb_line_length(0), fb_line_count(0), fb_line_pitch(0), 751061SN/A bus_options(BUS_OPTIONS_RESETV), 761060SN/A 771060SN/A v_sync(0), v_back_porch(0), v_data(0), v_front_porch(0), 781060SN/A h_sync(0), h_back_porch(0), h_data(0), h_front_porch(0), 792733Sktlim@umich.edu polarities(0), 802733Sktlim@umich.edu 811060SN/A command(0), 822292SN/A 832107SN/A pixel_format(0), 842690Sktlim@umich.edu red_select(0), green_select(0), blue_select(0), 852107SN/A 862690Sktlim@umich.edu virtRefreshEvent([this]{ virtRefresh(); }, name()), 872690Sktlim@umich.edu // Other 881060SN/A bmp(&pixelPump.fb), pic(NULL), conv(PixelConverter::rgba8888_le), 892292SN/A pixelPump(*this, *p->pxl_clk, p->pixel_chunk) 902292SN/A{ 918486Sgblack@eecs.umich.edu if (vnc) 922292SN/A vnc->setFrameBuffer(&pixelPump.fb); 932292SN/A} 942292SN/A 952292SN/AHDLcd::~HDLcd() 961060SN/A{ 975543Ssaidi@eecs.umich.edu} 985543Ssaidi@eecs.umich.edu 991060SN/Avoid 1001060SN/AHDLcd::regStats() 1012292SN/A{ 1022107SN/A AmbaDmaDevice::regStats(); 1038502Sgblack@eecs.umich.edu 1041060SN/A using namespace Stats; 1051060SN/A 1061060SN/A stats.underruns 1071060SN/A .name(name() + ".underruns") 1081060SN/A .desc("number of buffer underruns") 1091060SN/A .flags(nozero) 1102292SN/A ; 1111060SN/A} 1121060SN/A 1135358Sgblack@eecs.umich.eduvoid 1145358Sgblack@eecs.umich.eduHDLcd::serialize(CheckpointOut &cp) const 1155358Sgblack@eecs.umich.edu{ 1165358Sgblack@eecs.umich.edu DPRINTF(Checkpoint, "Serializing ARM HDLCD\n"); 1175358Sgblack@eecs.umich.edu 1185358Sgblack@eecs.umich.edu SERIALIZE_SCALAR(int_rawstat); 1195358Sgblack@eecs.umich.edu SERIALIZE_SCALAR(int_mask); 1205358Sgblack@eecs.umich.edu 1215358Sgblack@eecs.umich.edu SERIALIZE_SCALAR(fb_base); 1225358Sgblack@eecs.umich.edu SERIALIZE_SCALAR(fb_line_length); 1235358Sgblack@eecs.umich.edu SERIALIZE_SCALAR(fb_line_count); 1245358Sgblack@eecs.umich.edu SERIALIZE_SCALAR(fb_line_pitch); 1255358Sgblack@eecs.umich.edu SERIALIZE_SCALAR(bus_options); 1268444Sgblack@eecs.umich.edu 1277520Sgblack@eecs.umich.edu SERIALIZE_SCALAR(v_sync); 1288444Sgblack@eecs.umich.edu SERIALIZE_SCALAR(v_back_porch); 1298444Sgblack@eecs.umich.edu SERIALIZE_SCALAR(v_data); 1307520Sgblack@eecs.umich.edu SERIALIZE_SCALAR(v_front_porch); 1316974Stjones1@inf.ed.ac.uk 1326974Stjones1@inf.ed.ac.uk SERIALIZE_SCALAR(h_sync); 1336974Stjones1@inf.ed.ac.uk SERIALIZE_SCALAR(h_back_porch); 1346974Stjones1@inf.ed.ac.uk SERIALIZE_SCALAR(h_data); 1356973Stjones1@inf.ed.ac.uk SERIALIZE_SCALAR(h_front_porch); 1366974Stjones1@inf.ed.ac.uk 1376974Stjones1@inf.ed.ac.uk SERIALIZE_SCALAR(polarities); 1386973Stjones1@inf.ed.ac.uk 1396973Stjones1@inf.ed.ac.uk SERIALIZE_SCALAR(command); 1406973Stjones1@inf.ed.ac.uk SERIALIZE_SCALAR(pixel_format); 1416973Stjones1@inf.ed.ac.uk SERIALIZE_SCALAR(red_select); 1421060SN/A SERIALIZE_SCALAR(green_select); 1437944SGiacomo.Gabrielli@arm.com SERIALIZE_SCALAR(blue_select); 1447944SGiacomo.Gabrielli@arm.com 1457944SGiacomo.Gabrielli@arm.com SERIALIZE_OBJ(pixelPump); 1467944SGiacomo.Gabrielli@arm.com if (enabled()) 1477944SGiacomo.Gabrielli@arm.com dmaEngine->serializeSection(cp, "dmaEngine"); 1487944SGiacomo.Gabrielli@arm.com} 1498545Ssaidi@eecs.umich.edu 1508545Ssaidi@eecs.umich.eduvoid 1518545Ssaidi@eecs.umich.eduHDLcd::unserialize(CheckpointIn &cp) 1528545Ssaidi@eecs.umich.edu{ 1538545Ssaidi@eecs.umich.edu DPRINTF(Checkpoint, "Unserializing ARM HDLCD\n"); 1548545Ssaidi@eecs.umich.edu 1558545Ssaidi@eecs.umich.edu UNSERIALIZE_SCALAR(int_rawstat); 1568545Ssaidi@eecs.umich.edu UNSERIALIZE_SCALAR(int_mask); 1578545Ssaidi@eecs.umich.edu 1588545Ssaidi@eecs.umich.edu UNSERIALIZE_SCALAR(fb_base); 1598545Ssaidi@eecs.umich.edu UNSERIALIZE_SCALAR(fb_line_length); 1608545Ssaidi@eecs.umich.edu UNSERIALIZE_SCALAR(fb_line_count); 1618545Ssaidi@eecs.umich.edu UNSERIALIZE_SCALAR(fb_line_pitch); 1627944SGiacomo.Gabrielli@arm.com UNSERIALIZE_SCALAR(bus_options); 1637944SGiacomo.Gabrielli@arm.com 1647944SGiacomo.Gabrielli@arm.com UNSERIALIZE_SCALAR(v_sync); 1657944SGiacomo.Gabrielli@arm.com UNSERIALIZE_SCALAR(v_back_porch); 1667944SGiacomo.Gabrielli@arm.com UNSERIALIZE_SCALAR(v_data); 1677944SGiacomo.Gabrielli@arm.com UNSERIALIZE_SCALAR(v_front_porch); 1687944SGiacomo.Gabrielli@arm.com 1697944SGiacomo.Gabrielli@arm.com UNSERIALIZE_SCALAR(h_sync); 1707944SGiacomo.Gabrielli@arm.com UNSERIALIZE_SCALAR(h_back_porch); 1717944SGiacomo.Gabrielli@arm.com UNSERIALIZE_SCALAR(h_data); 1727944SGiacomo.Gabrielli@arm.com UNSERIALIZE_SCALAR(h_front_porch); 1737944SGiacomo.Gabrielli@arm.com 1747944SGiacomo.Gabrielli@arm.com UNSERIALIZE_SCALAR(polarities); 1757944SGiacomo.Gabrielli@arm.com 1767944SGiacomo.Gabrielli@arm.com UNSERIALIZE_SCALAR(command); 1777944SGiacomo.Gabrielli@arm.com UNSERIALIZE_SCALAR(pixel_format); 1787944SGiacomo.Gabrielli@arm.com UNSERIALIZE_SCALAR(red_select); 1791684SN/A UNSERIALIZE_SCALAR(green_select); 1801060SN/A UNSERIALIZE_SCALAR(blue_select); 1811060SN/A 1821060SN/A { 1831060SN/A // Try to unserialize the pixel pump. It might not exist if 1842731Sktlim@umich.edu // we're unserializing an old checkpoint. 1852731Sktlim@umich.edu ScopedCheckpointSection sec(cp, "pixelPump"); 1862731Sktlim@umich.edu if (cp.sectionExists(Serializable::currentSection())) 1872731Sktlim@umich.edu pixelPump.unserialize(cp); 1882731Sktlim@umich.edu } 1892731Sktlim@umich.edu 1902731Sktlim@umich.edu if (enabled()) { 1912731Sktlim@umich.edu // Create the DMA engine and read its state from the 1922731Sktlim@umich.edu // checkpoint. We don't need to worry about the pixel pump as 1932731Sktlim@umich.edu // it is a proper SimObject. 1942731Sktlim@umich.edu createDmaEngine(); 1952731Sktlim@umich.edu dmaEngine->unserializeSection(cp, "dmaEngine"); 1962731Sktlim@umich.edu 1972731Sktlim@umich.edu conv = pixelConverter(); 1982731Sktlim@umich.edu } 1992731Sktlim@umich.edu} 2002731Sktlim@umich.edu 2012731Sktlim@umich.eduvoid 2022731Sktlim@umich.eduHDLcd::drainResume() 2032731Sktlim@umich.edu{ 2042731Sktlim@umich.edu AmbaDmaDevice::drainResume(); 2052731Sktlim@umich.edu 2062731Sktlim@umich.edu if (enabled()) { 2072731Sktlim@umich.edu if (sys->bypassCaches()) { 2082731Sktlim@umich.edu // We restart the HDLCD if we are in KVM mode. This 2092292SN/A // ensures that we always use the fast refresh logic if we 2102731Sktlim@umich.edu // resume in KVM mode. 2112731Sktlim@umich.edu cmdDisable(); 2121060SN/A cmdEnable(); 2131060SN/A } else if (!pixelPump.active()) { 2146221Snate@binkert.org // We restored from an old checkpoint without a pixel 2151060SN/A // pump, start an new refresh. This typically happens when 2161060SN/A // restoring from old checkpoints. 2171060SN/A cmdEnable(); 2181060SN/A } 2192292SN/A } 2202292SN/A 2212292SN/A // We restored from a checkpoint and need to update the VNC server 2222733Sktlim@umich.edu if (pixelPump.active() && vnc) 2232733Sktlim@umich.edu vnc->setDirty(); 2241060SN/A} 2252680Sktlim@umich.edu 2262292SN/Avoid 2271060SN/AHDLcd::virtRefresh() 2281060SN/A{ 2292132SN/A pixelPump.renderFrame(); 2301060SN/A schedule(virtRefreshEvent, (curTick() + virtRefreshRate)); 2312702Sktlim@umich.edu} 2322669Sktlim@umich.edu 2332292SN/A// read registers and frame buffer 2341060SN/ATick 2351060SN/AHDLcd::read(PacketPtr pkt) 2361060SN/A{ 2378199SAli.Saidi@ARM.com assert(pkt->getAddr() >= pioAddr && 2388199SAli.Saidi@ARM.com pkt->getAddr() < pioAddr + pioSize); 2398199SAli.Saidi@ARM.com 2404032Sktlim@umich.edu const Addr daddr(pkt->getAddr() - pioAddr); 2414032Sktlim@umich.edu panic_if(pkt->getSize() != 4, 2424032Sktlim@umich.edu "Unhandled read size (address: 0x.4x, size: %u)", 2431060SN/A daddr, pkt->getSize()); 2441060SN/A 2451060SN/A const uint32_t data(readReg(daddr)); 2461060SN/A DPRINTF(HDLcd, "read register 0x%04x: 0x%x\n", daddr, data); 2471060SN/A 2481060SN/A pkt->set<uint32_t>(data); 2491464SN/A pkt->makeAtomicResponse(); 2501464SN/A return pioDelay; 2512356SN/A} 2521464SN/A 2531464SN/A// write registers and frame buffer 2541060SN/ATick 2551464SN/AHDLcd::write(PacketPtr pkt) 2561464SN/A{ 2571464SN/A assert(pkt->getAddr() >= pioAddr && 2581464SN/A pkt->getAddr() < pioAddr + pioSize); 2591060SN/A 2603326Sktlim@umich.edu const Addr daddr(pkt->getAddr() - pioAddr); 2613326Sktlim@umich.edu panic_if(pkt->getSize() != 4, 2623326Sktlim@umich.edu "Unhandled read size (address: 0x.4x, size: %u)", 2637597Sminkyu.jeong@arm.com daddr, pkt->getSize()); 2647597Sminkyu.jeong@arm.com const uint32_t data(pkt->get<uint32_t>()); 2657597Sminkyu.jeong@arm.com DPRINTF(HDLcd, "write register 0x%04x: 0x%x\n", daddr, data); 2663965Sgblack@eecs.umich.edu 2677720Sgblack@eecs.umich.edu writeReg(daddr, data); 2687720Sgblack@eecs.umich.edu 2691060SN/A pkt->makeAtomicResponse(); 2707720Sgblack@eecs.umich.edu return pioDelay; 2717720Sgblack@eecs.umich.edu} 2724636Sgblack@eecs.umich.edu 2733794Sgblack@eecs.umich.eduuint32_t 2743794Sgblack@eecs.umich.eduHDLcd::readReg(Addr offset) 2753794Sgblack@eecs.umich.edu{ 2763965Sgblack@eecs.umich.edu switch (offset) { 2773965Sgblack@eecs.umich.edu case Version: return version; 2782292SN/A 2792292SN/A case Int_RawStat: return int_rawstat; 2802292SN/A case Int_Clear: 2812292SN/A panic("HDLCD INT_CLEAR register is Write-Only\n"); 2822292SN/A case Int_Mask: return int_mask; 2832292SN/A case Int_Status: return intStatus(); 2841060SN/A 2851060SN/A case Fb_Base: return fb_base; 2861060SN/A case Fb_Line_Length: return fb_line_length; 2873770Sgblack@eecs.umich.edu case Fb_Line_Count: return fb_line_count; 2883770Sgblack@eecs.umich.edu case Fb_Line_Pitch: return fb_line_pitch; 2893770Sgblack@eecs.umich.edu case Bus_Options: return bus_options; 2903770Sgblack@eecs.umich.edu 2913770Sgblack@eecs.umich.edu case V_Sync: return v_sync; 2923770Sgblack@eecs.umich.edu case V_Back_Porch: return v_back_porch; 2933770Sgblack@eecs.umich.edu case V_Data: return v_data; 2943770Sgblack@eecs.umich.edu case V_Front_Porch: return v_front_porch; 2953770Sgblack@eecs.umich.edu case H_Sync: return h_sync; 2963770Sgblack@eecs.umich.edu case H_Back_Porch: return h_back_porch; 2973770Sgblack@eecs.umich.edu case H_Data: return h_data; 2983770Sgblack@eecs.umich.edu case H_Front_Porch: return h_front_porch; 2993770Sgblack@eecs.umich.edu case Polarities: return polarities; 3003770Sgblack@eecs.umich.edu 3013770Sgblack@eecs.umich.edu case Command: return command; 3023770Sgblack@eecs.umich.edu case Pixel_Format: return pixel_format; 3033770Sgblack@eecs.umich.edu case Red_Select: return red_select; 3043770Sgblack@eecs.umich.edu case Green_Select: return green_select; 3053770Sgblack@eecs.umich.edu case Blue_Select: return blue_select; 3063770Sgblack@eecs.umich.edu 3073770Sgblack@eecs.umich.edu default: 3083770Sgblack@eecs.umich.edu panic("Tried to read HDLCD register that doesn't exist\n", offset); 3093770Sgblack@eecs.umich.edu } 3103770Sgblack@eecs.umich.edu} 3113770Sgblack@eecs.umich.edu 3123770Sgblack@eecs.umich.eduvoid 3131060SN/AHDLcd::writeReg(Addr offset, uint32_t value) 3143770Sgblack@eecs.umich.edu{ 3153770Sgblack@eecs.umich.edu switch (offset) { 3163770Sgblack@eecs.umich.edu case Version: 3173770Sgblack@eecs.umich.edu panic("HDLCD VERSION register is read-Only\n"); 3183770Sgblack@eecs.umich.edu 3193770Sgblack@eecs.umich.edu case Int_RawStat: 3203770Sgblack@eecs.umich.edu intRaise(value); 3213770Sgblack@eecs.umich.edu return; 3223770Sgblack@eecs.umich.edu case Int_Clear: 3233770Sgblack@eecs.umich.edu intClear(value); 3243770Sgblack@eecs.umich.edu return; 3253770Sgblack@eecs.umich.edu case Int_Mask: 3263770Sgblack@eecs.umich.edu intMask(value); 3273770Sgblack@eecs.umich.edu return; 3283770Sgblack@eecs.umich.edu case Int_Status: 3293770Sgblack@eecs.umich.edu panic("HDLCD INT_STATUS register is read-Only\n"); 3303770Sgblack@eecs.umich.edu break; 3313770Sgblack@eecs.umich.edu 3323770Sgblack@eecs.umich.edu case Fb_Base: 3333770Sgblack@eecs.umich.edu fb_base = value; 3343770Sgblack@eecs.umich.edu return; 3353770Sgblack@eecs.umich.edu 3363770Sgblack@eecs.umich.edu case Fb_Line_Length: 3373770Sgblack@eecs.umich.edu fb_line_length = value; 3383770Sgblack@eecs.umich.edu return; 3393770Sgblack@eecs.umich.edu 3403770Sgblack@eecs.umich.edu case Fb_Line_Count: 3413770Sgblack@eecs.umich.edu fb_line_count = value; 3423770Sgblack@eecs.umich.edu return; 3433770Sgblack@eecs.umich.edu 3443770Sgblack@eecs.umich.edu case Fb_Line_Pitch: 3453770Sgblack@eecs.umich.edu fb_line_pitch = value; 3463770Sgblack@eecs.umich.edu return; 3473770Sgblack@eecs.umich.edu 3483770Sgblack@eecs.umich.edu case Bus_Options: { 3493770Sgblack@eecs.umich.edu const BusOptsReg old_bus_options(bus_options); 3503770Sgblack@eecs.umich.edu bus_options = value; 3513770Sgblack@eecs.umich.edu 3523770Sgblack@eecs.umich.edu if (bus_options.max_outstanding != old_bus_options.max_outstanding) { 3533770Sgblack@eecs.umich.edu DPRINTF(HDLcd, 3543770Sgblack@eecs.umich.edu "Changing HDLcd outstanding DMA transactions: %d -> %d\n", 3553770Sgblack@eecs.umich.edu old_bus_options.max_outstanding, 3563770Sgblack@eecs.umich.edu bus_options.max_outstanding); 3573770Sgblack@eecs.umich.edu 3583770Sgblack@eecs.umich.edu } 3593770Sgblack@eecs.umich.edu 3603770Sgblack@eecs.umich.edu if (bus_options.burst_len != old_bus_options.burst_len) { 3613770Sgblack@eecs.umich.edu DPRINTF(HDLcd, 3623770Sgblack@eecs.umich.edu "Changing HDLcd DMA burst flags: 0x%x -> 0x%x\n", 3633770Sgblack@eecs.umich.edu old_bus_options.burst_len, bus_options.burst_len); 3643770Sgblack@eecs.umich.edu } 3653770Sgblack@eecs.umich.edu } return; 3663770Sgblack@eecs.umich.edu 3673770Sgblack@eecs.umich.edu case V_Sync: 3683770Sgblack@eecs.umich.edu v_sync = value; 3693770Sgblack@eecs.umich.edu return; 3703770Sgblack@eecs.umich.edu case V_Back_Porch: 3713770Sgblack@eecs.umich.edu v_back_porch = value; 3723770Sgblack@eecs.umich.edu return; 3733770Sgblack@eecs.umich.edu case V_Data: 3743770Sgblack@eecs.umich.edu v_data = value; 3753770Sgblack@eecs.umich.edu return; 3763770Sgblack@eecs.umich.edu case V_Front_Porch: 3773770Sgblack@eecs.umich.edu v_front_porch = value; 3783770Sgblack@eecs.umich.edu return; 3793770Sgblack@eecs.umich.edu 3803770Sgblack@eecs.umich.edu case H_Sync: 3813770Sgblack@eecs.umich.edu h_sync = value; 3823770Sgblack@eecs.umich.edu return; 3833770Sgblack@eecs.umich.edu case H_Back_Porch: 3843770Sgblack@eecs.umich.edu h_back_porch = value; 3854636Sgblack@eecs.umich.edu return; 3864636Sgblack@eecs.umich.edu case H_Data: 3877720Sgblack@eecs.umich.edu h_data = value; 3887720Sgblack@eecs.umich.edu return; 3894636Sgblack@eecs.umich.edu case H_Front_Porch: 3904636Sgblack@eecs.umich.edu h_front_porch = value; 3914636Sgblack@eecs.umich.edu return; 3928502Sgblack@eecs.umich.edu 3938502Sgblack@eecs.umich.edu case Polarities: 3948502Sgblack@eecs.umich.edu polarities = value; 3953770Sgblack@eecs.umich.edu return; 3962292SN/A 3972292SN/A case Command: { 3982292SN/A const CommandReg new_command(value); 3998502Sgblack@eecs.umich.edu 4001060SN/A if (new_command.enable != command.enable) { 4011060SN/A DPRINTF(HDLcd, "HDLCD switched %s\n", 4021060SN/A new_command.enable ? "on" : "off"); 4031060SN/A 4041464SN/A if (new_command.enable) { 4051684SN/A cmdEnable(); 4061464SN/A } else { 4071060SN/A cmdDisable(); 4081464SN/A } 4091060SN/A } 4101060SN/A command = new_command; 4111060SN/A } return; 4121060SN/A 4131060SN/A case Pixel_Format: 4141060SN/A pixel_format = value; 4153326Sktlim@umich.edu return; 4165712Shsul@eecs.umich.edu 4173326Sktlim@umich.edu case Red_Select: 4185714Shsul@eecs.umich.edu red_select = value; 4195714Shsul@eecs.umich.edu return; 4205714Shsul@eecs.umich.edu case Green_Select: 4211060SN/A green_select = value; 4222132SN/A return; 4231060SN/A case Blue_Select: 4241060SN/A blue_select = value; 4251060SN/A return; 4261060SN/A 4272292SN/A default: 4281060SN/A panic("Tried to write HDLCD register that doesn't exist\n", offset); 4291060SN/A return; 4301060SN/A } 4317720Sgblack@eecs.umich.edu} 4327720Sgblack@eecs.umich.edu 4333965Sgblack@eecs.umich.eduPixelConverter 4347720Sgblack@eecs.umich.eduHDLcd::pixelConverter() const 4353965Sgblack@eecs.umich.edu{ 4362935Sksewell@umich.edu ByteOrder byte_order( 4377720Sgblack@eecs.umich.edu pixel_format.big_endian ? BigEndianByteOrder : LittleEndianByteOrder); 4381060SN/A 4393794Sgblack@eecs.umich.edu /* Some Linux kernels have a broken driver that swaps the red and 4407720Sgblack@eecs.umich.edu * blue color select registers. */ 4413794Sgblack@eecs.umich.edu if (!workaroundSwapRB) { 4423794Sgblack@eecs.umich.edu return PixelConverter( 4437720Sgblack@eecs.umich.edu pixel_format.bytes_per_pixel + 1, 4441060SN/A red_select.offset, green_select.offset, blue_select.offset, 4454636Sgblack@eecs.umich.edu red_select.size, green_select.size, blue_select.size, 4467720Sgblack@eecs.umich.edu byte_order); 4474636Sgblack@eecs.umich.edu } else { 4481060SN/A return PixelConverter( 4493794Sgblack@eecs.umich.edu pixel_format.bytes_per_pixel + 1, 4503794Sgblack@eecs.umich.edu blue_select.offset, green_select.offset, red_select.offset, 4513794Sgblack@eecs.umich.edu blue_select.size, green_select.size, red_select.size, 4523794Sgblack@eecs.umich.edu byte_order); 4533794Sgblack@eecs.umich.edu } 4543794Sgblack@eecs.umich.edu} 4553794Sgblack@eecs.umich.edu 4563794Sgblack@eecs.umich.eduDisplayTimings 4573794Sgblack@eecs.umich.eduHDLcd::displayTimings() const 4581060SN/A{ 4591060SN/A return DisplayTimings( 4602935Sksewell@umich.edu h_data.val + 1, v_data.val + 1, 4613794Sgblack@eecs.umich.edu h_back_porch.val + 1, h_sync.val + 1, h_front_porch.val + 1, 4627720Sgblack@eecs.umich.edu v_back_porch.val + 1, v_sync.val + 1, v_front_porch.val + 1); 4637720Sgblack@eecs.umich.edu} 4647720Sgblack@eecs.umich.edu 4653794Sgblack@eecs.umich.eduvoid 4663794Sgblack@eecs.umich.eduHDLcd::createDmaEngine() 4671060SN/A{ 4681060SN/A if (bus_options.max_outstanding == 0) { 4691060SN/A warn("Maximum number of outstanding DMA transfers set to 0."); 4705543Ssaidi@eecs.umich.edu return; 4715543Ssaidi@eecs.umich.edu } 4725543Ssaidi@eecs.umich.edu 4735543Ssaidi@eecs.umich.edu const uint32_t dma_burst_flags(bus_options.burst_len); 4742336SN/A const uint32_t dma_burst_len( 4752336SN/A dma_burst_flags ? 4761060SN/A (1UL << (findMsbSet(dma_burst_flags) - 1)) : 4771060SN/A MAX_BURST_LEN); 4785543Ssaidi@eecs.umich.edu // Some drivers seem to set the DMA line count incorrectly. This 4795543Ssaidi@eecs.umich.edu // could either be a driver bug or a specification bug. Unlike for 4805543Ssaidi@eecs.umich.edu // timings, the specification does not require 1 to be added to 4815543Ssaidi@eecs.umich.edu // the DMA engine's line count. 4825543Ssaidi@eecs.umich.edu const uint32_t dma_lines( 4835543Ssaidi@eecs.umich.edu fb_line_count + (workaroundDmaLineCount ? 1 : 0)); 4841060SN/A 4855543Ssaidi@eecs.umich.edu dmaEngine.reset(new DmaEngine( 4865543Ssaidi@eecs.umich.edu *this, pixelBufferSize, 4872935Sksewell@umich.edu AXI_PORT_WIDTH * dma_burst_len, 4881060SN/A bus_options.max_outstanding, 4891060SN/A fb_line_length, fb_line_pitch, dma_lines)); 4902292SN/A} 4912731Sktlim@umich.edu 4922292SN/Avoid 4932731Sktlim@umich.eduHDLcd::cmdEnable() 4947784SAli.Saidi@ARM.com{ 4951060SN/A createDmaEngine(); 4961060SN/A conv = pixelConverter(); 4971060SN/A 4982292SN/A // Update timing parameter before rendering frames 4992336SN/A pixelPump.updateTimings(displayTimings()); 5002308SN/A 5014828Sgblack@eecs.umich.edu if (sys->bypassCaches()) { 5024654Sgblack@eecs.umich.edu schedule(virtRefreshEvent, clockEdge()); 5034654Sgblack@eecs.umich.edu } else { 5044636Sgblack@eecs.umich.edu pixelPump.start(); 5054654Sgblack@eecs.umich.edu } 5064654Sgblack@eecs.umich.edu} 5074636Sgblack@eecs.umich.edu 5082292SN/Avoid 5092292SN/AHDLcd::cmdDisable() 5102731Sktlim@umich.edu{ 5112292SN/A pixelPump.stop(); 5122292SN/A // Disable the virtual refresh event 5132731Sktlim@umich.edu if (virtRefreshEvent.scheduled()) { 5142292SN/A assert(sys->bypassCaches()); 5152292SN/A deschedule(virtRefreshEvent); 5162731Sktlim@umich.edu } 5172292SN/A dmaEngine->abortFrame(); 5182292SN/A} 5192731Sktlim@umich.edu 5202292SN/Abool 5212292SN/AHDLcd::pxlNext(Pixel &p) 5222731Sktlim@umich.edu{ 5232292SN/A uint8_t pixel_data[MAX_PIXEL_SIZE]; 5242292SN/A assert(conv.length <= sizeof(pixel_data)); 5252731Sktlim@umich.edu if (dmaEngine->tryGet(pixel_data, conv.length)) { 5262292SN/A p = conv.toPixel(pixel_data); 5272731Sktlim@umich.edu return true; 5282731Sktlim@umich.edu } else { 5292292SN/A return false; 5302292SN/A } 5312292SN/A} 5322292SN/A 5332292SN/Avoid 5342292SN/AHDLcd::pxlVSyncBegin() 5352731Sktlim@umich.edu{ 5361060SN/A DPRINTF(HDLcd, "Raising VSYNC interrupt.\n"); 5371464SN/A intRaise(INT_VSYNC); 5381464SN/A} 5391464SN/A 5401464SN/Avoid 5417720Sgblack@eecs.umich.eduHDLcd::pxlVSyncEnd() 5427720Sgblack@eecs.umich.edu{ 5431464SN/A DPRINTF(HDLcd, "End of VSYNC, starting DMA engine\n"); 5442292SN/A dmaEngine->startFrame(fb_base); 5455543Ssaidi@eecs.umich.edu} 5461684SN/A 5472292SN/Avoid 5481060SN/AHDLcd::pxlUnderrun() 5491060SN/A{ 5501060SN/A DPRINTF(HDLcd, "Buffer underrun, stopping DMA fill.\n"); 5511060SN/A ++stats.underruns; 5521060SN/A intRaise(INT_UNDERRUN); 5531060SN/A dmaEngine->abortFrame(); 5541060SN/A} 5551060SN/A 5562292SN/Avoid 5571060SN/AHDLcd::pxlFrameDone() 5581060SN/A{ 5592292SN/A DPRINTF(HDLcd, "Reached end of last visible line.\n"); 5601060SN/A 5611684SN/A if (dmaEngine->size()) { 5621464SN/A warn("HDLCD %u bytes still in FIFO after frame: Ensure that DMA " 5631684SN/A "and PixelPump configuration is consistent\n", 5641684SN/A dmaEngine->size()); 5652356SN/A dmaEngine->dumpSettings(); 5661684SN/A pixelPump.dumpSettings(); 5671684SN/A } 5681464SN/A 5691060SN/A if (vnc) 5702702Sktlim@umich.edu vnc->setDirty(); 5713735Sstever@eecs.umich.edu 5721060SN/A if (enableCapture) { 5733326Sktlim@umich.edu if (!pic) { 5743326Sktlim@umich.edu pic = simout.create( 5751060SN/A csprintf("%s.framebuffer.bmp", sys->name()), 5761060SN/A true); 5772702Sktlim@umich.edu } 5783735Sstever@eecs.umich.edu 5793735Sstever@eecs.umich.edu assert(pic); 5802690Sktlim@umich.edu pic->stream()->seekp(0); 5813326Sktlim@umich.edu bmp.write(*pic->stream()); 5823326Sktlim@umich.edu } 5833326Sktlim@umich.edu} 5843326Sktlim@umich.edu 5853326Sktlim@umich.eduvoid 5863326Sktlim@umich.eduHDLcd::setInterrupts(uint32_t ints, uint32_t mask) 5873326Sktlim@umich.edu{ 5883326Sktlim@umich.edu const bool old_ints(intStatus()); 5892690Sktlim@umich.edu 5902690Sktlim@umich.edu int_mask = mask; 5912702Sktlim@umich.edu int_rawstat = ints; 5923735Sstever@eecs.umich.edu 5931060SN/A if (!old_ints && intStatus()) { 5943326Sktlim@umich.edu gic->sendInt(intNum); 5953326Sktlim@umich.edu } else if (old_ints && !intStatus()) { 5962308SN/A gic->clearInt(intNum); 5971060SN/A } 5982702Sktlim@umich.edu} 5993735Sstever@eecs.umich.edu 6003735Sstever@eecs.umich.eduHDLcd::DmaEngine::DmaEngine(HDLcd &_parent, size_t size, 6012308SN/A unsigned request_size, unsigned max_pending, 6023326Sktlim@umich.edu size_t line_size, ssize_t line_pitch, unsigned num_lines) 6033326Sktlim@umich.edu : DmaReadFifo( 6042308SN/A _parent.dmaPort, size, request_size, max_pending, 6051060SN/A Request::UNCACHEABLE), 6062702Sktlim@umich.edu parent(_parent), 6073735Sstever@eecs.umich.edu lineSize(line_size), linePitch(line_pitch), numLines(num_lines), 6082308SN/A nextLineAddr(0) 6093326Sktlim@umich.edu{ 6103326Sktlim@umich.edu} 6111060SN/A 6121060SN/Avoid 6132190SN/AHDLcd::DmaEngine::serialize(CheckpointOut &cp) const 6142292SN/A{ 6152190SN/A DmaReadFifo::serialize(cp); 6162331SN/A 6172292SN/A SERIALIZE_SCALAR(nextLineAddr); 6182190SN/A SERIALIZE_SCALAR(frameEnd); 6191684SN/A} 6201464SN/A 6211464SN/Avoid 6221464SN/AHDLcd::DmaEngine::unserialize(CheckpointIn &cp) 6231464SN/A{ 6241464SN/A DmaReadFifo::unserialize(cp); 6251684SN/A 6262731Sktlim@umich.edu UNSERIALIZE_SCALAR(nextLineAddr); 6271464SN/A UNSERIALIZE_SCALAR(frameEnd); 6282292SN/A} 6292731Sktlim@umich.edu 6301464SN/Avoid 6312731Sktlim@umich.eduHDLcd::DmaEngine::startFrame(Addr fb_base) 6322731Sktlim@umich.edu{ 6332308SN/A nextLineAddr = fb_base; 6342731Sktlim@umich.edu frameEnd = fb_base + numLines * linePitch; 6352731Sktlim@umich.edu 6362308SN/A startFill(nextLineAddr, lineSize); 6371060SN/A} 6382731Sktlim@umich.edu 6391060SN/Avoid 6401060SN/AHDLcd::DmaEngine::abortFrame() 6412731Sktlim@umich.edu{ 6421060SN/A nextLineAddr = frameEnd; 6434032Sktlim@umich.edu stopFill(); 6444032Sktlim@umich.edu flush(); 6454032Sktlim@umich.edu} 6461060SN/A 6472731Sktlim@umich.edu 6481060SN/Avoid 6491060SN/AHDLcd::DmaEngine::dumpSettings() 6502731Sktlim@umich.edu{ 6511060SN/A inform("DMA line size: %u bytes", lineSize); 6524032Sktlim@umich.edu inform("DMA line pitch: %i bytes", linePitch); 6534032Sktlim@umich.edu inform("DMA num lines: %u", numLines); 6544032Sktlim@umich.edu} 6551060SN/A 6562731Sktlim@umich.eduvoid 6571060SN/AHDLcd::DmaEngine::onEndOfBlock() 6581060SN/A{ 6592731Sktlim@umich.edu if (nextLineAddr == frameEnd) 6601060SN/A // We're done with this frame. Ignore calls to this method 6611060SN/A // until the next frame has been started. 6622731Sktlim@umich.edu return; 6631060SN/A 6641061SN/A nextLineAddr += linePitch; 6652731Sktlim@umich.edu if (nextLineAddr != frameEnd) 6661061SN/A startFill(nextLineAddr, lineSize); 6671060SN/A} 6682731Sktlim@umich.edu 6692731Sktlim@umich.eduvoid 6702731Sktlim@umich.eduHDLcd::DmaEngine::onIdle() 6712731Sktlim@umich.edu{ 6722731Sktlim@umich.edu parent.intRaise(INT_DMA_END); 6731060SN/A} 6742292SN/A 6752731Sktlim@umich.eduvoid 6762292SN/AHDLcd::PixelPump::dumpSettings() 6772292SN/A{ 6782731Sktlim@umich.edu const DisplayTimings &t(timings()); 6792292SN/A 6801060SN/A inform("PixelPump width: %u", t.width); 6812731Sktlim@umich.edu inform("PixelPump height: %u", t.height); 6821060SN/A 6831060SN/A inform("PixelPump horizontal back porch: %u", t.hBackPorch); 6842731Sktlim@umich.edu inform("PixelPump horizontal fron porch: %u", t.hFrontPorch); 6851060SN/A inform("PixelPump horizontal fron porch: %u", t.hSync); 6862292SN/A 6872292SN/A inform("PixelPump vertical back porch: %u", t.vBackPorch); 6882292SN/A inform("PixelPump vertical fron porch: %u", t.vFrontPorch); 6892731Sktlim@umich.edu inform("PixelPump vertical fron porch: %u", t.vSync); 6902292SN/A} 6912292SN/A 6922731Sktlim@umich.edu 6932731Sktlim@umich.eduHDLcd * 6942731Sktlim@umich.eduHDLcdParams::create() 6952731Sktlim@umich.edu{ 6962292SN/A return new HDLcd(this); 6971060SN/A} 6982731Sktlim@umich.edu