diff options
author | Yashpal Dutta <yashpal.dutta@freescale.com> | 2014-03-22 00:34:07 (GMT) |
---|---|---|
committer | Jose Rivera <German.Rivera@freescale.com> | 2014-03-24 16:08:48 (GMT) |
commit | 51e4af86b989140b99c22e21c6b8d4a6bd747f9f (patch) | |
tree | f2bde4010712e4496bb59fd149f65233c3c73941 /drivers/crypto/caam/ctrl.c | |
parent | 98169a417ed211ebabd4af3cc8d457039caa280d (diff) | |
download | linux-fsl-qoriq-51e4af86b989140b99c22e21c6b8d4a6bd747f9f.tar.xz |
Power Management support for CAAM
Platform can go in sleep where CAAM will remain power ON while in some
cases CAAM will be powered off during deep-sleep. The patch handles
graceful recovery of CAAM state in both the power-up and powered-down
cases across deep-sleep.
Signed-off-by: Yashpal Dutta <yashpal.dutta@freescale.com>
Change-Id: Ie27fdfa78fc50c9a05f6316938ad42a70a89a48e
Reviewed-on: http://git.am.freescale.net:8181/9771
Tested-by: Review Code-CDREVIEW <CDREVIEW@freescale.com>
Reviewed-by: Ruchika Gupta <ruchika.gupta@freescale.com>
Reviewed-by: Jose Rivera <German.Rivera@freescale.com>
Reviewed-on: http://git.am.freescale.net:8181/10085
Diffstat (limited to 'drivers/crypto/caam/ctrl.c')
-rw-r--r-- | drivers/crypto/caam/ctrl.c | 226 |
1 files changed, 164 insertions, 62 deletions
diff --git a/drivers/crypto/caam/ctrl.c b/drivers/crypto/caam/ctrl.c index ef249a5..712a4c3 100644 --- a/drivers/crypto/caam/ctrl.c +++ b/drivers/crypto/caam/ctrl.c @@ -312,13 +312,12 @@ static int caam_remove(struct platform_device *pdev) /* * kick_trng - sets the various parameters for enabling the initialization * of the RNG4 block in CAAM - * @pdev - pointer to the platform device + * @pdev - pointer to the caam device * @ent_delay - Defines the length (in system clocks) of each entropy sample. */ -static void kick_trng(struct platform_device *pdev, int ent_delay) +static void kick_trng(struct device *dev, int ent_delay) { - struct device *ctrldev = &pdev->dev; - struct caam_drv_private *ctrlpriv = dev_get_drvdata(ctrldev); + struct caam_drv_private *ctrlpriv = dev_get_drvdata(dev); struct caam_full __iomem *topregs; struct rng4tst __iomem *r4tst; u32 val; @@ -375,10 +374,77 @@ int caam_get_era(void) } EXPORT_SYMBOL(caam_get_era); +static int caam_rng_init(struct device *dev) +{ + int gen_sk, ent_delay = RTSDCTL_ENT_DLY_MIN; + struct caam_drv_private *ctrlpriv = dev_get_drvdata(dev); + u64 cha_vid; + struct caam_full __iomem *topregs; + int ret = 0; + + topregs = (struct caam_full __iomem *)ctrlpriv->ctrl; + cha_vid = rd_reg64(&topregs->ctrl.perfmon.cha_id); + /* + * If SEC has RNG version >= 4 and RNG state handle has not been + * already instantiated, do RNG instantiation + */ + if ((cha_vid & CHA_ID_RNG_MASK) >> CHA_ID_RNG_SHIFT >= 4) { + ctrlpriv->rng4_sh_init = + rd_reg32(&topregs->ctrl.r4tst[0].rdsta); + /* + * If the secure keys (TDKEK, JDKEK, TDSK), were already + * generated, signal this to the function that is instantiating + * the state handles. An error would occur if RNG4 attempts + * to regenerate these keys before the next POR. + */ + gen_sk = ctrlpriv->rng4_sh_init & RDSTA_SKVN ? 0 : 1; + ctrlpriv->rng4_sh_init &= RDSTA_IFMASK; + do { + int inst_handles = + rd_reg32(&topregs->ctrl.r4tst[0].rdsta) & + RDSTA_IFMASK; + /* + * If either SH were instantiated by somebody else + * (e.g. u-boot) then it is assumed that the entropy + * parameters are properly set and thus the function + * setting these (kick_trng(...)) is skipped. + * Also, if a handle was instantiated, do not change + * the TRNG parameters. + */ + if (!(ctrlpriv->rng4_sh_init || inst_handles)) { + kick_trng(dev, ent_delay); + ent_delay += 400; + } + /* + * if instantiate_rng(...) fails, the loop will rerun + * and the kick_trng(...) function will modfiy the + * upper and lower limits of the entropy sampling + * interval, leading to a sucessful initialization of + * the RNG. + */ + ret = instantiate_rng(dev, inst_handles, + gen_sk); + } while ((ret == -EAGAIN) && (ent_delay < RTSDCTL_ENT_DLY_MAX)); + if (ret) { + dev_err(dev, "failed to instantiate RNG"); + return ret; + } + /* + * Set handles init'ed by this module as the complement of the + * already initialized ones + */ + ctrlpriv->rng4_sh_init = ~ctrlpriv->rng4_sh_init & RDSTA_IFMASK; + + /* Enable RDB bit so that RNG works faster */ + setbits32(&topregs->ctrl.scfgr, SCFGR_RDBENABLE); + } + return 0; +} + /* Probe routine for CAAM top (controller) level */ static int caam_probe(struct platform_device *pdev) { - int ret, ring, rspec, gen_sk, ent_delay = RTSDCTL_ENT_DLY_MIN; + int ret, ring, rspec; u64 caam_id; struct device *dev; struct device_node *nprop, *np; @@ -388,7 +454,6 @@ static int caam_probe(struct platform_device *pdev) #ifdef CONFIG_DEBUG_FS struct caam_perfmon *perfmon; #endif - u64 cha_vid; ctrlpriv = kzalloc(sizeof(struct caam_drv_private), GFP_KERNEL); if (!ctrlpriv) @@ -498,62 +563,10 @@ static int caam_probe(struct platform_device *pdev) return -ENOMEM; } - cha_vid = rd_reg64(&topregs->ctrl.perfmon.cha_id); - - /* - * If SEC has RNG version >= 4 and RNG state handle has not been - * already instantiated, do RNG instantiation - */ - if ((cha_vid & CHA_ID_RNG_MASK) >> CHA_ID_RNG_SHIFT >= 4) { - ctrlpriv->rng4_sh_init = - rd_reg32(&topregs->ctrl.r4tst[0].rdsta); - /* - * If the secure keys (TDKEK, JDKEK, TDSK), were already - * generated, signal this to the function that is instantiating - * the state handles. An error would occur if RNG4 attempts - * to regenerate these keys before the next POR. - */ - gen_sk = ctrlpriv->rng4_sh_init & RDSTA_SKVN ? 0 : 1; - ctrlpriv->rng4_sh_init &= RDSTA_IFMASK; - do { - int inst_handles = - rd_reg32(&topregs->ctrl.r4tst[0].rdsta) & - RDSTA_IFMASK; - /* - * If either SH were instantiated by somebody else - * (e.g. u-boot) then it is assumed that the entropy - * parameters are properly set and thus the function - * setting these (kick_trng(...)) is skipped. - * Also, if a handle was instantiated, do not change - * the TRNG parameters. - */ - if (!(ctrlpriv->rng4_sh_init || inst_handles)) { - kick_trng(pdev, ent_delay); - ent_delay += 400; - } - /* - * if instantiate_rng(...) fails, the loop will rerun - * and the kick_trng(...) function will modfiy the - * upper and lower limits of the entropy sampling - * interval, leading to a sucessful initialization of - * the RNG. - */ - ret = instantiate_rng(dev, inst_handles, - gen_sk); - } while ((ret == -EAGAIN) && (ent_delay < RTSDCTL_ENT_DLY_MAX)); - if (ret) { - dev_err(dev, "failed to instantiate RNG"); - caam_remove(pdev); - return ret; - } - /* - * Set handles init'ed by this module as the complement of the - * already initialized ones - */ - ctrlpriv->rng4_sh_init = ~ctrlpriv->rng4_sh_init & RDSTA_IFMASK; - - /* Enable RDB bit so that RNG works faster */ - setbits32(&topregs->ctrl.scfgr, SCFGR_RDBENABLE); + ret = caam_rng_init(dev); + if (ret) { + caam_remove(pdev); + return ret; } /* NOTE: RTIC detection ought to go here, around Si time */ @@ -649,6 +662,92 @@ static int caam_probe(struct platform_device *pdev) return 0; } +#ifdef CONFIG_PM +static int caam_stop_qi(struct caam_full __iomem *topregs) +{ + int qi_stopped, loop = 0; + + setbits32(&topregs->qi.qi_control_lo, QICTL_STOP); + + /* + * Wait till QI Job's in Holding tank/deco are completed. + * No dequeue from QI will be happen till QI interface is + * reenabled. + */ + while (loop <= 100000) { + qi_stopped = rd_reg32(&topregs->qi.qi_status) & + QISTA_STOPD; + if (qi_stopped) { + wr_reg32(&topregs->qi.qi_control_lo, + QICTL_STOP); + return 0; + } + loop++; + } + + /* Failed to stop QI interface. Reenable QI Interface */ + wr_reg32(&topregs->qi.qi_control_lo, QICTL_DQEN); + return -EBUSY; +} + +/* Suspend handler for caam device */ +static int caam_suspend(struct device *dev) +{ + struct caam_drv_private *caam_priv; + struct caam_full __iomem *topregs; + struct caam_ctrl __iomem *ctrl; + int ret = 0; + + caam_priv = dev_get_drvdata(dev); + ctrl = caam_priv->ctrl; + topregs = (struct caam_full __iomem *)ctrl; + + /* QI Interface graceful stoppping during suspend */ + if (caam_priv->qi_present) { + int qi_dqen; + + qi_dqen = rd_reg32(&topregs->qi.qi_control_lo) & + QICTL_DQEN; + if (qi_dqen) + ret = caam_stop_qi(topregs); + } + + return ret; +} + +/* Resume handler for caam device */ +static int caam_resume(struct device *dev) +{ + struct caam_drv_private *caam_priv; + struct caam_full __iomem *topregs; + struct caam_ctrl __iomem *ctrl; + int ret; + + caam_priv = dev_get_drvdata(dev); + ctrl = caam_priv->ctrl; + topregs = (struct caam_full __iomem *)ctrl; + /* + * Enable DECO watchdogs and, if this is a PHYS_ADDR_T_64BIT kernel, + * long pointers in master configuration register + */ + setbits32(&topregs->ctrl.mcr, MCFGR_WDENABLE | + (sizeof(dma_addr_t) == sizeof(u64) ? MCFGR_LONG_PTR : 0)); + + /* Enable QI interface of SEC */ + if (caam_priv->qi_present) + wr_reg32(&topregs->qi.qi_control_lo, QICTL_DQEN); + + ret = caam_rng_init(dev); + + return ret; +} + +const struct dev_pm_ops caam_pm_ops = { + .suspend = caam_suspend, + .resume = caam_resume, +}; +#endif /* CONFIG_PM */ + static struct of_device_id caam_match[] = { { .compatible = "fsl,sec-v4.0", @@ -665,6 +764,9 @@ static struct platform_driver caam_driver = { .name = "caam", .owner = THIS_MODULE, .of_match_table = caam_match, +#ifdef CONFIG_PM + .pm = &caam_pm_ops, +#endif }, .probe = caam_probe, .remove = caam_remove, |