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