summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/crypto/caam/ctrl.c177
-rw-r--r--drivers/crypto/caam/inst_rng.c13
-rw-r--r--drivers/crypto/caam/intern.h35
-rw-r--r--drivers/crypto/caam/jr.c337
4 files changed, 446 insertions, 116 deletions
diff --git a/drivers/crypto/caam/ctrl.c b/drivers/crypto/caam/ctrl.c
index 1097ae664347..df5ec6479b9f 100644
--- a/drivers/crypto/caam/ctrl.c
+++ b/drivers/crypto/caam/ctrl.c
@@ -2,7 +2,7 @@
* Controller-level driver, kernel property detection, initialization
*
* Copyright 2008-2016 Freescale Semiconductor, Inc.
- * Copyright 2017-2018 NXP
+ * Copyright 2017-2019 NXP
*/
#include <linux/device.h>
@@ -43,6 +43,12 @@ static void enable_qi(struct caam_drv_private *ctrlpriv, int block_offset);
static int read_first_jr_index(struct caam_drv_private *ctrlpriv);
static int probe_w_seco(struct caam_drv_private *ctrlpriv);
static void init_debugfs(struct caam_drv_private *ctrlpriv);
+static void caam_ctrl_hw_configuration(struct caam_drv_private *ctrlpriv);
+static void enable_virt(struct caam_drv_private *ctrlpriv);
+
+#ifdef CONFIG_PM_SLEEP
+static int caam_off_during_pm(void);
+#endif
/*
* i.MX targets tend to have clock control subsystems that can
@@ -299,6 +305,27 @@ exit:
return ret;
}
+static void caam_ctrl_hw_configuration(struct caam_drv_private *ctrlpriv)
+{
+ /*
+ * Enable DECO watchdogs and, if this is a PHYS_ADDR_T_64BIT kernel,
+ * long pointers in master configuration register.
+ * In case of DPAA 2.x, Management Complex firmware performs
+ * the configuration.
+ */
+ if (!caam_dpaa2)
+ clrsetbits_32(&ctrlpriv->ctrl->mcr,
+ MCFGR_AWCACHE_MASK | MCFGR_LONG_PTR,
+ MCFGR_AWCACHE_CACH | MCFGR_AWCACHE_BUFF |
+ MCFGR_WDENABLE | MCFGR_LARGE_BURST |
+ (sizeof(dma_addr_t) == sizeof(u64) ?
+ MCFGR_LONG_PTR : 0));
+
+ handle_imx6_err005766(ctrlpriv);
+
+ enable_virt(ctrlpriv);
+}
+
/* Probe routine for CAAM top (controller) level */
static int caam_probe(struct platform_device *pdev)
{
@@ -349,16 +376,30 @@ static int caam_probe(struct platform_device *pdev)
}
ctrlpriv->ctrl = (struct caam_ctrl __force *)ctrl;
+ if (of_find_compatible_node(NULL, NULL, "linaro,optee-tz"))
+ ctrlpriv->has_optee = 1;
+
if (of_machine_is_compatible("fsl,imx8qm") ||
- of_machine_is_compatible("fsl,imx8qxp")) {
+ of_machine_is_compatible("fsl,imx8qxp"))
+ ctrlpriv->has_seco = 1;
+
+ /*
+ * The driver does not have access to Page 0 of the CAAM if there
+ * is a secure component managing the CAAM as optee or SECO.
+ */
+ ctrlpriv->has_access_p0 = !(ctrlpriv->has_optee || ctrlpriv->has_seco);
+
+#ifdef CONFIG_PM_SLEEP
+ ctrlpriv->caam_off_during_pm = caam_off_during_pm();
+#endif
+
+ if (ctrlpriv->has_seco) {
ret = probe_w_seco(ctrlpriv);
if (ret)
goto iounmap_ctrl;
return ret;
}
- ctrlpriv->has_seco = false;
-
if (caam_imx)
caam_little_end = true;
else
@@ -417,24 +458,12 @@ static int caam_probe(struct platform_device *pdev)
ctrlpriv->sm_size = PG_SIZE_64K;
}
- /*
- * Enable DECO watchdogs and, if this is a PHYS_ADDR_T_64BIT kernel,
- * long pointers in master configuration register.
- * In case of DPAA 2.x, Management Complex firmware performs
- * the configuration.
- */
caam_dpaa2 = !!(comp_params & CTPR_MS_DPAA2);
- if (!caam_dpaa2)
- clrsetbits_32(&ctrl->mcr, MCFGR_AWCACHE_MASK | MCFGR_LONG_PTR,
- MCFGR_AWCACHE_CACH | MCFGR_AWCACHE_BUFF |
- MCFGR_WDENABLE | MCFGR_LARGE_BURST |
- (sizeof(dma_addr_t) == sizeof(u64) ?
- MCFGR_LONG_PTR : 0));
-
- handle_imx6_err005766(ctrlpriv);
-
check_virt(ctrlpriv, comp_params);
+ if (ctrlpriv->has_access_p0)
+ caam_ctrl_hw_configuration(ctrlpriv);
+
/* Set DMA masks according to platform ranging */
if (of_machine_is_compatible("fsl,imx8mm") ||
of_machine_is_compatible("fsl,imx8qm") ||
@@ -504,6 +533,14 @@ exit:
return ret;
}
+static void enable_virt(struct caam_drv_private *ctrlpriv)
+{
+ if (ctrlpriv->virt_en == 1)
+ clrsetbits_32(&ctrlpriv->ctrl->jrstart, 0, JRSTART_JR0_START |
+ JRSTART_JR1_START | JRSTART_JR2_START |
+ JRSTART_JR3_START);
+}
+
static void check_virt(struct caam_drv_private *ctrlpriv, u32 comp_params)
{
/*
@@ -528,11 +565,6 @@ static void check_virt(struct caam_drv_private *ctrlpriv, u32 comp_params)
if (comp_params & CTPR_MS_VIRT_EN_POR)
ctrlpriv->virt_en = 1;
}
-
- if (ctrlpriv->virt_en == 1)
- clrsetbits_32(&ctrlpriv->ctrl->jrstart, 0, JRSTART_JR0_START |
- JRSTART_JR1_START | JRSTART_JR2_START |
- JRSTART_JR3_START);
}
static int enable_jobrings(struct caam_drv_private *ctrlpriv, int block_offset)
@@ -804,10 +836,107 @@ static const struct of_device_id caam_match[] = {
};
MODULE_DEVICE_TABLE(of, caam_match);
+#ifdef CONFIG_PM_SLEEP
+
+/*
+ * Indicate if the internal state of the CAAM is lost during PM
+ */
+static int caam_off_during_pm(void)
+{
+ if (IS_ENABLED(CONFIG_ARM64))
+ return 1;
+
+ if (of_machine_is_compatible("fsl,imx6sx") ||
+ of_machine_is_compatible("fsl,imx6ul") ||
+ of_machine_is_compatible("fsl,imx7ulp") ||
+ of_machine_is_compatible("fsl,imx7d") ||
+ of_machine_is_compatible("fsl,imx7s"))
+ return 1;
+
+ return 0;
+}
+
+static void caam_state_save(struct device *dev)
+{
+ int idx;
+ struct caam_drv_private *ctrlpriv = dev_get_drvdata(dev);
+ struct caam_ctl_state *state = &ctrlpriv->state;
+ struct caam_ctrl *ctrl = ctrlpriv->ctrl;
+
+ /* Save SCFGR */
+ state->scfgr = rd_reg32(&ctrl->scfgr);
+
+ /* Save DECO mid */
+ state->deco_mid[0].liodn_ms = rd_reg32(&ctrl->deco_mid[0].liodn_ms);
+ state->deco_mid[0].liodn_ls = rd_reg32(&ctrl->deco_mid[0].liodn_ls);
+
+ /* Save the MID for JR assigned to linux */
+ for (idx = 0; idx < JOBR_MAX_COUNT; idx++)
+ if (ctrlpriv->jr[idx]) {
+ state->jr_mid[idx].liodn_ms =
+ rd_reg32(&ctrl->jr_mid[idx].liodn_ms);
+ state->jr_mid[idx].liodn_ls =
+ rd_reg32(&ctrl->jr_mid[idx].liodn_ls);
+ }
+}
+
+static void caam_state_restore(const struct device *dev)
+{
+ int idx;
+ const struct caam_drv_private *ctrlpriv = dev_get_drvdata(dev);
+ const struct caam_ctl_state *state = &ctrlpriv->state;
+ struct caam_ctrl *ctrl = ctrlpriv->ctrl;
+
+ /* Restore SCFGR */
+ wr_reg32(&ctrl->scfgr, state->scfgr);
+
+ /* Restore DECO mid */
+ wr_reg32(&ctrl->deco_mid[0].liodn_ms, state->deco_mid[0].liodn_ms);
+ wr_reg32(&ctrl->deco_mid[0].liodn_ls, state->deco_mid[0].liodn_ls);
+
+ /* Restore the MID for JR assigned to linux */
+ for (idx = 0; idx < JOBR_MAX_COUNT; idx++)
+ if (ctrlpriv->jr[idx]) {
+ wr_reg32(&ctrl->jr_mid[idx].liodn_ms,
+ state->jr_mid[idx].liodn_ms);
+ wr_reg32(&ctrl->jr_mid[idx].liodn_ls,
+ state->jr_mid[idx].liodn_ls);
+ }
+}
+
+static int caam_ctrl_suspend(struct device *dev)
+{
+ const struct caam_drv_private *ctrlpriv = dev_get_drvdata(dev);
+
+ if (ctrlpriv->caam_off_during_pm && ctrlpriv->has_access_p0)
+ caam_state_save(dev);
+
+ return 0;
+}
+
+static int caam_ctrl_resume(struct device *dev)
+{
+ struct caam_drv_private *ctrlpriv = dev_get_drvdata(dev);
+
+ if (ctrlpriv->caam_off_during_pm && ctrlpriv->has_access_p0) {
+ caam_state_restore(dev);
+ caam_ctrl_hw_configuration(ctrlpriv);
+ }
+
+ return 0;
+}
+
+SIMPLE_DEV_PM_OPS(caam_ctrl_pm_ops, caam_ctrl_suspend, caam_ctrl_resume);
+
+#endif /* CONFIG_PM_SLEEP */
+
static struct platform_driver caam_driver = {
.driver = {
.name = "caam",
.of_match_table = caam_match,
+#ifdef CONFIG_PM_SLEEP
+ .pm = &caam_ctrl_pm_ops,
+#endif
},
.probe = caam_probe,
.remove = caam_remove,
diff --git a/drivers/crypto/caam/inst_rng.c b/drivers/crypto/caam/inst_rng.c
index c5c83ab9c158..2cdbef347e23 100644
--- a/drivers/crypto/caam/inst_rng.c
+++ b/drivers/crypto/caam/inst_rng.c
@@ -2,7 +2,7 @@
/*
* CAAM RNG instantiation driver backend
*
- * Copyright 2017-2018 NXP
+ * Copyright 2017-2019 NXP
*/
#include <linux/device.h>
@@ -290,17 +290,6 @@ int inst_rng_imx(struct platform_device *pdev)
ctrlpriv = dev_get_drvdata(ctrldev);
ctrl = (struct caam_ctrl __iomem *)ctrlpriv->ctrl;
-#ifndef CONFIG_ARM64
- /*
- * Check if the Secure Firmware is running,
- * check only for i.MX6 and i.MX7
- */
- if (of_find_compatible_node(NULL, NULL, "linaro,optee-tz")) {
- pr_info("RNG Instantation done by Secure Firmware\n");
- return ret;
- }
-#endif
-
cha_vid_ls = rd_reg32(&ctrl->perfmon.cha_id_ls);
/*
diff --git a/drivers/crypto/caam/intern.h b/drivers/crypto/caam/intern.h
index 5763536ba9bb..debdb603ff0e 100644
--- a/drivers/crypto/caam/intern.h
+++ b/drivers/crypto/caam/intern.h
@@ -4,7 +4,7 @@
* Private/internal definitions between modules
*
* Copyright 2008-2016 Freescale Semiconductor, Inc.
- * Copyright 2017-2018 NXP
+ * Copyright 2017-2019 NXP
*
*/
@@ -41,6 +41,18 @@ struct caam_jrentry_info {
u32 desc_size; /* Stored size for postprocessing, header derived */
};
+#ifdef CONFIG_PM_SLEEP
+struct caam_jr_state {
+ dma_addr_t inpbusaddr;
+ dma_addr_t outbusaddr;
+};
+#endif
+
+struct caam_jr_dequeue_params {
+ struct device *dev;
+ int enable_itr;
+};
+
/* Private sub-storage for a single JobR */
struct caam_drv_private_jr {
struct list_head list_node; /* Job Ring device list */
@@ -48,6 +60,7 @@ struct caam_drv_private_jr {
int ridx;
struct caam_job_ring __iomem *rregs; /* JobR's register space */
struct tasklet_struct irqtask;
+ struct caam_jr_dequeue_params tasklet_params;
int irq; /* One per queue */
/* Number of scatterlist crypt transforms active on the JobR */
@@ -64,7 +77,19 @@ struct caam_drv_private_jr {
int out_ring_read_index; /* Output index "tail" */
int tail; /* entinfo (s/w ring) tail index */
struct jr_outentry *outring; /* Base of output ring, DMA-safe */
+
+#ifdef CONFIG_PM_SLEEP
+ struct caam_jr_state state; /* State of the JR during PM */
+#endif
+};
+
+#ifdef CONFIG_PM_SLEEP
+struct caam_ctl_state {
+ u32 scfgr;
+ struct masterid deco_mid[1];
+ struct masterid jr_mid[4];
};
+#endif
/*
* Driver-private storage for a single CAAM block instance
@@ -125,6 +150,14 @@ struct caam_drv_private {
struct debugfs_blob_wrapper ctl_kek_wrap, ctl_tkek_wrap, ctl_tdsk_wrap;
struct dentry *ctl_kek, *ctl_tkek, *ctl_tdsk;
#endif
+
+ int has_optee;
+ int has_access_p0; /* If driver has acces to page 0 of the CAAM */
+
+#ifdef CONFIG_PM_SLEEP
+ int caam_off_during_pm; /* If the CAAM is reset after suspend */
+ struct caam_ctl_state state; /* State of the CTL during PM */
+#endif
};
void caam_jr_algapi_init(struct device *dev);
diff --git a/drivers/crypto/caam/jr.c b/drivers/crypto/caam/jr.c
index 616a42709010..88ec227b67a9 100644
--- a/drivers/crypto/caam/jr.c
+++ b/drivers/crypto/caam/jr.c
@@ -3,7 +3,7 @@
* JobR backend functionality
*
* Copyright 2008-2016 Freescale Semiconductor, Inc.
- * Copyright 2017-2018 NXP
+ * Copyright 2017-2019 NXP
*/
#include <linux/of_irq.h>
@@ -25,47 +25,122 @@ struct jr_driver_data {
static struct jr_driver_data driver_data;
-static int caam_reset_hw_jr(struct device *dev)
+static inline void mask_itr(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
- * for reset completion status
- */
clrsetbits_32(&jrp->rregs->rconfig_lo, 0, JRCFG_IMSK);
+}
- /* initiate flush (required prior to reset) */
- wr_reg32(&jrp->rregs->jrcommand, JRCR_RESET);
+static inline void unmask_itr(struct device *dev)
+{
+ struct caam_drv_private_jr *jrp = dev_get_drvdata(dev);
+
+ clrsetbits_32(&jrp->rregs->rconfig_lo, JRCFG_IMSK, 0);
+}
+
+/*
+ * Put the CAAM in quiesce, ie stop
+ *
+ * Must be called with itr disabled
+ */
+static int caam_jr_stop_processing(struct device *dev, u32 jrcr_bits)
+{
+ unsigned int timeout = 100000;
+ unsigned int halt_status;
+ struct caam_drv_private_jr *jrp = dev_get_drvdata(dev);
+
+ if (rd_reg32(&jrp->rregs->jrintstatus) & JRINT_ERR_HALT_MASK) {
+ dev_err(dev, "Not ready to quiesce\n");
+ return -EINVAL;
+ }
+
+ /* initiate quiesce */
+ wr_reg32(&jrp->rregs->jrcommand, jrcr_bits);
+
+ /* Wait for the quiesce completion or timeout run out */
do {
cpu_relax();
- reg_value = rd_reg32(&jrp->rregs->jrintstatus);
- } while (((reg_value & JRINT_ERR_HALT_MASK) ==
- JRINT_ERR_HALT_INPROGRESS) && --timeout);
+ halt_status = rd_reg32(&jrp->rregs->jrintstatus) &
+ JRINT_ERR_HALT_MASK;
+ } while ((halt_status == JRINT_ERR_HALT_INPROGRESS) &&
+ --timeout);
- if ((rd_reg32(&jrp->rregs->jrintstatus) & JRINT_ERR_HALT_MASK) !=
- JRINT_ERR_HALT_COMPLETE || timeout == 0) {
- dev_err(dev, "failed to flush job ring %d\n", jrp->ridx);
+ halt_status = rd_reg32(&jrp->rregs->jrintstatus) & JRINT_ERR_HALT_MASK;
+
+ /* Check that the flush is complete */
+ if (halt_status != JRINT_ERR_HALT_COMPLETE) {
+ dev_err(dev, "failed to quiesce\n");
return -EIO;
}
+ return 0;
+}
+
+/*
+ * Flush the job ring, so the jobs running will be stopped, jobs queued will be
+ * invalidated and the CAAM will no longer fetch fron input ring.
+ *
+ * Must be called with itr disabled
+ */
+static int caam_jr_flush(struct device *dev)
+{
+ return caam_jr_stop_processing(dev, JRCR_RESET);
+}
+
+#ifdef CONFIG_PM_SLEEP
+
+/* The resume can be used after a park or a flush if CAAM has not been reset */
+static int caam_jr_restart_processing(struct device *dev)
+{
+ struct caam_drv_private_jr *jrp = dev_get_drvdata(dev);
+ u32 park_status = rd_reg32(&jrp->rregs->jrintstatus) &
+ JRINT_ERR_HALT_MASK;
+
+ /* Check that the flush/park is completed */
+ if (park_status != JRINT_ERR_HALT_COMPLETE)
+ return -1;
+
+ /* Resume processing of jobs */
+ wr_reg32(&jrp->rregs->jrintstatus, JRINT_ERR_HALT_COMPLETE);
+
+ return 0;
+}
+
+#endif /* CONFIG_PM_SLEEP */
+
+static int caam_reset_hw_jr(struct device *dev)
+{
+ int err = 0;
+ struct caam_drv_private_jr *jrp = dev_get_drvdata(dev);
+ unsigned int timeout = 100000;
+ unsigned int reset_status;
+
+ /*
+ * mask interrupts since we are going to poll
+ * for reset completion status
+ */
+ mask_itr(dev);
+
+ err = caam_jr_flush(dev);
+ if (err)
+ return err;
+
/* initiate reset */
- timeout = 100000;
wr_reg32(&jrp->rregs->jrcommand, JRCR_RESET);
do {
cpu_relax();
- reg_value = rd_reg32(&jrp->rregs->jrcommand);
- } while ((reg_value & JRCR_RESET) && --timeout);
+ reset_status = rd_reg32(&jrp->rregs->jrcommand) & JRCR_RESET;
+ } while (reset_status && --timeout);
- if (timeout == 0) {
+ reset_status = rd_reg32(&jrp->rregs->jrcommand) & JRCR_RESET;
+ if (reset_status != 0) {
dev_err(dev, "failed to reset job ring %d\n", jrp->ridx);
return -EIO;
}
/* unmask interrupts */
- clrsetbits_32(&jrp->rregs->rconfig_lo, JRCFG_IMSK, 0);
+ unmask_itr(dev);
return 0;
}
@@ -161,7 +236,7 @@ static irqreturn_t caam_jr_interrupt(int irq, void *st_dev)
}
/* mask valid interrupts */
- clrsetbits_32(&jrp->rregs->rconfig_lo, 0, JRCFG_IMSK);
+ mask_itr(dev);
/* Have valid interrupt at this point, just ACK and trigger */
wr_reg32(&jrp->rregs->jrintstatus, irqstate);
@@ -174,10 +249,11 @@ static irqreturn_t caam_jr_interrupt(int irq, void *st_dev)
}
/* Deferred service handler, run as interrupt-fired tasklet */
-static void caam_jr_dequeue(unsigned long devarg)
+static void caam_jr_dequeue(unsigned long data)
{
int hw_idx, sw_idx, i, head, tail;
- struct device *dev = (struct device *)devarg;
+ struct caam_jr_dequeue_params *params = (void *)data;
+ struct device *dev = params->dev;
struct caam_drv_private_jr *jrp = dev_get_drvdata(dev);
void (*usercall)(struct device *dev, u32 *desc, u32 status, void *arg);
u32 *userdesc, userstatus;
@@ -251,7 +327,8 @@ static void caam_jr_dequeue(unsigned long devarg)
}
/* reenable / unmask IRQs */
- clrsetbits_32(&jrp->rregs->rconfig_lo, JRCFG_IMSK, 0);
+ if (params->enable_itr)
+ unmask_itr(dev);
}
/**
@@ -396,6 +473,30 @@ int caam_jr_enqueue(struct device *dev, u32 *desc,
}
EXPORT_SYMBOL(caam_jr_enqueue);
+static void caam_jr_init_hw(struct device *dev, dma_addr_t inpbusaddr,
+ dma_addr_t outbusaddr)
+{
+ struct caam_drv_private_jr *jrp = dev_get_drvdata(dev);
+
+ wr_reg64(&jrp->rregs->inpring_base, inpbusaddr);
+ wr_reg64(&jrp->rregs->outring_base, outbusaddr);
+ wr_reg32(&jrp->rregs->inpring_size, JOBR_DEPTH);
+ wr_reg32(&jrp->rregs->outring_size, JOBR_DEPTH);
+
+ /* Select interrupt coalescing parameters */
+ clrsetbits_32(&jrp->rregs->rconfig_lo, 0, JOBR_INTC |
+ (JOBR_INTC_COUNT_THLD << JRCFG_ICDCT_SHIFT) |
+ (JOBR_INTC_TIME_THLD << JRCFG_ICTT_SHIFT));
+}
+
+static void caam_jr_reset_index(struct caam_drv_private_jr *jrp)
+{
+ jrp->inp_ring_write_index = 0;
+ jrp->out_ring_read_index = 0;
+ jrp->head = 0;
+ jrp->tail = 0;
+}
+
/*
* Init JobR independent of platform property detection
*/
@@ -411,7 +512,10 @@ static int caam_jr_init(struct device *dev)
if (error)
goto out_kill_deq;
- tasklet_init(&jrp->irqtask, caam_jr_dequeue, (unsigned long)dev);
+ jrp->tasklet_params.dev = dev;
+ jrp->tasklet_params.enable_itr = 1;
+ tasklet_init(&jrp->irqtask, caam_jr_dequeue,
+ (unsigned long)&jrp->tasklet_params);
/* Connect job ring interrupt handler. */
error = request_irq(jrp->irq, caam_jr_interrupt, IRQF_SHARED,
@@ -441,26 +545,15 @@ static int caam_jr_init(struct device *dev)
jrp->entinfo[i].desc_addr_dma = !0;
/* Setup rings */
- jrp->inp_ring_write_index = 0;
- jrp->out_ring_read_index = 0;
- jrp->head = 0;
- jrp->tail = 0;
-
- wr_reg64(&jrp->rregs->inpring_base, inpbusaddr);
- wr_reg64(&jrp->rregs->outring_base, outbusaddr);
- wr_reg32(&jrp->rregs->inpring_size, JOBR_DEPTH);
- wr_reg32(&jrp->rregs->outring_size, JOBR_DEPTH);
+ caam_jr_reset_index(jrp);
jrp->ringsize = JOBR_DEPTH;
+ caam_jr_init_hw(dev, inpbusaddr, outbusaddr);
+
spin_lock_init(&jrp->inplock);
spin_lock_init(&jrp->outlock);
- /* Select interrupt coalescing parameters */
- clrsetbits_32(&jrp->rregs->rconfig_lo, 0, JOBR_INTC |
- (JOBR_INTC_COUNT_THLD << JRCFG_ICDCT_SHIFT) |
- (JOBR_INTC_TIME_THLD << JRCFG_ICTT_SHIFT));
-
return 0;
out_free_outring:
@@ -477,6 +570,29 @@ out_kill_deq:
return error;
}
+static int caam_jr_instantiate_rng(struct device *jrdev)
+{
+ int error = 0;
+ struct caam_drv_private_jr *jrpriv;
+ struct caam_drv_private *ctrlpriv = dev_get_drvdata(jrdev->parent);
+
+ if (ctrlpriv->has_seco || ctrlpriv->has_optee) {
+ dev_dbg(jrdev, "RNG instantiated by secure component\n");
+ goto exit;
+ }
+
+ jrpriv = dev_get_drvdata(jrdev);
+
+ /*
+ * If this is the first available JR
+ * then try to instantiate RNG
+ */
+ if (jrpriv->ridx == 0)
+ error = inst_rng_imx(to_platform_device(jrdev));
+
+exit:
+ return error;
+}
/*
* Probe routine for each detected JobR subsystem.
@@ -486,7 +602,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, *jrppriv;
+ struct caam_drv_private_jr *jrpriv;
static int total_jobrs;
int error;
@@ -498,6 +614,7 @@ static int caam_jr_probe(struct platform_device *pdev)
}
dev_set_drvdata(jrdev, jrpriv);
+ jrpriv->dev = jrdev;
/* save ring identity relative to detection */
jrpriv->ridx = total_jobrs++;
@@ -548,11 +665,9 @@ static int caam_jr_probe(struct platform_device *pdev)
/* Now do the platform independent part */
error = caam_jr_init(jrdev); /* now turn on hardware */
- if (error) {
+ if (error)
goto dispose_irq_mapping;
- }
- jrpriv->dev = jrdev;
spin_lock(&driver_data.jr_alloc_lock);
list_add_tail(&jrpriv->list_node, &driver_data.jr_list);
spin_unlock(&driver_data.jr_alloc_lock);
@@ -561,32 +676,8 @@ static int caam_jr_probe(struct platform_device *pdev)
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");
- error = -ENODEV;
- goto dispose_irq_mapping;
- }
- 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);
- }
+
+ error = caam_jr_instantiate_rng(jrdev);
if (error)
goto remove_jr_from_list;
@@ -605,32 +696,120 @@ exit:
return error;
}
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
+
+static void caam_jr_get_hw_state(struct device *dev)
+{
+ struct caam_drv_private_jr *jrp = dev_get_drvdata(dev);
+
+ jrp->state.inpbusaddr = rd_reg64(&jrp->rregs->inpring_base);
+ jrp->state.outbusaddr = rd_reg64(&jrp->rregs->outring_base);
+}
+
static int caam_jr_suspend(struct device *dev)
{
+ int err = 0;
struct platform_device *pdev = to_platform_device(dev);
struct caam_drv_private_jr *jrpriv = platform_get_drvdata(pdev);
+ struct caam_drv_private *ctrlpriv = dev_get_drvdata(dev->parent);
+ struct caam_jr_dequeue_params suspend_params = {
+ .dev = dev,
+ .enable_itr = 0,
+ };
+
+ if (ctrlpriv->caam_off_during_pm) {
+ tasklet_disable(&jrpriv->irqtask);
+
+ /* mask itr to call flush */
+ mask_itr(dev);
+
+ /* Invalid job in process */
+ err = caam_jr_flush(dev);
+ if (err) {
+ dev_err(dev, "Failed to flush\n");
+ goto exit;
+ }
+
+ /* Dequeing jobs flushed */
+ caam_jr_dequeue((unsigned long)&suspend_params);
- if (device_may_wakeup(&pdev->dev))
+ /* Save state */
+ caam_jr_get_hw_state(dev);
+
+ } else if (device_may_wakeup(&pdev->dev)) {
enable_irq_wake(jrpriv->irq);
+ }
- return 0;
+exit:
+ return err;
}
static int caam_jr_resume(struct device *dev)
{
+ int err = 0;
struct platform_device *pdev = to_platform_device(dev);
struct caam_drv_private_jr *jrpriv = platform_get_drvdata(pdev);
+ struct caam_drv_private *ctrlpriv = dev_get_drvdata(dev->parent);
+
+ if (ctrlpriv->caam_off_during_pm) {
+ u64 inp_addr;
+
+ /*
+ * Check if the CAAM has been resetted checking the address of
+ * the input ring
+ */
+ inp_addr = rd_reg64(&jrpriv->rregs->inpring_base);
+ if (inp_addr != 0) {
+ /* JR still has some configuration */
+ if (inp_addr == jrpriv->state.inpbusaddr) {
+ /* JR has not been resetted */
+ err = caam_jr_restart_processing(dev);
+ if (err)
+ goto exit;
+
+ tasklet_enable(&jrpriv->irqtask);
+
+ unmask_itr(dev);
+
+ goto exit;
+ } else if (ctrlpriv->has_optee) {
+ /* JR has been used by OPTEE, reset it */
+ err = caam_reset_hw_jr(dev);
+ if (err) {
+ dev_err(dev, "Failed to reset JR\n");
+ goto exit;
+ }
+ } else {
+ /* No explanation, return error */
+ err = -EIO;
+ goto exit;
+ }
+ }
+
+ caam_jr_reset_index(jrpriv);
- if (device_may_wakeup(&pdev->dev))
+ caam_jr_init_hw(dev, jrpriv->state.inpbusaddr,
+ jrpriv->state.outbusaddr);
+
+ tasklet_enable(&jrpriv->irqtask);
+
+ err = caam_jr_instantiate_rng(dev);
+ if (err) {
+ dev_err(dev, "Failed to instantiate RNG\n");
+ goto exit;
+ }
+
+ } else if (device_may_wakeup(&pdev->dev)) {
disable_irq_wake(jrpriv->irq);
+ }
- return 0;
+exit:
+ return err;
}
-static SIMPLE_DEV_PM_OPS(caam_jr_pm_ops, caam_jr_suspend,
- caam_jr_resume);
-#endif
+SIMPLE_DEV_PM_OPS(caam_jr_pm_ops, caam_jr_suspend, caam_jr_resume);
+
+#endif /* CONFIG_PM_SLEEP */
static const struct of_device_id caam_jr_match[] = {
{
@@ -647,7 +826,7 @@ static struct platform_driver caam_jr_driver = {
.driver = {
.name = "caam_jr",
.of_match_table = caam_jr_match,
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
.pm = &caam_jr_pm_ops,
#endif
},