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