xref: /rk3399_ARM-atf/plat/st/common/stm32mp_dt.c (revision 0a0a7a9ac82cb79af91f098cedc69cc67bca3978)
1 /*
2  * Copyright (c) 2017-2020, ARM Limited and Contributors. All rights reserved.
3  *
4  * SPDX-License-Identifier: BSD-3-Clause
5  */
6 
7 #include <assert.h>
8 #include <errno.h>
9 
10 #include <libfdt.h>
11 
12 #include <platform_def.h>
13 
14 #include <common/debug.h>
15 #include <drivers/st/stm32_gpio.h>
16 #include <drivers/st/stm32mp1_ddr.h>
17 #include <drivers/st/stm32mp1_ram.h>
18 
19 #include <stm32mp_dt.h>
20 
21 static int fdt_checked;
22 
23 static void *fdt = (void *)(uintptr_t)STM32MP_DTB_BASE;
24 
25 /*******************************************************************************
26  * This function checks device tree file with its header.
27  * Returns 0 on success and a negative FDT error code on failure.
28  ******************************************************************************/
29 int dt_open_and_check(void)
30 {
31 	int ret = fdt_check_header(fdt);
32 
33 	if (ret == 0) {
34 		fdt_checked = 1;
35 	}
36 
37 	return ret;
38 }
39 
40 /*******************************************************************************
41  * This function gets the address of the DT.
42  * If DT is OK, fdt_addr is filled with DT address.
43  * Returns 1 if success, 0 otherwise.
44  ******************************************************************************/
45 int fdt_get_address(void **fdt_addr)
46 {
47 	if (fdt_checked == 1) {
48 		*fdt_addr = fdt;
49 	}
50 
51 	return fdt_checked;
52 }
53 
54 /*******************************************************************************
55  * This function check the presence of a node (generic use of fdt library).
56  * Returns true if present, else return false.
57  ******************************************************************************/
58 bool fdt_check_node(int node)
59 {
60 	int len;
61 	const char *cchar;
62 
63 	cchar = fdt_get_name(fdt, node, &len);
64 
65 	return (cchar != NULL) && (len >= 0);
66 }
67 
68 /*******************************************************************************
69  * This function return global node status (generic use of fdt library).
70  ******************************************************************************/
71 uint8_t fdt_get_status(int node)
72 {
73 	uint8_t status = DT_DISABLED;
74 	int len;
75 	const char *cchar;
76 
77 	cchar = fdt_getprop(fdt, node, "status", &len);
78 	if ((cchar == NULL) ||
79 	    (strncmp(cchar, "okay", (size_t)len) == 0)) {
80 		status |= DT_NON_SECURE;
81 	}
82 
83 	cchar = fdt_getprop(fdt, node, "secure-status", &len);
84 	if (cchar == NULL) {
85 		if (status == DT_NON_SECURE) {
86 			status |= DT_SECURE;
87 		}
88 	} else if (strncmp(cchar, "okay", (size_t)len) == 0) {
89 		status |= DT_SECURE;
90 	}
91 
92 	return status;
93 }
94 
95 #if ENABLE_ASSERTIONS
96 /*******************************************************************************
97  * This function returns the address cells from the node parent.
98  * Returns:
99  * - #address-cells value if success.
100  * - invalid value if error.
101  * - a default value if undefined #address-cells property as per libfdt
102  *   implementation.
103  ******************************************************************************/
104 static int fdt_get_node_parent_address_cells(int node)
105 {
106 	int parent;
107 
108 	parent = fdt_parent_offset(fdt, node);
109 	if (parent < 0) {
110 		return -FDT_ERR_NOTFOUND;
111 	}
112 
113 	return fdt_address_cells(fdt, parent);
114 }
115 
116 /*******************************************************************************
117  * This function returns the size cells from the node parent.
118  * Returns:
119  * - #size-cells value if success.
120  * - invalid value if error.
121  * - a default value if undefined #size-cells property as per libfdt
122  *   implementation.
123  ******************************************************************************/
124 static int fdt_get_node_parent_size_cells(int node)
125 {
126 	int parent;
127 
128 	parent = fdt_parent_offset(fdt, node);
129 	if (parent < 0) {
130 		return -FDT_ERR_NOTFOUND;
131 	}
132 
133 	return fdt_size_cells(fdt, parent);
134 }
135 #endif
136 
137 /*******************************************************************************
138  * This function reads a value of a node property (generic use of fdt
139  * library).
140  * Returns value if success, and a default value if property not found.
141  * Default value is passed as parameter.
142  ******************************************************************************/
143 uint32_t fdt_read_uint32_default(int node, const char *prop_name,
144 				 uint32_t dflt_value)
145 {
146 	const fdt32_t *cuint;
147 	int lenp;
148 
149 	cuint = fdt_getprop(fdt, node, prop_name, &lenp);
150 	if (cuint == NULL) {
151 		return dflt_value;
152 	}
153 
154 	return fdt32_to_cpu(*cuint);
155 }
156 
157 /*******************************************************************************
158  * This function reads a series of parameters in a node property
159  * (generic use of fdt library).
160  * It reads the values inside the device tree, from property name and node.
161  * The number of parameters is also indicated as entry parameter.
162  * Returns 0 on success and a negative FDT error code on failure.
163  * If success, values are stored at the third parameter address.
164  ******************************************************************************/
165 int fdt_read_uint32_array(int node, const char *prop_name, uint32_t *array,
166 			  uint32_t count)
167 {
168 	const fdt32_t *cuint;
169 	int len;
170 	uint32_t i;
171 
172 	cuint = fdt_getprop(fdt, node, prop_name, &len);
173 	if (cuint == NULL) {
174 		return -FDT_ERR_NOTFOUND;
175 	}
176 
177 	if ((uint32_t)len != (count * sizeof(uint32_t))) {
178 		return -FDT_ERR_BADLAYOUT;
179 	}
180 
181 	for (i = 0; i < ((uint32_t)len / sizeof(uint32_t)); i++) {
182 		*array = fdt32_to_cpu(*cuint);
183 		array++;
184 		cuint++;
185 	}
186 
187 	return 0;
188 }
189 
190 /*******************************************************************************
191  * This function fills reg node info (base & size) with an index found by
192  * checking the reg-names node.
193  * Returns 0 on success and a negative FDT error code on failure.
194  ******************************************************************************/
195 int fdt_get_reg_props_by_name(int node, const char *name, uintptr_t *base,
196 			      size_t *size)
197 {
198 	const fdt32_t *cuint;
199 	int index, len;
200 
201 	assert((fdt_get_node_parent_address_cells(node) == 1) &&
202 	       (fdt_get_node_parent_size_cells(node) == 1));
203 
204 	index = fdt_stringlist_search(fdt, node, "reg-names", name);
205 	if (index < 0) {
206 		return index;
207 	}
208 
209 	cuint = fdt_getprop(fdt, node, "reg", &len);
210 	if (cuint == NULL) {
211 		return -FDT_ERR_NOTFOUND;
212 	}
213 
214 	if ((index * (int)sizeof(uint32_t)) > len) {
215 		return -FDT_ERR_BADVALUE;
216 	}
217 
218 	cuint += index << 1;
219 	if (base != NULL) {
220 		*base = fdt32_to_cpu(*cuint);
221 	}
222 	cuint++;
223 	if (size != NULL) {
224 		*size = fdt32_to_cpu(*cuint);
225 	}
226 
227 	return 0;
228 }
229 
230 /*******************************************************************************
231  * This function gets the stdout path node.
232  * It reads the value indicated inside the device tree.
233  * Returns node offset on success and a negative FDT error code on failure.
234  ******************************************************************************/
235 static int dt_get_stdout_node_offset(void)
236 {
237 	int node;
238 	const char *cchar;
239 
240 	node = fdt_path_offset(fdt, "/secure-chosen");
241 	if (node < 0) {
242 		node = fdt_path_offset(fdt, "/chosen");
243 		if (node < 0) {
244 			return -FDT_ERR_NOTFOUND;
245 		}
246 	}
247 
248 	cchar = fdt_getprop(fdt, node, "stdout-path", NULL);
249 	if (cchar == NULL) {
250 		return -FDT_ERR_NOTFOUND;
251 	}
252 
253 	node = -FDT_ERR_NOTFOUND;
254 	if (strchr(cchar, (int)':') != NULL) {
255 		const char *name;
256 		char *str = (char *)cchar;
257 		int len = 0;
258 
259 		while (strncmp(":", str, 1)) {
260 			len++;
261 			str++;
262 		}
263 
264 		name = fdt_get_alias_namelen(fdt, cchar, len);
265 
266 		if (name != NULL) {
267 			node = fdt_path_offset(fdt, name);
268 		}
269 	} else {
270 		node = fdt_path_offset(fdt, cchar);
271 	}
272 
273 	return node;
274 }
275 
276 /*******************************************************************************
277  * This function gets the stdout pin configuration information from the DT.
278  * And then calls the sub-function to treat it and set GPIO registers.
279  * Returns 0 on success and a negative FDT error code on failure.
280  ******************************************************************************/
281 int dt_set_stdout_pinctrl(void)
282 {
283 	int node;
284 
285 	node = dt_get_stdout_node_offset();
286 	if (node < 0) {
287 		return -FDT_ERR_NOTFOUND;
288 	}
289 
290 	return dt_set_pinctrl_config(node);
291 }
292 
293 /*******************************************************************************
294  * This function fills the generic information from a given node.
295  ******************************************************************************/
296 void dt_fill_device_info(struct dt_node_info *info, int node)
297 {
298 	const fdt32_t *cuint;
299 
300 	assert(fdt_get_node_parent_address_cells(node) == 1);
301 
302 	cuint = fdt_getprop(fdt, node, "reg", NULL);
303 	if (cuint != NULL) {
304 		info->base = fdt32_to_cpu(*cuint);
305 	} else {
306 		info->base = 0;
307 	}
308 
309 	cuint = fdt_getprop(fdt, node, "clocks", NULL);
310 	if (cuint != NULL) {
311 		cuint++;
312 		info->clock = (int)fdt32_to_cpu(*cuint);
313 	} else {
314 		info->clock = -1;
315 	}
316 
317 	cuint = fdt_getprop(fdt, node, "resets", NULL);
318 	if (cuint != NULL) {
319 		cuint++;
320 		info->reset = (int)fdt32_to_cpu(*cuint);
321 	} else {
322 		info->reset = -1;
323 	}
324 
325 	info->status = fdt_get_status(node);
326 }
327 
328 /*******************************************************************************
329  * This function retrieve the generic information from DT.
330  * Returns node on success and a negative FDT error code on failure.
331  ******************************************************************************/
332 int dt_get_node(struct dt_node_info *info, int offset, const char *compat)
333 {
334 	int node;
335 
336 	node = fdt_node_offset_by_compatible(fdt, offset, compat);
337 	if (node < 0) {
338 		return -FDT_ERR_NOTFOUND;
339 	}
340 
341 	dt_fill_device_info(info, node);
342 
343 	return node;
344 }
345 
346 /*******************************************************************************
347  * This function gets the UART instance info of stdout from the DT.
348  * Returns node on success and a negative FDT error code on failure.
349  ******************************************************************************/
350 int dt_get_stdout_uart_info(struct dt_node_info *info)
351 {
352 	int node;
353 
354 	node = dt_get_stdout_node_offset();
355 	if (node < 0) {
356 		return -FDT_ERR_NOTFOUND;
357 	}
358 
359 	dt_fill_device_info(info, node);
360 
361 	return node;
362 }
363 
364 /*******************************************************************************
365  * This function gets DDR size information from the DT.
366  * Returns value in bytes on success, and 0 on failure.
367  ******************************************************************************/
368 uint32_t dt_get_ddr_size(void)
369 {
370 	int node;
371 
372 	node = fdt_node_offset_by_compatible(fdt, -1, DT_DDR_COMPAT);
373 	if (node < 0) {
374 		INFO("%s: Cannot read DDR node in DT\n", __func__);
375 		return 0;
376 	}
377 
378 	return fdt_read_uint32_default(node, "st,mem-size", 0);
379 }
380 
381 /*******************************************************************************
382  * This function gets DDRCTRL base address information from the DT.
383  * Returns value on success, and 0 on failure.
384  ******************************************************************************/
385 uintptr_t dt_get_ddrctrl_base(void)
386 {
387 	int node;
388 	uint32_t array[4];
389 
390 	node = fdt_node_offset_by_compatible(fdt, -1, DT_DDR_COMPAT);
391 	if (node < 0) {
392 		INFO("%s: Cannot read DDR node in DT\n", __func__);
393 		return 0;
394 	}
395 
396 	assert((fdt_get_node_parent_address_cells(node) == 1) &&
397 	       (fdt_get_node_parent_size_cells(node) == 1));
398 
399 	if (fdt_read_uint32_array(node, "reg", array, 4) < 0) {
400 		return 0;
401 	}
402 
403 	return array[0];
404 }
405 
406 /*******************************************************************************
407  * This function gets DDRPHYC base address information from the DT.
408  * Returns value on success, and 0 on failure.
409  ******************************************************************************/
410 uintptr_t dt_get_ddrphyc_base(void)
411 {
412 	int node;
413 	uint32_t array[4];
414 
415 	node = fdt_node_offset_by_compatible(fdt, -1, DT_DDR_COMPAT);
416 	if (node < 0) {
417 		INFO("%s: Cannot read DDR node in DT\n", __func__);
418 		return 0;
419 	}
420 
421 	assert((fdt_get_node_parent_address_cells(node) == 1) &&
422 	       (fdt_get_node_parent_size_cells(node) == 1));
423 
424 	if (fdt_read_uint32_array(node, "reg", array, 4) < 0) {
425 		return 0;
426 	}
427 
428 	return array[2];
429 }
430 
431 /*******************************************************************************
432  * This function gets PWR base address information from the DT.
433  * Returns value on success, and 0 on failure.
434  ******************************************************************************/
435 uintptr_t dt_get_pwr_base(void)
436 {
437 	int node;
438 	const fdt32_t *cuint;
439 
440 	node = fdt_node_offset_by_compatible(fdt, -1, DT_PWR_COMPAT);
441 	if (node < 0) {
442 		INFO("%s: Cannot read PWR node in DT\n", __func__);
443 		return 0;
444 	}
445 
446 	assert(fdt_get_node_parent_address_cells(node) == 1);
447 
448 	cuint = fdt_getprop(fdt, node, "reg", NULL);
449 	if (cuint == NULL) {
450 		return 0;
451 	}
452 
453 	return fdt32_to_cpu(*cuint);
454 }
455 
456 /*******************************************************************************
457  * This function gets PWR VDD regulator voltage information from the DT.
458  * Returns value in microvolts on success, and 0 on failure.
459  ******************************************************************************/
460 uint32_t dt_get_pwr_vdd_voltage(void)
461 {
462 	int node, pwr_regulators_node;
463 	const fdt32_t *cuint;
464 
465 	node = fdt_node_offset_by_compatible(fdt, -1, DT_PWR_COMPAT);
466 	if (node < 0) {
467 		INFO("%s: Cannot read PWR node in DT\n", __func__);
468 		return 0;
469 	}
470 
471 	pwr_regulators_node = fdt_subnode_offset(fdt, node, "pwr-regulators");
472 	if (pwr_regulators_node < 0) {
473 		INFO("%s: Cannot read pwr-regulators node in DT\n", __func__);
474 		return 0;
475 	}
476 
477 	cuint = fdt_getprop(fdt, pwr_regulators_node, "vdd-supply", NULL);
478 	if (cuint == NULL) {
479 		return 0;
480 	}
481 
482 	node = fdt_node_offset_by_phandle(fdt, fdt32_to_cpu(*cuint));
483 	if (node < 0) {
484 		return 0;
485 	}
486 
487 	cuint = fdt_getprop(fdt, node, "regulator-min-microvolt", NULL);
488 	if (cuint == NULL) {
489 		return 0;
490 	}
491 
492 	return fdt32_to_cpu(*cuint);
493 }
494 
495 /*******************************************************************************
496  * This function gets SYSCFG base address information from the DT.
497  * Returns value on success, and 0 on failure.
498  ******************************************************************************/
499 uintptr_t dt_get_syscfg_base(void)
500 {
501 	int node;
502 	const fdt32_t *cuint;
503 
504 	node = fdt_node_offset_by_compatible(fdt, -1, DT_SYSCFG_COMPAT);
505 	if (node < 0) {
506 		INFO("%s: Cannot read SYSCFG node in DT\n", __func__);
507 		return 0;
508 	}
509 
510 	assert(fdt_get_node_parent_address_cells(node) == 1);
511 
512 	cuint = fdt_getprop(fdt, node, "reg", NULL);
513 	if (cuint == NULL) {
514 		return 0;
515 	}
516 
517 	return fdt32_to_cpu(*cuint);
518 }
519 
520 /*******************************************************************************
521  * This function retrieves board model from DT
522  * Returns string taken from model node, NULL otherwise
523  ******************************************************************************/
524 const char *dt_get_board_model(void)
525 {
526 	int node = fdt_path_offset(fdt, "/");
527 
528 	if (node < 0) {
529 		return NULL;
530 	}
531 
532 	return (const char *)fdt_getprop(fdt, node, "model", NULL);
533 }
534