(linenum→info "unix/slp.c:2238")

qemu/0.9.1/hw/omap_lcdc.c

    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: }
1
Syntax (Markdown)