summaryrefslogtreecommitdiffstats
path: root/hw/sm501.c
diff options
context:
space:
mode:
Diffstat (limited to 'hw/sm501.c')
-rw-r--r--hw/sm501.c172
1 files changed, 169 insertions, 3 deletions
diff --git a/hw/sm501.c b/hw/sm501.c
index 9310014..b5ec2da 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");
OpenPOWER on IntegriCloud