xref: /rk3399_ARM-atf/drivers/st/clk/stm32mp_clkfunc.c (revision e672698ce7edc2762a68112e18c30c0b19fbd252)
1 /*
2  * Copyright (c) 2017-2022, STMicroelectronics - All Rights Reserved
3  *
4  * SPDX-License-Identifier: BSD-3-Clause
5  */
6 
7 #include <errno.h>
8 
9 #include <arch_helpers.h>
10 #include <common/fdt_wrappers.h>
11 #include <drivers/clk.h>
12 #include <drivers/generic_delay_timer.h>
13 #include <drivers/st/stm32_gpio.h>
14 #include <drivers/st/stm32mp_clkfunc.h>
15 #include <lib/mmio.h>
16 #include <libfdt.h>
17 
18 #include <platform_def.h>
19 
20 #define DT_UART_COMPAT		"st,stm32h7-uart"
21 /*
22  * Get the frequency of an oscillator from its name in device tree.
23  * @param name: oscillator name
24  * @param freq: stores the frequency of the oscillator
25  * @return: 0 on success, and a negative FDT/ERRNO error code on failure.
26  */
27 int fdt_osc_read_freq(const char *name, uint32_t *freq)
28 {
29 	int node, subnode;
30 	void *fdt;
31 
32 	if (fdt_get_address(&fdt) == 0) {
33 		return -ENOENT;
34 	}
35 
36 	node = fdt_path_offset(fdt, "/clocks");
37 	if (node < 0) {
38 		return -FDT_ERR_NOTFOUND;
39 	}
40 
41 	fdt_for_each_subnode(subnode, fdt, node) {
42 		const char *cchar;
43 		int ret;
44 
45 		cchar = fdt_get_name(fdt, subnode, &ret);
46 		if (cchar == NULL) {
47 			return ret;
48 		}
49 
50 		if ((strncmp(cchar, name, (size_t)ret) == 0) &&
51 		    (fdt_get_status(subnode) != DT_DISABLED)) {
52 			const fdt32_t *cuint;
53 
54 			cuint = fdt_getprop(fdt, subnode, "clock-frequency",
55 					    &ret);
56 			if (cuint == NULL) {
57 				return ret;
58 			}
59 
60 			*freq = fdt32_to_cpu(*cuint);
61 
62 			return 0;
63 		}
64 	}
65 
66 	/* Oscillator not found, freq=0 */
67 	*freq = 0;
68 	return 0;
69 }
70 
71 /*
72  * Check the presence of an oscillator property from its id.
73  * @param node_label: clock node name
74  * @param prop_name: property name
75  * @return: true/false regarding search result.
76  */
77 bool fdt_clk_read_bool(const char *node_label, const char *prop_name)
78 {
79 	int node, subnode;
80 	void *fdt;
81 
82 	if (fdt_get_address(&fdt) == 0) {
83 		return false;
84 	}
85 
86 	node = fdt_path_offset(fdt, "/clocks");
87 	if (node < 0) {
88 		return false;
89 	}
90 
91 	fdt_for_each_subnode(subnode, fdt, node) {
92 		const char *cchar;
93 		int ret;
94 
95 		cchar = fdt_get_name(fdt, subnode, &ret);
96 		if (cchar == NULL) {
97 			return false;
98 		}
99 
100 		if (strncmp(cchar, node_label, (size_t)ret) != 0) {
101 			continue;
102 		}
103 
104 		if (fdt_getprop(fdt, subnode, prop_name, NULL) != NULL) {
105 			return true;
106 		}
107 	}
108 
109 	return false;
110 }
111 
112 /*
113  * Get the value of a oscillator property from its name.
114  * @param node_label: oscillator name
115  * @param prop_name: property name
116  * @param dflt_value: default value
117  * @return oscillator value on success, default value if property not found.
118  */
119 uint32_t fdt_clk_read_uint32_default(const char *node_label,
120 				     const char *prop_name, uint32_t dflt_value)
121 {
122 	int node, subnode;
123 	void *fdt;
124 
125 	if (fdt_get_address(&fdt) == 0) {
126 		return dflt_value;
127 	}
128 
129 	node = fdt_path_offset(fdt, "/clocks");
130 	if (node < 0) {
131 		return dflt_value;
132 	}
133 
134 	fdt_for_each_subnode(subnode, fdt, node) {
135 		const char *cchar;
136 		int ret;
137 
138 		cchar = fdt_get_name(fdt, subnode, &ret);
139 		if (cchar == NULL) {
140 			return dflt_value;
141 		}
142 
143 		if (strncmp(cchar, node_label, (size_t)ret) != 0) {
144 			continue;
145 		}
146 
147 		return fdt_read_uint32_default(fdt, subnode, prop_name,
148 					       dflt_value);
149 	}
150 
151 	return dflt_value;
152 }
153 
154 /*
155  * Get the RCC node offset from the device tree
156  * @param fdt: Device tree reference
157  * @return: Node offset or a negative value on error
158  */
159 static int fdt_get_rcc_node(void *fdt)
160 {
161 	static int node;
162 
163 	if (node <= 0) {
164 		node = fdt_node_offset_by_compatible(fdt, -1, DT_RCC_CLK_COMPAT);
165 	}
166 
167 	return node;
168 }
169 
170 /*
171  * Read a series of parameters in rcc-clk section in device tree
172  * @param prop_name: Name of the RCC property to be read
173  * @param array: the array to store the property parameters
174  * @param count: number of parameters to be read
175  * @return: 0 on succes or a negative value on error
176  */
177 int fdt_rcc_read_uint32_array(const char *prop_name, uint32_t count,
178 			      uint32_t *array)
179 {
180 	int node;
181 	void *fdt;
182 
183 	if (fdt_get_address(&fdt) == 0) {
184 		return -ENOENT;
185 	}
186 
187 	node = fdt_get_rcc_node(fdt);
188 	if (node < 0) {
189 		return -FDT_ERR_NOTFOUND;
190 	}
191 
192 	return fdt_read_uint32_array(fdt, node, prop_name, count, array);
193 }
194 
195 /*
196  * Get the subnode offset in rcc-clk section from its name in device tree
197  * @param name: name of the RCC property
198  * @return: offset on success, and a negative FDT/ERRNO error code on failure.
199  */
200 int fdt_rcc_subnode_offset(const char *name)
201 {
202 	int node, subnode;
203 	void *fdt;
204 
205 	if (fdt_get_address(&fdt) == 0) {
206 		return -ENOENT;
207 	}
208 
209 	node = fdt_get_rcc_node(fdt);
210 	if (node < 0) {
211 		return -FDT_ERR_NOTFOUND;
212 	}
213 
214 	subnode = fdt_subnode_offset(fdt, node, name);
215 	if (subnode <= 0) {
216 		return -FDT_ERR_NOTFOUND;
217 	}
218 
219 	return subnode;
220 }
221 
222 /*
223  * Get the pointer to a rcc-clk property from its name.
224  * @param name: name of the RCC property
225  * @param lenp: stores the length of the property.
226  * @return: pointer to the property on success, and NULL value on failure.
227  */
228 const fdt32_t *fdt_rcc_read_prop(const char *prop_name, int *lenp)
229 {
230 	const fdt32_t *cuint;
231 	int node, len;
232 	void *fdt;
233 
234 	if (fdt_get_address(&fdt) == 0) {
235 		return NULL;
236 	}
237 
238 	node = fdt_get_rcc_node(fdt);
239 	if (node < 0) {
240 		return NULL;
241 	}
242 
243 	cuint = fdt_getprop(fdt, node, prop_name, &len);
244 	if (cuint == NULL) {
245 		return NULL;
246 	}
247 
248 	*lenp = len;
249 	return cuint;
250 }
251 
252 /*
253  * Get the secure status for rcc node in device tree.
254  * @return: true if rcc is available from secure world, false if not.
255  */
256 bool fdt_get_rcc_secure_status(void)
257 {
258 	int node;
259 	void *fdt;
260 
261 	if (fdt_get_address(&fdt) == 0) {
262 		return false;
263 	}
264 
265 	node = fdt_get_rcc_node(fdt);
266 	if (node < 0) {
267 		return false;
268 	}
269 
270 	return !!(fdt_get_status(node) & DT_SECURE);
271 }
272 
273 /*
274  * Get the clock ID of the given node in device tree.
275  * @param node: node offset
276  * @return: Clock ID on success, and a negative FDT/ERRNO error code on failure.
277  */
278 int fdt_get_clock_id(int node)
279 {
280 	const fdt32_t *cuint;
281 	void *fdt;
282 
283 	if (fdt_get_address(&fdt) == 0) {
284 		return -ENOENT;
285 	}
286 
287 	cuint = fdt_getprop(fdt, node, "clocks", NULL);
288 	if (cuint == NULL) {
289 		return -FDT_ERR_NOTFOUND;
290 	}
291 
292 	cuint++;
293 	return (int)fdt32_to_cpu(*cuint);
294 }
295 
296 /*
297  * Get the frequency of the specified UART instance.
298  * @param instance: UART interface registers base address.
299  * @return: clock frequency on success, 0 value on failure.
300  */
301 unsigned long fdt_get_uart_clock_freq(uintptr_t instance)
302 {
303 	void *fdt;
304 	int node;
305 	int clk_id;
306 
307 	if (fdt_get_address(&fdt) == 0) {
308 		return 0UL;
309 	}
310 
311 	/* Check for UART nodes */
312 	node = dt_match_instance_by_compatible(DT_UART_COMPAT, instance);
313 	if (node < 0) {
314 		return 0UL;
315 	}
316 
317 	clk_id = fdt_get_clock_id(node);
318 	if (clk_id < 0) {
319 		return 0UL;
320 	}
321 
322 	return clk_get_rate((unsigned long)clk_id);
323 }
324 
325 /*******************************************************************************
326  * This function configures and restores the STGEN counter depending on the
327  * connected clock.
328  ******************************************************************************/
329 void stm32mp_stgen_config(unsigned long rate)
330 {
331 	uint32_t cntfid0;
332 	unsigned long long counter;
333 
334 	cntfid0 = mmio_read_32(STGEN_BASE + CNTFID_OFF);
335 
336 	if (cntfid0 == rate) {
337 		return;
338 	}
339 
340 	mmio_clrbits_32(STGEN_BASE + CNTCR_OFF, CNTCR_EN);
341 	counter = stm32mp_stgen_get_counter() * rate / cntfid0;
342 
343 	mmio_write_32(STGEN_BASE + CNTCVL_OFF, (uint32_t)counter);
344 	mmio_write_32(STGEN_BASE + CNTCVU_OFF, (uint32_t)(counter >> 32));
345 	mmio_write_32(STGEN_BASE + CNTFID_OFF, rate);
346 	mmio_setbits_32(STGEN_BASE + CNTCR_OFF, CNTCR_EN);
347 
348 	write_cntfrq_el0(rate);
349 
350 	/* Need to update timer with new frequency */
351 	generic_delay_timer_init();
352 }
353 
354 /*******************************************************************************
355  * This function returns the STGEN counter value.
356  ******************************************************************************/
357 unsigned long long stm32mp_stgen_get_counter(void)
358 {
359 	return (((unsigned long long)mmio_read_32(STGEN_BASE + CNTCVU_OFF) << 32) |
360 		mmio_read_32(STGEN_BASE + CNTCVL_OFF));
361 }
362 
363 /*******************************************************************************
364  * This function restores the STGEN counter value.
365  * It takes a first input value as a counter backup value to be restored and a
366  * offset in ms to be added.
367  ******************************************************************************/
368 void stm32mp_stgen_restore_counter(unsigned long long value,
369 				   unsigned long long offset_in_ms)
370 {
371 	unsigned long long cnt;
372 
373 	cnt = value + ((offset_in_ms *
374 			mmio_read_32(STGEN_BASE + CNTFID_OFF)) / 1000U);
375 
376 	mmio_clrbits_32(STGEN_BASE + CNTCR_OFF, CNTCR_EN);
377 	mmio_write_32(STGEN_BASE + CNTCVL_OFF, (uint32_t)cnt);
378 	mmio_write_32(STGEN_BASE + CNTCVU_OFF, (uint32_t)(cnt >> 32));
379 	mmio_setbits_32(STGEN_BASE + CNTCR_OFF, CNTCR_EN);
380 }
381