2 * Copyright (c) 2010-2012, 2015 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: William Wang
41 #include "dev/arm/pl111.hh"
43 #include "base/output.hh"
44 #include "base/trace.hh"
45 #include "base/vnc/vncinput.hh"
46 #include "debug/PL111.hh"
47 #include "debug/Uart.hh"
48 #include "dev/arm/amba_device.hh"
49 #include "dev/arm/base_gic.hh"
50 #include "mem/packet.hh"
51 #include "mem/packet_access.hh"
52 #include "sim/system.hh"
54 // clang complains about std::set being overloaded with Packet::set if
55 // we open up the entire namespace std
58 // initialize clcd registers
59 Pl111::Pl111(const Params
*p
)
60 : AmbaDmaDevice(p
), lcdTiming0(0), lcdTiming1(0), lcdTiming2(0),
61 lcdTiming3(0), lcdUpbase(0), lcdLpbase(0), lcdControl(0), lcdImsc(0),
63 clcdCrsrCtrl(0), clcdCrsrConfig(0), clcdCrsrPalette0(0),
64 clcdCrsrPalette1(0), clcdCrsrXY(0), clcdCrsrClip(0), clcdCrsrImsc(0),
65 clcdCrsrIcr(0), clcdCrsrRis(0), clcdCrsrMis(0),
66 pixelClock(p
->pixel_clock
),
67 converter(PixelConverter::rgba8888_le
), fb(LcdMaxWidth
, LcdMaxHeight
),
68 vnc(p
->vnc
), bmp(&fb
), pic(NULL
),
69 width(LcdMaxWidth
), height(LcdMaxHeight
),
70 bytesPerPixel(4), startTime(0), startAddr(0), maxAddr(0), curAddr(0),
71 waterMark(0), dmaPendingNum(0),
72 readEvent([this]{ readFramebuffer(); }, name()),
73 fillFifoEvent([this]{ fillFifo(); }, name()),
74 dmaDoneEventAll(maxOutstandingDma
, this),
75 dmaDoneEventFree(maxOutstandingDma
),
76 intEvent([this]{ generateInterrupt(); }, name()),
77 enableCapture(p
->enable_capture
)
81 dmaBuffer
= new uint8_t[buffer_size
];
83 memset(lcdPalette
, 0, sizeof(lcdPalette
));
84 memset(cursorImage
, 0, sizeof(cursorImage
));
85 memset(dmaBuffer
, 0, buffer_size
);
87 for (int i
= 0; i
< maxOutstandingDma
; ++i
)
88 dmaDoneEventFree
[i
] = &dmaDoneEventAll
[i
];
91 vnc
->setFrameBuffer(&fb
);
99 // read registers and frame buffer
101 Pl111::read(PacketPtr pkt
)
103 // use a temporary data since the LCD registers are read/written with
104 // different size operations
108 assert(pkt
->getAddr() >= pioAddr
&&
109 pkt
->getAddr() < pioAddr
+ pioSize
);
111 Addr daddr
= pkt
->getAddr() - pioAddr
;
113 DPRINTF(PL111
, " read register %#x size=%d\n", daddr
, pkt
->getSize());
147 panic("LCD register at offset %#x is Write-Only\n", daddr
);
159 data
= clcdCrsrConfig
;
161 case ClcdCrsrPalette0
:
162 data
= clcdCrsrPalette0
;
164 case ClcdCrsrPalette1
:
165 data
= clcdCrsrPalette1
;
177 panic("CLCD register at offset %#x is Write-Only\n", daddr
);
186 if (readId(pkt
, AMBA_ID
, pioAddr
)) {
187 // Hack for variable size accesses
188 data
= pkt
->get
<uint32_t>();
190 } else if (daddr
>= CrsrImage
&& daddr
<= 0xBFC) {
193 index
= (daddr
- CrsrImage
) >> 2;
194 data
= cursorImage
[index
];
196 } else if (daddr
>= LcdPalette
&& daddr
<= 0x3FC) {
199 index
= (daddr
- LcdPalette
) >> 2;
200 data
= lcdPalette
[index
];
203 panic("Tried to read CLCD register at offset %#x that "
204 "doesn't exist\n", daddr
);
209 switch(pkt
->getSize()) {
211 pkt
->set
<uint8_t>(data
);
214 pkt
->set
<uint16_t>(data
);
217 pkt
->set
<uint32_t>(data
);
220 panic("CLCD controller read size too big?\n");
224 pkt
->makeAtomicResponse();
228 // write registers and frame buffer
230 Pl111::write(PacketPtr pkt
)
232 // use a temporary data since the LCD registers are read/written with
233 // different size operations
237 switch(pkt
->getSize()) {
239 data
= pkt
->get
<uint8_t>();
242 data
= pkt
->get
<uint16_t>();
245 data
= pkt
->get
<uint32_t>();
248 panic("PL111 CLCD controller write size too big?\n");
252 assert(pkt
->getAddr() >= pioAddr
&&
253 pkt
->getAddr() < pioAddr
+ pioSize
);
255 Addr daddr
= pkt
->getAddr() - pioAddr
;
257 DPRINTF(PL111
, " write register %#x value %#x size=%d\n", daddr
,
258 pkt
->get
<uint8_t>(), pkt
->getSize());
263 // width = 16 * (PPL+1)
264 width
= (lcdTiming0
.ppl
+ 1) << 4;
269 height
= (lcdTiming1
.lpp
) + 1;
279 DPRINTF(PL111
, "####### Upper panel base set to: %#x #######\n", lcdUpbase
);
282 warn_once("LCD dual screen mode not supported\n");
284 DPRINTF(PL111
, "###### Lower panel base set to: %#x #######\n", lcdLpbase
);
288 old_lcdpwr
= lcdControl
.lcdpwr
;
291 DPRINTF(PL111
, "LCD power is:%d\n", lcdControl
.lcdpwr
);
294 if (lcdControl
.lcdpwr
&& !old_lcdpwr
) {
296 DPRINTF(PL111
, " lcd size: height %d width %d\n", height
, width
);
297 waterMark
= lcdControl
.watermark
? 8 : 4;
304 panic("Interrupting on vcomp not supported\n");
306 lcdMis
= lcdImsc
& lcdRis
;
309 gic
->clearInt(intNum
);
313 panic("LCD register at offset %#x is Read-Only\n", daddr
);
316 panic("LCD register at offset %#x is Read-Only\n", daddr
);
319 lcdRis
= lcdRis
& ~data
;
320 lcdMis
= lcdImsc
& lcdRis
;
323 gic
->clearInt(intNum
);
327 panic("LCD register at offset %#x is Read-Only\n", daddr
);
330 panic("LCD register at offset %#x is Read-Only\n", daddr
);
336 clcdCrsrConfig
= data
;
338 case ClcdCrsrPalette0
:
339 clcdCrsrPalette0
= data
;
341 case ClcdCrsrPalette1
:
342 clcdCrsrPalette1
= data
;
357 panic("CLCD register at offset %#x is Read-Only\n", daddr
);
360 panic("CLCD register at offset %#x is Read-Only\n", daddr
);
363 if (daddr
>= CrsrImage
&& daddr
<= 0xBFC) {
366 index
= (daddr
- CrsrImage
) >> 2;
367 cursorImage
[index
] = data
;
369 } else if (daddr
>= LcdPalette
&& daddr
<= 0x3FC) {
372 index
= (daddr
- LcdPalette
) >> 2;
373 lcdPalette
[index
] = data
;
376 panic("Tried to write PL111 register at offset %#x that "
377 "doesn't exist\n", daddr
);
382 pkt
->makeAtomicResponse();
387 Pl111::pixelConverter() const
392 switch (lcdControl
.lcdbpp
) {
410 panic("Unimplemented video mode\n");
413 if (lcdControl
.bgr
) {
414 return PixelConverter(
416 offsets
[2], offsets
[1], offsets
[0],
418 LittleEndianByteOrder
);
420 return PixelConverter(
422 offsets
[0], offsets
[1], offsets
[2],
424 LittleEndianByteOrder
);
429 Pl111::updateVideoParams()
431 if (lcdControl
.lcdbpp
== bpp24
) {
433 } else if (lcdControl
.lcdbpp
== bpp16m565
) {
437 fb
.resize(width
, height
);
438 converter
= pixelConverter();
440 // Workaround configuration bugs where multiple display
441 // controllers are attached to the same VNC server by reattaching
442 // enabled devices. This isn't ideal, but works as long as only
443 // one display controller is active at a time.
444 if (lcdControl
.lcdpwr
&& vnc
)
445 vnc
->setFrameBuffer(&fb
);
451 if (dmaPendingNum
!= 0 || readEvent
.scheduled())
457 Pl111::readFramebuffer()
459 // initialization for dma read from frame buffer to dma buffer
460 uint32_t length
= height
* width
;
461 if (startAddr
!= lcdUpbase
)
462 startAddr
= lcdUpbase
;
464 // Updating base address, interrupt if we're supposed to
466 if (!intEvent
.scheduled())
467 schedule(intEvent
, clockEdge());
470 startTime
= curTick();
472 maxAddr
= static_cast<Addr
>(length
* bytesPerPixel
);
474 DPRINTF(PL111
, " lcd frame buffer size of %d bytes \n", maxAddr
);
482 while ((dmaPendingNum
< maxOutstandingDma
) && (maxAddr
>= curAddr
+ dmaSize
)) {
483 // concurrent dma reads need different dma done events
484 // due to assertion in scheduling state
487 assert(!dmaDoneEventFree
.empty());
488 DmaDoneEvent
*event(dmaDoneEventFree
.back());
489 dmaDoneEventFree
.pop_back();
490 assert(!event
->scheduled());
492 // We use a uncachable request here because the requests from the CPU
493 // will be uncacheable as well. If we have uncacheable and cacheable
494 // requests in the memory system for the same address it won't be
496 dmaPort
.dmaAction(MemCmd::ReadReq
, curAddr
+ startAddr
, dmaSize
,
497 event
, curAddr
+ dmaBuffer
,
498 0, Request::UNCACHEABLE
);
506 DPRINTF(PL111
, "DMA Done\n");
508 Tick maxFrameTime
= lcdTiming2
.cpl
* height
* pixelClock
;
512 if (maxAddr
== curAddr
&& !dmaPendingNum
) {
513 if ((curTick() - startTime
) > maxFrameTime
) {
514 warn("CLCD controller buffer underrun, took %d ticks when should"
515 " have taken %d\n", curTick() - startTime
, maxFrameTime
);
516 lcdRis
.underflow
= 1;
517 if (!intEvent
.scheduled())
518 schedule(intEvent
, clockEdge());
521 assert(!readEvent
.scheduled());
522 fb
.copyIn(dmaBuffer
, converter
);
527 DPRINTF(PL111
, "-- write out frame buffer into bmp\n");
530 pic
= simout
.create(csprintf("%s.framebuffer.bmp", sys
->name()),
534 pic
->stream()->seekp(0);
535 bmp
.write(*pic
->stream());
538 // schedule the next read based on when the last frame started
539 // and the desired fps (i.e. maxFrameTime), we turn the
540 // argument into a relative number of cycles in the future
541 if (lcdControl
.lcden
)
542 schedule(readEvent
, clockEdge(ticksToCycles(startTime
-
547 if (dmaPendingNum
> (maxOutstandingDma
- waterMark
))
550 if (!fillFifoEvent
.scheduled())
551 schedule(fillFifoEvent
, clockEdge());
555 Pl111::serialize(CheckpointOut
&cp
) const
557 DPRINTF(PL111
, "Serializing ARM PL111\n");
559 uint32_t lcdTiming0_serial
= lcdTiming0
;
560 SERIALIZE_SCALAR(lcdTiming0_serial
);
562 uint32_t lcdTiming1_serial
= lcdTiming1
;
563 SERIALIZE_SCALAR(lcdTiming1_serial
);
565 uint32_t lcdTiming2_serial
= lcdTiming2
;
566 SERIALIZE_SCALAR(lcdTiming2_serial
);
568 uint32_t lcdTiming3_serial
= lcdTiming3
;
569 SERIALIZE_SCALAR(lcdTiming3_serial
);
571 SERIALIZE_SCALAR(lcdUpbase
);
572 SERIALIZE_SCALAR(lcdLpbase
);
574 uint32_t lcdControl_serial
= lcdControl
;
575 SERIALIZE_SCALAR(lcdControl_serial
);
577 uint8_t lcdImsc_serial
= lcdImsc
;
578 SERIALIZE_SCALAR(lcdImsc_serial
);
580 uint8_t lcdRis_serial
= lcdRis
;
581 SERIALIZE_SCALAR(lcdRis_serial
);
583 uint8_t lcdMis_serial
= lcdMis
;
584 SERIALIZE_SCALAR(lcdMis_serial
);
586 SERIALIZE_ARRAY(lcdPalette
, LcdPaletteSize
);
587 SERIALIZE_ARRAY(cursorImage
, CrsrImageSize
);
589 SERIALIZE_SCALAR(clcdCrsrCtrl
);
590 SERIALIZE_SCALAR(clcdCrsrConfig
);
591 SERIALIZE_SCALAR(clcdCrsrPalette0
);
592 SERIALIZE_SCALAR(clcdCrsrPalette1
);
593 SERIALIZE_SCALAR(clcdCrsrXY
);
594 SERIALIZE_SCALAR(clcdCrsrClip
);
596 uint8_t clcdCrsrImsc_serial
= clcdCrsrImsc
;
597 SERIALIZE_SCALAR(clcdCrsrImsc_serial
);
599 uint8_t clcdCrsrIcr_serial
= clcdCrsrIcr
;
600 SERIALIZE_SCALAR(clcdCrsrIcr_serial
);
602 uint8_t clcdCrsrRis_serial
= clcdCrsrRis
;
603 SERIALIZE_SCALAR(clcdCrsrRis_serial
);
605 uint8_t clcdCrsrMis_serial
= clcdCrsrMis
;
606 SERIALIZE_SCALAR(clcdCrsrMis_serial
);
608 SERIALIZE_SCALAR(height
);
609 SERIALIZE_SCALAR(width
);
610 SERIALIZE_SCALAR(bytesPerPixel
);
612 SERIALIZE_ARRAY(dmaBuffer
, buffer_size
);
613 SERIALIZE_SCALAR(startTime
);
614 SERIALIZE_SCALAR(startAddr
);
615 SERIALIZE_SCALAR(maxAddr
);
616 SERIALIZE_SCALAR(curAddr
);
617 SERIALIZE_SCALAR(waterMark
);
618 SERIALIZE_SCALAR(dmaPendingNum
);
620 Tick int_event_time
= 0;
621 Tick read_event_time
= 0;
622 Tick fill_fifo_event_time
= 0;
624 if (readEvent
.scheduled())
625 read_event_time
= readEvent
.when();
626 if (fillFifoEvent
.scheduled())
627 fill_fifo_event_time
= fillFifoEvent
.when();
628 if (intEvent
.scheduled())
629 int_event_time
= intEvent
.when();
631 SERIALIZE_SCALAR(read_event_time
);
632 SERIALIZE_SCALAR(fill_fifo_event_time
);
633 SERIALIZE_SCALAR(int_event_time
);
635 vector
<Tick
> dma_done_event_tick
;
636 dma_done_event_tick
.resize(maxOutstandingDma
);
637 for (int x
= 0; x
< maxOutstandingDma
; x
++) {
638 dma_done_event_tick
[x
] = dmaDoneEventAll
[x
].scheduled() ?
639 dmaDoneEventAll
[x
].when() : 0;
641 SERIALIZE_CONTAINER(dma_done_event_tick
);
645 Pl111::unserialize(CheckpointIn
&cp
)
647 DPRINTF(PL111
, "Unserializing ARM PL111\n");
649 uint32_t lcdTiming0_serial
;
650 UNSERIALIZE_SCALAR(lcdTiming0_serial
);
651 lcdTiming0
= lcdTiming0_serial
;
653 uint32_t lcdTiming1_serial
;
654 UNSERIALIZE_SCALAR(lcdTiming1_serial
);
655 lcdTiming1
= lcdTiming1_serial
;
657 uint32_t lcdTiming2_serial
;
658 UNSERIALIZE_SCALAR(lcdTiming2_serial
);
659 lcdTiming2
= lcdTiming2_serial
;
661 uint32_t lcdTiming3_serial
;
662 UNSERIALIZE_SCALAR(lcdTiming3_serial
);
663 lcdTiming3
= lcdTiming3_serial
;
665 UNSERIALIZE_SCALAR(lcdUpbase
);
666 UNSERIALIZE_SCALAR(lcdLpbase
);
668 uint32_t lcdControl_serial
;
669 UNSERIALIZE_SCALAR(lcdControl_serial
);
670 lcdControl
= lcdControl_serial
;
672 uint8_t lcdImsc_serial
;
673 UNSERIALIZE_SCALAR(lcdImsc_serial
);
674 lcdImsc
= lcdImsc_serial
;
676 uint8_t lcdRis_serial
;
677 UNSERIALIZE_SCALAR(lcdRis_serial
);
678 lcdRis
= lcdRis_serial
;
680 uint8_t lcdMis_serial
;
681 UNSERIALIZE_SCALAR(lcdMis_serial
);
682 lcdMis
= lcdMis_serial
;
684 UNSERIALIZE_ARRAY(lcdPalette
, LcdPaletteSize
);
685 UNSERIALIZE_ARRAY(cursorImage
, CrsrImageSize
);
687 UNSERIALIZE_SCALAR(clcdCrsrCtrl
);
688 UNSERIALIZE_SCALAR(clcdCrsrConfig
);
689 UNSERIALIZE_SCALAR(clcdCrsrPalette0
);
690 UNSERIALIZE_SCALAR(clcdCrsrPalette1
);
691 UNSERIALIZE_SCALAR(clcdCrsrXY
);
692 UNSERIALIZE_SCALAR(clcdCrsrClip
);
694 uint8_t clcdCrsrImsc_serial
;
695 UNSERIALIZE_SCALAR(clcdCrsrImsc_serial
);
696 clcdCrsrImsc
= clcdCrsrImsc_serial
;
698 uint8_t clcdCrsrIcr_serial
;
699 UNSERIALIZE_SCALAR(clcdCrsrIcr_serial
);
700 clcdCrsrIcr
= clcdCrsrIcr_serial
;
702 uint8_t clcdCrsrRis_serial
;
703 UNSERIALIZE_SCALAR(clcdCrsrRis_serial
);
704 clcdCrsrRis
= clcdCrsrRis_serial
;
706 uint8_t clcdCrsrMis_serial
;
707 UNSERIALIZE_SCALAR(clcdCrsrMis_serial
);
708 clcdCrsrMis
= clcdCrsrMis_serial
;
710 UNSERIALIZE_SCALAR(height
);
711 UNSERIALIZE_SCALAR(width
);
712 UNSERIALIZE_SCALAR(bytesPerPixel
);
714 UNSERIALIZE_ARRAY(dmaBuffer
, buffer_size
);
715 UNSERIALIZE_SCALAR(startTime
);
716 UNSERIALIZE_SCALAR(startAddr
);
717 UNSERIALIZE_SCALAR(maxAddr
);
718 UNSERIALIZE_SCALAR(curAddr
);
719 UNSERIALIZE_SCALAR(waterMark
);
720 UNSERIALIZE_SCALAR(dmaPendingNum
);
722 Tick int_event_time
= 0;
723 Tick read_event_time
= 0;
724 Tick fill_fifo_event_time
= 0;
726 UNSERIALIZE_SCALAR(read_event_time
);
727 UNSERIALIZE_SCALAR(fill_fifo_event_time
);
728 UNSERIALIZE_SCALAR(int_event_time
);
731 schedule(intEvent
, int_event_time
);
733 schedule(readEvent
, read_event_time
);
734 if (fill_fifo_event_time
)
735 schedule(fillFifoEvent
, fill_fifo_event_time
);
737 vector
<Tick
> dma_done_event_tick
;
738 dma_done_event_tick
.resize(maxOutstandingDma
);
739 UNSERIALIZE_CONTAINER(dma_done_event_tick
);
740 dmaDoneEventFree
.clear();
741 for (int x
= 0; x
< maxOutstandingDma
; x
++) {
742 if (dma_done_event_tick
[x
])
743 schedule(dmaDoneEventAll
[x
], dma_done_event_tick
[x
]);
745 dmaDoneEventFree
.push_back(&dmaDoneEventAll
[x
]);
747 assert(maxOutstandingDma
- dmaDoneEventFree
.size() == dmaPendingNum
);
749 if (lcdControl
.lcdpwr
) {
751 fb
.copyIn(dmaBuffer
, converter
);
758 Pl111::generateInterrupt()
760 DPRINTF(PL111
, "Generate Interrupt: lcdImsc=0x%x lcdRis=0x%x lcdMis=0x%x\n",
761 (uint32_t)lcdImsc
, (uint32_t)lcdRis
, (uint32_t)lcdMis
);
762 lcdMis
= lcdImsc
& lcdRis
;
764 if (lcdMis
.underflow
|| lcdMis
.baseaddr
|| lcdMis
.vcomp
|| lcdMis
.ahbmaster
) {
765 gic
->sendInt(intNum
);
766 DPRINTF(PL111
, " -- Generated\n");
771 Pl111::getAddrRanges() const
773 AddrRangeList ranges
;
774 ranges
.push_back(RangeSize(pioAddr
, pioSize
));
779 Pl111Params::create()
781 return new Pl111(this);