blob: d4c69cb4ec7b5be2b741673b6cbeb7b29a206b37 [file] [log] [blame]
Yann Gautier9aea69e2018-07-24 17:13:36 +02001/*
2 * Copyright (c) 2017-2018, STMicroelectronics - All Rights Reserved
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
7#include <dt-bindings/clock/stm32mp1-clksrc.h>
8#include <errno.h>
9#include <libfdt.h>
10#include <stm32mp1_clk.h>
11#include <stm32mp1_clkfunc.h>
12#include <stm32mp1_dt.h>
13
14#define DT_RCC_NODE_NAME "rcc@50000000"
15#define DT_RCC_CLK_COMPAT "st,stm32mp1-rcc"
16#define DT_RCC_COMPAT "syscon"
17#define DT_STGEN_COMPAT "st,stm32-stgen"
18#define DT_UART_COMPAT "st,stm32h7-uart"
19#define DT_USART_COMPAT "st,stm32h7-usart"
20
21const char *stm32mp_osc_node_label[NB_OSC] = {
22 [_LSI] = "clk-lsi",
23 [_LSE] = "clk-lse",
24 [_HSI] = "clk-hsi",
25 [_HSE] = "clk-hse",
26 [_CSI] = "clk-csi",
27 [_I2S_CKIN] = "i2s_ckin",
28 [_USB_PHY_48] = "ck_usbo_48m"
29};
30
31/*******************************************************************************
32 * This function reads the frequency of an oscillator from its name.
33 * It reads the value indicated inside the device tree.
34 * Returns 0 if success, and a negative value else.
35 * If success, value is stored in the second parameter.
36 ******************************************************************************/
37int fdt_osc_read_freq(const char *name, uint32_t *freq)
38{
39 int node, subnode;
40 void *fdt;
41
42 if (fdt_get_address(&fdt) == 0) {
43 return -ENOENT;
44 }
45
46 node = fdt_path_offset(fdt, "/clocks");
47 if (node < 0) {
48 return -FDT_ERR_NOTFOUND;
49 }
50
51 fdt_for_each_subnode(subnode, fdt, node) {
52 const char *cchar;
53 int ret;
54
55 cchar = fdt_get_name(fdt, subnode, &ret);
56 if (cchar == NULL) {
57 return ret;
58 }
59
60 if (strncmp(cchar, name, (size_t)ret) == 0) {
61 const fdt32_t *cuint;
62
63 cuint = fdt_getprop(fdt, subnode, "clock-frequency",
64 &ret);
65 if (cuint == NULL) {
66 return ret;
67 }
68
69 *freq = fdt32_to_cpu(*cuint);
70
71 return 0;
72 }
73 }
74
75 /* Oscillator not found, freq=0 */
76 *freq = 0;
77 return 0;
78}
79
80/*******************************************************************************
81 * This function checks the presence of an oscillator property from its id.
82 * The search is done inside the device tree.
83 * Returns true/false regarding search result.
84 ******************************************************************************/
85bool fdt_osc_read_bool(enum stm32mp_osc_id osc_id, const char *prop_name)
86{
87 int node, subnode;
88 void *fdt;
89
90 if (fdt_get_address(&fdt) == 0) {
91 return false;
92 }
93
94 if (osc_id >= NB_OSC) {
95 return false;
96 }
97
98 node = fdt_path_offset(fdt, "/clocks");
99 if (node < 0) {
100 return false;
101 }
102
103 fdt_for_each_subnode(subnode, fdt, node) {
104 const char *cchar;
105 int ret;
106
107 cchar = fdt_get_name(fdt, subnode, &ret);
108 if (cchar == NULL) {
109 return false;
110 }
111
112 if (strncmp(cchar, stm32mp_osc_node_label[osc_id],
113 (size_t)ret) != 0) {
114 continue;
115 }
116
117 if (fdt_getprop(fdt, subnode, prop_name, NULL) != NULL) {
118 return true;
119 }
120 }
121
122 return false;
123}
124
125/*******************************************************************************
126 * This function reads a value of a oscillator property from its id.
127 * Returns value if success, and a default value if property not found.
128 * Default value is passed as parameter.
129 ******************************************************************************/
130uint32_t fdt_osc_read_uint32_default(enum stm32mp_osc_id osc_id,
131 const char *prop_name, uint32_t dflt_value)
132{
133 int node, subnode;
134 void *fdt;
135
136 if (fdt_get_address(&fdt) == 0) {
137 return dflt_value;
138 }
139
140 if (osc_id >= NB_OSC) {
141 return dflt_value;
142 }
143
144 node = fdt_path_offset(fdt, "/clocks");
145 if (node < 0) {
146 return dflt_value;
147 }
148
149 fdt_for_each_subnode(subnode, fdt, node) {
150 const char *cchar;
151 int ret;
152
153 cchar = fdt_get_name(fdt, subnode, &ret);
154 if (cchar == NULL) {
155 return dflt_value;
156 }
157
158 if (strncmp(cchar, stm32mp_osc_node_label[osc_id],
159 (size_t)ret) != 0) {
160 continue;
161 }
162
163 return fdt_read_uint32_default(subnode, prop_name, dflt_value);
164 }
165
166 return dflt_value;
167}
168
169/*******************************************************************************
170 * This function reads the rcc base address.
171 * It reads the value indicated inside the device tree.
172 * Returns address if success, and 0 value else.
173 ******************************************************************************/
174uint32_t fdt_rcc_read_addr(void)
175{
176 int node, subnode;
177 void *fdt;
178
179 if (fdt_get_address(&fdt) == 0) {
180 return 0;
181 }
182
183 node = fdt_path_offset(fdt, "/soc");
184 if (node < 0) {
185 return 0;
186 }
187
188 fdt_for_each_subnode(subnode, fdt, node) {
189 const char *cchar;
190 int ret;
191
192 cchar = fdt_get_name(fdt, subnode, &ret);
193 if (cchar == NULL) {
194 return 0;
195 }
196
197 if (strncmp(cchar, DT_RCC_NODE_NAME, (size_t)ret) == 0) {
198 const fdt32_t *cuint;
199
200 cuint = fdt_getprop(fdt, subnode, "reg", NULL);
201 if (cuint == NULL) {
202 return 0;
203 }
204
205 return fdt32_to_cpu(*cuint);
206 }
207 }
208
209 return 0;
210}
211
212/*******************************************************************************
213 * This function reads a series of parameters in rcc-clk section.
214 * It reads the values indicated inside the device tree, from property name.
215 * The number of parameters is also indicated as entry parameter.
216 * Returns 0 if success, and a negative value else.
217 * If success, values are stored at the second parameter address.
218 ******************************************************************************/
219int fdt_rcc_read_uint32_array(const char *prop_name,
220 uint32_t *array, uint32_t count)
221{
222 int node;
223 void *fdt;
224
225 if (fdt_get_address(&fdt) == 0) {
226 return -ENOENT;
227 }
228
229 node = fdt_node_offset_by_compatible(fdt, -1, DT_RCC_CLK_COMPAT);
230 if (node < 0) {
231 return -FDT_ERR_NOTFOUND;
232 }
233
234 return fdt_read_uint32_array(node, prop_name, array, count);
235}
236
237/*******************************************************************************
238 * This function gets the subnode offset in rcc-clk section from its name.
239 * It reads the values indicated inside the device tree.
240 * Returns offset if success, and a negative value else.
241 ******************************************************************************/
242int fdt_rcc_subnode_offset(const char *name)
243{
244 int node, subnode;
245 void *fdt;
246
247 if (fdt_get_address(&fdt) == 0) {
248 return -ENOENT;
249 }
250
251 node = fdt_node_offset_by_compatible(fdt, -1, DT_RCC_CLK_COMPAT);
252 if (node < 0) {
253 return -FDT_ERR_NOTFOUND;
254 }
255
256 subnode = fdt_subnode_offset(fdt, node, name);
257 if (subnode <= 0) {
258 return -FDT_ERR_NOTFOUND;
259 }
260
261 return subnode;
262}
263
264/*******************************************************************************
265 * This function gets the pointer to a rcc-clk property from its name.
266 * It reads the values indicated inside the device tree.
267 * Length of the property is stored in the second parameter.
268 * Returns pointer if success, and NULL value else.
269 ******************************************************************************/
270const uint32_t *fdt_rcc_read_prop(const char *prop_name, int *lenp)
271{
272 const uint32_t *cuint;
273 int node, len;
274 void *fdt;
275
276 if (fdt_get_address(&fdt) == 0) {
277 return NULL;
278 }
279
280 node = fdt_node_offset_by_compatible(fdt, -1, DT_RCC_CLK_COMPAT);
281 if (node < 0) {
282 return NULL;
283 }
284
285 cuint = fdt_getprop(fdt, node, prop_name, &len);
286 if (cuint == NULL) {
287 return NULL;
288 }
289
290 *lenp = len;
291 return cuint;
292}
293
294/*******************************************************************************
295 * This function gets the secure status for rcc node.
296 * It reads secure-status in device tree.
297 * Returns 1 if rcc is available from secure world, 0 else.
298 ******************************************************************************/
299bool fdt_get_rcc_secure_status(void)
300{
301 int node;
302 void *fdt;
303
304 if (fdt_get_address(&fdt) == 0) {
305 return false;
306 }
307
308 node = fdt_node_offset_by_compatible(fdt, -1, DT_RCC_COMPAT);
309 if (node < 0) {
310 return false;
311 }
312
313 return fdt_check_secure_status(node);
314}
315
316/*******************************************************************************
317 * This function reads the stgen base address.
318 * It reads the value indicated inside the device tree.
319 * Returns address if success, and NULL value else.
320 ******************************************************************************/
321uintptr_t fdt_get_stgen_base(void)
322{
323 int node;
324 const fdt32_t *cuint;
325 void *fdt;
326
327 if (fdt_get_address(&fdt) == 0) {
328 return 0;
329 }
330
331 node = fdt_node_offset_by_compatible(fdt, -1, DT_STGEN_COMPAT);
332 if (node < 0) {
333 return 0;
334 }
335
336 cuint = fdt_getprop(fdt, node, "reg", NULL);
337 if (cuint == NULL) {
338 return 0;
339 }
340
341 return fdt32_to_cpu(*cuint);
342}
343
344/*******************************************************************************
345 * This function gets the clock ID of the given node.
346 * It reads the value indicated inside the device tree.
347 * Returns ID if success, and a negative value else.
348 ******************************************************************************/
349int fdt_get_clock_id(int node)
350{
351 const fdt32_t *cuint;
352 void *fdt;
353
354 if (fdt_get_address(&fdt) == 0) {
355 return -ENOENT;
356 }
357
358 cuint = fdt_getprop(fdt, node, "clocks", NULL);
359 if (cuint == NULL) {
360 return -FDT_ERR_NOTFOUND;
361 }
362
363 cuint++;
364 return (int)fdt32_to_cpu(*cuint);
365}