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