aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndres Rodriguez <andresx7@gmail.com>2019-06-19 14:09:01 -0400
committerDave Airlie <airlied@redhat.com>2019-06-25 00:32:26 -0400
commite28ad544f462231d3fd081a7316339359efbb481 (patch)
tree4e5a91bdb0e5f27cd4904f6c4918210449d33e6c
parentdfd03396d7b66f90071aa5e8fdc0f3c4a66471c5 (diff)
drm/edid: parse CEA blocks embedded in DisplayID
DisplayID blocks allow embedding of CEA blocks. The payloads are identical to traditional top level CEA extension blocks, but the header is slightly different. This change allows the CEA parser to find a CEA block inside a DisplayID block. Additionally, it adds support for parsing the embedded CTA header. No further changes are necessary due to payload parity. This change fixes audio support for the Valve Index HMD. Signed-off-by: Andres Rodriguez <andresx7@gmail.com> Reviewed-by: Dave Airlie <airlied@redhat.com> Cc: Jani Nikula <jani.nikula@linux.intel.com> Cc: <stable@vger.kernel.org> # v4.15 Signed-off-by: Dave Airlie <airlied@redhat.com> Link: https://patchwork.freedesktop.org/patch/msgid/20190619180901.17901-1-andresx7@gmail.com
-rw-r--r--drivers/gpu/drm/drm_edid.c81
-rw-r--r--include/drm/drm_displayid.h10
2 files changed, 80 insertions, 11 deletions
diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c
index 9d8f2b952004..df635afe41b7 100644
--- a/drivers/gpu/drm/drm_edid.c
+++ b/drivers/gpu/drm/drm_edid.c
@@ -1342,6 +1342,7 @@ MODULE_PARM_DESC(edid_fixup,
1342 1342
1343static void drm_get_displayid(struct drm_connector *connector, 1343static void drm_get_displayid(struct drm_connector *connector,
1344 struct edid *edid); 1344 struct edid *edid);
1345static int validate_displayid(u8 *displayid, int length, int idx);
1345 1346
1346static int drm_edid_block_checksum(const u8 *raw_edid) 1347static int drm_edid_block_checksum(const u8 *raw_edid)
1347{ 1348{
@@ -2926,16 +2927,46 @@ static u8 *drm_find_edid_extension(const struct edid *edid, int ext_id)
2926 return edid_ext; 2927 return edid_ext;
2927} 2928}
2928 2929
2929static u8 *drm_find_cea_extension(const struct edid *edid)
2930{
2931 return drm_find_edid_extension(edid, CEA_EXT);
2932}
2933 2930
2934static u8 *drm_find_displayid_extension(const struct edid *edid) 2931static u8 *drm_find_displayid_extension(const struct edid *edid)
2935{ 2932{
2936 return drm_find_edid_extension(edid, DISPLAYID_EXT); 2933 return drm_find_edid_extension(edid, DISPLAYID_EXT);
2937} 2934}
2938 2935
2936static u8 *drm_find_cea_extension(const struct edid *edid)
2937{
2938 int ret;
2939 int idx = 1;
2940 int length = EDID_LENGTH;
2941 struct displayid_block *block;
2942 u8 *cea;
2943 u8 *displayid;
2944
2945 /* Look for a top level CEA extension block */
2946 cea = drm_find_edid_extension(edid, CEA_EXT);
2947 if (cea)
2948 return cea;
2949
2950 /* CEA blocks can also be found embedded in a DisplayID block */
2951 displayid = drm_find_displayid_extension(edid);
2952 if (!displayid)
2953 return NULL;
2954
2955 ret = validate_displayid(displayid, length, idx);
2956 if (ret)
2957 return NULL;
2958
2959 idx += sizeof(struct displayid_hdr);
2960 for_each_displayid_db(displayid, block, idx, length) {
2961 if (block->tag == DATA_BLOCK_CTA) {
2962 cea = (u8 *)block;
2963 break;
2964 }
2965 }
2966
2967 return cea;
2968}
2969
2939/* 2970/*
2940 * Calculate the alternate clock for the CEA mode 2971 * Calculate the alternate clock for the CEA mode
2941 * (60Hz vs. 59.94Hz etc.) 2972 * (60Hz vs. 59.94Hz etc.)
@@ -3659,13 +3690,38 @@ cea_revision(const u8 *cea)
3659static int 3690static int
3660cea_db_offsets(const u8 *cea, int *start, int *end) 3691cea_db_offsets(const u8 *cea, int *start, int *end)
3661{ 3692{
3662 /* Data block offset in CEA extension block */ 3693 /* DisplayID CTA extension blocks and top-level CEA EDID
3663 *start = 4; 3694 * block header definitions differ in the following bytes:
3664 *end = cea[2]; 3695 * 1) Byte 2 of the header specifies length differently,
3665 if (*end == 0) 3696 * 2) Byte 3 is only present in the CEA top level block.
3666 *end = 127; 3697 *
3667 if (*end < 4 || *end > 127) 3698 * The different definitions for byte 2 follow.
3668 return -ERANGE; 3699 *
3700 * DisplayID CTA extension block defines byte 2 as:
3701 * Number of payload bytes
3702 *
3703 * CEA EDID block defines byte 2 as:
3704 * Byte number (decimal) within this block where the 18-byte
3705 * DTDs begin. If no non-DTD data is present in this extension
3706 * block, the value should be set to 04h (the byte after next).
3707 * If set to 00h, there are no DTDs present in this block and
3708 * no non-DTD data.
3709 */
3710 if (cea[0] == DATA_BLOCK_CTA) {
3711 *start = 3;
3712 *end = *start + cea[2];
3713 } else if (cea[0] == CEA_EXT) {
3714 /* Data block offset in CEA extension block */
3715 *start = 4;
3716 *end = cea[2];
3717 if (*end == 0)
3718 *end = 127;
3719 if (*end < 4 || *end > 127)
3720 return -ERANGE;
3721 } else {
3722 return -ENOTSUPP;
3723 }
3724
3669 return 0; 3725 return 0;
3670} 3726}
3671 3727
@@ -5406,6 +5462,9 @@ static int drm_parse_display_id(struct drm_connector *connector,
5406 case DATA_BLOCK_TYPE_1_DETAILED_TIMING: 5462 case DATA_BLOCK_TYPE_1_DETAILED_TIMING:
5407 /* handled in mode gathering code. */ 5463 /* handled in mode gathering code. */
5408 break; 5464 break;
5465 case DATA_BLOCK_CTA:
5466 /* handled in the cea parser code. */
5467 break;
5409 default: 5468 default:
5410 DRM_DEBUG_KMS("found DisplayID tag 0x%x, unhandled\n", block->tag); 5469 DRM_DEBUG_KMS("found DisplayID tag 0x%x, unhandled\n", block->tag);
5411 break; 5470 break;
diff --git a/include/drm/drm_displayid.h b/include/drm/drm_displayid.h
index c0d4df6a606f..9d3b745c3107 100644
--- a/include/drm/drm_displayid.h
+++ b/include/drm/drm_displayid.h
@@ -40,6 +40,7 @@
40#define DATA_BLOCK_DISPLAY_INTERFACE 0x0f 40#define DATA_BLOCK_DISPLAY_INTERFACE 0x0f
41#define DATA_BLOCK_STEREO_DISPLAY_INTERFACE 0x10 41#define DATA_BLOCK_STEREO_DISPLAY_INTERFACE 0x10
42#define DATA_BLOCK_TILED_DISPLAY 0x12 42#define DATA_BLOCK_TILED_DISPLAY 0x12
43#define DATA_BLOCK_CTA 0x81
43 44
44#define DATA_BLOCK_VENDOR_SPECIFIC 0x7f 45#define DATA_BLOCK_VENDOR_SPECIFIC 0x7f
45 46
@@ -90,4 +91,13 @@ struct displayid_detailed_timing_block {
90 struct displayid_block base; 91 struct displayid_block base;
91 struct displayid_detailed_timings_1 timings[0]; 92 struct displayid_detailed_timings_1 timings[0];
92}; 93};
94
95#define for_each_displayid_db(displayid, block, idx, length) \
96 for ((block) = (struct displayid_block *)&(displayid)[idx]; \
97 (idx) + sizeof(struct displayid_block) <= (length) && \
98 (idx) + sizeof(struct displayid_block) + (block)->num_bytes <= (length) && \
99 (block)->num_bytes > 0; \
100 (idx) += (block)->num_bytes + sizeof(struct displayid_block), \
101 (block) = (struct displayid_block *)&(displayid)[idx])
102
93#endif 103#endif