[PATCH] drm/edid: parse CEA blocks embedded in DisplayID
Jani Nikula
jani.nikula at linux.intel.com
Thu Jun 13 09:16:51 UTC 2019
On Wed, 12 Jun 2019, Andres Rodriguez <andresx7 at gmail.com> wrote:
> 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 enables audio support for the Valve Index HMD.
>
> Signed-off-by: Andres Rodriguez <andresx7 at gmail.com>
> ---
> drivers/gpu/drm/drm_edid.c | 79 +++++++++++++++++++++++++++++++++----
> include/drm/drm_displayid.h | 1 +
> 2 files changed, 72 insertions(+), 8 deletions(-)
>
> diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c
> index 649cfd8b4200..3e71c6ae48d4 100644
> --- a/drivers/gpu/drm/drm_edid.c
> +++ b/drivers/gpu/drm/drm_edid.c
> @@ -1339,6 +1339,8 @@ MODULE_PARM_DESC(edid_fixup,
>
> static void drm_get_displayid(struct drm_connector *connector,
> struct edid *edid);
> +static u8 *drm_find_displayid_extension(const struct edid *edid);
> +static int validate_displayid(u8 *displayid, int length, int idx);
>
> static int drm_edid_block_checksum(const u8 *raw_edid)
> {
> @@ -2885,7 +2887,40 @@ static u8 *drm_find_edid_extension(const struct edid *edid, int ext_id)
>
> static u8 *drm_find_cea_extension(const struct edid *edid)
> {
> - return drm_find_edid_extension(edid, CEA_EXT);
> + int ret;
> + int idx = 1;
> + int length = EDID_LENGTH;
> + struct displayid_block *block;
> + u8 *cea = NULL;
> + u8 *displayid = NULL;
Unnecessary initializations.
> +
> + cea = drm_find_edid_extension(edid, CEA_EXT);
> +
> + /* CEA blocks can also be found embedded in a DisplayID block */
> + if (!cea) {
It's customary to return early to reduce indent on the following code,
i.e.
if (cea)
return cea;
> + displayid = drm_find_displayid_extension(edid);
> + if (!displayid)
> + return NULL;
> +
> + ret = validate_displayid(displayid, length, idx);
> + if (ret)
> + return NULL;
> +
> + idx += sizeof(struct displayid_hdr);
> + while (block = (struct displayid_block *)&displayid[idx],
> + idx + sizeof(struct displayid_block) <= length &&
> + idx + sizeof(struct displayid_block) + block->num_bytes <= length &&
> + block->num_bytes > 0) {
I'm sure there's a for loop in there somewhere desperate to get out. The
above is unnecessarily tricky.
> + idx += block->num_bytes + sizeof(struct displayid_block);
> + switch (block->tag) {
> + case DATA_BLOCK_CTA:
> + cea = (u8 *)block;
> + break;
> + }
Looks like an if statement here. Why do you continue the while loop
after you've found the block?
BR,
Jani.
> + }
> + }
> +
> + return cea;
> }
>
> static u8 *drm_find_displayid_extension(const struct edid *edid)
> @@ -3616,13 +3651,38 @@ cea_revision(const u8 *cea)
> static int
> cea_db_offsets(const u8 *cea, int *start, int *end)
> {
> - /* Data block offset in CEA extension block */
> - *start = 4;
> - *end = cea[2];
> - if (*end == 0)
> - *end = 127;
> - if (*end < 4 || *end > 127)
> - return -ERANGE;
> +
> + /* DisplayID CTA extension blocks and top-level CEA EDID
> + * blocks headers differ in two byte definitions:
> + * 1) Byte 2 of the header specifies length differently,
> + * 2) Byte 3 is only present in the CEA top level block.
> + *
> + * The different definitions for byte 2 follow.
> + *
> + * DisplayID CTA extension block defines byte 2 as:
> + * Number of payload bytes
> + *
> + * CEA EDID block defines byte 2 as:
> + * Byte number (decimal) within this block where the 18-byte
> + * DTDs begin. If no non-DTD data is present in this extension
> + * block, the value should be set to 04h (the byte after next).
> + * If set to 00h, there are no DTDs present in this block and
> + * no non-DTD data.
> + */
> + if (cea[0] == DATA_BLOCK_CTA) {
> + *start = 3;
> + *end = *start + cea[2];
> + } else if (cea[0] == CEA_EXT) {
> + *start = 4;
> + *end = cea[2];
> + /* Data block offset in CEA extension block */
> + if (*end == 0)
> + *end = 127;
> + if (*end < 4 || *end > 127)
> + return -ERANGE;
> + } else
> + return -ENOTSUPP;
> +
> return 0;
> }
>
> @@ -5240,6 +5300,9 @@ static int drm_parse_display_id(struct drm_connector *connector,
> case DATA_BLOCK_TYPE_1_DETAILED_TIMING:
> /* handled in mode gathering code. */
> break;
> + case DATA_BLOCK_CTA:
> + /* handled in the cea parser code. */
> + break;
> default:
> DRM_DEBUG_KMS("found DisplayID tag 0x%x, unhandled\n", block->tag);
> break;
> diff --git a/include/drm/drm_displayid.h b/include/drm/drm_displayid.h
> index c0d4df6a606f..c7af857f4764 100644
> --- a/include/drm/drm_displayid.h
> +++ b/include/drm/drm_displayid.h
> @@ -40,6 +40,7 @@
> #define DATA_BLOCK_DISPLAY_INTERFACE 0x0f
> #define DATA_BLOCK_STEREO_DISPLAY_INTERFACE 0x10
> #define DATA_BLOCK_TILED_DISPLAY 0x12
> +#define DATA_BLOCK_CTA 0x81
>
> #define DATA_BLOCK_VENDOR_SPECIFIC 0x7f
--
Jani Nikula, Intel Open Source Graphics Center
More information about the dri-devel
mailing list