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