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

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

unix.superglobalmegacorp.com