xref: /optee_os/core/arch/arm/plat-stm32mp1/scmi_server.c (revision 8fa3e895ff00f06f6666a9dfa0affaa3451775cf)
1 // SPDX-License-Identifier: BSD-2-Clause
2 /*
3  * Copyright (c) 2019, STMicroelectronics
4  */
5 #include <assert.h>
6 #include <compiler.h>
7 #include <drivers/scmi-msg.h>
8 #include <drivers/scmi.h>
9 #include <dt-bindings/reset/stm32mp1-resets.h>
10 #include <initcall.h>
11 #include <mm/core_memprot.h>
12 #include <mm/core_mmu.h>
13 #include <platform_config.h>
14 #include <stdint.h>
15 #include <speculation_barrier.h>
16 #include <stm32_util.h>
17 #include <string.h>
18 #include <tee_api_defines.h>
19 #include <util.h>
20 
21 #define TIMEOUT_US_1MS		1000
22 
23 #define SCMI_RD_NAME_SIZE	16
24 
25 /*
26  * struct stm32_scmi_rd - Data for the exposed reset controller
27  * @reset_id: Reset identifier in RCC reset driver
28  * @name: Reset string ID exposed to agent
29  */
30 struct stm32_scmi_rd {
31 	unsigned long reset_id;
32 	const char *name;
33 };
34 
35 /* Locate all non-secure SMT message buffers in last page of SYSRAM */
36 #define SMT_BUFFER_BASE		CFG_STM32MP1_SCMI_SHM_BASE
37 #define SMT_BUFFER0_BASE	SMT_BUFFER_BASE
38 #define SMT_BUFFER1_BASE	(SMT_BUFFER_BASE + 0x200)
39 
40 #if (SMT_BUFFER1_BASE + SMT_BUF_SLOT_SIZE > \
41 	CFG_STM32MP1_SCMI_SHM_BASE + CFG_STM32MP1_SCMI_SHM_SIZE)
42 #error "SCMI shared memory mismatch"
43 #endif
44 
45 register_phys_mem(MEM_AREA_IO_NSEC, CFG_STM32MP1_SCMI_SHM_BASE,
46 		  CFG_STM32MP1_SCMI_SHM_SIZE);
47 
48 static struct scmi_msg_channel scmi_channel[] = {
49 	[0] = {
50 		.agent_name = "stm32mp1-agent-0",
51 		.shm_addr = { .pa = SMT_BUFFER0_BASE, },
52 		.shm_size = SMT_BUF_SLOT_SIZE,
53 	},
54 	[1] = {
55 		.agent_name = "stm32mp1-agent-1",
56 		.shm_addr =  { .pa = SMT_BUFFER1_BASE, },
57 		.shm_size = SMT_BUF_SLOT_SIZE,
58 	},
59 };
60 
61 struct scmi_msg_channel *plat_scmi_get_channel(unsigned int agent_id)
62 {
63 	assert(agent_id < ARRAY_SIZE(scmi_channel));
64 
65 	return &scmi_channel[agent_id];
66 }
67 
68 #define RESET_CELL(_scmi_id, _id, _name) \
69 	[_scmi_id] = { \
70 		.reset_id = _id, \
71 		.name = _name, \
72 	}
73 
74 struct stm32_scmi_rd stm32_scmi0_reset_domain[] = {
75 	RESET_CELL(RST_SCMI0_SPI6, SPI6_R, "spi6"),
76 	RESET_CELL(RST_SCMI0_I2C4, I2C4_R, "i2c4"),
77 	RESET_CELL(RST_SCMI0_I2C6, I2C6_R, "i2c6"),
78 	RESET_CELL(RST_SCMI0_USART1, USART1_R, "usart1"),
79 	RESET_CELL(RST_SCMI0_STGEN, STGEN_R, "stgen"),
80 	RESET_CELL(RST_SCMI0_GPIOZ, GPIOZ_R, "gpioz"),
81 	RESET_CELL(RST_SCMI0_CRYP1, CRYP1_R, "cryp1"),
82 	RESET_CELL(RST_SCMI0_HASH1, HASH1_R, "hash1"),
83 	RESET_CELL(RST_SCMI0_RNG1, RNG1_R, "rng1"),
84 	RESET_CELL(RST_SCMI0_MDMA, MDMA_R, "mdma"),
85 	RESET_CELL(RST_SCMI0_MCU, MCU_R, "mcu"),
86 };
87 
88 struct scmi_agent_resources {
89 	struct stm32_scmi_clk *clock;
90 	size_t clock_count;
91 	struct stm32_scmi_rd *rd;
92 	size_t rd_count;
93 	struct stm32_scmi_pd *pd;
94 	size_t pd_count;
95 	struct stm32_scmi_perfs *perfs;
96 	size_t perfs_count;
97 };
98 
99 const struct scmi_agent_resources agent_resources[] = {
100 	[0] = {
101 		.rd = stm32_scmi0_reset_domain,
102 		.rd_count = ARRAY_SIZE(stm32_scmi0_reset_domain),
103 	},
104 	[1] = { },
105 };
106 
107 static const struct scmi_agent_resources *find_resource(unsigned int agent_id)
108 {
109 	assert(agent_id < ARRAY_SIZE(agent_resources));
110 
111 	return &agent_resources[agent_id];
112 }
113 
114 static size_t __maybe_unused plat_scmi_protocol_count_paranoid(void)
115 {
116 	unsigned int n = 0;
117 	unsigned int count = 0;
118 	const size_t agent_count = ARRAY_SIZE(agent_resources);
119 
120 	for (n = 0; n < agent_count; n++)
121 		if (agent_resources[n].clock_count)
122 			break;
123 	if (n < agent_count)
124 		count++;
125 
126 	for (n = 0; n < agent_count; n++)
127 		if (agent_resources[n].rd_count)
128 			break;
129 	if (n < agent_count)
130 		count++;
131 
132 	for (n = 0; n < agent_count; n++)
133 		if (agent_resources[n].pd_count)
134 			break;
135 	if (n < agent_count)
136 		count++;
137 
138 	for (n = 0; n < agent_count; n++)
139 		if (agent_resources[n].perfs_count)
140 			break;
141 	if (n < agent_count)
142 		count++;
143 
144 	return count;
145 }
146 
147 static const char vendor[] = "ST";
148 static const char sub_vendor[] = "";
149 
150 const char *plat_scmi_vendor_name(void)
151 {
152 	return vendor;
153 }
154 
155 const char *plat_scmi_sub_vendor_name(void)
156 {
157 	return sub_vendor;
158 }
159 
160 /* Currently supporting Reset Domains */
161 static const uint8_t plat_protocol_list[] = {
162 	SCMI_PROTOCOL_ID_RESET_DOMAIN,
163 	0 /* Null termination */
164 };
165 
166 size_t plat_scmi_protocol_count(void)
167 {
168 	const size_t count = ARRAY_SIZE(plat_protocol_list) - 1;
169 
170 	assert(count == plat_scmi_protocol_count_paranoid());
171 
172 	return count;
173 }
174 
175 const uint8_t *plat_scmi_protocol_list(unsigned int agent_id __unused)
176 {
177 	assert(plat_scmi_protocol_count_paranoid() ==
178 	       (ARRAY_SIZE(plat_protocol_list) - 1));
179 
180 	return plat_protocol_list;
181 }
182 
183 /*
184  * Platform SCMI reset domains
185  */
186 static struct stm32_scmi_rd *find_rd(unsigned int agent_id,
187 				     unsigned int scmi_id)
188 {
189 	const struct scmi_agent_resources *resource = find_resource(agent_id);
190 	size_t n = 0;
191 
192 	if (resource) {
193 		for (n = 0; n < resource->rd_count; n++)
194 			if (n == scmi_id)
195 				return &resource->rd[n];
196 	}
197 
198 	return NULL;
199 }
200 
201 const char *plat_scmi_rd_get_name(unsigned int agent_id, unsigned int scmi_id)
202 {
203 	const struct stm32_scmi_rd *rd = find_rd(agent_id, scmi_id);
204 
205 	if (!rd)
206 		return NULL;
207 
208 	return rd->name;
209 }
210 
211 size_t plat_scmi_rd_count(unsigned int agent_id)
212 {
213 	const struct scmi_agent_resources *resource = find_resource(agent_id);
214 
215 	if (!resource)
216 		return 0;
217 
218 	return resource->rd_count;
219 }
220 
221 int32_t plat_scmi_rd_autonomous(unsigned int agent_id, unsigned int scmi_id,
222 				uint32_t state)
223 {
224 	const struct stm32_scmi_rd *rd = find_rd(agent_id, scmi_id);
225 
226 	if (!rd)
227 		return SCMI_NOT_FOUND;
228 
229 	if (!stm32mp_nsec_can_access_reset(rd->reset_id))
230 		return SCMI_DENIED;
231 
232 	/* Supports only reset with context loss */
233 	if (state)
234 		return SCMI_NOT_SUPPORTED;
235 
236 	DMSG("SCMI reset %u cycle", scmi_id);
237 
238 	if (stm32_reset_assert(rd->reset_id, TIMEOUT_US_1MS))
239 		return SCMI_HARDWARE_ERROR;
240 
241 	if (stm32_reset_deassert(rd->reset_id, TIMEOUT_US_1MS))
242 		return SCMI_HARDWARE_ERROR;
243 
244 	return SCMI_SUCCESS;
245 }
246 
247 int32_t plat_scmi_rd_set_state(unsigned int agent_id, unsigned int scmi_id,
248 			       bool assert_not_deassert)
249 {
250 	const struct stm32_scmi_rd *rd = find_rd(agent_id, scmi_id);
251 
252 	if (!rd)
253 		return SCMI_NOT_FOUND;
254 
255 	if (!stm32mp_nsec_can_access_reset(rd->reset_id))
256 		return SCMI_DENIED;
257 
258 	if (assert_not_deassert) {
259 		DMSG("SCMI reset %u set", scmi_id);
260 		stm32_reset_set(rd->reset_id);
261 	} else {
262 		DMSG("SCMI reset %u release", scmi_id);
263 		stm32_reset_release(rd->reset_id);
264 	}
265 
266 	return SCMI_SUCCESS;
267 }
268 
269 /*
270  * Initialize platform SCMI resources
271  */
272 static TEE_Result stm32mp1_init_scmi_server(void)
273 {
274 	size_t i = 0;
275 	size_t j = 0;
276 
277 	for (i = 0; i < ARRAY_SIZE(scmi_channel); i++) {
278 		struct scmi_msg_channel *chan = &scmi_channel[i];
279 
280 		/* Enforce non-secure shm mapped as device memory */
281 		chan->shm_addr.va = (vaddr_t)phys_to_virt(chan->shm_addr.pa,
282 							  MEM_AREA_IO_NSEC);
283 		assert(chan->shm_addr.va);
284 
285 		scmi_smt_init_agent_channel(chan);
286 	}
287 
288 	for (i = 0; i < ARRAY_SIZE(agent_resources); i++) {
289 		const struct scmi_agent_resources *res = &agent_resources[i];
290 
291 		for (j = 0; j < res->rd_count; j++) {
292 			struct stm32_scmi_rd *rd = &res->rd[j];
293 
294 			if (!rd->name ||
295 			    strlen(rd->name) >= SCMI_RD_NAME_SIZE)
296 				panic("SCMI reset domain name invalid");
297 		}
298 	}
299 
300 	return TEE_SUCCESS;
301 }
302 
303 driver_init_late(stm32mp1_init_scmi_server);
304