hdlcd.cc (10840:48039363f67a) hdlcd.cc (10905:a6ca6831e775)
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
9 * licensed hereunder. You may use the software subject to the license
10 * terms below provided that you ensure that this notice is replicated
11 * unmodified and in its entirety in all distributions of the software,
12 * modified or unmodified, in source code or in binary form.
13 *
14 * Redistribution and use in source and binary forms, with or without
15 * modification, are permitted provided that the following conditions are
16 * met: redistributions of source code must retain the above copyright
17 * notice, this list of conditions and the following disclaimer;
18 * redistributions in binary form must reproduce the above copyright
19 * notice, this list of conditions and the following disclaimer in the
20 * documentation and/or other materials provided with the distribution;
21 * neither the name of the copyright holders nor the names of its
22 * contributors may be used to endorse or promote products derived from
23 * this software without specific prior written permission.
24 *
25 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
26 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
27 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
28 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
29 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
30 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
31 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
32 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
33 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
34 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
35 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36 *
37 * Authors: Chris Emmons
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"
45#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"
51#include "sim/system.hh"
52
53using std::vector;
54
55
56// 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),
60 fb_base(0), fb_line_length(0), fb_line_count(0), fb_line_pitch(0),
61 bus_options(BUS_OPTIONS_RESETV),
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),
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;
81
82 for (int i = 0; i < MAX_OUTSTANDING_DMA_REQ_CAPACITY; ++i)
83 dmaDoneEventFree[i] = &dmaDoneEventAll[i];
84
85 if (vnc)
86 vnc->setFrameBuffer(&fb);
87}
88
89HDLcd::~HDLcd()
90{
91}
92
93// read registers and frame buffer
94Tick
95HDLcd::read(PacketPtr pkt)
96{
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 &&
104 pkt->getAddr() < pioAddr + pioSize &&
105 pkt->getSize() == 4);
106
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 }
184
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 &&
195 pkt->getAddr() < pioAddr + pioSize &&
196 pkt->getSize() == 4);
197
198 const uint32_t data = pkt->get<uint32_t>();
199 const Addr daddr = pkt->getAddr() - pioAddr;
200
201 DPRINTF(HDLcd, "write register BASE+%0x04x <= 0x%08x\n", daddr,
202 pkt->get<uint32_t>());
203
204 switch (daddr) {
205 case Version:
206 panic("HDLCD VERSION register is read-Only\n");
207 break;
208 case Int_RawStat:
209 int_rawstat = data;
210 break;
211 case Int_Clear:
212 int_clear = data;
213 break;
214 case Int_Mask:
215 int_mask = data;
216 break;
217 case Int_Status:
218 panic("HDLCD INT_STATUS register is read-Only\n");
219 break;
220 case Fb_Base:
221 fb_base = data;
222 DPRINTF(HDLcd, "HDLCD Frame Buffer located at addr 0x%08x\n", fb_base);
223 break;
224 case Fb_Line_Length:
225 fb_line_length = data;
226 DPRINTF(HDLcd, "HDLCD res = %d x %d\n", width(), height());
227 break;
228 case Fb_Line_Count:
229 fb_line_count = data;
230 DPRINTF(HDLcd, "HDLCD res = %d x %d\n", width(), height());
231 break;
232 case Fb_Line_Pitch:
233 fb_line_pitch = data;
234 break;
235 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;
248 case V_Sync:
249 v_sync = data;
250 break;
251 case V_Back_Porch:
252 v_back_porch = data;
253 break;
254 case V_Data:
255 v_data = data;
256 break;
257 case V_Front_Porch:
258 v_front_porch = data;
259 break;
260 case H_Sync:
261 h_sync = data;
262 break;
263 case H_Back_Porch:
264 h_back_porch = data;
265 break;
266 case H_Data:
267 h_data = data;
268 break;
269 case H_Front_Porch:
270 h_front_porch = data;
271 break;
272 case Polarities:
273 polarities = data;
274 break;
275 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;
290 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;
297 case Red_Select:
298 red_select = data;
299 break;
300 case Green_Select:
301 green_select = data;
302 break;
303 case Blue_Select:
304 blue_select = data;
305 break;
306 default:
307 panic("Tried to write HDLCD register that doesn't exist\n", daddr);
308 break;
309 }
310
311 pkt->makeAtomicResponse();
312 return pioDelay;
313}
314
315void
316HDLcd::updateVideoParams(bool unserializing = false)
317{
318 const uint16_t bpp M5_VAR_USED = bytesPerPixel() << 3;
319
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);
344 }
345
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);
364}
365
366void
367HDLcd::startFrame()
368{
369 // 0. Check that we are in the appropriate state
370 assert(!frameUnderway);
371 if (!command.enable)
372 return;
373 DPRINTF(HDLcd, "Frame read started\n");
374 if (doUpdateParams) {
375 updateVideoParams();
376 doUpdateParams = false;
377 }
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
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();
396
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);
404}
405
406void
407HDLcd::fillPixelBuffer()
408{
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 }
447}
448
449void
450HDLcd::renderPixel()
451{
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
456
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;
462 } 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 }
474 }
475
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);
503}
504
505PixelConverter
506HDLcd::pixelConverter() const
507{
508 ByteOrder byte_order(
509 pixel_format.big_endian ? BigEndianByteOrder : LittleEndianByteOrder);
510
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 }
526}
527
528void
529HDLcd::endFrame() {
530 assert(pixelBufferSize == 0);
531 assert(dmaPendingNum == 0);
532 assert(dmaBytesInFlight == 0);
533 assert(dmaDoneEventFree.size() == dmaDoneEventAll.size());
534
535 fb.copyIn(virtualDisplayBuffer, pixelConverter());
536
537 if (vnc)
538 vnc->setDirty();
539
540 if (enableCapture) {
541 if (!pic)
542 pic = simout.create(csprintf("%s.framebuffer.bmp", sys->name()), true);
543
544 assert(pic);
545 pic->seekp(0);
546 bmp.write(*pic);
547 }
548
549 // start the next frame
550 frameUnderway = false;
551 startFrame();
552}
553
554void
555HDLcd::dmaDone(DmaDoneEvent *event)
556{
557 const size_t transactionLength = event->getTransactionSize();
558 assert(pixelBufferSize + transactionLength < PIXEL_BUFFER_CAPACITY);
559 assert(dmaCurAddr <= dmaMaxAddr);
560
561 dmaDoneEventFree.push_back(event);
562 --dmaPendingNum;
563 assert(MAX_OUTSTANDING_DMA_REQ_CAPACITY - dmaDoneEventFree.size() ==
564 dmaPendingNum);
565
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());
579 }
580}
581
582void
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
9 * licensed hereunder. You may use the software subject to the license
10 * terms below provided that you ensure that this notice is replicated
11 * unmodified and in its entirety in all distributions of the software,
12 * modified or unmodified, in source code or in binary form.
13 *
14 * Redistribution and use in source and binary forms, with or without
15 * modification, are permitted provided that the following conditions are
16 * met: redistributions of source code must retain the above copyright
17 * notice, this list of conditions and the following disclaimer;
18 * redistributions in binary form must reproduce the above copyright
19 * notice, this list of conditions and the following disclaimer in the
20 * documentation and/or other materials provided with the distribution;
21 * neither the name of the copyright holders nor the names of its
22 * contributors may be used to endorse or promote products derived from
23 * this software without specific prior written permission.
24 *
25 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
26 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
27 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
28 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
29 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
30 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
31 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
32 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
33 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
34 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
35 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36 *
37 * Authors: Chris Emmons
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"
45#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"
51#include "sim/system.hh"
52
53using std::vector;
54
55
56// 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),
60 fb_base(0), fb_line_length(0), fb_line_count(0), fb_line_pitch(0),
61 bus_options(BUS_OPTIONS_RESETV),
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),
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;
81
82 for (int i = 0; i < MAX_OUTSTANDING_DMA_REQ_CAPACITY; ++i)
83 dmaDoneEventFree[i] = &dmaDoneEventAll[i];
84
85 if (vnc)
86 vnc->setFrameBuffer(&fb);
87}
88
89HDLcd::~HDLcd()
90{
91}
92
93// read registers and frame buffer
94Tick
95HDLcd::read(PacketPtr pkt)
96{
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 &&
104 pkt->getAddr() < pioAddr + pioSize &&
105 pkt->getSize() == 4);
106
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 }
184
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 &&
195 pkt->getAddr() < pioAddr + pioSize &&
196 pkt->getSize() == 4);
197
198 const uint32_t data = pkt->get<uint32_t>();
199 const Addr daddr = pkt->getAddr() - pioAddr;
200
201 DPRINTF(HDLcd, "write register BASE+%0x04x <= 0x%08x\n", daddr,
202 pkt->get<uint32_t>());
203
204 switch (daddr) {
205 case Version:
206 panic("HDLCD VERSION register is read-Only\n");
207 break;
208 case Int_RawStat:
209 int_rawstat = data;
210 break;
211 case Int_Clear:
212 int_clear = data;
213 break;
214 case Int_Mask:
215 int_mask = data;
216 break;
217 case Int_Status:
218 panic("HDLCD INT_STATUS register is read-Only\n");
219 break;
220 case Fb_Base:
221 fb_base = data;
222 DPRINTF(HDLcd, "HDLCD Frame Buffer located at addr 0x%08x\n", fb_base);
223 break;
224 case Fb_Line_Length:
225 fb_line_length = data;
226 DPRINTF(HDLcd, "HDLCD res = %d x %d\n", width(), height());
227 break;
228 case Fb_Line_Count:
229 fb_line_count = data;
230 DPRINTF(HDLcd, "HDLCD res = %d x %d\n", width(), height());
231 break;
232 case Fb_Line_Pitch:
233 fb_line_pitch = data;
234 break;
235 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;
248 case V_Sync:
249 v_sync = data;
250 break;
251 case V_Back_Porch:
252 v_back_porch = data;
253 break;
254 case V_Data:
255 v_data = data;
256 break;
257 case V_Front_Porch:
258 v_front_porch = data;
259 break;
260 case H_Sync:
261 h_sync = data;
262 break;
263 case H_Back_Porch:
264 h_back_porch = data;
265 break;
266 case H_Data:
267 h_data = data;
268 break;
269 case H_Front_Porch:
270 h_front_porch = data;
271 break;
272 case Polarities:
273 polarities = data;
274 break;
275 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;
290 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;
297 case Red_Select:
298 red_select = data;
299 break;
300 case Green_Select:
301 green_select = data;
302 break;
303 case Blue_Select:
304 blue_select = data;
305 break;
306 default:
307 panic("Tried to write HDLCD register that doesn't exist\n", daddr);
308 break;
309 }
310
311 pkt->makeAtomicResponse();
312 return pioDelay;
313}
314
315void
316HDLcd::updateVideoParams(bool unserializing = false)
317{
318 const uint16_t bpp M5_VAR_USED = bytesPerPixel() << 3;
319
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);
344 }
345
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);
364}
365
366void
367HDLcd::startFrame()
368{
369 // 0. Check that we are in the appropriate state
370 assert(!frameUnderway);
371 if (!command.enable)
372 return;
373 DPRINTF(HDLcd, "Frame read started\n");
374 if (doUpdateParams) {
375 updateVideoParams();
376 doUpdateParams = false;
377 }
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
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();
396
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);
404}
405
406void
407HDLcd::fillPixelBuffer()
408{
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 }
447}
448
449void
450HDLcd::renderPixel()
451{
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
456
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;
462 } 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 }
474 }
475
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);
503}
504
505PixelConverter
506HDLcd::pixelConverter() const
507{
508 ByteOrder byte_order(
509 pixel_format.big_endian ? BigEndianByteOrder : LittleEndianByteOrder);
510
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 }
526}
527
528void
529HDLcd::endFrame() {
530 assert(pixelBufferSize == 0);
531 assert(dmaPendingNum == 0);
532 assert(dmaBytesInFlight == 0);
533 assert(dmaDoneEventFree.size() == dmaDoneEventAll.size());
534
535 fb.copyIn(virtualDisplayBuffer, pixelConverter());
536
537 if (vnc)
538 vnc->setDirty();
539
540 if (enableCapture) {
541 if (!pic)
542 pic = simout.create(csprintf("%s.framebuffer.bmp", sys->name()), true);
543
544 assert(pic);
545 pic->seekp(0);
546 bmp.write(*pic);
547 }
548
549 // start the next frame
550 frameUnderway = false;
551 startFrame();
552}
553
554void
555HDLcd::dmaDone(DmaDoneEvent *event)
556{
557 const size_t transactionLength = event->getTransactionSize();
558 assert(pixelBufferSize + transactionLength < PIXEL_BUFFER_CAPACITY);
559 assert(dmaCurAddr <= dmaMaxAddr);
560
561 dmaDoneEventFree.push_back(event);
562 --dmaPendingNum;
563 assert(MAX_OUTSTANDING_DMA_REQ_CAPACITY - dmaDoneEventFree.size() ==
564 dmaPendingNum);
565
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());
579 }
580}
581
582void
583HDLcd::serialize(std::ostream &os)
583HDLcd::serialize(CheckpointOut &cp) const
584{
585 DPRINTF(HDLcd, "Serializing ARM HDLCD\n");
586
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);
597
598 SERIALIZE_SCALAR(fb_base);
599 SERIALIZE_SCALAR(fb_line_length);
600
601 const uint32_t fb_line_count_serial = fb_line_count;
602 SERIALIZE_SCALAR(fb_line_count_serial);
603
604 SERIALIZE_SCALAR(fb_line_pitch);
605
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);
636
637 SERIALIZE_SCALAR(frameReadStartTime);
638 SERIALIZE_SCALAR(dmaStartAddr);
639 SERIALIZE_SCALAR(dmaCurAddr);
640 SERIALIZE_SCALAR(dmaMaxAddr);
641 SERIALIZE_SCALAR(dmaPendingNum);
642 SERIALIZE_SCALAR(frameUnderrun);
643
584{
585 DPRINTF(HDLcd, "Serializing ARM HDLCD\n");
586
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);
597
598 SERIALIZE_SCALAR(fb_base);
599 SERIALIZE_SCALAR(fb_line_length);
600
601 const uint32_t fb_line_count_serial = fb_line_count;
602 SERIALIZE_SCALAR(fb_line_count_serial);
603
604 SERIALIZE_SCALAR(fb_line_pitch);
605
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);
636
637 SERIALIZE_SCALAR(frameReadStartTime);
638 SERIALIZE_SCALAR(dmaStartAddr);
639 SERIALIZE_SCALAR(dmaCurAddr);
640 SERIALIZE_SCALAR(dmaMaxAddr);
641 SERIALIZE_SCALAR(dmaPendingNum);
642 SERIALIZE_SCALAR(frameUnderrun);
643
644 arrayParamOut(os, "virtualDisplayBuffer", virtualDisplayBuffer);
644 arrayParamOut(cp, "virtualDisplayBuffer", virtualDisplayBuffer);
645
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 }
645
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(os, "dma_done_event_tick", dma_done_event_tick);
682 arrayParamOut(os, "dma_done_event_burst_length", dma_done_event_burst_len);
681 arrayParamOut(cp, "dma_done_event_tick", dma_done_event_tick);
682 arrayParamOut(cp, "dma_done_event_burst_length", dma_done_event_burst_len);
683}
684
685void
683}
684
685void
686HDLcd::unserialize(Checkpoint *cp, const std::string &section)
686HDLcd::unserialize(CheckpointIn &cp)
687{
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;
695
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
687{
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;
695
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, section, "virtualDisplayBuffer", virtualDisplayBuffer);
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);
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, section, "dma_done_event_tick", dma_done_event_tick);
787 arrayParamIn(cp, section, "dma_done_event_burst_length", dma_done_event_burst_len);
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 }
805}
806
807void
808HDLcd::generateInterrupt()
809{
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 }
819}
820
821AddrRangeList
822HDLcd::getAddrRanges() const
823{
824 AddrRangeList ranges;
825 ranges.push_back(RangeSize(pioAddr, pioSize));
826 return ranges;
827}
828
829HDLcd *
830HDLcdParams::create()
831{
832 return new HDLcd(this);
833}
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 }
805}
806
807void
808HDLcd::generateInterrupt()
809{
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 }
819}
820
821AddrRangeList
822HDLcd::getAddrRanges() const
823{
824 AddrRangeList ranges;
825 ranges.push_back(RangeSize(pioAddr, pioSize));
826 return ranges;
827}
828
829HDLcd *
830HDLcdParams::create()
831{
832 return new HDLcd(this);
833}