1172 lines · 31.9 KB · C
RawDownload
// 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_CRYPTO_DEV_FSL_CAAM_CRYPTO_API_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 1172.