xref: /rk3399_ARM-atf/drivers/st/clk/stm32mp_clkfunc.c (revision 7c62111381c0ea5f4d643a01035c30a2e6310056)
1 /*
2  * Copyright (c) 2017-2021, 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_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 			const fdt32_t *cuint;
49 
50 			cuint = fdt_getprop(fdt, subnode, "clock-frequency",
51 					    &ret);
52 			if (cuint == NULL) {
53 				return ret;
54 			}
55 
56 			*freq = fdt32_to_cpu(*cuint);
57 
58 			return 0;
59 		}
60 	}
61 
62 	/* Oscillator not found, freq=0 */
63 	*freq = 0;
64 	return 0;
65 }
66 
67 /*
68  * Check the presence of an oscillator property from its id.
69  * @param osc_id: oscillator ID
70  * @param prop_name: property name
71  * @return: true/false regarding search result.
72  */
73 bool fdt_osc_read_bool(enum stm32mp_osc_id osc_id, const char *prop_name)
74 {
75 	int node, subnode;
76 	void *fdt;
77 
78 	if (fdt_get_address(&fdt) == 0) {
79 		return false;
80 	}
81 
82 	if (osc_id >= NB_OSC) {
83 		return false;
84 	}
85 
86 	node = fdt_path_offset(fdt, "/clocks");
87 	if (node < 0) {
88 		return false;
89 	}
90 
91 	fdt_for_each_subnode(subnode, fdt, node) {
92 		const char *cchar;
93 		int ret;
94 
95 		cchar = fdt_get_name(fdt, subnode, &ret);
96 		if (cchar == NULL) {
97 			return false;
98 		}
99 
100 		if (strncmp(cchar, stm32mp_osc_node_label[osc_id],
101 			    (size_t)ret) != 0) {
102 			continue;
103 		}
104 
105 		if (fdt_getprop(fdt, subnode, prop_name, NULL) != NULL) {
106 			return true;
107 		}
108 	}
109 
110 	return false;
111 }
112 
113 /*
114  * Get the value of a oscillator property from its ID.
115  * @param osc_id: oscillator ID
116  * @param prop_name: property name
117  * @param dflt_value: default value
118  * @return oscillator value on success, default value if property not found.
119  */
120 uint32_t fdt_osc_read_uint32_default(enum stm32mp_osc_id osc_id,
121 				     const char *prop_name, uint32_t dflt_value)
122 {
123 	int node, subnode;
124 	void *fdt;
125 
126 	if (fdt_get_address(&fdt) == 0) {
127 		return dflt_value;
128 	}
129 
130 	if (osc_id >= NB_OSC) {
131 		return dflt_value;
132 	}
133 
134 	node = fdt_path_offset(fdt, "/clocks");
135 	if (node < 0) {
136 		return dflt_value;
137 	}
138 
139 	fdt_for_each_subnode(subnode, fdt, node) {
140 		const char *cchar;
141 		int ret;
142 
143 		cchar = fdt_get_name(fdt, subnode, &ret);
144 		if (cchar == NULL) {
145 			return dflt_value;
146 		}
147 
148 		if (strncmp(cchar, stm32mp_osc_node_label[osc_id],
149 			    (size_t)ret) != 0) {
150 			continue;
151 		}
152 
153 		return fdt_read_uint32_default(fdt, subnode, prop_name,
154 					       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 static int fdt_get_rcc_node(void *fdt)
166 {
167 	static int node;
168 
169 	if (node <= 0) {
170 		node = fdt_node_offset_by_compatible(fdt, -1, DT_RCC_CLK_COMPAT);
171 	}
172 
173 	return node;
174 }
175 
176 /*
177  * Read a series of parameters in rcc-clk section in device tree
178  * @param prop_name: Name of the RCC property to be read
179  * @param array: the array to store the property parameters
180  * @param count: number of parameters to be read
181  * @return: 0 on succes or a negative value on error
182  */
183 int fdt_rcc_read_uint32_array(const char *prop_name, uint32_t count,
184 			      uint32_t *array)
185 {
186 	int node;
187 	void *fdt;
188 
189 	if (fdt_get_address(&fdt) == 0) {
190 		return -ENOENT;
191 	}
192 
193 	node = fdt_get_rcc_node(fdt);
194 	if (node < 0) {
195 		return -FDT_ERR_NOTFOUND;
196 	}
197 
198 	return fdt_read_uint32_array(fdt, node, prop_name, count, array);
199 }
200 
201 /*
202  * Get the subnode offset in rcc-clk section from its name in device tree
203  * @param name: name of the RCC property
204  * @return: offset on success, and a negative FDT/ERRNO error code on failure.
205  */
206 int fdt_rcc_subnode_offset(const char *name)
207 {
208 	int node, subnode;
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 	subnode = fdt_subnode_offset(fdt, node, name);
221 	if (subnode <= 0) {
222 		return -FDT_ERR_NOTFOUND;
223 	}
224 
225 	return subnode;
226 }
227 
228 /*
229  * Get the pointer to a rcc-clk property from its name.
230  * @param name: name of the RCC property
231  * @param lenp: stores the length of the property.
232  * @return: pointer to the property on success, and NULL value on failure.
233  */
234 const fdt32_t *fdt_rcc_read_prop(const char *prop_name, int *lenp)
235 {
236 	const fdt32_t *cuint;
237 	int node, len;
238 	void *fdt;
239 
240 	if (fdt_get_address(&fdt) == 0) {
241 		return NULL;
242 	}
243 
244 	node = fdt_get_rcc_node(fdt);
245 	if (node < 0) {
246 		return NULL;
247 	}
248 
249 	cuint = fdt_getprop(fdt, node, prop_name, &len);
250 	if (cuint == NULL) {
251 		return NULL;
252 	}
253 
254 	*lenp = len;
255 	return cuint;
256 }
257 
258 /*
259  * Get the secure status for rcc node in device tree.
260  * @return: true if rcc is available from secure world, false if not.
261  */
262 bool fdt_get_rcc_secure_status(void)
263 {
264 	int node;
265 	void *fdt;
266 
267 	if (fdt_get_address(&fdt) == 0) {
268 		return false;
269 	}
270 
271 	node = fdt_get_rcc_node(fdt);
272 	if (node < 0) {
273 		return false;
274 	}
275 
276 	return !!(fdt_get_status(node) & DT_SECURE);
277 }
278 
279 /*
280  * Get the clock ID of the given node in device tree.
281  * @param node: node offset
282  * @return: Clock ID on success, and a negative FDT/ERRNO error code on failure.
283  */
284 int fdt_get_clock_id(int node)
285 {
286 	const fdt32_t *cuint;
287 	void *fdt;
288 
289 	if (fdt_get_address(&fdt) == 0) {
290 		return -ENOENT;
291 	}
292 
293 	cuint = fdt_getprop(fdt, node, "clocks", NULL);
294 	if (cuint == NULL) {
295 		return -FDT_ERR_NOTFOUND;
296 	}
297 
298 	cuint++;
299 	return (int)fdt32_to_cpu(*cuint);
300 }
301 
302 /*
303  * Get the frequency of the specified UART instance.
304  * @param instance: UART interface registers base address.
305  * @return: clock frequency on success, 0 value on failure.
306  */
307 unsigned long fdt_get_uart_clock_freq(uintptr_t instance)
308 {
309 	void *fdt;
310 	int node;
311 	int clk_id;
312 
313 	if (fdt_get_address(&fdt) == 0) {
314 		return 0UL;
315 	}
316 
317 	/* Check for UART nodes */
318 	node = dt_match_instance_by_compatible(DT_UART_COMPAT, instance);
319 	if (node < 0) {
320 		return 0UL;
321 	}
322 
323 	clk_id = fdt_get_clock_id(node);
324 	if (clk_id < 0) {
325 		return 0UL;
326 	}
327 
328 	return stm32mp_clk_get_rate((unsigned long)clk_id);
329 }
330