summaryrefslogtreecommitdiff
path: root/src/cim/cim_vop.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/cim/cim_vop.c')
-rw-r--r--src/cim/cim_vop.c604
1 files changed, 604 insertions, 0 deletions
diff --git a/src/cim/cim_vop.c b/src/cim/cim_vop.c
new file mode 100644
index 0000000..4b83c03
--- /dev/null
+++ b/src/cim/cim_vop.c
@@ -0,0 +1,604 @@
+/*
+ * Copyright (c) 2006 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Neither the name of the Advanced Micro Devices, Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ */
+
+ /*
+ * Cimarron VOP configuration routines.
+ */
+
+/*---------------------------------------------------------------------------
+ * 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);
+
+ return CIM_STATUS_OK;
+}
+
+/*---------------------------------------------------------------------------
+ * vop_restore_state
+ *
+ * This routine restores the state of the vop registers - which were
+ * previously saved using vop_save_state.
+ *--------------------------------------------------------------------------*/
+
+int
+vop_restore_state(VOPSTATEBUFFER * restore_buffer)
+{
+ if (!restore_buffer)
+ return CIM_STATUS_INVALIDPARAMS;
+
+ WRITE_VOP32(VOP_CONFIGURATION, restore_buffer->config);
+
+ return CIM_STATUS_OK;
+}
+
+/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+ * CIMARRON VOP READ ROUTINES
+ * These routines are included for use in diagnostics or when debugging. They
+ * can be optionally excluded from a project.
+ *++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
+
+#if CIMARRON_INCLUDE_VOP_READ_ROUTINES
+
+/*---------------------------------------------------------------------------
+ * vop_get_current_mode
+ *
+ * This routine reads the current VIP operating mode and stores it in the
+ * passed VOP_CONFIGURATION structure.
+ *--------------------------------------------------------------------------*/
+
+int
+vop_get_current_mode(VOPCONFIGURATIONBUFFER * config)
+{
+ unsigned long vop_config = 0;
+ unsigned long alpha;
+
+ if (!config)
+ return CIM_STATUS_INVALIDPARAMS;
+
+ vop_config = READ_VOP32(VOP_CONFIGURATION);
+ alpha = READ_VID32(DF_VID_ALPHA_CONTROL);
+
+ /* READ THE CURRENT MODE */
+
+ switch (vop_config & VOP_CONFIG_MODE_MASK) {
+ case VOP_CONFIG_DISABLED:
+ config->mode = VOP_MODE_DISABLED;
+ break;
+ case VOP_CONFIG_VIP1_1:
+ config->mode = VOP_MODE_VIP11;
+ break;
+ case VOP_CONFIG_CCIR656:
+ config->mode = VOP_MODE_CCIR656;
+ break;
+ case VOP_CONFIG_VIP2_0:
+
+ if (vop_config & VOP_CONFIG_ENABLE_601)
+ config->mode = VOP_MODE_601;
+ else if (vop_config & VOP_CONFIG_VIP2_16BIT)
+ config->mode = VOP_MODE_VIP20_16BIT;
+ else
+ config->mode = VOP_MODE_VIP20_8BIT;
+ break;
+ }
+
+ /* READ 601 SETTINGS */
+
+ config->vop601.flags = vop_config & (VOP_CONFIG_INVERT_DISPE |
+ VOP_CONFIG_INVERT_HSYNC | VOP_CONFIG_INVERT_VSYNC);
+
+ config->vop601.vsync_shift = vop_config & VOP_CONFIG_VSYNC_MASK;
+ config->vop601.vsync_shift_count =
+ READ_REG32(DC3_VID_DS_DELTA) & DC3_601_VSYNC_SHIFT_MASK;
+
+ if ((alpha & DF_CSC_GRAPHICS_RGB_TO_YUV) ||
+ (alpha & DF_CSC_VOP_RGB_TO_YUV)) {
+ /* YUV OUTPUT */
+
+ if (vop_config & VOP_CONFIG_DISABLE_DECIMATE)
+ config->vop601.output_mode = VOP_601_YUV_4_4_4;
+ else if (vop_config & VOP_CONFIG_VIP2_16BIT)
+ config->vop601.output_mode = VOP_601_YUV_16BIT;
+ else
+ config->vop601.output_mode = VOP_601_YUV_8BIT;
+ } else {
+ config->vop601.output_mode = VOP_601_RGB_8_8_8;
+ }
+
+ config->flags = 0;
+
+ /* READ THE UNIVERSAL VOP OPTIONS */
+
+ if (vop_config & VOP_CONFIG_SWAPUV)
+ config->flags |= VOP_FLAG_SWAP_UV;
+ if (vop_config & VOP_CONFIG_SWAPVBI)
+ config->flags |= VOP_FLAG_SWAP_VBI;
+ if (vop_config & VOP_CONFIG_VBI)
+ config->flags |= VOP_FLAG_VBI;
+ if (vop_config & VOP_CONFIG_TASK)
+ config->flags |= VOP_FLAG_TASK;
+ if (vop_config & VOP_CONFIG_SC_COMPATIBLE)
+ config->flags |= VOP_FLAG_SINGLECHIPCOMPAT;
+ if (vop_config & VOP_CONFIG_EXTENDED_SAV)
+ config->flags |= VOP_FLAG_EXTENDEDSAV;
+
+ config->conversion_mode = vop_config & VOP_CONFIG_422_MASK;
+
+ config->vsync_out = READ_VIP32(VIP_CONTROL2) & VIP_CONTROL2_SYNC2PIN_MASK;
+
+ return CIM_STATUS_OK;
+}
+
+/*---------------------------------------------------------------------------
+ * vop_get_vbi_window
+ *
+ * This routine reads the current VBI configuration for VOP output.
+ *--------------------------------------------------------------------------*/
+
+int
+vop_get_vbi_configuration(VOPVBIWINDOWBUFFER * buffer)
+{
+ unsigned long temp;
+ unsigned long hstart, hstop;
+ unsigned long htotal, hsyncstart;
+
+ if (!buffer)
+ return CIM_STATUS_INVALIDPARAMS;
+
+ htotal = ((READ_REG32(DC3_H_ACTIVE_TIMING) >> 16) & 0xFFF) + 1;
+ hsyncstart = (READ_REG32(DC3_H_SYNC_TIMING) & 0xFFF) + 1;
+
+ /* DECODE HORIZONTAL POSITION */
+ /* This is done according to the requested horizontal origin */
+
+ temp = READ_REG32(DC3_VBI_HOR);
+ hstart = (temp & DC3_VBI_HOR_START_MASK) + 1;
+ hstop = ((temp & DC3_VBI_HOR_END_MASK) >> DC3_VBI_HOR_END_SHIFT) + 1;
+ if (buffer->horz_from_hsync) {
+ buffer->horz_start = hstart + htotal - hsyncstart;
+ if (buffer->horz_start >= (long)htotal)
+ buffer->horz_start -= htotal;
+ } else {
+ if (hstart > hsyncstart)
+ buffer->horz_start = (long)hstart - (long)htotal;
+ else
+ buffer->horz_start = hstart;
+ }
+
+ if (hstop > hstart)
+ buffer->vbi_width = hstop - hstart;
+ else
+ buffer->vbi_width = (htotal - hstart) + hstop;
+
+ /* READ LINE MASKS */
+
+ temp = READ_REG32(DC3_VBI_LN_ODD);
+ buffer->odd_line_offset = (temp & DC3_VBI_ODD_LINE_MASK) >>
+ DC3_VBI_ODD_LINE_SHIFT;
+ buffer->odd_line_capture_mask = (temp & DC3_VBI_ODD_ENABLE_MASK);
+
+ temp = READ_REG32(DC3_VBI_LN_EVEN);
+ buffer->even_line_offset = (temp & DC3_VBI_EVEN_LINE_MASK) >>
+ DC3_VBI_EVEN_LINE_SHIFT;
+ buffer->even_line_capture_mask = (temp & DC3_VBI_EVEN_ENABLE_MASK);
+
+ /* READ VBI UPSCALE SETTINGS */
+
+ buffer->enable_upscale = 0;
+ temp = READ_REG32(DC3_VBI_EVEN_CTL);
+ if (temp & DC3_VBI_EVEN_CTL_UPSCALE)
+ buffer->enable_upscale = 1;
+
+ /* READ SOURCE OFFSETS */
+
+ buffer->even_address_offset = temp & DC3_VBI_EVEN_CTL_OFFSET_MASK;
+ buffer->odd_address_offset =
+ READ_REG32(DC3_VBI_ODD_CTL) & DC3_VBI_ODD_CTL_OFFSET_MASK;
+
+ /* PITCH AND SIZE */
+
+ temp = READ_REG32(DC3_VBI_PITCH);
+ buffer->data_size = (temp >> 16) << 3;
+ buffer->data_pitch = (temp & 0xFFFF);
+
+ return CIM_STATUS_OK;
+}
+
+/*---------------------------------------------------------------------------
+ * vop_get_vbi_enable
+ *
+ * This routine reads the current enable status of VBI output.
+ *--------------------------------------------------------------------------*/
+
+int
+vop_get_vbi_enable(void)
+{
+ if (READ_REG32(DC3_VBI_EVEN_CTL) & DC3_VBI_ENABLE)
+ return 1;
+
+ return 0;
+}
+
+/*---------------------------------------------------------------------------
+ * vop_get_crc
+ *
+ * This routine returns a CRC of the current VOP data
+ --------------------------------------------------------------------------*/
+
+unsigned long
+vop_get_crc(void)
+{
+ unsigned long crc;
+ unsigned long config = READ_VOP32(VOP_CONFIGURATION);
+ unsigned long timeout = 1000;
+
+ if (!(READ_REG32(DC3_DISPLAY_CFG) & DC3_DCFG_TGEN))
+ return 0xFFFFFFFF;
+
+ /* RESET CRC */
+
+ WRITE_VOP32(VOP_CONFIGURATION, config & ~VOP_CONFIG_ENABLE_SIGNATURE);
+
+ /* WAIT FOR THE RESET TO BE LATCHED */
+
+ while ((READ_VOP32(VOP_SIGNATURE) != 0x00000001) && timeout)
+ timeout--;
+
+ WRITE_VOP32(VOP_CONFIGURATION, config | VOP_CONFIG_ENABLE_SIGNATURE);
+
+ /* WAIT UNTIL NOT ACTIVE, THEN ACTIVE, NOT ACTIVE, THEN ACTIVE */
+
+ while (!(READ_VOP32(VOP_CONFIGURATION) & VOP_CONFIG_SIGVAL)) ;
+
+ crc = READ_VOP32(VOP_SIGNATURE);
+
+ return crc;
+}
+
+/*---------------------------------------------------------------------------
+ * vop_read_vbi_crc
+ *
+ * This routine returns a CRC of the current VBI data
+ ---------------------------------------------------------------------------*/
+
+unsigned long
+vop_read_vbi_crc(void)
+{
+ unsigned long gcfg, unlock, vbi_even;
+ unsigned long crc;
+
+ if (!(READ_REG32(DC3_DISPLAY_CFG) & DC3_DCFG_TGEN) ||
+ !(READ_REG32(DC3_VBI_EVEN_CTL) & DC3_VBI_ENABLE)) {
+ return 0xFFFFFFFF;
+ }
+
+ unlock = READ_REG32(DC3_UNLOCK);
+ gcfg = READ_REG32(DC3_GENERAL_CFG);
+ vbi_even = READ_REG32(DC3_VBI_EVEN_CTL);
+
+ gcfg |= DC3_GCFG_SGRE | DC3_GCFG_CRC_MODE;
+ gcfg &= ~(DC3_GCFG_SGFR | DC3_GCFG_SIG_SEL);
+ vbi_even |= DC3_VBI_EVEN_ENABLE_CRC;
+
+ WRITE_REG32(DC3_UNLOCK, DC3_UNLOCK_VALUE);
+ WRITE_REG32(DC3_VBI_EVEN_CTL, vbi_even);
+ WRITE_REG32(DC3_GENERAL_CFG, gcfg & ~DC3_GCFG_SIGE);
+ WRITE_REG32(DC3_GENERAL_CFG, gcfg | DC3_GCFG_SIGE);
+
+ /* WAIT FOR THE CRC TO BE COMPLETED */
+
+ while (!(READ_REG32(DC3_LINE_CNT_STATUS) & DC3_LNCNT_SIGC)) ;
+
+ /* READ THE COMPLETED CRC */
+
+ crc = READ_REG32(DC3_PAL_DATA);
+
+ /* RESTORE THE PALETTE SETTINGS */
+
+ gcfg &= ~DC3_GCFG_SGRE;
+ WRITE_REG32(DC3_GENERAL_CFG, gcfg);
+ WRITE_REG32(DC3_UNLOCK, unlock);
+
+ return crc;
+}
+
+#endif