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