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