xref: /rk3399_ARM-atf/drivers/st/clk/stm32mp_clkfunc.c (revision b208e3da0487b29bf3d67f3649cc2b1b6159b978)
1447b2b13SYann Gautier /*
2bcccdaccSPatrick Delaunay  * Copyright (c) 2017-2022, 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 
952a616b4SAndre Przywara #include <common/fdt_wrappers.h>
1033667d29SYann Gautier #include <drivers/clk.h>
11447b2b13SYann Gautier #include <drivers/st/stm32_gpio.h>
12447b2b13SYann Gautier #include <drivers/st/stm32mp_clkfunc.h>
13bcccdaccSPatrick Delaunay #include <libfdt.h>
14bcccdaccSPatrick Delaunay 
15bcccdaccSPatrick Delaunay #include <platform_def.h>
16447b2b13SYann Gautier 
17165ad556SNicolas Le Bayon #define DT_UART_COMPAT		"st,stm32h7-uart"
18447b2b13SYann Gautier /*
19f66358afSYann Gautier  * Get the frequency of an oscillator from its name in device tree.
20f66358afSYann Gautier  * @param name: oscillator name
21f66358afSYann Gautier  * @param freq: stores the frequency of the oscillator
22f66358afSYann Gautier  * @return: 0 on success, and a negative FDT/ERRNO error code on failure.
23f66358afSYann Gautier  */
24f66358afSYann Gautier int fdt_osc_read_freq(const char *name, uint32_t *freq)
25f66358afSYann Gautier {
26f66358afSYann Gautier 	int node, subnode;
27f66358afSYann Gautier 	void *fdt;
28f66358afSYann Gautier 
29f66358afSYann Gautier 	if (fdt_get_address(&fdt) == 0) {
30f66358afSYann Gautier 		return -ENOENT;
31f66358afSYann Gautier 	}
32f66358afSYann Gautier 
33f66358afSYann Gautier 	node = fdt_path_offset(fdt, "/clocks");
34f66358afSYann Gautier 	if (node < 0) {
35f66358afSYann Gautier 		return -FDT_ERR_NOTFOUND;
36f66358afSYann Gautier 	}
37f66358afSYann Gautier 
38f66358afSYann Gautier 	fdt_for_each_subnode(subnode, fdt, node) {
39f66358afSYann Gautier 		const char *cchar;
40f66358afSYann Gautier 		int ret;
41f66358afSYann Gautier 
42f66358afSYann Gautier 		cchar = fdt_get_name(fdt, subnode, &ret);
43f66358afSYann Gautier 		if (cchar == NULL) {
44f66358afSYann Gautier 			return ret;
45f66358afSYann Gautier 		}
46f66358afSYann Gautier 
47bcccdaccSPatrick Delaunay 		if ((strncmp(cchar, name, (size_t)ret) == 0) &&
48bcccdaccSPatrick Delaunay 		    (fdt_get_status(subnode) != DT_DISABLED)) {
49f66358afSYann Gautier 			const fdt32_t *cuint;
50f66358afSYann Gautier 
51f66358afSYann Gautier 			cuint = fdt_getprop(fdt, subnode, "clock-frequency",
52f66358afSYann Gautier 					    &ret);
53f66358afSYann Gautier 			if (cuint == NULL) {
54f66358afSYann Gautier 				return ret;
55f66358afSYann Gautier 			}
56f66358afSYann Gautier 
57f66358afSYann Gautier 			*freq = fdt32_to_cpu(*cuint);
58f66358afSYann Gautier 
59f66358afSYann Gautier 			return 0;
60f66358afSYann Gautier 		}
61f66358afSYann Gautier 	}
62f66358afSYann Gautier 
63f66358afSYann Gautier 	/* Oscillator not found, freq=0 */
64f66358afSYann Gautier 	*freq = 0;
65f66358afSYann Gautier 	return 0;
66f66358afSYann Gautier }
67f66358afSYann Gautier 
68f66358afSYann Gautier /*
69f66358afSYann Gautier  * Check the presence of an oscillator property from its id.
70*b208e3daSGabriel Fernandez  * @param node_label: clock node name
71f66358afSYann Gautier  * @param prop_name: property name
72f66358afSYann Gautier  * @return: true/false regarding search result.
73f66358afSYann Gautier  */
74*b208e3daSGabriel Fernandez bool fdt_clk_read_bool(const char *node_label, const char *prop_name)
75f66358afSYann Gautier {
76f66358afSYann Gautier 	int node, subnode;
77f66358afSYann Gautier 	void *fdt;
78f66358afSYann Gautier 
79f66358afSYann Gautier 	if (fdt_get_address(&fdt) == 0) {
80f66358afSYann Gautier 		return false;
81f66358afSYann Gautier 	}
82f66358afSYann Gautier 
83f66358afSYann Gautier 	node = fdt_path_offset(fdt, "/clocks");
84f66358afSYann Gautier 	if (node < 0) {
85f66358afSYann Gautier 		return false;
86f66358afSYann Gautier 	}
87f66358afSYann Gautier 
88f66358afSYann Gautier 	fdt_for_each_subnode(subnode, fdt, node) {
89f66358afSYann Gautier 		const char *cchar;
90f66358afSYann Gautier 		int ret;
91f66358afSYann Gautier 
92f66358afSYann Gautier 		cchar = fdt_get_name(fdt, subnode, &ret);
93f66358afSYann Gautier 		if (cchar == NULL) {
94f66358afSYann Gautier 			return false;
95f66358afSYann Gautier 		}
96f66358afSYann Gautier 
97*b208e3daSGabriel Fernandez 		if (strncmp(cchar, node_label, (size_t)ret) != 0) {
98f66358afSYann Gautier 			continue;
99f66358afSYann Gautier 		}
100f66358afSYann Gautier 
101f66358afSYann Gautier 		if (fdt_getprop(fdt, subnode, prop_name, NULL) != NULL) {
102f66358afSYann Gautier 			return true;
103f66358afSYann Gautier 		}
104f66358afSYann Gautier 	}
105f66358afSYann Gautier 
106f66358afSYann Gautier 	return false;
107f66358afSYann Gautier }
108f66358afSYann Gautier 
109f66358afSYann Gautier /*
110*b208e3daSGabriel Fernandez  * Get the value of a oscillator property from its name.
111*b208e3daSGabriel Fernandez  * @param node_label: oscillator name
112f66358afSYann Gautier  * @param prop_name: property name
113f66358afSYann Gautier  * @param dflt_value: default value
114f66358afSYann Gautier  * @return oscillator value on success, default value if property not found.
115f66358afSYann Gautier  */
116*b208e3daSGabriel Fernandez uint32_t fdt_clk_read_uint32_default(const char *node_label,
117f66358afSYann Gautier 				     const char *prop_name, uint32_t dflt_value)
118f66358afSYann Gautier {
119f66358afSYann Gautier 	int node, subnode;
120f66358afSYann Gautier 	void *fdt;
121f66358afSYann Gautier 
122f66358afSYann Gautier 	if (fdt_get_address(&fdt) == 0) {
123f66358afSYann Gautier 		return dflt_value;
124f66358afSYann Gautier 	}
125f66358afSYann Gautier 
126f66358afSYann Gautier 	node = fdt_path_offset(fdt, "/clocks");
127f66358afSYann Gautier 	if (node < 0) {
128f66358afSYann Gautier 		return dflt_value;
129f66358afSYann Gautier 	}
130f66358afSYann Gautier 
131f66358afSYann Gautier 	fdt_for_each_subnode(subnode, fdt, node) {
132f66358afSYann Gautier 		const char *cchar;
133f66358afSYann Gautier 		int ret;
134f66358afSYann Gautier 
135f66358afSYann Gautier 		cchar = fdt_get_name(fdt, subnode, &ret);
136f66358afSYann Gautier 		if (cchar == NULL) {
137f66358afSYann Gautier 			return dflt_value;
138f66358afSYann Gautier 		}
139f66358afSYann Gautier 
140*b208e3daSGabriel Fernandez 		if (strncmp(cchar, node_label, (size_t)ret) != 0) {
141f66358afSYann Gautier 			continue;
142f66358afSYann Gautier 		}
143f66358afSYann Gautier 
144be858cffSAndre Przywara 		return fdt_read_uint32_default(fdt, subnode, prop_name,
145be858cffSAndre Przywara 					       dflt_value);
146f66358afSYann Gautier 	}
147f66358afSYann Gautier 
148f66358afSYann Gautier 	return dflt_value;
149f66358afSYann Gautier }
150f66358afSYann Gautier 
151f66358afSYann Gautier /*
152447b2b13SYann Gautier  * Get the RCC node offset from the device tree
153447b2b13SYann Gautier  * @param fdt: Device tree reference
154447b2b13SYann Gautier  * @return: Node offset or a negative value on error
155447b2b13SYann Gautier  */
156ff18c4cdSPatrick Delaunay static int fdt_get_rcc_node(void *fdt)
157447b2b13SYann Gautier {
158ba57711cSYann Gautier 	static int node;
159ba57711cSYann Gautier 
160ba57711cSYann Gautier 	if (node <= 0) {
161ba57711cSYann Gautier 		node = fdt_node_offset_by_compatible(fdt, -1, DT_RCC_CLK_COMPAT);
162ba57711cSYann Gautier 	}
163ba57711cSYann Gautier 
164ba57711cSYann Gautier 	return node;
165447b2b13SYann Gautier }
166447b2b13SYann Gautier 
167447b2b13SYann Gautier /*
168447b2b13SYann Gautier  * Read a series of parameters in rcc-clk section in device tree
169447b2b13SYann Gautier  * @param prop_name: Name of the RCC property to be read
170447b2b13SYann Gautier  * @param array: the array to store the property parameters
171447b2b13SYann Gautier  * @param count: number of parameters to be read
172447b2b13SYann Gautier  * @return: 0 on succes or a negative value on error
173447b2b13SYann Gautier  */
17452a616b4SAndre Przywara int fdt_rcc_read_uint32_array(const char *prop_name, uint32_t count,
17552a616b4SAndre Przywara 			      uint32_t *array)
176447b2b13SYann Gautier {
177447b2b13SYann Gautier 	int node;
178447b2b13SYann Gautier 	void *fdt;
179447b2b13SYann Gautier 
180447b2b13SYann Gautier 	if (fdt_get_address(&fdt) == 0) {
181447b2b13SYann Gautier 		return -ENOENT;
182447b2b13SYann Gautier 	}
183447b2b13SYann Gautier 
184447b2b13SYann Gautier 	node = fdt_get_rcc_node(fdt);
185447b2b13SYann Gautier 	if (node < 0) {
186447b2b13SYann Gautier 		return -FDT_ERR_NOTFOUND;
187447b2b13SYann Gautier 	}
188447b2b13SYann Gautier 
18952a616b4SAndre Przywara 	return fdt_read_uint32_array(fdt, node, prop_name, count, array);
190447b2b13SYann Gautier }
191447b2b13SYann Gautier 
192447b2b13SYann Gautier /*
193447b2b13SYann Gautier  * Get the subnode offset in rcc-clk section from its name in device tree
194447b2b13SYann Gautier  * @param name: name of the RCC property
195447b2b13SYann Gautier  * @return: offset on success, and a negative FDT/ERRNO error code on failure.
196447b2b13SYann Gautier  */
197447b2b13SYann Gautier int fdt_rcc_subnode_offset(const char *name)
198447b2b13SYann Gautier {
199447b2b13SYann Gautier 	int node, subnode;
200447b2b13SYann Gautier 	void *fdt;
201447b2b13SYann Gautier 
202447b2b13SYann Gautier 	if (fdt_get_address(&fdt) == 0) {
203447b2b13SYann Gautier 		return -ENOENT;
204447b2b13SYann Gautier 	}
205447b2b13SYann Gautier 
206447b2b13SYann Gautier 	node = fdt_get_rcc_node(fdt);
207447b2b13SYann Gautier 	if (node < 0) {
208447b2b13SYann Gautier 		return -FDT_ERR_NOTFOUND;
209447b2b13SYann Gautier 	}
210447b2b13SYann Gautier 
211447b2b13SYann Gautier 	subnode = fdt_subnode_offset(fdt, node, name);
212447b2b13SYann Gautier 	if (subnode <= 0) {
213447b2b13SYann Gautier 		return -FDT_ERR_NOTFOUND;
214447b2b13SYann Gautier 	}
215447b2b13SYann Gautier 
216447b2b13SYann Gautier 	return subnode;
217447b2b13SYann Gautier }
218447b2b13SYann Gautier 
219447b2b13SYann Gautier /*
220447b2b13SYann Gautier  * Get the pointer to a rcc-clk property from its name.
221447b2b13SYann Gautier  * @param name: name of the RCC property
222447b2b13SYann Gautier  * @param lenp: stores the length of the property.
223447b2b13SYann Gautier  * @return: pointer to the property on success, and NULL value on failure.
224447b2b13SYann Gautier  */
225447b2b13SYann Gautier const fdt32_t *fdt_rcc_read_prop(const char *prop_name, int *lenp)
226447b2b13SYann Gautier {
227447b2b13SYann Gautier 	const fdt32_t *cuint;
228447b2b13SYann Gautier 	int node, len;
229447b2b13SYann Gautier 	void *fdt;
230447b2b13SYann Gautier 
231447b2b13SYann Gautier 	if (fdt_get_address(&fdt) == 0) {
232447b2b13SYann Gautier 		return NULL;
233447b2b13SYann Gautier 	}
234447b2b13SYann Gautier 
235447b2b13SYann Gautier 	node = fdt_get_rcc_node(fdt);
236447b2b13SYann Gautier 	if (node < 0) {
237447b2b13SYann Gautier 		return NULL;
238447b2b13SYann Gautier 	}
239447b2b13SYann Gautier 
240447b2b13SYann Gautier 	cuint = fdt_getprop(fdt, node, prop_name, &len);
241447b2b13SYann Gautier 	if (cuint == NULL) {
242447b2b13SYann Gautier 		return NULL;
243447b2b13SYann Gautier 	}
244447b2b13SYann Gautier 
245447b2b13SYann Gautier 	*lenp = len;
246447b2b13SYann Gautier 	return cuint;
247447b2b13SYann Gautier }
248447b2b13SYann Gautier 
249447b2b13SYann Gautier /*
250447b2b13SYann Gautier  * Get the secure status for rcc node in device tree.
251447b2b13SYann Gautier  * @return: true if rcc is available from secure world, false if not.
252447b2b13SYann Gautier  */
253447b2b13SYann Gautier bool fdt_get_rcc_secure_status(void)
254447b2b13SYann Gautier {
255447b2b13SYann Gautier 	int node;
256447b2b13SYann Gautier 	void *fdt;
257447b2b13SYann Gautier 
258447b2b13SYann Gautier 	if (fdt_get_address(&fdt) == 0) {
259447b2b13SYann Gautier 		return false;
260447b2b13SYann Gautier 	}
261447b2b13SYann Gautier 
262447b2b13SYann Gautier 	node = fdt_get_rcc_node(fdt);
263447b2b13SYann Gautier 	if (node < 0) {
264447b2b13SYann Gautier 		return false;
265447b2b13SYann Gautier 	}
266447b2b13SYann Gautier 
267447b2b13SYann Gautier 	return !!(fdt_get_status(node) & DT_SECURE);
268447b2b13SYann Gautier }
269447b2b13SYann Gautier 
270447b2b13SYann Gautier /*
271447b2b13SYann Gautier  * Get the clock ID of the given node in device tree.
272447b2b13SYann Gautier  * @param node: node offset
273447b2b13SYann Gautier  * @return: Clock ID on success, and a negative FDT/ERRNO error code on failure.
274447b2b13SYann Gautier  */
275447b2b13SYann Gautier int fdt_get_clock_id(int node)
276447b2b13SYann Gautier {
277447b2b13SYann Gautier 	const fdt32_t *cuint;
278447b2b13SYann Gautier 	void *fdt;
279447b2b13SYann Gautier 
280447b2b13SYann Gautier 	if (fdt_get_address(&fdt) == 0) {
281447b2b13SYann Gautier 		return -ENOENT;
282447b2b13SYann Gautier 	}
283447b2b13SYann Gautier 
284447b2b13SYann Gautier 	cuint = fdt_getprop(fdt, node, "clocks", NULL);
285447b2b13SYann Gautier 	if (cuint == NULL) {
286447b2b13SYann Gautier 		return -FDT_ERR_NOTFOUND;
287447b2b13SYann Gautier 	}
288447b2b13SYann Gautier 
289447b2b13SYann Gautier 	cuint++;
290447b2b13SYann Gautier 	return (int)fdt32_to_cpu(*cuint);
291447b2b13SYann Gautier }
292165ad556SNicolas Le Bayon 
293165ad556SNicolas Le Bayon /*
294165ad556SNicolas Le Bayon  * Get the frequency of the specified UART instance.
295165ad556SNicolas Le Bayon  * @param instance: UART interface registers base address.
296165ad556SNicolas Le Bayon  * @return: clock frequency on success, 0 value on failure.
297165ad556SNicolas Le Bayon  */
298165ad556SNicolas Le Bayon unsigned long fdt_get_uart_clock_freq(uintptr_t instance)
299165ad556SNicolas Le Bayon {
300165ad556SNicolas Le Bayon 	void *fdt;
301165ad556SNicolas Le Bayon 	int node;
302165ad556SNicolas Le Bayon 	int clk_id;
303165ad556SNicolas Le Bayon 
304165ad556SNicolas Le Bayon 	if (fdt_get_address(&fdt) == 0) {
305165ad556SNicolas Le Bayon 		return 0UL;
306165ad556SNicolas Le Bayon 	}
307165ad556SNicolas Le Bayon 
308165ad556SNicolas Le Bayon 	/* Check for UART nodes */
309165ad556SNicolas Le Bayon 	node = dt_match_instance_by_compatible(DT_UART_COMPAT, instance);
310165ad556SNicolas Le Bayon 	if (node < 0) {
311165ad556SNicolas Le Bayon 		return 0UL;
312165ad556SNicolas Le Bayon 	}
313165ad556SNicolas Le Bayon 
314165ad556SNicolas Le Bayon 	clk_id = fdt_get_clock_id(node);
315165ad556SNicolas Le Bayon 	if (clk_id < 0) {
316165ad556SNicolas Le Bayon 		return 0UL;
317165ad556SNicolas Le Bayon 	}
318165ad556SNicolas Le Bayon 
31933667d29SYann Gautier 	return clk_get_rate((unsigned long)clk_id);
320165ad556SNicolas Le Bayon }
321