2 * Copyright (c) 2010-2013, 2015, 2017 ARM Limited
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.
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.
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.
37 * Authors: Chris Emmons
41 #include "dev/arm/hdlcd.hh"
43 #include "base/output.hh"
44 #include "base/trace.hh"
45 #include "base/vnc/vncinput.hh"
46 #include "debug/Checkpoint.hh"
47 #include "debug/HDLcd.hh"
48 #include "dev/arm/amba_device.hh"
49 #include "dev/arm/base_gic.hh"
50 #include "enums/ImageFormat.hh"
51 #include "mem/packet.hh"
52 #include "mem/packet_access.hh"
53 #include "params/HDLcd.hh"
54 #include "sim/system.hh"
59 // initialize hdlcd registers
60 HDLcd::HDLcd(const HDLcdParams
*p
)
61 : AmbaDmaDevice(p
, 0xFFFF),
64 workaroundSwapRB(p
->workaround_swap_rb
),
65 workaroundDmaLineCount(p
->workaround_dma_line_count
),
66 addrRanges
{RangeSize(pioAddr
, pioSize
)},
67 enableCapture(p
->enable_capture
),
68 pixelBufferSize(p
->pixel_buffer_size
),
69 virtRefreshRate(p
->virt_refresh_rate
),
72 version(VERSION_RESETV
),
73 int_rawstat(0), int_mask(0),
75 fb_base(0), fb_line_length(0), fb_line_count(0), fb_line_pitch(0),
76 bus_options(BUS_OPTIONS_RESETV
),
78 v_sync(0), v_back_porch(0), v_data(0), v_front_porch(0),
79 h_sync(0), h_back_porch(0), h_data(0), h_front_porch(0),
85 red_select(0), green_select(0), blue_select(0),
87 virtRefreshEvent([this]{ virtRefresh(); }, name()),
89 imgFormat(p
->frame_format
), pic(NULL
), conv(PixelConverter::rgba8888_le
),
90 pixelPump(*this, *p
->pxl_clk
, p
->pixel_chunk
)
93 vnc
->setFrameBuffer(&pixelPump
.fb
);
95 imgWriter
= createImgWriter(imgFormat
, &pixelPump
.fb
);
105 AmbaDmaDevice::regStats();
107 using namespace Stats
;
110 .name(name() + ".underruns")
111 .desc("number of buffer underruns")
117 HDLcd::serialize(CheckpointOut
&cp
) const
119 DPRINTF(Checkpoint
, "Serializing ARM HDLCD\n");
121 SERIALIZE_SCALAR(int_rawstat
);
122 SERIALIZE_SCALAR(int_mask
);
124 SERIALIZE_SCALAR(fb_base
);
125 SERIALIZE_SCALAR(fb_line_length
);
126 SERIALIZE_SCALAR(fb_line_count
);
127 SERIALIZE_SCALAR(fb_line_pitch
);
128 SERIALIZE_SCALAR(bus_options
);
130 SERIALIZE_SCALAR(v_sync
);
131 SERIALIZE_SCALAR(v_back_porch
);
132 SERIALIZE_SCALAR(v_data
);
133 SERIALIZE_SCALAR(v_front_porch
);
135 SERIALIZE_SCALAR(h_sync
);
136 SERIALIZE_SCALAR(h_back_porch
);
137 SERIALIZE_SCALAR(h_data
);
138 SERIALIZE_SCALAR(h_front_porch
);
140 SERIALIZE_SCALAR(polarities
);
142 SERIALIZE_SCALAR(command
);
143 SERIALIZE_SCALAR(pixel_format
);
144 SERIALIZE_SCALAR(red_select
);
145 SERIALIZE_SCALAR(green_select
);
146 SERIALIZE_SCALAR(blue_select
);
148 SERIALIZE_OBJ(pixelPump
);
150 dmaEngine
->serializeSection(cp
, "dmaEngine");
154 HDLcd::unserialize(CheckpointIn
&cp
)
156 DPRINTF(Checkpoint
, "Unserializing ARM HDLCD\n");
158 UNSERIALIZE_SCALAR(int_rawstat
);
159 UNSERIALIZE_SCALAR(int_mask
);
161 UNSERIALIZE_SCALAR(fb_base
);
162 UNSERIALIZE_SCALAR(fb_line_length
);
163 UNSERIALIZE_SCALAR(fb_line_count
);
164 UNSERIALIZE_SCALAR(fb_line_pitch
);
165 UNSERIALIZE_SCALAR(bus_options
);
167 UNSERIALIZE_SCALAR(v_sync
);
168 UNSERIALIZE_SCALAR(v_back_porch
);
169 UNSERIALIZE_SCALAR(v_data
);
170 UNSERIALIZE_SCALAR(v_front_porch
);
172 UNSERIALIZE_SCALAR(h_sync
);
173 UNSERIALIZE_SCALAR(h_back_porch
);
174 UNSERIALIZE_SCALAR(h_data
);
175 UNSERIALIZE_SCALAR(h_front_porch
);
177 UNSERIALIZE_SCALAR(polarities
);
179 UNSERIALIZE_SCALAR(command
);
180 UNSERIALIZE_SCALAR(pixel_format
);
181 UNSERIALIZE_SCALAR(red_select
);
182 UNSERIALIZE_SCALAR(green_select
);
183 UNSERIALIZE_SCALAR(blue_select
);
186 // Try to unserialize the pixel pump. It might not exist if
187 // we're unserializing an old checkpoint.
188 ScopedCheckpointSection
sec(cp
, "pixelPump");
189 if (cp
.sectionExists(Serializable::currentSection()))
190 pixelPump
.unserialize(cp
);
194 // Create the DMA engine and read its state from the
195 // checkpoint. We don't need to worry about the pixel pump as
196 // it is a proper SimObject.
198 dmaEngine
->unserializeSection(cp
, "dmaEngine");
200 conv
= pixelConverter();
207 AmbaDmaDevice::drainResume();
210 if (sys
->bypassCaches()) {
211 // We restart the HDLCD if we are in KVM mode. This
212 // ensures that we always use the fast refresh logic if we
213 // resume in KVM mode.
216 } else if (!pixelPump
.active()) {
217 // We restored from an old checkpoint without a pixel
218 // pump, start an new refresh. This typically happens when
219 // restoring from old checkpoints.
224 // We restored from a checkpoint and need to update the VNC server
225 if (pixelPump
.active() && vnc
)
232 pixelPump
.renderFrame();
233 schedule(virtRefreshEvent
, (curTick() + virtRefreshRate
));
236 // read registers and frame buffer
238 HDLcd::read(PacketPtr pkt
)
240 assert(pkt
->getAddr() >= pioAddr
&&
241 pkt
->getAddr() < pioAddr
+ pioSize
);
243 const Addr
daddr(pkt
->getAddr() - pioAddr
);
244 panic_if(pkt
->getSize() != 4,
245 "Unhandled read size (address: 0x.4x, size: %u)",
246 daddr
, pkt
->getSize());
248 const uint32_t data(readReg(daddr
));
249 DPRINTF(HDLcd
, "read register 0x%04x: 0x%x\n", daddr
, data
);
251 pkt
->setLE
<uint32_t>(data
);
252 pkt
->makeAtomicResponse();
256 // write registers and frame buffer
258 HDLcd::write(PacketPtr pkt
)
260 assert(pkt
->getAddr() >= pioAddr
&&
261 pkt
->getAddr() < pioAddr
+ pioSize
);
263 const Addr
daddr(pkt
->getAddr() - pioAddr
);
264 panic_if(pkt
->getSize() != 4,
265 "Unhandled read size (address: 0x.4x, size: %u)",
266 daddr
, pkt
->getSize());
267 const uint32_t data(pkt
->getLE
<uint32_t>());
268 DPRINTF(HDLcd
, "write register 0x%04x: 0x%x\n", daddr
, data
);
270 writeReg(daddr
, data
);
272 pkt
->makeAtomicResponse();
277 HDLcd::readReg(Addr offset
)
280 case Version
: return version
;
282 case Int_RawStat
: return int_rawstat
;
284 panic("HDLCD INT_CLEAR register is Write-Only\n");
285 case Int_Mask
: return int_mask
;
286 case Int_Status
: return intStatus();
288 case Fb_Base
: return fb_base
;
289 case Fb_Line_Length
: return fb_line_length
;
290 case Fb_Line_Count
: return fb_line_count
;
291 case Fb_Line_Pitch
: return fb_line_pitch
;
292 case Bus_Options
: return bus_options
;
294 case V_Sync
: return v_sync
;
295 case V_Back_Porch
: return v_back_porch
;
296 case V_Data
: return v_data
;
297 case V_Front_Porch
: return v_front_porch
;
298 case H_Sync
: return h_sync
;
299 case H_Back_Porch
: return h_back_porch
;
300 case H_Data
: return h_data
;
301 case H_Front_Porch
: return h_front_porch
;
302 case Polarities
: return polarities
;
304 case Command
: return command
;
305 case Pixel_Format
: return pixel_format
;
306 case Red_Select
: return red_select
;
307 case Green_Select
: return green_select
;
308 case Blue_Select
: return blue_select
;
311 panic("Tried to read HDLCD register that doesn't exist\n", offset
);
316 HDLcd::writeReg(Addr offset
, uint32_t value
)
320 panic("HDLCD VERSION register is read-Only\n");
332 panic("HDLCD INT_STATUS register is read-Only\n");
340 fb_line_length
= value
;
344 fb_line_count
= value
;
348 fb_line_pitch
= value
;
352 const BusOptsReg
old_bus_options(bus_options
);
355 if (bus_options
.max_outstanding
!= old_bus_options
.max_outstanding
) {
357 "Changing HDLcd outstanding DMA transactions: %d -> %d\n",
358 old_bus_options
.max_outstanding
,
359 bus_options
.max_outstanding
);
363 if (bus_options
.burst_len
!= old_bus_options
.burst_len
) {
365 "Changing HDLcd DMA burst flags: 0x%x -> 0x%x\n",
366 old_bus_options
.burst_len
, bus_options
.burst_len
);
374 v_back_porch
= value
;
380 v_front_porch
= value
;
387 h_back_porch
= value
;
393 h_front_porch
= value
;
401 const CommandReg
new_command(value
);
403 if (new_command
.enable
!= command
.enable
) {
404 DPRINTF(HDLcd
, "HDLCD switched %s\n",
405 new_command
.enable
? "on" : "off");
407 if (new_command
.enable
) {
413 command
= new_command
;
417 pixel_format
= value
;
424 green_select
= value
;
431 panic("Tried to write HDLCD register that doesn't exist\n", offset
);
437 HDLcd::pixelConverter() const
439 ByteOrder
byte_order(
440 pixel_format
.big_endian
? BigEndianByteOrder
: LittleEndianByteOrder
);
442 /* Some Linux kernels have a broken driver that swaps the red and
443 * blue color select registers. */
444 if (!workaroundSwapRB
) {
445 return PixelConverter(
446 pixel_format
.bytes_per_pixel
+ 1,
447 red_select
.offset
, green_select
.offset
, blue_select
.offset
,
448 red_select
.size
, green_select
.size
, blue_select
.size
,
451 return PixelConverter(
452 pixel_format
.bytes_per_pixel
+ 1,
453 blue_select
.offset
, green_select
.offset
, red_select
.offset
,
454 blue_select
.size
, green_select
.size
, red_select
.size
,
460 HDLcd::displayTimings() const
462 return DisplayTimings(
463 h_data
.val
+ 1, v_data
.val
+ 1,
464 h_back_porch
.val
+ 1, h_sync
.val
+ 1, h_front_porch
.val
+ 1,
465 v_back_porch
.val
+ 1, v_sync
.val
+ 1, v_front_porch
.val
+ 1);
469 HDLcd::createDmaEngine()
471 if (bus_options
.max_outstanding
== 0) {
472 warn("Maximum number of outstanding DMA transfers set to 0.");
476 const uint32_t dma_burst_flags(bus_options
.burst_len
);
477 const uint32_t dma_burst_len(
479 (1UL << (findMsbSet(dma_burst_flags
) - 1)) :
481 // Some drivers seem to set the DMA line count incorrectly. This
482 // could either be a driver bug or a specification bug. Unlike for
483 // timings, the specification does not require 1 to be added to
484 // the DMA engine's line count.
485 const uint32_t dma_lines(
486 fb_line_count
+ (workaroundDmaLineCount
? 1 : 0));
488 dmaEngine
.reset(new DmaEngine(
489 *this, pixelBufferSize
,
490 AXI_PORT_WIDTH
* dma_burst_len
,
491 bus_options
.max_outstanding
,
492 fb_line_length
, fb_line_pitch
, dma_lines
));
499 conv
= pixelConverter();
501 // Update timing parameter before rendering frames
502 pixelPump
.updateTimings(displayTimings());
504 if (sys
->bypassCaches()) {
505 schedule(virtRefreshEvent
, clockEdge());
515 // Disable the virtual refresh event
516 if (virtRefreshEvent
.scheduled()) {
517 assert(sys
->bypassCaches());
518 deschedule(virtRefreshEvent
);
520 dmaEngine
->abortFrame();
524 HDLcd::pxlNext(Pixel
&p
)
526 uint8_t pixel_data
[MAX_PIXEL_SIZE
];
527 assert(conv
.length
<= sizeof(pixel_data
));
528 if (dmaEngine
->tryGet(pixel_data
, conv
.length
)) {
529 p
= conv
.toPixel(pixel_data
);
537 HDLcd::pxlVSyncBegin()
539 DPRINTF(HDLcd
, "Raising VSYNC interrupt.\n");
546 DPRINTF(HDLcd
, "End of VSYNC, starting DMA engine\n");
547 dmaEngine
->startFrame(fb_base
);
553 DPRINTF(HDLcd
, "Buffer underrun, stopping DMA fill.\n");
555 intRaise(INT_UNDERRUN
);
556 dmaEngine
->abortFrame();
560 HDLcd::pxlFrameDone()
562 DPRINTF(HDLcd
, "Reached end of last visible line.\n");
564 if (dmaEngine
->size()) {
565 warn("HDLCD %u bytes still in FIFO after frame: Ensure that DMA "
566 "and PixelPump configuration is consistent\n",
568 dmaEngine
->dumpSettings();
569 pixelPump
.dumpSettings();
578 csprintf("%s.framebuffer.%s",
579 sys
->name(), imgWriter
->getImgExtension()),
584 pic
->stream()->seekp(0);
585 imgWriter
->write(*pic
->stream());
590 HDLcd::setInterrupts(uint32_t ints
, uint32_t mask
)
592 const bool old_ints(intStatus());
597 if (!old_ints
&& intStatus()) {
598 gic
->sendInt(intNum
);
599 } else if (old_ints
&& !intStatus()) {
600 gic
->clearInt(intNum
);
604 HDLcd::DmaEngine::DmaEngine(HDLcd
&_parent
, size_t size
,
605 unsigned request_size
, unsigned max_pending
,
606 size_t line_size
, ssize_t line_pitch
, unsigned num_lines
)
608 _parent
.dmaPort
, size
, request_size
, max_pending
,
609 Request::UNCACHEABLE
),
611 lineSize(line_size
), linePitch(line_pitch
), numLines(num_lines
),
617 HDLcd::DmaEngine::serialize(CheckpointOut
&cp
) const
619 DmaReadFifo::serialize(cp
);
621 SERIALIZE_SCALAR(nextLineAddr
);
622 SERIALIZE_SCALAR(frameEnd
);
626 HDLcd::DmaEngine::unserialize(CheckpointIn
&cp
)
628 DmaReadFifo::unserialize(cp
);
630 UNSERIALIZE_SCALAR(nextLineAddr
);
631 UNSERIALIZE_SCALAR(frameEnd
);
635 HDLcd::DmaEngine::startFrame(Addr fb_base
)
637 nextLineAddr
= fb_base
;
638 frameEnd
= fb_base
+ numLines
* linePitch
;
640 startFill(nextLineAddr
, lineSize
);
644 HDLcd::DmaEngine::abortFrame()
646 nextLineAddr
= frameEnd
;
653 HDLcd::DmaEngine::dumpSettings()
655 inform("DMA line size: %u bytes", lineSize
);
656 inform("DMA line pitch: %i bytes", linePitch
);
657 inform("DMA num lines: %u", numLines
);
661 HDLcd::DmaEngine::onEndOfBlock()
663 if (nextLineAddr
== frameEnd
)
664 // We're done with this frame. Ignore calls to this method
665 // until the next frame has been started.
668 nextLineAddr
+= linePitch
;
669 if (nextLineAddr
!= frameEnd
)
670 startFill(nextLineAddr
, lineSize
);
674 HDLcd::DmaEngine::onIdle()
676 parent
.intRaise(INT_DMA_END
);
680 HDLcd::PixelPump::dumpSettings()
682 const DisplayTimings
&t(timings());
684 inform("PixelPump width: %u", t
.width
);
685 inform("PixelPump height: %u", t
.height
);
687 inform("PixelPump horizontal back porch: %u", t
.hBackPorch
);
688 inform("PixelPump horizontal fron porch: %u", t
.hFrontPorch
);
689 inform("PixelPump horizontal fron porch: %u", t
.hSync
);
691 inform("PixelPump vertical back porch: %u", t
.vBackPorch
);
692 inform("PixelPump vertical fron porch: %u", t
.vFrontPorch
);
693 inform("PixelPump vertical fron porch: %u", t
.vSync
);
698 HDLcdParams::create()
700 return new HDLcd(this);