diff --git a/r600-enable-mixed.patch b/r600-enable-mixed.patch deleted file mode 100644 index 10e11d0..0000000 --- a/r600-enable-mixed.patch +++ /dev/null @@ -1,17 +0,0 @@ -diff --git a/src/r600_exa.c b/src/r600_exa.c -index 86da68c..4e42509 100644 ---- a/src/r600_exa.c -+++ b/src/r600_exa.c -@@ -2330,9 +2330,9 @@ R600DrawInit(ScreenPtr pScreen) - #ifdef EXA_HANDLES_PIXMAPS - if (info->cs) { - info->accel_state->exa->flags |= EXA_HANDLES_PIXMAPS; --//#ifdef EXA_MIXED_PIXMAPS --// info->accel_state->exa->flags |= EXA_MIXED_PIXMAPS; --//#endif -+#ifdef EXA_MIXED_PIXMAPS -+ info->accel_state->exa->flags |= EXA_MIXED_PIXMAPS; -+#endif - } - #endif - #endif diff --git a/radeon-ums-displayport.patch b/radeon-ums-displayport.patch new file mode 100644 index 0000000..6e52960 --- /dev/null +++ b/radeon-ums-displayport.patch @@ -0,0 +1,1372 @@ +diff --git a/src/atombios_output.c b/src/atombios_output.c +index c9f1dfa..8047b53 100644 +--- a/src/atombios_output.c ++++ b/src/atombios_output.c +@@ -65,6 +65,8 @@ const char *device_name[12] = { + "DFP5", + }; + ++static void do_displayport_link_train(xf86OutputPtr output); ++ + static void atombios_set_output_crtc_source(xf86OutputPtr output); + + static int +@@ -466,41 +468,102 @@ atombios_get_encoder_mode(xf86OutputPtr output) + } + + static const int dp_clocks[] = { +- 16200, +- 27000, +- 32400, +- 54000, +- 0, +- 0, +- 64800, +- 108000, ++ 5400, // 1 lane, 1.62 Ghz ++ 9000, // 1 lane, 2.70 Ghz ++ 10800, // 2 lane, 1.62 Ghz ++ 18000, // 2 lane, 2.70 Ghz ++ 21600, // 4 lane, 1.62 Ghz ++ 36000, // 4 lane, 2.70 Ghz + }; + static const int num_dp_clocks = sizeof(dp_clocks) / sizeof(int); + ++# define DP_LINK_BW_1_62 0x06 ++# define DP_LINK_BW_2_7 0x0a ++ + static int +-dp_lanes_for_mode_clock(int mode_clock) ++dp_lanes_for_mode_clock(RADEONOutputPrivatePtr radeon_output, ++ int mode_clock) + { + int i; +- +- for (i = 0; i < num_dp_clocks; i++) +- if (dp_clocks[i] > (mode_clock / 10)) +- return (i / 2) + 1; ++ int max_link_bw = radeon_output->dpcd[1]; ++ ++ switch (max_link_bw) { ++ case DP_LINK_BW_1_62: ++ default: ++ for (i = 0; i < num_dp_clocks; i++) { ++ if (i % 2) ++ continue; ++ if (dp_clocks[i] > (mode_clock / 10)) { ++ if (i < 2) ++ return 1; ++ else if (i < 4) ++ return 2; ++ else ++ return 4; ++ } ++ } ++ break; ++ case DP_LINK_BW_2_7: ++ for (i = 0; i < num_dp_clocks; i++) { ++ if (dp_clocks[i] > (mode_clock / 10)) { ++ if (i < 2) ++ return 1; ++ else if (i < 4) ++ return 2; ++ else ++ return 4; ++ } ++ } ++ break; ++ } + + return 0; + } + + static int +-dp_link_clock_for_mode_clock(int mode_clock) ++dp_link_clock_for_mode_clock(RADEONOutputPrivatePtr radeon_output, ++ int mode_clock) + { + int i; ++ int max_link_bw = radeon_output->dpcd[1]; + +- for (i = 0; i < num_dp_clocks; i++) +- if (dp_clocks[i] > (mode_clock / 10)) +- return (dp_clocks[i % 2]); ++ switch (max_link_bw) { ++ case DP_LINK_BW_1_62: ++ default: ++ return 16200; ++ break; ++ case DP_LINK_BW_2_7: ++ for (i = 0; i < num_dp_clocks; i++) ++ if (dp_clocks[i] > (mode_clock / 10)) ++ return (i % 2) ? 27000 : 16200; ++ break; ++ } + + return 0; + } + ++/* ++ * DIG Encoder/Transmitter Setup ++ * ++ * DCE 3.0/3.1 ++ * - 2 DIG transmitter blocks. UNIPHY (links A and B) and LVTMA. ++ * Supports up to 3 digital outputs ++ * - 2 DIG encoder blocks. ++ * DIG1 can drive UNIPHY link A or link B ++ * DIG2 can drive UNIPHY link B or LVTMA ++ * ++ * DCE 3.2 ++ * - 3 DIG transmitter blocks. UNIPHY0/1/2 (links A and B). ++ * Supports up to 5 digital outputs ++ * - 2 DIG encoder blocks. ++ * DIG1/2 can drive UNIPHY0/1/2 link A or link B ++ * ++ * Routing ++ * crtc -> dig encoder -> UNIPHY/LVTMA (1 or 2 links) ++ * Examples: ++ * crtc0 -> dig2 -> LVTMA links A+B ++ * crtc1 -> dig1 -> UNIPHY0 link B ++ */ + static int + atombios_output_dig_encoder_setup(xf86OutputPtr output, int action) + { +@@ -528,10 +591,17 @@ atombios_output_dig_encoder_setup(xf86OutputPtr output, int action) + } else { + switch (radeon_encoder->encoder_id) { + case ENCODER_OBJECT_ID_INTERNAL_UNIPHY: +- index = GetIndexIntoMasterTable(COMMAND, DIG1EncoderControl); ++ /* doesn't really matter which dig encoder we pick as long as it's ++ * not already in use ++ */ ++ if (radeon_output->linkb) ++ index = GetIndexIntoMasterTable(COMMAND, DIG2EncoderControl); ++ else ++ index = GetIndexIntoMasterTable(COMMAND, DIG1EncoderControl); + num = 1; + break; + case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA: ++ /* Only dig2 encoder can drive LVTMA */ + index = GetIndexIntoMasterTable(COMMAND, DIG2EncoderControl); + num = 2; + break; +@@ -569,26 +639,18 @@ atombios_output_dig_encoder_setup(xf86OutputPtr output, int action) + disp_data.ucEncoderMode = atombios_get_encoder_mode(output); + + if (disp_data.ucEncoderMode == ATOM_ENCODER_MODE_DP) { +- if (radeon_output->linkb) +- disp_data.ucConfig |= ATOM_ENCODER_CONFIG_LINKB; +- else +- disp_data.ucConfig |= ATOM_ENCODER_CONFIG_LINKA; +- +- if (dp_link_clock_for_mode_clock(clock) == 27000) ++ if (dp_link_clock_for_mode_clock(radeon_output, clock) == 27000) + disp_data.ucConfig |= ATOM_ENCODER_CONFIG_DPLINKRATE_2_70GHZ; +- +- disp_data.ucLaneNum = dp_lanes_for_mode_clock(clock); +- } else if (clock > 165000) { +- disp_data.ucConfig |= ATOM_ENCODER_CONFIG_LINKA_B; ++ disp_data.ucLaneNum = dp_lanes_for_mode_clock(radeon_output, clock); ++ } else if (clock > 165000) + disp_data.ucLaneNum = 8; +- } else { +- if (radeon_output->linkb) +- disp_data.ucConfig |= ATOM_ENCODER_CONFIG_LINKB; +- else +- disp_data.ucConfig |= ATOM_ENCODER_CONFIG_LINKA; +- ++ else + disp_data.ucLaneNum = 4; +- } ++ ++ if (radeon_output->linkb) ++ disp_data.ucConfig |= ATOM_ENCODER_CONFIG_LINKB; ++ else ++ disp_data.ucConfig |= ATOM_ENCODER_CONFIG_LINKA; + + data.exec.index = index; + data.exec.dataSpace = (void *)&space; +@@ -610,7 +672,7 @@ union dig_transmitter_control { + }; + + static int +-atombios_output_dig_transmitter_setup(xf86OutputPtr output, int action) ++atombios_output_dig_transmitter_setup(xf86OutputPtr output, int action, uint8_t lane_num, uint8_t lane_set) + { + RADEONOutputPrivatePtr radeon_output = output->driver_private; + RADEONInfoPtr info = RADEONPTR(output->scrn); +@@ -648,10 +710,13 @@ atombios_output_dig_transmitter_setup(xf86OutputPtr output, int action) + if (IS_DCE32_VARIANT) { + if (action == ATOM_TRANSMITTER_ACTION_INIT) { + disp_data.v2.usInitInfo = radeon_output->connector_object_id; ++ } else if (action == ATOM_TRANSMITTER_ACTION_SETUP_VSEMPH) { ++ disp_data.v2.asMode.ucLaneSel = lane_num; ++ disp_data.v2.asMode.ucLaneSet = lane_set; + } else { + if (radeon_output->MonType == MT_DP) { + disp_data.v2.usPixelClock = +- cpu_to_le16(dp_link_clock_for_mode_clock(clock)); ++ cpu_to_le16(dp_link_clock_for_mode_clock(radeon_output, clock)); + disp_data.v2.acConfig.fDPConnector = 1; + } else if (clock > 165000) { + disp_data.v2.usPixelClock = cpu_to_le16((clock / 2) / 10); +@@ -663,6 +728,9 @@ atombios_output_dig_transmitter_setup(xf86OutputPtr output, int action) + if (dig_block) + disp_data.v2.acConfig.ucEncoderSel = 1; + ++ if (radeon_output->linkb) ++ disp_data.v2.acConfig.ucLinkSel = 1; ++ + switch (radeon_encoder->encoder_id) { + case ENCODER_OBJECT_ID_INTERNAL_UNIPHY: + disp_data.v2.acConfig.ucTransmitterSel = 0; +@@ -678,7 +746,9 @@ atombios_output_dig_transmitter_setup(xf86OutputPtr output, int action) + break; + } + +- if (radeon_output->active_device & (ATOM_DEVICE_DFP_SUPPORT)) { ++ if (radeon_output->MonType == MT_DP) ++ disp_data.v2.acConfig.fCoherentMode = 1; /* DP requires coherent */ ++ else if (radeon_output->active_device & (ATOM_DEVICE_DFP_SUPPORT)) { + if (radeon_output->coherent_mode) { + disp_data.v2.acConfig.fCoherentMode = 1; + xf86DrvMsg(output->scrn->scrnIndex, X_INFO, "UNIPHY%d transmitter: Coherent Mode enabled\n",disp_data.v2.acConfig.ucTransmitterSel); +@@ -690,10 +760,13 @@ atombios_output_dig_transmitter_setup(xf86OutputPtr output, int action) + + if (action == ATOM_TRANSMITTER_ACTION_INIT) { + disp_data.v1.usInitInfo = radeon_output->connector_object_id; ++ } else if (action == ATOM_TRANSMITTER_ACTION_SETUP_VSEMPH) { ++ disp_data.v2.asMode.ucLaneSel = lane_num; ++ disp_data.v2.asMode.ucLaneSet = lane_set; + } else { + if (radeon_output->MonType == MT_DP) + disp_data.v1.usPixelClock = +- cpu_to_le16(dp_link_clock_for_mode_clock(clock)); ++ cpu_to_le16(dp_link_clock_for_mode_clock(radeon_output, clock)); + else if (clock > 165000) + disp_data.v1.usPixelClock = cpu_to_le16((clock / 2) / 10); + else +@@ -702,18 +775,20 @@ atombios_output_dig_transmitter_setup(xf86OutputPtr output, int action) + + switch (radeon_encoder->encoder_id) { + case ENCODER_OBJECT_ID_INTERNAL_UNIPHY: +- disp_data.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_DIG1_ENCODER; ++ /* doesn't really matter which dig encoder we pick as long as it's ++ * not already in use ++ */ ++ if (radeon_output->linkb) ++ disp_data.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_DIG2_ENCODER; ++ else ++ disp_data.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_DIG1_ENCODER; + if (info->IsIGP) { + if (clock > 165000) { +- disp_data.v1.ucConfig |= (ATOM_TRANSMITTER_CONFIG_8LANE_LINK | +- ATOM_TRANSMITTER_CONFIG_LINKA_B); +- + if (radeon_output->igp_lane_info & 0x3) + disp_data.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LANE_0_7; + else if (radeon_output->igp_lane_info & 0xc) + disp_data.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LANE_8_15; + } else { +- disp_data.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LINKA; + if (radeon_output->igp_lane_info & 0x1) + disp_data.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LANE_0_3; + else if (radeon_output->igp_lane_info & 0x2) +@@ -723,39 +798,24 @@ atombios_output_dig_transmitter_setup(xf86OutputPtr output, int action) + else if (radeon_output->igp_lane_info & 0x8) + disp_data.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LANE_12_15; + } +- } else { +- if (clock > 165000) +- disp_data.v1.ucConfig |= (ATOM_TRANSMITTER_CONFIG_8LANE_LINK | +- ATOM_TRANSMITTER_CONFIG_LINKA_B | +- ATOM_TRANSMITTER_CONFIG_LANE_0_7); +- else { +- /* XXX */ +- if (radeon_output->linkb) +- disp_data.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LINKB | ATOM_TRANSMITTER_CONFIG_LANE_0_3; +- else +- disp_data.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LINKA | ATOM_TRANSMITTER_CONFIG_LANE_0_3; +- } + } + break; + case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA: ++ /* Only dig2 encoder can drive LVTMA */ + disp_data.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_DIG2_ENCODER; +- if (clock > 165000) +- disp_data.v1.ucConfig |= (ATOM_TRANSMITTER_CONFIG_8LANE_LINK | +- ATOM_TRANSMITTER_CONFIG_LINKA_B | +- ATOM_TRANSMITTER_CONFIG_LANE_0_7); +- else { +- /* XXX */ +- if (radeon_output->linkb) +- disp_data.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LINKB | ATOM_TRANSMITTER_CONFIG_LANE_0_3; +- else +- disp_data.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LINKA | ATOM_TRANSMITTER_CONFIG_LANE_0_3; +- } + break; + } ++ if (clock > 165000) ++ disp_data.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_8LANE_LINK; ++ if (radeon_output->linkb) ++ disp_data.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LINKB; ++ else ++ disp_data.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LINKA; + +- if (radeon_output->active_device & (ATOM_DEVICE_DFP_SUPPORT)) { +- if (radeon_output->coherent_mode && +- radeon_output->MonType != MT_DP) { ++ if (radeon_output->MonType == MT_DP) ++ disp_data.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_COHERENT; /* DP requires coherent */ ++ else if (radeon_output->active_device & (ATOM_DEVICE_DFP_SUPPORT)) { ++ if (radeon_output->coherent_mode) { + disp_data.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_COHERENT; + xf86DrvMsg(output->scrn->scrnIndex, X_INFO, + "DIG%d transmitter: Coherent Mode enabled\n", num); +@@ -1285,8 +1345,12 @@ atombios_output_dpms(xf86OutputPtr output, int mode) + switch (mode) { + case DPMSModeOn: + radeon_encoder->devices |= radeon_output->active_device; +- if (is_dig) +- atombios_output_dig_transmitter_setup(output, ATOM_TRANSMITTER_ACTION_ENABLE_OUTPUT); ++ if (is_dig) { ++ atombios_output_dig_transmitter_setup(output, ATOM_TRANSMITTER_ACTION_ENABLE_OUTPUT, 0, 0); ++ if (radeon_output->ConnectorType == CONNECTOR_DISPLAY_PORT && radeon_output->MonType == MT_DP) { ++ do_displayport_link_train(output); ++ } ++ } + else { + disp_data.ucAction = ATOM_ENABLE; + data.exec.index = index; +@@ -1310,7 +1374,7 @@ atombios_output_dpms(xf86OutputPtr output, int mode) + radeon_encoder->devices &= ~(radeon_output->active_device); + if (!radeon_encoder->devices) { + if (is_dig) +- atombios_output_dig_transmitter_setup(output, ATOM_TRANSMITTER_ACTION_DISABLE_OUTPUT); ++ atombios_output_dig_transmitter_setup(output, ATOM_TRANSMITTER_ACTION_DISABLE_OUTPUT, 0, 0); + else { + disp_data.ucAction = ATOM_DISABLE; + data.exec.index = index; +@@ -1418,10 +1482,18 @@ atombios_set_output_crtc_source(xf86OutputPtr output) + crtc_src_param2.ucEncoderID = ASIC_INT_DIG2_ENCODER_ID; + else + crtc_src_param2.ucEncoderID = ASIC_INT_DIG1_ENCODER_ID; +- } else +- crtc_src_param2.ucEncoderID = ASIC_INT_DIG1_ENCODER_ID; ++ } else { ++ /* doesn't really matter which dig encoder we pick as long as it's ++ * not already in use ++ */ ++ if (radeon_output->linkb) ++ crtc_src_param2.ucEncoderID = ASIC_INT_DIG2_ENCODER_ID; ++ else ++ crtc_src_param2.ucEncoderID = ASIC_INT_DIG1_ENCODER_ID; ++ } + break; + case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA: ++ /* Only dig2 encoder can drive LVTMA */ + crtc_src_param2.ucEncoderID = ASIC_INT_DIG2_ENCODER_ID; + break; + case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1: +@@ -1543,14 +1615,14 @@ atombios_output_mode_set(xf86OutputPtr output, + case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2: + case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA: + /* disable encoder and transmitter */ +- atombios_output_dig_transmitter_setup(output, ATOM_TRANSMITTER_ACTION_DISABLE); ++ atombios_output_dig_transmitter_setup(output, ATOM_TRANSMITTER_ACTION_DISABLE, 0, 0); + atombios_output_dig_encoder_setup(output, ATOM_DISABLE); + + /* setup and enable the encoder and transmitter */ + atombios_output_dig_encoder_setup(output, ATOM_ENABLE); +- atombios_output_dig_transmitter_setup(output, ATOM_TRANSMITTER_ACTION_INIT); +- atombios_output_dig_transmitter_setup(output, ATOM_TRANSMITTER_ACTION_SETUP); +- atombios_output_dig_transmitter_setup(output, ATOM_TRANSMITTER_ACTION_ENABLE); ++ atombios_output_dig_transmitter_setup(output, ATOM_TRANSMITTER_ACTION_INIT, 0, 0); ++ atombios_output_dig_transmitter_setup(output, ATOM_TRANSMITTER_ACTION_SETUP, 0, 0); ++ atombios_output_dig_transmitter_setup(output, ATOM_TRANSMITTER_ACTION_ENABLE, 0, 0); + break; + case ENCODER_OBJECT_ID_INTERNAL_DDI: + atombios_output_ddia_setup(output, ATOM_ENABLE); +@@ -1686,3 +1758,849 @@ atombios_dac_detect(xf86OutputPtr output) + return MonType; + } + ++#define AUX_NATIVE_WRITE 0x8 ++#define AUX_NATIVE_READ 0x9 ++ ++#define AUX_I2C_WRITE 0x0 ++#define AUX_I2C_READ 0x1 ++#define AUX_I2C_STATUS 0x2 ++#define AUX_I2C_MOT 0x4 ++ ++#define DP_DPCD_REV 0x0 ++#define DP_MAX_LINK_RATE 0x1 ++#define DP_MAX_LANE_COUNT 0x2 ++#define DP_MAX_DOWNSPREAD 0x3 ++#define DP_NORP 0x4 ++#define DP_DOWNSTREAMPORT_PRESENT 0x5 ++#define DP_MAIN_LINK_CHANNEL_CONFIG 0x6 ++#define DP_DP11_DOWNSTREAM_PORT_COUNT 0x7 ++ ++/* from intel i830_dp.h */ ++#define DP_LINK_BW_SET 0x100 ++//# define DP_LINK_BW_1_62 0x06 ++//# define DP_LINK_BW_2_7 0x0a ++#define DP_LANE_COUNT_SET 0x101 ++# define DP_LANE_COUNT_MASK 0x0f ++# define DP_LANE_COUNT_ENHANCED_FRAME_EN (1 << 7) ++ ++#define DP_TRAINING_PATTERN_SET 0x102 ++ ++# define DP_TRAINING_PATTERN_DISABLE 0 ++# define DP_TRAINING_PATTERN_1 1 ++# define DP_TRAINING_PATTERN_2 2 ++# define DP_TRAINING_PATTERN_MASK 0x3 ++ ++# define DP_LINK_QUAL_PATTERN_DISABLE (0 << 2) ++# define DP_LINK_QUAL_PATTERN_D10_2 (1 << 2) ++# define DP_LINK_QUAL_PATTERN_ERROR_RATE (2 << 2) ++# define DP_LINK_QUAL_PATTERN_PRBS7 (3 << 2) ++# define DP_LINK_QUAL_PATTERN_MASK (3 << 2) ++# define DP_RECOVERED_CLOCK_OUT_EN (1 << 4) ++# define DP_LINK_SCRAMBLING_DISABLE (1 << 5) ++ ++# define DP_SYMBOL_ERROR_COUNT_BOTH (0 << 6) ++# define DP_SYMBOL_ERROR_COUNT_DISPARITY (1 << 6) ++# define DP_SYMBOL_ERROR_COUNT_SYMBOL (2 << 6) ++# define DP_SYMBOL_ERROR_COUNT_MASK (3 << 6) ++ ++#define DP_TRAINING_LANE0_SET 0x103 ++#define DP_TRAINING_LANE1_SET 0x104 ++#define DP_TRAINING_LANE2_SET 0x105 ++#define DP_TRAINING_LANE3_SET 0x106 ++# define DP_TRAIN_VOLTAGE_SWING_MASK 0x3 ++# define DP_TRAIN_VOLTAGE_SWING_SHIFT 0 ++# define DP_TRAIN_MAX_SWING_REACHED (1 << 2) ++# define DP_TRAIN_VOLTAGE_SWING_400 (0 << 0) ++# define DP_TRAIN_VOLTAGE_SWING_600 (1 << 0) ++# define DP_TRAIN_VOLTAGE_SWING_800 (2 << 0) ++# define DP_TRAIN_VOLTAGE_SWING_1200 (3 << 0) ++ ++# define DP_TRAIN_PRE_EMPHASIS_MASK (3 << 3) ++# define DP_TRAIN_PRE_EMPHASIS_0 (0 << 3) ++# define DP_TRAIN_PRE_EMPHASIS_3_5 (1 << 3) ++# define DP_TRAIN_PRE_EMPHASIS_6 (2 << 3) ++# define DP_TRAIN_PRE_EMPHASIS_9_5 (3 << 3) ++ ++# define DP_TRAIN_PRE_EMPHASIS_SHIFT 3 ++# define DP_TRAIN_MAX_PRE_EMPHASIS_REACHED (1 << 5) ++#define DP_DOWNSPREAD_CTRL 0x107 ++# define DP_SPREAD_AMP_0_5 (1 << 4) ++ ++#define DP_MAIN_LINK_CHANNEL_CODING_SET 0x108 ++# define DP_SET_ANSI_8B10B (1 << 0) ++ ++#define DP_LANE0_1_STATUS 0x202 ++#define DP_LANE2_3_STATUS 0x203 ++ ++# define DP_LANE_CR_DONE (1 << 0) ++# define DP_LANE_CHANNEL_EQ_DONE (1 << 1) ++# define DP_LANE_SYMBOL_LOCKED (1 << 2) ++ ++#define DP_LANE_ALIGN_STATUS_UPDATED 0x204 ++#define DP_INTERLANE_ALIGN_DONE (1 << 0) ++#define DP_DOWNSTREAM_PORT_STATUS_CHANGED (1 << 6) ++#define DP_LINK_STATUS_UPDATED (1 << 7) ++ ++#define DP_SINK_STATUS 0x205 ++ ++#define DP_RECEIVE_PORT_0_STATUS (1 << 0) ++#define DP_RECEIVE_PORT_1_STATUS (1 << 1) ++ ++#define DP_ADJUST_REQUEST_LANE0_1 0x206 ++#define DP_ADJUST_REQUEST_LANE2_3 0x207 ++ ++#define DP_ADJUST_VOLTAGE_SWING_LANE0_MASK 0x03 ++#define DP_ADJUST_VOLTAGE_SWING_LANE0_SHIFT 0 ++#define DP_ADJUST_PRE_EMPHASIS_LANE0_MASK 0x0c ++#define DP_ADJUST_PRE_EMPHASIS_LANE0_SHIFT 2 ++#define DP_ADJUST_VOLTAGE_SWING_LANE1_MASK 0x30 ++#define DP_ADJUST_VOLTAGE_SWING_LANE1_SHIFT 4 ++#define DP_ADJUST_PRE_EMPHASIS_LANE1_MASK 0xc0 ++#define DP_ADJUST_PRE_EMPHASIS_LANE1_SHIFT 6 ++ ++#define DP_LINK_STATUS_SIZE 6 ++#define DP_LINK_CONFIGURATION_SIZE 9 ++ ++#define DP_SET_POWER_D0 0x1 ++#define DP_SET_POWER_D3 0x2 ++ ++static inline int atom_dp_get_encoder_id(xf86OutputPtr output) ++{ ++ RADEONInfoPtr info = RADEONPTR(output->scrn); ++ RADEONOutputPrivatePtr radeon_output = output->driver_private; ++ int ret = 0; ++ if (IS_DCE32_VARIANT) { ++ if (radeon_output->dig_block) ++ ret |= ATOM_DP_CONFIG_DIG2_ENCODER; ++ else ++ ret |= ATOM_DP_CONFIG_DIG1_ENCODER; ++ if (radeon_output->linkb) ++ ret |= ATOM_DP_CONFIG_LINK_B; ++ else ++ ret |= ATOM_DP_CONFIG_LINK_A; ++ } else { ++ if (radeon_output->linkb) ++ ret |= ATOM_DP_CONFIG_DIG2_ENCODER | ATOM_DP_CONFIG_LINK_B; ++ else ++ ret |= ATOM_DP_CONFIG_DIG1_ENCODER | ATOM_DP_CONFIG_LINK_A; ++ } ++ return ret; ++} ++ ++Bool ++RADEONProcessAuxCH(xf86OutputPtr output, uint8_t *req_bytes, uint8_t num_bytes, ++ uint8_t *read_byte, uint8_t read_buf_len, uint8_t delay) ++{ ++ RADEONOutputPrivatePtr radeon_output = output->driver_private; ++ RADEONInfoPtr info = RADEONPTR(output->scrn); ++ PROCESS_AUX_CHANNEL_TRANSACTION_PS_ALLOCATION args; ++ AtomBiosArgRec data; ++ unsigned char *space; ++ unsigned char *base; ++ ++ memset(&args, 0, sizeof(args)); ++ if (info->atomBIOS->fbBase) ++ base = info->FB + info->atomBIOS->fbBase; ++ else if (info->atomBIOS->scratchBase) ++ base = (unsigned char *)info->atomBIOS->scratchBase; ++ else ++ return FALSE; ++ ++ memcpy(base, req_bytes, num_bytes); ++ ++ args.lpAuxRequest = 0; ++ args.lpDataOut = 16; ++ args.ucDataOutLen = 0; ++ args.ucChannelID = radeon_output->ucI2cId; ++ args.ucDelay = delay / 10; /* 10 usec */ ++ ++ data.exec.index = GetIndexIntoMasterTable(COMMAND, ProcessAuxChannelTransaction); ++ data.exec.dataSpace = (void *)&space; ++ data.exec.pspace = &args; ++ ++ RHDAtomBiosFunc(info->atomBIOS->scrnIndex, info->atomBIOS, ATOMBIOS_EXEC, &data); ++ if (args.ucReplyStatus) { ++ ErrorF("failed to get auxch %02x%02x %02x %02x %02x\n", ++ req_bytes[1], req_bytes[0], req_bytes[2], req_bytes[3],args.ucReplyStatus); ++ return FALSE; ++ } ++ if (args.ucDataOutLen && read_byte && read_buf_len) { ++ if (read_buf_len < args.ucDataOutLen) { ++ ErrorF("%s: Buffer too small for return answer %d %d\n", __func__, read_buf_len, args.ucDataOutLen); ++ return FALSE; ++ } ++ { ++ int len = read_buf_len < args.ucDataOutLen ? read_buf_len : args.ucDataOutLen; ++ memcpy(read_byte, base+16, len); ++ } ++ } ++ return TRUE; ++} ++ ++static int ++RADEONDPEncoderService(xf86OutputPtr output, int action, uint8_t ucconfig, uint8_t lane_num) ++{ ++ RADEONInfoPtr info = RADEONPTR(output->scrn); ++ DP_ENCODER_SERVICE_PARAMETERS args; ++ AtomBiosArgRec data; ++ unsigned char *space; ++ ++ memset(&args, 0, sizeof(args)); ++ ++ args.ucLinkClock = 0; ++ args.ucConfig = ucconfig; ++ args.ucAction = action; ++ args.ucLaneNum = lane_num; ++ args.ucStatus = 0; ++ ++ data.exec.index = GetIndexIntoMasterTable(COMMAND, DPEncoderService); ++ data.exec.dataSpace = (void *)&space; ++ data.exec.pspace = &args; ++ ++ RHDAtomBiosFunc(info->atomBIOS->scrnIndex, info->atomBIOS, ATOMBIOS_EXEC, &data); ++ ++ ErrorF("%s: %d\n", __func__, args.ucStatus); ++ return args.ucStatus; ++} ++ ++int RADEON_DP_GetSinkType(xf86OutputPtr output) ++{ ++ RADEONOutputPrivatePtr radeon_output = output->driver_private; ++ ++ return RADEONDPEncoderService(output, ATOM_DP_ACTION_GET_SINK_TYPE, radeon_output->ucI2cId, 0); ++} ++ ++static Bool atom_dp_aux_native_write(xf86OutputPtr output, uint16_t address, ++ uint8_t send_bytes, uint8_t *send) ++{ ++ uint8_t msg[20]; ++ uint8_t msg_len, dp_msg_len; ++ int ret; ++ ++ dp_msg_len = 4; ++ msg[0] = address; ++ msg[1] = address >> 8; ++ msg[2] = AUX_NATIVE_WRITE << 4; ++ dp_msg_len += send_bytes; ++ msg[3] = (dp_msg_len << 4)| (send_bytes - 1); ++ ++ if (0) ++ ErrorF("writing %02x %02x %02x, %d, %d\n", msg[0], msg[1], msg[3], send_bytes, dp_msg_len); ++ if (send_bytes > 16) ++ return FALSE; ++ ++ memcpy(&msg[4], send, send_bytes); ++ msg_len = 4 + send_bytes; ++ ret = RADEONProcessAuxCH(output, msg, msg_len, NULL, 0, 0); ++ return ret; ++} ++ ++static Bool atom_dp_aux_native_read(xf86OutputPtr output, uint16_t address, ++ uint8_t delay, ++ uint8_t expected_bytes, uint8_t *read_p) ++{ ++ uint8_t msg[20]; ++ uint8_t msg_len, dp_msg_len; ++ int ret; ++ ++ msg_len = 4; ++ dp_msg_len = 4; ++ msg[0] = address; ++ msg[1] = address >> 8; ++ msg[2] = AUX_NATIVE_READ << 4; ++ msg[3] = (dp_msg_len) << 4; ++ msg[3] |= expected_bytes - 1; ++ ++ if (0) ++ ErrorF("reading %02x %02x %02x, %d, %d\n", msg[0], msg[1], msg[3], expected_bytes, dp_msg_len); ++ ret = RADEONProcessAuxCH(output, msg, msg_len, read_p, expected_bytes, delay); ++ return ret; ++} ++ ++/* fill out the DPCD structure */ ++void RADEON_DP_GetDPCD(xf86OutputPtr output) ++{ ++ RADEONOutputPrivatePtr radeon_output = output->driver_private; ++ uint8_t msg[25]; ++ int ret; ++ ++ ret = atom_dp_aux_native_read(output, DP_DPCD_REV, 0, 8, msg); ++ if (ret) { ++ memcpy(radeon_output->dpcd, msg, 8); ++ if (0) { ++ int i; ++ ErrorF("DPCD: "); ++ for (i = 0; i < 8; i++) ++ ErrorF("%02x ", radeon_output->dpcd[i]); ++ ErrorF("\n"); ++ } ++ ret = atom_dp_aux_native_read(output, DP_LINK_BW_SET, 0, 2, msg); ++ if (0) { ++ ErrorF("0x200: %02x %02x\n", msg[0], msg[1]); ++ } ++ return; ++ } ++ radeon_output->dpcd[0] = 0; ++ return; ++} ++ ++ ++enum dp_aux_i2c_mode { ++ dp_aux_i2c_start, ++ dp_aux_i2c_write, ++ dp_aux_i2c_read, ++ dp_aux_i2c_stop, ++}; ++ ++ ++static Bool atom_dp_aux_i2c_transaction(xf86OutputPtr output, uint16_t address, ++ enum dp_aux_i2c_mode mode, ++ uint8_t write_byte, uint8_t *read_byte) ++{ ++ uint8_t msg[8], msg_len, dp_msg_len; ++ int ret; ++ int auxch_cmd = 0; ++ ++ memset(msg, 0, 8); ++ ++ if (mode != dp_aux_i2c_stop) ++ auxch_cmd = AUX_I2C_MOT; ++ ++ if (address & 1) ++ auxch_cmd |= AUX_I2C_READ; ++ else ++ auxch_cmd |= AUX_I2C_WRITE; ++ ++ msg[2] = auxch_cmd << 4; ++ ++ msg[4] = 0; ++ msg[0] = (address >> 1); ++ msg[1] = (address >> 9); ++ ++ msg_len = 4; ++ dp_msg_len = 3; ++ switch (mode) { ++ case dp_aux_i2c_read: ++ /* bottom bits is byte count - 1 so for 1 byte == 0 */ ++ dp_msg_len += 1; ++ break; ++ case dp_aux_i2c_write: ++ dp_msg_len += 2; ++ msg[4] = write_byte; ++ msg_len++; ++ break; ++ default: ++ break; ++ } ++ msg[3] = dp_msg_len << 4; ++ ++ ret = RADEONProcessAuxCH(output, msg, msg_len, read_byte, 1, 0); ++ return ret; ++} ++ ++static Bool ++atom_dp_i2c_address(I2CDevPtr dev, I2CSlaveAddr addr) ++{ ++ I2CBusPtr bus = dev->pI2CBus; ++ xf86OutputPtr output = bus->DriverPrivate.ptr; ++ RADEONOutputPrivatePtr radeon_output = output->driver_private; ++ int ret; ++ ++ radeon_output->dp_i2c_addr = addr; ++ radeon_output->dp_i2c_running = TRUE; ++ ++ /* call i2c start */ ++ ret = atom_dp_aux_i2c_transaction(output, radeon_output->dp_i2c_addr, ++ dp_aux_i2c_start, 0, NULL); ++ ++ return ret; ++} ++static Bool ++atom_dp_i2c_start(I2CBusPtr bus, int timeout) ++{ ++ ErrorF("%s\n", __func__); ++ return TRUE; ++} ++ ++static void ++atom_dp_i2c_stop(I2CDevPtr dev) ++{ ++ I2CBusPtr bus = dev->pI2CBus; ++ xf86OutputPtr output = bus->DriverPrivate.ptr; ++ RADEONOutputPrivatePtr radeon_output = output->driver_private; ++ ++ if (radeon_output->dp_i2c_running) ++ atom_dp_aux_i2c_transaction(output, radeon_output->dp_i2c_addr, ++ dp_aux_i2c_stop, 0, NULL); ++ radeon_output->dp_i2c_running = FALSE; ++} ++ ++ ++static Bool ++atom_dp_i2c_put_byte(I2CDevPtr dev, I2CByte byte) ++{ ++ I2CBusPtr bus = dev->pI2CBus; ++ xf86OutputPtr output = bus->DriverPrivate.ptr; ++ RADEONOutputPrivatePtr radeon_output = output->driver_private; ++ Bool ret; ++ ++ ret = (atom_dp_aux_i2c_transaction(output, radeon_output->dp_i2c_addr, ++ dp_aux_i2c_write, byte, NULL)); ++ return ret; ++} ++ ++static Bool ++atom_dp_i2c_get_byte(I2CDevPtr dev, I2CByte *byte_ret, Bool last) ++{ ++ I2CBusPtr bus = dev->pI2CBus; ++ xf86OutputPtr output = bus->DriverPrivate.ptr; ++ RADEONOutputPrivatePtr radeon_output = output->driver_private; ++ Bool ret; ++ ++ ret = (atom_dp_aux_i2c_transaction(output, radeon_output->dp_i2c_addr, ++ dp_aux_i2c_read, 0, byte_ret)); ++ return ret; ++} ++ ++Bool ++RADEON_DP_I2CInit(ScrnInfoPtr pScrn, I2CBusPtr *bus_ptr, char *name, xf86OutputPtr output) ++{ ++ I2CBusPtr pI2CBus; ++ ++ pI2CBus = xf86CreateI2CBusRec(); ++ if (!pI2CBus) return FALSE; ++ ++ pI2CBus->BusName = name; ++ pI2CBus->scrnIndex = pScrn->scrnIndex; ++ pI2CBus->I2CGetByte = atom_dp_i2c_get_byte; ++ pI2CBus->I2CPutByte = atom_dp_i2c_put_byte; ++ pI2CBus->I2CAddress = atom_dp_i2c_address; ++ pI2CBus->I2CStart = atom_dp_i2c_start; ++ pI2CBus->I2CStop = atom_dp_i2c_stop; ++ pI2CBus->DriverPrivate.ptr = output; ++ ++ /* ++ * These were set incorrectly in the server pre-1.3, Having ++ * duplicate settings is sub-optimal, but this lets the driver ++ * work with older servers ++ */ ++ pI2CBus->ByteTimeout = 2200; /* VESA DDC spec 3 p. 43 (+10 %) */ ++ pI2CBus->StartTimeout = 550; ++ pI2CBus->BitTimeout = 40; ++ pI2CBus->AcknTimeout = 40; ++ pI2CBus->RiseFallTime = 20; ++ ++ if (!xf86I2CBusInit(pI2CBus)) ++ return FALSE; ++ ++ *bus_ptr = pI2CBus; ++ return TRUE; ++} ++ ++ ++static uint8_t dp_link_status(uint8_t link_status[DP_LINK_STATUS_SIZE], int r) ++{ ++ return link_status[r - DP_LANE0_1_STATUS]; ++} ++ ++static uint8_t dp_get_lane_status(uint8_t link_status[DP_LINK_STATUS_SIZE], int lane) ++{ ++ int i = DP_LANE0_1_STATUS + (lane >> 1); ++ int s = (lane & 1) * 4; ++ uint8_t l = dp_link_status(link_status, i); ++ return (l >> s) & 0xf; ++} ++ ++static Bool dp_clock_recovery_ok(uint8_t link_status[DP_LINK_STATUS_SIZE], int lane_count) ++{ ++ int lane; ++ ++ uint8_t lane_status; ++ ++ for (lane = 0; lane < lane_count; lane++) { ++ lane_status = dp_get_lane_status(link_status, lane); ++ if ((lane_status & DP_LANE_CR_DONE) == 0) ++ return FALSE; ++ } ++ return TRUE; ++} ++ ++ ++/* Check to see if channel eq is done on all channels */ ++#define CHANNEL_EQ_BITS (DP_LANE_CR_DONE|\ ++ DP_LANE_CHANNEL_EQ_DONE|\ ++ DP_LANE_SYMBOL_LOCKED) ++static Bool ++dp_channel_eq_ok(uint8_t link_status[DP_LINK_STATUS_SIZE], int lane_count) ++{ ++ uint8_t lane_align; ++ uint8_t lane_status; ++ int lane; ++ ++ lane_align = dp_link_status(link_status, ++ DP_LANE_ALIGN_STATUS_UPDATED); ++ if ((lane_align & DP_INTERLANE_ALIGN_DONE) == 0) ++ return FALSE; ++ for (lane = 0; lane < lane_count; lane++) { ++ lane_status = dp_get_lane_status(link_status, lane); ++ if ((lane_status & CHANNEL_EQ_BITS) != CHANNEL_EQ_BITS) ++ return FALSE; ++ } ++ return TRUE; ++} ++ ++/* ++ * Fetch AUX CH registers 0x202 - 0x207 which contain ++ * link status information ++ */ ++static Bool ++atom_dp_get_link_status(xf86OutputPtr output, ++ uint8_t link_status[DP_LINK_STATUS_SIZE]) ++{ ++ ScrnInfoPtr pScrn = output->scrn; ++ int ret; ++ ret = atom_dp_aux_native_read(output, DP_LANE0_1_STATUS, 100, ++ DP_LINK_STATUS_SIZE, link_status); ++ if (!ret) { ++ xf86DrvMsg(pScrn->scrnIndex, X_INFO, "dp link status failed\n"); ++ return FALSE; ++ } ++ ErrorF("link status %02x %02x %02x %02x %02x %02x\n", link_status[0], link_status[1], ++ link_status[2], link_status[3], link_status[4], link_status[5]); ++ ++ return TRUE; ++} ++ ++static uint8_t ++dp_get_adjust_request_voltage(uint8_t link_status[DP_LINK_STATUS_SIZE], ++ int lane) ++ ++{ ++ int i = DP_ADJUST_REQUEST_LANE0_1 + (lane >> 1); ++ int s = ((lane & 1) ? ++ DP_ADJUST_VOLTAGE_SWING_LANE1_SHIFT : ++ DP_ADJUST_VOLTAGE_SWING_LANE0_SHIFT); ++ uint8_t l = dp_link_status(link_status, i); ++ ++ return ((l >> s) & 3) << DP_TRAIN_VOLTAGE_SWING_SHIFT; ++} ++ ++static uint8_t ++dp_get_adjust_request_pre_emphasis(uint8_t link_status[DP_LINK_STATUS_SIZE], ++ int lane) ++{ ++ int i = DP_ADJUST_REQUEST_LANE0_1 + (lane >> 1); ++ int s = ((lane & 1) ? ++ DP_ADJUST_PRE_EMPHASIS_LANE1_SHIFT : ++ DP_ADJUST_PRE_EMPHASIS_LANE0_SHIFT); ++ uint8_t l = dp_link_status(link_status, i); ++ ++ return ((l >> s) & 3) << DP_TRAIN_PRE_EMPHASIS_SHIFT; ++} ++ ++static char *voltage_names[] = { ++ "0.4V", "0.6V", "0.8V", "1.2V" ++}; ++static char *pre_emph_names[] = { ++ "0dB", "3.5dB", "6dB", "9.5dB" ++}; ++ ++/* ++ * These are source-specific values; current Intel hardware supports ++ * a maximum voltage of 800mV and a maximum pre-emphasis of 6dB ++ */ ++#define DP_VOLTAGE_MAX DP_TRAIN_VOLTAGE_SWING_1200 ++ ++static uint8_t ++dp_pre_emphasis_max(uint8_t voltage_swing) ++{ ++ switch (voltage_swing & DP_TRAIN_VOLTAGE_SWING_MASK) { ++ case DP_TRAIN_VOLTAGE_SWING_400: ++ return DP_TRAIN_PRE_EMPHASIS_6; ++ case DP_TRAIN_VOLTAGE_SWING_600: ++ return DP_TRAIN_PRE_EMPHASIS_6; ++ case DP_TRAIN_VOLTAGE_SWING_800: ++ return DP_TRAIN_PRE_EMPHASIS_3_5; ++ case DP_TRAIN_VOLTAGE_SWING_1200: ++ default: ++ return DP_TRAIN_PRE_EMPHASIS_0; ++ } ++} ++ ++static void dp_set_training(xf86OutputPtr output, uint8_t training) ++{ ++ atom_dp_aux_native_write(output, DP_TRAINING_PATTERN_SET, 1, &training); ++} ++ ++static void dp_set_power(xf86OutputPtr output, uint8_t power_state) ++{ ++ RADEONOutputPrivatePtr radeon_output = output->driver_private; ++ ++ if (radeon_output->dpcd[0] >= 0x11) { ++ atom_dp_aux_native_write(output, 0x600, 1, &power_state); ++ } ++} ++ ++static void ++dp_get_adjust_train(xf86OutputPtr output, ++ uint8_t link_status[DP_LINK_STATUS_SIZE], ++ int lane_count, ++ uint8_t train_set[4]) ++{ ++ ScrnInfoPtr pScrn = output->scrn; ++ uint8_t v = 0; ++ uint8_t p = 0; ++ int lane; ++ ++ for (lane = 0; lane < lane_count; lane++) { ++ uint8_t this_v = dp_get_adjust_request_voltage(link_status, lane); ++ uint8_t this_p = dp_get_adjust_request_pre_emphasis(link_status, lane); ++ ++ if (0) { ++ xf86DrvMsg(pScrn->scrnIndex, X_INFO, ++ "requested signal parameters: lane %d voltage %s pre_emph %s\n", ++ lane, ++ voltage_names[this_v >> DP_TRAIN_VOLTAGE_SWING_SHIFT], ++ pre_emph_names[this_p >> DP_TRAIN_PRE_EMPHASIS_SHIFT]); ++ } ++ if (this_v > v) ++ v = this_v; ++ if (this_p > p) ++ p = this_p; ++ } ++ ++ if (v >= DP_VOLTAGE_MAX) ++ v = DP_VOLTAGE_MAX | DP_TRAIN_MAX_SWING_REACHED; ++ ++ if (p >= dp_pre_emphasis_max(v)) ++ p = dp_pre_emphasis_max(v) | DP_TRAIN_MAX_PRE_EMPHASIS_REACHED; ++ ++ if (0) { ++ xf86DrvMsg(pScrn->scrnIndex, X_INFO, ++ "using signal parameters: voltage %s pre_emph %s\n", ++ voltage_names[(v & DP_TRAIN_VOLTAGE_SWING_MASK) >> DP_TRAIN_VOLTAGE_SWING_SHIFT], ++ pre_emph_names[(p & DP_TRAIN_PRE_EMPHASIS_MASK) >> DP_TRAIN_PRE_EMPHASIS_SHIFT]); ++ } ++ for (lane = 0; lane < 4; lane++) ++ train_set[lane] = v | p; ++} ++ ++static int radeon_dp_max_lane_count(xf86OutputPtr output) ++{ ++ RADEONOutputPrivatePtr radeon_output = output->driver_private; ++ int max_lane_count = 4; ++ ++ if (radeon_output->dpcd[0] >= 0x11) { ++ max_lane_count = radeon_output->dpcd[2] & 0x1f; ++ switch(max_lane_count) { ++ case 1: case 2: case 4: ++ break; ++ default: ++ max_lane_count = 4; ++ } ++ } ++ return max_lane_count; ++} ++ ++static int radeon_dp_max_link_bw(xf86OutputPtr output) ++{ ++ RADEONOutputPrivatePtr radeon_output = output->driver_private; ++ int max_link_bw = radeon_output->dpcd[1]; ++ switch(max_link_bw) { ++ case DP_LINK_BW_1_62: ++ case DP_LINK_BW_2_7: ++ break; ++ default: ++ max_link_bw = DP_LINK_BW_1_62; ++ break; ++ } ++ return max_link_bw; ++} ++ ++static int radeon_dp_link_clock(uint8_t link_bw) ++{ ++ if (link_bw == DP_LINK_BW_2_7) ++ return 270000; ++ else ++ return 162000; ++} ++ ++ ++/* I think this is a fiction */ ++static int radeon_dp_link_required(int pixel_clock) ++{ ++ return pixel_clock * 3; ++} ++ ++Bool radeon_dp_mode_fixup(xf86OutputPtr output, DisplayModePtr mode, DisplayModePtr adjusted_mode) ++{ ++ RADEONOutputPrivatePtr radeon_output = output->driver_private; ++ int lane_count, clock; ++ int max_lane_count = radeon_dp_max_lane_count(output); ++ int max_clock = radeon_dp_max_link_bw(output) == DP_LINK_BW_2_7 ? 1 : 0; ++ static int bws[2] = { DP_LINK_BW_1_62, DP_LINK_BW_2_7 }; ++ ++ for (lane_count = 1; lane_count <= max_lane_count; lane_count <<= 1) { ++ for (clock = 0; clock <= max_clock; clock++) { ++ int link_avail = radeon_dp_link_clock(bws[clock]) * lane_count; ++ ++ if (radeon_dp_link_required(mode->Clock) <= link_avail) { ++ radeon_output->dp_lane_count = lane_count; ++ radeon_output->dp_clock = radeon_dp_link_clock(bws[clock]); ++ if (0) ++ xf86DrvMsg(0, X_INFO, ++ "lane_count %d clock %d\n", ++ radeon_output->dp_lane_count, ++ radeon_output->dp_clock); ++ return TRUE; ++ } ++ } ++ } ++ return FALSE; ++} ++ ++static void dp_update_dpvs_emph(xf86OutputPtr output, uint8_t train_set[4]) ++{ ++ RADEONOutputPrivatePtr radeon_output = output->driver_private; ++ int i; ++ for (i = 0; i < radeon_output->dp_lane_count; i++) ++ atombios_output_dig_transmitter_setup(output, ATOM_TRANSMITTER_ACTION_SETUP_VSEMPH, i, train_set[i]); ++ ++ atom_dp_aux_native_write(output, DP_TRAINING_LANE0_SET, radeon_output->dp_lane_count, train_set); ++} ++ ++static void do_displayport_link_train(xf86OutputPtr output) ++{ ++ ScrnInfoPtr pScrn = output->scrn; ++ RADEONOutputPrivatePtr radeon_output = output->driver_private; ++ int enc_id = atom_dp_get_encoder_id(output); ++ Bool clock_recovery; ++ uint8_t link_status[DP_LINK_STATUS_SIZE]; ++ uint8_t tries, voltage, ss_cntl; ++ uint8_t train_set[4]; ++ int i; ++ Bool channel_eq; ++ uint8_t dp_link_configuration[DP_LINK_CONFIGURATION_SIZE]; ++ ++ memset(train_set, 0, 4); ++ ++ /* set up link configuration */ ++ memset(dp_link_configuration, 0, DP_LINK_CONFIGURATION_SIZE); ++ ++ if (radeon_output->dp_clock == 270000) ++ dp_link_configuration[0] = DP_LINK_BW_2_7; ++ else ++ dp_link_configuration[0] = DP_LINK_BW_1_62; ++ dp_link_configuration[1] = radeon_output->dp_lane_count; ++ ++ if (radeon_output->dpcd[0] >= 0x11) { ++ dp_link_configuration[1] |= DP_LANE_COUNT_ENHANCED_FRAME_EN; ++ } ++ ++ /* power up to D0 */ ++ dp_set_power(output, DP_SET_POWER_D0); ++ ++ /* disable training */ ++ dp_set_training(output, DP_TRAINING_PATTERN_DISABLE); ++ ++ /* write link rate / num / eh framing */ ++ atom_dp_aux_native_write(output, DP_LINK_BW_SET, 2, ++ dp_link_configuration); ++ ++ /* write ss cntl */ ++ ss_cntl = 0; ++ atom_dp_aux_native_write(output, DP_DOWNSPREAD_CTRL, 1, ++ &ss_cntl); ++ ++ /* start local training start */ ++ RADEONDPEncoderService(output, ATOM_DP_ACTION_TRAINING_START, enc_id, 0); ++ RADEONDPEncoderService(output, ATOM_DP_ACTION_TRAINING_PATTERN_SEL, enc_id, 0); ++ ++ usleep(400); ++ dp_set_training(output, DP_TRAINING_PATTERN_1); ++ dp_update_dpvs_emph(output, train_set); ++ ++ /* loop around doing configuration reads and DP encoder setups */ ++ clock_recovery = FALSE; ++ tries = 0; ++ voltage = 0xff; ++ for (;;) { ++ usleep(100); ++ if (!atom_dp_get_link_status(output, link_status)) ++ break; ++ ++ if (dp_clock_recovery_ok(link_status, radeon_output->dp_lane_count)) { ++ clock_recovery = TRUE; ++ break; ++ } ++ ++ for (i = 0; i < radeon_output->dp_lane_count; i++) ++ if ((train_set[i] & DP_TRAIN_MAX_SWING_REACHED) == 0) ++ break; ++ if (i == radeon_output->dp_lane_count) { ++ xf86DrvMsg(pScrn->scrnIndex, X_INFO, ++ "clock recovery reached max voltage\n"); ++ break; ++ } ++ ++ /* Check to see if we've tried the same voltage 5 times */ ++ if ((train_set[0] & DP_TRAIN_VOLTAGE_SWING_MASK) == voltage) { ++ ++tries; ++ if (tries == 5) { ++ xf86DrvMsg(pScrn->scrnIndex, X_INFO, ++ "clock recovery tried 5 times\n"); ++ break; ++ } ++ } else ++ tries = 0; ++ ++ voltage = train_set[0] & DP_TRAIN_VOLTAGE_SWING_MASK; ++ ++ dp_get_adjust_train(output, link_status, radeon_output->dp_lane_count, train_set); ++ dp_update_dpvs_emph(output, train_set); ++ ++ } ++ ++ if (!clock_recovery) ++ xf86DrvMsg(pScrn->scrnIndex, X_ERROR, ++ "clock recovery failed\n"); ++ ++ /* channel equalization */ ++ tries = 0; ++ channel_eq = FALSE; ++ dp_set_training(output, DP_TRAINING_PATTERN_2); ++ RADEONDPEncoderService(output, ATOM_DP_ACTION_TRAINING_PATTERN_SEL, enc_id, 1); ++ ++ for (;;) { ++ usleep(400); ++ if (!atom_dp_get_link_status(output, link_status)) ++ break; ++ ++ if (dp_channel_eq_ok(link_status, radeon_output->dp_lane_count)) { ++ channel_eq = TRUE; ++ break; ++ } ++ ++ /* Try 5 times */ ++ if (tries > 5) { ++ xf86DrvMsg(pScrn->scrnIndex, X_INFO, ++ "channel eq failed: 5 tries\n"); ++ break; ++ } ++ ++ /* Compute new train_set as requested by target */ ++ dp_get_adjust_train(output, link_status, radeon_output->dp_lane_count, train_set); ++ dp_update_dpvs_emph(output, train_set); ++ ++ ++tries; ++ } ++ ++ if (!channel_eq) ++ xf86DrvMsg(pScrn->scrnIndex, X_ERROR, ++ "channel eq failed\n"); ++ ++ dp_set_training(output, DP_TRAINING_PATTERN_DISABLE); ++ RADEONDPEncoderService(output, ATOM_DP_ACTION_TRAINING_COMPLETE, enc_id, 0); ++ ++} ++ +diff --git a/src/radeon.h b/src/radeon.h +index 1b8ae3c..c9f388a 100644 +--- a/src/radeon.h ++++ b/src/radeon.h +@@ -1218,6 +1218,10 @@ void RADEONFreeRec(ScrnInfoPtr pScrn); + Bool RADEONPreInitVisual(ScrnInfoPtr pScrn); + Bool RADEONPreInitWeight(ScrnInfoPtr pScrn); + ++extern Bool RADEON_DP_I2CInit(ScrnInfoPtr pScrn, I2CBusPtr *bus_ptr, ++ char *name, xf86OutputPtr output); ++extern void RADEON_DP_GetDPCD(xf86OutputPtr output); ++extern int RADEON_DP_GetSinkType(xf86OutputPtr output); + + /* radeon_pm.c */ + extern void RADEONPMInit(ScrnInfoPtr pScrn); +@@ -1274,6 +1278,7 @@ extern void RADEONSetOutputType(ScrnInfoPtr pScrn, + extern Bool RADEONSetupConnectors(ScrnInfoPtr pScrn); + extern Bool RADEONI2CDoLock(xf86OutputPtr output, I2CBusPtr b, Bool lock_state); + ++extern Bool radeon_dp_mode_fixup(xf86OutputPtr output, DisplayModePtr mode, DisplayModePtr adjusted_mode); + + /* radeon_tv.c */ + extern void RADEONSaveTVRegisters(ScrnInfoPtr pScrn, RADEONSavePtr save); +diff --git a/src/radeon_atombios.c b/src/radeon_atombios.c +index 462c5ef..72fbe21 100644 +--- a/src/radeon_atombios.c ++++ b/src/radeon_atombios.c +@@ -1581,8 +1581,10 @@ rhdAtomParseI2CRecord(ScrnInfoPtr pScrn, atomBiosHandlePtr handle, + ATOM_I2C_RECORD *Record, int i) + { + RADEONInfoPtr info = RADEONPTR (pScrn); ++ uint8_t *temp = &Record->sucI2cId; + + info->BiosConnector[i].i2c_line_mux = Record->sucI2cId.bfI2C_LineMux; ++ info->BiosConnector[i].ucI2cId = *temp; + return RADEONLookupGPIOLineForDDC(pScrn, Record->sucI2cId.bfI2C_LineMux); + } + +diff --git a/src/radeon_output.c b/src/radeon_output.c +index a2733a7..107955d 100644 +--- a/src/radeon_output.c ++++ b/src/radeon_output.c +@@ -301,10 +301,13 @@ radeon_ddc_connected(xf86OutputPtr output) + RADEONMonitorType MonType = MT_NONE; + xf86MonPtr MonInfo = NULL; + RADEONOutputPrivatePtr radeon_output = output->driver_private; ++ int ret; + + if (radeon_output->custom_edid) { + MonInfo = xnfcalloc(sizeof(xf86Monitor), 1); + *MonInfo = *radeon_output->custom_mon; ++ } else if (radeon_output->ConnectorType == CONNECTOR_DISPLAY_PORT) { ++ MonInfo = xf86OutputGetEDID(output, radeon_output->dp_pI2CBus); + } else if (radeon_output->pI2CBus) { + if (info->get_hardcoded_edid_from_bios) + MonInfo = RADEONGetHardCodedEDIDFromBIOS(output); +@@ -364,7 +367,13 @@ radeon_ddc_connected(xf86OutputPtr output) + * XXX wrong. need to infer based on whether we got DDC from I2C + * or AUXCH. + */ +- MonType = MT_DFP; ++ ret = RADEON_DP_GetSinkType(output); ++ ++ if (ret == CONNECTOR_OBJECT_ID_DISPLAYPORT) { ++ MonType = MT_DP; ++ RADEON_DP_GetDPCD(output); ++ } else ++ MonType = MT_DFP; + break; + case CONNECTOR_HDMI_TYPE_B: + case CONNECTOR_DVI_I: +@@ -660,6 +669,9 @@ radeon_mode_fixup(xf86OutputPtr output, DisplayModePtr mode, + } + } + ++ if (radeon_output->ConnectorType == CONNECTOR_DISPLAY_PORT && radeon_output->MonType == MT_DP) { ++ radeon_dp_mode_fixup(output, mode, adjusted_mode); ++ } + return TRUE; + } + +@@ -2070,6 +2082,13 @@ void RADEONInitConnector(xf86OutputPtr output) + if (radeon_output->devices & (ATOM_DEVICE_DFP_SUPPORT)) + radeon_output->coherent_mode = TRUE; + ++ if (radeon_output->ConnectorType == CONNECTOR_DISPLAY_PORT) { ++ strcpy(radeon_output->dp_bus_name, output->name); ++ strcat(radeon_output->dp_bus_name, "-DP"); ++ RADEON_DP_I2CInit(pScrn, &radeon_output->dp_pI2CBus, radeon_output->dp_bus_name, output); ++ RADEON_DP_GetSinkType(output); ++ } ++ + if (radeon_output->ddc_i2c.valid) + RADEONI2CInit(pScrn, &radeon_output->pI2CBus, output->name, &radeon_output->ddc_i2c); + +@@ -2909,6 +2928,7 @@ Bool RADEONSetupConnectors(ScrnInfoPtr pScrn) + radeon_output->linkb = info->BiosConnector[i].linkb; + radeon_output->connector_id = info->BiosConnector[i].connector_object; + radeon_output->connector_object_id = info->BiosConnector[i].connector_object_id; ++ radeon_output->ucI2cId = info->BiosConnector[i].ucI2cId; + + /* Technically HDMI-B is a glorfied DL DVI so the bios is correct, + * but this can be confusing to users when it comes to output names, +diff --git a/src/radeon_probe.h b/src/radeon_probe.h +index 12e73ef..46bd1f5 100644 +--- a/src/radeon_probe.h ++++ b/src/radeon_probe.h +@@ -240,6 +240,7 @@ typedef struct { + Bool linkb; + uint16_t connector_object; + uint16_t connector_object_id; ++ uint8_t ucI2cId; + } RADEONBIOSConnector; + + typedef struct _RADEONOutputPrivateRec { +@@ -284,6 +285,17 @@ typedef struct _RADEONOutputPrivateRec { + int dig_block; + + int pixel_clock; ++ ++ /* DP - aux bus*/ ++ I2CBusPtr dp_pI2CBus; ++ uint8_t ucI2cId; ++ char dp_bus_name[20]; ++ uint32_t dp_i2c_addr; ++ Bool dp_i2c_running; ++ /* DP - general config */ ++ uint8_t dpcd[8]; ++ int dp_lane_count; ++ int dp_clock; + } RADEONOutputPrivateRec, *RADEONOutputPrivatePtr; + + struct avivo_pll_state { diff --git a/sources b/sources index 04616be..1a57ee3 100644 --- a/sources +++ b/sources @@ -1 +1 @@ -55a7141d73902a4d35837f4c59f4e6de xf86-video-ati-20090929.tar.xz +f66ac154c99ba836f38f4bea302e9d75 xf86-video-ati-20091201.tar.xz diff --git a/xorg-x11-drv-ati.spec b/xorg-x11-drv-ati.spec index de6aca5..7944d96 100644 --- a/xorg-x11-drv-ati.spec +++ b/xorg-x11-drv-ati.spec @@ -1,13 +1,13 @@ %define tarball xf86-video-ati %define moduledir %(pkg-config xorg-server --variable=moduledir ) %define driverdir %{moduledir}/drivers -%define gitdate 20090929 -%define gitversion 7968e1fb8 +%define gitdate 20091201 +%define gitversion 88a50a30d Summary: Xorg X11 ati video driver Name: xorg-x11-drv-ati Version: 6.13.0 -Release: 0.5.%{gitdate}git%{gitversion}%{?dist} +Release: 0.17.%{gitdate}git%{gitversion}%{?dist} URL: http://www.x.org License: MIT Group: User Interface/X Hardware Support @@ -18,24 +18,24 @@ Source0: %{tarball}-%{gitdate}.tar.xz # unlike the other drivers, radeon.xinf is generated Source1: mkxinf +Patch2: radeon-ums-displayport.patch Patch6: radeon-6.9.0-bgnr-enable.patch Patch10: radeon-6.12.2-lvds-default-modes.patch Patch13: fix-default-modes.patch -Patch14: r600-enable-mixed.patch ExcludeArch: s390 s390x BuildRequires: python BuildRequires: xorg-x11-server-sdk >= 1.4.99.1 BuildRequires: mesa-libGL-devel >= 6.4-4 -BuildRequires: libdrm-devel >= 2.4.0-0.21 +BuildRequires: libdrm-devel >= 2.4.16-0.1 BuildRequires: kernel-headers >= 2.6.27-0.308 BuildRequires: automake autoconf libtool pkgconfig BuildRequires: xorg-x11-util-macros >= 1.1.5 Requires: hwdata Requires: xorg-x11-server-Xorg >= 1.4.99.1 -Requires: libdrm >= 2.4.0-0.21 +Requires: libdrm >= 2.4.16-0.1 # new CS method needs newer kernel Requires: kernel >= 2.6.29.1-111.fc11 Obsoletes: xorg-x11-drv-avivo <= 0.0.2 @@ -45,10 +45,10 @@ X.Org X11 ati video driver. %prep %setup -q -n %{tarball}-%{gitdate} +%patch2 -p1 -b .dp %patch6 -p1 -b .bgnr %patch10 -p1 -b .lvds %patch13 -p1 -b .def -%patch14 -p1 -b .mix %build autoreconf -iv @@ -82,6 +82,43 @@ rm -rf $RPM_BUILD_ROOT %{_mandir}/man4/radeon.4* %changelog +* Wed Dec 02 2009 Dave Airlie 6.13.0-0.17.20091201git88a50a30d +- ums displayport + bump libdrm requires for new function needed + +* Tue Dec 01 2009 Dave Airlie 6.13.0-0.16.20091201git88a50a30d +- fixed up multi-op support for r600s + +* Fri Nov 27 2009 Dave Airlie 6.13.0-0.15.20091127gita8dbf7c23 +- upstream snapshot with fix for resize under shadowfb, merged multi-op + +* Thu Nov 26 2009 Dave Airlie 6.13.0-0.14.20091125git8b28534bc +- revert r600 multi-op for now seems to cause regression + +* Wed Nov 25 2009 Dave Airlie 6.13.0-0.13.20091125git8b28534bc +- rebase to upstream with r600 speed ups and r100 fixes integrated. + +* Fri Nov 20 2009 Dave Airlie 6.13.0-0.12.20091119git437113124 +- fix r100 Xv (partly inspired by 505152), rn50 small VRAM fixes. + +* Thu Nov 19 2009 Dave Airlie 6.13.0-0.11.20091119git437113124 +- upstream snapshot (#538561), amongst others + +* Fri Oct 09 2009 Dave Airlie 6.13.0-0.10.20091006git457646d73 +- Don't use scratch pixmaps for rotate + +* Fri Oct 09 2009 Dave Airlie 6.13.0-0.9.20091006git457646d73 +- reload cursors on mode switch/rotate + +* Wed Oct 07 2009 Dave Airlie 6.13.0-0.8.20091006git457646d73 +- fix rotate (#527000) + +* Tue Oct 06 2009 Dave Airlie 6.13.0-0.7.20091006git457646d73 +- resnapshot with VT switch fixes and mixed issue was in server which is fixed + +* Wed Sep 30 2009 Dave Airlie 6.13.0-0.6.20090929git7968e1fb8 +- mixed appears to break r600 for some reason need to investigate disable for + beta + * Tue Sep 29 2009 Dave Airlie 6.13.0-0.5.20090929git7968e1fb8 - rebase to latest upstream for vline fixes and zaphod fixes