xref: /openbmc/linux/drivers/net/ethernet/sfc/falcon/tenxpress.c (revision 75bf465f0bc33e9b776a46d6a1b9b990f5fb7c37)
1*d2912cb1SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
25a6681e2SEdward Cree /****************************************************************************
35a6681e2SEdward Cree  * Driver for Solarflare network controllers and boards
45a6681e2SEdward Cree  * Copyright 2007-2011 Solarflare Communications Inc.
55a6681e2SEdward Cree  */
65a6681e2SEdward Cree 
75a6681e2SEdward Cree #include <linux/delay.h>
85a6681e2SEdward Cree #include <linux/rtnetlink.h>
95a6681e2SEdward Cree #include <linux/seq_file.h>
105a6681e2SEdward Cree #include <linux/slab.h>
115a6681e2SEdward Cree #include "efx.h"
125a6681e2SEdward Cree #include "mdio_10g.h"
135a6681e2SEdward Cree #include "nic.h"
145a6681e2SEdward Cree #include "phy.h"
155a6681e2SEdward Cree #include "workarounds.h"
165a6681e2SEdward Cree 
175a6681e2SEdward Cree /* We expect these MMDs to be in the package. */
185a6681e2SEdward Cree #define TENXPRESS_REQUIRED_DEVS (MDIO_DEVS_PMAPMD	| \
195a6681e2SEdward Cree 				 MDIO_DEVS_PCS		| \
205a6681e2SEdward Cree 				 MDIO_DEVS_PHYXS	| \
215a6681e2SEdward Cree 				 MDIO_DEVS_AN)
225a6681e2SEdward Cree 
235a6681e2SEdward Cree #define SFX7101_LOOPBACKS ((1 << LOOPBACK_PHYXS) |	\
245a6681e2SEdward Cree 			   (1 << LOOPBACK_PCS) |	\
255a6681e2SEdward Cree 			   (1 << LOOPBACK_PMAPMD) |	\
265a6681e2SEdward Cree 			   (1 << LOOPBACK_PHYXS_WS))
275a6681e2SEdward Cree 
285a6681e2SEdward Cree /* We complain if we fail to see the link partner as 10G capable this many
295a6681e2SEdward Cree  * times in a row (must be > 1 as sampling the autoneg. registers is racy)
305a6681e2SEdward Cree  */
315a6681e2SEdward Cree #define MAX_BAD_LP_TRIES	(5)
325a6681e2SEdward Cree 
335a6681e2SEdward Cree /* Extended control register */
345a6681e2SEdward Cree #define PMA_PMD_XCONTROL_REG	49152
355a6681e2SEdward Cree #define PMA_PMD_EXT_GMII_EN_LBN	1
365a6681e2SEdward Cree #define PMA_PMD_EXT_GMII_EN_WIDTH 1
375a6681e2SEdward Cree #define PMA_PMD_EXT_CLK_OUT_LBN	2
385a6681e2SEdward Cree #define PMA_PMD_EXT_CLK_OUT_WIDTH 1
395a6681e2SEdward Cree #define PMA_PMD_LNPGA_POWERDOWN_LBN 8
405a6681e2SEdward Cree #define PMA_PMD_LNPGA_POWERDOWN_WIDTH 1
415a6681e2SEdward Cree #define PMA_PMD_EXT_CLK312_WIDTH 1
425a6681e2SEdward Cree #define PMA_PMD_EXT_LPOWER_LBN  12
435a6681e2SEdward Cree #define PMA_PMD_EXT_LPOWER_WIDTH 1
445a6681e2SEdward Cree #define PMA_PMD_EXT_ROBUST_LBN	14
455a6681e2SEdward Cree #define PMA_PMD_EXT_ROBUST_WIDTH 1
465a6681e2SEdward Cree #define PMA_PMD_EXT_SSR_LBN	15
475a6681e2SEdward Cree #define PMA_PMD_EXT_SSR_WIDTH	1
485a6681e2SEdward Cree 
495a6681e2SEdward Cree /* extended status register */
505a6681e2SEdward Cree #define PMA_PMD_XSTATUS_REG	49153
515a6681e2SEdward Cree #define PMA_PMD_XSTAT_MDIX_LBN	14
525a6681e2SEdward Cree #define PMA_PMD_XSTAT_FLP_LBN   (12)
535a6681e2SEdward Cree 
545a6681e2SEdward Cree /* LED control register */
555a6681e2SEdward Cree #define PMA_PMD_LED_CTRL_REG	49159
565a6681e2SEdward Cree #define PMA_PMA_LED_ACTIVITY_LBN	(3)
575a6681e2SEdward Cree 
585a6681e2SEdward Cree /* LED function override register */
595a6681e2SEdward Cree #define PMA_PMD_LED_OVERR_REG	49161
605a6681e2SEdward Cree /* Bit positions for different LEDs (there are more but not wired on SFE4001)*/
615a6681e2SEdward Cree #define PMA_PMD_LED_LINK_LBN	(0)
625a6681e2SEdward Cree #define PMA_PMD_LED_SPEED_LBN	(2)
635a6681e2SEdward Cree #define PMA_PMD_LED_TX_LBN	(4)
645a6681e2SEdward Cree #define PMA_PMD_LED_RX_LBN	(6)
655a6681e2SEdward Cree /* Override settings */
665a6681e2SEdward Cree #define	PMA_PMD_LED_AUTO	(0)	/* H/W control */
675a6681e2SEdward Cree #define	PMA_PMD_LED_ON		(1)
685a6681e2SEdward Cree #define	PMA_PMD_LED_OFF		(2)
695a6681e2SEdward Cree #define PMA_PMD_LED_FLASH	(3)
705a6681e2SEdward Cree #define PMA_PMD_LED_MASK	3
715a6681e2SEdward Cree /* All LEDs under hardware control */
725a6681e2SEdward Cree /* Green and Amber under hardware control, Red off */
735a6681e2SEdward Cree #define SFX7101_PMA_PMD_LED_DEFAULT (PMA_PMD_LED_OFF << PMA_PMD_LED_RX_LBN)
745a6681e2SEdward Cree 
755a6681e2SEdward Cree #define PMA_PMD_SPEED_ENABLE_REG 49192
765a6681e2SEdward Cree #define PMA_PMD_100TX_ADV_LBN    1
775a6681e2SEdward Cree #define PMA_PMD_100TX_ADV_WIDTH  1
785a6681e2SEdward Cree #define PMA_PMD_1000T_ADV_LBN    2
795a6681e2SEdward Cree #define PMA_PMD_1000T_ADV_WIDTH  1
805a6681e2SEdward Cree #define PMA_PMD_10000T_ADV_LBN   3
815a6681e2SEdward Cree #define PMA_PMD_10000T_ADV_WIDTH 1
825a6681e2SEdward Cree #define PMA_PMD_SPEED_LBN        4
835a6681e2SEdward Cree #define PMA_PMD_SPEED_WIDTH      4
845a6681e2SEdward Cree 
855a6681e2SEdward Cree /* Misc register defines */
865a6681e2SEdward Cree #define PCS_CLOCK_CTRL_REG	55297
875a6681e2SEdward Cree #define PLL312_RST_N_LBN 2
885a6681e2SEdward Cree 
895a6681e2SEdward Cree #define PCS_SOFT_RST2_REG	55302
905a6681e2SEdward Cree #define SERDES_RST_N_LBN 13
915a6681e2SEdward Cree #define XGXS_RST_N_LBN 12
925a6681e2SEdward Cree 
935a6681e2SEdward Cree #define	PCS_TEST_SELECT_REG	55303	/* PRM 10.5.8 */
945a6681e2SEdward Cree #define	CLK312_EN_LBN 3
955a6681e2SEdward Cree 
965a6681e2SEdward Cree /* PHYXS registers */
975a6681e2SEdward Cree #define PHYXS_XCONTROL_REG	49152
985a6681e2SEdward Cree #define PHYXS_RESET_LBN		15
995a6681e2SEdward Cree #define PHYXS_RESET_WIDTH	1
1005a6681e2SEdward Cree 
1015a6681e2SEdward Cree #define PHYXS_TEST1         (49162)
1025a6681e2SEdward Cree #define LOOPBACK_NEAR_LBN   (8)
1035a6681e2SEdward Cree #define LOOPBACK_NEAR_WIDTH (1)
1045a6681e2SEdward Cree 
1055a6681e2SEdward Cree /* Boot status register */
1065a6681e2SEdward Cree #define PCS_BOOT_STATUS_REG		53248
1075a6681e2SEdward Cree #define PCS_BOOT_FATAL_ERROR_LBN	0
1085a6681e2SEdward Cree #define PCS_BOOT_PROGRESS_LBN		1
1095a6681e2SEdward Cree #define PCS_BOOT_PROGRESS_WIDTH		2
1105a6681e2SEdward Cree #define PCS_BOOT_PROGRESS_INIT		0
1115a6681e2SEdward Cree #define PCS_BOOT_PROGRESS_WAIT_MDIO	1
1125a6681e2SEdward Cree #define PCS_BOOT_PROGRESS_CHECKSUM	2
1135a6681e2SEdward Cree #define PCS_BOOT_PROGRESS_JUMP		3
1145a6681e2SEdward Cree #define PCS_BOOT_DOWNLOAD_WAIT_LBN	3
1155a6681e2SEdward Cree #define PCS_BOOT_CODE_STARTED_LBN	4
1165a6681e2SEdward Cree 
1175a6681e2SEdward Cree /* 100M/1G PHY registers */
1185a6681e2SEdward Cree #define GPHY_XCONTROL_REG	49152
1195a6681e2SEdward Cree #define GPHY_ISOLATE_LBN	10
1205a6681e2SEdward Cree #define GPHY_ISOLATE_WIDTH	1
1215a6681e2SEdward Cree #define GPHY_DUPLEX_LBN		8
1225a6681e2SEdward Cree #define GPHY_DUPLEX_WIDTH	1
1235a6681e2SEdward Cree #define GPHY_LOOPBACK_NEAR_LBN	14
1245a6681e2SEdward Cree #define GPHY_LOOPBACK_NEAR_WIDTH 1
1255a6681e2SEdward Cree 
1265a6681e2SEdward Cree #define C22EXT_STATUS_REG       49153
1275a6681e2SEdward Cree #define C22EXT_STATUS_LINK_LBN  2
1285a6681e2SEdward Cree #define C22EXT_STATUS_LINK_WIDTH 1
1295a6681e2SEdward Cree 
1305a6681e2SEdward Cree #define C22EXT_MSTSLV_CTRL			49161
1315a6681e2SEdward Cree #define C22EXT_MSTSLV_CTRL_ADV_1000_HD_LBN	8
1325a6681e2SEdward Cree #define C22EXT_MSTSLV_CTRL_ADV_1000_FD_LBN	9
1335a6681e2SEdward Cree 
1345a6681e2SEdward Cree #define C22EXT_MSTSLV_STATUS			49162
1355a6681e2SEdward Cree #define C22EXT_MSTSLV_STATUS_LP_1000_HD_LBN	10
1365a6681e2SEdward Cree #define C22EXT_MSTSLV_STATUS_LP_1000_FD_LBN	11
1375a6681e2SEdward Cree 
1385a6681e2SEdward Cree /* Time to wait between powering down the LNPGA and turning off the power
1395a6681e2SEdward Cree  * rails */
1405a6681e2SEdward Cree #define LNPGA_PDOWN_WAIT	(HZ / 5)
1415a6681e2SEdward Cree 
1425a6681e2SEdward Cree struct tenxpress_phy_data {
1435a6681e2SEdward Cree 	enum ef4_loopback_mode loopback_mode;
1445a6681e2SEdward Cree 	enum ef4_phy_mode phy_mode;
1455a6681e2SEdward Cree 	int bad_lp_tries;
1465a6681e2SEdward Cree };
1475a6681e2SEdward Cree 
tenxpress_init(struct ef4_nic * efx)1485a6681e2SEdward Cree static int tenxpress_init(struct ef4_nic *efx)
1495a6681e2SEdward Cree {
1505a6681e2SEdward Cree 	/* Enable 312.5 MHz clock */
1515a6681e2SEdward Cree 	ef4_mdio_write(efx, MDIO_MMD_PCS, PCS_TEST_SELECT_REG,
1525a6681e2SEdward Cree 		       1 << CLK312_EN_LBN);
1535a6681e2SEdward Cree 
1545a6681e2SEdward Cree 	/* Set the LEDs up as: Green = Link, Amber = Link/Act, Red = Off */
1555a6681e2SEdward Cree 	ef4_mdio_set_flag(efx, MDIO_MMD_PMAPMD, PMA_PMD_LED_CTRL_REG,
1565a6681e2SEdward Cree 			  1 << PMA_PMA_LED_ACTIVITY_LBN, true);
1575a6681e2SEdward Cree 	ef4_mdio_write(efx, MDIO_MMD_PMAPMD, PMA_PMD_LED_OVERR_REG,
1585a6681e2SEdward Cree 		       SFX7101_PMA_PMD_LED_DEFAULT);
1595a6681e2SEdward Cree 
1605a6681e2SEdward Cree 	return 0;
1615a6681e2SEdward Cree }
1625a6681e2SEdward Cree 
tenxpress_phy_probe(struct ef4_nic * efx)1635a6681e2SEdward Cree static int tenxpress_phy_probe(struct ef4_nic *efx)
1645a6681e2SEdward Cree {
1655a6681e2SEdward Cree 	struct tenxpress_phy_data *phy_data;
1665a6681e2SEdward Cree 
1675a6681e2SEdward Cree 	/* Allocate phy private storage */
1685a6681e2SEdward Cree 	phy_data = kzalloc(sizeof(*phy_data), GFP_KERNEL);
1695a6681e2SEdward Cree 	if (!phy_data)
1705a6681e2SEdward Cree 		return -ENOMEM;
1715a6681e2SEdward Cree 	efx->phy_data = phy_data;
1725a6681e2SEdward Cree 	phy_data->phy_mode = efx->phy_mode;
1735a6681e2SEdward Cree 
1745a6681e2SEdward Cree 	efx->mdio.mmds = TENXPRESS_REQUIRED_DEVS;
1755a6681e2SEdward Cree 	efx->mdio.mode_support = MDIO_SUPPORTS_C45;
1765a6681e2SEdward Cree 
1775a6681e2SEdward Cree 	efx->loopback_modes = SFX7101_LOOPBACKS | FALCON_XMAC_LOOPBACKS;
1785a6681e2SEdward Cree 
1795a6681e2SEdward Cree 	efx->link_advertising = (ADVERTISED_TP | ADVERTISED_Autoneg |
1805a6681e2SEdward Cree 				 ADVERTISED_10000baseT_Full);
1815a6681e2SEdward Cree 
1825a6681e2SEdward Cree 	return 0;
1835a6681e2SEdward Cree }
1845a6681e2SEdward Cree 
tenxpress_phy_init(struct ef4_nic * efx)1855a6681e2SEdward Cree static int tenxpress_phy_init(struct ef4_nic *efx)
1865a6681e2SEdward Cree {
1875a6681e2SEdward Cree 	int rc;
1885a6681e2SEdward Cree 
1895a6681e2SEdward Cree 	falcon_board(efx)->type->init_phy(efx);
1905a6681e2SEdward Cree 
1915a6681e2SEdward Cree 	if (!(efx->phy_mode & PHY_MODE_SPECIAL)) {
1925a6681e2SEdward Cree 		rc = ef4_mdio_wait_reset_mmds(efx, TENXPRESS_REQUIRED_DEVS);
1935a6681e2SEdward Cree 		if (rc < 0)
1945a6681e2SEdward Cree 			return rc;
1955a6681e2SEdward Cree 
1965a6681e2SEdward Cree 		rc = ef4_mdio_check_mmds(efx, TENXPRESS_REQUIRED_DEVS);
1975a6681e2SEdward Cree 		if (rc < 0)
1985a6681e2SEdward Cree 			return rc;
1995a6681e2SEdward Cree 	}
2005a6681e2SEdward Cree 
2015a6681e2SEdward Cree 	rc = tenxpress_init(efx);
2025a6681e2SEdward Cree 	if (rc < 0)
2035a6681e2SEdward Cree 		return rc;
2045a6681e2SEdward Cree 
2055a6681e2SEdward Cree 	/* Reinitialise flow control settings */
2065a6681e2SEdward Cree 	ef4_link_set_wanted_fc(efx, efx->wanted_fc);
2075a6681e2SEdward Cree 	ef4_mdio_an_reconfigure(efx);
2085a6681e2SEdward Cree 
2095a6681e2SEdward Cree 	schedule_timeout_uninterruptible(HZ / 5); /* 200ms */
2105a6681e2SEdward Cree 
2115a6681e2SEdward Cree 	/* Let XGXS and SerDes out of reset */
2125a6681e2SEdward Cree 	falcon_reset_xaui(efx);
2135a6681e2SEdward Cree 
2145a6681e2SEdward Cree 	return 0;
2155a6681e2SEdward Cree }
2165a6681e2SEdward Cree 
2175a6681e2SEdward Cree /* Perform a "special software reset" on the PHY. The caller is
2185a6681e2SEdward Cree  * responsible for saving and restoring the PHY hardware registers
2195a6681e2SEdward Cree  * properly, and masking/unmasking LASI */
tenxpress_special_reset(struct ef4_nic * efx)2205a6681e2SEdward Cree static int tenxpress_special_reset(struct ef4_nic *efx)
2215a6681e2SEdward Cree {
2225a6681e2SEdward Cree 	int rc, reg;
2235a6681e2SEdward Cree 
2245a6681e2SEdward Cree 	/* The XGMAC clock is driven from the SFX7101 312MHz clock, so
2255a6681e2SEdward Cree 	 * a special software reset can glitch the XGMAC sufficiently for stats
2265a6681e2SEdward Cree 	 * requests to fail. */
2275a6681e2SEdward Cree 	falcon_stop_nic_stats(efx);
2285a6681e2SEdward Cree 
2295a6681e2SEdward Cree 	/* Initiate reset */
2305a6681e2SEdward Cree 	reg = ef4_mdio_read(efx, MDIO_MMD_PMAPMD, PMA_PMD_XCONTROL_REG);
2315a6681e2SEdward Cree 	reg |= (1 << PMA_PMD_EXT_SSR_LBN);
2325a6681e2SEdward Cree 	ef4_mdio_write(efx, MDIO_MMD_PMAPMD, PMA_PMD_XCONTROL_REG, reg);
2335a6681e2SEdward Cree 
2345a6681e2SEdward Cree 	mdelay(200);
2355a6681e2SEdward Cree 
2365a6681e2SEdward Cree 	/* Wait for the blocks to come out of reset */
2375a6681e2SEdward Cree 	rc = ef4_mdio_wait_reset_mmds(efx, TENXPRESS_REQUIRED_DEVS);
2385a6681e2SEdward Cree 	if (rc < 0)
2395a6681e2SEdward Cree 		goto out;
2405a6681e2SEdward Cree 
2415a6681e2SEdward Cree 	/* Try and reconfigure the device */
2425a6681e2SEdward Cree 	rc = tenxpress_init(efx);
2435a6681e2SEdward Cree 	if (rc < 0)
2445a6681e2SEdward Cree 		goto out;
2455a6681e2SEdward Cree 
2465a6681e2SEdward Cree 	/* Wait for the XGXS state machine to churn */
2475a6681e2SEdward Cree 	mdelay(10);
2485a6681e2SEdward Cree out:
2495a6681e2SEdward Cree 	falcon_start_nic_stats(efx);
2505a6681e2SEdward Cree 	return rc;
2515a6681e2SEdward Cree }
2525a6681e2SEdward Cree 
sfx7101_check_bad_lp(struct ef4_nic * efx,bool link_ok)2535a6681e2SEdward Cree static void sfx7101_check_bad_lp(struct ef4_nic *efx, bool link_ok)
2545a6681e2SEdward Cree {
2555a6681e2SEdward Cree 	struct tenxpress_phy_data *pd = efx->phy_data;
2565a6681e2SEdward Cree 	bool bad_lp;
2575a6681e2SEdward Cree 	int reg;
2585a6681e2SEdward Cree 
2595a6681e2SEdward Cree 	if (link_ok) {
2605a6681e2SEdward Cree 		bad_lp = false;
2615a6681e2SEdward Cree 	} else {
2625a6681e2SEdward Cree 		/* Check that AN has started but not completed. */
2635a6681e2SEdward Cree 		reg = ef4_mdio_read(efx, MDIO_MMD_AN, MDIO_STAT1);
2645a6681e2SEdward Cree 		if (!(reg & MDIO_AN_STAT1_LPABLE))
2655a6681e2SEdward Cree 			return; /* LP status is unknown */
2665a6681e2SEdward Cree 		bad_lp = !(reg & MDIO_AN_STAT1_COMPLETE);
2675a6681e2SEdward Cree 		if (bad_lp)
2685a6681e2SEdward Cree 			pd->bad_lp_tries++;
2695a6681e2SEdward Cree 	}
2705a6681e2SEdward Cree 
2715a6681e2SEdward Cree 	/* Nothing to do if all is well and was previously so. */
2725a6681e2SEdward Cree 	if (!pd->bad_lp_tries)
2735a6681e2SEdward Cree 		return;
2745a6681e2SEdward Cree 
2755a6681e2SEdward Cree 	/* Use the RX (red) LED as an error indicator once we've seen AN
2765a6681e2SEdward Cree 	 * failure several times in a row, and also log a message. */
2775a6681e2SEdward Cree 	if (!bad_lp || pd->bad_lp_tries == MAX_BAD_LP_TRIES) {
2785a6681e2SEdward Cree 		reg = ef4_mdio_read(efx, MDIO_MMD_PMAPMD,
2795a6681e2SEdward Cree 				    PMA_PMD_LED_OVERR_REG);
2805a6681e2SEdward Cree 		reg &= ~(PMA_PMD_LED_MASK << PMA_PMD_LED_RX_LBN);
2815a6681e2SEdward Cree 		if (!bad_lp) {
2825a6681e2SEdward Cree 			reg |= PMA_PMD_LED_OFF << PMA_PMD_LED_RX_LBN;
2835a6681e2SEdward Cree 		} else {
2845a6681e2SEdward Cree 			reg |= PMA_PMD_LED_FLASH << PMA_PMD_LED_RX_LBN;
2855a6681e2SEdward Cree 			netif_err(efx, link, efx->net_dev,
2865a6681e2SEdward Cree 				  "appears to be plugged into a port"
2875a6681e2SEdward Cree 				  " that is not 10GBASE-T capable. The PHY"
2885a6681e2SEdward Cree 				  " supports 10GBASE-T ONLY, so no link can"
2895a6681e2SEdward Cree 				  " be established\n");
2905a6681e2SEdward Cree 		}
2915a6681e2SEdward Cree 		ef4_mdio_write(efx, MDIO_MMD_PMAPMD,
2925a6681e2SEdward Cree 			       PMA_PMD_LED_OVERR_REG, reg);
2935a6681e2SEdward Cree 		pd->bad_lp_tries = bad_lp;
2945a6681e2SEdward Cree 	}
2955a6681e2SEdward Cree }
2965a6681e2SEdward Cree 
sfx7101_link_ok(struct ef4_nic * efx)2975a6681e2SEdward Cree static bool sfx7101_link_ok(struct ef4_nic *efx)
2985a6681e2SEdward Cree {
2995a6681e2SEdward Cree 	return ef4_mdio_links_ok(efx,
3005a6681e2SEdward Cree 				 MDIO_DEVS_PMAPMD |
3015a6681e2SEdward Cree 				 MDIO_DEVS_PCS |
3025a6681e2SEdward Cree 				 MDIO_DEVS_PHYXS);
3035a6681e2SEdward Cree }
3045a6681e2SEdward Cree 
tenxpress_ext_loopback(struct ef4_nic * efx)3055a6681e2SEdward Cree static void tenxpress_ext_loopback(struct ef4_nic *efx)
3065a6681e2SEdward Cree {
3075a6681e2SEdward Cree 	ef4_mdio_set_flag(efx, MDIO_MMD_PHYXS, PHYXS_TEST1,
3085a6681e2SEdward Cree 			  1 << LOOPBACK_NEAR_LBN,
3095a6681e2SEdward Cree 			  efx->loopback_mode == LOOPBACK_PHYXS);
3105a6681e2SEdward Cree }
3115a6681e2SEdward Cree 
tenxpress_low_power(struct ef4_nic * efx)3125a6681e2SEdward Cree static void tenxpress_low_power(struct ef4_nic *efx)
3135a6681e2SEdward Cree {
3145a6681e2SEdward Cree 	ef4_mdio_set_mmds_lpower(
3155a6681e2SEdward Cree 		efx, !!(efx->phy_mode & PHY_MODE_LOW_POWER),
3165a6681e2SEdward Cree 		TENXPRESS_REQUIRED_DEVS);
3175a6681e2SEdward Cree }
3185a6681e2SEdward Cree 
tenxpress_phy_reconfigure(struct ef4_nic * efx)3195a6681e2SEdward Cree static int tenxpress_phy_reconfigure(struct ef4_nic *efx)
3205a6681e2SEdward Cree {
3215a6681e2SEdward Cree 	struct tenxpress_phy_data *phy_data = efx->phy_data;
3225a6681e2SEdward Cree 	bool phy_mode_change, loop_reset;
3235a6681e2SEdward Cree 
3245a6681e2SEdward Cree 	if (efx->phy_mode & (PHY_MODE_OFF | PHY_MODE_SPECIAL)) {
3255a6681e2SEdward Cree 		phy_data->phy_mode = efx->phy_mode;
3265a6681e2SEdward Cree 		return 0;
3275a6681e2SEdward Cree 	}
3285a6681e2SEdward Cree 
3295a6681e2SEdward Cree 	phy_mode_change = (efx->phy_mode == PHY_MODE_NORMAL &&
3305a6681e2SEdward Cree 			   phy_data->phy_mode != PHY_MODE_NORMAL);
3315a6681e2SEdward Cree 	loop_reset = (LOOPBACK_OUT_OF(phy_data, efx, LOOPBACKS_EXTERNAL(efx)) ||
3325a6681e2SEdward Cree 		      LOOPBACK_CHANGED(phy_data, efx, 1 << LOOPBACK_GPHY));
3335a6681e2SEdward Cree 
3345a6681e2SEdward Cree 	if (loop_reset || phy_mode_change) {
3355a6681e2SEdward Cree 		tenxpress_special_reset(efx);
3365a6681e2SEdward Cree 		falcon_reset_xaui(efx);
3375a6681e2SEdward Cree 	}
3385a6681e2SEdward Cree 
3395a6681e2SEdward Cree 	tenxpress_low_power(efx);
3405a6681e2SEdward Cree 	ef4_mdio_transmit_disable(efx);
3415a6681e2SEdward Cree 	ef4_mdio_phy_reconfigure(efx);
3425a6681e2SEdward Cree 	tenxpress_ext_loopback(efx);
3435a6681e2SEdward Cree 	ef4_mdio_an_reconfigure(efx);
3445a6681e2SEdward Cree 
3455a6681e2SEdward Cree 	phy_data->loopback_mode = efx->loopback_mode;
3465a6681e2SEdward Cree 	phy_data->phy_mode = efx->phy_mode;
3475a6681e2SEdward Cree 
3485a6681e2SEdward Cree 	return 0;
3495a6681e2SEdward Cree }
3505a6681e2SEdward Cree 
3515a6681e2SEdward Cree /* Poll for link state changes */
tenxpress_phy_poll(struct ef4_nic * efx)3525a6681e2SEdward Cree static bool tenxpress_phy_poll(struct ef4_nic *efx)
3535a6681e2SEdward Cree {
3545a6681e2SEdward Cree 	struct ef4_link_state old_state = efx->link_state;
3555a6681e2SEdward Cree 
3565a6681e2SEdward Cree 	efx->link_state.up = sfx7101_link_ok(efx);
3575a6681e2SEdward Cree 	efx->link_state.speed = 10000;
3585a6681e2SEdward Cree 	efx->link_state.fd = true;
3595a6681e2SEdward Cree 	efx->link_state.fc = ef4_mdio_get_pause(efx);
3605a6681e2SEdward Cree 
3615a6681e2SEdward Cree 	sfx7101_check_bad_lp(efx, efx->link_state.up);
3625a6681e2SEdward Cree 
3635a6681e2SEdward Cree 	return !ef4_link_state_equal(&efx->link_state, &old_state);
3645a6681e2SEdward Cree }
3655a6681e2SEdward Cree 
sfx7101_phy_fini(struct ef4_nic * efx)3665a6681e2SEdward Cree static void sfx7101_phy_fini(struct ef4_nic *efx)
3675a6681e2SEdward Cree {
3685a6681e2SEdward Cree 	int reg;
3695a6681e2SEdward Cree 
3705a6681e2SEdward Cree 	/* Power down the LNPGA */
3715a6681e2SEdward Cree 	reg = (1 << PMA_PMD_LNPGA_POWERDOWN_LBN);
3725a6681e2SEdward Cree 	ef4_mdio_write(efx, MDIO_MMD_PMAPMD, PMA_PMD_XCONTROL_REG, reg);
3735a6681e2SEdward Cree 
3745a6681e2SEdward Cree 	/* Waiting here ensures that the board fini, which can turn
3755a6681e2SEdward Cree 	 * off the power to the PHY, won't get run until the LNPGA
3765a6681e2SEdward Cree 	 * powerdown has been given long enough to complete. */
3775a6681e2SEdward Cree 	schedule_timeout_uninterruptible(LNPGA_PDOWN_WAIT); /* 200 ms */
3785a6681e2SEdward Cree }
3795a6681e2SEdward Cree 
tenxpress_phy_remove(struct ef4_nic * efx)3805a6681e2SEdward Cree static void tenxpress_phy_remove(struct ef4_nic *efx)
3815a6681e2SEdward Cree {
3825a6681e2SEdward Cree 	kfree(efx->phy_data);
3835a6681e2SEdward Cree 	efx->phy_data = NULL;
3845a6681e2SEdward Cree }
3855a6681e2SEdward Cree 
3865a6681e2SEdward Cree 
3875a6681e2SEdward Cree /* Override the RX, TX and link LEDs */
tenxpress_set_id_led(struct ef4_nic * efx,enum ef4_led_mode mode)3885a6681e2SEdward Cree void tenxpress_set_id_led(struct ef4_nic *efx, enum ef4_led_mode mode)
3895a6681e2SEdward Cree {
3905a6681e2SEdward Cree 	int reg;
3915a6681e2SEdward Cree 
3925a6681e2SEdward Cree 	switch (mode) {
3935a6681e2SEdward Cree 	case EF4_LED_OFF:
3945a6681e2SEdward Cree 		reg = (PMA_PMD_LED_OFF << PMA_PMD_LED_TX_LBN) |
3955a6681e2SEdward Cree 			(PMA_PMD_LED_OFF << PMA_PMD_LED_RX_LBN) |
3965a6681e2SEdward Cree 			(PMA_PMD_LED_OFF << PMA_PMD_LED_LINK_LBN);
3975a6681e2SEdward Cree 		break;
3985a6681e2SEdward Cree 	case EF4_LED_ON:
3995a6681e2SEdward Cree 		reg = (PMA_PMD_LED_ON << PMA_PMD_LED_TX_LBN) |
4005a6681e2SEdward Cree 			(PMA_PMD_LED_ON << PMA_PMD_LED_RX_LBN) |
4015a6681e2SEdward Cree 			(PMA_PMD_LED_ON << PMA_PMD_LED_LINK_LBN);
4025a6681e2SEdward Cree 		break;
4035a6681e2SEdward Cree 	default:
4045a6681e2SEdward Cree 		reg = SFX7101_PMA_PMD_LED_DEFAULT;
4055a6681e2SEdward Cree 		break;
4065a6681e2SEdward Cree 	}
4075a6681e2SEdward Cree 
4085a6681e2SEdward Cree 	ef4_mdio_write(efx, MDIO_MMD_PMAPMD, PMA_PMD_LED_OVERR_REG, reg);
4095a6681e2SEdward Cree }
4105a6681e2SEdward Cree 
4115a6681e2SEdward Cree static const char *const sfx7101_test_names[] = {
4125a6681e2SEdward Cree 	"bist"
4135a6681e2SEdward Cree };
4145a6681e2SEdward Cree 
sfx7101_test_name(struct ef4_nic * efx,unsigned int index)4155a6681e2SEdward Cree static const char *sfx7101_test_name(struct ef4_nic *efx, unsigned int index)
4165a6681e2SEdward Cree {
4175a6681e2SEdward Cree 	if (index < ARRAY_SIZE(sfx7101_test_names))
4185a6681e2SEdward Cree 		return sfx7101_test_names[index];
4195a6681e2SEdward Cree 	return NULL;
4205a6681e2SEdward Cree }
4215a6681e2SEdward Cree 
4225a6681e2SEdward Cree static int
sfx7101_run_tests(struct ef4_nic * efx,int * results,unsigned flags)4235a6681e2SEdward Cree sfx7101_run_tests(struct ef4_nic *efx, int *results, unsigned flags)
4245a6681e2SEdward Cree {
4255a6681e2SEdward Cree 	int rc;
4265a6681e2SEdward Cree 
4275a6681e2SEdward Cree 	if (!(flags & ETH_TEST_FL_OFFLINE))
4285a6681e2SEdward Cree 		return 0;
4295a6681e2SEdward Cree 
4305a6681e2SEdward Cree 	/* BIST is automatically run after a special software reset */
4315a6681e2SEdward Cree 	rc = tenxpress_special_reset(efx);
4325a6681e2SEdward Cree 	results[0] = rc ? -1 : 1;
4335a6681e2SEdward Cree 
4345a6681e2SEdward Cree 	ef4_mdio_an_reconfigure(efx);
4355a6681e2SEdward Cree 
4365a6681e2SEdward Cree 	return rc;
4375a6681e2SEdward Cree }
4385a6681e2SEdward Cree 
4395a6681e2SEdward Cree static void
tenxpress_get_link_ksettings(struct ef4_nic * efx,struct ethtool_link_ksettings * cmd)440e938ed15SPhilippe Reynes tenxpress_get_link_ksettings(struct ef4_nic *efx,
441e938ed15SPhilippe Reynes 			     struct ethtool_link_ksettings *cmd)
4425a6681e2SEdward Cree {
4435a6681e2SEdward Cree 	u32 adv = 0, lpa = 0;
4445a6681e2SEdward Cree 	int reg;
4455a6681e2SEdward Cree 
4465a6681e2SEdward Cree 	reg = ef4_mdio_read(efx, MDIO_MMD_AN, MDIO_AN_10GBT_CTRL);
4475a6681e2SEdward Cree 	if (reg & MDIO_AN_10GBT_CTRL_ADV10G)
4485a6681e2SEdward Cree 		adv |= ADVERTISED_10000baseT_Full;
4495a6681e2SEdward Cree 	reg = ef4_mdio_read(efx, MDIO_MMD_AN, MDIO_AN_10GBT_STAT);
4505a6681e2SEdward Cree 	if (reg & MDIO_AN_10GBT_STAT_LP10G)
4515a6681e2SEdward Cree 		lpa |= ADVERTISED_10000baseT_Full;
4525a6681e2SEdward Cree 
453e938ed15SPhilippe Reynes 	mdio45_ethtool_ksettings_get_npage(&efx->mdio, cmd, adv, lpa);
4545a6681e2SEdward Cree 
4555a6681e2SEdward Cree 	/* In loopback, the PHY automatically brings up the correct interface,
4565a6681e2SEdward Cree 	 * but doesn't advertise the correct speed. So override it */
4575a6681e2SEdward Cree 	if (LOOPBACK_EXTERNAL(efx))
458e938ed15SPhilippe Reynes 		cmd->base.speed = SPEED_10000;
4595a6681e2SEdward Cree }
4605a6681e2SEdward Cree 
461e938ed15SPhilippe Reynes static int
tenxpress_set_link_ksettings(struct ef4_nic * efx,const struct ethtool_link_ksettings * cmd)462e938ed15SPhilippe Reynes tenxpress_set_link_ksettings(struct ef4_nic *efx,
463e938ed15SPhilippe Reynes 			     const struct ethtool_link_ksettings *cmd)
4645a6681e2SEdward Cree {
465e938ed15SPhilippe Reynes 	if (!cmd->base.autoneg)
4665a6681e2SEdward Cree 		return -EINVAL;
4675a6681e2SEdward Cree 
468e938ed15SPhilippe Reynes 	return ef4_mdio_set_link_ksettings(efx, cmd);
4695a6681e2SEdward Cree }
4705a6681e2SEdward Cree 
sfx7101_set_npage_adv(struct ef4_nic * efx,u32 advertising)4715a6681e2SEdward Cree static void sfx7101_set_npage_adv(struct ef4_nic *efx, u32 advertising)
4725a6681e2SEdward Cree {
4735a6681e2SEdward Cree 	ef4_mdio_set_flag(efx, MDIO_MMD_AN, MDIO_AN_10GBT_CTRL,
4745a6681e2SEdward Cree 			  MDIO_AN_10GBT_CTRL_ADV10G,
4755a6681e2SEdward Cree 			  advertising & ADVERTISED_10000baseT_Full);
4765a6681e2SEdward Cree }
4775a6681e2SEdward Cree 
4785a6681e2SEdward Cree const struct ef4_phy_operations falcon_sfx7101_phy_ops = {
4795a6681e2SEdward Cree 	.probe		  = tenxpress_phy_probe,
4805a6681e2SEdward Cree 	.init             = tenxpress_phy_init,
4815a6681e2SEdward Cree 	.reconfigure      = tenxpress_phy_reconfigure,
4825a6681e2SEdward Cree 	.poll             = tenxpress_phy_poll,
4835a6681e2SEdward Cree 	.fini             = sfx7101_phy_fini,
4845a6681e2SEdward Cree 	.remove		  = tenxpress_phy_remove,
485e938ed15SPhilippe Reynes 	.get_link_ksettings = tenxpress_get_link_ksettings,
486e938ed15SPhilippe Reynes 	.set_link_ksettings = tenxpress_set_link_ksettings,
4875a6681e2SEdward Cree 	.set_npage_adv    = sfx7101_set_npage_adv,
4885a6681e2SEdward Cree 	.test_alive	  = ef4_mdio_test_alive,
4895a6681e2SEdward Cree 	.test_name	  = sfx7101_test_name,
4905a6681e2SEdward Cree 	.run_tests	  = sfx7101_run_tests,
4915a6681e2SEdward Cree };
492