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 <common/fdt_wrappers.h> 16 #include <drivers/st/stm32_gpio.h> 17 #include <drivers/st/stm32mp1_ddr.h> 18 #include <drivers/st/stm32mp1_ram.h> 19 20 #include <stm32mp_dt.h> 21 22 static int fdt_checked; 23 24 static void *fdt = (void *)(uintptr_t)STM32MP_DTB_BASE; 25 26 /******************************************************************************* 27 * This function checks device tree file with its header. 28 * Returns 0 on success and a negative FDT error code on failure. 29 ******************************************************************************/ 30 int 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 ******************************************************************************/ 46 int 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). 57 * Returns true if present, else return false. 58 ******************************************************************************/ 59 bool 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 /******************************************************************************* 70 * This function return global node status (generic use of fdt library). 71 ******************************************************************************/ 72 uint8_t fdt_get_status(int node) 73 { 74 uint8_t status = DT_DISABLED; 75 int len; 76 const char *cchar; 77 78 cchar = fdt_getprop(fdt, node, "status", &len); 79 if ((cchar == NULL) || 80 (strncmp(cchar, "okay", (size_t)len) == 0)) { 81 status |= DT_NON_SECURE; 82 } 83 84 cchar = fdt_getprop(fdt, node, "secure-status", &len); 85 if (cchar == NULL) { 86 if (status == DT_NON_SECURE) { 87 status |= DT_SECURE; 88 } 89 } else if (strncmp(cchar, "okay", (size_t)len) == 0) { 90 status |= DT_SECURE; 91 } 92 93 return status; 94 } 95 96 #if ENABLE_ASSERTIONS 97 /******************************************************************************* 98 * 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 ******************************************************************************/ 105 static int fdt_get_node_parent_address_cells(int node) 106 { 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 ******************************************************************************/ 125 static int fdt_get_node_parent_size_cells(int node) 126 { 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 } 136 #endif 137 138 /******************************************************************************* 139 * This function fills reg node info (base & size) with an index found by 140 * checking the reg-names node. 141 * Returns 0 on success and a negative FDT error code on failure. 142 ******************************************************************************/ 143 int fdt_get_reg_props_by_name(int node, const char *name, uintptr_t *base, 144 size_t *size) 145 { 146 const fdt32_t *cuint; 147 int index, len; 148 149 assert((fdt_get_node_parent_address_cells(node) == 1) && 150 (fdt_get_node_parent_size_cells(node) == 1)); 151 152 index = fdt_stringlist_search(fdt, node, "reg-names", name); 153 if (index < 0) { 154 return index; 155 } 156 157 cuint = fdt_getprop(fdt, node, "reg", &len); 158 if (cuint == NULL) { 159 return -FDT_ERR_NOTFOUND; 160 } 161 162 if ((index * (int)sizeof(uint32_t)) > len) { 163 return -FDT_ERR_BADVALUE; 164 } 165 166 cuint += index << 1; 167 if (base != NULL) { 168 *base = fdt32_to_cpu(*cuint); 169 } 170 cuint++; 171 if (size != NULL) { 172 *size = fdt32_to_cpu(*cuint); 173 } 174 175 return 0; 176 } 177 178 /******************************************************************************* 179 * This function gets the stdout path node. 180 * It reads the value indicated inside the device tree. 181 * Returns node offset on success and a negative FDT error code on failure. 182 ******************************************************************************/ 183 static int dt_get_stdout_node_offset(void) 184 { 185 int node; 186 const char *cchar; 187 188 node = fdt_path_offset(fdt, "/secure-chosen"); 189 if (node < 0) { 190 node = fdt_path_offset(fdt, "/chosen"); 191 if (node < 0) { 192 return -FDT_ERR_NOTFOUND; 193 } 194 } 195 196 cchar = fdt_getprop(fdt, node, "stdout-path", NULL); 197 if (cchar == NULL) { 198 return -FDT_ERR_NOTFOUND; 199 } 200 201 node = -FDT_ERR_NOTFOUND; 202 if (strchr(cchar, (int)':') != NULL) { 203 const char *name; 204 char *str = (char *)cchar; 205 int len = 0; 206 207 while (strncmp(":", str, 1)) { 208 len++; 209 str++; 210 } 211 212 name = fdt_get_alias_namelen(fdt, cchar, len); 213 214 if (name != NULL) { 215 node = fdt_path_offset(fdt, name); 216 } 217 } else { 218 node = fdt_path_offset(fdt, cchar); 219 } 220 221 return node; 222 } 223 224 /******************************************************************************* 225 * This function gets the stdout pin configuration information from the DT. 226 * And then calls the sub-function to treat it and set GPIO registers. 227 * Returns 0 on success and a negative FDT error code on failure. 228 ******************************************************************************/ 229 int dt_set_stdout_pinctrl(void) 230 { 231 int node; 232 233 node = dt_get_stdout_node_offset(); 234 if (node < 0) { 235 return -FDT_ERR_NOTFOUND; 236 } 237 238 return dt_set_pinctrl_config(node); 239 } 240 241 /******************************************************************************* 242 * This function fills the generic information from a given node. 243 ******************************************************************************/ 244 void dt_fill_device_info(struct dt_node_info *info, int node) 245 { 246 const fdt32_t *cuint; 247 248 assert(fdt_get_node_parent_address_cells(node) == 1); 249 250 cuint = fdt_getprop(fdt, node, "reg", NULL); 251 if (cuint != NULL) { 252 info->base = fdt32_to_cpu(*cuint); 253 } else { 254 info->base = 0; 255 } 256 257 cuint = fdt_getprop(fdt, node, "clocks", NULL); 258 if (cuint != NULL) { 259 cuint++; 260 info->clock = (int)fdt32_to_cpu(*cuint); 261 } else { 262 info->clock = -1; 263 } 264 265 cuint = fdt_getprop(fdt, node, "resets", NULL); 266 if (cuint != NULL) { 267 cuint++; 268 info->reset = (int)fdt32_to_cpu(*cuint); 269 } else { 270 info->reset = -1; 271 } 272 273 info->status = fdt_get_status(node); 274 } 275 276 /******************************************************************************* 277 * This function retrieve the generic information from DT. 278 * Returns node on success and a negative FDT error code on failure. 279 ******************************************************************************/ 280 int dt_get_node(struct dt_node_info *info, int offset, const char *compat) 281 { 282 int node; 283 284 node = fdt_node_offset_by_compatible(fdt, offset, compat); 285 if (node < 0) { 286 return -FDT_ERR_NOTFOUND; 287 } 288 289 dt_fill_device_info(info, node); 290 291 return node; 292 } 293 294 /******************************************************************************* 295 * This function gets the UART instance info of stdout from the DT. 296 * Returns node on success and a negative FDT error code on failure. 297 ******************************************************************************/ 298 int dt_get_stdout_uart_info(struct dt_node_info *info) 299 { 300 int node; 301 302 node = dt_get_stdout_node_offset(); 303 if (node < 0) { 304 return -FDT_ERR_NOTFOUND; 305 } 306 307 dt_fill_device_info(info, node); 308 309 return node; 310 } 311 312 /******************************************************************************* 313 * This function gets DDR size information from the DT. 314 * Returns value in bytes on success, and 0 on failure. 315 ******************************************************************************/ 316 uint32_t dt_get_ddr_size(void) 317 { 318 int node; 319 320 node = fdt_node_offset_by_compatible(fdt, -1, DT_DDR_COMPAT); 321 if (node < 0) { 322 INFO("%s: Cannot read DDR node in DT\n", __func__); 323 return 0; 324 } 325 326 return fdt_read_uint32_default(fdt, node, "st,mem-size", 0); 327 } 328 329 /******************************************************************************* 330 * This function gets DDRCTRL base address information from the DT. 331 * Returns value on success, and 0 on failure. 332 ******************************************************************************/ 333 uintptr_t dt_get_ddrctrl_base(void) 334 { 335 int node; 336 uint32_t array[4]; 337 338 node = fdt_node_offset_by_compatible(fdt, -1, DT_DDR_COMPAT); 339 if (node < 0) { 340 INFO("%s: Cannot read DDR node in DT\n", __func__); 341 return 0; 342 } 343 344 assert((fdt_get_node_parent_address_cells(node) == 1) && 345 (fdt_get_node_parent_size_cells(node) == 1)); 346 347 if (fdt_read_uint32_array(fdt, node, "reg", 4, array) < 0) { 348 return 0; 349 } 350 351 return array[0]; 352 } 353 354 /******************************************************************************* 355 * This function gets DDRPHYC base address information from the DT. 356 * Returns value on success, and 0 on failure. 357 ******************************************************************************/ 358 uintptr_t dt_get_ddrphyc_base(void) 359 { 360 int node; 361 uint32_t array[4]; 362 363 node = fdt_node_offset_by_compatible(fdt, -1, DT_DDR_COMPAT); 364 if (node < 0) { 365 INFO("%s: Cannot read DDR node in DT\n", __func__); 366 return 0; 367 } 368 369 assert((fdt_get_node_parent_address_cells(node) == 1) && 370 (fdt_get_node_parent_size_cells(node) == 1)); 371 372 if (fdt_read_uint32_array(fdt, node, "reg", 4, array) < 0) { 373 return 0; 374 } 375 376 return array[2]; 377 } 378 379 /******************************************************************************* 380 * This function gets PWR base address information from the DT. 381 * Returns value on success, and 0 on failure. 382 ******************************************************************************/ 383 uintptr_t dt_get_pwr_base(void) 384 { 385 int node; 386 const fdt32_t *cuint; 387 388 node = fdt_node_offset_by_compatible(fdt, -1, DT_PWR_COMPAT); 389 if (node < 0) { 390 INFO("%s: Cannot read PWR node in DT\n", __func__); 391 return 0; 392 } 393 394 assert(fdt_get_node_parent_address_cells(node) == 1); 395 396 cuint = fdt_getprop(fdt, node, "reg", NULL); 397 if (cuint == NULL) { 398 return 0; 399 } 400 401 return fdt32_to_cpu(*cuint); 402 } 403 404 /******************************************************************************* 405 * This function gets PWR VDD regulator voltage information from the DT. 406 * Returns value in microvolts on success, and 0 on failure. 407 ******************************************************************************/ 408 uint32_t dt_get_pwr_vdd_voltage(void) 409 { 410 int node, pwr_regulators_node; 411 const fdt32_t *cuint; 412 413 node = fdt_node_offset_by_compatible(fdt, -1, DT_PWR_COMPAT); 414 if (node < 0) { 415 INFO("%s: Cannot read PWR node in DT\n", __func__); 416 return 0; 417 } 418 419 pwr_regulators_node = fdt_subnode_offset(fdt, node, "pwr-regulators"); 420 if (pwr_regulators_node < 0) { 421 INFO("%s: Cannot read pwr-regulators node in DT\n", __func__); 422 return 0; 423 } 424 425 cuint = fdt_getprop(fdt, pwr_regulators_node, "vdd-supply", NULL); 426 if (cuint == NULL) { 427 return 0; 428 } 429 430 node = fdt_node_offset_by_phandle(fdt, fdt32_to_cpu(*cuint)); 431 if (node < 0) { 432 return 0; 433 } 434 435 cuint = fdt_getprop(fdt, node, "regulator-min-microvolt", NULL); 436 if (cuint == NULL) { 437 return 0; 438 } 439 440 return fdt32_to_cpu(*cuint); 441 } 442 443 /******************************************************************************* 444 * This function gets SYSCFG base address information from the DT. 445 * Returns value on success, and 0 on failure. 446 ******************************************************************************/ 447 uintptr_t dt_get_syscfg_base(void) 448 { 449 int node; 450 const fdt32_t *cuint; 451 452 node = fdt_node_offset_by_compatible(fdt, -1, DT_SYSCFG_COMPAT); 453 if (node < 0) { 454 INFO("%s: Cannot read SYSCFG node in DT\n", __func__); 455 return 0; 456 } 457 458 assert(fdt_get_node_parent_address_cells(node) == 1); 459 460 cuint = fdt_getprop(fdt, node, "reg", NULL); 461 if (cuint == NULL) { 462 return 0; 463 } 464 465 return fdt32_to_cpu(*cuint); 466 } 467 468 /******************************************************************************* 469 * This function retrieves board model from DT 470 * Returns string taken from model node, NULL otherwise 471 ******************************************************************************/ 472 const char *dt_get_board_model(void) 473 { 474 int node = fdt_path_offset(fdt, "/"); 475 476 if (node < 0) { 477 return NULL; 478 } 479 480 return (const char *)fdt_getprop(fdt, node, "model", NULL); 481 } 482