1 // SPDX-License-Identifier: BSD-2-Clause 2 /* 3 * Copyright (C) 2021 Foundries.io Ltd 4 */ 5 6 #include <arm.h> 7 #include <drivers/zynqmp_pm.h> 8 #include <kernel/cache_helpers.h> 9 #include <kernel/thread.h> 10 #include <mm/core_memprot.h> 11 #include <string.h> 12 #include <tee/cache.h> 13 #include <tee_api_types.h> 14 #include <types_ext.h> 15 #include <utee_defines.h> 16 17 /* 18 * For additional details about ZynqMP specific SMC ID's and PM request 19 * handling in TF-A check 20 * https://xilinx-wiki.atlassian.net/wiki/spaces/A/pages/18842107/Arm+Trusted+Firmware 21 */ 22 #define EFUSE_ACCESS_SMC 0xC2000035 23 #define VERSION_ACCESS_SMC 0xC2000018 24 25 #define EFUSE_NOT_ENABLED 29 26 #define VERSION_MASK GENMASK_32(3, 0) 27 28 static uint32_t zynqmp_sip_call(uint32_t pm_api_id, uint32_t arg0, 29 uint32_t arg1, uint32_t arg2, uint32_t arg3, 30 uint32_t *payload) 31 { 32 struct thread_smc_args args = { 33 .a0 = pm_api_id, 34 .a1 = reg_pair_to_64(arg1, arg0), 35 .a2 = reg_pair_to_64(arg3, arg2), 36 }; 37 38 thread_smccc(&args); 39 40 if (payload) { 41 switch (pm_api_id) { 42 case EFUSE_ACCESS_SMC: 43 *payload = args.a0 >> 32; 44 break; 45 case VERSION_ACCESS_SMC: 46 *payload = args.a1 & VERSION_MASK; 47 break; 48 default: 49 break; 50 } 51 } 52 53 return args.a0; 54 } 55 56 /* 57 * Stores all required details to read/write eFuse memory. 58 * @src: Physical address of the buffer to store the data to be 59 * written/read (in LE) 60 * @size: number of 32-bit words to be read/written 61 * @offset: offset in bytes to be read from/written to 62 * @flag: EFUSE_READ - represents eFuse read operation 63 * EFUSE_WRITE - represents eFuse write operation 64 * @pufuserfuse:0 - represents non-PUF eFuses, offset is used for read/write 65 * 1 - represents PUF user eFuse row number. 66 */ 67 struct xilinx_efuse { 68 uint64_t src; 69 uint32_t size; 70 uint32_t offset; 71 uint32_t flag; 72 uint32_t pufuserfuse; 73 }; 74 75 enum efuse_op { EFUSE_READ = 0, EFUSE_WRITE = 1 }; 76 77 #define EFUSE_ELT(__x) \ 78 [__x] = { \ 79 .offset = ZYNQMP_EFUSE_##__x##_OFFSET, \ 80 .bytes = ZYNQMP_EFUSE_##__x##_LENGTH, \ 81 } 82 83 static const struct { 84 uint32_t offset; 85 uint32_t bytes; 86 } efuse_tbl[] = { 87 EFUSE_ELT(DNA), 88 EFUSE_ELT(IP_DISABLE), 89 EFUSE_ELT(MISC_USER_CTRL), 90 EFUSE_ELT(SEC_CTRL), 91 }; 92 93 static TEE_Result efuse_op(enum efuse_op op, uint8_t *buf, size_t buf_sz, 94 enum zynqmp_efuse_id id, bool puf) 95 { 96 struct xilinx_efuse efuse = { }; 97 paddr_t addr = 0; 98 uint32_t res = 0; 99 100 if (!buf) 101 return TEE_ERROR_BAD_PARAMETERS; 102 103 if (id >= ARRAY_SIZE(efuse_tbl)) { 104 EMSG("Invalid efuse"); 105 return TEE_ERROR_BAD_PARAMETERS; 106 } 107 108 if (!IS_ALIGNED((uintptr_t)buf, CACHELINE_LEN)) { 109 EMSG("Buffer should be cache aligned"); 110 return TEE_ERROR_BAD_PARAMETERS; 111 } 112 113 if (!IS_ALIGNED(buf_sz, CACHELINE_LEN)) 114 return TEE_ERROR_BAD_PARAMETERS; 115 116 efuse.size = efuse_tbl[id].bytes / sizeof(uint32_t); 117 efuse.offset = efuse_tbl[id].offset; 118 efuse.src = virt_to_phys(buf); 119 efuse.pufuserfuse = puf; 120 efuse.flag = op; 121 122 cache_operation(TEE_CACHECLEAN, buf, buf_sz); 123 cache_operation(TEE_CACHECLEAN, &efuse, sizeof(efuse)); 124 125 addr = virt_to_phys(&efuse); 126 127 res = zynqmp_sip_call(EFUSE_ACCESS_SMC, addr >> 32, addr, 0, 0, NULL); 128 if (res) { 129 if (res == EFUSE_NOT_ENABLED) 130 EMSG("eFuse access is not enabled"); 131 else 132 EMSG("Error in eFuse access %#"PRIx32, res); 133 134 return TEE_ERROR_GENERIC; 135 } 136 137 if (op == EFUSE_READ) 138 return cache_operation(TEE_CACHEINVALIDATE, buf, buf_sz); 139 140 return TEE_ERROR_NOT_IMPLEMENTED; 141 } 142 143 TEE_Result zynqmp_efuse_read(uint8_t *buf, size_t sz, enum zynqmp_efuse_id id, 144 bool puf) 145 { 146 return efuse_op(EFUSE_READ, buf, sz, id, puf); 147 } 148 149 TEE_Result zynqmp_soc_version(uint32_t *version) 150 { 151 uint32_t res = 0; 152 153 if (!version) 154 return TEE_ERROR_BAD_PARAMETERS; 155 156 res = zynqmp_sip_call(VERSION_ACCESS_SMC, 0, 0, 0, 0, version); 157 if (res) { 158 EMSG("Failed to retrieve version"); 159 return TEE_ERROR_GENERIC; 160 } 161 162 return TEE_SUCCESS; 163 } 164