1 /*
2  * Copyright 2022 Advanced Micro Devices, Inc.
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a
5  * copy of this software and associated documentation files (the "Software"),
6  * to deal in the Software without restriction, including without limitation
7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8  * and/or sell copies of the Software, and to permit persons to whom the
9  * Software is furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice shall be included in
12  * all copies or substantial portions of the Software.
13  *
14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
17  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
18  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20  * OTHER DEALINGS IN THE SOFTWARE.
21  *
22  * Authors: AMD
23  *
24  */
25 
26 /* FILE POLICY AND INTENDED USAGE:
27  * This file implements DP HPD short pulse handling sequence according to DP
28  * specifications
29  *
30  */
31 
32 #include "link_dp_irq_handler.h"
33 #include "link_dpcd.h"
34 #include "link_dp_training.h"
35 #include "link_dp_capability.h"
36 #include "link_edp_panel_control.h"
37 #include "link/accessories/link_dp_trace.h"
38 #include "link/link_dpms.h"
39 #include "dm_helpers.h"
40 
41 #define DC_LOGGER \
42 	link->ctx->logger
43 #define DC_LOGGER_INIT(logger)
44 
dp_parse_link_loss_status(struct dc_link * link,union hpd_irq_data * hpd_irq_dpcd_data)45 bool dp_parse_link_loss_status(
46 	struct dc_link *link,
47 	union hpd_irq_data *hpd_irq_dpcd_data)
48 {
49 	uint8_t irq_reg_rx_power_state = 0;
50 	enum dc_status dpcd_result = DC_ERROR_UNEXPECTED;
51 	union lane_status lane_status;
52 	uint32_t lane;
53 	bool sink_status_changed;
54 	bool return_code;
55 
56 	sink_status_changed = false;
57 	return_code = false;
58 
59 	if (link->cur_link_settings.lane_count == 0)
60 		return return_code;
61 
62 	/*1. Check that Link Status changed, before re-training.*/
63 
64 	/*parse lane status*/
65 	for (lane = 0; lane < link->cur_link_settings.lane_count; lane++) {
66 		/* check status of lanes 0,1
67 		 * changed DpcdAddress_Lane01Status (0x202)
68 		 */
69 		lane_status.raw = dp_get_nibble_at_index(
70 			&hpd_irq_dpcd_data->bytes.lane01_status.raw,
71 			lane);
72 
73 		if (!lane_status.bits.CHANNEL_EQ_DONE_0 ||
74 			!lane_status.bits.CR_DONE_0 ||
75 			!lane_status.bits.SYMBOL_LOCKED_0) {
76 			/* if one of the channel equalization, clock
77 			 * recovery or symbol lock is dropped
78 			 * consider it as (link has been
79 			 * dropped) dp sink status has changed
80 			 */
81 			sink_status_changed = true;
82 			break;
83 		}
84 	}
85 
86 	/* Check interlane align.*/
87 	if (link_dp_get_encoding_format(&link->cur_link_settings) == DP_128b_132b_ENCODING &&
88 			(!hpd_irq_dpcd_data->bytes.lane_status_updated.bits.EQ_INTERLANE_ALIGN_DONE_128b_132b ||
89 			 !hpd_irq_dpcd_data->bytes.lane_status_updated.bits.CDS_INTERLANE_ALIGN_DONE_128b_132b)) {
90 		sink_status_changed = true;
91 	} else if (!hpd_irq_dpcd_data->bytes.lane_status_updated.bits.INTERLANE_ALIGN_DONE) {
92 		sink_status_changed = true;
93 	}
94 
95 	if (sink_status_changed) {
96 
97 		DC_LOG_HW_HPD_IRQ("%s: Link Status changed.\n", __func__);
98 
99 		return_code = true;
100 
101 		/*2. Check that we can handle interrupt: Not in FS DOS,
102 		 *  Not in "Display Timeout" state, Link is trained.
103 		 */
104 		dpcd_result = core_link_read_dpcd(link,
105 			DP_SET_POWER,
106 			&irq_reg_rx_power_state,
107 			sizeof(irq_reg_rx_power_state));
108 
109 		if (dpcd_result != DC_OK) {
110 			DC_LOG_HW_HPD_IRQ("%s: DPCD read failed to obtain power state.\n",
111 				__func__);
112 		} else {
113 			if (irq_reg_rx_power_state != DP_SET_POWER_D0)
114 				return_code = false;
115 		}
116 	}
117 
118 	return return_code;
119 }
120 
handle_hpd_irq_psr_sink(struct dc_link * link)121 static bool handle_hpd_irq_psr_sink(struct dc_link *link)
122 {
123 	union dpcd_psr_configuration psr_configuration = {0};
124 
125 	if (!link->psr_settings.psr_feature_enabled)
126 		return false;
127 
128 	dm_helpers_dp_read_dpcd(
129 		link->ctx,
130 		link,
131 		368,/*DpcdAddress_PSR_Enable_Cfg*/
132 		&psr_configuration.raw,
133 		sizeof(psr_configuration.raw));
134 
135 	if (psr_configuration.bits.ENABLE) {
136 		unsigned char dpcdbuf[3] = {0};
137 		union psr_error_status psr_error_status;
138 		union psr_sink_psr_status psr_sink_psr_status;
139 
140 		dm_helpers_dp_read_dpcd(
141 			link->ctx,
142 			link,
143 			0x2006, /*DpcdAddress_PSR_Error_Status*/
144 			(unsigned char *) dpcdbuf,
145 			sizeof(dpcdbuf));
146 
147 		/*DPCD 2006h   ERROR STATUS*/
148 		psr_error_status.raw = dpcdbuf[0];
149 		/*DPCD 2008h   SINK PANEL SELF REFRESH STATUS*/
150 		psr_sink_psr_status.raw = dpcdbuf[2];
151 
152 		if (psr_error_status.bits.LINK_CRC_ERROR ||
153 				psr_error_status.bits.RFB_STORAGE_ERROR ||
154 				psr_error_status.bits.VSC_SDP_ERROR) {
155 			bool allow_active;
156 
157 			/* Acknowledge and clear error bits */
158 			dm_helpers_dp_write_dpcd(
159 				link->ctx,
160 				link,
161 				8198,/*DpcdAddress_PSR_Error_Status*/
162 				&psr_error_status.raw,
163 				sizeof(psr_error_status.raw));
164 
165 			/* PSR error, disable and re-enable PSR */
166 			if (link->psr_settings.psr_allow_active) {
167 				allow_active = false;
168 				edp_set_psr_allow_active(link, &allow_active, true, false, NULL);
169 				allow_active = true;
170 				edp_set_psr_allow_active(link, &allow_active, true, false, NULL);
171 			}
172 
173 			return true;
174 		} else if (psr_sink_psr_status.bits.SINK_SELF_REFRESH_STATUS ==
175 				PSR_SINK_STATE_ACTIVE_DISPLAY_FROM_SINK_RFB){
176 			/* No error is detect, PSR is active.
177 			 * We should return with IRQ_HPD handled without
178 			 * checking for loss of sync since PSR would have
179 			 * powered down main link.
180 			 */
181 			return true;
182 		}
183 	}
184 	return false;
185 }
186 
handle_hpd_irq_replay_sink(struct dc_link * link)187 static void handle_hpd_irq_replay_sink(struct dc_link *link)
188 {
189 	union dpcd_replay_configuration replay_configuration = {0};
190 	/*AMD Replay version reuse DP_PSR_ERROR_STATUS for REPLAY_ERROR status.*/
191 	union psr_error_status replay_error_status = {0};
192 	bool ret = false;
193 	int retries = 0;
194 
195 	if (!link->replay_settings.replay_feature_enabled)
196 		return;
197 
198 	while (retries < 10) {
199 		ret = dm_helpers_dp_read_dpcd(
200 			link->ctx,
201 			link,
202 			DP_SINK_PR_REPLAY_STATUS,
203 			&replay_configuration.raw,
204 			sizeof(replay_configuration.raw));
205 
206 		if (ret)
207 			break;
208 
209 		retries++;
210 	}
211 
212 	if (!ret)
213 		DC_LOG_WARNING("[%s][%d] DPCD read addr.0x%x failed with %d retries\n",
214 					__func__, __LINE__,
215 					DP_SINK_PR_REPLAY_STATUS, retries);
216 
217 	dm_helpers_dp_read_dpcd(
218 		link->ctx,
219 		link,
220 		DP_PSR_ERROR_STATUS,
221 		&replay_error_status.raw,
222 		sizeof(replay_error_status.raw));
223 
224 	link->replay_settings.config.replay_error_status.bits.LINK_CRC_ERROR =
225 		replay_error_status.bits.LINK_CRC_ERROR;
226 	link->replay_settings.config.replay_error_status.bits.DESYNC_ERROR =
227 		replay_configuration.bits.DESYNC_ERROR_STATUS;
228 	link->replay_settings.config.replay_error_status.bits.STATE_TRANSITION_ERROR =
229 		replay_configuration.bits.STATE_TRANSITION_ERROR_STATUS;
230 
231 	if (link->replay_settings.config.replay_error_status.bits.LINK_CRC_ERROR ||
232 		link->replay_settings.config.replay_error_status.bits.DESYNC_ERROR ||
233 		link->replay_settings.config.replay_error_status.bits.STATE_TRANSITION_ERROR) {
234 		bool allow_active;
235 
236 		if (link->replay_settings.config.replay_error_status.bits.DESYNC_ERROR)
237 			link->replay_settings.config.received_desync_error_hpd = 1;
238 
239 		if (link->replay_settings.config.force_disable_desync_error_check)
240 			return;
241 
242 		/* Acknowledge and clear configuration bits */
243 		dm_helpers_dp_write_dpcd(
244 			link->ctx,
245 			link,
246 			DP_SINK_PR_REPLAY_STATUS,
247 			&replay_configuration.raw,
248 			sizeof(replay_configuration.raw));
249 
250 		/* Acknowledge and clear error bits */
251 		dm_helpers_dp_write_dpcd(
252 			link->ctx,
253 			link,
254 			DP_PSR_ERROR_STATUS,/*DpcdAddress_REPLAY_Error_Status*/
255 			&replay_error_status.raw,
256 			sizeof(replay_error_status.raw));
257 
258 		/* Replay error, disable and re-enable Replay */
259 		if (link->replay_settings.replay_allow_active) {
260 			allow_active = false;
261 			edp_set_replay_allow_active(link, &allow_active, true, false, NULL);
262 			allow_active = true;
263 			edp_set_replay_allow_active(link, &allow_active, true, false, NULL);
264 		}
265 	}
266 }
267 
dp_handle_link_loss(struct dc_link * link)268 void dp_handle_link_loss(struct dc_link *link)
269 {
270 	struct pipe_ctx *pipes[MAX_PIPES];
271 	struct dc_state *state = link->dc->current_state;
272 	uint8_t count;
273 	int i;
274 
275 	link_get_master_pipes_with_dpms_on(link, state, &count, pipes);
276 
277 	for (i = 0; i < count; i++)
278 		link_set_dpms_off(pipes[i]);
279 
280 	for (i = count - 1; i >= 0; i--) {
281 		// Always use max settings here for DP 1.4a LL Compliance CTS
282 		if (link->skip_fallback_on_link_loss) {
283 			pipes[i]->link_config.dp_link_settings.lane_count =
284 					link->verified_link_cap.lane_count;
285 			pipes[i]->link_config.dp_link_settings.link_rate =
286 					link->verified_link_cap.link_rate;
287 			pipes[i]->link_config.dp_link_settings.link_spread =
288 					link->verified_link_cap.link_spread;
289 		}
290 		link_set_dpms_on(link->dc->current_state, pipes[i]);
291 	}
292 }
293 
read_dpcd204h_on_irq_hpd(struct dc_link * link,union hpd_irq_data * irq_data)294 static void read_dpcd204h_on_irq_hpd(struct dc_link *link, union hpd_irq_data *irq_data)
295 {
296 	enum dc_status retval;
297 	union lane_align_status_updated dpcd_lane_status_updated = {0};
298 
299 	retval = core_link_read_dpcd(
300 			link,
301 			DP_LANE_ALIGN_STATUS_UPDATED,
302 			&dpcd_lane_status_updated.raw,
303 			sizeof(union lane_align_status_updated));
304 
305 	if (retval == DC_OK) {
306 		irq_data->bytes.lane_status_updated.bits.EQ_INTERLANE_ALIGN_DONE_128b_132b =
307 				dpcd_lane_status_updated.bits.EQ_INTERLANE_ALIGN_DONE_128b_132b;
308 		irq_data->bytes.lane_status_updated.bits.CDS_INTERLANE_ALIGN_DONE_128b_132b =
309 				dpcd_lane_status_updated.bits.CDS_INTERLANE_ALIGN_DONE_128b_132b;
310 	}
311 }
312 
dp_read_hpd_rx_irq_data(struct dc_link * link,union hpd_irq_data * irq_data)313 enum dc_status dp_read_hpd_rx_irq_data(
314 	struct dc_link *link,
315 	union hpd_irq_data *irq_data)
316 {
317 	static enum dc_status retval;
318 
319 	/* The HW reads 16 bytes from 200h on HPD,
320 	 * but if we get an AUX_DEFER, the HW cannot retry
321 	 * and this causes the CTS tests 4.3.2.1 - 3.2.4 to
322 	 * fail, so we now explicitly read 6 bytes which is
323 	 * the req from the above mentioned test cases.
324 	 *
325 	 * For DP 1.4 we need to read those from 2002h range.
326 	 */
327 	if (link->dpcd_caps.dpcd_rev.raw < DPCD_REV_14)
328 		retval = core_link_read_dpcd(
329 			link,
330 			DP_SINK_COUNT,
331 			irq_data->raw,
332 			sizeof(union hpd_irq_data));
333 	else {
334 		/* Read 14 bytes in a single read and then copy only the required fields.
335 		 * This is more efficient than doing it in two separate AUX reads. */
336 
337 		uint8_t tmp[DP_SINK_STATUS_ESI - DP_SINK_COUNT_ESI + 1] = {0};
338 
339 		retval = core_link_read_dpcd(
340 			link,
341 			DP_SINK_COUNT_ESI,
342 			tmp,
343 			sizeof(tmp));
344 
345 		if (retval != DC_OK)
346 			return retval;
347 
348 		irq_data->bytes.sink_cnt.raw = tmp[DP_SINK_COUNT_ESI - DP_SINK_COUNT_ESI];
349 		irq_data->bytes.device_service_irq.raw = tmp[DP_DEVICE_SERVICE_IRQ_VECTOR_ESI0 - DP_SINK_COUNT_ESI];
350 		irq_data->bytes.lane01_status.raw = tmp[DP_LANE0_1_STATUS_ESI - DP_SINK_COUNT_ESI];
351 		irq_data->bytes.lane23_status.raw = tmp[DP_LANE2_3_STATUS_ESI - DP_SINK_COUNT_ESI];
352 		irq_data->bytes.lane_status_updated.raw = tmp[DP_LANE_ALIGN_STATUS_UPDATED_ESI - DP_SINK_COUNT_ESI];
353 		irq_data->bytes.sink_status.raw = tmp[DP_SINK_STATUS_ESI - DP_SINK_COUNT_ESI];
354 
355 		/*
356 		 * This display doesn't have correct values in DPCD200Eh.
357 		 * Read and check DPCD204h instead.
358 		 */
359 		if (link->wa_flags.read_dpcd204h_on_irq_hpd)
360 			read_dpcd204h_on_irq_hpd(link, irq_data);
361 	}
362 
363 	return retval;
364 }
365 
366 /*************************Short Pulse IRQ***************************/
dp_should_allow_hpd_rx_irq(const struct dc_link * link)367 bool dp_should_allow_hpd_rx_irq(const struct dc_link *link)
368 {
369 	/*
370 	 * Don't handle RX IRQ unless one of following is met:
371 	 * 1) The link is established (cur_link_settings != unknown)
372 	 * 2) We know we're dealing with a branch device, SST or MST
373 	 */
374 
375 	if ((link->cur_link_settings.lane_count != LANE_COUNT_UNKNOWN) ||
376 		is_dp_branch_device(link))
377 		return true;
378 
379 	return false;
380 }
381 
dp_handle_hpd_rx_irq(struct dc_link * link,union hpd_irq_data * out_hpd_irq_dpcd_data,bool * out_link_loss,bool defer_handling,bool * has_left_work)382 bool dp_handle_hpd_rx_irq(struct dc_link *link,
383 		union hpd_irq_data *out_hpd_irq_dpcd_data, bool *out_link_loss,
384 		bool defer_handling, bool *has_left_work)
385 {
386 	union hpd_irq_data hpd_irq_dpcd_data = {0};
387 	union device_service_irq device_service_clear = {0};
388 	enum dc_status result;
389 	bool status = false;
390 
391 	if (out_link_loss)
392 		*out_link_loss = false;
393 
394 	if (has_left_work)
395 		*has_left_work = false;
396 	/* For use cases related to down stream connection status change,
397 	 * PSR and device auto test, refer to function handle_sst_hpd_irq
398 	 * in DAL2.1*/
399 
400 	DC_LOG_HW_HPD_IRQ("%s: Got short pulse HPD on link %d\n",
401 		__func__, link->link_index);
402 
403 
404 	 /* All the "handle_hpd_irq_xxx()" methods
405 		 * should be called only after
406 		 * dal_dpsst_ls_read_hpd_irq_data
407 		 * Order of calls is important too
408 		 */
409 	result = dp_read_hpd_rx_irq_data(link, &hpd_irq_dpcd_data);
410 	if (out_hpd_irq_dpcd_data)
411 		*out_hpd_irq_dpcd_data = hpd_irq_dpcd_data;
412 
413 	if (result != DC_OK) {
414 		DC_LOG_HW_HPD_IRQ("%s: DPCD read failed to obtain irq data\n",
415 			__func__);
416 		return false;
417 	}
418 
419 	if (hpd_irq_dpcd_data.bytes.device_service_irq.bits.AUTOMATED_TEST) {
420 		// Workaround for DP 1.4a LL Compliance CTS as USB4 has to share encoders unlike DP and USBC
421 		if (link->ep_type == DISPLAY_ENDPOINT_USB4_DPIA)
422 			link->skip_fallback_on_link_loss = true;
423 
424 		device_service_clear.bits.AUTOMATED_TEST = 1;
425 		core_link_write_dpcd(
426 			link,
427 			DP_DEVICE_SERVICE_IRQ_VECTOR,
428 			&device_service_clear.raw,
429 			sizeof(device_service_clear.raw));
430 		device_service_clear.raw = 0;
431 		if (defer_handling && has_left_work)
432 			*has_left_work = true;
433 		else
434 			dc_link_dp_handle_automated_test(link);
435 		return false;
436 	}
437 
438 	if (!dp_should_allow_hpd_rx_irq(link)) {
439 		DC_LOG_HW_HPD_IRQ("%s: skipping HPD handling on %d\n",
440 			__func__, link->link_index);
441 		return false;
442 	}
443 
444 	if (handle_hpd_irq_psr_sink(link))
445 		/* PSR-related error was detected and handled */
446 		return true;
447 
448 	handle_hpd_irq_replay_sink(link);
449 
450 	/* If PSR-related error handled, Main link may be off,
451 	 * so do not handle as a normal sink status change interrupt.
452 	 */
453 
454 	if (hpd_irq_dpcd_data.bytes.device_service_irq.bits.UP_REQ_MSG_RDY) {
455 		if (defer_handling && has_left_work)
456 			*has_left_work = true;
457 		return true;
458 	}
459 
460 	/* check if we have MST msg and return since we poll for it */
461 	if (hpd_irq_dpcd_data.bytes.device_service_irq.bits.DOWN_REP_MSG_RDY) {
462 		if (defer_handling && has_left_work)
463 			*has_left_work = true;
464 		return false;
465 	}
466 
467 	/* For now we only handle 'Downstream port status' case.
468 	 * If we got sink count changed it means
469 	 * Downstream port status changed,
470 	 * then DM should call DC to do the detection.
471 	 * NOTE: Do not handle link loss on eDP since it is internal link
472 	 */
473 	if ((link->connector_signal != SIGNAL_TYPE_EDP) &&
474 			dp_parse_link_loss_status(
475 					link,
476 					&hpd_irq_dpcd_data)) {
477 		/* Connectivity log: link loss */
478 		CONN_DATA_LINK_LOSS(link,
479 					hpd_irq_dpcd_data.raw,
480 					sizeof(hpd_irq_dpcd_data),
481 					"Status: ");
482 
483 		if (defer_handling && has_left_work)
484 			*has_left_work = true;
485 		else
486 			dp_handle_link_loss(link);
487 
488 		status = false;
489 		if (out_link_loss)
490 			*out_link_loss = true;
491 
492 		dp_trace_link_loss_increment(link);
493 	}
494 
495 	if (link->type == dc_connection_sst_branch &&
496 		hpd_irq_dpcd_data.bytes.sink_cnt.bits.SINK_COUNT
497 			!= link->dpcd_sink_count)
498 		status = true;
499 
500 	/* reasons for HPD RX:
501 	 * 1. Link Loss - ie Re-train the Link
502 	 * 2. MST sideband message
503 	 * 3. Automated Test - ie. Internal Commit
504 	 * 4. CP (copy protection) - (not interesting for DM???)
505 	 * 5. DRR
506 	 * 6. Downstream Port status changed
507 	 * -ie. Detect - this the only one
508 	 * which is interesting for DM because
509 	 * it must call dc_link_detect.
510 	 */
511 	return status;
512 }
513