xref: /rk3399_ARM-atf/drivers/st/clk/stm32mp_clkfunc.c (revision f66358afeeea6b78912b1c59b0e87f9b96451d5f)
1447b2b13SYann Gautier /*
2447b2b13SYann Gautier  * Copyright (c) 2017-2019, STMicroelectronics - All Rights Reserved
3447b2b13SYann Gautier  *
4447b2b13SYann Gautier  * SPDX-License-Identifier: BSD-3-Clause
5447b2b13SYann Gautier  */
6447b2b13SYann Gautier 
7447b2b13SYann Gautier #include <errno.h>
8447b2b13SYann Gautier 
9447b2b13SYann Gautier #include <libfdt.h>
10447b2b13SYann Gautier 
11447b2b13SYann Gautier #include <platform_def.h>
12447b2b13SYann Gautier 
13447b2b13SYann Gautier #include <drivers/st/stm32_gpio.h>
14447b2b13SYann Gautier #include <drivers/st/stm32mp_clkfunc.h>
15447b2b13SYann Gautier 
16447b2b13SYann Gautier #define DT_STGEN_COMPAT		"st,stm32-stgen"
17447b2b13SYann Gautier 
18447b2b13SYann Gautier /*
19*f66358afSYann Gautier  * Get the frequency of an oscillator from its name in device tree.
20*f66358afSYann Gautier  * @param name: oscillator name
21*f66358afSYann Gautier  * @param freq: stores the frequency of the oscillator
22*f66358afSYann Gautier  * @return: 0 on success, and a negative FDT/ERRNO error code on failure.
23*f66358afSYann Gautier  */
24*f66358afSYann Gautier int fdt_osc_read_freq(const char *name, uint32_t *freq)
25*f66358afSYann Gautier {
26*f66358afSYann Gautier 	int node, subnode;
27*f66358afSYann Gautier 	void *fdt;
28*f66358afSYann Gautier 
29*f66358afSYann Gautier 	if (fdt_get_address(&fdt) == 0) {
30*f66358afSYann Gautier 		return -ENOENT;
31*f66358afSYann Gautier 	}
32*f66358afSYann Gautier 
33*f66358afSYann Gautier 	node = fdt_path_offset(fdt, "/clocks");
34*f66358afSYann Gautier 	if (node < 0) {
35*f66358afSYann Gautier 		return -FDT_ERR_NOTFOUND;
36*f66358afSYann Gautier 	}
37*f66358afSYann Gautier 
38*f66358afSYann Gautier 	fdt_for_each_subnode(subnode, fdt, node) {
39*f66358afSYann Gautier 		const char *cchar;
40*f66358afSYann Gautier 		int ret;
41*f66358afSYann Gautier 
42*f66358afSYann Gautier 		cchar = fdt_get_name(fdt, subnode, &ret);
43*f66358afSYann Gautier 		if (cchar == NULL) {
44*f66358afSYann Gautier 			return ret;
45*f66358afSYann Gautier 		}
46*f66358afSYann Gautier 
47*f66358afSYann Gautier 		if (strncmp(cchar, name, (size_t)ret) == 0) {
48*f66358afSYann Gautier 			const fdt32_t *cuint;
49*f66358afSYann Gautier 
50*f66358afSYann Gautier 			cuint = fdt_getprop(fdt, subnode, "clock-frequency",
51*f66358afSYann Gautier 					    &ret);
52*f66358afSYann Gautier 			if (cuint == NULL) {
53*f66358afSYann Gautier 				return ret;
54*f66358afSYann Gautier 			}
55*f66358afSYann Gautier 
56*f66358afSYann Gautier 			*freq = fdt32_to_cpu(*cuint);
57*f66358afSYann Gautier 
58*f66358afSYann Gautier 			return 0;
59*f66358afSYann Gautier 		}
60*f66358afSYann Gautier 	}
61*f66358afSYann Gautier 
62*f66358afSYann Gautier 	/* Oscillator not found, freq=0 */
63*f66358afSYann Gautier 	*freq = 0;
64*f66358afSYann Gautier 	return 0;
65*f66358afSYann Gautier }
66*f66358afSYann Gautier 
67*f66358afSYann Gautier /*
68*f66358afSYann Gautier  * Check the presence of an oscillator property from its id.
69*f66358afSYann Gautier  * @param osc_id: oscillator ID
70*f66358afSYann Gautier  * @param prop_name: property name
71*f66358afSYann Gautier  * @return: true/false regarding search result.
72*f66358afSYann Gautier  */
73*f66358afSYann Gautier bool fdt_osc_read_bool(enum stm32mp_osc_id osc_id, const char *prop_name)
74*f66358afSYann Gautier {
75*f66358afSYann Gautier 	int node, subnode;
76*f66358afSYann Gautier 	void *fdt;
77*f66358afSYann Gautier 
78*f66358afSYann Gautier 	if (fdt_get_address(&fdt) == 0) {
79*f66358afSYann Gautier 		return false;
80*f66358afSYann Gautier 	}
81*f66358afSYann Gautier 
82*f66358afSYann Gautier 	if (osc_id >= NB_OSC) {
83*f66358afSYann Gautier 		return false;
84*f66358afSYann Gautier 	}
85*f66358afSYann Gautier 
86*f66358afSYann Gautier 	node = fdt_path_offset(fdt, "/clocks");
87*f66358afSYann Gautier 	if (node < 0) {
88*f66358afSYann Gautier 		return false;
89*f66358afSYann Gautier 	}
90*f66358afSYann Gautier 
91*f66358afSYann Gautier 	fdt_for_each_subnode(subnode, fdt, node) {
92*f66358afSYann Gautier 		const char *cchar;
93*f66358afSYann Gautier 		int ret;
94*f66358afSYann Gautier 
95*f66358afSYann Gautier 		cchar = fdt_get_name(fdt, subnode, &ret);
96*f66358afSYann Gautier 		if (cchar == NULL) {
97*f66358afSYann Gautier 			return false;
98*f66358afSYann Gautier 		}
99*f66358afSYann Gautier 
100*f66358afSYann Gautier 		if (strncmp(cchar, stm32mp_osc_node_label[osc_id],
101*f66358afSYann Gautier 			    (size_t)ret) != 0) {
102*f66358afSYann Gautier 			continue;
103*f66358afSYann Gautier 		}
104*f66358afSYann Gautier 
105*f66358afSYann Gautier 		if (fdt_getprop(fdt, subnode, prop_name, NULL) != NULL) {
106*f66358afSYann Gautier 			return true;
107*f66358afSYann Gautier 		}
108*f66358afSYann Gautier 	}
109*f66358afSYann Gautier 
110*f66358afSYann Gautier 	return false;
111*f66358afSYann Gautier }
112*f66358afSYann Gautier 
113*f66358afSYann Gautier /*
114*f66358afSYann Gautier  * Get the value of a oscillator property from its ID.
115*f66358afSYann Gautier  * @param osc_id: oscillator ID
116*f66358afSYann Gautier  * @param prop_name: property name
117*f66358afSYann Gautier  * @param dflt_value: default value
118*f66358afSYann Gautier  * @return oscillator value on success, default value if property not found.
119*f66358afSYann Gautier  */
120*f66358afSYann Gautier uint32_t fdt_osc_read_uint32_default(enum stm32mp_osc_id osc_id,
121*f66358afSYann Gautier 				     const char *prop_name, uint32_t dflt_value)
122*f66358afSYann Gautier {
123*f66358afSYann Gautier 	int node, subnode;
124*f66358afSYann Gautier 	void *fdt;
125*f66358afSYann Gautier 
126*f66358afSYann Gautier 	if (fdt_get_address(&fdt) == 0) {
127*f66358afSYann Gautier 		return dflt_value;
128*f66358afSYann Gautier 	}
129*f66358afSYann Gautier 
130*f66358afSYann Gautier 	if (osc_id >= NB_OSC) {
131*f66358afSYann Gautier 		return dflt_value;
132*f66358afSYann Gautier 	}
133*f66358afSYann Gautier 
134*f66358afSYann Gautier 	node = fdt_path_offset(fdt, "/clocks");
135*f66358afSYann Gautier 	if (node < 0) {
136*f66358afSYann Gautier 		return dflt_value;
137*f66358afSYann Gautier 	}
138*f66358afSYann Gautier 
139*f66358afSYann Gautier 	fdt_for_each_subnode(subnode, fdt, node) {
140*f66358afSYann Gautier 		const char *cchar;
141*f66358afSYann Gautier 		int ret;
142*f66358afSYann Gautier 
143*f66358afSYann Gautier 		cchar = fdt_get_name(fdt, subnode, &ret);
144*f66358afSYann Gautier 		if (cchar == NULL) {
145*f66358afSYann Gautier 			return dflt_value;
146*f66358afSYann Gautier 		}
147*f66358afSYann Gautier 
148*f66358afSYann Gautier 		if (strncmp(cchar, stm32mp_osc_node_label[osc_id],
149*f66358afSYann Gautier 			    (size_t)ret) != 0) {
150*f66358afSYann Gautier 			continue;
151*f66358afSYann Gautier 		}
152*f66358afSYann Gautier 
153*f66358afSYann Gautier 		return fdt_read_uint32_default(subnode, prop_name, dflt_value);
154*f66358afSYann Gautier 	}
155*f66358afSYann Gautier 
156*f66358afSYann Gautier 	return dflt_value;
157*f66358afSYann Gautier }
158*f66358afSYann Gautier 
159*f66358afSYann Gautier /*
160447b2b13SYann Gautier  * Get the RCC node offset from the device tree
161447b2b13SYann Gautier  * @param fdt: Device tree reference
162447b2b13SYann Gautier  * @return: Node offset or a negative value on error
163447b2b13SYann Gautier  */
164447b2b13SYann Gautier int fdt_get_rcc_node(void *fdt)
165447b2b13SYann Gautier {
166447b2b13SYann Gautier 	return fdt_node_offset_by_compatible(fdt, -1, DT_RCC_CLK_COMPAT);
167447b2b13SYann Gautier }
168447b2b13SYann Gautier 
169447b2b13SYann Gautier /*
170447b2b13SYann Gautier  * Get the RCC base address from the device tree
171447b2b13SYann Gautier  * @return: RCC address or 0 on error
172447b2b13SYann Gautier  */
173447b2b13SYann Gautier uint32_t fdt_rcc_read_addr(void)
174447b2b13SYann Gautier {
175447b2b13SYann Gautier 	int node;
176447b2b13SYann Gautier 	void *fdt;
177447b2b13SYann Gautier 	const fdt32_t *cuint;
178447b2b13SYann Gautier 
179447b2b13SYann Gautier 	if (fdt_get_address(&fdt) == 0) {
180447b2b13SYann Gautier 		return 0;
181447b2b13SYann Gautier 	}
182447b2b13SYann Gautier 
183447b2b13SYann Gautier 	node = fdt_get_rcc_node(fdt);
184447b2b13SYann Gautier 	if (node < 0) {
185447b2b13SYann Gautier 		return 0;
186447b2b13SYann Gautier 	}
187447b2b13SYann Gautier 
188447b2b13SYann Gautier 	cuint = fdt_getprop(fdt, node, "reg", NULL);
189447b2b13SYann Gautier 	if (cuint == NULL) {
190447b2b13SYann Gautier 		return 0;
191447b2b13SYann Gautier 	}
192447b2b13SYann Gautier 
193447b2b13SYann Gautier 	return fdt32_to_cpu(*cuint);
194447b2b13SYann Gautier }
195447b2b13SYann Gautier 
196447b2b13SYann Gautier /*
197447b2b13SYann Gautier  * Read a series of parameters in rcc-clk section in device tree
198447b2b13SYann Gautier  * @param prop_name: Name of the RCC property to be read
199447b2b13SYann Gautier  * @param array: the array to store the property parameters
200447b2b13SYann Gautier  * @param count: number of parameters to be read
201447b2b13SYann Gautier  * @return: 0 on succes or a negative value on error
202447b2b13SYann Gautier  */
203447b2b13SYann Gautier int fdt_rcc_read_uint32_array(const char *prop_name,
204447b2b13SYann Gautier 			      uint32_t *array, uint32_t count)
205447b2b13SYann Gautier {
206447b2b13SYann Gautier 	int node;
207447b2b13SYann Gautier 	void *fdt;
208447b2b13SYann Gautier 
209447b2b13SYann Gautier 	if (fdt_get_address(&fdt) == 0) {
210447b2b13SYann Gautier 		return -ENOENT;
211447b2b13SYann Gautier 	}
212447b2b13SYann Gautier 
213447b2b13SYann Gautier 	node = fdt_get_rcc_node(fdt);
214447b2b13SYann Gautier 	if (node < 0) {
215447b2b13SYann Gautier 		return -FDT_ERR_NOTFOUND;
216447b2b13SYann Gautier 	}
217447b2b13SYann Gautier 
218447b2b13SYann Gautier 	return fdt_read_uint32_array(node, prop_name, array, count);
219447b2b13SYann Gautier }
220447b2b13SYann Gautier 
221447b2b13SYann Gautier /*
222447b2b13SYann Gautier  * Get the subnode offset in rcc-clk section from its name in device tree
223447b2b13SYann Gautier  * @param name: name of the RCC property
224447b2b13SYann Gautier  * @return: offset on success, and a negative FDT/ERRNO error code on failure.
225447b2b13SYann Gautier  */
226447b2b13SYann Gautier int fdt_rcc_subnode_offset(const char *name)
227447b2b13SYann Gautier {
228447b2b13SYann Gautier 	int node, subnode;
229447b2b13SYann Gautier 	void *fdt;
230447b2b13SYann Gautier 
231447b2b13SYann Gautier 	if (fdt_get_address(&fdt) == 0) {
232447b2b13SYann Gautier 		return -ENOENT;
233447b2b13SYann Gautier 	}
234447b2b13SYann Gautier 
235447b2b13SYann Gautier 	node = fdt_get_rcc_node(fdt);
236447b2b13SYann Gautier 	if (node < 0) {
237447b2b13SYann Gautier 		return -FDT_ERR_NOTFOUND;
238447b2b13SYann Gautier 	}
239447b2b13SYann Gautier 
240447b2b13SYann Gautier 	subnode = fdt_subnode_offset(fdt, node, name);
241447b2b13SYann Gautier 	if (subnode <= 0) {
242447b2b13SYann Gautier 		return -FDT_ERR_NOTFOUND;
243447b2b13SYann Gautier 	}
244447b2b13SYann Gautier 
245447b2b13SYann Gautier 	return subnode;
246447b2b13SYann Gautier }
247447b2b13SYann Gautier 
248447b2b13SYann Gautier /*
249447b2b13SYann Gautier  * Get the pointer to a rcc-clk property from its name.
250447b2b13SYann Gautier  * @param name: name of the RCC property
251447b2b13SYann Gautier  * @param lenp: stores the length of the property.
252447b2b13SYann Gautier  * @return: pointer to the property on success, and NULL value on failure.
253447b2b13SYann Gautier  */
254447b2b13SYann Gautier const fdt32_t *fdt_rcc_read_prop(const char *prop_name, int *lenp)
255447b2b13SYann Gautier {
256447b2b13SYann Gautier 	const fdt32_t *cuint;
257447b2b13SYann Gautier 	int node, len;
258447b2b13SYann Gautier 	void *fdt;
259447b2b13SYann Gautier 
260447b2b13SYann Gautier 	if (fdt_get_address(&fdt) == 0) {
261447b2b13SYann Gautier 		return NULL;
262447b2b13SYann Gautier 	}
263447b2b13SYann Gautier 
264447b2b13SYann Gautier 	node = fdt_get_rcc_node(fdt);
265447b2b13SYann Gautier 	if (node < 0) {
266447b2b13SYann Gautier 		return NULL;
267447b2b13SYann Gautier 	}
268447b2b13SYann Gautier 
269447b2b13SYann Gautier 	cuint = fdt_getprop(fdt, node, prop_name, &len);
270447b2b13SYann Gautier 	if (cuint == NULL) {
271447b2b13SYann Gautier 		return NULL;
272447b2b13SYann Gautier 	}
273447b2b13SYann Gautier 
274447b2b13SYann Gautier 	*lenp = len;
275447b2b13SYann Gautier 	return cuint;
276447b2b13SYann Gautier }
277447b2b13SYann Gautier 
278447b2b13SYann Gautier /*
279447b2b13SYann Gautier  * Get the secure status for rcc node in device tree.
280447b2b13SYann Gautier  * @return: true if rcc is available from secure world, false if not.
281447b2b13SYann Gautier  */
282447b2b13SYann Gautier bool fdt_get_rcc_secure_status(void)
283447b2b13SYann Gautier {
284447b2b13SYann Gautier 	int node;
285447b2b13SYann Gautier 	void *fdt;
286447b2b13SYann Gautier 
287447b2b13SYann Gautier 	if (fdt_get_address(&fdt) == 0) {
288447b2b13SYann Gautier 		return false;
289447b2b13SYann Gautier 	}
290447b2b13SYann Gautier 
291447b2b13SYann Gautier 	node = fdt_get_rcc_node(fdt);
292447b2b13SYann Gautier 	if (node < 0) {
293447b2b13SYann Gautier 		return false;
294447b2b13SYann Gautier 	}
295447b2b13SYann Gautier 
296447b2b13SYann Gautier 	return !!(fdt_get_status(node) & DT_SECURE);
297447b2b13SYann Gautier }
298447b2b13SYann Gautier 
299447b2b13SYann Gautier /*
300447b2b13SYann Gautier  * Get the stgen base address.
301447b2b13SYann Gautier  * @return: address of stgen on success, and NULL value on failure.
302447b2b13SYann Gautier  */
303447b2b13SYann Gautier uintptr_t fdt_get_stgen_base(void)
304447b2b13SYann Gautier {
305447b2b13SYann Gautier 	int node;
306447b2b13SYann Gautier 	const fdt32_t *cuint;
307447b2b13SYann Gautier 	void *fdt;
308447b2b13SYann Gautier 
309447b2b13SYann Gautier 	if (fdt_get_address(&fdt) == 0) {
310447b2b13SYann Gautier 		return 0;
311447b2b13SYann Gautier 	}
312447b2b13SYann Gautier 
313447b2b13SYann Gautier 	node = fdt_node_offset_by_compatible(fdt, -1, DT_STGEN_COMPAT);
314447b2b13SYann Gautier 	if (node < 0) {
315447b2b13SYann Gautier 		return 0;
316447b2b13SYann Gautier 	}
317447b2b13SYann Gautier 
318447b2b13SYann Gautier 	cuint = fdt_getprop(fdt, node, "reg", NULL);
319447b2b13SYann Gautier 	if (cuint == NULL) {
320447b2b13SYann Gautier 		return 0;
321447b2b13SYann Gautier 	}
322447b2b13SYann Gautier 
323447b2b13SYann Gautier 	return fdt32_to_cpu(*cuint);
324447b2b13SYann Gautier }
325447b2b13SYann Gautier 
326447b2b13SYann Gautier /*
327447b2b13SYann Gautier  * Get the clock ID of the given node in device tree.
328447b2b13SYann Gautier  * @param node: node offset
329447b2b13SYann Gautier  * @return: Clock ID on success, and a negative FDT/ERRNO error code on failure.
330447b2b13SYann Gautier  */
331447b2b13SYann Gautier int fdt_get_clock_id(int node)
332447b2b13SYann Gautier {
333447b2b13SYann Gautier 	const fdt32_t *cuint;
334447b2b13SYann Gautier 	void *fdt;
335447b2b13SYann Gautier 
336447b2b13SYann Gautier 	if (fdt_get_address(&fdt) == 0) {
337447b2b13SYann Gautier 		return -ENOENT;
338447b2b13SYann Gautier 	}
339447b2b13SYann Gautier 
340447b2b13SYann Gautier 	cuint = fdt_getprop(fdt, node, "clocks", NULL);
341447b2b13SYann Gautier 	if (cuint == NULL) {
342447b2b13SYann Gautier 		return -FDT_ERR_NOTFOUND;
343447b2b13SYann Gautier 	}
344447b2b13SYann Gautier 
345447b2b13SYann Gautier 	cuint++;
346447b2b13SYann Gautier 	return (int)fdt32_to_cpu(*cuint);
347447b2b13SYann Gautier }
348