blob: 356af0bbcfe049a35d8ba20e1b7e04f4528190c8 [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 Gautierf8055942019-06-04 17:20:44 +0200139 * This function gets the stdout path node.
140 * It reads the value indicated inside the device tree.
141 * Returns node offset on success and a negative FDT error code on failure.
142 ******************************************************************************/
143static int dt_get_stdout_node_offset(void)
144{
145 int node;
146 const char *cchar;
147
148 node = fdt_path_offset(fdt, "/secure-chosen");
149 if (node < 0) {
150 node = fdt_path_offset(fdt, "/chosen");
151 if (node < 0) {
152 return -FDT_ERR_NOTFOUND;
153 }
154 }
155
156 cchar = fdt_getprop(fdt, node, "stdout-path", NULL);
157 if (cchar == NULL) {
158 return -FDT_ERR_NOTFOUND;
159 }
160
161 node = -FDT_ERR_NOTFOUND;
162 if (strchr(cchar, (int)':') != NULL) {
163 const char *name;
164 char *str = (char *)cchar;
165 int len = 0;
166
167 while (strncmp(":", str, 1)) {
168 len++;
169 str++;
170 }
171
172 name = fdt_get_alias_namelen(fdt, cchar, len);
173
174 if (name != NULL) {
175 node = fdt_path_offset(fdt, name);
176 }
177 } else {
178 node = fdt_path_offset(fdt, cchar);
179 }
180
181 return node;
182}
183
184/*******************************************************************************
Yann Gautier278c34d2018-07-05 16:48:16 +0200185 * This function gets the stdout pin configuration information from the DT.
186 * And then calls the sub-function to treat it and set GPIO registers.
Yann Gautier1fc21302019-01-17 19:17:47 +0100187 * Returns 0 on success and a negative FDT error code on failure.
Yann Gautier278c34d2018-07-05 16:48:16 +0200188 ******************************************************************************/
189int dt_set_stdout_pinctrl(void)
190{
191 int node;
192
193 node = dt_get_stdout_node_offset();
194 if (node < 0) {
195 return -FDT_ERR_NOTFOUND;
196 }
197
198 return dt_set_pinctrl_config(node);
199}
200
201/*******************************************************************************
202 * This function fills the generic information from a given node.
203 ******************************************************************************/
204void dt_fill_device_info(struct dt_node_info *info, int node)
205{
206 const fdt32_t *cuint;
207
Lionel Debievedd85e572019-09-24 17:41:11 +0200208 assert(fdt_get_node_parent_address_cells(node) == 1);
209
Yann Gautier278c34d2018-07-05 16:48:16 +0200210 cuint = fdt_getprop(fdt, node, "reg", NULL);
211 if (cuint != NULL) {
212 info->base = fdt32_to_cpu(*cuint);
213 } else {
214 info->base = 0;
215 }
216
217 cuint = fdt_getprop(fdt, node, "clocks", NULL);
218 if (cuint != NULL) {
219 cuint++;
220 info->clock = (int)fdt32_to_cpu(*cuint);
221 } else {
222 info->clock = -1;
223 }
224
225 cuint = fdt_getprop(fdt, node, "resets", NULL);
226 if (cuint != NULL) {
227 cuint++;
228 info->reset = (int)fdt32_to_cpu(*cuint);
229 } else {
230 info->reset = -1;
231 }
232
Yann Gautier1fc21302019-01-17 19:17:47 +0100233 info->status = fdt_get_status(node);
Yann Gautier278c34d2018-07-05 16:48:16 +0200234}
235
236/*******************************************************************************
237 * This function retrieve the generic information from DT.
Yann Gautier1fc21302019-01-17 19:17:47 +0100238 * Returns node on success and a negative FDT error code on failure.
Yann Gautier278c34d2018-07-05 16:48:16 +0200239 ******************************************************************************/
240int dt_get_node(struct dt_node_info *info, int offset, const char *compat)
241{
242 int node;
243
244 node = fdt_node_offset_by_compatible(fdt, offset, compat);
245 if (node < 0) {
246 return -FDT_ERR_NOTFOUND;
247 }
248
249 dt_fill_device_info(info, node);
250
251 return node;
252}
253
254/*******************************************************************************
255 * This function gets the UART instance info of stdout from the DT.
Yann Gautier1fc21302019-01-17 19:17:47 +0100256 * Returns node on success and a negative FDT error code on failure.
Yann Gautier278c34d2018-07-05 16:48:16 +0200257 ******************************************************************************/
258int dt_get_stdout_uart_info(struct dt_node_info *info)
259{
260 int node;
261
262 node = dt_get_stdout_node_offset();
263 if (node < 0) {
264 return -FDT_ERR_NOTFOUND;
265 }
266
267 dt_fill_device_info(info, node);
268
269 return node;
270}
271
272/*******************************************************************************
Yann Gautier10a511c2018-07-24 17:18:19 +0200273 * This function gets DDR size information from the DT.
Yann Gautier1fc21302019-01-17 19:17:47 +0100274 * Returns value in bytes on success, and 0 on failure.
Yann Gautier10a511c2018-07-24 17:18:19 +0200275 ******************************************************************************/
276uint32_t dt_get_ddr_size(void)
277{
278 int node;
279
280 node = fdt_node_offset_by_compatible(fdt, -1, DT_DDR_COMPAT);
281 if (node < 0) {
282 INFO("%s: Cannot read DDR node in DT\n", __func__);
Yann Gautier1fc21302019-01-17 19:17:47 +0100283 return 0;
Yann Gautier10a511c2018-07-24 17:18:19 +0200284 }
285
Andre Przywarabe858cf2020-03-26 11:50:33 +0000286 return fdt_read_uint32_default(fdt, node, "st,mem-size", 0);
Yann Gautier10a511c2018-07-24 17:18:19 +0200287}
288
289/*******************************************************************************
Yann Gautier7ae58c62019-02-14 11:01:20 +0100290 * This function gets DDRCTRL base address information from the DT.
291 * Returns value on success, and 0 on failure.
292 ******************************************************************************/
293uintptr_t dt_get_ddrctrl_base(void)
294{
295 int node;
296 uint32_t array[4];
297
298 node = fdt_node_offset_by_compatible(fdt, -1, DT_DDR_COMPAT);
299 if (node < 0) {
300 INFO("%s: Cannot read DDR node in DT\n", __func__);
301 return 0;
302 }
303
Lionel Debievedd85e572019-09-24 17:41:11 +0200304 assert((fdt_get_node_parent_address_cells(node) == 1) &&
305 (fdt_get_node_parent_size_cells(node) == 1));
306
Andre Przywara52a616b2020-03-26 12:51:21 +0000307 if (fdt_read_uint32_array(fdt, node, "reg", 4, array) < 0) {
Yann Gautier7ae58c62019-02-14 11:01:20 +0100308 return 0;
309 }
310
311 return array[0];
312}
313
314/*******************************************************************************
315 * This function gets DDRPHYC base address information from the DT.
316 * Returns value on success, and 0 on failure.
317 ******************************************************************************/
318uintptr_t dt_get_ddrphyc_base(void)
319{
320 int node;
321 uint32_t array[4];
322
323 node = fdt_node_offset_by_compatible(fdt, -1, DT_DDR_COMPAT);
324 if (node < 0) {
325 INFO("%s: Cannot read DDR node in DT\n", __func__);
326 return 0;
327 }
328
Lionel Debievedd85e572019-09-24 17:41:11 +0200329 assert((fdt_get_node_parent_address_cells(node) == 1) &&
330 (fdt_get_node_parent_size_cells(node) == 1));
331
Andre Przywara52a616b2020-03-26 12:51:21 +0000332 if (fdt_read_uint32_array(fdt, node, "reg", 4, array) < 0) {
Yann Gautier7ae58c62019-02-14 11:01:20 +0100333 return 0;
334 }
335
336 return array[2];
337}
338
339/*******************************************************************************
340 * This function gets PWR base address information from the DT.
341 * Returns value on success, and 0 on failure.
342 ******************************************************************************/
343uintptr_t dt_get_pwr_base(void)
344{
345 int node;
346 const fdt32_t *cuint;
347
348 node = fdt_node_offset_by_compatible(fdt, -1, DT_PWR_COMPAT);
349 if (node < 0) {
350 INFO("%s: Cannot read PWR node in DT\n", __func__);
351 return 0;
352 }
353
Lionel Debievedd85e572019-09-24 17:41:11 +0200354 assert(fdt_get_node_parent_address_cells(node) == 1);
355
Yann Gautier7ae58c62019-02-14 11:01:20 +0100356 cuint = fdt_getprop(fdt, node, "reg", NULL);
357 if (cuint == NULL) {
358 return 0;
359 }
360
361 return fdt32_to_cpu(*cuint);
362}
363
364/*******************************************************************************
Yann Gautierf33b2432019-05-20 19:17:08 +0200365 * This function gets PWR VDD regulator voltage information from the DT.
366 * Returns value in microvolts on success, and 0 on failure.
367 ******************************************************************************/
368uint32_t dt_get_pwr_vdd_voltage(void)
369{
370 int node, pwr_regulators_node;
371 const fdt32_t *cuint;
372
373 node = fdt_node_offset_by_compatible(fdt, -1, DT_PWR_COMPAT);
374 if (node < 0) {
375 INFO("%s: Cannot read PWR node in DT\n", __func__);
376 return 0;
377 }
378
379 pwr_regulators_node = fdt_subnode_offset(fdt, node, "pwr-regulators");
Yann Gautiere9d1e5a2020-03-18 14:35:27 +0100380 if (pwr_regulators_node < 0) {
Yann Gautierf33b2432019-05-20 19:17:08 +0200381 INFO("%s: Cannot read pwr-regulators node in DT\n", __func__);
382 return 0;
383 }
384
385 cuint = fdt_getprop(fdt, pwr_regulators_node, "vdd-supply", NULL);
386 if (cuint == NULL) {
387 return 0;
388 }
389
390 node = fdt_node_offset_by_phandle(fdt, fdt32_to_cpu(*cuint));
391 if (node < 0) {
392 return 0;
393 }
394
395 cuint = fdt_getprop(fdt, node, "regulator-min-microvolt", NULL);
396 if (cuint == NULL) {
397 return 0;
398 }
399
400 return fdt32_to_cpu(*cuint);
401}
402
403/*******************************************************************************
404 * This function gets SYSCFG base address information from the DT.
405 * Returns value on success, and 0 on failure.
406 ******************************************************************************/
407uintptr_t dt_get_syscfg_base(void)
408{
409 int node;
410 const fdt32_t *cuint;
411
412 node = fdt_node_offset_by_compatible(fdt, -1, DT_SYSCFG_COMPAT);
413 if (node < 0) {
414 INFO("%s: Cannot read SYSCFG node in DT\n", __func__);
415 return 0;
416 }
417
Lionel Debievedd85e572019-09-24 17:41:11 +0200418 assert(fdt_get_node_parent_address_cells(node) == 1);
419
Yann Gautierf33b2432019-05-20 19:17:08 +0200420 cuint = fdt_getprop(fdt, node, "reg", NULL);
421 if (cuint == NULL) {
422 return 0;
423 }
424
425 return fdt32_to_cpu(*cuint);
426}
427
428/*******************************************************************************
Yann Gautier278c34d2018-07-05 16:48:16 +0200429 * This function retrieves board model from DT
430 * Returns string taken from model node, NULL otherwise
431 ******************************************************************************/
432const char *dt_get_board_model(void)
433{
434 int node = fdt_path_offset(fdt, "/");
435
436 if (node < 0) {
437 return NULL;
438 }
439
440 return (const char *)fdt_getprop(fdt, node, "model", NULL);
441}