1 /*
2 * VIDIX driver for VIA CLE266/Unichrome chipsets.
3 *
4 * Copyright (C) 2004 Timothy Lee
5 * Thanks to Gilles Frattini for bugfixes
6 * Doxygen documentation by Benjamin Zores <ben@geexbox.org>
7 * h/w revision detection by Timothy Lee <timothy.lee@siriushk.com>
8 *
9 * This file is part of MPlayer.
10 *
11 * MPlayer is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * MPlayer is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License along
22 * with MPlayer; if not, write to the Free Software Foundation, Inc.,
23 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
24 */
25
26 #include <errno.h>
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <inttypes.h>
31 #include <unistd.h>
32
33 #include "config.h"
34 #include "vidix.h"
35 #include "fourcc.h"
36 #include "dha.h"
37 #include "pci_ids.h"
38 #include "pci_names.h"
39 #include "mp_msg.h"
40
41 #include "unichrome_regs.h"
42
43 /**
44 * @brief Information on PCI device.
45 */
46 static pciinfo_t pci_info;
47
48 /**
49 * @brief Unichrome driver colorkey settings.
50 */
51 static vidix_grkey_t uc_grkey;
52
53 static int frames[VID_PLAY_MAXFRAMES];
54 static uint8_t *vio;
55 static uint8_t *uc_mem;
56 static uint8_t mclk_save[3];
57 static uint8_t hwrev;
58
59 #define VIA_OUT(hwregs, reg, val) *(volatile uint32_t *)((hwregs) + (reg)) = (val)
60 #define VIA_IN(hwregs, reg) *(volatile uint32_t *)((hwregs) + (reg))
61 #define VGA_OUT8(hwregs, reg, val) *(volatile uint8_t *)((hwregs) + (reg) + 0x8000) = (val)
62 #define VGA_IN8(hwregs, reg) *(volatile uint8_t *)((hwregs) + (reg) + 0x8000)
63 #define VIDEO_OUT(hwregs, reg, val) VIA_OUT((hwregs)+0x200, reg, val)
64 #define VIDEO_IN(hwregs, reg) VIA_IN((hwregs)+0x200, reg)
65
66 #define outb(val,reg) OUTPORT8(reg,val)
67 #define inb(reg) INPORT8(reg)
68
69 #define ALIGN_TO(v, n) (((v) + (n-1)) & ~(n-1))
70 #define UC_MAP_V1_FIFO_CONTROL(depth, pre_thr, thr) \
71 (((depth)-1) | ((thr) << 8) | ((pre_thr) << 24))
72
73 #define VIDEOMEMORY_SIZE (8 * 1024 * 1024)
74 #define FRAMEBUFFER_SIZE 0x200000
75 #define FRAMEBUFFER_START (VIDEOMEMORY_SIZE - FRAMEBUFFER_SIZE)
76
77 #ifdef DEBUG_LOGFILE
78 static FILE *logfile = 0;
79 #define LOGWRITE(x) {if(logfile) fprintf(logfile,x);}
80 #else
81 #define LOGWRITE(x)
82 #endif
83
84 /**
85 * @brief Unichrome driver vidix capabilities.
86 */
87 static const vidix_capability_t uc_cap = {
88 "VIA CLE266 Unichrome driver",
89 "Timothy Lee <timothy@siriushk.com>",
90 TYPE_OUTPUT,
91 {0, 0, 0, 0},
92 4096,
93 4096,
94 4,
95 4,
96 -1,
97 FLAG_UPSCALER | FLAG_DOWNSCALER,
98 VENDOR_VIA2,
99 -1,
100 {0, 0, 0, 0}
101 };
102
103 /**
104 * @brief list of card IDs compliant with the Unichrome driver .
105 */
106 static unsigned short uc_card_ids[] = {
107 DEVICE_VIA2_VT8623_APOLLO_CLE266,
108 DEVICE_VIA2_VT8378_S3_UNICHROME
109 };
110
111 /**
112 * @brief Find chip index in Unichrome compliant devices list.
113 *
114 * @param chip_id PCI device ID.
115 *
116 * @returns index position in uc_card_ids if successful.
117 * -1 if chip_id is not a compliant chipset ID.
118 */
119 static int
find_chip(unsigned chip_id)120 find_chip (unsigned chip_id)
121 {
122 unsigned i;
123 for (i = 0; i < sizeof (uc_card_ids) / sizeof (unsigned short); i++)
124 {
125 if (chip_id == uc_card_ids[i])
126 return i;
127 }
128 return -1;
129 }
130
131 /**
132 * @brief Map hardware settings for vertical scaling.
133 *
134 * @param sh source height.
135 * @param dh destination height.
136 * @param zoom will hold vertical setting of zoom register.
137 * @param mini will hold vertical setting of mini register.
138 *
139 * @returns 1 if successful.
140 * 0 if the zooming factor is too large or small.
141 *
142 * @note Derived from VIA's V4L driver.
143 * See ddover.c, DDOVER_HQVCalcZoomHeight()
144 */
145 static int
uc_ovl_map_vzoom(uint32_t sh,uint32_t dh,uint32_t * zoom,uint32_t * mini)146 uc_ovl_map_vzoom (uint32_t sh, uint32_t dh, uint32_t * zoom, uint32_t * mini)
147 {
148 uint32_t sh1, tmp, d;
149 int zoom_ok = 1;
150
151 if (sh == dh) /* No zoom */
152 {
153 /* Do nothing */
154 }
155 else if (sh < dh) /* Zoom in */
156 {
157 tmp = (sh * 0x0400) / dh;
158 zoom_ok = !(tmp > 0x3ff);
159
160 *zoom |= (tmp & 0x3ff) | V1_Y_ZOOM_ENABLE;
161 *mini |= V1_Y_INTERPOLY | V1_YCBCR_INTERPOLY;
162 }
163 else /* sw > dh - Zoom out */
164 {
165 /* Find a suitable divider (1 << d) = {2, 4, 8 or 16} */
166 sh1 = sh;
167 for (d = 1; d < 5; d++)
168 {
169 sh1 >>= 1;
170 if (sh1 <= dh)
171 break;
172 }
173 if (d == 5) /* too small */
174 {
175 d = 4;
176 zoom_ok = 0;
177 }
178
179 *mini |= ((d << 1) - 1) << 16; /* <= {1,3,5,7} << 16 */
180
181 /* Add scaling */
182 if (sh1 < dh)
183 {
184 tmp = (sh1 * 0x400) / dh;
185 *zoom |= ((tmp & 0x3ff) | V1_Y_ZOOM_ENABLE);
186 *mini |= V1_Y_INTERPOLY | V1_YCBCR_INTERPOLY;
187 }
188 }
189
190 return zoom_ok;
191 }
192
193 /**
194 * @brief Map hardware settings for horizontal scaling.
195 *
196 * @param sw source width.
197 * @param dw destination width.
198 * @param zoom will hold horizontal setting of zoom register.
199 * @param mini will hold horizontal setting of mini register.
200 * @param falign will hold fetch aligment.
201 * @param dcount will hold display count.
202 *
203 * @returns 1 if successful.
204 * 0 if the zooming factor is too large or small.
205 *
206 * @note Derived from VIA's V4L driver.
207 * See ddover.c, DDOVER_HQVCalcZoomWidth() and DDOver_GetDisplayCount()
208 */
209 static int
uc_ovl_map_hzoom(uint32_t sw,uint32_t dw,uint32_t * zoom,uint32_t * mini,int * falign,int * dcount)210 uc_ovl_map_hzoom (uint32_t sw, uint32_t dw, uint32_t * zoom, uint32_t * mini,
211 int *falign, int *dcount)
212 {
213 uint32_t tmp, sw1, d;
214 int md; /* Minify-divider */
215 int zoom_ok = 1;
216
217 md = 1;
218 *falign = 0;
219
220 if (sw == dw) /* no zoom */
221 {
222 /* Do nothing */
223 }
224 else if (sw < dw) /* zoom in */
225 {
226 tmp = (sw * 0x0800) / dw;
227 zoom_ok = !(tmp > 0x7ff);
228
229 *zoom |= ((tmp & 0x7ff) << 16) | V1_X_ZOOM_ENABLE;
230 *mini |= V1_X_INTERPOLY;
231 }
232 else /* sw > dw - Zoom out */
233 {
234 /* Find a suitable divider (1 << d) = {2, 4, 8 or 16} */
235 sw1 = sw;
236 for (d = 1; d < 5; d++)
237 {
238 sw1 >>= 1;
239 if (sw1 <= dw)
240 break;
241 }
242 if (d == 5) /* too small */
243 {
244 d = 4;
245 zoom_ok = 0;
246 }
247
248 md = 1 << d; /* <= {2,4,8,16} */
249 *falign = ((md << 1) - 1) & 0xf; /* <= {3,7,15,15} */
250 *mini |= V1_X_INTERPOLY;
251 *mini |= ((d << 1) - 1) << 24; /* <= {1,3,5,7} << 24 */
252
253 /* Add scaling */
254 if (sw1 < dw)
255 {
256 /* CLE bug */
257 /* tmp = sw1*0x0800 / dw; */
258 tmp = (sw1 - 2) * 0x0800 / dw;
259 *zoom |= ((tmp & 0x7ff) << 16) | V1_X_ZOOM_ENABLE;
260 }
261 }
262
263 *dcount = sw - md;
264 return zoom_ok;
265 }
266
267 /**
268 * @brief qword fetch register setting.
269 *
270 * @param format overlay pixel format.
271 * @param sw source width.
272 *
273 * @return qword fetch register setting
274 *
275 * @note Derived from VIA's V4L driver. See ddover.c, DDOver_GetFetch()
276 * @note Only call after uc_ovl_map_hzoom()
277 */
278 static uint32_t
uc_ovl_map_qwfetch(uint32_t format,int sw)279 uc_ovl_map_qwfetch (uint32_t format, int sw)
280 {
281 uint32_t fetch = 0;
282
283 switch (format)
284 {
285 case IMGFMT_YV12:
286 case IMGFMT_I420:
287 fetch = ALIGN_TO (sw, 32) >> 4;
288 break;
289 case IMGFMT_UYVY:
290 case IMGFMT_YVYU:
291 case IMGFMT_YUY2:
292 fetch = (ALIGN_TO (sw << 1, 16) >> 4) + 1;
293 break;
294 case IMGFMT_BGR15:
295 case IMGFMT_BGR16:
296 fetch = (ALIGN_TO (sw << 1, 16) >> 4) + 1;
297 break;
298 case IMGFMT_BGR32:
299 fetch = (ALIGN_TO (sw << 2, 16) >> 4) + 1;
300 break;
301 default:
302 mp_msg(MSGT_VO, MSGL_STATUS, "[unichrome] Unexpected pixelformat!");
303 break;
304 }
305
306 if (fetch < 4)
307 fetch = 4;
308
309 return fetch;
310 }
311
312 /**
313 * @brief Map pixel format.
314 *
315 * @param format pixel format.
316 *
317 * @return the mapped pixel format.
318 *
319 * @note Derived from VIA's V4L driver. See ddover.c, DDOver_GetV1Format()
320 */
321 static uint32_t
uc_ovl_map_format(uint32_t format)322 uc_ovl_map_format (uint32_t format)
323 {
324 switch (format)
325 {
326 case IMGFMT_UYVY:
327 case IMGFMT_YVYU:
328 case IMGFMT_YUY2:
329 return V1_COLORSPACE_SIGN | V1_YUV422;
330 case IMGFMT_IYUV:
331 return V1_COLORSPACE_SIGN | V1_YCbCr420 | V1_SWAP_SW;
332 case IMGFMT_YV12:
333 case IMGFMT_I420:
334 return V1_COLORSPACE_SIGN | V1_YCbCr420;
335 case IMGFMT_BGR15:
336 return V1_RGB15;
337 case IMGFMT_BGR16:
338 return V1_RGB16;
339 case IMGFMT_BGR32:
340 return V1_RGB32;
341 default:
342 mp_msg(MSGT_VO, MSGL_STATUS, "[unichrome] Unexpected pixelformat!");
343 return V1_YUV422;
344 }
345 }
346
347 /**
348 * @brief Calculate V1 control and fifo-control register values.
349 *
350 * @param format pixel format.
351 * @param sw source width.
352 * @param hwrev CLE266 hardware revision.
353 * @param extfifo_on set this 1 if the extended FIFO is enabled.
354 * @param control will hold value for V1_CONTROL.
355 * @param fifo will hold value for V1_FIFO_CONTROL.
356 */
357 static void
uc_ovl_map_v1_control(uint32_t format,int sw,int hwrev,int extfifo_on,uint32_t * control,uint32_t * fifo)358 uc_ovl_map_v1_control (uint32_t format, int sw,
359 int hwrev, int extfifo_on,
360 uint32_t * control, uint32_t * fifo)
361 {
362 *control = V1_BOB_ENABLE | uc_ovl_map_format (format);
363
364 if (hwrev == 0x10)
365 {
366 *control |= V1_EXPIRE_NUM_F;
367 }
368 else
369 {
370 if (extfifo_on)
371 {
372 *control |= V1_EXPIRE_NUM_A | V1_FIFO_EXTENDED;
373 }
374 else
375 {
376 *control |= V1_EXPIRE_NUM;
377 }
378 }
379
380 if ((format == IMGFMT_YV12) || (format == IMGFMT_I420))
381 {
382 /* Minified video will be skewed without this workaround. */
383 if (sw <= 80) /* Fetch count <= 5 */
384 {
385 *fifo = UC_MAP_V1_FIFO_CONTROL (16, 0, 0);
386 }
387 else
388 {
389 if (hwrev == 0x10)
390 *fifo = UC_MAP_V1_FIFO_CONTROL (64, 56, 56);
391 else
392 *fifo = UC_MAP_V1_FIFO_CONTROL (16, 12, 8);
393 }
394 }
395 else
396 {
397 if (hwrev == 0x10)
398 {
399 *fifo = UC_MAP_V1_FIFO_CONTROL (64, 56, 56); /* Default rev 0x10 */
400 }
401 else
402 {
403 if (extfifo_on)
404 *fifo = UC_MAP_V1_FIFO_CONTROL (48, 40, 40);
405 else
406 *fifo = UC_MAP_V1_FIFO_CONTROL (32, 29, 16); /* Default */
407 }
408 }
409 }
410
411 /**
412 * @brief Setup extended FIFO.
413 *
414 * @param extfifo_on pointer determining if extended fifo is enable or not.
415 * @param dst_w destination width.
416 */
417 static void
uc_ovl_setup_fifo(int * extfifo_on,int dst_w)418 uc_ovl_setup_fifo (int *extfifo_on, int dst_w)
419 {
420 if (dst_w <= 1024) /* Disable extended FIFO */
421 {
422 outb (0x16, 0x3c4);
423 outb (mclk_save[0], 0x3c5);
424 outb (0x17, 0x3c4);
425 outb (mclk_save[1], 0x3c5);
426 outb (0x18, 0x3c4);
427 outb (mclk_save[2], 0x3c5);
428 *extfifo_on = 0;
429 }
430 else /* Enable extended FIFO */
431 {
432 outb (0x17, 0x3c4);
433 outb (0x2f, 0x3c5);
434 outb (0x16, 0x3c4);
435 outb ((mclk_save[0] & 0xf0) | 0x14, 0x3c5);
436 outb (0x18, 0x3c4);
437 outb (0x56, 0x3c5);
438 *extfifo_on = 1;
439 }
440 }
441
442 static void
uc_ovl_vcmd_wait(volatile uint8_t * vio)443 uc_ovl_vcmd_wait (volatile uint8_t * vio)
444 {
445 while ((VIDEO_IN (vio, V_COMPOSE_MODE)
446 & (V1_COMMAND_FIRE | V3_COMMAND_FIRE)));
447 }
448
449 /**
450 * @brief Probe hardware to find some useable chipset.
451 *
452 * @param verbose specifies verbose level.
453 * @param force specifies force mode : driver should ignore
454 * device_id (danger but useful for new devices)
455 *
456 * @returns 0 if it can handle something in PC.
457 * a negative error code otherwise.
458 */
459 static int
unichrome_probe(int verbose,int force)460 unichrome_probe (int verbose, int force)
461 {
462 pciinfo_t lst[MAX_PCI_DEVICES];
463 unsigned i, num_pci;
464 int err;
465 err = pci_scan (lst, &num_pci);
466 if (err)
467 {
468 mp_msg(MSGT_VO, MSGL_STATUS, "[unichrome] Error occurred during pci scan: %s\n",
469 strerror (err));
470 return err;
471 }
472 else
473 {
474 err = ENXIO;
475 for (i = 0; i < num_pci; i++)
476 {
477 if (lst[i].vendor == VENDOR_VIA2)
478 {
479 int idx;
480 const char *dname;
481 idx = find_chip (lst[i].device);
482 if (idx == -1)
483 continue;
484 dname = pci_device_name (VENDOR_VIA2, lst[i].device);
485 dname = dname ? dname : "Unknown chip";
486 mp_msg(MSGT_VO, MSGL_STATUS, "[unichrome] Found chip: %s\n", dname);
487 if ((lst[i].command & PCI_COMMAND_IO) == 0)
488 {
489 mp_msg(MSGT_VO, MSGL_STATUS, "[unichrome] Device is disabled, ignoring\n");
490 continue;
491 }
492 err = 0;
493 memcpy (&pci_info, &lst[i], sizeof (pciinfo_t));
494 break;
495 }
496 }
497 }
498
499 if (err && verbose)
500 mp_msg(MSGT_VO, MSGL_STATUS, "[unichrome] Can't find chip\n");
501 return err;
502 }
503
504 /**
505 * @brief Initializes driver.
506 *
507 * @returns 0 if ok.
508 * a negative error code otherwise.
509 */
510 static int
unichrome_init(void)511 unichrome_init (void)
512 {
513 long tmp;
514 uc_mem = map_phys_mem (pci_info.base0, VIDEOMEMORY_SIZE);
515 enable_app_io ();
516
517 outb (0x2f, 0x3c4);
518 tmp = (unsigned)(inb (0x3c5)) << 0x18;
519 vio = map_phys_mem (tmp, 0x1000);
520
521 outb (0x16, 0x3c4);
522 mclk_save[0] = inb (0x3c5);
523 outb (0x17, 0x3c4);
524 mclk_save[1] = inb (0x3c5);
525 outb (0x18, 0x3c4);
526 mclk_save[2] = inb (0x3c5);
527
528 uc_grkey.ckey.blue = 0x00;
529 uc_grkey.ckey.green = 0x00;
530 uc_grkey.ckey.red = 0x00;
531
532 /* Detect whether we have a CLE266Ax or CLE266Cx */
533 outb (0x4f, 0x3d4);
534 tmp = inb (0x3d5);
535 outb (0x4f, 0x3d4);
536 outb (0x55, 0x3d5);
537 outb (0x4f, 0x3d4);
538 if (0x55 == inb (0x3d5))
539 {
540 /* Only CLE266Cx supports CR4F */
541 hwrev = 0x11;
542 }
543 else
544 {
545 /* Otherwise assume to be a CLE266Ax */
546 hwrev = 0x00;
547 }
548 outb (0x4f, 0x3d4);
549 outb (tmp, 0x3d5);
550
551 #ifdef DEBUG_LOGFILE
552 logfile = fopen ("/tmp/uc_vidix.log", "w");
553 #endif
554 return 0;
555 }
556
557 /**
558 * @brief Destroys driver.
559 */
560 static void
unichrome_destroy(void)561 unichrome_destroy (void)
562 {
563 #ifdef DEBUG_LOGFILE
564 if (logfile)
565 fclose (logfile);
566 #endif
567 outb (0x16, 0x3c4);
568 outb (mclk_save[0], 0x3c5);
569 outb (0x17, 0x3c4);
570 outb (mclk_save[1], 0x3c5);
571 outb (0x18, 0x3c4);
572 outb (mclk_save[2], 0x3c5);
573
574 disable_app_io ();
575 unmap_phys_mem (uc_mem, VIDEOMEMORY_SIZE);
576 unmap_phys_mem (vio, 0x1000);
577 }
578
579 /**
580 * @brief Get chipset's hardware capabilities.
581 *
582 * @param to Pointer to the vidix_capability_t structure to be filled.
583 *
584 * @returns 0.
585 */
586 static int
unichrome_get_caps(vidix_capability_t * to)587 unichrome_get_caps (vidix_capability_t * to)
588 {
589 memcpy (to, &uc_cap, sizeof (vidix_capability_t));
590 to->device_id = pci_info.device;
591 return 0;
592 }
593
594 /**
595 * @brief Report if the video FourCC is supported by hardware.
596 *
597 * @param fourcc input image format.
598 *
599 * @returns 1 if the fourcc is supported.
600 * 0 otherwise.
601 */
602 static int
is_supported_fourcc(uint32_t fourcc)603 is_supported_fourcc (uint32_t fourcc)
604 {
605 switch (fourcc)
606 {
607 case IMGFMT_YV12:
608 case IMGFMT_I420:
609 case IMGFMT_UYVY:
610 case IMGFMT_YVYU:
611 case IMGFMT_YUY2:
612 case IMGFMT_BGR15:
613 case IMGFMT_BGR16:
614 case IMGFMT_BGR32:
615 return 1;
616 default:
617 return 0;
618 }
619 }
620
621 /**
622 * @brief Try to configure video memory for given fourcc.
623 *
624 * @param to Pointer to the vidix_fourcc_t structure to be filled.
625 *
626 * @returns 0 if ok.
627 * errno otherwise.
628 */
629 static int
unichrome_query_fourcc(vidix_fourcc_t * to)630 unichrome_query_fourcc (vidix_fourcc_t * to)
631 {
632 if (is_supported_fourcc (to->fourcc))
633 {
634 to->depth = VID_DEPTH_ALL;
635 to->flags = VID_CAP_EXPAND | VID_CAP_SHRINK | VID_CAP_COLORKEY;
636 return 0;
637 }
638 return ENOSYS;
639 }
640
641 /**
642 * @brief Get the GrKeys
643 *
644 * @param grkey Pointer to the vidix_grkey_t structure to be filled by driver.
645 *
646 * @return 0.
647 */
648 static int
unichrome_get_gkey(vidix_grkey_t * grkey)649 unichrome_get_gkey (vidix_grkey_t * grkey)
650 {
651 memcpy (grkey, &uc_grkey, sizeof (vidix_grkey_t));
652 return 0;
653 }
654
655 /**
656 * @brief Set the GrKeys
657 *
658 * @param grkey Colorkey to be set.
659 *
660 * @return 0.
661 */
662 static int
unichrome_set_gkey(const vidix_grkey_t * grkey)663 unichrome_set_gkey (const vidix_grkey_t * grkey)
664 {
665 unsigned long dwCompose = VIDEO_IN (vio, V_COMPOSE_MODE) & ~0x0f;
666 memcpy (&uc_grkey, grkey, sizeof (vidix_grkey_t));
667 if (uc_grkey.ckey.op != CKEY_FALSE)
668 {
669 /* Set colorkey (how do I detect BPP in hardware ??) */
670 unsigned long ckey;
671 if (1) /* Assume 16-bit graphics */
672 {
673 ckey = (grkey->ckey.blue & 0x1f)
674 | ((grkey->ckey.green & 0x3f) << 5)
675 | ((grkey->ckey.red & 0x1f) << 11);
676 }
677 else
678 {
679 ckey = (grkey->ckey.blue)
680 | (grkey->ckey.green << 8) | (grkey->ckey.red << 16);
681 }
682 VIDEO_OUT (vio, V_COLOR_KEY, ckey);
683 dwCompose |= SELECT_VIDEO_IF_COLOR_KEY;
684 }
685
686 /* Execute the changes */
687 VIDEO_OUT (vio, V_COMPOSE_MODE, dwCompose | V1_COMMAND_FIRE);
688 return 0;
689 }
690
691 /**
692 * @brief Unichrome driver equalizer capabilities.
693 */
694 static vidix_video_eq_t equal = {
695 VEQ_CAP_BRIGHTNESS | VEQ_CAP_SATURATION | VEQ_CAP_HUE,
696 300, 100, 0, 0, 0, 0, 0, 0
697 };
698
699
700 /**
701 * @brief Get the equalizer capabilities.
702 *
703 * @param eq Pointer to the vidix_video_eq_t structure to be filled by driver.
704 *
705 * @return 0.
706 */
707 static int
unichrome_get_eq(vidix_video_eq_t * eq)708 unichrome_get_eq (vidix_video_eq_t * eq)
709 {
710 memcpy (eq, &equal, sizeof (vidix_video_eq_t));
711 return 0;
712 }
713
714 /**
715 * @brief Set the equalizer capabilities for color correction
716 *
717 * @param eq equalizer capabilities to be set.
718 *
719 * @return 0.
720 */
721 static int
unichrome_set_eq(const vidix_video_eq_t * eq)722 unichrome_set_eq (const vidix_video_eq_t * eq)
723 {
724 return 0;
725 }
726
727 /**
728 * @brief Y, U, V offsets.
729 */
730 static int YOffs, UOffs, VOffs;
731
732 static int unichrome_frame_select (unsigned int frame);
733
734 /**
735 * @brief Configure driver for playback. Driver should prepare BES.
736 *
737 * @param info configuration description for playback.
738 *
739 * @returns 0 in case of success.
740 * -1 otherwise.
741 */
742 static int
unichrome_config_playback(vidix_playback_t * info)743 unichrome_config_playback (vidix_playback_t * info)
744 {
745 int src_w, drw_w;
746 int src_h, drw_h;
747 long base0, pitch = 0;
748 int uv_size = 0, swap_uv;
749 unsigned int i;
750 int extfifo_on;
751
752 /* Overlay register settings */
753 uint32_t win_start, win_end;
754 uint32_t zoom, mini;
755 uint32_t dcount, falign, qwfetch;
756 uint32_t v_ctrl, fifo_ctrl;
757
758 if (!is_supported_fourcc (info->fourcc))
759 return -1;
760
761 src_w = info->src.w;
762 src_h = info->src.h;
763
764 drw_w = info->dest.w;
765 drw_h = info->dest.h;
766
767 /* Setup FIFO */
768 uc_ovl_setup_fifo (&extfifo_on, src_w);
769
770 /* Get image format, FIFO size, etc. */
771 uc_ovl_map_v1_control (info->fourcc, src_w, hwrev, extfifo_on,
772 &v_ctrl, &fifo_ctrl);
773
774 /* Setup layer window */
775 win_start = (info->dest.x << 16) | info->dest.y;
776 win_end = ((info->dest.x + drw_w - 1) << 16) | (info->dest.y + drw_h - 1);
777
778 /* Get scaling and data-fetch parameters */
779 zoom = 0;
780 mini = 0;
781 uc_ovl_map_vzoom (src_h, drw_h, &zoom, &mini);
782 uc_ovl_map_hzoom (src_w, drw_w, &zoom, &mini, (int *) &falign, (int *) &dcount);
783 qwfetch = uc_ovl_map_qwfetch (info->fourcc, src_w);
784
785 /* Calculate buffer sizes */
786 swap_uv = 0;
787 switch (info->fourcc)
788 {
789 case IMGFMT_YV12:
790 swap_uv = 1;
791 /* Fallthrough, same as the following otherwise */
792 case IMGFMT_I420:
793 case IMGFMT_UYVY:
794 case IMGFMT_YVYU:
795 pitch = ALIGN_TO (src_w, 32);
796 uv_size = (pitch >> 1) * (src_h >> 1);
797 break;
798
799 case IMGFMT_YUY2:
800 case IMGFMT_BGR15:
801 case IMGFMT_BGR16:
802 pitch = ALIGN_TO (src_w << 1, 32);
803 uv_size = 0;
804 break;
805
806 case IMGFMT_BGR32:
807 pitch = ALIGN_TO (src_w << 2, 32);
808 uv_size = 0;
809 break;
810
811 default: // should have been caught by is_supported_fourcc above
812 return -1;
813 }
814 if ((src_w > 4096) || (src_h > 4096) ||
815 (src_w < 32) || (src_h < 1) || (pitch > 0x1fff))
816 {
817 mp_msg(MSGT_VO, MSGL_STATUS, "[unichrome] Layer size out of bounds\n");
818 }
819
820 /* Calculate offsets */
821 info->offset.y = 0;
822 info->offset.v = info->offset.y + pitch * src_h;
823 info->offset.u = info->offset.v + uv_size;
824 info->frame_size = info->offset.u + uv_size;
825 YOffs = info->offset.y;
826 UOffs = (swap_uv ? info->offset.v : info->offset.u);
827 VOffs = (swap_uv ? info->offset.u : info->offset.v);
828
829 /* Assume we have 2 MB to play with */
830 info->num_frames = FRAMEBUFFER_SIZE / info->frame_size;
831 if (info->num_frames > VID_PLAY_MAXFRAMES)
832 info->num_frames = VID_PLAY_MAXFRAMES;
833
834 /* Start at 6 MB. Let's hope it's not in use. */
835 base0 = FRAMEBUFFER_START;
836 info->dga_addr = uc_mem + base0;
837
838 info->dest.pitch.y = 32;
839 info->dest.pitch.u = 32;
840 info->dest.pitch.v = 32;
841
842 for (i = 0; i < info->num_frames; i++)
843 {
844 info->offsets[i] = info->frame_size * i;
845 frames[i] = base0 + info->offsets[i];
846 }
847
848 /* Write to the hardware */
849 uc_ovl_vcmd_wait (vio);
850
851 /* Configure diy_pitchlay parameters now */
852 if (v_ctrl & V1_COLORSPACE_SIGN)
853 {
854 if (hwrev >= 0x10)
855 {
856 VIDEO_OUT (vio, V1_ColorSpaceReg_2, ColorSpaceValue_2_3123C0);
857 VIDEO_OUT (vio, V1_ColorSpaceReg_1, ColorSpaceValue_1_3123C0);
858 }
859 else
860 {
861 VIDEO_OUT (vio, V1_ColorSpaceReg_2, ColorSpaceValue_2);
862 VIDEO_OUT (vio, V1_ColorSpaceReg_1, ColorSpaceValue_1);
863 }
864 }
865
866 VIDEO_OUT (vio, V1_CONTROL, v_ctrl);
867 VIDEO_OUT (vio, V_FIFO_CONTROL, fifo_ctrl);
868
869 VIDEO_OUT (vio, V1_WIN_START_Y, win_start);
870 VIDEO_OUT (vio, V1_WIN_END_Y, win_end);
871
872 VIDEO_OUT (vio, V1_SOURCE_HEIGHT, (src_h << 16) | dcount);
873
874 VIDEO_OUT (vio, V12_QWORD_PER_LINE, qwfetch << 20);
875 VIDEO_OUT (vio, V1_STRIDE, pitch | ((pitch >> 1) << 16));
876
877 VIDEO_OUT (vio, V1_MINI_CONTROL, mini);
878 VIDEO_OUT (vio, V1_ZOOM_CONTROL, zoom);
879
880 /* Configure buffer address and execute the changes now! */
881 unichrome_frame_select (0);
882
883 return 0;
884 }
885
886 /**
887 * @brief Set playback on : driver should activate BES on this call.
888 *
889 * @return 0.
890 */
891 static int
unichrome_playback_on(void)892 unichrome_playback_on (void)
893 {
894 LOGWRITE ("Enable overlay\n");
895
896 /* Turn on overlay */
897 VIDEO_OUT (vio, V1_CONTROL, VIDEO_IN (vio, V1_CONTROL) | V1_ENABLE);
898
899 /* Execute the changes */
900 VIDEO_OUT (vio, V_COMPOSE_MODE,
901 VIDEO_IN (vio, V_COMPOSE_MODE) | V1_COMMAND_FIRE);
902
903 return 0;
904 }
905
906 /**
907 * @brief Set playback off : driver should deactivate BES on this call.
908 *
909 * @return 0.
910 */
911 static int
unichrome_playback_off(void)912 unichrome_playback_off (void)
913 {
914 LOGWRITE ("Disable overlay\n");
915
916 uc_ovl_vcmd_wait (vio);
917
918 /* Restore FIFO */
919 VIDEO_OUT (vio, V_FIFO_CONTROL, UC_MAP_V1_FIFO_CONTROL (16, 12, 8));
920
921 /* Turn off overlay */
922 VIDEO_OUT (vio, V1_CONTROL, VIDEO_IN (vio, V1_CONTROL) & ~V1_ENABLE);
923
924 /* Execute the changes */
925 VIDEO_OUT (vio, V_COMPOSE_MODE,
926 VIDEO_IN (vio, V_COMPOSE_MODE) | V1_COMMAND_FIRE);
927
928 return 0;
929 }
930
931 /**
932 * @brief Driver should prepare and activate corresponded frame.
933 *
934 * @param frame the frame index.
935 *
936 * @return 0.
937 *
938 * @note This function is used only for double and triple buffering
939 * and never used for single buffering playback.
940 */
941 static int
unichrome_frame_select(unsigned int frame)942 unichrome_frame_select (unsigned int frame)
943 {
944 LOGWRITE ("Frame select\n");
945
946 uc_ovl_vcmd_wait (vio);
947
948 /* Configure buffer address */
949 VIDEO_OUT (vio, V1_STARTADDR_Y0, frames[frame] + YOffs);
950 VIDEO_OUT (vio, V1_STARTADDR_CB0, frames[frame] + UOffs);
951 VIDEO_OUT (vio, V1_STARTADDR_CR0, frames[frame] + VOffs);
952
953 /* Execute the changes */
954 VIDEO_OUT (vio, V_COMPOSE_MODE,
955 VIDEO_IN (vio, V_COMPOSE_MODE) | V1_COMMAND_FIRE);
956
957 return 0;
958 }
959
960 const VDXDriver unichrome_drv = {
961 "unichrome",
962 NULL,
963 .probe = unichrome_probe,
964 .get_caps = unichrome_get_caps,
965 .query_fourcc = unichrome_query_fourcc,
966 .init = unichrome_init,
967 .destroy = unichrome_destroy,
968 .config_playback = unichrome_config_playback,
969 .playback_on = unichrome_playback_on,
970 .playback_off = unichrome_playback_off,
971 .frame_sel = unichrome_frame_select,
972 .get_eq = unichrome_get_eq,
973 .set_eq = unichrome_set_eq,
974 .get_gkey = unichrome_get_gkey,
975 .set_gkey = unichrome_set_gkey,
976 };
977