hdlcd.hh revision 9646:7a0c51f14095
1/*
2 * Copyright (c) 2010-2013 ARM Limited
3 * All rights reserved
4 *
5 * The license below extends only to copyright in the software and shall
6 * not be construed as granting a license to any other intellectual
7 * property including but not limited to intellectual property relating
8 * to a hardware implementation of the functionality of the software
9 * licensed hereunder.  You may use the software subject to the license
10 * terms below provided that you ensure that this notice is replicated
11 * unmodified and in its entirety in all distributions of the software,
12 * modified or unmodified, in source code or in binary form.
13 *
14 * Redistribution and use in source and binary forms, with or without
15 * modification, are permitted provided that the following conditions are
16 * met: redistributions of source code must retain the above copyright
17 * notice, this list of conditions and the following disclaimer;
18 * redistributions in binary form must reproduce the above copyright
19 * notice, this list of conditions and the following disclaimer in the
20 * documentation and/or other materials provided with the distribution;
21 * neither the name of the copyright holders nor the names of its
22 * contributors may be used to endorse or promote products derived from
23 * this software without specific prior written permission.
24 *
25 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
26 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
27 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
28 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
29 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
30 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
31 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
32 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
33 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
34 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
35 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36 *
37 * Authors: Chris Emmons
38 */
39
40
41/** @file
42 * Implementiation of the ARM HDLcd controller.
43 *
44 * This implementation aims to have sufficient detail such that underrun
45 * conditions are reasonable / behave similar to reality.  There are two
46 * 'engines' going at once.  First, the DMA engine running at LCD clock
47 * frequency is responsible for filling the controller's internal buffer.
48 * The second engine runs at the pixel clock frequency and reads the pixels
49 * out of the internal buffer.  The pixel rendering engine uses front / back
50 * porch and sync delays between lines and frames.
51 *
52 * If the pixel rendering engine does not have a pixel to display, it will
53 * cause an underrun event.  The HDLcd controller, per spec, will stop
54 * issuing DMA requests for the rest of the frame and resume normal behavior
55 * on the subsequent frame.  What pixels are rendered upon an underrun
56 * condition is different than the real hardware; while the user will see
57 * artifacts (previous frame mixed with current frame), it is not the same
58 * behavior as real hardware which repeats the last pixel value for the rest
59 * of the current frame.  This compromise was made to save on memory and
60 * complexity and assumes that it is not important to accurately model the
61 * content of an underrun frame.
62 *
63 * KNOWN ISSUES
64 * 1.  The default kernel driver used in testing sets the line count to one
65 * less than the expected 768.  However, it also sets the v_count to 767.
66 * The controller specifies that 1 should be added to v_count but does not
67 * specify adding 1 to the line count.  The driver is probably wrong.
68 * However, to sync these two numbers up, this model uses fb_line_count and
69 * fb_line_length rather than using v_data or h_data values to determine the
70 * width and height of the frame; those values are ignored.
71 * 2.  The HDLcd is implemented here as an AmbaDmaDevice, but it doesn't have
72 * an AMBA ID as far as I know.  That is the only bit of the AmbaDmaDevice
73 * interface that is irrelevant to it, so a fake AMBA ID is used for now.
74 * I didn't think inserting an extra layer of hierachy between AmbaDmaDevice
75 * and DmaDevice would be helpful to anyone else, but that may be the right
76 * answer.
77 * 3.  The internal buffer size is either 1 or 2 KB depending on which
78 * specification is referenced for the different Versatile Express tiles.
79 * This implementation uses the larger 2 KB buffer by default.
80 */
81
82#ifndef __DEV_ARM_HDLCD_HH__
83#define __DEV_ARM_HDLCD_HH__
84
85#include <fstream>
86
87#include "dev/arm/amba_device.hh"
88#include "params/HDLcd.hh"
89#include "sim/serialize.hh"
90
91class VncInput;
92class Bitmap;
93
94class HDLcd: public AmbaDmaDevice
95{
96  protected:
97    /** fake AMBA ID -- unused */
98    static const uint64_t AMBA_ID       = ULL(0xb105f00d00141000);
99
100    /** ARM HDLcd register offsets */
101    enum RegisterOffset {
102        Version          = 0x0000,
103        Int_RawStat      = 0x0010,
104        Int_Clear        = 0x0014,
105        Int_Mask         = 0x0018,
106        Int_Status       = 0x001C,
107        Fb_Base          = 0x0100,
108        Fb_Line_Length   = 0x0104,
109        Fb_Line_Count    = 0x0108,
110        Fb_Line_Pitch    = 0x010C,
111        Bus_Options      = 0x0110,
112        V_Sync           = 0x0200,
113        V_Back_Porch     = 0x0204,
114        V_Data           = 0x0208,
115        V_Front_Porch    = 0x020C,
116        H_Sync           = 0x0210,
117        H_Back_Porch     = 0x0214,
118        H_Data           = 0x0218,
119        H_Front_Porch    = 0x021C,
120        Polarities       = 0x0220,
121        Command          = 0x0230,
122        Pixel_Format     = 0x0240,
123        Red_Select       = 0x0244,
124        Green_Select     = 0x0248,
125        Blue_Select      = 0x024C };
126
127    /** Reset value for Bus_Options register */
128    static const size_t BUS_OPTIONS_RESETV = 0x408;
129
130    /** Reset value for Version register */
131    static const size_t VERSION_RESETV = 0x1CDC0000;
132
133    /** max number of outstanding DMA requests possible */
134    static const size_t MAX_OUTSTANDING_DMA_REQ_CAPACITY = 16;
135
136    /** max number of beats delivered in one dma burst */
137    static const size_t MAX_BURST_LEN = 16;
138
139    /** size of internal buffer in bytes */
140    static const size_t PIXEL_BUFFER_CAPACITY = 2048;
141
142    /** AXI port width in bytes */
143    static const size_t AXI_PORT_WIDTH = 8;
144
145    /**
146     * @name RegisterFieldLayouts
147     * Bit layout declarations for multi-field registers.
148     */
149    /**@{*/
150    BitUnion32(VersionReg)
151        Bitfield<7,0>   version_minor;
152        Bitfield<15,8>  version_major;
153        Bitfield<31,16> product_id;
154    EndBitUnion(VersionReg)
155
156    BitUnion32(InterruptReg)
157        Bitfield<0> dma_end;
158        Bitfield<1> bus_error;
159        Bitfield<2> vsync;
160        Bitfield<3> underrun;
161    EndBitUnion(InterruptReg)
162
163    BitUnion32(FbLineCountReg)
164        Bitfield<11,0>  fb_line_count;
165        Bitfield<31,12> reserved_31_12;
166    EndBitUnion(FbLineCountReg)
167
168    BitUnion32(BusOptsReg)
169        Bitfield<4,0>   burst_len;
170        Bitfield<7,5>   reserved_7_5;
171        Bitfield<11,8>  max_outstanding;
172        Bitfield<31,12> reserved_31_12;
173    EndBitUnion(BusOptsReg)
174
175    BitUnion32(TimingReg)
176        Bitfield<11,0>  val;
177        Bitfield<31,12> reserved_31_12;
178    EndBitUnion(TimingReg)
179
180    BitUnion32(PolaritiesReg)
181        Bitfield<0>    vsync_polarity;
182        Bitfield<1>    hsync_polarity;
183        Bitfield<2>    dataen_polarity;
184        Bitfield<3>    data_polarity;
185        Bitfield<4>    pxlclk_polarity;
186        Bitfield<31,5> reserved_31_5;
187    EndBitUnion(PolaritiesReg)
188
189    BitUnion32(CommandReg)
190        Bitfield<0>    enable;
191        Bitfield<31,1> reserved_31_1;
192    EndBitUnion(CommandReg)
193
194    BitUnion32(PixelFormatReg)
195        Bitfield<2,0>  reserved_2_0;
196        Bitfield<4,3>  bytes_per_pixel;
197        Bitfield<30,5> reserved_30_5;
198        Bitfield<31>   big_endian;
199    EndBitUnion(PixelFormatReg)
200
201    BitUnion32(ColorSelectReg)
202        Bitfield<4,0>   offset;
203        Bitfield<7,5>   reserved_7_5;
204        Bitfield<11,8>  size;
205        Bitfield<15,12> reserved_15_12;
206        Bitfield<23,16> default_color;
207        Bitfield<31,24> reserved_31_24;
208    EndBitUnion(ColorSelectReg)
209    /**@}*/
210
211    /**
212     * @name HDLCDRegisters
213     * HDLCD register contents.
214     */
215    /**@{*/
216    VersionReg version;             /**< Version register */
217    InterruptReg int_rawstat;       /**< Interrupt raw status register */
218    InterruptReg int_clear;         /**< Interrupt clear register */
219    InterruptReg int_mask;          /**< Interrupt mask register */
220    InterruptReg int_status;        /**< Interrupt status register */
221    uint32_t fb_base;               /**< Frame buffer base address register */
222    uint32_t fb_line_length;        /**< Frame buffer Line length register */
223    FbLineCountReg fb_line_count;   /**< Frame buffer Line count register */
224    uint32_t fb_line_pitch;         /**< Frame buffer Line pitch register */
225    BusOptsReg bus_options;         /**< Bus options register */
226    TimingReg v_sync;               /**< Vertical sync width register */
227    TimingReg v_back_porch;         /**< Vertical back porch width register */
228    TimingReg v_data;               /**< Vertical data width register */
229    TimingReg v_front_porch;        /**< Vertical front porch width register */
230    TimingReg h_sync;               /**< Horizontal sync width register */
231    TimingReg h_back_porch;         /**< Horizontal back porch width register */
232    TimingReg h_data;               /**< Horizontal data width register */
233    TimingReg h_front_porch;        /**< Horizontal front porch width reg */
234    PolaritiesReg polarities;       /**< Polarities register */
235    CommandReg command;             /**< Command register */
236    PixelFormatReg pixel_format;    /**< Pixel format register */
237    ColorSelectReg red_select;      /**< Red color select register */
238    ColorSelectReg green_select;    /**< Green color select register */
239    ColorSelectReg blue_select;     /**< Blue color select register */
240    /** @} */
241
242    /** Pixel clock period */
243    const Tick pixelClock;
244
245    /** VNC server */
246    VncInput *vnc;
247
248    /** Helper to write out bitmaps */
249    Bitmap *bmp;
250
251    /** Picture of what the current frame buffer looks like */
252    std::ostream *pic;
253
254    /**
255     * Event wrapper for dmaDone()
256     *
257     * This event call pushes its this pointer onto the freeDoneEvent vector
258     * and calls dmaDone() when triggered.  While most of the time the burst
259     * length of a transaction will be the max burst length set by the driver,
260     * any trailing bytes must be handled with smaller lengths thus requiring
261     * the configurable burst length option.
262     */
263    class DmaDoneEvent : public Event
264    {
265      private:
266        /** Reference to HDLCD that issued the corresponding DMA transaction */
267        HDLcd &obj;
268
269        /** Transaction size */
270        size_t transSize;
271
272      public:
273        /**
274         * Constructor.
275         *
276         * @param _obj HDLCD that issued the corresponding DMA transaction
277         */
278        DmaDoneEvent(HDLcd *_obj)
279            : Event(), obj(*_obj), transSize(0) {}
280
281        /**
282         * Sets the size of this transaction.
283         *
284         * @param len size of the transaction in bytes
285         */
286        void setTransactionSize(size_t len) {
287            transSize = len;
288        }
289
290        /**
291         * Gets the size of this transaction.
292         *
293         * @return size of this transaction in bytes
294         */
295        size_t getTransactionSize() const {
296            return transSize;
297        }
298
299        void process() {
300            obj.dmaDone(this);
301        }
302
303        const std::string name() const {
304            return obj.name() + ".DmaDoneEvent";
305        }
306    };
307
308    /** Start time for frame buffer dma read */
309    Tick frameReadStartTime;
310
311    /** Starting address for the current frame */
312    Addr dmaStartAddr;
313
314    /** Next address the dma should read from */
315    Addr dmaCurAddr;
316
317    /** One byte past the address of the last byte the dma should read
318      * from */
319    Addr dmaMaxAddr;
320
321    /** Number of pending dma reads */
322    size_t dmaPendingNum;
323
324    /** Flag indicating whether current frame has underrun */
325    bool frameUnderrun;
326
327    /** HDLcd virtual display buffer */
328    uint8_t *virtualDisplayBuffer;
329
330    /** Size of the pixel buffer */
331    size_t pixelBufferSize;
332
333    /** Index of the next pixel to render */
334    size_t pixelIndex;
335
336    /** Flag indicating whether video parameters need updating */
337    bool doUpdateParams;
338
339    /** Flag indicating whether a frame read / display is in progress */
340    bool frameUnderway;
341
342    /**
343     * Number of bytes in flight from DMA that have not reached the pixel
344     * buffer yet
345     */
346    uint32_t dmaBytesInFlight;
347
348    /**
349     * Gets the number of oustanding DMA transactions allowed on the bus at a
350     * time.
351     *
352     * @return gets the driver-specified number of outstanding DMA transactions
353     *         from the hdlcd controller that are allowed on the bus at a time
354     */
355    inline uint16_t maxOutstandingDma() const {
356        return bus_options.max_outstanding;
357    }
358
359    /**
360     * Gets the number of bytes free in the pixel buffer.
361     *
362     * @return number of bytes free in the internal pixel buffer
363     */
364    inline uint32_t bytesFreeInPixelBuffer() const {
365        return PIXEL_BUFFER_CAPACITY - (pixelBufferSize + dmaBytesInFlight);
366    }
367
368    /**
369     * Gets the number of beats-per-burst for bus transactions.
370     *
371     * @return number of beats-per-burst per HDLcd DMA transaction
372     */
373    inline size_t dmaBurstLength() const {
374        assert(bus_options.burst_len <= MAX_BURST_LEN);
375        return bus_options.burst_len;
376    }
377
378    /**
379     * Gets the number of bytes per pixel.
380     *
381     * @return bytes per pixel
382     */
383    inline size_t bytesPerPixel() const {
384        return pixel_format.bytes_per_pixel + 1;
385    }
386
387    /**
388     * Gets frame buffer width.
389     *
390     * @return frame buffer width (pixels per line)
391     */
392    inline size_t width() const {
393        return fb_line_length / bytesPerPixel();
394    }
395
396    /**
397     * Gets frame buffer height.
398     *
399     * @return frame buffer height (lines per panel)
400     */
401    inline size_t height() const {
402        return fb_line_count.fb_line_count;
403    }
404
405    /**
406     * Gets the total number of pixel clocks per display line.
407     *
408     * @return number of pixel clocks per display line including porch delays
409     *         and horizontal sync time
410     */
411    inline uint64_t PClksPerLine() const {
412        return h_back_porch.val + 1 +
413               h_data.val + 1 +
414               h_front_porch.val + 1 +
415               h_sync.val + 1;
416    }
417
418    /** Send updated parameters to the vnc server */
419    void updateVideoParams(bool unserializing);
420
421    /** Generates an interrupt */
422    void generateInterrupt();
423
424    /** Start reading the next frame */
425    void startFrame();
426
427    /** End of frame reached */
428    void endFrame();
429
430    /** Generate DMA read requests from frame buffer into pixel buffer */
431    void fillPixelBuffer();
432
433    /** DMA done event */
434    void dmaDone(DmaDoneEvent *event);
435
436    /** Called when it is time to render a pixel */
437    void renderPixel();
438
439    /** Start of frame event */
440    EventWrapper<HDLcd, &HDLcd::startFrame> startFrameEvent;
441
442    /** End of frame event */
443    EventWrapper<HDLcd, &HDLcd::endFrame> endFrameEvent;
444
445    /** Pixel render event */
446    EventWrapper<HDLcd, &HDLcd::renderPixel> renderPixelEvent;
447
448    /** Fill fifo */
449    EventWrapper<HDLcd, &HDLcd::fillPixelBuffer> fillPixelBufferEvent;
450
451    /** Wrapper to create an event out of the interrupt */
452    EventWrapper<HDLcd, &HDLcd::generateInterrupt> intEvent;
453
454    /**@{*/
455    /**
456     * All pre-allocated DMA done events
457     *
458     * The HDLCD model preallocates maxOutstandingDma() number of
459     * DmaDoneEvents to avoid having to heap allocate every single
460     * event when it is needed. In order to keep track of which events
461     * are in flight and which are ready to be used, we use two
462     * different vectors. dmaDoneEventAll contains <i>all</i>
463     * DmaDoneEvents that the object may use, while dmaDoneEventFree
464     * contains a list of currently <i>unused</i> events. When an
465     * event needs to be scheduled, the last element of the
466     * dmaDoneEventFree is used and removed from the list. When an
467     * event fires, it is added to the end of the
468     * dmaEventFreeList. dmaDoneEventAll is never used except for in
469     * initialization and serialization.
470     */
471    std::vector<DmaDoneEvent> dmaDoneEventAll;
472
473    /** Unused DMA done events that are ready to be scheduled */
474    std::vector<DmaDoneEvent *> dmaDoneEventFree;
475    /**@}*/
476
477  public:
478    typedef HDLcdParams Params;
479
480    const Params *
481    params() const
482    {
483        return dynamic_cast<const Params *>(_params);
484    }
485    HDLcd(const Params *p);
486    ~HDLcd();
487
488    virtual Tick read(PacketPtr pkt);
489    virtual Tick write(PacketPtr pkt);
490
491    virtual void serialize(std::ostream &os);
492    virtual void unserialize(Checkpoint *cp, const std::string &section);
493
494    /**
495     * Determine the address ranges that this device responds to.
496     *
497     * @return a list of non-overlapping address ranges
498     */
499    AddrRangeList getAddrRanges() const;
500};
501
502#endif
503