18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* Copyright (C) 2012-2019 ARM Limited or its affiliates. */ 38c2ecf20Sopenharmony_ci 48c2ecf20Sopenharmony_ci#include <linux/kernel.h> 58c2ecf20Sopenharmony_ci#include <linux/module.h> 68c2ecf20Sopenharmony_ci 78c2ecf20Sopenharmony_ci#include <linux/crypto.h> 88c2ecf20Sopenharmony_ci#include <linux/moduleparam.h> 98c2ecf20Sopenharmony_ci#include <linux/types.h> 108c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 118c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 128c2ecf20Sopenharmony_ci#include <linux/slab.h> 138c2ecf20Sopenharmony_ci#include <linux/spinlock.h> 148c2ecf20Sopenharmony_ci#include <linux/of.h> 158c2ecf20Sopenharmony_ci#include <linux/clk.h> 168c2ecf20Sopenharmony_ci#include <linux/of_address.h> 178c2ecf20Sopenharmony_ci#include <linux/of_device.h> 188c2ecf20Sopenharmony_ci#include <linux/pm_runtime.h> 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ci#include "cc_driver.h" 218c2ecf20Sopenharmony_ci#include "cc_request_mgr.h" 228c2ecf20Sopenharmony_ci#include "cc_buffer_mgr.h" 238c2ecf20Sopenharmony_ci#include "cc_debugfs.h" 248c2ecf20Sopenharmony_ci#include "cc_cipher.h" 258c2ecf20Sopenharmony_ci#include "cc_aead.h" 268c2ecf20Sopenharmony_ci#include "cc_hash.h" 278c2ecf20Sopenharmony_ci#include "cc_sram_mgr.h" 288c2ecf20Sopenharmony_ci#include "cc_pm.h" 298c2ecf20Sopenharmony_ci#include "cc_fips.h" 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_cibool cc_dump_desc; 328c2ecf20Sopenharmony_cimodule_param_named(dump_desc, cc_dump_desc, bool, 0600); 338c2ecf20Sopenharmony_ciMODULE_PARM_DESC(cc_dump_desc, "Dump descriptors to kernel log as debugging aid"); 348c2ecf20Sopenharmony_cibool cc_dump_bytes; 358c2ecf20Sopenharmony_cimodule_param_named(dump_bytes, cc_dump_bytes, bool, 0600); 368c2ecf20Sopenharmony_ciMODULE_PARM_DESC(cc_dump_bytes, "Dump buffers to kernel log as debugging aid"); 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_cistatic bool cc_sec_disable; 398c2ecf20Sopenharmony_cimodule_param_named(sec_disable, cc_sec_disable, bool, 0600); 408c2ecf20Sopenharmony_ciMODULE_PARM_DESC(cc_sec_disable, "Disable security functions"); 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_cistruct cc_hw_data { 438c2ecf20Sopenharmony_ci char *name; 448c2ecf20Sopenharmony_ci enum cc_hw_rev rev; 458c2ecf20Sopenharmony_ci u32 sig; 468c2ecf20Sopenharmony_ci u32 cidr_0123; 478c2ecf20Sopenharmony_ci u32 pidr_0124; 488c2ecf20Sopenharmony_ci int std_bodies; 498c2ecf20Sopenharmony_ci}; 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_ci#define CC_NUM_IDRS 4 528c2ecf20Sopenharmony_ci#define CC_HW_RESET_LOOP_COUNT 10 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci/* Note: PIDR3 holds CMOD/Rev so ignored for HW identification purposes */ 558c2ecf20Sopenharmony_cistatic const u32 pidr_0124_offsets[CC_NUM_IDRS] = { 568c2ecf20Sopenharmony_ci CC_REG(PERIPHERAL_ID_0), CC_REG(PERIPHERAL_ID_1), 578c2ecf20Sopenharmony_ci CC_REG(PERIPHERAL_ID_2), CC_REG(PERIPHERAL_ID_4) 588c2ecf20Sopenharmony_ci}; 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_cistatic const u32 cidr_0123_offsets[CC_NUM_IDRS] = { 618c2ecf20Sopenharmony_ci CC_REG(COMPONENT_ID_0), CC_REG(COMPONENT_ID_1), 628c2ecf20Sopenharmony_ci CC_REG(COMPONENT_ID_2), CC_REG(COMPONENT_ID_3) 638c2ecf20Sopenharmony_ci}; 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ci/* Hardware revisions defs. */ 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci/* The 703 is a OSCCA only variant of the 713 */ 688c2ecf20Sopenharmony_cistatic const struct cc_hw_data cc703_hw = { 698c2ecf20Sopenharmony_ci .name = "703", .rev = CC_HW_REV_713, .cidr_0123 = 0xB105F00DU, 708c2ecf20Sopenharmony_ci .pidr_0124 = 0x040BB0D0U, .std_bodies = CC_STD_OSCCA 718c2ecf20Sopenharmony_ci}; 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_cistatic const struct cc_hw_data cc713_hw = { 748c2ecf20Sopenharmony_ci .name = "713", .rev = CC_HW_REV_713, .cidr_0123 = 0xB105F00DU, 758c2ecf20Sopenharmony_ci .pidr_0124 = 0x040BB0D0U, .std_bodies = CC_STD_ALL 768c2ecf20Sopenharmony_ci}; 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_cistatic const struct cc_hw_data cc712_hw = { 798c2ecf20Sopenharmony_ci .name = "712", .rev = CC_HW_REV_712, .sig = 0xDCC71200U, 808c2ecf20Sopenharmony_ci .std_bodies = CC_STD_ALL 818c2ecf20Sopenharmony_ci}; 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_cistatic const struct cc_hw_data cc710_hw = { 848c2ecf20Sopenharmony_ci .name = "710", .rev = CC_HW_REV_710, .sig = 0xDCC63200U, 858c2ecf20Sopenharmony_ci .std_bodies = CC_STD_ALL 868c2ecf20Sopenharmony_ci}; 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_cistatic const struct cc_hw_data cc630p_hw = { 898c2ecf20Sopenharmony_ci .name = "630P", .rev = CC_HW_REV_630, .sig = 0xDCC63000U, 908c2ecf20Sopenharmony_ci .std_bodies = CC_STD_ALL 918c2ecf20Sopenharmony_ci}; 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_cistatic const struct of_device_id arm_ccree_dev_of_match[] = { 948c2ecf20Sopenharmony_ci { .compatible = "arm,cryptocell-703-ree", .data = &cc703_hw }, 958c2ecf20Sopenharmony_ci { .compatible = "arm,cryptocell-713-ree", .data = &cc713_hw }, 968c2ecf20Sopenharmony_ci { .compatible = "arm,cryptocell-712-ree", .data = &cc712_hw }, 978c2ecf20Sopenharmony_ci { .compatible = "arm,cryptocell-710-ree", .data = &cc710_hw }, 988c2ecf20Sopenharmony_ci { .compatible = "arm,cryptocell-630p-ree", .data = &cc630p_hw }, 998c2ecf20Sopenharmony_ci {} 1008c2ecf20Sopenharmony_ci}; 1018c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, arm_ccree_dev_of_match); 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_cistatic u32 cc_read_idr(struct cc_drvdata *drvdata, const u32 *idr_offsets) 1048c2ecf20Sopenharmony_ci{ 1058c2ecf20Sopenharmony_ci int i; 1068c2ecf20Sopenharmony_ci union { 1078c2ecf20Sopenharmony_ci u8 regs[CC_NUM_IDRS]; 1088c2ecf20Sopenharmony_ci __le32 val; 1098c2ecf20Sopenharmony_ci } idr; 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ci for (i = 0; i < CC_NUM_IDRS; ++i) 1128c2ecf20Sopenharmony_ci idr.regs[i] = cc_ioread(drvdata, idr_offsets[i]); 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ci return le32_to_cpu(idr.val); 1158c2ecf20Sopenharmony_ci} 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_civoid __dump_byte_array(const char *name, const u8 *buf, size_t len) 1188c2ecf20Sopenharmony_ci{ 1198c2ecf20Sopenharmony_ci char prefix[64]; 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_ci if (!buf) 1228c2ecf20Sopenharmony_ci return; 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_ci snprintf(prefix, sizeof(prefix), "%s[%zu]: ", name, len); 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_ci print_hex_dump(KERN_DEBUG, prefix, DUMP_PREFIX_ADDRESS, 16, 1, buf, 1278c2ecf20Sopenharmony_ci len, false); 1288c2ecf20Sopenharmony_ci} 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_cistatic irqreturn_t cc_isr(int irq, void *dev_id) 1318c2ecf20Sopenharmony_ci{ 1328c2ecf20Sopenharmony_ci struct cc_drvdata *drvdata = (struct cc_drvdata *)dev_id; 1338c2ecf20Sopenharmony_ci struct device *dev = drvdata_to_dev(drvdata); 1348c2ecf20Sopenharmony_ci u32 irr; 1358c2ecf20Sopenharmony_ci u32 imr; 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_ci /* STAT_OP_TYPE_GENERIC STAT_PHASE_0: Interrupt */ 1388c2ecf20Sopenharmony_ci /* if driver suspended return, probably shared interrupt */ 1398c2ecf20Sopenharmony_ci if (pm_runtime_suspended(dev)) 1408c2ecf20Sopenharmony_ci return IRQ_NONE; 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_ci /* read the interrupt status */ 1438c2ecf20Sopenharmony_ci irr = cc_ioread(drvdata, CC_REG(HOST_IRR)); 1448c2ecf20Sopenharmony_ci dev_dbg(dev, "Got IRR=0x%08X\n", irr); 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_ci if (irr == 0) /* Probably shared interrupt line */ 1478c2ecf20Sopenharmony_ci return IRQ_NONE; 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_ci imr = cc_ioread(drvdata, CC_REG(HOST_IMR)); 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_ci /* clear interrupt - must be before processing events */ 1528c2ecf20Sopenharmony_ci cc_iowrite(drvdata, CC_REG(HOST_ICR), irr); 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_ci drvdata->irq = irr; 1558c2ecf20Sopenharmony_ci /* Completion interrupt - most probable */ 1568c2ecf20Sopenharmony_ci if (irr & drvdata->comp_mask) { 1578c2ecf20Sopenharmony_ci /* Mask all completion interrupts - will be unmasked in 1588c2ecf20Sopenharmony_ci * deferred service handler 1598c2ecf20Sopenharmony_ci */ 1608c2ecf20Sopenharmony_ci cc_iowrite(drvdata, CC_REG(HOST_IMR), imr | drvdata->comp_mask); 1618c2ecf20Sopenharmony_ci irr &= ~drvdata->comp_mask; 1628c2ecf20Sopenharmony_ci complete_request(drvdata); 1638c2ecf20Sopenharmony_ci } 1648c2ecf20Sopenharmony_ci#ifdef CONFIG_CRYPTO_FIPS 1658c2ecf20Sopenharmony_ci /* TEE FIPS interrupt */ 1668c2ecf20Sopenharmony_ci if (irr & CC_GPR0_IRQ_MASK) { 1678c2ecf20Sopenharmony_ci /* Mask interrupt - will be unmasked in Deferred service 1688c2ecf20Sopenharmony_ci * handler 1698c2ecf20Sopenharmony_ci */ 1708c2ecf20Sopenharmony_ci cc_iowrite(drvdata, CC_REG(HOST_IMR), imr | CC_GPR0_IRQ_MASK); 1718c2ecf20Sopenharmony_ci irr &= ~CC_GPR0_IRQ_MASK; 1728c2ecf20Sopenharmony_ci fips_handler(drvdata); 1738c2ecf20Sopenharmony_ci } 1748c2ecf20Sopenharmony_ci#endif 1758c2ecf20Sopenharmony_ci /* AXI error interrupt */ 1768c2ecf20Sopenharmony_ci if (irr & CC_AXI_ERR_IRQ_MASK) { 1778c2ecf20Sopenharmony_ci u32 axi_err; 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_ci /* Read the AXI error ID */ 1808c2ecf20Sopenharmony_ci axi_err = cc_ioread(drvdata, CC_REG(AXIM_MON_ERR)); 1818c2ecf20Sopenharmony_ci dev_dbg(dev, "AXI completion error: axim_mon_err=0x%08X\n", 1828c2ecf20Sopenharmony_ci axi_err); 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_ci irr &= ~CC_AXI_ERR_IRQ_MASK; 1858c2ecf20Sopenharmony_ci } 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_ci if (irr) { 1888c2ecf20Sopenharmony_ci dev_dbg_ratelimited(dev, "IRR includes unknown cause bits (0x%08X)\n", 1898c2ecf20Sopenharmony_ci irr); 1908c2ecf20Sopenharmony_ci /* Just warning */ 1918c2ecf20Sopenharmony_ci } 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_ci return IRQ_HANDLED; 1948c2ecf20Sopenharmony_ci} 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_cibool cc_wait_for_reset_completion(struct cc_drvdata *drvdata) 1978c2ecf20Sopenharmony_ci{ 1988c2ecf20Sopenharmony_ci unsigned int val; 1998c2ecf20Sopenharmony_ci unsigned int i; 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_ci /* 712/710/63 has no reset completion indication, always return true */ 2028c2ecf20Sopenharmony_ci if (drvdata->hw_rev <= CC_HW_REV_712) 2038c2ecf20Sopenharmony_ci return true; 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_ci for (i = 0; i < CC_HW_RESET_LOOP_COUNT; i++) { 2068c2ecf20Sopenharmony_ci /* in cc7x3 NVM_IS_IDLE indicates that CC reset is 2078c2ecf20Sopenharmony_ci * completed and device is fully functional 2088c2ecf20Sopenharmony_ci */ 2098c2ecf20Sopenharmony_ci val = cc_ioread(drvdata, CC_REG(NVM_IS_IDLE)); 2108c2ecf20Sopenharmony_ci if (val & CC_NVM_IS_IDLE_MASK) { 2118c2ecf20Sopenharmony_ci /* hw indicate reset completed */ 2128c2ecf20Sopenharmony_ci return true; 2138c2ecf20Sopenharmony_ci } 2148c2ecf20Sopenharmony_ci /* allow scheduling other process on the processor */ 2158c2ecf20Sopenharmony_ci schedule(); 2168c2ecf20Sopenharmony_ci } 2178c2ecf20Sopenharmony_ci /* reset not completed */ 2188c2ecf20Sopenharmony_ci return false; 2198c2ecf20Sopenharmony_ci} 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_ciint init_cc_regs(struct cc_drvdata *drvdata, bool is_probe) 2228c2ecf20Sopenharmony_ci{ 2238c2ecf20Sopenharmony_ci unsigned int val, cache_params; 2248c2ecf20Sopenharmony_ci struct device *dev = drvdata_to_dev(drvdata); 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_ci /* Unmask all AXI interrupt sources AXI_CFG1 register */ 2278c2ecf20Sopenharmony_ci /* AXI interrupt config are obsoleted startign at cc7x3 */ 2288c2ecf20Sopenharmony_ci if (drvdata->hw_rev <= CC_HW_REV_712) { 2298c2ecf20Sopenharmony_ci val = cc_ioread(drvdata, CC_REG(AXIM_CFG)); 2308c2ecf20Sopenharmony_ci cc_iowrite(drvdata, CC_REG(AXIM_CFG), val & ~CC_AXI_IRQ_MASK); 2318c2ecf20Sopenharmony_ci dev_dbg(dev, "AXIM_CFG=0x%08X\n", 2328c2ecf20Sopenharmony_ci cc_ioread(drvdata, CC_REG(AXIM_CFG))); 2338c2ecf20Sopenharmony_ci } 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_ci /* Clear all pending interrupts */ 2368c2ecf20Sopenharmony_ci val = cc_ioread(drvdata, CC_REG(HOST_IRR)); 2378c2ecf20Sopenharmony_ci dev_dbg(dev, "IRR=0x%08X\n", val); 2388c2ecf20Sopenharmony_ci cc_iowrite(drvdata, CC_REG(HOST_ICR), val); 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_ci /* Unmask relevant interrupt cause */ 2418c2ecf20Sopenharmony_ci val = drvdata->comp_mask | CC_AXI_ERR_IRQ_MASK; 2428c2ecf20Sopenharmony_ci 2438c2ecf20Sopenharmony_ci if (drvdata->hw_rev >= CC_HW_REV_712) 2448c2ecf20Sopenharmony_ci val |= CC_GPR0_IRQ_MASK; 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_ci cc_iowrite(drvdata, CC_REG(HOST_IMR), ~val); 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_ci cache_params = (drvdata->coherent ? CC_COHERENT_CACHE_PARAMS : 0x0); 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_ci val = cc_ioread(drvdata, CC_REG(AXIM_CACHE_PARAMS)); 2518c2ecf20Sopenharmony_ci 2528c2ecf20Sopenharmony_ci if (is_probe) 2538c2ecf20Sopenharmony_ci dev_dbg(dev, "Cache params previous: 0x%08X\n", val); 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_ci cc_iowrite(drvdata, CC_REG(AXIM_CACHE_PARAMS), cache_params); 2568c2ecf20Sopenharmony_ci val = cc_ioread(drvdata, CC_REG(AXIM_CACHE_PARAMS)); 2578c2ecf20Sopenharmony_ci 2588c2ecf20Sopenharmony_ci if (is_probe) 2598c2ecf20Sopenharmony_ci dev_dbg(dev, "Cache params current: 0x%08X (expect: 0x%08X)\n", 2608c2ecf20Sopenharmony_ci val, cache_params); 2618c2ecf20Sopenharmony_ci 2628c2ecf20Sopenharmony_ci return 0; 2638c2ecf20Sopenharmony_ci} 2648c2ecf20Sopenharmony_ci 2658c2ecf20Sopenharmony_cistatic int init_cc_resources(struct platform_device *plat_dev) 2668c2ecf20Sopenharmony_ci{ 2678c2ecf20Sopenharmony_ci struct resource *req_mem_cc_regs = NULL; 2688c2ecf20Sopenharmony_ci struct cc_drvdata *new_drvdata; 2698c2ecf20Sopenharmony_ci struct device *dev = &plat_dev->dev; 2708c2ecf20Sopenharmony_ci struct device_node *np = dev->of_node; 2718c2ecf20Sopenharmony_ci u32 val, hw_rev_pidr, sig_cidr; 2728c2ecf20Sopenharmony_ci u64 dma_mask; 2738c2ecf20Sopenharmony_ci const struct cc_hw_data *hw_rev; 2748c2ecf20Sopenharmony_ci struct clk *clk; 2758c2ecf20Sopenharmony_ci int irq; 2768c2ecf20Sopenharmony_ci int rc = 0; 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_ci new_drvdata = devm_kzalloc(dev, sizeof(*new_drvdata), GFP_KERNEL); 2798c2ecf20Sopenharmony_ci if (!new_drvdata) 2808c2ecf20Sopenharmony_ci return -ENOMEM; 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_ci hw_rev = of_device_get_match_data(dev); 2838c2ecf20Sopenharmony_ci new_drvdata->hw_rev_name = hw_rev->name; 2848c2ecf20Sopenharmony_ci new_drvdata->hw_rev = hw_rev->rev; 2858c2ecf20Sopenharmony_ci new_drvdata->std_bodies = hw_rev->std_bodies; 2868c2ecf20Sopenharmony_ci 2878c2ecf20Sopenharmony_ci if (hw_rev->rev >= CC_HW_REV_712) { 2888c2ecf20Sopenharmony_ci new_drvdata->axim_mon_offset = CC_REG(AXIM_MON_COMP); 2898c2ecf20Sopenharmony_ci new_drvdata->sig_offset = CC_REG(HOST_SIGNATURE_712); 2908c2ecf20Sopenharmony_ci new_drvdata->ver_offset = CC_REG(HOST_VERSION_712); 2918c2ecf20Sopenharmony_ci } else { 2928c2ecf20Sopenharmony_ci new_drvdata->axim_mon_offset = CC_REG(AXIM_MON_COMP8); 2938c2ecf20Sopenharmony_ci new_drvdata->sig_offset = CC_REG(HOST_SIGNATURE_630); 2948c2ecf20Sopenharmony_ci new_drvdata->ver_offset = CC_REG(HOST_VERSION_630); 2958c2ecf20Sopenharmony_ci } 2968c2ecf20Sopenharmony_ci 2978c2ecf20Sopenharmony_ci new_drvdata->comp_mask = CC_COMP_IRQ_MASK; 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_ci platform_set_drvdata(plat_dev, new_drvdata); 3008c2ecf20Sopenharmony_ci new_drvdata->plat_dev = plat_dev; 3018c2ecf20Sopenharmony_ci 3028c2ecf20Sopenharmony_ci clk = devm_clk_get_optional(dev, NULL); 3038c2ecf20Sopenharmony_ci if (IS_ERR(clk)) 3048c2ecf20Sopenharmony_ci return dev_err_probe(dev, PTR_ERR(clk), "Error getting clock\n"); 3058c2ecf20Sopenharmony_ci new_drvdata->clk = clk; 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_ci new_drvdata->coherent = of_dma_is_coherent(np); 3088c2ecf20Sopenharmony_ci 3098c2ecf20Sopenharmony_ci /* Get device resources */ 3108c2ecf20Sopenharmony_ci /* First CC registers space */ 3118c2ecf20Sopenharmony_ci req_mem_cc_regs = platform_get_resource(plat_dev, IORESOURCE_MEM, 0); 3128c2ecf20Sopenharmony_ci /* Map registers space */ 3138c2ecf20Sopenharmony_ci new_drvdata->cc_base = devm_ioremap_resource(dev, req_mem_cc_regs); 3148c2ecf20Sopenharmony_ci if (IS_ERR(new_drvdata->cc_base)) { 3158c2ecf20Sopenharmony_ci dev_err(dev, "Failed to ioremap registers"); 3168c2ecf20Sopenharmony_ci return PTR_ERR(new_drvdata->cc_base); 3178c2ecf20Sopenharmony_ci } 3188c2ecf20Sopenharmony_ci 3198c2ecf20Sopenharmony_ci dev_dbg(dev, "Got MEM resource (%s): %pR\n", req_mem_cc_regs->name, 3208c2ecf20Sopenharmony_ci req_mem_cc_regs); 3218c2ecf20Sopenharmony_ci dev_dbg(dev, "CC registers mapped from %pa to 0x%p\n", 3228c2ecf20Sopenharmony_ci &req_mem_cc_regs->start, new_drvdata->cc_base); 3238c2ecf20Sopenharmony_ci 3248c2ecf20Sopenharmony_ci /* Then IRQ */ 3258c2ecf20Sopenharmony_ci irq = platform_get_irq(plat_dev, 0); 3268c2ecf20Sopenharmony_ci if (irq < 0) 3278c2ecf20Sopenharmony_ci return irq; 3288c2ecf20Sopenharmony_ci 3298c2ecf20Sopenharmony_ci init_completion(&new_drvdata->hw_queue_avail); 3308c2ecf20Sopenharmony_ci 3318c2ecf20Sopenharmony_ci if (!dev->dma_mask) 3328c2ecf20Sopenharmony_ci dev->dma_mask = &dev->coherent_dma_mask; 3338c2ecf20Sopenharmony_ci 3348c2ecf20Sopenharmony_ci dma_mask = DMA_BIT_MASK(DMA_BIT_MASK_LEN); 3358c2ecf20Sopenharmony_ci while (dma_mask > 0x7fffffffUL) { 3368c2ecf20Sopenharmony_ci if (dma_supported(dev, dma_mask)) { 3378c2ecf20Sopenharmony_ci rc = dma_set_coherent_mask(dev, dma_mask); 3388c2ecf20Sopenharmony_ci if (!rc) 3398c2ecf20Sopenharmony_ci break; 3408c2ecf20Sopenharmony_ci } 3418c2ecf20Sopenharmony_ci dma_mask >>= 1; 3428c2ecf20Sopenharmony_ci } 3438c2ecf20Sopenharmony_ci 3448c2ecf20Sopenharmony_ci if (rc) { 3458c2ecf20Sopenharmony_ci dev_err(dev, "Failed in dma_set_mask, mask=%llx\n", dma_mask); 3468c2ecf20Sopenharmony_ci return rc; 3478c2ecf20Sopenharmony_ci } 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_ci rc = clk_prepare_enable(new_drvdata->clk); 3508c2ecf20Sopenharmony_ci if (rc) { 3518c2ecf20Sopenharmony_ci dev_err(dev, "Failed to enable clock"); 3528c2ecf20Sopenharmony_ci return rc; 3538c2ecf20Sopenharmony_ci } 3548c2ecf20Sopenharmony_ci 3558c2ecf20Sopenharmony_ci new_drvdata->sec_disabled = cc_sec_disable; 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_ci pm_runtime_set_autosuspend_delay(dev, CC_SUSPEND_TIMEOUT); 3588c2ecf20Sopenharmony_ci pm_runtime_use_autosuspend(dev); 3598c2ecf20Sopenharmony_ci pm_runtime_set_active(dev); 3608c2ecf20Sopenharmony_ci pm_runtime_enable(dev); 3618c2ecf20Sopenharmony_ci rc = pm_runtime_get_sync(dev); 3628c2ecf20Sopenharmony_ci if (rc < 0) { 3638c2ecf20Sopenharmony_ci dev_err(dev, "pm_runtime_get_sync() failed: %d\n", rc); 3648c2ecf20Sopenharmony_ci goto post_pm_err; 3658c2ecf20Sopenharmony_ci } 3668c2ecf20Sopenharmony_ci 3678c2ecf20Sopenharmony_ci /* Wait for Cryptocell reset completion */ 3688c2ecf20Sopenharmony_ci if (!cc_wait_for_reset_completion(new_drvdata)) { 3698c2ecf20Sopenharmony_ci dev_err(dev, "Cryptocell reset not completed"); 3708c2ecf20Sopenharmony_ci } 3718c2ecf20Sopenharmony_ci 3728c2ecf20Sopenharmony_ci if (hw_rev->rev <= CC_HW_REV_712) { 3738c2ecf20Sopenharmony_ci /* Verify correct mapping */ 3748c2ecf20Sopenharmony_ci val = cc_ioread(new_drvdata, new_drvdata->sig_offset); 3758c2ecf20Sopenharmony_ci if (val != hw_rev->sig) { 3768c2ecf20Sopenharmony_ci dev_err(dev, "Invalid CC signature: SIGNATURE=0x%08X != expected=0x%08X\n", 3778c2ecf20Sopenharmony_ci val, hw_rev->sig); 3788c2ecf20Sopenharmony_ci rc = -EINVAL; 3798c2ecf20Sopenharmony_ci goto post_pm_err; 3808c2ecf20Sopenharmony_ci } 3818c2ecf20Sopenharmony_ci sig_cidr = val; 3828c2ecf20Sopenharmony_ci hw_rev_pidr = cc_ioread(new_drvdata, new_drvdata->ver_offset); 3838c2ecf20Sopenharmony_ci } else { 3848c2ecf20Sopenharmony_ci /* Verify correct mapping */ 3858c2ecf20Sopenharmony_ci val = cc_read_idr(new_drvdata, pidr_0124_offsets); 3868c2ecf20Sopenharmony_ci if (val != hw_rev->pidr_0124) { 3878c2ecf20Sopenharmony_ci dev_err(dev, "Invalid CC PIDR: PIDR0124=0x%08X != expected=0x%08X\n", 3888c2ecf20Sopenharmony_ci val, hw_rev->pidr_0124); 3898c2ecf20Sopenharmony_ci rc = -EINVAL; 3908c2ecf20Sopenharmony_ci goto post_pm_err; 3918c2ecf20Sopenharmony_ci } 3928c2ecf20Sopenharmony_ci hw_rev_pidr = val; 3938c2ecf20Sopenharmony_ci 3948c2ecf20Sopenharmony_ci val = cc_read_idr(new_drvdata, cidr_0123_offsets); 3958c2ecf20Sopenharmony_ci if (val != hw_rev->cidr_0123) { 3968c2ecf20Sopenharmony_ci dev_err(dev, "Invalid CC CIDR: CIDR0123=0x%08X != expected=0x%08X\n", 3978c2ecf20Sopenharmony_ci val, hw_rev->cidr_0123); 3988c2ecf20Sopenharmony_ci rc = -EINVAL; 3998c2ecf20Sopenharmony_ci goto post_pm_err; 4008c2ecf20Sopenharmony_ci } 4018c2ecf20Sopenharmony_ci sig_cidr = val; 4028c2ecf20Sopenharmony_ci 4038c2ecf20Sopenharmony_ci /* Check HW engine configuration */ 4048c2ecf20Sopenharmony_ci val = cc_ioread(new_drvdata, CC_REG(HOST_REMOVE_INPUT_PINS)); 4058c2ecf20Sopenharmony_ci switch (val) { 4068c2ecf20Sopenharmony_ci case CC_PINS_FULL: 4078c2ecf20Sopenharmony_ci /* This is fine */ 4088c2ecf20Sopenharmony_ci break; 4098c2ecf20Sopenharmony_ci case CC_PINS_SLIM: 4108c2ecf20Sopenharmony_ci if (new_drvdata->std_bodies & CC_STD_NIST) { 4118c2ecf20Sopenharmony_ci dev_warn(dev, "703 mode forced due to HW configuration.\n"); 4128c2ecf20Sopenharmony_ci new_drvdata->std_bodies = CC_STD_OSCCA; 4138c2ecf20Sopenharmony_ci } 4148c2ecf20Sopenharmony_ci break; 4158c2ecf20Sopenharmony_ci default: 4168c2ecf20Sopenharmony_ci dev_err(dev, "Unsupported engines configuration.\n"); 4178c2ecf20Sopenharmony_ci rc = -EINVAL; 4188c2ecf20Sopenharmony_ci goto post_pm_err; 4198c2ecf20Sopenharmony_ci } 4208c2ecf20Sopenharmony_ci 4218c2ecf20Sopenharmony_ci /* Check security disable state */ 4228c2ecf20Sopenharmony_ci val = cc_ioread(new_drvdata, CC_REG(SECURITY_DISABLED)); 4238c2ecf20Sopenharmony_ci val &= CC_SECURITY_DISABLED_MASK; 4248c2ecf20Sopenharmony_ci new_drvdata->sec_disabled |= !!val; 4258c2ecf20Sopenharmony_ci 4268c2ecf20Sopenharmony_ci if (!new_drvdata->sec_disabled) { 4278c2ecf20Sopenharmony_ci new_drvdata->comp_mask |= CC_CPP_SM4_ABORT_MASK; 4288c2ecf20Sopenharmony_ci if (new_drvdata->std_bodies & CC_STD_NIST) 4298c2ecf20Sopenharmony_ci new_drvdata->comp_mask |= CC_CPP_AES_ABORT_MASK; 4308c2ecf20Sopenharmony_ci } 4318c2ecf20Sopenharmony_ci } 4328c2ecf20Sopenharmony_ci 4338c2ecf20Sopenharmony_ci if (new_drvdata->sec_disabled) 4348c2ecf20Sopenharmony_ci dev_info(dev, "Security Disabled mode is in effect. Security functions disabled.\n"); 4358c2ecf20Sopenharmony_ci 4368c2ecf20Sopenharmony_ci /* Display HW versions */ 4378c2ecf20Sopenharmony_ci dev_info(dev, "ARM CryptoCell %s Driver: HW version 0x%08X/0x%8X, Driver version %s\n", 4388c2ecf20Sopenharmony_ci hw_rev->name, hw_rev_pidr, sig_cidr, DRV_MODULE_VERSION); 4398c2ecf20Sopenharmony_ci /* register the driver isr function */ 4408c2ecf20Sopenharmony_ci rc = devm_request_irq(dev, irq, cc_isr, IRQF_SHARED, "ccree", 4418c2ecf20Sopenharmony_ci new_drvdata); 4428c2ecf20Sopenharmony_ci if (rc) { 4438c2ecf20Sopenharmony_ci dev_err(dev, "Could not register to interrupt %d\n", irq); 4448c2ecf20Sopenharmony_ci goto post_pm_err; 4458c2ecf20Sopenharmony_ci } 4468c2ecf20Sopenharmony_ci dev_dbg(dev, "Registered to IRQ: %d\n", irq); 4478c2ecf20Sopenharmony_ci 4488c2ecf20Sopenharmony_ci rc = init_cc_regs(new_drvdata, true); 4498c2ecf20Sopenharmony_ci if (rc) { 4508c2ecf20Sopenharmony_ci dev_err(dev, "init_cc_regs failed\n"); 4518c2ecf20Sopenharmony_ci goto post_pm_err; 4528c2ecf20Sopenharmony_ci } 4538c2ecf20Sopenharmony_ci 4548c2ecf20Sopenharmony_ci rc = cc_debugfs_init(new_drvdata); 4558c2ecf20Sopenharmony_ci if (rc) { 4568c2ecf20Sopenharmony_ci dev_err(dev, "Failed registering debugfs interface\n"); 4578c2ecf20Sopenharmony_ci goto post_regs_err; 4588c2ecf20Sopenharmony_ci } 4598c2ecf20Sopenharmony_ci 4608c2ecf20Sopenharmony_ci rc = cc_fips_init(new_drvdata); 4618c2ecf20Sopenharmony_ci if (rc) { 4628c2ecf20Sopenharmony_ci dev_err(dev, "cc_fips_init failed 0x%x\n", rc); 4638c2ecf20Sopenharmony_ci goto post_debugfs_err; 4648c2ecf20Sopenharmony_ci } 4658c2ecf20Sopenharmony_ci rc = cc_sram_mgr_init(new_drvdata); 4668c2ecf20Sopenharmony_ci if (rc) { 4678c2ecf20Sopenharmony_ci dev_err(dev, "cc_sram_mgr_init failed\n"); 4688c2ecf20Sopenharmony_ci goto post_fips_init_err; 4698c2ecf20Sopenharmony_ci } 4708c2ecf20Sopenharmony_ci 4718c2ecf20Sopenharmony_ci new_drvdata->mlli_sram_addr = 4728c2ecf20Sopenharmony_ci cc_sram_alloc(new_drvdata, MAX_MLLI_BUFF_SIZE); 4738c2ecf20Sopenharmony_ci if (new_drvdata->mlli_sram_addr == NULL_SRAM_ADDR) { 4748c2ecf20Sopenharmony_ci rc = -ENOMEM; 4758c2ecf20Sopenharmony_ci goto post_fips_init_err; 4768c2ecf20Sopenharmony_ci } 4778c2ecf20Sopenharmony_ci 4788c2ecf20Sopenharmony_ci rc = cc_req_mgr_init(new_drvdata); 4798c2ecf20Sopenharmony_ci if (rc) { 4808c2ecf20Sopenharmony_ci dev_err(dev, "cc_req_mgr_init failed\n"); 4818c2ecf20Sopenharmony_ci goto post_fips_init_err; 4828c2ecf20Sopenharmony_ci } 4838c2ecf20Sopenharmony_ci 4848c2ecf20Sopenharmony_ci rc = cc_buffer_mgr_init(new_drvdata); 4858c2ecf20Sopenharmony_ci if (rc) { 4868c2ecf20Sopenharmony_ci dev_err(dev, "cc_buffer_mgr_init failed\n"); 4878c2ecf20Sopenharmony_ci goto post_req_mgr_err; 4888c2ecf20Sopenharmony_ci } 4898c2ecf20Sopenharmony_ci 4908c2ecf20Sopenharmony_ci /* Allocate crypto algs */ 4918c2ecf20Sopenharmony_ci rc = cc_cipher_alloc(new_drvdata); 4928c2ecf20Sopenharmony_ci if (rc) { 4938c2ecf20Sopenharmony_ci dev_err(dev, "cc_cipher_alloc failed\n"); 4948c2ecf20Sopenharmony_ci goto post_buf_mgr_err; 4958c2ecf20Sopenharmony_ci } 4968c2ecf20Sopenharmony_ci 4978c2ecf20Sopenharmony_ci /* hash must be allocated before aead since hash exports APIs */ 4988c2ecf20Sopenharmony_ci rc = cc_hash_alloc(new_drvdata); 4998c2ecf20Sopenharmony_ci if (rc) { 5008c2ecf20Sopenharmony_ci dev_err(dev, "cc_hash_alloc failed\n"); 5018c2ecf20Sopenharmony_ci goto post_cipher_err; 5028c2ecf20Sopenharmony_ci } 5038c2ecf20Sopenharmony_ci 5048c2ecf20Sopenharmony_ci rc = cc_aead_alloc(new_drvdata); 5058c2ecf20Sopenharmony_ci if (rc) { 5068c2ecf20Sopenharmony_ci dev_err(dev, "cc_aead_alloc failed\n"); 5078c2ecf20Sopenharmony_ci goto post_hash_err; 5088c2ecf20Sopenharmony_ci } 5098c2ecf20Sopenharmony_ci 5108c2ecf20Sopenharmony_ci /* If we got here and FIPS mode is enabled 5118c2ecf20Sopenharmony_ci * it means all FIPS test passed, so let TEE 5128c2ecf20Sopenharmony_ci * know we're good. 5138c2ecf20Sopenharmony_ci */ 5148c2ecf20Sopenharmony_ci cc_set_ree_fips_status(new_drvdata, true); 5158c2ecf20Sopenharmony_ci 5168c2ecf20Sopenharmony_ci pm_runtime_put(dev); 5178c2ecf20Sopenharmony_ci return 0; 5188c2ecf20Sopenharmony_ci 5198c2ecf20Sopenharmony_cipost_hash_err: 5208c2ecf20Sopenharmony_ci cc_hash_free(new_drvdata); 5218c2ecf20Sopenharmony_cipost_cipher_err: 5228c2ecf20Sopenharmony_ci cc_cipher_free(new_drvdata); 5238c2ecf20Sopenharmony_cipost_buf_mgr_err: 5248c2ecf20Sopenharmony_ci cc_buffer_mgr_fini(new_drvdata); 5258c2ecf20Sopenharmony_cipost_req_mgr_err: 5268c2ecf20Sopenharmony_ci cc_req_mgr_fini(new_drvdata); 5278c2ecf20Sopenharmony_cipost_fips_init_err: 5288c2ecf20Sopenharmony_ci cc_fips_fini(new_drvdata); 5298c2ecf20Sopenharmony_cipost_debugfs_err: 5308c2ecf20Sopenharmony_ci cc_debugfs_fini(new_drvdata); 5318c2ecf20Sopenharmony_cipost_regs_err: 5328c2ecf20Sopenharmony_ci fini_cc_regs(new_drvdata); 5338c2ecf20Sopenharmony_cipost_pm_err: 5348c2ecf20Sopenharmony_ci pm_runtime_put_noidle(dev); 5358c2ecf20Sopenharmony_ci pm_runtime_disable(dev); 5368c2ecf20Sopenharmony_ci pm_runtime_set_suspended(dev); 5378c2ecf20Sopenharmony_ci clk_disable_unprepare(new_drvdata->clk); 5388c2ecf20Sopenharmony_ci return rc; 5398c2ecf20Sopenharmony_ci} 5408c2ecf20Sopenharmony_ci 5418c2ecf20Sopenharmony_civoid fini_cc_regs(struct cc_drvdata *drvdata) 5428c2ecf20Sopenharmony_ci{ 5438c2ecf20Sopenharmony_ci /* Mask all interrupts */ 5448c2ecf20Sopenharmony_ci cc_iowrite(drvdata, CC_REG(HOST_IMR), 0xFFFFFFFF); 5458c2ecf20Sopenharmony_ci} 5468c2ecf20Sopenharmony_ci 5478c2ecf20Sopenharmony_cistatic void cleanup_cc_resources(struct platform_device *plat_dev) 5488c2ecf20Sopenharmony_ci{ 5498c2ecf20Sopenharmony_ci struct device *dev = &plat_dev->dev; 5508c2ecf20Sopenharmony_ci struct cc_drvdata *drvdata = 5518c2ecf20Sopenharmony_ci (struct cc_drvdata *)platform_get_drvdata(plat_dev); 5528c2ecf20Sopenharmony_ci 5538c2ecf20Sopenharmony_ci cc_aead_free(drvdata); 5548c2ecf20Sopenharmony_ci cc_hash_free(drvdata); 5558c2ecf20Sopenharmony_ci cc_cipher_free(drvdata); 5568c2ecf20Sopenharmony_ci cc_buffer_mgr_fini(drvdata); 5578c2ecf20Sopenharmony_ci cc_req_mgr_fini(drvdata); 5588c2ecf20Sopenharmony_ci cc_fips_fini(drvdata); 5598c2ecf20Sopenharmony_ci cc_debugfs_fini(drvdata); 5608c2ecf20Sopenharmony_ci fini_cc_regs(drvdata); 5618c2ecf20Sopenharmony_ci pm_runtime_put_noidle(dev); 5628c2ecf20Sopenharmony_ci pm_runtime_disable(dev); 5638c2ecf20Sopenharmony_ci pm_runtime_set_suspended(dev); 5648c2ecf20Sopenharmony_ci clk_disable_unprepare(drvdata->clk); 5658c2ecf20Sopenharmony_ci} 5668c2ecf20Sopenharmony_ci 5678c2ecf20Sopenharmony_ciunsigned int cc_get_default_hash_len(struct cc_drvdata *drvdata) 5688c2ecf20Sopenharmony_ci{ 5698c2ecf20Sopenharmony_ci if (drvdata->hw_rev >= CC_HW_REV_712) 5708c2ecf20Sopenharmony_ci return HASH_LEN_SIZE_712; 5718c2ecf20Sopenharmony_ci else 5728c2ecf20Sopenharmony_ci return HASH_LEN_SIZE_630; 5738c2ecf20Sopenharmony_ci} 5748c2ecf20Sopenharmony_ci 5758c2ecf20Sopenharmony_cistatic int ccree_probe(struct platform_device *plat_dev) 5768c2ecf20Sopenharmony_ci{ 5778c2ecf20Sopenharmony_ci int rc; 5788c2ecf20Sopenharmony_ci struct device *dev = &plat_dev->dev; 5798c2ecf20Sopenharmony_ci 5808c2ecf20Sopenharmony_ci /* Map registers space */ 5818c2ecf20Sopenharmony_ci rc = init_cc_resources(plat_dev); 5828c2ecf20Sopenharmony_ci if (rc) 5838c2ecf20Sopenharmony_ci return rc; 5848c2ecf20Sopenharmony_ci 5858c2ecf20Sopenharmony_ci dev_info(dev, "ARM ccree device initialized\n"); 5868c2ecf20Sopenharmony_ci 5878c2ecf20Sopenharmony_ci return 0; 5888c2ecf20Sopenharmony_ci} 5898c2ecf20Sopenharmony_ci 5908c2ecf20Sopenharmony_cistatic int ccree_remove(struct platform_device *plat_dev) 5918c2ecf20Sopenharmony_ci{ 5928c2ecf20Sopenharmony_ci struct device *dev = &plat_dev->dev; 5938c2ecf20Sopenharmony_ci 5948c2ecf20Sopenharmony_ci dev_dbg(dev, "Releasing ccree resources...\n"); 5958c2ecf20Sopenharmony_ci 5968c2ecf20Sopenharmony_ci cleanup_cc_resources(plat_dev); 5978c2ecf20Sopenharmony_ci 5988c2ecf20Sopenharmony_ci dev_info(dev, "ARM ccree device terminated\n"); 5998c2ecf20Sopenharmony_ci 6008c2ecf20Sopenharmony_ci return 0; 6018c2ecf20Sopenharmony_ci} 6028c2ecf20Sopenharmony_ci 6038c2ecf20Sopenharmony_cistatic struct platform_driver ccree_driver = { 6048c2ecf20Sopenharmony_ci .driver = { 6058c2ecf20Sopenharmony_ci .name = "ccree", 6068c2ecf20Sopenharmony_ci .of_match_table = arm_ccree_dev_of_match, 6078c2ecf20Sopenharmony_ci#ifdef CONFIG_PM 6088c2ecf20Sopenharmony_ci .pm = &ccree_pm, 6098c2ecf20Sopenharmony_ci#endif 6108c2ecf20Sopenharmony_ci }, 6118c2ecf20Sopenharmony_ci .probe = ccree_probe, 6128c2ecf20Sopenharmony_ci .remove = ccree_remove, 6138c2ecf20Sopenharmony_ci}; 6148c2ecf20Sopenharmony_ci 6158c2ecf20Sopenharmony_cistatic int __init ccree_init(void) 6168c2ecf20Sopenharmony_ci{ 6178c2ecf20Sopenharmony_ci int rc; 6188c2ecf20Sopenharmony_ci 6198c2ecf20Sopenharmony_ci cc_debugfs_global_init(); 6208c2ecf20Sopenharmony_ci 6218c2ecf20Sopenharmony_ci rc = platform_driver_register(&ccree_driver); 6228c2ecf20Sopenharmony_ci if (rc) { 6238c2ecf20Sopenharmony_ci cc_debugfs_global_fini(); 6248c2ecf20Sopenharmony_ci return rc; 6258c2ecf20Sopenharmony_ci } 6268c2ecf20Sopenharmony_ci 6278c2ecf20Sopenharmony_ci return 0; 6288c2ecf20Sopenharmony_ci} 6298c2ecf20Sopenharmony_cimodule_init(ccree_init); 6308c2ecf20Sopenharmony_ci 6318c2ecf20Sopenharmony_cistatic void __exit ccree_exit(void) 6328c2ecf20Sopenharmony_ci{ 6338c2ecf20Sopenharmony_ci platform_driver_unregister(&ccree_driver); 6348c2ecf20Sopenharmony_ci cc_debugfs_global_fini(); 6358c2ecf20Sopenharmony_ci} 6368c2ecf20Sopenharmony_cimodule_exit(ccree_exit); 6378c2ecf20Sopenharmony_ci 6388c2ecf20Sopenharmony_ci/* Module description */ 6398c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("ARM TrustZone CryptoCell REE Driver"); 6408c2ecf20Sopenharmony_ciMODULE_VERSION(DRV_MODULE_VERSION); 6418c2ecf20Sopenharmony_ciMODULE_AUTHOR("ARM"); 6428c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2"); 643