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