Annotation of qemu/hw/omap_lcdc.c, revision 1.1.1.6

1.1       root        1: /*
                      2:  * OMAP LCD controller.
                      3:  *
                      4:  * Copyright (C) 2006-2007 Andrzej Zaborowski  <balrog@zabor.org>
                      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
1.1.1.3   root       17:  * with this program; if not, see <http://www.gnu.org/licenses/>.
1.1       root       18:  */
                     19: #include "hw.h"
                     20: #include "console.h"
                     21: #include "omap.h"
1.1.1.3   root       22: #include "framebuffer.h"
1.1       root       23: 
                     24: struct omap_lcd_panel_s {
                     25:     qemu_irq irq;
                     26:     DisplayState *state;
                     27: 
                     28:     int plm;
                     29:     int tft;
                     30:     int mono;
                     31:     int enable;
                     32:     int width;
                     33:     int height;
                     34:     int interrupts;
                     35:     uint32_t timing[3];
                     36:     uint32_t subpanel;
                     37:     uint32_t ctrl;
                     38: 
                     39:     struct omap_dma_lcd_channel_s *dma;
                     40:     uint16_t palette[256];
                     41:     int palette_done;
                     42:     int frame_done;
                     43:     int invalidate;
                     44:     int sync_error;
                     45: };
                     46: 
                     47: static void omap_lcd_interrupts(struct omap_lcd_panel_s *s)
                     48: {
                     49:     if (s->frame_done && (s->interrupts & 1)) {
                     50:         qemu_irq_raise(s->irq);
                     51:         return;
                     52:     }
                     53: 
                     54:     if (s->palette_done && (s->interrupts & 2)) {
                     55:         qemu_irq_raise(s->irq);
                     56:         return;
                     57:     }
                     58: 
                     59:     if (s->sync_error) {
                     60:         qemu_irq_raise(s->irq);
                     61:         return;
                     62:     }
                     63: 
                     64:     qemu_irq_lower(s->irq);
                     65: }
                     66: 
                     67: #include "pixel_ops.h"
                     68: 
1.1.1.3   root       69: #define draw_line_func drawfn
1.1       root       70: 
                     71: #define DEPTH 8
                     72: #include "omap_lcd_template.h"
                     73: #define DEPTH 15
                     74: #include "omap_lcd_template.h"
                     75: #define DEPTH 16
                     76: #include "omap_lcd_template.h"
                     77: #define DEPTH 32
                     78: #include "omap_lcd_template.h"
                     79: 
1.1.1.3   root       80: static draw_line_func draw_line_table2[33] = {
1.1.1.4   root       81:     [0 ... 32] = NULL,
1.1       root       82:     [8]                = draw_line2_8,
                     83:     [15]       = draw_line2_15,
                     84:     [16]       = draw_line2_16,
                     85:     [32]       = draw_line2_32,
1.1.1.3   root       86: }, draw_line_table4[33] = {
1.1.1.4   root       87:     [0 ... 32] = NULL,
1.1       root       88:     [8]                = draw_line4_8,
                     89:     [15]       = draw_line4_15,
                     90:     [16]       = draw_line4_16,
                     91:     [32]       = draw_line4_32,
1.1.1.3   root       92: }, draw_line_table8[33] = {
1.1.1.4   root       93:     [0 ... 32] = NULL,
1.1       root       94:     [8]                = draw_line8_8,
                     95:     [15]       = draw_line8_15,
                     96:     [16]       = draw_line8_16,
                     97:     [32]       = draw_line8_32,
1.1.1.3   root       98: }, draw_line_table12[33] = {
1.1.1.4   root       99:     [0 ... 32] = NULL,
1.1       root      100:     [8]                = draw_line12_8,
                    101:     [15]       = draw_line12_15,
                    102:     [16]       = draw_line12_16,
                    103:     [32]       = draw_line12_32,
1.1.1.3   root      104: }, draw_line_table16[33] = {
1.1.1.4   root      105:     [0 ... 32] = NULL,
1.1       root      106:     [8]                = draw_line16_8,
                    107:     [15]       = draw_line16_15,
                    108:     [16]       = draw_line16_16,
                    109:     [32]       = draw_line16_32,
                    110: };
                    111: 
                    112: static void omap_update_display(void *opaque)
                    113: {
                    114:     struct omap_lcd_panel_s *omap_lcd = (struct omap_lcd_panel_s *) opaque;
1.1.1.3   root      115:     draw_line_func draw_line;
                    116:     int size, height, first, last;
                    117:     int width, linesize, step, bpp, frame_offset;
                    118:     target_phys_addr_t frame_base;
1.1       root      119: 
                    120:     if (!omap_lcd || omap_lcd->plm == 1 ||
1.1.1.2   root      121:                     !omap_lcd->enable || !ds_get_bits_per_pixel(omap_lcd->state))
1.1       root      122:         return;
                    123: 
                    124:     frame_offset = 0;
                    125:     if (omap_lcd->plm != 2) {
1.1.1.3   root      126:         cpu_physical_memory_read(omap_lcd->dma->phys_framebuffer[
                    127:                                   omap_lcd->dma->current_frame],
                    128:                                  (void *)omap_lcd->palette, 0x200);
1.1       root      129:         switch (omap_lcd->palette[0] >> 12 & 7) {
                    130:         case 3 ... 7:
                    131:             frame_offset += 0x200;
                    132:             break;
                    133:         default:
                    134:             frame_offset += 0x20;
                    135:         }
                    136:     }
                    137: 
                    138:     /* Colour depth */
                    139:     switch ((omap_lcd->palette[0] >> 12) & 7) {
                    140:     case 1:
1.1.1.2   root      141:         draw_line = draw_line_table2[ds_get_bits_per_pixel(omap_lcd->state)];
1.1       root      142:         bpp = 2;
                    143:         break;
                    144: 
                    145:     case 2:
1.1.1.2   root      146:         draw_line = draw_line_table4[ds_get_bits_per_pixel(omap_lcd->state)];
1.1       root      147:         bpp = 4;
                    148:         break;
                    149: 
                    150:     case 3:
1.1.1.2   root      151:         draw_line = draw_line_table8[ds_get_bits_per_pixel(omap_lcd->state)];
1.1       root      152:         bpp = 8;
                    153:         break;
                    154: 
                    155:     case 4 ... 7:
                    156:         if (!omap_lcd->tft)
1.1.1.2   root      157:             draw_line = draw_line_table12[ds_get_bits_per_pixel(omap_lcd->state)];
1.1       root      158:         else
1.1.1.2   root      159:             draw_line = draw_line_table16[ds_get_bits_per_pixel(omap_lcd->state)];
1.1       root      160:         bpp = 16;
                    161:         break;
                    162: 
                    163:     default:
                    164:         /* Unsupported at the moment.  */
                    165:         return;
                    166:     }
                    167: 
                    168:     /* Resolution */
                    169:     width = omap_lcd->width;
1.1.1.2   root      170:     if (width != ds_get_width(omap_lcd->state) ||
                    171:             omap_lcd->height != ds_get_height(omap_lcd->state)) {
                    172:         qemu_console_resize(omap_lcd->state,
                    173:                             omap_lcd->width, omap_lcd->height);
1.1       root      174:         omap_lcd->invalidate = 1;
                    175:     }
                    176: 
                    177:     if (omap_lcd->dma->current_frame == 0)
                    178:         size = omap_lcd->dma->src_f1_bottom - omap_lcd->dma->src_f1_top;
                    179:     else
                    180:         size = omap_lcd->dma->src_f2_bottom - omap_lcd->dma->src_f2_top;
                    181: 
                    182:     if (frame_offset + ((width * omap_lcd->height * bpp) >> 3) > size + 2) {
                    183:         omap_lcd->sync_error = 1;
                    184:         omap_lcd_interrupts(omap_lcd);
                    185:         omap_lcd->enable = 0;
                    186:         return;
                    187:     }
                    188: 
                    189:     /* Content */
                    190:     frame_base = omap_lcd->dma->phys_framebuffer[
                    191:             omap_lcd->dma->current_frame] + frame_offset;
                    192:     omap_lcd->dma->condition |= 1 << omap_lcd->dma->current_frame;
                    193:     if (omap_lcd->dma->interrupts & 1)
                    194:         qemu_irq_raise(omap_lcd->dma->irq);
                    195:     if (omap_lcd->dma->dual)
                    196:         omap_lcd->dma->current_frame ^= 1;
                    197: 
1.1.1.2   root      198:     if (!ds_get_bits_per_pixel(omap_lcd->state))
1.1       root      199:         return;
                    200: 
1.1.1.3   root      201:     first = 0;
1.1       root      202:     height = omap_lcd->height;
                    203:     if (omap_lcd->subpanel & (1 << 31)) {
                    204:         if (omap_lcd->subpanel & (1 << 29))
1.1.1.3   root      205:             first = (omap_lcd->subpanel >> 16) & 0x3ff;
1.1       root      206:         else
                    207:             height = (omap_lcd->subpanel >> 16) & 0x3ff;
                    208:         /* TODO: fill the rest of the panel with DPD */
                    209:     }
1.1.1.3   root      210: 
1.1       root      211:     step = width * bpp >> 3;
1.1.1.2   root      212:     linesize = ds_get_linesize(omap_lcd->state);
1.1.1.3   root      213:     framebuffer_update_display(omap_lcd->state,
                    214:                                frame_base, width, height,
                    215:                                step, linesize, 0,
                    216:                                omap_lcd->invalidate,
                    217:                                draw_line, omap_lcd->palette,
                    218:                                &first, &last);
                    219:     if (first >= 0) {
                    220:         dpy_update(omap_lcd->state, 0, first, width, last - first + 1);
1.1       root      221:     }
1.1.1.3   root      222:     omap_lcd->invalidate = 0;
1.1       root      223: }
                    224: 
                    225: static int ppm_save(const char *filename, uint8_t *data,
                    226:                 int w, int h, int linesize)
                    227: {
                    228:     FILE *f;
                    229:     uint8_t *d, *d1;
                    230:     unsigned int v;
                    231:     int y, x, bpp;
                    232: 
                    233:     f = fopen(filename, "wb");
                    234:     if (!f)
                    235:         return -1;
                    236:     fprintf(f, "P6\n%d %d\n%d\n", w, h, 255);
                    237:     d1 = data;
                    238:     bpp = linesize / w;
                    239:     for (y = 0; y < h; y ++) {
                    240:         d = d1;
                    241:         for (x = 0; x < w; x ++) {
                    242:             v = *(uint32_t *) d;
                    243:             switch (bpp) {
                    244:             case 2:
                    245:                 fputc((v >> 8) & 0xf8, f);
                    246:                 fputc((v >> 3) & 0xfc, f);
                    247:                 fputc((v << 3) & 0xf8, f);
                    248:                 break;
                    249:             case 3:
                    250:             case 4:
                    251:             default:
                    252:                 fputc((v >> 16) & 0xff, f);
                    253:                 fputc((v >> 8) & 0xff, f);
                    254:                 fputc((v) & 0xff, f);
                    255:                 break;
                    256:             }
                    257:             d += bpp;
                    258:         }
                    259:         d1 += linesize;
                    260:     }
                    261:     fclose(f);
                    262:     return 0;
                    263: }
                    264: 
                    265: static void omap_screen_dump(void *opaque, const char *filename) {
                    266:     struct omap_lcd_panel_s *omap_lcd = opaque;
                    267:     omap_update_display(opaque);
1.1.1.2   root      268:     if (omap_lcd && ds_get_data(omap_lcd->state))
                    269:         ppm_save(filename, ds_get_data(omap_lcd->state),
1.1       root      270:                 omap_lcd->width, omap_lcd->height,
1.1.1.2   root      271:                 ds_get_linesize(omap_lcd->state));
1.1       root      272: }
                    273: 
                    274: static void omap_invalidate_display(void *opaque) {
                    275:     struct omap_lcd_panel_s *omap_lcd = opaque;
                    276:     omap_lcd->invalidate = 1;
                    277: }
                    278: 
                    279: static void omap_lcd_update(struct omap_lcd_panel_s *s) {
                    280:     if (!s->enable) {
                    281:         s->dma->current_frame = -1;
                    282:         s->sync_error = 0;
                    283:         if (s->plm != 1)
                    284:             s->frame_done = 1;
                    285:         omap_lcd_interrupts(s);
                    286:         return;
                    287:     }
                    288: 
                    289:     if (s->dma->current_frame == -1) {
                    290:         s->frame_done = 0;
                    291:         s->palette_done = 0;
                    292:         s->dma->current_frame = 0;
                    293:     }
                    294: 
                    295:     if (!s->dma->mpu->port[s->dma->src].addr_valid(s->dma->mpu,
                    296:                             s->dma->src_f1_top) ||
                    297:                     !s->dma->mpu->port[
                    298:                     s->dma->src].addr_valid(s->dma->mpu,
                    299:                             s->dma->src_f1_bottom) ||
                    300:                     (s->dma->dual &&
                    301:                      (!s->dma->mpu->port[
                    302:                       s->dma->src].addr_valid(s->dma->mpu,
                    303:                               s->dma->src_f2_top) ||
                    304:                       !s->dma->mpu->port[
                    305:                       s->dma->src].addr_valid(s->dma->mpu,
                    306:                               s->dma->src_f2_bottom)))) {
                    307:         s->dma->condition |= 1 << 2;
                    308:         if (s->dma->interrupts & (1 << 1))
                    309:             qemu_irq_raise(s->dma->irq);
                    310:         s->enable = 0;
                    311:         return;
                    312:     }
                    313: 
1.1.1.3   root      314:     s->dma->phys_framebuffer[0] = s->dma->src_f1_top;
                    315:     s->dma->phys_framebuffer[1] = s->dma->src_f2_top;
1.1       root      316: 
                    317:     if (s->plm != 2 && !s->palette_done) {
1.1.1.3   root      318:         cpu_physical_memory_read(
                    319:             s->dma->phys_framebuffer[s->dma->current_frame],
                    320:             (void *)s->palette, 0x200);
1.1       root      321:         s->palette_done = 1;
                    322:         omap_lcd_interrupts(s);
                    323:     }
                    324: }
                    325: 
                    326: static uint32_t omap_lcdc_read(void *opaque, target_phys_addr_t addr)
                    327: {
                    328:     struct omap_lcd_panel_s *s = (struct omap_lcd_panel_s *) opaque;
                    329: 
1.1.1.2   root      330:     switch (addr) {
1.1       root      331:     case 0x00: /* LCD_CONTROL */
                    332:         return (s->tft << 23) | (s->plm << 20) |
                    333:                 (s->tft << 7) | (s->interrupts << 3) |
                    334:                 (s->mono << 1) | s->enable | s->ctrl | 0xfe000c34;
                    335: 
                    336:     case 0x04: /* LCD_TIMING0 */
                    337:         return (s->timing[0] << 10) | (s->width - 1) | 0x0000000f;
                    338: 
                    339:     case 0x08: /* LCD_TIMING1 */
                    340:         return (s->timing[1] << 10) | (s->height - 1);
                    341: 
                    342:     case 0x0c: /* LCD_TIMING2 */
                    343:         return s->timing[2] | 0xfc000000;
                    344: 
                    345:     case 0x10: /* LCD_STATUS */
                    346:         return (s->palette_done << 6) | (s->sync_error << 2) | s->frame_done;
                    347: 
                    348:     case 0x14: /* LCD_SUBPANEL */
                    349:         return s->subpanel;
                    350: 
                    351:     default:
                    352:         break;
                    353:     }
                    354:     OMAP_BAD_REG(addr);
                    355:     return 0;
                    356: }
                    357: 
                    358: static void omap_lcdc_write(void *opaque, target_phys_addr_t addr,
                    359:                 uint32_t value)
                    360: {
                    361:     struct omap_lcd_panel_s *s = (struct omap_lcd_panel_s *) opaque;
                    362: 
1.1.1.2   root      363:     switch (addr) {
1.1       root      364:     case 0x00: /* LCD_CONTROL */
                    365:         s->plm = (value >> 20) & 3;
                    366:         s->tft = (value >> 7) & 1;
                    367:         s->interrupts = (value >> 3) & 3;
                    368:         s->mono = (value >> 1) & 1;
                    369:         s->ctrl = value & 0x01cff300;
                    370:         if (s->enable != (value & 1)) {
                    371:             s->enable = value & 1;
                    372:             omap_lcd_update(s);
                    373:         }
                    374:         break;
                    375: 
                    376:     case 0x04: /* LCD_TIMING0 */
                    377:         s->timing[0] = value >> 10;
                    378:         s->width = (value & 0x3ff) + 1;
                    379:         break;
                    380: 
                    381:     case 0x08: /* LCD_TIMING1 */
                    382:         s->timing[1] = value >> 10;
                    383:         s->height = (value & 0x3ff) + 1;
                    384:         break;
                    385: 
                    386:     case 0x0c: /* LCD_TIMING2 */
                    387:         s->timing[2] = value;
                    388:         break;
                    389: 
                    390:     case 0x10: /* LCD_STATUS */
                    391:         break;
                    392: 
                    393:     case 0x14: /* LCD_SUBPANEL */
                    394:         s->subpanel = value & 0xa1ffffff;
                    395:         break;
                    396: 
                    397:     default:
                    398:         OMAP_BAD_REG(addr);
                    399:     }
                    400: }
                    401: 
1.1.1.4   root      402: static CPUReadMemoryFunc * const omap_lcdc_readfn[] = {
1.1       root      403:     omap_lcdc_read,
                    404:     omap_lcdc_read,
                    405:     omap_lcdc_read,
                    406: };
                    407: 
1.1.1.4   root      408: static CPUWriteMemoryFunc * const omap_lcdc_writefn[] = {
1.1       root      409:     omap_lcdc_write,
                    410:     omap_lcdc_write,
                    411:     omap_lcdc_write,
                    412: };
                    413: 
                    414: void omap_lcdc_reset(struct omap_lcd_panel_s *s)
                    415: {
                    416:     s->dma->current_frame = -1;
                    417:     s->plm = 0;
                    418:     s->tft = 0;
                    419:     s->mono = 0;
                    420:     s->enable = 0;
                    421:     s->width = 0;
                    422:     s->height = 0;
                    423:     s->interrupts = 0;
                    424:     s->timing[0] = 0;
                    425:     s->timing[1] = 0;
                    426:     s->timing[2] = 0;
                    427:     s->subpanel = 0;
                    428:     s->palette_done = 0;
                    429:     s->frame_done = 0;
                    430:     s->sync_error = 0;
                    431:     s->invalidate = 1;
                    432:     s->subpanel = 0;
                    433:     s->ctrl = 0;
                    434: }
                    435: 
                    436: struct omap_lcd_panel_s *omap_lcdc_init(target_phys_addr_t base, qemu_irq irq,
1.1.1.6 ! root      437:                 struct omap_dma_lcd_channel_s *dma, omap_clk clk)
1.1       root      438: {
                    439:     int iomemtype;
                    440:     struct omap_lcd_panel_s *s = (struct omap_lcd_panel_s *)
1.1.1.6 ! root      441:             g_malloc0(sizeof(struct omap_lcd_panel_s));
1.1       root      442: 
                    443:     s->irq = irq;
                    444:     s->dma = dma;
                    445:     omap_lcdc_reset(s);
                    446: 
1.1.1.3   root      447:     iomemtype = cpu_register_io_memory(omap_lcdc_readfn,
1.1.1.5   root      448:                     omap_lcdc_writefn, s, DEVICE_NATIVE_ENDIAN);
1.1.1.2   root      449:     cpu_register_physical_memory(base, 0x100, iomemtype);
1.1       root      450: 
1.1.1.2   root      451:     s->state = graphic_console_init(omap_update_display,
                    452:                                     omap_invalidate_display,
                    453:                                     omap_screen_dump, NULL, s);
1.1       root      454: 
                    455:     return s;
                    456: }

unix.superglobalmegacorp.com