blob: c76b033589494f2686e93c2c9ffa748ce4d8befb [file] [log] [blame]
Yann Gautier7839a052018-07-24 17:13:36 +02001/*
Yann Gautiercd4941d2020-03-11 17:17:51 +01002 * Copyright (c) 2017-2020, ARM Limited and Contributors. All rights reserved.
Yann Gautier7839a052018-07-24 17:13:36 +02003 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
7#include <assert.h>
Yann Gautier1fc21302019-01-17 19:17:47 +01008#include <errno.h>
Antonio Nino Diaz09d40e02018-12-14 00:18:21 +00009
Yann Gautier7839a052018-07-24 17:13:36 +020010#include <libfdt.h>
Antonio Nino Diaz09d40e02018-12-14 00:18:21 +000011
Yann Gautier7839a052018-07-24 17:13:36 +020012#include <platform_def.h>
Antonio Nino Diaz09d40e02018-12-14 00:18:21 +000013
14#include <common/debug.h>
Andre Przywara52a616b2020-03-26 12:51:21 +000015#include <common/fdt_wrappers.h>
Antonio Nino Diaz09d40e02018-12-14 00:18:21 +000016#include <drivers/st/stm32_gpio.h>
Antonio Nino Diaz09d40e02018-12-14 00:18:21 +000017#include <drivers/st/stm32mp1_ddr.h>
18#include <drivers/st/stm32mp1_ram.h>
19
Yann Gautierc9d75b32019-02-14 11:13:25 +010020#include <stm32mp_dt.h>
21
Yann Gautier7839a052018-07-24 17:13:36 +020022static int fdt_checked;
23
Yann Gautier3f9c9782019-02-14 11:13:39 +010024static void *fdt = (void *)(uintptr_t)STM32MP_DTB_BASE;
Yann Gautier7839a052018-07-24 17:13:36 +020025
26/*******************************************************************************
27 * This function checks device tree file with its header.
Yann Gautier1fc21302019-01-17 19:17:47 +010028 * Returns 0 on success and a negative FDT error code on failure.
Yann Gautier7839a052018-07-24 17:13:36 +020029 ******************************************************************************/
30int dt_open_and_check(void)
31{
32 int ret = fdt_check_header(fdt);
33
34 if (ret == 0) {
35 fdt_checked = 1;
36 }
37
38 return ret;
39}
40
41/*******************************************************************************
42 * This function gets the address of the DT.
43 * If DT is OK, fdt_addr is filled with DT address.
44 * Returns 1 if success, 0 otherwise.
45 ******************************************************************************/
46int fdt_get_address(void **fdt_addr)
47{
48 if (fdt_checked == 1) {
49 *fdt_addr = fdt;
50 }
51
52 return fdt_checked;
53}
54
55/*******************************************************************************
56 * This function check the presence of a node (generic use of fdt library).
Yann Gautier1fc21302019-01-17 19:17:47 +010057 * Returns true if present, else return false.
Yann Gautier7839a052018-07-24 17:13:36 +020058 ******************************************************************************/
59bool 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/*******************************************************************************
Yann Gautier1fc21302019-01-17 19:17:47 +010070 * This function return global node status (generic use of fdt library).
Yann Gautier7839a052018-07-24 17:13:36 +020071 ******************************************************************************/
Yann Gautierc9d75b32019-02-14 11:13:25 +010072uint8_t fdt_get_status(int node)
Yann Gautier7839a052018-07-24 17:13:36 +020073{
Yann Gautierc9d75b32019-02-14 11:13:25 +010074 uint8_t status = DT_DISABLED;
Yann Gautier7839a052018-07-24 17:13:36 +020075 int len;
76 const char *cchar;
77
78 cchar = fdt_getprop(fdt, node, "status", &len);
Yann Gautier1fc21302019-01-17 19:17:47 +010079 if ((cchar == NULL) ||
80 (strncmp(cchar, "okay", (size_t)len) == 0)) {
81 status |= DT_NON_SECURE;
Yann Gautier7839a052018-07-24 17:13:36 +020082 }
83
Yann Gautier7839a052018-07-24 17:13:36 +020084 cchar = fdt_getprop(fdt, node, "secure-status", &len);
85 if (cchar == NULL) {
Yann Gautier1fc21302019-01-17 19:17:47 +010086 if (status == DT_NON_SECURE) {
87 status |= DT_SECURE;
88 }
89 } else if (strncmp(cchar, "okay", (size_t)len) == 0) {
90 status |= DT_SECURE;
Yann Gautier7839a052018-07-24 17:13:36 +020091 }
92
Yann Gautier1fc21302019-01-17 19:17:47 +010093 return status;
Yann Gautier7839a052018-07-24 17:13:36 +020094}
95
Yann Gautiercd4941d2020-03-11 17:17:51 +010096#if ENABLE_ASSERTIONS
Yann Gautier7839a052018-07-24 17:13:36 +020097/*******************************************************************************
Lionel Debievedd85e572019-09-24 17:41:11 +020098 * This function returns the address cells from the node parent.
99 * Returns:
100 * - #address-cells value if success.
101 * - invalid value if error.
102 * - a default value if undefined #address-cells property as per libfdt
103 * implementation.
104 ******************************************************************************/
Yann Gautiercd4941d2020-03-11 17:17:51 +0100105static int fdt_get_node_parent_address_cells(int node)
Lionel Debievedd85e572019-09-24 17:41:11 +0200106{
107 int parent;
108
109 parent = fdt_parent_offset(fdt, node);
110 if (parent < 0) {
111 return -FDT_ERR_NOTFOUND;
112 }
113
114 return fdt_address_cells(fdt, parent);
115}
116
117/*******************************************************************************
118 * This function returns the size cells from the node parent.
119 * Returns:
120 * - #size-cells value if success.
121 * - invalid value if error.
122 * - a default value if undefined #size-cells property as per libfdt
123 * implementation.
124 ******************************************************************************/
Yann Gautiercd4941d2020-03-11 17:17:51 +0100125static int fdt_get_node_parent_size_cells(int node)
Lionel Debievedd85e572019-09-24 17:41:11 +0200126{
127 int parent;
128
129 parent = fdt_parent_offset(fdt, node);
130 if (parent < 0) {
131 return -FDT_ERR_NOTFOUND;
132 }
133
134 return fdt_size_cells(fdt, parent);
135}
Yann Gautiercd4941d2020-03-11 17:17:51 +0100136#endif
Lionel Debievedd85e572019-09-24 17:41:11 +0200137
138/*******************************************************************************
Lionel Debievedd85e572019-09-24 17:41:11 +0200139 * This function fills reg node info (base & size) with an index found by
140 * checking the reg-names node.
141 * Returns 0 on success and a negative FDT error code on failure.
142 ******************************************************************************/
143int fdt_get_reg_props_by_name(int node, const char *name, uintptr_t *base,
144 size_t *size)
145{
146 const fdt32_t *cuint;
147 int index, len;
148
149 assert((fdt_get_node_parent_address_cells(node) == 1) &&
150 (fdt_get_node_parent_size_cells(node) == 1));
151
152 index = fdt_stringlist_search(fdt, node, "reg-names", name);
153 if (index < 0) {
154 return index;
155 }
156
157 cuint = fdt_getprop(fdt, node, "reg", &len);
158 if (cuint == NULL) {
159 return -FDT_ERR_NOTFOUND;
160 }
161
162 if ((index * (int)sizeof(uint32_t)) > len) {
163 return -FDT_ERR_BADVALUE;
164 }
165
166 cuint += index << 1;
167 if (base != NULL) {
168 *base = fdt32_to_cpu(*cuint);
169 }
170 cuint++;
171 if (size != NULL) {
172 *size = fdt32_to_cpu(*cuint);
173 }
174
175 return 0;
176}
177
178/*******************************************************************************
Yann Gautierf8055942019-06-04 17:20:44 +0200179 * This function gets the stdout path node.
180 * It reads the value indicated inside the device tree.
181 * Returns node offset on success and a negative FDT error code on failure.
182 ******************************************************************************/
183static int dt_get_stdout_node_offset(void)
184{
185 int node;
186 const char *cchar;
187
188 node = fdt_path_offset(fdt, "/secure-chosen");
189 if (node < 0) {
190 node = fdt_path_offset(fdt, "/chosen");
191 if (node < 0) {
192 return -FDT_ERR_NOTFOUND;
193 }
194 }
195
196 cchar = fdt_getprop(fdt, node, "stdout-path", NULL);
197 if (cchar == NULL) {
198 return -FDT_ERR_NOTFOUND;
199 }
200
201 node = -FDT_ERR_NOTFOUND;
202 if (strchr(cchar, (int)':') != NULL) {
203 const char *name;
204 char *str = (char *)cchar;
205 int len = 0;
206
207 while (strncmp(":", str, 1)) {
208 len++;
209 str++;
210 }
211
212 name = fdt_get_alias_namelen(fdt, cchar, len);
213
214 if (name != NULL) {
215 node = fdt_path_offset(fdt, name);
216 }
217 } else {
218 node = fdt_path_offset(fdt, cchar);
219 }
220
221 return node;
222}
223
224/*******************************************************************************
Yann Gautier278c34d2018-07-05 16:48:16 +0200225 * This function gets the stdout pin configuration information from the DT.
226 * And then calls the sub-function to treat it and set GPIO registers.
Yann Gautier1fc21302019-01-17 19:17:47 +0100227 * Returns 0 on success and a negative FDT error code on failure.
Yann Gautier278c34d2018-07-05 16:48:16 +0200228 ******************************************************************************/
229int dt_set_stdout_pinctrl(void)
230{
231 int node;
232
233 node = dt_get_stdout_node_offset();
234 if (node < 0) {
235 return -FDT_ERR_NOTFOUND;
236 }
237
238 return dt_set_pinctrl_config(node);
239}
240
241/*******************************************************************************
242 * This function fills the generic information from a given node.
243 ******************************************************************************/
244void dt_fill_device_info(struct dt_node_info *info, int node)
245{
246 const fdt32_t *cuint;
247
Lionel Debievedd85e572019-09-24 17:41:11 +0200248 assert(fdt_get_node_parent_address_cells(node) == 1);
249
Yann Gautier278c34d2018-07-05 16:48:16 +0200250 cuint = fdt_getprop(fdt, node, "reg", NULL);
251 if (cuint != NULL) {
252 info->base = fdt32_to_cpu(*cuint);
253 } else {
254 info->base = 0;
255 }
256
257 cuint = fdt_getprop(fdt, node, "clocks", NULL);
258 if (cuint != NULL) {
259 cuint++;
260 info->clock = (int)fdt32_to_cpu(*cuint);
261 } else {
262 info->clock = -1;
263 }
264
265 cuint = fdt_getprop(fdt, node, "resets", NULL);
266 if (cuint != NULL) {
267 cuint++;
268 info->reset = (int)fdt32_to_cpu(*cuint);
269 } else {
270 info->reset = -1;
271 }
272
Yann Gautier1fc21302019-01-17 19:17:47 +0100273 info->status = fdt_get_status(node);
Yann Gautier278c34d2018-07-05 16:48:16 +0200274}
275
276/*******************************************************************************
277 * This function retrieve the generic information from DT.
Yann Gautier1fc21302019-01-17 19:17:47 +0100278 * Returns node on success and a negative FDT error code on failure.
Yann Gautier278c34d2018-07-05 16:48:16 +0200279 ******************************************************************************/
280int dt_get_node(struct dt_node_info *info, int offset, const char *compat)
281{
282 int node;
283
284 node = fdt_node_offset_by_compatible(fdt, offset, compat);
285 if (node < 0) {
286 return -FDT_ERR_NOTFOUND;
287 }
288
289 dt_fill_device_info(info, node);
290
291 return node;
292}
293
294/*******************************************************************************
295 * This function gets the UART instance info of stdout from the DT.
Yann Gautier1fc21302019-01-17 19:17:47 +0100296 * Returns node on success and a negative FDT error code on failure.
Yann Gautier278c34d2018-07-05 16:48:16 +0200297 ******************************************************************************/
298int dt_get_stdout_uart_info(struct dt_node_info *info)
299{
300 int node;
301
302 node = dt_get_stdout_node_offset();
303 if (node < 0) {
304 return -FDT_ERR_NOTFOUND;
305 }
306
307 dt_fill_device_info(info, node);
308
309 return node;
310}
311
312/*******************************************************************************
Yann Gautier10a511c2018-07-24 17:18:19 +0200313 * This function gets DDR size information from the DT.
Yann Gautier1fc21302019-01-17 19:17:47 +0100314 * Returns value in bytes on success, and 0 on failure.
Yann Gautier10a511c2018-07-24 17:18:19 +0200315 ******************************************************************************/
316uint32_t dt_get_ddr_size(void)
317{
318 int node;
319
320 node = fdt_node_offset_by_compatible(fdt, -1, DT_DDR_COMPAT);
321 if (node < 0) {
322 INFO("%s: Cannot read DDR node in DT\n", __func__);
Yann Gautier1fc21302019-01-17 19:17:47 +0100323 return 0;
Yann Gautier10a511c2018-07-24 17:18:19 +0200324 }
325
Andre Przywarabe858cf2020-03-26 11:50:33 +0000326 return fdt_read_uint32_default(fdt, node, "st,mem-size", 0);
Yann Gautier10a511c2018-07-24 17:18:19 +0200327}
328
329/*******************************************************************************
Yann Gautier7ae58c62019-02-14 11:01:20 +0100330 * This function gets DDRCTRL base address information from the DT.
331 * Returns value on success, and 0 on failure.
332 ******************************************************************************/
333uintptr_t dt_get_ddrctrl_base(void)
334{
335 int node;
336 uint32_t array[4];
337
338 node = fdt_node_offset_by_compatible(fdt, -1, DT_DDR_COMPAT);
339 if (node < 0) {
340 INFO("%s: Cannot read DDR node in DT\n", __func__);
341 return 0;
342 }
343
Lionel Debievedd85e572019-09-24 17:41:11 +0200344 assert((fdt_get_node_parent_address_cells(node) == 1) &&
345 (fdt_get_node_parent_size_cells(node) == 1));
346
Andre Przywara52a616b2020-03-26 12:51:21 +0000347 if (fdt_read_uint32_array(fdt, node, "reg", 4, array) < 0) {
Yann Gautier7ae58c62019-02-14 11:01:20 +0100348 return 0;
349 }
350
351 return array[0];
352}
353
354/*******************************************************************************
355 * This function gets DDRPHYC base address information from the DT.
356 * Returns value on success, and 0 on failure.
357 ******************************************************************************/
358uintptr_t dt_get_ddrphyc_base(void)
359{
360 int node;
361 uint32_t array[4];
362
363 node = fdt_node_offset_by_compatible(fdt, -1, DT_DDR_COMPAT);
364 if (node < 0) {
365 INFO("%s: Cannot read DDR node in DT\n", __func__);
366 return 0;
367 }
368
Lionel Debievedd85e572019-09-24 17:41:11 +0200369 assert((fdt_get_node_parent_address_cells(node) == 1) &&
370 (fdt_get_node_parent_size_cells(node) == 1));
371
Andre Przywara52a616b2020-03-26 12:51:21 +0000372 if (fdt_read_uint32_array(fdt, node, "reg", 4, array) < 0) {
Yann Gautier7ae58c62019-02-14 11:01:20 +0100373 return 0;
374 }
375
376 return array[2];
377}
378
379/*******************************************************************************
380 * This function gets PWR base address information from the DT.
381 * Returns value on success, and 0 on failure.
382 ******************************************************************************/
383uintptr_t dt_get_pwr_base(void)
384{
385 int node;
386 const fdt32_t *cuint;
387
388 node = fdt_node_offset_by_compatible(fdt, -1, DT_PWR_COMPAT);
389 if (node < 0) {
390 INFO("%s: Cannot read PWR node in DT\n", __func__);
391 return 0;
392 }
393
Lionel Debievedd85e572019-09-24 17:41:11 +0200394 assert(fdt_get_node_parent_address_cells(node) == 1);
395
Yann Gautier7ae58c62019-02-14 11:01:20 +0100396 cuint = fdt_getprop(fdt, node, "reg", NULL);
397 if (cuint == NULL) {
398 return 0;
399 }
400
401 return fdt32_to_cpu(*cuint);
402}
403
404/*******************************************************************************
Yann Gautierf33b2432019-05-20 19:17:08 +0200405 * This function gets PWR VDD regulator voltage information from the DT.
406 * Returns value in microvolts on success, and 0 on failure.
407 ******************************************************************************/
408uint32_t dt_get_pwr_vdd_voltage(void)
409{
410 int node, pwr_regulators_node;
411 const fdt32_t *cuint;
412
413 node = fdt_node_offset_by_compatible(fdt, -1, DT_PWR_COMPAT);
414 if (node < 0) {
415 INFO("%s: Cannot read PWR node in DT\n", __func__);
416 return 0;
417 }
418
419 pwr_regulators_node = fdt_subnode_offset(fdt, node, "pwr-regulators");
Yann Gautiere9d1e5a2020-03-18 14:35:27 +0100420 if (pwr_regulators_node < 0) {
Yann Gautierf33b2432019-05-20 19:17:08 +0200421 INFO("%s: Cannot read pwr-regulators node in DT\n", __func__);
422 return 0;
423 }
424
425 cuint = fdt_getprop(fdt, pwr_regulators_node, "vdd-supply", NULL);
426 if (cuint == NULL) {
427 return 0;
428 }
429
430 node = fdt_node_offset_by_phandle(fdt, fdt32_to_cpu(*cuint));
431 if (node < 0) {
432 return 0;
433 }
434
435 cuint = fdt_getprop(fdt, node, "regulator-min-microvolt", NULL);
436 if (cuint == NULL) {
437 return 0;
438 }
439
440 return fdt32_to_cpu(*cuint);
441}
442
443/*******************************************************************************
444 * This function gets SYSCFG base address information from the DT.
445 * Returns value on success, and 0 on failure.
446 ******************************************************************************/
447uintptr_t dt_get_syscfg_base(void)
448{
449 int node;
450 const fdt32_t *cuint;
451
452 node = fdt_node_offset_by_compatible(fdt, -1, DT_SYSCFG_COMPAT);
453 if (node < 0) {
454 INFO("%s: Cannot read SYSCFG node in DT\n", __func__);
455 return 0;
456 }
457
Lionel Debievedd85e572019-09-24 17:41:11 +0200458 assert(fdt_get_node_parent_address_cells(node) == 1);
459
Yann Gautierf33b2432019-05-20 19:17:08 +0200460 cuint = fdt_getprop(fdt, node, "reg", NULL);
461 if (cuint == NULL) {
462 return 0;
463 }
464
465 return fdt32_to_cpu(*cuint);
466}
467
468/*******************************************************************************
Yann Gautier278c34d2018-07-05 16:48:16 +0200469 * This function retrieves board model from DT
470 * Returns string taken from model node, NULL otherwise
471 ******************************************************************************/
472const char *dt_get_board_model(void)
473{
474 int node = fdt_path_offset(fdt, "/");
475
476 if (node < 0) {
477 return NULL;
478 }
479
480 return (const char *)fdt_getprop(fdt, node, "model", NULL);
481}