blob: 8e828631bfa89f8fe5cb14b024501b8c342429a5 [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 Gautier69035a82018-07-05 16:48:16 +0200149 * This function gets the stdout pin configuration information from the DT.
150 * And then calls the sub-function to treat it and set GPIO registers.
Yann Gautier038bff22019-01-17 19:17:47 +0100151 * Returns 0 on success and a negative FDT error code on failure.
Yann Gautier69035a82018-07-05 16:48:16 +0200152 ******************************************************************************/
153int dt_set_stdout_pinctrl(void)
154{
155 int node;
156
157 node = dt_get_stdout_node_offset();
158 if (node < 0) {
159 return -FDT_ERR_NOTFOUND;
160 }
161
162 return dt_set_pinctrl_config(node);
163}
164
165/*******************************************************************************
166 * This function fills the generic information from a given node.
167 ******************************************************************************/
168void dt_fill_device_info(struct dt_node_info *info, int node)
169{
170 const fdt32_t *cuint;
171
172 cuint = fdt_getprop(fdt, node, "reg", NULL);
173 if (cuint != NULL) {
174 info->base = fdt32_to_cpu(*cuint);
175 } else {
176 info->base = 0;
177 }
178
179 cuint = fdt_getprop(fdt, node, "clocks", NULL);
180 if (cuint != NULL) {
181 cuint++;
182 info->clock = (int)fdt32_to_cpu(*cuint);
183 } else {
184 info->clock = -1;
185 }
186
187 cuint = fdt_getprop(fdt, node, "resets", NULL);
188 if (cuint != NULL) {
189 cuint++;
190 info->reset = (int)fdt32_to_cpu(*cuint);
191 } else {
192 info->reset = -1;
193 }
194
Yann Gautier038bff22019-01-17 19:17:47 +0100195 info->status = fdt_get_status(node);
Yann Gautier69035a82018-07-05 16:48:16 +0200196}
197
198/*******************************************************************************
199 * This function retrieve the generic information from DT.
Yann Gautier038bff22019-01-17 19:17:47 +0100200 * Returns node on success and a negative FDT error code on failure.
Yann Gautier69035a82018-07-05 16:48:16 +0200201 ******************************************************************************/
202int dt_get_node(struct dt_node_info *info, int offset, const char *compat)
203{
204 int node;
205
206 node = fdt_node_offset_by_compatible(fdt, offset, compat);
207 if (node < 0) {
208 return -FDT_ERR_NOTFOUND;
209 }
210
211 dt_fill_device_info(info, node);
212
213 return node;
214}
215
216/*******************************************************************************
217 * This function gets the UART instance info of stdout from the DT.
Yann Gautier038bff22019-01-17 19:17:47 +0100218 * Returns node on success and a negative FDT error code on failure.
Yann Gautier69035a82018-07-05 16:48:16 +0200219 ******************************************************************************/
220int dt_get_stdout_uart_info(struct dt_node_info *info)
221{
222 int node;
223
224 node = dt_get_stdout_node_offset();
225 if (node < 0) {
226 return -FDT_ERR_NOTFOUND;
227 }
228
229 dt_fill_device_info(info, node);
230
231 return node;
232}
233
234/*******************************************************************************
235 * This function gets the stdout path node.
236 * It reads the value indicated inside the device tree.
237 * Returns node if success, and a negative value else.
238 ******************************************************************************/
239int dt_get_stdout_node_offset(void)
240{
241 int node;
242 const char *cchar;
243
244 node = fdt_path_offset(fdt, "/chosen");
245 if (node < 0) {
246 return -FDT_ERR_NOTFOUND;
247 }
248
249 cchar = fdt_getprop(fdt, node, "stdout-path", NULL);
250 if (cchar == NULL) {
251 return -FDT_ERR_NOTFOUND;
252 }
253
254 node = -FDT_ERR_NOTFOUND;
255 if (strchr(cchar, (int)':') != NULL) {
256 const char *name;
257 char *str = (char *)cchar;
258 int len = 0;
259
260 while (strncmp(":", str, 1)) {
261 len++;
262 str++;
263 }
264
265 name = fdt_get_alias_namelen(fdt, cchar, len);
266
267 if (name != NULL) {
268 node = fdt_path_offset(fdt, name);
269 }
270 } else {
271 node = fdt_path_offset(fdt, cchar);
272 }
273
274 return node;
275}
276
277/*******************************************************************************
Yann Gautiercaf575b2018-07-24 17:18:19 +0200278 * This function gets DDR size information from the DT.
Yann Gautier038bff22019-01-17 19:17:47 +0100279 * Returns value in bytes on success, and 0 on failure.
Yann Gautiercaf575b2018-07-24 17:18:19 +0200280 ******************************************************************************/
281uint32_t dt_get_ddr_size(void)
282{
283 int node;
284
285 node = fdt_node_offset_by_compatible(fdt, -1, DT_DDR_COMPAT);
286 if (node < 0) {
287 INFO("%s: Cannot read DDR node in DT\n", __func__);
Yann Gautier038bff22019-01-17 19:17:47 +0100288 return 0;
Yann Gautiercaf575b2018-07-24 17:18:19 +0200289 }
290
Yann Gautier038bff22019-01-17 19:17:47 +0100291 return fdt_read_uint32_default(node, "st,mem-size", 0);
Yann Gautiercaf575b2018-07-24 17:18:19 +0200292}
293
294/*******************************************************************************
Yann Gautier3d78a2e2019-02-14 11:01:20 +0100295 * This function gets DDRCTRL base address information from the DT.
296 * Returns value on success, and 0 on failure.
297 ******************************************************************************/
298uintptr_t dt_get_ddrctrl_base(void)
299{
300 int node;
301 uint32_t array[4];
302
303 node = fdt_node_offset_by_compatible(fdt, -1, DT_DDR_COMPAT);
304 if (node < 0) {
305 INFO("%s: Cannot read DDR node in DT\n", __func__);
306 return 0;
307 }
308
309 if (fdt_read_uint32_array(node, "reg", array, 4) < 0) {
310 return 0;
311 }
312
313 return array[0];
314}
315
316/*******************************************************************************
317 * This function gets DDRPHYC base address information from the DT.
318 * Returns value on success, and 0 on failure.
319 ******************************************************************************/
320uintptr_t dt_get_ddrphyc_base(void)
321{
322 int node;
323 uint32_t array[4];
324
325 node = fdt_node_offset_by_compatible(fdt, -1, DT_DDR_COMPAT);
326 if (node < 0) {
327 INFO("%s: Cannot read DDR node in DT\n", __func__);
328 return 0;
329 }
330
331 if (fdt_read_uint32_array(node, "reg", array, 4) < 0) {
332 return 0;
333 }
334
335 return array[2];
336}
337
338/*******************************************************************************
339 * This function gets PWR base address information from the DT.
340 * Returns value on success, and 0 on failure.
341 ******************************************************************************/
342uintptr_t dt_get_pwr_base(void)
343{
344 int node;
345 const fdt32_t *cuint;
346
347 node = fdt_node_offset_by_compatible(fdt, -1, DT_PWR_COMPAT);
348 if (node < 0) {
349 INFO("%s: Cannot read PWR node in DT\n", __func__);
350 return 0;
351 }
352
353 cuint = fdt_getprop(fdt, node, "reg", NULL);
354 if (cuint == NULL) {
355 return 0;
356 }
357
358 return fdt32_to_cpu(*cuint);
359}
360
361/*******************************************************************************
Yann Gautier3edc7c32019-05-20 19:17:08 +0200362 * This function gets PWR VDD regulator voltage information from the DT.
363 * Returns value in microvolts on success, and 0 on failure.
364 ******************************************************************************/
365uint32_t dt_get_pwr_vdd_voltage(void)
366{
367 int node, pwr_regulators_node;
368 const fdt32_t *cuint;
369
370 node = fdt_node_offset_by_compatible(fdt, -1, DT_PWR_COMPAT);
371 if (node < 0) {
372 INFO("%s: Cannot read PWR node in DT\n", __func__);
373 return 0;
374 }
375
376 pwr_regulators_node = fdt_subnode_offset(fdt, node, "pwr-regulators");
377 if (node < 0) {
378 INFO("%s: Cannot read pwr-regulators node in DT\n", __func__);
379 return 0;
380 }
381
382 cuint = fdt_getprop(fdt, pwr_regulators_node, "vdd-supply", NULL);
383 if (cuint == NULL) {
384 return 0;
385 }
386
387 node = fdt_node_offset_by_phandle(fdt, fdt32_to_cpu(*cuint));
388 if (node < 0) {
389 return 0;
390 }
391
392 cuint = fdt_getprop(fdt, node, "regulator-min-microvolt", NULL);
393 if (cuint == NULL) {
394 return 0;
395 }
396
397 return fdt32_to_cpu(*cuint);
398}
399
400/*******************************************************************************
401 * This function gets SYSCFG base address information from the DT.
402 * Returns value on success, and 0 on failure.
403 ******************************************************************************/
404uintptr_t dt_get_syscfg_base(void)
405{
406 int node;
407 const fdt32_t *cuint;
408
409 node = fdt_node_offset_by_compatible(fdt, -1, DT_SYSCFG_COMPAT);
410 if (node < 0) {
411 INFO("%s: Cannot read SYSCFG node in DT\n", __func__);
412 return 0;
413 }
414
415 cuint = fdt_getprop(fdt, node, "reg", NULL);
416 if (cuint == NULL) {
417 return 0;
418 }
419
420 return fdt32_to_cpu(*cuint);
421}
422
423/*******************************************************************************
Yann Gautier69035a82018-07-05 16:48:16 +0200424 * This function retrieves board model from DT
425 * Returns string taken from model node, NULL otherwise
426 ******************************************************************************/
427const char *dt_get_board_model(void)
428{
429 int node = fdt_path_offset(fdt, "/");
430
431 if (node < 0) {
432 return NULL;
433 }
434
435 return (const char *)fdt_getprop(fdt, node, "model", NULL);
436}