Skip to content

Commit

Permalink
crypto: caam - add power management support
Browse files Browse the repository at this point in the history
Add support for suspend and resume operation for PM in CAAM driver.

When the CAAM goes in suspend, the hardware is considered to do nothing.

On some platforms, the power of the CAAM is not turned off so it keeps
its configuration.
On other platforms, it doesn't so it is necessary to save the state of
the CAAM:
 - JRs MID
 - Address of input and output rings

Signed-off-by: Horia Geanta <[email protected]>
Signed-off-by: Victoria Milhoan <[email protected]>
Signed-off-by: Dan Douglass <[email protected]>
Signed-off-by: Vipul Kumar <[email protected]>
Signed-off-by: Franck LENORMAND <[email protected]>
Signed-off-by: Meenakshi Aggarwal <[email protected]>
Reviewed-by: Gaurav Jain <[email protected]>
Signed-off-by: Herbert Xu <[email protected]>
  • Loading branch information
horiag authored and herbertx committed Aug 4, 2023
1 parent 9a6913f commit 322d747
Show file tree
Hide file tree
Showing 4 changed files with 306 additions and 21 deletions.
106 changes: 106 additions & 0 deletions drivers/crypto/caam/ctrl.c
Original file line number Diff line number Diff line change
Expand Up @@ -740,6 +740,109 @@ static int caam_ctrl_rng_init(struct device *dev)
return 0;
}

/* Indicate if the internal state of the CAAM is lost during PM */
static int caam_off_during_pm(void)
{
bool not_off_during_pm = of_machine_is_compatible("fsl,imx6q") ||
of_machine_is_compatible("fsl,imx6qp") ||
of_machine_is_compatible("fsl,imx6dl");

return not_off_during_pm ? 0 : 1;
}

static void caam_state_save(struct device *dev)
{
struct caam_drv_private *ctrlpriv = dev_get_drvdata(dev);
struct caam_ctl_state *state = &ctrlpriv->state;
struct caam_ctrl __iomem *ctrl = ctrlpriv->ctrl;
u32 deco_inst, jr_inst;
int i;

state->mcr = rd_reg32(&ctrl->mcr);
state->scfgr = rd_reg32(&ctrl->scfgr);

deco_inst = (rd_reg32(&ctrl->perfmon.cha_num_ms) &
CHA_ID_MS_DECO_MASK) >> CHA_ID_MS_DECO_SHIFT;
for (i = 0; i < deco_inst; i++) {
state->deco_mid[i].liodn_ms =
rd_reg32(&ctrl->deco_mid[i].liodn_ms);
state->deco_mid[i].liodn_ls =
rd_reg32(&ctrl->deco_mid[i].liodn_ls);
}

jr_inst = (rd_reg32(&ctrl->perfmon.cha_num_ms) &
CHA_ID_MS_JR_MASK) >> CHA_ID_MS_JR_SHIFT;
for (i = 0; i < jr_inst; i++) {
state->jr_mid[i].liodn_ms =
rd_reg32(&ctrl->jr_mid[i].liodn_ms);
state->jr_mid[i].liodn_ls =
rd_reg32(&ctrl->jr_mid[i].liodn_ls);
}
}

static void caam_state_restore(const struct device *dev)
{
const struct caam_drv_private *ctrlpriv = dev_get_drvdata(dev);
const struct caam_ctl_state *state = &ctrlpriv->state;
struct caam_ctrl __iomem *ctrl = ctrlpriv->ctrl;
u32 deco_inst, jr_inst;
int i;

wr_reg32(&ctrl->mcr, state->mcr);
wr_reg32(&ctrl->scfgr, state->scfgr);

deco_inst = (rd_reg32(&ctrl->perfmon.cha_num_ms) &
CHA_ID_MS_DECO_MASK) >> CHA_ID_MS_DECO_SHIFT;
for (i = 0; i < deco_inst; i++) {
wr_reg32(&ctrl->deco_mid[i].liodn_ms,
state->deco_mid[i].liodn_ms);
wr_reg32(&ctrl->deco_mid[i].liodn_ls,
state->deco_mid[i].liodn_ls);
}

jr_inst = (rd_reg32(&ctrl->perfmon.cha_num_ms) &
CHA_ID_MS_JR_MASK) >> CHA_ID_MS_JR_SHIFT;
for (i = 0; i < jr_inst; i++) {
wr_reg32(&ctrl->jr_mid[i].liodn_ms,
state->jr_mid[i].liodn_ms);
wr_reg32(&ctrl->jr_mid[i].liodn_ls,
state->jr_mid[i].liodn_ls);
}

if (ctrlpriv->virt_en == 1)
clrsetbits_32(&ctrl->jrstart, 0, JRSTART_JR0_START |
JRSTART_JR1_START | JRSTART_JR2_START |
JRSTART_JR3_START);
}

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->optee_en)
caam_state_save(dev);

return 0;
}

static int caam_ctrl_resume(struct device *dev)
{
struct caam_drv_private *ctrlpriv = dev_get_drvdata(dev);
int ret = 0;

if (ctrlpriv->caam_off_during_pm && !ctrlpriv->optee_en) {
caam_state_restore(dev);

/* HW and rng will be reset so deinstantiation can be removed */
devm_remove_action(dev, devm_deinstantiate_rng, dev);
ret = caam_ctrl_rng_init(dev);
}

return ret;
}

static SIMPLE_DEV_PM_OPS(caam_ctrl_pm_ops, caam_ctrl_suspend, caam_ctrl_resume);

/* Probe routine for CAAM top (controller) level */
static int caam_probe(struct platform_device *pdev)
{
Expand Down Expand Up @@ -771,6 +874,8 @@ static int caam_probe(struct platform_device *pdev)

caam_imx = (bool)imx_soc_match;

ctrlpriv->caam_off_during_pm = caam_imx && caam_off_during_pm();

if (imx_soc_match) {
/*
* Until Layerscape and i.MX OP-TEE get in sync,
Expand Down Expand Up @@ -1033,6 +1138,7 @@ static struct platform_driver caam_driver = {
.driver = {
.name = "caam",
.of_match_table = caam_match,
.pm = &caam_ctrl_pm_ops,
},
.probe = caam_probe,
};
Expand Down
25 changes: 24 additions & 1 deletion drivers/crypto/caam/intern.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
* Private/internal definitions between modules
*
* Copyright 2008-2011 Freescale Semiconductor, Inc.
* Copyright 2019 NXP
* Copyright 2019, 2023 NXP
*/

#ifndef INTERN_H
Expand Down Expand Up @@ -47,13 +47,24 @@ struct caam_jrentry_info {
u32 desc_size; /* Stored size for postprocessing, header derived */
};

struct caam_jr_state {
dma_addr_t inpbusaddr;
dma_addr_t outbusaddr;
};

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 */
struct device *dev;
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 */
bool hwrng;

Expand All @@ -71,6 +82,15 @@ struct caam_drv_private_jr {
int tail; /* entinfo (s/w ring) tail index */
void *outring; /* Base of output ring, DMA-safe */
struct crypto_engine *engine;

struct caam_jr_state state; /* State of the JR during PM */
};

struct caam_ctl_state {
struct masterid deco_mid[16];
struct masterid jr_mid[4];
u32 mcr;
u32 scfgr;
};

/*
Expand Down Expand Up @@ -116,6 +136,9 @@ struct caam_drv_private {
struct dentry *ctl; /* controller dir */
struct debugfs_blob_wrapper ctl_kek_wrap, ctl_tkek_wrap, ctl_tdsk_wrap;
#endif

int caam_off_during_pm; /* If the CAAM is reset after suspend */
struct caam_ctl_state state; /* State of the CTL during PM */
};

#ifdef CONFIG_CRYPTO_DEV_FSL_CAAM_CRYPTO_API
Expand Down
Loading

0 comments on commit 322d747

Please sign in to comment.