16f486c69SFrançois Tigeot /* 26f486c69SFrançois Tigeot * Copyright © 2009 Keith Packard 36f486c69SFrançois Tigeot * 46f486c69SFrançois Tigeot * Permission to use, copy, modify, distribute, and sell this software and its 56f486c69SFrançois Tigeot * documentation for any purpose is hereby granted without fee, provided that 66f486c69SFrançois Tigeot * the above copyright notice appear in all copies and that both that copyright 76f486c69SFrançois Tigeot * notice and this permission notice appear in supporting documentation, and 86f486c69SFrançois Tigeot * that the name of the copyright holders not be used in advertising or 96f486c69SFrançois Tigeot * publicity pertaining to distribution of the software without specific, 106f486c69SFrançois Tigeot * written prior permission. The copyright holders make no representations 116f486c69SFrançois Tigeot * about the suitability of this software for any purpose. It is provided "as 126f486c69SFrançois Tigeot * is" without express or implied warranty. 136f486c69SFrançois Tigeot * 146f486c69SFrançois Tigeot * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 156f486c69SFrançois Tigeot * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO 166f486c69SFrançois Tigeot * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR 176f486c69SFrançois Tigeot * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, 186f486c69SFrançois Tigeot * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 196f486c69SFrançois Tigeot * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 206f486c69SFrançois Tigeot * OF THIS SOFTWARE. 216f486c69SFrançois Tigeot */ 226f486c69SFrançois Tigeot 2319df918dSFrançois Tigeot #include <linux/export.h> 2418e26a6dSFrançois Tigeot #include <drm/drmP.h> 2518e26a6dSFrançois Tigeot #include <drm/drm_dp_helper.h> 266f486c69SFrançois Tigeot 276f486c69SFrançois Tigeot 2819df918dSFrançois Tigeot /* Helpers for DP link training */ 29*9edbd4a0SFrançois Tigeot static u8 dp_link_status(const u8 link_status[DP_LINK_STATUS_SIZE], int r) 306f486c69SFrançois Tigeot { 316f486c69SFrançois Tigeot return link_status[r - DP_LANE0_1_STATUS]; 326f486c69SFrançois Tigeot } 336f486c69SFrançois Tigeot 34*9edbd4a0SFrançois Tigeot static u8 dp_get_lane_status(const u8 link_status[DP_LINK_STATUS_SIZE], 356f486c69SFrançois Tigeot int lane) 366f486c69SFrançois Tigeot { 376f486c69SFrançois Tigeot int i = DP_LANE0_1_STATUS + (lane >> 1); 386f486c69SFrançois Tigeot int s = (lane & 1) * 4; 396f486c69SFrançois Tigeot u8 l = dp_link_status(link_status, i); 406f486c69SFrançois Tigeot return (l >> s) & 0xf; 416f486c69SFrançois Tigeot } 426f486c69SFrançois Tigeot 43*9edbd4a0SFrançois Tigeot bool drm_dp_channel_eq_ok(const u8 link_status[DP_LINK_STATUS_SIZE], 446f486c69SFrançois Tigeot int lane_count) 456f486c69SFrançois Tigeot { 466f486c69SFrançois Tigeot u8 lane_align; 476f486c69SFrançois Tigeot u8 lane_status; 486f486c69SFrançois Tigeot int lane; 496f486c69SFrançois Tigeot 506f486c69SFrançois Tigeot lane_align = dp_link_status(link_status, 516f486c69SFrançois Tigeot DP_LANE_ALIGN_STATUS_UPDATED); 526f486c69SFrançois Tigeot if ((lane_align & DP_INTERLANE_ALIGN_DONE) == 0) 536f486c69SFrançois Tigeot return false; 546f486c69SFrançois Tigeot for (lane = 0; lane < lane_count; lane++) { 556f486c69SFrançois Tigeot lane_status = dp_get_lane_status(link_status, lane); 566f486c69SFrançois Tigeot if ((lane_status & DP_CHANNEL_EQ_BITS) != DP_CHANNEL_EQ_BITS) 576f486c69SFrançois Tigeot return false; 586f486c69SFrançois Tigeot } 596f486c69SFrançois Tigeot return true; 606f486c69SFrançois Tigeot } 6119df918dSFrançois Tigeot EXPORT_SYMBOL(drm_dp_channel_eq_ok); 626f486c69SFrançois Tigeot 63*9edbd4a0SFrançois Tigeot bool drm_dp_clock_recovery_ok(const u8 link_status[DP_LINK_STATUS_SIZE], 646f486c69SFrançois Tigeot int lane_count) 656f486c69SFrançois Tigeot { 666f486c69SFrançois Tigeot int lane; 676f486c69SFrançois Tigeot u8 lane_status; 686f486c69SFrançois Tigeot 696f486c69SFrançois Tigeot for (lane = 0; lane < lane_count; lane++) { 706f486c69SFrançois Tigeot lane_status = dp_get_lane_status(link_status, lane); 716f486c69SFrançois Tigeot if ((lane_status & DP_LANE_CR_DONE) == 0) 726f486c69SFrançois Tigeot return false; 736f486c69SFrançois Tigeot } 746f486c69SFrançois Tigeot return true; 756f486c69SFrançois Tigeot } 7619df918dSFrançois Tigeot EXPORT_SYMBOL(drm_dp_clock_recovery_ok); 776f486c69SFrançois Tigeot 78*9edbd4a0SFrançois Tigeot u8 drm_dp_get_adjust_request_voltage(const u8 link_status[DP_LINK_STATUS_SIZE], 796f486c69SFrançois Tigeot int lane) 806f486c69SFrançois Tigeot { 816f486c69SFrançois Tigeot int i = DP_ADJUST_REQUEST_LANE0_1 + (lane >> 1); 826f486c69SFrançois Tigeot int s = ((lane & 1) ? 836f486c69SFrançois Tigeot DP_ADJUST_VOLTAGE_SWING_LANE1_SHIFT : 846f486c69SFrançois Tigeot DP_ADJUST_VOLTAGE_SWING_LANE0_SHIFT); 856f486c69SFrançois Tigeot u8 l = dp_link_status(link_status, i); 866f486c69SFrançois Tigeot 876f486c69SFrançois Tigeot return ((l >> s) & 0x3) << DP_TRAIN_VOLTAGE_SWING_SHIFT; 886f486c69SFrançois Tigeot } 8919df918dSFrançois Tigeot EXPORT_SYMBOL(drm_dp_get_adjust_request_voltage); 906f486c69SFrançois Tigeot 91*9edbd4a0SFrançois Tigeot u8 drm_dp_get_adjust_request_pre_emphasis(const u8 link_status[DP_LINK_STATUS_SIZE], 926f486c69SFrançois Tigeot int lane) 936f486c69SFrançois Tigeot { 946f486c69SFrançois Tigeot int i = DP_ADJUST_REQUEST_LANE0_1 + (lane >> 1); 956f486c69SFrançois Tigeot int s = ((lane & 1) ? 966f486c69SFrançois Tigeot DP_ADJUST_PRE_EMPHASIS_LANE1_SHIFT : 976f486c69SFrançois Tigeot DP_ADJUST_PRE_EMPHASIS_LANE0_SHIFT); 986f486c69SFrançois Tigeot u8 l = dp_link_status(link_status, i); 996f486c69SFrançois Tigeot 1006f486c69SFrançois Tigeot return ((l >> s) & 0x3) << DP_TRAIN_PRE_EMPHASIS_SHIFT; 1016f486c69SFrançois Tigeot } 10219df918dSFrançois Tigeot EXPORT_SYMBOL(drm_dp_get_adjust_request_pre_emphasis); 1036f486c69SFrançois Tigeot 104*9edbd4a0SFrançois Tigeot void drm_dp_link_train_clock_recovery_delay(const u8 dpcd[DP_RECEIVER_CAP_SIZE]) { 1056f486c69SFrançois Tigeot if (dpcd[DP_TRAINING_AUX_RD_INTERVAL] == 0) 10619df918dSFrançois Tigeot udelay(100); 1076f486c69SFrançois Tigeot else 10819df918dSFrançois Tigeot mdelay(dpcd[DP_TRAINING_AUX_RD_INTERVAL] * 4); 1096f486c69SFrançois Tigeot } 11019df918dSFrançois Tigeot EXPORT_SYMBOL(drm_dp_link_train_clock_recovery_delay); 1116f486c69SFrançois Tigeot 112*9edbd4a0SFrançois Tigeot void drm_dp_link_train_channel_eq_delay(const u8 dpcd[DP_RECEIVER_CAP_SIZE]) { 1136f486c69SFrançois Tigeot if (dpcd[DP_TRAINING_AUX_RD_INTERVAL] == 0) 11419df918dSFrançois Tigeot udelay(400); 1156f486c69SFrançois Tigeot else 11619df918dSFrançois Tigeot mdelay(dpcd[DP_TRAINING_AUX_RD_INTERVAL] * 4); 1176f486c69SFrançois Tigeot } 11819df918dSFrançois Tigeot EXPORT_SYMBOL(drm_dp_link_train_channel_eq_delay); 1196f486c69SFrançois Tigeot 1206f486c69SFrançois Tigeot u8 drm_dp_link_rate_to_bw_code(int link_rate) 1216f486c69SFrançois Tigeot { 1226f486c69SFrançois Tigeot switch (link_rate) { 1236f486c69SFrançois Tigeot case 162000: 1246f486c69SFrançois Tigeot default: 1256f486c69SFrançois Tigeot return DP_LINK_BW_1_62; 1266f486c69SFrançois Tigeot case 270000: 1276f486c69SFrançois Tigeot return DP_LINK_BW_2_7; 1286f486c69SFrançois Tigeot case 540000: 1296f486c69SFrançois Tigeot return DP_LINK_BW_5_4; 1306f486c69SFrançois Tigeot } 1316f486c69SFrançois Tigeot } 13219df918dSFrançois Tigeot EXPORT_SYMBOL(drm_dp_link_rate_to_bw_code); 1336f486c69SFrançois Tigeot 1346f486c69SFrançois Tigeot int drm_dp_bw_code_to_link_rate(u8 link_bw) 1356f486c69SFrançois Tigeot { 1366f486c69SFrançois Tigeot switch (link_bw) { 1376f486c69SFrançois Tigeot case DP_LINK_BW_1_62: 1386f486c69SFrançois Tigeot default: 1396f486c69SFrançois Tigeot return 162000; 1406f486c69SFrançois Tigeot case DP_LINK_BW_2_7: 1416f486c69SFrançois Tigeot return 270000; 1426f486c69SFrançois Tigeot case DP_LINK_BW_5_4: 1436f486c69SFrançois Tigeot return 540000; 1446f486c69SFrançois Tigeot } 1456f486c69SFrançois Tigeot } 14619df918dSFrançois Tigeot EXPORT_SYMBOL(drm_dp_bw_code_to_link_rate); 147