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