diff options
-rw-r--r-- | drivers/crypto/caam/ctrl.c | 177 | ||||
-rw-r--r-- | drivers/crypto/caam/inst_rng.c | 13 | ||||
-rw-r--r-- | drivers/crypto/caam/intern.h | 35 | ||||
-rw-r--r-- | drivers/crypto/caam/jr.c | 337 |
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 }, |