xref: /rk3399_ARM-atf/drivers/st/clk/stm32mp_clkfunc.c (revision 658086747dc638e3012a052293e855339d211a95)
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(fdt, subnode, prop_name,
155 					       dflt_value);
156 	}
157 
158 	return dflt_value;
159 }
160 
161 /*
162  * Get the RCC node offset from the device tree
163  * @param fdt: Device tree reference
164  * @return: Node offset or a negative value on error
165  */
166 int fdt_get_rcc_node(void *fdt)
167 {
168 	return fdt_node_offset_by_compatible(fdt, -1, DT_RCC_CLK_COMPAT);
169 }
170 
171 /*
172  * Get the RCC base address from the device tree
173  * @return: RCC address or 0 on error
174  */
175 uint32_t fdt_rcc_read_addr(void)
176 {
177 	int node;
178 	void *fdt;
179 	const fdt32_t *cuint;
180 
181 	if (fdt_get_address(&fdt) == 0) {
182 		return 0;
183 	}
184 
185 	node = fdt_get_rcc_node(fdt);
186 	if (node < 0) {
187 		return 0;
188 	}
189 
190 	cuint = fdt_getprop(fdt, node, "reg", NULL);
191 	if (cuint == NULL) {
192 		return 0;
193 	}
194 
195 	return fdt32_to_cpu(*cuint);
196 }
197 
198 /*
199  * Read a series of parameters in rcc-clk section in device tree
200  * @param prop_name: Name of the RCC property to be read
201  * @param array: the array to store the property parameters
202  * @param count: number of parameters to be read
203  * @return: 0 on succes or a negative value on error
204  */
205 int fdt_rcc_read_uint32_array(const char *prop_name, uint32_t count,
206 			      uint32_t *array)
207 {
208 	int node;
209 	void *fdt;
210 
211 	if (fdt_get_address(&fdt) == 0) {
212 		return -ENOENT;
213 	}
214 
215 	node = fdt_get_rcc_node(fdt);
216 	if (node < 0) {
217 		return -FDT_ERR_NOTFOUND;
218 	}
219 
220 	return fdt_read_uint32_array(fdt, node, prop_name, count, array);
221 }
222 
223 /*
224  * Get the subnode offset in rcc-clk section from its name in device tree
225  * @param name: name of the RCC property
226  * @return: offset on success, and a negative FDT/ERRNO error code on failure.
227  */
228 int fdt_rcc_subnode_offset(const char *name)
229 {
230 	int node, subnode;
231 	void *fdt;
232 
233 	if (fdt_get_address(&fdt) == 0) {
234 		return -ENOENT;
235 	}
236 
237 	node = fdt_get_rcc_node(fdt);
238 	if (node < 0) {
239 		return -FDT_ERR_NOTFOUND;
240 	}
241 
242 	subnode = fdt_subnode_offset(fdt, node, name);
243 	if (subnode <= 0) {
244 		return -FDT_ERR_NOTFOUND;
245 	}
246 
247 	return subnode;
248 }
249 
250 /*
251  * Get the pointer to a rcc-clk property from its name.
252  * @param name: name of the RCC property
253  * @param lenp: stores the length of the property.
254  * @return: pointer to the property on success, and NULL value on failure.
255  */
256 const fdt32_t *fdt_rcc_read_prop(const char *prop_name, int *lenp)
257 {
258 	const fdt32_t *cuint;
259 	int node, len;
260 	void *fdt;
261 
262 	if (fdt_get_address(&fdt) == 0) {
263 		return NULL;
264 	}
265 
266 	node = fdt_get_rcc_node(fdt);
267 	if (node < 0) {
268 		return NULL;
269 	}
270 
271 	cuint = fdt_getprop(fdt, node, prop_name, &len);
272 	if (cuint == NULL) {
273 		return NULL;
274 	}
275 
276 	*lenp = len;
277 	return cuint;
278 }
279 
280 /*
281  * Get the secure status for rcc node in device tree.
282  * @return: true if rcc is available from secure world, false if not.
283  */
284 bool fdt_get_rcc_secure_status(void)
285 {
286 	int node;
287 	void *fdt;
288 
289 	if (fdt_get_address(&fdt) == 0) {
290 		return false;
291 	}
292 
293 	node = fdt_get_rcc_node(fdt);
294 	if (node < 0) {
295 		return false;
296 	}
297 
298 	return !!(fdt_get_status(node) & DT_SECURE);
299 }
300 
301 /*
302  * Get the stgen base address.
303  * @return: address of stgen on success, and NULL value on failure.
304  */
305 uintptr_t fdt_get_stgen_base(void)
306 {
307 	int node;
308 	const fdt32_t *cuint;
309 	void *fdt;
310 
311 	if (fdt_get_address(&fdt) == 0) {
312 		return 0;
313 	}
314 
315 	node = fdt_node_offset_by_compatible(fdt, -1, DT_STGEN_COMPAT);
316 	if (node < 0) {
317 		return 0;
318 	}
319 
320 	cuint = fdt_getprop(fdt, node, "reg", NULL);
321 	if (cuint == NULL) {
322 		return 0;
323 	}
324 
325 	return fdt32_to_cpu(*cuint);
326 }
327 
328 /*
329  * Get the clock ID of the given node in device tree.
330  * @param node: node offset
331  * @return: Clock ID on success, and a negative FDT/ERRNO error code on failure.
332  */
333 int fdt_get_clock_id(int node)
334 {
335 	const fdt32_t *cuint;
336 	void *fdt;
337 
338 	if (fdt_get_address(&fdt) == 0) {
339 		return -ENOENT;
340 	}
341 
342 	cuint = fdt_getprop(fdt, node, "clocks", NULL);
343 	if (cuint == NULL) {
344 		return -FDT_ERR_NOTFOUND;
345 	}
346 
347 	cuint++;
348 	return (int)fdt32_to_cpu(*cuint);
349 }
350