Logo Search packages:      
Sourcecode: xserver-xorg-video-ati version File versions

atombios_output.c

/*
 * Copyright © 2007 Red Hat, Inc.
 * Copyright 2007  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 (including the next
 * paragraph) 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.
 *
 * Authors:
 *    Dave Airlie <airlied@redhat.com>
 *    Alex Deucher <alexdeucher@gmail.com>
 *
 */

/*
 * avivo output handling functions.
 */
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
/* DPMS */
#define DPMS_SERVER
#include <X11/extensions/dpms.h>
#include <unistd.h>

#include "radeon.h"
#include "radeon_reg.h"
#include "radeon_macros.h"
#include "radeon_atombios.h"

#include "ati_pciids_gen.h"

const char *device_name[12] = {
    "CRT1",
    "LCD1",
    "TV1",
    "DFP1",
    "CRT2",
    "LCD2",
    "TV2",
    "DFP2",
    "CV",
    "DFP3",
    "DFP4",
    "DFP5",
};

static int
atombios_output_dac_setup(xf86OutputPtr output, int action)
{
    RADEONOutputPrivatePtr radeon_output = output->driver_private;
    RADEONInfoPtr info       = RADEONPTR(output->scrn);
    radeon_encoder_ptr radeon_encoder = radeon_get_encoder(output);
    radeon_tvout_ptr tvout = &radeon_output->tvout;
    DAC_ENCODER_CONTROL_PS_ALLOCATION disp_data;
    AtomBiosArgRec data;
    unsigned char *space;
    int index = 0, num = 0;
    int clock = radeon_output->pixel_clock;

    if (radeon_encoder == NULL)
      return ATOM_NOT_IMPLEMENTED;

    memset(&disp_data,0, sizeof(disp_data));

    switch (radeon_encoder->encoder_id) {
    case ENCODER_OBJECT_ID_INTERNAL_DAC1:
    case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1:
      index = GetIndexIntoMasterTable(COMMAND, DAC1EncoderControl);
      num = 1;
      break;
    case ENCODER_OBJECT_ID_INTERNAL_DAC2:
    case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC2:
      index = GetIndexIntoMasterTable(COMMAND, DAC2EncoderControl);
      num = 2;
      break;
    }

    disp_data.ucAction =action;

    if (radeon_output->active_device & (ATOM_DEVICE_CRT_SUPPORT))
      disp_data.ucDacStandard = ATOM_DAC1_PS2;
    else if (radeon_output->active_device & (ATOM_DEVICE_CV_SUPPORT))
      disp_data.ucDacStandard = ATOM_DAC1_CV;
    else {
      switch (tvout->tvStd) {
      case TV_STD_PAL:
      case TV_STD_PAL_M:
      case TV_STD_SCART_PAL:
      case TV_STD_SECAM:
      case TV_STD_PAL_CN:
          disp_data.ucDacStandard = ATOM_DAC1_PAL;
          break;
      case TV_STD_NTSC:
      case TV_STD_NTSC_J:
      case TV_STD_PAL_60:
      default:
          disp_data.ucDacStandard = ATOM_DAC1_NTSC;
          break;
      }
    }
    disp_data.usPixelClock = cpu_to_le16(clock / 10);

    data.exec.index = index;
    data.exec.dataSpace = (void *)&space;
    data.exec.pspace = &disp_data;

    if (RHDAtomBiosFunc(info->atomBIOS->scrnIndex, info->atomBIOS, ATOMBIOS_EXEC, &data) == ATOM_SUCCESS) {
      ErrorF("Output DAC%d setup success\n", num);
      return ATOM_SUCCESS;
    }

    ErrorF("Output DAC%d setup failed\n", num);
    return ATOM_NOT_IMPLEMENTED;

}

static int
atombios_output_tv_setup(xf86OutputPtr output, int action)
{
    RADEONOutputPrivatePtr radeon_output = output->driver_private;
    radeon_tvout_ptr tvout = &radeon_output->tvout;
    RADEONInfoPtr info       = RADEONPTR(output->scrn);
    TV_ENCODER_CONTROL_PS_ALLOCATION disp_data;
    AtomBiosArgRec data;
    unsigned char *space;
    int clock = radeon_output->pixel_clock;

    memset(&disp_data,0, sizeof(disp_data));

    disp_data.sTVEncoder.ucAction = action;

    if (radeon_output->active_device & (ATOM_DEVICE_CV_SUPPORT))
      disp_data.sTVEncoder.ucTvStandard = ATOM_TV_CV;
    else {
      switch (tvout->tvStd) {
      case TV_STD_NTSC:
          disp_data.sTVEncoder.ucTvStandard = ATOM_TV_NTSC;
          break;
      case TV_STD_PAL:
          disp_data.sTVEncoder.ucTvStandard = ATOM_TV_PAL;
          break;
      case TV_STD_PAL_M:
          disp_data.sTVEncoder.ucTvStandard = ATOM_TV_PALM;
          break;
      case TV_STD_PAL_60:
          disp_data.sTVEncoder.ucTvStandard = ATOM_TV_PAL60;
          break;
      case TV_STD_NTSC_J:
          disp_data.sTVEncoder.ucTvStandard = ATOM_TV_NTSCJ;
          break;
      case TV_STD_SCART_PAL:
          disp_data.sTVEncoder.ucTvStandard = ATOM_TV_PAL; /* ??? */
          break;
      case TV_STD_SECAM:
          disp_data.sTVEncoder.ucTvStandard = ATOM_TV_SECAM;
          break;
      case TV_STD_PAL_CN:
          disp_data.sTVEncoder.ucTvStandard = ATOM_TV_PALCN;
          break;
      default:
          disp_data.sTVEncoder.ucTvStandard = ATOM_TV_NTSC;
          break;
      }
    }

    disp_data.sTVEncoder.usPixelClock = cpu_to_le16(clock / 10);
    data.exec.index = GetIndexIntoMasterTable(COMMAND, TVEncoderControl);
    data.exec.dataSpace = (void *)&space;
    data.exec.pspace = &disp_data;

    if (RHDAtomBiosFunc(info->atomBIOS->scrnIndex, info->atomBIOS, ATOMBIOS_EXEC, &data) == ATOM_SUCCESS) {
      ErrorF("Output TV setup success\n");
      return ATOM_SUCCESS;
    }

    ErrorF("Output TV setup failed\n");
    return ATOM_NOT_IMPLEMENTED;

}

int
atombios_external_tmds_setup(xf86OutputPtr output, int action)
{
    RADEONOutputPrivatePtr radeon_output = output->driver_private;
    ScrnInfoPtr pScrn = output->scrn;
    RADEONInfoPtr info       = RADEONPTR(pScrn);
    ENABLE_EXTERNAL_TMDS_ENCODER_PS_ALLOCATION disp_data;
    AtomBiosArgRec data;
    unsigned char *space;
    int clock = radeon_output->pixel_clock;

    memset(&disp_data,0, sizeof(disp_data));

    disp_data.sXTmdsEncoder.ucEnable = action;

    if (clock > 165000)
      disp_data.sXTmdsEncoder.ucMisc = PANEL_ENCODER_MISC_DUAL;

    if (pScrn->rgbBits == 8)
      disp_data.sXTmdsEncoder.ucMisc |= (1 << 1);

    data.exec.index = GetIndexIntoMasterTable(COMMAND, DVOEncoderControl);
    data.exec.dataSpace = (void *)&space;
    data.exec.pspace = &disp_data;

    if (RHDAtomBiosFunc(info->atomBIOS->scrnIndex, info->atomBIOS, ATOMBIOS_EXEC, &data) == ATOM_SUCCESS) {
      ErrorF("External TMDS setup success\n");
      return ATOM_SUCCESS;
    }

    ErrorF("External TMDS setup failed\n");
    return ATOM_NOT_IMPLEMENTED;
}

static int
atombios_output_ddia_setup(xf86OutputPtr output, int action)
{
    RADEONOutputPrivatePtr radeon_output = output->driver_private;
    RADEONInfoPtr info       = RADEONPTR(output->scrn);
    DVO_ENCODER_CONTROL_PS_ALLOCATION disp_data;
    AtomBiosArgRec data;
    unsigned char *space;
    int clock = radeon_output->pixel_clock;

    memset(&disp_data,0, sizeof(disp_data));

    disp_data.sDVOEncoder.ucAction = action;
    disp_data.sDVOEncoder.usPixelClock = cpu_to_le16(clock / 10);

    if (clock > 165000)
      disp_data.sDVOEncoder.usDevAttr.sDigAttrib.ucAttribute = PANEL_ENCODER_MISC_DUAL;

    data.exec.index = GetIndexIntoMasterTable(COMMAND, DVOEncoderControl);
    data.exec.dataSpace = (void *)&space;
    data.exec.pspace = &disp_data;

    if (RHDAtomBiosFunc(info->atomBIOS->scrnIndex, info->atomBIOS, ATOMBIOS_EXEC, &data) == ATOM_SUCCESS) {
      ErrorF("DDIA setup success\n");
      return ATOM_SUCCESS;
    }

    ErrorF("DDIA setup failed\n");
    return ATOM_NOT_IMPLEMENTED;
}

static int
atombios_output_digital_setup(xf86OutputPtr output, int action)
{
    RADEONOutputPrivatePtr radeon_output = output->driver_private;
    ScrnInfoPtr pScrn = output->scrn;
    RADEONInfoPtr info       = RADEONPTR(pScrn);
    radeon_encoder_ptr radeon_encoder = radeon_get_encoder(output);
    LVDS_ENCODER_CONTROL_PS_ALLOCATION disp_data;
    LVDS_ENCODER_CONTROL_PS_ALLOCATION_V2 disp_data2;
    AtomBiosArgRec data;
    unsigned char *space;
    int index = 0;
    int major, minor;
    int lvds_misc = 0;
    int clock = radeon_output->pixel_clock;

    if (radeon_encoder == NULL)
      return ATOM_NOT_IMPLEMENTED;

    if (radeon_output->active_device & (ATOM_DEVICE_LCD_SUPPORT)) {
      radeon_lvds_ptr lvds = (radeon_lvds_ptr)radeon_encoder->dev_priv;
      if (lvds == NULL)
          return ATOM_NOT_IMPLEMENTED;
      lvds_misc = lvds->lvds_misc;
    }

    memset(&disp_data,0, sizeof(disp_data));
    memset(&disp_data2,0, sizeof(disp_data2));

    switch (radeon_encoder->encoder_id) {
    case ENCODER_OBJECT_ID_INTERNAL_LVDS:
      index = GetIndexIntoMasterTable(COMMAND, LVDSEncoderControl);
      break;
    case ENCODER_OBJECT_ID_INTERNAL_TMDS1:
    case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1:
      index = GetIndexIntoMasterTable(COMMAND, TMDS1EncoderControl);
      break;
    case ENCODER_OBJECT_ID_INTERNAL_LVTM1:
    case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA:
      if (radeon_output->active_device & (ATOM_DEVICE_LCD_SUPPORT))
          index = GetIndexIntoMasterTable(COMMAND, LVDSEncoderControl);
      else
          index = GetIndexIntoMasterTable(COMMAND, TMDS2EncoderControl);
      break;
    }

    atombios_get_command_table_version(info->atomBIOS, index, &major, &minor);

    /*ErrorF("table is %d %d\n", major, minor);*/
    switch (major) {
    case 0:
    case 1:
    case 2:
      switch (minor) {
      case 1:
          disp_data.ucMisc = 0;
          disp_data.ucAction = action;
          if ((radeon_output->ConnectorType == CONNECTOR_HDMI_TYPE_A) ||
            (radeon_output->ConnectorType == CONNECTOR_HDMI_TYPE_B))
            disp_data.ucMisc |= PANEL_ENCODER_MISC_HDMI_TYPE;
          disp_data.usPixelClock = cpu_to_le16(clock / 10);
          if (radeon_output->active_device & (ATOM_DEVICE_LCD_SUPPORT)) {
            if (lvds_misc & (1 << 0))
                disp_data.ucMisc |= PANEL_ENCODER_MISC_DUAL;
            if (lvds_misc & (1 << 1))
                disp_data.ucMisc |= (1 << 1);
          } else {
            if (radeon_output->linkb)
                disp_data.ucMisc |= PANEL_ENCODER_MISC_TMDS_LINKB;
            if (clock > 165000)
                disp_data.ucMisc |= PANEL_ENCODER_MISC_DUAL;
            if (pScrn->rgbBits == 8)
                disp_data.ucMisc |= (1 << 1);
          }
          data.exec.pspace = &disp_data;
          break;
      case 2:
      case 3:
          disp_data2.ucMisc = 0;
          disp_data2.ucAction = action;
          if (minor == 3) {
            if (radeon_output->coherent_mode) {
                disp_data2.ucMisc |= PANEL_ENCODER_MISC_COHERENT;
                xf86DrvMsg(output->scrn->scrnIndex, X_INFO, "Coherent Mode enabled\n");
            }
          }
          if ((radeon_output->ConnectorType == CONNECTOR_HDMI_TYPE_A) ||
            (radeon_output->ConnectorType == CONNECTOR_HDMI_TYPE_B))
            disp_data2.ucMisc |= PANEL_ENCODER_MISC_HDMI_TYPE;
          disp_data2.usPixelClock = cpu_to_le16(clock / 10);
          disp_data2.ucTruncate = 0;
          disp_data2.ucSpatial = 0;
          disp_data2.ucTemporal = 0;
          disp_data2.ucFRC = 0;
          if (radeon_output->active_device & (ATOM_DEVICE_LCD_SUPPORT)) {
            if (lvds_misc & (1 << 0))
                disp_data2.ucMisc |= PANEL_ENCODER_MISC_DUAL;
            if (lvds_misc & (1 << 5)) {
                disp_data2.ucSpatial = PANEL_ENCODER_SPATIAL_DITHER_EN;
                if (lvds_misc & (1 << 1))
                  disp_data2.ucSpatial |= PANEL_ENCODER_SPATIAL_DITHER_DEPTH;
            }
            if (lvds_misc & (1 << 6)) {
                disp_data2.ucTemporal = PANEL_ENCODER_TEMPORAL_DITHER_EN;
                if (lvds_misc & (1 << 1))
                  disp_data2.ucTemporal |= PANEL_ENCODER_TEMPORAL_DITHER_DEPTH;
                if (((lvds_misc >> 2) & 0x3) == 2)
                  disp_data2.ucTemporal |= PANEL_ENCODER_TEMPORAL_LEVEL_4;
            }
          } else {
            if (radeon_output->linkb)
                disp_data2.ucMisc |= PANEL_ENCODER_MISC_TMDS_LINKB;
            if (clock > 165000)
                disp_data2.ucMisc |= PANEL_ENCODER_MISC_DUAL;
          }
          data.exec.pspace = &disp_data2;
          break;
      default:
          ErrorF("Unknown table version\n");
          exit(-1);
      }
      break;
    default:
      ErrorF("Unknown table version\n");
      exit(-1);
    }

    data.exec.index = index;
    data.exec.dataSpace = (void *)&space;

    if (RHDAtomBiosFunc(info->atomBIOS->scrnIndex, info->atomBIOS, ATOMBIOS_EXEC, &data) == ATOM_SUCCESS) {
      ErrorF("Output digital setup success\n");
      return ATOM_SUCCESS;
    }

    ErrorF("Output digital setup failed\n");
    return ATOM_NOT_IMPLEMENTED;
}

static int
atombios_maybe_hdmi_mode(xf86OutputPtr output)
{
#ifndef EDID_COMPLETE_RAWDATA
    /* there's no getting this right unless we have complete EDID */
    return ATOM_ENCODER_MODE_HDMI;
#else
    if (output && xf86MonitorIsHDMI(output->MonInfo))
      return ATOM_ENCODER_MODE_HDMI;

    return ATOM_ENCODER_MODE_DVI;
#endif
}

int
atombios_get_encoder_mode(xf86OutputPtr output)
{
    RADEONOutputPrivatePtr radeon_output = output->driver_private;

    /* DVI should really be atombios_maybe_hdmi_mode() as well */
    switch (radeon_output->ConnectorType) {
    case CONNECTOR_DVI_I:
      if (radeon_output->active_device & (ATOM_DEVICE_DFP_SUPPORT))
          return ATOM_ENCODER_MODE_DVI;
      else
          return ATOM_ENCODER_MODE_CRT;
      break;
    case CONNECTOR_DVI_D:
    default:
      return ATOM_ENCODER_MODE_DVI;
      break;
    case CONNECTOR_HDMI_TYPE_A:
    case CONNECTOR_HDMI_TYPE_B:
      return atombios_maybe_hdmi_mode(output);
      break;
    case CONNECTOR_LVDS:
      return ATOM_ENCODER_MODE_LVDS;
      break;
    case CONNECTOR_DISPLAY_PORT:
      if (radeon_output->MonType == MT_DP)
          return ATOM_ENCODER_MODE_DP;
      else
          return atombios_maybe_hdmi_mode(output);
      break;
    case CONNECTOR_DVI_A:
    case CONNECTOR_VGA:
    case CONNECTOR_STV:
    case CONNECTOR_CTV:
    case CONNECTOR_DIN:
      if (radeon_output->active_device & (ATOM_DEVICE_TV_SUPPORT))
          return ATOM_ENCODER_MODE_TV;
      else if (radeon_output->active_device & (ATOM_DEVICE_CV_SUPPORT))
          return ATOM_ENCODER_MODE_CV;
      else
          return ATOM_ENCODER_MODE_CRT;
      break;
    }

}

static const int dp_clocks[] = {
    16200,
    27000,
    32400,
    54000,
    0,
    0,
    64800,
    108000,
};
static const int num_dp_clocks = sizeof(dp_clocks) / sizeof(int);

static int
dp_lanes_for_mode_clock(int mode_clock)
{
    int i;
    
    for (i = 0; i < num_dp_clocks; i++)
      if (dp_clocks[i] > (mode_clock / 10))
          return (i / 2) + 1;

    return 0;
}

static int
dp_link_clock_for_mode_clock(int mode_clock)
{
    int i;

    for (i = 0; i < num_dp_clocks; i++)
      if (dp_clocks[i] > (mode_clock / 10))
          return (dp_clocks[i % 2]);

    return 0;
}

static int
atombios_output_dig_encoder_setup(xf86OutputPtr output, int action)
{
    RADEONOutputPrivatePtr radeon_output = output->driver_private;
    RADEONInfoPtr info       = RADEONPTR(output->scrn);
    radeon_encoder_ptr radeon_encoder = radeon_get_encoder(output);
    DIG_ENCODER_CONTROL_PS_ALLOCATION disp_data;
    AtomBiosArgRec data;
    unsigned char *space;
    int index = 0, major, minor, num = 0;
    int clock = radeon_output->pixel_clock;
    int dig_block = radeon_output->dig_block;

    if (radeon_encoder == NULL)
      return ATOM_NOT_IMPLEMENTED;

    memset(&disp_data,0, sizeof(disp_data));

    if (IS_DCE32_VARIANT) {
      if (dig_block)
          index = GetIndexIntoMasterTable(COMMAND, DIG2EncoderControl);
      else
          index = GetIndexIntoMasterTable(COMMAND, DIG1EncoderControl);
      num = dig_block + 1;
    } else {
      switch (radeon_encoder->encoder_id) {
      case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
          index = GetIndexIntoMasterTable(COMMAND, DIG1EncoderControl);
          num = 1;
          break;
      case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA:
          index = GetIndexIntoMasterTable(COMMAND, DIG2EncoderControl);
          num = 2;
          break;
      }
    }

    atombios_get_command_table_version(info->atomBIOS, index, &major, &minor);

    disp_data.ucAction = action;
    disp_data.usPixelClock = cpu_to_le16(clock / 10);

    if (IS_DCE32_VARIANT) {
      switch (radeon_encoder->encoder_id) {
      case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
          disp_data.ucConfig = ATOM_ENCODER_CONFIG_V2_TRANSMITTER1;
          break;
      case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1:
          disp_data.ucConfig = ATOM_ENCODER_CONFIG_V2_TRANSMITTER2;
          break;
      case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2:
          disp_data.ucConfig = ATOM_ENCODER_CONFIG_V2_TRANSMITTER3;
          break;
      }
    } else {
      switch (radeon_encoder->encoder_id) {
      case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
          disp_data.ucConfig = ATOM_ENCODER_CONFIG_UNIPHY;
          break;
      case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA:
          disp_data.ucConfig = ATOM_ENCODER_CONFIG_LVTMA;
          break;
      }
    }

    disp_data.ucEncoderMode = atombios_get_encoder_mode(output);

    if (disp_data.ucEncoderMode == ATOM_ENCODER_MODE_DP) {
      if (radeon_output->linkb)
          disp_data.ucConfig |= ATOM_ENCODER_CONFIG_LINKB;
      else
          disp_data.ucConfig |= ATOM_ENCODER_CONFIG_LINKA;

      if (dp_link_clock_for_mode_clock(clock) == 27000)
          disp_data.ucConfig |= ATOM_ENCODER_CONFIG_DPLINKRATE_2_70GHZ;

      disp_data.ucLaneNum = dp_lanes_for_mode_clock(clock);
    } else if (clock > 165000) {
      disp_data.ucConfig |= ATOM_ENCODER_CONFIG_LINKA_B;
      disp_data.ucLaneNum = 8;
    } else {
      if (radeon_output->linkb)
          disp_data.ucConfig |= ATOM_ENCODER_CONFIG_LINKB;
      else
          disp_data.ucConfig |= ATOM_ENCODER_CONFIG_LINKA;

      disp_data.ucLaneNum = 4;
    }

    data.exec.index = index;
    data.exec.dataSpace = (void *)&space;
    data.exec.pspace = &disp_data;

    if (RHDAtomBiosFunc(info->atomBIOS->scrnIndex, info->atomBIOS, ATOMBIOS_EXEC, &data) == ATOM_SUCCESS) {
      ErrorF("Output DIG%d encoder setup success\n", num);
      return ATOM_SUCCESS;
    }

    ErrorF("Output DIG%d setup failed\n", num);
    return ATOM_NOT_IMPLEMENTED;

}

union dig_transmitter_control {
    DIG_TRANSMITTER_CONTROL_PS_ALLOCATION v1;
    DIG_TRANSMITTER_CONTROL_PARAMETERS_V2 v2;
};

static int
atombios_output_dig_transmitter_setup(xf86OutputPtr output, int action)
{
    RADEONOutputPrivatePtr radeon_output = output->driver_private;
    RADEONInfoPtr info       = RADEONPTR(output->scrn);
    radeon_encoder_ptr radeon_encoder = radeon_get_encoder(output);
    union dig_transmitter_control disp_data;
    AtomBiosArgRec data;
    unsigned char *space;
    int index = 0, num = 0;
    int major, minor;
    int clock = radeon_output->pixel_clock;
    int dig_block = radeon_output->dig_block;

    if (radeon_encoder == NULL)
        return ATOM_NOT_IMPLEMENTED;

    memset(&disp_data,0, sizeof(disp_data));

    if (IS_DCE32_VARIANT)
      index = GetIndexIntoMasterTable(COMMAND, UNIPHYTransmitterControl);
    else {
      switch (radeon_encoder->encoder_id) {
      case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
          index = GetIndexIntoMasterTable(COMMAND, DIG1TransmitterControl);
          break;
      case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA:
          index = GetIndexIntoMasterTable(COMMAND, DIG2TransmitterControl);
          break;
      }
    }

    atombios_get_command_table_version(info->atomBIOS, index, &major, &minor);

    disp_data.v1.ucAction = action;

    if (IS_DCE32_VARIANT) {
      if (radeon_output->MonType == MT_DP) {
          disp_data.v2.usPixelClock =
            cpu_to_le16(dp_link_clock_for_mode_clock(clock));
          disp_data.v2.acConfig.fDPConnector = 1;
      } else if (clock > 165000) {
          disp_data.v2.usPixelClock = cpu_to_le16((clock * 10 * 2) / 100);
          disp_data.v2.acConfig.fDualLinkConnector = 1;
      } else {
          disp_data.v2.usPixelClock = cpu_to_le16((clock * 10 * 4) / 100);
      }
      if (dig_block)
          disp_data.v2.acConfig.ucEncoderSel = 1;

      switch (radeon_encoder->encoder_id) {
      case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
          disp_data.v2.acConfig.ucTransmitterSel = 0;
          num = 0;
          break;
      case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1:
          disp_data.v2.acConfig.ucTransmitterSel = 1;
          num = 1;
          break;
      case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2:
          disp_data.v2.acConfig.ucTransmitterSel = 2;
          num = 2;
          break;
      }

      if (radeon_output->active_device & (ATOM_DEVICE_DFP_SUPPORT)) {
          if (radeon_output->coherent_mode) {
            disp_data.v2.acConfig.fCoherentMode = 1;
            xf86DrvMsg(output->scrn->scrnIndex, X_INFO, "UNIPHY%d transmitter: Coherent Mode enabled\n",disp_data.v2.acConfig.ucTransmitterSel);
          } else
            xf86DrvMsg(output->scrn->scrnIndex, X_INFO, "UNIPHY%d transmitter: Coherent Mode disabled\n",disp_data.v2.acConfig.ucTransmitterSel);
      }
    } else {
      disp_data.v1.ucConfig = ATOM_TRANSMITTER_CONFIG_CLKSRC_PPLL;

      if (radeon_output->MonType == MT_DP)
          disp_data.v1.usPixelClock =
            cpu_to_le16(dp_link_clock_for_mode_clock(clock));
      else
          disp_data.v1.usPixelClock = cpu_to_le16((clock) / 10);

      switch (radeon_encoder->encoder_id) {
      case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
          disp_data.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_DIG1_ENCODER;
          if (info->IsIGP) {
            if (clock > 165000) {
                disp_data.v1.ucConfig |= (ATOM_TRANSMITTER_CONFIG_8LANE_LINK |
                                    ATOM_TRANSMITTER_CONFIG_LINKA_B);

                if (radeon_output->igp_lane_info & 0x3)
                  disp_data.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LANE_0_7;
                else if (radeon_output->igp_lane_info & 0xc)
                  disp_data.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LANE_8_15;
            } else {
                disp_data.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LINKA;
                if (radeon_output->igp_lane_info & 0x1)
                  disp_data.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LANE_0_3;
                else if (radeon_output->igp_lane_info & 0x2)
                  disp_data.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LANE_4_7;
                else if (radeon_output->igp_lane_info & 0x4)
                  disp_data.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LANE_8_11;
                else if (radeon_output->igp_lane_info & 0x8)
                  disp_data.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LANE_12_15;
            }
          } else {
            if (clock > 165000)
                disp_data.v1.ucConfig |= (ATOM_TRANSMITTER_CONFIG_8LANE_LINK |
                                    ATOM_TRANSMITTER_CONFIG_LINKA_B |
                                    ATOM_TRANSMITTER_CONFIG_LANE_0_7);
            else {
                /* XXX */
                if (radeon_output->linkb)
                  disp_data.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LINKB | ATOM_TRANSMITTER_CONFIG_LANE_0_3;
                else
                  disp_data.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LINKA | ATOM_TRANSMITTER_CONFIG_LANE_0_3;
            }
          }
          break;
      case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA:
          disp_data.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_DIG2_ENCODER;
          if (clock > 165000)
            disp_data.v1.ucConfig |= (ATOM_TRANSMITTER_CONFIG_8LANE_LINK |
                                ATOM_TRANSMITTER_CONFIG_LINKA_B |
                                ATOM_TRANSMITTER_CONFIG_LANE_0_7);
          else {
            /* XXX */
            if (radeon_output->linkb)
                disp_data.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LINKB | ATOM_TRANSMITTER_CONFIG_LANE_0_3;
            else
                disp_data.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LINKA | ATOM_TRANSMITTER_CONFIG_LANE_0_3;
          }
          break;
      }

      if (radeon_output->active_device & (ATOM_DEVICE_DFP_SUPPORT)) {
          if (radeon_output->coherent_mode &&
            radeon_output->MonType != MT_DP) {
            disp_data.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_COHERENT;
            xf86DrvMsg(output->scrn->scrnIndex, X_INFO,
                  "DIG%d transmitter: Coherent Mode enabled\n", num);
          } else {
            xf86DrvMsg(output->scrn->scrnIndex, X_INFO,
                  "DIG%d transmitter: Coherent Mode disabled\n", num);
          }
      }
    }

    data.exec.index = index;
    data.exec.dataSpace = (void *)&space;
    data.exec.pspace = &disp_data;

    if (RHDAtomBiosFunc(info->atomBIOS->scrnIndex, info->atomBIOS, ATOMBIOS_EXEC, &data) == ATOM_SUCCESS) {
      if (IS_DCE32_VARIANT)
          ErrorF("Output UNIPHY%d transmitter setup success\n", num);
      else
         ErrorF("Output DIG%d transmitter setup success\n", num);
      return ATOM_SUCCESS;
    }

    ErrorF("Output DIG%d transmitter setup failed\n", num);
    return ATOM_NOT_IMPLEMENTED;

}

static void atom_rv515_force_tv_scaler(ScrnInfoPtr pScrn)
{
    RADEONInfoPtr info       = RADEONPTR(pScrn);
    unsigned char *RADEONMMIO = info->MMIO;

    OUTREG(0x659C,0x0);
    OUTREG(0x6594,0x705);
    OUTREG(0x65A4,0x10001);
    OUTREG(0x65D8,0x0);
    OUTREG(0x65B0,0x0);
    OUTREG(0x65C0,0x0);
    OUTREG(0x65D4,0x0);
    OUTREG(0x6578,0x0);
    OUTREG(0x657C,0x841880A8);
    OUTREG(0x6578,0x1);
    OUTREG(0x657C,0x84208680);
    OUTREG(0x6578,0x2);
    OUTREG(0x657C,0xBFF880B0);
    OUTREG(0x6578,0x100);
    OUTREG(0x657C,0x83D88088);
    OUTREG(0x6578,0x101);
    OUTREG(0x657C,0x84608680);
    OUTREG(0x6578,0x102);
    OUTREG(0x657C,0xBFF080D0);
    OUTREG(0x6578,0x200);
    OUTREG(0x657C,0x83988068);
    OUTREG(0x6578,0x201);
    OUTREG(0x657C,0x84A08680);
    OUTREG(0x6578,0x202);
    OUTREG(0x657C,0xBFF080F8);
    OUTREG(0x6578,0x300);
    OUTREG(0x657C,0x83588058);
    OUTREG(0x6578,0x301);
    OUTREG(0x657C,0x84E08660);
    OUTREG(0x6578,0x302);
    OUTREG(0x657C,0xBFF88120);
    OUTREG(0x6578,0x400);
    OUTREG(0x657C,0x83188040);
    OUTREG(0x6578,0x401);
    OUTREG(0x657C,0x85008660);
    OUTREG(0x6578,0x402);
    OUTREG(0x657C,0xBFF88150);
    OUTREG(0x6578,0x500);
    OUTREG(0x657C,0x82D88030);
    OUTREG(0x6578,0x501);
    OUTREG(0x657C,0x85408640);
    OUTREG(0x6578,0x502);
    OUTREG(0x657C,0xBFF88180);
    OUTREG(0x6578,0x600);
    OUTREG(0x657C,0x82A08018);
    OUTREG(0x6578,0x601);
    OUTREG(0x657C,0x85808620);
    OUTREG(0x6578,0x602);
    OUTREG(0x657C,0xBFF081B8);
    OUTREG(0x6578,0x700);
    OUTREG(0x657C,0x82608010);
    OUTREG(0x6578,0x701);
    OUTREG(0x657C,0x85A08600);
    OUTREG(0x6578,0x702);
    OUTREG(0x657C,0x800081F0);
    OUTREG(0x6578,0x800);
    OUTREG(0x657C,0x8228BFF8);
    OUTREG(0x6578,0x801);
    OUTREG(0x657C,0x85E085E0);
    OUTREG(0x6578,0x802);
    OUTREG(0x657C,0xBFF88228);
    OUTREG(0x6578,0x10000);
    OUTREG(0x657C,0x82A8BF00);
    OUTREG(0x6578,0x10001);
    OUTREG(0x657C,0x82A08CC0);
    OUTREG(0x6578,0x10002);
    OUTREG(0x657C,0x8008BEF8);
    OUTREG(0x6578,0x10100);
    OUTREG(0x657C,0x81F0BF28);
    OUTREG(0x6578,0x10101);
    OUTREG(0x657C,0x83608CA0);
    OUTREG(0x6578,0x10102);
    OUTREG(0x657C,0x8018BED0);
    OUTREG(0x6578,0x10200);
    OUTREG(0x657C,0x8148BF38);
    OUTREG(0x6578,0x10201);
    OUTREG(0x657C,0x84408C80);
    OUTREG(0x6578,0x10202);
    OUTREG(0x657C,0x8008BEB8);
    OUTREG(0x6578,0x10300);
    OUTREG(0x657C,0x80B0BF78);
    OUTREG(0x6578,0x10301);
    OUTREG(0x657C,0x85008C20);
    OUTREG(0x6578,0x10302);
    OUTREG(0x657C,0x8020BEA0);
    OUTREG(0x6578,0x10400);
    OUTREG(0x657C,0x8028BF90);
    OUTREG(0x6578,0x10401);
    OUTREG(0x657C,0x85E08BC0);
    OUTREG(0x6578,0x10402);
    OUTREG(0x657C,0x8018BE90);
    OUTREG(0x6578,0x10500);
    OUTREG(0x657C,0xBFB8BFB0);
    OUTREG(0x6578,0x10501);
    OUTREG(0x657C,0x86C08B40);
    OUTREG(0x6578,0x10502);
    OUTREG(0x657C,0x8010BE90);
    OUTREG(0x6578,0x10600);
    OUTREG(0x657C,0xBF58BFC8);
    OUTREG(0x6578,0x10601);
    OUTREG(0x657C,0x87A08AA0);
    OUTREG(0x6578,0x10602);
    OUTREG(0x657C,0x8010BE98);
    OUTREG(0x6578,0x10700);
    OUTREG(0x657C,0xBF10BFF0);
    OUTREG(0x6578,0x10701);
    OUTREG(0x657C,0x886089E0);
    OUTREG(0x6578,0x10702);
    OUTREG(0x657C,0x8018BEB0);
    OUTREG(0x6578,0x10800);
    OUTREG(0x657C,0xBED8BFE8);
    OUTREG(0x6578,0x10801);
    OUTREG(0x657C,0x89408940);
    OUTREG(0x6578,0x10802);
    OUTREG(0x657C,0xBFE8BED8);
    OUTREG(0x6578,0x20000);
    OUTREG(0x657C,0x80008000);
    OUTREG(0x6578,0x20001);
    OUTREG(0x657C,0x90008000);
    OUTREG(0x6578,0x20002);
    OUTREG(0x657C,0x80008000);
    OUTREG(0x6578,0x20003);
    OUTREG(0x657C,0x80008000);
    OUTREG(0x6578,0x20100);
    OUTREG(0x657C,0x80108000);
    OUTREG(0x6578,0x20101);
    OUTREG(0x657C,0x8FE0BF70);
    OUTREG(0x6578,0x20102);
    OUTREG(0x657C,0xBFE880C0);
    OUTREG(0x6578,0x20103);
    OUTREG(0x657C,0x80008000);
    OUTREG(0x6578,0x20200);
    OUTREG(0x657C,0x8018BFF8);
    OUTREG(0x6578,0x20201);
    OUTREG(0x657C,0x8F80BF08);
    OUTREG(0x6578,0x20202);
    OUTREG(0x657C,0xBFD081A0);
    OUTREG(0x6578,0x20203);
    OUTREG(0x657C,0xBFF88000);
    OUTREG(0x6578,0x20300);
    OUTREG(0x657C,0x80188000);
    OUTREG(0x6578,0x20301);
    OUTREG(0x657C,0x8EE0BEC0);
    OUTREG(0x6578,0x20302);
    OUTREG(0x657C,0xBFB082A0);
    OUTREG(0x6578,0x20303);
    OUTREG(0x657C,0x80008000);
    OUTREG(0x6578,0x20400);
    OUTREG(0x657C,0x80188000);
    OUTREG(0x6578,0x20401);
    OUTREG(0x657C,0x8E00BEA0);
    OUTREG(0x6578,0x20402);
    OUTREG(0x657C,0xBF8883C0);
    OUTREG(0x6578,0x20403);
    OUTREG(0x657C,0x80008000);
    OUTREG(0x6578,0x20500);
    OUTREG(0x657C,0x80188000);
    OUTREG(0x6578,0x20501);
    OUTREG(0x657C,0x8D00BE90);
    OUTREG(0x6578,0x20502);
    OUTREG(0x657C,0xBF588500);
    OUTREG(0x6578,0x20503);
    OUTREG(0x657C,0x80008008);
    OUTREG(0x6578,0x20600);
    OUTREG(0x657C,0x80188000);
    OUTREG(0x6578,0x20601);
    OUTREG(0x657C,0x8BC0BE98);
    OUTREG(0x6578,0x20602);
    OUTREG(0x657C,0xBF308660);
    OUTREG(0x6578,0x20603);
    OUTREG(0x657C,0x80008008);
    OUTREG(0x6578,0x20700);
    OUTREG(0x657C,0x80108000);
    OUTREG(0x6578,0x20701);
    OUTREG(0x657C,0x8A80BEB0);
    OUTREG(0x6578,0x20702);
    OUTREG(0x657C,0xBF0087C0);
    OUTREG(0x6578,0x20703);
    OUTREG(0x657C,0x80008008);
    OUTREG(0x6578,0x20800);
    OUTREG(0x657C,0x80108000);
    OUTREG(0x6578,0x20801);
    OUTREG(0x657C,0x8920BED0);
    OUTREG(0x6578,0x20802);
    OUTREG(0x657C,0xBED08920);
    OUTREG(0x6578,0x20803);
    OUTREG(0x657C,0x80008010);
    OUTREG(0x6578,0x30000);
    OUTREG(0x657C,0x90008000);
    OUTREG(0x6578,0x30001);
    OUTREG(0x657C,0x80008000);
    OUTREG(0x6578,0x30100);
    OUTREG(0x657C,0x8FE0BF90);
    OUTREG(0x6578,0x30101);
    OUTREG(0x657C,0xBFF880A0);
    OUTREG(0x6578,0x30200);
    OUTREG(0x657C,0x8F60BF40);
    OUTREG(0x6578,0x30201);
    OUTREG(0x657C,0xBFE88180);
    OUTREG(0x6578,0x30300);
    OUTREG(0x657C,0x8EC0BF00);
    OUTREG(0x6578,0x30301);
    OUTREG(0x657C,0xBFC88280);
    OUTREG(0x6578,0x30400);
    OUTREG(0x657C,0x8DE0BEE0);
    OUTREG(0x6578,0x30401);
    OUTREG(0x657C,0xBFA083A0);
    OUTREG(0x6578,0x30500);
    OUTREG(0x657C,0x8CE0BED0);
    OUTREG(0x6578,0x30501);
    OUTREG(0x657C,0xBF7884E0);
    OUTREG(0x6578,0x30600);
    OUTREG(0x657C,0x8BA0BED8);
    OUTREG(0x6578,0x30601);
    OUTREG(0x657C,0xBF508640);
    OUTREG(0x6578,0x30700);
    OUTREG(0x657C,0x8A60BEE8);
    OUTREG(0x6578,0x30701);
    OUTREG(0x657C,0xBF2087A0);
    OUTREG(0x6578,0x30800);
    OUTREG(0x657C,0x8900BF00);
    OUTREG(0x6578,0x30801);
    OUTREG(0x657C,0xBF008900);
}

static int
atombios_output_yuv_setup(xf86OutputPtr output, Bool enable)
{
    RADEONOutputPrivatePtr radeon_output = output->driver_private;
    RADEONInfoPtr info       = RADEONPTR(output->scrn);
    RADEONCrtcPrivatePtr radeon_crtc = output->crtc->driver_private;
    ENABLE_YUV_PS_ALLOCATION disp_data;
    AtomBiosArgRec data;
    unsigned char *space;
    unsigned char *RADEONMMIO = info->MMIO;
    uint32_t temp, reg;

    if (info->ChipFamily >= CHIP_FAMILY_R600)
      reg = R600_BIOS_3_SCRATCH;
    else
      reg = RADEON_BIOS_3_SCRATCH;

    //fix up scratch reg handling
    temp = INREG(reg);
    if (radeon_output->active_device & (ATOM_DEVICE_TV_SUPPORT))
      OUTREG(reg, (ATOM_S3_TV1_ACTIVE |
                 (radeon_crtc->crtc_id << 18)));
    else if (radeon_output->active_device & (ATOM_DEVICE_CV_SUPPORT))
      OUTREG(reg, (ATOM_S3_CV_ACTIVE |
                 (radeon_crtc->crtc_id << 24)));
    else
      OUTREG(reg, 0);

    memset(&disp_data, 0, sizeof(disp_data));

    if (enable)
      disp_data.ucEnable = ATOM_ENABLE;
    disp_data.ucCRTC = radeon_crtc->crtc_id;

    data.exec.index = GetIndexIntoMasterTable(COMMAND, EnableYUV);
    data.exec.dataSpace = (void *)&space;
    data.exec.pspace = &disp_data;

    if (RHDAtomBiosFunc(info->atomBIOS->scrnIndex, info->atomBIOS, ATOMBIOS_EXEC, &data) == ATOM_SUCCESS) {

      OUTREG(reg, temp);

      ErrorF("crtc %d YUV %s setup success\n", radeon_crtc->crtc_id, enable ? "enable" : "disable");
      return ATOM_SUCCESS;
    }

    OUTREG(reg, temp);

    ErrorF("crtc %d YUV %s setup failed\n", radeon_crtc->crtc_id, enable ? "enable" : "disable");
    return ATOM_NOT_IMPLEMENTED;

}

static int
atombios_output_overscan_setup(xf86OutputPtr output, DisplayModePtr mode, DisplayModePtr adjusted_mode)
{
    RADEONOutputPrivatePtr radeon_output = output->driver_private;
    RADEONCrtcPrivatePtr radeon_crtc = output->crtc->driver_private;
    RADEONInfoPtr info       = RADEONPTR(output->scrn);
    SET_CRTC_OVERSCAN_PS_ALLOCATION overscan_param;
    AtomBiosArgRec data;
    unsigned char *space;
    memset(&overscan_param, 0, sizeof(overscan_param));

    overscan_param.usOverscanRight = 0;
    overscan_param.usOverscanLeft = 0;
    overscan_param.usOverscanBottom = 0;
    overscan_param.usOverscanTop = 0;
    overscan_param.ucCRTC = radeon_crtc->crtc_id;

    if (radeon_output->Flags & RADEON_USE_RMX) {
      if (radeon_output->rmx_type == RMX_FULL) {
          overscan_param.usOverscanRight = 0;
          overscan_param.usOverscanLeft = 0;
          overscan_param.usOverscanBottom = 0;
          overscan_param.usOverscanTop = 0;
      } else if (radeon_output->rmx_type == RMX_CENTER) {
          overscan_param.usOverscanTop = (adjusted_mode->CrtcVDisplay - mode->CrtcVDisplay) / 2;
          overscan_param.usOverscanBottom = (adjusted_mode->CrtcVDisplay - mode->CrtcVDisplay) / 2;
          overscan_param.usOverscanLeft = (adjusted_mode->CrtcHDisplay - mode->CrtcHDisplay) / 2;
          overscan_param.usOverscanRight = (adjusted_mode->CrtcHDisplay - mode->CrtcHDisplay) / 2;
      } else if (radeon_output->rmx_type == RMX_ASPECT) {
          int a1 = mode->CrtcVDisplay * adjusted_mode->CrtcHDisplay;
          int a2 = adjusted_mode->CrtcVDisplay * mode->CrtcHDisplay;

          if (a1 > a2) {
            overscan_param.usOverscanLeft = (adjusted_mode->CrtcHDisplay - (a2 / mode->CrtcVDisplay)) / 2;
            overscan_param.usOverscanRight = (adjusted_mode->CrtcHDisplay - (a2 / mode->CrtcVDisplay)) / 2;
          } else if (a2 > a1) {
            overscan_param.usOverscanLeft = (adjusted_mode->CrtcVDisplay - (a1 / mode->CrtcHDisplay)) / 2;
            overscan_param.usOverscanRight = (adjusted_mode->CrtcVDisplay - (a1 / mode->CrtcHDisplay)) / 2;
          }
      }
    }

    data.exec.index = GetIndexIntoMasterTable(COMMAND, SetCRTC_OverScan);
    data.exec.dataSpace = (void *)&space;
    data.exec.pspace = &overscan_param;

    if (RHDAtomBiosFunc(info->atomBIOS->scrnIndex, info->atomBIOS, ATOMBIOS_EXEC, &data) == ATOM_SUCCESS) {
      ErrorF("Set CRTC %d Overscan success\n", radeon_crtc->crtc_id);
      return ATOM_SUCCESS ;
    }

    ErrorF("Set CRTC %d Overscan failed\n", radeon_crtc->crtc_id);
    return ATOM_NOT_IMPLEMENTED;
}

static int
atombios_output_scaler_setup(xf86OutputPtr output)
{
    RADEONInfoPtr info       = RADEONPTR(output->scrn);
    RADEONOutputPrivatePtr radeon_output = output->driver_private;
    radeon_tvout_ptr tvout = &radeon_output->tvout;
    RADEONCrtcPrivatePtr radeon_crtc = output->crtc->driver_private;
    ENABLE_SCALER_PS_ALLOCATION disp_data;
    AtomBiosArgRec data;
    unsigned char *space;

    if (!IS_AVIVO_VARIANT && radeon_crtc->crtc_id)
      return ATOM_SUCCESS;

    memset(&disp_data, 0, sizeof(disp_data));

    disp_data.ucScaler = radeon_crtc->crtc_id;

    if (radeon_output->active_device & (ATOM_DEVICE_TV_SUPPORT)) {
      switch (tvout->tvStd) {
      case TV_STD_NTSC:
          disp_data.ucTVStandard = ATOM_TV_NTSC;
          break;
      case TV_STD_PAL:
          disp_data.ucTVStandard = ATOM_TV_PAL;
          break;
      case TV_STD_PAL_M:
          disp_data.ucTVStandard = ATOM_TV_PALM;
          break;
      case TV_STD_PAL_60:
          disp_data.ucTVStandard = ATOM_TV_PAL60;
          break;
      case TV_STD_NTSC_J:
          disp_data.ucTVStandard = ATOM_TV_NTSCJ;
          break;
      case TV_STD_SCART_PAL:
          disp_data.ucTVStandard = ATOM_TV_PAL; /* ??? */
          break;
      case TV_STD_SECAM:
          disp_data.ucTVStandard = ATOM_TV_SECAM;
          break;
      case TV_STD_PAL_CN:
          disp_data.ucTVStandard = ATOM_TV_PALCN;
          break;
      default:
          disp_data.ucTVStandard = ATOM_TV_NTSC;
          break;
      }
      disp_data.ucEnable = SCALER_ENABLE_MULTITAP_MODE;
        ErrorF("Using TV scaler %x %x\n", disp_data.ucTVStandard, disp_data.ucEnable);
    } else if (radeon_output->active_device & (ATOM_DEVICE_CV_SUPPORT)) {
      disp_data.ucTVStandard = ATOM_TV_CV;
      disp_data.ucEnable = SCALER_ENABLE_MULTITAP_MODE;
        ErrorF("Using CV scaler %x %x\n", disp_data.ucTVStandard, disp_data.ucEnable);
    } else if (radeon_output->Flags & RADEON_USE_RMX) {
      ErrorF("Using RMX\n");
      if (radeon_output->rmx_type == RMX_FULL)
          disp_data.ucEnable = ATOM_SCALER_EXPANSION;
      else if (radeon_output->rmx_type == RMX_CENTER)
          disp_data.ucEnable = ATOM_SCALER_CENTER;
      else if (radeon_output->rmx_type == RMX_ASPECT)
          disp_data.ucEnable = ATOM_SCALER_EXPANSION;
    } else {
      ErrorF("Not using RMX\n");
      if (IS_AVIVO_VARIANT)
          disp_data.ucEnable = ATOM_SCALER_DISABLE;
      else
          disp_data.ucEnable = ATOM_SCALER_CENTER;
    }

    data.exec.index = GetIndexIntoMasterTable(COMMAND, EnableScaler);
    data.exec.dataSpace = (void *)&space;
    data.exec.pspace = &disp_data;

    if (RHDAtomBiosFunc(info->atomBIOS->scrnIndex, info->atomBIOS, ATOMBIOS_EXEC, &data) == ATOM_SUCCESS) {
      if (radeon_output->active_device & (ATOM_DEVICE_CV_SUPPORT | ATOM_DEVICE_TV_SUPPORT)
          && info->ChipFamily >= CHIP_FAMILY_RV515 && info->ChipFamily <= CHIP_FAMILY_RV570) {
          ErrorF("forcing TV scaler\n");
          atom_rv515_force_tv_scaler(output->scrn);
      }
      ErrorF("scaler %d setup success\n", radeon_crtc->crtc_id);
      return ATOM_SUCCESS;
    }

    ErrorF("scaler %d setup failed\n", radeon_crtc->crtc_id);
    return ATOM_NOT_IMPLEMENTED;

}

void
atombios_output_dpms(xf86OutputPtr output, int mode)
{
    RADEONOutputPrivatePtr radeon_output = output->driver_private;
    radeon_encoder_ptr radeon_encoder = radeon_get_encoder(output);
    RADEONInfoPtr info       = RADEONPTR(output->scrn);
    DISPLAY_DEVICE_OUTPUT_CONTROL_PS_ALLOCATION disp_data;
    AtomBiosArgRec data;
    unsigned char *space;
    int index = 0;
    Bool is_dig = FALSE;

    if (radeon_encoder == NULL)
        return;

    switch (radeon_encoder->encoder_id) {
    case ENCODER_OBJECT_ID_INTERNAL_TMDS1:
    case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1:
      index = GetIndexIntoMasterTable(COMMAND, TMDSAOutputControl);
      break;
    case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
    case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1:
    case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2:
    case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA:
      is_dig = TRUE;
      break;
    case ENCODER_OBJECT_ID_INTERNAL_DVO1:
    case ENCODER_OBJECT_ID_INTERNAL_DDI:
    case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1:
      index = GetIndexIntoMasterTable(COMMAND, DVOOutputControl);
      break;
    case ENCODER_OBJECT_ID_INTERNAL_LVDS:
      index = GetIndexIntoMasterTable(COMMAND, LCD1OutputControl);
      break;
    case ENCODER_OBJECT_ID_INTERNAL_LVTM1:
      if (radeon_output->active_device & (ATOM_DEVICE_LCD_SUPPORT))
          index = GetIndexIntoMasterTable(COMMAND, LCD1OutputControl);
      else
          index = GetIndexIntoMasterTable(COMMAND, LVTMAOutputControl);
      break;
    case ENCODER_OBJECT_ID_INTERNAL_DAC1:
    case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1:
      if (radeon_output->active_device & (ATOM_DEVICE_TV_SUPPORT))
          index = GetIndexIntoMasterTable(COMMAND, TV1OutputControl);
      else if (radeon_output->active_device & (ATOM_DEVICE_CV_SUPPORT))
          index = GetIndexIntoMasterTable(COMMAND, CV1OutputControl);
      else
          index = GetIndexIntoMasterTable(COMMAND, DAC1OutputControl);
      break;
    case ENCODER_OBJECT_ID_INTERNAL_DAC2:
    case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC2:
      if (radeon_output->active_device & (ATOM_DEVICE_TV_SUPPORT))
          index = GetIndexIntoMasterTable(COMMAND, TV1OutputControl);
      else if (radeon_output->active_device & (ATOM_DEVICE_CV_SUPPORT))
          index = GetIndexIntoMasterTable(COMMAND, CV1OutputControl);
      else
          index = GetIndexIntoMasterTable(COMMAND, DAC2OutputControl);
      break;
    }

    switch (mode) {
    case DPMSModeOn:
      radeon_encoder->devices |= radeon_output->active_device;
      if (is_dig)
          atombios_output_dig_transmitter_setup(output, ATOM_TRANSMITTER_ACTION_ENABLE_OUTPUT);
      else {
          disp_data.ucAction = ATOM_ENABLE;
          data.exec.index = index;
          data.exec.dataSpace = (void *)&space;
          data.exec.pspace = &disp_data;

          if (RHDAtomBiosFunc(info->atomBIOS->scrnIndex, info->atomBIOS, ATOMBIOS_EXEC, &data) == ATOM_SUCCESS)
            ErrorF("Output %s enable success\n",
                   device_name[radeon_get_device_index(radeon_output->active_device)]);
          else
            ErrorF("Output %s enable failed\n",
                   device_name[radeon_get_device_index(radeon_output->active_device)]);
      }
      break;
    case DPMSModeStandby:
    case DPMSModeSuspend:
    case DPMSModeOff:
      radeon_encoder->devices &= ~(radeon_output->active_device);
      if (!radeon_encoder->devices) {
          if (is_dig)
            atombios_output_dig_transmitter_setup(output, ATOM_TRANSMITTER_ACTION_DISABLE_OUTPUT);
          else {
            disp_data.ucAction = ATOM_DISABLE;
            data.exec.index = index;
            data.exec.dataSpace = (void *)&space;
            data.exec.pspace = &disp_data;

            if (RHDAtomBiosFunc(info->atomBIOS->scrnIndex, info->atomBIOS, ATOMBIOS_EXEC, &data)
                == ATOM_SUCCESS)
                ErrorF("Output %s disable success\n",
                     device_name[radeon_get_device_index(radeon_output->active_device)]);
            else
                ErrorF("Output %s disable failed\n",
                     device_name[radeon_get_device_index(radeon_output->active_device)]);
          }
      }
      break;
    }
}

static void
atombios_set_output_crtc_source(xf86OutputPtr output)
{
    RADEONOutputPrivatePtr radeon_output = output->driver_private;
    RADEONCrtcPrivatePtr radeon_crtc = output->crtc->driver_private;
    RADEONInfoPtr info       = RADEONPTR(output->scrn);
    radeon_encoder_ptr radeon_encoder = radeon_get_encoder(output);
    AtomBiosArgRec data;
    unsigned char *space;
    SELECT_CRTC_SOURCE_PS_ALLOCATION crtc_src_param;
    SELECT_CRTC_SOURCE_PARAMETERS_V2 crtc_src_param2;
    int index = GetIndexIntoMasterTable(COMMAND, SelectCRTC_Source);
    int major, minor;

    if (radeon_encoder == NULL)
      return;

    memset(&crtc_src_param, 0, sizeof(crtc_src_param));
    memset(&crtc_src_param2, 0, sizeof(crtc_src_param2));
    atombios_get_command_table_version(info->atomBIOS, index, &major, &minor);

    /*ErrorF("select crtc source table is %d %d\n", major, minor);*/

    switch(major) {
    case 1:
      switch(minor) {
      case 0:
      case 1:
      default:
          if (IS_AVIVO_VARIANT)
            crtc_src_param.ucCRTC = radeon_crtc->crtc_id;
          else {
            if (radeon_encoder->encoder_id == ENCODER_OBJECT_ID_INTERNAL_DAC1)
                crtc_src_param.ucCRTC = radeon_crtc->crtc_id;
            else
                crtc_src_param.ucCRTC = radeon_crtc->crtc_id << 2;
          }
          switch (radeon_encoder->encoder_id) {
          case ENCODER_OBJECT_ID_INTERNAL_TMDS1:
          case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1:
            crtc_src_param.ucDevice = ATOM_DEVICE_DFP1_INDEX;
            break;
          case ENCODER_OBJECT_ID_INTERNAL_LVDS:
          case ENCODER_OBJECT_ID_INTERNAL_LVTM1:
            if (radeon_output->active_device & ATOM_DEVICE_LCD1_SUPPORT)
                crtc_src_param.ucDevice = ATOM_DEVICE_LCD1_INDEX;
            else
                crtc_src_param.ucDevice = ATOM_DEVICE_DFP3_INDEX;
            break;
          case ENCODER_OBJECT_ID_INTERNAL_DVO1:
          case ENCODER_OBJECT_ID_INTERNAL_DDI:
          case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1:
            crtc_src_param.ucDevice = ATOM_DEVICE_DFP2_INDEX;
            break;
          case ENCODER_OBJECT_ID_INTERNAL_DAC1:
          case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1:
            if (radeon_output->active_device & (ATOM_DEVICE_TV_SUPPORT))
                crtc_src_param.ucDevice = ATOM_DEVICE_TV1_INDEX;
            else if (radeon_output->active_device & (ATOM_DEVICE_CV_SUPPORT))
                crtc_src_param.ucDevice = ATOM_DEVICE_CV_INDEX;
            else
                crtc_src_param.ucDevice = ATOM_DEVICE_CRT1_INDEX;
            break;
          case ENCODER_OBJECT_ID_INTERNAL_DAC2:
          case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC2:
            if (radeon_output->active_device & (ATOM_DEVICE_TV_SUPPORT))
                crtc_src_param.ucDevice = ATOM_DEVICE_TV1_INDEX;
            else if (radeon_output->active_device & (ATOM_DEVICE_CV_SUPPORT))
                crtc_src_param.ucDevice = ATOM_DEVICE_CV_INDEX;
            else
                crtc_src_param.ucDevice = ATOM_DEVICE_CRT2_INDEX;
            break;
          }
          data.exec.pspace = &crtc_src_param;
          /*ErrorF("device sourced: 0x%x\n", crtc_src_param.ucDevice);*/
          break;
      case 2:
          crtc_src_param2.ucCRTC = radeon_crtc->crtc_id;
          crtc_src_param2.ucEncodeMode = atombios_get_encoder_mode(output);
          switch (radeon_encoder->encoder_id) {
          case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
          case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1:
          case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2:
            if (IS_DCE32_VARIANT) {
                if (radeon_crtc->crtc_id)
                  crtc_src_param2.ucEncoderID = ASIC_INT_DIG2_ENCODER_ID;
                else
                  crtc_src_param2.ucEncoderID = ASIC_INT_DIG1_ENCODER_ID;
            } else
                crtc_src_param2.ucEncoderID = ASIC_INT_DIG1_ENCODER_ID;
            break;
          case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA:
            crtc_src_param2.ucEncoderID = ASIC_INT_DIG2_ENCODER_ID;
            break;
          case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1:
            if (radeon_output->active_device & (ATOM_DEVICE_TV_SUPPORT))
                crtc_src_param2.ucEncoderID = ASIC_INT_TV_ENCODER_ID;
            else if (radeon_output->active_device & (ATOM_DEVICE_CV_SUPPORT))
                crtc_src_param2.ucEncoderID = ASIC_INT_TV_ENCODER_ID;
            else
                crtc_src_param2.ucEncoderID = ASIC_INT_DAC1_ENCODER_ID;
            break;
          case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC2:
            if (radeon_output->active_device & (ATOM_DEVICE_TV_SUPPORT))
                crtc_src_param2.ucEncoderID = ASIC_INT_TV_ENCODER_ID;
            else if (radeon_output->active_device & (ATOM_DEVICE_CV_SUPPORT))
                crtc_src_param2.ucEncoderID = ASIC_INT_TV_ENCODER_ID;
            else
                crtc_src_param2.ucEncoderID = ASIC_INT_DAC2_ENCODER_ID;
            break;
          }
          data.exec.pspace = &crtc_src_param2;
          /*ErrorF("device sourced: 0x%x\n", crtc_src_param2.ucEncoderID);*/
          break;
      }
      break;
    default:
      ErrorF("Unknown table version\n");
      exit(-1);
    }

    data.exec.index = index;
    data.exec.dataSpace = (void *)&space;

    if (RHDAtomBiosFunc(info->atomBIOS->scrnIndex, info->atomBIOS, ATOMBIOS_EXEC, &data) == ATOM_SUCCESS) {
      ErrorF("Set CRTC %d Source success\n", radeon_crtc->crtc_id);
      return;
    }

    ErrorF("Set CRTC Source failed\n");
    return;
}

static void
atombios_apply_output_quirks(xf86OutputPtr output, DisplayModePtr mode)
{
    RADEONOutputPrivatePtr radeon_output = output->driver_private;
    RADEONCrtcPrivatePtr radeon_crtc = output->crtc->driver_private;
    RADEONInfoPtr info       = RADEONPTR(output->scrn);
    unsigned char *RADEONMMIO = info->MMIO;

    /* Funky macbooks */
    if ((info->Chipset == PCI_CHIP_RV530_71C5) &&
      (PCI_SUB_VENDOR_ID(info->PciInfo) == 0x106b) &&
      (PCI_SUB_DEVICE_ID(info->PciInfo) == 0x0080)) {
      if (radeon_output->MonType == MT_LCD) {
          if (radeon_output->devices & ATOM_DEVICE_LCD1_SUPPORT) {
            uint32_t lvtma_bit_depth_control = INREG(AVIVO_LVTMA_BIT_DEPTH_CONTROL);

            lvtma_bit_depth_control &= ~AVIVO_LVTMA_BIT_DEPTH_CONTROL_TRUNCATE_EN;
            lvtma_bit_depth_control &= ~AVIVO_LVTMA_BIT_DEPTH_CONTROL_SPATIAL_DITHER_EN;

            OUTREG(AVIVO_LVTMA_BIT_DEPTH_CONTROL, lvtma_bit_depth_control);
          }
      }
    }

    /* set scaler clears this on some chips */
    if (IS_AVIVO_VARIANT && (mode->Flags & V_INTERLACE))
      OUTREG(AVIVO_D1MODE_DATA_FORMAT + radeon_crtc->crtc_offset, AVIVO_D1MODE_INTERLEAVE_EN);
}

void
atombios_output_mode_set(xf86OutputPtr output,
                   DisplayModePtr mode,
                   DisplayModePtr adjusted_mode)
{
    RADEONOutputPrivatePtr radeon_output = output->driver_private;
    RADEONCrtcPrivatePtr radeon_crtc = output->crtc->driver_private;
    radeon_encoder_ptr radeon_encoder = radeon_get_encoder(output);
    RADEONInfoPtr info       = RADEONPTR(output->scrn);
    if (radeon_encoder == NULL)
        return;

    radeon_output->pixel_clock = adjusted_mode->Clock;
    radeon_output->dig_block = radeon_crtc->crtc_id;
    atombios_output_overscan_setup(output, mode, adjusted_mode);
    atombios_output_scaler_setup(output);
    atombios_set_output_crtc_source(output);

    if (IS_AVIVO_VARIANT) {
      if (radeon_output->active_device & (ATOM_DEVICE_CV_SUPPORT | ATOM_DEVICE_TV_SUPPORT))
          atombios_output_yuv_setup(output, TRUE);
      else
          atombios_output_yuv_setup(output, FALSE);
    }

    switch (radeon_encoder->encoder_id) {
    case ENCODER_OBJECT_ID_INTERNAL_TMDS1:
    case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1:
    case ENCODER_OBJECT_ID_INTERNAL_LVDS:
    case ENCODER_OBJECT_ID_INTERNAL_LVTM1:
      atombios_output_digital_setup(output, PANEL_ENCODER_ACTION_ENABLE);
      break;
    case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
    case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1:
    case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2:
    case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA:
      /* disable encoder and transmitter */
      atombios_output_dig_transmitter_setup(output, ATOM_TRANSMITTER_ACTION_DISABLE);
      atombios_output_dig_encoder_setup(output, ATOM_DISABLE);

      /* setup and enable the encoder and transmitter */
      atombios_output_dig_encoder_setup(output, ATOM_ENABLE);
      atombios_output_dig_transmitter_setup(output, ATOM_TRANSMITTER_ACTION_SETUP);
      atombios_output_dig_transmitter_setup(output, ATOM_TRANSMITTER_ACTION_ENABLE);
      break;
    case ENCODER_OBJECT_ID_INTERNAL_DDI:
      atombios_output_ddia_setup(output, ATOM_ENABLE);
      break;
    case ENCODER_OBJECT_ID_INTERNAL_DVO1:
    case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1:
      atombios_external_tmds_setup(output, ATOM_ENABLE);
      break;
    case ENCODER_OBJECT_ID_INTERNAL_DAC1:
    case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1:
    case ENCODER_OBJECT_ID_INTERNAL_DAC2:
    case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC2:
      atombios_output_dac_setup(output, ATOM_ENABLE);
      if (radeon_output->active_device & (ATOM_DEVICE_TV_SUPPORT | ATOM_DEVICE_CV_SUPPORT))
          atombios_output_tv_setup(output, ATOM_ENABLE);
      break;
    }
    atombios_apply_output_quirks(output, adjusted_mode);
}

static AtomBiosResult
atom_bios_dac_load_detect(atomBiosHandlePtr atomBIOS, xf86OutputPtr output)
{
    RADEONOutputPrivatePtr radeon_output = output->driver_private;
    RADEONInfoPtr info       = RADEONPTR(output->scrn);
    DAC_LOAD_DETECTION_PS_ALLOCATION dac_data;
    AtomBiosArgRec data;
    unsigned char *space;
    int major, minor;
    int index = GetIndexIntoMasterTable(COMMAND, DAC_LoadDetection);

    atombios_get_command_table_version(info->atomBIOS, index, &major, &minor);

    dac_data.sDacload.ucMisc = 0;

    if (radeon_output->devices & ATOM_DEVICE_CRT1_SUPPORT) {
      dac_data.sDacload.usDeviceID = cpu_to_le16(ATOM_DEVICE_CRT1_SUPPORT);
      if (info->encoders[ATOM_DEVICE_CRT1_INDEX] &&
          ((info->encoders[ATOM_DEVICE_CRT1_INDEX]->encoder_id == ENCODER_OBJECT_ID_INTERNAL_DAC1) ||
           (info->encoders[ATOM_DEVICE_CRT1_INDEX]->encoder_id == ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1)))
          dac_data.sDacload.ucDacType = ATOM_DAC_A;
      else
          dac_data.sDacload.ucDacType = ATOM_DAC_B;
    } else if (radeon_output->devices & ATOM_DEVICE_CRT2_SUPPORT) {
      dac_data.sDacload.usDeviceID = cpu_to_le16(ATOM_DEVICE_CRT2_SUPPORT);
      if (info->encoders[ATOM_DEVICE_CRT2_INDEX] &&
          ((info->encoders[ATOM_DEVICE_CRT2_INDEX]->encoder_id == ENCODER_OBJECT_ID_INTERNAL_DAC1) ||
           (info->encoders[ATOM_DEVICE_CRT2_INDEX]->encoder_id == ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1)))
          dac_data.sDacload.ucDacType = ATOM_DAC_A;
      else
          dac_data.sDacload.ucDacType = ATOM_DAC_B;
    } else if (radeon_output->devices & ATOM_DEVICE_CV_SUPPORT) {
      dac_data.sDacload.usDeviceID = cpu_to_le16(ATOM_DEVICE_CV_SUPPORT);
      if (info->encoders[ATOM_DEVICE_CV_INDEX] &&
          ((info->encoders[ATOM_DEVICE_CV_INDEX]->encoder_id == ENCODER_OBJECT_ID_INTERNAL_DAC1) ||
           (info->encoders[ATOM_DEVICE_CV_INDEX]->encoder_id == ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1)))
          dac_data.sDacload.ucDacType = ATOM_DAC_A;
      else
          dac_data.sDacload.ucDacType = ATOM_DAC_B;
      if (minor >= 3)
          dac_data.sDacload.ucMisc = DAC_LOAD_MISC_YPrPb;
    } else if (radeon_output->devices & ATOM_DEVICE_TV1_SUPPORT) {
      dac_data.sDacload.usDeviceID = cpu_to_le16(ATOM_DEVICE_TV1_SUPPORT);
      if (info->encoders[ATOM_DEVICE_TV1_INDEX] &&
          ((info->encoders[ATOM_DEVICE_TV1_INDEX]->encoder_id == ENCODER_OBJECT_ID_INTERNAL_DAC1) ||
           (info->encoders[ATOM_DEVICE_TV1_INDEX]->encoder_id == ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1)))
          dac_data.sDacload.ucDacType = ATOM_DAC_A;
      else
          dac_data.sDacload.ucDacType = ATOM_DAC_B;
      if (minor >= 3)
          dac_data.sDacload.ucMisc = DAC_LOAD_MISC_YPrPb;
    } else
      return ATOM_NOT_IMPLEMENTED;

    data.exec.index = index;
    data.exec.dataSpace = (void *)&space;
    data.exec.pspace = &dac_data;

    if (RHDAtomBiosFunc(atomBIOS->scrnIndex, atomBIOS, ATOMBIOS_EXEC, &data) == ATOM_SUCCESS) {
      ErrorF("Dac detection success\n");
      return ATOM_SUCCESS ;
    }

    ErrorF("DAC detection failed\n");
    return ATOM_NOT_IMPLEMENTED;
}

RADEONMonitorType
atombios_dac_detect(xf86OutputPtr output)
{
    ScrnInfoPtr pScrn = output->scrn;
    RADEONInfoPtr info       = RADEONPTR(pScrn);
    unsigned char *RADEONMMIO = info->MMIO;
    RADEONOutputPrivatePtr radeon_output = output->driver_private;
    RADEONMonitorType MonType = MT_NONE;
    AtomBiosResult ret;
    uint32_t bios_0_scratch;

    if (radeon_output->devices & ATOM_DEVICE_TV1_SUPPORT) {
      if (xf86ReturnOptValBool(info->Options, OPTION_FORCE_TVOUT, FALSE)) {
          if (radeon_output->ConnectorType == CONNECTOR_STV)
            return MT_STV;
          else
            return MT_CTV;
      }
    }

    ret = atom_bios_dac_load_detect(info->atomBIOS, output);
    if (ret == ATOM_SUCCESS) {
      if (info->ChipFamily >= CHIP_FAMILY_R600)
          bios_0_scratch = INREG(R600_BIOS_0_SCRATCH);
      else
          bios_0_scratch = INREG(RADEON_BIOS_0_SCRATCH);
      /*ErrorF("DAC connect %08X\n", (unsigned int)bios_0_scratch);*/

      if (radeon_output->devices & ATOM_DEVICE_CRT1_SUPPORT) {
          if (bios_0_scratch & ATOM_S0_CRT1_MASK)
            MonType = MT_CRT;
      } else if (radeon_output->devices & ATOM_DEVICE_CRT2_SUPPORT) {
          if (bios_0_scratch & ATOM_S0_CRT2_MASK)
            MonType = MT_CRT;
      } else if (radeon_output->devices & ATOM_DEVICE_CV_SUPPORT) {
          if (bios_0_scratch & (ATOM_S0_CV_MASK | ATOM_S0_CV_MASK_A))
            MonType = MT_CV;
      } else if (radeon_output->devices & ATOM_DEVICE_TV1_SUPPORT) {
          if (bios_0_scratch & (ATOM_S0_TV1_COMPOSITE | ATOM_S0_TV1_COMPOSITE_A))
            MonType = MT_CTV;
          else if (bios_0_scratch & (ATOM_S0_TV1_SVIDEO | ATOM_S0_TV1_SVIDEO_A))
            MonType = MT_STV;
      }
    }

    return MonType;
}


Generated by  Doxygen 1.6.0   Back to index