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