From fc1eeafc94b3bab13ffbfd85e0c255f3459355fa Mon Sep 17 00:00:00 2001 From: William Wang Date: Mon, 15 Nov 2010 14:04:03 -0600 Subject: ARM: Implement a CLCD Frame buffer --- src/dev/arm/RealView.py | 21 +- src/dev/arm/SConscript | 2 + src/dev/arm/amba_device.cc | 9 +- src/dev/arm/amba_device.hh | 14 +- src/dev/arm/pl111.cc | 653 +++++++++++++++++++++++++++++++++++++++++++++ src/dev/arm/pl111.hh | 368 +++++++++++++++++++++++++ 6 files changed, 1056 insertions(+), 11 deletions(-) create mode 100644 src/dev/arm/pl111.cc create mode 100644 src/dev/arm/pl111.hh 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(); + 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(data); + break; + case 2: + pkt->set(data); + break; + case 4: + pkt->set(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(); + break; + case 2: + data = pkt->get(); + break; + case 4: + data = pkt->get(); + 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(), 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(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(&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 §ion) +{ + 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(&magic), sizeof(magic)); + bmp.write(reinterpret_cast(&header), sizeof(header)); + bmp.write(reinterpret_cast(&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 + +#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 readEvent; + + /** Fill fifo */ + EventWrapper fillFifoEvent; + + /** DMA done event */ + vector > dmaDoneEvent; + + /** Wrapper to create an event out of the thing */ + EventWrapper intEvent; + + public: + typedef Pl111Params Params; + + const Params * + params() const + { + return dynamic_cast(_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 §ion); + + /** 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 -- cgit v1.2.3