📄 cim_vop.c
字号:
/*
* <LIC_AMD_STD>
* Copyright (C) 2005 Advanced Micro Devices, Inc. All Rights Reserved.
* </LIC_AMD_STD>
*
* <CTL_AMD_STD>
* </CTL_AMD_STD>
*
* <DOC_AMD_STD>
* Cimarron VOP configuration routines.
* </DOC_AMD_STD>
*
*/
/*---------------------------------------------------------------------------
* vop_set_vbi_window
*
* This routine configures the output position and location in memory of
* VBI data.
*---------------------------------------------------------------------------*/
int vop_set_vbi_window (VOPVBIWINDOWBUFFER *buffer)
{
unsigned long unlock, temp;
unsigned long hstart, hstop;
unsigned long htotal, hsyncstart;
if (!buffer)
return CIM_STATUS_INVALIDPARAMS;
unlock = READ_REG32 (DC3_UNLOCK);
WRITE_REG32 (DC3_UNLOCK, DC3_UNLOCK_VALUE);
/* PROGRAM HORIZONTAL POSITION */
/* The horizontal position is a little tricky. The counter for the horizontal */
/* timings is reused for the VBI counter. Consequently, the horizontal start */
/* and stop values are based off the beginning of active data. However, the */
/* VG has a quirk. If the counter start position is before the beginning of */
/* HSync, it applies to the previous line. If the counter is after the */
/* beginning of HSync it applies to the current line. So, for one line */
/* the real range can be thought of as HSync_start to (HSync_start + htotal - 1). */
/* However, the counters must be between 0 and htotal - 1. When placing VBI */
/* data before the start of active data, the horizontal end position will thus */
/* be *less* than the horizontal start. */
htotal = ((READ_REG32 (DC3_H_ACTIVE_TIMING) >> 16) & 0xFFF) + 1;
hsyncstart = (READ_REG32 (DC3_H_SYNC_TIMING) & 0xFFF) + 1;
if (buffer->horz_from_hsync)
{
/* VERIFY THAT THE INPUT IS VALID */
if (buffer->horz_start < 0 || (buffer->horz_start + buffer->vbi_width) > htotal)
return CIM_STATUS_INVALIDPARAMS;
hstart = buffer->horz_start + hsyncstart;
}
else
{
/* VERIFY THAT THE INPUT IS VALID */
if (buffer->horz_start < ((long)hsyncstart - (long)htotal) ||
buffer->horz_start > (long)hsyncstart ||
buffer->vbi_width > htotal)
{
return CIM_STATUS_INVALIDPARAMS;
}
hstart = buffer->horz_start + htotal;
}
hstop = hstart + buffer->vbi_width;
if (hstart > htotal) hstart -= htotal;
if (hstop > htotal) hstop -= htotal;
hstart--;
hstop--;
WRITE_REG32 (DC3_VBI_HOR, ((hstop << DC3_VBI_HOR_END_SHIFT) & DC3_VBI_HOR_END_MASK) |
(hstart & DC3_VBI_HOR_START_MASK));
/* WRITE LINE CAPTURE MASKS */
WRITE_REG32 (DC3_VBI_LN_ODD, ((buffer->odd_line_offset << DC3_VBI_ODD_LINE_SHIFT) & DC3_VBI_ODD_LINE_MASK) |
(buffer->odd_line_capture_mask & DC3_VBI_ODD_ENABLE_MASK));
WRITE_REG32 (DC3_VBI_LN_EVEN, ((buffer->even_line_offset << DC3_VBI_EVEN_LINE_SHIFT) & DC3_VBI_EVEN_LINE_MASK) |
(buffer->even_line_capture_mask & DC3_VBI_EVEN_ENABLE_MASK));
/* PROGRAM SOURCE OFFSETS */
/* Start with the even offsets. Note that we always enable 16-bit VBI, as this */
/* is the only way to get VBI data on each VOP clock. */
temp = READ_REG32 (DC3_VBI_EVEN_CTL) & ~DC3_VBI_EVEN_CTL_OFFSET_MASK;
temp |= DC3_VBI_EVEN_CTL_ENABLE_16;
if (buffer->enable_upscale)
temp |= DC3_VBI_EVEN_CTL_UPSCALE;
WRITE_REG32 (DC3_VBI_EVEN_CTL, temp | (buffer->even_address_offset & DC3_VBI_EVEN_CTL_OFFSET_MASK));
/* ODD OFFSET */
temp = READ_REG32 (DC3_VBI_ODD_CTL) & ~DC3_VBI_ODD_CTL_OFFSET_MASK;
WRITE_REG32 (DC3_VBI_ODD_CTL, temp | (buffer->odd_address_offset & DC3_VBI_ODD_CTL_OFFSET_MASK));
/* PITCH */
temp = ((buffer->data_size >> 3) << 16) | ((buffer->data_pitch >> 3) & 0x0000FFFF);
WRITE_REG32(DC3_VBI_PITCH, temp);
WRITE_REG32 (DC3_UNLOCK, unlock);
return CIM_STATUS_OK;
}
/*---------------------------------------------------------------------------
* vop_enable_vbi_output
*
* This routine enables/disables VBI fetching inside the video generator.
*---------------------------------------------------------------------------*/
int vop_enable_vbi_output (int enable)
{
unsigned long unlock, temp;
unlock = READ_REG32 (DC3_UNLOCK);
temp = READ_REG32 (DC3_VBI_EVEN_CTL);
if (enable) temp |= DC3_VBI_ENABLE;
else temp &= ~DC3_VBI_ENABLE;
WRITE_REG32 (DC3_UNLOCK, DC3_UNLOCK_VALUE);
WRITE_REG32 (DC3_VBI_EVEN_CTL, temp);
WRITE_REG32 (DC3_UNLOCK, unlock);
return CIM_STATUS_OK;
}
/*---------------------------------------------------------------------------
* vop_set_configuration
*
* This routine is passed a VOP_CONFIGURATION structure that contains all
* the necessary information to configure VOP output.
*---------------------------------------------------------------------------*/
int vop_set_configuration (VOPCONFIGURATIONBUFFER *config)
{
unsigned long vop_config = 0;
unsigned long alpha, control2;
unsigned long unlock;
unsigned long delta;
Q_WORD msr_value;
int rgb = 0;
if (!config)
return CIM_STATUS_INVALIDPARAMS;
unlock = READ_REG32 (DC3_UNLOCK);
delta = READ_REG32 (DC3_VID_DS_DELTA) & DC3_DS_DELTA_MASK;
/* OVERRIDE THE OUTPUT SETTINGS TO ENABLE VOP OUTPUT */
if (config->mode != VOP_MODE_DISABLED)
{
msr_read64 (MSR_DEVICE_GEODELX_DF, MSR_GEODELINK_CONFIG, &msr_value);
msr_value.low &= ~DF_CONFIG_OUTPUT_MASK;
msr_value.low |= DF_OUTPUT_VOP;
msr_write64 (MSR_DEVICE_GEODELX_DF, MSR_GEODELINK_CONFIG, &msr_value);
}
/* SET THE UNIVERSAL VOP OPTIONS */
if (config->flags & VOP_FLAG_SWAP_UV) vop_config |= VOP_CONFIG_SWAPUV;
if (config->flags & VOP_FLAG_SWAP_VBI) vop_config |= VOP_CONFIG_SWAPVBI;
/* SET THE MODE SPECIFIC PARAMETERS */
if (config->mode == VOP_MODE_601)
{
vop_config |= config->vop601.flags;
vop_config |= config->vop601.vsync_shift;
vop_config |= VOP_CONFIG_ENABLE_601 | VOP_CONFIG_VIP2_0;
switch (config->vop601.output_mode)
{
case VOP_601_YUV_16BIT:
vop_config |= VOP_CONFIG_VIP2_16BIT;
break;
case VOP_601_YUV_4_4_4:
vop_config |= VOP_CONFIG_DISABLE_DECIMATE;
break;
case VOP_601_RGB_8_8_8:
vop_config |= VOP_CONFIG_DISABLE_DECIMATE | VOP_CONFIG_RGBMODE;
rgb = 1;
break;
}
if (config->vop601.vsync_shift == VOP_VSYNC_LATER_BY_X)
{
delta |= (config->vop601.vsync_shift_count & DC3_601_VSYNC_SHIFT_MASK);
delta |= DC3_601_VSYNC_SHIFT_ENABLE;
}
}
else
{
if (config->flags & VOP_FLAG_VBI) vop_config |= VOP_CONFIG_VBI;
if (config->flags & VOP_FLAG_TASK) vop_config |= VOP_CONFIG_TASK;
if (config->flags & VOP_FLAG_SINGLECHIPCOMPAT) vop_config |= VOP_CONFIG_SC_COMPATIBLE;
if (config->flags & VOP_FLAG_EXTENDEDSAV) vop_config |= VOP_CONFIG_EXTENDED_SAV;
switch (config->mode)
{
case VOP_MODE_DISABLED:
vop_config |= VOP_CONFIG_DISABLED;
break;
case VOP_MODE_VIP11:
vop_config |= VOP_CONFIG_VIP1_1;
break;
case VOP_MODE_CCIR656:
vop_config |= VOP_CONFIG_CCIR656;
break;
case VOP_MODE_VIP20_8BIT:
vop_config |= VOP_CONFIG_VIP2_0;
break;
case VOP_MODE_VIP20_16BIT:
vop_config |= VOP_CONFIG_VIP2_0 | VOP_CONFIG_VIP2_16BIT;
break;
}
}
/* SET THE 4:4:4 TO 4:2:2 DECIMATION ALGORITHM */
vop_config |= (config->conversion_mode);
/* SET THE VSYNC OUT OPTIONS */
control2 = READ_VIP32 (VIP_CONTROL2) & ~VIP_CONTROL2_SYNC2PIN_MASK;
control2 |= config->vsync_out;
WRITE_VIP32 (VIP_CONTROL2, control2);
/* FORCE THE CORRECT VOP COLOR SPACE */
/* The output of the mixer will be either RGB or YUV. We must enable */
/* or disable the VOP CSC based on the desired output format. */
alpha = READ_VID32 (DF_VID_ALPHA_CONTROL);
if (!(alpha & DF_CSC_GRAPHICS_RGB_TO_YUV))
{
/* RGB OUTPUT FROM THE MIXER */
if (!rgb) alpha |= DF_CSC_VOP_RGB_TO_YUV;
else alpha &= ~DF_CSC_VOP_RGB_TO_YUV;
}
else
{
/* YUV OUTPUT FROM THE MIXER */
/* As there is no YUV->RGB VOP conversion, we simply disable the */
/* VOP CSC and trust that the user is competent. */
alpha &= ~DF_CSC_VOP_RGB_TO_YUV;
}
/* AND WRITE THE CONFIGURATION */
WRITE_VID32 (DF_VID_ALPHA_CONTROL, alpha);
WRITE_VOP32(VOP_CONFIGURATION, vop_config);
WRITE_REG32 (DC3_UNLOCK, DC3_UNLOCK_VALUE);
WRITE_REG32 (DC3_VID_DS_DELTA, delta);
WRITE_REG32 (DC3_UNLOCK, unlock);
return CIM_STATUS_OK;
}
/*---------------------------------------------------------------------------
* vop_save_state
*
* This routine saves the necessary register contents in order to restore
* at a later point to the same state. Note that the capture state is
* forced to OFF in this routine.
*---------------------------------------------------------------------------*/
int vop_save_state (VOPSTATEBUFFER *save_buffer)
{
if (!save_buffer)
return CIM_STATUS_INVALIDPARAMS;
save_buffer->config = READ_VOP32(VOP_CONFIGURATION);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -