xref: /rk3399_ARM-atf/plat/st/common/stm32mp_dt.c (revision ea97bbf6a001b270fd0a25b4b0d0c382e277f3f8)
1c9d75b3cSYann Gautier /*
2f714ca80SYann Gautier  * Copyright (c) 2017-2021, ARM Limited and Contributors. All rights reserved.
3c9d75b3cSYann Gautier  *
4c9d75b3cSYann Gautier  * SPDX-License-Identifier: BSD-3-Clause
5c9d75b3cSYann Gautier  */
6c9d75b3cSYann Gautier 
7c9d75b3cSYann Gautier #include <assert.h>
8c9d75b3cSYann Gautier #include <errno.h>
9c9d75b3cSYann Gautier 
10c9d75b3cSYann Gautier #include <libfdt.h>
11c9d75b3cSYann Gautier 
12c9d75b3cSYann Gautier #include <platform_def.h>
13c9d75b3cSYann Gautier 
14c9d75b3cSYann Gautier #include <common/debug.h>
1552a616b4SAndre Przywara #include <common/fdt_wrappers.h>
16c9d75b3cSYann Gautier #include <drivers/st/stm32_gpio.h>
17c9d75b3cSYann Gautier #include <drivers/st/stm32mp1_ddr.h>
18c9d75b3cSYann Gautier #include <drivers/st/stm32mp1_ram.h>
19c9d75b3cSYann Gautier 
20c9d75b3cSYann Gautier #include <stm32mp_dt.h>
21c9d75b3cSYann Gautier 
22c20b0606SYann Gautier static void *fdt;
23c9d75b3cSYann Gautier 
24c9d75b3cSYann Gautier /*******************************************************************************
25c9d75b3cSYann Gautier  * This function checks device tree file with its header.
26c9d75b3cSYann Gautier  * Returns 0 on success and a negative FDT error code on failure.
27c9d75b3cSYann Gautier  ******************************************************************************/
28c20b0606SYann Gautier int dt_open_and_check(uintptr_t dt_addr)
29c9d75b3cSYann Gautier {
30c20b0606SYann Gautier 	int ret;
31c9d75b3cSYann Gautier 
32c20b0606SYann Gautier 	ret = fdt_check_header((void *)dt_addr);
33c9d75b3cSYann Gautier 	if (ret == 0) {
34c20b0606SYann Gautier 		fdt = (void *)dt_addr;
35c9d75b3cSYann Gautier 	}
36c9d75b3cSYann Gautier 
37c9d75b3cSYann Gautier 	return ret;
38c9d75b3cSYann Gautier }
39c9d75b3cSYann Gautier 
40c9d75b3cSYann Gautier /*******************************************************************************
41c9d75b3cSYann Gautier  * This function gets the address of the DT.
42c9d75b3cSYann Gautier  * If DT is OK, fdt_addr is filled with DT address.
43c9d75b3cSYann Gautier  * Returns 1 if success, 0 otherwise.
44c9d75b3cSYann Gautier  ******************************************************************************/
45c9d75b3cSYann Gautier int fdt_get_address(void **fdt_addr)
46c9d75b3cSYann Gautier {
47c20b0606SYann Gautier 	if (fdt == NULL) {
48c20b0606SYann Gautier 		return 0;
49c9d75b3cSYann Gautier 	}
50c9d75b3cSYann Gautier 
51c20b0606SYann Gautier 	*fdt_addr = fdt;
52c20b0606SYann Gautier 
53c20b0606SYann Gautier 	return 1;
54c9d75b3cSYann Gautier }
55c9d75b3cSYann Gautier 
56c9d75b3cSYann Gautier /*******************************************************************************
57c9d75b3cSYann Gautier  * This function check the presence of a node (generic use of fdt library).
58c9d75b3cSYann Gautier  * Returns true if present, else return false.
59c9d75b3cSYann Gautier  ******************************************************************************/
60c9d75b3cSYann Gautier bool fdt_check_node(int node)
61c9d75b3cSYann Gautier {
62c9d75b3cSYann Gautier 	int len;
63c9d75b3cSYann Gautier 	const char *cchar;
64c9d75b3cSYann Gautier 
65c9d75b3cSYann Gautier 	cchar = fdt_get_name(fdt, node, &len);
66c9d75b3cSYann Gautier 
67c9d75b3cSYann Gautier 	return (cchar != NULL) && (len >= 0);
68c9d75b3cSYann Gautier }
69c9d75b3cSYann Gautier 
70c9d75b3cSYann Gautier /*******************************************************************************
71c9d75b3cSYann Gautier  * This function return global node status (generic use of fdt library).
72c9d75b3cSYann Gautier  ******************************************************************************/
73c9d75b3cSYann Gautier uint8_t fdt_get_status(int node)
74c9d75b3cSYann Gautier {
75c9d75b3cSYann Gautier 	uint8_t status = DT_DISABLED;
76c9d75b3cSYann Gautier 	const char *cchar;
77c9d75b3cSYann Gautier 
78f714ca80SYann Gautier 	cchar = fdt_getprop(fdt, node, "status", NULL);
79c9d75b3cSYann Gautier 	if ((cchar == NULL) ||
80f714ca80SYann Gautier 	    (strncmp(cchar, "okay", strlen("okay")) == 0)) {
81c9d75b3cSYann Gautier 		status |= DT_NON_SECURE;
82c9d75b3cSYann Gautier 	}
83c9d75b3cSYann Gautier 
84f714ca80SYann Gautier 	cchar = fdt_getprop(fdt, node, "secure-status", NULL);
85c9d75b3cSYann Gautier 	if (cchar == NULL) {
86c9d75b3cSYann Gautier 		if (status == DT_NON_SECURE) {
87c9d75b3cSYann Gautier 			status |= DT_SECURE;
88c9d75b3cSYann Gautier 		}
89f714ca80SYann Gautier 	} else if (strncmp(cchar, "okay", strlen("okay")) == 0) {
90c9d75b3cSYann Gautier 		status |= DT_SECURE;
91c9d75b3cSYann Gautier 	}
92c9d75b3cSYann Gautier 
93c9d75b3cSYann Gautier 	return status;
94c9d75b3cSYann Gautier }
95c9d75b3cSYann Gautier 
96cd4941deSYann Gautier #if ENABLE_ASSERTIONS
97c9d75b3cSYann Gautier /*******************************************************************************
98dd85e572SLionel Debieve  * This function returns the address cells from the node parent.
99dd85e572SLionel Debieve  * Returns:
100dd85e572SLionel Debieve  * - #address-cells value if success.
101dd85e572SLionel Debieve  * - invalid value if error.
102dd85e572SLionel Debieve  * - a default value if undefined #address-cells property as per libfdt
103dd85e572SLionel Debieve  *   implementation.
104dd85e572SLionel Debieve  ******************************************************************************/
105cd4941deSYann Gautier static int fdt_get_node_parent_address_cells(int node)
106dd85e572SLionel Debieve {
107dd85e572SLionel Debieve 	int parent;
108dd85e572SLionel Debieve 
109dd85e572SLionel Debieve 	parent = fdt_parent_offset(fdt, node);
110dd85e572SLionel Debieve 	if (parent < 0) {
111dd85e572SLionel Debieve 		return -FDT_ERR_NOTFOUND;
112dd85e572SLionel Debieve 	}
113dd85e572SLionel Debieve 
114dd85e572SLionel Debieve 	return fdt_address_cells(fdt, parent);
115dd85e572SLionel Debieve }
116cd4941deSYann Gautier #endif
117dd85e572SLionel Debieve 
118dd85e572SLionel Debieve /*******************************************************************************
119c9d75b3cSYann Gautier  * This function gets the stdout pin configuration information from the DT.
120c9d75b3cSYann Gautier  * And then calls the sub-function to treat it and set GPIO registers.
121c9d75b3cSYann Gautier  * Returns 0 on success and a negative FDT error code on failure.
122c9d75b3cSYann Gautier  ******************************************************************************/
123c9d75b3cSYann Gautier int dt_set_stdout_pinctrl(void)
124c9d75b3cSYann Gautier {
125c9d75b3cSYann Gautier 	int node;
126c9d75b3cSYann Gautier 
1277a61114dSAndre Przywara 	node = fdt_get_stdout_node_offset(fdt);
128c9d75b3cSYann Gautier 	if (node < 0) {
129c9d75b3cSYann Gautier 		return -FDT_ERR_NOTFOUND;
130c9d75b3cSYann Gautier 	}
131c9d75b3cSYann Gautier 
132c9d75b3cSYann Gautier 	return dt_set_pinctrl_config(node);
133c9d75b3cSYann Gautier }
134c9d75b3cSYann Gautier 
135c9d75b3cSYann Gautier /*******************************************************************************
136c9d75b3cSYann Gautier  * This function fills the generic information from a given node.
137c9d75b3cSYann Gautier  ******************************************************************************/
138c9d75b3cSYann Gautier void dt_fill_device_info(struct dt_node_info *info, int node)
139c9d75b3cSYann Gautier {
140c9d75b3cSYann Gautier 	const fdt32_t *cuint;
141c9d75b3cSYann Gautier 
142dd85e572SLionel Debieve 	assert(fdt_get_node_parent_address_cells(node) == 1);
143dd85e572SLionel Debieve 
144c9d75b3cSYann Gautier 	cuint = fdt_getprop(fdt, node, "reg", NULL);
145c9d75b3cSYann Gautier 	if (cuint != NULL) {
146c9d75b3cSYann Gautier 		info->base = fdt32_to_cpu(*cuint);
147c9d75b3cSYann Gautier 	} else {
148c9d75b3cSYann Gautier 		info->base = 0;
149c9d75b3cSYann Gautier 	}
150c9d75b3cSYann Gautier 
151c9d75b3cSYann Gautier 	cuint = fdt_getprop(fdt, node, "clocks", NULL);
152c9d75b3cSYann Gautier 	if (cuint != NULL) {
153c9d75b3cSYann Gautier 		cuint++;
154c9d75b3cSYann Gautier 		info->clock = (int)fdt32_to_cpu(*cuint);
155c9d75b3cSYann Gautier 	} else {
156c9d75b3cSYann Gautier 		info->clock = -1;
157c9d75b3cSYann Gautier 	}
158c9d75b3cSYann Gautier 
159c9d75b3cSYann Gautier 	cuint = fdt_getprop(fdt, node, "resets", NULL);
160c9d75b3cSYann Gautier 	if (cuint != NULL) {
161c9d75b3cSYann Gautier 		cuint++;
162c9d75b3cSYann Gautier 		info->reset = (int)fdt32_to_cpu(*cuint);
163c9d75b3cSYann Gautier 	} else {
164c9d75b3cSYann Gautier 		info->reset = -1;
165c9d75b3cSYann Gautier 	}
166c9d75b3cSYann Gautier 
167c9d75b3cSYann Gautier 	info->status = fdt_get_status(node);
168c9d75b3cSYann Gautier }
169c9d75b3cSYann Gautier 
170c9d75b3cSYann Gautier /*******************************************************************************
171c9d75b3cSYann Gautier  * This function retrieve the generic information from DT.
172c9d75b3cSYann Gautier  * Returns node on success and a negative FDT error code on failure.
173c9d75b3cSYann Gautier  ******************************************************************************/
174c9d75b3cSYann Gautier int dt_get_node(struct dt_node_info *info, int offset, const char *compat)
175c9d75b3cSYann Gautier {
176c9d75b3cSYann Gautier 	int node;
177c9d75b3cSYann Gautier 
178c9d75b3cSYann Gautier 	node = fdt_node_offset_by_compatible(fdt, offset, compat);
179c9d75b3cSYann Gautier 	if (node < 0) {
180c9d75b3cSYann Gautier 		return -FDT_ERR_NOTFOUND;
181c9d75b3cSYann Gautier 	}
182c9d75b3cSYann Gautier 
183c9d75b3cSYann Gautier 	dt_fill_device_info(info, node);
184c9d75b3cSYann Gautier 
185c9d75b3cSYann Gautier 	return node;
186c9d75b3cSYann Gautier }
187c9d75b3cSYann Gautier 
188c9d75b3cSYann Gautier /*******************************************************************************
189c9d75b3cSYann Gautier  * This function gets the UART instance info of stdout from the DT.
190c9d75b3cSYann Gautier  * Returns node on success and a negative FDT error code on failure.
191c9d75b3cSYann Gautier  ******************************************************************************/
192c9d75b3cSYann Gautier int dt_get_stdout_uart_info(struct dt_node_info *info)
193c9d75b3cSYann Gautier {
194c9d75b3cSYann Gautier 	int node;
195c9d75b3cSYann Gautier 
1967a61114dSAndre Przywara 	node = fdt_get_stdout_node_offset(fdt);
197c9d75b3cSYann Gautier 	if (node < 0) {
198c9d75b3cSYann Gautier 		return -FDT_ERR_NOTFOUND;
199c9d75b3cSYann Gautier 	}
200c9d75b3cSYann Gautier 
201c9d75b3cSYann Gautier 	dt_fill_device_info(info, node);
202c9d75b3cSYann Gautier 
203c9d75b3cSYann Gautier 	return node;
204c9d75b3cSYann Gautier }
205c9d75b3cSYann Gautier 
206c9d75b3cSYann Gautier /*******************************************************************************
207*ea97bbf6SYann Gautier  * This function returns the node offset matching compatible string in the DT,
208*ea97bbf6SYann Gautier  * and also matching the reg property with the given address.
209*ea97bbf6SYann Gautier  * Returns value on success, and error value on failure.
210*ea97bbf6SYann Gautier  ******************************************************************************/
211*ea97bbf6SYann Gautier int dt_match_instance_by_compatible(const char *compatible, uintptr_t address)
212*ea97bbf6SYann Gautier {
213*ea97bbf6SYann Gautier 	int node;
214*ea97bbf6SYann Gautier 
215*ea97bbf6SYann Gautier 	fdt_for_each_compatible_node(fdt, node, compatible) {
216*ea97bbf6SYann Gautier 		const fdt32_t *cuint;
217*ea97bbf6SYann Gautier 
218*ea97bbf6SYann Gautier 		assert(fdt_get_node_parent_address_cells(node) == 1);
219*ea97bbf6SYann Gautier 
220*ea97bbf6SYann Gautier 		cuint = fdt_getprop(fdt, node, "reg", NULL);
221*ea97bbf6SYann Gautier 		if (cuint == NULL) {
222*ea97bbf6SYann Gautier 			continue;
223*ea97bbf6SYann Gautier 		}
224*ea97bbf6SYann Gautier 
225*ea97bbf6SYann Gautier 		if ((uintptr_t)fdt32_to_cpu(*cuint) == address) {
226*ea97bbf6SYann Gautier 			return node;
227*ea97bbf6SYann Gautier 		}
228*ea97bbf6SYann Gautier 	}
229*ea97bbf6SYann Gautier 
230*ea97bbf6SYann Gautier 	return -FDT_ERR_NOTFOUND;
231*ea97bbf6SYann Gautier }
232*ea97bbf6SYann Gautier 
233*ea97bbf6SYann Gautier /*******************************************************************************
234c9d75b3cSYann Gautier  * This function gets DDR size information from the DT.
235c9d75b3cSYann Gautier  * Returns value in bytes on success, and 0 on failure.
236c9d75b3cSYann Gautier  ******************************************************************************/
237c9d75b3cSYann Gautier uint32_t dt_get_ddr_size(void)
238c9d75b3cSYann Gautier {
23991ffc1deSLionel Debieve 	static uint32_t size;
240c9d75b3cSYann Gautier 	int node;
241c9d75b3cSYann Gautier 
24291ffc1deSLionel Debieve 	if (size != 0U) {
24391ffc1deSLionel Debieve 		return size;
24491ffc1deSLionel Debieve 	}
24591ffc1deSLionel Debieve 
246c9d75b3cSYann Gautier 	node = fdt_node_offset_by_compatible(fdt, -1, DT_DDR_COMPAT);
247c9d75b3cSYann Gautier 	if (node < 0) {
248c9d75b3cSYann Gautier 		INFO("%s: Cannot read DDR node in DT\n", __func__);
249c9d75b3cSYann Gautier 		return 0;
250c9d75b3cSYann Gautier 	}
251c9d75b3cSYann Gautier 
25291ffc1deSLionel Debieve 	size = fdt_read_uint32_default(fdt, node, "st,mem-size", 0U);
25391ffc1deSLionel Debieve 
25491ffc1deSLionel Debieve 	flush_dcache_range((uintptr_t)&size, sizeof(uint32_t));
25591ffc1deSLionel Debieve 
25691ffc1deSLionel Debieve 	return size;
257c9d75b3cSYann Gautier }
258c9d75b3cSYann Gautier 
259c9d75b3cSYann Gautier /*******************************************************************************
260f33b2433SYann Gautier  * This function gets PWR VDD regulator voltage information from the DT.
261f33b2433SYann Gautier  * Returns value in microvolts on success, and 0 on failure.
262f33b2433SYann Gautier  ******************************************************************************/
263f33b2433SYann Gautier uint32_t dt_get_pwr_vdd_voltage(void)
264f33b2433SYann Gautier {
265f33b2433SYann Gautier 	int node, pwr_regulators_node;
266f33b2433SYann Gautier 	const fdt32_t *cuint;
267f33b2433SYann Gautier 
268f33b2433SYann Gautier 	node = fdt_node_offset_by_compatible(fdt, -1, DT_PWR_COMPAT);
269f33b2433SYann Gautier 	if (node < 0) {
270f33b2433SYann Gautier 		INFO("%s: Cannot read PWR node in DT\n", __func__);
271f33b2433SYann Gautier 		return 0;
272f33b2433SYann Gautier 	}
273f33b2433SYann Gautier 
274f33b2433SYann Gautier 	pwr_regulators_node = fdt_subnode_offset(fdt, node, "pwr-regulators");
275e9d1e5afSYann Gautier 	if (pwr_regulators_node < 0) {
276f33b2433SYann Gautier 		INFO("%s: Cannot read pwr-regulators node in DT\n", __func__);
277f33b2433SYann Gautier 		return 0;
278f33b2433SYann Gautier 	}
279f33b2433SYann Gautier 
280f33b2433SYann Gautier 	cuint = fdt_getprop(fdt, pwr_regulators_node, "vdd-supply", NULL);
281f33b2433SYann Gautier 	if (cuint == NULL) {
282f33b2433SYann Gautier 		return 0;
283f33b2433SYann Gautier 	}
284f33b2433SYann Gautier 
285f33b2433SYann Gautier 	node = fdt_node_offset_by_phandle(fdt, fdt32_to_cpu(*cuint));
286f33b2433SYann Gautier 	if (node < 0) {
287f33b2433SYann Gautier 		return 0;
288f33b2433SYann Gautier 	}
289f33b2433SYann Gautier 
290f33b2433SYann Gautier 	cuint = fdt_getprop(fdt, node, "regulator-min-microvolt", NULL);
291f33b2433SYann Gautier 	if (cuint == NULL) {
292f33b2433SYann Gautier 		return 0;
293f33b2433SYann Gautier 	}
294f33b2433SYann Gautier 
295f33b2433SYann Gautier 	return fdt32_to_cpu(*cuint);
296f33b2433SYann Gautier }
297f33b2433SYann Gautier 
298f33b2433SYann Gautier /*******************************************************************************
299c9d75b3cSYann Gautier  * This function retrieves board model from DT
300c9d75b3cSYann Gautier  * Returns string taken from model node, NULL otherwise
301c9d75b3cSYann Gautier  ******************************************************************************/
302c9d75b3cSYann Gautier const char *dt_get_board_model(void)
303c9d75b3cSYann Gautier {
304c9d75b3cSYann Gautier 	int node = fdt_path_offset(fdt, "/");
305c9d75b3cSYann Gautier 
306c9d75b3cSYann Gautier 	if (node < 0) {
307c9d75b3cSYann Gautier 		return NULL;
308c9d75b3cSYann Gautier 	}
309c9d75b3cSYann Gautier 
310c9d75b3cSYann Gautier 	return (const char *)fdt_getprop(fdt, node, "model", NULL);
311c9d75b3cSYann Gautier }
312ccc199edSEtienne Carriere 
313ccc199edSEtienne Carriere /*******************************************************************************
314ccc199edSEtienne Carriere  * This function gets the pin count for a GPIO bank based from the FDT.
315ccc199edSEtienne Carriere  * It also checks node consistency.
316ccc199edSEtienne Carriere  ******************************************************************************/
317ccc199edSEtienne Carriere int fdt_get_gpio_bank_pin_count(unsigned int bank)
318ccc199edSEtienne Carriere {
319ccc199edSEtienne Carriere 	int pinctrl_node;
320ccc199edSEtienne Carriere 	int node;
321ccc199edSEtienne Carriere 	uint32_t bank_offset;
322ccc199edSEtienne Carriere 
323ccc199edSEtienne Carriere 	pinctrl_node = stm32_get_gpio_bank_pinctrl_node(fdt, bank);
324ccc199edSEtienne Carriere 	if (pinctrl_node < 0) {
325ccc199edSEtienne Carriere 		return -FDT_ERR_NOTFOUND;
326ccc199edSEtienne Carriere 	}
327ccc199edSEtienne Carriere 
328ccc199edSEtienne Carriere 	bank_offset = stm32_get_gpio_bank_offset(bank);
329ccc199edSEtienne Carriere 
330ccc199edSEtienne Carriere 	fdt_for_each_subnode(node, fdt, pinctrl_node) {
331ccc199edSEtienne Carriere 		const fdt32_t *cuint;
332ccc199edSEtienne Carriere 
333ccc199edSEtienne Carriere 		if (fdt_getprop(fdt, node, "gpio-controller", NULL) == NULL) {
334ccc199edSEtienne Carriere 			continue;
335ccc199edSEtienne Carriere 		}
336ccc199edSEtienne Carriere 
337ccc199edSEtienne Carriere 		cuint = fdt_getprop(fdt, node, "reg", NULL);
338ccc199edSEtienne Carriere 		if (cuint == NULL) {
339ccc199edSEtienne Carriere 			continue;
340ccc199edSEtienne Carriere 		}
341ccc199edSEtienne Carriere 
342ccc199edSEtienne Carriere 		if (fdt32_to_cpu(*cuint) != bank_offset) {
343ccc199edSEtienne Carriere 			continue;
344ccc199edSEtienne Carriere 		}
345ccc199edSEtienne Carriere 
346ccc199edSEtienne Carriere 		if (fdt_get_status(node) == DT_DISABLED) {
347ccc199edSEtienne Carriere 			return 0;
348ccc199edSEtienne Carriere 		}
349ccc199edSEtienne Carriere 
350ccc199edSEtienne Carriere 		cuint = fdt_getprop(fdt, node, "ngpios", NULL);
351ccc199edSEtienne Carriere 		if (cuint == NULL) {
352ccc199edSEtienne Carriere 			return -FDT_ERR_NOTFOUND;
353ccc199edSEtienne Carriere 		}
354ccc199edSEtienne Carriere 
355ccc199edSEtienne Carriere 		return (int)fdt32_to_cpu(*cuint);
356ccc199edSEtienne Carriere 	}
357ccc199edSEtienne Carriere 
358ccc199edSEtienne Carriere 	return 0;
359ccc199edSEtienne Carriere }
360