summaryrefslogtreecommitdiff
path: root/src/video_out/vidix/drivers/radeon_vid.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/video_out/vidix/drivers/radeon_vid.c')
-rw-r--r--src/video_out/vidix/drivers/radeon_vid.c1610
1 files changed, 1610 insertions, 0 deletions
diff --git a/src/video_out/vidix/drivers/radeon_vid.c b/src/video_out/vidix/drivers/radeon_vid.c
new file mode 100644
index 000000000..91d961a73
--- /dev/null
+++ b/src/video_out/vidix/drivers/radeon_vid.c
@@ -0,0 +1,1610 @@
+/*
+ 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
+*/
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+#include <inttypes.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 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
+
+static int __verbose = 0;
+
+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 IsR200=0;
+#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)
+};
+
+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 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,(uint32_t)(radeon_mmio_base),addr)
+#define OUTREG8(addr,val) SETREG(uint8_t,(uint32_t)(radeon_mmio_base),addr,val)
+#define INREG(addr) GETREG(uint32_t,(uint32_t)(radeon_mmio_base),addr)
+#define OUTREG(addr,val) SETREG(uint32_t,(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 __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;
+}
+
+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(__BIG_ENDIAN)
+ OUTREGP(DP_DATATYPE,
+ HOST_BIG_ENDIAN_EN, ~HOST_BIG_ENDIAN_EN);
+#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(!IsR200)
+ {
+#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(!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;
+ 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_4X,
+ DEVICE_ATI_RAGE_128_SK_4X,
+ DEVICE_ATI_RAGE_128_SL_4X,
+ DEVICE_ATI_RAGE_128_SM_4X,
+ DEVICE_ATI_RAGE_128_4X2,
+ 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_8500_DV,
+ DEVICE_ATI_RADEON_MOBILITY_M6,
+ DEVICE_ATI_RADEON_MOBILITY_M62,
+ DEVICE_ATI_RADEON_MOBILITY_M63,
+ DEVICE_ATI_RADEON_QD,
+ DEVICE_ATI_RADEON_QE,
+ DEVICE_ATI_RADEON_QF,
+ DEVICE_ATI_RADEON_QG,
+ DEVICE_ATI_RADEON_QL,
+ DEVICE_ATI_RADEON_QW,
+ DEVICE_ATI_RADEON_VE_QY,
+ DEVICE_ATI_RADEON_VE_QZ
+#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;
+}
+
+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}
+};
+
+
+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 occured 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);
+#ifndef RAGE128
+ if(idx != -1)
+ if(ati_card_ids[idx] == DEVICE_ATI_RADEON_QL ||
+ ati_card_ids[idx] == DEVICE_ATI_RADEON_8500_DV ||
+ ati_card_ids[idx] == DEVICE_ATI_RADEON_QW) IsR200 = 1;
+#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;
+}
+
+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;
+ 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();
+ printf(RADEON_MSG" Video memory = %uMb\n",radeon_ram_size/0x100000);
+ 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");
+ if(bm_open() == 0) def_cap.flags |= FLAG_DMA | FLAG_EQ_DMA;
+ else
+ if(__verbose) printf(RADEON_MSG" Can't initialize busmastering: %s\n",strerror(errno));
+ return 0;
+}
+
+void vixDestroy( void )
+{
+ unmap_phys_mem(radeon_mem_base,radeon_ram_size);
+ unmap_phys_mem(radeon_mmio_base,0xFFFF);
+ bm_close();
+}
+
+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, IMGFMT_YVYU,
+ IMGFMT_RGB15, IMGFMT_BGR15,
+ IMGFMT_RGB16, IMGFMT_BGR16,
+ IMGFMT_RGB32, IMGFMT_BGR32
+};
+
+__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 | 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"*** 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);
+ 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);
+
+ /* 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 & 0x7f) |
+ (besr.saturation << 8) |
+ (besr.saturation << 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);
+
+ bes_flags = SCALER_ENABLE |
+ SCALER_SMART_SWITCH |
+#ifdef RADEON
+ SCALER_HORZ_PICK_NEAREST |
+#endif
+ 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: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;
+ 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_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_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_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)
+ {
+ case IMGFMT_YVU9:
+ /* 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;
+ besr.v_inc = (src_h << 20) / dest_h;
+ if(radeon_is_interlace()) besr.v_inc *= 2;
+ 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 = 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)
+ {
+ uint32_t d1line,d2line,d3line;
+ d1line = top*pitch;
+ d2line = src_h*pitch+(d1line>>2);
+ 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.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);
+ 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;
+ 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;
+ if(besr.fourcc == IMGFMT_I420 || besr.fourcc == IMGFMT_IYUV)
+ {
+ uint32_t tmp;
+ tmp = config->offset.u;
+ config->offset.u = config->offset.v;
+ config->offset.v = tmp;
+ }
+ }
+ 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 ? ((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;
+ if(is_rgb && !is_rgb32) h_inc<<=1;
+ if(is_rgb32)
+ besr.h_inc = (h_inc >> 1) | ((h_inc >> 1) << 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)
+ {
+ 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;
+}
+
+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_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;
+ 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;
+ 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)&REG_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)&REG_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:
+ 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:
+ 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|GRAPHIC_KEY_FN_EQ|CMP_MIX_AND;
+#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);
+}