1447b2b13SYann Gautier /* 2bcccdaccSPatrick Delaunay * Copyright (c) 2017-2022, 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 952a616b4SAndre Przywara #include <common/fdt_wrappers.h> 1033667d29SYann Gautier #include <drivers/clk.h> 11447b2b13SYann Gautier #include <drivers/st/stm32_gpio.h> 12447b2b13SYann Gautier #include <drivers/st/stm32mp_clkfunc.h> 13bcccdaccSPatrick Delaunay #include <libfdt.h> 14bcccdaccSPatrick Delaunay 15bcccdaccSPatrick Delaunay #include <platform_def.h> 16447b2b13SYann Gautier 17165ad556SNicolas 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 47bcccdaccSPatrick Delaunay if ((strncmp(cchar, name, (size_t)ret) == 0) && 48bcccdaccSPatrick Delaunay (fdt_get_status(subnode) != DT_DISABLED)) { 49f66358afSYann Gautier const fdt32_t *cuint; 50f66358afSYann Gautier 51f66358afSYann Gautier cuint = fdt_getprop(fdt, subnode, "clock-frequency", 52f66358afSYann Gautier &ret); 53f66358afSYann Gautier if (cuint == NULL) { 54f66358afSYann Gautier return ret; 55f66358afSYann Gautier } 56f66358afSYann Gautier 57f66358afSYann Gautier *freq = fdt32_to_cpu(*cuint); 58f66358afSYann Gautier 59f66358afSYann Gautier return 0; 60f66358afSYann Gautier } 61f66358afSYann Gautier } 62f66358afSYann Gautier 63f66358afSYann Gautier /* Oscillator not found, freq=0 */ 64f66358afSYann Gautier *freq = 0; 65f66358afSYann Gautier return 0; 66f66358afSYann Gautier } 67f66358afSYann Gautier 68f66358afSYann Gautier /* 69f66358afSYann Gautier * Check the presence of an oscillator property from its id. 70*b208e3daSGabriel Fernandez * @param node_label: clock node name 71f66358afSYann Gautier * @param prop_name: property name 72f66358afSYann Gautier * @return: true/false regarding search result. 73f66358afSYann Gautier */ 74*b208e3daSGabriel Fernandez bool fdt_clk_read_bool(const char *node_label, const char *prop_name) 75f66358afSYann Gautier { 76f66358afSYann Gautier int node, subnode; 77f66358afSYann Gautier void *fdt; 78f66358afSYann Gautier 79f66358afSYann Gautier if (fdt_get_address(&fdt) == 0) { 80f66358afSYann Gautier return false; 81f66358afSYann Gautier } 82f66358afSYann Gautier 83f66358afSYann Gautier node = fdt_path_offset(fdt, "/clocks"); 84f66358afSYann Gautier if (node < 0) { 85f66358afSYann Gautier return false; 86f66358afSYann Gautier } 87f66358afSYann Gautier 88f66358afSYann Gautier fdt_for_each_subnode(subnode, fdt, node) { 89f66358afSYann Gautier const char *cchar; 90f66358afSYann Gautier int ret; 91f66358afSYann Gautier 92f66358afSYann Gautier cchar = fdt_get_name(fdt, subnode, &ret); 93f66358afSYann Gautier if (cchar == NULL) { 94f66358afSYann Gautier return false; 95f66358afSYann Gautier } 96f66358afSYann Gautier 97*b208e3daSGabriel Fernandez if (strncmp(cchar, node_label, (size_t)ret) != 0) { 98f66358afSYann Gautier continue; 99f66358afSYann Gautier } 100f66358afSYann Gautier 101f66358afSYann Gautier if (fdt_getprop(fdt, subnode, prop_name, NULL) != NULL) { 102f66358afSYann Gautier return true; 103f66358afSYann Gautier } 104f66358afSYann Gautier } 105f66358afSYann Gautier 106f66358afSYann Gautier return false; 107f66358afSYann Gautier } 108f66358afSYann Gautier 109f66358afSYann Gautier /* 110*b208e3daSGabriel Fernandez * Get the value of a oscillator property from its name. 111*b208e3daSGabriel Fernandez * @param node_label: oscillator name 112f66358afSYann Gautier * @param prop_name: property name 113f66358afSYann Gautier * @param dflt_value: default value 114f66358afSYann Gautier * @return oscillator value on success, default value if property not found. 115f66358afSYann Gautier */ 116*b208e3daSGabriel Fernandez uint32_t fdt_clk_read_uint32_default(const char *node_label, 117f66358afSYann Gautier const char *prop_name, uint32_t dflt_value) 118f66358afSYann Gautier { 119f66358afSYann Gautier int node, subnode; 120f66358afSYann Gautier void *fdt; 121f66358afSYann Gautier 122f66358afSYann Gautier if (fdt_get_address(&fdt) == 0) { 123f66358afSYann Gautier return dflt_value; 124f66358afSYann Gautier } 125f66358afSYann Gautier 126f66358afSYann Gautier node = fdt_path_offset(fdt, "/clocks"); 127f66358afSYann Gautier if (node < 0) { 128f66358afSYann Gautier return dflt_value; 129f66358afSYann Gautier } 130f66358afSYann Gautier 131f66358afSYann Gautier fdt_for_each_subnode(subnode, fdt, node) { 132f66358afSYann Gautier const char *cchar; 133f66358afSYann Gautier int ret; 134f66358afSYann Gautier 135f66358afSYann Gautier cchar = fdt_get_name(fdt, subnode, &ret); 136f66358afSYann Gautier if (cchar == NULL) { 137f66358afSYann Gautier return dflt_value; 138f66358afSYann Gautier } 139f66358afSYann Gautier 140*b208e3daSGabriel Fernandez if (strncmp(cchar, node_label, (size_t)ret) != 0) { 141f66358afSYann Gautier continue; 142f66358afSYann Gautier } 143f66358afSYann Gautier 144be858cffSAndre Przywara return fdt_read_uint32_default(fdt, subnode, prop_name, 145be858cffSAndre Przywara dflt_value); 146f66358afSYann Gautier } 147f66358afSYann Gautier 148f66358afSYann Gautier return dflt_value; 149f66358afSYann Gautier } 150f66358afSYann Gautier 151f66358afSYann Gautier /* 152447b2b13SYann Gautier * Get the RCC node offset from the device tree 153447b2b13SYann Gautier * @param fdt: Device tree reference 154447b2b13SYann Gautier * @return: Node offset or a negative value on error 155447b2b13SYann Gautier */ 156ff18c4cdSPatrick Delaunay static int fdt_get_rcc_node(void *fdt) 157447b2b13SYann Gautier { 158ba57711cSYann Gautier static int node; 159ba57711cSYann Gautier 160ba57711cSYann Gautier if (node <= 0) { 161ba57711cSYann Gautier node = fdt_node_offset_by_compatible(fdt, -1, DT_RCC_CLK_COMPAT); 162ba57711cSYann Gautier } 163ba57711cSYann Gautier 164ba57711cSYann Gautier return node; 165447b2b13SYann Gautier } 166447b2b13SYann Gautier 167447b2b13SYann Gautier /* 168447b2b13SYann Gautier * Read a series of parameters in rcc-clk section in device tree 169447b2b13SYann Gautier * @param prop_name: Name of the RCC property to be read 170447b2b13SYann Gautier * @param array: the array to store the property parameters 171447b2b13SYann Gautier * @param count: number of parameters to be read 172447b2b13SYann Gautier * @return: 0 on succes or a negative value on error 173447b2b13SYann Gautier */ 17452a616b4SAndre Przywara int fdt_rcc_read_uint32_array(const char *prop_name, uint32_t count, 17552a616b4SAndre Przywara uint32_t *array) 176447b2b13SYann Gautier { 177447b2b13SYann Gautier int node; 178447b2b13SYann Gautier void *fdt; 179447b2b13SYann Gautier 180447b2b13SYann Gautier if (fdt_get_address(&fdt) == 0) { 181447b2b13SYann Gautier return -ENOENT; 182447b2b13SYann Gautier } 183447b2b13SYann Gautier 184447b2b13SYann Gautier node = fdt_get_rcc_node(fdt); 185447b2b13SYann Gautier if (node < 0) { 186447b2b13SYann Gautier return -FDT_ERR_NOTFOUND; 187447b2b13SYann Gautier } 188447b2b13SYann Gautier 18952a616b4SAndre Przywara return fdt_read_uint32_array(fdt, node, prop_name, count, array); 190447b2b13SYann Gautier } 191447b2b13SYann Gautier 192447b2b13SYann Gautier /* 193447b2b13SYann Gautier * Get the subnode offset in rcc-clk section from its name in device tree 194447b2b13SYann Gautier * @param name: name of the RCC property 195447b2b13SYann Gautier * @return: offset on success, and a negative FDT/ERRNO error code on failure. 196447b2b13SYann Gautier */ 197447b2b13SYann Gautier int fdt_rcc_subnode_offset(const char *name) 198447b2b13SYann Gautier { 199447b2b13SYann Gautier int node, subnode; 200447b2b13SYann Gautier void *fdt; 201447b2b13SYann Gautier 202447b2b13SYann Gautier if (fdt_get_address(&fdt) == 0) { 203447b2b13SYann Gautier return -ENOENT; 204447b2b13SYann Gautier } 205447b2b13SYann Gautier 206447b2b13SYann Gautier node = fdt_get_rcc_node(fdt); 207447b2b13SYann Gautier if (node < 0) { 208447b2b13SYann Gautier return -FDT_ERR_NOTFOUND; 209447b2b13SYann Gautier } 210447b2b13SYann Gautier 211447b2b13SYann Gautier subnode = fdt_subnode_offset(fdt, node, name); 212447b2b13SYann Gautier if (subnode <= 0) { 213447b2b13SYann Gautier return -FDT_ERR_NOTFOUND; 214447b2b13SYann Gautier } 215447b2b13SYann Gautier 216447b2b13SYann Gautier return subnode; 217447b2b13SYann Gautier } 218447b2b13SYann Gautier 219447b2b13SYann Gautier /* 220447b2b13SYann Gautier * Get the pointer to a rcc-clk property from its name. 221447b2b13SYann Gautier * @param name: name of the RCC property 222447b2b13SYann Gautier * @param lenp: stores the length of the property. 223447b2b13SYann Gautier * @return: pointer to the property on success, and NULL value on failure. 224447b2b13SYann Gautier */ 225447b2b13SYann Gautier const fdt32_t *fdt_rcc_read_prop(const char *prop_name, int *lenp) 226447b2b13SYann Gautier { 227447b2b13SYann Gautier const fdt32_t *cuint; 228447b2b13SYann Gautier int node, len; 229447b2b13SYann Gautier void *fdt; 230447b2b13SYann Gautier 231447b2b13SYann Gautier if (fdt_get_address(&fdt) == 0) { 232447b2b13SYann Gautier return NULL; 233447b2b13SYann Gautier } 234447b2b13SYann Gautier 235447b2b13SYann Gautier node = fdt_get_rcc_node(fdt); 236447b2b13SYann Gautier if (node < 0) { 237447b2b13SYann Gautier return NULL; 238447b2b13SYann Gautier } 239447b2b13SYann Gautier 240447b2b13SYann Gautier cuint = fdt_getprop(fdt, node, prop_name, &len); 241447b2b13SYann Gautier if (cuint == NULL) { 242447b2b13SYann Gautier return NULL; 243447b2b13SYann Gautier } 244447b2b13SYann Gautier 245447b2b13SYann Gautier *lenp = len; 246447b2b13SYann Gautier return cuint; 247447b2b13SYann Gautier } 248447b2b13SYann Gautier 249447b2b13SYann Gautier /* 250447b2b13SYann Gautier * Get the secure status for rcc node in device tree. 251447b2b13SYann Gautier * @return: true if rcc is available from secure world, false if not. 252447b2b13SYann Gautier */ 253447b2b13SYann Gautier bool fdt_get_rcc_secure_status(void) 254447b2b13SYann Gautier { 255447b2b13SYann Gautier int node; 256447b2b13SYann Gautier void *fdt; 257447b2b13SYann Gautier 258447b2b13SYann Gautier if (fdt_get_address(&fdt) == 0) { 259447b2b13SYann Gautier return false; 260447b2b13SYann Gautier } 261447b2b13SYann Gautier 262447b2b13SYann Gautier node = fdt_get_rcc_node(fdt); 263447b2b13SYann Gautier if (node < 0) { 264447b2b13SYann Gautier return false; 265447b2b13SYann Gautier } 266447b2b13SYann Gautier 267447b2b13SYann Gautier return !!(fdt_get_status(node) & DT_SECURE); 268447b2b13SYann Gautier } 269447b2b13SYann Gautier 270447b2b13SYann Gautier /* 271447b2b13SYann Gautier * Get the clock ID of the given node in device tree. 272447b2b13SYann Gautier * @param node: node offset 273447b2b13SYann Gautier * @return: Clock ID on success, and a negative FDT/ERRNO error code on failure. 274447b2b13SYann Gautier */ 275447b2b13SYann Gautier int fdt_get_clock_id(int node) 276447b2b13SYann Gautier { 277447b2b13SYann Gautier const fdt32_t *cuint; 278447b2b13SYann Gautier void *fdt; 279447b2b13SYann Gautier 280447b2b13SYann Gautier if (fdt_get_address(&fdt) == 0) { 281447b2b13SYann Gautier return -ENOENT; 282447b2b13SYann Gautier } 283447b2b13SYann Gautier 284447b2b13SYann Gautier cuint = fdt_getprop(fdt, node, "clocks", NULL); 285447b2b13SYann Gautier if (cuint == NULL) { 286447b2b13SYann Gautier return -FDT_ERR_NOTFOUND; 287447b2b13SYann Gautier } 288447b2b13SYann Gautier 289447b2b13SYann Gautier cuint++; 290447b2b13SYann Gautier return (int)fdt32_to_cpu(*cuint); 291447b2b13SYann Gautier } 292165ad556SNicolas Le Bayon 293165ad556SNicolas Le Bayon /* 294165ad556SNicolas Le Bayon * Get the frequency of the specified UART instance. 295165ad556SNicolas Le Bayon * @param instance: UART interface registers base address. 296165ad556SNicolas Le Bayon * @return: clock frequency on success, 0 value on failure. 297165ad556SNicolas Le Bayon */ 298165ad556SNicolas Le Bayon unsigned long fdt_get_uart_clock_freq(uintptr_t instance) 299165ad556SNicolas Le Bayon { 300165ad556SNicolas Le Bayon void *fdt; 301165ad556SNicolas Le Bayon int node; 302165ad556SNicolas Le Bayon int clk_id; 303165ad556SNicolas Le Bayon 304165ad556SNicolas Le Bayon if (fdt_get_address(&fdt) == 0) { 305165ad556SNicolas Le Bayon return 0UL; 306165ad556SNicolas Le Bayon } 307165ad556SNicolas Le Bayon 308165ad556SNicolas Le Bayon /* Check for UART nodes */ 309165ad556SNicolas Le Bayon node = dt_match_instance_by_compatible(DT_UART_COMPAT, instance); 310165ad556SNicolas Le Bayon if (node < 0) { 311165ad556SNicolas Le Bayon return 0UL; 312165ad556SNicolas Le Bayon } 313165ad556SNicolas Le Bayon 314165ad556SNicolas Le Bayon clk_id = fdt_get_clock_id(node); 315165ad556SNicolas Le Bayon if (clk_id < 0) { 316165ad556SNicolas Le Bayon return 0UL; 317165ad556SNicolas Le Bayon } 318165ad556SNicolas Le Bayon 31933667d29SYann Gautier return clk_get_rate((unsigned long)clk_id); 320165ad556SNicolas Le Bayon } 321