summaryrefslogtreecommitdiff
path: root/src/dev
diff options
context:
space:
mode:
authorWilliam Wang <William.Wang@arm.com>2010-11-15 14:04:03 -0600
committerWilliam Wang <William.Wang@arm.com>2010-11-15 14:04:03 -0600
commitfc1eeafc94b3bab13ffbfd85e0c255f3459355fa (patch)
tree0555eb8dbb5f0bc345454fc7eacb457552c01316 /src/dev
parent80db6a5ecb1ab836ca0d224ba2e88dd341dc2749 (diff)
downloadgem5-fc1eeafc94b3bab13ffbfd85e0c255f3459355fa.tar.xz
ARM: Implement a CLCD Frame buffer
Diffstat (limited to 'src/dev')
-rw-r--r--src/dev/arm/RealView.py21
-rw-r--r--src/dev/arm/SConscript2
-rw-r--r--src/dev/arm/amba_device.cc9
-rw-r--r--src/dev/arm/amba_device.hh14
-rw-r--r--src/dev/arm/pl111.cc653
-rw-r--r--src/dev/arm/pl111.hh368
6 files changed, 1056 insertions, 11 deletions
diff --git a/src/dev/arm/RealView.py b/src/dev/arm/RealView.py
index b529fdfd4..4b7cc787c 100644
--- a/src/dev/arm/RealView.py
+++ b/src/dev/arm/RealView.py
@@ -54,6 +54,10 @@ class AmbaDevice(BasicPioDevice):
class AmbaDmaDevice(DmaDevice):
type = 'AmbaDmaDevice'
abstract = True
+ pio_addr = Param.Addr("Address for AMBA slave interface")
+ pio_latency = Param.Latency("10ns", "Time between action and write/read result by AMBA DMA Device")
+ gic = Param.Gic(Parent.any, "Gic to use for interrupting")
+ int_num = Param.UInt32("Interrupt number that connects to GIC")
amba_id = Param.UInt32("ID of AMBA device for kernel detection")
class RealViewCtrl(BasicPioDevice):
@@ -89,16 +93,25 @@ class Sp804(AmbaDevice):
clock1 = Param.Clock('1MHz', "Clock speed of the input")
amba_id = 0x00141804
+class Pl111(AmbaDmaDevice):
+ type = 'Pl111'
+ clock = Param.Clock('24MHz', "Clock speed of the input")
+ amba_id = 0x00141111
+
class RealView(Platform):
type = 'RealView'
system = Param.System(Parent.any, "system")
+# Reference for memory map and interrupt number
+# RealView Platform Baseboard Explore for Cortex-A9 User Guide(ARM DUI 0440A)
+# Chapter 4: Programmer's Reference
class RealViewPBX(RealView):
uart = Pl011(pio_addr=0x10009000, int_num=44)
realview_io = RealViewCtrl(pio_addr=0x10000000)
gic = Gic()
timer0 = Sp804(int_num0=36, int_num1=36, pio_addr=0x10011000)
timer1 = Sp804(int_num0=37, int_num1=37, pio_addr=0x10012000)
+ clcd = Pl111(pio_addr=0x10020000, int_num=55)
l2x0_fake = IsaFake(pio_addr=0x1f002000, pio_size=0xfff)
flash_fake = IsaFake(pio_addr=0x40000000, pio_size=0x4000000)
@@ -107,7 +120,6 @@ class RealViewPBX(RealView):
uart2_fake = AmbaFake(pio_addr=0x1000b000)
uart3_fake = AmbaFake(pio_addr=0x1000c000)
smc_fake = AmbaFake(pio_addr=0x100e1000)
- clcd_fake = AmbaFake(pio_addr=0x10020000)
sp810_fake = AmbaFake(pio_addr=0x10001000, ignore_access=True)
watchdog_fake = AmbaFake(pio_addr=0x10010000)
gpio0_fake = AmbaFake(pio_addr=0x10013000)
@@ -136,12 +148,12 @@ class RealViewPBX(RealView):
self.realview_io.pio = bus.port
self.timer0.pio = bus.port
self.timer1.pio = bus.port
+ self.clcd.pio = bus.port
self.dmac_fake.pio = bus.port
self.uart1_fake.pio = bus.port
self.uart2_fake.pio = bus.port
self.uart3_fake.pio = bus.port
self.smc_fake.pio = bus.port
- self.clcd_fake.pio = bus.port
self.sp810_fake.pio = bus.port
self.watchdog_fake.pio = bus.port
self.gpio0_fake.pio = bus.port
@@ -156,12 +168,14 @@ class RealViewPBX(RealView):
self.rtc_fake.pio = bus.port
self.flash_fake.pio = bus.port
+# Interrupt numbers are wrong here
class RealViewEB(RealView):
uart = Pl011(pio_addr=0x10009000, int_num=44)
realview_io = RealViewCtrl(pio_addr=0x10000000)
gic = Gic(dist_addr=0x10041000, cpu_addr=0x10040000)
timer0 = Sp804(int_num0=36, int_num1=36, pio_addr=0x10011000)
timer1 = Sp804(int_num0=37, int_num1=37, pio_addr=0x10012000)
+ clcd = Pl111(pio_addr=0x10020000, int_num=55)
l2x0_fake = IsaFake(pio_addr=0x1f002000, pio_size=0xfff, warn_access="1")
dmac_fake = AmbaFake(pio_addr=0x10030000)
@@ -169,7 +183,6 @@ class RealViewEB(RealView):
uart2_fake = AmbaFake(pio_addr=0x1000b000)
uart3_fake = AmbaFake(pio_addr=0x1000c000)
smc_fake = AmbaFake(pio_addr=0x100e1000)
- clcd_fake = AmbaFake(pio_addr=0x10020000)
sp810_fake = AmbaFake(pio_addr=0x10001000, ignore_access=True)
watchdog_fake = AmbaFake(pio_addr=0x10010000)
gpio0_fake = AmbaFake(pio_addr=0x10013000)
@@ -198,12 +211,12 @@ class RealViewEB(RealView):
self.realview_io.pio = bus.port
self.timer0.pio = bus.port
self.timer1.pio = bus.port
+ self.clcd.pio = bus.port
self.dmac_fake.pio = bus.port
self.uart1_fake.pio = bus.port
self.uart2_fake.pio = bus.port
self.uart3_fake.pio = bus.port
self.smc_fake.pio = bus.port
- self.clcd_fake.pio = bus.port
self.sp810_fake.pio = bus.port
self.watchdog_fake.pio = bus.port
self.gpio0_fake.pio = bus.port
diff --git a/src/dev/arm/SConscript b/src/dev/arm/SConscript
index 66a97a92e..fc77c6d68 100644
--- a/src/dev/arm/SConscript
+++ b/src/dev/arm/SConscript
@@ -46,9 +46,11 @@ if env['FULL_SYSTEM'] and env['TARGET_ISA'] == 'arm':
Source('amba_fake.cc')
Source('gic.cc')
Source('pl011.cc')
+ Source('pl111.cc')
Source('timer_sp804.cc')
Source('rv_ctrl.cc')
Source('realview.cc')
TraceFlag('AMBA')
+ TraceFlag('PL111')
TraceFlag('GIC')
diff --git a/src/dev/arm/amba_device.cc b/src/dev/arm/amba_device.cc
index 0acd7208a..e5d53d6a3 100644
--- a/src/dev/arm/amba_device.cc
+++ b/src/dev/arm/amba_device.cc
@@ -42,20 +42,23 @@
#include "base/trace.hh"
#include "dev/arm/amba_fake.hh"
+#include "dev/arm/amba_device.hh"
#include "mem/packet.hh"
#include "mem/packet_access.hh"
+const uint64_t AmbaVendor = ULL(0xb105f00d00000000);
AmbaDevice::AmbaDevice(const Params *p)
- : BasicPioDevice(p), ambaId(ULL(0xb105f00d00000000) | p->amba_id)
+ : BasicPioDevice(p), ambaId(AmbaVendor | p->amba_id)
{
}
AmbaDmaDevice::AmbaDmaDevice(const Params *p)
- : DmaDevice(p), ambaId(ULL(0xb105f00d00000000) | p->amba_id)
+ : DmaDevice(p), ambaId(AmbaVendor | p->amba_id),
+ pioAddr(p->pio_addr), pioSize(0),
+ pioDelay(p->pio_latency),intNum(p->int_num), gic(p->gic)
{
}
-
namespace AmbaDev {
bool
readId(PacketPtr pkt, uint64_t amba_id, Addr pio_addr)
diff --git a/src/dev/arm/amba_device.hh b/src/dev/arm/amba_device.hh
index 679202c84..1782fb003 100644
--- a/src/dev/arm/amba_device.hh
+++ b/src/dev/arm/amba_device.hh
@@ -46,13 +46,14 @@
* Implementer ID calls.
*/
-#ifndef __DEV_ARM_AMBA_DEVICE_H__
-#define __DEV_ARM_AMBA_DEVICE_H__
+#ifndef __DEV_ARM_AMBA_DEVICE_HH__
+#define __DEV_ARM_AMBA_DEVICE_HH__
#include "base/range.hh"
+#include "dev/io_device.hh"
+#include "dev/arm/gic.hh"
#include "mem/packet.hh"
#include "mem/packet_access.hh"
-#include "dev/io_device.hh"
#include "params/AmbaDevice.hh"
#include "params/AmbaDmaDevice.hh"
@@ -84,6 +85,11 @@ class AmbaDmaDevice : public DmaDevice
{
protected:
uint64_t ambaId;
+ Addr pioAddr;
+ Addr pioSize;
+ Tick pioDelay;
+ int intNum;
+ Gic *gic;
public:
typedef AmbaDmaDeviceParams Params;
@@ -91,4 +97,4 @@ class AmbaDmaDevice : public DmaDevice
};
-#endif //__DEV_ARM_AMBA_DEVICE_H__
+#endif //__DEV_ARM_AMBA_DEVICE_HH__
diff --git a/src/dev/arm/pl111.cc b/src/dev/arm/pl111.cc
new file mode 100644
index 000000000..e78d28141
--- /dev/null
+++ b/src/dev/arm/pl111.cc
@@ -0,0 +1,653 @@
+/*
+ * Copyright (c) 2010 ARM Limited
+ * All rights reserved
+ *
+ * The license below extends only to copyright in the software and shall
+ * not be construed as granting a license to any other intellectual
+ * property including but not limited to intellectual property relating
+ * to a hardware implementation of the functionality of the software
+ * licensed hereunder. You may use the software subject to the license
+ * terms below provided that you ensure that this notice is replicated
+ * unmodified and in its entirety in all distributions of the software,
+ * modified or unmodified, in source code or in binary form.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: William Wang
+ */
+
+#include "base/trace.hh"
+#include "dev/arm/amba_device.hh"
+#include "dev/arm/gic.hh"
+#include "dev/arm/pl111.hh"
+#include "mem/packet.hh"
+#include "mem/packet_access.hh"
+
+using namespace AmbaDev;
+
+// initialize clcd registers
+Pl111::Pl111(const Params *p)
+ : AmbaDmaDevice(p), lcdTiming0(0), lcdTiming1(0), lcdTiming2(0),
+ lcdTiming3(0), lcdUpbase(0), lcdLpbase(0), lcdControl(0), lcdImsc(0),
+ lcdRis(0), lcdMis(0), lcdIcr(0), lcdUpcurr(0), lcdLpcurr(0),
+ clcdCrsrCtrl(0), clcdCrsrConfig(0), clcdCrsrPalette0(0),
+ clcdCrsrPalette1(0), clcdCrsrXY(0), clcdCrsrClip(0), clcdCrsrImsc(0),
+ clcdCrsrIcr(0), clcdCrsrRis(0), clcdCrsrMis(0), clock(p->clock),
+ height(0), width(0), startTime(0), startAddr(0), maxAddr(0), curAddr(0),
+ waterMark(0), dmaPendingNum(0), readEvent(this), fillFifoEvent(this),
+ dmaDoneEvent(maxOutstandingDma, this), intEvent(this)
+{
+ pioSize = 0xFFFF;
+
+ memset(lcdPalette, 0, sizeof(lcdPalette));
+ memset(cursorImage, 0, sizeof(cursorImage));
+ memset(dmaBuffer, 0, sizeof(dmaBuffer));
+ memset(frameBuffer, 0, sizeof(frameBuffer));
+}
+
+// read registers and frame buffer
+Tick
+Pl111::read(PacketPtr pkt)
+{
+ // use a temporary data since the LCD registers are read/written with
+ // different size operations
+
+ uint32_t data = 0;
+
+ if ((pkt->getAddr()& 0xffff0000) == pioAddr) {
+
+ assert(pkt->getAddr() >= pioAddr &&
+ pkt->getAddr() < pioAddr + pioSize);
+
+ Addr daddr = pkt->getAddr()&0xFFFF;
+ pkt->allocate();
+
+ DPRINTF(PL111, " read register %#x size=%d\n", daddr, pkt->getSize());
+
+ switch (daddr) {
+ case LcdTiming0:
+ data = lcdTiming0;
+ break;
+ case LcdTiming1:
+ data = lcdTiming1;
+ break;
+ case LcdTiming2:
+ data = lcdTiming2;
+ break;
+ case LcdTiming3:
+ data = lcdTiming3;
+ break;
+ case LcdUpBase:
+ data = lcdUpbase;
+ break;
+ case LcdLpBase:
+ data = lcdLpbase;
+ break;
+ case LcdControl:
+ data = lcdControl;
+ break;
+ case LcdImsc:
+ warn("LCD interrupt set/clear function not supported\n");
+ data = lcdImsc;
+ break;
+ case LcdRis:
+ warn("LCD Raw interrupt status function not supported\n");
+ data = lcdRis;
+ break;
+ case LcdMis:
+ warn("LCD Masked interrupt status function not supported\n");
+ data = lcdMis;
+ break;
+ case LcdIcr:
+ panic("LCD register at offset %#x is Write-Only\n", daddr);
+ break;
+ case LcdUpCurr:
+ data = lcdUpcurr;
+ break;
+ case LcdLpCurr:
+ data = lcdLpcurr;
+ break;
+ case ClcdCrsrCtrl:
+ data = clcdCrsrCtrl;
+ break;
+ case ClcdCrsrConfig:
+ data = clcdCrsrConfig;
+ break;
+ case ClcdCrsrPalette0:
+ data = clcdCrsrPalette0;
+ break;
+ case ClcdCrsrPalette1:
+ data = clcdCrsrPalette1;
+ break;
+ case ClcdCrsrXY:
+ data = clcdCrsrXY;
+ break;
+ case ClcdCrsrClip:
+ data = clcdCrsrClip;
+ break;
+ case ClcdCrsrImsc:
+ data = clcdCrsrImsc;
+ break;
+ case ClcdCrsrIcr:
+ panic("CLCD register at offset %#x is Write-Only\n", daddr);
+ break;
+ case ClcdCrsrRis:
+ data = clcdCrsrRis;
+ break;
+ case ClcdCrsrMis:
+ data = clcdCrsrMis;
+ break;
+ default:
+ if (AmbaDev::readId(pkt, AMBA_ID, pioAddr)) {
+ // Hack for variable size accesses
+ data = pkt->get<uint32_t>();
+ break;
+ } else if (daddr >= CrsrImage && daddr <= 0xBFC) {
+ // CURSOR IMAGE
+ int index;
+ index = (daddr - CrsrImage) >> 2;
+ data= cursorImage[index];
+ break;
+ } else if (daddr >= LcdPalette && daddr <= 0x3FC) {
+ // LCD Palette
+ int index;
+ index = (daddr - LcdPalette) >> 2;
+ data = lcdPalette[index];
+ break;
+ } else {
+ panic("Tried to read CLCD register at offset %#x that \
+ doesn't exist\n", daddr);
+ break;
+ }
+ }
+ }
+
+ switch(pkt->getSize()) {
+ case 1:
+ pkt->set<uint8_t>(data);
+ break;
+ case 2:
+ pkt->set<uint16_t>(data);
+ break;
+ case 4:
+ pkt->set<uint32_t>(data);
+ break;
+ default:
+ panic("CLCD controller read size too big?\n");
+ break;
+ }
+
+ pkt->makeAtomicResponse();
+ return pioDelay;
+}
+
+// write registers and frame buffer
+Tick
+Pl111::write(PacketPtr pkt)
+{
+ // use a temporary data since the LCD registers are read/written with
+ // different size operations
+ //
+ uint32_t data = 0;
+
+ switch(pkt->getSize()) {
+ case 1:
+ data = pkt->get<uint8_t>();
+ break;
+ case 2:
+ data = pkt->get<uint16_t>();
+ break;
+ case 4:
+ data = pkt->get<uint32_t>();
+ break;
+ default:
+ panic("PL111 CLCD controller write size too big?\n");
+ break;
+ }
+
+ if ((pkt->getAddr()& 0xffff0000) == pioAddr) {
+
+ assert(pkt->getAddr() >= pioAddr &&
+ pkt->getAddr() < pioAddr + pioSize);
+
+ Addr daddr = pkt->getAddr() - pioAddr;
+
+ DPRINTF(PL111, " write register %#x value %#x size=%d\n", daddr,
+ pkt->get<uint8_t>(), pkt->getSize());
+
+ switch (daddr) {
+ case LcdTiming0:
+ lcdTiming0 = data;
+ // width = 16 * (PPL+1)
+ width = (lcdTiming0.ppl + 1) << 4;
+ break;
+ case LcdTiming1:
+ lcdTiming1 = data;
+ // height = LPP + 1
+ height = (lcdTiming1.lpp) + 1;
+ break;
+ case LcdTiming2:
+ lcdTiming2 = data;
+ break;
+ case LcdTiming3:
+ lcdTiming3 = data;
+ break;
+ case LcdUpBase:
+ lcdUpbase = data;
+ break;
+ case LcdLpBase:
+ warn("LCD dual screen mode not supported\n");
+ lcdLpbase = data;
+ break;
+ case LcdControl:
+ int old_lcdpwr;
+ old_lcdpwr = lcdControl.lcdpwr;
+ lcdControl = data;
+ // LCD power enable
+ if (lcdControl.lcdpwr&&!old_lcdpwr) {
+ DPRINTF(PL111, " lcd size: height %d width %d\n", height, width);
+ waterMark = lcdControl.watermark ? 8 : 4;
+ readFramebuffer();
+ }
+ break;
+ case LcdImsc:
+ warn("LCD interrupt mask set/clear not supported\n");
+ lcdImsc = data;
+ break;
+ case LcdRis:
+ warn("LCD register at offset %#x is Read-Only\n", daddr);
+ break;
+ case LcdMis:
+ warn("LCD register at offset %#x is Read-Only\n", daddr);
+ break;
+ case LcdIcr:
+ warn("LCD interrupt clear not supported\n");
+ lcdIcr = data;
+ break;
+ case LcdUpCurr:
+ warn("LCD register at offset %#x is Read-Only\n", daddr);
+ break;
+ case LcdLpCurr:
+ warn("LCD register at offset %#x is Read-Only\n", daddr);
+ break;
+ case ClcdCrsrCtrl:
+ clcdCrsrCtrl = data;
+ break;
+ case ClcdCrsrConfig:
+ clcdCrsrConfig = data;
+ break;
+ case ClcdCrsrPalette0:
+ clcdCrsrPalette0 = data;
+ break;
+ case ClcdCrsrPalette1:
+ clcdCrsrPalette1 = data;
+ break;
+ case ClcdCrsrXY:
+ clcdCrsrXY = data;
+ break;
+ case ClcdCrsrClip:
+ clcdCrsrClip = data;
+ break;
+ case ClcdCrsrImsc:
+ clcdCrsrImsc = data;
+ break;
+ case ClcdCrsrIcr:
+ clcdCrsrIcr = data;
+ break;
+ case ClcdCrsrRis:
+ warn("CLCD register at offset %#x is Read-Only\n", daddr);
+ break;
+ case ClcdCrsrMis:
+ warn("CLCD register at offset %#x is Read-Only\n", daddr);
+ break;
+ default:
+ if (daddr >= CrsrImage && daddr <= 0xBFC) {
+ // CURSOR IMAGE
+ int index;
+ index = (daddr - CrsrImage) >> 2;
+ cursorImage[index] = data;
+ break;
+ } else if (daddr >= LcdPalette && daddr <= 0x3FC) {
+ // LCD Palette
+ int index;
+ index = (daddr - LcdPalette) >> 2;
+ lcdPalette[index] = data;
+ break;
+ } else {
+ panic("Tried to write PL111 register at offset %#x that \
+ doesn't exist\n", daddr);
+ break;
+ }
+ }
+ }
+
+ pkt->makeAtomicResponse();
+ return pioDelay;
+}
+
+void
+Pl111::readFramebuffer()
+{
+ // initialization for dma read from frame buffer to dma buffer
+ uint32_t length = height*width;
+ if (startAddr != lcdUpbase) {
+ startAddr = lcdUpbase;
+ }
+ curAddr = 0;
+ startTime = curTick;
+ maxAddr = static_cast<Addr>(length*sizeof(uint32_t));
+ dmaPendingNum =0 ;
+
+ fillFifo();
+}
+
+void
+Pl111::fillFifo()
+{
+ while ((dmaPendingNum < maxOutstandingDma) && (maxAddr >= curAddr + dmaSize )) {
+ // concurrent dma reads need different dma done events
+ // due to assertion in scheduling state
+ ++dmaPendingNum;
+ DPRINTF(PL111, " ++ DMA pending number %d read addr %#x\n",
+ dmaPendingNum, curAddr);
+ assert(!dmaDoneEvent[dmaPendingNum-1].scheduled());
+ dmaRead(curAddr + startAddr, dmaSize, &dmaDoneEvent[dmaPendingNum-1],
+ curAddr + dmaBuffer);
+ curAddr += dmaSize;
+ }
+}
+
+void
+Pl111::dmaDone()
+{
+ Tick maxFrameTime = lcdTiming2.cpl*height*clock;
+
+ --dmaPendingNum;
+
+ DPRINTF(PL111, " -- DMA pending number %d\n", dmaPendingNum);
+
+ if (maxAddr == curAddr && !dmaPendingNum) {
+ if ((curTick - startTime) > maxFrameTime)
+ warn("CLCD controller buffer underrun, took %d cycles when should"
+ " have taken %d\n", curTick - startTime, maxFrameTime);
+
+ // double buffering so the vnc server doesn't see a tear in the screen
+ memcpy(frameBuffer, dmaBuffer, maxAddr);
+ assert(!readEvent.scheduled());
+
+ DPRINTF(PL111, "-- write out frame buffer into bmp\n");
+ writeBMP(frameBuffer);
+
+ DPRINTF(PL111, "-- schedule next dma read event at %d tick \n",
+ maxFrameTime + curTick);
+ schedule(readEvent, nextCycle(startTime + maxFrameTime));
+ }
+
+ if (dmaPendingNum > (maxOutstandingDma - waterMark))
+ return;
+
+ if (!fillFifoEvent.scheduled())
+ schedule(fillFifoEvent, nextCycle());
+
+}
+
+Tick
+Pl111::nextCycle()
+{
+ Tick nextTick = curTick + clock - 1;
+ nextTick -= nextTick%clock;
+ return nextTick;
+}
+
+Tick
+Pl111::nextCycle(Tick beginTick)
+{
+ Tick nextTick = beginTick;
+ if (nextTick%clock!=0)
+ nextTick = nextTick - (nextTick%clock) + clock;
+
+ assert(nextTick >= curTick);
+ return nextTick;
+}
+
+// write out the frame buffer into a bitmap file
+void
+Pl111::writeBMP(uint32_t* frameBuffer)
+{
+ fstream pic;
+
+ // write out bmp head
+ std::string filename = "./m5out/frameBuffer.bmp";
+ pic.open(filename.c_str(), ios::out|ios::binary);
+ Bitmap bm(pic, height, width);
+
+ DPRINTF(PL111, "-- write out data into bmp\n");
+
+ // write out frame buffer data
+ for (int i = height -1; i >= 0; --i) {
+ for (int j = 0; j< width; ++j) {
+ uint32_t pixel = frameBuffer[i*width + j];
+ pic.write(reinterpret_cast<char*>(&pixel),
+ sizeof(uint32_t));
+ DPRINTF(PL111, " write pixel data %#x at addr %#x\n",
+ pixel, i*width + j);
+ }
+ }
+
+ pic.close();
+}
+
+void
+Pl111::serialize(std::ostream &os)
+{
+ DPRINTF(PL111, "Serializing ARM PL111\n");
+
+ uint32_t lcdTiming0_serial = lcdTiming0;
+ SERIALIZE_SCALAR(lcdTiming0_serial);
+
+ uint32_t lcdTiming1_serial = lcdTiming1;
+ SERIALIZE_SCALAR(lcdTiming1_serial);
+
+ uint32_t lcdTiming2_serial = lcdTiming2;
+ SERIALIZE_SCALAR(lcdTiming2_serial);
+
+ uint32_t lcdTiming3_serial = lcdTiming3;
+ SERIALIZE_SCALAR(lcdTiming3_serial);
+
+ SERIALIZE_SCALAR(lcdUpbase);
+ SERIALIZE_SCALAR(lcdLpbase);
+
+ uint32_t lcdControl_serial = lcdControl;
+ SERIALIZE_SCALAR(lcdControl_serial);
+
+ uint8_t lcdImsc_serial = lcdImsc;
+ SERIALIZE_SCALAR(lcdImsc_serial);
+
+ uint8_t lcdRis_serial = lcdRis;
+ SERIALIZE_SCALAR(lcdRis_serial);
+
+ uint8_t lcdMis_serial = lcdMis;
+ SERIALIZE_SCALAR(lcdMis_serial);
+
+ uint8_t lcdIcr_serial = lcdIcr;
+ SERIALIZE_SCALAR(lcdIcr_serial);
+
+ SERIALIZE_ARRAY(lcdPalette, LcdPaletteSize);
+ SERIALIZE_ARRAY(cursorImage, CrsrImageSize);
+
+ SERIALIZE_SCALAR(clcdCrsrCtrl);
+ SERIALIZE_SCALAR(clcdCrsrConfig);
+ SERIALIZE_SCALAR(clcdCrsrPalette0);
+ SERIALIZE_SCALAR(clcdCrsrPalette1);
+ SERIALIZE_SCALAR(clcdCrsrXY);
+ SERIALIZE_SCALAR(clcdCrsrClip);
+
+ uint8_t clcdCrsrImsc_serial = clcdCrsrImsc;
+ SERIALIZE_SCALAR(clcdCrsrImsc_serial);
+
+ uint8_t clcdCrsrIcr_serial = clcdCrsrIcr;
+ SERIALIZE_SCALAR(clcdCrsrIcr_serial);
+
+ uint8_t clcdCrsrRis_serial = clcdCrsrRis;
+ SERIALIZE_SCALAR(clcdCrsrRis_serial);
+
+ uint8_t clcdCrsrMis_serial = clcdCrsrMis;
+ SERIALIZE_SCALAR(clcdCrsrMis_serial);
+
+ SERIALIZE_SCALAR(clock);
+ SERIALIZE_SCALAR(height);
+ SERIALIZE_SCALAR(width);
+
+ SERIALIZE_ARRAY(dmaBuffer, height*width);
+ SERIALIZE_ARRAY(frameBuffer, height*width);
+ SERIALIZE_SCALAR(startTime);
+ SERIALIZE_SCALAR(startAddr);
+ SERIALIZE_SCALAR(maxAddr);
+ SERIALIZE_SCALAR(curAddr);
+ SERIALIZE_SCALAR(waterMark);
+ SERIALIZE_SCALAR(dmaPendingNum);
+}
+
+void
+Pl111::unserialize(Checkpoint *cp, const std::string &section)
+{
+ DPRINTF(PL111, "Unserializing ARM PL111\n");
+
+ uint32_t lcdTiming0_serial;
+ UNSERIALIZE_SCALAR(lcdTiming0_serial);
+ lcdTiming0 = lcdTiming0_serial;
+
+ uint32_t lcdTiming1_serial;
+ UNSERIALIZE_SCALAR(lcdTiming1_serial);
+ lcdTiming1 = lcdTiming1_serial;
+
+ uint32_t lcdTiming2_serial;
+ UNSERIALIZE_SCALAR(lcdTiming2_serial);
+ lcdTiming2 = lcdTiming2_serial;
+
+ uint32_t lcdTiming3_serial;
+ UNSERIALIZE_SCALAR(lcdTiming3_serial);
+ lcdTiming3 = lcdTiming3_serial;
+
+ UNSERIALIZE_SCALAR(lcdUpbase);
+ UNSERIALIZE_SCALAR(lcdLpbase);
+
+ uint32_t lcdControl_serial;
+ UNSERIALIZE_SCALAR(lcdControl_serial);
+ lcdControl = lcdControl_serial;
+
+ uint8_t lcdImsc_serial;
+ UNSERIALIZE_SCALAR(lcdImsc_serial);
+ lcdImsc = lcdImsc_serial;
+
+ uint8_t lcdRis_serial;
+ UNSERIALIZE_SCALAR(lcdRis_serial);
+ lcdRis = lcdRis_serial;
+
+ uint8_t lcdMis_serial;
+ UNSERIALIZE_SCALAR(lcdMis_serial);
+ lcdMis = lcdMis_serial;
+
+ uint8_t lcdIcr_serial;
+ UNSERIALIZE_SCALAR(lcdIcr_serial);
+ lcdIcr = lcdIcr_serial;
+
+ UNSERIALIZE_ARRAY(lcdPalette, LcdPaletteSize);
+ UNSERIALIZE_ARRAY(cursorImage, CrsrImageSize);
+
+ UNSERIALIZE_SCALAR(clcdCrsrCtrl);
+ UNSERIALIZE_SCALAR(clcdCrsrConfig);
+ UNSERIALIZE_SCALAR(clcdCrsrPalette0);
+ UNSERIALIZE_SCALAR(clcdCrsrPalette1);
+ UNSERIALIZE_SCALAR(clcdCrsrXY);
+ UNSERIALIZE_SCALAR(clcdCrsrClip);
+
+ uint8_t clcdCrsrImsc_serial;
+ UNSERIALIZE_SCALAR(clcdCrsrImsc_serial);
+ clcdCrsrImsc = clcdCrsrImsc_serial;
+
+ uint8_t clcdCrsrIcr_serial;
+ UNSERIALIZE_SCALAR(clcdCrsrIcr_serial);
+ clcdCrsrIcr = clcdCrsrIcr_serial;
+
+ uint8_t clcdCrsrRis_serial;
+ UNSERIALIZE_SCALAR(clcdCrsrRis_serial);
+ clcdCrsrRis = clcdCrsrRis_serial;
+
+ uint8_t clcdCrsrMis_serial;
+ UNSERIALIZE_SCALAR(clcdCrsrMis_serial);
+ clcdCrsrMis = clcdCrsrMis_serial;
+
+ UNSERIALIZE_SCALAR(clock);
+ UNSERIALIZE_SCALAR(height);
+ UNSERIALIZE_SCALAR(width);
+
+ UNSERIALIZE_ARRAY(dmaBuffer, height*width);
+ UNSERIALIZE_ARRAY(frameBuffer, height*width);
+ UNSERIALIZE_SCALAR(startTime);
+ UNSERIALIZE_SCALAR(startAddr);
+ UNSERIALIZE_SCALAR(maxAddr);
+ UNSERIALIZE_SCALAR(curAddr);
+ UNSERIALIZE_SCALAR(waterMark);
+ UNSERIALIZE_SCALAR(dmaPendingNum);
+}
+
+void
+Pl111::generateInterrupt()
+{
+ DPRINTF(PL111, "Generate Interrupt: lcdImsc=0x%x lcdRis=0x%x lcdMis=0x%x\n",
+ lcdImsc, lcdRis, lcdMis);
+ lcdMis = lcdImsc & lcdRis;
+
+ if (lcdMis.ffufie || lcdMis.nbupie || lcdMis.vtcpie || lcdMis.ahmeie) {
+ gic->sendInt(intNum);
+ DPRINTF(PL111, " -- Generated\n");
+ }
+}
+
+void
+Pl111::addressRanges(AddrRangeList& range_list)
+{
+ range_list.clear();
+ range_list.push_back(RangeSize(pioAddr, pioSize));
+}
+
+Pl111 *
+Pl111Params::create()
+{
+ return new Pl111(this);
+}
+
+// bitmap class ctor
+Bitmap::Bitmap(std::fstream& bmp, uint16_t h, uint16_t w)
+{
+ Magic magic = {{'B','M'}};
+ Header header = {sizeof(Color)*w*h , 0, 0, 54};
+ Info info = {sizeof(Info), w, h, 1, sizeof(Color)*8, 0,
+ ( sizeof(Color) *(w*h) ), 1, 1, 0, 0};
+
+ bmp.write(reinterpret_cast<char*>(&magic), sizeof(magic));
+ bmp.write(reinterpret_cast<char*>(&header), sizeof(header));
+ bmp.write(reinterpret_cast<char*>(&info), sizeof(info));
+}
diff --git a/src/dev/arm/pl111.hh b/src/dev/arm/pl111.hh
new file mode 100644
index 000000000..4e75af4e8
--- /dev/null
+++ b/src/dev/arm/pl111.hh
@@ -0,0 +1,368 @@
+/*
+ * Copyright (c) 2010 ARM Limited
+ * All rights reserved
+ *
+ * The license below extends only to copyright in the software and shall
+ * not be construed as granting a license to any other intellectual
+ * property including but not limited to intellectual property relating
+ * to a hardware implementation of the functionality of the software
+ * licensed hereunder. You may use the software subject to the license
+ * terms below provided that you ensure that this notice is replicated
+ * unmodified and in its entirety in all distributions of the software,
+ * modified or unmodified, in source code or in binary form.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: William Wang
+ */
+
+
+/** @file
+ * Implementiation of a PL111 CLCD controller
+ */
+
+#ifndef __DEV_ARM_PL111_HH__
+#define __DEV_ARM_PL111_HH__
+
+#include <fstream>
+
+#include "base/range.hh"
+#include "dev/arm/amba_device.hh"
+#include "params/Pl111.hh"
+#include "sim/serialize.hh"
+
+using namespace std;
+
+class Gic;
+
+class Pl111: public AmbaDmaDevice
+{
+ protected:
+ static const uint64_t AMBA_ID = ULL(0xb105f00d00141111);
+ /** ARM PL111 register map*/
+ static const int LcdTiming0 = 0x000;
+ static const int LcdTiming1 = 0x004;
+ static const int LcdTiming2 = 0x008;
+ static const int LcdTiming3 = 0x00C;
+ static const int LcdUpBase = 0x010;
+ static const int LcdLpBase = 0x014;
+ static const int LcdControl = 0x018;
+ static const int LcdImsc = 0x01C;
+ static const int LcdRis = 0x020;
+ static const int LcdMis = 0x024;
+ static const int LcdIcr = 0x028;
+ static const int LcdUpCurr = 0x02C;
+ static const int LcdLpCurr = 0x030;
+ static const int LcdPalette = 0x200;
+ static const int CrsrImage = 0x800;
+ static const int ClcdCrsrCtrl = 0xC00;
+ static const int ClcdCrsrConfig = 0xC04;
+ static const int ClcdCrsrPalette0 = 0xC08;
+ static const int ClcdCrsrPalette1 = 0xC0C;
+ static const int ClcdCrsrXY = 0xC10;
+ static const int ClcdCrsrClip = 0xC14;
+ static const int ClcdCrsrImsc = 0xC20;
+ static const int ClcdCrsrIcr = 0xC24;
+ static const int ClcdCrsrRis = 0xC28;
+ static const int ClcdCrsrMis = 0xC2C;
+
+ static const int LcdPaletteSize = 128;
+ static const int CrsrImageSize = 256;
+
+ static const int LcdMaxWidth = 1024; // pixels per line
+ static const int LcdMaxHeight = 768; // lines per panel
+
+ static const int dmaSize = 8; // 64 bits
+ static const int maxOutstandingDma = 16; // 16 deep FIFO of 64 bits
+
+ BitUnion8(InterruptReg)
+ Bitfield<1> ffufie;
+ Bitfield<2> nbupie;
+ Bitfield<3> vtcpie;
+ Bitfield<4> ahmeie;
+ EndBitUnion(InterruptReg)
+
+ BitUnion32(TimingReg0)
+ Bitfield<7,2> ppl;
+ Bitfield<15,8> hsw;
+ Bitfield<23,16> hfp;
+ Bitfield<31,24> hbp;
+ EndBitUnion(TimingReg0)
+
+ BitUnion32(TimingReg1)
+ Bitfield<9,0> lpp;
+ Bitfield<15,10> vsw;
+ Bitfield<23,16> vfp;
+ Bitfield<31,24> vbp;
+ EndBitUnion(TimingReg1)
+
+ BitUnion32(TimingReg2)
+ Bitfield<4,0> pcdlo;
+ Bitfield<5> clksel;
+ Bitfield<10,6> acb;
+ Bitfield<11> avs;
+ Bitfield<12> ihs;
+ Bitfield<13> ipc;
+ Bitfield<14> ioe;
+ Bitfield<25,16> cpl;
+ Bitfield<26> bcd;
+ Bitfield<31,27> pcdhi;
+ EndBitUnion(TimingReg2)
+
+ BitUnion32(TimingReg3)
+ Bitfield<6,0> led;
+ Bitfield<16> lee;
+ EndBitUnion(TimingReg3)
+
+ BitUnion32(ControlReg)
+ Bitfield<0> lcden;
+ Bitfield<3,1> lcdbpp;
+ Bitfield<4> lcdbw;
+ Bitfield<5> lcdtft;
+ Bitfield<6> lcdmono8;
+ Bitfield<7> lcddual;
+ Bitfield<8> bgr;
+ Bitfield<9> bebo;
+ Bitfield<10> bepo;
+ Bitfield<11> lcdpwr;
+ Bitfield<13,12> lcdvcomp;
+ Bitfield<16> watermark;
+ EndBitUnion(ControlReg)
+
+ /** Horizontal axis panel control register */
+ TimingReg0 lcdTiming0;
+
+ /** Vertical axis panel control register */
+ TimingReg1 lcdTiming1;
+
+ /** Clock and signal polarity control register */
+ TimingReg2 lcdTiming2;
+
+ /** Line end control register */
+ TimingReg3 lcdTiming3;
+
+ /** Upper panel frame base address register */
+ int lcdUpbase;
+
+ /** Lower panel frame base address register */
+ int lcdLpbase;
+
+ /** Control register */
+ ControlReg lcdControl;
+
+ /** Interrupt mask set/clear register */
+ InterruptReg lcdImsc;
+
+ /** Raw interrupt status register - const */
+ InterruptReg lcdRis;
+
+ /** Masked interrupt status register */
+ InterruptReg lcdMis;
+
+ /** Interrupt clear register */
+ InterruptReg lcdIcr;
+
+ /** Upper panel current address value register - ro */
+ int lcdUpcurr;
+
+ /** Lower panel current address value register - ro */
+ int lcdLpcurr;
+
+ /** 256x16-bit color palette registers
+ * 256 palette entries organized as 128 locations of two entries per word */
+ int lcdPalette[LcdPaletteSize];
+
+ /** Cursor image RAM register
+ * 256-word wide values defining images overlaid by the hw cursor mechanism */
+ int cursorImage[CrsrImageSize];
+
+ /** Cursor control register */
+ int clcdCrsrCtrl;
+
+ /** Cursor configuration register */
+ int clcdCrsrConfig;
+
+ /** Cursor palette registers */
+ int clcdCrsrPalette0;
+ int clcdCrsrPalette1;
+
+ /** Cursor XY position register */
+ int clcdCrsrXY;
+
+ /** Cursor clip position register */
+ int clcdCrsrClip;
+
+ /** Cursor interrupt mask set/clear register */
+ InterruptReg clcdCrsrImsc;
+
+ /** Cursor interrupt clear register */
+ InterruptReg clcdCrsrIcr;
+
+ /** Cursor raw interrupt status register - const */
+ InterruptReg clcdCrsrRis;
+
+ /** Cursor masked interrupt status register - const */
+ InterruptReg clcdCrsrMis;
+
+ /** Clock speed */
+ Tick clock;
+
+ /** Frame buffer height - lines per panel */
+ uint16_t height;
+
+ /** Frame buffer width - pixels per line */
+ uint16_t width;
+
+ /** CLCDC supports up to 1024x768 */
+ uint8_t dmaBuffer[LcdMaxWidth * LcdMaxHeight * sizeof(uint32_t)];
+
+ /** Double buffering */
+ uint32_t frameBuffer[LcdMaxWidth * LcdMaxHeight];
+
+ /** Start time for frame buffer dma read */
+ Tick startTime;
+
+ /** Frame buffer base address */
+ Addr startAddr;
+
+ /** Frame buffer max address */
+ Addr maxAddr;
+
+ /** Frame buffer current address */
+ Addr curAddr;
+
+ /** DMA FIFO watermark */
+ int waterMark;
+
+ /** Number of pending dma reads */
+ int dmaPendingNum;
+
+ /** DMA framebuffer read */
+ void readFramebuffer();
+
+ /** Write framebuffer to a bmp file */
+ void writeBMP(uint32_t*);
+
+ /** Generate dma framebuffer read event */
+ void generateReadEvent();
+
+ /** Function to generate interrupt */
+ void generateInterrupt();
+
+ /** fillFIFO event */
+ void fillFifo();
+
+ /** DMA done event */
+ void dmaDone();
+
+ /** Next cycle event */
+ Tick nextCycle();
+ Tick nextCycle(Tick beginTick);
+
+ /** DMA framebuffer read event */
+ EventWrapper<Pl111, &Pl111::readFramebuffer> readEvent;
+
+ /** Fill fifo */
+ EventWrapper<Pl111, &Pl111::fillFifo> fillFifoEvent;
+
+ /** DMA done event */
+ vector<EventWrapper<Pl111, &Pl111::dmaDone> > dmaDoneEvent;
+
+ /** Wrapper to create an event out of the thing */
+ EventWrapper<Pl111, &Pl111::generateInterrupt> intEvent;
+
+ public:
+ typedef Pl111Params Params;
+
+ const Params *
+ params() const
+ {
+ return dynamic_cast<const Params *>(_params);
+ }
+ Pl111(const Params *p);
+
+ virtual Tick read(PacketPtr pkt);
+ virtual Tick write(PacketPtr pkt);
+
+ virtual void serialize(std::ostream &os);
+ virtual void unserialize(Checkpoint *cp, const std::string &section);
+
+ /** return the address ranges that this device responds to.
+ * @param range_list range list to populate with ranges
+ */
+ void addressRanges(AddrRangeList &range_list);
+
+ /**
+ * Return if we have an interrupt pending
+ * @return interrupt status
+ * @todo fix me when implementation improves
+ */
+ virtual bool intStatus() { return false; }
+};
+
+// write frame buffer into a bitmap picture
+class Bitmap
+{
+ public:
+ Bitmap(std::fstream& bmp, uint16_t h, uint16_t w);
+
+ private:
+ struct Magic
+ {
+ unsigned char magic_number[2];
+ } magic;
+
+ struct Header
+ {
+ uint32_t size;
+ uint16_t reserved1;
+ uint16_t reserved2;
+ uint32_t offset;
+ } header;
+
+ struct Info
+ {
+ uint32_t Size;
+ uint32_t Width;
+ uint32_t Height;
+ uint16_t Planes;
+ uint16_t BitCount;
+ uint32_t Compression;
+ uint32_t SizeImage;
+ uint32_t XPelsPerMeter;
+ uint32_t YPelsPerMeter;
+ uint32_t ClrUsed;
+ uint32_t ClrImportant;
+ } info;
+
+ struct Color
+ {
+ unsigned char b;
+ unsigned char g;
+ unsigned char r;
+ unsigned char a;
+ } color;
+};
+
+#endif