blob: e87ab1ba74501681af507b5cdc47ce55a5454da2 [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
Andre Przywara2d5690c2020-03-26 11:50:33 +0000154 return fdt_read_uint32_default(fdt, subnode, prop_name,
155 dflt_value);
Yann Gautier5f2e8742019-05-17 15:57:56 +0200156 }
157
158 return dflt_value;
159}
160
161/*
Yann Gautier4d429472019-02-14 11:15:20 +0100162 * Get the RCC node offset from the device tree
163 * @param fdt: Device tree reference
164 * @return: Node offset or a negative value on error
165 */
166int fdt_get_rcc_node(void *fdt)
167{
168 return fdt_node_offset_by_compatible(fdt, -1, DT_RCC_CLK_COMPAT);
169}
170
171/*
172 * Get the RCC base address from the device tree
173 * @return: RCC address or 0 on error
174 */
175uint32_t fdt_rcc_read_addr(void)
176{
177 int node;
178 void *fdt;
179 const fdt32_t *cuint;
180
181 if (fdt_get_address(&fdt) == 0) {
182 return 0;
183 }
184
185 node = fdt_get_rcc_node(fdt);
186 if (node < 0) {
187 return 0;
188 }
189
190 cuint = fdt_getprop(fdt, node, "reg", NULL);
191 if (cuint == NULL) {
192 return 0;
193 }
194
195 return fdt32_to_cpu(*cuint);
196}
197
198/*
199 * Read a series of parameters in rcc-clk section in device tree
200 * @param prop_name: Name of the RCC property to be read
201 * @param array: the array to store the property parameters
202 * @param count: number of parameters to be read
203 * @return: 0 on succes or a negative value on error
204 */
Andre Przywaracc99f3f2020-03-26 12:51:21 +0000205int fdt_rcc_read_uint32_array(const char *prop_name, uint32_t count,
206 uint32_t *array)
Yann Gautier4d429472019-02-14 11:15:20 +0100207{
208 int node;
209 void *fdt;
210
211 if (fdt_get_address(&fdt) == 0) {
212 return -ENOENT;
213 }
214
215 node = fdt_get_rcc_node(fdt);
216 if (node < 0) {
217 return -FDT_ERR_NOTFOUND;
218 }
219
Andre Przywaracc99f3f2020-03-26 12:51:21 +0000220 return fdt_read_uint32_array(fdt, node, prop_name, count, array);
Yann Gautier4d429472019-02-14 11:15:20 +0100221}
222
223/*
224 * Get the subnode offset in rcc-clk section from its name in device tree
225 * @param name: name of the RCC property
226 * @return: offset on success, and a negative FDT/ERRNO error code on failure.
227 */
228int fdt_rcc_subnode_offset(const char *name)
229{
230 int node, subnode;
231 void *fdt;
232
233 if (fdt_get_address(&fdt) == 0) {
234 return -ENOENT;
235 }
236
237 node = fdt_get_rcc_node(fdt);
238 if (node < 0) {
239 return -FDT_ERR_NOTFOUND;
240 }
241
242 subnode = fdt_subnode_offset(fdt, node, name);
243 if (subnode <= 0) {
244 return -FDT_ERR_NOTFOUND;
245 }
246
247 return subnode;
248}
249
250/*
251 * Get the pointer to a rcc-clk property from its name.
252 * @param name: name of the RCC property
253 * @param lenp: stores the length of the property.
254 * @return: pointer to the property on success, and NULL value on failure.
255 */
256const fdt32_t *fdt_rcc_read_prop(const char *prop_name, int *lenp)
257{
258 const fdt32_t *cuint;
259 int node, len;
260 void *fdt;
261
262 if (fdt_get_address(&fdt) == 0) {
263 return NULL;
264 }
265
266 node = fdt_get_rcc_node(fdt);
267 if (node < 0) {
268 return NULL;
269 }
270
271 cuint = fdt_getprop(fdt, node, prop_name, &len);
272 if (cuint == NULL) {
273 return NULL;
274 }
275
276 *lenp = len;
277 return cuint;
278}
279
280/*
281 * Get the secure status for rcc node in device tree.
282 * @return: true if rcc is available from secure world, false if not.
283 */
284bool fdt_get_rcc_secure_status(void)
285{
286 int node;
287 void *fdt;
288
289 if (fdt_get_address(&fdt) == 0) {
290 return false;
291 }
292
293 node = fdt_get_rcc_node(fdt);
294 if (node < 0) {
295 return false;
296 }
297
298 return !!(fdt_get_status(node) & DT_SECURE);
299}
300
301/*
302 * Get the stgen base address.
303 * @return: address of stgen on success, and NULL value on failure.
304 */
305uintptr_t fdt_get_stgen_base(void)
306{
307 int node;
308 const fdt32_t *cuint;
309 void *fdt;
310
311 if (fdt_get_address(&fdt) == 0) {
312 return 0;
313 }
314
315 node = fdt_node_offset_by_compatible(fdt, -1, DT_STGEN_COMPAT);
316 if (node < 0) {
317 return 0;
318 }
319
320 cuint = fdt_getprop(fdt, node, "reg", NULL);
321 if (cuint == NULL) {
322 return 0;
323 }
324
325 return fdt32_to_cpu(*cuint);
326}
327
328/*
329 * Get the clock ID of the given node in device tree.
330 * @param node: node offset
331 * @return: Clock ID on success, and a negative FDT/ERRNO error code on failure.
332 */
333int fdt_get_clock_id(int node)
334{
335 const fdt32_t *cuint;
336 void *fdt;
337
338 if (fdt_get_address(&fdt) == 0) {
339 return -ENOENT;
340 }
341
342 cuint = fdt_getprop(fdt, node, "clocks", NULL);
343 if (cuint == NULL) {
344 return -FDT_ERR_NOTFOUND;
345 }
346
347 cuint++;
348 return (int)fdt32_to_cpu(*cuint);
349}