1209ff23fSmrg/* 2209ff23fSmrg * Copyright © 2007 Red Hat, Inc. 3209ff23fSmrg * Copyright 2007 Advanced Micro Devices, Inc. 4209ff23fSmrg * 5209ff23fSmrg * Permission is hereby granted, free of charge, to any person obtaining a 6209ff23fSmrg * copy of this software and associated documentation files (the "Software"), 7209ff23fSmrg * to deal in the Software without restriction, including without limitation 8209ff23fSmrg * the rights to use, copy, modify, merge, publish, distribute, sublicense, 9209ff23fSmrg * and/or sell copies of the Software, and to permit persons to whom the 10209ff23fSmrg * Software is furnished to do so, subject to the following conditions: 11209ff23fSmrg * 12209ff23fSmrg * The above copyright notice and this permission notice (including the next 13209ff23fSmrg * paragraph) shall be included in all copies or substantial portions of the 14209ff23fSmrg * Software. 15209ff23fSmrg * 16209ff23fSmrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17209ff23fSmrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18209ff23fSmrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19209ff23fSmrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20209ff23fSmrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21209ff23fSmrg * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22209ff23fSmrg * SOFTWARE. 23209ff23fSmrg * 24209ff23fSmrg * Authors: 25209ff23fSmrg * Dave Airlie <airlied@redhat.com> 26209ff23fSmrg * Alex Deucher <alexdeucher@gmail.com> 27209ff23fSmrg * 28209ff23fSmrg */ 29209ff23fSmrg 30209ff23fSmrg/* 31209ff23fSmrg * avivo output handling functions. 32209ff23fSmrg */ 33209ff23fSmrg#ifdef HAVE_CONFIG_H 34209ff23fSmrg#include "config.h" 35209ff23fSmrg#endif 36209ff23fSmrg/* DPMS */ 37c503f109Smrg#ifdef HAVE_XEXTPROTO_71 38c503f109Smrg#include <X11/extensions/dpmsconst.h> 39c503f109Smrg#else 40209ff23fSmrg#define DPMS_SERVER 41209ff23fSmrg#include <X11/extensions/dpms.h> 42c503f109Smrg#endif 43c503f109Smrg 44209ff23fSmrg#include <unistd.h> 45209ff23fSmrg 46209ff23fSmrg#include "radeon.h" 47209ff23fSmrg#include "radeon_reg.h" 48209ff23fSmrg#include "radeon_macros.h" 49209ff23fSmrg#include "radeon_atombios.h" 50209ff23fSmrg 51b7e1c893Smrg#include "ati_pciids_gen.h" 52b7e1c893Smrg 53b7e1c893Smrgconst char *device_name[12] = { 54b7e1c893Smrg "CRT1", 55b7e1c893Smrg "LCD1", 56b7e1c893Smrg "TV1", 57b7e1c893Smrg "DFP1", 58b7e1c893Smrg "CRT2", 59b7e1c893Smrg "LCD2", 60b7e1c893Smrg "TV2", 61b7e1c893Smrg "DFP2", 62b7e1c893Smrg "CV", 63b7e1c893Smrg "DFP3", 64b7e1c893Smrg "DFP4", 65b7e1c893Smrg "DFP5", 66b7e1c893Smrg}; 67b7e1c893Smrg 68921a55d8Smrg#define AUX_NATIVE_WRITE 0x8 69921a55d8Smrg#define AUX_NATIVE_READ 0x9 70921a55d8Smrg 71921a55d8Smrg#define AUX_I2C_WRITE 0x0 72921a55d8Smrg#define AUX_I2C_READ 0x1 73921a55d8Smrg#define AUX_I2C_STATUS 0x2 74921a55d8Smrg#define AUX_I2C_MOT 0x4 75921a55d8Smrg 76921a55d8Smrg#define DP_DPCD_REV 0x0 77921a55d8Smrg#define DP_MAX_LINK_RATE 0x1 78921a55d8Smrg#define DP_MAX_LANE_COUNT 0x2 79921a55d8Smrg#define DP_MAX_DOWNSPREAD 0x3 80921a55d8Smrg#define DP_NORP 0x4 81921a55d8Smrg#define DP_DOWNSTREAMPORT_PRESENT 0x5 82921a55d8Smrg#define DP_MAIN_LINK_CHANNEL_CONFIG 0x6 83921a55d8Smrg#define DP_DP11_DOWNSTREAM_PORT_COUNT 0x7 84921a55d8Smrg 85921a55d8Smrg/* from intel i830_dp.h */ 86921a55d8Smrg#define DP_LINK_BW_SET 0x100 87921a55d8Smrg//# define DP_LINK_BW_1_62 0x06 88921a55d8Smrg//# define DP_LINK_BW_2_7 0x0a 89921a55d8Smrg#define DP_LANE_COUNT_SET 0x101 90921a55d8Smrg# define DP_LANE_COUNT_MASK 0x0f 91921a55d8Smrg# define DP_LANE_COUNT_ENHANCED_FRAME_EN (1 << 7) 92921a55d8Smrg 93921a55d8Smrg#define DP_TRAINING_PATTERN_SET 0x102 94921a55d8Smrg 95921a55d8Smrg# define DP_TRAINING_PATTERN_DISABLE 0 96921a55d8Smrg# define DP_TRAINING_PATTERN_1 1 97921a55d8Smrg# define DP_TRAINING_PATTERN_2 2 98921a55d8Smrg# define DP_TRAINING_PATTERN_MASK 0x3 99921a55d8Smrg 100921a55d8Smrg# define DP_LINK_QUAL_PATTERN_DISABLE (0 << 2) 101921a55d8Smrg# define DP_LINK_QUAL_PATTERN_D10_2 (1 << 2) 102921a55d8Smrg# define DP_LINK_QUAL_PATTERN_ERROR_RATE (2 << 2) 103921a55d8Smrg# define DP_LINK_QUAL_PATTERN_PRBS7 (3 << 2) 104921a55d8Smrg# define DP_LINK_QUAL_PATTERN_MASK (3 << 2) 105921a55d8Smrg# define DP_RECOVERED_CLOCK_OUT_EN (1 << 4) 106921a55d8Smrg# define DP_LINK_SCRAMBLING_DISABLE (1 << 5) 107921a55d8Smrg 108921a55d8Smrg# define DP_SYMBOL_ERROR_COUNT_BOTH (0 << 6) 109921a55d8Smrg# define DP_SYMBOL_ERROR_COUNT_DISPARITY (1 << 6) 110921a55d8Smrg# define DP_SYMBOL_ERROR_COUNT_SYMBOL (2 << 6) 111921a55d8Smrg# define DP_SYMBOL_ERROR_COUNT_MASK (3 << 6) 112921a55d8Smrg 113921a55d8Smrg#define DP_TRAINING_LANE0_SET 0x103 114921a55d8Smrg#define DP_TRAINING_LANE1_SET 0x104 115921a55d8Smrg#define DP_TRAINING_LANE2_SET 0x105 116921a55d8Smrg#define DP_TRAINING_LANE3_SET 0x106 117921a55d8Smrg# define DP_TRAIN_VOLTAGE_SWING_MASK 0x3 118921a55d8Smrg# define DP_TRAIN_VOLTAGE_SWING_SHIFT 0 119921a55d8Smrg# define DP_TRAIN_MAX_SWING_REACHED (1 << 2) 120921a55d8Smrg# define DP_TRAIN_VOLTAGE_SWING_400 (0 << 0) 121921a55d8Smrg# define DP_TRAIN_VOLTAGE_SWING_600 (1 << 0) 122921a55d8Smrg# define DP_TRAIN_VOLTAGE_SWING_800 (2 << 0) 123921a55d8Smrg# define DP_TRAIN_VOLTAGE_SWING_1200 (3 << 0) 124921a55d8Smrg 125921a55d8Smrg# define DP_TRAIN_PRE_EMPHASIS_MASK (3 << 3) 126921a55d8Smrg# define DP_TRAIN_PRE_EMPHASIS_0 (0 << 3) 127921a55d8Smrg# define DP_TRAIN_PRE_EMPHASIS_3_5 (1 << 3) 128921a55d8Smrg# define DP_TRAIN_PRE_EMPHASIS_6 (2 << 3) 129921a55d8Smrg# define DP_TRAIN_PRE_EMPHASIS_9_5 (3 << 3) 130921a55d8Smrg 131921a55d8Smrg# define DP_TRAIN_PRE_EMPHASIS_SHIFT 3 132921a55d8Smrg# define DP_TRAIN_MAX_PRE_EMPHASIS_REACHED (1 << 5) 133921a55d8Smrg#define DP_DOWNSPREAD_CTRL 0x107 134921a55d8Smrg# define DP_SPREAD_AMP_0_5 (1 << 4) 135921a55d8Smrg 136921a55d8Smrg#define DP_MAIN_LINK_CHANNEL_CODING_SET 0x108 137921a55d8Smrg# define DP_SET_ANSI_8B10B (1 << 0) 138921a55d8Smrg 139921a55d8Smrg#define DP_LANE0_1_STATUS 0x202 140921a55d8Smrg#define DP_LANE2_3_STATUS 0x203 141921a55d8Smrg 142921a55d8Smrg# define DP_LANE_CR_DONE (1 << 0) 143921a55d8Smrg# define DP_LANE_CHANNEL_EQ_DONE (1 << 1) 144921a55d8Smrg# define DP_LANE_SYMBOL_LOCKED (1 << 2) 145921a55d8Smrg 146921a55d8Smrg#define DP_LANE_ALIGN_STATUS_UPDATED 0x204 147921a55d8Smrg#define DP_INTERLANE_ALIGN_DONE (1 << 0) 148921a55d8Smrg#define DP_DOWNSTREAM_PORT_STATUS_CHANGED (1 << 6) 149921a55d8Smrg#define DP_LINK_STATUS_UPDATED (1 << 7) 150921a55d8Smrg 151921a55d8Smrg#define DP_SINK_STATUS 0x205 152921a55d8Smrg 153921a55d8Smrg#define DP_RECEIVE_PORT_0_STATUS (1 << 0) 154921a55d8Smrg#define DP_RECEIVE_PORT_1_STATUS (1 << 1) 155921a55d8Smrg 156921a55d8Smrg#define DP_ADJUST_REQUEST_LANE0_1 0x206 157921a55d8Smrg#define DP_ADJUST_REQUEST_LANE2_3 0x207 158921a55d8Smrg 159921a55d8Smrg#define DP_ADJUST_VOLTAGE_SWING_LANE0_MASK 0x03 160921a55d8Smrg#define DP_ADJUST_VOLTAGE_SWING_LANE0_SHIFT 0 161921a55d8Smrg#define DP_ADJUST_PRE_EMPHASIS_LANE0_MASK 0x0c 162921a55d8Smrg#define DP_ADJUST_PRE_EMPHASIS_LANE0_SHIFT 2 163921a55d8Smrg#define DP_ADJUST_VOLTAGE_SWING_LANE1_MASK 0x30 164921a55d8Smrg#define DP_ADJUST_VOLTAGE_SWING_LANE1_SHIFT 4 165921a55d8Smrg#define DP_ADJUST_PRE_EMPHASIS_LANE1_MASK 0xc0 166921a55d8Smrg#define DP_ADJUST_PRE_EMPHASIS_LANE1_SHIFT 6 167921a55d8Smrg 168921a55d8Smrg#define DP_LINK_STATUS_SIZE 6 169921a55d8Smrg#define DP_LINK_CONFIGURATION_SIZE 9 170921a55d8Smrg 171921a55d8Smrg#define DP_SET_POWER_D0 0x1 172921a55d8Smrg#define DP_SET_POWER_D3 0x2 173921a55d8Smrg 174ad43ddacSmrgstatic void do_displayport_link_train(xf86OutputPtr output); 175ad43ddacSmrg 176209ff23fSmrgstatic int 177b7e1c893Smrgatombios_output_dac_setup(xf86OutputPtr output, int action) 178209ff23fSmrg{ 179209ff23fSmrg RADEONOutputPrivatePtr radeon_output = output->driver_private; 180209ff23fSmrg RADEONInfoPtr info = RADEONPTR(output->scrn); 181b7e1c893Smrg radeon_encoder_ptr radeon_encoder = radeon_get_encoder(output); 182b7e1c893Smrg radeon_tvout_ptr tvout = &radeon_output->tvout; 183209ff23fSmrg DAC_ENCODER_CONTROL_PS_ALLOCATION disp_data; 184209ff23fSmrg AtomBiosArgRec data; 185209ff23fSmrg unsigned char *space; 186b7e1c893Smrg int index = 0, num = 0; 187b7e1c893Smrg int clock = radeon_output->pixel_clock; 188b7e1c893Smrg 189b7e1c893Smrg if (radeon_encoder == NULL) 190b7e1c893Smrg return ATOM_NOT_IMPLEMENTED; 191b7e1c893Smrg 192b7e1c893Smrg memset(&disp_data,0, sizeof(disp_data)); 193b7e1c893Smrg 194b7e1c893Smrg switch (radeon_encoder->encoder_id) { 195b7e1c893Smrg case ENCODER_OBJECT_ID_INTERNAL_DAC1: 196b7e1c893Smrg case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1: 197b7e1c893Smrg index = GetIndexIntoMasterTable(COMMAND, DAC1EncoderControl); 198b7e1c893Smrg num = 1; 199b7e1c893Smrg break; 200b7e1c893Smrg case ENCODER_OBJECT_ID_INTERNAL_DAC2: 201b7e1c893Smrg case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC2: 202b7e1c893Smrg index = GetIndexIntoMasterTable(COMMAND, DAC2EncoderControl); 203b7e1c893Smrg num = 2; 204b7e1c893Smrg break; 205b7e1c893Smrg } 206209ff23fSmrg 207b7e1c893Smrg disp_data.ucAction =action; 208209ff23fSmrg 209b7e1c893Smrg if (radeon_output->active_device & (ATOM_DEVICE_CRT_SUPPORT)) 210209ff23fSmrg disp_data.ucDacStandard = ATOM_DAC1_PS2; 211b7e1c893Smrg else if (radeon_output->active_device & (ATOM_DEVICE_CV_SUPPORT)) 212209ff23fSmrg disp_data.ucDacStandard = ATOM_DAC1_CV; 213b7e1c893Smrg else { 214b7e1c893Smrg switch (tvout->tvStd) { 215209ff23fSmrg case TV_STD_PAL: 216209ff23fSmrg case TV_STD_PAL_M: 217209ff23fSmrg case TV_STD_SCART_PAL: 218209ff23fSmrg case TV_STD_SECAM: 219209ff23fSmrg case TV_STD_PAL_CN: 220209ff23fSmrg disp_data.ucDacStandard = ATOM_DAC1_PAL; 221209ff23fSmrg break; 222209ff23fSmrg case TV_STD_NTSC: 223209ff23fSmrg case TV_STD_NTSC_J: 224209ff23fSmrg case TV_STD_PAL_60: 225209ff23fSmrg default: 226b7e1c893Smrg disp_data.ucDacStandard = ATOM_DAC1_NTSC; 227209ff23fSmrg break; 228209ff23fSmrg } 229209ff23fSmrg } 230b7e1c893Smrg disp_data.usPixelClock = cpu_to_le16(clock / 10); 231209ff23fSmrg 232b7e1c893Smrg data.exec.index = index; 233209ff23fSmrg data.exec.dataSpace = (void *)&space; 234209ff23fSmrg data.exec.pspace = &disp_data; 235209ff23fSmrg 23668105dcbSveego if (RHDAtomBiosFunc(info->atomBIOS->pScrn, info->atomBIOS, ATOMBIOS_EXEC, &data) == ATOM_SUCCESS) { 237042789b0Sveego/* ErrorF("Output DAC%d setup success\n", num); */ 238209ff23fSmrg return ATOM_SUCCESS; 239209ff23fSmrg } 240209ff23fSmrg 241b7e1c893Smrg ErrorF("Output DAC%d setup failed\n", num); 242209ff23fSmrg return ATOM_NOT_IMPLEMENTED; 243209ff23fSmrg 244209ff23fSmrg} 245209ff23fSmrg 246209ff23fSmrgstatic int 247b7e1c893Smrgatombios_output_tv_setup(xf86OutputPtr output, int action) 248209ff23fSmrg{ 249209ff23fSmrg RADEONOutputPrivatePtr radeon_output = output->driver_private; 250b7e1c893Smrg radeon_tvout_ptr tvout = &radeon_output->tvout; 251209ff23fSmrg RADEONInfoPtr info = RADEONPTR(output->scrn); 252209ff23fSmrg TV_ENCODER_CONTROL_PS_ALLOCATION disp_data; 253209ff23fSmrg AtomBiosArgRec data; 254209ff23fSmrg unsigned char *space; 255b7e1c893Smrg int clock = radeon_output->pixel_clock; 256b7e1c893Smrg 257b7e1c893Smrg memset(&disp_data,0, sizeof(disp_data)); 258209ff23fSmrg 259b7e1c893Smrg disp_data.sTVEncoder.ucAction = action; 260209ff23fSmrg 261b7e1c893Smrg if (radeon_output->active_device & (ATOM_DEVICE_CV_SUPPORT)) 262209ff23fSmrg disp_data.sTVEncoder.ucTvStandard = ATOM_TV_CV; 263209ff23fSmrg else { 264b7e1c893Smrg switch (tvout->tvStd) { 265209ff23fSmrg case TV_STD_NTSC: 266209ff23fSmrg disp_data.sTVEncoder.ucTvStandard = ATOM_TV_NTSC; 267209ff23fSmrg break; 268209ff23fSmrg case TV_STD_PAL: 269209ff23fSmrg disp_data.sTVEncoder.ucTvStandard = ATOM_TV_PAL; 270209ff23fSmrg break; 271209ff23fSmrg case TV_STD_PAL_M: 272209ff23fSmrg disp_data.sTVEncoder.ucTvStandard = ATOM_TV_PALM; 273209ff23fSmrg break; 274209ff23fSmrg case TV_STD_PAL_60: 275209ff23fSmrg disp_data.sTVEncoder.ucTvStandard = ATOM_TV_PAL60; 276209ff23fSmrg break; 277209ff23fSmrg case TV_STD_NTSC_J: 278209ff23fSmrg disp_data.sTVEncoder.ucTvStandard = ATOM_TV_NTSCJ; 279209ff23fSmrg break; 280209ff23fSmrg case TV_STD_SCART_PAL: 281209ff23fSmrg disp_data.sTVEncoder.ucTvStandard = ATOM_TV_PAL; /* ??? */ 282209ff23fSmrg break; 283209ff23fSmrg case TV_STD_SECAM: 284209ff23fSmrg disp_data.sTVEncoder.ucTvStandard = ATOM_TV_SECAM; 285209ff23fSmrg break; 286209ff23fSmrg case TV_STD_PAL_CN: 287209ff23fSmrg disp_data.sTVEncoder.ucTvStandard = ATOM_TV_PALCN; 288209ff23fSmrg break; 289209ff23fSmrg default: 290209ff23fSmrg disp_data.sTVEncoder.ucTvStandard = ATOM_TV_NTSC; 291209ff23fSmrg break; 292209ff23fSmrg } 293209ff23fSmrg } 294209ff23fSmrg 295b7e1c893Smrg disp_data.sTVEncoder.usPixelClock = cpu_to_le16(clock / 10); 296209ff23fSmrg data.exec.index = GetIndexIntoMasterTable(COMMAND, TVEncoderControl); 297209ff23fSmrg data.exec.dataSpace = (void *)&space; 298209ff23fSmrg data.exec.pspace = &disp_data; 299209ff23fSmrg 30068105dcbSveego if (RHDAtomBiosFunc(info->atomBIOS->pScrn, info->atomBIOS, ATOMBIOS_EXEC, &data) == ATOM_SUCCESS) { 301042789b0Sveego/* ErrorF("Output TV setup success\n"); */ 302209ff23fSmrg return ATOM_SUCCESS; 303209ff23fSmrg } 304209ff23fSmrg 305b7e1c893Smrg ErrorF("Output TV setup failed\n"); 306209ff23fSmrg return ATOM_NOT_IMPLEMENTED; 307209ff23fSmrg 308209ff23fSmrg} 309209ff23fSmrg 310209ff23fSmrgint 311b7e1c893Smrgatombios_external_tmds_setup(xf86OutputPtr output, int action) 312209ff23fSmrg{ 313b7e1c893Smrg RADEONOutputPrivatePtr radeon_output = output->driver_private; 314b7e1c893Smrg ScrnInfoPtr pScrn = output->scrn; 315b7e1c893Smrg RADEONInfoPtr info = RADEONPTR(pScrn); 316209ff23fSmrg ENABLE_EXTERNAL_TMDS_ENCODER_PS_ALLOCATION disp_data; 317209ff23fSmrg AtomBiosArgRec data; 318209ff23fSmrg unsigned char *space; 319b7e1c893Smrg int clock = radeon_output->pixel_clock; 320209ff23fSmrg 321b7e1c893Smrg memset(&disp_data,0, sizeof(disp_data)); 322209ff23fSmrg 323b7e1c893Smrg disp_data.sXTmdsEncoder.ucEnable = action; 324b7e1c893Smrg 325b7e1c893Smrg if (clock > 165000) 326b7e1c893Smrg disp_data.sXTmdsEncoder.ucMisc = PANEL_ENCODER_MISC_DUAL; 327209ff23fSmrg 328b7e1c893Smrg if (pScrn->rgbBits == 8) 329209ff23fSmrg disp_data.sXTmdsEncoder.ucMisc |= (1 << 1); 330209ff23fSmrg 331209ff23fSmrg data.exec.index = GetIndexIntoMasterTable(COMMAND, DVOEncoderControl); 332209ff23fSmrg data.exec.dataSpace = (void *)&space; 333209ff23fSmrg data.exec.pspace = &disp_data; 334209ff23fSmrg 33568105dcbSveego if (RHDAtomBiosFunc(info->atomBIOS->pScrn, info->atomBIOS, ATOMBIOS_EXEC, &data) == ATOM_SUCCESS) { 336042789b0Sveego/* ErrorF("External TMDS setup success\n"); */ 337209ff23fSmrg return ATOM_SUCCESS; 338209ff23fSmrg } 339209ff23fSmrg 340209ff23fSmrg ErrorF("External TMDS setup failed\n"); 341209ff23fSmrg return ATOM_NOT_IMPLEMENTED; 342209ff23fSmrg} 343209ff23fSmrg 344209ff23fSmrgstatic int 345b7e1c893Smrgatombios_output_ddia_setup(xf86OutputPtr output, int action) 346209ff23fSmrg{ 347b7e1c893Smrg RADEONOutputPrivatePtr radeon_output = output->driver_private; 348209ff23fSmrg RADEONInfoPtr info = RADEONPTR(output->scrn); 349209ff23fSmrg DVO_ENCODER_CONTROL_PS_ALLOCATION disp_data; 350209ff23fSmrg AtomBiosArgRec data; 351209ff23fSmrg unsigned char *space; 352b7e1c893Smrg int clock = radeon_output->pixel_clock; 353b7e1c893Smrg 354b7e1c893Smrg memset(&disp_data,0, sizeof(disp_data)); 355209ff23fSmrg 356b7e1c893Smrg disp_data.sDVOEncoder.ucAction = action; 357b7e1c893Smrg disp_data.sDVOEncoder.usPixelClock = cpu_to_le16(clock / 10); 358209ff23fSmrg 359b7e1c893Smrg if (clock > 165000) 360209ff23fSmrg disp_data.sDVOEncoder.usDevAttr.sDigAttrib.ucAttribute = PANEL_ENCODER_MISC_DUAL; 361209ff23fSmrg 362209ff23fSmrg data.exec.index = GetIndexIntoMasterTable(COMMAND, DVOEncoderControl); 363209ff23fSmrg data.exec.dataSpace = (void *)&space; 364209ff23fSmrg data.exec.pspace = &disp_data; 365209ff23fSmrg 36668105dcbSveego if (RHDAtomBiosFunc(info->atomBIOS->pScrn, info->atomBIOS, ATOMBIOS_EXEC, &data) == ATOM_SUCCESS) { 367042789b0Sveego/* ErrorF("DDIA setup success\n"); */ 368209ff23fSmrg return ATOM_SUCCESS; 369209ff23fSmrg } 370209ff23fSmrg 371209ff23fSmrg ErrorF("DDIA setup failed\n"); 372209ff23fSmrg return ATOM_NOT_IMPLEMENTED; 373209ff23fSmrg} 374209ff23fSmrg 375209ff23fSmrgstatic int 376b7e1c893Smrgatombios_output_digital_setup(xf86OutputPtr output, int action) 377209ff23fSmrg{ 378b7e1c893Smrg RADEONOutputPrivatePtr radeon_output = output->driver_private; 379b7e1c893Smrg ScrnInfoPtr pScrn = output->scrn; 380b7e1c893Smrg RADEONInfoPtr info = RADEONPTR(pScrn); 381b7e1c893Smrg radeon_encoder_ptr radeon_encoder = radeon_get_encoder(output); 382b7e1c893Smrg LVDS_ENCODER_CONTROL_PS_ALLOCATION disp_data; 383b7e1c893Smrg LVDS_ENCODER_CONTROL_PS_ALLOCATION_V2 disp_data2; 384209ff23fSmrg AtomBiosArgRec data; 385209ff23fSmrg unsigned char *space; 386b7e1c893Smrg int index = 0; 387b7e1c893Smrg int major, minor; 388b7e1c893Smrg int lvds_misc = 0; 389b7e1c893Smrg int clock = radeon_output->pixel_clock; 390209ff23fSmrg 391b7e1c893Smrg if (radeon_encoder == NULL) 392b7e1c893Smrg return ATOM_NOT_IMPLEMENTED; 393b7e1c893Smrg 394b7e1c893Smrg if (radeon_output->active_device & (ATOM_DEVICE_LCD_SUPPORT)) { 395b7e1c893Smrg radeon_lvds_ptr lvds = (radeon_lvds_ptr)radeon_encoder->dev_priv; 396b7e1c893Smrg if (lvds == NULL) 397b7e1c893Smrg return ATOM_NOT_IMPLEMENTED; 398b7e1c893Smrg lvds_misc = lvds->lvds_misc; 399b7e1c893Smrg } 400b7e1c893Smrg 401b7e1c893Smrg memset(&disp_data,0, sizeof(disp_data)); 402b7e1c893Smrg memset(&disp_data2,0, sizeof(disp_data2)); 403b7e1c893Smrg 404b7e1c893Smrg switch (radeon_encoder->encoder_id) { 405b7e1c893Smrg case ENCODER_OBJECT_ID_INTERNAL_LVDS: 406b7e1c893Smrg index = GetIndexIntoMasterTable(COMMAND, LVDSEncoderControl); 407b7e1c893Smrg break; 408b7e1c893Smrg case ENCODER_OBJECT_ID_INTERNAL_TMDS1: 409b7e1c893Smrg case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1: 410b7e1c893Smrg index = GetIndexIntoMasterTable(COMMAND, TMDS1EncoderControl); 411b7e1c893Smrg break; 412b7e1c893Smrg case ENCODER_OBJECT_ID_INTERNAL_LVTM1: 413b7e1c893Smrg case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA: 414b7e1c893Smrg if (radeon_output->active_device & (ATOM_DEVICE_LCD_SUPPORT)) 415b7e1c893Smrg index = GetIndexIntoMasterTable(COMMAND, LVDSEncoderControl); 416b7e1c893Smrg else 417b7e1c893Smrg index = GetIndexIntoMasterTable(COMMAND, TMDS2EncoderControl); 418b7e1c893Smrg break; 419b7e1c893Smrg } 420b7e1c893Smrg 421b7e1c893Smrg atombios_get_command_table_version(info->atomBIOS, index, &major, &minor); 422b7e1c893Smrg 423b7e1c893Smrg /*ErrorF("table is %d %d\n", major, minor);*/ 424b7e1c893Smrg switch (major) { 425b7e1c893Smrg case 0: 426b7e1c893Smrg case 1: 427b7e1c893Smrg case 2: 428b7e1c893Smrg switch (minor) { 429b7e1c893Smrg case 1: 430b7e1c893Smrg disp_data.ucMisc = 0; 431b7e1c893Smrg disp_data.ucAction = action; 432b7e1c893Smrg if ((radeon_output->ConnectorType == CONNECTOR_HDMI_TYPE_A) || 433b7e1c893Smrg (radeon_output->ConnectorType == CONNECTOR_HDMI_TYPE_B)) 434b7e1c893Smrg disp_data.ucMisc |= PANEL_ENCODER_MISC_HDMI_TYPE; 435b7e1c893Smrg disp_data.usPixelClock = cpu_to_le16(clock / 10); 436b7e1c893Smrg if (radeon_output->active_device & (ATOM_DEVICE_LCD_SUPPORT)) { 437b7e1c893Smrg if (lvds_misc & (1 << 0)) 438b7e1c893Smrg disp_data.ucMisc |= PANEL_ENCODER_MISC_DUAL; 439b7e1c893Smrg if (lvds_misc & (1 << 1)) 440b7e1c893Smrg disp_data.ucMisc |= (1 << 1); 441b7e1c893Smrg } else { 442b7e1c893Smrg if (radeon_output->linkb) 443b7e1c893Smrg disp_data.ucMisc |= PANEL_ENCODER_MISC_TMDS_LINKB; 444b7e1c893Smrg if (clock > 165000) 445b7e1c893Smrg disp_data.ucMisc |= PANEL_ENCODER_MISC_DUAL; 446b7e1c893Smrg if (pScrn->rgbBits == 8) 447b7e1c893Smrg disp_data.ucMisc |= (1 << 1); 448b7e1c893Smrg } 449b7e1c893Smrg data.exec.pspace = &disp_data; 450b7e1c893Smrg break; 451b7e1c893Smrg case 2: 452b7e1c893Smrg case 3: 453b7e1c893Smrg disp_data2.ucMisc = 0; 454b7e1c893Smrg disp_data2.ucAction = action; 455b7e1c893Smrg if (minor == 3) { 456b7e1c893Smrg if (radeon_output->coherent_mode) { 457b7e1c893Smrg disp_data2.ucMisc |= PANEL_ENCODER_MISC_COHERENT; 458b7e1c893Smrg xf86DrvMsg(output->scrn->scrnIndex, X_INFO, "Coherent Mode enabled\n"); 459b7e1c893Smrg } 460b7e1c893Smrg } 461b7e1c893Smrg if ((radeon_output->ConnectorType == CONNECTOR_HDMI_TYPE_A) || 462b7e1c893Smrg (radeon_output->ConnectorType == CONNECTOR_HDMI_TYPE_B)) 463b7e1c893Smrg disp_data2.ucMisc |= PANEL_ENCODER_MISC_HDMI_TYPE; 464b7e1c893Smrg disp_data2.usPixelClock = cpu_to_le16(clock / 10); 465b7e1c893Smrg disp_data2.ucTruncate = 0; 466b7e1c893Smrg disp_data2.ucSpatial = 0; 467b7e1c893Smrg disp_data2.ucTemporal = 0; 468b7e1c893Smrg disp_data2.ucFRC = 0; 469b7e1c893Smrg if (radeon_output->active_device & (ATOM_DEVICE_LCD_SUPPORT)) { 470b7e1c893Smrg if (lvds_misc & (1 << 0)) 471b7e1c893Smrg disp_data2.ucMisc |= PANEL_ENCODER_MISC_DUAL; 472b7e1c893Smrg if (lvds_misc & (1 << 5)) { 473b7e1c893Smrg disp_data2.ucSpatial = PANEL_ENCODER_SPATIAL_DITHER_EN; 474b7e1c893Smrg if (lvds_misc & (1 << 1)) 475b7e1c893Smrg disp_data2.ucSpatial |= PANEL_ENCODER_SPATIAL_DITHER_DEPTH; 476b7e1c893Smrg } 477b7e1c893Smrg if (lvds_misc & (1 << 6)) { 478b7e1c893Smrg disp_data2.ucTemporal = PANEL_ENCODER_TEMPORAL_DITHER_EN; 479b7e1c893Smrg if (lvds_misc & (1 << 1)) 480b7e1c893Smrg disp_data2.ucTemporal |= PANEL_ENCODER_TEMPORAL_DITHER_DEPTH; 481b7e1c893Smrg if (((lvds_misc >> 2) & 0x3) == 2) 482b7e1c893Smrg disp_data2.ucTemporal |= PANEL_ENCODER_TEMPORAL_LEVEL_4; 483b7e1c893Smrg } 484b7e1c893Smrg } else { 485b7e1c893Smrg if (radeon_output->linkb) 486b7e1c893Smrg disp_data2.ucMisc |= PANEL_ENCODER_MISC_TMDS_LINKB; 487b7e1c893Smrg if (clock > 165000) 488b7e1c893Smrg disp_data2.ucMisc |= PANEL_ENCODER_MISC_DUAL; 489b7e1c893Smrg } 490b7e1c893Smrg data.exec.pspace = &disp_data2; 491b7e1c893Smrg break; 492b7e1c893Smrg default: 493b7e1c893Smrg ErrorF("Unknown table version\n"); 494b7e1c893Smrg exit(-1); 495b7e1c893Smrg } 496b7e1c893Smrg break; 497b7e1c893Smrg default: 498b7e1c893Smrg ErrorF("Unknown table version\n"); 499b7e1c893Smrg exit(-1); 500b7e1c893Smrg } 501b7e1c893Smrg 502b7e1c893Smrg data.exec.index = index; 503209ff23fSmrg data.exec.dataSpace = (void *)&space; 504209ff23fSmrg 50568105dcbSveego if (RHDAtomBiosFunc(info->atomBIOS->pScrn, info->atomBIOS, ATOMBIOS_EXEC, &data) == ATOM_SUCCESS) { 506042789b0Sveego/* ErrorF("Output digital setup success\n"); */ 507209ff23fSmrg return ATOM_SUCCESS; 508209ff23fSmrg } 509209ff23fSmrg 510b7e1c893Smrg ErrorF("Output digital setup failed\n"); 511209ff23fSmrg return ATOM_NOT_IMPLEMENTED; 512209ff23fSmrg} 513209ff23fSmrg 514209ff23fSmrgstatic int 515b7e1c893Smrgatombios_maybe_hdmi_mode(xf86OutputPtr output) 516209ff23fSmrg{ 517b7e1c893Smrg#ifndef EDID_COMPLETE_RAWDATA 518b7e1c893Smrg /* there's no getting this right unless we have complete EDID */ 519921a55d8Smrg return ATOM_ENCODER_MODE_DVI; 520b7e1c893Smrg#else 521b7e1c893Smrg if (output && xf86MonitorIsHDMI(output->MonInfo)) 522b7e1c893Smrg return ATOM_ENCODER_MODE_HDMI; 523b7e1c893Smrg 524b7e1c893Smrg return ATOM_ENCODER_MODE_DVI; 525b7e1c893Smrg#endif 526b7e1c893Smrg} 527209ff23fSmrg 528b7e1c893Smrgint 529b7e1c893Smrgatombios_get_encoder_mode(xf86OutputPtr output) 530b7e1c893Smrg{ 5310974d292Smrg ScrnInfoPtr pScrn = output->scrn; 5320974d292Smrg RADEONInfoPtr info = RADEONPTR(pScrn); 533b7e1c893Smrg RADEONOutputPrivatePtr radeon_output = output->driver_private; 534209ff23fSmrg 535b7e1c893Smrg /* DVI should really be atombios_maybe_hdmi_mode() as well */ 536b7e1c893Smrg switch (radeon_output->ConnectorType) { 537b7e1c893Smrg case CONNECTOR_DVI_I: 538b7e1c893Smrg if (radeon_output->active_device & (ATOM_DEVICE_DFP_SUPPORT)) 539b7e1c893Smrg return ATOM_ENCODER_MODE_DVI; 540b7e1c893Smrg else 541b7e1c893Smrg return ATOM_ENCODER_MODE_CRT; 542b7e1c893Smrg break; 543b7e1c893Smrg case CONNECTOR_DVI_D: 544b7e1c893Smrg default: 545b7e1c893Smrg return ATOM_ENCODER_MODE_DVI; 546b7e1c893Smrg break; 547b7e1c893Smrg case CONNECTOR_HDMI_TYPE_A: 548b7e1c893Smrg case CONNECTOR_HDMI_TYPE_B: 5490974d292Smrg if (IS_DCE4_VARIANT) 5500974d292Smrg return ATOM_ENCODER_MODE_DVI; 5510974d292Smrg else 5520974d292Smrg return atombios_maybe_hdmi_mode(output); 553b7e1c893Smrg break; 554b7e1c893Smrg case CONNECTOR_LVDS: 555b7e1c893Smrg return ATOM_ENCODER_MODE_LVDS; 556b7e1c893Smrg break; 557b7e1c893Smrg case CONNECTOR_DISPLAY_PORT: 558ad43ddacSmrg case CONNECTOR_EDP: 559b7e1c893Smrg if (radeon_output->MonType == MT_DP) 560b7e1c893Smrg return ATOM_ENCODER_MODE_DP; 5610974d292Smrg else { 5620974d292Smrg if (IS_DCE4_VARIANT) 5630974d292Smrg return ATOM_ENCODER_MODE_DVI; 5640974d292Smrg else 5650974d292Smrg return atombios_maybe_hdmi_mode(output); 5660974d292Smrg } 567b7e1c893Smrg break; 568b7e1c893Smrg case CONNECTOR_DVI_A: 569b7e1c893Smrg case CONNECTOR_VGA: 570b7e1c893Smrg case CONNECTOR_STV: 571b7e1c893Smrg case CONNECTOR_CTV: 572b7e1c893Smrg case CONNECTOR_DIN: 573b7e1c893Smrg if (radeon_output->active_device & (ATOM_DEVICE_TV_SUPPORT)) 574b7e1c893Smrg return ATOM_ENCODER_MODE_TV; 575b7e1c893Smrg else if (radeon_output->active_device & (ATOM_DEVICE_CV_SUPPORT)) 576b7e1c893Smrg return ATOM_ENCODER_MODE_CV; 577b7e1c893Smrg else 578b7e1c893Smrg return ATOM_ENCODER_MODE_CRT; 579b7e1c893Smrg break; 580209ff23fSmrg } 581209ff23fSmrg 582209ff23fSmrg} 583209ff23fSmrg 584b7e1c893Smrgstatic const int dp_clocks[] = { 585ad43ddacSmrg 5400, // 1 lane, 1.62 Ghz 586ad43ddacSmrg 9000, // 1 lane, 2.70 Ghz 587ad43ddacSmrg 10800, // 2 lane, 1.62 Ghz 588ad43ddacSmrg 18000, // 2 lane, 2.70 Ghz 589ad43ddacSmrg 21600, // 4 lane, 1.62 Ghz 590ad43ddacSmrg 36000, // 4 lane, 2.70 Ghz 591b7e1c893Smrg}; 592b7e1c893Smrgstatic const int num_dp_clocks = sizeof(dp_clocks) / sizeof(int); 593b7e1c893Smrg 594ad43ddacSmrg# define DP_LINK_BW_1_62 0x06 595ad43ddacSmrg# define DP_LINK_BW_2_7 0x0a 596921a55d8Smrgstatic int radeon_dp_max_lane_count(xf86OutputPtr output); 597ad43ddacSmrg 598209ff23fSmrgstatic int 599921a55d8Smrgdp_lanes_for_mode_clock(xf86OutputPtr output, int mode_clock) 600209ff23fSmrg{ 601921a55d8Smrg RADEONOutputPrivatePtr radeon_output = output->driver_private; 602b7e1c893Smrg int i; 603ad43ddacSmrg int max_link_bw = radeon_output->dpcd[1]; 604921a55d8Smrg int max_lane_count = radeon_dp_max_lane_count(output); 605ad43ddacSmrg 606ad43ddacSmrg switch (max_link_bw) { 607ad43ddacSmrg case DP_LINK_BW_1_62: 608ad43ddacSmrg default: 609ad43ddacSmrg for (i = 0; i < num_dp_clocks; i++) { 610921a55d8Smrg if (i % 2) 611921a55d8Smrg continue; 612921a55d8Smrg switch (max_lane_count) { 613921a55d8Smrg case 1: 614921a55d8Smrg if (i > 1) 615921a55d8Smrg return 0; 616921a55d8Smrg break; 617921a55d8Smrg case 2: 618921a55d8Smrg if (i > 3) 619921a55d8Smrg return 0; 620921a55d8Smrg break; 621921a55d8Smrg case 4: 622921a55d8Smrg default: 623921a55d8Smrg break; 624921a55d8Smrg } 625921a55d8Smrg if (dp_clocks[i] > (mode_clock/10)) { 626921a55d8Smrg if (i < 2) 627921a55d8Smrg return 1; 628921a55d8Smrg else if (i < 4) 629921a55d8Smrg return 2; 630921a55d8Smrg else 631921a55d8Smrg return 4; 632921a55d8Smrg } 633ad43ddacSmrg } 634ad43ddacSmrg break; 635ad43ddacSmrg case DP_LINK_BW_2_7: 636ad43ddacSmrg for (i = 0; i < num_dp_clocks; i++) { 637921a55d8Smrg switch (max_lane_count) { 638921a55d8Smrg case 1: 639921a55d8Smrg if (i > 1) 640921a55d8Smrg return 0; 641921a55d8Smrg break; 642921a55d8Smrg case 2: 643921a55d8Smrg if (i > 3) 644921a55d8Smrg return 0; 645921a55d8Smrg break; 646921a55d8Smrg case 4: 647921a55d8Smrg default: 648921a55d8Smrg break; 649921a55d8Smrg } 650921a55d8Smrg if (dp_clocks[i] > (mode_clock/10)) { 651921a55d8Smrg if (i < 2) 652921a55d8Smrg return 1; 653921a55d8Smrg else if (i < 4) 654921a55d8Smrg return 2; 655921a55d8Smrg else 656921a55d8Smrg return 4; 657921a55d8Smrg } 658ad43ddacSmrg } 659ad43ddacSmrg break; 660ad43ddacSmrg } 661209ff23fSmrg 662b7e1c893Smrg return 0; 663b7e1c893Smrg} 664209ff23fSmrg 665b7e1c893Smrgstatic int 666921a55d8Smrgdp_link_clock_for_mode_clock(xf86OutputPtr output, int mode_clock) 667b7e1c893Smrg{ 668921a55d8Smrg RADEONOutputPrivatePtr radeon_output = output->driver_private; 669b7e1c893Smrg int i; 670ad43ddacSmrg int max_link_bw = radeon_output->dpcd[1]; 671921a55d8Smrg int max_lane_count = radeon_dp_max_lane_count(output); 672209ff23fSmrg 673ad43ddacSmrg switch (max_link_bw) { 674ad43ddacSmrg case DP_LINK_BW_1_62: 675ad43ddacSmrg default: 676921a55d8Smrg for (i = 0; i < num_dp_clocks; i++) { 677921a55d8Smrg if (i % 2) 678921a55d8Smrg continue; 679921a55d8Smrg switch (max_lane_count) { 680921a55d8Smrg case 1: 681921a55d8Smrg if (i > 1) 682921a55d8Smrg return 0; 683921a55d8Smrg break; 684921a55d8Smrg case 2: 685921a55d8Smrg if (i > 3) 686921a55d8Smrg return 0; 687921a55d8Smrg break; 688921a55d8Smrg case 4: 689921a55d8Smrg default: 690921a55d8Smrg break; 691921a55d8Smrg } 692921a55d8Smrg if (dp_clocks[i] > (mode_clock/10)) 693921a55d8Smrg return 16200; 694921a55d8Smrg } 695ad43ddacSmrg break; 696ad43ddacSmrg case DP_LINK_BW_2_7: 697921a55d8Smrg for (i = 0; i < num_dp_clocks; i++) { 698921a55d8Smrg switch (max_lane_count) { 699921a55d8Smrg case 1: 700921a55d8Smrg if (i > 1) 701921a55d8Smrg return 0; 702921a55d8Smrg break; 703921a55d8Smrg case 2: 704921a55d8Smrg if (i > 3) 705921a55d8Smrg return 0; 706921a55d8Smrg break; 707921a55d8Smrg case 4: 708921a55d8Smrg default: 709921a55d8Smrg break; 710921a55d8Smrg } 711921a55d8Smrg if (dp_clocks[i] > (mode_clock/10)) 712921a55d8Smrg return (i % 2) ? 27000 : 16200; 713921a55d8Smrg } 714ad43ddacSmrg break; 715ad43ddacSmrg } 716b7e1c893Smrg 717b7e1c893Smrg return 0; 718209ff23fSmrg} 719209ff23fSmrg 720ad43ddacSmrg/* 721ad43ddacSmrg * DIG Encoder/Transmitter Setup 722ad43ddacSmrg * 723ad43ddacSmrg * DCE 3.0/3.1 724ad43ddacSmrg * - 2 DIG transmitter blocks. UNIPHY (links A and B) and LVTMA. 725ad43ddacSmrg * Supports up to 3 digital outputs 726ad43ddacSmrg * - 2 DIG encoder blocks. 727ad43ddacSmrg * DIG1 can drive UNIPHY link A or link B 728ad43ddacSmrg * DIG2 can drive UNIPHY link B or LVTMA 729ad43ddacSmrg * 730ad43ddacSmrg * DCE 3.2 731ad43ddacSmrg * - 3 DIG transmitter blocks. UNIPHY0/1/2 (links A and B). 732ad43ddacSmrg * Supports up to 5 digital outputs 733ad43ddacSmrg * - 2 DIG encoder blocks. 734ad43ddacSmrg * DIG1/2 can drive UNIPHY0/1/2 link A or link B 735ad43ddacSmrg * 7360974d292Smrg * DCE 4.0 7370974d292Smrg * - 3 DIG transmitter blocks UNPHY0/1/2 (links A and B). 7380974d292Smrg * Supports up to 6 digital outputs 7390974d292Smrg * - 6 DIG encoder blocks. 7400974d292Smrg * - DIG to PHY mapping is hardcoded 7410974d292Smrg * DIG1 drives UNIPHY0 link A, A+B 7420974d292Smrg * DIG2 drives UNIPHY0 link B 7430974d292Smrg * DIG3 drives UNIPHY1 link A, A+B 7440974d292Smrg * DIG4 drives UNIPHY1 link B 7450974d292Smrg * DIG5 drives UNIPHY2 link A, A+B 7460974d292Smrg * DIG6 drives UNIPHY2 link B 7470974d292Smrg * 748ad43ddacSmrg * Routing 749ad43ddacSmrg * crtc -> dig encoder -> UNIPHY/LVTMA (1 or 2 links) 750ad43ddacSmrg * Examples: 751ad43ddacSmrg * crtc0 -> dig2 -> LVTMA links A+B 752ad43ddacSmrg * crtc1 -> dig1 -> UNIPHY0 link B 7530974d292Smrg * crtc0 -> dig1 -> UNIPHY2 link A -> LVDS 7540974d292Smrg * crtc1 -> dig2 -> UNIPHY1 link B+A -> TMDS/HDMI 755ad43ddacSmrg */ 7560974d292Smrg 7570974d292Smrgunion dig_encoder_control { 7580974d292Smrg DIG_ENCODER_CONTROL_PS_ALLOCATION v1; 7590974d292Smrg DIG_ENCODER_CONTROL_PARAMETERS_V2 v2; 7600974d292Smrg DIG_ENCODER_CONTROL_PARAMETERS_V3 v3; 7610974d292Smrg}; 7620974d292Smrg 763209ff23fSmrgstatic int 764b7e1c893Smrgatombios_output_dig_encoder_setup(xf86OutputPtr output, int action) 765209ff23fSmrg{ 766209ff23fSmrg RADEONOutputPrivatePtr radeon_output = output->driver_private; 767209ff23fSmrg RADEONInfoPtr info = RADEONPTR(output->scrn); 768b7e1c893Smrg radeon_encoder_ptr radeon_encoder = radeon_get_encoder(output); 7690974d292Smrg union dig_encoder_control disp_data; 770209ff23fSmrg AtomBiosArgRec data; 771209ff23fSmrg unsigned char *space; 772ad43ddacSmrg int index = 0, major, minor; 773b7e1c893Smrg int clock = radeon_output->pixel_clock; 774b7e1c893Smrg 775b7e1c893Smrg if (radeon_encoder == NULL) 776b7e1c893Smrg return ATOM_NOT_IMPLEMENTED; 777b7e1c893Smrg 778b7e1c893Smrg memset(&disp_data,0, sizeof(disp_data)); 779b7e1c893Smrg 7800974d292Smrg if (IS_DCE4_VARIANT) 7810974d292Smrg index = GetIndexIntoMasterTable(COMMAND, DIGxEncoderControl); 7820974d292Smrg else if (radeon_output->dig_encoder) 783ad43ddacSmrg index = GetIndexIntoMasterTable(COMMAND, DIG2EncoderControl); 784ad43ddacSmrg else 785ad43ddacSmrg index = GetIndexIntoMasterTable(COMMAND, DIG1EncoderControl); 786209ff23fSmrg 787b7e1c893Smrg atombios_get_command_table_version(info->atomBIOS, index, &major, &minor); 788b7e1c893Smrg 7890974d292Smrg disp_data.v1.ucAction = action; 7900974d292Smrg disp_data.v1.usPixelClock = cpu_to_le16(clock / 10); 7910974d292Smrg disp_data.v1.ucEncoderMode = atombios_get_encoder_mode(output); 792b7e1c893Smrg 7930974d292Smrg if (disp_data.v1.ucEncoderMode == ATOM_ENCODER_MODE_DP) { 794921a55d8Smrg if (dp_link_clock_for_mode_clock(output, clock) == 27000) 7950974d292Smrg disp_data.v1.ucConfig |= ATOM_ENCODER_CONFIG_DPLINKRATE_2_70GHZ; 796921a55d8Smrg disp_data.v1.ucLaneNum = dp_lanes_for_mode_clock(output, clock); 7970974d292Smrg } else if (clock > 165000) 7980974d292Smrg disp_data.v1.ucLaneNum = 8; 7990974d292Smrg else 8000974d292Smrg disp_data.v1.ucLaneNum = 4; 8010974d292Smrg 8020974d292Smrg if (IS_DCE4_VARIANT) { 8030974d292Smrg disp_data.v3.acConfig.ucDigSel = radeon_output->dig_encoder; 8040974d292Smrg disp_data.v3.ucBitPerColor = PANEL_8BIT_PER_COLOR; 8050974d292Smrg } else { 806b7e1c893Smrg switch (radeon_encoder->encoder_id) { 807b7e1c893Smrg case ENCODER_OBJECT_ID_INTERNAL_UNIPHY: 8080974d292Smrg disp_data.v1.ucConfig = ATOM_ENCODER_CONFIG_V2_TRANSMITTER1; 809b7e1c893Smrg break; 810b7e1c893Smrg case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1: 811921a55d8Smrg case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA: 8120974d292Smrg disp_data.v1.ucConfig = ATOM_ENCODER_CONFIG_V2_TRANSMITTER2; 813b7e1c893Smrg break; 814b7e1c893Smrg case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2: 8150974d292Smrg disp_data.v1.ucConfig = ATOM_ENCODER_CONFIG_V2_TRANSMITTER3; 816b7e1c893Smrg break; 817b7e1c893Smrg } 8180974d292Smrg if (radeon_output->linkb) 8190974d292Smrg disp_data.v1.ucConfig |= ATOM_ENCODER_CONFIG_LINKB; 8200974d292Smrg else 8210974d292Smrg disp_data.v1.ucConfig |= ATOM_ENCODER_CONFIG_LINKA; 822209ff23fSmrg } 823209ff23fSmrg 824b7e1c893Smrg data.exec.index = index; 825209ff23fSmrg data.exec.dataSpace = (void *)&space; 826209ff23fSmrg data.exec.pspace = &disp_data; 827209ff23fSmrg 82868105dcbSveego if (RHDAtomBiosFunc(info->atomBIOS->pScrn, info->atomBIOS, ATOMBIOS_EXEC, &data) == ATOM_SUCCESS) { 829042789b0Sveego/* ErrorF("Output DIG%d encoder setup success\n", radeon_output->dig_encoder); */ 830209ff23fSmrg return ATOM_SUCCESS; 831209ff23fSmrg } 832209ff23fSmrg 833ad43ddacSmrg ErrorF("Output DIG%d setup failed\n", radeon_output->dig_encoder); 834209ff23fSmrg return ATOM_NOT_IMPLEMENTED; 835209ff23fSmrg 836209ff23fSmrg} 837209ff23fSmrg 838b7e1c893Smrgunion dig_transmitter_control { 839b7e1c893Smrg DIG_TRANSMITTER_CONTROL_PS_ALLOCATION v1; 840b7e1c893Smrg DIG_TRANSMITTER_CONTROL_PARAMETERS_V2 v2; 841ad43ddacSmrg DIG_TRANSMITTER_CONTROL_PARAMETERS_V3 v3; 842b7e1c893Smrg}; 843b7e1c893Smrg 844209ff23fSmrgstatic int 845ad43ddacSmrgatombios_output_dig_transmitter_setup(xf86OutputPtr output, int action, uint8_t lane_num, uint8_t lane_set) 846209ff23fSmrg{ 847209ff23fSmrg RADEONOutputPrivatePtr radeon_output = output->driver_private; 848209ff23fSmrg RADEONInfoPtr info = RADEONPTR(output->scrn); 849b7e1c893Smrg radeon_encoder_ptr radeon_encoder = radeon_get_encoder(output); 850b7e1c893Smrg union dig_transmitter_control disp_data; 851209ff23fSmrg AtomBiosArgRec data; 852209ff23fSmrg unsigned char *space; 853b7e1c893Smrg int index = 0, num = 0; 854b7e1c893Smrg int major, minor; 855b7e1c893Smrg int clock = radeon_output->pixel_clock; 856b7e1c893Smrg 857b7e1c893Smrg if (radeon_encoder == NULL) 858b7e1c893Smrg return ATOM_NOT_IMPLEMENTED; 859b7e1c893Smrg 860b7e1c893Smrg memset(&disp_data,0, sizeof(disp_data)); 861b7e1c893Smrg 862ad43ddacSmrg if (IS_DCE32_VARIANT || IS_DCE4_VARIANT) 863b7e1c893Smrg index = GetIndexIntoMasterTable(COMMAND, UNIPHYTransmitterControl); 864b7e1c893Smrg else { 865b7e1c893Smrg switch (radeon_encoder->encoder_id) { 866b7e1c893Smrg case ENCODER_OBJECT_ID_INTERNAL_UNIPHY: 867b7e1c893Smrg index = GetIndexIntoMasterTable(COMMAND, DIG1TransmitterControl); 868b7e1c893Smrg break; 869b7e1c893Smrg case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA: 870b7e1c893Smrg index = GetIndexIntoMasterTable(COMMAND, DIG2TransmitterControl); 871b7e1c893Smrg break; 872b7e1c893Smrg } 873b7e1c893Smrg } 874209ff23fSmrg 875b7e1c893Smrg atombios_get_command_table_version(info->atomBIOS, index, &major, &minor); 876b7e1c893Smrg 877b7e1c893Smrg disp_data.v1.ucAction = action; 8780974d292Smrg if (action == ATOM_TRANSMITTER_ACTION_INIT) { 8790974d292Smrg disp_data.v1.usInitInfo = radeon_output->connector_object_id; 8800974d292Smrg } else if (action == ATOM_TRANSMITTER_ACTION_SETUP_VSEMPH) { 8810974d292Smrg disp_data.v1.asMode.ucLaneSel = lane_num; 8820974d292Smrg disp_data.v1.asMode.ucLaneSet = lane_set; 8830974d292Smrg } else { 8840974d292Smrg if (radeon_output->MonType == MT_DP) 8850974d292Smrg disp_data.v1.usPixelClock = 886921a55d8Smrg cpu_to_le16(dp_link_clock_for_mode_clock(output, clock)); 8870974d292Smrg else if (clock > 165000) 8880974d292Smrg disp_data.v1.usPixelClock = cpu_to_le16((clock / 2) / 10); 8890974d292Smrg else 8900974d292Smrg disp_data.v1.usPixelClock = cpu_to_le16(clock / 10); 8910974d292Smrg } 892b7e1c893Smrg 893ad43ddacSmrg if (IS_DCE4_VARIANT) { 894ad43ddacSmrg if (radeon_output->MonType == MT_DP) 895921a55d8Smrg disp_data.v3.ucLaneNum = dp_lanes_for_mode_clock(output, clock); 896ad43ddacSmrg else if (clock > 165000) 897ad43ddacSmrg disp_data.v3.ucLaneNum = 8; 898ad43ddacSmrg else 899ad43ddacSmrg disp_data.v3.ucLaneNum = 4; 900ad43ddacSmrg 901ad43ddacSmrg if (radeon_output->linkb) { 902ad43ddacSmrg disp_data.v3.acConfig.ucLinkSel = 1; 903b7e1c893Smrg disp_data.v2.acConfig.ucEncoderSel = 1; 904ad43ddacSmrg } 905ad43ddacSmrg 906ad43ddacSmrg // select the PLL for the UNIPHY 9070974d292Smrg if (radeon_output->MonType == MT_DP && info->dp_extclk) 908ad43ddacSmrg disp_data.v3.acConfig.ucRefClkSource = 2; /* ext clk */ 909ad43ddacSmrg else 910ad43ddacSmrg disp_data.v3.acConfig.ucRefClkSource = radeon_output->pll_id; 911ad43ddacSmrg 912ad43ddacSmrg switch (radeon_encoder->encoder_id) { 913ad43ddacSmrg case ENCODER_OBJECT_ID_INTERNAL_UNIPHY: 914ad43ddacSmrg disp_data.v3.acConfig.ucTransmitterSel = 0; 915ad43ddacSmrg num = 0; 916ad43ddacSmrg break; 917ad43ddacSmrg case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1: 918ad43ddacSmrg disp_data.v3.acConfig.ucTransmitterSel = 1; 919ad43ddacSmrg num = 1; 920ad43ddacSmrg break; 921ad43ddacSmrg case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2: 922ad43ddacSmrg disp_data.v3.acConfig.ucTransmitterSel = 2; 923ad43ddacSmrg num = 2; 924ad43ddacSmrg break; 925ad43ddacSmrg } 926ad43ddacSmrg 927ad43ddacSmrg if (radeon_output->MonType == MT_DP) 928ad43ddacSmrg disp_data.v3.acConfig.fCoherentMode = 1; /* DP requires coherent */ 929ad43ddacSmrg else if (radeon_output->active_device & (ATOM_DEVICE_DFP_SUPPORT)) { 930ad43ddacSmrg if (radeon_output->coherent_mode) 931ad43ddacSmrg disp_data.v3.acConfig.fCoherentMode = 1; 9320974d292Smrg if (clock > 165000) 9330974d292Smrg disp_data.v3.acConfig.fDualLinkConnector = 1; 934ad43ddacSmrg } 935ad43ddacSmrg } else if (IS_DCE32_VARIANT) { 936ad43ddacSmrg if (radeon_output->dig_encoder) 937ad43ddacSmrg disp_data.v2.acConfig.ucEncoderSel = 1; 938ad43ddacSmrg 939ad43ddacSmrg if (radeon_output->linkb) 940ad43ddacSmrg disp_data.v2.acConfig.ucLinkSel = 1; 941b7e1c893Smrg 942b7e1c893Smrg switch (radeon_encoder->encoder_id) { 943b7e1c893Smrg case ENCODER_OBJECT_ID_INTERNAL_UNIPHY: 944b7e1c893Smrg disp_data.v2.acConfig.ucTransmitterSel = 0; 945b7e1c893Smrg num = 0; 946b7e1c893Smrg break; 947b7e1c893Smrg case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1: 948b7e1c893Smrg disp_data.v2.acConfig.ucTransmitterSel = 1; 949b7e1c893Smrg num = 1; 950b7e1c893Smrg break; 951b7e1c893Smrg case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2: 952b7e1c893Smrg disp_data.v2.acConfig.ucTransmitterSel = 2; 953b7e1c893Smrg num = 2; 954b7e1c893Smrg break; 955b7e1c893Smrg } 956b7e1c893Smrg 957ad43ddacSmrg if (radeon_output->MonType == MT_DP) 958ad43ddacSmrg disp_data.v2.acConfig.fCoherentMode = 1; /* DP requires coherent */ 959ad43ddacSmrg else if (radeon_output->active_device & (ATOM_DEVICE_DFP_SUPPORT)) { 960ad43ddacSmrg if (radeon_output->coherent_mode) 961b7e1c893Smrg disp_data.v2.acConfig.fCoherentMode = 1; 962921a55d8Smrg if (clock > 165000) 963921a55d8Smrg disp_data.v2.acConfig.fDualLinkConnector = 1; 964209ff23fSmrg } 965209ff23fSmrg } else { 966b7e1c893Smrg disp_data.v1.ucConfig = ATOM_TRANSMITTER_CONFIG_CLKSRC_PPLL; 967b7e1c893Smrg 968ad43ddacSmrg if (radeon_output->dig_encoder) 969ad43ddacSmrg disp_data.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_DIG2_ENCODER; 970209ff23fSmrg else 971ad43ddacSmrg disp_data.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_DIG1_ENCODER; 972b7e1c893Smrg 973b7e1c893Smrg switch (radeon_encoder->encoder_id) { 974b7e1c893Smrg case ENCODER_OBJECT_ID_INTERNAL_UNIPHY: 975b7e1c893Smrg if (info->IsIGP) { 976b7e1c893Smrg if (clock > 165000) { 977b7e1c893Smrg if (radeon_output->igp_lane_info & 0x3) 978b7e1c893Smrg disp_data.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LANE_0_7; 979b7e1c893Smrg else if (radeon_output->igp_lane_info & 0xc) 980b7e1c893Smrg disp_data.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LANE_8_15; 981b7e1c893Smrg } else { 982b7e1c893Smrg if (radeon_output->igp_lane_info & 0x1) 983b7e1c893Smrg disp_data.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LANE_0_3; 984b7e1c893Smrg else if (radeon_output->igp_lane_info & 0x2) 985b7e1c893Smrg disp_data.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LANE_4_7; 986b7e1c893Smrg else if (radeon_output->igp_lane_info & 0x4) 987b7e1c893Smrg disp_data.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LANE_8_11; 988b7e1c893Smrg else if (radeon_output->igp_lane_info & 0x8) 989b7e1c893Smrg disp_data.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LANE_12_15; 990b7e1c893Smrg } 991b7e1c893Smrg } 992b7e1c893Smrg break; 993b7e1c893Smrg } 994ad43ddacSmrg if (radeon_output->linkb) 995ad43ddacSmrg disp_data.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LINKB; 996ad43ddacSmrg else 997ad43ddacSmrg disp_data.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LINKA; 998209ff23fSmrg 999ad43ddacSmrg if (radeon_output->MonType == MT_DP) 1000ad43ddacSmrg disp_data.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_COHERENT; /* DP requires coherent */ 1001ad43ddacSmrg else if (radeon_output->active_device & (ATOM_DEVICE_DFP_SUPPORT)) { 1002ad43ddacSmrg if (radeon_output->coherent_mode) 1003b7e1c893Smrg disp_data.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_COHERENT; 10040974d292Smrg if (clock > 165000) 10050974d292Smrg disp_data.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_8LANE_LINK; 1006b7e1c893Smrg } 1007b7e1c893Smrg } 1008209ff23fSmrg 1009b7e1c893Smrg data.exec.index = index; 1010209ff23fSmrg data.exec.dataSpace = (void *)&space; 1011209ff23fSmrg data.exec.pspace = &disp_data; 1012209ff23fSmrg 101368105dcbSveego if (RHDAtomBiosFunc(info->atomBIOS->pScrn, info->atomBIOS, ATOMBIOS_EXEC, &data) == ATOM_SUCCESS) { 1014042789b0Sveego/* 1015b7e1c893Smrg if (IS_DCE32_VARIANT) 1016b7e1c893Smrg ErrorF("Output UNIPHY%d transmitter setup success\n", num); 1017b7e1c893Smrg else 1018b7e1c893Smrg ErrorF("Output DIG%d transmitter setup success\n", num); 1019042789b0Sveego*/ 1020209ff23fSmrg return ATOM_SUCCESS; 1021209ff23fSmrg } 1022209ff23fSmrg 1023b7e1c893Smrg ErrorF("Output DIG%d transmitter setup failed\n", num); 1024209ff23fSmrg return ATOM_NOT_IMPLEMENTED; 1025209ff23fSmrg 1026209ff23fSmrg} 1027209ff23fSmrg 1028c503f109Smrgstatic void atom_rv515_force_tv_scaler(ScrnInfoPtr pScrn, RADEONCrtcPrivatePtr radeon_crtc) 1029b7e1c893Smrg{ 1030b7e1c893Smrg RADEONInfoPtr info = RADEONPTR(pScrn); 1031b7e1c893Smrg unsigned char *RADEONMMIO = info->MMIO; 1032c503f109Smrg int index_reg = 0x6578, data_reg = 0x657c; 1033c503f109Smrg 1034c503f109Smrg index_reg += radeon_crtc->crtc_offset; 1035c503f109Smrg data_reg += radeon_crtc->crtc_offset; 1036c503f109Smrg 1037c503f109Smrg OUTREG(0x659C + radeon_crtc->crtc_offset, 0x0); 1038c503f109Smrg OUTREG(0x6594 + radeon_crtc->crtc_offset, 0x705); 1039c503f109Smrg OUTREG(0x65A4 + radeon_crtc->crtc_offset, 0x10001); 1040c503f109Smrg OUTREG(0x65D8 + radeon_crtc->crtc_offset, 0x0); 1041c503f109Smrg OUTREG(0x65B0 + radeon_crtc->crtc_offset, 0x0); 1042c503f109Smrg OUTREG(0x65C0 + radeon_crtc->crtc_offset, 0x0); 1043c503f109Smrg OUTREG(0x65D4 + radeon_crtc->crtc_offset, 0x0); 1044c503f109Smrg OUTREG(index_reg,0x0); 1045c503f109Smrg OUTREG(data_reg,0x841880A8); 1046c503f109Smrg OUTREG(index_reg,0x1); 1047c503f109Smrg OUTREG(data_reg,0x84208680); 1048c503f109Smrg OUTREG(index_reg,0x2); 1049c503f109Smrg OUTREG(data_reg,0xBFF880B0); 1050c503f109Smrg OUTREG(index_reg,0x100); 1051c503f109Smrg OUTREG(data_reg,0x83D88088); 1052c503f109Smrg OUTREG(index_reg,0x101); 1053c503f109Smrg OUTREG(data_reg,0x84608680); 1054c503f109Smrg OUTREG(index_reg,0x102); 1055c503f109Smrg OUTREG(data_reg,0xBFF080D0); 1056c503f109Smrg OUTREG(index_reg,0x200); 1057c503f109Smrg OUTREG(data_reg,0x83988068); 1058c503f109Smrg OUTREG(index_reg,0x201); 1059c503f109Smrg OUTREG(data_reg,0x84A08680); 1060c503f109Smrg OUTREG(index_reg,0x202); 1061c503f109Smrg OUTREG(data_reg,0xBFF080F8); 1062c503f109Smrg OUTREG(index_reg,0x300); 1063c503f109Smrg OUTREG(data_reg,0x83588058); 1064c503f109Smrg OUTREG(index_reg,0x301); 1065c503f109Smrg OUTREG(data_reg,0x84E08660); 1066c503f109Smrg OUTREG(index_reg,0x302); 1067c503f109Smrg OUTREG(data_reg,0xBFF88120); 1068c503f109Smrg OUTREG(index_reg,0x400); 1069c503f109Smrg OUTREG(data_reg,0x83188040); 1070c503f109Smrg OUTREG(index_reg,0x401); 1071c503f109Smrg OUTREG(data_reg,0x85008660); 1072c503f109Smrg OUTREG(index_reg,0x402); 1073c503f109Smrg OUTREG(data_reg,0xBFF88150); 1074c503f109Smrg OUTREG(index_reg,0x500); 1075c503f109Smrg OUTREG(data_reg,0x82D88030); 1076c503f109Smrg OUTREG(index_reg,0x501); 1077c503f109Smrg OUTREG(data_reg,0x85408640); 1078c503f109Smrg OUTREG(index_reg,0x502); 1079c503f109Smrg OUTREG(data_reg,0xBFF88180); 1080c503f109Smrg OUTREG(index_reg,0x600); 1081c503f109Smrg OUTREG(data_reg,0x82A08018); 1082c503f109Smrg OUTREG(index_reg,0x601); 1083c503f109Smrg OUTREG(data_reg,0x85808620); 1084c503f109Smrg OUTREG(index_reg,0x602); 1085c503f109Smrg OUTREG(data_reg,0xBFF081B8); 1086c503f109Smrg OUTREG(index_reg,0x700); 1087c503f109Smrg OUTREG(data_reg,0x82608010); 1088c503f109Smrg OUTREG(index_reg,0x701); 1089c503f109Smrg OUTREG(data_reg,0x85A08600); 1090c503f109Smrg OUTREG(index_reg,0x702); 1091c503f109Smrg OUTREG(data_reg,0x800081F0); 1092c503f109Smrg OUTREG(index_reg,0x800); 1093c503f109Smrg OUTREG(data_reg,0x8228BFF8); 1094c503f109Smrg OUTREG(index_reg,0x801); 1095c503f109Smrg OUTREG(data_reg,0x85E085E0); 1096c503f109Smrg OUTREG(index_reg,0x802); 1097c503f109Smrg OUTREG(data_reg,0xBFF88228); 1098c503f109Smrg OUTREG(index_reg,0x10000); 1099c503f109Smrg OUTREG(data_reg,0x82A8BF00); 1100c503f109Smrg OUTREG(index_reg,0x10001); 1101c503f109Smrg OUTREG(data_reg,0x82A08CC0); 1102c503f109Smrg OUTREG(index_reg,0x10002); 1103c503f109Smrg OUTREG(data_reg,0x8008BEF8); 1104c503f109Smrg OUTREG(index_reg,0x10100); 1105c503f109Smrg OUTREG(data_reg,0x81F0BF28); 1106c503f109Smrg OUTREG(index_reg,0x10101); 1107c503f109Smrg OUTREG(data_reg,0x83608CA0); 1108c503f109Smrg OUTREG(index_reg,0x10102); 1109c503f109Smrg OUTREG(data_reg,0x8018BED0); 1110c503f109Smrg OUTREG(index_reg,0x10200); 1111c503f109Smrg OUTREG(data_reg,0x8148BF38); 1112c503f109Smrg OUTREG(index_reg,0x10201); 1113c503f109Smrg OUTREG(data_reg,0x84408C80); 1114c503f109Smrg OUTREG(index_reg,0x10202); 1115c503f109Smrg OUTREG(data_reg,0x8008BEB8); 1116c503f109Smrg OUTREG(index_reg,0x10300); 1117c503f109Smrg OUTREG(data_reg,0x80B0BF78); 1118c503f109Smrg OUTREG(index_reg,0x10301); 1119c503f109Smrg OUTREG(data_reg,0x85008C20); 1120c503f109Smrg OUTREG(index_reg,0x10302); 1121c503f109Smrg OUTREG(data_reg,0x8020BEA0); 1122c503f109Smrg OUTREG(index_reg,0x10400); 1123c503f109Smrg OUTREG(data_reg,0x8028BF90); 1124c503f109Smrg OUTREG(index_reg,0x10401); 1125c503f109Smrg OUTREG(data_reg,0x85E08BC0); 1126c503f109Smrg OUTREG(index_reg,0x10402); 1127c503f109Smrg OUTREG(data_reg,0x8018BE90); 1128c503f109Smrg OUTREG(index_reg,0x10500); 1129c503f109Smrg OUTREG(data_reg,0xBFB8BFB0); 1130c503f109Smrg OUTREG(index_reg,0x10501); 1131c503f109Smrg OUTREG(data_reg,0x86C08B40); 1132c503f109Smrg OUTREG(index_reg,0x10502); 1133c503f109Smrg OUTREG(data_reg,0x8010BE90); 1134c503f109Smrg OUTREG(index_reg,0x10600); 1135c503f109Smrg OUTREG(data_reg,0xBF58BFC8); 1136c503f109Smrg OUTREG(index_reg,0x10601); 1137c503f109Smrg OUTREG(data_reg,0x87A08AA0); 1138c503f109Smrg OUTREG(index_reg,0x10602); 1139c503f109Smrg OUTREG(data_reg,0x8010BE98); 1140c503f109Smrg OUTREG(index_reg,0x10700); 1141c503f109Smrg OUTREG(data_reg,0xBF10BFF0); 1142c503f109Smrg OUTREG(index_reg,0x10701); 1143c503f109Smrg OUTREG(data_reg,0x886089E0); 1144c503f109Smrg OUTREG(index_reg,0x10702); 1145c503f109Smrg OUTREG(data_reg,0x8018BEB0); 1146c503f109Smrg OUTREG(index_reg,0x10800); 1147c503f109Smrg OUTREG(data_reg,0xBED8BFE8); 1148c503f109Smrg OUTREG(index_reg,0x10801); 1149c503f109Smrg OUTREG(data_reg,0x89408940); 1150c503f109Smrg OUTREG(index_reg,0x10802); 1151c503f109Smrg OUTREG(data_reg,0xBFE8BED8); 1152c503f109Smrg OUTREG(index_reg,0x20000); 1153c503f109Smrg OUTREG(data_reg,0x80008000); 1154c503f109Smrg OUTREG(index_reg,0x20001); 1155c503f109Smrg OUTREG(data_reg,0x90008000); 1156c503f109Smrg OUTREG(index_reg,0x20002); 1157c503f109Smrg OUTREG(data_reg,0x80008000); 1158c503f109Smrg OUTREG(index_reg,0x20003); 1159c503f109Smrg OUTREG(data_reg,0x80008000); 1160c503f109Smrg OUTREG(index_reg,0x20100); 1161c503f109Smrg OUTREG(data_reg,0x80108000); 1162c503f109Smrg OUTREG(index_reg,0x20101); 1163c503f109Smrg OUTREG(data_reg,0x8FE0BF70); 1164c503f109Smrg OUTREG(index_reg,0x20102); 1165c503f109Smrg OUTREG(data_reg,0xBFE880C0); 1166c503f109Smrg OUTREG(index_reg,0x20103); 1167c503f109Smrg OUTREG(data_reg,0x80008000); 1168c503f109Smrg OUTREG(index_reg,0x20200); 1169c503f109Smrg OUTREG(data_reg,0x8018BFF8); 1170c503f109Smrg OUTREG(index_reg,0x20201); 1171c503f109Smrg OUTREG(data_reg,0x8F80BF08); 1172c503f109Smrg OUTREG(index_reg,0x20202); 1173c503f109Smrg OUTREG(data_reg,0xBFD081A0); 1174c503f109Smrg OUTREG(index_reg,0x20203); 1175c503f109Smrg OUTREG(data_reg,0xBFF88000); 1176c503f109Smrg OUTREG(index_reg,0x20300); 1177c503f109Smrg OUTREG(data_reg,0x80188000); 1178c503f109Smrg OUTREG(index_reg,0x20301); 1179c503f109Smrg OUTREG(data_reg,0x8EE0BEC0); 1180c503f109Smrg OUTREG(index_reg,0x20302); 1181c503f109Smrg OUTREG(data_reg,0xBFB082A0); 1182c503f109Smrg OUTREG(index_reg,0x20303); 1183c503f109Smrg OUTREG(data_reg,0x80008000); 1184c503f109Smrg OUTREG(index_reg,0x20400); 1185c503f109Smrg OUTREG(data_reg,0x80188000); 1186c503f109Smrg OUTREG(index_reg,0x20401); 1187c503f109Smrg OUTREG(data_reg,0x8E00BEA0); 1188c503f109Smrg OUTREG(index_reg,0x20402); 1189c503f109Smrg OUTREG(data_reg,0xBF8883C0); 1190c503f109Smrg OUTREG(index_reg,0x20403); 1191c503f109Smrg OUTREG(data_reg,0x80008000); 1192c503f109Smrg OUTREG(index_reg,0x20500); 1193c503f109Smrg OUTREG(data_reg,0x80188000); 1194c503f109Smrg OUTREG(index_reg,0x20501); 1195c503f109Smrg OUTREG(data_reg,0x8D00BE90); 1196c503f109Smrg OUTREG(index_reg,0x20502); 1197c503f109Smrg OUTREG(data_reg,0xBF588500); 1198c503f109Smrg OUTREG(index_reg,0x20503); 1199c503f109Smrg OUTREG(data_reg,0x80008008); 1200c503f109Smrg OUTREG(index_reg,0x20600); 1201c503f109Smrg OUTREG(data_reg,0x80188000); 1202c503f109Smrg OUTREG(index_reg,0x20601); 1203c503f109Smrg OUTREG(data_reg,0x8BC0BE98); 1204c503f109Smrg OUTREG(index_reg,0x20602); 1205c503f109Smrg OUTREG(data_reg,0xBF308660); 1206c503f109Smrg OUTREG(index_reg,0x20603); 1207c503f109Smrg OUTREG(data_reg,0x80008008); 1208c503f109Smrg OUTREG(index_reg,0x20700); 1209c503f109Smrg OUTREG(data_reg,0x80108000); 1210c503f109Smrg OUTREG(index_reg,0x20701); 1211c503f109Smrg OUTREG(data_reg,0x8A80BEB0); 1212c503f109Smrg OUTREG(index_reg,0x20702); 1213c503f109Smrg OUTREG(data_reg,0xBF0087C0); 1214c503f109Smrg OUTREG(index_reg,0x20703); 1215c503f109Smrg OUTREG(data_reg,0x80008008); 1216c503f109Smrg OUTREG(index_reg,0x20800); 1217c503f109Smrg OUTREG(data_reg,0x80108000); 1218c503f109Smrg OUTREG(index_reg,0x20801); 1219c503f109Smrg OUTREG(data_reg,0x8920BED0); 1220c503f109Smrg OUTREG(index_reg,0x20802); 1221c503f109Smrg OUTREG(data_reg,0xBED08920); 1222c503f109Smrg OUTREG(index_reg,0x20803); 1223c503f109Smrg OUTREG(data_reg,0x80008010); 1224c503f109Smrg OUTREG(index_reg,0x30000); 1225c503f109Smrg OUTREG(data_reg,0x90008000); 1226c503f109Smrg OUTREG(index_reg,0x30001); 1227c503f109Smrg OUTREG(data_reg,0x80008000); 1228c503f109Smrg OUTREG(index_reg,0x30100); 1229c503f109Smrg OUTREG(data_reg,0x8FE0BF90); 1230c503f109Smrg OUTREG(index_reg,0x30101); 1231c503f109Smrg OUTREG(data_reg,0xBFF880A0); 1232c503f109Smrg OUTREG(index_reg,0x30200); 1233c503f109Smrg OUTREG(data_reg,0x8F60BF40); 1234c503f109Smrg OUTREG(index_reg,0x30201); 1235c503f109Smrg OUTREG(data_reg,0xBFE88180); 1236c503f109Smrg OUTREG(index_reg,0x30300); 1237c503f109Smrg OUTREG(data_reg,0x8EC0BF00); 1238c503f109Smrg OUTREG(index_reg,0x30301); 1239c503f109Smrg OUTREG(data_reg,0xBFC88280); 1240c503f109Smrg OUTREG(index_reg,0x30400); 1241c503f109Smrg OUTREG(data_reg,0x8DE0BEE0); 1242c503f109Smrg OUTREG(index_reg,0x30401); 1243c503f109Smrg OUTREG(data_reg,0xBFA083A0); 1244c503f109Smrg OUTREG(index_reg,0x30500); 1245c503f109Smrg OUTREG(data_reg,0x8CE0BED0); 1246c503f109Smrg OUTREG(index_reg,0x30501); 1247c503f109Smrg OUTREG(data_reg,0xBF7884E0); 1248c503f109Smrg OUTREG(index_reg,0x30600); 1249c503f109Smrg OUTREG(data_reg,0x8BA0BED8); 1250c503f109Smrg OUTREG(index_reg,0x30601); 1251c503f109Smrg OUTREG(data_reg,0xBF508640); 1252c503f109Smrg OUTREG(index_reg,0x30700); 1253c503f109Smrg OUTREG(data_reg,0x8A60BEE8); 1254c503f109Smrg OUTREG(index_reg,0x30701); 1255c503f109Smrg OUTREG(data_reg,0xBF2087A0); 1256c503f109Smrg OUTREG(index_reg,0x30800); 1257c503f109Smrg OUTREG(data_reg,0x8900BF00); 1258c503f109Smrg OUTREG(index_reg,0x30801); 1259c503f109Smrg OUTREG(data_reg,0xBF008900); 1260b7e1c893Smrg} 1261b7e1c893Smrg 1262209ff23fSmrgstatic int 1263b7e1c893Smrgatombios_output_yuv_setup(xf86OutputPtr output, Bool enable) 1264209ff23fSmrg{ 1265209ff23fSmrg RADEONOutputPrivatePtr radeon_output = output->driver_private; 1266209ff23fSmrg RADEONInfoPtr info = RADEONPTR(output->scrn); 1267b7e1c893Smrg RADEONCrtcPrivatePtr radeon_crtc = output->crtc->driver_private; 1268b7e1c893Smrg ENABLE_YUV_PS_ALLOCATION disp_data; 1269209ff23fSmrg AtomBiosArgRec data; 1270209ff23fSmrg unsigned char *space; 1271b7e1c893Smrg unsigned char *RADEONMMIO = info->MMIO; 1272b7e1c893Smrg uint32_t temp, reg; 1273209ff23fSmrg 1274b7e1c893Smrg if (info->ChipFamily >= CHIP_FAMILY_R600) 1275b7e1c893Smrg reg = R600_BIOS_3_SCRATCH; 1276b7e1c893Smrg else 1277b7e1c893Smrg reg = RADEON_BIOS_3_SCRATCH; 1278b7e1c893Smrg 1279b7e1c893Smrg //fix up scratch reg handling 1280b7e1c893Smrg temp = INREG(reg); 1281b7e1c893Smrg if (radeon_output->active_device & (ATOM_DEVICE_TV_SUPPORT)) 1282b7e1c893Smrg OUTREG(reg, (ATOM_S3_TV1_ACTIVE | 1283b7e1c893Smrg (radeon_crtc->crtc_id << 18))); 1284b7e1c893Smrg else if (radeon_output->active_device & (ATOM_DEVICE_CV_SUPPORT)) 1285b7e1c893Smrg OUTREG(reg, (ATOM_S3_CV_ACTIVE | 1286b7e1c893Smrg (radeon_crtc->crtc_id << 24))); 1287b7e1c893Smrg else 1288b7e1c893Smrg OUTREG(reg, 0); 1289209ff23fSmrg 1290b7e1c893Smrg memset(&disp_data, 0, sizeof(disp_data)); 1291209ff23fSmrg 1292b7e1c893Smrg if (enable) 1293b7e1c893Smrg disp_data.ucEnable = ATOM_ENABLE; 1294b7e1c893Smrg disp_data.ucCRTC = radeon_crtc->crtc_id; 1295209ff23fSmrg 1296b7e1c893Smrg data.exec.index = GetIndexIntoMasterTable(COMMAND, EnableYUV); 1297209ff23fSmrg data.exec.dataSpace = (void *)&space; 1298209ff23fSmrg data.exec.pspace = &disp_data; 1299209ff23fSmrg 130068105dcbSveego if (RHDAtomBiosFunc(info->atomBIOS->pScrn, info->atomBIOS, ATOMBIOS_EXEC, &data) == ATOM_SUCCESS) { 1301b7e1c893Smrg 1302b7e1c893Smrg OUTREG(reg, temp); 1303b7e1c893Smrg 1304042789b0Sveego/* ErrorF("crtc %d YUV %s setup success\n", radeon_crtc->crtc_id, enable ? "enable" : "disable"); */ 1305209ff23fSmrg return ATOM_SUCCESS; 1306209ff23fSmrg } 1307209ff23fSmrg 1308b7e1c893Smrg OUTREG(reg, temp); 1309b7e1c893Smrg 1310b7e1c893Smrg ErrorF("crtc %d YUV %s setup failed\n", radeon_crtc->crtc_id, enable ? "enable" : "disable"); 1311209ff23fSmrg return ATOM_NOT_IMPLEMENTED; 1312209ff23fSmrg 1313209ff23fSmrg} 1314209ff23fSmrg 1315209ff23fSmrgstatic int 1316b7e1c893Smrgatombios_output_overscan_setup(xf86OutputPtr output, DisplayModePtr mode, DisplayModePtr adjusted_mode) 1317209ff23fSmrg{ 1318209ff23fSmrg RADEONOutputPrivatePtr radeon_output = output->driver_private; 1319b7e1c893Smrg RADEONCrtcPrivatePtr radeon_crtc = output->crtc->driver_private; 1320209ff23fSmrg RADEONInfoPtr info = RADEONPTR(output->scrn); 1321b7e1c893Smrg SET_CRTC_OVERSCAN_PS_ALLOCATION overscan_param; 1322209ff23fSmrg AtomBiosArgRec data; 1323209ff23fSmrg unsigned char *space; 1324b7e1c893Smrg memset(&overscan_param, 0, sizeof(overscan_param)); 1325209ff23fSmrg 1326b7e1c893Smrg overscan_param.usOverscanRight = 0; 1327b7e1c893Smrg overscan_param.usOverscanLeft = 0; 1328b7e1c893Smrg overscan_param.usOverscanBottom = 0; 1329b7e1c893Smrg overscan_param.usOverscanTop = 0; 1330b7e1c893Smrg overscan_param.ucCRTC = radeon_crtc->crtc_id; 1331b7e1c893Smrg 1332b7e1c893Smrg if (radeon_output->Flags & RADEON_USE_RMX) { 1333b7e1c893Smrg if (radeon_output->rmx_type == RMX_FULL) { 1334b7e1c893Smrg overscan_param.usOverscanRight = 0; 1335b7e1c893Smrg overscan_param.usOverscanLeft = 0; 1336b7e1c893Smrg overscan_param.usOverscanBottom = 0; 1337b7e1c893Smrg overscan_param.usOverscanTop = 0; 1338b7e1c893Smrg } else if (radeon_output->rmx_type == RMX_CENTER) { 1339b7e1c893Smrg overscan_param.usOverscanTop = (adjusted_mode->CrtcVDisplay - mode->CrtcVDisplay) / 2; 1340b7e1c893Smrg overscan_param.usOverscanBottom = (adjusted_mode->CrtcVDisplay - mode->CrtcVDisplay) / 2; 1341b7e1c893Smrg overscan_param.usOverscanLeft = (adjusted_mode->CrtcHDisplay - mode->CrtcHDisplay) / 2; 1342b7e1c893Smrg overscan_param.usOverscanRight = (adjusted_mode->CrtcHDisplay - mode->CrtcHDisplay) / 2; 1343b7e1c893Smrg } else if (radeon_output->rmx_type == RMX_ASPECT) { 1344b7e1c893Smrg int a1 = mode->CrtcVDisplay * adjusted_mode->CrtcHDisplay; 1345b7e1c893Smrg int a2 = adjusted_mode->CrtcVDisplay * mode->CrtcHDisplay; 1346b7e1c893Smrg 1347b7e1c893Smrg if (a1 > a2) { 1348b7e1c893Smrg overscan_param.usOverscanLeft = (adjusted_mode->CrtcHDisplay - (a2 / mode->CrtcVDisplay)) / 2; 1349b7e1c893Smrg overscan_param.usOverscanRight = (adjusted_mode->CrtcHDisplay - (a2 / mode->CrtcVDisplay)) / 2; 1350b7e1c893Smrg } else if (a2 > a1) { 1351b7e1c893Smrg overscan_param.usOverscanLeft = (adjusted_mode->CrtcVDisplay - (a1 / mode->CrtcHDisplay)) / 2; 1352b7e1c893Smrg overscan_param.usOverscanRight = (adjusted_mode->CrtcVDisplay - (a1 / mode->CrtcHDisplay)) / 2; 1353b7e1c893Smrg } 1354209ff23fSmrg } 1355209ff23fSmrg } 1356209ff23fSmrg 1357b7e1c893Smrg data.exec.index = GetIndexIntoMasterTable(COMMAND, SetCRTC_OverScan); 1358209ff23fSmrg data.exec.dataSpace = (void *)&space; 1359b7e1c893Smrg data.exec.pspace = &overscan_param; 1360209ff23fSmrg 136168105dcbSveego if (RHDAtomBiosFunc(info->atomBIOS->pScrn, info->atomBIOS, ATOMBIOS_EXEC, &data) == ATOM_SUCCESS) { 1362042789b0Sveego/* ErrorF("Set CRTC %d Overscan success\n", radeon_crtc->crtc_id); */ 1363b7e1c893Smrg return ATOM_SUCCESS ; 1364209ff23fSmrg } 1365209ff23fSmrg 1366b7e1c893Smrg ErrorF("Set CRTC %d Overscan failed\n", radeon_crtc->crtc_id); 1367209ff23fSmrg return ATOM_NOT_IMPLEMENTED; 1368209ff23fSmrg} 1369209ff23fSmrg 1370209ff23fSmrgstatic int 1371b7e1c893Smrgatombios_output_scaler_setup(xf86OutputPtr output) 1372209ff23fSmrg{ 1373209ff23fSmrg RADEONInfoPtr info = RADEONPTR(output->scrn); 1374209ff23fSmrg RADEONOutputPrivatePtr radeon_output = output->driver_private; 1375b7e1c893Smrg radeon_tvout_ptr tvout = &radeon_output->tvout; 1376209ff23fSmrg RADEONCrtcPrivatePtr radeon_crtc = output->crtc->driver_private; 1377209ff23fSmrg ENABLE_SCALER_PS_ALLOCATION disp_data; 1378209ff23fSmrg AtomBiosArgRec data; 1379209ff23fSmrg unsigned char *space; 1380209ff23fSmrg 1381b7e1c893Smrg if (!IS_AVIVO_VARIANT && radeon_crtc->crtc_id) 1382b7e1c893Smrg return ATOM_SUCCESS; 1383b7e1c893Smrg 1384b7e1c893Smrg memset(&disp_data, 0, sizeof(disp_data)); 1385b7e1c893Smrg 1386209ff23fSmrg disp_data.ucScaler = radeon_crtc->crtc_id; 1387209ff23fSmrg 1388b7e1c893Smrg if (radeon_output->active_device & (ATOM_DEVICE_TV_SUPPORT)) { 1389b7e1c893Smrg switch (tvout->tvStd) { 1390b7e1c893Smrg case TV_STD_NTSC: 1391b7e1c893Smrg disp_data.ucTVStandard = ATOM_TV_NTSC; 1392b7e1c893Smrg break; 1393b7e1c893Smrg case TV_STD_PAL: 1394b7e1c893Smrg disp_data.ucTVStandard = ATOM_TV_PAL; 1395b7e1c893Smrg break; 1396b7e1c893Smrg case TV_STD_PAL_M: 1397b7e1c893Smrg disp_data.ucTVStandard = ATOM_TV_PALM; 1398b7e1c893Smrg break; 1399b7e1c893Smrg case TV_STD_PAL_60: 1400b7e1c893Smrg disp_data.ucTVStandard = ATOM_TV_PAL60; 1401b7e1c893Smrg break; 1402b7e1c893Smrg case TV_STD_NTSC_J: 1403b7e1c893Smrg disp_data.ucTVStandard = ATOM_TV_NTSCJ; 1404b7e1c893Smrg break; 1405b7e1c893Smrg case TV_STD_SCART_PAL: 1406b7e1c893Smrg disp_data.ucTVStandard = ATOM_TV_PAL; /* ??? */ 1407b7e1c893Smrg break; 1408b7e1c893Smrg case TV_STD_SECAM: 1409b7e1c893Smrg disp_data.ucTVStandard = ATOM_TV_SECAM; 1410b7e1c893Smrg break; 1411b7e1c893Smrg case TV_STD_PAL_CN: 1412b7e1c893Smrg disp_data.ucTVStandard = ATOM_TV_PALCN; 1413b7e1c893Smrg break; 1414b7e1c893Smrg default: 1415b7e1c893Smrg disp_data.ucTVStandard = ATOM_TV_NTSC; 1416b7e1c893Smrg break; 1417b7e1c893Smrg } 1418b7e1c893Smrg disp_data.ucEnable = SCALER_ENABLE_MULTITAP_MODE; 1419042789b0Sveego/* ErrorF("Using TV scaler %x %x\n", disp_data.ucTVStandard, disp_data.ucEnable); */ 1420b7e1c893Smrg } else if (radeon_output->active_device & (ATOM_DEVICE_CV_SUPPORT)) { 1421b7e1c893Smrg disp_data.ucTVStandard = ATOM_TV_CV; 1422b7e1c893Smrg disp_data.ucEnable = SCALER_ENABLE_MULTITAP_MODE; 1423042789b0Sveego/* ErrorF("Using CV scaler %x %x\n", disp_data.ucTVStandard, disp_data.ucEnable); */ 1424b7e1c893Smrg } else if (radeon_output->Flags & RADEON_USE_RMX) { 1425042789b0Sveego/* ErrorF("Using RMX\n"); */ 1426209ff23fSmrg if (radeon_output->rmx_type == RMX_FULL) 1427209ff23fSmrg disp_data.ucEnable = ATOM_SCALER_EXPANSION; 1428209ff23fSmrg else if (radeon_output->rmx_type == RMX_CENTER) 1429209ff23fSmrg disp_data.ucEnable = ATOM_SCALER_CENTER; 1430b7e1c893Smrg else if (radeon_output->rmx_type == RMX_ASPECT) 1431b7e1c893Smrg disp_data.ucEnable = ATOM_SCALER_EXPANSION; 1432209ff23fSmrg } else { 1433042789b0Sveego/* ErrorF("Not using RMX\n"); */ 1434b7e1c893Smrg if (IS_AVIVO_VARIANT) 1435b7e1c893Smrg disp_data.ucEnable = ATOM_SCALER_DISABLE; 1436b7e1c893Smrg else 1437b7e1c893Smrg disp_data.ucEnable = ATOM_SCALER_CENTER; 1438209ff23fSmrg } 1439209ff23fSmrg 1440209ff23fSmrg data.exec.index = GetIndexIntoMasterTable(COMMAND, EnableScaler); 1441209ff23fSmrg data.exec.dataSpace = (void *)&space; 1442209ff23fSmrg data.exec.pspace = &disp_data; 1443209ff23fSmrg 144468105dcbSveego if (RHDAtomBiosFunc(info->atomBIOS->pScrn, info->atomBIOS, ATOMBIOS_EXEC, &data) == ATOM_SUCCESS) { 1445b7e1c893Smrg if (radeon_output->active_device & (ATOM_DEVICE_CV_SUPPORT | ATOM_DEVICE_TV_SUPPORT) 1446b7e1c893Smrg && info->ChipFamily >= CHIP_FAMILY_RV515 && info->ChipFamily <= CHIP_FAMILY_RV570) { 1447042789b0Sveego/* ErrorF("forcing TV scaler\n"); */ 1448c503f109Smrg atom_rv515_force_tv_scaler(output->scrn, radeon_crtc); 1449b7e1c893Smrg } 1450042789b0Sveego/* ErrorF("scaler %d setup success\n", radeon_crtc->crtc_id); */ 1451209ff23fSmrg return ATOM_SUCCESS; 1452209ff23fSmrg } 1453209ff23fSmrg 1454209ff23fSmrg ErrorF("scaler %d setup failed\n", radeon_crtc->crtc_id); 1455209ff23fSmrg return ATOM_NOT_IMPLEMENTED; 1456209ff23fSmrg 1457209ff23fSmrg} 1458209ff23fSmrg 1459b7e1c893Smrgvoid 1460b7e1c893Smrgatombios_output_dpms(xf86OutputPtr output, int mode) 1461209ff23fSmrg{ 1462b7e1c893Smrg RADEONOutputPrivatePtr radeon_output = output->driver_private; 1463b7e1c893Smrg radeon_encoder_ptr radeon_encoder = radeon_get_encoder(output); 1464209ff23fSmrg RADEONInfoPtr info = RADEONPTR(output->scrn); 1465209ff23fSmrg DISPLAY_DEVICE_OUTPUT_CONTROL_PS_ALLOCATION disp_data; 1466209ff23fSmrg AtomBiosArgRec data; 1467209ff23fSmrg unsigned char *space; 1468209ff23fSmrg int index = 0; 1469b7e1c893Smrg Bool is_dig = FALSE; 147040732134Srjs unsigned char *RADEONMMIO = info->MMIO; 147140732134Srjs uint32_t reg = 0; 1472209ff23fSmrg 1473b7e1c893Smrg if (radeon_encoder == NULL) 1474b7e1c893Smrg return; 1475b7e1c893Smrg 1476b7e1c893Smrg switch (radeon_encoder->encoder_id) { 1477b7e1c893Smrg case ENCODER_OBJECT_ID_INTERNAL_TMDS1: 1478b7e1c893Smrg case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1: 1479209ff23fSmrg index = GetIndexIntoMasterTable(COMMAND, TMDSAOutputControl); 1480209ff23fSmrg break; 1481b7e1c893Smrg case ENCODER_OBJECT_ID_INTERNAL_UNIPHY: 1482b7e1c893Smrg case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1: 1483b7e1c893Smrg case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2: 1484b7e1c893Smrg case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA: 1485b7e1c893Smrg is_dig = TRUE; 1486209ff23fSmrg break; 1487b7e1c893Smrg case ENCODER_OBJECT_ID_INTERNAL_DVO1: 1488b7e1c893Smrg case ENCODER_OBJECT_ID_INTERNAL_DDI: 1489b7e1c893Smrg case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1: 1490b7e1c893Smrg index = GetIndexIntoMasterTable(COMMAND, DVOOutputControl); 1491209ff23fSmrg break; 1492b7e1c893Smrg case ENCODER_OBJECT_ID_INTERNAL_LVDS: 1493209ff23fSmrg index = GetIndexIntoMasterTable(COMMAND, LCD1OutputControl); 1494209ff23fSmrg break; 1495b7e1c893Smrg case ENCODER_OBJECT_ID_INTERNAL_LVTM1: 1496b7e1c893Smrg if (radeon_output->active_device & (ATOM_DEVICE_LCD_SUPPORT)) 1497b7e1c893Smrg index = GetIndexIntoMasterTable(COMMAND, LCD1OutputControl); 1498b7e1c893Smrg else 1499b7e1c893Smrg index = GetIndexIntoMasterTable(COMMAND, LVTMAOutputControl); 1500209ff23fSmrg break; 1501b7e1c893Smrg case ENCODER_OBJECT_ID_INTERNAL_DAC1: 1502b7e1c893Smrg case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1: 1503ad43ddacSmrg if (IS_DCE32_VARIANT) 1504b7e1c893Smrg index = GetIndexIntoMasterTable(COMMAND, DAC1OutputControl); 1505ad43ddacSmrg else { 1506ad43ddacSmrg if (radeon_output->active_device & (ATOM_DEVICE_TV_SUPPORT)) 1507ad43ddacSmrg index = GetIndexIntoMasterTable(COMMAND, TV1OutputControl); 1508ad43ddacSmrg else if (radeon_output->active_device & (ATOM_DEVICE_CV_SUPPORT)) 1509ad43ddacSmrg index = GetIndexIntoMasterTable(COMMAND, CV1OutputControl); 1510ad43ddacSmrg else 1511ad43ddacSmrg index = GetIndexIntoMasterTable(COMMAND, DAC1OutputControl); 1512ad43ddacSmrg } 1513209ff23fSmrg break; 1514b7e1c893Smrg case ENCODER_OBJECT_ID_INTERNAL_DAC2: 1515b7e1c893Smrg case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC2: 1516ad43ddacSmrg if (IS_DCE32_VARIANT) 1517b7e1c893Smrg index = GetIndexIntoMasterTable(COMMAND, DAC2OutputControl); 1518ad43ddacSmrg else { 1519ad43ddacSmrg if (radeon_output->active_device & (ATOM_DEVICE_TV_SUPPORT)) 1520ad43ddacSmrg index = GetIndexIntoMasterTable(COMMAND, TV1OutputControl); 1521ad43ddacSmrg else if (radeon_output->active_device & (ATOM_DEVICE_CV_SUPPORT)) 1522ad43ddacSmrg index = GetIndexIntoMasterTable(COMMAND, CV1OutputControl); 1523ad43ddacSmrg else 1524ad43ddacSmrg index = GetIndexIntoMasterTable(COMMAND, DAC2OutputControl); 1525ad43ddacSmrg } 1526209ff23fSmrg break; 1527209ff23fSmrg } 1528209ff23fSmrg 1529209ff23fSmrg switch (mode) { 1530209ff23fSmrg case DPMSModeOn: 1531b7e1c893Smrg radeon_encoder->devices |= radeon_output->active_device; 1532ad43ddacSmrg if (is_dig) { 1533921a55d8Smrg atombios_output_dig_transmitter_setup(output, ATOM_TRANSMITTER_ACTION_ENABLE_OUTPUT, 0, 0); 1534ad43ddacSmrg if (((radeon_output->ConnectorType == CONNECTOR_DISPLAY_PORT) || 1535ad43ddacSmrg (radeon_output->ConnectorType == CONNECTOR_EDP)) && 1536ad43ddacSmrg (radeon_output->MonType == MT_DP)) { 1537ad43ddacSmrg do_displayport_link_train(output); 1538ad43ddacSmrg if (IS_DCE4_VARIANT) 15390974d292Smrg atombios_output_dig_encoder_setup(output, ATOM_ENCODER_CMD_DP_VIDEO_ON); 1540ad43ddacSmrg } 1541ad43ddacSmrg } 1542b7e1c893Smrg else { 1543b7e1c893Smrg disp_data.ucAction = ATOM_ENABLE; 1544b7e1c893Smrg data.exec.index = index; 1545b7e1c893Smrg data.exec.dataSpace = (void *)&space; 1546b7e1c893Smrg data.exec.pspace = &disp_data; 1547b7e1c893Smrg 154840732134Srjs /* workaround for DVOOutputControl on some RS690 systems */ 154940732134Srjs if (radeon_encoder->encoder_id == ENCODER_OBJECT_ID_INTERNAL_DDI) { 155040732134Srjs reg = INREG(RADEON_BIOS_3_SCRATCH); 155140732134Srjs OUTREG(RADEON_BIOS_3_SCRATCH, reg & ~ATOM_S3_DFP2I_ACTIVE); 155240732134Srjs } 1553042789b0Sveego if (RHDAtomBiosFunc(info->atomBIOS->pScrn, info->atomBIOS, ATOMBIOS_EXEC, &data) != ATOM_SUCCESS) 1554042789b0Sveego/* 1555b7e1c893Smrg ErrorF("Output %s enable success\n", 1556b7e1c893Smrg device_name[radeon_get_device_index(radeon_output->active_device)]); 1557b7e1c893Smrg else 1558042789b0Sveego*/ 1559b7e1c893Smrg ErrorF("Output %s enable failed\n", 1560b7e1c893Smrg device_name[radeon_get_device_index(radeon_output->active_device)]); 156140732134Srjs if (radeon_encoder->encoder_id == ENCODER_OBJECT_ID_INTERNAL_DDI) 156240732134Srjs OUTREG(RADEON_BIOS_3_SCRATCH, reg); 1563b7e1c893Smrg } 1564c503f109Smrg /* at least for TV atom fails to reassociate the correct crtc source at dpms on */ 1565c503f109Smrg if (radeon_output->active_device & (ATOM_DEVICE_TV_SUPPORT)) 1566c503f109Smrg atombios_set_output_crtc_source(output); 1567209ff23fSmrg break; 1568209ff23fSmrg case DPMSModeStandby: 1569209ff23fSmrg case DPMSModeSuspend: 1570209ff23fSmrg case DPMSModeOff: 1571b7e1c893Smrg radeon_encoder->devices &= ~(radeon_output->active_device); 1572b7e1c893Smrg if (!radeon_encoder->devices) { 1573ad43ddacSmrg if (is_dig) { 1574921a55d8Smrg atombios_output_dig_transmitter_setup(output, ATOM_TRANSMITTER_ACTION_DISABLE_OUTPUT, 0, 0); 1575ad43ddacSmrg if (((radeon_output->ConnectorType == CONNECTOR_DISPLAY_PORT) || 1576ad43ddacSmrg (radeon_output->ConnectorType == CONNECTOR_EDP)) && 1577ad43ddacSmrg (radeon_output->MonType == MT_DP)) { 1578ad43ddacSmrg if (IS_DCE4_VARIANT) 15790974d292Smrg atombios_output_dig_encoder_setup(output, ATOM_ENCODER_CMD_DP_VIDEO_OFF); 1580ad43ddacSmrg } 1581ad43ddacSmrg } else { 1582b7e1c893Smrg disp_data.ucAction = ATOM_DISABLE; 1583b7e1c893Smrg data.exec.index = index; 1584b7e1c893Smrg data.exec.dataSpace = (void *)&space; 1585b7e1c893Smrg data.exec.pspace = &disp_data; 1586b7e1c893Smrg 158768105dcbSveego if (RHDAtomBiosFunc(info->atomBIOS->pScrn, info->atomBIOS, ATOMBIOS_EXEC, &data) 1588042789b0Sveego != ATOM_SUCCESS) 1589042789b0Sveego/* 1590b7e1c893Smrg ErrorF("Output %s disable success\n", 1591b7e1c893Smrg device_name[radeon_get_device_index(radeon_output->active_device)]); 1592b7e1c893Smrg else 1593042789b0Sveego*/ 1594b7e1c893Smrg ErrorF("Output %s disable failed\n", 1595b7e1c893Smrg device_name[radeon_get_device_index(radeon_output->active_device)]); 1596b7e1c893Smrg } 1597209ff23fSmrg } 1598b7e1c893Smrg break; 1599209ff23fSmrg } 1600209ff23fSmrg} 1601209ff23fSmrg 16020974d292Smrgunion crtc_source_param { 16030974d292Smrg SELECT_CRTC_SOURCE_PS_ALLOCATION v1; 16040974d292Smrg SELECT_CRTC_SOURCE_PARAMETERS_V2 v2; 16050974d292Smrg}; 16060974d292Smrg 16070974d292Smrgvoid 1608209ff23fSmrgatombios_set_output_crtc_source(xf86OutputPtr output) 1609209ff23fSmrg{ 1610209ff23fSmrg RADEONOutputPrivatePtr radeon_output = output->driver_private; 1611209ff23fSmrg RADEONCrtcPrivatePtr radeon_crtc = output->crtc->driver_private; 1612209ff23fSmrg RADEONInfoPtr info = RADEONPTR(output->scrn); 1613b7e1c893Smrg radeon_encoder_ptr radeon_encoder = radeon_get_encoder(output); 1614209ff23fSmrg AtomBiosArgRec data; 1615209ff23fSmrg unsigned char *space; 16160974d292Smrg union crtc_source_param args; 1617209ff23fSmrg int index = GetIndexIntoMasterTable(COMMAND, SelectCRTC_Source); 1618209ff23fSmrg int major, minor; 1619209ff23fSmrg 1620b7e1c893Smrg if (radeon_encoder == NULL) 1621b7e1c893Smrg return; 1622b7e1c893Smrg 16230974d292Smrg memset(&args, 0, sizeof(args)); 16240974d292Smrg 1625209ff23fSmrg atombios_get_command_table_version(info->atomBIOS, index, &major, &minor); 1626209ff23fSmrg 1627209ff23fSmrg /*ErrorF("select crtc source table is %d %d\n", major, minor);*/ 1628209ff23fSmrg 1629209ff23fSmrg switch(major) { 1630b7e1c893Smrg case 1: 1631209ff23fSmrg switch(minor) { 1632209ff23fSmrg case 0: 1633209ff23fSmrg case 1: 1634209ff23fSmrg default: 1635b7e1c893Smrg if (IS_AVIVO_VARIANT) 16360974d292Smrg args.v1.ucCRTC = radeon_crtc->crtc_id; 1637b7e1c893Smrg else { 1638b7e1c893Smrg if (radeon_encoder->encoder_id == ENCODER_OBJECT_ID_INTERNAL_DAC1) 16390974d292Smrg args.v1.ucCRTC = radeon_crtc->crtc_id; 1640b7e1c893Smrg else 16410974d292Smrg args.v1.ucCRTC = radeon_crtc->crtc_id << 2; 1642b7e1c893Smrg } 1643b7e1c893Smrg switch (radeon_encoder->encoder_id) { 1644b7e1c893Smrg case ENCODER_OBJECT_ID_INTERNAL_TMDS1: 1645b7e1c893Smrg case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1: 16460974d292Smrg args.v1.ucDevice = ATOM_DEVICE_DFP1_INDEX; 1647b7e1c893Smrg break; 1648b7e1c893Smrg case ENCODER_OBJECT_ID_INTERNAL_LVDS: 1649b7e1c893Smrg case ENCODER_OBJECT_ID_INTERNAL_LVTM1: 1650b7e1c893Smrg if (radeon_output->active_device & ATOM_DEVICE_LCD1_SUPPORT) 16510974d292Smrg args.v1.ucDevice = ATOM_DEVICE_LCD1_INDEX; 1652b7e1c893Smrg else 16530974d292Smrg args.v1.ucDevice = ATOM_DEVICE_DFP3_INDEX; 1654b7e1c893Smrg break; 1655b7e1c893Smrg case ENCODER_OBJECT_ID_INTERNAL_DVO1: 1656b7e1c893Smrg case ENCODER_OBJECT_ID_INTERNAL_DDI: 1657b7e1c893Smrg case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1: 16580974d292Smrg args.v1.ucDevice = ATOM_DEVICE_DFP2_INDEX; 1659b7e1c893Smrg break; 1660b7e1c893Smrg case ENCODER_OBJECT_ID_INTERNAL_DAC1: 1661b7e1c893Smrg case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1: 1662b7e1c893Smrg if (radeon_output->active_device & (ATOM_DEVICE_TV_SUPPORT)) 16630974d292Smrg args.v1.ucDevice = ATOM_DEVICE_TV1_INDEX; 1664b7e1c893Smrg else if (radeon_output->active_device & (ATOM_DEVICE_CV_SUPPORT)) 16650974d292Smrg args.v1.ucDevice = ATOM_DEVICE_CV_INDEX; 1666b7e1c893Smrg else 16670974d292Smrg args.v1.ucDevice = ATOM_DEVICE_CRT1_INDEX; 1668b7e1c893Smrg break; 1669b7e1c893Smrg case ENCODER_OBJECT_ID_INTERNAL_DAC2: 1670b7e1c893Smrg case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC2: 1671b7e1c893Smrg if (radeon_output->active_device & (ATOM_DEVICE_TV_SUPPORT)) 16720974d292Smrg args.v1.ucDevice = ATOM_DEVICE_TV1_INDEX; 1673b7e1c893Smrg else if (radeon_output->active_device & (ATOM_DEVICE_CV_SUPPORT)) 16740974d292Smrg args.v1.ucDevice = ATOM_DEVICE_CV_INDEX; 1675b7e1c893Smrg else 16760974d292Smrg args.v1.ucDevice = ATOM_DEVICE_CRT2_INDEX; 1677b7e1c893Smrg break; 1678209ff23fSmrg } 16790974d292Smrg /*ErrorF("device sourced: 0x%x\n", args.v1.ucDevice);*/ 1680209ff23fSmrg break; 1681209ff23fSmrg case 2: 16820974d292Smrg args.v2.ucCRTC = radeon_crtc->crtc_id; 16830974d292Smrg args.v2.ucEncodeMode = atombios_get_encoder_mode(output); 1684b7e1c893Smrg switch (radeon_encoder->encoder_id) { 1685b7e1c893Smrg case ENCODER_OBJECT_ID_INTERNAL_UNIPHY: 1686b7e1c893Smrg case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1: 1687b7e1c893Smrg case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2: 1688b7e1c893Smrg case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA: 1689ad43ddacSmrg switch (radeon_output->dig_encoder) { 1690ad43ddacSmrg case 0: 16910974d292Smrg args.v2.ucEncoderID = ASIC_INT_DIG1_ENCODER_ID; 1692ad43ddacSmrg break; 1693ad43ddacSmrg case 1: 16940974d292Smrg args.v2.ucEncoderID = ASIC_INT_DIG2_ENCODER_ID; 1695ad43ddacSmrg break; 1696ad43ddacSmrg case 2: 16970974d292Smrg args.v2.ucEncoderID = ASIC_INT_DIG3_ENCODER_ID; 1698ad43ddacSmrg break; 1699ad43ddacSmrg case 3: 17000974d292Smrg args.v2.ucEncoderID = ASIC_INT_DIG4_ENCODER_ID; 1701ad43ddacSmrg break; 1702ad43ddacSmrg case 4: 17030974d292Smrg args.v2.ucEncoderID = ASIC_INT_DIG5_ENCODER_ID; 1704ad43ddacSmrg break; 1705ad43ddacSmrg case 5: 17060974d292Smrg args.v2.ucEncoderID = ASIC_INT_DIG6_ENCODER_ID; 1707ad43ddacSmrg break; 1708ad43ddacSmrg } 1709b7e1c893Smrg break; 17100974d292Smrg case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1: 17110974d292Smrg args.v2.ucEncoderID = ASIC_INT_DVO_ENCODER_ID; 17120974d292Smrg break; 1713b7e1c893Smrg case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1: 1714b7e1c893Smrg if (radeon_output->active_device & (ATOM_DEVICE_TV_SUPPORT)) 17150974d292Smrg args.v2.ucEncoderID = ASIC_INT_TV_ENCODER_ID; 1716b7e1c893Smrg else if (radeon_output->active_device & (ATOM_DEVICE_CV_SUPPORT)) 17170974d292Smrg args.v2.ucEncoderID = ASIC_INT_TV_ENCODER_ID; 1718b7e1c893Smrg else 17190974d292Smrg args.v2.ucEncoderID = ASIC_INT_DAC1_ENCODER_ID; 1720b7e1c893Smrg break; 1721b7e1c893Smrg case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC2: 1722b7e1c893Smrg if (radeon_output->active_device & (ATOM_DEVICE_TV_SUPPORT)) 17230974d292Smrg args.v2.ucEncoderID = ASIC_INT_TV_ENCODER_ID; 1724b7e1c893Smrg else if (radeon_output->active_device & (ATOM_DEVICE_CV_SUPPORT)) 17250974d292Smrg args.v2.ucEncoderID = ASIC_INT_TV_ENCODER_ID; 1726b7e1c893Smrg else 17270974d292Smrg args.v2.ucEncoderID = ASIC_INT_DAC2_ENCODER_ID; 1728b7e1c893Smrg break; 1729209ff23fSmrg } 17300974d292Smrg /*ErrorF("device sourced: 0x%x\n", args.v2.ucEncoderID);*/ 1731209ff23fSmrg break; 1732209ff23fSmrg } 1733209ff23fSmrg break; 1734209ff23fSmrg default: 1735b7e1c893Smrg ErrorF("Unknown table version\n"); 1736b7e1c893Smrg exit(-1); 1737209ff23fSmrg } 1738209ff23fSmrg 17390974d292Smrg data.exec.pspace = &args; 1740209ff23fSmrg data.exec.index = index; 1741209ff23fSmrg data.exec.dataSpace = (void *)&space; 1742209ff23fSmrg 174368105dcbSveego if (RHDAtomBiosFunc(info->atomBIOS->pScrn, info->atomBIOS, ATOMBIOS_EXEC, &data) == ATOM_SUCCESS) { 1744042789b0Sveego/* ErrorF("Set CRTC %d Source success\n", radeon_crtc->crtc_id); */ 1745209ff23fSmrg return; 1746209ff23fSmrg } 1747209ff23fSmrg 1748209ff23fSmrg ErrorF("Set CRTC Source failed\n"); 1749209ff23fSmrg return; 1750209ff23fSmrg} 1751209ff23fSmrg 1752b7e1c893Smrgstatic void 1753b7e1c893Smrgatombios_apply_output_quirks(xf86OutputPtr output, DisplayModePtr mode) 1754b7e1c893Smrg{ 1755b7e1c893Smrg RADEONOutputPrivatePtr radeon_output = output->driver_private; 1756b7e1c893Smrg RADEONCrtcPrivatePtr radeon_crtc = output->crtc->driver_private; 1757b7e1c893Smrg RADEONInfoPtr info = RADEONPTR(output->scrn); 1758b7e1c893Smrg unsigned char *RADEONMMIO = info->MMIO; 1759b7e1c893Smrg 1760b7e1c893Smrg /* Funky macbooks */ 1761b7e1c893Smrg if ((info->Chipset == PCI_CHIP_RV530_71C5) && 1762b7e1c893Smrg (PCI_SUB_VENDOR_ID(info->PciInfo) == 0x106b) && 1763b7e1c893Smrg (PCI_SUB_DEVICE_ID(info->PciInfo) == 0x0080)) { 1764b7e1c893Smrg if (radeon_output->MonType == MT_LCD) { 1765b7e1c893Smrg if (radeon_output->devices & ATOM_DEVICE_LCD1_SUPPORT) { 1766b7e1c893Smrg uint32_t lvtma_bit_depth_control = INREG(AVIVO_LVTMA_BIT_DEPTH_CONTROL); 1767b7e1c893Smrg 1768b7e1c893Smrg lvtma_bit_depth_control &= ~AVIVO_LVTMA_BIT_DEPTH_CONTROL_TRUNCATE_EN; 1769b7e1c893Smrg lvtma_bit_depth_control &= ~AVIVO_LVTMA_BIT_DEPTH_CONTROL_SPATIAL_DITHER_EN; 1770b7e1c893Smrg 1771b7e1c893Smrg OUTREG(AVIVO_LVTMA_BIT_DEPTH_CONTROL, lvtma_bit_depth_control); 1772b7e1c893Smrg } 1773b7e1c893Smrg } 1774b7e1c893Smrg } 1775b7e1c893Smrg 1776b7e1c893Smrg /* set scaler clears this on some chips */ 1777ad43ddacSmrg if (!(radeon_output->active_device & (ATOM_DEVICE_CV_SUPPORT | ATOM_DEVICE_TV_SUPPORT))) { 1778ad43ddacSmrg if (IS_AVIVO_VARIANT && (mode->Flags & V_INTERLACE)) 1779ad43ddacSmrg OUTREG(AVIVO_D1MODE_DATA_FORMAT + radeon_crtc->crtc_offset, AVIVO_D1MODE_INTERLEAVE_EN); 1780ad43ddacSmrg } 1781ad43ddacSmrg 1782ad43ddacSmrg if (IS_DCE32_VARIANT && 1783ad43ddacSmrg (!IS_DCE4_VARIANT) && 1784ad43ddacSmrg (radeon_output->active_device & (ATOM_DEVICE_DFP_SUPPORT))) { 1785ad43ddacSmrg radeon_encoder_ptr radeon_encoder = radeon_get_encoder(output); 1786ad43ddacSmrg if (radeon_encoder == NULL) 1787ad43ddacSmrg return; 1788ad43ddacSmrg /* XXX: need to sort out why transmitter control table sometimes sets this to a 1789ad43ddacSmrg * different golden value. 1790ad43ddacSmrg */ 1791ad43ddacSmrg if (radeon_encoder->encoder_id == ENCODER_OBJECT_ID_INTERNAL_UNIPHY2) { 1792ad43ddacSmrg OUTREG(0x7ec4, 0x00824002); 1793ad43ddacSmrg } 1794ad43ddacSmrg } 1795b7e1c893Smrg} 1796b7e1c893Smrg 1797b13dfe66Smrgvoid 1798ad43ddacSmrgatombios_pick_dig_encoder(xf86OutputPtr output) 1799ad43ddacSmrg{ 1800ad43ddacSmrg xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(output->scrn); 1801ad43ddacSmrg RADEONOutputPrivatePtr radeon_output = output->driver_private; 1802ad43ddacSmrg RADEONInfoPtr info = RADEONPTR(output->scrn); 1803ad43ddacSmrg radeon_encoder_ptr radeon_encoder = NULL; 1804ad43ddacSmrg Bool is_lvtma = FALSE; 1805ad43ddacSmrg int i, mode; 1806ad43ddacSmrg uint32_t dig_enc_use_mask = 0; 1807ad43ddacSmrg 1808ad43ddacSmrg /* non digital encoders don't need a dig block */ 1809ad43ddacSmrg mode = atombios_get_encoder_mode(output); 1810ad43ddacSmrg if (mode == ATOM_ENCODER_MODE_CRT || 1811ad43ddacSmrg mode == ATOM_ENCODER_MODE_TV || 1812ad43ddacSmrg mode == ATOM_ENCODER_MODE_CV) 1813ad43ddacSmrg return; 1814ad43ddacSmrg 1815ad43ddacSmrg if (IS_DCE4_VARIANT) { 1816ad43ddacSmrg radeon_encoder = radeon_get_encoder(output); 1817ad43ddacSmrg 1818921a55d8Smrg if (IS_DCE41_VARIANT) { 1819ad43ddacSmrg if (radeon_output->linkb) 1820ad43ddacSmrg radeon_output->dig_encoder = 1; 1821ad43ddacSmrg else 1822ad43ddacSmrg radeon_output->dig_encoder = 0; 1823921a55d8Smrg } else { 1824921a55d8Smrg switch (radeon_encoder->encoder_id) { 1825921a55d8Smrg case ENCODER_OBJECT_ID_INTERNAL_UNIPHY: 1826921a55d8Smrg if (radeon_output->linkb) 1827921a55d8Smrg radeon_output->dig_encoder = 1; 1828921a55d8Smrg else 1829921a55d8Smrg radeon_output->dig_encoder = 0; 1830921a55d8Smrg break; 1831921a55d8Smrg case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1: 1832921a55d8Smrg if (radeon_output->linkb) 1833921a55d8Smrg radeon_output->dig_encoder = 3; 1834921a55d8Smrg else 1835921a55d8Smrg radeon_output->dig_encoder = 2; 1836921a55d8Smrg break; 1837921a55d8Smrg case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2: 1838921a55d8Smrg if (radeon_output->linkb) 1839921a55d8Smrg radeon_output->dig_encoder = 5; 1840921a55d8Smrg else 1841921a55d8Smrg radeon_output->dig_encoder = 4; 1842921a55d8Smrg break; 1843921a55d8Smrg default: 1844921a55d8Smrg ErrorF("Unknown encoder\n"); 1845921a55d8Smrg break; 1846921a55d8Smrg } 1847ad43ddacSmrg } 1848ad43ddacSmrg return; 1849ad43ddacSmrg } 1850ad43ddacSmrg 1851ad43ddacSmrg if (IS_DCE32_VARIANT) { 1852ad43ddacSmrg RADEONCrtcPrivatePtr radeon_crtc = output->crtc->driver_private; 1853ad43ddacSmrg radeon_output->dig_encoder = radeon_crtc->crtc_id; 1854ad43ddacSmrg return; 1855ad43ddacSmrg } 1856ad43ddacSmrg 1857ad43ddacSmrg for (i = 0; i < xf86_config->num_output; i++) { 1858ad43ddacSmrg xf86OutputPtr test = xf86_config->output[i]; 1859ad43ddacSmrg RADEONOutputPrivatePtr radeon_test = test->driver_private; 1860ad43ddacSmrg radeon_encoder = radeon_get_encoder(test); 1861ad43ddacSmrg 1862ad43ddacSmrg if (!radeon_encoder || !test->crtc) 1863ad43ddacSmrg continue; 1864ad43ddacSmrg 1865ad43ddacSmrg if (output == test && radeon_encoder->encoder_id == ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA) 1866ad43ddacSmrg is_lvtma = TRUE; 1867ad43ddacSmrg if (output != test && (radeon_test->dig_encoder >= 0)) 1868ad43ddacSmrg dig_enc_use_mask |= (1 << radeon_test->dig_encoder); 1869ad43ddacSmrg 1870ad43ddacSmrg } 1871ad43ddacSmrg if (is_lvtma) { 1872ad43ddacSmrg if (dig_enc_use_mask & 0x2) 1873ad43ddacSmrg ErrorF("Need digital encoder 2 for LVTMA and it isn't free - stealing\n"); 1874ad43ddacSmrg radeon_output->dig_encoder = 1; 1875ad43ddacSmrg return; 1876ad43ddacSmrg } 1877ad43ddacSmrg if (!(dig_enc_use_mask & 1)) 1878ad43ddacSmrg radeon_output->dig_encoder = 0; 1879ad43ddacSmrg else 1880ad43ddacSmrg radeon_output->dig_encoder = 1; 1881ad43ddacSmrg} 1882209ff23fSmrgvoid 1883209ff23fSmrgatombios_output_mode_set(xf86OutputPtr output, 1884209ff23fSmrg DisplayModePtr mode, 1885209ff23fSmrg DisplayModePtr adjusted_mode) 1886209ff23fSmrg{ 1887209ff23fSmrg RADEONOutputPrivatePtr radeon_output = output->driver_private; 1888b7e1c893Smrg radeon_encoder_ptr radeon_encoder = radeon_get_encoder(output); 1889209ff23fSmrg RADEONInfoPtr info = RADEONPTR(output->scrn); 1890b7e1c893Smrg if (radeon_encoder == NULL) 1891ad43ddacSmrg return; 1892209ff23fSmrg 1893b7e1c893Smrg radeon_output->pixel_clock = adjusted_mode->Clock; 1894b7e1c893Smrg atombios_output_overscan_setup(output, mode, adjusted_mode); 1895b7e1c893Smrg atombios_output_scaler_setup(output); 1896209ff23fSmrg atombios_set_output_crtc_source(output); 1897209ff23fSmrg 18980974d292Smrg if (IS_AVIVO_VARIANT && !IS_DCE4_VARIANT) { 1899b7e1c893Smrg if (radeon_output->active_device & (ATOM_DEVICE_CV_SUPPORT | ATOM_DEVICE_TV_SUPPORT)) 1900b7e1c893Smrg atombios_output_yuv_setup(output, TRUE); 1901b7e1c893Smrg else 1902b7e1c893Smrg atombios_output_yuv_setup(output, FALSE); 1903209ff23fSmrg } 1904209ff23fSmrg 1905b7e1c893Smrg switch (radeon_encoder->encoder_id) { 1906b7e1c893Smrg case ENCODER_OBJECT_ID_INTERNAL_TMDS1: 1907b7e1c893Smrg case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1: 1908b7e1c893Smrg case ENCODER_OBJECT_ID_INTERNAL_LVDS: 1909b7e1c893Smrg case ENCODER_OBJECT_ID_INTERNAL_LVTM1: 1910b7e1c893Smrg atombios_output_digital_setup(output, PANEL_ENCODER_ACTION_ENABLE); 1911b7e1c893Smrg break; 1912b7e1c893Smrg case ENCODER_OBJECT_ID_INTERNAL_UNIPHY: 1913b7e1c893Smrg case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1: 1914b7e1c893Smrg case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2: 1915b7e1c893Smrg case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA: 1916b7e1c893Smrg /* disable encoder and transmitter */ 1917b7e1c893Smrg /* setup and enable the encoder and transmitter */ 19180974d292Smrg if (IS_DCE4_VARIANT) { 19190974d292Smrg atombios_output_dig_transmitter_setup(output, ATOM_TRANSMITTER_ACTION_DISABLE, 0, 0); 19200974d292Smrg atombios_output_dig_encoder_setup(output, ATOM_ENCODER_CMD_SETUP); 19210974d292Smrg atombios_output_dig_transmitter_setup(output, ATOM_TRANSMITTER_ACTION_INIT, 0, 0); 19220974d292Smrg atombios_output_dig_transmitter_setup(output, ATOM_TRANSMITTER_ACTION_ENABLE, 0, 0); 19230974d292Smrg } else { 19240974d292Smrg atombios_output_dig_transmitter_setup(output, ATOM_TRANSMITTER_ACTION_DISABLE, 0, 0); 1925ad43ddacSmrg atombios_output_dig_encoder_setup(output, ATOM_DISABLE); 1926ad43ddacSmrg atombios_output_dig_encoder_setup(output, ATOM_ENABLE); 19270974d292Smrg 19280974d292Smrg atombios_output_dig_transmitter_setup(output, ATOM_TRANSMITTER_ACTION_INIT, 0, 0); 19290974d292Smrg atombios_output_dig_transmitter_setup(output, ATOM_TRANSMITTER_ACTION_SETUP, 0, 0); 19300974d292Smrg atombios_output_dig_transmitter_setup(output, ATOM_TRANSMITTER_ACTION_ENABLE, 0, 0); 1931ad43ddacSmrg } 1932b7e1c893Smrg break; 1933b7e1c893Smrg case ENCODER_OBJECT_ID_INTERNAL_DDI: 1934b7e1c893Smrg atombios_output_ddia_setup(output, ATOM_ENABLE); 1935b7e1c893Smrg break; 1936b7e1c893Smrg case ENCODER_OBJECT_ID_INTERNAL_DVO1: 1937b7e1c893Smrg case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1: 1938b7e1c893Smrg atombios_external_tmds_setup(output, ATOM_ENABLE); 1939b7e1c893Smrg break; 1940b7e1c893Smrg case ENCODER_OBJECT_ID_INTERNAL_DAC1: 1941b7e1c893Smrg case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1: 1942b7e1c893Smrg case ENCODER_OBJECT_ID_INTERNAL_DAC2: 1943b7e1c893Smrg case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC2: 1944b7e1c893Smrg atombios_output_dac_setup(output, ATOM_ENABLE); 19452f39173dSmrg if (radeon_output->devices & (ATOM_DEVICE_TV_SUPPORT | ATOM_DEVICE_CV_SUPPORT)) { 19462f39173dSmrg if (radeon_output->active_device & (ATOM_DEVICE_TV_SUPPORT | ATOM_DEVICE_CV_SUPPORT)) 19472f39173dSmrg atombios_output_tv_setup(output, ATOM_ENABLE); 19482f39173dSmrg else 19492f39173dSmrg atombios_output_tv_setup(output, ATOM_DISABLE); 19502f39173dSmrg } 1951b7e1c893Smrg break; 1952b7e1c893Smrg } 1953b7e1c893Smrg atombios_apply_output_quirks(output, adjusted_mode); 1954209ff23fSmrg} 1955209ff23fSmrg 1956209ff23fSmrgstatic AtomBiosResult 1957209ff23fSmrgatom_bios_dac_load_detect(atomBiosHandlePtr atomBIOS, xf86OutputPtr output) 1958209ff23fSmrg{ 1959209ff23fSmrg RADEONOutputPrivatePtr radeon_output = output->driver_private; 1960209ff23fSmrg RADEONInfoPtr info = RADEONPTR(output->scrn); 1961209ff23fSmrg DAC_LOAD_DETECTION_PS_ALLOCATION dac_data; 1962209ff23fSmrg AtomBiosArgRec data; 1963209ff23fSmrg unsigned char *space; 1964b7e1c893Smrg int major, minor; 1965b7e1c893Smrg int index = GetIndexIntoMasterTable(COMMAND, DAC_LoadDetection); 1966b7e1c893Smrg 1967b7e1c893Smrg atombios_get_command_table_version(info->atomBIOS, index, &major, &minor); 1968209ff23fSmrg 1969209ff23fSmrg dac_data.sDacload.ucMisc = 0; 1970209ff23fSmrg 1971209ff23fSmrg if (radeon_output->devices & ATOM_DEVICE_CRT1_SUPPORT) { 1972b7e1c893Smrg dac_data.sDacload.usDeviceID = cpu_to_le16(ATOM_DEVICE_CRT1_SUPPORT); 1973b7e1c893Smrg if (info->encoders[ATOM_DEVICE_CRT1_INDEX] && 1974b7e1c893Smrg ((info->encoders[ATOM_DEVICE_CRT1_INDEX]->encoder_id == ENCODER_OBJECT_ID_INTERNAL_DAC1) || 1975b7e1c893Smrg (info->encoders[ATOM_DEVICE_CRT1_INDEX]->encoder_id == ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1))) 1976209ff23fSmrg dac_data.sDacload.ucDacType = ATOM_DAC_A; 1977b7e1c893Smrg else 1978209ff23fSmrg dac_data.sDacload.ucDacType = ATOM_DAC_B; 1979209ff23fSmrg } else if (radeon_output->devices & ATOM_DEVICE_CRT2_SUPPORT) { 1980b7e1c893Smrg dac_data.sDacload.usDeviceID = cpu_to_le16(ATOM_DEVICE_CRT2_SUPPORT); 1981b7e1c893Smrg if (info->encoders[ATOM_DEVICE_CRT2_INDEX] && 1982b7e1c893Smrg ((info->encoders[ATOM_DEVICE_CRT2_INDEX]->encoder_id == ENCODER_OBJECT_ID_INTERNAL_DAC1) || 1983b7e1c893Smrg (info->encoders[ATOM_DEVICE_CRT2_INDEX]->encoder_id == ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1))) 1984209ff23fSmrg dac_data.sDacload.ucDacType = ATOM_DAC_A; 1985b7e1c893Smrg else 1986209ff23fSmrg dac_data.sDacload.ucDacType = ATOM_DAC_B; 1987209ff23fSmrg } else if (radeon_output->devices & ATOM_DEVICE_CV_SUPPORT) { 1988b7e1c893Smrg dac_data.sDacload.usDeviceID = cpu_to_le16(ATOM_DEVICE_CV_SUPPORT); 1989b7e1c893Smrg if (info->encoders[ATOM_DEVICE_CV_INDEX] && 1990b7e1c893Smrg ((info->encoders[ATOM_DEVICE_CV_INDEX]->encoder_id == ENCODER_OBJECT_ID_INTERNAL_DAC1) || 1991b7e1c893Smrg (info->encoders[ATOM_DEVICE_CV_INDEX]->encoder_id == ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1))) 1992209ff23fSmrg dac_data.sDacload.ucDacType = ATOM_DAC_A; 1993b7e1c893Smrg else 1994209ff23fSmrg dac_data.sDacload.ucDacType = ATOM_DAC_B; 1995b7e1c893Smrg if (minor >= 3) 1996b7e1c893Smrg dac_data.sDacload.ucMisc = DAC_LOAD_MISC_YPrPb; 1997209ff23fSmrg } else if (radeon_output->devices & ATOM_DEVICE_TV1_SUPPORT) { 1998b7e1c893Smrg dac_data.sDacload.usDeviceID = cpu_to_le16(ATOM_DEVICE_TV1_SUPPORT); 1999b7e1c893Smrg if (info->encoders[ATOM_DEVICE_TV1_INDEX] && 2000b7e1c893Smrg ((info->encoders[ATOM_DEVICE_TV1_INDEX]->encoder_id == ENCODER_OBJECT_ID_INTERNAL_DAC1) || 2001b7e1c893Smrg (info->encoders[ATOM_DEVICE_TV1_INDEX]->encoder_id == ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1))) 2002209ff23fSmrg dac_data.sDacload.ucDacType = ATOM_DAC_A; 2003b7e1c893Smrg else 2004209ff23fSmrg dac_data.sDacload.ucDacType = ATOM_DAC_B; 2005b7e1c893Smrg if (minor >= 3) 2006b7e1c893Smrg dac_data.sDacload.ucMisc = DAC_LOAD_MISC_YPrPb; 2007b7e1c893Smrg } else 2008209ff23fSmrg return ATOM_NOT_IMPLEMENTED; 2009209ff23fSmrg 2010b7e1c893Smrg data.exec.index = index; 2011209ff23fSmrg data.exec.dataSpace = (void *)&space; 2012209ff23fSmrg data.exec.pspace = &dac_data; 2013209ff23fSmrg 201468105dcbSveego if (RHDAtomBiosFunc(atomBIOS->pScrn, atomBIOS, ATOMBIOS_EXEC, &data) == ATOM_SUCCESS) { 2015042789b0Sveego/* ErrorF("Dac detection success\n"); */ 2016209ff23fSmrg return ATOM_SUCCESS ; 2017209ff23fSmrg } 2018209ff23fSmrg 2019209ff23fSmrg ErrorF("DAC detection failed\n"); 2020209ff23fSmrg return ATOM_NOT_IMPLEMENTED; 2021209ff23fSmrg} 2022209ff23fSmrg 2023209ff23fSmrgRADEONMonitorType 2024b7e1c893Smrgatombios_dac_detect(xf86OutputPtr output) 2025209ff23fSmrg{ 2026b7e1c893Smrg ScrnInfoPtr pScrn = output->scrn; 2027209ff23fSmrg RADEONInfoPtr info = RADEONPTR(pScrn); 2028209ff23fSmrg unsigned char *RADEONMMIO = info->MMIO; 2029209ff23fSmrg RADEONOutputPrivatePtr radeon_output = output->driver_private; 2030209ff23fSmrg RADEONMonitorType MonType = MT_NONE; 2031209ff23fSmrg AtomBiosResult ret; 2032c503f109Smrg RADEONSavePtr save = info->ModeReg; 2033209ff23fSmrg 2034b7e1c893Smrg if (radeon_output->devices & ATOM_DEVICE_TV1_SUPPORT) { 2035209ff23fSmrg if (xf86ReturnOptValBool(info->Options, OPTION_FORCE_TVOUT, FALSE)) { 2036b7e1c893Smrg if (radeon_output->ConnectorType == CONNECTOR_STV) 2037209ff23fSmrg return MT_STV; 2038209ff23fSmrg else 2039209ff23fSmrg return MT_CTV; 2040209ff23fSmrg } 2041209ff23fSmrg } 2042209ff23fSmrg 2043209ff23fSmrg ret = atom_bios_dac_load_detect(info->atomBIOS, output); 2044209ff23fSmrg if (ret == ATOM_SUCCESS) { 2045209ff23fSmrg if (info->ChipFamily >= CHIP_FAMILY_R600) 2046c503f109Smrg save->bios_0_scratch = INREG(R600_BIOS_0_SCRATCH); 2047209ff23fSmrg else 2048c503f109Smrg save->bios_0_scratch = INREG(RADEON_BIOS_0_SCRATCH); 2049c503f109Smrg /*ErrorF("DAC connect %08X\n", (unsigned int)save->bios_0_scratch);*/ 2050209ff23fSmrg 2051209ff23fSmrg if (radeon_output->devices & ATOM_DEVICE_CRT1_SUPPORT) { 2052c503f109Smrg if (save->bios_0_scratch & ATOM_S0_CRT1_MASK) 2053209ff23fSmrg MonType = MT_CRT; 2054209ff23fSmrg } else if (radeon_output->devices & ATOM_DEVICE_CRT2_SUPPORT) { 2055c503f109Smrg if (save->bios_0_scratch & ATOM_S0_CRT2_MASK) 2056209ff23fSmrg MonType = MT_CRT; 2057209ff23fSmrg } else if (radeon_output->devices & ATOM_DEVICE_CV_SUPPORT) { 2058c503f109Smrg if (save->bios_0_scratch & (ATOM_S0_CV_MASK | ATOM_S0_CV_MASK_A)) 2059209ff23fSmrg MonType = MT_CV; 2060209ff23fSmrg } else if (radeon_output->devices & ATOM_DEVICE_TV1_SUPPORT) { 2061c503f109Smrg if (save->bios_0_scratch & (ATOM_S0_TV1_COMPOSITE | ATOM_S0_TV1_COMPOSITE_A)) 2062209ff23fSmrg MonType = MT_CTV; 2063c503f109Smrg else if (save->bios_0_scratch & (ATOM_S0_TV1_SVIDEO | ATOM_S0_TV1_SVIDEO_A)) 2064209ff23fSmrg MonType = MT_STV; 2065209ff23fSmrg } 2066209ff23fSmrg } 2067209ff23fSmrg 2068209ff23fSmrg return MonType; 2069209ff23fSmrg} 2070209ff23fSmrg 2071ad43ddacSmrg 2072ad43ddacSmrgstatic inline int atom_dp_get_encoder_id(xf86OutputPtr output) 2073ad43ddacSmrg{ 2074ad43ddacSmrg RADEONOutputPrivatePtr radeon_output = output->driver_private; 2075ad43ddacSmrg int ret = 0; 2076ad43ddacSmrg if (radeon_output->dig_encoder) 2077ad43ddacSmrg ret |= ATOM_DP_CONFIG_DIG2_ENCODER; 2078ad43ddacSmrg else 2079ad43ddacSmrg ret |= ATOM_DP_CONFIG_DIG1_ENCODER; 2080ad43ddacSmrg if (radeon_output->linkb) 2081ad43ddacSmrg ret |= ATOM_DP_CONFIG_LINK_B; 2082ad43ddacSmrg else 2083ad43ddacSmrg ret |= ATOM_DP_CONFIG_LINK_A; 2084ad43ddacSmrg return ret; 2085ad43ddacSmrg} 2086ad43ddacSmrg 2087ad43ddacSmrgunion aux_channel_transaction { 2088ad43ddacSmrg PROCESS_AUX_CHANNEL_TRANSACTION_PS_ALLOCATION v1; 2089ad43ddacSmrg PROCESS_AUX_CHANNEL_TRANSACTION_PARAMETERS_V2 v2; 2090ad43ddacSmrg}; 2091ad43ddacSmrg 2092ad43ddacSmrgBool 2093ad43ddacSmrgRADEONProcessAuxCH(xf86OutputPtr output, uint8_t *req_bytes, uint8_t num_bytes, 2094ad43ddacSmrg uint8_t *read_byte, uint8_t read_buf_len, uint8_t delay) 2095ad43ddacSmrg{ 2096ad43ddacSmrg RADEONOutputPrivatePtr radeon_output = output->driver_private; 2097ad43ddacSmrg RADEONInfoPtr info = RADEONPTR(output->scrn); 2098ad43ddacSmrg union aux_channel_transaction args; 2099ad43ddacSmrg AtomBiosArgRec data; 2100ad43ddacSmrg unsigned char *space; 2101ad43ddacSmrg unsigned char *base; 21020974d292Smrg int retry_count = 0; 2103ad43ddacSmrg 2104ad43ddacSmrg memset(&args, 0, sizeof(args)); 2105ad43ddacSmrg if (info->atomBIOS->fbBase) 2106ad43ddacSmrg base = info->FB + info->atomBIOS->fbBase; 2107ad43ddacSmrg else if (info->atomBIOS->scratchBase) 2108ad43ddacSmrg base = (unsigned char *)info->atomBIOS->scratchBase; 2109ad43ddacSmrg else 2110ad43ddacSmrg return FALSE; 2111ad43ddacSmrg 21120974d292Smrgretry: 2113ad43ddacSmrg memcpy(base, req_bytes, num_bytes); 2114ad43ddacSmrg 2115ad43ddacSmrg args.v1.lpAuxRequest = 0; 2116ad43ddacSmrg args.v1.lpDataOut = 16; 2117ad43ddacSmrg args.v1.ucDataOutLen = 0; 2118ad43ddacSmrg args.v1.ucChannelID = radeon_output->ucI2cId; 2119ad43ddacSmrg args.v1.ucDelay = delay / 10; /* 10 usec */ 2120ad43ddacSmrg if (IS_DCE4_VARIANT) 2121ad43ddacSmrg args.v2.ucHPD_ID = radeon_output->hpd_id; 2122ad43ddacSmrg 2123ad43ddacSmrg data.exec.index = GetIndexIntoMasterTable(COMMAND, ProcessAuxChannelTransaction); 2124ad43ddacSmrg data.exec.dataSpace = (void *)&space; 2125ad43ddacSmrg data.exec.pspace = &args; 2126ad43ddacSmrg 212768105dcbSveego RHDAtomBiosFunc(info->atomBIOS->pScrn, info->atomBIOS, ATOMBIOS_EXEC, &data); 21280974d292Smrg if (args.v1.ucReplyStatus && !args.v1.ucDataOutLen) { 21290974d292Smrg if (args.v1.ucReplyStatus == 0x20 && retry_count++ < 10) 21300974d292Smrg goto retry; 21310974d292Smrg ErrorF("failed to get auxch %02x%02x %02x %02x %02x after %d retries\n", 21320974d292Smrg req_bytes[1], req_bytes[0], req_bytes[2], req_bytes[3], args.v1.ucReplyStatus, retry_count); 2133ad43ddacSmrg return FALSE; 2134ad43ddacSmrg } 2135ad43ddacSmrg if (args.v1.ucDataOutLen && read_byte && read_buf_len) { 2136ad43ddacSmrg if (read_buf_len < args.v1.ucDataOutLen) { 2137ad43ddacSmrg ErrorF("%s: Buffer too small for return answer %d %d\n", __func__, read_buf_len, args.v1.ucDataOutLen); 2138ad43ddacSmrg return FALSE; 2139ad43ddacSmrg } 2140ad43ddacSmrg { 2141ad43ddacSmrg int len = read_buf_len < args.v1.ucDataOutLen ? read_buf_len : args.v1.ucDataOutLen; 2142ad43ddacSmrg memcpy(read_byte, base+16, len); 2143ad43ddacSmrg } 2144ad43ddacSmrg } 2145ad43ddacSmrg return TRUE; 2146ad43ddacSmrg} 2147ad43ddacSmrg 2148ad43ddacSmrgstatic int 2149ad43ddacSmrgRADEONDPEncoderService(xf86OutputPtr output, int action, uint8_t ucconfig, uint8_t lane_num) 2150ad43ddacSmrg{ 2151ad43ddacSmrg RADEONInfoPtr info = RADEONPTR(output->scrn); 2152ad43ddacSmrg DP_ENCODER_SERVICE_PARAMETERS args; 2153ad43ddacSmrg AtomBiosArgRec data; 2154ad43ddacSmrg unsigned char *space; 2155ad43ddacSmrg 2156ad43ddacSmrg memset(&args, 0, sizeof(args)); 2157ad43ddacSmrg 2158ad43ddacSmrg args.ucLinkClock = 0; 2159ad43ddacSmrg args.ucConfig = ucconfig; 2160ad43ddacSmrg args.ucAction = action; 2161ad43ddacSmrg args.ucLaneNum = lane_num; 2162ad43ddacSmrg args.ucStatus = 0; 2163ad43ddacSmrg 2164ad43ddacSmrg data.exec.index = GetIndexIntoMasterTable(COMMAND, DPEncoderService); 2165ad43ddacSmrg data.exec.dataSpace = (void *)&space; 2166ad43ddacSmrg data.exec.pspace = &args; 2167ad43ddacSmrg 216868105dcbSveego RHDAtomBiosFunc(info->atomBIOS->pScrn, info->atomBIOS, ATOMBIOS_EXEC, &data); 2169ad43ddacSmrg 2170042789b0Sveego/* ErrorF("%s: %d %d\n", __func__, action, args.ucStatus); */ 2171ad43ddacSmrg return args.ucStatus; 2172ad43ddacSmrg} 2173ad43ddacSmrg 2174ad43ddacSmrgint RADEON_DP_GetSinkType(xf86OutputPtr output) 2175ad43ddacSmrg{ 2176ad43ddacSmrg RADEONOutputPrivatePtr radeon_output = output->driver_private; 2177ad43ddacSmrg 2178ad43ddacSmrg return RADEONDPEncoderService(output, ATOM_DP_ACTION_GET_SINK_TYPE, radeon_output->ucI2cId, 0); 2179ad43ddacSmrg} 2180ad43ddacSmrg 2181ad43ddacSmrgstatic Bool atom_dp_aux_native_write(xf86OutputPtr output, uint16_t address, 2182ad43ddacSmrg uint8_t send_bytes, uint8_t *send) 2183ad43ddacSmrg{ 2184ad43ddacSmrg uint8_t msg[20]; 2185ad43ddacSmrg uint8_t msg_len, dp_msg_len; 2186ad43ddacSmrg int ret; 2187ad43ddacSmrg 2188ad43ddacSmrg dp_msg_len = 4; 2189ad43ddacSmrg msg[0] = address; 2190ad43ddacSmrg msg[1] = address >> 8; 2191ad43ddacSmrg msg[2] = AUX_NATIVE_WRITE << 4; 2192ad43ddacSmrg dp_msg_len += send_bytes; 2193ad43ddacSmrg msg[3] = (dp_msg_len << 4)| (send_bytes - 1); 2194ad43ddacSmrg 2195ad43ddacSmrg if (0) 2196ad43ddacSmrg ErrorF("writing %02x %02x %02x, %d, %d\n", msg[0], msg[1], msg[3], send_bytes, dp_msg_len); 2197ad43ddacSmrg if (send_bytes > 16) 2198ad43ddacSmrg return FALSE; 2199ad43ddacSmrg 2200ad43ddacSmrg memcpy(&msg[4], send, send_bytes); 2201ad43ddacSmrg msg_len = 4 + send_bytes; 2202ad43ddacSmrg ret = RADEONProcessAuxCH(output, msg, msg_len, NULL, 0, 0); 2203ad43ddacSmrg return ret; 2204ad43ddacSmrg} 2205ad43ddacSmrg 2206ad43ddacSmrgstatic Bool atom_dp_aux_native_read(xf86OutputPtr output, uint16_t address, 2207ad43ddacSmrg uint8_t delay, 2208ad43ddacSmrg uint8_t expected_bytes, uint8_t *read_p) 2209ad43ddacSmrg{ 2210ad43ddacSmrg uint8_t msg[20]; 2211ad43ddacSmrg uint8_t msg_len, dp_msg_len; 2212ad43ddacSmrg int ret; 2213ad43ddacSmrg 2214ad43ddacSmrg msg_len = 4; 2215ad43ddacSmrg dp_msg_len = 4; 2216ad43ddacSmrg msg[0] = address; 2217ad43ddacSmrg msg[1] = address >> 8; 2218ad43ddacSmrg msg[2] = AUX_NATIVE_READ << 4; 2219ad43ddacSmrg msg[3] = (dp_msg_len) << 4; 2220ad43ddacSmrg msg[3] |= expected_bytes - 1; 2221ad43ddacSmrg 2222ad43ddacSmrg if (0) 2223ad43ddacSmrg ErrorF("reading %02x %02x %02x, %d, %d\n", msg[0], msg[1], msg[3], expected_bytes, dp_msg_len); 2224ad43ddacSmrg ret = RADEONProcessAuxCH(output, msg, msg_len, read_p, expected_bytes, delay); 2225ad43ddacSmrg return ret; 2226ad43ddacSmrg} 2227ad43ddacSmrg 2228ad43ddacSmrg/* fill out the DPCD structure */ 2229ad43ddacSmrgvoid RADEON_DP_GetDPCD(xf86OutputPtr output) 2230ad43ddacSmrg{ 2231ad43ddacSmrg RADEONOutputPrivatePtr radeon_output = output->driver_private; 2232ad43ddacSmrg uint8_t msg[25]; 2233ad43ddacSmrg int ret; 2234ad43ddacSmrg 2235ad43ddacSmrg ret = atom_dp_aux_native_read(output, DP_DPCD_REV, 0, 8, msg); 2236ad43ddacSmrg if (ret) { 2237ad43ddacSmrg memcpy(radeon_output->dpcd, msg, 8); 2238ad43ddacSmrg if (0) { 2239ad43ddacSmrg int i; 2240ad43ddacSmrg ErrorF("DPCD: "); 2241ad43ddacSmrg for (i = 0; i < 8; i++) 2242ad43ddacSmrg ErrorF("%02x ", radeon_output->dpcd[i]); 2243ad43ddacSmrg ErrorF("\n"); 2244ad43ddacSmrg } 2245ad43ddacSmrg ret = atom_dp_aux_native_read(output, DP_LINK_BW_SET, 0, 2, msg); 2246ad43ddacSmrg if (0) { 2247ad43ddacSmrg ErrorF("0x200: %02x %02x\n", msg[0], msg[1]); 2248ad43ddacSmrg } 2249ad43ddacSmrg return; 2250ad43ddacSmrg } 2251ad43ddacSmrg radeon_output->dpcd[0] = 0; 2252ad43ddacSmrg return; 2253ad43ddacSmrg} 2254ad43ddacSmrg 2255ad43ddacSmrg 2256ad43ddacSmrgenum dp_aux_i2c_mode { 2257ad43ddacSmrg dp_aux_i2c_start, 2258ad43ddacSmrg dp_aux_i2c_write, 2259ad43ddacSmrg dp_aux_i2c_read, 2260ad43ddacSmrg dp_aux_i2c_stop, 2261ad43ddacSmrg}; 2262ad43ddacSmrg 2263ad43ddacSmrg 2264ad43ddacSmrgstatic Bool atom_dp_aux_i2c_transaction(xf86OutputPtr output, uint16_t address, 2265ad43ddacSmrg enum dp_aux_i2c_mode mode, 2266ad43ddacSmrg uint8_t write_byte, uint8_t *read_byte) 2267ad43ddacSmrg{ 2268ad43ddacSmrg uint8_t msg[8], msg_len, dp_msg_len; 2269ad43ddacSmrg int ret; 2270ad43ddacSmrg int auxch_cmd = 0; 2271ad43ddacSmrg 2272ad43ddacSmrg memset(msg, 0, 8); 2273ad43ddacSmrg 2274ad43ddacSmrg if (mode != dp_aux_i2c_stop) 2275ad43ddacSmrg auxch_cmd = AUX_I2C_MOT; 2276ad43ddacSmrg 2277ad43ddacSmrg if (address & 1) 2278ad43ddacSmrg auxch_cmd |= AUX_I2C_READ; 2279ad43ddacSmrg else 2280ad43ddacSmrg auxch_cmd |= AUX_I2C_WRITE; 2281ad43ddacSmrg 2282ad43ddacSmrg msg[2] = auxch_cmd << 4; 2283ad43ddacSmrg 2284ad43ddacSmrg msg[4] = 0; 2285ad43ddacSmrg msg[0] = (address >> 1); 2286ad43ddacSmrg msg[1] = (address >> 9); 2287ad43ddacSmrg 2288ad43ddacSmrg msg_len = 4; 2289ad43ddacSmrg dp_msg_len = 3; 2290ad43ddacSmrg switch (mode) { 2291ad43ddacSmrg case dp_aux_i2c_read: 2292ad43ddacSmrg /* bottom bits is byte count - 1 so for 1 byte == 0 */ 2293ad43ddacSmrg dp_msg_len += 1; 2294ad43ddacSmrg break; 2295ad43ddacSmrg case dp_aux_i2c_write: 2296ad43ddacSmrg dp_msg_len += 2; 2297ad43ddacSmrg msg[4] = write_byte; 2298ad43ddacSmrg msg_len++; 2299ad43ddacSmrg break; 2300ad43ddacSmrg default: 2301ad43ddacSmrg break; 2302ad43ddacSmrg } 2303ad43ddacSmrg msg[3] = dp_msg_len << 4; 2304ad43ddacSmrg 2305ad43ddacSmrg ret = RADEONProcessAuxCH(output, msg, msg_len, read_byte, 1, 0); 2306ad43ddacSmrg return ret; 2307ad43ddacSmrg} 2308ad43ddacSmrg 2309ad43ddacSmrgstatic Bool 2310ad43ddacSmrgatom_dp_i2c_address(I2CDevPtr dev, I2CSlaveAddr addr) 2311ad43ddacSmrg{ 2312ad43ddacSmrg I2CBusPtr bus = dev->pI2CBus; 2313ad43ddacSmrg xf86OutputPtr output = bus->DriverPrivate.ptr; 2314ad43ddacSmrg RADEONOutputPrivatePtr radeon_output = output->driver_private; 2315ad43ddacSmrg int ret; 2316ad43ddacSmrg 2317ad43ddacSmrg radeon_output->dp_i2c_addr = addr; 2318ad43ddacSmrg radeon_output->dp_i2c_running = TRUE; 2319ad43ddacSmrg 2320ad43ddacSmrg /* call i2c start */ 2321ad43ddacSmrg ret = atom_dp_aux_i2c_transaction(output, radeon_output->dp_i2c_addr, 2322ad43ddacSmrg dp_aux_i2c_start, 0, NULL); 2323ad43ddacSmrg 2324ad43ddacSmrg return ret; 2325ad43ddacSmrg} 2326ad43ddacSmrgstatic Bool 2327ad43ddacSmrgatom_dp_i2c_start(I2CBusPtr bus, int timeout) 2328ad43ddacSmrg{ 2329042789b0Sveego/* ErrorF("%s\n", __func__); */ 2330ad43ddacSmrg return TRUE; 2331ad43ddacSmrg} 2332ad43ddacSmrg 2333ad43ddacSmrgstatic void 2334ad43ddacSmrgatom_dp_i2c_stop(I2CDevPtr dev) 2335ad43ddacSmrg{ 2336ad43ddacSmrg I2CBusPtr bus = dev->pI2CBus; 2337ad43ddacSmrg xf86OutputPtr output = bus->DriverPrivate.ptr; 2338ad43ddacSmrg RADEONOutputPrivatePtr radeon_output = output->driver_private; 2339ad43ddacSmrg 2340ad43ddacSmrg if (radeon_output->dp_i2c_running) 2341ad43ddacSmrg atom_dp_aux_i2c_transaction(output, radeon_output->dp_i2c_addr, 2342ad43ddacSmrg dp_aux_i2c_stop, 0, NULL); 2343ad43ddacSmrg radeon_output->dp_i2c_running = FALSE; 2344ad43ddacSmrg} 2345ad43ddacSmrg 2346ad43ddacSmrg 2347ad43ddacSmrgstatic Bool 2348ad43ddacSmrgatom_dp_i2c_put_byte(I2CDevPtr dev, I2CByte byte) 2349ad43ddacSmrg{ 2350ad43ddacSmrg I2CBusPtr bus = dev->pI2CBus; 2351ad43ddacSmrg xf86OutputPtr output = bus->DriverPrivate.ptr; 2352ad43ddacSmrg RADEONOutputPrivatePtr radeon_output = output->driver_private; 2353ad43ddacSmrg Bool ret; 2354ad43ddacSmrg 2355ad43ddacSmrg ret = (atom_dp_aux_i2c_transaction(output, radeon_output->dp_i2c_addr, 2356ad43ddacSmrg dp_aux_i2c_write, byte, NULL)); 2357ad43ddacSmrg return ret; 2358ad43ddacSmrg} 2359ad43ddacSmrg 2360ad43ddacSmrgstatic Bool 2361ad43ddacSmrgatom_dp_i2c_get_byte(I2CDevPtr dev, I2CByte *byte_ret, Bool last) 2362ad43ddacSmrg{ 2363ad43ddacSmrg I2CBusPtr bus = dev->pI2CBus; 2364ad43ddacSmrg xf86OutputPtr output = bus->DriverPrivate.ptr; 2365ad43ddacSmrg RADEONOutputPrivatePtr radeon_output = output->driver_private; 2366ad43ddacSmrg Bool ret; 2367ad43ddacSmrg 2368ad43ddacSmrg ret = (atom_dp_aux_i2c_transaction(output, radeon_output->dp_i2c_addr, 2369ad43ddacSmrg dp_aux_i2c_read, 0, byte_ret)); 2370ad43ddacSmrg return ret; 2371ad43ddacSmrg} 2372ad43ddacSmrg 2373ad43ddacSmrgBool 2374ad43ddacSmrgRADEON_DP_I2CInit(ScrnInfoPtr pScrn, I2CBusPtr *bus_ptr, char *name, xf86OutputPtr output) 2375ad43ddacSmrg{ 2376ad43ddacSmrg I2CBusPtr pI2CBus; 2377ad43ddacSmrg 2378ad43ddacSmrg pI2CBus = xf86CreateI2CBusRec(); 2379ad43ddacSmrg if (!pI2CBus) return FALSE; 2380ad43ddacSmrg 2381ad43ddacSmrg pI2CBus->BusName = name; 2382ad43ddacSmrg pI2CBus->scrnIndex = pScrn->scrnIndex; 2383ad43ddacSmrg pI2CBus->I2CGetByte = atom_dp_i2c_get_byte; 2384ad43ddacSmrg pI2CBus->I2CPutByte = atom_dp_i2c_put_byte; 2385ad43ddacSmrg pI2CBus->I2CAddress = atom_dp_i2c_address; 2386ad43ddacSmrg pI2CBus->I2CStart = atom_dp_i2c_start; 2387ad43ddacSmrg pI2CBus->I2CStop = atom_dp_i2c_stop; 2388ad43ddacSmrg pI2CBus->DriverPrivate.ptr = output; 2389ad43ddacSmrg 2390ad43ddacSmrg /* 2391ad43ddacSmrg * These were set incorrectly in the server pre-1.3, Having 2392ad43ddacSmrg * duplicate settings is sub-optimal, but this lets the driver 2393ad43ddacSmrg * work with older servers 2394ad43ddacSmrg */ 2395ad43ddacSmrg pI2CBus->ByteTimeout = 2200; /* VESA DDC spec 3 p. 43 (+10 %) */ 2396ad43ddacSmrg pI2CBus->StartTimeout = 550; 2397ad43ddacSmrg pI2CBus->BitTimeout = 40; 2398ad43ddacSmrg pI2CBus->AcknTimeout = 40; 2399ad43ddacSmrg pI2CBus->RiseFallTime = 20; 2400ad43ddacSmrg 2401ad43ddacSmrg if (!xf86I2CBusInit(pI2CBus)) 2402ad43ddacSmrg return FALSE; 2403ad43ddacSmrg 2404ad43ddacSmrg *bus_ptr = pI2CBus; 2405ad43ddacSmrg return TRUE; 2406ad43ddacSmrg} 2407ad43ddacSmrg 2408ad43ddacSmrg 2409ad43ddacSmrgstatic uint8_t dp_link_status(uint8_t link_status[DP_LINK_STATUS_SIZE], int r) 2410ad43ddacSmrg{ 2411ad43ddacSmrg return link_status[r - DP_LANE0_1_STATUS]; 2412ad43ddacSmrg} 2413ad43ddacSmrg 2414ad43ddacSmrgstatic uint8_t dp_get_lane_status(uint8_t link_status[DP_LINK_STATUS_SIZE], int lane) 2415ad43ddacSmrg{ 2416ad43ddacSmrg int i = DP_LANE0_1_STATUS + (lane >> 1); 2417ad43ddacSmrg int s = (lane & 1) * 4; 2418ad43ddacSmrg uint8_t l = dp_link_status(link_status, i); 2419ad43ddacSmrg return (l >> s) & 0xf; 2420ad43ddacSmrg} 2421ad43ddacSmrg 2422ad43ddacSmrgstatic Bool dp_clock_recovery_ok(uint8_t link_status[DP_LINK_STATUS_SIZE], int lane_count) 2423ad43ddacSmrg{ 2424ad43ddacSmrg int lane; 2425ad43ddacSmrg 2426ad43ddacSmrg uint8_t lane_status; 2427ad43ddacSmrg 2428ad43ddacSmrg for (lane = 0; lane < lane_count; lane++) { 2429ad43ddacSmrg lane_status = dp_get_lane_status(link_status, lane); 2430ad43ddacSmrg if ((lane_status & DP_LANE_CR_DONE) == 0) 2431ad43ddacSmrg return FALSE; 2432ad43ddacSmrg } 2433ad43ddacSmrg return TRUE; 2434ad43ddacSmrg} 2435ad43ddacSmrg 2436ad43ddacSmrg 2437ad43ddacSmrg/* Check to see if channel eq is done on all channels */ 2438ad43ddacSmrg#define CHANNEL_EQ_BITS (DP_LANE_CR_DONE|\ 2439ad43ddacSmrg DP_LANE_CHANNEL_EQ_DONE|\ 2440ad43ddacSmrg DP_LANE_SYMBOL_LOCKED) 2441ad43ddacSmrgstatic Bool 2442ad43ddacSmrgdp_channel_eq_ok(uint8_t link_status[DP_LINK_STATUS_SIZE], int lane_count) 2443ad43ddacSmrg{ 2444ad43ddacSmrg uint8_t lane_align; 2445ad43ddacSmrg uint8_t lane_status; 2446ad43ddacSmrg int lane; 2447ad43ddacSmrg 2448ad43ddacSmrg lane_align = dp_link_status(link_status, 2449ad43ddacSmrg DP_LANE_ALIGN_STATUS_UPDATED); 2450ad43ddacSmrg if ((lane_align & DP_INTERLANE_ALIGN_DONE) == 0) 2451ad43ddacSmrg return FALSE; 2452ad43ddacSmrg for (lane = 0; lane < lane_count; lane++) { 2453ad43ddacSmrg lane_status = dp_get_lane_status(link_status, lane); 2454ad43ddacSmrg if ((lane_status & CHANNEL_EQ_BITS) != CHANNEL_EQ_BITS) 2455ad43ddacSmrg return FALSE; 2456ad43ddacSmrg } 2457ad43ddacSmrg return TRUE; 2458ad43ddacSmrg} 2459ad43ddacSmrg 2460ad43ddacSmrg/* 2461ad43ddacSmrg * Fetch AUX CH registers 0x202 - 0x207 which contain 2462ad43ddacSmrg * link status information 2463ad43ddacSmrg */ 2464ad43ddacSmrgstatic Bool 2465ad43ddacSmrgatom_dp_get_link_status(xf86OutputPtr output, 2466ad43ddacSmrg uint8_t link_status[DP_LINK_STATUS_SIZE]) 2467ad43ddacSmrg{ 2468ad43ddacSmrg ScrnInfoPtr pScrn = output->scrn; 2469ad43ddacSmrg int ret; 2470ad43ddacSmrg ret = atom_dp_aux_native_read(output, DP_LANE0_1_STATUS, 100, 2471ad43ddacSmrg DP_LINK_STATUS_SIZE, link_status); 2472ad43ddacSmrg if (!ret) { 2473ad43ddacSmrg xf86DrvMsg(pScrn->scrnIndex, X_INFO, "dp link status failed\n"); 2474ad43ddacSmrg return FALSE; 2475ad43ddacSmrg } 2476042789b0Sveego/* ErrorF("link status %02x %02x %02x %02x %02x %02x\n", link_status[0], link_status[1], 2477042789b0Sveego link_status[2], link_status[3], link_status[4], link_status[5]); */ 2478ad43ddacSmrg 2479ad43ddacSmrg return TRUE; 2480ad43ddacSmrg} 2481ad43ddacSmrg 2482ad43ddacSmrgstatic uint8_t 2483ad43ddacSmrgdp_get_adjust_request_voltage(uint8_t link_status[DP_LINK_STATUS_SIZE], 2484ad43ddacSmrg int lane) 2485ad43ddacSmrg 2486ad43ddacSmrg{ 2487ad43ddacSmrg int i = DP_ADJUST_REQUEST_LANE0_1 + (lane >> 1); 2488ad43ddacSmrg int s = ((lane & 1) ? 2489ad43ddacSmrg DP_ADJUST_VOLTAGE_SWING_LANE1_SHIFT : 2490ad43ddacSmrg DP_ADJUST_VOLTAGE_SWING_LANE0_SHIFT); 2491ad43ddacSmrg uint8_t l = dp_link_status(link_status, i); 2492ad43ddacSmrg 2493ad43ddacSmrg return ((l >> s) & 3) << DP_TRAIN_VOLTAGE_SWING_SHIFT; 2494ad43ddacSmrg} 2495ad43ddacSmrg 2496ad43ddacSmrgstatic uint8_t 2497ad43ddacSmrgdp_get_adjust_request_pre_emphasis(uint8_t link_status[DP_LINK_STATUS_SIZE], 2498ad43ddacSmrg int lane) 2499ad43ddacSmrg{ 2500ad43ddacSmrg int i = DP_ADJUST_REQUEST_LANE0_1 + (lane >> 1); 2501ad43ddacSmrg int s = ((lane & 1) ? 2502ad43ddacSmrg DP_ADJUST_PRE_EMPHASIS_LANE1_SHIFT : 2503ad43ddacSmrg DP_ADJUST_PRE_EMPHASIS_LANE0_SHIFT); 2504ad43ddacSmrg uint8_t l = dp_link_status(link_status, i); 2505ad43ddacSmrg 2506ad43ddacSmrg return ((l >> s) & 3) << DP_TRAIN_PRE_EMPHASIS_SHIFT; 2507ad43ddacSmrg} 2508ad43ddacSmrg 2509ad43ddacSmrgstatic char *voltage_names[] = { 2510ad43ddacSmrg "0.4V", "0.6V", "0.8V", "1.2V" 2511ad43ddacSmrg}; 2512ad43ddacSmrgstatic char *pre_emph_names[] = { 2513ad43ddacSmrg "0dB", "3.5dB", "6dB", "9.5dB" 2514ad43ddacSmrg}; 2515ad43ddacSmrg 2516ad43ddacSmrg/* 2517ad43ddacSmrg * These are source-specific values; current Intel hardware supports 2518ad43ddacSmrg * a maximum voltage of 800mV and a maximum pre-emphasis of 6dB 2519ad43ddacSmrg */ 2520ad43ddacSmrg#define DP_VOLTAGE_MAX DP_TRAIN_VOLTAGE_SWING_1200 2521ad43ddacSmrg 2522ad43ddacSmrgstatic uint8_t 2523ad43ddacSmrgdp_pre_emphasis_max(uint8_t voltage_swing) 2524ad43ddacSmrg{ 2525ad43ddacSmrg switch (voltage_swing & DP_TRAIN_VOLTAGE_SWING_MASK) { 2526ad43ddacSmrg case DP_TRAIN_VOLTAGE_SWING_400: 2527ad43ddacSmrg return DP_TRAIN_PRE_EMPHASIS_6; 2528ad43ddacSmrg case DP_TRAIN_VOLTAGE_SWING_600: 2529ad43ddacSmrg return DP_TRAIN_PRE_EMPHASIS_6; 2530ad43ddacSmrg case DP_TRAIN_VOLTAGE_SWING_800: 2531ad43ddacSmrg return DP_TRAIN_PRE_EMPHASIS_3_5; 2532ad43ddacSmrg case DP_TRAIN_VOLTAGE_SWING_1200: 2533ad43ddacSmrg default: 2534ad43ddacSmrg return DP_TRAIN_PRE_EMPHASIS_0; 2535ad43ddacSmrg } 2536ad43ddacSmrg} 2537ad43ddacSmrg 2538ad43ddacSmrgstatic void dp_set_training(xf86OutputPtr output, uint8_t training) 2539ad43ddacSmrg{ 2540ad43ddacSmrg atom_dp_aux_native_write(output, DP_TRAINING_PATTERN_SET, 1, &training); 2541ad43ddacSmrg} 2542ad43ddacSmrg 2543ad43ddacSmrgstatic void dp_set_power(xf86OutputPtr output, uint8_t power_state) 2544ad43ddacSmrg{ 2545ad43ddacSmrg RADEONOutputPrivatePtr radeon_output = output->driver_private; 2546ad43ddacSmrg 2547ad43ddacSmrg if (radeon_output->dpcd[0] >= 0x11) { 2548ad43ddacSmrg atom_dp_aux_native_write(output, 0x600, 1, &power_state); 2549ad43ddacSmrg } 2550ad43ddacSmrg} 2551ad43ddacSmrg 2552ad43ddacSmrgstatic void 2553ad43ddacSmrgdp_get_adjust_train(xf86OutputPtr output, 2554ad43ddacSmrg uint8_t link_status[DP_LINK_STATUS_SIZE], 2555ad43ddacSmrg int lane_count, 2556ad43ddacSmrg uint8_t train_set[4]) 2557ad43ddacSmrg{ 2558ad43ddacSmrg ScrnInfoPtr pScrn = output->scrn; 2559ad43ddacSmrg uint8_t v = 0; 2560ad43ddacSmrg uint8_t p = 0; 2561ad43ddacSmrg int lane; 2562ad43ddacSmrg 2563ad43ddacSmrg for (lane = 0; lane < lane_count; lane++) { 2564ad43ddacSmrg uint8_t this_v = dp_get_adjust_request_voltage(link_status, lane); 2565ad43ddacSmrg uint8_t this_p = dp_get_adjust_request_pre_emphasis(link_status, lane); 2566ad43ddacSmrg 2567ad43ddacSmrg if (0) { 2568ad43ddacSmrg xf86DrvMsg(pScrn->scrnIndex, X_INFO, 2569ad43ddacSmrg "requested signal parameters: lane %d voltage %s pre_emph %s\n", 2570ad43ddacSmrg lane, 2571ad43ddacSmrg voltage_names[this_v >> DP_TRAIN_VOLTAGE_SWING_SHIFT], 2572ad43ddacSmrg pre_emph_names[this_p >> DP_TRAIN_PRE_EMPHASIS_SHIFT]); 2573ad43ddacSmrg } 2574ad43ddacSmrg if (this_v > v) 2575ad43ddacSmrg v = this_v; 2576ad43ddacSmrg if (this_p > p) 2577ad43ddacSmrg p = this_p; 2578ad43ddacSmrg } 2579ad43ddacSmrg 2580ad43ddacSmrg if (v >= DP_VOLTAGE_MAX) 2581ad43ddacSmrg v = DP_VOLTAGE_MAX | DP_TRAIN_MAX_SWING_REACHED; 2582ad43ddacSmrg 2583ad43ddacSmrg if (p >= dp_pre_emphasis_max(v)) 2584ad43ddacSmrg p = dp_pre_emphasis_max(v) | DP_TRAIN_MAX_PRE_EMPHASIS_REACHED; 2585ad43ddacSmrg 2586ad43ddacSmrg if (0) { 2587ad43ddacSmrg xf86DrvMsg(pScrn->scrnIndex, X_INFO, 2588ad43ddacSmrg "using signal parameters: voltage %s pre_emph %s\n", 2589ad43ddacSmrg voltage_names[(v & DP_TRAIN_VOLTAGE_SWING_MASK) >> DP_TRAIN_VOLTAGE_SWING_SHIFT], 2590ad43ddacSmrg pre_emph_names[(p & DP_TRAIN_PRE_EMPHASIS_MASK) >> DP_TRAIN_PRE_EMPHASIS_SHIFT]); 2591ad43ddacSmrg } 2592ad43ddacSmrg for (lane = 0; lane < 4; lane++) 2593ad43ddacSmrg train_set[lane] = v | p; 2594ad43ddacSmrg} 2595ad43ddacSmrg 2596ad43ddacSmrgstatic int radeon_dp_max_lane_count(xf86OutputPtr output) 2597ad43ddacSmrg{ 2598ad43ddacSmrg RADEONOutputPrivatePtr radeon_output = output->driver_private; 2599ad43ddacSmrg int max_lane_count = 4; 2600ad43ddacSmrg 2601ad43ddacSmrg if (radeon_output->dpcd[0] >= 0x11) { 2602ad43ddacSmrg max_lane_count = radeon_output->dpcd[2] & 0x1f; 2603ad43ddacSmrg switch(max_lane_count) { 2604ad43ddacSmrg case 1: case 2: case 4: 2605ad43ddacSmrg break; 2606ad43ddacSmrg default: 2607ad43ddacSmrg max_lane_count = 4; 2608ad43ddacSmrg } 2609ad43ddacSmrg } 2610ad43ddacSmrg return max_lane_count; 2611ad43ddacSmrg} 2612ad43ddacSmrg 2613ad43ddacSmrgBool radeon_dp_mode_fixup(xf86OutputPtr output, DisplayModePtr mode, DisplayModePtr adjusted_mode) 2614ad43ddacSmrg{ 2615921a55d8Smrg RADEONOutputPrivatePtr radeon_output = output->driver_private; 2616921a55d8Smrg int clock = adjusted_mode->Clock; 2617921a55d8Smrg 2618921a55d8Smrg radeon_output->dp_lane_count = dp_lanes_for_mode_clock(output, clock); 2619921a55d8Smrg radeon_output->dp_clock = dp_link_clock_for_mode_clock(output, clock); 2620921a55d8Smrg if (!radeon_output->dp_lane_count || !radeon_output->dp_clock) 2621921a55d8Smrg return FALSE; 2622921a55d8Smrg return TRUE; 2623ad43ddacSmrg} 2624ad43ddacSmrg 2625ad43ddacSmrgstatic void dp_update_dpvs_emph(xf86OutputPtr output, uint8_t train_set[4]) 2626ad43ddacSmrg{ 2627ad43ddacSmrg RADEONOutputPrivatePtr radeon_output = output->driver_private; 2628ad43ddacSmrg int i; 2629ad43ddacSmrg for (i = 0; i < radeon_output->dp_lane_count; i++) 2630ad43ddacSmrg atombios_output_dig_transmitter_setup(output, ATOM_TRANSMITTER_ACTION_SETUP_VSEMPH, i, train_set[i]); 2631ad43ddacSmrg 2632ad43ddacSmrg atom_dp_aux_native_write(output, DP_TRAINING_LANE0_SET, radeon_output->dp_lane_count, train_set); 2633ad43ddacSmrg} 2634ad43ddacSmrg 2635ad43ddacSmrgstatic void do_displayport_link_train(xf86OutputPtr output) 2636ad43ddacSmrg{ 2637ad43ddacSmrg ScrnInfoPtr pScrn = output->scrn; 2638ad43ddacSmrg RADEONInfoPtr info = RADEONPTR(pScrn); 2639ad43ddacSmrg RADEONOutputPrivatePtr radeon_output = output->driver_private; 2640ad43ddacSmrg int enc_id = atom_dp_get_encoder_id(output); 2641ad43ddacSmrg Bool clock_recovery; 2642ad43ddacSmrg uint8_t link_status[DP_LINK_STATUS_SIZE]; 2643ad43ddacSmrg uint8_t tries, voltage, ss_cntl; 2644ad43ddacSmrg uint8_t train_set[4]; 2645ad43ddacSmrg int i; 2646ad43ddacSmrg Bool channel_eq; 2647ad43ddacSmrg uint8_t dp_link_configuration[DP_LINK_CONFIGURATION_SIZE]; 2648ad43ddacSmrg 2649ad43ddacSmrg memset(train_set, 0, 4); 2650ad43ddacSmrg 2651ad43ddacSmrg /* set up link configuration */ 2652ad43ddacSmrg memset(dp_link_configuration, 0, DP_LINK_CONFIGURATION_SIZE); 2653ad43ddacSmrg 2654921a55d8Smrg if (radeon_output->dp_clock == 27000) 2655ad43ddacSmrg dp_link_configuration[0] = DP_LINK_BW_2_7; 2656ad43ddacSmrg else 2657ad43ddacSmrg dp_link_configuration[0] = DP_LINK_BW_1_62; 2658ad43ddacSmrg dp_link_configuration[1] = radeon_output->dp_lane_count; 2659ad43ddacSmrg 2660ad43ddacSmrg if (radeon_output->dpcd[0] >= 0x11) { 2661ad43ddacSmrg dp_link_configuration[1] |= DP_LANE_COUNT_ENHANCED_FRAME_EN; 2662ad43ddacSmrg } 2663ad43ddacSmrg 2664ad43ddacSmrg /* power up to D0 */ 2665ad43ddacSmrg dp_set_power(output, DP_SET_POWER_D0); 2666ad43ddacSmrg 2667ad43ddacSmrg /* disable training */ 2668ad43ddacSmrg dp_set_training(output, DP_TRAINING_PATTERN_DISABLE); 2669ad43ddacSmrg 2670ad43ddacSmrg /* write link rate / num / eh framing */ 2671ad43ddacSmrg atom_dp_aux_native_write(output, DP_LINK_BW_SET, 2, 2672ad43ddacSmrg dp_link_configuration); 2673ad43ddacSmrg 2674ad43ddacSmrg /* write ss cntl */ 2675ad43ddacSmrg ss_cntl = 0; 2676ad43ddacSmrg atom_dp_aux_native_write(output, DP_DOWNSPREAD_CTRL, 1, 2677ad43ddacSmrg &ss_cntl); 2678ad43ddacSmrg 2679ad43ddacSmrg /* start local training start */ 2680ad43ddacSmrg if (IS_DCE4_VARIANT) { 26810974d292Smrg atombios_output_dig_encoder_setup(output, ATOM_ENCODER_CMD_DP_LINK_TRAINING_START); 26820974d292Smrg atombios_output_dig_encoder_setup(output, ATOM_ENCODER_CMD_DP_LINK_TRAINING_PATTERN1); 2683ad43ddacSmrg } else { 2684ad43ddacSmrg RADEONDPEncoderService(output, ATOM_DP_ACTION_TRAINING_START, enc_id, 0); 2685ad43ddacSmrg RADEONDPEncoderService(output, ATOM_DP_ACTION_TRAINING_PATTERN_SEL, enc_id, 0); 2686ad43ddacSmrg } 2687ad43ddacSmrg 2688ad43ddacSmrg usleep(400); 2689ad43ddacSmrg dp_set_training(output, DP_TRAINING_PATTERN_1); 2690ad43ddacSmrg dp_update_dpvs_emph(output, train_set); 2691ad43ddacSmrg 2692ad43ddacSmrg /* loop around doing configuration reads and DP encoder setups */ 2693ad43ddacSmrg clock_recovery = FALSE; 2694ad43ddacSmrg tries = 0; 2695ad43ddacSmrg voltage = 0xff; 2696ad43ddacSmrg for (;;) { 2697ad43ddacSmrg usleep(100); 2698ad43ddacSmrg if (!atom_dp_get_link_status(output, link_status)) 2699ad43ddacSmrg break; 2700ad43ddacSmrg 2701ad43ddacSmrg if (dp_clock_recovery_ok(link_status, radeon_output->dp_lane_count)) { 2702ad43ddacSmrg clock_recovery = TRUE; 2703ad43ddacSmrg break; 2704ad43ddacSmrg } 2705ad43ddacSmrg 2706ad43ddacSmrg for (i = 0; i < radeon_output->dp_lane_count; i++) 2707ad43ddacSmrg if ((train_set[i] & DP_TRAIN_MAX_SWING_REACHED) == 0) 2708ad43ddacSmrg break; 2709ad43ddacSmrg if (i == radeon_output->dp_lane_count) { 2710ad43ddacSmrg xf86DrvMsg(pScrn->scrnIndex, X_INFO, 2711ad43ddacSmrg "clock recovery reached max voltage\n"); 2712ad43ddacSmrg break; 2713ad43ddacSmrg } 2714ad43ddacSmrg 2715ad43ddacSmrg /* Check to see if we've tried the same voltage 5 times */ 2716ad43ddacSmrg if ((train_set[0] & DP_TRAIN_VOLTAGE_SWING_MASK) == voltage) { 2717ad43ddacSmrg ++tries; 2718ad43ddacSmrg if (tries == 5) { 2719ad43ddacSmrg xf86DrvMsg(pScrn->scrnIndex, X_INFO, 2720ad43ddacSmrg "clock recovery tried 5 times\n"); 2721ad43ddacSmrg break; 2722ad43ddacSmrg } 2723ad43ddacSmrg } else 2724ad43ddacSmrg tries = 0; 2725ad43ddacSmrg 2726ad43ddacSmrg voltage = train_set[0] & DP_TRAIN_VOLTAGE_SWING_MASK; 2727ad43ddacSmrg 2728ad43ddacSmrg dp_get_adjust_train(output, link_status, radeon_output->dp_lane_count, train_set); 2729ad43ddacSmrg dp_update_dpvs_emph(output, train_set); 2730ad43ddacSmrg 2731ad43ddacSmrg } 2732ad43ddacSmrg 2733ad43ddacSmrg if (!clock_recovery) 2734ad43ddacSmrg xf86DrvMsg(pScrn->scrnIndex, X_ERROR, 2735ad43ddacSmrg "clock recovery failed\n"); 2736ad43ddacSmrg 2737ad43ddacSmrg /* channel equalization */ 2738ad43ddacSmrg tries = 0; 2739ad43ddacSmrg channel_eq = FALSE; 2740ad43ddacSmrg dp_set_training(output, DP_TRAINING_PATTERN_2); 2741ad43ddacSmrg if (IS_DCE4_VARIANT) 27420974d292Smrg atombios_output_dig_encoder_setup(output, ATOM_ENCODER_CMD_DP_LINK_TRAINING_PATTERN2); 2743ad43ddacSmrg else 2744ad43ddacSmrg RADEONDPEncoderService(output, ATOM_DP_ACTION_TRAINING_PATTERN_SEL, enc_id, 1); 2745ad43ddacSmrg 2746ad43ddacSmrg for (;;) { 2747ad43ddacSmrg usleep(400); 2748ad43ddacSmrg if (!atom_dp_get_link_status(output, link_status)) 2749ad43ddacSmrg break; 2750ad43ddacSmrg 2751ad43ddacSmrg if (dp_channel_eq_ok(link_status, radeon_output->dp_lane_count)) { 2752ad43ddacSmrg channel_eq = TRUE; 2753ad43ddacSmrg break; 2754ad43ddacSmrg } 2755ad43ddacSmrg 2756ad43ddacSmrg /* Try 5 times */ 2757ad43ddacSmrg if (tries > 5) { 2758ad43ddacSmrg xf86DrvMsg(pScrn->scrnIndex, X_INFO, 2759ad43ddacSmrg "channel eq failed: 5 tries\n"); 2760ad43ddacSmrg break; 2761ad43ddacSmrg } 2762ad43ddacSmrg 2763ad43ddacSmrg /* Compute new train_set as requested by target */ 2764ad43ddacSmrg dp_get_adjust_train(output, link_status, radeon_output->dp_lane_count, train_set); 2765ad43ddacSmrg dp_update_dpvs_emph(output, train_set); 2766ad43ddacSmrg 2767ad43ddacSmrg ++tries; 2768ad43ddacSmrg } 2769ad43ddacSmrg 2770ad43ddacSmrg if (!channel_eq) 2771ad43ddacSmrg xf86DrvMsg(pScrn->scrnIndex, X_ERROR, 2772ad43ddacSmrg "channel eq failed\n"); 2773ad43ddacSmrg 2774ad43ddacSmrg dp_set_training(output, DP_TRAINING_PATTERN_DISABLE); 2775ad43ddacSmrg if (IS_DCE4_VARIANT) 27760974d292Smrg atombios_output_dig_encoder_setup(output, ATOM_ENCODER_CMD_DP_LINK_TRAINING_COMPLETE); 2777ad43ddacSmrg else 2778ad43ddacSmrg RADEONDPEncoderService(output, ATOM_DP_ACTION_TRAINING_COMPLETE, enc_id, 0); 2779ad43ddacSmrg 2780ad43ddacSmrg} 2781ad43ddacSmrg 2782