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