hdlcd.hh revision 11091
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 * 458232Snate@binkert.org * This implementation aims to have sufficient detail such that underrun 466216Snate@binkert.org * conditions are reasonable / behave similar to reality. There are two 475338Sstever@gmail.com * 'engines' going at once. First, the DMA engine running at LCD clock 486216Snate@binkert.org * 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 552810SN/A * issuing DMA requests for the rest of the frame and resume normal behavior 566221Snate@binkert.org * 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 584903SN/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 602810SN/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 674903SN/A * doesn't have an AMBA ID as far as I know. That is the only 684908SN/A * bit of the AmbaDmaDevice interface that is irrelevant to it, 695875Ssteve.reinhardt@amd.com * so a fake AMBA ID is used for now. I didn't think inserting 704903SN/A * an extra layer of hierachy between AmbaDmaDevice and 715875Ssteve.reinhardt@amd.com * DmaDevice would be helpful to anyone else, but that may be 724903SN/A * the right answer. 734903SN/A * </ul> 744903SN/A */ 754903SN/A 767669Ssteve.reinhardt@amd.com#ifndef __DEV_ARM_HDLCD_HH__ 777669Ssteve.reinhardt@amd.com#define __DEV_ARM_HDLCD_HH__ 787669Ssteve.reinhardt@amd.com 797669Ssteve.reinhardt@amd.com#include <fstream> 804903SN/A#include <memory> 814903SN/A 825318SN/A#include "base/bitmap.hh" 834908SN/A#include "base/framebuffer.hh" 845318SN/A#include "dev/arm/amba_device.hh" 854908SN/A#include "dev/pixelpump.hh" 864908SN/A#include "sim/serialize.hh" 874908SN/A 884908SN/Aclass VncInput; 894908SN/Astruct HDLcdParams; 904903SN/Aclass HDLcdPixelPump; 914903SN/A 925875Ssteve.reinhardt@amd.comclass HDLcd: public AmbaDmaDevice 934903SN/A{ 944903SN/A public: 954903SN/A HDLcd(const HDLcdParams *p); 967667Ssteve.reinhardt@amd.com ~HDLcd(); 977667Ssteve.reinhardt@amd.com 987667Ssteve.reinhardt@amd.com void regStats() M5_ATTR_OVERRIDE; 997667Ssteve.reinhardt@amd.com 1007667Ssteve.reinhardt@amd.com void serialize(CheckpointOut &cp) const M5_ATTR_OVERRIDE; 1017667Ssteve.reinhardt@amd.com void unserialize(CheckpointIn &cp) M5_ATTR_OVERRIDE; 1027667Ssteve.reinhardt@amd.com 1037667Ssteve.reinhardt@amd.com void drainResume() M5_ATTR_OVERRIDE; 1047667Ssteve.reinhardt@amd.com 1057669Ssteve.reinhardt@amd.com public: // IO device interface 1067669Ssteve.reinhardt@amd.com Tick read(PacketPtr pkt) M5_ATTR_OVERRIDE; 1077669Ssteve.reinhardt@amd.com Tick write(PacketPtr pkt) M5_ATTR_OVERRIDE; 1087667Ssteve.reinhardt@amd.com 1097667Ssteve.reinhardt@amd.com AddrRangeList getAddrRanges() const M5_ATTR_OVERRIDE { return addrRanges; } 1107667Ssteve.reinhardt@amd.com 1117667Ssteve.reinhardt@amd.com protected: // Parameters 1124903SN/A VncInput *vnc; 1134903SN/A 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 1207667Ssteve.reinhardt@amd.com /** ARM HDLcd register offsets */ 1214903SN/A enum RegisterOffset { 1224903SN/A Version = 0x0000, 1234903SN/A Int_RawStat = 0x0010, 1244903SN/A Int_Clear = 0x0014, 1254903SN/A Int_Mask = 0x0018, 1264903SN/A Int_Status = 0x001C, 1272810SN/A Fb_Base = 0x0100, 1284908SN/A Fb_Line_Length = 0x0104, 1294908SN/A Fb_Line_Count = 0x0108, 1304908SN/A Fb_Line_Pitch = 0x010C, 1314908SN/A Bus_Options = 0x0110, 1325318SN/A V_Sync = 0x0200, 1335318SN/A V_Back_Porch = 0x0204, 1345318SN/A V_Data = 0x0208, 1355318SN/A V_Front_Porch = 0x020C, 1365318SN/A H_Sync = 0x0210, 1374908SN/A H_Back_Porch = 0x0214, 1384908SN/A H_Data = 0x0218, 1394908SN/A H_Front_Porch = 0x021C, 1404908SN/A Polarities = 0x0220, 1414908SN/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 */ 1494920SN/A static constexpr size_t BUS_OPTIONS_RESETV = 0x408; 1504920SN/A 1514920SN/A /** Reset value for Version register */ 1524920SN/A static constexpr size_t VERSION_RESETV = 0x1CDC0000; 1534920SN/A 1544920SN/A /** AXI port width in bytes */ 1554920SN/A static constexpr size_t AXI_PORT_WIDTH = 8; 1564908SN/A 1575314SN/A /** max number of beats delivered in one dma burst */ 1585314SN/A static constexpr size_t MAX_BURST_LEN = 16; 1595314SN/A 1605314SN/A /** Maximum number of bytes per pixel */ 1615314SN/A static constexpr size_t MAX_PIXEL_SIZE = 4; 1625875Ssteve.reinhardt@amd.com 1635875Ssteve.reinhardt@amd.com /** 1645875Ssteve.reinhardt@amd.com * @name RegisterFieldLayouts 1655875Ssteve.reinhardt@amd.com * Bit layout declarations for multi-field registers. 1665875Ssteve.reinhardt@amd.com */ 1675875Ssteve.reinhardt@amd.com /**@{*/ 1685875Ssteve.reinhardt@amd.com BitUnion32(VersionReg) 1695875Ssteve.reinhardt@amd.com Bitfield<7,0> version_minor; 1705314SN/A Bitfield<15,8> version_major; 1715314SN/A Bitfield<31,16> product_id; 1725314SN/A EndBitUnion(VersionReg) 1735314SN/A 1745314SN/A static constexpr uint32_t INT_DMA_END = (1UL << 0); 1755314SN/A static constexpr uint32_t INT_BUS_ERROR = (1UL << 1); 1764666SN/A static constexpr uint32_t INT_VSYNC = (1UL << 2); 1774871SN/A static constexpr uint32_t INT_UNDERRUN = (1UL << 3); 1782810SN/A 1792885SN/A BitUnion32(FbLineCountReg) 1804626SN/A Bitfield<11,0> fb_line_count; 1814871SN/A Bitfield<31,12> reserved_31_12; 1824666SN/A EndBitUnion(FbLineCountReg) 1834626SN/A 1845730SSteve.Reinhardt@amd.com BitUnion32(BusOptsReg) 1854626SN/A Bitfield<4,0> burst_len; 1864626SN/A Bitfield<7,5> reserved_7_5; 1874908SN/A Bitfield<11,8> max_outstanding; 1884626SN/A Bitfield<31,12> reserved_31_12; 1894626SN/A EndBitUnion(BusOptsReg) 1905875Ssteve.reinhardt@amd.com 1914626SN/A BitUnion32(TimingReg) 1925875Ssteve.reinhardt@amd.com Bitfield<11,0> val; 1935875Ssteve.reinhardt@amd.com Bitfield<31,12> reserved_31_12; 1945875Ssteve.reinhardt@amd.com EndBitUnion(TimingReg) 1955875Ssteve.reinhardt@amd.com 1964903SN/A BitUnion32(PolaritiesReg) 1974668SN/A Bitfield<0> vsync_polarity; 1982810SN/A Bitfield<1> hsync_polarity; 1992810SN/A Bitfield<2> dataen_polarity; 2004908SN/A Bitfield<3> data_polarity; 2015318SN/A Bitfield<4> pxlclk_polarity; 2025318SN/A Bitfield<31,5> reserved_31_5; 2035318SN/A EndBitUnion(PolaritiesReg) 2045318SN/A 2055318SN/A BitUnion32(CommandReg) 2065318SN/A Bitfield<0> enable; 2075318SN/A Bitfield<31,1> reserved_31_1; 2085318SN/A EndBitUnion(CommandReg) 2095318SN/A 2105318SN/A BitUnion32(PixelFormatReg) 2114908SN/A Bitfield<2,0> reserved_2_0; 2127667Ssteve.reinhardt@amd.com Bitfield<4,3> bytes_per_pixel; 2134908SN/A Bitfield<30,5> reserved_30_5; 2144908SN/A Bitfield<31> big_endian; 2155730SSteve.Reinhardt@amd.com EndBitUnion(PixelFormatReg) 2164908SN/A 2174908SN/A BitUnion32(ColorSelectReg) 2184908SN/A Bitfield<4,0> offset; 2194908SN/A 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; 2237667Ssteve.reinhardt@amd.com Bitfield<31,24> reserved_31_24; 2247667Ssteve.reinhardt@amd.com EndBitUnion(ColorSelectReg) 2257667Ssteve.reinhardt@amd.com /**@}*/ 2267667Ssteve.reinhardt@amd.com 2274908SN/A /** 2284908SN/A * @name HDLCDRegisters 2294908SN/A * HDLCD register contents. 2304908SN/A */ 2314908SN/A /**@{*/ 2324908SN/A const VersionReg version; /**< Version register */ 2334908SN/A uint32_t int_rawstat; /**< Interrupt raw status register */ 2344908SN/A uint32_t int_mask; /**< Interrupt mask register */ 2354908SN/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 */ 2394903SN/A BusOptsReg bus_options; /**< Bus options register */ 2404903SN/A TimingReg v_sync; /**< Vertical sync width register */ 2414903SN/A TimingReg v_back_porch; /**< Vertical back porch width register */ 2422810SN/A TimingReg v_data; /**< Vertical data width register */ 2432810SN/A TimingReg v_front_porch; /**< Vertical front porch width register */ 2442810SN/A TimingReg h_sync; /**< Horizontal sync width register */ 2452810SN/A TimingReg h_back_porch; /**< Horizontal back porch width register */ 2462810SN/A TimingReg h_data; /**< Horizontal data width register */ 2472810SN/A TimingReg h_front_porch; /**< Horizontal front porch width reg */ 2482810SN/A PolaritiesReg polarities; /**< Polarities register */ 2492810SN/A CommandReg command; /**< Command register */ 2504903SN/A PixelFormatReg pixel_format; /**< Pixel format register */ 2512810SN/A ColorSelectReg red_select; /**< Red color select register */ 2524903SN/A ColorSelectReg green_select; /**< Green color select register */ 2534903SN/A ColorSelectReg blue_select; /**< Blue color select register */ 2544903SN/A /** @} */ 2554903SN/A 2564903SN/A uint32_t readReg(Addr offset); 2574903SN/A void writeReg(Addr offset, uint32_t value); 2587667Ssteve.reinhardt@amd.com 2597667Ssteve.reinhardt@amd.com PixelConverter pixelConverter() const; 2607667Ssteve.reinhardt@amd.com DisplayTimings displayTimings() const; 2617667Ssteve.reinhardt@amd.com 2625875Ssteve.reinhardt@amd.com void createDmaEngine(); 2635875Ssteve.reinhardt@amd.com 2645875Ssteve.reinhardt@amd.com void cmdEnable(); 2655875Ssteve.reinhardt@amd.com void cmdDisable(); 2665875Ssteve.reinhardt@amd.com 2674903SN/A bool enabled() const { return command.enable; } 2687667Ssteve.reinhardt@amd.com 2697667Ssteve.reinhardt@amd.com public: // Pixel pump callbacks 2707667Ssteve.reinhardt@amd.com bool pxlNext(Pixel &p); 2714903SN/A void pxlVSyncBegin(); 2727667Ssteve.reinhardt@amd.com void pxlVSyncEnd(); 2737667Ssteve.reinhardt@amd.com void pxlUnderrun(); 2745875Ssteve.reinhardt@amd.com void pxlFrameDone(); 2754665SN/A 2765318SN/A protected: // Interrupt handling 2775318SN/A /** 2785318SN/A * Assign new interrupt values and update interrupt signals 2795318SN/A * 2805875Ssteve.reinhardt@amd.com * A new interrupt is scheduled signalled if the set of unmasked 2812810SN/A * interrupts goes empty to non-empty. Conversely, if the set of 2822810SN/A * unmasked interrupts goes from non-empty to empty, the interrupt 2832810SN/A * signal is cleared. 2844665SN/A * 2854665SN/A * @param ints New <i>raw</i> interrupt status 2864902SN/A * @param mask New interrupt mask 2874902SN/A */ 2884665SN/A void setInterrupts(uint32_t ints, uint32_t mask); 2894910SN/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 * 3014903SN/A * @see setInterrupts 3024903SN/A * @param ints Set of interrupts to raise 3034903SN/A */ 3044903SN/A void intRaise(uint32_t ints) { 3054903SN/A setInterrupts(int_rawstat | ints, int_mask); 3064903SN/A } 3074903SN/A 3084902SN/A /** 3094902SN/A * Convenience function to clear interrupts 3104665SN/A * 3114903SN/A * @see setInterrupts 3124903SN/A * @param ints Set of interrupts to clear 3134903SN/A */ 3144903SN/A void intClear(uint32_t ints) { 3154903SN/A setInterrupts(int_rawstat & ~ints, int_mask); 3164903SN/A } 3174903SN/A 3184903SN/A /** Masked interrupt status register */ 3197667Ssteve.reinhardt@amd.com const uint32_t intStatus() const { return int_rawstat & int_mask; } 3204665SN/A 3214903SN/A protected: // Pixel output 3224903SN/A class PixelPump : public BasePixelPump 3234902SN/A { 3244665SN/A public: 3254665SN/A 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(); 3297667Ssteve.reinhardt@amd.com 3307667Ssteve.reinhardt@amd.com protected: 3317667Ssteve.reinhardt@amd.com bool nextPixel(Pixel &p) M5_ATTR_OVERRIDE { return parent.pxlNext(p); } 3327667Ssteve.reinhardt@amd.com 3337667Ssteve.reinhardt@amd.com void onVSyncBegin() M5_ATTR_OVERRIDE { return parent.pxlVSyncBegin(); } 3347667Ssteve.reinhardt@amd.com void onVSyncEnd() M5_ATTR_OVERRIDE { return parent.pxlVSyncEnd(); } 3357667Ssteve.reinhardt@amd.com 3364970SN/A void onUnderrun(unsigned x, unsigned y) M5_ATTR_OVERRIDE { 3377823Ssteve.reinhardt@amd.com parent.pxlUnderrun(); 3385318SN/A } 3394670SN/A 3404670SN/A void onFrameDone() M5_ATTR_OVERRIDE { parent.pxlFrameDone(); } 3417667Ssteve.reinhardt@amd.com 3424670SN/A protected: 3434916SN/A HDLcd &parent; 3444670SN/A }; 3454670SN/A 3464670SN/A /** Helper to write out bitmaps */ 3474670SN/A Bitmap bmp; 3487667Ssteve.reinhardt@amd.com 3494670SN/A /** Picture of what the current frame buffer looks like */ 3507667Ssteve.reinhardt@amd.com std::ostream *pic; 3517667Ssteve.reinhardt@amd.com 3527667Ssteve.reinhardt@amd.com /** Cached pixel converter, set when the converter is enabled. */ 3537667Ssteve.reinhardt@amd.com PixelConverter conv; 3547667Ssteve.reinhardt@amd.com 3557667Ssteve.reinhardt@amd.com PixelPump pixelPump; 3564670SN/A 3574667SN/A protected: // DMA handling 3584902SN/A class DmaEngine : public DmaReadFifo 3594902SN/A { 3604665SN/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); 3644665SN/A 3654665SN/A void startFrame(Addr fb_base); 3664903SN/A void abortFrame(); 3674903SN/A void dumpSettings(); 3684665SN/A 3694665SN/A void serialize(CheckpointOut &cp) const M5_ATTR_OVERRIDE; 3704665SN/A void unserialize(CheckpointIn &cp) M5_ATTR_OVERRIDE; 3714903SN/A 3724903SN/A protected: 3734665SN/A void onEndOfBlock() M5_ATTR_OVERRIDE; 3744903SN/A void onIdle() M5_ATTR_OVERRIDE; 3752810SN/A 3764903SN/A HDLcd &parent; 3774903SN/A const size_t lineSize; 3784903SN/A const ssize_t linePitch; 3794903SN/A const unsigned numLines; 3804903SN/A 3814903SN/A Addr nextLineAddr; 3827823Ssteve.reinhardt@amd.com Addr frameEnd; 3834665SN/A }; 3844665SN/A 3852810SN/A std::unique_ptr<DmaEngine> dmaEngine; 3862810SN/A 3872810SN/A protected: // Statistics 3882810SN/A struct { 3894670SN/A Stats::Scalar underruns; 3904668SN/A } stats; 3917667Ssteve.reinhardt@amd.com}; 3927667Ssteve.reinhardt@amd.com 3935270SN/A#endif 3945270SN/A