From patchwork Sat Jun 15 17:53:30 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dmitry Baryshkov X-Patchwork-Id: 13699345 Received: from mail-lf1-f51.google.com (mail-lf1-f51.google.com [209.85.167.51]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id ABE654EB37 for ; Sat, 15 Jun 2024 17:53:36 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.167.51 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1718474019; cv=none; b=QtWJhC46WVqhSf9DvxabH/Er1K8Ux8c2iKdrLrcRLu+eOzQYkGSgaR+bCJdEHW62cCr+2Tu2MTx846W/OMaDQXkRrRoHvHl0coh9AI8kcIiZ2xkfVdAnxuDaTdXn45FqBlIn471N51k2CJtqVCkNki/dKl0C/jmg75UcS0v0DgM= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1718474019; c=relaxed/simple; bh=aL8nPSZM3lQNEMPRaCYGZfpxv/0gb5cmUE3ToFjqcjg=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=ipFb4+CIyp9EdFmM1gywuJqDhRCN/a1jJVUBV5b8zLD4XP/c94ewlRnIGbebZfWqxwkBOEbdiq4bQxB6F0waU2sjKnMjcIpe9L1c2jb7v0zQU5Zre25xtz9b+/01AB+OxA0kwuw9VV401hI8aEZxV51mcDyCURWd0fm9lW2n+rA= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linaro.org; spf=pass smtp.mailfrom=linaro.org; dkim=pass (2048-bit key) header.d=linaro.org header.i=@linaro.org header.b=D4k90L7Q; arc=none smtp.client-ip=209.85.167.51 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linaro.org Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linaro.org Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=linaro.org header.i=@linaro.org header.b="D4k90L7Q" Received: by mail-lf1-f51.google.com with SMTP id 2adb3069b0e04-52bc0a9cea4so2808188e87.0 for ; Sat, 15 Jun 2024 10:53:36 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; t=1718474015; x=1719078815; darn=vger.kernel.org; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:from:to:cc:subject:date:message-id :reply-to; bh=QlANpMb5skb9j8A6rCketIfwen0xll0H3lJtTWXdrxI=; b=D4k90L7Q7WXlibbDmBKTuq2AKDH686cwYarIgy+jlfiDPxUoVVA8UriIhvo5X9my2+ dYBzvOtg4DAb3EkxjU2W8mq6qVkz4zRuULBbUPo5YzNw7nrli1EQHjl/YNFjK1WjRmc3 X2vNF+yYhhEcQzM/Cs52r1GqzSPVszyJi9ON7Xo0eTYvabScvr496nwPVXsn63itq4fv 6496OS9zxm7E/ejbDs0R2XAFA2ybVyXt6aHmTQdlcDKlH4W9gH/81a7XKx+E1zLNF+tw U1Iy2NDmsYcw7bgz2xty2/GGMUtJiC347T5R+VYxZmlHl3BoXkwm6wivbNXwFg2+do79 XZMw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1718474015; x=1719078815; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=QlANpMb5skb9j8A6rCketIfwen0xll0H3lJtTWXdrxI=; b=oaZxoPcm1I20R9Xsb3fkgsCGqI6Us2Sm+2XiICC/Hr4r9I0Qd+yzX1TL4HmL5XCAUW UazSyWEmf1DOjREI2pILdzvZfhZDk9uDEIn6ymyOvStqlLFEKs/Uib+JwsKLokFswRhg Yl8Y3iEseJ0sp0WM3gZVvNd8uO0wqkT8J59efsZn25JYVLG5Js1n328CA7ZrE49ihbHg kU/i2jkomqDXlsPXu9byLWgxnxNfwr+KUG+8JS3+Wynvshe9lNbNaUc4rA5NTYmM2Soj 38tIZAm+FupL7gpqIf/t1TjEeCj0yQ04NY/JBdeFqu92vEPUFqhdyzbLqcQ3H6VMKYmf Mo7A== X-Forwarded-Encrypted: i=1; AJvYcCUGiacswPJzPpCGV2L9S/Z6D1JEa4iWpw1cUebIGpE12VvUO5Lbs+pQJ90c6hgrL8butCoWota3yvCf5/QDP71gJ+NlRmkXs2yMimU= X-Gm-Message-State: AOJu0Yzs3lwd1jLywbjoTn7kjshfZ9iMdgWCFdkQcoC1eEAL60QS2tdR mYjt9HLRIeEOheSlwKQ6PuuFofHBhDxUQ9BQDGDDASOsqt6dgaJB0XFTOtjCV/g= X-Google-Smtp-Source: AGHT+IHrTqiamW3tjd1h0AT0KzFG/oQcLS/rGaUBf5VuD/2/RtRDBwEeBxYBBv6ORagQqAsz4VOglg== X-Received: by 2002:a05:6512:ba0:b0:52c:8dea:c56f with SMTP id 2adb3069b0e04-52ca6cc6e6bmr2428094e87.25.1718474014884; Sat, 15 Jun 2024 10:53:34 -0700 (PDT) Received: from umbar.lan ([192.130.178.91]) by smtp.gmail.com with ESMTPSA id 2adb3069b0e04-52ca287affcsm799209e87.232.2024.06.15.10.53.34 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sat, 15 Jun 2024 10:53:34 -0700 (PDT) From: Dmitry Baryshkov Date: Sat, 15 Jun 2024 20:53:30 +0300 Subject: [PATCH RFC 1/5] drm/bridge: lt9611: use HDMI Connector helper to set InfoFrames Precedence: bulk X-Mailing-List: linux-sound@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Message-Id: <20240615-drm-bridge-hdmi-connector-v1-1-d59fc7865ab2@linaro.org> References: <20240615-drm-bridge-hdmi-connector-v1-0-d59fc7865ab2@linaro.org> In-Reply-To: <20240615-drm-bridge-hdmi-connector-v1-0-d59fc7865ab2@linaro.org> To: Andrzej Hajda , Neil Armstrong , Robert Foss , Laurent Pinchart , Jonas Karlman , Jernej Skrabec , Maarten Lankhorst , Maxime Ripard , Thomas Zimmermann , David Airlie , Daniel Vetter , Jaroslav Kysela , Takashi Iwai , Liam Girdwood , Mark Brown Cc: dri-devel@lists.freedesktop.org, linux-kernel@vger.kernel.org, linux-sound@vger.kernel.org X-Mailer: b4 0.13.0 X-Developer-Signature: v=1; a=openpgp-sha256; l=8080; i=dmitry.baryshkov@linaro.org; h=from:subject:message-id; bh=aL8nPSZM3lQNEMPRaCYGZfpxv/0gb5cmUE3ToFjqcjg=; b=owEBbQGS/pANAwAKAYs8ij4CKSjVAcsmYgBmbdUc5OiUzAZhdrE2hgXcqb9AuEMwC4hboqUw/ TdOkcnk+vaJATMEAAEKAB0WIQRMcISVXLJjVvC4lX+LPIo+Aiko1QUCZm3VHAAKCRCLPIo+Aiko 1eEpB/4pD9xOj0U7d0zlANyosGgLZMuY5Z39+KplUH8AYJi0qP23SR9naWQ3Zjd9IRCCuYT6ci9 CpbSLZxjnQrmzKY/hNkND0RTXEO2xq8PIyO2Bz7JVtdrXQY798c1DWk594WUjyUMvURU3SnhKDo P701fO8wo1DfyVRFdY3toI6QZR9TzJlS1HMRthB9tqfS2CTc59NiVXltHZpSXqRdIPd0LSUyPDF st4G/0eiHKTS7H8AqilwFzURyFbE6/rBzsZHM5Mz4IMiRYQY7btCDggLu6o8iqGwKh54mcq/JyN SnaIkkSNu80NxPJO/229ODMf+z1S4B85X0Kz/ADnXD5IblEH X-Developer-Key: i=dmitry.baryshkov@linaro.org; a=openpgp; fpr=8F88381DD5C873E4AE487DA5199BF1243632046A X-Patchwork-State: RFC Use new HDMI Connector helpers in the Lontium LT9611 bridge driver. Program InfoFrames using the helper's callbacks. Also use TMDS char rate validation callback to filter out modes, instead of hardcoding 4k@30. The Audio InfoFrame isn't yet handled by these helpers, it requires additional drm_bridge interface changes. Signed-off-by: Dmitry Baryshkov Reviewed-by: Maxime Ripard --- drivers/gpu/drm/bridge/Kconfig | 2 + drivers/gpu/drm/bridge/lontium-lt9611.c | 173 ++++++++++++++++++++++---------- 2 files changed, 120 insertions(+), 55 deletions(-) diff --git a/drivers/gpu/drm/bridge/Kconfig b/drivers/gpu/drm/bridge/Kconfig index c621be1a99a8..b27b8a072101 100644 --- a/drivers/gpu/drm/bridge/Kconfig +++ b/drivers/gpu/drm/bridge/Kconfig @@ -140,6 +140,8 @@ config DRM_LONTIUM_LT9611 select DRM_PANEL_BRIDGE select DRM_KMS_HELPER select DRM_MIPI_DSI + select DRM_DISPLAY_HELPER + select DRM_DISPLAY_HDMI_STATE_HELPER select REGMAP_I2C help Driver for Lontium LT9611 DSI to HDMI bridge diff --git a/drivers/gpu/drm/bridge/lontium-lt9611.c b/drivers/gpu/drm/bridge/lontium-lt9611.c index 73983f9b50cb..1b31fdebe164 100644 --- a/drivers/gpu/drm/bridge/lontium-lt9611.c +++ b/drivers/gpu/drm/bridge/lontium-lt9611.c @@ -23,6 +23,8 @@ #include #include #include +#include +#include #define EDID_SEG_SIZE 256 #define EDID_LEN 32 @@ -333,49 +335,6 @@ static int lt9611_video_check(struct lt9611 *lt9611) return temp; } -static void lt9611_hdmi_set_infoframes(struct lt9611 *lt9611, - struct drm_connector *connector, - struct drm_display_mode *mode) -{ - union hdmi_infoframe infoframe; - ssize_t len; - u8 iframes = 0x0a; /* UD1 infoframe */ - u8 buf[32]; - int ret; - int i; - - ret = drm_hdmi_avi_infoframe_from_display_mode(&infoframe.avi, - connector, - mode); - if (ret < 0) - goto out; - - len = hdmi_infoframe_pack(&infoframe, buf, sizeof(buf)); - if (len < 0) - goto out; - - for (i = 0; i < len; i++) - regmap_write(lt9611->regmap, 0x8440 + i, buf[i]); - - ret = drm_hdmi_vendor_infoframe_from_display_mode(&infoframe.vendor.hdmi, - connector, - mode); - if (ret < 0) - goto out; - - len = hdmi_infoframe_pack(&infoframe, buf, sizeof(buf)); - if (len < 0) - goto out; - - for (i = 0; i < len; i++) - regmap_write(lt9611->regmap, 0x8474 + i, buf[i]); - - iframes |= 0x20; - -out: - regmap_write(lt9611->regmap, 0x843d, iframes); /* UD1 infoframe */ -} - static void lt9611_hdmi_tx_digital(struct lt9611 *lt9611, bool is_hdmi) { if (is_hdmi) @@ -719,7 +678,7 @@ lt9611_bridge_atomic_enable(struct drm_bridge *bridge, } lt9611_mipi_input_analog(lt9611); - lt9611_hdmi_set_infoframes(lt9611, connector, mode); + drm_atomic_helper_connector_hdmi_update_infoframes(connector, state); lt9611_hdmi_tx_digital(lt9611, connector->display_info.is_hdmi); lt9611_hdmi_tx_phy(lt9611); @@ -798,22 +757,25 @@ static enum drm_mode_status lt9611_bridge_mode_valid(struct drm_bridge *bridge, const struct drm_display_mode *mode) { struct lt9611 *lt9611 = bridge_to_lt9611(bridge); + unsigned long long rate; if (mode->hdisplay > 3840) return MODE_BAD_HVALUE; - if (mode->vdisplay > 2160) - return MODE_BAD_VVALUE; - - if (mode->hdisplay == 3840 && - mode->vdisplay == 2160 && - drm_mode_vrefresh(mode) > 30) - return MODE_CLOCK_HIGH; - if (mode->hdisplay > 2000 && !lt9611->dsi1_node) return MODE_PANEL; - else - return MODE_OK; + + rate = drm_hdmi_compute_mode_clock(mode, 8, HDMI_COLORSPACE_RGB); + return bridge->funcs->hdmi_tmds_char_rate_valid(bridge, mode, rate); +} + +static int lt9611_bridge_atomic_check(struct drm_bridge *bridge, + struct drm_bridge_state *bridge_state, + struct drm_crtc_state *crtc_state, + struct drm_connector_state *conn_state) +{ + return drm_atomic_helper_connector_hdmi_check(conn_state->connector, + conn_state->state); } static void lt9611_bridge_atomic_pre_enable(struct drm_bridge *bridge, @@ -887,6 +849,99 @@ lt9611_atomic_get_input_bus_fmts(struct drm_bridge *bridge, return input_fmts; } +/* + * Other working frames: + * - 0x01, 0x84df + * - 0x04, 0x84c0 + */ +#define LT9611_INFOFRAME_AUDIO 0x02 +#define LT9611_INFOFRAME_AVI 0x08 +#define LT9611_INFOFRAME_SPD 0x10 +#define LT9611_INFOFRAME_VENDOR 0x20 + +static int lt9611_hdmi_clear_infoframe(struct drm_bridge *bridge, + enum hdmi_infoframe_type type) +{ + struct lt9611 *lt9611 = bridge_to_lt9611(bridge); + unsigned int mask; + + switch (type) { + case HDMI_INFOFRAME_TYPE_AVI: + mask = LT9611_INFOFRAME_AVI; + break; + + case HDMI_INFOFRAME_TYPE_SPD: + mask = LT9611_INFOFRAME_SPD; + break; + + case HDMI_INFOFRAME_TYPE_VENDOR: + mask = LT9611_INFOFRAME_VENDOR; + break; + + default: + drm_dbg_driver(lt9611->bridge.dev, "Unsupported HDMI InfoFrame %x\n", type); + mask = 0; + break; + } + + if (mask) + regmap_update_bits(lt9611->regmap, 0x843d, mask, 0); + + return 0; +} + +static int lt9611_hdmi_write_infoframe(struct drm_bridge *bridge, + enum hdmi_infoframe_type type, + const u8 *buffer, size_t len) +{ + struct lt9611 *lt9611 = bridge_to_lt9611(bridge); + unsigned int mask, addr; + int i; + + switch (type) { + case HDMI_INFOFRAME_TYPE_AVI: + mask = LT9611_INFOFRAME_AVI; + addr = 0x8440; + break; + + case HDMI_INFOFRAME_TYPE_SPD: + mask = LT9611_INFOFRAME_SPD; + addr = 0x8493; + break; + + case HDMI_INFOFRAME_TYPE_VENDOR: + mask = LT9611_INFOFRAME_VENDOR; + addr = 0x8474; + break; + + default: + drm_dbg_driver(lt9611->bridge.dev, "Unsupported HDMI InfoFrame %x\n", type); + mask = 0; + break; + } + + if (mask) { + for (i = 0; i < len; i++) + regmap_write(lt9611->regmap, addr + i, buffer[i]); + + regmap_update_bits(lt9611->regmap, 0x843d, mask, mask); + } + + return 0; +} + +static enum drm_mode_status +lt9611_hdmi_tmds_char_rate_valid(const struct drm_bridge *bridge, + const struct drm_display_mode *mode, + unsigned long long tmds_rate) +{ + /* 297 MHz for 4k@30 mode */ + if (tmds_rate > 297000000) + return MODE_CLOCK_HIGH; + + return MODE_OK; +} + static const struct drm_bridge_funcs lt9611_bridge_funcs = { .attach = lt9611_bridge_attach, .mode_valid = lt9611_bridge_mode_valid, @@ -894,6 +949,7 @@ static const struct drm_bridge_funcs lt9611_bridge_funcs = { .edid_read = lt9611_bridge_edid_read, .hpd_enable = lt9611_bridge_hpd_enable, + .atomic_check = lt9611_bridge_atomic_check, .atomic_pre_enable = lt9611_bridge_atomic_pre_enable, .atomic_enable = lt9611_bridge_atomic_enable, .atomic_disable = lt9611_bridge_atomic_disable, @@ -902,6 +958,10 @@ static const struct drm_bridge_funcs lt9611_bridge_funcs = { .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state, .atomic_reset = drm_atomic_helper_bridge_reset, .atomic_get_input_bus_fmts = lt9611_atomic_get_input_bus_fmts, + + .hdmi_tmds_char_rate_valid = lt9611_hdmi_tmds_char_rate_valid, + .hdmi_write_infoframe = lt9611_hdmi_write_infoframe, + .hdmi_clear_infoframe = lt9611_hdmi_clear_infoframe, }; static int lt9611_parse_dt(struct device *dev, @@ -1116,8 +1176,11 @@ static int lt9611_probe(struct i2c_client *client) lt9611->bridge.funcs = <9611_bridge_funcs; lt9611->bridge.of_node = client->dev.of_node; lt9611->bridge.ops = DRM_BRIDGE_OP_DETECT | DRM_BRIDGE_OP_EDID | - DRM_BRIDGE_OP_HPD | DRM_BRIDGE_OP_MODES; + DRM_BRIDGE_OP_HPD | DRM_BRIDGE_OP_MODES | + DRM_BRIDGE_OP_HDMI; lt9611->bridge.type = DRM_MODE_CONNECTOR_HDMIA; + lt9611->bridge.vendor = "Lontium"; + lt9611->bridge.product = "LT9611"; drm_bridge_add(<9611->bridge); From patchwork Sat Jun 15 17:53:31 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dmitry Baryshkov X-Patchwork-Id: 13699344 Received: from mail-lf1-f47.google.com (mail-lf1-f47.google.com [209.85.167.47]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id AC5EA50A63 for ; Sat, 15 Jun 2024 17:53:37 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.167.47 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1718474019; cv=none; b=lmo4hKPwsnbj1CmKe5ecjhClTQdfDntNxZgqOzxaLFYv4VP3C5mueROcLeIB/k96mULGlz3zoJacfAWVc4KJPJs8SuowyITU6Jq2sDvGZXiv6QgCy+jt5kkK3MUxEOwfF8cUsBTT/aB1dwm2oFo0hYCEDs5/YuZwS9iXaxy8enE= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1718474019; c=relaxed/simple; bh=pn2geVII/7Eo49RZTSaWQ/BY5SCV/YSpXIUmvyJMH0Y=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=e6ROG6oN9XU7s43WdTtkPdbWyK9EsCtvWdsn08zQQWObTOWrV1FbKwgGdZ9Hu03QTtAGv+pk5i23NEL2IUOLPUxgXLBB7x1gRcvkc9+Te8J1OOKEA4zH5Crq5HxdPX/UgqeSQtlVWWSp01tf3CqgZZ3i99Mqq6Yo7f94DkCuU5s= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linaro.org; spf=pass smtp.mailfrom=linaro.org; dkim=pass (2048-bit key) header.d=linaro.org header.i=@linaro.org header.b=VAYckJ/H; arc=none smtp.client-ip=209.85.167.47 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linaro.org Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linaro.org Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=linaro.org header.i=@linaro.org header.b="VAYckJ/H" Received: by mail-lf1-f47.google.com with SMTP id 2adb3069b0e04-52bc035a7ccso3393568e87.2 for ; Sat, 15 Jun 2024 10:53:37 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; t=1718474016; x=1719078816; darn=vger.kernel.org; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:from:to:cc:subject:date:message-id :reply-to; bh=RSmIEAIcnC5msdB38vTdYnwra4YbtdBczjpwQBiMsUo=; b=VAYckJ/H0io7WrI8vriTAYUCw18L5sUHKb3XVoNCmn0wQurr7PO/HISYJ0c2ZeRho8 10P+uRzVUWjHntCCbAuvhkQTh/cxBEtIgbUHkxztt+ORU/31tPYVKpI3S1GmfVbea2XT zXjv5ijc/k3K1TCQ7dFbQb2jLxPVJP2L1pQmd1WxsmSmHcfMY3/ffxLzPKghEaZZr6pU 5shfWuqeX4OHuOMLU9RgD3BJIgjaqzOgKwqL8R4gPoHucj6qDrJJvCou9lFyM+pWXg1J taGFZsur1SUqopd93B5z8z31/u5+rVUcV618LA9QaeSB3OxJWC9hEhNKrCxPQ4DtJSlC rPCQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1718474016; x=1719078816; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=RSmIEAIcnC5msdB38vTdYnwra4YbtdBczjpwQBiMsUo=; b=QWdQi7vj23mnZ8dRm/qEevN5/M7/rd0G+OnPcRkng4ooiWNGd0aRX016TqCSfa/oSI ctUvxcDMaoksrpl5n3PenHIhgcnAC7NmupiEtWY5SwVPDfC+KlXrxGiL9eO+oj2We7x+ DEaLufAgFuNKMlwo6HwU/u7rmefHlcAuguzAeL6/S2qoEfU8yRX2RpprW/PW1L5Wz8cb a3Ax1GRhxVSwlwNc+IYzx8Neni373c0V27WOVXFs+ibqe6Apuly9SjD116mwnIA9Blrn vFy+jnyBKzrqkMQPLnGSvZ7LOEGnbjlU/av4Wlw5ktGRnceyLuY8/NWijhjNUMGVcIPY jhiQ== X-Forwarded-Encrypted: i=1; AJvYcCUWuxS0U4T1B4ZHEH0xNQPkZnPLlknUc3fFvEFRLGgk30LgRI7BlDwh7JSiA8RvHk+xO48wYK4gLr9kfCrBe/wwDIxQZqfOMyLItME= X-Gm-Message-State: AOJu0Yx84fP3y+XLiIGfveTjF2wsMfAjf3RF+HuKMptO64dbqYBJLeK9 j6dA/3ocZ9HEUOY36s3grk1jFzA8c7odBukOcSjcSJlQT7tH848Kz2A0TTCSyhU= X-Google-Smtp-Source: AGHT+IFFYHgBPLlADC7SeWWeSUbYhyXls9nx5aYDUbEVtXba3FK5dU/UdVl0LGd0s9vqqrTQ+6kMww== X-Received: by 2002:ac2:4d84:0:b0:52c:859f:f4f0 with SMTP id 2adb3069b0e04-52ca6e55b9dmr3329487e87.1.1718474015617; Sat, 15 Jun 2024 10:53:35 -0700 (PDT) Received: from umbar.lan ([192.130.178.91]) by smtp.gmail.com with ESMTPSA id 2adb3069b0e04-52ca287affcsm799209e87.232.2024.06.15.10.53.34 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sat, 15 Jun 2024 10:53:35 -0700 (PDT) From: Dmitry Baryshkov Date: Sat, 15 Jun 2024 20:53:31 +0300 Subject: [PATCH RFC 2/5] ASoC: hdmi-codec: pass data to get_dai_id too Precedence: bulk X-Mailing-List: linux-sound@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Message-Id: <20240615-drm-bridge-hdmi-connector-v1-2-d59fc7865ab2@linaro.org> References: <20240615-drm-bridge-hdmi-connector-v1-0-d59fc7865ab2@linaro.org> In-Reply-To: <20240615-drm-bridge-hdmi-connector-v1-0-d59fc7865ab2@linaro.org> To: Andrzej Hajda , Neil Armstrong , Robert Foss , Laurent Pinchart , Jonas Karlman , Jernej Skrabec , Maarten Lankhorst , Maxime Ripard , Thomas Zimmermann , David Airlie , Daniel Vetter , Jaroslav Kysela , Takashi Iwai , Liam Girdwood , Mark Brown Cc: dri-devel@lists.freedesktop.org, linux-kernel@vger.kernel.org, linux-sound@vger.kernel.org X-Mailer: b4 0.13.0 X-Developer-Signature: v=1; a=openpgp-sha256; l=5201; i=dmitry.baryshkov@linaro.org; h=from:subject:message-id; bh=pn2geVII/7Eo49RZTSaWQ/BY5SCV/YSpXIUmvyJMH0Y=; b=owEBbQGS/pANAwAKAYs8ij4CKSjVAcsmYgBmbdUcJ8IWkUmCcVBgeC3Vg+4kMPVLklqkCSo8t dwBDiKMur6JATMEAAEKAB0WIQRMcISVXLJjVvC4lX+LPIo+Aiko1QUCZm3VHAAKCRCLPIo+Aiko 1TujB/9qMk4FvPARfIqiMMGapz1hICXprHpD56e2wjfXzSdlFR1jrjFrv6a9LcgotCtgzcV2MpJ ftnGmikXtNHqYanoz+ECPMv7dQSvXoJ7tjsQ8TuqMgbKXMlyZWHsjPSjeoJ7rVT9BK4VZ6X9uBE EvDhcHjkpNi9govajrxDXoeeHtyaapmizdRwSNHrVyC6Fdl3YS4gps7Fn2ig8b88Z4vKNSHL9ZF HEXHBUGPyqwQf5ikQPo3+Ceb1S9QCYCPmkEUdSWD98XX1mWWNlej5C7RMckzPk5rx87fdeVv5W0 Vs04wHXP3k8ekcQE5RW1sst75DpC5YGVc01V/SW2yawCH5ju X-Developer-Key: i=dmitry.baryshkov@linaro.org; a=openpgp; fpr=8F88381DD5C873E4AE487DA5199BF1243632046A X-Patchwork-State: RFC The upcoming DRM connector HDMI codec implementation is going to use codec-specific data in the .get_dai_id to get drm_connector. Pass data to the callback, as it is done with other hdmi_codec_ops callbacks. Signed-off-by: Dmitry Baryshkov Acked-by: Mark Brown --- drivers/gpu/drm/bridge/adv7511/adv7511_audio.c | 3 ++- drivers/gpu/drm/bridge/analogix/anx7625.c | 3 ++- drivers/gpu/drm/bridge/lontium-lt9611.c | 3 ++- drivers/gpu/drm/bridge/lontium-lt9611uxc.c | 3 ++- drivers/gpu/drm/bridge/sii902x.c | 3 ++- drivers/gpu/drm/bridge/synopsys/dw-hdmi-i2s-audio.c | 3 ++- include/sound/hdmi-codec.h | 3 ++- sound/soc/codecs/hdmi-codec.c | 2 +- 8 files changed, 15 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/bridge/adv7511/adv7511_audio.c b/drivers/gpu/drm/bridge/adv7511/adv7511_audio.c index 61f4a38e7d2b..51fb9a574b4e 100644 --- a/drivers/gpu/drm/bridge/adv7511/adv7511_audio.c +++ b/drivers/gpu/drm/bridge/adv7511/adv7511_audio.c @@ -204,7 +204,8 @@ static void audio_shutdown(struct device *dev, void *data) } static int adv7511_hdmi_i2s_get_dai_id(struct snd_soc_component *component, - struct device_node *endpoint) + struct device_node *endpoint, + void *data) { struct of_endpoint of_ep; int ret; diff --git a/drivers/gpu/drm/bridge/analogix/anx7625.c b/drivers/gpu/drm/bridge/analogix/anx7625.c index 88e4aa5830f3..f18cf79a292b 100644 --- a/drivers/gpu/drm/bridge/analogix/anx7625.c +++ b/drivers/gpu/drm/bridge/analogix/anx7625.c @@ -1962,7 +1962,8 @@ static void anx7625_audio_shutdown(struct device *dev, void *data) } static int anx7625_hdmi_i2s_get_dai_id(struct snd_soc_component *component, - struct device_node *endpoint) + struct device_node *endpoint, + void *data) { struct of_endpoint of_ep; int ret; diff --git a/drivers/gpu/drm/bridge/lontium-lt9611.c b/drivers/gpu/drm/bridge/lontium-lt9611.c index 1b31fdebe164..4fa0dfc5539a 100644 --- a/drivers/gpu/drm/bridge/lontium-lt9611.c +++ b/drivers/gpu/drm/bridge/lontium-lt9611.c @@ -1059,7 +1059,8 @@ static void lt9611_audio_shutdown(struct device *dev, void *data) } static int lt9611_hdmi_i2s_get_dai_id(struct snd_soc_component *component, - struct device_node *endpoint) + struct device_node *endpoint, + void *data) { struct of_endpoint of_ep; int ret; diff --git a/drivers/gpu/drm/bridge/lontium-lt9611uxc.c b/drivers/gpu/drm/bridge/lontium-lt9611uxc.c index 4e802b54a1cb..54c528fa168e 100644 --- a/drivers/gpu/drm/bridge/lontium-lt9611uxc.c +++ b/drivers/gpu/drm/bridge/lontium-lt9611uxc.c @@ -601,7 +601,8 @@ static void lt9611uxc_audio_shutdown(struct device *dev, void *data) } static int lt9611uxc_hdmi_i2s_get_dai_id(struct snd_soc_component *component, - struct device_node *endpoint) + struct device_node *endpoint, + void *data) { struct of_endpoint of_ep; int ret; diff --git a/drivers/gpu/drm/bridge/sii902x.c b/drivers/gpu/drm/bridge/sii902x.c index 7f91b0db161e..1883df5fd5c1 100644 --- a/drivers/gpu/drm/bridge/sii902x.c +++ b/drivers/gpu/drm/bridge/sii902x.c @@ -798,7 +798,8 @@ static int sii902x_audio_get_eld(struct device *dev, void *data, } static int sii902x_audio_get_dai_id(struct snd_soc_component *component, - struct device_node *endpoint) + struct device_node *endpoint, + void *data) { struct of_endpoint of_ep; int ret; diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-i2s-audio.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-i2s-audio.c index 26c187d20d97..86c412e9cbc8 100644 --- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-i2s-audio.c +++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-i2s-audio.c @@ -148,7 +148,8 @@ static int dw_hdmi_i2s_get_eld(struct device *dev, void *data, uint8_t *buf, } static int dw_hdmi_i2s_get_dai_id(struct snd_soc_component *component, - struct device_node *endpoint) + struct device_node *endpoint, + void *data) { struct of_endpoint of_ep; int ret; diff --git a/include/sound/hdmi-codec.h b/include/sound/hdmi-codec.h index 5e1a9eafd10f..b3407b47b4a7 100644 --- a/include/sound/hdmi-codec.h +++ b/include/sound/hdmi-codec.h @@ -105,7 +105,8 @@ struct hdmi_codec_ops { * Optional */ int (*get_dai_id)(struct snd_soc_component *comment, - struct device_node *endpoint); + struct device_node *endpoint, + void *data); /* * Hook callback function to handle connector plug event. diff --git a/sound/soc/codecs/hdmi-codec.c b/sound/soc/codecs/hdmi-codec.c index d3abb7ce2153..afad402122cb 100644 --- a/sound/soc/codecs/hdmi-codec.c +++ b/sound/soc/codecs/hdmi-codec.c @@ -981,7 +981,7 @@ static int hdmi_of_xlate_dai_id(struct snd_soc_component *component, int ret = -ENOTSUPP; /* see snd_soc_get_dai_id() */ if (hcp->hcd.ops->get_dai_id) - ret = hcp->hcd.ops->get_dai_id(component, endpoint); + ret = hcp->hcd.ops->get_dai_id(component, endpoint, hcp->hcd.data); return ret; } From patchwork Sat Jun 15 17:53:32 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dmitry Baryshkov X-Patchwork-Id: 13699346 Received: from mail-lf1-f53.google.com (mail-lf1-f53.google.com [209.85.167.53]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 630B626AD7 for ; Sat, 15 Jun 2024 17:53:38 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.167.53 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1718474020; cv=none; b=PYU5CTVCVWRdfGNGy8LyLj5gLUEliTUMYgQfvY++LA4hTw/D+llCPJF5ptMZY6sjov2DX2Cictw60k64olSEnA66pUHcibpotUFTponRwI8vxK1qjLWjSn4HfuHUj317n71KpsogkDlXHLBqWWnRtsFOl8Bf5AqoT1TPN3fPras= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1718474020; c=relaxed/simple; bh=K5vgL0vhPRPxQ6eViVsHTJN1OF+8i3TQQsnaweS4L10=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=qAgN3n7NHEGavDk9Jh05ytOEwerDbQebAm6p2C+XQdLkRYw4EYChrrtIJeN7X/KfwovvtTtGi1AUBm0dayG5SPxF/fHmQPvA9f28Ui1gW3eSWzy7RsYCHPcYLq/Ly2Uc7yt7U1k+9bwWO3tGkBFWJcnWSRpIOJmv3VnuQhwcCPI= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linaro.org; spf=pass smtp.mailfrom=linaro.org; dkim=pass (2048-bit key) header.d=linaro.org header.i=@linaro.org header.b=EUxEfXd9; arc=none smtp.client-ip=209.85.167.53 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linaro.org Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linaro.org Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=linaro.org header.i=@linaro.org header.b="EUxEfXd9" Received: by mail-lf1-f53.google.com with SMTP id 2adb3069b0e04-52bbdc237f0so3702040e87.0 for ; Sat, 15 Jun 2024 10:53:38 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; t=1718474016; x=1719078816; darn=vger.kernel.org; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:from:to:cc:subject:date:message-id :reply-to; bh=/ZP8ZmJRcZfMC764WUCJRbq634rGYP2EZWnL5wb9EkY=; b=EUxEfXd95M8idFdPeq31v/+VQXwoAmvPeyJ+jmi4hc34ZxgvL7fE43XTBt0FpvuD2D I/25qi7fZbxQMuXXCuaP1GL5AG8kmcYbzLcDZrWrVqagbQJmES8G1zwzBfzA+0lFzZNg cyuwEf7bhStM++Pz9yhP8mJdQktmjL12oSv2gvMKc+4tnnPRJ0+1jCs5APAC6AhPzpAF /tJ31Z1T7hcr1axhPW5lMaNO3BjUPui2RTCNWDvOH3aXK0wcB7lSROX8guok2CbHONAM KNgixLrcCOvjAg13F0n173kz8pWrafUSJjYykJzEpOHBUczoxTBv2MjSkHuO6o93r/bO B2aw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1718474016; x=1719078816; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=/ZP8ZmJRcZfMC764WUCJRbq634rGYP2EZWnL5wb9EkY=; b=ZRzRbl5LYALV0PY1r5J64H8FdXcb5I/TersLUTFAS1b0TpelGmkGnKtgPxuvNi2fHy Hx025g9g5RWbufv+tWKEwJx2aOz0xbqJ/bK5U3RST8kCdxca8zOwUFUiVsxkIbeoQG/G r/Gqlupg1X5TBmLQ9zwcaRWBtPc5YWKP9u59sJ4q51ekkAG22VB3y/ddQ2MyZ1DhE3wG bzBwNsQJJNbr0vde1446vdsYG1iGxQyw/KvszbBdq40cnckyek188JzW2O538RQK3mbA UPeVBth9F6rVK8Nig9DsChonvMRBdOr0VBxoBX6YfEuw6mY7F26Jjours2YpDk9VzN2G kqww== X-Forwarded-Encrypted: i=1; AJvYcCUh7mWs4Jt77bfHW7xMl+K9YaBq3uuAEGcxJfD3NYddim1ipNRlI0x1u43iM7hEATKWzFkM20XDcrpQFvuWdFsWPIMFoXzJg5V41KE= X-Gm-Message-State: AOJu0YyaPsXFqPZ99Ah4HJBUM/0mgfhXIGJKspkE4OSXMx0mT2pz4hUq 0vfcHea3aKhyB1/7oTZv26QneXNT3wkyBNxxMbnL14LEj5Kn3u1Qq64EAJ7lTeA= X-Google-Smtp-Source: AGHT+IHa8fs4DYvwjHxRGyKeDtJ0GQg9KFQnWvSFPwToS3LXMDqMAhg7ocLF67H+iIUSg/VAS5DoCQ== X-Received: by 2002:a05:6512:2255:b0:52b:9c8a:734f with SMTP id 2adb3069b0e04-52ca6e91af8mr5845407e87.50.1718474016331; Sat, 15 Jun 2024 10:53:36 -0700 (PDT) Received: from umbar.lan ([192.130.178.91]) by smtp.gmail.com with ESMTPSA id 2adb3069b0e04-52ca287affcsm799209e87.232.2024.06.15.10.53.35 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sat, 15 Jun 2024 10:53:35 -0700 (PDT) From: Dmitry Baryshkov Date: Sat, 15 Jun 2024 20:53:32 +0300 Subject: [PATCH RFC 3/5] drm/connector: implement generic HDMI codec helpers Precedence: bulk X-Mailing-List: linux-sound@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Message-Id: <20240615-drm-bridge-hdmi-connector-v1-3-d59fc7865ab2@linaro.org> References: <20240615-drm-bridge-hdmi-connector-v1-0-d59fc7865ab2@linaro.org> In-Reply-To: <20240615-drm-bridge-hdmi-connector-v1-0-d59fc7865ab2@linaro.org> To: Andrzej Hajda , Neil Armstrong , Robert Foss , Laurent Pinchart , Jonas Karlman , Jernej Skrabec , Maarten Lankhorst , Maxime Ripard , Thomas Zimmermann , David Airlie , Daniel Vetter , Jaroslav Kysela , Takashi Iwai , Liam Girdwood , Mark Brown Cc: dri-devel@lists.freedesktop.org, linux-kernel@vger.kernel.org, linux-sound@vger.kernel.org X-Mailer: b4 0.13.0 X-Developer-Signature: v=1; a=openpgp-sha256; l=10304; i=dmitry.baryshkov@linaro.org; h=from:subject:message-id; bh=K5vgL0vhPRPxQ6eViVsHTJN1OF+8i3TQQsnaweS4L10=; b=owEBbQGS/pANAwAKAYs8ij4CKSjVAcsmYgBmbdUccz+HSNoVnSr42Tp+fFI4KjEGOXkgx4ODh ETmC2gqoM6JATMEAAEKAB0WIQRMcISVXLJjVvC4lX+LPIo+Aiko1QUCZm3VHAAKCRCLPIo+Aiko 1d6UB/9tFOqKTD7wciyiUTwx6S8CIOsT77Re4jFxGQXDqa9oYP9IGx3yewxbxc5xowSI8FUnfAv OVg+IuK52MuBViqn5928WdDWTxiU2F8m0t7mUYZV65EqTkzR3PUv57NMeJoJE3y3TuOyXlIng5p pyLqhwnzbPHqies3C4QHcrOdiBlQobWfktvm5q1CwGBeX8e0i3EDUK8SaVdfIIjM88fVFBIaZlB Q7FXKM90U7bi5Dw9ardLbuU9MFDIMsxRxHBFnV5kYIVp+yJg9kovyoOjUNyLYgQec95X9FCbCBH sgGinR58x5ueD3dilzFZznoqaa0DRYpi4KyA/J3wAtIWpRir X-Developer-Key: i=dmitry.baryshkov@linaro.org; a=openpgp; fpr=8F88381DD5C873E4AE487DA5199BF1243632046A X-Patchwork-State: RFC Several DRM drivers implement HDMI codec support (despite its name it applies to both HDMI and DisplayPort drivers). Implement generic framework to be used by these drivers. This removes a requirement to implement get_eld() callback and provides default implementation for codec's plug handling. The framework is integrated with the DRM HDMI Connector framework, but can be used by DisplayPort drivers. Signed-off-by: Dmitry Baryshkov --- drivers/gpu/drm/Makefile | 1 + drivers/gpu/drm/drm_connector.c | 8 ++ drivers/gpu/drm/drm_connector_hdmi_codec.c | 157 +++++++++++++++++++++++++++++ include/drm/drm_connector.h | 33 ++++++ 4 files changed, 199 insertions(+) diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile index 68cc9258ffc4..e113a6eade23 100644 --- a/drivers/gpu/drm/Makefile +++ b/drivers/gpu/drm/Makefile @@ -45,6 +45,7 @@ drm-y := \ drm_client_modeset.o \ drm_color_mgmt.o \ drm_connector.o \ + drm_connector_hdmi_codec.o \ drm_crtc.o \ drm_displayid.o \ drm_drv.o \ diff --git a/drivers/gpu/drm/drm_connector.c b/drivers/gpu/drm/drm_connector.c index 3d73a981004c..66d6e9487339 100644 --- a/drivers/gpu/drm/drm_connector.c +++ b/drivers/gpu/drm/drm_connector.c @@ -279,6 +279,7 @@ static int __drm_connector_init(struct drm_device *dev, mutex_init(&connector->mutex); mutex_init(&connector->edid_override_mutex); mutex_init(&connector->hdmi.infoframes.lock); + mutex_init(&connector->hdmi_codec.lock); connector->edid_blob_ptr = NULL; connector->epoch_counter = 0; connector->tile_blob_ptr = NULL; @@ -529,6 +530,12 @@ int drmm_connector_hdmi_init(struct drm_device *dev, connector->hdmi.funcs = hdmi_funcs; + if (connector->hdmi_codec.i2s || connector->hdmi_codec.spdif) { + ret = drmm_connector_hdmi_codec_alloc(dev, connector, hdmi_funcs->codec_ops); + if (ret) + return ret; + } + return 0; } EXPORT_SYMBOL(drmm_connector_hdmi_init); @@ -665,6 +672,7 @@ void drm_connector_cleanup(struct drm_connector *connector) connector->funcs->atomic_destroy_state(connector, connector->state); + mutex_destroy(&connector->hdmi_codec.lock); mutex_destroy(&connector->hdmi.infoframes.lock); mutex_destroy(&connector->mutex); diff --git a/drivers/gpu/drm/drm_connector_hdmi_codec.c b/drivers/gpu/drm/drm_connector_hdmi_codec.c new file mode 100644 index 000000000000..a3a7ad117f6f --- /dev/null +++ b/drivers/gpu/drm/drm_connector_hdmi_codec.c @@ -0,0 +1,157 @@ +/* + * Copyright (c) 2024 Linaro Ltd + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that copyright + * notice and this permission notice appear in supporting documentation, and + * that the name of the copyright holders not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. The copyright holders make no representations + * about the suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +#include +#include + +#include +#include + +#include + +static int drm_connector_hdmi_codec_get_eld(struct device *dev, void *data, + uint8_t *buf, size_t len) +{ + struct drm_connector *connector = data; + + // FIXME: locking against drm_edid_to_eld ? + memcpy(buf, connector->eld, min(sizeof(connector->eld), len)); + + return 0; +} + +static int drm_connector_hdmi_codec_hook_plugged_cb(struct device *dev, + void *data, + hdmi_codec_plugged_cb fn, + struct device *codec_dev) +{ + struct drm_connector *connector = data; + + mutex_lock(&connector->hdmi_codec.lock); + + connector->hdmi_codec.plugged_cb = fn; + connector->hdmi_codec.plugged_cb_dev = codec_dev; + + fn(codec_dev, connector->hdmi_codec.last_state); + + mutex_unlock(&connector->hdmi_codec.lock); + + return 0; +} + +void drm_connector_hdmi_codec_plugged_notify(struct drm_connector *connector, + bool plugged) +{ + mutex_lock(&connector->hdmi_codec.lock); + + connector->hdmi_codec.last_state = plugged; + + if (connector->hdmi_codec.plugged_cb && + connector->hdmi_codec.plugged_cb_dev) + connector->hdmi_codec.plugged_cb(connector->hdmi_codec.plugged_cb_dev, + connector->hdmi_codec.last_state); + + mutex_unlock(&connector->hdmi_codec.lock); +} +EXPORT_SYMBOL(drm_connector_hdmi_codec_plugged_notify); + +static void drm_connector_hdmi_codec_cleanup_action(struct drm_device *dev, + void *ptr) +{ + struct platform_device *pdev = ptr; + + platform_device_unregister(pdev); +} + +/** + * drmm_connector_hdmi_alloc - Allocate HDMI Codec device for the DRM connector + * @dev: DRM device + * @connector: A pointer to the connector to allocate codec for + * @ops: callbacks for this connector + * + * Create a HDMI codec device to be used with the specified connector. + * + * Cleanup is automatically handled with in a DRM-managed action. + * + * The connector structure should be allocated with drmm_kzalloc(). + * + * Returns: + * Zero on success, error code on failure. + */ +int drmm_connector_hdmi_codec_alloc(struct drm_device *dev, + struct drm_connector *connector, + const struct hdmi_codec_ops *base_ops) +{ + struct hdmi_codec_pdata codec_pdata = {}; + struct platform_device *pdev; + struct hdmi_codec_ops *ops; + int ret; + + ops = drmm_kmalloc(dev, sizeof(*ops), GFP_KERNEL); + if (!ops) + return -ENOMEM; + + *ops = *base_ops; + + ops->get_eld = drm_connector_hdmi_codec_get_eld; + ops->hook_plugged_cb = drm_connector_hdmi_codec_hook_plugged_cb; + + codec_pdata.ops = ops; + codec_pdata.i2s = connector->hdmi_codec.i2s, + codec_pdata.spdif = connector->hdmi_codec.spdif, + codec_pdata.max_i2s_channels = connector->hdmi_codec.max_i2s_channels, + codec_pdata.data = connector; + + pdev = platform_device_register_data(connector->hdmi_codec.parent_dev, + HDMI_CODEC_DRV_NAME, + PLATFORM_DEVID_AUTO, + &codec_pdata, sizeof(codec_pdata)); + if (IS_ERR(pdev)) + return PTR_ERR(pdev); + + ret = drmm_add_action_or_reset(dev, drm_connector_hdmi_codec_cleanup_action, pdev); + if (ret) + return ret; + + connector->hdmi_codec.codec_pdev = pdev; + + return 0; +} +EXPORT_SYMBOL(drmm_connector_hdmi_codec_alloc); + +/** + * drmm_connector_hdmi_codec_free - rollback drmm_connector_hdmi_codec_alloc + * @dev: DRM device + * @hdmi_codec: A pointer to the HDMI codec data + * + * Rollback the drmm_connector_hdmi_codec_alloc() and free allocated data. + * While this function should not be necessary for a typical driver, DRM bridge + * drivers have to call it from the remove callback if the bridge uses + * Connector's HDMI Codec interface. + */ +void drmm_connector_hdmi_codec_free(struct drm_device *dev, + struct drm_connector_hdmi_codec *hdmi_codec) +{ + drmm_release_action(dev, drm_connector_hdmi_codec_cleanup_action, + hdmi_codec->codec_pdev); +} +EXPORT_SYMBOL(drmm_connector_hdmi_codec_free); diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h index f750765d8fbc..0eb8d8ed9495 100644 --- a/include/drm/drm_connector.h +++ b/include/drm/drm_connector.h @@ -46,6 +46,7 @@ struct drm_property_blob; struct drm_printer; struct drm_privacy_screen; struct edid; +struct hdmi_codec_ops; struct i2c_adapter; enum drm_connector_force { @@ -1199,6 +1200,8 @@ struct drm_connector_hdmi_funcs { int (*write_infoframe)(struct drm_connector *connector, enum hdmi_infoframe_type type, const u8 *buffer, size_t len); + + const struct hdmi_codec_ops *codec_ops; }; /** @@ -1706,6 +1709,22 @@ struct drm_connector_hdmi { } infoframes; }; +struct drm_connector_hdmi_codec { + struct device *parent_dev; + struct platform_device *codec_pdev; + + const struct drm_connector_hdmi_codec_funcs *funcs; + + struct mutex lock; /* protects last_state and plugged_cb */ + void (*plugged_cb)(struct device *dev, bool plugged); + struct device *plugged_cb_dev; + bool last_state; + + int max_i2s_channels; + uint i2s: 1; + uint spdif: 1; +}; + /** * struct drm_connector - central DRM connector control structure * @@ -2119,6 +2138,12 @@ struct drm_connector { * @hdmi: HDMI-related variable and properties. */ struct drm_connector_hdmi hdmi; + + /** + * @hdmi_codec: HDMI codec properties and variables. Also might be used + * for DisplayPort audio. + */ + struct drm_connector_hdmi_codec hdmi_codec; }; #define obj_to_connector(x) container_of(x, struct drm_connector, base) @@ -2152,6 +2177,14 @@ void drm_connector_unregister(struct drm_connector *connector); int drm_connector_attach_encoder(struct drm_connector *connector, struct drm_encoder *encoder); +int drmm_connector_hdmi_codec_alloc(struct drm_device *dev, + struct drm_connector *connector, + const struct hdmi_codec_ops *ops); +void drmm_connector_hdmi_codec_free(struct drm_device *dev, + struct drm_connector_hdmi_codec *codec); +void drm_connector_hdmi_codec_plugged_notify(struct drm_connector *connector, + bool plugged); + void drm_connector_cleanup(struct drm_connector *connector); static inline unsigned int drm_connector_index(const struct drm_connector *connector) From patchwork Sat Jun 15 17:53:33 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dmitry Baryshkov X-Patchwork-Id: 13699347 Received: from mail-lf1-f46.google.com (mail-lf1-f46.google.com [209.85.167.46]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id E12075380F for ; Sat, 15 Jun 2024 17:53:38 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.167.46 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1718474021; cv=none; b=r+qNBxfenh8O+mhnRewV+Nal6JNydLR4SalZ8gcDPjfnVDipKtpcC1QgY30QAP6WJFTQ5uBLY5wYtZPCA61r+MHASWaRN+Wi7ovV+rYLVYoajDWbTCTjNDc5JjGbuNbZ9Gu3Jjr6p2FGNRPfpLms8xHATiKHUQhajpqN0h+RBY4= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1718474021; c=relaxed/simple; bh=9qyJ3spGDjMnMxvSzQbD6SgbbMB2IHj4AFz00AeF73Y=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=Hos+7GNz7QRhnfRkMtjUohoFksul7ApiwZsYe1T0zKxdIP3sHwP6H7WuIGIupmXDGC/9TpCqxfg4EmhGhYjS4x4v+RxWdERv2hp8x0bdW1FxAN16NEfKLD42Rnah/bIdOD0NUv2ZKZAGeXrLQmP2mIQRk5r1bJdkcbfeqtB942E= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linaro.org; spf=pass smtp.mailfrom=linaro.org; dkim=pass (2048-bit key) header.d=linaro.org header.i=@linaro.org header.b=RlFTU/q1; arc=none smtp.client-ip=209.85.167.46 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linaro.org Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linaro.org Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=linaro.org header.i=@linaro.org header.b="RlFTU/q1" Received: by mail-lf1-f46.google.com with SMTP id 2adb3069b0e04-52c32d934c2so3526910e87.2 for ; Sat, 15 Jun 2024 10:53:38 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; t=1718474017; x=1719078817; darn=vger.kernel.org; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:from:to:cc:subject:date:message-id :reply-to; bh=zagial1Hqf0gQMJ4r3bBETUYdf9xoObT6u8X513CE/c=; b=RlFTU/q1uywMr6Dt1bLJQxh7RKmpmnS/QdmL9mCeI5TtCiFDnDpcZ3Of3/q/p7K26u 715w48qmLK7rCr6XOj1Sv+s9FKSbqcky1Jcner77oohAM/aX4BqVqA57GoXLIz2Zut/Z /tQtnWqsSZzhowoLPkM6FDjpnxR37mkEzcU7SDdYn7kTAcMwCFQHNNLoIIGPmj3kvEV0 gJCLoRek7/lhTriRq9WBkBHsZ6Et3yatrHrhnPIpx110EXmuo21YH7Yh0pcgodx5Rsdm BH+tRuMMBTWipaeEl5kwyAwF2eBZG3qEbDhs7XIBRlH25MCy2EvhtkTVoGCTU+8WG5YU zQkg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1718474017; x=1719078817; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=zagial1Hqf0gQMJ4r3bBETUYdf9xoObT6u8X513CE/c=; b=KNboyGZQyplKzzTVuLY6SMFYRfg1/yc2xzfmpE4pE4aKE133ymipm2Mzze4UWDgtAS Tbwoe8GiOFve9V+RQO/2anpNESolH1E7jPuJh0RzSjwpA2Ji9Cd6CDxzDS6FQUrbwsib 45x+lUk+lyC6lDOuZUIXF/t70kZ3jIrKZmIZkZxR+Y57BM/tvJrjdn+whSeiccHBm2F3 oPb2JPyIg3R076M9pkI4hxL2BD0Vb0nzbwZiHcajiYpdq8X3VRdkpiuxZGOzQHrWmkzo LqRKDexrOHltczavEgre2VRZJvjzlS1JkWHTd32U9eBOEuNxeAE812KHrozP4rTohKxB Vv3w== X-Forwarded-Encrypted: i=1; AJvYcCWTD30O+ERj8zSvjHMZsjOxwIW9YqzJYTDSfidrb5tI0uZfT+zcgNF87DmmFSAlMNvhTDOLjYaqnBRrhhMrZVQCjhimYbJZxScGt20= X-Gm-Message-State: AOJu0YxJLN6NWlxmKozuylJkA2rptZrVqxnM0s2TBvLO4qAHRTBIjRWg 2UpP6y8nCUDb4um3k+yoaaAyCLZ4iCkzDWlmqQjQowEn+k0vJYP6bDsO30dqAF8= X-Google-Smtp-Source: AGHT+IGEa6fYbnm8utLHEy/SZhPk/cQQ3mFskFXipOhkauxiVqiW0GWVOkOCWGj8UKZuDXRIYXPRdQ== X-Received: by 2002:a19:ac03:0:b0:52c:4cfa:c5a6 with SMTP id 2adb3069b0e04-52ca6e6d56dmr2918061e87.34.1718474017042; Sat, 15 Jun 2024 10:53:37 -0700 (PDT) Received: from umbar.lan ([192.130.178.91]) by smtp.gmail.com with ESMTPSA id 2adb3069b0e04-52ca287affcsm799209e87.232.2024.06.15.10.53.36 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sat, 15 Jun 2024 10:53:36 -0700 (PDT) From: Dmitry Baryshkov Date: Sat, 15 Jun 2024 20:53:33 +0300 Subject: [PATCH RFC 4/5] drm/bridge: connector: add support for HDMI codec framework Precedence: bulk X-Mailing-List: linux-sound@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Message-Id: <20240615-drm-bridge-hdmi-connector-v1-4-d59fc7865ab2@linaro.org> References: <20240615-drm-bridge-hdmi-connector-v1-0-d59fc7865ab2@linaro.org> In-Reply-To: <20240615-drm-bridge-hdmi-connector-v1-0-d59fc7865ab2@linaro.org> To: Andrzej Hajda , Neil Armstrong , Robert Foss , Laurent Pinchart , Jonas Karlman , Jernej Skrabec , Maarten Lankhorst , Maxime Ripard , Thomas Zimmermann , David Airlie , Daniel Vetter , Jaroslav Kysela , Takashi Iwai , Liam Girdwood , Mark Brown Cc: dri-devel@lists.freedesktop.org, linux-kernel@vger.kernel.org, linux-sound@vger.kernel.org X-Mailer: b4 0.13.0 X-Developer-Signature: v=1; a=openpgp-sha256; l=9543; i=dmitry.baryshkov@linaro.org; h=from:subject:message-id; bh=9qyJ3spGDjMnMxvSzQbD6SgbbMB2IHj4AFz00AeF73Y=; b=owEBbQGS/pANAwAKAYs8ij4CKSjVAcsmYgBmbdUcWcZAmhsCIb/4ABEiX4VMbOdSHnfRGXU8u fYxUsRmrqKJATMEAAEKAB0WIQRMcISVXLJjVvC4lX+LPIo+Aiko1QUCZm3VHAAKCRCLPIo+Aiko 1Wn7B/9NCdiqRayjQzUJ96ROIBhJzPiJOV57jaUlAdNu3hJjoZ5puOTfUggvMYIEAX5A1COiTij EDJ3SGQOfuShfl4KDkAQ1aBYHcH6ixE51266YpAPZiXZk/pz2Ooz4WL5S5KnHyYQ1Pcox0SI2KA Cn45B1QSWmYRGU6p5iIA5/Fh9QktxJp/TLrD7y7nriECTfmQrfu3MGIeU7E1WyIjfEx5j2sjhBn h2xtHgqRE2HUxmD9Fpjo6kDbIGMOiH01hNDdR8UNvSBapRJdsNGlIs+SMzenqdu7xjB8nLDHb6X EF2B2Axwv6XTFp+BfFlA0OnJTZBJJc9qufqHHmHjGlOULXbJ X-Developer-Key: i=dmitry.baryshkov@linaro.org; a=openpgp; fpr=8F88381DD5C873E4AE487DA5199BF1243632046A X-Patchwork-State: RFC Add necessary glue code to be able to use new HDMI codec framework from the DRM bridge drivers. The drm_bridge implements a limited set of the hdmi_codec_ops interface, with the functions accepting both drm_connector and drm_bridge instead of just a generic void pointer. This framework is integrated with the DRM HDMI Connector framework, but can also be used for DisplayPort connectors. Signed-off-by: Dmitry Baryshkov --- drivers/gpu/drm/drm_bridge_connector.c | 130 ++++++++++++++++++++++++++++++++- include/drm/drm_bridge.h | 46 ++++++++++++ 2 files changed, 174 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/drm_bridge_connector.c b/drivers/gpu/drm/drm_bridge_connector.c index 0869b663f17e..71d6fdc2391f 100644 --- a/drivers/gpu/drm/drm_bridge_connector.c +++ b/drivers/gpu/drm/drm_bridge_connector.c @@ -20,6 +20,8 @@ #include #include +#include + /** * DOC: overview * @@ -95,6 +97,14 @@ struct drm_bridge_connector { * HDMI connector infrastructure, if any (see &DRM_BRIDGE_OP_HDMI). */ struct drm_bridge *bridge_hdmi; + /** + * @bridge_hdmi_codec: + * + * The bridge in the chain that implements necessary support for the + * HDMI Audio Codec infrastructure, if any (see + * &DRM_BRIDGE_OP_HDMI_CODEC). + */ + struct drm_bridge *bridge_hdmi_codec; }; #define to_drm_bridge_connector(x) \ @@ -343,10 +353,104 @@ static int drm_bridge_connector_write_infoframe(struct drm_connector *connector, return bridge->funcs->hdmi_write_infoframe(bridge, type, buffer, len); } +static int drm_bridge_connector_audio_startup(struct device *dev, void *data) +{ + struct drm_connector *connector = data; + struct drm_bridge_connector *bridge_connector = + to_drm_bridge_connector(connector); + struct drm_bridge *bridge; + + bridge = bridge_connector->bridge_hdmi_codec; + if (!bridge) + return -EINVAL; + + if (bridge->funcs->hdmi_codec_audio_startup) + return bridge->funcs->hdmi_codec_audio_startup(dev, connector, bridge); + else + return 0; +} + +static int drm_bridge_connector_prepare(struct device *dev, void *data, + struct hdmi_codec_daifmt *fmt, + struct hdmi_codec_params *hparms) +{ + struct drm_connector *connector = data; + struct drm_bridge_connector *bridge_connector = + to_drm_bridge_connector(connector); + struct drm_bridge *bridge; + + bridge = bridge_connector->bridge_hdmi_codec; + if (!bridge) + return -EINVAL; + + return bridge->funcs->hdmi_codec_prepare(dev, connector, bridge, fmt, hparms); +} + +static void drm_bridge_connector_audio_shutdown(struct device *dev, void *data) +{ + struct drm_connector *connector = data; + struct drm_bridge_connector *bridge_connector = + to_drm_bridge_connector(connector); + struct drm_bridge *bridge; + + bridge = bridge_connector->bridge_hdmi_codec; + if (!bridge) + return; + + bridge->funcs->hdmi_codec_audio_shutdown(dev, connector, bridge); +} + +static int drm_bridge_connector_mute_stream(struct device *dev, void *data, + bool enable, int direction) +{ + struct drm_connector *connector = data; + struct drm_bridge_connector *bridge_connector = + to_drm_bridge_connector(connector); + struct drm_bridge *bridge; + + bridge = bridge_connector->bridge_hdmi_codec; + if (!bridge) + return -EINVAL; + + if (bridge->funcs->hdmi_codec_mute_stream) + return bridge->funcs->hdmi_codec_mute_stream(dev, connector, bridge, + enable, direction); + else + return -ENOTSUPP; +} + +static int drm_bridge_connector_get_dai_id(struct snd_soc_component *comment, + struct device_node *endpoint, + void *data) +{ + struct drm_connector *connector = data; + struct drm_bridge_connector *bridge_connector = + to_drm_bridge_connector(connector); + struct drm_bridge *bridge; + + bridge = bridge_connector->bridge_hdmi_codec; + if (!bridge) + return -EINVAL; + + if (bridge->funcs->hdmi_codec_get_dai_id) + return bridge->funcs->hdmi_codec_get_dai_id(connector, bridge, endpoint); + else + return -ENOTSUPP; +} + +static const struct hdmi_codec_ops drm_bridge_connector_hdmi_codec_ops = { + .audio_startup = drm_bridge_connector_audio_startup, + .prepare = drm_bridge_connector_prepare, + .audio_shutdown = drm_bridge_connector_audio_shutdown, + .mute_stream = drm_bridge_connector_mute_stream, + .get_dai_id = drm_bridge_connector_get_dai_id, +}; + static const struct drm_connector_hdmi_funcs drm_bridge_connector_hdmi_funcs = { .tmds_char_rate_valid = drm_bridge_connector_tmds_char_rate_valid, .clear_infoframe = drm_bridge_connector_clear_infoframe, .write_infoframe = drm_bridge_connector_write_infoframe, + .codec_ops = &drm_bridge_connector_hdmi_codec_ops, }; /* ----------------------------------------------------------------------------- @@ -427,6 +531,23 @@ struct drm_connector *drm_bridge_connector_init(struct drm_device *drm, max_bpc = bridge->max_bpc; } + if (bridge->ops & DRM_BRIDGE_OP_HDMI_CODEC) { + if (bridge_connector->bridge_hdmi_codec) + return ERR_PTR(-EBUSY); + if (!bridge->funcs->hdmi_codec_prepare || + !bridge->funcs->hdmi_codec_audio_shutdown) + return ERR_PTR(-EINVAL); + + bridge_connector->bridge_hdmi_codec = bridge; + + connector->hdmi_codec.parent_dev = bridge->parent; + connector->hdmi_codec.i2s = bridge->hdmi_codec_i2s; + connector->hdmi_codec.spdif = bridge->hdmi_codec_spdif; + connector->hdmi_codec.max_i2s_channels = bridge->max_i2s_channels; + + bridge->hdmi_codec = &connector->hdmi_codec; + } + if (!drm_bridge_get_next_bridge(bridge)) connector_type = bridge->type; @@ -448,7 +569,7 @@ struct drm_connector *drm_bridge_connector_init(struct drm_device *drm, return ERR_PTR(-EINVAL); } - if (bridge_connector->bridge_hdmi) + if (bridge_connector->bridge_hdmi) { ret = drmm_connector_hdmi_init(drm, connector, bridge_connector->bridge_hdmi->vendor, bridge_connector->bridge_hdmi->product, @@ -457,10 +578,15 @@ struct drm_connector *drm_bridge_connector_init(struct drm_device *drm, connector_type, ddc, supported_formats, max_bpc); - else + } else { ret = drmm_connector_init(drm, connector, &drm_bridge_connector_funcs, connector_type, ddc); + if (!ret && bridge_connector->bridge_hdmi_codec) { + ret = drmm_connector_hdmi_codec_alloc(drm, connector, + &drm_bridge_connector_hdmi_codec_ops); + } + } if (ret) { kfree(bridge_connector); return ERR_PTR(ret); diff --git a/include/drm/drm_bridge.h b/include/drm/drm_bridge.h index 75019d16be64..c4a95c489b00 100644 --- a/include/drm/drm_bridge.h +++ b/include/drm/drm_bridge.h @@ -41,6 +41,8 @@ struct drm_display_info; struct drm_minor; struct drm_panel; struct edid; +struct hdmi_codec_daifmt; +struct hdmi_codec_params; struct i2c_adapter; /** @@ -676,6 +678,29 @@ struct drm_bridge_funcs { enum hdmi_infoframe_type type, const u8 *buffer, size_t len); + int (*hdmi_codec_audio_startup)(struct device *dev, + struct drm_connector *connector, + struct drm_bridge *bridge); + + int (*hdmi_codec_prepare)(struct device *dev, + struct drm_connector *connector, + struct drm_bridge *bridge, + struct hdmi_codec_daifmt *fmt, + struct hdmi_codec_params *hparms); + + void (*hdmi_codec_audio_shutdown)(struct device *dev, + struct drm_connector *connector, + struct drm_bridge *bridge); + + int (*hdmi_codec_mute_stream)(struct device *dev, + struct drm_connector *connector, + struct drm_bridge *bridge, + bool enable, int direction); + + int (*hdmi_codec_get_dai_id)(struct drm_connector *connector, + struct drm_bridge *bridge, + struct device_node *endpoint); + /** * @debugfs_init: * @@ -761,6 +786,20 @@ enum drm_bridge_ops { * drivers. */ DRM_BRIDGE_OP_HDMI = BIT(4), + /** + * @DRM_BRIDGE_OP_HDMI_CODEC: The bridge provides HDMI Audio Codec + * operations. Bridges that set this flag must implement the + * &drm_bridge_funcs->hdmi_codec_prepare and + * &drm_bridge_funcs->hdmi_codec_audio_shutdown callbacks and set the + * relevant field in the &drm_bridge structure. + * + * This framework can be used by both HDMI and DisplayPort bridges. + * + * Note: currently there can be at most one bridge in a chain that sets + * this bit. This is to simplify corresponding glue code in connector + * drivers. + */ + DRM_BRIDGE_OP_HDMI_CODEC = BIT(5), }; /** @@ -771,6 +810,8 @@ struct drm_bridge { struct drm_private_obj base; /** @dev: DRM device this bridge belongs to */ struct drm_device *dev; + /** @parent: device corresponding to the bridge, required only for HDMI codec */ + struct device *parent; /** @encoder: encoder to which this bridge is connected */ struct drm_encoder *encoder; /** @chain_node: used to form a bridge chain */ @@ -854,6 +895,11 @@ struct drm_bridge { * @DRM_BRIDGE_OP_HDMI is set. */ unsigned int max_bpc; + + int max_i2s_channels; + unsigned int hdmi_codec_i2s : 1; + unsigned int hdmi_codec_spdif : 1; + struct drm_connector_hdmi_codec *hdmi_codec; }; static inline struct drm_bridge * From patchwork Sat Jun 15 17:53:34 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dmitry Baryshkov X-Patchwork-Id: 13699348 Received: from mail-lf1-f48.google.com (mail-lf1-f48.google.com [209.85.167.48]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id A15E95812F for ; Sat, 15 Jun 2024 17:53:39 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.167.48 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1718474023; cv=none; b=TanZXNzOQZsAldBw9IkUcBwAfrSy2aroxxRNcln+7A9+H3IqHQ+SkQig0YEUwHHsQnNlhCLySXYe9B89NuAYRUgbnPUCJQ7/1wZt9MbD5jGgqZYiFeIWufHuiTsoASuxwuPbB7/r9Pt3gYb3pg11B8h2Ye/rnM49gL1qUkBiqcc= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1718474023; c=relaxed/simple; bh=pg+NRAC0FNupuz6uv3BfUWUNO6rGMBpHZpbeR8Kzwy0=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=LR556dhCtRpKUcYRBEL74AOIu4DAoId8jsA3Si1RlqCiJrhH8mUL697kSnd/62qoceai/lvZsBL/p4V72JWOpW6+cfdF73VWzxr4IcFcQnxNDgzGnKjTaXo2PwQVckeZ86xOumFOL9zBtFv1zN7N1YvXRCsJL+t8RQ+gyIY++Sc= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linaro.org; spf=pass smtp.mailfrom=linaro.org; dkim=pass (2048-bit key) header.d=linaro.org header.i=@linaro.org header.b=wQMA219A; arc=none smtp.client-ip=209.85.167.48 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linaro.org Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linaro.org Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=linaro.org header.i=@linaro.org header.b="wQMA219A" Received: by mail-lf1-f48.google.com with SMTP id 2adb3069b0e04-52c32d934c2so3526921e87.2 for ; Sat, 15 Jun 2024 10:53:39 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; t=1718474018; x=1719078818; darn=vger.kernel.org; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:from:to:cc:subject:date:message-id :reply-to; bh=BNoqJV99DpCpKEKBVdbTZULLg3yGlQIJ3RlKgG+D6Ow=; b=wQMA219Ahl9yo+aAneW1SLw3btVQ85Y8goHPPtEYf2oWfguObeaQBvzYfCtinHkeW6 Huty4sc3cAsrmNV8jHgbZM1Ytm/EP5XI868OMA50ONdgTSjqSejgTW7gqJ1TCe6ddfnU lljtjqi1tl+3O+PsYomXODYc+iG/D4sAlr9PgoiFT917Uy1D2fIX8IFQwTfWV0rh31Ra CiiFCls0hAb3pSnC6zLosA6nbVeblmChnACOWpbJpC/UEM2TxE221GAkt73c+0YzhX17 v82dqPJL2e/EBBGhNdSOALUpxxVpyHXSAigypM6HplKaYp+47pFge1oV3FAvw63I0RPu Rgag== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1718474018; x=1719078818; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=BNoqJV99DpCpKEKBVdbTZULLg3yGlQIJ3RlKgG+D6Ow=; b=LpH+aHYOey2J5/PHVE0Ic57Hxdak1BDvbZ+qjfw9q0UExiAd/Al2/8kHDhplW2c9z/ GmrcXuoE8l9GWVKJdYOzapy8wZ3OOcUKkhyxrfe2KfinED4AS/5+Z1w9HoRRJNaMI6mV z7C1ayjaWEwqwLvnonmUUHBvFxFfjWQuxc3qCVL01nEMAAoJLFa34iNuRcHMGk76d2sS Vu2KMYE5AwfexyvAQlQwJ42hdqmfs05d8OPlkNhy82P8uu2BAu3tQJv7W+y9yWEYBGsl F2ll+R7dM16vLEdMjet0O+8rfUCVtpTUkdbriKfEn++B1KKxQCN2LUajndLy7gNmyVm6 D5Kw== X-Forwarded-Encrypted: i=1; AJvYcCUKJGDd67ry9Y1G1I1+xvsEv7v2hCjLci65fyDIKXQkQ8TuLu98dE6ISPLH+A6+xVl2NpYov+KsGlV0XfmxckOmPJdG8odX2GFWOgY= X-Gm-Message-State: AOJu0YwMtmfXYoNi5ELiZisHUuTXg+czgcNWcWOGXBGWXE8zMAzTtJug 0Y57XwFjsLzU7U4Y0Z72lh6KHzo+8evq24zMNeZN4W59rI2K8zaC80WvZDG24gJH4KWHcb3zQNc qlHw= X-Google-Smtp-Source: AGHT+IGMV2nV7xKWzH/4jIfi24E5+YGvRngTLXuMdzhfRlPyiUnBTAiPzEX2D9ECyNJt1xnPR/7s5Q== X-Received: by 2002:ac2:53a7:0:b0:52c:84b0:bd21 with SMTP id 2adb3069b0e04-52ca6e653femr3874949e87.16.1718474017740; Sat, 15 Jun 2024 10:53:37 -0700 (PDT) Received: from umbar.lan ([192.130.178.91]) by smtp.gmail.com with ESMTPSA id 2adb3069b0e04-52ca287affcsm799209e87.232.2024.06.15.10.53.37 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sat, 15 Jun 2024 10:53:37 -0700 (PDT) From: Dmitry Baryshkov Date: Sat, 15 Jun 2024 20:53:34 +0300 Subject: [PATCH RFC 5/5] drm/bridge: lt9611: switch to using the DRM HDMI codec framework Precedence: bulk X-Mailing-List: linux-sound@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Message-Id: <20240615-drm-bridge-hdmi-connector-v1-5-d59fc7865ab2@linaro.org> References: <20240615-drm-bridge-hdmi-connector-v1-0-d59fc7865ab2@linaro.org> In-Reply-To: <20240615-drm-bridge-hdmi-connector-v1-0-d59fc7865ab2@linaro.org> To: Andrzej Hajda , Neil Armstrong , Robert Foss , Laurent Pinchart , Jonas Karlman , Jernej Skrabec , Maarten Lankhorst , Maxime Ripard , Thomas Zimmermann , David Airlie , Daniel Vetter , Jaroslav Kysela , Takashi Iwai , Liam Girdwood , Mark Brown Cc: dri-devel@lists.freedesktop.org, linux-kernel@vger.kernel.org, linux-sound@vger.kernel.org X-Mailer: b4 0.13.0 X-Developer-Signature: v=1; a=openpgp-sha256; l=9303; i=dmitry.baryshkov@linaro.org; h=from:subject:message-id; bh=pg+NRAC0FNupuz6uv3BfUWUNO6rGMBpHZpbeR8Kzwy0=; b=owEBbQGS/pANAwAKAYs8ij4CKSjVAcsmYgBmbdUdiPOrd2HtCz9fm5aEflYaOE/wUAWKLvFrG 2NyaQ0z1OWJATMEAAEKAB0WIQRMcISVXLJjVvC4lX+LPIo+Aiko1QUCZm3VHQAKCRCLPIo+Aiko 1RkRCACS1kFdCiPQG5o+eQXNCAkRvuZZavw4HRwK4olL+TOkKtgLKWSlo/rhMujreuc3g3c/O/f vBcgurnu5awKebMRausxudvE9PfQpVjiw03oPbe0kyiLzFfJdsDU9POGTpghbjxbPHjZFtuRAqO 8T9ZuX3fGExcwdHWSUK35XWJwIaflRa9Ufgfr/d7cEEYYq/OhU1oZNjqW2Y8aQ2pLI4Vqn/Dt61 Re3KfBJm+lgUY24J4oJA+SQUSh5n5SjVBS8Ydfs5nPae63MY/hjZ105SOmEk2BBcWOJBwxqsR5h 781wwoauK61FcgzAwJk35MePBiQbYuk+2uSBxqbqE0CCBsUJ X-Developer-Key: i=dmitry.baryshkov@linaro.org; a=openpgp; fpr=8F88381DD5C873E4AE487DA5199BF1243632046A X-Patchwork-State: RFC Make the Lontium LT9611 DSI-to-HDMI bridge driver use the DRM HDMI Codec framework. This enables programming of Audio InfoFrames using the HDMI Connector interface and also enables support for the missing features, including the ELD retrieval and better hotplug support. Signed-off-by: Dmitry Baryshkov --- drivers/gpu/drm/bridge/lontium-lt9611.c | 207 ++++++++++++++++---------------- 1 file changed, 104 insertions(+), 103 deletions(-) diff --git a/drivers/gpu/drm/bridge/lontium-lt9611.c b/drivers/gpu/drm/bridge/lontium-lt9611.c index 4fa0dfc5539a..02953468cb76 100644 --- a/drivers/gpu/drm/bridge/lontium-lt9611.c +++ b/drivers/gpu/drm/bridge/lontium-lt9611.c @@ -45,7 +45,6 @@ struct lt9611 { struct device_node *dsi1_node; struct mipi_dsi_device *dsi0; struct mipi_dsi_device *dsi1; - struct platform_device *audio_pdev; bool ac_mode; @@ -688,15 +687,22 @@ lt9611_bridge_atomic_enable(struct drm_bridge *bridge, /* Enable HDMI output */ regmap_write(lt9611->regmap, 0x8130, 0xea); + + drm_connector_hdmi_codec_plugged_notify(connector, true); } static void lt9611_bridge_atomic_disable(struct drm_bridge *bridge, struct drm_bridge_state *old_bridge_state) { + struct drm_atomic_state *state = old_bridge_state->base.state; + struct drm_connector *connector; struct lt9611 *lt9611 = bridge_to_lt9611(bridge); int ret; + connector = drm_atomic_get_new_connector_for_encoder(state, bridge->encoder); + drm_connector_hdmi_codec_plugged_notify(connector, false); + /* Disable HDMI output */ ret = regmap_write(lt9611->regmap, 0x8130, 0x6a); if (ret) { @@ -866,6 +872,10 @@ static int lt9611_hdmi_clear_infoframe(struct drm_bridge *bridge, unsigned int mask; switch (type) { + case HDMI_INFOFRAME_TYPE_AUDIO: + mask = LT9611_INFOFRAME_AUDIO; + break; + case HDMI_INFOFRAME_TYPE_AVI: mask = LT9611_INFOFRAME_AVI; break; @@ -899,6 +909,11 @@ static int lt9611_hdmi_write_infoframe(struct drm_bridge *bridge, int i; switch (type) { + case HDMI_INFOFRAME_TYPE_AUDIO: + mask = LT9611_INFOFRAME_AUDIO; + addr = 0x84b2; + break; + case HDMI_INFOFRAME_TYPE_AVI: mask = LT9611_INFOFRAME_AVI; addr = 0x8440; @@ -942,6 +957,79 @@ lt9611_hdmi_tmds_char_rate_valid(const struct drm_bridge *bridge, return MODE_OK; } +static int lt9611_hdmi_codec_prepare(struct device *dev, + struct drm_connector *connector, + struct drm_bridge *bridge, + struct hdmi_codec_daifmt *fmt, + struct hdmi_codec_params *hparms) +{ + struct lt9611 *lt9611 = bridge_to_lt9611(bridge); + + if (hparms->sample_rate == 48000) + regmap_write(lt9611->regmap, 0x840f, 0x2b); + else if (hparms->sample_rate == 96000) + regmap_write(lt9611->regmap, 0x840f, 0xab); + else + return -EINVAL; + + regmap_write(lt9611->regmap, 0x8435, 0x00); + regmap_write(lt9611->regmap, 0x8436, 0x18); + regmap_write(lt9611->regmap, 0x8437, 0x00); + + return drm_atomic_helper_connector_hdmi_update_audio_infoframe(connector, + &hparms->cea); +} + +static int lt9611_hdmi_codec_audio_startup(struct device *dev, + struct drm_connector *connector, + struct drm_bridge *bridge) +{ + struct lt9611 *lt9611 = bridge_to_lt9611(bridge); + + regmap_write(lt9611->regmap, 0x82d6, 0x8c); + regmap_write(lt9611->regmap, 0x82d7, 0x04); + + regmap_write(lt9611->regmap, 0x8406, 0x08); + regmap_write(lt9611->regmap, 0x8407, 0x10); + + regmap_write(lt9611->regmap, 0x8434, 0xd5); + + return 0; +} + +static void lt9611_hdmi_codec_audio_shutdown(struct device *dev, + struct drm_connector *connector, + struct drm_bridge *bridge) +{ + struct lt9611 *lt9611 = bridge_to_lt9611(bridge); + + drm_atomic_helper_connector_hdmi_disable_audio_infoframe(connector); + + regmap_write(lt9611->regmap, 0x8406, 0x00); + regmap_write(lt9611->regmap, 0x8407, 0x00); +} + +static int lt9611_hdmi_codec_get_dai_id(struct drm_connector *connector, + struct drm_bridge *bridge, + struct device_node *endpoint) +{ + struct of_endpoint of_ep; + int ret; + + ret = of_graph_parse_endpoint(endpoint, &of_ep); + if (ret < 0) + return ret; + + /* + * HDMI sound should be located as reg = <2> + * Then, it is sound port 0 + */ + if (of_ep.port == 2) + return 0; + + return -EINVAL; +} + static const struct drm_bridge_funcs lt9611_bridge_funcs = { .attach = lt9611_bridge_attach, .mode_valid = lt9611_bridge_mode_valid, @@ -962,6 +1050,11 @@ static const struct drm_bridge_funcs lt9611_bridge_funcs = { .hdmi_tmds_char_rate_valid = lt9611_hdmi_tmds_char_rate_valid, .hdmi_write_infoframe = lt9611_hdmi_write_infoframe, .hdmi_clear_infoframe = lt9611_hdmi_clear_infoframe, + + .hdmi_codec_audio_startup = lt9611_hdmi_codec_audio_startup, + .hdmi_codec_prepare = lt9611_hdmi_codec_prepare, + .hdmi_codec_audio_shutdown = lt9611_hdmi_codec_audio_shutdown, + .hdmi_codec_get_dai_id = lt9611_hdmi_codec_get_dai_id, }; static int lt9611_parse_dt(struct device *dev, @@ -1015,102 +1108,6 @@ static int lt9611_read_device_rev(struct lt9611 *lt9611) return ret; } -static int lt9611_hdmi_hw_params(struct device *dev, void *data, - struct hdmi_codec_daifmt *fmt, - struct hdmi_codec_params *hparms) -{ - struct lt9611 *lt9611 = data; - - if (hparms->sample_rate == 48000) - regmap_write(lt9611->regmap, 0x840f, 0x2b); - else if (hparms->sample_rate == 96000) - regmap_write(lt9611->regmap, 0x840f, 0xab); - else - return -EINVAL; - - regmap_write(lt9611->regmap, 0x8435, 0x00); - regmap_write(lt9611->regmap, 0x8436, 0x18); - regmap_write(lt9611->regmap, 0x8437, 0x00); - - return 0; -} - -static int lt9611_audio_startup(struct device *dev, void *data) -{ - struct lt9611 *lt9611 = data; - - regmap_write(lt9611->regmap, 0x82d6, 0x8c); - regmap_write(lt9611->regmap, 0x82d7, 0x04); - - regmap_write(lt9611->regmap, 0x8406, 0x08); - regmap_write(lt9611->regmap, 0x8407, 0x10); - - regmap_write(lt9611->regmap, 0x8434, 0xd5); - - return 0; -} - -static void lt9611_audio_shutdown(struct device *dev, void *data) -{ - struct lt9611 *lt9611 = data; - - regmap_write(lt9611->regmap, 0x8406, 0x00); - regmap_write(lt9611->regmap, 0x8407, 0x00); -} - -static int lt9611_hdmi_i2s_get_dai_id(struct snd_soc_component *component, - struct device_node *endpoint, - void *data) -{ - struct of_endpoint of_ep; - int ret; - - ret = of_graph_parse_endpoint(endpoint, &of_ep); - if (ret < 0) - return ret; - - /* - * HDMI sound should be located as reg = <2> - * Then, it is sound port 0 - */ - if (of_ep.port == 2) - return 0; - - return -EINVAL; -} - -static const struct hdmi_codec_ops lt9611_codec_ops = { - .hw_params = lt9611_hdmi_hw_params, - .audio_shutdown = lt9611_audio_shutdown, - .audio_startup = lt9611_audio_startup, - .get_dai_id = lt9611_hdmi_i2s_get_dai_id, -}; - -static struct hdmi_codec_pdata codec_data = { - .ops = <9611_codec_ops, - .max_i2s_channels = 8, - .i2s = 1, -}; - -static int lt9611_audio_init(struct device *dev, struct lt9611 *lt9611) -{ - codec_data.data = lt9611; - lt9611->audio_pdev = - platform_device_register_data(dev, HDMI_CODEC_DRV_NAME, - PLATFORM_DEVID_AUTO, - &codec_data, sizeof(codec_data)); - - return PTR_ERR_OR_ZERO(lt9611->audio_pdev); -} - -static void lt9611_audio_exit(struct lt9611 *lt9611) -{ - if (lt9611->audio_pdev) { - platform_device_unregister(lt9611->audio_pdev); - lt9611->audio_pdev = NULL; - } -} - static int lt9611_probe(struct i2c_client *client) { struct lt9611 *lt9611; @@ -1174,14 +1171,20 @@ static int lt9611_probe(struct i2c_client *client) i2c_set_clientdata(client, lt9611); + /* Disable Audio InfoFrame, enabled by default */ + regmap_update_bits(lt9611->regmap, 0x843d, LT9611_INFOFRAME_AUDIO, 0); + lt9611->bridge.funcs = <9611_bridge_funcs; lt9611->bridge.of_node = client->dev.of_node; lt9611->bridge.ops = DRM_BRIDGE_OP_DETECT | DRM_BRIDGE_OP_EDID | DRM_BRIDGE_OP_HPD | DRM_BRIDGE_OP_MODES | - DRM_BRIDGE_OP_HDMI; + DRM_BRIDGE_OP_HDMI | DRM_BRIDGE_OP_HDMI_CODEC; lt9611->bridge.type = DRM_MODE_CONNECTOR_HDMIA; lt9611->bridge.vendor = "Lontium"; lt9611->bridge.product = "LT9611"; + lt9611->bridge.parent = dev; + lt9611->bridge.max_i2s_channels = 8; + lt9611->bridge.hdmi_codec_i2s = 1; drm_bridge_add(<9611->bridge); @@ -1203,10 +1206,6 @@ static int lt9611_probe(struct i2c_client *client) lt9611_enable_hpd_interrupts(lt9611); - ret = lt9611_audio_init(dev, lt9611); - if (ret) - goto err_remove_bridge; - return 0; err_remove_bridge: @@ -1227,7 +1226,9 @@ static void lt9611_remove(struct i2c_client *client) struct lt9611 *lt9611 = i2c_get_clientdata(client); disable_irq(client->irq); - lt9611_audio_exit(lt9611); + if (lt9611->bridge.dev) + drmm_connector_hdmi_codec_free(lt9611->bridge.dev, + lt9611->bridge.hdmi_codec); drm_bridge_remove(<9611->bridge); regulator_bulk_disable(ARRAY_SIZE(lt9611->supplies), lt9611->supplies);