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