1*54fd6939SJiyong Park /*
2*54fd6939SJiyong Park * Copyright (c) 2017-2021, STMicroelectronics - All Rights Reserved
3*54fd6939SJiyong Park *
4*54fd6939SJiyong Park * SPDX-License-Identifier: BSD-3-Clause
5*54fd6939SJiyong Park */
6*54fd6939SJiyong Park
7*54fd6939SJiyong Park #include <errno.h>
8*54fd6939SJiyong Park
9*54fd6939SJiyong Park #include <libfdt.h>
10*54fd6939SJiyong Park
11*54fd6939SJiyong Park #include <platform_def.h>
12*54fd6939SJiyong Park
13*54fd6939SJiyong Park #include <common/fdt_wrappers.h>
14*54fd6939SJiyong Park #include <drivers/st/stm32_gpio.h>
15*54fd6939SJiyong Park #include <drivers/st/stm32mp_clkfunc.h>
16*54fd6939SJiyong Park
17*54fd6939SJiyong Park /*
18*54fd6939SJiyong Park * Get the frequency of an oscillator from its name in device tree.
19*54fd6939SJiyong Park * @param name: oscillator name
20*54fd6939SJiyong Park * @param freq: stores the frequency of the oscillator
21*54fd6939SJiyong Park * @return: 0 on success, and a negative FDT/ERRNO error code on failure.
22*54fd6939SJiyong Park */
fdt_osc_read_freq(const char * name,uint32_t * freq)23*54fd6939SJiyong Park int fdt_osc_read_freq(const char *name, uint32_t *freq)
24*54fd6939SJiyong Park {
25*54fd6939SJiyong Park int node, subnode;
26*54fd6939SJiyong Park void *fdt;
27*54fd6939SJiyong Park
28*54fd6939SJiyong Park if (fdt_get_address(&fdt) == 0) {
29*54fd6939SJiyong Park return -ENOENT;
30*54fd6939SJiyong Park }
31*54fd6939SJiyong Park
32*54fd6939SJiyong Park node = fdt_path_offset(fdt, "/clocks");
33*54fd6939SJiyong Park if (node < 0) {
34*54fd6939SJiyong Park return -FDT_ERR_NOTFOUND;
35*54fd6939SJiyong Park }
36*54fd6939SJiyong Park
37*54fd6939SJiyong Park fdt_for_each_subnode(subnode, fdt, node) {
38*54fd6939SJiyong Park const char *cchar;
39*54fd6939SJiyong Park int ret;
40*54fd6939SJiyong Park
41*54fd6939SJiyong Park cchar = fdt_get_name(fdt, subnode, &ret);
42*54fd6939SJiyong Park if (cchar == NULL) {
43*54fd6939SJiyong Park return ret;
44*54fd6939SJiyong Park }
45*54fd6939SJiyong Park
46*54fd6939SJiyong Park if (strncmp(cchar, name, (size_t)ret) == 0) {
47*54fd6939SJiyong Park const fdt32_t *cuint;
48*54fd6939SJiyong Park
49*54fd6939SJiyong Park cuint = fdt_getprop(fdt, subnode, "clock-frequency",
50*54fd6939SJiyong Park &ret);
51*54fd6939SJiyong Park if (cuint == NULL) {
52*54fd6939SJiyong Park return ret;
53*54fd6939SJiyong Park }
54*54fd6939SJiyong Park
55*54fd6939SJiyong Park *freq = fdt32_to_cpu(*cuint);
56*54fd6939SJiyong Park
57*54fd6939SJiyong Park return 0;
58*54fd6939SJiyong Park }
59*54fd6939SJiyong Park }
60*54fd6939SJiyong Park
61*54fd6939SJiyong Park /* Oscillator not found, freq=0 */
62*54fd6939SJiyong Park *freq = 0;
63*54fd6939SJiyong Park return 0;
64*54fd6939SJiyong Park }
65*54fd6939SJiyong Park
66*54fd6939SJiyong Park /*
67*54fd6939SJiyong Park * Check the presence of an oscillator property from its id.
68*54fd6939SJiyong Park * @param osc_id: oscillator ID
69*54fd6939SJiyong Park * @param prop_name: property name
70*54fd6939SJiyong Park * @return: true/false regarding search result.
71*54fd6939SJiyong Park */
fdt_osc_read_bool(enum stm32mp_osc_id osc_id,const char * prop_name)72*54fd6939SJiyong Park bool fdt_osc_read_bool(enum stm32mp_osc_id osc_id, const char *prop_name)
73*54fd6939SJiyong Park {
74*54fd6939SJiyong Park int node, subnode;
75*54fd6939SJiyong Park void *fdt;
76*54fd6939SJiyong Park
77*54fd6939SJiyong Park if (fdt_get_address(&fdt) == 0) {
78*54fd6939SJiyong Park return false;
79*54fd6939SJiyong Park }
80*54fd6939SJiyong Park
81*54fd6939SJiyong Park if (osc_id >= NB_OSC) {
82*54fd6939SJiyong Park return false;
83*54fd6939SJiyong Park }
84*54fd6939SJiyong Park
85*54fd6939SJiyong Park node = fdt_path_offset(fdt, "/clocks");
86*54fd6939SJiyong Park if (node < 0) {
87*54fd6939SJiyong Park return false;
88*54fd6939SJiyong Park }
89*54fd6939SJiyong Park
90*54fd6939SJiyong Park fdt_for_each_subnode(subnode, fdt, node) {
91*54fd6939SJiyong Park const char *cchar;
92*54fd6939SJiyong Park int ret;
93*54fd6939SJiyong Park
94*54fd6939SJiyong Park cchar = fdt_get_name(fdt, subnode, &ret);
95*54fd6939SJiyong Park if (cchar == NULL) {
96*54fd6939SJiyong Park return false;
97*54fd6939SJiyong Park }
98*54fd6939SJiyong Park
99*54fd6939SJiyong Park if (strncmp(cchar, stm32mp_osc_node_label[osc_id],
100*54fd6939SJiyong Park (size_t)ret) != 0) {
101*54fd6939SJiyong Park continue;
102*54fd6939SJiyong Park }
103*54fd6939SJiyong Park
104*54fd6939SJiyong Park if (fdt_getprop(fdt, subnode, prop_name, NULL) != NULL) {
105*54fd6939SJiyong Park return true;
106*54fd6939SJiyong Park }
107*54fd6939SJiyong Park }
108*54fd6939SJiyong Park
109*54fd6939SJiyong Park return false;
110*54fd6939SJiyong Park }
111*54fd6939SJiyong Park
112*54fd6939SJiyong Park /*
113*54fd6939SJiyong Park * Get the value of a oscillator property from its ID.
114*54fd6939SJiyong Park * @param osc_id: oscillator ID
115*54fd6939SJiyong Park * @param prop_name: property name
116*54fd6939SJiyong Park * @param dflt_value: default value
117*54fd6939SJiyong Park * @return oscillator value on success, default value if property not found.
118*54fd6939SJiyong Park */
fdt_osc_read_uint32_default(enum stm32mp_osc_id osc_id,const char * prop_name,uint32_t dflt_value)119*54fd6939SJiyong Park uint32_t fdt_osc_read_uint32_default(enum stm32mp_osc_id osc_id,
120*54fd6939SJiyong Park const char *prop_name, uint32_t dflt_value)
121*54fd6939SJiyong Park {
122*54fd6939SJiyong Park int node, subnode;
123*54fd6939SJiyong Park void *fdt;
124*54fd6939SJiyong Park
125*54fd6939SJiyong Park if (fdt_get_address(&fdt) == 0) {
126*54fd6939SJiyong Park return dflt_value;
127*54fd6939SJiyong Park }
128*54fd6939SJiyong Park
129*54fd6939SJiyong Park if (osc_id >= NB_OSC) {
130*54fd6939SJiyong Park return dflt_value;
131*54fd6939SJiyong Park }
132*54fd6939SJiyong Park
133*54fd6939SJiyong Park node = fdt_path_offset(fdt, "/clocks");
134*54fd6939SJiyong Park if (node < 0) {
135*54fd6939SJiyong Park return dflt_value;
136*54fd6939SJiyong Park }
137*54fd6939SJiyong Park
138*54fd6939SJiyong Park fdt_for_each_subnode(subnode, fdt, node) {
139*54fd6939SJiyong Park const char *cchar;
140*54fd6939SJiyong Park int ret;
141*54fd6939SJiyong Park
142*54fd6939SJiyong Park cchar = fdt_get_name(fdt, subnode, &ret);
143*54fd6939SJiyong Park if (cchar == NULL) {
144*54fd6939SJiyong Park return dflt_value;
145*54fd6939SJiyong Park }
146*54fd6939SJiyong Park
147*54fd6939SJiyong Park if (strncmp(cchar, stm32mp_osc_node_label[osc_id],
148*54fd6939SJiyong Park (size_t)ret) != 0) {
149*54fd6939SJiyong Park continue;
150*54fd6939SJiyong Park }
151*54fd6939SJiyong Park
152*54fd6939SJiyong Park return fdt_read_uint32_default(fdt, subnode, prop_name,
153*54fd6939SJiyong Park dflt_value);
154*54fd6939SJiyong Park }
155*54fd6939SJiyong Park
156*54fd6939SJiyong Park return dflt_value;
157*54fd6939SJiyong Park }
158*54fd6939SJiyong Park
159*54fd6939SJiyong Park /*
160*54fd6939SJiyong Park * Get the RCC node offset from the device tree
161*54fd6939SJiyong Park * @param fdt: Device tree reference
162*54fd6939SJiyong Park * @return: Node offset or a negative value on error
163*54fd6939SJiyong Park */
fdt_get_rcc_node(void * fdt)164*54fd6939SJiyong Park static int fdt_get_rcc_node(void *fdt)
165*54fd6939SJiyong Park {
166*54fd6939SJiyong Park static int node;
167*54fd6939SJiyong Park
168*54fd6939SJiyong Park if (node <= 0) {
169*54fd6939SJiyong Park node = fdt_node_offset_by_compatible(fdt, -1, DT_RCC_CLK_COMPAT);
170*54fd6939SJiyong Park }
171*54fd6939SJiyong Park
172*54fd6939SJiyong Park return node;
173*54fd6939SJiyong Park }
174*54fd6939SJiyong Park
175*54fd6939SJiyong Park /*
176*54fd6939SJiyong Park * Read a series of parameters in rcc-clk section in device tree
177*54fd6939SJiyong Park * @param prop_name: Name of the RCC property to be read
178*54fd6939SJiyong Park * @param array: the array to store the property parameters
179*54fd6939SJiyong Park * @param count: number of parameters to be read
180*54fd6939SJiyong Park * @return: 0 on succes or a negative value on error
181*54fd6939SJiyong Park */
fdt_rcc_read_uint32_array(const char * prop_name,uint32_t count,uint32_t * array)182*54fd6939SJiyong Park int fdt_rcc_read_uint32_array(const char *prop_name, uint32_t count,
183*54fd6939SJiyong Park uint32_t *array)
184*54fd6939SJiyong Park {
185*54fd6939SJiyong Park int node;
186*54fd6939SJiyong Park void *fdt;
187*54fd6939SJiyong Park
188*54fd6939SJiyong Park if (fdt_get_address(&fdt) == 0) {
189*54fd6939SJiyong Park return -ENOENT;
190*54fd6939SJiyong Park }
191*54fd6939SJiyong Park
192*54fd6939SJiyong Park node = fdt_get_rcc_node(fdt);
193*54fd6939SJiyong Park if (node < 0) {
194*54fd6939SJiyong Park return -FDT_ERR_NOTFOUND;
195*54fd6939SJiyong Park }
196*54fd6939SJiyong Park
197*54fd6939SJiyong Park return fdt_read_uint32_array(fdt, node, prop_name, count, array);
198*54fd6939SJiyong Park }
199*54fd6939SJiyong Park
200*54fd6939SJiyong Park /*
201*54fd6939SJiyong Park * Get the subnode offset in rcc-clk section from its name in device tree
202*54fd6939SJiyong Park * @param name: name of the RCC property
203*54fd6939SJiyong Park * @return: offset on success, and a negative FDT/ERRNO error code on failure.
204*54fd6939SJiyong Park */
fdt_rcc_subnode_offset(const char * name)205*54fd6939SJiyong Park int fdt_rcc_subnode_offset(const char *name)
206*54fd6939SJiyong Park {
207*54fd6939SJiyong Park int node, subnode;
208*54fd6939SJiyong Park void *fdt;
209*54fd6939SJiyong Park
210*54fd6939SJiyong Park if (fdt_get_address(&fdt) == 0) {
211*54fd6939SJiyong Park return -ENOENT;
212*54fd6939SJiyong Park }
213*54fd6939SJiyong Park
214*54fd6939SJiyong Park node = fdt_get_rcc_node(fdt);
215*54fd6939SJiyong Park if (node < 0) {
216*54fd6939SJiyong Park return -FDT_ERR_NOTFOUND;
217*54fd6939SJiyong Park }
218*54fd6939SJiyong Park
219*54fd6939SJiyong Park subnode = fdt_subnode_offset(fdt, node, name);
220*54fd6939SJiyong Park if (subnode <= 0) {
221*54fd6939SJiyong Park return -FDT_ERR_NOTFOUND;
222*54fd6939SJiyong Park }
223*54fd6939SJiyong Park
224*54fd6939SJiyong Park return subnode;
225*54fd6939SJiyong Park }
226*54fd6939SJiyong Park
227*54fd6939SJiyong Park /*
228*54fd6939SJiyong Park * Get the pointer to a rcc-clk property from its name.
229*54fd6939SJiyong Park * @param name: name of the RCC property
230*54fd6939SJiyong Park * @param lenp: stores the length of the property.
231*54fd6939SJiyong Park * @return: pointer to the property on success, and NULL value on failure.
232*54fd6939SJiyong Park */
fdt_rcc_read_prop(const char * prop_name,int * lenp)233*54fd6939SJiyong Park const fdt32_t *fdt_rcc_read_prop(const char *prop_name, int *lenp)
234*54fd6939SJiyong Park {
235*54fd6939SJiyong Park const fdt32_t *cuint;
236*54fd6939SJiyong Park int node, len;
237*54fd6939SJiyong Park void *fdt;
238*54fd6939SJiyong Park
239*54fd6939SJiyong Park if (fdt_get_address(&fdt) == 0) {
240*54fd6939SJiyong Park return NULL;
241*54fd6939SJiyong Park }
242*54fd6939SJiyong Park
243*54fd6939SJiyong Park node = fdt_get_rcc_node(fdt);
244*54fd6939SJiyong Park if (node < 0) {
245*54fd6939SJiyong Park return NULL;
246*54fd6939SJiyong Park }
247*54fd6939SJiyong Park
248*54fd6939SJiyong Park cuint = fdt_getprop(fdt, node, prop_name, &len);
249*54fd6939SJiyong Park if (cuint == NULL) {
250*54fd6939SJiyong Park return NULL;
251*54fd6939SJiyong Park }
252*54fd6939SJiyong Park
253*54fd6939SJiyong Park *lenp = len;
254*54fd6939SJiyong Park return cuint;
255*54fd6939SJiyong Park }
256*54fd6939SJiyong Park
257*54fd6939SJiyong Park /*
258*54fd6939SJiyong Park * Get the secure status for rcc node in device tree.
259*54fd6939SJiyong Park * @return: true if rcc is available from secure world, false if not.
260*54fd6939SJiyong Park */
fdt_get_rcc_secure_status(void)261*54fd6939SJiyong Park bool fdt_get_rcc_secure_status(void)
262*54fd6939SJiyong Park {
263*54fd6939SJiyong Park int node;
264*54fd6939SJiyong Park void *fdt;
265*54fd6939SJiyong Park
266*54fd6939SJiyong Park if (fdt_get_address(&fdt) == 0) {
267*54fd6939SJiyong Park return false;
268*54fd6939SJiyong Park }
269*54fd6939SJiyong Park
270*54fd6939SJiyong Park node = fdt_get_rcc_node(fdt);
271*54fd6939SJiyong Park if (node < 0) {
272*54fd6939SJiyong Park return false;
273*54fd6939SJiyong Park }
274*54fd6939SJiyong Park
275*54fd6939SJiyong Park return !!(fdt_get_status(node) & DT_SECURE);
276*54fd6939SJiyong Park }
277*54fd6939SJiyong Park
278*54fd6939SJiyong Park /*
279*54fd6939SJiyong Park * Get the clock ID of the given node in device tree.
280*54fd6939SJiyong Park * @param node: node offset
281*54fd6939SJiyong Park * @return: Clock ID on success, and a negative FDT/ERRNO error code on failure.
282*54fd6939SJiyong Park */
fdt_get_clock_id(int node)283*54fd6939SJiyong Park int fdt_get_clock_id(int node)
284*54fd6939SJiyong Park {
285*54fd6939SJiyong Park const fdt32_t *cuint;
286*54fd6939SJiyong Park void *fdt;
287*54fd6939SJiyong Park
288*54fd6939SJiyong Park if (fdt_get_address(&fdt) == 0) {
289*54fd6939SJiyong Park return -ENOENT;
290*54fd6939SJiyong Park }
291*54fd6939SJiyong Park
292*54fd6939SJiyong Park cuint = fdt_getprop(fdt, node, "clocks", NULL);
293*54fd6939SJiyong Park if (cuint == NULL) {
294*54fd6939SJiyong Park return -FDT_ERR_NOTFOUND;
295*54fd6939SJiyong Park }
296*54fd6939SJiyong Park
297*54fd6939SJiyong Park cuint++;
298*54fd6939SJiyong Park return (int)fdt32_to_cpu(*cuint);
299*54fd6939SJiyong Park }
300