Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

drm/dp: start a DPCD based DP sink/branch device quirk database

Face the fact, there are Display Port sink and branch devices out there
in the wild that don't follow the Display Port specifications, or they
have bugs, or just otherwise require special treatment. Start a common
quirk database the drivers can query based on the DP device
identification. At least for now, we leave the workarounds for the
drivers to implement as they see fit.

For starters, add a branch device that can't handle full 24-bit main
link Mdiv and Ndiv main link attributes properly. Naturally, the
workaround of reducing main link attributes for all devices ended up in
regressions for other devices. So here we are.

v2: Rebase on DRM DP desc read helpers

v3: Fix the OUI memcmp blunder (Clint)

Cc: Ville Syrjälä <ville.syrjala@linux.intel.com>
Cc: Dhinakaran Pandiyan <dhinakaran.pandiyan@intel.com>
Cc: Clint Taylor <clinton.a.taylor@intel.com>
Cc: Adam Jackson <ajax@redhat.com>
Cc: Harry Wentland <harry.wentland@amd.com>
Tested-by: Clinton Taylor <clinton.a.taylor@intel.com>
Reviewed-by: Clinton Taylor <clinton.a.taylor@intel.com>
Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch> # v2
Signed-off-by: Jani Nikula <jani.nikula@intel.com>
Link: http://patchwork.freedesktop.org/patch/msgid/91ec198dd95258dbf3bee2f6be739e0da73b4fdd.1495105635.git.jani.nikula@intel.com

+82 -2
+50 -2
drivers/gpu/drm/drm_dp_helper.c
··· 1209 1209 } 1210 1210 EXPORT_SYMBOL(drm_dp_stop_crc); 1211 1211 1212 + struct dpcd_quirk { 1213 + u8 oui[3]; 1214 + bool is_branch; 1215 + u32 quirks; 1216 + }; 1217 + 1218 + #define OUI(first, second, third) { (first), (second), (third) } 1219 + 1220 + static const struct dpcd_quirk dpcd_quirk_list[] = { 1221 + /* Analogix 7737 needs reduced M and N at HBR2 link rates */ 1222 + { OUI(0x00, 0x22, 0xb9), true, BIT(DP_DPCD_QUIRK_LIMITED_M_N) }, 1223 + }; 1224 + 1225 + #undef OUI 1226 + 1227 + /* 1228 + * Get a bit mask of DPCD quirks for the sink/branch device identified by 1229 + * ident. The quirk data is shared but it's up to the drivers to act on the 1230 + * data. 1231 + * 1232 + * For now, only the OUI (first three bytes) is used, but this may be extended 1233 + * to device identification string and hardware/firmware revisions later. 1234 + */ 1235 + static u32 1236 + drm_dp_get_quirks(const struct drm_dp_dpcd_ident *ident, bool is_branch) 1237 + { 1238 + const struct dpcd_quirk *quirk; 1239 + u32 quirks = 0; 1240 + int i; 1241 + 1242 + for (i = 0; i < ARRAY_SIZE(dpcd_quirk_list); i++) { 1243 + quirk = &dpcd_quirk_list[i]; 1244 + 1245 + if (quirk->is_branch != is_branch) 1246 + continue; 1247 + 1248 + if (memcmp(quirk->oui, ident->oui, sizeof(ident->oui)) != 0) 1249 + continue; 1250 + 1251 + quirks |= quirk->quirks; 1252 + } 1253 + 1254 + return quirks; 1255 + } 1256 + 1212 1257 /** 1213 1258 * drm_dp_read_desc - read sink/branch descriptor from DPCD 1214 1259 * @aux: DisplayPort AUX channel ··· 1276 1231 if (ret < 0) 1277 1232 return ret; 1278 1233 1234 + desc->quirks = drm_dp_get_quirks(ident, is_branch); 1235 + 1279 1236 dev_id_len = strnlen(ident->device_id, sizeof(ident->device_id)); 1280 1237 1281 - DRM_DEBUG_KMS("DP %s: OUI %*phD dev-ID %*pE HW-rev %d.%d SW-rev %d.%d\n", 1238 + DRM_DEBUG_KMS("DP %s: OUI %*phD dev-ID %*pE HW-rev %d.%d SW-rev %d.%d quirks 0x%04x\n", 1282 1239 is_branch ? "branch" : "sink", 1283 1240 (int)sizeof(ident->oui), ident->oui, 1284 1241 dev_id_len, ident->device_id, 1285 1242 ident->hw_rev >> 4, ident->hw_rev & 0xf, 1286 - ident->sw_major_rev, ident->sw_minor_rev); 1243 + ident->sw_major_rev, ident->sw_minor_rev, 1244 + desc->quirks); 1287 1245 1288 1246 return 0; 1289 1247 }
+32
include/drm/drm_dp_helper.h
··· 924 924 /** 925 925 * struct drm_dp_desc - DP branch/sink device descriptor 926 926 * @ident: DP device identification from DPCD 0x400 (sink) or 0x500 (branch). 927 + * @quirks: Quirks; use drm_dp_has_quirk() to query for the quirks. 927 928 */ 928 929 struct drm_dp_desc { 929 930 struct drm_dp_dpcd_ident ident; 931 + u32 quirks; 930 932 }; 931 933 932 934 int drm_dp_read_desc(struct drm_dp_aux *aux, struct drm_dp_desc *desc, 933 935 bool is_branch); 936 + 937 + /** 938 + * enum drm_dp_quirk - Display Port sink/branch device specific quirks 939 + * 940 + * Display Port sink and branch devices in the wild have a variety of bugs, try 941 + * to collect them here. The quirks are shared, but it's up to the drivers to 942 + * implement workarounds for them. 943 + */ 944 + enum drm_dp_quirk { 945 + /** 946 + * @DP_DPCD_QUIRK_LIMITED_M_N: 947 + * 948 + * The device requires main link attributes Mvid and Nvid to be limited 949 + * to 16 bits. 950 + */ 951 + DP_DPCD_QUIRK_LIMITED_M_N, 952 + }; 953 + 954 + /** 955 + * drm_dp_has_quirk() - does the DP device have a specific quirk 956 + * @desc: Device decriptor filled by drm_dp_read_desc() 957 + * @quirk: Quirk to query for 958 + * 959 + * Return true if DP device identified by @desc has @quirk. 960 + */ 961 + static inline bool 962 + drm_dp_has_quirk(const struct drm_dp_desc *desc, enum drm_dp_quirk quirk) 963 + { 964 + return desc->quirks & BIT(quirk); 965 + } 934 966 935 967 #endif /* _DRM_DP_HELPER_H_ */