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