2 * Copyright (c) 2010 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 "base/vnc/vncserver.hh"
42 #include "base/bitmap.hh"
43 #include "base/output.hh"
44 #include "base/trace.hh"
45 #include "debug/PL111.hh"
46 #include "debug/Uart.hh"
47 #include "dev/arm/amba_device.hh"
48 #include "dev/arm/gic.hh"
49 #include "dev/arm/pl111.hh"
50 #include "mem/packet.hh"
51 #include "mem/packet_access.hh"
53 // clang complains about std::set being overloaded with Packet::set if
54 // we open up the entire namespace std
57 using namespace AmbaDev
;
59 // initialize clcd registers
60 Pl111::Pl111(const Params
*p
)
61 : AmbaDmaDevice(p
), lcdTiming0(0), lcdTiming1(0), lcdTiming2(0),
62 lcdTiming3(0), lcdUpbase(0), lcdLpbase(0), lcdControl(0), lcdImsc(0),
64 clcdCrsrCtrl(0), clcdCrsrConfig(0), clcdCrsrPalette0(0),
65 clcdCrsrPalette1(0), clcdCrsrXY(0), clcdCrsrClip(0), clcdCrsrImsc(0),
66 clcdCrsrIcr(0), clcdCrsrRis(0), clcdCrsrMis(0), clock(p
->clock
),
67 vncserver(p
->vnc
), bmp(NULL
), width(LcdMaxWidth
), height(LcdMaxHeight
),
68 bytesPerPixel(4), startTime(0), startAddr(0), maxAddr(0), curAddr(0),
69 waterMark(0), dmaPendingNum(0), readEvent(this), fillFifoEvent(this),
70 dmaDoneEvent(maxOutstandingDma
, this), intEvent(this)
74 pic
= simout
.create(csprintf("%s.framebuffer.bmp", sys
->name()), true);
76 const int buffer_size
= LcdMaxWidth
* LcdMaxHeight
* sizeof(uint32_t);
77 dmaBuffer
= new uint8_t[buffer_size
];
79 memset(lcdPalette
, 0, sizeof(lcdPalette
));
80 memset(cursorImage
, 0, sizeof(cursorImage
));
81 memset(dmaBuffer
, 0, buffer_size
);
84 vncserver
->setFramebufferAddr(dmaBuffer
);
87 // read registers and frame buffer
89 Pl111::read(PacketPtr pkt
)
91 // use a temporary data since the LCD registers are read/written with
92 // different size operations
96 assert(pkt
->getAddr() >= pioAddr
&&
97 pkt
->getAddr() < pioAddr
+ pioSize
);
99 Addr daddr
= pkt
->getAddr() - pioAddr
;
102 DPRINTF(PL111
, " read register %#x size=%d\n", daddr
, pkt
->getSize());
136 panic("LCD register at offset %#x is Write-Only\n", daddr
);
148 data
= clcdCrsrConfig
;
150 case ClcdCrsrPalette0
:
151 data
= clcdCrsrPalette0
;
153 case ClcdCrsrPalette1
:
154 data
= clcdCrsrPalette1
;
166 panic("CLCD register at offset %#x is Write-Only\n", daddr
);
175 if (AmbaDev::readId(pkt
, AMBA_ID
, pioAddr
)) {
176 // Hack for variable size accesses
177 data
= pkt
->get
<uint32_t>();
179 } else if (daddr
>= CrsrImage
&& daddr
<= 0xBFC) {
182 index
= (daddr
- CrsrImage
) >> 2;
183 data
= cursorImage
[index
];
185 } else if (daddr
>= LcdPalette
&& daddr
<= 0x3FC) {
188 index
= (daddr
- LcdPalette
) >> 2;
189 data
= lcdPalette
[index
];
192 panic("Tried to read CLCD register at offset %#x that \
193 doesn't exist\n", daddr
);
198 switch(pkt
->getSize()) {
200 pkt
->set
<uint8_t>(data
);
203 pkt
->set
<uint16_t>(data
);
206 pkt
->set
<uint32_t>(data
);
209 panic("CLCD controller read size too big?\n");
213 pkt
->makeAtomicResponse();
217 // write registers and frame buffer
219 Pl111::write(PacketPtr pkt
)
221 // use a temporary data since the LCD registers are read/written with
222 // different size operations
226 switch(pkt
->getSize()) {
228 data
= pkt
->get
<uint8_t>();
231 data
= pkt
->get
<uint16_t>();
234 data
= pkt
->get
<uint32_t>();
237 panic("PL111 CLCD controller write size too big?\n");
241 assert(pkt
->getAddr() >= pioAddr
&&
242 pkt
->getAddr() < pioAddr
+ pioSize
);
244 Addr daddr
= pkt
->getAddr() - pioAddr
;
246 DPRINTF(PL111
, " write register %#x value %#x size=%d\n", daddr
,
247 pkt
->get
<uint8_t>(), pkt
->getSize());
252 // width = 16 * (PPL+1)
253 width
= (lcdTiming0
.ppl
+ 1) << 4;
258 height
= (lcdTiming1
.lpp
) + 1;
268 DPRINTF(PL111
, "####### Upper panel base set to: %#x #######\n", lcdUpbase
);
271 warn_once("LCD dual screen mode not supported\n");
273 DPRINTF(PL111
, "###### Lower panel base set to: %#x #######\n", lcdLpbase
);
277 old_lcdpwr
= lcdControl
.lcdpwr
;
280 DPRINTF(PL111
, "LCD power is:%d\n", lcdControl
.lcdpwr
);
283 if (lcdControl
.lcdpwr
&& !old_lcdpwr
) {
285 DPRINTF(PL111
, " lcd size: height %d width %d\n", height
, width
);
286 waterMark
= lcdControl
.watermark
? 8 : 4;
293 panic("Interrupting on vcomp not supported\n");
295 lcdMis
= lcdImsc
& lcdRis
;
298 gic
->clearInt(intNum
);
302 panic("LCD register at offset %#x is Read-Only\n", daddr
);
305 panic("LCD register at offset %#x is Read-Only\n", daddr
);
308 lcdRis
= lcdRis
& ~data
;
309 lcdMis
= lcdImsc
& lcdRis
;
312 gic
->clearInt(intNum
);
316 panic("LCD register at offset %#x is Read-Only\n", daddr
);
319 panic("LCD register at offset %#x is Read-Only\n", daddr
);
325 clcdCrsrConfig
= data
;
327 case ClcdCrsrPalette0
:
328 clcdCrsrPalette0
= data
;
330 case ClcdCrsrPalette1
:
331 clcdCrsrPalette1
= data
;
346 panic("CLCD register at offset %#x is Read-Only\n", daddr
);
349 panic("CLCD register at offset %#x is Read-Only\n", daddr
);
352 if (daddr
>= CrsrImage
&& daddr
<= 0xBFC) {
355 index
= (daddr
- CrsrImage
) >> 2;
356 cursorImage
[index
] = data
;
358 } else if (daddr
>= LcdPalette
&& daddr
<= 0x3FC) {
361 index
= (daddr
- LcdPalette
) >> 2;
362 lcdPalette
[index
] = data
;
365 panic("Tried to write PL111 register at offset %#x that \
366 doesn't exist\n", daddr
);
371 pkt
->makeAtomicResponse();
376 Pl111::updateVideoParams()
378 if (lcdControl
.lcdbpp
== bpp24
) {
380 } else if (lcdControl
.lcdbpp
== bpp16m565
) {
385 if (lcdControl
.lcdbpp
== bpp24
&& lcdControl
.bgr
)
386 vncserver
->setFrameBufferParams(VideoConvert::bgr8888
, width
,
388 else if (lcdControl
.lcdbpp
== bpp24
&& !lcdControl
.bgr
)
389 vncserver
->setFrameBufferParams(VideoConvert::rgb8888
, width
,
391 else if (lcdControl
.lcdbpp
== bpp16m565
&& lcdControl
.bgr
)
392 vncserver
->setFrameBufferParams(VideoConvert::bgr565
, width
,
394 else if (lcdControl
.lcdbpp
== bpp16m565
&& !lcdControl
.bgr
)
395 vncserver
->setFrameBufferParams(VideoConvert::rgb565
, width
,
398 panic("Unimplemented video mode\n");
404 if (lcdControl
.lcdbpp
== bpp24
&& lcdControl
.bgr
)
405 bmp
= new Bitmap(VideoConvert::bgr8888
, width
, height
, dmaBuffer
);
406 else if (lcdControl
.lcdbpp
== bpp24
&& !lcdControl
.bgr
)
407 bmp
= new Bitmap(VideoConvert::rgb8888
, width
, height
, dmaBuffer
);
408 else if (lcdControl
.lcdbpp
== bpp16m565
&& lcdControl
.bgr
)
409 bmp
= new Bitmap(VideoConvert::bgr565
, width
, height
, dmaBuffer
);
410 else if (lcdControl
.lcdbpp
== bpp16m565
&& !lcdControl
.bgr
)
411 bmp
= new Bitmap(VideoConvert::rgb565
, width
, height
, dmaBuffer
);
413 panic("Unimplemented video mode\n");
419 if (dmaPendingNum
!= 0 || readEvent
.scheduled())
425 Pl111::readFramebuffer()
427 // initialization for dma read from frame buffer to dma buffer
428 uint32_t length
= height
* width
;
429 if (startAddr
!= lcdUpbase
)
430 startAddr
= lcdUpbase
;
432 // Updating base address, interrupt if we're supposed to
434 if (!intEvent
.scheduled())
435 schedule(intEvent
, nextCycle());
438 startTime
= curTick();
440 maxAddr
= static_cast<Addr
>(length
* bytesPerPixel
);
442 DPRINTF(PL111
, " lcd frame buffer size of %d bytes \n", maxAddr
);
452 while ((dmaPendingNum
< maxOutstandingDma
) && (maxAddr
>= curAddr
+ dmaSize
)) {
453 // concurrent dma reads need different dma done events
454 // due to assertion in scheduling state
457 assert(!dmaDoneEvent
[dmaPendingNum
-1].scheduled());
459 // We use a uncachable request here because the requests from the CPU
460 // will be uncacheable as well. If we have uncacheable and cacheable
461 // requests in the memory system for the same address it won't be
463 dmaPort
->dmaAction(MemCmd::ReadReq
, curAddr
+ startAddr
, dmaSize
,
464 &dmaDoneEvent
[dmaPendingNum
-1], curAddr
+ dmaBuffer
, 0,
465 Request::UNCACHEABLE
);
473 Tick maxFrameTime
= lcdTiming2
.cpl
* height
* clock
;
477 if (maxAddr
== curAddr
&& !dmaPendingNum
) {
478 if ((curTick() - startTime
) > maxFrameTime
) {
479 warn("CLCD controller buffer underrun, took %d cycles when should"
480 " have taken %d\n", curTick() - startTime
, maxFrameTime
);
481 lcdRis
.underflow
= 1;
482 if (!intEvent
.scheduled())
483 schedule(intEvent
, nextCycle());
486 assert(!readEvent
.scheduled());
488 vncserver
->setDirty();
490 DPRINTF(PL111
, "-- write out frame buffer into bmp\n");
496 DPRINTF(PL111
, "-- schedule next dma read event at %d tick \n",
497 maxFrameTime
+ curTick());
499 if (lcdControl
.lcden
)
500 schedule(readEvent
, nextCycle(startTime
+ maxFrameTime
));
503 if (dmaPendingNum
> (maxOutstandingDma
- waterMark
))
506 if (!fillFifoEvent
.scheduled())
507 schedule(fillFifoEvent
, nextCycle());
514 Tick nextTick
= curTick() + clock
- 1;
515 nextTick
-= nextTick
%clock
;
520 Pl111::nextCycle(Tick beginTick
)
522 Tick nextTick
= beginTick
;
523 if (nextTick
%clock
!=0)
524 nextTick
= nextTick
- (nextTick
%clock
) + clock
;
526 assert(nextTick
>= curTick());
531 Pl111::serialize(std::ostream
&os
)
533 DPRINTF(PL111
, "Serializing ARM PL111\n");
535 uint32_t lcdTiming0_serial
= lcdTiming0
;
536 SERIALIZE_SCALAR(lcdTiming0_serial
);
538 uint32_t lcdTiming1_serial
= lcdTiming1
;
539 SERIALIZE_SCALAR(lcdTiming1_serial
);
541 uint32_t lcdTiming2_serial
= lcdTiming2
;
542 SERIALIZE_SCALAR(lcdTiming2_serial
);
544 uint32_t lcdTiming3_serial
= lcdTiming3
;
545 SERIALIZE_SCALAR(lcdTiming3_serial
);
547 SERIALIZE_SCALAR(lcdUpbase
);
548 SERIALIZE_SCALAR(lcdLpbase
);
550 uint32_t lcdControl_serial
= lcdControl
;
551 SERIALIZE_SCALAR(lcdControl_serial
);
553 uint8_t lcdImsc_serial
= lcdImsc
;
554 SERIALIZE_SCALAR(lcdImsc_serial
);
556 uint8_t lcdRis_serial
= lcdRis
;
557 SERIALIZE_SCALAR(lcdRis_serial
);
559 uint8_t lcdMis_serial
= lcdMis
;
560 SERIALIZE_SCALAR(lcdMis_serial
);
562 SERIALIZE_ARRAY(lcdPalette
, LcdPaletteSize
);
563 SERIALIZE_ARRAY(cursorImage
, CrsrImageSize
);
565 SERIALIZE_SCALAR(clcdCrsrCtrl
);
566 SERIALIZE_SCALAR(clcdCrsrConfig
);
567 SERIALIZE_SCALAR(clcdCrsrPalette0
);
568 SERIALIZE_SCALAR(clcdCrsrPalette1
);
569 SERIALIZE_SCALAR(clcdCrsrXY
);
570 SERIALIZE_SCALAR(clcdCrsrClip
);
572 uint8_t clcdCrsrImsc_serial
= clcdCrsrImsc
;
573 SERIALIZE_SCALAR(clcdCrsrImsc_serial
);
575 uint8_t clcdCrsrIcr_serial
= clcdCrsrIcr
;
576 SERIALIZE_SCALAR(clcdCrsrIcr_serial
);
578 uint8_t clcdCrsrRis_serial
= clcdCrsrRis
;
579 SERIALIZE_SCALAR(clcdCrsrRis_serial
);
581 uint8_t clcdCrsrMis_serial
= clcdCrsrMis
;
582 SERIALIZE_SCALAR(clcdCrsrMis_serial
);
584 SERIALIZE_SCALAR(clock
);
585 SERIALIZE_SCALAR(height
);
586 SERIALIZE_SCALAR(width
);
587 SERIALIZE_SCALAR(bytesPerPixel
);
589 SERIALIZE_ARRAY(dmaBuffer
, height
* width
);
590 SERIALIZE_SCALAR(startTime
);
591 SERIALIZE_SCALAR(startAddr
);
592 SERIALIZE_SCALAR(maxAddr
);
593 SERIALIZE_SCALAR(curAddr
);
594 SERIALIZE_SCALAR(waterMark
);
595 SERIALIZE_SCALAR(dmaPendingNum
);
597 Tick int_event_time
= 0;
598 Tick read_event_time
= 0;
599 Tick fill_fifo_event_time
= 0;
601 if (readEvent
.scheduled())
602 read_event_time
= readEvent
.when();
603 if (fillFifoEvent
.scheduled())
604 fill_fifo_event_time
= fillFifoEvent
.when();
605 if (intEvent
.scheduled())
606 int_event_time
= intEvent
.when();
608 SERIALIZE_SCALAR(read_event_time
);
609 SERIALIZE_SCALAR(fill_fifo_event_time
);
610 SERIALIZE_SCALAR(int_event_time
);
612 vector
<Tick
> dma_done_event_tick
;
613 dma_done_event_tick
.resize(maxOutstandingDma
);
614 for (int x
= 0; x
< maxOutstandingDma
; x
++) {
615 dma_done_event_tick
[x
] = dmaDoneEvent
[x
].scheduled() ?
616 dmaDoneEvent
[x
].when() : 0;
618 arrayParamOut(os
, "dma_done_event_tick", dma_done_event_tick
);
622 Pl111::unserialize(Checkpoint
*cp
, const std::string
§ion
)
624 DPRINTF(PL111
, "Unserializing ARM PL111\n");
626 uint32_t lcdTiming0_serial
;
627 UNSERIALIZE_SCALAR(lcdTiming0_serial
);
628 lcdTiming0
= lcdTiming0_serial
;
630 uint32_t lcdTiming1_serial
;
631 UNSERIALIZE_SCALAR(lcdTiming1_serial
);
632 lcdTiming1
= lcdTiming1_serial
;
634 uint32_t lcdTiming2_serial
;
635 UNSERIALIZE_SCALAR(lcdTiming2_serial
);
636 lcdTiming2
= lcdTiming2_serial
;
638 uint32_t lcdTiming3_serial
;
639 UNSERIALIZE_SCALAR(lcdTiming3_serial
);
640 lcdTiming3
= lcdTiming3_serial
;
642 UNSERIALIZE_SCALAR(lcdUpbase
);
643 UNSERIALIZE_SCALAR(lcdLpbase
);
645 uint32_t lcdControl_serial
;
646 UNSERIALIZE_SCALAR(lcdControl_serial
);
647 lcdControl
= lcdControl_serial
;
649 uint8_t lcdImsc_serial
;
650 UNSERIALIZE_SCALAR(lcdImsc_serial
);
651 lcdImsc
= lcdImsc_serial
;
653 uint8_t lcdRis_serial
;
654 UNSERIALIZE_SCALAR(lcdRis_serial
);
655 lcdRis
= lcdRis_serial
;
657 uint8_t lcdMis_serial
;
658 UNSERIALIZE_SCALAR(lcdMis_serial
);
659 lcdMis
= lcdMis_serial
;
661 UNSERIALIZE_ARRAY(lcdPalette
, LcdPaletteSize
);
662 UNSERIALIZE_ARRAY(cursorImage
, CrsrImageSize
);
664 UNSERIALIZE_SCALAR(clcdCrsrCtrl
);
665 UNSERIALIZE_SCALAR(clcdCrsrConfig
);
666 UNSERIALIZE_SCALAR(clcdCrsrPalette0
);
667 UNSERIALIZE_SCALAR(clcdCrsrPalette1
);
668 UNSERIALIZE_SCALAR(clcdCrsrXY
);
669 UNSERIALIZE_SCALAR(clcdCrsrClip
);
671 uint8_t clcdCrsrImsc_serial
;
672 UNSERIALIZE_SCALAR(clcdCrsrImsc_serial
);
673 clcdCrsrImsc
= clcdCrsrImsc_serial
;
675 uint8_t clcdCrsrIcr_serial
;
676 UNSERIALIZE_SCALAR(clcdCrsrIcr_serial
);
677 clcdCrsrIcr
= clcdCrsrIcr_serial
;
679 uint8_t clcdCrsrRis_serial
;
680 UNSERIALIZE_SCALAR(clcdCrsrRis_serial
);
681 clcdCrsrRis
= clcdCrsrRis_serial
;
683 uint8_t clcdCrsrMis_serial
;
684 UNSERIALIZE_SCALAR(clcdCrsrMis_serial
);
685 clcdCrsrMis
= clcdCrsrMis_serial
;
687 UNSERIALIZE_SCALAR(clock
);
688 UNSERIALIZE_SCALAR(height
);
689 UNSERIALIZE_SCALAR(width
);
690 UNSERIALIZE_SCALAR(bytesPerPixel
);
692 UNSERIALIZE_ARRAY(dmaBuffer
, height
* width
);
693 UNSERIALIZE_SCALAR(startTime
);
694 UNSERIALIZE_SCALAR(startAddr
);
695 UNSERIALIZE_SCALAR(maxAddr
);
696 UNSERIALIZE_SCALAR(curAddr
);
697 UNSERIALIZE_SCALAR(waterMark
);
698 UNSERIALIZE_SCALAR(dmaPendingNum
);
700 Tick int_event_time
= 0;
701 Tick read_event_time
= 0;
702 Tick fill_fifo_event_time
= 0;
704 UNSERIALIZE_SCALAR(read_event_time
);
705 UNSERIALIZE_SCALAR(fill_fifo_event_time
);
706 UNSERIALIZE_SCALAR(int_event_time
);
709 schedule(intEvent
, int_event_time
);
711 schedule(readEvent
, read_event_time
);
712 if (fill_fifo_event_time
)
713 schedule(fillFifoEvent
, fill_fifo_event_time
);
715 vector
<Tick
> dma_done_event_tick
;
716 dma_done_event_tick
.resize(maxOutstandingDma
);
717 arrayParamIn(cp
, section
, "dma_done_event_tick", dma_done_event_tick
);
718 for (int x
= 0; x
< maxOutstandingDma
; x
++) {
719 if (dma_done_event_tick
[x
])
720 schedule(dmaDoneEvent
[x
], dma_done_event_tick
[x
]);
723 if (lcdControl
.lcdpwr
) {
726 vncserver
->setDirty();
731 Pl111::generateInterrupt()
733 DPRINTF(PL111
, "Generate Interrupt: lcdImsc=0x%x lcdRis=0x%x lcdMis=0x%x\n",
734 (uint32_t)lcdImsc
, (uint32_t)lcdRis
, (uint32_t)lcdMis
);
735 lcdMis
= lcdImsc
& lcdRis
;
737 if (lcdMis
.underflow
|| lcdMis
.baseaddr
|| lcdMis
.vcomp
|| lcdMis
.ahbmaster
) {
738 gic
->sendInt(intNum
);
739 DPRINTF(PL111
, " -- Generated\n");
744 Pl111::getAddrRanges()
746 AddrRangeList ranges
;
747 ranges
.push_back(RangeSize(pioAddr
, pioSize
));
752 Pl111Params::create()
754 return new Pl111(this);