summaryrefslogtreecommitdiff
path: root/drivers/crypto/caam/jr.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/crypto/caam/jr.c')
-rw-r--r--drivers/crypto/caam/jr.c104
1 files changed, 90 insertions, 14 deletions
diff --git a/drivers/crypto/caam/jr.c b/drivers/crypto/caam/jr.c
index 6d475a2e298c..73e5596f82bd 100644
--- a/drivers/crypto/caam/jr.c
+++ b/drivers/crypto/caam/jr.c
@@ -2,17 +2,18 @@
* CAAM/SEC 4.x transport/backend driver
* JobR backend functionality
*
- * Copyright 2008-2012 Freescale Semiconductor, Inc.
+ * Copyright 2008-2016 Freescale Semiconductor, Inc.
+ * Copyright 2017-2018 NXP
*/
#include <linux/of_irq.h>
#include <linux/of_address.h>
-
#include "compat.h"
#include "regs.h"
#include "jr.h"
#include "desc.h"
#include "intern.h"
+#include "inst_rng.h"
struct jr_driver_data {
/* List of Physical JobR's with the Driver */
@@ -26,6 +27,7 @@ static int caam_reset_hw_jr(struct device *dev)
{
struct caam_drv_private_jr *jrp = dev_get_drvdata(dev);
unsigned int timeout = 100000;
+ unsigned int reg_value;
/*
* mask interrupts since we are going to poll
@@ -35,9 +37,11 @@ static int caam_reset_hw_jr(struct device *dev)
/* initiate flush (required prior to reset) */
wr_reg32(&jrp->rregs->jrcommand, JRCR_RESET);
- while (((rd_reg32(&jrp->rregs->jrintstatus) & JRINT_ERR_HALT_MASK) ==
- JRINT_ERR_HALT_INPROGRESS) && --timeout)
+ do {
cpu_relax();
+ reg_value = rd_reg32(&jrp->rregs->jrintstatus);
+ } while (((reg_value & JRINT_ERR_HALT_MASK) ==
+ JRINT_ERR_HALT_INPROGRESS) && --timeout);
if ((rd_reg32(&jrp->rregs->jrintstatus) & JRINT_ERR_HALT_MASK) !=
JRINT_ERR_HALT_COMPLETE || timeout == 0) {
@@ -48,8 +52,10 @@ static int caam_reset_hw_jr(struct device *dev)
/* initiate reset */
timeout = 100000;
wr_reg32(&jrp->rregs->jrcommand, JRCR_RESET);
- while ((rd_reg32(&jrp->rregs->jrcommand) & JRCR_RESET) && --timeout)
+ do {
cpu_relax();
+ reg_value = rd_reg32(&jrp->rregs->jrcommand);
+ } while ((reg_value & JRCR_RESET) && --timeout);
if (timeout == 0) {
dev_err(dev, "failed to reset job ring %d\n", jrp->ridx);
@@ -100,6 +106,12 @@ static int caam_jr_remove(struct platform_device *pdev)
jrpriv = dev_get_drvdata(jrdev);
/*
+ * Deinstantiate RNG by first JR
+ */
+ if (jrpriv->ridx == 0)
+ deinst_rng(pdev);
+
+ /*
* Return EBUSY if job ring already allocated.
*/
if (atomic_read(&jrpriv->tfm_count)) {
@@ -297,8 +309,7 @@ EXPORT_SYMBOL(caam_jr_free);
* caam_jr_enqueue() - Enqueue a job descriptor head. Returns 0 if OK,
* -EBUSY if the queue is full, -EIO if it cannot map the caller's
* descriptor.
- * @dev: device of the job ring to be used. This device should have
- * been assigned prior by caam_jr_register().
+ * @dev: device of the job ring to be used.
* @desc: points to a job descriptor that execute our request. All
* descriptors (and all referenced data) must be in a DMAable
* region, and all data references must be physical addresses
@@ -358,7 +369,6 @@ int caam_jr_enqueue(struct device *dev, u32 *desc,
head_entry->desc_addr_dma = desc_dma;
jrp->inpring[jrp->inp_ring_write_index] = cpu_to_caam_dma(desc_dma);
-
/*
* Guarantee that the descriptor's DMA address has been written to
* the next slot in the ring before the write index is updated, since
@@ -395,6 +405,10 @@ static int caam_jr_init(struct device *dev)
jrp = dev_get_drvdata(dev);
+ error = caam_reset_hw_jr(dev);
+ if (error)
+ goto out_kill_deq;
+
tasklet_init(&jrp->irqtask, caam_jr_dequeue, (unsigned long)dev);
/* Connect job ring interrupt handler. */
@@ -406,10 +420,6 @@ static int caam_jr_init(struct device *dev)
goto out_kill_deq;
}
- error = caam_reset_hw_jr(dev);
- if (error)
- goto out_free_irq;
-
error = -ENOMEM;
jrp->inpring = dma_alloc_coherent(dev, sizeof(*jrp->inpring) *
JOBR_DEPTH, &inpbusaddr, GFP_KERNEL);
@@ -474,7 +484,7 @@ static int caam_jr_probe(struct platform_device *pdev)
struct device *jrdev;
struct device_node *nprop;
struct caam_job_ring __iomem *ctrl;
- struct caam_drv_private_jr *jrpriv;
+ struct caam_drv_private_jr *jrpriv, *jrppriv;
static int total_jobrs;
int error;
@@ -509,6 +519,10 @@ static int caam_jr_probe(struct platform_device *pdev)
/* Identify the interrupt */
jrpriv->irq = irq_of_parse_and_map(nprop, 0);
+ if (jrpriv->irq <= 0) {
+ kfree(jrpriv);
+ return -EINVAL;
+ }
/* Now do the platform independent part */
error = caam_jr_init(jrdev); /* now turn on hardware */
@@ -516,7 +530,7 @@ static int caam_jr_probe(struct platform_device *pdev)
irq_dispose_mapping(jrpriv->irq);
iounmap(ctrl);
return error;
- }
+ }
jrpriv->dev = jrdev;
spin_lock(&driver_data.jr_alloc_lock);
@@ -525,9 +539,68 @@ static int caam_jr_probe(struct platform_device *pdev)
atomic_set(&jrpriv->tfm_count, 0);
+ device_init_wakeup(&pdev->dev, 1);
+ device_set_wakeup_enable(&pdev->dev, false);
+ /*
+ * Instantiate RNG by JR rather than DECO
+ */
+ spin_lock(&driver_data.jr_alloc_lock);
+ if (list_empty(&driver_data.jr_list)) {
+ spin_unlock(&driver_data.jr_alloc_lock);
+ dev_err(jrdev, "jr_list is empty\n");
+ return -ENODEV;
+ }
+ jrppriv = list_first_entry(&driver_data.jr_list,
+ struct caam_drv_private_jr, list_node);
+ spin_unlock(&driver_data.jr_alloc_lock);
+ /*
+ * If this is the first available JR
+ * then try to instantiate RNG
+ */
+ if (jrppriv->ridx == jrpriv->ridx) {
+ if (!of_machine_is_compatible("fsl,imx8qm") &&
+ !of_machine_is_compatible("fsl,imx8qxp"))
+ /*
+ * This call is done for legacy SOCs:
+ * i.MX6 i.MX7 and i.MX8M (mScale).
+ */
+ error = inst_rng_imx(pdev);
+ }
+ if (error != 0) {
+ spin_lock(&driver_data.jr_alloc_lock);
+ list_del(&jrpriv->list_node);
+ spin_unlock(&driver_data.jr_alloc_lock);
+ }
+ return error;
+}
+
+#ifdef CONFIG_PM
+static int caam_jr_suspend(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct caam_drv_private_jr *jrpriv = platform_get_drvdata(pdev);
+
+ if (device_may_wakeup(&pdev->dev))
+ enable_irq_wake(jrpriv->irq);
+
+ return 0;
+}
+
+static int caam_jr_resume(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct caam_drv_private_jr *jrpriv = platform_get_drvdata(pdev);
+
+ if (device_may_wakeup(&pdev->dev))
+ disable_irq_wake(jrpriv->irq);
+
return 0;
}
+static SIMPLE_DEV_PM_OPS(caam_jr_pm_ops, caam_jr_suspend,
+ caam_jr_resume);
+#endif
+
static struct of_device_id caam_jr_match[] = {
{
.compatible = "fsl,sec-v4.0-job-ring",
@@ -543,6 +616,9 @@ static struct platform_driver caam_jr_driver = {
.driver = {
.name = "caam_jr",
.of_match_table = caam_jr_match,
+#ifdef CONFIG_PM
+ .pm = &caam_jr_pm_ops,
+#endif
},
.probe = caam_jr_probe,
.remove = caam_jr_remove,