19b61a2bcSJorge Ramirez-Ortiz // SPDX-License-Identifier: BSD-2-Clause 29b61a2bcSJorge Ramirez-Ortiz /* 39b61a2bcSJorge Ramirez-Ortiz * Copyright (C) 2021 Foundries.io Ltd 49b61a2bcSJorge Ramirez-Ortiz */ 59b61a2bcSJorge Ramirez-Ortiz 69b61a2bcSJorge Ramirez-Ortiz #include <arm.h> 79b61a2bcSJorge Ramirez-Ortiz #include <drivers/zynqmp_pm.h> 89b61a2bcSJorge Ramirez-Ortiz #include <kernel/cache_helpers.h> 997558570SVesa Jääskeläinen #include <kernel/tee_misc.h> 109b61a2bcSJorge Ramirez-Ortiz #include <kernel/thread.h> 119b61a2bcSJorge Ramirez-Ortiz #include <mm/core_memprot.h> 129b61a2bcSJorge Ramirez-Ortiz #include <string.h> 139b61a2bcSJorge Ramirez-Ortiz #include <tee/cache.h> 149b61a2bcSJorge Ramirez-Ortiz #include <tee_api_types.h> 159b61a2bcSJorge Ramirez-Ortiz #include <types_ext.h> 169b61a2bcSJorge Ramirez-Ortiz #include <utee_defines.h> 179b61a2bcSJorge Ramirez-Ortiz 189b61a2bcSJorge Ramirez-Ortiz /* 199b61a2bcSJorge Ramirez-Ortiz * For additional details about ZynqMP specific SMC ID's and PM request 209b61a2bcSJorge Ramirez-Ortiz * handling in TF-A check 219b61a2bcSJorge Ramirez-Ortiz * https://xilinx-wiki.atlassian.net/wiki/spaces/A/pages/18842107/Arm+Trusted+Firmware 229b61a2bcSJorge Ramirez-Ortiz */ 239b61a2bcSJorge Ramirez-Ortiz #define EFUSE_ACCESS_SMC 0xC2000035 249b61a2bcSJorge Ramirez-Ortiz #define VERSION_ACCESS_SMC 0xC2000018 259b61a2bcSJorge Ramirez-Ortiz 269b61a2bcSJorge Ramirez-Ortiz #define EFUSE_NOT_ENABLED 29 279b61a2bcSJorge Ramirez-Ortiz #define VERSION_MASK GENMASK_32(3, 0) 289b61a2bcSJorge Ramirez-Ortiz 299b61a2bcSJorge Ramirez-Ortiz static uint32_t zynqmp_sip_call(uint32_t pm_api_id, uint32_t arg0, 309b61a2bcSJorge Ramirez-Ortiz uint32_t arg1, uint32_t arg2, uint32_t arg3, 319b61a2bcSJorge Ramirez-Ortiz uint32_t *payload) 329b61a2bcSJorge Ramirez-Ortiz { 339b61a2bcSJorge Ramirez-Ortiz struct thread_smc_args args = { 349b61a2bcSJorge Ramirez-Ortiz .a0 = pm_api_id, 359b61a2bcSJorge Ramirez-Ortiz .a1 = reg_pair_to_64(arg1, arg0), 369b61a2bcSJorge Ramirez-Ortiz .a2 = reg_pair_to_64(arg3, arg2), 379b61a2bcSJorge Ramirez-Ortiz }; 389b61a2bcSJorge Ramirez-Ortiz 399b61a2bcSJorge Ramirez-Ortiz thread_smccc(&args); 409b61a2bcSJorge Ramirez-Ortiz 419b61a2bcSJorge Ramirez-Ortiz if (payload) { 429b61a2bcSJorge Ramirez-Ortiz switch (pm_api_id) { 439b61a2bcSJorge Ramirez-Ortiz case EFUSE_ACCESS_SMC: 449b61a2bcSJorge Ramirez-Ortiz *payload = args.a0 >> 32; 459b61a2bcSJorge Ramirez-Ortiz break; 469b61a2bcSJorge Ramirez-Ortiz case VERSION_ACCESS_SMC: 479b61a2bcSJorge Ramirez-Ortiz *payload = args.a1 & VERSION_MASK; 489b61a2bcSJorge Ramirez-Ortiz break; 499b61a2bcSJorge Ramirez-Ortiz default: 509b61a2bcSJorge Ramirez-Ortiz break; 519b61a2bcSJorge Ramirez-Ortiz } 529b61a2bcSJorge Ramirez-Ortiz } 539b61a2bcSJorge Ramirez-Ortiz 549b61a2bcSJorge Ramirez-Ortiz return args.a0; 559b61a2bcSJorge Ramirez-Ortiz } 569b61a2bcSJorge Ramirez-Ortiz 579b61a2bcSJorge Ramirez-Ortiz /* 589b61a2bcSJorge Ramirez-Ortiz * Stores all required details to read/write eFuse memory. 599b61a2bcSJorge Ramirez-Ortiz * @src: Physical address of the buffer to store the data to be 609b61a2bcSJorge Ramirez-Ortiz * written/read (in LE) 619b61a2bcSJorge Ramirez-Ortiz * @size: number of 32-bit words to be read/written 629b61a2bcSJorge Ramirez-Ortiz * @offset: offset in bytes to be read from/written to 639b61a2bcSJorge Ramirez-Ortiz * @flag: EFUSE_READ - represents eFuse read operation 649b61a2bcSJorge Ramirez-Ortiz * EFUSE_WRITE - represents eFuse write operation 659b61a2bcSJorge Ramirez-Ortiz * @pufuserfuse:0 - represents non-PUF eFuses, offset is used for read/write 669b61a2bcSJorge Ramirez-Ortiz * 1 - represents PUF user eFuse row number. 679b61a2bcSJorge Ramirez-Ortiz */ 689b61a2bcSJorge Ramirez-Ortiz struct xilinx_efuse { 699b61a2bcSJorge Ramirez-Ortiz uint64_t src; 709b61a2bcSJorge Ramirez-Ortiz uint32_t size; 719b61a2bcSJorge Ramirez-Ortiz uint32_t offset; 729b61a2bcSJorge Ramirez-Ortiz uint32_t flag; 739b61a2bcSJorge Ramirez-Ortiz uint32_t pufuserfuse; 749b61a2bcSJorge Ramirez-Ortiz }; 759b61a2bcSJorge Ramirez-Ortiz 769b61a2bcSJorge Ramirez-Ortiz enum efuse_op { EFUSE_READ = 0, EFUSE_WRITE = 1 }; 779b61a2bcSJorge Ramirez-Ortiz 789b61a2bcSJorge Ramirez-Ortiz #define EFUSE_ELT(__x) \ 799b61a2bcSJorge Ramirez-Ortiz [__x] = { \ 809b61a2bcSJorge Ramirez-Ortiz .offset = ZYNQMP_EFUSE_##__x##_OFFSET, \ 819b61a2bcSJorge Ramirez-Ortiz .bytes = ZYNQMP_EFUSE_##__x##_LENGTH, \ 829b61a2bcSJorge Ramirez-Ortiz } 839b61a2bcSJorge Ramirez-Ortiz 849b61a2bcSJorge Ramirez-Ortiz static const struct { 859b61a2bcSJorge Ramirez-Ortiz uint32_t offset; 869b61a2bcSJorge Ramirez-Ortiz uint32_t bytes; 879b61a2bcSJorge Ramirez-Ortiz } efuse_tbl[] = { 889b61a2bcSJorge Ramirez-Ortiz EFUSE_ELT(DNA), 899b61a2bcSJorge Ramirez-Ortiz EFUSE_ELT(IP_DISABLE), 909b61a2bcSJorge Ramirez-Ortiz EFUSE_ELT(MISC_USER_CTRL), 919b61a2bcSJorge Ramirez-Ortiz EFUSE_ELT(SEC_CTRL), 929b61a2bcSJorge Ramirez-Ortiz }; 939b61a2bcSJorge Ramirez-Ortiz 949b61a2bcSJorge Ramirez-Ortiz static TEE_Result efuse_op(enum efuse_op op, uint8_t *buf, size_t buf_sz, 959b61a2bcSJorge Ramirez-Ortiz enum zynqmp_efuse_id id, bool puf) 969b61a2bcSJorge Ramirez-Ortiz { 9797558570SVesa Jääskeläinen struct xilinx_efuse *efuse_op = NULL; 9897558570SVesa Jääskeläinen uint8_t *tmpbuf = NULL; 999b61a2bcSJorge Ramirez-Ortiz paddr_t addr = 0; 10097558570SVesa Jääskeläinen uint32_t efuse_ret = 0; 10197558570SVesa Jääskeläinen TEE_Result res = TEE_ERROR_GENERIC; 1029b61a2bcSJorge Ramirez-Ortiz 1039b61a2bcSJorge Ramirez-Ortiz if (!buf) 1049b61a2bcSJorge Ramirez-Ortiz return TEE_ERROR_BAD_PARAMETERS; 1059b61a2bcSJorge Ramirez-Ortiz 1069b61a2bcSJorge Ramirez-Ortiz if (id >= ARRAY_SIZE(efuse_tbl)) { 1079b61a2bcSJorge Ramirez-Ortiz EMSG("Invalid efuse"); 1089b61a2bcSJorge Ramirez-Ortiz return TEE_ERROR_BAD_PARAMETERS; 1099b61a2bcSJorge Ramirez-Ortiz } 1109b61a2bcSJorge Ramirez-Ortiz 11197558570SVesa Jääskeläinen efuse_op = alloc_cache_aligned(sizeof(*efuse_op)); 11297558570SVesa Jääskeläinen if (!efuse_op) { 11397558570SVesa Jääskeläinen EMSG("Failed to allocate cache aligned buffer for operation"); 11497558570SVesa Jääskeläinen return TEE_ERROR_OUT_OF_MEMORY; 1159b61a2bcSJorge Ramirez-Ortiz } 1169b61a2bcSJorge Ramirez-Ortiz 11797558570SVesa Jääskeläinen tmpbuf = alloc_cache_aligned(buf_sz); 11897558570SVesa Jääskeläinen if (!tmpbuf) { 11997558570SVesa Jääskeläinen EMSG("Failed to allocate cache aligned buffer for data"); 12097558570SVesa Jääskeläinen res = TEE_ERROR_OUT_OF_MEMORY; 12197558570SVesa Jääskeläinen goto out; 12297558570SVesa Jääskeläinen } 1239b61a2bcSJorge Ramirez-Ortiz 124*6e96536eSVesa Jääskeläinen if (op == EFUSE_WRITE) 125*6e96536eSVesa Jääskeläinen memcpy(tmpbuf, buf, buf_sz); 126*6e96536eSVesa Jääskeläinen 12797558570SVesa Jääskeläinen efuse_op->size = efuse_tbl[id].bytes / sizeof(uint32_t); 12897558570SVesa Jääskeläinen efuse_op->offset = efuse_tbl[id].offset; 12997558570SVesa Jääskeläinen efuse_op->src = virt_to_phys(tmpbuf); 13097558570SVesa Jääskeläinen efuse_op->pufuserfuse = puf; 13197558570SVesa Jääskeläinen efuse_op->flag = op; 1329b61a2bcSJorge Ramirez-Ortiz 13397558570SVesa Jääskeläinen cache_operation(TEE_CACHECLEAN, tmpbuf, buf_sz); 13497558570SVesa Jääskeläinen cache_operation(TEE_CACHECLEAN, efuse_op, sizeof(*efuse_op)); 1359b61a2bcSJorge Ramirez-Ortiz 13697558570SVesa Jääskeläinen addr = virt_to_phys(efuse_op); 1379b61a2bcSJorge Ramirez-Ortiz 13897558570SVesa Jääskeläinen efuse_ret = zynqmp_sip_call(EFUSE_ACCESS_SMC, addr >> 32, addr, 0, 0, 13997558570SVesa Jääskeläinen NULL); 14097558570SVesa Jääskeläinen if (efuse_ret) { 14197558570SVesa Jääskeläinen if (efuse_ret == EFUSE_NOT_ENABLED) 1429b61a2bcSJorge Ramirez-Ortiz EMSG("eFuse access is not enabled"); 1439b61a2bcSJorge Ramirez-Ortiz else 14497558570SVesa Jääskeläinen EMSG("Error in eFuse access %#"PRIx32, efuse_ret); 14597558570SVesa Jääskeläinen res = TEE_ERROR_GENERIC; 14697558570SVesa Jääskeläinen goto out; 1479b61a2bcSJorge Ramirez-Ortiz } 1489b61a2bcSJorge Ramirez-Ortiz 14997558570SVesa Jääskeläinen if (op == EFUSE_READ) { 15097558570SVesa Jääskeläinen res = cache_operation(TEE_CACHEINVALIDATE, tmpbuf, buf_sz); 15197558570SVesa Jääskeläinen if (res) 15297558570SVesa Jääskeläinen goto out; 15397558570SVesa Jääskeläinen memcpy(buf, tmpbuf, buf_sz); 15497558570SVesa Jääskeläinen } 1559b61a2bcSJorge Ramirez-Ortiz 156*6e96536eSVesa Jääskeläinen res = TEE_SUCCESS; 157*6e96536eSVesa Jääskeläinen 15897558570SVesa Jääskeläinen out: 15997558570SVesa Jääskeläinen free(tmpbuf); 16097558570SVesa Jääskeläinen free(efuse_op); 16197558570SVesa Jääskeläinen return res; 1629b61a2bcSJorge Ramirez-Ortiz } 1639b61a2bcSJorge Ramirez-Ortiz 1649b61a2bcSJorge Ramirez-Ortiz TEE_Result zynqmp_efuse_read(uint8_t *buf, size_t sz, enum zynqmp_efuse_id id, 1659b61a2bcSJorge Ramirez-Ortiz bool puf) 1669b61a2bcSJorge Ramirez-Ortiz { 1679b61a2bcSJorge Ramirez-Ortiz return efuse_op(EFUSE_READ, buf, sz, id, puf); 1689b61a2bcSJorge Ramirez-Ortiz } 1699b61a2bcSJorge Ramirez-Ortiz 170*6e96536eSVesa Jääskeläinen TEE_Result zynqmp_efuse_write(uint8_t *buf, size_t sz, enum zynqmp_efuse_id id, 171*6e96536eSVesa Jääskeläinen bool puf) 172*6e96536eSVesa Jääskeläinen { 173*6e96536eSVesa Jääskeläinen return efuse_op(EFUSE_WRITE, buf, sz, id, puf); 174*6e96536eSVesa Jääskeläinen } 175*6e96536eSVesa Jääskeläinen 1769b61a2bcSJorge Ramirez-Ortiz TEE_Result zynqmp_soc_version(uint32_t *version) 1779b61a2bcSJorge Ramirez-Ortiz { 1789b61a2bcSJorge Ramirez-Ortiz uint32_t res = 0; 1799b61a2bcSJorge Ramirez-Ortiz 1809b61a2bcSJorge Ramirez-Ortiz if (!version) 1819b61a2bcSJorge Ramirez-Ortiz return TEE_ERROR_BAD_PARAMETERS; 1829b61a2bcSJorge Ramirez-Ortiz 1839b61a2bcSJorge Ramirez-Ortiz res = zynqmp_sip_call(VERSION_ACCESS_SMC, 0, 0, 0, 0, version); 1849b61a2bcSJorge Ramirez-Ortiz if (res) { 1859b61a2bcSJorge Ramirez-Ortiz EMSG("Failed to retrieve version"); 1869b61a2bcSJorge Ramirez-Ortiz return TEE_ERROR_GENERIC; 1879b61a2bcSJorge Ramirez-Ortiz } 1889b61a2bcSJorge Ramirez-Ortiz 1899b61a2bcSJorge Ramirez-Ortiz return TEE_SUCCESS; 1909b61a2bcSJorge Ramirez-Ortiz } 191