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 osc_id: oscillator ID 71 * @param prop_name: property name 72 * @return: true/false regarding search result. 73 */ 74 bool fdt_osc_read_bool(enum stm32mp_osc_id osc_id, 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 if (osc_id >= NB_OSC) { 84 return false; 85 } 86 87 node = fdt_path_offset(fdt, "/clocks"); 88 if (node < 0) { 89 return false; 90 } 91 92 fdt_for_each_subnode(subnode, fdt, node) { 93 const char *cchar; 94 int ret; 95 96 cchar = fdt_get_name(fdt, subnode, &ret); 97 if (cchar == NULL) { 98 return false; 99 } 100 101 if (strncmp(cchar, stm32mp_osc_node_label[osc_id], 102 (size_t)ret) != 0) { 103 continue; 104 } 105 106 if (fdt_getprop(fdt, subnode, prop_name, NULL) != NULL) { 107 return true; 108 } 109 } 110 111 return false; 112 } 113 114 /* 115 * Get the value of a oscillator property from its ID. 116 * @param osc_id: oscillator ID 117 * @param prop_name: property name 118 * @param dflt_value: default value 119 * @return oscillator value on success, default value if property not found. 120 */ 121 uint32_t fdt_osc_read_uint32_default(enum stm32mp_osc_id osc_id, 122 const char *prop_name, uint32_t dflt_value) 123 { 124 int node, subnode; 125 void *fdt; 126 127 if (fdt_get_address(&fdt) == 0) { 128 return dflt_value; 129 } 130 131 if (osc_id >= NB_OSC) { 132 return dflt_value; 133 } 134 135 node = fdt_path_offset(fdt, "/clocks"); 136 if (node < 0) { 137 return dflt_value; 138 } 139 140 fdt_for_each_subnode(subnode, fdt, node) { 141 const char *cchar; 142 int ret; 143 144 cchar = fdt_get_name(fdt, subnode, &ret); 145 if (cchar == NULL) { 146 return dflt_value; 147 } 148 149 if (strncmp(cchar, stm32mp_osc_node_label[osc_id], 150 (size_t)ret) != 0) { 151 continue; 152 } 153 154 return fdt_read_uint32_default(fdt, subnode, prop_name, 155 dflt_value); 156 } 157 158 return dflt_value; 159 } 160 161 /* 162 * Get the RCC node offset from the device tree 163 * @param fdt: Device tree reference 164 * @return: Node offset or a negative value on error 165 */ 166 static int fdt_get_rcc_node(void *fdt) 167 { 168 static int node; 169 170 if (node <= 0) { 171 node = fdt_node_offset_by_compatible(fdt, -1, DT_RCC_CLK_COMPAT); 172 } 173 174 return node; 175 } 176 177 /* 178 * Read a series of parameters in rcc-clk section in device tree 179 * @param prop_name: Name of the RCC property to be read 180 * @param array: the array to store the property parameters 181 * @param count: number of parameters to be read 182 * @return: 0 on succes or a negative value on error 183 */ 184 int fdt_rcc_read_uint32_array(const char *prop_name, uint32_t count, 185 uint32_t *array) 186 { 187 int node; 188 void *fdt; 189 190 if (fdt_get_address(&fdt) == 0) { 191 return -ENOENT; 192 } 193 194 node = fdt_get_rcc_node(fdt); 195 if (node < 0) { 196 return -FDT_ERR_NOTFOUND; 197 } 198 199 return fdt_read_uint32_array(fdt, node, prop_name, count, array); 200 } 201 202 /* 203 * Get the subnode offset in rcc-clk section from its name in device tree 204 * @param name: name of the RCC property 205 * @return: offset on success, and a negative FDT/ERRNO error code on failure. 206 */ 207 int fdt_rcc_subnode_offset(const char *name) 208 { 209 int node, subnode; 210 void *fdt; 211 212 if (fdt_get_address(&fdt) == 0) { 213 return -ENOENT; 214 } 215 216 node = fdt_get_rcc_node(fdt); 217 if (node < 0) { 218 return -FDT_ERR_NOTFOUND; 219 } 220 221 subnode = fdt_subnode_offset(fdt, node, name); 222 if (subnode <= 0) { 223 return -FDT_ERR_NOTFOUND; 224 } 225 226 return subnode; 227 } 228 229 /* 230 * Get the pointer to a rcc-clk property from its name. 231 * @param name: name of the RCC property 232 * @param lenp: stores the length of the property. 233 * @return: pointer to the property on success, and NULL value on failure. 234 */ 235 const fdt32_t *fdt_rcc_read_prop(const char *prop_name, int *lenp) 236 { 237 const fdt32_t *cuint; 238 int node, len; 239 void *fdt; 240 241 if (fdt_get_address(&fdt) == 0) { 242 return NULL; 243 } 244 245 node = fdt_get_rcc_node(fdt); 246 if (node < 0) { 247 return NULL; 248 } 249 250 cuint = fdt_getprop(fdt, node, prop_name, &len); 251 if (cuint == NULL) { 252 return NULL; 253 } 254 255 *lenp = len; 256 return cuint; 257 } 258 259 /* 260 * Get the secure status for rcc node in device tree. 261 * @return: true if rcc is available from secure world, false if not. 262 */ 263 bool fdt_get_rcc_secure_status(void) 264 { 265 int node; 266 void *fdt; 267 268 if (fdt_get_address(&fdt) == 0) { 269 return false; 270 } 271 272 node = fdt_get_rcc_node(fdt); 273 if (node < 0) { 274 return false; 275 } 276 277 return !!(fdt_get_status(node) & DT_SECURE); 278 } 279 280 /* 281 * Get the clock ID of the given node in device tree. 282 * @param node: node offset 283 * @return: Clock ID on success, and a negative FDT/ERRNO error code on failure. 284 */ 285 int fdt_get_clock_id(int node) 286 { 287 const fdt32_t *cuint; 288 void *fdt; 289 290 if (fdt_get_address(&fdt) == 0) { 291 return -ENOENT; 292 } 293 294 cuint = fdt_getprop(fdt, node, "clocks", NULL); 295 if (cuint == NULL) { 296 return -FDT_ERR_NOTFOUND; 297 } 298 299 cuint++; 300 return (int)fdt32_to_cpu(*cuint); 301 } 302 303 /* 304 * Get the frequency of the specified UART instance. 305 * @param instance: UART interface registers base address. 306 * @return: clock frequency on success, 0 value on failure. 307 */ 308 unsigned long fdt_get_uart_clock_freq(uintptr_t instance) 309 { 310 void *fdt; 311 int node; 312 int clk_id; 313 314 if (fdt_get_address(&fdt) == 0) { 315 return 0UL; 316 } 317 318 /* Check for UART nodes */ 319 node = dt_match_instance_by_compatible(DT_UART_COMPAT, instance); 320 if (node < 0) { 321 return 0UL; 322 } 323 324 clk_id = fdt_get_clock_id(node); 325 if (clk_id < 0) { 326 return 0UL; 327 } 328 329 return clk_get_rate((unsigned long)clk_id); 330 } 331