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