blob: 4fa796f0c89ff2e49d7355524b39dbaab72cda87 [file] [log] [blame]
Yann Gautier9aea69e2018-07-24 17:13:36 +02001/*
Yann Gautier038bff22019-01-17 19:17:47 +01002 * Copyright (c) 2017-2019, 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
95/*******************************************************************************
Lionel Debieveb0899eb2019-09-24 17:41:11 +020096 * This function returns the address cells from the node parent.
97 * Returns:
98 * - #address-cells value if success.
99 * - invalid value if error.
100 * - a default value if undefined #address-cells property as per libfdt
101 * implementation.
102 ******************************************************************************/
103int fdt_get_node_parent_address_cells(int node)
104{
105 int parent;
106
107 parent = fdt_parent_offset(fdt, node);
108 if (parent < 0) {
109 return -FDT_ERR_NOTFOUND;
110 }
111
112 return fdt_address_cells(fdt, parent);
113}
114
115/*******************************************************************************
116 * This function returns the size cells from the node parent.
117 * Returns:
118 * - #size-cells value if success.
119 * - invalid value if error.
120 * - a default value if undefined #size-cells property as per libfdt
121 * implementation.
122 ******************************************************************************/
123int fdt_get_node_parent_size_cells(int node)
124{
125 int parent;
126
127 parent = fdt_parent_offset(fdt, node);
128 if (parent < 0) {
129 return -FDT_ERR_NOTFOUND;
130 }
131
132 return fdt_size_cells(fdt, parent);
133}
134
135/*******************************************************************************
Yann Gautier9aea69e2018-07-24 17:13:36 +0200136 * This function reads a value of a node property (generic use of fdt
137 * library).
138 * Returns value if success, and a default value if property not found.
139 * Default value is passed as parameter.
140 ******************************************************************************/
141uint32_t fdt_read_uint32_default(int node, const char *prop_name,
142 uint32_t dflt_value)
143{
144 const fdt32_t *cuint;
145 int lenp;
146
147 cuint = fdt_getprop(fdt, node, prop_name, &lenp);
148 if (cuint == NULL) {
149 return dflt_value;
150 }
151
152 return fdt32_to_cpu(*cuint);
153}
154
155/*******************************************************************************
156 * This function reads a series of parameters in a node property
157 * (generic use of fdt library).
158 * It reads the values inside the device tree, from property name and node.
159 * The number of parameters is also indicated as entry parameter.
Yann Gautier038bff22019-01-17 19:17:47 +0100160 * Returns 0 on success and a negative FDT error code on failure.
Yann Gautier9aea69e2018-07-24 17:13:36 +0200161 * If success, values are stored at the third parameter address.
162 ******************************************************************************/
163int fdt_read_uint32_array(int node, const char *prop_name, uint32_t *array,
164 uint32_t count)
165{
166 const fdt32_t *cuint;
167 int len;
168 uint32_t i;
169
170 cuint = fdt_getprop(fdt, node, prop_name, &len);
171 if (cuint == NULL) {
172 return -FDT_ERR_NOTFOUND;
173 }
174
175 if ((uint32_t)len != (count * sizeof(uint32_t))) {
176 return -FDT_ERR_BADLAYOUT;
177 }
178
179 for (i = 0; i < ((uint32_t)len / sizeof(uint32_t)); i++) {
180 *array = fdt32_to_cpu(*cuint);
181 array++;
182 cuint++;
183 }
184
185 return 0;
186}
Yann Gautierd0ca7f42018-07-13 21:33:09 +0200187
188/*******************************************************************************
Lionel Debieveb0899eb2019-09-24 17:41:11 +0200189 * This function fills reg node info (base & size) with an index found by
190 * checking the reg-names node.
191 * Returns 0 on success and a negative FDT error code on failure.
192 ******************************************************************************/
193int fdt_get_reg_props_by_name(int node, const char *name, uintptr_t *base,
194 size_t *size)
195{
196 const fdt32_t *cuint;
197 int index, len;
198
199 assert((fdt_get_node_parent_address_cells(node) == 1) &&
200 (fdt_get_node_parent_size_cells(node) == 1));
201
202 index = fdt_stringlist_search(fdt, node, "reg-names", name);
203 if (index < 0) {
204 return index;
205 }
206
207 cuint = fdt_getprop(fdt, node, "reg", &len);
208 if (cuint == NULL) {
209 return -FDT_ERR_NOTFOUND;
210 }
211
212 if ((index * (int)sizeof(uint32_t)) > len) {
213 return -FDT_ERR_BADVALUE;
214 }
215
216 cuint += index << 1;
217 if (base != NULL) {
218 *base = fdt32_to_cpu(*cuint);
219 }
220 cuint++;
221 if (size != NULL) {
222 *size = fdt32_to_cpu(*cuint);
223 }
224
225 return 0;
226}
227
228/*******************************************************************************
Yann Gautier1bef97a2019-06-04 17:20:44 +0200229 * This function gets the stdout path node.
230 * It reads the value indicated inside the device tree.
231 * Returns node offset on success and a negative FDT error code on failure.
232 ******************************************************************************/
233static int dt_get_stdout_node_offset(void)
234{
235 int node;
236 const char *cchar;
237
238 node = fdt_path_offset(fdt, "/secure-chosen");
239 if (node < 0) {
240 node = fdt_path_offset(fdt, "/chosen");
241 if (node < 0) {
242 return -FDT_ERR_NOTFOUND;
243 }
244 }
245
246 cchar = fdt_getprop(fdt, node, "stdout-path", NULL);
247 if (cchar == NULL) {
248 return -FDT_ERR_NOTFOUND;
249 }
250
251 node = -FDT_ERR_NOTFOUND;
252 if (strchr(cchar, (int)':') != NULL) {
253 const char *name;
254 char *str = (char *)cchar;
255 int len = 0;
256
257 while (strncmp(":", str, 1)) {
258 len++;
259 str++;
260 }
261
262 name = fdt_get_alias_namelen(fdt, cchar, len);
263
264 if (name != NULL) {
265 node = fdt_path_offset(fdt, name);
266 }
267 } else {
268 node = fdt_path_offset(fdt, cchar);
269 }
270
271 return node;
272}
273
274/*******************************************************************************
Yann Gautier69035a82018-07-05 16:48:16 +0200275 * This function gets the stdout pin configuration information from the DT.
276 * And then calls the sub-function to treat it and set GPIO registers.
Yann Gautier038bff22019-01-17 19:17:47 +0100277 * Returns 0 on success and a negative FDT error code on failure.
Yann Gautier69035a82018-07-05 16:48:16 +0200278 ******************************************************************************/
279int dt_set_stdout_pinctrl(void)
280{
281 int node;
282
283 node = dt_get_stdout_node_offset();
284 if (node < 0) {
285 return -FDT_ERR_NOTFOUND;
286 }
287
288 return dt_set_pinctrl_config(node);
289}
290
291/*******************************************************************************
292 * This function fills the generic information from a given node.
293 ******************************************************************************/
294void dt_fill_device_info(struct dt_node_info *info, int node)
295{
296 const fdt32_t *cuint;
297
Lionel Debieveb0899eb2019-09-24 17:41:11 +0200298 assert(fdt_get_node_parent_address_cells(node) == 1);
299
Yann Gautier69035a82018-07-05 16:48:16 +0200300 cuint = fdt_getprop(fdt, node, "reg", NULL);
301 if (cuint != NULL) {
302 info->base = fdt32_to_cpu(*cuint);
303 } else {
304 info->base = 0;
305 }
306
307 cuint = fdt_getprop(fdt, node, "clocks", NULL);
308 if (cuint != NULL) {
309 cuint++;
310 info->clock = (int)fdt32_to_cpu(*cuint);
311 } else {
312 info->clock = -1;
313 }
314
315 cuint = fdt_getprop(fdt, node, "resets", NULL);
316 if (cuint != NULL) {
317 cuint++;
318 info->reset = (int)fdt32_to_cpu(*cuint);
319 } else {
320 info->reset = -1;
321 }
322
Yann Gautier038bff22019-01-17 19:17:47 +0100323 info->status = fdt_get_status(node);
Yann Gautier69035a82018-07-05 16:48:16 +0200324}
325
326/*******************************************************************************
327 * This function retrieve the generic information from DT.
Yann Gautier038bff22019-01-17 19:17:47 +0100328 * Returns node on success and a negative FDT error code on failure.
Yann Gautier69035a82018-07-05 16:48:16 +0200329 ******************************************************************************/
330int dt_get_node(struct dt_node_info *info, int offset, const char *compat)
331{
332 int node;
333
334 node = fdt_node_offset_by_compatible(fdt, offset, compat);
335 if (node < 0) {
336 return -FDT_ERR_NOTFOUND;
337 }
338
339 dt_fill_device_info(info, node);
340
341 return node;
342}
343
344/*******************************************************************************
345 * This function gets the UART instance info of stdout from the DT.
Yann Gautier038bff22019-01-17 19:17:47 +0100346 * Returns node on success and a negative FDT error code on failure.
Yann Gautier69035a82018-07-05 16:48:16 +0200347 ******************************************************************************/
348int dt_get_stdout_uart_info(struct dt_node_info *info)
349{
350 int node;
351
352 node = dt_get_stdout_node_offset();
353 if (node < 0) {
354 return -FDT_ERR_NOTFOUND;
355 }
356
357 dt_fill_device_info(info, node);
358
359 return node;
360}
361
362/*******************************************************************************
Yann Gautiercaf575b2018-07-24 17:18:19 +0200363 * This function gets DDR size information from the DT.
Yann Gautier038bff22019-01-17 19:17:47 +0100364 * Returns value in bytes on success, and 0 on failure.
Yann Gautiercaf575b2018-07-24 17:18:19 +0200365 ******************************************************************************/
366uint32_t dt_get_ddr_size(void)
367{
368 int node;
369
370 node = fdt_node_offset_by_compatible(fdt, -1, DT_DDR_COMPAT);
371 if (node < 0) {
372 INFO("%s: Cannot read DDR node in DT\n", __func__);
Yann Gautier038bff22019-01-17 19:17:47 +0100373 return 0;
Yann Gautiercaf575b2018-07-24 17:18:19 +0200374 }
375
Yann Gautier038bff22019-01-17 19:17:47 +0100376 return fdt_read_uint32_default(node, "st,mem-size", 0);
Yann Gautiercaf575b2018-07-24 17:18:19 +0200377}
378
379/*******************************************************************************
Yann Gautier3d78a2e2019-02-14 11:01:20 +0100380 * This function gets DDRCTRL base address information from the DT.
381 * Returns value on success, and 0 on failure.
382 ******************************************************************************/
383uintptr_t dt_get_ddrctrl_base(void)
384{
385 int node;
386 uint32_t array[4];
387
388 node = fdt_node_offset_by_compatible(fdt, -1, DT_DDR_COMPAT);
389 if (node < 0) {
390 INFO("%s: Cannot read DDR node in DT\n", __func__);
391 return 0;
392 }
393
Lionel Debieveb0899eb2019-09-24 17:41:11 +0200394 assert((fdt_get_node_parent_address_cells(node) == 1) &&
395 (fdt_get_node_parent_size_cells(node) == 1));
396
Yann Gautier3d78a2e2019-02-14 11:01:20 +0100397 if (fdt_read_uint32_array(node, "reg", array, 4) < 0) {
398 return 0;
399 }
400
401 return array[0];
402}
403
404/*******************************************************************************
405 * This function gets DDRPHYC base address information from the DT.
406 * Returns value on success, and 0 on failure.
407 ******************************************************************************/
408uintptr_t dt_get_ddrphyc_base(void)
409{
410 int node;
411 uint32_t array[4];
412
413 node = fdt_node_offset_by_compatible(fdt, -1, DT_DDR_COMPAT);
414 if (node < 0) {
415 INFO("%s: Cannot read DDR node in DT\n", __func__);
416 return 0;
417 }
418
Lionel Debieveb0899eb2019-09-24 17:41:11 +0200419 assert((fdt_get_node_parent_address_cells(node) == 1) &&
420 (fdt_get_node_parent_size_cells(node) == 1));
421
Yann Gautier3d78a2e2019-02-14 11:01:20 +0100422 if (fdt_read_uint32_array(node, "reg", array, 4) < 0) {
423 return 0;
424 }
425
426 return array[2];
427}
428
429/*******************************************************************************
430 * This function gets PWR base address information from the DT.
431 * Returns value on success, and 0 on failure.
432 ******************************************************************************/
433uintptr_t dt_get_pwr_base(void)
434{
435 int node;
436 const fdt32_t *cuint;
437
438 node = fdt_node_offset_by_compatible(fdt, -1, DT_PWR_COMPAT);
439 if (node < 0) {
440 INFO("%s: Cannot read PWR node in DT\n", __func__);
441 return 0;
442 }
443
Lionel Debieveb0899eb2019-09-24 17:41:11 +0200444 assert(fdt_get_node_parent_address_cells(node) == 1);
445
Yann Gautier3d78a2e2019-02-14 11:01:20 +0100446 cuint = fdt_getprop(fdt, node, "reg", NULL);
447 if (cuint == NULL) {
448 return 0;
449 }
450
451 return fdt32_to_cpu(*cuint);
452}
453
454/*******************************************************************************
Yann Gautier3edc7c32019-05-20 19:17:08 +0200455 * This function gets PWR VDD regulator voltage information from the DT.
456 * Returns value in microvolts on success, and 0 on failure.
457 ******************************************************************************/
458uint32_t dt_get_pwr_vdd_voltage(void)
459{
460 int node, pwr_regulators_node;
461 const fdt32_t *cuint;
462
463 node = fdt_node_offset_by_compatible(fdt, -1, DT_PWR_COMPAT);
464 if (node < 0) {
465 INFO("%s: Cannot read PWR node in DT\n", __func__);
466 return 0;
467 }
468
469 pwr_regulators_node = fdt_subnode_offset(fdt, node, "pwr-regulators");
470 if (node < 0) {
471 INFO("%s: Cannot read pwr-regulators node in DT\n", __func__);
472 return 0;
473 }
474
475 cuint = fdt_getprop(fdt, pwr_regulators_node, "vdd-supply", NULL);
476 if (cuint == NULL) {
477 return 0;
478 }
479
480 node = fdt_node_offset_by_phandle(fdt, fdt32_to_cpu(*cuint));
481 if (node < 0) {
482 return 0;
483 }
484
485 cuint = fdt_getprop(fdt, node, "regulator-min-microvolt", NULL);
486 if (cuint == NULL) {
487 return 0;
488 }
489
490 return fdt32_to_cpu(*cuint);
491}
492
493/*******************************************************************************
494 * This function gets SYSCFG base address information from the DT.
495 * Returns value on success, and 0 on failure.
496 ******************************************************************************/
497uintptr_t dt_get_syscfg_base(void)
498{
499 int node;
500 const fdt32_t *cuint;
501
502 node = fdt_node_offset_by_compatible(fdt, -1, DT_SYSCFG_COMPAT);
503 if (node < 0) {
504 INFO("%s: Cannot read SYSCFG node in DT\n", __func__);
505 return 0;
506 }
507
Lionel Debieveb0899eb2019-09-24 17:41:11 +0200508 assert(fdt_get_node_parent_address_cells(node) == 1);
509
Yann Gautier3edc7c32019-05-20 19:17:08 +0200510 cuint = fdt_getprop(fdt, node, "reg", NULL);
511 if (cuint == NULL) {
512 return 0;
513 }
514
515 return fdt32_to_cpu(*cuint);
516}
517
518/*******************************************************************************
Yann Gautier69035a82018-07-05 16:48:16 +0200519 * This function retrieves board model from DT
520 * Returns string taken from model node, NULL otherwise
521 ******************************************************************************/
522const char *dt_get_board_model(void)
523{
524 int node = fdt_path_offset(fdt, "/");
525
526 if (node < 0) {
527 return NULL;
528 }
529
530 return (const char *)fdt_getprop(fdt, node, "model", NULL);
531}