blob: acb323cf29f9448d83865567ce8258b6ff096a08 [file] [log] [blame]
Yann Gautier9aea69e2018-07-24 17:13:36 +02001/*
Yann Gautier2260b842020-03-11 17:17:51 +01002 * Copyright (c) 2017-2020, ARM Limited and Contributors. All rights reserved.
Yann Gautier9aea69e2018-07-24 17:13:36 +02003 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
7#include <assert.h>
Yann Gautier038bff22019-01-17 19:17:47 +01008#include <errno.h>
Antonio Nino Diaze0f90632018-12-14 00:18:21 +00009
Yann Gautier9aea69e2018-07-24 17:13:36 +020010#include <libfdt.h>
Antonio Nino Diaze0f90632018-12-14 00:18:21 +000011
Yann Gautier9aea69e2018-07-24 17:13:36 +020012#include <platform_def.h>
Antonio Nino Diaze0f90632018-12-14 00:18:21 +000013
14#include <common/debug.h>
15#include <drivers/st/stm32_gpio.h>
Antonio Nino Diaze0f90632018-12-14 00:18:21 +000016#include <drivers/st/stm32mp1_ddr.h>
17#include <drivers/st/stm32mp1_ram.h>
18
Yann Gautieree8f5422019-02-14 11:13:25 +010019#include <stm32mp_dt.h>
20
Yann Gautier9aea69e2018-07-24 17:13:36 +020021static int fdt_checked;
22
Yann Gautiera2e2a302019-02-14 11:13:39 +010023static void *fdt = (void *)(uintptr_t)STM32MP_DTB_BASE;
Yann Gautier9aea69e2018-07-24 17:13:36 +020024
25/*******************************************************************************
26 * This function checks device tree file with its header.
Yann Gautier038bff22019-01-17 19:17:47 +010027 * Returns 0 on success and a negative FDT error code on failure.
Yann Gautier9aea69e2018-07-24 17:13:36 +020028 ******************************************************************************/
29int dt_open_and_check(void)
30{
31 int ret = fdt_check_header(fdt);
32
33 if (ret == 0) {
34 fdt_checked = 1;
35 }
36
37 return ret;
38}
39
40/*******************************************************************************
41 * This function gets the address of the DT.
42 * If DT is OK, fdt_addr is filled with DT address.
43 * Returns 1 if success, 0 otherwise.
44 ******************************************************************************/
45int fdt_get_address(void **fdt_addr)
46{
47 if (fdt_checked == 1) {
48 *fdt_addr = fdt;
49 }
50
51 return fdt_checked;
52}
53
54/*******************************************************************************
55 * This function check the presence of a node (generic use of fdt library).
Yann Gautier038bff22019-01-17 19:17:47 +010056 * Returns true if present, else return false.
Yann Gautier9aea69e2018-07-24 17:13:36 +020057 ******************************************************************************/
58bool fdt_check_node(int node)
59{
60 int len;
61 const char *cchar;
62
63 cchar = fdt_get_name(fdt, node, &len);
64
65 return (cchar != NULL) && (len >= 0);
66}
67
68/*******************************************************************************
Yann Gautier038bff22019-01-17 19:17:47 +010069 * This function return global node status (generic use of fdt library).
Yann Gautier9aea69e2018-07-24 17:13:36 +020070 ******************************************************************************/
Yann Gautieree8f5422019-02-14 11:13:25 +010071uint8_t fdt_get_status(int node)
Yann Gautier9aea69e2018-07-24 17:13:36 +020072{
Yann Gautieree8f5422019-02-14 11:13:25 +010073 uint8_t status = DT_DISABLED;
Yann Gautier9aea69e2018-07-24 17:13:36 +020074 int len;
75 const char *cchar;
76
77 cchar = fdt_getprop(fdt, node, "status", &len);
Yann Gautier038bff22019-01-17 19:17:47 +010078 if ((cchar == NULL) ||
79 (strncmp(cchar, "okay", (size_t)len) == 0)) {
80 status |= DT_NON_SECURE;
Yann Gautier9aea69e2018-07-24 17:13:36 +020081 }
82
Yann Gautier9aea69e2018-07-24 17:13:36 +020083 cchar = fdt_getprop(fdt, node, "secure-status", &len);
84 if (cchar == NULL) {
Yann Gautier038bff22019-01-17 19:17:47 +010085 if (status == DT_NON_SECURE) {
86 status |= DT_SECURE;
87 }
88 } else if (strncmp(cchar, "okay", (size_t)len) == 0) {
89 status |= DT_SECURE;
Yann Gautier9aea69e2018-07-24 17:13:36 +020090 }
91
Yann Gautier038bff22019-01-17 19:17:47 +010092 return status;
Yann Gautier9aea69e2018-07-24 17:13:36 +020093}
94
Yann Gautier2260b842020-03-11 17:17:51 +010095#if ENABLE_ASSERTIONS
Yann Gautier9aea69e2018-07-24 17:13:36 +020096/*******************************************************************************
Lionel Debieveb0899eb2019-09-24 17:41:11 +020097 * 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 ******************************************************************************/
Yann Gautier2260b842020-03-11 17:17:51 +0100104static int fdt_get_node_parent_address_cells(int node)
Lionel Debieveb0899eb2019-09-24 17:41:11 +0200105{
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
116/*******************************************************************************
117 * This function returns the size cells from the node parent.
118 * Returns:
119 * - #size-cells value if success.
120 * - invalid value if error.
121 * - a default value if undefined #size-cells property as per libfdt
122 * implementation.
123 ******************************************************************************/
Yann Gautier2260b842020-03-11 17:17:51 +0100124static int fdt_get_node_parent_size_cells(int node)
Lionel Debieveb0899eb2019-09-24 17:41:11 +0200125{
126 int parent;
127
128 parent = fdt_parent_offset(fdt, node);
129 if (parent < 0) {
130 return -FDT_ERR_NOTFOUND;
131 }
132
133 return fdt_size_cells(fdt, parent);
134}
Yann Gautier2260b842020-03-11 17:17:51 +0100135#endif
Lionel Debieveb0899eb2019-09-24 17:41:11 +0200136
137/*******************************************************************************
Yann Gautier9aea69e2018-07-24 17:13:36 +0200138 * This function reads a value of a node property (generic use of fdt
139 * library).
140 * Returns value if success, and a default value if property not found.
141 * Default value is passed as parameter.
142 ******************************************************************************/
143uint32_t fdt_read_uint32_default(int node, const char *prop_name,
144 uint32_t dflt_value)
145{
146 const fdt32_t *cuint;
147 int lenp;
148
149 cuint = fdt_getprop(fdt, node, prop_name, &lenp);
150 if (cuint == NULL) {
151 return dflt_value;
152 }
153
154 return fdt32_to_cpu(*cuint);
155}
156
157/*******************************************************************************
158 * This function reads a series of parameters in a node property
159 * (generic use of fdt library).
160 * It reads the values inside the device tree, from property name and node.
161 * The number of parameters is also indicated as entry parameter.
Yann Gautier038bff22019-01-17 19:17:47 +0100162 * Returns 0 on success and a negative FDT error code on failure.
Yann Gautier9aea69e2018-07-24 17:13:36 +0200163 * If success, values are stored at the third parameter address.
164 ******************************************************************************/
165int fdt_read_uint32_array(int node, const char *prop_name, uint32_t *array,
166 uint32_t count)
167{
168 const fdt32_t *cuint;
169 int len;
170 uint32_t i;
171
172 cuint = fdt_getprop(fdt, node, prop_name, &len);
173 if (cuint == NULL) {
174 return -FDT_ERR_NOTFOUND;
175 }
176
177 if ((uint32_t)len != (count * sizeof(uint32_t))) {
178 return -FDT_ERR_BADLAYOUT;
179 }
180
181 for (i = 0; i < ((uint32_t)len / sizeof(uint32_t)); i++) {
182 *array = fdt32_to_cpu(*cuint);
183 array++;
184 cuint++;
185 }
186
187 return 0;
188}
Yann Gautierd0ca7f42018-07-13 21:33:09 +0200189
190/*******************************************************************************
Lionel Debieveb0899eb2019-09-24 17:41:11 +0200191 * This function fills reg node info (base & size) with an index found by
192 * checking the reg-names node.
193 * Returns 0 on success and a negative FDT error code on failure.
194 ******************************************************************************/
195int fdt_get_reg_props_by_name(int node, const char *name, uintptr_t *base,
196 size_t *size)
197{
198 const fdt32_t *cuint;
199 int index, len;
200
201 assert((fdt_get_node_parent_address_cells(node) == 1) &&
202 (fdt_get_node_parent_size_cells(node) == 1));
203
204 index = fdt_stringlist_search(fdt, node, "reg-names", name);
205 if (index < 0) {
206 return index;
207 }
208
209 cuint = fdt_getprop(fdt, node, "reg", &len);
210 if (cuint == NULL) {
211 return -FDT_ERR_NOTFOUND;
212 }
213
214 if ((index * (int)sizeof(uint32_t)) > len) {
215 return -FDT_ERR_BADVALUE;
216 }
217
218 cuint += index << 1;
219 if (base != NULL) {
220 *base = fdt32_to_cpu(*cuint);
221 }
222 cuint++;
223 if (size != NULL) {
224 *size = fdt32_to_cpu(*cuint);
225 }
226
227 return 0;
228}
229
230/*******************************************************************************
Yann Gautier1bef97a2019-06-04 17:20:44 +0200231 * This function gets the stdout path node.
232 * It reads the value indicated inside the device tree.
233 * Returns node offset on success and a negative FDT error code on failure.
234 ******************************************************************************/
235static int dt_get_stdout_node_offset(void)
236{
237 int node;
238 const char *cchar;
239
240 node = fdt_path_offset(fdt, "/secure-chosen");
241 if (node < 0) {
242 node = fdt_path_offset(fdt, "/chosen");
243 if (node < 0) {
244 return -FDT_ERR_NOTFOUND;
245 }
246 }
247
248 cchar = fdt_getprop(fdt, node, "stdout-path", NULL);
249 if (cchar == NULL) {
250 return -FDT_ERR_NOTFOUND;
251 }
252
253 node = -FDT_ERR_NOTFOUND;
254 if (strchr(cchar, (int)':') != NULL) {
255 const char *name;
256 char *str = (char *)cchar;
257 int len = 0;
258
259 while (strncmp(":", str, 1)) {
260 len++;
261 str++;
262 }
263
264 name = fdt_get_alias_namelen(fdt, cchar, len);
265
266 if (name != NULL) {
267 node = fdt_path_offset(fdt, name);
268 }
269 } else {
270 node = fdt_path_offset(fdt, cchar);
271 }
272
273 return node;
274}
275
276/*******************************************************************************
Yann Gautier69035a82018-07-05 16:48:16 +0200277 * This function gets the stdout pin configuration information from the DT.
278 * And then calls the sub-function to treat it and set GPIO registers.
Yann Gautier038bff22019-01-17 19:17:47 +0100279 * Returns 0 on success and a negative FDT error code on failure.
Yann Gautier69035a82018-07-05 16:48:16 +0200280 ******************************************************************************/
281int dt_set_stdout_pinctrl(void)
282{
283 int node;
284
285 node = dt_get_stdout_node_offset();
286 if (node < 0) {
287 return -FDT_ERR_NOTFOUND;
288 }
289
290 return dt_set_pinctrl_config(node);
291}
292
293/*******************************************************************************
294 * This function fills the generic information from a given node.
295 ******************************************************************************/
296void dt_fill_device_info(struct dt_node_info *info, int node)
297{
298 const fdt32_t *cuint;
299
Lionel Debieveb0899eb2019-09-24 17:41:11 +0200300 assert(fdt_get_node_parent_address_cells(node) == 1);
301
Yann Gautier69035a82018-07-05 16:48:16 +0200302 cuint = fdt_getprop(fdt, node, "reg", NULL);
303 if (cuint != NULL) {
304 info->base = fdt32_to_cpu(*cuint);
305 } else {
306 info->base = 0;
307 }
308
309 cuint = fdt_getprop(fdt, node, "clocks", NULL);
310 if (cuint != NULL) {
311 cuint++;
312 info->clock = (int)fdt32_to_cpu(*cuint);
313 } else {
314 info->clock = -1;
315 }
316
317 cuint = fdt_getprop(fdt, node, "resets", NULL);
318 if (cuint != NULL) {
319 cuint++;
320 info->reset = (int)fdt32_to_cpu(*cuint);
321 } else {
322 info->reset = -1;
323 }
324
Yann Gautier038bff22019-01-17 19:17:47 +0100325 info->status = fdt_get_status(node);
Yann Gautier69035a82018-07-05 16:48:16 +0200326}
327
328/*******************************************************************************
329 * This function retrieve the generic information from DT.
Yann Gautier038bff22019-01-17 19:17:47 +0100330 * Returns node on success and a negative FDT error code on failure.
Yann Gautier69035a82018-07-05 16:48:16 +0200331 ******************************************************************************/
332int dt_get_node(struct dt_node_info *info, int offset, const char *compat)
333{
334 int node;
335
336 node = fdt_node_offset_by_compatible(fdt, offset, compat);
337 if (node < 0) {
338 return -FDT_ERR_NOTFOUND;
339 }
340
341 dt_fill_device_info(info, node);
342
343 return node;
344}
345
346/*******************************************************************************
347 * This function gets the UART instance info of stdout from the DT.
Yann Gautier038bff22019-01-17 19:17:47 +0100348 * Returns node on success and a negative FDT error code on failure.
Yann Gautier69035a82018-07-05 16:48:16 +0200349 ******************************************************************************/
350int dt_get_stdout_uart_info(struct dt_node_info *info)
351{
352 int node;
353
354 node = dt_get_stdout_node_offset();
355 if (node < 0) {
356 return -FDT_ERR_NOTFOUND;
357 }
358
359 dt_fill_device_info(info, node);
360
361 return node;
362}
363
364/*******************************************************************************
Yann Gautiercaf575b2018-07-24 17:18:19 +0200365 * This function gets DDR size information from the DT.
Yann Gautier038bff22019-01-17 19:17:47 +0100366 * Returns value in bytes on success, and 0 on failure.
Yann Gautiercaf575b2018-07-24 17:18:19 +0200367 ******************************************************************************/
368uint32_t dt_get_ddr_size(void)
369{
370 int node;
371
372 node = fdt_node_offset_by_compatible(fdt, -1, DT_DDR_COMPAT);
373 if (node < 0) {
374 INFO("%s: Cannot read DDR node in DT\n", __func__);
Yann Gautier038bff22019-01-17 19:17:47 +0100375 return 0;
Yann Gautiercaf575b2018-07-24 17:18:19 +0200376 }
377
Yann Gautier038bff22019-01-17 19:17:47 +0100378 return fdt_read_uint32_default(node, "st,mem-size", 0);
Yann Gautiercaf575b2018-07-24 17:18:19 +0200379}
380
381/*******************************************************************************
Yann Gautier3d78a2e2019-02-14 11:01:20 +0100382 * This function gets DDRCTRL base address information from the DT.
383 * Returns value on success, and 0 on failure.
384 ******************************************************************************/
385uintptr_t dt_get_ddrctrl_base(void)
386{
387 int node;
388 uint32_t array[4];
389
390 node = fdt_node_offset_by_compatible(fdt, -1, DT_DDR_COMPAT);
391 if (node < 0) {
392 INFO("%s: Cannot read DDR node in DT\n", __func__);
393 return 0;
394 }
395
Lionel Debieveb0899eb2019-09-24 17:41:11 +0200396 assert((fdt_get_node_parent_address_cells(node) == 1) &&
397 (fdt_get_node_parent_size_cells(node) == 1));
398
Yann Gautier3d78a2e2019-02-14 11:01:20 +0100399 if (fdt_read_uint32_array(node, "reg", array, 4) < 0) {
400 return 0;
401 }
402
403 return array[0];
404}
405
406/*******************************************************************************
407 * This function gets DDRPHYC base address information from the DT.
408 * Returns value on success, and 0 on failure.
409 ******************************************************************************/
410uintptr_t dt_get_ddrphyc_base(void)
411{
412 int node;
413 uint32_t array[4];
414
415 node = fdt_node_offset_by_compatible(fdt, -1, DT_DDR_COMPAT);
416 if (node < 0) {
417 INFO("%s: Cannot read DDR node in DT\n", __func__);
418 return 0;
419 }
420
Lionel Debieveb0899eb2019-09-24 17:41:11 +0200421 assert((fdt_get_node_parent_address_cells(node) == 1) &&
422 (fdt_get_node_parent_size_cells(node) == 1));
423
Yann Gautier3d78a2e2019-02-14 11:01:20 +0100424 if (fdt_read_uint32_array(node, "reg", array, 4) < 0) {
425 return 0;
426 }
427
428 return array[2];
429}
430
431/*******************************************************************************
432 * This function gets PWR base address information from the DT.
433 * Returns value on success, and 0 on failure.
434 ******************************************************************************/
435uintptr_t dt_get_pwr_base(void)
436{
437 int node;
438 const fdt32_t *cuint;
439
440 node = fdt_node_offset_by_compatible(fdt, -1, DT_PWR_COMPAT);
441 if (node < 0) {
442 INFO("%s: Cannot read PWR node in DT\n", __func__);
443 return 0;
444 }
445
Lionel Debieveb0899eb2019-09-24 17:41:11 +0200446 assert(fdt_get_node_parent_address_cells(node) == 1);
447
Yann Gautier3d78a2e2019-02-14 11:01:20 +0100448 cuint = fdt_getprop(fdt, node, "reg", NULL);
449 if (cuint == NULL) {
450 return 0;
451 }
452
453 return fdt32_to_cpu(*cuint);
454}
455
456/*******************************************************************************
Yann Gautier3edc7c32019-05-20 19:17:08 +0200457 * This function gets PWR VDD regulator voltage information from the DT.
458 * Returns value in microvolts on success, and 0 on failure.
459 ******************************************************************************/
460uint32_t dt_get_pwr_vdd_voltage(void)
461{
462 int node, pwr_regulators_node;
463 const fdt32_t *cuint;
464
465 node = fdt_node_offset_by_compatible(fdt, -1, DT_PWR_COMPAT);
466 if (node < 0) {
467 INFO("%s: Cannot read PWR node in DT\n", __func__);
468 return 0;
469 }
470
471 pwr_regulators_node = fdt_subnode_offset(fdt, node, "pwr-regulators");
Yann Gautierdf473922020-03-18 14:35:27 +0100472 if (pwr_regulators_node < 0) {
Yann Gautier3edc7c32019-05-20 19:17:08 +0200473 INFO("%s: Cannot read pwr-regulators node in DT\n", __func__);
474 return 0;
475 }
476
477 cuint = fdt_getprop(fdt, pwr_regulators_node, "vdd-supply", NULL);
478 if (cuint == NULL) {
479 return 0;
480 }
481
482 node = fdt_node_offset_by_phandle(fdt, fdt32_to_cpu(*cuint));
483 if (node < 0) {
484 return 0;
485 }
486
487 cuint = fdt_getprop(fdt, node, "regulator-min-microvolt", NULL);
488 if (cuint == NULL) {
489 return 0;
490 }
491
492 return fdt32_to_cpu(*cuint);
493}
494
495/*******************************************************************************
496 * This function gets SYSCFG base address information from the DT.
497 * Returns value on success, and 0 on failure.
498 ******************************************************************************/
499uintptr_t dt_get_syscfg_base(void)
500{
501 int node;
502 const fdt32_t *cuint;
503
504 node = fdt_node_offset_by_compatible(fdt, -1, DT_SYSCFG_COMPAT);
505 if (node < 0) {
506 INFO("%s: Cannot read SYSCFG node in DT\n", __func__);
507 return 0;
508 }
509
Lionel Debieveb0899eb2019-09-24 17:41:11 +0200510 assert(fdt_get_node_parent_address_cells(node) == 1);
511
Yann Gautier3edc7c32019-05-20 19:17:08 +0200512 cuint = fdt_getprop(fdt, node, "reg", NULL);
513 if (cuint == NULL) {
514 return 0;
515 }
516
517 return fdt32_to_cpu(*cuint);
518}
519
520/*******************************************************************************
Yann Gautier69035a82018-07-05 16:48:16 +0200521 * This function retrieves board model from DT
522 * Returns string taken from model node, NULL otherwise
523 ******************************************************************************/
524const char *dt_get_board_model(void)
525{
526 int node = fdt_path_offset(fdt, "/");
527
528 if (node < 0) {
529 return NULL;
530 }
531
532 return (const char *)fdt_getprop(fdt, node, "model", NULL);
533}