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 
core_link_read_dpcd(struct dc_link * link,uint32_t address,uint8_t * data,uint32_t size)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 
core_link_write_dpcd(struct dc_link * link,uint32_t address,const uint8_t * data,uint32_t size)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 
dp_receiver_power_ctrl(struct dc_link * link,bool on)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 
dp_enable_link_phy(struct dc_link * link,enum signal_type signal,enum clock_source_id clock_source,const struct dc_link_settings * link_settings)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 
edp_receiver_ready_T9(struct dc_link * link)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 }
edp_receiver_ready_T7(struct dc_link * link)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 
dp_disable_link_phy(struct dc_link * link,enum signal_type signal)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 
dp_disable_link_phy_mst(struct dc_link * link,enum signal_type signal)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 
dp_set_hw_training_pattern(struct dc_link * link,enum hw_dp_training_pattern pattern)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 
dp_set_hw_lane_settings(struct dc_link * link,const struct link_training_settings * link_settings)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 
dp_get_panel_mode(struct dc_link * link)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 
dp_set_hw_test_pattern(struct dc_link * link,enum dp_test_pattern test_pattern,uint8_t * custom_pattern,uint32_t custom_pattern_size)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 
dp_retrain_link_dp_test(struct dc_link * link,struct dc_link_settings * link_setting,bool skip_video_pattern)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