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