xref: /rk3399_ARM-atf/plat/st/common/stm32mp_dt.c (revision ae3ce8b28eac73e9a41fdb28424d9f0f4b5f200e)
1c9d75b3cSYann Gautier /*
2*ae3ce8b2SLionel Debieve  * Copyright (c) 2017-2022, 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 <common/debug.h>
1152a616b4SAndre Przywara #include <common/fdt_wrappers.h>
12c39c658eSYann Gautier #include <drivers/st/regulator.h>
13c9d75b3cSYann Gautier #include <drivers/st/stm32_gpio.h>
14c9d75b3cSYann Gautier #include <drivers/st/stm32mp1_ddr.h>
15c9d75b3cSYann Gautier #include <drivers/st/stm32mp1_ram.h>
16c39c658eSYann Gautier #include <libfdt.h>
17c9d75b3cSYann Gautier 
18c39c658eSYann Gautier #include <platform_def.h>
19c9d75b3cSYann Gautier #include <stm32mp_dt.h>
20c9d75b3cSYann Gautier 
21c20b0606SYann Gautier static void *fdt;
22c9d75b3cSYann Gautier 
23c9d75b3cSYann Gautier /*******************************************************************************
24c9d75b3cSYann Gautier  * This function checks device tree file with its header.
25c9d75b3cSYann Gautier  * Returns 0 on success and a negative FDT error code on failure.
26c9d75b3cSYann Gautier  ******************************************************************************/
27c20b0606SYann Gautier int dt_open_and_check(uintptr_t dt_addr)
28c9d75b3cSYann Gautier {
29c20b0606SYann Gautier 	int ret;
30c9d75b3cSYann Gautier 
31c20b0606SYann Gautier 	ret = fdt_check_header((void *)dt_addr);
32c9d75b3cSYann Gautier 	if (ret == 0) {
33c20b0606SYann Gautier 		fdt = (void *)dt_addr;
34c9d75b3cSYann Gautier 	}
35c9d75b3cSYann Gautier 
36c9d75b3cSYann Gautier 	return ret;
37c9d75b3cSYann Gautier }
38c9d75b3cSYann Gautier 
39c9d75b3cSYann Gautier /*******************************************************************************
40c9d75b3cSYann Gautier  * This function gets the address of the DT.
41c9d75b3cSYann Gautier  * If DT is OK, fdt_addr is filled with DT address.
42c9d75b3cSYann Gautier  * Returns 1 if success, 0 otherwise.
43c9d75b3cSYann Gautier  ******************************************************************************/
44c9d75b3cSYann Gautier int fdt_get_address(void **fdt_addr)
45c9d75b3cSYann Gautier {
46c20b0606SYann Gautier 	if (fdt == NULL) {
47c20b0606SYann Gautier 		return 0;
48c9d75b3cSYann Gautier 	}
49c9d75b3cSYann Gautier 
50c20b0606SYann Gautier 	*fdt_addr = fdt;
51c20b0606SYann Gautier 
52c20b0606SYann Gautier 	return 1;
53c9d75b3cSYann Gautier }
54c9d75b3cSYann Gautier 
55c9d75b3cSYann Gautier /*******************************************************************************
56c9d75b3cSYann Gautier  * This function check the presence of a node (generic use of fdt library).
57c9d75b3cSYann Gautier  * Returns true if present, else return false.
58c9d75b3cSYann Gautier  ******************************************************************************/
59c9d75b3cSYann Gautier bool fdt_check_node(int node)
60c9d75b3cSYann Gautier {
61c9d75b3cSYann Gautier 	int len;
62c9d75b3cSYann Gautier 	const char *cchar;
63c9d75b3cSYann Gautier 
64c9d75b3cSYann Gautier 	cchar = fdt_get_name(fdt, node, &len);
65c9d75b3cSYann Gautier 
66c9d75b3cSYann Gautier 	return (cchar != NULL) && (len >= 0);
67c9d75b3cSYann Gautier }
68c9d75b3cSYann Gautier 
69c9d75b3cSYann Gautier /*******************************************************************************
70c9d75b3cSYann Gautier  * This function return global node status (generic use of fdt library).
71c9d75b3cSYann Gautier  ******************************************************************************/
72c9d75b3cSYann Gautier uint8_t fdt_get_status(int node)
73c9d75b3cSYann Gautier {
74c9d75b3cSYann Gautier 	uint8_t status = DT_DISABLED;
75c9d75b3cSYann Gautier 	const char *cchar;
76c9d75b3cSYann Gautier 
77f714ca80SYann Gautier 	cchar = fdt_getprop(fdt, node, "status", NULL);
78c9d75b3cSYann Gautier 	if ((cchar == NULL) ||
79f714ca80SYann Gautier 	    (strncmp(cchar, "okay", strlen("okay")) == 0)) {
80c9d75b3cSYann Gautier 		status |= DT_NON_SECURE;
81c9d75b3cSYann Gautier 	}
82c9d75b3cSYann Gautier 
83f714ca80SYann Gautier 	cchar = fdt_getprop(fdt, node, "secure-status", NULL);
84c9d75b3cSYann Gautier 	if (cchar == NULL) {
85c9d75b3cSYann Gautier 		if (status == DT_NON_SECURE) {
86c9d75b3cSYann Gautier 			status |= DT_SECURE;
87c9d75b3cSYann Gautier 		}
88f714ca80SYann Gautier 	} else if (strncmp(cchar, "okay", strlen("okay")) == 0) {
89c9d75b3cSYann Gautier 		status |= DT_SECURE;
90c9d75b3cSYann Gautier 	}
91c9d75b3cSYann Gautier 
92c9d75b3cSYann Gautier 	return status;
93c9d75b3cSYann Gautier }
94c9d75b3cSYann Gautier 
95cd4941deSYann Gautier #if ENABLE_ASSERTIONS
96c9d75b3cSYann Gautier /*******************************************************************************
97dd85e572SLionel Debieve  * This function returns the address cells from the node parent.
98dd85e572SLionel Debieve  * Returns:
99dd85e572SLionel Debieve  * - #address-cells value if success.
100dd85e572SLionel Debieve  * - invalid value if error.
101dd85e572SLionel Debieve  * - a default value if undefined #address-cells property as per libfdt
102dd85e572SLionel Debieve  *   implementation.
103dd85e572SLionel Debieve  ******************************************************************************/
104cd4941deSYann Gautier static int fdt_get_node_parent_address_cells(int node)
105dd85e572SLionel Debieve {
106dd85e572SLionel Debieve 	int parent;
107dd85e572SLionel Debieve 
108dd85e572SLionel Debieve 	parent = fdt_parent_offset(fdt, node);
109dd85e572SLionel Debieve 	if (parent < 0) {
110dd85e572SLionel Debieve 		return -FDT_ERR_NOTFOUND;
111dd85e572SLionel Debieve 	}
112dd85e572SLionel Debieve 
113dd85e572SLionel Debieve 	return fdt_address_cells(fdt, parent);
114dd85e572SLionel Debieve }
115cd4941deSYann Gautier #endif
116dd85e572SLionel Debieve 
117dd85e572SLionel Debieve /*******************************************************************************
118c9d75b3cSYann Gautier  * This function gets the stdout pin configuration information from the DT.
119c9d75b3cSYann Gautier  * And then calls the sub-function to treat it and set GPIO registers.
120c9d75b3cSYann Gautier  * Returns 0 on success and a negative FDT error code on failure.
121c9d75b3cSYann Gautier  ******************************************************************************/
122c9d75b3cSYann Gautier int dt_set_stdout_pinctrl(void)
123c9d75b3cSYann Gautier {
124c9d75b3cSYann Gautier 	int node;
125c9d75b3cSYann Gautier 
1267a61114dSAndre Przywara 	node = fdt_get_stdout_node_offset(fdt);
127c9d75b3cSYann Gautier 	if (node < 0) {
128c9d75b3cSYann Gautier 		return -FDT_ERR_NOTFOUND;
129c9d75b3cSYann Gautier 	}
130c9d75b3cSYann Gautier 
131c9d75b3cSYann Gautier 	return dt_set_pinctrl_config(node);
132c9d75b3cSYann Gautier }
133c9d75b3cSYann Gautier 
134c9d75b3cSYann Gautier /*******************************************************************************
135c9d75b3cSYann Gautier  * This function fills the generic information from a given node.
136c9d75b3cSYann Gautier  ******************************************************************************/
137c9d75b3cSYann Gautier void dt_fill_device_info(struct dt_node_info *info, int node)
138c9d75b3cSYann Gautier {
139c9d75b3cSYann Gautier 	const fdt32_t *cuint;
140c9d75b3cSYann Gautier 
141dd85e572SLionel Debieve 	assert(fdt_get_node_parent_address_cells(node) == 1);
142dd85e572SLionel Debieve 
143c9d75b3cSYann Gautier 	cuint = fdt_getprop(fdt, node, "reg", NULL);
144c9d75b3cSYann Gautier 	if (cuint != NULL) {
145c9d75b3cSYann Gautier 		info->base = fdt32_to_cpu(*cuint);
146c9d75b3cSYann Gautier 	} else {
147c9d75b3cSYann Gautier 		info->base = 0;
148c9d75b3cSYann Gautier 	}
149c9d75b3cSYann Gautier 
150c9d75b3cSYann Gautier 	cuint = fdt_getprop(fdt, node, "clocks", NULL);
151c9d75b3cSYann Gautier 	if (cuint != NULL) {
152c9d75b3cSYann Gautier 		cuint++;
153c9d75b3cSYann Gautier 		info->clock = (int)fdt32_to_cpu(*cuint);
154c9d75b3cSYann Gautier 	} else {
155c9d75b3cSYann Gautier 		info->clock = -1;
156c9d75b3cSYann Gautier 	}
157c9d75b3cSYann Gautier 
158c9d75b3cSYann Gautier 	cuint = fdt_getprop(fdt, node, "resets", NULL);
159c9d75b3cSYann Gautier 	if (cuint != NULL) {
160c9d75b3cSYann Gautier 		cuint++;
161c9d75b3cSYann Gautier 		info->reset = (int)fdt32_to_cpu(*cuint);
162c9d75b3cSYann Gautier 	} else {
163c9d75b3cSYann Gautier 		info->reset = -1;
164c9d75b3cSYann Gautier 	}
165c9d75b3cSYann Gautier 
166c9d75b3cSYann Gautier 	info->status = fdt_get_status(node);
167c9d75b3cSYann Gautier }
168c9d75b3cSYann Gautier 
169c9d75b3cSYann Gautier /*******************************************************************************
170c9d75b3cSYann Gautier  * This function retrieve the generic information from DT.
171c9d75b3cSYann Gautier  * Returns node on success and a negative FDT error code on failure.
172c9d75b3cSYann Gautier  ******************************************************************************/
173c9d75b3cSYann Gautier int dt_get_node(struct dt_node_info *info, int offset, const char *compat)
174c9d75b3cSYann Gautier {
175c9d75b3cSYann Gautier 	int node;
176c9d75b3cSYann Gautier 
177c9d75b3cSYann Gautier 	node = fdt_node_offset_by_compatible(fdt, offset, compat);
178c9d75b3cSYann Gautier 	if (node < 0) {
179c9d75b3cSYann Gautier 		return -FDT_ERR_NOTFOUND;
180c9d75b3cSYann Gautier 	}
181c9d75b3cSYann Gautier 
182c9d75b3cSYann Gautier 	dt_fill_device_info(info, node);
183c9d75b3cSYann Gautier 
184c9d75b3cSYann Gautier 	return node;
185c9d75b3cSYann Gautier }
186c9d75b3cSYann Gautier 
187c9d75b3cSYann Gautier /*******************************************************************************
188c9d75b3cSYann Gautier  * This function gets the UART instance info of stdout from the DT.
189c9d75b3cSYann Gautier  * Returns node on success and a negative FDT error code on failure.
190c9d75b3cSYann Gautier  ******************************************************************************/
191c9d75b3cSYann Gautier int dt_get_stdout_uart_info(struct dt_node_info *info)
192c9d75b3cSYann Gautier {
193c9d75b3cSYann Gautier 	int node;
194c9d75b3cSYann Gautier 
1957a61114dSAndre Przywara 	node = fdt_get_stdout_node_offset(fdt);
196c9d75b3cSYann Gautier 	if (node < 0) {
197c9d75b3cSYann Gautier 		return -FDT_ERR_NOTFOUND;
198c9d75b3cSYann Gautier 	}
199c9d75b3cSYann Gautier 
200c9d75b3cSYann Gautier 	dt_fill_device_info(info, node);
201c9d75b3cSYann Gautier 
202c9d75b3cSYann Gautier 	return node;
203c9d75b3cSYann Gautier }
204c9d75b3cSYann Gautier 
205c9d75b3cSYann Gautier /*******************************************************************************
206ea97bbf6SYann Gautier  * This function returns the node offset matching compatible string in the DT,
207ea97bbf6SYann Gautier  * and also matching the reg property with the given address.
208ea97bbf6SYann Gautier  * Returns value on success, and error value on failure.
209ea97bbf6SYann Gautier  ******************************************************************************/
210ea97bbf6SYann Gautier int dt_match_instance_by_compatible(const char *compatible, uintptr_t address)
211ea97bbf6SYann Gautier {
212ea97bbf6SYann Gautier 	int node;
213ea97bbf6SYann Gautier 
214ea97bbf6SYann Gautier 	fdt_for_each_compatible_node(fdt, node, compatible) {
215ea97bbf6SYann Gautier 		const fdt32_t *cuint;
216ea97bbf6SYann Gautier 
217ea97bbf6SYann Gautier 		assert(fdt_get_node_parent_address_cells(node) == 1);
218ea97bbf6SYann Gautier 
219ea97bbf6SYann Gautier 		cuint = fdt_getprop(fdt, node, "reg", NULL);
220ea97bbf6SYann Gautier 		if (cuint == NULL) {
221ea97bbf6SYann Gautier 			continue;
222ea97bbf6SYann Gautier 		}
223ea97bbf6SYann Gautier 
224ea97bbf6SYann Gautier 		if ((uintptr_t)fdt32_to_cpu(*cuint) == address) {
225ea97bbf6SYann Gautier 			return node;
226ea97bbf6SYann Gautier 		}
227ea97bbf6SYann Gautier 	}
228ea97bbf6SYann Gautier 
229ea97bbf6SYann Gautier 	return -FDT_ERR_NOTFOUND;
230ea97bbf6SYann Gautier }
231ea97bbf6SYann Gautier 
232ea97bbf6SYann Gautier /*******************************************************************************
233c9d75b3cSYann Gautier  * This function gets DDR size information from the DT.
234c9d75b3cSYann Gautier  * Returns value in bytes on success, and 0 on failure.
235c9d75b3cSYann Gautier  ******************************************************************************/
236c9d75b3cSYann Gautier uint32_t dt_get_ddr_size(void)
237c9d75b3cSYann Gautier {
23891ffc1deSLionel Debieve 	static uint32_t size;
239c9d75b3cSYann Gautier 	int node;
240c9d75b3cSYann Gautier 
24191ffc1deSLionel Debieve 	if (size != 0U) {
24291ffc1deSLionel Debieve 		return size;
24391ffc1deSLionel Debieve 	}
24491ffc1deSLionel Debieve 
245c9d75b3cSYann Gautier 	node = fdt_node_offset_by_compatible(fdt, -1, DT_DDR_COMPAT);
246c9d75b3cSYann Gautier 	if (node < 0) {
247c9d75b3cSYann Gautier 		INFO("%s: Cannot read DDR node in DT\n", __func__);
248c9d75b3cSYann Gautier 		return 0;
249c9d75b3cSYann Gautier 	}
250c9d75b3cSYann Gautier 
25191ffc1deSLionel Debieve 	size = fdt_read_uint32_default(fdt, node, "st,mem-size", 0U);
25291ffc1deSLionel Debieve 
25391ffc1deSLionel Debieve 	flush_dcache_range((uintptr_t)&size, sizeof(uint32_t));
25491ffc1deSLionel Debieve 
25591ffc1deSLionel Debieve 	return size;
256c9d75b3cSYann Gautier }
257c9d75b3cSYann Gautier 
258c9d75b3cSYann Gautier /*******************************************************************************
259f33b2433SYann Gautier  * This function gets PWR VDD regulator voltage information from the DT.
260f33b2433SYann Gautier  * Returns value in microvolts on success, and 0 on failure.
261f33b2433SYann Gautier  ******************************************************************************/
262f33b2433SYann Gautier uint32_t dt_get_pwr_vdd_voltage(void)
263f33b2433SYann Gautier {
264c39c658eSYann Gautier 	struct rdev *regul = dt_get_vdd_regulator();
265c39c658eSYann Gautier 	uint16_t min;
266f33b2433SYann Gautier 
267c39c658eSYann Gautier 	if (regul == NULL) {
268c39c658eSYann Gautier 		return 0;
269c39c658eSYann Gautier 	}
270c39c658eSYann Gautier 
271c39c658eSYann Gautier 	regulator_get_range(regul, &min, NULL);
272c39c658eSYann Gautier 
273c39c658eSYann Gautier 	return (uint32_t)min * 1000U;
274c39c658eSYann Gautier }
275c39c658eSYann Gautier 
276c39c658eSYann Gautier /*******************************************************************************
277c39c658eSYann Gautier  * This function retrieves VDD supply regulator from DT.
278c39c658eSYann Gautier  * Returns an rdev taken from supply node, NULL otherwise.
279c39c658eSYann Gautier  ******************************************************************************/
280c39c658eSYann Gautier struct rdev *dt_get_vdd_regulator(void)
281c39c658eSYann Gautier {
282c39c658eSYann Gautier 	int node = fdt_node_offset_by_compatible(fdt, -1, DT_PWR_COMPAT);
283c39c658eSYann Gautier 
284f33b2433SYann Gautier 	if (node < 0) {
285c39c658eSYann Gautier 		return NULL;
286f33b2433SYann Gautier 	}
287f33b2433SYann Gautier 
288c39c658eSYann Gautier 	return regulator_get_by_supply_name(fdt, node, "vdd");
289f33b2433SYann Gautier }
290f33b2433SYann Gautier 
291c39c658eSYann Gautier /*******************************************************************************
292c39c658eSYann Gautier  * This function retrieves CPU supply regulator from DT.
293c39c658eSYann Gautier  * Returns an rdev taken from supply node, NULL otherwise.
294c39c658eSYann Gautier  ******************************************************************************/
295c39c658eSYann Gautier struct rdev *dt_get_cpu_regulator(void)
296c39c658eSYann Gautier {
297c39c658eSYann Gautier 	int node = fdt_path_offset(fdt, "/cpus/cpu@0");
298f33b2433SYann Gautier 
299f33b2433SYann Gautier 	if (node < 0) {
300c39c658eSYann Gautier 		return NULL;
301f33b2433SYann Gautier 	}
302f33b2433SYann Gautier 
303c39c658eSYann Gautier 	return regulator_get_by_supply_name(fdt, node, "cpu");
304f33b2433SYann Gautier }
305f33b2433SYann Gautier 
306f33b2433SYann Gautier /*******************************************************************************
307c9d75b3cSYann Gautier  * This function retrieves board model from DT
308c9d75b3cSYann Gautier  * Returns string taken from model node, NULL otherwise
309c9d75b3cSYann Gautier  ******************************************************************************/
310c9d75b3cSYann Gautier const char *dt_get_board_model(void)
311c9d75b3cSYann Gautier {
312c9d75b3cSYann Gautier 	int node = fdt_path_offset(fdt, "/");
313c9d75b3cSYann Gautier 
314c9d75b3cSYann Gautier 	if (node < 0) {
315c9d75b3cSYann Gautier 		return NULL;
316c9d75b3cSYann Gautier 	}
317c9d75b3cSYann Gautier 
318c9d75b3cSYann Gautier 	return (const char *)fdt_getprop(fdt, node, "model", NULL);
319c9d75b3cSYann Gautier }
320ccc199edSEtienne Carriere 
321ccc199edSEtienne Carriere /*******************************************************************************
322*ae3ce8b2SLionel Debieve  * dt_find_otp_name: get OTP ID and length in DT.
323*ae3ce8b2SLionel Debieve  * name: sub-node name to look up.
324*ae3ce8b2SLionel Debieve  * otp: pointer to read OTP number or NULL.
325*ae3ce8b2SLionel Debieve  * otp_len: pointer to read OTP length in bits or NULL.
326*ae3ce8b2SLionel Debieve  * return value: 0 if no error, an FDT error value otherwise.
327*ae3ce8b2SLionel Debieve  ******************************************************************************/
328*ae3ce8b2SLionel Debieve int dt_find_otp_name(const char *name, uint32_t *otp, uint32_t *otp_len)
329*ae3ce8b2SLionel Debieve {
330*ae3ce8b2SLionel Debieve 	int node;
331*ae3ce8b2SLionel Debieve 	int index, len;
332*ae3ce8b2SLionel Debieve 	const fdt32_t *cuint;
333*ae3ce8b2SLionel Debieve 
334*ae3ce8b2SLionel Debieve 	if ((name == NULL) || (otp == NULL)) {
335*ae3ce8b2SLionel Debieve 		return -FDT_ERR_BADVALUE;
336*ae3ce8b2SLionel Debieve 	}
337*ae3ce8b2SLionel Debieve 
338*ae3ce8b2SLionel Debieve 	node = fdt_node_offset_by_compatible(fdt, -1, DT_NVMEM_LAYOUT_COMPAT);
339*ae3ce8b2SLionel Debieve 	if (node < 0) {
340*ae3ce8b2SLionel Debieve 		return node;
341*ae3ce8b2SLionel Debieve 	}
342*ae3ce8b2SLionel Debieve 
343*ae3ce8b2SLionel Debieve 	index = fdt_stringlist_search(fdt, node, "nvmem-cell-names", name);
344*ae3ce8b2SLionel Debieve 	if (index < 0) {
345*ae3ce8b2SLionel Debieve 		return index;
346*ae3ce8b2SLionel Debieve 	}
347*ae3ce8b2SLionel Debieve 
348*ae3ce8b2SLionel Debieve 	cuint = fdt_getprop(fdt, node, "nvmem-cells", &len);
349*ae3ce8b2SLionel Debieve 	if (cuint == NULL) {
350*ae3ce8b2SLionel Debieve 		return -FDT_ERR_NOTFOUND;
351*ae3ce8b2SLionel Debieve 	}
352*ae3ce8b2SLionel Debieve 
353*ae3ce8b2SLionel Debieve 	if ((index * (int)sizeof(uint32_t)) > len) {
354*ae3ce8b2SLionel Debieve 		return -FDT_ERR_BADVALUE;
355*ae3ce8b2SLionel Debieve 	}
356*ae3ce8b2SLionel Debieve 
357*ae3ce8b2SLionel Debieve 	cuint += index;
358*ae3ce8b2SLionel Debieve 
359*ae3ce8b2SLionel Debieve 	node = fdt_node_offset_by_phandle(fdt, fdt32_to_cpu(*cuint));
360*ae3ce8b2SLionel Debieve 	if (node < 0) {
361*ae3ce8b2SLionel Debieve 		ERROR("Malformed nvmem_layout node: ignored\n");
362*ae3ce8b2SLionel Debieve 		return node;
363*ae3ce8b2SLionel Debieve 	}
364*ae3ce8b2SLionel Debieve 
365*ae3ce8b2SLionel Debieve 	cuint = fdt_getprop(fdt, node, "reg", &len);
366*ae3ce8b2SLionel Debieve 	if ((cuint == NULL) || (len != (2 * (int)sizeof(uint32_t)))) {
367*ae3ce8b2SLionel Debieve 		ERROR("Malformed nvmem_layout node: ignored\n");
368*ae3ce8b2SLionel Debieve 		return -FDT_ERR_BADVALUE;
369*ae3ce8b2SLionel Debieve 	}
370*ae3ce8b2SLionel Debieve 
371*ae3ce8b2SLionel Debieve 	if (fdt32_to_cpu(*cuint) % sizeof(uint32_t)) {
372*ae3ce8b2SLionel Debieve 		ERROR("Misaligned nvmem_layout element: ignored\n");
373*ae3ce8b2SLionel Debieve 		return -FDT_ERR_BADVALUE;
374*ae3ce8b2SLionel Debieve 	}
375*ae3ce8b2SLionel Debieve 
376*ae3ce8b2SLionel Debieve 	if (otp != NULL) {
377*ae3ce8b2SLionel Debieve 		*otp = fdt32_to_cpu(*cuint) / sizeof(uint32_t);
378*ae3ce8b2SLionel Debieve 	}
379*ae3ce8b2SLionel Debieve 
380*ae3ce8b2SLionel Debieve 	if (otp_len != NULL) {
381*ae3ce8b2SLionel Debieve 		cuint++;
382*ae3ce8b2SLionel Debieve 		*otp_len = fdt32_to_cpu(*cuint) * CHAR_BIT;
383*ae3ce8b2SLionel Debieve 	}
384*ae3ce8b2SLionel Debieve 
385*ae3ce8b2SLionel Debieve 	return 0;
386*ae3ce8b2SLionel Debieve }
387*ae3ce8b2SLionel Debieve 
388*ae3ce8b2SLionel Debieve /*******************************************************************************
389ccc199edSEtienne Carriere  * This function gets the pin count for a GPIO bank based from the FDT.
390ccc199edSEtienne Carriere  * It also checks node consistency.
391ccc199edSEtienne Carriere  ******************************************************************************/
392ccc199edSEtienne Carriere int fdt_get_gpio_bank_pin_count(unsigned int bank)
393ccc199edSEtienne Carriere {
394ccc199edSEtienne Carriere 	int pinctrl_node;
395ccc199edSEtienne Carriere 	int node;
396ccc199edSEtienne Carriere 	uint32_t bank_offset;
397ccc199edSEtienne Carriere 
398ccc199edSEtienne Carriere 	pinctrl_node = stm32_get_gpio_bank_pinctrl_node(fdt, bank);
399ccc199edSEtienne Carriere 	if (pinctrl_node < 0) {
400ccc199edSEtienne Carriere 		return -FDT_ERR_NOTFOUND;
401ccc199edSEtienne Carriere 	}
402ccc199edSEtienne Carriere 
403ccc199edSEtienne Carriere 	bank_offset = stm32_get_gpio_bank_offset(bank);
404ccc199edSEtienne Carriere 
405ccc199edSEtienne Carriere 	fdt_for_each_subnode(node, fdt, pinctrl_node) {
406ccc199edSEtienne Carriere 		const fdt32_t *cuint;
407ccc199edSEtienne Carriere 
408ccc199edSEtienne Carriere 		if (fdt_getprop(fdt, node, "gpio-controller", NULL) == NULL) {
409ccc199edSEtienne Carriere 			continue;
410ccc199edSEtienne Carriere 		}
411ccc199edSEtienne Carriere 
412ccc199edSEtienne Carriere 		cuint = fdt_getprop(fdt, node, "reg", NULL);
413ccc199edSEtienne Carriere 		if (cuint == NULL) {
414ccc199edSEtienne Carriere 			continue;
415ccc199edSEtienne Carriere 		}
416ccc199edSEtienne Carriere 
417ccc199edSEtienne Carriere 		if (fdt32_to_cpu(*cuint) != bank_offset) {
418ccc199edSEtienne Carriere 			continue;
419ccc199edSEtienne Carriere 		}
420ccc199edSEtienne Carriere 
421ccc199edSEtienne Carriere 		if (fdt_get_status(node) == DT_DISABLED) {
422ccc199edSEtienne Carriere 			return 0;
423ccc199edSEtienne Carriere 		}
424ccc199edSEtienne Carriere 
425ccc199edSEtienne Carriere 		cuint = fdt_getprop(fdt, node, "ngpios", NULL);
426ccc199edSEtienne Carriere 		if (cuint == NULL) {
427ccc199edSEtienne Carriere 			return -FDT_ERR_NOTFOUND;
428ccc199edSEtienne Carriere 		}
429ccc199edSEtienne Carriere 
430ccc199edSEtienne Carriere 		return (int)fdt32_to_cpu(*cuint);
431ccc199edSEtienne Carriere 	}
432ccc199edSEtienne Carriere 
433ccc199edSEtienne Carriere 	return 0;
434ccc199edSEtienne Carriere }
435