|
1 /* |
|
2 * Intel XScale PXA255/270 LCDC emulation. |
|
3 * |
|
4 * Copyright (c) 2006 Openedhand Ltd. |
|
5 * Written by Andrzej Zaborowski <balrog@zabor.org> |
|
6 * |
|
7 * This code is licensed under the GPLv2. |
|
8 */ |
|
9 |
|
10 #include "hw.h" |
|
11 #include "gui.h" |
|
12 #include "pxa.h" |
|
13 #include "pixel_ops.h" |
|
14 /* FIXME: For graphic_rotate. Should probably be done in common code. */ |
|
15 #include "sysemu.h" |
|
16 |
|
17 typedef void (*drawfn)(uint32_t *, uint8_t *, const uint8_t *, int, int); |
|
18 |
|
19 struct pxa2xx_lcdc_s { |
|
20 qemu_irq irq; |
|
21 int irqlevel; |
|
22 |
|
23 int invalidated; |
|
24 DisplayState *ds; |
|
25 drawfn *line_fn[2]; |
|
26 int dest_width; |
|
27 int xres, yres; |
|
28 int pal_for; |
|
29 int transp; |
|
30 enum { |
|
31 pxa_lcdc_2bpp = 1, |
|
32 pxa_lcdc_4bpp = 2, |
|
33 pxa_lcdc_8bpp = 3, |
|
34 pxa_lcdc_16bpp = 4, |
|
35 pxa_lcdc_18bpp = 5, |
|
36 pxa_lcdc_18pbpp = 6, |
|
37 pxa_lcdc_19bpp = 7, |
|
38 pxa_lcdc_19pbpp = 8, |
|
39 pxa_lcdc_24bpp = 9, |
|
40 pxa_lcdc_25bpp = 10, |
|
41 } bpp; |
|
42 |
|
43 uint32_t control[6]; |
|
44 uint32_t status[2]; |
|
45 uint32_t ovl1c[2]; |
|
46 uint32_t ovl2c[2]; |
|
47 uint32_t ccr; |
|
48 uint32_t cmdcr; |
|
49 uint32_t trgbr; |
|
50 uint32_t tcr; |
|
51 uint32_t liidr; |
|
52 uint8_t bscntr; |
|
53 |
|
54 struct { |
|
55 target_phys_addr_t branch; |
|
56 int up; |
|
57 uint8_t palette[1024]; |
|
58 uint8_t pbuffer[1024]; |
|
59 void (*redraw)(struct pxa2xx_lcdc_s *s, uint8_t *fb, |
|
60 int *miny, int *maxy); |
|
61 |
|
62 target_phys_addr_t descriptor; |
|
63 target_phys_addr_t source; |
|
64 uint32_t id; |
|
65 uint32_t command; |
|
66 } dma_ch[7]; |
|
67 |
|
68 qemu_irq vsync_cb; |
|
69 int orientation; |
|
70 }; |
|
71 |
|
72 struct __attribute__ ((__packed__)) pxa_frame_descriptor_s { |
|
73 uint32_t fdaddr; |
|
74 uint32_t fsaddr; |
|
75 uint32_t fidr; |
|
76 uint32_t ldcmd; |
|
77 }; |
|
78 |
|
79 #define LCCR0 0x000 /* LCD Controller Control register 0 */ |
|
80 #define LCCR1 0x004 /* LCD Controller Control register 1 */ |
|
81 #define LCCR2 0x008 /* LCD Controller Control register 2 */ |
|
82 #define LCCR3 0x00c /* LCD Controller Control register 3 */ |
|
83 #define LCCR4 0x010 /* LCD Controller Control register 4 */ |
|
84 #define LCCR5 0x014 /* LCD Controller Control register 5 */ |
|
85 |
|
86 #define FBR0 0x020 /* DMA Channel 0 Frame Branch register */ |
|
87 #define FBR1 0x024 /* DMA Channel 1 Frame Branch register */ |
|
88 #define FBR2 0x028 /* DMA Channel 2 Frame Branch register */ |
|
89 #define FBR3 0x02c /* DMA Channel 3 Frame Branch register */ |
|
90 #define FBR4 0x030 /* DMA Channel 4 Frame Branch register */ |
|
91 #define FBR5 0x110 /* DMA Channel 5 Frame Branch register */ |
|
92 #define FBR6 0x114 /* DMA Channel 6 Frame Branch register */ |
|
93 |
|
94 #define LCSR1 0x034 /* LCD Controller Status register 1 */ |
|
95 #define LCSR0 0x038 /* LCD Controller Status register 0 */ |
|
96 #define LIIDR 0x03c /* LCD Controller Interrupt ID register */ |
|
97 |
|
98 #define TRGBR 0x040 /* TMED RGB Seed register */ |
|
99 #define TCR 0x044 /* TMED Control register */ |
|
100 |
|
101 #define OVL1C1 0x050 /* Overlay 1 Control register 1 */ |
|
102 #define OVL1C2 0x060 /* Overlay 1 Control register 2 */ |
|
103 #define OVL2C1 0x070 /* Overlay 2 Control register 1 */ |
|
104 #define OVL2C2 0x080 /* Overlay 2 Control register 2 */ |
|
105 #define CCR 0x090 /* Cursor Control register */ |
|
106 |
|
107 #define CMDCR 0x100 /* Command Control register */ |
|
108 #define PRSR 0x104 /* Panel Read Status register */ |
|
109 |
|
110 #define PXA_LCDDMA_CHANS 7 |
|
111 #define DMA_FDADR 0x00 /* Frame Descriptor Address register */ |
|
112 #define DMA_FSADR 0x04 /* Frame Source Address register */ |
|
113 #define DMA_FIDR 0x08 /* Frame ID register */ |
|
114 #define DMA_LDCMD 0x0c /* Command register */ |
|
115 |
|
116 /* LCD Buffer Strength Control register */ |
|
117 #define BSCNTR 0x04000054 |
|
118 |
|
119 /* Bitfield masks */ |
|
120 #define LCCR0_ENB (1 << 0) |
|
121 #define LCCR0_CMS (1 << 1) |
|
122 #define LCCR0_SDS (1 << 2) |
|
123 #define LCCR0_LDM (1 << 3) |
|
124 #define LCCR0_SOFM0 (1 << 4) |
|
125 #define LCCR0_IUM (1 << 5) |
|
126 #define LCCR0_EOFM0 (1 << 6) |
|
127 #define LCCR0_PAS (1 << 7) |
|
128 #define LCCR0_DPD (1 << 9) |
|
129 #define LCCR0_DIS (1 << 10) |
|
130 #define LCCR0_QDM (1 << 11) |
|
131 #define LCCR0_PDD (0xff << 12) |
|
132 #define LCCR0_BSM0 (1 << 20) |
|
133 #define LCCR0_OUM (1 << 21) |
|
134 #define LCCR0_LCDT (1 << 22) |
|
135 #define LCCR0_RDSTM (1 << 23) |
|
136 #define LCCR0_CMDIM (1 << 24) |
|
137 #define LCCR0_OUC (1 << 25) |
|
138 #define LCCR0_LDDALT (1 << 26) |
|
139 #define LCCR1_PPL(x) ((x) & 0x3ff) |
|
140 #define LCCR2_LPP(x) ((x) & 0x3ff) |
|
141 #define LCCR3_API (15 << 16) |
|
142 #define LCCR3_BPP(x) ((((x) >> 24) & 7) | (((x) >> 26) & 8)) |
|
143 #define LCCR3_PDFOR(x) (((x) >> 30) & 3) |
|
144 #define LCCR4_K1(x) (((x) >> 0) & 7) |
|
145 #define LCCR4_K2(x) (((x) >> 3) & 7) |
|
146 #define LCCR4_K3(x) (((x) >> 6) & 7) |
|
147 #define LCCR4_PALFOR(x) (((x) >> 15) & 3) |
|
148 #define LCCR5_SOFM(ch) (1 << (ch - 1)) |
|
149 #define LCCR5_EOFM(ch) (1 << (ch + 7)) |
|
150 #define LCCR5_BSM(ch) (1 << (ch + 15)) |
|
151 #define LCCR5_IUM(ch) (1 << (ch + 23)) |
|
152 #define OVLC1_EN (1 << 31) |
|
153 #define CCR_CEN (1 << 31) |
|
154 #define FBR_BRA (1 << 0) |
|
155 #define FBR_BINT (1 << 1) |
|
156 #define FBR_SRCADDR (0xfffffff << 4) |
|
157 #define LCSR0_LDD (1 << 0) |
|
158 #define LCSR0_SOF0 (1 << 1) |
|
159 #define LCSR0_BER (1 << 2) |
|
160 #define LCSR0_ABC (1 << 3) |
|
161 #define LCSR0_IU0 (1 << 4) |
|
162 #define LCSR0_IU1 (1 << 5) |
|
163 #define LCSR0_OU (1 << 6) |
|
164 #define LCSR0_QD (1 << 7) |
|
165 #define LCSR0_EOF0 (1 << 8) |
|
166 #define LCSR0_BS0 (1 << 9) |
|
167 #define LCSR0_SINT (1 << 10) |
|
168 #define LCSR0_RDST (1 << 11) |
|
169 #define LCSR0_CMDINT (1 << 12) |
|
170 #define LCSR0_BERCH(x) (((x) & 7) << 28) |
|
171 #define LCSR1_SOF(ch) (1 << (ch - 1)) |
|
172 #define LCSR1_EOF(ch) (1 << (ch + 7)) |
|
173 #define LCSR1_BS(ch) (1 << (ch + 15)) |
|
174 #define LCSR1_IU(ch) (1 << (ch + 23)) |
|
175 #define LDCMD_LENGTH(x) ((x) & 0x001ffffc) |
|
176 #define LDCMD_EOFINT (1 << 21) |
|
177 #define LDCMD_SOFINT (1 << 22) |
|
178 #define LDCMD_PAL (1 << 26) |
|
179 |
|
180 /* Route internal interrupt lines to the global IC */ |
|
181 static void pxa2xx_lcdc_int_update(struct pxa2xx_lcdc_s *s) |
|
182 { |
|
183 int level = 0; |
|
184 level |= (s->status[0] & LCSR0_LDD) && !(s->control[0] & LCCR0_LDM); |
|
185 level |= (s->status[0] & LCSR0_SOF0) && !(s->control[0] & LCCR0_SOFM0); |
|
186 level |= (s->status[0] & LCSR0_IU0) && !(s->control[0] & LCCR0_IUM); |
|
187 level |= (s->status[0] & LCSR0_IU1) && !(s->control[5] & LCCR5_IUM(1)); |
|
188 level |= (s->status[0] & LCSR0_OU) && !(s->control[0] & LCCR0_OUM); |
|
189 level |= (s->status[0] & LCSR0_QD) && !(s->control[0] & LCCR0_QDM); |
|
190 level |= (s->status[0] & LCSR0_EOF0) && !(s->control[0] & LCCR0_EOFM0); |
|
191 level |= (s->status[0] & LCSR0_BS0) && !(s->control[0] & LCCR0_BSM0); |
|
192 level |= (s->status[0] & LCSR0_RDST) && !(s->control[0] & LCCR0_RDSTM); |
|
193 level |= (s->status[0] & LCSR0_CMDINT) && !(s->control[0] & LCCR0_CMDIM); |
|
194 level |= (s->status[1] & ~s->control[5]); |
|
195 |
|
196 qemu_set_irq(s->irq, !!level); |
|
197 s->irqlevel = level; |
|
198 } |
|
199 |
|
200 /* Set Branch Status interrupt high and poke associated registers */ |
|
201 static inline void pxa2xx_dma_bs_set(struct pxa2xx_lcdc_s *s, int ch) |
|
202 { |
|
203 int unmasked; |
|
204 if (ch == 0) { |
|
205 s->status[0] |= LCSR0_BS0; |
|
206 unmasked = !(s->control[0] & LCCR0_BSM0); |
|
207 } else { |
|
208 s->status[1] |= LCSR1_BS(ch); |
|
209 unmasked = !(s->control[5] & LCCR5_BSM(ch)); |
|
210 } |
|
211 |
|
212 if (unmasked) { |
|
213 if (s->irqlevel) |
|
214 s->status[0] |= LCSR0_SINT; |
|
215 else |
|
216 s->liidr = s->dma_ch[ch].id; |
|
217 } |
|
218 } |
|
219 |
|
220 /* Set Start Of Frame Status interrupt high and poke associated registers */ |
|
221 static inline void pxa2xx_dma_sof_set(struct pxa2xx_lcdc_s *s, int ch) |
|
222 { |
|
223 int unmasked; |
|
224 if (!(s->dma_ch[ch].command & LDCMD_SOFINT)) |
|
225 return; |
|
226 |
|
227 if (ch == 0) { |
|
228 s->status[0] |= LCSR0_SOF0; |
|
229 unmasked = !(s->control[0] & LCCR0_SOFM0); |
|
230 } else { |
|
231 s->status[1] |= LCSR1_SOF(ch); |
|
232 unmasked = !(s->control[5] & LCCR5_SOFM(ch)); |
|
233 } |
|
234 |
|
235 if (unmasked) { |
|
236 if (s->irqlevel) |
|
237 s->status[0] |= LCSR0_SINT; |
|
238 else |
|
239 s->liidr = s->dma_ch[ch].id; |
|
240 } |
|
241 } |
|
242 |
|
243 /* Set End Of Frame Status interrupt high and poke associated registers */ |
|
244 static inline void pxa2xx_dma_eof_set(struct pxa2xx_lcdc_s *s, int ch) |
|
245 { |
|
246 int unmasked; |
|
247 if (!(s->dma_ch[ch].command & LDCMD_EOFINT)) |
|
248 return; |
|
249 |
|
250 if (ch == 0) { |
|
251 s->status[0] |= LCSR0_EOF0; |
|
252 unmasked = !(s->control[0] & LCCR0_EOFM0); |
|
253 } else { |
|
254 s->status[1] |= LCSR1_EOF(ch); |
|
255 unmasked = !(s->control[5] & LCCR5_EOFM(ch)); |
|
256 } |
|
257 |
|
258 if (unmasked) { |
|
259 if (s->irqlevel) |
|
260 s->status[0] |= LCSR0_SINT; |
|
261 else |
|
262 s->liidr = s->dma_ch[ch].id; |
|
263 } |
|
264 } |
|
265 |
|
266 /* Set Bus Error Status interrupt high and poke associated registers */ |
|
267 static inline void pxa2xx_dma_ber_set(struct pxa2xx_lcdc_s *s, int ch) |
|
268 { |
|
269 s->status[0] |= LCSR0_BERCH(ch) | LCSR0_BER; |
|
270 if (s->irqlevel) |
|
271 s->status[0] |= LCSR0_SINT; |
|
272 else |
|
273 s->liidr = s->dma_ch[ch].id; |
|
274 } |
|
275 |
|
276 /* Set Read Status interrupt high and poke associated registers */ |
|
277 static inline void pxa2xx_dma_rdst_set(struct pxa2xx_lcdc_s *s) |
|
278 { |
|
279 s->status[0] |= LCSR0_RDST; |
|
280 if (s->irqlevel && !(s->control[0] & LCCR0_RDSTM)) |
|
281 s->status[0] |= LCSR0_SINT; |
|
282 } |
|
283 |
|
284 /* Load new Frame Descriptors from DMA */ |
|
285 static void pxa2xx_descriptor_load(struct pxa2xx_lcdc_s *s) |
|
286 { |
|
287 struct pxa_frame_descriptor_s *desc[PXA_LCDDMA_CHANS]; |
|
288 target_phys_addr_t descptr; |
|
289 int i; |
|
290 |
|
291 for (i = 0; i < PXA_LCDDMA_CHANS; i ++) { |
|
292 desc[i] = 0; |
|
293 s->dma_ch[i].source = 0; |
|
294 |
|
295 if (!s->dma_ch[i].up) |
|
296 continue; |
|
297 |
|
298 if (s->dma_ch[i].branch & FBR_BRA) { |
|
299 descptr = s->dma_ch[i].branch & FBR_SRCADDR; |
|
300 if (s->dma_ch[i].branch & FBR_BINT) |
|
301 pxa2xx_dma_bs_set(s, i); |
|
302 s->dma_ch[i].branch &= ~FBR_BRA; |
|
303 } else |
|
304 descptr = s->dma_ch[i].descriptor; |
|
305 |
|
306 if (!(descptr >= PXA2XX_SDRAM_BASE && descptr + |
|
307 sizeof(*desc[i]) <= PXA2XX_SDRAM_BASE + phys_ram_size)) |
|
308 continue; |
|
309 |
|
310 descptr -= PXA2XX_SDRAM_BASE; |
|
311 /* FIXME: This is broken if it spans multiple RAM regions. */ |
|
312 desc[i] = (struct pxa_frame_descriptor_s *) host_ram_addr(descptr); |
|
313 s->dma_ch[i].descriptor = desc[i]->fdaddr; |
|
314 s->dma_ch[i].source = desc[i]->fsaddr; |
|
315 s->dma_ch[i].id = desc[i]->fidr; |
|
316 s->dma_ch[i].command = desc[i]->ldcmd; |
|
317 } |
|
318 } |
|
319 |
|
320 static uint32_t pxa2xx_lcdc_read(void *opaque, target_phys_addr_t offset) |
|
321 { |
|
322 struct pxa2xx_lcdc_s *s = (struct pxa2xx_lcdc_s *) opaque; |
|
323 int ch; |
|
324 |
|
325 switch (offset) { |
|
326 case LCCR0: |
|
327 return s->control[0]; |
|
328 case LCCR1: |
|
329 return s->control[1]; |
|
330 case LCCR2: |
|
331 return s->control[2]; |
|
332 case LCCR3: |
|
333 return s->control[3]; |
|
334 case LCCR4: |
|
335 return s->control[4]; |
|
336 case LCCR5: |
|
337 return s->control[5]; |
|
338 |
|
339 case OVL1C1: |
|
340 return s->ovl1c[0]; |
|
341 case OVL1C2: |
|
342 return s->ovl1c[1]; |
|
343 case OVL2C1: |
|
344 return s->ovl2c[0]; |
|
345 case OVL2C2: |
|
346 return s->ovl2c[1]; |
|
347 |
|
348 case CCR: |
|
349 return s->ccr; |
|
350 |
|
351 case CMDCR: |
|
352 return s->cmdcr; |
|
353 |
|
354 case TRGBR: |
|
355 return s->trgbr; |
|
356 case TCR: |
|
357 return s->tcr; |
|
358 |
|
359 case 0x200 ... 0x1000: /* DMA per-channel registers */ |
|
360 ch = (offset - 0x200) >> 4; |
|
361 if (!(ch >= 0 && ch < PXA_LCDDMA_CHANS)) |
|
362 goto fail; |
|
363 |
|
364 switch (offset & 0xf) { |
|
365 case DMA_FDADR: |
|
366 return s->dma_ch[ch].descriptor; |
|
367 case DMA_FSADR: |
|
368 return s->dma_ch[ch].source; |
|
369 case DMA_FIDR: |
|
370 return s->dma_ch[ch].id; |
|
371 case DMA_LDCMD: |
|
372 return s->dma_ch[ch].command; |
|
373 default: |
|
374 goto fail; |
|
375 } |
|
376 |
|
377 case FBR0: |
|
378 return s->dma_ch[0].branch; |
|
379 case FBR1: |
|
380 return s->dma_ch[1].branch; |
|
381 case FBR2: |
|
382 return s->dma_ch[2].branch; |
|
383 case FBR3: |
|
384 return s->dma_ch[3].branch; |
|
385 case FBR4: |
|
386 return s->dma_ch[4].branch; |
|
387 case FBR5: |
|
388 return s->dma_ch[5].branch; |
|
389 case FBR6: |
|
390 return s->dma_ch[6].branch; |
|
391 |
|
392 case BSCNTR: |
|
393 return s->bscntr; |
|
394 |
|
395 case PRSR: |
|
396 return 0; |
|
397 |
|
398 case LCSR0: |
|
399 return s->status[0]; |
|
400 case LCSR1: |
|
401 return s->status[1]; |
|
402 case LIIDR: |
|
403 return s->liidr; |
|
404 |
|
405 default: |
|
406 fail: |
|
407 cpu_abort(cpu_single_env, |
|
408 "%s: Bad offset " REG_FMT "\n", __FUNCTION__, offset); |
|
409 } |
|
410 |
|
411 return 0; |
|
412 } |
|
413 |
|
414 static void pxa2xx_lcdc_write(void *opaque, |
|
415 target_phys_addr_t offset, uint32_t value) |
|
416 { |
|
417 struct pxa2xx_lcdc_s *s = (struct pxa2xx_lcdc_s *) opaque; |
|
418 int ch; |
|
419 |
|
420 switch (offset) { |
|
421 case LCCR0: |
|
422 /* ACK Quick Disable done */ |
|
423 if ((s->control[0] & LCCR0_ENB) && !(value & LCCR0_ENB)) |
|
424 s->status[0] |= LCSR0_QD; |
|
425 |
|
426 if (!(s->control[0] & LCCR0_LCDT) && (value & LCCR0_LCDT)) |
|
427 printf("%s: internal frame buffer unsupported\n", __FUNCTION__); |
|
428 |
|
429 if ((s->control[3] & LCCR3_API) && |
|
430 (value & LCCR0_ENB) && !(value & LCCR0_LCDT)) |
|
431 s->status[0] |= LCSR0_ABC; |
|
432 |
|
433 s->control[0] = value & 0x07ffffff; |
|
434 pxa2xx_lcdc_int_update(s); |
|
435 |
|
436 s->dma_ch[0].up = !!(value & LCCR0_ENB); |
|
437 s->dma_ch[1].up = (s->ovl1c[0] & OVLC1_EN) || (value & LCCR0_SDS); |
|
438 break; |
|
439 |
|
440 case LCCR1: |
|
441 s->control[1] = value; |
|
442 break; |
|
443 |
|
444 case LCCR2: |
|
445 s->control[2] = value; |
|
446 break; |
|
447 |
|
448 case LCCR3: |
|
449 s->control[3] = value & 0xefffffff; |
|
450 s->bpp = LCCR3_BPP(value); |
|
451 break; |
|
452 |
|
453 case LCCR4: |
|
454 s->control[4] = value & 0x83ff81ff; |
|
455 break; |
|
456 |
|
457 case LCCR5: |
|
458 s->control[5] = value & 0x3f3f3f3f; |
|
459 break; |
|
460 |
|
461 case OVL1C1: |
|
462 if (!(s->ovl1c[0] & OVLC1_EN) && (value & OVLC1_EN)) |
|
463 printf("%s: Overlay 1 not supported\n", __FUNCTION__); |
|
464 |
|
465 s->ovl1c[0] = value & 0x80ffffff; |
|
466 s->dma_ch[1].up = (value & OVLC1_EN) || (s->control[0] & LCCR0_SDS); |
|
467 break; |
|
468 |
|
469 case OVL1C2: |
|
470 s->ovl1c[1] = value & 0x000fffff; |
|
471 break; |
|
472 |
|
473 case OVL2C1: |
|
474 if (!(s->ovl2c[0] & OVLC1_EN) && (value & OVLC1_EN)) |
|
475 printf("%s: Overlay 2 not supported\n", __FUNCTION__); |
|
476 |
|
477 s->ovl2c[0] = value & 0x80ffffff; |
|
478 s->dma_ch[2].up = !!(value & OVLC1_EN); |
|
479 s->dma_ch[3].up = !!(value & OVLC1_EN); |
|
480 s->dma_ch[4].up = !!(value & OVLC1_EN); |
|
481 break; |
|
482 |
|
483 case OVL2C2: |
|
484 s->ovl2c[1] = value & 0x007fffff; |
|
485 break; |
|
486 |
|
487 case CCR: |
|
488 if (!(s->ccr & CCR_CEN) && (value & CCR_CEN)) |
|
489 printf("%s: Hardware cursor unimplemented\n", __FUNCTION__); |
|
490 |
|
491 s->ccr = value & 0x81ffffe7; |
|
492 s->dma_ch[5].up = !!(value & CCR_CEN); |
|
493 break; |
|
494 |
|
495 case CMDCR: |
|
496 s->cmdcr = value & 0xff; |
|
497 break; |
|
498 |
|
499 case TRGBR: |
|
500 s->trgbr = value & 0x00ffffff; |
|
501 break; |
|
502 |
|
503 case TCR: |
|
504 s->tcr = value & 0x7fff; |
|
505 break; |
|
506 |
|
507 case 0x200 ... 0x1000: /* DMA per-channel registers */ |
|
508 ch = (offset - 0x200) >> 4; |
|
509 if (!(ch >= 0 && ch < PXA_LCDDMA_CHANS)) |
|
510 goto fail; |
|
511 |
|
512 switch (offset & 0xf) { |
|
513 case DMA_FDADR: |
|
514 s->dma_ch[ch].descriptor = value & 0xfffffff0; |
|
515 break; |
|
516 |
|
517 default: |
|
518 goto fail; |
|
519 } |
|
520 break; |
|
521 |
|
522 case FBR0: |
|
523 s->dma_ch[0].branch = value & 0xfffffff3; |
|
524 break; |
|
525 case FBR1: |
|
526 s->dma_ch[1].branch = value & 0xfffffff3; |
|
527 break; |
|
528 case FBR2: |
|
529 s->dma_ch[2].branch = value & 0xfffffff3; |
|
530 break; |
|
531 case FBR3: |
|
532 s->dma_ch[3].branch = value & 0xfffffff3; |
|
533 break; |
|
534 case FBR4: |
|
535 s->dma_ch[4].branch = value & 0xfffffff3; |
|
536 break; |
|
537 case FBR5: |
|
538 s->dma_ch[5].branch = value & 0xfffffff3; |
|
539 break; |
|
540 case FBR6: |
|
541 s->dma_ch[6].branch = value & 0xfffffff3; |
|
542 break; |
|
543 |
|
544 case BSCNTR: |
|
545 s->bscntr = value & 0xf; |
|
546 break; |
|
547 |
|
548 case PRSR: |
|
549 break; |
|
550 |
|
551 case LCSR0: |
|
552 s->status[0] &= ~(value & 0xfff); |
|
553 if (value & LCSR0_BER) |
|
554 s->status[0] &= ~LCSR0_BERCH(7); |
|
555 break; |
|
556 |
|
557 case LCSR1: |
|
558 s->status[1] &= ~(value & 0x3e3f3f); |
|
559 break; |
|
560 |
|
561 default: |
|
562 fail: |
|
563 cpu_abort(cpu_single_env, |
|
564 "%s: Bad offset " REG_FMT "\n", __FUNCTION__, offset); |
|
565 } |
|
566 } |
|
567 |
|
568 static CPUReadMemoryFunc *pxa2xx_lcdc_readfn[] = { |
|
569 pxa2xx_lcdc_read, |
|
570 pxa2xx_lcdc_read, |
|
571 pxa2xx_lcdc_read |
|
572 }; |
|
573 |
|
574 static CPUWriteMemoryFunc *pxa2xx_lcdc_writefn[] = { |
|
575 pxa2xx_lcdc_write, |
|
576 pxa2xx_lcdc_write, |
|
577 pxa2xx_lcdc_write |
|
578 }; |
|
579 |
|
580 /* Load new palette for a given DMA channel, convert to internal format */ |
|
581 static void pxa2xx_palette_parse(struct pxa2xx_lcdc_s *s, int ch, int bpp) |
|
582 { |
|
583 int i, n, format, r, g, b, alpha; |
|
584 uint32_t *dest, *src; |
|
585 s->pal_for = LCCR4_PALFOR(s->control[4]); |
|
586 format = s->pal_for; |
|
587 |
|
588 switch (bpp) { |
|
589 case pxa_lcdc_2bpp: |
|
590 n = 4; |
|
591 break; |
|
592 case pxa_lcdc_4bpp: |
|
593 n = 16; |
|
594 break; |
|
595 case pxa_lcdc_8bpp: |
|
596 n = 256; |
|
597 break; |
|
598 default: |
|
599 format = 0; |
|
600 return; |
|
601 } |
|
602 |
|
603 src = (uint32_t *) s->dma_ch[ch].pbuffer; |
|
604 dest = (uint32_t *) s->dma_ch[ch].palette; |
|
605 alpha = r = g = b = 0; |
|
606 |
|
607 for (i = 0; i < n; i ++) { |
|
608 switch (format) { |
|
609 case 0: /* 16 bpp, no transparency */ |
|
610 alpha = 0; |
|
611 if (s->control[0] & LCCR0_CMS) |
|
612 r = g = b = *src & 0xff; |
|
613 else { |
|
614 r = (*src & 0xf800) >> 8; |
|
615 g = (*src & 0x07e0) >> 3; |
|
616 b = (*src & 0x001f) << 3; |
|
617 } |
|
618 break; |
|
619 case 1: /* 16 bpp plus transparency */ |
|
620 alpha = *src & (1 << 24); |
|
621 if (s->control[0] & LCCR0_CMS) |
|
622 r = g = b = *src & 0xff; |
|
623 else { |
|
624 r = (*src & 0xf800) >> 8; |
|
625 g = (*src & 0x07e0) >> 3; |
|
626 b = (*src & 0x001f) << 3; |
|
627 } |
|
628 break; |
|
629 case 2: /* 18 bpp plus transparency */ |
|
630 alpha = *src & (1 << 24); |
|
631 if (s->control[0] & LCCR0_CMS) |
|
632 r = g = b = *src & 0xff; |
|
633 else { |
|
634 r = (*src & 0xf80000) >> 16; |
|
635 g = (*src & 0x00fc00) >> 8; |
|
636 b = (*src & 0x0000f8); |
|
637 } |
|
638 break; |
|
639 case 3: /* 24 bpp plus transparency */ |
|
640 alpha = *src & (1 << 24); |
|
641 if (s->control[0] & LCCR0_CMS) |
|
642 r = g = b = *src & 0xff; |
|
643 else { |
|
644 r = (*src & 0xff0000) >> 16; |
|
645 g = (*src & 0x00ff00) >> 8; |
|
646 b = (*src & 0x0000ff); |
|
647 } |
|
648 break; |
|
649 } |
|
650 switch (ds_get_bits_per_pixel(s->ds)) { |
|
651 case 8: |
|
652 *dest = rgb_to_pixel8(r, g, b) | alpha; |
|
653 break; |
|
654 case 15: |
|
655 *dest = rgb_to_pixel15(r, g, b) | alpha; |
|
656 break; |
|
657 case 16: |
|
658 *dest = rgb_to_pixel16(r, g, b) | alpha; |
|
659 break; |
|
660 case 24: |
|
661 *dest = rgb_to_pixel24(r, g, b) | alpha; |
|
662 break; |
|
663 case 32: |
|
664 *dest = rgb_to_pixel32(r, g, b) | alpha; |
|
665 break; |
|
666 } |
|
667 src ++; |
|
668 dest ++; |
|
669 } |
|
670 } |
|
671 |
|
672 static void pxa2xx_lcdc_dma0_redraw_horiz(struct pxa2xx_lcdc_s *s, |
|
673 uint8_t *fb, int *miny, int *maxy) |
|
674 { |
|
675 int y, src_width, dest_width, dirty[2]; |
|
676 uint8_t *src, *dest; |
|
677 ram_addr_t x, addr, new_addr, start, end; |
|
678 drawfn fn = 0; |
|
679 if (s->dest_width) |
|
680 fn = s->line_fn[s->transp][s->bpp]; |
|
681 if (!fn) |
|
682 return; |
|
683 |
|
684 src = fb; |
|
685 src_width = (s->xres + 3) & ~3; /* Pad to a 4 pixels multiple */ |
|
686 if (s->bpp == pxa_lcdc_19pbpp || s->bpp == pxa_lcdc_18pbpp) |
|
687 src_width *= 3; |
|
688 else if (s->bpp > pxa_lcdc_16bpp) |
|
689 src_width *= 4; |
|
690 else if (s->bpp > pxa_lcdc_8bpp) |
|
691 src_width *= 2; |
|
692 |
|
693 dest = ds_get_data(s->ds); |
|
694 dest_width = s->xres * s->dest_width; |
|
695 |
|
696 addr = ram_offset_from_host(fb); |
|
697 start = addr + s->yres * src_width; |
|
698 end = addr; |
|
699 dirty[0] = dirty[1] = cpu_physical_memory_get_dirty(addr, VGA_DIRTY_FLAG); |
|
700 for (y = 0; y < s->yres; y ++) { |
|
701 new_addr = addr + src_width; |
|
702 for (x = addr + TARGET_PAGE_SIZE; x < new_addr; |
|
703 x += TARGET_PAGE_SIZE) { |
|
704 dirty[1] = cpu_physical_memory_get_dirty(x, VGA_DIRTY_FLAG); |
|
705 dirty[0] |= dirty[1]; |
|
706 } |
|
707 if (dirty[0] || s->invalidated) { |
|
708 fn((uint32_t *) s->dma_ch[0].palette, |
|
709 dest, src, s->xres, s->dest_width); |
|
710 if (addr < start) |
|
711 start = addr; |
|
712 end = new_addr; |
|
713 if (y < *miny) |
|
714 *miny = y; |
|
715 if (y >= *maxy) |
|
716 *maxy = y + 1; |
|
717 } |
|
718 addr = new_addr; |
|
719 dirty[0] = dirty[1]; |
|
720 src += src_width; |
|
721 dest += dest_width; |
|
722 } |
|
723 |
|
724 if (end > start) |
|
725 cpu_physical_memory_reset_dirty(start, end, VGA_DIRTY_FLAG); |
|
726 } |
|
727 |
|
728 static void pxa2xx_lcdc_dma0_redraw_vert(struct pxa2xx_lcdc_s *s, |
|
729 uint8_t *fb, int *miny, int *maxy) |
|
730 { |
|
731 int y, src_width, dest_width, dirty[2]; |
|
732 uint8_t *src, *dest; |
|
733 ram_addr_t x, addr, new_addr, start, end; |
|
734 drawfn fn = 0; |
|
735 if (s->dest_width) |
|
736 fn = s->line_fn[s->transp][s->bpp]; |
|
737 if (!fn) |
|
738 return; |
|
739 |
|
740 src = fb; |
|
741 src_width = (s->xres + 3) & ~3; /* Pad to a 4 pixels multiple */ |
|
742 if (s->bpp == pxa_lcdc_19pbpp || s->bpp == pxa_lcdc_18pbpp) |
|
743 src_width *= 3; |
|
744 else if (s->bpp > pxa_lcdc_16bpp) |
|
745 src_width *= 4; |
|
746 else if (s->bpp > pxa_lcdc_8bpp) |
|
747 src_width *= 2; |
|
748 |
|
749 dest_width = s->yres * s->dest_width; |
|
750 dest = ds_get_data(s->ds) + dest_width * (s->xres - 1); |
|
751 |
|
752 addr = ram_offset_from_host(fb); |
|
753 start = addr + s->yres * src_width; |
|
754 end = addr; |
|
755 x = addr + TARGET_PAGE_SIZE; |
|
756 dirty[0] = dirty[1] = cpu_physical_memory_get_dirty(start, VGA_DIRTY_FLAG); |
|
757 for (y = 0; y < s->yres; y ++) { |
|
758 new_addr = addr + src_width; |
|
759 for (; x < new_addr; x += TARGET_PAGE_SIZE) { |
|
760 dirty[1] = cpu_physical_memory_get_dirty(x, VGA_DIRTY_FLAG); |
|
761 dirty[0] |= dirty[1]; |
|
762 } |
|
763 if (dirty[0] || s->invalidated) { |
|
764 fn((uint32_t *) s->dma_ch[0].palette, |
|
765 dest, src, s->xres, -dest_width); |
|
766 if (addr < start) |
|
767 start = addr; |
|
768 end = new_addr; |
|
769 if (y < *miny) |
|
770 *miny = y; |
|
771 if (y >= *maxy) |
|
772 *maxy = y + 1; |
|
773 } |
|
774 addr = new_addr; |
|
775 dirty[0] = dirty[1]; |
|
776 src += src_width; |
|
777 dest += s->dest_width; |
|
778 } |
|
779 |
|
780 if (end > start) |
|
781 cpu_physical_memory_reset_dirty(start, end, VGA_DIRTY_FLAG); |
|
782 } |
|
783 |
|
784 static void pxa2xx_lcdc_resize(struct pxa2xx_lcdc_s *s) |
|
785 { |
|
786 int width, height; |
|
787 if (!(s->control[0] & LCCR0_ENB)) |
|
788 return; |
|
789 |
|
790 width = LCCR1_PPL(s->control[1]) + 1; |
|
791 height = LCCR2_LPP(s->control[2]) + 1; |
|
792 |
|
793 if (width != s->xres || height != s->yres) { |
|
794 if (s->orientation) |
|
795 gui_resize_vt(s->ds, height, width); |
|
796 else |
|
797 gui_resize_vt(s->ds, width, height); |
|
798 s->invalidated = 1; |
|
799 s->xres = width; |
|
800 s->yres = height; |
|
801 } |
|
802 } |
|
803 |
|
804 static void pxa2xx_update_display(void *opaque) |
|
805 { |
|
806 struct pxa2xx_lcdc_s *s = (struct pxa2xx_lcdc_s *) opaque; |
|
807 uint8_t *fb; |
|
808 target_phys_addr_t fbptr; |
|
809 int miny, maxy; |
|
810 int ch; |
|
811 if (!(s->control[0] & LCCR0_ENB)) |
|
812 return; |
|
813 |
|
814 pxa2xx_descriptor_load(s); |
|
815 |
|
816 pxa2xx_lcdc_resize(s); |
|
817 miny = s->yres; |
|
818 maxy = 0; |
|
819 s->transp = s->dma_ch[2].up || s->dma_ch[3].up; |
|
820 /* Note: With overlay planes the order depends on LCCR0 bit 25. */ |
|
821 for (ch = 0; ch < PXA_LCDDMA_CHANS; ch ++) |
|
822 if (s->dma_ch[ch].up) { |
|
823 if (!s->dma_ch[ch].source) { |
|
824 pxa2xx_dma_ber_set(s, ch); |
|
825 continue; |
|
826 } |
|
827 fbptr = s->dma_ch[ch].source; |
|
828 if (!(fbptr >= PXA2XX_SDRAM_BASE && |
|
829 fbptr <= PXA2XX_SDRAM_BASE + phys_ram_size)) { |
|
830 pxa2xx_dma_ber_set(s, ch); |
|
831 continue; |
|
832 } |
|
833 fbptr -= PXA2XX_SDRAM_BASE; |
|
834 /* FIXME: This is broken if it spans multiple RAM regions. */ |
|
835 fb = host_ram_addr(fbptr); |
|
836 |
|
837 if (s->dma_ch[ch].command & LDCMD_PAL) { |
|
838 memcpy(s->dma_ch[ch].pbuffer, fb, |
|
839 MAX(LDCMD_LENGTH(s->dma_ch[ch].command), |
|
840 sizeof(s->dma_ch[ch].pbuffer))); |
|
841 pxa2xx_palette_parse(s, ch, s->bpp); |
|
842 } else { |
|
843 /* Do we need to reparse palette */ |
|
844 if (LCCR4_PALFOR(s->control[4]) != s->pal_for) |
|
845 pxa2xx_palette_parse(s, ch, s->bpp); |
|
846 |
|
847 /* ACK frame start */ |
|
848 pxa2xx_dma_sof_set(s, ch); |
|
849 |
|
850 s->dma_ch[ch].redraw(s, fb, &miny, &maxy); |
|
851 s->invalidated = 0; |
|
852 |
|
853 /* ACK frame completed */ |
|
854 pxa2xx_dma_eof_set(s, ch); |
|
855 } |
|
856 } |
|
857 |
|
858 if (s->control[0] & LCCR0_DIS) { |
|
859 /* ACK last frame completed */ |
|
860 s->control[0] &= ~LCCR0_ENB; |
|
861 s->status[0] |= LCSR0_LDD; |
|
862 } |
|
863 |
|
864 if (s->orientation) |
|
865 dpy_update(s->ds, miny, 0, maxy, s->xres); |
|
866 else |
|
867 dpy_update(s->ds, 0, miny, s->xres, maxy); |
|
868 pxa2xx_lcdc_int_update(s); |
|
869 |
|
870 qemu_irq_raise(s->vsync_cb); |
|
871 } |
|
872 |
|
873 static void pxa2xx_invalidate_display(void *opaque) |
|
874 { |
|
875 struct pxa2xx_lcdc_s *s = (struct pxa2xx_lcdc_s *) opaque; |
|
876 s->invalidated = 1; |
|
877 } |
|
878 |
|
879 static void pxa2xx_screen_dump(void *opaque, const char *filename) |
|
880 { |
|
881 /* TODO */ |
|
882 } |
|
883 |
|
884 static void pxa2xx_lcdc_orientation(void *opaque, int angle) |
|
885 { |
|
886 struct pxa2xx_lcdc_s *s = (struct pxa2xx_lcdc_s *) opaque; |
|
887 |
|
888 if (angle) { |
|
889 s->dma_ch[0].redraw = pxa2xx_lcdc_dma0_redraw_vert; |
|
890 } else { |
|
891 s->dma_ch[0].redraw = pxa2xx_lcdc_dma0_redraw_horiz; |
|
892 } |
|
893 |
|
894 s->orientation = angle; |
|
895 s->xres = s->yres = -1; |
|
896 pxa2xx_lcdc_resize(s); |
|
897 } |
|
898 |
|
899 static void pxa2xx_lcdc_save(QEMUFile *f, void *opaque) |
|
900 { |
|
901 struct pxa2xx_lcdc_s *s = (struct pxa2xx_lcdc_s *) opaque; |
|
902 int i; |
|
903 |
|
904 qemu_put_be32(f, s->irqlevel); |
|
905 qemu_put_be32(f, s->transp); |
|
906 |
|
907 for (i = 0; i < 6; i ++) |
|
908 qemu_put_be32s(f, &s->control[i]); |
|
909 for (i = 0; i < 2; i ++) |
|
910 qemu_put_be32s(f, &s->status[i]); |
|
911 for (i = 0; i < 2; i ++) |
|
912 qemu_put_be32s(f, &s->ovl1c[i]); |
|
913 for (i = 0; i < 2; i ++) |
|
914 qemu_put_be32s(f, &s->ovl2c[i]); |
|
915 qemu_put_be32s(f, &s->ccr); |
|
916 qemu_put_be32s(f, &s->cmdcr); |
|
917 qemu_put_be32s(f, &s->trgbr); |
|
918 qemu_put_be32s(f, &s->tcr); |
|
919 qemu_put_be32s(f, &s->liidr); |
|
920 qemu_put_8s(f, &s->bscntr); |
|
921 |
|
922 for (i = 0; i < 7; i ++) { |
|
923 qemu_put_betl(f, s->dma_ch[i].branch); |
|
924 qemu_put_byte(f, s->dma_ch[i].up); |
|
925 qemu_put_buffer(f, s->dma_ch[i].pbuffer, sizeof(s->dma_ch[i].pbuffer)); |
|
926 |
|
927 qemu_put_betl(f, s->dma_ch[i].descriptor); |
|
928 qemu_put_betl(f, s->dma_ch[i].source); |
|
929 qemu_put_be32s(f, &s->dma_ch[i].id); |
|
930 qemu_put_be32s(f, &s->dma_ch[i].command); |
|
931 } |
|
932 } |
|
933 |
|
934 static int pxa2xx_lcdc_load(QEMUFile *f, void *opaque, int version_id) |
|
935 { |
|
936 struct pxa2xx_lcdc_s *s = (struct pxa2xx_lcdc_s *) opaque; |
|
937 int i; |
|
938 |
|
939 s->irqlevel = qemu_get_be32(f); |
|
940 s->transp = qemu_get_be32(f); |
|
941 |
|
942 for (i = 0; i < 6; i ++) |
|
943 qemu_get_be32s(f, &s->control[i]); |
|
944 for (i = 0; i < 2; i ++) |
|
945 qemu_get_be32s(f, &s->status[i]); |
|
946 for (i = 0; i < 2; i ++) |
|
947 qemu_get_be32s(f, &s->ovl1c[i]); |
|
948 for (i = 0; i < 2; i ++) |
|
949 qemu_get_be32s(f, &s->ovl2c[i]); |
|
950 qemu_get_be32s(f, &s->ccr); |
|
951 qemu_get_be32s(f, &s->cmdcr); |
|
952 qemu_get_be32s(f, &s->trgbr); |
|
953 qemu_get_be32s(f, &s->tcr); |
|
954 qemu_get_be32s(f, &s->liidr); |
|
955 qemu_get_8s(f, &s->bscntr); |
|
956 |
|
957 for (i = 0; i < 7; i ++) { |
|
958 s->dma_ch[i].branch = qemu_get_betl(f); |
|
959 s->dma_ch[i].up = qemu_get_byte(f); |
|
960 qemu_get_buffer(f, s->dma_ch[i].pbuffer, sizeof(s->dma_ch[i].pbuffer)); |
|
961 |
|
962 s->dma_ch[i].descriptor = qemu_get_betl(f); |
|
963 s->dma_ch[i].source = qemu_get_betl(f); |
|
964 qemu_get_be32s(f, &s->dma_ch[i].id); |
|
965 qemu_get_be32s(f, &s->dma_ch[i].command); |
|
966 } |
|
967 |
|
968 s->bpp = LCCR3_BPP(s->control[3]); |
|
969 s->xres = s->yres = s->pal_for = -1; |
|
970 |
|
971 return 0; |
|
972 } |
|
973 |
|
974 #define BITS 8 |
|
975 #include "pxa2xx_template.h" |
|
976 #define BITS 15 |
|
977 #include "pxa2xx_template.h" |
|
978 #define BITS 16 |
|
979 #include "pxa2xx_template.h" |
|
980 #define BITS 24 |
|
981 #include "pxa2xx_template.h" |
|
982 #define BITS 32 |
|
983 #include "pxa2xx_template.h" |
|
984 |
|
985 struct pxa2xx_lcdc_s *pxa2xx_lcdc_init(target_phys_addr_t base, qemu_irq irq, |
|
986 DisplayState *ds) |
|
987 { |
|
988 int iomemtype; |
|
989 struct pxa2xx_lcdc_s *s; |
|
990 |
|
991 s = (struct pxa2xx_lcdc_s *) qemu_mallocz(sizeof(struct pxa2xx_lcdc_s)); |
|
992 s->invalidated = 1; |
|
993 s->irq = irq; |
|
994 |
|
995 pxa2xx_lcdc_orientation(s, graphic_rotate); |
|
996 |
|
997 iomemtype = cpu_register_io_memory(0, pxa2xx_lcdc_readfn, |
|
998 pxa2xx_lcdc_writefn, s); |
|
999 cpu_register_physical_memory(base, 0x00100000, iomemtype); |
|
1000 |
|
1001 s->ds = gui_get_graphic_console(NULL, |
|
1002 pxa2xx_update_display, |
|
1003 pxa2xx_invalidate_display, |
|
1004 pxa2xx_screen_dump, s); |
|
1005 |
|
1006 switch (ds_get_bits_per_pixel(s->ds)) { |
|
1007 case 0: |
|
1008 s->dest_width = 0; |
|
1009 break; |
|
1010 case 8: |
|
1011 s->line_fn[0] = pxa2xx_draw_fn_8; |
|
1012 s->line_fn[1] = pxa2xx_draw_fn_8t; |
|
1013 s->dest_width = 1; |
|
1014 break; |
|
1015 case 15: |
|
1016 s->line_fn[0] = pxa2xx_draw_fn_15; |
|
1017 s->line_fn[1] = pxa2xx_draw_fn_15t; |
|
1018 s->dest_width = 2; |
|
1019 break; |
|
1020 case 16: |
|
1021 s->line_fn[0] = pxa2xx_draw_fn_16; |
|
1022 s->line_fn[1] = pxa2xx_draw_fn_16t; |
|
1023 s->dest_width = 2; |
|
1024 break; |
|
1025 case 24: |
|
1026 s->line_fn[0] = pxa2xx_draw_fn_24; |
|
1027 s->line_fn[1] = pxa2xx_draw_fn_24t; |
|
1028 s->dest_width = 3; |
|
1029 break; |
|
1030 case 32: |
|
1031 s->line_fn[0] = pxa2xx_draw_fn_32; |
|
1032 s->line_fn[1] = pxa2xx_draw_fn_32t; |
|
1033 s->dest_width = 4; |
|
1034 break; |
|
1035 default: |
|
1036 fprintf(stderr, "%s: Bad color depth\n", __FUNCTION__); |
|
1037 exit(1); |
|
1038 } |
|
1039 |
|
1040 register_savevm("pxa2xx_lcdc", 0, 0, |
|
1041 pxa2xx_lcdc_save, pxa2xx_lcdc_load, s); |
|
1042 |
|
1043 return s; |
|
1044 } |
|
1045 |
|
1046 void pxa2xx_lcd_vsync_notifier(struct pxa2xx_lcdc_s *s, qemu_irq handler) |
|
1047 { |
|
1048 s->vsync_cb = handler; |
|
1049 } |