blob: 379547fd1148041ae67bd80ce92de5711944debe [file] [log] [blame]
Yann Gautier4d429472019-02-14 11:15:20 +01001/*
Yann Gautier18bef772019-12-06 09:38:43 +01002 * Copyright (c) 2017-2023, STMicroelectronics - All Rights Reserved
Yann Gautier4d429472019-02-14 11:15:20 +01003 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
7#include <errno.h>
8
Lionel Debievedeef9692019-12-04 21:50:19 +01009#include <arch_helpers.h>
Andre Przywaracc99f3f2020-03-26 12:51:21 +000010#include <common/fdt_wrappers.h>
Yann Gautiera205a5c2021-08-30 15:06:54 +020011#include <drivers/clk.h>
Lionel Debievedeef9692019-12-04 21:50:19 +010012#include <drivers/generic_delay_timer.h>
Yann Gautier4d429472019-02-14 11:15:20 +010013#include <drivers/st/stm32_gpio.h>
14#include <drivers/st/stm32mp_clkfunc.h>
Lionel Debievedeef9692019-12-04 21:50:19 +010015#include <lib/mmio.h>
Patrick Delaunay48519b32019-07-01 08:59:24 +020016#include <libfdt.h>
17
18#include <platform_def.h>
Yann Gautier4d429472019-02-14 11:15:20 +010019
Yann Gautier4d429472019-02-14 11:15:20 +010020/*
Yann Gautier5f2e8742019-05-17 15:57:56 +020021 * Get the frequency of an oscillator from its name in device tree.
22 * @param name: oscillator name
23 * @param freq: stores the frequency of the oscillator
24 * @return: 0 on success, and a negative FDT/ERRNO error code on failure.
25 */
26int fdt_osc_read_freq(const char *name, uint32_t *freq)
27{
28 int node, subnode;
29 void *fdt;
30
31 if (fdt_get_address(&fdt) == 0) {
32 return -ENOENT;
33 }
34
35 node = fdt_path_offset(fdt, "/clocks");
36 if (node < 0) {
37 return -FDT_ERR_NOTFOUND;
38 }
39
40 fdt_for_each_subnode(subnode, fdt, node) {
41 const char *cchar;
42 int ret;
43
44 cchar = fdt_get_name(fdt, subnode, &ret);
45 if (cchar == NULL) {
46 return ret;
47 }
48
Patrick Delaunay48519b32019-07-01 08:59:24 +020049 if ((strncmp(cchar, name, (size_t)ret) == 0) &&
50 (fdt_get_status(subnode) != DT_DISABLED)) {
Yann Gautier5f2e8742019-05-17 15:57:56 +020051 const fdt32_t *cuint;
52
53 cuint = fdt_getprop(fdt, subnode, "clock-frequency",
54 &ret);
55 if (cuint == NULL) {
56 return ret;
57 }
58
59 *freq = fdt32_to_cpu(*cuint);
60
61 return 0;
62 }
63 }
64
65 /* Oscillator not found, freq=0 */
66 *freq = 0;
67 return 0;
68}
69
70/*
71 * Check the presence of an oscillator property from its id.
Gabriel Fernandez5177ea22020-05-15 08:00:03 +020072 * @param node_label: clock node name
Yann Gautier5f2e8742019-05-17 15:57:56 +020073 * @param prop_name: property name
74 * @return: true/false regarding search result.
75 */
Gabriel Fernandez5177ea22020-05-15 08:00:03 +020076bool fdt_clk_read_bool(const char *node_label, const char *prop_name)
Yann Gautier5f2e8742019-05-17 15:57:56 +020077{
78 int node, subnode;
79 void *fdt;
80
81 if (fdt_get_address(&fdt) == 0) {
82 return false;
83 }
84
Yann Gautier5f2e8742019-05-17 15:57:56 +020085 node = fdt_path_offset(fdt, "/clocks");
86 if (node < 0) {
87 return false;
88 }
89
90 fdt_for_each_subnode(subnode, fdt, node) {
91 const char *cchar;
92 int ret;
93
94 cchar = fdt_get_name(fdt, subnode, &ret);
95 if (cchar == NULL) {
96 return false;
97 }
98
Gabriel Fernandez5177ea22020-05-15 08:00:03 +020099 if (strncmp(cchar, node_label, (size_t)ret) != 0) {
Yann Gautier5f2e8742019-05-17 15:57:56 +0200100 continue;
101 }
102
103 if (fdt_getprop(fdt, subnode, prop_name, NULL) != NULL) {
104 return true;
105 }
106 }
107
108 return false;
109}
110
111/*
Gabriel Fernandez5177ea22020-05-15 08:00:03 +0200112 * Get the value of a oscillator property from its name.
113 * @param node_label: oscillator name
Yann Gautier5f2e8742019-05-17 15:57:56 +0200114 * @param prop_name: property name
115 * @param dflt_value: default value
116 * @return oscillator value on success, default value if property not found.
117 */
Gabriel Fernandez5177ea22020-05-15 08:00:03 +0200118uint32_t fdt_clk_read_uint32_default(const char *node_label,
Yann Gautier5f2e8742019-05-17 15:57:56 +0200119 const char *prop_name, uint32_t dflt_value)
120{
121 int node, subnode;
122 void *fdt;
123
124 if (fdt_get_address(&fdt) == 0) {
125 return dflt_value;
126 }
127
Yann Gautier5f2e8742019-05-17 15:57:56 +0200128 node = fdt_path_offset(fdt, "/clocks");
129 if (node < 0) {
130 return dflt_value;
131 }
132
133 fdt_for_each_subnode(subnode, fdt, node) {
134 const char *cchar;
135 int ret;
136
137 cchar = fdt_get_name(fdt, subnode, &ret);
138 if (cchar == NULL) {
139 return dflt_value;
140 }
141
Gabriel Fernandez5177ea22020-05-15 08:00:03 +0200142 if (strncmp(cchar, node_label, (size_t)ret) != 0) {
Yann Gautier5f2e8742019-05-17 15:57:56 +0200143 continue;
144 }
145
Andre Przywara2d5690c2020-03-26 11:50:33 +0000146 return fdt_read_uint32_default(fdt, subnode, prop_name,
147 dflt_value);
Yann Gautier5f2e8742019-05-17 15:57:56 +0200148 }
149
150 return dflt_value;
151}
152
153/*
Yann Gautier4d429472019-02-14 11:15:20 +0100154 * Get the RCC node offset from the device tree
155 * @param fdt: Device tree reference
156 * @return: Node offset or a negative value on error
157 */
Patrick Delaunay286d81e2020-10-06 14:32:26 +0200158static int fdt_get_rcc_node(void *fdt)
Yann Gautier4d429472019-02-14 11:15:20 +0100159{
Yann Gautiereaab37d2020-10-22 15:37:22 +0200160 static int node;
161
162 if (node <= 0) {
163 node = fdt_node_offset_by_compatible(fdt, -1, DT_RCC_CLK_COMPAT);
164 }
165
166 return node;
Yann Gautier4d429472019-02-14 11:15:20 +0100167}
168
169/*
Yann Gautier4d429472019-02-14 11:15:20 +0100170 * Read a series of parameters in rcc-clk section in device tree
171 * @param prop_name: Name of the RCC property to be read
172 * @param array: the array to store the property parameters
173 * @param count: number of parameters to be read
174 * @return: 0 on succes or a negative value on error
175 */
Andre Przywaracc99f3f2020-03-26 12:51:21 +0000176int fdt_rcc_read_uint32_array(const char *prop_name, uint32_t count,
177 uint32_t *array)
Yann Gautier4d429472019-02-14 11:15:20 +0100178{
179 int node;
180 void *fdt;
181
182 if (fdt_get_address(&fdt) == 0) {
183 return -ENOENT;
184 }
185
186 node = fdt_get_rcc_node(fdt);
187 if (node < 0) {
188 return -FDT_ERR_NOTFOUND;
189 }
190
Andre Przywaracc99f3f2020-03-26 12:51:21 +0000191 return fdt_read_uint32_array(fdt, node, prop_name, count, array);
Yann Gautier4d429472019-02-14 11:15:20 +0100192}
193
194/*
195 * Get the subnode offset in rcc-clk section from its name in device tree
196 * @param name: name of the RCC property
197 * @return: offset on success, and a negative FDT/ERRNO error code on failure.
198 */
199int fdt_rcc_subnode_offset(const char *name)
200{
201 int node, subnode;
202 void *fdt;
203
204 if (fdt_get_address(&fdt) == 0) {
205 return -ENOENT;
206 }
207
208 node = fdt_get_rcc_node(fdt);
209 if (node < 0) {
210 return -FDT_ERR_NOTFOUND;
211 }
212
213 subnode = fdt_subnode_offset(fdt, node, name);
214 if (subnode <= 0) {
215 return -FDT_ERR_NOTFOUND;
216 }
217
218 return subnode;
219}
220
221/*
222 * Get the pointer to a rcc-clk property from its name.
223 * @param name: name of the RCC property
224 * @param lenp: stores the length of the property.
225 * @return: pointer to the property on success, and NULL value on failure.
226 */
227const fdt32_t *fdt_rcc_read_prop(const char *prop_name, int *lenp)
228{
229 const fdt32_t *cuint;
230 int node, len;
231 void *fdt;
232
233 if (fdt_get_address(&fdt) == 0) {
234 return NULL;
235 }
236
237 node = fdt_get_rcc_node(fdt);
238 if (node < 0) {
239 return NULL;
240 }
241
242 cuint = fdt_getprop(fdt, node, prop_name, &len);
243 if (cuint == NULL) {
244 return NULL;
245 }
246
247 *lenp = len;
248 return cuint;
249}
250
Yann Gautier3005c432023-06-13 18:44:51 +0200251#if defined(IMAGE_BL32)
Yann Gautier4d429472019-02-14 11:15:20 +0100252/*
Lionel Debieve3c0fbfe2020-12-15 10:35:59 +0100253 * Get the secure state for rcc node in device tree.
254 * @return: true if rcc is configured for secure world access, false if not.
Yann Gautier4d429472019-02-14 11:15:20 +0100255 */
Lionel Debieve3c0fbfe2020-12-15 10:35:59 +0100256bool fdt_get_rcc_secure_state(void)
Yann Gautier4d429472019-02-14 11:15:20 +0100257{
Yann Gautier4d429472019-02-14 11:15:20 +0100258 void *fdt;
259
260 if (fdt_get_address(&fdt) == 0) {
261 return false;
262 }
263
Lionel Debieve3c0fbfe2020-12-15 10:35:59 +0100264 if (fdt_node_offset_by_compatible(fdt, -1, DT_RCC_SEC_CLK_COMPAT) < 0) {
Yann Gautier4d429472019-02-14 11:15:20 +0100265 return false;
266 }
267
Lionel Debieve3c0fbfe2020-12-15 10:35:59 +0100268 return true;
Yann Gautier4d429472019-02-14 11:15:20 +0100269}
Yann Gautier3005c432023-06-13 18:44:51 +0200270#endif
Yann Gautier4d429472019-02-14 11:15:20 +0100271
272/*
Yann Gautier4d429472019-02-14 11:15:20 +0100273 * Get the clock ID of the given node in device tree.
274 * @param node: node offset
275 * @return: Clock ID on success, and a negative FDT/ERRNO error code on failure.
276 */
277int fdt_get_clock_id(int node)
278{
279 const fdt32_t *cuint;
280 void *fdt;
281
282 if (fdt_get_address(&fdt) == 0) {
283 return -ENOENT;
284 }
285
286 cuint = fdt_getprop(fdt, node, "clocks", NULL);
287 if (cuint == NULL) {
288 return -FDT_ERR_NOTFOUND;
289 }
290
291 cuint++;
292 return (int)fdt32_to_cpu(*cuint);
293}
Nicolas Le Bayondc08ebe2019-09-11 11:46:40 +0200294
295/*
296 * Get the frequency of the specified UART instance.
297 * @param instance: UART interface registers base address.
298 * @return: clock frequency on success, 0 value on failure.
299 */
300unsigned long fdt_get_uart_clock_freq(uintptr_t instance)
301{
302 void *fdt;
303 int node;
304 int clk_id;
305
306 if (fdt_get_address(&fdt) == 0) {
307 return 0UL;
308 }
309
310 /* Check for UART nodes */
311 node = dt_match_instance_by_compatible(DT_UART_COMPAT, instance);
312 if (node < 0) {
313 return 0UL;
314 }
315
316 clk_id = fdt_get_clock_id(node);
317 if (clk_id < 0) {
318 return 0UL;
319 }
320
Yann Gautiera205a5c2021-08-30 15:06:54 +0200321 return clk_get_rate((unsigned long)clk_id);
Nicolas Le Bayondc08ebe2019-09-11 11:46:40 +0200322}
Lionel Debievedeef9692019-12-04 21:50:19 +0100323
324/*******************************************************************************
Yann Gautier18bef772019-12-06 09:38:43 +0100325 * This function sets the STGEN counter value.
326 ******************************************************************************/
327static void stgen_set_counter(unsigned long long counter)
328{
329#ifdef __aarch64__
330 mmio_write_64(STGEN_BASE + CNTCV_OFF, counter);
331#else
332 mmio_write_32(STGEN_BASE + CNTCVL_OFF, (uint32_t)counter);
333 mmio_write_32(STGEN_BASE + CNTCVU_OFF, (uint32_t)(counter >> 32));
334#endif
335}
336
337/*******************************************************************************
Lionel Debievedeef9692019-12-04 21:50:19 +0100338 * This function configures and restores the STGEN counter depending on the
339 * connected clock.
340 ******************************************************************************/
341void stm32mp_stgen_config(unsigned long rate)
342{
343 uint32_t cntfid0;
344 unsigned long long counter;
345
346 cntfid0 = mmio_read_32(STGEN_BASE + CNTFID_OFF);
347
348 if (cntfid0 == rate) {
349 return;
350 }
351
352 mmio_clrbits_32(STGEN_BASE + CNTCR_OFF, CNTCR_EN);
353 counter = stm32mp_stgen_get_counter() * rate / cntfid0;
354
Yann Gautier18bef772019-12-06 09:38:43 +0100355 stgen_set_counter(counter);
Lionel Debievedeef9692019-12-04 21:50:19 +0100356 mmio_write_32(STGEN_BASE + CNTFID_OFF, rate);
357 mmio_setbits_32(STGEN_BASE + CNTCR_OFF, CNTCR_EN);
358
359 write_cntfrq_el0(rate);
360
361 /* Need to update timer with new frequency */
362 generic_delay_timer_init();
363}
364
365/*******************************************************************************
366 * This function returns the STGEN counter value.
367 ******************************************************************************/
368unsigned long long stm32mp_stgen_get_counter(void)
369{
Yann Gautier18bef772019-12-06 09:38:43 +0100370#ifdef __aarch64__
371 return mmio_read_64(STGEN_BASE + CNTCV_OFF);
372#else
Lionel Debievedeef9692019-12-04 21:50:19 +0100373 return (((unsigned long long)mmio_read_32(STGEN_BASE + CNTCVU_OFF) << 32) |
374 mmio_read_32(STGEN_BASE + CNTCVL_OFF));
Yann Gautier18bef772019-12-06 09:38:43 +0100375#endif
Lionel Debievedeef9692019-12-04 21:50:19 +0100376}
377
378/*******************************************************************************
379 * This function restores the STGEN counter value.
380 * It takes a first input value as a counter backup value to be restored and a
381 * offset in ms to be added.
382 ******************************************************************************/
383void stm32mp_stgen_restore_counter(unsigned long long value,
384 unsigned long long offset_in_ms)
385{
386 unsigned long long cnt;
387
388 cnt = value + ((offset_in_ms *
389 mmio_read_32(STGEN_BASE + CNTFID_OFF)) / 1000U);
390
391 mmio_clrbits_32(STGEN_BASE + CNTCR_OFF, CNTCR_EN);
Yann Gautier18bef772019-12-06 09:38:43 +0100392 stgen_set_counter(cnt);
Lionel Debievedeef9692019-12-04 21:50:19 +0100393 mmio_setbits_32(STGEN_BASE + CNTCR_OFF, CNTCR_EN);
394}