atombios_output.c revision 0974d292
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 68ad43ddacSmrgstatic void do_displayport_link_train(xf86OutputPtr output); 69ad43ddacSmrg 70209ff23fSmrgstatic int 71b7e1c893Smrgatombios_output_dac_setup(xf86OutputPtr output, int action) 72209ff23fSmrg{ 73209ff23fSmrg RADEONOutputPrivatePtr radeon_output = output->driver_private; 74209ff23fSmrg RADEONInfoPtr info = RADEONPTR(output->scrn); 75b7e1c893Smrg radeon_encoder_ptr radeon_encoder = radeon_get_encoder(output); 76b7e1c893Smrg radeon_tvout_ptr tvout = &radeon_output->tvout; 77209ff23fSmrg DAC_ENCODER_CONTROL_PS_ALLOCATION disp_data; 78209ff23fSmrg AtomBiosArgRec data; 79209ff23fSmrg unsigned char *space; 80b7e1c893Smrg int index = 0, num = 0; 81b7e1c893Smrg int clock = radeon_output->pixel_clock; 82b7e1c893Smrg 83b7e1c893Smrg if (radeon_encoder == NULL) 84b7e1c893Smrg return ATOM_NOT_IMPLEMENTED; 85b7e1c893Smrg 86b7e1c893Smrg memset(&disp_data,0, sizeof(disp_data)); 87b7e1c893Smrg 88b7e1c893Smrg switch (radeon_encoder->encoder_id) { 89b7e1c893Smrg case ENCODER_OBJECT_ID_INTERNAL_DAC1: 90b7e1c893Smrg case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1: 91b7e1c893Smrg index = GetIndexIntoMasterTable(COMMAND, DAC1EncoderControl); 92b7e1c893Smrg num = 1; 93b7e1c893Smrg break; 94b7e1c893Smrg case ENCODER_OBJECT_ID_INTERNAL_DAC2: 95b7e1c893Smrg case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC2: 96b7e1c893Smrg index = GetIndexIntoMasterTable(COMMAND, DAC2EncoderControl); 97b7e1c893Smrg num = 2; 98b7e1c893Smrg break; 99b7e1c893Smrg } 100209ff23fSmrg 101b7e1c893Smrg disp_data.ucAction =action; 102209ff23fSmrg 103b7e1c893Smrg if (radeon_output->active_device & (ATOM_DEVICE_CRT_SUPPORT)) 104209ff23fSmrg disp_data.ucDacStandard = ATOM_DAC1_PS2; 105b7e1c893Smrg else if (radeon_output->active_device & (ATOM_DEVICE_CV_SUPPORT)) 106209ff23fSmrg disp_data.ucDacStandard = ATOM_DAC1_CV; 107b7e1c893Smrg else { 108b7e1c893Smrg switch (tvout->tvStd) { 109209ff23fSmrg case TV_STD_PAL: 110209ff23fSmrg case TV_STD_PAL_M: 111209ff23fSmrg case TV_STD_SCART_PAL: 112209ff23fSmrg case TV_STD_SECAM: 113209ff23fSmrg case TV_STD_PAL_CN: 114209ff23fSmrg disp_data.ucDacStandard = ATOM_DAC1_PAL; 115209ff23fSmrg break; 116209ff23fSmrg case TV_STD_NTSC: 117209ff23fSmrg case TV_STD_NTSC_J: 118209ff23fSmrg case TV_STD_PAL_60: 119209ff23fSmrg default: 120b7e1c893Smrg disp_data.ucDacStandard = ATOM_DAC1_NTSC; 121209ff23fSmrg break; 122209ff23fSmrg } 123209ff23fSmrg } 124b7e1c893Smrg disp_data.usPixelClock = cpu_to_le16(clock / 10); 125209ff23fSmrg 126b7e1c893Smrg data.exec.index = index; 127209ff23fSmrg data.exec.dataSpace = (void *)&space; 128209ff23fSmrg data.exec.pspace = &disp_data; 129209ff23fSmrg 130209ff23fSmrg if (RHDAtomBiosFunc(info->atomBIOS->scrnIndex, info->atomBIOS, ATOMBIOS_EXEC, &data) == ATOM_SUCCESS) { 131b7e1c893Smrg ErrorF("Output DAC%d setup success\n", num); 132209ff23fSmrg return ATOM_SUCCESS; 133209ff23fSmrg } 134209ff23fSmrg 135b7e1c893Smrg ErrorF("Output DAC%d setup failed\n", num); 136209ff23fSmrg return ATOM_NOT_IMPLEMENTED; 137209ff23fSmrg 138209ff23fSmrg} 139209ff23fSmrg 140209ff23fSmrgstatic int 141b7e1c893Smrgatombios_output_tv_setup(xf86OutputPtr output, int action) 142209ff23fSmrg{ 143209ff23fSmrg RADEONOutputPrivatePtr radeon_output = output->driver_private; 144b7e1c893Smrg radeon_tvout_ptr tvout = &radeon_output->tvout; 145209ff23fSmrg RADEONInfoPtr info = RADEONPTR(output->scrn); 146209ff23fSmrg TV_ENCODER_CONTROL_PS_ALLOCATION disp_data; 147209ff23fSmrg AtomBiosArgRec data; 148209ff23fSmrg unsigned char *space; 149b7e1c893Smrg int clock = radeon_output->pixel_clock; 150b7e1c893Smrg 151b7e1c893Smrg memset(&disp_data,0, sizeof(disp_data)); 152209ff23fSmrg 153b7e1c893Smrg disp_data.sTVEncoder.ucAction = action; 154209ff23fSmrg 155b7e1c893Smrg if (radeon_output->active_device & (ATOM_DEVICE_CV_SUPPORT)) 156209ff23fSmrg disp_data.sTVEncoder.ucTvStandard = ATOM_TV_CV; 157209ff23fSmrg else { 158b7e1c893Smrg switch (tvout->tvStd) { 159209ff23fSmrg case TV_STD_NTSC: 160209ff23fSmrg disp_data.sTVEncoder.ucTvStandard = ATOM_TV_NTSC; 161209ff23fSmrg break; 162209ff23fSmrg case TV_STD_PAL: 163209ff23fSmrg disp_data.sTVEncoder.ucTvStandard = ATOM_TV_PAL; 164209ff23fSmrg break; 165209ff23fSmrg case TV_STD_PAL_M: 166209ff23fSmrg disp_data.sTVEncoder.ucTvStandard = ATOM_TV_PALM; 167209ff23fSmrg break; 168209ff23fSmrg case TV_STD_PAL_60: 169209ff23fSmrg disp_data.sTVEncoder.ucTvStandard = ATOM_TV_PAL60; 170209ff23fSmrg break; 171209ff23fSmrg case TV_STD_NTSC_J: 172209ff23fSmrg disp_data.sTVEncoder.ucTvStandard = ATOM_TV_NTSCJ; 173209ff23fSmrg break; 174209ff23fSmrg case TV_STD_SCART_PAL: 175209ff23fSmrg disp_data.sTVEncoder.ucTvStandard = ATOM_TV_PAL; /* ??? */ 176209ff23fSmrg break; 177209ff23fSmrg case TV_STD_SECAM: 178209ff23fSmrg disp_data.sTVEncoder.ucTvStandard = ATOM_TV_SECAM; 179209ff23fSmrg break; 180209ff23fSmrg case TV_STD_PAL_CN: 181209ff23fSmrg disp_data.sTVEncoder.ucTvStandard = ATOM_TV_PALCN; 182209ff23fSmrg break; 183209ff23fSmrg default: 184209ff23fSmrg disp_data.sTVEncoder.ucTvStandard = ATOM_TV_NTSC; 185209ff23fSmrg break; 186209ff23fSmrg } 187209ff23fSmrg } 188209ff23fSmrg 189b7e1c893Smrg disp_data.sTVEncoder.usPixelClock = cpu_to_le16(clock / 10); 190209ff23fSmrg data.exec.index = GetIndexIntoMasterTable(COMMAND, TVEncoderControl); 191209ff23fSmrg data.exec.dataSpace = (void *)&space; 192209ff23fSmrg data.exec.pspace = &disp_data; 193209ff23fSmrg 194209ff23fSmrg if (RHDAtomBiosFunc(info->atomBIOS->scrnIndex, info->atomBIOS, ATOMBIOS_EXEC, &data) == ATOM_SUCCESS) { 195b7e1c893Smrg ErrorF("Output TV setup success\n"); 196209ff23fSmrg return ATOM_SUCCESS; 197209ff23fSmrg } 198209ff23fSmrg 199b7e1c893Smrg ErrorF("Output TV setup failed\n"); 200209ff23fSmrg return ATOM_NOT_IMPLEMENTED; 201209ff23fSmrg 202209ff23fSmrg} 203209ff23fSmrg 204209ff23fSmrgint 205b7e1c893Smrgatombios_external_tmds_setup(xf86OutputPtr output, int action) 206209ff23fSmrg{ 207b7e1c893Smrg RADEONOutputPrivatePtr radeon_output = output->driver_private; 208b7e1c893Smrg ScrnInfoPtr pScrn = output->scrn; 209b7e1c893Smrg RADEONInfoPtr info = RADEONPTR(pScrn); 210209ff23fSmrg ENABLE_EXTERNAL_TMDS_ENCODER_PS_ALLOCATION disp_data; 211209ff23fSmrg AtomBiosArgRec data; 212209ff23fSmrg unsigned char *space; 213b7e1c893Smrg int clock = radeon_output->pixel_clock; 214209ff23fSmrg 215b7e1c893Smrg memset(&disp_data,0, sizeof(disp_data)); 216209ff23fSmrg 217b7e1c893Smrg disp_data.sXTmdsEncoder.ucEnable = action; 218b7e1c893Smrg 219b7e1c893Smrg if (clock > 165000) 220b7e1c893Smrg disp_data.sXTmdsEncoder.ucMisc = PANEL_ENCODER_MISC_DUAL; 221209ff23fSmrg 222b7e1c893Smrg if (pScrn->rgbBits == 8) 223209ff23fSmrg disp_data.sXTmdsEncoder.ucMisc |= (1 << 1); 224209ff23fSmrg 225209ff23fSmrg data.exec.index = GetIndexIntoMasterTable(COMMAND, DVOEncoderControl); 226209ff23fSmrg data.exec.dataSpace = (void *)&space; 227209ff23fSmrg data.exec.pspace = &disp_data; 228209ff23fSmrg 229209ff23fSmrg if (RHDAtomBiosFunc(info->atomBIOS->scrnIndex, info->atomBIOS, ATOMBIOS_EXEC, &data) == ATOM_SUCCESS) { 230209ff23fSmrg ErrorF("External TMDS setup success\n"); 231209ff23fSmrg return ATOM_SUCCESS; 232209ff23fSmrg } 233209ff23fSmrg 234209ff23fSmrg ErrorF("External TMDS setup failed\n"); 235209ff23fSmrg return ATOM_NOT_IMPLEMENTED; 236209ff23fSmrg} 237209ff23fSmrg 238209ff23fSmrgstatic int 239b7e1c893Smrgatombios_output_ddia_setup(xf86OutputPtr output, int action) 240209ff23fSmrg{ 241b7e1c893Smrg RADEONOutputPrivatePtr radeon_output = output->driver_private; 242209ff23fSmrg RADEONInfoPtr info = RADEONPTR(output->scrn); 243209ff23fSmrg DVO_ENCODER_CONTROL_PS_ALLOCATION disp_data; 244209ff23fSmrg AtomBiosArgRec data; 245209ff23fSmrg unsigned char *space; 246b7e1c893Smrg int clock = radeon_output->pixel_clock; 247b7e1c893Smrg 248b7e1c893Smrg memset(&disp_data,0, sizeof(disp_data)); 249209ff23fSmrg 250b7e1c893Smrg disp_data.sDVOEncoder.ucAction = action; 251b7e1c893Smrg disp_data.sDVOEncoder.usPixelClock = cpu_to_le16(clock / 10); 252209ff23fSmrg 253b7e1c893Smrg if (clock > 165000) 254209ff23fSmrg disp_data.sDVOEncoder.usDevAttr.sDigAttrib.ucAttribute = PANEL_ENCODER_MISC_DUAL; 255209ff23fSmrg 256209ff23fSmrg data.exec.index = GetIndexIntoMasterTable(COMMAND, DVOEncoderControl); 257209ff23fSmrg data.exec.dataSpace = (void *)&space; 258209ff23fSmrg data.exec.pspace = &disp_data; 259209ff23fSmrg 260209ff23fSmrg if (RHDAtomBiosFunc(info->atomBIOS->scrnIndex, info->atomBIOS, ATOMBIOS_EXEC, &data) == ATOM_SUCCESS) { 261209ff23fSmrg ErrorF("DDIA setup success\n"); 262209ff23fSmrg return ATOM_SUCCESS; 263209ff23fSmrg } 264209ff23fSmrg 265209ff23fSmrg ErrorF("DDIA setup failed\n"); 266209ff23fSmrg return ATOM_NOT_IMPLEMENTED; 267209ff23fSmrg} 268209ff23fSmrg 269209ff23fSmrgstatic int 270b7e1c893Smrgatombios_output_digital_setup(xf86OutputPtr output, int action) 271209ff23fSmrg{ 272b7e1c893Smrg RADEONOutputPrivatePtr radeon_output = output->driver_private; 273b7e1c893Smrg ScrnInfoPtr pScrn = output->scrn; 274b7e1c893Smrg RADEONInfoPtr info = RADEONPTR(pScrn); 275b7e1c893Smrg radeon_encoder_ptr radeon_encoder = radeon_get_encoder(output); 276b7e1c893Smrg LVDS_ENCODER_CONTROL_PS_ALLOCATION disp_data; 277b7e1c893Smrg LVDS_ENCODER_CONTROL_PS_ALLOCATION_V2 disp_data2; 278209ff23fSmrg AtomBiosArgRec data; 279209ff23fSmrg unsigned char *space; 280b7e1c893Smrg int index = 0; 281b7e1c893Smrg int major, minor; 282b7e1c893Smrg int lvds_misc = 0; 283b7e1c893Smrg int clock = radeon_output->pixel_clock; 284209ff23fSmrg 285b7e1c893Smrg if (radeon_encoder == NULL) 286b7e1c893Smrg return ATOM_NOT_IMPLEMENTED; 287b7e1c893Smrg 288b7e1c893Smrg if (radeon_output->active_device & (ATOM_DEVICE_LCD_SUPPORT)) { 289b7e1c893Smrg radeon_lvds_ptr lvds = (radeon_lvds_ptr)radeon_encoder->dev_priv; 290b7e1c893Smrg if (lvds == NULL) 291b7e1c893Smrg return ATOM_NOT_IMPLEMENTED; 292b7e1c893Smrg lvds_misc = lvds->lvds_misc; 293b7e1c893Smrg } 294b7e1c893Smrg 295b7e1c893Smrg memset(&disp_data,0, sizeof(disp_data)); 296b7e1c893Smrg memset(&disp_data2,0, sizeof(disp_data2)); 297b7e1c893Smrg 298b7e1c893Smrg switch (radeon_encoder->encoder_id) { 299b7e1c893Smrg case ENCODER_OBJECT_ID_INTERNAL_LVDS: 300b7e1c893Smrg index = GetIndexIntoMasterTable(COMMAND, LVDSEncoderControl); 301b7e1c893Smrg break; 302b7e1c893Smrg case ENCODER_OBJECT_ID_INTERNAL_TMDS1: 303b7e1c893Smrg case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1: 304b7e1c893Smrg index = GetIndexIntoMasterTable(COMMAND, TMDS1EncoderControl); 305b7e1c893Smrg break; 306b7e1c893Smrg case ENCODER_OBJECT_ID_INTERNAL_LVTM1: 307b7e1c893Smrg case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA: 308b7e1c893Smrg if (radeon_output->active_device & (ATOM_DEVICE_LCD_SUPPORT)) 309b7e1c893Smrg index = GetIndexIntoMasterTable(COMMAND, LVDSEncoderControl); 310b7e1c893Smrg else 311b7e1c893Smrg index = GetIndexIntoMasterTable(COMMAND, TMDS2EncoderControl); 312b7e1c893Smrg break; 313b7e1c893Smrg } 314b7e1c893Smrg 315b7e1c893Smrg atombios_get_command_table_version(info->atomBIOS, index, &major, &minor); 316b7e1c893Smrg 317b7e1c893Smrg /*ErrorF("table is %d %d\n", major, minor);*/ 318b7e1c893Smrg switch (major) { 319b7e1c893Smrg case 0: 320b7e1c893Smrg case 1: 321b7e1c893Smrg case 2: 322b7e1c893Smrg switch (minor) { 323b7e1c893Smrg case 1: 324b7e1c893Smrg disp_data.ucMisc = 0; 325b7e1c893Smrg disp_data.ucAction = action; 326b7e1c893Smrg if ((radeon_output->ConnectorType == CONNECTOR_HDMI_TYPE_A) || 327b7e1c893Smrg (radeon_output->ConnectorType == CONNECTOR_HDMI_TYPE_B)) 328b7e1c893Smrg disp_data.ucMisc |= PANEL_ENCODER_MISC_HDMI_TYPE; 329b7e1c893Smrg disp_data.usPixelClock = cpu_to_le16(clock / 10); 330b7e1c893Smrg if (radeon_output->active_device & (ATOM_DEVICE_LCD_SUPPORT)) { 331b7e1c893Smrg if (lvds_misc & (1 << 0)) 332b7e1c893Smrg disp_data.ucMisc |= PANEL_ENCODER_MISC_DUAL; 333b7e1c893Smrg if (lvds_misc & (1 << 1)) 334b7e1c893Smrg disp_data.ucMisc |= (1 << 1); 335b7e1c893Smrg } else { 336b7e1c893Smrg if (radeon_output->linkb) 337b7e1c893Smrg disp_data.ucMisc |= PANEL_ENCODER_MISC_TMDS_LINKB; 338b7e1c893Smrg if (clock > 165000) 339b7e1c893Smrg disp_data.ucMisc |= PANEL_ENCODER_MISC_DUAL; 340b7e1c893Smrg if (pScrn->rgbBits == 8) 341b7e1c893Smrg disp_data.ucMisc |= (1 << 1); 342b7e1c893Smrg } 343b7e1c893Smrg data.exec.pspace = &disp_data; 344b7e1c893Smrg break; 345b7e1c893Smrg case 2: 346b7e1c893Smrg case 3: 347b7e1c893Smrg disp_data2.ucMisc = 0; 348b7e1c893Smrg disp_data2.ucAction = action; 349b7e1c893Smrg if (minor == 3) { 350b7e1c893Smrg if (radeon_output->coherent_mode) { 351b7e1c893Smrg disp_data2.ucMisc |= PANEL_ENCODER_MISC_COHERENT; 352b7e1c893Smrg xf86DrvMsg(output->scrn->scrnIndex, X_INFO, "Coherent Mode enabled\n"); 353b7e1c893Smrg } 354b7e1c893Smrg } 355b7e1c893Smrg if ((radeon_output->ConnectorType == CONNECTOR_HDMI_TYPE_A) || 356b7e1c893Smrg (radeon_output->ConnectorType == CONNECTOR_HDMI_TYPE_B)) 357b7e1c893Smrg disp_data2.ucMisc |= PANEL_ENCODER_MISC_HDMI_TYPE; 358b7e1c893Smrg disp_data2.usPixelClock = cpu_to_le16(clock / 10); 359b7e1c893Smrg disp_data2.ucTruncate = 0; 360b7e1c893Smrg disp_data2.ucSpatial = 0; 361b7e1c893Smrg disp_data2.ucTemporal = 0; 362b7e1c893Smrg disp_data2.ucFRC = 0; 363b7e1c893Smrg if (radeon_output->active_device & (ATOM_DEVICE_LCD_SUPPORT)) { 364b7e1c893Smrg if (lvds_misc & (1 << 0)) 365b7e1c893Smrg disp_data2.ucMisc |= PANEL_ENCODER_MISC_DUAL; 366b7e1c893Smrg if (lvds_misc & (1 << 5)) { 367b7e1c893Smrg disp_data2.ucSpatial = PANEL_ENCODER_SPATIAL_DITHER_EN; 368b7e1c893Smrg if (lvds_misc & (1 << 1)) 369b7e1c893Smrg disp_data2.ucSpatial |= PANEL_ENCODER_SPATIAL_DITHER_DEPTH; 370b7e1c893Smrg } 371b7e1c893Smrg if (lvds_misc & (1 << 6)) { 372b7e1c893Smrg disp_data2.ucTemporal = PANEL_ENCODER_TEMPORAL_DITHER_EN; 373b7e1c893Smrg if (lvds_misc & (1 << 1)) 374b7e1c893Smrg disp_data2.ucTemporal |= PANEL_ENCODER_TEMPORAL_DITHER_DEPTH; 375b7e1c893Smrg if (((lvds_misc >> 2) & 0x3) == 2) 376b7e1c893Smrg disp_data2.ucTemporal |= PANEL_ENCODER_TEMPORAL_LEVEL_4; 377b7e1c893Smrg } 378b7e1c893Smrg } else { 379b7e1c893Smrg if (radeon_output->linkb) 380b7e1c893Smrg disp_data2.ucMisc |= PANEL_ENCODER_MISC_TMDS_LINKB; 381b7e1c893Smrg if (clock > 165000) 382b7e1c893Smrg disp_data2.ucMisc |= PANEL_ENCODER_MISC_DUAL; 383b7e1c893Smrg } 384b7e1c893Smrg data.exec.pspace = &disp_data2; 385b7e1c893Smrg break; 386b7e1c893Smrg default: 387b7e1c893Smrg ErrorF("Unknown table version\n"); 388b7e1c893Smrg exit(-1); 389b7e1c893Smrg } 390b7e1c893Smrg break; 391b7e1c893Smrg default: 392b7e1c893Smrg ErrorF("Unknown table version\n"); 393b7e1c893Smrg exit(-1); 394b7e1c893Smrg } 395b7e1c893Smrg 396b7e1c893Smrg data.exec.index = index; 397209ff23fSmrg data.exec.dataSpace = (void *)&space; 398209ff23fSmrg 399209ff23fSmrg if (RHDAtomBiosFunc(info->atomBIOS->scrnIndex, info->atomBIOS, ATOMBIOS_EXEC, &data) == ATOM_SUCCESS) { 400b7e1c893Smrg ErrorF("Output digital setup success\n"); 401209ff23fSmrg return ATOM_SUCCESS; 402209ff23fSmrg } 403209ff23fSmrg 404b7e1c893Smrg ErrorF("Output digital setup failed\n"); 405209ff23fSmrg return ATOM_NOT_IMPLEMENTED; 406209ff23fSmrg} 407209ff23fSmrg 408209ff23fSmrgstatic int 409b7e1c893Smrgatombios_maybe_hdmi_mode(xf86OutputPtr output) 410209ff23fSmrg{ 411b7e1c893Smrg#ifndef EDID_COMPLETE_RAWDATA 412b7e1c893Smrg /* there's no getting this right unless we have complete EDID */ 413b7e1c893Smrg return ATOM_ENCODER_MODE_HDMI; 414b7e1c893Smrg#else 415b7e1c893Smrg if (output && xf86MonitorIsHDMI(output->MonInfo)) 416b7e1c893Smrg return ATOM_ENCODER_MODE_HDMI; 417b7e1c893Smrg 418b7e1c893Smrg return ATOM_ENCODER_MODE_DVI; 419b7e1c893Smrg#endif 420b7e1c893Smrg} 421209ff23fSmrg 422b7e1c893Smrgint 423b7e1c893Smrgatombios_get_encoder_mode(xf86OutputPtr output) 424b7e1c893Smrg{ 4250974d292Smrg ScrnInfoPtr pScrn = output->scrn; 4260974d292Smrg RADEONInfoPtr info = RADEONPTR(pScrn); 427b7e1c893Smrg RADEONOutputPrivatePtr radeon_output = output->driver_private; 428209ff23fSmrg 429b7e1c893Smrg /* DVI should really be atombios_maybe_hdmi_mode() as well */ 430b7e1c893Smrg switch (radeon_output->ConnectorType) { 431b7e1c893Smrg case CONNECTOR_DVI_I: 432b7e1c893Smrg if (radeon_output->active_device & (ATOM_DEVICE_DFP_SUPPORT)) 433b7e1c893Smrg return ATOM_ENCODER_MODE_DVI; 434b7e1c893Smrg else 435b7e1c893Smrg return ATOM_ENCODER_MODE_CRT; 436b7e1c893Smrg break; 437b7e1c893Smrg case CONNECTOR_DVI_D: 438b7e1c893Smrg default: 439b7e1c893Smrg return ATOM_ENCODER_MODE_DVI; 440b7e1c893Smrg break; 441b7e1c893Smrg case CONNECTOR_HDMI_TYPE_A: 442b7e1c893Smrg case CONNECTOR_HDMI_TYPE_B: 4430974d292Smrg if (IS_DCE4_VARIANT) 4440974d292Smrg return ATOM_ENCODER_MODE_DVI; 4450974d292Smrg else 4460974d292Smrg return atombios_maybe_hdmi_mode(output); 447b7e1c893Smrg break; 448b7e1c893Smrg case CONNECTOR_LVDS: 449b7e1c893Smrg return ATOM_ENCODER_MODE_LVDS; 450b7e1c893Smrg break; 451b7e1c893Smrg case CONNECTOR_DISPLAY_PORT: 452ad43ddacSmrg case CONNECTOR_EDP: 453b7e1c893Smrg if (radeon_output->MonType == MT_DP) 454b7e1c893Smrg return ATOM_ENCODER_MODE_DP; 4550974d292Smrg else { 4560974d292Smrg if (IS_DCE4_VARIANT) 4570974d292Smrg return ATOM_ENCODER_MODE_DVI; 4580974d292Smrg else 4590974d292Smrg return atombios_maybe_hdmi_mode(output); 4600974d292Smrg } 461b7e1c893Smrg break; 462b7e1c893Smrg case CONNECTOR_DVI_A: 463b7e1c893Smrg case CONNECTOR_VGA: 464b7e1c893Smrg case CONNECTOR_STV: 465b7e1c893Smrg case CONNECTOR_CTV: 466b7e1c893Smrg case CONNECTOR_DIN: 467b7e1c893Smrg if (radeon_output->active_device & (ATOM_DEVICE_TV_SUPPORT)) 468b7e1c893Smrg return ATOM_ENCODER_MODE_TV; 469b7e1c893Smrg else if (radeon_output->active_device & (ATOM_DEVICE_CV_SUPPORT)) 470b7e1c893Smrg return ATOM_ENCODER_MODE_CV; 471b7e1c893Smrg else 472b7e1c893Smrg return ATOM_ENCODER_MODE_CRT; 473b7e1c893Smrg break; 474209ff23fSmrg } 475209ff23fSmrg 476209ff23fSmrg} 477209ff23fSmrg 478b7e1c893Smrgstatic const int dp_clocks[] = { 479ad43ddacSmrg 5400, // 1 lane, 1.62 Ghz 480ad43ddacSmrg 9000, // 1 lane, 2.70 Ghz 481ad43ddacSmrg 10800, // 2 lane, 1.62 Ghz 482ad43ddacSmrg 18000, // 2 lane, 2.70 Ghz 483ad43ddacSmrg 21600, // 4 lane, 1.62 Ghz 484ad43ddacSmrg 36000, // 4 lane, 2.70 Ghz 485b7e1c893Smrg}; 486b7e1c893Smrgstatic const int num_dp_clocks = sizeof(dp_clocks) / sizeof(int); 487b7e1c893Smrg 488ad43ddacSmrg# define DP_LINK_BW_1_62 0x06 489ad43ddacSmrg# define DP_LINK_BW_2_7 0x0a 490ad43ddacSmrg 491209ff23fSmrgstatic int 492ad43ddacSmrgdp_lanes_for_mode_clock(RADEONOutputPrivatePtr radeon_output, 493ad43ddacSmrg int mode_clock) 494209ff23fSmrg{ 495b7e1c893Smrg int i; 496ad43ddacSmrg int max_link_bw = radeon_output->dpcd[1]; 497ad43ddacSmrg 498ad43ddacSmrg switch (max_link_bw) { 499ad43ddacSmrg case DP_LINK_BW_1_62: 500ad43ddacSmrg default: 501ad43ddacSmrg for (i = 0; i < num_dp_clocks; i++) { 502ad43ddacSmrg if (i % 2) 503ad43ddacSmrg continue; 504ad43ddacSmrg if (dp_clocks[i] > (mode_clock / 10)) { 505ad43ddacSmrg if (i < 2) 506ad43ddacSmrg return 1; 507ad43ddacSmrg else if (i < 4) 508ad43ddacSmrg return 2; 509ad43ddacSmrg else 510ad43ddacSmrg return 4; 511ad43ddacSmrg } 512ad43ddacSmrg } 513ad43ddacSmrg break; 514ad43ddacSmrg case DP_LINK_BW_2_7: 515ad43ddacSmrg for (i = 0; i < num_dp_clocks; i++) { 516ad43ddacSmrg if (dp_clocks[i] > (mode_clock / 10)) { 517ad43ddacSmrg if (i < 2) 518ad43ddacSmrg return 1; 519ad43ddacSmrg else if (i < 4) 520ad43ddacSmrg return 2; 521ad43ddacSmrg else 522ad43ddacSmrg return 4; 523ad43ddacSmrg } 524ad43ddacSmrg } 525ad43ddacSmrg break; 526ad43ddacSmrg } 527209ff23fSmrg 528b7e1c893Smrg return 0; 529b7e1c893Smrg} 530209ff23fSmrg 531b7e1c893Smrgstatic int 532ad43ddacSmrgdp_link_clock_for_mode_clock(RADEONOutputPrivatePtr radeon_output, 533ad43ddacSmrg int mode_clock) 534b7e1c893Smrg{ 535b7e1c893Smrg int i; 536ad43ddacSmrg int max_link_bw = radeon_output->dpcd[1]; 537209ff23fSmrg 538ad43ddacSmrg switch (max_link_bw) { 539ad43ddacSmrg case DP_LINK_BW_1_62: 540ad43ddacSmrg default: 541ad43ddacSmrg return 16200; 542ad43ddacSmrg break; 543ad43ddacSmrg case DP_LINK_BW_2_7: 544ad43ddacSmrg for (i = 0; i < num_dp_clocks; i++) 545ad43ddacSmrg if (dp_clocks[i] > (mode_clock / 10)) 546ad43ddacSmrg return (i % 2) ? 27000 : 16200; 547ad43ddacSmrg break; 548ad43ddacSmrg } 549b7e1c893Smrg 550b7e1c893Smrg return 0; 551209ff23fSmrg} 552209ff23fSmrg 553ad43ddacSmrg/* 554ad43ddacSmrg * DIG Encoder/Transmitter Setup 555ad43ddacSmrg * 556ad43ddacSmrg * DCE 3.0/3.1 557ad43ddacSmrg * - 2 DIG transmitter blocks. UNIPHY (links A and B) and LVTMA. 558ad43ddacSmrg * Supports up to 3 digital outputs 559ad43ddacSmrg * - 2 DIG encoder blocks. 560ad43ddacSmrg * DIG1 can drive UNIPHY link A or link B 561ad43ddacSmrg * DIG2 can drive UNIPHY link B or LVTMA 562ad43ddacSmrg * 563ad43ddacSmrg * DCE 3.2 564ad43ddacSmrg * - 3 DIG transmitter blocks. UNIPHY0/1/2 (links A and B). 565ad43ddacSmrg * Supports up to 5 digital outputs 566ad43ddacSmrg * - 2 DIG encoder blocks. 567ad43ddacSmrg * DIG1/2 can drive UNIPHY0/1/2 link A or link B 568ad43ddacSmrg * 5690974d292Smrg * DCE 4.0 5700974d292Smrg * - 3 DIG transmitter blocks UNPHY0/1/2 (links A and B). 5710974d292Smrg * Supports up to 6 digital outputs 5720974d292Smrg * - 6 DIG encoder blocks. 5730974d292Smrg * - DIG to PHY mapping is hardcoded 5740974d292Smrg * DIG1 drives UNIPHY0 link A, A+B 5750974d292Smrg * DIG2 drives UNIPHY0 link B 5760974d292Smrg * DIG3 drives UNIPHY1 link A, A+B 5770974d292Smrg * DIG4 drives UNIPHY1 link B 5780974d292Smrg * DIG5 drives UNIPHY2 link A, A+B 5790974d292Smrg * DIG6 drives UNIPHY2 link B 5800974d292Smrg * 581ad43ddacSmrg * Routing 582ad43ddacSmrg * crtc -> dig encoder -> UNIPHY/LVTMA (1 or 2 links) 583ad43ddacSmrg * Examples: 584ad43ddacSmrg * crtc0 -> dig2 -> LVTMA links A+B 585ad43ddacSmrg * crtc1 -> dig1 -> UNIPHY0 link B 5860974d292Smrg * crtc0 -> dig1 -> UNIPHY2 link A -> LVDS 5870974d292Smrg * crtc1 -> dig2 -> UNIPHY1 link B+A -> TMDS/HDMI 588ad43ddacSmrg */ 5890974d292Smrg 5900974d292Smrgunion dig_encoder_control { 5910974d292Smrg DIG_ENCODER_CONTROL_PS_ALLOCATION v1; 5920974d292Smrg DIG_ENCODER_CONTROL_PARAMETERS_V2 v2; 5930974d292Smrg DIG_ENCODER_CONTROL_PARAMETERS_V3 v3; 5940974d292Smrg}; 5950974d292Smrg 596209ff23fSmrgstatic int 597b7e1c893Smrgatombios_output_dig_encoder_setup(xf86OutputPtr output, int action) 598209ff23fSmrg{ 599209ff23fSmrg RADEONOutputPrivatePtr radeon_output = output->driver_private; 600209ff23fSmrg RADEONInfoPtr info = RADEONPTR(output->scrn); 601b7e1c893Smrg radeon_encoder_ptr radeon_encoder = radeon_get_encoder(output); 6020974d292Smrg union dig_encoder_control disp_data; 603209ff23fSmrg AtomBiosArgRec data; 604209ff23fSmrg unsigned char *space; 605ad43ddacSmrg int index = 0, major, minor; 606b7e1c893Smrg int clock = radeon_output->pixel_clock; 607b7e1c893Smrg 608b7e1c893Smrg if (radeon_encoder == NULL) 609b7e1c893Smrg return ATOM_NOT_IMPLEMENTED; 610b7e1c893Smrg 611b7e1c893Smrg memset(&disp_data,0, sizeof(disp_data)); 612b7e1c893Smrg 6130974d292Smrg if (IS_DCE4_VARIANT) 6140974d292Smrg index = GetIndexIntoMasterTable(COMMAND, DIGxEncoderControl); 6150974d292Smrg else if (radeon_output->dig_encoder) 616ad43ddacSmrg index = GetIndexIntoMasterTable(COMMAND, DIG2EncoderControl); 617ad43ddacSmrg else 618ad43ddacSmrg index = GetIndexIntoMasterTable(COMMAND, DIG1EncoderControl); 619209ff23fSmrg 620b7e1c893Smrg atombios_get_command_table_version(info->atomBIOS, index, &major, &minor); 621b7e1c893Smrg 6220974d292Smrg disp_data.v1.ucAction = action; 6230974d292Smrg disp_data.v1.usPixelClock = cpu_to_le16(clock / 10); 6240974d292Smrg disp_data.v1.ucEncoderMode = atombios_get_encoder_mode(output); 625b7e1c893Smrg 6260974d292Smrg if (disp_data.v1.ucEncoderMode == ATOM_ENCODER_MODE_DP) { 6270974d292Smrg if (dp_link_clock_for_mode_clock(radeon_output, clock) == 27000) 6280974d292Smrg disp_data.v1.ucConfig |= ATOM_ENCODER_CONFIG_DPLINKRATE_2_70GHZ; 6290974d292Smrg disp_data.v1.ucLaneNum = dp_lanes_for_mode_clock(radeon_output, clock); 6300974d292Smrg } else if (clock > 165000) 6310974d292Smrg disp_data.v1.ucLaneNum = 8; 6320974d292Smrg else 6330974d292Smrg disp_data.v1.ucLaneNum = 4; 6340974d292Smrg 6350974d292Smrg if (IS_DCE4_VARIANT) { 6360974d292Smrg disp_data.v3.acConfig.ucDigSel = radeon_output->dig_encoder; 6370974d292Smrg disp_data.v3.ucBitPerColor = PANEL_8BIT_PER_COLOR; 6380974d292Smrg } else { 639b7e1c893Smrg switch (radeon_encoder->encoder_id) { 640b7e1c893Smrg case ENCODER_OBJECT_ID_INTERNAL_UNIPHY: 6410974d292Smrg disp_data.v1.ucConfig = ATOM_ENCODER_CONFIG_V2_TRANSMITTER1; 642b7e1c893Smrg break; 643b7e1c893Smrg case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1: 6440974d292Smrg disp_data.v1.ucConfig = ATOM_ENCODER_CONFIG_V2_TRANSMITTER2; 645b7e1c893Smrg break; 646b7e1c893Smrg case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2: 6470974d292Smrg disp_data.v1.ucConfig = ATOM_ENCODER_CONFIG_V2_TRANSMITTER3; 648b7e1c893Smrg break; 649b7e1c893Smrg } 6500974d292Smrg if (radeon_output->linkb) 6510974d292Smrg disp_data.v1.ucConfig |= ATOM_ENCODER_CONFIG_LINKB; 6520974d292Smrg else 6530974d292Smrg disp_data.v1.ucConfig |= ATOM_ENCODER_CONFIG_LINKA; 654209ff23fSmrg } 655209ff23fSmrg 656b7e1c893Smrg data.exec.index = index; 657209ff23fSmrg data.exec.dataSpace = (void *)&space; 658209ff23fSmrg data.exec.pspace = &disp_data; 659209ff23fSmrg 660209ff23fSmrg if (RHDAtomBiosFunc(info->atomBIOS->scrnIndex, info->atomBIOS, ATOMBIOS_EXEC, &data) == ATOM_SUCCESS) { 661ad43ddacSmrg ErrorF("Output DIG%d encoder setup success\n", radeon_output->dig_encoder); 662209ff23fSmrg return ATOM_SUCCESS; 663209ff23fSmrg } 664209ff23fSmrg 665ad43ddacSmrg ErrorF("Output DIG%d setup failed\n", radeon_output->dig_encoder); 666209ff23fSmrg return ATOM_NOT_IMPLEMENTED; 667209ff23fSmrg 668209ff23fSmrg} 669209ff23fSmrg 670b7e1c893Smrgunion dig_transmitter_control { 671b7e1c893Smrg DIG_TRANSMITTER_CONTROL_PS_ALLOCATION v1; 672b7e1c893Smrg DIG_TRANSMITTER_CONTROL_PARAMETERS_V2 v2; 673ad43ddacSmrg DIG_TRANSMITTER_CONTROL_PARAMETERS_V3 v3; 674b7e1c893Smrg}; 675b7e1c893Smrg 676209ff23fSmrgstatic int 677ad43ddacSmrgatombios_output_dig_transmitter_setup(xf86OutputPtr output, int action, uint8_t lane_num, uint8_t lane_set) 678209ff23fSmrg{ 679209ff23fSmrg RADEONOutputPrivatePtr radeon_output = output->driver_private; 680209ff23fSmrg RADEONInfoPtr info = RADEONPTR(output->scrn); 681b7e1c893Smrg radeon_encoder_ptr radeon_encoder = radeon_get_encoder(output); 682b7e1c893Smrg union dig_transmitter_control disp_data; 683209ff23fSmrg AtomBiosArgRec data; 684209ff23fSmrg unsigned char *space; 685b7e1c893Smrg int index = 0, num = 0; 686b7e1c893Smrg int major, minor; 687b7e1c893Smrg int clock = radeon_output->pixel_clock; 688b7e1c893Smrg 689b7e1c893Smrg if (radeon_encoder == NULL) 690b7e1c893Smrg return ATOM_NOT_IMPLEMENTED; 691b7e1c893Smrg 692b7e1c893Smrg memset(&disp_data,0, sizeof(disp_data)); 693b7e1c893Smrg 694ad43ddacSmrg if (IS_DCE32_VARIANT || IS_DCE4_VARIANT) 695b7e1c893Smrg index = GetIndexIntoMasterTable(COMMAND, UNIPHYTransmitterControl); 696b7e1c893Smrg else { 697b7e1c893Smrg switch (radeon_encoder->encoder_id) { 698b7e1c893Smrg case ENCODER_OBJECT_ID_INTERNAL_UNIPHY: 699b7e1c893Smrg index = GetIndexIntoMasterTable(COMMAND, DIG1TransmitterControl); 700b7e1c893Smrg break; 701b7e1c893Smrg case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA: 702b7e1c893Smrg index = GetIndexIntoMasterTable(COMMAND, DIG2TransmitterControl); 703b7e1c893Smrg break; 704b7e1c893Smrg } 705b7e1c893Smrg } 706209ff23fSmrg 707b7e1c893Smrg atombios_get_command_table_version(info->atomBIOS, index, &major, &minor); 708b7e1c893Smrg 709b7e1c893Smrg disp_data.v1.ucAction = action; 7100974d292Smrg if (action == ATOM_TRANSMITTER_ACTION_INIT) { 7110974d292Smrg disp_data.v1.usInitInfo = radeon_output->connector_object_id; 7120974d292Smrg } else if (action == ATOM_TRANSMITTER_ACTION_SETUP_VSEMPH) { 7130974d292Smrg disp_data.v1.asMode.ucLaneSel = lane_num; 7140974d292Smrg disp_data.v1.asMode.ucLaneSet = lane_set; 7150974d292Smrg } else { 7160974d292Smrg if (radeon_output->MonType == MT_DP) 7170974d292Smrg disp_data.v1.usPixelClock = 7180974d292Smrg cpu_to_le16(dp_link_clock_for_mode_clock(radeon_output, clock)); 7190974d292Smrg else if (clock > 165000) 7200974d292Smrg disp_data.v1.usPixelClock = cpu_to_le16((clock / 2) / 10); 7210974d292Smrg else 7220974d292Smrg disp_data.v1.usPixelClock = cpu_to_le16(clock / 10); 7230974d292Smrg } 724b7e1c893Smrg 725ad43ddacSmrg if (IS_DCE4_VARIANT) { 726ad43ddacSmrg if (radeon_output->MonType == MT_DP) 727ad43ddacSmrg disp_data.v3.ucLaneNum = dp_lanes_for_mode_clock(radeon_output, clock); 728ad43ddacSmrg else if (clock > 165000) 729ad43ddacSmrg disp_data.v3.ucLaneNum = 8; 730ad43ddacSmrg else 731ad43ddacSmrg disp_data.v3.ucLaneNum = 4; 732ad43ddacSmrg 733ad43ddacSmrg if (radeon_output->linkb) { 734ad43ddacSmrg disp_data.v3.acConfig.ucLinkSel = 1; 735b7e1c893Smrg disp_data.v2.acConfig.ucEncoderSel = 1; 736ad43ddacSmrg } 737ad43ddacSmrg 738ad43ddacSmrg // select the PLL for the UNIPHY 7390974d292Smrg if (radeon_output->MonType == MT_DP && info->dp_extclk) 740ad43ddacSmrg disp_data.v3.acConfig.ucRefClkSource = 2; /* ext clk */ 741ad43ddacSmrg else 742ad43ddacSmrg disp_data.v3.acConfig.ucRefClkSource = radeon_output->pll_id; 743ad43ddacSmrg 744ad43ddacSmrg switch (radeon_encoder->encoder_id) { 745ad43ddacSmrg case ENCODER_OBJECT_ID_INTERNAL_UNIPHY: 746ad43ddacSmrg disp_data.v3.acConfig.ucTransmitterSel = 0; 747ad43ddacSmrg num = 0; 748ad43ddacSmrg break; 749ad43ddacSmrg case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1: 750ad43ddacSmrg disp_data.v3.acConfig.ucTransmitterSel = 1; 751ad43ddacSmrg num = 1; 752ad43ddacSmrg break; 753ad43ddacSmrg case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2: 754ad43ddacSmrg disp_data.v3.acConfig.ucTransmitterSel = 2; 755ad43ddacSmrg num = 2; 756ad43ddacSmrg break; 757ad43ddacSmrg } 758ad43ddacSmrg 759ad43ddacSmrg if (radeon_output->MonType == MT_DP) 760ad43ddacSmrg disp_data.v3.acConfig.fCoherentMode = 1; /* DP requires coherent */ 761ad43ddacSmrg else if (radeon_output->active_device & (ATOM_DEVICE_DFP_SUPPORT)) { 762ad43ddacSmrg if (radeon_output->coherent_mode) 763ad43ddacSmrg disp_data.v3.acConfig.fCoherentMode = 1; 7640974d292Smrg if (clock > 165000) 7650974d292Smrg disp_data.v3.acConfig.fDualLinkConnector = 1; 766ad43ddacSmrg } 767ad43ddacSmrg } else if (IS_DCE32_VARIANT) { 768ad43ddacSmrg if (radeon_output->dig_encoder) 769ad43ddacSmrg disp_data.v2.acConfig.ucEncoderSel = 1; 770ad43ddacSmrg 771ad43ddacSmrg if (radeon_output->linkb) 772ad43ddacSmrg disp_data.v2.acConfig.ucLinkSel = 1; 773b7e1c893Smrg 774b7e1c893Smrg switch (radeon_encoder->encoder_id) { 775b7e1c893Smrg case ENCODER_OBJECT_ID_INTERNAL_UNIPHY: 776b7e1c893Smrg disp_data.v2.acConfig.ucTransmitterSel = 0; 777b7e1c893Smrg num = 0; 778b7e1c893Smrg break; 779b7e1c893Smrg case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1: 780b7e1c893Smrg disp_data.v2.acConfig.ucTransmitterSel = 1; 781b7e1c893Smrg num = 1; 782b7e1c893Smrg break; 783b7e1c893Smrg case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2: 784b7e1c893Smrg disp_data.v2.acConfig.ucTransmitterSel = 2; 785b7e1c893Smrg num = 2; 786b7e1c893Smrg break; 787b7e1c893Smrg } 788b7e1c893Smrg 789ad43ddacSmrg if (radeon_output->MonType == MT_DP) 790ad43ddacSmrg disp_data.v2.acConfig.fCoherentMode = 1; /* DP requires coherent */ 791ad43ddacSmrg else if (radeon_output->active_device & (ATOM_DEVICE_DFP_SUPPORT)) { 792ad43ddacSmrg if (radeon_output->coherent_mode) 793b7e1c893Smrg disp_data.v2.acConfig.fCoherentMode = 1; 794209ff23fSmrg } 795209ff23fSmrg } else { 796b7e1c893Smrg disp_data.v1.ucConfig = ATOM_TRANSMITTER_CONFIG_CLKSRC_PPLL; 797b7e1c893Smrg 798ad43ddacSmrg if (radeon_output->dig_encoder) 799ad43ddacSmrg disp_data.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_DIG2_ENCODER; 800209ff23fSmrg else 801ad43ddacSmrg disp_data.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_DIG1_ENCODER; 802b7e1c893Smrg 803b7e1c893Smrg switch (radeon_encoder->encoder_id) { 804b7e1c893Smrg case ENCODER_OBJECT_ID_INTERNAL_UNIPHY: 805b7e1c893Smrg if (info->IsIGP) { 806b7e1c893Smrg if (clock > 165000) { 807b7e1c893Smrg if (radeon_output->igp_lane_info & 0x3) 808b7e1c893Smrg disp_data.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LANE_0_7; 809b7e1c893Smrg else if (radeon_output->igp_lane_info & 0xc) 810b7e1c893Smrg disp_data.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LANE_8_15; 811b7e1c893Smrg } else { 812b7e1c893Smrg if (radeon_output->igp_lane_info & 0x1) 813b7e1c893Smrg disp_data.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LANE_0_3; 814b7e1c893Smrg else if (radeon_output->igp_lane_info & 0x2) 815b7e1c893Smrg disp_data.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LANE_4_7; 816b7e1c893Smrg else if (radeon_output->igp_lane_info & 0x4) 817b7e1c893Smrg disp_data.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LANE_8_11; 818b7e1c893Smrg else if (radeon_output->igp_lane_info & 0x8) 819b7e1c893Smrg disp_data.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LANE_12_15; 820b7e1c893Smrg } 821b7e1c893Smrg } 822b7e1c893Smrg break; 823b7e1c893Smrg } 824ad43ddacSmrg if (radeon_output->linkb) 825ad43ddacSmrg disp_data.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LINKB; 826ad43ddacSmrg else 827ad43ddacSmrg disp_data.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LINKA; 828209ff23fSmrg 829ad43ddacSmrg if (radeon_output->MonType == MT_DP) 830ad43ddacSmrg disp_data.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_COHERENT; /* DP requires coherent */ 831ad43ddacSmrg else if (radeon_output->active_device & (ATOM_DEVICE_DFP_SUPPORT)) { 832ad43ddacSmrg if (radeon_output->coherent_mode) 833b7e1c893Smrg disp_data.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_COHERENT; 8340974d292Smrg if (clock > 165000) 8350974d292Smrg disp_data.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_8LANE_LINK; 836b7e1c893Smrg } 837b7e1c893Smrg } 838209ff23fSmrg 839b7e1c893Smrg data.exec.index = index; 840209ff23fSmrg data.exec.dataSpace = (void *)&space; 841209ff23fSmrg data.exec.pspace = &disp_data; 842209ff23fSmrg 843209ff23fSmrg if (RHDAtomBiosFunc(info->atomBIOS->scrnIndex, info->atomBIOS, ATOMBIOS_EXEC, &data) == ATOM_SUCCESS) { 844b7e1c893Smrg if (IS_DCE32_VARIANT) 845b7e1c893Smrg ErrorF("Output UNIPHY%d transmitter setup success\n", num); 846b7e1c893Smrg else 847b7e1c893Smrg ErrorF("Output DIG%d transmitter setup success\n", num); 848209ff23fSmrg return ATOM_SUCCESS; 849209ff23fSmrg } 850209ff23fSmrg 851b7e1c893Smrg ErrorF("Output DIG%d transmitter setup failed\n", num); 852209ff23fSmrg return ATOM_NOT_IMPLEMENTED; 853209ff23fSmrg 854209ff23fSmrg} 855209ff23fSmrg 856c503f109Smrgstatic void atom_rv515_force_tv_scaler(ScrnInfoPtr pScrn, RADEONCrtcPrivatePtr radeon_crtc) 857b7e1c893Smrg{ 858b7e1c893Smrg RADEONInfoPtr info = RADEONPTR(pScrn); 859b7e1c893Smrg unsigned char *RADEONMMIO = info->MMIO; 860c503f109Smrg int index_reg = 0x6578, data_reg = 0x657c; 861c503f109Smrg 862c503f109Smrg index_reg += radeon_crtc->crtc_offset; 863c503f109Smrg data_reg += radeon_crtc->crtc_offset; 864c503f109Smrg 865c503f109Smrg OUTREG(0x659C + radeon_crtc->crtc_offset, 0x0); 866c503f109Smrg OUTREG(0x6594 + radeon_crtc->crtc_offset, 0x705); 867c503f109Smrg OUTREG(0x65A4 + radeon_crtc->crtc_offset, 0x10001); 868c503f109Smrg OUTREG(0x65D8 + radeon_crtc->crtc_offset, 0x0); 869c503f109Smrg OUTREG(0x65B0 + radeon_crtc->crtc_offset, 0x0); 870c503f109Smrg OUTREG(0x65C0 + radeon_crtc->crtc_offset, 0x0); 871c503f109Smrg OUTREG(0x65D4 + radeon_crtc->crtc_offset, 0x0); 872c503f109Smrg OUTREG(index_reg,0x0); 873c503f109Smrg OUTREG(data_reg,0x841880A8); 874c503f109Smrg OUTREG(index_reg,0x1); 875c503f109Smrg OUTREG(data_reg,0x84208680); 876c503f109Smrg OUTREG(index_reg,0x2); 877c503f109Smrg OUTREG(data_reg,0xBFF880B0); 878c503f109Smrg OUTREG(index_reg,0x100); 879c503f109Smrg OUTREG(data_reg,0x83D88088); 880c503f109Smrg OUTREG(index_reg,0x101); 881c503f109Smrg OUTREG(data_reg,0x84608680); 882c503f109Smrg OUTREG(index_reg,0x102); 883c503f109Smrg OUTREG(data_reg,0xBFF080D0); 884c503f109Smrg OUTREG(index_reg,0x200); 885c503f109Smrg OUTREG(data_reg,0x83988068); 886c503f109Smrg OUTREG(index_reg,0x201); 887c503f109Smrg OUTREG(data_reg,0x84A08680); 888c503f109Smrg OUTREG(index_reg,0x202); 889c503f109Smrg OUTREG(data_reg,0xBFF080F8); 890c503f109Smrg OUTREG(index_reg,0x300); 891c503f109Smrg OUTREG(data_reg,0x83588058); 892c503f109Smrg OUTREG(index_reg,0x301); 893c503f109Smrg OUTREG(data_reg,0x84E08660); 894c503f109Smrg OUTREG(index_reg,0x302); 895c503f109Smrg OUTREG(data_reg,0xBFF88120); 896c503f109Smrg OUTREG(index_reg,0x400); 897c503f109Smrg OUTREG(data_reg,0x83188040); 898c503f109Smrg OUTREG(index_reg,0x401); 899c503f109Smrg OUTREG(data_reg,0x85008660); 900c503f109Smrg OUTREG(index_reg,0x402); 901c503f109Smrg OUTREG(data_reg,0xBFF88150); 902c503f109Smrg OUTREG(index_reg,0x500); 903c503f109Smrg OUTREG(data_reg,0x82D88030); 904c503f109Smrg OUTREG(index_reg,0x501); 905c503f109Smrg OUTREG(data_reg,0x85408640); 906c503f109Smrg OUTREG(index_reg,0x502); 907c503f109Smrg OUTREG(data_reg,0xBFF88180); 908c503f109Smrg OUTREG(index_reg,0x600); 909c503f109Smrg OUTREG(data_reg,0x82A08018); 910c503f109Smrg OUTREG(index_reg,0x601); 911c503f109Smrg OUTREG(data_reg,0x85808620); 912c503f109Smrg OUTREG(index_reg,0x602); 913c503f109Smrg OUTREG(data_reg,0xBFF081B8); 914c503f109Smrg OUTREG(index_reg,0x700); 915c503f109Smrg OUTREG(data_reg,0x82608010); 916c503f109Smrg OUTREG(index_reg,0x701); 917c503f109Smrg OUTREG(data_reg,0x85A08600); 918c503f109Smrg OUTREG(index_reg,0x702); 919c503f109Smrg OUTREG(data_reg,0x800081F0); 920c503f109Smrg OUTREG(index_reg,0x800); 921c503f109Smrg OUTREG(data_reg,0x8228BFF8); 922c503f109Smrg OUTREG(index_reg,0x801); 923c503f109Smrg OUTREG(data_reg,0x85E085E0); 924c503f109Smrg OUTREG(index_reg,0x802); 925c503f109Smrg OUTREG(data_reg,0xBFF88228); 926c503f109Smrg OUTREG(index_reg,0x10000); 927c503f109Smrg OUTREG(data_reg,0x82A8BF00); 928c503f109Smrg OUTREG(index_reg,0x10001); 929c503f109Smrg OUTREG(data_reg,0x82A08CC0); 930c503f109Smrg OUTREG(index_reg,0x10002); 931c503f109Smrg OUTREG(data_reg,0x8008BEF8); 932c503f109Smrg OUTREG(index_reg,0x10100); 933c503f109Smrg OUTREG(data_reg,0x81F0BF28); 934c503f109Smrg OUTREG(index_reg,0x10101); 935c503f109Smrg OUTREG(data_reg,0x83608CA0); 936c503f109Smrg OUTREG(index_reg,0x10102); 937c503f109Smrg OUTREG(data_reg,0x8018BED0); 938c503f109Smrg OUTREG(index_reg,0x10200); 939c503f109Smrg OUTREG(data_reg,0x8148BF38); 940c503f109Smrg OUTREG(index_reg,0x10201); 941c503f109Smrg OUTREG(data_reg,0x84408C80); 942c503f109Smrg OUTREG(index_reg,0x10202); 943c503f109Smrg OUTREG(data_reg,0x8008BEB8); 944c503f109Smrg OUTREG(index_reg,0x10300); 945c503f109Smrg OUTREG(data_reg,0x80B0BF78); 946c503f109Smrg OUTREG(index_reg,0x10301); 947c503f109Smrg OUTREG(data_reg,0x85008C20); 948c503f109Smrg OUTREG(index_reg,0x10302); 949c503f109Smrg OUTREG(data_reg,0x8020BEA0); 950c503f109Smrg OUTREG(index_reg,0x10400); 951c503f109Smrg OUTREG(data_reg,0x8028BF90); 952c503f109Smrg OUTREG(index_reg,0x10401); 953c503f109Smrg OUTREG(data_reg,0x85E08BC0); 954c503f109Smrg OUTREG(index_reg,0x10402); 955c503f109Smrg OUTREG(data_reg,0x8018BE90); 956c503f109Smrg OUTREG(index_reg,0x10500); 957c503f109Smrg OUTREG(data_reg,0xBFB8BFB0); 958c503f109Smrg OUTREG(index_reg,0x10501); 959c503f109Smrg OUTREG(data_reg,0x86C08B40); 960c503f109Smrg OUTREG(index_reg,0x10502); 961c503f109Smrg OUTREG(data_reg,0x8010BE90); 962c503f109Smrg OUTREG(index_reg,0x10600); 963c503f109Smrg OUTREG(data_reg,0xBF58BFC8); 964c503f109Smrg OUTREG(index_reg,0x10601); 965c503f109Smrg OUTREG(data_reg,0x87A08AA0); 966c503f109Smrg OUTREG(index_reg,0x10602); 967c503f109Smrg OUTREG(data_reg,0x8010BE98); 968c503f109Smrg OUTREG(index_reg,0x10700); 969c503f109Smrg OUTREG(data_reg,0xBF10BFF0); 970c503f109Smrg OUTREG(index_reg,0x10701); 971c503f109Smrg OUTREG(data_reg,0x886089E0); 972c503f109Smrg OUTREG(index_reg,0x10702); 973c503f109Smrg OUTREG(data_reg,0x8018BEB0); 974c503f109Smrg OUTREG(index_reg,0x10800); 975c503f109Smrg OUTREG(data_reg,0xBED8BFE8); 976c503f109Smrg OUTREG(index_reg,0x10801); 977c503f109Smrg OUTREG(data_reg,0x89408940); 978c503f109Smrg OUTREG(index_reg,0x10802); 979c503f109Smrg OUTREG(data_reg,0xBFE8BED8); 980c503f109Smrg OUTREG(index_reg,0x20000); 981c503f109Smrg OUTREG(data_reg,0x80008000); 982c503f109Smrg OUTREG(index_reg,0x20001); 983c503f109Smrg OUTREG(data_reg,0x90008000); 984c503f109Smrg OUTREG(index_reg,0x20002); 985c503f109Smrg OUTREG(data_reg,0x80008000); 986c503f109Smrg OUTREG(index_reg,0x20003); 987c503f109Smrg OUTREG(data_reg,0x80008000); 988c503f109Smrg OUTREG(index_reg,0x20100); 989c503f109Smrg OUTREG(data_reg,0x80108000); 990c503f109Smrg OUTREG(index_reg,0x20101); 991c503f109Smrg OUTREG(data_reg,0x8FE0BF70); 992c503f109Smrg OUTREG(index_reg,0x20102); 993c503f109Smrg OUTREG(data_reg,0xBFE880C0); 994c503f109Smrg OUTREG(index_reg,0x20103); 995c503f109Smrg OUTREG(data_reg,0x80008000); 996c503f109Smrg OUTREG(index_reg,0x20200); 997c503f109Smrg OUTREG(data_reg,0x8018BFF8); 998c503f109Smrg OUTREG(index_reg,0x20201); 999c503f109Smrg OUTREG(data_reg,0x8F80BF08); 1000c503f109Smrg OUTREG(index_reg,0x20202); 1001c503f109Smrg OUTREG(data_reg,0xBFD081A0); 1002c503f109Smrg OUTREG(index_reg,0x20203); 1003c503f109Smrg OUTREG(data_reg,0xBFF88000); 1004c503f109Smrg OUTREG(index_reg,0x20300); 1005c503f109Smrg OUTREG(data_reg,0x80188000); 1006c503f109Smrg OUTREG(index_reg,0x20301); 1007c503f109Smrg OUTREG(data_reg,0x8EE0BEC0); 1008c503f109Smrg OUTREG(index_reg,0x20302); 1009c503f109Smrg OUTREG(data_reg,0xBFB082A0); 1010c503f109Smrg OUTREG(index_reg,0x20303); 1011c503f109Smrg OUTREG(data_reg,0x80008000); 1012c503f109Smrg OUTREG(index_reg,0x20400); 1013c503f109Smrg OUTREG(data_reg,0x80188000); 1014c503f109Smrg OUTREG(index_reg,0x20401); 1015c503f109Smrg OUTREG(data_reg,0x8E00BEA0); 1016c503f109Smrg OUTREG(index_reg,0x20402); 1017c503f109Smrg OUTREG(data_reg,0xBF8883C0); 1018c503f109Smrg OUTREG(index_reg,0x20403); 1019c503f109Smrg OUTREG(data_reg,0x80008000); 1020c503f109Smrg OUTREG(index_reg,0x20500); 1021c503f109Smrg OUTREG(data_reg,0x80188000); 1022c503f109Smrg OUTREG(index_reg,0x20501); 1023c503f109Smrg OUTREG(data_reg,0x8D00BE90); 1024c503f109Smrg OUTREG(index_reg,0x20502); 1025c503f109Smrg OUTREG(data_reg,0xBF588500); 1026c503f109Smrg OUTREG(index_reg,0x20503); 1027c503f109Smrg OUTREG(data_reg,0x80008008); 1028c503f109Smrg OUTREG(index_reg,0x20600); 1029c503f109Smrg OUTREG(data_reg,0x80188000); 1030c503f109Smrg OUTREG(index_reg,0x20601); 1031c503f109Smrg OUTREG(data_reg,0x8BC0BE98); 1032c503f109Smrg OUTREG(index_reg,0x20602); 1033c503f109Smrg OUTREG(data_reg,0xBF308660); 1034c503f109Smrg OUTREG(index_reg,0x20603); 1035c503f109Smrg OUTREG(data_reg,0x80008008); 1036c503f109Smrg OUTREG(index_reg,0x20700); 1037c503f109Smrg OUTREG(data_reg,0x80108000); 1038c503f109Smrg OUTREG(index_reg,0x20701); 1039c503f109Smrg OUTREG(data_reg,0x8A80BEB0); 1040c503f109Smrg OUTREG(index_reg,0x20702); 1041c503f109Smrg OUTREG(data_reg,0xBF0087C0); 1042c503f109Smrg OUTREG(index_reg,0x20703); 1043c503f109Smrg OUTREG(data_reg,0x80008008); 1044c503f109Smrg OUTREG(index_reg,0x20800); 1045c503f109Smrg OUTREG(data_reg,0x80108000); 1046c503f109Smrg OUTREG(index_reg,0x20801); 1047c503f109Smrg OUTREG(data_reg,0x8920BED0); 1048c503f109Smrg OUTREG(index_reg,0x20802); 1049c503f109Smrg OUTREG(data_reg,0xBED08920); 1050c503f109Smrg OUTREG(index_reg,0x20803); 1051c503f109Smrg OUTREG(data_reg,0x80008010); 1052c503f109Smrg OUTREG(index_reg,0x30000); 1053c503f109Smrg OUTREG(data_reg,0x90008000); 1054c503f109Smrg OUTREG(index_reg,0x30001); 1055c503f109Smrg OUTREG(data_reg,0x80008000); 1056c503f109Smrg OUTREG(index_reg,0x30100); 1057c503f109Smrg OUTREG(data_reg,0x8FE0BF90); 1058c503f109Smrg OUTREG(index_reg,0x30101); 1059c503f109Smrg OUTREG(data_reg,0xBFF880A0); 1060c503f109Smrg OUTREG(index_reg,0x30200); 1061c503f109Smrg OUTREG(data_reg,0x8F60BF40); 1062c503f109Smrg OUTREG(index_reg,0x30201); 1063c503f109Smrg OUTREG(data_reg,0xBFE88180); 1064c503f109Smrg OUTREG(index_reg,0x30300); 1065c503f109Smrg OUTREG(data_reg,0x8EC0BF00); 1066c503f109Smrg OUTREG(index_reg,0x30301); 1067c503f109Smrg OUTREG(data_reg,0xBFC88280); 1068c503f109Smrg OUTREG(index_reg,0x30400); 1069c503f109Smrg OUTREG(data_reg,0x8DE0BEE0); 1070c503f109Smrg OUTREG(index_reg,0x30401); 1071c503f109Smrg OUTREG(data_reg,0xBFA083A0); 1072c503f109Smrg OUTREG(index_reg,0x30500); 1073c503f109Smrg OUTREG(data_reg,0x8CE0BED0); 1074c503f109Smrg OUTREG(index_reg,0x30501); 1075c503f109Smrg OUTREG(data_reg,0xBF7884E0); 1076c503f109Smrg OUTREG(index_reg,0x30600); 1077c503f109Smrg OUTREG(data_reg,0x8BA0BED8); 1078c503f109Smrg OUTREG(index_reg,0x30601); 1079c503f109Smrg OUTREG(data_reg,0xBF508640); 1080c503f109Smrg OUTREG(index_reg,0x30700); 1081c503f109Smrg OUTREG(data_reg,0x8A60BEE8); 1082c503f109Smrg OUTREG(index_reg,0x30701); 1083c503f109Smrg OUTREG(data_reg,0xBF2087A0); 1084c503f109Smrg OUTREG(index_reg,0x30800); 1085c503f109Smrg OUTREG(data_reg,0x8900BF00); 1086c503f109Smrg OUTREG(index_reg,0x30801); 1087c503f109Smrg OUTREG(data_reg,0xBF008900); 1088b7e1c893Smrg} 1089b7e1c893Smrg 1090209ff23fSmrgstatic int 1091b7e1c893Smrgatombios_output_yuv_setup(xf86OutputPtr output, Bool enable) 1092209ff23fSmrg{ 1093209ff23fSmrg RADEONOutputPrivatePtr radeon_output = output->driver_private; 1094209ff23fSmrg RADEONInfoPtr info = RADEONPTR(output->scrn); 1095b7e1c893Smrg RADEONCrtcPrivatePtr radeon_crtc = output->crtc->driver_private; 1096b7e1c893Smrg ENABLE_YUV_PS_ALLOCATION disp_data; 1097209ff23fSmrg AtomBiosArgRec data; 1098209ff23fSmrg unsigned char *space; 1099b7e1c893Smrg unsigned char *RADEONMMIO = info->MMIO; 1100b7e1c893Smrg uint32_t temp, reg; 1101209ff23fSmrg 1102b7e1c893Smrg if (info->ChipFamily >= CHIP_FAMILY_R600) 1103b7e1c893Smrg reg = R600_BIOS_3_SCRATCH; 1104b7e1c893Smrg else 1105b7e1c893Smrg reg = RADEON_BIOS_3_SCRATCH; 1106b7e1c893Smrg 1107b7e1c893Smrg //fix up scratch reg handling 1108b7e1c893Smrg temp = INREG(reg); 1109b7e1c893Smrg if (radeon_output->active_device & (ATOM_DEVICE_TV_SUPPORT)) 1110b7e1c893Smrg OUTREG(reg, (ATOM_S3_TV1_ACTIVE | 1111b7e1c893Smrg (radeon_crtc->crtc_id << 18))); 1112b7e1c893Smrg else if (radeon_output->active_device & (ATOM_DEVICE_CV_SUPPORT)) 1113b7e1c893Smrg OUTREG(reg, (ATOM_S3_CV_ACTIVE | 1114b7e1c893Smrg (radeon_crtc->crtc_id << 24))); 1115b7e1c893Smrg else 1116b7e1c893Smrg OUTREG(reg, 0); 1117209ff23fSmrg 1118b7e1c893Smrg memset(&disp_data, 0, sizeof(disp_data)); 1119209ff23fSmrg 1120b7e1c893Smrg if (enable) 1121b7e1c893Smrg disp_data.ucEnable = ATOM_ENABLE; 1122b7e1c893Smrg disp_data.ucCRTC = radeon_crtc->crtc_id; 1123209ff23fSmrg 1124b7e1c893Smrg data.exec.index = GetIndexIntoMasterTable(COMMAND, EnableYUV); 1125209ff23fSmrg data.exec.dataSpace = (void *)&space; 1126209ff23fSmrg data.exec.pspace = &disp_data; 1127209ff23fSmrg 1128209ff23fSmrg if (RHDAtomBiosFunc(info->atomBIOS->scrnIndex, info->atomBIOS, ATOMBIOS_EXEC, &data) == ATOM_SUCCESS) { 1129b7e1c893Smrg 1130b7e1c893Smrg OUTREG(reg, temp); 1131b7e1c893Smrg 1132b7e1c893Smrg ErrorF("crtc %d YUV %s setup success\n", radeon_crtc->crtc_id, enable ? "enable" : "disable"); 1133209ff23fSmrg return ATOM_SUCCESS; 1134209ff23fSmrg } 1135209ff23fSmrg 1136b7e1c893Smrg OUTREG(reg, temp); 1137b7e1c893Smrg 1138b7e1c893Smrg ErrorF("crtc %d YUV %s setup failed\n", radeon_crtc->crtc_id, enable ? "enable" : "disable"); 1139209ff23fSmrg return ATOM_NOT_IMPLEMENTED; 1140209ff23fSmrg 1141209ff23fSmrg} 1142209ff23fSmrg 1143209ff23fSmrgstatic int 1144b7e1c893Smrgatombios_output_overscan_setup(xf86OutputPtr output, DisplayModePtr mode, DisplayModePtr adjusted_mode) 1145209ff23fSmrg{ 1146209ff23fSmrg RADEONOutputPrivatePtr radeon_output = output->driver_private; 1147b7e1c893Smrg RADEONCrtcPrivatePtr radeon_crtc = output->crtc->driver_private; 1148209ff23fSmrg RADEONInfoPtr info = RADEONPTR(output->scrn); 1149b7e1c893Smrg SET_CRTC_OVERSCAN_PS_ALLOCATION overscan_param; 1150209ff23fSmrg AtomBiosArgRec data; 1151209ff23fSmrg unsigned char *space; 1152b7e1c893Smrg memset(&overscan_param, 0, sizeof(overscan_param)); 1153209ff23fSmrg 1154b7e1c893Smrg overscan_param.usOverscanRight = 0; 1155b7e1c893Smrg overscan_param.usOverscanLeft = 0; 1156b7e1c893Smrg overscan_param.usOverscanBottom = 0; 1157b7e1c893Smrg overscan_param.usOverscanTop = 0; 1158b7e1c893Smrg overscan_param.ucCRTC = radeon_crtc->crtc_id; 1159b7e1c893Smrg 1160b7e1c893Smrg if (radeon_output->Flags & RADEON_USE_RMX) { 1161b7e1c893Smrg if (radeon_output->rmx_type == RMX_FULL) { 1162b7e1c893Smrg overscan_param.usOverscanRight = 0; 1163b7e1c893Smrg overscan_param.usOverscanLeft = 0; 1164b7e1c893Smrg overscan_param.usOverscanBottom = 0; 1165b7e1c893Smrg overscan_param.usOverscanTop = 0; 1166b7e1c893Smrg } else if (radeon_output->rmx_type == RMX_CENTER) { 1167b7e1c893Smrg overscan_param.usOverscanTop = (adjusted_mode->CrtcVDisplay - mode->CrtcVDisplay) / 2; 1168b7e1c893Smrg overscan_param.usOverscanBottom = (adjusted_mode->CrtcVDisplay - mode->CrtcVDisplay) / 2; 1169b7e1c893Smrg overscan_param.usOverscanLeft = (adjusted_mode->CrtcHDisplay - mode->CrtcHDisplay) / 2; 1170b7e1c893Smrg overscan_param.usOverscanRight = (adjusted_mode->CrtcHDisplay - mode->CrtcHDisplay) / 2; 1171b7e1c893Smrg } else if (radeon_output->rmx_type == RMX_ASPECT) { 1172b7e1c893Smrg int a1 = mode->CrtcVDisplay * adjusted_mode->CrtcHDisplay; 1173b7e1c893Smrg int a2 = adjusted_mode->CrtcVDisplay * mode->CrtcHDisplay; 1174b7e1c893Smrg 1175b7e1c893Smrg if (a1 > a2) { 1176b7e1c893Smrg overscan_param.usOverscanLeft = (adjusted_mode->CrtcHDisplay - (a2 / mode->CrtcVDisplay)) / 2; 1177b7e1c893Smrg overscan_param.usOverscanRight = (adjusted_mode->CrtcHDisplay - (a2 / mode->CrtcVDisplay)) / 2; 1178b7e1c893Smrg } else if (a2 > a1) { 1179b7e1c893Smrg overscan_param.usOverscanLeft = (adjusted_mode->CrtcVDisplay - (a1 / mode->CrtcHDisplay)) / 2; 1180b7e1c893Smrg overscan_param.usOverscanRight = (adjusted_mode->CrtcVDisplay - (a1 / mode->CrtcHDisplay)) / 2; 1181b7e1c893Smrg } 1182209ff23fSmrg } 1183209ff23fSmrg } 1184209ff23fSmrg 1185b7e1c893Smrg data.exec.index = GetIndexIntoMasterTable(COMMAND, SetCRTC_OverScan); 1186209ff23fSmrg data.exec.dataSpace = (void *)&space; 1187b7e1c893Smrg data.exec.pspace = &overscan_param; 1188209ff23fSmrg 1189209ff23fSmrg if (RHDAtomBiosFunc(info->atomBIOS->scrnIndex, info->atomBIOS, ATOMBIOS_EXEC, &data) == ATOM_SUCCESS) { 1190b7e1c893Smrg ErrorF("Set CRTC %d Overscan success\n", radeon_crtc->crtc_id); 1191b7e1c893Smrg return ATOM_SUCCESS ; 1192209ff23fSmrg } 1193209ff23fSmrg 1194b7e1c893Smrg ErrorF("Set CRTC %d Overscan failed\n", radeon_crtc->crtc_id); 1195209ff23fSmrg return ATOM_NOT_IMPLEMENTED; 1196209ff23fSmrg} 1197209ff23fSmrg 1198209ff23fSmrgstatic int 1199b7e1c893Smrgatombios_output_scaler_setup(xf86OutputPtr output) 1200209ff23fSmrg{ 1201209ff23fSmrg RADEONInfoPtr info = RADEONPTR(output->scrn); 1202209ff23fSmrg RADEONOutputPrivatePtr radeon_output = output->driver_private; 1203b7e1c893Smrg radeon_tvout_ptr tvout = &radeon_output->tvout; 1204209ff23fSmrg RADEONCrtcPrivatePtr radeon_crtc = output->crtc->driver_private; 1205209ff23fSmrg ENABLE_SCALER_PS_ALLOCATION disp_data; 1206209ff23fSmrg AtomBiosArgRec data; 1207209ff23fSmrg unsigned char *space; 1208209ff23fSmrg 1209b7e1c893Smrg if (!IS_AVIVO_VARIANT && radeon_crtc->crtc_id) 1210b7e1c893Smrg return ATOM_SUCCESS; 1211b7e1c893Smrg 1212b7e1c893Smrg memset(&disp_data, 0, sizeof(disp_data)); 1213b7e1c893Smrg 1214209ff23fSmrg disp_data.ucScaler = radeon_crtc->crtc_id; 1215209ff23fSmrg 1216b7e1c893Smrg if (radeon_output->active_device & (ATOM_DEVICE_TV_SUPPORT)) { 1217b7e1c893Smrg switch (tvout->tvStd) { 1218b7e1c893Smrg case TV_STD_NTSC: 1219b7e1c893Smrg disp_data.ucTVStandard = ATOM_TV_NTSC; 1220b7e1c893Smrg break; 1221b7e1c893Smrg case TV_STD_PAL: 1222b7e1c893Smrg disp_data.ucTVStandard = ATOM_TV_PAL; 1223b7e1c893Smrg break; 1224b7e1c893Smrg case TV_STD_PAL_M: 1225b7e1c893Smrg disp_data.ucTVStandard = ATOM_TV_PALM; 1226b7e1c893Smrg break; 1227b7e1c893Smrg case TV_STD_PAL_60: 1228b7e1c893Smrg disp_data.ucTVStandard = ATOM_TV_PAL60; 1229b7e1c893Smrg break; 1230b7e1c893Smrg case TV_STD_NTSC_J: 1231b7e1c893Smrg disp_data.ucTVStandard = ATOM_TV_NTSCJ; 1232b7e1c893Smrg break; 1233b7e1c893Smrg case TV_STD_SCART_PAL: 1234b7e1c893Smrg disp_data.ucTVStandard = ATOM_TV_PAL; /* ??? */ 1235b7e1c893Smrg break; 1236b7e1c893Smrg case TV_STD_SECAM: 1237b7e1c893Smrg disp_data.ucTVStandard = ATOM_TV_SECAM; 1238b7e1c893Smrg break; 1239b7e1c893Smrg case TV_STD_PAL_CN: 1240b7e1c893Smrg disp_data.ucTVStandard = ATOM_TV_PALCN; 1241b7e1c893Smrg break; 1242b7e1c893Smrg default: 1243b7e1c893Smrg disp_data.ucTVStandard = ATOM_TV_NTSC; 1244b7e1c893Smrg break; 1245b7e1c893Smrg } 1246b7e1c893Smrg disp_data.ucEnable = SCALER_ENABLE_MULTITAP_MODE; 1247b7e1c893Smrg ErrorF("Using TV scaler %x %x\n", disp_data.ucTVStandard, disp_data.ucEnable); 1248b7e1c893Smrg } else if (radeon_output->active_device & (ATOM_DEVICE_CV_SUPPORT)) { 1249b7e1c893Smrg disp_data.ucTVStandard = ATOM_TV_CV; 1250b7e1c893Smrg disp_data.ucEnable = SCALER_ENABLE_MULTITAP_MODE; 1251b7e1c893Smrg ErrorF("Using CV scaler %x %x\n", disp_data.ucTVStandard, disp_data.ucEnable); 1252b7e1c893Smrg } else if (radeon_output->Flags & RADEON_USE_RMX) { 1253209ff23fSmrg ErrorF("Using RMX\n"); 1254209ff23fSmrg if (radeon_output->rmx_type == RMX_FULL) 1255209ff23fSmrg disp_data.ucEnable = ATOM_SCALER_EXPANSION; 1256209ff23fSmrg else if (radeon_output->rmx_type == RMX_CENTER) 1257209ff23fSmrg disp_data.ucEnable = ATOM_SCALER_CENTER; 1258b7e1c893Smrg else if (radeon_output->rmx_type == RMX_ASPECT) 1259b7e1c893Smrg disp_data.ucEnable = ATOM_SCALER_EXPANSION; 1260209ff23fSmrg } else { 1261209ff23fSmrg ErrorF("Not using RMX\n"); 1262b7e1c893Smrg if (IS_AVIVO_VARIANT) 1263b7e1c893Smrg disp_data.ucEnable = ATOM_SCALER_DISABLE; 1264b7e1c893Smrg else 1265b7e1c893Smrg disp_data.ucEnable = ATOM_SCALER_CENTER; 1266209ff23fSmrg } 1267209ff23fSmrg 1268209ff23fSmrg data.exec.index = GetIndexIntoMasterTable(COMMAND, EnableScaler); 1269209ff23fSmrg data.exec.dataSpace = (void *)&space; 1270209ff23fSmrg data.exec.pspace = &disp_data; 1271209ff23fSmrg 1272209ff23fSmrg if (RHDAtomBiosFunc(info->atomBIOS->scrnIndex, info->atomBIOS, ATOMBIOS_EXEC, &data) == ATOM_SUCCESS) { 1273b7e1c893Smrg if (radeon_output->active_device & (ATOM_DEVICE_CV_SUPPORT | ATOM_DEVICE_TV_SUPPORT) 1274b7e1c893Smrg && info->ChipFamily >= CHIP_FAMILY_RV515 && info->ChipFamily <= CHIP_FAMILY_RV570) { 1275b7e1c893Smrg ErrorF("forcing TV scaler\n"); 1276c503f109Smrg atom_rv515_force_tv_scaler(output->scrn, radeon_crtc); 1277b7e1c893Smrg } 1278209ff23fSmrg ErrorF("scaler %d setup success\n", radeon_crtc->crtc_id); 1279209ff23fSmrg return ATOM_SUCCESS; 1280209ff23fSmrg } 1281209ff23fSmrg 1282209ff23fSmrg ErrorF("scaler %d setup failed\n", radeon_crtc->crtc_id); 1283209ff23fSmrg return ATOM_NOT_IMPLEMENTED; 1284209ff23fSmrg 1285209ff23fSmrg} 1286209ff23fSmrg 1287b7e1c893Smrgvoid 1288b7e1c893Smrgatombios_output_dpms(xf86OutputPtr output, int mode) 1289209ff23fSmrg{ 1290b7e1c893Smrg RADEONOutputPrivatePtr radeon_output = output->driver_private; 1291b7e1c893Smrg radeon_encoder_ptr radeon_encoder = radeon_get_encoder(output); 1292209ff23fSmrg RADEONInfoPtr info = RADEONPTR(output->scrn); 1293209ff23fSmrg DISPLAY_DEVICE_OUTPUT_CONTROL_PS_ALLOCATION disp_data; 1294209ff23fSmrg AtomBiosArgRec data; 1295209ff23fSmrg unsigned char *space; 1296209ff23fSmrg int index = 0; 1297b7e1c893Smrg Bool is_dig = FALSE; 1298209ff23fSmrg 1299b7e1c893Smrg if (radeon_encoder == NULL) 1300b7e1c893Smrg return; 1301b7e1c893Smrg 1302b7e1c893Smrg switch (radeon_encoder->encoder_id) { 1303b7e1c893Smrg case ENCODER_OBJECT_ID_INTERNAL_TMDS1: 1304b7e1c893Smrg case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1: 1305209ff23fSmrg index = GetIndexIntoMasterTable(COMMAND, TMDSAOutputControl); 1306209ff23fSmrg break; 1307b7e1c893Smrg case ENCODER_OBJECT_ID_INTERNAL_UNIPHY: 1308b7e1c893Smrg case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1: 1309b7e1c893Smrg case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2: 1310b7e1c893Smrg case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA: 1311b7e1c893Smrg is_dig = TRUE; 1312209ff23fSmrg break; 1313b7e1c893Smrg case ENCODER_OBJECT_ID_INTERNAL_DVO1: 1314b7e1c893Smrg case ENCODER_OBJECT_ID_INTERNAL_DDI: 1315b7e1c893Smrg case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1: 1316b7e1c893Smrg index = GetIndexIntoMasterTable(COMMAND, DVOOutputControl); 1317209ff23fSmrg break; 1318b7e1c893Smrg case ENCODER_OBJECT_ID_INTERNAL_LVDS: 1319209ff23fSmrg index = GetIndexIntoMasterTable(COMMAND, LCD1OutputControl); 1320209ff23fSmrg break; 1321b7e1c893Smrg case ENCODER_OBJECT_ID_INTERNAL_LVTM1: 1322b7e1c893Smrg if (radeon_output->active_device & (ATOM_DEVICE_LCD_SUPPORT)) 1323b7e1c893Smrg index = GetIndexIntoMasterTable(COMMAND, LCD1OutputControl); 1324b7e1c893Smrg else 1325b7e1c893Smrg index = GetIndexIntoMasterTable(COMMAND, LVTMAOutputControl); 1326209ff23fSmrg break; 1327b7e1c893Smrg case ENCODER_OBJECT_ID_INTERNAL_DAC1: 1328b7e1c893Smrg case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1: 1329ad43ddacSmrg if (IS_DCE32_VARIANT) 1330b7e1c893Smrg index = GetIndexIntoMasterTable(COMMAND, DAC1OutputControl); 1331ad43ddacSmrg else { 1332ad43ddacSmrg if (radeon_output->active_device & (ATOM_DEVICE_TV_SUPPORT)) 1333ad43ddacSmrg index = GetIndexIntoMasterTable(COMMAND, TV1OutputControl); 1334ad43ddacSmrg else if (radeon_output->active_device & (ATOM_DEVICE_CV_SUPPORT)) 1335ad43ddacSmrg index = GetIndexIntoMasterTable(COMMAND, CV1OutputControl); 1336ad43ddacSmrg else 1337ad43ddacSmrg index = GetIndexIntoMasterTable(COMMAND, DAC1OutputControl); 1338ad43ddacSmrg } 1339209ff23fSmrg break; 1340b7e1c893Smrg case ENCODER_OBJECT_ID_INTERNAL_DAC2: 1341b7e1c893Smrg case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC2: 1342ad43ddacSmrg if (IS_DCE32_VARIANT) 1343b7e1c893Smrg index = GetIndexIntoMasterTable(COMMAND, DAC2OutputControl); 1344ad43ddacSmrg else { 1345ad43ddacSmrg if (radeon_output->active_device & (ATOM_DEVICE_TV_SUPPORT)) 1346ad43ddacSmrg index = GetIndexIntoMasterTable(COMMAND, TV1OutputControl); 1347ad43ddacSmrg else if (radeon_output->active_device & (ATOM_DEVICE_CV_SUPPORT)) 1348ad43ddacSmrg index = GetIndexIntoMasterTable(COMMAND, CV1OutputControl); 1349ad43ddacSmrg else 1350ad43ddacSmrg index = GetIndexIntoMasterTable(COMMAND, DAC2OutputControl); 1351ad43ddacSmrg } 1352209ff23fSmrg break; 1353209ff23fSmrg } 1354209ff23fSmrg 1355209ff23fSmrg switch (mode) { 1356209ff23fSmrg case DPMSModeOn: 1357b7e1c893Smrg radeon_encoder->devices |= radeon_output->active_device; 1358ad43ddacSmrg if (is_dig) { 13590974d292Smrg if (!IS_DCE4_VARIANT) 13600974d292Smrg atombios_output_dig_transmitter_setup(output, ATOM_TRANSMITTER_ACTION_ENABLE_OUTPUT, 0, 0); 1361ad43ddacSmrg if (((radeon_output->ConnectorType == CONNECTOR_DISPLAY_PORT) || 1362ad43ddacSmrg (radeon_output->ConnectorType == CONNECTOR_EDP)) && 1363ad43ddacSmrg (radeon_output->MonType == MT_DP)) { 1364ad43ddacSmrg do_displayport_link_train(output); 1365ad43ddacSmrg if (IS_DCE4_VARIANT) 13660974d292Smrg atombios_output_dig_encoder_setup(output, ATOM_ENCODER_CMD_DP_VIDEO_ON); 1367ad43ddacSmrg } 1368ad43ddacSmrg } 1369b7e1c893Smrg else { 1370b7e1c893Smrg disp_data.ucAction = ATOM_ENABLE; 1371b7e1c893Smrg data.exec.index = index; 1372b7e1c893Smrg data.exec.dataSpace = (void *)&space; 1373b7e1c893Smrg data.exec.pspace = &disp_data; 1374b7e1c893Smrg 1375b7e1c893Smrg if (RHDAtomBiosFunc(info->atomBIOS->scrnIndex, info->atomBIOS, ATOMBIOS_EXEC, &data) == ATOM_SUCCESS) 1376b7e1c893Smrg ErrorF("Output %s enable success\n", 1377b7e1c893Smrg device_name[radeon_get_device_index(radeon_output->active_device)]); 1378b7e1c893Smrg else 1379b7e1c893Smrg ErrorF("Output %s enable failed\n", 1380b7e1c893Smrg device_name[radeon_get_device_index(radeon_output->active_device)]); 1381b7e1c893Smrg } 1382c503f109Smrg /* at least for TV atom fails to reassociate the correct crtc source at dpms on */ 1383c503f109Smrg if (radeon_output->active_device & (ATOM_DEVICE_TV_SUPPORT)) 1384c503f109Smrg atombios_set_output_crtc_source(output); 1385209ff23fSmrg break; 1386209ff23fSmrg case DPMSModeStandby: 1387209ff23fSmrg case DPMSModeSuspend: 1388209ff23fSmrg case DPMSModeOff: 1389b7e1c893Smrg radeon_encoder->devices &= ~(radeon_output->active_device); 1390b7e1c893Smrg if (!radeon_encoder->devices) { 1391ad43ddacSmrg if (is_dig) { 13920974d292Smrg if (!IS_DCE4_VARIANT) 13930974d292Smrg atombios_output_dig_transmitter_setup(output, ATOM_TRANSMITTER_ACTION_DISABLE_OUTPUT, 0, 0); 1394ad43ddacSmrg if (((radeon_output->ConnectorType == CONNECTOR_DISPLAY_PORT) || 1395ad43ddacSmrg (radeon_output->ConnectorType == CONNECTOR_EDP)) && 1396ad43ddacSmrg (radeon_output->MonType == MT_DP)) { 1397ad43ddacSmrg if (IS_DCE4_VARIANT) 13980974d292Smrg atombios_output_dig_encoder_setup(output, ATOM_ENCODER_CMD_DP_VIDEO_OFF); 1399ad43ddacSmrg } 1400ad43ddacSmrg } else { 1401b7e1c893Smrg disp_data.ucAction = ATOM_DISABLE; 1402b7e1c893Smrg data.exec.index = index; 1403b7e1c893Smrg data.exec.dataSpace = (void *)&space; 1404b7e1c893Smrg data.exec.pspace = &disp_data; 1405b7e1c893Smrg 1406b7e1c893Smrg if (RHDAtomBiosFunc(info->atomBIOS->scrnIndex, info->atomBIOS, ATOMBIOS_EXEC, &data) 1407b7e1c893Smrg == ATOM_SUCCESS) 1408b7e1c893Smrg ErrorF("Output %s disable success\n", 1409b7e1c893Smrg device_name[radeon_get_device_index(radeon_output->active_device)]); 1410b7e1c893Smrg else 1411b7e1c893Smrg ErrorF("Output %s disable failed\n", 1412b7e1c893Smrg device_name[radeon_get_device_index(radeon_output->active_device)]); 1413b7e1c893Smrg } 1414209ff23fSmrg } 1415b7e1c893Smrg break; 1416209ff23fSmrg } 1417209ff23fSmrg} 1418209ff23fSmrg 14190974d292Smrgunion crtc_source_param { 14200974d292Smrg SELECT_CRTC_SOURCE_PS_ALLOCATION v1; 14210974d292Smrg SELECT_CRTC_SOURCE_PARAMETERS_V2 v2; 14220974d292Smrg}; 14230974d292Smrg 14240974d292Smrgvoid 1425209ff23fSmrgatombios_set_output_crtc_source(xf86OutputPtr output) 1426209ff23fSmrg{ 1427209ff23fSmrg RADEONOutputPrivatePtr radeon_output = output->driver_private; 1428209ff23fSmrg RADEONCrtcPrivatePtr radeon_crtc = output->crtc->driver_private; 1429209ff23fSmrg RADEONInfoPtr info = RADEONPTR(output->scrn); 1430b7e1c893Smrg radeon_encoder_ptr radeon_encoder = radeon_get_encoder(output); 1431209ff23fSmrg AtomBiosArgRec data; 1432209ff23fSmrg unsigned char *space; 14330974d292Smrg union crtc_source_param args; 1434209ff23fSmrg int index = GetIndexIntoMasterTable(COMMAND, SelectCRTC_Source); 1435209ff23fSmrg int major, minor; 1436209ff23fSmrg 1437b7e1c893Smrg if (radeon_encoder == NULL) 1438b7e1c893Smrg return; 1439b7e1c893Smrg 14400974d292Smrg memset(&args, 0, sizeof(args)); 14410974d292Smrg 1442209ff23fSmrg atombios_get_command_table_version(info->atomBIOS, index, &major, &minor); 1443209ff23fSmrg 1444209ff23fSmrg /*ErrorF("select crtc source table is %d %d\n", major, minor);*/ 1445209ff23fSmrg 1446209ff23fSmrg switch(major) { 1447b7e1c893Smrg case 1: 1448209ff23fSmrg switch(minor) { 1449209ff23fSmrg case 0: 1450209ff23fSmrg case 1: 1451209ff23fSmrg default: 1452b7e1c893Smrg if (IS_AVIVO_VARIANT) 14530974d292Smrg args.v1.ucCRTC = radeon_crtc->crtc_id; 1454b7e1c893Smrg else { 1455b7e1c893Smrg if (radeon_encoder->encoder_id == ENCODER_OBJECT_ID_INTERNAL_DAC1) 14560974d292Smrg args.v1.ucCRTC = radeon_crtc->crtc_id; 1457b7e1c893Smrg else 14580974d292Smrg args.v1.ucCRTC = radeon_crtc->crtc_id << 2; 1459b7e1c893Smrg } 1460b7e1c893Smrg switch (radeon_encoder->encoder_id) { 1461b7e1c893Smrg case ENCODER_OBJECT_ID_INTERNAL_TMDS1: 1462b7e1c893Smrg case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1: 14630974d292Smrg args.v1.ucDevice = ATOM_DEVICE_DFP1_INDEX; 1464b7e1c893Smrg break; 1465b7e1c893Smrg case ENCODER_OBJECT_ID_INTERNAL_LVDS: 1466b7e1c893Smrg case ENCODER_OBJECT_ID_INTERNAL_LVTM1: 1467b7e1c893Smrg if (radeon_output->active_device & ATOM_DEVICE_LCD1_SUPPORT) 14680974d292Smrg args.v1.ucDevice = ATOM_DEVICE_LCD1_INDEX; 1469b7e1c893Smrg else 14700974d292Smrg args.v1.ucDevice = ATOM_DEVICE_DFP3_INDEX; 1471b7e1c893Smrg break; 1472b7e1c893Smrg case ENCODER_OBJECT_ID_INTERNAL_DVO1: 1473b7e1c893Smrg case ENCODER_OBJECT_ID_INTERNAL_DDI: 1474b7e1c893Smrg case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1: 14750974d292Smrg args.v1.ucDevice = ATOM_DEVICE_DFP2_INDEX; 1476b7e1c893Smrg break; 1477b7e1c893Smrg case ENCODER_OBJECT_ID_INTERNAL_DAC1: 1478b7e1c893Smrg case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1: 1479b7e1c893Smrg if (radeon_output->active_device & (ATOM_DEVICE_TV_SUPPORT)) 14800974d292Smrg args.v1.ucDevice = ATOM_DEVICE_TV1_INDEX; 1481b7e1c893Smrg else if (radeon_output->active_device & (ATOM_DEVICE_CV_SUPPORT)) 14820974d292Smrg args.v1.ucDevice = ATOM_DEVICE_CV_INDEX; 1483b7e1c893Smrg else 14840974d292Smrg args.v1.ucDevice = ATOM_DEVICE_CRT1_INDEX; 1485b7e1c893Smrg break; 1486b7e1c893Smrg case ENCODER_OBJECT_ID_INTERNAL_DAC2: 1487b7e1c893Smrg case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC2: 1488b7e1c893Smrg if (radeon_output->active_device & (ATOM_DEVICE_TV_SUPPORT)) 14890974d292Smrg args.v1.ucDevice = ATOM_DEVICE_TV1_INDEX; 1490b7e1c893Smrg else if (radeon_output->active_device & (ATOM_DEVICE_CV_SUPPORT)) 14910974d292Smrg args.v1.ucDevice = ATOM_DEVICE_CV_INDEX; 1492b7e1c893Smrg else 14930974d292Smrg args.v1.ucDevice = ATOM_DEVICE_CRT2_INDEX; 1494b7e1c893Smrg break; 1495209ff23fSmrg } 14960974d292Smrg /*ErrorF("device sourced: 0x%x\n", args.v1.ucDevice);*/ 1497209ff23fSmrg break; 1498209ff23fSmrg case 2: 14990974d292Smrg args.v2.ucCRTC = radeon_crtc->crtc_id; 15000974d292Smrg args.v2.ucEncodeMode = atombios_get_encoder_mode(output); 1501b7e1c893Smrg switch (radeon_encoder->encoder_id) { 1502b7e1c893Smrg case ENCODER_OBJECT_ID_INTERNAL_UNIPHY: 1503b7e1c893Smrg case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1: 1504b7e1c893Smrg case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2: 1505b7e1c893Smrg case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA: 1506ad43ddacSmrg switch (radeon_output->dig_encoder) { 1507ad43ddacSmrg case 0: 15080974d292Smrg args.v2.ucEncoderID = ASIC_INT_DIG1_ENCODER_ID; 1509ad43ddacSmrg break; 1510ad43ddacSmrg case 1: 15110974d292Smrg args.v2.ucEncoderID = ASIC_INT_DIG2_ENCODER_ID; 1512ad43ddacSmrg break; 1513ad43ddacSmrg case 2: 15140974d292Smrg args.v2.ucEncoderID = ASIC_INT_DIG3_ENCODER_ID; 1515ad43ddacSmrg break; 1516ad43ddacSmrg case 3: 15170974d292Smrg args.v2.ucEncoderID = ASIC_INT_DIG4_ENCODER_ID; 1518ad43ddacSmrg break; 1519ad43ddacSmrg case 4: 15200974d292Smrg args.v2.ucEncoderID = ASIC_INT_DIG5_ENCODER_ID; 1521ad43ddacSmrg break; 1522ad43ddacSmrg case 5: 15230974d292Smrg args.v2.ucEncoderID = ASIC_INT_DIG6_ENCODER_ID; 1524ad43ddacSmrg break; 1525ad43ddacSmrg } 1526b7e1c893Smrg break; 15270974d292Smrg case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1: 15280974d292Smrg args.v2.ucEncoderID = ASIC_INT_DVO_ENCODER_ID; 15290974d292Smrg break; 1530b7e1c893Smrg case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1: 1531b7e1c893Smrg if (radeon_output->active_device & (ATOM_DEVICE_TV_SUPPORT)) 15320974d292Smrg args.v2.ucEncoderID = ASIC_INT_TV_ENCODER_ID; 1533b7e1c893Smrg else if (radeon_output->active_device & (ATOM_DEVICE_CV_SUPPORT)) 15340974d292Smrg args.v2.ucEncoderID = ASIC_INT_TV_ENCODER_ID; 1535b7e1c893Smrg else 15360974d292Smrg args.v2.ucEncoderID = ASIC_INT_DAC1_ENCODER_ID; 1537b7e1c893Smrg break; 1538b7e1c893Smrg case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC2: 1539b7e1c893Smrg if (radeon_output->active_device & (ATOM_DEVICE_TV_SUPPORT)) 15400974d292Smrg args.v2.ucEncoderID = ASIC_INT_TV_ENCODER_ID; 1541b7e1c893Smrg else if (radeon_output->active_device & (ATOM_DEVICE_CV_SUPPORT)) 15420974d292Smrg args.v2.ucEncoderID = ASIC_INT_TV_ENCODER_ID; 1543b7e1c893Smrg else 15440974d292Smrg args.v2.ucEncoderID = ASIC_INT_DAC2_ENCODER_ID; 1545b7e1c893Smrg break; 1546209ff23fSmrg } 15470974d292Smrg /*ErrorF("device sourced: 0x%x\n", args.v2.ucEncoderID);*/ 1548209ff23fSmrg break; 1549209ff23fSmrg } 1550209ff23fSmrg break; 1551209ff23fSmrg default: 1552b7e1c893Smrg ErrorF("Unknown table version\n"); 1553b7e1c893Smrg exit(-1); 1554209ff23fSmrg } 1555209ff23fSmrg 15560974d292Smrg data.exec.pspace = &args; 1557209ff23fSmrg data.exec.index = index; 1558209ff23fSmrg data.exec.dataSpace = (void *)&space; 1559209ff23fSmrg 1560209ff23fSmrg if (RHDAtomBiosFunc(info->atomBIOS->scrnIndex, info->atomBIOS, ATOMBIOS_EXEC, &data) == ATOM_SUCCESS) { 1561209ff23fSmrg ErrorF("Set CRTC %d Source success\n", radeon_crtc->crtc_id); 1562209ff23fSmrg return; 1563209ff23fSmrg } 1564209ff23fSmrg 1565209ff23fSmrg ErrorF("Set CRTC Source failed\n"); 1566209ff23fSmrg return; 1567209ff23fSmrg} 1568209ff23fSmrg 1569b7e1c893Smrgstatic void 1570b7e1c893Smrgatombios_apply_output_quirks(xf86OutputPtr output, DisplayModePtr mode) 1571b7e1c893Smrg{ 1572b7e1c893Smrg RADEONOutputPrivatePtr radeon_output = output->driver_private; 1573b7e1c893Smrg RADEONCrtcPrivatePtr radeon_crtc = output->crtc->driver_private; 1574b7e1c893Smrg RADEONInfoPtr info = RADEONPTR(output->scrn); 1575b7e1c893Smrg unsigned char *RADEONMMIO = info->MMIO; 1576b7e1c893Smrg 1577b7e1c893Smrg /* Funky macbooks */ 1578b7e1c893Smrg if ((info->Chipset == PCI_CHIP_RV530_71C5) && 1579b7e1c893Smrg (PCI_SUB_VENDOR_ID(info->PciInfo) == 0x106b) && 1580b7e1c893Smrg (PCI_SUB_DEVICE_ID(info->PciInfo) == 0x0080)) { 1581b7e1c893Smrg if (radeon_output->MonType == MT_LCD) { 1582b7e1c893Smrg if (radeon_output->devices & ATOM_DEVICE_LCD1_SUPPORT) { 1583b7e1c893Smrg uint32_t lvtma_bit_depth_control = INREG(AVIVO_LVTMA_BIT_DEPTH_CONTROL); 1584b7e1c893Smrg 1585b7e1c893Smrg lvtma_bit_depth_control &= ~AVIVO_LVTMA_BIT_DEPTH_CONTROL_TRUNCATE_EN; 1586b7e1c893Smrg lvtma_bit_depth_control &= ~AVIVO_LVTMA_BIT_DEPTH_CONTROL_SPATIAL_DITHER_EN; 1587b7e1c893Smrg 1588b7e1c893Smrg OUTREG(AVIVO_LVTMA_BIT_DEPTH_CONTROL, lvtma_bit_depth_control); 1589b7e1c893Smrg } 1590b7e1c893Smrg } 1591b7e1c893Smrg } 1592b7e1c893Smrg 1593b7e1c893Smrg /* set scaler clears this on some chips */ 1594ad43ddacSmrg if (!(radeon_output->active_device & (ATOM_DEVICE_CV_SUPPORT | ATOM_DEVICE_TV_SUPPORT))) { 1595ad43ddacSmrg if (IS_AVIVO_VARIANT && (mode->Flags & V_INTERLACE)) 1596ad43ddacSmrg OUTREG(AVIVO_D1MODE_DATA_FORMAT + radeon_crtc->crtc_offset, AVIVO_D1MODE_INTERLEAVE_EN); 1597ad43ddacSmrg } 1598ad43ddacSmrg 1599ad43ddacSmrg if (IS_DCE32_VARIANT && 1600ad43ddacSmrg (!IS_DCE4_VARIANT) && 1601ad43ddacSmrg (radeon_output->active_device & (ATOM_DEVICE_DFP_SUPPORT))) { 1602ad43ddacSmrg radeon_encoder_ptr radeon_encoder = radeon_get_encoder(output); 1603ad43ddacSmrg if (radeon_encoder == NULL) 1604ad43ddacSmrg return; 1605ad43ddacSmrg /* XXX: need to sort out why transmitter control table sometimes sets this to a 1606ad43ddacSmrg * different golden value. 1607ad43ddacSmrg */ 1608ad43ddacSmrg if (radeon_encoder->encoder_id == ENCODER_OBJECT_ID_INTERNAL_UNIPHY2) { 1609ad43ddacSmrg OUTREG(0x7ec4, 0x00824002); 1610ad43ddacSmrg } 1611ad43ddacSmrg } 1612b7e1c893Smrg} 1613b7e1c893Smrg 1614ad43ddacSmrgstatic void 1615ad43ddacSmrgatombios_pick_dig_encoder(xf86OutputPtr output) 1616ad43ddacSmrg{ 1617ad43ddacSmrg xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(output->scrn); 1618ad43ddacSmrg RADEONOutputPrivatePtr radeon_output = output->driver_private; 1619ad43ddacSmrg RADEONInfoPtr info = RADEONPTR(output->scrn); 1620ad43ddacSmrg radeon_encoder_ptr radeon_encoder = NULL; 1621ad43ddacSmrg Bool is_lvtma = FALSE; 1622ad43ddacSmrg int i, mode; 1623ad43ddacSmrg uint32_t dig_enc_use_mask = 0; 1624ad43ddacSmrg 1625ad43ddacSmrg /* non digital encoders don't need a dig block */ 1626ad43ddacSmrg mode = atombios_get_encoder_mode(output); 1627ad43ddacSmrg if (mode == ATOM_ENCODER_MODE_CRT || 1628ad43ddacSmrg mode == ATOM_ENCODER_MODE_TV || 1629ad43ddacSmrg mode == ATOM_ENCODER_MODE_CV) 1630ad43ddacSmrg return; 1631ad43ddacSmrg 1632ad43ddacSmrg if (IS_DCE4_VARIANT) { 1633ad43ddacSmrg radeon_encoder = radeon_get_encoder(output); 1634ad43ddacSmrg 1635ad43ddacSmrg switch (radeon_encoder->encoder_id) { 1636ad43ddacSmrg case ENCODER_OBJECT_ID_INTERNAL_UNIPHY: 1637ad43ddacSmrg if (radeon_output->linkb) 1638ad43ddacSmrg radeon_output->dig_encoder = 1; 1639ad43ddacSmrg else 1640ad43ddacSmrg radeon_output->dig_encoder = 0; 1641ad43ddacSmrg break; 1642ad43ddacSmrg case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1: 1643ad43ddacSmrg if (radeon_output->linkb) 1644ad43ddacSmrg radeon_output->dig_encoder = 3; 1645ad43ddacSmrg else 1646ad43ddacSmrg radeon_output->dig_encoder = 2; 1647ad43ddacSmrg break; 1648ad43ddacSmrg case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2: 1649ad43ddacSmrg if (radeon_output->linkb) 1650ad43ddacSmrg radeon_output->dig_encoder = 5; 1651ad43ddacSmrg else 1652ad43ddacSmrg radeon_output->dig_encoder = 4; 1653ad43ddacSmrg break; 1654ad43ddacSmrg default: 1655ad43ddacSmrg ErrorF("Unknown encoder\n"); 1656ad43ddacSmrg break; 1657ad43ddacSmrg } 1658ad43ddacSmrg return; 1659ad43ddacSmrg } 1660ad43ddacSmrg 1661ad43ddacSmrg if (IS_DCE32_VARIANT) { 1662ad43ddacSmrg RADEONCrtcPrivatePtr radeon_crtc = output->crtc->driver_private; 1663ad43ddacSmrg radeon_output->dig_encoder = radeon_crtc->crtc_id; 1664ad43ddacSmrg return; 1665ad43ddacSmrg } 1666ad43ddacSmrg 1667ad43ddacSmrg for (i = 0; i < xf86_config->num_output; i++) { 1668ad43ddacSmrg xf86OutputPtr test = xf86_config->output[i]; 1669ad43ddacSmrg RADEONOutputPrivatePtr radeon_test = test->driver_private; 1670ad43ddacSmrg radeon_encoder = radeon_get_encoder(test); 1671ad43ddacSmrg 1672ad43ddacSmrg if (!radeon_encoder || !test->crtc) 1673ad43ddacSmrg continue; 1674ad43ddacSmrg 1675ad43ddacSmrg if (output == test && radeon_encoder->encoder_id == ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA) 1676ad43ddacSmrg is_lvtma = TRUE; 1677ad43ddacSmrg if (output != test && (radeon_test->dig_encoder >= 0)) 1678ad43ddacSmrg dig_enc_use_mask |= (1 << radeon_test->dig_encoder); 1679ad43ddacSmrg 1680ad43ddacSmrg } 1681ad43ddacSmrg if (is_lvtma) { 1682ad43ddacSmrg if (dig_enc_use_mask & 0x2) 1683ad43ddacSmrg ErrorF("Need digital encoder 2 for LVTMA and it isn't free - stealing\n"); 1684ad43ddacSmrg radeon_output->dig_encoder = 1; 1685ad43ddacSmrg return; 1686ad43ddacSmrg } 1687ad43ddacSmrg if (!(dig_enc_use_mask & 1)) 1688ad43ddacSmrg radeon_output->dig_encoder = 0; 1689ad43ddacSmrg else 1690ad43ddacSmrg radeon_output->dig_encoder = 1; 1691ad43ddacSmrg} 1692209ff23fSmrgvoid 1693209ff23fSmrgatombios_output_mode_set(xf86OutputPtr output, 1694209ff23fSmrg DisplayModePtr mode, 1695209ff23fSmrg DisplayModePtr adjusted_mode) 1696209ff23fSmrg{ 1697209ff23fSmrg RADEONOutputPrivatePtr radeon_output = output->driver_private; 1698b7e1c893Smrg radeon_encoder_ptr radeon_encoder = radeon_get_encoder(output); 1699209ff23fSmrg RADEONInfoPtr info = RADEONPTR(output->scrn); 1700b7e1c893Smrg if (radeon_encoder == NULL) 1701ad43ddacSmrg return; 1702209ff23fSmrg 1703b7e1c893Smrg radeon_output->pixel_clock = adjusted_mode->Clock; 1704ad43ddacSmrg atombios_pick_dig_encoder(output); 1705b7e1c893Smrg atombios_output_overscan_setup(output, mode, adjusted_mode); 1706b7e1c893Smrg atombios_output_scaler_setup(output); 1707209ff23fSmrg atombios_set_output_crtc_source(output); 1708209ff23fSmrg 17090974d292Smrg if (IS_AVIVO_VARIANT && !IS_DCE4_VARIANT) { 1710b7e1c893Smrg if (radeon_output->active_device & (ATOM_DEVICE_CV_SUPPORT | ATOM_DEVICE_TV_SUPPORT)) 1711b7e1c893Smrg atombios_output_yuv_setup(output, TRUE); 1712b7e1c893Smrg else 1713b7e1c893Smrg atombios_output_yuv_setup(output, FALSE); 1714209ff23fSmrg } 1715209ff23fSmrg 1716b7e1c893Smrg switch (radeon_encoder->encoder_id) { 1717b7e1c893Smrg case ENCODER_OBJECT_ID_INTERNAL_TMDS1: 1718b7e1c893Smrg case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1: 1719b7e1c893Smrg case ENCODER_OBJECT_ID_INTERNAL_LVDS: 1720b7e1c893Smrg case ENCODER_OBJECT_ID_INTERNAL_LVTM1: 1721b7e1c893Smrg atombios_output_digital_setup(output, PANEL_ENCODER_ACTION_ENABLE); 1722b7e1c893Smrg break; 1723b7e1c893Smrg case ENCODER_OBJECT_ID_INTERNAL_UNIPHY: 1724b7e1c893Smrg case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1: 1725b7e1c893Smrg case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2: 1726b7e1c893Smrg case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA: 1727b7e1c893Smrg /* disable encoder and transmitter */ 1728b7e1c893Smrg /* setup and enable the encoder and transmitter */ 17290974d292Smrg if (IS_DCE4_VARIANT) { 17300974d292Smrg atombios_output_dig_transmitter_setup(output, ATOM_TRANSMITTER_ACTION_DISABLE, 0, 0); 17310974d292Smrg atombios_output_dig_encoder_setup(output, ATOM_ENCODER_CMD_SETUP); 17320974d292Smrg atombios_output_dig_transmitter_setup(output, ATOM_TRANSMITTER_ACTION_INIT, 0, 0); 17330974d292Smrg atombios_output_dig_transmitter_setup(output, ATOM_TRANSMITTER_ACTION_ENABLE, 0, 0); 17340974d292Smrg } else { 17350974d292Smrg atombios_output_dig_transmitter_setup(output, ATOM_TRANSMITTER_ACTION_DISABLE, 0, 0); 1736ad43ddacSmrg atombios_output_dig_encoder_setup(output, ATOM_DISABLE); 1737ad43ddacSmrg atombios_output_dig_encoder_setup(output, ATOM_ENABLE); 17380974d292Smrg 17390974d292Smrg atombios_output_dig_transmitter_setup(output, ATOM_TRANSMITTER_ACTION_INIT, 0, 0); 17400974d292Smrg atombios_output_dig_transmitter_setup(output, ATOM_TRANSMITTER_ACTION_SETUP, 0, 0); 17410974d292Smrg atombios_output_dig_transmitter_setup(output, ATOM_TRANSMITTER_ACTION_ENABLE, 0, 0); 1742ad43ddacSmrg } 1743b7e1c893Smrg break; 1744b7e1c893Smrg case ENCODER_OBJECT_ID_INTERNAL_DDI: 1745b7e1c893Smrg atombios_output_ddia_setup(output, ATOM_ENABLE); 1746b7e1c893Smrg break; 1747b7e1c893Smrg case ENCODER_OBJECT_ID_INTERNAL_DVO1: 1748b7e1c893Smrg case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1: 1749b7e1c893Smrg atombios_external_tmds_setup(output, ATOM_ENABLE); 1750b7e1c893Smrg break; 1751b7e1c893Smrg case ENCODER_OBJECT_ID_INTERNAL_DAC1: 1752b7e1c893Smrg case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1: 1753b7e1c893Smrg case ENCODER_OBJECT_ID_INTERNAL_DAC2: 1754b7e1c893Smrg case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC2: 1755b7e1c893Smrg atombios_output_dac_setup(output, ATOM_ENABLE); 17562f39173dSmrg if (radeon_output->devices & (ATOM_DEVICE_TV_SUPPORT | ATOM_DEVICE_CV_SUPPORT)) { 17572f39173dSmrg if (radeon_output->active_device & (ATOM_DEVICE_TV_SUPPORT | ATOM_DEVICE_CV_SUPPORT)) 17582f39173dSmrg atombios_output_tv_setup(output, ATOM_ENABLE); 17592f39173dSmrg else 17602f39173dSmrg atombios_output_tv_setup(output, ATOM_DISABLE); 17612f39173dSmrg } 1762b7e1c893Smrg break; 1763b7e1c893Smrg } 1764b7e1c893Smrg atombios_apply_output_quirks(output, adjusted_mode); 1765209ff23fSmrg} 1766209ff23fSmrg 1767209ff23fSmrgstatic AtomBiosResult 1768209ff23fSmrgatom_bios_dac_load_detect(atomBiosHandlePtr atomBIOS, xf86OutputPtr output) 1769209ff23fSmrg{ 1770209ff23fSmrg RADEONOutputPrivatePtr radeon_output = output->driver_private; 1771209ff23fSmrg RADEONInfoPtr info = RADEONPTR(output->scrn); 1772209ff23fSmrg DAC_LOAD_DETECTION_PS_ALLOCATION dac_data; 1773209ff23fSmrg AtomBiosArgRec data; 1774209ff23fSmrg unsigned char *space; 1775b7e1c893Smrg int major, minor; 1776b7e1c893Smrg int index = GetIndexIntoMasterTable(COMMAND, DAC_LoadDetection); 1777b7e1c893Smrg 1778b7e1c893Smrg atombios_get_command_table_version(info->atomBIOS, index, &major, &minor); 1779209ff23fSmrg 1780209ff23fSmrg dac_data.sDacload.ucMisc = 0; 1781209ff23fSmrg 1782209ff23fSmrg if (radeon_output->devices & ATOM_DEVICE_CRT1_SUPPORT) { 1783b7e1c893Smrg dac_data.sDacload.usDeviceID = cpu_to_le16(ATOM_DEVICE_CRT1_SUPPORT); 1784b7e1c893Smrg if (info->encoders[ATOM_DEVICE_CRT1_INDEX] && 1785b7e1c893Smrg ((info->encoders[ATOM_DEVICE_CRT1_INDEX]->encoder_id == ENCODER_OBJECT_ID_INTERNAL_DAC1) || 1786b7e1c893Smrg (info->encoders[ATOM_DEVICE_CRT1_INDEX]->encoder_id == ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1))) 1787209ff23fSmrg dac_data.sDacload.ucDacType = ATOM_DAC_A; 1788b7e1c893Smrg else 1789209ff23fSmrg dac_data.sDacload.ucDacType = ATOM_DAC_B; 1790209ff23fSmrg } else if (radeon_output->devices & ATOM_DEVICE_CRT2_SUPPORT) { 1791b7e1c893Smrg dac_data.sDacload.usDeviceID = cpu_to_le16(ATOM_DEVICE_CRT2_SUPPORT); 1792b7e1c893Smrg if (info->encoders[ATOM_DEVICE_CRT2_INDEX] && 1793b7e1c893Smrg ((info->encoders[ATOM_DEVICE_CRT2_INDEX]->encoder_id == ENCODER_OBJECT_ID_INTERNAL_DAC1) || 1794b7e1c893Smrg (info->encoders[ATOM_DEVICE_CRT2_INDEX]->encoder_id == ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1))) 1795209ff23fSmrg dac_data.sDacload.ucDacType = ATOM_DAC_A; 1796b7e1c893Smrg else 1797209ff23fSmrg dac_data.sDacload.ucDacType = ATOM_DAC_B; 1798209ff23fSmrg } else if (radeon_output->devices & ATOM_DEVICE_CV_SUPPORT) { 1799b7e1c893Smrg dac_data.sDacload.usDeviceID = cpu_to_le16(ATOM_DEVICE_CV_SUPPORT); 1800b7e1c893Smrg if (info->encoders[ATOM_DEVICE_CV_INDEX] && 1801b7e1c893Smrg ((info->encoders[ATOM_DEVICE_CV_INDEX]->encoder_id == ENCODER_OBJECT_ID_INTERNAL_DAC1) || 1802b7e1c893Smrg (info->encoders[ATOM_DEVICE_CV_INDEX]->encoder_id == ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1))) 1803209ff23fSmrg dac_data.sDacload.ucDacType = ATOM_DAC_A; 1804b7e1c893Smrg else 1805209ff23fSmrg dac_data.sDacload.ucDacType = ATOM_DAC_B; 1806b7e1c893Smrg if (minor >= 3) 1807b7e1c893Smrg dac_data.sDacload.ucMisc = DAC_LOAD_MISC_YPrPb; 1808209ff23fSmrg } else if (radeon_output->devices & ATOM_DEVICE_TV1_SUPPORT) { 1809b7e1c893Smrg dac_data.sDacload.usDeviceID = cpu_to_le16(ATOM_DEVICE_TV1_SUPPORT); 1810b7e1c893Smrg if (info->encoders[ATOM_DEVICE_TV1_INDEX] && 1811b7e1c893Smrg ((info->encoders[ATOM_DEVICE_TV1_INDEX]->encoder_id == ENCODER_OBJECT_ID_INTERNAL_DAC1) || 1812b7e1c893Smrg (info->encoders[ATOM_DEVICE_TV1_INDEX]->encoder_id == ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1))) 1813209ff23fSmrg dac_data.sDacload.ucDacType = ATOM_DAC_A; 1814b7e1c893Smrg else 1815209ff23fSmrg dac_data.sDacload.ucDacType = ATOM_DAC_B; 1816b7e1c893Smrg if (minor >= 3) 1817b7e1c893Smrg dac_data.sDacload.ucMisc = DAC_LOAD_MISC_YPrPb; 1818b7e1c893Smrg } else 1819209ff23fSmrg return ATOM_NOT_IMPLEMENTED; 1820209ff23fSmrg 1821b7e1c893Smrg data.exec.index = index; 1822209ff23fSmrg data.exec.dataSpace = (void *)&space; 1823209ff23fSmrg data.exec.pspace = &dac_data; 1824209ff23fSmrg 1825209ff23fSmrg if (RHDAtomBiosFunc(atomBIOS->scrnIndex, atomBIOS, ATOMBIOS_EXEC, &data) == ATOM_SUCCESS) { 1826209ff23fSmrg ErrorF("Dac detection success\n"); 1827209ff23fSmrg return ATOM_SUCCESS ; 1828209ff23fSmrg } 1829209ff23fSmrg 1830209ff23fSmrg ErrorF("DAC detection failed\n"); 1831209ff23fSmrg return ATOM_NOT_IMPLEMENTED; 1832209ff23fSmrg} 1833209ff23fSmrg 1834209ff23fSmrgRADEONMonitorType 1835b7e1c893Smrgatombios_dac_detect(xf86OutputPtr output) 1836209ff23fSmrg{ 1837b7e1c893Smrg ScrnInfoPtr pScrn = output->scrn; 1838209ff23fSmrg RADEONInfoPtr info = RADEONPTR(pScrn); 1839209ff23fSmrg unsigned char *RADEONMMIO = info->MMIO; 1840209ff23fSmrg RADEONOutputPrivatePtr radeon_output = output->driver_private; 1841209ff23fSmrg RADEONMonitorType MonType = MT_NONE; 1842209ff23fSmrg AtomBiosResult ret; 1843c503f109Smrg RADEONSavePtr save = info->ModeReg; 1844209ff23fSmrg 1845b7e1c893Smrg if (radeon_output->devices & ATOM_DEVICE_TV1_SUPPORT) { 1846209ff23fSmrg if (xf86ReturnOptValBool(info->Options, OPTION_FORCE_TVOUT, FALSE)) { 1847b7e1c893Smrg if (radeon_output->ConnectorType == CONNECTOR_STV) 1848209ff23fSmrg return MT_STV; 1849209ff23fSmrg else 1850209ff23fSmrg return MT_CTV; 1851209ff23fSmrg } 1852209ff23fSmrg } 1853209ff23fSmrg 1854209ff23fSmrg ret = atom_bios_dac_load_detect(info->atomBIOS, output); 1855209ff23fSmrg if (ret == ATOM_SUCCESS) { 1856209ff23fSmrg if (info->ChipFamily >= CHIP_FAMILY_R600) 1857c503f109Smrg save->bios_0_scratch = INREG(R600_BIOS_0_SCRATCH); 1858209ff23fSmrg else 1859c503f109Smrg save->bios_0_scratch = INREG(RADEON_BIOS_0_SCRATCH); 1860c503f109Smrg /*ErrorF("DAC connect %08X\n", (unsigned int)save->bios_0_scratch);*/ 1861209ff23fSmrg 1862209ff23fSmrg if (radeon_output->devices & ATOM_DEVICE_CRT1_SUPPORT) { 1863c503f109Smrg if (save->bios_0_scratch & ATOM_S0_CRT1_MASK) 1864209ff23fSmrg MonType = MT_CRT; 1865209ff23fSmrg } else if (radeon_output->devices & ATOM_DEVICE_CRT2_SUPPORT) { 1866c503f109Smrg if (save->bios_0_scratch & ATOM_S0_CRT2_MASK) 1867209ff23fSmrg MonType = MT_CRT; 1868209ff23fSmrg } else if (radeon_output->devices & ATOM_DEVICE_CV_SUPPORT) { 1869c503f109Smrg if (save->bios_0_scratch & (ATOM_S0_CV_MASK | ATOM_S0_CV_MASK_A)) 1870209ff23fSmrg MonType = MT_CV; 1871209ff23fSmrg } else if (radeon_output->devices & ATOM_DEVICE_TV1_SUPPORT) { 1872c503f109Smrg if (save->bios_0_scratch & (ATOM_S0_TV1_COMPOSITE | ATOM_S0_TV1_COMPOSITE_A)) 1873209ff23fSmrg MonType = MT_CTV; 1874c503f109Smrg else if (save->bios_0_scratch & (ATOM_S0_TV1_SVIDEO | ATOM_S0_TV1_SVIDEO_A)) 1875209ff23fSmrg MonType = MT_STV; 1876209ff23fSmrg } 1877209ff23fSmrg } 1878209ff23fSmrg 1879209ff23fSmrg return MonType; 1880209ff23fSmrg} 1881209ff23fSmrg 1882ad43ddacSmrg#define AUX_NATIVE_WRITE 0x8 1883ad43ddacSmrg#define AUX_NATIVE_READ 0x9 1884ad43ddacSmrg 1885ad43ddacSmrg#define AUX_I2C_WRITE 0x0 1886ad43ddacSmrg#define AUX_I2C_READ 0x1 1887ad43ddacSmrg#define AUX_I2C_STATUS 0x2 1888ad43ddacSmrg#define AUX_I2C_MOT 0x4 1889ad43ddacSmrg 1890ad43ddacSmrg#define DP_DPCD_REV 0x0 1891ad43ddacSmrg#define DP_MAX_LINK_RATE 0x1 1892ad43ddacSmrg#define DP_MAX_LANE_COUNT 0x2 1893ad43ddacSmrg#define DP_MAX_DOWNSPREAD 0x3 1894ad43ddacSmrg#define DP_NORP 0x4 1895ad43ddacSmrg#define DP_DOWNSTREAMPORT_PRESENT 0x5 1896ad43ddacSmrg#define DP_MAIN_LINK_CHANNEL_CONFIG 0x6 1897ad43ddacSmrg#define DP_DP11_DOWNSTREAM_PORT_COUNT 0x7 1898ad43ddacSmrg 1899ad43ddacSmrg/* from intel i830_dp.h */ 1900ad43ddacSmrg#define DP_LINK_BW_SET 0x100 1901ad43ddacSmrg//# define DP_LINK_BW_1_62 0x06 1902ad43ddacSmrg//# define DP_LINK_BW_2_7 0x0a 1903ad43ddacSmrg#define DP_LANE_COUNT_SET 0x101 1904ad43ddacSmrg# define DP_LANE_COUNT_MASK 0x0f 1905ad43ddacSmrg# define DP_LANE_COUNT_ENHANCED_FRAME_EN (1 << 7) 1906ad43ddacSmrg 1907ad43ddacSmrg#define DP_TRAINING_PATTERN_SET 0x102 1908ad43ddacSmrg 1909ad43ddacSmrg# define DP_TRAINING_PATTERN_DISABLE 0 1910ad43ddacSmrg# define DP_TRAINING_PATTERN_1 1 1911ad43ddacSmrg# define DP_TRAINING_PATTERN_2 2 1912ad43ddacSmrg# define DP_TRAINING_PATTERN_MASK 0x3 1913ad43ddacSmrg 1914ad43ddacSmrg# define DP_LINK_QUAL_PATTERN_DISABLE (0 << 2) 1915ad43ddacSmrg# define DP_LINK_QUAL_PATTERN_D10_2 (1 << 2) 1916ad43ddacSmrg# define DP_LINK_QUAL_PATTERN_ERROR_RATE (2 << 2) 1917ad43ddacSmrg# define DP_LINK_QUAL_PATTERN_PRBS7 (3 << 2) 1918ad43ddacSmrg# define DP_LINK_QUAL_PATTERN_MASK (3 << 2) 1919ad43ddacSmrg# define DP_RECOVERED_CLOCK_OUT_EN (1 << 4) 1920ad43ddacSmrg# define DP_LINK_SCRAMBLING_DISABLE (1 << 5) 1921ad43ddacSmrg 1922ad43ddacSmrg# define DP_SYMBOL_ERROR_COUNT_BOTH (0 << 6) 1923ad43ddacSmrg# define DP_SYMBOL_ERROR_COUNT_DISPARITY (1 << 6) 1924ad43ddacSmrg# define DP_SYMBOL_ERROR_COUNT_SYMBOL (2 << 6) 1925ad43ddacSmrg# define DP_SYMBOL_ERROR_COUNT_MASK (3 << 6) 1926ad43ddacSmrg 1927ad43ddacSmrg#define DP_TRAINING_LANE0_SET 0x103 1928ad43ddacSmrg#define DP_TRAINING_LANE1_SET 0x104 1929ad43ddacSmrg#define DP_TRAINING_LANE2_SET 0x105 1930ad43ddacSmrg#define DP_TRAINING_LANE3_SET 0x106 1931ad43ddacSmrg# define DP_TRAIN_VOLTAGE_SWING_MASK 0x3 1932ad43ddacSmrg# define DP_TRAIN_VOLTAGE_SWING_SHIFT 0 1933ad43ddacSmrg# define DP_TRAIN_MAX_SWING_REACHED (1 << 2) 1934ad43ddacSmrg# define DP_TRAIN_VOLTAGE_SWING_400 (0 << 0) 1935ad43ddacSmrg# define DP_TRAIN_VOLTAGE_SWING_600 (1 << 0) 1936ad43ddacSmrg# define DP_TRAIN_VOLTAGE_SWING_800 (2 << 0) 1937ad43ddacSmrg# define DP_TRAIN_VOLTAGE_SWING_1200 (3 << 0) 1938ad43ddacSmrg 1939ad43ddacSmrg# define DP_TRAIN_PRE_EMPHASIS_MASK (3 << 3) 1940ad43ddacSmrg# define DP_TRAIN_PRE_EMPHASIS_0 (0 << 3) 1941ad43ddacSmrg# define DP_TRAIN_PRE_EMPHASIS_3_5 (1 << 3) 1942ad43ddacSmrg# define DP_TRAIN_PRE_EMPHASIS_6 (2 << 3) 1943ad43ddacSmrg# define DP_TRAIN_PRE_EMPHASIS_9_5 (3 << 3) 1944ad43ddacSmrg 1945ad43ddacSmrg# define DP_TRAIN_PRE_EMPHASIS_SHIFT 3 1946ad43ddacSmrg# define DP_TRAIN_MAX_PRE_EMPHASIS_REACHED (1 << 5) 1947ad43ddacSmrg#define DP_DOWNSPREAD_CTRL 0x107 1948ad43ddacSmrg# define DP_SPREAD_AMP_0_5 (1 << 4) 1949ad43ddacSmrg 1950ad43ddacSmrg#define DP_MAIN_LINK_CHANNEL_CODING_SET 0x108 1951ad43ddacSmrg# define DP_SET_ANSI_8B10B (1 << 0) 1952ad43ddacSmrg 1953ad43ddacSmrg#define DP_LANE0_1_STATUS 0x202 1954ad43ddacSmrg#define DP_LANE2_3_STATUS 0x203 1955ad43ddacSmrg 1956ad43ddacSmrg# define DP_LANE_CR_DONE (1 << 0) 1957ad43ddacSmrg# define DP_LANE_CHANNEL_EQ_DONE (1 << 1) 1958ad43ddacSmrg# define DP_LANE_SYMBOL_LOCKED (1 << 2) 1959ad43ddacSmrg 1960ad43ddacSmrg#define DP_LANE_ALIGN_STATUS_UPDATED 0x204 1961ad43ddacSmrg#define DP_INTERLANE_ALIGN_DONE (1 << 0) 1962ad43ddacSmrg#define DP_DOWNSTREAM_PORT_STATUS_CHANGED (1 << 6) 1963ad43ddacSmrg#define DP_LINK_STATUS_UPDATED (1 << 7) 1964ad43ddacSmrg 1965ad43ddacSmrg#define DP_SINK_STATUS 0x205 1966ad43ddacSmrg 1967ad43ddacSmrg#define DP_RECEIVE_PORT_0_STATUS (1 << 0) 1968ad43ddacSmrg#define DP_RECEIVE_PORT_1_STATUS (1 << 1) 1969ad43ddacSmrg 1970ad43ddacSmrg#define DP_ADJUST_REQUEST_LANE0_1 0x206 1971ad43ddacSmrg#define DP_ADJUST_REQUEST_LANE2_3 0x207 1972ad43ddacSmrg 1973ad43ddacSmrg#define DP_ADJUST_VOLTAGE_SWING_LANE0_MASK 0x03 1974ad43ddacSmrg#define DP_ADJUST_VOLTAGE_SWING_LANE0_SHIFT 0 1975ad43ddacSmrg#define DP_ADJUST_PRE_EMPHASIS_LANE0_MASK 0x0c 1976ad43ddacSmrg#define DP_ADJUST_PRE_EMPHASIS_LANE0_SHIFT 2 1977ad43ddacSmrg#define DP_ADJUST_VOLTAGE_SWING_LANE1_MASK 0x30 1978ad43ddacSmrg#define DP_ADJUST_VOLTAGE_SWING_LANE1_SHIFT 4 1979ad43ddacSmrg#define DP_ADJUST_PRE_EMPHASIS_LANE1_MASK 0xc0 1980ad43ddacSmrg#define DP_ADJUST_PRE_EMPHASIS_LANE1_SHIFT 6 1981ad43ddacSmrg 1982ad43ddacSmrg#define DP_LINK_STATUS_SIZE 6 1983ad43ddacSmrg#define DP_LINK_CONFIGURATION_SIZE 9 1984ad43ddacSmrg 1985ad43ddacSmrg#define DP_SET_POWER_D0 0x1 1986ad43ddacSmrg#define DP_SET_POWER_D3 0x2 1987ad43ddacSmrg 1988ad43ddacSmrgstatic inline int atom_dp_get_encoder_id(xf86OutputPtr output) 1989ad43ddacSmrg{ 1990ad43ddacSmrg RADEONOutputPrivatePtr radeon_output = output->driver_private; 1991ad43ddacSmrg int ret = 0; 1992ad43ddacSmrg if (radeon_output->dig_encoder) 1993ad43ddacSmrg ret |= ATOM_DP_CONFIG_DIG2_ENCODER; 1994ad43ddacSmrg else 1995ad43ddacSmrg ret |= ATOM_DP_CONFIG_DIG1_ENCODER; 1996ad43ddacSmrg if (radeon_output->linkb) 1997ad43ddacSmrg ret |= ATOM_DP_CONFIG_LINK_B; 1998ad43ddacSmrg else 1999ad43ddacSmrg ret |= ATOM_DP_CONFIG_LINK_A; 2000ad43ddacSmrg return ret; 2001ad43ddacSmrg} 2002ad43ddacSmrg 2003ad43ddacSmrgunion aux_channel_transaction { 2004ad43ddacSmrg PROCESS_AUX_CHANNEL_TRANSACTION_PS_ALLOCATION v1; 2005ad43ddacSmrg PROCESS_AUX_CHANNEL_TRANSACTION_PARAMETERS_V2 v2; 2006ad43ddacSmrg}; 2007ad43ddacSmrg 2008ad43ddacSmrgBool 2009ad43ddacSmrgRADEONProcessAuxCH(xf86OutputPtr output, uint8_t *req_bytes, uint8_t num_bytes, 2010ad43ddacSmrg uint8_t *read_byte, uint8_t read_buf_len, uint8_t delay) 2011ad43ddacSmrg{ 2012ad43ddacSmrg RADEONOutputPrivatePtr radeon_output = output->driver_private; 2013ad43ddacSmrg RADEONInfoPtr info = RADEONPTR(output->scrn); 2014ad43ddacSmrg union aux_channel_transaction args; 2015ad43ddacSmrg AtomBiosArgRec data; 2016ad43ddacSmrg unsigned char *space; 2017ad43ddacSmrg unsigned char *base; 20180974d292Smrg int retry_count = 0; 2019ad43ddacSmrg 2020ad43ddacSmrg memset(&args, 0, sizeof(args)); 2021ad43ddacSmrg if (info->atomBIOS->fbBase) 2022ad43ddacSmrg base = info->FB + info->atomBIOS->fbBase; 2023ad43ddacSmrg else if (info->atomBIOS->scratchBase) 2024ad43ddacSmrg base = (unsigned char *)info->atomBIOS->scratchBase; 2025ad43ddacSmrg else 2026ad43ddacSmrg return FALSE; 2027ad43ddacSmrg 20280974d292Smrgretry: 2029ad43ddacSmrg memcpy(base, req_bytes, num_bytes); 2030ad43ddacSmrg 2031ad43ddacSmrg args.v1.lpAuxRequest = 0; 2032ad43ddacSmrg args.v1.lpDataOut = 16; 2033ad43ddacSmrg args.v1.ucDataOutLen = 0; 2034ad43ddacSmrg args.v1.ucChannelID = radeon_output->ucI2cId; 2035ad43ddacSmrg args.v1.ucDelay = delay / 10; /* 10 usec */ 2036ad43ddacSmrg if (IS_DCE4_VARIANT) 2037ad43ddacSmrg args.v2.ucHPD_ID = radeon_output->hpd_id; 2038ad43ddacSmrg 2039ad43ddacSmrg data.exec.index = GetIndexIntoMasterTable(COMMAND, ProcessAuxChannelTransaction); 2040ad43ddacSmrg data.exec.dataSpace = (void *)&space; 2041ad43ddacSmrg data.exec.pspace = &args; 2042ad43ddacSmrg 2043ad43ddacSmrg RHDAtomBiosFunc(info->atomBIOS->scrnIndex, info->atomBIOS, ATOMBIOS_EXEC, &data); 20440974d292Smrg if (args.v1.ucReplyStatus && !args.v1.ucDataOutLen) { 20450974d292Smrg if (args.v1.ucReplyStatus == 0x20 && retry_count++ < 10) 20460974d292Smrg goto retry; 20470974d292Smrg ErrorF("failed to get auxch %02x%02x %02x %02x %02x after %d retries\n", 20480974d292Smrg req_bytes[1], req_bytes[0], req_bytes[2], req_bytes[3], args.v1.ucReplyStatus, retry_count); 2049ad43ddacSmrg return FALSE; 2050ad43ddacSmrg } 2051ad43ddacSmrg if (args.v1.ucDataOutLen && read_byte && read_buf_len) { 2052ad43ddacSmrg if (read_buf_len < args.v1.ucDataOutLen) { 2053ad43ddacSmrg ErrorF("%s: Buffer too small for return answer %d %d\n", __func__, read_buf_len, args.v1.ucDataOutLen); 2054ad43ddacSmrg return FALSE; 2055ad43ddacSmrg } 2056ad43ddacSmrg { 2057ad43ddacSmrg int len = read_buf_len < args.v1.ucDataOutLen ? read_buf_len : args.v1.ucDataOutLen; 2058ad43ddacSmrg memcpy(read_byte, base+16, len); 2059ad43ddacSmrg } 2060ad43ddacSmrg } 2061ad43ddacSmrg return TRUE; 2062ad43ddacSmrg} 2063ad43ddacSmrg 2064ad43ddacSmrgstatic int 2065ad43ddacSmrgRADEONDPEncoderService(xf86OutputPtr output, int action, uint8_t ucconfig, uint8_t lane_num) 2066ad43ddacSmrg{ 2067ad43ddacSmrg RADEONInfoPtr info = RADEONPTR(output->scrn); 2068ad43ddacSmrg DP_ENCODER_SERVICE_PARAMETERS args; 2069ad43ddacSmrg AtomBiosArgRec data; 2070ad43ddacSmrg unsigned char *space; 2071ad43ddacSmrg 2072ad43ddacSmrg memset(&args, 0, sizeof(args)); 2073ad43ddacSmrg 2074ad43ddacSmrg args.ucLinkClock = 0; 2075ad43ddacSmrg args.ucConfig = ucconfig; 2076ad43ddacSmrg args.ucAction = action; 2077ad43ddacSmrg args.ucLaneNum = lane_num; 2078ad43ddacSmrg args.ucStatus = 0; 2079ad43ddacSmrg 2080ad43ddacSmrg data.exec.index = GetIndexIntoMasterTable(COMMAND, DPEncoderService); 2081ad43ddacSmrg data.exec.dataSpace = (void *)&space; 2082ad43ddacSmrg data.exec.pspace = &args; 2083ad43ddacSmrg 2084ad43ddacSmrg RHDAtomBiosFunc(info->atomBIOS->scrnIndex, info->atomBIOS, ATOMBIOS_EXEC, &data); 2085ad43ddacSmrg 20860974d292Smrg ErrorF("%s: %d %d\n", __func__, action, args.ucStatus); 2087ad43ddacSmrg return args.ucStatus; 2088ad43ddacSmrg} 2089ad43ddacSmrg 2090ad43ddacSmrgint RADEON_DP_GetSinkType(xf86OutputPtr output) 2091ad43ddacSmrg{ 2092ad43ddacSmrg RADEONOutputPrivatePtr radeon_output = output->driver_private; 2093ad43ddacSmrg 2094ad43ddacSmrg return RADEONDPEncoderService(output, ATOM_DP_ACTION_GET_SINK_TYPE, radeon_output->ucI2cId, 0); 2095ad43ddacSmrg} 2096ad43ddacSmrg 2097ad43ddacSmrgstatic Bool atom_dp_aux_native_write(xf86OutputPtr output, uint16_t address, 2098ad43ddacSmrg uint8_t send_bytes, uint8_t *send) 2099ad43ddacSmrg{ 2100ad43ddacSmrg uint8_t msg[20]; 2101ad43ddacSmrg uint8_t msg_len, dp_msg_len; 2102ad43ddacSmrg int ret; 2103ad43ddacSmrg 2104ad43ddacSmrg dp_msg_len = 4; 2105ad43ddacSmrg msg[0] = address; 2106ad43ddacSmrg msg[1] = address >> 8; 2107ad43ddacSmrg msg[2] = AUX_NATIVE_WRITE << 4; 2108ad43ddacSmrg dp_msg_len += send_bytes; 2109ad43ddacSmrg msg[3] = (dp_msg_len << 4)| (send_bytes - 1); 2110ad43ddacSmrg 2111ad43ddacSmrg if (0) 2112ad43ddacSmrg ErrorF("writing %02x %02x %02x, %d, %d\n", msg[0], msg[1], msg[3], send_bytes, dp_msg_len); 2113ad43ddacSmrg if (send_bytes > 16) 2114ad43ddacSmrg return FALSE; 2115ad43ddacSmrg 2116ad43ddacSmrg memcpy(&msg[4], send, send_bytes); 2117ad43ddacSmrg msg_len = 4 + send_bytes; 2118ad43ddacSmrg ret = RADEONProcessAuxCH(output, msg, msg_len, NULL, 0, 0); 2119ad43ddacSmrg return ret; 2120ad43ddacSmrg} 2121ad43ddacSmrg 2122ad43ddacSmrgstatic Bool atom_dp_aux_native_read(xf86OutputPtr output, uint16_t address, 2123ad43ddacSmrg uint8_t delay, 2124ad43ddacSmrg uint8_t expected_bytes, uint8_t *read_p) 2125ad43ddacSmrg{ 2126ad43ddacSmrg uint8_t msg[20]; 2127ad43ddacSmrg uint8_t msg_len, dp_msg_len; 2128ad43ddacSmrg int ret; 2129ad43ddacSmrg 2130ad43ddacSmrg msg_len = 4; 2131ad43ddacSmrg dp_msg_len = 4; 2132ad43ddacSmrg msg[0] = address; 2133ad43ddacSmrg msg[1] = address >> 8; 2134ad43ddacSmrg msg[2] = AUX_NATIVE_READ << 4; 2135ad43ddacSmrg msg[3] = (dp_msg_len) << 4; 2136ad43ddacSmrg msg[3] |= expected_bytes - 1; 2137ad43ddacSmrg 2138ad43ddacSmrg if (0) 2139ad43ddacSmrg ErrorF("reading %02x %02x %02x, %d, %d\n", msg[0], msg[1], msg[3], expected_bytes, dp_msg_len); 2140ad43ddacSmrg ret = RADEONProcessAuxCH(output, msg, msg_len, read_p, expected_bytes, delay); 2141ad43ddacSmrg return ret; 2142ad43ddacSmrg} 2143ad43ddacSmrg 2144ad43ddacSmrg/* fill out the DPCD structure */ 2145ad43ddacSmrgvoid RADEON_DP_GetDPCD(xf86OutputPtr output) 2146ad43ddacSmrg{ 2147ad43ddacSmrg RADEONOutputPrivatePtr radeon_output = output->driver_private; 2148ad43ddacSmrg uint8_t msg[25]; 2149ad43ddacSmrg int ret; 2150ad43ddacSmrg 2151ad43ddacSmrg ret = atom_dp_aux_native_read(output, DP_DPCD_REV, 0, 8, msg); 2152ad43ddacSmrg if (ret) { 2153ad43ddacSmrg memcpy(radeon_output->dpcd, msg, 8); 2154ad43ddacSmrg if (0) { 2155ad43ddacSmrg int i; 2156ad43ddacSmrg ErrorF("DPCD: "); 2157ad43ddacSmrg for (i = 0; i < 8; i++) 2158ad43ddacSmrg ErrorF("%02x ", radeon_output->dpcd[i]); 2159ad43ddacSmrg ErrorF("\n"); 2160ad43ddacSmrg } 2161ad43ddacSmrg ret = atom_dp_aux_native_read(output, DP_LINK_BW_SET, 0, 2, msg); 2162ad43ddacSmrg if (0) { 2163ad43ddacSmrg ErrorF("0x200: %02x %02x\n", msg[0], msg[1]); 2164ad43ddacSmrg } 2165ad43ddacSmrg return; 2166ad43ddacSmrg } 2167ad43ddacSmrg radeon_output->dpcd[0] = 0; 2168ad43ddacSmrg return; 2169ad43ddacSmrg} 2170ad43ddacSmrg 2171ad43ddacSmrg 2172ad43ddacSmrgenum dp_aux_i2c_mode { 2173ad43ddacSmrg dp_aux_i2c_start, 2174ad43ddacSmrg dp_aux_i2c_write, 2175ad43ddacSmrg dp_aux_i2c_read, 2176ad43ddacSmrg dp_aux_i2c_stop, 2177ad43ddacSmrg}; 2178ad43ddacSmrg 2179ad43ddacSmrg 2180ad43ddacSmrgstatic Bool atom_dp_aux_i2c_transaction(xf86OutputPtr output, uint16_t address, 2181ad43ddacSmrg enum dp_aux_i2c_mode mode, 2182ad43ddacSmrg uint8_t write_byte, uint8_t *read_byte) 2183ad43ddacSmrg{ 2184ad43ddacSmrg uint8_t msg[8], msg_len, dp_msg_len; 2185ad43ddacSmrg int ret; 2186ad43ddacSmrg int auxch_cmd = 0; 2187ad43ddacSmrg 2188ad43ddacSmrg memset(msg, 0, 8); 2189ad43ddacSmrg 2190ad43ddacSmrg if (mode != dp_aux_i2c_stop) 2191ad43ddacSmrg auxch_cmd = AUX_I2C_MOT; 2192ad43ddacSmrg 2193ad43ddacSmrg if (address & 1) 2194ad43ddacSmrg auxch_cmd |= AUX_I2C_READ; 2195ad43ddacSmrg else 2196ad43ddacSmrg auxch_cmd |= AUX_I2C_WRITE; 2197ad43ddacSmrg 2198ad43ddacSmrg msg[2] = auxch_cmd << 4; 2199ad43ddacSmrg 2200ad43ddacSmrg msg[4] = 0; 2201ad43ddacSmrg msg[0] = (address >> 1); 2202ad43ddacSmrg msg[1] = (address >> 9); 2203ad43ddacSmrg 2204ad43ddacSmrg msg_len = 4; 2205ad43ddacSmrg dp_msg_len = 3; 2206ad43ddacSmrg switch (mode) { 2207ad43ddacSmrg case dp_aux_i2c_read: 2208ad43ddacSmrg /* bottom bits is byte count - 1 so for 1 byte == 0 */ 2209ad43ddacSmrg dp_msg_len += 1; 2210ad43ddacSmrg break; 2211ad43ddacSmrg case dp_aux_i2c_write: 2212ad43ddacSmrg dp_msg_len += 2; 2213ad43ddacSmrg msg[4] = write_byte; 2214ad43ddacSmrg msg_len++; 2215ad43ddacSmrg break; 2216ad43ddacSmrg default: 2217ad43ddacSmrg break; 2218ad43ddacSmrg } 2219ad43ddacSmrg msg[3] = dp_msg_len << 4; 2220ad43ddacSmrg 2221ad43ddacSmrg ret = RADEONProcessAuxCH(output, msg, msg_len, read_byte, 1, 0); 2222ad43ddacSmrg return ret; 2223ad43ddacSmrg} 2224ad43ddacSmrg 2225ad43ddacSmrgstatic Bool 2226ad43ddacSmrgatom_dp_i2c_address(I2CDevPtr dev, I2CSlaveAddr addr) 2227ad43ddacSmrg{ 2228ad43ddacSmrg I2CBusPtr bus = dev->pI2CBus; 2229ad43ddacSmrg xf86OutputPtr output = bus->DriverPrivate.ptr; 2230ad43ddacSmrg RADEONOutputPrivatePtr radeon_output = output->driver_private; 2231ad43ddacSmrg int ret; 2232ad43ddacSmrg 2233ad43ddacSmrg radeon_output->dp_i2c_addr = addr; 2234ad43ddacSmrg radeon_output->dp_i2c_running = TRUE; 2235ad43ddacSmrg 2236ad43ddacSmrg /* call i2c start */ 2237ad43ddacSmrg ret = atom_dp_aux_i2c_transaction(output, radeon_output->dp_i2c_addr, 2238ad43ddacSmrg dp_aux_i2c_start, 0, NULL); 2239ad43ddacSmrg 2240ad43ddacSmrg return ret; 2241ad43ddacSmrg} 2242ad43ddacSmrgstatic Bool 2243ad43ddacSmrgatom_dp_i2c_start(I2CBusPtr bus, int timeout) 2244ad43ddacSmrg{ 2245ad43ddacSmrg ErrorF("%s\n", __func__); 2246ad43ddacSmrg return TRUE; 2247ad43ddacSmrg} 2248ad43ddacSmrg 2249ad43ddacSmrgstatic void 2250ad43ddacSmrgatom_dp_i2c_stop(I2CDevPtr dev) 2251ad43ddacSmrg{ 2252ad43ddacSmrg I2CBusPtr bus = dev->pI2CBus; 2253ad43ddacSmrg xf86OutputPtr output = bus->DriverPrivate.ptr; 2254ad43ddacSmrg RADEONOutputPrivatePtr radeon_output = output->driver_private; 2255ad43ddacSmrg 2256ad43ddacSmrg if (radeon_output->dp_i2c_running) 2257ad43ddacSmrg atom_dp_aux_i2c_transaction(output, radeon_output->dp_i2c_addr, 2258ad43ddacSmrg dp_aux_i2c_stop, 0, NULL); 2259ad43ddacSmrg radeon_output->dp_i2c_running = FALSE; 2260ad43ddacSmrg} 2261ad43ddacSmrg 2262ad43ddacSmrg 2263ad43ddacSmrgstatic Bool 2264ad43ddacSmrgatom_dp_i2c_put_byte(I2CDevPtr dev, I2CByte byte) 2265ad43ddacSmrg{ 2266ad43ddacSmrg I2CBusPtr bus = dev->pI2CBus; 2267ad43ddacSmrg xf86OutputPtr output = bus->DriverPrivate.ptr; 2268ad43ddacSmrg RADEONOutputPrivatePtr radeon_output = output->driver_private; 2269ad43ddacSmrg Bool ret; 2270ad43ddacSmrg 2271ad43ddacSmrg ret = (atom_dp_aux_i2c_transaction(output, radeon_output->dp_i2c_addr, 2272ad43ddacSmrg dp_aux_i2c_write, byte, NULL)); 2273ad43ddacSmrg return ret; 2274ad43ddacSmrg} 2275ad43ddacSmrg 2276ad43ddacSmrgstatic Bool 2277ad43ddacSmrgatom_dp_i2c_get_byte(I2CDevPtr dev, I2CByte *byte_ret, Bool last) 2278ad43ddacSmrg{ 2279ad43ddacSmrg I2CBusPtr bus = dev->pI2CBus; 2280ad43ddacSmrg xf86OutputPtr output = bus->DriverPrivate.ptr; 2281ad43ddacSmrg RADEONOutputPrivatePtr radeon_output = output->driver_private; 2282ad43ddacSmrg Bool ret; 2283ad43ddacSmrg 2284ad43ddacSmrg ret = (atom_dp_aux_i2c_transaction(output, radeon_output->dp_i2c_addr, 2285ad43ddacSmrg dp_aux_i2c_read, 0, byte_ret)); 2286ad43ddacSmrg return ret; 2287ad43ddacSmrg} 2288ad43ddacSmrg 2289ad43ddacSmrgBool 2290ad43ddacSmrgRADEON_DP_I2CInit(ScrnInfoPtr pScrn, I2CBusPtr *bus_ptr, char *name, xf86OutputPtr output) 2291ad43ddacSmrg{ 2292ad43ddacSmrg I2CBusPtr pI2CBus; 2293ad43ddacSmrg 2294ad43ddacSmrg pI2CBus = xf86CreateI2CBusRec(); 2295ad43ddacSmrg if (!pI2CBus) return FALSE; 2296ad43ddacSmrg 2297ad43ddacSmrg pI2CBus->BusName = name; 2298ad43ddacSmrg pI2CBus->scrnIndex = pScrn->scrnIndex; 2299ad43ddacSmrg pI2CBus->I2CGetByte = atom_dp_i2c_get_byte; 2300ad43ddacSmrg pI2CBus->I2CPutByte = atom_dp_i2c_put_byte; 2301ad43ddacSmrg pI2CBus->I2CAddress = atom_dp_i2c_address; 2302ad43ddacSmrg pI2CBus->I2CStart = atom_dp_i2c_start; 2303ad43ddacSmrg pI2CBus->I2CStop = atom_dp_i2c_stop; 2304ad43ddacSmrg pI2CBus->DriverPrivate.ptr = output; 2305ad43ddacSmrg 2306ad43ddacSmrg /* 2307ad43ddacSmrg * These were set incorrectly in the server pre-1.3, Having 2308ad43ddacSmrg * duplicate settings is sub-optimal, but this lets the driver 2309ad43ddacSmrg * work with older servers 2310ad43ddacSmrg */ 2311ad43ddacSmrg pI2CBus->ByteTimeout = 2200; /* VESA DDC spec 3 p. 43 (+10 %) */ 2312ad43ddacSmrg pI2CBus->StartTimeout = 550; 2313ad43ddacSmrg pI2CBus->BitTimeout = 40; 2314ad43ddacSmrg pI2CBus->AcknTimeout = 40; 2315ad43ddacSmrg pI2CBus->RiseFallTime = 20; 2316ad43ddacSmrg 2317ad43ddacSmrg if (!xf86I2CBusInit(pI2CBus)) 2318ad43ddacSmrg return FALSE; 2319ad43ddacSmrg 2320ad43ddacSmrg *bus_ptr = pI2CBus; 2321ad43ddacSmrg return TRUE; 2322ad43ddacSmrg} 2323ad43ddacSmrg 2324ad43ddacSmrg 2325ad43ddacSmrgstatic uint8_t dp_link_status(uint8_t link_status[DP_LINK_STATUS_SIZE], int r) 2326ad43ddacSmrg{ 2327ad43ddacSmrg return link_status[r - DP_LANE0_1_STATUS]; 2328ad43ddacSmrg} 2329ad43ddacSmrg 2330ad43ddacSmrgstatic uint8_t dp_get_lane_status(uint8_t link_status[DP_LINK_STATUS_SIZE], int lane) 2331ad43ddacSmrg{ 2332ad43ddacSmrg int i = DP_LANE0_1_STATUS + (lane >> 1); 2333ad43ddacSmrg int s = (lane & 1) * 4; 2334ad43ddacSmrg uint8_t l = dp_link_status(link_status, i); 2335ad43ddacSmrg return (l >> s) & 0xf; 2336ad43ddacSmrg} 2337ad43ddacSmrg 2338ad43ddacSmrgstatic Bool dp_clock_recovery_ok(uint8_t link_status[DP_LINK_STATUS_SIZE], int lane_count) 2339ad43ddacSmrg{ 2340ad43ddacSmrg int lane; 2341ad43ddacSmrg 2342ad43ddacSmrg uint8_t lane_status; 2343ad43ddacSmrg 2344ad43ddacSmrg for (lane = 0; lane < lane_count; lane++) { 2345ad43ddacSmrg lane_status = dp_get_lane_status(link_status, lane); 2346ad43ddacSmrg if ((lane_status & DP_LANE_CR_DONE) == 0) 2347ad43ddacSmrg return FALSE; 2348ad43ddacSmrg } 2349ad43ddacSmrg return TRUE; 2350ad43ddacSmrg} 2351ad43ddacSmrg 2352ad43ddacSmrg 2353ad43ddacSmrg/* Check to see if channel eq is done on all channels */ 2354ad43ddacSmrg#define CHANNEL_EQ_BITS (DP_LANE_CR_DONE|\ 2355ad43ddacSmrg DP_LANE_CHANNEL_EQ_DONE|\ 2356ad43ddacSmrg DP_LANE_SYMBOL_LOCKED) 2357ad43ddacSmrgstatic Bool 2358ad43ddacSmrgdp_channel_eq_ok(uint8_t link_status[DP_LINK_STATUS_SIZE], int lane_count) 2359ad43ddacSmrg{ 2360ad43ddacSmrg uint8_t lane_align; 2361ad43ddacSmrg uint8_t lane_status; 2362ad43ddacSmrg int lane; 2363ad43ddacSmrg 2364ad43ddacSmrg lane_align = dp_link_status(link_status, 2365ad43ddacSmrg DP_LANE_ALIGN_STATUS_UPDATED); 2366ad43ddacSmrg if ((lane_align & DP_INTERLANE_ALIGN_DONE) == 0) 2367ad43ddacSmrg return FALSE; 2368ad43ddacSmrg for (lane = 0; lane < lane_count; lane++) { 2369ad43ddacSmrg lane_status = dp_get_lane_status(link_status, lane); 2370ad43ddacSmrg if ((lane_status & CHANNEL_EQ_BITS) != CHANNEL_EQ_BITS) 2371ad43ddacSmrg return FALSE; 2372ad43ddacSmrg } 2373ad43ddacSmrg return TRUE; 2374ad43ddacSmrg} 2375ad43ddacSmrg 2376ad43ddacSmrg/* 2377ad43ddacSmrg * Fetch AUX CH registers 0x202 - 0x207 which contain 2378ad43ddacSmrg * link status information 2379ad43ddacSmrg */ 2380ad43ddacSmrgstatic Bool 2381ad43ddacSmrgatom_dp_get_link_status(xf86OutputPtr output, 2382ad43ddacSmrg uint8_t link_status[DP_LINK_STATUS_SIZE]) 2383ad43ddacSmrg{ 2384ad43ddacSmrg ScrnInfoPtr pScrn = output->scrn; 2385ad43ddacSmrg int ret; 2386ad43ddacSmrg ret = atom_dp_aux_native_read(output, DP_LANE0_1_STATUS, 100, 2387ad43ddacSmrg DP_LINK_STATUS_SIZE, link_status); 2388ad43ddacSmrg if (!ret) { 2389ad43ddacSmrg xf86DrvMsg(pScrn->scrnIndex, X_INFO, "dp link status failed\n"); 2390ad43ddacSmrg return FALSE; 2391ad43ddacSmrg } 2392ad43ddacSmrg ErrorF("link status %02x %02x %02x %02x %02x %02x\n", link_status[0], link_status[1], 2393ad43ddacSmrg link_status[2], link_status[3], link_status[4], link_status[5]); 2394ad43ddacSmrg 2395ad43ddacSmrg return TRUE; 2396ad43ddacSmrg} 2397ad43ddacSmrg 2398ad43ddacSmrgstatic uint8_t 2399ad43ddacSmrgdp_get_adjust_request_voltage(uint8_t link_status[DP_LINK_STATUS_SIZE], 2400ad43ddacSmrg int lane) 2401ad43ddacSmrg 2402ad43ddacSmrg{ 2403ad43ddacSmrg int i = DP_ADJUST_REQUEST_LANE0_1 + (lane >> 1); 2404ad43ddacSmrg int s = ((lane & 1) ? 2405ad43ddacSmrg DP_ADJUST_VOLTAGE_SWING_LANE1_SHIFT : 2406ad43ddacSmrg DP_ADJUST_VOLTAGE_SWING_LANE0_SHIFT); 2407ad43ddacSmrg uint8_t l = dp_link_status(link_status, i); 2408ad43ddacSmrg 2409ad43ddacSmrg return ((l >> s) & 3) << DP_TRAIN_VOLTAGE_SWING_SHIFT; 2410ad43ddacSmrg} 2411ad43ddacSmrg 2412ad43ddacSmrgstatic uint8_t 2413ad43ddacSmrgdp_get_adjust_request_pre_emphasis(uint8_t link_status[DP_LINK_STATUS_SIZE], 2414ad43ddacSmrg int lane) 2415ad43ddacSmrg{ 2416ad43ddacSmrg int i = DP_ADJUST_REQUEST_LANE0_1 + (lane >> 1); 2417ad43ddacSmrg int s = ((lane & 1) ? 2418ad43ddacSmrg DP_ADJUST_PRE_EMPHASIS_LANE1_SHIFT : 2419ad43ddacSmrg DP_ADJUST_PRE_EMPHASIS_LANE0_SHIFT); 2420ad43ddacSmrg uint8_t l = dp_link_status(link_status, i); 2421ad43ddacSmrg 2422ad43ddacSmrg return ((l >> s) & 3) << DP_TRAIN_PRE_EMPHASIS_SHIFT; 2423ad43ddacSmrg} 2424ad43ddacSmrg 2425ad43ddacSmrgstatic char *voltage_names[] = { 2426ad43ddacSmrg "0.4V", "0.6V", "0.8V", "1.2V" 2427ad43ddacSmrg}; 2428ad43ddacSmrgstatic char *pre_emph_names[] = { 2429ad43ddacSmrg "0dB", "3.5dB", "6dB", "9.5dB" 2430ad43ddacSmrg}; 2431ad43ddacSmrg 2432ad43ddacSmrg/* 2433ad43ddacSmrg * These are source-specific values; current Intel hardware supports 2434ad43ddacSmrg * a maximum voltage of 800mV and a maximum pre-emphasis of 6dB 2435ad43ddacSmrg */ 2436ad43ddacSmrg#define DP_VOLTAGE_MAX DP_TRAIN_VOLTAGE_SWING_1200 2437ad43ddacSmrg 2438ad43ddacSmrgstatic uint8_t 2439ad43ddacSmrgdp_pre_emphasis_max(uint8_t voltage_swing) 2440ad43ddacSmrg{ 2441ad43ddacSmrg switch (voltage_swing & DP_TRAIN_VOLTAGE_SWING_MASK) { 2442ad43ddacSmrg case DP_TRAIN_VOLTAGE_SWING_400: 2443ad43ddacSmrg return DP_TRAIN_PRE_EMPHASIS_6; 2444ad43ddacSmrg case DP_TRAIN_VOLTAGE_SWING_600: 2445ad43ddacSmrg return DP_TRAIN_PRE_EMPHASIS_6; 2446ad43ddacSmrg case DP_TRAIN_VOLTAGE_SWING_800: 2447ad43ddacSmrg return DP_TRAIN_PRE_EMPHASIS_3_5; 2448ad43ddacSmrg case DP_TRAIN_VOLTAGE_SWING_1200: 2449ad43ddacSmrg default: 2450ad43ddacSmrg return DP_TRAIN_PRE_EMPHASIS_0; 2451ad43ddacSmrg } 2452ad43ddacSmrg} 2453ad43ddacSmrg 2454ad43ddacSmrgstatic void dp_set_training(xf86OutputPtr output, uint8_t training) 2455ad43ddacSmrg{ 2456ad43ddacSmrg atom_dp_aux_native_write(output, DP_TRAINING_PATTERN_SET, 1, &training); 2457ad43ddacSmrg} 2458ad43ddacSmrg 2459ad43ddacSmrgstatic void dp_set_power(xf86OutputPtr output, uint8_t power_state) 2460ad43ddacSmrg{ 2461ad43ddacSmrg RADEONOutputPrivatePtr radeon_output = output->driver_private; 2462ad43ddacSmrg 2463ad43ddacSmrg if (radeon_output->dpcd[0] >= 0x11) { 2464ad43ddacSmrg atom_dp_aux_native_write(output, 0x600, 1, &power_state); 2465ad43ddacSmrg } 2466ad43ddacSmrg} 2467ad43ddacSmrg 2468ad43ddacSmrgstatic void 2469ad43ddacSmrgdp_get_adjust_train(xf86OutputPtr output, 2470ad43ddacSmrg uint8_t link_status[DP_LINK_STATUS_SIZE], 2471ad43ddacSmrg int lane_count, 2472ad43ddacSmrg uint8_t train_set[4]) 2473ad43ddacSmrg{ 2474ad43ddacSmrg ScrnInfoPtr pScrn = output->scrn; 2475ad43ddacSmrg uint8_t v = 0; 2476ad43ddacSmrg uint8_t p = 0; 2477ad43ddacSmrg int lane; 2478ad43ddacSmrg 2479ad43ddacSmrg for (lane = 0; lane < lane_count; lane++) { 2480ad43ddacSmrg uint8_t this_v = dp_get_adjust_request_voltage(link_status, lane); 2481ad43ddacSmrg uint8_t this_p = dp_get_adjust_request_pre_emphasis(link_status, lane); 2482ad43ddacSmrg 2483ad43ddacSmrg if (0) { 2484ad43ddacSmrg xf86DrvMsg(pScrn->scrnIndex, X_INFO, 2485ad43ddacSmrg "requested signal parameters: lane %d voltage %s pre_emph %s\n", 2486ad43ddacSmrg lane, 2487ad43ddacSmrg voltage_names[this_v >> DP_TRAIN_VOLTAGE_SWING_SHIFT], 2488ad43ddacSmrg pre_emph_names[this_p >> DP_TRAIN_PRE_EMPHASIS_SHIFT]); 2489ad43ddacSmrg } 2490ad43ddacSmrg if (this_v > v) 2491ad43ddacSmrg v = this_v; 2492ad43ddacSmrg if (this_p > p) 2493ad43ddacSmrg p = this_p; 2494ad43ddacSmrg } 2495ad43ddacSmrg 2496ad43ddacSmrg if (v >= DP_VOLTAGE_MAX) 2497ad43ddacSmrg v = DP_VOLTAGE_MAX | DP_TRAIN_MAX_SWING_REACHED; 2498ad43ddacSmrg 2499ad43ddacSmrg if (p >= dp_pre_emphasis_max(v)) 2500ad43ddacSmrg p = dp_pre_emphasis_max(v) | DP_TRAIN_MAX_PRE_EMPHASIS_REACHED; 2501ad43ddacSmrg 2502ad43ddacSmrg if (0) { 2503ad43ddacSmrg xf86DrvMsg(pScrn->scrnIndex, X_INFO, 2504ad43ddacSmrg "using signal parameters: voltage %s pre_emph %s\n", 2505ad43ddacSmrg voltage_names[(v & DP_TRAIN_VOLTAGE_SWING_MASK) >> DP_TRAIN_VOLTAGE_SWING_SHIFT], 2506ad43ddacSmrg pre_emph_names[(p & DP_TRAIN_PRE_EMPHASIS_MASK) >> DP_TRAIN_PRE_EMPHASIS_SHIFT]); 2507ad43ddacSmrg } 2508ad43ddacSmrg for (lane = 0; lane < 4; lane++) 2509ad43ddacSmrg train_set[lane] = v | p; 2510ad43ddacSmrg} 2511ad43ddacSmrg 2512ad43ddacSmrgstatic int radeon_dp_max_lane_count(xf86OutputPtr output) 2513ad43ddacSmrg{ 2514ad43ddacSmrg RADEONOutputPrivatePtr radeon_output = output->driver_private; 2515ad43ddacSmrg int max_lane_count = 4; 2516ad43ddacSmrg 2517ad43ddacSmrg if (radeon_output->dpcd[0] >= 0x11) { 2518ad43ddacSmrg max_lane_count = radeon_output->dpcd[2] & 0x1f; 2519ad43ddacSmrg switch(max_lane_count) { 2520ad43ddacSmrg case 1: case 2: case 4: 2521ad43ddacSmrg break; 2522ad43ddacSmrg default: 2523ad43ddacSmrg max_lane_count = 4; 2524ad43ddacSmrg } 2525ad43ddacSmrg } 2526ad43ddacSmrg return max_lane_count; 2527ad43ddacSmrg} 2528ad43ddacSmrg 2529ad43ddacSmrgstatic int radeon_dp_max_link_bw(xf86OutputPtr output) 2530ad43ddacSmrg{ 2531ad43ddacSmrg RADEONOutputPrivatePtr radeon_output = output->driver_private; 2532ad43ddacSmrg int max_link_bw = radeon_output->dpcd[1]; 2533ad43ddacSmrg switch(max_link_bw) { 2534ad43ddacSmrg case DP_LINK_BW_1_62: 2535ad43ddacSmrg case DP_LINK_BW_2_7: 2536ad43ddacSmrg break; 2537ad43ddacSmrg default: 2538ad43ddacSmrg max_link_bw = DP_LINK_BW_1_62; 2539ad43ddacSmrg break; 2540ad43ddacSmrg } 2541ad43ddacSmrg return max_link_bw; 2542ad43ddacSmrg} 2543ad43ddacSmrg 2544ad43ddacSmrgstatic int radeon_dp_link_clock(uint8_t link_bw) 2545ad43ddacSmrg{ 2546ad43ddacSmrg if (link_bw == DP_LINK_BW_2_7) 2547ad43ddacSmrg return 270000; 2548ad43ddacSmrg else 2549ad43ddacSmrg return 162000; 2550ad43ddacSmrg} 2551ad43ddacSmrg 2552ad43ddacSmrg 2553ad43ddacSmrg/* I think this is a fiction */ 2554ad43ddacSmrgstatic int radeon_dp_link_required(int pixel_clock) 2555ad43ddacSmrg{ 2556ad43ddacSmrg return pixel_clock * 3; 2557ad43ddacSmrg} 2558ad43ddacSmrg 25590974d292Smrgstatic int link_bw_avail(int max_link_clock, int max_lanes) 25600974d292Smrg{ 25610974d292Smrg return (max_link_clock * max_lanes * 8) / 10; 25620974d292Smrg} 25630974d292Smrg 2564ad43ddacSmrgBool radeon_dp_mode_fixup(xf86OutputPtr output, DisplayModePtr mode, DisplayModePtr adjusted_mode) 2565ad43ddacSmrg{ 2566ad43ddacSmrg RADEONOutputPrivatePtr radeon_output = output->driver_private; 2567ad43ddacSmrg int lane_count, clock; 2568ad43ddacSmrg int max_lane_count = radeon_dp_max_lane_count(output); 2569ad43ddacSmrg int max_clock = radeon_dp_max_link_bw(output) == DP_LINK_BW_2_7 ? 1 : 0; 2570ad43ddacSmrg static int bws[2] = { DP_LINK_BW_1_62, DP_LINK_BW_2_7 }; 2571ad43ddacSmrg 2572ad43ddacSmrg for (lane_count = 1; lane_count <= max_lane_count; lane_count <<= 1) { 2573ad43ddacSmrg for (clock = 0; clock <= max_clock; clock++) { 25740974d292Smrg int link_avail = link_bw_avail(radeon_dp_link_clock(bws[clock]), lane_count); 2575ad43ddacSmrg 2576ad43ddacSmrg if (radeon_dp_link_required(mode->Clock) <= link_avail) { 2577ad43ddacSmrg radeon_output->dp_lane_count = lane_count; 2578ad43ddacSmrg radeon_output->dp_clock = radeon_dp_link_clock(bws[clock]); 2579ad43ddacSmrg if (0) 2580ad43ddacSmrg xf86DrvMsg(0, X_INFO, 2581ad43ddacSmrg "lane_count %d clock %d\n", 2582ad43ddacSmrg radeon_output->dp_lane_count, 2583ad43ddacSmrg radeon_output->dp_clock); 2584ad43ddacSmrg return TRUE; 2585ad43ddacSmrg } 2586ad43ddacSmrg } 2587ad43ddacSmrg } 2588ad43ddacSmrg return FALSE; 2589ad43ddacSmrg} 2590ad43ddacSmrg 2591ad43ddacSmrgstatic void dp_update_dpvs_emph(xf86OutputPtr output, uint8_t train_set[4]) 2592ad43ddacSmrg{ 2593ad43ddacSmrg RADEONOutputPrivatePtr radeon_output = output->driver_private; 2594ad43ddacSmrg int i; 2595ad43ddacSmrg for (i = 0; i < radeon_output->dp_lane_count; i++) 2596ad43ddacSmrg atombios_output_dig_transmitter_setup(output, ATOM_TRANSMITTER_ACTION_SETUP_VSEMPH, i, train_set[i]); 2597ad43ddacSmrg 2598ad43ddacSmrg atom_dp_aux_native_write(output, DP_TRAINING_LANE0_SET, radeon_output->dp_lane_count, train_set); 2599ad43ddacSmrg} 2600ad43ddacSmrg 2601ad43ddacSmrgstatic void do_displayport_link_train(xf86OutputPtr output) 2602ad43ddacSmrg{ 2603ad43ddacSmrg ScrnInfoPtr pScrn = output->scrn; 2604ad43ddacSmrg RADEONInfoPtr info = RADEONPTR(pScrn); 2605ad43ddacSmrg RADEONOutputPrivatePtr radeon_output = output->driver_private; 2606ad43ddacSmrg int enc_id = atom_dp_get_encoder_id(output); 2607ad43ddacSmrg Bool clock_recovery; 2608ad43ddacSmrg uint8_t link_status[DP_LINK_STATUS_SIZE]; 2609ad43ddacSmrg uint8_t tries, voltage, ss_cntl; 2610ad43ddacSmrg uint8_t train_set[4]; 2611ad43ddacSmrg int i; 2612ad43ddacSmrg Bool channel_eq; 2613ad43ddacSmrg uint8_t dp_link_configuration[DP_LINK_CONFIGURATION_SIZE]; 2614ad43ddacSmrg 2615ad43ddacSmrg memset(train_set, 0, 4); 2616ad43ddacSmrg 2617ad43ddacSmrg /* set up link configuration */ 2618ad43ddacSmrg memset(dp_link_configuration, 0, DP_LINK_CONFIGURATION_SIZE); 2619ad43ddacSmrg 2620ad43ddacSmrg if (radeon_output->dp_clock == 270000) 2621ad43ddacSmrg dp_link_configuration[0] = DP_LINK_BW_2_7; 2622ad43ddacSmrg else 2623ad43ddacSmrg dp_link_configuration[0] = DP_LINK_BW_1_62; 2624ad43ddacSmrg dp_link_configuration[1] = radeon_output->dp_lane_count; 2625ad43ddacSmrg 2626ad43ddacSmrg if (radeon_output->dpcd[0] >= 0x11) { 2627ad43ddacSmrg dp_link_configuration[1] |= DP_LANE_COUNT_ENHANCED_FRAME_EN; 2628ad43ddacSmrg } 2629ad43ddacSmrg 2630ad43ddacSmrg /* power up to D0 */ 2631ad43ddacSmrg dp_set_power(output, DP_SET_POWER_D0); 2632ad43ddacSmrg 2633ad43ddacSmrg /* disable training */ 2634ad43ddacSmrg dp_set_training(output, DP_TRAINING_PATTERN_DISABLE); 2635ad43ddacSmrg 2636ad43ddacSmrg /* write link rate / num / eh framing */ 2637ad43ddacSmrg atom_dp_aux_native_write(output, DP_LINK_BW_SET, 2, 2638ad43ddacSmrg dp_link_configuration); 2639ad43ddacSmrg 2640ad43ddacSmrg /* write ss cntl */ 2641ad43ddacSmrg ss_cntl = 0; 2642ad43ddacSmrg atom_dp_aux_native_write(output, DP_DOWNSPREAD_CTRL, 1, 2643ad43ddacSmrg &ss_cntl); 2644ad43ddacSmrg 2645ad43ddacSmrg /* start local training start */ 2646ad43ddacSmrg if (IS_DCE4_VARIANT) { 26470974d292Smrg atombios_output_dig_encoder_setup(output, ATOM_ENCODER_CMD_DP_LINK_TRAINING_START); 26480974d292Smrg atombios_output_dig_encoder_setup(output, ATOM_ENCODER_CMD_DP_LINK_TRAINING_PATTERN1); 2649ad43ddacSmrg } else { 2650ad43ddacSmrg RADEONDPEncoderService(output, ATOM_DP_ACTION_TRAINING_START, enc_id, 0); 2651ad43ddacSmrg RADEONDPEncoderService(output, ATOM_DP_ACTION_TRAINING_PATTERN_SEL, enc_id, 0); 2652ad43ddacSmrg } 2653ad43ddacSmrg 2654ad43ddacSmrg usleep(400); 2655ad43ddacSmrg dp_set_training(output, DP_TRAINING_PATTERN_1); 2656ad43ddacSmrg dp_update_dpvs_emph(output, train_set); 2657ad43ddacSmrg 2658ad43ddacSmrg /* loop around doing configuration reads and DP encoder setups */ 2659ad43ddacSmrg clock_recovery = FALSE; 2660ad43ddacSmrg tries = 0; 2661ad43ddacSmrg voltage = 0xff; 2662ad43ddacSmrg for (;;) { 2663ad43ddacSmrg usleep(100); 2664ad43ddacSmrg if (!atom_dp_get_link_status(output, link_status)) 2665ad43ddacSmrg break; 2666ad43ddacSmrg 2667ad43ddacSmrg if (dp_clock_recovery_ok(link_status, radeon_output->dp_lane_count)) { 2668ad43ddacSmrg clock_recovery = TRUE; 2669ad43ddacSmrg break; 2670ad43ddacSmrg } 2671ad43ddacSmrg 2672ad43ddacSmrg for (i = 0; i < radeon_output->dp_lane_count; i++) 2673ad43ddacSmrg if ((train_set[i] & DP_TRAIN_MAX_SWING_REACHED) == 0) 2674ad43ddacSmrg break; 2675ad43ddacSmrg if (i == radeon_output->dp_lane_count) { 2676ad43ddacSmrg xf86DrvMsg(pScrn->scrnIndex, X_INFO, 2677ad43ddacSmrg "clock recovery reached max voltage\n"); 2678ad43ddacSmrg break; 2679ad43ddacSmrg } 2680ad43ddacSmrg 2681ad43ddacSmrg /* Check to see if we've tried the same voltage 5 times */ 2682ad43ddacSmrg if ((train_set[0] & DP_TRAIN_VOLTAGE_SWING_MASK) == voltage) { 2683ad43ddacSmrg ++tries; 2684ad43ddacSmrg if (tries == 5) { 2685ad43ddacSmrg xf86DrvMsg(pScrn->scrnIndex, X_INFO, 2686ad43ddacSmrg "clock recovery tried 5 times\n"); 2687ad43ddacSmrg break; 2688ad43ddacSmrg } 2689ad43ddacSmrg } else 2690ad43ddacSmrg tries = 0; 2691ad43ddacSmrg 2692ad43ddacSmrg voltage = train_set[0] & DP_TRAIN_VOLTAGE_SWING_MASK; 2693ad43ddacSmrg 2694ad43ddacSmrg dp_get_adjust_train(output, link_status, radeon_output->dp_lane_count, train_set); 2695ad43ddacSmrg dp_update_dpvs_emph(output, train_set); 2696ad43ddacSmrg 2697ad43ddacSmrg } 2698ad43ddacSmrg 2699ad43ddacSmrg if (!clock_recovery) 2700ad43ddacSmrg xf86DrvMsg(pScrn->scrnIndex, X_ERROR, 2701ad43ddacSmrg "clock recovery failed\n"); 2702ad43ddacSmrg 2703ad43ddacSmrg /* channel equalization */ 2704ad43ddacSmrg tries = 0; 2705ad43ddacSmrg channel_eq = FALSE; 2706ad43ddacSmrg dp_set_training(output, DP_TRAINING_PATTERN_2); 2707ad43ddacSmrg if (IS_DCE4_VARIANT) 27080974d292Smrg atombios_output_dig_encoder_setup(output, ATOM_ENCODER_CMD_DP_LINK_TRAINING_PATTERN2); 2709ad43ddacSmrg else 2710ad43ddacSmrg RADEONDPEncoderService(output, ATOM_DP_ACTION_TRAINING_PATTERN_SEL, enc_id, 1); 2711ad43ddacSmrg 2712ad43ddacSmrg for (;;) { 2713ad43ddacSmrg usleep(400); 2714ad43ddacSmrg if (!atom_dp_get_link_status(output, link_status)) 2715ad43ddacSmrg break; 2716ad43ddacSmrg 2717ad43ddacSmrg if (dp_channel_eq_ok(link_status, radeon_output->dp_lane_count)) { 2718ad43ddacSmrg channel_eq = TRUE; 2719ad43ddacSmrg break; 2720ad43ddacSmrg } 2721ad43ddacSmrg 2722ad43ddacSmrg /* Try 5 times */ 2723ad43ddacSmrg if (tries > 5) { 2724ad43ddacSmrg xf86DrvMsg(pScrn->scrnIndex, X_INFO, 2725ad43ddacSmrg "channel eq failed: 5 tries\n"); 2726ad43ddacSmrg break; 2727ad43ddacSmrg } 2728ad43ddacSmrg 2729ad43ddacSmrg /* Compute new train_set as requested by target */ 2730ad43ddacSmrg dp_get_adjust_train(output, link_status, radeon_output->dp_lane_count, train_set); 2731ad43ddacSmrg dp_update_dpvs_emph(output, train_set); 2732ad43ddacSmrg 2733ad43ddacSmrg ++tries; 2734ad43ddacSmrg } 2735ad43ddacSmrg 2736ad43ddacSmrg if (!channel_eq) 2737ad43ddacSmrg xf86DrvMsg(pScrn->scrnIndex, X_ERROR, 2738ad43ddacSmrg "channel eq failed\n"); 2739ad43ddacSmrg 2740ad43ddacSmrg dp_set_training(output, DP_TRAINING_PATTERN_DISABLE); 2741ad43ddacSmrg if (IS_DCE4_VARIANT) 27420974d292Smrg atombios_output_dig_encoder_setup(output, ATOM_ENCODER_CMD_DP_LINK_TRAINING_COMPLETE); 2743ad43ddacSmrg else 2744ad43ddacSmrg RADEONDPEncoderService(output, ATOM_DP_ACTION_TRAINING_COMPLETE, enc_id, 0); 2745ad43ddacSmrg 2746ad43ddacSmrg} 2747ad43ddacSmrg 2748