1447b2b13SYann Gautier /* 2ade9ce03SYann Gautier * Copyright (c) 2017-2020, 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 17447b2b13SYann Gautier /* 18f66358afSYann Gautier * Get the frequency of an oscillator from its name in device tree. 19f66358afSYann Gautier * @param name: oscillator name 20f66358afSYann Gautier * @param freq: stores the frequency of the oscillator 21f66358afSYann Gautier * @return: 0 on success, and a negative FDT/ERRNO error code on failure. 22f66358afSYann Gautier */ 23f66358afSYann Gautier int fdt_osc_read_freq(const char *name, uint32_t *freq) 24f66358afSYann Gautier { 25f66358afSYann Gautier int node, subnode; 26f66358afSYann Gautier void *fdt; 27f66358afSYann Gautier 28f66358afSYann Gautier if (fdt_get_address(&fdt) == 0) { 29f66358afSYann Gautier return -ENOENT; 30f66358afSYann Gautier } 31f66358afSYann Gautier 32f66358afSYann Gautier node = fdt_path_offset(fdt, "/clocks"); 33f66358afSYann Gautier if (node < 0) { 34f66358afSYann Gautier return -FDT_ERR_NOTFOUND; 35f66358afSYann Gautier } 36f66358afSYann Gautier 37f66358afSYann Gautier fdt_for_each_subnode(subnode, fdt, node) { 38f66358afSYann Gautier const char *cchar; 39f66358afSYann Gautier int ret; 40f66358afSYann Gautier 41f66358afSYann Gautier cchar = fdt_get_name(fdt, subnode, &ret); 42f66358afSYann Gautier if (cchar == NULL) { 43f66358afSYann Gautier return ret; 44f66358afSYann Gautier } 45f66358afSYann Gautier 46f66358afSYann Gautier if (strncmp(cchar, name, (size_t)ret) == 0) { 47f66358afSYann Gautier const fdt32_t *cuint; 48f66358afSYann Gautier 49f66358afSYann Gautier cuint = fdt_getprop(fdt, subnode, "clock-frequency", 50f66358afSYann Gautier &ret); 51f66358afSYann Gautier if (cuint == NULL) { 52f66358afSYann Gautier return ret; 53f66358afSYann Gautier } 54f66358afSYann Gautier 55f66358afSYann Gautier *freq = fdt32_to_cpu(*cuint); 56f66358afSYann Gautier 57f66358afSYann Gautier return 0; 58f66358afSYann Gautier } 59f66358afSYann Gautier } 60f66358afSYann Gautier 61f66358afSYann Gautier /* Oscillator not found, freq=0 */ 62f66358afSYann Gautier *freq = 0; 63f66358afSYann Gautier return 0; 64f66358afSYann Gautier } 65f66358afSYann Gautier 66f66358afSYann Gautier /* 67f66358afSYann Gautier * Check the presence of an oscillator property from its id. 68f66358afSYann Gautier * @param osc_id: oscillator ID 69f66358afSYann Gautier * @param prop_name: property name 70f66358afSYann Gautier * @return: true/false regarding search result. 71f66358afSYann Gautier */ 72f66358afSYann Gautier bool fdt_osc_read_bool(enum stm32mp_osc_id osc_id, const char *prop_name) 73f66358afSYann Gautier { 74f66358afSYann Gautier int node, subnode; 75f66358afSYann Gautier void *fdt; 76f66358afSYann Gautier 77f66358afSYann Gautier if (fdt_get_address(&fdt) == 0) { 78f66358afSYann Gautier return false; 79f66358afSYann Gautier } 80f66358afSYann Gautier 81f66358afSYann Gautier if (osc_id >= NB_OSC) { 82f66358afSYann Gautier return false; 83f66358afSYann Gautier } 84f66358afSYann Gautier 85f66358afSYann Gautier node = fdt_path_offset(fdt, "/clocks"); 86f66358afSYann Gautier if (node < 0) { 87f66358afSYann Gautier return false; 88f66358afSYann Gautier } 89f66358afSYann Gautier 90f66358afSYann Gautier fdt_for_each_subnode(subnode, fdt, node) { 91f66358afSYann Gautier const char *cchar; 92f66358afSYann Gautier int ret; 93f66358afSYann Gautier 94f66358afSYann Gautier cchar = fdt_get_name(fdt, subnode, &ret); 95f66358afSYann Gautier if (cchar == NULL) { 96f66358afSYann Gautier return false; 97f66358afSYann Gautier } 98f66358afSYann Gautier 99f66358afSYann Gautier if (strncmp(cchar, stm32mp_osc_node_label[osc_id], 100f66358afSYann Gautier (size_t)ret) != 0) { 101f66358afSYann Gautier continue; 102f66358afSYann Gautier } 103f66358afSYann Gautier 104f66358afSYann Gautier if (fdt_getprop(fdt, subnode, prop_name, NULL) != NULL) { 105f66358afSYann Gautier return true; 106f66358afSYann Gautier } 107f66358afSYann Gautier } 108f66358afSYann Gautier 109f66358afSYann Gautier return false; 110f66358afSYann Gautier } 111f66358afSYann Gautier 112f66358afSYann Gautier /* 113f66358afSYann Gautier * Get the value of a oscillator property from its ID. 114f66358afSYann Gautier * @param osc_id: oscillator ID 115f66358afSYann Gautier * @param prop_name: property name 116f66358afSYann Gautier * @param dflt_value: default value 117f66358afSYann Gautier * @return oscillator value on success, default value if property not found. 118f66358afSYann Gautier */ 119f66358afSYann Gautier uint32_t fdt_osc_read_uint32_default(enum stm32mp_osc_id osc_id, 120f66358afSYann Gautier const char *prop_name, uint32_t dflt_value) 121f66358afSYann Gautier { 122f66358afSYann Gautier int node, subnode; 123f66358afSYann Gautier void *fdt; 124f66358afSYann Gautier 125f66358afSYann Gautier if (fdt_get_address(&fdt) == 0) { 126f66358afSYann Gautier return dflt_value; 127f66358afSYann Gautier } 128f66358afSYann Gautier 129f66358afSYann Gautier if (osc_id >= NB_OSC) { 130f66358afSYann Gautier return dflt_value; 131f66358afSYann Gautier } 132f66358afSYann Gautier 133f66358afSYann Gautier node = fdt_path_offset(fdt, "/clocks"); 134f66358afSYann Gautier if (node < 0) { 135f66358afSYann Gautier return dflt_value; 136f66358afSYann Gautier } 137f66358afSYann Gautier 138f66358afSYann Gautier fdt_for_each_subnode(subnode, fdt, node) { 139f66358afSYann Gautier const char *cchar; 140f66358afSYann Gautier int ret; 141f66358afSYann Gautier 142f66358afSYann Gautier cchar = fdt_get_name(fdt, subnode, &ret); 143f66358afSYann Gautier if (cchar == NULL) { 144f66358afSYann Gautier return dflt_value; 145f66358afSYann Gautier } 146f66358afSYann Gautier 147f66358afSYann Gautier if (strncmp(cchar, stm32mp_osc_node_label[osc_id], 148f66358afSYann Gautier (size_t)ret) != 0) { 149f66358afSYann Gautier continue; 150f66358afSYann Gautier } 151f66358afSYann Gautier 152be858cffSAndre Przywara return fdt_read_uint32_default(fdt, subnode, prop_name, 153be858cffSAndre Przywara dflt_value); 154f66358afSYann Gautier } 155f66358afSYann Gautier 156f66358afSYann Gautier return dflt_value; 157f66358afSYann Gautier } 158f66358afSYann Gautier 159f66358afSYann 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 */ 164*ff18c4cdSPatrick Delaunay static 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 * Read a series of parameters in rcc-clk section in device tree 171447b2b13SYann Gautier * @param prop_name: Name of the RCC property to be read 172447b2b13SYann Gautier * @param array: the array to store the property parameters 173447b2b13SYann Gautier * @param count: number of parameters to be read 174447b2b13SYann Gautier * @return: 0 on succes or a negative value on error 175447b2b13SYann Gautier */ 17652a616b4SAndre Przywara int fdt_rcc_read_uint32_array(const char *prop_name, uint32_t count, 17752a616b4SAndre Przywara uint32_t *array) 178447b2b13SYann Gautier { 179447b2b13SYann Gautier int node; 180447b2b13SYann Gautier void *fdt; 181447b2b13SYann Gautier 182447b2b13SYann Gautier if (fdt_get_address(&fdt) == 0) { 183447b2b13SYann Gautier return -ENOENT; 184447b2b13SYann Gautier } 185447b2b13SYann Gautier 186447b2b13SYann Gautier node = fdt_get_rcc_node(fdt); 187447b2b13SYann Gautier if (node < 0) { 188447b2b13SYann Gautier return -FDT_ERR_NOTFOUND; 189447b2b13SYann Gautier } 190447b2b13SYann Gautier 19152a616b4SAndre Przywara return fdt_read_uint32_array(fdt, node, prop_name, count, array); 192447b2b13SYann Gautier } 193447b2b13SYann Gautier 194447b2b13SYann Gautier /* 195447b2b13SYann Gautier * Get the subnode offset in rcc-clk section from its name in device tree 196447b2b13SYann Gautier * @param name: name of the RCC property 197447b2b13SYann Gautier * @return: offset on success, and a negative FDT/ERRNO error code on failure. 198447b2b13SYann Gautier */ 199447b2b13SYann Gautier int fdt_rcc_subnode_offset(const char *name) 200447b2b13SYann Gautier { 201447b2b13SYann Gautier int node, subnode; 202447b2b13SYann Gautier void *fdt; 203447b2b13SYann Gautier 204447b2b13SYann Gautier if (fdt_get_address(&fdt) == 0) { 205447b2b13SYann Gautier return -ENOENT; 206447b2b13SYann Gautier } 207447b2b13SYann Gautier 208447b2b13SYann Gautier node = fdt_get_rcc_node(fdt); 209447b2b13SYann Gautier if (node < 0) { 210447b2b13SYann Gautier return -FDT_ERR_NOTFOUND; 211447b2b13SYann Gautier } 212447b2b13SYann Gautier 213447b2b13SYann Gautier subnode = fdt_subnode_offset(fdt, node, name); 214447b2b13SYann Gautier if (subnode <= 0) { 215447b2b13SYann Gautier return -FDT_ERR_NOTFOUND; 216447b2b13SYann Gautier } 217447b2b13SYann Gautier 218447b2b13SYann Gautier return subnode; 219447b2b13SYann Gautier } 220447b2b13SYann Gautier 221447b2b13SYann Gautier /* 222447b2b13SYann Gautier * Get the pointer to a rcc-clk property from its name. 223447b2b13SYann Gautier * @param name: name of the RCC property 224447b2b13SYann Gautier * @param lenp: stores the length of the property. 225447b2b13SYann Gautier * @return: pointer to the property on success, and NULL value on failure. 226447b2b13SYann Gautier */ 227447b2b13SYann Gautier const fdt32_t *fdt_rcc_read_prop(const char *prop_name, int *lenp) 228447b2b13SYann Gautier { 229447b2b13SYann Gautier const fdt32_t *cuint; 230447b2b13SYann Gautier int node, len; 231447b2b13SYann Gautier void *fdt; 232447b2b13SYann Gautier 233447b2b13SYann Gautier if (fdt_get_address(&fdt) == 0) { 234447b2b13SYann Gautier return NULL; 235447b2b13SYann Gautier } 236447b2b13SYann Gautier 237447b2b13SYann Gautier node = fdt_get_rcc_node(fdt); 238447b2b13SYann Gautier if (node < 0) { 239447b2b13SYann Gautier return NULL; 240447b2b13SYann Gautier } 241447b2b13SYann Gautier 242447b2b13SYann Gautier cuint = fdt_getprop(fdt, node, prop_name, &len); 243447b2b13SYann Gautier if (cuint == NULL) { 244447b2b13SYann Gautier return NULL; 245447b2b13SYann Gautier } 246447b2b13SYann Gautier 247447b2b13SYann Gautier *lenp = len; 248447b2b13SYann Gautier return cuint; 249447b2b13SYann Gautier } 250447b2b13SYann Gautier 251447b2b13SYann Gautier /* 252447b2b13SYann Gautier * Get the secure status for rcc node in device tree. 253447b2b13SYann Gautier * @return: true if rcc is available from secure world, false if not. 254447b2b13SYann Gautier */ 255447b2b13SYann Gautier bool fdt_get_rcc_secure_status(void) 256447b2b13SYann Gautier { 257447b2b13SYann Gautier int node; 258447b2b13SYann Gautier void *fdt; 259447b2b13SYann Gautier 260447b2b13SYann Gautier if (fdt_get_address(&fdt) == 0) { 261447b2b13SYann Gautier return false; 262447b2b13SYann Gautier } 263447b2b13SYann Gautier 264447b2b13SYann Gautier node = fdt_get_rcc_node(fdt); 265447b2b13SYann Gautier if (node < 0) { 266447b2b13SYann Gautier return false; 267447b2b13SYann Gautier } 268447b2b13SYann Gautier 269447b2b13SYann Gautier return !!(fdt_get_status(node) & DT_SECURE); 270447b2b13SYann Gautier } 271447b2b13SYann Gautier 272447b2b13SYann Gautier /* 273447b2b13SYann Gautier * Get the clock ID of the given node in device tree. 274447b2b13SYann Gautier * @param node: node offset 275447b2b13SYann Gautier * @return: Clock ID on success, and a negative FDT/ERRNO error code on failure. 276447b2b13SYann Gautier */ 277447b2b13SYann Gautier int fdt_get_clock_id(int node) 278447b2b13SYann Gautier { 279447b2b13SYann Gautier const fdt32_t *cuint; 280447b2b13SYann Gautier void *fdt; 281447b2b13SYann Gautier 282447b2b13SYann Gautier if (fdt_get_address(&fdt) == 0) { 283447b2b13SYann Gautier return -ENOENT; 284447b2b13SYann Gautier } 285447b2b13SYann Gautier 286447b2b13SYann Gautier cuint = fdt_getprop(fdt, node, "clocks", NULL); 287447b2b13SYann Gautier if (cuint == NULL) { 288447b2b13SYann Gautier return -FDT_ERR_NOTFOUND; 289447b2b13SYann Gautier } 290447b2b13SYann Gautier 291447b2b13SYann Gautier cuint++; 292447b2b13SYann Gautier return (int)fdt32_to_cpu(*cuint); 293447b2b13SYann Gautier } 294