xref: /rk3399_ARM-atf/plat/st/common/stm32mp_dt.c (revision 7ad6d362016a875eaee0d227365b74acd464050b)
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 gets the stdout path node.
140  * It reads the value indicated inside the device tree.
141  * Returns node offset on success and a negative FDT error code on failure.
142  ******************************************************************************/
143 static int dt_get_stdout_node_offset(void)
144 {
145 	int node;
146 	const char *cchar;
147 
148 	node = fdt_path_offset(fdt, "/secure-chosen");
149 	if (node < 0) {
150 		node = fdt_path_offset(fdt, "/chosen");
151 		if (node < 0) {
152 			return -FDT_ERR_NOTFOUND;
153 		}
154 	}
155 
156 	cchar = fdt_getprop(fdt, node, "stdout-path", NULL);
157 	if (cchar == NULL) {
158 		return -FDT_ERR_NOTFOUND;
159 	}
160 
161 	node = -FDT_ERR_NOTFOUND;
162 	if (strchr(cchar, (int)':') != NULL) {
163 		const char *name;
164 		char *str = (char *)cchar;
165 		int len = 0;
166 
167 		while (strncmp(":", str, 1)) {
168 			len++;
169 			str++;
170 		}
171 
172 		name = fdt_get_alias_namelen(fdt, cchar, len);
173 
174 		if (name != NULL) {
175 			node = fdt_path_offset(fdt, name);
176 		}
177 	} else {
178 		node = fdt_path_offset(fdt, cchar);
179 	}
180 
181 	return node;
182 }
183 
184 /*******************************************************************************
185  * This function gets the stdout pin configuration information from the DT.
186  * And then calls the sub-function to treat it and set GPIO registers.
187  * Returns 0 on success and a negative FDT error code on failure.
188  ******************************************************************************/
189 int dt_set_stdout_pinctrl(void)
190 {
191 	int node;
192 
193 	node = dt_get_stdout_node_offset();
194 	if (node < 0) {
195 		return -FDT_ERR_NOTFOUND;
196 	}
197 
198 	return dt_set_pinctrl_config(node);
199 }
200 
201 /*******************************************************************************
202  * This function fills the generic information from a given node.
203  ******************************************************************************/
204 void dt_fill_device_info(struct dt_node_info *info, int node)
205 {
206 	const fdt32_t *cuint;
207 
208 	assert(fdt_get_node_parent_address_cells(node) == 1);
209 
210 	cuint = fdt_getprop(fdt, node, "reg", NULL);
211 	if (cuint != NULL) {
212 		info->base = fdt32_to_cpu(*cuint);
213 	} else {
214 		info->base = 0;
215 	}
216 
217 	cuint = fdt_getprop(fdt, node, "clocks", NULL);
218 	if (cuint != NULL) {
219 		cuint++;
220 		info->clock = (int)fdt32_to_cpu(*cuint);
221 	} else {
222 		info->clock = -1;
223 	}
224 
225 	cuint = fdt_getprop(fdt, node, "resets", NULL);
226 	if (cuint != NULL) {
227 		cuint++;
228 		info->reset = (int)fdt32_to_cpu(*cuint);
229 	} else {
230 		info->reset = -1;
231 	}
232 
233 	info->status = fdt_get_status(node);
234 }
235 
236 /*******************************************************************************
237  * This function retrieve the generic information from DT.
238  * Returns node on success and a negative FDT error code on failure.
239  ******************************************************************************/
240 int dt_get_node(struct dt_node_info *info, int offset, const char *compat)
241 {
242 	int node;
243 
244 	node = fdt_node_offset_by_compatible(fdt, offset, compat);
245 	if (node < 0) {
246 		return -FDT_ERR_NOTFOUND;
247 	}
248 
249 	dt_fill_device_info(info, node);
250 
251 	return node;
252 }
253 
254 /*******************************************************************************
255  * This function gets the UART instance info of stdout from the DT.
256  * Returns node on success and a negative FDT error code on failure.
257  ******************************************************************************/
258 int dt_get_stdout_uart_info(struct dt_node_info *info)
259 {
260 	int node;
261 
262 	node = dt_get_stdout_node_offset();
263 	if (node < 0) {
264 		return -FDT_ERR_NOTFOUND;
265 	}
266 
267 	dt_fill_device_info(info, node);
268 
269 	return node;
270 }
271 
272 /*******************************************************************************
273  * This function gets DDR size information from the DT.
274  * Returns value in bytes on success, and 0 on failure.
275  ******************************************************************************/
276 uint32_t dt_get_ddr_size(void)
277 {
278 	int node;
279 
280 	node = fdt_node_offset_by_compatible(fdt, -1, DT_DDR_COMPAT);
281 	if (node < 0) {
282 		INFO("%s: Cannot read DDR node in DT\n", __func__);
283 		return 0;
284 	}
285 
286 	return fdt_read_uint32_default(fdt, node, "st,mem-size", 0);
287 }
288 
289 /*******************************************************************************
290  * This function gets DDRCTRL base address information from the DT.
291  * Returns value on success, and 0 on failure.
292  ******************************************************************************/
293 uintptr_t dt_get_ddrctrl_base(void)
294 {
295 	int node;
296 	uint32_t array[4];
297 
298 	node = fdt_node_offset_by_compatible(fdt, -1, DT_DDR_COMPAT);
299 	if (node < 0) {
300 		INFO("%s: Cannot read DDR node in DT\n", __func__);
301 		return 0;
302 	}
303 
304 	assert((fdt_get_node_parent_address_cells(node) == 1) &&
305 	       (fdt_get_node_parent_size_cells(node) == 1));
306 
307 	if (fdt_read_uint32_array(fdt, node, "reg", 4, array) < 0) {
308 		return 0;
309 	}
310 
311 	return array[0];
312 }
313 
314 /*******************************************************************************
315  * This function gets DDRPHYC base address information from the DT.
316  * Returns value on success, and 0 on failure.
317  ******************************************************************************/
318 uintptr_t dt_get_ddrphyc_base(void)
319 {
320 	int node;
321 	uint32_t array[4];
322 
323 	node = fdt_node_offset_by_compatible(fdt, -1, DT_DDR_COMPAT);
324 	if (node < 0) {
325 		INFO("%s: Cannot read DDR node in DT\n", __func__);
326 		return 0;
327 	}
328 
329 	assert((fdt_get_node_parent_address_cells(node) == 1) &&
330 	       (fdt_get_node_parent_size_cells(node) == 1));
331 
332 	if (fdt_read_uint32_array(fdt, node, "reg", 4, array) < 0) {
333 		return 0;
334 	}
335 
336 	return array[2];
337 }
338 
339 /*******************************************************************************
340  * This function gets PWR base address information from the DT.
341  * Returns value on success, and 0 on failure.
342  ******************************************************************************/
343 uintptr_t dt_get_pwr_base(void)
344 {
345 	int node;
346 	const fdt32_t *cuint;
347 
348 	node = fdt_node_offset_by_compatible(fdt, -1, DT_PWR_COMPAT);
349 	if (node < 0) {
350 		INFO("%s: Cannot read PWR node in DT\n", __func__);
351 		return 0;
352 	}
353 
354 	assert(fdt_get_node_parent_address_cells(node) == 1);
355 
356 	cuint = fdt_getprop(fdt, node, "reg", NULL);
357 	if (cuint == NULL) {
358 		return 0;
359 	}
360 
361 	return fdt32_to_cpu(*cuint);
362 }
363 
364 /*******************************************************************************
365  * This function gets PWR VDD regulator voltage information from the DT.
366  * Returns value in microvolts on success, and 0 on failure.
367  ******************************************************************************/
368 uint32_t dt_get_pwr_vdd_voltage(void)
369 {
370 	int node, pwr_regulators_node;
371 	const fdt32_t *cuint;
372 
373 	node = fdt_node_offset_by_compatible(fdt, -1, DT_PWR_COMPAT);
374 	if (node < 0) {
375 		INFO("%s: Cannot read PWR node in DT\n", __func__);
376 		return 0;
377 	}
378 
379 	pwr_regulators_node = fdt_subnode_offset(fdt, node, "pwr-regulators");
380 	if (pwr_regulators_node < 0) {
381 		INFO("%s: Cannot read pwr-regulators node in DT\n", __func__);
382 		return 0;
383 	}
384 
385 	cuint = fdt_getprop(fdt, pwr_regulators_node, "vdd-supply", NULL);
386 	if (cuint == NULL) {
387 		return 0;
388 	}
389 
390 	node = fdt_node_offset_by_phandle(fdt, fdt32_to_cpu(*cuint));
391 	if (node < 0) {
392 		return 0;
393 	}
394 
395 	cuint = fdt_getprop(fdt, node, "regulator-min-microvolt", NULL);
396 	if (cuint == NULL) {
397 		return 0;
398 	}
399 
400 	return fdt32_to_cpu(*cuint);
401 }
402 
403 /*******************************************************************************
404  * This function gets SYSCFG base address information from the DT.
405  * Returns value on success, and 0 on failure.
406  ******************************************************************************/
407 uintptr_t dt_get_syscfg_base(void)
408 {
409 	int node;
410 	const fdt32_t *cuint;
411 
412 	node = fdt_node_offset_by_compatible(fdt, -1, DT_SYSCFG_COMPAT);
413 	if (node < 0) {
414 		INFO("%s: Cannot read SYSCFG node in DT\n", __func__);
415 		return 0;
416 	}
417 
418 	assert(fdt_get_node_parent_address_cells(node) == 1);
419 
420 	cuint = fdt_getprop(fdt, node, "reg", NULL);
421 	if (cuint == NULL) {
422 		return 0;
423 	}
424 
425 	return fdt32_to_cpu(*cuint);
426 }
427 
428 /*******************************************************************************
429  * This function retrieves board model from DT
430  * Returns string taken from model node, NULL otherwise
431  ******************************************************************************/
432 const char *dt_get_board_model(void)
433 {
434 	int node = fdt_path_offset(fdt, "/");
435 
436 	if (node < 0) {
437 		return NULL;
438 	}
439 
440 	return (const char *)fdt_getprop(fdt, node, "model", NULL);
441 }
442