summaryrefslogtreecommitdiff
path: root/drivers/crypto/caam/ctrl.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/crypto/caam/ctrl.c')
-rw-r--r--drivers/crypto/caam/ctrl.c177
1 files changed, 153 insertions, 24 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,