1 /* Copyright 2015 Advanced Micro Devices, Inc. */
4 #include "dm_services.h"
6 #include "inc/core_types.h"
7 #include "include/ddc_service_types.h"
8 #include "include/i2caux_interface.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"
16 enum dc_status core_link_read_dpcd(
22 if (!dm_helpers_dp_read_dpcd(link->ctx,
25 return DC_ERROR_UNEXPECTED;
30 enum dc_status core_link_write_dpcd(
36 if (!dm_helpers_dp_write_dpcd(link->ctx,
39 return DC_ERROR_UNEXPECTED;
44 void dp_receiver_power_ctrl(struct dc_link *link, bool on)
48 state = on ? DP_POWER_STATE_D0 : DP_POWER_STATE_D3;
50 core_link_write_dpcd(link, DP_SET_POWER, &state,
54 void dp_enable_link_phy(
56 enum signal_type signal,
57 enum clock_source_id clock_source,
58 const struct dc_link_settings *link_settings)
60 struct link_encoder *link_enc = link->link_enc;
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;
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.
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);
88 if (dc_is_dp_sst_signal(signal)) {
89 link_enc->funcs->enable_dp_output(
94 link_enc->funcs->enable_dp_mst_output(
100 dp_receiver_power_ctrl(link, true);
103 bool edp_receiver_ready_T9(struct dc_link *link)
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)
112 /* start from eDP version 1.2, SINK_STAUS indicate the sink is ready.*/
115 result = core_link_read_dpcd(link, DP_SINK_STATUS, &sinkstatus, sizeof(sinkstatus));
120 udelay(100); //MAx T9
121 } while (++tries < 50);
124 bool edp_receiver_ready_T7(struct dc_link *link)
126 unsigned int tries = 0;
127 unsigned char sinkstatus = 0;
128 unsigned char edpRev = 0;
129 enum dc_status result = DC_OK;
131 result = core_link_read_dpcd(link, DP_EDP_DPCD_REV, &edpRev, sizeof(edpRev));
132 if (result == DC_OK && edpRev < DP_EDP_12)
134 /* start from eDP version 1.2, SINK_STAUS indicate the sink is ready.*/
137 result = core_link_read_dpcd(link, DP_SINK_STATUS, &sinkstatus, sizeof(sinkstatus));
142 udelay(25); //MAx T7 is 50ms
143 } while (++tries < 300);
147 void dp_disable_link_phy(struct dc_link *link, enum signal_type signal)
149 if (!link->wa_flags.dp_keep_receiver_powered)
150 dp_receiver_power_ctrl(link, false);
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);
156 link->link_enc->funcs->disable_output(link->link_enc, signal);
158 /* Clear current link setting.*/
159 memset(&link->cur_link_settings, 0,
160 sizeof(link->cur_link_settings));
163 void dp_disable_link_phy_mst(struct dc_link *link, enum signal_type signal)
165 /* MST disable link only when no stream use the link */
166 if (link->mst_stream_alloc_table.stream_count > 0)
169 dp_disable_link_phy(link, signal);
171 /* set the sink to SST mode after disabling the link */
172 dp_enable_mst_on_sink(link, false);
175 bool dp_set_hw_training_pattern(
176 struct dc_link *link,
177 enum hw_dp_training_pattern pattern)
179 enum dp_test_pattern test_pattern = DP_TEST_PATTERN_UNSUPPORTED;
182 case HW_DP_TRAINING_PATTERN_1:
183 test_pattern = DP_TEST_PATTERN_TRAINING_PATTERN1;
185 case HW_DP_TRAINING_PATTERN_2:
186 test_pattern = DP_TEST_PATTERN_TRAINING_PATTERN2;
188 case HW_DP_TRAINING_PATTERN_3:
189 test_pattern = DP_TEST_PATTERN_TRAINING_PATTERN3;
191 case HW_DP_TRAINING_PATTERN_4:
192 test_pattern = DP_TEST_PATTERN_TRAINING_PATTERN4;
198 dp_set_hw_test_pattern(link, test_pattern, NULL, 0);
203 void dp_set_hw_lane_settings(
204 struct dc_link *link,
205 const struct link_training_settings *link_settings)
207 struct link_encoder *encoder = link->link_enc;
209 /* call Encoder to set lane settings */
210 encoder->funcs->dp_set_lane_settings(encoder, link_settings);
213 enum dp_panel_mode dp_get_panel_mode(struct dc_link *link)
215 /* We need to explicitly check that connector
216 * is not DP. Some Travis_VGA get reported
217 * by video bios as DP.
219 if (link->connector_signal != SIGNAL_TYPE_DISPLAY_PORT) {
221 switch (link->dpcd_caps.branch_dev_id) {
222 case DP_BRANCH_DEVICE_ID_2:
224 link->dpcd_caps.branch_dev_name,
225 DP_VGA_LVDS_CONVERTER_ID_2,
228 branch_dev_name)) == 0) {
229 return DP_PANEL_MODE_SPECIAL;
232 case DP_BRANCH_DEVICE_ID_3:
233 if (strncmp(link->dpcd_caps.branch_dev_name,
234 DP_VGA_LVDS_CONVERTER_ID_3,
237 branch_dev_name)) == 0) {
238 return DP_PANEL_MODE_SPECIAL;
246 if (link->dpcd_caps.panel_mode_edp) {
247 return DP_PANEL_MODE_EDP;
250 return DP_PANEL_MODE_DEFAULT;
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)
259 struct encoder_set_dp_phy_pattern_param pattern_param = {0};
260 struct link_encoder *encoder = link->link_enc;
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);
267 encoder->funcs->dp_set_phy_pattern(encoder, &pattern_param);
270 void dp_retrain_link_dp_test(struct dc_link *link,
271 struct dc_link_settings *link_setting,
272 bool skip_video_pattern)
274 struct pipe_ctx *pipes =
275 &link->dc->current_state->res_ctx.pipe_ctx[0];
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) {
287 pipes[i].stream_res.stream_enc->funcs->dp_blank(
288 pipes[i].stream_res.stream_enc);
290 /* disable any test pattern that might be active */
291 dp_set_hw_test_pattern(link,
292 DP_TEST_PATTERN_VIDEO_MODE, NULL, 0);
294 dp_receiver_power_ctrl(link, false);
296 link->dc->hwss.disable_stream(&pipes[i], KEEP_ACQUIRED_RESOURCE);
298 link->link_enc->funcs->disable_output(
300 SIGNAL_TYPE_DISPLAY_PORT);
302 /* Clear current link setting. */
303 memset(&link->cur_link_settings, 0,
304 sizeof(link->cur_link_settings));
306 link->link_enc->funcs->enable_dp_output(
309 pipes[i].clock_source->id);
311 dp_receiver_power_ctrl(link, true);
313 perform_link_training_with_retries(
317 LINK_TRAINING_ATTEMPTS);
319 link->cur_link_settings = *link_setting;
321 link->dc->hwss.enable_stream(&pipes[i]);
323 link->dc->hwss.unblank_stream(&pipes[i],
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);
333 /* TODO: audio should be per stream rather than
335 pipes[i].stream_res.stream_enc->funcs->
337 pipes[i].stream_res.stream_enc, false);