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