1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* Copyright (C) 2022, Intel Corporation. */ |
3 | |
4 | #include "ice.h" |
5 | #include "ice_lib.h" |
6 | #include "ice_trace.h" |
7 | #include <linux/dpll.h> |
8 | |
9 | #define ICE_CGU_STATE_ACQ_ERR_THRESHOLD 50 |
10 | #define ICE_DPLL_PIN_IDX_INVALID 0xff |
11 | #define ICE_DPLL_RCLK_NUM_PER_PF 1 |
12 | |
13 | /** |
14 | * enum ice_dpll_pin_type - enumerate ice pin types: |
15 | * @ICE_DPLL_PIN_INVALID: invalid pin type |
16 | * @ICE_DPLL_PIN_TYPE_INPUT: input pin |
17 | * @ICE_DPLL_PIN_TYPE_OUTPUT: output pin |
18 | * @ICE_DPLL_PIN_TYPE_RCLK_INPUT: recovery clock input pin |
19 | */ |
20 | enum ice_dpll_pin_type { |
21 | ICE_DPLL_PIN_INVALID, |
22 | ICE_DPLL_PIN_TYPE_INPUT, |
23 | ICE_DPLL_PIN_TYPE_OUTPUT, |
24 | ICE_DPLL_PIN_TYPE_RCLK_INPUT, |
25 | }; |
26 | |
27 | static const char * const pin_type_name[] = { |
28 | [ICE_DPLL_PIN_TYPE_INPUT] = "input" , |
29 | [ICE_DPLL_PIN_TYPE_OUTPUT] = "output" , |
30 | [ICE_DPLL_PIN_TYPE_RCLK_INPUT] = "rclk-input" , |
31 | }; |
32 | |
33 | /** |
34 | * ice_dpll_pin_freq_set - set pin's frequency |
35 | * @pf: private board structure |
36 | * @pin: pointer to a pin |
37 | * @pin_type: type of pin being configured |
38 | * @freq: frequency to be set |
39 | * @extack: error reporting |
40 | * |
41 | * Set requested frequency on a pin. |
42 | * |
43 | * Context: Called under pf->dplls.lock |
44 | * Return: |
45 | * * 0 - success |
46 | * * negative - error on AQ or wrong pin type given |
47 | */ |
48 | static int |
49 | ice_dpll_pin_freq_set(struct ice_pf *pf, struct ice_dpll_pin *pin, |
50 | enum ice_dpll_pin_type pin_type, const u32 freq, |
51 | struct netlink_ext_ack *extack) |
52 | { |
53 | u8 flags; |
54 | int ret; |
55 | |
56 | switch (pin_type) { |
57 | case ICE_DPLL_PIN_TYPE_INPUT: |
58 | flags = ICE_AQC_SET_CGU_IN_CFG_FLG1_UPDATE_FREQ; |
59 | ret = ice_aq_set_input_pin_cfg(hw: &pf->hw, input_idx: pin->idx, flags1: flags, |
60 | flags2: pin->flags[0], freq, phase_delay: 0); |
61 | break; |
62 | case ICE_DPLL_PIN_TYPE_OUTPUT: |
63 | flags = ICE_AQC_SET_CGU_OUT_CFG_UPDATE_FREQ; |
64 | ret = ice_aq_set_output_pin_cfg(hw: &pf->hw, output_idx: pin->idx, flags, |
65 | src_sel: 0, freq, phase_delay: 0); |
66 | break; |
67 | default: |
68 | return -EINVAL; |
69 | } |
70 | if (ret) { |
71 | NL_SET_ERR_MSG_FMT(extack, |
72 | "err:%d %s failed to set pin freq:%u on pin:%u\n" , |
73 | ret, |
74 | ice_aq_str(pf->hw.adminq.sq_last_status), |
75 | freq, pin->idx); |
76 | return ret; |
77 | } |
78 | pin->freq = freq; |
79 | |
80 | return 0; |
81 | } |
82 | |
83 | /** |
84 | * ice_dpll_frequency_set - wrapper for pin callback for set frequency |
85 | * @pin: pointer to a pin |
86 | * @pin_priv: private data pointer passed on pin registration |
87 | * @dpll: pointer to dpll |
88 | * @dpll_priv: private data pointer passed on dpll registration |
89 | * @frequency: frequency to be set |
90 | * @extack: error reporting |
91 | * @pin_type: type of pin being configured |
92 | * |
93 | * Wraps internal set frequency command on a pin. |
94 | * |
95 | * Context: Acquires pf->dplls.lock |
96 | * Return: |
97 | * * 0 - success |
98 | * * negative - error pin not found or couldn't set in hw |
99 | */ |
100 | static int |
101 | ice_dpll_frequency_set(const struct dpll_pin *pin, void *pin_priv, |
102 | const struct dpll_device *dpll, void *dpll_priv, |
103 | const u32 frequency, |
104 | struct netlink_ext_ack *extack, |
105 | enum ice_dpll_pin_type pin_type) |
106 | { |
107 | struct ice_dpll_pin *p = pin_priv; |
108 | struct ice_dpll *d = dpll_priv; |
109 | struct ice_pf *pf = d->pf; |
110 | int ret; |
111 | |
112 | mutex_lock(&pf->dplls.lock); |
113 | ret = ice_dpll_pin_freq_set(pf, pin: p, pin_type, freq: frequency, extack); |
114 | mutex_unlock(lock: &pf->dplls.lock); |
115 | |
116 | return ret; |
117 | } |
118 | |
119 | /** |
120 | * ice_dpll_input_frequency_set - input pin callback for set frequency |
121 | * @pin: pointer to a pin |
122 | * @pin_priv: private data pointer passed on pin registration |
123 | * @dpll: pointer to dpll |
124 | * @dpll_priv: private data pointer passed on dpll registration |
125 | * @frequency: frequency to be set |
126 | * @extack: error reporting |
127 | * |
128 | * Wraps internal set frequency command on a pin. |
129 | * |
130 | * Context: Calls a function which acquires pf->dplls.lock |
131 | * Return: |
132 | * * 0 - success |
133 | * * negative - error pin not found or couldn't set in hw |
134 | */ |
135 | static int |
136 | ice_dpll_input_frequency_set(const struct dpll_pin *pin, void *pin_priv, |
137 | const struct dpll_device *dpll, void *dpll_priv, |
138 | u64 frequency, struct netlink_ext_ack *extack) |
139 | { |
140 | return ice_dpll_frequency_set(pin, pin_priv, dpll, dpll_priv, frequency, |
141 | extack, pin_type: ICE_DPLL_PIN_TYPE_INPUT); |
142 | } |
143 | |
144 | /** |
145 | * ice_dpll_output_frequency_set - output pin callback for set frequency |
146 | * @pin: pointer to a pin |
147 | * @pin_priv: private data pointer passed on pin registration |
148 | * @dpll: pointer to dpll |
149 | * @dpll_priv: private data pointer passed on dpll registration |
150 | * @frequency: frequency to be set |
151 | * @extack: error reporting |
152 | * |
153 | * Wraps internal set frequency command on a pin. |
154 | * |
155 | * Context: Calls a function which acquires pf->dplls.lock |
156 | * Return: |
157 | * * 0 - success |
158 | * * negative - error pin not found or couldn't set in hw |
159 | */ |
160 | static int |
161 | ice_dpll_output_frequency_set(const struct dpll_pin *pin, void *pin_priv, |
162 | const struct dpll_device *dpll, void *dpll_priv, |
163 | u64 frequency, struct netlink_ext_ack *extack) |
164 | { |
165 | return ice_dpll_frequency_set(pin, pin_priv, dpll, dpll_priv, frequency, |
166 | extack, pin_type: ICE_DPLL_PIN_TYPE_OUTPUT); |
167 | } |
168 | |
169 | /** |
170 | * ice_dpll_frequency_get - wrapper for pin callback for get frequency |
171 | * @pin: pointer to a pin |
172 | * @pin_priv: private data pointer passed on pin registration |
173 | * @dpll: pointer to dpll |
174 | * @dpll_priv: private data pointer passed on dpll registration |
175 | * @frequency: on success holds pin's frequency |
176 | * @extack: error reporting |
177 | * @pin_type: type of pin being configured |
178 | * |
179 | * Wraps internal get frequency command of a pin. |
180 | * |
181 | * Context: Acquires pf->dplls.lock |
182 | * Return: |
183 | * * 0 - success |
184 | * * negative - error pin not found or couldn't get from hw |
185 | */ |
186 | static int |
187 | ice_dpll_frequency_get(const struct dpll_pin *pin, void *pin_priv, |
188 | const struct dpll_device *dpll, void *dpll_priv, |
189 | u64 *frequency, struct netlink_ext_ack *extack, |
190 | enum ice_dpll_pin_type pin_type) |
191 | { |
192 | struct ice_dpll_pin *p = pin_priv; |
193 | struct ice_dpll *d = dpll_priv; |
194 | struct ice_pf *pf = d->pf; |
195 | |
196 | mutex_lock(&pf->dplls.lock); |
197 | *frequency = p->freq; |
198 | mutex_unlock(lock: &pf->dplls.lock); |
199 | |
200 | return 0; |
201 | } |
202 | |
203 | /** |
204 | * ice_dpll_input_frequency_get - input pin callback for get frequency |
205 | * @pin: pointer to a pin |
206 | * @pin_priv: private data pointer passed on pin registration |
207 | * @dpll: pointer to dpll |
208 | * @dpll_priv: private data pointer passed on dpll registration |
209 | * @frequency: on success holds pin's frequency |
210 | * @extack: error reporting |
211 | * |
212 | * Wraps internal get frequency command of a input pin. |
213 | * |
214 | * Context: Calls a function which acquires pf->dplls.lock |
215 | * Return: |
216 | * * 0 - success |
217 | * * negative - error pin not found or couldn't get from hw |
218 | */ |
219 | static int |
220 | ice_dpll_input_frequency_get(const struct dpll_pin *pin, void *pin_priv, |
221 | const struct dpll_device *dpll, void *dpll_priv, |
222 | u64 *frequency, struct netlink_ext_ack *extack) |
223 | { |
224 | return ice_dpll_frequency_get(pin, pin_priv, dpll, dpll_priv, frequency, |
225 | extack, pin_type: ICE_DPLL_PIN_TYPE_INPUT); |
226 | } |
227 | |
228 | /** |
229 | * ice_dpll_output_frequency_get - output pin callback for get frequency |
230 | * @pin: pointer to a pin |
231 | * @pin_priv: private data pointer passed on pin registration |
232 | * @dpll: pointer to dpll |
233 | * @dpll_priv: private data pointer passed on dpll registration |
234 | * @frequency: on success holds pin's frequency |
235 | * @extack: error reporting |
236 | * |
237 | * Wraps internal get frequency command of a pin. |
238 | * |
239 | * Context: Calls a function which acquires pf->dplls.lock |
240 | * Return: |
241 | * * 0 - success |
242 | * * negative - error pin not found or couldn't get from hw |
243 | */ |
244 | static int |
245 | ice_dpll_output_frequency_get(const struct dpll_pin *pin, void *pin_priv, |
246 | const struct dpll_device *dpll, void *dpll_priv, |
247 | u64 *frequency, struct netlink_ext_ack *extack) |
248 | { |
249 | return ice_dpll_frequency_get(pin, pin_priv, dpll, dpll_priv, frequency, |
250 | extack, pin_type: ICE_DPLL_PIN_TYPE_OUTPUT); |
251 | } |
252 | |
253 | /** |
254 | * ice_dpll_pin_enable - enable a pin on dplls |
255 | * @hw: board private hw structure |
256 | * @pin: pointer to a pin |
257 | * @pin_type: type of pin being enabled |
258 | * @extack: error reporting |
259 | * |
260 | * Enable a pin on both dplls. Store current state in pin->flags. |
261 | * |
262 | * Context: Called under pf->dplls.lock |
263 | * Return: |
264 | * * 0 - OK |
265 | * * negative - error |
266 | */ |
267 | static int |
268 | ice_dpll_pin_enable(struct ice_hw *hw, struct ice_dpll_pin *pin, |
269 | enum ice_dpll_pin_type pin_type, |
270 | struct netlink_ext_ack *extack) |
271 | { |
272 | u8 flags = 0; |
273 | int ret; |
274 | |
275 | switch (pin_type) { |
276 | case ICE_DPLL_PIN_TYPE_INPUT: |
277 | if (pin->flags[0] & ICE_AQC_GET_CGU_IN_CFG_FLG2_ESYNC_EN) |
278 | flags |= ICE_AQC_SET_CGU_IN_CFG_FLG2_ESYNC_EN; |
279 | flags |= ICE_AQC_SET_CGU_IN_CFG_FLG2_INPUT_EN; |
280 | ret = ice_aq_set_input_pin_cfg(hw, input_idx: pin->idx, flags1: 0, flags2: flags, freq: 0, phase_delay: 0); |
281 | break; |
282 | case ICE_DPLL_PIN_TYPE_OUTPUT: |
283 | if (pin->flags[0] & ICE_AQC_GET_CGU_OUT_CFG_ESYNC_EN) |
284 | flags |= ICE_AQC_SET_CGU_OUT_CFG_ESYNC_EN; |
285 | flags |= ICE_AQC_SET_CGU_OUT_CFG_OUT_EN; |
286 | ret = ice_aq_set_output_pin_cfg(hw, output_idx: pin->idx, flags, src_sel: 0, freq: 0, phase_delay: 0); |
287 | break; |
288 | default: |
289 | return -EINVAL; |
290 | } |
291 | if (ret) |
292 | NL_SET_ERR_MSG_FMT(extack, |
293 | "err:%d %s failed to enable %s pin:%u\n" , |
294 | ret, ice_aq_str(hw->adminq.sq_last_status), |
295 | pin_type_name[pin_type], pin->idx); |
296 | |
297 | return ret; |
298 | } |
299 | |
300 | /** |
301 | * ice_dpll_pin_disable - disable a pin on dplls |
302 | * @hw: board private hw structure |
303 | * @pin: pointer to a pin |
304 | * @pin_type: type of pin being disabled |
305 | * @extack: error reporting |
306 | * |
307 | * Disable a pin on both dplls. Store current state in pin->flags. |
308 | * |
309 | * Context: Called under pf->dplls.lock |
310 | * Return: |
311 | * * 0 - OK |
312 | * * negative - error |
313 | */ |
314 | static int |
315 | ice_dpll_pin_disable(struct ice_hw *hw, struct ice_dpll_pin *pin, |
316 | enum ice_dpll_pin_type pin_type, |
317 | struct netlink_ext_ack *extack) |
318 | { |
319 | u8 flags = 0; |
320 | int ret; |
321 | |
322 | switch (pin_type) { |
323 | case ICE_DPLL_PIN_TYPE_INPUT: |
324 | if (pin->flags[0] & ICE_AQC_GET_CGU_IN_CFG_FLG2_ESYNC_EN) |
325 | flags |= ICE_AQC_SET_CGU_IN_CFG_FLG2_ESYNC_EN; |
326 | ret = ice_aq_set_input_pin_cfg(hw, input_idx: pin->idx, flags1: 0, flags2: flags, freq: 0, phase_delay: 0); |
327 | break; |
328 | case ICE_DPLL_PIN_TYPE_OUTPUT: |
329 | if (pin->flags[0] & ICE_AQC_GET_CGU_OUT_CFG_ESYNC_EN) |
330 | flags |= ICE_AQC_SET_CGU_OUT_CFG_ESYNC_EN; |
331 | ret = ice_aq_set_output_pin_cfg(hw, output_idx: pin->idx, flags, src_sel: 0, freq: 0, phase_delay: 0); |
332 | break; |
333 | default: |
334 | return -EINVAL; |
335 | } |
336 | if (ret) |
337 | NL_SET_ERR_MSG_FMT(extack, |
338 | "err:%d %s failed to disable %s pin:%u\n" , |
339 | ret, ice_aq_str(hw->adminq.sq_last_status), |
340 | pin_type_name[pin_type], pin->idx); |
341 | |
342 | return ret; |
343 | } |
344 | |
345 | /** |
346 | * ice_dpll_pin_state_update - update pin's state |
347 | * @pf: private board struct |
348 | * @pin: structure with pin attributes to be updated |
349 | * @pin_type: type of pin being updated |
350 | * @extack: error reporting |
351 | * |
352 | * Determine pin current state and frequency, then update struct |
353 | * holding the pin info. For input pin states are separated for each |
354 | * dpll, for rclk pins states are separated for each parent. |
355 | * |
356 | * Context: Called under pf->dplls.lock |
357 | * Return: |
358 | * * 0 - OK |
359 | * * negative - error |
360 | */ |
361 | static int |
362 | ice_dpll_pin_state_update(struct ice_pf *pf, struct ice_dpll_pin *pin, |
363 | enum ice_dpll_pin_type pin_type, |
364 | struct netlink_ext_ack *extack) |
365 | { |
366 | u8 parent, port_num = ICE_AQC_SET_PHY_REC_CLK_OUT_CURR_PORT; |
367 | int ret; |
368 | |
369 | switch (pin_type) { |
370 | case ICE_DPLL_PIN_TYPE_INPUT: |
371 | ret = ice_aq_get_input_pin_cfg(hw: &pf->hw, input_idx: pin->idx, NULL, NULL, |
372 | NULL, flags2: &pin->flags[0], |
373 | freq: &pin->freq, NULL); |
374 | if (ret) |
375 | goto err; |
376 | if (ICE_AQC_GET_CGU_IN_CFG_FLG2_INPUT_EN & pin->flags[0]) { |
377 | if (pin->pin) { |
378 | pin->state[pf->dplls.eec.dpll_idx] = |
379 | pin->pin == pf->dplls.eec.active_input ? |
380 | DPLL_PIN_STATE_CONNECTED : |
381 | DPLL_PIN_STATE_SELECTABLE; |
382 | pin->state[pf->dplls.pps.dpll_idx] = |
383 | pin->pin == pf->dplls.pps.active_input ? |
384 | DPLL_PIN_STATE_CONNECTED : |
385 | DPLL_PIN_STATE_SELECTABLE; |
386 | } else { |
387 | pin->state[pf->dplls.eec.dpll_idx] = |
388 | DPLL_PIN_STATE_SELECTABLE; |
389 | pin->state[pf->dplls.pps.dpll_idx] = |
390 | DPLL_PIN_STATE_SELECTABLE; |
391 | } |
392 | } else { |
393 | pin->state[pf->dplls.eec.dpll_idx] = |
394 | DPLL_PIN_STATE_DISCONNECTED; |
395 | pin->state[pf->dplls.pps.dpll_idx] = |
396 | DPLL_PIN_STATE_DISCONNECTED; |
397 | } |
398 | break; |
399 | case ICE_DPLL_PIN_TYPE_OUTPUT: |
400 | ret = ice_aq_get_output_pin_cfg(hw: &pf->hw, output_idx: pin->idx, |
401 | flags: &pin->flags[0], NULL, |
402 | freq: &pin->freq, NULL); |
403 | if (ret) |
404 | goto err; |
405 | if (ICE_AQC_SET_CGU_OUT_CFG_OUT_EN & pin->flags[0]) |
406 | pin->state[0] = DPLL_PIN_STATE_CONNECTED; |
407 | else |
408 | pin->state[0] = DPLL_PIN_STATE_DISCONNECTED; |
409 | break; |
410 | case ICE_DPLL_PIN_TYPE_RCLK_INPUT: |
411 | for (parent = 0; parent < pf->dplls.rclk.num_parents; |
412 | parent++) { |
413 | u8 p = parent; |
414 | |
415 | ret = ice_aq_get_phy_rec_clk_out(hw: &pf->hw, phy_output: &p, |
416 | port_num: &port_num, |
417 | flags: &pin->flags[parent], |
418 | NULL); |
419 | if (ret) |
420 | goto err; |
421 | if (ICE_AQC_GET_PHY_REC_CLK_OUT_OUT_EN & |
422 | pin->flags[parent]) |
423 | pin->state[parent] = DPLL_PIN_STATE_CONNECTED; |
424 | else |
425 | pin->state[parent] = |
426 | DPLL_PIN_STATE_DISCONNECTED; |
427 | } |
428 | break; |
429 | default: |
430 | return -EINVAL; |
431 | } |
432 | |
433 | return 0; |
434 | err: |
435 | if (extack) |
436 | NL_SET_ERR_MSG_FMT(extack, |
437 | "err:%d %s failed to update %s pin:%u\n" , |
438 | ret, |
439 | ice_aq_str(pf->hw.adminq.sq_last_status), |
440 | pin_type_name[pin_type], pin->idx); |
441 | else |
442 | dev_err_ratelimited(ice_pf_to_dev(pf), |
443 | "err:%d %s failed to update %s pin:%u\n" , |
444 | ret, |
445 | ice_aq_str(pf->hw.adminq.sq_last_status), |
446 | pin_type_name[pin_type], pin->idx); |
447 | return ret; |
448 | } |
449 | |
450 | /** |
451 | * ice_dpll_hw_input_prio_set - set input priority value in hardware |
452 | * @pf: board private structure |
453 | * @dpll: ice dpll pointer |
454 | * @pin: ice pin pointer |
455 | * @prio: priority value being set on a dpll |
456 | * @extack: error reporting |
457 | * |
458 | * Internal wrapper for setting the priority in the hardware. |
459 | * |
460 | * Context: Called under pf->dplls.lock |
461 | * Return: |
462 | * * 0 - success |
463 | * * negative - failure |
464 | */ |
465 | static int |
466 | ice_dpll_hw_input_prio_set(struct ice_pf *pf, struct ice_dpll *dpll, |
467 | struct ice_dpll_pin *pin, const u32 prio, |
468 | struct netlink_ext_ack *extack) |
469 | { |
470 | int ret; |
471 | |
472 | ret = ice_aq_set_cgu_ref_prio(hw: &pf->hw, dpll_num: dpll->dpll_idx, ref_idx: pin->idx, |
473 | ref_priority: (u8)prio); |
474 | if (ret) |
475 | NL_SET_ERR_MSG_FMT(extack, |
476 | "err:%d %s failed to set pin prio:%u on pin:%u\n" , |
477 | ret, |
478 | ice_aq_str(pf->hw.adminq.sq_last_status), |
479 | prio, pin->idx); |
480 | else |
481 | dpll->input_prio[pin->idx] = prio; |
482 | |
483 | return ret; |
484 | } |
485 | |
486 | /** |
487 | * ice_dpll_lock_status_get - get dpll lock status callback |
488 | * @dpll: registered dpll pointer |
489 | * @dpll_priv: private data pointer passed on dpll registration |
490 | * @status: on success holds dpll's lock status |
491 | * @extack: error reporting |
492 | * |
493 | * Dpll subsystem callback, provides dpll's lock status. |
494 | * |
495 | * Context: Acquires pf->dplls.lock |
496 | * Return: |
497 | * * 0 - success |
498 | * * negative - failure |
499 | */ |
500 | static int |
501 | ice_dpll_lock_status_get(const struct dpll_device *dpll, void *dpll_priv, |
502 | enum dpll_lock_status *status, |
503 | struct netlink_ext_ack *extack) |
504 | { |
505 | struct ice_dpll *d = dpll_priv; |
506 | struct ice_pf *pf = d->pf; |
507 | |
508 | mutex_lock(&pf->dplls.lock); |
509 | *status = d->dpll_state; |
510 | mutex_unlock(lock: &pf->dplls.lock); |
511 | |
512 | return 0; |
513 | } |
514 | |
515 | /** |
516 | * ice_dpll_mode_supported - check if dpll's working mode is supported |
517 | * @dpll: registered dpll pointer |
518 | * @dpll_priv: private data pointer passed on dpll registration |
519 | * @mode: mode to be checked for support |
520 | * @extack: error reporting |
521 | * |
522 | * Dpll subsystem callback. Provides information if working mode is supported |
523 | * by dpll. |
524 | * |
525 | * Return: |
526 | * * true - mode is supported |
527 | * * false - mode is not supported |
528 | */ |
529 | static bool ice_dpll_mode_supported(const struct dpll_device *dpll, |
530 | void *dpll_priv, |
531 | enum dpll_mode mode, |
532 | struct netlink_ext_ack *extack) |
533 | { |
534 | if (mode == DPLL_MODE_AUTOMATIC) |
535 | return true; |
536 | |
537 | return false; |
538 | } |
539 | |
540 | /** |
541 | * ice_dpll_mode_get - get dpll's working mode |
542 | * @dpll: registered dpll pointer |
543 | * @dpll_priv: private data pointer passed on dpll registration |
544 | * @mode: on success holds current working mode of dpll |
545 | * @extack: error reporting |
546 | * |
547 | * Dpll subsystem callback. Provides working mode of dpll. |
548 | * |
549 | * Context: Acquires pf->dplls.lock |
550 | * Return: |
551 | * * 0 - success |
552 | * * negative - failure |
553 | */ |
554 | static int ice_dpll_mode_get(const struct dpll_device *dpll, void *dpll_priv, |
555 | enum dpll_mode *mode, |
556 | struct netlink_ext_ack *extack) |
557 | { |
558 | struct ice_dpll *d = dpll_priv; |
559 | struct ice_pf *pf = d->pf; |
560 | |
561 | mutex_lock(&pf->dplls.lock); |
562 | *mode = d->mode; |
563 | mutex_unlock(lock: &pf->dplls.lock); |
564 | |
565 | return 0; |
566 | } |
567 | |
568 | /** |
569 | * ice_dpll_pin_state_set - set pin's state on dpll |
570 | * @pin: pointer to a pin |
571 | * @pin_priv: private data pointer passed on pin registration |
572 | * @dpll: registered dpll pointer |
573 | * @dpll_priv: private data pointer passed on dpll registration |
574 | * @enable: if pin shalll be enabled |
575 | * @extack: error reporting |
576 | * @pin_type: type of a pin |
577 | * |
578 | * Set pin state on a pin. |
579 | * |
580 | * Context: Acquires pf->dplls.lock |
581 | * Return: |
582 | * * 0 - OK or no change required |
583 | * * negative - error |
584 | */ |
585 | static int |
586 | ice_dpll_pin_state_set(const struct dpll_pin *pin, void *pin_priv, |
587 | const struct dpll_device *dpll, void *dpll_priv, |
588 | bool enable, struct netlink_ext_ack *extack, |
589 | enum ice_dpll_pin_type pin_type) |
590 | { |
591 | struct ice_dpll_pin *p = pin_priv; |
592 | struct ice_dpll *d = dpll_priv; |
593 | struct ice_pf *pf = d->pf; |
594 | int ret; |
595 | |
596 | mutex_lock(&pf->dplls.lock); |
597 | if (enable) |
598 | ret = ice_dpll_pin_enable(hw: &pf->hw, pin: p, pin_type, extack); |
599 | else |
600 | ret = ice_dpll_pin_disable(hw: &pf->hw, pin: p, pin_type, extack); |
601 | if (!ret) |
602 | ret = ice_dpll_pin_state_update(pf, pin: p, pin_type, extack); |
603 | mutex_unlock(lock: &pf->dplls.lock); |
604 | |
605 | return ret; |
606 | } |
607 | |
608 | /** |
609 | * ice_dpll_output_state_set - enable/disable output pin on dpll device |
610 | * @pin: pointer to a pin |
611 | * @pin_priv: private data pointer passed on pin registration |
612 | * @dpll: dpll being configured |
613 | * @dpll_priv: private data pointer passed on dpll registration |
614 | * @state: state of pin to be set |
615 | * @extack: error reporting |
616 | * |
617 | * Dpll subsystem callback. Set given state on output type pin. |
618 | * |
619 | * Context: Calls a function which acquires pf->dplls.lock |
620 | * Return: |
621 | * * 0 - successfully enabled mode |
622 | * * negative - failed to enable mode |
623 | */ |
624 | static int |
625 | ice_dpll_output_state_set(const struct dpll_pin *pin, void *pin_priv, |
626 | const struct dpll_device *dpll, void *dpll_priv, |
627 | enum dpll_pin_state state, |
628 | struct netlink_ext_ack *extack) |
629 | { |
630 | bool enable = state == DPLL_PIN_STATE_CONNECTED; |
631 | |
632 | return ice_dpll_pin_state_set(pin, pin_priv, dpll, dpll_priv, enable, |
633 | extack, pin_type: ICE_DPLL_PIN_TYPE_OUTPUT); |
634 | } |
635 | |
636 | /** |
637 | * ice_dpll_input_state_set - enable/disable input pin on dpll levice |
638 | * @pin: pointer to a pin |
639 | * @pin_priv: private data pointer passed on pin registration |
640 | * @dpll: dpll being configured |
641 | * @dpll_priv: private data pointer passed on dpll registration |
642 | * @state: state of pin to be set |
643 | * @extack: error reporting |
644 | * |
645 | * Dpll subsystem callback. Enables given mode on input type pin. |
646 | * |
647 | * Context: Calls a function which acquires pf->dplls.lock |
648 | * Return: |
649 | * * 0 - successfully enabled mode |
650 | * * negative - failed to enable mode |
651 | */ |
652 | static int |
653 | ice_dpll_input_state_set(const struct dpll_pin *pin, void *pin_priv, |
654 | const struct dpll_device *dpll, void *dpll_priv, |
655 | enum dpll_pin_state state, |
656 | struct netlink_ext_ack *extack) |
657 | { |
658 | bool enable = state == DPLL_PIN_STATE_SELECTABLE; |
659 | |
660 | return ice_dpll_pin_state_set(pin, pin_priv, dpll, dpll_priv, enable, |
661 | extack, pin_type: ICE_DPLL_PIN_TYPE_INPUT); |
662 | } |
663 | |
664 | /** |
665 | * ice_dpll_pin_state_get - set pin's state on dpll |
666 | * @pin: pointer to a pin |
667 | * @pin_priv: private data pointer passed on pin registration |
668 | * @dpll: registered dpll pointer |
669 | * @dpll_priv: private data pointer passed on dpll registration |
670 | * @state: on success holds state of the pin |
671 | * @extack: error reporting |
672 | * @pin_type: type of questioned pin |
673 | * |
674 | * Determine pin state set it on a pin. |
675 | * |
676 | * Context: Acquires pf->dplls.lock |
677 | * Return: |
678 | * * 0 - success |
679 | * * negative - failed to get state |
680 | */ |
681 | static int |
682 | ice_dpll_pin_state_get(const struct dpll_pin *pin, void *pin_priv, |
683 | const struct dpll_device *dpll, void *dpll_priv, |
684 | enum dpll_pin_state *state, |
685 | struct netlink_ext_ack *extack, |
686 | enum ice_dpll_pin_type pin_type) |
687 | { |
688 | struct ice_dpll_pin *p = pin_priv; |
689 | struct ice_dpll *d = dpll_priv; |
690 | struct ice_pf *pf = d->pf; |
691 | int ret; |
692 | |
693 | mutex_lock(&pf->dplls.lock); |
694 | ret = ice_dpll_pin_state_update(pf, pin: p, pin_type, extack); |
695 | if (ret) |
696 | goto unlock; |
697 | if (pin_type == ICE_DPLL_PIN_TYPE_INPUT) |
698 | *state = p->state[d->dpll_idx]; |
699 | else if (pin_type == ICE_DPLL_PIN_TYPE_OUTPUT) |
700 | *state = p->state[0]; |
701 | ret = 0; |
702 | unlock: |
703 | mutex_unlock(lock: &pf->dplls.lock); |
704 | |
705 | return ret; |
706 | } |
707 | |
708 | /** |
709 | * ice_dpll_output_state_get - get output pin state on dpll device |
710 | * @pin: pointer to a pin |
711 | * @pin_priv: private data pointer passed on pin registration |
712 | * @dpll: registered dpll pointer |
713 | * @dpll_priv: private data pointer passed on dpll registration |
714 | * @state: on success holds state of the pin |
715 | * @extack: error reporting |
716 | * |
717 | * Dpll subsystem callback. Check state of a pin. |
718 | * |
719 | * Context: Calls a function which acquires pf->dplls.lock |
720 | * Return: |
721 | * * 0 - success |
722 | * * negative - failed to get state |
723 | */ |
724 | static int |
725 | ice_dpll_output_state_get(const struct dpll_pin *pin, void *pin_priv, |
726 | const struct dpll_device *dpll, void *dpll_priv, |
727 | enum dpll_pin_state *state, |
728 | struct netlink_ext_ack *extack) |
729 | { |
730 | return ice_dpll_pin_state_get(pin, pin_priv, dpll, dpll_priv, state, |
731 | extack, pin_type: ICE_DPLL_PIN_TYPE_OUTPUT); |
732 | } |
733 | |
734 | /** |
735 | * ice_dpll_input_state_get - get input pin state on dpll device |
736 | * @pin: pointer to a pin |
737 | * @pin_priv: private data pointer passed on pin registration |
738 | * @dpll: registered dpll pointer |
739 | * @dpll_priv: private data pointer passed on dpll registration |
740 | * @state: on success holds state of the pin |
741 | * @extack: error reporting |
742 | * |
743 | * Dpll subsystem callback. Check state of a input pin. |
744 | * |
745 | * Context: Calls a function which acquires pf->dplls.lock |
746 | * Return: |
747 | * * 0 - success |
748 | * * negative - failed to get state |
749 | */ |
750 | static int |
751 | ice_dpll_input_state_get(const struct dpll_pin *pin, void *pin_priv, |
752 | const struct dpll_device *dpll, void *dpll_priv, |
753 | enum dpll_pin_state *state, |
754 | struct netlink_ext_ack *extack) |
755 | { |
756 | return ice_dpll_pin_state_get(pin, pin_priv, dpll, dpll_priv, state, |
757 | extack, pin_type: ICE_DPLL_PIN_TYPE_INPUT); |
758 | } |
759 | |
760 | /** |
761 | * ice_dpll_input_prio_get - get dpll's input prio |
762 | * @pin: pointer to a pin |
763 | * @pin_priv: private data pointer passed on pin registration |
764 | * @dpll: registered dpll pointer |
765 | * @dpll_priv: private data pointer passed on dpll registration |
766 | * @prio: on success - returns input priority on dpll |
767 | * @extack: error reporting |
768 | * |
769 | * Dpll subsystem callback. Handler for getting priority of a input pin. |
770 | * |
771 | * Context: Acquires pf->dplls.lock |
772 | * Return: |
773 | * * 0 - success |
774 | * * negative - failure |
775 | */ |
776 | static int |
777 | ice_dpll_input_prio_get(const struct dpll_pin *pin, void *pin_priv, |
778 | const struct dpll_device *dpll, void *dpll_priv, |
779 | u32 *prio, struct netlink_ext_ack *extack) |
780 | { |
781 | struct ice_dpll_pin *p = pin_priv; |
782 | struct ice_dpll *d = dpll_priv; |
783 | struct ice_pf *pf = d->pf; |
784 | |
785 | mutex_lock(&pf->dplls.lock); |
786 | *prio = d->input_prio[p->idx]; |
787 | mutex_unlock(lock: &pf->dplls.lock); |
788 | |
789 | return 0; |
790 | } |
791 | |
792 | /** |
793 | * ice_dpll_input_prio_set - set dpll input prio |
794 | * @pin: pointer to a pin |
795 | * @pin_priv: private data pointer passed on pin registration |
796 | * @dpll: registered dpll pointer |
797 | * @dpll_priv: private data pointer passed on dpll registration |
798 | * @prio: input priority to be set on dpll |
799 | * @extack: error reporting |
800 | * |
801 | * Dpll subsystem callback. Handler for setting priority of a input pin. |
802 | * |
803 | * Context: Acquires pf->dplls.lock |
804 | * Return: |
805 | * * 0 - success |
806 | * * negative - failure |
807 | */ |
808 | static int |
809 | ice_dpll_input_prio_set(const struct dpll_pin *pin, void *pin_priv, |
810 | const struct dpll_device *dpll, void *dpll_priv, |
811 | u32 prio, struct netlink_ext_ack *extack) |
812 | { |
813 | struct ice_dpll_pin *p = pin_priv; |
814 | struct ice_dpll *d = dpll_priv; |
815 | struct ice_pf *pf = d->pf; |
816 | int ret; |
817 | |
818 | if (prio > ICE_DPLL_PRIO_MAX) { |
819 | NL_SET_ERR_MSG_FMT(extack, "prio out of supported range 0-%d" , |
820 | ICE_DPLL_PRIO_MAX); |
821 | return -EINVAL; |
822 | } |
823 | |
824 | mutex_lock(&pf->dplls.lock); |
825 | ret = ice_dpll_hw_input_prio_set(pf, dpll: d, pin: p, prio, extack); |
826 | mutex_unlock(lock: &pf->dplls.lock); |
827 | |
828 | return ret; |
829 | } |
830 | |
831 | /** |
832 | * ice_dpll_input_direction - callback for get input pin direction |
833 | * @pin: pointer to a pin |
834 | * @pin_priv: private data pointer passed on pin registration |
835 | * @dpll: registered dpll pointer |
836 | * @dpll_priv: private data pointer passed on dpll registration |
837 | * @direction: holds input pin direction |
838 | * @extack: error reporting |
839 | * |
840 | * Dpll subsystem callback. Handler for getting direction of a input pin. |
841 | * |
842 | * Return: |
843 | * * 0 - success |
844 | */ |
845 | static int |
846 | ice_dpll_input_direction(const struct dpll_pin *pin, void *pin_priv, |
847 | const struct dpll_device *dpll, void *dpll_priv, |
848 | enum dpll_pin_direction *direction, |
849 | struct netlink_ext_ack *extack) |
850 | { |
851 | *direction = DPLL_PIN_DIRECTION_INPUT; |
852 | |
853 | return 0; |
854 | } |
855 | |
856 | /** |
857 | * ice_dpll_output_direction - callback for get output pin direction |
858 | * @pin: pointer to a pin |
859 | * @pin_priv: private data pointer passed on pin registration |
860 | * @dpll: registered dpll pointer |
861 | * @dpll_priv: private data pointer passed on dpll registration |
862 | * @direction: holds output pin direction |
863 | * @extack: error reporting |
864 | * |
865 | * Dpll subsystem callback. Handler for getting direction of an output pin. |
866 | * |
867 | * Return: |
868 | * * 0 - success |
869 | */ |
870 | static int |
871 | ice_dpll_output_direction(const struct dpll_pin *pin, void *pin_priv, |
872 | const struct dpll_device *dpll, void *dpll_priv, |
873 | enum dpll_pin_direction *direction, |
874 | struct netlink_ext_ack *extack) |
875 | { |
876 | *direction = DPLL_PIN_DIRECTION_OUTPUT; |
877 | |
878 | return 0; |
879 | } |
880 | |
881 | /** |
882 | * ice_dpll_pin_phase_adjust_get - callback for get pin phase adjust value |
883 | * @pin: pointer to a pin |
884 | * @pin_priv: private data pointer passed on pin registration |
885 | * @dpll: registered dpll pointer |
886 | * @dpll_priv: private data pointer passed on dpll registration |
887 | * @phase_adjust: on success holds pin phase_adjust value |
888 | * @extack: error reporting |
889 | * |
890 | * Dpll subsystem callback. Handler for getting phase adjust value of a pin. |
891 | * |
892 | * Context: Acquires pf->dplls.lock |
893 | * Return: |
894 | * * 0 - success |
895 | * * negative - error |
896 | */ |
897 | static int |
898 | ice_dpll_pin_phase_adjust_get(const struct dpll_pin *pin, void *pin_priv, |
899 | const struct dpll_device *dpll, void *dpll_priv, |
900 | s32 *phase_adjust, |
901 | struct netlink_ext_ack *extack) |
902 | { |
903 | struct ice_dpll_pin *p = pin_priv; |
904 | struct ice_pf *pf = p->pf; |
905 | |
906 | mutex_lock(&pf->dplls.lock); |
907 | *phase_adjust = p->phase_adjust; |
908 | mutex_unlock(lock: &pf->dplls.lock); |
909 | |
910 | return 0; |
911 | } |
912 | |
913 | /** |
914 | * ice_dpll_pin_phase_adjust_set - helper for setting a pin phase adjust value |
915 | * @pin: pointer to a pin |
916 | * @pin_priv: private data pointer passed on pin registration |
917 | * @dpll: registered dpll pointer |
918 | * @dpll_priv: private data pointer passed on dpll registration |
919 | * @phase_adjust: phase_adjust to be set |
920 | * @extack: error reporting |
921 | * @type: type of a pin |
922 | * |
923 | * Helper for dpll subsystem callback. Handler for setting phase adjust value |
924 | * of a pin. |
925 | * |
926 | * Context: Acquires pf->dplls.lock |
927 | * Return: |
928 | * * 0 - success |
929 | * * negative - error |
930 | */ |
931 | static int |
932 | ice_dpll_pin_phase_adjust_set(const struct dpll_pin *pin, void *pin_priv, |
933 | const struct dpll_device *dpll, void *dpll_priv, |
934 | s32 phase_adjust, |
935 | struct netlink_ext_ack *extack, |
936 | enum ice_dpll_pin_type type) |
937 | { |
938 | struct ice_dpll_pin *p = pin_priv; |
939 | struct ice_dpll *d = dpll_priv; |
940 | struct ice_pf *pf = d->pf; |
941 | u8 flag, flags_en = 0; |
942 | int ret; |
943 | |
944 | mutex_lock(&pf->dplls.lock); |
945 | switch (type) { |
946 | case ICE_DPLL_PIN_TYPE_INPUT: |
947 | flag = ICE_AQC_SET_CGU_IN_CFG_FLG1_UPDATE_DELAY; |
948 | if (p->flags[0] & ICE_AQC_GET_CGU_IN_CFG_FLG2_ESYNC_EN) |
949 | flags_en |= ICE_AQC_SET_CGU_IN_CFG_FLG2_ESYNC_EN; |
950 | if (p->flags[0] & ICE_AQC_GET_CGU_IN_CFG_FLG2_INPUT_EN) |
951 | flags_en |= ICE_AQC_SET_CGU_IN_CFG_FLG2_INPUT_EN; |
952 | ret = ice_aq_set_input_pin_cfg(hw: &pf->hw, input_idx: p->idx, flags1: flag, flags2: flags_en, |
953 | freq: 0, phase_delay: phase_adjust); |
954 | break; |
955 | case ICE_DPLL_PIN_TYPE_OUTPUT: |
956 | flag = ICE_AQC_SET_CGU_OUT_CFG_UPDATE_PHASE; |
957 | if (p->flags[0] & ICE_AQC_GET_CGU_OUT_CFG_OUT_EN) |
958 | flag |= ICE_AQC_SET_CGU_OUT_CFG_OUT_EN; |
959 | if (p->flags[0] & ICE_AQC_GET_CGU_OUT_CFG_ESYNC_EN) |
960 | flag |= ICE_AQC_SET_CGU_OUT_CFG_ESYNC_EN; |
961 | ret = ice_aq_set_output_pin_cfg(hw: &pf->hw, output_idx: p->idx, flags: flag, src_sel: 0, freq: 0, |
962 | phase_delay: phase_adjust); |
963 | break; |
964 | default: |
965 | ret = -EINVAL; |
966 | } |
967 | if (!ret) |
968 | p->phase_adjust = phase_adjust; |
969 | mutex_unlock(lock: &pf->dplls.lock); |
970 | if (ret) |
971 | NL_SET_ERR_MSG_FMT(extack, |
972 | "err:%d %s failed to set pin phase_adjust:%d for pin:%u on dpll:%u\n" , |
973 | ret, |
974 | ice_aq_str(pf->hw.adminq.sq_last_status), |
975 | phase_adjust, p->idx, d->dpll_idx); |
976 | |
977 | return ret; |
978 | } |
979 | |
980 | /** |
981 | * ice_dpll_input_phase_adjust_set - callback for set input pin phase adjust |
982 | * @pin: pointer to a pin |
983 | * @pin_priv: private data pointer passed on pin registration |
984 | * @dpll: registered dpll pointer |
985 | * @dpll_priv: private data pointer passed on dpll registration |
986 | * @phase_adjust: phase_adjust to be set |
987 | * @extack: error reporting |
988 | * |
989 | * Dpll subsystem callback. Wraps a handler for setting phase adjust on input |
990 | * pin. |
991 | * |
992 | * Context: Calls a function which acquires pf->dplls.lock |
993 | * Return: |
994 | * * 0 - success |
995 | * * negative - error |
996 | */ |
997 | static int |
998 | ice_dpll_input_phase_adjust_set(const struct dpll_pin *pin, void *pin_priv, |
999 | const struct dpll_device *dpll, void *dpll_priv, |
1000 | s32 phase_adjust, |
1001 | struct netlink_ext_ack *extack) |
1002 | { |
1003 | return ice_dpll_pin_phase_adjust_set(pin, pin_priv, dpll, dpll_priv, |
1004 | phase_adjust, extack, |
1005 | type: ICE_DPLL_PIN_TYPE_INPUT); |
1006 | } |
1007 | |
1008 | /** |
1009 | * ice_dpll_output_phase_adjust_set - callback for set output pin phase adjust |
1010 | * @pin: pointer to a pin |
1011 | * @pin_priv: private data pointer passed on pin registration |
1012 | * @dpll: registered dpll pointer |
1013 | * @dpll_priv: private data pointer passed on dpll registration |
1014 | * @phase_adjust: phase_adjust to be set |
1015 | * @extack: error reporting |
1016 | * |
1017 | * Dpll subsystem callback. Wraps a handler for setting phase adjust on output |
1018 | * pin. |
1019 | * |
1020 | * Context: Calls a function which acquires pf->dplls.lock |
1021 | * Return: |
1022 | * * 0 - success |
1023 | * * negative - error |
1024 | */ |
1025 | static int |
1026 | ice_dpll_output_phase_adjust_set(const struct dpll_pin *pin, void *pin_priv, |
1027 | const struct dpll_device *dpll, void *dpll_priv, |
1028 | s32 phase_adjust, |
1029 | struct netlink_ext_ack *extack) |
1030 | { |
1031 | return ice_dpll_pin_phase_adjust_set(pin, pin_priv, dpll, dpll_priv, |
1032 | phase_adjust, extack, |
1033 | type: ICE_DPLL_PIN_TYPE_OUTPUT); |
1034 | } |
1035 | |
1036 | #define ICE_DPLL_PHASE_OFFSET_DIVIDER 100 |
1037 | #define ICE_DPLL_PHASE_OFFSET_FACTOR \ |
1038 | (DPLL_PHASE_OFFSET_DIVIDER / ICE_DPLL_PHASE_OFFSET_DIVIDER) |
1039 | /** |
1040 | * ice_dpll_phase_offset_get - callback for get dpll phase shift value |
1041 | * @pin: pointer to a pin |
1042 | * @pin_priv: private data pointer passed on pin registration |
1043 | * @dpll: registered dpll pointer |
1044 | * @dpll_priv: private data pointer passed on dpll registration |
1045 | * @phase_offset: on success holds pin phase_offset value |
1046 | * @extack: error reporting |
1047 | * |
1048 | * Dpll subsystem callback. Handler for getting phase shift value between |
1049 | * dpll's input and output. |
1050 | * |
1051 | * Context: Acquires pf->dplls.lock |
1052 | * Return: |
1053 | * * 0 - success |
1054 | * * negative - error |
1055 | */ |
1056 | static int |
1057 | ice_dpll_phase_offset_get(const struct dpll_pin *pin, void *pin_priv, |
1058 | const struct dpll_device *dpll, void *dpll_priv, |
1059 | s64 *phase_offset, struct netlink_ext_ack *extack) |
1060 | { |
1061 | struct ice_dpll *d = dpll_priv; |
1062 | struct ice_pf *pf = d->pf; |
1063 | |
1064 | mutex_lock(&pf->dplls.lock); |
1065 | if (d->active_input == pin) |
1066 | *phase_offset = d->phase_offset * ICE_DPLL_PHASE_OFFSET_FACTOR; |
1067 | else |
1068 | *phase_offset = 0; |
1069 | mutex_unlock(lock: &pf->dplls.lock); |
1070 | |
1071 | return 0; |
1072 | } |
1073 | |
1074 | /** |
1075 | * ice_dpll_rclk_state_on_pin_set - set a state on rclk pin |
1076 | * @pin: pointer to a pin |
1077 | * @pin_priv: private data pointer passed on pin registration |
1078 | * @parent_pin: pin parent pointer |
1079 | * @parent_pin_priv: parent private data pointer passed on pin registration |
1080 | * @state: state to be set on pin |
1081 | * @extack: error reporting |
1082 | * |
1083 | * Dpll subsystem callback, set a state of a rclk pin on a parent pin |
1084 | * |
1085 | * Context: Acquires pf->dplls.lock |
1086 | * Return: |
1087 | * * 0 - success |
1088 | * * negative - failure |
1089 | */ |
1090 | static int |
1091 | ice_dpll_rclk_state_on_pin_set(const struct dpll_pin *pin, void *pin_priv, |
1092 | const struct dpll_pin *parent_pin, |
1093 | void *parent_pin_priv, |
1094 | enum dpll_pin_state state, |
1095 | struct netlink_ext_ack *extack) |
1096 | { |
1097 | struct ice_dpll_pin *p = pin_priv, *parent = parent_pin_priv; |
1098 | bool enable = state == DPLL_PIN_STATE_CONNECTED; |
1099 | struct ice_pf *pf = p->pf; |
1100 | int ret = -EINVAL; |
1101 | u32 hw_idx; |
1102 | |
1103 | mutex_lock(&pf->dplls.lock); |
1104 | hw_idx = parent->idx - pf->dplls.base_rclk_idx; |
1105 | if (hw_idx >= pf->dplls.num_inputs) |
1106 | goto unlock; |
1107 | |
1108 | if ((enable && p->state[hw_idx] == DPLL_PIN_STATE_CONNECTED) || |
1109 | (!enable && p->state[hw_idx] == DPLL_PIN_STATE_DISCONNECTED)) { |
1110 | NL_SET_ERR_MSG_FMT(extack, |
1111 | "pin:%u state:%u on parent:%u already set" , |
1112 | p->idx, state, parent->idx); |
1113 | goto unlock; |
1114 | } |
1115 | ret = ice_aq_set_phy_rec_clk_out(hw: &pf->hw, phy_output: hw_idx, enable, |
1116 | freq: &p->freq); |
1117 | if (ret) |
1118 | NL_SET_ERR_MSG_FMT(extack, |
1119 | "err:%d %s failed to set pin state:%u for pin:%u on parent:%u\n" , |
1120 | ret, |
1121 | ice_aq_str(pf->hw.adminq.sq_last_status), |
1122 | state, p->idx, parent->idx); |
1123 | unlock: |
1124 | mutex_unlock(lock: &pf->dplls.lock); |
1125 | |
1126 | return ret; |
1127 | } |
1128 | |
1129 | /** |
1130 | * ice_dpll_rclk_state_on_pin_get - get a state of rclk pin |
1131 | * @pin: pointer to a pin |
1132 | * @pin_priv: private data pointer passed on pin registration |
1133 | * @parent_pin: pin parent pointer |
1134 | * @parent_pin_priv: pin parent priv data pointer passed on pin registration |
1135 | * @state: on success holds pin state on parent pin |
1136 | * @extack: error reporting |
1137 | * |
1138 | * dpll subsystem callback, get a state of a recovered clock pin. |
1139 | * |
1140 | * Context: Acquires pf->dplls.lock |
1141 | * Return: |
1142 | * * 0 - success |
1143 | * * negative - failure |
1144 | */ |
1145 | static int |
1146 | ice_dpll_rclk_state_on_pin_get(const struct dpll_pin *pin, void *pin_priv, |
1147 | const struct dpll_pin *parent_pin, |
1148 | void *parent_pin_priv, |
1149 | enum dpll_pin_state *state, |
1150 | struct netlink_ext_ack *extack) |
1151 | { |
1152 | struct ice_dpll_pin *p = pin_priv, *parent = parent_pin_priv; |
1153 | struct ice_pf *pf = p->pf; |
1154 | int ret = -EINVAL; |
1155 | u32 hw_idx; |
1156 | |
1157 | mutex_lock(&pf->dplls.lock); |
1158 | hw_idx = parent->idx - pf->dplls.base_rclk_idx; |
1159 | if (hw_idx >= pf->dplls.num_inputs) |
1160 | goto unlock; |
1161 | |
1162 | ret = ice_dpll_pin_state_update(pf, pin: p, pin_type: ICE_DPLL_PIN_TYPE_RCLK_INPUT, |
1163 | extack); |
1164 | if (ret) |
1165 | goto unlock; |
1166 | |
1167 | *state = p->state[hw_idx]; |
1168 | ret = 0; |
1169 | unlock: |
1170 | mutex_unlock(lock: &pf->dplls.lock); |
1171 | |
1172 | return ret; |
1173 | } |
1174 | |
1175 | static const struct dpll_pin_ops ice_dpll_rclk_ops = { |
1176 | .state_on_pin_set = ice_dpll_rclk_state_on_pin_set, |
1177 | .state_on_pin_get = ice_dpll_rclk_state_on_pin_get, |
1178 | .direction_get = ice_dpll_input_direction, |
1179 | }; |
1180 | |
1181 | static const struct dpll_pin_ops ice_dpll_input_ops = { |
1182 | .frequency_get = ice_dpll_input_frequency_get, |
1183 | .frequency_set = ice_dpll_input_frequency_set, |
1184 | .state_on_dpll_get = ice_dpll_input_state_get, |
1185 | .state_on_dpll_set = ice_dpll_input_state_set, |
1186 | .prio_get = ice_dpll_input_prio_get, |
1187 | .prio_set = ice_dpll_input_prio_set, |
1188 | .direction_get = ice_dpll_input_direction, |
1189 | .phase_adjust_get = ice_dpll_pin_phase_adjust_get, |
1190 | .phase_adjust_set = ice_dpll_input_phase_adjust_set, |
1191 | .phase_offset_get = ice_dpll_phase_offset_get, |
1192 | }; |
1193 | |
1194 | static const struct dpll_pin_ops ice_dpll_output_ops = { |
1195 | .frequency_get = ice_dpll_output_frequency_get, |
1196 | .frequency_set = ice_dpll_output_frequency_set, |
1197 | .state_on_dpll_get = ice_dpll_output_state_get, |
1198 | .state_on_dpll_set = ice_dpll_output_state_set, |
1199 | .direction_get = ice_dpll_output_direction, |
1200 | .phase_adjust_get = ice_dpll_pin_phase_adjust_get, |
1201 | .phase_adjust_set = ice_dpll_output_phase_adjust_set, |
1202 | }; |
1203 | |
1204 | static const struct dpll_device_ops ice_dpll_ops = { |
1205 | .lock_status_get = ice_dpll_lock_status_get, |
1206 | .mode_supported = ice_dpll_mode_supported, |
1207 | .mode_get = ice_dpll_mode_get, |
1208 | }; |
1209 | |
1210 | /** |
1211 | * ice_generate_clock_id - generates unique clock_id for registering dpll. |
1212 | * @pf: board private structure |
1213 | * |
1214 | * Generates unique (per board) clock_id for allocation and search of dpll |
1215 | * devices in Linux dpll subsystem. |
1216 | * |
1217 | * Return: generated clock id for the board |
1218 | */ |
1219 | static u64 ice_generate_clock_id(struct ice_pf *pf) |
1220 | { |
1221 | return pci_get_dsn(dev: pf->pdev); |
1222 | } |
1223 | |
1224 | /** |
1225 | * ice_dpll_notify_changes - notify dpll subsystem about changes |
1226 | * @d: pointer do dpll |
1227 | * |
1228 | * Once change detected appropriate event is submitted to the dpll subsystem. |
1229 | */ |
1230 | static void ice_dpll_notify_changes(struct ice_dpll *d) |
1231 | { |
1232 | bool pin_notified = false; |
1233 | |
1234 | if (d->prev_dpll_state != d->dpll_state) { |
1235 | d->prev_dpll_state = d->dpll_state; |
1236 | dpll_device_change_ntf(dpll: d->dpll); |
1237 | } |
1238 | if (d->prev_input != d->active_input) { |
1239 | if (d->prev_input) |
1240 | dpll_pin_change_ntf(pin: d->prev_input); |
1241 | d->prev_input = d->active_input; |
1242 | if (d->active_input) { |
1243 | dpll_pin_change_ntf(pin: d->active_input); |
1244 | pin_notified = true; |
1245 | } |
1246 | } |
1247 | if (d->prev_phase_offset != d->phase_offset) { |
1248 | d->prev_phase_offset = d->phase_offset; |
1249 | if (!pin_notified && d->active_input) |
1250 | dpll_pin_change_ntf(pin: d->active_input); |
1251 | } |
1252 | } |
1253 | |
1254 | /** |
1255 | * ice_dpll_update_state - update dpll state |
1256 | * @pf: pf private structure |
1257 | * @d: pointer to queried dpll device |
1258 | * @init: if function called on initialization of ice dpll |
1259 | * |
1260 | * Poll current state of dpll from hw and update ice_dpll struct. |
1261 | * |
1262 | * Context: Called by kworker under pf->dplls.lock |
1263 | * Return: |
1264 | * * 0 - success |
1265 | * * negative - AQ failure |
1266 | */ |
1267 | static int |
1268 | ice_dpll_update_state(struct ice_pf *pf, struct ice_dpll *d, bool init) |
1269 | { |
1270 | struct ice_dpll_pin *p = NULL; |
1271 | int ret; |
1272 | |
1273 | ret = ice_get_cgu_state(hw: &pf->hw, dpll_idx: d->dpll_idx, last_dpll_state: d->prev_dpll_state, |
1274 | pin: &d->input_idx, ref_state: &d->ref_state, eec_mode: &d->eec_mode, |
1275 | phase_offset: &d->phase_offset, dpll_state: &d->dpll_state); |
1276 | |
1277 | dev_dbg(ice_pf_to_dev(pf), |
1278 | "update dpll=%d, prev_src_idx:%u, src_idx:%u, state:%d, prev:%d mode:%d\n" , |
1279 | d->dpll_idx, d->prev_input_idx, d->input_idx, |
1280 | d->dpll_state, d->prev_dpll_state, d->mode); |
1281 | if (ret) { |
1282 | dev_err(ice_pf_to_dev(pf), |
1283 | "update dpll=%d state failed, ret=%d %s\n" , |
1284 | d->dpll_idx, ret, |
1285 | ice_aq_str(pf->hw.adminq.sq_last_status)); |
1286 | return ret; |
1287 | } |
1288 | if (init) { |
1289 | if (d->dpll_state == DPLL_LOCK_STATUS_LOCKED || |
1290 | d->dpll_state == DPLL_LOCK_STATUS_LOCKED_HO_ACQ) |
1291 | d->active_input = pf->dplls.inputs[d->input_idx].pin; |
1292 | p = &pf->dplls.inputs[d->input_idx]; |
1293 | return ice_dpll_pin_state_update(pf, pin: p, |
1294 | pin_type: ICE_DPLL_PIN_TYPE_INPUT, NULL); |
1295 | } |
1296 | if (d->dpll_state == DPLL_LOCK_STATUS_HOLDOVER || |
1297 | d->dpll_state == DPLL_LOCK_STATUS_UNLOCKED) { |
1298 | d->active_input = NULL; |
1299 | if (d->input_idx != ICE_DPLL_PIN_IDX_INVALID) |
1300 | p = &pf->dplls.inputs[d->input_idx]; |
1301 | d->prev_input_idx = ICE_DPLL_PIN_IDX_INVALID; |
1302 | d->input_idx = ICE_DPLL_PIN_IDX_INVALID; |
1303 | if (!p) |
1304 | return 0; |
1305 | ret = ice_dpll_pin_state_update(pf, pin: p, |
1306 | pin_type: ICE_DPLL_PIN_TYPE_INPUT, NULL); |
1307 | } else if (d->input_idx != d->prev_input_idx) { |
1308 | if (d->prev_input_idx != ICE_DPLL_PIN_IDX_INVALID) { |
1309 | p = &pf->dplls.inputs[d->prev_input_idx]; |
1310 | ice_dpll_pin_state_update(pf, pin: p, |
1311 | pin_type: ICE_DPLL_PIN_TYPE_INPUT, |
1312 | NULL); |
1313 | } |
1314 | if (d->input_idx != ICE_DPLL_PIN_IDX_INVALID) { |
1315 | p = &pf->dplls.inputs[d->input_idx]; |
1316 | d->active_input = p->pin; |
1317 | ice_dpll_pin_state_update(pf, pin: p, |
1318 | pin_type: ICE_DPLL_PIN_TYPE_INPUT, |
1319 | NULL); |
1320 | } |
1321 | d->prev_input_idx = d->input_idx; |
1322 | } |
1323 | |
1324 | return ret; |
1325 | } |
1326 | |
1327 | /** |
1328 | * ice_dpll_periodic_work - DPLLs periodic worker |
1329 | * @work: pointer to kthread_work structure |
1330 | * |
1331 | * DPLLs periodic worker is responsible for polling state of dpll. |
1332 | * Context: Holds pf->dplls.lock |
1333 | */ |
1334 | static void ice_dpll_periodic_work(struct kthread_work *work) |
1335 | { |
1336 | struct ice_dplls *d = container_of(work, struct ice_dplls, work.work); |
1337 | struct ice_pf *pf = container_of(d, struct ice_pf, dplls); |
1338 | struct ice_dpll *de = &pf->dplls.eec; |
1339 | struct ice_dpll *dp = &pf->dplls.pps; |
1340 | int ret; |
1341 | |
1342 | mutex_lock(&pf->dplls.lock); |
1343 | ret = ice_dpll_update_state(pf, d: de, init: false); |
1344 | if (!ret) |
1345 | ret = ice_dpll_update_state(pf, d: dp, init: false); |
1346 | if (ret) { |
1347 | d->cgu_state_acq_err_num++; |
1348 | /* stop rescheduling this worker */ |
1349 | if (d->cgu_state_acq_err_num > |
1350 | ICE_CGU_STATE_ACQ_ERR_THRESHOLD) { |
1351 | dev_err(ice_pf_to_dev(pf), |
1352 | "EEC/PPS DPLLs periodic work disabled\n" ); |
1353 | mutex_unlock(lock: &pf->dplls.lock); |
1354 | return; |
1355 | } |
1356 | } |
1357 | mutex_unlock(lock: &pf->dplls.lock); |
1358 | ice_dpll_notify_changes(d: de); |
1359 | ice_dpll_notify_changes(d: dp); |
1360 | |
1361 | /* Run twice a second or reschedule if update failed */ |
1362 | kthread_queue_delayed_work(worker: d->kworker, dwork: &d->work, |
1363 | delay: ret ? msecs_to_jiffies(m: 10) : |
1364 | msecs_to_jiffies(m: 500)); |
1365 | } |
1366 | |
1367 | /** |
1368 | * ice_dpll_release_pins - release pins resources from dpll subsystem |
1369 | * @pins: pointer to pins array |
1370 | * @count: number of pins |
1371 | * |
1372 | * Release resources of given pins array in the dpll subsystem. |
1373 | */ |
1374 | static void ice_dpll_release_pins(struct ice_dpll_pin *pins, int count) |
1375 | { |
1376 | int i; |
1377 | |
1378 | for (i = 0; i < count; i++) |
1379 | dpll_pin_put(pin: pins[i].pin); |
1380 | } |
1381 | |
1382 | /** |
1383 | * ice_dpll_get_pins - get pins from dpll subsystem |
1384 | * @pf: board private structure |
1385 | * @pins: pointer to pins array |
1386 | * @start_idx: get starts from this pin idx value |
1387 | * @count: number of pins |
1388 | * @clock_id: clock_id of dpll device |
1389 | * |
1390 | * Get pins - allocate - in dpll subsystem, store them in pin field of given |
1391 | * pins array. |
1392 | * |
1393 | * Return: |
1394 | * * 0 - success |
1395 | * * negative - allocation failure reason |
1396 | */ |
1397 | static int |
1398 | ice_dpll_get_pins(struct ice_pf *pf, struct ice_dpll_pin *pins, |
1399 | int start_idx, int count, u64 clock_id) |
1400 | { |
1401 | int i, ret; |
1402 | |
1403 | for (i = 0; i < count; i++) { |
1404 | pins[i].pin = dpll_pin_get(clock_id, dev_driver_id: i + start_idx, THIS_MODULE, |
1405 | prop: &pins[i].prop); |
1406 | if (IS_ERR(ptr: pins[i].pin)) { |
1407 | ret = PTR_ERR(ptr: pins[i].pin); |
1408 | goto release_pins; |
1409 | } |
1410 | } |
1411 | |
1412 | return 0; |
1413 | |
1414 | release_pins: |
1415 | while (--i >= 0) |
1416 | dpll_pin_put(pin: pins[i].pin); |
1417 | return ret; |
1418 | } |
1419 | |
1420 | /** |
1421 | * ice_dpll_unregister_pins - unregister pins from a dpll |
1422 | * @dpll: dpll device pointer |
1423 | * @pins: pointer to pins array |
1424 | * @ops: callback ops registered with the pins |
1425 | * @count: number of pins |
1426 | * |
1427 | * Unregister pins of a given array of pins from given dpll device registered in |
1428 | * dpll subsystem. |
1429 | */ |
1430 | static void |
1431 | ice_dpll_unregister_pins(struct dpll_device *dpll, struct ice_dpll_pin *pins, |
1432 | const struct dpll_pin_ops *ops, int count) |
1433 | { |
1434 | int i; |
1435 | |
1436 | for (i = 0; i < count; i++) |
1437 | dpll_pin_unregister(dpll, pin: pins[i].pin, ops, priv: &pins[i]); |
1438 | } |
1439 | |
1440 | /** |
1441 | * ice_dpll_register_pins - register pins with a dpll |
1442 | * @dpll: dpll pointer to register pins with |
1443 | * @pins: pointer to pins array |
1444 | * @ops: callback ops registered with the pins |
1445 | * @count: number of pins |
1446 | * |
1447 | * Register pins of a given array with given dpll in dpll subsystem. |
1448 | * |
1449 | * Return: |
1450 | * * 0 - success |
1451 | * * negative - registration failure reason |
1452 | */ |
1453 | static int |
1454 | ice_dpll_register_pins(struct dpll_device *dpll, struct ice_dpll_pin *pins, |
1455 | const struct dpll_pin_ops *ops, int count) |
1456 | { |
1457 | int ret, i; |
1458 | |
1459 | for (i = 0; i < count; i++) { |
1460 | ret = dpll_pin_register(dpll, pin: pins[i].pin, ops, priv: &pins[i]); |
1461 | if (ret) |
1462 | goto unregister_pins; |
1463 | } |
1464 | |
1465 | return 0; |
1466 | |
1467 | unregister_pins: |
1468 | while (--i >= 0) |
1469 | dpll_pin_unregister(dpll, pin: pins[i].pin, ops, priv: &pins[i]); |
1470 | return ret; |
1471 | } |
1472 | |
1473 | /** |
1474 | * ice_dpll_deinit_direct_pins - deinitialize direct pins |
1475 | * @cgu: if cgu is present and controlled by this NIC |
1476 | * @pins: pointer to pins array |
1477 | * @count: number of pins |
1478 | * @ops: callback ops registered with the pins |
1479 | * @first: dpll device pointer |
1480 | * @second: dpll device pointer |
1481 | * |
1482 | * If cgu is owned unregister pins from given dplls. |
1483 | * Release pins resources to the dpll subsystem. |
1484 | */ |
1485 | static void |
1486 | ice_dpll_deinit_direct_pins(bool cgu, struct ice_dpll_pin *pins, int count, |
1487 | const struct dpll_pin_ops *ops, |
1488 | struct dpll_device *first, |
1489 | struct dpll_device *second) |
1490 | { |
1491 | if (cgu) { |
1492 | ice_dpll_unregister_pins(dpll: first, pins, ops, count); |
1493 | ice_dpll_unregister_pins(dpll: second, pins, ops, count); |
1494 | } |
1495 | ice_dpll_release_pins(pins, count); |
1496 | } |
1497 | |
1498 | /** |
1499 | * ice_dpll_init_direct_pins - initialize direct pins |
1500 | * @pf: board private structure |
1501 | * @cgu: if cgu is present and controlled by this NIC |
1502 | * @pins: pointer to pins array |
1503 | * @start_idx: on which index shall allocation start in dpll subsystem |
1504 | * @count: number of pins |
1505 | * @ops: callback ops registered with the pins |
1506 | * @first: dpll device pointer |
1507 | * @second: dpll device pointer |
1508 | * |
1509 | * Allocate directly connected pins of a given array in dpll subsystem. |
1510 | * If cgu is owned register allocated pins with given dplls. |
1511 | * |
1512 | * Return: |
1513 | * * 0 - success |
1514 | * * negative - registration failure reason |
1515 | */ |
1516 | static int |
1517 | ice_dpll_init_direct_pins(struct ice_pf *pf, bool cgu, |
1518 | struct ice_dpll_pin *pins, int start_idx, int count, |
1519 | const struct dpll_pin_ops *ops, |
1520 | struct dpll_device *first, struct dpll_device *second) |
1521 | { |
1522 | int ret; |
1523 | |
1524 | ret = ice_dpll_get_pins(pf, pins, start_idx, count, clock_id: pf->dplls.clock_id); |
1525 | if (ret) |
1526 | return ret; |
1527 | if (cgu) { |
1528 | ret = ice_dpll_register_pins(dpll: first, pins, ops, count); |
1529 | if (ret) |
1530 | goto release_pins; |
1531 | ret = ice_dpll_register_pins(dpll: second, pins, ops, count); |
1532 | if (ret) |
1533 | goto unregister_first; |
1534 | } |
1535 | |
1536 | return 0; |
1537 | |
1538 | unregister_first: |
1539 | ice_dpll_unregister_pins(dpll: first, pins, ops, count); |
1540 | release_pins: |
1541 | ice_dpll_release_pins(pins, count); |
1542 | return ret; |
1543 | } |
1544 | |
1545 | /** |
1546 | * ice_dpll_deinit_rclk_pin - release rclk pin resources |
1547 | * @pf: board private structure |
1548 | * |
1549 | * Deregister rclk pin from parent pins and release resources in dpll subsystem. |
1550 | */ |
1551 | static void ice_dpll_deinit_rclk_pin(struct ice_pf *pf) |
1552 | { |
1553 | struct ice_dpll_pin *rclk = &pf->dplls.rclk; |
1554 | struct ice_vsi *vsi = ice_get_main_vsi(pf); |
1555 | struct dpll_pin *parent; |
1556 | int i; |
1557 | |
1558 | for (i = 0; i < rclk->num_parents; i++) { |
1559 | parent = pf->dplls.inputs[rclk->parent_idx[i]].pin; |
1560 | if (!parent) |
1561 | continue; |
1562 | dpll_pin_on_pin_unregister(parent, pin: rclk->pin, |
1563 | ops: &ice_dpll_rclk_ops, priv: rclk); |
1564 | } |
1565 | if (WARN_ON_ONCE(!vsi || !vsi->netdev)) |
1566 | return; |
1567 | netdev_dpll_pin_clear(dev: vsi->netdev); |
1568 | dpll_pin_put(pin: rclk->pin); |
1569 | } |
1570 | |
1571 | /** |
1572 | * ice_dpll_init_rclk_pins - initialize recovered clock pin |
1573 | * @pf: board private structure |
1574 | * @pin: pin to register |
1575 | * @start_idx: on which index shall allocation start in dpll subsystem |
1576 | * @ops: callback ops registered with the pins |
1577 | * |
1578 | * Allocate resource for recovered clock pin in dpll subsystem. Register the |
1579 | * pin with the parents it has in the info. Register pin with the pf's main vsi |
1580 | * netdev. |
1581 | * |
1582 | * Return: |
1583 | * * 0 - success |
1584 | * * negative - registration failure reason |
1585 | */ |
1586 | static int |
1587 | ice_dpll_init_rclk_pins(struct ice_pf *pf, struct ice_dpll_pin *pin, |
1588 | int start_idx, const struct dpll_pin_ops *ops) |
1589 | { |
1590 | struct ice_vsi *vsi = ice_get_main_vsi(pf); |
1591 | struct dpll_pin *parent; |
1592 | int ret, i; |
1593 | |
1594 | ret = ice_dpll_get_pins(pf, pins: pin, start_idx, ICE_DPLL_RCLK_NUM_PER_PF, |
1595 | clock_id: pf->dplls.clock_id); |
1596 | if (ret) |
1597 | return ret; |
1598 | for (i = 0; i < pf->dplls.rclk.num_parents; i++) { |
1599 | parent = pf->dplls.inputs[pf->dplls.rclk.parent_idx[i]].pin; |
1600 | if (!parent) { |
1601 | ret = -ENODEV; |
1602 | goto unregister_pins; |
1603 | } |
1604 | ret = dpll_pin_on_pin_register(parent, pin: pf->dplls.rclk.pin, |
1605 | ops, priv: &pf->dplls.rclk); |
1606 | if (ret) |
1607 | goto unregister_pins; |
1608 | } |
1609 | if (WARN_ON((!vsi || !vsi->netdev))) |
1610 | return -EINVAL; |
1611 | netdev_dpll_pin_set(dev: vsi->netdev, dpll_pin: pf->dplls.rclk.pin); |
1612 | |
1613 | return 0; |
1614 | |
1615 | unregister_pins: |
1616 | while (i) { |
1617 | parent = pf->dplls.inputs[pf->dplls.rclk.parent_idx[--i]].pin; |
1618 | dpll_pin_on_pin_unregister(parent, pin: pf->dplls.rclk.pin, |
1619 | ops: &ice_dpll_rclk_ops, priv: &pf->dplls.rclk); |
1620 | } |
1621 | ice_dpll_release_pins(pins: pin, ICE_DPLL_RCLK_NUM_PER_PF); |
1622 | return ret; |
1623 | } |
1624 | |
1625 | /** |
1626 | * ice_dpll_deinit_pins - deinitialize direct pins |
1627 | * @pf: board private structure |
1628 | * @cgu: if cgu is controlled by this pf |
1629 | * |
1630 | * If cgu is owned unregister directly connected pins from the dplls. |
1631 | * Release resources of directly connected pins from the dpll subsystem. |
1632 | */ |
1633 | static void ice_dpll_deinit_pins(struct ice_pf *pf, bool cgu) |
1634 | { |
1635 | struct ice_dpll_pin *outputs = pf->dplls.outputs; |
1636 | struct ice_dpll_pin *inputs = pf->dplls.inputs; |
1637 | int num_outputs = pf->dplls.num_outputs; |
1638 | int num_inputs = pf->dplls.num_inputs; |
1639 | struct ice_dplls *d = &pf->dplls; |
1640 | struct ice_dpll *de = &d->eec; |
1641 | struct ice_dpll *dp = &d->pps; |
1642 | |
1643 | ice_dpll_deinit_rclk_pin(pf); |
1644 | if (cgu) { |
1645 | ice_dpll_unregister_pins(dpll: dp->dpll, pins: inputs, ops: &ice_dpll_input_ops, |
1646 | count: num_inputs); |
1647 | ice_dpll_unregister_pins(dpll: de->dpll, pins: inputs, ops: &ice_dpll_input_ops, |
1648 | count: num_inputs); |
1649 | } |
1650 | ice_dpll_release_pins(pins: inputs, count: num_inputs); |
1651 | if (cgu) { |
1652 | ice_dpll_unregister_pins(dpll: dp->dpll, pins: outputs, |
1653 | ops: &ice_dpll_output_ops, count: num_outputs); |
1654 | ice_dpll_unregister_pins(dpll: de->dpll, pins: outputs, |
1655 | ops: &ice_dpll_output_ops, count: num_outputs); |
1656 | ice_dpll_release_pins(pins: outputs, count: num_outputs); |
1657 | } |
1658 | } |
1659 | |
1660 | /** |
1661 | * ice_dpll_init_pins - init pins and register pins with a dplls |
1662 | * @pf: board private structure |
1663 | * @cgu: if cgu is present and controlled by this NIC |
1664 | * |
1665 | * Initialize directly connected pf's pins within pf's dplls in a Linux dpll |
1666 | * subsystem. |
1667 | * |
1668 | * Return: |
1669 | * * 0 - success |
1670 | * * negative - initialization failure reason |
1671 | */ |
1672 | static int ice_dpll_init_pins(struct ice_pf *pf, bool cgu) |
1673 | { |
1674 | u32 rclk_idx; |
1675 | int ret; |
1676 | |
1677 | ret = ice_dpll_init_direct_pins(pf, cgu, pins: pf->dplls.inputs, start_idx: 0, |
1678 | count: pf->dplls.num_inputs, |
1679 | ops: &ice_dpll_input_ops, |
1680 | first: pf->dplls.eec.dpll, second: pf->dplls.pps.dpll); |
1681 | if (ret) |
1682 | return ret; |
1683 | if (cgu) { |
1684 | ret = ice_dpll_init_direct_pins(pf, cgu, pins: pf->dplls.outputs, |
1685 | start_idx: pf->dplls.num_inputs, |
1686 | count: pf->dplls.num_outputs, |
1687 | ops: &ice_dpll_output_ops, |
1688 | first: pf->dplls.eec.dpll, |
1689 | second: pf->dplls.pps.dpll); |
1690 | if (ret) |
1691 | goto deinit_inputs; |
1692 | } |
1693 | rclk_idx = pf->dplls.num_inputs + pf->dplls.num_outputs + pf->hw.pf_id; |
1694 | ret = ice_dpll_init_rclk_pins(pf, pin: &pf->dplls.rclk, start_idx: rclk_idx, |
1695 | ops: &ice_dpll_rclk_ops); |
1696 | if (ret) |
1697 | goto deinit_outputs; |
1698 | |
1699 | return 0; |
1700 | deinit_outputs: |
1701 | ice_dpll_deinit_direct_pins(cgu, pins: pf->dplls.outputs, |
1702 | count: pf->dplls.num_outputs, |
1703 | ops: &ice_dpll_output_ops, first: pf->dplls.pps.dpll, |
1704 | second: pf->dplls.eec.dpll); |
1705 | deinit_inputs: |
1706 | ice_dpll_deinit_direct_pins(cgu, pins: pf->dplls.inputs, count: pf->dplls.num_inputs, |
1707 | ops: &ice_dpll_input_ops, first: pf->dplls.pps.dpll, |
1708 | second: pf->dplls.eec.dpll); |
1709 | return ret; |
1710 | } |
1711 | |
1712 | /** |
1713 | * ice_dpll_deinit_dpll - deinitialize dpll device |
1714 | * @pf: board private structure |
1715 | * @d: pointer to ice_dpll |
1716 | * @cgu: if cgu is present and controlled by this NIC |
1717 | * |
1718 | * If cgu is owned unregister the dpll from dpll subsystem. |
1719 | * Release resources of dpll device from dpll subsystem. |
1720 | */ |
1721 | static void |
1722 | ice_dpll_deinit_dpll(struct ice_pf *pf, struct ice_dpll *d, bool cgu) |
1723 | { |
1724 | if (cgu) |
1725 | dpll_device_unregister(dpll: d->dpll, ops: &ice_dpll_ops, priv: d); |
1726 | dpll_device_put(dpll: d->dpll); |
1727 | } |
1728 | |
1729 | /** |
1730 | * ice_dpll_init_dpll - initialize dpll device in dpll subsystem |
1731 | * @pf: board private structure |
1732 | * @d: dpll to be initialized |
1733 | * @cgu: if cgu is present and controlled by this NIC |
1734 | * @type: type of dpll being initialized |
1735 | * |
1736 | * Allocate dpll instance for this board in dpll subsystem, if cgu is controlled |
1737 | * by this NIC, register dpll with the callback ops. |
1738 | * |
1739 | * Return: |
1740 | * * 0 - success |
1741 | * * negative - initialization failure reason |
1742 | */ |
1743 | static int |
1744 | ice_dpll_init_dpll(struct ice_pf *pf, struct ice_dpll *d, bool cgu, |
1745 | enum dpll_type type) |
1746 | { |
1747 | u64 clock_id = pf->dplls.clock_id; |
1748 | int ret; |
1749 | |
1750 | d->dpll = dpll_device_get(clock_id, dev_driver_id: d->dpll_idx, THIS_MODULE); |
1751 | if (IS_ERR(ptr: d->dpll)) { |
1752 | ret = PTR_ERR(ptr: d->dpll); |
1753 | dev_err(ice_pf_to_dev(pf), |
1754 | "dpll_device_get failed (%p) err=%d\n" , d, ret); |
1755 | return ret; |
1756 | } |
1757 | d->pf = pf; |
1758 | if (cgu) { |
1759 | ret = dpll_device_register(dpll: d->dpll, type, ops: &ice_dpll_ops, priv: d); |
1760 | if (ret) { |
1761 | dpll_device_put(dpll: d->dpll); |
1762 | return ret; |
1763 | } |
1764 | } |
1765 | |
1766 | return 0; |
1767 | } |
1768 | |
1769 | /** |
1770 | * ice_dpll_deinit_worker - deinitialize dpll kworker |
1771 | * @pf: board private structure |
1772 | * |
1773 | * Stop dpll's kworker, release it's resources. |
1774 | */ |
1775 | static void ice_dpll_deinit_worker(struct ice_pf *pf) |
1776 | { |
1777 | struct ice_dplls *d = &pf->dplls; |
1778 | |
1779 | kthread_cancel_delayed_work_sync(work: &d->work); |
1780 | kthread_destroy_worker(worker: d->kworker); |
1781 | } |
1782 | |
1783 | /** |
1784 | * ice_dpll_init_worker - Initialize DPLLs periodic worker |
1785 | * @pf: board private structure |
1786 | * |
1787 | * Create and start DPLLs periodic worker. |
1788 | * |
1789 | * Context: Shall be called after pf->dplls.lock is initialized. |
1790 | * Return: |
1791 | * * 0 - success |
1792 | * * negative - create worker failure |
1793 | */ |
1794 | static int ice_dpll_init_worker(struct ice_pf *pf) |
1795 | { |
1796 | struct ice_dplls *d = &pf->dplls; |
1797 | struct kthread_worker *kworker; |
1798 | |
1799 | ice_dpll_update_state(pf, d: &d->eec, init: true); |
1800 | ice_dpll_update_state(pf, d: &d->pps, init: true); |
1801 | kthread_init_delayed_work(&d->work, ice_dpll_periodic_work); |
1802 | kworker = kthread_create_worker(flags: 0, namefmt: "ice-dplls-%s" , |
1803 | dev_name(ice_pf_to_dev(pf))); |
1804 | if (IS_ERR(ptr: kworker)) |
1805 | return PTR_ERR(ptr: kworker); |
1806 | d->kworker = kworker; |
1807 | d->cgu_state_acq_err_num = 0; |
1808 | kthread_queue_delayed_work(worker: d->kworker, dwork: &d->work, delay: 0); |
1809 | |
1810 | return 0; |
1811 | } |
1812 | |
1813 | /** |
1814 | * ice_dpll_init_info_direct_pins - initializes direct pins info |
1815 | * @pf: board private structure |
1816 | * @pin_type: type of pins being initialized |
1817 | * |
1818 | * Init information for directly connected pins, cache them in pf's pins |
1819 | * structures. |
1820 | * |
1821 | * Return: |
1822 | * * 0 - success |
1823 | * * negative - init failure reason |
1824 | */ |
1825 | static int |
1826 | ice_dpll_init_info_direct_pins(struct ice_pf *pf, |
1827 | enum ice_dpll_pin_type pin_type) |
1828 | { |
1829 | struct ice_dpll *de = &pf->dplls.eec, *dp = &pf->dplls.pps; |
1830 | int num_pins, i, ret = -EINVAL; |
1831 | struct ice_hw *hw = &pf->hw; |
1832 | struct ice_dpll_pin *pins; |
1833 | u8 freq_supp_num; |
1834 | bool input; |
1835 | |
1836 | switch (pin_type) { |
1837 | case ICE_DPLL_PIN_TYPE_INPUT: |
1838 | pins = pf->dplls.inputs; |
1839 | num_pins = pf->dplls.num_inputs; |
1840 | input = true; |
1841 | break; |
1842 | case ICE_DPLL_PIN_TYPE_OUTPUT: |
1843 | pins = pf->dplls.outputs; |
1844 | num_pins = pf->dplls.num_outputs; |
1845 | input = false; |
1846 | break; |
1847 | default: |
1848 | return -EINVAL; |
1849 | } |
1850 | |
1851 | for (i = 0; i < num_pins; i++) { |
1852 | pins[i].idx = i; |
1853 | pins[i].prop.board_label = ice_cgu_get_pin_name(hw, pin: i, input); |
1854 | pins[i].prop.type = ice_cgu_get_pin_type(hw, pin: i, input); |
1855 | if (input) { |
1856 | ret = ice_aq_get_cgu_ref_prio(hw, dpll_num: de->dpll_idx, ref_idx: i, |
1857 | ref_prio: &de->input_prio[i]); |
1858 | if (ret) |
1859 | return ret; |
1860 | ret = ice_aq_get_cgu_ref_prio(hw, dpll_num: dp->dpll_idx, ref_idx: i, |
1861 | ref_prio: &dp->input_prio[i]); |
1862 | if (ret) |
1863 | return ret; |
1864 | pins[i].prop.capabilities |= |
1865 | DPLL_PIN_CAPABILITIES_PRIORITY_CAN_CHANGE; |
1866 | pins[i].prop.phase_range.min = |
1867 | pf->dplls.input_phase_adj_max; |
1868 | pins[i].prop.phase_range.max = |
1869 | -pf->dplls.input_phase_adj_max; |
1870 | } else { |
1871 | pins[i].prop.phase_range.min = |
1872 | pf->dplls.output_phase_adj_max; |
1873 | pins[i].prop.phase_range.max = |
1874 | -pf->dplls.output_phase_adj_max; |
1875 | } |
1876 | pins[i].prop.capabilities |= |
1877 | DPLL_PIN_CAPABILITIES_STATE_CAN_CHANGE; |
1878 | ret = ice_dpll_pin_state_update(pf, pin: &pins[i], pin_type, NULL); |
1879 | if (ret) |
1880 | return ret; |
1881 | pins[i].prop.freq_supported = |
1882 | ice_cgu_get_pin_freq_supp(hw, pin: i, input, num: &freq_supp_num); |
1883 | pins[i].prop.freq_supported_num = freq_supp_num; |
1884 | pins[i].pf = pf; |
1885 | } |
1886 | |
1887 | return ret; |
1888 | } |
1889 | |
1890 | /** |
1891 | * ice_dpll_init_info_rclk_pin - initializes rclk pin information |
1892 | * @pf: board private structure |
1893 | * |
1894 | * Init information for rclk pin, cache them in pf->dplls.rclk. |
1895 | * |
1896 | * Return: |
1897 | * * 0 - success |
1898 | * * negative - init failure reason |
1899 | */ |
1900 | static int ice_dpll_init_info_rclk_pin(struct ice_pf *pf) |
1901 | { |
1902 | struct ice_dpll_pin *pin = &pf->dplls.rclk; |
1903 | |
1904 | pin->prop.type = DPLL_PIN_TYPE_SYNCE_ETH_PORT; |
1905 | pin->prop.capabilities |= DPLL_PIN_CAPABILITIES_STATE_CAN_CHANGE; |
1906 | pin->pf = pf; |
1907 | |
1908 | return ice_dpll_pin_state_update(pf, pin, |
1909 | pin_type: ICE_DPLL_PIN_TYPE_RCLK_INPUT, NULL); |
1910 | } |
1911 | |
1912 | /** |
1913 | * ice_dpll_init_pins_info - init pins info wrapper |
1914 | * @pf: board private structure |
1915 | * @pin_type: type of pins being initialized |
1916 | * |
1917 | * Wraps functions for pin initialization. |
1918 | * |
1919 | * Return: |
1920 | * * 0 - success |
1921 | * * negative - init failure reason |
1922 | */ |
1923 | static int |
1924 | ice_dpll_init_pins_info(struct ice_pf *pf, enum ice_dpll_pin_type pin_type) |
1925 | { |
1926 | switch (pin_type) { |
1927 | case ICE_DPLL_PIN_TYPE_INPUT: |
1928 | case ICE_DPLL_PIN_TYPE_OUTPUT: |
1929 | return ice_dpll_init_info_direct_pins(pf, pin_type); |
1930 | case ICE_DPLL_PIN_TYPE_RCLK_INPUT: |
1931 | return ice_dpll_init_info_rclk_pin(pf); |
1932 | default: |
1933 | return -EINVAL; |
1934 | } |
1935 | } |
1936 | |
1937 | /** |
1938 | * ice_dpll_deinit_info - release memory allocated for pins info |
1939 | * @pf: board private structure |
1940 | * |
1941 | * Release memory allocated for pins by ice_dpll_init_info function. |
1942 | */ |
1943 | static void ice_dpll_deinit_info(struct ice_pf *pf) |
1944 | { |
1945 | kfree(objp: pf->dplls.inputs); |
1946 | kfree(objp: pf->dplls.outputs); |
1947 | kfree(objp: pf->dplls.eec.input_prio); |
1948 | kfree(objp: pf->dplls.pps.input_prio); |
1949 | } |
1950 | |
1951 | /** |
1952 | * ice_dpll_init_info - prepare pf's dpll information structure |
1953 | * @pf: board private structure |
1954 | * @cgu: if cgu is present and controlled by this NIC |
1955 | * |
1956 | * Acquire (from HW) and set basic dpll information (on pf->dplls struct). |
1957 | * |
1958 | * Return: |
1959 | * * 0 - success |
1960 | * * negative - init failure reason |
1961 | */ |
1962 | static int ice_dpll_init_info(struct ice_pf *pf, bool cgu) |
1963 | { |
1964 | struct ice_aqc_get_cgu_abilities abilities; |
1965 | struct ice_dpll *de = &pf->dplls.eec; |
1966 | struct ice_dpll *dp = &pf->dplls.pps; |
1967 | struct ice_dplls *d = &pf->dplls; |
1968 | struct ice_hw *hw = &pf->hw; |
1969 | int ret, alloc_size, i; |
1970 | |
1971 | d->clock_id = ice_generate_clock_id(pf); |
1972 | ret = ice_aq_get_cgu_abilities(hw, abilities: &abilities); |
1973 | if (ret) { |
1974 | dev_err(ice_pf_to_dev(pf), |
1975 | "err:%d %s failed to read cgu abilities\n" , |
1976 | ret, ice_aq_str(hw->adminq.sq_last_status)); |
1977 | return ret; |
1978 | } |
1979 | |
1980 | de->dpll_idx = abilities.eec_dpll_idx; |
1981 | dp->dpll_idx = abilities.pps_dpll_idx; |
1982 | d->num_inputs = abilities.num_inputs; |
1983 | d->num_outputs = abilities.num_outputs; |
1984 | d->input_phase_adj_max = le32_to_cpu(abilities.max_in_phase_adj); |
1985 | d->output_phase_adj_max = le32_to_cpu(abilities.max_out_phase_adj); |
1986 | |
1987 | alloc_size = sizeof(*d->inputs) * d->num_inputs; |
1988 | d->inputs = kzalloc(size: alloc_size, GFP_KERNEL); |
1989 | if (!d->inputs) |
1990 | return -ENOMEM; |
1991 | |
1992 | alloc_size = sizeof(*de->input_prio) * d->num_inputs; |
1993 | de->input_prio = kzalloc(size: alloc_size, GFP_KERNEL); |
1994 | if (!de->input_prio) |
1995 | return -ENOMEM; |
1996 | |
1997 | dp->input_prio = kzalloc(size: alloc_size, GFP_KERNEL); |
1998 | if (!dp->input_prio) |
1999 | return -ENOMEM; |
2000 | |
2001 | ret = ice_dpll_init_pins_info(pf, pin_type: ICE_DPLL_PIN_TYPE_INPUT); |
2002 | if (ret) |
2003 | goto deinit_info; |
2004 | |
2005 | if (cgu) { |
2006 | alloc_size = sizeof(*d->outputs) * d->num_outputs; |
2007 | d->outputs = kzalloc(size: alloc_size, GFP_KERNEL); |
2008 | if (!d->outputs) { |
2009 | ret = -ENOMEM; |
2010 | goto deinit_info; |
2011 | } |
2012 | |
2013 | ret = ice_dpll_init_pins_info(pf, pin_type: ICE_DPLL_PIN_TYPE_OUTPUT); |
2014 | if (ret) |
2015 | goto deinit_info; |
2016 | } |
2017 | |
2018 | ret = ice_get_cgu_rclk_pin_info(hw: &pf->hw, base_idx: &d->base_rclk_idx, |
2019 | pin_num: &pf->dplls.rclk.num_parents); |
2020 | if (ret) |
2021 | return ret; |
2022 | for (i = 0; i < pf->dplls.rclk.num_parents; i++) |
2023 | pf->dplls.rclk.parent_idx[i] = d->base_rclk_idx + i; |
2024 | ret = ice_dpll_init_pins_info(pf, pin_type: ICE_DPLL_PIN_TYPE_RCLK_INPUT); |
2025 | if (ret) |
2026 | return ret; |
2027 | de->mode = DPLL_MODE_AUTOMATIC; |
2028 | dp->mode = DPLL_MODE_AUTOMATIC; |
2029 | |
2030 | dev_dbg(ice_pf_to_dev(pf), |
2031 | "%s - success, inputs:%u, outputs:%u rclk-parents:%u\n" , |
2032 | __func__, d->num_inputs, d->num_outputs, d->rclk.num_parents); |
2033 | |
2034 | return 0; |
2035 | |
2036 | deinit_info: |
2037 | dev_err(ice_pf_to_dev(pf), |
2038 | "%s - fail: d->inputs:%p, de->input_prio:%p, dp->input_prio:%p, d->outputs:%p\n" , |
2039 | __func__, d->inputs, de->input_prio, |
2040 | dp->input_prio, d->outputs); |
2041 | ice_dpll_deinit_info(pf); |
2042 | return ret; |
2043 | } |
2044 | |
2045 | /** |
2046 | * ice_dpll_deinit - Disable the driver/HW support for dpll subsystem |
2047 | * the dpll device. |
2048 | * @pf: board private structure |
2049 | * |
2050 | * Handles the cleanup work required after dpll initialization, freeing |
2051 | * resources and unregistering the dpll, pin and all resources used for |
2052 | * handling them. |
2053 | * |
2054 | * Context: Destroys pf->dplls.lock mutex. Call only if ICE_FLAG_DPLL was set. |
2055 | */ |
2056 | void ice_dpll_deinit(struct ice_pf *pf) |
2057 | { |
2058 | bool cgu = ice_is_feature_supported(pf, f: ICE_F_CGU); |
2059 | |
2060 | clear_bit(nr: ICE_FLAG_DPLL, addr: pf->flags); |
2061 | if (cgu) |
2062 | ice_dpll_deinit_worker(pf); |
2063 | |
2064 | ice_dpll_deinit_pins(pf, cgu); |
2065 | ice_dpll_deinit_dpll(pf, d: &pf->dplls.pps, cgu); |
2066 | ice_dpll_deinit_dpll(pf, d: &pf->dplls.eec, cgu); |
2067 | ice_dpll_deinit_info(pf); |
2068 | mutex_destroy(lock: &pf->dplls.lock); |
2069 | } |
2070 | |
2071 | /** |
2072 | * ice_dpll_init - initialize support for dpll subsystem |
2073 | * @pf: board private structure |
2074 | * |
2075 | * Set up the device dplls, register them and pins connected within Linux dpll |
2076 | * subsystem. Allow userspace to obtain state of DPLL and handling of DPLL |
2077 | * configuration requests. |
2078 | * |
2079 | * Context: Initializes pf->dplls.lock mutex. |
2080 | */ |
2081 | void ice_dpll_init(struct ice_pf *pf) |
2082 | { |
2083 | bool cgu = ice_is_feature_supported(pf, f: ICE_F_CGU); |
2084 | struct ice_dplls *d = &pf->dplls; |
2085 | int err = 0; |
2086 | |
2087 | err = ice_dpll_init_info(pf, cgu); |
2088 | if (err) |
2089 | goto err_exit; |
2090 | err = ice_dpll_init_dpll(pf, d: &pf->dplls.eec, cgu, type: DPLL_TYPE_EEC); |
2091 | if (err) |
2092 | goto deinit_info; |
2093 | err = ice_dpll_init_dpll(pf, d: &pf->dplls.pps, cgu, type: DPLL_TYPE_PPS); |
2094 | if (err) |
2095 | goto deinit_eec; |
2096 | err = ice_dpll_init_pins(pf, cgu); |
2097 | if (err) |
2098 | goto deinit_pps; |
2099 | mutex_init(&d->lock); |
2100 | if (cgu) { |
2101 | err = ice_dpll_init_worker(pf); |
2102 | if (err) |
2103 | goto deinit_pins; |
2104 | } |
2105 | set_bit(nr: ICE_FLAG_DPLL, addr: pf->flags); |
2106 | |
2107 | return; |
2108 | |
2109 | deinit_pins: |
2110 | ice_dpll_deinit_pins(pf, cgu); |
2111 | deinit_pps: |
2112 | ice_dpll_deinit_dpll(pf, d: &pf->dplls.pps, cgu); |
2113 | deinit_eec: |
2114 | ice_dpll_deinit_dpll(pf, d: &pf->dplls.eec, cgu); |
2115 | deinit_info: |
2116 | ice_dpll_deinit_info(pf); |
2117 | err_exit: |
2118 | mutex_destroy(lock: &d->lock); |
2119 | dev_warn(ice_pf_to_dev(pf), "DPLLs init failure err:%d\n" , err); |
2120 | } |
2121 | |