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