From patchwork Mon Feb 24 13:35:56 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jai Luthra X-Patchwork-Id: 13988110 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 94641248866; Mon, 24 Feb 2025 13:40:48 +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=1740404450; cv=none; b=OjT17E/SjyhrAzM6JxnDIaPftuekNsYlsxN1oGL+7C7fJxgANlQtGwm91rS+3+dShhdLbY15hv+J7xQhyi5T1YGxTj7ZJoyW09yFo/bdG1KD5nwK1ioWNCOkBjGXsQs4R2SSZZDFCTMslQzOFXnldn6WhAcw1fr1L4Nmtr0F7RQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1740404450; c=relaxed/simple; bh=/hb8XpoHfN5TkFNW4WCJoAf7bdbLnMTQCs8WzFgEb8U=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=Yt+93bEI57d6We3bBhwt/VBZTyRhlYJnETnYMqrnC8sBrHwo8GaVdqnAf8SZUforX0Br264TEIIeHvlAw9JUYZscYcxkLb6U6Imxm6FC/yUSpP+YN6QldnhkfhmLMFVQWF47dvEuMto2cBRW5la495oJgy4PuMfaApPfSl9Gjp8= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (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=tUGCzz0v; arc=none smtp.client-ip=213.167.242.64 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (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="tUGCzz0v" Received: from mail.ideasonboard.com (unknown [223.190.81.199]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 6DCBE455; Mon, 24 Feb 2025 14:39:20 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1740404361; bh=/hb8XpoHfN5TkFNW4WCJoAf7bdbLnMTQCs8WzFgEb8U=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From; b=tUGCzz0vyRAUUstWDEaZjnzwb9qytJeNvIbo/9nv3AIhHWqhsMWnGxC0mqf+JTrsT qNAUmbQUJcoHZH2U7TK3sMQiJe+A7osEdWNuZclUOOU6MiQnMLRd4cbA/p0zEibHPq JyGlxpNse+6YiYTmuiruHLXT2FhUtwuLRtPFwsIU= From: Jai Luthra Date: Mon, 24 Feb 2025 19:05:56 +0530 Subject: [PATCH 1/3] media: cadence: csi2rx: Support runtime PM Precedence: bulk X-Mailing-List: linux-media@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Message-Id: <20250224-ti_csi_pm-v1-1-8f8c29ef646d@ideasonboard.com> References: <20250224-ti_csi_pm-v1-0-8f8c29ef646d@ideasonboard.com> In-Reply-To: <20250224-ti_csi_pm-v1-0-8f8c29ef646d@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 , Jai Luthra X-Mailer: b4 0.14.2 X-Developer-Signature: v=1; a=openpgp-sha256; l=7317; i=jai.luthra@ideasonboard.com; h=from:subject:message-id; bh=90ICLFjJh7hBrJU7wrD1GxE2bG6CWGg7Dagw1g1eEMw=; b=owEBbQKS/ZANAwAIAUPekfkkmnFFAcsmYgBnvHbAtW75BWsui36gFb+G1tB0zQTyjWwkpXeOA wZPrVeHIT2JAjMEAAEIAB0WIQRN4NgY5dV16NRar8VD3pH5JJpxRQUCZ7x2wAAKCRBD3pH5JJpx ReJnD/9s8msMhdoBjdjY+Joxka44sVEAxDnxYrM7JaL+v5nre937m+pTRC0P/wJH8ZX0BZFGOVU UjciA81Vo5oxCg1Jk6quq15v7nBi66VsQJrC0D1GBrQdkyyHY2HECI64Scq7BuONlzBcDOhd3iq XgxquZlIPX1Oy+SJPawbeYvx7K3qWnAuQnhl7oKxeCMJb3xUurKRrbT4ihO1tng4Wegow9oZbZ9 gaQF5lfIWTl4j+JhKUiQK+SBtGT3iawE20y4gpHXoEjqRY9jvp+ssccLI7hjkOlDv1v7RvKl70u WFeCk6V6C197EzFlZc8+Y2zbenSg0Sbkq6NmDw8DWASSK2ohH5SLz0o8yMxjLhuUqUA3pTIjAJx axF9bt8DY5s+TLOjoOVvY3UAFhqpt4+NqpeEEmci9xMq/oCh4Vl15ZS6bH1IejR9prxJUyjTn4f q6hljxMzQS4xnew5kS4NAjk/sGWp3bFigFcpdsjbTI3vaopEujMvBFP1lwL6Cml0avQJS5btHFm 0zFAEMTW0z91wKNnx6RALs675I8WODXDnTCuBdcu5j+zYXDdVa82N8drAKDf4zGPW0PdHFtdu/u KvPsTx6+MGqcBA6czx/HEhe5ET24Px4oPzGAMxjNGpc+Ob2VH9pSLqRN1aI5CRA94a/2AZOo8yS znlZDgAlcYO56Gw== 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 Signed-off-by: Jai Luthra --- drivers/media/platform/cadence/Kconfig | 1 + drivers/media/platform/cadence/cdns-csi2rx.c | 121 ++++++++++++++++++--------- 2 files changed, 81 insertions(+), 41 deletions(-) diff --git a/drivers/media/platform/cadence/Kconfig b/drivers/media/platform/cadence/Kconfig index 1aa608c00dbce9b52d0d48b5ac8c877db7494fd7..ea85ef82760e694c1e03fa323fc7a468b135e2e1 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/platform/cadence/cdns-csi2rx.c index 4d64df829e7585b6e305651f3ff9bdd008508ec5..44d3189fbec11d391352d4630326d78962b49a0e 100644 --- a/drivers/media/platform/cadence/cdns-csi2rx.c +++ b/drivers/media/platform/cadence/cdns-csi2rx.c @@ -211,11 +211,6 @@ static int csi2rx_start(struct csi2rx_priv *csi2rx) u32 reg; int ret; - ret = clk_prepare_enable(csi2rx->p_clk); - if (ret) - return ret; - - reset_control_deassert(csi2rx->p_rst); csi2rx_reset(csi2rx); reg = csi2rx->num_lanes << 8; @@ -253,7 +248,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; } } @@ -268,11 +263,6 @@ static int csi2rx_start(struct csi2rx_priv *csi2rx) * hence the reference counting. */ for (i = 0; i < csi2rx->max_streams; i++) { - ret = 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, csi2rx->base + CSI2RX_STREAM_CFG_REG(i)); @@ -288,34 +278,18 @@ static int csi2rx_start(struct csi2rx_priv *csi2rx) csi2rx->base + CSI2RX_STREAM_CTRL_REG(i)); } - ret = clk_prepare_enable(csi2rx->sys_clk); - if (ret) - goto err_disable_pixclk; - - reset_control_deassert(csi2rx->sys_rst); ret = v4l2_subdev_call(csi2rx->source_subdev, video, s_stream, true); if (ret) - goto err_disable_sysclk; - - clk_disable_unprepare(csi2rx->p_clk); + goto err_phy_power_off; return 0; -err_disable_sysclk: - clk_disable_unprepare(csi2rx->sys_clk); -err_disable_pixclk: - for (; i > 0; i--) { - reset_control_assert(csi2rx->pixel_rst[i - 1]); - clk_disable_unprepare(csi2rx->pixel_clk[i - 1]); - } - +err_phy_power_off: 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; } @@ -326,10 +300,6 @@ static void csi2rx_stop(struct csi2rx_priv *csi2rx) u32 val; int ret; - clk_prepare_enable(csi2rx->p_clk); - reset_control_assert(csi2rx->sys_rst); - clk_disable_unprepare(csi2rx->sys_clk); - for (i = 0; i < csi2rx->max_streams; i++) { writel(CSI2RX_STREAM_CTRL_STOP, csi2rx->base + CSI2RX_STREAM_CTRL_REG(i)); @@ -342,14 +312,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]); } - reset_control_assert(csi2rx->p_rst); - clk_disable_unprepare(csi2rx->p_clk); - if (v4l2_subdev_call(csi2rx->source_subdev, video, s_stream, false)) dev_warn(csi2rx->dev, "Couldn't disable our subdev\n"); @@ -374,9 +338,15 @@ static int csi2rx_s_stream(struct v4l2_subdev *subdev, int enable) * enable the whole controller. */ if (!csi2rx->count) { + ret = pm_runtime_resume_and_get(csi2rx->dev); + if (ret < 0) + goto out; + ret = csi2rx_start(csi2rx); - if (ret) + if (ret) { + pm_runtime_put(csi2rx->dev); goto out; + } } csi2rx->count++; @@ -386,8 +356,10 @@ static int csi2rx_s_stream(struct v4l2_subdev *subdev, int enable) /* * Let the last user turn off the lights. */ - if (!csi2rx->count) + if (!csi2rx->count) { csi2rx_stop(csi2rx); + pm_runtime_put(csi2rx->dev); + } } out: @@ -707,6 +679,7 @@ static int csi2rx_probe(struct platform_device *pdev) if (ret) goto err_cleanup; + pm_runtime_enable(csi2rx->dev); ret = v4l2_async_register_subdev(&csi2rx->subdev); if (ret < 0) goto err_free_state; @@ -721,6 +694,7 @@ static int csi2rx_probe(struct platform_device *pdev) 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); @@ -739,9 +713,73 @@ static void csi2rx_remove(struct platform_device *pdev) v4l2_async_unregister_subdev(&csi2rx->subdev); v4l2_subdev_cleanup(&csi2rx->subdev); media_entity_cleanup(&csi2rx->subdev.entity); + pm_runtime_disable(csi2rx->dev); kfree(csi2rx); } +static int csi2rx_runtime_suspend(struct device *dev) +{ + struct csi2rx_priv *csi2rx = dev_get_drvdata(dev); + unsigned int i; + + reset_control_assert(csi2rx->sys_rst); + clk_disable_unprepare(csi2rx->sys_clk); + + for (i = 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 = dev_get_drvdata(dev); + unsigned int i; + int ret; + + ret = clk_prepare_enable(csi2rx->p_clk); + if (ret) + return ret; + + reset_control_deassert(csi2rx->p_rst); + + for (i = 0; i < csi2rx->max_streams; i++) { + ret = clk_prepare_enable(csi2rx->pixel_clk[i]); + if (ret) + goto err_disable_pixclk; + + reset_control_deassert(csi2rx->pixel_rst[i]); + } + + ret = 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 = { + RUNTIME_PM_OPS(csi2rx_runtime_suspend, csi2rx_runtime_resume, NULL) +}; + static const struct of_device_id csi2rx_of_table[] = { { .compatible = "starfive,jh7110-csi2rx" }, { .compatible = "cdns,csi2rx" }, @@ -756,6 +794,7 @@ static struct platform_driver csi2rx_driver = { .driver = { .name = "cdns-csi2rx", .of_match_table = csi2rx_of_table, + .pm = &csi2rx_pm_ops, }, }; module_platform_driver(csi2rx_driver); From patchwork Mon Feb 24 13:35:57 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jai Luthra X-Patchwork-Id: 13988111 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 9B23624BBF3; Mon, 24 Feb 2025 13:41:05 +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=1740404467; cv=none; b=T5XqOc7TVh99LVCw+nwj47dbVa5E5tBTtpK6dlBYQ0MTlTbYlSxoHpOdgma3ZCzJumz05nxZZ5bNfZMI8ds49LDCFPWF7LVF1kNh610me0BhR5ZyIp1FWvNybqFFdwqc2KqjL5zhZ8PAO6neqkO/F1G8ovjgnvHscGIk3IWgcXg= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1740404467; c=relaxed/simple; bh=V4qAb7I4cMDuLM8U3qsvQxbc/Luxo0zWXTg0V5c+6ow=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=RP8inlQU9Sl4Zu9iwG/MD784cnD9a3Y4n7xkYvGvT527IuZoSy+ztGL5D46M2uvRX4Q6kxrGJPkf2QTpjgYAirbFnP4hPG2dzO4TJ8CmowH37OpgxFe7xqf/i9YCiG7MOmXcDcDg+FWktz7XC52n1TX8Gs61xStVs4UrQbCY8DY= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (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=PomR9QA9; arc=none smtp.client-ip=213.167.242.64 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (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="PomR9QA9" Received: from mail.ideasonboard.com (unknown [223.190.81.199]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id C6811455; Mon, 24 Feb 2025 14:39:36 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1740404377; bh=V4qAb7I4cMDuLM8U3qsvQxbc/Luxo0zWXTg0V5c+6ow=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From; b=PomR9QA9hGzeXo94uzeN/LN2n7hjogOa3cN0YeAUbB8ggnGeg3UeSIKe+sffQLPIY JUdJlaO+I3T0i9jWKSN3xlOWxQnU33XJLfETsu/9Hr+hmw9CfPpIVcXnJjC0UcNKzz v/hfyNvNZMM1rYGTTQEcf1m/C7QXiG88HBthgo94= From: Jai Luthra Date: Mon, 24 Feb 2025 19:05:57 +0530 Subject: [PATCH 2/3] media: ti: j721e-csi2rx: Support runtime suspend Precedence: bulk X-Mailing-List: linux-media@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Message-Id: <20250224-ti_csi_pm-v1-2-8f8c29ef646d@ideasonboard.com> References: <20250224-ti_csi_pm-v1-0-8f8c29ef646d@ideasonboard.com> In-Reply-To: <20250224-ti_csi_pm-v1-0-8f8c29ef646d@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 , Jai Luthra X-Mailer: b4 0.14.2 X-Developer-Signature: v=1; a=openpgp-sha256; l=6025; i=jai.luthra@ideasonboard.com; h=from:subject:message-id; bh=V4qAb7I4cMDuLM8U3qsvQxbc/Luxo0zWXTg0V5c+6ow=; b=owEBbQKS/ZANAwAIAUPekfkkmnFFAcsmYgBnvHbAzDj4PokWcTa4AOHY0KiQv9Yk3G9NXUo0l yPKK6AGIeWJAjMEAAEIAB0WIQRN4NgY5dV16NRar8VD3pH5JJpxRQUCZ7x2wAAKCRBD3pH5JJpx RVGbD/4/c9ZIALOSCIXsf0v+HA/7qai2SewgtXGHBf4kCWuQO1lYFIBoRIu15CfKVfu6sejBoca YRxXANppf5ZXk1YANkDPUDFO/vIvCQ3ps7+cx0QQUx3DSgJshyUxeO7ErupkBEEMPbQQPAKfrEo kXLHiSAZtAlSdiBzbCXBS/JNbOqQqLMMnMbu3hDj6KV++96Hvc63oSKoavSz01vzEfybXWznKDX xe79MsS79xH4Y5yO7Dt3CpRkCR0dYioav5W2VfJkO7zgYGe7SFxQ1ztEBZpT73sphDqusJsDCzQ 9q2dO7liLwGEkyjWfKVmObvCASgFF4R94peUrMtYCl//5aCueYvTtIPBEIK4paaQ1N/jqtuZhLQ VheBtKRUeOYu4a+dbYjU4Enp2Ggd/zeSgf4bQG9iSUHyD6VPWWxLARTy9f5cXtPCl7cQBZ0pHQd kKvvZQgz01id/wZryd0r/OsMm80jtF/BiC2u8iT5HLFblAOekH/TCRfHrCEH+03dbCFeiMfSXiP /cwQNCDWzg05gBMLiHbGyULVcKMcAF1Pmn7K/1zQC0OcZFFquqQgLchVxRkMaGVy76xwPSzOO4o qu0dZOzbMNVDCg2EYsn/T+8db8aOtpMGzwJ4CPHagF73RaVk2ndQabJ0MrRmZhiPVr2ft5bO8wu mqIokv0bb6Lx8FQ== 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. Signed-off-by: Jai Luthra --- drivers/media/platform/ti/Kconfig | 1 + .../media/platform/ti/j721e-csi2rx/j721e-csi2rx.c | 71 +++++++++++++++++++--- 2 files changed, 62 insertions(+), 10 deletions(-) diff --git a/drivers/media/platform/ti/Kconfig b/drivers/media/platform/ti/Kconfig index bab998c4179aca3b07372782b9be7de340cb8d45..9d06a537ca9393b6e87a7ab196d26137d4008374 100644 --- a/drivers/media/platform/ti/Kconfig +++ b/drivers/media/platform/ti/Kconfig @@ -69,6 +69,7 @@ config VIDEO_TI_J721E_CSI2RX depends on MEDIA_SUPPORT && MEDIA_CONTROLLER depends on (PHY_CADENCE_DPHY_RX && VIDEO_CADENCE_CSI2RX) || 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/drivers/media/platform/ti/j721e-csi2rx/j721e-csi2rx.c index 6412a00be8eab89548950dd21b3b3ec02dafa5b4..dc15759562f94fcfc53955b455b7e03fb733e8e4 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 #include @@ -808,12 +809,16 @@ static int ti_csi2rx_start_streaming(struct vb2_queue *vq, unsigned int count) unsigned long flags; int ret = 0; + ret = pm_runtime_resume_and_get(csi->dev); + if (ret) + return ret; + spin_lock_irqsave(&dma->lock, flags); if (list_empty(&dma->queue)) ret = -EIO; spin_unlock_irqrestore(&dma->lock, flags); if (ret) - return ret; + goto err; ret = video_device_pipeline_start(&csi->vdev, &csi->pipe); if (ret) @@ -851,6 +856,8 @@ static int ti_csi2rx_start_streaming(struct vb2_queue *vq, unsigned int count) writel(0, csi->shim + SHIM_DMACNTX); err: ti_csi2rx_cleanup_buffers(csi, VB2_BUF_STATE_QUEUED); + pm_runtime_put(csi->dev); + return ret; } @@ -870,6 +877,7 @@ static void ti_csi2rx_stop_streaming(struct vb2_queue *vq) ti_csi2rx_stop_dma(csi); ti_csi2rx_cleanup_buffers(csi, VB2_BUF_STATE_ERROR); + pm_runtime_put(csi->dev); } static const struct vb2_ops csi_vb2_qops = { @@ -963,19 +971,13 @@ static const struct media_entity_operations ti_csi2rx_video_entity_ops = { .link_validate = ti_csi2rx_link_validate, }; -static int ti_csi2rx_init_dma(struct ti_csi2rx_dev *csi) +static int ti_csi2rx_dma_request_chan(struct ti_csi2rx_dev *csi) { struct dma_slave_config cfg = { .src_addr_width = DMA_SLAVE_BUSWIDTH_16_BYTES, }; int ret; - INIT_LIST_HEAD(&csi->dma.queue); - INIT_LIST_HEAD(&csi->dma.submitted); - spin_lock_init(&csi->dma.lock); - - csi->dma.state = TI_CSI2RX_DMA_STOPPED; - csi->dma.chan = dma_request_chan(csi->dev, "rx0"); if (IS_ERR(csi->dma.chan)) return PTR_ERR(csi->dma.chan); @@ -983,9 +985,25 @@ static int ti_csi2rx_init_dma(struct ti_csi2rx_dev *csi) ret = dmaengine_slave_config(csi->dma.chan, &cfg); if (ret) { dma_release_channel(csi->dma.chan); - return ret; } + return ret; +} + +static int ti_csi2rx_init_dma(struct ti_csi2rx_dev *csi) +{ + int ret; + + INIT_LIST_HEAD(&csi->dma.queue); + INIT_LIST_HEAD(&csi->dma.submitted); + spin_lock_init(&csi->dma.lock); + + csi->dma.state = TI_CSI2RX_DMA_STOPPED; + + ret = ti_csi2rx_dma_request_chan(csi); + if (ret) + return ret; + csi->dma.drain.len = DRAIN_BUFFER_SIZE; csi->dma.drain.vaddr = dma_alloc_coherent(csi->dev, csi->dma.drain.len, &csi->dma.drain.paddr, @@ -1062,7 +1080,9 @@ static void ti_csi2rx_cleanup_dma(struct ti_csi2rx_dev *csi) dma_free_coherent(csi->dev, csi->dma.drain.len, csi->dma.drain.vaddr, csi->dma.drain.paddr); csi->dma.drain.vaddr = NULL; - dma_release_channel(csi->dma.chan); + + if (!pm_runtime_status_suspended(csi->dev)) + dma_release_channel(csi->dma.chan); } static void ti_csi2rx_cleanup_v4l2(struct ti_csi2rx_dev *csi) @@ -1083,6 +1103,29 @@ static void ti_csi2rx_cleanup_vb2q(struct ti_csi2rx_dev *csi) vb2_queue_release(&csi->vidq); } +static int ti_csi2rx_runtime_suspend(struct device *dev) +{ + struct ti_csi2rx_dev *csi = dev_get_drvdata(dev); + + /* DMA channel pairing is lost when device is powered off */ + dma_release_channel(csi->dma.chan); + + return 0; +} + +static int ti_csi2rx_runtime_resume(struct device *dev) +{ + struct ti_csi2rx_dev *csi = dev_get_drvdata(dev); + + /* Re-acquire DMA channel */ + return ti_csi2rx_dma_request_chan(csi); +} + +static const struct dev_pm_ops ti_csi2rx_pm_ops = { + RUNTIME_PM_OPS(ti_csi2rx_runtime_suspend, ti_csi2rx_runtime_resume, + NULL) +}; + static int ti_csi2rx_probe(struct platform_device *pdev) { struct ti_csi2rx_dev *csi; @@ -1124,6 +1167,10 @@ static int ti_csi2rx_probe(struct platform_device *pdev) goto err_subdev; } + pm_runtime_set_active(csi->dev); + pm_runtime_enable(csi->dev); + pm_request_idle(csi->dev); + return 0; err_subdev: @@ -1150,6 +1197,9 @@ static void ti_csi2rx_remove(struct platform_device *pdev) ti_csi2rx_cleanup_v4l2(csi); ti_csi2rx_cleanup_dma(csi); + pm_runtime_disable(&pdev->dev); + pm_runtime_set_suspended(&pdev->dev); + mutex_destroy(&csi->mutex); } @@ -1165,6 +1215,7 @@ static struct platform_driver ti_csi2rx_pdrv = { .driver = { .name = TI_CSI2RX_MODULE_NAME, .of_match_table = ti_csi2rx_of_match, + .pm = &ti_csi2rx_pm_ops, }, }; From patchwork Mon Feb 24 13:35:58 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jai Luthra X-Patchwork-Id: 13988112 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 9DD69248892; Mon, 24 Feb 2025 13:41:22 +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=1740404484; cv=none; b=ayxwbTKFGSspde8dOvSnMO3FS5PAqYEpcDlWXTq+3Nv6NViLcP/UHFPJkjGHx8H5pnV/7IIbOpXFmrKrvTqjPGXutgFEDDyizw5XDknL/JfjSAljLnw97gVtXE3Sga5X43oQSv44WLYSBv3f9uZPBqOnRQRMsWrS8Uh+/ij5JmM= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1740404484; c=relaxed/simple; bh=kTzLMj1TbgwqOPWA8o8pj/AbPtM7CHZiAy1qsF8VOj8=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=La5WksSKpjyGJNpUjx7qo2zA3G/c7TvTrTlpyCiMCMdvB1vR1xw57z2GTkby/fR6NQLgaAsHYTfOSu244L8Vschn0TtQiKgaUr3dq7I6KsM0p155fove5iCXg/XCNJkcZUz6bGJjc7XbGbSARoQzKy4UaqQ6rTTWZwlgVH96pKo= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (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=v/cM47Gs; arc=none smtp.client-ip=213.167.242.64 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (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="v/cM47Gs" Received: from mail.ideasonboard.com (unknown [223.190.81.199]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 168B3455; Mon, 24 Feb 2025 14:39:53 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1740404394; bh=kTzLMj1TbgwqOPWA8o8pj/AbPtM7CHZiAy1qsF8VOj8=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From; b=v/cM47Gs/aBmyEL8BiM4ZYrIVLHq3jD883I9JliaivcMCVBklxDHNjA5+9MovCU9V PyPpGY+gmEwIt9sgF3G+CvCyj+B+WCQCkK6+hns8ON7VwU3qKohwB3RpZaplycd6n7 rzRYDYEiCbiwF0LZ2BqoOB+BN6ehHo9+bZVuZKuI= From: Jai Luthra Date: Mon, 24 Feb 2025 19:05:58 +0530 Subject: [PATCH 3/3] media: ti: j721e-csi2rx: Support system suspend using pm_notifier Precedence: bulk X-Mailing-List: linux-media@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Message-Id: <20250224-ti_csi_pm-v1-3-8f8c29ef646d@ideasonboard.com> References: <20250224-ti_csi_pm-v1-0-8f8c29ef646d@ideasonboard.com> In-Reply-To: <20250224-ti_csi_pm-v1-0-8f8c29ef646d@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 , Jai Luthra X-Mailer: b4 0.14.2 X-Developer-Signature: v=1; a=openpgp-sha256; l=5639; i=jai.luthra@ideasonboard.com; h=from:subject:message-id; bh=kTzLMj1TbgwqOPWA8o8pj/AbPtM7CHZiAy1qsF8VOj8=; b=owEBbQKS/ZANAwAIAUPekfkkmnFFAcsmYgBnvHbAzc1e65XFpTHHTkJ1i4+66Zc63WaSwu5Ay mwu8sz3l96JAjMEAAEIAB0WIQRN4NgY5dV16NRar8VD3pH5JJpxRQUCZ7x2wAAKCRBD3pH5JJpx RRLuD/9kzSdNYRrsWsWP7sqyNPBZF5T2H9b5cVqnM3MQAvHJYZ2wiUYeF1OwRtbULIMipsxZmg4 CxVQ2UeuCWDawgsYNgt9KqYAQ+LwjSb1SntK6wFZV4M6kOshkwoWfP2YTBHNds747GIsLLkxNaW eQqzg/t28etXTQ7tkPVBRsVMfhFOOzIsp9S6CUSjNmBo8oK9PXtza35OUMI9QkH1EdxJsCH0evq 3bTbQJS4ksIcF3Kg1kr3FC3Mzp0Bc8osN5TXRke37LxQjnFyYKrWkcpnJT8QePcsJ5FT3V42DZP qs1GxkUypIPDvLbQmIDgzsx6fdIg2o3+3gIijMt7yNQXpoynFdTwqJYMT4iMNCM4mKcyG50OHvr KDDJBjh5oJW1ud9Crv78kuLEIZBt45h2RFgwgJHf2xD8GB6901VsgtUYJmq7w3CScVxNVD7o+8K stgHn38Y/M6ws4yBgC0M52vpk5/qu72mBgFBlvB8AKH1iAPO0JklM779tOoo/H+QhJVfnwHnsqg q3+VfFacCs9XSEeKXiVTmgpVUuiwdNemBjwlyjeUIybJD3EqwBxbEo20IqYeNPbb7j/kKAgHknF N4ZdJWPLpGOIp66nMBqJNsaM+r6Vq6YGalAo+4yJzksm4xNW/HN93czN41j7832VbUwXBPFalLi KQV7bA9ca+5tCSQ== 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 to prevent races from userspace ioctl calls we hold the lock for the video device operations while we are dealing with the notifier events. Signed-off-by: Jai Luthra --- .../media/platform/ti/j721e-csi2rx/j721e-csi2rx.c | 109 +++++++++++++++++++++ 1 file changed, 109 insertions(+) diff --git a/drivers/media/platform/ti/j721e-csi2rx/j721e-csi2rx.c b/drivers/media/platform/ti/j721e-csi2rx/j721e-csi2rx.c index dc15759562f94fcfc53955b455b7e03fb733e8e4..5a318b2080532882b0f0fcbde8e1c35208d198c7 100644 --- a/drivers/media/platform/ti/j721e-csi2rx/j721e-csi2rx.c +++ b/drivers/media/platform/ti/j721e-csi2rx/j721e-csi2rx.c @@ -107,6 +107,7 @@ struct ti_csi2rx_dev { struct mutex mutex; /* To serialize ioctls. */ struct v4l2_format v_fmt; struct ti_csi2rx_dma dma; + struct notifier_block pm_notifier; u32 sequence; }; @@ -1121,6 +1122,105 @@ static int ti_csi2rx_runtime_resume(struct device *dev) return ti_csi2rx_dma_request_chan(csi); } +static int ti_csi2rx_suspend(struct device *dev) +{ + struct ti_csi2rx_dev *csi = dev_get_drvdata(dev); + enum ti_csi2rx_dma_state state; + struct ti_csi2rx_dma *dma = &csi->dma; + unsigned long flags = 0; + int ret = 0; + + /* If device was not in use we can simply suspend */ + if (pm_runtime_status_suspended(dev)) + return 0; + + /* Acquire the lock used for video dev/queue operations */ + mutex_lock(&csi->mutex); + + /* Stop any on-going streams */ + writel(0, csi->shim + SHIM_CNTL); + writel(0, csi->shim + SHIM_DMACNTX); + + spin_lock_irqsave(&dma->lock, flags); + state = dma->state; + spin_unlock_irqrestore(&dma->lock, flags); + + if (state != TI_CSI2RX_DMA_STOPPED) { + /* Disable source */ + ret = v4l2_subdev_call(csi->source, video, s_stream, 0); + if (ret) + dev_err(csi->dev, "Failed to stop subdev stream\n"); + } + + /* Drain DMA */ + ti_csi2rx_drain_dma(csi); + + /* Terminate DMA */ + ret = dmaengine_terminate_sync(csi->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 = dev_get_drvdata(dev); + struct ti_csi2rx_dma *dma = &csi->dma; + struct ti_csi2rx_buffer *buf; + unsigned long flags = 0; + int ret = 0; + + /* If device was not in use, we can simply wakeup */ + if (pm_runtime_status_suspended(dev)) + return 0; + + spin_lock_irqsave(&dma->lock, flags); + if (dma->state != TI_CSI2RX_DMA_STOPPED) { + /* Re-submit all previously submitted buffers to DMA */ + list_for_each_entry(buf, &csi->dma.submitted, list) { + ti_csi2rx_start_dma(csi, buf); + } + spin_unlock_irqrestore(&dma->lock, flags); + + /* Restore stream config */ + ti_csi2rx_setup_shim(csi); + + ret = v4l2_subdev_call(csi->source, video, s_stream, 1); + if (ret) + dev_err(csi->dev, "Failed to start subdev\n"); + } else { + spin_unlock_irqrestore(&dma->lock, flags); + } + + /* Release the lock used for video dev/queue operations */ + mutex_unlock(&csi->mutex); + + return ret; +} + +static int ti_csi2rx_pm_notifier(struct notifier_block *nb, + unsigned long action, void *data) +{ + struct ti_csi2rx_dev *csi = + 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 = { RUNTIME_PM_OPS(ti_csi2rx_runtime_suspend, ti_csi2rx_runtime_resume, NULL) @@ -1167,6 +1267,13 @@ static int ti_csi2rx_probe(struct platform_device *pdev) goto err_subdev; } + csi->pm_notifier.notifier_call = ti_csi2rx_pm_notifier; + ret = register_pm_notifier(&csi->pm_notifier); + if (ret) { + dev_err(csi->dev, "Failed to create PM notifier: %d\n", ret); + goto err_subdev; + } + pm_runtime_set_active(csi->dev); pm_runtime_enable(csi->dev); pm_request_idle(csi->dev); @@ -1192,6 +1299,8 @@ static void ti_csi2rx_remove(struct platform_device *pdev) video_unregister_device(&csi->vdev); + unregister_pm_notifier(&csi->pm_notifier); + ti_csi2rx_cleanup_vb2q(csi); ti_csi2rx_cleanup_subdev(csi); ti_csi2rx_cleanup_v4l2(csi);