blob: 6b76424ae37c7ba08392a50e0108e8602056e022 [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/*******************************************************************************
Yann Gautier7839a052018-07-24 17:13:36 +0200139 * This function reads a value of a node property (generic use of fdt
140 * library).
141 * Returns value if success, and a default value if property not found.
142 * Default value is passed as parameter.
143 ******************************************************************************/
144uint32_t fdt_read_uint32_default(int node, const char *prop_name,
145 uint32_t dflt_value)
146{
147 const fdt32_t *cuint;
148 int lenp;
149
150 cuint = fdt_getprop(fdt, node, prop_name, &lenp);
151 if (cuint == NULL) {
152 return dflt_value;
153 }
154
155 return fdt32_to_cpu(*cuint);
156}
157
158/*******************************************************************************
Lionel Debievedd85e572019-09-24 17:41:11 +0200159 * This function fills reg node info (base & size) with an index found by
160 * checking the reg-names node.
161 * Returns 0 on success and a negative FDT error code on failure.
162 ******************************************************************************/
163int fdt_get_reg_props_by_name(int node, const char *name, uintptr_t *base,
164 size_t *size)
165{
166 const fdt32_t *cuint;
167 int index, len;
168
169 assert((fdt_get_node_parent_address_cells(node) == 1) &&
170 (fdt_get_node_parent_size_cells(node) == 1));
171
172 index = fdt_stringlist_search(fdt, node, "reg-names", name);
173 if (index < 0) {
174 return index;
175 }
176
177 cuint = fdt_getprop(fdt, node, "reg", &len);
178 if (cuint == NULL) {
179 return -FDT_ERR_NOTFOUND;
180 }
181
182 if ((index * (int)sizeof(uint32_t)) > len) {
183 return -FDT_ERR_BADVALUE;
184 }
185
186 cuint += index << 1;
187 if (base != NULL) {
188 *base = fdt32_to_cpu(*cuint);
189 }
190 cuint++;
191 if (size != NULL) {
192 *size = fdt32_to_cpu(*cuint);
193 }
194
195 return 0;
196}
197
198/*******************************************************************************
Yann Gautierf8055942019-06-04 17:20:44 +0200199 * This function gets the stdout path node.
200 * It reads the value indicated inside the device tree.
201 * Returns node offset on success and a negative FDT error code on failure.
202 ******************************************************************************/
203static int dt_get_stdout_node_offset(void)
204{
205 int node;
206 const char *cchar;
207
208 node = fdt_path_offset(fdt, "/secure-chosen");
209 if (node < 0) {
210 node = fdt_path_offset(fdt, "/chosen");
211 if (node < 0) {
212 return -FDT_ERR_NOTFOUND;
213 }
214 }
215
216 cchar = fdt_getprop(fdt, node, "stdout-path", NULL);
217 if (cchar == NULL) {
218 return -FDT_ERR_NOTFOUND;
219 }
220
221 node = -FDT_ERR_NOTFOUND;
222 if (strchr(cchar, (int)':') != NULL) {
223 const char *name;
224 char *str = (char *)cchar;
225 int len = 0;
226
227 while (strncmp(":", str, 1)) {
228 len++;
229 str++;
230 }
231
232 name = fdt_get_alias_namelen(fdt, cchar, len);
233
234 if (name != NULL) {
235 node = fdt_path_offset(fdt, name);
236 }
237 } else {
238 node = fdt_path_offset(fdt, cchar);
239 }
240
241 return node;
242}
243
244/*******************************************************************************
Yann Gautier278c34d2018-07-05 16:48:16 +0200245 * This function gets the stdout pin configuration information from the DT.
246 * And then calls the sub-function to treat it and set GPIO registers.
Yann Gautier1fc21302019-01-17 19:17:47 +0100247 * Returns 0 on success and a negative FDT error code on failure.
Yann Gautier278c34d2018-07-05 16:48:16 +0200248 ******************************************************************************/
249int dt_set_stdout_pinctrl(void)
250{
251 int node;
252
253 node = dt_get_stdout_node_offset();
254 if (node < 0) {
255 return -FDT_ERR_NOTFOUND;
256 }
257
258 return dt_set_pinctrl_config(node);
259}
260
261/*******************************************************************************
262 * This function fills the generic information from a given node.
263 ******************************************************************************/
264void dt_fill_device_info(struct dt_node_info *info, int node)
265{
266 const fdt32_t *cuint;
267
Lionel Debievedd85e572019-09-24 17:41:11 +0200268 assert(fdt_get_node_parent_address_cells(node) == 1);
269
Yann Gautier278c34d2018-07-05 16:48:16 +0200270 cuint = fdt_getprop(fdt, node, "reg", NULL);
271 if (cuint != NULL) {
272 info->base = fdt32_to_cpu(*cuint);
273 } else {
274 info->base = 0;
275 }
276
277 cuint = fdt_getprop(fdt, node, "clocks", NULL);
278 if (cuint != NULL) {
279 cuint++;
280 info->clock = (int)fdt32_to_cpu(*cuint);
281 } else {
282 info->clock = -1;
283 }
284
285 cuint = fdt_getprop(fdt, node, "resets", NULL);
286 if (cuint != NULL) {
287 cuint++;
288 info->reset = (int)fdt32_to_cpu(*cuint);
289 } else {
290 info->reset = -1;
291 }
292
Yann Gautier1fc21302019-01-17 19:17:47 +0100293 info->status = fdt_get_status(node);
Yann Gautier278c34d2018-07-05 16:48:16 +0200294}
295
296/*******************************************************************************
297 * This function retrieve the generic information from DT.
Yann Gautier1fc21302019-01-17 19:17:47 +0100298 * Returns node on success and a negative FDT error code on failure.
Yann Gautier278c34d2018-07-05 16:48:16 +0200299 ******************************************************************************/
300int dt_get_node(struct dt_node_info *info, int offset, const char *compat)
301{
302 int node;
303
304 node = fdt_node_offset_by_compatible(fdt, offset, compat);
305 if (node < 0) {
306 return -FDT_ERR_NOTFOUND;
307 }
308
309 dt_fill_device_info(info, node);
310
311 return node;
312}
313
314/*******************************************************************************
315 * This function gets the UART instance info of stdout from the DT.
Yann Gautier1fc21302019-01-17 19:17:47 +0100316 * Returns node on success and a negative FDT error code on failure.
Yann Gautier278c34d2018-07-05 16:48:16 +0200317 ******************************************************************************/
318int dt_get_stdout_uart_info(struct dt_node_info *info)
319{
320 int node;
321
322 node = dt_get_stdout_node_offset();
323 if (node < 0) {
324 return -FDT_ERR_NOTFOUND;
325 }
326
327 dt_fill_device_info(info, node);
328
329 return node;
330}
331
332/*******************************************************************************
Yann Gautier10a511c2018-07-24 17:18:19 +0200333 * This function gets DDR size information from the DT.
Yann Gautier1fc21302019-01-17 19:17:47 +0100334 * Returns value in bytes on success, and 0 on failure.
Yann Gautier10a511c2018-07-24 17:18:19 +0200335 ******************************************************************************/
336uint32_t dt_get_ddr_size(void)
337{
338 int node;
339
340 node = fdt_node_offset_by_compatible(fdt, -1, DT_DDR_COMPAT);
341 if (node < 0) {
342 INFO("%s: Cannot read DDR node in DT\n", __func__);
Yann Gautier1fc21302019-01-17 19:17:47 +0100343 return 0;
Yann Gautier10a511c2018-07-24 17:18:19 +0200344 }
345
Yann Gautier1fc21302019-01-17 19:17:47 +0100346 return fdt_read_uint32_default(node, "st,mem-size", 0);
Yann Gautier10a511c2018-07-24 17:18:19 +0200347}
348
349/*******************************************************************************
Yann Gautier7ae58c62019-02-14 11:01:20 +0100350 * This function gets DDRCTRL base address information from the DT.
351 * Returns value on success, and 0 on failure.
352 ******************************************************************************/
353uintptr_t dt_get_ddrctrl_base(void)
354{
355 int node;
356 uint32_t array[4];
357
358 node = fdt_node_offset_by_compatible(fdt, -1, DT_DDR_COMPAT);
359 if (node < 0) {
360 INFO("%s: Cannot read DDR node in DT\n", __func__);
361 return 0;
362 }
363
Lionel Debievedd85e572019-09-24 17:41:11 +0200364 assert((fdt_get_node_parent_address_cells(node) == 1) &&
365 (fdt_get_node_parent_size_cells(node) == 1));
366
Andre Przywara52a616b2020-03-26 12:51:21 +0000367 if (fdt_read_uint32_array(fdt, node, "reg", 4, array) < 0) {
Yann Gautier7ae58c62019-02-14 11:01:20 +0100368 return 0;
369 }
370
371 return array[0];
372}
373
374/*******************************************************************************
375 * This function gets DDRPHYC base address information from the DT.
376 * Returns value on success, and 0 on failure.
377 ******************************************************************************/
378uintptr_t dt_get_ddrphyc_base(void)
379{
380 int node;
381 uint32_t array[4];
382
383 node = fdt_node_offset_by_compatible(fdt, -1, DT_DDR_COMPAT);
384 if (node < 0) {
385 INFO("%s: Cannot read DDR node in DT\n", __func__);
386 return 0;
387 }
388
Lionel Debievedd85e572019-09-24 17:41:11 +0200389 assert((fdt_get_node_parent_address_cells(node) == 1) &&
390 (fdt_get_node_parent_size_cells(node) == 1));
391
Andre Przywara52a616b2020-03-26 12:51:21 +0000392 if (fdt_read_uint32_array(fdt, node, "reg", 4, array) < 0) {
Yann Gautier7ae58c62019-02-14 11:01:20 +0100393 return 0;
394 }
395
396 return array[2];
397}
398
399/*******************************************************************************
400 * This function gets PWR base address information from the DT.
401 * Returns value on success, and 0 on failure.
402 ******************************************************************************/
403uintptr_t dt_get_pwr_base(void)
404{
405 int node;
406 const fdt32_t *cuint;
407
408 node = fdt_node_offset_by_compatible(fdt, -1, DT_PWR_COMPAT);
409 if (node < 0) {
410 INFO("%s: Cannot read PWR node in DT\n", __func__);
411 return 0;
412 }
413
Lionel Debievedd85e572019-09-24 17:41:11 +0200414 assert(fdt_get_node_parent_address_cells(node) == 1);
415
Yann Gautier7ae58c62019-02-14 11:01:20 +0100416 cuint = fdt_getprop(fdt, node, "reg", NULL);
417 if (cuint == NULL) {
418 return 0;
419 }
420
421 return fdt32_to_cpu(*cuint);
422}
423
424/*******************************************************************************
Yann Gautierf33b2432019-05-20 19:17:08 +0200425 * This function gets PWR VDD regulator voltage information from the DT.
426 * Returns value in microvolts on success, and 0 on failure.
427 ******************************************************************************/
428uint32_t dt_get_pwr_vdd_voltage(void)
429{
430 int node, pwr_regulators_node;
431 const fdt32_t *cuint;
432
433 node = fdt_node_offset_by_compatible(fdt, -1, DT_PWR_COMPAT);
434 if (node < 0) {
435 INFO("%s: Cannot read PWR node in DT\n", __func__);
436 return 0;
437 }
438
439 pwr_regulators_node = fdt_subnode_offset(fdt, node, "pwr-regulators");
Yann Gautiere9d1e5a2020-03-18 14:35:27 +0100440 if (pwr_regulators_node < 0) {
Yann Gautierf33b2432019-05-20 19:17:08 +0200441 INFO("%s: Cannot read pwr-regulators node in DT\n", __func__);
442 return 0;
443 }
444
445 cuint = fdt_getprop(fdt, pwr_regulators_node, "vdd-supply", NULL);
446 if (cuint == NULL) {
447 return 0;
448 }
449
450 node = fdt_node_offset_by_phandle(fdt, fdt32_to_cpu(*cuint));
451 if (node < 0) {
452 return 0;
453 }
454
455 cuint = fdt_getprop(fdt, node, "regulator-min-microvolt", NULL);
456 if (cuint == NULL) {
457 return 0;
458 }
459
460 return fdt32_to_cpu(*cuint);
461}
462
463/*******************************************************************************
464 * This function gets SYSCFG base address information from the DT.
465 * Returns value on success, and 0 on failure.
466 ******************************************************************************/
467uintptr_t dt_get_syscfg_base(void)
468{
469 int node;
470 const fdt32_t *cuint;
471
472 node = fdt_node_offset_by_compatible(fdt, -1, DT_SYSCFG_COMPAT);
473 if (node < 0) {
474 INFO("%s: Cannot read SYSCFG node in DT\n", __func__);
475 return 0;
476 }
477
Lionel Debievedd85e572019-09-24 17:41:11 +0200478 assert(fdt_get_node_parent_address_cells(node) == 1);
479
Yann Gautierf33b2432019-05-20 19:17:08 +0200480 cuint = fdt_getprop(fdt, node, "reg", NULL);
481 if (cuint == NULL) {
482 return 0;
483 }
484
485 return fdt32_to_cpu(*cuint);
486}
487
488/*******************************************************************************
Yann Gautier278c34d2018-07-05 16:48:16 +0200489 * This function retrieves board model from DT
490 * Returns string taken from model node, NULL otherwise
491 ******************************************************************************/
492const char *dt_get_board_model(void)
493{
494 int node = fdt_path_offset(fdt, "/");
495
496 if (node < 0) {
497 return NULL;
498 }
499
500 return (const char *)fdt_getprop(fdt, node, "model", NULL);
501}