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 /* 18 * Get the frequency of an oscillator from its name in device tree. 19 * @param name: oscillator name 20 * @param freq: stores the frequency of the oscillator 21 * @return: 0 on success, and a negative FDT/ERRNO error code on failure. 22 */ 23 int fdt_osc_read_freq(const char *name, uint32_t *freq) 24 { 25 int node, subnode; 26 void *fdt; 27 28 if (fdt_get_address(&fdt) == 0) { 29 return -ENOENT; 30 } 31 32 node = fdt_path_offset(fdt, "/clocks"); 33 if (node < 0) { 34 return -FDT_ERR_NOTFOUND; 35 } 36 37 fdt_for_each_subnode(subnode, fdt, node) { 38 const char *cchar; 39 int ret; 40 41 cchar = fdt_get_name(fdt, subnode, &ret); 42 if (cchar == NULL) { 43 return ret; 44 } 45 46 if (strncmp(cchar, name, (size_t)ret) == 0) { 47 const fdt32_t *cuint; 48 49 cuint = fdt_getprop(fdt, subnode, "clock-frequency", 50 &ret); 51 if (cuint == NULL) { 52 return ret; 53 } 54 55 *freq = fdt32_to_cpu(*cuint); 56 57 return 0; 58 } 59 } 60 61 /* Oscillator not found, freq=0 */ 62 *freq = 0; 63 return 0; 64 } 65 66 /* 67 * Check the presence of an oscillator property from its id. 68 * @param osc_id: oscillator ID 69 * @param prop_name: property name 70 * @return: true/false regarding search result. 71 */ 72 bool fdt_osc_read_bool(enum stm32mp_osc_id osc_id, const char *prop_name) 73 { 74 int node, subnode; 75 void *fdt; 76 77 if (fdt_get_address(&fdt) == 0) { 78 return false; 79 } 80 81 if (osc_id >= NB_OSC) { 82 return false; 83 } 84 85 node = fdt_path_offset(fdt, "/clocks"); 86 if (node < 0) { 87 return false; 88 } 89 90 fdt_for_each_subnode(subnode, fdt, node) { 91 const char *cchar; 92 int ret; 93 94 cchar = fdt_get_name(fdt, subnode, &ret); 95 if (cchar == NULL) { 96 return false; 97 } 98 99 if (strncmp(cchar, stm32mp_osc_node_label[osc_id], 100 (size_t)ret) != 0) { 101 continue; 102 } 103 104 if (fdt_getprop(fdt, subnode, prop_name, NULL) != NULL) { 105 return true; 106 } 107 } 108 109 return false; 110 } 111 112 /* 113 * Get the value of a oscillator property from its ID. 114 * @param osc_id: oscillator ID 115 * @param prop_name: property name 116 * @param dflt_value: default value 117 * @return oscillator value on success, default value if property not found. 118 */ 119 uint32_t fdt_osc_read_uint32_default(enum stm32mp_osc_id osc_id, 120 const char *prop_name, uint32_t dflt_value) 121 { 122 int node, subnode; 123 void *fdt; 124 125 if (fdt_get_address(&fdt) == 0) { 126 return dflt_value; 127 } 128 129 if (osc_id >= NB_OSC) { 130 return dflt_value; 131 } 132 133 node = fdt_path_offset(fdt, "/clocks"); 134 if (node < 0) { 135 return dflt_value; 136 } 137 138 fdt_for_each_subnode(subnode, fdt, node) { 139 const char *cchar; 140 int ret; 141 142 cchar = fdt_get_name(fdt, subnode, &ret); 143 if (cchar == NULL) { 144 return dflt_value; 145 } 146 147 if (strncmp(cchar, stm32mp_osc_node_label[osc_id], 148 (size_t)ret) != 0) { 149 continue; 150 } 151 152 return fdt_read_uint32_default(fdt, subnode, prop_name, 153 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 static int fdt_get_rcc_node(void *fdt) 165 { 166 static int node; 167 168 if (node <= 0) { 169 node = fdt_node_offset_by_compatible(fdt, -1, DT_RCC_CLK_COMPAT); 170 } 171 172 return node; 173 } 174 175 /* 176 * Read a series of parameters in rcc-clk section in device tree 177 * @param prop_name: Name of the RCC property to be read 178 * @param array: the array to store the property parameters 179 * @param count: number of parameters to be read 180 * @return: 0 on succes or a negative value on error 181 */ 182 int fdt_rcc_read_uint32_array(const char *prop_name, uint32_t count, 183 uint32_t *array) 184 { 185 int node; 186 void *fdt; 187 188 if (fdt_get_address(&fdt) == 0) { 189 return -ENOENT; 190 } 191 192 node = fdt_get_rcc_node(fdt); 193 if (node < 0) { 194 return -FDT_ERR_NOTFOUND; 195 } 196 197 return fdt_read_uint32_array(fdt, node, prop_name, count, array); 198 } 199 200 /* 201 * Get the subnode offset in rcc-clk section from its name in device tree 202 * @param name: name of the RCC property 203 * @return: offset on success, and a negative FDT/ERRNO error code on failure. 204 */ 205 int fdt_rcc_subnode_offset(const char *name) 206 { 207 int node, subnode; 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 subnode = fdt_subnode_offset(fdt, node, name); 220 if (subnode <= 0) { 221 return -FDT_ERR_NOTFOUND; 222 } 223 224 return subnode; 225 } 226 227 /* 228 * Get the pointer to a rcc-clk property from its name. 229 * @param name: name of the RCC property 230 * @param lenp: stores the length of the property. 231 * @return: pointer to the property on success, and NULL value on failure. 232 */ 233 const fdt32_t *fdt_rcc_read_prop(const char *prop_name, int *lenp) 234 { 235 const fdt32_t *cuint; 236 int node, len; 237 void *fdt; 238 239 if (fdt_get_address(&fdt) == 0) { 240 return NULL; 241 } 242 243 node = fdt_get_rcc_node(fdt); 244 if (node < 0) { 245 return NULL; 246 } 247 248 cuint = fdt_getprop(fdt, node, prop_name, &len); 249 if (cuint == NULL) { 250 return NULL; 251 } 252 253 *lenp = len; 254 return cuint; 255 } 256 257 /* 258 * Get the secure status for rcc node in device tree. 259 * @return: true if rcc is available from secure world, false if not. 260 */ 261 bool fdt_get_rcc_secure_status(void) 262 { 263 int node; 264 void *fdt; 265 266 if (fdt_get_address(&fdt) == 0) { 267 return false; 268 } 269 270 node = fdt_get_rcc_node(fdt); 271 if (node < 0) { 272 return false; 273 } 274 275 return !!(fdt_get_status(node) & DT_SECURE); 276 } 277 278 /* 279 * Get the clock ID of the given node in device tree. 280 * @param node: node offset 281 * @return: Clock ID on success, and a negative FDT/ERRNO error code on failure. 282 */ 283 int fdt_get_clock_id(int node) 284 { 285 const fdt32_t *cuint; 286 void *fdt; 287 288 if (fdt_get_address(&fdt) == 0) { 289 return -ENOENT; 290 } 291 292 cuint = fdt_getprop(fdt, node, "clocks", NULL); 293 if (cuint == NULL) { 294 return -FDT_ERR_NOTFOUND; 295 } 296 297 cuint++; 298 return (int)fdt32_to_cpu(*cuint); 299 } 300