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