From nobody Sat Jul 25 00:15:11 2026 Received: from pidgin.makrotopia.org (pidgin.makrotopia.org [185.142.180.65]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id A5267353A60 for ; Wed, 22 Jul 2026 00:59:17 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=185.142.180.65 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784681959; cv=none; b=GhsGQi3gBowR9Igu4DDpQA+5xdzPnpV8d6VHd6V++LJ3XshUndiRoCG+/kAK7EsYZ2djceYdHe7ods4qDpmofpO20XTRCxpvAltuwJvHYtwTBWw+VRltPeSRQK0KriYwm2aFf1CcbJ1KMuYk9QIs3jFHxj35jr8fGlJjcWxEl1M= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784681959; c=relaxed/simple; bh=e/FC+5OMvZQornNdZIugxh0MFBwGqK42nm0O3iRQsFE=; h=Date:From:To:Cc:Subject:Message-ID:References:MIME-Version: Content-Type:Content-Disposition:In-Reply-To; b=WddUoqEWOOIirF61vySFKUFXtNTVeEIH0w31yXwT48t4R6a7fC6/LhgLWAhVI8jTQBWMjfVPcLcK/NhMJuvQoDVRkPBYyAv4ovaVn/gQXen/2ygQHxwuEo9XcuJDQst5HPWaUB7dg9L3b+PvAaaKmH304mseJ9XptVrfHo/gowQ= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=makrotopia.org; spf=pass smtp.mailfrom=makrotopia.org; arc=none smtp.client-ip=185.142.180.65 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=makrotopia.org Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=makrotopia.org Received: from local by pidgin.makrotopia.org with esmtpsa (TLS1.3:TLS_AES_256_GCM_SHA384:256) (Exim 4.99) (envelope-from ) id 1wmLIl-000000000x8-1oIs; Wed, 22 Jul 2026 00:59:11 +0000 Date: Wed, 22 Jul 2026 01:59:08 +0100 From: Daniel Golle To: Andrzej Hajda , Neil Armstrong , Robert Foss , Laurent Pinchart , Jonas Karlman , Jernej Skrabec , Luca Ceresoli , Maarten Lankhorst , Maxime Ripard , Thomas Zimmermann , David Airlie , Simona Vetter , Matthias Brugger , AngeloGioacchino Del Regno , Hermes Wu , Allen Chen , Pin-yen Lin , dri-devel@lists.freedesktop.org, linux-kernel@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-mediatek@lists.infradead.org Cc: Chen-Yu Tsai Subject: [PATCH v4 1/5] drm/bridge: it6505: quiesce event sources and work on remove() Message-ID: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Disposition: inline In-Reply-To: Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" it6505_i2c_remove() tears down the bridge and frees its state without cancelling any of the driver's background work. struct it6505 is allocated with devm_drm_bridge_alloc(), so devres frees it as soon as remove() returns; link_works, hdcp_wait_ksv_list, hdcp_work and extcon_wq can all still be pending or running at that point and will then dereference freed memory. link_works and extcon_wq are flushed in it6505_bridge_detach(), but that only runs if DRM core calls the bridge's .detach() before the i2c client is unbound -- not guaranteed if the i2c driver is unbound independently of the DRM device that consumes it. hdcp_wait_ksv_list and hdcp_work are never cancelled anywhere. Cancelling the work items alone would not be enough: the threaded IRQ handler and the extcon notifier both stay live until devres teardown after remove() returns, and both can requeue a work item right after it was cancelled. Remove the DRM-facing interfaces first, then quiesce the scheduling sources by unregistering the extcon notifier and disabling the interrupt, and only then cancel the work items. Unregistering the extcon notifier on remove() means it6505_remove_notifier_module() can now run twice, from .detach() and from remove(), while devm_extcon_unregister_notifier() WARNs when the notifier is not registered. Track the registration in event_nb.notifier_call to make the helper idempotent. Initialise extcon_wq in probe rather than in it6505_use_notifier_module(): cancel_work_sync() on a work item that was never INIT_WORK()'d trips WARN_ON(!work->func) in __flush_work(), which would fire when unbinding a device whose bridge was never attached. Fixes: b5c84a9edcd4 ("drm/bridge: add it6505 driver") Signed-off-by: Daniel Golle --- v4: * retitled from "drm/bridge: it6505: cancel outstanding work before teardown in remove()" * quiesce the scheduling sources (extcon notifier, threaded IRQ) before cancelling the work items, and cancel only after the DRM-facing interfaces are removed, closing the requeue race flagged by Sashiko AI review * make it6505_remove_notifier_module() idempotent so both .detach() and remove() can call it * initialise extcon_wq in probe instead of relying on cancel_work_sync() coping with a zeroed work_struct, which would trip WARN_ON(!work->func) in __flush_work(); flagged by Sashiko AI review and confirmed by Chen-Yu Tsai v3: new patch drivers/gpu/drm/bridge/ite-it6505.c | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/bridge/ite-it6505.c b/drivers/gpu/drm/bridge/i= te-it6505.c index 8ecb43611dba..7873ae6df3af 100644 --- a/drivers/gpu/drm/bridge/ite-it6505.c +++ b/drivers/gpu/drm/bridge/ite-it6505.c @@ -2935,11 +2935,11 @@ static int it6505_use_notifier_module(struct it6505= *it6505) struct device *dev =3D it6505->dev; =20 it6505->event_nb.notifier_call =3D it6505_extcon_notifier; - INIT_WORK(&it6505->extcon_wq, it6505_extcon_work); ret =3D devm_extcon_register_notifier(it6505->dev, it6505->extcon, EXTCON_DISP_DP, &it6505->event_nb); if (ret) { + it6505->event_nb.notifier_call =3D NULL; dev_err(dev, "failed to register notifier for DP"); return ret; } @@ -2951,13 +2951,14 @@ static int it6505_use_notifier_module(struct it6505= *it6505) =20 static void it6505_remove_notifier_module(struct it6505 *it6505) { - if (it6505->extcon) { - devm_extcon_unregister_notifier(it6505->dev, - it6505->extcon, EXTCON_DISP_DP, - &it6505->event_nb); + if (!it6505->extcon || !it6505->event_nb.notifier_call) + return; =20 - flush_work(&it6505->extcon_wq); - } + devm_extcon_unregister_notifier(it6505->dev, it6505->extcon, + EXTCON_DISP_DP, &it6505->event_nb); + it6505->event_nb.notifier_call =3D NULL; + + flush_work(&it6505->extcon_wq); } =20 static void __maybe_unused it6505_delayed_audio(struct work_struct *work) @@ -3615,6 +3616,7 @@ static int it6505_i2c_probe(struct i2c_client *client) INIT_WORK(&it6505->link_works, it6505_link_training_work); INIT_WORK(&it6505->hdcp_wait_ksv_list, it6505_hdcp_wait_ksv_list); INIT_DELAYED_WORK(&it6505->hdcp_work, it6505_hdcp_work); + INIT_WORK(&it6505->extcon_wq, it6505_extcon_work); init_completion(&it6505->extcon_completion); memset(it6505->dpcd, 0, sizeof(it6505->dpcd)); it6505->powered =3D false; @@ -3647,6 +3649,12 @@ static void it6505_i2c_remove(struct i2c_client *cli= ent) drm_bridge_remove(&it6505->bridge); drm_dp_aux_unregister(&it6505->aux); it6505_debugfs_remove(it6505); + it6505_remove_notifier_module(it6505); + disable_irq(it6505->irq); + cancel_work_sync(&it6505->link_works); + cancel_work_sync(&it6505->hdcp_wait_ksv_list); + cancel_delayed_work_sync(&it6505->hdcp_work); + cancel_work_sync(&it6505->extcon_wq); it6505_poweroff(it6505); it6505_remove_edid(it6505); } --=20 2.55.0 From nobody Sat Jul 25 00:15:11 2026 Received: from pidgin.makrotopia.org (pidgin.makrotopia.org [185.142.180.65]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 8F19A360ED6 for ; Wed, 22 Jul 2026 00:59:30 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=185.142.180.65 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784681972; cv=none; b=OCqgyfVDsLNOG4ea+M31sZf36OQjTw91587Jw7XYCSZ8ags1z/yHc4QdzwOjWpw1RsFSAM53NF6n+84apVDEYopbV7hUxorsLItPkIV6e0tPkTFW2LuuHZH04Z7dtjFhbckTRVpUtVULDnRafdUrh5EPGg7dTlGHO1wlUtGjxAU= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784681972; c=relaxed/simple; bh=xqgI+pKYGT8fZgsfbsMvAA/ehq5ZqseNvAV3GFP8G2s=; h=Date:From:To:Cc:Subject:Message-ID:References:MIME-Version: Content-Type:Content-Disposition:In-Reply-To; b=UFI4f/Lfu8yLlKyt+D9GmN3sQhJBlocS/d3GMTpB353VK+8Hb7YOWkmmrxKCLt/pJlPIgFE/SfMSQ3KCpDPb9Iax8h0V/Hu87MKcyhliclJKAOVadvXtT1sED5j5eJp2jsN9/0TMl1/J0UjdGONc+8Wmq4fr2rQ8JMavo9mjZS4= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=makrotopia.org; spf=pass smtp.mailfrom=makrotopia.org; arc=none smtp.client-ip=185.142.180.65 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=makrotopia.org Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=makrotopia.org Received: from local by pidgin.makrotopia.org with esmtpsa (TLS1.3:TLS_AES_256_GCM_SHA384:256) (Exim 4.99) (envelope-from ) id 1wmLIy-000000000yY-1plf; Wed, 22 Jul 2026 00:59:24 +0000 Date: Wed, 22 Jul 2026 01:59:21 +0100 From: Daniel Golle To: Andrzej Hajda , Neil Armstrong , Robert Foss , Laurent Pinchart , Jonas Karlman , Jernej Skrabec , Luca Ceresoli , Maarten Lankhorst , Maxime Ripard , Thomas Zimmermann , David Airlie , Simona Vetter , Matthias Brugger , AngeloGioacchino Del Regno , Hermes Wu , Allen Chen , Pin-yen Lin , dri-devel@lists.freedesktop.org, linux-kernel@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-mediatek@lists.infradead.org Cc: Chen-Yu Tsai Subject: [PATCH v4 2/5] drm/bridge: it6505: disable runtime PM on remove Message-ID: <59d6066b37a33878c8673bf1659e16fd2624cae4.1784681487.git.daniel@makrotopia.org> References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Disposition: inline In-Reply-To: Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" it6505_i2c_probe() enables runtime PM but it6505_i2c_remove() never disables it, leaving the device with an unbalanced disable depth after unbind. Binding the driver again then triggers the "Unbalanced pm_runtime_enable!" warning. Disable runtime PM in remove() after all work items have been cancelled (the extcon work calls pm_runtime_get_sync() and pm_runtime_put_sync()) and before powering the chip off manually. Fixes: 10517777d302 ("drm/bridge: it6505: Adapt runtime power management fr= amework") Signed-off-by: Daniel Golle --- v4: new patch drivers/gpu/drm/bridge/ite-it6505.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/bridge/ite-it6505.c b/drivers/gpu/drm/bridge/i= te-it6505.c index 7873ae6df3af..2a8298ee6c03 100644 --- a/drivers/gpu/drm/bridge/ite-it6505.c +++ b/drivers/gpu/drm/bridge/ite-it6505.c @@ -3655,6 +3655,7 @@ static void it6505_i2c_remove(struct i2c_client *clie= nt) cancel_work_sync(&it6505->hdcp_wait_ksv_list); cancel_delayed_work_sync(&it6505->hdcp_work); cancel_work_sync(&it6505->extcon_wq); + pm_runtime_disable(&client->dev); it6505_poweroff(it6505); it6505_remove_edid(it6505); } --=20 2.55.0 From nobody Sat Jul 25 00:15:11 2026 Received: from pidgin.makrotopia.org (pidgin.makrotopia.org [185.142.180.65]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id A8A5B25B08A for ; Wed, 22 Jul 2026 00:59:48 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=185.142.180.65 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784681990; cv=none; b=UbPiahvKIQjXHvcN+TaSDRP/WVyQ2WhRn7ULB428hG2TpyCXSrahZsJQ7SYF66MzCmAeWcyzie72tGstCdhb8y5W3ToGuz0xd6FzlQGgsfvfpRWnZPx6yEIpOmb8HWeZwJ2CVnbXHgGZr109giOxqdJz9KZbR6JV0hL2GgrHoto= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784681990; c=relaxed/simple; bh=40q7PBGkLuW5l0eUB4WAtJACCsiHsKu6KuMFXOoMEhw=; h=Date:From:To:Cc:Subject:Message-ID:References:MIME-Version: Content-Type:Content-Disposition:In-Reply-To; b=FoXiUeNF3mr6ZlOl0c7EMSAZWWe5amLYKSGxoem4hydUJ0DjzLXNYj3cUSyTt6lkanX7hQzBAk0ctEkmJzd2jzZLLqhvxRH2QtP0QC/L8SMIh4LPdBYo2Fw8ZBbzlONrCjwT6NnWhIi/T+GENJPgqxVyBDKm1tQ0wyZ3nVsWztA= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=makrotopia.org; spf=pass smtp.mailfrom=makrotopia.org; arc=none smtp.client-ip=185.142.180.65 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=makrotopia.org Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=makrotopia.org Received: from local by pidgin.makrotopia.org with esmtpsa (TLS1.3:TLS_AES_256_GCM_SHA384:256) (Exim 4.99) (envelope-from ) id 1wmLJF-000000000zf-0Aua; Wed, 22 Jul 2026 00:59:41 +0000 Date: Wed, 22 Jul 2026 01:59:37 +0100 From: Daniel Golle To: Andrzej Hajda , Neil Armstrong , Robert Foss , Laurent Pinchart , Jonas Karlman , Jernej Skrabec , Luca Ceresoli , Maarten Lankhorst , Maxime Ripard , Thomas Zimmermann , David Airlie , Simona Vetter , Matthias Brugger , AngeloGioacchino Del Regno , Hermes Wu , Allen Chen , Pin-yen Lin , dri-devel@lists.freedesktop.org, linux-kernel@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-mediatek@lists.infradead.org Cc: Chen-Yu Tsai Subject: [PATCH v4 3/5] drm/bridge: it6505: guard against zero channel count in audio infoframe Message-ID: <94721d5c75645a574263cc849249c56e504c2ade.1784681487.git.daniel@makrotopia.org> References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Disposition: inline In-Reply-To: Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" it6505->audio.channel_count is zero from allocation until either DP link training has run once (it6505_variable_config()) or a valid hw_params call has cached a channel count. it6505_enable_audio() can be reached before either of those has happened, e.g. from the audio-FIFO-error IRQ, which is unmasked unconditionally at poweron. it6505_enable_audio_infoframe() then indexes the 8-entry audio_info_ca[] table with channel_count - 1, an out-of-bounds stack read when channel_count is still 0. Bail out of it6505_enable_audio_infoframe() when channel_count is not yet known instead of indexing with it. While here, fix the debug print in it6505_audio_setup_hw_params(): on the invalid-channel-count path it logged the previously cached channel_count instead of the actually-rejected params->cea.channels. Fixes: b5c84a9edcd4 ("drm/bridge: add it6505 driver") Signed-off-by: Daniel Golle Reviewed-by: Chen-Yu Tsai --- v4: no changes v3: new patch, split out to fix pre-existing bugs flagged by automated review of v2's audio series; needed before that series starts exercising the audio-FIFO-error IRQ path in a configuration where channel_count =3D=3D 0 is actually reachable. drivers/gpu/drm/bridge/ite-it6505.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/bridge/ite-it6505.c b/drivers/gpu/drm/bridge/i= te-it6505.c index 2a8298ee6c03..443ea5579744 100644 --- a/drivers/gpu/drm/bridge/ite-it6505.c +++ b/drivers/gpu/drm/bridge/ite-it6505.c @@ -1575,6 +1575,9 @@ static void it6505_enable_audio_infoframe(struct it65= 05 *it6505) struct device *dev =3D it6505->dev; u8 audio_info_ca[] =3D { 0x00, 0x00, 0x01, 0x03, 0x07, 0x0B, 0x0F, 0x1F }; =20 + if (!it6505->audio.channel_count) + return; + DRM_DEV_DEBUG_DRIVER(dev, "infoframe channel_allocation:0x%02x", audio_info_ca[it6505->audio.channel_count - 1]); =20 @@ -2991,7 +2994,7 @@ static int __maybe_unused it6505_audio_setup_hw_param= s(struct it6505 *it6505, =20 if (params->cea.channels <=3D 1 || params->cea.channels > 8) { DRM_DEV_DEBUG_DRIVER(dev, "channel number: %d not support", - it6505->audio.channel_count); + params->cea.channels); return -EINVAL; } =20 --=20 2.55.0 From nobody Sat Jul 25 00:15:11 2026 Received: from pidgin.makrotopia.org (pidgin.makrotopia.org [185.142.180.65]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id DBFD034B1A6 for ; Wed, 22 Jul 2026 01:00:36 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=185.142.180.65 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784682038; cv=none; b=uCkNSEd0Our0mNPtTALlqrLJi66+dtMpFjRJty31oMr6O8AKTWQygY6R8s4+Lnd/5keTVkH9GMAwCRaK2ezaO6S/cK+ZzslTv72zX9vPGWAU7VI+qPd80GEtx04sRiuW3wOe75nTfs3aW5YO6libKRtBFxpgQQB9buodOHQ+l48= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784682038; c=relaxed/simple; bh=X3Ndq2jbhMLF4e8GjXpB3WCWN+LPRT8zVlIq665PPL4=; h=Date:From:To:Cc:Subject:Message-ID:References:MIME-Version: Content-Type:Content-Disposition:In-Reply-To; b=UEAegD93vU5UmTRDyuKiojLskf+Kuf3biXG0Nq4HQRrM1LkEvFF1IsT20HOZx6nRHjmgcICIBkcicu/iIQs4b6KnI2bUjZIBAOWB3e/cvrislrEWwL/xrE+8YuO6HJJNkL0L09YloQ48imqHq0do5dLq2nx+6KdiwN+UhDC89x0= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=makrotopia.org; spf=pass smtp.mailfrom=makrotopia.org; arc=none smtp.client-ip=185.142.180.65 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=makrotopia.org Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=makrotopia.org Received: from local by pidgin.makrotopia.org with esmtpsa (TLS1.3:TLS_AES_256_GCM_SHA384:256) (Exim 4.99) (envelope-from ) id 1wmLK0-0000000010j-3bXW; Wed, 22 Jul 2026 01:00:28 +0000 Date: Wed, 22 Jul 2026 02:00:25 +0100 From: Daniel Golle To: Andrzej Hajda , Neil Armstrong , Robert Foss , Laurent Pinchart , Jonas Karlman , Jernej Skrabec , Luca Ceresoli , Maarten Lankhorst , Maxime Ripard , Thomas Zimmermann , David Airlie , Simona Vetter , Matthias Brugger , AngeloGioacchino Del Regno , Hermes Wu , Allen Chen , Pin-yen Lin , dri-devel@lists.freedesktop.org, linux-kernel@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-mediatek@lists.infradead.org Cc: Chen-Yu Tsai Subject: [PATCH v4 4/5] drm/bridge: it6505: Add audio support Message-ID: <82871481f951bbba67febdf7a7445d01f0bd60f2.1784681487.git.daniel@makrotopia.org> References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Disposition: inline In-Reply-To: Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Jiaxin Yu Add audio support for it6505 by bridging to the hdmi-codec, registering an "hdmi-audio-codec" platform device from probe. The it6505's audio setup/shutdown helpers were merged earlier as unused code; wire them up via hdmi_codec_ops so the DAI actually appears, which unblocks the mt8186-mt6366 sound card that references it6505 as the I2S3 codec. Some DP-to-HDMI dongles get into a bad state if InfoFrame is sent without audio data, so it6505's audio is only enabled once the stream is unmuted. The audio state starts out muted so the audio-FIFO-error IRQ cannot enable audio before ALSA has configured and unmuted the stream. it6505_enable_audio()/it6505_disable_audio() can be called from several contexts: the HPD-low path, the audio-FIFO-error IRQ, the delayed audio-enable work and the .mute_stream/.audio_shutdown hdmi_codec_ops added here. None of these are mutually exclusive, so serialize the actual register sequences with a new audio_lock mutex. The mute state and the stream parameters cached by .hw_params are updated under the same lock, and the audio-FIFO-error IRQ handler (a threaded IRQ, so it may sleep) probes the audio input and re-enables audio in a single critical section, re-checking the mute state there so it cannot undo a concurrent ALSA-requested mute. On remove, unregister the audio codec platform device only once the event sources and the other work items have been quiesced, so nothing can call back into the freed codec device through plugged_cb, and cancel the delayed audio work after that, when nothing is left that could requeue it. Signed-off-by: Jiaxin Yu Link: https://lore.kernel.org/all/20230730180803.22570-4-jiaxin.yu@mediatek= .com/ Signed-off-by: Daniel Golle --- v4: * start out muted (audio.mute =3D true) so the audio-FIFO-error IRQ cannot enable audio before ALSA has configured and unmuted the stream * update the mute state and the cached stream parameters under audio_lock, and split out __it6505_enable_audio() so the audio-FIFO-error IRQ handler can probe the audio input and enable audio in one critical section, re-checking the mute state under the lock; closes a race where a FIFO error racing with an ALSA mute could undo the mute * unregister the audio codec platform device only after event sources and work items are quiesced, closing a use-after-free of codec_dev; cancel delayed_audio after the codec is gone All of the above flagged by Sashiko AI review of v3. v3: * serialise it6505_enable_audio()/it6505_disable_audio() with a new audio_lock mutex, resolving the "input welcome on whether a lock is warranted" note below * track requested mute state in it6505->audio.mute and have the audio-FIFO-error IRQ handler skip re-enabling audio while muted, both addressing automated review of v2 v2: * store the hdmi-codec platform_device and unregister it on i2c remove, fixing a resource leak and use-after-free on unbind * initialise the delayed audio work before registering the codec device instead of after * synchronously cancel the delayed audio work on audio shutdown and on driver remove (cancel_delayed_work_sync) * rework the mute path to cancel pending work synchronously and disable audio immediately when muting, removing a race with the delayed enable work djg: respin of Jiaxin Yu's v3, rebased onto current mainline. Changes from his v3: hdmi_codec_ops lost .trigger, so drive enable/disable from .mute_stream; drop the now-redundant __maybe_unused; use it6505->dev instead of &client->dev, addressing AngeloGioacchino Del Regno's v3 review. Also fix issues in v3: initialise delayed_audio before registering the codec device; keep and unregister the platform_device and cancel delayed_audio on remove to avoid a leak and a use-after-free; cancel the delayed work on audio shutdown; and actually disable audio (not just cancel the pending enable) when the stream is muted. drivers/gpu/drm/bridge/ite-it6505.c | 162 +++++++++++++++++++++++----- 1 file changed, 133 insertions(+), 29 deletions(-) diff --git a/drivers/gpu/drm/bridge/ite-it6505.c b/drivers/gpu/drm/bridge/i= te-it6505.c index 443ea5579744..6bb5db565cca 100644 --- a/drivers/gpu/drm/bridge/ite-it6505.c +++ b/drivers/gpu/drm/bridge/ite-it6505.c @@ -407,6 +407,7 @@ struct it6505_audio_data { u8 i2s_data_delay; u8 i2s_ws_channel; u8 i2s_data_sequence; + bool mute; }; =20 struct it6505_audio_sample_rate_map { @@ -439,6 +440,7 @@ struct it6505 { struct mutex extcon_lock; struct mutex mode_lock; /* used to bridge_detect */ struct mutex aux_lock; /* used to aux data transfers */ + struct mutex audio_lock; /* serializes audio enable/disable */ struct regmap *regmap; struct drm_display_mode source_output_mode; struct drm_display_mode video_info; @@ -476,6 +478,7 @@ struct it6505 { bool enable_enhanced_frame; hdmi_codec_plugged_cb plugged_cb; struct device *codec_dev; + struct platform_device *audio_pdev; struct delayed_work delayed_audio; struct it6505_audio_data audio; struct dentry *debugfs; @@ -1594,7 +1597,7 @@ static void it6505_enable_audio_infoframe(struct it65= 05 *it6505) EN_AUD_CTRL_PKT); } =20 -static void it6505_disable_audio(struct it6505 *it6505) +static void __it6505_disable_audio(struct it6505 *it6505) { it6505_set_bits(it6505, REG_DATA_MUTE_CTRL, EN_AUD_MUTE, EN_AUD_MUTE); it6505_set_bits(it6505, REG_AUDIO_SRC_CTRL, M_AUDIO_I2S_EN, 0x00); @@ -1602,13 +1605,21 @@ static void it6505_disable_audio(struct it6505 *it6= 505) it6505_set_bits(it6505, REG_RESET_CTRL, AUDIO_RESET, AUDIO_RESET); } =20 -static void it6505_enable_audio(struct it6505 *it6505) +static void it6505_disable_audio(struct it6505 *it6505) +{ + mutex_lock(&it6505->audio_lock); + __it6505_disable_audio(it6505); + mutex_unlock(&it6505->audio_lock); +} + +static void __it6505_enable_audio(struct it6505 *it6505) { struct device *dev =3D it6505->dev; int regbe; =20 DRM_DEV_DEBUG_DRIVER(dev, "start"); - it6505_disable_audio(it6505); + + __it6505_disable_audio(it6505); =20 it6505_setup_audio_channel_status(it6505); it6505_setup_audio_format(it6505); @@ -1629,6 +1640,14 @@ static void it6505_enable_audio(struct it6505 *it650= 5) it6505_set_bits(it6505, REG_DATA_MUTE_CTRL, EN_AUD_MUTE, 0x00); } =20 +static void it6505_enable_audio(struct it6505 *it6505) +{ + mutex_lock(&it6505->audio_lock); + if (!it6505->audio.mute) + __it6505_enable_audio(it6505); + mutex_unlock(&it6505->audio_lock); +} + static bool it6505_use_step_train_check(struct it6505 *it6505) { if (it6505->link.revision >=3D 0x12) @@ -2323,19 +2342,12 @@ static void it6505_stop_link_train(struct it6505 *i= t6505) =20 static void it6505_link_train_ok(struct it6505 *it6505) { - struct device *dev =3D it6505->dev; - it6505->link_state =3D LINK_OK; /* disalbe mute enable avi info frame */ it6505_set_bits(it6505, REG_DATA_MUTE_CTRL, EN_VID_MUTE, 0x00); it6505_set_bits(it6505, REG_INFOFRAME_CTRL, EN_VID_CTRL_PKT, EN_VID_CTRL_PKT); =20 - if (it6505_audio_input(it6505)) { - DRM_DEV_DEBUG_DRIVER(dev, "Enable audio!"); - it6505_enable_audio(it6505); - } - if (it6505->hdcp_desired) it6505_start_hdcp(it6505); } @@ -2627,8 +2639,10 @@ static void it6505_irq_audio_fifo_error(struct it650= 5 *it6505) =20 DRM_DEV_DEBUG_DRIVER(dev, "audio fifo error Interrupt"); =20 - if (it6505_audio_input(it6505)) - it6505_enable_audio(it6505); + mutex_lock(&it6505->audio_lock); + if (!it6505->audio.mute && it6505_audio_input(it6505)) + __it6505_enable_audio(it6505); + mutex_unlock(&it6505->audio_lock); } =20 static void it6505_irq_link_train_fail(struct it6505 *it6505) @@ -2964,7 +2978,7 @@ static void it6505_remove_notifier_module(struct it65= 05 *it6505) flush_work(&it6505->extcon_wq); } =20 -static void __maybe_unused it6505_delayed_audio(struct work_struct *work) +static void it6505_delayed_audio(struct work_struct *work) { struct it6505 *it6505 =3D container_of(work, struct it6505, delayed_audio.work); @@ -2978,11 +2992,12 @@ static void __maybe_unused it6505_delayed_audio(str= uct work_struct *work) it6505_enable_audio(it6505); } =20 -static int __maybe_unused it6505_audio_setup_hw_params(struct it6505 *it65= 05, - struct hdmi_codec_params - *params) +static int it6505_audio_setup_hw_params(struct it6505 *it6505, + struct hdmi_codec_params + *params) { struct device *dev =3D it6505->dev; + u8 word_length; int i =3D 0; =20 DRM_DEV_DEBUG_DRIVER(dev, "%s %d Hz, %d bit, %d channels\n", __func__, @@ -2998,8 +3013,6 @@ static int __maybe_unused it6505_audio_setup_hw_param= s(struct it6505 *it6505, return -EINVAL; } =20 - it6505->audio.channel_count =3D params->cea.channels; - while (i < ARRAY_SIZE(audio_sample_rate_map) && params->sample_rate !=3D audio_sample_rate_map[i].sample_rate_value) { @@ -3010,21 +3023,20 @@ static int __maybe_unused it6505_audio_setup_hw_par= ams(struct it6505 *it6505, params->sample_rate); return -EINVAL; } - it6505->audio.sample_rate =3D audio_sample_rate_map[i].rate; =20 switch (params->sample_width) { case 16: - it6505->audio.word_length =3D WORD_LENGTH_16BIT; + word_length =3D WORD_LENGTH_16BIT; break; case 18: - it6505->audio.word_length =3D WORD_LENGTH_18BIT; + word_length =3D WORD_LENGTH_18BIT; break; case 20: - it6505->audio.word_length =3D WORD_LENGTH_20BIT; + word_length =3D WORD_LENGTH_20BIT; break; case 24: case 32: - it6505->audio.word_length =3D WORD_LENGTH_24BIT; + word_length =3D WORD_LENGTH_24BIT; break; default: DRM_DEV_DEBUG_DRIVER(dev, "wordlength: %d bit not support", @@ -3032,21 +3044,70 @@ static int __maybe_unused it6505_audio_setup_hw_par= ams(struct it6505 *it6505, return -EINVAL; } =20 + mutex_lock(&it6505->audio_lock); + it6505->audio.channel_count =3D params->cea.channels; + it6505->audio.sample_rate =3D audio_sample_rate_map[i].rate; + it6505->audio.word_length =3D word_length; + mutex_unlock(&it6505->audio_lock); + return 0; } =20 -static void __maybe_unused it6505_audio_shutdown(struct device *dev, void = *data) +static void it6505_audio_shutdown(struct device *dev, void *data) { struct it6505 *it6505 =3D dev_get_drvdata(dev); =20 + mutex_lock(&it6505->audio_lock); + it6505->audio.mute =3D true; if (it6505->powered) - it6505_disable_audio(it6505); + __it6505_disable_audio(it6505); + mutex_unlock(&it6505->audio_lock); + cancel_delayed_work_sync(&it6505->delayed_audio); +} + +static int it6505_audio_hw_params(struct device *dev, void *data, + struct hdmi_codec_daifmt *daifmt, + struct hdmi_codec_params *params) +{ + struct it6505 *it6505 =3D dev_get_drvdata(dev); + + return it6505_audio_setup_hw_params(it6505, params); } =20 -static int __maybe_unused it6505_audio_hook_plugged_cb(struct device *dev, - void *data, - hdmi_codec_plugged_cb fn, - struct device *codec_dev) +static int it6505_audio_mute(struct device *dev, void *data, + bool enable, int direction) +{ + struct it6505 *it6505 =3D dev_get_drvdata(dev); + + DRM_DEV_DEBUG_DRIVER(dev, "mute: %d", enable); + + /* + * Some DP-to-HDMI dongles get into a bad state if the InfoFrame is + * sent without audio data, so only enable it6505's audio once the + * stream is unmuted (i.e. actually playing). + */ + if (enable) { + mutex_lock(&it6505->audio_lock); + it6505->audio.mute =3D true; + if (it6505->powered) + __it6505_disable_audio(it6505); + mutex_unlock(&it6505->audio_lock); + cancel_delayed_work_sync(&it6505->delayed_audio); + } else { + mutex_lock(&it6505->audio_lock); + it6505->audio.mute =3D false; + mutex_unlock(&it6505->audio_lock); + queue_delayed_work(system_wq, &it6505->delayed_audio, + msecs_to_jiffies(180)); + } + + return 0; +} + +static int it6505_audio_hook_plugged_cb(struct device *dev, + void *data, + hdmi_codec_plugged_cb fn, + struct device *codec_dev) { struct it6505 *it6505 =3D data; =20 @@ -3057,6 +3118,40 @@ static int __maybe_unused it6505_audio_hook_plugged_= cb(struct device *dev, return 0; } =20 +static const struct hdmi_codec_ops it6505_audio_codec_ops =3D { + .hw_params =3D it6505_audio_hw_params, + .mute_stream =3D it6505_audio_mute, + .audio_shutdown =3D it6505_audio_shutdown, + .hook_plugged_cb =3D it6505_audio_hook_plugged_cb, +}; + +static int it6505_register_audio_driver(struct device *dev) +{ + struct it6505 *it6505 =3D dev_get_drvdata(dev); + struct hdmi_codec_pdata codec_data =3D { + .ops =3D &it6505_audio_codec_ops, + .max_i2s_channels =3D 8, + .i2s =3D 1, + .no_capture_mute =3D 1, + .data =3D it6505, + }; + struct platform_device *pdev; + + it6505->audio.mute =3D true; + INIT_DELAYED_WORK(&it6505->delayed_audio, it6505_delayed_audio); + + pdev =3D platform_device_register_data(dev, HDMI_CODEC_DRV_NAME, + PLATFORM_DEVID_AUTO, &codec_data, + sizeof(codec_data)); + if (IS_ERR(pdev)) + return PTR_ERR(pdev); + + it6505->audio_pdev =3D pdev; + DRM_DEV_DEBUG_DRIVER(dev, "bound to %s", HDMI_CODEC_DRV_NAME); + + return 0; +} + static inline struct it6505 *bridge_to_it6505(struct drm_bridge *bridge) { return container_of(bridge, struct it6505, bridge); @@ -3566,6 +3661,7 @@ static int it6505_i2c_probe(struct i2c_client *client) mutex_init(&it6505->extcon_lock); mutex_init(&it6505->mode_lock); mutex_init(&it6505->aux_lock); + mutex_init(&it6505->audio_lock); =20 it6505->bridge.of_node =3D client->dev.of_node; it6505->connector_status =3D connector_status_disconnected; @@ -3616,6 +3712,12 @@ static int it6505_i2c_probe(struct i2c_client *clien= t) return err; } =20 + err =3D it6505_register_audio_driver(dev); + if (err < 0) { + dev_err(dev, "Failed to register audio driver: %d", err); + return err; + } + INIT_WORK(&it6505->link_works, it6505_link_training_work); INIT_WORK(&it6505->hdcp_wait_ksv_list, it6505_hdcp_wait_ksv_list); INIT_DELAYED_WORK(&it6505->hdcp_work, it6505_hdcp_work); @@ -3658,6 +3760,8 @@ static void it6505_i2c_remove(struct i2c_client *clie= nt) cancel_work_sync(&it6505->hdcp_wait_ksv_list); cancel_delayed_work_sync(&it6505->hdcp_work); cancel_work_sync(&it6505->extcon_wq); + platform_device_unregister(it6505->audio_pdev); + cancel_delayed_work_sync(&it6505->delayed_audio); pm_runtime_disable(&client->dev); it6505_poweroff(it6505); it6505_remove_edid(it6505); --=20 2.55.0 From nobody Sat Jul 25 00:15:11 2026 Received: from pidgin.makrotopia.org (pidgin.makrotopia.org [185.142.180.65]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id BFF1433D6F0 for ; Wed, 22 Jul 2026 01:01:03 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=185.142.180.65 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784682065; cv=none; b=Qzwun0YRkXt9yMeLlVBhnRtpmPAjr+s2OGmcM53L0tnlzOE0iVRckAM8yB0jYNkHJX5LCWynpi/sHUu7kWvDugdsz64iP2lwfO60WKELWpr1vEQxVN2cArQiF2OFQLtdusmSpyCJ0JFVuENiGGdGIgXIlTTk5xKwc839jL51Q/A= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784682065; c=relaxed/simple; bh=0xjnipQ4R10vtXrHz80G5lJVBAj3ns4DZdy8/TV1TxY=; h=Date:From:To:Cc:Subject:Message-ID:References:MIME-Version: Content-Type:Content-Disposition:In-Reply-To; b=mZ+GZ2kdiNNf/Y7BgTuiti9HccqO/LOOZd/6wtojBf5mVpDgu4oaJRKKd+J7QuUR9heDbzljRhyu8ECcOvLWe/6dFJKj2nUO7ZxWXuPBgxvMB90TOPQUBtPsIpTjvXesQSAVCs+1M9rSskDETBNQCeyeJmytDqMlztQ1jQ6zMkQ= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=makrotopia.org; spf=pass smtp.mailfrom=makrotopia.org; arc=none smtp.client-ip=185.142.180.65 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=makrotopia.org Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=makrotopia.org Received: from local by pidgin.makrotopia.org with esmtpsa (TLS1.3:TLS_AES_256_GCM_SHA384:256) (Exim 4.99) (envelope-from ) id 1wmLKR-0000000011Z-1W3E; Wed, 22 Jul 2026 01:00:55 +0000 Date: Wed, 22 Jul 2026 02:00:52 +0100 From: Daniel Golle To: Andrzej Hajda , Neil Armstrong , Robert Foss , Laurent Pinchart , Jonas Karlman , Jernej Skrabec , Luca Ceresoli , Maarten Lankhorst , Maxime Ripard , Thomas Zimmermann , David Airlie , Simona Vetter , Matthias Brugger , AngeloGioacchino Del Regno , Hermes Wu , Allen Chen , Pin-yen Lin , dri-devel@lists.freedesktop.org, linux-kernel@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-mediatek@lists.infradead.org Cc: Chen-Yu Tsai Subject: [PATCH v4 5/5] drm/bridge: it6505: Don't reject audio hw_params without an encoder Message-ID: <2c08315fede798f8632fe985da5ffd568c945de3.1784681487.git.daniel@makrotopia.org> References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Disposition: inline In-Reply-To: Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" it6505_audio_setup_hw_params() returns -ENODEV when the bridge is not attached to a DRM encoder. Now that it6505 registers an hdmi-audio-codec, this callback runs whenever a stream is configured on the I2S DAI it is wired to, including when that DAI is shared with another codec. On mt8186-corsola the speaker amplifier (rt1019) and it6505 share I2S3, so when the it6505 DP output has no display attached (bridge.encoder is NULL) the -ENODEV propagates up through dpcm_be_dai_hw_params() and tears down the whole backend, breaking speaker playback. The check is harmful in its own right: the rest of the function only caches the stream parameters (channel count, rate, word length) in software, none of which needs an encoder. Returning early leaves it6505->audio.channel_count at 0, which would then index audio_info_ca[-1] in it6505_enable_audio_infoframe() should a display be hotplugged while a stream is running, and makes such a hotplug play with stale parameters. Drop the encoder check so the parameters are always cached; the actual audio output is already gated by it6505->powered. For the cached parameters to survive until a display shows up they must also not be clobbered when it appears: it6505_variable_config() re-applies the compile-time audio defaults on every fresh DPCD read. Apply the defaults once at probe time instead, so a hotplug uses whatever ALSA last configured. Fixes: b5c84a9edcd4 ("drm/bridge: add it6505 driver") Signed-off-by: Daniel Golle --- v4: * move the audio parameter defaults from it6505_variable_config() to probe time: it runs again on every fresh DPCD read (i.e. on display hotplug) and would clobber the parameters cached from hw_params with the 2ch/48kHz defaults, defeating this patch's purpose; flagged by Sashiko AI review of v3 v3: no changes v2: drop the encoder check entirely instead of returning 0 early, so the stream parameters are always cached even while no display is attached; rewrite the commit message to explain why the check is harmful drivers/gpu/drm/bridge/ite-it6505.c | 23 ++++++++++------------- 1 file changed, 10 insertions(+), 13 deletions(-) diff --git a/drivers/gpu/drm/bridge/ite-it6505.c b/drivers/gpu/drm/bridge/i= te-it6505.c index 6bb5db565cca..e01d57b0166a 100644 --- a/drivers/gpu/drm/bridge/ite-it6505.c +++ b/drivers/gpu/drm/bridge/ite-it6505.c @@ -1369,16 +1369,6 @@ static void it6505_variable_config(struct it6505 *it= 6505) it6505->link_state =3D LINK_IDLE; it6505->hdcp_desired =3D HDCP_DESIRED; it6505->auto_train_retry =3D AUTO_TRAIN_RETRY; - it6505->audio.select =3D AUDIO_SELECT; - it6505->audio.sample_rate =3D AUDIO_SAMPLE_RATE; - it6505->audio.channel_count =3D AUDIO_CHANNEL_COUNT; - it6505->audio.type =3D AUDIO_TYPE; - it6505->audio.i2s_input_format =3D I2S_INPUT_FORMAT; - it6505->audio.i2s_justified =3D I2S_JUSTIFIED; - it6505->audio.i2s_data_delay =3D I2S_DATA_DELAY; - it6505->audio.i2s_ws_channel =3D I2S_WS_CHANNEL; - it6505->audio.i2s_data_sequence =3D I2S_DATA_SEQUENCE; - it6505->audio.word_length =3D AUDIO_WORD_LENGTH; memset(it6505->sha1_input, 0, sizeof(it6505->sha1_input)); memset(it6505->bksvs, 0, sizeof(it6505->bksvs)); } @@ -3004,9 +2994,6 @@ static int it6505_audio_setup_hw_params(struct it6505= *it6505, params->sample_rate, params->sample_width, params->cea.channels); =20 - if (!it6505->bridge.encoder) - return -ENODEV; - if (params->cea.channels <=3D 1 || params->cea.channels > 8) { DRM_DEV_DEBUG_DRIVER(dev, "channel number: %d not support", params->cea.channels); @@ -3137,6 +3124,16 @@ static int it6505_register_audio_driver(struct devic= e *dev) }; struct platform_device *pdev; =20 + it6505->audio.select =3D AUDIO_SELECT; + it6505->audio.sample_rate =3D AUDIO_SAMPLE_RATE; + it6505->audio.channel_count =3D AUDIO_CHANNEL_COUNT; + it6505->audio.type =3D AUDIO_TYPE; + it6505->audio.i2s_input_format =3D I2S_INPUT_FORMAT; + it6505->audio.i2s_justified =3D I2S_JUSTIFIED; + it6505->audio.i2s_data_delay =3D I2S_DATA_DELAY; + it6505->audio.i2s_ws_channel =3D I2S_WS_CHANNEL; + it6505->audio.i2s_data_sequence =3D I2S_DATA_SEQUENCE; + it6505->audio.word_length =3D AUDIO_WORD_LENGTH; it6505->audio.mute =3D true; INIT_DELAYED_WORK(&it6505->delayed_audio, it6505_delayed_audio); =20 --=20 2.55.0