1447b2b13SYann Gautier /* 2ba57711cSYann Gautier * Copyright (c) 2017-2021, 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 1352a616b4SAndre Przywara #include <common/fdt_wrappers.h> 14447b2b13SYann Gautier #include <drivers/st/stm32_gpio.h> 15447b2b13SYann Gautier #include <drivers/st/stm32mp_clkfunc.h> 16447b2b13SYann Gautier 17*165ad556SNicolas Le Bayon #define DT_UART_COMPAT "st,stm32h7-uart" 18447b2b13SYann Gautier /* 19f66358afSYann Gautier * Get the frequency of an oscillator from its name in device tree. 20f66358afSYann Gautier * @param name: oscillator name 21f66358afSYann Gautier * @param freq: stores the frequency of the oscillator 22f66358afSYann Gautier * @return: 0 on success, and a negative FDT/ERRNO error code on failure. 23f66358afSYann Gautier */ 24f66358afSYann Gautier int fdt_osc_read_freq(const char *name, uint32_t *freq) 25f66358afSYann Gautier { 26f66358afSYann Gautier int node, subnode; 27f66358afSYann Gautier void *fdt; 28f66358afSYann Gautier 29f66358afSYann Gautier if (fdt_get_address(&fdt) == 0) { 30f66358afSYann Gautier return -ENOENT; 31f66358afSYann Gautier } 32f66358afSYann Gautier 33f66358afSYann Gautier node = fdt_path_offset(fdt, "/clocks"); 34f66358afSYann Gautier if (node < 0) { 35f66358afSYann Gautier return -FDT_ERR_NOTFOUND; 36f66358afSYann Gautier } 37f66358afSYann Gautier 38f66358afSYann Gautier fdt_for_each_subnode(subnode, fdt, node) { 39f66358afSYann Gautier const char *cchar; 40f66358afSYann Gautier int ret; 41f66358afSYann Gautier 42f66358afSYann Gautier cchar = fdt_get_name(fdt, subnode, &ret); 43f66358afSYann Gautier if (cchar == NULL) { 44f66358afSYann Gautier return ret; 45f66358afSYann Gautier } 46f66358afSYann Gautier 47f66358afSYann Gautier if (strncmp(cchar, name, (size_t)ret) == 0) { 48f66358afSYann Gautier const fdt32_t *cuint; 49f66358afSYann Gautier 50f66358afSYann Gautier cuint = fdt_getprop(fdt, subnode, "clock-frequency", 51f66358afSYann Gautier &ret); 52f66358afSYann Gautier if (cuint == NULL) { 53f66358afSYann Gautier return ret; 54f66358afSYann Gautier } 55f66358afSYann Gautier 56f66358afSYann Gautier *freq = fdt32_to_cpu(*cuint); 57f66358afSYann Gautier 58f66358afSYann Gautier return 0; 59f66358afSYann Gautier } 60f66358afSYann Gautier } 61f66358afSYann Gautier 62f66358afSYann Gautier /* Oscillator not found, freq=0 */ 63f66358afSYann Gautier *freq = 0; 64f66358afSYann Gautier return 0; 65f66358afSYann Gautier } 66f66358afSYann Gautier 67f66358afSYann Gautier /* 68f66358afSYann Gautier * Check the presence of an oscillator property from its id. 69f66358afSYann Gautier * @param osc_id: oscillator ID 70f66358afSYann Gautier * @param prop_name: property name 71f66358afSYann Gautier * @return: true/false regarding search result. 72f66358afSYann Gautier */ 73f66358afSYann Gautier bool fdt_osc_read_bool(enum stm32mp_osc_id osc_id, const char *prop_name) 74f66358afSYann Gautier { 75f66358afSYann Gautier int node, subnode; 76f66358afSYann Gautier void *fdt; 77f66358afSYann Gautier 78f66358afSYann Gautier if (fdt_get_address(&fdt) == 0) { 79f66358afSYann Gautier return false; 80f66358afSYann Gautier } 81f66358afSYann Gautier 82f66358afSYann Gautier if (osc_id >= NB_OSC) { 83f66358afSYann Gautier return false; 84f66358afSYann Gautier } 85f66358afSYann Gautier 86f66358afSYann Gautier node = fdt_path_offset(fdt, "/clocks"); 87f66358afSYann Gautier if (node < 0) { 88f66358afSYann Gautier return false; 89f66358afSYann Gautier } 90f66358afSYann Gautier 91f66358afSYann Gautier fdt_for_each_subnode(subnode, fdt, node) { 92f66358afSYann Gautier const char *cchar; 93f66358afSYann Gautier int ret; 94f66358afSYann Gautier 95f66358afSYann Gautier cchar = fdt_get_name(fdt, subnode, &ret); 96f66358afSYann Gautier if (cchar == NULL) { 97f66358afSYann Gautier return false; 98f66358afSYann Gautier } 99f66358afSYann Gautier 100f66358afSYann Gautier if (strncmp(cchar, stm32mp_osc_node_label[osc_id], 101f66358afSYann Gautier (size_t)ret) != 0) { 102f66358afSYann Gautier continue; 103f66358afSYann Gautier } 104f66358afSYann Gautier 105f66358afSYann Gautier if (fdt_getprop(fdt, subnode, prop_name, NULL) != NULL) { 106f66358afSYann Gautier return true; 107f66358afSYann Gautier } 108f66358afSYann Gautier } 109f66358afSYann Gautier 110f66358afSYann Gautier return false; 111f66358afSYann Gautier } 112f66358afSYann Gautier 113f66358afSYann Gautier /* 114f66358afSYann Gautier * Get the value of a oscillator property from its ID. 115f66358afSYann Gautier * @param osc_id: oscillator ID 116f66358afSYann Gautier * @param prop_name: property name 117f66358afSYann Gautier * @param dflt_value: default value 118f66358afSYann Gautier * @return oscillator value on success, default value if property not found. 119f66358afSYann Gautier */ 120f66358afSYann Gautier uint32_t fdt_osc_read_uint32_default(enum stm32mp_osc_id osc_id, 121f66358afSYann Gautier const char *prop_name, uint32_t dflt_value) 122f66358afSYann Gautier { 123f66358afSYann Gautier int node, subnode; 124f66358afSYann Gautier void *fdt; 125f66358afSYann Gautier 126f66358afSYann Gautier if (fdt_get_address(&fdt) == 0) { 127f66358afSYann Gautier return dflt_value; 128f66358afSYann Gautier } 129f66358afSYann Gautier 130f66358afSYann Gautier if (osc_id >= NB_OSC) { 131f66358afSYann Gautier return dflt_value; 132f66358afSYann Gautier } 133f66358afSYann Gautier 134f66358afSYann Gautier node = fdt_path_offset(fdt, "/clocks"); 135f66358afSYann Gautier if (node < 0) { 136f66358afSYann Gautier return dflt_value; 137f66358afSYann Gautier } 138f66358afSYann Gautier 139f66358afSYann Gautier fdt_for_each_subnode(subnode, fdt, node) { 140f66358afSYann Gautier const char *cchar; 141f66358afSYann Gautier int ret; 142f66358afSYann Gautier 143f66358afSYann Gautier cchar = fdt_get_name(fdt, subnode, &ret); 144f66358afSYann Gautier if (cchar == NULL) { 145f66358afSYann Gautier return dflt_value; 146f66358afSYann Gautier } 147f66358afSYann Gautier 148f66358afSYann Gautier if (strncmp(cchar, stm32mp_osc_node_label[osc_id], 149f66358afSYann Gautier (size_t)ret) != 0) { 150f66358afSYann Gautier continue; 151f66358afSYann Gautier } 152f66358afSYann Gautier 153be858cffSAndre Przywara return fdt_read_uint32_default(fdt, subnode, prop_name, 154be858cffSAndre Przywara dflt_value); 155f66358afSYann Gautier } 156f66358afSYann Gautier 157f66358afSYann Gautier return dflt_value; 158f66358afSYann Gautier } 159f66358afSYann Gautier 160f66358afSYann Gautier /* 161447b2b13SYann Gautier * Get the RCC node offset from the device tree 162447b2b13SYann Gautier * @param fdt: Device tree reference 163447b2b13SYann Gautier * @return: Node offset or a negative value on error 164447b2b13SYann Gautier */ 165ff18c4cdSPatrick Delaunay static int fdt_get_rcc_node(void *fdt) 166447b2b13SYann Gautier { 167ba57711cSYann Gautier static int node; 168ba57711cSYann Gautier 169ba57711cSYann Gautier if (node <= 0) { 170ba57711cSYann Gautier node = fdt_node_offset_by_compatible(fdt, -1, DT_RCC_CLK_COMPAT); 171ba57711cSYann Gautier } 172ba57711cSYann Gautier 173ba57711cSYann Gautier return node; 174447b2b13SYann Gautier } 175447b2b13SYann Gautier 176447b2b13SYann Gautier /* 177447b2b13SYann Gautier * Read a series of parameters in rcc-clk section in device tree 178447b2b13SYann Gautier * @param prop_name: Name of the RCC property to be read 179447b2b13SYann Gautier * @param array: the array to store the property parameters 180447b2b13SYann Gautier * @param count: number of parameters to be read 181447b2b13SYann Gautier * @return: 0 on succes or a negative value on error 182447b2b13SYann Gautier */ 18352a616b4SAndre Przywara int fdt_rcc_read_uint32_array(const char *prop_name, uint32_t count, 18452a616b4SAndre Przywara uint32_t *array) 185447b2b13SYann Gautier { 186447b2b13SYann Gautier int node; 187447b2b13SYann Gautier void *fdt; 188447b2b13SYann Gautier 189447b2b13SYann Gautier if (fdt_get_address(&fdt) == 0) { 190447b2b13SYann Gautier return -ENOENT; 191447b2b13SYann Gautier } 192447b2b13SYann Gautier 193447b2b13SYann Gautier node = fdt_get_rcc_node(fdt); 194447b2b13SYann Gautier if (node < 0) { 195447b2b13SYann Gautier return -FDT_ERR_NOTFOUND; 196447b2b13SYann Gautier } 197447b2b13SYann Gautier 19852a616b4SAndre Przywara return fdt_read_uint32_array(fdt, node, prop_name, count, array); 199447b2b13SYann Gautier } 200447b2b13SYann Gautier 201447b2b13SYann Gautier /* 202447b2b13SYann Gautier * Get the subnode offset in rcc-clk section from its name in device tree 203447b2b13SYann Gautier * @param name: name of the RCC property 204447b2b13SYann Gautier * @return: offset on success, and a negative FDT/ERRNO error code on failure. 205447b2b13SYann Gautier */ 206447b2b13SYann Gautier int fdt_rcc_subnode_offset(const char *name) 207447b2b13SYann Gautier { 208447b2b13SYann Gautier int node, subnode; 209447b2b13SYann Gautier void *fdt; 210447b2b13SYann Gautier 211447b2b13SYann Gautier if (fdt_get_address(&fdt) == 0) { 212447b2b13SYann Gautier return -ENOENT; 213447b2b13SYann Gautier } 214447b2b13SYann Gautier 215447b2b13SYann Gautier node = fdt_get_rcc_node(fdt); 216447b2b13SYann Gautier if (node < 0) { 217447b2b13SYann Gautier return -FDT_ERR_NOTFOUND; 218447b2b13SYann Gautier } 219447b2b13SYann Gautier 220447b2b13SYann Gautier subnode = fdt_subnode_offset(fdt, node, name); 221447b2b13SYann Gautier if (subnode <= 0) { 222447b2b13SYann Gautier return -FDT_ERR_NOTFOUND; 223447b2b13SYann Gautier } 224447b2b13SYann Gautier 225447b2b13SYann Gautier return subnode; 226447b2b13SYann Gautier } 227447b2b13SYann Gautier 228447b2b13SYann Gautier /* 229447b2b13SYann Gautier * Get the pointer to a rcc-clk property from its name. 230447b2b13SYann Gautier * @param name: name of the RCC property 231447b2b13SYann Gautier * @param lenp: stores the length of the property. 232447b2b13SYann Gautier * @return: pointer to the property on success, and NULL value on failure. 233447b2b13SYann Gautier */ 234447b2b13SYann Gautier const fdt32_t *fdt_rcc_read_prop(const char *prop_name, int *lenp) 235447b2b13SYann Gautier { 236447b2b13SYann Gautier const fdt32_t *cuint; 237447b2b13SYann Gautier int node, len; 238447b2b13SYann Gautier void *fdt; 239447b2b13SYann Gautier 240447b2b13SYann Gautier if (fdt_get_address(&fdt) == 0) { 241447b2b13SYann Gautier return NULL; 242447b2b13SYann Gautier } 243447b2b13SYann Gautier 244447b2b13SYann Gautier node = fdt_get_rcc_node(fdt); 245447b2b13SYann Gautier if (node < 0) { 246447b2b13SYann Gautier return NULL; 247447b2b13SYann Gautier } 248447b2b13SYann Gautier 249447b2b13SYann Gautier cuint = fdt_getprop(fdt, node, prop_name, &len); 250447b2b13SYann Gautier if (cuint == NULL) { 251447b2b13SYann Gautier return NULL; 252447b2b13SYann Gautier } 253447b2b13SYann Gautier 254447b2b13SYann Gautier *lenp = len; 255447b2b13SYann Gautier return cuint; 256447b2b13SYann Gautier } 257447b2b13SYann Gautier 258447b2b13SYann Gautier /* 259447b2b13SYann Gautier * Get the secure status for rcc node in device tree. 260447b2b13SYann Gautier * @return: true if rcc is available from secure world, false if not. 261447b2b13SYann Gautier */ 262447b2b13SYann Gautier bool fdt_get_rcc_secure_status(void) 263447b2b13SYann Gautier { 264447b2b13SYann Gautier int node; 265447b2b13SYann Gautier void *fdt; 266447b2b13SYann Gautier 267447b2b13SYann Gautier if (fdt_get_address(&fdt) == 0) { 268447b2b13SYann Gautier return false; 269447b2b13SYann Gautier } 270447b2b13SYann Gautier 271447b2b13SYann Gautier node = fdt_get_rcc_node(fdt); 272447b2b13SYann Gautier if (node < 0) { 273447b2b13SYann Gautier return false; 274447b2b13SYann Gautier } 275447b2b13SYann Gautier 276447b2b13SYann Gautier return !!(fdt_get_status(node) & DT_SECURE); 277447b2b13SYann Gautier } 278447b2b13SYann Gautier 279447b2b13SYann Gautier /* 280447b2b13SYann Gautier * Get the clock ID of the given node in device tree. 281447b2b13SYann Gautier * @param node: node offset 282447b2b13SYann Gautier * @return: Clock ID on success, and a negative FDT/ERRNO error code on failure. 283447b2b13SYann Gautier */ 284447b2b13SYann Gautier int fdt_get_clock_id(int node) 285447b2b13SYann Gautier { 286447b2b13SYann Gautier const fdt32_t *cuint; 287447b2b13SYann Gautier void *fdt; 288447b2b13SYann Gautier 289447b2b13SYann Gautier if (fdt_get_address(&fdt) == 0) { 290447b2b13SYann Gautier return -ENOENT; 291447b2b13SYann Gautier } 292447b2b13SYann Gautier 293447b2b13SYann Gautier cuint = fdt_getprop(fdt, node, "clocks", NULL); 294447b2b13SYann Gautier if (cuint == NULL) { 295447b2b13SYann Gautier return -FDT_ERR_NOTFOUND; 296447b2b13SYann Gautier } 297447b2b13SYann Gautier 298447b2b13SYann Gautier cuint++; 299447b2b13SYann Gautier return (int)fdt32_to_cpu(*cuint); 300447b2b13SYann Gautier } 301*165ad556SNicolas Le Bayon 302*165ad556SNicolas Le Bayon /* 303*165ad556SNicolas Le Bayon * Get the frequency of the specified UART instance. 304*165ad556SNicolas Le Bayon * @param instance: UART interface registers base address. 305*165ad556SNicolas Le Bayon * @return: clock frequency on success, 0 value on failure. 306*165ad556SNicolas Le Bayon */ 307*165ad556SNicolas Le Bayon unsigned long fdt_get_uart_clock_freq(uintptr_t instance) 308*165ad556SNicolas Le Bayon { 309*165ad556SNicolas Le Bayon void *fdt; 310*165ad556SNicolas Le Bayon int node; 311*165ad556SNicolas Le Bayon int clk_id; 312*165ad556SNicolas Le Bayon 313*165ad556SNicolas Le Bayon if (fdt_get_address(&fdt) == 0) { 314*165ad556SNicolas Le Bayon return 0UL; 315*165ad556SNicolas Le Bayon } 316*165ad556SNicolas Le Bayon 317*165ad556SNicolas Le Bayon /* Check for UART nodes */ 318*165ad556SNicolas Le Bayon node = dt_match_instance_by_compatible(DT_UART_COMPAT, instance); 319*165ad556SNicolas Le Bayon if (node < 0) { 320*165ad556SNicolas Le Bayon return 0UL; 321*165ad556SNicolas Le Bayon } 322*165ad556SNicolas Le Bayon 323*165ad556SNicolas Le Bayon clk_id = fdt_get_clock_id(node); 324*165ad556SNicolas Le Bayon if (clk_id < 0) { 325*165ad556SNicolas Le Bayon return 0UL; 326*165ad556SNicolas Le Bayon } 327*165ad556SNicolas Le Bayon 328*165ad556SNicolas Le Bayon return stm32mp_clk_get_rate((unsigned long)clk_id); 329*165ad556SNicolas Le Bayon } 330