18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+ 28c2ecf20Sopenharmony_ci/* * CAAM control-plane driver backend 38c2ecf20Sopenharmony_ci * Controller-level driver, kernel property detection, initialization 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright 2008-2012 Freescale Semiconductor, Inc. 68c2ecf20Sopenharmony_ci * Copyright 2018-2019 NXP 78c2ecf20Sopenharmony_ci */ 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_ci#include <linux/device.h> 108c2ecf20Sopenharmony_ci#include <linux/of_address.h> 118c2ecf20Sopenharmony_ci#include <linux/of_irq.h> 128c2ecf20Sopenharmony_ci#include <linux/sys_soc.h> 138c2ecf20Sopenharmony_ci#include <linux/fsl/mc.h> 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_ci#include "compat.h" 168c2ecf20Sopenharmony_ci#include "debugfs.h" 178c2ecf20Sopenharmony_ci#include "regs.h" 188c2ecf20Sopenharmony_ci#include "intern.h" 198c2ecf20Sopenharmony_ci#include "jr.h" 208c2ecf20Sopenharmony_ci#include "desc_constr.h" 218c2ecf20Sopenharmony_ci#include "ctrl.h" 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_cibool caam_dpaa2; 248c2ecf20Sopenharmony_ciEXPORT_SYMBOL(caam_dpaa2); 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ci#ifdef CONFIG_CAAM_QI 278c2ecf20Sopenharmony_ci#include "qi.h" 288c2ecf20Sopenharmony_ci#endif 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_ci/* 318c2ecf20Sopenharmony_ci * Descriptor to instantiate RNG State Handle 0 in normal mode and 328c2ecf20Sopenharmony_ci * load the JDKEK, TDKEK and TDSK registers 338c2ecf20Sopenharmony_ci */ 348c2ecf20Sopenharmony_cistatic void build_instantiation_desc(u32 *desc, int handle, int do_sk) 358c2ecf20Sopenharmony_ci{ 368c2ecf20Sopenharmony_ci u32 *jump_cmd, op_flags; 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci init_job_desc(desc, 0); 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_ci op_flags = OP_TYPE_CLASS1_ALG | OP_ALG_ALGSEL_RNG | 418c2ecf20Sopenharmony_ci (handle << OP_ALG_AAI_SHIFT) | OP_ALG_AS_INIT | 428c2ecf20Sopenharmony_ci OP_ALG_PR_ON; 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_ci /* INIT RNG in non-test mode */ 458c2ecf20Sopenharmony_ci append_operation(desc, op_flags); 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_ci if (!handle && do_sk) { 488c2ecf20Sopenharmony_ci /* 498c2ecf20Sopenharmony_ci * For SH0, Secure Keys must be generated as well 508c2ecf20Sopenharmony_ci */ 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_ci /* wait for done */ 538c2ecf20Sopenharmony_ci jump_cmd = append_jump(desc, JUMP_CLASS_CLASS1); 548c2ecf20Sopenharmony_ci set_jump_tgt_here(desc, jump_cmd); 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_ci /* 578c2ecf20Sopenharmony_ci * load 1 to clear written reg: 588c2ecf20Sopenharmony_ci * resets the done interrupt and returns the RNG to idle. 598c2ecf20Sopenharmony_ci */ 608c2ecf20Sopenharmony_ci append_load_imm_u32(desc, 1, LDST_SRCDST_WORD_CLRW); 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_ci /* Initialize State Handle */ 638c2ecf20Sopenharmony_ci append_operation(desc, OP_TYPE_CLASS1_ALG | OP_ALG_ALGSEL_RNG | 648c2ecf20Sopenharmony_ci OP_ALG_AAI_RNG4_SK); 658c2ecf20Sopenharmony_ci } 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci append_jump(desc, JUMP_CLASS_CLASS1 | JUMP_TYPE_HALT); 688c2ecf20Sopenharmony_ci} 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_ci/* Descriptor for deinstantiation of State Handle 0 of the RNG block. */ 718c2ecf20Sopenharmony_cistatic void build_deinstantiation_desc(u32 *desc, int handle) 728c2ecf20Sopenharmony_ci{ 738c2ecf20Sopenharmony_ci init_job_desc(desc, 0); 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ci /* Uninstantiate State Handle 0 */ 768c2ecf20Sopenharmony_ci append_operation(desc, OP_TYPE_CLASS1_ALG | OP_ALG_ALGSEL_RNG | 778c2ecf20Sopenharmony_ci (handle << OP_ALG_AAI_SHIFT) | OP_ALG_AS_INITFINAL); 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_ci append_jump(desc, JUMP_CLASS_CLASS1 | JUMP_TYPE_HALT); 808c2ecf20Sopenharmony_ci} 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ci/* 838c2ecf20Sopenharmony_ci * run_descriptor_deco0 - runs a descriptor on DECO0, under direct control of 848c2ecf20Sopenharmony_ci * the software (no JR/QI used). 858c2ecf20Sopenharmony_ci * @ctrldev - pointer to device 868c2ecf20Sopenharmony_ci * @status - descriptor status, after being run 878c2ecf20Sopenharmony_ci * 888c2ecf20Sopenharmony_ci * Return: - 0 if no error occurred 898c2ecf20Sopenharmony_ci * - -ENODEV if the DECO couldn't be acquired 908c2ecf20Sopenharmony_ci * - -EAGAIN if an error occurred while executing the descriptor 918c2ecf20Sopenharmony_ci */ 928c2ecf20Sopenharmony_cistatic inline int run_descriptor_deco0(struct device *ctrldev, u32 *desc, 938c2ecf20Sopenharmony_ci u32 *status) 948c2ecf20Sopenharmony_ci{ 958c2ecf20Sopenharmony_ci struct caam_drv_private *ctrlpriv = dev_get_drvdata(ctrldev); 968c2ecf20Sopenharmony_ci struct caam_ctrl __iomem *ctrl = ctrlpriv->ctrl; 978c2ecf20Sopenharmony_ci struct caam_deco __iomem *deco = ctrlpriv->deco; 988c2ecf20Sopenharmony_ci unsigned int timeout = 100000; 998c2ecf20Sopenharmony_ci u32 deco_dbg_reg, deco_state, flags; 1008c2ecf20Sopenharmony_ci int i; 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_ci if (ctrlpriv->virt_en == 1 || 1048c2ecf20Sopenharmony_ci /* 1058c2ecf20Sopenharmony_ci * Apparently on i.MX8M{Q,M,N,P} it doesn't matter if virt_en == 1 1068c2ecf20Sopenharmony_ci * and the following steps should be performed regardless 1078c2ecf20Sopenharmony_ci */ 1088c2ecf20Sopenharmony_ci of_machine_is_compatible("fsl,imx8mq") || 1098c2ecf20Sopenharmony_ci of_machine_is_compatible("fsl,imx8mm") || 1108c2ecf20Sopenharmony_ci of_machine_is_compatible("fsl,imx8mn") || 1118c2ecf20Sopenharmony_ci of_machine_is_compatible("fsl,imx8mp")) { 1128c2ecf20Sopenharmony_ci clrsetbits_32(&ctrl->deco_rsr, 0, DECORSR_JR0); 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ci while (!(rd_reg32(&ctrl->deco_rsr) & DECORSR_VALID) && 1158c2ecf20Sopenharmony_ci --timeout) 1168c2ecf20Sopenharmony_ci cpu_relax(); 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_ci timeout = 100000; 1198c2ecf20Sopenharmony_ci } 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_ci clrsetbits_32(&ctrl->deco_rq, 0, DECORR_RQD0ENABLE); 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci while (!(rd_reg32(&ctrl->deco_rq) & DECORR_DEN0) && 1248c2ecf20Sopenharmony_ci --timeout) 1258c2ecf20Sopenharmony_ci cpu_relax(); 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_ci if (!timeout) { 1288c2ecf20Sopenharmony_ci dev_err(ctrldev, "failed to acquire DECO 0\n"); 1298c2ecf20Sopenharmony_ci clrsetbits_32(&ctrl->deco_rq, DECORR_RQD0ENABLE, 0); 1308c2ecf20Sopenharmony_ci return -ENODEV; 1318c2ecf20Sopenharmony_ci } 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ci for (i = 0; i < desc_len(desc); i++) 1348c2ecf20Sopenharmony_ci wr_reg32(&deco->descbuf[i], caam32_to_cpu(*(desc + i))); 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_ci flags = DECO_JQCR_WHL; 1378c2ecf20Sopenharmony_ci /* 1388c2ecf20Sopenharmony_ci * If the descriptor length is longer than 4 words, then the 1398c2ecf20Sopenharmony_ci * FOUR bit in JRCTRL register must be set. 1408c2ecf20Sopenharmony_ci */ 1418c2ecf20Sopenharmony_ci if (desc_len(desc) >= 4) 1428c2ecf20Sopenharmony_ci flags |= DECO_JQCR_FOUR; 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_ci /* Instruct the DECO to execute it */ 1458c2ecf20Sopenharmony_ci clrsetbits_32(&deco->jr_ctl_hi, 0, flags); 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_ci timeout = 10000000; 1488c2ecf20Sopenharmony_ci do { 1498c2ecf20Sopenharmony_ci deco_dbg_reg = rd_reg32(&deco->desc_dbg); 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_ci if (ctrlpriv->era < 10) 1528c2ecf20Sopenharmony_ci deco_state = (deco_dbg_reg & DESC_DBG_DECO_STAT_MASK) >> 1538c2ecf20Sopenharmony_ci DESC_DBG_DECO_STAT_SHIFT; 1548c2ecf20Sopenharmony_ci else 1558c2ecf20Sopenharmony_ci deco_state = (rd_reg32(&deco->dbg_exec) & 1568c2ecf20Sopenharmony_ci DESC_DER_DECO_STAT_MASK) >> 1578c2ecf20Sopenharmony_ci DESC_DER_DECO_STAT_SHIFT; 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_ci /* 1608c2ecf20Sopenharmony_ci * If an error occurred in the descriptor, then 1618c2ecf20Sopenharmony_ci * the DECO status field will be set to 0x0D 1628c2ecf20Sopenharmony_ci */ 1638c2ecf20Sopenharmony_ci if (deco_state == DECO_STAT_HOST_ERR) 1648c2ecf20Sopenharmony_ci break; 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_ci cpu_relax(); 1678c2ecf20Sopenharmony_ci } while ((deco_dbg_reg & DESC_DBG_DECO_STAT_VALID) && --timeout); 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_ci *status = rd_reg32(&deco->op_status_hi) & 1708c2ecf20Sopenharmony_ci DECO_OP_STATUS_HI_ERR_MASK; 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_ci if (ctrlpriv->virt_en == 1) 1738c2ecf20Sopenharmony_ci clrsetbits_32(&ctrl->deco_rsr, DECORSR_JR0, 0); 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_ci /* Mark the DECO as free */ 1768c2ecf20Sopenharmony_ci clrsetbits_32(&ctrl->deco_rq, DECORR_RQD0ENABLE, 0); 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_ci if (!timeout) 1798c2ecf20Sopenharmony_ci return -EAGAIN; 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_ci return 0; 1828c2ecf20Sopenharmony_ci} 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_ci/* 1858c2ecf20Sopenharmony_ci * deinstantiate_rng - builds and executes a descriptor on DECO0, 1868c2ecf20Sopenharmony_ci * which deinitializes the RNG block. 1878c2ecf20Sopenharmony_ci * @ctrldev - pointer to device 1888c2ecf20Sopenharmony_ci * @state_handle_mask - bitmask containing the instantiation status 1898c2ecf20Sopenharmony_ci * for the RNG4 state handles which exist in 1908c2ecf20Sopenharmony_ci * the RNG4 block: 1 if it's been instantiated 1918c2ecf20Sopenharmony_ci * 1928c2ecf20Sopenharmony_ci * Return: - 0 if no error occurred 1938c2ecf20Sopenharmony_ci * - -ENOMEM if there isn't enough memory to allocate the descriptor 1948c2ecf20Sopenharmony_ci * - -ENODEV if DECO0 couldn't be acquired 1958c2ecf20Sopenharmony_ci * - -EAGAIN if an error occurred when executing the descriptor 1968c2ecf20Sopenharmony_ci */ 1978c2ecf20Sopenharmony_cistatic int deinstantiate_rng(struct device *ctrldev, int state_handle_mask) 1988c2ecf20Sopenharmony_ci{ 1998c2ecf20Sopenharmony_ci u32 *desc, status; 2008c2ecf20Sopenharmony_ci int sh_idx, ret = 0; 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_ci desc = kmalloc(CAAM_CMD_SZ * 3, GFP_KERNEL | GFP_DMA); 2038c2ecf20Sopenharmony_ci if (!desc) 2048c2ecf20Sopenharmony_ci return -ENOMEM; 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_ci for (sh_idx = 0; sh_idx < RNG4_MAX_HANDLES; sh_idx++) { 2078c2ecf20Sopenharmony_ci /* 2088c2ecf20Sopenharmony_ci * If the corresponding bit is set, then it means the state 2098c2ecf20Sopenharmony_ci * handle was initialized by us, and thus it needs to be 2108c2ecf20Sopenharmony_ci * deinitialized as well 2118c2ecf20Sopenharmony_ci */ 2128c2ecf20Sopenharmony_ci if ((1 << sh_idx) & state_handle_mask) { 2138c2ecf20Sopenharmony_ci /* 2148c2ecf20Sopenharmony_ci * Create the descriptor for deinstantating this state 2158c2ecf20Sopenharmony_ci * handle 2168c2ecf20Sopenharmony_ci */ 2178c2ecf20Sopenharmony_ci build_deinstantiation_desc(desc, sh_idx); 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_ci /* Try to run it through DECO0 */ 2208c2ecf20Sopenharmony_ci ret = run_descriptor_deco0(ctrldev, desc, &status); 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_ci if (ret || 2238c2ecf20Sopenharmony_ci (status && status != JRSTA_SSRC_JUMP_HALT_CC)) { 2248c2ecf20Sopenharmony_ci dev_err(ctrldev, 2258c2ecf20Sopenharmony_ci "Failed to deinstantiate RNG4 SH%d\n", 2268c2ecf20Sopenharmony_ci sh_idx); 2278c2ecf20Sopenharmony_ci break; 2288c2ecf20Sopenharmony_ci } 2298c2ecf20Sopenharmony_ci dev_info(ctrldev, "Deinstantiated RNG4 SH%d\n", sh_idx); 2308c2ecf20Sopenharmony_ci } 2318c2ecf20Sopenharmony_ci } 2328c2ecf20Sopenharmony_ci 2338c2ecf20Sopenharmony_ci kfree(desc); 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_ci return ret; 2368c2ecf20Sopenharmony_ci} 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_cistatic void devm_deinstantiate_rng(void *data) 2398c2ecf20Sopenharmony_ci{ 2408c2ecf20Sopenharmony_ci struct device *ctrldev = data; 2418c2ecf20Sopenharmony_ci struct caam_drv_private *ctrlpriv = dev_get_drvdata(ctrldev); 2428c2ecf20Sopenharmony_ci 2438c2ecf20Sopenharmony_ci /* 2448c2ecf20Sopenharmony_ci * De-initialize RNG state handles initialized by this driver. 2458c2ecf20Sopenharmony_ci * In case of SoCs with Management Complex, RNG is managed by MC f/w. 2468c2ecf20Sopenharmony_ci */ 2478c2ecf20Sopenharmony_ci if (ctrlpriv->rng4_sh_init) 2488c2ecf20Sopenharmony_ci deinstantiate_rng(ctrldev, ctrlpriv->rng4_sh_init); 2498c2ecf20Sopenharmony_ci} 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_ci/* 2528c2ecf20Sopenharmony_ci * instantiate_rng - builds and executes a descriptor on DECO0, 2538c2ecf20Sopenharmony_ci * which initializes the RNG block. 2548c2ecf20Sopenharmony_ci * @ctrldev - pointer to device 2558c2ecf20Sopenharmony_ci * @state_handle_mask - bitmask containing the instantiation status 2568c2ecf20Sopenharmony_ci * for the RNG4 state handles which exist in 2578c2ecf20Sopenharmony_ci * the RNG4 block: 1 if it's been instantiated 2588c2ecf20Sopenharmony_ci * by an external entry, 0 otherwise. 2598c2ecf20Sopenharmony_ci * @gen_sk - generate data to be loaded into the JDKEK, TDKEK and TDSK; 2608c2ecf20Sopenharmony_ci * Caution: this can be done only once; if the keys need to be 2618c2ecf20Sopenharmony_ci * regenerated, a POR is required 2628c2ecf20Sopenharmony_ci * 2638c2ecf20Sopenharmony_ci * Return: - 0 if no error occurred 2648c2ecf20Sopenharmony_ci * - -ENOMEM if there isn't enough memory to allocate the descriptor 2658c2ecf20Sopenharmony_ci * - -ENODEV if DECO0 couldn't be acquired 2668c2ecf20Sopenharmony_ci * - -EAGAIN if an error occurred when executing the descriptor 2678c2ecf20Sopenharmony_ci * f.i. there was a RNG hardware error due to not "good enough" 2688c2ecf20Sopenharmony_ci * entropy being acquired. 2698c2ecf20Sopenharmony_ci */ 2708c2ecf20Sopenharmony_cistatic int instantiate_rng(struct device *ctrldev, int state_handle_mask, 2718c2ecf20Sopenharmony_ci int gen_sk) 2728c2ecf20Sopenharmony_ci{ 2738c2ecf20Sopenharmony_ci struct caam_drv_private *ctrlpriv = dev_get_drvdata(ctrldev); 2748c2ecf20Sopenharmony_ci struct caam_ctrl __iomem *ctrl; 2758c2ecf20Sopenharmony_ci u32 *desc, status = 0, rdsta_val; 2768c2ecf20Sopenharmony_ci int ret = 0, sh_idx; 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_ci ctrl = (struct caam_ctrl __iomem *)ctrlpriv->ctrl; 2798c2ecf20Sopenharmony_ci desc = kmalloc(CAAM_CMD_SZ * 7, GFP_KERNEL | GFP_DMA); 2808c2ecf20Sopenharmony_ci if (!desc) 2818c2ecf20Sopenharmony_ci return -ENOMEM; 2828c2ecf20Sopenharmony_ci 2838c2ecf20Sopenharmony_ci for (sh_idx = 0; sh_idx < RNG4_MAX_HANDLES; sh_idx++) { 2848c2ecf20Sopenharmony_ci const u32 rdsta_if = RDSTA_IF0 << sh_idx; 2858c2ecf20Sopenharmony_ci const u32 rdsta_pr = RDSTA_PR0 << sh_idx; 2868c2ecf20Sopenharmony_ci const u32 rdsta_mask = rdsta_if | rdsta_pr; 2878c2ecf20Sopenharmony_ci 2888c2ecf20Sopenharmony_ci /* Clear the contents before using the descriptor */ 2898c2ecf20Sopenharmony_ci memset(desc, 0x00, CAAM_CMD_SZ * 7); 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_ci /* 2928c2ecf20Sopenharmony_ci * If the corresponding bit is set, this state handle 2938c2ecf20Sopenharmony_ci * was initialized by somebody else, so it's left alone. 2948c2ecf20Sopenharmony_ci */ 2958c2ecf20Sopenharmony_ci if (rdsta_if & state_handle_mask) { 2968c2ecf20Sopenharmony_ci if (rdsta_pr & state_handle_mask) 2978c2ecf20Sopenharmony_ci continue; 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_ci dev_info(ctrldev, 3008c2ecf20Sopenharmony_ci "RNG4 SH%d was previously instantiated without prediction resistance. Tearing it down\n", 3018c2ecf20Sopenharmony_ci sh_idx); 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_ci ret = deinstantiate_rng(ctrldev, rdsta_if); 3048c2ecf20Sopenharmony_ci if (ret) 3058c2ecf20Sopenharmony_ci break; 3068c2ecf20Sopenharmony_ci } 3078c2ecf20Sopenharmony_ci 3088c2ecf20Sopenharmony_ci /* Create the descriptor for instantiating RNG State Handle */ 3098c2ecf20Sopenharmony_ci build_instantiation_desc(desc, sh_idx, gen_sk); 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_ci /* Try to run it through DECO0 */ 3128c2ecf20Sopenharmony_ci ret = run_descriptor_deco0(ctrldev, desc, &status); 3138c2ecf20Sopenharmony_ci 3148c2ecf20Sopenharmony_ci /* 3158c2ecf20Sopenharmony_ci * If ret is not 0, or descriptor status is not 0, then 3168c2ecf20Sopenharmony_ci * something went wrong. No need to try the next state 3178c2ecf20Sopenharmony_ci * handle (if available), bail out here. 3188c2ecf20Sopenharmony_ci * Also, if for some reason, the State Handle didn't get 3198c2ecf20Sopenharmony_ci * instantiated although the descriptor has finished 3208c2ecf20Sopenharmony_ci * without any error (HW optimizations for later 3218c2ecf20Sopenharmony_ci * CAAM eras), then try again. 3228c2ecf20Sopenharmony_ci */ 3238c2ecf20Sopenharmony_ci if (ret) 3248c2ecf20Sopenharmony_ci break; 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_ci rdsta_val = rd_reg32(&ctrl->r4tst[0].rdsta) & RDSTA_MASK; 3278c2ecf20Sopenharmony_ci if ((status && status != JRSTA_SSRC_JUMP_HALT_CC) || 3288c2ecf20Sopenharmony_ci (rdsta_val & rdsta_mask) != rdsta_mask) { 3298c2ecf20Sopenharmony_ci ret = -EAGAIN; 3308c2ecf20Sopenharmony_ci break; 3318c2ecf20Sopenharmony_ci } 3328c2ecf20Sopenharmony_ci 3338c2ecf20Sopenharmony_ci dev_info(ctrldev, "Instantiated RNG4 SH%d\n", sh_idx); 3348c2ecf20Sopenharmony_ci } 3358c2ecf20Sopenharmony_ci 3368c2ecf20Sopenharmony_ci kfree(desc); 3378c2ecf20Sopenharmony_ci 3388c2ecf20Sopenharmony_ci if (ret) 3398c2ecf20Sopenharmony_ci return ret; 3408c2ecf20Sopenharmony_ci 3418c2ecf20Sopenharmony_ci return devm_add_action_or_reset(ctrldev, devm_deinstantiate_rng, ctrldev); 3428c2ecf20Sopenharmony_ci} 3438c2ecf20Sopenharmony_ci 3448c2ecf20Sopenharmony_ci/* 3458c2ecf20Sopenharmony_ci * kick_trng - sets the various parameters for enabling the initialization 3468c2ecf20Sopenharmony_ci * of the RNG4 block in CAAM 3478c2ecf20Sopenharmony_ci * @pdev - pointer to the platform device 3488c2ecf20Sopenharmony_ci * @ent_delay - Defines the length (in system clocks) of each entropy sample. 3498c2ecf20Sopenharmony_ci */ 3508c2ecf20Sopenharmony_cistatic void kick_trng(struct platform_device *pdev, int ent_delay) 3518c2ecf20Sopenharmony_ci{ 3528c2ecf20Sopenharmony_ci struct device *ctrldev = &pdev->dev; 3538c2ecf20Sopenharmony_ci struct caam_drv_private *ctrlpriv = dev_get_drvdata(ctrldev); 3548c2ecf20Sopenharmony_ci struct caam_ctrl __iomem *ctrl; 3558c2ecf20Sopenharmony_ci struct rng4tst __iomem *r4tst; 3568c2ecf20Sopenharmony_ci u32 val; 3578c2ecf20Sopenharmony_ci 3588c2ecf20Sopenharmony_ci ctrl = (struct caam_ctrl __iomem *)ctrlpriv->ctrl; 3598c2ecf20Sopenharmony_ci r4tst = &ctrl->r4tst[0]; 3608c2ecf20Sopenharmony_ci 3618c2ecf20Sopenharmony_ci /* 3628c2ecf20Sopenharmony_ci * Setting both RTMCTL:PRGM and RTMCTL:TRNG_ACC causes TRNG to 3638c2ecf20Sopenharmony_ci * properly invalidate the entropy in the entropy register and 3648c2ecf20Sopenharmony_ci * force re-generation. 3658c2ecf20Sopenharmony_ci */ 3668c2ecf20Sopenharmony_ci clrsetbits_32(&r4tst->rtmctl, 0, RTMCTL_PRGM | RTMCTL_ACC); 3678c2ecf20Sopenharmony_ci 3688c2ecf20Sopenharmony_ci /* 3698c2ecf20Sopenharmony_ci * Performance-wise, it does not make sense to 3708c2ecf20Sopenharmony_ci * set the delay to a value that is lower 3718c2ecf20Sopenharmony_ci * than the last one that worked (i.e. the state handles 3728c2ecf20Sopenharmony_ci * were instantiated properly. Thus, instead of wasting 3738c2ecf20Sopenharmony_ci * time trying to set the values controlling the sample 3748c2ecf20Sopenharmony_ci * frequency, the function simply returns. 3758c2ecf20Sopenharmony_ci */ 3768c2ecf20Sopenharmony_ci val = (rd_reg32(&r4tst->rtsdctl) & RTSDCTL_ENT_DLY_MASK) 3778c2ecf20Sopenharmony_ci >> RTSDCTL_ENT_DLY_SHIFT; 3788c2ecf20Sopenharmony_ci if (ent_delay <= val) 3798c2ecf20Sopenharmony_ci goto start_rng; 3808c2ecf20Sopenharmony_ci 3818c2ecf20Sopenharmony_ci val = rd_reg32(&r4tst->rtsdctl); 3828c2ecf20Sopenharmony_ci val = (val & ~RTSDCTL_ENT_DLY_MASK) | 3838c2ecf20Sopenharmony_ci (ent_delay << RTSDCTL_ENT_DLY_SHIFT); 3848c2ecf20Sopenharmony_ci wr_reg32(&r4tst->rtsdctl, val); 3858c2ecf20Sopenharmony_ci /* min. freq. count, equal to 1/4 of the entropy sample length */ 3868c2ecf20Sopenharmony_ci wr_reg32(&r4tst->rtfrqmin, ent_delay >> 2); 3878c2ecf20Sopenharmony_ci /* disable maximum frequency count */ 3888c2ecf20Sopenharmony_ci wr_reg32(&r4tst->rtfrqmax, RTFRQMAX_DISABLE); 3898c2ecf20Sopenharmony_ci /* read the control register */ 3908c2ecf20Sopenharmony_ci val = rd_reg32(&r4tst->rtmctl); 3918c2ecf20Sopenharmony_cistart_rng: 3928c2ecf20Sopenharmony_ci /* 3938c2ecf20Sopenharmony_ci * select raw sampling in both entropy shifter 3948c2ecf20Sopenharmony_ci * and statistical checker; ; put RNG4 into run mode 3958c2ecf20Sopenharmony_ci */ 3968c2ecf20Sopenharmony_ci clrsetbits_32(&r4tst->rtmctl, RTMCTL_PRGM | RTMCTL_ACC, 3978c2ecf20Sopenharmony_ci RTMCTL_SAMP_MODE_RAW_ES_SC); 3988c2ecf20Sopenharmony_ci} 3998c2ecf20Sopenharmony_ci 4008c2ecf20Sopenharmony_cistatic int caam_get_era_from_hw(struct caam_ctrl __iomem *ctrl) 4018c2ecf20Sopenharmony_ci{ 4028c2ecf20Sopenharmony_ci static const struct { 4038c2ecf20Sopenharmony_ci u16 ip_id; 4048c2ecf20Sopenharmony_ci u8 maj_rev; 4058c2ecf20Sopenharmony_ci u8 era; 4068c2ecf20Sopenharmony_ci } id[] = { 4078c2ecf20Sopenharmony_ci {0x0A10, 1, 1}, 4088c2ecf20Sopenharmony_ci {0x0A10, 2, 2}, 4098c2ecf20Sopenharmony_ci {0x0A12, 1, 3}, 4108c2ecf20Sopenharmony_ci {0x0A14, 1, 3}, 4118c2ecf20Sopenharmony_ci {0x0A14, 2, 4}, 4128c2ecf20Sopenharmony_ci {0x0A16, 1, 4}, 4138c2ecf20Sopenharmony_ci {0x0A10, 3, 4}, 4148c2ecf20Sopenharmony_ci {0x0A11, 1, 4}, 4158c2ecf20Sopenharmony_ci {0x0A18, 1, 4}, 4168c2ecf20Sopenharmony_ci {0x0A11, 2, 5}, 4178c2ecf20Sopenharmony_ci {0x0A12, 2, 5}, 4188c2ecf20Sopenharmony_ci {0x0A13, 1, 5}, 4198c2ecf20Sopenharmony_ci {0x0A1C, 1, 5} 4208c2ecf20Sopenharmony_ci }; 4218c2ecf20Sopenharmony_ci u32 ccbvid, id_ms; 4228c2ecf20Sopenharmony_ci u8 maj_rev, era; 4238c2ecf20Sopenharmony_ci u16 ip_id; 4248c2ecf20Sopenharmony_ci int i; 4258c2ecf20Sopenharmony_ci 4268c2ecf20Sopenharmony_ci ccbvid = rd_reg32(&ctrl->perfmon.ccb_id); 4278c2ecf20Sopenharmony_ci era = (ccbvid & CCBVID_ERA_MASK) >> CCBVID_ERA_SHIFT; 4288c2ecf20Sopenharmony_ci if (era) /* This is '0' prior to CAAM ERA-6 */ 4298c2ecf20Sopenharmony_ci return era; 4308c2ecf20Sopenharmony_ci 4318c2ecf20Sopenharmony_ci id_ms = rd_reg32(&ctrl->perfmon.caam_id_ms); 4328c2ecf20Sopenharmony_ci ip_id = (id_ms & SECVID_MS_IPID_MASK) >> SECVID_MS_IPID_SHIFT; 4338c2ecf20Sopenharmony_ci maj_rev = (id_ms & SECVID_MS_MAJ_REV_MASK) >> SECVID_MS_MAJ_REV_SHIFT; 4348c2ecf20Sopenharmony_ci 4358c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(id); i++) 4368c2ecf20Sopenharmony_ci if (id[i].ip_id == ip_id && id[i].maj_rev == maj_rev) 4378c2ecf20Sopenharmony_ci return id[i].era; 4388c2ecf20Sopenharmony_ci 4398c2ecf20Sopenharmony_ci return -ENOTSUPP; 4408c2ecf20Sopenharmony_ci} 4418c2ecf20Sopenharmony_ci 4428c2ecf20Sopenharmony_ci/** 4438c2ecf20Sopenharmony_ci * caam_get_era() - Return the ERA of the SEC on SoC, based 4448c2ecf20Sopenharmony_ci * on "sec-era" optional property in the DTS. This property is updated 4458c2ecf20Sopenharmony_ci * by u-boot. 4468c2ecf20Sopenharmony_ci * In case this property is not passed an attempt to retrieve the CAAM 4478c2ecf20Sopenharmony_ci * era via register reads will be made. 4488c2ecf20Sopenharmony_ci * 4498c2ecf20Sopenharmony_ci * @ctrl: controller region 4508c2ecf20Sopenharmony_ci */ 4518c2ecf20Sopenharmony_cistatic int caam_get_era(struct caam_ctrl __iomem *ctrl) 4528c2ecf20Sopenharmony_ci{ 4538c2ecf20Sopenharmony_ci struct device_node *caam_node; 4548c2ecf20Sopenharmony_ci int ret; 4558c2ecf20Sopenharmony_ci u32 prop; 4568c2ecf20Sopenharmony_ci 4578c2ecf20Sopenharmony_ci caam_node = of_find_compatible_node(NULL, NULL, "fsl,sec-v4.0"); 4588c2ecf20Sopenharmony_ci ret = of_property_read_u32(caam_node, "fsl,sec-era", &prop); 4598c2ecf20Sopenharmony_ci of_node_put(caam_node); 4608c2ecf20Sopenharmony_ci 4618c2ecf20Sopenharmony_ci if (!ret) 4628c2ecf20Sopenharmony_ci return prop; 4638c2ecf20Sopenharmony_ci else 4648c2ecf20Sopenharmony_ci return caam_get_era_from_hw(ctrl); 4658c2ecf20Sopenharmony_ci} 4668c2ecf20Sopenharmony_ci 4678c2ecf20Sopenharmony_ci/* 4688c2ecf20Sopenharmony_ci * ERRATA: imx6 devices (imx6D, imx6Q, imx6DL, imx6S, imx6DP and imx6QP) 4698c2ecf20Sopenharmony_ci * have an issue wherein AXI bus transactions may not occur in the correct 4708c2ecf20Sopenharmony_ci * order. This isn't a problem running single descriptors, but can be if 4718c2ecf20Sopenharmony_ci * running multiple concurrent descriptors. Reworking the driver to throttle 4728c2ecf20Sopenharmony_ci * to single requests is impractical, thus the workaround is to limit the AXI 4738c2ecf20Sopenharmony_ci * pipeline to a depth of 1 (from it's default of 4) to preclude this situation 4748c2ecf20Sopenharmony_ci * from occurring. 4758c2ecf20Sopenharmony_ci */ 4768c2ecf20Sopenharmony_cistatic void handle_imx6_err005766(u32 __iomem *mcr) 4778c2ecf20Sopenharmony_ci{ 4788c2ecf20Sopenharmony_ci if (of_machine_is_compatible("fsl,imx6q") || 4798c2ecf20Sopenharmony_ci of_machine_is_compatible("fsl,imx6dl") || 4808c2ecf20Sopenharmony_ci of_machine_is_compatible("fsl,imx6qp")) 4818c2ecf20Sopenharmony_ci clrsetbits_32(mcr, MCFGR_AXIPIPE_MASK, 4828c2ecf20Sopenharmony_ci 1 << MCFGR_AXIPIPE_SHIFT); 4838c2ecf20Sopenharmony_ci} 4848c2ecf20Sopenharmony_ci 4858c2ecf20Sopenharmony_cistatic const struct of_device_id caam_match[] = { 4868c2ecf20Sopenharmony_ci { 4878c2ecf20Sopenharmony_ci .compatible = "fsl,sec-v4.0", 4888c2ecf20Sopenharmony_ci }, 4898c2ecf20Sopenharmony_ci { 4908c2ecf20Sopenharmony_ci .compatible = "fsl,sec4.0", 4918c2ecf20Sopenharmony_ci }, 4928c2ecf20Sopenharmony_ci {}, 4938c2ecf20Sopenharmony_ci}; 4948c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, caam_match); 4958c2ecf20Sopenharmony_ci 4968c2ecf20Sopenharmony_cistruct caam_imx_data { 4978c2ecf20Sopenharmony_ci const struct clk_bulk_data *clks; 4988c2ecf20Sopenharmony_ci int num_clks; 4998c2ecf20Sopenharmony_ci}; 5008c2ecf20Sopenharmony_ci 5018c2ecf20Sopenharmony_cistatic const struct clk_bulk_data caam_imx6_clks[] = { 5028c2ecf20Sopenharmony_ci { .id = "ipg" }, 5038c2ecf20Sopenharmony_ci { .id = "mem" }, 5048c2ecf20Sopenharmony_ci { .id = "aclk" }, 5058c2ecf20Sopenharmony_ci { .id = "emi_slow" }, 5068c2ecf20Sopenharmony_ci}; 5078c2ecf20Sopenharmony_ci 5088c2ecf20Sopenharmony_cistatic const struct caam_imx_data caam_imx6_data = { 5098c2ecf20Sopenharmony_ci .clks = caam_imx6_clks, 5108c2ecf20Sopenharmony_ci .num_clks = ARRAY_SIZE(caam_imx6_clks), 5118c2ecf20Sopenharmony_ci}; 5128c2ecf20Sopenharmony_ci 5138c2ecf20Sopenharmony_cistatic const struct clk_bulk_data caam_imx7_clks[] = { 5148c2ecf20Sopenharmony_ci { .id = "ipg" }, 5158c2ecf20Sopenharmony_ci { .id = "aclk" }, 5168c2ecf20Sopenharmony_ci}; 5178c2ecf20Sopenharmony_ci 5188c2ecf20Sopenharmony_cistatic const struct caam_imx_data caam_imx7_data = { 5198c2ecf20Sopenharmony_ci .clks = caam_imx7_clks, 5208c2ecf20Sopenharmony_ci .num_clks = ARRAY_SIZE(caam_imx7_clks), 5218c2ecf20Sopenharmony_ci}; 5228c2ecf20Sopenharmony_ci 5238c2ecf20Sopenharmony_cistatic const struct clk_bulk_data caam_imx6ul_clks[] = { 5248c2ecf20Sopenharmony_ci { .id = "ipg" }, 5258c2ecf20Sopenharmony_ci { .id = "mem" }, 5268c2ecf20Sopenharmony_ci { .id = "aclk" }, 5278c2ecf20Sopenharmony_ci}; 5288c2ecf20Sopenharmony_ci 5298c2ecf20Sopenharmony_cistatic const struct caam_imx_data caam_imx6ul_data = { 5308c2ecf20Sopenharmony_ci .clks = caam_imx6ul_clks, 5318c2ecf20Sopenharmony_ci .num_clks = ARRAY_SIZE(caam_imx6ul_clks), 5328c2ecf20Sopenharmony_ci}; 5338c2ecf20Sopenharmony_ci 5348c2ecf20Sopenharmony_cistatic const struct clk_bulk_data caam_vf610_clks[] = { 5358c2ecf20Sopenharmony_ci { .id = "ipg" }, 5368c2ecf20Sopenharmony_ci}; 5378c2ecf20Sopenharmony_ci 5388c2ecf20Sopenharmony_cistatic const struct caam_imx_data caam_vf610_data = { 5398c2ecf20Sopenharmony_ci .clks = caam_vf610_clks, 5408c2ecf20Sopenharmony_ci .num_clks = ARRAY_SIZE(caam_vf610_clks), 5418c2ecf20Sopenharmony_ci}; 5428c2ecf20Sopenharmony_ci 5438c2ecf20Sopenharmony_cistatic const struct soc_device_attribute caam_imx_soc_table[] = { 5448c2ecf20Sopenharmony_ci { .soc_id = "i.MX6UL", .data = &caam_imx6ul_data }, 5458c2ecf20Sopenharmony_ci { .soc_id = "i.MX6*", .data = &caam_imx6_data }, 5468c2ecf20Sopenharmony_ci { .soc_id = "i.MX7*", .data = &caam_imx7_data }, 5478c2ecf20Sopenharmony_ci { .soc_id = "i.MX8M*", .data = &caam_imx7_data }, 5488c2ecf20Sopenharmony_ci { .soc_id = "VF*", .data = &caam_vf610_data }, 5498c2ecf20Sopenharmony_ci { .family = "Freescale i.MX" }, 5508c2ecf20Sopenharmony_ci { /* sentinel */ } 5518c2ecf20Sopenharmony_ci}; 5528c2ecf20Sopenharmony_ci 5538c2ecf20Sopenharmony_cistatic void disable_clocks(void *data) 5548c2ecf20Sopenharmony_ci{ 5558c2ecf20Sopenharmony_ci struct caam_drv_private *ctrlpriv = data; 5568c2ecf20Sopenharmony_ci 5578c2ecf20Sopenharmony_ci clk_bulk_disable_unprepare(ctrlpriv->num_clks, ctrlpriv->clks); 5588c2ecf20Sopenharmony_ci} 5598c2ecf20Sopenharmony_ci 5608c2ecf20Sopenharmony_cistatic int init_clocks(struct device *dev, const struct caam_imx_data *data) 5618c2ecf20Sopenharmony_ci{ 5628c2ecf20Sopenharmony_ci struct caam_drv_private *ctrlpriv = dev_get_drvdata(dev); 5638c2ecf20Sopenharmony_ci int ret; 5648c2ecf20Sopenharmony_ci 5658c2ecf20Sopenharmony_ci ctrlpriv->num_clks = data->num_clks; 5668c2ecf20Sopenharmony_ci ctrlpriv->clks = devm_kmemdup(dev, data->clks, 5678c2ecf20Sopenharmony_ci data->num_clks * sizeof(data->clks[0]), 5688c2ecf20Sopenharmony_ci GFP_KERNEL); 5698c2ecf20Sopenharmony_ci if (!ctrlpriv->clks) 5708c2ecf20Sopenharmony_ci return -ENOMEM; 5718c2ecf20Sopenharmony_ci 5728c2ecf20Sopenharmony_ci ret = devm_clk_bulk_get(dev, ctrlpriv->num_clks, ctrlpriv->clks); 5738c2ecf20Sopenharmony_ci if (ret) { 5748c2ecf20Sopenharmony_ci dev_err(dev, 5758c2ecf20Sopenharmony_ci "Failed to request all necessary clocks\n"); 5768c2ecf20Sopenharmony_ci return ret; 5778c2ecf20Sopenharmony_ci } 5788c2ecf20Sopenharmony_ci 5798c2ecf20Sopenharmony_ci ret = clk_bulk_prepare_enable(ctrlpriv->num_clks, ctrlpriv->clks); 5808c2ecf20Sopenharmony_ci if (ret) { 5818c2ecf20Sopenharmony_ci dev_err(dev, 5828c2ecf20Sopenharmony_ci "Failed to prepare/enable all necessary clocks\n"); 5838c2ecf20Sopenharmony_ci return ret; 5848c2ecf20Sopenharmony_ci } 5858c2ecf20Sopenharmony_ci 5868c2ecf20Sopenharmony_ci return devm_add_action_or_reset(dev, disable_clocks, ctrlpriv); 5878c2ecf20Sopenharmony_ci} 5888c2ecf20Sopenharmony_ci 5898c2ecf20Sopenharmony_cistatic void caam_remove_debugfs(void *root) 5908c2ecf20Sopenharmony_ci{ 5918c2ecf20Sopenharmony_ci debugfs_remove_recursive(root); 5928c2ecf20Sopenharmony_ci} 5938c2ecf20Sopenharmony_ci 5948c2ecf20Sopenharmony_ci#ifdef CONFIG_FSL_MC_BUS 5958c2ecf20Sopenharmony_cistatic bool check_version(struct fsl_mc_version *mc_version, u32 major, 5968c2ecf20Sopenharmony_ci u32 minor, u32 revision) 5978c2ecf20Sopenharmony_ci{ 5988c2ecf20Sopenharmony_ci if (mc_version->major > major) 5998c2ecf20Sopenharmony_ci return true; 6008c2ecf20Sopenharmony_ci 6018c2ecf20Sopenharmony_ci if (mc_version->major == major) { 6028c2ecf20Sopenharmony_ci if (mc_version->minor > minor) 6038c2ecf20Sopenharmony_ci return true; 6048c2ecf20Sopenharmony_ci 6058c2ecf20Sopenharmony_ci if (mc_version->minor == minor && 6068c2ecf20Sopenharmony_ci mc_version->revision > revision) 6078c2ecf20Sopenharmony_ci return true; 6088c2ecf20Sopenharmony_ci } 6098c2ecf20Sopenharmony_ci 6108c2ecf20Sopenharmony_ci return false; 6118c2ecf20Sopenharmony_ci} 6128c2ecf20Sopenharmony_ci#endif 6138c2ecf20Sopenharmony_ci 6148c2ecf20Sopenharmony_cistatic bool needs_entropy_delay_adjustment(void) 6158c2ecf20Sopenharmony_ci{ 6168c2ecf20Sopenharmony_ci if (of_machine_is_compatible("fsl,imx6sx")) 6178c2ecf20Sopenharmony_ci return true; 6188c2ecf20Sopenharmony_ci return false; 6198c2ecf20Sopenharmony_ci} 6208c2ecf20Sopenharmony_ci 6218c2ecf20Sopenharmony_ci/* Probe routine for CAAM top (controller) level */ 6228c2ecf20Sopenharmony_cistatic int caam_probe(struct platform_device *pdev) 6238c2ecf20Sopenharmony_ci{ 6248c2ecf20Sopenharmony_ci int ret, ring, gen_sk, ent_delay = RTSDCTL_ENT_DLY_MIN; 6258c2ecf20Sopenharmony_ci u64 caam_id; 6268c2ecf20Sopenharmony_ci const struct soc_device_attribute *imx_soc_match; 6278c2ecf20Sopenharmony_ci struct device *dev; 6288c2ecf20Sopenharmony_ci struct device_node *nprop, *np; 6298c2ecf20Sopenharmony_ci struct caam_ctrl __iomem *ctrl; 6308c2ecf20Sopenharmony_ci struct caam_drv_private *ctrlpriv; 6318c2ecf20Sopenharmony_ci struct dentry *dfs_root; 6328c2ecf20Sopenharmony_ci u32 scfgr, comp_params; 6338c2ecf20Sopenharmony_ci u8 rng_vid; 6348c2ecf20Sopenharmony_ci int pg_size; 6358c2ecf20Sopenharmony_ci int BLOCK_OFFSET = 0; 6368c2ecf20Sopenharmony_ci bool pr_support = false; 6378c2ecf20Sopenharmony_ci 6388c2ecf20Sopenharmony_ci ctrlpriv = devm_kzalloc(&pdev->dev, sizeof(*ctrlpriv), GFP_KERNEL); 6398c2ecf20Sopenharmony_ci if (!ctrlpriv) 6408c2ecf20Sopenharmony_ci return -ENOMEM; 6418c2ecf20Sopenharmony_ci 6428c2ecf20Sopenharmony_ci dev = &pdev->dev; 6438c2ecf20Sopenharmony_ci dev_set_drvdata(dev, ctrlpriv); 6448c2ecf20Sopenharmony_ci nprop = pdev->dev.of_node; 6458c2ecf20Sopenharmony_ci 6468c2ecf20Sopenharmony_ci imx_soc_match = soc_device_match(caam_imx_soc_table); 6478c2ecf20Sopenharmony_ci caam_imx = (bool)imx_soc_match; 6488c2ecf20Sopenharmony_ci 6498c2ecf20Sopenharmony_ci if (imx_soc_match) { 6508c2ecf20Sopenharmony_ci if (!imx_soc_match->data) { 6518c2ecf20Sopenharmony_ci dev_err(dev, "No clock data provided for i.MX SoC"); 6528c2ecf20Sopenharmony_ci return -EINVAL; 6538c2ecf20Sopenharmony_ci } 6548c2ecf20Sopenharmony_ci 6558c2ecf20Sopenharmony_ci ret = init_clocks(dev, imx_soc_match->data); 6568c2ecf20Sopenharmony_ci if (ret) 6578c2ecf20Sopenharmony_ci return ret; 6588c2ecf20Sopenharmony_ci } 6598c2ecf20Sopenharmony_ci 6608c2ecf20Sopenharmony_ci 6618c2ecf20Sopenharmony_ci /* Get configuration properties from device tree */ 6628c2ecf20Sopenharmony_ci /* First, get register page */ 6638c2ecf20Sopenharmony_ci ctrl = devm_of_iomap(dev, nprop, 0, NULL); 6648c2ecf20Sopenharmony_ci ret = PTR_ERR_OR_ZERO(ctrl); 6658c2ecf20Sopenharmony_ci if (ret) { 6668c2ecf20Sopenharmony_ci dev_err(dev, "caam: of_iomap() failed\n"); 6678c2ecf20Sopenharmony_ci return ret; 6688c2ecf20Sopenharmony_ci } 6698c2ecf20Sopenharmony_ci 6708c2ecf20Sopenharmony_ci caam_little_end = !(bool)(rd_reg32(&ctrl->perfmon.status) & 6718c2ecf20Sopenharmony_ci (CSTA_PLEND | CSTA_ALT_PLEND)); 6728c2ecf20Sopenharmony_ci comp_params = rd_reg32(&ctrl->perfmon.comp_parms_ms); 6738c2ecf20Sopenharmony_ci if (comp_params & CTPR_MS_PS && rd_reg32(&ctrl->mcr) & MCFGR_LONG_PTR) 6748c2ecf20Sopenharmony_ci caam_ptr_sz = sizeof(u64); 6758c2ecf20Sopenharmony_ci else 6768c2ecf20Sopenharmony_ci caam_ptr_sz = sizeof(u32); 6778c2ecf20Sopenharmony_ci caam_dpaa2 = !!(comp_params & CTPR_MS_DPAA2); 6788c2ecf20Sopenharmony_ci ctrlpriv->qi_present = !!(comp_params & CTPR_MS_QI_MASK); 6798c2ecf20Sopenharmony_ci 6808c2ecf20Sopenharmony_ci#ifdef CONFIG_CAAM_QI 6818c2ecf20Sopenharmony_ci /* If (DPAA 1.x) QI present, check whether dependencies are available */ 6828c2ecf20Sopenharmony_ci if (ctrlpriv->qi_present && !caam_dpaa2) { 6838c2ecf20Sopenharmony_ci ret = qman_is_probed(); 6848c2ecf20Sopenharmony_ci if (!ret) { 6858c2ecf20Sopenharmony_ci return -EPROBE_DEFER; 6868c2ecf20Sopenharmony_ci } else if (ret < 0) { 6878c2ecf20Sopenharmony_ci dev_err(dev, "failing probe due to qman probe error\n"); 6888c2ecf20Sopenharmony_ci return -ENODEV; 6898c2ecf20Sopenharmony_ci } 6908c2ecf20Sopenharmony_ci 6918c2ecf20Sopenharmony_ci ret = qman_portals_probed(); 6928c2ecf20Sopenharmony_ci if (!ret) { 6938c2ecf20Sopenharmony_ci return -EPROBE_DEFER; 6948c2ecf20Sopenharmony_ci } else if (ret < 0) { 6958c2ecf20Sopenharmony_ci dev_err(dev, "failing probe due to qman portals probe error\n"); 6968c2ecf20Sopenharmony_ci return -ENODEV; 6978c2ecf20Sopenharmony_ci } 6988c2ecf20Sopenharmony_ci } 6998c2ecf20Sopenharmony_ci#endif 7008c2ecf20Sopenharmony_ci 7018c2ecf20Sopenharmony_ci /* Allocating the BLOCK_OFFSET based on the supported page size on 7028c2ecf20Sopenharmony_ci * the platform 7038c2ecf20Sopenharmony_ci */ 7048c2ecf20Sopenharmony_ci pg_size = (comp_params & CTPR_MS_PG_SZ_MASK) >> CTPR_MS_PG_SZ_SHIFT; 7058c2ecf20Sopenharmony_ci if (pg_size == 0) 7068c2ecf20Sopenharmony_ci BLOCK_OFFSET = PG_SIZE_4K; 7078c2ecf20Sopenharmony_ci else 7088c2ecf20Sopenharmony_ci BLOCK_OFFSET = PG_SIZE_64K; 7098c2ecf20Sopenharmony_ci 7108c2ecf20Sopenharmony_ci ctrlpriv->ctrl = (struct caam_ctrl __iomem __force *)ctrl; 7118c2ecf20Sopenharmony_ci ctrlpriv->assure = (struct caam_assurance __iomem __force *) 7128c2ecf20Sopenharmony_ci ((__force uint8_t *)ctrl + 7138c2ecf20Sopenharmony_ci BLOCK_OFFSET * ASSURE_BLOCK_NUMBER 7148c2ecf20Sopenharmony_ci ); 7158c2ecf20Sopenharmony_ci ctrlpriv->deco = (struct caam_deco __iomem __force *) 7168c2ecf20Sopenharmony_ci ((__force uint8_t *)ctrl + 7178c2ecf20Sopenharmony_ci BLOCK_OFFSET * DECO_BLOCK_NUMBER 7188c2ecf20Sopenharmony_ci ); 7198c2ecf20Sopenharmony_ci 7208c2ecf20Sopenharmony_ci /* Get the IRQ of the controller (for security violations only) */ 7218c2ecf20Sopenharmony_ci ctrlpriv->secvio_irq = irq_of_parse_and_map(nprop, 0); 7228c2ecf20Sopenharmony_ci np = of_find_compatible_node(NULL, NULL, "fsl,qoriq-mc"); 7238c2ecf20Sopenharmony_ci ctrlpriv->mc_en = !!np; 7248c2ecf20Sopenharmony_ci of_node_put(np); 7258c2ecf20Sopenharmony_ci 7268c2ecf20Sopenharmony_ci#ifdef CONFIG_FSL_MC_BUS 7278c2ecf20Sopenharmony_ci if (ctrlpriv->mc_en) { 7288c2ecf20Sopenharmony_ci struct fsl_mc_version *mc_version; 7298c2ecf20Sopenharmony_ci 7308c2ecf20Sopenharmony_ci mc_version = fsl_mc_get_version(); 7318c2ecf20Sopenharmony_ci if (mc_version) 7328c2ecf20Sopenharmony_ci pr_support = check_version(mc_version, 10, 20, 0); 7338c2ecf20Sopenharmony_ci else 7348c2ecf20Sopenharmony_ci return -EPROBE_DEFER; 7358c2ecf20Sopenharmony_ci } 7368c2ecf20Sopenharmony_ci#endif 7378c2ecf20Sopenharmony_ci 7388c2ecf20Sopenharmony_ci /* 7398c2ecf20Sopenharmony_ci * Enable DECO watchdogs and, if this is a PHYS_ADDR_T_64BIT kernel, 7408c2ecf20Sopenharmony_ci * long pointers in master configuration register. 7418c2ecf20Sopenharmony_ci * In case of SoCs with Management Complex, MC f/w performs 7428c2ecf20Sopenharmony_ci * the configuration. 7438c2ecf20Sopenharmony_ci */ 7448c2ecf20Sopenharmony_ci if (!ctrlpriv->mc_en) 7458c2ecf20Sopenharmony_ci clrsetbits_32(&ctrl->mcr, MCFGR_AWCACHE_MASK, 7468c2ecf20Sopenharmony_ci MCFGR_AWCACHE_CACH | MCFGR_AWCACHE_BUFF | 7478c2ecf20Sopenharmony_ci MCFGR_WDENABLE | MCFGR_LARGE_BURST); 7488c2ecf20Sopenharmony_ci 7498c2ecf20Sopenharmony_ci handle_imx6_err005766(&ctrl->mcr); 7508c2ecf20Sopenharmony_ci 7518c2ecf20Sopenharmony_ci /* 7528c2ecf20Sopenharmony_ci * Read the Compile Time parameters and SCFGR to determine 7538c2ecf20Sopenharmony_ci * if virtualization is enabled for this platform 7548c2ecf20Sopenharmony_ci */ 7558c2ecf20Sopenharmony_ci scfgr = rd_reg32(&ctrl->scfgr); 7568c2ecf20Sopenharmony_ci 7578c2ecf20Sopenharmony_ci ctrlpriv->virt_en = 0; 7588c2ecf20Sopenharmony_ci if (comp_params & CTPR_MS_VIRT_EN_INCL) { 7598c2ecf20Sopenharmony_ci /* VIRT_EN_INCL = 1 & VIRT_EN_POR = 1 or 7608c2ecf20Sopenharmony_ci * VIRT_EN_INCL = 1 & VIRT_EN_POR = 0 & SCFGR_VIRT_EN = 1 7618c2ecf20Sopenharmony_ci */ 7628c2ecf20Sopenharmony_ci if ((comp_params & CTPR_MS_VIRT_EN_POR) || 7638c2ecf20Sopenharmony_ci (!(comp_params & CTPR_MS_VIRT_EN_POR) && 7648c2ecf20Sopenharmony_ci (scfgr & SCFGR_VIRT_EN))) 7658c2ecf20Sopenharmony_ci ctrlpriv->virt_en = 1; 7668c2ecf20Sopenharmony_ci } else { 7678c2ecf20Sopenharmony_ci /* VIRT_EN_INCL = 0 && VIRT_EN_POR_VALUE = 1 */ 7688c2ecf20Sopenharmony_ci if (comp_params & CTPR_MS_VIRT_EN_POR) 7698c2ecf20Sopenharmony_ci ctrlpriv->virt_en = 1; 7708c2ecf20Sopenharmony_ci } 7718c2ecf20Sopenharmony_ci 7728c2ecf20Sopenharmony_ci if (ctrlpriv->virt_en == 1) 7738c2ecf20Sopenharmony_ci clrsetbits_32(&ctrl->jrstart, 0, JRSTART_JR0_START | 7748c2ecf20Sopenharmony_ci JRSTART_JR1_START | JRSTART_JR2_START | 7758c2ecf20Sopenharmony_ci JRSTART_JR3_START); 7768c2ecf20Sopenharmony_ci 7778c2ecf20Sopenharmony_ci ret = dma_set_mask_and_coherent(dev, caam_get_dma_mask(dev)); 7788c2ecf20Sopenharmony_ci if (ret) { 7798c2ecf20Sopenharmony_ci dev_err(dev, "dma_set_mask_and_coherent failed (%d)\n", ret); 7808c2ecf20Sopenharmony_ci return ret; 7818c2ecf20Sopenharmony_ci } 7828c2ecf20Sopenharmony_ci 7838c2ecf20Sopenharmony_ci ctrlpriv->era = caam_get_era(ctrl); 7848c2ecf20Sopenharmony_ci ctrlpriv->domain = iommu_get_domain_for_dev(dev); 7858c2ecf20Sopenharmony_ci 7868c2ecf20Sopenharmony_ci dfs_root = debugfs_create_dir(dev_name(dev), NULL); 7878c2ecf20Sopenharmony_ci if (IS_ENABLED(CONFIG_DEBUG_FS)) { 7888c2ecf20Sopenharmony_ci ret = devm_add_action_or_reset(dev, caam_remove_debugfs, 7898c2ecf20Sopenharmony_ci dfs_root); 7908c2ecf20Sopenharmony_ci if (ret) 7918c2ecf20Sopenharmony_ci return ret; 7928c2ecf20Sopenharmony_ci } 7938c2ecf20Sopenharmony_ci 7948c2ecf20Sopenharmony_ci caam_debugfs_init(ctrlpriv, dfs_root); 7958c2ecf20Sopenharmony_ci 7968c2ecf20Sopenharmony_ci /* Check to see if (DPAA 1.x) QI present. If so, enable */ 7978c2ecf20Sopenharmony_ci if (ctrlpriv->qi_present && !caam_dpaa2) { 7988c2ecf20Sopenharmony_ci ctrlpriv->qi = (struct caam_queue_if __iomem __force *) 7998c2ecf20Sopenharmony_ci ((__force uint8_t *)ctrl + 8008c2ecf20Sopenharmony_ci BLOCK_OFFSET * QI_BLOCK_NUMBER 8018c2ecf20Sopenharmony_ci ); 8028c2ecf20Sopenharmony_ci /* This is all that's required to physically enable QI */ 8038c2ecf20Sopenharmony_ci wr_reg32(&ctrlpriv->qi->qi_control_lo, QICTL_DQEN); 8048c2ecf20Sopenharmony_ci 8058c2ecf20Sopenharmony_ci /* If QMAN driver is present, init CAAM-QI backend */ 8068c2ecf20Sopenharmony_ci#ifdef CONFIG_CAAM_QI 8078c2ecf20Sopenharmony_ci ret = caam_qi_init(pdev); 8088c2ecf20Sopenharmony_ci if (ret) 8098c2ecf20Sopenharmony_ci dev_err(dev, "caam qi i/f init failed: %d\n", ret); 8108c2ecf20Sopenharmony_ci#endif 8118c2ecf20Sopenharmony_ci } 8128c2ecf20Sopenharmony_ci 8138c2ecf20Sopenharmony_ci ring = 0; 8148c2ecf20Sopenharmony_ci for_each_available_child_of_node(nprop, np) 8158c2ecf20Sopenharmony_ci if (of_device_is_compatible(np, "fsl,sec-v4.0-job-ring") || 8168c2ecf20Sopenharmony_ci of_device_is_compatible(np, "fsl,sec4.0-job-ring")) { 8178c2ecf20Sopenharmony_ci ctrlpriv->jr[ring] = (struct caam_job_ring __iomem __force *) 8188c2ecf20Sopenharmony_ci ((__force uint8_t *)ctrl + 8198c2ecf20Sopenharmony_ci (ring + JR_BLOCK_NUMBER) * 8208c2ecf20Sopenharmony_ci BLOCK_OFFSET 8218c2ecf20Sopenharmony_ci ); 8228c2ecf20Sopenharmony_ci ctrlpriv->total_jobrs++; 8238c2ecf20Sopenharmony_ci ring++; 8248c2ecf20Sopenharmony_ci } 8258c2ecf20Sopenharmony_ci 8268c2ecf20Sopenharmony_ci /* If no QI and no rings specified, quit and go home */ 8278c2ecf20Sopenharmony_ci if ((!ctrlpriv->qi_present) && (!ctrlpriv->total_jobrs)) { 8288c2ecf20Sopenharmony_ci dev_err(dev, "no queues configured, terminating\n"); 8298c2ecf20Sopenharmony_ci return -ENOMEM; 8308c2ecf20Sopenharmony_ci } 8318c2ecf20Sopenharmony_ci 8328c2ecf20Sopenharmony_ci if (ctrlpriv->era < 10) 8338c2ecf20Sopenharmony_ci rng_vid = (rd_reg32(&ctrl->perfmon.cha_id_ls) & 8348c2ecf20Sopenharmony_ci CHA_ID_LS_RNG_MASK) >> CHA_ID_LS_RNG_SHIFT; 8358c2ecf20Sopenharmony_ci else 8368c2ecf20Sopenharmony_ci rng_vid = (rd_reg32(&ctrl->vreg.rng) & CHA_VER_VID_MASK) >> 8378c2ecf20Sopenharmony_ci CHA_VER_VID_SHIFT; 8388c2ecf20Sopenharmony_ci 8398c2ecf20Sopenharmony_ci /* 8408c2ecf20Sopenharmony_ci * If SEC has RNG version >= 4 and RNG state handle has not been 8418c2ecf20Sopenharmony_ci * already instantiated, do RNG instantiation 8428c2ecf20Sopenharmony_ci * In case of SoCs with Management Complex, RNG is managed by MC f/w. 8438c2ecf20Sopenharmony_ci */ 8448c2ecf20Sopenharmony_ci if (!(ctrlpriv->mc_en && pr_support) && rng_vid >= 4) { 8458c2ecf20Sopenharmony_ci ctrlpriv->rng4_sh_init = 8468c2ecf20Sopenharmony_ci rd_reg32(&ctrl->r4tst[0].rdsta); 8478c2ecf20Sopenharmony_ci /* 8488c2ecf20Sopenharmony_ci * If the secure keys (TDKEK, JDKEK, TDSK), were already 8498c2ecf20Sopenharmony_ci * generated, signal this to the function that is instantiating 8508c2ecf20Sopenharmony_ci * the state handles. An error would occur if RNG4 attempts 8518c2ecf20Sopenharmony_ci * to regenerate these keys before the next POR. 8528c2ecf20Sopenharmony_ci */ 8538c2ecf20Sopenharmony_ci gen_sk = ctrlpriv->rng4_sh_init & RDSTA_SKVN ? 0 : 1; 8548c2ecf20Sopenharmony_ci ctrlpriv->rng4_sh_init &= RDSTA_MASK; 8558c2ecf20Sopenharmony_ci do { 8568c2ecf20Sopenharmony_ci int inst_handles = 8578c2ecf20Sopenharmony_ci rd_reg32(&ctrl->r4tst[0].rdsta) & 8588c2ecf20Sopenharmony_ci RDSTA_MASK; 8598c2ecf20Sopenharmony_ci /* 8608c2ecf20Sopenharmony_ci * If either SH were instantiated by somebody else 8618c2ecf20Sopenharmony_ci * (e.g. u-boot) then it is assumed that the entropy 8628c2ecf20Sopenharmony_ci * parameters are properly set and thus the function 8638c2ecf20Sopenharmony_ci * setting these (kick_trng(...)) is skipped. 8648c2ecf20Sopenharmony_ci * Also, if a handle was instantiated, do not change 8658c2ecf20Sopenharmony_ci * the TRNG parameters. 8668c2ecf20Sopenharmony_ci */ 8678c2ecf20Sopenharmony_ci if (needs_entropy_delay_adjustment()) 8688c2ecf20Sopenharmony_ci ent_delay = 12000; 8698c2ecf20Sopenharmony_ci if (!(ctrlpriv->rng4_sh_init || inst_handles)) { 8708c2ecf20Sopenharmony_ci dev_info(dev, 8718c2ecf20Sopenharmony_ci "Entropy delay = %u\n", 8728c2ecf20Sopenharmony_ci ent_delay); 8738c2ecf20Sopenharmony_ci kick_trng(pdev, ent_delay); 8748c2ecf20Sopenharmony_ci ent_delay += 400; 8758c2ecf20Sopenharmony_ci } 8768c2ecf20Sopenharmony_ci /* 8778c2ecf20Sopenharmony_ci * if instantiate_rng(...) fails, the loop will rerun 8788c2ecf20Sopenharmony_ci * and the kick_trng(...) function will modify the 8798c2ecf20Sopenharmony_ci * upper and lower limits of the entropy sampling 8808c2ecf20Sopenharmony_ci * interval, leading to a successful initialization of 8818c2ecf20Sopenharmony_ci * the RNG. 8828c2ecf20Sopenharmony_ci */ 8838c2ecf20Sopenharmony_ci ret = instantiate_rng(dev, inst_handles, 8848c2ecf20Sopenharmony_ci gen_sk); 8858c2ecf20Sopenharmony_ci /* 8868c2ecf20Sopenharmony_ci * Entropy delay is determined via TRNG characterization. 8878c2ecf20Sopenharmony_ci * TRNG characterization is run across different voltages 8888c2ecf20Sopenharmony_ci * and temperatures. 8898c2ecf20Sopenharmony_ci * If worst case value for ent_dly is identified, 8908c2ecf20Sopenharmony_ci * the loop can be skipped for that platform. 8918c2ecf20Sopenharmony_ci */ 8928c2ecf20Sopenharmony_ci if (needs_entropy_delay_adjustment()) 8938c2ecf20Sopenharmony_ci break; 8948c2ecf20Sopenharmony_ci if (ret == -EAGAIN) 8958c2ecf20Sopenharmony_ci /* 8968c2ecf20Sopenharmony_ci * if here, the loop will rerun, 8978c2ecf20Sopenharmony_ci * so don't hog the CPU 8988c2ecf20Sopenharmony_ci */ 8998c2ecf20Sopenharmony_ci cpu_relax(); 9008c2ecf20Sopenharmony_ci } while ((ret == -EAGAIN) && (ent_delay < RTSDCTL_ENT_DLY_MAX)); 9018c2ecf20Sopenharmony_ci if (ret) { 9028c2ecf20Sopenharmony_ci dev_err(dev, "failed to instantiate RNG"); 9038c2ecf20Sopenharmony_ci return ret; 9048c2ecf20Sopenharmony_ci } 9058c2ecf20Sopenharmony_ci /* 9068c2ecf20Sopenharmony_ci * Set handles initialized by this module as the complement of 9078c2ecf20Sopenharmony_ci * the already initialized ones 9088c2ecf20Sopenharmony_ci */ 9098c2ecf20Sopenharmony_ci ctrlpriv->rng4_sh_init = ~ctrlpriv->rng4_sh_init & RDSTA_MASK; 9108c2ecf20Sopenharmony_ci 9118c2ecf20Sopenharmony_ci /* Enable RDB bit so that RNG works faster */ 9128c2ecf20Sopenharmony_ci clrsetbits_32(&ctrl->scfgr, 0, SCFGR_RDBENABLE); 9138c2ecf20Sopenharmony_ci } 9148c2ecf20Sopenharmony_ci 9158c2ecf20Sopenharmony_ci /* NOTE: RTIC detection ought to go here, around Si time */ 9168c2ecf20Sopenharmony_ci 9178c2ecf20Sopenharmony_ci caam_id = (u64)rd_reg32(&ctrl->perfmon.caam_id_ms) << 32 | 9188c2ecf20Sopenharmony_ci (u64)rd_reg32(&ctrl->perfmon.caam_id_ls); 9198c2ecf20Sopenharmony_ci 9208c2ecf20Sopenharmony_ci /* Report "alive" for developer to see */ 9218c2ecf20Sopenharmony_ci dev_info(dev, "device ID = 0x%016llx (Era %d)\n", caam_id, 9228c2ecf20Sopenharmony_ci ctrlpriv->era); 9238c2ecf20Sopenharmony_ci dev_info(dev, "job rings = %d, qi = %d\n", 9248c2ecf20Sopenharmony_ci ctrlpriv->total_jobrs, ctrlpriv->qi_present); 9258c2ecf20Sopenharmony_ci 9268c2ecf20Sopenharmony_ci ret = devm_of_platform_populate(dev); 9278c2ecf20Sopenharmony_ci if (ret) 9288c2ecf20Sopenharmony_ci dev_err(dev, "JR platform devices creation error\n"); 9298c2ecf20Sopenharmony_ci 9308c2ecf20Sopenharmony_ci return ret; 9318c2ecf20Sopenharmony_ci} 9328c2ecf20Sopenharmony_ci 9338c2ecf20Sopenharmony_cistatic struct platform_driver caam_driver = { 9348c2ecf20Sopenharmony_ci .driver = { 9358c2ecf20Sopenharmony_ci .name = "caam", 9368c2ecf20Sopenharmony_ci .of_match_table = caam_match, 9378c2ecf20Sopenharmony_ci }, 9388c2ecf20Sopenharmony_ci .probe = caam_probe, 9398c2ecf20Sopenharmony_ci}; 9408c2ecf20Sopenharmony_ci 9418c2ecf20Sopenharmony_cimodule_platform_driver(caam_driver); 9428c2ecf20Sopenharmony_ci 9438c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 9448c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("FSL CAAM request backend"); 9458c2ecf20Sopenharmony_ciMODULE_AUTHOR("Freescale Semiconductor - NMG/STC"); 946