hdlcd.cc revision 12086:069c529a76fd
11060SN/A/*
22702Sktlim@umich.edu * Copyright (c) 2010-2013, 2015, 2017 ARM Limited
36973Stjones1@inf.ed.ac.uk * All rights reserved
41060SN/A *
51060SN/A * The license below extends only to copyright in the software and shall
61060SN/A * not be construed as granting a license to any other intellectual
71060SN/A * property including but not limited to intellectual property relating
81060SN/A * to a hardware implementation of the functionality of the software
91060SN/A * licensed hereunder.  You may use the software subject to the license
101060SN/A * terms below provided that you ensure that this notice is replicated
111060SN/A * unmodified and in its entirety in all distributions of the software,
121060SN/A * modified or unmodified, in source code or in binary form.
131060SN/A *
141060SN/A * Redistribution and use in source and binary forms, with or without
151060SN/A * 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
282665Ssaidi@eecs.umich.edu * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
292665Ssaidi@eecs.umich.edu * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
306973Stjones1@inf.ed.ac.uk * 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
331464SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
341464SN/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.
362731Sktlim@umich.edu *
372292SN/A * Authors: Chris Emmons
381464SN/A *          Andreas Sandberg
391060SN/A */
402669Sktlim@umich.edu
417720Sgblack@eecs.umich.edu#include "dev/arm/hdlcd.hh"
421060SN/A
431060SN/A#include "base/output.hh"
441858SN/A#include "base/trace.hh"
456658Snate@binkert.org#include "base/vnc/vncinput.hh"
463770Sgblack@eecs.umich.edu#include "debug/Checkpoint.hh"
471464SN/A#include "debug/HDLcd.hh"
481464SN/A#include "dev/arm/amba_device.hh"
492669Sktlim@umich.edu#include "dev/arm/base_gic.hh"
501060SN/A#include "mem/packet.hh"
516973Stjones1@inf.ed.ac.uk#include "mem/packet_access.hh"
522669Sktlim@umich.edu#include "params/HDLcd.hh"
537678Sgblack@eecs.umich.edu#include "sim/system.hh"
542292SN/A
556023Snate@binkert.orgusing std::vector;
561060SN/A
571060SN/A
581060SN/A// initialize hdlcd registers
591060SN/AHDLcd::HDLcd(const HDLcdParams *p)
601060SN/A    : AmbaDmaDevice(p, 0xFFFF),
611060SN/A      // Parameters
621061SN/A      vnc(p->vnc),
631061SN/A      workaroundSwapRB(p->workaround_swap_rb),
641060SN/A      workaroundDmaLineCount(p->workaround_dma_line_count),
651060SN/A      addrRanges{RangeSize(pioAddr, pioSize)},
661061SN/A      enableCapture(p->enable_capture),
671060SN/A      pixelBufferSize(p->pixel_buffer_size),
681060SN/A      virtRefreshRate(p->virt_refresh_rate),
691060SN/A
702733Sktlim@umich.edu      // Registers
712733Sktlim@umich.edu      version(VERSION_RESETV),
721060SN/A      int_rawstat(0), int_mask(0),
732292SN/A
742107SN/A      fb_base(0), fb_line_length(0), fb_line_count(0), fb_line_pitch(0),
752690Sktlim@umich.edu      bus_options(BUS_OPTIONS_RESETV),
762107SN/A
772690Sktlim@umich.edu      v_sync(0), v_back_porch(0), v_data(0), v_front_porch(0),
782690Sktlim@umich.edu      h_sync(0), h_back_porch(0), h_data(0), h_front_porch(0),
791060SN/A      polarities(0),
802292SN/A
812292SN/A      command(0),
822292SN/A
832292SN/A      pixel_format(0),
842292SN/A      red_select(0), green_select(0), blue_select(0),
852292SN/A
861060SN/A      virtRefreshEvent([this]{ virtRefresh(); }, name()),
875543Ssaidi@eecs.umich.edu      // Other
885543Ssaidi@eecs.umich.edu      bmp(&pixelPump.fb), pic(NULL), conv(PixelConverter::rgba8888_le),
891060SN/A      pixelPump(*this, *p->pxl_clk, p->pixel_chunk)
901060SN/A{
912292SN/A    if (vnc)
922107SN/A        vnc->setFrameBuffer(&pixelPump.fb);
931060SN/A}
941060SN/A
951060SN/AHDLcd::~HDLcd()
961060SN/A{
971060SN/A}
981060SN/A
992292SN/Avoid
1001060SN/AHDLcd::regStats()
1011060SN/A{
1025358Sgblack@eecs.umich.edu    AmbaDmaDevice::regStats();
1035358Sgblack@eecs.umich.edu
1045358Sgblack@eecs.umich.edu    using namespace Stats;
1055358Sgblack@eecs.umich.edu
1065358Sgblack@eecs.umich.edu    stats.underruns
1075358Sgblack@eecs.umich.edu        .name(name() + ".underruns")
1085358Sgblack@eecs.umich.edu        .desc("number of buffer underruns")
1095358Sgblack@eecs.umich.edu        .flags(nozero)
1105358Sgblack@eecs.umich.edu        ;
1115358Sgblack@eecs.umich.edu}
1125358Sgblack@eecs.umich.edu
1135358Sgblack@eecs.umich.eduvoid
1145358Sgblack@eecs.umich.eduHDLcd::serialize(CheckpointOut &cp) const
1152292SN/A{
1162292SN/A    DPRINTF(Checkpoint, "Serializing ARM HDLCD\n");
1172292SN/A
1182292SN/A    SERIALIZE_SCALAR(int_rawstat);
1192292SN/A    SERIALIZE_SCALAR(int_mask);
1202292SN/A
1212292SN/A    SERIALIZE_SCALAR(fb_base);
1221060SN/A    SERIALIZE_SCALAR(fb_line_length);
1232132SN/A    SERIALIZE_SCALAR(fb_line_count);
1241060SN/A    SERIALIZE_SCALAR(fb_line_pitch);
1257520Sgblack@eecs.umich.edu    SERIALIZE_SCALAR(bus_options);
1267520Sgblack@eecs.umich.edu
1272292SN/A    SERIALIZE_SCALAR(v_sync);
1282292SN/A    SERIALIZE_SCALAR(v_back_porch);
1292292SN/A    SERIALIZE_SCALAR(v_data);
1302292SN/A    SERIALIZE_SCALAR(v_front_porch);
1312292SN/A
1322292SN/A    SERIALIZE_SCALAR(h_sync);
1332292SN/A    SERIALIZE_SCALAR(h_back_porch);
1342292SN/A    SERIALIZE_SCALAR(h_data);
1351060SN/A    SERIALIZE_SCALAR(h_front_porch);
1366973Stjones1@inf.ed.ac.uk
1376973Stjones1@inf.ed.ac.uk    SERIALIZE_SCALAR(polarities);
1387520Sgblack@eecs.umich.edu
1397520Sgblack@eecs.umich.edu    SERIALIZE_SCALAR(command);
1407520Sgblack@eecs.umich.edu    SERIALIZE_SCALAR(pixel_format);
1416974Stjones1@inf.ed.ac.uk    SERIALIZE_SCALAR(red_select);
1426974Stjones1@inf.ed.ac.uk    SERIALIZE_SCALAR(green_select);
1436974Stjones1@inf.ed.ac.uk    SERIALIZE_SCALAR(blue_select);
1446974Stjones1@inf.ed.ac.uk
1456973Stjones1@inf.ed.ac.uk    SERIALIZE_OBJ(pixelPump);
1466974Stjones1@inf.ed.ac.uk    if (enabled())
1476974Stjones1@inf.ed.ac.uk        dmaEngine->serializeSection(cp, "dmaEngine");
1486973Stjones1@inf.ed.ac.uk}
1496973Stjones1@inf.ed.ac.uk
1506973Stjones1@inf.ed.ac.ukvoid
1516973Stjones1@inf.ed.ac.ukHDLcd::unserialize(CheckpointIn &cp)
1521060SN/A{
1531684SN/A    DPRINTF(Checkpoint, "Unserializing ARM HDLCD\n");
1541060SN/A
1551060SN/A    UNSERIALIZE_SCALAR(int_rawstat);
1561060SN/A    UNSERIALIZE_SCALAR(int_mask);
1571060SN/A
1582731Sktlim@umich.edu    UNSERIALIZE_SCALAR(fb_base);
1592731Sktlim@umich.edu    UNSERIALIZE_SCALAR(fb_line_length);
1602731Sktlim@umich.edu    UNSERIALIZE_SCALAR(fb_line_count);
1612731Sktlim@umich.edu    UNSERIALIZE_SCALAR(fb_line_pitch);
1622731Sktlim@umich.edu    UNSERIALIZE_SCALAR(bus_options);
1632731Sktlim@umich.edu
1642731Sktlim@umich.edu    UNSERIALIZE_SCALAR(v_sync);
1652731Sktlim@umich.edu    UNSERIALIZE_SCALAR(v_back_porch);
1662731Sktlim@umich.edu    UNSERIALIZE_SCALAR(v_data);
1672731Sktlim@umich.edu    UNSERIALIZE_SCALAR(v_front_porch);
1682731Sktlim@umich.edu
1692731Sktlim@umich.edu    UNSERIALIZE_SCALAR(h_sync);
1702731Sktlim@umich.edu    UNSERIALIZE_SCALAR(h_back_porch);
1712731Sktlim@umich.edu    UNSERIALIZE_SCALAR(h_data);
1722731Sktlim@umich.edu    UNSERIALIZE_SCALAR(h_front_porch);
1732731Sktlim@umich.edu
1742731Sktlim@umich.edu    UNSERIALIZE_SCALAR(polarities);
1752731Sktlim@umich.edu
1762731Sktlim@umich.edu    UNSERIALIZE_SCALAR(command);
1772731Sktlim@umich.edu    UNSERIALIZE_SCALAR(pixel_format);
1782731Sktlim@umich.edu    UNSERIALIZE_SCALAR(red_select);
1792731Sktlim@umich.edu    UNSERIALIZE_SCALAR(green_select);
1802731Sktlim@umich.edu    UNSERIALIZE_SCALAR(blue_select);
1812731Sktlim@umich.edu
1822731Sktlim@umich.edu    {
1832292SN/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");
1861060SN/A        if (cp.sectionExists(Serializable::currentSection()))
1871060SN/A            pixelPump.unserialize(cp);
1886221Snate@binkert.org    }
1891060SN/A
1901060SN/A    if (enabled()) {
1911060SN/A        // Create the DMA engine and read its state from the
1921060SN/A        // checkpoint. We don't need to worry about the pixel pump as
1932292SN/A        // it is a proper SimObject.
1942292SN/A        createDmaEngine();
1952292SN/A        dmaEngine->unserializeSection(cp, "dmaEngine");
1962733Sktlim@umich.edu
1972733Sktlim@umich.edu        conv = pixelConverter();
1981060SN/A    }
1992680Sktlim@umich.edu}
2002292SN/A
2011060SN/Avoid
2021060SN/AHDLcd::drainResume()
2032132SN/A{
2041060SN/A    AmbaDmaDevice::drainResume();
2052702Sktlim@umich.edu
2062669Sktlim@umich.edu    if (enabled()) {
2072292SN/A        if (sys->bypassCaches()) {
2081060SN/A            // We restart the HDLCD if we are in KVM mode. This
2091060SN/A            // ensures that we always use the fast refresh logic if we
2101060SN/A            // resume in KVM mode.
2114032Sktlim@umich.edu            cmdDisable();
2124032Sktlim@umich.edu            cmdEnable();
2134032Sktlim@umich.edu        } else if (!pixelPump.active()) {
2141060SN/A            // 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        }
2191060SN/A    }
2201060SN/A
2211060SN/A    // We restored from a checkpoint and need to update the VNC server
2221060SN/A    if (pixelPump.active() && vnc)
2231060SN/A        vnc->setDirty();
2241060SN/A}
2251060SN/A
2261464SN/Avoid
2271464SN/AHDLcd::virtRefresh()
2282356SN/A{
2291464SN/A    pixelPump.renderFrame();
2301464SN/A    schedule(virtRefreshEvent, (curTick() + virtRefreshRate));
2311060SN/A}
2321464SN/A
2331464SN/A// read registers and frame buffer
2341464SN/ATick
2351464SN/AHDLcd::read(PacketPtr pkt)
2361060SN/A{
2373326Sktlim@umich.edu    assert(pkt->getAddr() >= pioAddr &&
2383326Sktlim@umich.edu           pkt->getAddr() < pioAddr + pioSize);
2393326Sktlim@umich.edu
2407597Sminkyu.jeong@arm.com    const Addr daddr(pkt->getAddr() - pioAddr);
2417597Sminkyu.jeong@arm.com    panic_if(pkt->getSize() != 4,
2427597Sminkyu.jeong@arm.com             "Unhandled read size (address: 0x.4x, size: %u)",
2433965Sgblack@eecs.umich.edu             daddr, pkt->getSize());
2447720Sgblack@eecs.umich.edu
2457720Sgblack@eecs.umich.edu    const uint32_t data(readReg(daddr));
2461060SN/A    DPRINTF(HDLcd, "read register 0x%04x: 0x%x\n", daddr, data);
2477720Sgblack@eecs.umich.edu
2487720Sgblack@eecs.umich.edu    pkt->set<uint32_t>(data);
2494636Sgblack@eecs.umich.edu    pkt->makeAtomicResponse();
2503794Sgblack@eecs.umich.edu    return pioDelay;
2513794Sgblack@eecs.umich.edu}
2523794Sgblack@eecs.umich.edu
2533965Sgblack@eecs.umich.edu// write registers and frame buffer
2543965Sgblack@eecs.umich.eduTick
2552292SN/AHDLcd::write(PacketPtr pkt)
2562292SN/A{
2572292SN/A    assert(pkt->getAddr() >= pioAddr &&
2582292SN/A           pkt->getAddr() < pioAddr + pioSize);
2592292SN/A
2602292SN/A    const Addr daddr(pkt->getAddr() - pioAddr);
2611060SN/A    panic_if(pkt->getSize() != 4,
2621060SN/A             "Unhandled read size (address: 0x.4x, size: %u)",
2631060SN/A             daddr, pkt->getSize());
2643770Sgblack@eecs.umich.edu    const uint32_t data(pkt->get<uint32_t>());
2653770Sgblack@eecs.umich.edu    DPRINTF(HDLcd, "write register 0x%04x: 0x%x\n", daddr, data);
2663770Sgblack@eecs.umich.edu
2673770Sgblack@eecs.umich.edu    writeReg(daddr, data);
2683770Sgblack@eecs.umich.edu
2693770Sgblack@eecs.umich.edu    pkt->makeAtomicResponse();
2703770Sgblack@eecs.umich.edu    return pioDelay;
2713770Sgblack@eecs.umich.edu}
2723770Sgblack@eecs.umich.edu
2733770Sgblack@eecs.umich.eduuint32_t
2743770Sgblack@eecs.umich.eduHDLcd::readReg(Addr offset)
2753770Sgblack@eecs.umich.edu{
2763770Sgblack@eecs.umich.edu    switch (offset) {
2773770Sgblack@eecs.umich.edu      case Version: return version;
2783770Sgblack@eecs.umich.edu
2793770Sgblack@eecs.umich.edu      case Int_RawStat: return int_rawstat;
2803770Sgblack@eecs.umich.edu      case Int_Clear:
2813770Sgblack@eecs.umich.edu        panic("HDLCD INT_CLEAR register is Write-Only\n");
2823770Sgblack@eecs.umich.edu      case Int_Mask: return int_mask;
2833770Sgblack@eecs.umich.edu      case Int_Status: return intStatus();
2843770Sgblack@eecs.umich.edu
2853770Sgblack@eecs.umich.edu      case Fb_Base: return fb_base;
2863770Sgblack@eecs.umich.edu      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;
2901060SN/A
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
3133770Sgblack@eecs.umich.eduHDLcd::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,
3624636Sgblack@eecs.umich.edu                      "Changing HDLcd DMA burst flags: 0x%x -> 0x%x\n",
3634636Sgblack@eecs.umich.edu                      old_bus_options.burst_len, bus_options.burst_len);
3647720Sgblack@eecs.umich.edu          }
3657720Sgblack@eecs.umich.edu      } return;
3664636Sgblack@eecs.umich.edu
3674636Sgblack@eecs.umich.edu      case V_Sync:
3684636Sgblack@eecs.umich.edu        v_sync = value;
3697720Sgblack@eecs.umich.edu        return;
3707720Sgblack@eecs.umich.edu      case V_Back_Porch:
3713770Sgblack@eecs.umich.edu        v_back_porch = value;
3722292SN/A        return;
3732292SN/A      case V_Data:
3747720Sgblack@eecs.umich.edu        v_data = value;
3757720Sgblack@eecs.umich.edu        return;
3762292SN/A      case V_Front_Porch:
3772292SN/A        v_front_porch = value;
3782292SN/A        return;
3797720Sgblack@eecs.umich.edu
3807720Sgblack@eecs.umich.edu      case H_Sync:
3811060SN/A        h_sync = value;
3822292SN/A        return;
3832292SN/A      case H_Back_Porch:
3842292SN/A        h_back_porch = value;
3852107SN/A        return;
3861060SN/A      case H_Data:
3871060SN/A        h_data = value;
3881060SN/A        return;
3891060SN/A      case H_Front_Porch:
3901464SN/A        h_front_porch = value;
3911684SN/A        return;
3921464SN/A
3931060SN/A      case Polarities:
3941464SN/A        polarities = value;
3951060SN/A        return;
3961060SN/A
3971060SN/A      case Command: {
3981060SN/A          const CommandReg new_command(value);
3991060SN/A
4001060SN/A          if (new_command.enable != command.enable) {
4013326Sktlim@umich.edu              DPRINTF(HDLcd, "HDLCD switched %s\n",
4025712Shsul@eecs.umich.edu                      new_command.enable ? "on" : "off");
4033326Sktlim@umich.edu
4045714Shsul@eecs.umich.edu              if (new_command.enable) {
4055714Shsul@eecs.umich.edu                  cmdEnable();
4065714Shsul@eecs.umich.edu              } else {
4071060SN/A                  cmdDisable();
4082132SN/A              }
4091060SN/A          }
4101060SN/A          command = new_command;
4111060SN/A      } return;
4121060SN/A
4132292SN/A      case Pixel_Format:
4141060SN/A        pixel_format = value;
4151060SN/A        return;
4161060SN/A
4177720Sgblack@eecs.umich.edu      case Red_Select:
4187720Sgblack@eecs.umich.edu        red_select = value;
4193965Sgblack@eecs.umich.edu        return;
4207720Sgblack@eecs.umich.edu      case Green_Select:
4213965Sgblack@eecs.umich.edu        green_select = value;
4222935Sksewell@umich.edu        return;
4237720Sgblack@eecs.umich.edu      case Blue_Select:
4241060SN/A        blue_select = value;
4253794Sgblack@eecs.umich.edu        return;
4267720Sgblack@eecs.umich.edu
4273794Sgblack@eecs.umich.edu      default:
4283794Sgblack@eecs.umich.edu        panic("Tried to write HDLCD register that doesn't exist\n", offset);
4297720Sgblack@eecs.umich.edu        return;
4301060SN/A    }
4314636Sgblack@eecs.umich.edu}
4327720Sgblack@eecs.umich.edu
4334636Sgblack@eecs.umich.eduPixelConverter
4341060SN/AHDLcd::pixelConverter() const
4353794Sgblack@eecs.umich.edu{
4363794Sgblack@eecs.umich.edu    ByteOrder byte_order(
4373794Sgblack@eecs.umich.edu        pixel_format.big_endian ? BigEndianByteOrder : LittleEndianByteOrder);
4383794Sgblack@eecs.umich.edu
4393794Sgblack@eecs.umich.edu    /* Some Linux kernels have a broken driver that swaps the red and
4403794Sgblack@eecs.umich.edu     * blue color select registers. */
4413794Sgblack@eecs.umich.edu    if (!workaroundSwapRB) {
4423794Sgblack@eecs.umich.edu        return PixelConverter(
4433794Sgblack@eecs.umich.edu            pixel_format.bytes_per_pixel + 1,
4441060SN/A            red_select.offset, green_select.offset, blue_select.offset,
4451060SN/A            red_select.size, green_select.size, blue_select.size,
4462935Sksewell@umich.edu            byte_order);
4473794Sgblack@eecs.umich.edu    } else {
4487720Sgblack@eecs.umich.edu        return PixelConverter(
4497720Sgblack@eecs.umich.edu            pixel_format.bytes_per_pixel + 1,
4507720Sgblack@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);
4531060SN/A    }
4541060SN/A}
4551060SN/A
4565543Ssaidi@eecs.umich.eduDisplayTimings
4575543Ssaidi@eecs.umich.eduHDLcd::displayTimings() const
4585543Ssaidi@eecs.umich.edu{
4595543Ssaidi@eecs.umich.edu    return DisplayTimings(
4602336SN/A        h_data.val + 1, v_data.val + 1,
4612336SN/A        h_back_porch.val + 1, h_sync.val + 1, h_front_porch.val + 1,
4621060SN/A        v_back_porch.val + 1, v_sync.val + 1, v_front_porch.val + 1);
4631060SN/A}
4641060SN/A
4655543Ssaidi@eecs.umich.eduvoid
4665543Ssaidi@eecs.umich.eduHDLcd::createDmaEngine()
4675543Ssaidi@eecs.umich.edu{
4685543Ssaidi@eecs.umich.edu    if (bus_options.max_outstanding == 0) {
4695543Ssaidi@eecs.umich.edu        warn("Maximum number of outstanding DMA transfers set to 0.");
4705543Ssaidi@eecs.umich.edu        return;
4711060SN/A    }
4725543Ssaidi@eecs.umich.edu
4735543Ssaidi@eecs.umich.edu    const uint32_t dma_burst_flags(bus_options.burst_len);
4742935Sksewell@umich.edu    const uint32_t dma_burst_len(
4751060SN/A        dma_burst_flags ?
4761060SN/A        (1UL << (findMsbSet(dma_burst_flags) - 1)) :
4772292SN/A        MAX_BURST_LEN);
4782731Sktlim@umich.edu    // Some drivers seem to set the DMA line count incorrectly. This
4792292SN/A    // could either be a driver bug or a specification bug. Unlike for
4802731Sktlim@umich.edu    // timings, the specification does not require 1 to be added to
4817784SAli.Saidi@ARM.com    // the DMA engine's line count.
4821060SN/A    const uint32_t dma_lines(
4831060SN/A        fb_line_count + (workaroundDmaLineCount ? 1 : 0));
4841060SN/A
4852292SN/A    dmaEngine.reset(new DmaEngine(
4862336SN/A                        *this, pixelBufferSize,
4872308SN/A                        AXI_PORT_WIDTH * dma_burst_len,
4884828Sgblack@eecs.umich.edu                        bus_options.max_outstanding,
4894654Sgblack@eecs.umich.edu                        fb_line_length, fb_line_pitch, dma_lines));
4904654Sgblack@eecs.umich.edu}
4914636Sgblack@eecs.umich.edu
4924654Sgblack@eecs.umich.eduvoid
4934654Sgblack@eecs.umich.eduHDLcd::cmdEnable()
4944636Sgblack@eecs.umich.edu{
4952292SN/A    createDmaEngine();
4962292SN/A    conv = pixelConverter();
4972731Sktlim@umich.edu
4982292SN/A    // Update timing parameter before rendering frames
4992292SN/A    pixelPump.updateTimings(displayTimings());
5002731Sktlim@umich.edu
5012292SN/A    if (sys->bypassCaches()) {
5022292SN/A        schedule(virtRefreshEvent, clockEdge());
5032731Sktlim@umich.edu    } else {
5042292SN/A        pixelPump.start();
5052292SN/A    }
5062731Sktlim@umich.edu}
5072292SN/A
5082292SN/Avoid
5092731Sktlim@umich.eduHDLcd::cmdDisable()
5102292SN/A{
5112292SN/A    pixelPump.stop();
5122731Sktlim@umich.edu    // Disable the virtual refresh event
5132292SN/A    if (virtRefreshEvent.scheduled()) {
5142731Sktlim@umich.edu        assert(sys->bypassCaches());
5152731Sktlim@umich.edu        deschedule(virtRefreshEvent);
5162292SN/A    }
5172292SN/A    dmaEngine->abortFrame();
5182292SN/A}
5192292SN/A
5202292SN/Abool
5212292SN/AHDLcd::pxlNext(Pixel &p)
5222731Sktlim@umich.edu{
5231060SN/A    uint8_t pixel_data[MAX_PIXEL_SIZE];
5241464SN/A    assert(conv.length <= sizeof(pixel_data));
5251464SN/A    if (dmaEngine->tryGet(pixel_data, conv.length)) {
5261464SN/A        p = conv.toPixel(pixel_data);
5271464SN/A        return true;
5287720Sgblack@eecs.umich.edu    } else {
5297720Sgblack@eecs.umich.edu        return false;
5301464SN/A    }
5312292SN/A}
5325543Ssaidi@eecs.umich.edu
5331684SN/Avoid
5342292SN/AHDLcd::pxlVSyncBegin()
5351060SN/A{
5361060SN/A    DPRINTF(HDLcd, "Raising VSYNC interrupt.\n");
5371060SN/A    intRaise(INT_VSYNC);
5381060SN/A}
5391060SN/A
5401060SN/Avoid
5411060SN/AHDLcd::pxlVSyncEnd()
5421060SN/A{
5432292SN/A    DPRINTF(HDLcd, "End of VSYNC, starting DMA engine\n");
5441060SN/A    dmaEngine->startFrame(fb_base);
5451060SN/A}
5462292SN/A
5471060SN/Avoid
5481684SN/AHDLcd::pxlUnderrun()
5491464SN/A{
5501684SN/A    DPRINTF(HDLcd, "Buffer underrun, stopping DMA fill.\n");
5511684SN/A    ++stats.underruns;
5522356SN/A    intRaise(INT_UNDERRUN);
5531684SN/A    dmaEngine->abortFrame();
5541684SN/A}
5551464SN/A
5561060SN/Avoid
5572702Sktlim@umich.eduHDLcd::pxlFrameDone()
5583735Sstever@eecs.umich.edu{
5591060SN/A    DPRINTF(HDLcd, "Reached end of last visible line.\n");
5603326Sktlim@umich.edu
5613326Sktlim@umich.edu    if (dmaEngine->size()) {
5621060SN/A        warn("HDLCD %u bytes still in FIFO after frame: Ensure that DMA "
5631060SN/A             "and PixelPump configuration is consistent\n",
5642702Sktlim@umich.edu             dmaEngine->size());
5653735Sstever@eecs.umich.edu        dmaEngine->dumpSettings();
5663735Sstever@eecs.umich.edu        pixelPump.dumpSettings();
5672690Sktlim@umich.edu    }
5683326Sktlim@umich.edu
5693326Sktlim@umich.edu    if (vnc)
5703326Sktlim@umich.edu        vnc->setDirty();
5713326Sktlim@umich.edu
5723326Sktlim@umich.edu    if (enableCapture) {
5733326Sktlim@umich.edu        if (!pic) {
5743326Sktlim@umich.edu            pic = simout.create(
5753326Sktlim@umich.edu                csprintf("%s.framebuffer.bmp", sys->name()),
5762690Sktlim@umich.edu                true);
5772690Sktlim@umich.edu        }
5782702Sktlim@umich.edu
5793735Sstever@eecs.umich.edu        assert(pic);
5801060SN/A        pic->stream()->seekp(0);
5813326Sktlim@umich.edu        bmp.write(*pic->stream());
5823326Sktlim@umich.edu    }
5832308SN/A}
5841060SN/A
5852702Sktlim@umich.eduvoid
5863735Sstever@eecs.umich.eduHDLcd::setInterrupts(uint32_t ints, uint32_t mask)
5873735Sstever@eecs.umich.edu{
5882308SN/A    const bool old_ints(intStatus());
5893326Sktlim@umich.edu
5903326Sktlim@umich.edu    int_mask = mask;
5912308SN/A    int_rawstat = ints;
5921060SN/A
5932702Sktlim@umich.edu    if (!old_ints && intStatus()) {
5943735Sstever@eecs.umich.edu        gic->sendInt(intNum);
5952308SN/A    } else if (old_ints && !intStatus()) {
5963326Sktlim@umich.edu        gic->clearInt(intNum);
5973326Sktlim@umich.edu    }
5981060SN/A}
5991060SN/A
6002190SN/AHDLcd::DmaEngine::DmaEngine(HDLcd &_parent, size_t size,
6012292SN/A          unsigned request_size, unsigned max_pending,
6022190SN/A          size_t line_size, ssize_t line_pitch, unsigned num_lines)
6032331SN/A    : DmaReadFifo(
6042292SN/A        _parent.dmaPort, size, request_size, max_pending,
6052190SN/A        Request::UNCACHEABLE),
6061684SN/A      parent(_parent),
6071464SN/A      lineSize(line_size), linePitch(line_pitch), numLines(num_lines),
6081464SN/A      nextLineAddr(0)
6091464SN/A{
6101464SN/A}
6111464SN/A
6121684SN/Avoid
6132731Sktlim@umich.eduHDLcd::DmaEngine::serialize(CheckpointOut &cp) const
6141464SN/A{
6152292SN/A    DmaReadFifo::serialize(cp);
6162731Sktlim@umich.edu
6171464SN/A    SERIALIZE_SCALAR(nextLineAddr);
6182731Sktlim@umich.edu    SERIALIZE_SCALAR(frameEnd);
6192731Sktlim@umich.edu}
6202308SN/A
6212731Sktlim@umich.eduvoid
6222731Sktlim@umich.eduHDLcd::DmaEngine::unserialize(CheckpointIn &cp)
6232308SN/A{
6241060SN/A    DmaReadFifo::unserialize(cp);
6252731Sktlim@umich.edu
6261060SN/A    UNSERIALIZE_SCALAR(nextLineAddr);
6271060SN/A    UNSERIALIZE_SCALAR(frameEnd);
6282731Sktlim@umich.edu}
6291060SN/A
6304032Sktlim@umich.eduvoid
6314032Sktlim@umich.eduHDLcd::DmaEngine::startFrame(Addr fb_base)
6324032Sktlim@umich.edu{
6331060SN/A    nextLineAddr = fb_base;
6342731Sktlim@umich.edu    frameEnd = fb_base + numLines * linePitch;
6351060SN/A
6361060SN/A    startFill(nextLineAddr, lineSize);
6372731Sktlim@umich.edu}
6381060SN/A
6394032Sktlim@umich.eduvoid
6404032Sktlim@umich.eduHDLcd::DmaEngine::abortFrame()
6414032Sktlim@umich.edu{
6421060SN/A    nextLineAddr = frameEnd;
6432731Sktlim@umich.edu    stopFill();
6441060SN/A    flush();
6451060SN/A}
6462731Sktlim@umich.edu
6471060SN/A
6481060SN/Avoid
6492731Sktlim@umich.eduHDLcd::DmaEngine::dumpSettings()
6501060SN/A{
6511061SN/A    inform("DMA line size: %u bytes", lineSize);
6522731Sktlim@umich.edu    inform("DMA line pitch: %i bytes", linePitch);
6531061SN/A    inform("DMA num lines: %u", numLines);
6541060SN/A}
6552731Sktlim@umich.edu
6562731Sktlim@umich.eduvoid
6572731Sktlim@umich.eduHDLcd::DmaEngine::onEndOfBlock()
6582731Sktlim@umich.edu{
6592731Sktlim@umich.edu    if (nextLineAddr == frameEnd)
6601060SN/A        // We're done with this frame. Ignore calls to this method
6612292SN/A        // until the next frame has been started.
6622731Sktlim@umich.edu        return;
6632292SN/A
6642292SN/A    nextLineAddr += linePitch;
6652731Sktlim@umich.edu    if (nextLineAddr != frameEnd)
6662292SN/A        startFill(nextLineAddr, lineSize);
6671060SN/A}
6682731Sktlim@umich.edu
6691060SN/Avoid
6701060SN/AHDLcd::DmaEngine::onIdle()
6712731Sktlim@umich.edu{
6721060SN/A    parent.intRaise(INT_DMA_END);
6732292SN/A}
6742292SN/A
6752292SN/Avoid
6762731Sktlim@umich.eduHDLcd::PixelPump::dumpSettings()
6772292SN/A{
6782292SN/A    const DisplayTimings &t(timings());
6792731Sktlim@umich.edu
6802731Sktlim@umich.edu    inform("PixelPump width: %u", t.width);
6812731Sktlim@umich.edu    inform("PixelPump height: %u", t.height);
6822731Sktlim@umich.edu
6832292SN/A    inform("PixelPump horizontal back porch: %u", t.hBackPorch);
6841060SN/A    inform("PixelPump horizontal fron porch: %u", t.hFrontPorch);
6852731Sktlim@umich.edu    inform("PixelPump horizontal fron porch: %u", t.hSync);
6861060SN/A
6871060SN/A    inform("PixelPump vertical back porch: %u", t.vBackPorch);
6882731Sktlim@umich.edu    inform("PixelPump vertical fron porch: %u", t.vFrontPorch);
6892292SN/A    inform("PixelPump vertical fron porch: %u", t.vSync);
6902292SN/A}
6912292SN/A
6922292SN/A
6932292SN/AHDLcd *
6942731Sktlim@umich.eduHDLcdParams::create()
6952292SN/A{
6962292SN/A    return new HDLcd(this);
6972731Sktlim@umich.edu}
6982731Sktlim@umich.edu