From nobody Fri Oct 3 10:15:02 2025 Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) (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 BD15B2F6197; Tue, 2 Sep 2025 10:57:23 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=213.167.242.64 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1756810645; cv=none; b=ccbR41HXv3rkODHv4vJn1c83Q/7HyBd/7DcCI2IBdhZnsIB0Z7Cw8nzVl2xEcnZn+S2SaWlfp5t6xd9lf8Otutor2E6YUkOATZcvj2kR6V9EVKl67Ok0nbYigEjLw8nLuI3n/lLJug9HlyJR+DBjJZ5nB+mxxSQkUgQjziwZiWg= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1756810645; c=relaxed/simple; bh=huBM6u3sNxRpnxJBrZpY0B7keydyhtbBnOV4Aft0+Tg=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=rrnHniZ5joRw2zJllspz3EtndQEvs5T1utF53qV8JbPwpRYJ6448OdeNy7bnISumD7Dx4NJP/2SEbTWYOYBGGNKD9IyFGs6rWKtzfgVjatQOQRYAnOTaxC+jTK242hL6fHFazHeHf+3QxChluz34o15LlzEl6CenFUMAz0mnDos= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=ideasonboard.com; spf=pass smtp.mailfrom=ideasonboard.com; dkim=pass (1024-bit key) header.d=ideasonboard.com header.i=@ideasonboard.com header.b=bVR3NfNJ; arc=none smtp.client-ip=213.167.242.64 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=ideasonboard.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=ideasonboard.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="bVR3NfNJ" Received: from mail.ideasonboard.com (unknown [IPv6:2401:4900:1c69:480e:e039:1d0b:c5ff:a9e2]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id B806BC72; Tue, 2 Sep 2025 12:56:13 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1756810574; bh=huBM6u3sNxRpnxJBrZpY0B7keydyhtbBnOV4Aft0+Tg=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From; b=bVR3NfNJXo19V+OFTH52Pf7nSF1ZdTLYNVYhB8F4oJTKduI2L6yKRff+uxlo6eg1Q +8XmKPvMgZ/ONQ+qCTL/XBuPzUfeZdrWH2cGU0DqBll36jL9KqQa80nxUBZ8aAsWMd 3KUnm0vssVh6G5UOXZHlzrz0sDhnN9MiE0n2zoOE= From: Jai Luthra Date: Tue, 02 Sep 2025 16:26:49 +0530 Subject: [PATCH v2 1/3] media: cadence: csi2rx: Support runtime PM Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20250902-ti_csi_pm-v2-1-59a3be199940@ideasonboard.com> References: <20250902-ti_csi_pm-v2-0-59a3be199940@ideasonboard.com> In-Reply-To: <20250902-ti_csi_pm-v2-0-59a3be199940@ideasonboard.com> To: Mauro Carvalho Chehab , Maxime Ripard , Philipp Zabel , Sakari Ailus Cc: linux-media@vger.kernel.org, linux-kernel@vger.kernel.org, Laurent Pinchart , Tomi Valkeinen , Changhuang Liang , Devarsh Thakkar , Rishikesh Donadkar , Jai Luthra X-Mailer: b4 0.14.2 X-Developer-Signature: v=1; a=openpgp-sha256; l=7583; i=jai.luthra@ideasonboard.com; h=from:subject:message-id; bh=aqs7ljfIPQcuvWd4u15PtiVXmyox+XqlctCH69f8xUo=; b=owEBbQKS/ZANAwAKAUPekfkkmnFFAcsmYgBots2EsH2ECW4WrkGMf9IhFc2guYWfLpMy+syRB 7lQZFhWEmGJAjMEAAEKAB0WIQRN4NgY5dV16NRar8VD3pH5JJpxRQUCaLbNhAAKCRBD3pH5JJpx ReOvD/0W9Znq3jQz4qU/8xuF80OFy1F1Xwa8z405/6mt8FV4bce5NyIXczf5dxsxNsAlK3NL/D1 ryKJ1eRLoitCn0Ypzx5bVnhzzMEW7cgILYdr+/BLOismVhSZ7bCyIWvzxf6aG2vsKrdSGwj4rmL xGR0LpW8lEDXXusIUl3J3McfsEocZm00i2wdMv9uiB1aTxeiiyJf07DR55JvL7lMUOsqybgZh00 KwF6inao7g+/cXnTsxBYnmSDxJtyDVDDB9uyVR8n6tZjPKGKhGY6IaeVloHiXnHrhrjE/a16cUS GtO9gE0gZGRnqlwGZOFT8hlWwBM++u6AuVvtRdvx+M/kyKQv8fYOBv3gg/RpucewtPXqSvt/XwI FSpQwv9YDQFN+RDsZenio9bh6DWwRtHmU7HfVlfmHb1sjAu2UK/X/EcrZC9tUPw+zQaazT1Mpdn RaO3/V296tzLdJsB5Fho6YRYEudHT42Zq681sRwPJlQYRe7CTemk3xk1fjGKFpClLIvvxAg8vyv xTbkLLpj60W41swjF4IEzTnnXdg/z52RFUqVpv3OEOS8fqxrF9+FahCMA6ugfoucCgnMZHT/5t/ 8RJEaIAv2X2sko4GWw6vLwRuKDMsVOhNTJiDYdglFSrUog3oYlnWrtZ756BRs8AHcRAEjxbuyFL 8wlatMiGlAlFMfA== X-Developer-Key: i=jai.luthra@ideasonboard.com; a=openpgp; fpr=4DE0D818E5D575E8D45AAFC543DE91F9249A7145 From: Changhuang Liang Use runtime power management hooks to save power when CSI-RX is not in use. Signed-off-by: Changhuang Liang Tested-by: Rishikesh Donadkar Reviewed-by: Rishikesh Donadkar Signed-off-by: Jai Luthra --- drivers/media/platform/cadence/Kconfig | 1 + drivers/media/platform/cadence/cdns-csi2rx.c | 129 +++++++++++++++++------= ---- 2 files changed, 83 insertions(+), 47 deletions(-) diff --git a/drivers/media/platform/cadence/Kconfig b/drivers/media/platfor= m/cadence/Kconfig index 1aa608c00dbce9b52d0d48b5ac8c877db7494fd7..ea85ef82760e694c1e03fa323fc= 7a468b135e2e1 100644 --- a/drivers/media/platform/cadence/Kconfig +++ b/drivers/media/platform/cadence/Kconfig @@ -5,6 +5,7 @@ comment "Cadence media platform drivers" config VIDEO_CADENCE_CSI2RX tristate "Cadence MIPI-CSI2 RX Controller" depends on VIDEO_DEV + depends on PM select MEDIA_CONTROLLER select VIDEO_V4L2_SUBDEV_API select V4L2_FWNODE diff --git a/drivers/media/platform/cadence/cdns-csi2rx.c b/drivers/media/p= latform/cadence/cdns-csi2rx.c index 11b73c79adff8c2be0b363eea3b54dd050842c81..fce9397448cda253d4de2c69050= ff47059e0e1f1 100644 --- a/drivers/media/platform/cadence/cdns-csi2rx.c +++ b/drivers/media/platform/cadence/cdns-csi2rx.c @@ -343,11 +343,6 @@ static int csi2rx_start(struct csi2rx_priv *csi2rx) u32 reg; int ret; =20 - ret =3D clk_prepare_enable(csi2rx->p_clk); - if (ret) - return ret; - - reset_control_deassert(csi2rx->p_rst); csi2rx_reset(csi2rx); =20 if (csi2rx->error_irq >=3D 0) @@ -388,7 +383,7 @@ static int csi2rx_start(struct csi2rx_priv *csi2rx) if (ret) { dev_err(csi2rx->dev, "Failed to configure external DPHY: %d\n", ret); - goto err_disable_pclk; + return ret; } } =20 @@ -403,12 +398,6 @@ static int csi2rx_start(struct csi2rx_priv *csi2rx) * hence the reference counting. */ for (i =3D 0; i < csi2rx->max_streams; i++) { - ret =3D clk_prepare_enable(csi2rx->pixel_clk[i]); - if (ret) - goto err_disable_pixclk; - - reset_control_deassert(csi2rx->pixel_rst[i]); - writel(CSI2RX_STREAM_CFG_FIFO_MODE_LARGE_BUF | FIELD_PREP(CSI2RX_STREAM_CFG_NUM_PIXELS_MASK, csi2rx->num_pixels[i]), @@ -421,30 +410,8 @@ static int csi2rx_start(struct csi2rx_priv *csi2rx) csi2rx->base + CSI2RX_STREAM_CTRL_REG(i)); } =20 - ret =3D clk_prepare_enable(csi2rx->sys_clk); - if (ret) - goto err_disable_pixclk; - - reset_control_deassert(csi2rx->sys_rst); - - clk_disable_unprepare(csi2rx->p_clk); =20 return 0; - -err_disable_pixclk: - for (; i > 0; i--) { - reset_control_assert(csi2rx->pixel_rst[i - 1]); - clk_disable_unprepare(csi2rx->pixel_clk[i - 1]); - } - - if (csi2rx->dphy) { - writel(0, csi2rx->base + CSI2RX_DPHY_LANE_CTRL_REG); - phy_power_off(csi2rx->dphy); - } -err_disable_pclk: - clk_disable_unprepare(csi2rx->p_clk); - - return ret; } =20 static void csi2rx_stop(struct csi2rx_priv *csi2rx) @@ -453,10 +420,6 @@ static void csi2rx_stop(struct csi2rx_priv *csi2rx) u32 val; int ret; =20 - clk_prepare_enable(csi2rx->p_clk); - reset_control_assert(csi2rx->sys_rst); - clk_disable_unprepare(csi2rx->sys_clk); - writel(0, csi2rx->base + CSI2RX_ERROR_IRQS_MASK_REG); =20 for (i =3D 0; i < csi2rx->max_streams; i++) { @@ -471,14 +434,8 @@ static void csi2rx_stop(struct csi2rx_priv *csi2rx) if (ret) dev_warn(csi2rx->dev, "Failed to stop streaming on pad%u\n", i); - - reset_control_assert(csi2rx->pixel_rst[i]); - clk_disable_unprepare(csi2rx->pixel_clk[i]); } =20 - reset_control_assert(csi2rx->p_rst); - clk_disable_unprepare(csi2rx->p_clk); - if (csi2rx->dphy) { writel(0, csi2rx->base + CSI2RX_DPHY_LANE_CTRL_REG); =20 @@ -555,10 +512,17 @@ static int csi2rx_enable_streams(struct v4l2_subdev *= subdev, * enable the whole controller. */ if (!csi2rx->count) { + ret =3D pm_runtime_resume_and_get(csi2rx->dev); + if (ret < 0) + return ret; + csi2rx_update_vc_select(csi2rx, state); + ret =3D csi2rx_start(csi2rx); - if (ret) + if (ret) { + pm_runtime_put(csi2rx->dev); return ret; + } } =20 /* Start streaming on the source */ @@ -568,8 +532,10 @@ static int csi2rx_enable_streams(struct v4l2_subdev *s= ubdev, dev_err(csi2rx->dev, "Failed to start streams %#llx on subdev\n", sink_streams); - if (!csi2rx->count) + if (!csi2rx->count) { csi2rx_stop(csi2rx); + pm_runtime_put(csi2rx->dev); + } return ret; } =20 @@ -597,8 +563,10 @@ static int csi2rx_disable_streams(struct v4l2_subdev *= subdev, csi2rx->count--; =20 /* Let the last user turn off the lights. */ - if (!csi2rx->count) + if (!csi2rx->count) { csi2rx_stop(csi2rx); + pm_runtime_put(csi2rx->dev); + } =20 return 0; } @@ -1101,6 +1069,7 @@ static int csi2rx_probe(struct platform_device *pdev) if (ret) goto err_cleanup; =20 + pm_runtime_enable(csi2rx->dev); ret =3D v4l2_async_register_subdev(&csi2rx->subdev); if (ret < 0) goto err_free_state; @@ -1115,6 +1084,7 @@ static int csi2rx_probe(struct platform_device *pdev) =20 err_free_state: v4l2_subdev_cleanup(&csi2rx->subdev); + pm_runtime_disable(csi2rx->dev); err_cleanup: v4l2_async_nf_unregister(&csi2rx->notifier); v4l2_async_nf_cleanup(&csi2rx->notifier); @@ -1133,9 +1103,73 @@ static void csi2rx_remove(struct platform_device *pd= ev) v4l2_async_unregister_subdev(&csi2rx->subdev); v4l2_subdev_cleanup(&csi2rx->subdev); media_entity_cleanup(&csi2rx->subdev.entity); + pm_runtime_disable(csi2rx->dev); kfree(csi2rx); } =20 +static int csi2rx_runtime_suspend(struct device *dev) +{ + struct csi2rx_priv *csi2rx =3D dev_get_drvdata(dev); + unsigned int i; + + reset_control_assert(csi2rx->sys_rst); + clk_disable_unprepare(csi2rx->sys_clk); + + for (i =3D 0; i < csi2rx->max_streams; i++) { + reset_control_assert(csi2rx->pixel_rst[i]); + clk_disable_unprepare(csi2rx->pixel_clk[i]); + } + + reset_control_assert(csi2rx->p_rst); + clk_disable_unprepare(csi2rx->p_clk); + + return 0; +} + +static int csi2rx_runtime_resume(struct device *dev) +{ + struct csi2rx_priv *csi2rx =3D dev_get_drvdata(dev); + unsigned int i; + int ret; + + ret =3D clk_prepare_enable(csi2rx->p_clk); + if (ret) + return ret; + + reset_control_deassert(csi2rx->p_rst); + + for (i =3D 0; i < csi2rx->max_streams; i++) { + ret =3D clk_prepare_enable(csi2rx->pixel_clk[i]); + if (ret) + goto err_disable_pixclk; + + reset_control_deassert(csi2rx->pixel_rst[i]); + } + + ret =3D clk_prepare_enable(csi2rx->sys_clk); + if (ret) + goto err_disable_pixclk; + + reset_control_deassert(csi2rx->sys_rst); + + return 0; + +err_disable_pixclk: + for (; i > 0; i--) { + reset_control_assert(csi2rx->pixel_rst[i - 1]); + clk_disable_unprepare(csi2rx->pixel_clk[i - 1]); + } + + reset_control_assert(csi2rx->p_rst); + clk_disable_unprepare(csi2rx->p_clk); + + return ret; +} + +static const struct dev_pm_ops csi2rx_pm_ops =3D { + RUNTIME_PM_OPS(csi2rx_runtime_suspend, csi2rx_runtime_resume, NULL) +}; + static const struct of_device_id csi2rx_of_table[] =3D { { .compatible =3D "starfive,jh7110-csi2rx" }, { .compatible =3D "cdns,csi2rx" }, @@ -1150,6 +1184,7 @@ static struct platform_driver csi2rx_driver =3D { .driver =3D { .name =3D "cdns-csi2rx", .of_match_table =3D csi2rx_of_table, + .pm =3D &csi2rx_pm_ops, }, }; module_platform_driver(csi2rx_driver); --=20 2.50.1 From nobody Fri Oct 3 10:15:02 2025 Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) (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 C75D92F617D; Tue, 2 Sep 2025 10:57:30 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=213.167.242.64 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1756810652; cv=none; b=bD/pBZJbtJ7dHJWYKHmWWZT1/5wxFoQwYP2b0iZwAK7ojLVs6dj/6zJ1KKD1Y624gIA1HzE83vDzNdmGgidolXMxEhxaF/yeLJtFQJTWYvf0z8uLMYaWBJcILs5lThEhN6W7/tNTkuNEx79bao8o6p8zYrKozuYXNWYPbNNbe5U= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1756810652; c=relaxed/simple; bh=RuHVHnR21Q8ucDLs4WTrD09d5g8ramYRZLMjgtPRKL0=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=Vta+IXaHerbeUu8NBcrTJr1qUcACgggtD2qZqixUm8mPTtPiFW2/YnOUc1LswRh8Sx13SXekpHQ4TQ88WfZwuQbw0hO7OtbeAe9yJX1bWXiE2Q3KXW/SKXoe+/egc2BBod/lIrpOYnKsTfEb90T14Szrf0yYsSOpLFhI4Podekc= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=ideasonboard.com; spf=pass smtp.mailfrom=ideasonboard.com; dkim=pass (1024-bit key) header.d=ideasonboard.com header.i=@ideasonboard.com header.b=Mnd+M1wZ; arc=none smtp.client-ip=213.167.242.64 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=ideasonboard.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=ideasonboard.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="Mnd+M1wZ" Received: from mail.ideasonboard.com (unknown [IPv6:2401:4900:1c69:480e:e039:1d0b:c5ff:a9e2]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id CCBB978C; Tue, 2 Sep 2025 12:56:20 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1756810581; bh=RuHVHnR21Q8ucDLs4WTrD09d5g8ramYRZLMjgtPRKL0=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From; b=Mnd+M1wZ5K3sTAWXlSZFZ3UAsb90S/pwmabWTt/DM1PBb6Mlgdpcb/GZE98q6LFiz A+/tTNgsupyWPhDCkIXLnHdmJxDOQP3dmEO22fAK2fuoLVAEhB5nJvBXUc1slbwTyy T6pMnuN61eGjEdg1oCIV7RARG4La0FUDXjppsSdo= From: Jai Luthra Date: Tue, 02 Sep 2025 16:26:50 +0530 Subject: [PATCH v2 2/3] media: ti: j721e-csi2rx: Support runtime suspend Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20250902-ti_csi_pm-v2-2-59a3be199940@ideasonboard.com> References: <20250902-ti_csi_pm-v2-0-59a3be199940@ideasonboard.com> In-Reply-To: <20250902-ti_csi_pm-v2-0-59a3be199940@ideasonboard.com> To: Mauro Carvalho Chehab , Maxime Ripard , Philipp Zabel , Sakari Ailus Cc: linux-media@vger.kernel.org, linux-kernel@vger.kernel.org, Laurent Pinchart , Tomi Valkeinen , Changhuang Liang , Devarsh Thakkar , Rishikesh Donadkar , Jai Luthra X-Mailer: b4 0.14.2 X-Developer-Signature: v=1; a=openpgp-sha256; l=4901; i=jai.luthra@ideasonboard.com; h=from:subject:message-id; bh=RuHVHnR21Q8ucDLs4WTrD09d5g8ramYRZLMjgtPRKL0=; b=owEBbQKS/ZANAwAKAUPekfkkmnFFAcsmYgBots2F3Kn5WL1RrK11Y458F88L+3IiH/S36ebux 0eIAPKo+K6JAjMEAAEKAB0WIQRN4NgY5dV16NRar8VD3pH5JJpxRQUCaLbNhQAKCRBD3pH5JJpx Rb1gD/9sSeyCIizmLzdyMjDbrLuf2Q3kHrqGJZfnkQZU2ENI3ayHxuNoUS4+vonH0FfrPrWR0h4 CXCSzf6dUKMTZjHNm3xM90auEWACNFTPNfgQNwEQg2sOuTeXq5nhRrWSLGj091d+K1VbisSRQJr 99fzhecvL4Xe+jeKwSLzAnJkTBsfnOZOlIazX0tVc3gs27j7lRc21rhRX81NDAV5mIlmCPgjplD EQEgZ8J5uo6odeHtXTsf3EcjojE6MQ2fjHmxqUw6xUL64y90EGDrzK4sDtelHkYHDIG8S2BbZkj G8y5jTaISSa8h/FtZUGvERzBqMdK6wr5cbDj/TT7gbluLAu8IElGd1u+LWSAOTJV2S1co5Ow0so tKYa39Q5ATvLt9g2yZv9mxDiD2P3HslZ2mCc+kFyCM9NQvzI1hF2LcYbvZyCB+Ed2X4tXEqsoMy mfUGscYE2j84vHNbqSLLZEVQ8dMgxlQdhODv32isgCTYNJyERvaTHq4KW0S3pYl21+ilXAofklD k+r2tpq3u96ADdy7mXdevEfGin7tg+s7Hoaqhpwo8k8y5hB3RLlUayViRA7niKfPa3kpPvp6uSa T52T3HaFPIy1My8A3RLWX0dhhKwHcggRwMnqVcU+fOMkNZlVwJd3AVU1stz6ZQMQze+LbvUFknc Fll5TXNDTKifHzA== X-Developer-Key: i=jai.luthra@ideasonboard.com; a=openpgp; fpr=4DE0D818E5D575E8D45AAFC543DE91F9249A7145 Add support for runtime power-management to enable powering off the shared power domain between Cadence CSI2RX and TI CSI2RX wrapper when the device(s) are not in use. When powering off the IP, the PSI-L endpoint loses the paired DMA channels. Thus we have to release the DMA channels at runtime suspend and request them again at resume. Tested-by: Rishikesh Donadkar Reviewed-by: Rishikesh Donadkar Signed-off-by: Jai Luthra --- drivers/media/platform/ti/Kconfig | 1 + .../media/platform/ti/j721e-csi2rx/j721e-csi2rx.c | 55 ++++++++++++++++++= +++- 2 files changed, 54 insertions(+), 2 deletions(-) diff --git a/drivers/media/platform/ti/Kconfig b/drivers/media/platform/ti/= Kconfig index 3bc4aa35887e6edc9fa8749d9956a67714c59001..a808063e24779d72b1f73a15b38= c021dfb915fa0 100644 --- a/drivers/media/platform/ti/Kconfig +++ b/drivers/media/platform/ti/Kconfig @@ -70,6 +70,7 @@ config VIDEO_TI_J721E_CSI2RX depends on VIDEO_CADENCE_CSI2RX depends on PHY_CADENCE_DPHY_RX || COMPILE_TEST depends on ARCH_K3 || COMPILE_TEST + depends on PM select VIDEOBUF2_DMA_CONTIG select V4L2_FWNODE help diff --git a/drivers/media/platform/ti/j721e-csi2rx/j721e-csi2rx.c b/driver= s/media/platform/ti/j721e-csi2rx/j721e-csi2rx.c index 3acd01223cdd2191ba67b4efc3f84695c525624b..a5cd7885f26b2cda87e0c68833c= 2cc584061698e 100644 --- a/drivers/media/platform/ti/j721e-csi2rx/j721e-csi2rx.c +++ b/drivers/media/platform/ti/j721e-csi2rx/j721e-csi2rx.c @@ -13,6 +13,7 @@ #include #include #include +#include #include =20 #include @@ -988,12 +989,16 @@ static int ti_csi2rx_start_streaming(struct vb2_queue= *vq, unsigned int count) unsigned long flags; int ret =3D 0; =20 + ret =3D pm_runtime_resume_and_get(csi->dev); + if (ret) + return ret; + spin_lock_irqsave(&dma->lock, flags); if (list_empty(&dma->queue)) ret =3D -EIO; spin_unlock_irqrestore(&dma->lock, flags); if (ret) - return ret; + goto err; =20 ret =3D video_device_pipeline_start(&ctx->vdev, &csi->pipe); if (ret) @@ -1049,6 +1054,8 @@ static int ti_csi2rx_start_streaming(struct vb2_queue= *vq, unsigned int count) writel(0, csi->shim + SHIM_DMACNTX(ctx->idx)); err: ti_csi2rx_cleanup_buffers(ctx, VB2_BUF_STATE_QUEUED); + pm_runtime_put(csi->dev); + return ret; } =20 @@ -1080,6 +1087,7 @@ static void ti_csi2rx_stop_streaming(struct vb2_queue= *vq) =20 ti_csi2rx_stop_dma(ctx); ti_csi2rx_cleanup_buffers(ctx, VB2_BUF_STATE_ERROR); + pm_runtime_put(csi->dev); } =20 static const struct vb2_ops csi_vb2_qops =3D { @@ -1288,7 +1296,9 @@ static void ti_csi2rx_cleanup_notifier(struct ti_csi2= rx_dev *csi) =20 static void ti_csi2rx_cleanup_ctx(struct ti_csi2rx_ctx *ctx) { - dma_release_channel(ctx->dma.chan); + if (!pm_runtime_status_suspended(ctx->csi->dev)) + dma_release_channel(ctx->dma.chan); + vb2_queue_release(&ctx->vidq); =20 video_unregister_device(&ctx->vdev); @@ -1544,6 +1554,39 @@ static int ti_csi2rx_init_ctx(struct ti_csi2rx_ctx *= ctx) return ret; } =20 +static int ti_csi2rx_runtime_suspend(struct device *dev) +{ + struct ti_csi2rx_dev *csi =3D dev_get_drvdata(dev); + int i; + + if (csi->enable_count !=3D 0) + return -EBUSY; + + for (i =3D 0; i < csi->num_ctx; i++) + dma_release_channel(csi->ctx[i].dma.chan); + + return 0; +} + +static int ti_csi2rx_runtime_resume(struct device *dev) +{ + struct ti_csi2rx_dev *csi =3D dev_get_drvdata(dev); + int ret, i; + + for (i =3D 0; i < csi->num_ctx; i++) { + ret =3D ti_csi2rx_init_dma(&csi->ctx[i]); + if (ret) + return ret; + } + + return 0; +} + +static const struct dev_pm_ops ti_csi2rx_pm_ops =3D { + RUNTIME_PM_OPS(ti_csi2rx_runtime_suspend, ti_csi2rx_runtime_resume, + NULL) +}; + static int ti_csi2rx_probe(struct platform_device *pdev) { struct device_node *np =3D pdev->dev.of_node; @@ -1610,6 +1653,10 @@ static int ti_csi2rx_probe(struct platform_device *p= dev) goto err_notifier; } =20 + pm_runtime_set_active(csi->dev); + pm_runtime_enable(csi->dev); + pm_request_idle(csi->dev); + return 0; =20 err_notifier: @@ -1640,6 +1687,9 @@ static void ti_csi2rx_remove(struct platform_device *= pdev) mutex_destroy(&csi->mutex); dma_free_coherent(csi->dev, csi->drain.len, csi->drain.vaddr, csi->drain.paddr); + pm_runtime_disable(&pdev->dev); + pm_runtime_set_suspended(&pdev->dev); + } =20 static const struct of_device_id ti_csi2rx_of_match[] =3D { @@ -1654,6 +1704,7 @@ static struct platform_driver ti_csi2rx_pdrv =3D { .driver =3D { .name =3D TI_CSI2RX_MODULE_NAME, .of_match_table =3D ti_csi2rx_of_match, + .pm =3D &ti_csi2rx_pm_ops, }, }; =20 --=20 2.50.1 From nobody Fri Oct 3 10:15:02 2025 Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) (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 43DB62FA0FC; Tue, 2 Sep 2025 10:57:35 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=213.167.242.64 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1756810657; cv=none; b=c5LsSgVHUGh2kXm7xpezWGqVug42D/gHww9Jj6ZEFoVJrbqHC8vPS7tDqx8bZVjmNTK6RQ72ZkCDIoUKLudBgh0U5MYMRLqph5QTyHh7waiLI6Hp0iiUhts4etaWV1oPWAP7uqW+JcZWnWTCN114NlNEYXnt3bBlL+u3vej4rBQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1756810657; c=relaxed/simple; bh=yK29nMj0x/n6vyRa/wmf8inh11piNH7wp9tI8JUNnPA=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=gcdqvSuiQfk8GQfFoLeAC5iIJBM8LMtwMByigokzzW3rbyGsVovXYH8zLF64ASE+yaWaXJ4YlDDllOYm2drf7/sZkSUl8Dd3I7CuobHZTk6Bzu2itCAUA60p6KR1AGWJzNtEYacdcYqx8q2WXtdR/c0BJAh5JsgJV9mZRx7qea8= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=ideasonboard.com; spf=pass smtp.mailfrom=ideasonboard.com; dkim=pass (1024-bit key) header.d=ideasonboard.com header.i=@ideasonboard.com header.b=p4uuKyOO; arc=none smtp.client-ip=213.167.242.64 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=ideasonboard.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=ideasonboard.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="p4uuKyOO" Received: from mail.ideasonboard.com (unknown [IPv6:2401:4900:1c69:480e:e039:1d0b:c5ff:a9e2]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id B51D5C72; Tue, 2 Sep 2025 12:56:25 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1756810586; bh=yK29nMj0x/n6vyRa/wmf8inh11piNH7wp9tI8JUNnPA=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From; b=p4uuKyOO//Wk/8NkBzRzYjK6tSNrsoS0vxIUMVfcaDIDJPuduaENYNRlPYjOekYXs RMgbi6vtFf5qlBJrSEwRRsinuiC0C0gDzd9iS81b0toQuEdXZzRSugrOd5t2Ojbe4j FJC1/ROAug4mlAXNjQQRzqdmqhFxMka0sArMWyOI= From: Jai Luthra Date: Tue, 02 Sep 2025 16:26:51 +0530 Subject: [PATCH v2 3/3] media: ti: j721e-csi2rx: Support system suspend using pm_notifier Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20250902-ti_csi_pm-v2-3-59a3be199940@ideasonboard.com> References: <20250902-ti_csi_pm-v2-0-59a3be199940@ideasonboard.com> In-Reply-To: <20250902-ti_csi_pm-v2-0-59a3be199940@ideasonboard.com> To: Mauro Carvalho Chehab , Maxime Ripard , Philipp Zabel , Sakari Ailus Cc: linux-media@vger.kernel.org, linux-kernel@vger.kernel.org, Laurent Pinchart , Tomi Valkeinen , Changhuang Liang , Devarsh Thakkar , Rishikesh Donadkar , Jai Luthra X-Mailer: b4 0.14.2 X-Developer-Signature: v=1; a=openpgp-sha256; l=6315; i=jai.luthra@ideasonboard.com; h=from:subject:message-id; bh=yK29nMj0x/n6vyRa/wmf8inh11piNH7wp9tI8JUNnPA=; b=owEBbQKS/ZANAwAKAUPekfkkmnFFAcsmYgBots2GcoiTbnZO5rpex82JVzhv5SwYs3r4gAHkn a9BaMNVHsmJAjMEAAEKAB0WIQRN4NgY5dV16NRar8VD3pH5JJpxRQUCaLbNhgAKCRBD3pH5JJpx RSiyD/9ppkQe4UMAIjUQiC3u8HIex6vMh+R7qkGtgXvafaGrReAk0shvkcGYeLh3j2xwh6dKOby xc2VQLKjdem/TtmaP0qJCKYyoDHVTZt78CEwPpU6ruemszLzbFyP4jg5FklUh3t+uUcfHzN5Q9a pVSymfM5PFahlHsBK+Ja7rXwta3RYbkX6fy8CxibZqoYwdGiXjY+jqcwWazlGOw7YmL4aWttzCV tmWGU1Ph4W0/qPkK8MehCMA+DjbAjG/wuTzsk1Z53j3WxZS4pPHbbmwNaybg6zx4nDMvQNAPPxp oMcaZ0R6rUer5lptl6BjShrw0fC+s8C3qUZIaXtvCf8wSTxd2WtAnLAiJMch/PF+ZFpOh9cuDWC SfgvhKrxzAjUnyzlT6QnoZB9Xvi6jA07Kaauz1CZjQDlf55GeuErLWneAsaO1xyxhuTJeF64t/+ eqx8XsYDyopcV+JmU0FkM6kzkuLjzGC872lo8qrNWIL4ZPstAIIEYbri8hMTD3hao+rLsvKi3Fo DvIvvy1zegf9GW50sJ7+EMbk2TnsdpvEZ/WH5vvdg1MioCB0uzDDL6wbcQVVi4FvhXQ1BeTtKYX WGqbAtfzUQof0E8lpvFgPx8uAUAAmLh9S0tuxoLwWLh81S3pqZlKiXMfhe6XM7TorLS6bkclioN 4wiNobxzueFulug== X-Developer-Key: i=jai.luthra@ideasonboard.com; a=openpgp; fpr=4DE0D818E5D575E8D45AAFC543DE91F9249A7145 As this device is the "orchestrator" for the rest of the media pipeline, we need to stop all on-going streams before system suspend and enable them back when the system wakes up from sleep. Using .suspend/.resume callbacks does not work, as the order of those callbacks amongst various devices in the camera pipeline like the sensor, FPD serdes, CSI bridge etc. is impossible to enforce, even with device links. For example, the Cadence CSI bridge is a child device of this device, thus we cannot create a device link with the CSI bridge as a provider and this device as consumer. This can lead to situations where all the dependencies for the bridge have not yet resumed when we request the subdev to start streaming again through the .resume callback defined in this device. Instead here we register a notifier callback with the PM framework which is triggered when the system is fully functional. At this point we can cleanly stop or start the streams, because we know all other devices and their dependencies are functional. A downside of this approach is that the userspace is also alive (not frozen yet, or just thawed), so the suspend notifier might complete before the userspace has completed all ioctls, like QBUF/DQBUF/STREAMON/STREAMOFF. Tested-by: Rishikesh Donadkar Reviewed-by: Rishikesh Donadkar Signed-off-by: Jai Luthra --- .../media/platform/ti/j721e-csi2rx/j721e-csi2rx.c | 128 +++++++++++++++++= ++++ 1 file changed, 128 insertions(+) diff --git a/drivers/media/platform/ti/j721e-csi2rx/j721e-csi2rx.c b/driver= s/media/platform/ti/j721e-csi2rx/j721e-csi2rx.c index a5cd7885f26b2cda87e0c68833c2cc584061698e..49860916a29ebe89a300d372368= f11ce4a078b50 100644 --- a/drivers/media/platform/ti/j721e-csi2rx/j721e-csi2rx.c +++ b/drivers/media/platform/ti/j721e-csi2rx/j721e-csi2rx.c @@ -131,6 +131,7 @@ struct ti_csi2rx_dev { struct v4l2_subdev *source; struct v4l2_subdev subdev; struct ti_csi2rx_ctx ctx[TI_CSI2RX_MAX_CTX]; + struct notifier_block pm_notifier; u8 pix_per_clk; /* Buffer to drain stale data from PSI-L endpoint */ struct { @@ -1582,6 +1583,124 @@ static int ti_csi2rx_runtime_resume(struct device *= dev) return 0; } =20 +static int ti_csi2rx_suspend(struct device *dev) +{ + struct ti_csi2rx_dev *csi =3D dev_get_drvdata(dev); + enum ti_csi2rx_dma_state state; + struct ti_csi2rx_ctx *ctx; + struct ti_csi2rx_dma *dma; + unsigned long flags =3D 0; + int i, ret =3D 0; + + /* If device was not in use we can simply suspend */ + if (pm_runtime_status_suspended(dev)) + return 0; + + /* + * If device is running, assert the pixel reset to cleanly stop any + * on-going streams before we suspend. + */ + writel(0, csi->shim + SHIM_CNTL); + + for (i =3D 0; i < csi->num_ctx; i++) { + ctx =3D &csi->ctx[i]; + dma =3D &ctx->dma; + + spin_lock_irqsave(&dma->lock, flags); + state =3D dma->state; + spin_unlock_irqrestore(&dma->lock, flags); + + if (state !=3D TI_CSI2RX_DMA_STOPPED) { + /* Disable source */ + ret =3D v4l2_subdev_disable_streams(&csi->subdev, + TI_CSI2RX_PAD_FIRST_SOURCE + ctx->idx, + BIT(0)); + if (ret) + dev_err(csi->dev, "Failed to stop subdev stream\n"); + } + + /* Stop any on-going streams */ + writel(0, csi->shim + SHIM_DMACNTX(ctx->idx)); + + /* Drain DMA */ + ti_csi2rx_drain_dma(ctx); + + /* Terminate DMA */ + ret =3D dmaengine_terminate_sync(ctx->dma.chan); + if (ret) + dev_err(csi->dev, "Failed to stop DMA\n"); + } + + return ret; +} + +static int ti_csi2rx_resume(struct device *dev) +{ + struct ti_csi2rx_dev *csi =3D dev_get_drvdata(dev); + struct ti_csi2rx_ctx *ctx; + struct ti_csi2rx_dma *dma; + struct ti_csi2rx_buffer *buf; + unsigned long flags =3D 0; + unsigned int reg; + int i, ret =3D 0; + + /* If device was not in use, we can simply wakeup */ + if (pm_runtime_status_suspended(dev)) + return 0; + + /* If device was in use before, restore all the running streams */ + reg =3D SHIM_CNTL_PIX_RST; + writel(reg, csi->shim + SHIM_CNTL); + + for (i =3D 0; i < csi->num_ctx; i++) { + ctx =3D &csi->ctx[i]; + dma =3D &ctx->dma; + spin_lock_irqsave(&dma->lock, flags); + if (dma->state !=3D TI_CSI2RX_DMA_STOPPED) { + /* Re-submit all previously submitted buffers to DMA */ + list_for_each_entry(buf, &ctx->dma.submitted, list) { + ti_csi2rx_start_dma(ctx, buf); + } + spin_unlock_irqrestore(&dma->lock, flags); + + /* Restore stream config */ + ti_csi2rx_setup_shim(ctx); + + ret =3D v4l2_subdev_enable_streams(&csi->subdev, + TI_CSI2RX_PAD_FIRST_SOURCE + ctx->idx, + BIT(0)); + if (ret) + dev_err(ctx->csi->dev, "Failed to start subdev\n"); + } else { + spin_unlock_irqrestore(&dma->lock, flags); + } + } + + return ret; +} + +static int ti_csi2rx_pm_notifier(struct notifier_block *nb, + unsigned long action, void *data) +{ + struct ti_csi2rx_dev *csi =3D + container_of(nb, struct ti_csi2rx_dev, pm_notifier); + + switch (action) { + case PM_HIBERNATION_PREPARE: + case PM_SUSPEND_PREPARE: + case PM_RESTORE_PREPARE: + ti_csi2rx_suspend(csi->dev); + break; + case PM_POST_SUSPEND: + case PM_POST_HIBERNATION: + case PM_POST_RESTORE: + ti_csi2rx_resume(csi->dev); + break; + } + + return NOTIFY_DONE; +} + static const struct dev_pm_ops ti_csi2rx_pm_ops =3D { RUNTIME_PM_OPS(ti_csi2rx_runtime_suspend, ti_csi2rx_runtime_resume, NULL) @@ -1653,6 +1772,13 @@ static int ti_csi2rx_probe(struct platform_device *p= dev) goto err_notifier; } =20 + csi->pm_notifier.notifier_call =3D ti_csi2rx_pm_notifier; + ret =3D register_pm_notifier(&csi->pm_notifier); + if (ret) { + dev_err(csi->dev, "Failed to create PM notifier: %d\n", ret); + goto err_notifier; + } + pm_runtime_set_active(csi->dev); pm_runtime_enable(csi->dev); pm_request_idle(csi->dev); @@ -1683,6 +1809,8 @@ static void ti_csi2rx_remove(struct platform_device *= pdev) ti_csi2rx_cleanup_ctx(&csi->ctx[i]); =20 ti_csi2rx_cleanup_notifier(csi); + unregister_pm_notifier(&csi->pm_notifier); + ti_csi2rx_cleanup_v4l2(csi); mutex_destroy(&csi->mutex); dma_free_coherent(csi->dev, csi->drain.len, csi->drain.vaddr, --=20 2.50.1