blob: c83b8ad05a2ffd3ffc2708d447a1d23bf84e2d0d [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 Gautiera205a5c2021-08-30 15:06:54 +020014#include <drivers/clk.h>
Yann Gautier4d429472019-02-14 11:15:20 +010015#include <drivers/st/stm32_gpio.h>
16#include <drivers/st/stm32mp_clkfunc.h>
17
Nicolas Le Bayondc08ebe2019-09-11 11:46:40 +020018#define DT_UART_COMPAT "st,stm32h7-uart"
Yann Gautier4d429472019-02-14 11:15:20 +010019/*
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 */
Patrick Delaunay286d81e2020-10-06 14:32:26 +0200166static int fdt_get_rcc_node(void *fdt)
Yann Gautier4d429472019-02-14 11:15:20 +0100167{
Yann Gautiereaab37d2020-10-22 15:37:22 +0200168 static int node;
169
170 if (node <= 0) {
171 node = fdt_node_offset_by_compatible(fdt, -1, DT_RCC_CLK_COMPAT);
172 }
173
174 return node;
Yann Gautier4d429472019-02-14 11:15:20 +0100175}
176
177/*
Yann Gautier4d429472019-02-14 11:15:20 +0100178 * Read a series of parameters in rcc-clk section in device tree
179 * @param prop_name: Name of the RCC property to be read
180 * @param array: the array to store the property parameters
181 * @param count: number of parameters to be read
182 * @return: 0 on succes or a negative value on error
183 */
Andre Przywaracc99f3f2020-03-26 12:51:21 +0000184int fdt_rcc_read_uint32_array(const char *prop_name, uint32_t count,
185 uint32_t *array)
Yann Gautier4d429472019-02-14 11:15:20 +0100186{
187 int node;
188 void *fdt;
189
190 if (fdt_get_address(&fdt) == 0) {
191 return -ENOENT;
192 }
193
194 node = fdt_get_rcc_node(fdt);
195 if (node < 0) {
196 return -FDT_ERR_NOTFOUND;
197 }
198
Andre Przywaracc99f3f2020-03-26 12:51:21 +0000199 return fdt_read_uint32_array(fdt, node, prop_name, count, array);
Yann Gautier4d429472019-02-14 11:15:20 +0100200}
201
202/*
203 * Get the subnode offset in rcc-clk section from its name in device tree
204 * @param name: name of the RCC property
205 * @return: offset on success, and a negative FDT/ERRNO error code on failure.
206 */
207int fdt_rcc_subnode_offset(const char *name)
208{
209 int node, subnode;
210 void *fdt;
211
212 if (fdt_get_address(&fdt) == 0) {
213 return -ENOENT;
214 }
215
216 node = fdt_get_rcc_node(fdt);
217 if (node < 0) {
218 return -FDT_ERR_NOTFOUND;
219 }
220
221 subnode = fdt_subnode_offset(fdt, node, name);
222 if (subnode <= 0) {
223 return -FDT_ERR_NOTFOUND;
224 }
225
226 return subnode;
227}
228
229/*
230 * Get the pointer to a rcc-clk property from its name.
231 * @param name: name of the RCC property
232 * @param lenp: stores the length of the property.
233 * @return: pointer to the property on success, and NULL value on failure.
234 */
235const fdt32_t *fdt_rcc_read_prop(const char *prop_name, int *lenp)
236{
237 const fdt32_t *cuint;
238 int node, len;
239 void *fdt;
240
241 if (fdt_get_address(&fdt) == 0) {
242 return NULL;
243 }
244
245 node = fdt_get_rcc_node(fdt);
246 if (node < 0) {
247 return NULL;
248 }
249
250 cuint = fdt_getprop(fdt, node, prop_name, &len);
251 if (cuint == NULL) {
252 return NULL;
253 }
254
255 *lenp = len;
256 return cuint;
257}
258
259/*
260 * Get the secure status for rcc node in device tree.
261 * @return: true if rcc is available from secure world, false if not.
262 */
263bool fdt_get_rcc_secure_status(void)
264{
265 int node;
266 void *fdt;
267
268 if (fdt_get_address(&fdt) == 0) {
269 return false;
270 }
271
272 node = fdt_get_rcc_node(fdt);
273 if (node < 0) {
274 return false;
275 }
276
277 return !!(fdt_get_status(node) & DT_SECURE);
278}
279
280/*
Yann Gautier4d429472019-02-14 11:15:20 +0100281 * Get the clock ID of the given node in device tree.
282 * @param node: node offset
283 * @return: Clock ID on success, and a negative FDT/ERRNO error code on failure.
284 */
285int fdt_get_clock_id(int node)
286{
287 const fdt32_t *cuint;
288 void *fdt;
289
290 if (fdt_get_address(&fdt) == 0) {
291 return -ENOENT;
292 }
293
294 cuint = fdt_getprop(fdt, node, "clocks", NULL);
295 if (cuint == NULL) {
296 return -FDT_ERR_NOTFOUND;
297 }
298
299 cuint++;
300 return (int)fdt32_to_cpu(*cuint);
301}
Nicolas Le Bayondc08ebe2019-09-11 11:46:40 +0200302
303/*
304 * Get the frequency of the specified UART instance.
305 * @param instance: UART interface registers base address.
306 * @return: clock frequency on success, 0 value on failure.
307 */
308unsigned long fdt_get_uart_clock_freq(uintptr_t instance)
309{
310 void *fdt;
311 int node;
312 int clk_id;
313
314 if (fdt_get_address(&fdt) == 0) {
315 return 0UL;
316 }
317
318 /* Check for UART nodes */
319 node = dt_match_instance_by_compatible(DT_UART_COMPAT, instance);
320 if (node < 0) {
321 return 0UL;
322 }
323
324 clk_id = fdt_get_clock_id(node);
325 if (clk_id < 0) {
326 return 0UL;
327 }
328
Yann Gautiera205a5c2021-08-30 15:06:54 +0200329 return clk_get_rate((unsigned long)clk_id);
Nicolas Le Bayondc08ebe2019-09-11 11:46:40 +0200330}