// SPDX-License-Identifier: GPL-2.0+/* * CAAM control-plane driver backend * Controller-level driver, kernel property detection, initialization * * Copyright 2008-2012 Freescale Semiconductor, Inc. * Copyright 2018-2019, 2023 NXP */ #include <linux/device.h>#include <linux/of_address.h>#include <linux/of_irq.h>#include <linux/platform_device.h>#include <linux/sys_soc.h>#include <linux/fsl/mc.h> #include "compat.h"#include "debugfs.h"#include "regs.h"#include "intern.h"#include "jr.h"#include "desc_constr.h"#include "ctrl.h" bool caam_dpaa2;EXPORT_SYMBOL(caam_dpaa2); #ifdef CONFIG_CAAM_QI#include "qi.h"#endif /* * Descriptor to instantiate RNG State Handle 0 in normal mode and * load the JDKEK, TDKEK and TDSK registers */static void build_instantiation_desc(u32 *desc, int handle, int do_sk){ u32 *jump_cmd, op_flags; init_job_desc(desc, 0); op_flags = OP_TYPE_CLASS1_ALG | OP_ALG_ALGSEL_RNG | (handle << OP_ALG_AAI_SHIFT) | OP_ALG_AS_INIT | OP_ALG_PR_ON; /* INIT RNG in non-test mode */ append_operation(desc, op_flags); if (!handle && do_sk) { /* * For SH0, Secure Keys must be generated as well */ /* wait for done */ jump_cmd = append_jump(desc, JUMP_CLASS_CLASS1); set_jump_tgt_here(desc, jump_cmd); /* * load 1 to clear written reg: * resets the done interrupt and returns the RNG to idle. */ append_load_imm_u32(desc, 1, LDST_SRCDST_WORD_CLRW); /* Initialize State Handle */ append_operation(desc, OP_TYPE_CLASS1_ALG | OP_ALG_ALGSEL_RNG | OP_ALG_AAI_RNG4_SK); } append_jump(desc, JUMP_CLASS_CLASS1 | JUMP_TYPE_HALT);} /* Descriptor for deinstantiation of State Handle 0 of the RNG block. */static void build_deinstantiation_desc(u32 *desc, int handle){ init_job_desc(desc, 0); /* Uninstantiate State Handle 0 */ append_operation(desc, OP_TYPE_CLASS1_ALG | OP_ALG_ALGSEL_RNG | (handle << OP_ALG_AAI_SHIFT) | OP_ALG_AS_INITFINAL); append_jump(desc, JUMP_CLASS_CLASS1 | JUMP_TYPE_HALT);} #ifdef CONFIG_OFstatic const struct of_device_id imx8m_machine_match[] = { { .compatible = "fsl,imx8mm", }, { .compatible = "fsl,imx8mn", }, { .compatible = "fsl,imx8mp", }, { .compatible = "fsl,imx8mq", }, { .compatible = "fsl,imx8ulp", }, { }};#endif /* * run_descriptor_deco0 - runs a descriptor on DECO0, under direct control of * the software (no JR/QI used). * @ctrldev - pointer to device * @status - descriptor status, after being run * * Return: - 0 if no error occurred * - -ENODEV if the DECO couldn't be acquired * - -EAGAIN if an error occurred while executing the descriptor */static inline int run_descriptor_deco0(struct device *ctrldev, u32 *desc, u32 *status){ struct caam_drv_private *ctrlpriv = dev_get_drvdata(ctrldev); struct caam_ctrl __iomem *ctrl = ctrlpriv->ctrl; struct caam_deco __iomem *deco = ctrlpriv->deco; unsigned int timeout = 100000; u32 deco_dbg_reg, deco_state, flags; int i; if (ctrlpriv->virt_en == 1 || /* * Apparently on i.MX8M{Q,M,N,P} it doesn't matter if virt_en == 1 * and the following steps should be performed regardless */ of_match_node(imx8m_machine_match, of_root)) { clrsetbits_32(&ctrl->deco_rsr, 0, DECORSR_JR0); while (!(rd_reg32(&ctrl->deco_rsr) & DECORSR_VALID) && --timeout) cpu_relax(); timeout = 100000; } clrsetbits_32(&ctrl->deco_rq, 0, DECORR_RQD0ENABLE); while (!(rd_reg32(&ctrl->deco_rq) & DECORR_DEN0) && --timeout) cpu_relax(); if (!timeout) { dev_err(ctrldev, "failed to acquire DECO 0\n"); clrsetbits_32(&ctrl->deco_rq, DECORR_RQD0ENABLE, 0); return -ENODEV; } for (i = 0; i < desc_len(desc); i++) wr_reg32(&deco->descbuf[i], caam32_to_cpu(*(desc + i))); flags = DECO_JQCR_WHL; /* * If the descriptor length is longer than 4 words, then the * FOUR bit in JRCTRL register must be set. */ if (desc_len(desc) >= 4) flags |= DECO_JQCR_FOUR; /* Instruct the DECO to execute it */ clrsetbits_32(&deco->jr_ctl_hi, 0, flags); timeout = 10000000; do { deco_dbg_reg = rd_reg32(&deco->desc_dbg); if (ctrlpriv->era < 10) deco_state = (deco_dbg_reg & DESC_DBG_DECO_STAT_MASK) >> DESC_DBG_DECO_STAT_SHIFT; else deco_state = (rd_reg32(&deco->dbg_exec) & DESC_DER_DECO_STAT_MASK) >> DESC_DER_DECO_STAT_SHIFT; /* * If an error occurred in the descriptor, then * the DECO status field will be set to 0x0D */ if (deco_state == DECO_STAT_HOST_ERR) break; cpu_relax(); } while ((deco_dbg_reg & DESC_DBG_DECO_STAT_VALID) && --timeout); *status = rd_reg32(&deco->op_status_hi) & DECO_OP_STATUS_HI_ERR_MASK; if (ctrlpriv->virt_en == 1) clrsetbits_32(&ctrl->deco_rsr, DECORSR_JR0, 0); /* Mark the DECO as free */ clrsetbits_32(&ctrl->deco_rq, DECORR_RQD0ENABLE, 0); if (!timeout) return -EAGAIN; return 0;} /* * deinstantiate_rng - builds and executes a descriptor on DECO0, * which deinitializes the RNG block. * @ctrldev - pointer to device * @state_handle_mask - bitmask containing the instantiation status * for the RNG4 state handles which exist in * the RNG4 block: 1 if it's been instantiated * * Return: - 0 if no error occurred * - -ENOMEM if there isn't enough memory to allocate the descriptor * - -ENODEV if DECO0 couldn't be acquired * - -EAGAIN if an error occurred when executing the descriptor */static int deinstantiate_rng(struct device *ctrldev, int state_handle_mask){ u32 *desc, status; int sh_idx, ret = 0; desc = kmalloc(CAAM_CMD_SZ * 3, GFP_KERNEL); if (!desc) return -ENOMEM; for (sh_idx = 0; sh_idx < RNG4_MAX_HANDLES; sh_idx++) { /* * If the corresponding bit is set, then it means the state * handle was initialized by us, and thus it needs to be * deinitialized as well */ if ((1 << sh_idx) & state_handle_mask) { /* * Create the descriptor for deinstantating this state * handle */ build_deinstantiation_desc(desc, sh_idx); /* Try to run it through DECO0 */ ret = run_descriptor_deco0(ctrldev, desc, &status); if (ret || (status && status != JRSTA_SSRC_JUMP_HALT_CC)) { dev_err(ctrldev, "Failed to deinstantiate RNG4 SH%d\n", sh_idx); break; } dev_info(ctrldev, "Deinstantiated RNG4 SH%d\n", sh_idx); } } kfree(desc); return ret;} static void devm_deinstantiate_rng(void *data){ struct device *ctrldev = data; struct caam_drv_private *ctrlpriv = dev_get_drvdata(ctrldev); /* * De-initialize RNG state handles initialized by this driver. * In case of SoCs with Management Complex, RNG is managed by MC f/w. */ if (ctrlpriv->rng4_sh_init) deinstantiate_rng(ctrldev, ctrlpriv->rng4_sh_init);} /* * instantiate_rng - builds and executes a descriptor on DECO0, * which initializes the RNG block. * @ctrldev - pointer to device * @state_handle_mask - bitmask containing the instantiation status * for the RNG4 state handles which exist in * the RNG4 block: 1 if it's been instantiated * by an external entry, 0 otherwise. * @gen_sk - generate data to be loaded into the JDKEK, TDKEK and TDSK; * Caution: this can be done only once; if the keys need to be * regenerated, a POR is required * * Return: - 0 if no error occurred * - -ENOMEM if there isn't enough memory to allocate the descriptor * - -ENODEV if DECO0 couldn't be acquired * - -EAGAIN if an error occurred when executing the descriptor * f.i. there was a RNG hardware error due to not "good enough" * entropy being acquired. */static int instantiate_rng(struct device *ctrldev, int state_handle_mask, int gen_sk){ struct caam_drv_private *ctrlpriv = dev_get_drvdata(ctrldev); struct caam_ctrl __iomem *ctrl; u32 *desc, status = 0, rdsta_val; int ret = 0, sh_idx; ctrl = (struct caam_ctrl __iomem *)ctrlpriv->ctrl; desc = kmalloc(CAAM_CMD_SZ * 7, GFP_KERNEL); if (!desc) return -ENOMEM; for (sh_idx = 0; sh_idx < RNG4_MAX_HANDLES; sh_idx++) { const u32 rdsta_if = RDSTA_IF0 << sh_idx; const u32 rdsta_pr = RDSTA_PR0 << sh_idx; const u32 rdsta_mask = rdsta_if | rdsta_pr; /* Clear the contents before using the descriptor */ memset(desc, 0x00, CAAM_CMD_SZ * 7); /* * If the corresponding bit is set, this state handle * was initialized by somebody else, so it's left alone. */ if (rdsta_if & state_handle_mask) { if (rdsta_pr & state_handle_mask) continue; dev_info(ctrldev, "RNG4 SH%d was previously instantiated without prediction resistance. Tearing it down\n", sh_idx); ret = deinstantiate_rng(ctrldev, rdsta_if); if (ret) break; } /* Create the descriptor for instantiating RNG State Handle */ build_instantiation_desc(desc, sh_idx, gen_sk); /* Try to run it through DECO0 */ ret = run_descriptor_deco0(ctrldev, desc, &status); /* * If ret is not 0, or descriptor status is not 0, then * something went wrong. No need to try the next state * handle (if available), bail out here. * Also, if for some reason, the State Handle didn't get * instantiated although the descriptor has finished * without any error (HW optimizations for later * CAAM eras), then try again. */ if (ret) break; rdsta_val = rd_reg32(&ctrl->r4tst[0].rdsta) & RDSTA_MASK; if ((status && status != JRSTA_SSRC_JUMP_HALT_CC) || (rdsta_val & rdsta_mask) != rdsta_mask) { ret = -EAGAIN; break; } dev_info(ctrldev, "Instantiated RNG4 SH%d\n", sh_idx); } kfree(desc); if (ret) return ret; return devm_add_action_or_reset(ctrldev, devm_deinstantiate_rng, ctrldev);} /* * kick_trng - sets the various parameters for enabling the initialization * of the RNG4 block in CAAM * @dev - pointer to the controller device * @ent_delay - Defines the length (in system clocks) of each entropy sample. */static void kick_trng(struct device *dev, int ent_delay){ struct caam_drv_private *ctrlpriv = dev_get_drvdata(dev); struct caam_ctrl __iomem *ctrl; struct rng4tst __iomem *r4tst; u32 val, rtsdctl; ctrl = (struct caam_ctrl __iomem *)ctrlpriv->ctrl; r4tst = &ctrl->r4tst[0]; /* * Setting both RTMCTL:PRGM and RTMCTL:TRNG_ACC causes TRNG to * properly invalidate the entropy in the entropy register and * force re-generation. */ clrsetbits_32(&r4tst->rtmctl, 0, RTMCTL_PRGM | RTMCTL_ACC); /* * Performance-wise, it does not make sense to * set the delay to a value that is lower * than the last one that worked (i.e. the state handles * were instantiated properly). */ rtsdctl = rd_reg32(&r4tst->rtsdctl); val = (rtsdctl & RTSDCTL_ENT_DLY_MASK) >> RTSDCTL_ENT_DLY_SHIFT; if (ent_delay > val) { val = ent_delay; /* min. freq. count, equal to 1/4 of the entropy sample length */ wr_reg32(&r4tst->rtfrqmin, val >> 2); /* disable maximum frequency count */ wr_reg32(&r4tst->rtfrqmax, RTFRQMAX_DISABLE); } wr_reg32(&r4tst->rtsdctl, (val << RTSDCTL_ENT_DLY_SHIFT) | RTSDCTL_SAMP_SIZE_VAL); /* * To avoid reprogramming the self-test parameters over and over again, * use RTSDCTL[SAMP_SIZE] as an indicator. */ if ((rtsdctl & RTSDCTL_SAMP_SIZE_MASK) != RTSDCTL_SAMP_SIZE_VAL) { wr_reg32(&r4tst->rtscmisc, (2 << 16) | 32); wr_reg32(&r4tst->rtpkrrng, 570); wr_reg32(&r4tst->rtpkrmax, 1600); wr_reg32(&r4tst->rtscml, (122 << 16) | 317); wr_reg32(&r4tst->rtscrl[0], (80 << 16) | 107); wr_reg32(&r4tst->rtscrl[1], (57 << 16) | 62); wr_reg32(&r4tst->rtscrl[2], (39 << 16) | 39); wr_reg32(&r4tst->rtscrl[3], (27 << 16) | 26); wr_reg32(&r4tst->rtscrl[4], (19 << 16) | 18); wr_reg32(&r4tst->rtscrl[5], (18 << 16) | 17); } /* * select raw sampling in both entropy shifter * and statistical checker; ; put RNG4 into run mode */ clrsetbits_32(&r4tst->rtmctl, RTMCTL_PRGM | RTMCTL_ACC, RTMCTL_SAMP_MODE_RAW_ES_SC);} static int caam_get_era_from_hw(struct caam_perfmon __iomem *perfmon){ static const struct { u16 ip_id; u8 maj_rev; u8 era; } id[] = { {0x0A10, 1, 1}, {0x0A10, 2, 2}, {0x0A12, 1, 3}, {0x0A14, 1, 3}, {0x0A14, 2, 4}, {0x0A16, 1, 4}, {0x0A10, 3, 4}, {0x0A11, 1, 4}, {0x0A18, 1, 4}, {0x0A11, 2, 5}, {0x0A12, 2, 5}, {0x0A13, 1, 5}, {0x0A1C, 1, 5} }; u32 ccbvid, id_ms; u8 maj_rev, era; u16 ip_id; int i; ccbvid = rd_reg32(&perfmon->ccb_id); era = (ccbvid & CCBVID_ERA_MASK) >> CCBVID_ERA_SHIFT; if (era) /* This is '0' prior to CAAM ERA-6 */ return era; id_ms = rd_reg32(&perfmon->caam_id_ms); ip_id = (id_ms & SECVID_MS_IPID_MASK) >> SECVID_MS_IPID_SHIFT; maj_rev = (id_ms & SECVID_MS_MAJ_REV_MASK) >> SECVID_MS_MAJ_REV_SHIFT; for (i = 0; i < ARRAY_SIZE(id); i++) if (id[i].ip_id == ip_id && id[i].maj_rev == maj_rev) return id[i].era; return -ENOTSUPP;} /** * caam_get_era() - Return the ERA of the SEC on SoC, based * on "sec-era" optional property in the DTS. This property is updated * by u-boot. * In case this property is not passed an attempt to retrieve the CAAM * era via register reads will be made. * * @perfmon: Performance Monitor Registers */static int caam_get_era(struct caam_perfmon __iomem *perfmon){ struct device_node *caam_node; int ret; u32 prop; caam_node = of_find_compatible_node(NULL, NULL, "fsl,sec-v4.0"); ret = of_property_read_u32(caam_node, "fsl,sec-era", &prop); of_node_put(caam_node); if (!ret) return prop; else return caam_get_era_from_hw(perfmon);} /* * ERRATA: imx6 devices (imx6D, imx6Q, imx6DL, imx6S, imx6DP and imx6QP) * have an issue wherein AXI bus transactions may not occur in the correct * order. This isn't a problem running single descriptors, but can be if * running multiple concurrent descriptors. Reworking the driver to throttle * to single requests is impractical, thus the workaround is to limit the AXI * pipeline to a depth of 1 (from it's default of 4) to preclude this situation * from occurring. */static void handle_imx6_err005766(u32 __iomem *mcr){ if (of_machine_is_compatible("fsl,imx6q") || of_machine_is_compatible("fsl,imx6dl") || of_machine_is_compatible("fsl,imx6qp"))Lines 1–500 of 1170. Load more
// SPDX-License-Identifier: GPL-2.0+ /* * CAAM control-plane driver backend * Controller-level driver, kernel property detection, initialization * * Copyright 2008-2012 Freescale Semiconductor, Inc. * Copyright 2018-2019, 2023 NXP */ #include <linux/device.h> #include <linux/of_address.h> #include <linux/of_irq.h> #include <linux/platform_device.h> #include <linux/sys_soc.h> #include <linux/fsl/mc.h> #include "compat.h" #include "debugfs.h" #include "regs.h" #include "intern.h" #include "jr.h" #include "desc_constr.h" #include "ctrl.h" bool caam_dpaa2; EXPORT_SYMBOL(caam_dpaa2); #ifdef CONFIG_CAAM_QI #include "qi.h" #endif /* * Descriptor to instantiate RNG State Handle 0 in normal mode and * load the JDKEK, TDKEK and TDSK registers */ static void build_instantiation_desc(u32 *desc, int handle, int do_sk) { u32 *jump_cmd, op_flags; init_job_desc(desc, 0); op_flags = OP_TYPE_CLASS1_ALG | OP_ALG_ALGSEL_RNG | (handle << OP_ALG_AAI_SHIFT) | OP_ALG_AS_INIT | OP_ALG_PR_ON; /* INIT RNG in non-test mode */ append_operation(desc, op_flags); if (!handle && do_sk) { /* * For SH0, Secure Keys must be generated as well */ /* wait for done */ jump_cmd = append_jump(desc, JUMP_CLASS_CLASS1); set_jump_tgt_here(desc, jump_cmd); /* * load 1 to clear written reg: * resets the done interrupt and returns the RNG to idle. */ append_load_imm_u32(desc, 1, LDST_SRCDST_WORD_CLRW); /* Initialize State Handle */ append_operation(desc, OP_TYPE_CLASS1_ALG | OP_ALG_ALGSEL_RNG | OP_ALG_AAI_RNG4_SK); } append_jump(desc, JUMP_CLASS_CLASS1 | JUMP_TYPE_HALT); } /* Descriptor for deinstantiation of State Handle 0 of the RNG block. */ static void build_deinstantiation_desc(u32 *desc, int handle) { init_job_desc(desc, 0); /* Uninstantiate State Handle 0 */ append_operation(desc, OP_TYPE_CLASS1_ALG | OP_ALG_ALGSEL_RNG | (handle << OP_ALG_AAI_SHIFT) | OP_ALG_AS_INITFINAL); append_jump(desc, JUMP_CLASS_CLASS1 | JUMP_TYPE_HALT); } #ifdef CONFIG_OF static const struct of_device_id imx8m_machine_match[] = { { .compatible = "fsl,imx8mm", }, { .compatible = "fsl,imx8mn", }, { .compatible = "fsl,imx8mp", }, { .compatible = "fsl,imx8mq", }, { .compatible = "fsl,imx8ulp", }, { } }; #endif /* * run_descriptor_deco0 - runs a descriptor on DECO0, under direct control of * the software (no JR/QI used). * @ctrldev - pointer to device * @status - descriptor status, after being run * * Return: - 0 if no error occurred * - -ENODEV if the DECO couldn't be acquired * - -EAGAIN if an error occurred while executing the descriptor */ static inline int run_descriptor_deco0(struct device *ctrldev, u32 *desc, u32 *status) { struct caam_drv_private *ctrlpriv = dev_get_drvdata(ctrldev); struct caam_ctrl __iomem *ctrl = ctrlpriv->ctrl; struct caam_deco __iomem *deco = ctrlpriv->deco; unsigned int timeout = 100000; u32 deco_dbg_reg, deco_state, flags; int i; if (ctrlpriv->virt_en == 1 || /* * Apparently on i.MX8M{Q,M,N,P} it doesn't matter if virt_en == 1 * and the following steps should be performed regardless */ of_match_node(imx8m_machine_match, of_root)) { clrsetbits_32(&ctrl->deco_rsr, 0, DECORSR_JR0); while (!(rd_reg32(&ctrl->deco_rsr) & DECORSR_VALID) && --timeout) cpu_relax(); timeout = 100000; } clrsetbits_32(&ctrl->deco_rq, 0, DECORR_RQD0ENABLE); while (!(rd_reg32(&ctrl->deco_rq) & DECORR_DEN0) && --timeout) cpu_relax(); if (!timeout) { dev_err(ctrldev, "failed to acquire DECO 0\n"); clrsetbits_32(&ctrl->deco_rq, DECORR_RQD0ENABLE, 0); return -ENODEV; } for (i = 0; i < desc_len(desc); i++) wr_reg32(&deco->descbuf[i], caam32_to_cpu(*(desc + i))); flags = DECO_JQCR_WHL; /* * If the descriptor length is longer than 4 words, then the * FOUR bit in JRCTRL register must be set. */ if (desc_len(desc) >= 4) flags |= DECO_JQCR_FOUR; /* Instruct the DECO to execute it */ clrsetbits_32(&deco->jr_ctl_hi, 0, flags); timeout = 10000000; do { deco_dbg_reg = rd_reg32(&deco->desc_dbg); if (ctrlpriv->era < 10) deco_state = (deco_dbg_reg & DESC_DBG_DECO_STAT_MASK) >> DESC_DBG_DECO_STAT_SHIFT; else deco_state = (rd_reg32(&deco->dbg_exec) & DESC_DER_DECO_STAT_MASK) >> DESC_DER_DECO_STAT_SHIFT; /* * If an error occurred in the descriptor, then * the DECO status field will be set to 0x0D */ if (deco_state == DECO_STAT_HOST_ERR) break; cpu_relax(); } while ((deco_dbg_reg & DESC_DBG_DECO_STAT_VALID) && --timeout); *status = rd_reg32(&deco->op_status_hi) & DECO_OP_STATUS_HI_ERR_MASK; if (ctrlpriv->virt_en == 1) clrsetbits_32(&ctrl->deco_rsr, DECORSR_JR0, 0); /* Mark the DECO as free */ clrsetbits_32(&ctrl->deco_rq, DECORR_RQD0ENABLE, 0); if (!timeout) return -EAGAIN; return 0; } /* * deinstantiate_rng - builds and executes a descriptor on DECO0, * which deinitializes the RNG block. * @ctrldev - pointer to device * @state_handle_mask - bitmask containing the instantiation status * for the RNG4 state handles which exist in * the RNG4 block: 1 if it's been instantiated * * Return: - 0 if no error occurred * - -ENOMEM if there isn't enough memory to allocate the descriptor * - -ENODEV if DECO0 couldn't be acquired * - -EAGAIN if an error occurred when executing the descriptor */ static int deinstantiate_rng(struct device *ctrldev, int state_handle_mask) { u32 *desc, status; int sh_idx, ret = 0; desc = kmalloc(CAAM_CMD_SZ * 3, GFP_KERNEL); if (!desc) return -ENOMEM; for (sh_idx = 0; sh_idx < RNG4_MAX_HANDLES; sh_idx++) { /* * If the corresponding bit is set, then it means the state * handle was initialized by us, and thus it needs to be * deinitialized as well */ if ((1 << sh_idx) & state_handle_mask) { /* * Create the descriptor for deinstantating this state * handle */ build_deinstantiation_desc(desc, sh_idx); /* Try to run it through DECO0 */ ret = run_descriptor_deco0(ctrldev, desc, &status); if (ret || (status && status != JRSTA_SSRC_JUMP_HALT_CC)) { dev_err(ctrldev, "Failed to deinstantiate RNG4 SH%d\n", sh_idx); break; } dev_info(ctrldev, "Deinstantiated RNG4 SH%d\n", sh_idx); } } kfree(desc); return ret; } static void devm_deinstantiate_rng(void *data) { struct device *ctrldev = data; struct caam_drv_private *ctrlpriv = dev_get_drvdata(ctrldev); /* * De-initialize RNG state handles initialized by this driver. * In case of SoCs with Management Complex, RNG is managed by MC f/w. */ if (ctrlpriv->rng4_sh_init) deinstantiate_rng(ctrldev, ctrlpriv->rng4_sh_init); } /* * instantiate_rng - builds and executes a descriptor on DECO0, * which initializes the RNG block. * @ctrldev - pointer to device * @state_handle_mask - bitmask containing the instantiation status * for the RNG4 state handles which exist in * the RNG4 block: 1 if it's been instantiated * by an external entry, 0 otherwise. * @gen_sk - generate data to be loaded into the JDKEK, TDKEK and TDSK; * Caution: this can be done only once; if the keys need to be * regenerated, a POR is required * * Return: - 0 if no error occurred * - -ENOMEM if there isn't enough memory to allocate the descriptor * - -ENODEV if DECO0 couldn't be acquired * - -EAGAIN if an error occurred when executing the descriptor * f.i. there was a RNG hardware error due to not "good enough" * entropy being acquired. */ static int instantiate_rng(struct device *ctrldev, int state_handle_mask, int gen_sk) { struct caam_drv_private *ctrlpriv = dev_get_drvdata(ctrldev); struct caam_ctrl __iomem *ctrl; u32 *desc, status = 0, rdsta_val; int ret = 0, sh_idx; ctrl = (struct caam_ctrl __iomem *)ctrlpriv->ctrl; desc = kmalloc(CAAM_CMD_SZ * 7, GFP_KERNEL); if (!desc) return -ENOMEM; for (sh_idx = 0; sh_idx < RNG4_MAX_HANDLES; sh_idx++) { const u32 rdsta_if = RDSTA_IF0 << sh_idx; const u32 rdsta_pr = RDSTA_PR0 << sh_idx; const u32 rdsta_mask = rdsta_if | rdsta_pr; /* Clear the contents before using the descriptor */ memset(desc, 0x00, CAAM_CMD_SZ * 7); /* * If the corresponding bit is set, this state handle * was initialized by somebody else, so it's left alone. */ if (rdsta_if & state_handle_mask) { if (rdsta_pr & state_handle_mask) continue; dev_info(ctrldev, "RNG4 SH%d was previously instantiated without prediction resistance. Tearing it down\n", sh_idx); ret = deinstantiate_rng(ctrldev, rdsta_if); if (ret) break; } /* Create the descriptor for instantiating RNG State Handle */ build_instantiation_desc(desc, sh_idx, gen_sk); /* Try to run it through DECO0 */ ret = run_descriptor_deco0(ctrldev, desc, &status); /* * If ret is not 0, or descriptor status is not 0, then * something went wrong. No need to try the next state * handle (if available), bail out here. * Also, if for some reason, the State Handle didn't get * instantiated although the descriptor has finished * without any error (HW optimizations for later * CAAM eras), then try again. */ if (ret) break; rdsta_val = rd_reg32(&ctrl->r4tst[0].rdsta) & RDSTA_MASK; if ((status && status != JRSTA_SSRC_JUMP_HALT_CC) || (rdsta_val & rdsta_mask) != rdsta_mask) { ret = -EAGAIN; break; } dev_info(ctrldev, "Instantiated RNG4 SH%d\n", sh_idx); } kfree(desc); if (ret) return ret; return devm_add_action_or_reset(ctrldev, devm_deinstantiate_rng, ctrldev); } /* * kick_trng - sets the various parameters for enabling the initialization * of the RNG4 block in CAAM * @dev - pointer to the controller device * @ent_delay - Defines the length (in system clocks) of each entropy sample. */ static void kick_trng(struct device *dev, int ent_delay) { struct caam_drv_private *ctrlpriv = dev_get_drvdata(dev); struct caam_ctrl __iomem *ctrl; struct rng4tst __iomem *r4tst; u32 val, rtsdctl; ctrl = (struct caam_ctrl __iomem *)ctrlpriv->ctrl; r4tst = &ctrl->r4tst[0]; /* * Setting both RTMCTL:PRGM and RTMCTL:TRNG_ACC causes TRNG to * properly invalidate the entropy in the entropy register and * force re-generation. */ clrsetbits_32(&r4tst->rtmctl, 0, RTMCTL_PRGM | RTMCTL_ACC); /* * Performance-wise, it does not make sense to * set the delay to a value that is lower * than the last one that worked (i.e. the state handles * were instantiated properly). */ rtsdctl = rd_reg32(&r4tst->rtsdctl); val = (rtsdctl & RTSDCTL_ENT_DLY_MASK) >> RTSDCTL_ENT_DLY_SHIFT; if (ent_delay > val) { val = ent_delay; /* min. freq. count, equal to 1/4 of the entropy sample length */ wr_reg32(&r4tst->rtfrqmin, val >> 2); /* disable maximum frequency count */ wr_reg32(&r4tst->rtfrqmax, RTFRQMAX_DISABLE); } wr_reg32(&r4tst->rtsdctl, (val << RTSDCTL_ENT_DLY_SHIFT) | RTSDCTL_SAMP_SIZE_VAL); /* * To avoid reprogramming the self-test parameters over and over again, * use RTSDCTL[SAMP_SIZE] as an indicator. */ if ((rtsdctl & RTSDCTL_SAMP_SIZE_MASK) != RTSDCTL_SAMP_SIZE_VAL) { wr_reg32(&r4tst->rtscmisc, (2 << 16) | 32); wr_reg32(&r4tst->rtpkrrng, 570); wr_reg32(&r4tst->rtpkrmax, 1600); wr_reg32(&r4tst->rtscml, (122 << 16) | 317); wr_reg32(&r4tst->rtscrl[0], (80 << 16) | 107); wr_reg32(&r4tst->rtscrl[1], (57 << 16) | 62); wr_reg32(&r4tst->rtscrl[2], (39 << 16) | 39); wr_reg32(&r4tst->rtscrl[3], (27 << 16) | 26); wr_reg32(&r4tst->rtscrl[4], (19 << 16) | 18); wr_reg32(&r4tst->rtscrl[5], (18 << 16) | 17); } /* * select raw sampling in both entropy shifter * and statistical checker; ; put RNG4 into run mode */ clrsetbits_32(&r4tst->rtmctl, RTMCTL_PRGM | RTMCTL_ACC, RTMCTL_SAMP_MODE_RAW_ES_SC); } static int caam_get_era_from_hw(struct caam_perfmon __iomem *perfmon) { static const struct { u16 ip_id; u8 maj_rev; u8 era; } id[] = { {0x0A10, 1, 1}, {0x0A10, 2, 2}, {0x0A12, 1, 3}, {0x0A14, 1, 3}, {0x0A14, 2, 4}, {0x0A16, 1, 4}, {0x0A10, 3, 4}, {0x0A11, 1, 4}, {0x0A18, 1, 4}, {0x0A11, 2, 5}, {0x0A12, 2, 5}, {0x0A13, 1, 5}, {0x0A1C, 1, 5} }; u32 ccbvid, id_ms; u8 maj_rev, era; u16 ip_id; int i; ccbvid = rd_reg32(&perfmon->ccb_id); era = (ccbvid & CCBVID_ERA_MASK) >> CCBVID_ERA_SHIFT; if (era) /* This is '0' prior to CAAM ERA-6 */ return era; id_ms = rd_reg32(&perfmon->caam_id_ms); ip_id = (id_ms & SECVID_MS_IPID_MASK) >> SECVID_MS_IPID_SHIFT; maj_rev = (id_ms & SECVID_MS_MAJ_REV_MASK) >> SECVID_MS_MAJ_REV_SHIFT; for (i = 0; i < ARRAY_SIZE(id); i++) if (id[i].ip_id == ip_id && id[i].maj_rev == maj_rev) return id[i].era; return -ENOTSUPP; } /** * caam_get_era() - Return the ERA of the SEC on SoC, based * on "sec-era" optional property in the DTS. This property is updated * by u-boot. * In case this property is not passed an attempt to retrieve the CAAM * era via register reads will be made. * * @perfmon: Performance Monitor Registers */ static int caam_get_era(struct caam_perfmon __iomem *perfmon) { struct device_node *caam_node; int ret; u32 prop; caam_node = of_find_compatible_node(NULL, NULL, "fsl,sec-v4.0"); ret = of_property_read_u32(caam_node, "fsl,sec-era", &prop); of_node_put(caam_node); if (!ret) return prop; else return caam_get_era_from_hw(perfmon); } /* * ERRATA: imx6 devices (imx6D, imx6Q, imx6DL, imx6S, imx6DP and imx6QP) * have an issue wherein AXI bus transactions may not occur in the correct * order. This isn't a problem running single descriptors, but can be if * running multiple concurrent descriptors. Reworking the driver to throttle * to single requests is impractical, thus the workaround is to limit the AXI * pipeline to a depth of 1 (from it's default of 4) to preclude this situation * from occurring. */ static void handle_imx6_err005766(u32 __iomem *mcr) { if (of_machine_is_compatible("fsl,imx6q") || of_machine_is_compatible("fsl,imx6dl") || of_machine_is_compatible("fsl,imx6qp"))