Mercurial > mplayer.hg
diff vidix/radeon_vid.c @ 22850:9a1e26fef45b
Move driver files directly into the vidix directory.
author | diego |
---|---|
date | Sun, 01 Apr 2007 00:02:43 +0000 |
parents | |
children | 77def5093daf |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vidix/radeon_vid.c Sun Apr 01 00:02:43 2007 +0000 @@ -0,0 +1,2101 @@ +/* + radeon_vid - VIDIX based video driver for Radeon and Rage128 chips + Copyrights 2002 Nick Kurshev. This file is based on sources from + GATOS (gatos.sf.net) and X11 (www.xfree86.org) + Licence: GPL + + 31.12.2002 added support for fglrx drivers by Marcel Naziri (zwobbl@zwobbl.de) + 6.04.2004 fixes to allow compiling vidix without X11 (broken in original patch) + PPC support by Alex Beregszaszi +*/ + +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <math.h> +#include <inttypes.h> + +#include "../config.h" +#include "../libavutil/common.h" +#include "../mpbswap.h" +#include "../libdha/pci_ids.h" +#include "../libdha/pci_names.h" +#include "vidix.h" +#include "fourcc.h" +#include "../libdha/libdha.h" +#include "radeon.h" + +#ifdef HAVE_X11 +#include <X11/Xlib.h> +#endif + +#ifdef RAGE128 +#define RADEON_MSG "[rage128]" +#define X_ADJUST 0 +#else +#define RADEON_MSG "[radeon]" +#define X_ADJUST (is_shift_required ? 8 : 0) +#ifndef RADEON +#define RADEON +#endif +#endif + +static int __verbose = 0; +#ifdef RADEON +static int is_shift_required = 0; +#endif + +typedef struct bes_registers_s +{ + /* base address of yuv framebuffer */ + uint32_t yuv_base; + uint32_t fourcc; + uint32_t dest_bpp; + /* YUV BES registers */ + uint32_t reg_load_cntl; + uint32_t h_inc; + uint32_t step_by; + uint32_t y_x_start; + uint32_t y_x_end; + uint32_t v_inc; + uint32_t p1_blank_lines_at_top; + uint32_t p23_blank_lines_at_top; + uint32_t vid_buf_pitch0_value; + uint32_t vid_buf_pitch1_value; + uint32_t p1_x_start_end; + uint32_t p2_x_start_end; + uint32_t p3_x_start_end; + uint32_t base_addr; + uint32_t vid_buf_base_adrs_y[VID_PLAY_MAXFRAMES]; + uint32_t vid_buf_base_adrs_u[VID_PLAY_MAXFRAMES]; + uint32_t vid_buf_base_adrs_v[VID_PLAY_MAXFRAMES]; + uint32_t vid_nbufs; + + uint32_t p1_v_accum_init; + uint32_t p1_h_accum_init; + uint32_t p23_v_accum_init; + uint32_t p23_h_accum_init; + uint32_t scale_cntl; + uint32_t exclusive_horz; + uint32_t auto_flip_cntl; + uint32_t filter_cntl; + uint32_t key_cntl; + uint32_t test; + /* Configurable stuff */ + int double_buff; + + int brightness; + int saturation; + + int ckey_on; + uint32_t graphics_key_clr; + uint32_t graphics_key_msk; + uint32_t ckey_cntl; + + int deinterlace_on; + uint32_t deinterlace_pattern; + +} bes_registers_t; + +typedef struct video_registers_s +{ + const char * sname; + uint32_t name; + uint32_t value; +}video_registers_t; + +static bes_registers_t besr; +#ifndef RAGE128 +static int RadeonFamily=100; +#endif +#define DECLARE_VREG(name) { #name, name, 0 } +static video_registers_t vregs[] = +{ + DECLARE_VREG(VIDEOMUX_CNTL), + DECLARE_VREG(VIPPAD_MASK), + DECLARE_VREG(VIPPAD1_A), + DECLARE_VREG(VIPPAD1_EN), + DECLARE_VREG(VIPPAD1_Y), + DECLARE_VREG(OV0_Y_X_START), + DECLARE_VREG(OV0_Y_X_END), + DECLARE_VREG(OV0_PIPELINE_CNTL), + DECLARE_VREG(OV0_EXCLUSIVE_HORZ), + DECLARE_VREG(OV0_EXCLUSIVE_VERT), + DECLARE_VREG(OV0_REG_LOAD_CNTL), + DECLARE_VREG(OV0_SCALE_CNTL), + DECLARE_VREG(OV0_V_INC), + DECLARE_VREG(OV0_P1_V_ACCUM_INIT), + DECLARE_VREG(OV0_P23_V_ACCUM_INIT), + DECLARE_VREG(OV0_P1_BLANK_LINES_AT_TOP), + DECLARE_VREG(OV0_P23_BLANK_LINES_AT_TOP), +#ifdef RADEON + DECLARE_VREG(OV0_BASE_ADDR), +#endif + DECLARE_VREG(OV0_VID_BUF0_BASE_ADRS), + DECLARE_VREG(OV0_VID_BUF1_BASE_ADRS), + DECLARE_VREG(OV0_VID_BUF2_BASE_ADRS), + DECLARE_VREG(OV0_VID_BUF3_BASE_ADRS), + DECLARE_VREG(OV0_VID_BUF4_BASE_ADRS), + DECLARE_VREG(OV0_VID_BUF5_BASE_ADRS), + DECLARE_VREG(OV0_VID_BUF_PITCH0_VALUE), + DECLARE_VREG(OV0_VID_BUF_PITCH1_VALUE), + DECLARE_VREG(OV0_AUTO_FLIP_CNTL), + DECLARE_VREG(OV0_DEINTERLACE_PATTERN), + DECLARE_VREG(OV0_SUBMIT_HISTORY), + DECLARE_VREG(OV0_H_INC), + DECLARE_VREG(OV0_STEP_BY), + DECLARE_VREG(OV0_P1_H_ACCUM_INIT), + DECLARE_VREG(OV0_P23_H_ACCUM_INIT), + DECLARE_VREG(OV0_P1_X_START_END), + DECLARE_VREG(OV0_P2_X_START_END), + DECLARE_VREG(OV0_P3_X_START_END), + DECLARE_VREG(OV0_FILTER_CNTL), + DECLARE_VREG(OV0_FOUR_TAP_COEF_0), + DECLARE_VREG(OV0_FOUR_TAP_COEF_1), + DECLARE_VREG(OV0_FOUR_TAP_COEF_2), + DECLARE_VREG(OV0_FOUR_TAP_COEF_3), + DECLARE_VREG(OV0_FOUR_TAP_COEF_4), + DECLARE_VREG(OV0_FLAG_CNTL), +#ifdef RAGE128 + DECLARE_VREG(OV0_COLOUR_CNTL), +#else + DECLARE_VREG(OV0_SLICE_CNTL), +#endif + DECLARE_VREG(OV0_VID_KEY_CLR), + DECLARE_VREG(OV0_VID_KEY_MSK), + DECLARE_VREG(OV0_GRAPHICS_KEY_CLR), + DECLARE_VREG(OV0_GRAPHICS_KEY_MSK), + DECLARE_VREG(OV0_KEY_CNTL), + DECLARE_VREG(OV0_TEST), + DECLARE_VREG(OV0_LIN_TRANS_A), + DECLARE_VREG(OV0_LIN_TRANS_B), + DECLARE_VREG(OV0_LIN_TRANS_C), + DECLARE_VREG(OV0_LIN_TRANS_D), + DECLARE_VREG(OV0_LIN_TRANS_E), + DECLARE_VREG(OV0_LIN_TRANS_F), + DECLARE_VREG(OV0_GAMMA_0_F), + DECLARE_VREG(OV0_GAMMA_10_1F), + DECLARE_VREG(OV0_GAMMA_20_3F), + DECLARE_VREG(OV0_GAMMA_40_7F), + DECLARE_VREG(OV0_GAMMA_380_3BF), + DECLARE_VREG(OV0_GAMMA_3C0_3FF), + DECLARE_VREG(SUBPIC_CNTL), + DECLARE_VREG(SUBPIC_DEFCOLCON), + DECLARE_VREG(SUBPIC_Y_X_START), + DECLARE_VREG(SUBPIC_Y_X_END), + DECLARE_VREG(SUBPIC_V_INC), + DECLARE_VREG(SUBPIC_H_INC), + DECLARE_VREG(SUBPIC_BUF0_OFFSET), + DECLARE_VREG(SUBPIC_BUF1_OFFSET), + DECLARE_VREG(SUBPIC_LC0_OFFSET), + DECLARE_VREG(SUBPIC_LC1_OFFSET), + DECLARE_VREG(SUBPIC_PITCH), + DECLARE_VREG(SUBPIC_BTN_HLI_COLCON), + DECLARE_VREG(SUBPIC_BTN_HLI_Y_X_START), + DECLARE_VREG(SUBPIC_BTN_HLI_Y_X_END), + DECLARE_VREG(SUBPIC_PALETTE_INDEX), + DECLARE_VREG(SUBPIC_PALETTE_DATA), + DECLARE_VREG(SUBPIC_H_ACCUM_INIT), + DECLARE_VREG(SUBPIC_V_ACCUM_INIT), + DECLARE_VREG(IDCT_RUNS), + DECLARE_VREG(IDCT_LEVELS), + DECLARE_VREG(IDCT_AUTH_CONTROL), + DECLARE_VREG(IDCT_AUTH), + DECLARE_VREG(IDCT_CONTROL), + DECLARE_VREG(CONFIG_CNTL) +}; + +#ifdef HAVE_X11 +static uint32_t firegl_shift = 0; +#endif +static void * radeon_mmio_base = 0; +static void * radeon_mem_base = 0; +static int32_t radeon_overlay_off = 0; +static uint32_t radeon_ram_size = 0; +/* Restore on exit */ +static uint32_t SAVED_OV0_GRAPHICS_KEY_CLR = 0; +static uint32_t SAVED_OV0_GRAPHICS_KEY_MSK = 0; +static uint32_t SAVED_OV0_VID_KEY_CLR = 0; +static uint32_t SAVED_OV0_VID_KEY_MSK = 0; +static uint32_t SAVED_OV0_KEY_CNTL = 0; +#ifdef WORDS_BIGENDIAN +static uint32_t SAVED_CONFIG_CNTL = 0; +#if defined(RAGE128) +#define APER_0_BIG_ENDIAN_16BPP_SWAP (1<<0) +#define APER_0_BIG_ENDIAN_32BPP_SWAP (2<<0) +#else +#define RADEON_SURFACE_CNTL 0x0b00 +#define RADEON_NONSURF_AP0_SWP_16BPP (1 << 20) +#define RADEON_NONSURF_AP0_SWP_32BPP (1 << 21) +#endif +#endif + +#define GETREG(TYPE,PTR,OFFZ) (*((volatile TYPE*)((PTR)+(OFFZ)))) +#define SETREG(TYPE,PTR,OFFZ,VAL) (*((volatile TYPE*)((PTR)+(OFFZ))))=VAL + +#define INREG8(addr) GETREG(uint8_t,(uint8_t*)(radeon_mmio_base),addr) +#define OUTREG8(addr,val) SETREG(uint8_t,(uint8_t*)(radeon_mmio_base),addr,val) + +static inline uint32_t INREG (uint32_t addr) { + uint32_t tmp = GETREG(uint32_t,(uint8_t*)(radeon_mmio_base),addr); + return le2me_32(tmp); +} +//#define OUTREG(addr,val) SETREG(uint32_t,(uint8_t*)(radeon_mmio_base),addr,val) +#define OUTREG(addr,val) SETREG(uint32_t,(uint8_t*)(radeon_mmio_base),addr,le2me_32(val)) +#define OUTREGP(addr,val,mask) \ + do { \ + unsigned int _tmp = INREG(addr); \ + _tmp &= (mask); \ + _tmp |= (val); \ + OUTREG(addr, _tmp); \ + } while (0) + +static __inline__ uint32_t INPLL(uint32_t addr) +{ + OUTREG8(CLOCK_CNTL_INDEX, addr & 0x0000001f); + return (INREG(CLOCK_CNTL_DATA)); +} + +#define OUTPLL(addr,val) OUTREG8(CLOCK_CNTL_INDEX, (addr & 0x0000001f) | 0x00000080); \ + OUTREG(CLOCK_CNTL_DATA, val) +#define OUTPLLP(addr,val,mask) \ + do { \ + unsigned int _tmp = INPLL(addr); \ + _tmp &= (mask); \ + _tmp |= (val); \ + OUTPLL(addr, _tmp); \ + } while (0) + +static uint32_t radeon_vid_get_dbpp( void ) +{ + uint32_t dbpp,retval; + dbpp = (INREG(CRTC_GEN_CNTL)>>8)& 0xF; + switch(dbpp) + { + case DST_8BPP: retval = 8; break; + case DST_15BPP: retval = 15; break; + case DST_16BPP: retval = 16; break; + case DST_24BPP: retval = 24; break; + default: retval=32; break; + } + return retval; +} + +static int radeon_is_dbl_scan( void ) +{ + return (INREG(CRTC_GEN_CNTL))&CRTC_DBL_SCAN_EN; +} + +static int radeon_is_interlace( void ) +{ + return (INREG(CRTC_GEN_CNTL))&CRTC_INTERLACE_EN; +} + +static uint32_t radeon_get_xres( void ) +{ + /* FIXME: currently we extract that from CRTC!!!*/ + uint32_t xres,h_total; + h_total = INREG(CRTC_H_TOTAL_DISP); + xres = (h_total >> 16) & 0xffff; + return (xres + 1)*8; +} + +static uint32_t radeon_get_yres( void ) +{ + /* FIXME: currently we extract that from CRTC!!!*/ + uint32_t yres,v_total; + v_total = INREG(CRTC_V_TOTAL_DISP); + yres = (v_total >> 16) & 0xffff; + return yres + 1; +} + +/* get flat panel x resolution*/ +static uint32_t radeon_get_fp_xres( void ){ + uint32_t xres=(INREG(FP_HORZ_STRETCH)&0x00fff000)>>16; + xres=(xres+1)*8; + return xres; +} + +/* get flat panel y resolution*/ +static uint32_t radeon_get_fp_yres( void ){ + uint32_t yres=(INREG(FP_VERT_STRETCH)&0x00fff000)>>12; + return yres+1; +} + +static void radeon_wait_vsync(void) +{ + int i; + + OUTREG(GEN_INT_STATUS, VSYNC_INT_AK); + for (i = 0; i < 2000000; i++) + { + if (INREG(GEN_INT_STATUS) & VSYNC_INT) break; + } +} + +#ifdef RAGE128 +static void _radeon_engine_idle(void); +static void _radeon_fifo_wait(unsigned); +#define radeon_engine_idle() _radeon_engine_idle() +#define radeon_fifo_wait(entries) _radeon_fifo_wait(entries) +/* Flush all dirty data in the Pixel Cache to memory. */ +static __inline__ void radeon_engine_flush ( void ) +{ + unsigned i; + + OUTREGP(PC_NGUI_CTLSTAT, PC_FLUSH_ALL, ~PC_FLUSH_ALL); + for (i = 0; i < 2000000; i++) { + if (!(INREG(PC_NGUI_CTLSTAT) & PC_BUSY)) break; + } +} + +/* Reset graphics card to known state. */ +static void radeon_engine_reset( void ) +{ + uint32_t clock_cntl_index; + uint32_t mclk_cntl; + uint32_t gen_reset_cntl; + + radeon_engine_flush(); + + clock_cntl_index = INREG(CLOCK_CNTL_INDEX); + mclk_cntl = INPLL(MCLK_CNTL); + + OUTPLL(MCLK_CNTL, mclk_cntl | FORCE_GCP | FORCE_PIPE3D_CP); + + gen_reset_cntl = INREG(GEN_RESET_CNTL); + + OUTREG(GEN_RESET_CNTL, gen_reset_cntl | SOFT_RESET_GUI); + INREG(GEN_RESET_CNTL); + OUTREG(GEN_RESET_CNTL, + gen_reset_cntl & (uint32_t)(~SOFT_RESET_GUI)); + INREG(GEN_RESET_CNTL); + + OUTPLL(MCLK_CNTL, mclk_cntl); + OUTREG(CLOCK_CNTL_INDEX, clock_cntl_index); + OUTREG(GEN_RESET_CNTL, gen_reset_cntl); +} +#else + +static __inline__ void radeon_engine_flush ( void ) +{ + int i; + + /* initiate flush */ + OUTREGP(RB2D_DSTCACHE_CTLSTAT, RB2D_DC_FLUSH_ALL, + ~RB2D_DC_FLUSH_ALL); + + for (i=0; i < 2000000; i++) { + if (!(INREG(RB2D_DSTCACHE_CTLSTAT) & RB2D_DC_BUSY)) + break; + } +} + +static void _radeon_engine_idle(void); +static void _radeon_fifo_wait(unsigned); +#define radeon_engine_idle() _radeon_engine_idle() +#define radeon_fifo_wait(entries) _radeon_fifo_wait(entries) + +static void radeon_engine_reset( void ) +{ + uint32_t clock_cntl_index, mclk_cntl, rbbm_soft_reset; + + radeon_engine_flush (); + + clock_cntl_index = INREG(CLOCK_CNTL_INDEX); + mclk_cntl = INPLL(MCLK_CNTL); + + OUTPLL(MCLK_CNTL, (mclk_cntl | + FORCEON_MCLKA | + FORCEON_MCLKB | + FORCEON_YCLKA | + FORCEON_YCLKB | + FORCEON_MC | + FORCEON_AIC)); + rbbm_soft_reset = INREG(RBBM_SOFT_RESET); + + OUTREG(RBBM_SOFT_RESET, rbbm_soft_reset | + SOFT_RESET_CP | + SOFT_RESET_HI | + SOFT_RESET_SE | + SOFT_RESET_RE | + SOFT_RESET_PP | + SOFT_RESET_E2 | + SOFT_RESET_RB | + SOFT_RESET_HDP); + INREG(RBBM_SOFT_RESET); + OUTREG(RBBM_SOFT_RESET, rbbm_soft_reset & (uint32_t) + ~(SOFT_RESET_CP | + SOFT_RESET_HI | + SOFT_RESET_SE | + SOFT_RESET_RE | + SOFT_RESET_PP | + SOFT_RESET_E2 | + SOFT_RESET_RB | + SOFT_RESET_HDP)); + INREG(RBBM_SOFT_RESET); + + OUTPLL(MCLK_CNTL, mclk_cntl); + OUTREG(CLOCK_CNTL_INDEX, clock_cntl_index); + OUTREG(RBBM_SOFT_RESET, rbbm_soft_reset); + + return; +} +#endif +static void radeon_engine_restore( void ) +{ +#ifndef RAGE128 + int pitch64; + uint32_t xres,yres,bpp; + radeon_fifo_wait(1); + xres = radeon_get_xres(); + yres = radeon_get_yres(); + bpp = radeon_vid_get_dbpp(); + /* turn of all automatic flushing - we'll do it all */ + OUTREG(RB2D_DSTCACHE_MODE, 0); + + pitch64 = ((xres * (bpp / 8) + 0x3f)) >> 6; + + radeon_fifo_wait(1); + OUTREG(DEFAULT_OFFSET, (INREG(DEFAULT_OFFSET) & 0xC0000000) | + (pitch64 << 22)); + + radeon_fifo_wait(1); +#if defined(WORDS_BIGENDIAN) +#ifdef RADEON + OUTREGP(DP_DATATYPE, HOST_BIG_ENDIAN_EN, ~HOST_BIG_ENDIAN_EN); +#endif +#else + OUTREGP(DP_DATATYPE, 0, ~HOST_BIG_ENDIAN_EN); +#endif + + radeon_fifo_wait(1); + OUTREG(DEFAULT_SC_BOTTOM_RIGHT, (DEFAULT_SC_RIGHT_MAX + | DEFAULT_SC_BOTTOM_MAX)); + radeon_fifo_wait(1); + OUTREG(DP_GUI_MASTER_CNTL, (INREG(DP_GUI_MASTER_CNTL) + | GMC_BRUSH_SOLID_COLOR + | GMC_SRC_DATATYPE_COLOR)); + + radeon_fifo_wait(7); + OUTREG(DST_LINE_START, 0); + OUTREG(DST_LINE_END, 0); + OUTREG(DP_BRUSH_FRGD_CLR, 0xffffffff); + OUTREG(DP_BRUSH_BKGD_CLR, 0x00000000); + OUTREG(DP_SRC_FRGD_CLR, 0xffffffff); + OUTREG(DP_SRC_BKGD_CLR, 0x00000000); + OUTREG(DP_WRITE_MASK, 0xffffffff); + + radeon_engine_idle(); +#endif +} +#ifdef RAGE128 +static void _radeon_fifo_wait (unsigned entries) +{ + unsigned i; + + for(;;) + { + for (i=0; i<2000000; i++) + if ((INREG(GUI_STAT) & GUI_FIFOCNT_MASK) >= entries) + return; + radeon_engine_reset(); + radeon_engine_restore(); + } +} + +static void _radeon_engine_idle ( void ) +{ + unsigned i; + + /* ensure FIFO is empty before waiting for idle */ + radeon_fifo_wait (64); + for(;;) + { + for (i=0; i<2000000; i++) { + if ((INREG(GUI_STAT) & GUI_ACTIVE) == 0) { + radeon_engine_flush (); + return; + } + } + radeon_engine_reset(); + radeon_engine_restore(); + } +} +#else +static void _radeon_fifo_wait (unsigned entries) +{ + unsigned i; + + for(;;) + { + for (i=0; i<2000000; i++) + if ((INREG(RBBM_STATUS) & RBBM_FIFOCNT_MASK) >= entries) + return; + radeon_engine_reset(); + radeon_engine_restore(); + } +} +static void _radeon_engine_idle ( void ) +{ + int i; + + /* ensure FIFO is empty before waiting for idle */ + radeon_fifo_wait (64); + for(;;) + { + for (i=0; i<2000000; i++) { + if (((INREG(RBBM_STATUS) & RBBM_ACTIVE)) == 0) { + radeon_engine_flush (); + return; + } + } + radeon_engine_reset(); + radeon_engine_restore(); + } +} +#endif + +#ifndef RAGE128 +/* Reference color space transform data */ +typedef struct tagREF_TRANSFORM +{ + float RefLuma; + float RefRCb; + float RefRCr; + float RefGCb; + float RefGCr; + float RefBCb; + float RefBCr; +} REF_TRANSFORM; + +/* Parameters for ITU-R BT.601 and ITU-R BT.709 colour spaces */ +REF_TRANSFORM trans[2] = +{ + {1.1678, 0.0, 1.6007, -0.3929, -0.8154, 2.0232, 0.0}, /* BT.601 */ + {1.1678, 0.0, 1.7980, -0.2139, -0.5345, 2.1186, 0.0} /* BT.709 */ +}; +/**************************************************************************** + * SetTransform * + * Function: Calculates and sets color space transform from supplied * + * reference transform, gamma, brightness, contrast, hue and * + * saturation. * + * Inputs: bright - brightness * + * cont - contrast * + * sat - saturation * + * hue - hue * + * red_intensity - intense of red component * + * green_intensity - intense of green component * + * blue_intensity - intense of blue component * + * ref - index to the table of refernce transforms * + * Outputs: NONE * + ****************************************************************************/ + +static void radeon_set_transform(float bright, float cont, float sat, + float hue, float red_intensity, + float green_intensity,float blue_intensity, + unsigned ref) +{ + float OvHueSin, OvHueCos; + float CAdjLuma, CAdjOff; + float RedAdj,GreenAdj,BlueAdj; + float CAdjRCb, CAdjRCr; + float CAdjGCb, CAdjGCr; + float CAdjBCb, CAdjBCr; + float OvLuma, OvROff, OvGOff, OvBOff; + float OvRCb, OvRCr; + float OvGCb, OvGCr; + float OvBCb, OvBCr; + float Loff = 64.0; + float Coff = 512.0f; + + uint32_t dwOvLuma, dwOvROff, dwOvGOff, dwOvBOff; + uint32_t dwOvRCb, dwOvRCr; + uint32_t dwOvGCb, dwOvGCr; + uint32_t dwOvBCb, dwOvBCr; + + if (ref >= 2) return; + + OvHueSin = sin((double)hue); + OvHueCos = cos((double)hue); + + CAdjLuma = cont * trans[ref].RefLuma; + CAdjOff = cont * trans[ref].RefLuma * bright * 1023.0; + RedAdj = cont * trans[ref].RefLuma * red_intensity * 1023.0; + GreenAdj = cont * trans[ref].RefLuma * green_intensity * 1023.0; + BlueAdj = cont * trans[ref].RefLuma * blue_intensity * 1023.0; + + CAdjRCb = sat * -OvHueSin * trans[ref].RefRCr; + CAdjRCr = sat * OvHueCos * trans[ref].RefRCr; + CAdjGCb = sat * (OvHueCos * trans[ref].RefGCb - OvHueSin * trans[ref].RefGCr); + CAdjGCr = sat * (OvHueSin * trans[ref].RefGCb + OvHueCos * trans[ref].RefGCr); + CAdjBCb = sat * OvHueCos * trans[ref].RefBCb; + CAdjBCr = sat * OvHueSin * trans[ref].RefBCb; + +#if 0 /* default constants */ + CAdjLuma = 1.16455078125; + + CAdjRCb = 0.0; + CAdjRCr = 1.59619140625; + CAdjGCb = -0.39111328125; + CAdjGCr = -0.8125; + CAdjBCb = 2.01708984375; + CAdjBCr = 0; +#endif + OvLuma = CAdjLuma; + OvRCb = CAdjRCb; + OvRCr = CAdjRCr; + OvGCb = CAdjGCb; + OvGCr = CAdjGCr; + OvBCb = CAdjBCb; + OvBCr = CAdjBCr; + OvROff = RedAdj + CAdjOff - + OvLuma * Loff - (OvRCb + OvRCr) * Coff; + OvGOff = GreenAdj + CAdjOff - + OvLuma * Loff - (OvGCb + OvGCr) * Coff; + OvBOff = BlueAdj + CAdjOff - + OvLuma * Loff - (OvBCb + OvBCr) * Coff; +#if 0 /* default constants */ + OvROff = -888.5; + OvGOff = 545; + OvBOff = -1104; +#endif + + dwOvROff = ((int)(OvROff * 2.0)) & 0x1fff; + dwOvGOff = (int)(OvGOff * 2.0) & 0x1fff; + dwOvBOff = (int)(OvBOff * 2.0) & 0x1fff; + /* Whatever docs say about R200 having 3.8 format instead of 3.11 + as in Radeon is a lie */ +#if 0 + if(RadeonFamily == 100) + { +#endif + dwOvLuma =(((int)(OvLuma * 2048.0))&0x7fff)<<17; + dwOvRCb = (((int)(OvRCb * 2048.0))&0x7fff)<<1; + dwOvRCr = (((int)(OvRCr * 2048.0))&0x7fff)<<17; + dwOvGCb = (((int)(OvGCb * 2048.0))&0x7fff)<<1; + dwOvGCr = (((int)(OvGCr * 2048.0))&0x7fff)<<17; + dwOvBCb = (((int)(OvBCb * 2048.0))&0x7fff)<<1; + dwOvBCr = (((int)(OvBCr * 2048.0))&0x7fff)<<17; +#if 0 + } + else + { + dwOvLuma = (((int)(OvLuma * 256.0))&0x7ff)<<20; + dwOvRCb = (((int)(OvRCb * 256.0))&0x7ff)<<4; + dwOvRCr = (((int)(OvRCr * 256.0))&0x7ff)<<20; + dwOvGCb = (((int)(OvGCb * 256.0))&0x7ff)<<4; + dwOvGCr = (((int)(OvGCr * 256.0))&0x7ff)<<20; + dwOvBCb = (((int)(OvBCb * 256.0))&0x7ff)<<4; + dwOvBCr = (((int)(OvBCr * 256.0))&0x7ff)<<20; + } +#endif + OUTREG(OV0_LIN_TRANS_A, dwOvRCb | dwOvLuma); + OUTREG(OV0_LIN_TRANS_B, dwOvROff | dwOvRCr); + OUTREG(OV0_LIN_TRANS_C, dwOvGCb | dwOvLuma); + OUTREG(OV0_LIN_TRANS_D, dwOvGOff | dwOvGCr); + OUTREG(OV0_LIN_TRANS_E, dwOvBCb | dwOvLuma); + OUTREG(OV0_LIN_TRANS_F, dwOvBOff | dwOvBCr); +} + +/* Gamma curve definition */ +typedef struct +{ + unsigned int gammaReg; + unsigned int gammaSlope; + unsigned int gammaOffset; +}GAMMA_SETTINGS; + +/* Recommended gamma curve parameters */ +GAMMA_SETTINGS r200_def_gamma[18] = +{ + {OV0_GAMMA_0_F, 0x100, 0x0000}, + {OV0_GAMMA_10_1F, 0x100, 0x0020}, + {OV0_GAMMA_20_3F, 0x100, 0x0040}, + {OV0_GAMMA_40_7F, 0x100, 0x0080}, + {OV0_GAMMA_80_BF, 0x100, 0x0100}, + {OV0_GAMMA_C0_FF, 0x100, 0x0100}, + {OV0_GAMMA_100_13F, 0x100, 0x0200}, + {OV0_GAMMA_140_17F, 0x100, 0x0200}, + {OV0_GAMMA_180_1BF, 0x100, 0x0300}, + {OV0_GAMMA_1C0_1FF, 0x100, 0x0300}, + {OV0_GAMMA_200_23F, 0x100, 0x0400}, + {OV0_GAMMA_240_27F, 0x100, 0x0400}, + {OV0_GAMMA_280_2BF, 0x100, 0x0500}, + {OV0_GAMMA_2C0_2FF, 0x100, 0x0500}, + {OV0_GAMMA_300_33F, 0x100, 0x0600}, + {OV0_GAMMA_340_37F, 0x100, 0x0600}, + {OV0_GAMMA_380_3BF, 0x100, 0x0700}, + {OV0_GAMMA_3C0_3FF, 0x100, 0x0700} +}; + +GAMMA_SETTINGS r100_def_gamma[6] = +{ + {OV0_GAMMA_0_F, 0x100, 0x0000}, + {OV0_GAMMA_10_1F, 0x100, 0x0020}, + {OV0_GAMMA_20_3F, 0x100, 0x0040}, + {OV0_GAMMA_40_7F, 0x100, 0x0080}, + {OV0_GAMMA_380_3BF, 0x100, 0x0100}, + {OV0_GAMMA_3C0_3FF, 0x100, 0x0100} +}; + +static void make_default_gamma_correction( void ) +{ + size_t i; + if(RadeonFamily == 100) { + OUTREG(OV0_LIN_TRANS_A, 0x12A00000); + OUTREG(OV0_LIN_TRANS_B, 0x199018FE); + OUTREG(OV0_LIN_TRANS_C, 0x12A0F9B0); + OUTREG(OV0_LIN_TRANS_D, 0xF2F0043B); + OUTREG(OV0_LIN_TRANS_E, 0x12A02050); + OUTREG(OV0_LIN_TRANS_F, 0x0000174E); + for(i=0; i<6; i++){ + OUTREG(r100_def_gamma[i].gammaReg, + (r100_def_gamma[i].gammaSlope<<16) | + r100_def_gamma[i].gammaOffset); + } + } + else{ + OUTREG(OV0_LIN_TRANS_A, 0x12a00000); + OUTREG(OV0_LIN_TRANS_B, 0x1990190e); + OUTREG(OV0_LIN_TRANS_C, 0x12a0f9c0); + OUTREG(OV0_LIN_TRANS_D, 0xf3000442); + OUTREG(OV0_LIN_TRANS_E, 0x12a02040); + OUTREG(OV0_LIN_TRANS_F, 0x175f); + + /* Default Gamma, + Of 18 segments for gamma cure, all segments in R200 are programmable, + while only lower 4 and upper 2 segments are programmable in Radeon*/ + for(i=0; i<18; i++){ + OUTREG(r200_def_gamma[i].gammaReg, + (r200_def_gamma[i].gammaSlope<<16) | + r200_def_gamma[i].gammaOffset); + } + } +} +#endif + +static void radeon_vid_make_default(void) +{ +#ifdef RAGE128 + OUTREG(OV0_COLOUR_CNTL,0x00101000UL); /* Default brightness and saturation for Rage128 */ +#else + make_default_gamma_correction(); +#endif + besr.deinterlace_pattern = 0x900AAAAA; + OUTREG(OV0_DEINTERLACE_PATTERN,besr.deinterlace_pattern); + besr.deinterlace_on=1; + besr.double_buff=1; + besr.ckey_on=0; + besr.graphics_key_msk=0; + besr.graphics_key_clr=0; + besr.ckey_cntl = VIDEO_KEY_FN_TRUE|GRAPHIC_KEY_FN_TRUE|CMP_MIX_AND; +} + + +unsigned vixGetVersion( void ) { return VIDIX_VERSION; } + +static unsigned short ati_card_ids[] = +{ +#ifdef RAGE128 + /* + This driver should be compatible with Rage128 (pro) chips. + (include adaptive deinterlacing!!!). + Moreover: the same logic can be used with Mach64 chips. + (I mean: mach64xx, 3d rage, 3d rage IIc, 3D rage pro, 3d rage mobility). + but they are incompatible by i/o ports. So if enthusiasts will want + then they can redefine OUTREG and INREG macros and redefine OV0_* + constants. Also it seems that mach64 chips supports only: YUY2, YV12, UYVY + fourccs (422 and 420 formats only). + */ +/* Rage128 Pro GL */ + DEVICE_ATI_RAGE_128_PA_PRO, + DEVICE_ATI_RAGE_128_PB_PRO, + DEVICE_ATI_RAGE_128_PC_PRO, + DEVICE_ATI_RAGE_128_PD_PRO, + DEVICE_ATI_RAGE_128_PE_PRO, + DEVICE_ATI_RAGE_128_PF_PRO, +/* Rage128 Pro VR */ + DEVICE_ATI_RAGE_128_PG_PRO, + DEVICE_ATI_RAGE_128_PH_PRO, + DEVICE_ATI_RAGE_128_PI_PRO, + DEVICE_ATI_RAGE_128_PJ_PRO, + DEVICE_ATI_RAGE_128_PK_PRO, + DEVICE_ATI_RAGE_128_PL_PRO, + DEVICE_ATI_RAGE_128_PM_PRO, + DEVICE_ATI_RAGE_128_PN_PRO, + DEVICE_ATI_RAGE_128_PO_PRO, + DEVICE_ATI_RAGE_128_PP_PRO, + DEVICE_ATI_RAGE_128_PQ_PRO, + DEVICE_ATI_RAGE_128_PR_PRO, + DEVICE_ATI_RAGE_128_PS_PRO, + DEVICE_ATI_RAGE_128_PT_PRO, + DEVICE_ATI_RAGE_128_PU_PRO, + DEVICE_ATI_RAGE_128_PV_PRO, + DEVICE_ATI_RAGE_128_PW_PRO, + DEVICE_ATI_RAGE_128_PX_PRO, +/* Rage128 GL */ + DEVICE_ATI_RAGE_128_RE_SG, + DEVICE_ATI_RAGE_128_RF_SG, + DEVICE_ATI_RAGE_128_RG, + DEVICE_ATI_RAGE_128_RK_VR, + DEVICE_ATI_RAGE_128_RL_VR, + DEVICE_ATI_RAGE_128_SE_4X, + DEVICE_ATI_RAGE_128_SF_4X, + DEVICE_ATI_RAGE_128_SG_4X, + DEVICE_ATI_RAGE_128_SH, + DEVICE_ATI_RAGE_128_SK_4X, + DEVICE_ATI_RAGE_128_SL_4X, + DEVICE_ATI_RAGE_128_SM_4X, + DEVICE_ATI_RAGE_128_4X, + DEVICE_ATI_RAGE_128_PRO, + DEVICE_ATI_RAGE_128_PRO2, + DEVICE_ATI_RAGE_128_PRO3, +/* these seem to be based on rage 128 instead of mach64 */ + DEVICE_ATI_RAGE_MOBILITY_M3, + DEVICE_ATI_RAGE_MOBILITY_M32 +#else +/* Radeons (indeed: Rage 256 Pro ;) */ + DEVICE_ATI_RADEON_R100_QD, + DEVICE_ATI_RADEON_R100_QE, + DEVICE_ATI_RADEON_R100_QF, + DEVICE_ATI_RADEON_R100_QG, + DEVICE_ATI_RADEON_VE_QY, + DEVICE_ATI_RADEON_VE_QZ, + DEVICE_ATI_RADEON_MOBILITY_M7, + DEVICE_ATI_RADEON_MOBILITY_M72, + DEVICE_ATI_RADEON_MOBILITY_M6, + DEVICE_ATI_RADEON_MOBILITY_M62, + DEVICE_ATI_RADEON_MOBILITY_U1, + DEVICE_ATI_RADEON_R200_BB, + DEVICE_ATI_RADEON_R200_QH, + DEVICE_ATI_RADEON_R200_QI, + DEVICE_ATI_RADEON_R200_QJ, + DEVICE_ATI_RADEON_R200_QK, + DEVICE_ATI_RADEON_R200_QL, + DEVICE_ATI_RADEON_R200_QM, + DEVICE_ATI_RADEON_R200_QH2, + DEVICE_ATI_RADEON_R200_QI2, + DEVICE_ATI_RADEON_R200_QJ2, + DEVICE_ATI_RADEON_R200_QK2, + DEVICE_ATI_RADEON_RV200_QW, + DEVICE_ATI_RADEON_RV200_QX, + DEVICE_ATI_RADEON_R250_ID, + DEVICE_ATI_RADEON_R250_IE, + DEVICE_ATI_RADEON_R250_IF, + DEVICE_ATI_RADEON_R250_IG, + DEVICE_ATI_RADEON_R250_LD, + DEVICE_ATI_RADEON_R250_LE, + DEVICE_ATI_RADEON_R250_LF, + DEVICE_ATI_RADEON_R250_LG, + DEVICE_ATI_RV370_5B60_RADEON, + DEVICE_ATI_RV250_5C61_RADEON, + DEVICE_ATI_RV250_5C63_RADEON, + DEVICE_ATI_RV280_RADEON_9200, + DEVICE_ATI_RV280_RADEON_92002, + DEVICE_ATI_RV280_RADEON_92003, + DEVICE_ATI_RV280_RADEON_92004, + DEVICE_ATI_RV280_RADEON_92005, + DEVICE_ATI_RV280_RADEON_92006, + DEVICE_ATI_RADEON_R300_ND, + DEVICE_ATI_RADEON_R300_NE, + DEVICE_ATI_RADEON_R300_NF, + DEVICE_ATI_RADEON_R300_NG, + DEVICE_ATI_RADEON_R300_AE, + DEVICE_ATI_RADEON_R300_AF, + DEVICE_ATI_RADEON_RV350_AP, + DEVICE_ATI_RADEON_RV350_AQ, + DEVICE_ATI_RADEON_RV350_AR, + DEVICE_ATI_RADEON_RV350_BK, + DEVICE_ATI_RADEON_R350_AH, + DEVICE_ATI_RADEON_R350_AI, + DEVICE_ATI_RADEON_R350_NH, + DEVICE_ATI_RADEON_R360_NJ, + DEVICE_ATI_RV350_MOBILITY_RADEON, + DEVICE_ATI_RV350_MOBILITY_RADEON2 +#endif +}; + +static int find_chip(unsigned chip_id) +{ + unsigned i; + for(i = 0;i < sizeof(ati_card_ids)/sizeof(unsigned short);i++) + { + if(chip_id == ati_card_ids[i]) return i; + } + return -1; +} + +static pciinfo_t pci_info; +static int probed=0; + +vidix_capability_t def_cap = +{ +#ifdef RAGE128 + "BES driver for Rage128 cards", +#else + "BES driver for Radeon cards", +#endif + "Nick Kurshev", + TYPE_OUTPUT | TYPE_FX, + { 0, 0, 0, 0 }, + 2048, + 2048, + 4, + 4, + -1, + FLAG_UPSCALER | FLAG_DOWNSCALER | FLAG_EQUALIZER, + VENDOR_ATI, + 0, + { 0, 0, 0, 0} +}; + +#ifdef HAVE_X11 +static void probe_fireGL_driver(void) { + Display *dp = XOpenDisplay ((void*)0); + int n = 0; + char **extlist; + if (dp==NULL) { + return; + } + extlist = XListExtensions (dp, &n); + XCloseDisplay (dp); + if (extlist) { + int i; + int ext_fgl = 0, ext_fglrx = 0; + for (i = 0; i < n; i++) { + if (!strcmp(extlist[i], "ATIFGLEXTENSION")) ext_fgl = 1; + if (!strcmp(extlist[i], "ATIFGLRXDRI")) ext_fglrx = 1; + } + if (ext_fgl) { + printf(RADEON_MSG" ATI FireGl driver detected"); + firegl_shift = 0x500000; + if (!ext_fglrx) { + printf(", but DRI seems not to be activated\n"); + printf(RADEON_MSG" Output may not work correctly, check your DRI configuration!"); + } + printf("\n"); + } + } +} +#endif + +int vixProbe( int verbose,int force ) +{ + pciinfo_t lst[MAX_PCI_DEVICES]; + unsigned i,num_pci; + int err; + __verbose = verbose; + err = pci_scan(lst,&num_pci); + if(err) + { + printf(RADEON_MSG" Error occurred during pci scan: %s\n",strerror(err)); + return err; + } + else + { + err = ENXIO; + for(i=0;i<num_pci;i++) + { + if(lst[i].vendor == VENDOR_ATI) + { + int idx; + const char *dname; + idx = find_chip(lst[i].device); + if(idx == -1 && force == PROBE_NORMAL) continue; + dname = pci_device_name(VENDOR_ATI,lst[i].device); + dname = dname ? dname : "Unknown chip"; + printf(RADEON_MSG" Found chip: %s\n",dname); +#if 0 + if ((lst[i].command & PCI_COMMAND_IO) == 0) + { + printf("[radeon] Device is disabled, ignoring\n"); + continue; + } +#endif +#ifndef RAGE128 + if(idx != -1) +#ifdef HAVE_X11 + probe_fireGL_driver(); +#endif + { + switch(ati_card_ids[idx]) { + /* Original radeon */ + case DEVICE_ATI_RADEON_R100_QD: + case DEVICE_ATI_RADEON_R100_QE: + case DEVICE_ATI_RADEON_R100_QF: + case DEVICE_ATI_RADEON_R100_QG: + RadeonFamily = 100; + break; + + /* Radeon VE / Radeon Mobility */ + case DEVICE_ATI_RADEON_VE_QY: + case DEVICE_ATI_RADEON_VE_QZ: + case DEVICE_ATI_RADEON_MOBILITY_M6: + case DEVICE_ATI_RADEON_MOBILITY_M62: + case DEVICE_ATI_RADEON_MOBILITY_U1: + RadeonFamily = 120; + break; + + /* Radeon 7500 / Radeon Mobility 7500 */ + case DEVICE_ATI_RADEON_RV200_QW: + case DEVICE_ATI_RADEON_RV200_QX: + case DEVICE_ATI_RADEON_MOBILITY_M7: + case DEVICE_ATI_RADEON_MOBILITY_M72: + RadeonFamily = 150; + break; + + /* Radeon 8500 */ + case DEVICE_ATI_RADEON_R200_BB: + case DEVICE_ATI_RADEON_R200_QH: + case DEVICE_ATI_RADEON_R200_QI: + case DEVICE_ATI_RADEON_R200_QJ: + case DEVICE_ATI_RADEON_R200_QK: + case DEVICE_ATI_RADEON_R200_QL: + case DEVICE_ATI_RADEON_R200_QM: + case DEVICE_ATI_RADEON_R200_QH2: + case DEVICE_ATI_RADEON_R200_QI2: + case DEVICE_ATI_RADEON_R200_QJ2: + case DEVICE_ATI_RADEON_R200_QK2: + RadeonFamily = 200; + break; + + /* Radeon 9000 */ + case DEVICE_ATI_RADEON_R250_ID: + case DEVICE_ATI_RADEON_R250_IE: + case DEVICE_ATI_RADEON_R250_IF: + case DEVICE_ATI_RADEON_R250_IG: + case DEVICE_ATI_RADEON_R250_LD: + case DEVICE_ATI_RADEON_R250_LE: + case DEVICE_ATI_RADEON_R250_LF: + case DEVICE_ATI_RADEON_R250_LG: + case DEVICE_ATI_RV250_5C61_RADEON: + case DEVICE_ATI_RV250_5C63_RADEON: + RadeonFamily = 250; + break; + + /* Radeon 9200 */ + case DEVICE_ATI_RV280_RADEON_9200: + case DEVICE_ATI_RV280_RADEON_92002: + case DEVICE_ATI_RV280_RADEON_92003: + case DEVICE_ATI_RV280_RADEON_92004: + case DEVICE_ATI_RV280_RADEON_92005: + case DEVICE_ATI_RV280_RADEON_92006: + RadeonFamily = 280; + break; + + /* Radeon 9700 */ + case DEVICE_ATI_RADEON_R300_ND: + case DEVICE_ATI_RADEON_R300_NE: + case DEVICE_ATI_RADEON_R300_NF: + case DEVICE_ATI_RADEON_R300_NG: + case DEVICE_ATI_RADEON_R300_AE: + case DEVICE_ATI_RADEON_R300_AF: + RadeonFamily = 300; + break; + + /* Radeon 9600/9800 */ + case DEVICE_ATI_RV370_5B60_RADEON: + case DEVICE_ATI_RADEON_RV350_AP: + case DEVICE_ATI_RADEON_RV350_AQ: + case DEVICE_ATI_RADEON_RV350_AR: + case DEVICE_ATI_RADEON_RV350_BK: + case DEVICE_ATI_RADEON_R350_NH: + case DEVICE_ATI_RADEON_R350_AH: + case DEVICE_ATI_RADEON_R350_AI: + case DEVICE_ATI_RADEON_R360_NJ: + case DEVICE_ATI_RV350_MOBILITY_RADEON: + case DEVICE_ATI_RV350_MOBILITY_RADEON2: + RadeonFamily = 350; + break; + + default: + break; + } + } +#endif + if(force > PROBE_NORMAL) + { + printf(RADEON_MSG" Driver was forced. Was found %sknown chip\n",idx == -1 ? "un" : ""); + if(idx == -1) +#ifdef RAGE128 + printf(RADEON_MSG" Assuming it as Rage128\n"); +#else + printf(RADEON_MSG" Assuming it as Radeon1\n"); +#endif + } + def_cap.device_id = lst[i].device; + err = 0; + memcpy(&pci_info,&lst[i],sizeof(pciinfo_t)); + probed=1; + break; + } + } + } + if(err && verbose) printf(RADEON_MSG" Can't find chip\n"); + return err; +} + +static void radeon_vid_dump_regs( void ); /* forward declaration */ + +int vixInit( void ) +{ + int err; + if(!probed) + { + printf(RADEON_MSG" Driver was not probed but is being initializing\n"); + return EINTR; + } + if((radeon_mmio_base = map_phys_mem(pci_info.base2,0xFFFF))==(void *)-1) return ENOMEM; + radeon_ram_size = INREG(CONFIG_MEMSIZE); + /* mem size is bits [28:0], mask off the rest. Range: from 1Mb up to 512 Mb */ + radeon_ram_size &= CONFIG_MEMSIZE_MASK; +#ifdef RADEON + /* according to XFree86 4.2.0, some production M6's return 0 for 8MB */ + if (radeon_ram_size == 0 && + (def_cap.device_id == DEVICE_ATI_RADEON_MOBILITY_M6 || + def_cap.device_id == DEVICE_ATI_RADEON_MOBILITY_M62)) + { + printf(RADEON_MSG" Workarounding buggy Radeon Mobility M6 (0 vs. 8MB ram)\n"); + radeon_ram_size = 8192*1024; + } +#else + /* Rage Mobility (rage128) also has memsize bug */ + if (radeon_ram_size == 0 && + (def_cap.device_id == DEVICE_ATI_RAGE_MOBILITY_M3 || + def_cap.device_id == DEVICE_ATI_RAGE_128_RL_VR || + def_cap.device_id == DEVICE_ATI_RAGE_MOBILITY_M32)) + { + printf(RADEON_MSG" Workarounding buggy Rage Mobility M3 (0 vs. 8MB ram)\n"); + radeon_ram_size = 8192*1024; + } +#endif + printf(RADEON_MSG" Video memory = %uMb\n",radeon_ram_size/0x100000); +#ifdef WIN32 + //mapping large areas of video ram will fail on windows + if(radeon_ram_size > 16*1024*1024)radeon_ram_size=16*1024*1024; +#endif + if((radeon_mem_base = map_phys_mem(pci_info.base0,radeon_ram_size))==(void *)-1) return ENOMEM; + memset(&besr,0,sizeof(bes_registers_t)); + radeon_vid_make_default(); + err = mtrr_set_type(pci_info.base0,radeon_ram_size,MTRR_TYPE_WRCOMB); + if(!err) printf(RADEON_MSG" Set write-combining type of video memory\n"); + + radeon_fifo_wait(3); + SAVED_OV0_GRAPHICS_KEY_CLR = INREG(OV0_GRAPHICS_KEY_CLR); + SAVED_OV0_GRAPHICS_KEY_MSK = INREG(OV0_GRAPHICS_KEY_MSK); + SAVED_OV0_VID_KEY_CLR = INREG(OV0_VID_KEY_CLR); + SAVED_OV0_VID_KEY_MSK = INREG(OV0_VID_KEY_MSK); + SAVED_OV0_KEY_CNTL = INREG(OV0_KEY_CNTL); + printf(RADEON_MSG" Saved overlay colorkey settings\n"); + +#ifdef RADEON + switch(RadeonFamily) + { + case 100: + case 120: + case 150: + case 250: + case 280: + is_shift_required=1; + break; + default: + break; + } +#endif + +/* XXX: hack, but it works for me (tm) */ +#ifdef WORDS_BIGENDIAN +#if defined(RAGE128) + /* code from gatos */ + { + SAVED_CONFIG_CNTL = INREG(CONFIG_CNTL); + OUTREG(CONFIG_CNTL, SAVED_CONFIG_CNTL & + ~(APER_0_BIG_ENDIAN_16BPP_SWAP|APER_0_BIG_ENDIAN_32BPP_SWAP)); + +// printf("saved: %x, current: %x\n", SAVED_CONFIG_CNTL, +// INREG(CONFIG_CNTL)); + } +#else + /*code from radeon_video.c*/ + { + SAVED_CONFIG_CNTL = INREG(RADEON_SURFACE_CNTL); +/* OUTREG(RADEON_SURFACE_CNTL, (SAVED_CONFIG_CNTL | + RADEON_NONSURF_AP0_SWP_32BPP) & ~RADEON_NONSURF_AP0_SWP_16BPP); +*/ + OUTREG(RADEON_SURFACE_CNTL, SAVED_CONFIG_CNTL & ~(RADEON_NONSURF_AP0_SWP_32BPP + | RADEON_NONSURF_AP0_SWP_16BPP)); + +/* + OUTREG(RADEON_SURFACE_CNTL, (SAVED_CONFIG_CNTL | RADEON_NONSURF_AP0_SWP_32BPP) + & ~RADEON_NONSURF_AP0_SWP_16BPP); +*/ + } +#endif +#endif + + if(__verbose > 1) radeon_vid_dump_regs(); + return 0; +} + +void vixDestroy( void ) +{ + /* remove colorkeying */ + radeon_fifo_wait(3); + OUTREG(OV0_GRAPHICS_KEY_CLR, SAVED_OV0_GRAPHICS_KEY_CLR); + OUTREG(OV0_GRAPHICS_KEY_MSK, SAVED_OV0_GRAPHICS_KEY_MSK); + OUTREG(OV0_VID_KEY_CLR, SAVED_OV0_VID_KEY_CLR); + OUTREG(OV0_VID_KEY_MSK, SAVED_OV0_VID_KEY_MSK); + OUTREG(OV0_KEY_CNTL, SAVED_OV0_KEY_CNTL); + printf(RADEON_MSG" Restored overlay colorkey settings\n"); + +#ifdef WORDS_BIGENDIAN +#if defined(RAGE128) + OUTREG(CONFIG_CNTL, SAVED_CONFIG_CNTL); +// printf("saved: %x, restored: %x\n", SAVED_CONFIG_CNTL, +// INREG(CONFIG_CNTL)); +#else + OUTREG(RADEON_SURFACE_CNTL, SAVED_CONFIG_CNTL); +#endif +#endif + + unmap_phys_mem(radeon_mem_base,radeon_ram_size); + unmap_phys_mem(radeon_mmio_base,0xFFFF); +} + +int vixGetCapability(vidix_capability_t *to) +{ + memcpy(to,&def_cap,sizeof(vidix_capability_t)); + return 0; +} + +/* + Full list of fourcc which are supported by Win2K redeon driver: + YUY2, UYVY, DDES, OGLT, OGL2, OGLS, OGLB, OGNT, OGNZ, OGNS, + IF09, YVU9, IMC4, M2IA, IYUV, VBID, DXT1, DXT2, DXT3, DXT4, DXT5 +*/ +uint32_t supported_fourcc[] = +{ + IMGFMT_Y800, IMGFMT_Y8, IMGFMT_YVU9, IMGFMT_IF09, + IMGFMT_YV12, IMGFMT_I420, IMGFMT_IYUV, + IMGFMT_UYVY, IMGFMT_YUY2, IMGFMT_YVYU, + IMGFMT_RGB15, IMGFMT_BGR15, + IMGFMT_RGB16, IMGFMT_BGR16, + IMGFMT_RGB32, IMGFMT_BGR32 +}; + +inline static int is_supported_fourcc(uint32_t fourcc) +{ + unsigned int i; + for(i=0;i<sizeof(supported_fourcc)/sizeof(uint32_t);i++) + { + if(fourcc==supported_fourcc[i]) return 1; + } + return 0; +} + +int vixQueryFourcc(vidix_fourcc_t *to) +{ + if(is_supported_fourcc(to->fourcc)) + { + to->depth = VID_DEPTH_1BPP | VID_DEPTH_2BPP | + VID_DEPTH_4BPP | VID_DEPTH_8BPP | + VID_DEPTH_12BPP| VID_DEPTH_15BPP| + VID_DEPTH_16BPP| VID_DEPTH_24BPP| + VID_DEPTH_32BPP; + to->flags = VID_CAP_EXPAND | VID_CAP_SHRINK | VID_CAP_COLORKEY; + return 0; + } + else to->depth = to->flags = 0; + return ENOSYS; +} + +static void radeon_vid_dump_regs( void ) +{ + size_t i; + printf(RADEON_MSG"*** Begin of DRIVER variables dump ***\n"); + printf(RADEON_MSG"radeon_mmio_base=%p\n",radeon_mmio_base); + printf(RADEON_MSG"radeon_mem_base=%p\n",radeon_mem_base); + printf(RADEON_MSG"radeon_overlay_off=%08X\n",radeon_overlay_off); + printf(RADEON_MSG"radeon_ram_size=%08X\n",radeon_ram_size); + printf(RADEON_MSG"video mode: %ux%u@%u\n",radeon_get_xres(),radeon_get_yres(),radeon_vid_get_dbpp()); + printf(RADEON_MSG"flatpanel size: %ux%u\n",radeon_get_fp_xres(),radeon_get_fp_yres()); + printf(RADEON_MSG"*** Begin of OV0 registers dump ***\n"); + for(i=0;i<sizeof(vregs)/sizeof(video_registers_t);i++) + printf(RADEON_MSG"%s = %08X\n",vregs[i].sname,INREG(vregs[i].name)); + printf(RADEON_MSG"*** End of OV0 registers dump ***\n"); +} + +static void radeon_vid_stop_video( void ) +{ + radeon_engine_idle(); + OUTREG(OV0_SCALE_CNTL, SCALER_SOFT_RESET); + OUTREG(OV0_EXCLUSIVE_HORZ, 0); + OUTREG(OV0_AUTO_FLIP_CNTL, 0); /* maybe */ + OUTREG(OV0_FILTER_CNTL, FILTER_HARDCODED_COEF); +#ifdef RADEON + OUTREG(OV0_KEY_CNTL, GRAPHIC_KEY_FN_EQ); +#else + OUTREG(OV0_KEY_CNTL, GRAPHIC_KEY_FN_NE); +#endif + OUTREG(OV0_TEST, 0); +} + +static void radeon_vid_display_video( void ) +{ + int bes_flags; + /** workaround for Xorg-6.8 not saving the surface registers on bigendian architectures */ +#ifdef WORDS_BIGENDIAN +#if defined(RAGE128) + /* code from gatos */ + { + SAVED_CONFIG_CNTL = INREG(CONFIG_CNTL); + OUTREG(CONFIG_CNTL, SAVED_CONFIG_CNTL & + ~(APER_0_BIG_ENDIAN_16BPP_SWAP|APER_0_BIG_ENDIAN_32BPP_SWAP)); + +// printf("saved: %x, current: %x\n", SAVED_CONFIG_CNTL, +// INREG(CONFIG_CNTL)); + } +#else + /*code from radeon_video.c*/ + { + SAVED_CONFIG_CNTL = INREG(RADEON_SURFACE_CNTL); +/* OUTREG(RADEON_SURFACE_CNTL, (SAVED_CONFIG_CNTL | + RADEON_NONSURF_AP0_SWP_32BPP) & ~RADEON_NONSURF_AP0_SWP_16BPP); +*/ + OUTREG(RADEON_SURFACE_CNTL, SAVED_CONFIG_CNTL & ~(RADEON_NONSURF_AP0_SWP_32BPP + | RADEON_NONSURF_AP0_SWP_16BPP)); + +/* + OUTREG(RADEON_SURFACE_CNTL, (SAVED_CONFIG_CNTL | RADEON_NONSURF_AP0_SWP_32BPP) + & ~RADEON_NONSURF_AP0_SWP_16BPP); +*/ + } +#endif +#endif + + + + radeon_fifo_wait(2); + OUTREG(OV0_REG_LOAD_CNTL, REG_LD_CTL_LOCK); + radeon_engine_idle(); + while(!(INREG(OV0_REG_LOAD_CNTL)®_LD_CTL_LOCK_READBACK)); + radeon_fifo_wait(15); + + /* Shutdown capturing */ + OUTREG(FCP_CNTL, FCP_CNTL__GND); + OUTREG(CAP0_TRIG_CNTL, 0); + + OUTREG(VID_BUFFER_CONTROL, (1<<16) | 0x01); + OUTREG(DISP_TEST_DEBUG_CNTL, 0); + + OUTREG(OV0_AUTO_FLIP_CNTL,OV0_AUTO_FLIP_CNTL_SOFT_BUF_ODD); + + if(besr.deinterlace_on) OUTREG(OV0_DEINTERLACE_PATTERN,besr.deinterlace_pattern); +#ifdef RAGE128 + OUTREG(OV0_COLOUR_CNTL, (((besr.brightness*64)/1000) & 0x7f) | + (((besr.saturation*31+31000)/2000) << 8) | + (((besr.saturation*31+31000)/2000) << 16)); +#endif + radeon_fifo_wait(2); + OUTREG(OV0_GRAPHICS_KEY_MSK, besr.graphics_key_msk); + OUTREG(OV0_GRAPHICS_KEY_CLR, besr.graphics_key_clr); + OUTREG(OV0_KEY_CNTL,besr.ckey_cntl); + + OUTREG(OV0_H_INC, besr.h_inc); + OUTREG(OV0_STEP_BY, besr.step_by); + OUTREG(OV0_Y_X_START, besr.y_x_start); + OUTREG(OV0_Y_X_END, besr.y_x_end); + OUTREG(OV0_V_INC, besr.v_inc); + OUTREG(OV0_P1_BLANK_LINES_AT_TOP, besr.p1_blank_lines_at_top); + OUTREG(OV0_P23_BLANK_LINES_AT_TOP, besr.p23_blank_lines_at_top); + OUTREG(OV0_VID_BUF_PITCH0_VALUE, besr.vid_buf_pitch0_value); + OUTREG(OV0_VID_BUF_PITCH1_VALUE, besr.vid_buf_pitch1_value); + OUTREG(OV0_P1_X_START_END, besr.p1_x_start_end); + OUTREG(OV0_P2_X_START_END, besr.p2_x_start_end); + OUTREG(OV0_P3_X_START_END, besr.p3_x_start_end); +#ifdef RADEON + OUTREG(OV0_BASE_ADDR, besr.base_addr); +#endif + OUTREG(OV0_VID_BUF0_BASE_ADRS, besr.vid_buf_base_adrs_y[0]); + OUTREG(OV0_VID_BUF1_BASE_ADRS, besr.vid_buf_base_adrs_v[0]); + OUTREG(OV0_VID_BUF2_BASE_ADRS, besr.vid_buf_base_adrs_u[0]); + radeon_fifo_wait(9); + OUTREG(OV0_VID_BUF3_BASE_ADRS, besr.vid_buf_base_adrs_y[0]); + OUTREG(OV0_VID_BUF4_BASE_ADRS, besr.vid_buf_base_adrs_v[0]); + OUTREG(OV0_VID_BUF5_BASE_ADRS, besr.vid_buf_base_adrs_u[0]); + OUTREG(OV0_P1_V_ACCUM_INIT, besr.p1_v_accum_init); + OUTREG(OV0_P1_H_ACCUM_INIT, besr.p1_h_accum_init); + OUTREG(OV0_P23_H_ACCUM_INIT, besr.p23_h_accum_init); + OUTREG(OV0_P23_V_ACCUM_INIT, besr.p23_v_accum_init); + +#ifdef RADEON + bes_flags = SCALER_ENABLE | + SCALER_SMART_SWITCH; +// SCALER_HORZ_PICK_NEAREST | +// SCALER_VERT_PICK_NEAREST | +#endif + bes_flags = SCALER_ENABLE | + SCALER_SMART_SWITCH | + SCALER_Y2R_TEMP | + SCALER_PIX_EXPAND; + if(besr.double_buff) bes_flags |= SCALER_DOUBLE_BUFFER; + if(besr.deinterlace_on) bes_flags |= SCALER_ADAPTIVE_DEINT; +#ifdef RAGE128 + bes_flags |= SCALER_BURST_PER_PLANE; +#endif + switch(besr.fourcc) + { + case IMGFMT_RGB15: + case IMGFMT_BGR15: bes_flags |= SCALER_SOURCE_15BPP; break; + case IMGFMT_RGB16: + case IMGFMT_BGR16: bes_flags |= SCALER_SOURCE_16BPP; break; +/* + case IMGFMT_RGB24: + case IMGFMT_BGR24: bes_flags |= SCALER_SOURCE_24BPP; break; +*/ + case IMGFMT_RGB32: + case IMGFMT_BGR32: bes_flags |= SCALER_SOURCE_32BPP; break; + /* 4:1:0 */ + case IMGFMT_IF09: + case IMGFMT_YVU9: bes_flags |= SCALER_SOURCE_YUV9; break; + /* 4:0:0 */ + case IMGFMT_Y800: + case IMGFMT_Y8: + /* 4:2:0 */ + case IMGFMT_IYUV: + case IMGFMT_I420: + case IMGFMT_YV12: bes_flags |= SCALER_SOURCE_YUV12; break; + /* 4:2:2 */ + case IMGFMT_YVYU: + case IMGFMT_UYVY: bes_flags |= SCALER_SOURCE_YVYU422; break; + case IMGFMT_YUY2: + default: bes_flags |= SCALER_SOURCE_VYUY422; break; + } + OUTREG(OV0_SCALE_CNTL, bes_flags); + OUTREG(OV0_REG_LOAD_CNTL, 0); + if(__verbose > 1) printf(RADEON_MSG"we wanted: scaler=%08X\n",bes_flags); + if(__verbose > 1) radeon_vid_dump_regs(); +} + +static unsigned radeon_query_pitch(unsigned fourcc,const vidix_yuv_t *spitch) +{ + unsigned pitch,spy,spv,spu; + spy = spv = spu = 0; + switch(spitch->y) + { + case 16: + case 32: + case 64: + case 128: + case 256: spy = spitch->y; break; + default: break; + } + switch(spitch->u) + { + case 16: + case 32: + case 64: + case 128: + case 256: spu = spitch->u; break; + default: break; + } + switch(spitch->v) + { + case 16: + case 32: + case 64: + case 128: + case 256: spv = spitch->v; break; + default: break; + } + switch(fourcc) + { + /* 4:2:0 */ + case IMGFMT_IYUV: + case IMGFMT_YV12: + case IMGFMT_I420: + if(spy > 16 && spu == spy/2 && spv == spy/2) pitch = spy; + else pitch = 32; + break; + /* 4:1:0 */ + case IMGFMT_IF09: + case IMGFMT_YVU9: + if(spy > 32 && spu == spy/4 && spv == spy/4) pitch = spy; + else pitch = 64; + break; + default: + if(spy >= 16) pitch = spy; + else pitch = 16; + break; + } + return pitch; +} + +static int radeon_vid_init_video( vidix_playback_t *config ) +{ + uint32_t i,tmp,src_w,src_h,dest_w,dest_h,pitch,h_inc,step_by,left,leftUV,top; + int is_400,is_410,is_420,is_rgb32,is_rgb,best_pitch,mpitch; + radeon_vid_stop_video(); + left = config->src.x << 16; + top = config->src.y << 16; + src_h = config->src.h; + src_w = config->src.w; + is_400 = is_410 = is_420 = is_rgb32 = is_rgb = 0; + if(config->fourcc == IMGFMT_YV12 || + config->fourcc == IMGFMT_I420 || + config->fourcc == IMGFMT_IYUV) is_420 = 1; + if(config->fourcc == IMGFMT_YVU9 || + config->fourcc == IMGFMT_IF09) is_410 = 1; + if(config->fourcc == IMGFMT_Y800 || + config->fourcc == IMGFMT_Y8) is_400 = 1; + if(config->fourcc == IMGFMT_RGB32 || + config->fourcc == IMGFMT_BGR32) is_rgb32 = 1; + if(config->fourcc == IMGFMT_RGB32 || + config->fourcc == IMGFMT_BGR32 || + config->fourcc == IMGFMT_RGB24 || + config->fourcc == IMGFMT_BGR24 || + config->fourcc == IMGFMT_RGB16 || + config->fourcc == IMGFMT_BGR16 || + config->fourcc == IMGFMT_RGB15 || + config->fourcc == IMGFMT_BGR15) is_rgb = 1; + best_pitch = radeon_query_pitch(config->fourcc,&config->src.pitch); + mpitch = best_pitch-1; + switch(config->fourcc) + { + /* 4:0:0 */ + case IMGFMT_Y800: + case IMGFMT_Y8: + /* 4:1:0 */ + case IMGFMT_YVU9: + case IMGFMT_IF09: + /* 4:2:0 */ + case IMGFMT_IYUV: + case IMGFMT_YV12: + case IMGFMT_I420: pitch = (src_w + mpitch) & ~mpitch; + config->dest.pitch.y = + config->dest.pitch.u = + config->dest.pitch.v = best_pitch; + break; + /* RGB 4:4:4:4 */ + case IMGFMT_RGB32: + case IMGFMT_BGR32: pitch = (src_w*4 + mpitch) & ~mpitch; + config->dest.pitch.y = + config->dest.pitch.u = + config->dest.pitch.v = best_pitch; + break; + /* 4:2:2 */ + default: /* RGB15, RGB16, YVYU, UYVY, YUY2 */ + pitch = ((src_w*2) + mpitch) & ~mpitch; + config->dest.pitch.y = + config->dest.pitch.u = + config->dest.pitch.v = best_pitch; + break; + } + dest_w = config->dest.w; + dest_h = config->dest.h; + if(radeon_is_dbl_scan()) dest_h *= 2; + besr.dest_bpp = radeon_vid_get_dbpp(); + besr.fourcc = config->fourcc; + + /* flat panel */ + if(INREG(FP_VERT_STRETCH)&VERT_STRETCH_ENABLE){ + besr.v_inc = (src_h * radeon_get_yres() / radeon_get_fp_yres() << 20) / dest_h; + } + else besr.v_inc = (src_h << 20) / dest_h; + if(radeon_is_interlace()) besr.v_inc *= 2; + h_inc = (src_w << 12) / dest_w; + + { + unsigned int ecp_div; + ecp_div = (INPLL(VCLK_ECP_CNTL) >> 8) & 3; + h_inc <<= ecp_div; + } + + + step_by = 1; + while(h_inc >= (2 << 12)) { + step_by++; + h_inc >>= 1; + } + + /* keep everything in 16.16 */ + besr.base_addr = INREG(DISPLAY_BASE_ADDR); + config->offsets[0] = 0; + for(i=1;i<besr.vid_nbufs;i++) + config->offsets[i] = config->offsets[i-1]+config->frame_size; + if(is_420 || is_410 || is_400) + { + uint32_t d1line,d2line,d3line; + d1line = top*pitch; + if(is_420) + { + d2line = src_h*pitch+(d1line>>2); + d3line = d2line+((src_h*pitch)>>2); + } + else + if(is_410) + { + d2line = src_h*pitch+(d1line>>4); + d3line = d2line+((src_h*pitch)>>4); + } + else + { + d2line = 0; + d3line = 0; + } + d1line += (left >> 16) & ~15; + if(is_420) + { + d2line += (left >> 17) & ~15; + d3line += (left >> 17) & ~15; + } + else + if(is_410) + { + d2line += (left >> 18) & ~15; + d3line += (left >> 18) & ~15; + } + config->offset.y = d1line & VIF_BUF0_BASE_ADRS_MASK; + if(is_400) + { + config->offset.v = 0; + config->offset.u = 0; + } + else + { + config->offset.v = d2line & VIF_BUF1_BASE_ADRS_MASK; + config->offset.u = d3line & VIF_BUF2_BASE_ADRS_MASK; + } + for(i=0;i<besr.vid_nbufs;i++) + { + besr.vid_buf_base_adrs_y[i]=((radeon_overlay_off+config->offsets[i]+config->offset.y)&VIF_BUF0_BASE_ADRS_MASK); + if(is_400) + { + besr.vid_buf_base_adrs_v[i]=0; + besr.vid_buf_base_adrs_u[i]=0; + } + else + { + if (besr.fourcc == IMGFMT_I420 || besr.fourcc == IMGFMT_IYUV) + { + besr.vid_buf_base_adrs_u[i]=((radeon_overlay_off+config->offsets[i]+config->offset.v)&VIF_BUF1_BASE_ADRS_MASK)|VIF_BUF1_PITCH_SEL; + besr.vid_buf_base_adrs_v[i]=((radeon_overlay_off+config->offsets[i]+config->offset.u)&VIF_BUF2_BASE_ADRS_MASK)|VIF_BUF2_PITCH_SEL; + } + else + { + besr.vid_buf_base_adrs_v[i]=((radeon_overlay_off+config->offsets[i]+config->offset.v)&VIF_BUF1_BASE_ADRS_MASK)|VIF_BUF1_PITCH_SEL; + besr.vid_buf_base_adrs_u[i]=((radeon_overlay_off+config->offsets[i]+config->offset.u)&VIF_BUF2_BASE_ADRS_MASK)|VIF_BUF2_PITCH_SEL; + } + } + } + config->offset.y = ((besr.vid_buf_base_adrs_y[0])&VIF_BUF0_BASE_ADRS_MASK) - radeon_overlay_off; + if(is_400) + { + config->offset.v = 0; + config->offset.u = 0; + } + else + { + config->offset.v = ((besr.vid_buf_base_adrs_v[0])&VIF_BUF1_BASE_ADRS_MASK) - radeon_overlay_off; + config->offset.u = ((besr.vid_buf_base_adrs_u[0])&VIF_BUF2_BASE_ADRS_MASK) - radeon_overlay_off; + } + } + else + { + config->offset.y = config->offset.u = config->offset.v = ((left & ~7) << 1)&VIF_BUF0_BASE_ADRS_MASK; + for(i=0;i<besr.vid_nbufs;i++) + { + besr.vid_buf_base_adrs_y[i] = + besr.vid_buf_base_adrs_u[i] = + besr.vid_buf_base_adrs_v[i] = radeon_overlay_off + config->offsets[i] + config->offset.y; + } + } + + tmp = (left & 0x0003ffff) + 0x00028000 + (h_inc << 3); + besr.p1_h_accum_init = ((tmp << 4) & 0x000f8000) | + ((tmp << 12) & 0xf0000000); + + tmp = ((left >> 1) & 0x0001ffff) + 0x00028000 + (h_inc << 2); + besr.p23_h_accum_init = ((tmp << 4) & 0x000f8000) | + ((tmp << 12) & 0x70000000); + tmp = (top & 0x0000ffff) + 0x00018000; + besr.p1_v_accum_init = ((tmp << 4) & OV0_P1_V_ACCUM_INIT_MASK) + |(OV0_P1_MAX_LN_IN_PER_LN_OUT & 1); + + tmp = ((top >> 1) & 0x0000ffff) + 0x00018000; + besr.p23_v_accum_init = (is_420||is_410) ? + ((tmp << 4) & OV0_P23_V_ACCUM_INIT_MASK) + |(OV0_P23_MAX_LN_IN_PER_LN_OUT & 1) : 0; + + leftUV = (left >> (is_410?18:17)) & 15; + left = (left >> 16) & 15; + if(is_rgb && !is_rgb32) h_inc<<=1; + if(is_rgb32) + besr.h_inc = (h_inc >> 1) | ((h_inc >> 1) << 16); + else + if(is_410) + besr.h_inc = h_inc | ((h_inc >> 2) << 16); + else + besr.h_inc = h_inc | ((h_inc >> 1) << 16); + besr.step_by = step_by | (step_by << 8); + besr.y_x_start = (config->dest.x+X_ADJUST) | (config->dest.y << 16); + besr.y_x_end = (config->dest.x + dest_w+X_ADJUST) | ((config->dest.y + dest_h) << 16); + besr.p1_blank_lines_at_top = P1_BLNK_LN_AT_TOP_M1_MASK|((src_h-1)<<16); + if(is_420 || is_410) + { + src_h = (src_h + 1) >> (is_410?2:1); + besr.p23_blank_lines_at_top = P23_BLNK_LN_AT_TOP_M1_MASK|((src_h-1)<<16); + } + else besr.p23_blank_lines_at_top = 0; + besr.vid_buf_pitch0_value = pitch; + besr.vid_buf_pitch1_value = is_410 ? pitch>>2 : is_420 ? pitch>>1 : pitch; + besr.p1_x_start_end = (src_w+left-1)|(left<<16); + if (is_410||is_420) src_w>>=is_410?2:1; + if(is_400) + { + besr.p2_x_start_end = 0; + besr.p3_x_start_end = 0; + } + else + { + besr.p2_x_start_end = (src_w+left-1)|(leftUV<<16); + besr.p3_x_start_end = besr.p2_x_start_end; + } + + return 0; +} + +static void radeon_compute_framesize(vidix_playback_t *info) +{ + unsigned pitch,awidth,dbpp; + pitch = radeon_query_pitch(info->fourcc,&info->src.pitch); + dbpp = radeon_vid_get_dbpp(); + switch(info->fourcc) + { + case IMGFMT_I420: + case IMGFMT_YV12: + case IMGFMT_IYUV: + awidth = (info->src.w + (pitch-1)) & ~(pitch-1); + info->frame_size = awidth*(info->src.h+info->src.h/2); + break; + case IMGFMT_Y800: + case IMGFMT_Y8: + awidth = (info->src.w + (pitch-1)) & ~(pitch-1); + info->frame_size = awidth*info->src.h; + break; + case IMGFMT_IF09: + case IMGFMT_YVU9: + awidth = (info->src.w + (pitch-1)) & ~(pitch-1); + info->frame_size = awidth*(info->src.h+info->src.h/8); + break; + case IMGFMT_RGB32: + case IMGFMT_BGR32: + awidth = (info->src.w*4 + (pitch-1)) & ~(pitch-1); + info->frame_size = awidth*info->src.h; + break; + /* YUY2 YVYU, RGB15, RGB16 */ + default: + awidth = (info->src.w*2 + (pitch-1)) & ~(pitch-1); + info->frame_size = awidth*info->src.h; + break; + } +} + +int vixConfigPlayback(vidix_playback_t *info) +{ + unsigned rgb_size,nfr; + if(!is_supported_fourcc(info->fourcc)) return ENOSYS; + if(info->num_frames>VID_PLAY_MAXFRAMES) info->num_frames=VID_PLAY_MAXFRAMES; + if(info->num_frames==1) besr.double_buff=0; + else besr.double_buff=1; + radeon_compute_framesize(info); + + rgb_size = radeon_get_xres()*radeon_get_yres()*((radeon_vid_get_dbpp()+7)/8); + nfr = info->num_frames; + for(;nfr>0; nfr--) + { + radeon_overlay_off = radeon_ram_size - info->frame_size*nfr; +#ifdef HAVE_X11 + radeon_overlay_off -= firegl_shift; +#endif + radeon_overlay_off &= 0xffff0000; + if(radeon_overlay_off >= (int)rgb_size ) break; + } + if(nfr <= 3) + { + nfr = info->num_frames; + for(;nfr>0; nfr--) + { + radeon_overlay_off = radeon_ram_size - info->frame_size*nfr; +#ifdef HAVE_X11 + radeon_overlay_off -= firegl_shift; +#endif + radeon_overlay_off &= 0xffff0000; + if(radeon_overlay_off > 0) break; + } + } + if(nfr <= 0) return EINVAL; + info->num_frames = nfr; + besr.vid_nbufs = info->num_frames; + info->dga_addr = (char *)radeon_mem_base + radeon_overlay_off; + radeon_vid_init_video(info); + return 0; +} + +int vixPlaybackOn( void ) +{ + radeon_vid_display_video(); + return 0; +} + +int vixPlaybackOff( void ) +{ + radeon_vid_stop_video(); + return 0; +} + +int vixPlaybackFrameSelect(unsigned frame) +{ + uint32_t off[6]; + int prev_frame= (frame-1+besr.vid_nbufs) % besr.vid_nbufs; + /* + buf3-5 always should point onto second buffer for better + deinterlacing and TV-in + */ + if(!besr.double_buff) return 0; + if(frame > besr.vid_nbufs) frame = besr.vid_nbufs-1; + if(prev_frame > (int)besr.vid_nbufs) prev_frame = besr.vid_nbufs-1; + off[0] = besr.vid_buf_base_adrs_y[frame]; + off[1] = besr.vid_buf_base_adrs_v[frame]; + off[2] = besr.vid_buf_base_adrs_u[frame]; + off[3] = besr.vid_buf_base_adrs_y[prev_frame]; + off[4] = besr.vid_buf_base_adrs_v[prev_frame]; + off[5] = besr.vid_buf_base_adrs_u[prev_frame]; + radeon_fifo_wait(8); + OUTREG(OV0_REG_LOAD_CNTL, REG_LD_CTL_LOCK); + radeon_engine_idle(); + while(!(INREG(OV0_REG_LOAD_CNTL)®_LD_CTL_LOCK_READBACK)); + OUTREG(OV0_VID_BUF0_BASE_ADRS, off[0]); + OUTREG(OV0_VID_BUF1_BASE_ADRS, off[1]); + OUTREG(OV0_VID_BUF2_BASE_ADRS, off[2]); + OUTREG(OV0_VID_BUF3_BASE_ADRS, off[3]); + OUTREG(OV0_VID_BUF4_BASE_ADRS, off[4]); + OUTREG(OV0_VID_BUF5_BASE_ADRS, off[5]); + OUTREG(OV0_REG_LOAD_CNTL, 0); + if(besr.vid_nbufs == 2) radeon_wait_vsync(); + if(__verbose > 1) radeon_vid_dump_regs(); + return 0; +} + +vidix_video_eq_t equal = +{ + VEQ_CAP_BRIGHTNESS | VEQ_CAP_SATURATION +#ifndef RAGE128 + | VEQ_CAP_CONTRAST | VEQ_CAP_HUE | VEQ_CAP_RGB_INTENSITY +#endif + , + 0, 0, 0, 0, 0, 0, 0, 0 }; + +int vixPlaybackGetEq( vidix_video_eq_t * eq) +{ + memcpy(eq,&equal,sizeof(vidix_video_eq_t)); + return 0; +} + +#ifndef RAGE128 +#define RTFSaturation(a) (1.0 + ((a)*1.0)/1000.0) +#define RTFBrightness(a) (((a)*1.0)/2000.0) +#define RTFIntensity(a) (((a)*1.0)/2000.0) +#define RTFContrast(a) (1.0 + ((a)*1.0)/1000.0) +#define RTFHue(a) (((a)*3.1416)/1000.0) +#define RTFCheckParam(a) {if((a)<-1000) (a)=-1000; if((a)>1000) (a)=1000;} +#endif + +int vixPlaybackSetEq( const vidix_video_eq_t * eq) +{ +#ifdef RAGE128 + int br,sat; +#else + int itu_space; +#endif + if(eq->cap & VEQ_CAP_BRIGHTNESS) equal.brightness = eq->brightness; + if(eq->cap & VEQ_CAP_CONTRAST) equal.contrast = eq->contrast; + if(eq->cap & VEQ_CAP_SATURATION) equal.saturation = eq->saturation; + if(eq->cap & VEQ_CAP_HUE) equal.hue = eq->hue; + if(eq->cap & VEQ_CAP_RGB_INTENSITY) + { + equal.red_intensity = eq->red_intensity; + equal.green_intensity = eq->green_intensity; + equal.blue_intensity = eq->blue_intensity; + } + equal.flags = eq->flags; +#ifdef RAGE128 + br = equal.brightness * 64 / 1000; + if(br < -64) br = -64; if(br > 63) br = 63; + sat = (equal.saturation + 1000) * 16 / 1000; + if(sat < 0) sat = 0; if(sat > 31) sat = 31; + OUTREG(OV0_COLOUR_CNTL, (br & 0x7f) | (sat << 8) | (sat << 16)); +#else + itu_space = equal.flags == VEQ_FLG_ITU_R_BT_709 ? 1 : 0; + RTFCheckParam(equal.brightness); + RTFCheckParam(equal.saturation); + RTFCheckParam(equal.contrast); + RTFCheckParam(equal.hue); + RTFCheckParam(equal.red_intensity); + RTFCheckParam(equal.green_intensity); + RTFCheckParam(equal.blue_intensity); + radeon_set_transform(RTFBrightness(equal.brightness), + RTFContrast(equal.contrast), + RTFSaturation(equal.saturation), + RTFHue(equal.hue), + RTFIntensity(equal.red_intensity), + RTFIntensity(equal.green_intensity), + RTFIntensity(equal.blue_intensity), + itu_space); +#endif + return 0; +} + +int vixPlaybackSetDeint( const vidix_deinterlace_t * info) +{ + unsigned sflg; + switch(info->flags) + { + default: + case CFG_NON_INTERLACED: + besr.deinterlace_on = 0; + break; + case CFG_EVEN_ODD_INTERLACING: + case CFG_INTERLACED: + besr.deinterlace_on = 1; + besr.deinterlace_pattern = 0x900AAAAA; + break; + case CFG_ODD_EVEN_INTERLACING: + besr.deinterlace_on = 1; + besr.deinterlace_pattern = 0x00055555; + break; + case CFG_UNIQUE_INTERLACING: + besr.deinterlace_on = 1; + besr.deinterlace_pattern = info->deinterlace_pattern; + break; + } + OUTREG(OV0_REG_LOAD_CNTL, REG_LD_CTL_LOCK); + radeon_engine_idle(); + while(!(INREG(OV0_REG_LOAD_CNTL)®_LD_CTL_LOCK_READBACK)); + radeon_fifo_wait(15); + sflg = INREG(OV0_SCALE_CNTL); + if(besr.deinterlace_on) + { + OUTREG(OV0_SCALE_CNTL,sflg | SCALER_ADAPTIVE_DEINT); + OUTREG(OV0_DEINTERLACE_PATTERN,besr.deinterlace_pattern); + } + else OUTREG(OV0_SCALE_CNTL,sflg & (~SCALER_ADAPTIVE_DEINT)); + OUTREG(OV0_REG_LOAD_CNTL, 0); + return 0; +} + +int vixPlaybackGetDeint( vidix_deinterlace_t * info) +{ + if(!besr.deinterlace_on) info->flags = CFG_NON_INTERLACED; + else + { + info->flags = CFG_UNIQUE_INTERLACING; + info->deinterlace_pattern = besr.deinterlace_pattern; + } + return 0; +} + + +/* Graphic keys */ +static vidix_grkey_t radeon_grkey; + +static void set_gr_key( void ) +{ + if(radeon_grkey.ckey.op == CKEY_TRUE) + { + int dbpp=radeon_vid_get_dbpp(); + besr.ckey_on=1; + + switch(dbpp) + { + case 15: +#ifdef RADEON + if(RadeonFamily > 100) + besr.graphics_key_clr= + ((radeon_grkey.ckey.blue &0xF8)) + | ((radeon_grkey.ckey.green&0xF8)<<8) + | ((radeon_grkey.ckey.red &0xF8)<<16); + else +#endif + besr.graphics_key_clr= + ((radeon_grkey.ckey.blue &0xF8)>>3) + | ((radeon_grkey.ckey.green&0xF8)<<2) + | ((radeon_grkey.ckey.red &0xF8)<<7); + break; + case 16: +#ifdef RADEON + /* This test may be too general/specific */ + if(RadeonFamily > 100) + besr.graphics_key_clr= + ((radeon_grkey.ckey.blue &0xF8)) + | ((radeon_grkey.ckey.green&0xFC)<<8) + | ((radeon_grkey.ckey.red &0xF8)<<16); + else +#endif + besr.graphics_key_clr= + ((radeon_grkey.ckey.blue &0xF8)>>3) + | ((radeon_grkey.ckey.green&0xFC)<<3) + | ((radeon_grkey.ckey.red &0xF8)<<8); + break; + case 24: + besr.graphics_key_clr= + ((radeon_grkey.ckey.blue &0xFF)) + | ((radeon_grkey.ckey.green&0xFF)<<8) + | ((radeon_grkey.ckey.red &0xFF)<<16); + break; + case 32: + besr.graphics_key_clr= + ((radeon_grkey.ckey.blue &0xFF)) + | ((radeon_grkey.ckey.green&0xFF)<<8) + | ((radeon_grkey.ckey.red &0xFF)<<16); + break; + default: + besr.ckey_on=0; + besr.graphics_key_msk=0; + besr.graphics_key_clr=0; + } +#ifdef RAGE128 + besr.graphics_key_msk=(1<<dbpp)-1; + besr.ckey_cntl = VIDEO_KEY_FN_TRUE|GRAPHIC_KEY_FN_NE|CMP_MIX_AND; +#else + besr.graphics_key_msk=besr.graphics_key_clr; + besr.ckey_cntl = VIDEO_KEY_FN_TRUE|CMP_MIX_AND|GRAPHIC_KEY_FN_EQ; +#endif + } + else + { + besr.ckey_on=0; + besr.graphics_key_msk=0; + besr.graphics_key_clr=0; + besr.ckey_cntl = VIDEO_KEY_FN_TRUE|GRAPHIC_KEY_FN_TRUE|CMP_MIX_AND; + } + radeon_fifo_wait(3); + OUTREG(OV0_GRAPHICS_KEY_MSK, besr.graphics_key_msk); + OUTREG(OV0_GRAPHICS_KEY_CLR, besr.graphics_key_clr); + OUTREG(OV0_KEY_CNTL,besr.ckey_cntl); +} + +int vixGetGrKeys(vidix_grkey_t *grkey) +{ + memcpy(grkey, &radeon_grkey, sizeof(vidix_grkey_t)); + return(0); +} + +int vixSetGrKeys(const vidix_grkey_t *grkey) +{ + memcpy(&radeon_grkey, grkey, sizeof(vidix_grkey_t)); + set_gr_key(); + return(0); +}