blob: 5ba64fd4e6a656d67faf09c902681a88625761ab [file] [log] [blame]
Yann Gautier4d429472019-02-14 11:15:20 +01001/*
Patrick Delaunay48519b32019-07-01 08:59:24 +02002 * Copyright (c) 2017-2022, 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
Andre Przywaracc99f3f2020-03-26 12:51:21 +00009#include <common/fdt_wrappers.h>
Yann Gautiera205a5c2021-08-30 15:06:54 +020010#include <drivers/clk.h>
Yann Gautier4d429472019-02-14 11:15:20 +010011#include <drivers/st/stm32_gpio.h>
12#include <drivers/st/stm32mp_clkfunc.h>
Patrick Delaunay48519b32019-07-01 08:59:24 +020013#include <libfdt.h>
14
15#include <platform_def.h>
Yann Gautier4d429472019-02-14 11:15:20 +010016
Nicolas Le Bayondc08ebe2019-09-11 11:46:40 +020017#define DT_UART_COMPAT "st,stm32h7-uart"
Yann Gautier4d429472019-02-14 11:15:20 +010018/*
Yann Gautier5f2e8742019-05-17 15:57:56 +020019 * Get the frequency of an oscillator from its name in device tree.
20 * @param name: oscillator name
21 * @param freq: stores the frequency of the oscillator
22 * @return: 0 on success, and a negative FDT/ERRNO error code on failure.
23 */
24int fdt_osc_read_freq(const char *name, uint32_t *freq)
25{
26 int node, subnode;
27 void *fdt;
28
29 if (fdt_get_address(&fdt) == 0) {
30 return -ENOENT;
31 }
32
33 node = fdt_path_offset(fdt, "/clocks");
34 if (node < 0) {
35 return -FDT_ERR_NOTFOUND;
36 }
37
38 fdt_for_each_subnode(subnode, fdt, node) {
39 const char *cchar;
40 int ret;
41
42 cchar = fdt_get_name(fdt, subnode, &ret);
43 if (cchar == NULL) {
44 return ret;
45 }
46
Patrick Delaunay48519b32019-07-01 08:59:24 +020047 if ((strncmp(cchar, name, (size_t)ret) == 0) &&
48 (fdt_get_status(subnode) != DT_DISABLED)) {
Yann Gautier5f2e8742019-05-17 15:57:56 +020049 const fdt32_t *cuint;
50
51 cuint = fdt_getprop(fdt, subnode, "clock-frequency",
52 &ret);
53 if (cuint == NULL) {
54 return ret;
55 }
56
57 *freq = fdt32_to_cpu(*cuint);
58
59 return 0;
60 }
61 }
62
63 /* Oscillator not found, freq=0 */
64 *freq = 0;
65 return 0;
66}
67
68/*
69 * Check the presence of an oscillator property from its id.
Gabriel Fernandez5177ea22020-05-15 08:00:03 +020070 * @param node_label: clock node name
Yann Gautier5f2e8742019-05-17 15:57:56 +020071 * @param prop_name: property name
72 * @return: true/false regarding search result.
73 */
Gabriel Fernandez5177ea22020-05-15 08:00:03 +020074bool fdt_clk_read_bool(const char *node_label, const char *prop_name)
Yann Gautier5f2e8742019-05-17 15:57:56 +020075{
76 int node, subnode;
77 void *fdt;
78
79 if (fdt_get_address(&fdt) == 0) {
80 return false;
81 }
82
Yann Gautier5f2e8742019-05-17 15:57:56 +020083 node = fdt_path_offset(fdt, "/clocks");
84 if (node < 0) {
85 return false;
86 }
87
88 fdt_for_each_subnode(subnode, fdt, node) {
89 const char *cchar;
90 int ret;
91
92 cchar = fdt_get_name(fdt, subnode, &ret);
93 if (cchar == NULL) {
94 return false;
95 }
96
Gabriel Fernandez5177ea22020-05-15 08:00:03 +020097 if (strncmp(cchar, node_label, (size_t)ret) != 0) {
Yann Gautier5f2e8742019-05-17 15:57:56 +020098 continue;
99 }
100
101 if (fdt_getprop(fdt, subnode, prop_name, NULL) != NULL) {
102 return true;
103 }
104 }
105
106 return false;
107}
108
109/*
Gabriel Fernandez5177ea22020-05-15 08:00:03 +0200110 * Get the value of a oscillator property from its name.
111 * @param node_label: oscillator name
Yann Gautier5f2e8742019-05-17 15:57:56 +0200112 * @param prop_name: property name
113 * @param dflt_value: default value
114 * @return oscillator value on success, default value if property not found.
115 */
Gabriel Fernandez5177ea22020-05-15 08:00:03 +0200116uint32_t fdt_clk_read_uint32_default(const char *node_label,
Yann Gautier5f2e8742019-05-17 15:57:56 +0200117 const char *prop_name, uint32_t dflt_value)
118{
119 int node, subnode;
120 void *fdt;
121
122 if (fdt_get_address(&fdt) == 0) {
123 return dflt_value;
124 }
125
Yann Gautier5f2e8742019-05-17 15:57:56 +0200126 node = fdt_path_offset(fdt, "/clocks");
127 if (node < 0) {
128 return dflt_value;
129 }
130
131 fdt_for_each_subnode(subnode, fdt, node) {
132 const char *cchar;
133 int ret;
134
135 cchar = fdt_get_name(fdt, subnode, &ret);
136 if (cchar == NULL) {
137 return dflt_value;
138 }
139
Gabriel Fernandez5177ea22020-05-15 08:00:03 +0200140 if (strncmp(cchar, node_label, (size_t)ret) != 0) {
Yann Gautier5f2e8742019-05-17 15:57:56 +0200141 continue;
142 }
143
Andre Przywara2d5690c2020-03-26 11:50:33 +0000144 return fdt_read_uint32_default(fdt, subnode, prop_name,
145 dflt_value);
Yann Gautier5f2e8742019-05-17 15:57:56 +0200146 }
147
148 return dflt_value;
149}
150
151/*
Yann Gautier4d429472019-02-14 11:15:20 +0100152 * Get the RCC node offset from the device tree
153 * @param fdt: Device tree reference
154 * @return: Node offset or a negative value on error
155 */
Patrick Delaunay286d81e2020-10-06 14:32:26 +0200156static int fdt_get_rcc_node(void *fdt)
Yann Gautier4d429472019-02-14 11:15:20 +0100157{
Yann Gautiereaab37d2020-10-22 15:37:22 +0200158 static int node;
159
160 if (node <= 0) {
161 node = fdt_node_offset_by_compatible(fdt, -1, DT_RCC_CLK_COMPAT);
162 }
163
164 return node;
Yann Gautier4d429472019-02-14 11:15:20 +0100165}
166
167/*
Yann Gautier4d429472019-02-14 11:15:20 +0100168 * Read a series of parameters in rcc-clk section in device tree
169 * @param prop_name: Name of the RCC property to be read
170 * @param array: the array to store the property parameters
171 * @param count: number of parameters to be read
172 * @return: 0 on succes or a negative value on error
173 */
Andre Przywaracc99f3f2020-03-26 12:51:21 +0000174int fdt_rcc_read_uint32_array(const char *prop_name, uint32_t count,
175 uint32_t *array)
Yann Gautier4d429472019-02-14 11:15:20 +0100176{
177 int node;
178 void *fdt;
179
180 if (fdt_get_address(&fdt) == 0) {
181 return -ENOENT;
182 }
183
184 node = fdt_get_rcc_node(fdt);
185 if (node < 0) {
186 return -FDT_ERR_NOTFOUND;
187 }
188
Andre Przywaracc99f3f2020-03-26 12:51:21 +0000189 return fdt_read_uint32_array(fdt, node, prop_name, count, array);
Yann Gautier4d429472019-02-14 11:15:20 +0100190}
191
192/*
193 * Get the subnode offset in rcc-clk section from its name in device tree
194 * @param name: name of the RCC property
195 * @return: offset on success, and a negative FDT/ERRNO error code on failure.
196 */
197int fdt_rcc_subnode_offset(const char *name)
198{
199 int node, subnode;
200 void *fdt;
201
202 if (fdt_get_address(&fdt) == 0) {
203 return -ENOENT;
204 }
205
206 node = fdt_get_rcc_node(fdt);
207 if (node < 0) {
208 return -FDT_ERR_NOTFOUND;
209 }
210
211 subnode = fdt_subnode_offset(fdt, node, name);
212 if (subnode <= 0) {
213 return -FDT_ERR_NOTFOUND;
214 }
215
216 return subnode;
217}
218
219/*
220 * Get the pointer to a rcc-clk property from its name.
221 * @param name: name of the RCC property
222 * @param lenp: stores the length of the property.
223 * @return: pointer to the property on success, and NULL value on failure.
224 */
225const fdt32_t *fdt_rcc_read_prop(const char *prop_name, int *lenp)
226{
227 const fdt32_t *cuint;
228 int node, len;
229 void *fdt;
230
231 if (fdt_get_address(&fdt) == 0) {
232 return NULL;
233 }
234
235 node = fdt_get_rcc_node(fdt);
236 if (node < 0) {
237 return NULL;
238 }
239
240 cuint = fdt_getprop(fdt, node, prop_name, &len);
241 if (cuint == NULL) {
242 return NULL;
243 }
244
245 *lenp = len;
246 return cuint;
247}
248
249/*
250 * Get the secure status for rcc node in device tree.
251 * @return: true if rcc is available from secure world, false if not.
252 */
253bool fdt_get_rcc_secure_status(void)
254{
255 int node;
256 void *fdt;
257
258 if (fdt_get_address(&fdt) == 0) {
259 return false;
260 }
261
262 node = fdt_get_rcc_node(fdt);
263 if (node < 0) {
264 return false;
265 }
266
267 return !!(fdt_get_status(node) & DT_SECURE);
268}
269
270/*
Yann Gautier4d429472019-02-14 11:15:20 +0100271 * Get the clock ID of the given node in device tree.
272 * @param node: node offset
273 * @return: Clock ID on success, and a negative FDT/ERRNO error code on failure.
274 */
275int fdt_get_clock_id(int node)
276{
277 const fdt32_t *cuint;
278 void *fdt;
279
280 if (fdt_get_address(&fdt) == 0) {
281 return -ENOENT;
282 }
283
284 cuint = fdt_getprop(fdt, node, "clocks", NULL);
285 if (cuint == NULL) {
286 return -FDT_ERR_NOTFOUND;
287 }
288
289 cuint++;
290 return (int)fdt32_to_cpu(*cuint);
291}
Nicolas Le Bayondc08ebe2019-09-11 11:46:40 +0200292
293/*
294 * Get the frequency of the specified UART instance.
295 * @param instance: UART interface registers base address.
296 * @return: clock frequency on success, 0 value on failure.
297 */
298unsigned long fdt_get_uart_clock_freq(uintptr_t instance)
299{
300 void *fdt;
301 int node;
302 int clk_id;
303
304 if (fdt_get_address(&fdt) == 0) {
305 return 0UL;
306 }
307
308 /* Check for UART nodes */
309 node = dt_match_instance_by_compatible(DT_UART_COMPAT, instance);
310 if (node < 0) {
311 return 0UL;
312 }
313
314 clk_id = fdt_get_clock_id(node);
315 if (clk_id < 0) {
316 return 0UL;
317 }
318
Yann Gautiera205a5c2021-08-30 15:06:54 +0200319 return clk_get_rate((unsigned long)clk_id);
Nicolas Le Bayondc08ebe2019-09-11 11:46:40 +0200320}