summaryrefslogtreecommitdiff
path: root/drivers/crypto/caam/ctrl.c
diff options
context:
space:
mode:
authorYashpal Dutta <yashpal.dutta@freescale.com>2014-03-22 00:34:07 (GMT)
committerJose Rivera <German.Rivera@freescale.com>2014-03-24 16:08:48 (GMT)
commit51e4af86b989140b99c22e21c6b8d4a6bd747f9f (patch)
treef2bde4010712e4496bb59fd149f65233c3c73941 /drivers/crypto/caam/ctrl.c
parent98169a417ed211ebabd4af3cc8d457039caa280d (diff)
downloadlinux-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.c226
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,