blob: 4b8b2db909e8edd56cd3a1433a2383fac84c8085 [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>
Andre Przywaracc99f3f2020-03-26 12:51:21 +000015#include <common/fdt_wrappers.h>
Antonio Nino Diaze0f90632018-12-14 00:18:21 +000016#include <drivers/st/stm32_gpio.h>
Antonio Nino Diaze0f90632018-12-14 00:18:21 +000017#include <drivers/st/stm32mp1_ddr.h>
18#include <drivers/st/stm32mp1_ram.h>
19
Yann Gautieree8f5422019-02-14 11:13:25 +010020#include <stm32mp_dt.h>
21
Yann Gautier9aea69e2018-07-24 17:13:36 +020022static int fdt_checked;
23
Yann Gautiera2e2a302019-02-14 11:13:39 +010024static void *fdt = (void *)(uintptr_t)STM32MP_DTB_BASE;
Yann Gautier9aea69e2018-07-24 17:13:36 +020025
26/*******************************************************************************
27 * This function checks device tree file with its header.
Yann Gautier038bff22019-01-17 19:17:47 +010028 * Returns 0 on success and a negative FDT error code on failure.
Yann Gautier9aea69e2018-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 Gautier038bff22019-01-17 19:17:47 +010057 * Returns true if present, else return false.
Yann Gautier9aea69e2018-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 Gautier038bff22019-01-17 19:17:47 +010070 * This function return global node status (generic use of fdt library).
Yann Gautier9aea69e2018-07-24 17:13:36 +020071 ******************************************************************************/
Yann Gautieree8f5422019-02-14 11:13:25 +010072uint8_t fdt_get_status(int node)
Yann Gautier9aea69e2018-07-24 17:13:36 +020073{
Yann Gautieree8f5422019-02-14 11:13:25 +010074 uint8_t status = DT_DISABLED;
Yann Gautier9aea69e2018-07-24 17:13:36 +020075 int len;
76 const char *cchar;
77
78 cchar = fdt_getprop(fdt, node, "status", &len);
Yann Gautier038bff22019-01-17 19:17:47 +010079 if ((cchar == NULL) ||
80 (strncmp(cchar, "okay", (size_t)len) == 0)) {
81 status |= DT_NON_SECURE;
Yann Gautier9aea69e2018-07-24 17:13:36 +020082 }
83
Yann Gautier9aea69e2018-07-24 17:13:36 +020084 cchar = fdt_getprop(fdt, node, "secure-status", &len);
85 if (cchar == NULL) {
Yann Gautier038bff22019-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 Gautier9aea69e2018-07-24 17:13:36 +020091 }
92
Yann Gautier038bff22019-01-17 19:17:47 +010093 return status;
Yann Gautier9aea69e2018-07-24 17:13:36 +020094}
95
Yann Gautier2260b842020-03-11 17:17:51 +010096#if ENABLE_ASSERTIONS
Yann Gautier9aea69e2018-07-24 17:13:36 +020097/*******************************************************************************
Lionel Debieveb0899eb2019-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 Gautier2260b842020-03-11 17:17:51 +0100105static int fdt_get_node_parent_address_cells(int node)
Lionel Debieveb0899eb2019-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 Gautier2260b842020-03-11 17:17:51 +0100125static int fdt_get_node_parent_size_cells(int node)
Lionel Debieveb0899eb2019-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 Gautier2260b842020-03-11 17:17:51 +0100136#endif
Lionel Debieveb0899eb2019-09-24 17:41:11 +0200137
138/*******************************************************************************
Yann Gautier69035a82018-07-05 16:48:16 +0200139 * This function gets the stdout pin configuration information from the DT.
140 * And then calls the sub-function to treat it and set GPIO registers.
Yann Gautier038bff22019-01-17 19:17:47 +0100141 * Returns 0 on success and a negative FDT error code on failure.
Yann Gautier69035a82018-07-05 16:48:16 +0200142 ******************************************************************************/
143int dt_set_stdout_pinctrl(void)
144{
145 int node;
146
Andre Przywaraeec91922020-04-09 11:27:21 +0100147 node = fdt_get_stdout_node_offset(fdt);
Yann Gautier69035a82018-07-05 16:48:16 +0200148 if (node < 0) {
149 return -FDT_ERR_NOTFOUND;
150 }
151
152 return dt_set_pinctrl_config(node);
153}
154
155/*******************************************************************************
156 * This function fills the generic information from a given node.
157 ******************************************************************************/
158void dt_fill_device_info(struct dt_node_info *info, int node)
159{
160 const fdt32_t *cuint;
161
Lionel Debieveb0899eb2019-09-24 17:41:11 +0200162 assert(fdt_get_node_parent_address_cells(node) == 1);
163
Yann Gautier69035a82018-07-05 16:48:16 +0200164 cuint = fdt_getprop(fdt, node, "reg", NULL);
165 if (cuint != NULL) {
166 info->base = fdt32_to_cpu(*cuint);
167 } else {
168 info->base = 0;
169 }
170
171 cuint = fdt_getprop(fdt, node, "clocks", NULL);
172 if (cuint != NULL) {
173 cuint++;
174 info->clock = (int)fdt32_to_cpu(*cuint);
175 } else {
176 info->clock = -1;
177 }
178
179 cuint = fdt_getprop(fdt, node, "resets", NULL);
180 if (cuint != NULL) {
181 cuint++;
182 info->reset = (int)fdt32_to_cpu(*cuint);
183 } else {
184 info->reset = -1;
185 }
186
Yann Gautier038bff22019-01-17 19:17:47 +0100187 info->status = fdt_get_status(node);
Yann Gautier69035a82018-07-05 16:48:16 +0200188}
189
190/*******************************************************************************
191 * This function retrieve the generic information from DT.
Yann Gautier038bff22019-01-17 19:17:47 +0100192 * Returns node on success and a negative FDT error code on failure.
Yann Gautier69035a82018-07-05 16:48:16 +0200193 ******************************************************************************/
194int dt_get_node(struct dt_node_info *info, int offset, const char *compat)
195{
196 int node;
197
198 node = fdt_node_offset_by_compatible(fdt, offset, compat);
199 if (node < 0) {
200 return -FDT_ERR_NOTFOUND;
201 }
202
203 dt_fill_device_info(info, node);
204
205 return node;
206}
207
208/*******************************************************************************
209 * This function gets the UART instance info of stdout from the DT.
Yann Gautier038bff22019-01-17 19:17:47 +0100210 * Returns node on success and a negative FDT error code on failure.
Yann Gautier69035a82018-07-05 16:48:16 +0200211 ******************************************************************************/
212int dt_get_stdout_uart_info(struct dt_node_info *info)
213{
214 int node;
215
Andre Przywaraeec91922020-04-09 11:27:21 +0100216 node = fdt_get_stdout_node_offset(fdt);
Yann Gautier69035a82018-07-05 16:48:16 +0200217 if (node < 0) {
218 return -FDT_ERR_NOTFOUND;
219 }
220
221 dt_fill_device_info(info, node);
222
223 return node;
224}
225
226/*******************************************************************************
Yann Gautiercaf575b2018-07-24 17:18:19 +0200227 * This function gets DDR size information from the DT.
Yann Gautier038bff22019-01-17 19:17:47 +0100228 * Returns value in bytes on success, and 0 on failure.
Yann Gautiercaf575b2018-07-24 17:18:19 +0200229 ******************************************************************************/
230uint32_t dt_get_ddr_size(void)
231{
232 int node;
233
234 node = fdt_node_offset_by_compatible(fdt, -1, DT_DDR_COMPAT);
235 if (node < 0) {
236 INFO("%s: Cannot read DDR node in DT\n", __func__);
Yann Gautier038bff22019-01-17 19:17:47 +0100237 return 0;
Yann Gautiercaf575b2018-07-24 17:18:19 +0200238 }
239
Andre Przywara2d5690c2020-03-26 11:50:33 +0000240 return fdt_read_uint32_default(fdt, node, "st,mem-size", 0);
Yann Gautiercaf575b2018-07-24 17:18:19 +0200241}
242
243/*******************************************************************************
Yann Gautier3d78a2e2019-02-14 11:01:20 +0100244 * This function gets DDRCTRL base address information from the DT.
245 * Returns value on success, and 0 on failure.
246 ******************************************************************************/
247uintptr_t dt_get_ddrctrl_base(void)
248{
249 int node;
250 uint32_t array[4];
251
252 node = fdt_node_offset_by_compatible(fdt, -1, DT_DDR_COMPAT);
253 if (node < 0) {
254 INFO("%s: Cannot read DDR node in DT\n", __func__);
255 return 0;
256 }
257
Lionel Debieveb0899eb2019-09-24 17:41:11 +0200258 assert((fdt_get_node_parent_address_cells(node) == 1) &&
259 (fdt_get_node_parent_size_cells(node) == 1));
260
Andre Przywaracc99f3f2020-03-26 12:51:21 +0000261 if (fdt_read_uint32_array(fdt, node, "reg", 4, array) < 0) {
Yann Gautier3d78a2e2019-02-14 11:01:20 +0100262 return 0;
263 }
264
265 return array[0];
266}
267
268/*******************************************************************************
269 * This function gets DDRPHYC base address information from the DT.
270 * Returns value on success, and 0 on failure.
271 ******************************************************************************/
272uintptr_t dt_get_ddrphyc_base(void)
273{
274 int node;
275 uint32_t array[4];
276
277 node = fdt_node_offset_by_compatible(fdt, -1, DT_DDR_COMPAT);
278 if (node < 0) {
279 INFO("%s: Cannot read DDR node in DT\n", __func__);
280 return 0;
281 }
282
Lionel Debieveb0899eb2019-09-24 17:41:11 +0200283 assert((fdt_get_node_parent_address_cells(node) == 1) &&
284 (fdt_get_node_parent_size_cells(node) == 1));
285
Andre Przywaracc99f3f2020-03-26 12:51:21 +0000286 if (fdt_read_uint32_array(fdt, node, "reg", 4, array) < 0) {
Yann Gautier3d78a2e2019-02-14 11:01:20 +0100287 return 0;
288 }
289
290 return array[2];
291}
292
293/*******************************************************************************
294 * This function gets PWR base address information from the DT.
295 * Returns value on success, and 0 on failure.
296 ******************************************************************************/
297uintptr_t dt_get_pwr_base(void)
298{
299 int node;
300 const fdt32_t *cuint;
301
302 node = fdt_node_offset_by_compatible(fdt, -1, DT_PWR_COMPAT);
303 if (node < 0) {
304 INFO("%s: Cannot read PWR node in DT\n", __func__);
305 return 0;
306 }
307
Lionel Debieveb0899eb2019-09-24 17:41:11 +0200308 assert(fdt_get_node_parent_address_cells(node) == 1);
309
Yann Gautier3d78a2e2019-02-14 11:01:20 +0100310 cuint = fdt_getprop(fdt, node, "reg", NULL);
311 if (cuint == NULL) {
312 return 0;
313 }
314
315 return fdt32_to_cpu(*cuint);
316}
317
318/*******************************************************************************
Yann Gautier3edc7c32019-05-20 19:17:08 +0200319 * This function gets PWR VDD regulator voltage information from the DT.
320 * Returns value in microvolts on success, and 0 on failure.
321 ******************************************************************************/
322uint32_t dt_get_pwr_vdd_voltage(void)
323{
324 int node, pwr_regulators_node;
325 const fdt32_t *cuint;
326
327 node = fdt_node_offset_by_compatible(fdt, -1, DT_PWR_COMPAT);
328 if (node < 0) {
329 INFO("%s: Cannot read PWR node in DT\n", __func__);
330 return 0;
331 }
332
333 pwr_regulators_node = fdt_subnode_offset(fdt, node, "pwr-regulators");
Yann Gautierdf473922020-03-18 14:35:27 +0100334 if (pwr_regulators_node < 0) {
Yann Gautier3edc7c32019-05-20 19:17:08 +0200335 INFO("%s: Cannot read pwr-regulators node in DT\n", __func__);
336 return 0;
337 }
338
339 cuint = fdt_getprop(fdt, pwr_regulators_node, "vdd-supply", NULL);
340 if (cuint == NULL) {
341 return 0;
342 }
343
344 node = fdt_node_offset_by_phandle(fdt, fdt32_to_cpu(*cuint));
345 if (node < 0) {
346 return 0;
347 }
348
349 cuint = fdt_getprop(fdt, node, "regulator-min-microvolt", NULL);
350 if (cuint == NULL) {
351 return 0;
352 }
353
354 return fdt32_to_cpu(*cuint);
355}
356
357/*******************************************************************************
358 * This function gets SYSCFG base address information from the DT.
359 * Returns value on success, and 0 on failure.
360 ******************************************************************************/
361uintptr_t dt_get_syscfg_base(void)
362{
363 int node;
364 const fdt32_t *cuint;
365
366 node = fdt_node_offset_by_compatible(fdt, -1, DT_SYSCFG_COMPAT);
367 if (node < 0) {
368 INFO("%s: Cannot read SYSCFG node in DT\n", __func__);
369 return 0;
370 }
371
Lionel Debieveb0899eb2019-09-24 17:41:11 +0200372 assert(fdt_get_node_parent_address_cells(node) == 1);
373
Yann Gautier3edc7c32019-05-20 19:17:08 +0200374 cuint = fdt_getprop(fdt, node, "reg", NULL);
375 if (cuint == NULL) {
376 return 0;
377 }
378
379 return fdt32_to_cpu(*cuint);
380}
381
382/*******************************************************************************
Yann Gautier69035a82018-07-05 16:48:16 +0200383 * This function retrieves board model from DT
384 * Returns string taken from model node, NULL otherwise
385 ******************************************************************************/
386const char *dt_get_board_model(void)
387{
388 int node = fdt_path_offset(fdt, "/");
389
390 if (node < 0) {
391 return NULL;
392 }
393
394 return (const char *)fdt_getprop(fdt, node, "model", NULL);
395}
Etienne Carriered81dadf2020-04-25 11:14:45 +0200396
397/*******************************************************************************
398 * This function gets the pin count for a GPIO bank based from the FDT.
399 * It also checks node consistency.
400 ******************************************************************************/
401int fdt_get_gpio_bank_pin_count(unsigned int bank)
402{
403 int pinctrl_node;
404 int node;
405 uint32_t bank_offset;
406
407 pinctrl_node = stm32_get_gpio_bank_pinctrl_node(fdt, bank);
408 if (pinctrl_node < 0) {
409 return -FDT_ERR_NOTFOUND;
410 }
411
412 bank_offset = stm32_get_gpio_bank_offset(bank);
413
414 fdt_for_each_subnode(node, fdt, pinctrl_node) {
415 const fdt32_t *cuint;
416
417 if (fdt_getprop(fdt, node, "gpio-controller", NULL) == NULL) {
418 continue;
419 }
420
421 cuint = fdt_getprop(fdt, node, "reg", NULL);
422 if (cuint == NULL) {
423 continue;
424 }
425
426 if (fdt32_to_cpu(*cuint) != bank_offset) {
427 continue;
428 }
429
430 if (fdt_get_status(node) == DT_DISABLED) {
431 return 0;
432 }
433
434 cuint = fdt_getprop(fdt, node, "ngpios", NULL);
435 if (cuint == NULL) {
436 return -FDT_ERR_NOTFOUND;
437 }
438
439 return (int)fdt32_to_cpu(*cuint);
440 }
441
442 return 0;
443}