xref: /optee_os/core/lib/scmi-server/scmi_server_scpfw.c (revision c9a214b74d8c39349681c23c5486e510a0599c3c)
1ce6ea411SValentin Caron // SPDX-License-Identifier: BSD-2-Clause
2ce6ea411SValentin Caron /*
3ce6ea411SValentin Caron  * Copyright (c) 2024, STMicroelectronics International N.V.
4ce6ea411SValentin Caron  */
5ce6ea411SValentin Caron 
6ce6ea411SValentin Caron #include <assert.h>
7ce6ea411SValentin Caron #include <drivers/scmi.h>
8ce6ea411SValentin Caron #include <kernel/boot.h>
9ce6ea411SValentin Caron #include <kernel/dt.h>
10ce6ea411SValentin Caron #include <kernel/panic.h>
11ce6ea411SValentin Caron #include <libfdt.h>
12ce6ea411SValentin Caron #include <scmi_agent_configuration.h>
13b61cea09SValentin Caron #include <scmi_clock_consumer.h>
14*c9a214b7SValentin Caron #include <scmi_reset_consumer.h>
15ce6ea411SValentin Caron #include <stdlib.h>
16ce6ea411SValentin Caron #include <sys/queue.h>
17ce6ea411SValentin Caron #include <util.h>
18ce6ea411SValentin Caron 
19ce6ea411SValentin Caron /*
20ce6ea411SValentin Caron  * struct optee_scmi_server - Data of scmi_server_scpfw
21ce6ea411SValentin Caron  *
22ce6ea411SValentin Caron  * @dt_name: SCMI node name
23ce6ea411SValentin Caron  * @agent_list: list of optee_scmi_server_agent
24ce6ea411SValentin Caron  */
25ce6ea411SValentin Caron struct optee_scmi_server {
26ce6ea411SValentin Caron 	const char *dt_name;
27ce6ea411SValentin Caron 	SIMPLEQ_HEAD(, optee_scmi_server_agent) agent_list;
28ce6ea411SValentin Caron };
29ce6ea411SValentin Caron 
30ce6ea411SValentin Caron /*
31ce6ea411SValentin Caron  * @struct optee_scmi_server_agent - Data of an SCMI agent
32ce6ea411SValentin Caron  *
33ce6ea411SValentin Caron  * @dt_name: SCMI agent node name
34ce6ea411SValentin Caron  * @agent_id: SCMI agent identifier
35ce6ea411SValentin Caron  * @channel_id: SCMI channel identifier
36ce6ea411SValentin Caron  * @protocol_list: list of optee_scmi_server_protocol
37ce6ea411SValentin Caron  * @link: link for optee_scmi_server:agent_list
38ce6ea411SValentin Caron  */
39ce6ea411SValentin Caron struct optee_scmi_server_agent {
40ce6ea411SValentin Caron 	const char *dt_name;
41ce6ea411SValentin Caron 	unsigned int agent_id;
42ce6ea411SValentin Caron 	unsigned int channel_id;
43ce6ea411SValentin Caron 	SIMPLEQ_HEAD(, optee_scmi_server_protocol) protocol_list;
44ce6ea411SValentin Caron 	SIMPLEQ_ENTRY(optee_scmi_server_agent) link;
45ce6ea411SValentin Caron };
46ce6ea411SValentin Caron 
47ce6ea411SValentin Caron /*
48ce6ea411SValentin Caron  * struct optee_scmi_server_protocol - Data of an SCMI protocol
49ce6ea411SValentin Caron  *
50ce6ea411SValentin Caron  * @dt_name: SCMI protocol node name
51ce6ea411SValentin Caron  * @dt_node: SCMI protocol node
52ce6ea411SValentin Caron  * @protocol_id: SCMI protocol identifier
53ce6ea411SValentin Caron  * @link: list for optee_scmi_server_agent:protocol_list
54ce6ea411SValentin Caron  */
55ce6ea411SValentin Caron struct optee_scmi_server_protocol {
56ce6ea411SValentin Caron 	const char *dt_name;
57ce6ea411SValentin Caron 	int dt_node;
58ce6ea411SValentin Caron 	unsigned int protocol_id;
59ce6ea411SValentin Caron 	SIMPLEQ_ENTRY(optee_scmi_server_protocol) link;
60ce6ea411SValentin Caron };
61ce6ea411SValentin Caron 
62ce6ea411SValentin Caron /* scmi_agent_configuration API */
63ce6ea411SValentin Caron static struct scpfw_config scpfw_cfg;
64ce6ea411SValentin Caron 
scmi_scpfw_free_agent(struct scpfw_agent_config * agent_cfg)65ce6ea411SValentin Caron static void scmi_scpfw_free_agent(struct scpfw_agent_config *agent_cfg)
66ce6ea411SValentin Caron {
67b61cea09SValentin Caron 	unsigned int j = 0;
68b61cea09SValentin Caron 
69b61cea09SValentin Caron 	for (j = 0; j < agent_cfg->channel_count; j++) {
70b61cea09SValentin Caron 		struct scpfw_channel_config *channel_cfg =
71b61cea09SValentin Caron 			agent_cfg->channel_config + j;
72b61cea09SValentin Caron 
73*c9a214b7SValentin Caron 		free(channel_cfg->reset);
74b61cea09SValentin Caron 		free(channel_cfg->clock);
75b61cea09SValentin Caron 	}
76ce6ea411SValentin Caron 	free(agent_cfg->channel_config);
77ce6ea411SValentin Caron }
78ce6ea411SValentin Caron 
scmi_scpfw_get_configuration(void)79ce6ea411SValentin Caron struct scpfw_config *scmi_scpfw_get_configuration(void)
80ce6ea411SValentin Caron {
81ce6ea411SValentin Caron 	struct scpfw_agent_config *old_agent_config = scpfw_cfg.agent_config;
82ce6ea411SValentin Caron 
83ce6ea411SValentin Caron 	assert(scpfw_cfg.agent_count >= 1);
84ce6ea411SValentin Caron 	assert(!old_agent_config[0].channel_count);
85ce6ea411SValentin Caron 
86ce6ea411SValentin Caron 	/*
87ce6ea411SValentin Caron 	 * The agents config data passed to SCP-firmware do not consider
88ce6ea411SValentin Caron 	 * agent ID 0 that is reserved for the SCMI server itself in
89ce6ea411SValentin Caron 	 * SCP-firmware and therefore has no configuration data.
90ce6ea411SValentin Caron 	 */
91ce6ea411SValentin Caron 	scpfw_cfg.agent_count--;
92ce6ea411SValentin Caron 	scpfw_cfg.agent_config = calloc(scpfw_cfg.agent_count,
93ce6ea411SValentin Caron 					sizeof(*scpfw_cfg.agent_config));
94ce6ea411SValentin Caron 
95ce6ea411SValentin Caron 	memcpy(scpfw_cfg.agent_config, old_agent_config + 1,
96ce6ea411SValentin Caron 	       sizeof(*scpfw_cfg.agent_config) * scpfw_cfg.agent_count);
97ce6ea411SValentin Caron 
98ce6ea411SValentin Caron 	free(old_agent_config);
99ce6ea411SValentin Caron 
100ce6ea411SValentin Caron 	return &scpfw_cfg;
101ce6ea411SValentin Caron }
102ce6ea411SValentin Caron 
scmi_scpfw_release_configuration(void)103ce6ea411SValentin Caron void scmi_scpfw_release_configuration(void)
104ce6ea411SValentin Caron {
105ce6ea411SValentin Caron 	unsigned int i = 0;
106ce6ea411SValentin Caron 
107ce6ea411SValentin Caron 	for (i = 0; i < scpfw_cfg.agent_count; i++)
108ce6ea411SValentin Caron 		scmi_scpfw_free_agent(scpfw_cfg.agent_config + i);
109ce6ea411SValentin Caron 
110ce6ea411SValentin Caron 	free(scpfw_cfg.agent_config);
111ce6ea411SValentin Caron }
112ce6ea411SValentin Caron 
optee_scmi_server_probe_agent(const void * fdt,int agent_node,struct optee_scmi_server_agent * agent_ctx)113ce6ea411SValentin Caron static TEE_Result optee_scmi_server_probe_agent(const void *fdt, int agent_node,
114ce6ea411SValentin Caron 						struct optee_scmi_server_agent
115ce6ea411SValentin Caron 							*agent_ctx)
116ce6ea411SValentin Caron {
117ce6ea411SValentin Caron 	struct optee_scmi_server_protocol *protocol_ctx = NULL;
118ce6ea411SValentin Caron 	int protocol_node = 0;
119ce6ea411SValentin Caron 	const fdt32_t *cuint = NULL;
120ce6ea411SValentin Caron 
121ce6ea411SValentin Caron 	SIMPLEQ_INIT(&agent_ctx->protocol_list);
122ce6ea411SValentin Caron 
123ce6ea411SValentin Caron 	/*
124ce6ea411SValentin Caron 	 * Get agent ID from reg property, implicitly a single
125ce6ea411SValentin Caron 	 * 32bit cell value. (required)
126ce6ea411SValentin Caron 	 */
127ce6ea411SValentin Caron 	cuint = fdt_getprop(fdt, agent_node, "reg", NULL);
128ce6ea411SValentin Caron 	if (!cuint) {
129ce6ea411SValentin Caron 		EMSG("%s Missing property reg", agent_ctx->dt_name);
130ce6ea411SValentin Caron 		panic();
131ce6ea411SValentin Caron 	}
132ce6ea411SValentin Caron 	agent_ctx->agent_id = fdt32_to_cpu(*cuint);
133ce6ea411SValentin Caron 
134ce6ea411SValentin Caron 	/* Agent ID 0 is strictly reserved to SCMI server. */
135ce6ea411SValentin Caron 	assert(agent_ctx->agent_id > 0);
136ce6ea411SValentin Caron 
137ce6ea411SValentin Caron 	if (!fdt_node_check_compatible(fdt, agent_node, "linaro,scmi-optee")) {
138ce6ea411SValentin Caron 		cuint = fdt_getprop(fdt, agent_node, "scmi-channel-id", NULL);
139ce6ea411SValentin Caron 		if (!cuint) {
140ce6ea411SValentin Caron 			EMSG("%s scmi-channel-id property not found",
141ce6ea411SValentin Caron 			     agent_ctx->dt_name);
142ce6ea411SValentin Caron 			panic();
143ce6ea411SValentin Caron 		}
144ce6ea411SValentin Caron 		agent_ctx->channel_id = fdt32_to_cpu(*cuint);
145ce6ea411SValentin Caron 	} else {
146ce6ea411SValentin Caron 		EMSG("%s Incorrect compatible", agent_ctx->dt_name);
147ce6ea411SValentin Caron 		panic();
148ce6ea411SValentin Caron 	}
149ce6ea411SValentin Caron 
150ce6ea411SValentin Caron 	fdt_for_each_subnode(protocol_node, fdt, agent_node) {
151ce6ea411SValentin Caron 		const char *node_name = fdt_get_name(fdt, protocol_node, NULL);
152ce6ea411SValentin Caron 		struct optee_scmi_server_protocol *p = NULL;
153ce6ea411SValentin Caron 
154ce6ea411SValentin Caron 		if (!strstr(node_name, "protocol@"))
155ce6ea411SValentin Caron 			continue;
156ce6ea411SValentin Caron 
157ce6ea411SValentin Caron 		protocol_ctx = calloc(1, sizeof(*protocol_ctx));
158ce6ea411SValentin Caron 		if (!protocol_ctx)
159ce6ea411SValentin Caron 			return TEE_ERROR_OUT_OF_MEMORY;
160ce6ea411SValentin Caron 
161ce6ea411SValentin Caron 		protocol_ctx->dt_name = node_name;
162ce6ea411SValentin Caron 		protocol_ctx->dt_node = protocol_node;
163ce6ea411SValentin Caron 
164ce6ea411SValentin Caron 		/*
165ce6ea411SValentin Caron 		 * Get protocol ID from reg property, implicitly a single
166ce6ea411SValentin Caron 		 * 32bit cell value. (required)
167ce6ea411SValentin Caron 		 */
168ce6ea411SValentin Caron 		cuint = fdt_getprop(fdt, protocol_node, "reg", NULL);
169ce6ea411SValentin Caron 		if (!cuint) {
170ce6ea411SValentin Caron 			EMSG("%s Missing property reg", protocol_ctx->dt_name);
171ce6ea411SValentin Caron 			panic();
172ce6ea411SValentin Caron 		}
173ce6ea411SValentin Caron 		protocol_ctx->protocol_id = fdt32_to_cpu(*cuint);
174ce6ea411SValentin Caron 
175ce6ea411SValentin Caron 		SIMPLEQ_FOREACH(p, &agent_ctx->protocol_list, link)
176ce6ea411SValentin Caron 			assert(p->protocol_id != protocol_ctx->protocol_id);
177ce6ea411SValentin Caron 
178ce6ea411SValentin Caron 		SIMPLEQ_INSERT_TAIL(&agent_ctx->protocol_list, protocol_ctx,
179ce6ea411SValentin Caron 				    link);
180ce6ea411SValentin Caron 	}
181ce6ea411SValentin Caron 
182ce6ea411SValentin Caron 	return TEE_SUCCESS;
183ce6ea411SValentin Caron }
184ce6ea411SValentin Caron 
185ce6ea411SValentin Caron static void
optee_scmi_server_init_protocol(const void * fdt,struct optee_scmi_server_protocol * protocol_ctx,struct scpfw_agent_config * agent_cfg,struct scpfw_channel_config * channel_cfg)186ce6ea411SValentin Caron optee_scmi_server_init_protocol(const void *fdt,
187ce6ea411SValentin Caron 				struct optee_scmi_server_protocol *protocol_ctx,
188b61cea09SValentin Caron 				struct scpfw_agent_config *agent_cfg,
189b61cea09SValentin Caron 				struct scpfw_channel_config *channel_cfg)
190ce6ea411SValentin Caron {
191ce6ea411SValentin Caron 	switch (protocol_ctx->protocol_id) {
192b61cea09SValentin Caron 	case SCMI_PROTOCOL_ID_CLOCK:
193b61cea09SValentin Caron 		if (optee_scmi_server_init_clocks(fdt, protocol_ctx->dt_node,
194b61cea09SValentin Caron 						  agent_cfg, channel_cfg))
195b61cea09SValentin Caron 			panic("Error during clocks init");
196b61cea09SValentin Caron 		break;
197*c9a214b7SValentin Caron 	case SCMI_PROTOCOL_ID_RESET_DOMAIN:
198*c9a214b7SValentin Caron 		if (optee_scmi_server_init_resets(fdt, protocol_ctx->dt_node,
199*c9a214b7SValentin Caron 						  agent_cfg, channel_cfg))
200*c9a214b7SValentin Caron 			panic("Error during resets init");
201*c9a214b7SValentin Caron 		break;
202ce6ea411SValentin Caron 	default:
203ce6ea411SValentin Caron 		EMSG("%s Unknown protocol ID: %#x", protocol_ctx->dt_name,
204ce6ea411SValentin Caron 		     protocol_ctx->protocol_id);
205ce6ea411SValentin Caron 		panic();
206ce6ea411SValentin Caron 	}
207ce6ea411SValentin Caron }
208ce6ea411SValentin Caron 
optee_scmi_server_probe(const void * fdt,int parent_node,const void * compat_data __unused)209ce6ea411SValentin Caron static TEE_Result optee_scmi_server_probe(const void *fdt, int parent_node,
210ce6ea411SValentin Caron 					  const void *compat_data __unused)
211ce6ea411SValentin Caron {
212ce6ea411SValentin Caron 	struct optee_scmi_server *ctx = NULL;
213ce6ea411SValentin Caron 	struct optee_scmi_server_agent *agent_ctx = NULL;
214ce6ea411SValentin Caron 	struct optee_scmi_server_agent *a = NULL;
215ce6ea411SValentin Caron 	TEE_Result res = TEE_SUCCESS;
216ce6ea411SValentin Caron 	unsigned int agent_cfg_count = 0;
217ce6ea411SValentin Caron 	unsigned int i = 0;
218ce6ea411SValentin Caron 	int agent_node = 0;
219ce6ea411SValentin Caron 
220ce6ea411SValentin Caron 	ctx = calloc(1, sizeof(*ctx));
221ce6ea411SValentin Caron 	if (!ctx)
222ce6ea411SValentin Caron 		return TEE_ERROR_OUT_OF_MEMORY;
223ce6ea411SValentin Caron 
224ce6ea411SValentin Caron 	ctx->dt_name = fdt_get_name(fdt, parent_node, NULL);
225ce6ea411SValentin Caron 
226ce6ea411SValentin Caron 	/* Read device tree */
227ce6ea411SValentin Caron 	SIMPLEQ_INIT(&ctx->agent_list);
228ce6ea411SValentin Caron 
229ce6ea411SValentin Caron 	fdt_for_each_subnode(agent_node, fdt, parent_node) {
230ce6ea411SValentin Caron 		const char *node_name = fdt_get_name(fdt, agent_node, NULL);
231ce6ea411SValentin Caron 
232ce6ea411SValentin Caron 		if (!strstr(node_name, "agent@"))
233ce6ea411SValentin Caron 			continue;
234ce6ea411SValentin Caron 
235ce6ea411SValentin Caron 		agent_ctx = calloc(1, sizeof(*agent_ctx));
236ce6ea411SValentin Caron 		if (!agent_ctx) {
237ce6ea411SValentin Caron 			res = TEE_ERROR_OUT_OF_MEMORY;
238ce6ea411SValentin Caron 			goto fail_agent;
239ce6ea411SValentin Caron 		}
240ce6ea411SValentin Caron 		agent_ctx->dt_name = node_name;
241ce6ea411SValentin Caron 
242ce6ea411SValentin Caron 		res = optee_scmi_server_probe_agent(fdt, agent_node, agent_ctx);
243ce6ea411SValentin Caron 		if (res)
244ce6ea411SValentin Caron 			goto fail_agent;
245ce6ea411SValentin Caron 
246ce6ea411SValentin Caron 		SIMPLEQ_FOREACH(a, &ctx->agent_list, link)
247ce6ea411SValentin Caron 			assert(a->agent_id != agent_ctx->agent_id);
248ce6ea411SValentin Caron 
249ce6ea411SValentin Caron 		SIMPLEQ_INSERT_TAIL(&ctx->agent_list, agent_ctx, link);
250ce6ea411SValentin Caron 		agent_cfg_count = MAX(agent_cfg_count, agent_ctx->agent_id);
251ce6ea411SValentin Caron 	}
252ce6ea411SValentin Caron 
253ce6ea411SValentin Caron 	agent_cfg_count++;
254ce6ea411SValentin Caron 
255ce6ea411SValentin Caron 	/* Create SCMI config structures */
256ce6ea411SValentin Caron 	scpfw_cfg.agent_count = agent_cfg_count;
257ce6ea411SValentin Caron 	scpfw_cfg.agent_config = calloc(scpfw_cfg.agent_count,
258ce6ea411SValentin Caron 					sizeof(*scpfw_cfg.agent_config));
259ce6ea411SValentin Caron 	if (!scpfw_cfg.agent_config) {
260ce6ea411SValentin Caron 		res = TEE_ERROR_OUT_OF_MEMORY;
261ce6ea411SValentin Caron 		scpfw_cfg.agent_count = 0;
262ce6ea411SValentin Caron 		goto fail_agent;
263ce6ea411SValentin Caron 	}
264ce6ea411SValentin Caron 
265ce6ea411SValentin Caron 	SIMPLEQ_FOREACH(agent_ctx, &ctx->agent_list, link) {
266ce6ea411SValentin Caron 		struct scpfw_agent_config *agent_cfg =
267ce6ea411SValentin Caron 			scpfw_cfg.agent_config + agent_ctx->agent_id;
268ce6ea411SValentin Caron 
269ce6ea411SValentin Caron 		agent_cfg->name = (const char *)strdup(agent_ctx->dt_name);
270ce6ea411SValentin Caron 		if (!agent_cfg->name) {
271ce6ea411SValentin Caron 			res = TEE_ERROR_OUT_OF_MEMORY;
272ce6ea411SValentin Caron 			goto fail_scpfw_cfg;
273ce6ea411SValentin Caron 		}
274ce6ea411SValentin Caron 
275ce6ea411SValentin Caron 		agent_cfg->agent_id = agent_ctx->agent_id;
276ce6ea411SValentin Caron 
277ce6ea411SValentin Caron 		/*
278ce6ea411SValentin Caron 		 * Right now this driver can handle one channel per agent only.
279ce6ea411SValentin Caron 		 */
280ce6ea411SValentin Caron 		assert(agent_ctx->channel_id == 0);
281ce6ea411SValentin Caron 		agent_cfg->channel_count = 1;
282ce6ea411SValentin Caron 		agent_cfg->channel_config =
283ce6ea411SValentin Caron 			calloc(agent_cfg->channel_count,
284ce6ea411SValentin Caron 			       sizeof(*agent_cfg->channel_config));
285ce6ea411SValentin Caron 		if (!agent_cfg->channel_config) {
286ce6ea411SValentin Caron 			res = TEE_ERROR_OUT_OF_MEMORY;
287ce6ea411SValentin Caron 			agent_cfg->channel_count = 0;
288ce6ea411SValentin Caron 			goto fail_scpfw_cfg;
289ce6ea411SValentin Caron 		}
290ce6ea411SValentin Caron 
291ce6ea411SValentin Caron 		for (i = 0; i < agent_cfg->channel_count; i++) {
292ce6ea411SValentin Caron 			struct scpfw_channel_config *channel_cfg =
293ce6ea411SValentin Caron 				agent_cfg->channel_config + i;
294ce6ea411SValentin Caron 
295ce6ea411SValentin Caron 			channel_cfg->name = "channel";
296ce6ea411SValentin Caron 			channel_cfg->channel_id = agent_ctx->channel_id;
297ce6ea411SValentin Caron 		}
298ce6ea411SValentin Caron 	}
299ce6ea411SValentin Caron 
300ce6ea411SValentin Caron 	/* Parse protocols and fill channels config */
301ce6ea411SValentin Caron 	SIMPLEQ_FOREACH(agent_ctx, &ctx->agent_list, link) {
302ce6ea411SValentin Caron 		struct optee_scmi_server_protocol *protocol_ctx = NULL;
303ce6ea411SValentin Caron 		struct scpfw_agent_config *agent_cfg =
304ce6ea411SValentin Caron 			scpfw_cfg.agent_config + agent_ctx->agent_id;
305ce6ea411SValentin Caron 		struct scpfw_channel_config *channel_cfg =
306ce6ea411SValentin Caron 			agent_cfg->channel_config + agent_ctx->channel_id;
307ce6ea411SValentin Caron 
308ce6ea411SValentin Caron 		SIMPLEQ_FOREACH(protocol_ctx, &agent_ctx->protocol_list, link)
309ce6ea411SValentin Caron 			optee_scmi_server_init_protocol(fdt, protocol_ctx,
310ce6ea411SValentin Caron 							agent_cfg, channel_cfg);
311ce6ea411SValentin Caron 	}
312ce6ea411SValentin Caron 
313ce6ea411SValentin Caron 	return TEE_SUCCESS;
314ce6ea411SValentin Caron 
315ce6ea411SValentin Caron fail_scpfw_cfg:
316ce6ea411SValentin Caron 	scmi_scpfw_release_configuration();
317ce6ea411SValentin Caron 
318ce6ea411SValentin Caron 	for (i = 0; i < scpfw_cfg.agent_count; i++)
319ce6ea411SValentin Caron 		free((void *)scpfw_cfg.agent_config[i].name);
320ce6ea411SValentin Caron 
321ce6ea411SValentin Caron fail_agent:
322ce6ea411SValentin Caron 	while (!SIMPLEQ_EMPTY(&ctx->agent_list)) {
323ce6ea411SValentin Caron 		agent_ctx = SIMPLEQ_FIRST(&ctx->agent_list);
324ce6ea411SValentin Caron 
325ce6ea411SValentin Caron 		while (!SIMPLEQ_EMPTY(&agent_ctx->protocol_list)) {
326ce6ea411SValentin Caron 			struct optee_scmi_server_protocol *protocol_ctx =
327ce6ea411SValentin Caron 				SIMPLEQ_FIRST(&agent_ctx->protocol_list);
328ce6ea411SValentin Caron 
329ce6ea411SValentin Caron 			SIMPLEQ_REMOVE_HEAD(&agent_ctx->protocol_list, link);
330ce6ea411SValentin Caron 			free(protocol_ctx);
331ce6ea411SValentin Caron 		}
332ce6ea411SValentin Caron 
333ce6ea411SValentin Caron 		SIMPLEQ_REMOVE_HEAD(&ctx->agent_list, link);
334ce6ea411SValentin Caron 		free(agent_ctx);
335ce6ea411SValentin Caron 	}
336ce6ea411SValentin Caron 
337ce6ea411SValentin Caron 	free(ctx);
338ce6ea411SValentin Caron 
339ce6ea411SValentin Caron 	return res;
340ce6ea411SValentin Caron }
341ce6ea411SValentin Caron 
optee_scmi_server_init(void)342ce6ea411SValentin Caron static TEE_Result optee_scmi_server_init(void)
343ce6ea411SValentin Caron {
344ce6ea411SValentin Caron 	const void *fdt = get_embedded_dt();
345ce6ea411SValentin Caron 	int node = -1;
346ce6ea411SValentin Caron 
347ce6ea411SValentin Caron 	if (!fdt)
348ce6ea411SValentin Caron 		panic();
349ce6ea411SValentin Caron 
350ce6ea411SValentin Caron 	node = fdt_node_offset_by_compatible(fdt, node, "optee,scmi-server");
351ce6ea411SValentin Caron 	if (node < 0)
352ce6ea411SValentin Caron 		panic();
353ce6ea411SValentin Caron 
354ce6ea411SValentin Caron 	return optee_scmi_server_probe(fdt, node, NULL);
355ce6ea411SValentin Caron }
356ce6ea411SValentin Caron 
357ce6ea411SValentin Caron driver_init_late(optee_scmi_server_init);
358