1 /* 2 * Epson S1D13744/S1D13745 (Blizzard/Hailstorm/Tornado) LCD/TV controller. 3 * 4 * Copyright (C) 2008 Nokia Corporation 5 * Written by Andrzej Zaborowski <andrew@openedhand.com> 6 * 7 * This program is free software; you can redistribute it and/or 8 * modify it under the terms of the GNU General Public License as 9 * published by the Free Software Foundation; either version 2 or 10 * (at your option) version 3 of the License. 11 * 12 * This program is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 * GNU General Public License for more details. 16 * 17 * You should have received a copy of the GNU General Public License along 18 * with this program; if not, see <http://www.gnu.org/licenses/>. 19 */ 20 21 #include "qemu/osdep.h" 22 #include "qemu-common.h" 23 #include "ui/console.h" 24 #include "hw/display/blizzard.h" 25 #include "ui/pixel_ops.h" 26 27 typedef void (*blizzard_fn_t)(uint8_t *, const uint8_t *, unsigned int); 28 29 typedef struct { 30 uint8_t reg; 31 uint32_t addr; 32 int swallow; 33 34 int pll; 35 int pll_range; 36 int pll_ctrl; 37 uint8_t pll_mode; 38 uint8_t clksel; 39 int memenable; 40 int memrefresh; 41 uint8_t timing[3]; 42 int priority; 43 44 uint8_t lcd_config; 45 int x; 46 int y; 47 int skipx; 48 int skipy; 49 uint8_t hndp; 50 uint8_t vndp; 51 uint8_t hsync; 52 uint8_t vsync; 53 uint8_t pclk; 54 uint8_t u; 55 uint8_t v; 56 uint8_t yrc[2]; 57 int ix[2]; 58 int iy[2]; 59 int ox[2]; 60 int oy[2]; 61 62 int enable; 63 int blank; 64 int bpp; 65 int invalidate; 66 int mx[2]; 67 int my[2]; 68 uint8_t mode; 69 uint8_t effect; 70 uint8_t iformat; 71 uint8_t source; 72 QemuConsole *con; 73 blizzard_fn_t *line_fn_tab[2]; 74 void *fb; 75 76 uint8_t hssi_config[3]; 77 uint8_t tv_config; 78 uint8_t tv_timing[4]; 79 uint8_t vbi; 80 uint8_t tv_x; 81 uint8_t tv_y; 82 uint8_t tv_test; 83 uint8_t tv_filter_config; 84 uint8_t tv_filter_idx; 85 uint8_t tv_filter_coeff[0x20]; 86 uint8_t border_r; 87 uint8_t border_g; 88 uint8_t border_b; 89 uint8_t gamma_config; 90 uint8_t gamma_idx; 91 uint8_t gamma_lut[0x100]; 92 uint8_t matrix_ena; 93 uint8_t matrix_coeff[0x12]; 94 uint8_t matrix_r; 95 uint8_t matrix_g; 96 uint8_t matrix_b; 97 uint8_t pm; 98 uint8_t status; 99 uint8_t rgbgpio_dir; 100 uint8_t rgbgpio; 101 uint8_t gpio_dir; 102 uint8_t gpio; 103 uint8_t gpio_edge[2]; 104 uint8_t gpio_irq; 105 uint8_t gpio_pdown; 106 107 struct { 108 int x; 109 int y; 110 int dx; 111 int dy; 112 int len; 113 int buflen; 114 void *buf; 115 void *data; 116 uint16_t *ptr; 117 int angle; 118 int pitch; 119 blizzard_fn_t line_fn; 120 } data; 121 } BlizzardState; 122 123 /* Bytes(!) per pixel */ 124 static const int blizzard_iformat_bpp[0x10] = { 125 0, 126 2, /* RGB 5:6:5*/ 127 3, /* RGB 6:6:6 mode 1 */ 128 3, /* RGB 8:8:8 mode 1 */ 129 0, 0, 130 4, /* RGB 6:6:6 mode 2 */ 131 4, /* RGB 8:8:8 mode 2 */ 132 0, /* YUV 4:2:2 */ 133 0, /* YUV 4:2:0 */ 134 0, 0, 0, 0, 0, 0, 135 }; 136 137 static void blizzard_window(BlizzardState *s) 138 { 139 DisplaySurface *surface = qemu_console_surface(s->con); 140 uint8_t *src, *dst; 141 int bypp[2]; 142 int bypl[3]; 143 int y; 144 blizzard_fn_t fn = s->data.line_fn; 145 146 if (!fn) 147 return; 148 if (s->mx[0] > s->data.x) 149 s->mx[0] = s->data.x; 150 if (s->my[0] > s->data.y) 151 s->my[0] = s->data.y; 152 if (s->mx[1] < s->data.x + s->data.dx) 153 s->mx[1] = s->data.x + s->data.dx; 154 if (s->my[1] < s->data.y + s->data.dy) 155 s->my[1] = s->data.y + s->data.dy; 156 157 bypp[0] = s->bpp; 158 bypp[1] = surface_bytes_per_pixel(surface); 159 bypl[0] = bypp[0] * s->data.pitch; 160 bypl[1] = bypp[1] * s->x; 161 bypl[2] = bypp[0] * s->data.dx; 162 163 src = s->data.data; 164 dst = s->fb + bypl[1] * s->data.y + bypp[1] * s->data.x; 165 for (y = s->data.dy; y > 0; y --, src += bypl[0], dst += bypl[1]) 166 fn(dst, src, bypl[2]); 167 } 168 169 static int blizzard_transfer_setup(BlizzardState *s) 170 { 171 if (s->source > 3 || !s->bpp || 172 s->ix[1] < s->ix[0] || s->iy[1] < s->iy[0]) 173 return 0; 174 175 s->data.angle = s->effect & 3; 176 s->data.line_fn = s->line_fn_tab[!!s->data.angle][s->iformat]; 177 s->data.x = s->ix[0]; 178 s->data.y = s->iy[0]; 179 s->data.dx = s->ix[1] - s->ix[0] + 1; 180 s->data.dy = s->iy[1] - s->iy[0] + 1; 181 s->data.len = s->bpp * s->data.dx * s->data.dy; 182 s->data.pitch = s->data.dx; 183 if (s->data.len > s->data.buflen) { 184 s->data.buf = g_realloc(s->data.buf, s->data.len); 185 s->data.buflen = s->data.len; 186 } 187 s->data.ptr = s->data.buf; 188 s->data.data = s->data.buf; 189 s->data.len /= 2; 190 return 1; 191 } 192 193 static void blizzard_reset(BlizzardState *s) 194 { 195 s->reg = 0; 196 s->swallow = 0; 197 198 s->pll = 9; 199 s->pll_range = 1; 200 s->pll_ctrl = 0x14; 201 s->pll_mode = 0x32; 202 s->clksel = 0x00; 203 s->memenable = 0; 204 s->memrefresh = 0x25c; 205 s->timing[0] = 0x3f; 206 s->timing[1] = 0x13; 207 s->timing[2] = 0x21; 208 s->priority = 0; 209 210 s->lcd_config = 0x74; 211 s->x = 8; 212 s->y = 1; 213 s->skipx = 0; 214 s->skipy = 0; 215 s->hndp = 3; 216 s->vndp = 2; 217 s->hsync = 1; 218 s->vsync = 1; 219 s->pclk = 0x80; 220 221 s->ix[0] = 0; 222 s->ix[1] = 0; 223 s->iy[0] = 0; 224 s->iy[1] = 0; 225 s->ox[0] = 0; 226 s->ox[1] = 0; 227 s->oy[0] = 0; 228 s->oy[1] = 0; 229 230 s->yrc[0] = 0x00; 231 s->yrc[1] = 0x30; 232 s->u = 0; 233 s->v = 0; 234 235 s->iformat = 3; 236 s->source = 0; 237 s->bpp = blizzard_iformat_bpp[s->iformat]; 238 239 s->hssi_config[0] = 0x00; 240 s->hssi_config[1] = 0x00; 241 s->hssi_config[2] = 0x01; 242 s->tv_config = 0x00; 243 s->tv_timing[0] = 0x00; 244 s->tv_timing[1] = 0x00; 245 s->tv_timing[2] = 0x00; 246 s->tv_timing[3] = 0x00; 247 s->vbi = 0x10; 248 s->tv_x = 0x14; 249 s->tv_y = 0x03; 250 s->tv_test = 0x00; 251 s->tv_filter_config = 0x80; 252 s->tv_filter_idx = 0x00; 253 s->border_r = 0x10; 254 s->border_g = 0x80; 255 s->border_b = 0x80; 256 s->gamma_config = 0x00; 257 s->gamma_idx = 0x00; 258 s->matrix_ena = 0x00; 259 memset(&s->matrix_coeff, 0, sizeof(s->matrix_coeff)); 260 s->matrix_r = 0x00; 261 s->matrix_g = 0x00; 262 s->matrix_b = 0x00; 263 s->pm = 0x02; 264 s->status = 0x00; 265 s->rgbgpio_dir = 0x00; 266 s->gpio_dir = 0x00; 267 s->gpio_edge[0] = 0x00; 268 s->gpio_edge[1] = 0x00; 269 s->gpio_irq = 0x00; 270 s->gpio_pdown = 0xff; 271 } 272 273 static inline void blizzard_invalidate_display(void *opaque) { 274 BlizzardState *s = (BlizzardState *) opaque; 275 276 s->invalidate = 1; 277 } 278 279 static uint16_t blizzard_reg_read(void *opaque, uint8_t reg) 280 { 281 BlizzardState *s = (BlizzardState *) opaque; 282 283 switch (reg) { 284 case 0x00: /* Revision Code */ 285 return 0xa5; 286 287 case 0x02: /* Configuration Readback */ 288 return 0x83; /* Macrovision OK, CNF[2:0] = 3 */ 289 290 case 0x04: /* PLL M-Divider */ 291 return (s->pll - 1) | (1 << 7); 292 case 0x06: /* PLL Lock Range Control */ 293 return s->pll_range; 294 case 0x08: /* PLL Lock Synthesis Control 0 */ 295 return s->pll_ctrl & 0xff; 296 case 0x0a: /* PLL Lock Synthesis Control 1 */ 297 return s->pll_ctrl >> 8; 298 case 0x0c: /* PLL Mode Control 0 */ 299 return s->pll_mode; 300 301 case 0x0e: /* Clock-Source Select */ 302 return s->clksel; 303 304 case 0x10: /* Memory Controller Activate */ 305 case 0x14: /* Memory Controller Bank 0 Status Flag */ 306 return s->memenable; 307 308 case 0x18: /* Auto-Refresh Interval Setting 0 */ 309 return s->memrefresh & 0xff; 310 case 0x1a: /* Auto-Refresh Interval Setting 1 */ 311 return s->memrefresh >> 8; 312 313 case 0x1c: /* Power-On Sequence Timing Control */ 314 return s->timing[0]; 315 case 0x1e: /* Timing Control 0 */ 316 return s->timing[1]; 317 case 0x20: /* Timing Control 1 */ 318 return s->timing[2]; 319 320 case 0x24: /* Arbitration Priority Control */ 321 return s->priority; 322 323 case 0x28: /* LCD Panel Configuration */ 324 return s->lcd_config; 325 326 case 0x2a: /* LCD Horizontal Display Width */ 327 return s->x >> 3; 328 case 0x2c: /* LCD Horizontal Non-display Period */ 329 return s->hndp; 330 case 0x2e: /* LCD Vertical Display Height 0 */ 331 return s->y & 0xff; 332 case 0x30: /* LCD Vertical Display Height 1 */ 333 return s->y >> 8; 334 case 0x32: /* LCD Vertical Non-display Period */ 335 return s->vndp; 336 case 0x34: /* LCD HS Pulse-width */ 337 return s->hsync; 338 case 0x36: /* LCd HS Pulse Start Position */ 339 return s->skipx >> 3; 340 case 0x38: /* LCD VS Pulse-width */ 341 return s->vsync; 342 case 0x3a: /* LCD VS Pulse Start Position */ 343 return s->skipy; 344 345 case 0x3c: /* PCLK Polarity */ 346 return s->pclk; 347 348 case 0x3e: /* High-speed Serial Interface Tx Configuration Port 0 */ 349 return s->hssi_config[0]; 350 case 0x40: /* High-speed Serial Interface Tx Configuration Port 1 */ 351 return s->hssi_config[1]; 352 case 0x42: /* High-speed Serial Interface Tx Mode */ 353 return s->hssi_config[2]; 354 case 0x44: /* TV Display Configuration */ 355 return s->tv_config; 356 case 0x46 ... 0x4c: /* TV Vertical Blanking Interval Data bits */ 357 return s->tv_timing[(reg - 0x46) >> 1]; 358 case 0x4e: /* VBI: Closed Caption / XDS Control / Status */ 359 return s->vbi; 360 case 0x50: /* TV Horizontal Start Position */ 361 return s->tv_x; 362 case 0x52: /* TV Vertical Start Position */ 363 return s->tv_y; 364 case 0x54: /* TV Test Pattern Setting */ 365 return s->tv_test; 366 case 0x56: /* TV Filter Setting */ 367 return s->tv_filter_config; 368 case 0x58: /* TV Filter Coefficient Index */ 369 return s->tv_filter_idx; 370 case 0x5a: /* TV Filter Coefficient Data */ 371 if (s->tv_filter_idx < 0x20) 372 return s->tv_filter_coeff[s->tv_filter_idx ++]; 373 return 0; 374 375 case 0x60: /* Input YUV/RGB Translate Mode 0 */ 376 return s->yrc[0]; 377 case 0x62: /* Input YUV/RGB Translate Mode 1 */ 378 return s->yrc[1]; 379 case 0x64: /* U Data Fix */ 380 return s->u; 381 case 0x66: /* V Data Fix */ 382 return s->v; 383 384 case 0x68: /* Display Mode */ 385 return s->mode; 386 387 case 0x6a: /* Special Effects */ 388 return s->effect; 389 390 case 0x6c: /* Input Window X Start Position 0 */ 391 return s->ix[0] & 0xff; 392 case 0x6e: /* Input Window X Start Position 1 */ 393 return s->ix[0] >> 3; 394 case 0x70: /* Input Window Y Start Position 0 */ 395 return s->ix[0] & 0xff; 396 case 0x72: /* Input Window Y Start Position 1 */ 397 return s->ix[0] >> 3; 398 case 0x74: /* Input Window X End Position 0 */ 399 return s->ix[1] & 0xff; 400 case 0x76: /* Input Window X End Position 1 */ 401 return s->ix[1] >> 3; 402 case 0x78: /* Input Window Y End Position 0 */ 403 return s->ix[1] & 0xff; 404 case 0x7a: /* Input Window Y End Position 1 */ 405 return s->ix[1] >> 3; 406 case 0x7c: /* Output Window X Start Position 0 */ 407 return s->ox[0] & 0xff; 408 case 0x7e: /* Output Window X Start Position 1 */ 409 return s->ox[0] >> 3; 410 case 0x80: /* Output Window Y Start Position 0 */ 411 return s->oy[0] & 0xff; 412 case 0x82: /* Output Window Y Start Position 1 */ 413 return s->oy[0] >> 3; 414 case 0x84: /* Output Window X End Position 0 */ 415 return s->ox[1] & 0xff; 416 case 0x86: /* Output Window X End Position 1 */ 417 return s->ox[1] >> 3; 418 case 0x88: /* Output Window Y End Position 0 */ 419 return s->oy[1] & 0xff; 420 case 0x8a: /* Output Window Y End Position 1 */ 421 return s->oy[1] >> 3; 422 423 case 0x8c: /* Input Data Format */ 424 return s->iformat; 425 case 0x8e: /* Data Source Select */ 426 return s->source; 427 case 0x90: /* Display Memory Data Port */ 428 return 0; 429 430 case 0xa8: /* Border Color 0 */ 431 return s->border_r; 432 case 0xaa: /* Border Color 1 */ 433 return s->border_g; 434 case 0xac: /* Border Color 2 */ 435 return s->border_b; 436 437 case 0xb4: /* Gamma Correction Enable */ 438 return s->gamma_config; 439 case 0xb6: /* Gamma Correction Table Index */ 440 return s->gamma_idx; 441 case 0xb8: /* Gamma Correction Table Data */ 442 return s->gamma_lut[s->gamma_idx ++]; 443 444 case 0xba: /* 3x3 Matrix Enable */ 445 return s->matrix_ena; 446 case 0xbc ... 0xde: /* Coefficient Registers */ 447 return s->matrix_coeff[(reg - 0xbc) >> 1]; 448 case 0xe0: /* 3x3 Matrix Red Offset */ 449 return s->matrix_r; 450 case 0xe2: /* 3x3 Matrix Green Offset */ 451 return s->matrix_g; 452 case 0xe4: /* 3x3 Matrix Blue Offset */ 453 return s->matrix_b; 454 455 case 0xe6: /* Power-save */ 456 return s->pm; 457 case 0xe8: /* Non-display Period Control / Status */ 458 return s->status | (1 << 5); 459 case 0xea: /* RGB Interface Control */ 460 return s->rgbgpio_dir; 461 case 0xec: /* RGB Interface Status */ 462 return s->rgbgpio; 463 case 0xee: /* General-purpose IO Pins Configuration */ 464 return s->gpio_dir; 465 case 0xf0: /* General-purpose IO Pins Status / Control */ 466 return s->gpio; 467 case 0xf2: /* GPIO Positive Edge Interrupt Trigger */ 468 return s->gpio_edge[0]; 469 case 0xf4: /* GPIO Negative Edge Interrupt Trigger */ 470 return s->gpio_edge[1]; 471 case 0xf6: /* GPIO Interrupt Status */ 472 return s->gpio_irq; 473 case 0xf8: /* GPIO Pull-down Control */ 474 return s->gpio_pdown; 475 476 default: 477 fprintf(stderr, "%s: unknown register %02x\n", __func__, reg); 478 return 0; 479 } 480 } 481 482 static void blizzard_reg_write(void *opaque, uint8_t reg, uint16_t value) 483 { 484 BlizzardState *s = (BlizzardState *) opaque; 485 486 switch (reg) { 487 case 0x04: /* PLL M-Divider */ 488 s->pll = (value & 0x3f) + 1; 489 break; 490 case 0x06: /* PLL Lock Range Control */ 491 s->pll_range = value & 3; 492 break; 493 case 0x08: /* PLL Lock Synthesis Control 0 */ 494 s->pll_ctrl &= 0xf00; 495 s->pll_ctrl |= (value << 0) & 0x0ff; 496 break; 497 case 0x0a: /* PLL Lock Synthesis Control 1 */ 498 s->pll_ctrl &= 0x0ff; 499 s->pll_ctrl |= (value << 8) & 0xf00; 500 break; 501 case 0x0c: /* PLL Mode Control 0 */ 502 s->pll_mode = value & 0x77; 503 if ((value & 3) == 0 || (value & 3) == 3) 504 fprintf(stderr, "%s: wrong PLL Control bits (%i)\n", 505 __func__, value & 3); 506 break; 507 508 case 0x0e: /* Clock-Source Select */ 509 s->clksel = value & 0xff; 510 break; 511 512 case 0x10: /* Memory Controller Activate */ 513 s->memenable = value & 1; 514 break; 515 case 0x14: /* Memory Controller Bank 0 Status Flag */ 516 break; 517 518 case 0x18: /* Auto-Refresh Interval Setting 0 */ 519 s->memrefresh &= 0xf00; 520 s->memrefresh |= (value << 0) & 0x0ff; 521 break; 522 case 0x1a: /* Auto-Refresh Interval Setting 1 */ 523 s->memrefresh &= 0x0ff; 524 s->memrefresh |= (value << 8) & 0xf00; 525 break; 526 527 case 0x1c: /* Power-On Sequence Timing Control */ 528 s->timing[0] = value & 0x7f; 529 break; 530 case 0x1e: /* Timing Control 0 */ 531 s->timing[1] = value & 0x17; 532 break; 533 case 0x20: /* Timing Control 1 */ 534 s->timing[2] = value & 0x35; 535 break; 536 537 case 0x24: /* Arbitration Priority Control */ 538 s->priority = value & 1; 539 break; 540 541 case 0x28: /* LCD Panel Configuration */ 542 s->lcd_config = value & 0xff; 543 if (value & (1 << 7)) 544 fprintf(stderr, "%s: data swap not supported!\n", __func__); 545 break; 546 547 case 0x2a: /* LCD Horizontal Display Width */ 548 s->x = value << 3; 549 break; 550 case 0x2c: /* LCD Horizontal Non-display Period */ 551 s->hndp = value & 0xff; 552 break; 553 case 0x2e: /* LCD Vertical Display Height 0 */ 554 s->y &= 0x300; 555 s->y |= (value << 0) & 0x0ff; 556 break; 557 case 0x30: /* LCD Vertical Display Height 1 */ 558 s->y &= 0x0ff; 559 s->y |= (value << 8) & 0x300; 560 break; 561 case 0x32: /* LCD Vertical Non-display Period */ 562 s->vndp = value & 0xff; 563 break; 564 case 0x34: /* LCD HS Pulse-width */ 565 s->hsync = value & 0xff; 566 break; 567 case 0x36: /* LCD HS Pulse Start Position */ 568 s->skipx = value & 0xff; 569 break; 570 case 0x38: /* LCD VS Pulse-width */ 571 s->vsync = value & 0xbf; 572 break; 573 case 0x3a: /* LCD VS Pulse Start Position */ 574 s->skipy = value & 0xff; 575 break; 576 577 case 0x3c: /* PCLK Polarity */ 578 s->pclk = value & 0x82; 579 /* Affects calculation of s->hndp, s->hsync and s->skipx. */ 580 break; 581 582 case 0x3e: /* High-speed Serial Interface Tx Configuration Port 0 */ 583 s->hssi_config[0] = value; 584 break; 585 case 0x40: /* High-speed Serial Interface Tx Configuration Port 1 */ 586 s->hssi_config[1] = value; 587 if (((value >> 4) & 3) == 3) 588 fprintf(stderr, "%s: Illegal active-data-links value\n", 589 __func__); 590 break; 591 case 0x42: /* High-speed Serial Interface Tx Mode */ 592 s->hssi_config[2] = value & 0xbd; 593 break; 594 595 case 0x44: /* TV Display Configuration */ 596 s->tv_config = value & 0xfe; 597 break; 598 case 0x46 ... 0x4c: /* TV Vertical Blanking Interval Data bits 0 */ 599 s->tv_timing[(reg - 0x46) >> 1] = value; 600 break; 601 case 0x4e: /* VBI: Closed Caption / XDS Control / Status */ 602 s->vbi = value; 603 break; 604 case 0x50: /* TV Horizontal Start Position */ 605 s->tv_x = value; 606 break; 607 case 0x52: /* TV Vertical Start Position */ 608 s->tv_y = value & 0x7f; 609 break; 610 case 0x54: /* TV Test Pattern Setting */ 611 s->tv_test = value; 612 break; 613 case 0x56: /* TV Filter Setting */ 614 s->tv_filter_config = value & 0xbf; 615 break; 616 case 0x58: /* TV Filter Coefficient Index */ 617 s->tv_filter_idx = value & 0x1f; 618 break; 619 case 0x5a: /* TV Filter Coefficient Data */ 620 if (s->tv_filter_idx < 0x20) 621 s->tv_filter_coeff[s->tv_filter_idx ++] = value; 622 break; 623 624 case 0x60: /* Input YUV/RGB Translate Mode 0 */ 625 s->yrc[0] = value & 0xb0; 626 break; 627 case 0x62: /* Input YUV/RGB Translate Mode 1 */ 628 s->yrc[1] = value & 0x30; 629 break; 630 case 0x64: /* U Data Fix */ 631 s->u = value & 0xff; 632 break; 633 case 0x66: /* V Data Fix */ 634 s->v = value & 0xff; 635 break; 636 637 case 0x68: /* Display Mode */ 638 if ((s->mode ^ value) & 3) 639 s->invalidate = 1; 640 s->mode = value & 0xb7; 641 s->enable = value & 1; 642 s->blank = (value >> 1) & 1; 643 if (value & (1 << 4)) 644 fprintf(stderr, "%s: Macrovision enable attempt!\n", __func__); 645 break; 646 647 case 0x6a: /* Special Effects */ 648 s->effect = value & 0xfb; 649 break; 650 651 case 0x6c: /* Input Window X Start Position 0 */ 652 s->ix[0] &= 0x300; 653 s->ix[0] |= (value << 0) & 0x0ff; 654 break; 655 case 0x6e: /* Input Window X Start Position 1 */ 656 s->ix[0] &= 0x0ff; 657 s->ix[0] |= (value << 8) & 0x300; 658 break; 659 case 0x70: /* Input Window Y Start Position 0 */ 660 s->iy[0] &= 0x300; 661 s->iy[0] |= (value << 0) & 0x0ff; 662 break; 663 case 0x72: /* Input Window Y Start Position 1 */ 664 s->iy[0] &= 0x0ff; 665 s->iy[0] |= (value << 8) & 0x300; 666 break; 667 case 0x74: /* Input Window X End Position 0 */ 668 s->ix[1] &= 0x300; 669 s->ix[1] |= (value << 0) & 0x0ff; 670 break; 671 case 0x76: /* Input Window X End Position 1 */ 672 s->ix[1] &= 0x0ff; 673 s->ix[1] |= (value << 8) & 0x300; 674 break; 675 case 0x78: /* Input Window Y End Position 0 */ 676 s->iy[1] &= 0x300; 677 s->iy[1] |= (value << 0) & 0x0ff; 678 break; 679 case 0x7a: /* Input Window Y End Position 1 */ 680 s->iy[1] &= 0x0ff; 681 s->iy[1] |= (value << 8) & 0x300; 682 break; 683 case 0x7c: /* Output Window X Start Position 0 */ 684 s->ox[0] &= 0x300; 685 s->ox[0] |= (value << 0) & 0x0ff; 686 break; 687 case 0x7e: /* Output Window X Start Position 1 */ 688 s->ox[0] &= 0x0ff; 689 s->ox[0] |= (value << 8) & 0x300; 690 break; 691 case 0x80: /* Output Window Y Start Position 0 */ 692 s->oy[0] &= 0x300; 693 s->oy[0] |= (value << 0) & 0x0ff; 694 break; 695 case 0x82: /* Output Window Y Start Position 1 */ 696 s->oy[0] &= 0x0ff; 697 s->oy[0] |= (value << 8) & 0x300; 698 break; 699 case 0x84: /* Output Window X End Position 0 */ 700 s->ox[1] &= 0x300; 701 s->ox[1] |= (value << 0) & 0x0ff; 702 break; 703 case 0x86: /* Output Window X End Position 1 */ 704 s->ox[1] &= 0x0ff; 705 s->ox[1] |= (value << 8) & 0x300; 706 break; 707 case 0x88: /* Output Window Y End Position 0 */ 708 s->oy[1] &= 0x300; 709 s->oy[1] |= (value << 0) & 0x0ff; 710 break; 711 case 0x8a: /* Output Window Y End Position 1 */ 712 s->oy[1] &= 0x0ff; 713 s->oy[1] |= (value << 8) & 0x300; 714 break; 715 716 case 0x8c: /* Input Data Format */ 717 s->iformat = value & 0xf; 718 s->bpp = blizzard_iformat_bpp[s->iformat]; 719 if (!s->bpp) 720 fprintf(stderr, "%s: Illegal or unsupported input format %x\n", 721 __func__, s->iformat); 722 break; 723 case 0x8e: /* Data Source Select */ 724 s->source = value & 7; 725 /* Currently all windows will be "destructive overlays". */ 726 if ((!(s->effect & (1 << 3)) && (s->ix[0] != s->ox[0] || 727 s->iy[0] != s->oy[0] || 728 s->ix[1] != s->ox[1] || 729 s->iy[1] != s->oy[1])) || 730 !((s->ix[1] - s->ix[0]) & (s->iy[1] - s->iy[0]) & 731 (s->ox[1] - s->ox[0]) & (s->oy[1] - s->oy[0]) & 1)) 732 fprintf(stderr, "%s: Illegal input/output window positions\n", 733 __func__); 734 735 blizzard_transfer_setup(s); 736 break; 737 738 case 0x90: /* Display Memory Data Port */ 739 if (!s->data.len && !blizzard_transfer_setup(s)) 740 break; 741 742 *s->data.ptr ++ = value; 743 if (-- s->data.len == 0) 744 blizzard_window(s); 745 break; 746 747 case 0xa8: /* Border Color 0 */ 748 s->border_r = value; 749 break; 750 case 0xaa: /* Border Color 1 */ 751 s->border_g = value; 752 break; 753 case 0xac: /* Border Color 2 */ 754 s->border_b = value; 755 break; 756 757 case 0xb4: /* Gamma Correction Enable */ 758 s->gamma_config = value & 0x87; 759 break; 760 case 0xb6: /* Gamma Correction Table Index */ 761 s->gamma_idx = value; 762 break; 763 case 0xb8: /* Gamma Correction Table Data */ 764 s->gamma_lut[s->gamma_idx ++] = value; 765 break; 766 767 case 0xba: /* 3x3 Matrix Enable */ 768 s->matrix_ena = value & 1; 769 break; 770 case 0xbc ... 0xde: /* Coefficient Registers */ 771 s->matrix_coeff[(reg - 0xbc) >> 1] = value & ((reg & 2) ? 0x80 : 0xff); 772 break; 773 case 0xe0: /* 3x3 Matrix Red Offset */ 774 s->matrix_r = value; 775 break; 776 case 0xe2: /* 3x3 Matrix Green Offset */ 777 s->matrix_g = value; 778 break; 779 case 0xe4: /* 3x3 Matrix Blue Offset */ 780 s->matrix_b = value; 781 break; 782 783 case 0xe6: /* Power-save */ 784 s->pm = value & 0x83; 785 if (value & s->mode & 1) 786 fprintf(stderr, "%s: The display must be disabled before entering " 787 "Standby Mode\n", __func__); 788 break; 789 case 0xe8: /* Non-display Period Control / Status */ 790 s->status = value & 0x1b; 791 break; 792 case 0xea: /* RGB Interface Control */ 793 s->rgbgpio_dir = value & 0x8f; 794 break; 795 case 0xec: /* RGB Interface Status */ 796 s->rgbgpio = value & 0xcf; 797 break; 798 case 0xee: /* General-purpose IO Pins Configuration */ 799 s->gpio_dir = value; 800 break; 801 case 0xf0: /* General-purpose IO Pins Status / Control */ 802 s->gpio = value; 803 break; 804 case 0xf2: /* GPIO Positive Edge Interrupt Trigger */ 805 s->gpio_edge[0] = value; 806 break; 807 case 0xf4: /* GPIO Negative Edge Interrupt Trigger */ 808 s->gpio_edge[1] = value; 809 break; 810 case 0xf6: /* GPIO Interrupt Status */ 811 s->gpio_irq &= value; 812 break; 813 case 0xf8: /* GPIO Pull-down Control */ 814 s->gpio_pdown = value; 815 break; 816 817 default: 818 fprintf(stderr, "%s: unknown register %02x\n", __func__, reg); 819 break; 820 } 821 } 822 823 uint16_t s1d13745_read(void *opaque, int dc) 824 { 825 BlizzardState *s = (BlizzardState *) opaque; 826 uint16_t value = blizzard_reg_read(s, s->reg); 827 828 if (s->swallow -- > 0) 829 return 0; 830 if (dc) 831 s->reg ++; 832 833 return value; 834 } 835 836 void s1d13745_write(void *opaque, int dc, uint16_t value) 837 { 838 BlizzardState *s = (BlizzardState *) opaque; 839 840 if (s->swallow -- > 0) 841 return; 842 if (dc) { 843 blizzard_reg_write(s, s->reg, value); 844 845 if (s->reg != 0x90 && s->reg != 0x5a && s->reg != 0xb8) 846 s->reg += 2; 847 } else 848 s->reg = value & 0xff; 849 } 850 851 void s1d13745_write_block(void *opaque, int dc, 852 void *buf, size_t len, int pitch) 853 { 854 BlizzardState *s = (BlizzardState *) opaque; 855 856 while (len > 0) { 857 if (s->reg == 0x90 && dc && 858 (s->data.len || blizzard_transfer_setup(s)) && 859 len >= (s->data.len << 1)) { 860 len -= s->data.len << 1; 861 s->data.len = 0; 862 s->data.data = buf; 863 if (pitch) 864 s->data.pitch = pitch; 865 blizzard_window(s); 866 s->data.data = s->data.buf; 867 continue; 868 } 869 870 s1d13745_write(opaque, dc, *(uint16_t *) buf); 871 len -= 2; 872 buf += 2; 873 } 874 } 875 876 static void blizzard_update_display(void *opaque) 877 { 878 BlizzardState *s = (BlizzardState *) opaque; 879 DisplaySurface *surface = qemu_console_surface(s->con); 880 int y, bypp, bypl, bwidth; 881 uint8_t *src, *dst; 882 883 if (!s->enable) 884 return; 885 886 if (s->x != surface_width(surface) || s->y != surface_height(surface)) { 887 s->invalidate = 1; 888 qemu_console_resize(s->con, s->x, s->y); 889 surface = qemu_console_surface(s->con); 890 } 891 892 if (s->invalidate) { 893 s->invalidate = 0; 894 895 if (s->blank) { 896 bypp = surface_bytes_per_pixel(surface); 897 memset(surface_data(surface), 0, bypp * s->x * s->y); 898 return; 899 } 900 901 s->mx[0] = 0; 902 s->mx[1] = s->x; 903 s->my[0] = 0; 904 s->my[1] = s->y; 905 } 906 907 if (s->mx[1] <= s->mx[0]) 908 return; 909 910 bypp = surface_bytes_per_pixel(surface); 911 bypl = bypp * s->x; 912 bwidth = bypp * (s->mx[1] - s->mx[0]); 913 y = s->my[0]; 914 src = s->fb + bypl * y + bypp * s->mx[0]; 915 dst = surface_data(surface) + bypl * y + bypp * s->mx[0]; 916 for (; y < s->my[1]; y ++, src += bypl, dst += bypl) 917 memcpy(dst, src, bwidth); 918 919 dpy_gfx_update(s->con, s->mx[0], s->my[0], 920 s->mx[1] - s->mx[0], y - s->my[0]); 921 922 s->mx[0] = s->x; 923 s->mx[1] = 0; 924 s->my[0] = s->y; 925 s->my[1] = 0; 926 } 927 928 static void blizzard_draw_line16_32(uint32_t *dest, 929 const uint16_t *src, unsigned int width) 930 { 931 uint16_t data; 932 unsigned int r, g, b; 933 const uint16_t *end = (const void *) src + width; 934 while (src < end) { 935 data = *src ++; 936 b = (data & 0x1f) << 3; 937 data >>= 5; 938 g = (data & 0x3f) << 2; 939 data >>= 6; 940 r = (data & 0x1f) << 3; 941 data >>= 5; 942 *dest++ = rgb_to_pixel32(r, g, b); 943 } 944 } 945 946 static void blizzard_draw_line24mode1_32(uint32_t *dest, 947 const uint8_t *src, unsigned int width) 948 { 949 /* TODO: check if SDL 24-bit planes are not in the same format and 950 * if so, use memcpy */ 951 unsigned int r[2], g[2], b[2]; 952 const uint8_t *end = src + width; 953 while (src < end) { 954 g[0] = *src ++; 955 r[0] = *src ++; 956 r[1] = *src ++; 957 b[0] = *src ++; 958 *dest++ = rgb_to_pixel32(r[0], g[0], b[0]); 959 b[1] = *src ++; 960 g[1] = *src ++; 961 *dest++ = rgb_to_pixel32(r[1], g[1], b[1]); 962 } 963 } 964 965 static void blizzard_draw_line24mode2_32(uint32_t *dest, 966 const uint8_t *src, unsigned int width) 967 { 968 unsigned int r, g, b; 969 const uint8_t *end = src + width; 970 while (src < end) { 971 r = *src ++; 972 src ++; 973 b = *src ++; 974 g = *src ++; 975 *dest++ = rgb_to_pixel32(r, g, b); 976 } 977 } 978 979 /* No rotation */ 980 static blizzard_fn_t blizzard_draw_fn_32[0x10] = { 981 NULL, 982 /* RGB 5:6:5*/ 983 (blizzard_fn_t) blizzard_draw_line16_32, 984 /* RGB 6:6:6 mode 1 */ 985 (blizzard_fn_t) blizzard_draw_line24mode1_32, 986 /* RGB 8:8:8 mode 1 */ 987 (blizzard_fn_t) blizzard_draw_line24mode1_32, 988 NULL, NULL, 989 /* RGB 6:6:6 mode 2 */ 990 (blizzard_fn_t) blizzard_draw_line24mode2_32, 991 /* RGB 8:8:8 mode 2 */ 992 (blizzard_fn_t) blizzard_draw_line24mode2_32, 993 /* YUV 4:2:2 */ 994 NULL, 995 /* YUV 4:2:0 */ 996 NULL, 997 NULL, NULL, NULL, NULL, NULL, NULL, 998 }; 999 1000 /* 90deg, 180deg and 270deg rotation */ 1001 static blizzard_fn_t blizzard_draw_fn_r_32[0x10] = { 1002 /* TODO */ 1003 [0 ... 0xf] = NULL, 1004 }; 1005 1006 static const GraphicHwOps blizzard_ops = { 1007 .invalidate = blizzard_invalidate_display, 1008 .gfx_update = blizzard_update_display, 1009 }; 1010 1011 void *s1d13745_init(qemu_irq gpio_int) 1012 { 1013 BlizzardState *s = (BlizzardState *) g_malloc0(sizeof(*s)); 1014 DisplaySurface *surface; 1015 1016 s->fb = g_malloc(0x180000); 1017 1018 s->con = graphic_console_init(NULL, 0, &blizzard_ops, s); 1019 surface = qemu_console_surface(s->con); 1020 1021 assert(surface_bits_per_pixel(surface) == 32); 1022 1023 s->line_fn_tab[0] = blizzard_draw_fn_32; 1024 s->line_fn_tab[1] = blizzard_draw_fn_r_32; 1025 1026 blizzard_reset(s); 1027 1028 return s; 1029 } 1030