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
versal_sip_call(uint32_t smc_fid,uint32_t arg0,uint32_t arg1,uint32_t arg2,uint32_t arg3,struct versal_sip_payload * payload)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 */
versal_write_fpga(paddr_t pa)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
versal_soc_version(uint8_t * version)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
uuid_is_versal_pm(void)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
versal_check_pm_abi(void)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