xref: /optee_os/core/lib/scmi-server/scmi_reset_consumer.c (revision c9a214b74d8c39349681c23c5486e510a0599c3c)
1*c9a214b7SValentin Caron // SPDX-License-Identifier: BSD-2-Clause
2*c9a214b7SValentin Caron /*
3*c9a214b7SValentin Caron  * Copyright (c) 2024, STMicroelectronics
4*c9a214b7SValentin Caron  */
5*c9a214b7SValentin Caron 
6*c9a214b7SValentin Caron #include <assert.h>
7*c9a214b7SValentin Caron #include <drivers/rstctrl.h>
8*c9a214b7SValentin Caron #include <kernel/dt.h>
9*c9a214b7SValentin Caron #include <kernel/panic.h>
10*c9a214b7SValentin Caron #include <libfdt.h>
11*c9a214b7SValentin Caron #include <malloc.h>
12*c9a214b7SValentin Caron #include <scmi_agent_configuration.h>
13*c9a214b7SValentin Caron #include <scmi_reset_consumer.h>
14*c9a214b7SValentin Caron #include <tee_api_defines_extensions.h>
15*c9a214b7SValentin Caron #include <trace.h>
16*c9a214b7SValentin Caron 
17*c9a214b7SValentin Caron /*
18*c9a214b7SValentin Caron  * struct scmi_server_reset: data for a SCMI reset in DT
19*c9a214b7SValentin Caron  *
20*c9a214b7SValentin Caron  * @domain_id: SCMI domain identifier
21*c9a214b7SValentin Caron  * @domain_name: SCMI domain name
22*c9a214b7SValentin Caron  * @reset: reset to control through SCMI protocol
23*c9a214b7SValentin Caron  */
24*c9a214b7SValentin Caron struct scmi_server_reset {
25*c9a214b7SValentin Caron 	uint32_t domain_id;
26*c9a214b7SValentin Caron 	const char *domain_name;
27*c9a214b7SValentin Caron 	struct rstctrl *reset;
28*c9a214b7SValentin Caron };
29*c9a214b7SValentin Caron 
optee_scmi_server_init_resets(const void * fdt,int node,struct scpfw_agent_config * agent_cfg,struct scpfw_channel_config * channel_cfg)30*c9a214b7SValentin Caron TEE_Result optee_scmi_server_init_resets(const void *fdt, int node,
31*c9a214b7SValentin Caron 					 struct scpfw_agent_config *agent_cfg,
32*c9a214b7SValentin Caron 					 struct scpfw_channel_config
33*c9a214b7SValentin Caron 							*channel_cfg)
34*c9a214b7SValentin Caron {
35*c9a214b7SValentin Caron 	TEE_Result res = TEE_ERROR_GENERIC;
36*c9a214b7SValentin Caron 	struct scmi_server_reset *s_resets = NULL;
37*c9a214b7SValentin Caron 	size_t s_resets_count = 0;
38*c9a214b7SValentin Caron 	int item_node = 0;
39*c9a214b7SValentin Caron 	int subnode = 0;
40*c9a214b7SValentin Caron 	bool have_subnodes = false;
41*c9a214b7SValentin Caron 	size_t n = 0;
42*c9a214b7SValentin Caron 
43*c9a214b7SValentin Caron 	item_node = fdt_subnode_offset(fdt, node, "resets");
44*c9a214b7SValentin Caron 	if (item_node < 0)
45*c9a214b7SValentin Caron 		return TEE_SUCCESS;
46*c9a214b7SValentin Caron 
47*c9a214b7SValentin Caron 	/* Compute the number of domains to allocate */
48*c9a214b7SValentin Caron 	fdt_for_each_subnode(subnode, fdt, item_node) {
49*c9a214b7SValentin Caron 		paddr_t reg = fdt_reg_base_address(fdt, subnode);
50*c9a214b7SValentin Caron 
51*c9a214b7SValentin Caron 		assert(reg != DT_INFO_INVALID_REG);
52*c9a214b7SValentin Caron 		if (reg > s_resets_count)
53*c9a214b7SValentin Caron 			s_resets_count = reg;
54*c9a214b7SValentin Caron 
55*c9a214b7SValentin Caron 		have_subnodes = true;
56*c9a214b7SValentin Caron 	}
57*c9a214b7SValentin Caron 
58*c9a214b7SValentin Caron 	if (!have_subnodes)
59*c9a214b7SValentin Caron 		return TEE_SUCCESS;
60*c9a214b7SValentin Caron 
61*c9a214b7SValentin Caron 	/* Number of SCMI reset domains is the max domain ID + 1 */
62*c9a214b7SValentin Caron 	s_resets_count += 1;
63*c9a214b7SValentin Caron 	s_resets = calloc(s_resets_count, sizeof(*s_resets));
64*c9a214b7SValentin Caron 	if (!s_resets)
65*c9a214b7SValentin Caron 		return TEE_ERROR_OUT_OF_MEMORY;
66*c9a214b7SValentin Caron 
67*c9a214b7SValentin Caron 	fdt_for_each_subnode(subnode, fdt, item_node) {
68*c9a214b7SValentin Caron 		struct scmi_server_reset *s_reset = NULL;
69*c9a214b7SValentin Caron 		struct rstctrl *reset = NULL;
70*c9a214b7SValentin Caron 		const fdt32_t *cuint = NULL;
71*c9a214b7SValentin Caron 		uint32_t domain_id = 0;
72*c9a214b7SValentin Caron 
73*c9a214b7SValentin Caron 		res = rstctrl_dt_get_by_index(fdt, subnode, 0, &reset);
74*c9a214b7SValentin Caron 		if (res == TEE_ERROR_DEFER_DRIVER_INIT) {
75*c9a214b7SValentin Caron 			panic("Unexpected init deferral");
76*c9a214b7SValentin Caron 		} else if (res) {
77*c9a214b7SValentin Caron 			EMSG("Can't get reset %s (%#"PRIx32"), skipped",
78*c9a214b7SValentin Caron 			     fdt_get_name(fdt, subnode, NULL), res);
79*c9a214b7SValentin Caron 			continue;
80*c9a214b7SValentin Caron 		}
81*c9a214b7SValentin Caron 
82*c9a214b7SValentin Caron 		domain_id = fdt_reg_base_address(fdt, subnode);
83*c9a214b7SValentin Caron 		s_reset = s_resets + domain_id;
84*c9a214b7SValentin Caron 		s_reset->domain_id = domain_id;
85*c9a214b7SValentin Caron 
86*c9a214b7SValentin Caron 		cuint = fdt_getprop(fdt, subnode, "domain-name", NULL);
87*c9a214b7SValentin Caron 		if (cuint)
88*c9a214b7SValentin Caron 			s_reset->domain_name = (char *)cuint;
89*c9a214b7SValentin Caron 		else
90*c9a214b7SValentin Caron 			s_reset->domain_name = fdt_get_name(fdt, subnode, NULL);
91*c9a214b7SValentin Caron 
92*c9a214b7SValentin Caron 		/* Check that the domain_id is not already used */
93*c9a214b7SValentin Caron 		if (s_reset->reset) {
94*c9a214b7SValentin Caron 			EMSG("Domain ID %"PRIu32" already used", domain_id);
95*c9a214b7SValentin Caron 			panic();
96*c9a214b7SValentin Caron 		}
97*c9a214b7SValentin Caron 		s_reset->reset = reset;
98*c9a214b7SValentin Caron 
99*c9a214b7SValentin Caron 		DMSG("scmi reset shares %s on domain ID %"PRIu32,
100*c9a214b7SValentin Caron 		     s_reset->domain_name, domain_id);
101*c9a214b7SValentin Caron 	}
102*c9a214b7SValentin Caron 
103*c9a214b7SValentin Caron 	for (n = 0; n < s_resets_count; n++) {
104*c9a214b7SValentin Caron 		/*
105*c9a214b7SValentin Caron 		 * Assign domain IDs to un-exposed reset as SCMI specification
106*c9a214b7SValentin Caron 		 * requires the resource is defined even if not accessible.
107*c9a214b7SValentin Caron 		 */
108*c9a214b7SValentin Caron 		if (!s_resets[n].reset) {
109*c9a214b7SValentin Caron 			s_resets[n].domain_id = n;
110*c9a214b7SValentin Caron 			s_resets[n].domain_name = "";
111*c9a214b7SValentin Caron 		}
112*c9a214b7SValentin Caron 
113*c9a214b7SValentin Caron 		s_resets[n].domain_name = strdup(s_resets[n].domain_name);
114*c9a214b7SValentin Caron 		if (!s_resets[n].domain_name)
115*c9a214b7SValentin Caron 			panic();
116*c9a214b7SValentin Caron 	}
117*c9a214b7SValentin Caron 
118*c9a214b7SValentin Caron 	if (channel_cfg->reset) {
119*c9a214b7SValentin Caron 		EMSG("Reset already loaded: agent %u, channel %u",
120*c9a214b7SValentin Caron 		     agent_cfg->agent_id, channel_cfg->channel_id);
121*c9a214b7SValentin Caron 		panic();
122*c9a214b7SValentin Caron 	}
123*c9a214b7SValentin Caron 
124*c9a214b7SValentin Caron 	channel_cfg->reset_count = s_resets_count;
125*c9a214b7SValentin Caron 	channel_cfg->reset = calloc(channel_cfg->reset_count,
126*c9a214b7SValentin Caron 				    sizeof(*channel_cfg->reset));
127*c9a214b7SValentin Caron 	if (!channel_cfg->reset)
128*c9a214b7SValentin Caron 		panic();
129*c9a214b7SValentin Caron 
130*c9a214b7SValentin Caron 	for (n = 0; n < s_resets_count; n++) {
131*c9a214b7SValentin Caron 		unsigned int domain_id = s_resets[n].domain_id;
132*c9a214b7SValentin Caron 
133*c9a214b7SValentin Caron 		channel_cfg->reset[domain_id] = (struct scmi_reset){
134*c9a214b7SValentin Caron 			.name = s_resets[n].domain_name,
135*c9a214b7SValentin Caron 			.rstctrl = s_resets[n].reset,
136*c9a214b7SValentin Caron 		};
137*c9a214b7SValentin Caron 	}
138*c9a214b7SValentin Caron 
139*c9a214b7SValentin Caron 	return TEE_SUCCESS;
140*c9a214b7SValentin Caron }
141