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