162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+ 262306a36Sopenharmony_ci/* * CAAM control-plane driver backend 362306a36Sopenharmony_ci * Controller-level driver, kernel property detection, initialization 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright 2008-2012 Freescale Semiconductor, Inc. 662306a36Sopenharmony_ci * Copyright 2018-2019, 2023 NXP 762306a36Sopenharmony_ci */ 862306a36Sopenharmony_ci 962306a36Sopenharmony_ci#include <linux/device.h> 1062306a36Sopenharmony_ci#include <linux/of_address.h> 1162306a36Sopenharmony_ci#include <linux/of_irq.h> 1262306a36Sopenharmony_ci#include <linux/platform_device.h> 1362306a36Sopenharmony_ci#include <linux/sys_soc.h> 1462306a36Sopenharmony_ci#include <linux/fsl/mc.h> 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_ci#include "compat.h" 1762306a36Sopenharmony_ci#include "debugfs.h" 1862306a36Sopenharmony_ci#include "regs.h" 1962306a36Sopenharmony_ci#include "intern.h" 2062306a36Sopenharmony_ci#include "jr.h" 2162306a36Sopenharmony_ci#include "desc_constr.h" 2262306a36Sopenharmony_ci#include "ctrl.h" 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_cibool caam_dpaa2; 2562306a36Sopenharmony_ciEXPORT_SYMBOL(caam_dpaa2); 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_ci#ifdef CONFIG_CAAM_QI 2862306a36Sopenharmony_ci#include "qi.h" 2962306a36Sopenharmony_ci#endif 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_ci/* 3262306a36Sopenharmony_ci * Descriptor to instantiate RNG State Handle 0 in normal mode and 3362306a36Sopenharmony_ci * load the JDKEK, TDKEK and TDSK registers 3462306a36Sopenharmony_ci */ 3562306a36Sopenharmony_cistatic void build_instantiation_desc(u32 *desc, int handle, int do_sk) 3662306a36Sopenharmony_ci{ 3762306a36Sopenharmony_ci u32 *jump_cmd, op_flags; 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ci init_job_desc(desc, 0); 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ci op_flags = OP_TYPE_CLASS1_ALG | OP_ALG_ALGSEL_RNG | 4262306a36Sopenharmony_ci (handle << OP_ALG_AAI_SHIFT) | OP_ALG_AS_INIT | 4362306a36Sopenharmony_ci OP_ALG_PR_ON; 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_ci /* INIT RNG in non-test mode */ 4662306a36Sopenharmony_ci append_operation(desc, op_flags); 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_ci if (!handle && do_sk) { 4962306a36Sopenharmony_ci /* 5062306a36Sopenharmony_ci * For SH0, Secure Keys must be generated as well 5162306a36Sopenharmony_ci */ 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_ci /* wait for done */ 5462306a36Sopenharmony_ci jump_cmd = append_jump(desc, JUMP_CLASS_CLASS1); 5562306a36Sopenharmony_ci set_jump_tgt_here(desc, jump_cmd); 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_ci /* 5862306a36Sopenharmony_ci * load 1 to clear written reg: 5962306a36Sopenharmony_ci * resets the done interrupt and returns the RNG to idle. 6062306a36Sopenharmony_ci */ 6162306a36Sopenharmony_ci append_load_imm_u32(desc, 1, LDST_SRCDST_WORD_CLRW); 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_ci /* Initialize State Handle */ 6462306a36Sopenharmony_ci append_operation(desc, OP_TYPE_CLASS1_ALG | OP_ALG_ALGSEL_RNG | 6562306a36Sopenharmony_ci OP_ALG_AAI_RNG4_SK); 6662306a36Sopenharmony_ci } 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_ci append_jump(desc, JUMP_CLASS_CLASS1 | JUMP_TYPE_HALT); 6962306a36Sopenharmony_ci} 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_ci/* Descriptor for deinstantiation of State Handle 0 of the RNG block. */ 7262306a36Sopenharmony_cistatic void build_deinstantiation_desc(u32 *desc, int handle) 7362306a36Sopenharmony_ci{ 7462306a36Sopenharmony_ci init_job_desc(desc, 0); 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_ci /* Uninstantiate State Handle 0 */ 7762306a36Sopenharmony_ci append_operation(desc, OP_TYPE_CLASS1_ALG | OP_ALG_ALGSEL_RNG | 7862306a36Sopenharmony_ci (handle << OP_ALG_AAI_SHIFT) | OP_ALG_AS_INITFINAL); 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_ci append_jump(desc, JUMP_CLASS_CLASS1 | JUMP_TYPE_HALT); 8162306a36Sopenharmony_ci} 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_cistatic const struct of_device_id imx8m_machine_match[] = { 8462306a36Sopenharmony_ci { .compatible = "fsl,imx8mm", }, 8562306a36Sopenharmony_ci { .compatible = "fsl,imx8mn", }, 8662306a36Sopenharmony_ci { .compatible = "fsl,imx8mp", }, 8762306a36Sopenharmony_ci { .compatible = "fsl,imx8mq", }, 8862306a36Sopenharmony_ci { .compatible = "fsl,imx8ulp", }, 8962306a36Sopenharmony_ci { } 9062306a36Sopenharmony_ci}; 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ci/* 9362306a36Sopenharmony_ci * run_descriptor_deco0 - runs a descriptor on DECO0, under direct control of 9462306a36Sopenharmony_ci * the software (no JR/QI used). 9562306a36Sopenharmony_ci * @ctrldev - pointer to device 9662306a36Sopenharmony_ci * @status - descriptor status, after being run 9762306a36Sopenharmony_ci * 9862306a36Sopenharmony_ci * Return: - 0 if no error occurred 9962306a36Sopenharmony_ci * - -ENODEV if the DECO couldn't be acquired 10062306a36Sopenharmony_ci * - -EAGAIN if an error occurred while executing the descriptor 10162306a36Sopenharmony_ci */ 10262306a36Sopenharmony_cistatic inline int run_descriptor_deco0(struct device *ctrldev, u32 *desc, 10362306a36Sopenharmony_ci u32 *status) 10462306a36Sopenharmony_ci{ 10562306a36Sopenharmony_ci struct caam_drv_private *ctrlpriv = dev_get_drvdata(ctrldev); 10662306a36Sopenharmony_ci struct caam_ctrl __iomem *ctrl = ctrlpriv->ctrl; 10762306a36Sopenharmony_ci struct caam_deco __iomem *deco = ctrlpriv->deco; 10862306a36Sopenharmony_ci unsigned int timeout = 100000; 10962306a36Sopenharmony_ci u32 deco_dbg_reg, deco_state, flags; 11062306a36Sopenharmony_ci int i; 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_ci if (ctrlpriv->virt_en == 1 || 11462306a36Sopenharmony_ci /* 11562306a36Sopenharmony_ci * Apparently on i.MX8M{Q,M,N,P} it doesn't matter if virt_en == 1 11662306a36Sopenharmony_ci * and the following steps should be performed regardless 11762306a36Sopenharmony_ci */ 11862306a36Sopenharmony_ci of_match_node(imx8m_machine_match, of_root)) { 11962306a36Sopenharmony_ci clrsetbits_32(&ctrl->deco_rsr, 0, DECORSR_JR0); 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_ci while (!(rd_reg32(&ctrl->deco_rsr) & DECORSR_VALID) && 12262306a36Sopenharmony_ci --timeout) 12362306a36Sopenharmony_ci cpu_relax(); 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_ci timeout = 100000; 12662306a36Sopenharmony_ci } 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_ci clrsetbits_32(&ctrl->deco_rq, 0, DECORR_RQD0ENABLE); 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_ci while (!(rd_reg32(&ctrl->deco_rq) & DECORR_DEN0) && 13162306a36Sopenharmony_ci --timeout) 13262306a36Sopenharmony_ci cpu_relax(); 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_ci if (!timeout) { 13562306a36Sopenharmony_ci dev_err(ctrldev, "failed to acquire DECO 0\n"); 13662306a36Sopenharmony_ci clrsetbits_32(&ctrl->deco_rq, DECORR_RQD0ENABLE, 0); 13762306a36Sopenharmony_ci return -ENODEV; 13862306a36Sopenharmony_ci } 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_ci for (i = 0; i < desc_len(desc); i++) 14162306a36Sopenharmony_ci wr_reg32(&deco->descbuf[i], caam32_to_cpu(*(desc + i))); 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_ci flags = DECO_JQCR_WHL; 14462306a36Sopenharmony_ci /* 14562306a36Sopenharmony_ci * If the descriptor length is longer than 4 words, then the 14662306a36Sopenharmony_ci * FOUR bit in JRCTRL register must be set. 14762306a36Sopenharmony_ci */ 14862306a36Sopenharmony_ci if (desc_len(desc) >= 4) 14962306a36Sopenharmony_ci flags |= DECO_JQCR_FOUR; 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_ci /* Instruct the DECO to execute it */ 15262306a36Sopenharmony_ci clrsetbits_32(&deco->jr_ctl_hi, 0, flags); 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_ci timeout = 10000000; 15562306a36Sopenharmony_ci do { 15662306a36Sopenharmony_ci deco_dbg_reg = rd_reg32(&deco->desc_dbg); 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_ci if (ctrlpriv->era < 10) 15962306a36Sopenharmony_ci deco_state = (deco_dbg_reg & DESC_DBG_DECO_STAT_MASK) >> 16062306a36Sopenharmony_ci DESC_DBG_DECO_STAT_SHIFT; 16162306a36Sopenharmony_ci else 16262306a36Sopenharmony_ci deco_state = (rd_reg32(&deco->dbg_exec) & 16362306a36Sopenharmony_ci DESC_DER_DECO_STAT_MASK) >> 16462306a36Sopenharmony_ci DESC_DER_DECO_STAT_SHIFT; 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_ci /* 16762306a36Sopenharmony_ci * If an error occurred in the descriptor, then 16862306a36Sopenharmony_ci * the DECO status field will be set to 0x0D 16962306a36Sopenharmony_ci */ 17062306a36Sopenharmony_ci if (deco_state == DECO_STAT_HOST_ERR) 17162306a36Sopenharmony_ci break; 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_ci cpu_relax(); 17462306a36Sopenharmony_ci } while ((deco_dbg_reg & DESC_DBG_DECO_STAT_VALID) && --timeout); 17562306a36Sopenharmony_ci 17662306a36Sopenharmony_ci *status = rd_reg32(&deco->op_status_hi) & 17762306a36Sopenharmony_ci DECO_OP_STATUS_HI_ERR_MASK; 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_ci if (ctrlpriv->virt_en == 1) 18062306a36Sopenharmony_ci clrsetbits_32(&ctrl->deco_rsr, DECORSR_JR0, 0); 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_ci /* Mark the DECO as free */ 18362306a36Sopenharmony_ci clrsetbits_32(&ctrl->deco_rq, DECORR_RQD0ENABLE, 0); 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_ci if (!timeout) 18662306a36Sopenharmony_ci return -EAGAIN; 18762306a36Sopenharmony_ci 18862306a36Sopenharmony_ci return 0; 18962306a36Sopenharmony_ci} 19062306a36Sopenharmony_ci 19162306a36Sopenharmony_ci/* 19262306a36Sopenharmony_ci * deinstantiate_rng - builds and executes a descriptor on DECO0, 19362306a36Sopenharmony_ci * which deinitializes the RNG block. 19462306a36Sopenharmony_ci * @ctrldev - pointer to device 19562306a36Sopenharmony_ci * @state_handle_mask - bitmask containing the instantiation status 19662306a36Sopenharmony_ci * for the RNG4 state handles which exist in 19762306a36Sopenharmony_ci * the RNG4 block: 1 if it's been instantiated 19862306a36Sopenharmony_ci * 19962306a36Sopenharmony_ci * Return: - 0 if no error occurred 20062306a36Sopenharmony_ci * - -ENOMEM if there isn't enough memory to allocate the descriptor 20162306a36Sopenharmony_ci * - -ENODEV if DECO0 couldn't be acquired 20262306a36Sopenharmony_ci * - -EAGAIN if an error occurred when executing the descriptor 20362306a36Sopenharmony_ci */ 20462306a36Sopenharmony_cistatic int deinstantiate_rng(struct device *ctrldev, int state_handle_mask) 20562306a36Sopenharmony_ci{ 20662306a36Sopenharmony_ci u32 *desc, status; 20762306a36Sopenharmony_ci int sh_idx, ret = 0; 20862306a36Sopenharmony_ci 20962306a36Sopenharmony_ci desc = kmalloc(CAAM_CMD_SZ * 3, GFP_KERNEL); 21062306a36Sopenharmony_ci if (!desc) 21162306a36Sopenharmony_ci return -ENOMEM; 21262306a36Sopenharmony_ci 21362306a36Sopenharmony_ci for (sh_idx = 0; sh_idx < RNG4_MAX_HANDLES; sh_idx++) { 21462306a36Sopenharmony_ci /* 21562306a36Sopenharmony_ci * If the corresponding bit is set, then it means the state 21662306a36Sopenharmony_ci * handle was initialized by us, and thus it needs to be 21762306a36Sopenharmony_ci * deinitialized as well 21862306a36Sopenharmony_ci */ 21962306a36Sopenharmony_ci if ((1 << sh_idx) & state_handle_mask) { 22062306a36Sopenharmony_ci /* 22162306a36Sopenharmony_ci * Create the descriptor for deinstantating this state 22262306a36Sopenharmony_ci * handle 22362306a36Sopenharmony_ci */ 22462306a36Sopenharmony_ci build_deinstantiation_desc(desc, sh_idx); 22562306a36Sopenharmony_ci 22662306a36Sopenharmony_ci /* Try to run it through DECO0 */ 22762306a36Sopenharmony_ci ret = run_descriptor_deco0(ctrldev, desc, &status); 22862306a36Sopenharmony_ci 22962306a36Sopenharmony_ci if (ret || 23062306a36Sopenharmony_ci (status && status != JRSTA_SSRC_JUMP_HALT_CC)) { 23162306a36Sopenharmony_ci dev_err(ctrldev, 23262306a36Sopenharmony_ci "Failed to deinstantiate RNG4 SH%d\n", 23362306a36Sopenharmony_ci sh_idx); 23462306a36Sopenharmony_ci break; 23562306a36Sopenharmony_ci } 23662306a36Sopenharmony_ci dev_info(ctrldev, "Deinstantiated RNG4 SH%d\n", sh_idx); 23762306a36Sopenharmony_ci } 23862306a36Sopenharmony_ci } 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_ci kfree(desc); 24162306a36Sopenharmony_ci 24262306a36Sopenharmony_ci return ret; 24362306a36Sopenharmony_ci} 24462306a36Sopenharmony_ci 24562306a36Sopenharmony_cistatic void devm_deinstantiate_rng(void *data) 24662306a36Sopenharmony_ci{ 24762306a36Sopenharmony_ci struct device *ctrldev = data; 24862306a36Sopenharmony_ci struct caam_drv_private *ctrlpriv = dev_get_drvdata(ctrldev); 24962306a36Sopenharmony_ci 25062306a36Sopenharmony_ci /* 25162306a36Sopenharmony_ci * De-initialize RNG state handles initialized by this driver. 25262306a36Sopenharmony_ci * In case of SoCs with Management Complex, RNG is managed by MC f/w. 25362306a36Sopenharmony_ci */ 25462306a36Sopenharmony_ci if (ctrlpriv->rng4_sh_init) 25562306a36Sopenharmony_ci deinstantiate_rng(ctrldev, ctrlpriv->rng4_sh_init); 25662306a36Sopenharmony_ci} 25762306a36Sopenharmony_ci 25862306a36Sopenharmony_ci/* 25962306a36Sopenharmony_ci * instantiate_rng - builds and executes a descriptor on DECO0, 26062306a36Sopenharmony_ci * which initializes the RNG block. 26162306a36Sopenharmony_ci * @ctrldev - pointer to device 26262306a36Sopenharmony_ci * @state_handle_mask - bitmask containing the instantiation status 26362306a36Sopenharmony_ci * for the RNG4 state handles which exist in 26462306a36Sopenharmony_ci * the RNG4 block: 1 if it's been instantiated 26562306a36Sopenharmony_ci * by an external entry, 0 otherwise. 26662306a36Sopenharmony_ci * @gen_sk - generate data to be loaded into the JDKEK, TDKEK and TDSK; 26762306a36Sopenharmony_ci * Caution: this can be done only once; if the keys need to be 26862306a36Sopenharmony_ci * regenerated, a POR is required 26962306a36Sopenharmony_ci * 27062306a36Sopenharmony_ci * Return: - 0 if no error occurred 27162306a36Sopenharmony_ci * - -ENOMEM if there isn't enough memory to allocate the descriptor 27262306a36Sopenharmony_ci * - -ENODEV if DECO0 couldn't be acquired 27362306a36Sopenharmony_ci * - -EAGAIN if an error occurred when executing the descriptor 27462306a36Sopenharmony_ci * f.i. there was a RNG hardware error due to not "good enough" 27562306a36Sopenharmony_ci * entropy being acquired. 27662306a36Sopenharmony_ci */ 27762306a36Sopenharmony_cistatic int instantiate_rng(struct device *ctrldev, int state_handle_mask, 27862306a36Sopenharmony_ci int gen_sk) 27962306a36Sopenharmony_ci{ 28062306a36Sopenharmony_ci struct caam_drv_private *ctrlpriv = dev_get_drvdata(ctrldev); 28162306a36Sopenharmony_ci struct caam_ctrl __iomem *ctrl; 28262306a36Sopenharmony_ci u32 *desc, status = 0, rdsta_val; 28362306a36Sopenharmony_ci int ret = 0, sh_idx; 28462306a36Sopenharmony_ci 28562306a36Sopenharmony_ci ctrl = (struct caam_ctrl __iomem *)ctrlpriv->ctrl; 28662306a36Sopenharmony_ci desc = kmalloc(CAAM_CMD_SZ * 7, GFP_KERNEL); 28762306a36Sopenharmony_ci if (!desc) 28862306a36Sopenharmony_ci return -ENOMEM; 28962306a36Sopenharmony_ci 29062306a36Sopenharmony_ci for (sh_idx = 0; sh_idx < RNG4_MAX_HANDLES; sh_idx++) { 29162306a36Sopenharmony_ci const u32 rdsta_if = RDSTA_IF0 << sh_idx; 29262306a36Sopenharmony_ci const u32 rdsta_pr = RDSTA_PR0 << sh_idx; 29362306a36Sopenharmony_ci const u32 rdsta_mask = rdsta_if | rdsta_pr; 29462306a36Sopenharmony_ci 29562306a36Sopenharmony_ci /* Clear the contents before using the descriptor */ 29662306a36Sopenharmony_ci memset(desc, 0x00, CAAM_CMD_SZ * 7); 29762306a36Sopenharmony_ci 29862306a36Sopenharmony_ci /* 29962306a36Sopenharmony_ci * If the corresponding bit is set, this state handle 30062306a36Sopenharmony_ci * was initialized by somebody else, so it's left alone. 30162306a36Sopenharmony_ci */ 30262306a36Sopenharmony_ci if (rdsta_if & state_handle_mask) { 30362306a36Sopenharmony_ci if (rdsta_pr & state_handle_mask) 30462306a36Sopenharmony_ci continue; 30562306a36Sopenharmony_ci 30662306a36Sopenharmony_ci dev_info(ctrldev, 30762306a36Sopenharmony_ci "RNG4 SH%d was previously instantiated without prediction resistance. Tearing it down\n", 30862306a36Sopenharmony_ci sh_idx); 30962306a36Sopenharmony_ci 31062306a36Sopenharmony_ci ret = deinstantiate_rng(ctrldev, rdsta_if); 31162306a36Sopenharmony_ci if (ret) 31262306a36Sopenharmony_ci break; 31362306a36Sopenharmony_ci } 31462306a36Sopenharmony_ci 31562306a36Sopenharmony_ci /* Create the descriptor for instantiating RNG State Handle */ 31662306a36Sopenharmony_ci build_instantiation_desc(desc, sh_idx, gen_sk); 31762306a36Sopenharmony_ci 31862306a36Sopenharmony_ci /* Try to run it through DECO0 */ 31962306a36Sopenharmony_ci ret = run_descriptor_deco0(ctrldev, desc, &status); 32062306a36Sopenharmony_ci 32162306a36Sopenharmony_ci /* 32262306a36Sopenharmony_ci * If ret is not 0, or descriptor status is not 0, then 32362306a36Sopenharmony_ci * something went wrong. No need to try the next state 32462306a36Sopenharmony_ci * handle (if available), bail out here. 32562306a36Sopenharmony_ci * Also, if for some reason, the State Handle didn't get 32662306a36Sopenharmony_ci * instantiated although the descriptor has finished 32762306a36Sopenharmony_ci * without any error (HW optimizations for later 32862306a36Sopenharmony_ci * CAAM eras), then try again. 32962306a36Sopenharmony_ci */ 33062306a36Sopenharmony_ci if (ret) 33162306a36Sopenharmony_ci break; 33262306a36Sopenharmony_ci 33362306a36Sopenharmony_ci rdsta_val = rd_reg32(&ctrl->r4tst[0].rdsta) & RDSTA_MASK; 33462306a36Sopenharmony_ci if ((status && status != JRSTA_SSRC_JUMP_HALT_CC) || 33562306a36Sopenharmony_ci (rdsta_val & rdsta_mask) != rdsta_mask) { 33662306a36Sopenharmony_ci ret = -EAGAIN; 33762306a36Sopenharmony_ci break; 33862306a36Sopenharmony_ci } 33962306a36Sopenharmony_ci 34062306a36Sopenharmony_ci dev_info(ctrldev, "Instantiated RNG4 SH%d\n", sh_idx); 34162306a36Sopenharmony_ci } 34262306a36Sopenharmony_ci 34362306a36Sopenharmony_ci kfree(desc); 34462306a36Sopenharmony_ci 34562306a36Sopenharmony_ci if (ret) 34662306a36Sopenharmony_ci return ret; 34762306a36Sopenharmony_ci 34862306a36Sopenharmony_ci return devm_add_action_or_reset(ctrldev, devm_deinstantiate_rng, ctrldev); 34962306a36Sopenharmony_ci} 35062306a36Sopenharmony_ci 35162306a36Sopenharmony_ci/* 35262306a36Sopenharmony_ci * kick_trng - sets the various parameters for enabling the initialization 35362306a36Sopenharmony_ci * of the RNG4 block in CAAM 35462306a36Sopenharmony_ci * @dev - pointer to the controller device 35562306a36Sopenharmony_ci * @ent_delay - Defines the length (in system clocks) of each entropy sample. 35662306a36Sopenharmony_ci */ 35762306a36Sopenharmony_cistatic void kick_trng(struct device *dev, int ent_delay) 35862306a36Sopenharmony_ci{ 35962306a36Sopenharmony_ci struct caam_drv_private *ctrlpriv = dev_get_drvdata(dev); 36062306a36Sopenharmony_ci struct caam_ctrl __iomem *ctrl; 36162306a36Sopenharmony_ci struct rng4tst __iomem *r4tst; 36262306a36Sopenharmony_ci u32 val, rtsdctl; 36362306a36Sopenharmony_ci 36462306a36Sopenharmony_ci ctrl = (struct caam_ctrl __iomem *)ctrlpriv->ctrl; 36562306a36Sopenharmony_ci r4tst = &ctrl->r4tst[0]; 36662306a36Sopenharmony_ci 36762306a36Sopenharmony_ci /* 36862306a36Sopenharmony_ci * Setting both RTMCTL:PRGM and RTMCTL:TRNG_ACC causes TRNG to 36962306a36Sopenharmony_ci * properly invalidate the entropy in the entropy register and 37062306a36Sopenharmony_ci * force re-generation. 37162306a36Sopenharmony_ci */ 37262306a36Sopenharmony_ci clrsetbits_32(&r4tst->rtmctl, 0, RTMCTL_PRGM | RTMCTL_ACC); 37362306a36Sopenharmony_ci 37462306a36Sopenharmony_ci /* 37562306a36Sopenharmony_ci * Performance-wise, it does not make sense to 37662306a36Sopenharmony_ci * set the delay to a value that is lower 37762306a36Sopenharmony_ci * than the last one that worked (i.e. the state handles 37862306a36Sopenharmony_ci * were instantiated properly). 37962306a36Sopenharmony_ci */ 38062306a36Sopenharmony_ci rtsdctl = rd_reg32(&r4tst->rtsdctl); 38162306a36Sopenharmony_ci val = (rtsdctl & RTSDCTL_ENT_DLY_MASK) >> RTSDCTL_ENT_DLY_SHIFT; 38262306a36Sopenharmony_ci if (ent_delay > val) { 38362306a36Sopenharmony_ci val = ent_delay; 38462306a36Sopenharmony_ci /* min. freq. count, equal to 1/4 of the entropy sample length */ 38562306a36Sopenharmony_ci wr_reg32(&r4tst->rtfrqmin, val >> 2); 38662306a36Sopenharmony_ci /* disable maximum frequency count */ 38762306a36Sopenharmony_ci wr_reg32(&r4tst->rtfrqmax, RTFRQMAX_DISABLE); 38862306a36Sopenharmony_ci } 38962306a36Sopenharmony_ci 39062306a36Sopenharmony_ci wr_reg32(&r4tst->rtsdctl, (val << RTSDCTL_ENT_DLY_SHIFT) | 39162306a36Sopenharmony_ci RTSDCTL_SAMP_SIZE_VAL); 39262306a36Sopenharmony_ci 39362306a36Sopenharmony_ci /* 39462306a36Sopenharmony_ci * To avoid reprogramming the self-test parameters over and over again, 39562306a36Sopenharmony_ci * use RTSDCTL[SAMP_SIZE] as an indicator. 39662306a36Sopenharmony_ci */ 39762306a36Sopenharmony_ci if ((rtsdctl & RTSDCTL_SAMP_SIZE_MASK) != RTSDCTL_SAMP_SIZE_VAL) { 39862306a36Sopenharmony_ci wr_reg32(&r4tst->rtscmisc, (2 << 16) | 32); 39962306a36Sopenharmony_ci wr_reg32(&r4tst->rtpkrrng, 570); 40062306a36Sopenharmony_ci wr_reg32(&r4tst->rtpkrmax, 1600); 40162306a36Sopenharmony_ci wr_reg32(&r4tst->rtscml, (122 << 16) | 317); 40262306a36Sopenharmony_ci wr_reg32(&r4tst->rtscrl[0], (80 << 16) | 107); 40362306a36Sopenharmony_ci wr_reg32(&r4tst->rtscrl[1], (57 << 16) | 62); 40462306a36Sopenharmony_ci wr_reg32(&r4tst->rtscrl[2], (39 << 16) | 39); 40562306a36Sopenharmony_ci wr_reg32(&r4tst->rtscrl[3], (27 << 16) | 26); 40662306a36Sopenharmony_ci wr_reg32(&r4tst->rtscrl[4], (19 << 16) | 18); 40762306a36Sopenharmony_ci wr_reg32(&r4tst->rtscrl[5], (18 << 16) | 17); 40862306a36Sopenharmony_ci } 40962306a36Sopenharmony_ci 41062306a36Sopenharmony_ci /* 41162306a36Sopenharmony_ci * select raw sampling in both entropy shifter 41262306a36Sopenharmony_ci * and statistical checker; ; put RNG4 into run mode 41362306a36Sopenharmony_ci */ 41462306a36Sopenharmony_ci clrsetbits_32(&r4tst->rtmctl, RTMCTL_PRGM | RTMCTL_ACC, 41562306a36Sopenharmony_ci RTMCTL_SAMP_MODE_RAW_ES_SC); 41662306a36Sopenharmony_ci} 41762306a36Sopenharmony_ci 41862306a36Sopenharmony_cistatic int caam_get_era_from_hw(struct caam_perfmon __iomem *perfmon) 41962306a36Sopenharmony_ci{ 42062306a36Sopenharmony_ci static const struct { 42162306a36Sopenharmony_ci u16 ip_id; 42262306a36Sopenharmony_ci u8 maj_rev; 42362306a36Sopenharmony_ci u8 era; 42462306a36Sopenharmony_ci } id[] = { 42562306a36Sopenharmony_ci {0x0A10, 1, 1}, 42662306a36Sopenharmony_ci {0x0A10, 2, 2}, 42762306a36Sopenharmony_ci {0x0A12, 1, 3}, 42862306a36Sopenharmony_ci {0x0A14, 1, 3}, 42962306a36Sopenharmony_ci {0x0A14, 2, 4}, 43062306a36Sopenharmony_ci {0x0A16, 1, 4}, 43162306a36Sopenharmony_ci {0x0A10, 3, 4}, 43262306a36Sopenharmony_ci {0x0A11, 1, 4}, 43362306a36Sopenharmony_ci {0x0A18, 1, 4}, 43462306a36Sopenharmony_ci {0x0A11, 2, 5}, 43562306a36Sopenharmony_ci {0x0A12, 2, 5}, 43662306a36Sopenharmony_ci {0x0A13, 1, 5}, 43762306a36Sopenharmony_ci {0x0A1C, 1, 5} 43862306a36Sopenharmony_ci }; 43962306a36Sopenharmony_ci u32 ccbvid, id_ms; 44062306a36Sopenharmony_ci u8 maj_rev, era; 44162306a36Sopenharmony_ci u16 ip_id; 44262306a36Sopenharmony_ci int i; 44362306a36Sopenharmony_ci 44462306a36Sopenharmony_ci ccbvid = rd_reg32(&perfmon->ccb_id); 44562306a36Sopenharmony_ci era = (ccbvid & CCBVID_ERA_MASK) >> CCBVID_ERA_SHIFT; 44662306a36Sopenharmony_ci if (era) /* This is '0' prior to CAAM ERA-6 */ 44762306a36Sopenharmony_ci return era; 44862306a36Sopenharmony_ci 44962306a36Sopenharmony_ci id_ms = rd_reg32(&perfmon->caam_id_ms); 45062306a36Sopenharmony_ci ip_id = (id_ms & SECVID_MS_IPID_MASK) >> SECVID_MS_IPID_SHIFT; 45162306a36Sopenharmony_ci maj_rev = (id_ms & SECVID_MS_MAJ_REV_MASK) >> SECVID_MS_MAJ_REV_SHIFT; 45262306a36Sopenharmony_ci 45362306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(id); i++) 45462306a36Sopenharmony_ci if (id[i].ip_id == ip_id && id[i].maj_rev == maj_rev) 45562306a36Sopenharmony_ci return id[i].era; 45662306a36Sopenharmony_ci 45762306a36Sopenharmony_ci return -ENOTSUPP; 45862306a36Sopenharmony_ci} 45962306a36Sopenharmony_ci 46062306a36Sopenharmony_ci/** 46162306a36Sopenharmony_ci * caam_get_era() - Return the ERA of the SEC on SoC, based 46262306a36Sopenharmony_ci * on "sec-era" optional property in the DTS. This property is updated 46362306a36Sopenharmony_ci * by u-boot. 46462306a36Sopenharmony_ci * In case this property is not passed an attempt to retrieve the CAAM 46562306a36Sopenharmony_ci * era via register reads will be made. 46662306a36Sopenharmony_ci * 46762306a36Sopenharmony_ci * @perfmon: Performance Monitor Registers 46862306a36Sopenharmony_ci */ 46962306a36Sopenharmony_cistatic int caam_get_era(struct caam_perfmon __iomem *perfmon) 47062306a36Sopenharmony_ci{ 47162306a36Sopenharmony_ci struct device_node *caam_node; 47262306a36Sopenharmony_ci int ret; 47362306a36Sopenharmony_ci u32 prop; 47462306a36Sopenharmony_ci 47562306a36Sopenharmony_ci caam_node = of_find_compatible_node(NULL, NULL, "fsl,sec-v4.0"); 47662306a36Sopenharmony_ci ret = of_property_read_u32(caam_node, "fsl,sec-era", &prop); 47762306a36Sopenharmony_ci of_node_put(caam_node); 47862306a36Sopenharmony_ci 47962306a36Sopenharmony_ci if (!ret) 48062306a36Sopenharmony_ci return prop; 48162306a36Sopenharmony_ci else 48262306a36Sopenharmony_ci return caam_get_era_from_hw(perfmon); 48362306a36Sopenharmony_ci} 48462306a36Sopenharmony_ci 48562306a36Sopenharmony_ci/* 48662306a36Sopenharmony_ci * ERRATA: imx6 devices (imx6D, imx6Q, imx6DL, imx6S, imx6DP and imx6QP) 48762306a36Sopenharmony_ci * have an issue wherein AXI bus transactions may not occur in the correct 48862306a36Sopenharmony_ci * order. This isn't a problem running single descriptors, but can be if 48962306a36Sopenharmony_ci * running multiple concurrent descriptors. Reworking the driver to throttle 49062306a36Sopenharmony_ci * to single requests is impractical, thus the workaround is to limit the AXI 49162306a36Sopenharmony_ci * pipeline to a depth of 1 (from it's default of 4) to preclude this situation 49262306a36Sopenharmony_ci * from occurring. 49362306a36Sopenharmony_ci */ 49462306a36Sopenharmony_cistatic void handle_imx6_err005766(u32 __iomem *mcr) 49562306a36Sopenharmony_ci{ 49662306a36Sopenharmony_ci if (of_machine_is_compatible("fsl,imx6q") || 49762306a36Sopenharmony_ci of_machine_is_compatible("fsl,imx6dl") || 49862306a36Sopenharmony_ci of_machine_is_compatible("fsl,imx6qp")) 49962306a36Sopenharmony_ci clrsetbits_32(mcr, MCFGR_AXIPIPE_MASK, 50062306a36Sopenharmony_ci 1 << MCFGR_AXIPIPE_SHIFT); 50162306a36Sopenharmony_ci} 50262306a36Sopenharmony_ci 50362306a36Sopenharmony_cistatic const struct of_device_id caam_match[] = { 50462306a36Sopenharmony_ci { 50562306a36Sopenharmony_ci .compatible = "fsl,sec-v4.0", 50662306a36Sopenharmony_ci }, 50762306a36Sopenharmony_ci { 50862306a36Sopenharmony_ci .compatible = "fsl,sec4.0", 50962306a36Sopenharmony_ci }, 51062306a36Sopenharmony_ci {}, 51162306a36Sopenharmony_ci}; 51262306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, caam_match); 51362306a36Sopenharmony_ci 51462306a36Sopenharmony_cistruct caam_imx_data { 51562306a36Sopenharmony_ci const struct clk_bulk_data *clks; 51662306a36Sopenharmony_ci int num_clks; 51762306a36Sopenharmony_ci}; 51862306a36Sopenharmony_ci 51962306a36Sopenharmony_cistatic const struct clk_bulk_data caam_imx6_clks[] = { 52062306a36Sopenharmony_ci { .id = "ipg" }, 52162306a36Sopenharmony_ci { .id = "mem" }, 52262306a36Sopenharmony_ci { .id = "aclk" }, 52362306a36Sopenharmony_ci { .id = "emi_slow" }, 52462306a36Sopenharmony_ci}; 52562306a36Sopenharmony_ci 52662306a36Sopenharmony_cistatic const struct caam_imx_data caam_imx6_data = { 52762306a36Sopenharmony_ci .clks = caam_imx6_clks, 52862306a36Sopenharmony_ci .num_clks = ARRAY_SIZE(caam_imx6_clks), 52962306a36Sopenharmony_ci}; 53062306a36Sopenharmony_ci 53162306a36Sopenharmony_cistatic const struct clk_bulk_data caam_imx7_clks[] = { 53262306a36Sopenharmony_ci { .id = "ipg" }, 53362306a36Sopenharmony_ci { .id = "aclk" }, 53462306a36Sopenharmony_ci}; 53562306a36Sopenharmony_ci 53662306a36Sopenharmony_cistatic const struct caam_imx_data caam_imx7_data = { 53762306a36Sopenharmony_ci .clks = caam_imx7_clks, 53862306a36Sopenharmony_ci .num_clks = ARRAY_SIZE(caam_imx7_clks), 53962306a36Sopenharmony_ci}; 54062306a36Sopenharmony_ci 54162306a36Sopenharmony_cistatic const struct clk_bulk_data caam_imx6ul_clks[] = { 54262306a36Sopenharmony_ci { .id = "ipg" }, 54362306a36Sopenharmony_ci { .id = "mem" }, 54462306a36Sopenharmony_ci { .id = "aclk" }, 54562306a36Sopenharmony_ci}; 54662306a36Sopenharmony_ci 54762306a36Sopenharmony_cistatic const struct caam_imx_data caam_imx6ul_data = { 54862306a36Sopenharmony_ci .clks = caam_imx6ul_clks, 54962306a36Sopenharmony_ci .num_clks = ARRAY_SIZE(caam_imx6ul_clks), 55062306a36Sopenharmony_ci}; 55162306a36Sopenharmony_ci 55262306a36Sopenharmony_cistatic const struct clk_bulk_data caam_vf610_clks[] = { 55362306a36Sopenharmony_ci { .id = "ipg" }, 55462306a36Sopenharmony_ci}; 55562306a36Sopenharmony_ci 55662306a36Sopenharmony_cistatic const struct caam_imx_data caam_vf610_data = { 55762306a36Sopenharmony_ci .clks = caam_vf610_clks, 55862306a36Sopenharmony_ci .num_clks = ARRAY_SIZE(caam_vf610_clks), 55962306a36Sopenharmony_ci}; 56062306a36Sopenharmony_ci 56162306a36Sopenharmony_cistatic const struct soc_device_attribute caam_imx_soc_table[] = { 56262306a36Sopenharmony_ci { .soc_id = "i.MX6UL", .data = &caam_imx6ul_data }, 56362306a36Sopenharmony_ci { .soc_id = "i.MX6*", .data = &caam_imx6_data }, 56462306a36Sopenharmony_ci { .soc_id = "i.MX7*", .data = &caam_imx7_data }, 56562306a36Sopenharmony_ci { .soc_id = "i.MX8M*", .data = &caam_imx7_data }, 56662306a36Sopenharmony_ci { .soc_id = "VF*", .data = &caam_vf610_data }, 56762306a36Sopenharmony_ci { .family = "Freescale i.MX" }, 56862306a36Sopenharmony_ci { /* sentinel */ } 56962306a36Sopenharmony_ci}; 57062306a36Sopenharmony_ci 57162306a36Sopenharmony_cistatic void disable_clocks(void *data) 57262306a36Sopenharmony_ci{ 57362306a36Sopenharmony_ci struct caam_drv_private *ctrlpriv = data; 57462306a36Sopenharmony_ci 57562306a36Sopenharmony_ci clk_bulk_disable_unprepare(ctrlpriv->num_clks, ctrlpriv->clks); 57662306a36Sopenharmony_ci} 57762306a36Sopenharmony_ci 57862306a36Sopenharmony_cistatic int init_clocks(struct device *dev, const struct caam_imx_data *data) 57962306a36Sopenharmony_ci{ 58062306a36Sopenharmony_ci struct caam_drv_private *ctrlpriv = dev_get_drvdata(dev); 58162306a36Sopenharmony_ci int ret; 58262306a36Sopenharmony_ci 58362306a36Sopenharmony_ci ctrlpriv->num_clks = data->num_clks; 58462306a36Sopenharmony_ci ctrlpriv->clks = devm_kmemdup(dev, data->clks, 58562306a36Sopenharmony_ci data->num_clks * sizeof(data->clks[0]), 58662306a36Sopenharmony_ci GFP_KERNEL); 58762306a36Sopenharmony_ci if (!ctrlpriv->clks) 58862306a36Sopenharmony_ci return -ENOMEM; 58962306a36Sopenharmony_ci 59062306a36Sopenharmony_ci ret = devm_clk_bulk_get(dev, ctrlpriv->num_clks, ctrlpriv->clks); 59162306a36Sopenharmony_ci if (ret) { 59262306a36Sopenharmony_ci dev_err(dev, 59362306a36Sopenharmony_ci "Failed to request all necessary clocks\n"); 59462306a36Sopenharmony_ci return ret; 59562306a36Sopenharmony_ci } 59662306a36Sopenharmony_ci 59762306a36Sopenharmony_ci ret = clk_bulk_prepare_enable(ctrlpriv->num_clks, ctrlpriv->clks); 59862306a36Sopenharmony_ci if (ret) { 59962306a36Sopenharmony_ci dev_err(dev, 60062306a36Sopenharmony_ci "Failed to prepare/enable all necessary clocks\n"); 60162306a36Sopenharmony_ci return ret; 60262306a36Sopenharmony_ci } 60362306a36Sopenharmony_ci 60462306a36Sopenharmony_ci return devm_add_action_or_reset(dev, disable_clocks, ctrlpriv); 60562306a36Sopenharmony_ci} 60662306a36Sopenharmony_ci 60762306a36Sopenharmony_cistatic void caam_remove_debugfs(void *root) 60862306a36Sopenharmony_ci{ 60962306a36Sopenharmony_ci debugfs_remove_recursive(root); 61062306a36Sopenharmony_ci} 61162306a36Sopenharmony_ci 61262306a36Sopenharmony_ci#ifdef CONFIG_FSL_MC_BUS 61362306a36Sopenharmony_cistatic bool check_version(struct fsl_mc_version *mc_version, u32 major, 61462306a36Sopenharmony_ci u32 minor, u32 revision) 61562306a36Sopenharmony_ci{ 61662306a36Sopenharmony_ci if (mc_version->major > major) 61762306a36Sopenharmony_ci return true; 61862306a36Sopenharmony_ci 61962306a36Sopenharmony_ci if (mc_version->major == major) { 62062306a36Sopenharmony_ci if (mc_version->minor > minor) 62162306a36Sopenharmony_ci return true; 62262306a36Sopenharmony_ci 62362306a36Sopenharmony_ci if (mc_version->minor == minor && 62462306a36Sopenharmony_ci mc_version->revision > revision) 62562306a36Sopenharmony_ci return true; 62662306a36Sopenharmony_ci } 62762306a36Sopenharmony_ci 62862306a36Sopenharmony_ci return false; 62962306a36Sopenharmony_ci} 63062306a36Sopenharmony_ci#endif 63162306a36Sopenharmony_ci 63262306a36Sopenharmony_cistatic bool needs_entropy_delay_adjustment(void) 63362306a36Sopenharmony_ci{ 63462306a36Sopenharmony_ci if (of_machine_is_compatible("fsl,imx6sx")) 63562306a36Sopenharmony_ci return true; 63662306a36Sopenharmony_ci return false; 63762306a36Sopenharmony_ci} 63862306a36Sopenharmony_ci 63962306a36Sopenharmony_cistatic int caam_ctrl_rng_init(struct device *dev) 64062306a36Sopenharmony_ci{ 64162306a36Sopenharmony_ci struct caam_drv_private *ctrlpriv = dev_get_drvdata(dev); 64262306a36Sopenharmony_ci struct caam_ctrl __iomem *ctrl = ctrlpriv->ctrl; 64362306a36Sopenharmony_ci int ret, gen_sk, ent_delay = RTSDCTL_ENT_DLY_MIN; 64462306a36Sopenharmony_ci u8 rng_vid; 64562306a36Sopenharmony_ci 64662306a36Sopenharmony_ci if (ctrlpriv->era < 10) { 64762306a36Sopenharmony_ci struct caam_perfmon __iomem *perfmon; 64862306a36Sopenharmony_ci 64962306a36Sopenharmony_ci perfmon = ctrlpriv->total_jobrs ? 65062306a36Sopenharmony_ci (struct caam_perfmon __iomem *)&ctrlpriv->jr[0]->perfmon : 65162306a36Sopenharmony_ci (struct caam_perfmon __iomem *)&ctrl->perfmon; 65262306a36Sopenharmony_ci 65362306a36Sopenharmony_ci rng_vid = (rd_reg32(&perfmon->cha_id_ls) & 65462306a36Sopenharmony_ci CHA_ID_LS_RNG_MASK) >> CHA_ID_LS_RNG_SHIFT; 65562306a36Sopenharmony_ci } else { 65662306a36Sopenharmony_ci struct version_regs __iomem *vreg; 65762306a36Sopenharmony_ci 65862306a36Sopenharmony_ci vreg = ctrlpriv->total_jobrs ? 65962306a36Sopenharmony_ci (struct version_regs __iomem *)&ctrlpriv->jr[0]->vreg : 66062306a36Sopenharmony_ci (struct version_regs __iomem *)&ctrl->vreg; 66162306a36Sopenharmony_ci 66262306a36Sopenharmony_ci rng_vid = (rd_reg32(&vreg->rng) & CHA_VER_VID_MASK) >> 66362306a36Sopenharmony_ci CHA_VER_VID_SHIFT; 66462306a36Sopenharmony_ci } 66562306a36Sopenharmony_ci 66662306a36Sopenharmony_ci /* 66762306a36Sopenharmony_ci * If SEC has RNG version >= 4 and RNG state handle has not been 66862306a36Sopenharmony_ci * already instantiated, do RNG instantiation 66962306a36Sopenharmony_ci * In case of SoCs with Management Complex, RNG is managed by MC f/w. 67062306a36Sopenharmony_ci */ 67162306a36Sopenharmony_ci if (!(ctrlpriv->mc_en && ctrlpriv->pr_support) && rng_vid >= 4) { 67262306a36Sopenharmony_ci ctrlpriv->rng4_sh_init = 67362306a36Sopenharmony_ci rd_reg32(&ctrl->r4tst[0].rdsta); 67462306a36Sopenharmony_ci /* 67562306a36Sopenharmony_ci * If the secure keys (TDKEK, JDKEK, TDSK), were already 67662306a36Sopenharmony_ci * generated, signal this to the function that is instantiating 67762306a36Sopenharmony_ci * the state handles. An error would occur if RNG4 attempts 67862306a36Sopenharmony_ci * to regenerate these keys before the next POR. 67962306a36Sopenharmony_ci */ 68062306a36Sopenharmony_ci gen_sk = ctrlpriv->rng4_sh_init & RDSTA_SKVN ? 0 : 1; 68162306a36Sopenharmony_ci ctrlpriv->rng4_sh_init &= RDSTA_MASK; 68262306a36Sopenharmony_ci do { 68362306a36Sopenharmony_ci int inst_handles = 68462306a36Sopenharmony_ci rd_reg32(&ctrl->r4tst[0].rdsta) & RDSTA_MASK; 68562306a36Sopenharmony_ci /* 68662306a36Sopenharmony_ci * If either SH were instantiated by somebody else 68762306a36Sopenharmony_ci * (e.g. u-boot) then it is assumed that the entropy 68862306a36Sopenharmony_ci * parameters are properly set and thus the function 68962306a36Sopenharmony_ci * setting these (kick_trng(...)) is skipped. 69062306a36Sopenharmony_ci * Also, if a handle was instantiated, do not change 69162306a36Sopenharmony_ci * the TRNG parameters. 69262306a36Sopenharmony_ci */ 69362306a36Sopenharmony_ci if (needs_entropy_delay_adjustment()) 69462306a36Sopenharmony_ci ent_delay = 12000; 69562306a36Sopenharmony_ci if (!(ctrlpriv->rng4_sh_init || inst_handles)) { 69662306a36Sopenharmony_ci dev_info(dev, 69762306a36Sopenharmony_ci "Entropy delay = %u\n", 69862306a36Sopenharmony_ci ent_delay); 69962306a36Sopenharmony_ci kick_trng(dev, ent_delay); 70062306a36Sopenharmony_ci ent_delay += 400; 70162306a36Sopenharmony_ci } 70262306a36Sopenharmony_ci /* 70362306a36Sopenharmony_ci * if instantiate_rng(...) fails, the loop will rerun 70462306a36Sopenharmony_ci * and the kick_trng(...) function will modify the 70562306a36Sopenharmony_ci * upper and lower limits of the entropy sampling 70662306a36Sopenharmony_ci * interval, leading to a successful initialization of 70762306a36Sopenharmony_ci * the RNG. 70862306a36Sopenharmony_ci */ 70962306a36Sopenharmony_ci ret = instantiate_rng(dev, inst_handles, 71062306a36Sopenharmony_ci gen_sk); 71162306a36Sopenharmony_ci /* 71262306a36Sopenharmony_ci * Entropy delay is determined via TRNG characterization. 71362306a36Sopenharmony_ci * TRNG characterization is run across different voltages 71462306a36Sopenharmony_ci * and temperatures. 71562306a36Sopenharmony_ci * If worst case value for ent_dly is identified, 71662306a36Sopenharmony_ci * the loop can be skipped for that platform. 71762306a36Sopenharmony_ci */ 71862306a36Sopenharmony_ci if (needs_entropy_delay_adjustment()) 71962306a36Sopenharmony_ci break; 72062306a36Sopenharmony_ci if (ret == -EAGAIN) 72162306a36Sopenharmony_ci /* 72262306a36Sopenharmony_ci * if here, the loop will rerun, 72362306a36Sopenharmony_ci * so don't hog the CPU 72462306a36Sopenharmony_ci */ 72562306a36Sopenharmony_ci cpu_relax(); 72662306a36Sopenharmony_ci } while ((ret == -EAGAIN) && (ent_delay < RTSDCTL_ENT_DLY_MAX)); 72762306a36Sopenharmony_ci if (ret) { 72862306a36Sopenharmony_ci dev_err(dev, "failed to instantiate RNG"); 72962306a36Sopenharmony_ci return ret; 73062306a36Sopenharmony_ci } 73162306a36Sopenharmony_ci /* 73262306a36Sopenharmony_ci * Set handles initialized by this module as the complement of 73362306a36Sopenharmony_ci * the already initialized ones 73462306a36Sopenharmony_ci */ 73562306a36Sopenharmony_ci ctrlpriv->rng4_sh_init = ~ctrlpriv->rng4_sh_init & RDSTA_MASK; 73662306a36Sopenharmony_ci 73762306a36Sopenharmony_ci /* Enable RDB bit so that RNG works faster */ 73862306a36Sopenharmony_ci clrsetbits_32(&ctrl->scfgr, 0, SCFGR_RDBENABLE); 73962306a36Sopenharmony_ci } 74062306a36Sopenharmony_ci 74162306a36Sopenharmony_ci return 0; 74262306a36Sopenharmony_ci} 74362306a36Sopenharmony_ci 74462306a36Sopenharmony_ci/* Indicate if the internal state of the CAAM is lost during PM */ 74562306a36Sopenharmony_cistatic int caam_off_during_pm(void) 74662306a36Sopenharmony_ci{ 74762306a36Sopenharmony_ci bool not_off_during_pm = of_machine_is_compatible("fsl,imx6q") || 74862306a36Sopenharmony_ci of_machine_is_compatible("fsl,imx6qp") || 74962306a36Sopenharmony_ci of_machine_is_compatible("fsl,imx6dl"); 75062306a36Sopenharmony_ci 75162306a36Sopenharmony_ci return not_off_during_pm ? 0 : 1; 75262306a36Sopenharmony_ci} 75362306a36Sopenharmony_ci 75462306a36Sopenharmony_cistatic void caam_state_save(struct device *dev) 75562306a36Sopenharmony_ci{ 75662306a36Sopenharmony_ci struct caam_drv_private *ctrlpriv = dev_get_drvdata(dev); 75762306a36Sopenharmony_ci struct caam_ctl_state *state = &ctrlpriv->state; 75862306a36Sopenharmony_ci struct caam_ctrl __iomem *ctrl = ctrlpriv->ctrl; 75962306a36Sopenharmony_ci u32 deco_inst, jr_inst; 76062306a36Sopenharmony_ci int i; 76162306a36Sopenharmony_ci 76262306a36Sopenharmony_ci state->mcr = rd_reg32(&ctrl->mcr); 76362306a36Sopenharmony_ci state->scfgr = rd_reg32(&ctrl->scfgr); 76462306a36Sopenharmony_ci 76562306a36Sopenharmony_ci deco_inst = (rd_reg32(&ctrl->perfmon.cha_num_ms) & 76662306a36Sopenharmony_ci CHA_ID_MS_DECO_MASK) >> CHA_ID_MS_DECO_SHIFT; 76762306a36Sopenharmony_ci for (i = 0; i < deco_inst; i++) { 76862306a36Sopenharmony_ci state->deco_mid[i].liodn_ms = 76962306a36Sopenharmony_ci rd_reg32(&ctrl->deco_mid[i].liodn_ms); 77062306a36Sopenharmony_ci state->deco_mid[i].liodn_ls = 77162306a36Sopenharmony_ci rd_reg32(&ctrl->deco_mid[i].liodn_ls); 77262306a36Sopenharmony_ci } 77362306a36Sopenharmony_ci 77462306a36Sopenharmony_ci jr_inst = (rd_reg32(&ctrl->perfmon.cha_num_ms) & 77562306a36Sopenharmony_ci CHA_ID_MS_JR_MASK) >> CHA_ID_MS_JR_SHIFT; 77662306a36Sopenharmony_ci for (i = 0; i < jr_inst; i++) { 77762306a36Sopenharmony_ci state->jr_mid[i].liodn_ms = 77862306a36Sopenharmony_ci rd_reg32(&ctrl->jr_mid[i].liodn_ms); 77962306a36Sopenharmony_ci state->jr_mid[i].liodn_ls = 78062306a36Sopenharmony_ci rd_reg32(&ctrl->jr_mid[i].liodn_ls); 78162306a36Sopenharmony_ci } 78262306a36Sopenharmony_ci} 78362306a36Sopenharmony_ci 78462306a36Sopenharmony_cistatic void caam_state_restore(const struct device *dev) 78562306a36Sopenharmony_ci{ 78662306a36Sopenharmony_ci const struct caam_drv_private *ctrlpriv = dev_get_drvdata(dev); 78762306a36Sopenharmony_ci const struct caam_ctl_state *state = &ctrlpriv->state; 78862306a36Sopenharmony_ci struct caam_ctrl __iomem *ctrl = ctrlpriv->ctrl; 78962306a36Sopenharmony_ci u32 deco_inst, jr_inst; 79062306a36Sopenharmony_ci int i; 79162306a36Sopenharmony_ci 79262306a36Sopenharmony_ci wr_reg32(&ctrl->mcr, state->mcr); 79362306a36Sopenharmony_ci wr_reg32(&ctrl->scfgr, state->scfgr); 79462306a36Sopenharmony_ci 79562306a36Sopenharmony_ci deco_inst = (rd_reg32(&ctrl->perfmon.cha_num_ms) & 79662306a36Sopenharmony_ci CHA_ID_MS_DECO_MASK) >> CHA_ID_MS_DECO_SHIFT; 79762306a36Sopenharmony_ci for (i = 0; i < deco_inst; i++) { 79862306a36Sopenharmony_ci wr_reg32(&ctrl->deco_mid[i].liodn_ms, 79962306a36Sopenharmony_ci state->deco_mid[i].liodn_ms); 80062306a36Sopenharmony_ci wr_reg32(&ctrl->deco_mid[i].liodn_ls, 80162306a36Sopenharmony_ci state->deco_mid[i].liodn_ls); 80262306a36Sopenharmony_ci } 80362306a36Sopenharmony_ci 80462306a36Sopenharmony_ci jr_inst = (rd_reg32(&ctrl->perfmon.cha_num_ms) & 80562306a36Sopenharmony_ci CHA_ID_MS_JR_MASK) >> CHA_ID_MS_JR_SHIFT; 80662306a36Sopenharmony_ci for (i = 0; i < jr_inst; i++) { 80762306a36Sopenharmony_ci wr_reg32(&ctrl->jr_mid[i].liodn_ms, 80862306a36Sopenharmony_ci state->jr_mid[i].liodn_ms); 80962306a36Sopenharmony_ci wr_reg32(&ctrl->jr_mid[i].liodn_ls, 81062306a36Sopenharmony_ci state->jr_mid[i].liodn_ls); 81162306a36Sopenharmony_ci } 81262306a36Sopenharmony_ci 81362306a36Sopenharmony_ci if (ctrlpriv->virt_en == 1) 81462306a36Sopenharmony_ci clrsetbits_32(&ctrl->jrstart, 0, JRSTART_JR0_START | 81562306a36Sopenharmony_ci JRSTART_JR1_START | JRSTART_JR2_START | 81662306a36Sopenharmony_ci JRSTART_JR3_START); 81762306a36Sopenharmony_ci} 81862306a36Sopenharmony_ci 81962306a36Sopenharmony_cistatic int caam_ctrl_suspend(struct device *dev) 82062306a36Sopenharmony_ci{ 82162306a36Sopenharmony_ci const struct caam_drv_private *ctrlpriv = dev_get_drvdata(dev); 82262306a36Sopenharmony_ci 82362306a36Sopenharmony_ci if (ctrlpriv->caam_off_during_pm && !ctrlpriv->optee_en) 82462306a36Sopenharmony_ci caam_state_save(dev); 82562306a36Sopenharmony_ci 82662306a36Sopenharmony_ci return 0; 82762306a36Sopenharmony_ci} 82862306a36Sopenharmony_ci 82962306a36Sopenharmony_cistatic int caam_ctrl_resume(struct device *dev) 83062306a36Sopenharmony_ci{ 83162306a36Sopenharmony_ci struct caam_drv_private *ctrlpriv = dev_get_drvdata(dev); 83262306a36Sopenharmony_ci int ret = 0; 83362306a36Sopenharmony_ci 83462306a36Sopenharmony_ci if (ctrlpriv->caam_off_during_pm && !ctrlpriv->optee_en) { 83562306a36Sopenharmony_ci caam_state_restore(dev); 83662306a36Sopenharmony_ci 83762306a36Sopenharmony_ci /* HW and rng will be reset so deinstantiation can be removed */ 83862306a36Sopenharmony_ci devm_remove_action(dev, devm_deinstantiate_rng, dev); 83962306a36Sopenharmony_ci ret = caam_ctrl_rng_init(dev); 84062306a36Sopenharmony_ci } 84162306a36Sopenharmony_ci 84262306a36Sopenharmony_ci return ret; 84362306a36Sopenharmony_ci} 84462306a36Sopenharmony_ci 84562306a36Sopenharmony_cistatic DEFINE_SIMPLE_DEV_PM_OPS(caam_ctrl_pm_ops, caam_ctrl_suspend, caam_ctrl_resume); 84662306a36Sopenharmony_ci 84762306a36Sopenharmony_ci/* Probe routine for CAAM top (controller) level */ 84862306a36Sopenharmony_cistatic int caam_probe(struct platform_device *pdev) 84962306a36Sopenharmony_ci{ 85062306a36Sopenharmony_ci int ret, ring; 85162306a36Sopenharmony_ci u64 caam_id; 85262306a36Sopenharmony_ci const struct soc_device_attribute *imx_soc_match; 85362306a36Sopenharmony_ci struct device *dev; 85462306a36Sopenharmony_ci struct device_node *nprop, *np; 85562306a36Sopenharmony_ci struct caam_ctrl __iomem *ctrl; 85662306a36Sopenharmony_ci struct caam_drv_private *ctrlpriv; 85762306a36Sopenharmony_ci struct caam_perfmon __iomem *perfmon; 85862306a36Sopenharmony_ci struct dentry *dfs_root; 85962306a36Sopenharmony_ci u32 scfgr, comp_params; 86062306a36Sopenharmony_ci int pg_size; 86162306a36Sopenharmony_ci int BLOCK_OFFSET = 0; 86262306a36Sopenharmony_ci bool reg_access = true; 86362306a36Sopenharmony_ci 86462306a36Sopenharmony_ci ctrlpriv = devm_kzalloc(&pdev->dev, sizeof(*ctrlpriv), GFP_KERNEL); 86562306a36Sopenharmony_ci if (!ctrlpriv) 86662306a36Sopenharmony_ci return -ENOMEM; 86762306a36Sopenharmony_ci 86862306a36Sopenharmony_ci dev = &pdev->dev; 86962306a36Sopenharmony_ci dev_set_drvdata(dev, ctrlpriv); 87062306a36Sopenharmony_ci nprop = pdev->dev.of_node; 87162306a36Sopenharmony_ci 87262306a36Sopenharmony_ci imx_soc_match = soc_device_match(caam_imx_soc_table); 87362306a36Sopenharmony_ci if (!imx_soc_match && of_match_node(imx8m_machine_match, of_root)) 87462306a36Sopenharmony_ci return -EPROBE_DEFER; 87562306a36Sopenharmony_ci 87662306a36Sopenharmony_ci caam_imx = (bool)imx_soc_match; 87762306a36Sopenharmony_ci 87862306a36Sopenharmony_ci ctrlpriv->caam_off_during_pm = caam_imx && caam_off_during_pm(); 87962306a36Sopenharmony_ci 88062306a36Sopenharmony_ci if (imx_soc_match) { 88162306a36Sopenharmony_ci /* 88262306a36Sopenharmony_ci * Until Layerscape and i.MX OP-TEE get in sync, 88362306a36Sopenharmony_ci * only i.MX OP-TEE use cases disallow access to 88462306a36Sopenharmony_ci * caam page 0 (controller) registers. 88562306a36Sopenharmony_ci */ 88662306a36Sopenharmony_ci np = of_find_compatible_node(NULL, NULL, "linaro,optee-tz"); 88762306a36Sopenharmony_ci ctrlpriv->optee_en = !!np; 88862306a36Sopenharmony_ci of_node_put(np); 88962306a36Sopenharmony_ci 89062306a36Sopenharmony_ci reg_access = !ctrlpriv->optee_en; 89162306a36Sopenharmony_ci 89262306a36Sopenharmony_ci if (!imx_soc_match->data) { 89362306a36Sopenharmony_ci dev_err(dev, "No clock data provided for i.MX SoC"); 89462306a36Sopenharmony_ci return -EINVAL; 89562306a36Sopenharmony_ci } 89662306a36Sopenharmony_ci 89762306a36Sopenharmony_ci ret = init_clocks(dev, imx_soc_match->data); 89862306a36Sopenharmony_ci if (ret) 89962306a36Sopenharmony_ci return ret; 90062306a36Sopenharmony_ci } 90162306a36Sopenharmony_ci 90262306a36Sopenharmony_ci 90362306a36Sopenharmony_ci /* Get configuration properties from device tree */ 90462306a36Sopenharmony_ci /* First, get register page */ 90562306a36Sopenharmony_ci ctrl = devm_of_iomap(dev, nprop, 0, NULL); 90662306a36Sopenharmony_ci ret = PTR_ERR_OR_ZERO(ctrl); 90762306a36Sopenharmony_ci if (ret) { 90862306a36Sopenharmony_ci dev_err(dev, "caam: of_iomap() failed\n"); 90962306a36Sopenharmony_ci return ret; 91062306a36Sopenharmony_ci } 91162306a36Sopenharmony_ci 91262306a36Sopenharmony_ci ring = 0; 91362306a36Sopenharmony_ci for_each_available_child_of_node(nprop, np) 91462306a36Sopenharmony_ci if (of_device_is_compatible(np, "fsl,sec-v4.0-job-ring") || 91562306a36Sopenharmony_ci of_device_is_compatible(np, "fsl,sec4.0-job-ring")) { 91662306a36Sopenharmony_ci u32 reg; 91762306a36Sopenharmony_ci 91862306a36Sopenharmony_ci if (of_property_read_u32_index(np, "reg", 0, ®)) { 91962306a36Sopenharmony_ci dev_err(dev, "%s read reg property error\n", 92062306a36Sopenharmony_ci np->full_name); 92162306a36Sopenharmony_ci continue; 92262306a36Sopenharmony_ci } 92362306a36Sopenharmony_ci 92462306a36Sopenharmony_ci ctrlpriv->jr[ring] = (struct caam_job_ring __iomem __force *) 92562306a36Sopenharmony_ci ((__force uint8_t *)ctrl + reg); 92662306a36Sopenharmony_ci 92762306a36Sopenharmony_ci ctrlpriv->total_jobrs++; 92862306a36Sopenharmony_ci ring++; 92962306a36Sopenharmony_ci } 93062306a36Sopenharmony_ci 93162306a36Sopenharmony_ci /* 93262306a36Sopenharmony_ci * Wherever possible, instead of accessing registers from the global page, 93362306a36Sopenharmony_ci * use the alias registers in the first (cf. DT nodes order) 93462306a36Sopenharmony_ci * job ring's page. 93562306a36Sopenharmony_ci */ 93662306a36Sopenharmony_ci perfmon = ring ? (struct caam_perfmon __iomem *)&ctrlpriv->jr[0]->perfmon : 93762306a36Sopenharmony_ci (struct caam_perfmon __iomem *)&ctrl->perfmon; 93862306a36Sopenharmony_ci 93962306a36Sopenharmony_ci caam_little_end = !(bool)(rd_reg32(&perfmon->status) & 94062306a36Sopenharmony_ci (CSTA_PLEND | CSTA_ALT_PLEND)); 94162306a36Sopenharmony_ci comp_params = rd_reg32(&perfmon->comp_parms_ms); 94262306a36Sopenharmony_ci if (reg_access && comp_params & CTPR_MS_PS && 94362306a36Sopenharmony_ci rd_reg32(&ctrl->mcr) & MCFGR_LONG_PTR) 94462306a36Sopenharmony_ci caam_ptr_sz = sizeof(u64); 94562306a36Sopenharmony_ci else 94662306a36Sopenharmony_ci caam_ptr_sz = sizeof(u32); 94762306a36Sopenharmony_ci caam_dpaa2 = !!(comp_params & CTPR_MS_DPAA2); 94862306a36Sopenharmony_ci ctrlpriv->qi_present = !!(comp_params & CTPR_MS_QI_MASK); 94962306a36Sopenharmony_ci 95062306a36Sopenharmony_ci#ifdef CONFIG_CAAM_QI 95162306a36Sopenharmony_ci /* If (DPAA 1.x) QI present, check whether dependencies are available */ 95262306a36Sopenharmony_ci if (ctrlpriv->qi_present && !caam_dpaa2) { 95362306a36Sopenharmony_ci ret = qman_is_probed(); 95462306a36Sopenharmony_ci if (!ret) { 95562306a36Sopenharmony_ci return -EPROBE_DEFER; 95662306a36Sopenharmony_ci } else if (ret < 0) { 95762306a36Sopenharmony_ci dev_err(dev, "failing probe due to qman probe error\n"); 95862306a36Sopenharmony_ci return -ENODEV; 95962306a36Sopenharmony_ci } 96062306a36Sopenharmony_ci 96162306a36Sopenharmony_ci ret = qman_portals_probed(); 96262306a36Sopenharmony_ci if (!ret) { 96362306a36Sopenharmony_ci return -EPROBE_DEFER; 96462306a36Sopenharmony_ci } else if (ret < 0) { 96562306a36Sopenharmony_ci dev_err(dev, "failing probe due to qman portals probe error\n"); 96662306a36Sopenharmony_ci return -ENODEV; 96762306a36Sopenharmony_ci } 96862306a36Sopenharmony_ci } 96962306a36Sopenharmony_ci#endif 97062306a36Sopenharmony_ci 97162306a36Sopenharmony_ci /* Allocating the BLOCK_OFFSET based on the supported page size on 97262306a36Sopenharmony_ci * the platform 97362306a36Sopenharmony_ci */ 97462306a36Sopenharmony_ci pg_size = (comp_params & CTPR_MS_PG_SZ_MASK) >> CTPR_MS_PG_SZ_SHIFT; 97562306a36Sopenharmony_ci if (pg_size == 0) 97662306a36Sopenharmony_ci BLOCK_OFFSET = PG_SIZE_4K; 97762306a36Sopenharmony_ci else 97862306a36Sopenharmony_ci BLOCK_OFFSET = PG_SIZE_64K; 97962306a36Sopenharmony_ci 98062306a36Sopenharmony_ci ctrlpriv->ctrl = (struct caam_ctrl __iomem __force *)ctrl; 98162306a36Sopenharmony_ci ctrlpriv->assure = (struct caam_assurance __iomem __force *) 98262306a36Sopenharmony_ci ((__force uint8_t *)ctrl + 98362306a36Sopenharmony_ci BLOCK_OFFSET * ASSURE_BLOCK_NUMBER 98462306a36Sopenharmony_ci ); 98562306a36Sopenharmony_ci ctrlpriv->deco = (struct caam_deco __iomem __force *) 98662306a36Sopenharmony_ci ((__force uint8_t *)ctrl + 98762306a36Sopenharmony_ci BLOCK_OFFSET * DECO_BLOCK_NUMBER 98862306a36Sopenharmony_ci ); 98962306a36Sopenharmony_ci 99062306a36Sopenharmony_ci /* Get the IRQ of the controller (for security violations only) */ 99162306a36Sopenharmony_ci ctrlpriv->secvio_irq = irq_of_parse_and_map(nprop, 0); 99262306a36Sopenharmony_ci np = of_find_compatible_node(NULL, NULL, "fsl,qoriq-mc"); 99362306a36Sopenharmony_ci ctrlpriv->mc_en = !!np; 99462306a36Sopenharmony_ci of_node_put(np); 99562306a36Sopenharmony_ci 99662306a36Sopenharmony_ci#ifdef CONFIG_FSL_MC_BUS 99762306a36Sopenharmony_ci if (ctrlpriv->mc_en) { 99862306a36Sopenharmony_ci struct fsl_mc_version *mc_version; 99962306a36Sopenharmony_ci 100062306a36Sopenharmony_ci mc_version = fsl_mc_get_version(); 100162306a36Sopenharmony_ci if (mc_version) 100262306a36Sopenharmony_ci ctrlpriv->pr_support = check_version(mc_version, 10, 20, 100362306a36Sopenharmony_ci 0); 100462306a36Sopenharmony_ci else 100562306a36Sopenharmony_ci return -EPROBE_DEFER; 100662306a36Sopenharmony_ci } 100762306a36Sopenharmony_ci#endif 100862306a36Sopenharmony_ci 100962306a36Sopenharmony_ci if (!reg_access) 101062306a36Sopenharmony_ci goto set_dma_mask; 101162306a36Sopenharmony_ci 101262306a36Sopenharmony_ci /* 101362306a36Sopenharmony_ci * Enable DECO watchdogs and, if this is a PHYS_ADDR_T_64BIT kernel, 101462306a36Sopenharmony_ci * long pointers in master configuration register. 101562306a36Sopenharmony_ci * In case of SoCs with Management Complex, MC f/w performs 101662306a36Sopenharmony_ci * the configuration. 101762306a36Sopenharmony_ci */ 101862306a36Sopenharmony_ci if (!ctrlpriv->mc_en) 101962306a36Sopenharmony_ci clrsetbits_32(&ctrl->mcr, MCFGR_AWCACHE_MASK, 102062306a36Sopenharmony_ci MCFGR_AWCACHE_CACH | MCFGR_AWCACHE_BUFF | 102162306a36Sopenharmony_ci MCFGR_WDENABLE | MCFGR_LARGE_BURST); 102262306a36Sopenharmony_ci 102362306a36Sopenharmony_ci handle_imx6_err005766(&ctrl->mcr); 102462306a36Sopenharmony_ci 102562306a36Sopenharmony_ci /* 102662306a36Sopenharmony_ci * Read the Compile Time parameters and SCFGR to determine 102762306a36Sopenharmony_ci * if virtualization is enabled for this platform 102862306a36Sopenharmony_ci */ 102962306a36Sopenharmony_ci scfgr = rd_reg32(&ctrl->scfgr); 103062306a36Sopenharmony_ci 103162306a36Sopenharmony_ci ctrlpriv->virt_en = 0; 103262306a36Sopenharmony_ci if (comp_params & CTPR_MS_VIRT_EN_INCL) { 103362306a36Sopenharmony_ci /* VIRT_EN_INCL = 1 & VIRT_EN_POR = 1 or 103462306a36Sopenharmony_ci * VIRT_EN_INCL = 1 & VIRT_EN_POR = 0 & SCFGR_VIRT_EN = 1 103562306a36Sopenharmony_ci */ 103662306a36Sopenharmony_ci if ((comp_params & CTPR_MS_VIRT_EN_POR) || 103762306a36Sopenharmony_ci (!(comp_params & CTPR_MS_VIRT_EN_POR) && 103862306a36Sopenharmony_ci (scfgr & SCFGR_VIRT_EN))) 103962306a36Sopenharmony_ci ctrlpriv->virt_en = 1; 104062306a36Sopenharmony_ci } else { 104162306a36Sopenharmony_ci /* VIRT_EN_INCL = 0 && VIRT_EN_POR_VALUE = 1 */ 104262306a36Sopenharmony_ci if (comp_params & CTPR_MS_VIRT_EN_POR) 104362306a36Sopenharmony_ci ctrlpriv->virt_en = 1; 104462306a36Sopenharmony_ci } 104562306a36Sopenharmony_ci 104662306a36Sopenharmony_ci if (ctrlpriv->virt_en == 1) 104762306a36Sopenharmony_ci clrsetbits_32(&ctrl->jrstart, 0, JRSTART_JR0_START | 104862306a36Sopenharmony_ci JRSTART_JR1_START | JRSTART_JR2_START | 104962306a36Sopenharmony_ci JRSTART_JR3_START); 105062306a36Sopenharmony_ci 105162306a36Sopenharmony_ciset_dma_mask: 105262306a36Sopenharmony_ci ret = dma_set_mask_and_coherent(dev, caam_get_dma_mask(dev)); 105362306a36Sopenharmony_ci if (ret) { 105462306a36Sopenharmony_ci dev_err(dev, "dma_set_mask_and_coherent failed (%d)\n", ret); 105562306a36Sopenharmony_ci return ret; 105662306a36Sopenharmony_ci } 105762306a36Sopenharmony_ci 105862306a36Sopenharmony_ci ctrlpriv->era = caam_get_era(perfmon); 105962306a36Sopenharmony_ci ctrlpriv->domain = iommu_get_domain_for_dev(dev); 106062306a36Sopenharmony_ci 106162306a36Sopenharmony_ci dfs_root = debugfs_create_dir(dev_name(dev), NULL); 106262306a36Sopenharmony_ci if (IS_ENABLED(CONFIG_DEBUG_FS)) { 106362306a36Sopenharmony_ci ret = devm_add_action_or_reset(dev, caam_remove_debugfs, 106462306a36Sopenharmony_ci dfs_root); 106562306a36Sopenharmony_ci if (ret) 106662306a36Sopenharmony_ci return ret; 106762306a36Sopenharmony_ci } 106862306a36Sopenharmony_ci 106962306a36Sopenharmony_ci caam_debugfs_init(ctrlpriv, perfmon, dfs_root); 107062306a36Sopenharmony_ci 107162306a36Sopenharmony_ci /* Check to see if (DPAA 1.x) QI present. If so, enable */ 107262306a36Sopenharmony_ci if (ctrlpriv->qi_present && !caam_dpaa2) { 107362306a36Sopenharmony_ci ctrlpriv->qi = (struct caam_queue_if __iomem __force *) 107462306a36Sopenharmony_ci ((__force uint8_t *)ctrl + 107562306a36Sopenharmony_ci BLOCK_OFFSET * QI_BLOCK_NUMBER 107662306a36Sopenharmony_ci ); 107762306a36Sopenharmony_ci /* This is all that's required to physically enable QI */ 107862306a36Sopenharmony_ci wr_reg32(&ctrlpriv->qi->qi_control_lo, QICTL_DQEN); 107962306a36Sopenharmony_ci 108062306a36Sopenharmony_ci /* If QMAN driver is present, init CAAM-QI backend */ 108162306a36Sopenharmony_ci#ifdef CONFIG_CAAM_QI 108262306a36Sopenharmony_ci ret = caam_qi_init(pdev); 108362306a36Sopenharmony_ci if (ret) 108462306a36Sopenharmony_ci dev_err(dev, "caam qi i/f init failed: %d\n", ret); 108562306a36Sopenharmony_ci#endif 108662306a36Sopenharmony_ci } 108762306a36Sopenharmony_ci 108862306a36Sopenharmony_ci /* If no QI and no rings specified, quit and go home */ 108962306a36Sopenharmony_ci if ((!ctrlpriv->qi_present) && (!ctrlpriv->total_jobrs)) { 109062306a36Sopenharmony_ci dev_err(dev, "no queues configured, terminating\n"); 109162306a36Sopenharmony_ci return -ENOMEM; 109262306a36Sopenharmony_ci } 109362306a36Sopenharmony_ci 109462306a36Sopenharmony_ci comp_params = rd_reg32(&perfmon->comp_parms_ls); 109562306a36Sopenharmony_ci ctrlpriv->blob_present = !!(comp_params & CTPR_LS_BLOB); 109662306a36Sopenharmony_ci 109762306a36Sopenharmony_ci /* 109862306a36Sopenharmony_ci * Some SoCs like the LS1028A (non-E) indicate CTPR_LS_BLOB support, 109962306a36Sopenharmony_ci * but fail when actually using it due to missing AES support, so 110062306a36Sopenharmony_ci * check both here. 110162306a36Sopenharmony_ci */ 110262306a36Sopenharmony_ci if (ctrlpriv->era < 10) { 110362306a36Sopenharmony_ci ctrlpriv->blob_present = ctrlpriv->blob_present && 110462306a36Sopenharmony_ci (rd_reg32(&perfmon->cha_num_ls) & CHA_ID_LS_AES_MASK); 110562306a36Sopenharmony_ci } else { 110662306a36Sopenharmony_ci struct version_regs __iomem *vreg; 110762306a36Sopenharmony_ci 110862306a36Sopenharmony_ci vreg = ctrlpriv->total_jobrs ? 110962306a36Sopenharmony_ci (struct version_regs __iomem *)&ctrlpriv->jr[0]->vreg : 111062306a36Sopenharmony_ci (struct version_regs __iomem *)&ctrl->vreg; 111162306a36Sopenharmony_ci 111262306a36Sopenharmony_ci ctrlpriv->blob_present = ctrlpriv->blob_present && 111362306a36Sopenharmony_ci (rd_reg32(&vreg->aesa) & CHA_VER_MISC_AES_NUM_MASK); 111462306a36Sopenharmony_ci } 111562306a36Sopenharmony_ci 111662306a36Sopenharmony_ci if (reg_access) { 111762306a36Sopenharmony_ci ret = caam_ctrl_rng_init(dev); 111862306a36Sopenharmony_ci if (ret) 111962306a36Sopenharmony_ci return ret; 112062306a36Sopenharmony_ci } 112162306a36Sopenharmony_ci 112262306a36Sopenharmony_ci caam_id = (u64)rd_reg32(&perfmon->caam_id_ms) << 32 | 112362306a36Sopenharmony_ci (u64)rd_reg32(&perfmon->caam_id_ls); 112462306a36Sopenharmony_ci 112562306a36Sopenharmony_ci /* Report "alive" for developer to see */ 112662306a36Sopenharmony_ci dev_info(dev, "device ID = 0x%016llx (Era %d)\n", caam_id, 112762306a36Sopenharmony_ci ctrlpriv->era); 112862306a36Sopenharmony_ci dev_info(dev, "job rings = %d, qi = %d\n", 112962306a36Sopenharmony_ci ctrlpriv->total_jobrs, ctrlpriv->qi_present); 113062306a36Sopenharmony_ci 113162306a36Sopenharmony_ci ret = devm_of_platform_populate(dev); 113262306a36Sopenharmony_ci if (ret) 113362306a36Sopenharmony_ci dev_err(dev, "JR platform devices creation error\n"); 113462306a36Sopenharmony_ci 113562306a36Sopenharmony_ci return ret; 113662306a36Sopenharmony_ci} 113762306a36Sopenharmony_ci 113862306a36Sopenharmony_cistatic struct platform_driver caam_driver = { 113962306a36Sopenharmony_ci .driver = { 114062306a36Sopenharmony_ci .name = "caam", 114162306a36Sopenharmony_ci .of_match_table = caam_match, 114262306a36Sopenharmony_ci .pm = pm_ptr(&caam_ctrl_pm_ops), 114362306a36Sopenharmony_ci }, 114462306a36Sopenharmony_ci .probe = caam_probe, 114562306a36Sopenharmony_ci}; 114662306a36Sopenharmony_ci 114762306a36Sopenharmony_cimodule_platform_driver(caam_driver); 114862306a36Sopenharmony_ci 114962306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 115062306a36Sopenharmony_ciMODULE_DESCRIPTION("FSL CAAM request backend"); 115162306a36Sopenharmony_ciMODULE_AUTHOR("Freescale Semiconductor - NMG/STC"); 1152