xref: /rk3399_ARM-atf/drivers/st/clk/stm32mp_clkfunc.c (revision ba57711c38c965e0c33bf9e5c4f6e3adfc59b4d4)
1447b2b13SYann Gautier /*
2*ba57711cSYann Gautier  * Copyright (c) 2017-2021, 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 
1352a616b4SAndre Przywara #include <common/fdt_wrappers.h>
14447b2b13SYann Gautier #include <drivers/st/stm32_gpio.h>
15447b2b13SYann Gautier #include <drivers/st/stm32mp_clkfunc.h>
16447b2b13SYann Gautier 
17447b2b13SYann Gautier /*
18f66358afSYann Gautier  * Get the frequency of an oscillator from its name in device tree.
19f66358afSYann Gautier  * @param name: oscillator name
20f66358afSYann Gautier  * @param freq: stores the frequency of the oscillator
21f66358afSYann Gautier  * @return: 0 on success, and a negative FDT/ERRNO error code on failure.
22f66358afSYann Gautier  */
23f66358afSYann Gautier int fdt_osc_read_freq(const char *name, uint32_t *freq)
24f66358afSYann Gautier {
25f66358afSYann Gautier 	int node, subnode;
26f66358afSYann Gautier 	void *fdt;
27f66358afSYann Gautier 
28f66358afSYann Gautier 	if (fdt_get_address(&fdt) == 0) {
29f66358afSYann Gautier 		return -ENOENT;
30f66358afSYann Gautier 	}
31f66358afSYann Gautier 
32f66358afSYann Gautier 	node = fdt_path_offset(fdt, "/clocks");
33f66358afSYann Gautier 	if (node < 0) {
34f66358afSYann Gautier 		return -FDT_ERR_NOTFOUND;
35f66358afSYann Gautier 	}
36f66358afSYann Gautier 
37f66358afSYann Gautier 	fdt_for_each_subnode(subnode, fdt, node) {
38f66358afSYann Gautier 		const char *cchar;
39f66358afSYann Gautier 		int ret;
40f66358afSYann Gautier 
41f66358afSYann Gautier 		cchar = fdt_get_name(fdt, subnode, &ret);
42f66358afSYann Gautier 		if (cchar == NULL) {
43f66358afSYann Gautier 			return ret;
44f66358afSYann Gautier 		}
45f66358afSYann Gautier 
46f66358afSYann Gautier 		if (strncmp(cchar, name, (size_t)ret) == 0) {
47f66358afSYann Gautier 			const fdt32_t *cuint;
48f66358afSYann Gautier 
49f66358afSYann Gautier 			cuint = fdt_getprop(fdt, subnode, "clock-frequency",
50f66358afSYann Gautier 					    &ret);
51f66358afSYann Gautier 			if (cuint == NULL) {
52f66358afSYann Gautier 				return ret;
53f66358afSYann Gautier 			}
54f66358afSYann Gautier 
55f66358afSYann Gautier 			*freq = fdt32_to_cpu(*cuint);
56f66358afSYann Gautier 
57f66358afSYann Gautier 			return 0;
58f66358afSYann Gautier 		}
59f66358afSYann Gautier 	}
60f66358afSYann Gautier 
61f66358afSYann Gautier 	/* Oscillator not found, freq=0 */
62f66358afSYann Gautier 	*freq = 0;
63f66358afSYann Gautier 	return 0;
64f66358afSYann Gautier }
65f66358afSYann Gautier 
66f66358afSYann Gautier /*
67f66358afSYann Gautier  * Check the presence of an oscillator property from its id.
68f66358afSYann Gautier  * @param osc_id: oscillator ID
69f66358afSYann Gautier  * @param prop_name: property name
70f66358afSYann Gautier  * @return: true/false regarding search result.
71f66358afSYann Gautier  */
72f66358afSYann Gautier bool fdt_osc_read_bool(enum stm32mp_osc_id osc_id, const char *prop_name)
73f66358afSYann Gautier {
74f66358afSYann Gautier 	int node, subnode;
75f66358afSYann Gautier 	void *fdt;
76f66358afSYann Gautier 
77f66358afSYann Gautier 	if (fdt_get_address(&fdt) == 0) {
78f66358afSYann Gautier 		return false;
79f66358afSYann Gautier 	}
80f66358afSYann Gautier 
81f66358afSYann Gautier 	if (osc_id >= NB_OSC) {
82f66358afSYann Gautier 		return false;
83f66358afSYann Gautier 	}
84f66358afSYann Gautier 
85f66358afSYann Gautier 	node = fdt_path_offset(fdt, "/clocks");
86f66358afSYann Gautier 	if (node < 0) {
87f66358afSYann Gautier 		return false;
88f66358afSYann Gautier 	}
89f66358afSYann Gautier 
90f66358afSYann Gautier 	fdt_for_each_subnode(subnode, fdt, node) {
91f66358afSYann Gautier 		const char *cchar;
92f66358afSYann Gautier 		int ret;
93f66358afSYann Gautier 
94f66358afSYann Gautier 		cchar = fdt_get_name(fdt, subnode, &ret);
95f66358afSYann Gautier 		if (cchar == NULL) {
96f66358afSYann Gautier 			return false;
97f66358afSYann Gautier 		}
98f66358afSYann Gautier 
99f66358afSYann Gautier 		if (strncmp(cchar, stm32mp_osc_node_label[osc_id],
100f66358afSYann Gautier 			    (size_t)ret) != 0) {
101f66358afSYann Gautier 			continue;
102f66358afSYann Gautier 		}
103f66358afSYann Gautier 
104f66358afSYann Gautier 		if (fdt_getprop(fdt, subnode, prop_name, NULL) != NULL) {
105f66358afSYann Gautier 			return true;
106f66358afSYann Gautier 		}
107f66358afSYann Gautier 	}
108f66358afSYann Gautier 
109f66358afSYann Gautier 	return false;
110f66358afSYann Gautier }
111f66358afSYann Gautier 
112f66358afSYann Gautier /*
113f66358afSYann Gautier  * Get the value of a oscillator property from its ID.
114f66358afSYann Gautier  * @param osc_id: oscillator ID
115f66358afSYann Gautier  * @param prop_name: property name
116f66358afSYann Gautier  * @param dflt_value: default value
117f66358afSYann Gautier  * @return oscillator value on success, default value if property not found.
118f66358afSYann Gautier  */
119f66358afSYann Gautier uint32_t fdt_osc_read_uint32_default(enum stm32mp_osc_id osc_id,
120f66358afSYann Gautier 				     const char *prop_name, uint32_t dflt_value)
121f66358afSYann Gautier {
122f66358afSYann Gautier 	int node, subnode;
123f66358afSYann Gautier 	void *fdt;
124f66358afSYann Gautier 
125f66358afSYann Gautier 	if (fdt_get_address(&fdt) == 0) {
126f66358afSYann Gautier 		return dflt_value;
127f66358afSYann Gautier 	}
128f66358afSYann Gautier 
129f66358afSYann Gautier 	if (osc_id >= NB_OSC) {
130f66358afSYann Gautier 		return dflt_value;
131f66358afSYann Gautier 	}
132f66358afSYann Gautier 
133f66358afSYann Gautier 	node = fdt_path_offset(fdt, "/clocks");
134f66358afSYann Gautier 	if (node < 0) {
135f66358afSYann Gautier 		return dflt_value;
136f66358afSYann Gautier 	}
137f66358afSYann Gautier 
138f66358afSYann Gautier 	fdt_for_each_subnode(subnode, fdt, node) {
139f66358afSYann Gautier 		const char *cchar;
140f66358afSYann Gautier 		int ret;
141f66358afSYann Gautier 
142f66358afSYann Gautier 		cchar = fdt_get_name(fdt, subnode, &ret);
143f66358afSYann Gautier 		if (cchar == NULL) {
144f66358afSYann Gautier 			return dflt_value;
145f66358afSYann Gautier 		}
146f66358afSYann Gautier 
147f66358afSYann Gautier 		if (strncmp(cchar, stm32mp_osc_node_label[osc_id],
148f66358afSYann Gautier 			    (size_t)ret) != 0) {
149f66358afSYann Gautier 			continue;
150f66358afSYann Gautier 		}
151f66358afSYann Gautier 
152be858cffSAndre Przywara 		return fdt_read_uint32_default(fdt, subnode, prop_name,
153be858cffSAndre Przywara 					       dflt_value);
154f66358afSYann Gautier 	}
155f66358afSYann Gautier 
156f66358afSYann Gautier 	return dflt_value;
157f66358afSYann Gautier }
158f66358afSYann Gautier 
159f66358afSYann 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  */
164ff18c4cdSPatrick Delaunay static int fdt_get_rcc_node(void *fdt)
165447b2b13SYann Gautier {
166*ba57711cSYann Gautier 	static int node;
167*ba57711cSYann Gautier 
168*ba57711cSYann Gautier 	if (node <= 0) {
169*ba57711cSYann Gautier 		node = fdt_node_offset_by_compatible(fdt, -1, DT_RCC_CLK_COMPAT);
170*ba57711cSYann Gautier 	}
171*ba57711cSYann Gautier 
172*ba57711cSYann Gautier 	return node;
173447b2b13SYann Gautier }
174447b2b13SYann Gautier 
175447b2b13SYann Gautier /*
176447b2b13SYann Gautier  * Read a series of parameters in rcc-clk section in device tree
177447b2b13SYann Gautier  * @param prop_name: Name of the RCC property to be read
178447b2b13SYann Gautier  * @param array: the array to store the property parameters
179447b2b13SYann Gautier  * @param count: number of parameters to be read
180447b2b13SYann Gautier  * @return: 0 on succes or a negative value on error
181447b2b13SYann Gautier  */
18252a616b4SAndre Przywara int fdt_rcc_read_uint32_array(const char *prop_name, uint32_t count,
18352a616b4SAndre Przywara 			      uint32_t *array)
184447b2b13SYann Gautier {
185447b2b13SYann Gautier 	int node;
186447b2b13SYann Gautier 	void *fdt;
187447b2b13SYann Gautier 
188447b2b13SYann Gautier 	if (fdt_get_address(&fdt) == 0) {
189447b2b13SYann Gautier 		return -ENOENT;
190447b2b13SYann Gautier 	}
191447b2b13SYann Gautier 
192447b2b13SYann Gautier 	node = fdt_get_rcc_node(fdt);
193447b2b13SYann Gautier 	if (node < 0) {
194447b2b13SYann Gautier 		return -FDT_ERR_NOTFOUND;
195447b2b13SYann Gautier 	}
196447b2b13SYann Gautier 
19752a616b4SAndre Przywara 	return fdt_read_uint32_array(fdt, node, prop_name, count, array);
198447b2b13SYann Gautier }
199447b2b13SYann Gautier 
200447b2b13SYann Gautier /*
201447b2b13SYann Gautier  * Get the subnode offset in rcc-clk section from its name in device tree
202447b2b13SYann Gautier  * @param name: name of the RCC property
203447b2b13SYann Gautier  * @return: offset on success, and a negative FDT/ERRNO error code on failure.
204447b2b13SYann Gautier  */
205447b2b13SYann Gautier int fdt_rcc_subnode_offset(const char *name)
206447b2b13SYann Gautier {
207447b2b13SYann Gautier 	int node, subnode;
208447b2b13SYann Gautier 	void *fdt;
209447b2b13SYann Gautier 
210447b2b13SYann Gautier 	if (fdt_get_address(&fdt) == 0) {
211447b2b13SYann Gautier 		return -ENOENT;
212447b2b13SYann Gautier 	}
213447b2b13SYann Gautier 
214447b2b13SYann Gautier 	node = fdt_get_rcc_node(fdt);
215447b2b13SYann Gautier 	if (node < 0) {
216447b2b13SYann Gautier 		return -FDT_ERR_NOTFOUND;
217447b2b13SYann Gautier 	}
218447b2b13SYann Gautier 
219447b2b13SYann Gautier 	subnode = fdt_subnode_offset(fdt, node, name);
220447b2b13SYann Gautier 	if (subnode <= 0) {
221447b2b13SYann Gautier 		return -FDT_ERR_NOTFOUND;
222447b2b13SYann Gautier 	}
223447b2b13SYann Gautier 
224447b2b13SYann Gautier 	return subnode;
225447b2b13SYann Gautier }
226447b2b13SYann Gautier 
227447b2b13SYann Gautier /*
228447b2b13SYann Gautier  * Get the pointer to a rcc-clk property from its name.
229447b2b13SYann Gautier  * @param name: name of the RCC property
230447b2b13SYann Gautier  * @param lenp: stores the length of the property.
231447b2b13SYann Gautier  * @return: pointer to the property on success, and NULL value on failure.
232447b2b13SYann Gautier  */
233447b2b13SYann Gautier const fdt32_t *fdt_rcc_read_prop(const char *prop_name, int *lenp)
234447b2b13SYann Gautier {
235447b2b13SYann Gautier 	const fdt32_t *cuint;
236447b2b13SYann Gautier 	int node, len;
237447b2b13SYann Gautier 	void *fdt;
238447b2b13SYann Gautier 
239447b2b13SYann Gautier 	if (fdt_get_address(&fdt) == 0) {
240447b2b13SYann Gautier 		return NULL;
241447b2b13SYann Gautier 	}
242447b2b13SYann Gautier 
243447b2b13SYann Gautier 	node = fdt_get_rcc_node(fdt);
244447b2b13SYann Gautier 	if (node < 0) {
245447b2b13SYann Gautier 		return NULL;
246447b2b13SYann Gautier 	}
247447b2b13SYann Gautier 
248447b2b13SYann Gautier 	cuint = fdt_getprop(fdt, node, prop_name, &len);
249447b2b13SYann Gautier 	if (cuint == NULL) {
250447b2b13SYann Gautier 		return NULL;
251447b2b13SYann Gautier 	}
252447b2b13SYann Gautier 
253447b2b13SYann Gautier 	*lenp = len;
254447b2b13SYann Gautier 	return cuint;
255447b2b13SYann Gautier }
256447b2b13SYann Gautier 
257447b2b13SYann Gautier /*
258447b2b13SYann Gautier  * Get the secure status for rcc node in device tree.
259447b2b13SYann Gautier  * @return: true if rcc is available from secure world, false if not.
260447b2b13SYann Gautier  */
261447b2b13SYann Gautier bool fdt_get_rcc_secure_status(void)
262447b2b13SYann Gautier {
263447b2b13SYann Gautier 	int node;
264447b2b13SYann Gautier 	void *fdt;
265447b2b13SYann Gautier 
266447b2b13SYann Gautier 	if (fdt_get_address(&fdt) == 0) {
267447b2b13SYann Gautier 		return false;
268447b2b13SYann Gautier 	}
269447b2b13SYann Gautier 
270447b2b13SYann Gautier 	node = fdt_get_rcc_node(fdt);
271447b2b13SYann Gautier 	if (node < 0) {
272447b2b13SYann Gautier 		return false;
273447b2b13SYann Gautier 	}
274447b2b13SYann Gautier 
275447b2b13SYann Gautier 	return !!(fdt_get_status(node) & DT_SECURE);
276447b2b13SYann Gautier }
277447b2b13SYann Gautier 
278447b2b13SYann Gautier /*
279447b2b13SYann Gautier  * Get the clock ID of the given node in device tree.
280447b2b13SYann Gautier  * @param node: node offset
281447b2b13SYann Gautier  * @return: Clock ID on success, and a negative FDT/ERRNO error code on failure.
282447b2b13SYann Gautier  */
283447b2b13SYann Gautier int fdt_get_clock_id(int node)
284447b2b13SYann Gautier {
285447b2b13SYann Gautier 	const fdt32_t *cuint;
286447b2b13SYann Gautier 	void *fdt;
287447b2b13SYann Gautier 
288447b2b13SYann Gautier 	if (fdt_get_address(&fdt) == 0) {
289447b2b13SYann Gautier 		return -ENOENT;
290447b2b13SYann Gautier 	}
291447b2b13SYann Gautier 
292447b2b13SYann Gautier 	cuint = fdt_getprop(fdt, node, "clocks", NULL);
293447b2b13SYann Gautier 	if (cuint == NULL) {
294447b2b13SYann Gautier 		return -FDT_ERR_NOTFOUND;
295447b2b13SYann Gautier 	}
296447b2b13SYann Gautier 
297447b2b13SYann Gautier 	cuint++;
298447b2b13SYann Gautier 	return (int)fdt32_to_cpu(*cuint);
299447b2b13SYann Gautier }
300