hdlcd.hh revision 11294
12810SN/A/* 22810SN/A * Copyright (c) 2010-2013, 2015 ARM Limited 37636Ssteve.reinhardt@amd.com * All rights reserved 42810SN/A * 52810SN/A * The license below extends only to copyright in the software and shall 62810SN/A * not be construed as granting a license to any other intellectual 72810SN/A * property including but not limited to intellectual property relating 82810SN/A * to a hardware implementation of the functionality of the software 92810SN/A * licensed hereunder. You may use the software subject to the license 102810SN/A * terms below provided that you ensure that this notice is replicated 112810SN/A * unmodified and in its entirety in all distributions of the software, 122810SN/A * modified or unmodified, in source code or in binary form. 132810SN/A * 142810SN/A * Redistribution and use in source and binary forms, with or without 152810SN/A * modification, are permitted provided that the following conditions are 162810SN/A * met: redistributions of source code must retain the above copyright 172810SN/A * notice, this list of conditions and the following disclaimer; 182810SN/A * redistributions in binary form must reproduce the above copyright 192810SN/A * notice, this list of conditions and the following disclaimer in the 202810SN/A * documentation and/or other materials provided with the distribution; 212810SN/A * neither the name of the copyright holders nor the names of its 222810SN/A * contributors may be used to endorse or promote products derived from 232810SN/A * this software without specific prior written permission. 242810SN/A * 252810SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 262810SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 272810SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 282810SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 292810SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 302810SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 312810SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 322810SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 332810SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 342810SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 352810SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 362810SN/A * 372810SN/A * Authors: Chris Emmons 386216Snate@binkert.org * Andreas Sandberg 396216Snate@binkert.org */ 402810SN/A 412810SN/A 422810SN/A/** @file 436216Snate@binkert.org * Implementiation of the ARM HDLcd controller. 446216Snate@binkert.org * 456216Snate@binkert.org * This implementation aims to have sufficient detail such that underrun 465338Sstever@gmail.com * conditions are reasonable / behave similar to reality. There are two 476216Snate@binkert.org * 'engines' going at once. First, the DMA engine running at LCD clock 482810SN/A * frequency is responsible for filling the controller's internal buffer. 492810SN/A * The second engine runs at the pixel clock frequency and reads the pixels 502810SN/A * out of the internal buffer. The pixel rendering engine uses front / back 512810SN/A * porch and sync delays between lines and frames. 522810SN/A * 532810SN/A * If the pixel rendering engine does not have a pixel to display, it will 542810SN/A * cause an underrun event. The HDLcd controller, per spec, will stop 556221Snate@binkert.org * issuing DMA requests for the rest of the frame and resume normal behavior 564903SN/A * on the subsequent frame. What pixels are rendered upon an underrun 574903SN/A * condition is different than the real hardware; while the user will see 582810SN/A * artifacts (previous frame mixed with current frame), it is not the same 592810SN/A * behavior as real hardware which repeats the last pixel value for the rest 604903SN/A * of the current frame. This compromise was made to save on memory and 614903SN/A * complexity and assumes that it is not important to accurately model the 624903SN/A * content of an underrun frame. 634903SN/A * 644903SN/A * KNOWN ISSUES 654903SN/A * <ul> 664903SN/A * <li>The HDLcd is implemented here as an AmbaDmaDevice, but it 674908SN/A * doesn't have an AMBA ID as far as I know. That is the only 685875Ssteve.reinhardt@amd.com * bit of the AmbaDmaDevice interface that is irrelevant to it, 694903SN/A * so a fake AMBA ID is used for now. I didn't think inserting 705875Ssteve.reinhardt@amd.com * an extra layer of hierachy between AmbaDmaDevice and 714903SN/A * DmaDevice would be helpful to anyone else, but that may be 724903SN/A * the right answer. 734903SN/A * </ul> 744903SN/A */ 757465Ssteve.reinhardt@amd.com 764903SN/A#ifndef __DEV_ARM_HDLCD_HH__ 774903SN/A#define __DEV_ARM_HDLCD_HH__ 785318SN/A 794908SN/A#include <fstream> 805318SN/A#include <memory> 814908SN/A 824908SN/A#include "base/bitmap.hh" 834908SN/A#include "base/framebuffer.hh" 844908SN/A#include "dev/arm/amba_device.hh" 854908SN/A#include "dev/pixelpump.hh" 864903SN/A#include "sim/serialize.hh" 874903SN/A 885875Ssteve.reinhardt@amd.comclass VncInput; 894903SN/Astruct HDLcdParams; 904903SN/Aclass HDLcdPixelPump; 914903SN/A 927667Ssteve.reinhardt@amd.comclass HDLcd: public AmbaDmaDevice 937667Ssteve.reinhardt@amd.com{ 947667Ssteve.reinhardt@amd.com public: 957667Ssteve.reinhardt@amd.com HDLcd(const HDLcdParams *p); 967667Ssteve.reinhardt@amd.com ~HDLcd(); 977667Ssteve.reinhardt@amd.com 987667Ssteve.reinhardt@amd.com void regStats() override; 997667Ssteve.reinhardt@amd.com 1007667Ssteve.reinhardt@amd.com void serialize(CheckpointOut &cp) const override; 1017667Ssteve.reinhardt@amd.com void unserialize(CheckpointIn &cp) override; 1027667Ssteve.reinhardt@amd.com 1037667Ssteve.reinhardt@amd.com void drainResume() override; 1047667Ssteve.reinhardt@amd.com 1054903SN/A public: // IO device interface 1064903SN/A Tick read(PacketPtr pkt) override; 1074903SN/A Tick write(PacketPtr pkt) override; 1084903SN/A 1094903SN/A AddrRangeList getAddrRanges() const override { return addrRanges; } 1104903SN/A 1114903SN/A protected: // Parameters 1124903SN/A VncInput *vnc; 1137667Ssteve.reinhardt@amd.com const bool workaroundSwapRB; 1144903SN/A const bool workaroundDmaLineCount; 1154903SN/A const AddrRangeList addrRanges; 1164903SN/A const bool enableCapture; 1174903SN/A const Addr pixelBufferSize; 1184903SN/A 1194903SN/A protected: // Register handling 1202810SN/A /** ARM HDLcd register offsets */ 1214908SN/A enum RegisterOffset { 1224908SN/A Version = 0x0000, 1234908SN/A Int_RawStat = 0x0010, 1244908SN/A Int_Clear = 0x0014, 1255318SN/A Int_Mask = 0x0018, 1265318SN/A Int_Status = 0x001C, 1275318SN/A Fb_Base = 0x0100, 1285318SN/A Fb_Line_Length = 0x0104, 1295318SN/A Fb_Line_Count = 0x0108, 1304908SN/A Fb_Line_Pitch = 0x010C, 1314908SN/A Bus_Options = 0x0110, 1324908SN/A V_Sync = 0x0200, 1334908SN/A V_Back_Porch = 0x0204, 1344908SN/A V_Data = 0x0208, 1354920SN/A V_Front_Porch = 0x020C, 1364920SN/A H_Sync = 0x0210, 1374920SN/A H_Back_Porch = 0x0214, 1384920SN/A H_Data = 0x0218, 1394920SN/A H_Front_Porch = 0x021C, 1404920SN/A Polarities = 0x0220, 1414920SN/A Command = 0x0230, 1424920SN/A Pixel_Format = 0x0240, 1434920SN/A Red_Select = 0x0244, 1444920SN/A Green_Select = 0x0248, 1454920SN/A Blue_Select = 0x024C, 1464920SN/A }; 1474920SN/A 1484920SN/A /** Reset value for Bus_Options register */ 1494908SN/A static constexpr size_t BUS_OPTIONS_RESETV = 0x408; 1505314SN/A 1515314SN/A /** Reset value for Version register */ 1525314SN/A static constexpr size_t VERSION_RESETV = 0x1CDC0000; 1535314SN/A 1545314SN/A /** AXI port width in bytes */ 1555875Ssteve.reinhardt@amd.com static constexpr size_t AXI_PORT_WIDTH = 8; 1565875Ssteve.reinhardt@amd.com 1575875Ssteve.reinhardt@amd.com /** max number of beats delivered in one dma burst */ 1585875Ssteve.reinhardt@amd.com static constexpr size_t MAX_BURST_LEN = 16; 1595875Ssteve.reinhardt@amd.com 1605875Ssteve.reinhardt@amd.com /** Maximum number of bytes per pixel */ 1615875Ssteve.reinhardt@amd.com static constexpr size_t MAX_PIXEL_SIZE = 4; 1625875Ssteve.reinhardt@amd.com 1635314SN/A /** 1645314SN/A * @name RegisterFieldLayouts 1655314SN/A * Bit layout declarations for multi-field registers. 1665314SN/A */ 1675314SN/A /**@{*/ 1685314SN/A BitUnion32(VersionReg) 1694666SN/A Bitfield<7,0> version_minor; 1704871SN/A Bitfield<15,8> version_major; 1712810SN/A Bitfield<31,16> product_id; 1722885SN/A EndBitUnion(VersionReg) 1734626SN/A 1744871SN/A static constexpr uint32_t INT_DMA_END = (1UL << 0); 1754666SN/A static constexpr uint32_t INT_BUS_ERROR = (1UL << 1); 1764626SN/A static constexpr uint32_t INT_VSYNC = (1UL << 2); 1775730SSteve.Reinhardt@amd.com static constexpr uint32_t INT_UNDERRUN = (1UL << 3); 1784626SN/A 1794626SN/A BitUnion32(FbLineCountReg) 1804908SN/A Bitfield<11,0> fb_line_count; 1814626SN/A Bitfield<31,12> reserved_31_12; 1824626SN/A EndBitUnion(FbLineCountReg) 1835875Ssteve.reinhardt@amd.com 1844626SN/A BitUnion32(BusOptsReg) 1855875Ssteve.reinhardt@amd.com Bitfield<4,0> burst_len; 1865875Ssteve.reinhardt@amd.com Bitfield<7,5> reserved_7_5; 1875875Ssteve.reinhardt@amd.com Bitfield<11,8> max_outstanding; 1885875Ssteve.reinhardt@amd.com Bitfield<31,12> reserved_31_12; 1894903SN/A EndBitUnion(BusOptsReg) 1904668SN/A 1912810SN/A BitUnion32(TimingReg) 1922810SN/A Bitfield<11,0> val; 1934908SN/A Bitfield<31,12> reserved_31_12; 1945318SN/A EndBitUnion(TimingReg) 1955318SN/A 1965318SN/A BitUnion32(PolaritiesReg) 1975318SN/A Bitfield<0> vsync_polarity; 1985318SN/A Bitfield<1> hsync_polarity; 1995318SN/A Bitfield<2> dataen_polarity; 2005318SN/A Bitfield<3> data_polarity; 2015318SN/A Bitfield<4> pxlclk_polarity; 2025318SN/A Bitfield<31,5> reserved_31_5; 2035318SN/A EndBitUnion(PolaritiesReg) 2044908SN/A 2057667Ssteve.reinhardt@amd.com BitUnion32(CommandReg) 2064908SN/A Bitfield<0> enable; 2074908SN/A Bitfield<31,1> reserved_31_1; 2085730SSteve.Reinhardt@amd.com EndBitUnion(CommandReg) 2094908SN/A 2104908SN/A BitUnion32(PixelFormatReg) 2114908SN/A Bitfield<2,0> reserved_2_0; 2124908SN/A Bitfield<4,3> bytes_per_pixel; 2134908SN/A Bitfield<30,5> reserved_30_5; 2144908SN/A Bitfield<31> big_endian; 2154908SN/A EndBitUnion(PixelFormatReg) 2167667Ssteve.reinhardt@amd.com 2177667Ssteve.reinhardt@amd.com BitUnion32(ColorSelectReg) 2187667Ssteve.reinhardt@amd.com Bitfield<4,0> offset; 2197667Ssteve.reinhardt@amd.com Bitfield<7,5> reserved_7_5; 2204908SN/A Bitfield<11,8> size; 2214908SN/A Bitfield<15,12> reserved_15_12; 2224908SN/A Bitfield<23,16> default_color; 2234908SN/A Bitfield<31,24> reserved_31_24; 2244908SN/A EndBitUnion(ColorSelectReg) 2254908SN/A /**@}*/ 2264908SN/A 2274908SN/A /** 2284908SN/A * @name HDLCDRegisters 2292810SN/A * HDLCD register contents. 2302810SN/A */ 2312810SN/A /**@{*/ 2324903SN/A const VersionReg version; /**< Version register */ 2334903SN/A uint32_t int_rawstat; /**< Interrupt raw status register */ 2344903SN/A uint32_t int_mask; /**< Interrupt mask register */ 2352810SN/A uint32_t fb_base; /**< Frame buffer base address register */ 2362810SN/A uint32_t fb_line_length; /**< Frame buffer Line length register */ 2372810SN/A FbLineCountReg fb_line_count; /**< Frame buffer Line count register */ 2382810SN/A int32_t fb_line_pitch; /**< Frame buffer Line pitch register */ 2392810SN/A BusOptsReg bus_options; /**< Bus options register */ 2402810SN/A TimingReg v_sync; /**< Vertical sync width register */ 2412810SN/A TimingReg v_back_porch; /**< Vertical back porch width register */ 2422810SN/A TimingReg v_data; /**< Vertical data width register */ 2434903SN/A TimingReg v_front_porch; /**< Vertical front porch width register */ 2442810SN/A TimingReg h_sync; /**< Horizontal sync width register */ 2454903SN/A TimingReg h_back_porch; /**< Horizontal back porch width register */ 2464903SN/A TimingReg h_data; /**< Horizontal data width register */ 2474903SN/A TimingReg h_front_porch; /**< Horizontal front porch width reg */ 2484903SN/A PolaritiesReg polarities; /**< Polarities register */ 2494903SN/A CommandReg command; /**< Command register */ 2504903SN/A PixelFormatReg pixel_format; /**< Pixel format register */ 2517667Ssteve.reinhardt@amd.com ColorSelectReg red_select; /**< Red color select register */ 2527667Ssteve.reinhardt@amd.com ColorSelectReg green_select; /**< Green color select register */ 2537667Ssteve.reinhardt@amd.com ColorSelectReg blue_select; /**< Blue color select register */ 2547667Ssteve.reinhardt@amd.com /** @} */ 2555875Ssteve.reinhardt@amd.com 2565875Ssteve.reinhardt@amd.com uint32_t readReg(Addr offset); 2575875Ssteve.reinhardt@amd.com void writeReg(Addr offset, uint32_t value); 2585875Ssteve.reinhardt@amd.com 2595875Ssteve.reinhardt@amd.com PixelConverter pixelConverter() const; 2604903SN/A DisplayTimings displayTimings() const; 2617667Ssteve.reinhardt@amd.com 2627667Ssteve.reinhardt@amd.com void createDmaEngine(); 2637667Ssteve.reinhardt@amd.com 2644903SN/A void cmdEnable(); 2657667Ssteve.reinhardt@amd.com void cmdDisable(); 2667667Ssteve.reinhardt@amd.com 2675875Ssteve.reinhardt@amd.com bool enabled() const { return command.enable; } 2684665SN/A 2695318SN/A public: // Pixel pump callbacks 2705318SN/A bool pxlNext(Pixel &p); 2715318SN/A void pxlVSyncBegin(); 2725318SN/A void pxlVSyncEnd(); 2735875Ssteve.reinhardt@amd.com void pxlUnderrun(); 2742810SN/A void pxlFrameDone(); 2752810SN/A 2762810SN/A protected: // Interrupt handling 2774665SN/A /** 2784665SN/A * Assign new interrupt values and update interrupt signals 2794902SN/A * 2804902SN/A * A new interrupt is scheduled signalled if the set of unmasked 2814665SN/A * interrupts goes empty to non-empty. Conversely, if the set of 2824910SN/A * unmasked interrupts goes from non-empty to empty, the interrupt 2834903SN/A * signal is cleared. 2844903SN/A * 2854903SN/A * @param ints New <i>raw</i> interrupt status 2864903SN/A * @param mask New interrupt mask 2874903SN/A */ 2884903SN/A void setInterrupts(uint32_t ints, uint32_t mask); 2894903SN/A 2904903SN/A /** 2914903SN/A * Convenience function to update the interrupt mask 2924903SN/A * 2934903SN/A * @see setInterrupts 2944903SN/A * @param mask New interrupt mask 2954903SN/A */ 2964903SN/A void intMask(uint32_t mask) { setInterrupts(int_rawstat, mask); } 2974903SN/A 2984903SN/A /** 2994903SN/A * Convenience function to raise a new interrupt 3004903SN/A * 3014902SN/A * @see setInterrupts 3024902SN/A * @param ints Set of interrupts to raise 3034665SN/A */ 3044903SN/A void intRaise(uint32_t ints) { 3054903SN/A setInterrupts(int_rawstat | ints, int_mask); 3064903SN/A } 3074903SN/A 3084903SN/A /** 3094903SN/A * Convenience function to clear interrupts 3104903SN/A * 3114903SN/A * @see setInterrupts 3127667Ssteve.reinhardt@amd.com * @param ints Set of interrupts to clear 3134665SN/A */ 3144903SN/A void intClear(uint32_t ints) { 3154903SN/A setInterrupts(int_rawstat & ~ints, int_mask); 3164902SN/A } 3174665SN/A 3184665SN/A /** Masked interrupt status register */ 3197667Ssteve.reinhardt@amd.com uint32_t intStatus() const { return int_rawstat & int_mask; } 3207667Ssteve.reinhardt@amd.com 3217667Ssteve.reinhardt@amd.com protected: // Pixel output 3227667Ssteve.reinhardt@amd.com class PixelPump : public BasePixelPump 3237667Ssteve.reinhardt@amd.com { 3247667Ssteve.reinhardt@amd.com public: 3257667Ssteve.reinhardt@amd.com PixelPump(HDLcd &p, ClockDomain &pxl_clk, unsigned pixel_chunk) 3267667Ssteve.reinhardt@amd.com : BasePixelPump(p, pxl_clk, pixel_chunk), parent(p) {} 3277667Ssteve.reinhardt@amd.com 3287667Ssteve.reinhardt@amd.com void dumpSettings(); 3294970SN/A 3305875Ssteve.reinhardt@amd.com protected: 3315318SN/A bool nextPixel(Pixel &p) override { return parent.pxlNext(p); } 3324670SN/A 3334670SN/A void onVSyncBegin() override { return parent.pxlVSyncBegin(); } 3347667Ssteve.reinhardt@amd.com void onVSyncEnd() override { return parent.pxlVSyncEnd(); } 3354670SN/A 3364916SN/A void onUnderrun(unsigned x, unsigned y) override { 3374670SN/A parent.pxlUnderrun(); 3384670SN/A } 3394670SN/A 3404670SN/A void onFrameDone() override { parent.pxlFrameDone(); } 3417667Ssteve.reinhardt@amd.com 3424670SN/A protected: 3437667Ssteve.reinhardt@amd.com HDLcd &parent; 3447667Ssteve.reinhardt@amd.com }; 3457667Ssteve.reinhardt@amd.com 3467667Ssteve.reinhardt@amd.com /** Helper to write out bitmaps */ 3477667Ssteve.reinhardt@amd.com Bitmap bmp; 3487667Ssteve.reinhardt@amd.com 3494670SN/A /** Picture of what the current frame buffer looks like */ 3504667SN/A std::ostream *pic; 3514902SN/A 3524902SN/A /** Cached pixel converter, set when the converter is enabled. */ 3534665SN/A PixelConverter conv; 3544665SN/A 3554665SN/A PixelPump pixelPump; 3564665SN/A 3574665SN/A protected: // DMA handling 3584665SN/A class DmaEngine : public DmaReadFifo 3594903SN/A { 3604903SN/A public: 3614665SN/A DmaEngine(HDLcd &_parent, size_t size, 3624665SN/A unsigned request_size, unsigned max_pending, 3634665SN/A size_t line_size, ssize_t line_pitch, unsigned num_lines); 3644903SN/A 3654903SN/A void startFrame(Addr fb_base); 3664665SN/A void abortFrame(); 3674903SN/A void dumpSettings(); 3682810SN/A 3694903SN/A void serialize(CheckpointOut &cp) const override; 3704903SN/A void unserialize(CheckpointIn &cp) override; 3714903SN/A 3724903SN/A protected: 3734903SN/A void onEndOfBlock() override; 3744903SN/A void onIdle() override; 3754903SN/A 3764665SN/A HDLcd &parent; 3774665SN/A const size_t lineSize; 3782810SN/A const ssize_t linePitch; 3792810SN/A const unsigned numLines; 3802810SN/A 3812810SN/A Addr nextLineAddr; 3824670SN/A Addr frameEnd; 3834668SN/A }; 3847667Ssteve.reinhardt@amd.com 3857667Ssteve.reinhardt@amd.com std::unique_ptr<DmaEngine> dmaEngine; 3865270SN/A 3875270SN/A protected: // Statistics 3885270SN/A struct { 3895270SN/A Stats::Scalar underruns; 3905270SN/A } stats; 3915270SN/A}; 3925270SN/A 3935270SN/A#endif 3945270SN/A