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