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