1 // SPDX-License-Identifier: BSD-2-Clause 2 /* 3 * Copyright (C) 2022 Foundries.io Ltd 4 * Jorge Ramirez-Ortiz <jorge@foundries.io> 5 */ 6 7 #include <arm.h> 8 #include <drivers/versal_pm.h> 9 #include <drivers/versal_pmc.h> 10 #include <initcall.h> 11 #include <kernel/cache_helpers.h> 12 #include <kernel/delay.h> 13 #include <kernel/panic.h> 14 #include <kernel/thread.h> 15 #include <mm/core_memprot.h> 16 #include <string.h> 17 #include <tee/cache.h> 18 #include <tee_api_types.h> 19 #include <utee_defines.h> 20 21 #ifdef PLATFORM_FLAVOR_net 22 /* VERSAL_SIP_UID: 80d4c25a-ebaf-11eb-94680b4e3b8fc360 */ 23 #define VERSAL_SIP_UID_0 U(0x5ac2d480) 24 #define VERSAL_SIP_UID_1 U(0xeb11afeb) 25 #define VERSAL_SIP_UID_2 U(0x4e0b6894) 26 #define VERSAL_SIP_UID_3 U(0x60c38f3b) 27 #else 28 /* VERSAL_SIP_UID: 2ab9e4ec-93b9-11e7-a019dfe0dbad0ae0 */ 29 #define VERSAL_SIP_UID_0 U(0xece4b92a) 30 #define VERSAL_SIP_UID_1 U(0xe711b993) 31 #define VERSAL_SIP_UID_2 U(0xe0df19a0) 32 #define VERSAL_SIP_UID_3 U(0xe00aaddb) 33 #endif 34 #define VERSAL_SIP_MAJOR 0 35 #define VERSAL_SIP_MINOR 1 36 37 #define VERSAL_SIP_SVC_VERSION 0x8200ff03 38 #define VERSAL_SIP_SVC_UID 0x8200ff01 39 #define VERSAL_SIP_SVC 0xc2000000 40 41 #define PAYLOAD_ARG_CNT 8 42 43 /* MBOX IPI */ 44 #define PM_MODULE_SHIFT 8 45 #define PM_MODULE 2 46 #define PM_API_ID(x) ((PM_MODULE << PM_MODULE_SHIFT) | (x)) 47 #define VERSAL_PM_MAJOR 1 48 #define VERSAL_PM_MINOR 0 49 50 /* PM API ids */ 51 #define PM_GET_API_VERSION 1 52 #define PM_GET_DEVICE_STATUS 3 53 #define PM_GET_OP_CHARACTERISTIC 4 54 #define PM_REGISTER_NOTIFIER 5 55 #define PM_REQ_SUSPEND 6 56 #define PM_SELF_SUSPEND 7 57 #define PM_FORCE_POWERDOWN 8 58 #define PM_ABORT_SUSPEND 9 59 #define PM_REQ_WAKEUP 10 60 #define PM_SET_WAKEUP_SOURCE 11 61 #define PM_SYSTEM_SHUTDOWN 12 62 #define PM_REQUEST_DEVICE 13 63 #define PM_RELEASE_DEVICE 14 64 #define PM_SET_REQUIREMENT 15 65 #define PM_SET_MAX_LATENCY 16 66 #define PM_RESET_ASSERT 17 67 #define PM_RESET_GET_STATUS 18 68 #define PM_INIT_FINALIZE 21 69 #define PM_GET_CHIPID 24 70 #define PM_PINCTRL_REQUEST 28 71 #define PM_PINCTRL_RELEASE 29 72 #define PM_PINCTRL_GET_FUNCTION 30 73 #define PM_PINCTRL_SET_FUNCTION 31 74 #define PM_PINCTRL_CONFIG_PARAM_GET 32 75 #define PM_PINCTRL_CONFIG_PARAM_SET 33 76 #define PM_IOCTL 34 77 #define PM_QUERY_DATA 35 78 #define PM_CLOCK_ENABLE 36 79 #define PM_CLOCK_DISABLE 37 80 #define PM_CLOCK_GETSTATE 38 81 #define PM_CLOCK_SETDIVIDER 39 82 #define PM_CLOCK_GETDIVIDER 40 83 #define PM_CLOCK_SETRATE 41 84 #define PM_CLOCK_GETRATE 42 85 #define PM_CLOCK_SETPARENT 43 86 #define PM_CLOCK_GETPARENT 44 87 #define PM_PLL_SET_PARAMETER 48 88 #define PM_PLL_GET_PARAMETER 49 89 #define PM_PLL_SET_MODE 50 90 #define PM_PLL_GET_MODE 51 91 #define PM_FEATURE_CHECK 63 92 93 /* Loader API id */ 94 #define PM_LOAD_PDI 0x701 95 96 /* PDI sources */ 97 #define PDI_SRC_JTAG 0x0 98 #define PDI_SRC_QSPI24 0x1 99 #define PDI_SRC_QSPI32 0x2 100 #define PDI_SRC_SD0 0x3 101 #define PDI_SRC_EMMC0 0x4 102 #define PDI_SRC_SD1 0x5 103 #define PDI_SRC_EMMC1 0x6 104 #define PDI_SRC_USB 0x7 105 #define PDI_SRC_OSPI 0x8 106 #define PDI_SRC_SBI 0x9 107 #define PDI_SRC_SMAP 0xA 108 #define PDI_SRC_PCIE 0xB 109 #define PDI_SRC_SD1_LS 0xE 110 #define PDI_SRC_DDR 0xF 111 112 struct versal_sip_payload { 113 uint32_t data[PAYLOAD_ARG_CNT]; 114 }; 115 116 static uint32_t versal_sip_call(uint32_t smc_fid, uint32_t arg0, uint32_t arg1, 117 uint32_t arg2, uint32_t arg3, 118 struct versal_sip_payload *payload) 119 { 120 struct thread_smc_args args = { 121 .a0 = smc_fid, 122 .a1 = reg_pair_to_64(arg1, arg0), 123 .a2 = reg_pair_to_64(arg3, arg2), 124 }; 125 126 thread_smccc(&args); 127 128 if (payload) { 129 reg_pair_from_64(args.a0, &payload->data[1], &payload->data[0]); 130 reg_pair_from_64(args.a1, &payload->data[3], &payload->data[2]); 131 reg_pair_from_64(args.a2, &payload->data[5], &payload->data[4]); 132 reg_pair_from_64(args.a3, &payload->data[7], &payload->data[6]); 133 } 134 135 /* allow the PLM to output its debug information */ 136 if (IS_ENABLED(CFG_VERSAL_TRACE_PLM)) 137 mdelay(500); 138 139 return args.a0; 140 } 141 142 /* SIP call to program the FPGA has been obsoleted, use the PLM */ 143 TEE_Result versal_write_fpga(paddr_t pa) 144 { 145 struct versal_ipi_cmd cmd = { }; 146 147 cmd.data[0] = PM_LOAD_PDI; 148 cmd.data[1] = PDI_SRC_DDR; 149 reg_pair_from_64(pa, &cmd.data[2], &cmd.data[3]); 150 151 if (versal_pmc_notify(&cmd, NULL, NULL)) 152 return TEE_ERROR_GENERIC; 153 154 return TEE_SUCCESS; 155 } 156 157 TEE_Result versal_soc_version(uint8_t *version) 158 { 159 struct versal_sip_payload p = { }; 160 const uint32_t version_shift = 12; 161 162 if (!version) 163 return TEE_ERROR_BAD_PARAMETERS; 164 165 if (versal_sip_call(VERSAL_SIP_SVC | PM_GET_CHIPID, 0, 0, 0, 0, &p)) 166 return TEE_ERROR_GENERIC; 167 168 *version = p.data[2] >> version_shift; 169 170 return TEE_SUCCESS; 171 } 172 173 static bool uuid_is_versal_pm(void) 174 { 175 struct versal_sip_payload p = { }; 176 177 versal_sip_call(VERSAL_SIP_SVC_UID, 0, 0, 0, 0, &p); 178 179 if (p.data[0] == VERSAL_SIP_UID_0 && p.data[2] == VERSAL_SIP_UID_1 && 180 p.data[4] == VERSAL_SIP_UID_2 && p.data[6] == VERSAL_SIP_UID_3) 181 return true; 182 183 return false; 184 } 185 186 static TEE_Result versal_check_pm_abi(void) 187 { 188 struct versal_sip_payload p = { }; 189 struct versal_ipi_cmd cmd = { }; 190 struct versal_ipi_cmd rsp = { }; 191 unsigned int major = 0; 192 unsigned int minor = 0; 193 194 if (!uuid_is_versal_pm()) { 195 EMSG("Invalid SiP Service"); 196 return TEE_ERROR_GENERIC; 197 } 198 199 if (versal_sip_call(VERSAL_SIP_SVC_VERSION, 0, 0, 0, 0, &p)) 200 return TEE_ERROR_GENERIC; 201 202 major = p.data[0]; 203 minor = p.data[2]; 204 if (major != VERSAL_SIP_MAJOR || minor < VERSAL_SIP_MINOR) { 205 EMSG("Invalid SiP version: Major %d, Minor %d", major, minor); 206 return TEE_ERROR_GENERIC; 207 } 208 209 cmd.data[0] = PM_API_ID(PM_GET_API_VERSION); 210 if (versal_pmc_notify(&cmd, &rsp, NULL)) 211 return TEE_ERROR_GENERIC; 212 213 minor = rsp.data[1] & 0xFFFF; 214 major = rsp.data[1] >> 16; 215 if (major != VERSAL_PM_MAJOR || (int)minor < VERSAL_PM_MINOR) { 216 EMSG("Invalid PM version: Major %d, Minor %d", major, minor); 217 return TEE_ERROR_GENERIC; 218 } 219 220 return TEE_SUCCESS; 221 } 222 223 early_init_late(versal_check_pm_abi); 224