summaryrefslogtreecommitdiffstats
path: root/vidix/drivers/radeon_vid.c
diff options
context:
space:
mode:
Diffstat (limited to 'vidix/drivers/radeon_vid.c')
-rw-r--r--vidix/drivers/radeon_vid.c1043
1 files changed, 1043 insertions, 0 deletions
diff --git a/vidix/drivers/radeon_vid.c b/vidix/drivers/radeon_vid.c
new file mode 100644
index 0000000000..96e81a654e
--- /dev/null
+++ b/vidix/drivers/radeon_vid.c
@@ -0,0 +1,1043 @@
+/*
+ radeon_vid - VIDIX based video driver for Radeon and Rage128 chips
+*/
+
+#include <linux/pci_ids.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+#include <stdint.h>
+#include "../vidix.h"
+#include "../fourcc.h"
+#include "../../libdha/libdha.h"
+#include "radeon.h"
+
+#ifdef RAGE128
+#define RADEON_MSG "Rage128_vid:"
+#define X_ADJUST 0
+#else
+#define RADEON_MSG "Radeon_vid:"
+#define X_ADJUST 8
+#ifndef RADEON
+#define RADEON
+#endif
+#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_buf0_base_adrs;
+ /* These ones are for auto flip: maybe in the future */
+ uint32_t vid_buf1_base_adrs;
+ uint32_t vid_buf2_base_adrs;
+ uint32_t vid_buf3_base_adrs;
+ uint32_t vid_buf4_base_adrs;
+ uint32_t vid_buf5_base_adrs;
+
+ 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;
+
+ int deinterlace_on;
+ uint32_t deinterlace_pattern;
+
+} bes_registers_t;
+
+typedef struct video_registers_s
+{
+#ifdef DEBUG
+ const char * sname;
+#endif
+ uint32_t name;
+ uint32_t value;
+}video_registers_t;
+
+static bes_registers_t besr;
+#ifndef RAGE128
+static int IsR200=0;
+#endif
+#ifdef DEBUG
+#define DECLARE_VREG(name) { #name, name, 0 }
+#else
+#define DECLARE_VREG(name) { name, 0 }
+#endif
+#ifdef DEBUG
+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)
+};
+#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;
+
+#define INREG8(addr) INPORT8((uint32_t)(radeon_mmio_base)+addr)
+#define OUTREG8(addr,val) OUTPORT8((uint32_t)(radeon_mmio_base)+addr,val)
+#define INREG(addr) INPORT((uint32_t)(radeon_mmio_base)+addr)
+#define OUTREG(addr,val) OUTPORT((uint32_t)(radeon_mmio_base)+addr,val)
+#define OUTREGP(addr,val,mask) \
+ do { \
+ unsigned int _tmp = INREG(addr); \
+ _tmp &= (mask); \
+ _tmp |= (val); \
+ OUTREG(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 __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 __inline__ void _radeon_fifo_wait (unsigned entries)
+{
+ int i;
+
+ for (i=0; i<2000000; i++)
+ if ((INREG(RBBM_STATUS) & 0x7f) >= entries)
+ return;
+}
+
+
+static __inline__ void _radeon_engine_idle ( void )
+{
+ int i;
+
+ /* ensure FIFO is empty before waiting for idle */
+ _radeon_fifo_wait (64);
+
+ for (i=0; i<2000000; i++) {
+ if (((INREG(RBBM_STATUS) & GUI_ACTIVE)) == 0) {
+ radeon_engine_flush ();
+ return;
+ }
+ }
+}
+
+#define radeon_engine_idle() _radeon_engine_idle()
+#define radeon_fifo_wait(entries) _radeon_fifo_wait(entries)
+
+
+#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 *
+ * ref - index to the table of refernce transforms *
+ * Outputs: NONE *
+ ****************************************************************************/
+
+static void radeon_set_transform(float bright, float cont, float sat,
+ float hue, unsigned ref)
+{
+ float OvHueSin, OvHueCos;
+ float CAdjLuma, CAdjOff;
+ 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;
+
+ 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 = CAdjOff -
+ OvLuma * Loff - (OvRCb + OvRCr) * Coff;
+ OvGOff = CAdjOff -
+ OvLuma * Loff - (OvGCb + OvGCr) * Coff;
+ OvBOff = 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;
+ if(!IsR200)
+ {
+ 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;
+ }
+ 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;
+ }
+
+ 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(!IsR200){
+ 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 brihgtness 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;
+}
+
+
+unsigned vixGetVersion( void ) { return VIDIX_VERSION; }
+
+struct ati_card_id_s
+{
+ const unsigned id;
+ const char name[17];
+};
+
+const struct ati_card_id_s 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 */
+ { PCI_DEVICE_ID_ATI_Rage128_PA, "R128Pro PA" },
+ { PCI_DEVICE_ID_ATI_Rage128_PB, "R128Pro PB" },
+ { PCI_DEVICE_ID_ATI_Rage128_PC, "R128Pro PC" },
+ { PCI_DEVICE_ID_ATI_Rage128_PD, "R128Pro PD" },
+ { PCI_DEVICE_ID_ATI_Rage128_PE, "R128Pro PE" },
+ { PCI_DEVICE_ID_ATI_RAGE128_PF, "R128Pro PF" },
+/* Rage128 Pro VR */
+ { PCI_DEVICE_ID_ATI_RAGE128_PG, "R128Pro PG" },
+ { PCI_DEVICE_ID_ATI_RAGE128_PH, "R128Pro PH" },
+ { PCI_DEVICE_ID_ATI_RAGE128_PI, "R128Pro PI" },
+ { PCI_DEVICE_ID_ATI_RAGE128_PJ, "R128Pro PJ" },
+ { PCI_DEVICE_ID_ATI_RAGE128_PK, "R128Pro PK" },
+ { PCI_DEVICE_ID_ATI_RAGE128_PL, "R128Pro PL" },
+ { PCI_DEVICE_ID_ATI_RAGE128_PM, "R128Pro PM" },
+ { PCI_DEVICE_ID_ATI_RAGE128_PN, "R128Pro PN" },
+ { PCI_DEVICE_ID_ATI_RAGE128_PO, "R128Pro PO" },
+ { PCI_DEVICE_ID_ATI_RAGE128_PP, "R128Pro PP" },
+ { PCI_DEVICE_ID_ATI_RAGE128_PQ, "R128Pro PQ" },
+ { PCI_DEVICE_ID_ATI_RAGE128_PR, "R128Pro PR" },
+ { PCI_DEVICE_ID_ATI_RAGE128_TR, "R128Pro TR" },
+ { PCI_DEVICE_ID_ATI_RAGE128_PS, "R128Pro PS" },
+ { PCI_DEVICE_ID_ATI_RAGE128_PT, "R128Pro PT" },
+ { PCI_DEVICE_ID_ATI_RAGE128_PU, "R128Pro PU" },
+ { PCI_DEVICE_ID_ATI_RAGE128_PV, "R128Pro PV" },
+ { PCI_DEVICE_ID_ATI_RAGE128_PW, "R128Pro PW" },
+ { PCI_DEVICE_ID_ATI_RAGE128_PX, "R128Pro PX" },
+/* Rage128 GL */
+ { PCI_DEVICE_ID_ATI_RAGE128_RE, "R128 RE" },
+ { PCI_DEVICE_ID_ATI_RAGE128_RF, "R128 RF" },
+ { PCI_DEVICE_ID_ATI_RAGE128_RG, "R128 RG" },
+ { PCI_DEVICE_ID_ATI_RAGE128_RH, "R128 RH" },
+ { PCI_DEVICE_ID_ATI_RAGE128_RI, "R128 RI" },
+/* Rage128 VR */
+ { PCI_DEVICE_ID_ATI_RAGE128_RK, "R128 RK" },
+ { PCI_DEVICE_ID_ATI_RAGE128_RL, "R128 RL" },
+ { PCI_DEVICE_ID_ATI_RAGE128_RM, "R128 RM" },
+ { PCI_DEVICE_ID_ATI_RAGE128_RN, "R128 RN" },
+ { PCI_DEVICE_ID_ATI_RAGE128_RO, "R128 RO" },
+/* Rage128 M3 */
+ { PCI_DEVICE_ID_ATI_RAGE128_LE, "R128 M3 LE" },
+ { PCI_DEVICE_ID_ATI_RAGE128_LF, "R128 M3 LF" },
+/* Rage128 Pro Ultra */
+ { PCI_DEVICE_ID_ATI_RAGE128_U1, "R128Pro U1" },
+ { PCI_DEVICE_ID_ATI_RAGE128_U2, "R128Pro U2" },
+ { PCI_DEVICE_ID_ATI_RAGE128_U3, "R128Pro U3" }
+#else
+/* Radeons (indeed: Rage 256 Pro ;) */
+ { PCI_DEVICE_ID_RADEON_QD, "Radeon QD " },
+ { PCI_DEVICE_ID_RADEON_QE, "Radeon QE " },
+ { PCI_DEVICE_ID_RADEON_QF, "Radeon QF " },
+ { PCI_DEVICE_ID_RADEON_QG, "Radeon QG " },
+ { PCI_DEVICE_ID_RADEON_QY, "Radeon VE QY " },
+ { PCI_DEVICE_ID_RADEON_QZ, "Radeon VE QZ " },
+ { PCI_DEVICE_ID_RADEON_LY, "Radeon M6 LY " },
+ { PCI_DEVICE_ID_RADEON_LZ, "Radeon M6 LZ " },
+ { PCI_DEVICE_ID_RADEON_LW, "Radeon M7 LW " },
+ { PCI_DEVICE_ID_R200_QL, "Radeon2 8500 QL " },
+ { PCI_DEVICE_ID_R200_BB, "Radeon2 8500 AIW" },
+ { PCI_DEVICE_ID_RV200_QW, "Radeon2 7500 QW " }
+#endif
+};
+
+static int find_chip(unsigned chip_id)
+{
+ unsigned i;
+ for(i = 0;i < sizeof(ati_card_ids)/sizeof(struct ati_card_id_s);i++)
+ {
+ if(chip_id == ati_card_ids[i].id) return i;
+ }
+ return -1;
+}
+
+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
+ TYPE_OUTPUT | TYPE_FX,
+ 0,
+ 1,
+ 0,
+ 0,
+ 1024,
+ 768,
+ 4,
+ 4,
+ -1,
+ FLAG_UPSCALER | FLAG_DOWNSCALER,
+ 1002,
+ 0,
+ { 0, 0, 0, 0}
+};
+
+
+int vixProbe( int verbose )
+{
+ pciinfo_t lst[MAX_PCI_DEVICES];
+ unsigned i,num_pci;
+ int err;
+ err = pci_scan(lst,&num_pci);
+ if(err)
+ {
+ printf(RADEON_MSG" Error occured during pci scan: %s\n",strerror(err));
+ return err;
+ }
+ else
+ {
+ err = ENXIO;
+ for(i=0;i<num_pci;i++)
+ {
+ if(lst[i].vendor == PCI_VENDOR_ID_ATI)
+ {
+ int idx;
+ idx = find_chip(lst[i].device);
+ if(idx == -1) continue;
+ printf(RADEON_MSG" Found chip: %s\n",ati_card_ids[idx].name);
+#ifndef RAGE128
+ if(ati_card_ids[idx].id == PCI_DEVICE_ID_R200_QL ||
+ ati_card_ids[idx].id == PCI_DEVICE_ID_R200_BB ||
+ ati_card_ids[idx].id == PCI_DEVICE_ID_RV200_QW) IsR200 = 1;
+#endif
+ def_cap.device_id = ati_card_ids[idx].id;
+ 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;
+}
+
+int vixInit( void )
+{
+ if(!probed) return EINTR;
+ if((radeon_mmio_base = map_phys_mem(pci_info.base2,0x7FFF))==(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;
+ if((radeon_mem_base = map_phys_mem(pci_info.base0,radeon_ram_size))==(void *)-1) return ENOMEM;
+ radeon_vid_make_default();
+ printf(RADEON_MSG" Video memory = %uMb\n",radeon_ram_size/0x100000);
+ return 0;
+}
+
+void vixDestroy( void )
+{
+ unmap_phys_mem(radeon_mem_base,radeon_ram_size);
+ unmap_phys_mem(radeon_mmio_base,0x7FFF);
+}
+
+int vixGetCapability(vidix_capability_t *to)
+{
+ memcpy(to,&def_cap,sizeof(vidix_capability_t));
+ return 0;
+}
+
+uint32_t supported_fourcc[] =
+{
+ IMGFMT_YV12, IMGFMT_I420, IMGFMT_IYUV,
+ IMGFMT_UYVY, IMGFMT_YUY2
+};
+
+__inline__ static int is_supported_fourcc(uint32_t fourcc)
+{
+ unsigned 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;
+ return 0;
+ }
+ return ENOSYS;
+}
+
+#ifdef DEBUG
+static void radeon_vid_dump_regs( void )
+{
+ size_t i;
+ printk(RVID_MSG"*** Begin of OV0 registers dump ***\n");
+ for(i=0;i<sizeof(vregs)/sizeof(video_registers_t);i++)
+ printk(RVID_MSG"%s = %08X\n",vregs[i].sname,INREG(vregs[i].name));
+ printk(RVID_MSG"*** End of OV0 registers dump ***\n");
+}
+#endif
+
+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);
+ OUTREG(OV0_KEY_CNTL, GRAPHIC_KEY_FN_NE);
+ OUTREG(OV0_TEST, 0);
+}
+
+static void radeon_vid_display_video( void )
+{
+ int bes_flags;
+ radeon_fifo_wait(2);
+ OUTREG(OV0_REG_LOAD_CNTL, REG_LD_CTL_LOCK);
+ radeon_engine_idle();
+ while(!(INREG(OV0_REG_LOAD_CNTL)&REG_LD_CTL_LOCK_READBACK));
+ radeon_fifo_wait(15);
+ OUTREG(OV0_AUTO_FLIP_CNTL,OV0_AUTO_FLIP_CNTL_SOFT_BUF_ODD);
+ OUTREG(OV0_AUTO_FLIP_CNTL,(INREG(OV0_AUTO_FLIP_CNTL)^OV0_AUTO_FLIP_CNTL_SOFT_EOF_TOGGLE));
+ OUTREG(OV0_AUTO_FLIP_CNTL,(INREG(OV0_AUTO_FLIP_CNTL)^OV0_AUTO_FLIP_CNTL_SOFT_EOF_TOGGLE));
+
+ OUTREG(OV0_DEINTERLACE_PATTERN,besr.deinterlace_pattern);
+#ifdef RAGE128
+ OUTREG(OV0_COLOUR_CNTL, (besr.brightness & 0x7f) |
+ (besr.saturation << 8) |
+ (besr.saturation << 16));
+#endif
+ radeon_fifo_wait(2);
+ if(besr.ckey_on)
+ {
+ OUTREG(OV0_GRAPHICS_KEY_MSK, besr.graphics_key_msk);
+ OUTREG(OV0_GRAPHICS_KEY_CLR, besr.graphics_key_clr);
+ OUTREG(OV0_KEY_CNTL,GRAPHIC_KEY_FN_EQ|VIDEO_KEY_FN_FALSE|CMP_MIX_OR);
+ }
+ else
+ {
+ OUTREG(OV0_GRAPHICS_KEY_MSK, 0ULL);
+ OUTREG(OV0_GRAPHICS_KEY_CLR, 0ULL);
+ OUTREG(OV0_KEY_CNTL,GRAPHIC_KEY_FN_NE);
+ }
+
+ 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_buf0_base_adrs);
+ OUTREG(OV0_VID_BUF1_BASE_ADRS, besr.vid_buf1_base_adrs);
+ OUTREG(OV0_VID_BUF2_BASE_ADRS, besr.vid_buf2_base_adrs);
+ radeon_fifo_wait(9);
+ OUTREG(OV0_VID_BUF3_BASE_ADRS, besr.vid_buf3_base_adrs);
+ OUTREG(OV0_VID_BUF4_BASE_ADRS, besr.vid_buf4_base_adrs);
+ OUTREG(OV0_VID_BUF5_BASE_ADRS, besr.vid_buf5_base_adrs);
+ 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);
+
+ bes_flags = SCALER_ENABLE |
+ SCALER_SMART_SWITCH |
+#ifdef RADEON
+ SCALER_HORZ_PICK_NEAREST;
+#else
+ SCALER_Y2R_TEMP |
+ SCALER_PIX_EXPAND;
+#endif
+ 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:2:0 */
+ case IMGFMT_IYUV:
+ case IMGFMT_I420:
+ case IMGFMT_YV12: bes_flags |= SCALER_SOURCE_YUV12;
+ break;
+ /* 4:2:2 */
+ 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);
+#ifdef DEBUG
+ radeon_vid_dump_regs();
+#endif
+}
+
+static int radeon_vid_init_video( vidix_playback_t *config )
+{
+ uint32_t tmp,src_w,src_h,dest_w,dest_h,pitch,h_inc,step_by,left,leftUV,top;
+ int is_420;
+ 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_420 = 0;
+ if(config->fourcc == IMGFMT_YV12 ||
+ config->fourcc == IMGFMT_I420 ||
+ config->fourcc == IMGFMT_IYUV) is_420 = 1;
+ switch(config->fourcc)
+ {
+ /* 4:2:0 */
+ case IMGFMT_IYUV:
+ case IMGFMT_YV12:
+ case IMGFMT_I420: pitch = (src_w + 31) & ~31;
+ config->dest.pitch.y =
+ config->dest.pitch.u =
+ config->dest.pitch.v = 32;
+ break;
+ /* 4:2:2 */
+ default:
+ case IMGFMT_UYVY:
+ case IMGFMT_YUY2:
+ pitch = ((src_w*2) + 15) & ~15;
+ config->dest.pitch.y =
+ config->dest.pitch.u =
+ config->dest.pitch.v = 16;
+ break;
+ }
+ dest_w = config->dest.w;
+ dest_h = config->dest.h;
+ if(radeon_is_dbl_scan()) dest_h *= 2;
+ else
+ if(radeon_is_interlace()) dest_h /= 2;
+ besr.dest_bpp = radeon_vid_get_dbpp();
+ besr.fourcc = config->fourcc;
+ besr.v_inc = (src_h << 20) / dest_h;
+ h_inc = (src_w << 12) / dest_w;
+ step_by = 1;
+
+ while(h_inc >= (2 << 12)) {
+ step_by++;
+ h_inc >>= 1;
+ }
+
+ /* keep everything in 16.16 */
+ besr.base_addr = (uint32_t)radeon_mem_base;
+ if(is_420)
+ {
+ uint32_t d1line,d2line,d3line;
+ d1line = top*pitch;
+ d2line = src_h*pitch+(d1line>>1);
+ d3line = d2line+((src_h*pitch)>>2);
+ d1line += (left >> 16) & ~15;
+ d2line += (left >> 17) & ~15;
+ d3line += (left >> 17) & ~15;
+ config->offset.y = d1line & VIF_BUF0_BASE_ADRS_MASK;
+ config->offset.u = d2line & VIF_BUF1_BASE_ADRS_MASK;
+ config->offset.v = d3line & VIF_BUF2_BASE_ADRS_MASK;
+ besr.vid_buf0_base_adrs=(radeon_overlay_off+config->offset.y);
+ besr.vid_buf1_base_adrs=(radeon_overlay_off+config->offset.u)|VIF_BUF1_PITCH_SEL;
+ besr.vid_buf2_base_adrs=(radeon_overlay_off+config->offset.v)|VIF_BUF2_PITCH_SEL;
+ if(besr.fourcc == IMGFMT_I420 || besr.fourcc == IMGFMT_IYUV)
+ {
+ uint32_t tmp;
+ tmp = besr.vid_buf1_base_adrs;
+ besr.vid_buf1_base_adrs = besr.vid_buf2_base_adrs;
+ besr.vid_buf2_base_adrs = tmp;
+ tmp = config->offset.u;
+ config->offset.u = config->offset.v;
+ config->offset.v = tmp;
+ }
+ }
+ else
+ {
+ besr.vid_buf0_base_adrs = radeon_overlay_off;
+ config->offset.y = config->offset.u = config->offset.v = ((left & ~7) << 1)&VIF_BUF0_BASE_ADRS_MASK;
+ besr.vid_buf0_base_adrs += config->offset.y;
+ besr.vid_buf1_base_adrs = besr.vid_buf0_base_adrs;
+ besr.vid_buf2_base_adrs = besr.vid_buf0_base_adrs;
+ }
+ config->offsets[0] = 0;
+ config->offsets[1] = config->frame_size;
+ besr.vid_buf3_base_adrs = besr.vid_buf0_base_adrs+config->frame_size;
+ besr.vid_buf4_base_adrs = besr.vid_buf1_base_adrs+config->frame_size;
+ besr.vid_buf5_base_adrs = besr.vid_buf2_base_adrs+config->frame_size;
+
+ 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 ? ((tmp << 4) & OV0_P23_V_ACCUM_INIT_MASK)
+ |(OV0_P23_MAX_LN_IN_PER_LN_OUT & 1) : 0;
+
+ leftUV = (left >> 17) & 15;
+ left = (left >> 16) & 15;
+ 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)
+ {
+ src_h = (src_h + 1) >> 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_420 ? pitch>>1 : pitch;
+ besr.p1_x_start_end = (src_w+left-1)|(left<<16);
+ src_w>>=1;
+ besr.p2_x_start_end = (src_w+left-1)|(leftUV<<16);
+ besr.p3_x_start_end = besr.p2_x_start_end;
+ return 0;
+}
+
+int vixConfigPlayback(vidix_playback_t *info)
+{
+ if(!is_supported_fourcc(info->fourcc)) return ENOSYS;
+ if(info->num_frames>2) info->num_frames=2;
+ radeon_overlay_off = radeon_ram_size - info->frame_size*info->num_frames;
+ radeon_overlay_off &= 0xffff0000;
+ if(radeon_overlay_off < 0) return EINVAL;
+ 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 vixPlaybackFrameSel(unsigned frame)
+{
+ uint32_t off0,off1,off2;
+/* if(!besr.double_buff) return; */
+ if(frame%2)
+ {
+ off0 = besr.vid_buf3_base_adrs;
+ off1 = besr.vid_buf4_base_adrs;
+ off2 = besr.vid_buf5_base_adrs;
+ }
+ else
+ {
+ off0 = besr.vid_buf0_base_adrs;
+ off1 = besr.vid_buf1_base_adrs;
+ off2 = besr.vid_buf2_base_adrs;
+ }
+ OUTREG(OV0_REG_LOAD_CNTL, REG_LD_CTL_LOCK);
+ while(!(INREG(OV0_REG_LOAD_CNTL)&REG_LD_CTL_LOCK_READBACK));
+ OUTREG(OV0_VID_BUF0_BASE_ADRS, off0);
+ OUTREG(OV0_VID_BUF1_BASE_ADRS, off1);
+ OUTREG(OV0_VID_BUF2_BASE_ADRS, off2);
+ OUTREG(OV0_REG_LOAD_CNTL, 0);
+ return 0;
+}
+
+vidix_video_eq_t equal = { 0, 0, 0, 0, 0, 0, 0 };
+
+int vixPlaybackGetEq( vidix_video_eq_t * eq)
+{
+ memcpy(eq,&equal,sizeof(vidix_video_eq_t));
+ return 0;
+}
+
+int vixPlaybackSetEq( const vidix_video_eq_t * eq)
+{
+#ifdef RAGE128
+ int br,sat;
+#endif
+ memcpy(&equal,eq,sizeof(vidix_video_eq_t));
+#ifdef RAGE128
+ br = equal.brightness * 64 / 1000;
+ sat = equal.saturation * 32 / 1000;
+ if(sat < 0) sat = 0;
+ OUTREG(OV0_COLOUR_CNTL, (br & 0x7f) | (sat << 8) | (sat << 16));
+#else
+ radeon_set_transform(equal.brightness,equal.contrast,
+ equal.saturation,equal.hue,0);
+#endif
+ return 0;
+}
+