1 /* 2 * Copyright (c) 2017-2019, 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_STGEN_COMPAT "st,stm32-stgen" 18 19 /* 20 * Get the frequency of an oscillator from its name in device tree. 21 * @param name: oscillator name 22 * @param freq: stores the frequency of the oscillator 23 * @return: 0 on success, and a negative FDT/ERRNO error code on failure. 24 */ 25 int fdt_osc_read_freq(const char *name, uint32_t *freq) 26 { 27 int node, subnode; 28 void *fdt; 29 30 if (fdt_get_address(&fdt) == 0) { 31 return -ENOENT; 32 } 33 34 node = fdt_path_offset(fdt, "/clocks"); 35 if (node < 0) { 36 return -FDT_ERR_NOTFOUND; 37 } 38 39 fdt_for_each_subnode(subnode, fdt, node) { 40 const char *cchar; 41 int ret; 42 43 cchar = fdt_get_name(fdt, subnode, &ret); 44 if (cchar == NULL) { 45 return ret; 46 } 47 48 if (strncmp(cchar, name, (size_t)ret) == 0) { 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(subnode, prop_name, 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 int fdt_get_rcc_node(void *fdt) 166 { 167 return fdt_node_offset_by_compatible(fdt, -1, DT_RCC_CLK_COMPAT); 168 } 169 170 /* 171 * Get the RCC base address from the device tree 172 * @return: RCC address or 0 on error 173 */ 174 uint32_t fdt_rcc_read_addr(void) 175 { 176 int node; 177 void *fdt; 178 const fdt32_t *cuint; 179 180 if (fdt_get_address(&fdt) == 0) { 181 return 0; 182 } 183 184 node = fdt_get_rcc_node(fdt); 185 if (node < 0) { 186 return 0; 187 } 188 189 cuint = fdt_getprop(fdt, node, "reg", NULL); 190 if (cuint == NULL) { 191 return 0; 192 } 193 194 return fdt32_to_cpu(*cuint); 195 } 196 197 /* 198 * Read a series of parameters in rcc-clk section in device tree 199 * @param prop_name: Name of the RCC property to be read 200 * @param array: the array to store the property parameters 201 * @param count: number of parameters to be read 202 * @return: 0 on succes or a negative value on error 203 */ 204 int fdt_rcc_read_uint32_array(const char *prop_name, uint32_t count, 205 uint32_t *array) 206 { 207 int node; 208 void *fdt; 209 210 if (fdt_get_address(&fdt) == 0) { 211 return -ENOENT; 212 } 213 214 node = fdt_get_rcc_node(fdt); 215 if (node < 0) { 216 return -FDT_ERR_NOTFOUND; 217 } 218 219 return fdt_read_uint32_array(fdt, node, prop_name, count, array); 220 } 221 222 /* 223 * Get the subnode offset in rcc-clk section from its name in device tree 224 * @param name: name of the RCC property 225 * @return: offset on success, and a negative FDT/ERRNO error code on failure. 226 */ 227 int fdt_rcc_subnode_offset(const char *name) 228 { 229 int node, subnode; 230 void *fdt; 231 232 if (fdt_get_address(&fdt) == 0) { 233 return -ENOENT; 234 } 235 236 node = fdt_get_rcc_node(fdt); 237 if (node < 0) { 238 return -FDT_ERR_NOTFOUND; 239 } 240 241 subnode = fdt_subnode_offset(fdt, node, name); 242 if (subnode <= 0) { 243 return -FDT_ERR_NOTFOUND; 244 } 245 246 return subnode; 247 } 248 249 /* 250 * Get the pointer to a rcc-clk property from its name. 251 * @param name: name of the RCC property 252 * @param lenp: stores the length of the property. 253 * @return: pointer to the property on success, and NULL value on failure. 254 */ 255 const fdt32_t *fdt_rcc_read_prop(const char *prop_name, int *lenp) 256 { 257 const fdt32_t *cuint; 258 int node, len; 259 void *fdt; 260 261 if (fdt_get_address(&fdt) == 0) { 262 return NULL; 263 } 264 265 node = fdt_get_rcc_node(fdt); 266 if (node < 0) { 267 return NULL; 268 } 269 270 cuint = fdt_getprop(fdt, node, prop_name, &len); 271 if (cuint == NULL) { 272 return NULL; 273 } 274 275 *lenp = len; 276 return cuint; 277 } 278 279 /* 280 * Get the secure status for rcc node in device tree. 281 * @return: true if rcc is available from secure world, false if not. 282 */ 283 bool fdt_get_rcc_secure_status(void) 284 { 285 int node; 286 void *fdt; 287 288 if (fdt_get_address(&fdt) == 0) { 289 return false; 290 } 291 292 node = fdt_get_rcc_node(fdt); 293 if (node < 0) { 294 return false; 295 } 296 297 return !!(fdt_get_status(node) & DT_SECURE); 298 } 299 300 /* 301 * Get the stgen base address. 302 * @return: address of stgen on success, and NULL value on failure. 303 */ 304 uintptr_t fdt_get_stgen_base(void) 305 { 306 int node; 307 const fdt32_t *cuint; 308 void *fdt; 309 310 if (fdt_get_address(&fdt) == 0) { 311 return 0; 312 } 313 314 node = fdt_node_offset_by_compatible(fdt, -1, DT_STGEN_COMPAT); 315 if (node < 0) { 316 return 0; 317 } 318 319 cuint = fdt_getprop(fdt, node, "reg", NULL); 320 if (cuint == NULL) { 321 return 0; 322 } 323 324 return fdt32_to_cpu(*cuint); 325 } 326 327 /* 328 * Get the clock ID of the given node in device tree. 329 * @param node: node offset 330 * @return: Clock ID on success, and a negative FDT/ERRNO error code on failure. 331 */ 332 int fdt_get_clock_id(int node) 333 { 334 const fdt32_t *cuint; 335 void *fdt; 336 337 if (fdt_get_address(&fdt) == 0) { 338 return -ENOENT; 339 } 340 341 cuint = fdt_getprop(fdt, node, "clocks", NULL); 342 if (cuint == NULL) { 343 return -FDT_ERR_NOTFOUND; 344 } 345 346 cuint++; 347 return (int)fdt32_to_cpu(*cuint); 348 } 349