File Index
Files and directories
Sign in
FILE

dp_link.c

File preview with syntax highlighting.

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