xref: /dpdk/drivers/net/axgbe/axgbe_phy_impl.c (revision 1f9d2d3a948f61d46fe80d5c7c3b944393e7232c)
14ac7516bSRavi Kumar /*   SPDX-License-Identifier: BSD-3-Clause
24ac7516bSRavi Kumar  *   Copyright(c) 2018 Advanced Micro Devices, Inc. All rights reserved.
34ac7516bSRavi Kumar  *   Copyright(c) 2018 Synopsys, Inc. All rights reserved.
44ac7516bSRavi Kumar  */
54ac7516bSRavi Kumar 
64ac7516bSRavi Kumar #include "axgbe_ethdev.h"
74ac7516bSRavi Kumar #include "axgbe_common.h"
84ac7516bSRavi Kumar #include "axgbe_phy.h"
94ac7516bSRavi Kumar 
10*1f9d2d3aSVenkat Kumar Ande #define AXGBE_PHY_PORT_SPEED_10		BIT(0)
11a935a4c3SSelwin Sebastian #define AXGBE_PHY_PORT_SPEED_100	BIT(1)
12a935a4c3SSelwin Sebastian #define AXGBE_PHY_PORT_SPEED_1000	BIT(2)
13a935a4c3SSelwin Sebastian #define AXGBE_PHY_PORT_SPEED_2500	BIT(3)
14a935a4c3SSelwin Sebastian #define AXGBE_PHY_PORT_SPEED_10000	BIT(4)
154ac7516bSRavi Kumar 
164ac7516bSRavi Kumar #define AXGBE_MUTEX_RELEASE		0x80000000
174ac7516bSRavi Kumar 
184ac7516bSRavi Kumar #define AXGBE_SFP_DIRECT		7
194ac7516bSRavi Kumar 
204ac7516bSRavi Kumar /* I2C target addresses */
214ac7516bSRavi Kumar #define AXGBE_SFP_SERIAL_ID_ADDRESS	0x50
224ac7516bSRavi Kumar #define AXGBE_SFP_DIAG_INFO_ADDRESS	0x51
234ac7516bSRavi Kumar #define AXGBE_SFP_PHY_ADDRESS		0x56
244ac7516bSRavi Kumar #define AXGBE_GPIO_ADDRESS_PCA9555	0x20
254ac7516bSRavi Kumar 
264ac7516bSRavi Kumar /* SFP sideband signal indicators */
274ac7516bSRavi Kumar #define AXGBE_GPIO_NO_TX_FAULT		BIT(0)
284ac7516bSRavi Kumar #define AXGBE_GPIO_NO_RATE_SELECT	BIT(1)
294ac7516bSRavi Kumar #define AXGBE_GPIO_NO_MOD_ABSENT	BIT(2)
304ac7516bSRavi Kumar #define AXGBE_GPIO_NO_RX_LOS		BIT(3)
314ac7516bSRavi Kumar 
324ac7516bSRavi Kumar /* Rate-change complete wait/retry count */
334ac7516bSRavi Kumar #define AXGBE_RATECHANGE_COUNT		500
344ac7516bSRavi Kumar 
3500072056SRavi Kumar /* CDR delay values for KR support (in usec) */
3600072056SRavi Kumar #define AXGBE_CDR_DELAY_INIT		10000
3700072056SRavi Kumar #define AXGBE_CDR_DELAY_INC		10000
3800072056SRavi Kumar #define AXGBE_CDR_DELAY_MAX		100000
3900072056SRavi Kumar 
404ac7516bSRavi Kumar enum axgbe_port_mode {
414ac7516bSRavi Kumar 	AXGBE_PORT_MODE_RSVD = 0,
424ac7516bSRavi Kumar 	AXGBE_PORT_MODE_BACKPLANE,
434ac7516bSRavi Kumar 	AXGBE_PORT_MODE_BACKPLANE_2500,
444ac7516bSRavi Kumar 	AXGBE_PORT_MODE_1000BASE_T,
454ac7516bSRavi Kumar 	AXGBE_PORT_MODE_1000BASE_X,
464ac7516bSRavi Kumar 	AXGBE_PORT_MODE_NBASE_T,
474ac7516bSRavi Kumar 	AXGBE_PORT_MODE_10GBASE_T,
484ac7516bSRavi Kumar 	AXGBE_PORT_MODE_10GBASE_R,
494ac7516bSRavi Kumar 	AXGBE_PORT_MODE_SFP,
50443ab5aaSSelwin Sebastian 	AXGBE_PORT_MODE_BACKPLANE_NO_AUTONEG,
514ac7516bSRavi Kumar 	AXGBE_PORT_MODE_MAX,
524ac7516bSRavi Kumar };
534ac7516bSRavi Kumar 
544ac7516bSRavi Kumar enum axgbe_conn_type {
554ac7516bSRavi Kumar 	AXGBE_CONN_TYPE_NONE = 0,
564ac7516bSRavi Kumar 	AXGBE_CONN_TYPE_SFP,
574ac7516bSRavi Kumar 	AXGBE_CONN_TYPE_MDIO,
584ac7516bSRavi Kumar 	AXGBE_CONN_TYPE_RSVD1,
594ac7516bSRavi Kumar 	AXGBE_CONN_TYPE_BACKPLANE,
604ac7516bSRavi Kumar 	AXGBE_CONN_TYPE_MAX,
614ac7516bSRavi Kumar };
624ac7516bSRavi Kumar 
634ac7516bSRavi Kumar /* SFP/SFP+ related definitions */
644ac7516bSRavi Kumar enum axgbe_sfp_comm {
654ac7516bSRavi Kumar 	AXGBE_SFP_COMM_DIRECT = 0,
664ac7516bSRavi Kumar 	AXGBE_SFP_COMM_PCA9545,
674ac7516bSRavi Kumar };
684ac7516bSRavi Kumar 
694ac7516bSRavi Kumar enum axgbe_sfp_cable {
704ac7516bSRavi Kumar 	AXGBE_SFP_CABLE_UNKNOWN = 0,
714ac7516bSRavi Kumar 	AXGBE_SFP_CABLE_ACTIVE,
724ac7516bSRavi Kumar 	AXGBE_SFP_CABLE_PASSIVE,
734823ccdbSVenkat Kumar Ande 	AXGBE_SFP_CABLE_FIBER,
744ac7516bSRavi Kumar };
754ac7516bSRavi Kumar 
764ac7516bSRavi Kumar enum axgbe_sfp_base {
774ac7516bSRavi Kumar 	AXGBE_SFP_BASE_UNKNOWN = 0,
784ac7516bSRavi Kumar 	AXGBE_SFP_BASE_1000_T,
794ac7516bSRavi Kumar 	AXGBE_SFP_BASE_1000_SX,
804ac7516bSRavi Kumar 	AXGBE_SFP_BASE_1000_LX,
814ac7516bSRavi Kumar 	AXGBE_SFP_BASE_1000_CX,
824ac7516bSRavi Kumar 	AXGBE_SFP_BASE_10000_SR,
834ac7516bSRavi Kumar 	AXGBE_SFP_BASE_10000_LR,
844ac7516bSRavi Kumar 	AXGBE_SFP_BASE_10000_LRM,
854ac7516bSRavi Kumar 	AXGBE_SFP_BASE_10000_ER,
864ac7516bSRavi Kumar 	AXGBE_SFP_BASE_10000_CR,
874ac7516bSRavi Kumar };
884ac7516bSRavi Kumar 
894ac7516bSRavi Kumar enum axgbe_sfp_speed {
904ac7516bSRavi Kumar 	AXGBE_SFP_SPEED_UNKNOWN = 0,
914ac7516bSRavi Kumar 	AXGBE_SFP_SPEED_100_1000,
924ac7516bSRavi Kumar 	AXGBE_SFP_SPEED_1000,
934ac7516bSRavi Kumar 	AXGBE_SFP_SPEED_10000,
944ac7516bSRavi Kumar };
954ac7516bSRavi Kumar 
964ac7516bSRavi Kumar /* SFP Serial ID Base ID values relative to an offset of 0 */
974ac7516bSRavi Kumar #define AXGBE_SFP_BASE_ID			0
984ac7516bSRavi Kumar #define AXGBE_SFP_ID_SFP			0x03
994ac7516bSRavi Kumar 
1004ac7516bSRavi Kumar #define AXGBE_SFP_BASE_EXT_ID			1
1014ac7516bSRavi Kumar #define AXGBE_SFP_EXT_ID_SFP			0x04
1024ac7516bSRavi Kumar 
1034ac7516bSRavi Kumar #define AXGBE_SFP_BASE_10GBE_CC			3
1044ac7516bSRavi Kumar #define AXGBE_SFP_BASE_10GBE_CC_SR		BIT(4)
1054ac7516bSRavi Kumar #define AXGBE_SFP_BASE_10GBE_CC_LR		BIT(5)
1064ac7516bSRavi Kumar #define AXGBE_SFP_BASE_10GBE_CC_LRM		BIT(6)
1074ac7516bSRavi Kumar #define AXGBE_SFP_BASE_10GBE_CC_ER		BIT(7)
1084ac7516bSRavi Kumar 
1094ac7516bSRavi Kumar #define AXGBE_SFP_BASE_1GBE_CC			6
1104ac7516bSRavi Kumar #define AXGBE_SFP_BASE_1GBE_CC_SX		BIT(0)
1114ac7516bSRavi Kumar #define AXGBE_SFP_BASE_1GBE_CC_LX		BIT(1)
1124ac7516bSRavi Kumar #define AXGBE_SFP_BASE_1GBE_CC_CX		BIT(2)
1134ac7516bSRavi Kumar #define AXGBE_SFP_BASE_1GBE_CC_T		BIT(3)
1144ac7516bSRavi Kumar 
1154ac7516bSRavi Kumar #define AXGBE_SFP_BASE_CABLE			8
1164ac7516bSRavi Kumar #define AXGBE_SFP_BASE_CABLE_PASSIVE		BIT(2)
1174ac7516bSRavi Kumar #define AXGBE_SFP_BASE_CABLE_ACTIVE		BIT(3)
1184ac7516bSRavi Kumar 
1194ac7516bSRavi Kumar #define AXGBE_SFP_BASE_BR			12
1204ac7516bSRavi Kumar #define AXGBE_SFP_BASE_BR_1GBE_MIN		0x0a
1214ac7516bSRavi Kumar #define AXGBE_SFP_BASE_BR_10GBE_MIN		0x64
1224ac7516bSRavi Kumar 
1234ac7516bSRavi Kumar #define AXGBE_SFP_BASE_CU_CABLE_LEN		18
1244ac7516bSRavi Kumar 
1254ac7516bSRavi Kumar #define AXGBE_SFP_BASE_VENDOR_NAME		20
1264ac7516bSRavi Kumar #define AXGBE_SFP_BASE_VENDOR_NAME_LEN		16
1274ac7516bSRavi Kumar #define AXGBE_SFP_BASE_VENDOR_PN		40
1284ac7516bSRavi Kumar #define AXGBE_SFP_BASE_VENDOR_PN_LEN		16
1294ac7516bSRavi Kumar #define AXGBE_SFP_BASE_VENDOR_REV		56
1304ac7516bSRavi Kumar #define AXGBE_SFP_BASE_VENDOR_REV_LEN		4
1314ac7516bSRavi Kumar 
1324ac7516bSRavi Kumar #define AXGBE_SFP_BASE_CC			63
1334ac7516bSRavi Kumar 
1344ac7516bSRavi Kumar /* SFP Serial ID Extended ID values relative to an offset of 64 */
1354ac7516bSRavi Kumar #define AXGBE_SFP_BASE_VENDOR_SN		4
1364ac7516bSRavi Kumar #define AXGBE_SFP_BASE_VENDOR_SN_LEN		16
1374ac7516bSRavi Kumar 
1384ac7516bSRavi Kumar #define AXGBE_SFP_EXTD_DIAG			28
1394ac7516bSRavi Kumar #define AXGBE_SFP_EXTD_DIAG_ADDR_CHANGE		BIT(2)
1404ac7516bSRavi Kumar 
1414ac7516bSRavi Kumar #define AXGBE_SFP_EXTD_SFF_8472			30
1424ac7516bSRavi Kumar 
1434ac7516bSRavi Kumar #define AXGBE_SFP_EXTD_CC			31
1444ac7516bSRavi Kumar 
1454ac7516bSRavi Kumar struct axgbe_sfp_eeprom {
1464ac7516bSRavi Kumar 	u8 base[64];
1474ac7516bSRavi Kumar 	u8 extd[32];
1484ac7516bSRavi Kumar 	u8 vendor[32];
1494ac7516bSRavi Kumar };
1504ac7516bSRavi Kumar 
1514ac7516bSRavi Kumar #define AXGBE_BEL_FUSE_VENDOR	"BEL-FUSE"
1524ac7516bSRavi Kumar #define AXGBE_BEL_FUSE_PARTNO	"1GBT-SFP06"
1534ac7516bSRavi Kumar 
1544ac7516bSRavi Kumar struct axgbe_sfp_ascii {
1554ac7516bSRavi Kumar 	union {
1564ac7516bSRavi Kumar 		char vendor[AXGBE_SFP_BASE_VENDOR_NAME_LEN + 1];
1574ac7516bSRavi Kumar 		char partno[AXGBE_SFP_BASE_VENDOR_PN_LEN + 1];
1584ac7516bSRavi Kumar 		char rev[AXGBE_SFP_BASE_VENDOR_REV_LEN + 1];
1594ac7516bSRavi Kumar 		char serno[AXGBE_SFP_BASE_VENDOR_SN_LEN + 1];
1604ac7516bSRavi Kumar 	} u;
1614ac7516bSRavi Kumar };
1624ac7516bSRavi Kumar 
1634ac7516bSRavi Kumar /* MDIO PHY reset types */
1644ac7516bSRavi Kumar enum axgbe_mdio_reset {
1654ac7516bSRavi Kumar 	AXGBE_MDIO_RESET_NONE = 0,
1664ac7516bSRavi Kumar 	AXGBE_MDIO_RESET_I2C_GPIO,
1674ac7516bSRavi Kumar 	AXGBE_MDIO_RESET_INT_GPIO,
1684ac7516bSRavi Kumar 	AXGBE_MDIO_RESET_MAX,
1694ac7516bSRavi Kumar };
1704ac7516bSRavi Kumar 
1714ac7516bSRavi Kumar /* Re-driver related definitions */
1724ac7516bSRavi Kumar enum axgbe_phy_redrv_if {
1734ac7516bSRavi Kumar 	AXGBE_PHY_REDRV_IF_MDIO = 0,
1744ac7516bSRavi Kumar 	AXGBE_PHY_REDRV_IF_I2C,
1754ac7516bSRavi Kumar 	AXGBE_PHY_REDRV_IF_MAX,
1764ac7516bSRavi Kumar };
1774ac7516bSRavi Kumar 
1784ac7516bSRavi Kumar enum axgbe_phy_redrv_model {
1794ac7516bSRavi Kumar 	AXGBE_PHY_REDRV_MODEL_4223 = 0,
1804ac7516bSRavi Kumar 	AXGBE_PHY_REDRV_MODEL_4227,
1814ac7516bSRavi Kumar 	AXGBE_PHY_REDRV_MODEL_MAX,
1824ac7516bSRavi Kumar };
1834ac7516bSRavi Kumar 
1844ac7516bSRavi Kumar enum axgbe_phy_redrv_mode {
1854ac7516bSRavi Kumar 	AXGBE_PHY_REDRV_MODE_CX = 5,
1864ac7516bSRavi Kumar 	AXGBE_PHY_REDRV_MODE_SR = 9,
1874ac7516bSRavi Kumar };
1884ac7516bSRavi Kumar 
1894ac7516bSRavi Kumar #define AXGBE_PHY_REDRV_MODE_REG	0x12b0
1904ac7516bSRavi Kumar 
1914ac7516bSRavi Kumar /* PHY related configuration information */
1924ac7516bSRavi Kumar struct axgbe_phy_data {
1934ac7516bSRavi Kumar 	enum axgbe_port_mode port_mode;
1944ac7516bSRavi Kumar 
1954ac7516bSRavi Kumar 	unsigned int port_id;
1964ac7516bSRavi Kumar 
1974ac7516bSRavi Kumar 	unsigned int port_speeds;
1984ac7516bSRavi Kumar 
1994ac7516bSRavi Kumar 	enum axgbe_conn_type conn_type;
2004ac7516bSRavi Kumar 
2014ac7516bSRavi Kumar 	enum axgbe_mode cur_mode;
2024ac7516bSRavi Kumar 	enum axgbe_mode start_mode;
2034ac7516bSRavi Kumar 
2044ac7516bSRavi Kumar 	unsigned int rrc_count;
2054ac7516bSRavi Kumar 
2064ac7516bSRavi Kumar 	unsigned int mdio_addr;
2074ac7516bSRavi Kumar 
2084ac7516bSRavi Kumar 	/* SFP Support */
2094ac7516bSRavi Kumar 	enum axgbe_sfp_comm sfp_comm;
2104ac7516bSRavi Kumar 	unsigned int sfp_mux_address;
2114ac7516bSRavi Kumar 	unsigned int sfp_mux_channel;
2124ac7516bSRavi Kumar 
2134ac7516bSRavi Kumar 	unsigned int sfp_gpio_address;
2144ac7516bSRavi Kumar 	unsigned int sfp_gpio_mask;
2154ac7516bSRavi Kumar 	unsigned int sfp_gpio_rx_los;
2164ac7516bSRavi Kumar 	unsigned int sfp_gpio_tx_fault;
2174ac7516bSRavi Kumar 	unsigned int sfp_gpio_mod_absent;
2184ac7516bSRavi Kumar 	unsigned int sfp_gpio_rate_select;
2194ac7516bSRavi Kumar 
2204ac7516bSRavi Kumar 	unsigned int sfp_rx_los;
2214ac7516bSRavi Kumar 	unsigned int sfp_tx_fault;
2224ac7516bSRavi Kumar 	unsigned int sfp_mod_absent;
2234ac7516bSRavi Kumar 	unsigned int sfp_changed;
2244ac7516bSRavi Kumar 	unsigned int sfp_phy_avail;
2254ac7516bSRavi Kumar 	unsigned int sfp_cable_len;
2264ac7516bSRavi Kumar 	enum axgbe_sfp_base sfp_base;
2274ac7516bSRavi Kumar 	enum axgbe_sfp_cable sfp_cable;
2284ac7516bSRavi Kumar 	enum axgbe_sfp_speed sfp_speed;
2294ac7516bSRavi Kumar 	struct axgbe_sfp_eeprom sfp_eeprom;
2304ac7516bSRavi Kumar 
2314ac7516bSRavi Kumar 	/* External PHY support */
2324ac7516bSRavi Kumar 	enum axgbe_mdio_mode phydev_mode;
2334ac7516bSRavi Kumar 	enum axgbe_mdio_reset mdio_reset;
2344ac7516bSRavi Kumar 	unsigned int mdio_reset_addr;
2354ac7516bSRavi Kumar 	unsigned int mdio_reset_gpio;
2364ac7516bSRavi Kumar 
2374ac7516bSRavi Kumar 	/* Re-driver support */
2384ac7516bSRavi Kumar 	unsigned int redrv;
2394ac7516bSRavi Kumar 	unsigned int redrv_if;
2404ac7516bSRavi Kumar 	unsigned int redrv_addr;
2414ac7516bSRavi Kumar 	unsigned int redrv_lane;
2424ac7516bSRavi Kumar 	unsigned int redrv_model;
24300072056SRavi Kumar 
24400072056SRavi Kumar 	/* KR AN support */
24500072056SRavi Kumar 	unsigned int phy_cdr_notrack;
24600072056SRavi Kumar 	unsigned int phy_cdr_delay;
2474ac7516bSRavi Kumar };
2484ac7516bSRavi Kumar 
249a5c72737SRavi Kumar static enum axgbe_an_mode axgbe_phy_an_mode(struct axgbe_port *pdata);
250a5c72737SRavi Kumar 
251a5c72737SRavi Kumar static int axgbe_phy_i2c_xfer(struct axgbe_port *pdata,
252a5c72737SRavi Kumar 			      struct axgbe_i2c_op *i2c_op)
253a5c72737SRavi Kumar {
254a5c72737SRavi Kumar 	return pdata->i2c_if.i2c_xfer(pdata, i2c_op);
255a5c72737SRavi Kumar }
256a5c72737SRavi Kumar 
257a5c72737SRavi Kumar static int axgbe_phy_redrv_write(struct axgbe_port *pdata, unsigned int reg,
258a5c72737SRavi Kumar 				 unsigned int val)
259a5c72737SRavi Kumar {
260a5c72737SRavi Kumar 	struct axgbe_phy_data *phy_data = pdata->phy_data;
261a5c72737SRavi Kumar 	struct axgbe_i2c_op i2c_op;
262a5c72737SRavi Kumar 	uint16_t *redrv_val;
263a5c72737SRavi Kumar 	u8 redrv_data[5], csum;
264a5c72737SRavi Kumar 	unsigned int i, retry;
265a5c72737SRavi Kumar 	int ret;
266a5c72737SRavi Kumar 
267a5c72737SRavi Kumar 	/* High byte of register contains read/write indicator */
268a5c72737SRavi Kumar 	redrv_data[0] = ((reg >> 8) & 0xff) << 1;
269a5c72737SRavi Kumar 	redrv_data[1] = reg & 0xff;
270a5c72737SRavi Kumar 	redrv_val = (uint16_t *)&redrv_data[2];
271a5c72737SRavi Kumar 	*redrv_val = rte_cpu_to_be_16(val);
272a5c72737SRavi Kumar 
273a5c72737SRavi Kumar 	/* Calculate 1 byte checksum */
274a5c72737SRavi Kumar 	csum = 0;
275a5c72737SRavi Kumar 	for (i = 0; i < 4; i++) {
276a5c72737SRavi Kumar 		csum += redrv_data[i];
277a5c72737SRavi Kumar 		if (redrv_data[i] > csum)
278a5c72737SRavi Kumar 			csum++;
279a5c72737SRavi Kumar 	}
280a5c72737SRavi Kumar 	redrv_data[4] = ~csum;
281a5c72737SRavi Kumar 
282a5c72737SRavi Kumar 	retry = 1;
283a5c72737SRavi Kumar again1:
284a5c72737SRavi Kumar 	i2c_op.cmd = AXGBE_I2C_CMD_WRITE;
285a5c72737SRavi Kumar 	i2c_op.target = phy_data->redrv_addr;
286a5c72737SRavi Kumar 	i2c_op.len = sizeof(redrv_data);
287a5c72737SRavi Kumar 	i2c_op.buf = redrv_data;
288a5c72737SRavi Kumar 	ret = axgbe_phy_i2c_xfer(pdata, &i2c_op);
289a5c72737SRavi Kumar 	if (ret) {
290a5c72737SRavi Kumar 		if ((ret == -EAGAIN) && retry--)
291a5c72737SRavi Kumar 			goto again1;
292a5c72737SRavi Kumar 
293a5c72737SRavi Kumar 		return ret;
294a5c72737SRavi Kumar 	}
295a5c72737SRavi Kumar 
296a5c72737SRavi Kumar 	retry = 1;
297a5c72737SRavi Kumar again2:
298a5c72737SRavi Kumar 	i2c_op.cmd = AXGBE_I2C_CMD_READ;
299a5c72737SRavi Kumar 	i2c_op.target = phy_data->redrv_addr;
300a5c72737SRavi Kumar 	i2c_op.len = 1;
301a5c72737SRavi Kumar 	i2c_op.buf = redrv_data;
302a5c72737SRavi Kumar 	ret = axgbe_phy_i2c_xfer(pdata, &i2c_op);
303a5c72737SRavi Kumar 	if (ret) {
304a5c72737SRavi Kumar 		if ((ret == -EAGAIN) && retry--)
305a5c72737SRavi Kumar 			goto again2;
306a5c72737SRavi Kumar 
307a5c72737SRavi Kumar 		return ret;
308a5c72737SRavi Kumar 	}
309a5c72737SRavi Kumar 
310a5c72737SRavi Kumar 	if (redrv_data[0] != 0xff) {
311a5c72737SRavi Kumar 		PMD_DRV_LOG(ERR, "Redriver write checksum error\n");
312a5c72737SRavi Kumar 		ret = -EIO;
313a5c72737SRavi Kumar 	}
314a5c72737SRavi Kumar 
315a5c72737SRavi Kumar 	return ret;
316a5c72737SRavi Kumar }
317a5c72737SRavi Kumar 
318a5c72737SRavi Kumar static int axgbe_phy_i2c_read(struct axgbe_port *pdata, unsigned int target,
319a5c72737SRavi Kumar 			      void *reg, unsigned int reg_len,
320a5c72737SRavi Kumar 			      void *val, unsigned int val_len)
321a5c72737SRavi Kumar {
322a5c72737SRavi Kumar 	struct axgbe_i2c_op i2c_op;
323a5c72737SRavi Kumar 	int retry, ret;
324a5c72737SRavi Kumar 
325a5c72737SRavi Kumar 	retry = 1;
326a5c72737SRavi Kumar again1:
327a5c72737SRavi Kumar 	/* Set the specified register to read */
328a5c72737SRavi Kumar 	i2c_op.cmd = AXGBE_I2C_CMD_WRITE;
329a5c72737SRavi Kumar 	i2c_op.target = target;
330a5c72737SRavi Kumar 	i2c_op.len = reg_len;
331a5c72737SRavi Kumar 	i2c_op.buf = reg;
332a5c72737SRavi Kumar 	ret = axgbe_phy_i2c_xfer(pdata, &i2c_op);
333a5c72737SRavi Kumar 	if (ret) {
334a5c72737SRavi Kumar 		if ((ret == -EAGAIN) && retry--)
335a5c72737SRavi Kumar 			goto again1;
336a5c72737SRavi Kumar 
337a5c72737SRavi Kumar 		return ret;
338a5c72737SRavi Kumar 	}
339a5c72737SRavi Kumar 
340a5c72737SRavi Kumar 	retry = 1;
341a5c72737SRavi Kumar again2:
3427be78d02SJosh Soref 	/* Read the specified register */
343a5c72737SRavi Kumar 	i2c_op.cmd = AXGBE_I2C_CMD_READ;
344a5c72737SRavi Kumar 	i2c_op.target = target;
345a5c72737SRavi Kumar 	i2c_op.len = val_len;
346a5c72737SRavi Kumar 	i2c_op.buf = val;
347a5c72737SRavi Kumar 	ret = axgbe_phy_i2c_xfer(pdata, &i2c_op);
348a5c72737SRavi Kumar 	if ((ret == -EAGAIN) && retry--)
349a5c72737SRavi Kumar 		goto again2;
350a5c72737SRavi Kumar 
351a5c72737SRavi Kumar 	return ret;
352a5c72737SRavi Kumar }
353a5c72737SRavi Kumar 
354a5c72737SRavi Kumar static int axgbe_phy_sfp_put_mux(struct axgbe_port *pdata)
355a5c72737SRavi Kumar {
356a5c72737SRavi Kumar 	struct axgbe_phy_data *phy_data = pdata->phy_data;
357a5c72737SRavi Kumar 	struct axgbe_i2c_op i2c_op;
358a5c72737SRavi Kumar 	uint8_t mux_channel;
359a5c72737SRavi Kumar 
360a5c72737SRavi Kumar 	if (phy_data->sfp_comm == AXGBE_SFP_COMM_DIRECT)
361a5c72737SRavi Kumar 		return 0;
362a5c72737SRavi Kumar 
363a5c72737SRavi Kumar 	/* Select no mux channels */
364a5c72737SRavi Kumar 	mux_channel = 0;
365a5c72737SRavi Kumar 	i2c_op.cmd = AXGBE_I2C_CMD_WRITE;
366a5c72737SRavi Kumar 	i2c_op.target = phy_data->sfp_mux_address;
367a5c72737SRavi Kumar 	i2c_op.len = sizeof(mux_channel);
368a5c72737SRavi Kumar 	i2c_op.buf = &mux_channel;
369a5c72737SRavi Kumar 
370a5c72737SRavi Kumar 	return axgbe_phy_i2c_xfer(pdata, &i2c_op);
371a5c72737SRavi Kumar }
372a5c72737SRavi Kumar 
373a5c72737SRavi Kumar static int axgbe_phy_sfp_get_mux(struct axgbe_port *pdata)
374a5c72737SRavi Kumar {
375a5c72737SRavi Kumar 	struct axgbe_phy_data *phy_data = pdata->phy_data;
376a5c72737SRavi Kumar 	struct axgbe_i2c_op i2c_op;
377a5c72737SRavi Kumar 	u8 mux_channel;
378a5c72737SRavi Kumar 
379a5c72737SRavi Kumar 	if (phy_data->sfp_comm == AXGBE_SFP_COMM_DIRECT)
380a5c72737SRavi Kumar 		return 0;
381a5c72737SRavi Kumar 
382a5c72737SRavi Kumar 	/* Select desired mux channel */
383a5c72737SRavi Kumar 	mux_channel = 1 << phy_data->sfp_mux_channel;
384a5c72737SRavi Kumar 	i2c_op.cmd = AXGBE_I2C_CMD_WRITE;
385a5c72737SRavi Kumar 	i2c_op.target = phy_data->sfp_mux_address;
386a5c72737SRavi Kumar 	i2c_op.len = sizeof(mux_channel);
387a5c72737SRavi Kumar 	i2c_op.buf = &mux_channel;
388a5c72737SRavi Kumar 
389a5c72737SRavi Kumar 	return axgbe_phy_i2c_xfer(pdata, &i2c_op);
390a5c72737SRavi Kumar }
391a5c72737SRavi Kumar 
392a5c72737SRavi Kumar static void axgbe_phy_put_comm_ownership(struct axgbe_port *pdata)
393a5c72737SRavi Kumar {
394a5c72737SRavi Kumar 	pthread_mutex_unlock(&pdata->phy_mutex);
395a5c72737SRavi Kumar }
396a5c72737SRavi Kumar 
397a5c72737SRavi Kumar static int axgbe_phy_get_comm_ownership(struct axgbe_port *pdata)
398a5c72737SRavi Kumar {
399a5c72737SRavi Kumar 	struct axgbe_phy_data *phy_data = pdata->phy_data;
400a5c72737SRavi Kumar 	uint64_t timeout;
401a5c72737SRavi Kumar 	unsigned int mutex_id;
402a5c72737SRavi Kumar 
403a5c72737SRavi Kumar 	/* The I2C and MDIO/GPIO bus is multiplexed between multiple devices,
404a5c72737SRavi Kumar 	 * the driver needs to take the software mutex and then the hardware
405a5c72737SRavi Kumar 	 * mutexes before being able to use the busses.
406a5c72737SRavi Kumar 	 */
407a5c72737SRavi Kumar 	pthread_mutex_lock(&pdata->phy_mutex);
408a5c72737SRavi Kumar 
409a5c72737SRavi Kumar 	/* Clear the mutexes */
410a5c72737SRavi Kumar 	XP_IOWRITE(pdata, XP_I2C_MUTEX, AXGBE_MUTEX_RELEASE);
411a5c72737SRavi Kumar 	XP_IOWRITE(pdata, XP_MDIO_MUTEX, AXGBE_MUTEX_RELEASE);
412a5c72737SRavi Kumar 
413a5c72737SRavi Kumar 	/* Mutex formats are the same for I2C and MDIO/GPIO */
414a5c72737SRavi Kumar 	mutex_id = 0;
415a5c72737SRavi Kumar 	XP_SET_BITS(mutex_id, XP_I2C_MUTEX, ID, phy_data->port_id);
416a5c72737SRavi Kumar 	XP_SET_BITS(mutex_id, XP_I2C_MUTEX, ACTIVE, 1);
417a5c72737SRavi Kumar 
418a5c72737SRavi Kumar 	timeout = rte_get_timer_cycles() + (rte_get_timer_hz() * 5);
419a5c72737SRavi Kumar 	while (time_before(rte_get_timer_cycles(), timeout)) {
420a5c72737SRavi Kumar 		/* Must be all zeroes in order to obtain the mutex */
421a5c72737SRavi Kumar 		if (XP_IOREAD(pdata, XP_I2C_MUTEX) ||
422a5c72737SRavi Kumar 		    XP_IOREAD(pdata, XP_MDIO_MUTEX)) {
423a5c72737SRavi Kumar 			rte_delay_us(100);
424a5c72737SRavi Kumar 			continue;
425a5c72737SRavi Kumar 		}
426a5c72737SRavi Kumar 
427a5c72737SRavi Kumar 		/* Obtain the mutex */
428a5c72737SRavi Kumar 		XP_IOWRITE(pdata, XP_I2C_MUTEX, mutex_id);
429a5c72737SRavi Kumar 		XP_IOWRITE(pdata, XP_MDIO_MUTEX, mutex_id);
430a5c72737SRavi Kumar 
431a5c72737SRavi Kumar 		return 0;
432a5c72737SRavi Kumar 	}
433a5c72737SRavi Kumar 
434a5c72737SRavi Kumar 	pthread_mutex_unlock(&pdata->phy_mutex);
435a5c72737SRavi Kumar 
436a5c72737SRavi Kumar 	PMD_DRV_LOG(ERR, "unable to obtain hardware mutexes\n");
437a5c72737SRavi Kumar 
438a5c72737SRavi Kumar 	return -ETIMEDOUT;
439a5c72737SRavi Kumar }
440a5c72737SRavi Kumar 
441a5c72737SRavi Kumar static void axgbe_phy_sfp_phy_settings(struct axgbe_port *pdata)
442a5c72737SRavi Kumar {
443a5c72737SRavi Kumar 	struct axgbe_phy_data *phy_data = pdata->phy_data;
444a5c72737SRavi Kumar 
445a5c72737SRavi Kumar 	if (phy_data->sfp_mod_absent) {
446a5c72737SRavi Kumar 		pdata->phy.speed = SPEED_UNKNOWN;
447a5c72737SRavi Kumar 		pdata->phy.duplex = DUPLEX_UNKNOWN;
448a5c72737SRavi Kumar 		pdata->phy.autoneg = AUTONEG_ENABLE;
449a5c72737SRavi Kumar 		pdata->phy.advertising = pdata->phy.supported;
450a5c72737SRavi Kumar 	}
451a5c72737SRavi Kumar 
452a5c72737SRavi Kumar 	pdata->phy.advertising &= ~ADVERTISED_Autoneg;
453a5c72737SRavi Kumar 	pdata->phy.advertising &= ~ADVERTISED_TP;
454a5c72737SRavi Kumar 	pdata->phy.advertising &= ~ADVERTISED_FIBRE;
455a5c72737SRavi Kumar 	pdata->phy.advertising &= ~ADVERTISED_100baseT_Full;
456a5c72737SRavi Kumar 	pdata->phy.advertising &= ~ADVERTISED_1000baseT_Full;
457a5c72737SRavi Kumar 	pdata->phy.advertising &= ~ADVERTISED_10000baseT_Full;
458a5c72737SRavi Kumar 	pdata->phy.advertising &= ~ADVERTISED_10000baseR_FEC;
459a5c72737SRavi Kumar 
460a5c72737SRavi Kumar 	switch (phy_data->sfp_base) {
461a5c72737SRavi Kumar 	case AXGBE_SFP_BASE_1000_T:
462a5c72737SRavi Kumar 	case AXGBE_SFP_BASE_1000_SX:
463a5c72737SRavi Kumar 	case AXGBE_SFP_BASE_1000_LX:
464a5c72737SRavi Kumar 	case AXGBE_SFP_BASE_1000_CX:
465a5c72737SRavi Kumar 		pdata->phy.speed = SPEED_UNKNOWN;
466a5c72737SRavi Kumar 		pdata->phy.duplex = DUPLEX_UNKNOWN;
467a5c72737SRavi Kumar 		pdata->phy.autoneg = AUTONEG_ENABLE;
468a5c72737SRavi Kumar 		pdata->phy.advertising |= ADVERTISED_Autoneg;
469a5c72737SRavi Kumar 		break;
470a5c72737SRavi Kumar 	case AXGBE_SFP_BASE_10000_SR:
471a5c72737SRavi Kumar 	case AXGBE_SFP_BASE_10000_LR:
472a5c72737SRavi Kumar 	case AXGBE_SFP_BASE_10000_LRM:
473a5c72737SRavi Kumar 	case AXGBE_SFP_BASE_10000_ER:
474a5c72737SRavi Kumar 	case AXGBE_SFP_BASE_10000_CR:
475a5c72737SRavi Kumar 	default:
476a5c72737SRavi Kumar 		pdata->phy.speed = SPEED_10000;
477a5c72737SRavi Kumar 		pdata->phy.duplex = DUPLEX_FULL;
478a5c72737SRavi Kumar 		pdata->phy.autoneg = AUTONEG_DISABLE;
479a5c72737SRavi Kumar 		break;
480a5c72737SRavi Kumar 	}
481a5c72737SRavi Kumar 
482a5c72737SRavi Kumar 	switch (phy_data->sfp_base) {
483a5c72737SRavi Kumar 	case AXGBE_SFP_BASE_1000_T:
484a5c72737SRavi Kumar 	case AXGBE_SFP_BASE_1000_CX:
485a5c72737SRavi Kumar 	case AXGBE_SFP_BASE_10000_CR:
486a5c72737SRavi Kumar 		pdata->phy.advertising |= ADVERTISED_TP;
487a5c72737SRavi Kumar 		break;
488a5c72737SRavi Kumar 	default:
489a5c72737SRavi Kumar 		pdata->phy.advertising |= ADVERTISED_FIBRE;
490a5c72737SRavi Kumar 	}
491a5c72737SRavi Kumar 
492a5c72737SRavi Kumar 	switch (phy_data->sfp_speed) {
493a5c72737SRavi Kumar 	case AXGBE_SFP_SPEED_100_1000:
494*1f9d2d3aSVenkat Kumar Ande 		if (phy_data->port_speeds & AXGBE_PHY_PORT_SPEED_10)
495*1f9d2d3aSVenkat Kumar Ande 			pdata->phy.advertising |= ADVERTISED_10baseT_Full;
496a5c72737SRavi Kumar 		if (phy_data->port_speeds & AXGBE_PHY_PORT_SPEED_100)
497a5c72737SRavi Kumar 			pdata->phy.advertising |= ADVERTISED_100baseT_Full;
498a5c72737SRavi Kumar 		if (phy_data->port_speeds & AXGBE_PHY_PORT_SPEED_1000)
499a5c72737SRavi Kumar 			pdata->phy.advertising |= ADVERTISED_1000baseT_Full;
500a5c72737SRavi Kumar 		break;
501a5c72737SRavi Kumar 	case AXGBE_SFP_SPEED_1000:
502a5c72737SRavi Kumar 		if (phy_data->port_speeds & AXGBE_PHY_PORT_SPEED_1000)
503a5c72737SRavi Kumar 			pdata->phy.advertising |= ADVERTISED_1000baseT_Full;
504a5c72737SRavi Kumar 		break;
505a5c72737SRavi Kumar 	case AXGBE_SFP_SPEED_10000:
506a5c72737SRavi Kumar 		if (phy_data->port_speeds & AXGBE_PHY_PORT_SPEED_10000)
507a5c72737SRavi Kumar 			pdata->phy.advertising |= ADVERTISED_10000baseT_Full;
508a5c72737SRavi Kumar 		break;
509a5c72737SRavi Kumar 	default:
510a5c72737SRavi Kumar 		/* Choose the fastest supported speed */
511a5c72737SRavi Kumar 		if (phy_data->port_speeds & AXGBE_PHY_PORT_SPEED_10000)
512a5c72737SRavi Kumar 			pdata->phy.advertising |= ADVERTISED_10000baseT_Full;
513a5c72737SRavi Kumar 		else if (phy_data->port_speeds & AXGBE_PHY_PORT_SPEED_1000)
514a5c72737SRavi Kumar 			pdata->phy.advertising |= ADVERTISED_1000baseT_Full;
515a5c72737SRavi Kumar 		else if (phy_data->port_speeds & AXGBE_PHY_PORT_SPEED_100)
516a5c72737SRavi Kumar 			pdata->phy.advertising |= ADVERTISED_100baseT_Full;
517*1f9d2d3aSVenkat Kumar Ande 		else if (phy_data->port_speeds & AXGBE_PHY_PORT_SPEED_10)
518*1f9d2d3aSVenkat Kumar Ande 			pdata->phy.advertising |= ADVERTISED_10baseT_Full;
519a5c72737SRavi Kumar 	}
520a5c72737SRavi Kumar }
521a5c72737SRavi Kumar 
522a5c72737SRavi Kumar static bool axgbe_phy_sfp_bit_rate(struct axgbe_sfp_eeprom *sfp_eeprom,
523a5c72737SRavi Kumar 				   enum axgbe_sfp_speed sfp_speed)
524a5c72737SRavi Kumar {
525b5587a39SVenkat Kumar Ande 	u8 *sfp_base, min;
526a5c72737SRavi Kumar 
527a5c72737SRavi Kumar 	sfp_base = sfp_eeprom->base;
528a5c72737SRavi Kumar 
529a5c72737SRavi Kumar 	switch (sfp_speed) {
530a5c72737SRavi Kumar 	case AXGBE_SFP_SPEED_1000:
531a5c72737SRavi Kumar 		min = AXGBE_SFP_BASE_BR_1GBE_MIN;
532a5c72737SRavi Kumar 		break;
533a5c72737SRavi Kumar 	case AXGBE_SFP_SPEED_10000:
534a5c72737SRavi Kumar 		min = AXGBE_SFP_BASE_BR_10GBE_MIN;
535a5c72737SRavi Kumar 		break;
536a5c72737SRavi Kumar 	default:
537a5c72737SRavi Kumar 		return false;
538a5c72737SRavi Kumar 	}
539a5c72737SRavi Kumar 
540b5587a39SVenkat Kumar Ande 	return sfp_base[AXGBE_SFP_BASE_BR] >= min;
541a5c72737SRavi Kumar }
542a5c72737SRavi Kumar 
543a5c72737SRavi Kumar static void axgbe_phy_sfp_external_phy(struct axgbe_port *pdata)
544a5c72737SRavi Kumar {
545a5c72737SRavi Kumar 	struct axgbe_phy_data *phy_data = pdata->phy_data;
546a5c72737SRavi Kumar 
547a5c72737SRavi Kumar 	if (!phy_data->sfp_changed)
548a5c72737SRavi Kumar 		return;
549a5c72737SRavi Kumar 
550a5c72737SRavi Kumar 	phy_data->sfp_phy_avail = 0;
551a5c72737SRavi Kumar 
552a5c72737SRavi Kumar 	if (phy_data->sfp_base != AXGBE_SFP_BASE_1000_T)
553a5c72737SRavi Kumar 		return;
554a5c72737SRavi Kumar }
555a5c72737SRavi Kumar 
556a5c72737SRavi Kumar static bool axgbe_phy_belfuse_parse_quirks(struct axgbe_port *pdata)
557a5c72737SRavi Kumar {
558a5c72737SRavi Kumar 	struct axgbe_phy_data *phy_data = pdata->phy_data;
559a5c72737SRavi Kumar 	struct axgbe_sfp_eeprom *sfp_eeprom = &phy_data->sfp_eeprom;
560a5c72737SRavi Kumar 
561a5c72737SRavi Kumar 	if (memcmp(&sfp_eeprom->base[AXGBE_SFP_BASE_VENDOR_NAME],
56227578231SAndy Green 		   AXGBE_BEL_FUSE_VENDOR, strlen(AXGBE_BEL_FUSE_VENDOR)))
563a5c72737SRavi Kumar 		return false;
564a770d00aSVenkat Kumar Ande 	/* For Bel-Fuse, use the extra AN flag */
565a770d00aSVenkat Kumar Ande 	pdata->an_again = 1;
566a5c72737SRavi Kumar 
5673abfda0fSVenkat Kumar Ande 	/* Reset PHY - wait for self-clearing reset bit to clear */
5683abfda0fSVenkat Kumar Ande 	pdata->phy_if.phy_impl.reset(pdata);
5693abfda0fSVenkat Kumar Ande 
570a5c72737SRavi Kumar 	if (!memcmp(&sfp_eeprom->base[AXGBE_SFP_BASE_VENDOR_PN],
57127578231SAndy Green 		    AXGBE_BEL_FUSE_PARTNO, strlen(AXGBE_BEL_FUSE_PARTNO))) {
572a5c72737SRavi Kumar 		phy_data->sfp_base = AXGBE_SFP_BASE_1000_SX;
573a5c72737SRavi Kumar 		phy_data->sfp_cable = AXGBE_SFP_CABLE_ACTIVE;
574a5c72737SRavi Kumar 		phy_data->sfp_speed = AXGBE_SFP_SPEED_1000;
575a5c72737SRavi Kumar 		return true;
576a5c72737SRavi Kumar 	}
577a5c72737SRavi Kumar 
578a5c72737SRavi Kumar 	return false;
579a5c72737SRavi Kumar }
580a5c72737SRavi Kumar 
581a5c72737SRavi Kumar static bool axgbe_phy_sfp_parse_quirks(struct axgbe_port *pdata)
582a5c72737SRavi Kumar {
583a5c72737SRavi Kumar 	if (axgbe_phy_belfuse_parse_quirks(pdata))
584a5c72737SRavi Kumar 		return true;
585a5c72737SRavi Kumar 
586a5c72737SRavi Kumar 	return false;
587a5c72737SRavi Kumar }
588a5c72737SRavi Kumar 
589a5c72737SRavi Kumar static void axgbe_phy_sfp_parse_eeprom(struct axgbe_port *pdata)
590a5c72737SRavi Kumar {
591a5c72737SRavi Kumar 	struct axgbe_phy_data *phy_data = pdata->phy_data;
592a5c72737SRavi Kumar 	struct axgbe_sfp_eeprom *sfp_eeprom = &phy_data->sfp_eeprom;
593a5c72737SRavi Kumar 	uint8_t *sfp_base;
594a5c72737SRavi Kumar 
595a5c72737SRavi Kumar 	sfp_base = sfp_eeprom->base;
596a5c72737SRavi Kumar 
597a5c72737SRavi Kumar 	if (sfp_base[AXGBE_SFP_BASE_ID] != AXGBE_SFP_ID_SFP)
598a5c72737SRavi Kumar 		return;
599a5c72737SRavi Kumar 
600a5c72737SRavi Kumar 	if (sfp_base[AXGBE_SFP_BASE_EXT_ID] != AXGBE_SFP_EXT_ID_SFP)
601a5c72737SRavi Kumar 		return;
602a5c72737SRavi Kumar 
603936e294cSGirish Nandibasappa 	axgbe_phy_sfp_parse_quirks(pdata);
604a5c72737SRavi Kumar 
6054823ccdbSVenkat Kumar Ande 	/* Assume FIBER cable unless told otherwise */
606a5c72737SRavi Kumar 	if (sfp_base[AXGBE_SFP_BASE_CABLE] & AXGBE_SFP_BASE_CABLE_PASSIVE) {
607a5c72737SRavi Kumar 		phy_data->sfp_cable = AXGBE_SFP_CABLE_PASSIVE;
608a5c72737SRavi Kumar 		phy_data->sfp_cable_len = sfp_base[AXGBE_SFP_BASE_CU_CABLE_LEN];
6094823ccdbSVenkat Kumar Ande 	} else if (sfp_base[AXGBE_SFP_BASE_CABLE] & AXGBE_SFP_BASE_CABLE_ACTIVE) {
610a5c72737SRavi Kumar 		phy_data->sfp_cable = AXGBE_SFP_CABLE_ACTIVE;
6114823ccdbSVenkat Kumar Ande 	} else {
6124823ccdbSVenkat Kumar Ande 		phy_data->sfp_cable = AXGBE_SFP_CABLE_FIBER;
613a5c72737SRavi Kumar 	}
614a5c72737SRavi Kumar 
615a5c72737SRavi Kumar 	/* Determine the type of SFP */
6164823ccdbSVenkat Kumar Ande 	if (phy_data->sfp_cable != AXGBE_SFP_CABLE_FIBER &&
6174eefb1b1SVenkat Kumar Ande 		 axgbe_phy_sfp_bit_rate(sfp_eeprom, AXGBE_SFP_SPEED_10000))
6184eefb1b1SVenkat Kumar Ande 		phy_data->sfp_base = AXGBE_SFP_BASE_10000_CR;
6194eefb1b1SVenkat Kumar Ande 	else if (sfp_base[AXGBE_SFP_BASE_10GBE_CC] & AXGBE_SFP_BASE_10GBE_CC_SR)
620a5c72737SRavi Kumar 		phy_data->sfp_base = AXGBE_SFP_BASE_10000_SR;
621a5c72737SRavi Kumar 	else if (sfp_base[AXGBE_SFP_BASE_10GBE_CC] & AXGBE_SFP_BASE_10GBE_CC_LR)
622a5c72737SRavi Kumar 		phy_data->sfp_base = AXGBE_SFP_BASE_10000_LR;
623a5c72737SRavi Kumar 	else if (sfp_base[AXGBE_SFP_BASE_10GBE_CC] &
624a5c72737SRavi Kumar 		 AXGBE_SFP_BASE_10GBE_CC_LRM)
625a5c72737SRavi Kumar 		phy_data->sfp_base = AXGBE_SFP_BASE_10000_LRM;
626a5c72737SRavi Kumar 	else if (sfp_base[AXGBE_SFP_BASE_10GBE_CC] & AXGBE_SFP_BASE_10GBE_CC_ER)
627a5c72737SRavi Kumar 		phy_data->sfp_base = AXGBE_SFP_BASE_10000_ER;
628a5c72737SRavi Kumar 	else if (sfp_base[AXGBE_SFP_BASE_1GBE_CC] & AXGBE_SFP_BASE_1GBE_CC_SX)
629a5c72737SRavi Kumar 		phy_data->sfp_base = AXGBE_SFP_BASE_1000_SX;
630a5c72737SRavi Kumar 	else if (sfp_base[AXGBE_SFP_BASE_1GBE_CC] & AXGBE_SFP_BASE_1GBE_CC_LX)
631a5c72737SRavi Kumar 		phy_data->sfp_base = AXGBE_SFP_BASE_1000_LX;
632a5c72737SRavi Kumar 	else if (sfp_base[AXGBE_SFP_BASE_1GBE_CC] & AXGBE_SFP_BASE_1GBE_CC_CX)
633a5c72737SRavi Kumar 		phy_data->sfp_base = AXGBE_SFP_BASE_1000_CX;
634a5c72737SRavi Kumar 	else if (sfp_base[AXGBE_SFP_BASE_1GBE_CC] & AXGBE_SFP_BASE_1GBE_CC_T)
635a5c72737SRavi Kumar 		phy_data->sfp_base = AXGBE_SFP_BASE_1000_T;
636a5c72737SRavi Kumar 
637a5c72737SRavi Kumar 	switch (phy_data->sfp_base) {
638a5c72737SRavi Kumar 	case AXGBE_SFP_BASE_1000_T:
639a5c72737SRavi Kumar 		phy_data->sfp_speed = AXGBE_SFP_SPEED_100_1000;
640a5c72737SRavi Kumar 		break;
641a5c72737SRavi Kumar 	case AXGBE_SFP_BASE_1000_SX:
642a5c72737SRavi Kumar 	case AXGBE_SFP_BASE_1000_LX:
643a5c72737SRavi Kumar 	case AXGBE_SFP_BASE_1000_CX:
644a5c72737SRavi Kumar 		phy_data->sfp_speed = AXGBE_SFP_SPEED_1000;
645a5c72737SRavi Kumar 		break;
646a5c72737SRavi Kumar 	case AXGBE_SFP_BASE_10000_SR:
647a5c72737SRavi Kumar 	case AXGBE_SFP_BASE_10000_LR:
648a5c72737SRavi Kumar 	case AXGBE_SFP_BASE_10000_LRM:
649a5c72737SRavi Kumar 	case AXGBE_SFP_BASE_10000_ER:
650a5c72737SRavi Kumar 	case AXGBE_SFP_BASE_10000_CR:
651a5c72737SRavi Kumar 		phy_data->sfp_speed = AXGBE_SFP_SPEED_10000;
652a5c72737SRavi Kumar 		break;
653a5c72737SRavi Kumar 	default:
654a5c72737SRavi Kumar 		break;
655a5c72737SRavi Kumar 	}
656a5c72737SRavi Kumar }
657a5c72737SRavi Kumar 
658a5c72737SRavi Kumar static bool axgbe_phy_sfp_verify_eeprom(uint8_t cc_in, uint8_t *buf,
659a5c72737SRavi Kumar 					unsigned int len)
660a5c72737SRavi Kumar {
661a5c72737SRavi Kumar 	uint8_t cc;
662a5c72737SRavi Kumar 
663a5c72737SRavi Kumar 	for (cc = 0; len; buf++, len--)
664a5c72737SRavi Kumar 		cc += *buf;
665a5c72737SRavi Kumar 
666aca000c0SVenkat Kumar Ande 	return cc == cc_in;
667a5c72737SRavi Kumar }
668a5c72737SRavi Kumar 
669a5c72737SRavi Kumar static int axgbe_phy_sfp_read_eeprom(struct axgbe_port *pdata)
670a5c72737SRavi Kumar {
671a5c72737SRavi Kumar 	struct axgbe_phy_data *phy_data = pdata->phy_data;
672a5c72737SRavi Kumar 	struct axgbe_sfp_eeprom sfp_eeprom;
673a5c72737SRavi Kumar 	uint8_t eeprom_addr;
674a5c72737SRavi Kumar 	int ret;
675a5c72737SRavi Kumar 
676a5c72737SRavi Kumar 	ret = axgbe_phy_sfp_get_mux(pdata);
677a5c72737SRavi Kumar 	if (ret) {
678a5c72737SRavi Kumar 		PMD_DRV_LOG(ERR, "I2C error setting SFP MUX\n");
679a5c72737SRavi Kumar 		return ret;
680a5c72737SRavi Kumar 	}
681a5c72737SRavi Kumar 
682a5c72737SRavi Kumar 	/* Read the SFP serial ID eeprom */
683a5c72737SRavi Kumar 	eeprom_addr = 0;
684a5c72737SRavi Kumar 	ret = axgbe_phy_i2c_read(pdata, AXGBE_SFP_SERIAL_ID_ADDRESS,
685a5c72737SRavi Kumar 				 &eeprom_addr, sizeof(eeprom_addr),
686a5c72737SRavi Kumar 				 &sfp_eeprom, sizeof(sfp_eeprom));
687a5c72737SRavi Kumar 	if (ret) {
688a5c72737SRavi Kumar 		PMD_DRV_LOG(ERR, "I2C error reading SFP EEPROM\n");
689a5c72737SRavi Kumar 		goto put;
690a5c72737SRavi Kumar 	}
691a5c72737SRavi Kumar 
692a5c72737SRavi Kumar 	/* Validate the contents read */
693a5c72737SRavi Kumar 	if (!axgbe_phy_sfp_verify_eeprom(sfp_eeprom.base[AXGBE_SFP_BASE_CC],
694a5c72737SRavi Kumar 					 sfp_eeprom.base,
695a5c72737SRavi Kumar 					 sizeof(sfp_eeprom.base) - 1)) {
696a5c72737SRavi Kumar 		ret = -EINVAL;
697a5c72737SRavi Kumar 		goto put;
698a5c72737SRavi Kumar 	}
699a5c72737SRavi Kumar 
700a5c72737SRavi Kumar 	if (!axgbe_phy_sfp_verify_eeprom(sfp_eeprom.extd[AXGBE_SFP_EXTD_CC],
701a5c72737SRavi Kumar 					 sfp_eeprom.extd,
702a5c72737SRavi Kumar 					 sizeof(sfp_eeprom.extd) - 1)) {
703a5c72737SRavi Kumar 		ret = -EINVAL;
704a5c72737SRavi Kumar 		goto put;
705a5c72737SRavi Kumar 	}
706a5c72737SRavi Kumar 
707a5c72737SRavi Kumar 	/* Check for an added or changed SFP */
708a5c72737SRavi Kumar 	if (memcmp(&phy_data->sfp_eeprom, &sfp_eeprom, sizeof(sfp_eeprom))) {
709a5c72737SRavi Kumar 		phy_data->sfp_changed = 1;
710a5c72737SRavi Kumar 		memcpy(&phy_data->sfp_eeprom, &sfp_eeprom, sizeof(sfp_eeprom));
711a5c72737SRavi Kumar 	} else {
712a5c72737SRavi Kumar 		phy_data->sfp_changed = 0;
713a5c72737SRavi Kumar 	}
714a5c72737SRavi Kumar 
715a5c72737SRavi Kumar put:
716a5c72737SRavi Kumar 	axgbe_phy_sfp_put_mux(pdata);
717a5c72737SRavi Kumar 
718a5c72737SRavi Kumar 	return ret;
719a5c72737SRavi Kumar }
720a5c72737SRavi Kumar 
721a5c72737SRavi Kumar static void axgbe_phy_sfp_signals(struct axgbe_port *pdata)
722a5c72737SRavi Kumar {
723a5c72737SRavi Kumar 	struct axgbe_phy_data *phy_data = pdata->phy_data;
724a5c72737SRavi Kumar 	unsigned int gpio_input;
725a5c72737SRavi Kumar 	u8 gpio_reg, gpio_ports[2];
726a5c72737SRavi Kumar 	int ret;
727a5c72737SRavi Kumar 
728a5c72737SRavi Kumar 	/* Read the input port registers */
729a5c72737SRavi Kumar 	gpio_reg = 0;
730a5c72737SRavi Kumar 	ret = axgbe_phy_i2c_read(pdata, phy_data->sfp_gpio_address,
731a5c72737SRavi Kumar 				 &gpio_reg, sizeof(gpio_reg),
732a5c72737SRavi Kumar 				 gpio_ports, sizeof(gpio_ports));
733a5c72737SRavi Kumar 	if (ret) {
734a5c72737SRavi Kumar 		PMD_DRV_LOG(ERR, "I2C error reading SFP GPIOs\n");
735a5c72737SRavi Kumar 		return;
736a5c72737SRavi Kumar 	}
737a5c72737SRavi Kumar 
738a5c72737SRavi Kumar 	gpio_input = (gpio_ports[1] << 8) | gpio_ports[0];
739a5c72737SRavi Kumar 
740a5c72737SRavi Kumar 	if (phy_data->sfp_gpio_mask & AXGBE_GPIO_NO_MOD_ABSENT) {
741a5c72737SRavi Kumar 		/* No GPIO, just assume the module is present for now */
742a5c72737SRavi Kumar 		phy_data->sfp_mod_absent = 0;
743a5c72737SRavi Kumar 	} else {
744a5c72737SRavi Kumar 		if (!(gpio_input & (1 << phy_data->sfp_gpio_mod_absent)))
745a5c72737SRavi Kumar 			phy_data->sfp_mod_absent = 0;
746a5c72737SRavi Kumar 	}
747a5c72737SRavi Kumar 
748a5c72737SRavi Kumar 	if (!(phy_data->sfp_gpio_mask & AXGBE_GPIO_NO_RX_LOS) &&
749a5c72737SRavi Kumar 	    (gpio_input & (1 << phy_data->sfp_gpio_rx_los)))
750a5c72737SRavi Kumar 		phy_data->sfp_rx_los = 1;
751a5c72737SRavi Kumar 
752a5c72737SRavi Kumar 	if (!(phy_data->sfp_gpio_mask & AXGBE_GPIO_NO_TX_FAULT) &&
753a5c72737SRavi Kumar 	    (gpio_input & (1 << phy_data->sfp_gpio_tx_fault)))
754a5c72737SRavi Kumar 		phy_data->sfp_tx_fault = 1;
755a5c72737SRavi Kumar }
756a5c72737SRavi Kumar 
757a5c72737SRavi Kumar static void axgbe_phy_sfp_mod_absent(struct axgbe_port *pdata)
758a5c72737SRavi Kumar {
759a5c72737SRavi Kumar 	struct axgbe_phy_data *phy_data = pdata->phy_data;
760a5c72737SRavi Kumar 
761a5c72737SRavi Kumar 	phy_data->sfp_mod_absent = 1;
762a5c72737SRavi Kumar 	phy_data->sfp_phy_avail = 0;
763a5c72737SRavi Kumar 	memset(&phy_data->sfp_eeprom, 0, sizeof(phy_data->sfp_eeprom));
764a5c72737SRavi Kumar }
765a5c72737SRavi Kumar 
766a5c72737SRavi Kumar static void axgbe_phy_sfp_reset(struct axgbe_phy_data *phy_data)
767a5c72737SRavi Kumar {
768a5c72737SRavi Kumar 	phy_data->sfp_rx_los = 0;
769a5c72737SRavi Kumar 	phy_data->sfp_tx_fault = 0;
770a5c72737SRavi Kumar 	phy_data->sfp_mod_absent = 1;
771a5c72737SRavi Kumar 	phy_data->sfp_base = AXGBE_SFP_BASE_UNKNOWN;
772a5c72737SRavi Kumar 	phy_data->sfp_cable = AXGBE_SFP_CABLE_UNKNOWN;
773a5c72737SRavi Kumar 	phy_data->sfp_speed = AXGBE_SFP_SPEED_UNKNOWN;
774a5c72737SRavi Kumar }
775a5c72737SRavi Kumar 
7764216cdc0SChandu Babu N static const char *axgbe_base_as_string(enum axgbe_sfp_base sfp_base)
7774216cdc0SChandu Babu N {
7784216cdc0SChandu Babu N 	switch (sfp_base) {
7794216cdc0SChandu Babu N 	case AXGBE_SFP_BASE_1000_T:
7804216cdc0SChandu Babu N 		return "1G_T";
7814216cdc0SChandu Babu N 	case AXGBE_SFP_BASE_1000_SX:
7824216cdc0SChandu Babu N 		return "1G_SX";
7834216cdc0SChandu Babu N 	case AXGBE_SFP_BASE_1000_LX:
7844216cdc0SChandu Babu N 		return "1G_LX";
7854216cdc0SChandu Babu N 	case AXGBE_SFP_BASE_1000_CX:
7864216cdc0SChandu Babu N 		return "1G_CX";
7874216cdc0SChandu Babu N 	case AXGBE_SFP_BASE_10000_SR:
7884216cdc0SChandu Babu N 		return "10G_SR";
7894216cdc0SChandu Babu N 	case AXGBE_SFP_BASE_10000_LR:
7904216cdc0SChandu Babu N 		return "10G_LR";
7914216cdc0SChandu Babu N 	case AXGBE_SFP_BASE_10000_LRM:
7924216cdc0SChandu Babu N 		return "10G_LRM";
7934216cdc0SChandu Babu N 	case AXGBE_SFP_BASE_10000_ER:
7944216cdc0SChandu Babu N 		return "10G_ER";
7954216cdc0SChandu Babu N 	case AXGBE_SFP_BASE_10000_CR:
7964216cdc0SChandu Babu N 		return "10G_CR";
7974216cdc0SChandu Babu N 	default:
7984216cdc0SChandu Babu N 		return "Unknown";
7994216cdc0SChandu Babu N 	}
8004216cdc0SChandu Babu N }
8014216cdc0SChandu Babu N 
802a5c72737SRavi Kumar static void axgbe_phy_sfp_detect(struct axgbe_port *pdata)
803a5c72737SRavi Kumar {
804a5c72737SRavi Kumar 	struct axgbe_phy_data *phy_data = pdata->phy_data;
805a5c72737SRavi Kumar 	int ret;
806a5c72737SRavi Kumar 
807a770d00aSVenkat Kumar Ande 	/* Clear the extra AN flag */
808a770d00aSVenkat Kumar Ande 	pdata->an_again = 0;
809a770d00aSVenkat Kumar Ande 
810a5c72737SRavi Kumar 	/* Reset the SFP signals and info */
811a5c72737SRavi Kumar 	axgbe_phy_sfp_reset(phy_data);
812a5c72737SRavi Kumar 
813a5c72737SRavi Kumar 	ret = axgbe_phy_get_comm_ownership(pdata);
814a5c72737SRavi Kumar 	if (ret)
815a5c72737SRavi Kumar 		return;
816a5c72737SRavi Kumar 
817a5c72737SRavi Kumar 	/* Read the SFP signals and check for module presence */
818a5c72737SRavi Kumar 	axgbe_phy_sfp_signals(pdata);
819a5c72737SRavi Kumar 	if (phy_data->sfp_mod_absent) {
820a5c72737SRavi Kumar 		axgbe_phy_sfp_mod_absent(pdata);
821a5c72737SRavi Kumar 		goto put;
822a5c72737SRavi Kumar 	}
823a5c72737SRavi Kumar 
824a5c72737SRavi Kumar 	ret = axgbe_phy_sfp_read_eeprom(pdata);
825a5c72737SRavi Kumar 	if (ret) {
826a5c72737SRavi Kumar 		/* Treat any error as if there isn't an SFP plugged in */
827a5c72737SRavi Kumar 		axgbe_phy_sfp_reset(phy_data);
828a5c72737SRavi Kumar 		axgbe_phy_sfp_mod_absent(pdata);
829a5c72737SRavi Kumar 		goto put;
830a5c72737SRavi Kumar 	}
831a5c72737SRavi Kumar 
832a5c72737SRavi Kumar 	axgbe_phy_sfp_parse_eeprom(pdata);
833a5c72737SRavi Kumar 	axgbe_phy_sfp_external_phy(pdata);
834a5c72737SRavi Kumar 
8354216cdc0SChandu Babu N 	PMD_DRV_LOG(DEBUG, "SFP Base: %s\n",
8364216cdc0SChandu Babu N 		    axgbe_base_as_string(phy_data->sfp_base));
8374216cdc0SChandu Babu N 
838a5c72737SRavi Kumar put:
839a5c72737SRavi Kumar 	axgbe_phy_sfp_phy_settings(pdata);
840a5c72737SRavi Kumar 	axgbe_phy_put_comm_ownership(pdata);
841a5c72737SRavi Kumar }
842a5c72737SRavi Kumar 
843a5c72737SRavi Kumar static void axgbe_phy_phydev_flowctrl(struct axgbe_port *pdata)
844a5c72737SRavi Kumar {
845a5c72737SRavi Kumar 	pdata->phy.tx_pause = 0;
846a5c72737SRavi Kumar 	pdata->phy.rx_pause = 0;
847a5c72737SRavi Kumar }
848a5c72737SRavi Kumar 
849a5c72737SRavi Kumar static enum axgbe_mode axgbe_phy_an73_redrv_outcome(struct axgbe_port *pdata)
850a5c72737SRavi Kumar {
851a5c72737SRavi Kumar 	struct axgbe_phy_data *phy_data = pdata->phy_data;
852a5c72737SRavi Kumar 	enum axgbe_mode mode;
853a5c72737SRavi Kumar 	unsigned int ad_reg, lp_reg;
854a5c72737SRavi Kumar 
855a5c72737SRavi Kumar 	pdata->phy.lp_advertising |= ADVERTISED_Autoneg;
856a5c72737SRavi Kumar 	pdata->phy.lp_advertising |= ADVERTISED_Backplane;
857a5c72737SRavi Kumar 
858a5c72737SRavi Kumar 	/* Use external PHY to determine flow control */
859a5c72737SRavi Kumar 	if (pdata->phy.pause_autoneg)
860a5c72737SRavi Kumar 		axgbe_phy_phydev_flowctrl(pdata);
861a5c72737SRavi Kumar 
862a5c72737SRavi Kumar 	/* Compare Advertisement and Link Partner register 2 */
863a5c72737SRavi Kumar 	ad_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE + 1);
864a5c72737SRavi Kumar 	lp_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_LPA + 1);
865a5c72737SRavi Kumar 	if (lp_reg & 0x80)
866a5c72737SRavi Kumar 		pdata->phy.lp_advertising |= ADVERTISED_10000baseKR_Full;
867a5c72737SRavi Kumar 	if (lp_reg & 0x20)
868a5c72737SRavi Kumar 		pdata->phy.lp_advertising |= ADVERTISED_1000baseKX_Full;
869a5c72737SRavi Kumar 
870a5c72737SRavi Kumar 	ad_reg &= lp_reg;
871a5c72737SRavi Kumar 	if (ad_reg & 0x80) {
872a5c72737SRavi Kumar 		switch (phy_data->port_mode) {
873a5c72737SRavi Kumar 		case AXGBE_PORT_MODE_BACKPLANE:
874443ab5aaSSelwin Sebastian 		case AXGBE_PORT_MODE_BACKPLANE_NO_AUTONEG:
875a5c72737SRavi Kumar 			mode = AXGBE_MODE_KR;
876a5c72737SRavi Kumar 			break;
877a5c72737SRavi Kumar 		default:
878a5c72737SRavi Kumar 			mode = AXGBE_MODE_SFI;
879a5c72737SRavi Kumar 			break;
880a5c72737SRavi Kumar 		}
881a5c72737SRavi Kumar 	} else if (ad_reg & 0x20) {
882a5c72737SRavi Kumar 		switch (phy_data->port_mode) {
883a5c72737SRavi Kumar 		case AXGBE_PORT_MODE_BACKPLANE:
884443ab5aaSSelwin Sebastian 		case AXGBE_PORT_MODE_BACKPLANE_NO_AUTONEG:
885a5c72737SRavi Kumar 			mode = AXGBE_MODE_KX_1000;
886a5c72737SRavi Kumar 			break;
887a5c72737SRavi Kumar 		case AXGBE_PORT_MODE_1000BASE_X:
888a5c72737SRavi Kumar 			mode = AXGBE_MODE_X;
889a5c72737SRavi Kumar 			break;
890a5c72737SRavi Kumar 		case AXGBE_PORT_MODE_SFP:
891a5c72737SRavi Kumar 			switch (phy_data->sfp_base) {
892a5c72737SRavi Kumar 			case AXGBE_SFP_BASE_1000_T:
893a5c72737SRavi Kumar 				mode = AXGBE_MODE_SGMII_1000;
894a5c72737SRavi Kumar 				break;
895a5c72737SRavi Kumar 			case AXGBE_SFP_BASE_1000_SX:
896a5c72737SRavi Kumar 			case AXGBE_SFP_BASE_1000_LX:
897a5c72737SRavi Kumar 			case AXGBE_SFP_BASE_1000_CX:
898a5c72737SRavi Kumar 			default:
899a5c72737SRavi Kumar 				mode = AXGBE_MODE_X;
900a5c72737SRavi Kumar 				break;
901a5c72737SRavi Kumar 			}
902a5c72737SRavi Kumar 			break;
903a5c72737SRavi Kumar 		default:
904a5c72737SRavi Kumar 			mode = AXGBE_MODE_SGMII_1000;
905a5c72737SRavi Kumar 			break;
906a5c72737SRavi Kumar 		}
907a5c72737SRavi Kumar 	} else {
908a5c72737SRavi Kumar 		mode = AXGBE_MODE_UNKNOWN;
909a5c72737SRavi Kumar 	}
910a5c72737SRavi Kumar 
911a5c72737SRavi Kumar 	/* Compare Advertisement and Link Partner register 3 */
912a5c72737SRavi Kumar 	ad_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE + 2);
913a5c72737SRavi Kumar 	lp_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_LPA + 2);
914a5c72737SRavi Kumar 	if (lp_reg & 0xc000)
915a5c72737SRavi Kumar 		pdata->phy.lp_advertising |= ADVERTISED_10000baseR_FEC;
916a5c72737SRavi Kumar 
917a5c72737SRavi Kumar 	return mode;
918a5c72737SRavi Kumar }
919a5c72737SRavi Kumar 
920a5c72737SRavi Kumar static enum axgbe_mode axgbe_phy_an73_outcome(struct axgbe_port *pdata)
921a5c72737SRavi Kumar {
922a5c72737SRavi Kumar 	enum axgbe_mode mode;
923a5c72737SRavi Kumar 	unsigned int ad_reg, lp_reg;
924a5c72737SRavi Kumar 
925a5c72737SRavi Kumar 	pdata->phy.lp_advertising |= ADVERTISED_Autoneg;
926a5c72737SRavi Kumar 	pdata->phy.lp_advertising |= ADVERTISED_Backplane;
927a5c72737SRavi Kumar 
928a5c72737SRavi Kumar 	/* Compare Advertisement and Link Partner register 1 */
929a5c72737SRavi Kumar 	ad_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE);
930a5c72737SRavi Kumar 	lp_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_LPA);
931a5c72737SRavi Kumar 	if (lp_reg & 0x400)
932a5c72737SRavi Kumar 		pdata->phy.lp_advertising |= ADVERTISED_Pause;
933a5c72737SRavi Kumar 	if (lp_reg & 0x800)
934a5c72737SRavi Kumar 		pdata->phy.lp_advertising |= ADVERTISED_Asym_Pause;
935a5c72737SRavi Kumar 
936a5c72737SRavi Kumar 	if (pdata->phy.pause_autoneg) {
937a5c72737SRavi Kumar 		/* Set flow control based on auto-negotiation result */
938a5c72737SRavi Kumar 		pdata->phy.tx_pause = 0;
939a5c72737SRavi Kumar 		pdata->phy.rx_pause = 0;
940a5c72737SRavi Kumar 
941a5c72737SRavi Kumar 		if (ad_reg & lp_reg & 0x400) {
942a5c72737SRavi Kumar 			pdata->phy.tx_pause = 1;
943a5c72737SRavi Kumar 			pdata->phy.rx_pause = 1;
944a5c72737SRavi Kumar 		} else if (ad_reg & lp_reg & 0x800) {
945a5c72737SRavi Kumar 			if (ad_reg & 0x400)
946a5c72737SRavi Kumar 				pdata->phy.rx_pause = 1;
947a5c72737SRavi Kumar 			else if (lp_reg & 0x400)
948a5c72737SRavi Kumar 				pdata->phy.tx_pause = 1;
949a5c72737SRavi Kumar 		}
950a5c72737SRavi Kumar 	}
951a5c72737SRavi Kumar 
952a5c72737SRavi Kumar 	/* Compare Advertisement and Link Partner register 2 */
953a5c72737SRavi Kumar 	ad_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE + 1);
954a5c72737SRavi Kumar 	lp_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_LPA + 1);
955a5c72737SRavi Kumar 	if (lp_reg & 0x80)
956a5c72737SRavi Kumar 		pdata->phy.lp_advertising |= ADVERTISED_10000baseKR_Full;
957a5c72737SRavi Kumar 	if (lp_reg & 0x20)
958a5c72737SRavi Kumar 		pdata->phy.lp_advertising |= ADVERTISED_1000baseKX_Full;
959a5c72737SRavi Kumar 
960a5c72737SRavi Kumar 	ad_reg &= lp_reg;
961a5c72737SRavi Kumar 	if (ad_reg & 0x80)
962a5c72737SRavi Kumar 		mode = AXGBE_MODE_KR;
963a5c72737SRavi Kumar 	else if (ad_reg & 0x20)
964a5c72737SRavi Kumar 		mode = AXGBE_MODE_KX_1000;
965a5c72737SRavi Kumar 	else
966a5c72737SRavi Kumar 		mode = AXGBE_MODE_UNKNOWN;
967a5c72737SRavi Kumar 
968a5c72737SRavi Kumar 	/* Compare Advertisement and Link Partner register 3 */
969a5c72737SRavi Kumar 	ad_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE + 2);
970a5c72737SRavi Kumar 	lp_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_LPA + 2);
971a5c72737SRavi Kumar 	if (lp_reg & 0xc000)
972a5c72737SRavi Kumar 		pdata->phy.lp_advertising |= ADVERTISED_10000baseR_FEC;
973a5c72737SRavi Kumar 
974a5c72737SRavi Kumar 	return mode;
975a5c72737SRavi Kumar }
976a5c72737SRavi Kumar 
977102b6ec3SGirish Nandibasappa static enum axgbe_mode axgbe_phy_an37_sgmii_outcome(struct axgbe_port *pdata)
978102b6ec3SGirish Nandibasappa {
979102b6ec3SGirish Nandibasappa 	enum axgbe_mode mode;
980102b6ec3SGirish Nandibasappa 
981102b6ec3SGirish Nandibasappa 	pdata->phy.lp_advertising |= ADVERTISED_Autoneg;
982102b6ec3SGirish Nandibasappa 	pdata->phy.lp_advertising |= ADVERTISED_1000baseT_Full;
983102b6ec3SGirish Nandibasappa 
984102b6ec3SGirish Nandibasappa 	if (pdata->phy.pause_autoneg)
985102b6ec3SGirish Nandibasappa 		axgbe_phy_phydev_flowctrl(pdata);
986102b6ec3SGirish Nandibasappa 
987102b6ec3SGirish Nandibasappa 	switch (pdata->an_status & AXGBE_SGMII_AN_LINK_SPEED) {
988*1f9d2d3aSVenkat Kumar Ande 	case AXGBE_SGMII_AN_LINK_SPEED_10:
989*1f9d2d3aSVenkat Kumar Ande 		if (pdata->an_status & AXGBE_SGMII_AN_LINK_DUPLEX) {
990*1f9d2d3aSVenkat Kumar Ande 			pdata->phy.lp_advertising |= ADVERTISED_10baseT_Full;
991*1f9d2d3aSVenkat Kumar Ande 			mode = AXGBE_MODE_SGMII_10;
992*1f9d2d3aSVenkat Kumar Ande 		} else {
993*1f9d2d3aSVenkat Kumar Ande 			mode = AXGBE_MODE_UNKNOWN;
994*1f9d2d3aSVenkat Kumar Ande 		}
995*1f9d2d3aSVenkat Kumar Ande 		break;
996102b6ec3SGirish Nandibasappa 	case AXGBE_SGMII_AN_LINK_SPEED_100:
997102b6ec3SGirish Nandibasappa 		if (pdata->an_status & AXGBE_SGMII_AN_LINK_DUPLEX) {
998102b6ec3SGirish Nandibasappa 			pdata->phy.lp_advertising |= ADVERTISED_100baseT_Full;
999102b6ec3SGirish Nandibasappa 			mode = AXGBE_MODE_SGMII_100;
1000102b6ec3SGirish Nandibasappa 		} else {
1001102b6ec3SGirish Nandibasappa 			mode = AXGBE_MODE_UNKNOWN;
1002102b6ec3SGirish Nandibasappa 		}
1003102b6ec3SGirish Nandibasappa 		break;
1004102b6ec3SGirish Nandibasappa 	case AXGBE_SGMII_AN_LINK_SPEED_1000:
1005102b6ec3SGirish Nandibasappa 		if (pdata->an_status & AXGBE_SGMII_AN_LINK_DUPLEX) {
1006102b6ec3SGirish Nandibasappa 			pdata->phy.lp_advertising |= ADVERTISED_1000baseT_Full;
1007102b6ec3SGirish Nandibasappa 			mode = AXGBE_MODE_SGMII_1000;
1008102b6ec3SGirish Nandibasappa 		} else {
1009102b6ec3SGirish Nandibasappa 			/* Half-duplex not supported */
1010102b6ec3SGirish Nandibasappa 			mode = AXGBE_MODE_UNKNOWN;
1011102b6ec3SGirish Nandibasappa 		}
1012102b6ec3SGirish Nandibasappa 		break;
1013102b6ec3SGirish Nandibasappa 	default:
1014102b6ec3SGirish Nandibasappa 		mode = AXGBE_MODE_UNKNOWN;
1015102b6ec3SGirish Nandibasappa 		break;
1016102b6ec3SGirish Nandibasappa 	}
1017102b6ec3SGirish Nandibasappa 	return mode;
1018102b6ec3SGirish Nandibasappa }
1019102b6ec3SGirish Nandibasappa 
1020a5c72737SRavi Kumar static enum axgbe_mode axgbe_phy_an_outcome(struct axgbe_port *pdata)
1021a5c72737SRavi Kumar {
1022a5c72737SRavi Kumar 	switch (pdata->an_mode) {
1023a5c72737SRavi Kumar 	case AXGBE_AN_MODE_CL73:
1024a5c72737SRavi Kumar 		return axgbe_phy_an73_outcome(pdata);
1025a5c72737SRavi Kumar 	case AXGBE_AN_MODE_CL73_REDRV:
1026a5c72737SRavi Kumar 		return axgbe_phy_an73_redrv_outcome(pdata);
1027a5c72737SRavi Kumar 	case AXGBE_AN_MODE_CL37:
1028a5c72737SRavi Kumar 	case AXGBE_AN_MODE_CL37_SGMII:
1029102b6ec3SGirish Nandibasappa 		return axgbe_phy_an37_sgmii_outcome(pdata);
1030a5c72737SRavi Kumar 	default:
1031a5c72737SRavi Kumar 		return AXGBE_MODE_UNKNOWN;
1032a5c72737SRavi Kumar 	}
1033a5c72737SRavi Kumar }
1034a5c72737SRavi Kumar 
1035a5c72737SRavi Kumar static unsigned int axgbe_phy_an_advertising(struct axgbe_port *pdata)
1036a5c72737SRavi Kumar {
1037a5c72737SRavi Kumar 	struct axgbe_phy_data *phy_data = pdata->phy_data;
1038a5c72737SRavi Kumar 	unsigned int advertising;
1039a5c72737SRavi Kumar 
1040a5c72737SRavi Kumar 	/* Without a re-driver, just return current advertising */
1041a5c72737SRavi Kumar 	if (!phy_data->redrv)
1042a5c72737SRavi Kumar 		return pdata->phy.advertising;
1043a5c72737SRavi Kumar 
1044a5c72737SRavi Kumar 	/* With the KR re-driver we need to advertise a single speed */
1045a5c72737SRavi Kumar 	advertising = pdata->phy.advertising;
1046a5c72737SRavi Kumar 	advertising &= ~ADVERTISED_1000baseKX_Full;
1047a5c72737SRavi Kumar 	advertising &= ~ADVERTISED_10000baseKR_Full;
1048a5c72737SRavi Kumar 
1049a5c72737SRavi Kumar 	switch (phy_data->port_mode) {
1050a5c72737SRavi Kumar 	case AXGBE_PORT_MODE_BACKPLANE:
1051443ab5aaSSelwin Sebastian 	case AXGBE_PORT_MODE_BACKPLANE_NO_AUTONEG:
1052a5c72737SRavi Kumar 		advertising |= ADVERTISED_10000baseKR_Full;
1053a5c72737SRavi Kumar 		break;
1054a5c72737SRavi Kumar 	case AXGBE_PORT_MODE_BACKPLANE_2500:
1055a5c72737SRavi Kumar 		advertising |= ADVERTISED_1000baseKX_Full;
1056a5c72737SRavi Kumar 		break;
1057a5c72737SRavi Kumar 	case AXGBE_PORT_MODE_1000BASE_T:
1058a5c72737SRavi Kumar 	case AXGBE_PORT_MODE_1000BASE_X:
1059a5c72737SRavi Kumar 	case AXGBE_PORT_MODE_NBASE_T:
1060a5c72737SRavi Kumar 		advertising |= ADVERTISED_1000baseKX_Full;
1061a5c72737SRavi Kumar 		break;
1062a5c72737SRavi Kumar 	case AXGBE_PORT_MODE_10GBASE_T:
1063a5c72737SRavi Kumar 		PMD_DRV_LOG(ERR, "10GBASE_T mode is not supported\n");
1064a5c72737SRavi Kumar 		break;
1065a5c72737SRavi Kumar 	case AXGBE_PORT_MODE_10GBASE_R:
1066a5c72737SRavi Kumar 		advertising |= ADVERTISED_10000baseKR_Full;
1067a5c72737SRavi Kumar 		break;
1068a5c72737SRavi Kumar 	case AXGBE_PORT_MODE_SFP:
1069a5c72737SRavi Kumar 		switch (phy_data->sfp_base) {
1070a5c72737SRavi Kumar 		case AXGBE_SFP_BASE_1000_T:
1071a5c72737SRavi Kumar 		case AXGBE_SFP_BASE_1000_SX:
1072a5c72737SRavi Kumar 		case AXGBE_SFP_BASE_1000_LX:
1073a5c72737SRavi Kumar 		case AXGBE_SFP_BASE_1000_CX:
1074a5c72737SRavi Kumar 			advertising |= ADVERTISED_1000baseKX_Full;
1075a5c72737SRavi Kumar 			break;
1076a5c72737SRavi Kumar 		default:
1077a5c72737SRavi Kumar 			advertising |= ADVERTISED_10000baseKR_Full;
1078a5c72737SRavi Kumar 			break;
1079a5c72737SRavi Kumar 		}
1080a5c72737SRavi Kumar 		break;
1081a5c72737SRavi Kumar 	default:
1082a5c72737SRavi Kumar 		advertising |= ADVERTISED_10000baseKR_Full;
1083a5c72737SRavi Kumar 		break;
1084a5c72737SRavi Kumar 	}
1085a5c72737SRavi Kumar 
1086a5c72737SRavi Kumar 	return advertising;
1087a5c72737SRavi Kumar }
1088a5c72737SRavi Kumar 
1089a5c72737SRavi Kumar static int axgbe_phy_an_config(struct axgbe_port *pdata __rte_unused)
1090a5c72737SRavi Kumar {
1091a5c72737SRavi Kumar 	return 0;
1092a5c72737SRavi Kumar 	/* Dummy API since there is no case to support
10937be78d02SJosh Soref 	 * external phy devices registered through kernel APIs
1094a5c72737SRavi Kumar 	 */
1095a5c72737SRavi Kumar }
1096a5c72737SRavi Kumar 
1097a5c72737SRavi Kumar static enum axgbe_an_mode axgbe_phy_an_sfp_mode(struct axgbe_phy_data *phy_data)
1098a5c72737SRavi Kumar {
1099a5c72737SRavi Kumar 	switch (phy_data->sfp_base) {
1100a5c72737SRavi Kumar 	case AXGBE_SFP_BASE_1000_T:
1101a5c72737SRavi Kumar 		return AXGBE_AN_MODE_CL37_SGMII;
1102a5c72737SRavi Kumar 	case AXGBE_SFP_BASE_1000_SX:
1103a5c72737SRavi Kumar 	case AXGBE_SFP_BASE_1000_LX:
1104a5c72737SRavi Kumar 	case AXGBE_SFP_BASE_1000_CX:
1105a5c72737SRavi Kumar 		return AXGBE_AN_MODE_CL37;
1106a5c72737SRavi Kumar 	default:
1107a5c72737SRavi Kumar 		return AXGBE_AN_MODE_NONE;
1108a5c72737SRavi Kumar 	}
1109a5c72737SRavi Kumar }
1110a5c72737SRavi Kumar 
1111a5c72737SRavi Kumar static enum axgbe_an_mode axgbe_phy_an_mode(struct axgbe_port *pdata)
1112a5c72737SRavi Kumar {
1113a5c72737SRavi Kumar 	struct axgbe_phy_data *phy_data = pdata->phy_data;
1114a5c72737SRavi Kumar 
1115a5c72737SRavi Kumar 	/* A KR re-driver will always require CL73 AN */
1116a5c72737SRavi Kumar 	if (phy_data->redrv)
1117a5c72737SRavi Kumar 		return AXGBE_AN_MODE_CL73_REDRV;
1118a5c72737SRavi Kumar 
1119a5c72737SRavi Kumar 	switch (phy_data->port_mode) {
1120a5c72737SRavi Kumar 	case AXGBE_PORT_MODE_BACKPLANE:
1121a5c72737SRavi Kumar 		return AXGBE_AN_MODE_CL73;
1122443ab5aaSSelwin Sebastian 	case AXGBE_PORT_MODE_BACKPLANE_NO_AUTONEG:
1123a5c72737SRavi Kumar 	case AXGBE_PORT_MODE_BACKPLANE_2500:
1124a5c72737SRavi Kumar 		return AXGBE_AN_MODE_NONE;
1125a5c72737SRavi Kumar 	case AXGBE_PORT_MODE_1000BASE_T:
1126a5c72737SRavi Kumar 		return AXGBE_AN_MODE_CL37_SGMII;
1127a5c72737SRavi Kumar 	case AXGBE_PORT_MODE_1000BASE_X:
1128a5c72737SRavi Kumar 		return AXGBE_AN_MODE_CL37;
1129a5c72737SRavi Kumar 	case AXGBE_PORT_MODE_NBASE_T:
1130a5c72737SRavi Kumar 		return AXGBE_AN_MODE_CL37_SGMII;
1131a5c72737SRavi Kumar 	case AXGBE_PORT_MODE_10GBASE_T:
1132a5c72737SRavi Kumar 		return AXGBE_AN_MODE_CL73;
1133a5c72737SRavi Kumar 	case AXGBE_PORT_MODE_10GBASE_R:
1134a5c72737SRavi Kumar 		return AXGBE_AN_MODE_NONE;
1135a5c72737SRavi Kumar 	case AXGBE_PORT_MODE_SFP:
1136a5c72737SRavi Kumar 		return axgbe_phy_an_sfp_mode(phy_data);
1137a5c72737SRavi Kumar 	default:
1138a5c72737SRavi Kumar 		return AXGBE_AN_MODE_NONE;
1139a5c72737SRavi Kumar 	}
1140a5c72737SRavi Kumar }
1141a5c72737SRavi Kumar 
1142a5c72737SRavi Kumar static int axgbe_phy_set_redrv_mode_mdio(struct axgbe_port *pdata,
1143a5c72737SRavi Kumar 					 enum axgbe_phy_redrv_mode mode)
1144a5c72737SRavi Kumar {
1145a5c72737SRavi Kumar 	struct axgbe_phy_data *phy_data = pdata->phy_data;
1146a5c72737SRavi Kumar 	u16 redrv_reg, redrv_val;
1147a5c72737SRavi Kumar 
1148a5c72737SRavi Kumar 	redrv_reg = AXGBE_PHY_REDRV_MODE_REG + (phy_data->redrv_lane * 0x1000);
1149a5c72737SRavi Kumar 	redrv_val = (u16)mode;
1150a5c72737SRavi Kumar 
1151a5c72737SRavi Kumar 	return pdata->hw_if.write_ext_mii_regs(pdata, phy_data->redrv_addr,
1152a5c72737SRavi Kumar 					       redrv_reg, redrv_val);
1153a5c72737SRavi Kumar }
1154a5c72737SRavi Kumar 
1155a5c72737SRavi Kumar static int axgbe_phy_set_redrv_mode_i2c(struct axgbe_port *pdata,
1156a5c72737SRavi Kumar 					enum axgbe_phy_redrv_mode mode)
1157a5c72737SRavi Kumar {
1158a5c72737SRavi Kumar 	struct axgbe_phy_data *phy_data = pdata->phy_data;
1159a5c72737SRavi Kumar 	unsigned int redrv_reg;
1160a5c72737SRavi Kumar 	int ret;
1161a5c72737SRavi Kumar 
1162a5c72737SRavi Kumar 	/* Calculate the register to write */
1163a5c72737SRavi Kumar 	redrv_reg = AXGBE_PHY_REDRV_MODE_REG + (phy_data->redrv_lane * 0x1000);
1164a5c72737SRavi Kumar 
1165a5c72737SRavi Kumar 	ret = axgbe_phy_redrv_write(pdata, redrv_reg, mode);
1166a5c72737SRavi Kumar 
1167a5c72737SRavi Kumar 	return ret;
1168a5c72737SRavi Kumar }
1169a5c72737SRavi Kumar 
1170a5c72737SRavi Kumar static void axgbe_phy_set_redrv_mode(struct axgbe_port *pdata)
1171a5c72737SRavi Kumar {
1172a5c72737SRavi Kumar 	struct axgbe_phy_data *phy_data = pdata->phy_data;
1173a5c72737SRavi Kumar 	enum axgbe_phy_redrv_mode mode;
1174a5c72737SRavi Kumar 	int ret;
1175a5c72737SRavi Kumar 
1176a5c72737SRavi Kumar 	if (!phy_data->redrv)
1177a5c72737SRavi Kumar 		return;
1178a5c72737SRavi Kumar 
1179a5c72737SRavi Kumar 	mode = AXGBE_PHY_REDRV_MODE_CX;
1180a5c72737SRavi Kumar 	if ((phy_data->port_mode == AXGBE_PORT_MODE_SFP) &&
1181a5c72737SRavi Kumar 	    (phy_data->sfp_base != AXGBE_SFP_BASE_1000_CX) &&
1182a5c72737SRavi Kumar 	    (phy_data->sfp_base != AXGBE_SFP_BASE_10000_CR))
1183a5c72737SRavi Kumar 		mode = AXGBE_PHY_REDRV_MODE_SR;
1184a5c72737SRavi Kumar 
1185a5c72737SRavi Kumar 	ret = axgbe_phy_get_comm_ownership(pdata);
1186a5c72737SRavi Kumar 	if (ret)
1187a5c72737SRavi Kumar 		return;
1188a5c72737SRavi Kumar 
1189a5c72737SRavi Kumar 	if (phy_data->redrv_if)
1190a5c72737SRavi Kumar 		axgbe_phy_set_redrv_mode_i2c(pdata, mode);
1191a5c72737SRavi Kumar 	else
1192a5c72737SRavi Kumar 		axgbe_phy_set_redrv_mode_mdio(pdata, mode);
1193a5c72737SRavi Kumar 
1194a5c72737SRavi Kumar 	axgbe_phy_put_comm_ownership(pdata);
1195a5c72737SRavi Kumar }
1196a5c72737SRavi Kumar 
1197cd48955bSSelwin Sebastian static void axgbe_phy_rx_reset(struct axgbe_port *pdata)
1198cd48955bSSelwin Sebastian {
1199cd48955bSSelwin Sebastian 	int reg;
1200cd48955bSSelwin Sebastian 
1201cd48955bSSelwin Sebastian 	reg = XMDIO_READ_BITS(pdata, MDIO_MMD_PCS, MDIO_PCS_DIGITAL_STAT,
1202cd48955bSSelwin Sebastian 			      XGBE_PCS_PSEQ_STATE_MASK);
1203cd48955bSSelwin Sebastian 	if (reg == XGBE_PCS_PSEQ_STATE_POWER_GOOD) {
1204cd48955bSSelwin Sebastian 		/* Mailbox command timed out, reset of RX block is required.
1205cd48955bSSelwin Sebastian 		 * This can be done by asseting the reset bit and wait for
1206cd48955bSSelwin Sebastian 		 * its compeletion.
1207cd48955bSSelwin Sebastian 		 */
1208cd48955bSSelwin Sebastian 		XMDIO_WRITE_BITS(pdata, MDIO_MMD_PMAPMD, MDIO_PMA_RX_CTRL1,
1209cd48955bSSelwin Sebastian 				 XGBE_PMA_RX_RST_0_MASK, XGBE_PMA_RX_RST_0_RESET_ON);
1210cd48955bSSelwin Sebastian 		rte_delay_us(20);
1211cd48955bSSelwin Sebastian 		XMDIO_WRITE_BITS(pdata, MDIO_MMD_PMAPMD, MDIO_PMA_RX_CTRL1,
1212cd48955bSSelwin Sebastian 				 XGBE_PMA_RX_RST_0_MASK, XGBE_PMA_RX_RST_0_RESET_OFF);
1213cd48955bSSelwin Sebastian 		rte_delay_us(45);
1214cd48955bSSelwin Sebastian 		PMD_DRV_LOG(ERR, "firmware mailbox reset performed\n");
1215cd48955bSSelwin Sebastian 	}
1216cd48955bSSelwin Sebastian }
1217cd48955bSSelwin Sebastian 
1218cd48955bSSelwin Sebastian 
121909b0a36cSSelwin Sebastian static void axgbe_phy_pll_ctrl(struct axgbe_port *pdata, bool enable)
122009b0a36cSSelwin Sebastian {
12211c68b393SVenkat Kumar Ande 	/* PLL_CTRL feature needs to be enabled for fixed PHY modes (Non-Autoneg) only */
12221c68b393SVenkat Kumar Ande 	if (pdata->phy.autoneg != AUTONEG_DISABLE)
12231c68b393SVenkat Kumar Ande 		return;
12241c68b393SVenkat Kumar Ande 
122509b0a36cSSelwin Sebastian 	XMDIO_WRITE_BITS(pdata, MDIO_MMD_PMAPMD, MDIO_VEND2_PMA_MISC_CTRL0,
122609b0a36cSSelwin Sebastian 			XGBE_PMA_PLL_CTRL_MASK,
122709b0a36cSSelwin Sebastian 			enable ? XGBE_PMA_PLL_CTRL_SET
122809b0a36cSSelwin Sebastian 			: XGBE_PMA_PLL_CTRL_CLEAR);
122909b0a36cSSelwin Sebastian 
123009b0a36cSSelwin Sebastian 	/* Wait for command to complete */
123109b0a36cSSelwin Sebastian 	rte_delay_us(150);
123209b0a36cSSelwin Sebastian }
123309b0a36cSSelwin Sebastian 
12340df8d8dfSSelwin Sebastian static void axgbe_phy_perform_ratechange(struct axgbe_port *pdata,
1235cf96031aSVenkat Kumar Ande 		enum axgbe_mb_cmd cmd, enum axgbe_mb_subcmd sub_cmd)
1236a5c72737SRavi Kumar {
12370df8d8dfSSelwin Sebastian 	unsigned int s0 = 0;
12380df8d8dfSSelwin Sebastian 	unsigned int wait;
123909b0a36cSSelwin Sebastian 	/* Clear the PLL so that it helps in power down sequence */
124009b0a36cSSelwin Sebastian 	axgbe_phy_pll_ctrl(pdata, false);
124109b0a36cSSelwin Sebastian 
12424216cdc0SChandu Babu N 	/* Log if a previous command did not complete */
1243cd48955bSSelwin Sebastian 	if (XP_IOREAD_BITS(pdata, XP_DRIVER_INT_RO, STATUS)) {
12444216cdc0SChandu Babu N 		PMD_DRV_LOG(NOTICE, "firmware mailbox not ready for command\n");
1245cd48955bSSelwin Sebastian 		axgbe_phy_rx_reset(pdata);
1246cd48955bSSelwin Sebastian 	}
1247a5c72737SRavi Kumar 
12480df8d8dfSSelwin Sebastian 	/* Construct the command */
12490df8d8dfSSelwin Sebastian 	XP_SET_BITS(s0, XP_DRIVER_SCRATCH_0, COMMAND, cmd);
12500df8d8dfSSelwin Sebastian 	XP_SET_BITS(s0, XP_DRIVER_SCRATCH_0, SUB_COMMAND, sub_cmd);
12510df8d8dfSSelwin Sebastian 
12520df8d8dfSSelwin Sebastian 	/* Issue the command */
12530df8d8dfSSelwin Sebastian 	XP_IOWRITE(pdata, XP_DRIVER_SCRATCH_0, s0);
12540df8d8dfSSelwin Sebastian 	XP_IOWRITE(pdata, XP_DRIVER_SCRATCH_1, 0);
12550df8d8dfSSelwin Sebastian 	XP_IOWRITE_BITS(pdata, XP_DRIVER_INT_REQ, REQUEST, 1);
1256a5c72737SRavi Kumar 
1257a5c72737SRavi Kumar 	/* Wait for command to complete */
1258a5c72737SRavi Kumar 	wait = AXGBE_RATECHANGE_COUNT;
1259a5c72737SRavi Kumar 	while (wait--) {
1260a5c72737SRavi Kumar 		if (!XP_IOREAD_BITS(pdata, XP_DRIVER_INT_RO, STATUS))
126109b0a36cSSelwin Sebastian 			goto reenable_pll;
1262a5c72737SRavi Kumar 		rte_delay_us(1500);
1263a5c72737SRavi Kumar 	}
1264cd48955bSSelwin Sebastian 	PMD_DRV_LOG(NOTICE, "firmware mailbox command did not complete\n");
1265cd48955bSSelwin Sebastian 	/* Reset on error */
1266cd48955bSSelwin Sebastian 	axgbe_phy_rx_reset(pdata);
126709b0a36cSSelwin Sebastian 
126809b0a36cSSelwin Sebastian reenable_pll:
12691c68b393SVenkat Kumar Ande 	/* Enable PLL re-initialization, not needed for PHY Power Off and RRC cmds */
1270cf96031aSVenkat Kumar Ande 	if (cmd != AXGBE_MB_CMD_POWER_OFF &&
1271cf96031aSVenkat Kumar Ande 		cmd != AXGBE_MB_CMD_RRC)
127209b0a36cSSelwin Sebastian 		axgbe_phy_pll_ctrl(pdata, true);
127309b0a36cSSelwin Sebastian 
12744216cdc0SChandu Babu N 	PMD_DRV_LOG(NOTICE, "firmware mailbox command did not complete\n");
1275a5c72737SRavi Kumar }
1276a5c72737SRavi Kumar 
1277a5c72737SRavi Kumar static void axgbe_phy_rrc(struct axgbe_port *pdata)
1278a5c72737SRavi Kumar {
1279a5c72737SRavi Kumar 
1280a5c72737SRavi Kumar 
1281a5c72737SRavi Kumar 	/* Receiver Reset Cycle */
1282cf96031aSVenkat Kumar Ande 	axgbe_phy_perform_ratechange(pdata, AXGBE_MB_CMD_RRC, AXGBE_MB_SUBCMD_NONE);
12834216cdc0SChandu Babu N 
12844216cdc0SChandu Babu N 	PMD_DRV_LOG(DEBUG, "receiver reset complete\n");
1285a5c72737SRavi Kumar }
1286a5c72737SRavi Kumar 
1287a5c72737SRavi Kumar static void axgbe_phy_power_off(struct axgbe_port *pdata)
1288a5c72737SRavi Kumar {
1289a5c72737SRavi Kumar 	struct axgbe_phy_data *phy_data = pdata->phy_data;
1290a5c72737SRavi Kumar 
12910df8d8dfSSelwin Sebastian 	/* Power off */
1292cf96031aSVenkat Kumar Ande 	axgbe_phy_perform_ratechange(pdata, AXGBE_MB_CMD_POWER_OFF, AXGBE_MB_SUBCMD_NONE);
1293a5c72737SRavi Kumar 
1294a5c72737SRavi Kumar 	phy_data->cur_mode = AXGBE_MODE_UNKNOWN;
12954216cdc0SChandu Babu N 
12964216cdc0SChandu Babu N 	PMD_DRV_LOG(DEBUG, "phy powered off\n");
1297a5c72737SRavi Kumar }
1298a5c72737SRavi Kumar 
1299a5c72737SRavi Kumar static void axgbe_phy_sfi_mode(struct axgbe_port *pdata)
1300a5c72737SRavi Kumar {
1301a5c72737SRavi Kumar 	struct axgbe_phy_data *phy_data = pdata->phy_data;
1302a5c72737SRavi Kumar 
1303a5c72737SRavi Kumar 	axgbe_phy_set_redrv_mode(pdata);
1304a5c72737SRavi Kumar 
1305a5c72737SRavi Kumar 	/* 10G/SFI */
1306a5c72737SRavi Kumar 	if (phy_data->sfp_cable != AXGBE_SFP_CABLE_PASSIVE) {
1307cf96031aSVenkat Kumar Ande 		axgbe_phy_perform_ratechange(pdata, AXGBE_MB_CMD_SET_10G_SFI,
1308cf96031aSVenkat Kumar Ande 							AXGBE_MB_SUBCMD_ACTIVE);
1309a5c72737SRavi Kumar 	} else {
1310a5c72737SRavi Kumar 		if (phy_data->sfp_cable_len <= 1)
1311cf96031aSVenkat Kumar Ande 			axgbe_phy_perform_ratechange(pdata, AXGBE_MB_CMD_SET_10G_SFI,
1312cf96031aSVenkat Kumar Ande 							AXGBE_MB_SUBCMD_PASSIVE_1M);
1313a5c72737SRavi Kumar 		else if (phy_data->sfp_cable_len <= 3)
1314cf96031aSVenkat Kumar Ande 			axgbe_phy_perform_ratechange(pdata, AXGBE_MB_CMD_SET_10G_SFI,
1315cf96031aSVenkat Kumar Ande 							AXGBE_MB_SUBCMD_PASSIVE_3M);
1316a5c72737SRavi Kumar 		else
1317cf96031aSVenkat Kumar Ande 			axgbe_phy_perform_ratechange(pdata, AXGBE_MB_CMD_SET_10G_SFI,
1318cf96031aSVenkat Kumar Ande 							AXGBE_MB_SUBCMD_PASSIVE_OTHER);
1319a5c72737SRavi Kumar 	}
1320a5c72737SRavi Kumar 
1321a5c72737SRavi Kumar 	phy_data->cur_mode = AXGBE_MODE_SFI;
13224216cdc0SChandu Babu N 
13234216cdc0SChandu Babu N 	PMD_DRV_LOG(DEBUG, "10GbE SFI mode set\n");
1324a5c72737SRavi Kumar }
1325a5c72737SRavi Kumar 
1326a5c72737SRavi Kumar static void axgbe_phy_kr_mode(struct axgbe_port *pdata)
1327a5c72737SRavi Kumar {
1328a5c72737SRavi Kumar 	struct axgbe_phy_data *phy_data = pdata->phy_data;
1329a5c72737SRavi Kumar 
1330a5c72737SRavi Kumar 	axgbe_phy_set_redrv_mode(pdata);
1331a5c72737SRavi Kumar 
1332a5c72737SRavi Kumar 	/* 10G/KR */
1333cf96031aSVenkat Kumar Ande 		axgbe_phy_perform_ratechange(pdata, AXGBE_MB_CMD_SET_10G_KR,
1334cf96031aSVenkat Kumar Ande 						AXGBE_MB_SUBCMD_NONE);
1335a5c72737SRavi Kumar 	phy_data->cur_mode = AXGBE_MODE_KR;
13364216cdc0SChandu Babu N 
13374216cdc0SChandu Babu N 	PMD_DRV_LOG(DEBUG, "10GbE KR mode set\n");
1338a5c72737SRavi Kumar }
1339a5c72737SRavi Kumar 
1340936e294cSGirish Nandibasappa static void axgbe_phy_kx_2500_mode(struct axgbe_port *pdata)
1341936e294cSGirish Nandibasappa {
1342936e294cSGirish Nandibasappa 	struct axgbe_phy_data *phy_data = pdata->phy_data;
1343936e294cSGirish Nandibasappa 
1344936e294cSGirish Nandibasappa 	axgbe_phy_set_redrv_mode(pdata);
13450df8d8dfSSelwin Sebastian 
1346936e294cSGirish Nandibasappa 	/* 2.5G/KX */
1347cf96031aSVenkat Kumar Ande 	axgbe_phy_perform_ratechange(pdata, AXGBE_MB_CMD_SET_2_5G, AXGBE_MB_SUBCMD_NONE);
1348936e294cSGirish Nandibasappa 	phy_data->cur_mode = AXGBE_MODE_KX_2500;
1349936e294cSGirish Nandibasappa }
1350936e294cSGirish Nandibasappa 
1351936e294cSGirish Nandibasappa static void axgbe_phy_sgmii_1000_mode(struct axgbe_port *pdata)
1352936e294cSGirish Nandibasappa {
1353936e294cSGirish Nandibasappa 	struct axgbe_phy_data *phy_data = pdata->phy_data;
1354936e294cSGirish Nandibasappa 
1355936e294cSGirish Nandibasappa 	axgbe_phy_set_redrv_mode(pdata);
1356936e294cSGirish Nandibasappa 
1357936e294cSGirish Nandibasappa 	/* 1G/SGMII */
1358cf96031aSVenkat Kumar Ande 	axgbe_phy_perform_ratechange(pdata, AXGBE_MB_CMD_SET_1G, AXGBE_MB_SUBCMD_1G_SGMII);
1359936e294cSGirish Nandibasappa 
1360936e294cSGirish Nandibasappa 	phy_data->cur_mode = AXGBE_MODE_SGMII_1000;
1361936e294cSGirish Nandibasappa }
1362936e294cSGirish Nandibasappa 
1363*1f9d2d3aSVenkat Kumar Ande static void axgbe_phy_sgmii_10_mode(struct axgbe_port *pdata)
1364*1f9d2d3aSVenkat Kumar Ande {
1365*1f9d2d3aSVenkat Kumar Ande 	struct axgbe_phy_data *phy_data = pdata->phy_data;
1366*1f9d2d3aSVenkat Kumar Ande 
1367*1f9d2d3aSVenkat Kumar Ande 	axgbe_phy_set_redrv_mode(pdata);
1368*1f9d2d3aSVenkat Kumar Ande 
1369*1f9d2d3aSVenkat Kumar Ande 	/* 10M/SGMII */
1370*1f9d2d3aSVenkat Kumar Ande 	axgbe_phy_perform_ratechange(pdata, AXGBE_MB_CMD_SET_1G, AXGBE_MB_SUBCMD_10MBITS);
1371*1f9d2d3aSVenkat Kumar Ande 
1372*1f9d2d3aSVenkat Kumar Ande 	phy_data->cur_mode = AXGBE_MODE_SGMII_10;
1373*1f9d2d3aSVenkat Kumar Ande }
1374*1f9d2d3aSVenkat Kumar Ande 
1375a5c72737SRavi Kumar static enum axgbe_mode axgbe_phy_cur_mode(struct axgbe_port *pdata)
1376a5c72737SRavi Kumar {
1377a5c72737SRavi Kumar 	struct axgbe_phy_data *phy_data = pdata->phy_data;
1378a5c72737SRavi Kumar 
1379a5c72737SRavi Kumar 	return phy_data->cur_mode;
1380a5c72737SRavi Kumar }
1381a5c72737SRavi Kumar 
1382a5c72737SRavi Kumar static enum axgbe_mode axgbe_phy_switch_baset_mode(struct axgbe_port *pdata)
1383a5c72737SRavi Kumar {
1384a5c72737SRavi Kumar 	struct axgbe_phy_data *phy_data = pdata->phy_data;
1385a5c72737SRavi Kumar 
1386a5c72737SRavi Kumar 	/* No switching if not 10GBase-T */
1387a5c72737SRavi Kumar 	if (phy_data->port_mode != AXGBE_PORT_MODE_10GBASE_T)
1388a5c72737SRavi Kumar 		return axgbe_phy_cur_mode(pdata);
1389a5c72737SRavi Kumar 
1390a5c72737SRavi Kumar 	switch (axgbe_phy_cur_mode(pdata)) {
1391*1f9d2d3aSVenkat Kumar Ande 	case AXGBE_MODE_SGMII_10:
1392a5c72737SRavi Kumar 	case AXGBE_MODE_SGMII_100:
1393a5c72737SRavi Kumar 	case AXGBE_MODE_SGMII_1000:
1394a5c72737SRavi Kumar 		return AXGBE_MODE_KR;
1395a5c72737SRavi Kumar 	case AXGBE_MODE_KR:
1396a5c72737SRavi Kumar 	default:
1397a5c72737SRavi Kumar 		return AXGBE_MODE_SGMII_1000;
1398a5c72737SRavi Kumar 	}
1399a5c72737SRavi Kumar }
1400a5c72737SRavi Kumar 
1401a5c72737SRavi Kumar static enum axgbe_mode axgbe_phy_switch_bp_2500_mode(struct axgbe_port *pdata
1402a5c72737SRavi Kumar 						     __rte_unused)
1403a5c72737SRavi Kumar {
1404a5c72737SRavi Kumar 	return AXGBE_MODE_KX_2500;
1405a5c72737SRavi Kumar }
1406a5c72737SRavi Kumar 
1407a5c72737SRavi Kumar static enum axgbe_mode axgbe_phy_switch_bp_mode(struct axgbe_port *pdata)
1408a5c72737SRavi Kumar {
1409a5c72737SRavi Kumar 	/* If we are in KR switch to KX, and vice-versa */
1410a5c72737SRavi Kumar 	switch (axgbe_phy_cur_mode(pdata)) {
1411a5c72737SRavi Kumar 	case AXGBE_MODE_KX_1000:
1412a5c72737SRavi Kumar 		return AXGBE_MODE_KR;
1413a5c72737SRavi Kumar 	case AXGBE_MODE_KR:
1414a5c72737SRavi Kumar 	default:
1415a5c72737SRavi Kumar 		return AXGBE_MODE_KX_1000;
1416a5c72737SRavi Kumar 	}
1417a5c72737SRavi Kumar }
1418a5c72737SRavi Kumar 
1419a5c72737SRavi Kumar static enum axgbe_mode axgbe_phy_switch_mode(struct axgbe_port *pdata)
1420a5c72737SRavi Kumar {
1421a5c72737SRavi Kumar 	struct axgbe_phy_data *phy_data = pdata->phy_data;
1422a5c72737SRavi Kumar 
1423a5c72737SRavi Kumar 	switch (phy_data->port_mode) {
1424a5c72737SRavi Kumar 	case AXGBE_PORT_MODE_BACKPLANE:
1425443ab5aaSSelwin Sebastian 	case AXGBE_PORT_MODE_BACKPLANE_NO_AUTONEG:
1426a5c72737SRavi Kumar 		return axgbe_phy_switch_bp_mode(pdata);
1427a5c72737SRavi Kumar 	case AXGBE_PORT_MODE_BACKPLANE_2500:
1428a5c72737SRavi Kumar 		return axgbe_phy_switch_bp_2500_mode(pdata);
1429a5c72737SRavi Kumar 	case AXGBE_PORT_MODE_1000BASE_T:
1430a5c72737SRavi Kumar 	case AXGBE_PORT_MODE_NBASE_T:
1431a5c72737SRavi Kumar 	case AXGBE_PORT_MODE_10GBASE_T:
1432a5c72737SRavi Kumar 		return axgbe_phy_switch_baset_mode(pdata);
1433a5c72737SRavi Kumar 	case AXGBE_PORT_MODE_1000BASE_X:
1434a5c72737SRavi Kumar 	case AXGBE_PORT_MODE_10GBASE_R:
1435a5c72737SRavi Kumar 	case AXGBE_PORT_MODE_SFP:
1436a5c72737SRavi Kumar 		/* No switching, so just return current mode */
1437a5c72737SRavi Kumar 		return axgbe_phy_cur_mode(pdata);
1438a5c72737SRavi Kumar 	default:
1439a5c72737SRavi Kumar 		return AXGBE_MODE_UNKNOWN;
1440a5c72737SRavi Kumar 	}
1441a5c72737SRavi Kumar }
1442a5c72737SRavi Kumar 
1443a5c72737SRavi Kumar static enum axgbe_mode axgbe_phy_get_basex_mode(struct axgbe_phy_data *phy_data
1444a5c72737SRavi Kumar 						__rte_unused,
1445a5c72737SRavi Kumar 						int speed)
1446a5c72737SRavi Kumar {
1447a5c72737SRavi Kumar 	switch (speed) {
1448a5c72737SRavi Kumar 	case SPEED_1000:
1449a5c72737SRavi Kumar 		return AXGBE_MODE_X;
1450a5c72737SRavi Kumar 	case SPEED_10000:
1451a5c72737SRavi Kumar 		return AXGBE_MODE_KR;
1452a5c72737SRavi Kumar 	default:
1453a5c72737SRavi Kumar 		return AXGBE_MODE_UNKNOWN;
1454a5c72737SRavi Kumar 	}
1455a5c72737SRavi Kumar }
1456a5c72737SRavi Kumar 
1457a5c72737SRavi Kumar static enum axgbe_mode axgbe_phy_get_baset_mode(struct axgbe_phy_data *phy_data
1458a5c72737SRavi Kumar 						__rte_unused,
1459a5c72737SRavi Kumar 						int speed)
1460a5c72737SRavi Kumar {
1461a5c72737SRavi Kumar 	switch (speed) {
1462*1f9d2d3aSVenkat Kumar Ande 	case SPEED_10:
1463*1f9d2d3aSVenkat Kumar Ande 		return AXGBE_MODE_SGMII_10;
1464a5c72737SRavi Kumar 	case SPEED_100:
1465a5c72737SRavi Kumar 		return AXGBE_MODE_SGMII_100;
1466a5c72737SRavi Kumar 	case SPEED_1000:
1467a5c72737SRavi Kumar 		return AXGBE_MODE_SGMII_1000;
1468a5c72737SRavi Kumar 	case SPEED_10000:
1469a5c72737SRavi Kumar 		return AXGBE_MODE_KR;
1470a5c72737SRavi Kumar 	default:
1471a5c72737SRavi Kumar 		return AXGBE_MODE_UNKNOWN;
1472a5c72737SRavi Kumar 	}
1473a5c72737SRavi Kumar }
1474a5c72737SRavi Kumar 
1475a5c72737SRavi Kumar static enum axgbe_mode axgbe_phy_get_sfp_mode(struct axgbe_phy_data *phy_data,
1476a5c72737SRavi Kumar 					      int speed)
1477a5c72737SRavi Kumar {
1478a5c72737SRavi Kumar 	switch (speed) {
1479*1f9d2d3aSVenkat Kumar Ande 	case SPEED_10:
1480*1f9d2d3aSVenkat Kumar Ande 		return AXGBE_MODE_SGMII_10;
1481a5c72737SRavi Kumar 	case SPEED_100:
1482a5c72737SRavi Kumar 		return AXGBE_MODE_SGMII_100;
1483a5c72737SRavi Kumar 	case SPEED_1000:
1484a5c72737SRavi Kumar 		if (phy_data->sfp_base == AXGBE_SFP_BASE_1000_T)
1485a5c72737SRavi Kumar 			return AXGBE_MODE_SGMII_1000;
1486a5c72737SRavi Kumar 		else
1487a5c72737SRavi Kumar 			return AXGBE_MODE_X;
1488a5c72737SRavi Kumar 	case SPEED_10000:
1489a5c72737SRavi Kumar 	case SPEED_UNKNOWN:
1490a5c72737SRavi Kumar 		return AXGBE_MODE_SFI;
1491a5c72737SRavi Kumar 	default:
1492a5c72737SRavi Kumar 		return AXGBE_MODE_UNKNOWN;
1493a5c72737SRavi Kumar 	}
1494a5c72737SRavi Kumar }
1495a5c72737SRavi Kumar 
1496a5c72737SRavi Kumar static enum axgbe_mode axgbe_phy_get_bp_2500_mode(int speed)
1497a5c72737SRavi Kumar {
1498a5c72737SRavi Kumar 	switch (speed) {
1499a5c72737SRavi Kumar 	case SPEED_2500:
1500a5c72737SRavi Kumar 		return AXGBE_MODE_KX_2500;
1501a5c72737SRavi Kumar 	default:
1502a5c72737SRavi Kumar 		return AXGBE_MODE_UNKNOWN;
1503a5c72737SRavi Kumar 	}
1504a5c72737SRavi Kumar }
1505a5c72737SRavi Kumar 
1506a5c72737SRavi Kumar static enum axgbe_mode axgbe_phy_get_bp_mode(int speed)
1507a5c72737SRavi Kumar {
1508a5c72737SRavi Kumar 	switch (speed) {
1509a5c72737SRavi Kumar 	case SPEED_1000:
1510a5c72737SRavi Kumar 		return AXGBE_MODE_KX_1000;
1511a5c72737SRavi Kumar 	case SPEED_10000:
1512a5c72737SRavi Kumar 		return AXGBE_MODE_KR;
1513a5c72737SRavi Kumar 	default:
1514a5c72737SRavi Kumar 		return AXGBE_MODE_UNKNOWN;
1515a5c72737SRavi Kumar 	}
1516a5c72737SRavi Kumar }
1517a5c72737SRavi Kumar 
1518a5c72737SRavi Kumar static enum axgbe_mode axgbe_phy_get_mode(struct axgbe_port *pdata,
1519a5c72737SRavi Kumar 					  int speed)
1520a5c72737SRavi Kumar {
1521a5c72737SRavi Kumar 	struct axgbe_phy_data *phy_data = pdata->phy_data;
1522a5c72737SRavi Kumar 
1523a5c72737SRavi Kumar 	switch (phy_data->port_mode) {
1524a5c72737SRavi Kumar 	case AXGBE_PORT_MODE_BACKPLANE:
1525443ab5aaSSelwin Sebastian 	case AXGBE_PORT_MODE_BACKPLANE_NO_AUTONEG:
1526a5c72737SRavi Kumar 		return axgbe_phy_get_bp_mode(speed);
1527a5c72737SRavi Kumar 	case AXGBE_PORT_MODE_BACKPLANE_2500:
1528a5c72737SRavi Kumar 		return axgbe_phy_get_bp_2500_mode(speed);
1529a5c72737SRavi Kumar 	case AXGBE_PORT_MODE_1000BASE_T:
1530a5c72737SRavi Kumar 	case AXGBE_PORT_MODE_NBASE_T:
1531a5c72737SRavi Kumar 	case AXGBE_PORT_MODE_10GBASE_T:
1532a5c72737SRavi Kumar 		return axgbe_phy_get_baset_mode(phy_data, speed);
1533a5c72737SRavi Kumar 	case AXGBE_PORT_MODE_1000BASE_X:
1534a5c72737SRavi Kumar 	case AXGBE_PORT_MODE_10GBASE_R:
1535a5c72737SRavi Kumar 		return axgbe_phy_get_basex_mode(phy_data, speed);
1536a5c72737SRavi Kumar 	case AXGBE_PORT_MODE_SFP:
1537a5c72737SRavi Kumar 		return axgbe_phy_get_sfp_mode(phy_data, speed);
1538a5c72737SRavi Kumar 	default:
1539a5c72737SRavi Kumar 		return AXGBE_MODE_UNKNOWN;
1540a5c72737SRavi Kumar 	}
1541a5c72737SRavi Kumar }
1542a5c72737SRavi Kumar 
1543a5c72737SRavi Kumar static void axgbe_phy_set_mode(struct axgbe_port *pdata, enum axgbe_mode mode)
1544a5c72737SRavi Kumar {
1545a5c72737SRavi Kumar 	switch (mode) {
1546a5c72737SRavi Kumar 	case AXGBE_MODE_KR:
1547a5c72737SRavi Kumar 		axgbe_phy_kr_mode(pdata);
1548a5c72737SRavi Kumar 		break;
1549a5c72737SRavi Kumar 	case AXGBE_MODE_SFI:
1550a5c72737SRavi Kumar 		axgbe_phy_sfi_mode(pdata);
1551a5c72737SRavi Kumar 		break;
1552936e294cSGirish Nandibasappa 	case AXGBE_MODE_KX_2500:
1553936e294cSGirish Nandibasappa 		axgbe_phy_kx_2500_mode(pdata);
1554936e294cSGirish Nandibasappa 		break;
1555936e294cSGirish Nandibasappa 	case AXGBE_MODE_SGMII_1000:
1556936e294cSGirish Nandibasappa 		axgbe_phy_sgmii_1000_mode(pdata);
1557936e294cSGirish Nandibasappa 		break;
1558*1f9d2d3aSVenkat Kumar Ande 	case AXGBE_MODE_SGMII_10:
1559*1f9d2d3aSVenkat Kumar Ande 		axgbe_phy_sgmii_10_mode(pdata);
1560*1f9d2d3aSVenkat Kumar Ande 		break;
1561a5c72737SRavi Kumar 	default:
1562a5c72737SRavi Kumar 		break;
1563a5c72737SRavi Kumar 	}
1564a5c72737SRavi Kumar }
1565a5c72737SRavi Kumar 
1566a5c72737SRavi Kumar static bool axgbe_phy_check_mode(struct axgbe_port *pdata,
1567a5c72737SRavi Kumar 				 enum axgbe_mode mode, u32 advert)
1568a5c72737SRavi Kumar {
1569a5c72737SRavi Kumar 	if (pdata->phy.autoneg == AUTONEG_ENABLE) {
1570a5c72737SRavi Kumar 		if (pdata->phy.advertising & advert)
1571a5c72737SRavi Kumar 			return true;
1572a5c72737SRavi Kumar 	} else {
1573a5c72737SRavi Kumar 		enum axgbe_mode cur_mode;
1574a5c72737SRavi Kumar 
1575a5c72737SRavi Kumar 		cur_mode = axgbe_phy_get_mode(pdata, pdata->phy.speed);
1576a5c72737SRavi Kumar 		if (cur_mode == mode)
1577a5c72737SRavi Kumar 			return true;
1578a5c72737SRavi Kumar 	}
1579a5c72737SRavi Kumar 
1580a5c72737SRavi Kumar 	return false;
1581a5c72737SRavi Kumar }
1582a5c72737SRavi Kumar 
1583a5c72737SRavi Kumar static bool axgbe_phy_use_basex_mode(struct axgbe_port *pdata,
1584a5c72737SRavi Kumar 				     enum axgbe_mode mode)
1585a5c72737SRavi Kumar {
1586a5c72737SRavi Kumar 	switch (mode) {
1587a5c72737SRavi Kumar 	case AXGBE_MODE_X:
1588a5c72737SRavi Kumar 		return axgbe_phy_check_mode(pdata, mode,
1589a5c72737SRavi Kumar 					    ADVERTISED_1000baseT_Full);
1590a5c72737SRavi Kumar 	case AXGBE_MODE_KR:
1591a5c72737SRavi Kumar 		return axgbe_phy_check_mode(pdata, mode,
1592a5c72737SRavi Kumar 					    ADVERTISED_10000baseT_Full);
1593a5c72737SRavi Kumar 	default:
1594a5c72737SRavi Kumar 		return false;
1595a5c72737SRavi Kumar 	}
1596a5c72737SRavi Kumar }
1597a5c72737SRavi Kumar 
1598a5c72737SRavi Kumar static bool axgbe_phy_use_baset_mode(struct axgbe_port *pdata,
1599a5c72737SRavi Kumar 				     enum axgbe_mode mode)
1600a5c72737SRavi Kumar {
1601a5c72737SRavi Kumar 	switch (mode) {
1602*1f9d2d3aSVenkat Kumar Ande 	case AXGBE_MODE_SGMII_10:
1603*1f9d2d3aSVenkat Kumar Ande 		return axgbe_phy_check_mode(pdata, mode,
1604*1f9d2d3aSVenkat Kumar Ande 					    ADVERTISED_10baseT_Full);
1605a5c72737SRavi Kumar 	case AXGBE_MODE_SGMII_100:
1606a5c72737SRavi Kumar 		return axgbe_phy_check_mode(pdata, mode,
1607a5c72737SRavi Kumar 					    ADVERTISED_100baseT_Full);
1608a5c72737SRavi Kumar 	case AXGBE_MODE_SGMII_1000:
1609a5c72737SRavi Kumar 		return axgbe_phy_check_mode(pdata, mode,
1610a5c72737SRavi Kumar 					    ADVERTISED_1000baseT_Full);
1611a5c72737SRavi Kumar 	case AXGBE_MODE_KR:
1612a5c72737SRavi Kumar 		return axgbe_phy_check_mode(pdata, mode,
1613a5c72737SRavi Kumar 					    ADVERTISED_10000baseT_Full);
1614a5c72737SRavi Kumar 	default:
1615a5c72737SRavi Kumar 		return false;
1616a5c72737SRavi Kumar 	}
1617a5c72737SRavi Kumar }
1618a5c72737SRavi Kumar 
1619a5c72737SRavi Kumar static bool axgbe_phy_use_sfp_mode(struct axgbe_port *pdata,
1620a5c72737SRavi Kumar 				   enum axgbe_mode mode)
1621a5c72737SRavi Kumar {
1622a5c72737SRavi Kumar 	struct axgbe_phy_data *phy_data = pdata->phy_data;
1623a5c72737SRavi Kumar 
1624a5c72737SRavi Kumar 	switch (mode) {
1625a5c72737SRavi Kumar 	case AXGBE_MODE_X:
1626a5c72737SRavi Kumar 		if (phy_data->sfp_base == AXGBE_SFP_BASE_1000_T)
1627a5c72737SRavi Kumar 			return false;
1628a5c72737SRavi Kumar 		return axgbe_phy_check_mode(pdata, mode,
1629a5c72737SRavi Kumar 					    ADVERTISED_1000baseT_Full);
1630*1f9d2d3aSVenkat Kumar Ande 	case AXGBE_MODE_SGMII_10:
1631*1f9d2d3aSVenkat Kumar Ande 		if (phy_data->sfp_base != AXGBE_SFP_BASE_1000_T)
1632*1f9d2d3aSVenkat Kumar Ande 			return false;
1633*1f9d2d3aSVenkat Kumar Ande 		return axgbe_phy_check_mode(pdata, mode,
1634*1f9d2d3aSVenkat Kumar Ande 					    ADVERTISED_10baseT_Full);
1635a5c72737SRavi Kumar 	case AXGBE_MODE_SGMII_100:
1636a5c72737SRavi Kumar 		if (phy_data->sfp_base != AXGBE_SFP_BASE_1000_T)
1637a5c72737SRavi Kumar 			return false;
1638a5c72737SRavi Kumar 		return axgbe_phy_check_mode(pdata, mode,
1639a5c72737SRavi Kumar 					    ADVERTISED_100baseT_Full);
1640a5c72737SRavi Kumar 	case AXGBE_MODE_SGMII_1000:
1641a5c72737SRavi Kumar 		if (phy_data->sfp_base != AXGBE_SFP_BASE_1000_T)
1642a5c72737SRavi Kumar 			return false;
1643a5c72737SRavi Kumar 		return axgbe_phy_check_mode(pdata, mode,
1644a5c72737SRavi Kumar 					    ADVERTISED_1000baseT_Full);
1645a5c72737SRavi Kumar 	case AXGBE_MODE_SFI:
1646a5c72737SRavi Kumar 		return axgbe_phy_check_mode(pdata, mode,
1647a5c72737SRavi Kumar 					    ADVERTISED_10000baseT_Full);
1648a5c72737SRavi Kumar 	default:
1649a5c72737SRavi Kumar 		return false;
1650a5c72737SRavi Kumar 	}
1651a5c72737SRavi Kumar }
1652a5c72737SRavi Kumar 
1653a5c72737SRavi Kumar static bool axgbe_phy_use_bp_2500_mode(struct axgbe_port *pdata,
1654a5c72737SRavi Kumar 				       enum axgbe_mode mode)
1655a5c72737SRavi Kumar {
1656a5c72737SRavi Kumar 	switch (mode) {
1657a5c72737SRavi Kumar 	case AXGBE_MODE_KX_2500:
1658a5c72737SRavi Kumar 		return axgbe_phy_check_mode(pdata, mode,
1659a5c72737SRavi Kumar 					    ADVERTISED_2500baseX_Full);
1660a5c72737SRavi Kumar 	default:
1661a5c72737SRavi Kumar 		return false;
1662a5c72737SRavi Kumar 	}
1663a5c72737SRavi Kumar }
1664a5c72737SRavi Kumar 
1665a5c72737SRavi Kumar static bool axgbe_phy_use_bp_mode(struct axgbe_port *pdata,
1666a5c72737SRavi Kumar 				  enum axgbe_mode mode)
1667a5c72737SRavi Kumar {
1668a5c72737SRavi Kumar 	switch (mode) {
1669a5c72737SRavi Kumar 	case AXGBE_MODE_KX_1000:
1670a5c72737SRavi Kumar 		return axgbe_phy_check_mode(pdata, mode,
1671a5c72737SRavi Kumar 					    ADVERTISED_1000baseKX_Full);
1672a5c72737SRavi Kumar 	case AXGBE_MODE_KR:
1673a5c72737SRavi Kumar 		return axgbe_phy_check_mode(pdata, mode,
1674a5c72737SRavi Kumar 					    ADVERTISED_10000baseKR_Full);
1675a5c72737SRavi Kumar 	default:
1676a5c72737SRavi Kumar 		return false;
1677a5c72737SRavi Kumar 	}
1678a5c72737SRavi Kumar }
1679a5c72737SRavi Kumar 
1680a5c72737SRavi Kumar static bool axgbe_phy_use_mode(struct axgbe_port *pdata, enum axgbe_mode mode)
1681a5c72737SRavi Kumar {
1682a5c72737SRavi Kumar 	struct axgbe_phy_data *phy_data = pdata->phy_data;
1683a5c72737SRavi Kumar 
1684a5c72737SRavi Kumar 	switch (phy_data->port_mode) {
1685a5c72737SRavi Kumar 	case AXGBE_PORT_MODE_BACKPLANE:
1686443ab5aaSSelwin Sebastian 	case AXGBE_PORT_MODE_BACKPLANE_NO_AUTONEG:
1687a5c72737SRavi Kumar 		return axgbe_phy_use_bp_mode(pdata, mode);
1688a5c72737SRavi Kumar 	case AXGBE_PORT_MODE_BACKPLANE_2500:
1689a5c72737SRavi Kumar 		return axgbe_phy_use_bp_2500_mode(pdata, mode);
1690a5c72737SRavi Kumar 	case AXGBE_PORT_MODE_1000BASE_T:
1691a5c72737SRavi Kumar 	case AXGBE_PORT_MODE_NBASE_T:
1692a5c72737SRavi Kumar 	case AXGBE_PORT_MODE_10GBASE_T:
1693a5c72737SRavi Kumar 		return axgbe_phy_use_baset_mode(pdata, mode);
1694a5c72737SRavi Kumar 	case AXGBE_PORT_MODE_1000BASE_X:
1695a5c72737SRavi Kumar 	case AXGBE_PORT_MODE_10GBASE_R:
1696a5c72737SRavi Kumar 		return axgbe_phy_use_basex_mode(pdata, mode);
1697a5c72737SRavi Kumar 	case AXGBE_PORT_MODE_SFP:
1698a5c72737SRavi Kumar 		return axgbe_phy_use_sfp_mode(pdata, mode);
1699a5c72737SRavi Kumar 	default:
1700a5c72737SRavi Kumar 		return false;
1701a5c72737SRavi Kumar 	}
1702a5c72737SRavi Kumar }
1703a5c72737SRavi Kumar 
1704a5c72737SRavi Kumar static int axgbe_phy_link_status(struct axgbe_port *pdata, int *an_restart)
1705a5c72737SRavi Kumar {
1706a5c72737SRavi Kumar 	struct axgbe_phy_data *phy_data = pdata->phy_data;
1707a5c72737SRavi Kumar 	unsigned int reg;
1708a5c72737SRavi Kumar 
1709a5c72737SRavi Kumar 	*an_restart = 0;
1710a5c72737SRavi Kumar 
1711a5c72737SRavi Kumar 	if (phy_data->port_mode == AXGBE_PORT_MODE_SFP) {
1712a5c72737SRavi Kumar 		/* Check SFP signals */
1713a5c72737SRavi Kumar 		axgbe_phy_sfp_detect(pdata);
1714a5c72737SRavi Kumar 
1715a5c72737SRavi Kumar 		if (phy_data->sfp_changed) {
1716a5c72737SRavi Kumar 			*an_restart = 1;
1717a5c72737SRavi Kumar 			return 0;
1718a5c72737SRavi Kumar 		}
1719a5c72737SRavi Kumar 
1720a5c72737SRavi Kumar 		if (phy_data->sfp_mod_absent || phy_data->sfp_rx_los)
1721a5c72737SRavi Kumar 			return 0;
1722a5c72737SRavi Kumar 	}
1723a5c72737SRavi Kumar 
1724a5c72737SRavi Kumar 	/* Link status is latched low, so read once to clear
1725a5c72737SRavi Kumar 	 * and then read again to get current state
1726a5c72737SRavi Kumar 	 */
1727a5c72737SRavi Kumar 	reg = XMDIO_READ(pdata, MDIO_MMD_PCS, MDIO_STAT1);
1728a5c72737SRavi Kumar 	reg = XMDIO_READ(pdata, MDIO_MMD_PCS, MDIO_STAT1);
1729a5c72737SRavi Kumar 	if (reg & MDIO_STAT1_LSTATUS)
1730a5c72737SRavi Kumar 		return 1;
1731a5c72737SRavi Kumar 
1732edf46325SVenkat Kumar Ande 	if (pdata->phy.autoneg == AUTONEG_ENABLE &&
1733edf46325SVenkat Kumar Ande 			phy_data->port_mode == AXGBE_PORT_MODE_BACKPLANE) {
1734edf46325SVenkat Kumar Ande 		if (rte_bit_relaxed_get32(AXGBE_LINK_INIT, &pdata->dev_state)) {
1735edf46325SVenkat Kumar Ande 			*an_restart = 1;
1736edf46325SVenkat Kumar Ande 		}
1737edf46325SVenkat Kumar Ande 	}
1738edf46325SVenkat Kumar Ande 
1739a5c72737SRavi Kumar 	/* No link, attempt a receiver reset cycle */
1740e82b0fe0SVenkat Kumar Ande 	if (pdata->vdata->enable_rrc && phy_data->rrc_count++) {
1741a5c72737SRavi Kumar 		phy_data->rrc_count = 0;
1742a5c72737SRavi Kumar 		axgbe_phy_rrc(pdata);
1743a5c72737SRavi Kumar 	}
1744a5c72737SRavi Kumar 
1745a5c72737SRavi Kumar 	return 0;
1746a5c72737SRavi Kumar }
1747a5c72737SRavi Kumar 
17484ac7516bSRavi Kumar static void axgbe_phy_sfp_gpio_setup(struct axgbe_port *pdata)
17494ac7516bSRavi Kumar {
17504ac7516bSRavi Kumar 	struct axgbe_phy_data *phy_data = pdata->phy_data;
17514ac7516bSRavi Kumar 
17524ac7516bSRavi Kumar 	phy_data->sfp_gpio_address = AXGBE_GPIO_ADDRESS_PCA9555 +
1753a3ec01b4SVenkat Kumar Ande 		XP_GET_BITS(pdata->pp3, XP_PROP_3, GPIO_ADDR);
17544ac7516bSRavi Kumar 
1755a3ec01b4SVenkat Kumar Ande 	phy_data->sfp_gpio_mask = XP_GET_BITS(pdata->pp3, XP_PROP_3, GPIO_MASK);
17564ac7516bSRavi Kumar 
1757a3ec01b4SVenkat Kumar Ande 	phy_data->sfp_gpio_rx_los = XP_GET_BITS(pdata->pp3, XP_PROP_3,
17584ac7516bSRavi Kumar 						GPIO_RX_LOS);
1759a3ec01b4SVenkat Kumar Ande 	phy_data->sfp_gpio_tx_fault = XP_GET_BITS(pdata->pp3, XP_PROP_3,
17604ac7516bSRavi Kumar 						  GPIO_TX_FAULT);
1761a3ec01b4SVenkat Kumar Ande 	phy_data->sfp_gpio_mod_absent = XP_GET_BITS(pdata->pp3, XP_PROP_3,
17624ac7516bSRavi Kumar 						    GPIO_MOD_ABS);
1763a3ec01b4SVenkat Kumar Ande 	phy_data->sfp_gpio_rate_select = XP_GET_BITS(pdata->pp3, XP_PROP_3,
17644ac7516bSRavi Kumar 						     GPIO_RATE_SELECT);
17654ac7516bSRavi Kumar }
17664ac7516bSRavi Kumar 
17674ac7516bSRavi Kumar static void axgbe_phy_sfp_comm_setup(struct axgbe_port *pdata)
17684ac7516bSRavi Kumar {
17694ac7516bSRavi Kumar 	struct axgbe_phy_data *phy_data = pdata->phy_data;
1770a3ec01b4SVenkat Kumar Ande 	unsigned int mux_addr_hi, mux_addr_lo;
17714ac7516bSRavi Kumar 
1772a3ec01b4SVenkat Kumar Ande 	mux_addr_hi = XP_GET_BITS(pdata->pp4, XP_PROP_4, MUX_ADDR_HI);
1773a3ec01b4SVenkat Kumar Ande 	mux_addr_lo = XP_GET_BITS(pdata->pp4, XP_PROP_4, MUX_ADDR_LO);
17744ac7516bSRavi Kumar 	if (mux_addr_lo == AXGBE_SFP_DIRECT)
17754ac7516bSRavi Kumar 		return;
17764ac7516bSRavi Kumar 
17774ac7516bSRavi Kumar 	phy_data->sfp_comm = AXGBE_SFP_COMM_PCA9545;
17784ac7516bSRavi Kumar 	phy_data->sfp_mux_address = (mux_addr_hi << 2) + mux_addr_lo;
1779a3ec01b4SVenkat Kumar Ande 	phy_data->sfp_mux_channel = XP_GET_BITS(pdata->pp4, XP_PROP_4, MUX_CHAN);
17804ac7516bSRavi Kumar }
17814ac7516bSRavi Kumar 
17824ac7516bSRavi Kumar static void axgbe_phy_sfp_setup(struct axgbe_port *pdata)
17834ac7516bSRavi Kumar {
17844ac7516bSRavi Kumar 	axgbe_phy_sfp_comm_setup(pdata);
17854ac7516bSRavi Kumar 	axgbe_phy_sfp_gpio_setup(pdata);
17864ac7516bSRavi Kumar }
17874ac7516bSRavi Kumar 
17884ac7516bSRavi Kumar static bool axgbe_phy_redrv_error(struct axgbe_phy_data *phy_data)
17894ac7516bSRavi Kumar {
17904ac7516bSRavi Kumar 	if (!phy_data->redrv)
17914ac7516bSRavi Kumar 		return false;
17924ac7516bSRavi Kumar 
17934ac7516bSRavi Kumar 	if (phy_data->redrv_if >= AXGBE_PHY_REDRV_IF_MAX)
17944ac7516bSRavi Kumar 		return true;
17954ac7516bSRavi Kumar 
17964ac7516bSRavi Kumar 	switch (phy_data->redrv_model) {
17974ac7516bSRavi Kumar 	case AXGBE_PHY_REDRV_MODEL_4223:
17984ac7516bSRavi Kumar 		if (phy_data->redrv_lane > 3)
17994ac7516bSRavi Kumar 			return true;
18004ac7516bSRavi Kumar 		break;
18014ac7516bSRavi Kumar 	case AXGBE_PHY_REDRV_MODEL_4227:
18024ac7516bSRavi Kumar 		if (phy_data->redrv_lane > 1)
18034ac7516bSRavi Kumar 			return true;
18044ac7516bSRavi Kumar 		break;
18054ac7516bSRavi Kumar 	default:
18064ac7516bSRavi Kumar 		return true;
18074ac7516bSRavi Kumar 	}
18084ac7516bSRavi Kumar 
18094ac7516bSRavi Kumar 	return false;
18104ac7516bSRavi Kumar }
18114ac7516bSRavi Kumar 
18124ac7516bSRavi Kumar static int axgbe_phy_mdio_reset_setup(struct axgbe_port *pdata)
18134ac7516bSRavi Kumar {
18144ac7516bSRavi Kumar 	struct axgbe_phy_data *phy_data = pdata->phy_data;
18154ac7516bSRavi Kumar 
18164ac7516bSRavi Kumar 	if (phy_data->conn_type != AXGBE_CONN_TYPE_MDIO)
18174ac7516bSRavi Kumar 		return 0;
1818a3ec01b4SVenkat Kumar Ande 
1819a3ec01b4SVenkat Kumar Ande 	phy_data->mdio_reset = XP_GET_BITS(pdata->pp3, XP_PROP_3, MDIO_RESET);
18204ac7516bSRavi Kumar 	switch (phy_data->mdio_reset) {
18214ac7516bSRavi Kumar 	case AXGBE_MDIO_RESET_NONE:
18224ac7516bSRavi Kumar 	case AXGBE_MDIO_RESET_I2C_GPIO:
18234ac7516bSRavi Kumar 	case AXGBE_MDIO_RESET_INT_GPIO:
18244ac7516bSRavi Kumar 		break;
18254ac7516bSRavi Kumar 	default:
18264ac7516bSRavi Kumar 		PMD_DRV_LOG(ERR, "unsupported MDIO reset (%#x)\n",
18274ac7516bSRavi Kumar 			    phy_data->mdio_reset);
18284ac7516bSRavi Kumar 		return -EINVAL;
18294ac7516bSRavi Kumar 	}
18304ac7516bSRavi Kumar 	if (phy_data->mdio_reset == AXGBE_MDIO_RESET_I2C_GPIO) {
18314ac7516bSRavi Kumar 		phy_data->mdio_reset_addr = AXGBE_GPIO_ADDRESS_PCA9555 +
1832a3ec01b4SVenkat Kumar Ande 			XP_GET_BITS(pdata->pp3, XP_PROP_3,
18334ac7516bSRavi Kumar 				    MDIO_RESET_I2C_ADDR);
1834a3ec01b4SVenkat Kumar Ande 		phy_data->mdio_reset_gpio = XP_GET_BITS(pdata->pp3, XP_PROP_3,
18354ac7516bSRavi Kumar 							MDIO_RESET_I2C_GPIO);
18364ac7516bSRavi Kumar 	} else if (phy_data->mdio_reset == AXGBE_MDIO_RESET_INT_GPIO) {
1837a3ec01b4SVenkat Kumar Ande 		phy_data->mdio_reset_gpio = XP_GET_BITS(pdata->pp3, XP_PROP_3,
18384ac7516bSRavi Kumar 							MDIO_RESET_INT_GPIO);
18394ac7516bSRavi Kumar 	}
18404ac7516bSRavi Kumar 
18414ac7516bSRavi Kumar 	return 0;
18424ac7516bSRavi Kumar }
18434ac7516bSRavi Kumar 
18444ac7516bSRavi Kumar static bool axgbe_phy_port_mode_mismatch(struct axgbe_port *pdata)
18454ac7516bSRavi Kumar {
18464ac7516bSRavi Kumar 	struct axgbe_phy_data *phy_data = pdata->phy_data;
1847*1f9d2d3aSVenkat Kumar Ande 	unsigned int ver;
1848*1f9d2d3aSVenkat Kumar Ande 
1849*1f9d2d3aSVenkat Kumar Ande 	/* 10 Mbps speed is not supported in ver < 30H */
1850*1f9d2d3aSVenkat Kumar Ande 	ver = AXGMAC_GET_BITS(pdata->hw_feat.version, MAC_VR, SNPSVER);
1851*1f9d2d3aSVenkat Kumar Ande 	if (ver < 0x30 && phy_data->port_speeds & AXGBE_PHY_PORT_SPEED_10)
1852*1f9d2d3aSVenkat Kumar Ande 		return true;
18534ac7516bSRavi Kumar 
18544ac7516bSRavi Kumar 	switch (phy_data->port_mode) {
18554ac7516bSRavi Kumar 	case AXGBE_PORT_MODE_BACKPLANE:
1856443ab5aaSSelwin Sebastian 	case AXGBE_PORT_MODE_BACKPLANE_NO_AUTONEG:
18574ac7516bSRavi Kumar 		if ((phy_data->port_speeds & AXGBE_PHY_PORT_SPEED_1000) ||
18584ac7516bSRavi Kumar 		    (phy_data->port_speeds & AXGBE_PHY_PORT_SPEED_10000))
18594ac7516bSRavi Kumar 			return false;
18604ac7516bSRavi Kumar 		break;
18614ac7516bSRavi Kumar 	case AXGBE_PORT_MODE_BACKPLANE_2500:
18624ac7516bSRavi Kumar 		if (phy_data->port_speeds & AXGBE_PHY_PORT_SPEED_2500)
18634ac7516bSRavi Kumar 			return false;
18644ac7516bSRavi Kumar 		break;
18654ac7516bSRavi Kumar 	case AXGBE_PORT_MODE_1000BASE_T:
1866*1f9d2d3aSVenkat Kumar Ande 		if ((phy_data->port_speeds & AXGBE_PHY_PORT_SPEED_10)  ||
1867*1f9d2d3aSVenkat Kumar Ande 			(phy_data->port_speeds & AXGBE_PHY_PORT_SPEED_100) ||
18684ac7516bSRavi Kumar 		    (phy_data->port_speeds & AXGBE_PHY_PORT_SPEED_1000))
18694ac7516bSRavi Kumar 			return false;
18704ac7516bSRavi Kumar 		break;
18714ac7516bSRavi Kumar 	case AXGBE_PORT_MODE_1000BASE_X:
18724ac7516bSRavi Kumar 		if (phy_data->port_speeds & AXGBE_PHY_PORT_SPEED_1000)
18734ac7516bSRavi Kumar 			return false;
18744ac7516bSRavi Kumar 		break;
18754ac7516bSRavi Kumar 	case AXGBE_PORT_MODE_NBASE_T:
1876*1f9d2d3aSVenkat Kumar Ande 		if ((phy_data->port_speeds & AXGBE_PHY_PORT_SPEED_10)  ||
1877*1f9d2d3aSVenkat Kumar Ande 			(phy_data->port_speeds & AXGBE_PHY_PORT_SPEED_100) ||
18784ac7516bSRavi Kumar 		    (phy_data->port_speeds & AXGBE_PHY_PORT_SPEED_1000) ||
18794ac7516bSRavi Kumar 		    (phy_data->port_speeds & AXGBE_PHY_PORT_SPEED_2500))
18804ac7516bSRavi Kumar 			return false;
18814ac7516bSRavi Kumar 		break;
18824ac7516bSRavi Kumar 	case AXGBE_PORT_MODE_10GBASE_T:
1883*1f9d2d3aSVenkat Kumar Ande 		if ((phy_data->port_speeds & AXGBE_PHY_PORT_SPEED_10)  ||
1884*1f9d2d3aSVenkat Kumar Ande 		    (phy_data->port_speeds & AXGBE_PHY_PORT_SPEED_100) ||
18854ac7516bSRavi Kumar 		    (phy_data->port_speeds & AXGBE_PHY_PORT_SPEED_1000) ||
18864ac7516bSRavi Kumar 		    (phy_data->port_speeds & AXGBE_PHY_PORT_SPEED_10000))
18874ac7516bSRavi Kumar 			return false;
18884ac7516bSRavi Kumar 		break;
18894ac7516bSRavi Kumar 	case AXGBE_PORT_MODE_10GBASE_R:
18904ac7516bSRavi Kumar 		if (phy_data->port_speeds & AXGBE_PHY_PORT_SPEED_10000)
18914ac7516bSRavi Kumar 			return false;
18924ac7516bSRavi Kumar 		break;
18934ac7516bSRavi Kumar 	case AXGBE_PORT_MODE_SFP:
1894*1f9d2d3aSVenkat Kumar Ande 		if ((phy_data->port_speeds & AXGBE_PHY_PORT_SPEED_10)  ||
1895*1f9d2d3aSVenkat Kumar Ande 			(phy_data->port_speeds & AXGBE_PHY_PORT_SPEED_100) ||
18964ac7516bSRavi Kumar 		    (phy_data->port_speeds & AXGBE_PHY_PORT_SPEED_1000) ||
18974ac7516bSRavi Kumar 		    (phy_data->port_speeds & AXGBE_PHY_PORT_SPEED_10000))
18984ac7516bSRavi Kumar 			return false;
18994ac7516bSRavi Kumar 		break;
19004ac7516bSRavi Kumar 	default:
19014ac7516bSRavi Kumar 		break;
19024ac7516bSRavi Kumar 	}
19034ac7516bSRavi Kumar 
19044ac7516bSRavi Kumar 	return true;
19054ac7516bSRavi Kumar }
19064ac7516bSRavi Kumar 
19074ac7516bSRavi Kumar static bool axgbe_phy_conn_type_mismatch(struct axgbe_port *pdata)
19084ac7516bSRavi Kumar {
19094ac7516bSRavi Kumar 	struct axgbe_phy_data *phy_data = pdata->phy_data;
19104ac7516bSRavi Kumar 
19114ac7516bSRavi Kumar 	switch (phy_data->port_mode) {
19124ac7516bSRavi Kumar 	case AXGBE_PORT_MODE_BACKPLANE:
1913443ab5aaSSelwin Sebastian 	case AXGBE_PORT_MODE_BACKPLANE_NO_AUTONEG:
19144ac7516bSRavi Kumar 	case AXGBE_PORT_MODE_BACKPLANE_2500:
19154ac7516bSRavi Kumar 		if (phy_data->conn_type == AXGBE_CONN_TYPE_BACKPLANE)
19164ac7516bSRavi Kumar 			return false;
19174ac7516bSRavi Kumar 		break;
19184ac7516bSRavi Kumar 	case AXGBE_PORT_MODE_1000BASE_T:
19194ac7516bSRavi Kumar 	case AXGBE_PORT_MODE_1000BASE_X:
19204ac7516bSRavi Kumar 	case AXGBE_PORT_MODE_NBASE_T:
19214ac7516bSRavi Kumar 	case AXGBE_PORT_MODE_10GBASE_T:
19224ac7516bSRavi Kumar 	case AXGBE_PORT_MODE_10GBASE_R:
19234ac7516bSRavi Kumar 		if (phy_data->conn_type == AXGBE_CONN_TYPE_MDIO)
19244ac7516bSRavi Kumar 			return false;
19254ac7516bSRavi Kumar 		break;
19264ac7516bSRavi Kumar 	case AXGBE_PORT_MODE_SFP:
19274ac7516bSRavi Kumar 		if (phy_data->conn_type == AXGBE_CONN_TYPE_SFP)
19284ac7516bSRavi Kumar 			return false;
19294ac7516bSRavi Kumar 		break;
19304ac7516bSRavi Kumar 	default:
19314ac7516bSRavi Kumar 		break;
19324ac7516bSRavi Kumar 	}
19334ac7516bSRavi Kumar 
19344ac7516bSRavi Kumar 	return true;
19354ac7516bSRavi Kumar }
19364ac7516bSRavi Kumar 
19374ac7516bSRavi Kumar static bool axgbe_phy_port_enabled(struct axgbe_port *pdata)
19384ac7516bSRavi Kumar {
1939a3ec01b4SVenkat Kumar Ande 	if (!XP_GET_BITS(pdata->pp0, XP_PROP_0, PORT_SPEEDS))
19404ac7516bSRavi Kumar 		return false;
1941a3ec01b4SVenkat Kumar Ande 	if (!XP_GET_BITS(pdata->pp0, XP_PROP_0, CONN_TYPE))
19424ac7516bSRavi Kumar 		return false;
19434ac7516bSRavi Kumar 
19444ac7516bSRavi Kumar 	return true;
19454ac7516bSRavi Kumar }
19464ac7516bSRavi Kumar 
194700072056SRavi Kumar static void axgbe_phy_cdr_track(struct axgbe_port *pdata)
194800072056SRavi Kumar {
194900072056SRavi Kumar 	struct axgbe_phy_data *phy_data = pdata->phy_data;
195000072056SRavi Kumar 
195100072056SRavi Kumar 	if (!pdata->vdata->an_cdr_workaround)
195200072056SRavi Kumar 		return;
195300072056SRavi Kumar 
195400072056SRavi Kumar 	if (!phy_data->phy_cdr_notrack)
195500072056SRavi Kumar 		return;
195600072056SRavi Kumar 
195700072056SRavi Kumar 	rte_delay_us(phy_data->phy_cdr_delay + 400);
195800072056SRavi Kumar 
195900072056SRavi Kumar 	XMDIO_WRITE_BITS(pdata, MDIO_MMD_PMAPMD, MDIO_VEND2_PMA_CDR_CONTROL,
196000072056SRavi Kumar 			 AXGBE_PMA_CDR_TRACK_EN_MASK,
196100072056SRavi Kumar 			 AXGBE_PMA_CDR_TRACK_EN_ON);
196200072056SRavi Kumar 
196300072056SRavi Kumar 	phy_data->phy_cdr_notrack = 0;
196400072056SRavi Kumar }
196500072056SRavi Kumar 
196600072056SRavi Kumar static void axgbe_phy_cdr_notrack(struct axgbe_port *pdata)
196700072056SRavi Kumar {
196800072056SRavi Kumar 	struct axgbe_phy_data *phy_data = pdata->phy_data;
196900072056SRavi Kumar 
197000072056SRavi Kumar 	if (!pdata->vdata->an_cdr_workaround)
197100072056SRavi Kumar 		return;
197200072056SRavi Kumar 
197300072056SRavi Kumar 	if (phy_data->phy_cdr_notrack)
197400072056SRavi Kumar 		return;
197500072056SRavi Kumar 
197600072056SRavi Kumar 	XMDIO_WRITE_BITS(pdata, MDIO_MMD_PMAPMD, MDIO_VEND2_PMA_CDR_CONTROL,
197700072056SRavi Kumar 			 AXGBE_PMA_CDR_TRACK_EN_MASK,
197800072056SRavi Kumar 			 AXGBE_PMA_CDR_TRACK_EN_OFF);
197900072056SRavi Kumar 
198000072056SRavi Kumar 	axgbe_phy_rrc(pdata);
198100072056SRavi Kumar 
198200072056SRavi Kumar 	phy_data->phy_cdr_notrack = 1;
198300072056SRavi Kumar }
198400072056SRavi Kumar 
198500072056SRavi Kumar static void axgbe_phy_kr_training_post(struct axgbe_port *pdata)
198600072056SRavi Kumar {
198700072056SRavi Kumar 	if (!pdata->cdr_track_early)
198800072056SRavi Kumar 		axgbe_phy_cdr_track(pdata);
198900072056SRavi Kumar }
199000072056SRavi Kumar 
199100072056SRavi Kumar static void axgbe_phy_kr_training_pre(struct axgbe_port *pdata)
199200072056SRavi Kumar {
199300072056SRavi Kumar 	if (pdata->cdr_track_early)
199400072056SRavi Kumar 		axgbe_phy_cdr_track(pdata);
199500072056SRavi Kumar }
199600072056SRavi Kumar 
199700072056SRavi Kumar static void axgbe_phy_an_post(struct axgbe_port *pdata)
199800072056SRavi Kumar {
199900072056SRavi Kumar 	struct axgbe_phy_data *phy_data = pdata->phy_data;
200000072056SRavi Kumar 
200100072056SRavi Kumar 	switch (pdata->an_mode) {
200200072056SRavi Kumar 	case AXGBE_AN_MODE_CL73:
200300072056SRavi Kumar 	case AXGBE_AN_MODE_CL73_REDRV:
200400072056SRavi Kumar 		if (phy_data->cur_mode != AXGBE_MODE_KR)
200500072056SRavi Kumar 			break;
200600072056SRavi Kumar 
200700072056SRavi Kumar 		axgbe_phy_cdr_track(pdata);
200800072056SRavi Kumar 
200900072056SRavi Kumar 		switch (pdata->an_result) {
201000072056SRavi Kumar 		case AXGBE_AN_READY:
201100072056SRavi Kumar 		case AXGBE_AN_COMPLETE:
201200072056SRavi Kumar 			break;
201300072056SRavi Kumar 		default:
201400072056SRavi Kumar 			if (phy_data->phy_cdr_delay < AXGBE_CDR_DELAY_MAX)
201500072056SRavi Kumar 				phy_data->phy_cdr_delay += AXGBE_CDR_DELAY_INC;
201600072056SRavi Kumar 			break;
201700072056SRavi Kumar 		}
201800072056SRavi Kumar 		break;
201900072056SRavi Kumar 	default:
202000072056SRavi Kumar 		break;
202100072056SRavi Kumar 	}
202200072056SRavi Kumar }
202300072056SRavi Kumar 
202400072056SRavi Kumar static void axgbe_phy_an_pre(struct axgbe_port *pdata)
202500072056SRavi Kumar {
202600072056SRavi Kumar 	struct axgbe_phy_data *phy_data = pdata->phy_data;
202700072056SRavi Kumar 
202800072056SRavi Kumar 	switch (pdata->an_mode) {
202900072056SRavi Kumar 	case AXGBE_AN_MODE_CL73:
203000072056SRavi Kumar 	case AXGBE_AN_MODE_CL73_REDRV:
203100072056SRavi Kumar 		if (phy_data->cur_mode != AXGBE_MODE_KR)
203200072056SRavi Kumar 			break;
203300072056SRavi Kumar 
203400072056SRavi Kumar 		axgbe_phy_cdr_notrack(pdata);
203500072056SRavi Kumar 		break;
203600072056SRavi Kumar 	default:
203700072056SRavi Kumar 		break;
203800072056SRavi Kumar 	}
203900072056SRavi Kumar }
204000072056SRavi Kumar 
2041a5c72737SRavi Kumar static void axgbe_phy_stop(struct axgbe_port *pdata)
2042a5c72737SRavi Kumar {
2043a5c72737SRavi Kumar 	struct axgbe_phy_data *phy_data = pdata->phy_data;
2044a5c72737SRavi Kumar 
2045a5c72737SRavi Kumar 	/* Reset SFP data */
2046a5c72737SRavi Kumar 	axgbe_phy_sfp_reset(phy_data);
2047a5c72737SRavi Kumar 	axgbe_phy_sfp_mod_absent(pdata);
2048a5c72737SRavi Kumar 
204900072056SRavi Kumar 	/* Reset CDR support */
205000072056SRavi Kumar 	axgbe_phy_cdr_track(pdata);
205100072056SRavi Kumar 
2052a5c72737SRavi Kumar 	/* Power off the PHY */
2053a5c72737SRavi Kumar 	axgbe_phy_power_off(pdata);
2054a5c72737SRavi Kumar 
2055a5c72737SRavi Kumar 	/* Stop the I2C controller */
2056a5c72737SRavi Kumar 	pdata->i2c_if.i2c_stop(pdata);
2057a5c72737SRavi Kumar }
2058a5c72737SRavi Kumar 
2059a5c72737SRavi Kumar static int axgbe_phy_start(struct axgbe_port *pdata)
2060a5c72737SRavi Kumar {
2061a5c72737SRavi Kumar 	struct axgbe_phy_data *phy_data = pdata->phy_data;
2062a5c72737SRavi Kumar 	int ret;
2063a5c72737SRavi Kumar 
2064a5c72737SRavi Kumar 	/* Start the I2C controller */
2065a5c72737SRavi Kumar 	ret = pdata->i2c_if.i2c_start(pdata);
2066a5c72737SRavi Kumar 	if (ret)
2067a5c72737SRavi Kumar 		return ret;
2068a5c72737SRavi Kumar 
2069a5c72737SRavi Kumar 	/* Start in highest supported mode */
2070a5c72737SRavi Kumar 	axgbe_phy_set_mode(pdata, phy_data->start_mode);
2071a5c72737SRavi Kumar 
207200072056SRavi Kumar 	/* Reset CDR support */
207300072056SRavi Kumar 	axgbe_phy_cdr_track(pdata);
207400072056SRavi Kumar 
2075a5c72737SRavi Kumar 	/* After starting the I2C controller, we can check for an SFP */
2076a5c72737SRavi Kumar 	switch (phy_data->port_mode) {
2077a5c72737SRavi Kumar 	case AXGBE_PORT_MODE_SFP:
2078a5c72737SRavi Kumar 		axgbe_phy_sfp_detect(pdata);
2079a5c72737SRavi Kumar 		break;
2080a5c72737SRavi Kumar 	default:
2081a5c72737SRavi Kumar 		break;
2082a5c72737SRavi Kumar 	}
2083102b6ec3SGirish Nandibasappa 	pdata->phy.advertising &= axgbe_phy_an_advertising(pdata);
2084a5c72737SRavi Kumar 
2085a5c72737SRavi Kumar 	return ret;
2086a5c72737SRavi Kumar }
2087a5c72737SRavi Kumar 
2088a5c72737SRavi Kumar static int axgbe_phy_reset(struct axgbe_port *pdata)
2089a5c72737SRavi Kumar {
2090a5c72737SRavi Kumar 	struct axgbe_phy_data *phy_data = pdata->phy_data;
2091a5c72737SRavi Kumar 	enum axgbe_mode cur_mode;
2092a5c72737SRavi Kumar 
2093a5c72737SRavi Kumar 	/* Reset by power cycling the PHY */
2094a5c72737SRavi Kumar 	cur_mode = phy_data->cur_mode;
2095a5c72737SRavi Kumar 	axgbe_phy_power_off(pdata);
2096a5c72737SRavi Kumar 	/* First time reset is done with passed unknown mode*/
2097a5c72737SRavi Kumar 	axgbe_phy_set_mode(pdata, cur_mode);
2098a5c72737SRavi Kumar 	return 0;
2099a5c72737SRavi Kumar }
2100a5c72737SRavi Kumar 
21014ac7516bSRavi Kumar static int axgbe_phy_init(struct axgbe_port *pdata)
21024ac7516bSRavi Kumar {
21034ac7516bSRavi Kumar 	struct axgbe_phy_data *phy_data;
21044ac7516bSRavi Kumar 	int ret;
21054ac7516bSRavi Kumar 
21064ac7516bSRavi Kumar 	/* Check if enabled */
21074ac7516bSRavi Kumar 	if (!axgbe_phy_port_enabled(pdata)) {
21084ac7516bSRavi Kumar 		PMD_DRV_LOG(ERR, "device is not enabled\n");
21094ac7516bSRavi Kumar 		return -ENODEV;
21104ac7516bSRavi Kumar 	}
21114ac7516bSRavi Kumar 
21124ac7516bSRavi Kumar 	/* Initialize the I2C controller */
21134ac7516bSRavi Kumar 	ret = pdata->i2c_if.i2c_init(pdata);
21144ac7516bSRavi Kumar 	if (ret)
21154ac7516bSRavi Kumar 		return ret;
21164ac7516bSRavi Kumar 
21174ac7516bSRavi Kumar 	phy_data = rte_zmalloc("phy_data memory", sizeof(*phy_data), 0);
21184ac7516bSRavi Kumar 	if (!phy_data) {
21194ac7516bSRavi Kumar 		PMD_DRV_LOG(ERR, "phy_data allocation failed\n");
21204ac7516bSRavi Kumar 		return -ENOMEM;
21214ac7516bSRavi Kumar 	}
21224ac7516bSRavi Kumar 	pdata->phy_data = phy_data;
21234ac7516bSRavi Kumar 
2124a3ec01b4SVenkat Kumar Ande 	phy_data->port_mode = XP_GET_BITS(pdata->pp0, XP_PROP_0, PORT_MODE);
2125a3ec01b4SVenkat Kumar Ande 	phy_data->port_id = XP_GET_BITS(pdata->pp0, XP_PROP_0, PORT_ID);
2126a3ec01b4SVenkat Kumar Ande 	phy_data->port_speeds = XP_GET_BITS(pdata->pp0, XP_PROP_0, PORT_SPEEDS);
2127a3ec01b4SVenkat Kumar Ande 	phy_data->conn_type = XP_GET_BITS(pdata->pp0, XP_PROP_0, CONN_TYPE);
2128a3ec01b4SVenkat Kumar Ande 	phy_data->mdio_addr = XP_GET_BITS(pdata->pp0, XP_PROP_0, MDIO_ADDR);
21294ac7516bSRavi Kumar 
2130a3ec01b4SVenkat Kumar Ande 	phy_data->redrv = XP_GET_BITS(pdata->pp4, XP_PROP_4, REDRV_PRESENT);
2131a3ec01b4SVenkat Kumar Ande 	phy_data->redrv_if = XP_GET_BITS(pdata->pp4, XP_PROP_4, REDRV_IF);
2132a3ec01b4SVenkat Kumar Ande 	phy_data->redrv_addr = XP_GET_BITS(pdata->pp4, XP_PROP_4, REDRV_ADDR);
2133a3ec01b4SVenkat Kumar Ande 	phy_data->redrv_lane = XP_GET_BITS(pdata->pp4, XP_PROP_4, REDRV_LANE);
2134a3ec01b4SVenkat Kumar Ande 	phy_data->redrv_model = XP_GET_BITS(pdata->pp4, XP_PROP_4, REDRV_MODEL);
21354ac7516bSRavi Kumar 
21364ac7516bSRavi Kumar 	/* Validate the connection requested */
21374ac7516bSRavi Kumar 	if (axgbe_phy_conn_type_mismatch(pdata)) {
21384ac7516bSRavi Kumar 		PMD_DRV_LOG(ERR, "phy mode/connection mismatch (%#x/%#x)\n",
21394ac7516bSRavi Kumar 			    phy_data->port_mode, phy_data->conn_type);
21404ac7516bSRavi Kumar 		return -EINVAL;
21414ac7516bSRavi Kumar 	}
21424ac7516bSRavi Kumar 
21434ac7516bSRavi Kumar 	/* Validate the mode requested */
21444ac7516bSRavi Kumar 	if (axgbe_phy_port_mode_mismatch(pdata)) {
21454ac7516bSRavi Kumar 		PMD_DRV_LOG(ERR, "phy mode/speed mismatch (%#x/%#x)\n",
21464ac7516bSRavi Kumar 			    phy_data->port_mode, phy_data->port_speeds);
21474ac7516bSRavi Kumar 		return -EINVAL;
21484ac7516bSRavi Kumar 	}
21494ac7516bSRavi Kumar 
21504ac7516bSRavi Kumar 	/* Check for and validate MDIO reset support */
21514ac7516bSRavi Kumar 	ret = axgbe_phy_mdio_reset_setup(pdata);
21524ac7516bSRavi Kumar 	if (ret)
21534ac7516bSRavi Kumar 		return ret;
21544ac7516bSRavi Kumar 
21554ac7516bSRavi Kumar 	/* Validate the re-driver information */
21564ac7516bSRavi Kumar 	if (axgbe_phy_redrv_error(phy_data)) {
21574ac7516bSRavi Kumar 		PMD_DRV_LOG(ERR, "phy re-driver settings error\n");
21584ac7516bSRavi Kumar 		return -EINVAL;
21594ac7516bSRavi Kumar 	}
21604ac7516bSRavi Kumar 	pdata->kr_redrv = phy_data->redrv;
21614ac7516bSRavi Kumar 
21624ac7516bSRavi Kumar 	/* Indicate current mode is unknown */
21634ac7516bSRavi Kumar 	phy_data->cur_mode = AXGBE_MODE_UNKNOWN;
21644ac7516bSRavi Kumar 
21654ac7516bSRavi Kumar 	/* Initialize supported features */
21664ac7516bSRavi Kumar 	pdata->phy.supported = 0;
21674ac7516bSRavi Kumar 
21684ac7516bSRavi Kumar 	switch (phy_data->port_mode) {
21694ac7516bSRavi Kumar 		/* Backplane support */
21704ac7516bSRavi Kumar 	case AXGBE_PORT_MODE_BACKPLANE:
21714ac7516bSRavi Kumar 		pdata->phy.supported |= SUPPORTED_Autoneg;
2172443ab5aaSSelwin Sebastian 		/* Fallthrough */
2173443ab5aaSSelwin Sebastian 	case AXGBE_PORT_MODE_BACKPLANE_NO_AUTONEG:
21744ac7516bSRavi Kumar 		pdata->phy.supported |= SUPPORTED_Pause | SUPPORTED_Asym_Pause;
21754ac7516bSRavi Kumar 		pdata->phy.supported |= SUPPORTED_Backplane;
21764ac7516bSRavi Kumar 		if (phy_data->port_speeds & AXGBE_PHY_PORT_SPEED_1000) {
21774ac7516bSRavi Kumar 			pdata->phy.supported |= SUPPORTED_1000baseKX_Full;
21784ac7516bSRavi Kumar 			phy_data->start_mode = AXGBE_MODE_KX_1000;
21794ac7516bSRavi Kumar 		}
21804ac7516bSRavi Kumar 		if (phy_data->port_speeds & AXGBE_PHY_PORT_SPEED_10000) {
21814ac7516bSRavi Kumar 			pdata->phy.supported |= SUPPORTED_10000baseKR_Full;
21824ac7516bSRavi Kumar 			if (pdata->fec_ability & MDIO_PMA_10GBR_FECABLE_ABLE)
21834ac7516bSRavi Kumar 				pdata->phy.supported |=
21844ac7516bSRavi Kumar 					SUPPORTED_10000baseR_FEC;
21854ac7516bSRavi Kumar 			phy_data->start_mode = AXGBE_MODE_KR;
21864ac7516bSRavi Kumar 		}
21874ac7516bSRavi Kumar 
21884ac7516bSRavi Kumar 		phy_data->phydev_mode = AXGBE_MDIO_MODE_NONE;
21894ac7516bSRavi Kumar 		break;
21904ac7516bSRavi Kumar 	case AXGBE_PORT_MODE_BACKPLANE_2500:
21914ac7516bSRavi Kumar 		pdata->phy.supported |= SUPPORTED_Pause | SUPPORTED_Asym_Pause;
21924ac7516bSRavi Kumar 		pdata->phy.supported |= SUPPORTED_Backplane;
21934ac7516bSRavi Kumar 		pdata->phy.supported |= SUPPORTED_2500baseX_Full;
21944ac7516bSRavi Kumar 		phy_data->start_mode = AXGBE_MODE_KX_2500;
21954ac7516bSRavi Kumar 
21964ac7516bSRavi Kumar 		phy_data->phydev_mode = AXGBE_MDIO_MODE_NONE;
21974ac7516bSRavi Kumar 		break;
21984ac7516bSRavi Kumar 
21994ac7516bSRavi Kumar 		/* MDIO 1GBase-T support */
22004ac7516bSRavi Kumar 	case AXGBE_PORT_MODE_1000BASE_T:
22014ac7516bSRavi Kumar 		pdata->phy.supported |= SUPPORTED_Autoneg;
22024ac7516bSRavi Kumar 		pdata->phy.supported |= SUPPORTED_Pause | SUPPORTED_Asym_Pause;
22034ac7516bSRavi Kumar 		pdata->phy.supported |= SUPPORTED_TP;
2204*1f9d2d3aSVenkat Kumar Ande 		if (phy_data->port_speeds & AXGBE_PHY_PORT_SPEED_10) {
2205*1f9d2d3aSVenkat Kumar Ande 			pdata->phy.supported |= SUPPORTED_10baseT_Full;
2206*1f9d2d3aSVenkat Kumar Ande 			phy_data->start_mode = AXGBE_MODE_SGMII_10;
2207*1f9d2d3aSVenkat Kumar Ande 		}
22084ac7516bSRavi Kumar 		if (phy_data->port_speeds & AXGBE_PHY_PORT_SPEED_100) {
22094ac7516bSRavi Kumar 			pdata->phy.supported |= SUPPORTED_100baseT_Full;
22104ac7516bSRavi Kumar 			phy_data->start_mode = AXGBE_MODE_SGMII_100;
22114ac7516bSRavi Kumar 		}
22124ac7516bSRavi Kumar 		if (phy_data->port_speeds & AXGBE_PHY_PORT_SPEED_1000) {
22134ac7516bSRavi Kumar 			pdata->phy.supported |= SUPPORTED_1000baseT_Full;
22144ac7516bSRavi Kumar 			phy_data->start_mode = AXGBE_MODE_SGMII_1000;
22154ac7516bSRavi Kumar 		}
22164ac7516bSRavi Kumar 
22174ac7516bSRavi Kumar 		phy_data->phydev_mode = AXGBE_MDIO_MODE_CL22;
22184ac7516bSRavi Kumar 		break;
22194ac7516bSRavi Kumar 
22204ac7516bSRavi Kumar 		/* MDIO Base-X support */
22214ac7516bSRavi Kumar 	case AXGBE_PORT_MODE_1000BASE_X:
22224ac7516bSRavi Kumar 		pdata->phy.supported |= SUPPORTED_Autoneg;
22234ac7516bSRavi Kumar 		pdata->phy.supported |= SUPPORTED_Pause | SUPPORTED_Asym_Pause;
22244ac7516bSRavi Kumar 		pdata->phy.supported |= SUPPORTED_FIBRE;
22254ac7516bSRavi Kumar 		pdata->phy.supported |= SUPPORTED_1000baseT_Full;
22264ac7516bSRavi Kumar 		phy_data->start_mode = AXGBE_MODE_X;
22274ac7516bSRavi Kumar 
22284ac7516bSRavi Kumar 		phy_data->phydev_mode = AXGBE_MDIO_MODE_CL22;
22294ac7516bSRavi Kumar 		break;
22304ac7516bSRavi Kumar 
22314ac7516bSRavi Kumar 		/* MDIO NBase-T support */
22324ac7516bSRavi Kumar 	case AXGBE_PORT_MODE_NBASE_T:
22334ac7516bSRavi Kumar 		pdata->phy.supported |= SUPPORTED_Autoneg;
22344ac7516bSRavi Kumar 		pdata->phy.supported |= SUPPORTED_Pause | SUPPORTED_Asym_Pause;
22354ac7516bSRavi Kumar 		pdata->phy.supported |= SUPPORTED_TP;
2236*1f9d2d3aSVenkat Kumar Ande 		if (phy_data->port_speeds & AXGBE_PHY_PORT_SPEED_10) {
2237*1f9d2d3aSVenkat Kumar Ande 			pdata->phy.supported |= SUPPORTED_10baseT_Full;
2238*1f9d2d3aSVenkat Kumar Ande 			phy_data->start_mode = AXGBE_MODE_SGMII_10;
2239*1f9d2d3aSVenkat Kumar Ande 		}
22404ac7516bSRavi Kumar 		if (phy_data->port_speeds & AXGBE_PHY_PORT_SPEED_100) {
22414ac7516bSRavi Kumar 			pdata->phy.supported |= SUPPORTED_100baseT_Full;
22424ac7516bSRavi Kumar 			phy_data->start_mode = AXGBE_MODE_SGMII_100;
22434ac7516bSRavi Kumar 		}
22444ac7516bSRavi Kumar 		if (phy_data->port_speeds & AXGBE_PHY_PORT_SPEED_1000) {
22454ac7516bSRavi Kumar 			pdata->phy.supported |= SUPPORTED_1000baseT_Full;
22464ac7516bSRavi Kumar 			phy_data->start_mode = AXGBE_MODE_SGMII_1000;
22474ac7516bSRavi Kumar 		}
22484ac7516bSRavi Kumar 		if (phy_data->port_speeds & AXGBE_PHY_PORT_SPEED_2500) {
22494ac7516bSRavi Kumar 			pdata->phy.supported |= SUPPORTED_2500baseX_Full;
22504ac7516bSRavi Kumar 			phy_data->start_mode = AXGBE_MODE_KX_2500;
22514ac7516bSRavi Kumar 		}
22524ac7516bSRavi Kumar 
22534ac7516bSRavi Kumar 		phy_data->phydev_mode = AXGBE_MDIO_MODE_CL45;
22544ac7516bSRavi Kumar 		break;
22554ac7516bSRavi Kumar 
22564ac7516bSRavi Kumar 		/* 10GBase-T support */
22574ac7516bSRavi Kumar 	case AXGBE_PORT_MODE_10GBASE_T:
22584ac7516bSRavi Kumar 		pdata->phy.supported |= SUPPORTED_Autoneg;
22594ac7516bSRavi Kumar 		pdata->phy.supported |= SUPPORTED_Pause | SUPPORTED_Asym_Pause;
22604ac7516bSRavi Kumar 		pdata->phy.supported |= SUPPORTED_TP;
2261*1f9d2d3aSVenkat Kumar Ande 		if (phy_data->port_speeds & AXGBE_PHY_PORT_SPEED_10) {
2262*1f9d2d3aSVenkat Kumar Ande 			pdata->phy.supported |= SUPPORTED_10baseT_Full;
2263*1f9d2d3aSVenkat Kumar Ande 			phy_data->start_mode = AXGBE_MODE_SGMII_10;
2264*1f9d2d3aSVenkat Kumar Ande 		}
22654ac7516bSRavi Kumar 		if (phy_data->port_speeds & AXGBE_PHY_PORT_SPEED_100) {
22664ac7516bSRavi Kumar 			pdata->phy.supported |= SUPPORTED_100baseT_Full;
22674ac7516bSRavi Kumar 			phy_data->start_mode = AXGBE_MODE_SGMII_100;
22684ac7516bSRavi Kumar 		}
22694ac7516bSRavi Kumar 		if (phy_data->port_speeds & AXGBE_PHY_PORT_SPEED_1000) {
22704ac7516bSRavi Kumar 			pdata->phy.supported |= SUPPORTED_1000baseT_Full;
22714ac7516bSRavi Kumar 			phy_data->start_mode = AXGBE_MODE_SGMII_1000;
22724ac7516bSRavi Kumar 		}
22734ac7516bSRavi Kumar 		if (phy_data->port_speeds & AXGBE_PHY_PORT_SPEED_10000) {
22744ac7516bSRavi Kumar 			pdata->phy.supported |= SUPPORTED_10000baseT_Full;
22754ac7516bSRavi Kumar 			phy_data->start_mode = AXGBE_MODE_KR;
22764ac7516bSRavi Kumar 		}
22774ac7516bSRavi Kumar 
22784ac7516bSRavi Kumar 		phy_data->phydev_mode = AXGBE_MDIO_MODE_NONE;
22794ac7516bSRavi Kumar 		break;
22804ac7516bSRavi Kumar 
22814ac7516bSRavi Kumar 		/* 10GBase-R support */
22824ac7516bSRavi Kumar 	case AXGBE_PORT_MODE_10GBASE_R:
22834ac7516bSRavi Kumar 		pdata->phy.supported |= SUPPORTED_Autoneg;
22844ac7516bSRavi Kumar 		pdata->phy.supported |= SUPPORTED_Pause | SUPPORTED_Asym_Pause;
22854ac7516bSRavi Kumar 		pdata->phy.supported |= SUPPORTED_TP;
22864ac7516bSRavi Kumar 		pdata->phy.supported |= SUPPORTED_10000baseT_Full;
22874ac7516bSRavi Kumar 		if (pdata->fec_ability & MDIO_PMA_10GBR_FECABLE_ABLE)
22884ac7516bSRavi Kumar 			pdata->phy.supported |= SUPPORTED_10000baseR_FEC;
22894ac7516bSRavi Kumar 		phy_data->start_mode = AXGBE_MODE_SFI;
22904ac7516bSRavi Kumar 
22914ac7516bSRavi Kumar 		phy_data->phydev_mode = AXGBE_MDIO_MODE_NONE;
22924ac7516bSRavi Kumar 		break;
22934ac7516bSRavi Kumar 
22944ac7516bSRavi Kumar 		/* SFP support */
22954ac7516bSRavi Kumar 	case AXGBE_PORT_MODE_SFP:
22964ac7516bSRavi Kumar 		pdata->phy.supported |= SUPPORTED_Autoneg;
22974ac7516bSRavi Kumar 		pdata->phy.supported |= SUPPORTED_Pause | SUPPORTED_Asym_Pause;
22984ac7516bSRavi Kumar 		pdata->phy.supported |= SUPPORTED_TP;
22994ac7516bSRavi Kumar 		pdata->phy.supported |= SUPPORTED_FIBRE;
2300*1f9d2d3aSVenkat Kumar Ande 		if (phy_data->port_speeds & AXGBE_PHY_PORT_SPEED_10) {
2301*1f9d2d3aSVenkat Kumar Ande 			pdata->phy.supported |= SUPPORTED_10baseT_Full;
2302*1f9d2d3aSVenkat Kumar Ande 			phy_data->start_mode = AXGBE_MODE_SGMII_10;
2303*1f9d2d3aSVenkat Kumar Ande 		}
23044ac7516bSRavi Kumar 		if (phy_data->port_speeds & AXGBE_PHY_PORT_SPEED_100) {
23054ac7516bSRavi Kumar 			pdata->phy.supported |= SUPPORTED_100baseT_Full;
23064ac7516bSRavi Kumar 			phy_data->start_mode = AXGBE_MODE_SGMII_100;
23074ac7516bSRavi Kumar 		}
23084ac7516bSRavi Kumar 		if (phy_data->port_speeds & AXGBE_PHY_PORT_SPEED_1000) {
23094ac7516bSRavi Kumar 			pdata->phy.supported |= SUPPORTED_1000baseT_Full;
23104ac7516bSRavi Kumar 			phy_data->start_mode = AXGBE_MODE_SGMII_1000;
23114ac7516bSRavi Kumar 		}
23124ac7516bSRavi Kumar 		if (phy_data->port_speeds & AXGBE_PHY_PORT_SPEED_10000) {
23134ac7516bSRavi Kumar 			pdata->phy.supported |= SUPPORTED_10000baseT_Full;
23144ac7516bSRavi Kumar 			phy_data->start_mode = AXGBE_MODE_SFI;
23154ac7516bSRavi Kumar 			if (pdata->fec_ability & MDIO_PMA_10GBR_FECABLE_ABLE)
23164ac7516bSRavi Kumar 				pdata->phy.supported |=
23174ac7516bSRavi Kumar 					SUPPORTED_10000baseR_FEC;
23184ac7516bSRavi Kumar 		}
23194ac7516bSRavi Kumar 
23204ac7516bSRavi Kumar 		phy_data->phydev_mode = AXGBE_MDIO_MODE_CL22;
23214ac7516bSRavi Kumar 
23224ac7516bSRavi Kumar 		axgbe_phy_sfp_setup(pdata);
23234ac7516bSRavi Kumar 		break;
23244ac7516bSRavi Kumar 	default:
23254ac7516bSRavi Kumar 		return -EINVAL;
23264ac7516bSRavi Kumar 	}
23274ac7516bSRavi Kumar 
23284ac7516bSRavi Kumar 	if ((phy_data->conn_type & AXGBE_CONN_TYPE_MDIO) &&
23294ac7516bSRavi Kumar 	    (phy_data->phydev_mode != AXGBE_MDIO_MODE_NONE)) {
23304ac7516bSRavi Kumar 		ret = pdata->hw_if.set_ext_mii_mode(pdata, phy_data->mdio_addr,
23314ac7516bSRavi Kumar 						    phy_data->phydev_mode);
23324ac7516bSRavi Kumar 		if (ret) {
23334ac7516bSRavi Kumar 			PMD_DRV_LOG(ERR, "mdio port/clause not compatible (%d/%u)\n",
23344ac7516bSRavi Kumar 				    phy_data->mdio_addr, phy_data->phydev_mode);
23354ac7516bSRavi Kumar 			return -EINVAL;
23364ac7516bSRavi Kumar 		}
23374ac7516bSRavi Kumar 	}
23384ac7516bSRavi Kumar 
23394ac7516bSRavi Kumar 	if (phy_data->redrv && !phy_data->redrv_if) {
23404ac7516bSRavi Kumar 		ret = pdata->hw_if.set_ext_mii_mode(pdata, phy_data->redrv_addr,
23414ac7516bSRavi Kumar 						    AXGBE_MDIO_MODE_CL22);
23424ac7516bSRavi Kumar 		if (ret) {
23434ac7516bSRavi Kumar 			PMD_DRV_LOG(ERR, "redriver mdio port not compatible (%u)\n",
23444ac7516bSRavi Kumar 				    phy_data->redrv_addr);
23454ac7516bSRavi Kumar 			return -EINVAL;
23464ac7516bSRavi Kumar 		}
23474ac7516bSRavi Kumar 	}
234800072056SRavi Kumar 
234900072056SRavi Kumar 	phy_data->phy_cdr_delay = AXGBE_CDR_DELAY_INIT;
23504ac7516bSRavi Kumar 	return 0;
23514ac7516bSRavi Kumar }
23524ac7516bSRavi Kumar void axgbe_init_function_ptrs_phy_v2(struct axgbe_phy_if *phy_if)
23534ac7516bSRavi Kumar {
23544ac7516bSRavi Kumar 	struct axgbe_phy_impl_if *phy_impl = &phy_if->phy_impl;
23554ac7516bSRavi Kumar 
23564ac7516bSRavi Kumar 	phy_impl->init			= axgbe_phy_init;
2357a5c72737SRavi Kumar 	phy_impl->reset			= axgbe_phy_reset;
2358a5c72737SRavi Kumar 	phy_impl->start			= axgbe_phy_start;
2359a5c72737SRavi Kumar 	phy_impl->stop			= axgbe_phy_stop;
2360a5c72737SRavi Kumar 	phy_impl->link_status		= axgbe_phy_link_status;
2361a5c72737SRavi Kumar 	phy_impl->use_mode		= axgbe_phy_use_mode;
2362a5c72737SRavi Kumar 	phy_impl->set_mode		= axgbe_phy_set_mode;
2363a5c72737SRavi Kumar 	phy_impl->get_mode		= axgbe_phy_get_mode;
2364a5c72737SRavi Kumar 	phy_impl->switch_mode		= axgbe_phy_switch_mode;
2365a5c72737SRavi Kumar 	phy_impl->cur_mode		= axgbe_phy_cur_mode;
2366a5c72737SRavi Kumar 	phy_impl->an_mode		= axgbe_phy_an_mode;
2367a5c72737SRavi Kumar 	phy_impl->an_config		= axgbe_phy_an_config;
2368a5c72737SRavi Kumar 	phy_impl->an_advertising	= axgbe_phy_an_advertising;
2369a5c72737SRavi Kumar 	phy_impl->an_outcome		= axgbe_phy_an_outcome;
237000072056SRavi Kumar 
237100072056SRavi Kumar 	phy_impl->an_pre		= axgbe_phy_an_pre;
237200072056SRavi Kumar 	phy_impl->an_post		= axgbe_phy_an_post;
237300072056SRavi Kumar 
237400072056SRavi Kumar 	phy_impl->kr_training_pre	= axgbe_phy_kr_training_pre;
237500072056SRavi Kumar 	phy_impl->kr_training_post	= axgbe_phy_kr_training_post;
23764ac7516bSRavi Kumar }
2377