Statistics
| Branch: | Revision:

root / hw / omap_lcdc.c @ 9b32d5a5

History | View | Annotate | Download (13.7 kB)

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