blob: 6404d9933c5fe1e9ad90b8a7186f30e82679cc19 [file] [log] [blame]
Yann Gautier4d429472019-02-14 11:15:20 +01001/*
2 * Copyright (c) 2017-2019, STMicroelectronics - All Rights Reserved
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
7#include <errno.h>
8
9#include <libfdt.h>
10
11#include <platform_def.h>
12
Andre Przywaracc99f3f2020-03-26 12:51:21 +000013#include <common/fdt_wrappers.h>
Yann Gautier4d429472019-02-14 11:15:20 +010014#include <drivers/st/stm32_gpio.h>
15#include <drivers/st/stm32mp_clkfunc.h>
16
17#define DT_STGEN_COMPAT "st,stm32-stgen"
18
19/*
Yann Gautier5f2e8742019-05-17 15:57:56 +020020 * Get the frequency of an oscillator from its name in device tree.
21 * @param name: oscillator name
22 * @param freq: stores the frequency of the oscillator
23 * @return: 0 on success, and a negative FDT/ERRNO error code on failure.
24 */
25int fdt_osc_read_freq(const char *name, uint32_t *freq)
26{
27 int node, subnode;
28 void *fdt;
29
30 if (fdt_get_address(&fdt) == 0) {
31 return -ENOENT;
32 }
33
34 node = fdt_path_offset(fdt, "/clocks");
35 if (node < 0) {
36 return -FDT_ERR_NOTFOUND;
37 }
38
39 fdt_for_each_subnode(subnode, fdt, node) {
40 const char *cchar;
41 int ret;
42
43 cchar = fdt_get_name(fdt, subnode, &ret);
44 if (cchar == NULL) {
45 return ret;
46 }
47
48 if (strncmp(cchar, name, (size_t)ret) == 0) {
49 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.
70 * @param osc_id: oscillator ID
71 * @param prop_name: property name
72 * @return: true/false regarding search result.
73 */
74bool fdt_osc_read_bool(enum stm32mp_osc_id osc_id, const char *prop_name)
75{
76 int node, subnode;
77 void *fdt;
78
79 if (fdt_get_address(&fdt) == 0) {
80 return false;
81 }
82
83 if (osc_id >= NB_OSC) {
84 return false;
85 }
86
87 node = fdt_path_offset(fdt, "/clocks");
88 if (node < 0) {
89 return false;
90 }
91
92 fdt_for_each_subnode(subnode, fdt, node) {
93 const char *cchar;
94 int ret;
95
96 cchar = fdt_get_name(fdt, subnode, &ret);
97 if (cchar == NULL) {
98 return false;
99 }
100
101 if (strncmp(cchar, stm32mp_osc_node_label[osc_id],
102 (size_t)ret) != 0) {
103 continue;
104 }
105
106 if (fdt_getprop(fdt, subnode, prop_name, NULL) != NULL) {
107 return true;
108 }
109 }
110
111 return false;
112}
113
114/*
115 * Get the value of a oscillator property from its ID.
116 * @param osc_id: oscillator ID
117 * @param prop_name: property name
118 * @param dflt_value: default value
119 * @return oscillator value on success, default value if property not found.
120 */
121uint32_t fdt_osc_read_uint32_default(enum stm32mp_osc_id osc_id,
122 const char *prop_name, uint32_t dflt_value)
123{
124 int node, subnode;
125 void *fdt;
126
127 if (fdt_get_address(&fdt) == 0) {
128 return dflt_value;
129 }
130
131 if (osc_id >= NB_OSC) {
132 return dflt_value;
133 }
134
135 node = fdt_path_offset(fdt, "/clocks");
136 if (node < 0) {
137 return dflt_value;
138 }
139
140 fdt_for_each_subnode(subnode, fdt, node) {
141 const char *cchar;
142 int ret;
143
144 cchar = fdt_get_name(fdt, subnode, &ret);
145 if (cchar == NULL) {
146 return dflt_value;
147 }
148
149 if (strncmp(cchar, stm32mp_osc_node_label[osc_id],
150 (size_t)ret) != 0) {
151 continue;
152 }
153
154 return fdt_read_uint32_default(subnode, prop_name, dflt_value);
155 }
156
157 return dflt_value;
158}
159
160/*
Yann Gautier4d429472019-02-14 11:15:20 +0100161 * Get the RCC node offset from the device tree
162 * @param fdt: Device tree reference
163 * @return: Node offset or a negative value on error
164 */
165int fdt_get_rcc_node(void *fdt)
166{
167 return fdt_node_offset_by_compatible(fdt, -1, DT_RCC_CLK_COMPAT);
168}
169
170/*
171 * Get the RCC base address from the device tree
172 * @return: RCC address or 0 on error
173 */
174uint32_t fdt_rcc_read_addr(void)
175{
176 int node;
177 void *fdt;
178 const fdt32_t *cuint;
179
180 if (fdt_get_address(&fdt) == 0) {
181 return 0;
182 }
183
184 node = fdt_get_rcc_node(fdt);
185 if (node < 0) {
186 return 0;
187 }
188
189 cuint = fdt_getprop(fdt, node, "reg", NULL);
190 if (cuint == NULL) {
191 return 0;
192 }
193
194 return fdt32_to_cpu(*cuint);
195}
196
197/*
198 * Read a series of parameters in rcc-clk section in device tree
199 * @param prop_name: Name of the RCC property to be read
200 * @param array: the array to store the property parameters
201 * @param count: number of parameters to be read
202 * @return: 0 on succes or a negative value on error
203 */
Andre Przywaracc99f3f2020-03-26 12:51:21 +0000204int fdt_rcc_read_uint32_array(const char *prop_name, uint32_t count,
205 uint32_t *array)
Yann Gautier4d429472019-02-14 11:15:20 +0100206{
207 int node;
208 void *fdt;
209
210 if (fdt_get_address(&fdt) == 0) {
211 return -ENOENT;
212 }
213
214 node = fdt_get_rcc_node(fdt);
215 if (node < 0) {
216 return -FDT_ERR_NOTFOUND;
217 }
218
Andre Przywaracc99f3f2020-03-26 12:51:21 +0000219 return fdt_read_uint32_array(fdt, node, prop_name, count, array);
Yann Gautier4d429472019-02-14 11:15:20 +0100220}
221
222/*
223 * Get the subnode offset in rcc-clk section from its name in device tree
224 * @param name: name of the RCC property
225 * @return: offset on success, and a negative FDT/ERRNO error code on failure.
226 */
227int fdt_rcc_subnode_offset(const char *name)
228{
229 int node, subnode;
230 void *fdt;
231
232 if (fdt_get_address(&fdt) == 0) {
233 return -ENOENT;
234 }
235
236 node = fdt_get_rcc_node(fdt);
237 if (node < 0) {
238 return -FDT_ERR_NOTFOUND;
239 }
240
241 subnode = fdt_subnode_offset(fdt, node, name);
242 if (subnode <= 0) {
243 return -FDT_ERR_NOTFOUND;
244 }
245
246 return subnode;
247}
248
249/*
250 * Get the pointer to a rcc-clk property from its name.
251 * @param name: name of the RCC property
252 * @param lenp: stores the length of the property.
253 * @return: pointer to the property on success, and NULL value on failure.
254 */
255const fdt32_t *fdt_rcc_read_prop(const char *prop_name, int *lenp)
256{
257 const fdt32_t *cuint;
258 int node, len;
259 void *fdt;
260
261 if (fdt_get_address(&fdt) == 0) {
262 return NULL;
263 }
264
265 node = fdt_get_rcc_node(fdt);
266 if (node < 0) {
267 return NULL;
268 }
269
270 cuint = fdt_getprop(fdt, node, prop_name, &len);
271 if (cuint == NULL) {
272 return NULL;
273 }
274
275 *lenp = len;
276 return cuint;
277}
278
279/*
280 * Get the secure status for rcc node in device tree.
281 * @return: true if rcc is available from secure world, false if not.
282 */
283bool fdt_get_rcc_secure_status(void)
284{
285 int node;
286 void *fdt;
287
288 if (fdt_get_address(&fdt) == 0) {
289 return false;
290 }
291
292 node = fdt_get_rcc_node(fdt);
293 if (node < 0) {
294 return false;
295 }
296
297 return !!(fdt_get_status(node) & DT_SECURE);
298}
299
300/*
301 * Get the stgen base address.
302 * @return: address of stgen on success, and NULL value on failure.
303 */
304uintptr_t fdt_get_stgen_base(void)
305{
306 int node;
307 const fdt32_t *cuint;
308 void *fdt;
309
310 if (fdt_get_address(&fdt) == 0) {
311 return 0;
312 }
313
314 node = fdt_node_offset_by_compatible(fdt, -1, DT_STGEN_COMPAT);
315 if (node < 0) {
316 return 0;
317 }
318
319 cuint = fdt_getprop(fdt, node, "reg", NULL);
320 if (cuint == NULL) {
321 return 0;
322 }
323
324 return fdt32_to_cpu(*cuint);
325}
326
327/*
328 * Get the clock ID of the given node in device tree.
329 * @param node: node offset
330 * @return: Clock ID on success, and a negative FDT/ERRNO error code on failure.
331 */
332int fdt_get_clock_id(int node)
333{
334 const fdt32_t *cuint;
335 void *fdt;
336
337 if (fdt_get_address(&fdt) == 0) {
338 return -ENOENT;
339 }
340
341 cuint = fdt_getprop(fdt, node, "clocks", NULL);
342 if (cuint == NULL) {
343 return -FDT_ERR_NOTFOUND;
344 }
345
346 cuint++;
347 return (int)fdt32_to_cpu(*cuint);
348}