diff options
-rw-r--r-- | hw/sm501.c | 172 |
1 files changed, 169 insertions, 3 deletions
diff --git a/hw/sm501.c b/hw/sm501.c index 931001479a..b5ec2dae9c 100644 --- a/hw/sm501.c +++ b/hw/sm501.c @@ -31,16 +31,16 @@ #include "qdev-addr.h" /* - * Status: 2008/11/02 + * Status: 2010/05/07 * - Minimum implementation for Linux console : mmio regs and CRT layer. - * - Always updates full screen. + * - 2D grapihcs acceleration partially supported : only fill rectangle. * * TODO: * - Panel support - * - Hardware cursor support * - Touch panel support * - USB support * - UART support + * - More 2D graphics engine support * - Performance tuning */ @@ -510,6 +510,18 @@ typedef struct SM501State { uint32_t dc_crt_hwc_color_1_2; uint32_t dc_crt_hwc_color_3; + uint32_t twoD_destination; + uint32_t twoD_dimension; + uint32_t twoD_control; + uint32_t twoD_pitch; + uint32_t twoD_foreground; + uint32_t twoD_stretch; + uint32_t twoD_color_compare_mask; + uint32_t twoD_mask; + uint32_t twoD_window_width; + uint32_t twoD_source_base; + uint32_t twoD_destination_base; + } SM501State; static uint32_t get_local_mem_size_index(uint32_t size) @@ -619,6 +631,69 @@ static int within_hwc_y_range(SM501State *state, int y, int crt) return (hwc_y <= y && y < hwc_y + SM501_HWC_HEIGHT); } +static void sm501_2d_operation(SM501State * s) +{ + /* obtain operation parameters */ + int operation = (s->twoD_control >> 16) & 0x1f; + int dst_x = (s->twoD_destination >> 16) & 0x01FFF; + int dst_y = s->twoD_destination & 0xFFFF; + int operation_width = (s->twoD_dimension >> 16) & 0x1FFF; + int operation_height = s->twoD_dimension & 0xFFFF; + uint32_t color = s->twoD_foreground; + int format_flags = (s->twoD_stretch >> 20) & 0x3; + int addressing = (s->twoD_stretch >> 16) & 0xF; + + /* get frame buffer info */ +#if 0 /* for future use */ + uint8_t * src = s->local_mem + (s->twoD_source_base & 0x03FFFFFF); +#endif + uint8_t * dst = s->local_mem + (s->twoD_destination_base & 0x03FFFFFF); + int dst_width = (s->dc_crt_h_total & 0x00000FFF) + 1; + + if (addressing != 0x0) { + printf("%s: only XY addressing is supported.\n", __func__); + abort(); + } + + if ((s->twoD_source_base & 0x08000000) || + (s->twoD_destination_base & 0x08000000)) { + printf("%s: only local memory is supported.\n", __func__); + abort(); + } + + switch (operation) { + case 0x01: /* fill rectangle */ + +#define FILL_RECT(_bpp, _pixel_type) { \ + int y, x; \ + for (y = 0; y < operation_height; y++) { \ + for (x = 0; x < operation_width; x++) { \ + int index = ((dst_y + y) * dst_width + dst_x + x) * _bpp; \ + *(_pixel_type*)&dst[index] = (_pixel_type)color; \ + } \ + } \ + } + + switch (format_flags) { + case 0: + FILL_RECT(1, uint8_t); + break; + case 1: + FILL_RECT(2, uint16_t); + break; + case 2: + FILL_RECT(4, uint32_t); + break; + } + break; + + default: + printf("non-implemented SM501 2D operation. %d\n", operation); + abort(); + break; + } +} + static uint32_t sm501_system_config_read(void *opaque, target_phys_addr_t addr) { SM501State * s = (SM501State *)opaque; @@ -969,6 +1044,92 @@ static CPUWriteMemoryFunc * const sm501_disp_ctrl_writefn[] = { &sm501_disp_ctrl_write, }; +static uint32_t sm501_2d_engine_read(void *opaque, target_phys_addr_t addr) +{ + SM501State * s = (SM501State *)opaque; + uint32_t ret = 0; + SM501_DPRINTF("sm501 2d engine regs : read addr=%x\n", (int)addr); + + switch(addr) { + case SM501_2D_SOURCE_BASE: + ret = s->twoD_source_base; + break; + default: + printf("sm501 disp ctrl : not implemented register read." + " addr=%x\n", (int)addr); + abort(); + } + + return ret; +} + +static void sm501_2d_engine_write(void *opaque, + target_phys_addr_t addr, uint32_t value) +{ + SM501State * s = (SM501State *)opaque; + SM501_DPRINTF("sm501 2d engine regs : write addr=%x, val=%x\n", + addr, value); + + switch(addr) { + case SM501_2D_DESTINATION: + s->twoD_destination = value; + break; + case SM501_2D_DIMENSION: + s->twoD_dimension = value; + break; + case SM501_2D_CONTROL: + s->twoD_control = value; + + /* do 2d operation if start flag is set. */ + if (value & 0x80000000) { + sm501_2d_operation(s); + s->twoD_control &= ~0x80000000; /* start flag down */ + } + + break; + case SM501_2D_PITCH: + s->twoD_pitch = value; + break; + case SM501_2D_FOREGROUND: + s->twoD_foreground = value; + break; + case SM501_2D_STRETCH: + s->twoD_stretch = value; + break; + case SM501_2D_COLOR_COMPARE_MASK: + s->twoD_color_compare_mask = value; + break; + case SM501_2D_MASK: + s->twoD_mask = value; + break; + case SM501_2D_WINDOW_WIDTH: + s->twoD_window_width = value; + break; + case SM501_2D_SOURCE_BASE: + s->twoD_source_base = value; + break; + case SM501_2D_DESTINATION_BASE: + s->twoD_destination_base = value; + break; + default: + printf("sm501 2d engine : not implemented register write." + " addr=%x, val=%x\n", (int)addr, value); + abort(); + } +} + +static CPUReadMemoryFunc * const sm501_2d_engine_readfn[] = { + NULL, + NULL, + &sm501_2d_engine_read, +}; + +static CPUWriteMemoryFunc * const sm501_2d_engine_writefn[] = { + NULL, + NULL, + &sm501_2d_engine_write, +}; + /* draw line functions for all console modes */ #include "pixel_ops.h" @@ -1195,6 +1356,7 @@ void sm501_init(uint32_t base, uint32_t local_mem_bytes, qemu_irq irq, DeviceState *dev; int sm501_system_config_index; int sm501_disp_ctrl_index; + int sm501_2d_engine_index; /* allocate management data region */ s = (SM501State *)qemu_mallocz(sizeof(SM501State)); @@ -1223,6 +1385,10 @@ void sm501_init(uint32_t base, uint32_t local_mem_bytes, qemu_irq irq, sm501_disp_ctrl_writefn, s); cpu_register_physical_memory(base + MMIO_BASE_OFFSET + SM501_DC, 0x1000, sm501_disp_ctrl_index); + sm501_2d_engine_index = cpu_register_io_memory(sm501_2d_engine_readfn, + sm501_2d_engine_writefn, s); + cpu_register_physical_memory(base + MMIO_BASE_OFFSET + SM501_2D_ENGINE, + 0x54, sm501_2d_engine_index); /* bridge to usb host emulation module */ dev = qdev_create(NULL, "sysbus-ohci"); |