1 /* Copyright 2015 Advanced Micro Devices, Inc. */ 2 3 4 #include "dm_services.h" 5 #include "dc.h" 6 #include "inc/core_types.h" 7 #include "include/ddc_service_types.h" 8 #include "include/i2caux_interface.h" 9 #include "link_hwss.h" 10 #include "hw_sequencer.h" 11 #include "dc_link_dp.h" 12 #include "dc_link_ddc.h" 13 #include "dm_helpers.h" 14 #include "dpcd_defs.h" 15 16 enum dc_status core_link_read_dpcd( 17 struct dc_link *link, 18 uint32_t address, 19 uint8_t *data, 20 uint32_t size) 21 { 22 if (!dm_helpers_dp_read_dpcd(link->ctx, 23 link, 24 address, data, size)) 25 return DC_ERROR_UNEXPECTED; 26 27 return DC_OK; 28 } 29 30 enum dc_status core_link_write_dpcd( 31 struct dc_link *link, 32 uint32_t address, 33 const uint8_t *data, 34 uint32_t size) 35 { 36 if (!dm_helpers_dp_write_dpcd(link->ctx, 37 link, 38 address, data, size)) 39 return DC_ERROR_UNEXPECTED; 40 41 return DC_OK; 42 } 43 44 void dp_receiver_power_ctrl(struct dc_link *link, bool on) 45 { 46 uint8_t state; 47 48 state = on ? DP_POWER_STATE_D0 : DP_POWER_STATE_D3; 49 50 core_link_write_dpcd(link, DP_SET_POWER, &state, 51 sizeof(state)); 52 } 53 54 void dp_enable_link_phy( 55 struct dc_link *link, 56 enum signal_type signal, 57 enum clock_source_id clock_source, 58 const struct dc_link_settings *link_settings) 59 { 60 struct link_encoder *link_enc = link->link_enc; 61 62 struct pipe_ctx *pipes = 63 link->dc->current_state->res_ctx.pipe_ctx; 64 struct clock_source *dp_cs = 65 link->dc->res_pool->dp_clock_source; 66 unsigned int i; 67 /* If the current pixel clock source is not DTO(happens after 68 * switching from HDMI passive dongle to DP on the same connector), 69 * switch the pixel clock source to DTO. 70 */ 71 for (i = 0; i < MAX_PIPES; i++) { 72 if (pipes[i].stream != NULL && 73 pipes[i].stream->sink != NULL && 74 pipes[i].stream->sink->link == link) { 75 if (pipes[i].clock_source != NULL && 76 pipes[i].clock_source->id != CLOCK_SOURCE_ID_DP_DTO) { 77 pipes[i].clock_source = dp_cs; 78 pipes[i].stream_res.pix_clk_params.requested_pix_clk = 79 pipes[i].stream->timing.pix_clk_khz; 80 pipes[i].clock_source->funcs->program_pix_clk( 81 pipes[i].clock_source, 82 &pipes[i].stream_res.pix_clk_params, 83 &pipes[i].pll_settings); 84 } 85 } 86 } 87 88 if (dc_is_dp_sst_signal(signal)) { 89 link_enc->funcs->enable_dp_output( 90 link_enc, 91 link_settings, 92 clock_source); 93 } else { 94 link_enc->funcs->enable_dp_mst_output( 95 link_enc, 96 link_settings, 97 clock_source); 98 } 99 100 dp_receiver_power_ctrl(link, true); 101 } 102 103 bool edp_receiver_ready_T9(struct dc_link *link) 104 { 105 unsigned int tries = 0; 106 unsigned char sinkstatus = 0; 107 unsigned char edpRev = 0; 108 enum dc_status result = DC_OK; 109 result = core_link_read_dpcd(link, DP_EDP_DPCD_REV, &edpRev, sizeof(edpRev)); 110 if (edpRev < DP_EDP_12) 111 return true; 112 /* start from eDP version 1.2, SINK_STAUS indicate the sink is ready.*/ 113 do { 114 sinkstatus = 1; 115 result = core_link_read_dpcd(link, DP_SINK_STATUS, &sinkstatus, sizeof(sinkstatus)); 116 if (sinkstatus == 0) 117 break; 118 if (result != DC_OK) 119 break; 120 udelay(100); //MAx T9 121 } while (++tries < 50); 122 return result; 123 } 124 bool edp_receiver_ready_T7(struct dc_link *link) 125 { 126 unsigned int tries = 0; 127 unsigned char sinkstatus = 0; 128 unsigned char edpRev = 0; 129 enum dc_status result = DC_OK; 130 131 result = core_link_read_dpcd(link, DP_EDP_DPCD_REV, &edpRev, sizeof(edpRev)); 132 if (result == DC_OK && edpRev < DP_EDP_12) 133 return true; 134 /* start from eDP version 1.2, SINK_STAUS indicate the sink is ready.*/ 135 do { 136 sinkstatus = 0; 137 result = core_link_read_dpcd(link, DP_SINK_STATUS, &sinkstatus, sizeof(sinkstatus)); 138 if (sinkstatus == 1) 139 break; 140 if (result != DC_OK) 141 break; 142 udelay(25); //MAx T7 is 50ms 143 } while (++tries < 300); 144 return result; 145 } 146 147 void dp_disable_link_phy(struct dc_link *link, enum signal_type signal) 148 { 149 if (!link->wa_flags.dp_keep_receiver_powered) 150 dp_receiver_power_ctrl(link, false); 151 152 if (signal == SIGNAL_TYPE_EDP) { 153 link->link_enc->funcs->disable_output(link->link_enc, signal); 154 link->dc->hwss.edp_power_control(link, false); 155 } else 156 link->link_enc->funcs->disable_output(link->link_enc, signal); 157 158 /* Clear current link setting.*/ 159 memset(&link->cur_link_settings, 0, 160 sizeof(link->cur_link_settings)); 161 } 162 163 void dp_disable_link_phy_mst(struct dc_link *link, enum signal_type signal) 164 { 165 /* MST disable link only when no stream use the link */ 166 if (link->mst_stream_alloc_table.stream_count > 0) 167 return; 168 169 dp_disable_link_phy(link, signal); 170 171 /* set the sink to SST mode after disabling the link */ 172 dp_enable_mst_on_sink(link, false); 173 } 174 175 bool dp_set_hw_training_pattern( 176 struct dc_link *link, 177 enum hw_dp_training_pattern pattern) 178 { 179 enum dp_test_pattern test_pattern = DP_TEST_PATTERN_UNSUPPORTED; 180 181 switch (pattern) { 182 case HW_DP_TRAINING_PATTERN_1: 183 test_pattern = DP_TEST_PATTERN_TRAINING_PATTERN1; 184 break; 185 case HW_DP_TRAINING_PATTERN_2: 186 test_pattern = DP_TEST_PATTERN_TRAINING_PATTERN2; 187 break; 188 case HW_DP_TRAINING_PATTERN_3: 189 test_pattern = DP_TEST_PATTERN_TRAINING_PATTERN3; 190 break; 191 case HW_DP_TRAINING_PATTERN_4: 192 test_pattern = DP_TEST_PATTERN_TRAINING_PATTERN4; 193 break; 194 default: 195 break; 196 } 197 198 dp_set_hw_test_pattern(link, test_pattern, NULL, 0); 199 200 return true; 201 } 202 203 void dp_set_hw_lane_settings( 204 struct dc_link *link, 205 const struct link_training_settings *link_settings) 206 { 207 struct link_encoder *encoder = link->link_enc; 208 209 /* call Encoder to set lane settings */ 210 encoder->funcs->dp_set_lane_settings(encoder, link_settings); 211 } 212 213 enum dp_panel_mode dp_get_panel_mode(struct dc_link *link) 214 { 215 /* We need to explicitly check that connector 216 * is not DP. Some Travis_VGA get reported 217 * by video bios as DP. 218 */ 219 if (link->connector_signal != SIGNAL_TYPE_DISPLAY_PORT) { 220 221 switch (link->dpcd_caps.branch_dev_id) { 222 case DP_BRANCH_DEVICE_ID_2: 223 if (strncmp( 224 link->dpcd_caps.branch_dev_name, 225 DP_VGA_LVDS_CONVERTER_ID_2, 226 sizeof( 227 link->dpcd_caps. 228 branch_dev_name)) == 0) { 229 return DP_PANEL_MODE_SPECIAL; 230 } 231 break; 232 case DP_BRANCH_DEVICE_ID_3: 233 if (strncmp(link->dpcd_caps.branch_dev_name, 234 DP_VGA_LVDS_CONVERTER_ID_3, 235 sizeof( 236 link->dpcd_caps. 237 branch_dev_name)) == 0) { 238 return DP_PANEL_MODE_SPECIAL; 239 } 240 break; 241 default: 242 break; 243 } 244 } 245 246 if (link->dpcd_caps.panel_mode_edp) { 247 return DP_PANEL_MODE_EDP; 248 } 249 250 return DP_PANEL_MODE_DEFAULT; 251 } 252 253 void dp_set_hw_test_pattern( 254 struct dc_link *link, 255 enum dp_test_pattern test_pattern, 256 uint8_t *custom_pattern, 257 uint32_t custom_pattern_size) 258 { 259 struct encoder_set_dp_phy_pattern_param pattern_param = {0}; 260 struct link_encoder *encoder = link->link_enc; 261 262 pattern_param.dp_phy_pattern = test_pattern; 263 pattern_param.custom_pattern = custom_pattern; 264 pattern_param.custom_pattern_size = custom_pattern_size; 265 pattern_param.dp_panel_mode = dp_get_panel_mode(link); 266 267 encoder->funcs->dp_set_phy_pattern(encoder, &pattern_param); 268 } 269 270 void dp_retrain_link_dp_test(struct dc_link *link, 271 struct dc_link_settings *link_setting, 272 bool skip_video_pattern) 273 { 274 struct pipe_ctx *pipes = 275 &link->dc->current_state->res_ctx.pipe_ctx[0]; 276 unsigned int i; 277 278 for (i = 0; i < MAX_PIPES; i++) { 279 if (pipes[i].stream != NULL && 280 !pipes[i].top_pipe && 281 pipes[i].stream->sink != NULL && 282 pipes[i].stream->sink->link != NULL && 283 pipes[i].stream_res.stream_enc != NULL && 284 pipes[i].stream->sink->link == link) { 285 udelay(100); 286 287 pipes[i].stream_res.stream_enc->funcs->dp_blank( 288 pipes[i].stream_res.stream_enc); 289 290 /* disable any test pattern that might be active */ 291 dp_set_hw_test_pattern(link, 292 DP_TEST_PATTERN_VIDEO_MODE, NULL, 0); 293 294 dp_receiver_power_ctrl(link, false); 295 296 link->dc->hwss.disable_stream(&pipes[i], KEEP_ACQUIRED_RESOURCE); 297 298 link->link_enc->funcs->disable_output( 299 link->link_enc, 300 SIGNAL_TYPE_DISPLAY_PORT); 301 302 /* Clear current link setting. */ 303 memset(&link->cur_link_settings, 0, 304 sizeof(link->cur_link_settings)); 305 306 link->link_enc->funcs->enable_dp_output( 307 link->link_enc, 308 link_setting, 309 pipes[i].clock_source->id); 310 311 dp_receiver_power_ctrl(link, true); 312 313 perform_link_training_with_retries( 314 link, 315 link_setting, 316 skip_video_pattern, 317 LINK_TRAINING_ATTEMPTS); 318 319 link->cur_link_settings = *link_setting; 320 321 link->dc->hwss.enable_stream(&pipes[i]); 322 323 link->dc->hwss.unblank_stream(&pipes[i], 324 link_setting); 325 326 if (pipes[i].stream_res.audio) { 327 /* notify audio driver for 328 * audio modes of monitor */ 329 pipes[i].stream_res.audio->funcs->az_enable( 330 pipes[i].stream_res.audio); 331 332 /* un-mute audio */ 333 /* TODO: audio should be per stream rather than 334 * per link */ 335 pipes[i].stream_res.stream_enc->funcs-> 336 audio_mute_control( 337 pipes[i].stream_res.stream_enc, false); 338 } 339 } 340 } 341 } 342