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