blob: d57f120b91ec4ae1fd414a979bdc5462033c0220 [file] [log] [blame]
Yann Gautier4d429472019-02-14 11:15:20 +01001/*
Yann Gautiereaab37d2020-10-22 15:37:22 +02002 * Copyright (c) 2017-2021, 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
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
Yann Gautier4d429472019-02-14 11:15:20 +010017/*
Yann Gautier5f2e8742019-05-17 15:57:56 +020018 * Get the frequency of an oscillator from its name in device tree.
19 * @param name: oscillator name
20 * @param freq: stores the frequency of the oscillator
21 * @return: 0 on success, and a negative FDT/ERRNO error code on failure.
22 */
23int fdt_osc_read_freq(const char *name, uint32_t *freq)
24{
25 int node, subnode;
26 void *fdt;
27
28 if (fdt_get_address(&fdt) == 0) {
29 return -ENOENT;
30 }
31
32 node = fdt_path_offset(fdt, "/clocks");
33 if (node < 0) {
34 return -FDT_ERR_NOTFOUND;
35 }
36
37 fdt_for_each_subnode(subnode, fdt, node) {
38 const char *cchar;
39 int ret;
40
41 cchar = fdt_get_name(fdt, subnode, &ret);
42 if (cchar == NULL) {
43 return ret;
44 }
45
46 if (strncmp(cchar, name, (size_t)ret) == 0) {
47 const fdt32_t *cuint;
48
49 cuint = fdt_getprop(fdt, subnode, "clock-frequency",
50 &ret);
51 if (cuint == NULL) {
52 return ret;
53 }
54
55 *freq = fdt32_to_cpu(*cuint);
56
57 return 0;
58 }
59 }
60
61 /* Oscillator not found, freq=0 */
62 *freq = 0;
63 return 0;
64}
65
66/*
67 * Check the presence of an oscillator property from its id.
68 * @param osc_id: oscillator ID
69 * @param prop_name: property name
70 * @return: true/false regarding search result.
71 */
72bool fdt_osc_read_bool(enum stm32mp_osc_id osc_id, const char *prop_name)
73{
74 int node, subnode;
75 void *fdt;
76
77 if (fdt_get_address(&fdt) == 0) {
78 return false;
79 }
80
81 if (osc_id >= NB_OSC) {
82 return false;
83 }
84
85 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
99 if (strncmp(cchar, stm32mp_osc_node_label[osc_id],
100 (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 ID.
114 * @param osc_id: oscillator ID
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 */
119uint32_t fdt_osc_read_uint32_default(enum stm32mp_osc_id osc_id,
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 if (osc_id >= NB_OSC) {
130 return dflt_value;
131 }
132
133 node = fdt_path_offset(fdt, "/clocks");
134 if (node < 0) {
135 return dflt_value;
136 }
137
138 fdt_for_each_subnode(subnode, fdt, node) {
139 const char *cchar;
140 int ret;
141
142 cchar = fdt_get_name(fdt, subnode, &ret);
143 if (cchar == NULL) {
144 return dflt_value;
145 }
146
147 if (strncmp(cchar, stm32mp_osc_node_label[osc_id],
148 (size_t)ret) != 0) {
149 continue;
150 }
151
Andre Przywara2d5690c2020-03-26 11:50:33 +0000152 return fdt_read_uint32_default(fdt, subnode, prop_name,
153 dflt_value);
Yann Gautier5f2e8742019-05-17 15:57:56 +0200154 }
155
156 return dflt_value;
157}
158
159/*
Yann Gautier4d429472019-02-14 11:15:20 +0100160 * Get the RCC node offset from the device tree
161 * @param fdt: Device tree reference
162 * @return: Node offset or a negative value on error
163 */
Patrick Delaunay286d81e2020-10-06 14:32:26 +0200164static int fdt_get_rcc_node(void *fdt)
Yann Gautier4d429472019-02-14 11:15:20 +0100165{
Yann Gautiereaab37d2020-10-22 15:37:22 +0200166 static int node;
167
168 if (node <= 0) {
169 node = fdt_node_offset_by_compatible(fdt, -1, DT_RCC_CLK_COMPAT);
170 }
171
172 return node;
Yann Gautier4d429472019-02-14 11:15:20 +0100173}
174
175/*
Yann Gautier4d429472019-02-14 11:15:20 +0100176 * Read a series of parameters in rcc-clk section in device tree
177 * @param prop_name: Name of the RCC property to be read
178 * @param array: the array to store the property parameters
179 * @param count: number of parameters to be read
180 * @return: 0 on succes or a negative value on error
181 */
Andre Przywaracc99f3f2020-03-26 12:51:21 +0000182int fdt_rcc_read_uint32_array(const char *prop_name, uint32_t count,
183 uint32_t *array)
Yann Gautier4d429472019-02-14 11:15:20 +0100184{
185 int node;
186 void *fdt;
187
188 if (fdt_get_address(&fdt) == 0) {
189 return -ENOENT;
190 }
191
192 node = fdt_get_rcc_node(fdt);
193 if (node < 0) {
194 return -FDT_ERR_NOTFOUND;
195 }
196
Andre Przywaracc99f3f2020-03-26 12:51:21 +0000197 return fdt_read_uint32_array(fdt, node, prop_name, count, array);
Yann Gautier4d429472019-02-14 11:15:20 +0100198}
199
200/*
201 * Get the subnode offset in rcc-clk section from its name in device tree
202 * @param name: name of the RCC property
203 * @return: offset on success, and a negative FDT/ERRNO error code on failure.
204 */
205int fdt_rcc_subnode_offset(const char *name)
206{
207 int node, subnode;
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
219 subnode = fdt_subnode_offset(fdt, node, name);
220 if (subnode <= 0) {
221 return -FDT_ERR_NOTFOUND;
222 }
223
224 return subnode;
225}
226
227/*
228 * Get the pointer to a rcc-clk property from its name.
229 * @param name: name of the RCC property
230 * @param lenp: stores the length of the property.
231 * @return: pointer to the property on success, and NULL value on failure.
232 */
233const fdt32_t *fdt_rcc_read_prop(const char *prop_name, int *lenp)
234{
235 const fdt32_t *cuint;
236 int node, len;
237 void *fdt;
238
239 if (fdt_get_address(&fdt) == 0) {
240 return NULL;
241 }
242
243 node = fdt_get_rcc_node(fdt);
244 if (node < 0) {
245 return NULL;
246 }
247
248 cuint = fdt_getprop(fdt, node, prop_name, &len);
249 if (cuint == NULL) {
250 return NULL;
251 }
252
253 *lenp = len;
254 return cuint;
255}
256
257/*
258 * Get the secure status for rcc node in device tree.
259 * @return: true if rcc is available from secure world, false if not.
260 */
261bool fdt_get_rcc_secure_status(void)
262{
263 int node;
264 void *fdt;
265
266 if (fdt_get_address(&fdt) == 0) {
267 return false;
268 }
269
270 node = fdt_get_rcc_node(fdt);
271 if (node < 0) {
272 return false;
273 }
274
275 return !!(fdt_get_status(node) & DT_SECURE);
276}
277
278/*
Yann Gautier4d429472019-02-14 11:15:20 +0100279 * Get the clock ID of the given node in device tree.
280 * @param node: node offset
281 * @return: Clock ID on success, and a negative FDT/ERRNO error code on failure.
282 */
283int fdt_get_clock_id(int node)
284{
285 const fdt32_t *cuint;
286 void *fdt;
287
288 if (fdt_get_address(&fdt) == 0) {
289 return -ENOENT;
290 }
291
292 cuint = fdt_getprop(fdt, node, "clocks", NULL);
293 if (cuint == NULL) {
294 return -FDT_ERR_NOTFOUND;
295 }
296
297 cuint++;
298 return (int)fdt32_to_cpu(*cuint);
299}