common/cnxk: use wider mask to extract RPM ID
[dpdk.git] / drivers / common / cnxk / roc_bphy_cgx.c
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(C) 2021 Marvell.
3  */
4
5 #include <pthread.h>
6
7 #include "roc_api.h"
8 #include "roc_priv.h"
9
10 #define CGX_CMRX_CONFIG                0x00
11 #define CGX_CMRX_CONFIG_DATA_PKT_RX_EN BIT_ULL(54)
12 #define CGX_CMRX_CONFIG_DATA_PKT_TX_EN BIT_ULL(53)
13 #define CGX_CMRX_INT                   0x40
14 #define CGX_CMRX_INT_OVERFLW           BIT_ULL(1)
15 /*
16  * CN10K stores number of lmacs in 4 bit filed
17  * in contrary to CN9K which uses only 3 bits.
18  *
19  * In theory masks should differ yet on CN9K
20  * bits beyond specified range contain zeros.
21  *
22  * Hence common longer mask may be used.
23  */
24 #define CGX_CMRX_RX_LMACS                     0x128
25 #define CGX_CMRX_RX_LMACS_LMACS               GENMASK_ULL(3, 0)
26 #define CGX_CMRX_SCRATCH0                     0x1050
27 #define CGX_CMRX_SCRATCH1                     0x1058
28 #define CGX_MTI_MAC100X_COMMAND_CONFIG        0x8010
29 #define CGX_MTI_MAC100X_COMMAND_CONFIG_RX_ENA BIT_ULL(1)
30 #define CGX_MTI_MAC100X_COMMAND_CONFIG_TX_ENA BIT_ULL(0)
31
32 static uint64_t
33 roc_bphy_cgx_read(struct roc_bphy_cgx *roc_cgx, uint64_t lmac, uint64_t offset)
34 {
35         int shift = roc_model_is_cn10k() ? 20 : 18;
36         uint64_t base = (uint64_t)roc_cgx->bar0_va;
37
38         return plt_read64(base + (lmac << shift) + offset);
39 }
40
41 static void
42 roc_bphy_cgx_write(struct roc_bphy_cgx *roc_cgx, uint64_t lmac, uint64_t offset,
43                    uint64_t value)
44 {
45         int shift = roc_model_is_cn10k() ? 20 : 18;
46         uint64_t base = (uint64_t)roc_cgx->bar0_va;
47
48         plt_write64(value, base + (lmac << shift) + offset);
49 }
50
51 static void
52 roc_bphy_cgx_ack(struct roc_bphy_cgx *roc_cgx, unsigned int lmac,
53                  uint64_t *scr0)
54 {
55         uint64_t val;
56
57         /* clear interrupt */
58         val = roc_bphy_cgx_read(roc_cgx, lmac, CGX_CMRX_INT);
59         val |= FIELD_PREP(CGX_CMRX_INT_OVERFLW, 1);
60         roc_bphy_cgx_write(roc_cgx, lmac, CGX_CMRX_INT, val);
61
62         /* ack fw response */
63         *scr0 &= ~SCR0_ETH_EVT_STS_S_ACK;
64         roc_bphy_cgx_write(roc_cgx, lmac, CGX_CMRX_SCRATCH0, *scr0);
65 }
66
67 static int
68 roc_bphy_cgx_wait_for_ownership(struct roc_bphy_cgx *roc_cgx, unsigned int lmac,
69                                 uint64_t *scr0)
70 {
71         int tries = 5000;
72         uint64_t scr1;
73
74         do {
75                 *scr0 = roc_bphy_cgx_read(roc_cgx, lmac, CGX_CMRX_SCRATCH0);
76                 scr1 = roc_bphy_cgx_read(roc_cgx, lmac, CGX_CMRX_SCRATCH1);
77
78                 if (FIELD_GET(SCR1_OWN_STATUS, scr1) == ETH_OWN_NON_SECURE_SW &&
79                     FIELD_GET(SCR0_ETH_EVT_STS_S_ACK, *scr0) == 0)
80                         break;
81
82                 /* clear async events if any */
83                 if (FIELD_GET(SCR0_ETH_EVT_STS_S_EVT_TYPE, *scr0) ==
84                     ETH_EVT_ASYNC &&
85                     FIELD_GET(SCR0_ETH_EVT_STS_S_ACK, *scr0))
86                         roc_bphy_cgx_ack(roc_cgx, lmac, scr0);
87
88                 plt_delay_ms(1);
89         } while (--tries);
90
91         return tries ? 0 : -ETIMEDOUT;
92 }
93
94 static int
95 roc_bphy_cgx_wait_for_ack(struct roc_bphy_cgx *roc_cgx, unsigned int lmac,
96                           uint64_t *scr0)
97 {
98         int tries = 5000;
99         uint64_t scr1;
100
101         do {
102                 *scr0 = roc_bphy_cgx_read(roc_cgx, lmac, CGX_CMRX_SCRATCH0);
103                 scr1 = roc_bphy_cgx_read(roc_cgx, lmac, CGX_CMRX_SCRATCH1);
104
105                 if (FIELD_GET(SCR1_OWN_STATUS, scr1) == ETH_OWN_NON_SECURE_SW &&
106                     FIELD_GET(SCR0_ETH_EVT_STS_S_ACK, *scr0))
107                         break;
108
109                 plt_delay_ms(1);
110         } while (--tries);
111
112         return tries ? 0 : -ETIMEDOUT;
113 }
114
115 static int
116 roc_bphy_cgx_intf_req(struct roc_bphy_cgx *roc_cgx, unsigned int lmac,
117                       uint64_t scr1, uint64_t *scr0)
118 {
119         uint8_t cmd_id = FIELD_GET(SCR1_ETH_CMD_ID, scr1);
120         int ret;
121
122         pthread_mutex_lock(&roc_cgx->lock);
123
124         /* wait for ownership */
125         ret = roc_bphy_cgx_wait_for_ownership(roc_cgx, lmac, scr0);
126         if (ret) {
127                 plt_err("timed out waiting for ownership");
128                 goto out;
129         }
130
131         /* write command */
132         scr1 |= FIELD_PREP(SCR1_OWN_STATUS, ETH_OWN_FIRMWARE);
133         roc_bphy_cgx_write(roc_cgx, lmac, CGX_CMRX_SCRATCH1, scr1);
134
135         /* wait for command ack */
136         ret = roc_bphy_cgx_wait_for_ack(roc_cgx, lmac, scr0);
137         if (ret) {
138                 plt_err("timed out waiting for response");
139                 goto out;
140         }
141
142         if (cmd_id == ETH_CMD_INTF_SHUTDOWN)
143                 goto out;
144
145         if (FIELD_GET(SCR0_ETH_EVT_STS_S_EVT_TYPE, *scr0) != ETH_EVT_CMD_RESP) {
146                 plt_err("received async event instead of cmd resp event");
147                 ret = -EIO;
148                 goto out;
149         }
150
151         if (FIELD_GET(SCR0_ETH_EVT_STS_S_ID, *scr0) != cmd_id) {
152                 plt_err("received resp for cmd %d expected for cmd %d",
153                         (int)FIELD_GET(SCR0_ETH_EVT_STS_S_ID, *scr0), cmd_id);
154                 ret = -EIO;
155                 goto out;
156         }
157
158         if (FIELD_GET(SCR0_ETH_EVT_STS_S_STAT, *scr0) != ETH_STAT_SUCCESS) {
159                 plt_err("cmd %d failed on cgx%u lmac%u with errcode %d", cmd_id,
160                         roc_cgx->id, lmac,
161                         (int)FIELD_GET(SCR0_ETH_LNK_STS_S_ERR_TYPE, *scr0));
162                 ret = -EIO;
163         }
164
165 out:
166         roc_bphy_cgx_ack(roc_cgx, lmac, scr0);
167
168         pthread_mutex_unlock(&roc_cgx->lock);
169
170         return ret;
171 }
172
173 static unsigned int
174 roc_bphy_cgx_dev_id(struct roc_bphy_cgx *roc_cgx)
175 {
176         uint64_t cgx_id;
177
178         if (roc_model_is_cnf10kb())
179                 cgx_id = GENMASK_ULL(27, 24);
180         else if (roc_model_is_cn10k())
181                 cgx_id = GENMASK_ULL(26, 24);
182         else
183                 cgx_id = GENMASK_ULL(25, 24);
184
185         return FIELD_GET(cgx_id, roc_cgx->bar0_pa);
186 }
187
188 int
189 roc_bphy_cgx_dev_init(struct roc_bphy_cgx *roc_cgx)
190 {
191         uint64_t val;
192         int ret;
193
194         if (!roc_cgx || !roc_cgx->bar0_va || !roc_cgx->bar0_pa)
195                 return -EINVAL;
196
197         ret = pthread_mutex_init(&roc_cgx->lock, NULL);
198         if (ret)
199                 return ret;
200
201         val = roc_bphy_cgx_read(roc_cgx, 0, CGX_CMRX_RX_LMACS);
202         val = FIELD_GET(CGX_CMRX_RX_LMACS_LMACS, val);
203         if (roc_model_is_cn9k())
204                 val = GENMASK_ULL(val - 1, 0);
205         roc_cgx->lmac_bmap = val;
206         roc_cgx->id = roc_bphy_cgx_dev_id(roc_cgx);
207
208         return 0;
209 }
210
211 int
212 roc_bphy_cgx_dev_fini(struct roc_bphy_cgx *roc_cgx)
213 {
214         if (!roc_cgx)
215                 return -EINVAL;
216
217         pthread_mutex_destroy(&roc_cgx->lock);
218
219         return 0;
220 }
221
222 static bool
223 roc_bphy_cgx_lmac_exists(struct roc_bphy_cgx *roc_cgx, unsigned int lmac)
224 {
225         return (lmac < MAX_LMACS_PER_CGX) &&
226                (roc_cgx->lmac_bmap & BIT_ULL(lmac));
227 }
228
229 static int
230 roc_bphy_cgx_start_stop_rxtx(struct roc_bphy_cgx *roc_cgx, unsigned int lmac,
231                              bool start)
232 {
233         uint64_t val, reg, rx_field, tx_field;
234
235         if (!roc_cgx)
236                 return -EINVAL;
237
238         if (!roc_bphy_cgx_lmac_exists(roc_cgx, lmac))
239                 return -ENODEV;
240
241         if (roc_model_is_cnf10kb()) {
242                 reg = CGX_MTI_MAC100X_COMMAND_CONFIG;
243                 rx_field = CGX_MTI_MAC100X_COMMAND_CONFIG_RX_ENA;
244                 tx_field = CGX_MTI_MAC100X_COMMAND_CONFIG_TX_ENA;
245         } else {
246                 reg = CGX_CMRX_CONFIG;
247                 rx_field = CGX_CMRX_CONFIG_DATA_PKT_RX_EN;
248                 tx_field = CGX_CMRX_CONFIG_DATA_PKT_TX_EN;
249         }
250
251         pthread_mutex_lock(&roc_cgx->lock);
252         val = roc_bphy_cgx_read(roc_cgx, lmac, reg);
253         val &= ~(rx_field | tx_field);
254
255         if (start)
256                 val |= FIELD_PREP(rx_field, 1) | FIELD_PREP(tx_field, 1);
257
258         roc_bphy_cgx_write(roc_cgx, lmac, reg, val);
259         pthread_mutex_unlock(&roc_cgx->lock);
260
261         return 0;
262 }
263
264 static int
265 roc_bphy_cgx_intlbk_ena_dis(struct roc_bphy_cgx *roc_cgx, unsigned int lmac,
266                             bool enable)
267 {
268         uint64_t scr1, scr0;
269
270         if (!roc_cgx)
271                 return -EINVAL;
272
273         if (!roc_bphy_cgx_lmac_exists(roc_cgx, lmac))
274                 return -ENODEV;
275
276         scr1 = FIELD_PREP(SCR1_ETH_CMD_ID, ETH_CMD_INTERNAL_LBK) |
277                FIELD_PREP(SCR1_ETH_CTL_ARGS_ENABLE, enable);
278
279         return roc_bphy_cgx_intf_req(roc_cgx, lmac, scr1, &scr0);
280 }
281
282 static int
283 roc_bphy_cgx_ptp_rx_ena_dis(struct roc_bphy_cgx *roc_cgx, unsigned int lmac,
284                             bool enable)
285 {
286         uint64_t scr1, scr0;
287
288         if (roc_model_is_cn10k())
289                 return -ENOTSUP;
290
291         if (!roc_cgx)
292                 return -EINVAL;
293
294         if (!roc_bphy_cgx_lmac_exists(roc_cgx, lmac))
295                 return -ENODEV;
296
297         scr1 = FIELD_PREP(SCR1_ETH_CMD_ID, ETH_CMD_SET_PTP_MODE) |
298                FIELD_PREP(SCR1_ETH_CTL_ARGS_ENABLE, enable);
299
300         return roc_bphy_cgx_intf_req(roc_cgx, lmac, scr1, &scr0);
301 }
302
303 int
304 roc_bphy_cgx_start_rxtx(struct roc_bphy_cgx *roc_cgx, unsigned int lmac)
305 {
306         return roc_bphy_cgx_start_stop_rxtx(roc_cgx, lmac, true);
307 }
308
309 int
310 roc_bphy_cgx_stop_rxtx(struct roc_bphy_cgx *roc_cgx, unsigned int lmac)
311 {
312         return roc_bphy_cgx_start_stop_rxtx(roc_cgx, lmac, false);
313 }
314
315 int
316 roc_bphy_cgx_set_link_state(struct roc_bphy_cgx *roc_cgx, unsigned int lmac,
317                             bool state)
318 {
319         uint64_t scr1, scr0;
320
321         if (!roc_cgx)
322                 return -EINVAL;
323
324         if (!roc_bphy_cgx_lmac_exists(roc_cgx, lmac))
325                 return -ENODEV;
326
327         scr1 = state ? FIELD_PREP(SCR1_ETH_CMD_ID, ETH_CMD_LINK_BRING_UP) :
328                        FIELD_PREP(SCR1_ETH_CMD_ID, ETH_CMD_LINK_BRING_DOWN);
329
330         return roc_bphy_cgx_intf_req(roc_cgx, lmac, scr1, &scr0);
331 }
332
333 int
334 roc_bphy_cgx_get_linkinfo(struct roc_bphy_cgx *roc_cgx, unsigned int lmac,
335                           struct roc_bphy_cgx_link_info *info)
336 {
337         uint64_t scr1, scr0;
338         int ret;
339
340         if (!roc_cgx)
341                 return -EINVAL;
342
343         if (!roc_bphy_cgx_lmac_exists(roc_cgx, lmac))
344                 return -ENODEV;
345
346         if (!info)
347                 return -EINVAL;
348
349         scr1 = FIELD_PREP(SCR1_ETH_CMD_ID, ETH_CMD_GET_LINK_STS);
350         ret = roc_bphy_cgx_intf_req(roc_cgx, lmac, scr1, &scr0);
351         if (ret)
352                 return ret;
353
354         info->link_up = FIELD_GET(SCR0_ETH_LNK_STS_S_LINK_UP, scr0);
355         info->full_duplex = FIELD_GET(SCR0_ETH_LNK_STS_S_FULL_DUPLEX, scr0);
356         info->speed = FIELD_GET(SCR0_ETH_LNK_STS_S_SPEED, scr0);
357         info->an = FIELD_GET(SCR0_ETH_LNK_STS_S_AN, scr0);
358         info->fec = FIELD_GET(SCR0_ETH_LNK_STS_S_FEC, scr0);
359         info->mode = FIELD_GET(SCR0_ETH_LNK_STS_S_MODE, scr0);
360
361         return 0;
362 }
363
364 int
365 roc_bphy_cgx_set_link_mode(struct roc_bphy_cgx *roc_cgx, unsigned int lmac,
366                            struct roc_bphy_cgx_link_mode *mode)
367 {
368         uint64_t scr1, scr0;
369
370         if (roc_model_is_cn10k())
371                 return -ENOTSUP;
372
373         if (!roc_cgx)
374                 return -EINVAL;
375
376         if (!roc_bphy_cgx_lmac_exists(roc_cgx, lmac))
377                 return -ENODEV;
378
379         if (!mode)
380                 return -EINVAL;
381
382         scr1 = FIELD_PREP(SCR1_ETH_CMD_ID, ETH_CMD_MODE_CHANGE) |
383                FIELD_PREP(SCR1_ETH_MODE_CHANGE_ARGS_SPEED, mode->speed) |
384                FIELD_PREP(SCR1_ETH_MODE_CHANGE_ARGS_DUPLEX, mode->full_duplex) |
385                FIELD_PREP(SCR1_ETH_MODE_CHANGE_ARGS_AN, mode->an) |
386                FIELD_PREP(SCR1_ETH_MODE_CHANGE_ARGS_PORT, mode->port) |
387                FIELD_PREP(SCR1_ETH_MODE_CHANGE_ARGS_MODE, BIT_ULL(mode->mode));
388
389         return roc_bphy_cgx_intf_req(roc_cgx, lmac, scr1, &scr0);
390 }
391
392 int
393 roc_bphy_cgx_intlbk_enable(struct roc_bphy_cgx *roc_cgx, unsigned int lmac)
394 {
395         return roc_bphy_cgx_intlbk_ena_dis(roc_cgx, lmac, true);
396 }
397
398 int
399 roc_bphy_cgx_intlbk_disable(struct roc_bphy_cgx *roc_cgx, unsigned int lmac)
400 {
401         return roc_bphy_cgx_intlbk_ena_dis(roc_cgx, lmac, false);
402 }
403
404 int
405 roc_bphy_cgx_ptp_rx_enable(struct roc_bphy_cgx *roc_cgx, unsigned int lmac)
406 {
407         return roc_bphy_cgx_ptp_rx_ena_dis(roc_cgx, lmac, true);
408 }
409
410 int
411 roc_bphy_cgx_ptp_rx_disable(struct roc_bphy_cgx *roc_cgx, unsigned int lmac)
412 {
413         return roc_bphy_cgx_ptp_rx_ena_dis(roc_cgx, lmac, false);
414 }
415
416 int
417 roc_bphy_cgx_fec_set(struct roc_bphy_cgx *roc_cgx, unsigned int lmac,
418                      enum roc_bphy_cgx_eth_link_fec fec)
419 {
420         uint64_t scr1, scr0;
421
422         if (!roc_cgx)
423                 return -EINVAL;
424
425         if (!roc_bphy_cgx_lmac_exists(roc_cgx, lmac))
426                 return -ENODEV;
427
428         scr1 = FIELD_PREP(SCR1_ETH_CMD_ID, ETH_CMD_SET_FEC) |
429                FIELD_PREP(SCR1_ETH_SET_FEC_ARGS, fec);
430
431         return roc_bphy_cgx_intf_req(roc_cgx, lmac, scr1, &scr0);
432 }
433
434 int
435 roc_bphy_cgx_fec_supported_get(struct roc_bphy_cgx *roc_cgx, unsigned int lmac,
436                                enum roc_bphy_cgx_eth_link_fec *fec)
437 {
438         uint64_t scr1, scr0;
439         int ret;
440
441         if (!roc_cgx || !fec)
442                 return -EINVAL;
443
444         if (!roc_bphy_cgx_lmac_exists(roc_cgx, lmac))
445                 return -ENODEV;
446
447         scr1 = FIELD_PREP(SCR1_ETH_CMD_ID, ETH_CMD_GET_SUPPORTED_FEC);
448
449         ret = roc_bphy_cgx_intf_req(roc_cgx, lmac, scr1, &scr0);
450         if (ret)
451                 return ret;
452
453         scr0 = FIELD_GET(SCR0_ETH_FEC_TYPES_S_FEC, scr0);
454         *fec = (enum roc_bphy_cgx_eth_link_fec)scr0;
455
456         return 0;
457 }