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}