brintos

brintos / linux-shallow public Read only

0
0
Text · 31.2 KiB · d896761 Raw
1233 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Copyright (c) 2012-2020, The Linux Foundation. All rights reserved.4 */5 6#define pr_fmt(fmt)	"[drm-dp] %s: " fmt, __func__7 8#include <drm/drm_print.h>9 10#include "dp_reg.h"11#include "dp_link.h"12#include "dp_panel.h"13 14#define DP_TEST_REQUEST_MASK		0x7F15 16enum audio_sample_rate {17	AUDIO_SAMPLE_RATE_32_KHZ	= 0x00,18	AUDIO_SAMPLE_RATE_44_1_KHZ	= 0x01,19	AUDIO_SAMPLE_RATE_48_KHZ	= 0x02,20	AUDIO_SAMPLE_RATE_88_2_KHZ	= 0x03,21	AUDIO_SAMPLE_RATE_96_KHZ	= 0x04,22	AUDIO_SAMPLE_RATE_176_4_KHZ	= 0x05,23	AUDIO_SAMPLE_RATE_192_KHZ	= 0x06,24};25 26enum audio_pattern_type {27	AUDIO_TEST_PATTERN_OPERATOR_DEFINED	= 0x00,28	AUDIO_TEST_PATTERN_SAWTOOTH		= 0x01,29};30 31struct dp_link_request {32	u32 test_requested;33	u32 test_link_rate;34	u32 test_lane_count;35};36 37struct dp_link_private {38	u32 prev_sink_count;39	struct drm_device *drm_dev;40	struct drm_dp_aux *aux;41	struct dp_link dp_link;42 43	struct dp_link_request request;44	struct mutex psm_mutex;45	u8 link_status[DP_LINK_STATUS_SIZE];46};47 48static int dp_aux_link_power_up(struct drm_dp_aux *aux,49					struct dp_link_info *link)50{51	u8 value;52	ssize_t len;53	int i;54 55	if (link->revision < 0x11)56		return 0;57 58	len = drm_dp_dpcd_readb(aux, DP_SET_POWER, &value);59	if (len < 0)60		return len;61 62	value &= ~DP_SET_POWER_MASK;63	value |= DP_SET_POWER_D0;64 65	/* retry for 1ms to give the sink time to wake up */66	for (i = 0; i < 3; i++) {67		len = drm_dp_dpcd_writeb(aux, DP_SET_POWER, value);68		usleep_range(1000, 2000);69		if (len == 1)70			break;71	}72 73	return 0;74}75 76static int dp_aux_link_power_down(struct drm_dp_aux *aux,77					struct dp_link_info *link)78{79	u8 value;80	int err;81 82	if (link->revision < 0x11)83		return 0;84 85	err = drm_dp_dpcd_readb(aux, DP_SET_POWER, &value);86	if (err < 0)87		return err;88 89	value &= ~DP_SET_POWER_MASK;90	value |= DP_SET_POWER_D3;91 92	err = drm_dp_dpcd_writeb(aux, DP_SET_POWER, value);93	if (err < 0)94		return err;95 96	return 0;97}98 99static int dp_link_get_period(struct dp_link_private *link, int const addr)100{101	int ret = 0;102	u8 data;103	u32 const max_audio_period = 0xA;104 105	/* TEST_AUDIO_PERIOD_CH_XX */106	if (drm_dp_dpcd_readb(link->aux, addr, &data) < 0) {107		DRM_ERROR("failed to read test_audio_period (0x%x)\n", addr);108		ret = -EINVAL;109		goto exit;110	}111 112	/* Period - Bits 3:0 */113	data = data & 0xF;114	if ((int)data > max_audio_period) {115		DRM_ERROR("invalid test_audio_period_ch_1 = 0x%x\n", data);116		ret = -EINVAL;117		goto exit;118	}119 120	ret = data;121exit:122	return ret;123}124 125static int dp_link_parse_audio_channel_period(struct dp_link_private *link)126{127	int ret = 0;128	struct dp_link_test_audio *req = &link->dp_link.test_audio;129 130	ret = dp_link_get_period(link, DP_TEST_AUDIO_PERIOD_CH1);131	if (ret == -EINVAL)132		goto exit;133 134	req->test_audio_period_ch_1 = ret;135	drm_dbg_dp(link->drm_dev, "test_audio_period_ch_1 = 0x%x\n", ret);136 137	ret = dp_link_get_period(link, DP_TEST_AUDIO_PERIOD_CH2);138	if (ret == -EINVAL)139		goto exit;140 141	req->test_audio_period_ch_2 = ret;142	drm_dbg_dp(link->drm_dev, "test_audio_period_ch_2 = 0x%x\n", ret);143 144	/* TEST_AUDIO_PERIOD_CH_3 (Byte 0x275) */145	ret = dp_link_get_period(link, DP_TEST_AUDIO_PERIOD_CH3);146	if (ret == -EINVAL)147		goto exit;148 149	req->test_audio_period_ch_3 = ret;150	drm_dbg_dp(link->drm_dev, "test_audio_period_ch_3 = 0x%x\n", ret);151 152	ret = dp_link_get_period(link, DP_TEST_AUDIO_PERIOD_CH4);153	if (ret == -EINVAL)154		goto exit;155 156	req->test_audio_period_ch_4 = ret;157	drm_dbg_dp(link->drm_dev, "test_audio_period_ch_4 = 0x%x\n", ret);158 159	ret = dp_link_get_period(link, DP_TEST_AUDIO_PERIOD_CH5);160	if (ret == -EINVAL)161		goto exit;162 163	req->test_audio_period_ch_5 = ret;164	drm_dbg_dp(link->drm_dev, "test_audio_period_ch_5 = 0x%x\n", ret);165 166	ret = dp_link_get_period(link, DP_TEST_AUDIO_PERIOD_CH6);167	if (ret == -EINVAL)168		goto exit;169 170	req->test_audio_period_ch_6 = ret;171	drm_dbg_dp(link->drm_dev, "test_audio_period_ch_6 = 0x%x\n", ret);172 173	ret = dp_link_get_period(link, DP_TEST_AUDIO_PERIOD_CH7);174	if (ret == -EINVAL)175		goto exit;176 177	req->test_audio_period_ch_7 = ret;178	drm_dbg_dp(link->drm_dev, "test_audio_period_ch_7 = 0x%x\n", ret);179 180	ret = dp_link_get_period(link, DP_TEST_AUDIO_PERIOD_CH8);181	if (ret == -EINVAL)182		goto exit;183 184	req->test_audio_period_ch_8 = ret;185	drm_dbg_dp(link->drm_dev, "test_audio_period_ch_8 = 0x%x\n", ret);186exit:187	return ret;188}189 190static int dp_link_parse_audio_pattern_type(struct dp_link_private *link)191{192	int ret = 0;193	u8 data;194	ssize_t rlen;195	int const max_audio_pattern_type = 0x1;196 197	rlen = drm_dp_dpcd_readb(link->aux,198				DP_TEST_AUDIO_PATTERN_TYPE, &data);199	if (rlen < 0) {200		DRM_ERROR("failed to read link audio mode. rlen=%zd\n", rlen);201		return rlen;202	}203 204	/* Audio Pattern Type - Bits 7:0 */205	if ((int)data > max_audio_pattern_type) {206		DRM_ERROR("invalid audio pattern type = 0x%x\n", data);207		ret = -EINVAL;208		goto exit;209	}210 211	link->dp_link.test_audio.test_audio_pattern_type = data;212	drm_dbg_dp(link->drm_dev, "audio pattern type = 0x%x\n", data);213exit:214	return ret;215}216 217static int dp_link_parse_audio_mode(struct dp_link_private *link)218{219	int ret = 0;220	u8 data;221	ssize_t rlen;222	int const max_audio_sampling_rate = 0x6;223	int const max_audio_channel_count = 0x8;224	int sampling_rate = 0x0;225	int channel_count = 0x0;226 227	rlen = drm_dp_dpcd_readb(link->aux, DP_TEST_AUDIO_MODE, &data);228	if (rlen < 0) {229		DRM_ERROR("failed to read link audio mode. rlen=%zd\n", rlen);230		return rlen;231	}232 233	/* Sampling Rate - Bits 3:0 */234	sampling_rate = data & 0xF;235	if (sampling_rate > max_audio_sampling_rate) {236		DRM_ERROR("sampling rate (0x%x) greater than max (0x%x)\n",237				sampling_rate, max_audio_sampling_rate);238		ret = -EINVAL;239		goto exit;240	}241 242	/* Channel Count - Bits 7:4 */243	channel_count = ((data & 0xF0) >> 4) + 1;244	if (channel_count > max_audio_channel_count) {245		DRM_ERROR("channel_count (0x%x) greater than max (0x%x)\n",246				channel_count, max_audio_channel_count);247		ret = -EINVAL;248		goto exit;249	}250 251	link->dp_link.test_audio.test_audio_sampling_rate = sampling_rate;252	link->dp_link.test_audio.test_audio_channel_count = channel_count;253	drm_dbg_dp(link->drm_dev,254			"sampling_rate = 0x%x, channel_count = 0x%x\n",255			sampling_rate, channel_count);256exit:257	return ret;258}259 260static int dp_link_parse_audio_pattern_params(struct dp_link_private *link)261{262	int ret = 0;263 264	ret = dp_link_parse_audio_mode(link);265	if (ret)266		goto exit;267 268	ret = dp_link_parse_audio_pattern_type(link);269	if (ret)270		goto exit;271 272	ret = dp_link_parse_audio_channel_period(link);273 274exit:275	return ret;276}277 278static bool dp_link_is_video_pattern_valid(u32 pattern)279{280	switch (pattern) {281	case DP_NO_TEST_PATTERN:282	case DP_COLOR_RAMP:283	case DP_BLACK_AND_WHITE_VERTICAL_LINES:284	case DP_COLOR_SQUARE:285		return true;286	default:287		return false;288	}289}290 291/**292 * dp_link_is_bit_depth_valid() - validates the bit depth requested293 * @tbd: bit depth requested by the sink294 *295 * Returns true if the requested bit depth is supported.296 */297static bool dp_link_is_bit_depth_valid(u32 tbd)298{299	/* DP_TEST_VIDEO_PATTERN_NONE is treated as invalid */300	switch (tbd) {301	case DP_TEST_BIT_DEPTH_6:302	case DP_TEST_BIT_DEPTH_8:303	case DP_TEST_BIT_DEPTH_10:304		return true;305	default:306		return false;307	}308}309 310static int dp_link_parse_timing_params1(struct dp_link_private *link,311					int addr, int len, u32 *val)312{313	u8 bp[2];314	int rlen;315 316	if (len != 2)317		return -EINVAL;318 319	/* Read the requested video link pattern (Byte 0x221). */320	rlen = drm_dp_dpcd_read(link->aux, addr, bp, len);321	if (rlen < len) {322		DRM_ERROR("failed to read 0x%x\n", addr);323		return -EINVAL;324	}325 326	*val = bp[1] | (bp[0] << 8);327 328	return 0;329}330 331static int dp_link_parse_timing_params2(struct dp_link_private *link,332					int addr, int len,333					u32 *val1, u32 *val2)334{335	u8 bp[2];336	int rlen;337 338	if (len != 2)339		return -EINVAL;340 341	/* Read the requested video link pattern (Byte 0x221). */342	rlen = drm_dp_dpcd_read(link->aux, addr, bp, len);343	if (rlen < len) {344		DRM_ERROR("failed to read 0x%x\n", addr);345		return -EINVAL;346	}347 348	*val1 = (bp[0] & BIT(7)) >> 7;349	*val2 = bp[1] | ((bp[0] & 0x7F) << 8);350 351	return 0;352}353 354static int dp_link_parse_timing_params3(struct dp_link_private *link,355					int addr, u32 *val)356{357	u8 bp;358	u32 len = 1;359	int rlen;360 361	rlen = drm_dp_dpcd_read(link->aux, addr, &bp, len);362	if (rlen < 1) {363		DRM_ERROR("failed to read 0x%x\n", addr);364		return -EINVAL;365	}366	*val = bp;367 368	return 0;369}370 371/**372 * dp_link_parse_video_pattern_params() - parses video pattern parameters from DPCD373 * @link: Display Port Driver data374 *375 * Returns 0 if it successfully parses the video link pattern and the link376 * bit depth requested by the sink and, and if the values parsed are valid.377 */378static int dp_link_parse_video_pattern_params(struct dp_link_private *link)379{380	int ret = 0;381	ssize_t rlen;382	u8 bp;383 384	rlen = drm_dp_dpcd_readb(link->aux, DP_TEST_PATTERN, &bp);385	if (rlen < 0) {386		DRM_ERROR("failed to read link video pattern. rlen=%zd\n",387			rlen);388		return rlen;389	}390 391	if (!dp_link_is_video_pattern_valid(bp)) {392		DRM_ERROR("invalid link video pattern = 0x%x\n", bp);393		ret = -EINVAL;394		return ret;395	}396 397	link->dp_link.test_video.test_video_pattern = bp;398 399	/* Read the requested color bit depth and dynamic range (Byte 0x232) */400	rlen = drm_dp_dpcd_readb(link->aux, DP_TEST_MISC0, &bp);401	if (rlen < 0) {402		DRM_ERROR("failed to read link bit depth. rlen=%zd\n", rlen);403		return rlen;404	}405 406	/* Dynamic Range */407	link->dp_link.test_video.test_dyn_range =408			(bp & DP_TEST_DYNAMIC_RANGE_CEA);409 410	/* Color bit depth */411	bp &= DP_TEST_BIT_DEPTH_MASK;412	if (!dp_link_is_bit_depth_valid(bp)) {413		DRM_ERROR("invalid link bit depth = 0x%x\n", bp);414		ret = -EINVAL;415		return ret;416	}417 418	link->dp_link.test_video.test_bit_depth = bp;419 420	/* resolution timing params */421	ret = dp_link_parse_timing_params1(link, DP_TEST_H_TOTAL_HI, 2,422			&link->dp_link.test_video.test_h_total);423	if (ret) {424		DRM_ERROR("failed to parse test_htotal(DP_TEST_H_TOTAL_HI)\n");425		return ret;426	}427 428	ret = dp_link_parse_timing_params1(link, DP_TEST_V_TOTAL_HI, 2,429			&link->dp_link.test_video.test_v_total);430	if (ret) {431		DRM_ERROR("failed to parse test_v_total(DP_TEST_V_TOTAL_HI)\n");432		return ret;433	}434 435	ret = dp_link_parse_timing_params1(link, DP_TEST_H_START_HI, 2,436			&link->dp_link.test_video.test_h_start);437	if (ret) {438		DRM_ERROR("failed to parse test_h_start(DP_TEST_H_START_HI)\n");439		return ret;440	}441 442	ret = dp_link_parse_timing_params1(link, DP_TEST_V_START_HI, 2,443			&link->dp_link.test_video.test_v_start);444	if (ret) {445		DRM_ERROR("failed to parse test_v_start(DP_TEST_V_START_HI)\n");446		return ret;447	}448 449	ret = dp_link_parse_timing_params2(link, DP_TEST_HSYNC_HI, 2,450			&link->dp_link.test_video.test_hsync_pol,451			&link->dp_link.test_video.test_hsync_width);452	if (ret) {453		DRM_ERROR("failed to parse (DP_TEST_HSYNC_HI)\n");454		return ret;455	}456 457	ret = dp_link_parse_timing_params2(link, DP_TEST_VSYNC_HI, 2,458			&link->dp_link.test_video.test_vsync_pol,459			&link->dp_link.test_video.test_vsync_width);460	if (ret) {461		DRM_ERROR("failed to parse (DP_TEST_VSYNC_HI)\n");462		return ret;463	}464 465	ret = dp_link_parse_timing_params1(link, DP_TEST_H_WIDTH_HI, 2,466			&link->dp_link.test_video.test_h_width);467	if (ret) {468		DRM_ERROR("failed to parse test_h_width(DP_TEST_H_WIDTH_HI)\n");469		return ret;470	}471 472	ret = dp_link_parse_timing_params1(link, DP_TEST_V_HEIGHT_HI, 2,473			&link->dp_link.test_video.test_v_height);474	if (ret) {475		DRM_ERROR("failed to parse test_v_height\n");476		return ret;477	}478 479	ret = dp_link_parse_timing_params3(link, DP_TEST_MISC1,480		&link->dp_link.test_video.test_rr_d);481	link->dp_link.test_video.test_rr_d &= DP_TEST_REFRESH_DENOMINATOR;482	if (ret) {483		DRM_ERROR("failed to parse test_rr_d (DP_TEST_MISC1)\n");484		return ret;485	}486 487	ret = dp_link_parse_timing_params3(link, DP_TEST_REFRESH_RATE_NUMERATOR,488		&link->dp_link.test_video.test_rr_n);489	if (ret) {490		DRM_ERROR("failed to parse test_rr_n\n");491		return ret;492	}493 494	drm_dbg_dp(link->drm_dev,495		"link video pattern = 0x%x\n"496		"link dynamic range = 0x%x\n"497		"link bit depth = 0x%x\n"498		"TEST_H_TOTAL = %d, TEST_V_TOTAL = %d\n"499		"TEST_H_START = %d, TEST_V_START = %d\n"500		"TEST_HSYNC_POL = %d\n"501		"TEST_HSYNC_WIDTH = %d\n"502		"TEST_VSYNC_POL = %d\n"503		"TEST_VSYNC_WIDTH = %d\n"504		"TEST_H_WIDTH = %d\n"505		"TEST_V_HEIGHT = %d\n"506		"TEST_REFRESH_DENOMINATOR = %d\n"507		 "TEST_REFRESH_NUMERATOR = %d\n",508		link->dp_link.test_video.test_video_pattern,509		link->dp_link.test_video.test_dyn_range,510		link->dp_link.test_video.test_bit_depth,511		link->dp_link.test_video.test_h_total,512		link->dp_link.test_video.test_v_total,513		link->dp_link.test_video.test_h_start,514		link->dp_link.test_video.test_v_start,515		link->dp_link.test_video.test_hsync_pol,516		link->dp_link.test_video.test_hsync_width,517		link->dp_link.test_video.test_vsync_pol,518		link->dp_link.test_video.test_vsync_width,519		link->dp_link.test_video.test_h_width,520		link->dp_link.test_video.test_v_height,521		link->dp_link.test_video.test_rr_d,522		link->dp_link.test_video.test_rr_n);523 524	return ret;525}526 527/**528 * dp_link_parse_link_training_params() - parses link training parameters from529 * DPCD530 * @link: Display Port Driver data531 *532 * Returns 0 if it successfully parses the link rate (Byte 0x219) and lane533 * count (Byte 0x220), and if these values parse are valid.534 */535static int dp_link_parse_link_training_params(struct dp_link_private *link)536{537	u8 bp;538	ssize_t rlen;539 540	rlen = drm_dp_dpcd_readb(link->aux, DP_TEST_LINK_RATE,	&bp);541	if (rlen < 0) {542		DRM_ERROR("failed to read link rate. rlen=%zd\n", rlen);543		return rlen;544	}545 546	if (!is_link_rate_valid(bp)) {547		DRM_ERROR("invalid link rate = 0x%x\n", bp);548		return -EINVAL;549	}550 551	link->request.test_link_rate = bp;552	drm_dbg_dp(link->drm_dev, "link rate = 0x%x\n",553				link->request.test_link_rate);554 555	rlen = drm_dp_dpcd_readb(link->aux, DP_TEST_LANE_COUNT, &bp);556	if (rlen < 0) {557		DRM_ERROR("failed to read lane count. rlen=%zd\n", rlen);558		return rlen;559	}560	bp &= DP_MAX_LANE_COUNT_MASK;561 562	if (!is_lane_count_valid(bp)) {563		DRM_ERROR("invalid lane count = 0x%x\n", bp);564		return -EINVAL;565	}566 567	link->request.test_lane_count = bp;568	drm_dbg_dp(link->drm_dev, "lane count = 0x%x\n",569				link->request.test_lane_count);570	return 0;571}572 573/**574 * dp_link_parse_phy_test_params() - parses the phy link parameters575 * @link: Display Port Driver data576 *577 * Parses the DPCD (Byte 0x248) for the DP PHY link pattern that is being578 * requested.579 */580static int dp_link_parse_phy_test_params(struct dp_link_private *link)581{582	u8 data;583	ssize_t rlen;584 585	rlen = drm_dp_dpcd_readb(link->aux, DP_PHY_TEST_PATTERN,586					&data);587	if (rlen < 0) {588		DRM_ERROR("failed to read phy link pattern. rlen=%zd\n", rlen);589		return rlen;590	}591 592	link->dp_link.phy_params.phy_test_pattern_sel = data & 0x07;593 594	drm_dbg_dp(link->drm_dev, "phy_test_pattern_sel = 0x%x\n", data);595 596	switch (data) {597	case DP_PHY_TEST_PATTERN_SEL_MASK:598	case DP_PHY_TEST_PATTERN_NONE:599	case DP_PHY_TEST_PATTERN_D10_2:600	case DP_PHY_TEST_PATTERN_ERROR_COUNT:601	case DP_PHY_TEST_PATTERN_PRBS7:602	case DP_PHY_TEST_PATTERN_80BIT_CUSTOM:603	case DP_PHY_TEST_PATTERN_CP2520:604		return 0;605	default:606		return -EINVAL;607	}608}609 610/**611 * dp_link_is_video_audio_test_requested() - checks for audio/video link request612 * @link: link requested by the sink613 *614 * Returns true if the requested link is a permitted audio/video link.615 */616static bool dp_link_is_video_audio_test_requested(u32 link)617{618	u8 video_audio_test = (DP_TEST_LINK_VIDEO_PATTERN |619				DP_TEST_LINK_AUDIO_PATTERN |620				DP_TEST_LINK_AUDIO_DISABLED_VIDEO);621 622	return ((link & video_audio_test) &&623		!(link & ~video_audio_test));624}625 626/**627 * dp_link_parse_request() - parses link request parameters from sink628 * @link: Display Port Driver data629 *630 * Parses the DPCD to check if an automated link is requested (Byte 0x201),631 * and what type of link automation is being requested (Byte 0x218).632 */633static int dp_link_parse_request(struct dp_link_private *link)634{635	int ret = 0;636	u8 data;637	ssize_t rlen;638 639	/**640	 * Read the device service IRQ vector (Byte 0x201) to determine641	 * whether an automated link has been requested by the sink.642	 */643	rlen = drm_dp_dpcd_readb(link->aux,644				DP_DEVICE_SERVICE_IRQ_VECTOR, &data);645	if (rlen < 0) {646		DRM_ERROR("aux read failed. rlen=%zd\n", rlen);647		return rlen;648	}649 650	drm_dbg_dp(link->drm_dev, "device service irq vector = 0x%x\n", data);651 652	if (!(data & DP_AUTOMATED_TEST_REQUEST)) {653		drm_dbg_dp(link->drm_dev, "no test requested\n");654		return 0;655	}656 657	/**658	 * Read the link request byte (Byte 0x218) to determine what type659	 * of automated link has been requested by the sink.660	 */661	rlen = drm_dp_dpcd_readb(link->aux, DP_TEST_REQUEST, &data);662	if (rlen < 0) {663		DRM_ERROR("aux read failed. rlen=%zd\n", rlen);664		return rlen;665	}666 667	if (!data || (data == DP_TEST_LINK_FAUX_PATTERN)) {668		drm_dbg_dp(link->drm_dev, "link 0x%x not supported\n", data);669		goto end;670	}671 672	drm_dbg_dp(link->drm_dev, "Test:(0x%x) requested\n", data);673	link->request.test_requested = data;674	if (link->request.test_requested == DP_TEST_LINK_PHY_TEST_PATTERN) {675		ret = dp_link_parse_phy_test_params(link);676		if (ret)677			goto end;678		ret = dp_link_parse_link_training_params(link);679		if (ret)680			goto end;681	}682 683	if (link->request.test_requested == DP_TEST_LINK_TRAINING) {684		ret = dp_link_parse_link_training_params(link);685		if (ret)686			goto end;687	}688 689	if (dp_link_is_video_audio_test_requested(690			link->request.test_requested)) {691		ret = dp_link_parse_video_pattern_params(link);692		if (ret)693			goto end;694 695		ret = dp_link_parse_audio_pattern_params(link);696	}697end:698	/*699	 * Send a DP_TEST_ACK if all link parameters are valid, otherwise send700	 * a DP_TEST_NAK.701	 */702	if (ret) {703		link->dp_link.test_response = DP_TEST_NAK;704	} else {705		if (link->request.test_requested != DP_TEST_LINK_EDID_READ)706			link->dp_link.test_response = DP_TEST_ACK;707		else708			link->dp_link.test_response =709				DP_TEST_EDID_CHECKSUM_WRITE;710	}711 712	return ret;713}714 715static int dp_link_parse_sink_status_field(struct dp_link_private *link)716{717	int len;718 719	link->prev_sink_count = link->dp_link.sink_count;720	len = drm_dp_read_sink_count(link->aux);721	if (len < 0) {722		DRM_ERROR("DP parse sink count failed\n");723		return len;724	}725	link->dp_link.sink_count = len;726 727	len = drm_dp_dpcd_read_link_status(link->aux,728		link->link_status);729	if (len < DP_LINK_STATUS_SIZE) {730		DRM_ERROR("DP link status read failed\n");731		return len;732	}733 734	return dp_link_parse_request(link);735}736 737/**738 * dp_link_process_link_training_request() - processes new training requests739 * @link: Display Port link data740 *741 * This function will handle new link training requests that are initiated by742 * the sink. In particular, it will update the requested lane count and link743 * rate, and then trigger the link retraining procedure.744 *745 * The function will return 0 if a link training request has been processed,746 * otherwise it will return -EINVAL.747 */748static int dp_link_process_link_training_request(struct dp_link_private *link)749{750	if (link->request.test_requested != DP_TEST_LINK_TRAINING)751		return -EINVAL;752 753	drm_dbg_dp(link->drm_dev,754			"Test:0x%x link rate = 0x%x, lane count = 0x%x\n",755			DP_TEST_LINK_TRAINING,756			link->request.test_link_rate,757			link->request.test_lane_count);758 759	link->dp_link.link_params.num_lanes = link->request.test_lane_count;760	link->dp_link.link_params.rate =761		drm_dp_bw_code_to_link_rate(link->request.test_link_rate);762 763	return 0;764}765 766bool dp_link_send_test_response(struct dp_link *dp_link)767{768	struct dp_link_private *link = NULL;769	int ret = 0;770 771	if (!dp_link) {772		DRM_ERROR("invalid input\n");773		return false;774	}775 776	link = container_of(dp_link, struct dp_link_private, dp_link);777 778	ret = drm_dp_dpcd_writeb(link->aux, DP_TEST_RESPONSE,779			dp_link->test_response);780 781	return ret == 1;782}783 784int dp_link_psm_config(struct dp_link *dp_link,785			      struct dp_link_info *link_info, bool enable)786{787	struct dp_link_private *link = NULL;788	int ret = 0;789 790	if (!dp_link) {791		DRM_ERROR("invalid params\n");792		return -EINVAL;793	}794 795	link = container_of(dp_link, struct dp_link_private, dp_link);796 797	mutex_lock(&link->psm_mutex);798	if (enable)799		ret = dp_aux_link_power_down(link->aux, link_info);800	else801		ret = dp_aux_link_power_up(link->aux, link_info);802 803	if (ret)804		DRM_ERROR("Failed to %s low power mode\n", enable ?805							"enter" : "exit");806 807	mutex_unlock(&link->psm_mutex);808	return ret;809}810 811bool dp_link_send_edid_checksum(struct dp_link *dp_link, u8 checksum)812{813	struct dp_link_private *link = NULL;814	int ret = 0;815 816	if (!dp_link) {817		DRM_ERROR("invalid input\n");818		return false;819	}820 821	link = container_of(dp_link, struct dp_link_private, dp_link);822 823	ret = drm_dp_dpcd_writeb(link->aux, DP_TEST_EDID_CHECKSUM,824						checksum);825	return ret == 1;826}827 828static void dp_link_parse_vx_px(struct dp_link_private *link)829{830	drm_dbg_dp(link->drm_dev, "vx: 0=%d, 1=%d, 2=%d, 3=%d\n",831		drm_dp_get_adjust_request_voltage(link->link_status, 0),832		drm_dp_get_adjust_request_voltage(link->link_status, 1),833		drm_dp_get_adjust_request_voltage(link->link_status, 2),834		drm_dp_get_adjust_request_voltage(link->link_status, 3));835 836	drm_dbg_dp(link->drm_dev, "px: 0=%d, 1=%d, 2=%d, 3=%d\n",837		drm_dp_get_adjust_request_pre_emphasis(link->link_status, 0),838		drm_dp_get_adjust_request_pre_emphasis(link->link_status, 1),839		drm_dp_get_adjust_request_pre_emphasis(link->link_status, 2),840		drm_dp_get_adjust_request_pre_emphasis(link->link_status, 3));841 842	/**843	 * Update the voltage and pre-emphasis levels as per DPCD request844	 * vector.845	 */846	drm_dbg_dp(link->drm_dev,847			 "Current: v_level = 0x%x, p_level = 0x%x\n",848			link->dp_link.phy_params.v_level,849			link->dp_link.phy_params.p_level);850	link->dp_link.phy_params.v_level =851		drm_dp_get_adjust_request_voltage(link->link_status, 0);852	link->dp_link.phy_params.p_level =853		drm_dp_get_adjust_request_pre_emphasis(link->link_status, 0);854 855	link->dp_link.phy_params.p_level >>= DP_TRAIN_PRE_EMPHASIS_SHIFT;856 857	drm_dbg_dp(link->drm_dev,858			"Requested: v_level = 0x%x, p_level = 0x%x\n",859			link->dp_link.phy_params.v_level,860			link->dp_link.phy_params.p_level);861}862 863/**864 * dp_link_process_phy_test_pattern_request() - process new phy link requests865 * @link: Display Port Driver data866 *867 * This function will handle new phy link pattern requests that are initiated868 * by the sink. The function will return 0 if a phy link pattern has been869 * processed, otherwise it will return -EINVAL.870 */871static int dp_link_process_phy_test_pattern_request(872		struct dp_link_private *link)873{874	if (!(link->request.test_requested & DP_TEST_LINK_PHY_TEST_PATTERN)) {875		drm_dbg_dp(link->drm_dev, "no phy test\n");876		return -EINVAL;877	}878 879	if (!is_link_rate_valid(link->request.test_link_rate) ||880		!is_lane_count_valid(link->request.test_lane_count)) {881		DRM_ERROR("Invalid: link rate = 0x%x,lane count = 0x%x\n",882				link->request.test_link_rate,883				link->request.test_lane_count);884		return -EINVAL;885	}886 887	drm_dbg_dp(link->drm_dev,888			"Current: rate = 0x%x, lane count = 0x%x\n",889			link->dp_link.link_params.rate,890			link->dp_link.link_params.num_lanes);891 892	drm_dbg_dp(link->drm_dev,893			"Requested: rate = 0x%x, lane count = 0x%x\n",894			link->request.test_link_rate,895			link->request.test_lane_count);896 897	link->dp_link.link_params.num_lanes = link->request.test_lane_count;898	link->dp_link.link_params.rate =899		drm_dp_bw_code_to_link_rate(link->request.test_link_rate);900 901	dp_link_parse_vx_px(link);902 903	return 0;904}905 906static bool dp_link_read_psr_error_status(struct dp_link_private *link)907{908	u8 status;909 910	drm_dp_dpcd_read(link->aux, DP_PSR_ERROR_STATUS, &status, 1);911 912	if (status & DP_PSR_LINK_CRC_ERROR)913		DRM_ERROR("PSR LINK CRC ERROR\n");914	else if (status & DP_PSR_RFB_STORAGE_ERROR)915		DRM_ERROR("PSR RFB STORAGE ERROR\n");916	else if (status & DP_PSR_VSC_SDP_UNCORRECTABLE_ERROR)917		DRM_ERROR("PSR VSC SDP UNCORRECTABLE ERROR\n");918	else919		return false;920 921	return true;922}923 924static bool dp_link_psr_capability_changed(struct dp_link_private *link)925{926	u8 status;927 928	drm_dp_dpcd_read(link->aux, DP_PSR_ESI, &status, 1);929 930	if (status & DP_PSR_CAPS_CHANGE) {931		drm_dbg_dp(link->drm_dev, "PSR Capability Change\n");932		return true;933	}934 935	return false;936}937 938static u8 get_link_status(const u8 link_status[DP_LINK_STATUS_SIZE], int r)939{940	return link_status[r - DP_LANE0_1_STATUS];941}942 943/**944 * dp_link_process_link_status_update() - processes link status updates945 * @link: Display Port link module data946 *947 * This function will check for changes in the link status, e.g. clock948 * recovery done on all lanes, and trigger link training if there is a949 * failure/error on the link.950 *951 * The function will return 0 if the a link status update has been processed,952 * otherwise it will return -EINVAL.953 */954static int dp_link_process_link_status_update(struct dp_link_private *link)955{956	bool channel_eq_done = drm_dp_channel_eq_ok(link->link_status,957			link->dp_link.link_params.num_lanes);958 959	bool clock_recovery_done = drm_dp_clock_recovery_ok(link->link_status,960			link->dp_link.link_params.num_lanes);961 962	drm_dbg_dp(link->drm_dev,963		       "channel_eq_done = %d, clock_recovery_done = %d\n",964                        channel_eq_done, clock_recovery_done);965 966	if (channel_eq_done && clock_recovery_done)967		return -EINVAL;968 969	return 0;970}971 972/**973 * dp_link_process_ds_port_status_change() - process port status changes974 * @link: Display Port Driver data975 *976 * This function will handle downstream port updates that are initiated by977 * the sink. If the downstream port status has changed, the EDID is read via978 * AUX.979 *980 * The function will return 0 if a downstream port update has been981 * processed, otherwise it will return -EINVAL.982 */983static int dp_link_process_ds_port_status_change(struct dp_link_private *link)984{985	if (get_link_status(link->link_status, DP_LANE_ALIGN_STATUS_UPDATED) &986					DP_DOWNSTREAM_PORT_STATUS_CHANGED)987		goto reset;988 989	if (link->prev_sink_count == link->dp_link.sink_count)990		return -EINVAL;991 992reset:993	/* reset prev_sink_count */994	link->prev_sink_count = link->dp_link.sink_count;995 996	return 0;997}998 999static bool dp_link_is_video_pattern_requested(struct dp_link_private *link)1000{1001	return (link->request.test_requested & DP_TEST_LINK_VIDEO_PATTERN)1002		&& !(link->request.test_requested &1003		DP_TEST_LINK_AUDIO_DISABLED_VIDEO);1004}1005 1006static bool dp_link_is_audio_pattern_requested(struct dp_link_private *link)1007{1008	return (link->request.test_requested & DP_TEST_LINK_AUDIO_PATTERN);1009}1010 1011static void dp_link_reset_data(struct dp_link_private *link)1012{1013	link->request = (const struct dp_link_request){ 0 };1014	link->dp_link.test_video = (const struct dp_link_test_video){ 0 };1015	link->dp_link.test_video.test_bit_depth = DP_TEST_BIT_DEPTH_UNKNOWN;1016	link->dp_link.test_audio = (const struct dp_link_test_audio){ 0 };1017	link->dp_link.phy_params.phy_test_pattern_sel = 0;1018	link->dp_link.sink_request = 0;1019	link->dp_link.test_response = 0;1020}1021 1022/**1023 * dp_link_process_request() - handle HPD IRQ transition to HIGH1024 * @dp_link: pointer to link module data1025 *1026 * This function will handle the HPD IRQ state transitions from LOW to HIGH1027 * (including cases when there are back to back HPD IRQ HIGH) indicating1028 * the start of a new link training request or sink status update.1029 */1030int dp_link_process_request(struct dp_link *dp_link)1031{1032	int ret = 0;1033	struct dp_link_private *link;1034 1035	if (!dp_link) {1036		DRM_ERROR("invalid input\n");1037		return -EINVAL;1038	}1039 1040	link = container_of(dp_link, struct dp_link_private, dp_link);1041 1042	dp_link_reset_data(link);1043 1044	ret = dp_link_parse_sink_status_field(link);1045	if (ret)1046		return ret;1047 1048	if (link->request.test_requested == DP_TEST_LINK_EDID_READ) {1049		dp_link->sink_request |= DP_TEST_LINK_EDID_READ;1050	} else if (!dp_link_process_ds_port_status_change(link)) {1051		dp_link->sink_request |= DS_PORT_STATUS_CHANGED;1052	} else if (!dp_link_process_link_training_request(link)) {1053		dp_link->sink_request |= DP_TEST_LINK_TRAINING;1054	} else if (!dp_link_process_phy_test_pattern_request(link)) {1055		dp_link->sink_request |= DP_TEST_LINK_PHY_TEST_PATTERN;1056	} else if (dp_link_read_psr_error_status(link)) {1057		DRM_ERROR("PSR IRQ_HPD received\n");1058	} else if (dp_link_psr_capability_changed(link)) {1059		drm_dbg_dp(link->drm_dev, "PSR Capability changed\n");1060	} else {1061		ret = dp_link_process_link_status_update(link);1062		if (!ret) {1063			dp_link->sink_request |= DP_LINK_STATUS_UPDATED;1064		} else {1065			if (dp_link_is_video_pattern_requested(link)) {1066				ret = 0;1067				dp_link->sink_request |= DP_TEST_LINK_VIDEO_PATTERN;1068			}1069			if (dp_link_is_audio_pattern_requested(link)) {1070				dp_link->sink_request |= DP_TEST_LINK_AUDIO_PATTERN;1071				ret = -EINVAL;1072			}1073		}1074	}1075 1076	drm_dbg_dp(link->drm_dev, "sink request=%#x\n",1077				dp_link->sink_request);1078	return ret;1079}1080 1081int dp_link_get_colorimetry_config(struct dp_link *dp_link)1082{1083	u32 cc = DP_MISC0_COLORIMERY_CFG_LEGACY_RGB;1084	struct dp_link_private *link;1085 1086	if (!dp_link) {1087		DRM_ERROR("invalid input\n");1088		return -EINVAL;1089	}1090 1091	link = container_of(dp_link, struct dp_link_private, dp_link);1092 1093	/*1094	 * Unless a video pattern CTS test is ongoing, use RGB_VESA1095	 * Only RGB_VESA and RGB_CEA supported for now1096	 */1097	if (dp_link_is_video_pattern_requested(link)) {1098		if (link->dp_link.test_video.test_dyn_range &1099					DP_TEST_DYNAMIC_RANGE_CEA)1100			cc = DP_MISC0_COLORIMERY_CFG_CEA_RGB;1101	}1102 1103	return cc;1104}1105 1106int dp_link_adjust_levels(struct dp_link *dp_link, u8 *link_status)1107{1108	int i;1109	u8 max_p_level;1110	int v_max = 0, p_max = 0;1111	struct dp_link_private *link;1112 1113	if (!dp_link) {1114		DRM_ERROR("invalid input\n");1115		return -EINVAL;1116	}1117 1118	link = container_of(dp_link, struct dp_link_private, dp_link);1119 1120	/* use the max level across lanes */1121	for (i = 0; i < dp_link->link_params.num_lanes; i++) {1122		u8 data_v = drm_dp_get_adjust_request_voltage(link_status, i);1123		u8 data_p = drm_dp_get_adjust_request_pre_emphasis(link_status,1124									 i);1125		drm_dbg_dp(link->drm_dev,1126				"lane=%d req_vol_swing=%d req_pre_emphasis=%d\n",1127				i, data_v, data_p);1128		if (v_max < data_v)1129			v_max = data_v;1130		if (p_max < data_p)1131			p_max = data_p;1132	}1133 1134	dp_link->phy_params.v_level = v_max >> DP_TRAIN_VOLTAGE_SWING_SHIFT;1135	dp_link->phy_params.p_level = p_max >> DP_TRAIN_PRE_EMPHASIS_SHIFT;1136 1137	/**1138	 * Adjust the voltage swing and pre-emphasis level combination to within1139	 * the allowable range.1140	 */1141	if (dp_link->phy_params.v_level > DP_TRAIN_LEVEL_MAX) {1142		drm_dbg_dp(link->drm_dev,1143			"Requested vSwingLevel=%d, change to %d\n",1144			dp_link->phy_params.v_level,1145			DP_TRAIN_LEVEL_MAX);1146		dp_link->phy_params.v_level = DP_TRAIN_LEVEL_MAX;1147	}1148 1149	if (dp_link->phy_params.p_level > DP_TRAIN_LEVEL_MAX) {1150		drm_dbg_dp(link->drm_dev,1151			"Requested preEmphasisLevel=%d, change to %d\n",1152			dp_link->phy_params.p_level,1153			DP_TRAIN_LEVEL_MAX);1154		dp_link->phy_params.p_level = DP_TRAIN_LEVEL_MAX;1155	}1156 1157	max_p_level = DP_TRAIN_LEVEL_MAX - dp_link->phy_params.v_level;1158	if (dp_link->phy_params.p_level > max_p_level) {1159		drm_dbg_dp(link->drm_dev,1160			"Requested preEmphasisLevel=%d, change to %d\n",1161			dp_link->phy_params.p_level,1162			max_p_level);1163		dp_link->phy_params.p_level = max_p_level;1164	}1165 1166	drm_dbg_dp(link->drm_dev, "adjusted: v_level=%d, p_level=%d\n",1167		dp_link->phy_params.v_level, dp_link->phy_params.p_level);1168 1169	return 0;1170}1171 1172void dp_link_reset_phy_params_vx_px(struct dp_link *dp_link)1173{1174	dp_link->phy_params.v_level = 0;1175	dp_link->phy_params.p_level = 0;1176}1177 1178u32 dp_link_get_test_bits_depth(struct dp_link *dp_link, u32 bpp)1179{1180	u32 tbd;1181	struct dp_link_private *link;1182 1183	link = container_of(dp_link, struct dp_link_private, dp_link);1184 1185	/*1186	 * Few simplistic rules and assumptions made here:1187	 *    1. Test bit depth is bit depth per color component1188	 *    2. Assume 3 color components1189	 */1190	switch (bpp) {1191	case 18:1192		tbd = DP_TEST_BIT_DEPTH_6;1193		break;1194	case 24:1195		tbd = DP_TEST_BIT_DEPTH_8;1196		break;1197	case 30:1198		tbd = DP_TEST_BIT_DEPTH_10;1199		break;1200	default:1201		drm_dbg_dp(link->drm_dev, "bpp=%d not supported, use bpc=8\n",1202			   bpp);1203		tbd = DP_TEST_BIT_DEPTH_8;1204		break;1205	}1206 1207	tbd = (tbd >> DP_TEST_BIT_DEPTH_SHIFT);1208 1209	return tbd;1210}1211 1212struct dp_link *dp_link_get(struct device *dev, struct drm_dp_aux *aux)1213{1214	struct dp_link_private *link;1215	struct dp_link *dp_link;1216 1217	if (!dev || !aux) {1218		DRM_ERROR("invalid input\n");1219		return ERR_PTR(-EINVAL);1220	}1221 1222	link = devm_kzalloc(dev, sizeof(*link), GFP_KERNEL);1223	if (!link)1224		return ERR_PTR(-ENOMEM);1225 1226	link->aux   = aux;1227 1228	mutex_init(&link->psm_mutex);1229	dp_link = &link->dp_link;1230 1231	return dp_link;1232}1233