Add basic support for the Marvell 88X multi-speed ethernet
transceiver.
This PHY provides data transmission over fiber-optic as well as Twinax
copper links. The 88X supports 2 ports of 10GBase-R and 1000Base-X
on the line-side interface. The host-side interface supports 4 ports of
10GBase-R, RXAUI, 1000Base-X and 2 ports of XAUI.
This driver, however, supports only XAUI on the host-side and
1000Base-X/10GBase-R on the line-side, for now. The SGMII is also
supported over 1000Base-X. Interrupts are not supported.
Internal registers access compliant with the Clause 45 specification.
Signed-off-by: Ivan Bornyakov
---
drivers/net/phy/Kconfig | 6 +
drivers/net/phy/Makefile | 1 +
drivers/net/phy/marvell-88x.c | 533 ++
include/linux/marvell_phy.h | 1 +
4 files changed, 541 insertions(+)
create mode 100644 drivers/net/phy/marvell-88x.c
diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig
index 698bea312adc..a615b3660b05 100644
--- a/drivers/net/phy/Kconfig
+++ b/drivers/net/phy/Kconfig
@@ -201,6 +201,12 @@ config MARVELL_10G_PHY
help
Support for the Marvell Alaska MV88X3310 and compatible PHYs.
+config MARVELL_88X_PHY
+ tristate "Marvell 88X PHY"
+ help
+ Support for the Marvell 88X Dual-port Multi-speed Ethernet
+ Transceiver.
+
config MICREL_PHY
tristate "Micrel PHYs"
help
diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile
index a13e402074cf..de683e3abe63 100644
--- a/drivers/net/phy/Makefile
+++ b/drivers/net/phy/Makefile
@@ -63,6 +63,7 @@ obj-$(CONFIG_LSI_ET1011C_PHY) += et1011c.o
obj-$(CONFIG_LXT_PHY) += lxt.o
obj-$(CONFIG_MARVELL_10G_PHY) += marvell10g.o
obj-$(CONFIG_MARVELL_PHY) += marvell.o
+obj-$(CONFIG_MARVELL_88X_PHY) += marvell-88x.o
obj-$(CONFIG_MESON_GXL_PHY)+= meson-gxl.o
obj-$(CONFIG_MICREL_KS8995MA) += spi_ks8995.o
obj-$(CONFIG_MICREL_PHY) += micrel.o
diff --git a/drivers/net/phy/marvell-88x.c
b/drivers/net/phy/marvell-88x.c
new file mode 100644
index ..aec7e299c165
--- /dev/null
+++ b/drivers/net/phy/marvell-88x.c
@@ -0,0 +1,533 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Marvell 88x dual-port multi-speed ethernet transceiver.
+ *
+ * Supports:
+ * XAUI on the host side.
+ * 1000Base-X or 10GBase-R on the line side.
+ * SGMII over 1000Base-X.
+ */
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+/* Port PCS Configuration */
+#defineMV_PCS_CONFIG 0xF002
+#defineMV_PCS_HOST_XAUI0x73
+#defineMV_PCS_LINE_10GBR (0x71 << 8)
+#defineMV_PCS_LINE_1GBX_AN (0x7B << 8)
+#defineMV_PCS_LINE_SGMII_AN(0x7F << 8)
+
+/* Port Reset and Power Down */
+#defineMV_PORT_RST 0xF003
+#defineMV_LINE_RST_SW BIT(15)
+#defineMV_HOST_RST_SW BIT(7)
+#defineMV_PORT_RST_SW (MV_LINE_RST_SW | MV_HOST_RST_SW)
+
+/* 1000Base-X/SGMII Control Register */
+#defineMV_1GBX_CTRL(0x2000 + MII_BMCR)
+
+/* 1000BASE-X/SGMII Status Register */
+#defineMV_1GBX_STAT(0x2000 + MII_BMSR)
+
+/* 1000Base-X Auto-Negotiation Advertisement Register */
+#defineMV_1GBX_ADVERTISE (0x2000 + MII_ADVERTISE)
+
+/* 1000Base-X PHY Specific Status Register */
+#defineMV_1GBX_PHY_STAT0xA003
+#defineMV_1GBX_PHY_STAT_AN_RESOLVEDBIT(11)
+#defineMV_1GBX_PHY_STAT_DUPLEX BIT(13)
+#defineMV_1GBX_PHY_STAT_SPEED100 BIT(14)
+#defineMV_1GBX_PHY_STAT_SPEED1000 BIT(15)
+
+struct mv_data {
+ phy_interface_t line_interface;
+ __ETHTOOL_DECLARE_LINK_MODE_MASK(supported);
+};
+
+/* SFI PMA transmit enable */
+static int mv_tx_enable(struct phy_device *phydev)
+{
+ return phy_clear_bits_mmd(phydev, MDIO_MMD_PMAPMD, MDIO_PMA_TXDIS,
+ MDIO_PMD_TXDIS_GLOBAL);
+}
+
+/* SFI PMA transmit disable */
+static int mv_tx_disable(struct phy_device *phydev)
+{
+ return phy_set_bits_mmd(phydev, MDIO_MMD_PMAPMD, MDIO_PMA_TXDIS,
+ MDIO_PMD_TXDIS_GLOBAL);
+}
+
+static int mv_soft_reset(struct phy_device *phydev)
+{
+ int val, ret;
+
+ ret = phy_write_mmd(phydev, MDIO_MMD_VEND2, MV_PORT_RST,
+ MV_PORT_RST_SW);
+ if (ret < 0)
+ return ret;
+
+ return phy_read_mmd_poll_timeout(phydev, MDIO_MMD_VEND2, MV_PORT_RST,
+val, !(val & MV_PORT_RST_SW),
+5000, 100, true);
+}
+
+/* Returns negative on error, 0 if link is down, 1 if link is up */
+static int mv_read_status_10g(struct phy_device *phydev)
+{
+ int val, link = 0;
+
+ val = phy_read_mmd(phydev,