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