net/axgbe: add phy init and related APIs
[dpdk.git] / drivers / net / axgbe / axgbe_dev.c
1 /*   SPDX-License-Identifier: BSD-3-Clause
2  *   Copyright(c) 2018 Advanced Micro Devices, Inc. All rights reserved.
3  *   Copyright(c) 2018 Synopsys, Inc. All rights reserved.
4  */
5
6 #include "axgbe_ethdev.h"
7 #include "axgbe_common.h"
8 #include "axgbe_phy.h"
9
10 /* query busy bit */
11 static int mdio_complete(struct axgbe_port *pdata)
12 {
13         if (!AXGMAC_IOREAD_BITS(pdata, MAC_MDIOSCCDR, BUSY))
14                 return 1;
15
16         return 0;
17 }
18
19 static int axgbe_write_ext_mii_regs(struct axgbe_port *pdata, int addr,
20                                     int reg, u16 val)
21 {
22         unsigned int mdio_sca, mdio_sccd;
23         uint64_t timeout;
24
25         mdio_sca = 0;
26         AXGMAC_SET_BITS(mdio_sca, MAC_MDIOSCAR, REG, reg);
27         AXGMAC_SET_BITS(mdio_sca, MAC_MDIOSCAR, DA, addr);
28         AXGMAC_IOWRITE(pdata, MAC_MDIOSCAR, mdio_sca);
29
30         mdio_sccd = 0;
31         AXGMAC_SET_BITS(mdio_sccd, MAC_MDIOSCCDR, DATA, val);
32         AXGMAC_SET_BITS(mdio_sccd, MAC_MDIOSCCDR, CMD, 1);
33         AXGMAC_SET_BITS(mdio_sccd, MAC_MDIOSCCDR, BUSY, 1);
34         AXGMAC_IOWRITE(pdata, MAC_MDIOSCCDR, mdio_sccd);
35
36         timeout = rte_get_timer_cycles() + rte_get_timer_hz();
37         while (time_before(rte_get_timer_cycles(), timeout)) {
38                 rte_delay_us(100);
39                 if (mdio_complete(pdata))
40                         return 0;
41         }
42
43         PMD_DRV_LOG(ERR, "Mdio write operation timed out\n");
44         return -ETIMEDOUT;
45 }
46
47 static int axgbe_read_ext_mii_regs(struct axgbe_port *pdata, int addr,
48                                    int reg)
49 {
50         unsigned int mdio_sca, mdio_sccd;
51         uint64_t timeout;
52
53         mdio_sca = 0;
54         AXGMAC_SET_BITS(mdio_sca, MAC_MDIOSCAR, REG, reg);
55         AXGMAC_SET_BITS(mdio_sca, MAC_MDIOSCAR, DA, addr);
56         AXGMAC_IOWRITE(pdata, MAC_MDIOSCAR, mdio_sca);
57
58         mdio_sccd = 0;
59         AXGMAC_SET_BITS(mdio_sccd, MAC_MDIOSCCDR, CMD, 3);
60         AXGMAC_SET_BITS(mdio_sccd, MAC_MDIOSCCDR, BUSY, 1);
61         AXGMAC_IOWRITE(pdata, MAC_MDIOSCCDR, mdio_sccd);
62
63         timeout = rte_get_timer_cycles() + rte_get_timer_hz();
64
65         while (time_before(rte_get_timer_cycles(), timeout)) {
66                 rte_delay_us(100);
67                 if (mdio_complete(pdata))
68                         goto success;
69         }
70
71         PMD_DRV_LOG(ERR, "Mdio read operation timed out\n");
72         return -ETIMEDOUT;
73
74 success:
75         return AXGMAC_IOREAD_BITS(pdata, MAC_MDIOSCCDR, DATA);
76 }
77
78 static int axgbe_set_ext_mii_mode(struct axgbe_port *pdata, unsigned int port,
79                                   enum axgbe_mdio_mode mode)
80 {
81         unsigned int reg_val = 0;
82
83         switch (mode) {
84         case AXGBE_MDIO_MODE_CL22:
85                 if (port > AXGMAC_MAX_C22_PORT)
86                         return -EINVAL;
87                 reg_val |= (1 << port);
88                 break;
89         case AXGBE_MDIO_MODE_CL45:
90                 break;
91         default:
92                 return -EINVAL;
93         }
94         AXGMAC_IOWRITE(pdata, MAC_MDIOCL22R, reg_val);
95
96         return 0;
97 }
98
99 static int axgbe_read_mmd_regs_v2(struct axgbe_port *pdata,
100                                   int prtad __rte_unused, int mmd_reg)
101 {
102         unsigned int mmd_address, index, offset;
103         int mmd_data;
104
105         if (mmd_reg & MII_ADDR_C45)
106                 mmd_address = mmd_reg & ~MII_ADDR_C45;
107         else
108                 mmd_address = (pdata->mdio_mmd << 16) | (mmd_reg & 0xffff);
109
110         /* The PCS registers are accessed using mmio. The underlying
111          * management interface uses indirect addressing to access the MMD
112          * register sets. This requires accessing of the PCS register in two
113          * phases, an address phase and a data phase.
114          *
115          * The mmio interface is based on 16-bit offsets and values. All
116          * register offsets must therefore be adjusted by left shifting the
117          * offset 1 bit and reading 16 bits of data.
118          */
119         mmd_address <<= 1;
120         index = mmd_address & ~pdata->xpcs_window_mask;
121         offset = pdata->xpcs_window + (mmd_address & pdata->xpcs_window_mask);
122
123         pthread_mutex_lock(&pdata->xpcs_mutex);
124
125         XPCS32_IOWRITE(pdata, pdata->xpcs_window_sel_reg, index);
126         mmd_data = XPCS16_IOREAD(pdata, offset);
127
128         pthread_mutex_unlock(&pdata->xpcs_mutex);
129
130         return mmd_data;
131 }
132
133 static void axgbe_write_mmd_regs_v2(struct axgbe_port *pdata,
134                                     int prtad __rte_unused,
135                                     int mmd_reg, int mmd_data)
136 {
137         unsigned int mmd_address, index, offset;
138
139         if (mmd_reg & MII_ADDR_C45)
140                 mmd_address = mmd_reg & ~MII_ADDR_C45;
141         else
142                 mmd_address = (pdata->mdio_mmd << 16) | (mmd_reg & 0xffff);
143
144         /* The PCS registers are accessed using mmio. The underlying
145          * management interface uses indirect addressing to access the MMD
146          * register sets. This requires accessing of the PCS register in two
147          * phases, an address phase and a data phase.
148          *
149          * The mmio interface is based on 16-bit offsets and values. All
150          * register offsets must therefore be adjusted by left shifting the
151          * offset 1 bit and writing 16 bits of data.
152          */
153         mmd_address <<= 1;
154         index = mmd_address & ~pdata->xpcs_window_mask;
155         offset = pdata->xpcs_window + (mmd_address & pdata->xpcs_window_mask);
156
157         pthread_mutex_lock(&pdata->xpcs_mutex);
158
159         XPCS32_IOWRITE(pdata, pdata->xpcs_window_sel_reg, index);
160         XPCS16_IOWRITE(pdata, offset, mmd_data);
161
162         pthread_mutex_unlock(&pdata->xpcs_mutex);
163 }
164
165 static int axgbe_read_mmd_regs(struct axgbe_port *pdata, int prtad,
166                                int mmd_reg)
167 {
168         switch (pdata->vdata->xpcs_access) {
169         case AXGBE_XPCS_ACCESS_V1:
170                 PMD_DRV_LOG(ERR, "PHY_Version 1 is not supported\n");
171                 return -1;
172         case AXGBE_XPCS_ACCESS_V2:
173         default:
174                 return axgbe_read_mmd_regs_v2(pdata, prtad, mmd_reg);
175         }
176 }
177
178 static void axgbe_write_mmd_regs(struct axgbe_port *pdata, int prtad,
179                                  int mmd_reg, int mmd_data)
180 {
181         switch (pdata->vdata->xpcs_access) {
182         case AXGBE_XPCS_ACCESS_V1:
183                 PMD_DRV_LOG(ERR, "PHY_Version 1 is not supported\n");
184                 return;
185         case AXGBE_XPCS_ACCESS_V2:
186         default:
187                 return axgbe_write_mmd_regs_v2(pdata, prtad, mmd_reg, mmd_data);
188         }
189 }
190
191 static int __axgbe_exit(struct axgbe_port *pdata)
192 {
193         unsigned int count = 2000;
194
195         /* Issue a software reset */
196         AXGMAC_IOWRITE_BITS(pdata, DMA_MR, SWR, 1);
197         rte_delay_us(10);
198
199         /* Poll Until Poll Condition */
200         while (--count && AXGMAC_IOREAD_BITS(pdata, DMA_MR, SWR))
201                 rte_delay_us(500);
202
203         if (!count)
204                 return -EBUSY;
205
206         return 0;
207 }
208
209 static int axgbe_exit(struct axgbe_port *pdata)
210 {
211         int ret;
212
213         /* To guard against possible incorrectly generated interrupts,
214          * issue the software reset twice.
215          */
216         ret = __axgbe_exit(pdata);
217         if (ret)
218                 return ret;
219
220         return __axgbe_exit(pdata);
221 }
222
223 void axgbe_init_function_ptrs_dev(struct axgbe_hw_if *hw_if)
224 {
225         hw_if->exit = axgbe_exit;
226
227         hw_if->read_mmd_regs = axgbe_read_mmd_regs;
228         hw_if->write_mmd_regs = axgbe_write_mmd_regs;
229
230         hw_if->set_ext_mii_mode = axgbe_set_ext_mii_mode;
231         hw_if->read_ext_mii_regs = axgbe_read_ext_mii_regs;
232         hw_if->write_ext_mii_regs = axgbe_write_ext_mii_regs;
233 }