blob: 0db0dee0268f9cc3db661c7bae7d43c2fa5e5d2a [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
Nicolas Le Bayondc08ebe2019-09-11 11:46:40 +020017#define DT_UART_COMPAT "st,stm32h7-uart"
Yann Gautier4d429472019-02-14 11:15:20 +010018/*
Yann Gautier5f2e8742019-05-17 15:57:56 +020019 * Get the frequency of an oscillator from its name in device tree.
20 * @param name: oscillator name
21 * @param freq: stores the frequency of the oscillator
22 * @return: 0 on success, and a negative FDT/ERRNO error code on failure.
23 */
24int fdt_osc_read_freq(const char *name, uint32_t *freq)
25{
26 int node, subnode;
27 void *fdt;
28
29 if (fdt_get_address(&fdt) == 0) {
30 return -ENOENT;
31 }
32
33 node = fdt_path_offset(fdt, "/clocks");
34 if (node < 0) {
35 return -FDT_ERR_NOTFOUND;
36 }
37
38 fdt_for_each_subnode(subnode, fdt, node) {
39 const char *cchar;
40 int ret;
41
42 cchar = fdt_get_name(fdt, subnode, &ret);
43 if (cchar == NULL) {
44 return ret;
45 }
46
47 if (strncmp(cchar, name, (size_t)ret) == 0) {
48 const fdt32_t *cuint;
49
50 cuint = fdt_getprop(fdt, subnode, "clock-frequency",
51 &ret);
52 if (cuint == NULL) {
53 return ret;
54 }
55
56 *freq = fdt32_to_cpu(*cuint);
57
58 return 0;
59 }
60 }
61
62 /* Oscillator not found, freq=0 */
63 *freq = 0;
64 return 0;
65}
66
67/*
68 * Check the presence of an oscillator property from its id.
69 * @param osc_id: oscillator ID
70 * @param prop_name: property name
71 * @return: true/false regarding search result.
72 */
73bool fdt_osc_read_bool(enum stm32mp_osc_id osc_id, const char *prop_name)
74{
75 int node, subnode;
76 void *fdt;
77
78 if (fdt_get_address(&fdt) == 0) {
79 return false;
80 }
81
82 if (osc_id >= NB_OSC) {
83 return false;
84 }
85
86 node = fdt_path_offset(fdt, "/clocks");
87 if (node < 0) {
88 return false;
89 }
90
91 fdt_for_each_subnode(subnode, fdt, node) {
92 const char *cchar;
93 int ret;
94
95 cchar = fdt_get_name(fdt, subnode, &ret);
96 if (cchar == NULL) {
97 return false;
98 }
99
100 if (strncmp(cchar, stm32mp_osc_node_label[osc_id],
101 (size_t)ret) != 0) {
102 continue;
103 }
104
105 if (fdt_getprop(fdt, subnode, prop_name, NULL) != NULL) {
106 return true;
107 }
108 }
109
110 return false;
111}
112
113/*
114 * Get the value of a oscillator property from its ID.
115 * @param osc_id: oscillator ID
116 * @param prop_name: property name
117 * @param dflt_value: default value
118 * @return oscillator value on success, default value if property not found.
119 */
120uint32_t fdt_osc_read_uint32_default(enum stm32mp_osc_id osc_id,
121 const char *prop_name, uint32_t dflt_value)
122{
123 int node, subnode;
124 void *fdt;
125
126 if (fdt_get_address(&fdt) == 0) {
127 return dflt_value;
128 }
129
130 if (osc_id >= NB_OSC) {
131 return dflt_value;
132 }
133
134 node = fdt_path_offset(fdt, "/clocks");
135 if (node < 0) {
136 return dflt_value;
137 }
138
139 fdt_for_each_subnode(subnode, fdt, node) {
140 const char *cchar;
141 int ret;
142
143 cchar = fdt_get_name(fdt, subnode, &ret);
144 if (cchar == NULL) {
145 return dflt_value;
146 }
147
148 if (strncmp(cchar, stm32mp_osc_node_label[osc_id],
149 (size_t)ret) != 0) {
150 continue;
151 }
152
Andre Przywara2d5690c2020-03-26 11:50:33 +0000153 return fdt_read_uint32_default(fdt, subnode, prop_name,
154 dflt_value);
Yann Gautier5f2e8742019-05-17 15:57:56 +0200155 }
156
157 return dflt_value;
158}
159
160/*
Yann Gautier4d429472019-02-14 11:15:20 +0100161 * Get the RCC node offset from the device tree
162 * @param fdt: Device tree reference
163 * @return: Node offset or a negative value on error
164 */
Patrick Delaunay286d81e2020-10-06 14:32:26 +0200165static int fdt_get_rcc_node(void *fdt)
Yann Gautier4d429472019-02-14 11:15:20 +0100166{
Yann Gautiereaab37d2020-10-22 15:37:22 +0200167 static int node;
168
169 if (node <= 0) {
170 node = fdt_node_offset_by_compatible(fdt, -1, DT_RCC_CLK_COMPAT);
171 }
172
173 return node;
Yann Gautier4d429472019-02-14 11:15:20 +0100174}
175
176/*
Yann Gautier4d429472019-02-14 11:15:20 +0100177 * Read a series of parameters in rcc-clk section in device tree
178 * @param prop_name: Name of the RCC property to be read
179 * @param array: the array to store the property parameters
180 * @param count: number of parameters to be read
181 * @return: 0 on succes or a negative value on error
182 */
Andre Przywaracc99f3f2020-03-26 12:51:21 +0000183int fdt_rcc_read_uint32_array(const char *prop_name, uint32_t count,
184 uint32_t *array)
Yann Gautier4d429472019-02-14 11:15:20 +0100185{
186 int node;
187 void *fdt;
188
189 if (fdt_get_address(&fdt) == 0) {
190 return -ENOENT;
191 }
192
193 node = fdt_get_rcc_node(fdt);
194 if (node < 0) {
195 return -FDT_ERR_NOTFOUND;
196 }
197
Andre Przywaracc99f3f2020-03-26 12:51:21 +0000198 return fdt_read_uint32_array(fdt, node, prop_name, count, array);
Yann Gautier4d429472019-02-14 11:15:20 +0100199}
200
201/*
202 * Get the subnode offset in rcc-clk section from its name in device tree
203 * @param name: name of the RCC property
204 * @return: offset on success, and a negative FDT/ERRNO error code on failure.
205 */
206int fdt_rcc_subnode_offset(const char *name)
207{
208 int node, subnode;
209 void *fdt;
210
211 if (fdt_get_address(&fdt) == 0) {
212 return -ENOENT;
213 }
214
215 node = fdt_get_rcc_node(fdt);
216 if (node < 0) {
217 return -FDT_ERR_NOTFOUND;
218 }
219
220 subnode = fdt_subnode_offset(fdt, node, name);
221 if (subnode <= 0) {
222 return -FDT_ERR_NOTFOUND;
223 }
224
225 return subnode;
226}
227
228/*
229 * Get the pointer to a rcc-clk property from its name.
230 * @param name: name of the RCC property
231 * @param lenp: stores the length of the property.
232 * @return: pointer to the property on success, and NULL value on failure.
233 */
234const fdt32_t *fdt_rcc_read_prop(const char *prop_name, int *lenp)
235{
236 const fdt32_t *cuint;
237 int node, len;
238 void *fdt;
239
240 if (fdt_get_address(&fdt) == 0) {
241 return NULL;
242 }
243
244 node = fdt_get_rcc_node(fdt);
245 if (node < 0) {
246 return NULL;
247 }
248
249 cuint = fdt_getprop(fdt, node, prop_name, &len);
250 if (cuint == NULL) {
251 return NULL;
252 }
253
254 *lenp = len;
255 return cuint;
256}
257
258/*
259 * Get the secure status for rcc node in device tree.
260 * @return: true if rcc is available from secure world, false if not.
261 */
262bool fdt_get_rcc_secure_status(void)
263{
264 int node;
265 void *fdt;
266
267 if (fdt_get_address(&fdt) == 0) {
268 return false;
269 }
270
271 node = fdt_get_rcc_node(fdt);
272 if (node < 0) {
273 return false;
274 }
275
276 return !!(fdt_get_status(node) & DT_SECURE);
277}
278
279/*
Yann Gautier4d429472019-02-14 11:15:20 +0100280 * Get the clock ID of the given node in device tree.
281 * @param node: node offset
282 * @return: Clock ID on success, and a negative FDT/ERRNO error code on failure.
283 */
284int fdt_get_clock_id(int node)
285{
286 const fdt32_t *cuint;
287 void *fdt;
288
289 if (fdt_get_address(&fdt) == 0) {
290 return -ENOENT;
291 }
292
293 cuint = fdt_getprop(fdt, node, "clocks", NULL);
294 if (cuint == NULL) {
295 return -FDT_ERR_NOTFOUND;
296 }
297
298 cuint++;
299 return (int)fdt32_to_cpu(*cuint);
300}
Nicolas Le Bayondc08ebe2019-09-11 11:46:40 +0200301
302/*
303 * Get the frequency of the specified UART instance.
304 * @param instance: UART interface registers base address.
305 * @return: clock frequency on success, 0 value on failure.
306 */
307unsigned long fdt_get_uart_clock_freq(uintptr_t instance)
308{
309 void *fdt;
310 int node;
311 int clk_id;
312
313 if (fdt_get_address(&fdt) == 0) {
314 return 0UL;
315 }
316
317 /* Check for UART nodes */
318 node = dt_match_instance_by_compatible(DT_UART_COMPAT, instance);
319 if (node < 0) {
320 return 0UL;
321 }
322
323 clk_id = fdt_get_clock_id(node);
324 if (clk_id < 0) {
325 return 0UL;
326 }
327
328 return stm32mp_clk_get_rate((unsigned long)clk_id);
329}