hdlcd.hh revision 10839:10cac0f0f419
11689SN/A/*
210330Smitch.hayenga@arm.com * Copyright (c) 2010-2013, 2015 ARM Limited
38842Smrinmoy.ghosh@arm.com * All rights reserved
48842Smrinmoy.ghosh@arm.com *
58842Smrinmoy.ghosh@arm.com * The license below extends only to copyright in the software and shall
68842Smrinmoy.ghosh@arm.com * not be construed as granting a license to any other intellectual
78842Smrinmoy.ghosh@arm.com * property including but not limited to intellectual property relating
88842Smrinmoy.ghosh@arm.com * to a hardware implementation of the functionality of the software
98842Smrinmoy.ghosh@arm.com * licensed hereunder.  You may use the software subject to the license
108842Smrinmoy.ghosh@arm.com * terms below provided that you ensure that this notice is replicated
118842Smrinmoy.ghosh@arm.com * unmodified and in its entirety in all distributions of the software,
128842Smrinmoy.ghosh@arm.com * modified or unmodified, in source code or in binary form.
138842Smrinmoy.ghosh@arm.com *
142345SN/A * Redistribution and use in source and binary forms, with or without
151689SN/A * modification, are permitted provided that the following conditions are
161689SN/A * met: redistributions of source code must retain the above copyright
171689SN/A * notice, this list of conditions and the following disclaimer;
181689SN/A * redistributions in binary form must reproduce the above copyright
191689SN/A * notice, this list of conditions and the following disclaimer in the
201689SN/A * documentation and/or other materials provided with the distribution;
211689SN/A * neither the name of the copyright holders nor the names of its
221689SN/A * contributors may be used to endorse or promote products derived from
231689SN/A * this software without specific prior written permission.
241689SN/A *
251689SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
261689SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
271689SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
281689SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
291689SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
301689SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
311689SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
321689SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
331689SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
341689SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
351689SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
361689SN/A *
371689SN/A * Authors: Chris Emmons
381689SN/A */
392665SN/A
402665SN/A
419480Snilay@cs.wisc.edu/** @file
429480Snilay@cs.wisc.edu * Implementiation of the ARM HDLcd controller.
431689SN/A *
441689SN/A * This implementation aims to have sufficient detail such that underrun
459480Snilay@cs.wisc.edu * conditions are reasonable / behave similar to reality.  There are two
469480Snilay@cs.wisc.edu * 'engines' going at once.  First, the DMA engine running at LCD clock
471062SN/A * frequency is responsible for filling the controller's internal buffer.
486216SN/A * The second engine runs at the pixel clock frequency and reads the pixels
496216SN/A * out of the internal buffer.  The pixel rendering engine uses front / back
506216SN/A * porch and sync delays between lines and frames.
519480Snilay@cs.wisc.edu *
529480Snilay@cs.wisc.edu * If the pixel rendering engine does not have a pixel to display, it will
5310785Sgope@wisc.edu * cause an underrun event.  The HDLcd controller, per spec, will stop
541062SN/A * issuing DMA requests for the rest of the frame and resume normal behavior
552345SN/A * on the subsequent frame.  What pixels are rendered upon an underrun
562345SN/A * condition is different than the real hardware; while the user will see
572345SN/A * artifacts (previous frame mixed with current frame), it is not the same
582345SN/A * behavior as real hardware which repeats the last pixel value for the rest
592345SN/A * of the current frame.  This compromise was made to save on memory and
602345SN/A * complexity and assumes that it is not important to accurately model the
612345SN/A * content of an underrun frame.
622345SN/A *
632345SN/A * KNOWN ISSUES
649480Snilay@cs.wisc.edu * 1.  The default kernel driver used in testing sets the line count to one
651062SN/A * less than the expected 768.  However, it also sets the v_count to 767.
661062SN/A * The controller specifies that 1 should be added to v_count but does not
671062SN/A * specify adding 1 to the line count.  The driver is probably wrong.
681062SN/A * However, to sync these two numbers up, this model uses fb_line_count and
691062SN/A * fb_line_length rather than using v_data or h_data values to determine the
7010785Sgope@wisc.edu * width and height of the frame; those values are ignored.
711062SN/A * 2.  The HDLcd is implemented here as an AmbaDmaDevice, but it doesn't have
721062SN/A * an AMBA ID as far as I know.  That is the only bit of the AmbaDmaDevice
731062SN/A * interface that is irrelevant to it, so a fake AMBA ID is used for now.
742345SN/A * I didn't think inserting an extra layer of hierachy between AmbaDmaDevice
752345SN/A * and DmaDevice would be helpful to anyone else, but that may be the right
761062SN/A * answer.
772345SN/A * 3.  The internal buffer size is either 1 or 2 KB depending on which
781062SN/A * specification is referenced for the different Versatile Express tiles.
791062SN/A * This implementation uses the larger 2 KB buffer by default.
809480Snilay@cs.wisc.edu */
812345SN/A
822345SN/A#ifndef __DEV_ARM_HDLCD_HH__
832345SN/A#define __DEV_ARM_HDLCD_HH__
842345SN/A
852345SN/A#include <fstream>
862345SN/A#include <memory>
872345SN/A
8810785Sgope@wisc.edu#include "base/bitmap.hh"
898842Smrinmoy.ghosh@arm.com#include "base/framebuffer.hh"
908842Smrinmoy.ghosh@arm.com#include "dev/arm/amba_device.hh"
918842Smrinmoy.ghosh@arm.com#include "params/HDLcd.hh"
928842Smrinmoy.ghosh@arm.com#include "sim/serialize.hh"
938842Smrinmoy.ghosh@arm.com
948842Smrinmoy.ghosh@arm.comclass VncInput;
958842Smrinmoy.ghosh@arm.com
969480Snilay@cs.wisc.educlass HDLcd: public AmbaDmaDevice
971062SN/A{
981062SN/A  protected:
991062SN/A    /** fake AMBA ID -- unused */
1001062SN/A    static const uint64_t AMBA_ID       = ULL(0xb105f00d00141000);
1012345SN/A
1022345SN/A    /** ARM HDLcd register offsets */
1038842Smrinmoy.ghosh@arm.com    enum RegisterOffset {
1048842Smrinmoy.ghosh@arm.com        Version          = 0x0000,
1051062SN/A        Int_RawStat      = 0x0010,
1069480Snilay@cs.wisc.edu        Int_Clear        = 0x0014,
1071062SN/A        Int_Mask         = 0x0018,
10810330Smitch.hayenga@arm.com        Int_Status       = 0x001C,
10910330Smitch.hayenga@arm.com        Fb_Base          = 0x0100,
1102345SN/A        Fb_Line_Length   = 0x0104,
1112345SN/A        Fb_Line_Count    = 0x0108,
1122345SN/A        Fb_Line_Pitch    = 0x010C,
1132345SN/A        Bus_Options      = 0x0110,
1142345SN/A        V_Sync           = 0x0200,
1152345SN/A        V_Back_Porch     = 0x0204,
1162345SN/A        V_Data           = 0x0208,
1172345SN/A        V_Front_Porch    = 0x020C,
1181684SN/A        H_Sync           = 0x0210,
1191062SN/A        H_Back_Porch     = 0x0214,
1201062SN/A        H_Data           = 0x0218,
1212345SN/A        H_Front_Porch    = 0x021C,
1222345SN/A        Polarities       = 0x0220,
1232345SN/A        Command          = 0x0230,
1242345SN/A        Pixel_Format     = 0x0240,
1252345SN/A        Red_Select       = 0x0244,
1261062SN/A        Green_Select     = 0x0248,
1271062SN/A        Blue_Select      = 0x024C };
1282345SN/A
1292345SN/A    /** Reset value for Bus_Options register */
1302345SN/A    static const size_t BUS_OPTIONS_RESETV = 0x408;
1312345SN/A
1321062SN/A    /** Reset value for Version register */
1331062SN/A    static const size_t VERSION_RESETV = 0x1CDC0000;
1342345SN/A
1352345SN/A    /** max number of outstanding DMA requests possible */
1361062SN/A    static const size_t MAX_OUTSTANDING_DMA_REQ_CAPACITY = 16;
1372345SN/A
1382345SN/A    /** max number of beats delivered in one dma burst */
1392345SN/A    static const size_t MAX_BURST_LEN = 16;
1402345SN/A
1412345SN/A    /** size of internal buffer in bytes */
1422345SN/A    static const size_t PIXEL_BUFFER_CAPACITY = 2048;
1432345SN/A
1442345SN/A    /** AXI port width in bytes */
1452345SN/A    static const size_t AXI_PORT_WIDTH = 8;
1462345SN/A
1472345SN/A    static const size_t MAX_BURST_SIZE = MAX_BURST_LEN * AXI_PORT_WIDTH;
1482345SN/A
1492345SN/A    /**
1502345SN/A     * @name RegisterFieldLayouts
1512345SN/A     * Bit layout declarations for multi-field registers.
1522345SN/A     */
1532345SN/A    /**@{*/
1542345SN/A    BitUnion32(VersionReg)
1552345SN/A        Bitfield<7,0>   version_minor;
1562345SN/A        Bitfield<15,8>  version_major;
1572345SN/A        Bitfield<31,16> product_id;
1582345SN/A    EndBitUnion(VersionReg)
1592345SN/A
1602345SN/A    BitUnion32(InterruptReg)
1612345SN/A        Bitfield<0> dma_end;
1622345SN/A        Bitfield<1> bus_error;
1632345SN/A        Bitfield<2> vsync;
1642345SN/A        Bitfield<3> underrun;
1652345SN/A    EndBitUnion(InterruptReg)
1662345SN/A
1672345SN/A    BitUnion32(FbLineCountReg)
1682345SN/A        Bitfield<11,0>  fb_line_count;
1692345SN/A        Bitfield<31,12> reserved_31_12;
17011098Slukefahr@umich.edu    EndBitUnion(FbLineCountReg)
1718842Smrinmoy.ghosh@arm.com
1722345SN/A    BitUnion32(BusOptsReg)
1732345SN/A        Bitfield<4,0>   burst_len;
1742345SN/A        Bitfield<7,5>   reserved_7_5;
1752345SN/A        Bitfield<11,8>  max_outstanding;
1761062SN/A        Bitfield<31,12> reserved_31_12;
1778842Smrinmoy.ghosh@arm.com    EndBitUnion(BusOptsReg)
1788842Smrinmoy.ghosh@arm.com
1791062SN/A    BitUnion32(TimingReg)
1802292SN/A        Bitfield<11,0>  val;
1811062SN/A        Bitfield<31,12> reserved_31_12;
1829360SE.Tomusk@sms.ed.ac.uk    EndBitUnion(TimingReg)
1831684SN/A
1841062SN/A    BitUnion32(PolaritiesReg)
1859360SE.Tomusk@sms.ed.ac.uk        Bitfield<0>    vsync_polarity;
1862356SN/A        Bitfield<1>    hsync_polarity;
1872356SN/A        Bitfield<2>    dataen_polarity;
1881062SN/A        Bitfield<3>    data_polarity;
1891684SN/A        Bitfield<4>    pxlclk_polarity;
1901062SN/A        Bitfield<31,5> reserved_31_5;
1911062SN/A    EndBitUnion(PolaritiesReg)
1922292SN/A
1931062SN/A    BitUnion32(CommandReg)
1949360SE.Tomusk@sms.ed.ac.uk        Bitfield<0>    enable;
1951684SN/A        Bitfield<31,1> reserved_31_1;
1961062SN/A    EndBitUnion(CommandReg)
1979360SE.Tomusk@sms.ed.ac.uk
1981684SN/A    BitUnion32(PixelFormatReg)
1991062SN/A        Bitfield<2,0>  reserved_2_0;
2001062SN/A        Bitfield<4,3>  bytes_per_pixel;
2012292SN/A        Bitfield<30,5> reserved_30_5;
2021062SN/A        Bitfield<31>   big_endian;
2039360SE.Tomusk@sms.ed.ac.uk    EndBitUnion(PixelFormatReg)
2041684SN/A
2051062SN/A    BitUnion32(ColorSelectReg)
2061062SN/A        Bitfield<4,0>   offset;
2071684SN/A        Bitfield<7,5>   reserved_7_5;
2081062SN/A        Bitfield<11,8>  size;
2099360SE.Tomusk@sms.ed.ac.uk        Bitfield<15,12> reserved_15_12;
2109360SE.Tomusk@sms.ed.ac.uk        Bitfield<23,16> default_color;
2119360SE.Tomusk@sms.ed.ac.uk        Bitfield<31,24> reserved_31_24;
2121684SN/A    EndBitUnion(ColorSelectReg)
2131062SN/A    /**@}*/
2149360SE.Tomusk@sms.ed.ac.uk
2159360SE.Tomusk@sms.ed.ac.uk    /**
2161684SN/A     * @name HDLCDRegisters
2171062SN/A     * HDLCD register contents.
2189360SE.Tomusk@sms.ed.ac.uk     */
2199360SE.Tomusk@sms.ed.ac.uk    /**@{*/
2201062SN/A    VersionReg version;             /**< Version register */
2211062SN/A    InterruptReg int_rawstat;       /**< Interrupt raw status register */
2229360SE.Tomusk@sms.ed.ac.uk    InterruptReg int_clear;         /**< Interrupt clear register */
2239360SE.Tomusk@sms.ed.ac.uk    InterruptReg int_mask;          /**< Interrupt mask register */
2249360SE.Tomusk@sms.ed.ac.uk    InterruptReg int_status;        /**< Interrupt status register */
2259360SE.Tomusk@sms.ed.ac.uk    uint32_t fb_base;               /**< Frame buffer base address register */
2269360SE.Tomusk@sms.ed.ac.uk    uint32_t fb_line_length;        /**< Frame buffer Line length register */
2279360SE.Tomusk@sms.ed.ac.uk    FbLineCountReg fb_line_count;   /**< Frame buffer Line count register */
2289360SE.Tomusk@sms.ed.ac.uk    uint32_t fb_line_pitch;         /**< Frame buffer Line pitch register */
2299360SE.Tomusk@sms.ed.ac.uk    BusOptsReg bus_options;         /**< Bus options register */
2301062SN/A    TimingReg v_sync;               /**< Vertical sync width register */
2312292SN/A    TimingReg v_back_porch;         /**< Vertical back porch width register */
2321062SN/A    TimingReg v_data;               /**< Vertical data width register */
2339360SE.Tomusk@sms.ed.ac.uk    TimingReg v_front_porch;        /**< Vertical front porch width register */
2341684SN/A    TimingReg h_sync;               /**< Horizontal sync width register */
2351062SN/A    TimingReg h_back_porch;         /**< Horizontal back porch width register */
2369360SE.Tomusk@sms.ed.ac.uk    TimingReg h_data;               /**< Horizontal data width register */
2371684SN/A    TimingReg h_front_porch;        /**< Horizontal front porch width reg */
2381062SN/A    PolaritiesReg polarities;       /**< Polarities register */
2399360SE.Tomusk@sms.ed.ac.uk    CommandReg command;             /**< Command register */
2401062SN/A    PixelFormatReg pixel_format;    /**< Pixel format register */
2411062SN/A    ColorSelectReg red_select;      /**< Red color select register */
2429360SE.Tomusk@sms.ed.ac.uk    ColorSelectReg green_select;    /**< Green color select register */
2439360SE.Tomusk@sms.ed.ac.uk    ColorSelectReg blue_select;     /**< Blue color select register */
2449360SE.Tomusk@sms.ed.ac.uk    /** @} */
2451062SN/A
2461062SN/A    /** Pixel clock period */
2479480Snilay@cs.wisc.edu    const Tick pixelClock;
248
249    FrameBuffer fb;
250
251    /** VNC server */
252    VncInput *vnc;
253
254    /** Helper to write out bitmaps */
255    Bitmap bmp;
256
257    /** Picture of what the current frame buffer looks like */
258    std::ostream *pic;
259
260    /**
261     * Event wrapper for dmaDone()
262     *
263     * This event call pushes its this pointer onto the freeDoneEvent vector
264     * and calls dmaDone() when triggered.  While most of the time the burst
265     * length of a transaction will be the max burst length set by the driver,
266     * any trailing bytes must be handled with smaller lengths thus requiring
267     * the configurable burst length option.
268     */
269    class DmaDoneEvent : public Event
270    {
271      private:
272        /** Reference to HDLCD that issued the corresponding DMA transaction */
273        HDLcd &obj;
274
275        /** Transaction size */
276        size_t transSize;
277
278      public:
279        /**
280         * Constructor.
281         *
282         * @param _obj HDLCD that issued the corresponding DMA transaction
283         */
284        DmaDoneEvent(HDLcd *_obj)
285            : Event(), obj(*_obj), transSize(0) {}
286
287        /**
288         * Sets the size of this transaction.
289         *
290         * @param len size of the transaction in bytes
291         */
292        void setTransactionSize(size_t len) {
293            transSize = len;
294        }
295
296        /**
297         * Gets the size of this transaction.
298         *
299         * @return size of this transaction in bytes
300         */
301        size_t getTransactionSize() const {
302            return transSize;
303        }
304
305        void process() {
306            obj.dmaDone(this);
307        }
308
309        const std::string name() const {
310            return obj.name() + ".DmaDoneEvent";
311        }
312    };
313
314    /** Start time for frame buffer dma read */
315    Tick frameReadStartTime;
316
317    /** Starting address for the current frame */
318    Addr dmaStartAddr;
319
320    /** Next address the dma should read from */
321    Addr dmaCurAddr;
322
323    /** One byte past the address of the last byte the dma should read
324      * from */
325    Addr dmaMaxAddr;
326
327    /** Number of pending dma reads */
328    size_t dmaPendingNum;
329
330    /** Flag indicating whether current frame has underrun */
331    bool frameUnderrun;
332
333    /** HDLcd virtual display buffer */
334    std::vector<uint8_t> virtualDisplayBuffer;
335
336    /** Size of the pixel buffer */
337    size_t pixelBufferSize;
338
339    /** Index of the next pixel to render */
340    size_t pixelIndex;
341
342    /** Flag indicating whether video parameters need updating */
343    bool doUpdateParams;
344
345    /** Flag indicating whether a frame read / display is in progress */
346    bool frameUnderway;
347
348    /**
349     * Number of bytes in flight from DMA that have not reached the pixel
350     * buffer yet
351     */
352    uint32_t dmaBytesInFlight;
353
354    /**
355     * Gets the number of oustanding DMA transactions allowed on the bus at a
356     * time.
357     *
358     * @return gets the driver-specified number of outstanding DMA transactions
359     *         from the hdlcd controller that are allowed on the bus at a time
360     */
361    inline uint16_t maxOutstandingDma() const {
362        return bus_options.max_outstanding;
363    }
364
365    /**
366     * Gets the number of bytes free in the pixel buffer.
367     *
368     * @return number of bytes free in the internal pixel buffer
369     */
370    inline uint32_t bytesFreeInPixelBuffer() const {
371        return PIXEL_BUFFER_CAPACITY - (pixelBufferSize + dmaBytesInFlight);
372    }
373
374    /**
375     * Gets the number of beats-per-burst for bus transactions.
376     *
377     * @return number of beats-per-burst per HDLcd DMA transaction
378     */
379    inline size_t dmaBurstLength() const {
380        assert(bus_options.burst_len <= MAX_BURST_LEN);
381        return bus_options.burst_len;
382    }
383
384    /**
385     * Gets the number of bytes per pixel.
386     *
387     * @return bytes per pixel
388     */
389    inline size_t bytesPerPixel() const {
390        return pixel_format.bytes_per_pixel + 1;
391    }
392
393    /**
394     * Gets frame buffer width.
395     *
396     * @return frame buffer width (pixels per line)
397     */
398    inline size_t width() const {
399        return fb_line_length / bytesPerPixel();
400    }
401
402    /**
403     * Gets frame buffer height.
404     *
405     * @return frame buffer height (lines per panel)
406     */
407    inline size_t height() const {
408        return fb_line_count.fb_line_count;
409    }
410
411    inline size_t area() const { return height() * width(); }
412
413    /**
414     * Gets the total number of pixel clocks per display line.
415     *
416     * @return number of pixel clocks per display line including porch delays
417     *         and horizontal sync time
418     */
419    inline uint64_t PClksPerLine() const {
420        return h_back_porch.val + 1 +
421               h_data.val + 1 +
422               h_front_porch.val + 1 +
423               h_sync.val + 1;
424    }
425
426    /** Send updated parameters to the vnc server */
427    void updateVideoParams(bool unserializing);
428
429    /** Generates an interrupt */
430    void generateInterrupt();
431
432    /** Start reading the next frame */
433    void startFrame();
434
435    /** End of frame reached */
436    void endFrame();
437
438    /** Generate DMA read requests from frame buffer into pixel buffer */
439    void fillPixelBuffer();
440
441    /** DMA done event */
442    void dmaDone(DmaDoneEvent *event);
443
444    /** Called when it is time to render a pixel */
445    void renderPixel();
446
447    PixelConverter pixelConverter() const;
448
449    /** Start of frame event */
450    EventWrapper<HDLcd, &HDLcd::startFrame> startFrameEvent;
451
452    /** End of frame event */
453    EventWrapper<HDLcd, &HDLcd::endFrame> endFrameEvent;
454
455    /** Pixel render event */
456    EventWrapper<HDLcd, &HDLcd::renderPixel> renderPixelEvent;
457
458    /** Fill fifo */
459    EventWrapper<HDLcd, &HDLcd::fillPixelBuffer> fillPixelBufferEvent;
460
461    /** Wrapper to create an event out of the interrupt */
462    EventWrapper<HDLcd, &HDLcd::generateInterrupt> intEvent;
463
464    /**@{*/
465    /**
466     * All pre-allocated DMA done events
467     *
468     * The HDLCD model preallocates maxOutstandingDma() number of
469     * DmaDoneEvents to avoid having to heap allocate every single
470     * event when it is needed. In order to keep track of which events
471     * are in flight and which are ready to be used, we use two
472     * different vectors. dmaDoneEventAll contains <i>all</i>
473     * DmaDoneEvents that the object may use, while dmaDoneEventFree
474     * contains a list of currently <i>unused</i> events. When an
475     * event needs to be scheduled, the last element of the
476     * dmaDoneEventFree is used and removed from the list. When an
477     * event fires, it is added to the end of the
478     * dmaEventFreeList. dmaDoneEventAll is never used except for in
479     * initialization and serialization.
480     */
481    std::vector<DmaDoneEvent> dmaDoneEventAll;
482
483    /** Unused DMA done events that are ready to be scheduled */
484    std::vector<DmaDoneEvent *> dmaDoneEventFree;
485    /**@}*/
486
487    bool enableCapture;
488
489  public:
490    typedef HDLcdParams Params;
491
492    const Params *
493    params() const
494    {
495        return dynamic_cast<const Params *>(_params);
496    }
497    HDLcd(const Params *p);
498    ~HDLcd();
499
500    virtual Tick read(PacketPtr pkt);
501    virtual Tick write(PacketPtr pkt);
502
503    virtual void serialize(std::ostream &os);
504    virtual void unserialize(Checkpoint *cp, const std::string &section);
505
506    /**
507     * Determine the address ranges that this device responds to.
508     *
509     * @return a list of non-overlapping address ranges
510     */
511    AddrRangeList getAddrRanges() const;
512};
513
514#endif
515