From patchwork Mon Mar 27 10:28:11 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Abdiel Janulgue X-Patchwork-Id: 9646371 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id A8D46602C8 for ; Mon, 27 Mar 2017 10:29:33 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id B464D27D4A for ; Mon, 27 Mar 2017 10:29:33 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id A86302835B; Mon, 27 Mar 2017 10:29:33 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-4.2 required=2.0 tests=BAYES_00, RCVD_IN_DNSWL_MED autolearn=ham version=3.3.1 Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) (using TLSv1.2 with cipher DHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id 0B8AC27D4A for ; Mon, 27 Mar 2017 10:29:33 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 6C0956E1AD; Mon, 27 Mar 2017 10:29:32 +0000 (UTC) X-Original-To: intel-gfx@lists.freedesktop.org Delivered-To: intel-gfx@lists.freedesktop.org Received: from mga06.intel.com (mga06.intel.com [134.134.136.31]) by gabe.freedesktop.org (Postfix) with ESMTPS id 9DDA96E1AD for ; Mon, 27 Mar 2017 10:29:30 +0000 (UTC) Received: from fmsmga003.fm.intel.com ([10.253.24.29]) by orsmga104.jf.intel.com with ESMTP; 27 Mar 2017 03:29:30 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.36,231,1486454400"; d="scan'208";a="838848286" Received: from skylake-nuc.fi.intel.com ([10.237.72.145]) by FMSMGA003.fm.intel.com with ESMTP; 27 Mar 2017 03:29:28 -0700 From: Abdiel Janulgue To: intel-gfx@lists.freedesktop.org Date: Mon, 27 Mar 2017 13:28:11 +0300 Message-Id: <1490610492-18649-1-git-send-email-abdiel.janulgue@linux.intel.com> X-Mailer: git-send-email 2.7.4 Subject: [Intel-gfx] [i-g-t PATCH v4 1/2] lib/igt_kms: Add support for 4K and audio HDMI EDID injection. X-BeenThere: intel-gfx@lists.freedesktop.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: Intel graphics driver community testing & development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: intel-gfx-bounces@lists.freedesktop.org Sender: "Intel-gfx" X-Virus-Scanned: ClamAV using ClamSMTP Based on the initial work by Marius Vlad. v3: Bring back audio injection v4: Make a helper for 3d/4k/audio HDMI injection (Petri) Cc: Petri Latvala Signed-off-by: Abdiel Janulgue Reviewed-by: Petri Latvala --- lib/igt_kms.c | 230 +++++++++++++++++++++++++++++++++++++++++++--------------- lib/igt_kms.h | 2 + 2 files changed, 175 insertions(+), 57 deletions(-) diff --git a/lib/igt_kms.c b/lib/igt_kms.c index 5811414..9bfa0e1 100644 --- a/lib/igt_kms.c +++ b/lib/igt_kms.c @@ -83,7 +83,7 @@ static char *forced_connectors[MAX_CONNECTORS + 1]; static int forced_connectors_device[MAX_CONNECTORS + 1]; -static void update_edid_csum(unsigned char *edid) +static void update_edid_csum(unsigned char *edid, int cea_pos) { int i, sum = 0; struct tm *tm; @@ -96,9 +96,9 @@ static void update_edid_csum(unsigned char *edid) /* calculate checksum */ for (i = 0; i < 127; i++) { - sum = sum + edid[i]; + sum = sum + edid[cea_pos + i]; } - edid[127] = 256 - sum; + edid[cea_pos + 127] = 256 - sum; } #define VFREQ 60 @@ -136,7 +136,7 @@ static void update_edid_csum(unsigned char *edid) */ const unsigned char* igt_kms_get_base_edid(void) { - update_edid_csum(base_edid); + update_edid_csum(base_edid, 0); return base_edid; } @@ -306,7 +306,7 @@ igt_atomic_fill_pipe_props(igt_display_t *display, igt_pipe_t *pipe, */ const unsigned char* igt_kms_get_alt_edid(void) { - update_edid_csum(alt_edid); + update_edid_csum(alt_edid, 0); return alt_edid; } @@ -1116,6 +1116,59 @@ kmstest_get_property(int drm_fd, uint32_t object_id, uint32_t object_type, return found; } +struct edid_block { + int pos; + unsigned char *data; +}; + +#define DTD_SUPPORTS_AUDIO 1<<6 + +static struct edid_block +init_cea_block(const unsigned char *edid, size_t length, + unsigned char *new_edid_ptr[], size_t *new_length, + char extra_extensions_length, + uint32_t dtd_support) +{ + struct edid_block new_edid; + int n_extensions; + int pos; + static const char cea_header_len = 4, video_block_len = 6; + + igt_assert(new_edid_ptr != NULL && new_length != NULL); + + *new_length = length + 128; + + new_edid.data = calloc(*new_length, sizeof(char)); + igt_assert_f(new_edid.data, "Failed to allocate %zu bytes for edid\n", sizeof(new_length)); + memcpy(new_edid.data, edid, length); + *new_edid_ptr = new_edid.data; + + n_extensions = new_edid.data[126]; + n_extensions++; + new_edid.data[126] = n_extensions; + + update_edid_csum(new_edid.data, 0); + + /* add a cea-861 extension block */ + pos = length; + new_edid.data[pos++] = 0x2; + new_edid.data[pos++] = 0x3; + new_edid.data[pos++] = cea_header_len + video_block_len + + extra_extensions_length; + new_edid.data[pos++] = dtd_support; + + /* video block (id | length) */ + new_edid.data[pos++] = 2 << 5 | (video_block_len - 1); + new_edid.data[pos++] = 32 | 0x80; /* 1080p @ 24Hz | (native)*/ + new_edid.data[pos++] = 5; /* 1080i @ 60Hz */ + new_edid.data[pos++] = 20; /* 1080i @ 50Hz */ + new_edid.data[pos++] = 4; /* 720p @ 60Hz*/ + new_edid.data[pos++] = 19; /* 720p @ 50Hz*/ + new_edid.pos = pos; + + return new_edid; +} + /** * kmstest_edid_add_3d: * @edid: an existing valid edid block @@ -1129,72 +1182,135 @@ kmstest_get_property(int drm_fd, uint32_t object_id, uint32_t object_type, void kmstest_edid_add_3d(const unsigned char *edid, size_t length, unsigned char *new_edid_ptr[], size_t *new_length) { - unsigned char *new_edid; - int n_extensions; - char sum = 0; - int pos; - int i; - char cea_header_len = 4, video_block_len = 6, vsdb_block_len = 11; - - igt_assert(new_edid_ptr != NULL && new_length != NULL); + char vsdb_block_len = 11; + struct edid_block new_edid = init_cea_block(edid, length, new_edid_ptr, + new_length, vsdb_block_len, + 0); + int pos = new_edid.pos; - *new_length = length + 128; + /* vsdb block ( id | length ) */ + new_edid.data[pos++] = 3 << 5 | (vsdb_block_len - 1); + /* registration id */ + new_edid.data[pos++] = 0x3; + new_edid.data[pos++] = 0xc; + new_edid.data[pos++] = 0x0; + /* source physical address */ + new_edid.data[pos++] = 0x10; + new_edid.data[pos++] = 0x00; + /* Supports_AI ... etc */ + new_edid.data[pos++] = 0x00; + /* Max TMDS Clock */ + new_edid.data[pos++] = 0x00; + /* Latency present, HDMI Video Present */ + new_edid.data[pos++] = 0x20; + /* HDMI Video */ + new_edid.data[pos++] = 0x80; + new_edid.data[pos++] = 0x00; - new_edid = calloc(*new_length, sizeof(char)); - igt_assert_f(new_edid, "Failed to allocate %zu bytes for edid\n", sizeof(new_length)); - memcpy(new_edid, edid, length); - *new_edid_ptr = new_edid; + update_edid_csum(new_edid.data, length); +} - n_extensions = new_edid[126]; - n_extensions++; - new_edid[126] = n_extensions; +/** + * kmstest_edid_add_4k: + * @edid: an existing valid edid block + * @length: length of @edid + * @new_edid_ptr: pointer to where the new edid will be placed + * @new_length: pointer to the size of the new edid + * + * Makes a copy of an existing edid block and adds an extension indicating + * a HDMI 4K mode in vsdb. + */ +void kmstest_edid_add_4k(const unsigned char *edid, size_t length, + unsigned char *new_edid_ptr[], size_t *new_length) +{ + char vsdb_block_len = 12; + struct edid_block new_edid = init_cea_block(edid, length, new_edid_ptr, + new_length, vsdb_block_len, + 0); + int pos = new_edid.pos; - /* recompute checksum */ - for (i = 0; i < 127; i++) { - sum = sum + new_edid[i]; - } - new_edid[127] = 256 - sum; + /* vsdb block ( id | length ) */ + new_edid.data[pos++] = 3 << 5 | (vsdb_block_len - 1); + /* registration id */ + new_edid.data[pos++] = 0x3; + new_edid.data[pos++] = 0xc; + new_edid.data[pos++] = 0x0; + /* source physical address */ + new_edid.data[pos++] = 0x10; + new_edid.data[pos++] = 0x00; + /* Supports_AI ... etc */ + new_edid.data[pos++] = 0x00; + /* Max TMDS Clock */ + new_edid.data[pos++] = 0x00; + /* Latency present, HDMI Video Present */ + new_edid.data[pos++] = 0x20; + /* HDMI Video */ + new_edid.data[pos++] = 0x00; /* 3D present */ - /* add a cea-861 extension block */ - pos = length; - new_edid[pos++] = 0x2; - new_edid[pos++] = 0x3; - new_edid[pos++] = cea_header_len + video_block_len + vsdb_block_len; - new_edid[pos++] = 0x0; + /* HDMI MODE LEN -- how many entries */ + new_edid.data[pos++] = 0x20; + /* 2160p, specified as short descriptor */ + new_edid.data[pos++] = 0x01; - /* video block (id | length) */ - new_edid[pos++] = 2 << 5 | (video_block_len - 1); - new_edid[pos++] = 32 | 0x80; /* 1080p @ 24Hz | (native)*/ - new_edid[pos++] = 5; /* 1080i @ 60Hz */ - new_edid[pos++] = 20; /* 1080i @ 50Hz */ - new_edid[pos++] = 4; /* 720p @ 60Hz*/ - new_edid[pos++] = 19; /* 720p @ 50Hz*/ + update_edid_csum(new_edid.data, length); +} - /* vsdb block ( id | length ) */ - new_edid[pos++] = 3 << 5 | (vsdb_block_len - 1); +/** + * kmstest_edid_add_audio: + * @edid: an existing valid edid block + * @length: length of @edid + * @new_edid_ptr: pointer to where the new edid will be placed + * @new_length: pointer to the size of the new edid + * + * Makes a copy of an existing edid block and adds an extension indicating + * basic audio support and speaker data block. + * + */ +void kmstest_edid_add_audio(const unsigned char *edid, size_t length, + unsigned char *new_edid_ptr[], size_t *new_length) +{ + char vsdb_block_len = 10, audio_block_len = 4, spkr_block_len = 4; + struct edid_block new_edid = init_cea_block(edid, length, new_edid_ptr, + new_length, + vsdb_block_len + + audio_block_len + + spkr_block_len, + DTD_SUPPORTS_AUDIO); + int pos = new_edid.pos; + + /* audio block, short audio block descriptors */ + new_edid.data[pos++] = (1 << 5) | (audio_block_len - 1); + new_edid.data[pos++] = 0x09; /* Audio Format, PCM */ + new_edid.data[pos++] = 0x07; /* Frequency, 32, 44.1, 48kHz */ + new_edid.data[pos++] = 0x07; /* Bit Rate 16, 20, 24 bit */ + + + /* vsdb block ( id | length ) -- need vsdb as well + * otherwise the kernel will fallback to lower clock modes */ + new_edid.data[pos++] = 3 << 5 | (vsdb_block_len - 1); /* registration id */ - new_edid[pos++] = 0x3; - new_edid[pos++] = 0xc; - new_edid[pos++] = 0x0; + new_edid.data[pos++] = 0x3; + new_edid.data[pos++] = 0xc; + new_edid.data[pos++] = 0x0; /* source physical address */ - new_edid[pos++] = 0x10; - new_edid[pos++] = 0x00; + new_edid.data[pos++] = 0x10; + new_edid.data[pos++] = 0x00; /* Supports_AI ... etc */ - new_edid[pos++] = 0x00; + new_edid.data[pos++] = 0x00; /* Max TMDS Clock */ - new_edid[pos++] = 0x00; + new_edid.data[pos++] = 0x00; /* Latency present, HDMI Video Present */ - new_edid[pos++] = 0x20; + new_edid.data[pos++] = 0x20; /* HDMI Video */ - new_edid[pos++] = 0x80; - new_edid[pos++] = 0x00; + new_edid.data[pos++] = 0x00; /* 3D present */ - /* checksum */ - sum = 0; - for (i = 0; i < 127; i++) { - sum = sum + new_edid[length + i]; - } - new_edid[length + 127] = 256 - sum; + /* speaker data block */ + new_edid.data[pos++] = (4 << 5) | (spkr_block_len - 1); + new_edid.data[pos++] = (1 << 5); + new_edid.data[pos++] = 0x00; + new_edid.data[pos++] = 0x00; + + update_edid_csum(new_edid.data, length); } /** diff --git a/lib/igt_kms.h b/lib/igt_kms.h index 595832d..9567a26 100644 --- a/lib/igt_kms.h +++ b/lib/igt_kms.h @@ -184,6 +184,8 @@ enum kmstest_broadcast_rgb_mode { bool kmstest_force_connector(int fd, drmModeConnector *connector, enum kmstest_force_connector_state state); void kmstest_edid_add_3d(const unsigned char *edid, size_t length, unsigned char *new_edid_ptr[], size_t *new_length); +void kmstest_edid_add_4k(const unsigned char *edid, size_t length, unsigned char *new_edid_ptr[], size_t *new_length); +void kmstest_edid_add_audio(const unsigned char *edid, size_t length, unsigned char *new_edid_ptr[], size_t *new_length); void kmstest_force_edid(int drm_fd, drmModeConnector *connector, const unsigned char *edid, size_t length);