1 /* 2 * Copyright (c) 2017-2023, 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 size = (size_t)fdt_read_uint32_default(fdt, node, "st,mem-size", 0U); 247 248 flush_dcache_range((uintptr_t)&size, sizeof(size_t)); 249 250 return size; 251 } 252 253 /******************************************************************************* 254 * This function gets PWR VDD regulator voltage information from the DT. 255 * Returns value in microvolts on success, and 0 on failure. 256 ******************************************************************************/ 257 uint32_t dt_get_pwr_vdd_voltage(void) 258 { 259 struct rdev *regul = dt_get_vdd_regulator(); 260 uint16_t min; 261 262 if (regul == NULL) { 263 return 0; 264 } 265 266 regulator_get_range(regul, &min, NULL); 267 268 return (uint32_t)min * 1000U; 269 } 270 271 /******************************************************************************* 272 * This function retrieves VDD supply regulator from DT. 273 * Returns an rdev taken from supply node, NULL otherwise. 274 ******************************************************************************/ 275 struct rdev *dt_get_vdd_regulator(void) 276 { 277 int node = fdt_node_offset_by_compatible(fdt, -1, DT_PWR_COMPAT); 278 279 if (node < 0) { 280 return NULL; 281 } 282 283 return regulator_get_by_supply_name(fdt, node, "vdd"); 284 } 285 286 /******************************************************************************* 287 * This function retrieves CPU supply regulator from DT. 288 * Returns an rdev taken from supply node, NULL otherwise. 289 ******************************************************************************/ 290 struct rdev *dt_get_cpu_regulator(void) 291 { 292 int node = fdt_path_offset(fdt, "/cpus/cpu@0"); 293 294 if (node < 0) { 295 return NULL; 296 } 297 298 return regulator_get_by_supply_name(fdt, node, "cpu"); 299 } 300 301 /******************************************************************************* 302 * This function retrieves board model from DT 303 * Returns string taken from model node, NULL otherwise 304 ******************************************************************************/ 305 const char *dt_get_board_model(void) 306 { 307 int node = fdt_path_offset(fdt, "/"); 308 309 if (node < 0) { 310 return NULL; 311 } 312 313 return (const char *)fdt_getprop(fdt, node, "model", NULL); 314 } 315 316 /******************************************************************************* 317 * dt_find_otp_name: get OTP ID and length in DT. 318 * name: sub-node name to look up. 319 * otp: pointer to read OTP number or NULL. 320 * otp_len: pointer to read OTP length in bits or NULL. 321 * return value: 0 if no error, an FDT error value otherwise. 322 ******************************************************************************/ 323 int dt_find_otp_name(const char *name, uint32_t *otp, uint32_t *otp_len) 324 { 325 int node; 326 int len; 327 const fdt32_t *cuint; 328 329 if ((name == NULL) || (otp == NULL)) { 330 return -FDT_ERR_BADVALUE; 331 } 332 333 node = fdt_node_offset_by_compatible(fdt, -1, DT_BSEC_COMPAT); 334 if (node < 0) { 335 return node; 336 } 337 338 node = fdt_subnode_offset(fdt, node, name); 339 if (node < 0) { 340 ERROR("nvmem node %s not found\n", name); 341 return node; 342 } 343 344 cuint = fdt_getprop(fdt, node, "reg", &len); 345 if ((cuint == NULL) || (len != (2 * (int)sizeof(uint32_t)))) { 346 ERROR("Malformed nvmem node %s: ignored\n", name); 347 return -FDT_ERR_BADVALUE; 348 } 349 350 if ((fdt32_to_cpu(*cuint) % sizeof(uint32_t)) != 0U) { 351 ERROR("Misaligned nvmem %s element: ignored\n", name); 352 return -FDT_ERR_BADVALUE; 353 } 354 355 if (otp != NULL) { 356 *otp = fdt32_to_cpu(*cuint) / sizeof(uint32_t); 357 } 358 359 if (otp_len != NULL) { 360 cuint++; 361 *otp_len = fdt32_to_cpu(*cuint) * CHAR_BIT; 362 } 363 364 return 0; 365 } 366 367 /******************************************************************************* 368 * This function gets the pin count for a GPIO bank based from the FDT. 369 * It also checks node consistency. 370 ******************************************************************************/ 371 int fdt_get_gpio_bank_pin_count(unsigned int bank) 372 { 373 int pinctrl_node; 374 int node; 375 uint32_t bank_offset; 376 377 pinctrl_node = stm32_get_gpio_bank_pinctrl_node(fdt, bank); 378 if (pinctrl_node < 0) { 379 return -FDT_ERR_NOTFOUND; 380 } 381 382 bank_offset = stm32_get_gpio_bank_offset(bank); 383 384 fdt_for_each_subnode(node, fdt, pinctrl_node) { 385 const fdt32_t *cuint; 386 int pin_count = 0; 387 int len; 388 int i; 389 390 if (fdt_getprop(fdt, node, "gpio-controller", NULL) == NULL) { 391 continue; 392 } 393 394 cuint = fdt_getprop(fdt, node, "reg", NULL); 395 if (cuint == NULL) { 396 continue; 397 } 398 399 if (fdt32_to_cpu(*cuint) != bank_offset) { 400 continue; 401 } 402 403 if (fdt_get_status(node) == DT_DISABLED) { 404 return 0; 405 } 406 407 /* Parse gpio-ranges with its 4 parameters */ 408 cuint = fdt_getprop(fdt, node, "gpio-ranges", &len); 409 len /= sizeof(*cuint); 410 if ((len % 4) != 0) { 411 return -FDT_ERR_BADVALUE; 412 } 413 414 /* Get the last defined gpio line (offset + nb of pins) */ 415 for (i = 0; i < len; i += 4) { 416 pin_count = MAX(pin_count, (int)(fdt32_to_cpu(cuint[i + 1]) + 417 fdt32_to_cpu(cuint[i + 3]))); 418 } 419 420 return pin_count; 421 } 422 423 return 0; 424 } 425