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