1 /* 2 * Copyright (c) 2017-2024, 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 <common/debug.h> 11 #include <common/fdt_wrappers.h> 12 #include <drivers/st/regulator.h> 13 #include <drivers/st/stm32_gpio.h> 14 #include <libfdt.h> 15 16 #include <platform_def.h> 17 #include <stm32mp_dt.h> 18 19 static void *fdt; 20 21 /******************************************************************************* 22 * This function checks device tree file with its header. 23 * Returns 0 on success and a negative FDT error code on failure. 24 ******************************************************************************/ 25 int dt_open_and_check(uintptr_t dt_addr) 26 { 27 int ret; 28 29 ret = fdt_check_header((void *)dt_addr); 30 if (ret == 0) { 31 fdt = (void *)dt_addr; 32 } 33 34 return ret; 35 } 36 37 /******************************************************************************* 38 * This function gets the address of the DT. 39 * If DT is OK, fdt_addr is filled with DT address. 40 * Returns 1 if success, 0 otherwise. 41 ******************************************************************************/ 42 int fdt_get_address(void **fdt_addr) 43 { 44 if (fdt == NULL) { 45 return 0; 46 } 47 48 *fdt_addr = fdt; 49 50 return 1; 51 } 52 53 /******************************************************************************* 54 * This function check the presence of a node (generic use of fdt library). 55 * Returns true if present, else return false. 56 ******************************************************************************/ 57 bool fdt_check_node(int node) 58 { 59 int len; 60 const char *cchar; 61 62 cchar = fdt_get_name(fdt, node, &len); 63 64 return (cchar != NULL) && (len >= 0); 65 } 66 67 /******************************************************************************* 68 * This function return global node status (generic use of fdt library). 69 ******************************************************************************/ 70 uint8_t fdt_get_status(int node) 71 { 72 uint8_t status = DT_DISABLED; 73 const char *cchar; 74 75 cchar = fdt_getprop(fdt, node, "status", NULL); 76 if ((cchar == NULL) || 77 (strncmp(cchar, "okay", strlen("okay")) == 0)) { 78 status |= DT_NON_SECURE; 79 } 80 81 cchar = fdt_getprop(fdt, node, "secure-status", NULL); 82 if (((cchar == NULL) && (status == DT_NON_SECURE)) || 83 ((cchar != NULL) && (strncmp(cchar, "okay", strlen("okay")) == 0))) { 84 status |= DT_SECURE; 85 } 86 87 return status; 88 } 89 90 #if ENABLE_ASSERTIONS 91 /******************************************************************************* 92 * This function returns the address cells from the node parent. 93 * Returns: 94 * - #address-cells value if success. 95 * - invalid value if error. 96 * - a default value if undefined #address-cells property as per libfdt 97 * implementation. 98 ******************************************************************************/ 99 static int fdt_get_node_parent_address_cells(int node) 100 { 101 int parent; 102 103 parent = fdt_parent_offset(fdt, node); 104 if (parent < 0) { 105 return -FDT_ERR_NOTFOUND; 106 } 107 108 return fdt_address_cells(fdt, parent); 109 } 110 #endif 111 112 /******************************************************************************* 113 * This function gets the stdout pin configuration information from the DT. 114 * And then calls the sub-function to treat it and set GPIO registers. 115 * Returns 0 on success and a negative FDT error code on failure. 116 ******************************************************************************/ 117 int dt_set_stdout_pinctrl(void) 118 { 119 int node; 120 121 node = fdt_get_stdout_node_offset(fdt); 122 if (node < 0) { 123 return -FDT_ERR_NOTFOUND; 124 } 125 126 return dt_set_pinctrl_config(node); 127 } 128 129 /******************************************************************************* 130 * This function fills the generic information from a given node. 131 ******************************************************************************/ 132 void dt_fill_device_info(struct dt_node_info *info, int node) 133 { 134 const fdt32_t *cuint; 135 136 assert(fdt_get_node_parent_address_cells(node) == 1); 137 138 cuint = fdt_getprop(fdt, node, "reg", NULL); 139 if (cuint != NULL) { 140 info->base = fdt32_to_cpu(*cuint); 141 } else { 142 info->base = 0; 143 } 144 145 cuint = fdt_getprop(fdt, node, "clocks", NULL); 146 if (cuint != NULL) { 147 cuint++; 148 info->clock = (int)fdt32_to_cpu(*cuint); 149 } else { 150 info->clock = -1; 151 } 152 153 cuint = fdt_getprop(fdt, node, "resets", NULL); 154 if (cuint != NULL) { 155 cuint++; 156 info->reset = (int)fdt32_to_cpu(*cuint); 157 } else { 158 info->reset = -1; 159 } 160 161 info->status = fdt_get_status(node); 162 } 163 164 /******************************************************************************* 165 * This function retrieve the generic information from DT. 166 * Returns node on success and a negative FDT error code on failure. 167 ******************************************************************************/ 168 int dt_get_node(struct dt_node_info *info, int offset, const char *compat) 169 { 170 int node; 171 172 node = fdt_node_offset_by_compatible(fdt, offset, compat); 173 if (node < 0) { 174 return -FDT_ERR_NOTFOUND; 175 } 176 177 dt_fill_device_info(info, node); 178 179 return node; 180 } 181 182 /******************************************************************************* 183 * This function gets the UART instance info of stdout from the DT. 184 * Returns node on success and a negative FDT error code on failure. 185 ******************************************************************************/ 186 int dt_get_stdout_uart_info(struct dt_node_info *info) 187 { 188 int node; 189 190 node = fdt_get_stdout_node_offset(fdt); 191 if (node < 0) { 192 return -FDT_ERR_NOTFOUND; 193 } 194 195 dt_fill_device_info(info, node); 196 197 return node; 198 } 199 200 /******************************************************************************* 201 * This function returns the node offset matching compatible string in the DT, 202 * and also matching the reg property with the given address. 203 * Returns value on success, and error value on failure. 204 ******************************************************************************/ 205 int dt_match_instance_by_compatible(const char *compatible, uintptr_t address) 206 { 207 int node; 208 209 fdt_for_each_compatible_node(fdt, node, compatible) { 210 const fdt32_t *cuint; 211 212 assert(fdt_get_node_parent_address_cells(node) == 1); 213 214 cuint = fdt_getprop(fdt, node, "reg", NULL); 215 if (cuint == NULL) { 216 continue; 217 } 218 219 if ((uintptr_t)fdt32_to_cpu(*cuint) == address) { 220 return node; 221 } 222 } 223 224 return -FDT_ERR_NOTFOUND; 225 } 226 227 /******************************************************************************* 228 * This function gets DDR size information from the DT. 229 * Returns value in bytes on success, and 0 on failure. 230 ******************************************************************************/ 231 size_t dt_get_ddr_size(void) 232 { 233 static size_t size; 234 int node; 235 236 if (size != 0U) { 237 return size; 238 } 239 240 node = fdt_node_offset_by_compatible(fdt, -1, DT_DDR_COMPAT); 241 if (node < 0) { 242 INFO("%s: Cannot read DDR node in DT\n", __func__); 243 return 0U; 244 } 245 246 #ifdef __aarch64__ 247 size = (size_t)fdt_read_uint64_default(fdt, node, "st,mem-size", 0ULL); 248 #else /* __aarch64__ */ 249 size = (size_t)fdt_read_uint32_default(fdt, node, "st,mem-size", 0U); 250 #endif /* __aarch64__ */ 251 252 flush_dcache_range((uintptr_t)&size, sizeof(size_t)); 253 254 return size; 255 } 256 257 /******************************************************************************* 258 * This function gets PWR VDD regulator voltage information from the DT. 259 * Returns value in microvolts on success, and 0 on failure. 260 ******************************************************************************/ 261 uint32_t dt_get_pwr_vdd_voltage(void) 262 { 263 struct rdev *regul = dt_get_vdd_regulator(); 264 uint16_t min; 265 266 if (regul == NULL) { 267 return 0; 268 } 269 270 regulator_get_range(regul, &min, NULL); 271 272 return (uint32_t)min * 1000U; 273 } 274 275 /******************************************************************************* 276 * This function retrieves VDD supply regulator from DT. 277 * Returns an rdev taken from supply node, NULL otherwise. 278 ******************************************************************************/ 279 struct rdev *dt_get_vdd_regulator(void) 280 { 281 int node = fdt_node_offset_by_compatible(fdt, -1, DT_PWR_COMPAT); 282 283 if (node < 0) { 284 return NULL; 285 } 286 287 return regulator_get_by_supply_name(fdt, node, "vdd"); 288 } 289 290 /******************************************************************************* 291 * This function retrieves CPU supply regulator from DT. 292 * Returns an rdev taken from supply node, NULL otherwise. 293 ******************************************************************************/ 294 struct rdev *dt_get_cpu_regulator(void) 295 { 296 int node = fdt_path_offset(fdt, "/cpus/cpu@0"); 297 298 if (node < 0) { 299 return NULL; 300 } 301 302 return regulator_get_by_supply_name(fdt, node, "cpu"); 303 } 304 305 /******************************************************************************* 306 * This function retrieves board model from DT 307 * Returns string taken from model node, NULL otherwise 308 ******************************************************************************/ 309 const char *dt_get_board_model(void) 310 { 311 int node = fdt_path_offset(fdt, "/"); 312 313 if (node < 0) { 314 return NULL; 315 } 316 317 return (const char *)fdt_getprop(fdt, node, "model", NULL); 318 } 319 320 /******************************************************************************* 321 * dt_find_otp_name: get OTP ID and length in DT. 322 * name: sub-node name to look up. 323 * otp: pointer to read OTP number or NULL. 324 * otp_len: pointer to read OTP length in bits or NULL. 325 * return value: 0 if no error, an FDT error value otherwise. 326 ******************************************************************************/ 327 int dt_find_otp_name(const char *name, uint32_t *otp, uint32_t *otp_len) 328 { 329 int node; 330 int len; 331 const fdt32_t *cuint; 332 333 if ((name == NULL) || (otp == NULL)) { 334 return -FDT_ERR_BADVALUE; 335 } 336 337 node = fdt_node_offset_by_compatible(fdt, -1, DT_BSEC_COMPAT); 338 if (node < 0) { 339 return node; 340 } 341 342 node = fdt_subnode_offset(fdt, node, name); 343 if (node < 0) { 344 ERROR("nvmem node %s not found\n", name); 345 return node; 346 } 347 348 cuint = fdt_getprop(fdt, node, "reg", &len); 349 if ((cuint == NULL) || (len != (2 * (int)sizeof(uint32_t)))) { 350 ERROR("Malformed nvmem node %s: ignored\n", name); 351 return -FDT_ERR_BADVALUE; 352 } 353 354 if ((fdt32_to_cpu(*cuint) % sizeof(uint32_t)) != 0U) { 355 ERROR("Misaligned nvmem %s element: ignored\n", name); 356 return -FDT_ERR_BADVALUE; 357 } 358 359 if (otp != NULL) { 360 *otp = fdt32_to_cpu(*cuint) / sizeof(uint32_t); 361 } 362 363 if (otp_len != NULL) { 364 cuint++; 365 *otp_len = fdt32_to_cpu(*cuint) * CHAR_BIT; 366 } 367 368 return 0; 369 } 370 371 /******************************************************************************* 372 * This function gets the pin count for a GPIO bank based from the FDT. 373 * It also checks node consistency. 374 ******************************************************************************/ 375 int fdt_get_gpio_bank_pin_count(unsigned int bank) 376 { 377 int pinctrl_node; 378 int node; 379 uint32_t bank_offset; 380 381 pinctrl_node = stm32_get_gpio_bank_pinctrl_node(fdt, bank); 382 if (pinctrl_node < 0) { 383 return -FDT_ERR_NOTFOUND; 384 } 385 386 bank_offset = stm32_get_gpio_bank_offset(bank); 387 388 fdt_for_each_subnode(node, fdt, pinctrl_node) { 389 const fdt32_t *cuint; 390 int pin_count = 0; 391 int len; 392 int i; 393 394 if (fdt_getprop(fdt, node, "gpio-controller", NULL) == NULL) { 395 continue; 396 } 397 398 cuint = fdt_getprop(fdt, node, "reg", NULL); 399 if (cuint == NULL) { 400 continue; 401 } 402 403 if (fdt32_to_cpu(*cuint) != bank_offset) { 404 continue; 405 } 406 407 if (fdt_get_status(node) == DT_DISABLED) { 408 return 0; 409 } 410 411 /* Parse gpio-ranges with its 4 parameters */ 412 cuint = fdt_getprop(fdt, node, "gpio-ranges", &len); 413 len /= sizeof(*cuint); 414 if ((len % 4) != 0) { 415 return -FDT_ERR_BADVALUE; 416 } 417 418 /* Get the last defined gpio line (offset + nb of pins) */ 419 for (i = 0; i < len; i += 4) { 420 pin_count = MAX(pin_count, (int)(fdt32_to_cpu(cuint[i + 1]) + 421 fdt32_to_cpu(cuint[i + 3]))); 422 } 423 424 return pin_count; 425 } 426 427 return 0; 428 } 429