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 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 ******************************************************************************/ 101 uint32_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. 120 * Returns 0 on success and a negative FDT error code on failure. 121 * If success, values are stored at the third parameter address. 122 ******************************************************************************/ 123 int 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 } 147 148 /******************************************************************************* 149 * 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 ******************************************************************************/ 153 static 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 /******************************************************************************* 195 * 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. 197 * Returns 0 on success and a negative FDT error code on failure. 198 ******************************************************************************/ 199 int 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 ******************************************************************************/ 214 void 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 241 info->status = fdt_get_status(node); 242 } 243 244 /******************************************************************************* 245 * This function retrieve the generic information from DT. 246 * Returns node on success and a negative FDT error code on failure. 247 ******************************************************************************/ 248 int 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. 264 * Returns node on success and a negative FDT error code on failure. 265 ******************************************************************************/ 266 int 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 /******************************************************************************* 281 * This function gets DDR size information from the DT. 282 * Returns value in bytes on success, and 0 on failure. 283 ******************************************************************************/ 284 uint32_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__); 291 return 0; 292 } 293 294 return fdt_read_uint32_default(node, "st,mem-size", 0); 295 } 296 297 /******************************************************************************* 298 * This function gets DDRCTRL base address information from the DT. 299 * Returns value on success, and 0 on failure. 300 ******************************************************************************/ 301 uintptr_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 ******************************************************************************/ 323 uintptr_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 ******************************************************************************/ 345 uintptr_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 /******************************************************************************* 365 * This function gets PWR VDD regulator voltage information from the DT. 366 * Returns value in microvolts on success, and 0 on failure. 367 ******************************************************************************/ 368 uint32_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 ******************************************************************************/ 407 uintptr_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 /******************************************************************************* 427 * This function retrieves board model from DT 428 * Returns string taken from model node, NULL otherwise 429 ******************************************************************************/ 430 const 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 } 440