1 // SPDX-License-Identifier: GPL-2.0
2 /* Marvell CN10K RPM driver
3 *
4 * Copyright (C) 2020 Marvell.
5 *
6 */
7
8 #include "cgx.h"
9 #include "lmac_common.h"
10
11 static struct mac_ops rpm_mac_ops = {
12 .name = "rpm",
13 .csr_offset = 0x4e00,
14 .lmac_offset = 20,
15 .int_register = RPMX_CMRX_SW_INT,
16 .int_set_reg = RPMX_CMRX_SW_INT_ENA_W1S,
17 .irq_offset = 1,
18 .int_ena_bit = BIT_ULL(0),
19 .lmac_fwi = RPM_LMAC_FWI,
20 .non_contiguous_serdes_lane = true,
21 .rx_stats_cnt = 43,
22 .tx_stats_cnt = 34,
23 .get_nr_lmacs = rpm_get_nr_lmacs,
24 .get_lmac_type = rpm_get_lmac_type,
25 .lmac_fifo_len = rpm_get_lmac_fifo_len,
26 .mac_lmac_intl_lbk = rpm_lmac_internal_loopback,
27 .mac_get_rx_stats = rpm_get_rx_stats,
28 .mac_get_tx_stats = rpm_get_tx_stats,
29 .mac_enadis_rx_pause_fwding = rpm_lmac_enadis_rx_pause_fwding,
30 .mac_get_pause_frm_status = rpm_lmac_get_pause_frm_status,
31 .mac_enadis_pause_frm = rpm_lmac_enadis_pause_frm,
32 .mac_pause_frm_config = rpm_lmac_pause_frm_config,
33 .mac_enadis_ptp_config = rpm_lmac_ptp_config,
34 .mac_rx_tx_enable = rpm_lmac_rx_tx_enable,
35 .mac_tx_enable = rpm_lmac_tx_enable,
36 };
37
rpm_get_mac_ops(void)38 struct mac_ops *rpm_get_mac_ops(void)
39 {
40 return &rpm_mac_ops;
41 }
42
rpm_write(rpm_t * rpm,u64 lmac,u64 offset,u64 val)43 static void rpm_write(rpm_t *rpm, u64 lmac, u64 offset, u64 val)
44 {
45 cgx_write(rpm, lmac, offset, val);
46 }
47
rpm_read(rpm_t * rpm,u64 lmac,u64 offset)48 static u64 rpm_read(rpm_t *rpm, u64 lmac, u64 offset)
49 {
50 return cgx_read(rpm, lmac, offset);
51 }
52
rpm_get_nr_lmacs(void * rpmd)53 int rpm_get_nr_lmacs(void *rpmd)
54 {
55 rpm_t *rpm = rpmd;
56
57 return hweight8(rpm_read(rpm, 0, CGXX_CMRX_RX_LMACS) & 0xFULL);
58 }
59
rpm_lmac_tx_enable(void * rpmd,int lmac_id,bool enable)60 int rpm_lmac_tx_enable(void *rpmd, int lmac_id, bool enable)
61 {
62 rpm_t *rpm = rpmd;
63 u64 cfg, last;
64
65 if (!is_lmac_valid(rpm, lmac_id))
66 return -ENODEV;
67
68 cfg = rpm_read(rpm, lmac_id, RPMX_MTI_MAC100X_COMMAND_CONFIG);
69 last = cfg;
70 if (enable)
71 cfg |= RPM_TX_EN;
72 else
73 cfg &= ~(RPM_TX_EN);
74
75 if (cfg != last)
76 rpm_write(rpm, lmac_id, RPMX_MTI_MAC100X_COMMAND_CONFIG, cfg);
77 return !!(last & RPM_TX_EN);
78 }
79
rpm_lmac_rx_tx_enable(void * rpmd,int lmac_id,bool enable)80 int rpm_lmac_rx_tx_enable(void *rpmd, int lmac_id, bool enable)
81 {
82 rpm_t *rpm = rpmd;
83 u64 cfg;
84
85 if (!is_lmac_valid(rpm, lmac_id))
86 return -ENODEV;
87
88 cfg = rpm_read(rpm, lmac_id, RPMX_MTI_MAC100X_COMMAND_CONFIG);
89 if (enable)
90 cfg |= RPM_RX_EN | RPM_TX_EN;
91 else
92 cfg &= ~(RPM_RX_EN | RPM_TX_EN);
93 rpm_write(rpm, lmac_id, RPMX_MTI_MAC100X_COMMAND_CONFIG, cfg);
94 return 0;
95 }
96
rpm_lmac_enadis_rx_pause_fwding(void * rpmd,int lmac_id,bool enable)97 void rpm_lmac_enadis_rx_pause_fwding(void *rpmd, int lmac_id, bool enable)
98 {
99 rpm_t *rpm = rpmd;
100 u64 cfg;
101
102 if (!rpm)
103 return;
104
105 if (enable) {
106 cfg = rpm_read(rpm, lmac_id, RPMX_MTI_MAC100X_COMMAND_CONFIG);
107 cfg &= ~RPMX_MTI_MAC100X_COMMAND_CONFIG_PAUSE_IGNORE;
108 rpm_write(rpm, lmac_id, RPMX_MTI_MAC100X_COMMAND_CONFIG, cfg);
109 } else {
110 cfg = rpm_read(rpm, lmac_id, RPMX_MTI_MAC100X_COMMAND_CONFIG);
111 cfg |= RPMX_MTI_MAC100X_COMMAND_CONFIG_PAUSE_IGNORE;
112 rpm_write(rpm, lmac_id, RPMX_MTI_MAC100X_COMMAND_CONFIG, cfg);
113 }
114 }
115
rpm_lmac_get_pause_frm_status(void * rpmd,int lmac_id,u8 * tx_pause,u8 * rx_pause)116 int rpm_lmac_get_pause_frm_status(void *rpmd, int lmac_id,
117 u8 *tx_pause, u8 *rx_pause)
118 {
119 rpm_t *rpm = rpmd;
120 u64 cfg;
121
122 if (!is_lmac_valid(rpm, lmac_id))
123 return -ENODEV;
124
125 cfg = rpm_read(rpm, lmac_id, RPMX_MTI_MAC100X_COMMAND_CONFIG);
126 *rx_pause = !(cfg & RPMX_MTI_MAC100X_COMMAND_CONFIG_RX_P_DISABLE);
127
128 cfg = rpm_read(rpm, lmac_id, RPMX_MTI_MAC100X_COMMAND_CONFIG);
129 *tx_pause = !(cfg & RPMX_MTI_MAC100X_COMMAND_CONFIG_TX_P_DISABLE);
130 return 0;
131 }
132
rpm_lmac_enadis_pause_frm(void * rpmd,int lmac_id,u8 tx_pause,u8 rx_pause)133 int rpm_lmac_enadis_pause_frm(void *rpmd, int lmac_id, u8 tx_pause,
134 u8 rx_pause)
135 {
136 rpm_t *rpm = rpmd;
137 u64 cfg;
138
139 if (!is_lmac_valid(rpm, lmac_id))
140 return -ENODEV;
141
142 cfg = rpm_read(rpm, lmac_id, RPMX_MTI_MAC100X_COMMAND_CONFIG);
143 cfg &= ~RPMX_MTI_MAC100X_COMMAND_CONFIG_RX_P_DISABLE;
144 cfg |= rx_pause ? 0x0 : RPMX_MTI_MAC100X_COMMAND_CONFIG_RX_P_DISABLE;
145 cfg &= ~RPMX_MTI_MAC100X_COMMAND_CONFIG_PAUSE_IGNORE;
146 cfg |= rx_pause ? 0x0 : RPMX_MTI_MAC100X_COMMAND_CONFIG_PAUSE_IGNORE;
147 rpm_write(rpm, lmac_id, RPMX_MTI_MAC100X_COMMAND_CONFIG, cfg);
148
149 cfg = rpm_read(rpm, lmac_id, RPMX_MTI_MAC100X_COMMAND_CONFIG);
150 cfg &= ~RPMX_MTI_MAC100X_COMMAND_CONFIG_TX_P_DISABLE;
151 cfg |= tx_pause ? 0x0 : RPMX_MTI_MAC100X_COMMAND_CONFIG_TX_P_DISABLE;
152 rpm_write(rpm, lmac_id, RPMX_MTI_MAC100X_COMMAND_CONFIG, cfg);
153
154 cfg = rpm_read(rpm, 0, RPMX_CMR_RX_OVR_BP);
155 if (tx_pause) {
156 cfg &= ~RPMX_CMR_RX_OVR_BP_EN(lmac_id);
157 } else {
158 cfg |= RPMX_CMR_RX_OVR_BP_EN(lmac_id);
159 cfg &= ~RPMX_CMR_RX_OVR_BP_BP(lmac_id);
160 }
161 rpm_write(rpm, 0, RPMX_CMR_RX_OVR_BP, cfg);
162 return 0;
163 }
164
rpm_lmac_pause_frm_config(void * rpmd,int lmac_id,bool enable)165 void rpm_lmac_pause_frm_config(void *rpmd, int lmac_id, bool enable)
166 {
167 rpm_t *rpm = rpmd;
168 u64 cfg;
169
170 if (enable) {
171 /* Set pause time and interval */
172 cfg = rpm_read(rpm, lmac_id,
173 RPMX_MTI_MAC100X_CL01_PAUSE_QUANTA);
174 cfg &= ~0xFFFFULL;
175 rpm_write(rpm, lmac_id, RPMX_MTI_MAC100X_CL01_PAUSE_QUANTA,
176 cfg | RPM_DEFAULT_PAUSE_TIME);
177 /* Set pause interval as the hardware default is too short */
178 cfg = rpm_read(rpm, lmac_id,
179 RPMX_MTI_MAC100X_CL01_QUANTA_THRESH);
180 cfg &= ~0xFFFFULL;
181 rpm_write(rpm, lmac_id, RPMX_MTI_MAC100X_CL01_QUANTA_THRESH,
182 cfg | (RPM_DEFAULT_PAUSE_TIME / 2));
183 }
184
185 /* ALL pause frames received are completely ignored */
186 cfg = rpm_read(rpm, lmac_id, RPMX_MTI_MAC100X_COMMAND_CONFIG);
187 cfg |= RPMX_MTI_MAC100X_COMMAND_CONFIG_RX_P_DISABLE;
188 rpm_write(rpm, lmac_id, RPMX_MTI_MAC100X_COMMAND_CONFIG, cfg);
189
190 /* Disable forward pause to TX block */
191 cfg = rpm_read(rpm, lmac_id, RPMX_MTI_MAC100X_COMMAND_CONFIG);
192 cfg |= RPMX_MTI_MAC100X_COMMAND_CONFIG_PAUSE_IGNORE;
193 rpm_write(rpm, lmac_id, RPMX_MTI_MAC100X_COMMAND_CONFIG, cfg);
194
195 /* Disable pause frames transmission */
196 cfg = rpm_read(rpm, lmac_id, RPMX_MTI_MAC100X_COMMAND_CONFIG);
197 cfg |= RPMX_MTI_MAC100X_COMMAND_CONFIG_TX_P_DISABLE;
198 rpm_write(rpm, lmac_id, RPMX_MTI_MAC100X_COMMAND_CONFIG, cfg);
199 }
200
rpm_get_rx_stats(void * rpmd,int lmac_id,int idx,u64 * rx_stat)201 int rpm_get_rx_stats(void *rpmd, int lmac_id, int idx, u64 *rx_stat)
202 {
203 rpm_t *rpm = rpmd;
204 u64 val_lo, val_hi;
205
206 if (!rpm || lmac_id >= rpm->lmac_count)
207 return -ENODEV;
208
209 mutex_lock(&rpm->lock);
210
211 /* Update idx to point per lmac Rx statistics page */
212 idx += lmac_id * rpm->mac_ops->rx_stats_cnt;
213
214 /* Read lower 32 bits of counter */
215 val_lo = rpm_read(rpm, 0, RPMX_MTI_STAT_RX_STAT_PAGES_COUNTERX +
216 (idx * 8));
217
218 /* upon read of lower 32 bits, higher 32 bits are written
219 * to RPMX_MTI_STAT_DATA_HI_CDC
220 */
221 val_hi = rpm_read(rpm, 0, RPMX_MTI_STAT_DATA_HI_CDC);
222
223 *rx_stat = (val_hi << 32 | val_lo);
224
225 mutex_unlock(&rpm->lock);
226 return 0;
227 }
228
rpm_get_tx_stats(void * rpmd,int lmac_id,int idx,u64 * tx_stat)229 int rpm_get_tx_stats(void *rpmd, int lmac_id, int idx, u64 *tx_stat)
230 {
231 rpm_t *rpm = rpmd;
232 u64 val_lo, val_hi;
233
234 if (!rpm || lmac_id >= rpm->lmac_count)
235 return -ENODEV;
236
237 mutex_lock(&rpm->lock);
238
239 /* Update idx to point per lmac Tx statistics page */
240 idx += lmac_id * rpm->mac_ops->tx_stats_cnt;
241
242 val_lo = rpm_read(rpm, 0, RPMX_MTI_STAT_TX_STAT_PAGES_COUNTERX +
243 (idx * 8));
244 val_hi = rpm_read(rpm, 0, RPMX_MTI_STAT_DATA_HI_CDC);
245
246 *tx_stat = (val_hi << 32 | val_lo);
247
248 mutex_unlock(&rpm->lock);
249 return 0;
250 }
251
rpm_get_lmac_type(void * rpmd,int lmac_id)252 u8 rpm_get_lmac_type(void *rpmd, int lmac_id)
253 {
254 rpm_t *rpm = rpmd;
255 u64 req = 0, resp;
256 int err;
257
258 req = FIELD_SET(CMDREG_ID, CGX_CMD_GET_LINK_STS, req);
259 err = cgx_fwi_cmd_generic(req, &resp, rpm, 0);
260 if (!err)
261 return FIELD_GET(RESP_LINKSTAT_LMAC_TYPE, resp);
262 return err;
263 }
264
rpm_get_lmac_fifo_len(void * rpmd,int lmac_id)265 u32 rpm_get_lmac_fifo_len(void *rpmd, int lmac_id)
266 {
267 rpm_t *rpm = rpmd;
268 u64 hi_perf_lmac;
269 u8 num_lmacs;
270 u32 fifo_len;
271
272 fifo_len = rpm->mac_ops->fifo_len;
273 num_lmacs = rpm->mac_ops->get_nr_lmacs(rpm);
274
275 switch (num_lmacs) {
276 case 1:
277 return fifo_len;
278 case 2:
279 return fifo_len / 2;
280 case 3:
281 /* LMAC marked as hi_perf gets half of the FIFO and rest 1/4th */
282 hi_perf_lmac = rpm_read(rpm, 0, CGXX_CMRX_RX_LMACS);
283 hi_perf_lmac = (hi_perf_lmac >> 4) & 0x3ULL;
284 if (lmac_id == hi_perf_lmac)
285 return fifo_len / 2;
286 return fifo_len / 4;
287 case 4:
288 default:
289 return fifo_len / 4;
290 }
291 return 0;
292 }
293
rpm_lmac_internal_loopback(void * rpmd,int lmac_id,bool enable)294 int rpm_lmac_internal_loopback(void *rpmd, int lmac_id, bool enable)
295 {
296 rpm_t *rpm = rpmd;
297 u8 lmac_type;
298 u64 cfg;
299
300 if (!rpm || lmac_id >= rpm->lmac_count)
301 return -ENODEV;
302 lmac_type = rpm->mac_ops->get_lmac_type(rpm, lmac_id);
303
304 if (lmac_type == LMAC_MODE_QSGMII || lmac_type == LMAC_MODE_SGMII) {
305 dev_err(&rpm->pdev->dev, "loopback not supported for LPC mode\n");
306 return 0;
307 }
308
309 cfg = rpm_read(rpm, lmac_id, RPMX_MTI_PCS100X_CONTROL1);
310
311 if (enable)
312 cfg |= RPMX_MTI_PCS_LBK;
313 else
314 cfg &= ~RPMX_MTI_PCS_LBK;
315 rpm_write(rpm, lmac_id, RPMX_MTI_PCS100X_CONTROL1, cfg);
316
317 return 0;
318 }
319
rpm_lmac_ptp_config(void * rpmd,int lmac_id,bool enable)320 void rpm_lmac_ptp_config(void *rpmd, int lmac_id, bool enable)
321 {
322 rpm_t *rpm = rpmd;
323 u64 cfg;
324
325 if (!is_lmac_valid(rpm, lmac_id))
326 return;
327
328 cfg = rpm_read(rpm, lmac_id, RPMX_CMRX_CFG);
329 if (enable)
330 cfg |= RPMX_RX_TS_PREPEND;
331 else
332 cfg &= ~RPMX_RX_TS_PREPEND;
333 rpm_write(rpm, lmac_id, RPMX_CMRX_CFG, cfg);
334 }
335