hdlcd.cc (10905:a6ca6831e775) | hdlcd.cc (11090:f37a6b82f98f) |
---|---|
1/* 2 * Copyright (c) 2010-2013, 2015 ARM Limited 3 * All rights reserved 4 * 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 --- 21 unchanged lines hidden (view full) --- 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. 36 * 37 * Authors: Chris Emmons | 1/* 2 * Copyright (c) 2010-2013, 2015 ARM Limited 3 * All rights reserved 4 * 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 --- 21 unchanged lines hidden (view full) --- 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. 36 * 37 * Authors: Chris Emmons |
38 * Andreas Sandberg |
|
38 */ 39 40#include "dev/arm/hdlcd.hh" 41 42#include "base/vnc/vncinput.hh" 43#include "base/output.hh" 44#include "base/trace.hh" | 39 */ 40 41#include "dev/arm/hdlcd.hh" 42 43#include "base/vnc/vncinput.hh" 44#include "base/output.hh" 45#include "base/trace.hh" |
46#include "debug/Checkpoint.hh" |
|
45#include "debug/HDLcd.hh" | 47#include "debug/HDLcd.hh" |
46#include "debug/Uart.hh" | |
47#include "dev/arm/amba_device.hh" 48#include "dev/arm/base_gic.hh" 49#include "mem/packet.hh" 50#include "mem/packet_access.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 "params/HDLcd.hh" |
|
51#include "sim/system.hh" 52 53using std::vector; 54 55 56// initialize hdlcd registers | 53#include "sim/system.hh" 54 55using std::vector; 56 57 58// initialize hdlcd registers |
57HDLcd::HDLcd(const Params *p) 58 : AmbaDmaDevice(p), version(VERSION_RESETV), 59 int_rawstat(0), int_clear(0), int_mask(0), int_status(0), | 59HDLcd::HDLcd(const HDLcdParams *p) 60 : AmbaDmaDevice(p, 0xFFFF), 61 // Parameters 62 vnc(p->vnc), 63 workaroundSwapRB(p->workaround_swap_rb), 64 workaroundDmaLineCount(p->workaround_dma_line_count), 65 addrRanges{RangeSize(pioAddr, pioSize)}, 66 enableCapture(p->enable_capture), 67 pixelBufferSize(p->pixel_buffer_size), 68 69 // Registers 70 version(VERSION_RESETV), 71 int_rawstat(0), int_mask(0), 72 |
60 fb_base(0), fb_line_length(0), fb_line_count(0), fb_line_pitch(0), 61 bus_options(BUS_OPTIONS_RESETV), | 73 fb_base(0), fb_line_length(0), fb_line_count(0), fb_line_pitch(0), 74 bus_options(BUS_OPTIONS_RESETV), |
75 |
|
62 v_sync(0), v_back_porch(0), v_data(0), v_front_porch(0), 63 h_sync(0), h_back_porch(0), h_data(0), h_front_porch(0), | 76 v_sync(0), v_back_porch(0), v_data(0), v_front_porch(0), 77 h_sync(0), h_back_porch(0), h_data(0), h_front_porch(0), |
64 polarities(0), command(0), pixel_format(0), 65 red_select(0), green_select(0), blue_select(0), 66 pixelClock(p->pixel_clock), 67 fb(0, 0), vnc(p->vnc), bmp(&fb), pic(NULL), 68 frameReadStartTime(0), 69 dmaStartAddr(0), dmaCurAddr(0), dmaMaxAddr(0), dmaPendingNum(0), 70 frameUnderrun(false), pixelBufferSize(0), 71 pixelIndex(0), doUpdateParams(false), frameUnderway(false), 72 dmaBytesInFlight(0), 73 startFrameEvent(this), endFrameEvent(this), renderPixelEvent(this), 74 fillPixelBufferEvent(this), intEvent(this), 75 dmaDoneEventAll(MAX_OUTSTANDING_DMA_REQ_CAPACITY, this), 76 dmaDoneEventFree(MAX_OUTSTANDING_DMA_REQ_CAPACITY), 77 enableCapture(p->enable_capture), 78 workaround_swap_rb(p->workaround_swap_rb) 79{ 80 pioSize = 0xFFFF; | 78 polarities(0), |
81 | 79 |
82 for (int i = 0; i < MAX_OUTSTANDING_DMA_REQ_CAPACITY; ++i) 83 dmaDoneEventFree[i] = &dmaDoneEventAll[i]; | 80 command(0), |
84 | 81 |
82 pixel_format(0), 83 red_select(0), green_select(0), blue_select(0), 84 85 // Other 86 bmp(&pixelPump.fb), pic(NULL), conv(PixelConverter::rgba8888_le), 87 pixelPump(*this, *p->pxl_clk, p->pixel_chunk) 88{ |
|
85 if (vnc) | 89 if (vnc) |
86 vnc->setFrameBuffer(&fb); | 90 vnc->setFrameBuffer(&pixelPump.fb); |
87} 88 89HDLcd::~HDLcd() 90{ 91} 92 | 91} 92 93HDLcd::~HDLcd() 94{ 95} 96 |
97void 98HDLcd::serialize(CheckpointOut &cp) const 99{ 100 DPRINTF(Checkpoint, "Serializing ARM HDLCD\n"); 101 102 SERIALIZE_SCALAR(int_rawstat); 103 SERIALIZE_SCALAR(int_mask); 104 105 SERIALIZE_SCALAR(fb_base); 106 SERIALIZE_SCALAR(fb_line_length); 107 SERIALIZE_SCALAR(fb_line_count); 108 SERIALIZE_SCALAR(fb_line_pitch); 109 SERIALIZE_SCALAR(bus_options); 110 111 SERIALIZE_SCALAR(v_sync); 112 SERIALIZE_SCALAR(v_back_porch); 113 SERIALIZE_SCALAR(v_data); 114 SERIALIZE_SCALAR(v_front_porch); 115 116 SERIALIZE_SCALAR(h_sync); 117 SERIALIZE_SCALAR(h_back_porch); 118 SERIALIZE_SCALAR(h_data); 119 SERIALIZE_SCALAR(h_front_porch); 120 121 SERIALIZE_SCALAR(polarities); 122 123 SERIALIZE_SCALAR(command); 124 SERIALIZE_SCALAR(pixel_format); 125 SERIALIZE_SCALAR(red_select); 126 SERIALIZE_SCALAR(green_select); 127 SERIALIZE_SCALAR(blue_select); 128 129 SERIALIZE_OBJ(pixelPump); 130 if (enabled()) 131 dmaEngine->serializeSection(cp, "dmaEngine"); 132} 133 134void 135HDLcd::unserialize(CheckpointIn &cp) 136{ 137 DPRINTF(Checkpoint, "Unserializing ARM HDLCD\n"); 138 139 UNSERIALIZE_SCALAR(int_rawstat); 140 UNSERIALIZE_SCALAR(int_mask); 141 142 UNSERIALIZE_SCALAR(fb_base); 143 UNSERIALIZE_SCALAR(fb_line_length); 144 UNSERIALIZE_SCALAR(fb_line_count); 145 UNSERIALIZE_SCALAR(fb_line_pitch); 146 UNSERIALIZE_SCALAR(bus_options); 147 148 UNSERIALIZE_SCALAR(v_sync); 149 UNSERIALIZE_SCALAR(v_back_porch); 150 UNSERIALIZE_SCALAR(v_data); 151 UNSERIALIZE_SCALAR(v_front_porch); 152 153 UNSERIALIZE_SCALAR(h_sync); 154 UNSERIALIZE_SCALAR(h_back_porch); 155 UNSERIALIZE_SCALAR(h_data); 156 UNSERIALIZE_SCALAR(h_front_porch); 157 158 UNSERIALIZE_SCALAR(polarities); 159 160 UNSERIALIZE_SCALAR(command); 161 UNSERIALIZE_SCALAR(pixel_format); 162 UNSERIALIZE_SCALAR(red_select); 163 UNSERIALIZE_SCALAR(green_select); 164 UNSERIALIZE_SCALAR(blue_select); 165 166 { 167 // Try to unserialize the pixel pump. It might not exist if 168 // we're unserializing an old checkpoint. 169 ScopedCheckpointSection sec(cp, "pixelPump"); 170 if (cp.sectionExists(Serializable::currentSection())) 171 pixelPump.unserialize(cp); 172 } 173 174 if (enabled()) { 175 // Create the DMA engine and read its state from the 176 // checkpoint. We don't need to worry about the pixel pump as 177 // it is a proper SimObject. 178 createDmaEngine(); 179 dmaEngine->unserializeSection(cp, "dmaEngine"); 180 181 conv = pixelConverter(); 182 } 183} 184 185void 186HDLcd::drainResume() 187{ 188 AmbaDmaDevice::drainResume(); 189 190 // We restored from an old checkpoint without a pixel pump, start 191 // an new refresh. This typically happens when restoring from old 192 // checkpoints. 193 if (enabled() && !pixelPump.active()) 194 pixelPump.start(displayTimings()); 195 196 // We restored from a checkpoint and need to update the VNC server 197 if (pixelPump.active() && vnc) 198 vnc->setDirty(); 199} 200 |
|
93// read registers and frame buffer 94Tick 95HDLcd::read(PacketPtr pkt) 96{ | 201// read registers and frame buffer 202Tick 203HDLcd::read(PacketPtr pkt) 204{ |
97 uint32_t data = 0; 98 const Addr daddr = pkt->getAddr() - pioAddr; 99 100 DPRINTF(HDLcd, "read register BASE+0x%04x size=%d\n", daddr, 101 pkt->getSize()); 102 | |
103 assert(pkt->getAddr() >= pioAddr && | 205 assert(pkt->getAddr() >= pioAddr && |
104 pkt->getAddr() < pioAddr + pioSize && 105 pkt->getSize() == 4); | 206 pkt->getAddr() < pioAddr + pioSize); |
106 | 207 |
107 switch (daddr) { 108 case Version: 109 data = version; 110 break; 111 case Int_RawStat: 112 data = int_rawstat; 113 break; 114 case Int_Clear: 115 panic("HDLCD INT_CLEAR register is Write-Only\n"); 116 break; 117 case Int_Mask: 118 data = int_mask; 119 break; 120 case Int_Status: 121 data = int_status; 122 break; 123 case Fb_Base: 124 data = fb_base; 125 break; 126 case Fb_Line_Length: 127 data = fb_line_length; 128 break; 129 case Fb_Line_Count: 130 data = fb_line_count; 131 break; 132 case Fb_Line_Pitch: 133 data = fb_line_pitch; 134 break; 135 case Bus_Options: 136 data = bus_options; 137 break; 138 case V_Sync: 139 data = v_sync; 140 break; 141 case V_Back_Porch: 142 data = v_back_porch; 143 break; 144 case V_Data: 145 data = v_data; 146 break; 147 case V_Front_Porch: 148 data = v_front_porch; 149 break; 150 case H_Sync: 151 data = h_sync; 152 break; 153 case H_Back_Porch: 154 data = h_back_porch; 155 break; 156 case H_Data: 157 data = h_data; 158 break; 159 case H_Front_Porch: 160 data = h_front_porch; 161 break; 162 case Polarities: 163 data = polarities; 164 break; 165 case Command: 166 data = command; 167 break; 168 case Pixel_Format: 169 data = pixel_format; 170 break; 171 case Red_Select: 172 data = red_select; 173 break; 174 case Green_Select: 175 data = green_select; 176 break; 177 case Blue_Select: 178 data = blue_select; 179 break; 180 default: 181 panic("Tried to read HDLCD register that doesn't exist\n", daddr); 182 break; 183 } | 208 const Addr daddr(pkt->getAddr() - pioAddr); 209 panic_if(pkt->getSize() != 4, 210 "Unhandled read size (address: 0x.4x, size: %u)", 211 daddr, pkt->getSize()); |
184 | 212 |
213 const uint32_t data(readReg(daddr)); 214 DPRINTF(HDLcd, "read register 0x%04x: 0x%x\n", daddr, data); 215 |
|
185 pkt->set<uint32_t>(data); 186 pkt->makeAtomicResponse(); 187 return pioDelay; 188} 189 190// write registers and frame buffer 191Tick 192HDLcd::write(PacketPtr pkt) 193{ 194 assert(pkt->getAddr() >= pioAddr && | 216 pkt->set<uint32_t>(data); 217 pkt->makeAtomicResponse(); 218 return pioDelay; 219} 220 221// write registers and frame buffer 222Tick 223HDLcd::write(PacketPtr pkt) 224{ 225 assert(pkt->getAddr() >= pioAddr && |
195 pkt->getAddr() < pioAddr + pioSize && 196 pkt->getSize() == 4); | 226 pkt->getAddr() < pioAddr + pioSize); |
197 | 227 |
198 const uint32_t data = pkt->get<uint32_t>(); 199 const Addr daddr = pkt->getAddr() - pioAddr; | 228 const Addr daddr(pkt->getAddr() - pioAddr); 229 panic_if(pkt->getSize() != 4, 230 "Unhandled read size (address: 0x.4x, size: %u)", 231 daddr, pkt->getSize()); 232 const uint32_t data(pkt->get<uint32_t>()); 233 DPRINTF(HDLcd, "write register 0x%04x: 0x%x\n", daddr, data); |
200 | 234 |
201 DPRINTF(HDLcd, "write register BASE+%0x04x <= 0x%08x\n", daddr, 202 pkt->get<uint32_t>()); | 235 writeReg(daddr, data); |
203 | 236 |
204 switch (daddr) { | 237 pkt->makeAtomicResponse(); 238 return pioDelay; 239} 240 241uint32_t 242HDLcd::readReg(Addr offset) 243{ 244 switch (offset) { 245 case Version: return version; 246 247 case Int_RawStat: return int_rawstat; 248 case Int_Clear: 249 panic("HDLCD INT_CLEAR register is Write-Only\n"); 250 case Int_Mask: return int_mask; 251 case Int_Status: return intStatus(); 252 253 case Fb_Base: return fb_base; 254 case Fb_Line_Length: return fb_line_length; 255 case Fb_Line_Count: return fb_line_count; 256 case Fb_Line_Pitch: return fb_line_pitch; 257 case Bus_Options: return bus_options; 258 259 case V_Sync: return v_sync; 260 case V_Back_Porch: return v_back_porch; 261 case V_Data: return v_data; 262 case V_Front_Porch: return v_front_porch; 263 case H_Sync: return h_sync; 264 case H_Back_Porch: return h_back_porch; 265 case H_Data: return h_data; 266 case H_Front_Porch: return h_front_porch; 267 case Polarities: return polarities; 268 269 case Command: return command; 270 case Pixel_Format: return pixel_format; 271 case Red_Select: return red_select; 272 case Green_Select: return green_select; 273 case Blue_Select: return blue_select; 274 275 default: 276 panic("Tried to read HDLCD register that doesn't exist\n", offset); 277 } 278} 279 280void 281HDLcd::writeReg(Addr offset, uint32_t value) 282{ 283 switch (offset) { |
205 case Version: 206 panic("HDLCD VERSION register is read-Only\n"); | 284 case Version: 285 panic("HDLCD VERSION register is read-Only\n"); |
207 break; | 286 |
208 case Int_RawStat: | 287 case Int_RawStat: |
209 int_rawstat = data; 210 break; | 288 intRaise(value); 289 return; |
211 case Int_Clear: | 290 case Int_Clear: |
212 int_clear = data; 213 break; | 291 intClear(value); 292 return; |
214 case Int_Mask: | 293 case Int_Mask: |
215 int_mask = data; 216 break; | 294 intMask(value); 295 return; |
217 case Int_Status: 218 panic("HDLCD INT_STATUS register is read-Only\n"); 219 break; | 296 case Int_Status: 297 panic("HDLCD INT_STATUS register is read-Only\n"); 298 break; |
299 |
|
220 case Fb_Base: | 300 case Fb_Base: |
221 fb_base = data; 222 DPRINTF(HDLcd, "HDLCD Frame Buffer located at addr 0x%08x\n", fb_base); 223 break; | 301 fb_base = value; 302 return; 303 |
224 case Fb_Line_Length: | 304 case Fb_Line_Length: |
225 fb_line_length = data; 226 DPRINTF(HDLcd, "HDLCD res = %d x %d\n", width(), height()); 227 break; | 305 fb_line_length = value; 306 return; 307 |
228 case Fb_Line_Count: | 308 case Fb_Line_Count: |
229 fb_line_count = data; 230 DPRINTF(HDLcd, "HDLCD res = %d x %d\n", width(), height()); 231 break; | 309 fb_line_count = value; 310 return; 311 |
232 case Fb_Line_Pitch: | 312 case Fb_Line_Pitch: |
233 fb_line_pitch = data; 234 break; | 313 fb_line_pitch = value; 314 return; 315 |
235 case Bus_Options: { | 316 case Bus_Options: { |
236 BusOptsReg old_bus_options; 237 old_bus_options = bus_options; 238 bus_options = data; 239 if (bus_options.max_outstanding != old_bus_options.max_outstanding) 240 DPRINTF(HDLcd, 241 "Changing HDLcd outstanding dma transactions from %d to %d\n", 242 old_bus_options.max_outstanding, bus_options.max_outstanding); 243 if (bus_options.burst_len != old_bus_options.burst_len) 244 DPRINTF(HDLcd, 245 "Changing HDLcd dma burst length from %d bytes to %d bytes\n", 246 old_bus_options.burst_len, bus_options.burst_len); } 247 break; | 317 const BusOptsReg old_bus_options(bus_options); 318 bus_options = value; 319 320 if (bus_options.max_outstanding != old_bus_options.max_outstanding) { 321 DPRINTF(HDLcd, 322 "Changing HDLcd outstanding DMA transactions: %d -> %d\n", 323 old_bus_options.max_outstanding, 324 bus_options.max_outstanding); 325 326 } 327 328 if (bus_options.burst_len != old_bus_options.burst_len) { 329 DPRINTF(HDLcd, 330 "Changing HDLcd DMA burst flags: 0x%x -> 0x%x\n", 331 old_bus_options.burst_len, bus_options.burst_len); 332 } 333 } return; 334 |
248 case V_Sync: | 335 case V_Sync: |
249 v_sync = data; 250 break; | 336 v_sync = value; 337 return; |
251 case V_Back_Porch: | 338 case V_Back_Porch: |
252 v_back_porch = data; 253 break; | 339 v_back_porch = value; 340 return; |
254 case V_Data: | 341 case V_Data: |
255 v_data = data; 256 break; | 342 v_data = value; 343 return; |
257 case V_Front_Porch: | 344 case V_Front_Porch: |
258 v_front_porch = data; 259 break; | 345 v_front_porch = value; 346 return; 347 |
260 case H_Sync: | 348 case H_Sync: |
261 h_sync = data; 262 break; | 349 h_sync = value; 350 return; |
263 case H_Back_Porch: | 351 case H_Back_Porch: |
264 h_back_porch = data; 265 break; | 352 h_back_porch = value; 353 return; |
266 case H_Data: | 354 case H_Data: |
267 h_data = data; 268 break; | 355 h_data = value; 356 return; |
269 case H_Front_Porch: | 357 case H_Front_Porch: |
270 h_front_porch = data; 271 break; | 358 h_front_porch = value; 359 return; 360 |
272 case Polarities: | 361 case Polarities: |
273 polarities = data; 274 break; | 362 polarities = value; 363 return; 364 |
275 case Command: { | 365 case Command: { |
276 CommandReg new_command; 277 new_command = data; 278 if (new_command.enable != command.enable) { 279 DPRINTF(HDLcd, "HDLCD switched %s\n", 280 new_command.enable==0 ? "off" : "on"); 281 if (new_command.enable) { 282 doUpdateParams = true; 283 if (!frameUnderway) { 284 schedule(startFrameEvent, clockEdge()); 285 } 286 } 287 } 288 command = new_command; } 289 break; | 366 const CommandReg new_command(value); 367 368 if (new_command.enable != command.enable) { 369 DPRINTF(HDLcd, "HDLCD switched %s\n", 370 new_command.enable ? "on" : "off"); 371 372 if (new_command.enable) { 373 cmdEnable(); 374 } else { 375 cmdDisable(); 376 } 377 } 378 command = new_command; 379 } return; 380 |
290 case Pixel_Format: | 381 case Pixel_Format: |
291 pixel_format = data; 292 DPRINTF(HDLcd, "HDLCD res = %d x %d\n", width(), height()); 293 DPRINTF(HDLcd, "HDLCD bytes per pixel = %d\n", bytesPerPixel()); 294 DPRINTF(HDLcd, "HDLCD endianness = %s\n", 295 pixel_format.big_endian ? "big" : "little"); 296 break; | 382 pixel_format = value; 383 return; 384 |
297 case Red_Select: | 385 case Red_Select: |
298 red_select = data; 299 break; | 386 red_select = value; 387 return; |
300 case Green_Select: | 388 case Green_Select: |
301 green_select = data; 302 break; | 389 green_select = value; 390 return; |
303 case Blue_Select: | 391 case Blue_Select: |
304 blue_select = data; 305 break; | 392 blue_select = value; 393 return; 394 |
306 default: | 395 default: |
307 panic("Tried to write HDLCD register that doesn't exist\n", daddr); 308 break; | 396 panic("Tried to write HDLCD register that doesn't exist\n", offset); 397 return; |
309 } | 398 } |
310 311 pkt->makeAtomicResponse(); 312 return pioDelay; | |
313} 314 | 399} 400 |
315void 316HDLcd::updateVideoParams(bool unserializing = false) | 401PixelConverter 402HDLcd::pixelConverter() const |
317{ | 403{ |
318 const uint16_t bpp M5_VAR_USED = bytesPerPixel() << 3; | 404 ByteOrder byte_order( 405 pixel_format.big_endian ? BigEndianByteOrder : LittleEndianByteOrder); |
319 | 406 |
320 // Workaround configuration bugs where multiple display 321 // controllers are attached to the same VNC server by reattaching 322 // enabled devices. This isn't ideal, but works as long as only 323 // one display controller is active at a time. 324 if (command.enable && vnc) 325 vnc->setFrameBuffer(&fb); 326 327 // updating these parameters while LCD is enabled is not supported 328 if (frameUnderway && !unserializing) 329 panic("Attempting to change some HDLCD parameters while the controller" 330 " is active is not allowed"); 331 332 // resize the virtualDisplayBuffer unless we are unserializing - it may 333 // have changed size 334 // there must be no outstanding DMA transactions for this to work 335 if (!unserializing) { 336 assert(dmaPendingNum == 0); 337 338 virtualDisplayBuffer.resize(bytesPerPixel() * area()); 339 fb.resize(width(), height()); 340 fb.clear(); 341 342 std::fill(virtualDisplayBuffer.begin(), virtualDisplayBuffer.end(), 343 0); | 407 /* Some Linux kernels have a broken driver that swaps the red and 408 * blue color select registers. */ 409 if (!workaroundSwapRB) { 410 return PixelConverter( 411 pixel_format.bytes_per_pixel + 1, 412 red_select.offset, green_select.offset, blue_select.offset, 413 red_select.size, green_select.size, blue_select.size, 414 byte_order); 415 } else { 416 return PixelConverter( 417 pixel_format.bytes_per_pixel + 1, 418 blue_select.offset, green_select.offset, red_select.offset, 419 blue_select.size, green_select.size, red_select.size, 420 byte_order); |
344 } | 421 } |
422} |
|
345 | 423 |
346 DPRINTF(HDLcd, "bpp = %d\n", bpp); 347 DPRINTF(HDLcd, "display size = %d x %d\n", width(), height()); 348#if TRACING_ON 349 const size_t totalLinesPerFrame = v_back_porch.val + 1 + 350 v_data.val + 1 + 351 v_front_porch.val + 1 + 352 v_sync.val + 1; 353 const double fps = (double)SimClock::Frequency / 354 (double)(PClksPerLine() * totalLinesPerFrame * pixelClock); 355#endif 356 DPRINTF(HDLcd, "simulated refresh rate ~ %.1ffps generating ~ %.1fMB/s " 357 "traffic ([%.1fMHz, T=%d sim clocks] pclk, %d bpp => %.1fMB/s peak requirement)\n", 358 fps, 359 fps * virtualDisplayBuffer.size() / 1024 / 1024, 360 (double)SimClock::Frequency / pixelClock / 1000000.0, 361 pixelClock, 362 bpp, 363 (double)(SimClock::Frequency / pixelClock * (bpp / 8)) / 1024 / 1024); | 424DisplayTimings 425HDLcd::displayTimings() const 426{ 427 return DisplayTimings( 428 h_data.val + 1, v_data.val + 1, 429 h_back_porch.val + 1, h_sync.val + 1, h_front_porch.val + 1, 430 v_back_porch.val + 1, v_sync.val + 1, v_front_porch.val + 1); |
364} 365 366void | 431} 432 433void |
367HDLcd::startFrame() | 434HDLcd::createDmaEngine() |
368{ | 435{ |
369 // 0. Check that we are in the appropriate state 370 assert(!frameUnderway); 371 if (!command.enable) | 436 if (bus_options.max_outstanding == 0) { 437 warn("Maximum number of outstanding DMA transfers set to 0."); |
372 return; | 438 return; |
373 DPRINTF(HDLcd, "Frame read started\n"); 374 if (doUpdateParams) { 375 updateVideoParams(); 376 doUpdateParams = false; | |
377 } | 439 } |
378 frameUnderway = true; 379 assert(!virtualDisplayBuffer.empty()); 380 assert(pixelBufferSize == 0); 381 assert(dmaBytesInFlight == 0); 382 assert(dmaPendingNum == 0); 383 assert(dmaDoneEventFree.size() == dmaDoneEventAll.size()); 384 assert(!renderPixelEvent.scheduled()); 385 // currently only support positive line pitches equal to the line length 386 assert(width() * bytesPerPixel() == fb_line_pitch); | |
387 | 440 |
388 // 1. Start DMA'ing the frame; subsequent transactions created as we go 389 dmaCurAddr = dmaStartAddr = fb_base; 390 dmaMaxAddr = static_cast<Addr>(width() * height() * bytesPerPixel()) + 391 dmaCurAddr; 392 frameReadStartTime = curTick(); 393 pixelIndex = 0; 394 frameUnderrun = false; 395 fillPixelBuffer(); | 441 const uint32_t dma_burst_flags(bus_options.burst_len); 442 const uint32_t dma_burst_len( 443 dma_burst_flags ? 444 (1UL << (findMsbSet(dma_burst_flags) - 1)) : 445 MAX_BURST_LEN); 446 // Some drivers seem to set the DMA line count incorrectly. This 447 // could either be a driver bug or a specification bug. Unlike for 448 // timings, the specification does not require 1 to be added to 449 // the DMA engine's line count. 450 const uint32_t dma_lines( 451 fb_line_count + (workaroundDmaLineCount ? 1 : 0)); |
396 | 452 |
397 // 2. Schedule first pixelclock read; subsequent reads generated as we go 398 Tick firstPixelReadTick = curTick() + pixelClock * ( 399 PClksPerLine() * (v_sync.val + 1 + 400 v_back_porch.val + 1) + 401 h_sync.val + 1 + 402 h_back_porch.val + 1); 403 schedule(renderPixelEvent, firstPixelReadTick); | 453 dmaEngine.reset(new DmaEngine( 454 *this, pixelBufferSize, 455 AXI_PORT_WIDTH * dma_burst_len, 456 bus_options.max_outstanding, 457 fb_line_length, fb_line_pitch, dma_lines)); |
404} 405 406void | 458} 459 460void |
407HDLcd::fillPixelBuffer() | 461HDLcd::cmdEnable() |
408{ | 462{ |
409 // - am I under the LCD dma transaction total? 410 // - do I have more data to transfer? 411 // - have I not yet underrun for this frame? 412 // - is there room to put the data in the pixel buffer including any 413 // outstanding dma transfers in flight? 414 while ((dmaPendingNum < maxOutstandingDma()) && 415 (dmaMaxAddr > dmaCurAddr) && 416 !frameUnderrun && 417 bytesFreeInPixelBuffer() > dmaBurstLength() * AXI_PORT_WIDTH) { 418 // try largest transaction size allowed first but switch to smaller 419 // sizes for trailing bytes 420 size_t transaction_size = dmaBurstLength() * AXI_PORT_WIDTH; 421 while (transaction_size > (dmaMaxAddr - dmaCurAddr)) 422 transaction_size >>= 1; 423 assert(transaction_size > 0); 424 425 // concurrent dma reads need different dma done events 426 // due to assertion in scheduling state 427 ++dmaPendingNum; 428 429 assert(!dmaDoneEventFree.empty()); 430 DmaDoneEvent *event(dmaDoneEventFree.back()); 431 dmaDoneEventFree.pop_back(); 432 assert(event); 433 assert(!event->scheduled()); 434 435 // We use a uncachable request here because the requests from the CPU 436 // will be uncacheable as well. If we have uncacheable and cacheable 437 // requests in the memory system for the same address it won't be 438 // pleased 439 uint8_t *const dma_dst( 440 virtualDisplayBuffer.data() + dmaCurAddr - dmaStartAddr); 441 event->setTransactionSize(transaction_size); 442 dmaPort.dmaAction(MemCmd::ReadReq, dmaCurAddr, transaction_size, event, 443 dma_dst, 0, Request::UNCACHEABLE); 444 dmaCurAddr += transaction_size; 445 dmaBytesInFlight += transaction_size; 446 } | 463 createDmaEngine(); 464 conv = pixelConverter(); 465 pixelPump.start(displayTimings()); |
447} 448 449void | 466} 467 468void |
450HDLcd::renderPixel() | 469HDLcd::cmdDisable() |
451{ | 470{ |
452 // try to handle multiple pixels at a time; doing so reduces the accuracy 453 // of the underrun detection but lowers simulation overhead 454 const size_t count = 32; 455 assert(width() % count == 0); // not set up to handle trailing pixels | 471 pixelPump.stop(); 472 dmaEngine->abortFrame(); 473} |
456 | 474 |
457 // have we underrun on this frame anytime before? 458 if (frameUnderrun) { 459 // the LCD controller gives up on a frame if an underrun occurs and 460 // resumes regular operation on the next frame 461 pixelBufferSize = 0; | 475bool 476HDLcd::pxlNext(Pixel &p) 477{ 478 uint8_t pixel_data[MAX_PIXEL_SIZE]; 479 assert(conv.length <= sizeof(pixel_data)); 480 if (dmaEngine->tryGet(pixel_data, conv.length)) { 481 p = conv.toPixel(pixel_data); 482 return true; |
462 } else { | 483 } else { |
463 // did we underrun on this set of pixels? 464 if (pixelBufferSize < bytesPerPixel() * count) { 465 warn("HDLcd controller buffer underrun\n"); 466 frameUnderrun = true; 467 int_rawstat.underrun = 1; 468 if (!intEvent.scheduled()) 469 schedule(intEvent, clockEdge()); 470 } else { 471 // emulate the pixel read from the internal buffer 472 pixelBufferSize -= bytesPerPixel() * count; 473 } | 484 return false; |
474 } | 485 } |
486} |
|
475 | 487 |
476 // the DMA may have previously stalled due to the buffer being full; 477 // give it a kick; it knows not to fill if at end of frame, underrun, etc 478 if (!fillPixelBufferEvent.scheduled()) 479 schedule(fillPixelBufferEvent, clockEdge()); 480 481 // schedule the next pixel read according to where it is in the frame 482 pixelIndex += count; 483 assert(pixelIndex <= width() * height()); 484 size_t x = pixelIndex % width(); 485 Tick nextEventTick = curTick(); 486 if (x == 0) { 487 // start of new line 488 nextEventTick += pixelClock * ((h_front_porch.val + 1) + 489 (h_back_porch.val + 1) + 490 (h_sync.val + 1)); 491 if (pixelIndex == width() * height()) { 492 // end of frame 493 nextEventTick += PClksPerLine() * (v_front_porch.val + 1) * 494 pixelClock; 495 schedule(endFrameEvent, nextEventTick); 496 return; 497 } 498 } else { 499 nextEventTick += pixelClock * count; 500 } 501 502 schedule(renderPixelEvent, nextEventTick); | 488void 489HDLcd::pxlVSyncBegin() 490{ 491 DPRINTF(HDLcd, "Raising VSYNC interrupt.\n"); 492 intRaise(INT_VSYNC); |
503} 504 | 493} 494 |
505PixelConverter 506HDLcd::pixelConverter() const | 495void 496HDLcd::pxlVSyncEnd() |
507{ | 497{ |
508 ByteOrder byte_order( 509 pixel_format.big_endian ? BigEndianByteOrder : LittleEndianByteOrder); | 498 DPRINTF(HDLcd, "End of VSYNC, starting DMA engine\n"); 499 dmaEngine->startFrame(fb_base); 500} |
510 | 501 |
511 /* Some Linux kernels have a broken driver that swaps the red and 512 * blue color select registers. */ 513 if (!workaround_swap_rb) { 514 return PixelConverter( 515 bytesPerPixel(), 516 red_select.offset, green_select.offset, blue_select.offset, 517 red_select.size, green_select.size, blue_select.size, 518 byte_order); 519 } else { 520 return PixelConverter( 521 bytesPerPixel(), 522 blue_select.offset, green_select.offset, red_select.offset, 523 blue_select.size, green_select.size, red_select.size, 524 byte_order); 525 } | 502void 503HDLcd::pxlUnderrun() 504{ 505 DPRINTF(HDLcd, "Buffer underrun, stopping DMA fill.\n"); 506 intRaise(INT_UNDERRUN); 507 dmaEngine->abortFrame(); |
526} 527 528void | 508} 509 510void |
529HDLcd::endFrame() { 530 assert(pixelBufferSize == 0); 531 assert(dmaPendingNum == 0); 532 assert(dmaBytesInFlight == 0); 533 assert(dmaDoneEventFree.size() == dmaDoneEventAll.size()); | 511HDLcd::pxlFrameDone() 512{ 513 DPRINTF(HDLcd, "Reached end of last visible line.\n"); |
534 | 514 |
535 fb.copyIn(virtualDisplayBuffer, pixelConverter()); | 515 if (dmaEngine->size()) { 516 warn("HDLCD %u bytes still in FIFO after frame: Ensure that DMA " 517 "and PixelPump configuration is consistent\n", 518 dmaEngine->size()); 519 dmaEngine->dumpSettings(); 520 pixelPump.dumpSettings(); 521 } |
536 537 if (vnc) 538 vnc->setDirty(); 539 540 if (enableCapture) { | 522 523 if (vnc) 524 vnc->setDirty(); 525 526 if (enableCapture) { |
541 if (!pic) 542 pic = simout.create(csprintf("%s.framebuffer.bmp", sys->name()), true); | 527 if (!pic) { 528 pic = simout.create( 529 csprintf("%s.framebuffer.bmp", sys->name()), 530 true); 531 } |
543 544 assert(pic); 545 pic->seekp(0); 546 bmp.write(*pic); 547 } | 532 533 assert(pic); 534 pic->seekp(0); 535 bmp.write(*pic); 536 } |
548 549 // start the next frame 550 frameUnderway = false; 551 startFrame(); | |
552} 553 554void | 537} 538 539void |
555HDLcd::dmaDone(DmaDoneEvent *event) | 540HDLcd::setInterrupts(uint32_t ints, uint32_t mask) |
556{ | 541{ |
557 const size_t transactionLength = event->getTransactionSize(); 558 assert(pixelBufferSize + transactionLength < PIXEL_BUFFER_CAPACITY); 559 assert(dmaCurAddr <= dmaMaxAddr); | 542 const bool old_ints(intStatus()); |
560 | 543 |
561 dmaDoneEventFree.push_back(event); 562 --dmaPendingNum; 563 assert(MAX_OUTSTANDING_DMA_REQ_CAPACITY - dmaDoneEventFree.size() == 564 dmaPendingNum); | 544 int_mask = mask; 545 int_rawstat = ints; |
565 | 546 |
566 // add the data to the pixel buffer 567 dmaBytesInFlight -= transactionLength; 568 pixelBufferSize += transactionLength; 569 570 // schedule another dma transaction if: 571 // - we're not done reading the frame 572 // - there is sufficient room in the pixel buffer for another transaction 573 // - another fillPixelBufferEvent is not already scheduled 574 const size_t targetTransSize = dmaBurstLength() * AXI_PORT_WIDTH; 575 if ((dmaCurAddr < dmaMaxAddr) && 576 (bytesFreeInPixelBuffer() + targetTransSize < PIXEL_BUFFER_CAPACITY) && 577 !fillPixelBufferEvent.scheduled()) { 578 schedule(fillPixelBufferEvent, clockEdge()); | 547 if (!old_ints && intStatus()) { 548 gic->sendInt(intNum); 549 } else if (old_ints && !intStatus()) { 550 gic->clearInt(intNum); |
579 } 580} 581 | 551 } 552} 553 |
554HDLcd::DmaEngine::DmaEngine(HDLcd &_parent, size_t size, 555 unsigned request_size, unsigned max_pending, 556 size_t line_size, ssize_t line_pitch, unsigned num_lines) 557 : DmaReadFifo( 558 _parent.dmaPort, size, request_size, max_pending, 559 Request::UNCACHEABLE), 560 parent(_parent), 561 lineSize(line_size), linePitch(line_pitch), numLines(num_lines), 562 nextLineAddr(0) 563{ 564} 565 |
|
582void | 566void |
583HDLcd::serialize(CheckpointOut &cp) const | 567HDLcd::DmaEngine::serialize(CheckpointOut &cp) const |
584{ | 568{ |
585 DPRINTF(HDLcd, "Serializing ARM HDLCD\n"); | 569 DmaReadFifo::serialize(cp); |
586 | 570 |
587 const uint32_t version_serial = version; 588 SERIALIZE_SCALAR(version_serial); 589 const uint32_t int_rawstat_serial = int_rawstat; 590 SERIALIZE_SCALAR(int_rawstat_serial); 591 const uint32_t int_clear_serial = int_clear; 592 SERIALIZE_SCALAR(int_clear_serial); 593 const uint32_t int_mask_serial = int_mask; 594 SERIALIZE_SCALAR(int_mask_serial); 595 const uint32_t int_status_serial = int_status; 596 SERIALIZE_SCALAR(int_status_serial); | 571 SERIALIZE_SCALAR(nextLineAddr); 572 SERIALIZE_SCALAR(frameEnd); 573} |
597 | 574 |
598 SERIALIZE_SCALAR(fb_base); 599 SERIALIZE_SCALAR(fb_line_length); | 575void 576HDLcd::DmaEngine::unserialize(CheckpointIn &cp) 577{ 578 DmaReadFifo::unserialize(cp); |
600 | 579 |
601 const uint32_t fb_line_count_serial = fb_line_count; 602 SERIALIZE_SCALAR(fb_line_count_serial); | 580 UNSERIALIZE_SCALAR(nextLineAddr); 581 UNSERIALIZE_SCALAR(frameEnd); 582} |
603 | 583 |
604 SERIALIZE_SCALAR(fb_line_pitch); | 584void 585HDLcd::DmaEngine::startFrame(Addr fb_base) 586{ 587 nextLineAddr = fb_base; 588 frameEnd = fb_base + numLines * linePitch; |
605 | 589 |
606 const uint32_t bus_options_serial = bus_options; 607 SERIALIZE_SCALAR(bus_options_serial); 608 const uint32_t v_sync_serial = v_sync; 609 SERIALIZE_SCALAR(v_sync_serial); 610 const uint32_t v_back_porch_serial = v_back_porch; 611 SERIALIZE_SCALAR(v_back_porch_serial); 612 const uint32_t v_data_serial = v_data; 613 SERIALIZE_SCALAR(v_data_serial); 614 const uint32_t v_front_porch_serial = v_front_porch; 615 SERIALIZE_SCALAR(v_front_porch_serial); 616 const uint32_t h_sync_serial = h_sync; 617 SERIALIZE_SCALAR(h_sync_serial); 618 const uint32_t h_back_porch_serial = h_back_porch; 619 SERIALIZE_SCALAR(h_back_porch_serial); 620 const uint32_t h_data_serial = h_data; 621 SERIALIZE_SCALAR(h_data_serial); 622 const uint32_t h_front_porch_serial = h_front_porch; 623 SERIALIZE_SCALAR(h_front_porch_serial); 624 const uint32_t polarities_serial = polarities; 625 SERIALIZE_SCALAR(polarities_serial); 626 const uint32_t command_serial = command; 627 SERIALIZE_SCALAR(command_serial); 628 const uint32_t pixel_format_serial = pixel_format; 629 SERIALIZE_SCALAR(pixel_format_serial); 630 const uint32_t red_select_serial = red_select; 631 SERIALIZE_SCALAR(red_select_serial); 632 const uint32_t green_select_serial = green_select; 633 SERIALIZE_SCALAR(green_select_serial); 634 const uint32_t blue_select_serial = blue_select; 635 SERIALIZE_SCALAR(blue_select_serial); | 590 startFill(nextLineAddr, lineSize); 591} |
636 | 592 |
637 SERIALIZE_SCALAR(frameReadStartTime); 638 SERIALIZE_SCALAR(dmaStartAddr); 639 SERIALIZE_SCALAR(dmaCurAddr); 640 SERIALIZE_SCALAR(dmaMaxAddr); 641 SERIALIZE_SCALAR(dmaPendingNum); 642 SERIALIZE_SCALAR(frameUnderrun); | 593void 594HDLcd::DmaEngine::abortFrame() 595{ 596 nextLineAddr = frameEnd; 597 stopFill(); 598 flush(); 599} |
643 | 600 |
644 arrayParamOut(cp, "virtualDisplayBuffer", virtualDisplayBuffer); | |
645 | 601 |
646 SERIALIZE_SCALAR(pixelBufferSize); 647 SERIALIZE_SCALAR(pixelIndex); 648 SERIALIZE_SCALAR(doUpdateParams); 649 SERIALIZE_SCALAR(frameUnderway); 650 SERIALIZE_SCALAR(dmaBytesInFlight); 651 652 Tick start_event_time = 0; 653 Tick end_event_time = 0; 654 Tick render_pixel_event_time = 0; 655 Tick fill_pixel_buffer_event_time = 0; 656 Tick int_event_time = 0; 657 if (startFrameEvent.scheduled()) 658 start_event_time = startFrameEvent.when(); 659 if (endFrameEvent.scheduled()) 660 end_event_time = endFrameEvent.when(); 661 if (renderPixelEvent.scheduled()) 662 render_pixel_event_time = renderPixelEvent.when(); 663 if (fillPixelBufferEvent.scheduled()) 664 fill_pixel_buffer_event_time = fillPixelBufferEvent.when(); 665 if (intEvent.scheduled()) 666 int_event_time = intEvent.when(); 667 SERIALIZE_SCALAR(start_event_time); 668 SERIALIZE_SCALAR(end_event_time); 669 SERIALIZE_SCALAR(render_pixel_event_time); 670 SERIALIZE_SCALAR(fill_pixel_buffer_event_time); 671 SERIALIZE_SCALAR(int_event_time); 672 673 vector<Tick> dma_done_event_tick(MAX_OUTSTANDING_DMA_REQ_CAPACITY); 674 vector<size_t> dma_done_event_burst_len(MAX_OUTSTANDING_DMA_REQ_CAPACITY); 675 for (int x = 0; x < MAX_OUTSTANDING_DMA_REQ_CAPACITY; ++x) { 676 dma_done_event_tick[x] = dmaDoneEventAll[x].scheduled() ? 677 dmaDoneEventAll[x].when() : 0; 678 dma_done_event_burst_len[x] = dmaDoneEventAll[x].scheduled() ? 679 dmaDoneEventAll[x].getTransactionSize() : 0; 680 } 681 arrayParamOut(cp, "dma_done_event_tick", dma_done_event_tick); 682 arrayParamOut(cp, "dma_done_event_burst_length", dma_done_event_burst_len); | 602void 603HDLcd::DmaEngine::dumpSettings() 604{ 605 inform("DMA line size: %u bytes", lineSize); 606 inform("DMA line pitch: %i bytes", linePitch); 607 inform("DMA num lines: %u", numLines); |
683} 684 685void | 608} 609 610void |
686HDLcd::unserialize(CheckpointIn &cp) | 611HDLcd::DmaEngine::onEndOfBlock() |
687{ | 612{ |
688 uint32_t version_serial, int_rawstat_serial, int_clear_serial, 689 int_mask_serial, int_status_serial, fb_line_count_serial, 690 bus_options_serial, v_sync_serial, v_back_porch_serial, 691 v_data_serial, v_front_porch_serial, h_sync_serial, 692 h_back_porch_serial, h_data_serial, h_front_porch_serial, 693 polarities_serial, command_serial, pixel_format_serial, 694 red_select_serial, green_select_serial, blue_select_serial; | 613 if (nextLineAddr == frameEnd) 614 // We're done with this frame. Ignore calls to this method 615 // until the next frame has been started. 616 return; |
695 | 617 |
696 DPRINTF(HDLcd, "Unserializing ARM HDLCD\n"); 697 698 UNSERIALIZE_SCALAR(version_serial); 699 version = version_serial; 700 UNSERIALIZE_SCALAR(int_rawstat_serial); 701 int_rawstat = int_rawstat_serial; 702 UNSERIALIZE_SCALAR(int_clear_serial); 703 int_clear = int_clear_serial; 704 UNSERIALIZE_SCALAR(int_mask_serial); 705 int_mask = int_mask_serial; 706 UNSERIALIZE_SCALAR(int_status_serial); 707 int_status = int_status_serial; 708 709 UNSERIALIZE_SCALAR(fb_base); 710 UNSERIALIZE_SCALAR(fb_line_length); 711 712 UNSERIALIZE_SCALAR(fb_line_count_serial); 713 fb_line_count = fb_line_count_serial; 714 715 UNSERIALIZE_SCALAR(fb_line_pitch); 716 717 UNSERIALIZE_SCALAR(bus_options_serial); 718 bus_options = bus_options_serial; 719 UNSERIALIZE_SCALAR(v_sync_serial); 720 v_sync = v_sync_serial; 721 UNSERIALIZE_SCALAR(v_back_porch_serial); 722 v_back_porch = v_back_porch_serial; 723 UNSERIALIZE_SCALAR(v_data_serial); 724 v_data = v_data_serial; 725 UNSERIALIZE_SCALAR(v_front_porch_serial); 726 v_front_porch = v_front_porch_serial; 727 UNSERIALIZE_SCALAR(h_sync_serial); 728 h_sync = h_sync_serial; 729 UNSERIALIZE_SCALAR(h_back_porch_serial); 730 h_back_porch = h_back_porch_serial; 731 UNSERIALIZE_SCALAR(h_data_serial); 732 h_data = h_data_serial; 733 UNSERIALIZE_SCALAR(h_front_porch_serial); 734 h_front_porch = h_front_porch_serial; 735 UNSERIALIZE_SCALAR(polarities_serial); 736 polarities = polarities_serial; 737 UNSERIALIZE_SCALAR(command_serial); 738 command = command_serial; 739 UNSERIALIZE_SCALAR(pixel_format_serial); 740 pixel_format = pixel_format_serial; 741 UNSERIALIZE_SCALAR(red_select_serial); 742 red_select = red_select_serial; 743 UNSERIALIZE_SCALAR(green_select_serial); 744 green_select = green_select_serial; 745 UNSERIALIZE_SCALAR(blue_select_serial); 746 blue_select = blue_select_serial; 747 748 UNSERIALIZE_SCALAR(frameReadStartTime); 749 UNSERIALIZE_SCALAR(dmaStartAddr); 750 UNSERIALIZE_SCALAR(dmaCurAddr); 751 UNSERIALIZE_SCALAR(dmaMaxAddr); 752 UNSERIALIZE_SCALAR(dmaPendingNum); 753 UNSERIALIZE_SCALAR(frameUnderrun); 754 UNSERIALIZE_SCALAR(dmaBytesInFlight); 755 756 arrayParamIn(cp, "virtualDisplayBuffer", virtualDisplayBuffer); 757 758 UNSERIALIZE_SCALAR(pixelBufferSize); 759 UNSERIALIZE_SCALAR(pixelIndex); 760 UNSERIALIZE_SCALAR(doUpdateParams); 761 UNSERIALIZE_SCALAR(frameUnderway); 762 763 Tick start_event_time = 0; 764 Tick end_event_time = 0; 765 Tick render_pixel_event_time = 0; 766 Tick fill_pixel_buffer_event_time = 0; 767 Tick int_event_time = 0; 768 UNSERIALIZE_SCALAR(start_event_time); 769 UNSERIALIZE_SCALAR(end_event_time); 770 UNSERIALIZE_SCALAR(render_pixel_event_time); 771 UNSERIALIZE_SCALAR(fill_pixel_buffer_event_time); 772 UNSERIALIZE_SCALAR(int_event_time); 773 if (start_event_time) 774 schedule(startFrameEvent, start_event_time); 775 if (end_event_time) 776 schedule(endFrameEvent, end_event_time); 777 if (render_pixel_event_time) 778 schedule(renderPixelEvent, render_pixel_event_time); 779 if (fill_pixel_buffer_event_time) 780 schedule(fillPixelBufferEvent, fill_pixel_buffer_event_time); 781 if (int_event_time) 782 schedule(intEvent, int_event_time); 783 784 vector<Tick> dma_done_event_tick(MAX_OUTSTANDING_DMA_REQ_CAPACITY); 785 vector<Tick> dma_done_event_burst_len(MAX_OUTSTANDING_DMA_REQ_CAPACITY); 786 arrayParamIn(cp, "dma_done_event_tick", dma_done_event_tick); 787 arrayParamIn(cp, "dma_done_event_burst_length", dma_done_event_burst_len); 788 dmaDoneEventFree.clear(); 789 for (int x = 0; x < MAX_OUTSTANDING_DMA_REQ_CAPACITY; ++x) { 790 if (dma_done_event_tick[x]) { 791 dmaDoneEventAll[x].setTransactionSize(dma_done_event_burst_len[x]); 792 schedule(dmaDoneEventAll[x], dma_done_event_tick[x]); 793 } else 794 dmaDoneEventFree.push_back(&dmaDoneEventAll[x]); 795 } 796 assert(MAX_OUTSTANDING_DMA_REQ_CAPACITY - dmaDoneEventFree.size() == dmaPendingNum); 797 798 if (frameUnderway) { 799 updateVideoParams(true); 800 fb.resize(width(), height()); 801 fb.copyIn(virtualDisplayBuffer, pixelConverter()); 802 if (vnc) 803 vnc->setDirty(); 804 } | 618 nextLineAddr += linePitch; 619 if (nextLineAddr != frameEnd) 620 startFill(nextLineAddr, lineSize); |
805} 806 807void | 621} 622 623void |
808HDLcd::generateInterrupt() | 624HDLcd::DmaEngine::onIdle() |
809{ | 625{ |
810 int_status = int_rawstat & int_mask; 811 DPRINTF(HDLcd, "Generate Interrupt: int_rawstat=0x%08x int_mask=0x%08x " 812 "int_status=0x%08x\n", 813 (uint32_t)int_rawstat, (uint32_t)int_mask, (uint32_t)int_status); 814 815 if (int_status != 0) { 816 gic->sendInt(intNum); 817 DPRINTF(HDLcd, " -- Generated\n"); 818 } | 626 parent.intRaise(INT_DMA_END); |
819} 820 | 627} 628 |
821AddrRangeList 822HDLcd::getAddrRanges() const | 629void 630HDLcd::PixelPump::dumpSettings() |
823{ | 631{ |
824 AddrRangeList ranges; 825 ranges.push_back(RangeSize(pioAddr, pioSize)); 826 return ranges; | 632 const DisplayTimings &t(timings()); 633 634 inform("PixelPump width: %u", t.width); 635 inform("PixelPump height: %u", t.height); 636 637 inform("PixelPump horizontal back porch: %u", t.hBackPorch); 638 inform("PixelPump horizontal fron porch: %u", t.hFrontPorch); 639 inform("PixelPump horizontal fron porch: %u", t.hSync); 640 641 inform("PixelPump vertical back porch: %u", t.vBackPorch); 642 inform("PixelPump vertical fron porch: %u", t.vFrontPorch); 643 inform("PixelPump vertical fron porch: %u", t.vSync); |
827} 828 | 644} 645 |
646 |
|
829HDLcd * 830HDLcdParams::create() 831{ 832 return new HDLcd(this); 833} | 647HDLcd * 648HDLcdParams::create() 649{ 650 return new HDLcd(this); 651} |