[RFC 1/1] crypto: dcp - add power management support

Dragos Rosioru (OSS) dragos.rosioru at oss.nxp.com
Fri Mar 19 00:22:57 GMT 2021


From: Dragos Rosioru <dragos.rosioru at nxp.com>

Added suspend/resume operations for PM support in the DCP driver.
After a suspend/resume cycle DCP would still be in a low-power mode
and have its clocks gated, thus requiring state to be saved beforehand:
- Control register value(DCP_CTRL)
- Channel control register value(DCP_CHANNELCTRL)

Signed-off-by: Dragos Rosioru <dragos.rosioru at nxp.com>
---
 drivers/crypto/mxs-dcp.c | 76 ++++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 74 insertions(+), 2 deletions(-)

diff --git a/drivers/crypto/mxs-dcp.c b/drivers/crypto/mxs-dcp.c
index d6a7784..6748a4a 100644
--- a/drivers/crypto/mxs-dcp.c
+++ b/drivers/crypto/mxs-dcp.c
@@ -23,6 +23,10 @@
 #include <crypto/internal/skcipher.h>
 #include <crypto/scatterwalk.h>
 
+#ifdef CONFIG_PM_SLEEP
+#include <linux/freezer.h>
+#endif
+
 #define DCP_MAX_CHANS	4
 #define DCP_BUF_SZ	PAGE_SIZE
 #define DCP_SHA_PAY_SZ  64
@@ -124,7 +128,10 @@ struct dcp_export_state {
  * design of Linux Crypto API.
  */
 static struct dcp *global_sdcp;
-
+#ifdef CONFIG_PM_SLEEP
+static uint32_t ctrl_bak;
+static int dcp_vmi_irq_bak, dcp_irq_bak;
+#endif
 /* DCP register layout. */
 #define MXS_DCP_CTRL				0x00
 #define MXS_DCP_CTRL_GATHER_RESIDUAL_WRITES	(1 << 23)
@@ -398,9 +405,15 @@ static int dcp_chan_thread_aes(void *data)
 
 	int ret;
 
+#ifdef CONFIG_PM_SLEEP
+	set_freezable();
+#endif
 	while (!kthread_should_stop()) {
 		set_current_state(TASK_INTERRUPTIBLE);
 
+#ifdef CONFIG_PM_SLEEP
+		try_to_freeze();
+#endif
 		spin_lock(&sdcp->lock[chan]);
 		backlog = crypto_get_backlog(&sdcp->queue[chan]);
 		arq = crypto_dequeue_request(&sdcp->queue[chan]);
@@ -438,6 +451,10 @@ static int mxs_dcp_block_fallback(struct skcipher_request *req, int enc)
 	skcipher_request_set_crypt(&rctx->fallback_req, req->src, req->dst,
 				   req->cryptlen, req->iv);
 
+#ifdef CONFIG_PM_SLEEP
+	set_freezable();
+	try_to_freeze();
+#endif
 	if (enc)
 		ret = crypto_skcipher_encrypt(&rctx->fallback_req);
 	else
@@ -686,9 +703,15 @@ static int dcp_chan_thread_sha(void *data)
 	struct crypto_async_request *arq;
 	int ret;
 
+#ifdef CONFIG_PM_SLEEP
+	set_freezable();
+#endif
 	while (!kthread_should_stop()) {
 		set_current_state(TASK_INTERRUPTIBLE);
 
+#ifdef CONFIG_PM_SLEEP
+		try_to_freeze();
+#endif
 		spin_lock(&sdcp->lock[chan]);
 		backlog = crypto_get_backlog(&sdcp->queue[chan]);
 		arq = crypto_dequeue_request(&sdcp->queue[chan]);
@@ -961,6 +984,49 @@ static irqreturn_t mxs_dcp_irq(int irq, void *context)
 	return IRQ_HANDLED;
 }
 
+#ifdef CONFIG_PM_SLEEP
+static int mxs_dcp_resume(struct device *dev)
+{
+	struct dcp *sdcp = global_sdcp;
+	int ret;
+
+	/* Restart the DCP block */
+	ret = stmp_reset_block(sdcp->base);
+	if (ret) {
+		dev_err(dev, "Failed reset\n");
+		clk_disable_unprepare(sdcp->dcp_clk);
+		return ret;
+	}
+
+	/* Restore control register */
+	writel(ctrl_bak, sdcp->base + MXS_DCP_CTRL);
+	/* Enable all DCP DMA channels */
+	writel(MXS_DCP_CHANNELCTRL_ENABLE_CHANNEL_MASK,
+	       sdcp->base + MXS_DCP_CHANNELCTRL);
+
+	/* Re-enable DCP interrupts */
+	enable_irq(dcp_irq_bak);
+	enable_irq(dcp_vmi_irq_bak);
+
+	return 0;
+}
+
+static int mxs_dcp_suspend(struct device *dev)
+{
+	struct dcp *sdcp = global_sdcp;
+
+	/* Backup control register */
+	ctrl_bak = readl(sdcp->base + MXS_DCP_CTRL);
+	/* Temporarily disable DCP interrupts */
+	disable_irq(dcp_irq_bak);
+	disable_irq(dcp_vmi_irq_bak);
+
+	return 0;
+}
+
+SIMPLE_DEV_PM_OPS(mxs_dcp_pm_ops, mxs_dcp_suspend, mxs_dcp_resume);
+#endif
+
 static int mxs_dcp_probe(struct platform_device *pdev)
 {
 	struct device *dev = &pdev->dev;
@@ -980,7 +1046,10 @@ static int mxs_dcp_probe(struct platform_device *pdev)
 	dcp_irq = platform_get_irq(pdev, 1);
 	if (dcp_irq < 0)
 		return dcp_irq;
-
+#ifdef CONFIG_PM_SLEEP
+	dcp_vmi_irq_bak = dcp_vmi_irq;
+	dcp_irq_bak = dcp_irq;
+#endif
 	sdcp = devm_kzalloc(dev, sizeof(*sdcp), GFP_KERNEL);
 	if (!sdcp)
 		return -ENOMEM;
@@ -1172,6 +1241,9 @@ static struct platform_driver mxs_dcp_driver = {
 	.driver	= {
 		.name		= "mxs-dcp",
 		.of_match_table	= mxs_dcp_dt_ids,
+#ifdef CONFIG_PM_SLEEP
+		.pm = &mxs_dcp_pm_ops
+#endif
 	},
 };
 
-- 
2.7.4




More information about the linux-arm-kernel mailing list