blob: 17da4904ac8f80c3b9905ee742fb0c3020911376 [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/*******************************************************************************
96 * This function reads a value of a node property (generic use of fdt
97 * library).
98 * Returns value if success, and a default value if property not found.
99 * Default value is passed as parameter.
100 ******************************************************************************/
101uint32_t fdt_read_uint32_default(int node, const char *prop_name,
102 uint32_t dflt_value)
103{
104 const fdt32_t *cuint;
105 int lenp;
106
107 cuint = fdt_getprop(fdt, node, prop_name, &lenp);
108 if (cuint == NULL) {
109 return dflt_value;
110 }
111
112 return fdt32_to_cpu(*cuint);
113}
114
115/*******************************************************************************
116 * This function reads a series of parameters in a node property
117 * (generic use of fdt library).
118 * It reads the values inside the device tree, from property name and node.
119 * The number of parameters is also indicated as entry parameter.
Yann Gautier038bff22019-01-17 19:17:47 +0100120 * Returns 0 on success and a negative FDT error code on failure.
Yann Gautier9aea69e2018-07-24 17:13:36 +0200121 * If success, values are stored at the third parameter address.
122 ******************************************************************************/
123int fdt_read_uint32_array(int node, const char *prop_name, uint32_t *array,
124 uint32_t count)
125{
126 const fdt32_t *cuint;
127 int len;
128 uint32_t i;
129
130 cuint = fdt_getprop(fdt, node, prop_name, &len);
131 if (cuint == NULL) {
132 return -FDT_ERR_NOTFOUND;
133 }
134
135 if ((uint32_t)len != (count * sizeof(uint32_t))) {
136 return -FDT_ERR_BADLAYOUT;
137 }
138
139 for (i = 0; i < ((uint32_t)len / sizeof(uint32_t)); i++) {
140 *array = fdt32_to_cpu(*cuint);
141 array++;
142 cuint++;
143 }
144
145 return 0;
146}
Yann Gautierd0ca7f42018-07-13 21:33:09 +0200147
148/*******************************************************************************
Yann Gautier1bef97a2019-06-04 17:20:44 +0200149 * This function gets the stdout path node.
150 * It reads the value indicated inside the device tree.
151 * Returns node offset on success and a negative FDT error code on failure.
152 ******************************************************************************/
153static int dt_get_stdout_node_offset(void)
154{
155 int node;
156 const char *cchar;
157
158 node = fdt_path_offset(fdt, "/secure-chosen");
159 if (node < 0) {
160 node = fdt_path_offset(fdt, "/chosen");
161 if (node < 0) {
162 return -FDT_ERR_NOTFOUND;
163 }
164 }
165
166 cchar = fdt_getprop(fdt, node, "stdout-path", NULL);
167 if (cchar == NULL) {
168 return -FDT_ERR_NOTFOUND;
169 }
170
171 node = -FDT_ERR_NOTFOUND;
172 if (strchr(cchar, (int)':') != NULL) {
173 const char *name;
174 char *str = (char *)cchar;
175 int len = 0;
176
177 while (strncmp(":", str, 1)) {
178 len++;
179 str++;
180 }
181
182 name = fdt_get_alias_namelen(fdt, cchar, len);
183
184 if (name != NULL) {
185 node = fdt_path_offset(fdt, name);
186 }
187 } else {
188 node = fdt_path_offset(fdt, cchar);
189 }
190
191 return node;
192}
193
194/*******************************************************************************
Yann Gautier69035a82018-07-05 16:48:16 +0200195 * This function gets the stdout pin configuration information from the DT.
196 * And then calls the sub-function to treat it and set GPIO registers.
Yann Gautier038bff22019-01-17 19:17:47 +0100197 * Returns 0 on success and a negative FDT error code on failure.
Yann Gautier69035a82018-07-05 16:48:16 +0200198 ******************************************************************************/
199int dt_set_stdout_pinctrl(void)
200{
201 int node;
202
203 node = dt_get_stdout_node_offset();
204 if (node < 0) {
205 return -FDT_ERR_NOTFOUND;
206 }
207
208 return dt_set_pinctrl_config(node);
209}
210
211/*******************************************************************************
212 * This function fills the generic information from a given node.
213 ******************************************************************************/
214void dt_fill_device_info(struct dt_node_info *info, int node)
215{
216 const fdt32_t *cuint;
217
218 cuint = fdt_getprop(fdt, node, "reg", NULL);
219 if (cuint != NULL) {
220 info->base = fdt32_to_cpu(*cuint);
221 } else {
222 info->base = 0;
223 }
224
225 cuint = fdt_getprop(fdt, node, "clocks", NULL);
226 if (cuint != NULL) {
227 cuint++;
228 info->clock = (int)fdt32_to_cpu(*cuint);
229 } else {
230 info->clock = -1;
231 }
232
233 cuint = fdt_getprop(fdt, node, "resets", NULL);
234 if (cuint != NULL) {
235 cuint++;
236 info->reset = (int)fdt32_to_cpu(*cuint);
237 } else {
238 info->reset = -1;
239 }
240
Yann Gautier038bff22019-01-17 19:17:47 +0100241 info->status = fdt_get_status(node);
Yann Gautier69035a82018-07-05 16:48:16 +0200242}
243
244/*******************************************************************************
245 * This function retrieve the generic information from DT.
Yann Gautier038bff22019-01-17 19:17:47 +0100246 * Returns node on success and a negative FDT error code on failure.
Yann Gautier69035a82018-07-05 16:48:16 +0200247 ******************************************************************************/
248int dt_get_node(struct dt_node_info *info, int offset, const char *compat)
249{
250 int node;
251
252 node = fdt_node_offset_by_compatible(fdt, offset, compat);
253 if (node < 0) {
254 return -FDT_ERR_NOTFOUND;
255 }
256
257 dt_fill_device_info(info, node);
258
259 return node;
260}
261
262/*******************************************************************************
263 * This function gets the UART instance info of stdout from the DT.
Yann Gautier038bff22019-01-17 19:17:47 +0100264 * Returns node on success and a negative FDT error code on failure.
Yann Gautier69035a82018-07-05 16:48:16 +0200265 ******************************************************************************/
266int dt_get_stdout_uart_info(struct dt_node_info *info)
267{
268 int node;
269
270 node = dt_get_stdout_node_offset();
271 if (node < 0) {
272 return -FDT_ERR_NOTFOUND;
273 }
274
275 dt_fill_device_info(info, node);
276
277 return node;
278}
279
280/*******************************************************************************
Yann Gautiercaf575b2018-07-24 17:18:19 +0200281 * This function gets DDR size information from the DT.
Yann Gautier038bff22019-01-17 19:17:47 +0100282 * Returns value in bytes on success, and 0 on failure.
Yann Gautiercaf575b2018-07-24 17:18:19 +0200283 ******************************************************************************/
284uint32_t dt_get_ddr_size(void)
285{
286 int node;
287
288 node = fdt_node_offset_by_compatible(fdt, -1, DT_DDR_COMPAT);
289 if (node < 0) {
290 INFO("%s: Cannot read DDR node in DT\n", __func__);
Yann Gautier038bff22019-01-17 19:17:47 +0100291 return 0;
Yann Gautiercaf575b2018-07-24 17:18:19 +0200292 }
293
Yann Gautier038bff22019-01-17 19:17:47 +0100294 return fdt_read_uint32_default(node, "st,mem-size", 0);
Yann Gautiercaf575b2018-07-24 17:18:19 +0200295}
296
297/*******************************************************************************
Yann Gautier3d78a2e2019-02-14 11:01:20 +0100298 * This function gets DDRCTRL base address information from the DT.
299 * Returns value on success, and 0 on failure.
300 ******************************************************************************/
301uintptr_t dt_get_ddrctrl_base(void)
302{
303 int node;
304 uint32_t array[4];
305
306 node = fdt_node_offset_by_compatible(fdt, -1, DT_DDR_COMPAT);
307 if (node < 0) {
308 INFO("%s: Cannot read DDR node in DT\n", __func__);
309 return 0;
310 }
311
312 if (fdt_read_uint32_array(node, "reg", array, 4) < 0) {
313 return 0;
314 }
315
316 return array[0];
317}
318
319/*******************************************************************************
320 * This function gets DDRPHYC base address information from the DT.
321 * Returns value on success, and 0 on failure.
322 ******************************************************************************/
323uintptr_t dt_get_ddrphyc_base(void)
324{
325 int node;
326 uint32_t array[4];
327
328 node = fdt_node_offset_by_compatible(fdt, -1, DT_DDR_COMPAT);
329 if (node < 0) {
330 INFO("%s: Cannot read DDR node in DT\n", __func__);
331 return 0;
332 }
333
334 if (fdt_read_uint32_array(node, "reg", array, 4) < 0) {
335 return 0;
336 }
337
338 return array[2];
339}
340
341/*******************************************************************************
342 * This function gets PWR base address information from the DT.
343 * Returns value on success, and 0 on failure.
344 ******************************************************************************/
345uintptr_t dt_get_pwr_base(void)
346{
347 int node;
348 const fdt32_t *cuint;
349
350 node = fdt_node_offset_by_compatible(fdt, -1, DT_PWR_COMPAT);
351 if (node < 0) {
352 INFO("%s: Cannot read PWR node in DT\n", __func__);
353 return 0;
354 }
355
356 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 Gautier3edc7c32019-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");
380 if (node < 0) {
381 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
418 cuint = fdt_getprop(fdt, node, "reg", NULL);
419 if (cuint == NULL) {
420 return 0;
421 }
422
423 return fdt32_to_cpu(*cuint);
424}
425
426/*******************************************************************************
Yann Gautier69035a82018-07-05 16:48:16 +0200427 * This function retrieves board model from DT
428 * Returns string taken from model node, NULL otherwise
429 ******************************************************************************/
430const char *dt_get_board_model(void)
431{
432 int node = fdt_path_offset(fdt, "/");
433
434 if (node < 0) {
435 return NULL;
436 }
437
438 return (const char *)fdt_getprop(fdt, node, "model", NULL);
439}