summaryrefslogtreecommitdiff
path: root/drivers/net/ethernet/intel/ice/ice_dpll.h
blob: bce0bea9a664bc28203c5085e48bc62ae16334bb (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
/* SPDX-License-Identifier: GPL-2.0 */
/* Copyright (C) 2022, Intel Corporation. */

#ifndef _ICE_DPLL_H_
#define _ICE_DPLL_H_

#include "ice.h"

#define ICE_DPLL_RCLK_NUM_MAX	4
#define ICE_DPLL_TXCLK_NUM_MAX	2
#define E825_EXT_EREF_PIN_IDX	0
#define E825_EXT_SYNCE_PIN_IDX	1

#define ICE_CGU_R10			0x28
#define ICE_CGU_R10_SYNCE_CLKO_SEL	GENMASK(8, 5)
#define ICE_CGU_R10_SYNCE_CLKODIV_M1	GENMASK(13, 9)
#define ICE_CGU_R10_SYNCE_CLKODIV_LOAD	BIT(14)
#define ICE_CGU_R10_SYNCE_DCK_RST	BIT(15)
#define ICE_CGU_R10_SYNCE_ETHCLKO_SEL	GENMASK(18, 16)
#define ICE_CGU_R10_SYNCE_ETHDIV_M1	GENMASK(23, 19)
#define ICE_CGU_R10_SYNCE_ETHDIV_LOAD	BIT(24)
#define ICE_CGU_R10_SYNCE_DCK2_RST	BIT(25)
#define ICE_CGU_R10_SYNCE_S_REF_CLK	GENMASK(31, 27)

#define ICE_CGU_R11			0x2C
#define ICE_CGU_R11_SYNCE_S_BYP_CLK	GENMASK(6, 1)

#define ICE_CGU_BYPASS_MUX_OFFSET_E825C	3

/**
 * enum ice_dpll_pin_sw - enumerate ice software pin indices:
 * @ICE_DPLL_PIN_SW_1_IDX: index of first SW pin
 * @ICE_DPLL_PIN_SW_2_IDX: index of second SW pin
 * @ICE_DPLL_PIN_SW_NUM: number of SW pins in pair
 */
enum ice_dpll_pin_sw {
	ICE_DPLL_PIN_SW_1_IDX,
	ICE_DPLL_PIN_SW_2_IDX,
	ICE_DPLL_PIN_SW_NUM
};

struct ice_dpll_pin_work {
	struct work_struct work;
	unsigned long action;
	struct ice_dpll_pin *pin;
};

/** ice_dpll_pin - store info about pins
 * @pin: dpll pin structure
 * @pf: pointer to pf, which has registered the dpll_pin
 * @tracker: reference count tracker
 * @idx: ice pin private idx
 * @num_parents: hols number of parent pins
 * @parent_idx: hold indexes of parent pins
 * @flags: pin flags returned from HW
 * @state: state of a pin
 * @prop: pin properties
 * @freq: current frequency of a pin
 * @phase_adjust: current phase adjust value
 * @phase_offset: monitored phase offset value
 * @ref_sync: store id of reference sync pin
 */
struct ice_dpll_pin {
	struct dpll_pin *pin;
	struct ice_pf *pf;
	dpll_tracker tracker;
	struct fwnode_handle *fwnode;
	struct notifier_block nb;
	u8 idx;
	u8 num_parents;
	u8 parent_idx[ICE_DPLL_RCLK_NUM_MAX];
	u8 flags[ICE_DPLL_RCLK_NUM_MAX];
	u8 state[ICE_DPLL_RCLK_NUM_MAX];
	struct dpll_pin_properties prop;
	u32 freq;
	s32 phase_adjust;
	struct ice_dpll_pin *input;
	struct ice_dpll_pin *output;
	enum dpll_pin_direction direction;
	s64 phase_offset;
	u8 status;
	u8 ref_sync;
	bool active;
	bool hidden;
	enum ice_e825c_ref_clk tx_ref_src;
};

/** ice_dpll - store info required for DPLL control
 * @dpll: pointer to dpll dev
 * @pf: pointer to pf, which has registered the dpll_device
 * @tracker: reference count tracker
 * @dpll_idx: index of dpll on the NIC
 * @input_idx: currently selected input index
 * @prev_input_idx: previously selected input index
 * @ref_state: state of dpll reference signals
 * @eec_mode: eec_mode dpll is configured for
 * @phase_offset: phase offset of active pin vs dpll signal
 * @prev_phase_offset: previous phase offset of active pin vs dpll signal
 * @input_prio: priorities of each input
 * @dpll_state: current dpll sync state
 * @prev_dpll_state: last dpll sync state
 * @phase_offset_monitor_period: period for phase offset monitor read frequency
 * @active_input: pointer to active input pin
 * @prev_input: pointer to previous active input pin
 * @ops: holds the registered ops
 */
struct ice_dpll {
	struct dpll_device *dpll;
	struct ice_pf *pf;
	dpll_tracker tracker;
	u8 dpll_idx;
	u8 input_idx;
	u8 prev_input_idx;
	u8 ref_state;
	u8 eec_mode;
	s64 phase_offset;
	s64 prev_phase_offset;
	u8 *input_prio;
	enum dpll_lock_status dpll_state;
	enum dpll_lock_status prev_dpll_state;
	enum dpll_mode mode;
	u32 phase_offset_monitor_period;
	struct dpll_pin *active_input;
	struct dpll_pin *prev_input;
	const struct dpll_device_ops *ops;
};

/** ice_dplls - store info required for CCU (clock controlling unit)
 * @kworker: periodic worker
 * @work: periodic work
 * @wq: workqueue used to schedule DPLL-related deferred work
 * @lock: protects DPLL configuration (see Locking below)
 * @eec: pointer to EEC dpll dev
 * @pps: pointer to PPS dpll dev
 * @txc: pointer to TXC dpll dev
 * @tspll: pointer to TSPLL dpll dev (E825 only)
 * @inputs: input pins pointer
 * @outputs: output pins pointer
 * @rclk: recovered pins pointer
 * @txclks: TX clock reference pins pointer
 * @tspll_in: TSPLL TIME_REF fwnode input pin (E825 only)
 * @num_inputs: number of input pins available on dpll
 * @num_outputs: number of output pins available on dpll
 * @cgu_state_acq_err_num: number of errors returned during periodic work
 * @base_rclk_idx: idx of first pin used for clock revocery pins
 * @clock_id: clock_id of dplls
 * @input_phase_adj_max: max phase adjust value for an input pins
 * @output_phase_adj_max: max phase adjust value for an output pins
 * @periodic_counter: counter of periodic work executions
 * @generic: true when generic DPLL ops are used
 * @txclk_work: deferred TX reference clock switch worker
 * @txclk_switch_requested: a TX ref clock switch is queued in @txclk_work
 * @txclk_notify_rwsem: drains in-flight TXCLK notifications on teardown
 *
 * Locking:
 *   Acquisition order (top to bottom):
 *
 *     txclk_notify_rwsem (read)
 *       -> pf->dplls.lock
 *         -> ctrl_pf->dplls.lock
 *
 *   - @lock serializes all DPLL state mutations on this PF. When the
 *     controlling PF's lock must also be taken (e.g. updating the shared
 *     tx_refclks usage map), acquire pf->dplls.lock first, then
 *     ctrl_pf->dplls.lock. Skip the second acquire when pf == ctrl_pf
 *     to avoid recursive locking.
 *   - @txclk_notify_rwsem is held for read across
 *     ice_txclk_update_and_notify(), including the out-of-lock
 *     dpll_*_change_ntf() calls. ice_dpll_deinit() takes the write side
 *     standalone (not nested under any other lock) to drain in-flight
 *     readers before pins and the TXC DPLL device are freed.
 */
struct ice_dplls {
	struct kthread_worker *kworker;
	struct kthread_delayed_work work;
	struct workqueue_struct *wq;
	struct mutex lock;
	struct completion dpll_init;
	struct ice_dpll eec;
	struct ice_dpll pps;
	struct ice_dpll txc;
	struct ice_dpll tspll;
	struct ice_dpll_pin *inputs;
	struct ice_dpll_pin *outputs;
	struct ice_dpll_pin sma[ICE_DPLL_PIN_SW_NUM];
	struct ice_dpll_pin ufl[ICE_DPLL_PIN_SW_NUM];
	struct ice_dpll_pin rclk;
	struct ice_dpll_pin txclks[ICE_DPLL_TXCLK_NUM_MAX];
	struct ice_dpll_pin tspll_in;
	u8 num_inputs;
	u8 num_outputs;
	u8 sma_data;
	u8 base_rclk_idx;
	int cgu_state_acq_err_num;
	u64 clock_id;
	s32 input_phase_adj_max;
	s32 output_phase_adj_max;
	u32 periodic_counter;
	bool generic;
	struct work_struct txclk_work;
	bool txclk_switch_requested;
	struct rw_semaphore txclk_notify_rwsem;
};

#if IS_ENABLED(CONFIG_PTP_1588_CLOCK)
void ice_dpll_init(struct ice_pf *pf);
void ice_dpll_deinit(struct ice_pf *pf);
#else
static inline void ice_dpll_init(struct ice_pf *pf) { }
static inline void ice_dpll_deinit(struct ice_pf *pf) { }
#endif

#endif