1 /* 2 * Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved. 3 * 4 * SPDX-License-Identifier: BSD-3-Clause 5 */ 6 7 #include <assert.h> 8 #include <errno.h> 9 10 #include <libfdt.h> 11 12 #include <platform_def.h> 13 14 #include <common/debug.h> 15 #include <drivers/st/stm32_gpio.h> 16 #include <drivers/st/stm32mp1_ddr.h> 17 #include <drivers/st/stm32mp1_ram.h> 18 19 #include <stm32mp_dt.h> 20 21 static int fdt_checked; 22 23 static void *fdt = (void *)(uintptr_t)STM32MP_DTB_BASE; 24 25 /******************************************************************************* 26 * This function checks device tree file with its header. 27 * Returns 0 on success and a negative FDT error code on failure. 28 ******************************************************************************/ 29 int 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 ******************************************************************************/ 45 int 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). 56 * Returns true if present, else return false. 57 ******************************************************************************/ 58 bool 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 /******************************************************************************* 69 * This function return global node status (generic use of fdt library). 70 ******************************************************************************/ 71 uint8_t fdt_get_status(int node) 72 { 73 uint8_t status = DT_DISABLED; 74 int len; 75 const char *cchar; 76 77 cchar = fdt_getprop(fdt, node, "status", &len); 78 if ((cchar == NULL) || 79 (strncmp(cchar, "okay", (size_t)len) == 0)) { 80 status |= DT_NON_SECURE; 81 } 82 83 cchar = fdt_getprop(fdt, node, "secure-status", &len); 84 if (cchar == NULL) { 85 if (status == DT_NON_SECURE) { 86 status |= DT_SECURE; 87 } 88 } else if (strncmp(cchar, "okay", (size_t)len) == 0) { 89 status |= DT_SECURE; 90 } 91 92 return status; 93 } 94 95 /******************************************************************************* 96 * This function returns the address cells from the node parent. 97 * Returns: 98 * - #address-cells value if success. 99 * - invalid value if error. 100 * - a default value if undefined #address-cells property as per libfdt 101 * implementation. 102 ******************************************************************************/ 103 int fdt_get_node_parent_address_cells(int node) 104 { 105 int parent; 106 107 parent = fdt_parent_offset(fdt, node); 108 if (parent < 0) { 109 return -FDT_ERR_NOTFOUND; 110 } 111 112 return fdt_address_cells(fdt, parent); 113 } 114 115 /******************************************************************************* 116 * This function returns the size cells from the node parent. 117 * Returns: 118 * - #size-cells value if success. 119 * - invalid value if error. 120 * - a default value if undefined #size-cells property as per libfdt 121 * implementation. 122 ******************************************************************************/ 123 int fdt_get_node_parent_size_cells(int node) 124 { 125 int parent; 126 127 parent = fdt_parent_offset(fdt, node); 128 if (parent < 0) { 129 return -FDT_ERR_NOTFOUND; 130 } 131 132 return fdt_size_cells(fdt, parent); 133 } 134 135 /******************************************************************************* 136 * This function reads a value of a node property (generic use of fdt 137 * library). 138 * Returns value if success, and a default value if property not found. 139 * Default value is passed as parameter. 140 ******************************************************************************/ 141 uint32_t fdt_read_uint32_default(int node, const char *prop_name, 142 uint32_t dflt_value) 143 { 144 const fdt32_t *cuint; 145 int lenp; 146 147 cuint = fdt_getprop(fdt, node, prop_name, &lenp); 148 if (cuint == NULL) { 149 return dflt_value; 150 } 151 152 return fdt32_to_cpu(*cuint); 153 } 154 155 /******************************************************************************* 156 * This function reads a series of parameters in a node property 157 * (generic use of fdt library). 158 * It reads the values inside the device tree, from property name and node. 159 * The number of parameters is also indicated as entry parameter. 160 * Returns 0 on success and a negative FDT error code on failure. 161 * If success, values are stored at the third parameter address. 162 ******************************************************************************/ 163 int fdt_read_uint32_array(int node, const char *prop_name, uint32_t *array, 164 uint32_t count) 165 { 166 const fdt32_t *cuint; 167 int len; 168 uint32_t i; 169 170 cuint = fdt_getprop(fdt, node, prop_name, &len); 171 if (cuint == NULL) { 172 return -FDT_ERR_NOTFOUND; 173 } 174 175 if ((uint32_t)len != (count * sizeof(uint32_t))) { 176 return -FDT_ERR_BADLAYOUT; 177 } 178 179 for (i = 0; i < ((uint32_t)len / sizeof(uint32_t)); i++) { 180 *array = fdt32_to_cpu(*cuint); 181 array++; 182 cuint++; 183 } 184 185 return 0; 186 } 187 188 /******************************************************************************* 189 * This function fills reg node info (base & size) with an index found by 190 * checking the reg-names node. 191 * Returns 0 on success and a negative FDT error code on failure. 192 ******************************************************************************/ 193 int fdt_get_reg_props_by_name(int node, const char *name, uintptr_t *base, 194 size_t *size) 195 { 196 const fdt32_t *cuint; 197 int index, len; 198 199 assert((fdt_get_node_parent_address_cells(node) == 1) && 200 (fdt_get_node_parent_size_cells(node) == 1)); 201 202 index = fdt_stringlist_search(fdt, node, "reg-names", name); 203 if (index < 0) { 204 return index; 205 } 206 207 cuint = fdt_getprop(fdt, node, "reg", &len); 208 if (cuint == NULL) { 209 return -FDT_ERR_NOTFOUND; 210 } 211 212 if ((index * (int)sizeof(uint32_t)) > len) { 213 return -FDT_ERR_BADVALUE; 214 } 215 216 cuint += index << 1; 217 if (base != NULL) { 218 *base = fdt32_to_cpu(*cuint); 219 } 220 cuint++; 221 if (size != NULL) { 222 *size = fdt32_to_cpu(*cuint); 223 } 224 225 return 0; 226 } 227 228 /******************************************************************************* 229 * This function gets the stdout path node. 230 * It reads the value indicated inside the device tree. 231 * Returns node offset on success and a negative FDT error code on failure. 232 ******************************************************************************/ 233 static int dt_get_stdout_node_offset(void) 234 { 235 int node; 236 const char *cchar; 237 238 node = fdt_path_offset(fdt, "/secure-chosen"); 239 if (node < 0) { 240 node = fdt_path_offset(fdt, "/chosen"); 241 if (node < 0) { 242 return -FDT_ERR_NOTFOUND; 243 } 244 } 245 246 cchar = fdt_getprop(fdt, node, "stdout-path", NULL); 247 if (cchar == NULL) { 248 return -FDT_ERR_NOTFOUND; 249 } 250 251 node = -FDT_ERR_NOTFOUND; 252 if (strchr(cchar, (int)':') != NULL) { 253 const char *name; 254 char *str = (char *)cchar; 255 int len = 0; 256 257 while (strncmp(":", str, 1)) { 258 len++; 259 str++; 260 } 261 262 name = fdt_get_alias_namelen(fdt, cchar, len); 263 264 if (name != NULL) { 265 node = fdt_path_offset(fdt, name); 266 } 267 } else { 268 node = fdt_path_offset(fdt, cchar); 269 } 270 271 return node; 272 } 273 274 /******************************************************************************* 275 * This function gets the stdout pin configuration information from the DT. 276 * And then calls the sub-function to treat it and set GPIO registers. 277 * Returns 0 on success and a negative FDT error code on failure. 278 ******************************************************************************/ 279 int dt_set_stdout_pinctrl(void) 280 { 281 int node; 282 283 node = dt_get_stdout_node_offset(); 284 if (node < 0) { 285 return -FDT_ERR_NOTFOUND; 286 } 287 288 return dt_set_pinctrl_config(node); 289 } 290 291 /******************************************************************************* 292 * This function fills the generic information from a given node. 293 ******************************************************************************/ 294 void dt_fill_device_info(struct dt_node_info *info, int node) 295 { 296 const fdt32_t *cuint; 297 298 assert(fdt_get_node_parent_address_cells(node) == 1); 299 300 cuint = fdt_getprop(fdt, node, "reg", NULL); 301 if (cuint != NULL) { 302 info->base = fdt32_to_cpu(*cuint); 303 } else { 304 info->base = 0; 305 } 306 307 cuint = fdt_getprop(fdt, node, "clocks", NULL); 308 if (cuint != NULL) { 309 cuint++; 310 info->clock = (int)fdt32_to_cpu(*cuint); 311 } else { 312 info->clock = -1; 313 } 314 315 cuint = fdt_getprop(fdt, node, "resets", NULL); 316 if (cuint != NULL) { 317 cuint++; 318 info->reset = (int)fdt32_to_cpu(*cuint); 319 } else { 320 info->reset = -1; 321 } 322 323 info->status = fdt_get_status(node); 324 } 325 326 /******************************************************************************* 327 * This function retrieve the generic information from DT. 328 * Returns node on success and a negative FDT error code on failure. 329 ******************************************************************************/ 330 int dt_get_node(struct dt_node_info *info, int offset, const char *compat) 331 { 332 int node; 333 334 node = fdt_node_offset_by_compatible(fdt, offset, compat); 335 if (node < 0) { 336 return -FDT_ERR_NOTFOUND; 337 } 338 339 dt_fill_device_info(info, node); 340 341 return node; 342 } 343 344 /******************************************************************************* 345 * This function gets the UART instance info of stdout from the DT. 346 * Returns node on success and a negative FDT error code on failure. 347 ******************************************************************************/ 348 int dt_get_stdout_uart_info(struct dt_node_info *info) 349 { 350 int node; 351 352 node = dt_get_stdout_node_offset(); 353 if (node < 0) { 354 return -FDT_ERR_NOTFOUND; 355 } 356 357 dt_fill_device_info(info, node); 358 359 return node; 360 } 361 362 /******************************************************************************* 363 * This function gets DDR size information from the DT. 364 * Returns value in bytes on success, and 0 on failure. 365 ******************************************************************************/ 366 uint32_t dt_get_ddr_size(void) 367 { 368 int node; 369 370 node = fdt_node_offset_by_compatible(fdt, -1, DT_DDR_COMPAT); 371 if (node < 0) { 372 INFO("%s: Cannot read DDR node in DT\n", __func__); 373 return 0; 374 } 375 376 return fdt_read_uint32_default(node, "st,mem-size", 0); 377 } 378 379 /******************************************************************************* 380 * This function gets DDRCTRL base address information from the DT. 381 * Returns value on success, and 0 on failure. 382 ******************************************************************************/ 383 uintptr_t dt_get_ddrctrl_base(void) 384 { 385 int node; 386 uint32_t array[4]; 387 388 node = fdt_node_offset_by_compatible(fdt, -1, DT_DDR_COMPAT); 389 if (node < 0) { 390 INFO("%s: Cannot read DDR node in DT\n", __func__); 391 return 0; 392 } 393 394 assert((fdt_get_node_parent_address_cells(node) == 1) && 395 (fdt_get_node_parent_size_cells(node) == 1)); 396 397 if (fdt_read_uint32_array(node, "reg", array, 4) < 0) { 398 return 0; 399 } 400 401 return array[0]; 402 } 403 404 /******************************************************************************* 405 * This function gets DDRPHYC base address information from the DT. 406 * Returns value on success, and 0 on failure. 407 ******************************************************************************/ 408 uintptr_t dt_get_ddrphyc_base(void) 409 { 410 int node; 411 uint32_t array[4]; 412 413 node = fdt_node_offset_by_compatible(fdt, -1, DT_DDR_COMPAT); 414 if (node < 0) { 415 INFO("%s: Cannot read DDR node in DT\n", __func__); 416 return 0; 417 } 418 419 assert((fdt_get_node_parent_address_cells(node) == 1) && 420 (fdt_get_node_parent_size_cells(node) == 1)); 421 422 if (fdt_read_uint32_array(node, "reg", array, 4) < 0) { 423 return 0; 424 } 425 426 return array[2]; 427 } 428 429 /******************************************************************************* 430 * This function gets PWR base address information from the DT. 431 * Returns value on success, and 0 on failure. 432 ******************************************************************************/ 433 uintptr_t dt_get_pwr_base(void) 434 { 435 int node; 436 const fdt32_t *cuint; 437 438 node = fdt_node_offset_by_compatible(fdt, -1, DT_PWR_COMPAT); 439 if (node < 0) { 440 INFO("%s: Cannot read PWR node in DT\n", __func__); 441 return 0; 442 } 443 444 assert(fdt_get_node_parent_address_cells(node) == 1); 445 446 cuint = fdt_getprop(fdt, node, "reg", NULL); 447 if (cuint == NULL) { 448 return 0; 449 } 450 451 return fdt32_to_cpu(*cuint); 452 } 453 454 /******************************************************************************* 455 * This function gets PWR VDD regulator voltage information from the DT. 456 * Returns value in microvolts on success, and 0 on failure. 457 ******************************************************************************/ 458 uint32_t dt_get_pwr_vdd_voltage(void) 459 { 460 int node, pwr_regulators_node; 461 const fdt32_t *cuint; 462 463 node = fdt_node_offset_by_compatible(fdt, -1, DT_PWR_COMPAT); 464 if (node < 0) { 465 INFO("%s: Cannot read PWR node in DT\n", __func__); 466 return 0; 467 } 468 469 pwr_regulators_node = fdt_subnode_offset(fdt, node, "pwr-regulators"); 470 if (node < 0) { 471 INFO("%s: Cannot read pwr-regulators node in DT\n", __func__); 472 return 0; 473 } 474 475 cuint = fdt_getprop(fdt, pwr_regulators_node, "vdd-supply", NULL); 476 if (cuint == NULL) { 477 return 0; 478 } 479 480 node = fdt_node_offset_by_phandle(fdt, fdt32_to_cpu(*cuint)); 481 if (node < 0) { 482 return 0; 483 } 484 485 cuint = fdt_getprop(fdt, node, "regulator-min-microvolt", NULL); 486 if (cuint == NULL) { 487 return 0; 488 } 489 490 return fdt32_to_cpu(*cuint); 491 } 492 493 /******************************************************************************* 494 * This function gets SYSCFG base address information from the DT. 495 * Returns value on success, and 0 on failure. 496 ******************************************************************************/ 497 uintptr_t dt_get_syscfg_base(void) 498 { 499 int node; 500 const fdt32_t *cuint; 501 502 node = fdt_node_offset_by_compatible(fdt, -1, DT_SYSCFG_COMPAT); 503 if (node < 0) { 504 INFO("%s: Cannot read SYSCFG node in DT\n", __func__); 505 return 0; 506 } 507 508 assert(fdt_get_node_parent_address_cells(node) == 1); 509 510 cuint = fdt_getprop(fdt, node, "reg", NULL); 511 if (cuint == NULL) { 512 return 0; 513 } 514 515 return fdt32_to_cpu(*cuint); 516 } 517 518 /******************************************************************************* 519 * This function retrieves board model from DT 520 * Returns string taken from model node, NULL otherwise 521 ******************************************************************************/ 522 const char *dt_get_board_model(void) 523 { 524 int node = fdt_path_offset(fdt, "/"); 525 526 if (node < 0) { 527 return NULL; 528 } 529 530 return (const char *)fdt_getprop(fdt, node, "model", NULL); 531 } 532