1 /* 2 * Copyright (c) 2017-2020, 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 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 * Read a series of parameters in rcc-clk section in device tree 171 * @param prop_name: Name of the RCC property to be read 172 * @param array: the array to store the property parameters 173 * @param count: number of parameters to be read 174 * @return: 0 on succes or a negative value on error 175 */ 176 int fdt_rcc_read_uint32_array(const char *prop_name, uint32_t count, 177 uint32_t *array) 178 { 179 int node; 180 void *fdt; 181 182 if (fdt_get_address(&fdt) == 0) { 183 return -ENOENT; 184 } 185 186 node = fdt_get_rcc_node(fdt); 187 if (node < 0) { 188 return -FDT_ERR_NOTFOUND; 189 } 190 191 return fdt_read_uint32_array(fdt, node, prop_name, count, array); 192 } 193 194 /* 195 * Get the subnode offset in rcc-clk section from its name in device tree 196 * @param name: name of the RCC property 197 * @return: offset on success, and a negative FDT/ERRNO error code on failure. 198 */ 199 int fdt_rcc_subnode_offset(const char *name) 200 { 201 int node, subnode; 202 void *fdt; 203 204 if (fdt_get_address(&fdt) == 0) { 205 return -ENOENT; 206 } 207 208 node = fdt_get_rcc_node(fdt); 209 if (node < 0) { 210 return -FDT_ERR_NOTFOUND; 211 } 212 213 subnode = fdt_subnode_offset(fdt, node, name); 214 if (subnode <= 0) { 215 return -FDT_ERR_NOTFOUND; 216 } 217 218 return subnode; 219 } 220 221 /* 222 * Get the pointer to a rcc-clk property from its name. 223 * @param name: name of the RCC property 224 * @param lenp: stores the length of the property. 225 * @return: pointer to the property on success, and NULL value on failure. 226 */ 227 const fdt32_t *fdt_rcc_read_prop(const char *prop_name, int *lenp) 228 { 229 const fdt32_t *cuint; 230 int node, len; 231 void *fdt; 232 233 if (fdt_get_address(&fdt) == 0) { 234 return NULL; 235 } 236 237 node = fdt_get_rcc_node(fdt); 238 if (node < 0) { 239 return NULL; 240 } 241 242 cuint = fdt_getprop(fdt, node, prop_name, &len); 243 if (cuint == NULL) { 244 return NULL; 245 } 246 247 *lenp = len; 248 return cuint; 249 } 250 251 /* 252 * Get the secure status for rcc node in device tree. 253 * @return: true if rcc is available from secure world, false if not. 254 */ 255 bool fdt_get_rcc_secure_status(void) 256 { 257 int node; 258 void *fdt; 259 260 if (fdt_get_address(&fdt) == 0) { 261 return false; 262 } 263 264 node = fdt_get_rcc_node(fdt); 265 if (node < 0) { 266 return false; 267 } 268 269 return !!(fdt_get_status(node) & DT_SECURE); 270 } 271 272 /* 273 * Get the clock ID of the given node in device tree. 274 * @param node: node offset 275 * @return: Clock ID on success, and a negative FDT/ERRNO error code on failure. 276 */ 277 int fdt_get_clock_id(int node) 278 { 279 const fdt32_t *cuint; 280 void *fdt; 281 282 if (fdt_get_address(&fdt) == 0) { 283 return -ENOENT; 284 } 285 286 cuint = fdt_getprop(fdt, node, "clocks", NULL); 287 if (cuint == NULL) { 288 return -FDT_ERR_NOTFOUND; 289 } 290 291 cuint++; 292 return (int)fdt32_to_cpu(*cuint); 293 } 294