qemu/hw/display/sm501.c
<<
>>
Prefs
   1/*
   2 * QEMU SM501 Device
   3 *
   4 * Copyright (c) 2008 Shin-ichiro KAWASAKI
   5 *
   6 * Permission is hereby granted, free of charge, to any person obtaining a copy
   7 * of this software and associated documentation files (the "Software"), to deal
   8 * in the Software without restriction, including without limitation the rights
   9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  10 * copies of the Software, and to permit persons to whom the Software is
  11 * furnished to do so, subject to the following conditions:
  12 *
  13 * The above copyright notice and this permission notice shall be included in
  14 * all copies or substantial portions of the Software.
  15 *
  16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
  19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  22 * THE SOFTWARE.
  23 */
  24
  25#include "qemu/osdep.h"
  26#include "qapi/error.h"
  27#include "qemu-common.h"
  28#include "cpu.h"
  29#include "hw/hw.h"
  30#include "hw/char/serial.h"
  31#include "ui/console.h"
  32#include "hw/devices.h"
  33#include "hw/sysbus.h"
  34#include "qemu/range.h"
  35#include "ui/pixel_ops.h"
  36#include "exec/address-spaces.h"
  37
  38/*
  39 * Status: 2010/05/07
  40 *   - Minimum implementation for Linux console : mmio regs and CRT layer.
  41 *   - 2D grapihcs acceleration partially supported : only fill rectangle.
  42 *
  43 * TODO:
  44 *   - Panel support
  45 *   - Touch panel support
  46 *   - USB support
  47 *   - UART support
  48 *   - More 2D graphics engine support
  49 *   - Performance tuning
  50 */
  51
  52//#define DEBUG_SM501
  53//#define DEBUG_BITBLT
  54
  55#ifdef DEBUG_SM501
  56#define SM501_DPRINTF(fmt, ...) printf(fmt, ## __VA_ARGS__)
  57#else
  58#define SM501_DPRINTF(fmt, ...) do {} while(0)
  59#endif
  60
  61
  62#define MMIO_BASE_OFFSET 0x3e00000
  63
  64/* SM501 register definitions taken from "linux/include/linux/sm501-regs.h" */
  65
  66/* System Configuration area */
  67/* System config base */
  68#define SM501_SYS_CONFIG                (0x000000)
  69
  70/* config 1 */
  71#define SM501_SYSTEM_CONTROL            (0x000000)
  72
  73#define SM501_SYSCTRL_PANEL_TRISTATE    (1<<0)
  74#define SM501_SYSCTRL_MEM_TRISTATE      (1<<1)
  75#define SM501_SYSCTRL_CRT_TRISTATE      (1<<2)
  76
  77#define SM501_SYSCTRL_PCI_SLAVE_BURST_MASK (3<<4)
  78#define SM501_SYSCTRL_PCI_SLAVE_BURST_1 (0<<4)
  79#define SM501_SYSCTRL_PCI_SLAVE_BURST_2 (1<<4)
  80#define SM501_SYSCTRL_PCI_SLAVE_BURST_4 (2<<4)
  81#define SM501_SYSCTRL_PCI_SLAVE_BURST_8 (3<<4)
  82
  83#define SM501_SYSCTRL_PCI_CLOCK_RUN_EN  (1<<6)
  84#define SM501_SYSCTRL_PCI_RETRY_DISABLE (1<<7)
  85#define SM501_SYSCTRL_PCI_SUBSYS_LOCK   (1<<11)
  86#define SM501_SYSCTRL_PCI_BURST_READ_EN (1<<15)
  87
  88/* miscellaneous control */
  89
  90#define SM501_MISC_CONTROL              (0x000004)
  91
  92#define SM501_MISC_BUS_SH               (0x0)
  93#define SM501_MISC_BUS_PCI              (0x1)
  94#define SM501_MISC_BUS_XSCALE           (0x2)
  95#define SM501_MISC_BUS_NEC              (0x6)
  96#define SM501_MISC_BUS_MASK             (0x7)
  97
  98#define SM501_MISC_VR_62MB              (1<<3)
  99#define SM501_MISC_CDR_RESET            (1<<7)
 100#define SM501_MISC_USB_LB               (1<<8)
 101#define SM501_MISC_USB_SLAVE            (1<<9)
 102#define SM501_MISC_BL_1                 (1<<10)
 103#define SM501_MISC_MC                   (1<<11)
 104#define SM501_MISC_DAC_POWER            (1<<12)
 105#define SM501_MISC_IRQ_INVERT           (1<<16)
 106#define SM501_MISC_SH                   (1<<17)
 107
 108#define SM501_MISC_HOLD_EMPTY           (0<<18)
 109#define SM501_MISC_HOLD_8               (1<<18)
 110#define SM501_MISC_HOLD_16              (2<<18)
 111#define SM501_MISC_HOLD_24              (3<<18)
 112#define SM501_MISC_HOLD_32              (4<<18)
 113#define SM501_MISC_HOLD_MASK            (7<<18)
 114
 115#define SM501_MISC_FREQ_12              (1<<24)
 116#define SM501_MISC_PNL_24BIT            (1<<25)
 117#define SM501_MISC_8051_LE              (1<<26)
 118
 119
 120
 121#define SM501_GPIO31_0_CONTROL          (0x000008)
 122#define SM501_GPIO63_32_CONTROL         (0x00000C)
 123#define SM501_DRAM_CONTROL              (0x000010)
 124
 125/* command list */
 126#define SM501_ARBTRTN_CONTROL           (0x000014)
 127
 128/* command list */
 129#define SM501_COMMAND_LIST_STATUS       (0x000024)
 130
 131/* interrupt debug */
 132#define SM501_RAW_IRQ_STATUS            (0x000028)
 133#define SM501_RAW_IRQ_CLEAR             (0x000028)
 134#define SM501_IRQ_STATUS                (0x00002C)
 135#define SM501_IRQ_MASK                  (0x000030)
 136#define SM501_DEBUG_CONTROL             (0x000034)
 137
 138/* power management */
 139#define SM501_POWERMODE_P2X_SRC         (1<<29)
 140#define SM501_POWERMODE_V2X_SRC         (1<<20)
 141#define SM501_POWERMODE_M_SRC           (1<<12)
 142#define SM501_POWERMODE_M1_SRC          (1<<4)
 143
 144#define SM501_CURRENT_GATE              (0x000038)
 145#define SM501_CURRENT_CLOCK             (0x00003C)
 146#define SM501_POWER_MODE_0_GATE         (0x000040)
 147#define SM501_POWER_MODE_0_CLOCK        (0x000044)
 148#define SM501_POWER_MODE_1_GATE         (0x000048)
 149#define SM501_POWER_MODE_1_CLOCK        (0x00004C)
 150#define SM501_SLEEP_MODE_GATE           (0x000050)
 151#define SM501_POWER_MODE_CONTROL        (0x000054)
 152
 153/* power gates for units within the 501 */
 154#define SM501_GATE_HOST                 (0)
 155#define SM501_GATE_MEMORY               (1)
 156#define SM501_GATE_DISPLAY              (2)
 157#define SM501_GATE_2D_ENGINE            (3)
 158#define SM501_GATE_CSC                  (4)
 159#define SM501_GATE_ZVPORT               (5)
 160#define SM501_GATE_GPIO                 (6)
 161#define SM501_GATE_UART0                (7)
 162#define SM501_GATE_UART1                (8)
 163#define SM501_GATE_SSP                  (10)
 164#define SM501_GATE_USB_HOST             (11)
 165#define SM501_GATE_USB_GADGET           (12)
 166#define SM501_GATE_UCONTROLLER          (17)
 167#define SM501_GATE_AC97                 (18)
 168
 169/* panel clock */
 170#define SM501_CLOCK_P2XCLK              (24)
 171/* crt clock */
 172#define SM501_CLOCK_V2XCLK              (16)
 173/* main clock */
 174#define SM501_CLOCK_MCLK                (8)
 175/* SDRAM controller clock */
 176#define SM501_CLOCK_M1XCLK              (0)
 177
 178/* config 2 */
 179#define SM501_PCI_MASTER_BASE           (0x000058)
 180#define SM501_ENDIAN_CONTROL            (0x00005C)
 181#define SM501_DEVICEID                  (0x000060)
 182/* 0x050100A0 */
 183
 184#define SM501_DEVICEID_SM501            (0x05010000)
 185#define SM501_DEVICEID_IDMASK           (0xffff0000)
 186#define SM501_DEVICEID_REVMASK          (0x000000ff)
 187
 188#define SM501_PLLCLOCK_COUNT            (0x000064)
 189#define SM501_MISC_TIMING               (0x000068)
 190#define SM501_CURRENT_SDRAM_CLOCK       (0x00006C)
 191
 192#define SM501_PROGRAMMABLE_PLL_CONTROL  (0x000074)
 193
 194/* GPIO base */
 195#define SM501_GPIO                      (0x010000)
 196#define SM501_GPIO_DATA_LOW             (0x00)
 197#define SM501_GPIO_DATA_HIGH            (0x04)
 198#define SM501_GPIO_DDR_LOW              (0x08)
 199#define SM501_GPIO_DDR_HIGH             (0x0C)
 200#define SM501_GPIO_IRQ_SETUP            (0x10)
 201#define SM501_GPIO_IRQ_STATUS           (0x14)
 202#define SM501_GPIO_IRQ_RESET            (0x14)
 203
 204/* I2C controller base */
 205#define SM501_I2C                       (0x010040)
 206#define SM501_I2C_BYTE_COUNT            (0x00)
 207#define SM501_I2C_CONTROL               (0x01)
 208#define SM501_I2C_STATUS                (0x02)
 209#define SM501_I2C_RESET                 (0x02)
 210#define SM501_I2C_SLAVE_ADDRESS         (0x03)
 211#define SM501_I2C_DATA                  (0x04)
 212
 213/* SSP base */
 214#define SM501_SSP                       (0x020000)
 215
 216/* Uart 0 base */
 217#define SM501_UART0                     (0x030000)
 218
 219/* Uart 1 base */
 220#define SM501_UART1                     (0x030020)
 221
 222/* USB host port base */
 223#define SM501_USB_HOST                  (0x040000)
 224
 225/* USB slave/gadget base */
 226#define SM501_USB_GADGET                (0x060000)
 227
 228/* USB slave/gadget data port base */
 229#define SM501_USB_GADGET_DATA           (0x070000)
 230
 231/* Display controller/video engine base */
 232#define SM501_DC                        (0x080000)
 233
 234/* common defines for the SM501 address registers */
 235#define SM501_ADDR_FLIP                 (1<<31)
 236#define SM501_ADDR_EXT                  (1<<27)
 237#define SM501_ADDR_CS1                  (1<<26)
 238#define SM501_ADDR_MASK                 (0x3f << 26)
 239
 240#define SM501_FIFO_MASK                 (0x3 << 16)
 241#define SM501_FIFO_1                    (0x0 << 16)
 242#define SM501_FIFO_3                    (0x1 << 16)
 243#define SM501_FIFO_7                    (0x2 << 16)
 244#define SM501_FIFO_11                   (0x3 << 16)
 245
 246/* common registers for panel and the crt */
 247#define SM501_OFF_DC_H_TOT              (0x000)
 248#define SM501_OFF_DC_V_TOT              (0x008)
 249#define SM501_OFF_DC_H_SYNC             (0x004)
 250#define SM501_OFF_DC_V_SYNC             (0x00C)
 251
 252#define SM501_DC_PANEL_CONTROL          (0x000)
 253
 254#define SM501_DC_PANEL_CONTROL_FPEN     (1<<27)
 255#define SM501_DC_PANEL_CONTROL_BIAS     (1<<26)
 256#define SM501_DC_PANEL_CONTROL_DATA     (1<<25)
 257#define SM501_DC_PANEL_CONTROL_VDD      (1<<24)
 258#define SM501_DC_PANEL_CONTROL_DP       (1<<23)
 259
 260#define SM501_DC_PANEL_CONTROL_TFT_888  (0<<21)
 261#define SM501_DC_PANEL_CONTROL_TFT_333  (1<<21)
 262#define SM501_DC_PANEL_CONTROL_TFT_444  (2<<21)
 263
 264#define SM501_DC_PANEL_CONTROL_DE       (1<<20)
 265
 266#define SM501_DC_PANEL_CONTROL_LCD_TFT  (0<<18)
 267#define SM501_DC_PANEL_CONTROL_LCD_STN8 (1<<18)
 268#define SM501_DC_PANEL_CONTROL_LCD_STN12 (2<<18)
 269
 270#define SM501_DC_PANEL_CONTROL_CP       (1<<14)
 271#define SM501_DC_PANEL_CONTROL_VSP      (1<<13)
 272#define SM501_DC_PANEL_CONTROL_HSP      (1<<12)
 273#define SM501_DC_PANEL_CONTROL_CK       (1<<9)
 274#define SM501_DC_PANEL_CONTROL_TE       (1<<8)
 275#define SM501_DC_PANEL_CONTROL_VPD      (1<<7)
 276#define SM501_DC_PANEL_CONTROL_VP       (1<<6)
 277#define SM501_DC_PANEL_CONTROL_HPD      (1<<5)
 278#define SM501_DC_PANEL_CONTROL_HP       (1<<4)
 279#define SM501_DC_PANEL_CONTROL_GAMMA    (1<<3)
 280#define SM501_DC_PANEL_CONTROL_EN       (1<<2)
 281
 282#define SM501_DC_PANEL_CONTROL_8BPP     (0<<0)
 283#define SM501_DC_PANEL_CONTROL_16BPP    (1<<0)
 284#define SM501_DC_PANEL_CONTROL_32BPP    (2<<0)
 285
 286
 287#define SM501_DC_PANEL_PANNING_CONTROL  (0x004)
 288#define SM501_DC_PANEL_COLOR_KEY        (0x008)
 289#define SM501_DC_PANEL_FB_ADDR          (0x00C)
 290#define SM501_DC_PANEL_FB_OFFSET        (0x010)
 291#define SM501_DC_PANEL_FB_WIDTH         (0x014)
 292#define SM501_DC_PANEL_FB_HEIGHT        (0x018)
 293#define SM501_DC_PANEL_TL_LOC           (0x01C)
 294#define SM501_DC_PANEL_BR_LOC           (0x020)
 295#define SM501_DC_PANEL_H_TOT            (0x024)
 296#define SM501_DC_PANEL_H_SYNC           (0x028)
 297#define SM501_DC_PANEL_V_TOT            (0x02C)
 298#define SM501_DC_PANEL_V_SYNC           (0x030)
 299#define SM501_DC_PANEL_CUR_LINE         (0x034)
 300
 301#define SM501_DC_VIDEO_CONTROL          (0x040)
 302#define SM501_DC_VIDEO_FB0_ADDR         (0x044)
 303#define SM501_DC_VIDEO_FB_WIDTH         (0x048)
 304#define SM501_DC_VIDEO_FB0_LAST_ADDR    (0x04C)
 305#define SM501_DC_VIDEO_TL_LOC           (0x050)
 306#define SM501_DC_VIDEO_BR_LOC           (0x054)
 307#define SM501_DC_VIDEO_SCALE            (0x058)
 308#define SM501_DC_VIDEO_INIT_SCALE       (0x05C)
 309#define SM501_DC_VIDEO_YUV_CONSTANTS    (0x060)
 310#define SM501_DC_VIDEO_FB1_ADDR         (0x064)
 311#define SM501_DC_VIDEO_FB1_LAST_ADDR    (0x068)
 312
 313#define SM501_DC_VIDEO_ALPHA_CONTROL    (0x080)
 314#define SM501_DC_VIDEO_ALPHA_FB_ADDR    (0x084)
 315#define SM501_DC_VIDEO_ALPHA_FB_OFFSET  (0x088)
 316#define SM501_DC_VIDEO_ALPHA_FB_LAST_ADDR       (0x08C)
 317#define SM501_DC_VIDEO_ALPHA_TL_LOC     (0x090)
 318#define SM501_DC_VIDEO_ALPHA_BR_LOC     (0x094)
 319#define SM501_DC_VIDEO_ALPHA_SCALE      (0x098)
 320#define SM501_DC_VIDEO_ALPHA_INIT_SCALE (0x09C)
 321#define SM501_DC_VIDEO_ALPHA_CHROMA_KEY (0x0A0)
 322#define SM501_DC_VIDEO_ALPHA_COLOR_LOOKUP       (0x0A4)
 323
 324#define SM501_DC_PANEL_HWC_BASE         (0x0F0)
 325#define SM501_DC_PANEL_HWC_ADDR         (0x0F0)
 326#define SM501_DC_PANEL_HWC_LOC          (0x0F4)
 327#define SM501_DC_PANEL_HWC_COLOR_1_2    (0x0F8)
 328#define SM501_DC_PANEL_HWC_COLOR_3      (0x0FC)
 329
 330#define SM501_HWC_EN                    (1<<31)
 331
 332#define SM501_OFF_HWC_ADDR              (0x00)
 333#define SM501_OFF_HWC_LOC               (0x04)
 334#define SM501_OFF_HWC_COLOR_1_2         (0x08)
 335#define SM501_OFF_HWC_COLOR_3           (0x0C)
 336
 337#define SM501_DC_ALPHA_CONTROL          (0x100)
 338#define SM501_DC_ALPHA_FB_ADDR          (0x104)
 339#define SM501_DC_ALPHA_FB_OFFSET        (0x108)
 340#define SM501_DC_ALPHA_TL_LOC           (0x10C)
 341#define SM501_DC_ALPHA_BR_LOC           (0x110)
 342#define SM501_DC_ALPHA_CHROMA_KEY       (0x114)
 343#define SM501_DC_ALPHA_COLOR_LOOKUP     (0x118)
 344
 345#define SM501_DC_CRT_CONTROL            (0x200)
 346
 347#define SM501_DC_CRT_CONTROL_TVP        (1<<15)
 348#define SM501_DC_CRT_CONTROL_CP         (1<<14)
 349#define SM501_DC_CRT_CONTROL_VSP        (1<<13)
 350#define SM501_DC_CRT_CONTROL_HSP        (1<<12)
 351#define SM501_DC_CRT_CONTROL_VS         (1<<11)
 352#define SM501_DC_CRT_CONTROL_BLANK      (1<<10)
 353#define SM501_DC_CRT_CONTROL_SEL        (1<<9)
 354#define SM501_DC_CRT_CONTROL_TE         (1<<8)
 355#define SM501_DC_CRT_CONTROL_PIXEL_MASK (0xF << 4)
 356#define SM501_DC_CRT_CONTROL_GAMMA      (1<<3)
 357#define SM501_DC_CRT_CONTROL_ENABLE     (1<<2)
 358
 359#define SM501_DC_CRT_CONTROL_8BPP       (0<<0)
 360#define SM501_DC_CRT_CONTROL_16BPP      (1<<0)
 361#define SM501_DC_CRT_CONTROL_32BPP      (2<<0)
 362
 363#define SM501_DC_CRT_FB_ADDR            (0x204)
 364#define SM501_DC_CRT_FB_OFFSET          (0x208)
 365#define SM501_DC_CRT_H_TOT              (0x20C)
 366#define SM501_DC_CRT_H_SYNC             (0x210)
 367#define SM501_DC_CRT_V_TOT              (0x214)
 368#define SM501_DC_CRT_V_SYNC             (0x218)
 369#define SM501_DC_CRT_SIGNATURE_ANALYZER (0x21C)
 370#define SM501_DC_CRT_CUR_LINE           (0x220)
 371#define SM501_DC_CRT_MONITOR_DETECT     (0x224)
 372
 373#define SM501_DC_CRT_HWC_BASE           (0x230)
 374#define SM501_DC_CRT_HWC_ADDR           (0x230)
 375#define SM501_DC_CRT_HWC_LOC            (0x234)
 376#define SM501_DC_CRT_HWC_COLOR_1_2      (0x238)
 377#define SM501_DC_CRT_HWC_COLOR_3        (0x23C)
 378
 379#define SM501_DC_PANEL_PALETTE          (0x400)
 380
 381#define SM501_DC_VIDEO_PALETTE          (0x800)
 382
 383#define SM501_DC_CRT_PALETTE            (0xC00)
 384
 385/* Zoom Video port base */
 386#define SM501_ZVPORT                    (0x090000)
 387
 388/* AC97/I2S base */
 389#define SM501_AC97                      (0x0A0000)
 390
 391/* 8051 micro controller base */
 392#define SM501_UCONTROLLER               (0x0B0000)
 393
 394/* 8051 micro controller SRAM base */
 395#define SM501_UCONTROLLER_SRAM          (0x0C0000)
 396
 397/* DMA base */
 398#define SM501_DMA                       (0x0D0000)
 399
 400/* 2d engine base */
 401#define SM501_2D_ENGINE                 (0x100000)
 402#define SM501_2D_SOURCE                 (0x00)
 403#define SM501_2D_DESTINATION            (0x04)
 404#define SM501_2D_DIMENSION              (0x08)
 405#define SM501_2D_CONTROL                (0x0C)
 406#define SM501_2D_PITCH                  (0x10)
 407#define SM501_2D_FOREGROUND             (0x14)
 408#define SM501_2D_BACKGROUND             (0x18)
 409#define SM501_2D_STRETCH                (0x1C)
 410#define SM501_2D_COLOR_COMPARE          (0x20)
 411#define SM501_2D_COLOR_COMPARE_MASK     (0x24)
 412#define SM501_2D_MASK                   (0x28)
 413#define SM501_2D_CLIP_TL                (0x2C)
 414#define SM501_2D_CLIP_BR                (0x30)
 415#define SM501_2D_MONO_PATTERN_LOW       (0x34)
 416#define SM501_2D_MONO_PATTERN_HIGH      (0x38)
 417#define SM501_2D_WINDOW_WIDTH           (0x3C)
 418#define SM501_2D_SOURCE_BASE            (0x40)
 419#define SM501_2D_DESTINATION_BASE       (0x44)
 420#define SM501_2D_ALPHA                  (0x48)
 421#define SM501_2D_WRAP                   (0x4C)
 422#define SM501_2D_STATUS                 (0x50)
 423
 424#define SM501_CSC_Y_SOURCE_BASE         (0xC8)
 425#define SM501_CSC_CONSTANTS             (0xCC)
 426#define SM501_CSC_Y_SOURCE_X            (0xD0)
 427#define SM501_CSC_Y_SOURCE_Y            (0xD4)
 428#define SM501_CSC_U_SOURCE_BASE         (0xD8)
 429#define SM501_CSC_V_SOURCE_BASE         (0xDC)
 430#define SM501_CSC_SOURCE_DIMENSION      (0xE0)
 431#define SM501_CSC_SOURCE_PITCH          (0xE4)
 432#define SM501_CSC_DESTINATION           (0xE8)
 433#define SM501_CSC_DESTINATION_DIMENSION (0xEC)
 434#define SM501_CSC_DESTINATION_PITCH     (0xF0)
 435#define SM501_CSC_SCALE_FACTOR          (0xF4)
 436#define SM501_CSC_DESTINATION_BASE      (0xF8)
 437#define SM501_CSC_CONTROL               (0xFC)
 438
 439/* 2d engine data port base */
 440#define SM501_2D_ENGINE_DATA            (0x110000)
 441
 442/* end of register definitions */
 443
 444#define SM501_HWC_WIDTH                       (64)
 445#define SM501_HWC_HEIGHT                      (64)
 446
 447/* SM501 local memory size taken from "linux/drivers/mfd/sm501.c" */
 448static const uint32_t sm501_mem_local_size[] = {
 449        [0]     = 4*1024*1024,
 450        [1]     = 8*1024*1024,
 451        [2]     = 16*1024*1024,
 452        [3]     = 32*1024*1024,
 453        [4]     = 64*1024*1024,
 454        [5]     = 2*1024*1024,
 455};
 456#define get_local_mem_size(s) sm501_mem_local_size[(s)->local_mem_size_index]
 457
 458typedef struct SM501State {
 459    /* graphic console status */
 460    QemuConsole *con;
 461
 462    /* status & internal resources */
 463    hwaddr base;
 464    uint32_t local_mem_size_index;
 465    uint8_t * local_mem;
 466    MemoryRegion local_mem_region;
 467    uint32_t last_width;
 468    uint32_t last_height;
 469
 470    /* mmio registers */
 471    uint32_t system_control;
 472    uint32_t misc_control;
 473    uint32_t gpio_31_0_control;
 474    uint32_t gpio_63_32_control;
 475    uint32_t dram_control;
 476    uint32_t irq_mask;
 477    uint32_t misc_timing;
 478    uint32_t power_mode_control;
 479
 480    uint32_t uart0_ier;
 481    uint32_t uart0_lcr;
 482    uint32_t uart0_mcr;
 483    uint32_t uart0_scr;
 484
 485    uint8_t dc_palette[0x400 * 3];
 486
 487    uint32_t dc_panel_control;
 488    uint32_t dc_panel_panning_control;
 489    uint32_t dc_panel_fb_addr;
 490    uint32_t dc_panel_fb_offset;
 491    uint32_t dc_panel_fb_width;
 492    uint32_t dc_panel_fb_height;
 493    uint32_t dc_panel_tl_location;
 494    uint32_t dc_panel_br_location;
 495    uint32_t dc_panel_h_total;
 496    uint32_t dc_panel_h_sync;
 497    uint32_t dc_panel_v_total;
 498    uint32_t dc_panel_v_sync;
 499
 500    uint32_t dc_panel_hwc_addr;
 501    uint32_t dc_panel_hwc_location;
 502    uint32_t dc_panel_hwc_color_1_2;
 503    uint32_t dc_panel_hwc_color_3;
 504
 505    uint32_t dc_crt_control;
 506    uint32_t dc_crt_fb_addr;
 507    uint32_t dc_crt_fb_offset;
 508    uint32_t dc_crt_h_total;
 509    uint32_t dc_crt_h_sync;
 510    uint32_t dc_crt_v_total;
 511    uint32_t dc_crt_v_sync;
 512
 513    uint32_t dc_crt_hwc_addr;
 514    uint32_t dc_crt_hwc_location;
 515    uint32_t dc_crt_hwc_color_1_2;
 516    uint32_t dc_crt_hwc_color_3;
 517
 518    uint32_t twoD_source;
 519    uint32_t twoD_destination;
 520    uint32_t twoD_dimension;
 521    uint32_t twoD_control;
 522    uint32_t twoD_pitch;
 523    uint32_t twoD_foreground;
 524    uint32_t twoD_stretch;
 525    uint32_t twoD_color_compare_mask;
 526    uint32_t twoD_mask;
 527    uint32_t twoD_window_width;
 528    uint32_t twoD_source_base;
 529    uint32_t twoD_destination_base;
 530
 531} SM501State;
 532
 533static uint32_t get_local_mem_size_index(uint32_t size)
 534{
 535    uint32_t norm_size = 0;
 536    int i, index = 0;
 537
 538    for (i = 0; i < ARRAY_SIZE(sm501_mem_local_size); i++) {
 539        uint32_t new_size = sm501_mem_local_size[i];
 540        if (new_size >= size) {
 541            if (norm_size == 0 || norm_size > new_size) {
 542                norm_size = new_size;
 543                index = i;
 544            }
 545        }
 546    }
 547
 548    return index;
 549}
 550
 551/**
 552 * Check the availability of hardware cursor.
 553 * @param crt  0 for PANEL, 1 for CRT.
 554 */
 555static inline int is_hwc_enabled(SM501State *state, int crt)
 556{
 557    uint32_t addr = crt ? state->dc_crt_hwc_addr : state->dc_panel_hwc_addr;
 558    return addr & 0x80000000;
 559}
 560
 561/**
 562 * Get the address which holds cursor pattern data.
 563 * @param crt  0 for PANEL, 1 for CRT.
 564 */
 565static inline uint32_t get_hwc_address(SM501State *state, int crt)
 566{
 567    uint32_t addr = crt ? state->dc_crt_hwc_addr : state->dc_panel_hwc_addr;
 568    return (addr & 0x03FFFFF0)/* >> 4*/;
 569}
 570
 571/**
 572 * Get the cursor position in y coordinate.
 573 * @param crt  0 for PANEL, 1 for CRT.
 574 */
 575static inline uint32_t get_hwc_y(SM501State *state, int crt)
 576{
 577    uint32_t location = crt ? state->dc_crt_hwc_location
 578                            : state->dc_panel_hwc_location;
 579    return (location & 0x07FF0000) >> 16;
 580}
 581
 582/**
 583 * Get the cursor position in x coordinate.
 584 * @param crt  0 for PANEL, 1 for CRT.
 585 */
 586static inline uint32_t get_hwc_x(SM501State *state, int crt)
 587{
 588    uint32_t location = crt ? state->dc_crt_hwc_location
 589                            : state->dc_panel_hwc_location;
 590    return location & 0x000007FF;
 591}
 592
 593/**
 594 * Get the cursor position in x coordinate.
 595 * @param crt  0 for PANEL, 1 for CRT.
 596 * @param index  0, 1, 2 or 3 which specifies color of corsor dot.
 597 */
 598static inline uint16_t get_hwc_color(SM501State *state, int crt, int index)
 599{
 600    uint32_t color_reg = 0;
 601    uint16_t color_565 = 0;
 602
 603    if (index == 0) {
 604        return 0;
 605    }
 606
 607    switch (index) {
 608    case 1:
 609    case 2:
 610        color_reg = crt ? state->dc_crt_hwc_color_1_2
 611                        : state->dc_panel_hwc_color_1_2;
 612        break;
 613    case 3:
 614        color_reg = crt ? state->dc_crt_hwc_color_3
 615                        : state->dc_panel_hwc_color_3;
 616        break;
 617    default:
 618        printf("invalid hw cursor color.\n");
 619        abort();
 620    }
 621
 622    switch (index) {
 623    case 1:
 624    case 3:
 625        color_565 = (uint16_t)(color_reg & 0xFFFF);
 626        break;
 627    case 2:
 628        color_565 = (uint16_t)((color_reg >> 16) & 0xFFFF);
 629        break;
 630    }
 631    return color_565;
 632}
 633
 634static int within_hwc_y_range(SM501State *state, int y, int crt)
 635{
 636    int hwc_y = get_hwc_y(state, crt);
 637    return (hwc_y <= y && y < hwc_y + SM501_HWC_HEIGHT);
 638}
 639
 640static void sm501_2d_operation(SM501State * s)
 641{
 642    /* obtain operation parameters */
 643    int operation = (s->twoD_control >> 16) & 0x1f;
 644    int rtl = s->twoD_control & 0x8000000;
 645    int src_x = (s->twoD_source >> 16) & 0x01FFF;
 646    int src_y = s->twoD_source & 0xFFFF;
 647    int dst_x = (s->twoD_destination >> 16) & 0x01FFF;
 648    int dst_y = s->twoD_destination & 0xFFFF;
 649    int operation_width = (s->twoD_dimension >> 16) & 0x1FFF;
 650    int operation_height = s->twoD_dimension & 0xFFFF;
 651    uint32_t color = s->twoD_foreground;
 652    int format_flags = (s->twoD_stretch >> 20) & 0x3;
 653    int addressing = (s->twoD_stretch >> 16) & 0xF;
 654
 655    /* get frame buffer info */
 656    uint8_t * src = s->local_mem + (s->twoD_source_base & 0x03FFFFFF);
 657    uint8_t * dst = s->local_mem + (s->twoD_destination_base & 0x03FFFFFF);
 658    int src_width = (s->dc_crt_h_total & 0x00000FFF) + 1;
 659    int dst_width = (s->dc_crt_h_total & 0x00000FFF) + 1;
 660
 661    if (addressing != 0x0) {
 662        printf("%s: only XY addressing is supported.\n", __func__);
 663        abort();
 664    }
 665
 666    if ((s->twoD_source_base & 0x08000000) ||
 667        (s->twoD_destination_base & 0x08000000)) {
 668        printf("%s: only local memory is supported.\n", __func__);
 669        abort();
 670    }
 671
 672    switch (operation) {
 673    case 0x00: /* copy area */
 674#define COPY_AREA(_bpp, _pixel_type, rtl) {                                 \
 675        int y, x, index_d, index_s;                                         \
 676        for (y = 0; y < operation_height; y++) {                            \
 677            for (x = 0; x < operation_width; x++) {                         \
 678                if (rtl) {                                                  \
 679                    index_s = ((src_y - y) * src_width + src_x - x) * _bpp; \
 680                    index_d = ((dst_y - y) * dst_width + dst_x - x) * _bpp; \
 681                } else {                                                    \
 682                    index_s = ((src_y + y) * src_width + src_x + x) * _bpp; \
 683                    index_d = ((dst_y + y) * dst_width + dst_x + x) * _bpp; \
 684                }                                                           \
 685                *(_pixel_type*)&dst[index_d] = *(_pixel_type*)&src[index_s];\
 686            }                                                               \
 687        }                                                                   \
 688    }
 689        switch (format_flags) {
 690        case 0:
 691            COPY_AREA(1, uint8_t, rtl);
 692            break;
 693        case 1:
 694            COPY_AREA(2, uint16_t, rtl);
 695            break;
 696        case 2:
 697            COPY_AREA(4, uint32_t, rtl);
 698            break;
 699        }
 700        break;
 701
 702    case 0x01: /* fill rectangle */
 703#define FILL_RECT(_bpp, _pixel_type) {                                      \
 704        int y, x;                                                           \
 705        for (y = 0; y < operation_height; y++) {                            \
 706            for (x = 0; x < operation_width; x++) {                         \
 707                int index = ((dst_y + y) * dst_width + dst_x + x) * _bpp;   \
 708                *(_pixel_type*)&dst[index] = (_pixel_type)color;            \
 709            }                                                               \
 710        }                                                                   \
 711    }
 712
 713        switch (format_flags) {
 714        case 0:
 715            FILL_RECT(1, uint8_t);
 716            break;
 717        case 1:
 718            FILL_RECT(2, uint16_t);
 719            break;
 720        case 2:
 721            FILL_RECT(4, uint32_t);
 722            break;
 723        }
 724        break;
 725
 726    default:
 727        printf("non-implemented SM501 2D operation. %d\n", operation);
 728        abort();
 729        break;
 730    }
 731}
 732
 733static uint64_t sm501_system_config_read(void *opaque, hwaddr addr,
 734                                         unsigned size)
 735{
 736    SM501State * s = (SM501State *)opaque;
 737    uint32_t ret = 0;
 738    SM501_DPRINTF("sm501 system config regs : read addr=%x\n", (int)addr);
 739
 740    switch(addr) {
 741    case SM501_SYSTEM_CONTROL:
 742        ret = s->system_control;
 743        break;
 744    case SM501_MISC_CONTROL:
 745        ret = s->misc_control;
 746        break;
 747    case SM501_GPIO31_0_CONTROL:
 748        ret = s->gpio_31_0_control;
 749        break;
 750    case SM501_GPIO63_32_CONTROL:
 751        ret = s->gpio_63_32_control;
 752        break;
 753    case SM501_DEVICEID:
 754        ret = 0x050100A0;
 755        break;
 756    case SM501_DRAM_CONTROL:
 757        ret = (s->dram_control & 0x07F107C0) | s->local_mem_size_index << 13;
 758        break;
 759    case SM501_IRQ_MASK:
 760        ret = s->irq_mask;
 761        break;
 762    case SM501_MISC_TIMING:
 763        /* TODO : simulate gate control */
 764        ret = s->misc_timing;
 765        break;
 766    case SM501_CURRENT_GATE:
 767        /* TODO : simulate gate control */
 768        ret = 0x00021807;
 769        break;
 770    case SM501_CURRENT_CLOCK:
 771        ret = 0x2A1A0A09;
 772        break;
 773    case SM501_POWER_MODE_CONTROL:
 774        ret = s->power_mode_control;
 775        break;
 776
 777    default:
 778        printf("sm501 system config : not implemented register read."
 779               " addr=%x\n", (int)addr);
 780        abort();
 781    }
 782
 783    return ret;
 784}
 785
 786static void sm501_system_config_write(void *opaque, hwaddr addr,
 787                                      uint64_t value, unsigned size)
 788{
 789    SM501State * s = (SM501State *)opaque;
 790    SM501_DPRINTF("sm501 system config regs : write addr=%x, val=%x\n",
 791                  (uint32_t)addr, (uint32_t)value);
 792
 793    switch(addr) {
 794    case SM501_SYSTEM_CONTROL:
 795        s->system_control = value & 0xE300B8F7;
 796        break;
 797    case SM501_MISC_CONTROL:
 798        s->misc_control = value & 0xFF7FFF20;
 799        break;
 800    case SM501_GPIO31_0_CONTROL:
 801        s->gpio_31_0_control = value;
 802        break;
 803    case SM501_GPIO63_32_CONTROL:
 804        s->gpio_63_32_control = value;
 805        break;
 806    case SM501_DRAM_CONTROL:
 807        s->local_mem_size_index = (value >> 13) & 0x7;
 808        /* rODO : check validity of size change */
 809        s->dram_control |=  value & 0x7FFFFFC3;
 810        break;
 811    case SM501_IRQ_MASK:
 812        s->irq_mask = value;
 813        break;
 814    case SM501_MISC_TIMING:
 815        s->misc_timing = value & 0xF31F1FFF;
 816        break;
 817    case SM501_POWER_MODE_0_GATE:
 818    case SM501_POWER_MODE_1_GATE:
 819    case SM501_POWER_MODE_0_CLOCK:
 820    case SM501_POWER_MODE_1_CLOCK:
 821        /* TODO : simulate gate & clock control */
 822        break;
 823    case SM501_POWER_MODE_CONTROL:
 824        s->power_mode_control = value & 0x00000003;
 825        break;
 826
 827    default:
 828        printf("sm501 system config : not implemented register write."
 829               " addr=%x, val=%x\n", (int)addr, (uint32_t)value);
 830        abort();
 831    }
 832}
 833
 834static const MemoryRegionOps sm501_system_config_ops = {
 835    .read = sm501_system_config_read,
 836    .write = sm501_system_config_write,
 837    .valid = {
 838        .min_access_size = 4,
 839        .max_access_size = 4,
 840    },
 841    .endianness = DEVICE_NATIVE_ENDIAN,
 842};
 843
 844static uint32_t sm501_palette_read(void *opaque, hwaddr addr)
 845{
 846    SM501State * s = (SM501State *)opaque;
 847    SM501_DPRINTF("sm501 palette read addr=%x\n", (int)addr);
 848
 849    /* TODO : consider BYTE/WORD access */
 850    /* TODO : consider endian */
 851
 852    assert(range_covers_byte(0, 0x400 * 3, addr));
 853    return *(uint32_t*)&s->dc_palette[addr];
 854}
 855
 856static void sm501_palette_write(void *opaque,
 857                                hwaddr addr, uint32_t value)
 858{
 859    SM501State * s = (SM501State *)opaque;
 860    SM501_DPRINTF("sm501 palette write addr=%x, val=%x\n",
 861                  (int)addr, value);
 862
 863    /* TODO : consider BYTE/WORD access */
 864    /* TODO : consider endian */
 865
 866    assert(range_covers_byte(0, 0x400 * 3, addr));
 867    *(uint32_t*)&s->dc_palette[addr] = value;
 868}
 869
 870static uint64_t sm501_disp_ctrl_read(void *opaque, hwaddr addr,
 871                                     unsigned size)
 872{
 873    SM501State * s = (SM501State *)opaque;
 874    uint32_t ret = 0;
 875    SM501_DPRINTF("sm501 disp ctrl regs : read addr=%x\n", (int)addr);
 876
 877    switch(addr) {
 878
 879    case SM501_DC_PANEL_CONTROL:
 880        ret = s->dc_panel_control;
 881        break;
 882    case SM501_DC_PANEL_PANNING_CONTROL:
 883        ret = s->dc_panel_panning_control;
 884        break;
 885    case SM501_DC_PANEL_FB_ADDR:
 886        ret = s->dc_panel_fb_addr;
 887        break;
 888    case SM501_DC_PANEL_FB_OFFSET:
 889        ret = s->dc_panel_fb_offset;
 890        break;
 891    case SM501_DC_PANEL_FB_WIDTH:
 892        ret = s->dc_panel_fb_width;
 893        break;
 894    case SM501_DC_PANEL_FB_HEIGHT:
 895        ret = s->dc_panel_fb_height;
 896        break;
 897    case SM501_DC_PANEL_TL_LOC:
 898        ret = s->dc_panel_tl_location;
 899        break;
 900    case SM501_DC_PANEL_BR_LOC:
 901        ret = s->dc_panel_br_location;
 902        break;
 903
 904    case SM501_DC_PANEL_H_TOT:
 905        ret = s->dc_panel_h_total;
 906        break;
 907    case SM501_DC_PANEL_H_SYNC:
 908        ret = s->dc_panel_h_sync;
 909        break;
 910    case SM501_DC_PANEL_V_TOT:
 911        ret = s->dc_panel_v_total;
 912        break;
 913    case SM501_DC_PANEL_V_SYNC:
 914        ret = s->dc_panel_v_sync;
 915        break;
 916
 917    case SM501_DC_CRT_CONTROL:
 918        ret = s->dc_crt_control;
 919        break;
 920    case SM501_DC_CRT_FB_ADDR:
 921        ret = s->dc_crt_fb_addr;
 922        break;
 923    case SM501_DC_CRT_FB_OFFSET:
 924        ret = s->dc_crt_fb_offset;
 925        break;
 926    case SM501_DC_CRT_H_TOT:
 927        ret = s->dc_crt_h_total;
 928        break;
 929    case SM501_DC_CRT_H_SYNC:
 930        ret = s->dc_crt_h_sync;
 931        break;
 932    case SM501_DC_CRT_V_TOT:
 933        ret = s->dc_crt_v_total;
 934        break;
 935    case SM501_DC_CRT_V_SYNC:
 936        ret = s->dc_crt_v_sync;
 937        break;
 938
 939    case SM501_DC_CRT_HWC_ADDR:
 940        ret = s->dc_crt_hwc_addr;
 941        break;
 942    case SM501_DC_CRT_HWC_LOC:
 943        ret = s->dc_crt_hwc_location;
 944        break;
 945    case SM501_DC_CRT_HWC_COLOR_1_2:
 946        ret = s->dc_crt_hwc_color_1_2;
 947        break;
 948    case SM501_DC_CRT_HWC_COLOR_3:
 949        ret = s->dc_crt_hwc_color_3;
 950        break;
 951
 952    case SM501_DC_PANEL_PALETTE ... SM501_DC_PANEL_PALETTE + 0x400*3 - 4:
 953        ret = sm501_palette_read(opaque, addr - SM501_DC_PANEL_PALETTE);
 954        break;
 955
 956    default:
 957        printf("sm501 disp ctrl : not implemented register read."
 958               " addr=%x\n", (int)addr);
 959        abort();
 960    }
 961
 962    return ret;
 963}
 964
 965static void sm501_disp_ctrl_write(void *opaque, hwaddr addr,
 966                                  uint64_t value, unsigned size)
 967{
 968    SM501State * s = (SM501State *)opaque;
 969    SM501_DPRINTF("sm501 disp ctrl regs : write addr=%x, val=%x\n",
 970                  (unsigned)addr, (unsigned)value);
 971
 972    switch(addr) {
 973    case SM501_DC_PANEL_CONTROL:
 974        s->dc_panel_control = value & 0x0FFF73FF;
 975        break;
 976    case SM501_DC_PANEL_PANNING_CONTROL:
 977        s->dc_panel_panning_control = value & 0xFF3FFF3F;
 978        break;
 979    case SM501_DC_PANEL_FB_ADDR:
 980        s->dc_panel_fb_addr = value & 0x8FFFFFF0;
 981        break;
 982    case SM501_DC_PANEL_FB_OFFSET:
 983        s->dc_panel_fb_offset = value & 0x3FF03FF0;
 984        break;
 985    case SM501_DC_PANEL_FB_WIDTH:
 986        s->dc_panel_fb_width = value & 0x0FFF0FFF;
 987        break;
 988    case SM501_DC_PANEL_FB_HEIGHT:
 989        s->dc_panel_fb_height = value & 0x0FFF0FFF;
 990        break;
 991    case SM501_DC_PANEL_TL_LOC:
 992        s->dc_panel_tl_location = value & 0x07FF07FF;
 993        break;
 994    case SM501_DC_PANEL_BR_LOC:
 995        s->dc_panel_br_location = value & 0x07FF07FF;
 996        break;
 997
 998    case SM501_DC_PANEL_H_TOT:
 999        s->dc_panel_h_total = value & 0x0FFF0FFF;
1000        break;
1001    case SM501_DC_PANEL_H_SYNC:
1002        s->dc_panel_h_sync = value & 0x00FF0FFF;
1003        break;
1004    case SM501_DC_PANEL_V_TOT:
1005        s->dc_panel_v_total = value & 0x0FFF0FFF;
1006        break;
1007    case SM501_DC_PANEL_V_SYNC:
1008        s->dc_panel_v_sync = value & 0x003F0FFF;
1009        break;
1010
1011    case SM501_DC_PANEL_HWC_ADDR:
1012        s->dc_panel_hwc_addr = value & 0x8FFFFFF0;
1013        break;
1014    case SM501_DC_PANEL_HWC_LOC:
1015        s->dc_panel_hwc_location = value & 0x0FFF0FFF;
1016        break;
1017    case SM501_DC_PANEL_HWC_COLOR_1_2:
1018        s->dc_panel_hwc_color_1_2 = value;
1019        break;
1020    case SM501_DC_PANEL_HWC_COLOR_3:
1021        s->dc_panel_hwc_color_3 = value & 0x0000FFFF;
1022        break;
1023
1024    case SM501_DC_CRT_CONTROL:
1025        s->dc_crt_control = value & 0x0003FFFF;
1026        break;
1027    case SM501_DC_CRT_FB_ADDR:
1028        s->dc_crt_fb_addr = value & 0x8FFFFFF0;
1029        break;
1030    case SM501_DC_CRT_FB_OFFSET:
1031        s->dc_crt_fb_offset = value & 0x3FF03FF0;
1032        break;
1033    case SM501_DC_CRT_H_TOT:
1034        s->dc_crt_h_total = value & 0x0FFF0FFF;
1035        break;
1036    case SM501_DC_CRT_H_SYNC:
1037        s->dc_crt_h_sync = value & 0x00FF0FFF;
1038        break;
1039    case SM501_DC_CRT_V_TOT:
1040        s->dc_crt_v_total = value & 0x0FFF0FFF;
1041        break;
1042    case SM501_DC_CRT_V_SYNC:
1043        s->dc_crt_v_sync = value & 0x003F0FFF;
1044        break;
1045
1046    case SM501_DC_CRT_HWC_ADDR:
1047        s->dc_crt_hwc_addr = value & 0x8FFFFFF0;
1048        break;
1049    case SM501_DC_CRT_HWC_LOC:
1050        s->dc_crt_hwc_location = value & 0x0FFF0FFF;
1051        break;
1052    case SM501_DC_CRT_HWC_COLOR_1_2:
1053        s->dc_crt_hwc_color_1_2 = value;
1054        break;
1055    case SM501_DC_CRT_HWC_COLOR_3:
1056        s->dc_crt_hwc_color_3 = value & 0x0000FFFF;
1057        break;
1058
1059    case SM501_DC_PANEL_PALETTE ... SM501_DC_PANEL_PALETTE + 0x400*3 - 4:
1060        sm501_palette_write(opaque, addr - SM501_DC_PANEL_PALETTE, value);
1061        break;
1062
1063    default:
1064        printf("sm501 disp ctrl : not implemented register write."
1065               " addr=%x, val=%x\n", (int)addr, (unsigned)value);
1066        abort();
1067    }
1068}
1069
1070static const MemoryRegionOps sm501_disp_ctrl_ops = {
1071    .read = sm501_disp_ctrl_read,
1072    .write = sm501_disp_ctrl_write,
1073    .valid = {
1074        .min_access_size = 4,
1075        .max_access_size = 4,
1076    },
1077    .endianness = DEVICE_NATIVE_ENDIAN,
1078};
1079
1080static uint64_t sm501_2d_engine_read(void *opaque, hwaddr addr,
1081                                     unsigned size)
1082{
1083    SM501State * s = (SM501State *)opaque;
1084    uint32_t ret = 0;
1085    SM501_DPRINTF("sm501 2d engine regs : read addr=%x\n", (int)addr);
1086
1087    switch(addr) {
1088    case SM501_2D_SOURCE_BASE:
1089        ret = s->twoD_source_base;
1090        break;
1091    default:
1092        printf("sm501 disp ctrl : not implemented register read."
1093               " addr=%x\n", (int)addr);
1094        abort();
1095    }
1096
1097    return ret;
1098}
1099
1100static void sm501_2d_engine_write(void *opaque, hwaddr addr,
1101                                  uint64_t value, unsigned size)
1102{
1103    SM501State * s = (SM501State *)opaque;
1104    SM501_DPRINTF("sm501 2d engine regs : write addr=%x, val=%x\n",
1105                  (unsigned)addr, (unsigned)value);
1106
1107    switch(addr) {
1108    case SM501_2D_SOURCE:
1109        s->twoD_source = value;
1110        break;
1111    case SM501_2D_DESTINATION:
1112        s->twoD_destination = value;
1113        break;
1114    case SM501_2D_DIMENSION:
1115        s->twoD_dimension = value;
1116        break;
1117    case SM501_2D_CONTROL:
1118        s->twoD_control = value;
1119
1120        /* do 2d operation if start flag is set. */
1121        if (value & 0x80000000) {
1122            sm501_2d_operation(s);
1123            s->twoD_control &= ~0x80000000; /* start flag down */
1124        }
1125
1126        break;
1127    case SM501_2D_PITCH:
1128        s->twoD_pitch = value;
1129        break;
1130    case SM501_2D_FOREGROUND:
1131        s->twoD_foreground = value;
1132        break;
1133    case SM501_2D_STRETCH:
1134        s->twoD_stretch = value;
1135        break;
1136    case SM501_2D_COLOR_COMPARE_MASK:
1137        s->twoD_color_compare_mask = value;
1138        break;
1139    case SM501_2D_MASK:
1140        s->twoD_mask = value;
1141        break;
1142    case SM501_2D_WINDOW_WIDTH:
1143        s->twoD_window_width = value;
1144        break;
1145    case SM501_2D_SOURCE_BASE:
1146        s->twoD_source_base = value;
1147        break;
1148    case SM501_2D_DESTINATION_BASE:
1149        s->twoD_destination_base = value;
1150        break;
1151    default:
1152        printf("sm501 2d engine : not implemented register write."
1153               " addr=%x, val=%x\n", (int)addr, (unsigned)value);
1154        abort();
1155    }
1156}
1157
1158static const MemoryRegionOps sm501_2d_engine_ops = {
1159    .read = sm501_2d_engine_read,
1160    .write = sm501_2d_engine_write,
1161    .valid = {
1162        .min_access_size = 4,
1163        .max_access_size = 4,
1164    },
1165    .endianness = DEVICE_NATIVE_ENDIAN,
1166};
1167
1168/* draw line functions for all console modes */
1169
1170typedef void draw_line_func(uint8_t *d, const uint8_t *s,
1171                            int width, const uint32_t *pal);
1172
1173typedef void draw_hwc_line_func(SM501State * s, int crt, uint8_t * palette,
1174                                int c_y, uint8_t *d, int width);
1175
1176#define DEPTH 8
1177#include "sm501_template.h"
1178
1179#define DEPTH 15
1180#include "sm501_template.h"
1181
1182#define BGR_FORMAT
1183#define DEPTH 15
1184#include "sm501_template.h"
1185
1186#define DEPTH 16
1187#include "sm501_template.h"
1188
1189#define BGR_FORMAT
1190#define DEPTH 16
1191#include "sm501_template.h"
1192
1193#define DEPTH 32
1194#include "sm501_template.h"
1195
1196#define BGR_FORMAT
1197#define DEPTH 32
1198#include "sm501_template.h"
1199
1200static draw_line_func * draw_line8_funcs[] = {
1201    draw_line8_8,
1202    draw_line8_15,
1203    draw_line8_16,
1204    draw_line8_32,
1205    draw_line8_32bgr,
1206    draw_line8_15bgr,
1207    draw_line8_16bgr,
1208};
1209
1210static draw_line_func * draw_line16_funcs[] = {
1211    draw_line16_8,
1212    draw_line16_15,
1213    draw_line16_16,
1214    draw_line16_32,
1215    draw_line16_32bgr,
1216    draw_line16_15bgr,
1217    draw_line16_16bgr,
1218};
1219
1220static draw_line_func * draw_line32_funcs[] = {
1221    draw_line32_8,
1222    draw_line32_15,
1223    draw_line32_16,
1224    draw_line32_32,
1225    draw_line32_32bgr,
1226    draw_line32_15bgr,
1227    draw_line32_16bgr,
1228};
1229
1230static draw_hwc_line_func * draw_hwc_line_funcs[] = {
1231    draw_hwc_line_8,
1232    draw_hwc_line_15,
1233    draw_hwc_line_16,
1234    draw_hwc_line_32,
1235    draw_hwc_line_32bgr,
1236    draw_hwc_line_15bgr,
1237    draw_hwc_line_16bgr,
1238};
1239
1240static inline int get_depth_index(DisplaySurface *surface)
1241{
1242    switch (surface_bits_per_pixel(surface)) {
1243    default:
1244    case 8:
1245        return 0;
1246    case 15:
1247        return 1;
1248    case 16:
1249        return 2;
1250    case 32:
1251        if (is_surface_bgr(surface)) {
1252            return 4;
1253        } else {
1254            return 3;
1255        }
1256    }
1257}
1258
1259static void sm501_draw_crt(SM501State * s)
1260{
1261    DisplaySurface *surface = qemu_console_surface(s->con);
1262    int y;
1263    int width = (s->dc_crt_h_total & 0x00000FFF) + 1;
1264    int height = (s->dc_crt_v_total & 0x00000FFF) + 1;
1265
1266    uint8_t  * src = s->local_mem;
1267    int src_bpp = 0;
1268    int dst_bpp = surface_bytes_per_pixel(surface);
1269    uint32_t * palette = (uint32_t *)&s->dc_palette[SM501_DC_CRT_PALETTE
1270                                                    - SM501_DC_PANEL_PALETTE];
1271    uint8_t hwc_palette[3 * 3];
1272    int ds_depth_index = get_depth_index(surface);
1273    draw_line_func * draw_line = NULL;
1274    draw_hwc_line_func * draw_hwc_line = NULL;
1275    int full_update = 0;
1276    int y_start = -1;
1277    ram_addr_t page_min = ~0l;
1278    ram_addr_t page_max = 0l;
1279    ram_addr_t offset = 0;
1280
1281    /* choose draw_line function */
1282    switch (s->dc_crt_control & 3) {
1283    case SM501_DC_CRT_CONTROL_8BPP:
1284        src_bpp = 1;
1285        draw_line = draw_line8_funcs[ds_depth_index];
1286        break;
1287    case SM501_DC_CRT_CONTROL_16BPP:
1288        src_bpp = 2;
1289        draw_line = draw_line16_funcs[ds_depth_index];
1290        break;
1291    case SM501_DC_CRT_CONTROL_32BPP:
1292        src_bpp = 4;
1293        draw_line = draw_line32_funcs[ds_depth_index];
1294        break;
1295    default:
1296        printf("sm501 draw crt : invalid DC_CRT_CONTROL=%x.\n",
1297               s->dc_crt_control);
1298        abort();
1299        break;
1300    }
1301
1302    /* set up to draw hardware cursor */
1303    if (is_hwc_enabled(s, 1)) {
1304        int i;
1305
1306        /* get cursor palette */
1307        for (i = 0; i < 3; i++) {
1308            uint16_t rgb565 = get_hwc_color(s, 1, i + 1);
1309            hwc_palette[i * 3 + 0] = (rgb565 & 0xf800) >> 8; /* red */
1310            hwc_palette[i * 3 + 1] = (rgb565 & 0x07e0) >> 3; /* green */
1311            hwc_palette[i * 3 + 2] = (rgb565 & 0x001f) << 3; /* blue */
1312        }
1313
1314        /* choose cursor draw line function */
1315        draw_hwc_line = draw_hwc_line_funcs[ds_depth_index];
1316    }
1317
1318    /* adjust console size */
1319    if (s->last_width != width || s->last_height != height) {
1320        qemu_console_resize(s->con, width, height);
1321        surface = qemu_console_surface(s->con);
1322        s->last_width = width;
1323        s->last_height = height;
1324        full_update = 1;
1325    }
1326
1327    /* draw each line according to conditions */
1328    memory_region_sync_dirty_bitmap(&s->local_mem_region);
1329    for (y = 0; y < height; y++) {
1330        int update_hwc = draw_hwc_line ? within_hwc_y_range(s, y, 1) : 0;
1331        int update = full_update || update_hwc;
1332        ram_addr_t page0 = offset;
1333        ram_addr_t page1 = offset + width * src_bpp - 1;
1334
1335        /* check dirty flags for each line */
1336        update = memory_region_get_dirty(&s->local_mem_region, page0,
1337                                         page1 - page0, DIRTY_MEMORY_VGA);
1338
1339        /* draw line and change status */
1340        if (update) {
1341            uint8_t *d = surface_data(surface);
1342            d +=  y * width * dst_bpp;
1343
1344            /* draw graphics layer */
1345            draw_line(d, src, width, palette);
1346
1347            /* draw haredware cursor */
1348            if (update_hwc) {
1349                draw_hwc_line(s, 1, hwc_palette, y - get_hwc_y(s, 1), d, width);
1350            }
1351
1352            if (y_start < 0)
1353                y_start = y;
1354            if (page0 < page_min)
1355                page_min = page0;
1356            if (page1 > page_max)
1357                page_max = page1;
1358        } else {
1359            if (y_start >= 0) {
1360                /* flush to display */
1361                dpy_gfx_update(s->con, 0, y_start, width, y - y_start);
1362                y_start = -1;
1363            }
1364        }
1365
1366        src += width * src_bpp;
1367        offset += width * src_bpp;
1368    }
1369
1370    /* complete flush to display */
1371    if (y_start >= 0)
1372        dpy_gfx_update(s->con, 0, y_start, width, y - y_start);
1373
1374    /* clear dirty flags */
1375    if (page_min != ~0l) {
1376        memory_region_reset_dirty(&s->local_mem_region,
1377                                  page_min, page_max + TARGET_PAGE_SIZE,
1378                                  DIRTY_MEMORY_VGA);
1379    }
1380}
1381
1382static void sm501_update_display(void *opaque)
1383{
1384    SM501State * s = (SM501State *)opaque;
1385
1386    if (s->dc_crt_control & SM501_DC_CRT_CONTROL_ENABLE)
1387        sm501_draw_crt(s);
1388}
1389
1390static const GraphicHwOps sm501_ops = {
1391    .gfx_update  = sm501_update_display,
1392};
1393
1394void sm501_init(MemoryRegion *address_space_mem, uint32_t base,
1395                uint32_t local_mem_bytes, qemu_irq irq, CharDriverState *chr)
1396{
1397    SM501State * s;
1398    DeviceState *dev;
1399    MemoryRegion *sm501_system_config = g_new(MemoryRegion, 1);
1400    MemoryRegion *sm501_disp_ctrl = g_new(MemoryRegion, 1);
1401    MemoryRegion *sm501_2d_engine = g_new(MemoryRegion, 1);
1402
1403    /* allocate management data region */
1404    s = (SM501State *)g_malloc0(sizeof(SM501State));
1405    s->base = base;
1406    s->local_mem_size_index
1407        = get_local_mem_size_index(local_mem_bytes);
1408    SM501_DPRINTF("local mem size=%x. index=%d\n", get_local_mem_size(s),
1409                  s->local_mem_size_index);
1410    s->system_control = 0x00100000;
1411    s->misc_control = 0x00001000; /* assumes SH, active=low */
1412    s->dc_panel_control = 0x00010000;
1413    s->dc_crt_control = 0x00010000;
1414
1415    /* allocate local memory */
1416    memory_region_init_ram(&s->local_mem_region, NULL, "sm501.local",
1417                           local_mem_bytes, &error_fatal);
1418    vmstate_register_ram_global(&s->local_mem_region);
1419    memory_region_set_log(&s->local_mem_region, true, DIRTY_MEMORY_VGA);
1420    s->local_mem = memory_region_get_ram_ptr(&s->local_mem_region);
1421    memory_region_add_subregion(address_space_mem, base, &s->local_mem_region);
1422
1423    /* map mmio */
1424    memory_region_init_io(sm501_system_config, NULL, &sm501_system_config_ops, s,
1425                          "sm501-system-config", 0x6c);
1426    memory_region_add_subregion(address_space_mem, base + MMIO_BASE_OFFSET,
1427                                sm501_system_config);
1428    memory_region_init_io(sm501_disp_ctrl, NULL, &sm501_disp_ctrl_ops, s,
1429                          "sm501-disp-ctrl", 0x1000);
1430    memory_region_add_subregion(address_space_mem,
1431                                base + MMIO_BASE_OFFSET + SM501_DC,
1432                                sm501_disp_ctrl);
1433    memory_region_init_io(sm501_2d_engine, NULL, &sm501_2d_engine_ops, s,
1434                          "sm501-2d-engine", 0x54);
1435    memory_region_add_subregion(address_space_mem,
1436                                base + MMIO_BASE_OFFSET + SM501_2D_ENGINE,
1437                                sm501_2d_engine);
1438
1439    /* bridge to usb host emulation module */
1440    dev = qdev_create(NULL, "sysbus-ohci");
1441    qdev_prop_set_uint32(dev, "num-ports", 2);
1442    qdev_prop_set_uint64(dev, "dma-offset", base);
1443    qdev_init_nofail(dev);
1444    sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0,
1445                    base + MMIO_BASE_OFFSET + SM501_USB_HOST);
1446    sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, irq);
1447
1448    /* bridge to serial emulation module */
1449    if (chr) {
1450        serial_mm_init(address_space_mem,
1451                       base + MMIO_BASE_OFFSET + SM501_UART0, 2,
1452                       NULL, /* TODO : chain irq to IRL */
1453                       115200, chr, DEVICE_NATIVE_ENDIAN);
1454    }
1455
1456    /* create qemu graphic console */
1457    s->con = graphic_console_init(DEVICE(dev), 0, &sm501_ops, s);
1458}
1459