// SPDX-License-Identifier: GPL-2.0+
/*
* Marvell 10G 88x3310 PHY driver
*
* Based upon the ID registers, this PHY appears to be a mixture of IPs
* from two different companies.
*
* There appears to be several different data paths through the PHY which
* are automatically managed by the PHY. The following has been determined
* via observation and experimentation for a setup using single-lane Serdes:
*
* SGMII PHYXS -- BASE-T PCS -- 10G PMA -- AN -- Copper (for <= 1G)
* 10GBASE-KR PHYXS -- BASE-T PCS -- 10G PMA -- AN -- Copper (for 10G)
* 10GBASE-KR PHYXS -- BASE-R PCS -- Fiber
*
* With XAUI, observation shows:
*
* XAUI PHYXS -- <appropriate PCS as above>
*
* and no switching of the host interface mode occurs.
*
* If both the fiber and copper ports are connected, the first to gain
* link takes priority and the other port is completely locked out.
*/
#include <linux/bitfield.h>
#include <linux/ctype.h>
#include <linux/delay.h>
#include <linux/hwmon.h>
#include <linux/marvell_phy.h>
#include <linux/phy.h>
#include <linux/sfp.h>
#include <linux/netdevice.h>
#define MV_PHY_ALASKA_NBT_QUIRK_MASK 0xfffffffe
#define MV_PHY_ALASKA_NBT_QUIRK_REV (MARVELL_PHY_ID_88X3310 | 0xa)
#define MV_VERSION(a,b,c,d) ((a) << 24 | (b) << 16 | (c) << 8 | (d))
enum {
MV_PMA_FW_VER0 = 0xc011,
MV_PMA_FW_VER1 = 0xc012,
MV_PMA_21X0_PORT_CTRL = 0xc04a,
MV_PMA_21X0_PORT_CTRL_SWRST = BIT(15),
MV_PMA_21X0_PORT_CTRL_MACTYPE_MASK = 0x7,
MV_PMA_21X0_PORT_CTRL_MACTYPE_USXGMII = 0x0,
MV_PMA_2180_PORT_CTRL_MACTYPE_DXGMII = 0x1,
MV_PMA_2180_PORT_CTRL_MACTYPE_QXGMII = 0x2,
MV_PMA_21X0_PORT_CTRL_MACTYPE_5GBASER = 0x4,
MV_PMA_21X0_PORT_CTRL_MACTYPE_5GBASER_NO_SGMII_AN = 0x5,
MV_PMA_21X0_PORT_CTRL_MACTYPE_10GBASER_RATE_MATCH = 0x6,
MV_PMA_BOOT = 0xc050,
MV_PMA_BOOT_FATAL = BIT(0),
MV_PCS_BASE_T = 0x0000,
MV_PCS_BASE_R = 0x1000,
MV_PCS_1000BASEX = 0x2000,
MV_PCS_CSCR1 = 0x8000,
MV_PCS_CSCR1_ED_MASK = 0x0300,
MV_PCS_CSCR1_ED_OFF = 0x0000,
MV_PCS_CSCR1_ED_RX = 0x0200,
MV_PCS_CSCR1_ED_NLP = 0x0300,
MV_PCS_CSCR1_MDIX_MASK = 0x0060,
MV_PCS_CSCR1_MDIX_MDI = 0x0000,
MV_PCS_CSCR1_MDIX_MDIX = 0x0020,
MV_PCS_CSCR1_MDIX_AUTO = 0x0060,
MV_PCS_DSC1 = 0x8003,
MV_PCS_DSC1_ENABLE = BIT(9),
MV_PCS_DSC1_10GBT = 0x01c0,
MV_PCS_DSC1_1GBR = 0x0038,
MV_PCS_DSC1_100BTX = 0x0007,
MV_PCS_DSC2 = 0x8004,
MV_PCS_DSC2_2P5G = 0xf000,
MV_PCS_DSC2_5G = 0x0f00,
MV_PCS_CSSR1 = 0x8008,
MV_PCS_CSSR1_SPD1_MASK = 0xc000,
MV_PCS_CSSR1_SPD1_SPD2 = 0xc000,
MV_PCS_CSSR1_SPD1_1000 = 0x8000,
MV_PCS_CSSR1_SPD1_100 = 0x4000,
MV_PCS_CSSR1_SPD1_10 = 0x0000,
MV_PCS_CSSR1_DUPLEX_FULL= BIT(13),
MV_PCS_CSSR1_RESOLVED = BIT(11),
MV_PCS_CSSR1_MDIX = BIT(6),
MV_PCS_CSSR1_SPD2_MASK = 0x000c,
MV_PCS_CSSR1_SPD2_5000 = 0x0008,
MV_PCS_CSSR1_SPD2_2500 = 0x0004,
MV_PCS_CSSR1_SPD2_10000 = 0x0000,
/* Temperature read register (88E2110 only) */
MV_PCS_TEMP = 0x8042,
/* Number of ports on the device */
MV_PCS_PORT_INFO = 0xd00d,
MV_PCS_PORT_INFO_NPORTS_MASK = 0x0380,
MV_PCS_PORT_INFO_NPORTS_SHIFT = 7,
/* These registers appear at 0x800X and 0xa00X - the 0xa00X control
* registers appear to set themselves to the 0x800X when AN is
* restarted, but status registers appear readable from either.
*/
MV_AN_CTRL1000 = 0x8000, /* 1000base-T control register */
MV_AN_STAT1000 = 0x8001, /* 1000base-T status register */
/* Vendor2 MMD registers */
MV_V2_PORT_CTRL = 0xf001,
MV_V2_PORT_CTRL_PWRDOWN = BIT(11),
MV_V2_33X0_PORT_CTRL_SWRST = BIT(15),
MV_V2_33X0_PORT_CTRL_MACTYPE_MASK = 0x7,
MV_V2_33X0_PORT_CTRL_MACTYPE_RXAUI = 0x0,
MV_V2_3310_PORT_CTRL_MACTYPE_XAUI_RATE_MATCH = 0x1,
MV_V2_3340_PORT_CTRL_MACTYPE_RXAUI_NO_SGMII_AN = 0x1,
MV_V2_33X