xref: /optee_os/core/lib/scmi-server/scmi_clock_consumer.c (revision 941a58d78c99c4754fbd4ec3079ec9e1d596af8f)
1 // SPDX-License-Identifier: BSD-2-Clause
2 /*
3  * Copyright (c) 2024, STMicroelectronics
4  */
5 
6 #include <assert.h>
7 #include <drivers/clk.h>
8 #include <drivers/clk_dt.h>
9 #include <dt-bindings/scmi/scmi-clock.h>
10 #include <kernel/boot.h>
11 #include <kernel/panic.h>
12 #include <libfdt.h>
13 #include <malloc.h>
14 #include <scmi_agent_configuration.h>
15 #include <scmi_clock_consumer.h>
16 #include <tee_api_defines_extensions.h>
17 #include <trace.h>
18 
19 /*
20  * struct scmi_server_clock: data for a SCMI clock in DT
21  *
22  * @domain_id: SCMI domain identifier
23  * @domain_name: SCMI domain name
24  * @clock: clock to control through SCMI protocol
25  * @flags: capabilities of the SCMI clock
26  */
27 struct scmi_server_clock {
28 	uint32_t domain_id;
29 	const char *domain_name;
30 	struct clk *clock;
31 	uint32_t flags;
32 };
33 
34 /*
35  * struct scmi_clock_consumer: context of scmi_clock_consumer.c for one channel
36  *
37  * @clocks: platform clocks exposed with SCMI
38  * @scmi_flags: capabilities of an clocks
39  * @count: number of clocks and scmi_flags
40  * @link: link for list of scmi_clock_consumer
41  */
42 struct scmi_clock_consumer {
43 	struct clk *clocks;
44 	uint32_t *scmi_flags;
45 	unsigned int count;
46 
47 	SLIST_ENTRY(scmi_clock_consumer) link;
48 };
49 
50 static SLIST_HEAD(scmi_clock_consumer_head, scmi_clock_consumer) ctx =
51 	SLIST_HEAD_INITIALIZER(&ctx);
52 
53 static TEE_Result scmi_clk_get_rates_array(struct clk *clk, size_t index,
54 					   unsigned long *rates,
55 					   size_t *nb_elts)
56 {
57 	uint32_t scmi_flags = *(uint32_t *)clk->priv;
58 
59 	if (!nb_elts)
60 		return TEE_ERROR_BAD_PARAMETERS;
61 
62 	if (scmi_flags & SCMI_CLOCK_ALLOW_SET_RATE)
63 		return clk_get_rates_array(clk->parent, index, rates, nb_elts);
64 
65 	if (!rates || !*nb_elts) {
66 		*nb_elts = 1;
67 		return TEE_SUCCESS;
68 	}
69 
70 	if (index)
71 		return TEE_ERROR_BAD_PARAMETERS;
72 
73 	/*
74 	 * Clocks not exposed have no effective parent/platform clock.
75 	 * Report a 0 Hz rate in this case.
76 	 */
77 	if (clk->parent)
78 		*rates = clk_get_rate(clk->parent);
79 	else
80 		*rates = 0;
81 
82 	*nb_elts = 1;
83 
84 	return TEE_SUCCESS;
85 }
86 
87 static TEE_Result scmi_clk_get_rates_steps(struct clk *clk,
88 					   unsigned long *min,
89 					   unsigned long *max,
90 					   unsigned long *step)
91 {
92 	uint32_t scmi_flags = *(uint32_t *)clk->priv;
93 	TEE_Result res = TEE_ERROR_GENERIC;
94 
95 	if (scmi_flags & SCMI_CLOCK_ALLOW_SET_RATE) {
96 		res = clk_get_rates_steps(clk->parent, min, max, step);
97 	} else {
98 		*min = clk_get_rate(clk);
99 		*max = *min;
100 		*step = 1;
101 
102 		res = TEE_SUCCESS;
103 	}
104 
105 	return res;
106 }
107 
108 static const struct clk_ops scmi_clk_ops = {
109 	.get_rates_array = scmi_clk_get_rates_array,
110 	.get_rates_steps = scmi_clk_get_rates_steps,
111 };
112 
113 TEE_Result optee_scmi_server_init_clocks(const void *fdt, int node,
114 					 struct scpfw_agent_config *agent_cfg,
115 					 struct scpfw_channel_config
116 						*channel_cfg)
117 {
118 	TEE_Result res = TEE_ERROR_GENERIC;
119 	struct scmi_clock_consumer *consumer = NULL;
120 	struct scmi_server_clock *s_clocks = NULL;
121 	size_t s_clocks_count = 0;
122 	int item_node = 0;
123 	int subnode = 0;
124 	bool have_subnodes = false;
125 	size_t n = 0;
126 	size_t i = 0;
127 
128 	item_node = fdt_subnode_offset(fdt, node, "clocks");
129 	if (item_node < 0)
130 		return TEE_SUCCESS;
131 
132 	/* Compute the number of domains to allocate */
133 	fdt_for_each_subnode(subnode, fdt, item_node) {
134 		paddr_t reg = fdt_reg_base_address(fdt, subnode);
135 
136 		assert(reg != DT_INFO_INVALID_REG);
137 		if (reg > s_clocks_count)
138 			s_clocks_count = reg;
139 
140 		have_subnodes = true;
141 	}
142 
143 	if (!have_subnodes)
144 		return TEE_SUCCESS;
145 
146 	consumer = calloc(1, sizeof(*consumer));
147 	if (!consumer)
148 		return TEE_ERROR_OUT_OF_MEMORY;
149 
150 	SLIST_INSERT_HEAD(&ctx, consumer, link);
151 
152 	/* Number of SCMI clock domains is the max domain ID + 1 */
153 	s_clocks_count++;
154 	s_clocks = calloc(s_clocks_count, sizeof(*s_clocks));
155 	if (!s_clocks)
156 		panic();
157 
158 	fdt_for_each_subnode(subnode, fdt, item_node) {
159 		struct scmi_server_clock *s_clock = NULL;
160 		const fdt32_t *cuint = NULL;
161 		struct clk *clock = NULL;
162 		uint32_t domain_id = 0;
163 
164 		res = clk_dt_get_by_index(fdt, subnode, 0, &clock);
165 		if (res == TEE_ERROR_DEFER_DRIVER_INIT) {
166 			panic("Unexpected init deferral");
167 		} else if (res) {
168 			EMSG("Can't get clock %s (%#"PRIx32"), skipped",
169 			     fdt_get_name(fdt, subnode, NULL), res);
170 			continue;
171 		}
172 
173 		domain_id = fdt_reg_base_address(fdt, subnode);
174 		s_clock = s_clocks + domain_id;
175 		s_clock->domain_id = domain_id;
176 
177 		cuint = fdt_getprop(fdt, subnode, "domain-name", NULL);
178 		if (cuint)
179 			s_clock->domain_name = (char *)cuint;
180 		else
181 			s_clock->domain_name = fdt_get_name(fdt, subnode, NULL);
182 
183 		/* Check that the domain_id is not already used */
184 		if (s_clock->clock) {
185 			EMSG("Domain ID %"PRIu32" already used", domain_id);
186 			panic();
187 		}
188 		s_clock->clock = clock;
189 
190 		/*
191 		 * Get clock flags
192 		 */
193 		cuint = fdt_getprop(fdt, subnode, "flags", NULL);
194 		if (cuint) {
195 			s_clock->flags = fdt32_to_cpu(*cuint);
196 			s_clock->flags &= SCMI_CLOCK_MASK;
197 		}
198 
199 		DMSG("scmi clock shares %s on domain ID %"PRIu32,
200 		     s_clock->domain_name, domain_id);
201 	}
202 
203 	for (n = 0; n < s_clocks_count; n++) {
204 		/*
205 		 * Assign domain IDs to un-exposed clock as SCMI specification
206 		 * requires the resource is defined even if not accessible.
207 		 */
208 		if (!s_clocks[n].clock) {
209 			s_clocks[n].domain_id = n;
210 			s_clocks[n].domain_name = "";
211 		}
212 
213 		s_clocks[n].domain_name = strdup(s_clocks[n].domain_name);
214 		if (!s_clocks[n].domain_name)
215 			panic();
216 	}
217 
218 	if (consumer->clocks || channel_cfg->clock) {
219 		EMSG("Clock already loaded: agent %u, channel %u",
220 		     agent_cfg->agent_id, channel_cfg->channel_id);
221 		panic();
222 	}
223 
224 	consumer->count = s_clocks_count;
225 	consumer->clocks = calloc(consumer->count, sizeof(*consumer->clocks));
226 	assert(consumer->clocks);
227 
228 	consumer->scmi_flags = calloc(consumer->count,
229 				      sizeof(*consumer->scmi_flags));
230 	assert(consumer->scmi_flags);
231 
232 	channel_cfg->clock_count = s_clocks_count;
233 	channel_cfg->clock = calloc(channel_cfg->clock_count,
234 				    sizeof(*channel_cfg->clock));
235 	assert(channel_cfg->clock);
236 
237 	for (i = 0; i < s_clocks_count; i++) {
238 		unsigned int domain_id = s_clocks[i].domain_id;
239 		struct clk *new_clock = consumer->clocks + domain_id;
240 		uint32_t *scmi_flags = consumer->scmi_flags + domain_id;
241 
242 		*scmi_flags = s_clocks[i].flags;
243 
244 		new_clock->ops = &scmi_clk_ops;
245 		new_clock->priv = scmi_flags;
246 		new_clock->name = s_clocks[i].domain_name;
247 		new_clock->parent = s_clocks[i].clock;
248 
249 		if (*scmi_flags & SCMI_CLOCK_ALLOW_SET_RATE)
250 			new_clock->flags = CLK_SET_RATE_PARENT;
251 
252 		new_clock->flags |= CLK_DUTY_CYCLE_PARENT;
253 
254 		if (clk_register(new_clock))
255 			panic();
256 
257 		channel_cfg->clock[domain_id] = (struct scmi_clock){
258 			.name = clk_get_name(new_clock),
259 			.clk = new_clock,
260 			.enabled = *scmi_flags & SCMI_CLOCK_DEFAULT_ENABLED,
261 		};
262 	}
263 
264 	/*
265 	 * We can free s_clk_channel resources since content is now
266 	 * referenced from the SCMI server configuration data.
267 	 */
268 	free(s_clocks);
269 
270 	return TEE_SUCCESS;
271 }
272