1 /* 2 * Copyright (c) 2017-2022, STMicroelectronics - All Rights Reserved 3 * 4 * SPDX-License-Identifier: BSD-3-Clause 5 */ 6 7 #include <errno.h> 8 9 #include <common/fdt_wrappers.h> 10 #include <drivers/clk.h> 11 #include <drivers/st/stm32_gpio.h> 12 #include <drivers/st/stm32mp_clkfunc.h> 13 #include <libfdt.h> 14 15 #include <platform_def.h> 16 17 #define DT_UART_COMPAT "st,stm32h7-uart" 18 /* 19 * Get the frequency of an oscillator from its name in device tree. 20 * @param name: oscillator name 21 * @param freq: stores the frequency of the oscillator 22 * @return: 0 on success, and a negative FDT/ERRNO error code on failure. 23 */ 24 int fdt_osc_read_freq(const char *name, uint32_t *freq) 25 { 26 int node, subnode; 27 void *fdt; 28 29 if (fdt_get_address(&fdt) == 0) { 30 return -ENOENT; 31 } 32 33 node = fdt_path_offset(fdt, "/clocks"); 34 if (node < 0) { 35 return -FDT_ERR_NOTFOUND; 36 } 37 38 fdt_for_each_subnode(subnode, fdt, node) { 39 const char *cchar; 40 int ret; 41 42 cchar = fdt_get_name(fdt, subnode, &ret); 43 if (cchar == NULL) { 44 return ret; 45 } 46 47 if ((strncmp(cchar, name, (size_t)ret) == 0) && 48 (fdt_get_status(subnode) != DT_DISABLED)) { 49 const fdt32_t *cuint; 50 51 cuint = fdt_getprop(fdt, subnode, "clock-frequency", 52 &ret); 53 if (cuint == NULL) { 54 return ret; 55 } 56 57 *freq = fdt32_to_cpu(*cuint); 58 59 return 0; 60 } 61 } 62 63 /* Oscillator not found, freq=0 */ 64 *freq = 0; 65 return 0; 66 } 67 68 /* 69 * Check the presence of an oscillator property from its id. 70 * @param node_label: clock node name 71 * @param prop_name: property name 72 * @return: true/false regarding search result. 73 */ 74 bool fdt_clk_read_bool(const char *node_label, const char *prop_name) 75 { 76 int node, subnode; 77 void *fdt; 78 79 if (fdt_get_address(&fdt) == 0) { 80 return false; 81 } 82 83 node = fdt_path_offset(fdt, "/clocks"); 84 if (node < 0) { 85 return false; 86 } 87 88 fdt_for_each_subnode(subnode, fdt, node) { 89 const char *cchar; 90 int ret; 91 92 cchar = fdt_get_name(fdt, subnode, &ret); 93 if (cchar == NULL) { 94 return false; 95 } 96 97 if (strncmp(cchar, node_label, (size_t)ret) != 0) { 98 continue; 99 } 100 101 if (fdt_getprop(fdt, subnode, prop_name, NULL) != NULL) { 102 return true; 103 } 104 } 105 106 return false; 107 } 108 109 /* 110 * Get the value of a oscillator property from its name. 111 * @param node_label: oscillator name 112 * @param prop_name: property name 113 * @param dflt_value: default value 114 * @return oscillator value on success, default value if property not found. 115 */ 116 uint32_t fdt_clk_read_uint32_default(const char *node_label, 117 const char *prop_name, uint32_t dflt_value) 118 { 119 int node, subnode; 120 void *fdt; 121 122 if (fdt_get_address(&fdt) == 0) { 123 return dflt_value; 124 } 125 126 node = fdt_path_offset(fdt, "/clocks"); 127 if (node < 0) { 128 return dflt_value; 129 } 130 131 fdt_for_each_subnode(subnode, fdt, node) { 132 const char *cchar; 133 int ret; 134 135 cchar = fdt_get_name(fdt, subnode, &ret); 136 if (cchar == NULL) { 137 return dflt_value; 138 } 139 140 if (strncmp(cchar, node_label, (size_t)ret) != 0) { 141 continue; 142 } 143 144 return fdt_read_uint32_default(fdt, subnode, prop_name, 145 dflt_value); 146 } 147 148 return dflt_value; 149 } 150 151 /* 152 * Get the RCC node offset from the device tree 153 * @param fdt: Device tree reference 154 * @return: Node offset or a negative value on error 155 */ 156 static int fdt_get_rcc_node(void *fdt) 157 { 158 static int node; 159 160 if (node <= 0) { 161 node = fdt_node_offset_by_compatible(fdt, -1, DT_RCC_CLK_COMPAT); 162 } 163 164 return node; 165 } 166 167 /* 168 * Read a series of parameters in rcc-clk section in device tree 169 * @param prop_name: Name of the RCC property to be read 170 * @param array: the array to store the property parameters 171 * @param count: number of parameters to be read 172 * @return: 0 on succes or a negative value on error 173 */ 174 int fdt_rcc_read_uint32_array(const char *prop_name, uint32_t count, 175 uint32_t *array) 176 { 177 int node; 178 void *fdt; 179 180 if (fdt_get_address(&fdt) == 0) { 181 return -ENOENT; 182 } 183 184 node = fdt_get_rcc_node(fdt); 185 if (node < 0) { 186 return -FDT_ERR_NOTFOUND; 187 } 188 189 return fdt_read_uint32_array(fdt, node, prop_name, count, array); 190 } 191 192 /* 193 * Get the subnode offset in rcc-clk section from its name in device tree 194 * @param name: name of the RCC property 195 * @return: offset on success, and a negative FDT/ERRNO error code on failure. 196 */ 197 int fdt_rcc_subnode_offset(const char *name) 198 { 199 int node, subnode; 200 void *fdt; 201 202 if (fdt_get_address(&fdt) == 0) { 203 return -ENOENT; 204 } 205 206 node = fdt_get_rcc_node(fdt); 207 if (node < 0) { 208 return -FDT_ERR_NOTFOUND; 209 } 210 211 subnode = fdt_subnode_offset(fdt, node, name); 212 if (subnode <= 0) { 213 return -FDT_ERR_NOTFOUND; 214 } 215 216 return subnode; 217 } 218 219 /* 220 * Get the pointer to a rcc-clk property from its name. 221 * @param name: name of the RCC property 222 * @param lenp: stores the length of the property. 223 * @return: pointer to the property on success, and NULL value on failure. 224 */ 225 const fdt32_t *fdt_rcc_read_prop(const char *prop_name, int *lenp) 226 { 227 const fdt32_t *cuint; 228 int node, len; 229 void *fdt; 230 231 if (fdt_get_address(&fdt) == 0) { 232 return NULL; 233 } 234 235 node = fdt_get_rcc_node(fdt); 236 if (node < 0) { 237 return NULL; 238 } 239 240 cuint = fdt_getprop(fdt, node, prop_name, &len); 241 if (cuint == NULL) { 242 return NULL; 243 } 244 245 *lenp = len; 246 return cuint; 247 } 248 249 /* 250 * Get the secure status for rcc node in device tree. 251 * @return: true if rcc is available from secure world, false if not. 252 */ 253 bool fdt_get_rcc_secure_status(void) 254 { 255 int node; 256 void *fdt; 257 258 if (fdt_get_address(&fdt) == 0) { 259 return false; 260 } 261 262 node = fdt_get_rcc_node(fdt); 263 if (node < 0) { 264 return false; 265 } 266 267 return !!(fdt_get_status(node) & DT_SECURE); 268 } 269 270 /* 271 * Get the clock ID of the given node in device tree. 272 * @param node: node offset 273 * @return: Clock ID on success, and a negative FDT/ERRNO error code on failure. 274 */ 275 int fdt_get_clock_id(int node) 276 { 277 const fdt32_t *cuint; 278 void *fdt; 279 280 if (fdt_get_address(&fdt) == 0) { 281 return -ENOENT; 282 } 283 284 cuint = fdt_getprop(fdt, node, "clocks", NULL); 285 if (cuint == NULL) { 286 return -FDT_ERR_NOTFOUND; 287 } 288 289 cuint++; 290 return (int)fdt32_to_cpu(*cuint); 291 } 292 293 /* 294 * Get the frequency of the specified UART instance. 295 * @param instance: UART interface registers base address. 296 * @return: clock frequency on success, 0 value on failure. 297 */ 298 unsigned long fdt_get_uart_clock_freq(uintptr_t instance) 299 { 300 void *fdt; 301 int node; 302 int clk_id; 303 304 if (fdt_get_address(&fdt) == 0) { 305 return 0UL; 306 } 307 308 /* Check for UART nodes */ 309 node = dt_match_instance_by_compatible(DT_UART_COMPAT, instance); 310 if (node < 0) { 311 return 0UL; 312 } 313 314 clk_id = fdt_get_clock_id(node); 315 if (clk_id < 0) { 316 return 0UL; 317 } 318 319 return clk_get_rate((unsigned long)clk_id); 320 } 321