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

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
        !            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: }

unix.superglobalmegacorp.com