Browse Source
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1746 c046a42c-6fe2-441c-8c8c-71466251a162stable-0.10
5 changed files with 657 additions and 1 deletions
@ -0,0 +1,393 @@ |
|||
/*
|
|||
* Arm PrimeCell PL110 Color LCD Controller |
|||
* |
|||
* Copyright (c) 2005 CodeSourcery, LLC. |
|||
* Written by Paul Brook |
|||
* |
|||
* This code is licenced under the GNU LGPL |
|||
*/ |
|||
|
|||
#include "vl.h" |
|||
|
|||
#define PL110_CR_EN 0x001 |
|||
#define PL110_CR_BEBO 0x200 |
|||
#define PL110_CR_BEPO 0x400 |
|||
#define PL110_CR_PWR 0x800 |
|||
|
|||
enum pl110_bppmode |
|||
{ |
|||
BPP_1, |
|||
BPP_2, |
|||
BPP_4, |
|||
BPP_8, |
|||
BPP_16, |
|||
BPP_32 |
|||
}; |
|||
|
|||
typedef struct { |
|||
uint32_t base; |
|||
DisplayState *ds; |
|||
void *pic; |
|||
uint32_t timing[4]; |
|||
uint32_t cr; |
|||
uint32_t upbase; |
|||
uint32_t lpbase; |
|||
uint32_t int_status; |
|||
uint32_t int_mask; |
|||
int cols; |
|||
int rows; |
|||
enum pl110_bppmode bpp; |
|||
int invalidate; |
|||
uint32_t pallette[256]; |
|||
uint32_t raw_pallette[128]; |
|||
int irq; |
|||
} pl110_state; |
|||
|
|||
static const unsigned char pl110_id[] = |
|||
{ 0x10, 0x11, 0x04, 0x00, 0x0d, 0xf0, 0x05, 0xb1 }; |
|||
|
|||
static inline uint32_t rgb_to_pixel8(unsigned int r, unsigned int g, unsigned b) |
|||
{ |
|||
return ((r >> 5) << 5) | ((g >> 5) << 2) | (b >> 6); |
|||
} |
|||
|
|||
static inline uint32_t rgb_to_pixel15(unsigned int r, unsigned int g, unsigned b) |
|||
{ |
|||
return ((r >> 3) << 10) | ((g >> 3) << 5) | (b >> 3); |
|||
} |
|||
|
|||
static inline uint32_t rgb_to_pixel16(unsigned int r, unsigned int g, unsigned b) |
|||
{ |
|||
return ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3); |
|||
} |
|||
|
|||
static inline uint32_t rgb_to_pixel24(unsigned int r, unsigned int g, unsigned b) |
|||
{ |
|||
return (r << 16) | (g << 8) | b; |
|||
} |
|||
|
|||
static inline uint32_t rgb_to_pixel32(unsigned int r, unsigned int g, unsigned b) |
|||
{ |
|||
return (r << 16) | (g << 8) | b; |
|||
} |
|||
|
|||
typedef void (*drawfn)(uint32_t *, uint8_t *, const uint8_t *, int); |
|||
|
|||
#define BITS 8 |
|||
#include "pl110_template.h" |
|||
#define BITS 15 |
|||
#include "pl110_template.h" |
|||
#define BITS 16 |
|||
#include "pl110_template.h" |
|||
#define BITS 24 |
|||
#include "pl110_template.h" |
|||
#define BITS 32 |
|||
#include "pl110_template.h" |
|||
|
|||
static int pl110_enabled(pl110_state *s) |
|||
{ |
|||
return (s->cr & PL110_CR_EN) && (s->cr & PL110_CR_PWR); |
|||
} |
|||
|
|||
void pl110_update_display(void *opaque) |
|||
{ |
|||
pl110_state *s = (pl110_state *)opaque; |
|||
drawfn* fntable; |
|||
drawfn fn; |
|||
uint32_t *pallette; |
|||
uint32_t addr; |
|||
uint32_t base; |
|||
int dest_width; |
|||
int src_width; |
|||
uint8_t *dest; |
|||
uint8_t *src; |
|||
int first, last; |
|||
int dirty, new_dirty; |
|||
int i; |
|||
|
|||
if (!pl110_enabled(s)) |
|||
return; |
|||
|
|||
switch (s->ds->depth) { |
|||
case 8: |
|||
fntable = pl110_draw_fn_8; |
|||
dest_width = 1; |
|||
break; |
|||
case 15: |
|||
fntable = pl110_draw_fn_15; |
|||
dest_width = 2; |
|||
break; |
|||
case 16: |
|||
fntable = pl110_draw_fn_16; |
|||
dest_width = 2; |
|||
break; |
|||
case 24: |
|||
fntable = pl110_draw_fn_24; |
|||
dest_width = 3; |
|||
break; |
|||
case 32: |
|||
fntable = pl110_draw_fn_32; |
|||
dest_width = 4; |
|||
break; |
|||
default: |
|||
fprintf(stderr, "qemu: Bad color depth\n"); |
|||
exit(1); |
|||
} |
|||
if (s->cr & PL110_CR_BEBO) |
|||
fn = fntable[s->bpp + 6]; |
|||
else if (s->cr & PL110_CR_BEPO) |
|||
fn = fntable[s->bpp + 12]; |
|||
else |
|||
fn = fntable[s->bpp]; |
|||
|
|||
src_width = s->cols; |
|||
switch (s->bpp) { |
|||
case BPP_1: |
|||
src_width >>= 3; |
|||
break; |
|||
case BPP_2: |
|||
src_width >>= 2; |
|||
break; |
|||
case BPP_4: |
|||
src_width >>= 1; |
|||
break; |
|||
case BPP_8: |
|||
break; |
|||
case BPP_16: |
|||
src_width <<= 1; |
|||
break; |
|||
case BPP_32: |
|||
src_width <<= 2; |
|||
break; |
|||
} |
|||
dest_width *= s->cols; |
|||
pallette = s->pallette; |
|||
base = s->upbase; |
|||
/* HACK: Arm aliases physical memory at 0x80000000. */ |
|||
if (base > 0x80000000) |
|||
base -= 0x80000000; |
|||
src = phys_ram_base + base; |
|||
dest = s->ds->data; |
|||
first = -1; |
|||
addr = base; |
|||
|
|||
dirty = cpu_physical_memory_get_dirty(addr, VGA_DIRTY_FLAG); |
|||
for (i = 0; i < s->rows; i++) { |
|||
new_dirty = 0; |
|||
if ((addr & TARGET_PAGE_MASK) + src_width >= TARGET_PAGE_SIZE) { |
|||
uint32_t tmp; |
|||
for (tmp = 0; tmp < src_width; tmp += TARGET_PAGE_SIZE) { |
|||
new_dirty |= cpu_physical_memory_get_dirty(addr + tmp, |
|||
VGA_DIRTY_FLAG); |
|||
} |
|||
} |
|||
|
|||
if (dirty || new_dirty || s->invalidate) { |
|||
fn(pallette, dest, src, s->cols); |
|||
if (first == -1) |
|||
first = i; |
|||
last = i; |
|||
} |
|||
dirty = new_dirty; |
|||
addr += src_width; |
|||
dest += dest_width; |
|||
src += src_width; |
|||
} |
|||
if (first < 0) |
|||
return; |
|||
|
|||
s->invalidate = 0; |
|||
cpu_physical_memory_reset_dirty(base + first * src_width, |
|||
base + (last + 1) * src_width, |
|||
VGA_DIRTY_FLAG); |
|||
dpy_update(s->ds, 0, first, s->cols, last - first + 1); |
|||
} |
|||
|
|||
void pl110_invalidate_display(void * opaque) |
|||
{ |
|||
pl110_state *s = (pl110_state *)opaque; |
|||
s->invalidate = 1; |
|||
} |
|||
|
|||
static void pl110_update_pallette(pl110_state *s, int n) |
|||
{ |
|||
int i; |
|||
uint32_t raw; |
|||
unsigned int r, g, b; |
|||
|
|||
raw = s->raw_pallette[n]; |
|||
n <<= 1; |
|||
for (i = 0; i < 2; i++) { |
|||
r = (raw & 0x1f) << 3; |
|||
raw >>= 5; |
|||
g = (raw & 0x1f) << 3; |
|||
raw >>= 5; |
|||
b = (raw & 0x1f) << 3; |
|||
/* The I bit is ignored. */ |
|||
raw >>= 6; |
|||
switch (s->ds->depth) { |
|||
case 8: |
|||
s->pallette[n] = rgb_to_pixel8(r, g, b); |
|||
break; |
|||
case 15: |
|||
s->pallette[n] = rgb_to_pixel15(r, g, b); |
|||
break; |
|||
case 16: |
|||
s->pallette[n] = rgb_to_pixel16(r, g, b); |
|||
break; |
|||
case 24: |
|||
case 32: |
|||
s->pallette[n] = rgb_to_pixel32(r, g, b); |
|||
break; |
|||
} |
|||
n++; |
|||
} |
|||
} |
|||
|
|||
static void pl110_resize(pl110_state *s, int width, int height) |
|||
{ |
|||
if (width != s->cols || height != s->rows) { |
|||
if (pl110_enabled(s)) { |
|||
dpy_resize(s->ds, s->cols, s->rows); |
|||
} |
|||
} |
|||
s->cols = width; |
|||
s->rows = height; |
|||
} |
|||
|
|||
/* Update interrupts. */ |
|||
static void pl110_update(pl110_state *s) |
|||
{ |
|||
/* TODO: Implement interrupts. */ |
|||
} |
|||
|
|||
static uint32_t pl110_read(void *opaque, target_phys_addr_t offset) |
|||
{ |
|||
pl110_state *s = (pl110_state *)opaque; |
|||
|
|||
offset -= s->base; |
|||
if (offset >= 0xfe0 && offset < 0x1000) { |
|||
return pl110_id[(offset - 0xfe0) >> 2]; |
|||
} |
|||
if (offset >= 0x200 && offset < 0x400) { |
|||
return s->raw_pallette[(offset - 0x200) >> 2]; |
|||
} |
|||
switch (offset >> 2) { |
|||
case 0: /* LCDTiming0 */ |
|||
return s->timing[0]; |
|||
case 1: /* LCDTiming1 */ |
|||
return s->timing[1]; |
|||
case 2: /* LCDTiming2 */ |
|||
return s->timing[2]; |
|||
case 3: /* LCDTiming3 */ |
|||
return s->timing[3]; |
|||
case 4: /* LCDUPBASE */ |
|||
return s->upbase; |
|||
case 5: /* LCDLPBASE */ |
|||
return s->lpbase; |
|||
case 6: /* LCDIMSC */ |
|||
return s->int_mask; |
|||
case 7: /* LCDControl */ |
|||
return s->cr; |
|||
case 8: /* LCDRIS */ |
|||
return s->int_status; |
|||
case 9: /* LCDMIS */ |
|||
return s->int_status & s->int_mask; |
|||
case 11: /* LCDUPCURR */ |
|||
/* TODO: Implement vertical refresh. */ |
|||
return s->upbase; |
|||
case 12: /* LCDLPCURR */ |
|||
return s->lpbase; |
|||
default: |
|||
cpu_abort (cpu_single_env, "pl110_read: Bad offset %x\n", offset); |
|||
return 0; |
|||
} |
|||
} |
|||
|
|||
static void pl110_write(void *opaque, target_phys_addr_t offset, |
|||
uint32_t val) |
|||
{ |
|||
pl110_state *s = (pl110_state *)opaque; |
|||
int n; |
|||
|
|||
/* For simplicity invalidate the display whenever a control register
|
|||
is writen to. */ |
|||
s->invalidate = 1; |
|||
offset -= s->base; |
|||
if (offset >= 0x200 && offset < 0x400) { |
|||
/* Pallette. */ |
|||
n = (offset - 0x200) >> 2; |
|||
s->raw_pallette[(offset - 0x200) >> 2] = val; |
|||
pl110_update_pallette(s, n); |
|||
} |
|||
switch (offset >> 2) { |
|||
case 0: /* LCDTiming0 */ |
|||
s->timing[0] = val; |
|||
n = ((val & 0xfc) + 4) * 4; |
|||
pl110_resize(s, n, s->rows); |
|||
break; |
|||
case 1: /* LCDTiming1 */ |
|||
s->timing[1] = val; |
|||
n = (val & 0x3ff) + 1; |
|||
pl110_resize(s, s->cols, n); |
|||
break; |
|||
case 2: /* LCDTiming2 */ |
|||
s->timing[2] = val; |
|||
break; |
|||
case 3: /* LCDTiming3 */ |
|||
s->timing[3] = val; |
|||
break; |
|||
case 4: /* LCDUPBASE */ |
|||
s->upbase = val; |
|||
break; |
|||
case 5: /* LCDLPBASE */ |
|||
s->lpbase = val; |
|||
break; |
|||
case 6: /* LCDIMSC */ |
|||
s->int_mask = val; |
|||
pl110_update(s); |
|||
break; |
|||
case 7: /* LCDControl */ |
|||
s->cr = val; |
|||
s->bpp = (val >> 1) & 7; |
|||
if (pl110_enabled(s)) { |
|||
dpy_resize(s->ds, s->cols, s->rows); |
|||
} |
|||
break; |
|||
case 10: /* LCDICR */ |
|||
s->int_status &= ~val; |
|||
pl110_update(s); |
|||
break; |
|||
default: |
|||
cpu_abort (cpu_single_env, "pl110_write: Bad offset %x\n", offset); |
|||
} |
|||
} |
|||
|
|||
static CPUReadMemoryFunc *pl110_readfn[] = { |
|||
pl110_read, |
|||
pl110_read, |
|||
pl110_read |
|||
}; |
|||
|
|||
static CPUWriteMemoryFunc *pl110_writefn[] = { |
|||
pl110_write, |
|||
pl110_write, |
|||
pl110_write |
|||
}; |
|||
|
|||
void *pl110_init(DisplayState *ds, uint32_t base, void *pic, int irq) |
|||
{ |
|||
pl110_state *s; |
|||
int iomemtype; |
|||
|
|||
s = (pl110_state *)qemu_mallocz(sizeof(pl110_state)); |
|||
iomemtype = cpu_register_io_memory(0, pl110_readfn, |
|||
pl110_writefn, s); |
|||
cpu_register_physical_memory(base, 0x007fffff, iomemtype); |
|||
s->base = base; |
|||
s->ds = ds; |
|||
s->pic = pic; |
|||
s->irq = irq; |
|||
/* ??? Save/restore. */ |
|||
return s; |
|||
} |
|||
@ -0,0 +1,252 @@ |
|||
/*
|
|||
* Arm PrimeCell PL110 Color LCD Controller |
|||
* |
|||
* Copyright (c) 2005 CodeSourcery, LLC. |
|||
* Written by Paul Brook |
|||
* |
|||
* This code is licenced under the GNU LGPL |
|||
* |
|||
* Framebuffer format conversion routines. |
|||
*/ |
|||
|
|||
#ifndef ORDER |
|||
|
|||
#if BITS == 8 |
|||
#define COPY_PIXEL(to, from) *(to++) = from |
|||
#elif BITS == 15 || BITS == 16 |
|||
#define COPY_PIXEL(to, from) *(uint16_t *)to = from; to += 2; |
|||
#elif BITS == 24 |
|||
#define COPY_PIXEL(to, from) \ |
|||
*(to++) = from; *(to++) = (from) >> 8; *(to++) = (from) >> 16 |
|||
#elif BITS == 32 |
|||
#define COPY_PIXEL(to, from) *(uint32_t *)to = from; to += 4; |
|||
#else |
|||
#error unknown bit depth |
|||
#endif |
|||
|
|||
#define ORDER 0 |
|||
#include "pl110_template.h" |
|||
#define ORDER 1 |
|||
#include "pl110_template.h" |
|||
#define ORDER 2 |
|||
#include "pl110_template.h" |
|||
|
|||
static drawfn glue(pl110_draw_fn_,BITS)[18] = |
|||
{ |
|||
glue(pl110_draw_line1_lblp,BITS), |
|||
glue(pl110_draw_line2_lblp,BITS), |
|||
glue(pl110_draw_line4_lblp,BITS), |
|||
glue(pl110_draw_line8_lblp,BITS), |
|||
glue(pl110_draw_line16_lblp,BITS), |
|||
glue(pl110_draw_line32_lblp,BITS), |
|||
|
|||
glue(pl110_draw_line1_bbbp,BITS), |
|||
glue(pl110_draw_line2_bbbp,BITS), |
|||
glue(pl110_draw_line4_bbbp,BITS), |
|||
glue(pl110_draw_line8_bbbp,BITS), |
|||
glue(pl110_draw_line16_bbbp,BITS), |
|||
glue(pl110_draw_line32_bbbp,BITS), |
|||
|
|||
glue(pl110_draw_line1_lbbp,BITS), |
|||
glue(pl110_draw_line2_lbbp,BITS), |
|||
glue(pl110_draw_line4_lbbp,BITS), |
|||
glue(pl110_draw_line8_lbbp,BITS), |
|||
glue(pl110_draw_line16_lbbp,BITS), |
|||
glue(pl110_draw_line32_lbbp,BITS) |
|||
}; |
|||
|
|||
#undef BITS |
|||
#undef COPY_PIXEL |
|||
|
|||
#else |
|||
|
|||
#if ORDER == 0 |
|||
#define NAME glue(lblp, BITS) |
|||
#ifdef WORDS_BIGENDIAN |
|||
#define SWAP_WORDS 1 |
|||
#endif |
|||
#elif ORDER == 1 |
|||
#define NAME glue(bbbp, BITS) |
|||
#ifndef WORDS_BIGENDIAN |
|||
#define SWAP_WORDS 1 |
|||
#endif |
|||
#else |
|||
#define SWAP_PIXELS 1 |
|||
#define NAME glue(lbbp, BITS) |
|||
#ifdef WORDS_BIGENDIAN |
|||
#define SWAP_WORDS 1 |
|||
#endif |
|||
#endif |
|||
|
|||
#define FN_2(x, y) FN(x, y) FN(x+1, y) |
|||
#define FN_4(x, y) FN_2(x, y) FN_2(x+1, y) |
|||
#define FN_8(y) FN_4(0, y) FN_4(4, y) |
|||
|
|||
static void glue(pl110_draw_line1_,NAME)(uint32_t *pallette, uint8_t *d, const uint8_t *src, int width) |
|||
{ |
|||
uint32_t data; |
|||
while (width > 0) { |
|||
data = *(uint32_t *)src; |
|||
#ifdef SWAP_PIXELS |
|||
#define FN(x, y) COPY_PIXEL(d, pallette[(data >> (y + 7 - (x))) & 1]); |
|||
#else |
|||
#define FN(x, y) COPY_PIXEL(d, pallette[(data >> ((x) + y)) & 1]); |
|||
#endif |
|||
#ifdef SWAP_BYTES |
|||
FN_8(24) |
|||
FN_8(16) |
|||
FN_8(8) |
|||
FN_8(0) |
|||
#else |
|||
FN_8(0) |
|||
FN_8(8) |
|||
FN_8(16) |
|||
FN_8(24) |
|||
#endif |
|||
#undef FN |
|||
width -= 32; |
|||
src += 4; |
|||
} |
|||
} |
|||
|
|||
static void glue(pl110_draw_line2_,NAME)(uint32_t *pallette, uint8_t *d, const uint8_t *src, int width) |
|||
{ |
|||
uint32_t data; |
|||
while (width > 0) { |
|||
data = *(uint32_t *)src; |
|||
#ifdef SWAP_PIXELS |
|||
#define FN(x, y) COPY_PIXEL(d, pallette[(data >> (y + 6 - (x)*2)) & 3]); |
|||
#else |
|||
#define FN(x, y) COPY_PIXEL(d, pallette[(data >> ((x)*2 + y)) & 3]); |
|||
#endif |
|||
#ifdef SWAP_BYTES |
|||
FN_4(0, 24) |
|||
FN_4(0, 16) |
|||
FN_4(0, 8) |
|||
FN_4(0, 0) |
|||
#else |
|||
FN_4(0, 0) |
|||
FN_4(0, 8) |
|||
FN_4(0, 16) |
|||
FN_4(0, 24) |
|||
#endif |
|||
#undef FN |
|||
width -= 16; |
|||
src += 4; |
|||
} |
|||
} |
|||
|
|||
static void glue(pl110_draw_line4_,NAME)(uint32_t *pallette, uint8_t *d, const uint8_t *src, int width) |
|||
{ |
|||
uint32_t data; |
|||
while (width > 0) { |
|||
data = *(uint32_t *)src; |
|||
#ifdef SWAP_PIXELS |
|||
#define FN(x, y) COPY_PIXEL(d, pallette[(data >> (y + 4 - (x)*4)) & 0xf]); |
|||
#else |
|||
#define FN(x, y) COPY_PIXEL(d, pallette[(data >> ((x)*4 + y)) & 0xf]); |
|||
#endif |
|||
#ifdef SWAP_BYTES |
|||
FN_2(0, 24) |
|||
FN_2(0, 16) |
|||
FN_2(0, 8) |
|||
FN_2(0, 0) |
|||
#else |
|||
FN_2(0, 0) |
|||
FN_2(0, 8) |
|||
FN_2(0, 16) |
|||
FN_2(0, 24) |
|||
#endif |
|||
#undef FN |
|||
width -= 8; |
|||
src += 4; |
|||
} |
|||
} |
|||
|
|||
static void glue(pl110_draw_line8_,NAME)(uint32_t *pallette, uint8_t *d, const uint8_t *src, int width) |
|||
{ |
|||
uint32_t data; |
|||
while (width > 0) { |
|||
data = *(uint32_t *)src; |
|||
#define FN(x) COPY_PIXEL(d, pallette[(data >> (x)) & 0xff]); |
|||
#ifdef SWAP_BYTES |
|||
FN(24) |
|||
FN(16) |
|||
FN(8) |
|||
FN(0) |
|||
#else |
|||
FN(0) |
|||
FN(8) |
|||
FN(16) |
|||
FN(24) |
|||
#endif |
|||
#undef FN |
|||
width -= 4; |
|||
src += 4; |
|||
} |
|||
} |
|||
|
|||
static void glue(pl110_draw_line16_,NAME)(uint32_t *pallette, uint8_t *d, const uint8_t *src, int width) |
|||
{ |
|||
uint32_t data; |
|||
unsigned int r, g, b; |
|||
while (width > 0) { |
|||
data = *(uint32_t *)src; |
|||
#ifdef SWAP_BYTES |
|||
data = bswap32(data); |
|||
#endif |
|||
#if 0 |
|||
r = data & 0x1f; |
|||
data >>= 5; |
|||
g = data & 0x3f; |
|||
data >>= 6; |
|||
b = data & 0x1f; |
|||
data >>= 5; |
|||
#else |
|||
r = (data & 0x1f) << 3; |
|||
data >>= 5; |
|||
g = (data & 0x3f) << 2; |
|||
data >>= 6; |
|||
b = (data & 0x1f) << 3; |
|||
data >>= 5; |
|||
#endif |
|||
COPY_PIXEL(d, glue(rgb_to_pixel,BITS)(r, g, b)); |
|||
r = (data & 0x1f) << 3; |
|||
data >>= 5; |
|||
g = (data & 0x3f) << 2; |
|||
data >>= 6; |
|||
b = (data & 0x1f) << 3; |
|||
data >>= 5; |
|||
COPY_PIXEL(d, glue(rgb_to_pixel,BITS)(r, g, b)); |
|||
width -= 2; |
|||
src += 4; |
|||
} |
|||
} |
|||
|
|||
static void glue(pl110_draw_line32_,NAME)(uint32_t *pallette, uint8_t *d, const uint8_t *src, int width) |
|||
{ |
|||
uint32_t data; |
|||
unsigned int r, g, b; |
|||
while (width > 0) { |
|||
data = *(uint32_t *)src; |
|||
#ifdef SWAP_BYTES |
|||
r = data & 0xff; |
|||
g = (data >> 8) & 0xff; |
|||
b = (data >> 16) & 0xff; |
|||
#else |
|||
r = (data >> 24) & 0xff; |
|||
g = (data >> 16) & 0xff; |
|||
b = (data >> 8) & 0xff; |
|||
#endif |
|||
COPY_PIXEL(d, glue(rgb_to_pixel,BITS)(r, g, b)); |
|||
width--; |
|||
src += 4; |
|||
} |
|||
} |
|||
|
|||
#undef SWAP_PIXELS |
|||
#undef NAME |
|||
#undef SWAP_WORDS |
|||
#undef ORDER |
|||
|
|||
#endif |
|||
Loading…
Reference in new issue