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
zynqmp_sip_call(uint32_t pm_api_id,uint32_t arg0,uint32_t arg1,uint32_t arg2,uint32_t arg3,uint32_t * payload)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
efuse_op(enum efuse_op op,uint8_t * buf,size_t buf_sz,enum zynqmp_efuse_id id,bool puf)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
zynqmp_efuse_read(uint8_t * buf,size_t sz,enum zynqmp_efuse_id id,bool puf)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
zynqmp_efuse_write(uint8_t * buf,size_t sz,enum zynqmp_efuse_id id,bool puf)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
zynqmp_soc_version(uint32_t * version)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