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