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