diff options
author | Nilay Vaish <nilay@cs.wisc.edu> | 2015-09-12 16:23:47 -0500 |
---|---|---|
committer | Nilay Vaish <nilay@cs.wisc.edu> | 2015-09-12 16:23:47 -0500 |
commit | 78bf2dfeac083f5f945ce61cf8ec32374e7c94ae (patch) | |
tree | 5f872502626284236c08afec9612c4492fee2ae0 /src/dev/arm/hdlcd.hh | |
parent | 8b199b775e209c20cd7f7a8c085455931f8cb70e (diff) | |
parent | a1517867415abe0705d195bbe4cf62cc7fa03e47 (diff) | |
download | gem5-78bf2dfeac083f5f945ce61cf8ec32374e7c94ae.tar.xz |
merged with 62e1504b9c64
Diffstat (limited to 'src/dev/arm/hdlcd.hh')
-rw-r--r-- | src/dev/arm/hdlcd.hh | 415 |
1 files changed, 146 insertions, 269 deletions
diff --git a/src/dev/arm/hdlcd.hh b/src/dev/arm/hdlcd.hh index 1396c9a8b..cb47b8522 100644 --- a/src/dev/arm/hdlcd.hh +++ b/src/dev/arm/hdlcd.hh @@ -35,6 +35,7 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * Authors: Chris Emmons + * Andreas Sandberg */ @@ -61,22 +62,15 @@ * content of an underrun frame. * * KNOWN ISSUES - * 1. The default kernel driver used in testing sets the line count to one - * less than the expected 768. However, it also sets the v_count to 767. - * The controller specifies that 1 should be added to v_count but does not - * specify adding 1 to the line count. The driver is probably wrong. - * However, to sync these two numbers up, this model uses fb_line_count and - * fb_line_length rather than using v_data or h_data values to determine the - * width and height of the frame; those values are ignored. - * 2. The HDLcd is implemented here as an AmbaDmaDevice, but it doesn't have - * an AMBA ID as far as I know. That is the only bit of the AmbaDmaDevice - * interface that is irrelevant to it, so a fake AMBA ID is used for now. - * I didn't think inserting an extra layer of hierachy between AmbaDmaDevice - * and DmaDevice would be helpful to anyone else, but that may be the right - * answer. - * 3. The internal buffer size is either 1 or 2 KB depending on which - * specification is referenced for the different Versatile Express tiles. - * This implementation uses the larger 2 KB buffer by default. + * <ul> + * <li>The HDLcd is implemented here as an AmbaDmaDevice, but it + * doesn't have an AMBA ID as far as I know. That is the only + * bit of the AmbaDmaDevice interface that is irrelevant to it, + * so a fake AMBA ID is used for now. I didn't think inserting + * an extra layer of hierachy between AmbaDmaDevice and + * DmaDevice would be helpful to anyone else, but that may be + * the right answer. + * </ul> */ #ifndef __DEV_ARM_HDLCD_HH__ @@ -88,17 +82,41 @@ #include "base/bitmap.hh" #include "base/framebuffer.hh" #include "dev/arm/amba_device.hh" -#include "params/HDLcd.hh" +#include "dev/pixelpump.hh" #include "sim/serialize.hh" class VncInput; +struct HDLcdParams; +class HDLcdPixelPump; class HDLcd: public AmbaDmaDevice { - protected: - /** fake AMBA ID -- unused */ - static const uint64_t AMBA_ID = ULL(0xb105f00d00141000); + public: + HDLcd(const HDLcdParams *p); + ~HDLcd(); + + void regStats() M5_ATTR_OVERRIDE; + + void serialize(CheckpointOut &cp) const M5_ATTR_OVERRIDE; + void unserialize(CheckpointIn &cp) M5_ATTR_OVERRIDE; + void drainResume() M5_ATTR_OVERRIDE; + + public: // IO device interface + Tick read(PacketPtr pkt) M5_ATTR_OVERRIDE; + Tick write(PacketPtr pkt) M5_ATTR_OVERRIDE; + + AddrRangeList getAddrRanges() const M5_ATTR_OVERRIDE { return addrRanges; } + + protected: // Parameters + VncInput *vnc; + const bool workaroundSwapRB; + const bool workaroundDmaLineCount; + const AddrRangeList addrRanges; + const bool enableCapture; + const Addr pixelBufferSize; + + protected: // Register handling /** ARM HDLcd register offsets */ enum RegisterOffset { Version = 0x0000, @@ -124,27 +142,23 @@ class HDLcd: public AmbaDmaDevice Pixel_Format = 0x0240, Red_Select = 0x0244, Green_Select = 0x0248, - Blue_Select = 0x024C }; + Blue_Select = 0x024C, + }; /** Reset value for Bus_Options register */ - static const size_t BUS_OPTIONS_RESETV = 0x408; + static constexpr size_t BUS_OPTIONS_RESETV = 0x408; /** Reset value for Version register */ - static const size_t VERSION_RESETV = 0x1CDC0000; + static constexpr size_t VERSION_RESETV = 0x1CDC0000; - /** max number of outstanding DMA requests possible */ - static const size_t MAX_OUTSTANDING_DMA_REQ_CAPACITY = 16; + /** AXI port width in bytes */ + static constexpr size_t AXI_PORT_WIDTH = 8; /** max number of beats delivered in one dma burst */ - static const size_t MAX_BURST_LEN = 16; - - /** size of internal buffer in bytes */ - static const size_t PIXEL_BUFFER_CAPACITY = 2048; - - /** AXI port width in bytes */ - static const size_t AXI_PORT_WIDTH = 8; + static constexpr size_t MAX_BURST_LEN = 16; - static const size_t MAX_BURST_SIZE = MAX_BURST_LEN * AXI_PORT_WIDTH; + /** Maximum number of bytes per pixel */ + static constexpr size_t MAX_PIXEL_SIZE = 4; /** * @name RegisterFieldLayouts @@ -157,12 +171,10 @@ class HDLcd: public AmbaDmaDevice Bitfield<31,16> product_id; EndBitUnion(VersionReg) - BitUnion32(InterruptReg) - Bitfield<0> dma_end; - Bitfield<1> bus_error; - Bitfield<2> vsync; - Bitfield<3> underrun; - EndBitUnion(InterruptReg) + static constexpr uint32_t INT_DMA_END = (1UL << 0); + static constexpr uint32_t INT_BUS_ERROR = (1UL << 1); + static constexpr uint32_t INT_VSYNC = (1UL << 2); + static constexpr uint32_t INT_UNDERRUN = (1UL << 3); BitUnion32(FbLineCountReg) Bitfield<11,0> fb_line_count; @@ -217,15 +229,13 @@ class HDLcd: public AmbaDmaDevice * HDLCD register contents. */ /**@{*/ - VersionReg version; /**< Version register */ - InterruptReg int_rawstat; /**< Interrupt raw status register */ - InterruptReg int_clear; /**< Interrupt clear register */ - InterruptReg int_mask; /**< Interrupt mask register */ - InterruptReg int_status; /**< Interrupt status register */ + const VersionReg version; /**< Version register */ + uint32_t int_rawstat; /**< Interrupt raw status register */ + uint32_t int_mask; /**< Interrupt mask register */ uint32_t fb_base; /**< Frame buffer base address register */ uint32_t fb_line_length; /**< Frame buffer Line length register */ FbLineCountReg fb_line_count; /**< Frame buffer Line count register */ - uint32_t fb_line_pitch; /**< Frame buffer Line pitch register */ + int32_t fb_line_pitch; /**< Frame buffer Line pitch register */ BusOptsReg bus_options; /**< Bus options register */ TimingReg v_sync; /**< Vertical sync width register */ TimingReg v_back_porch; /**< Vertical back porch width register */ @@ -243,274 +253,141 @@ class HDLcd: public AmbaDmaDevice ColorSelectReg blue_select; /**< Blue color select register */ /** @} */ - /** Pixel clock period */ - const Tick pixelClock; - - FrameBuffer fb; - - /** VNC server */ - VncInput *vnc; - - /** Helper to write out bitmaps */ - Bitmap bmp; - - /** Picture of what the current frame buffer looks like */ - std::ostream *pic; - - /** - * Event wrapper for dmaDone() - * - * This event call pushes its this pointer onto the freeDoneEvent vector - * and calls dmaDone() when triggered. While most of the time the burst - * length of a transaction will be the max burst length set by the driver, - * any trailing bytes must be handled with smaller lengths thus requiring - * the configurable burst length option. - */ - class DmaDoneEvent : public Event - { - private: - /** Reference to HDLCD that issued the corresponding DMA transaction */ - HDLcd &obj; - - /** Transaction size */ - size_t transSize; - - public: - /** - * Constructor. - * - * @param _obj HDLCD that issued the corresponding DMA transaction - */ - DmaDoneEvent(HDLcd *_obj) - : Event(), obj(*_obj), transSize(0) {} - - /** - * Sets the size of this transaction. - * - * @param len size of the transaction in bytes - */ - void setTransactionSize(size_t len) { - transSize = len; - } - - /** - * Gets the size of this transaction. - * - * @return size of this transaction in bytes - */ - size_t getTransactionSize() const { - return transSize; - } - - void process() { - obj.dmaDone(this); - } - - const std::string name() const { - return obj.name() + ".DmaDoneEvent"; - } - }; - - /** Start time for frame buffer dma read */ - Tick frameReadStartTime; - - /** Starting address for the current frame */ - Addr dmaStartAddr; - - /** Next address the dma should read from */ - Addr dmaCurAddr; - - /** One byte past the address of the last byte the dma should read - * from */ - Addr dmaMaxAddr; - - /** Number of pending dma reads */ - size_t dmaPendingNum; - - /** Flag indicating whether current frame has underrun */ - bool frameUnderrun; - - /** HDLcd virtual display buffer */ - std::vector<uint8_t> virtualDisplayBuffer; + uint32_t readReg(Addr offset); + void writeReg(Addr offset, uint32_t value); - /** Size of the pixel buffer */ - size_t pixelBufferSize; - - /** Index of the next pixel to render */ - size_t pixelIndex; - - /** Flag indicating whether video parameters need updating */ - bool doUpdateParams; + PixelConverter pixelConverter() const; + DisplayTimings displayTimings() const; - /** Flag indicating whether a frame read / display is in progress */ - bool frameUnderway; + void createDmaEngine(); - /** - * Number of bytes in flight from DMA that have not reached the pixel - * buffer yet - */ - uint32_t dmaBytesInFlight; + void cmdEnable(); + void cmdDisable(); - /** - * Gets the number of oustanding DMA transactions allowed on the bus at a - * time. - * - * @return gets the driver-specified number of outstanding DMA transactions - * from the hdlcd controller that are allowed on the bus at a time - */ - inline uint16_t maxOutstandingDma() const { - return bus_options.max_outstanding; - } + bool enabled() const { return command.enable; } - /** - * Gets the number of bytes free in the pixel buffer. - * - * @return number of bytes free in the internal pixel buffer - */ - inline uint32_t bytesFreeInPixelBuffer() const { - return PIXEL_BUFFER_CAPACITY - (pixelBufferSize + dmaBytesInFlight); - } + public: // Pixel pump callbacks + bool pxlNext(Pixel &p); + void pxlVSyncBegin(); + void pxlVSyncEnd(); + void pxlUnderrun(); + void pxlFrameDone(); + protected: // Interrupt handling /** - * Gets the number of beats-per-burst for bus transactions. + * Assign new interrupt values and update interrupt signals * - * @return number of beats-per-burst per HDLcd DMA transaction - */ - inline size_t dmaBurstLength() const { - assert(bus_options.burst_len <= MAX_BURST_LEN); - return bus_options.burst_len; - } - - /** - * Gets the number of bytes per pixel. + * A new interrupt is scheduled signalled if the set of unmasked + * interrupts goes empty to non-empty. Conversely, if the set of + * unmasked interrupts goes from non-empty to empty, the interrupt + * signal is cleared. * - * @return bytes per pixel + * @param ints New <i>raw</i> interrupt status + * @param mask New interrupt mask */ - inline size_t bytesPerPixel() const { - return pixel_format.bytes_per_pixel + 1; - } + void setInterrupts(uint32_t ints, uint32_t mask); /** - * Gets frame buffer width. + * Convenience function to update the interrupt mask * - * @return frame buffer width (pixels per line) + * @see setInterrupts + * @param mask New interrupt mask */ - inline size_t width() const { - return fb_line_length / bytesPerPixel(); - } + void intMask(uint32_t mask) { setInterrupts(int_rawstat, mask); } /** - * Gets frame buffer height. + * Convenience function to raise a new interrupt * - * @return frame buffer height (lines per panel) + * @see setInterrupts + * @param ints Set of interrupts to raise */ - inline size_t height() const { - return fb_line_count.fb_line_count; + void intRaise(uint32_t ints) { + setInterrupts(int_rawstat | ints, int_mask); } - inline size_t area() const { return height() * width(); } - /** - * Gets the total number of pixel clocks per display line. + * Convenience function to clear interrupts * - * @return number of pixel clocks per display line including porch delays - * and horizontal sync time + * @see setInterrupts + * @param ints Set of interrupts to clear */ - inline uint64_t PClksPerLine() const { - return h_back_porch.val + 1 + - h_data.val + 1 + - h_front_porch.val + 1 + - h_sync.val + 1; + void intClear(uint32_t ints) { + setInterrupts(int_rawstat & ~ints, int_mask); } - /** Send updated parameters to the vnc server */ - void updateVideoParams(bool unserializing); - - /** Generates an interrupt */ - void generateInterrupt(); + /** Masked interrupt status register */ + const uint32_t intStatus() const { return int_rawstat & int_mask; } - /** Start reading the next frame */ - void startFrame(); - - /** End of frame reached */ - void endFrame(); + protected: // Pixel output + class PixelPump : public BasePixelPump + { + public: + PixelPump(HDLcd &p, ClockDomain &pxl_clk, unsigned pixel_chunk) + : BasePixelPump(p, pxl_clk, pixel_chunk), parent(p) {} - /** Generate DMA read requests from frame buffer into pixel buffer */ - void fillPixelBuffer(); + void dumpSettings(); - /** DMA done event */ - void dmaDone(DmaDoneEvent *event); + protected: + bool nextPixel(Pixel &p) M5_ATTR_OVERRIDE { return parent.pxlNext(p); } - /** Called when it is time to render a pixel */ - void renderPixel(); + void onVSyncBegin() M5_ATTR_OVERRIDE { return parent.pxlVSyncBegin(); } + void onVSyncEnd() M5_ATTR_OVERRIDE { return parent.pxlVSyncEnd(); } - PixelConverter pixelConverter() const; + void onUnderrun(unsigned x, unsigned y) M5_ATTR_OVERRIDE { + parent.pxlUnderrun(); + } - /** Start of frame event */ - EventWrapper<HDLcd, &HDLcd::startFrame> startFrameEvent; + void onFrameDone() M5_ATTR_OVERRIDE { parent.pxlFrameDone(); } - /** End of frame event */ - EventWrapper<HDLcd, &HDLcd::endFrame> endFrameEvent; + protected: + HDLcd &parent; + }; - /** Pixel render event */ - EventWrapper<HDLcd, &HDLcd::renderPixel> renderPixelEvent; + /** Helper to write out bitmaps */ + Bitmap bmp; - /** Fill fifo */ - EventWrapper<HDLcd, &HDLcd::fillPixelBuffer> fillPixelBufferEvent; + /** Picture of what the current frame buffer looks like */ + std::ostream *pic; - /** Wrapper to create an event out of the interrupt */ - EventWrapper<HDLcd, &HDLcd::generateInterrupt> intEvent; + /** Cached pixel converter, set when the converter is enabled. */ + PixelConverter conv; - /**@{*/ - /** - * All pre-allocated DMA done events - * - * The HDLCD model preallocates maxOutstandingDma() number of - * DmaDoneEvents to avoid having to heap allocate every single - * event when it is needed. In order to keep track of which events - * are in flight and which are ready to be used, we use two - * different vectors. dmaDoneEventAll contains <i>all</i> - * DmaDoneEvents that the object may use, while dmaDoneEventFree - * contains a list of currently <i>unused</i> events. When an - * event needs to be scheduled, the last element of the - * dmaDoneEventFree is used and removed from the list. When an - * event fires, it is added to the end of the - * dmaEventFreeList. dmaDoneEventAll is never used except for in - * initialization and serialization. - */ - std::vector<DmaDoneEvent> dmaDoneEventAll; + PixelPump pixelPump; - /** Unused DMA done events that are ready to be scheduled */ - std::vector<DmaDoneEvent *> dmaDoneEventFree; - /**@}*/ + protected: // DMA handling + class DmaEngine : public DmaReadFifo + { + public: + DmaEngine(HDLcd &_parent, size_t size, + unsigned request_size, unsigned max_pending, + size_t line_size, ssize_t line_pitch, unsigned num_lines); - bool enableCapture; + void startFrame(Addr fb_base); + void abortFrame(); + void dumpSettings(); - const bool workaround_swap_rb; + void serialize(CheckpointOut &cp) const M5_ATTR_OVERRIDE; + void unserialize(CheckpointIn &cp) M5_ATTR_OVERRIDE; - public: - typedef HDLcdParams Params; + protected: + void onEndOfBlock() M5_ATTR_OVERRIDE; + void onIdle() M5_ATTR_OVERRIDE; - const Params * - params() const - { - return dynamic_cast<const Params *>(_params); - } - HDLcd(const Params *p); - ~HDLcd(); + HDLcd &parent; + const size_t lineSize; + const ssize_t linePitch; + const unsigned numLines; - virtual Tick read(PacketPtr pkt); - virtual Tick write(PacketPtr pkt); + Addr nextLineAddr; + Addr frameEnd; + }; - void serialize(CheckpointOut &cp) const M5_ATTR_OVERRIDE; - void unserialize(CheckpointIn &cp) M5_ATTR_OVERRIDE; + std::unique_ptr<DmaEngine> dmaEngine; - /** - * Determine the address ranges that this device responds to. - * - * @return a list of non-overlapping address ranges - */ - AddrRangeList getAddrRanges() const; + protected: // Statistics + struct { + Stats::Scalar underruns; + } stats; }; #endif |