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