1 // SPDX-License-Identifier: GPL-2.0-only 2 3 #include <linux/array_size.h> 4 #include <linux/dev_printk.h> 5 #include <linux/err.h> 6 #include <linux/errno.h> 7 #include <linux/fwnode.h> 8 #include <linux/property.h> 9 #include <linux/slab.h> 10 #include <linux/string.h> 11 12 #include "core.h" 13 #include "prop.h" 14 15 /** 16 * zl3073x_pin_check_freq - verify frequency for given pin 17 * @zldev: pointer to zl3073x device 18 * @dir: pin direction 19 * @id: pin index 20 * @freq: frequency to check 21 * 22 * The function checks the given frequency is valid for the device. For input 23 * pins it checks that the frequency can be factorized using supported base 24 * frequencies. For output pins it checks that the frequency divides connected 25 * synth frequency without remainder. 26 * 27 * Return: true if the frequency is valid, false if not. 28 */ 29 static bool 30 zl3073x_pin_check_freq(struct zl3073x_dev *zldev, enum dpll_pin_direction dir, 31 u8 id, u64 freq) 32 { 33 if (freq > U32_MAX) 34 goto err_inv_freq; 35 36 if (dir == DPLL_PIN_DIRECTION_INPUT) { 37 int rc; 38 39 /* Check if the frequency can be factorized */ 40 rc = zl3073x_ref_freq_factorize(freq, NULL, NULL); 41 if (rc) 42 goto err_inv_freq; 43 } else { 44 u32 synth_freq; 45 u8 out, synth; 46 47 /* Get output pin synthesizer */ 48 out = zl3073x_output_pin_out_get(id); 49 synth = zl3073x_dev_out_synth_get(zldev, out); 50 51 /* Get synth frequency */ 52 synth_freq = zl3073x_dev_synth_freq_get(zldev, synth); 53 54 /* Check the frequency divides synth frequency */ 55 if (synth_freq % (u32)freq) 56 goto err_inv_freq; 57 } 58 59 return true; 60 61 err_inv_freq: 62 dev_warn(zldev->dev, 63 "Unsupported frequency %llu Hz in firmware node\n", freq); 64 65 return false; 66 } 67 68 /** 69 * zl3073x_prop_pin_package_label_set - get package label for the pin 70 * @zldev: pointer to zl3073x device 71 * @props: pointer to pin properties 72 * @dir: pin direction 73 * @id: pin index 74 * 75 * Generates package label string and stores it into pin properties structure. 76 * 77 * Possible formats: 78 * REF<n> - differential input reference 79 * REF<n>P & REF<n>N - single-ended input reference (P or N pin) 80 * OUT<n> - differential output 81 * OUT<n>P & OUT<n>N - single-ended output (P or N pin) 82 */ 83 static void 84 zl3073x_prop_pin_package_label_set(struct zl3073x_dev *zldev, 85 struct zl3073x_pin_props *props, 86 enum dpll_pin_direction dir, u8 id) 87 { 88 const char *prefix, *suffix; 89 bool is_diff; 90 91 if (dir == DPLL_PIN_DIRECTION_INPUT) { 92 u8 ref; 93 94 prefix = "REF"; 95 ref = zl3073x_input_pin_ref_get(id); 96 is_diff = zl3073x_dev_ref_is_diff(zldev, ref); 97 } else { 98 u8 out; 99 100 prefix = "OUT"; 101 out = zl3073x_output_pin_out_get(id); 102 is_diff = zl3073x_dev_out_is_diff(zldev, out); 103 } 104 105 if (!is_diff) 106 suffix = zl3073x_is_p_pin(id) ? "P" : "N"; 107 else 108 suffix = ""; /* No suffix for differential one */ 109 110 snprintf(props->package_label, sizeof(props->package_label), "%s%u%s", 111 prefix, id / 2, suffix); 112 113 /* Set package_label pointer in DPLL core properties to generated 114 * string. 115 */ 116 props->dpll_props.package_label = props->package_label; 117 } 118 119 /** 120 * zl3073x_prop_pin_fwnode_get - get fwnode for given pin 121 * @zldev: pointer to zl3073x device 122 * @props: pointer to pin properties 123 * @dir: pin direction 124 * @id: pin index 125 * 126 * Return: 0 on success, -ENOENT if the firmware node does not exist 127 */ 128 static int 129 zl3073x_prop_pin_fwnode_get(struct zl3073x_dev *zldev, 130 struct zl3073x_pin_props *props, 131 enum dpll_pin_direction dir, u8 id) 132 { 133 struct fwnode_handle *pins_node, *pin_node; 134 const char *node_name; 135 136 if (dir == DPLL_PIN_DIRECTION_INPUT) 137 node_name = "input-pins"; 138 else 139 node_name = "output-pins"; 140 141 /* Get node containing input or output pins */ 142 pins_node = device_get_named_child_node(zldev->dev, node_name); 143 if (!pins_node) { 144 dev_dbg(zldev->dev, "'%s' sub-node is missing\n", node_name); 145 return -ENOENT; 146 } 147 148 /* Enumerate child pin nodes and find the requested one */ 149 fwnode_for_each_child_node(pins_node, pin_node) { 150 u32 reg; 151 152 if (fwnode_property_read_u32(pin_node, "reg", ®)) 153 continue; 154 155 if (id == reg) 156 break; 157 } 158 159 /* Release pin parent node */ 160 fwnode_handle_put(pins_node); 161 162 /* Save found node */ 163 props->fwnode = pin_node; 164 165 dev_dbg(zldev->dev, "Firmware node for %s %sfound\n", 166 props->package_label, pin_node ? "" : "NOT "); 167 168 return pin_node ? 0 : -ENOENT; 169 } 170 171 /** 172 * zl3073x_pin_props_get - get pin properties 173 * @zldev: pointer to zl3073x device 174 * @dir: pin direction 175 * @index: pin index 176 * 177 * The function looks for firmware node for the given pin if it is provided 178 * by the system firmware (DT or ACPI), allocates pin properties structure, 179 * generates package label string according pin type and optionally fetches 180 * board label, connection type, supported frequencies and esync capability 181 * from the firmware node if it does exist. 182 * 183 * Pointer that is returned by this function should be freed using 184 * @zl3073x_pin_props_put(). 185 * 186 * Return: 187 * * pointer to allocated pin properties structure on success 188 * * error pointer in case of error 189 */ 190 struct zl3073x_pin_props *zl3073x_pin_props_get(struct zl3073x_dev *zldev, 191 enum dpll_pin_direction dir, 192 u8 index) 193 { 194 struct dpll_pin_frequency *ranges; 195 struct zl3073x_pin_props *props; 196 int i, j, num_freqs = 0, rc; 197 u64 *freqs = NULL; 198 const char *type; 199 u32 curr_freq; 200 201 props = kzalloc_obj(*props); 202 if (!props) 203 return ERR_PTR(-ENOMEM); 204 205 /* Set default pin type and capabilities */ 206 if (dir == DPLL_PIN_DIRECTION_INPUT) { 207 props->dpll_props.type = DPLL_PIN_TYPE_EXT; 208 props->dpll_props.capabilities = 209 DPLL_PIN_CAPABILITIES_PRIORITY_CAN_CHANGE | 210 DPLL_PIN_CAPABILITIES_STATE_CAN_CHANGE; 211 curr_freq = zl3073x_dev_ref_freq_get(zldev, index); 212 } else { 213 u8 out, synth; 214 u32 f; 215 216 props->dpll_props.type = DPLL_PIN_TYPE_GNSS; 217 218 /* The output pin phase adjustment granularity equals half of 219 * the synth frequency count. 220 */ 221 out = zl3073x_output_pin_out_get(index); 222 synth = zl3073x_dev_out_synth_get(zldev, out); 223 f = 2 * zl3073x_dev_synth_freq_get(zldev, synth); 224 props->dpll_props.phase_gran = f ? div_u64(PSEC_PER_SEC, f) : 1; 225 curr_freq = zl3073x_dev_output_pin_freq_get(zldev, index); 226 } 227 228 props->dpll_props.phase_range.min = S32_MIN; 229 props->dpll_props.phase_range.max = S32_MAX; 230 231 zl3073x_prop_pin_package_label_set(zldev, props, dir, index); 232 233 /* Get firmware node for the given pin */ 234 rc = zl3073x_prop_pin_fwnode_get(zldev, props, dir, index); 235 if (rc) 236 goto skip_fwnode_props; 237 238 /* Look for label property and store the value as board label */ 239 fwnode_property_read_string(props->fwnode, "label", 240 &props->dpll_props.board_label); 241 242 /* Look for pin type property and translate its value to DPLL 243 * pin type enum if it is present. 244 */ 245 if (!fwnode_property_read_string(props->fwnode, "connection-type", 246 &type)) { 247 if (!strcmp(type, "ext")) 248 props->dpll_props.type = DPLL_PIN_TYPE_EXT; 249 else if (!strcmp(type, "gnss")) 250 props->dpll_props.type = DPLL_PIN_TYPE_GNSS; 251 else if (!strcmp(type, "int")) 252 props->dpll_props.type = DPLL_PIN_TYPE_INT_OSCILLATOR; 253 else if (!strcmp(type, "synce")) 254 props->dpll_props.type = DPLL_PIN_TYPE_SYNCE_ETH_PORT; 255 else if (!strcmp(type, "mux")) 256 props->dpll_props.type = DPLL_PIN_TYPE_MUX; 257 else 258 dev_warn(zldev->dev, 259 "Unknown or unsupported pin type '%s'\n", 260 type); 261 } 262 263 /* Check if the pin supports embedded sync control */ 264 props->esync_control = fwnode_property_read_bool(props->fwnode, 265 "esync-control"); 266 267 /* Read supported frequencies property if it is specified */ 268 num_freqs = fwnode_property_count_u64(props->fwnode, 269 "supported-frequencies-hz"); 270 if (num_freqs <= 0) { 271 num_freqs = 0; 272 goto skip_fwnode_props; 273 } 274 275 /* The firmware node specifies list of supported frequencies while 276 * DPLL core pin properties requires list of frequency ranges. 277 * So read the frequency list into temporary array. 278 */ 279 freqs = kcalloc(num_freqs, sizeof(*freqs), GFP_KERNEL); 280 if (!freqs) { 281 rc = -ENOMEM; 282 goto err_alloc_freqs; 283 } 284 285 /* Read frequencies list from firmware node */ 286 fwnode_property_read_u64_array(props->fwnode, 287 "supported-frequencies-hz", freqs, 288 num_freqs); 289 290 skip_fwnode_props: 291 /* Allocate frequency ranges list - extra slot for current frequency */ 292 ranges = kzalloc_objs(*ranges, num_freqs + 1); 293 if (!ranges) { 294 rc = -ENOMEM; 295 goto err_alloc_ranges; 296 } 297 298 /* Start with current frequency at index 0 */ 299 ranges[0] = (struct dpll_pin_frequency)DPLL_PIN_FREQUENCY(curr_freq); 300 301 /* Add frequencies from firmware node, skipping current frequency 302 * and filtering out frequencies not representable by device 303 */ 304 for (i = 0, j = 1; i < num_freqs; i++) { 305 struct dpll_pin_frequency freq = DPLL_PIN_FREQUENCY(freqs[i]); 306 307 if (freqs[i] == curr_freq) 308 continue; 309 if (zl3073x_pin_check_freq(zldev, dir, index, freqs[i])) { 310 ranges[j] = freq; 311 j++; 312 } 313 } 314 315 /* Save number of freq ranges and pointer to them into pin properties */ 316 props->dpll_props.freq_supported = ranges; 317 props->dpll_props.freq_supported_num = j; 318 319 /* Free temporary array */ 320 kfree(freqs); 321 322 return props; 323 324 err_alloc_ranges: 325 kfree(freqs); 326 err_alloc_freqs: 327 fwnode_handle_put(props->fwnode); 328 kfree(props); 329 330 return ERR_PTR(rc); 331 } 332 333 /** 334 * zl3073x_pin_props_put - release pin properties 335 * @props: pin properties to free 336 * 337 * The function deallocates given pin properties structure. 338 */ 339 void zl3073x_pin_props_put(struct zl3073x_pin_props *props) 340 { 341 /* Free supported frequency ranges list if it is present */ 342 kfree(props->dpll_props.freq_supported); 343 344 /* Put firmware handle if it is present */ 345 if (props->fwnode) 346 fwnode_handle_put(props->fwnode); 347 348 kfree(props); 349 } 350 351 /** 352 * zl3073x_prop_dpll_type_get - get DPLL channel type 353 * @zldev: pointer to zl3073x device 354 * @index: DPLL channel index 355 * 356 * Return: DPLL type for given DPLL channel 357 */ 358 enum dpll_type 359 zl3073x_prop_dpll_type_get(struct zl3073x_dev *zldev, u8 index) 360 { 361 const char *types[ZL3073X_MAX_CHANNELS]; 362 int count; 363 364 /* Read dpll types property from firmware */ 365 count = device_property_read_string_array(zldev->dev, "dpll-types", 366 types, ARRAY_SIZE(types)); 367 368 /* Return default if property or entry for given channel is missing */ 369 if (index >= count) 370 return DPLL_TYPE_PPS; 371 372 if (!strcmp(types[index], "pps")) 373 return DPLL_TYPE_PPS; 374 else if (!strcmp(types[index], "eec")) 375 return DPLL_TYPE_EEC; 376 377 dev_info(zldev->dev, "Unknown DPLL type '%s', using default\n", 378 types[index]); 379 380 return DPLL_TYPE_PPS; /* Default */ 381 } 382