changeset f37a6b82f98f in /z/repo/gem5 details: http://repo.gem5.org/gem5?cmd=changeset;node=f37a6b82f98f description: dev, arm: Rewrite the HDLCD controller
Rewrite the HDLCD controller to use the new DMA engine and pixel pump. This fixes several bugs in the current implementation: * Broken/missing interrupt support (VSync, underrun, DMA end) * Fragile resolution changes (changing resolutions used to cause assertion errors). * Support for resolutions with a width that isn't divisible by 32. * The pixel clock can now be set dynamically. This breaks checkpoint compatibility. Checkpoints can be upgraded with the checkpoint conversion script. However, upgraded checkpoints won't contain the state of the current frame. That means that HDLCD controllers restoring from a converted checkpoint immediately start drawing a new frame (i.e, expect timing differences). diffstat: src/dev/arm/RealView.py | 18 +- src/dev/arm/hdlcd.cc | 1146 +++++++++++++----------------- src/dev/arm/hdlcd.hh | 462 ++++-------- util/cpt_upgraders/arm-hdlcd-upgrade.py | 109 ++ 4 files changed, 767 insertions(+), 968 deletions(-) diffs (truncated from 1990 to 300 lines): diff -r 4808f8c4a47e -r f37a6b82f98f src/dev/arm/RealView.py --- a/src/dev/arm/RealView.py Tue Sep 08 19:32:04 2015 -0500 +++ b/src/dev/arm/RealView.py Fri Sep 11 15:55:46 2015 +0100 @@ -54,6 +54,7 @@ from SimpleMemory import SimpleMemory from Gic import * from EnergyCtrl import EnergyCtrl +from ClockDomain import SrcClockDomain class AmbaPioDevice(BasicPioDevice): type = 'AmbaPioDevice' @@ -218,23 +219,23 @@ amba_id = 0x00141111 enable_capture = Param.Bool(True, "capture frame to system.framebuffer.bmp") - class HDLcd(AmbaDmaDevice): type = 'HDLcd' cxx_header = "dev/arm/hdlcd.hh" - # For reference, 1024x768MR-16@60 ~= 56 MHz - # 1920x1080MR-16@60 ~= 137 MHz - # 3840x2160MR-16@60 ~= 533 MHz - # Match against the resolution selected in the Linux DTS/DTB file. - pixel_clock = Param.Clock('137MHz', "Clock frequency of the pixel clock " - "(i.e. PXLREFCLK / OSCCLK 5") vnc = Param.VncInput(Parent.any, "Vnc server for remote frame buffer " "display") amba_id = 0x00141000 workaround_swap_rb = Param.Bool(True, "Workaround incorrect color " "selector order in some kernels") + workaround_dma_line_count = Param.Bool(True, "Workaround incorrect " + "DMA line count (off by 1)") enable_capture = Param.Bool(True, "capture frame to system.framebuffer.bmp") + pixel_buffer_size = Param.MemorySize32("2kB", "Size of address range") + + pxl_clk = Param.ClockDomain("Pixel clock source") + pixel_chunk = Param.Unsigned(32, "Number of pixels to handle in one batch") + class RealView(Platform): type = 'RealView' cxx_header = "dev/arm/realview.hh" @@ -518,7 +519,8 @@ timer0 = Sp804(int_num0=34, int_num1=34, pio_addr=0x1C110000, clock0='1MHz', clock1='1MHz') timer1 = Sp804(int_num0=35, int_num1=35, pio_addr=0x1C120000, clock0='1MHz', clock1='1MHz') clcd = Pl111(pio_addr=0x1c1f0000, int_num=46) - hdlcd = HDLcd(pio_addr=0x2b000000, int_num=117) + hdlcd = HDLcd(pxl_clk=realview_io.osc_pxl, + pio_addr=0x2b000000, int_num=117) kmi0 = Pl050(pio_addr=0x1c060000, int_num=44) kmi1 = Pl050(pio_addr=0x1c070000, int_num=45, is_mouse=True) vgic = VGic(vcpu_addr=0x2c006000, hv_addr=0x2c004000, ppint=25) diff -r 4808f8c4a47e -r f37a6b82f98f src/dev/arm/hdlcd.cc --- a/src/dev/arm/hdlcd.cc Tue Sep 08 19:32:04 2015 -0500 +++ b/src/dev/arm/hdlcd.cc Fri Sep 11 15:55:46 2015 +0100 @@ -35,6 +35,7 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * Authors: Chris Emmons + * Andreas Sandberg */ #include "dev/arm/hdlcd.hh" @@ -42,145 +43,175 @@ #include "base/vnc/vncinput.hh" #include "base/output.hh" #include "base/trace.hh" +#include "debug/Checkpoint.hh" #include "debug/HDLcd.hh" -#include "debug/Uart.hh" #include "dev/arm/amba_device.hh" #include "dev/arm/base_gic.hh" #include "mem/packet.hh" #include "mem/packet_access.hh" +#include "params/HDLcd.hh" #include "sim/system.hh" using std::vector; // initialize hdlcd registers -HDLcd::HDLcd(const Params *p) - : AmbaDmaDevice(p), version(VERSION_RESETV), - int_rawstat(0), int_clear(0), int_mask(0), int_status(0), +HDLcd::HDLcd(const HDLcdParams *p) + : AmbaDmaDevice(p, 0xFFFF), + // Parameters + vnc(p->vnc), + workaroundSwapRB(p->workaround_swap_rb), + workaroundDmaLineCount(p->workaround_dma_line_count), + addrRanges{RangeSize(pioAddr, pioSize)}, + enableCapture(p->enable_capture), + pixelBufferSize(p->pixel_buffer_size), + + // Registers + version(VERSION_RESETV), + int_rawstat(0), int_mask(0), + fb_base(0), fb_line_length(0), fb_line_count(0), fb_line_pitch(0), bus_options(BUS_OPTIONS_RESETV), + v_sync(0), v_back_porch(0), v_data(0), v_front_porch(0), h_sync(0), h_back_porch(0), h_data(0), h_front_porch(0), - polarities(0), command(0), pixel_format(0), + polarities(0), + + command(0), + + pixel_format(0), red_select(0), green_select(0), blue_select(0), - pixelClock(p->pixel_clock), - fb(0, 0), vnc(p->vnc), bmp(&fb), pic(NULL), - frameReadStartTime(0), - dmaStartAddr(0), dmaCurAddr(0), dmaMaxAddr(0), dmaPendingNum(0), - frameUnderrun(false), pixelBufferSize(0), - pixelIndex(0), doUpdateParams(false), frameUnderway(false), - dmaBytesInFlight(0), - startFrameEvent(this), endFrameEvent(this), renderPixelEvent(this), - fillPixelBufferEvent(this), intEvent(this), - dmaDoneEventAll(MAX_OUTSTANDING_DMA_REQ_CAPACITY, this), - dmaDoneEventFree(MAX_OUTSTANDING_DMA_REQ_CAPACITY), - enableCapture(p->enable_capture), - workaround_swap_rb(p->workaround_swap_rb) + + // Other + bmp(&pixelPump.fb), pic(NULL), conv(PixelConverter::rgba8888_le), + pixelPump(*this, *p->pxl_clk, p->pixel_chunk) { - pioSize = 0xFFFF; - - for (int i = 0; i < MAX_OUTSTANDING_DMA_REQ_CAPACITY; ++i) - dmaDoneEventFree[i] = &dmaDoneEventAll[i]; - if (vnc) - vnc->setFrameBuffer(&fb); + vnc->setFrameBuffer(&pixelPump.fb); } HDLcd::~HDLcd() { } +void +HDLcd::serialize(CheckpointOut &cp) const +{ + DPRINTF(Checkpoint, "Serializing ARM HDLCD\n"); + + SERIALIZE_SCALAR(int_rawstat); + SERIALIZE_SCALAR(int_mask); + + SERIALIZE_SCALAR(fb_base); + SERIALIZE_SCALAR(fb_line_length); + SERIALIZE_SCALAR(fb_line_count); + SERIALIZE_SCALAR(fb_line_pitch); + SERIALIZE_SCALAR(bus_options); + + SERIALIZE_SCALAR(v_sync); + SERIALIZE_SCALAR(v_back_porch); + SERIALIZE_SCALAR(v_data); + SERIALIZE_SCALAR(v_front_porch); + + SERIALIZE_SCALAR(h_sync); + SERIALIZE_SCALAR(h_back_porch); + SERIALIZE_SCALAR(h_data); + SERIALIZE_SCALAR(h_front_porch); + + SERIALIZE_SCALAR(polarities); + + SERIALIZE_SCALAR(command); + SERIALIZE_SCALAR(pixel_format); + SERIALIZE_SCALAR(red_select); + SERIALIZE_SCALAR(green_select); + SERIALIZE_SCALAR(blue_select); + + SERIALIZE_OBJ(pixelPump); + if (enabled()) + dmaEngine->serializeSection(cp, "dmaEngine"); +} + +void +HDLcd::unserialize(CheckpointIn &cp) +{ + DPRINTF(Checkpoint, "Unserializing ARM HDLCD\n"); + + UNSERIALIZE_SCALAR(int_rawstat); + UNSERIALIZE_SCALAR(int_mask); + + UNSERIALIZE_SCALAR(fb_base); + UNSERIALIZE_SCALAR(fb_line_length); + UNSERIALIZE_SCALAR(fb_line_count); + UNSERIALIZE_SCALAR(fb_line_pitch); + UNSERIALIZE_SCALAR(bus_options); + + UNSERIALIZE_SCALAR(v_sync); + UNSERIALIZE_SCALAR(v_back_porch); + UNSERIALIZE_SCALAR(v_data); + UNSERIALIZE_SCALAR(v_front_porch); + + UNSERIALIZE_SCALAR(h_sync); + UNSERIALIZE_SCALAR(h_back_porch); + UNSERIALIZE_SCALAR(h_data); + UNSERIALIZE_SCALAR(h_front_porch); + + UNSERIALIZE_SCALAR(polarities); + + UNSERIALIZE_SCALAR(command); + UNSERIALIZE_SCALAR(pixel_format); + UNSERIALIZE_SCALAR(red_select); + UNSERIALIZE_SCALAR(green_select); + UNSERIALIZE_SCALAR(blue_select); + + { + // Try to unserialize the pixel pump. It might not exist if + // we're unserializing an old checkpoint. + ScopedCheckpointSection sec(cp, "pixelPump"); + if (cp.sectionExists(Serializable::currentSection())) + pixelPump.unserialize(cp); + } + + if (enabled()) { + // Create the DMA engine and read its state from the + // checkpoint. We don't need to worry about the pixel pump as + // it is a proper SimObject. + createDmaEngine(); + dmaEngine->unserializeSection(cp, "dmaEngine"); + + conv = pixelConverter(); + } +} + +void +HDLcd::drainResume() +{ + AmbaDmaDevice::drainResume(); + + // We restored from an old checkpoint without a pixel pump, start + // an new refresh. This typically happens when restoring from old + // checkpoints. + if (enabled() && !pixelPump.active()) + pixelPump.start(displayTimings()); + + // We restored from a checkpoint and need to update the VNC server + if (pixelPump.active() && vnc) + vnc->setDirty(); +} + // read registers and frame buffer Tick HDLcd::read(PacketPtr pkt) { - uint32_t data = 0; - const Addr daddr = pkt->getAddr() - pioAddr; + assert(pkt->getAddr() >= pioAddr && + pkt->getAddr() < pioAddr + pioSize); - DPRINTF(HDLcd, "read register BASE+0x%04x size=%d\n", daddr, - pkt->getSize()); + const Addr daddr(pkt->getAddr() - pioAddr); + panic_if(pkt->getSize() != 4, + "Unhandled read size (address: 0x.4x, size: %u)", + daddr, pkt->getSize()); - assert(pkt->getAddr() >= pioAddr && - pkt->getAddr() < pioAddr + pioSize && - pkt->getSize() == 4); - - switch (daddr) { - case Version: - data = version; - break; - case Int_RawStat: - data = int_rawstat; - break; - case Int_Clear: - panic("HDLCD INT_CLEAR register is Write-Only\n"); - break; - case Int_Mask: - data = int_mask; - break; - case Int_Status: - data = int_status; - break; - case Fb_Base: - data = fb_base; - break; - case Fb_Line_Length: - data = fb_line_length; - break; - case Fb_Line_Count: - data = fb_line_count; - break; - case Fb_Line_Pitch: - data = fb_line_pitch; - break; - case Bus_Options: - data = bus_options; - break; - case V_Sync: - data = v_sync; - break; _______________________________________________ gem5-dev mailing list gem5-dev@gem5.org http://m5sim.org/mailman/listinfo/gem5-dev