1 /* 2 * Copyright © 2009 Keith Packard 3 * 4 * Permission to use, copy, modify, distribute, and sell this software and its 5 * documentation for any purpose is hereby granted without fee, provided that 6 * the above copyright notice appear in all copies and that both that copyright 7 * notice and this permission notice appear in supporting documentation, and 8 * that the name of the copyright holders not be used in advertising or 9 * publicity pertaining to distribution of the software without specific, 10 * written prior permission. The copyright holders make no representations 11 * about the suitability of this software for any purpose. It is provided "as 12 * is" without express or implied warranty. 13 * 14 * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 15 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO 16 * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR 17 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, 18 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 19 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 20 * OF THIS SOFTWARE. 21 * 22 * $FreeBSD: head/sys/dev/drm2/drm_dp_helper.c 254817 2013-08-24 23:38:57Z dumbbell $ 23 */ 24 25 #include <drm/drmP.h> 26 #include <drm/drm_dp_helper.h> 27 28 /** 29 * DOC: dp helpers 30 * 31 * These functions contain some common logic and helpers at various abstraction 32 * levels to deal with Display Port sink devices and related things like DP aux 33 * channel transfers, EDID reading over DP aux channels, decoding certain DPCD 34 * blocks, ... 35 */ 36 37 static u8 dp_link_status(u8 link_status[DP_LINK_STATUS_SIZE], int r) 38 { 39 return link_status[r - DP_LANE0_1_STATUS]; 40 } 41 42 static u8 dp_get_lane_status(u8 link_status[DP_LINK_STATUS_SIZE], 43 int lane) 44 { 45 int i = DP_LANE0_1_STATUS + (lane >> 1); 46 int s = (lane & 1) * 4; 47 u8 l = dp_link_status(link_status, i); 48 return (l >> s) & 0xf; 49 } 50 51 bool drm_dp_channel_eq_ok(u8 link_status[DP_LINK_STATUS_SIZE], 52 int lane_count) 53 { 54 u8 lane_align; 55 u8 lane_status; 56 int lane; 57 58 lane_align = dp_link_status(link_status, 59 DP_LANE_ALIGN_STATUS_UPDATED); 60 if ((lane_align & DP_INTERLANE_ALIGN_DONE) == 0) 61 return false; 62 for (lane = 0; lane < lane_count; lane++) { 63 lane_status = dp_get_lane_status(link_status, lane); 64 if ((lane_status & DP_CHANNEL_EQ_BITS) != DP_CHANNEL_EQ_BITS) 65 return false; 66 } 67 return true; 68 } 69 70 bool drm_dp_clock_recovery_ok(u8 link_status[DP_LINK_STATUS_SIZE], 71 int lane_count) 72 { 73 int lane; 74 u8 lane_status; 75 76 for (lane = 0; lane < lane_count; lane++) { 77 lane_status = dp_get_lane_status(link_status, lane); 78 if ((lane_status & DP_LANE_CR_DONE) == 0) 79 return false; 80 } 81 return true; 82 } 83 84 u8 drm_dp_get_adjust_request_voltage(u8 link_status[DP_LINK_STATUS_SIZE], 85 int lane) 86 { 87 int i = DP_ADJUST_REQUEST_LANE0_1 + (lane >> 1); 88 int s = ((lane & 1) ? 89 DP_ADJUST_VOLTAGE_SWING_LANE1_SHIFT : 90 DP_ADJUST_VOLTAGE_SWING_LANE0_SHIFT); 91 u8 l = dp_link_status(link_status, i); 92 93 return ((l >> s) & 0x3) << DP_TRAIN_VOLTAGE_SWING_SHIFT; 94 } 95 96 u8 drm_dp_get_adjust_request_pre_emphasis(u8 link_status[DP_LINK_STATUS_SIZE], 97 int lane) 98 { 99 int i = DP_ADJUST_REQUEST_LANE0_1 + (lane >> 1); 100 int s = ((lane & 1) ? 101 DP_ADJUST_PRE_EMPHASIS_LANE1_SHIFT : 102 DP_ADJUST_PRE_EMPHASIS_LANE0_SHIFT); 103 u8 l = dp_link_status(link_status, i); 104 105 return ((l >> s) & 0x3) << DP_TRAIN_PRE_EMPHASIS_SHIFT; 106 } 107 108 void drm_dp_link_train_clock_recovery_delay(u8 dpcd[DP_RECEIVER_CAP_SIZE]) { 109 if (dpcd[DP_TRAINING_AUX_RD_INTERVAL] == 0) 110 DRM_UDELAY(100); 111 else 112 DRM_MDELAY(dpcd[DP_TRAINING_AUX_RD_INTERVAL] * 4); 113 } 114 115 void drm_dp_link_train_channel_eq_delay(u8 dpcd[DP_RECEIVER_CAP_SIZE]) { 116 if (dpcd[DP_TRAINING_AUX_RD_INTERVAL] == 0) 117 DRM_UDELAY(400); 118 else 119 DRM_MDELAY(dpcd[DP_TRAINING_AUX_RD_INTERVAL] * 4); 120 } 121 122 u8 drm_dp_link_rate_to_bw_code(int link_rate) 123 { 124 switch (link_rate) { 125 case 162000: 126 default: 127 return DP_LINK_BW_1_62; 128 case 270000: 129 return DP_LINK_BW_2_7; 130 case 540000: 131 return DP_LINK_BW_5_4; 132 } 133 } 134 135 int drm_dp_bw_code_to_link_rate(u8 link_bw) 136 { 137 switch (link_bw) { 138 case DP_LINK_BW_1_62: 139 default: 140 return 162000; 141 case DP_LINK_BW_2_7: 142 return 270000; 143 case DP_LINK_BW_5_4: 144 return 540000; 145 } 146 } 147