• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2017-2019, STMicroelectronics - All Rights Reserved
3  *
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 
13 #include <drivers/st/stm32_gpio.h>
14 #include <drivers/st/stm32mp_clkfunc.h>
15 
16 #define DT_STGEN_COMPAT		"st,stm32-stgen"
17 
18 /*
19  * 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  */
fdt_osc_read_freq(const char * name,uint32_t * freq)24 int 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  */
fdt_osc_read_bool(enum stm32mp_osc_id osc_id,const char * prop_name)73 bool 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  */
fdt_osc_read_uint32_default(enum stm32mp_osc_id osc_id,const char * prop_name,uint32_t dflt_value)120 uint32_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 
153 		return fdt_read_uint32_default(subnode, prop_name, dflt_value);
154 	}
155 
156 	return dflt_value;
157 }
158 
159 /*
160  * Get the RCC node offset from the device tree
161  * @param fdt: Device tree reference
162  * @return: Node offset or a negative value on error
163  */
fdt_get_rcc_node(void * fdt)164 int fdt_get_rcc_node(void *fdt)
165 {
166 	return fdt_node_offset_by_compatible(fdt, -1, DT_RCC_CLK_COMPAT);
167 }
168 
169 /*
170  * Get the RCC base address from the device tree
171  * @return: RCC address or 0 on error
172  */
fdt_rcc_read_addr(void)173 uint32_t fdt_rcc_read_addr(void)
174 {
175 	int node;
176 	void *fdt;
177 	const fdt32_t *cuint;
178 
179 	if (fdt_get_address(&fdt) == 0) {
180 		return 0;
181 	}
182 
183 	node = fdt_get_rcc_node(fdt);
184 	if (node < 0) {
185 		return 0;
186 	}
187 
188 	cuint = fdt_getprop(fdt, node, "reg", NULL);
189 	if (cuint == NULL) {
190 		return 0;
191 	}
192 
193 	return fdt32_to_cpu(*cuint);
194 }
195 
196 /*
197  * Read a series of parameters in rcc-clk section in device tree
198  * @param prop_name: Name of the RCC property to be read
199  * @param array: the array to store the property parameters
200  * @param count: number of parameters to be read
201  * @return: 0 on succes or a negative value on error
202  */
fdt_rcc_read_uint32_array(const char * prop_name,uint32_t * array,uint32_t count)203 int fdt_rcc_read_uint32_array(const char *prop_name,
204 			      uint32_t *array, uint32_t count)
205 {
206 	int node;
207 	void *fdt;
208 
209 	if (fdt_get_address(&fdt) == 0) {
210 		return -ENOENT;
211 	}
212 
213 	node = fdt_get_rcc_node(fdt);
214 	if (node < 0) {
215 		return -FDT_ERR_NOTFOUND;
216 	}
217 
218 	return fdt_read_uint32_array(node, prop_name, array, count);
219 }
220 
221 /*
222  * Get the subnode offset in rcc-clk section from its name in device tree
223  * @param name: name of the RCC property
224  * @return: offset on success, and a negative FDT/ERRNO error code on failure.
225  */
fdt_rcc_subnode_offset(const char * name)226 int fdt_rcc_subnode_offset(const char *name)
227 {
228 	int node, subnode;
229 	void *fdt;
230 
231 	if (fdt_get_address(&fdt) == 0) {
232 		return -ENOENT;
233 	}
234 
235 	node = fdt_get_rcc_node(fdt);
236 	if (node < 0) {
237 		return -FDT_ERR_NOTFOUND;
238 	}
239 
240 	subnode = fdt_subnode_offset(fdt, node, name);
241 	if (subnode <= 0) {
242 		return -FDT_ERR_NOTFOUND;
243 	}
244 
245 	return subnode;
246 }
247 
248 /*
249  * Get the pointer to a rcc-clk property from its name.
250  * @param name: name of the RCC property
251  * @param lenp: stores the length of the property.
252  * @return: pointer to the property on success, and NULL value on failure.
253  */
fdt_rcc_read_prop(const char * prop_name,int * lenp)254 const fdt32_t *fdt_rcc_read_prop(const char *prop_name, int *lenp)
255 {
256 	const fdt32_t *cuint;
257 	int node, len;
258 	void *fdt;
259 
260 	if (fdt_get_address(&fdt) == 0) {
261 		return NULL;
262 	}
263 
264 	node = fdt_get_rcc_node(fdt);
265 	if (node < 0) {
266 		return NULL;
267 	}
268 
269 	cuint = fdt_getprop(fdt, node, prop_name, &len);
270 	if (cuint == NULL) {
271 		return NULL;
272 	}
273 
274 	*lenp = len;
275 	return cuint;
276 }
277 
278 /*
279  * Get the secure status for rcc node in device tree.
280  * @return: true if rcc is available from secure world, false if not.
281  */
fdt_get_rcc_secure_status(void)282 bool fdt_get_rcc_secure_status(void)
283 {
284 	int node;
285 	void *fdt;
286 
287 	if (fdt_get_address(&fdt) == 0) {
288 		return false;
289 	}
290 
291 	node = fdt_get_rcc_node(fdt);
292 	if (node < 0) {
293 		return false;
294 	}
295 
296 	return !!(fdt_get_status(node) & DT_SECURE);
297 }
298 
299 /*
300  * Get the stgen base address.
301  * @return: address of stgen on success, and NULL value on failure.
302  */
fdt_get_stgen_base(void)303 uintptr_t fdt_get_stgen_base(void)
304 {
305 	int node;
306 	const fdt32_t *cuint;
307 	void *fdt;
308 
309 	if (fdt_get_address(&fdt) == 0) {
310 		return 0;
311 	}
312 
313 	node = fdt_node_offset_by_compatible(fdt, -1, DT_STGEN_COMPAT);
314 	if (node < 0) {
315 		return 0;
316 	}
317 
318 	cuint = fdt_getprop(fdt, node, "reg", NULL);
319 	if (cuint == NULL) {
320 		return 0;
321 	}
322 
323 	return fdt32_to_cpu(*cuint);
324 }
325 
326 /*
327  * Get the clock ID of the given node in device tree.
328  * @param node: node offset
329  * @return: Clock ID on success, and a negative FDT/ERRNO error code on failure.
330  */
fdt_get_clock_id(int node)331 int fdt_get_clock_id(int node)
332 {
333 	const fdt32_t *cuint;
334 	void *fdt;
335 
336 	if (fdt_get_address(&fdt) == 0) {
337 		return -ENOENT;
338 	}
339 
340 	cuint = fdt_getprop(fdt, node, "clocks", NULL);
341 	if (cuint == NULL) {
342 		return -FDT_ERR_NOTFOUND;
343 	}
344 
345 	cuint++;
346 	return (int)fdt32_to_cpu(*cuint);
347 }
348