xref: /rk3399_ARM-atf/drivers/st/clk/stm32mp_clkfunc.c (revision 52a616b48c617fe8721106f29f2910ca4681afea)
1 /*
2  * Copyright (c) 2017-2019, STMicroelectronics - All Rights Reserved
3  *
4  * SPDX-License-Identifier: BSD-3-Clause
5  */
6 
7 #include <errno.h>
8 
9 #include <libfdt.h>
10 
11 #include <platform_def.h>
12 
13 #include <common/fdt_wrappers.h>
14 #include <drivers/st/stm32_gpio.h>
15 #include <drivers/st/stm32mp_clkfunc.h>
16 
17 #define DT_STGEN_COMPAT		"st,stm32-stgen"
18 
19 /*
20  * Get the frequency of an oscillator from its name in device tree.
21  * @param name: oscillator name
22  * @param freq: stores the frequency of the oscillator
23  * @return: 0 on success, and a negative FDT/ERRNO error code on failure.
24  */
25 int fdt_osc_read_freq(const char *name, uint32_t *freq)
26 {
27 	int node, subnode;
28 	void *fdt;
29 
30 	if (fdt_get_address(&fdt) == 0) {
31 		return -ENOENT;
32 	}
33 
34 	node = fdt_path_offset(fdt, "/clocks");
35 	if (node < 0) {
36 		return -FDT_ERR_NOTFOUND;
37 	}
38 
39 	fdt_for_each_subnode(subnode, fdt, node) {
40 		const char *cchar;
41 		int ret;
42 
43 		cchar = fdt_get_name(fdt, subnode, &ret);
44 		if (cchar == NULL) {
45 			return ret;
46 		}
47 
48 		if (strncmp(cchar, name, (size_t)ret) == 0) {
49 			const fdt32_t *cuint;
50 
51 			cuint = fdt_getprop(fdt, subnode, "clock-frequency",
52 					    &ret);
53 			if (cuint == NULL) {
54 				return ret;
55 			}
56 
57 			*freq = fdt32_to_cpu(*cuint);
58 
59 			return 0;
60 		}
61 	}
62 
63 	/* Oscillator not found, freq=0 */
64 	*freq = 0;
65 	return 0;
66 }
67 
68 /*
69  * Check the presence of an oscillator property from its id.
70  * @param osc_id: oscillator ID
71  * @param prop_name: property name
72  * @return: true/false regarding search result.
73  */
74 bool fdt_osc_read_bool(enum stm32mp_osc_id osc_id, const char *prop_name)
75 {
76 	int node, subnode;
77 	void *fdt;
78 
79 	if (fdt_get_address(&fdt) == 0) {
80 		return false;
81 	}
82 
83 	if (osc_id >= NB_OSC) {
84 		return false;
85 	}
86 
87 	node = fdt_path_offset(fdt, "/clocks");
88 	if (node < 0) {
89 		return false;
90 	}
91 
92 	fdt_for_each_subnode(subnode, fdt, node) {
93 		const char *cchar;
94 		int ret;
95 
96 		cchar = fdt_get_name(fdt, subnode, &ret);
97 		if (cchar == NULL) {
98 			return false;
99 		}
100 
101 		if (strncmp(cchar, stm32mp_osc_node_label[osc_id],
102 			    (size_t)ret) != 0) {
103 			continue;
104 		}
105 
106 		if (fdt_getprop(fdt, subnode, prop_name, NULL) != NULL) {
107 			return true;
108 		}
109 	}
110 
111 	return false;
112 }
113 
114 /*
115  * Get the value of a oscillator property from its ID.
116  * @param osc_id: oscillator ID
117  * @param prop_name: property name
118  * @param dflt_value: default value
119  * @return oscillator value on success, default value if property not found.
120  */
121 uint32_t fdt_osc_read_uint32_default(enum stm32mp_osc_id osc_id,
122 				     const char *prop_name, uint32_t dflt_value)
123 {
124 	int node, subnode;
125 	void *fdt;
126 
127 	if (fdt_get_address(&fdt) == 0) {
128 		return dflt_value;
129 	}
130 
131 	if (osc_id >= NB_OSC) {
132 		return dflt_value;
133 	}
134 
135 	node = fdt_path_offset(fdt, "/clocks");
136 	if (node < 0) {
137 		return dflt_value;
138 	}
139 
140 	fdt_for_each_subnode(subnode, fdt, node) {
141 		const char *cchar;
142 		int ret;
143 
144 		cchar = fdt_get_name(fdt, subnode, &ret);
145 		if (cchar == NULL) {
146 			return dflt_value;
147 		}
148 
149 		if (strncmp(cchar, stm32mp_osc_node_label[osc_id],
150 			    (size_t)ret) != 0) {
151 			continue;
152 		}
153 
154 		return fdt_read_uint32_default(subnode, prop_name, dflt_value);
155 	}
156 
157 	return dflt_value;
158 }
159 
160 /*
161  * Get the RCC node offset from the device tree
162  * @param fdt: Device tree reference
163  * @return: Node offset or a negative value on error
164  */
165 int fdt_get_rcc_node(void *fdt)
166 {
167 	return fdt_node_offset_by_compatible(fdt, -1, DT_RCC_CLK_COMPAT);
168 }
169 
170 /*
171  * Get the RCC base address from the device tree
172  * @return: RCC address or 0 on error
173  */
174 uint32_t fdt_rcc_read_addr(void)
175 {
176 	int node;
177 	void *fdt;
178 	const fdt32_t *cuint;
179 
180 	if (fdt_get_address(&fdt) == 0) {
181 		return 0;
182 	}
183 
184 	node = fdt_get_rcc_node(fdt);
185 	if (node < 0) {
186 		return 0;
187 	}
188 
189 	cuint = fdt_getprop(fdt, node, "reg", NULL);
190 	if (cuint == NULL) {
191 		return 0;
192 	}
193 
194 	return fdt32_to_cpu(*cuint);
195 }
196 
197 /*
198  * Read a series of parameters in rcc-clk section in device tree
199  * @param prop_name: Name of the RCC property to be read
200  * @param array: the array to store the property parameters
201  * @param count: number of parameters to be read
202  * @return: 0 on succes or a negative value on error
203  */
204 int fdt_rcc_read_uint32_array(const char *prop_name, uint32_t count,
205 			      uint32_t *array)
206 {
207 	int node;
208 	void *fdt;
209 
210 	if (fdt_get_address(&fdt) == 0) {
211 		return -ENOENT;
212 	}
213 
214 	node = fdt_get_rcc_node(fdt);
215 	if (node < 0) {
216 		return -FDT_ERR_NOTFOUND;
217 	}
218 
219 	return fdt_read_uint32_array(fdt, node, prop_name, count, array);
220 }
221 
222 /*
223  * Get the subnode offset in rcc-clk section from its name in device tree
224  * @param name: name of the RCC property
225  * @return: offset on success, and a negative FDT/ERRNO error code on failure.
226  */
227 int fdt_rcc_subnode_offset(const char *name)
228 {
229 	int node, subnode;
230 	void *fdt;
231 
232 	if (fdt_get_address(&fdt) == 0) {
233 		return -ENOENT;
234 	}
235 
236 	node = fdt_get_rcc_node(fdt);
237 	if (node < 0) {
238 		return -FDT_ERR_NOTFOUND;
239 	}
240 
241 	subnode = fdt_subnode_offset(fdt, node, name);
242 	if (subnode <= 0) {
243 		return -FDT_ERR_NOTFOUND;
244 	}
245 
246 	return subnode;
247 }
248 
249 /*
250  * Get the pointer to a rcc-clk property from its name.
251  * @param name: name of the RCC property
252  * @param lenp: stores the length of the property.
253  * @return: pointer to the property on success, and NULL value on failure.
254  */
255 const fdt32_t *fdt_rcc_read_prop(const char *prop_name, int *lenp)
256 {
257 	const fdt32_t *cuint;
258 	int node, len;
259 	void *fdt;
260 
261 	if (fdt_get_address(&fdt) == 0) {
262 		return NULL;
263 	}
264 
265 	node = fdt_get_rcc_node(fdt);
266 	if (node < 0) {
267 		return NULL;
268 	}
269 
270 	cuint = fdt_getprop(fdt, node, prop_name, &len);
271 	if (cuint == NULL) {
272 		return NULL;
273 	}
274 
275 	*lenp = len;
276 	return cuint;
277 }
278 
279 /*
280  * Get the secure status for rcc node in device tree.
281  * @return: true if rcc is available from secure world, false if not.
282  */
283 bool fdt_get_rcc_secure_status(void)
284 {
285 	int node;
286 	void *fdt;
287 
288 	if (fdt_get_address(&fdt) == 0) {
289 		return false;
290 	}
291 
292 	node = fdt_get_rcc_node(fdt);
293 	if (node < 0) {
294 		return false;
295 	}
296 
297 	return !!(fdt_get_status(node) & DT_SECURE);
298 }
299 
300 /*
301  * Get the stgen base address.
302  * @return: address of stgen on success, and NULL value on failure.
303  */
304 uintptr_t fdt_get_stgen_base(void)
305 {
306 	int node;
307 	const fdt32_t *cuint;
308 	void *fdt;
309 
310 	if (fdt_get_address(&fdt) == 0) {
311 		return 0;
312 	}
313 
314 	node = fdt_node_offset_by_compatible(fdt, -1, DT_STGEN_COMPAT);
315 	if (node < 0) {
316 		return 0;
317 	}
318 
319 	cuint = fdt_getprop(fdt, node, "reg", NULL);
320 	if (cuint == NULL) {
321 		return 0;
322 	}
323 
324 	return fdt32_to_cpu(*cuint);
325 }
326 
327 /*
328  * Get the clock ID of the given node in device tree.
329  * @param node: node offset
330  * @return: Clock ID on success, and a negative FDT/ERRNO error code on failure.
331  */
332 int fdt_get_clock_id(int node)
333 {
334 	const fdt32_t *cuint;
335 	void *fdt;
336 
337 	if (fdt_get_address(&fdt) == 0) {
338 		return -ENOENT;
339 	}
340 
341 	cuint = fdt_getprop(fdt, node, "clocks", NULL);
342 	if (cuint == NULL) {
343 		return -FDT_ERR_NOTFOUND;
344 	}
345 
346 	cuint++;
347 	return (int)fdt32_to_cpu(*cuint);
348 }
349