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