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