From patchwork Fri May 10 15:47:11 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Thomas Zimmermann X-Patchwork-Id: 13661769 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 90F7FC25B10 for ; Fri, 10 May 2024 15:48:51 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 39A8610EE12; Fri, 10 May 2024 15:48:49 +0000 (UTC) Authentication-Results: gabe.freedesktop.org; dkim=pass (1024-bit key; unprotected) header.d=suse.de header.i=@suse.de header.b="cafOYiSN"; dkim=permerror (0-bit key) header.d=suse.de header.i=@suse.de header.b="svngPe3s"; dkim=pass (1024-bit key) header.d=suse.de header.i=@suse.de header.b="ju/0Rk75"; dkim=permerror (0-bit key) header.d=suse.de header.i=@suse.de header.b="7EQsqbXr"; dkim-atps=neutral Received: from smtp-out2.suse.de (smtp-out2.suse.de [195.135.223.131]) by gabe.freedesktop.org (Postfix) with ESMTPS id 6873A10ED80 for ; Fri, 10 May 2024 15:48:46 +0000 (UTC) Received: from imap1.dmz-prg2.suse.org (imap1.dmz-prg2.suse.org [IPv6:2a07:de40:b281:104:10:150:64:97]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by smtp-out2.suse.de (Postfix) with ESMTPS id E754067431; Fri, 10 May 2024 15:48:44 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=suse.de; s=susede2_rsa; t=1715356125; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc:cc: mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=y8qyw+XKhKEb5aa1OZTo1CW/JkH37z58owvoTc6eEm0=; b=cafOYiSN5cywuTiJq6OXxWYmkMCdkOFs0yqyZRHhu0nofwFZDH4vpzISdFIbnheOA60a3a cdD5gsX1/KT4oQtwZGG8T3ghYGuaWdCDSekUFSspGbqzphsP61Nkn7LqKn3kcXraK/VvOe piMopdHsObPaUnYqcuNzNdTfnNmKy+k= DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; d=suse.de; s=susede2_ed25519; t=1715356125; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc:cc: mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=y8qyw+XKhKEb5aa1OZTo1CW/JkH37z58owvoTc6eEm0=; b=svngPe3s2kq8S8DiAPlsYpsBDL6mLsQ3SRmGLR9HP+Y+7CSM1zzxSmJhMy8eut+mbWvdYP LM/kIet9iYF3QRAw== Authentication-Results: smtp-out2.suse.de; dkim=pass header.d=suse.de header.s=susede2_rsa header.b="ju/0Rk75"; dkim=pass header.d=suse.de header.s=susede2_ed25519 header.b=7EQsqbXr DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=suse.de; s=susede2_rsa; t=1715356124; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc:cc: mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=y8qyw+XKhKEb5aa1OZTo1CW/JkH37z58owvoTc6eEm0=; b=ju/0Rk75u8gL+oeEnN9yE8FbOWx/cHaoD4bzCqe8xWJgxttykJzpENrpF2mQZ2cLANqtVJ jOMmC/5vp3cCv8vZBSf5QcnJcVJxl1+v/s4CC6023LJCq5H1/Ol3NVDgEeFLu+dIFV3JyP mlPNHytCbtwMA6s6TMcsK2EPo5oCT8s= DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; d=suse.de; s=susede2_ed25519; t=1715356124; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc:cc: mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=y8qyw+XKhKEb5aa1OZTo1CW/JkH37z58owvoTc6eEm0=; b=7EQsqbXrMpMPomQMo6uVsyEygT/AXEjrlCUorNyPu8ke9Ewp3lAoqoU3CJeo/uMe+RWAWQ CYSMkN1UtenvRkDA== Received: from imap1.dmz-prg2.suse.org (localhost [127.0.0.1]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by imap1.dmz-prg2.suse.org (Postfix) with ESMTPS id B4CD913A31; Fri, 10 May 2024 15:48:44 +0000 (UTC) Received: from dovecot-director2.suse.de ([2a07:de40:b281:106:10:150:64:167]) by imap1.dmz-prg2.suse.org with ESMTPSA id EID+KtxBPma7MgAAD6G6ig (envelope-from ); Fri, 10 May 2024 15:48:44 +0000 From: Thomas Zimmermann To: javierm@redhat.com, jani.nikula@linux.intel.com, airlied@redhat.com, sean@poorly.run Cc: dri-devel@lists.freedesktop.org, Thomas Zimmermann , Jani Nikula Subject: [PATCH v3 4/5] drm/udl: Untangle .get_modes() and .detect_ctx() Date: Fri, 10 May 2024 17:47:11 +0200 Message-ID: <20240510154841.11370-5-tzimmermann@suse.de> X-Mailer: git-send-email 2.44.0 In-Reply-To: <20240510154841.11370-1-tzimmermann@suse.de> References: <20240510154841.11370-1-tzimmermann@suse.de> MIME-Version: 1.0 X-Spamd-Result: default: False [-3.01 / 50.00]; BAYES_HAM(-3.00)[100.00%]; MID_CONTAINS_FROM(1.00)[]; NEURAL_HAM_LONG(-1.00)[-1.000]; R_MISSING_CHARSET(0.50)[]; R_DKIM_ALLOW(-0.20)[suse.de:s=susede2_rsa,suse.de:s=susede2_ed25519]; NEURAL_HAM_SHORT(-0.20)[-1.000]; MIME_GOOD(-0.10)[text/plain]; MX_GOOD(-0.01)[]; DBL_BLOCKED_OPENRESOLVER(0.00)[suse.de:dkim,suse.de:email]; RCVD_VIA_SMTP_AUTH(0.00)[]; FROM_EQ_ENVFROM(0.00)[]; ARC_NA(0.00)[]; MIME_TRACE(0.00)[0:+]; FROM_HAS_DN(0.00)[]; TO_MATCH_ENVRCPT_ALL(0.00)[]; RCVD_TLS_ALL(0.00)[]; RCPT_COUNT_SEVEN(0.00)[7]; DKIM_SIGNED(0.00)[suse.de:s=susede2_rsa,suse.de:s=susede2_ed25519]; FUZZY_BLOCKED(0.00)[rspamd.com]; RCVD_COUNT_TWO(0.00)[2]; DWL_DNSWL_BLOCKED(0.00)[suse.de:dkim]; TO_DN_SOME(0.00)[]; DKIM_TRACE(0.00)[suse.de:+] X-Rspamd-Action: no action X-Rspamd-Queue-Id: E754067431 X-Rspamd-Server: rspamd1.dmz-prg2.suse.org 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" Provide separate implementations of .get_modes() and .detect_ctx() from struct drm_connector. Switch to struct drm_edid. Udl's .detect() helper used to fetch the EDID from the adapter and the .get_modes() helper provided display modes from the data. But this relied on the DRM helpers to call the functions in the correct order. When no EDID could be retrieved, .detect() regularly printed a warning to the kernel log. Switching to the new helpers around struct drm_edid separates both from each other. The .get_modes() helper now fetches the EDID by itself and the .detect_ctx() helper only tests for its presence. The patch does a number of things to implement this. - Move udl_get_edid_block() to udl_edid.c and rename it to udl_read_edid_block(). Then use the helper to implement probing in udl_probe_edid() and reading in udl_edid_read(). The latter helper is build on top of DRM helpers. - Replace the existing code in .get_modes() and .detect() with udl's new EDID helpers. The new code behaves like DRM's similar DDC-based helpers. Instead of .detect(), udl now implements .detect_ctx(). - Remove the edid data from struct udl_connector. The field cached the EDID data between calls to .detect() and .get_modes(), but is now unused. v3: - implement udl_probe_edid() with memchr_inv() (Jani) v2: - implement udl_probe_edid() within udl - reword commit description Signed-off-by: Thomas Zimmermann Reviewed-by: Jani Nikula --- drivers/gpu/drm/udl/Makefile | 1 + drivers/gpu/drm/udl/udl_drv.h | 2 - drivers/gpu/drm/udl/udl_edid.c | 80 +++++++++++++++++++++++++++ drivers/gpu/drm/udl/udl_edid.h | 15 ++++++ drivers/gpu/drm/udl/udl_modeset.c | 90 +++++++------------------------ 5 files changed, 115 insertions(+), 73 deletions(-) create mode 100644 drivers/gpu/drm/udl/udl_edid.c create mode 100644 drivers/gpu/drm/udl/udl_edid.h diff --git a/drivers/gpu/drm/udl/Makefile b/drivers/gpu/drm/udl/Makefile index 00690741db376..43d69a16af183 100644 --- a/drivers/gpu/drm/udl/Makefile +++ b/drivers/gpu/drm/udl/Makefile @@ -2,6 +2,7 @@ udl-y := \ udl_drv.o \ + udl_edid.o \ udl_main.o \ udl_modeset.o \ udl_transfer.o diff --git a/drivers/gpu/drm/udl/udl_drv.h b/drivers/gpu/drm/udl/udl_drv.h index 282ebd6c02fda..f112cfb270f31 100644 --- a/drivers/gpu/drm/udl/udl_drv.h +++ b/drivers/gpu/drm/udl/udl_drv.h @@ -51,8 +51,6 @@ struct urb_list { struct udl_connector { struct drm_connector connector; - /* last udl_detect edid */ - struct edid *edid; }; static inline struct udl_connector *to_udl_connector(struct drm_connector *connector) diff --git a/drivers/gpu/drm/udl/udl_edid.c b/drivers/gpu/drm/udl/udl_edid.c new file mode 100644 index 0000000000000..d67e6bf1f2aec --- /dev/null +++ b/drivers/gpu/drm/udl/udl_edid.c @@ -0,0 +1,80 @@ +// SPDX-License-Identifier: GPL-2.0-only + +#include + +#include +#include + +#include "udl_drv.h" +#include "udl_edid.h" + +static int udl_read_edid_block(void *data, u8 *buf, unsigned int block, size_t len) +{ + struct udl_device *udl = data; + struct drm_device *dev = &udl->drm; + struct usb_device *udev = udl_to_usb_device(udl); + u8 *read_buff; + int idx, ret; + size_t i; + + read_buff = kmalloc(2, GFP_KERNEL); + if (!read_buff) + return -ENOMEM; + + if (!drm_dev_enter(dev, &idx)) { + ret = -ENODEV; + goto err_kfree; + } + + for (i = 0; i < len; i++) { + int bval = (i + block * EDID_LENGTH) << 8; + + ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), + 0x02, (0x80 | (0x02 << 5)), bval, + 0xA1, read_buff, 2, USB_CTRL_GET_TIMEOUT); + if (ret < 0) { + drm_err(dev, "Read EDID byte %zu failed err %x\n", i, ret); + goto err_drm_dev_exit; + } else if (ret < 1) { + ret = -EIO; + drm_err(dev, "Read EDID byte %zu failed\n", i); + goto err_drm_dev_exit; + } + + buf[i] = read_buff[1]; + } + + drm_dev_exit(idx); + kfree(read_buff); + + return 0; + +err_drm_dev_exit: + drm_dev_exit(idx); +err_kfree: + kfree(read_buff); + return ret; +} + +bool udl_probe_edid(struct udl_device *udl) +{ + u8 hdr[8]; + int ret; + + ret = udl_read_edid_block(udl, hdr, 0, sizeof(hdr)); + if (ret) + return false; + + /* + * The adapter sends all-zeros if no monitor has been + * connected. We consider anything else a connection. + */ + return !!memchr_inv(hdr, 0, sizeof(hdr)); +} + +const struct drm_edid *udl_edid_read(struct drm_connector *connector) +{ + struct udl_device *udl = to_udl(connector->dev); + + return drm_edid_read_custom(connector, udl_read_edid_block, udl); +} diff --git a/drivers/gpu/drm/udl/udl_edid.h b/drivers/gpu/drm/udl/udl_edid.h new file mode 100644 index 0000000000000..fe15ff3752b7d --- /dev/null +++ b/drivers/gpu/drm/udl/udl_edid.h @@ -0,0 +1,15 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#ifndef UDL_EDID_H +#define UDL_EDID_H + +#include + +struct drm_connector; +struct drm_edid; +struct udl_device; + +bool udl_probe_edid(struct udl_device *udl); +const struct drm_edid *udl_edid_read(struct drm_connector *connector); + +#endif diff --git a/drivers/gpu/drm/udl/udl_modeset.c b/drivers/gpu/drm/udl/udl_modeset.c index 3df9fc38388b4..4236ce57f5945 100644 --- a/drivers/gpu/drm/udl/udl_modeset.c +++ b/drivers/gpu/drm/udl/udl_modeset.c @@ -25,6 +25,7 @@ #include #include "udl_drv.h" +#include "udl_edid.h" #include "udl_proto.h" /* @@ -415,97 +416,44 @@ static const struct drm_encoder_funcs udl_encoder_funcs = { static int udl_connector_helper_get_modes(struct drm_connector *connector) { - struct udl_connector *udl_connector = to_udl_connector(connector); + const struct drm_edid *drm_edid; + int count; - drm_connector_update_edid_property(connector, udl_connector->edid); - if (udl_connector->edid) - return drm_add_edid_modes(connector, udl_connector->edid); + drm_edid = udl_edid_read(connector); + drm_edid_connector_update(connector, drm_edid); + count = drm_edid_connector_add_modes(connector); + drm_edid_free(drm_edid); - return 0; + return count; } -static const struct drm_connector_helper_funcs udl_connector_helper_funcs = { - .get_modes = udl_connector_helper_get_modes, -}; - -static int udl_get_edid_block(void *data, u8 *buf, unsigned int block, size_t len) +static int udl_connector_helper_detect_ctx(struct drm_connector *connector, + struct drm_modeset_acquire_ctx *ctx, + bool force) { - struct udl_device *udl = data; - struct drm_device *dev = &udl->drm; - struct usb_device *udev = udl_to_usb_device(udl); - u8 *read_buff; - int idx, ret; - size_t i; - - read_buff = kmalloc(2, GFP_KERNEL); - if (!read_buff) - return -ENOMEM; + struct udl_device *udl = to_udl(connector->dev); - if (!drm_dev_enter(dev, &idx)) { - ret = -ENODEV; - goto err_kfree; - } - - for (i = 0; i < len; i++) { - int bval = (i + block * EDID_LENGTH) << 8; - - ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), - 0x02, (0x80 | (0x02 << 5)), bval, - 0xA1, read_buff, 2, USB_CTRL_GET_TIMEOUT); - if (ret < 0) { - drm_err(dev, "Read EDID byte %zu failed err %x\n", i, ret); - goto err_drm_dev_exit; - } else if (ret < 1) { - ret = -EIO; - drm_err(dev, "Read EDID byte %zu failed\n", i); - goto err_drm_dev_exit; - } - - buf[i] = read_buff[1]; - } + if (udl_probe_edid(udl)) + return connector_status_connected; - drm_dev_exit(idx); - kfree(read_buff); - - return 0; - -err_drm_dev_exit: - drm_dev_exit(idx); -err_kfree: - kfree(read_buff); - return ret; + return connector_status_disconnected; } -static enum drm_connector_status udl_connector_detect(struct drm_connector *connector, bool force) -{ - struct drm_device *dev = connector->dev; - struct udl_device *udl = to_udl(dev); - struct udl_connector *udl_connector = to_udl_connector(connector); - enum drm_connector_status status = connector_status_disconnected; - - /* cleanup previous EDID */ - kfree(udl_connector->edid); - udl_connector->edid = NULL; - - udl_connector->edid = drm_do_get_edid(connector, udl_get_edid_block, udl); - if (udl_connector->edid) - status = connector_status_connected; - - return status; -} +static const struct drm_connector_helper_funcs udl_connector_helper_funcs = { + .get_modes = udl_connector_helper_get_modes, + .detect_ctx = udl_connector_helper_detect_ctx, +}; static void udl_connector_destroy(struct drm_connector *connector) { struct udl_connector *udl_connector = to_udl_connector(connector); drm_connector_cleanup(connector); - kfree(udl_connector->edid); kfree(udl_connector); } static const struct drm_connector_funcs udl_connector_funcs = { .reset = drm_atomic_helper_connector_reset, - .detect = udl_connector_detect, .fill_modes = drm_helper_probe_single_connector_modes, .destroy = udl_connector_destroy, .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,