1447b2b13SYann Gautier /* 2447b2b13SYann Gautier * Copyright (c) 2017-2019, STMicroelectronics - All Rights Reserved 3447b2b13SYann Gautier * 4447b2b13SYann Gautier * SPDX-License-Identifier: BSD-3-Clause 5447b2b13SYann Gautier */ 6447b2b13SYann Gautier 7447b2b13SYann Gautier #include <errno.h> 8447b2b13SYann Gautier 9447b2b13SYann Gautier #include <libfdt.h> 10447b2b13SYann Gautier 11447b2b13SYann Gautier #include <platform_def.h> 12447b2b13SYann Gautier 13447b2b13SYann Gautier #include <drivers/st/stm32_gpio.h> 14447b2b13SYann Gautier #include <drivers/st/stm32mp_clkfunc.h> 15447b2b13SYann Gautier 16447b2b13SYann Gautier #define DT_STGEN_COMPAT "st,stm32-stgen" 17447b2b13SYann Gautier 18447b2b13SYann Gautier /* 19*f66358afSYann Gautier * Get the frequency of an oscillator from its name in device tree. 20*f66358afSYann Gautier * @param name: oscillator name 21*f66358afSYann Gautier * @param freq: stores the frequency of the oscillator 22*f66358afSYann Gautier * @return: 0 on success, and a negative FDT/ERRNO error code on failure. 23*f66358afSYann Gautier */ 24*f66358afSYann Gautier int fdt_osc_read_freq(const char *name, uint32_t *freq) 25*f66358afSYann Gautier { 26*f66358afSYann Gautier int node, subnode; 27*f66358afSYann Gautier void *fdt; 28*f66358afSYann Gautier 29*f66358afSYann Gautier if (fdt_get_address(&fdt) == 0) { 30*f66358afSYann Gautier return -ENOENT; 31*f66358afSYann Gautier } 32*f66358afSYann Gautier 33*f66358afSYann Gautier node = fdt_path_offset(fdt, "/clocks"); 34*f66358afSYann Gautier if (node < 0) { 35*f66358afSYann Gautier return -FDT_ERR_NOTFOUND; 36*f66358afSYann Gautier } 37*f66358afSYann Gautier 38*f66358afSYann Gautier fdt_for_each_subnode(subnode, fdt, node) { 39*f66358afSYann Gautier const char *cchar; 40*f66358afSYann Gautier int ret; 41*f66358afSYann Gautier 42*f66358afSYann Gautier cchar = fdt_get_name(fdt, subnode, &ret); 43*f66358afSYann Gautier if (cchar == NULL) { 44*f66358afSYann Gautier return ret; 45*f66358afSYann Gautier } 46*f66358afSYann Gautier 47*f66358afSYann Gautier if (strncmp(cchar, name, (size_t)ret) == 0) { 48*f66358afSYann Gautier const fdt32_t *cuint; 49*f66358afSYann Gautier 50*f66358afSYann Gautier cuint = fdt_getprop(fdt, subnode, "clock-frequency", 51*f66358afSYann Gautier &ret); 52*f66358afSYann Gautier if (cuint == NULL) { 53*f66358afSYann Gautier return ret; 54*f66358afSYann Gautier } 55*f66358afSYann Gautier 56*f66358afSYann Gautier *freq = fdt32_to_cpu(*cuint); 57*f66358afSYann Gautier 58*f66358afSYann Gautier return 0; 59*f66358afSYann Gautier } 60*f66358afSYann Gautier } 61*f66358afSYann Gautier 62*f66358afSYann Gautier /* Oscillator not found, freq=0 */ 63*f66358afSYann Gautier *freq = 0; 64*f66358afSYann Gautier return 0; 65*f66358afSYann Gautier } 66*f66358afSYann Gautier 67*f66358afSYann Gautier /* 68*f66358afSYann Gautier * Check the presence of an oscillator property from its id. 69*f66358afSYann Gautier * @param osc_id: oscillator ID 70*f66358afSYann Gautier * @param prop_name: property name 71*f66358afSYann Gautier * @return: true/false regarding search result. 72*f66358afSYann Gautier */ 73*f66358afSYann Gautier bool fdt_osc_read_bool(enum stm32mp_osc_id osc_id, const char *prop_name) 74*f66358afSYann Gautier { 75*f66358afSYann Gautier int node, subnode; 76*f66358afSYann Gautier void *fdt; 77*f66358afSYann Gautier 78*f66358afSYann Gautier if (fdt_get_address(&fdt) == 0) { 79*f66358afSYann Gautier return false; 80*f66358afSYann Gautier } 81*f66358afSYann Gautier 82*f66358afSYann Gautier if (osc_id >= NB_OSC) { 83*f66358afSYann Gautier return false; 84*f66358afSYann Gautier } 85*f66358afSYann Gautier 86*f66358afSYann Gautier node = fdt_path_offset(fdt, "/clocks"); 87*f66358afSYann Gautier if (node < 0) { 88*f66358afSYann Gautier return false; 89*f66358afSYann Gautier } 90*f66358afSYann Gautier 91*f66358afSYann Gautier fdt_for_each_subnode(subnode, fdt, node) { 92*f66358afSYann Gautier const char *cchar; 93*f66358afSYann Gautier int ret; 94*f66358afSYann Gautier 95*f66358afSYann Gautier cchar = fdt_get_name(fdt, subnode, &ret); 96*f66358afSYann Gautier if (cchar == NULL) { 97*f66358afSYann Gautier return false; 98*f66358afSYann Gautier } 99*f66358afSYann Gautier 100*f66358afSYann Gautier if (strncmp(cchar, stm32mp_osc_node_label[osc_id], 101*f66358afSYann Gautier (size_t)ret) != 0) { 102*f66358afSYann Gautier continue; 103*f66358afSYann Gautier } 104*f66358afSYann Gautier 105*f66358afSYann Gautier if (fdt_getprop(fdt, subnode, prop_name, NULL) != NULL) { 106*f66358afSYann Gautier return true; 107*f66358afSYann Gautier } 108*f66358afSYann Gautier } 109*f66358afSYann Gautier 110*f66358afSYann Gautier return false; 111*f66358afSYann Gautier } 112*f66358afSYann Gautier 113*f66358afSYann Gautier /* 114*f66358afSYann Gautier * Get the value of a oscillator property from its ID. 115*f66358afSYann Gautier * @param osc_id: oscillator ID 116*f66358afSYann Gautier * @param prop_name: property name 117*f66358afSYann Gautier * @param dflt_value: default value 118*f66358afSYann Gautier * @return oscillator value on success, default value if property not found. 119*f66358afSYann Gautier */ 120*f66358afSYann Gautier uint32_t fdt_osc_read_uint32_default(enum stm32mp_osc_id osc_id, 121*f66358afSYann Gautier const char *prop_name, uint32_t dflt_value) 122*f66358afSYann Gautier { 123*f66358afSYann Gautier int node, subnode; 124*f66358afSYann Gautier void *fdt; 125*f66358afSYann Gautier 126*f66358afSYann Gautier if (fdt_get_address(&fdt) == 0) { 127*f66358afSYann Gautier return dflt_value; 128*f66358afSYann Gautier } 129*f66358afSYann Gautier 130*f66358afSYann Gautier if (osc_id >= NB_OSC) { 131*f66358afSYann Gautier return dflt_value; 132*f66358afSYann Gautier } 133*f66358afSYann Gautier 134*f66358afSYann Gautier node = fdt_path_offset(fdt, "/clocks"); 135*f66358afSYann Gautier if (node < 0) { 136*f66358afSYann Gautier return dflt_value; 137*f66358afSYann Gautier } 138*f66358afSYann Gautier 139*f66358afSYann Gautier fdt_for_each_subnode(subnode, fdt, node) { 140*f66358afSYann Gautier const char *cchar; 141*f66358afSYann Gautier int ret; 142*f66358afSYann Gautier 143*f66358afSYann Gautier cchar = fdt_get_name(fdt, subnode, &ret); 144*f66358afSYann Gautier if (cchar == NULL) { 145*f66358afSYann Gautier return dflt_value; 146*f66358afSYann Gautier } 147*f66358afSYann Gautier 148*f66358afSYann Gautier if (strncmp(cchar, stm32mp_osc_node_label[osc_id], 149*f66358afSYann Gautier (size_t)ret) != 0) { 150*f66358afSYann Gautier continue; 151*f66358afSYann Gautier } 152*f66358afSYann Gautier 153*f66358afSYann Gautier return fdt_read_uint32_default(subnode, prop_name, dflt_value); 154*f66358afSYann Gautier } 155*f66358afSYann Gautier 156*f66358afSYann Gautier return dflt_value; 157*f66358afSYann Gautier } 158*f66358afSYann Gautier 159*f66358afSYann Gautier /* 160447b2b13SYann Gautier * Get the RCC node offset from the device tree 161447b2b13SYann Gautier * @param fdt: Device tree reference 162447b2b13SYann Gautier * @return: Node offset or a negative value on error 163447b2b13SYann Gautier */ 164447b2b13SYann Gautier int fdt_get_rcc_node(void *fdt) 165447b2b13SYann Gautier { 166447b2b13SYann Gautier return fdt_node_offset_by_compatible(fdt, -1, DT_RCC_CLK_COMPAT); 167447b2b13SYann Gautier } 168447b2b13SYann Gautier 169447b2b13SYann Gautier /* 170447b2b13SYann Gautier * Get the RCC base address from the device tree 171447b2b13SYann Gautier * @return: RCC address or 0 on error 172447b2b13SYann Gautier */ 173447b2b13SYann Gautier uint32_t fdt_rcc_read_addr(void) 174447b2b13SYann Gautier { 175447b2b13SYann Gautier int node; 176447b2b13SYann Gautier void *fdt; 177447b2b13SYann Gautier const fdt32_t *cuint; 178447b2b13SYann Gautier 179447b2b13SYann Gautier if (fdt_get_address(&fdt) == 0) { 180447b2b13SYann Gautier return 0; 181447b2b13SYann Gautier } 182447b2b13SYann Gautier 183447b2b13SYann Gautier node = fdt_get_rcc_node(fdt); 184447b2b13SYann Gautier if (node < 0) { 185447b2b13SYann Gautier return 0; 186447b2b13SYann Gautier } 187447b2b13SYann Gautier 188447b2b13SYann Gautier cuint = fdt_getprop(fdt, node, "reg", NULL); 189447b2b13SYann Gautier if (cuint == NULL) { 190447b2b13SYann Gautier return 0; 191447b2b13SYann Gautier } 192447b2b13SYann Gautier 193447b2b13SYann Gautier return fdt32_to_cpu(*cuint); 194447b2b13SYann Gautier } 195447b2b13SYann Gautier 196447b2b13SYann Gautier /* 197447b2b13SYann Gautier * Read a series of parameters in rcc-clk section in device tree 198447b2b13SYann Gautier * @param prop_name: Name of the RCC property to be read 199447b2b13SYann Gautier * @param array: the array to store the property parameters 200447b2b13SYann Gautier * @param count: number of parameters to be read 201447b2b13SYann Gautier * @return: 0 on succes or a negative value on error 202447b2b13SYann Gautier */ 203447b2b13SYann Gautier int fdt_rcc_read_uint32_array(const char *prop_name, 204447b2b13SYann Gautier uint32_t *array, uint32_t count) 205447b2b13SYann Gautier { 206447b2b13SYann Gautier int node; 207447b2b13SYann Gautier void *fdt; 208447b2b13SYann Gautier 209447b2b13SYann Gautier if (fdt_get_address(&fdt) == 0) { 210447b2b13SYann Gautier return -ENOENT; 211447b2b13SYann Gautier } 212447b2b13SYann Gautier 213447b2b13SYann Gautier node = fdt_get_rcc_node(fdt); 214447b2b13SYann Gautier if (node < 0) { 215447b2b13SYann Gautier return -FDT_ERR_NOTFOUND; 216447b2b13SYann Gautier } 217447b2b13SYann Gautier 218447b2b13SYann Gautier return fdt_read_uint32_array(node, prop_name, array, count); 219447b2b13SYann Gautier } 220447b2b13SYann Gautier 221447b2b13SYann Gautier /* 222447b2b13SYann Gautier * Get the subnode offset in rcc-clk section from its name in device tree 223447b2b13SYann Gautier * @param name: name of the RCC property 224447b2b13SYann Gautier * @return: offset on success, and a negative FDT/ERRNO error code on failure. 225447b2b13SYann Gautier */ 226447b2b13SYann Gautier int fdt_rcc_subnode_offset(const char *name) 227447b2b13SYann Gautier { 228447b2b13SYann Gautier int node, subnode; 229447b2b13SYann Gautier void *fdt; 230447b2b13SYann Gautier 231447b2b13SYann Gautier if (fdt_get_address(&fdt) == 0) { 232447b2b13SYann Gautier return -ENOENT; 233447b2b13SYann Gautier } 234447b2b13SYann Gautier 235447b2b13SYann Gautier node = fdt_get_rcc_node(fdt); 236447b2b13SYann Gautier if (node < 0) { 237447b2b13SYann Gautier return -FDT_ERR_NOTFOUND; 238447b2b13SYann Gautier } 239447b2b13SYann Gautier 240447b2b13SYann Gautier subnode = fdt_subnode_offset(fdt, node, name); 241447b2b13SYann Gautier if (subnode <= 0) { 242447b2b13SYann Gautier return -FDT_ERR_NOTFOUND; 243447b2b13SYann Gautier } 244447b2b13SYann Gautier 245447b2b13SYann Gautier return subnode; 246447b2b13SYann Gautier } 247447b2b13SYann Gautier 248447b2b13SYann Gautier /* 249447b2b13SYann Gautier * Get the pointer to a rcc-clk property from its name. 250447b2b13SYann Gautier * @param name: name of the RCC property 251447b2b13SYann Gautier * @param lenp: stores the length of the property. 252447b2b13SYann Gautier * @return: pointer to the property on success, and NULL value on failure. 253447b2b13SYann Gautier */ 254447b2b13SYann Gautier const fdt32_t *fdt_rcc_read_prop(const char *prop_name, int *lenp) 255447b2b13SYann Gautier { 256447b2b13SYann Gautier const fdt32_t *cuint; 257447b2b13SYann Gautier int node, len; 258447b2b13SYann Gautier void *fdt; 259447b2b13SYann Gautier 260447b2b13SYann Gautier if (fdt_get_address(&fdt) == 0) { 261447b2b13SYann Gautier return NULL; 262447b2b13SYann Gautier } 263447b2b13SYann Gautier 264447b2b13SYann Gautier node = fdt_get_rcc_node(fdt); 265447b2b13SYann Gautier if (node < 0) { 266447b2b13SYann Gautier return NULL; 267447b2b13SYann Gautier } 268447b2b13SYann Gautier 269447b2b13SYann Gautier cuint = fdt_getprop(fdt, node, prop_name, &len); 270447b2b13SYann Gautier if (cuint == NULL) { 271447b2b13SYann Gautier return NULL; 272447b2b13SYann Gautier } 273447b2b13SYann Gautier 274447b2b13SYann Gautier *lenp = len; 275447b2b13SYann Gautier return cuint; 276447b2b13SYann Gautier } 277447b2b13SYann Gautier 278447b2b13SYann Gautier /* 279447b2b13SYann Gautier * Get the secure status for rcc node in device tree. 280447b2b13SYann Gautier * @return: true if rcc is available from secure world, false if not. 281447b2b13SYann Gautier */ 282447b2b13SYann Gautier bool fdt_get_rcc_secure_status(void) 283447b2b13SYann Gautier { 284447b2b13SYann Gautier int node; 285447b2b13SYann Gautier void *fdt; 286447b2b13SYann Gautier 287447b2b13SYann Gautier if (fdt_get_address(&fdt) == 0) { 288447b2b13SYann Gautier return false; 289447b2b13SYann Gautier } 290447b2b13SYann Gautier 291447b2b13SYann Gautier node = fdt_get_rcc_node(fdt); 292447b2b13SYann Gautier if (node < 0) { 293447b2b13SYann Gautier return false; 294447b2b13SYann Gautier } 295447b2b13SYann Gautier 296447b2b13SYann Gautier return !!(fdt_get_status(node) & DT_SECURE); 297447b2b13SYann Gautier } 298447b2b13SYann Gautier 299447b2b13SYann Gautier /* 300447b2b13SYann Gautier * Get the stgen base address. 301447b2b13SYann Gautier * @return: address of stgen on success, and NULL value on failure. 302447b2b13SYann Gautier */ 303447b2b13SYann Gautier uintptr_t fdt_get_stgen_base(void) 304447b2b13SYann Gautier { 305447b2b13SYann Gautier int node; 306447b2b13SYann Gautier const fdt32_t *cuint; 307447b2b13SYann Gautier void *fdt; 308447b2b13SYann Gautier 309447b2b13SYann Gautier if (fdt_get_address(&fdt) == 0) { 310447b2b13SYann Gautier return 0; 311447b2b13SYann Gautier } 312447b2b13SYann Gautier 313447b2b13SYann Gautier node = fdt_node_offset_by_compatible(fdt, -1, DT_STGEN_COMPAT); 314447b2b13SYann Gautier if (node < 0) { 315447b2b13SYann Gautier return 0; 316447b2b13SYann Gautier } 317447b2b13SYann Gautier 318447b2b13SYann Gautier cuint = fdt_getprop(fdt, node, "reg", NULL); 319447b2b13SYann Gautier if (cuint == NULL) { 320447b2b13SYann Gautier return 0; 321447b2b13SYann Gautier } 322447b2b13SYann Gautier 323447b2b13SYann Gautier return fdt32_to_cpu(*cuint); 324447b2b13SYann Gautier } 325447b2b13SYann Gautier 326447b2b13SYann Gautier /* 327447b2b13SYann Gautier * Get the clock ID of the given node in device tree. 328447b2b13SYann Gautier * @param node: node offset 329447b2b13SYann Gautier * @return: Clock ID on success, and a negative FDT/ERRNO error code on failure. 330447b2b13SYann Gautier */ 331447b2b13SYann Gautier int fdt_get_clock_id(int node) 332447b2b13SYann Gautier { 333447b2b13SYann Gautier const fdt32_t *cuint; 334447b2b13SYann Gautier void *fdt; 335447b2b13SYann Gautier 336447b2b13SYann Gautier if (fdt_get_address(&fdt) == 0) { 337447b2b13SYann Gautier return -ENOENT; 338447b2b13SYann Gautier } 339447b2b13SYann Gautier 340447b2b13SYann Gautier cuint = fdt_getprop(fdt, node, "clocks", NULL); 341447b2b13SYann Gautier if (cuint == NULL) { 342447b2b13SYann Gautier return -FDT_ERR_NOTFOUND; 343447b2b13SYann Gautier } 344447b2b13SYann Gautier 345447b2b13SYann Gautier cuint++; 346447b2b13SYann Gautier return (int)fdt32_to_cpu(*cuint); 347447b2b13SYann Gautier } 348