From patchwork Wed Feb 12 05:05:54 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Egor Vorontsov X-Patchwork-Id: 13971245 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 266F8C02198 for ; Wed, 12 Feb 2025 06:43:03 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 9D12D10E7B8; Wed, 12 Feb 2025 06:43:02 +0000 (UTC) Authentication-Results: gabe.freedesktop.org; dkim=pass (1024-bit key; unprotected) header.d=sdore.me header.i=@sdore.me header.b="bvkhKi2I"; dkim-atps=neutral Received: from sdore.me (unknown [95.165.1.78]) by gabe.freedesktop.org (Postfix) with ESMTPS id 17AEC10E7A9 for ; Wed, 12 Feb 2025 05:05:56 +0000 (UTC) Received: from [192.168.1.2] (beast.lan [192.168.1.2]) by sdore.me (Postfix) with ESMTPSA id 80C11EE79A0C6; Wed, 12 Feb 2025 08:05:54 +0300 (MSK) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=sdore.me; s=SERV; t=1739336754; bh=jBow0XBFS4NkVA2SAiZo353ClhCTYHuSKNX+QguRRms=; h=Subject:From:Reply-To:To:Cc:Date; b=bvkhKi2IDfgS1+SaLEqoNVl59MlZOPT/q5z0Kj0o9cVMWKkKIXwSUMOrGBkYJ3eEr /iQc0SfkeUrPvJZdtTPhP/yTMClS6yaK/Gqzkj+WMP045CYYMTbGVSL6LMU9rvdqkK v69X6HM3CwOVyy9W3gSAPiu1XMQJcoCa6A+IP4tw= Message-ID: <7cab8349bc8bb6fa08d2a7127a724efea155f154.camel@sdore.me> Subject: [PATCH v2] drm/edid: Implement DisplayID Type IX & X timing blocks parsing From: Egor Vorontsov To: linux-kernel@vger.kernel.org Cc: dri-devel@lists.freedesktop.org, Maarten Lankhorst , Maxime Ripard , Thomas Zimmermann , Jani Nikula , Egor Vorontsov Date: Wed, 12 Feb 2025 08:05:54 +0300 Autocrypt: addr=sdoregor@sdore.me; prefer-encrypt=mutual; keydata=mQINBGDSFnMBEADfvtLiuRL6CHdMzETKrux7sNHWG+eJ2+pgRZ3Nc9pH/YWqjoed8OpFx OLeUxr9YSQ3uMD//JEe3+Sgte29Z3PAAHVkCwKBIucCnhHpXbcQZgC9xYMCd6GWR5+DpXN9szOIyb kvnEtuqTddz6Q7fYsaFDs0pH3jUUWmSAyCn2JCIRfT22XgO44B/yoqnM3JXHAayeHbEAQOzMe81q3 deauI9W7SC9ScRT6VkgLuc+SxqH99el/OkiKTe/QpO6I6cVS8leesqnOGffkRPos/o2eRonqgDu0e Mw4YTu0x5iNr8Lbr4TefU2W1l6M3MNwOsLmI+58+3fK1vh0QqZ70NC4eyD9UEXk3mJyV7epfNU6fY 0mFJbAhGV1TXomcy2MlOD1rDixw85zdK5uUwp0tfEkpxqKtihJmrTdApOTTVed303CLzgDsMokTIe aUOPqVZoWFDkvOzq6IppBkApJHBf1lcLlgwEn3cLQlGpYRSSi5NY3+UYtcOEZLDbF3TO6ncY8W2h3 yQH/sAcSllfKKvkhdqEz4/Mha3GbZQXWgjrLy9BcISsQFj+DBN54I6a6kLm2n5wXH99sOp7s3jMeN zSU6PtuxZq4Gkt2K5JGT8yrIdfJfOH7yRUVm+8JqKNKqd6oczlDKV+lzRk9M/kjb8VQivaNSNwTo9 3NxEuft0+tZgwARAQABtCJFZ29yIFZvcm9udHNvdiA8c2RvcmVnb3JAc2RvcmUubWU+iQJOBBMBCA A4FiEEXlTCjXwaPBiJP3U33a9iH2xv60MFAmDSFnMCGwMFCwkIBwIGFQoJCAsCBBYCAwECHgECF4A ACgkQ3a9iH2xv60OquRAAgbgenXi+Ud0tYoAz6giuFKYqzuEYuoSVkjxYvZq90ODrzbu7EdvMVuKA qNqYjs3VRBPBMHXhJKEftKbX4bZwCoC2o2wB5oV5O13jVN083r49FTLCxmOoufCkaqscBBxi/X2T6 +i0n5Nqx5NLBL0kE4NMTk1jxEEyuEjv7bBMs196G/d3EpNJT3YGkLXBUibpaSaVjE6zBr3UygieLD 2QXNkRJubx2d0FoD8TezSt5hsHWg9FOElsW6ZImRI+5q+ptL39K3cpjxHMKyhmo7xypD5XNWdmsmV 1+STnK7R+id18xs7JUDxHBtG7Z/3K6txgF5CPbPvtaEi9fB3K/uS03BnIzsY2/cY3r9UHHrHa/sP6 DhDwj9dr2xIFG5w6ZNh4mUTHEJoWKEEsYKwXy2eJCB3XvP7GURAm8fXdIapONbHDYj7XX49Mj+LBr s4PNBuKaZTFgGQ6RSc7LpAR56xaEDR93m7zNy84mQtpab/owaox1A+BEujzKK/vEDvj9f8EWlWZRa DH2auNNAxdr2ACR8RzkojcFDCErAgc5sFQrgVUlvNmMdn3VL0CWmndzEQxsOdgVk9SwoHHYpHf4Cg gtchq3pTQ5XSRaP/wxOtQpzqJWq5uFERBTLU8WRXYv3mM3KMdvtTJadF8+P+KSSnn+/yHahR0HKVx PtHSH7Px/vI= User-Agent: Evolution 3.54.2 MIME-Version: 1.0 X-Mailman-Approved-At: Wed, 12 Feb 2025 06:42:53 +0000 X-BeenThere: dri-devel@lists.freedesktop.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Direct Rendering Infrastructure - Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-To: sdoregor@sdore.me Errors-To: dri-devel-bounces@lists.freedesktop.org Sender: "dri-devel" Some newer high refresh rate consumer monitors (including those by Samsung) make use of DisplayID 2.1 timing blocks in their EDID data, notably for their highest refresh rate modes. Such modes won't be available as of now. Implement partial support for such blocks in order to enable native support of HRR modes of most such monitors for users without having to rely on EDID patching/override (or need thereof). Closes: https://gitlab.freedesktop.org/drm/misc/kernel/-/issues/55 Suggested-by: Maximilian Boße Signed-off-by: Egor Vorontsov Reviewed-by: Jani Nikula --- drivers/gpu/drm/drm_displayid_internal.h | 13 +++++ drivers/gpu/drm/drm_edid.c | 63 ++++++++++++++++++++++++ 2 files changed, 76 insertions(+) diff --git a/drivers/gpu/drm/drm_displayid_internal.h b/drivers/gpu/drm/drm_displayid_internal.h index aee1b86a73c1..88220c107822 100644 --- a/drivers/gpu/drm/drm_displayid_internal.h +++ b/drivers/gpu/drm/drm_displayid_internal.h @@ -66,6 +66,7 @@ struct drm_edid; #define DATA_BLOCK_2_STEREO_DISPLAY_INTERFACE 0x27 #define DATA_BLOCK_2_TILED_DISPLAY_TOPOLOGY 0x28 #define DATA_BLOCK_2_CONTAINER_ID 0x29 +#define DATA_BLOCK_2_TYPE_10_FORMULA_TIMING 0x2a #define DATA_BLOCK_2_VENDOR_SPECIFIC 0x7e #define DATA_BLOCK_2_CTA_DISPLAY_ID 0x81 @@ -129,6 +130,18 @@ struct displayid_detailed_timing_block { struct displayid_detailed_timings_1 timings[]; }; +struct displayid_formula_timings_9 { + u8 flags; + __be16 hactive; + __be16 vactive; + u8 vrefresh; +} __packed; + +struct displayid_formula_timing_block { + struct displayid_block base; + struct displayid_formula_timings_9 timings[]; +} __packed; + #define DISPLAYID_VESA_MSO_OVERLAP GENMASK(3, 0) #define DISPLAYID_VESA_MSO_MODE GENMASK(6, 5) diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index 13bc4c290b17..9c363df5af9a 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -6833,6 +6833,66 @@ static int add_displayid_detailed_1_modes(struct drm_connector *connector, return num_modes; } +static struct drm_display_mode *drm_mode_displayid_formula(struct drm_device *dev, + const struct displayid_formula_timings_9 *timings, + bool type_10) +{ + struct drm_display_mode *mode; + u16 hactive = be16_to_cpu(timings->hactive) + 1; + u16 vactive = be16_to_cpu(timings->vactive) + 1; + u8 timing_formula = timings->flags & 0x7; + + /* TODO: support RB-v2 & RB-v3 */ + if (timing_formula > 1) + return NULL; + + /* TODO: support video-optimized refresh rate */ + if (timings->flags & (1 << 4)) + return NULL; + + mode = drm_cvt_mode(dev, hactive, vactive, timings->vrefresh + 1, timing_formula == 1, false, false); + if (!mode) + return NULL; + + /* TODO: interpret S3D flags */ + + mode->type = DRM_MODE_TYPE_DRIVER; + drm_mode_set_name(mode); + + return mode; +} + +static int add_displayid_formula_modes(struct drm_connector *connector, + const struct displayid_block *block) +{ + const struct displayid_formula_timing_block *formula_block = (struct displayid_formula_timing_block *)block; + int num_timings; + struct drm_display_mode *newmode; + int num_modes = 0; + bool type_10 = block->tag == DATA_BLOCK_2_TYPE_10_FORMULA_TIMING; + int timing_size = 6 + ((formula_block->base.rev & 0x70) >> 4); + + /* extended blocks are not supported yet */ + if (timing_size != 6) + return 0; + + if (block->num_bytes % timing_size) + return 0; + + num_timings = block->num_bytes / timing_size; + for (int i = 0; i < num_timings; i++) { + const struct displayid_formula_timings_9 *timings = &formula_block->timings[i]; + + newmode = drm_mode_displayid_formula(connector->dev, timings, type_10); + if (!newmode) + continue; + + drm_mode_probed_add(connector, newmode); + num_modes++; + } + return num_modes; +} + static int add_displayid_detailed_modes(struct drm_connector *connector, const struct drm_edid *drm_edid) { @@ -6845,6 +6905,9 @@ static int add_displayid_detailed_modes(struct drm_connector *connector, if (block->tag == DATA_BLOCK_TYPE_1_DETAILED_TIMING || block->tag == DATA_BLOCK_2_TYPE_7_DETAILED_TIMING) num_modes += add_displayid_detailed_1_modes(connector, block); + else if (block->tag == DATA_BLOCK_2_TYPE_9_FORMULA_TIMING || + block->tag == DATA_BLOCK_2_TYPE_10_FORMULA_TIMING) + num_modes += add_displayid_formula_modes(connector, block); } displayid_iter_end(&iter); From patchwork Fri Feb 14 01:05:45 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Egor Vorontsov X-Patchwork-Id: 13974263 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id CC344C021A0 for ; Fri, 14 Feb 2025 01:14:40 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 3DD3B10E078; Fri, 14 Feb 2025 01:14:40 +0000 (UTC) Authentication-Results: gabe.freedesktop.org; dkim=pass (1024-bit key; unprotected) header.d=sdore.me header.i=@sdore.me header.b="aneva66j"; dkim-atps=neutral X-Greylist: delayed 468 seconds by postgrey-1.36 at gabe; Fri, 14 Feb 2025 01:14:39 UTC Received: from sdore.me (unknown [95.165.1.78]) by gabe.freedesktop.org (Postfix) with ESMTPS id 0E81410E078 for ; Fri, 14 Feb 2025 01:14:39 +0000 (UTC) Received: by sdore.me (Postfix, from userid 1000) id 07ED8EE8796B7; Fri, 14 Feb 2025 04:06:46 +0300 (MSK) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=sdore.me; s=SERV; t=1739495206; bh=oZ8NyCjs7z+25+3ZAPDoEXaqLtn+ZFW9ddncRWyxRQw=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=aneva66j9xj4E1eEGIqoEZzyLw1Ylx0+fVPECiK/hqyJ9EHvVJSkzjRXRbn4rT8Vp R0/qcHitIWllWMtFbb4C0Sq+Wdmmd1wDTkA3V7//INUPKZXuLdypPDbw6sXX+OiDcD OTX/b73AJIzDDeFks5irfVt9KU7oJaOSmBDdwieU= From: Egor Vorontsov To: linux-kernel@vger.kernel.org Cc: dri-devel@lists.freedesktop.org, Maarten Lankhorst , Maxime Ripard , Thomas Zimmermann , Jani Nikula , Egor Vorontsov Subject: [PATCH v2 2/2] drm/edid: Refactor DisplayID timing block structs Date: Fri, 14 Feb 2025 04:05:45 +0300 Message-ID: <20250214010545.3793736-1-sdoregor@sdore.me> X-Mailer: git-send-email 2.48.0 In-Reply-To: <7cab8349bc8bb6fa08d2a7127a724efea155f154.camel@sdore.me> References: <7cab8349bc8bb6fa08d2a7127a724efea155f154.camel@sdore.me> MIME-Version: 1.0 X-BeenThere: dri-devel@lists.freedesktop.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Direct Rendering Infrastructure - Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dri-devel-bounces@lists.freedesktop.org Sender: "dri-devel" Using le16 instead of u8[2]. Replaced an error with a printed warning as well. Suggested-by: Jani Nikula Signed-off-by: Egor Vorontsov --- drivers/gpu/drm/drm_displayid_internal.h | 22 ++++++++-------- drivers/gpu/drm/drm_edid.c | 32 ++++++++++++------------ 2 files changed, 27 insertions(+), 27 deletions(-) diff --git a/drivers/gpu/drm/drm_displayid_internal.h b/drivers/gpu/drm/drm_displayid_internal.h index 88220c107822..957dd0619f5c 100644 --- a/drivers/gpu/drm/drm_displayid_internal.h +++ b/drivers/gpu/drm/drm_displayid_internal.h @@ -115,25 +115,25 @@ struct displayid_tiled_block { struct displayid_detailed_timings_1 { u8 pixel_clock[3]; u8 flags; - u8 hactive[2]; - u8 hblank[2]; - u8 hsync[2]; - u8 hsw[2]; - u8 vactive[2]; - u8 vblank[2]; - u8 vsync[2]; - u8 vsw[2]; + __le16 hactive; + __le16 hblank; + __le16 hsync; + __le16 hsw; + __le16 vactive; + __le16 vblank; + __le16 vsync; + __le16 vsw; } __packed; struct displayid_detailed_timing_block { struct displayid_block base; struct displayid_detailed_timings_1 timings[]; -}; +} __packed; struct displayid_formula_timings_9 { u8 flags; - __be16 hactive; - __be16 vactive; + __le16 hactive; + __le16 vactive; u8 vrefresh; } __packed; diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index 9c363df5af9a..54122a12a24f 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -6764,19 +6764,19 @@ static struct drm_display_mode *drm_mode_displayid_detailed(struct drm_device *d bool type_7) { struct drm_display_mode *mode; - unsigned pixel_clock = (timings->pixel_clock[0] | - (timings->pixel_clock[1] << 8) | - (timings->pixel_clock[2] << 16)) + 1; - unsigned hactive = (timings->hactive[0] | timings->hactive[1] << 8) + 1; - unsigned hblank = (timings->hblank[0] | timings->hblank[1] << 8) + 1; - unsigned hsync = (timings->hsync[0] | (timings->hsync[1] & 0x7f) << 8) + 1; - unsigned hsync_width = (timings->hsw[0] | timings->hsw[1] << 8) + 1; - unsigned vactive = (timings->vactive[0] | timings->vactive[1] << 8) + 1; - unsigned vblank = (timings->vblank[0] | timings->vblank[1] << 8) + 1; - unsigned vsync = (timings->vsync[0] | (timings->vsync[1] & 0x7f) << 8) + 1; - unsigned vsync_width = (timings->vsw[0] | timings->vsw[1] << 8) + 1; - bool hsync_positive = (timings->hsync[1] >> 7) & 0x1; - bool vsync_positive = (timings->vsync[1] >> 7) & 0x1; + unsigned int pixel_clock = (timings->pixel_clock[0] | + (timings->pixel_clock[1] << 8) | + (timings->pixel_clock[2] << 16)) + 1; + unsigned int hactive = le16_to_cpu(timings->hactive) + 1; + unsigned int hblank = le16_to_cpu(timings->hblank) + 1; + unsigned int hsync = (le16_to_cpu(timings->hsync) & 0x7fff) + 1; + unsigned int hsync_width = le16_to_cpu(timings->hsw) + 1; + unsigned int vactive = le16_to_cpu(timings->vactive) + 1; + unsigned int vblank = le16_to_cpu(timings->vblank) + 1; + unsigned int vsync = (le16_to_cpu(timings->vsync) & 0x7fff) + 1; + unsigned int vsync_width = le16_to_cpu(timings->vsw) + 1; + bool hsync_positive = le16_to_cpu(timings->hsync) & (1 << 15); + bool vsync_positive = le16_to_cpu(timings->vsync) & (1 << 15); mode = drm_mode_create(dev); if (!mode) @@ -6838,8 +6838,8 @@ static struct drm_display_mode *drm_mode_displayid_formula(struct drm_device *de bool type_10) { struct drm_display_mode *mode; - u16 hactive = be16_to_cpu(timings->hactive) + 1; - u16 vactive = be16_to_cpu(timings->vactive) + 1; + u16 hactive = le16_to_cpu(timings->hactive) + 1; + u16 vactive = le16_to_cpu(timings->vactive) + 1; u8 timing_formula = timings->flags & 0x7; /* TODO: support RB-v2 & RB-v3 */ @@ -6848,7 +6848,7 @@ static struct drm_display_mode *drm_mode_displayid_formula(struct drm_device *de /* TODO: support video-optimized refresh rate */ if (timings->flags & (1 << 4)) - return NULL; + drm_dbg_kms(dev, "Fractional vrefresh is not implemented, proceeding with non-video-optimized refresh rate"); mode = drm_cvt_mode(dev, hactive, vactive, timings->vrefresh + 1, timing_formula == 1, false, false); if (!mode)