|
|
1.1 root 1: /*
2: * OMAP LCD controller.
3: *
4: * Copyright (C) 2006-2007 Andrzej Zaborowski <[email protected]>
5: *
6: * This program is free software; you can redistribute it and/or
7: * modify it under the terms of the GNU General Public License as
8: * published by the Free Software Foundation; either version 2 of
9: * the License, or (at your option) any later version.
10: *
11: * This program is distributed in the hope that it will be useful,
12: * but WITHOUT ANY WARRANTY; without even the implied warranty of
13: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14: * GNU General Public License for more details.
15: *
1.1.1.2 ! root 16: * You should have received a copy of the GNU General Public License along
! 17: * with this program; if not, write to the Free Software Foundation, Inc.,
! 18: * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
1.1 root 19: */
20: #include "hw.h"
21: #include "console.h"
22: #include "omap.h"
23:
24: struct omap_lcd_panel_s {
25: qemu_irq irq;
26: DisplayState *state;
27: ram_addr_t imif_base;
28: ram_addr_t emiff_base;
29:
30: int plm;
31: int tft;
32: int mono;
33: int enable;
34: int width;
35: int height;
36: int interrupts;
37: uint32_t timing[3];
38: uint32_t subpanel;
39: uint32_t ctrl;
40:
41: struct omap_dma_lcd_channel_s *dma;
42: uint16_t palette[256];
43: int palette_done;
44: int frame_done;
45: int invalidate;
46: int sync_error;
47: };
48:
49: static void omap_lcd_interrupts(struct omap_lcd_panel_s *s)
50: {
51: if (s->frame_done && (s->interrupts & 1)) {
52: qemu_irq_raise(s->irq);
53: return;
54: }
55:
56: if (s->palette_done && (s->interrupts & 2)) {
57: qemu_irq_raise(s->irq);
58: return;
59: }
60:
61: if (s->sync_error) {
62: qemu_irq_raise(s->irq);
63: return;
64: }
65:
66: qemu_irq_lower(s->irq);
67: }
68:
69: #include "pixel_ops.h"
70:
71: typedef void draw_line_func(
72: uint8_t *d, const uint8_t *s, int width, const uint16_t *pal);
73:
74: #define DEPTH 8
75: #include "omap_lcd_template.h"
76: #define DEPTH 15
77: #include "omap_lcd_template.h"
78: #define DEPTH 16
79: #include "omap_lcd_template.h"
80: #define DEPTH 32
81: #include "omap_lcd_template.h"
82:
83: static draw_line_func *draw_line_table2[33] = {
84: [0 ... 32] = 0,
85: [8] = draw_line2_8,
86: [15] = draw_line2_15,
87: [16] = draw_line2_16,
88: [32] = draw_line2_32,
89: }, *draw_line_table4[33] = {
90: [0 ... 32] = 0,
91: [8] = draw_line4_8,
92: [15] = draw_line4_15,
93: [16] = draw_line4_16,
94: [32] = draw_line4_32,
95: }, *draw_line_table8[33] = {
96: [0 ... 32] = 0,
97: [8] = draw_line8_8,
98: [15] = draw_line8_15,
99: [16] = draw_line8_16,
100: [32] = draw_line8_32,
101: }, *draw_line_table12[33] = {
102: [0 ... 32] = 0,
103: [8] = draw_line12_8,
104: [15] = draw_line12_15,
105: [16] = draw_line12_16,
106: [32] = draw_line12_32,
107: }, *draw_line_table16[33] = {
108: [0 ... 32] = 0,
109: [8] = draw_line16_8,
110: [15] = draw_line16_15,
111: [16] = draw_line16_16,
112: [32] = draw_line16_32,
113: };
114:
115: static void omap_update_display(void *opaque)
116: {
117: struct omap_lcd_panel_s *omap_lcd = (struct omap_lcd_panel_s *) opaque;
118: draw_line_func *draw_line;
119: int size, dirty[2], minline, maxline, height;
120: int line, width, linesize, step, bpp, frame_offset;
121: ram_addr_t frame_base, scanline, newline, x;
122: uint8_t *s, *d;
123:
124: if (!omap_lcd || omap_lcd->plm == 1 ||
1.1.1.2 ! root 125: !omap_lcd->enable || !ds_get_bits_per_pixel(omap_lcd->state))
1.1 root 126: return;
127:
128: frame_offset = 0;
129: if (omap_lcd->plm != 2) {
130: memcpy(omap_lcd->palette, phys_ram_base +
131: omap_lcd->dma->phys_framebuffer[
132: omap_lcd->dma->current_frame], 0x200);
133: switch (omap_lcd->palette[0] >> 12 & 7) {
134: case 3 ... 7:
135: frame_offset += 0x200;
136: break;
137: default:
138: frame_offset += 0x20;
139: }
140: }
141:
142: /* Colour depth */
143: switch ((omap_lcd->palette[0] >> 12) & 7) {
144: case 1:
1.1.1.2 ! root 145: draw_line = draw_line_table2[ds_get_bits_per_pixel(omap_lcd->state)];
1.1 root 146: bpp = 2;
147: break;
148:
149: case 2:
1.1.1.2 ! root 150: draw_line = draw_line_table4[ds_get_bits_per_pixel(omap_lcd->state)];
1.1 root 151: bpp = 4;
152: break;
153:
154: case 3:
1.1.1.2 ! root 155: draw_line = draw_line_table8[ds_get_bits_per_pixel(omap_lcd->state)];
1.1 root 156: bpp = 8;
157: break;
158:
159: case 4 ... 7:
160: if (!omap_lcd->tft)
1.1.1.2 ! root 161: draw_line = draw_line_table12[ds_get_bits_per_pixel(omap_lcd->state)];
1.1 root 162: else
1.1.1.2 ! root 163: draw_line = draw_line_table16[ds_get_bits_per_pixel(omap_lcd->state)];
1.1 root 164: bpp = 16;
165: break;
166:
167: default:
168: /* Unsupported at the moment. */
169: return;
170: }
171:
172: /* Resolution */
173: width = omap_lcd->width;
1.1.1.2 ! root 174: if (width != ds_get_width(omap_lcd->state) ||
! 175: omap_lcd->height != ds_get_height(omap_lcd->state)) {
! 176: qemu_console_resize(omap_lcd->state,
! 177: omap_lcd->width, omap_lcd->height);
1.1 root 178: omap_lcd->invalidate = 1;
179: }
180:
181: if (omap_lcd->dma->current_frame == 0)
182: size = omap_lcd->dma->src_f1_bottom - omap_lcd->dma->src_f1_top;
183: else
184: size = omap_lcd->dma->src_f2_bottom - omap_lcd->dma->src_f2_top;
185:
186: if (frame_offset + ((width * omap_lcd->height * bpp) >> 3) > size + 2) {
187: omap_lcd->sync_error = 1;
188: omap_lcd_interrupts(omap_lcd);
189: omap_lcd->enable = 0;
190: return;
191: }
192:
193: /* Content */
194: frame_base = omap_lcd->dma->phys_framebuffer[
195: omap_lcd->dma->current_frame] + frame_offset;
196: omap_lcd->dma->condition |= 1 << omap_lcd->dma->current_frame;
197: if (omap_lcd->dma->interrupts & 1)
198: qemu_irq_raise(omap_lcd->dma->irq);
199: if (omap_lcd->dma->dual)
200: omap_lcd->dma->current_frame ^= 1;
201:
1.1.1.2 ! root 202: if (!ds_get_bits_per_pixel(omap_lcd->state))
1.1 root 203: return;
204:
205: line = 0;
206: height = omap_lcd->height;
207: if (omap_lcd->subpanel & (1 << 31)) {
208: if (omap_lcd->subpanel & (1 << 29))
209: line = (omap_lcd->subpanel >> 16) & 0x3ff;
210: else
211: height = (omap_lcd->subpanel >> 16) & 0x3ff;
212: /* TODO: fill the rest of the panel with DPD */
213: }
214: step = width * bpp >> 3;
215: scanline = frame_base + step * line;
216: s = (uint8_t *) (phys_ram_base + scanline);
1.1.1.2 ! root 217: d = ds_get_data(omap_lcd->state);
! 218: linesize = ds_get_linesize(omap_lcd->state);
1.1 root 219:
220: dirty[0] = dirty[1] =
221: cpu_physical_memory_get_dirty(scanline, VGA_DIRTY_FLAG);
222: minline = height;
223: maxline = line;
224: for (; line < height; line ++) {
225: newline = scanline + step;
226: for (x = scanline + TARGET_PAGE_SIZE; x < newline;
227: x += TARGET_PAGE_SIZE) {
228: dirty[1] = cpu_physical_memory_get_dirty(x, VGA_DIRTY_FLAG);
229: dirty[0] |= dirty[1];
230: }
231: if (dirty[0] || omap_lcd->invalidate) {
232: draw_line(d, s, width, omap_lcd->palette);
233: if (line < minline)
234: minline = line;
235: maxline = line + 1;
236: }
237: scanline = newline;
238: dirty[0] = dirty[1];
239: s += step;
240: d += linesize;
241: }
242:
243: if (maxline >= minline) {
244: dpy_update(omap_lcd->state, 0, minline, width, maxline);
245: cpu_physical_memory_reset_dirty(frame_base + step * minline,
246: frame_base + step * maxline, VGA_DIRTY_FLAG);
247: }
248: }
249:
250: static int ppm_save(const char *filename, uint8_t *data,
251: int w, int h, int linesize)
252: {
253: FILE *f;
254: uint8_t *d, *d1;
255: unsigned int v;
256: int y, x, bpp;
257:
258: f = fopen(filename, "wb");
259: if (!f)
260: return -1;
261: fprintf(f, "P6\n%d %d\n%d\n", w, h, 255);
262: d1 = data;
263: bpp = linesize / w;
264: for (y = 0; y < h; y ++) {
265: d = d1;
266: for (x = 0; x < w; x ++) {
267: v = *(uint32_t *) d;
268: switch (bpp) {
269: case 2:
270: fputc((v >> 8) & 0xf8, f);
271: fputc((v >> 3) & 0xfc, f);
272: fputc((v << 3) & 0xf8, f);
273: break;
274: case 3:
275: case 4:
276: default:
277: fputc((v >> 16) & 0xff, f);
278: fputc((v >> 8) & 0xff, f);
279: fputc((v) & 0xff, f);
280: break;
281: }
282: d += bpp;
283: }
284: d1 += linesize;
285: }
286: fclose(f);
287: return 0;
288: }
289:
290: static void omap_screen_dump(void *opaque, const char *filename) {
291: struct omap_lcd_panel_s *omap_lcd = opaque;
292: omap_update_display(opaque);
1.1.1.2 ! root 293: if (omap_lcd && ds_get_data(omap_lcd->state))
! 294: ppm_save(filename, ds_get_data(omap_lcd->state),
1.1 root 295: omap_lcd->width, omap_lcd->height,
1.1.1.2 ! root 296: ds_get_linesize(omap_lcd->state));
1.1 root 297: }
298:
299: static void omap_invalidate_display(void *opaque) {
300: struct omap_lcd_panel_s *omap_lcd = opaque;
301: omap_lcd->invalidate = 1;
302: }
303:
304: static void omap_lcd_update(struct omap_lcd_panel_s *s) {
305: if (!s->enable) {
306: s->dma->current_frame = -1;
307: s->sync_error = 0;
308: if (s->plm != 1)
309: s->frame_done = 1;
310: omap_lcd_interrupts(s);
311: return;
312: }
313:
314: if (s->dma->current_frame == -1) {
315: s->frame_done = 0;
316: s->palette_done = 0;
317: s->dma->current_frame = 0;
318: }
319:
320: if (!s->dma->mpu->port[s->dma->src].addr_valid(s->dma->mpu,
321: s->dma->src_f1_top) ||
322: !s->dma->mpu->port[
323: s->dma->src].addr_valid(s->dma->mpu,
324: s->dma->src_f1_bottom) ||
325: (s->dma->dual &&
326: (!s->dma->mpu->port[
327: s->dma->src].addr_valid(s->dma->mpu,
328: s->dma->src_f2_top) ||
329: !s->dma->mpu->port[
330: s->dma->src].addr_valid(s->dma->mpu,
331: s->dma->src_f2_bottom)))) {
332: s->dma->condition |= 1 << 2;
333: if (s->dma->interrupts & (1 << 1))
334: qemu_irq_raise(s->dma->irq);
335: s->enable = 0;
336: return;
337: }
338:
339: if (s->dma->src == imif) {
340: /* Framebuffers are in SRAM */
341: s->dma->phys_framebuffer[0] = s->imif_base +
342: s->dma->src_f1_top - OMAP_IMIF_BASE;
343:
344: s->dma->phys_framebuffer[1] = s->imif_base +
345: s->dma->src_f2_top - OMAP_IMIF_BASE;
346: } else {
347: /* Framebuffers are in RAM */
348: s->dma->phys_framebuffer[0] = s->emiff_base +
349: s->dma->src_f1_top - OMAP_EMIFF_BASE;
350:
351: s->dma->phys_framebuffer[1] = s->emiff_base +
352: s->dma->src_f2_top - OMAP_EMIFF_BASE;
353: }
354:
355: if (s->plm != 2 && !s->palette_done) {
356: memcpy(s->palette, phys_ram_base +
357: s->dma->phys_framebuffer[s->dma->current_frame], 0x200);
358: s->palette_done = 1;
359: omap_lcd_interrupts(s);
360: }
361: }
362:
363: static uint32_t omap_lcdc_read(void *opaque, target_phys_addr_t addr)
364: {
365: struct omap_lcd_panel_s *s = (struct omap_lcd_panel_s *) opaque;
366:
1.1.1.2 ! root 367: switch (addr) {
1.1 root 368: case 0x00: /* LCD_CONTROL */
369: return (s->tft << 23) | (s->plm << 20) |
370: (s->tft << 7) | (s->interrupts << 3) |
371: (s->mono << 1) | s->enable | s->ctrl | 0xfe000c34;
372:
373: case 0x04: /* LCD_TIMING0 */
374: return (s->timing[0] << 10) | (s->width - 1) | 0x0000000f;
375:
376: case 0x08: /* LCD_TIMING1 */
377: return (s->timing[1] << 10) | (s->height - 1);
378:
379: case 0x0c: /* LCD_TIMING2 */
380: return s->timing[2] | 0xfc000000;
381:
382: case 0x10: /* LCD_STATUS */
383: return (s->palette_done << 6) | (s->sync_error << 2) | s->frame_done;
384:
385: case 0x14: /* LCD_SUBPANEL */
386: return s->subpanel;
387:
388: default:
389: break;
390: }
391: OMAP_BAD_REG(addr);
392: return 0;
393: }
394:
395: static void omap_lcdc_write(void *opaque, target_phys_addr_t addr,
396: uint32_t value)
397: {
398: struct omap_lcd_panel_s *s = (struct omap_lcd_panel_s *) opaque;
399:
1.1.1.2 ! root 400: switch (addr) {
1.1 root 401: case 0x00: /* LCD_CONTROL */
402: s->plm = (value >> 20) & 3;
403: s->tft = (value >> 7) & 1;
404: s->interrupts = (value >> 3) & 3;
405: s->mono = (value >> 1) & 1;
406: s->ctrl = value & 0x01cff300;
407: if (s->enable != (value & 1)) {
408: s->enable = value & 1;
409: omap_lcd_update(s);
410: }
411: break;
412:
413: case 0x04: /* LCD_TIMING0 */
414: s->timing[0] = value >> 10;
415: s->width = (value & 0x3ff) + 1;
416: break;
417:
418: case 0x08: /* LCD_TIMING1 */
419: s->timing[1] = value >> 10;
420: s->height = (value & 0x3ff) + 1;
421: break;
422:
423: case 0x0c: /* LCD_TIMING2 */
424: s->timing[2] = value;
425: break;
426:
427: case 0x10: /* LCD_STATUS */
428: break;
429:
430: case 0x14: /* LCD_SUBPANEL */
431: s->subpanel = value & 0xa1ffffff;
432: break;
433:
434: default:
435: OMAP_BAD_REG(addr);
436: }
437: }
438:
439: static CPUReadMemoryFunc *omap_lcdc_readfn[] = {
440: omap_lcdc_read,
441: omap_lcdc_read,
442: omap_lcdc_read,
443: };
444:
445: static CPUWriteMemoryFunc *omap_lcdc_writefn[] = {
446: omap_lcdc_write,
447: omap_lcdc_write,
448: omap_lcdc_write,
449: };
450:
451: void omap_lcdc_reset(struct omap_lcd_panel_s *s)
452: {
453: s->dma->current_frame = -1;
454: s->plm = 0;
455: s->tft = 0;
456: s->mono = 0;
457: s->enable = 0;
458: s->width = 0;
459: s->height = 0;
460: s->interrupts = 0;
461: s->timing[0] = 0;
462: s->timing[1] = 0;
463: s->timing[2] = 0;
464: s->subpanel = 0;
465: s->palette_done = 0;
466: s->frame_done = 0;
467: s->sync_error = 0;
468: s->invalidate = 1;
469: s->subpanel = 0;
470: s->ctrl = 0;
471: }
472:
473: struct omap_lcd_panel_s *omap_lcdc_init(target_phys_addr_t base, qemu_irq irq,
1.1.1.2 ! root 474: struct omap_dma_lcd_channel_s *dma,
1.1 root 475: ram_addr_t imif_base, ram_addr_t emiff_base, omap_clk clk)
476: {
477: int iomemtype;
478: struct omap_lcd_panel_s *s = (struct omap_lcd_panel_s *)
479: qemu_mallocz(sizeof(struct omap_lcd_panel_s));
480:
481: s->irq = irq;
482: s->dma = dma;
483: s->imif_base = imif_base;
484: s->emiff_base = emiff_base;
485: omap_lcdc_reset(s);
486:
487: iomemtype = cpu_register_io_memory(0, omap_lcdc_readfn,
488: omap_lcdc_writefn, s);
1.1.1.2 ! root 489: cpu_register_physical_memory(base, 0x100, iomemtype);
1.1 root 490:
1.1.1.2 ! root 491: s->state = graphic_console_init(omap_update_display,
! 492: omap_invalidate_display,
! 493: omap_screen_dump, NULL, s);
1.1 root 494:
495: return s;
496: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.