Statistics
| Branch: | Revision:

root / hw / blizzard.c @ bc24a225

History | View | Annotate | Download (28.5 kB)

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, 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
typedef struct {
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
} BlizzardState;
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(BlizzardState *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(BlizzardState *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(BlizzardState *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
    BlizzardState *s = (BlizzardState *) opaque;
284

    
285
    s->invalidate = 1;
286
}
287

    
288
static uint16_t blizzard_reg_read(void *opaque, uint8_t reg)
289
{
290
    BlizzardState *s = (BlizzardState *) 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
    BlizzardState *s = (BlizzardState *) 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
    BlizzardState *s = (BlizzardState *) 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
    BlizzardState *s = (BlizzardState *) 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
    BlizzardState *s = (BlizzardState *) 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
    BlizzardState *s = (BlizzardState *) 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
    BlizzardState *s = (BlizzardState *) 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
    BlizzardState *s = (BlizzardState *) 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
}