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