blob: 19dfe1b25417df5f9146157851edf2dcbd0d3819 [file] [log] [blame]
Yann Gautier9aea69e2018-07-24 17:13:36 +02001/*
Yann Gautier1a3fc9f2019-01-17 14:35:22 +01002 * Copyright (c) 2017-2019, STMicroelectronics - All Rights Reserved
Yann Gautier9aea69e2018-07-24 17:13:36 +02003 *
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/*******************************************************************************
Yann Gautier038bff22019-01-17 19:17:47 +010035 * This function returns the RCC node in the device tree.
36 ******************************************************************************/
37static int fdt_get_rcc_node(void *fdt)
38{
39 return fdt_node_offset_by_compatible(fdt, -1, DT_RCC_CLK_COMPAT);
40}
41
42/*******************************************************************************
Yann Gautier9aea69e2018-07-24 17:13:36 +020043 * This function reads the frequency of an oscillator from its name.
44 * It reads the value indicated inside the device tree.
Yann Gautier1a3fc9f2019-01-17 14:35:22 +010045 * Returns 0 on success, and a negative FDT/ERRNO error code on failure.
46 * On success, value is stored in the second parameter.
Yann Gautier9aea69e2018-07-24 17:13:36 +020047 ******************************************************************************/
48int fdt_osc_read_freq(const char *name, uint32_t *freq)
49{
50 int node, subnode;
51 void *fdt;
52
53 if (fdt_get_address(&fdt) == 0) {
54 return -ENOENT;
55 }
56
57 node = fdt_path_offset(fdt, "/clocks");
58 if (node < 0) {
59 return -FDT_ERR_NOTFOUND;
60 }
61
62 fdt_for_each_subnode(subnode, fdt, node) {
63 const char *cchar;
64 int ret;
65
66 cchar = fdt_get_name(fdt, subnode, &ret);
67 if (cchar == NULL) {
68 return ret;
69 }
70
71 if (strncmp(cchar, name, (size_t)ret) == 0) {
72 const fdt32_t *cuint;
73
74 cuint = fdt_getprop(fdt, subnode, "clock-frequency",
75 &ret);
76 if (cuint == NULL) {
77 return ret;
78 }
79
80 *freq = fdt32_to_cpu(*cuint);
81
82 return 0;
83 }
84 }
85
86 /* Oscillator not found, freq=0 */
87 *freq = 0;
88 return 0;
89}
90
91/*******************************************************************************
92 * This function checks the presence of an oscillator property from its id.
93 * The search is done inside the device tree.
94 * Returns true/false regarding search result.
95 ******************************************************************************/
96bool fdt_osc_read_bool(enum stm32mp_osc_id osc_id, const char *prop_name)
97{
98 int node, subnode;
99 void *fdt;
100
101 if (fdt_get_address(&fdt) == 0) {
102 return false;
103 }
104
105 if (osc_id >= NB_OSC) {
106 return false;
107 }
108
109 node = fdt_path_offset(fdt, "/clocks");
110 if (node < 0) {
111 return false;
112 }
113
114 fdt_for_each_subnode(subnode, fdt, node) {
115 const char *cchar;
116 int ret;
117
118 cchar = fdt_get_name(fdt, subnode, &ret);
119 if (cchar == NULL) {
120 return false;
121 }
122
123 if (strncmp(cchar, stm32mp_osc_node_label[osc_id],
124 (size_t)ret) != 0) {
125 continue;
126 }
127
128 if (fdt_getprop(fdt, subnode, prop_name, NULL) != NULL) {
129 return true;
130 }
131 }
132
133 return false;
134}
135
136/*******************************************************************************
137 * This function reads a value of a oscillator property from its id.
Yann Gautier1a3fc9f2019-01-17 14:35:22 +0100138 * Returns value on success, and a default value if property not found.
Yann Gautier9aea69e2018-07-24 17:13:36 +0200139 * Default value is passed as parameter.
140 ******************************************************************************/
141uint32_t fdt_osc_read_uint32_default(enum stm32mp_osc_id osc_id,
142 const char *prop_name, uint32_t dflt_value)
143{
144 int node, subnode;
145 void *fdt;
146
147 if (fdt_get_address(&fdt) == 0) {
148 return dflt_value;
149 }
150
151 if (osc_id >= NB_OSC) {
152 return dflt_value;
153 }
154
155 node = fdt_path_offset(fdt, "/clocks");
156 if (node < 0) {
157 return dflt_value;
158 }
159
160 fdt_for_each_subnode(subnode, fdt, node) {
161 const char *cchar;
162 int ret;
163
164 cchar = fdt_get_name(fdt, subnode, &ret);
165 if (cchar == NULL) {
166 return dflt_value;
167 }
168
169 if (strncmp(cchar, stm32mp_osc_node_label[osc_id],
170 (size_t)ret) != 0) {
171 continue;
172 }
173
174 return fdt_read_uint32_default(subnode, prop_name, dflt_value);
175 }
176
177 return dflt_value;
178}
179
180/*******************************************************************************
181 * This function reads the rcc base address.
182 * It reads the value indicated inside the device tree.
183 * Returns address if success, and 0 value else.
184 ******************************************************************************/
185uint32_t fdt_rcc_read_addr(void)
186{
187 int node, subnode;
188 void *fdt;
189
190 if (fdt_get_address(&fdt) == 0) {
191 return 0;
192 }
193
194 node = fdt_path_offset(fdt, "/soc");
195 if (node < 0) {
196 return 0;
197 }
198
199 fdt_for_each_subnode(subnode, fdt, node) {
200 const char *cchar;
201 int ret;
202
203 cchar = fdt_get_name(fdt, subnode, &ret);
204 if (cchar == NULL) {
205 return 0;
206 }
207
208 if (strncmp(cchar, DT_RCC_NODE_NAME, (size_t)ret) == 0) {
209 const fdt32_t *cuint;
210
211 cuint = fdt_getprop(fdt, subnode, "reg", NULL);
212 if (cuint == NULL) {
213 return 0;
214 }
215
216 return fdt32_to_cpu(*cuint);
217 }
218 }
219
220 return 0;
221}
222
223/*******************************************************************************
224 * This function reads a series of parameters in rcc-clk section.
225 * It reads the values indicated inside the device tree, from property name.
226 * The number of parameters is also indicated as entry parameter.
227 * Returns 0 if success, and a negative value else.
228 * If success, values are stored at the second parameter address.
229 ******************************************************************************/
230int fdt_rcc_read_uint32_array(const char *prop_name,
231 uint32_t *array, uint32_t count)
232{
233 int node;
234 void *fdt;
235
236 if (fdt_get_address(&fdt) == 0) {
237 return -ENOENT;
238 }
239
240 node = fdt_node_offset_by_compatible(fdt, -1, DT_RCC_CLK_COMPAT);
241 if (node < 0) {
242 return -FDT_ERR_NOTFOUND;
243 }
244
245 return fdt_read_uint32_array(node, prop_name, array, count);
246}
247
248/*******************************************************************************
249 * This function gets the subnode offset in rcc-clk section from its name.
250 * It reads the values indicated inside the device tree.
Yann Gautier038bff22019-01-17 19:17:47 +0100251 * Returns offset on success, and a negative FDT/ERRNO error code on failure.
Yann Gautier9aea69e2018-07-24 17:13:36 +0200252 ******************************************************************************/
253int fdt_rcc_subnode_offset(const char *name)
254{
255 int node, subnode;
256 void *fdt;
257
258 if (fdt_get_address(&fdt) == 0) {
259 return -ENOENT;
260 }
261
Yann Gautier038bff22019-01-17 19:17:47 +0100262 node = fdt_get_rcc_node(fdt);
Yann Gautier9aea69e2018-07-24 17:13:36 +0200263 if (node < 0) {
264 return -FDT_ERR_NOTFOUND;
265 }
266
267 subnode = fdt_subnode_offset(fdt, node, name);
268 if (subnode <= 0) {
269 return -FDT_ERR_NOTFOUND;
270 }
271
272 return subnode;
273}
274
275/*******************************************************************************
276 * This function gets the pointer to a rcc-clk property from its name.
277 * It reads the values indicated inside the device tree.
278 * Length of the property is stored in the second parameter.
Yann Gautierf9af3bc2018-11-09 15:57:18 +0100279 * Returns pointer on success, and NULL value on failure.
Yann Gautier9aea69e2018-07-24 17:13:36 +0200280 ******************************************************************************/
Yann Gautierf9af3bc2018-11-09 15:57:18 +0100281const fdt32_t *fdt_rcc_read_prop(const char *prop_name, int *lenp)
Yann Gautier9aea69e2018-07-24 17:13:36 +0200282{
Yann Gautierf9af3bc2018-11-09 15:57:18 +0100283 const fdt32_t *cuint;
Yann Gautier9aea69e2018-07-24 17:13:36 +0200284 int node, len;
285 void *fdt;
286
287 if (fdt_get_address(&fdt) == 0) {
288 return NULL;
289 }
290
Yann Gautier038bff22019-01-17 19:17:47 +0100291 node = fdt_get_rcc_node(fdt);
Yann Gautier9aea69e2018-07-24 17:13:36 +0200292 if (node < 0) {
293 return NULL;
294 }
295
296 cuint = fdt_getprop(fdt, node, prop_name, &len);
297 if (cuint == NULL) {
298 return NULL;
299 }
300
301 *lenp = len;
302 return cuint;
303}
304
305/*******************************************************************************
306 * This function gets the secure status for rcc node.
307 * It reads secure-status in device tree.
Yann Gautier038bff22019-01-17 19:17:47 +0100308 * Returns true if rcc is available from secure world, false if not.
Yann Gautier9aea69e2018-07-24 17:13:36 +0200309 ******************************************************************************/
310bool fdt_get_rcc_secure_status(void)
311{
312 int node;
313 void *fdt;
314
315 if (fdt_get_address(&fdt) == 0) {
316 return false;
317 }
318
Yann Gautier038bff22019-01-17 19:17:47 +0100319 node = fdt_get_rcc_node(fdt);
Yann Gautier9aea69e2018-07-24 17:13:36 +0200320 if (node < 0) {
321 return false;
322 }
323
Yann Gautier038bff22019-01-17 19:17:47 +0100324 return (fdt_get_status(node) & DT_SECURE) != 0U;
Yann Gautier9aea69e2018-07-24 17:13:36 +0200325}
326
327/*******************************************************************************
328 * This function reads the stgen base address.
329 * It reads the value indicated inside the device tree.
Yann Gautier038bff22019-01-17 19:17:47 +0100330 * Returns address on success, and NULL value on failure.
Yann Gautier9aea69e2018-07-24 17:13:36 +0200331 ******************************************************************************/
332uintptr_t fdt_get_stgen_base(void)
333{
334 int node;
335 const fdt32_t *cuint;
336 void *fdt;
337
338 if (fdt_get_address(&fdt) == 0) {
339 return 0;
340 }
341
342 node = fdt_node_offset_by_compatible(fdt, -1, DT_STGEN_COMPAT);
343 if (node < 0) {
344 return 0;
345 }
346
347 cuint = fdt_getprop(fdt, node, "reg", NULL);
348 if (cuint == NULL) {
349 return 0;
350 }
351
352 return fdt32_to_cpu(*cuint);
353}
354
355/*******************************************************************************
356 * This function gets the clock ID of the given node.
357 * It reads the value indicated inside the device tree.
Yann Gautier038bff22019-01-17 19:17:47 +0100358 * Returns ID on success, and a negative FDT/ERRNO error code on failure.
Yann Gautier9aea69e2018-07-24 17:13:36 +0200359 ******************************************************************************/
360int fdt_get_clock_id(int node)
361{
362 const fdt32_t *cuint;
363 void *fdt;
364
365 if (fdt_get_address(&fdt) == 0) {
366 return -ENOENT;
367 }
368
369 cuint = fdt_getprop(fdt, node, "clocks", NULL);
370 if (cuint == NULL) {
371 return -FDT_ERR_NOTFOUND;
372 }
373
374 cuint++;
375 return (int)fdt32_to_cpu(*cuint);
376}