2 * VIDIX driver for ATI Mach64 and 3DRage chipsets.
4 * Copyright (C) 2002 Nick Kurshev
5 * This file is based on sources from
6 * GATOS (gatos.sf.net) and X11 (www.xfree86.org)
8 * This file is part of MPlayer.
10 * MPlayer is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
15 * MPlayer is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License along
21 * with MPlayer; if not, write to the Free Software Foundation, Inc.,
22 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
34 #include "libavutil/common.h"
40 #include "pci_names.h"
44 #define UNUSED(x) ((void)(x)) /**< Removes warning about unused arguments */
46 static void *mach64_mmio_base
= 0;
47 static void *mach64_mem_base
= 0;
48 static int32_t mach64_overlay_offset
= 0;
49 static uint32_t mach64_ram_size
= 0;
50 static uint32_t mach64_buffer_base
[10][3];
51 static int num_mach64_buffers
=-1;
52 static int supports_planar
=0;
53 static int supports_lcd_v_stretch
=0;
55 static pciinfo_t pci_info
;
56 static int probed
= 0;
57 static int verbosity
= 0;
59 #define VERBOSE_LEVEL 1
61 typedef struct bes_registers_s
63 /* base address of yuv framebuffer */
66 /* YUV BES registers */
67 uint32_t reg_load_cntl
;
71 uint32_t vid_buf_pitch
;
72 uint32_t height_width
;
75 uint32_t exclusive_horz
;
76 uint32_t auto_flip_cntl
;
80 /* Configurable stuff */
86 uint32_t graphics_key_clr
;
87 uint32_t graphics_key_msk
;
90 uint32_t deinterlace_pattern
;
94 static bes_registers_t besr
;
96 typedef struct video_registers_s
104 static vidix_grkey_t mach64_grkey
;
106 #define DECLARE_VREG(name) { #name, name, 0 }
107 static video_registers_t vregs
[] =
109 DECLARE_VREG(OVERLAY_SCALE_INC
),
110 DECLARE_VREG(OVERLAY_Y_X_START
),
111 DECLARE_VREG(OVERLAY_Y_X_END
),
112 DECLARE_VREG(OVERLAY_SCALE_CNTL
),
113 DECLARE_VREG(OVERLAY_EXCLUSIVE_HORZ
),
114 DECLARE_VREG(OVERLAY_EXCLUSIVE_VERT
),
115 DECLARE_VREG(OVERLAY_TEST
),
116 DECLARE_VREG(SCALER_BUF_PITCH
),
117 DECLARE_VREG(SCALER_HEIGHT_WIDTH
),
118 DECLARE_VREG(SCALER_BUF0_OFFSET
),
119 DECLARE_VREG(SCALER_BUF0_OFFSET_U
),
120 DECLARE_VREG(SCALER_BUF0_OFFSET_V
),
121 DECLARE_VREG(SCALER_BUF1_OFFSET
),
122 DECLARE_VREG(SCALER_BUF1_OFFSET_U
),
123 DECLARE_VREG(SCALER_BUF1_OFFSET_V
),
124 DECLARE_VREG(SCALER_H_COEFF0
),
125 DECLARE_VREG(SCALER_H_COEFF1
),
126 DECLARE_VREG(SCALER_H_COEFF2
),
127 DECLARE_VREG(SCALER_H_COEFF3
),
128 DECLARE_VREG(SCALER_H_COEFF4
),
129 DECLARE_VREG(SCALER_COLOUR_CNTL
),
130 DECLARE_VREG(SCALER_THRESHOLD
),
131 DECLARE_VREG(VIDEO_FORMAT
),
132 DECLARE_VREG(VIDEO_CONFIG
),
133 DECLARE_VREG(VIDEO_SYNC_TEST
),
134 DECLARE_VREG(VIDEO_SYNC_TEST_B
)
137 /* have to restore it on exit */
138 static uint32_t SAVED_OVERLAY_GRAPHICS_KEY_CLR
;
143 #define GETREG(TYPE,PTR,OFFZ) (*((volatile TYPE*)((PTR)+(OFFZ))))
144 #define SETREG(TYPE,PTR,OFFZ,VAL) (*((volatile TYPE*)((PTR)+(OFFZ))))=VAL
146 #define INREG8(addr) GETREG(uint8_t,(uint8_t *)mach64_mmio_base,((addr)^0x100)<<2)
147 #define OUTREG8(addr,val) SETREG(uint8_t,(uint8_t *)mach64_mmio_base,((addr)^0x100)<<2,val)
149 static inline uint32_t INREG (uint32_t addr
) {
150 uint32_t tmp
= GETREG(uint32_t,(uint8_t *)mach64_mmio_base
,((addr
)^0x100)<<2);
151 return le2me_32(tmp
);
153 #define OUTREG(addr,val) SETREG(uint32_t,(uint8_t *)mach64_mmio_base,((addr)^0x100)<<2,le2me_32(val))
155 #define OUTREGP(addr,val,mask) \
157 unsigned int _tmp = INREG(addr); \
160 OUTREG(addr, _tmp); \
163 static __inline__
int ATIGetMach64LCDReg(int _Index
)
165 OUTREG8(LCD_INDEX
, _Index
);
166 return INREG(LCD_DATA
);
169 static __inline__
uint32_t INPLL(uint32_t addr
)
174 in
= INREG(CLOCK_CNTL
);
175 in
&= ~((PLL_WR_EN
| PLL_ADDR
)); //clean some stuff
176 OUTREG(CLOCK_CNTL
, in
| (addr
<<10));
178 /* read the register value */
179 res
= (INREG(CLOCK_CNTL
)>>16)&0xFF;
183 static __inline__
void OUTPLL(uint32_t addr
,uint32_t val
)
185 //FIXME buggy but its not used
186 /* write addr byte */
187 OUTREG8(CLOCK_CNTL
+ 1, (addr
<< 2) | PLL_WR_EN
);
188 /* write the register value */
189 OUTREG(CLOCK_CNTL
+ 2, val
);
190 OUTREG8(CLOCK_CNTL
+ 1, (addr
<< 2) & ~PLL_WR_EN
);
193 #define OUTPLLP(addr,val,mask) \
195 unsigned int _tmp = INPLL(addr); \
198 OUTPLL(addr, _tmp); \
201 static void mach64_fifo_wait(unsigned n
)
203 while ((INREG(FIFO_STAT
) & 0xffff) > ((uint32_t)(0x8000 >> n
)));
206 static void mach64_wait_for_idle( void )
208 mach64_fifo_wait(16);
209 while ((INREG(GUI_STAT
) & 1)!= 0);
212 static void mach64_wait_vsync( void )
216 for(i
=0; i
<2000000; i
++)
217 if( (INREG(CRTC_INT_CNTL
)&CRTC_VBLANK
)==0 ) break;
218 for(i
=0; i
<2000000; i
++)
219 if( (INREG(CRTC_INT_CNTL
)&CRTC_VBLANK
) ) break;
223 static vidix_capability_t mach64_cap
=
225 "BES driver for Mach64/3DRage cards",
226 "Nick Kurshev and Michael Niedermayer",
234 FLAG_UPSCALER
|FLAG_DOWNSCALER
,
240 static uint32_t mach64_vid_get_dbpp( void )
242 uint32_t dbpp
,retval
;
243 dbpp
= (INREG(CRTC_GEN_CNTL
)>>8)& 0x7;
246 case 1: retval
= 4; break;
247 case 2: retval
= 8; break;
248 case 3: retval
= 15; break;
249 case 4: retval
= 16; break;
250 case 5: retval
= 24; break;
251 default: retval
=32; break;
256 static int mach64_is_dbl_scan( void )
258 return INREG(CRTC_GEN_CNTL
) & CRTC_DBL_SCAN_EN
;
261 static int mach64_is_interlace( void )
263 return INREG(CRTC_GEN_CNTL
) & CRTC_INTERLACE_EN
;
266 static uint32_t mach64_get_xres( void )
268 /* FIXME: currently we extract that from CRTC!!!*/
269 uint32_t xres
,h_total
;
270 h_total
= INREG(CRTC_H_TOTAL_DISP
);
271 xres
= (h_total
>> 16) & 0xffff;
275 static uint32_t mach64_get_yres( void )
277 /* FIXME: currently we extract that from CRTC!!!*/
278 uint32_t yres
,v_total
;
279 v_total
= INREG(CRTC_V_TOTAL_DISP
);
280 yres
= (v_total
>> 16) & 0xffff;
284 // returns the verical stretch factor in 16.16
285 static int mach64_get_vert_stretch(void)
289 int ext_vert_stretch
;
291 int yres
= mach64_get_yres();
293 if(!supports_lcd_v_stretch
){
294 if(verbosity
> 0) printf("[mach64] vertical stretching not supported\n");
298 lcd_index
= INREG(LCD_INDEX
);
300 vert_stretching
= ATIGetMach64LCDReg(LCD_VERT_STRETCHING
);
301 if(!(vert_stretching
&VERT_STRETCH_EN
)) ret
= 1<<16;
306 ext_vert_stretch
= ATIGetMach64LCDReg(LCD_EXT_VERT_STRETCH
);
307 panel_size
= (ext_vert_stretch
&VERT_PANEL_SIZE
)>>11;
310 ret
= ((yres
<<16) + (panel_size
>>1))/panel_size
;
313 // lcd_gen_ctrl = ATIGetMach64LCDReg(LCD_GEN_CNTL);
315 OUTREG(LCD_INDEX
, lcd_index
);
317 if(verbosity
> 0) printf("[mach64] vertical stretching factor= %d\n", ret
);
322 static void mach64_vid_make_default(void)
325 OUTREG(SCALER_COLOUR_CNTL
,0x00101000);
328 besr
.graphics_key_msk
=0;
329 besr
.graphics_key_clr
=0;
331 OUTREG(OVERLAY_GRAPHICS_KEY_MSK
, besr
.graphics_key_msk
);
332 OUTREG(OVERLAY_GRAPHICS_KEY_CLR
, besr
.graphics_key_clr
);
333 OUTREG(OVERLAY_KEY_CNTL
,VIDEO_KEY_FN_TRUE
|GRAPHIC_KEY_FN_EQ
|CMP_MIX_AND
);
337 static void mach64_vid_dump_regs( void )
340 printf("[mach64] *** Begin of DRIVER variables dump ***\n");
341 printf("[mach64] mach64_mmio_base=%p\n",mach64_mmio_base
);
342 printf("[mach64] mach64_mem_base=%p\n",mach64_mem_base
);
343 printf("[mach64] mach64_overlay_off=%08X\n",mach64_overlay_offset
);
344 printf("[mach64] mach64_ram_size=%08X\n",mach64_ram_size
);
345 printf("[mach64] video mode: %ux%u@%u\n",mach64_get_xres(),mach64_get_yres(),mach64_vid_get_dbpp());
346 printf("[mach64] *** Begin of OV0 registers dump ***\n");
347 for(i
=0;i
<sizeof(vregs
)/sizeof(video_registers_t
);i
++)
349 mach64_wait_for_idle();
350 printf("[mach64] %s = %08X\n",vregs
[i
].sname
,INREG(vregs
[i
].name
));
352 printf("[mach64] *** End of OV0 registers dump ***\n");
356 static unsigned short ati_card_ids
[] =
358 DEVICE_ATI_215CT_MACH64_CT
,
359 DEVICE_ATI_210888CX_MACH64_CX
,
360 DEVICE_ATI_210888ET_MACH64_ET
,
361 DEVICE_ATI_MACH64_VT
,
362 DEVICE_ATI_210888GX_MACH64_GX
,
363 DEVICE_ATI_264LT_MACH64_LT
,
364 DEVICE_ATI_264VT_MACH64_VT
,
365 DEVICE_ATI_264VT3_MACH64_VT3
,
366 DEVICE_ATI_264VT4_MACH64_VT4
,
368 DEVICE_ATI_3D_RAGE_PRO
,
369 DEVICE_ATI_3D_RAGE_PRO2
,
370 DEVICE_ATI_3D_RAGE_PRO3
,
371 DEVICE_ATI_3D_RAGE_PRO4
,
373 DEVICE_ATI_RAGE_XL_AGP
,
374 DEVICE_ATI_RAGE_XC_AGP
,
376 DEVICE_ATI_3D_RAGE_PRO5
,
377 DEVICE_ATI_3D_RAGE_PRO6
,
380 DEVICE_ATI_3D_RAGE_I_II
,
381 DEVICE_ATI_3D_RAGE_II
,
382 DEVICE_ATI_3D_RAGE_IIC
,
383 DEVICE_ATI_3D_RAGE_IIC2
,
384 DEVICE_ATI_3D_RAGE_IIC3
,
385 DEVICE_ATI_3D_RAGE_IIC4
,
386 DEVICE_ATI_3D_RAGE_LT
,
387 DEVICE_ATI_3D_RAGE_LT2
,
388 DEVICE_ATI_3D_RAGE_LT_G
,
389 DEVICE_ATI_3D_RAGE_LT3
,
390 DEVICE_ATI_RAGE_MOBILITY_P_M
,
391 DEVICE_ATI_RAGE_MOBILITY_L
,
392 DEVICE_ATI_3D_RAGE_LT4
,
393 DEVICE_ATI_3D_RAGE_LT5
,
394 DEVICE_ATI_RAGE_MOBILITY_P_M2
,
395 DEVICE_ATI_RAGE_MOBILITY_L2
398 static int find_chip(unsigned chip_id
)
401 for(i
= 0;i
< sizeof(ati_card_ids
)/sizeof(unsigned short);i
++)
403 if(chip_id
== ati_card_ids
[i
]) return i
;
408 static int mach64_probe(int verbose
,int force
)
410 pciinfo_t lst
[MAX_PCI_DEVICES
];
414 err
= pci_scan(lst
,&num_pci
);
417 printf("[mach64] Error occurred during pci scan: %s\n",strerror(err
));
423 for(i
=0;i
<num_pci
;i
++)
425 if(lst
[i
].vendor
== VENDOR_ATI
)
429 idx
= find_chip(lst
[i
].device
);
430 if(idx
== -1 && force
== PROBE_NORMAL
) continue;
431 dname
= pci_device_name(VENDOR_ATI
,lst
[i
].device
);
432 dname
= dname
? dname
: "Unknown chip";
433 printf("[mach64] Found chip: %s\n",dname
);
435 if ((lst
[i
].command
& PCI_COMMAND_IO
) == 0)
437 printf("[mach64] Device is disabled, ignoring\n");
441 if(force
> PROBE_NORMAL
)
443 printf("[mach64] Driver was forced. Was found %sknown chip\n",idx
== -1 ? "un" : "");
445 printf("[mach64] Assuming it as Mach64\n");
447 mach64_cap
.device_id
= lst
[i
].device
;
449 memcpy(&pci_info
,&lst
[i
],sizeof(pciinfo_t
));
455 if(err
&& verbose
) printf("[mach64] Can't find chip\n");
459 static void reset_regs( void )
462 for(i
=0;i
<sizeof(vregs
)/sizeof(video_registers_t
);i
++)
465 OUTREG(vregs
[i
].name
,0);
470 static int mach64_init(void)
475 printf("[mach64] Driver was not probed but is being initializing\n");
479 if((mach64_mmio_base
= map_phys_mem(pci_info
.base2
,0x1000))==(void *)-1) return ENOMEM
;
480 mach64_wait_for_idle();
481 mach64_ram_size
= INREG(MEM_CNTL
) & CTL_MEM_SIZEB
;
482 if (mach64_ram_size
< 8) mach64_ram_size
= (mach64_ram_size
+ 1) * 512;
483 else if (mach64_ram_size
< 12) mach64_ram_size
= (mach64_ram_size
- 3) * 1024;
484 else mach64_ram_size
= (mach64_ram_size
- 7) * 2048;
485 mach64_ram_size
*= 0x400; /* KB -> bytes */
486 if((mach64_mem_base
= map_phys_mem(pci_info
.base0
,mach64_ram_size
))==(void *)-1) return ENOMEM
;
487 memset(&besr
,0,sizeof(bes_registers_t
));
488 printf("[mach64] Video memory = %uMb\n",mach64_ram_size
/0x100000);
489 err
= mtrr_set_type(pci_info
.base0
,mach64_ram_size
,MTRR_TYPE_WRCOMB
);
490 if(!err
) printf("[mach64] Set write-combining type of video memory\n");
493 mach64_wait_for_idle();
494 SAVED_OVERLAY_GRAPHICS_KEY_CLR
= INREG(OVERLAY_GRAPHICS_KEY_CLR
);
496 /* check if planar formats are supported */
498 mach64_wait_for_idle();
500 if(INREG(SCALER_BUF0_OFFSET_U
)) supports_planar
=1;
503 OUTREG(SCALER_BUF0_OFFSET_U
, -1);
506 mach64_wait_for_idle();
509 if(INREG(SCALER_BUF0_OFFSET_U
)) supports_planar
=1;
511 if(supports_planar
) printf("[mach64] Planar YUV formats are supported :)\n");
512 else printf("[mach64] Planar YUV formats are not supported :(\n");
514 if( mach64_cap
.device_id
==DEVICE_ATI_RAGE_MOBILITY_P_M
515 || mach64_cap
.device_id
==DEVICE_ATI_RAGE_MOBILITY_P_M2
516 || mach64_cap
.device_id
==DEVICE_ATI_RAGE_MOBILITY_L
517 || mach64_cap
.device_id
==DEVICE_ATI_RAGE_MOBILITY_L2
)
518 supports_lcd_v_stretch
=1;
520 supports_lcd_v_stretch
=0;
523 mach64_vid_make_default();
525 if(verbosity
> VERBOSE_LEVEL
) mach64_vid_dump_regs();
529 static void mach64_destroy(void)
532 mach64_wait_for_idle();
533 OUTREG(OVERLAY_GRAPHICS_KEY_CLR
,SAVED_OVERLAY_GRAPHICS_KEY_CLR
);
535 unmap_phys_mem(mach64_mem_base
,mach64_ram_size
);
536 unmap_phys_mem(mach64_mmio_base
,0x1000);
539 static int mach64_get_caps(vidix_capability_t
*to
)
541 memcpy(to
, &mach64_cap
, sizeof(vidix_capability_t
));
545 static unsigned mach64_query_pitch(unsigned fourcc
,const vidix_yuv_t
*spitch
)
547 unsigned pitch
,spy
,spv
,spu
;
555 case 256: spy
= spitch
->y
; break;
564 case 256: spu
= spitch
->u
; break;
573 case 256: spv
= spitch
->v
; break;
582 if(spy
> 16 && spu
== spy
/2 && spv
== spy
/2) pitch
= spy
;
586 if(spy
> 32 && spu
== spy
/4 && spv
== spy
/4) pitch
= spy
;
590 if(spy
>= 16) pitch
= spy
;
597 static void mach64_compute_framesize(vidix_playback_t
*info
)
599 unsigned pitch
,awidth
;
600 pitch
= mach64_query_pitch(info
->fourcc
,&info
->src
.pitch
);
606 awidth
= (info
->src
.w
+ (pitch
-1)) & ~(pitch
-1);
607 info
->frame_size
= awidth
*(info
->src
.h
+info
->src
.h
/2);
610 awidth
= (info
->src
.w
+ (pitch
-1)) & ~(pitch
-1);
611 info
->frame_size
= awidth
*(info
->src
.h
+info
->src
.h
/8);
613 // case IMGFMT_RGB32:
615 awidth
= (info
->src
.w
*4 + (pitch
-1)) & ~(pitch
-1);
616 info
->frame_size
= (awidth
*info
->src
.h
);
618 /* YUY2 YVYU, RGB15, RGB16 */
620 awidth
= (info
->src
.w
*2 + (pitch
-1)) & ~(pitch
-1);
621 info
->frame_size
= (awidth
*info
->src
.h
);
624 info
->frame_size
+=256; // so we have some space for alignment & such
625 info
->frame_size
&=~16;
628 static void mach64_vid_stop_video( void )
630 mach64_fifo_wait(14);
631 OUTREG(OVERLAY_SCALE_CNTL
, 0x80000000);
632 OUTREG(OVERLAY_EXCLUSIVE_HORZ
, 0);
633 OUTREG(OVERLAY_EXCLUSIVE_VERT
, 0);
634 OUTREG(SCALER_H_COEFF0
, 0x00002000);
635 OUTREG(SCALER_H_COEFF1
, 0x0D06200D);
636 OUTREG(SCALER_H_COEFF2
, 0x0D0A1C0D);
637 OUTREG(SCALER_H_COEFF3
, 0x0C0E1A0C);
638 OUTREG(SCALER_H_COEFF4
, 0x0C14140C);
639 OUTREG(VIDEO_FORMAT
, 0xB000B);
640 OUTREG(OVERLAY_TEST
, 0x0);
643 static void mach64_vid_display_video( void )
646 mach64_fifo_wait(14);
648 OUTREG(OVERLAY_Y_X_START
, besr
.y_x_start
);
649 OUTREG(OVERLAY_Y_X_END
, besr
.y_x_end
);
650 OUTREG(OVERLAY_SCALE_INC
, besr
.scale_inc
);
651 OUTREG(SCALER_BUF_PITCH
, besr
.vid_buf_pitch
);
652 OUTREG(SCALER_HEIGHT_WIDTH
, besr
.height_width
);
653 OUTREG(SCALER_BUF0_OFFSET
, mach64_buffer_base
[0][0]);
654 OUTREG(SCALER_BUF0_OFFSET_U
, mach64_buffer_base
[0][1]);
655 OUTREG(SCALER_BUF0_OFFSET_V
, mach64_buffer_base
[0][2]);
656 OUTREG(SCALER_BUF1_OFFSET
, mach64_buffer_base
[0][0]);
657 OUTREG(SCALER_BUF1_OFFSET_U
, mach64_buffer_base
[0][1]);
658 OUTREG(SCALER_BUF1_OFFSET_V
, mach64_buffer_base
[0][2]);
662 OUTREG(OVERLAY_SCALE_CNTL
, 0xC4000003);
663 // OVERLAY_SCALE_CNTL bits & what they seem to affect
665 // bit 1 yuv2rgb coeff related
666 // bit 2 horizontal interpolation if 0
667 // bit 3 vertical interpolation if 0
668 // bit 4 chroma encoding (0-> 128=neutral / 1-> 0->neutral)
669 // bit 5-6 gamma correction
670 // bit 7 nothing visible if set
671 // bit 8-27 no effect
672 // bit 28-31 nothing interresting just crashed my system when i played with them :(
674 mach64_wait_for_idle();
675 vf
= INREG(VIDEO_FORMAT
);
677 // Bits 16-19 seem to select the format
678 // 0x0 dunno behaves strange
679 // 0x1 dunno behaves strange
680 // 0x2 dunno behaves strange
683 // 0x5 BGR16 (hmm, that need investigation, 2 BGR16 formats, i guess 1 will have only 5bits for green)
685 // 0x7 BGR32 with somehow mixed even / odd pixels ?
691 // 0xD UYVY (no difference is visible if i switch between C/D for every even/odd frame)
692 // 0xE dunno behaves strange
693 // 0xF dunno behaves strange
694 // Bit 28 all values are assumed to be 7 bit with chroma=64 for black (tested with YV12 & YUY2)
695 // the remaining bits seem to have no effect
701 case IMGFMT_BGR15
: OUTREG(VIDEO_FORMAT
, 0x00030000); break;
702 case IMGFMT_BGR16
: OUTREG(VIDEO_FORMAT
, 0x00040000); break;
703 case IMGFMT_BGR32
: OUTREG(VIDEO_FORMAT
, 0x00060000); break;
707 case IMGFMT_YV12
: OUTREG(VIDEO_FORMAT
, 0x000A0000); break;
709 case IMGFMT_YVU9
: OUTREG(VIDEO_FORMAT
, 0x00090000); break;
712 case IMGFMT_UYVY
: OUTREG(VIDEO_FORMAT
, 0x000C0000); break;
714 default: OUTREG(VIDEO_FORMAT
, 0x000B0000); break;
716 if(verbosity
> VERBOSE_LEVEL
) mach64_vid_dump_regs();
719 static int mach64_vid_init_video( vidix_playback_t
*config
)
721 uint32_t src_w
,src_h
,dest_w
,dest_h
,pitch
,h_inc
,v_inc
,left
,leftUV
,top
,ecp
,y_pos
;
722 int is_420
,best_pitch
,mpitch
;
723 int src_offset_y
, src_offset_u
, src_offset_v
;
726 mach64_vid_stop_video();
727 /* warning, if left or top are != 0 this will fail, as the framesize is too small then */
728 left
= config
->src
.x
;
730 src_h
= config
->src
.h
;
731 src_w
= config
->src
.w
;
733 if(config
->fourcc
== IMGFMT_YV12
||
734 config
->fourcc
== IMGFMT_I420
||
735 config
->fourcc
== IMGFMT_IYUV
) is_420
= 1;
736 best_pitch
= mach64_query_pitch(config
->fourcc
,&config
->src
.pitch
);
737 mpitch
= best_pitch
-1;
738 switch(config
->fourcc
)
744 case IMGFMT_I420
: pitch
= (src_w
+ mpitch
) & ~mpitch
;
745 config
->dest
.pitch
.y
=
746 config
->dest
.pitch
.u
=
747 config
->dest
.pitch
.v
= best_pitch
;
748 besr
.vid_buf_pitch
= pitch
;
752 case IMGFMT_BGR32
: pitch
= (src_w
*4 + mpitch
) & ~mpitch
;
753 config
->dest
.pitch
.y
=
754 config
->dest
.pitch
.u
=
755 config
->dest
.pitch
.v
= best_pitch
;
756 besr
.vid_buf_pitch
= pitch
>>2;
759 default: /* RGB15, RGB16, YVYU, UYVY, YUY2 */
760 pitch
= ((src_w
*2) + mpitch
) & ~mpitch
;
761 config
->dest
.pitch
.y
=
762 config
->dest
.pitch
.u
=
763 config
->dest
.pitch
.v
= best_pitch
;
764 besr
.vid_buf_pitch
= pitch
>>1;
767 dest_w
= config
->dest
.w
;
768 dest_h
= config
->dest
.h
;
769 besr
.fourcc
= config
->fourcc
;
770 ecp
= (INPLL(PLL_VCLK_CNTL
) & PLL_ECP_DIV
) >> 4;
772 if(verbosity
> 0) printf("[mach64] ecp: %d\n", ecp
);
773 v_inc
= src_h
* mach64_get_vert_stretch();
775 if(mach64_is_interlace()) v_inc
<<=1;
776 if(mach64_is_dbl_scan() ) v_inc
>>=1;
777 v_inc
>>=4; // convert 16.16 -> 20.12
780 h_inc
= (src_w
<< (12+ecp
)) / dest_w
;
781 /* keep everything in 16.16 */
782 config
->offsets
[0] = 0;
783 for(i
=1; i
<config
->num_frames
; i
++)
784 config
->offsets
[i
] = config
->offsets
[i
-1] + config
->frame_size
;
786 /*FIXME the left / top stuff is broken (= zoom a src rectangle from a larger one)
787 1. the framesize isn't known as the outer src rectangle dimensions aren't known
788 2. the mach64 needs aligned addresses so it can't work anyway
789 -> so we could shift the outer buffer to compensate that but that would mean
790 alignment problems for the code which writes into it
796 config
->offset
.u
= (pitch
*src_h
+ 15)&~15;
797 config
->offset
.v
= (config
->offset
.u
+ (pitch
*src_h
>>2) + 15)&~15;
799 if(besr
.fourcc
== IMGFMT_I420
|| besr
.fourcc
== IMGFMT_IYUV
)
802 tmp
= config
->offset
.u
;
803 config
->offset
.u
= config
->offset
.v
;
804 config
->offset
.v
= tmp
;
807 src_offset_y
= config
->offset
.y
+ top
*pitch
+ left
;
808 src_offset_u
= config
->offset
.u
+ (top
*pitch
>>2) + (left
>>1);
809 src_offset_v
= config
->offset
.v
+ (top
*pitch
>>2) + (left
>>1);
811 else if(besr
.fourcc
== IMGFMT_YVU9
)
814 config
->offset
.u
= (pitch
*src_h
+ 15)&~15;
815 config
->offset
.v
= (config
->offset
.u
+ (pitch
*src_h
>>4) + 15)&~15;
817 src_offset_y
= config
->offset
.y
+ top
*pitch
+ left
;
818 src_offset_u
= config
->offset
.u
+ (top
*pitch
>>4) + (left
>>1);
819 src_offset_v
= config
->offset
.v
+ (top
*pitch
>>4) + (left
>>1);
821 else if(besr
.fourcc
== IMGFMT_BGR32
)
823 config
->offset
.y
= config
->offset
.u
= config
->offset
.v
= 0;
824 src_offset_y
= src_offset_u
= src_offset_v
= top
*pitch
+ (left
<< 2);
828 config
->offset
.y
= config
->offset
.u
= config
->offset
.v
= 0;
829 src_offset_y
= src_offset_u
= src_offset_v
= top
*pitch
+ (left
<< 1);
832 num_mach64_buffers
= config
->num_frames
;
833 for(i
=0; i
<config
->num_frames
; i
++)
835 mach64_buffer_base
[i
][0]= (mach64_overlay_offset
+ config
->offsets
[i
] + src_offset_y
)&~15;
836 mach64_buffer_base
[i
][1]= (mach64_overlay_offset
+ config
->offsets
[i
] + src_offset_u
)&~15;
837 mach64_buffer_base
[i
][2]= (mach64_overlay_offset
+ config
->offsets
[i
] + src_offset_v
)&~15;
840 leftUV
= (left
>> 17) & 15;
841 left
= (left
>> 16) & 15;
842 besr
.scale_inc
= ( h_inc
<< 16 ) | v_inc
;
843 y_pos
= config
->dest
.y
;
844 if(mach64_is_dbl_scan()) y_pos
*=2;
846 if(mach64_is_interlace()) y_pos
/=2;
847 besr
.y_x_start
= y_pos
| (config
->dest
.x
<< 16);
848 y_pos
=config
->dest
.y
+ dest_h
;
849 if(mach64_is_dbl_scan()) y_pos
*=2;
851 if(mach64_is_interlace()) y_pos
/=2;
852 besr
.y_x_end
= y_pos
| ((config
->dest
.x
+ dest_w
) << 16);
853 besr
.height_width
= ((src_w
- left
)<<16) | (src_h
- top
);
858 static int is_supported_fourcc(uint32_t fourcc
)
866 return supports_planar
;
878 static int mach64_query_fourcc(vidix_fourcc_t
*to
)
880 if(is_supported_fourcc(to
->fourcc
))
882 to
->depth
= VID_DEPTH_ALL
;
883 to
->flags
= VID_CAP_EXPAND
| VID_CAP_SHRINK
| VID_CAP_COLORKEY
;
886 else to
->depth
= to
->flags
= 0;
890 static int mach64_config_playback(vidix_playback_t
*info
)
892 if(!is_supported_fourcc(info
->fourcc
)) return ENOSYS
;
894 mach64_compute_framesize(info
);
896 if(info
->num_frames
>4) info
->num_frames
=4;
897 for(;info
->num_frames
>0; info
->num_frames
--)
899 mach64_overlay_offset
= mach64_ram_size
- info
->frame_size
*info
->num_frames
;
900 mach64_overlay_offset
&= 0xffff0000;
901 if(mach64_overlay_offset
>0) break;
903 if(info
->num_frames
<= 0) return EINVAL
;
905 info
->dga_addr
= (char *)mach64_mem_base
+ mach64_overlay_offset
;
906 mach64_vid_init_video(info
);
910 static int mach64_playback_on(void)
912 mach64_vid_display_video();
916 static int mach64_playback_off(void)
918 mach64_vid_stop_video();
922 static int mach64_frame_sel(unsigned int frame
)
926 int last_frame
= (frame
-1+num_mach64_buffers
) % num_mach64_buffers
;
927 //printf("Selecting frame %d\n", frame);
929 buf3-5 always should point onto second buffer for better
930 deinterlacing and TV-in
932 if(num_mach64_buffers
==1) return 0;
936 off
[i
] = mach64_buffer_base
[frame
][i
];
937 off
[i
+3]= mach64_buffer_base
[last_frame
][i
];
940 mach64_wait_for_idle();
943 OUTREG(SCALER_BUF0_OFFSET
, off
[0]);
944 OUTREG(SCALER_BUF0_OFFSET_U
, off
[1]);
945 OUTREG(SCALER_BUF0_OFFSET_V
, off
[2]);
946 OUTREG(SCALER_BUF1_OFFSET
, off
[3]);
947 OUTREG(SCALER_BUF1_OFFSET_U
, off
[4]);
948 OUTREG(SCALER_BUF1_OFFSET_V
, off
[5]);
949 if(num_mach64_buffers
==2) mach64_wait_vsync(); //only wait for vsync if we do double buffering
951 if(verbosity
> VERBOSE_LEVEL
) mach64_vid_dump_regs();
955 static vidix_video_eq_t equal
=
957 VEQ_CAP_BRIGHTNESS
| VEQ_CAP_SATURATION
959 0, 0, 0, 0, 0, 0, 0, 0 };
961 static int mach64_get_eq( vidix_video_eq_t
* eq
)
963 memcpy(eq
,&equal
,sizeof(vidix_video_eq_t
));
967 static int mach64_set_eq( const vidix_video_eq_t
* eq
)
970 if(eq
->cap
& VEQ_CAP_BRIGHTNESS
) equal
.brightness
= eq
->brightness
;
971 if(eq
->cap
& VEQ_CAP_CONTRAST
) equal
.contrast
= eq
->contrast
;
972 if(eq
->cap
& VEQ_CAP_SATURATION
) equal
.saturation
= eq
->saturation
;
973 if(eq
->cap
& VEQ_CAP_HUE
) equal
.hue
= eq
->hue
;
974 if(eq
->cap
& VEQ_CAP_RGB_INTENSITY
)
976 equal
.red_intensity
= eq
->red_intensity
;
977 equal
.green_intensity
= eq
->green_intensity
;
978 equal
.blue_intensity
= eq
->blue_intensity
;
980 equal
.flags
= eq
->flags
;
981 br
= equal
.brightness
* 64 / 1000;
982 if(br
< -64) br
= -64; if(br
> 63) br
= 63;
983 sat
= (equal
.saturation
+ 1000) * 16 / 1000;
984 if(sat
< 0) sat
= 0; if(sat
> 31) sat
= 31;
985 OUTREG(SCALER_COLOUR_CNTL
, (br
& 0x7f) | (sat
<< 8) | (sat
<< 16));
989 static int mach64_get_gkeys(vidix_grkey_t
*grkey
)
991 memcpy(grkey
, &mach64_grkey
, sizeof(vidix_grkey_t
));
995 static int mach64_set_gkeys(const vidix_grkey_t
*grkey
)
997 memcpy(&mach64_grkey
, grkey
, sizeof(vidix_grkey_t
));
999 if(mach64_grkey
.ckey
.op
== CKEY_TRUE
)
1003 switch(mach64_vid_get_dbpp())
1006 besr
.graphics_key_msk
=0x7FFF;
1007 besr
.graphics_key_clr
=
1008 ((mach64_grkey
.ckey
.blue
&0xF8)>>3)
1009 | ((mach64_grkey
.ckey
.green
&0xF8)<<2)
1010 | ((mach64_grkey
.ckey
.red
&0xF8)<<7);
1013 besr
.graphics_key_msk
=0xFFFF;
1014 besr
.graphics_key_clr
=
1015 ((mach64_grkey
.ckey
.blue
&0xF8)>>3)
1016 | ((mach64_grkey
.ckey
.green
&0xFC)<<3)
1017 | ((mach64_grkey
.ckey
.red
&0xF8)<<8);
1018 //besr.graphics_key_clr=le2me_32(besr.graphics_key_clr);
1021 besr
.graphics_key_msk
=0xFFFFFF;
1022 besr
.graphics_key_clr
=
1023 ((mach64_grkey
.ckey
.blue
&0xFF))
1024 | ((mach64_grkey
.ckey
.green
&0xFF)<<8)
1025 | ((mach64_grkey
.ckey
.red
&0xFF)<<16);
1028 besr
.graphics_key_msk
=0xFFFFFF;
1029 besr
.graphics_key_clr
=
1030 ((mach64_grkey
.ckey
.blue
&0xFF))
1031 | ((mach64_grkey
.ckey
.green
&0xFF)<<8)
1032 | ((mach64_grkey
.ckey
.red
&0xFF)<<16);
1036 besr
.graphics_key_msk
=0;
1037 besr
.graphics_key_clr
=0;
1043 besr
.graphics_key_msk
=0;
1044 besr
.graphics_key_clr
=0;
1047 mach64_fifo_wait(4);
1048 OUTREG(OVERLAY_GRAPHICS_KEY_MSK
, besr
.graphics_key_msk
);
1049 OUTREG(OVERLAY_GRAPHICS_KEY_CLR
, besr
.graphics_key_clr
);
1050 // OUTREG(OVERLAY_VIDEO_KEY_MSK, 0);
1051 // OUTREG(OVERLAY_VIDEO_KEY_CLR, 0);
1053 OUTREG(OVERLAY_KEY_CNTL
,VIDEO_KEY_FN_TRUE
|GRAPHIC_KEY_FN_EQ
|CMP_MIX_AND
);
1055 OUTREG(OVERLAY_KEY_CNTL
,VIDEO_KEY_FN_TRUE
|GRAPHIC_KEY_FN_TRUE
|CMP_MIX_AND
);
1060 VDXDriver mach64_drv
= {
1063 .probe
= mach64_probe
,
1064 .get_caps
= mach64_get_caps
,
1065 .query_fourcc
= mach64_query_fourcc
,
1066 .init
= mach64_init
,
1067 .destroy
= mach64_destroy
,
1068 .config_playback
= mach64_config_playback
,
1069 .playback_on
= mach64_playback_on
,
1070 .playback_off
= mach64_playback_off
,
1071 .frame_sel
= mach64_frame_sel
,
1072 .get_eq
= mach64_get_eq
,
1073 .set_eq
= mach64_set_eq
,
1074 .get_gkey
= mach64_get_gkeys
,
1075 .set_gkey
= mach64_set_gkeys
,