1a2443fd1SAndrew Lunn // SPDX-License-Identifier: GPL-2.0+ 200db8189SAndy Fleming /* 300db8189SAndy Fleming * drivers/net/phy/marvell.c 400db8189SAndy Fleming * 500db8189SAndy Fleming * Driver for Marvell PHYs 600db8189SAndy Fleming * 700db8189SAndy Fleming * Author: Andy Fleming 800db8189SAndy Fleming * 900db8189SAndy Fleming * Copyright (c) 2004 Freescale Semiconductor, Inc. 1000db8189SAndy Fleming * 113871c387SMichael Stapelberg * Copyright (c) 2013 Michael Stapelberg <michael@stapelberg.de> 1200db8189SAndy Fleming */ 1300db8189SAndy Fleming #include <linux/kernel.h> 1400db8189SAndy Fleming #include <linux/string.h> 150b04680fSAndrew Lunn #include <linux/ctype.h> 1600db8189SAndy Fleming #include <linux/errno.h> 1700db8189SAndy Fleming #include <linux/unistd.h> 180b04680fSAndrew Lunn #include <linux/hwmon.h> 1900db8189SAndy Fleming #include <linux/interrupt.h> 2000db8189SAndy Fleming #include <linux/init.h> 2100db8189SAndy Fleming #include <linux/delay.h> 2200db8189SAndy Fleming #include <linux/netdevice.h> 2300db8189SAndy Fleming #include <linux/etherdevice.h> 2400db8189SAndy Fleming #include <linux/skbuff.h> 2500db8189SAndy Fleming #include <linux/spinlock.h> 2600db8189SAndy Fleming #include <linux/mm.h> 2700db8189SAndy Fleming #include <linux/module.h> 2800db8189SAndy Fleming #include <linux/mii.h> 2900db8189SAndy Fleming #include <linux/ethtool.h> 3000db8189SAndy Fleming #include <linux/phy.h> 312f495c39SBenjamin Herrenschmidt #include <linux/marvell_phy.h> 3269f42be8SHeiner Kallweit #include <linux/bitfield.h> 33cf41a51dSDavid Daney #include <linux/of.h> 3400db8189SAndy Fleming 35eea3b201SAvinash Kumar #include <linux/io.h> 3600db8189SAndy Fleming #include <asm/irq.h> 37eea3b201SAvinash Kumar #include <linux/uaccess.h> 3800db8189SAndy Fleming 3927d916d6SDavid Daney #define MII_MARVELL_PHY_PAGE 22 4052295666SAndrew Lunn #define MII_MARVELL_COPPER_PAGE 0x00 4152295666SAndrew Lunn #define MII_MARVELL_FIBER_PAGE 0x01 4252295666SAndrew Lunn #define MII_MARVELL_MSCR_PAGE 0x02 4352295666SAndrew Lunn #define MII_MARVELL_LED_PAGE 0x03 4452295666SAndrew Lunn #define MII_MARVELL_MISC_TEST_PAGE 0x06 4552295666SAndrew Lunn #define MII_MARVELL_WOL_PAGE 0x11 4627d916d6SDavid Daney 4700db8189SAndy Fleming #define MII_M1011_IEVENT 0x13 4800db8189SAndy Fleming #define MII_M1011_IEVENT_CLEAR 0x0000 4900db8189SAndy Fleming 5000db8189SAndy Fleming #define MII_M1011_IMASK 0x12 5100db8189SAndy Fleming #define MII_M1011_IMASK_INIT 0x6400 5200db8189SAndy Fleming #define MII_M1011_IMASK_CLEAR 0x0000 5300db8189SAndy Fleming 5476884679SAndy Fleming #define MII_M1011_PHY_SCR 0x10 55fecd5e91SAndrew Lunn #define MII_M1011_PHY_SCR_DOWNSHIFT_EN BIT(11) 56f8d975beSHeiner Kallweit #define MII_M1011_PHY_SCR_DOWNSHIFT_MASK GENMASK(14, 12) 57a3bdfce7SHeiner Kallweit #define MII_M1011_PHY_SCR_DOWNSHIFT_MAX 8 58fecd5e91SAndrew Lunn #define MII_M1011_PHY_SCR_MDI (0x0 << 5) 59fecd5e91SAndrew Lunn #define MII_M1011_PHY_SCR_MDI_X (0x1 << 5) 60fecd5e91SAndrew Lunn #define MII_M1011_PHY_SCR_AUTO_CROSS (0x3 << 5) 6176884679SAndy Fleming 62a3bdfce7SHeiner Kallweit #define MII_M1011_PHY_SSR 0x11 63a3bdfce7SHeiner Kallweit #define MII_M1011_PHY_SSR_DOWNSHIFT BIT(5) 64a3bdfce7SHeiner Kallweit 6576884679SAndy Fleming #define MII_M1111_PHY_LED_CONTROL 0x18 6676884679SAndy Fleming #define MII_M1111_PHY_LED_DIRECT 0x4100 6776884679SAndy Fleming #define MII_M1111_PHY_LED_COMBINE 0x411c 68895ee682SKim Phillips #define MII_M1111_PHY_EXT_CR 0x14 695c6bc519SHeiner Kallweit #define MII_M1111_PHY_EXT_CR_DOWNSHIFT_MASK GENMASK(11, 9) 705c6bc519SHeiner Kallweit #define MII_M1111_PHY_EXT_CR_DOWNSHIFT_MAX 8 715c6bc519SHeiner Kallweit #define MII_M1111_PHY_EXT_CR_DOWNSHIFT_EN BIT(8) 7261111598SAndrew Lunn #define MII_M1111_RGMII_RX_DELAY BIT(7) 7361111598SAndrew Lunn #define MII_M1111_RGMII_TX_DELAY BIT(1) 74895ee682SKim Phillips #define MII_M1111_PHY_EXT_SR 0x1b 75be937f1fSAlexandr Smirnov 76895ee682SKim Phillips #define MII_M1111_HWCFG_MODE_MASK 0xf 77be937f1fSAlexandr Smirnov #define MII_M1111_HWCFG_MODE_FIBER_RGMII 0x3 784117b5beSKapil Juneja #define MII_M1111_HWCFG_MODE_SGMII_NO_CLK 0x4 79865b813aSAndrew Lunn #define MII_M1111_HWCFG_MODE_RTBI 0x7 805f8cbc13SLiu Yu-B13201 #define MII_M1111_HWCFG_MODE_COPPER_RTBI 0x9 81865b813aSAndrew Lunn #define MII_M1111_HWCFG_MODE_COPPER_RGMII 0xb 82865b813aSAndrew Lunn #define MII_M1111_HWCFG_FIBER_COPPER_RES BIT(13) 83865b813aSAndrew Lunn #define MII_M1111_HWCFG_FIBER_COPPER_AUTO BIT(15) 84be937f1fSAlexandr Smirnov 85c477d044SCyril Chemparathy #define MII_88E1121_PHY_MSCR_REG 21 86c477d044SCyril Chemparathy #define MII_88E1121_PHY_MSCR_RX_DELAY BIT(5) 87c477d044SCyril Chemparathy #define MII_88E1121_PHY_MSCR_TX_DELAY BIT(4) 88424ca4c5SRussell King #define MII_88E1121_PHY_MSCR_DELAY_MASK (BIT(5) | BIT(4)) 89c477d044SCyril Chemparathy 900b04680fSAndrew Lunn #define MII_88E1121_MISC_TEST 0x1a 910b04680fSAndrew Lunn #define MII_88E1510_MISC_TEST_TEMP_THRESHOLD_MASK 0x1f00 920b04680fSAndrew Lunn #define MII_88E1510_MISC_TEST_TEMP_THRESHOLD_SHIFT 8 930b04680fSAndrew Lunn #define MII_88E1510_MISC_TEST_TEMP_IRQ_EN BIT(7) 940b04680fSAndrew Lunn #define MII_88E1510_MISC_TEST_TEMP_IRQ BIT(6) 950b04680fSAndrew Lunn #define MII_88E1121_MISC_TEST_TEMP_SENSOR_EN BIT(5) 960b04680fSAndrew Lunn #define MII_88E1121_MISC_TEST_TEMP_MASK 0x1f 970b04680fSAndrew Lunn 980b04680fSAndrew Lunn #define MII_88E1510_TEMP_SENSOR 0x1b 990b04680fSAndrew Lunn #define MII_88E1510_TEMP_SENSOR_MASK 0xff 1000b04680fSAndrew Lunn 10169f42be8SHeiner Kallweit #define MII_88E1540_COPPER_CTRL3 0x1a 10269f42be8SHeiner Kallweit #define MII_88E1540_COPPER_CTRL3_LINK_DOWN_DELAY_MASK GENMASK(11, 10) 10369f42be8SHeiner Kallweit #define MII_88E1540_COPPER_CTRL3_LINK_DOWN_DELAY_00MS 0 10469f42be8SHeiner Kallweit #define MII_88E1540_COPPER_CTRL3_LINK_DOWN_DELAY_10MS 1 10569f42be8SHeiner Kallweit #define MII_88E1540_COPPER_CTRL3_LINK_DOWN_DELAY_20MS 2 10669f42be8SHeiner Kallweit #define MII_88E1540_COPPER_CTRL3_LINK_DOWN_DELAY_40MS 3 10769f42be8SHeiner Kallweit #define MII_88E1540_COPPER_CTRL3_FAST_LINK_DOWN BIT(9) 10869f42be8SHeiner Kallweit 109fee2d546SAndrew Lunn #define MII_88E6390_MISC_TEST 0x1b 110fee2d546SAndrew Lunn #define MII_88E6390_MISC_TEST_SAMPLE_1S 0 111fee2d546SAndrew Lunn #define MII_88E6390_MISC_TEST_SAMPLE_10MS BIT(14) 112fee2d546SAndrew Lunn #define MII_88E6390_MISC_TEST_SAMPLE_DISABLE BIT(15) 113fee2d546SAndrew Lunn #define MII_88E6390_MISC_TEST_SAMPLE_ENABLE 0 114fee2d546SAndrew Lunn #define MII_88E6390_MISC_TEST_SAMPLE_MASK (0x3 << 14) 115fee2d546SAndrew Lunn 116fee2d546SAndrew Lunn #define MII_88E6390_TEMP_SENSOR 0x1c 117fee2d546SAndrew Lunn #define MII_88E6390_TEMP_SENSOR_MASK 0xff 118fee2d546SAndrew Lunn #define MII_88E6390_TEMP_SENSOR_SAMPLES 10 119fee2d546SAndrew Lunn 120337ac9d5SCyril Chemparathy #define MII_88E1318S_PHY_MSCR1_REG 16 121337ac9d5SCyril Chemparathy #define MII_88E1318S_PHY_MSCR1_PAD_ODD BIT(6) 1223ff1c259SCyril Chemparathy 1233871c387SMichael Stapelberg /* Copper Specific Interrupt Enable Register */ 1243871c387SMichael Stapelberg #define MII_88E1318S_PHY_CSIER 0x12 1253871c387SMichael Stapelberg /* WOL Event Interrupt Enable */ 1263871c387SMichael Stapelberg #define MII_88E1318S_PHY_CSIER_WOL_EIE BIT(7) 1273871c387SMichael Stapelberg 1283871c387SMichael Stapelberg /* LED Timer Control Register */ 1293871c387SMichael Stapelberg #define MII_88E1318S_PHY_LED_TCR 0x12 1303871c387SMichael Stapelberg #define MII_88E1318S_PHY_LED_TCR_FORCE_INT BIT(15) 1313871c387SMichael Stapelberg #define MII_88E1318S_PHY_LED_TCR_INTn_ENABLE BIT(7) 1323871c387SMichael Stapelberg #define MII_88E1318S_PHY_LED_TCR_INT_ACTIVE_LOW BIT(11) 1333871c387SMichael Stapelberg 1343871c387SMichael Stapelberg /* Magic Packet MAC address registers */ 1353871c387SMichael Stapelberg #define MII_88E1318S_PHY_MAGIC_PACKET_WORD2 0x17 1363871c387SMichael Stapelberg #define MII_88E1318S_PHY_MAGIC_PACKET_WORD1 0x18 1373871c387SMichael Stapelberg #define MII_88E1318S_PHY_MAGIC_PACKET_WORD0 0x19 1383871c387SMichael Stapelberg 1393871c387SMichael Stapelberg #define MII_88E1318S_PHY_WOL_CTRL 0x10 1403871c387SMichael Stapelberg #define MII_88E1318S_PHY_WOL_CTRL_CLEAR_WOL_STATUS BIT(12) 1413871c387SMichael Stapelberg #define MII_88E1318S_PHY_WOL_CTRL_MAGIC_PACKET_MATCH_ENABLE BIT(14) 1423871c387SMichael Stapelberg 14307777246SWang Dongsheng #define MII_PHY_LED_CTRL 16 144140bc929SSergei Poselenov #define MII_88E1121_PHY_LED_DEF 0x0030 14507777246SWang Dongsheng #define MII_88E1510_PHY_LED_DEF 0x1177 146a93f7fe1SJian Shen #define MII_88E1510_PHY_LED0_LINK_LED1_ACTIVE 0x1040 147140bc929SSergei Poselenov 148be937f1fSAlexandr Smirnov #define MII_M1011_PHY_STATUS 0x11 149be937f1fSAlexandr Smirnov #define MII_M1011_PHY_STATUS_1000 0x8000 150be937f1fSAlexandr Smirnov #define MII_M1011_PHY_STATUS_100 0x4000 151be937f1fSAlexandr Smirnov #define MII_M1011_PHY_STATUS_SPD_MASK 0xc000 152be937f1fSAlexandr Smirnov #define MII_M1011_PHY_STATUS_FULLDUPLEX 0x2000 153be937f1fSAlexandr Smirnov #define MII_M1011_PHY_STATUS_RESOLVED 0x0800 154be937f1fSAlexandr Smirnov #define MII_M1011_PHY_STATUS_LINK 0x0400 155be937f1fSAlexandr Smirnov 1566b358aedSSebastian Hesselbarth #define MII_88E3016_PHY_SPEC_CTRL 0x10 1576b358aedSSebastian Hesselbarth #define MII_88E3016_DISABLE_SCRAMBLER 0x0200 1586b358aedSSebastian Hesselbarth #define MII_88E3016_AUTO_MDIX_CROSSOVER 0x0030 15976884679SAndy Fleming 160930b37eeSStefan Roese #define MII_88E1510_GEN_CTRL_REG_1 0x14 161930b37eeSStefan Roese #define MII_88E1510_GEN_CTRL_REG_1_MODE_MASK 0x7 162930b37eeSStefan Roese #define MII_88E1510_GEN_CTRL_REG_1_MODE_SGMII 0x1 /* SGMII to copper */ 163930b37eeSStefan Roese #define MII_88E1510_GEN_CTRL_REG_1_RESET 0x8000 /* Soft reset */ 164930b37eeSStefan Roese 1656cfb3bccSCharles-Antoine Couret #define LPA_PAUSE_FIBER 0x180 1666cfb3bccSCharles-Antoine Couret #define LPA_PAUSE_ASYM_FIBER 0x100 1676cfb3bccSCharles-Antoine Couret 1682170fef7SCharles-Antoine Couret #define NB_FIBER_STATS 1 1696cfb3bccSCharles-Antoine Couret 17000db8189SAndy Fleming MODULE_DESCRIPTION("Marvell PHY driver"); 17100db8189SAndy Fleming MODULE_AUTHOR("Andy Fleming"); 17200db8189SAndy Fleming MODULE_LICENSE("GPL"); 17300db8189SAndy Fleming 174d2fa47d9SAndrew Lunn struct marvell_hw_stat { 175d2fa47d9SAndrew Lunn const char *string; 176d2fa47d9SAndrew Lunn u8 page; 177d2fa47d9SAndrew Lunn u8 reg; 178d2fa47d9SAndrew Lunn u8 bits; 179d2fa47d9SAndrew Lunn }; 180d2fa47d9SAndrew Lunn 181d2fa47d9SAndrew Lunn static struct marvell_hw_stat marvell_hw_stats[] = { 1822170fef7SCharles-Antoine Couret { "phy_receive_errors_copper", 0, 21, 16}, 183d2fa47d9SAndrew Lunn { "phy_idle_errors", 0, 10, 8 }, 1842170fef7SCharles-Antoine Couret { "phy_receive_errors_fiber", 1, 21, 16}, 185d2fa47d9SAndrew Lunn }; 186d2fa47d9SAndrew Lunn 187d2fa47d9SAndrew Lunn struct marvell_priv { 188d2fa47d9SAndrew Lunn u64 stats[ARRAY_SIZE(marvell_hw_stats)]; 1890b04680fSAndrew Lunn char *hwmon_name; 1900b04680fSAndrew Lunn struct device *hwmon_dev; 191d2fa47d9SAndrew Lunn }; 192d2fa47d9SAndrew Lunn 193424ca4c5SRussell King static int marvell_read_page(struct phy_device *phydev) 1946427bb2dSAndrew Lunn { 195424ca4c5SRussell King return __phy_read(phydev, MII_MARVELL_PHY_PAGE); 196424ca4c5SRussell King } 197424ca4c5SRussell King 198424ca4c5SRussell King static int marvell_write_page(struct phy_device *phydev, int page) 199424ca4c5SRussell King { 200424ca4c5SRussell King return __phy_write(phydev, MII_MARVELL_PHY_PAGE, page); 2016427bb2dSAndrew Lunn } 2026427bb2dSAndrew Lunn 2036427bb2dSAndrew Lunn static int marvell_set_page(struct phy_device *phydev, int page) 2046427bb2dSAndrew Lunn { 2056427bb2dSAndrew Lunn return phy_write(phydev, MII_MARVELL_PHY_PAGE, page); 2066427bb2dSAndrew Lunn } 2076427bb2dSAndrew Lunn 20800db8189SAndy Fleming static int marvell_ack_interrupt(struct phy_device *phydev) 20900db8189SAndy Fleming { 21000db8189SAndy Fleming int err; 21100db8189SAndy Fleming 21200db8189SAndy Fleming /* Clear the interrupts by reading the reg */ 21300db8189SAndy Fleming err = phy_read(phydev, MII_M1011_IEVENT); 21400db8189SAndy Fleming 21500db8189SAndy Fleming if (err < 0) 21600db8189SAndy Fleming return err; 21700db8189SAndy Fleming 21800db8189SAndy Fleming return 0; 21900db8189SAndy Fleming } 22000db8189SAndy Fleming 22100db8189SAndy Fleming static int marvell_config_intr(struct phy_device *phydev) 22200db8189SAndy Fleming { 22300db8189SAndy Fleming int err; 22400db8189SAndy Fleming 22500db8189SAndy Fleming if (phydev->interrupts == PHY_INTERRUPT_ENABLED) 22623beb38fSAndrew Lunn err = phy_write(phydev, MII_M1011_IMASK, 22723beb38fSAndrew Lunn MII_M1011_IMASK_INIT); 22800db8189SAndy Fleming else 22923beb38fSAndrew Lunn err = phy_write(phydev, MII_M1011_IMASK, 23023beb38fSAndrew Lunn MII_M1011_IMASK_CLEAR); 23100db8189SAndy Fleming 23200db8189SAndy Fleming return err; 23300db8189SAndy Fleming } 23400db8189SAndy Fleming 235239aa55bSDavid Thomson static int marvell_set_polarity(struct phy_device *phydev, int polarity) 236239aa55bSDavid Thomson { 237239aa55bSDavid Thomson int reg; 238239aa55bSDavid Thomson int err; 239239aa55bSDavid Thomson int val; 240239aa55bSDavid Thomson 241239aa55bSDavid Thomson /* get the current settings */ 242239aa55bSDavid Thomson reg = phy_read(phydev, MII_M1011_PHY_SCR); 243239aa55bSDavid Thomson if (reg < 0) 244239aa55bSDavid Thomson return reg; 245239aa55bSDavid Thomson 246239aa55bSDavid Thomson val = reg; 247239aa55bSDavid Thomson val &= ~MII_M1011_PHY_SCR_AUTO_CROSS; 248239aa55bSDavid Thomson switch (polarity) { 249239aa55bSDavid Thomson case ETH_TP_MDI: 250239aa55bSDavid Thomson val |= MII_M1011_PHY_SCR_MDI; 251239aa55bSDavid Thomson break; 252239aa55bSDavid Thomson case ETH_TP_MDI_X: 253239aa55bSDavid Thomson val |= MII_M1011_PHY_SCR_MDI_X; 254239aa55bSDavid Thomson break; 255239aa55bSDavid Thomson case ETH_TP_MDI_AUTO: 256239aa55bSDavid Thomson case ETH_TP_MDI_INVALID: 257239aa55bSDavid Thomson default: 258239aa55bSDavid Thomson val |= MII_M1011_PHY_SCR_AUTO_CROSS; 259239aa55bSDavid Thomson break; 260239aa55bSDavid Thomson } 261239aa55bSDavid Thomson 262239aa55bSDavid Thomson if (val != reg) { 263239aa55bSDavid Thomson /* Set the new polarity value in the register */ 264239aa55bSDavid Thomson err = phy_write(phydev, MII_M1011_PHY_SCR, val); 265239aa55bSDavid Thomson if (err) 266239aa55bSDavid Thomson return err; 267239aa55bSDavid Thomson } 268239aa55bSDavid Thomson 269d6ab9336SFlorian Fainelli return val != reg; 270239aa55bSDavid Thomson } 271239aa55bSDavid Thomson 27200db8189SAndy Fleming static int marvell_config_aneg(struct phy_device *phydev) 27300db8189SAndy Fleming { 274d6ab9336SFlorian Fainelli int changed = 0; 27500db8189SAndy Fleming int err; 27600db8189SAndy Fleming 2774e26c5c3SRaju Lakkaraju err = marvell_set_polarity(phydev, phydev->mdix_ctrl); 27876884679SAndy Fleming if (err < 0) 27976884679SAndy Fleming return err; 28076884679SAndy Fleming 281d6ab9336SFlorian Fainelli changed = err; 282d6ab9336SFlorian Fainelli 28376884679SAndy Fleming err = phy_write(phydev, MII_M1111_PHY_LED_CONTROL, 28476884679SAndy Fleming MII_M1111_PHY_LED_DIRECT); 28576884679SAndy Fleming if (err < 0) 28676884679SAndy Fleming return err; 28700db8189SAndy Fleming 28800db8189SAndy Fleming err = genphy_config_aneg(phydev); 2898ff44985SAnton Vorontsov if (err < 0) 29000db8189SAndy Fleming return err; 2918ff44985SAnton Vorontsov 292d6ab9336SFlorian Fainelli if (phydev->autoneg != AUTONEG_ENABLE || changed) { 2930c3439bcSAndrew Lunn /* A write to speed/duplex bits (that is performed by 2948ff44985SAnton Vorontsov * genphy_config_aneg() call above) must be followed by 2958ff44985SAnton Vorontsov * a software reset. Otherwise, the write has no effect. 2968ff44985SAnton Vorontsov */ 29734386344SAndrew Lunn err = genphy_soft_reset(phydev); 2988ff44985SAnton Vorontsov if (err < 0) 2998ff44985SAnton Vorontsov return err; 3008ff44985SAnton Vorontsov } 3018ff44985SAnton Vorontsov 3028ff44985SAnton Vorontsov return 0; 30300db8189SAndy Fleming } 30400db8189SAndy Fleming 305f2899788SAndrew Lunn static int m88e1101_config_aneg(struct phy_device *phydev) 306f2899788SAndrew Lunn { 307f2899788SAndrew Lunn int err; 308f2899788SAndrew Lunn 309f2899788SAndrew Lunn /* This Marvell PHY has an errata which requires 310f2899788SAndrew Lunn * that certain registers get written in order 311f2899788SAndrew Lunn * to restart autonegotiation 312f2899788SAndrew Lunn */ 31334386344SAndrew Lunn err = genphy_soft_reset(phydev); 314f2899788SAndrew Lunn if (err < 0) 315f2899788SAndrew Lunn return err; 316f2899788SAndrew Lunn 317f2899788SAndrew Lunn err = phy_write(phydev, 0x1d, 0x1f); 318f2899788SAndrew Lunn if (err < 0) 319f2899788SAndrew Lunn return err; 320f2899788SAndrew Lunn 321f2899788SAndrew Lunn err = phy_write(phydev, 0x1e, 0x200c); 322f2899788SAndrew Lunn if (err < 0) 323f2899788SAndrew Lunn return err; 324f2899788SAndrew Lunn 325f2899788SAndrew Lunn err = phy_write(phydev, 0x1d, 0x5); 326f2899788SAndrew Lunn if (err < 0) 327f2899788SAndrew Lunn return err; 328f2899788SAndrew Lunn 329f2899788SAndrew Lunn err = phy_write(phydev, 0x1e, 0); 330f2899788SAndrew Lunn if (err < 0) 331f2899788SAndrew Lunn return err; 332f2899788SAndrew Lunn 333f2899788SAndrew Lunn err = phy_write(phydev, 0x1e, 0x100); 334f2899788SAndrew Lunn if (err < 0) 335f2899788SAndrew Lunn return err; 336f2899788SAndrew Lunn 337f2899788SAndrew Lunn return marvell_config_aneg(phydev); 338f2899788SAndrew Lunn } 339f2899788SAndrew Lunn 340cf41a51dSDavid Daney #ifdef CONFIG_OF_MDIO 3410c3439bcSAndrew Lunn /* Set and/or override some configuration registers based on the 342cf41a51dSDavid Daney * marvell,reg-init property stored in the of_node for the phydev. 343cf41a51dSDavid Daney * 344cf41a51dSDavid Daney * marvell,reg-init = <reg-page reg mask value>,...; 345cf41a51dSDavid Daney * 346cf41a51dSDavid Daney * There may be one or more sets of <reg-page reg mask value>: 347cf41a51dSDavid Daney * 348cf41a51dSDavid Daney * reg-page: which register bank to use. 349cf41a51dSDavid Daney * reg: the register. 350cf41a51dSDavid Daney * mask: if non-zero, ANDed with existing register value. 351cf41a51dSDavid Daney * value: ORed with the masked value and written to the regiser. 352cf41a51dSDavid Daney * 353cf41a51dSDavid Daney */ 354cf41a51dSDavid Daney static int marvell_of_reg_init(struct phy_device *phydev) 355cf41a51dSDavid Daney { 356cf41a51dSDavid Daney const __be32 *paddr; 357424ca4c5SRussell King int len, i, saved_page, current_page, ret = 0; 358cf41a51dSDavid Daney 359e5a03bfdSAndrew Lunn if (!phydev->mdio.dev.of_node) 360cf41a51dSDavid Daney return 0; 361cf41a51dSDavid Daney 362e5a03bfdSAndrew Lunn paddr = of_get_property(phydev->mdio.dev.of_node, 363e5a03bfdSAndrew Lunn "marvell,reg-init", &len); 364cf41a51dSDavid Daney if (!paddr || len < (4 * sizeof(*paddr))) 365cf41a51dSDavid Daney return 0; 366cf41a51dSDavid Daney 367424ca4c5SRussell King saved_page = phy_save_page(phydev); 368cf41a51dSDavid Daney if (saved_page < 0) 369424ca4c5SRussell King goto err; 370cf41a51dSDavid Daney current_page = saved_page; 371cf41a51dSDavid Daney 372cf41a51dSDavid Daney len /= sizeof(*paddr); 373cf41a51dSDavid Daney for (i = 0; i < len - 3; i += 4) { 3746427bb2dSAndrew Lunn u16 page = be32_to_cpup(paddr + i); 375cf41a51dSDavid Daney u16 reg = be32_to_cpup(paddr + i + 1); 376cf41a51dSDavid Daney u16 mask = be32_to_cpup(paddr + i + 2); 377cf41a51dSDavid Daney u16 val_bits = be32_to_cpup(paddr + i + 3); 378cf41a51dSDavid Daney int val; 379cf41a51dSDavid Daney 3806427bb2dSAndrew Lunn if (page != current_page) { 3816427bb2dSAndrew Lunn current_page = page; 382424ca4c5SRussell King ret = marvell_write_page(phydev, page); 383cf41a51dSDavid Daney if (ret < 0) 384cf41a51dSDavid Daney goto err; 385cf41a51dSDavid Daney } 386cf41a51dSDavid Daney 387cf41a51dSDavid Daney val = 0; 388cf41a51dSDavid Daney if (mask) { 389424ca4c5SRussell King val = __phy_read(phydev, reg); 390cf41a51dSDavid Daney if (val < 0) { 391cf41a51dSDavid Daney ret = val; 392cf41a51dSDavid Daney goto err; 393cf41a51dSDavid Daney } 394cf41a51dSDavid Daney val &= mask; 395cf41a51dSDavid Daney } 396cf41a51dSDavid Daney val |= val_bits; 397cf41a51dSDavid Daney 398424ca4c5SRussell King ret = __phy_write(phydev, reg, val); 399cf41a51dSDavid Daney if (ret < 0) 400cf41a51dSDavid Daney goto err; 401cf41a51dSDavid Daney } 402cf41a51dSDavid Daney err: 403424ca4c5SRussell King return phy_restore_page(phydev, saved_page, ret); 404cf41a51dSDavid Daney } 405cf41a51dSDavid Daney #else 406cf41a51dSDavid Daney static int marvell_of_reg_init(struct phy_device *phydev) 407cf41a51dSDavid Daney { 408cf41a51dSDavid Daney return 0; 409cf41a51dSDavid Daney } 410cf41a51dSDavid Daney #endif /* CONFIG_OF_MDIO */ 411cf41a51dSDavid Daney 412864dc729SAndrew Lunn static int m88e1121_config_aneg_rgmii_delays(struct phy_device *phydev) 413140bc929SSergei Poselenov { 414424ca4c5SRussell King int mscr; 415c477d044SCyril Chemparathy 416c477d044SCyril Chemparathy if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID) 417424ca4c5SRussell King mscr = MII_88E1121_PHY_MSCR_RX_DELAY | 418424ca4c5SRussell King MII_88E1121_PHY_MSCR_TX_DELAY; 419c477d044SCyril Chemparathy else if (phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID) 420424ca4c5SRussell King mscr = MII_88E1121_PHY_MSCR_RX_DELAY; 421c477d044SCyril Chemparathy else if (phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID) 422424ca4c5SRussell King mscr = MII_88E1121_PHY_MSCR_TX_DELAY; 423424ca4c5SRussell King else 424424ca4c5SRussell King mscr = 0; 425c477d044SCyril Chemparathy 426424ca4c5SRussell King return phy_modify_paged(phydev, MII_MARVELL_MSCR_PAGE, 427424ca4c5SRussell King MII_88E1121_PHY_MSCR_REG, 428424ca4c5SRussell King MII_88E1121_PHY_MSCR_DELAY_MASK, mscr); 429be8c6480SArnaud Patard } 430c477d044SCyril Chemparathy 431864dc729SAndrew Lunn static int m88e1121_config_aneg(struct phy_device *phydev) 432864dc729SAndrew Lunn { 433d6ab9336SFlorian Fainelli int changed = 0; 434864dc729SAndrew Lunn int err = 0; 435864dc729SAndrew Lunn 436864dc729SAndrew Lunn if (phy_interface_is_rgmii(phydev)) { 437864dc729SAndrew Lunn err = m88e1121_config_aneg_rgmii_delays(phydev); 438fea23fb5SRussell King if (err < 0) 439864dc729SAndrew Lunn return err; 440864dc729SAndrew Lunn } 441140bc929SSergei Poselenov 442fecd5e91SAndrew Lunn err = marvell_set_polarity(phydev, phydev->mdix_ctrl); 443140bc929SSergei Poselenov if (err < 0) 444140bc929SSergei Poselenov return err; 445140bc929SSergei Poselenov 446d6ab9336SFlorian Fainelli changed = err; 447d6ab9336SFlorian Fainelli 448d6ab9336SFlorian Fainelli err = genphy_config_aneg(phydev); 449d6ab9336SFlorian Fainelli if (err < 0) 450d6ab9336SFlorian Fainelli return err; 451d6ab9336SFlorian Fainelli 4524b1bd697SDavid S. Miller if (phydev->autoneg != AUTONEG_ENABLE || changed) { 453d6ab9336SFlorian Fainelli /* A software reset is used to ensure a "commit" of the 454d6ab9336SFlorian Fainelli * changes is done. 455d6ab9336SFlorian Fainelli */ 456d6ab9336SFlorian Fainelli err = genphy_soft_reset(phydev); 457d6ab9336SFlorian Fainelli if (err < 0) 458d6ab9336SFlorian Fainelli return err; 459d6ab9336SFlorian Fainelli } 460d6ab9336SFlorian Fainelli 461d6ab9336SFlorian Fainelli return 0; 462140bc929SSergei Poselenov } 463140bc929SSergei Poselenov 464337ac9d5SCyril Chemparathy static int m88e1318_config_aneg(struct phy_device *phydev) 4653ff1c259SCyril Chemparathy { 466424ca4c5SRussell King int err; 4673ff1c259SCyril Chemparathy 468424ca4c5SRussell King err = phy_modify_paged(phydev, MII_MARVELL_MSCR_PAGE, 469424ca4c5SRussell King MII_88E1318S_PHY_MSCR1_REG, 470424ca4c5SRussell King 0, MII_88E1318S_PHY_MSCR1_PAD_ODD); 4713ff1c259SCyril Chemparathy if (err < 0) 4723ff1c259SCyril Chemparathy return err; 4733ff1c259SCyril Chemparathy 4743ff1c259SCyril Chemparathy return m88e1121_config_aneg(phydev); 4753ff1c259SCyril Chemparathy } 4763ff1c259SCyril Chemparathy 47778301ebeSCharles-Antoine Couret /** 4783c1bcc86SAndrew Lunn * linkmode_adv_to_fiber_adv_t 4793c1bcc86SAndrew Lunn * @advertise: the linkmode advertisement settings 48078301ebeSCharles-Antoine Couret * 4813c1bcc86SAndrew Lunn * A small helper function that translates linkmode advertisement 4823c1bcc86SAndrew Lunn * settings to phy autonegotiation advertisements for the MII_ADV 4833c1bcc86SAndrew Lunn * register for fiber link. 48478301ebeSCharles-Antoine Couret */ 4853c1bcc86SAndrew Lunn static inline u32 linkmode_adv_to_fiber_adv_t(unsigned long *advertise) 48678301ebeSCharles-Antoine Couret { 48778301ebeSCharles-Antoine Couret u32 result = 0; 48878301ebeSCharles-Antoine Couret 4893c1bcc86SAndrew Lunn if (linkmode_test_bit(ETHTOOL_LINK_MODE_1000baseT_Half_BIT, advertise)) 49020ecf424SRussell King result |= ADVERTISE_1000XHALF; 4913c1bcc86SAndrew Lunn if (linkmode_test_bit(ETHTOOL_LINK_MODE_1000baseT_Full_BIT, advertise)) 49220ecf424SRussell King result |= ADVERTISE_1000XFULL; 49378301ebeSCharles-Antoine Couret 4943c1bcc86SAndrew Lunn if (linkmode_test_bit(ETHTOOL_LINK_MODE_Asym_Pause_BIT, advertise) && 4953c1bcc86SAndrew Lunn linkmode_test_bit(ETHTOOL_LINK_MODE_Pause_BIT, advertise)) 49620ecf424SRussell King result |= ADVERTISE_1000XPSE_ASYM; 4973c1bcc86SAndrew Lunn else if (linkmode_test_bit(ETHTOOL_LINK_MODE_Pause_BIT, advertise)) 49820ecf424SRussell King result |= ADVERTISE_1000XPAUSE; 49978301ebeSCharles-Antoine Couret 50078301ebeSCharles-Antoine Couret return result; 50178301ebeSCharles-Antoine Couret } 50278301ebeSCharles-Antoine Couret 50378301ebeSCharles-Antoine Couret /** 50478301ebeSCharles-Antoine Couret * marvell_config_aneg_fiber - restart auto-negotiation or write BMCR 50578301ebeSCharles-Antoine Couret * @phydev: target phy_device struct 50678301ebeSCharles-Antoine Couret * 50778301ebeSCharles-Antoine Couret * Description: If auto-negotiation is enabled, we configure the 50878301ebeSCharles-Antoine Couret * advertising, and then restart auto-negotiation. If it is not 50978301ebeSCharles-Antoine Couret * enabled, then we write the BMCR. Adapted for fiber link in 51078301ebeSCharles-Antoine Couret * some Marvell's devices. 51178301ebeSCharles-Antoine Couret */ 51278301ebeSCharles-Antoine Couret static int marvell_config_aneg_fiber(struct phy_device *phydev) 51378301ebeSCharles-Antoine Couret { 51478301ebeSCharles-Antoine Couret int changed = 0; 51578301ebeSCharles-Antoine Couret int err; 5169f4bae70SRussell King u16 adv; 51778301ebeSCharles-Antoine Couret 51878301ebeSCharles-Antoine Couret if (phydev->autoneg != AUTONEG_ENABLE) 51978301ebeSCharles-Antoine Couret return genphy_setup_forced(phydev); 52078301ebeSCharles-Antoine Couret 52178301ebeSCharles-Antoine Couret /* Only allow advertising what this PHY supports */ 5223c1bcc86SAndrew Lunn linkmode_and(phydev->advertising, phydev->advertising, 5233c1bcc86SAndrew Lunn phydev->supported); 52478301ebeSCharles-Antoine Couret 5259f4bae70SRussell King adv = linkmode_adv_to_fiber_adv_t(phydev->advertising); 5269f4bae70SRussell King 52778301ebeSCharles-Antoine Couret /* Setup fiber advertisement */ 5289f4bae70SRussell King err = phy_modify_changed(phydev, MII_ADVERTISE, 5299f4bae70SRussell King ADVERTISE_1000XHALF | ADVERTISE_1000XFULL | 5309f4bae70SRussell King ADVERTISE_1000XPAUSE | ADVERTISE_1000XPSE_ASYM, 5319f4bae70SRussell King adv); 53278301ebeSCharles-Antoine Couret if (err < 0) 53378301ebeSCharles-Antoine Couret return err; 5349f4bae70SRussell King if (err > 0) 53578301ebeSCharles-Antoine Couret changed = 1; 53678301ebeSCharles-Antoine Couret 537b5abac2dSRussell King return genphy_check_and_restart_aneg(phydev, changed); 53878301ebeSCharles-Antoine Couret } 53978301ebeSCharles-Antoine Couret 54010e24caaSMichal Simek static int m88e1510_config_aneg(struct phy_device *phydev) 54110e24caaSMichal Simek { 54210e24caaSMichal Simek int err; 54310e24caaSMichal Simek 54452295666SAndrew Lunn err = marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE); 54578301ebeSCharles-Antoine Couret if (err < 0) 54678301ebeSCharles-Antoine Couret goto error; 54778301ebeSCharles-Antoine Couret 54878301ebeSCharles-Antoine Couret /* Configure the copper link first */ 54910e24caaSMichal Simek err = m88e1318_config_aneg(phydev); 55010e24caaSMichal Simek if (err < 0) 55178301ebeSCharles-Antoine Couret goto error; 55210e24caaSMichal Simek 553de9c4e06SRussell King /* Do not touch the fiber page if we're in copper->sgmii mode */ 554de9c4e06SRussell King if (phydev->interface == PHY_INTERFACE_MODE_SGMII) 555de9c4e06SRussell King return 0; 556de9c4e06SRussell King 55778301ebeSCharles-Antoine Couret /* Then the fiber link */ 55852295666SAndrew Lunn err = marvell_set_page(phydev, MII_MARVELL_FIBER_PAGE); 55978301ebeSCharles-Antoine Couret if (err < 0) 56078301ebeSCharles-Antoine Couret goto error; 56178301ebeSCharles-Antoine Couret 56278301ebeSCharles-Antoine Couret err = marvell_config_aneg_fiber(phydev); 56378301ebeSCharles-Antoine Couret if (err < 0) 56478301ebeSCharles-Antoine Couret goto error; 56578301ebeSCharles-Antoine Couret 56652295666SAndrew Lunn return marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE); 56778301ebeSCharles-Antoine Couret 56878301ebeSCharles-Antoine Couret error: 56952295666SAndrew Lunn marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE); 57078301ebeSCharles-Antoine Couret return err; 57179be1a1cSClemens Gruber } 57279be1a1cSClemens Gruber 57307777246SWang Dongsheng static void marvell_config_led(struct phy_device *phydev) 57407777246SWang Dongsheng { 57507777246SWang Dongsheng u16 def_config; 57607777246SWang Dongsheng int err; 57707777246SWang Dongsheng 57807777246SWang Dongsheng switch (MARVELL_PHY_FAMILY_ID(phydev->phy_id)) { 57907777246SWang Dongsheng /* Default PHY LED config: LED[0] .. Link, LED[1] .. Activity */ 58007777246SWang Dongsheng case MARVELL_PHY_FAMILY_ID(MARVELL_PHY_ID_88E1121R): 58107777246SWang Dongsheng case MARVELL_PHY_FAMILY_ID(MARVELL_PHY_ID_88E1318S): 58207777246SWang Dongsheng def_config = MII_88E1121_PHY_LED_DEF; 58307777246SWang Dongsheng break; 58407777246SWang Dongsheng /* Default PHY LED config: 58507777246SWang Dongsheng * LED[0] .. 1000Mbps Link 58607777246SWang Dongsheng * LED[1] .. 100Mbps Link 58707777246SWang Dongsheng * LED[2] .. Blink, Activity 58807777246SWang Dongsheng */ 58907777246SWang Dongsheng case MARVELL_PHY_FAMILY_ID(MARVELL_PHY_ID_88E1510): 590a93f7fe1SJian Shen if (phydev->dev_flags & MARVELL_PHY_LED0_LINK_LED1_ACTIVE) 591a93f7fe1SJian Shen def_config = MII_88E1510_PHY_LED0_LINK_LED1_ACTIVE; 592a93f7fe1SJian Shen else 59307777246SWang Dongsheng def_config = MII_88E1510_PHY_LED_DEF; 59407777246SWang Dongsheng break; 59507777246SWang Dongsheng default: 59607777246SWang Dongsheng return; 59707777246SWang Dongsheng } 59807777246SWang Dongsheng 59907777246SWang Dongsheng err = phy_write_paged(phydev, MII_MARVELL_LED_PAGE, MII_PHY_LED_CTRL, 60007777246SWang Dongsheng def_config); 60107777246SWang Dongsheng if (err < 0) 602ab2a605fSAndrew Lunn phydev_warn(phydev, "Fail to config marvell phy LED.\n"); 60307777246SWang Dongsheng } 60407777246SWang Dongsheng 60579be1a1cSClemens Gruber static int marvell_config_init(struct phy_device *phydev) 60679be1a1cSClemens Gruber { 60707777246SWang Dongsheng /* Set defalut LED */ 60807777246SWang Dongsheng marvell_config_led(phydev); 60907777246SWang Dongsheng 61079be1a1cSClemens Gruber /* Set registers from marvell,reg-init DT property */ 61110e24caaSMichal Simek return marvell_of_reg_init(phydev); 61210e24caaSMichal Simek } 61310e24caaSMichal Simek 6146b358aedSSebastian Hesselbarth static int m88e3016_config_init(struct phy_device *phydev) 6156b358aedSSebastian Hesselbarth { 616fea23fb5SRussell King int ret; 6176b358aedSSebastian Hesselbarth 6186b358aedSSebastian Hesselbarth /* Enable Scrambler and Auto-Crossover */ 619fea23fb5SRussell King ret = phy_modify(phydev, MII_88E3016_PHY_SPEC_CTRL, 620f102852fSRussell King MII_88E3016_DISABLE_SCRAMBLER, 621fea23fb5SRussell King MII_88E3016_AUTO_MDIX_CROSSOVER); 622fea23fb5SRussell King if (ret < 0) 623fea23fb5SRussell King return ret; 6246b358aedSSebastian Hesselbarth 62579be1a1cSClemens Gruber return marvell_config_init(phydev); 6266b358aedSSebastian Hesselbarth } 6276b358aedSSebastian Hesselbarth 628865b813aSAndrew Lunn static int m88e1111_config_init_hwcfg_mode(struct phy_device *phydev, 629865b813aSAndrew Lunn u16 mode, 630865b813aSAndrew Lunn int fibre_copper_auto) 631865b813aSAndrew Lunn { 632865b813aSAndrew Lunn if (fibre_copper_auto) 633fea23fb5SRussell King mode |= MII_M1111_HWCFG_FIBER_COPPER_AUTO; 634865b813aSAndrew Lunn 635fea23fb5SRussell King return phy_modify(phydev, MII_M1111_PHY_EXT_SR, 636f102852fSRussell King MII_M1111_HWCFG_MODE_MASK | 637fea23fb5SRussell King MII_M1111_HWCFG_FIBER_COPPER_AUTO | 638f102852fSRussell King MII_M1111_HWCFG_FIBER_COPPER_RES, 639fea23fb5SRussell King mode); 640865b813aSAndrew Lunn } 641865b813aSAndrew Lunn 64261111598SAndrew Lunn static int m88e1111_config_init_rgmii_delays(struct phy_device *phydev) 643895ee682SKim Phillips { 644fea23fb5SRussell King int delay; 645895ee682SKim Phillips 6469daf5a76SKim Phillips if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID) { 647fea23fb5SRussell King delay = MII_M1111_RGMII_RX_DELAY | MII_M1111_RGMII_TX_DELAY; 6489daf5a76SKim Phillips } else if (phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID) { 649fea23fb5SRussell King delay = MII_M1111_RGMII_RX_DELAY; 6509daf5a76SKim Phillips } else if (phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID) { 651fea23fb5SRussell King delay = MII_M1111_RGMII_TX_DELAY; 652fea23fb5SRussell King } else { 653fea23fb5SRussell King delay = 0; 6549daf5a76SKim Phillips } 655895ee682SKim Phillips 656fea23fb5SRussell King return phy_modify(phydev, MII_M1111_PHY_EXT_CR, 657f102852fSRussell King MII_M1111_RGMII_RX_DELAY | MII_M1111_RGMII_TX_DELAY, 658fea23fb5SRussell King delay); 65961111598SAndrew Lunn } 66061111598SAndrew Lunn 66161111598SAndrew Lunn static int m88e1111_config_init_rgmii(struct phy_device *phydev) 66261111598SAndrew Lunn { 66361111598SAndrew Lunn int temp; 66461111598SAndrew Lunn int err; 66561111598SAndrew Lunn 66661111598SAndrew Lunn err = m88e1111_config_init_rgmii_delays(phydev); 667895ee682SKim Phillips if (err < 0) 668895ee682SKim Phillips return err; 669895ee682SKim Phillips 670895ee682SKim Phillips temp = phy_read(phydev, MII_M1111_PHY_EXT_SR); 671895ee682SKim Phillips if (temp < 0) 672895ee682SKim Phillips return temp; 673895ee682SKim Phillips 674895ee682SKim Phillips temp &= ~(MII_M1111_HWCFG_MODE_MASK); 675be937f1fSAlexandr Smirnov 6767239016dSWang Jian if (temp & MII_M1111_HWCFG_FIBER_COPPER_RES) 677be937f1fSAlexandr Smirnov temp |= MII_M1111_HWCFG_MODE_FIBER_RGMII; 678be937f1fSAlexandr Smirnov else 679be937f1fSAlexandr Smirnov temp |= MII_M1111_HWCFG_MODE_COPPER_RGMII; 680895ee682SKim Phillips 681e1dde8dcSAndrew Lunn return phy_write(phydev, MII_M1111_PHY_EXT_SR, temp); 682895ee682SKim Phillips } 683895ee682SKim Phillips 684e1dde8dcSAndrew Lunn static int m88e1111_config_init_sgmii(struct phy_device *phydev) 685e1dde8dcSAndrew Lunn { 686e1dde8dcSAndrew Lunn int err; 687e1dde8dcSAndrew Lunn 688865b813aSAndrew Lunn err = m88e1111_config_init_hwcfg_mode( 689865b813aSAndrew Lunn phydev, 690865b813aSAndrew Lunn MII_M1111_HWCFG_MODE_SGMII_NO_CLK, 691865b813aSAndrew Lunn MII_M1111_HWCFG_FIBER_COPPER_AUTO); 6924117b5beSKapil Juneja if (err < 0) 6934117b5beSKapil Juneja return err; 69407151bc9SMadalin Bucur 69507151bc9SMadalin Bucur /* make sure copper is selected */ 69652295666SAndrew Lunn return marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE); 6974117b5beSKapil Juneja } 6984117b5beSKapil Juneja 699e1dde8dcSAndrew Lunn static int m88e1111_config_init_rtbi(struct phy_device *phydev) 700e1dde8dcSAndrew Lunn { 70161111598SAndrew Lunn int err; 702e1dde8dcSAndrew Lunn 70361111598SAndrew Lunn err = m88e1111_config_init_rgmii_delays(phydev); 704fea23fb5SRussell King if (err < 0) 7055f8cbc13SLiu Yu-B13201 return err; 7065f8cbc13SLiu Yu-B13201 707865b813aSAndrew Lunn err = m88e1111_config_init_hwcfg_mode( 708865b813aSAndrew Lunn phydev, 709865b813aSAndrew Lunn MII_M1111_HWCFG_MODE_RTBI, 710865b813aSAndrew Lunn MII_M1111_HWCFG_FIBER_COPPER_AUTO); 7115f8cbc13SLiu Yu-B13201 if (err < 0) 7125f8cbc13SLiu Yu-B13201 return err; 7135f8cbc13SLiu Yu-B13201 7145f8cbc13SLiu Yu-B13201 /* soft reset */ 71534386344SAndrew Lunn err = genphy_soft_reset(phydev); 7165f8cbc13SLiu Yu-B13201 if (err < 0) 7175f8cbc13SLiu Yu-B13201 return err; 718e1dde8dcSAndrew Lunn 719865b813aSAndrew Lunn return m88e1111_config_init_hwcfg_mode( 720865b813aSAndrew Lunn phydev, 721865b813aSAndrew Lunn MII_M1111_HWCFG_MODE_RTBI, 722865b813aSAndrew Lunn MII_M1111_HWCFG_FIBER_COPPER_AUTO); 723e1dde8dcSAndrew Lunn } 724e1dde8dcSAndrew Lunn 725e1dde8dcSAndrew Lunn static int m88e1111_config_init(struct phy_device *phydev) 726e1dde8dcSAndrew Lunn { 727e1dde8dcSAndrew Lunn int err; 728e1dde8dcSAndrew Lunn 729e1dde8dcSAndrew Lunn if (phy_interface_is_rgmii(phydev)) { 730e1dde8dcSAndrew Lunn err = m88e1111_config_init_rgmii(phydev); 731fea23fb5SRussell King if (err < 0) 732e1dde8dcSAndrew Lunn return err; 733e1dde8dcSAndrew Lunn } 734e1dde8dcSAndrew Lunn 735e1dde8dcSAndrew Lunn if (phydev->interface == PHY_INTERFACE_MODE_SGMII) { 736e1dde8dcSAndrew Lunn err = m88e1111_config_init_sgmii(phydev); 737e1dde8dcSAndrew Lunn if (err < 0) 738e1dde8dcSAndrew Lunn return err; 739e1dde8dcSAndrew Lunn } 740e1dde8dcSAndrew Lunn 741e1dde8dcSAndrew Lunn if (phydev->interface == PHY_INTERFACE_MODE_RTBI) { 742e1dde8dcSAndrew Lunn err = m88e1111_config_init_rtbi(phydev); 7435f8cbc13SLiu Yu-B13201 if (err < 0) 7445f8cbc13SLiu Yu-B13201 return err; 7455f8cbc13SLiu Yu-B13201 } 7465f8cbc13SLiu Yu-B13201 747cf41a51dSDavid Daney err = marvell_of_reg_init(phydev); 748cf41a51dSDavid Daney if (err < 0) 749cf41a51dSDavid Daney return err; 7505f8cbc13SLiu Yu-B13201 75134386344SAndrew Lunn return genphy_soft_reset(phydev); 752895ee682SKim Phillips } 753895ee682SKim Phillips 7545c6bc519SHeiner Kallweit static int m88e1111_get_downshift(struct phy_device *phydev, u8 *data) 7555c6bc519SHeiner Kallweit { 7565c6bc519SHeiner Kallweit int val, cnt, enable; 7575c6bc519SHeiner Kallweit 7585c6bc519SHeiner Kallweit val = phy_read(phydev, MII_M1111_PHY_EXT_CR); 7595c6bc519SHeiner Kallweit if (val < 0) 7605c6bc519SHeiner Kallweit return val; 7615c6bc519SHeiner Kallweit 7625c6bc519SHeiner Kallweit enable = FIELD_GET(MII_M1111_PHY_EXT_CR_DOWNSHIFT_EN, val); 7635c6bc519SHeiner Kallweit cnt = FIELD_GET(MII_M1111_PHY_EXT_CR_DOWNSHIFT_MASK, val) + 1; 7645c6bc519SHeiner Kallweit 7655c6bc519SHeiner Kallweit *data = enable ? cnt : DOWNSHIFT_DEV_DISABLE; 7665c6bc519SHeiner Kallweit 7675c6bc519SHeiner Kallweit return 0; 7685c6bc519SHeiner Kallweit } 7695c6bc519SHeiner Kallweit 7705c6bc519SHeiner Kallweit static int m88e1111_set_downshift(struct phy_device *phydev, u8 cnt) 7715c6bc519SHeiner Kallweit { 7725c6bc519SHeiner Kallweit int val; 7735c6bc519SHeiner Kallweit 7745c6bc519SHeiner Kallweit if (cnt > MII_M1111_PHY_EXT_CR_DOWNSHIFT_MAX) 7755c6bc519SHeiner Kallweit return -E2BIG; 7765c6bc519SHeiner Kallweit 7775c6bc519SHeiner Kallweit if (!cnt) 7785c6bc519SHeiner Kallweit return phy_clear_bits(phydev, MII_M1111_PHY_EXT_CR, 7795c6bc519SHeiner Kallweit MII_M1111_PHY_EXT_CR_DOWNSHIFT_EN); 7805c6bc519SHeiner Kallweit 7815c6bc519SHeiner Kallweit val = MII_M1111_PHY_EXT_CR_DOWNSHIFT_EN; 7825c6bc519SHeiner Kallweit val |= FIELD_PREP(MII_M1111_PHY_EXT_CR_DOWNSHIFT_MASK, cnt - 1); 7835c6bc519SHeiner Kallweit 7845c6bc519SHeiner Kallweit return phy_modify(phydev, MII_M1111_PHY_EXT_CR, 7855c6bc519SHeiner Kallweit MII_M1111_PHY_EXT_CR_DOWNSHIFT_EN | 7865c6bc519SHeiner Kallweit MII_M1111_PHY_EXT_CR_DOWNSHIFT_MASK, 7875c6bc519SHeiner Kallweit val); 7885c6bc519SHeiner Kallweit } 7895c6bc519SHeiner Kallweit 7905c6bc519SHeiner Kallweit static int m88e1111_get_tunable(struct phy_device *phydev, 7915c6bc519SHeiner Kallweit struct ethtool_tunable *tuna, void *data) 7925c6bc519SHeiner Kallweit { 7935c6bc519SHeiner Kallweit switch (tuna->id) { 7945c6bc519SHeiner Kallweit case ETHTOOL_PHY_DOWNSHIFT: 7955c6bc519SHeiner Kallweit return m88e1111_get_downshift(phydev, data); 7965c6bc519SHeiner Kallweit default: 7975c6bc519SHeiner Kallweit return -EOPNOTSUPP; 7985c6bc519SHeiner Kallweit } 7995c6bc519SHeiner Kallweit } 8005c6bc519SHeiner Kallweit 8015c6bc519SHeiner Kallweit static int m88e1111_set_tunable(struct phy_device *phydev, 8025c6bc519SHeiner Kallweit struct ethtool_tunable *tuna, const void *data) 8035c6bc519SHeiner Kallweit { 8045c6bc519SHeiner Kallweit switch (tuna->id) { 8055c6bc519SHeiner Kallweit case ETHTOOL_PHY_DOWNSHIFT: 8065c6bc519SHeiner Kallweit return m88e1111_set_downshift(phydev, *(const u8 *)data); 8075c6bc519SHeiner Kallweit default: 8085c6bc519SHeiner Kallweit return -EOPNOTSUPP; 8095c6bc519SHeiner Kallweit } 8105c6bc519SHeiner Kallweit } 8115c6bc519SHeiner Kallweit 812911af5e1SHeiner Kallweit static int m88e1011_get_downshift(struct phy_device *phydev, u8 *data) 813a3bdfce7SHeiner Kallweit { 814a3bdfce7SHeiner Kallweit int val, cnt, enable; 815a3bdfce7SHeiner Kallweit 816a3bdfce7SHeiner Kallweit val = phy_read(phydev, MII_M1011_PHY_SCR); 817a3bdfce7SHeiner Kallweit if (val < 0) 818a3bdfce7SHeiner Kallweit return val; 819a3bdfce7SHeiner Kallweit 820a3bdfce7SHeiner Kallweit enable = FIELD_GET(MII_M1011_PHY_SCR_DOWNSHIFT_EN, val); 821f8d975beSHeiner Kallweit cnt = FIELD_GET(MII_M1011_PHY_SCR_DOWNSHIFT_MASK, val) + 1; 822a3bdfce7SHeiner Kallweit 823a3bdfce7SHeiner Kallweit *data = enable ? cnt : DOWNSHIFT_DEV_DISABLE; 824a3bdfce7SHeiner Kallweit 825a3bdfce7SHeiner Kallweit return 0; 826a3bdfce7SHeiner Kallweit } 827a3bdfce7SHeiner Kallweit 828911af5e1SHeiner Kallweit static int m88e1011_set_downshift(struct phy_device *phydev, u8 cnt) 829a3bdfce7SHeiner Kallweit { 830a3bdfce7SHeiner Kallweit int val; 831a3bdfce7SHeiner Kallweit 832a3bdfce7SHeiner Kallweit if (cnt > MII_M1011_PHY_SCR_DOWNSHIFT_MAX) 833a3bdfce7SHeiner Kallweit return -E2BIG; 834a3bdfce7SHeiner Kallweit 835a3bdfce7SHeiner Kallweit if (!cnt) 836a3bdfce7SHeiner Kallweit return phy_clear_bits(phydev, MII_M1011_PHY_SCR, 837a3bdfce7SHeiner Kallweit MII_M1011_PHY_SCR_DOWNSHIFT_EN); 838a3bdfce7SHeiner Kallweit 839a3bdfce7SHeiner Kallweit val = MII_M1011_PHY_SCR_DOWNSHIFT_EN; 840f8d975beSHeiner Kallweit val |= FIELD_PREP(MII_M1011_PHY_SCR_DOWNSHIFT_MASK, cnt - 1); 841a3bdfce7SHeiner Kallweit 842a3bdfce7SHeiner Kallweit return phy_modify(phydev, MII_M1011_PHY_SCR, 843a3bdfce7SHeiner Kallweit MII_M1011_PHY_SCR_DOWNSHIFT_EN | 844f8d975beSHeiner Kallweit MII_M1011_PHY_SCR_DOWNSHIFT_MASK, 845a3bdfce7SHeiner Kallweit val); 846a3bdfce7SHeiner Kallweit } 847a3bdfce7SHeiner Kallweit 848911af5e1SHeiner Kallweit static int m88e1011_get_tunable(struct phy_device *phydev, 849a3bdfce7SHeiner Kallweit struct ethtool_tunable *tuna, void *data) 850a3bdfce7SHeiner Kallweit { 851a3bdfce7SHeiner Kallweit switch (tuna->id) { 852a3bdfce7SHeiner Kallweit case ETHTOOL_PHY_DOWNSHIFT: 853911af5e1SHeiner Kallweit return m88e1011_get_downshift(phydev, data); 854a3bdfce7SHeiner Kallweit default: 855a3bdfce7SHeiner Kallweit return -EOPNOTSUPP; 856a3bdfce7SHeiner Kallweit } 857a3bdfce7SHeiner Kallweit } 858a3bdfce7SHeiner Kallweit 859911af5e1SHeiner Kallweit static int m88e1011_set_tunable(struct phy_device *phydev, 860a3bdfce7SHeiner Kallweit struct ethtool_tunable *tuna, const void *data) 861a3bdfce7SHeiner Kallweit { 862a3bdfce7SHeiner Kallweit switch (tuna->id) { 863a3bdfce7SHeiner Kallweit case ETHTOOL_PHY_DOWNSHIFT: 864911af5e1SHeiner Kallweit return m88e1011_set_downshift(phydev, *(const u8 *)data); 865a3bdfce7SHeiner Kallweit default: 866a3bdfce7SHeiner Kallweit return -EOPNOTSUPP; 867a3bdfce7SHeiner Kallweit } 868a3bdfce7SHeiner Kallweit } 869a3bdfce7SHeiner Kallweit 870911af5e1SHeiner Kallweit static void m88e1011_link_change_notify(struct phy_device *phydev) 871a3bdfce7SHeiner Kallweit { 872a3bdfce7SHeiner Kallweit int status; 873a3bdfce7SHeiner Kallweit 874a3bdfce7SHeiner Kallweit if (phydev->state != PHY_RUNNING) 875a3bdfce7SHeiner Kallweit return; 876a3bdfce7SHeiner Kallweit 877a3bdfce7SHeiner Kallweit /* we may be on fiber page currently */ 878a3bdfce7SHeiner Kallweit status = phy_read_paged(phydev, MII_MARVELL_COPPER_PAGE, 879a3bdfce7SHeiner Kallweit MII_M1011_PHY_SSR); 880a3bdfce7SHeiner Kallweit 881a3bdfce7SHeiner Kallweit if (status > 0 && status & MII_M1011_PHY_SSR_DOWNSHIFT) 882a3bdfce7SHeiner Kallweit phydev_warn(phydev, "Downshift occurred! Cabling may be defective.\n"); 883a3bdfce7SHeiner Kallweit } 884a3bdfce7SHeiner Kallweit 885e2d861ccSHeiner Kallweit static int m88e1116r_config_init(struct phy_device *phydev) 886e2d861ccSHeiner Kallweit { 887e2d861ccSHeiner Kallweit int err; 888e2d861ccSHeiner Kallweit 889e2d861ccSHeiner Kallweit err = genphy_soft_reset(phydev); 890e2d861ccSHeiner Kallweit if (err < 0) 891e2d861ccSHeiner Kallweit return err; 892e2d861ccSHeiner Kallweit 893e2d861ccSHeiner Kallweit msleep(500); 894e2d861ccSHeiner Kallweit 895e2d861ccSHeiner Kallweit err = marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE); 896e2d861ccSHeiner Kallweit if (err < 0) 897e2d861ccSHeiner Kallweit return err; 898e2d861ccSHeiner Kallweit 899e2d861ccSHeiner Kallweit err = marvell_set_polarity(phydev, phydev->mdix_ctrl); 900e2d861ccSHeiner Kallweit if (err < 0) 901e2d861ccSHeiner Kallweit return err; 902e2d861ccSHeiner Kallweit 903911af5e1SHeiner Kallweit err = m88e1011_set_downshift(phydev, 8); 904e2d861ccSHeiner Kallweit if (err < 0) 905e2d861ccSHeiner Kallweit return err; 906e2d861ccSHeiner Kallweit 907e2d861ccSHeiner Kallweit if (phy_interface_is_rgmii(phydev)) { 908e2d861ccSHeiner Kallweit err = m88e1121_config_aneg_rgmii_delays(phydev); 909e2d861ccSHeiner Kallweit if (err < 0) 910e2d861ccSHeiner Kallweit return err; 911e2d861ccSHeiner Kallweit } 912e2d861ccSHeiner Kallweit 913e2d861ccSHeiner Kallweit err = genphy_soft_reset(phydev); 914e2d861ccSHeiner Kallweit if (err < 0) 915e2d861ccSHeiner Kallweit return err; 916e2d861ccSHeiner Kallweit 917e2d861ccSHeiner Kallweit return marvell_config_init(phydev); 918e2d861ccSHeiner Kallweit } 919e2d861ccSHeiner Kallweit 920dd9a122aSEsben Haabendal static int m88e1318_config_init(struct phy_device *phydev) 921dd9a122aSEsben Haabendal { 922dd9a122aSEsben Haabendal if (phy_interrupt_is_valid(phydev)) { 923dd9a122aSEsben Haabendal int err = phy_modify_paged( 924dd9a122aSEsben Haabendal phydev, MII_MARVELL_LED_PAGE, 925dd9a122aSEsben Haabendal MII_88E1318S_PHY_LED_TCR, 926dd9a122aSEsben Haabendal MII_88E1318S_PHY_LED_TCR_FORCE_INT, 927dd9a122aSEsben Haabendal MII_88E1318S_PHY_LED_TCR_INTn_ENABLE | 928dd9a122aSEsben Haabendal MII_88E1318S_PHY_LED_TCR_INT_ACTIVE_LOW); 929dd9a122aSEsben Haabendal if (err < 0) 930dd9a122aSEsben Haabendal return err; 931dd9a122aSEsben Haabendal } 932dd9a122aSEsben Haabendal 93307777246SWang Dongsheng return marvell_config_init(phydev); 934dd9a122aSEsben Haabendal } 935dd9a122aSEsben Haabendal 936407353ecSClemens Gruber static int m88e1510_config_init(struct phy_device *phydev) 937407353ecSClemens Gruber { 938407353ecSClemens Gruber int err; 939407353ecSClemens Gruber 940407353ecSClemens Gruber /* SGMII-to-Copper mode initialization */ 941407353ecSClemens Gruber if (phydev->interface == PHY_INTERFACE_MODE_SGMII) { 942407353ecSClemens Gruber /* Select page 18 */ 9436427bb2dSAndrew Lunn err = marvell_set_page(phydev, 18); 944407353ecSClemens Gruber if (err < 0) 945407353ecSClemens Gruber return err; 946407353ecSClemens Gruber 947407353ecSClemens Gruber /* In reg 20, write MODE[2:0] = 0x1 (SGMII to Copper) */ 948fea23fb5SRussell King err = phy_modify(phydev, MII_88E1510_GEN_CTRL_REG_1, 949f102852fSRussell King MII_88E1510_GEN_CTRL_REG_1_MODE_MASK, 950fea23fb5SRussell King MII_88E1510_GEN_CTRL_REG_1_MODE_SGMII); 951407353ecSClemens Gruber if (err < 0) 952407353ecSClemens Gruber return err; 953407353ecSClemens Gruber 954407353ecSClemens Gruber /* PHY reset is necessary after changing MODE[2:0] */ 955fea23fb5SRussell King err = phy_modify(phydev, MII_88E1510_GEN_CTRL_REG_1, 0, 956fea23fb5SRussell King MII_88E1510_GEN_CTRL_REG_1_RESET); 957407353ecSClemens Gruber if (err < 0) 958407353ecSClemens Gruber return err; 959407353ecSClemens Gruber 960407353ecSClemens Gruber /* Reset page selection */ 96152295666SAndrew Lunn err = marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE); 962407353ecSClemens Gruber if (err < 0) 963407353ecSClemens Gruber return err; 964407353ecSClemens Gruber } 965407353ecSClemens Gruber 966dd9a122aSEsben Haabendal return m88e1318_config_init(phydev); 967407353ecSClemens Gruber } 968407353ecSClemens Gruber 969605f196eSRon Madrid static int m88e1118_config_aneg(struct phy_device *phydev) 970605f196eSRon Madrid { 971605f196eSRon Madrid int err; 972605f196eSRon Madrid 97334386344SAndrew Lunn err = genphy_soft_reset(phydev); 974605f196eSRon Madrid if (err < 0) 975605f196eSRon Madrid return err; 976605f196eSRon Madrid 977fecd5e91SAndrew Lunn err = marvell_set_polarity(phydev, phydev->mdix_ctrl); 978605f196eSRon Madrid if (err < 0) 979605f196eSRon Madrid return err; 980605f196eSRon Madrid 981605f196eSRon Madrid err = genphy_config_aneg(phydev); 982605f196eSRon Madrid return 0; 983605f196eSRon Madrid } 984605f196eSRon Madrid 985605f196eSRon Madrid static int m88e1118_config_init(struct phy_device *phydev) 986605f196eSRon Madrid { 987605f196eSRon Madrid int err; 988605f196eSRon Madrid 989605f196eSRon Madrid /* Change address */ 99052295666SAndrew Lunn err = marvell_set_page(phydev, MII_MARVELL_MSCR_PAGE); 991605f196eSRon Madrid if (err < 0) 992605f196eSRon Madrid return err; 993605f196eSRon Madrid 994605f196eSRon Madrid /* Enable 1000 Mbit */ 995605f196eSRon Madrid err = phy_write(phydev, 0x15, 0x1070); 996605f196eSRon Madrid if (err < 0) 997605f196eSRon Madrid return err; 998605f196eSRon Madrid 999605f196eSRon Madrid /* Change address */ 100052295666SAndrew Lunn err = marvell_set_page(phydev, MII_MARVELL_LED_PAGE); 1001605f196eSRon Madrid if (err < 0) 1002605f196eSRon Madrid return err; 1003605f196eSRon Madrid 1004605f196eSRon Madrid /* Adjust LED Control */ 10052f495c39SBenjamin Herrenschmidt if (phydev->dev_flags & MARVELL_PHY_M1118_DNS323_LEDS) 10062f495c39SBenjamin Herrenschmidt err = phy_write(phydev, 0x10, 0x1100); 10072f495c39SBenjamin Herrenschmidt else 1008605f196eSRon Madrid err = phy_write(phydev, 0x10, 0x021e); 1009605f196eSRon Madrid if (err < 0) 1010605f196eSRon Madrid return err; 1011605f196eSRon Madrid 1012cf41a51dSDavid Daney err = marvell_of_reg_init(phydev); 1013cf41a51dSDavid Daney if (err < 0) 1014cf41a51dSDavid Daney return err; 1015cf41a51dSDavid Daney 1016605f196eSRon Madrid /* Reset address */ 101752295666SAndrew Lunn err = marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE); 1018605f196eSRon Madrid if (err < 0) 1019605f196eSRon Madrid return err; 1020605f196eSRon Madrid 102134386344SAndrew Lunn return genphy_soft_reset(phydev); 1022605f196eSRon Madrid } 1023605f196eSRon Madrid 102490600732SDavid Daney static int m88e1149_config_init(struct phy_device *phydev) 102590600732SDavid Daney { 102690600732SDavid Daney int err; 102790600732SDavid Daney 102890600732SDavid Daney /* Change address */ 102952295666SAndrew Lunn err = marvell_set_page(phydev, MII_MARVELL_MSCR_PAGE); 103090600732SDavid Daney if (err < 0) 103190600732SDavid Daney return err; 103290600732SDavid Daney 103390600732SDavid Daney /* Enable 1000 Mbit */ 103490600732SDavid Daney err = phy_write(phydev, 0x15, 0x1048); 103590600732SDavid Daney if (err < 0) 103690600732SDavid Daney return err; 103790600732SDavid Daney 1038cf41a51dSDavid Daney err = marvell_of_reg_init(phydev); 1039cf41a51dSDavid Daney if (err < 0) 1040cf41a51dSDavid Daney return err; 1041cf41a51dSDavid Daney 104290600732SDavid Daney /* Reset address */ 104352295666SAndrew Lunn err = marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE); 104490600732SDavid Daney if (err < 0) 104590600732SDavid Daney return err; 104690600732SDavid Daney 104734386344SAndrew Lunn return genphy_soft_reset(phydev); 104890600732SDavid Daney } 104990600732SDavid Daney 1050e1dde8dcSAndrew Lunn static int m88e1145_config_init_rgmii(struct phy_device *phydev) 105176884679SAndy Fleming { 105276884679SAndy Fleming int err; 1053e69d9ed4SAndrew Lunn 105461111598SAndrew Lunn err = m88e1111_config_init_rgmii_delays(phydev); 105576884679SAndy Fleming if (err < 0) 105676884679SAndy Fleming return err; 105776884679SAndy Fleming 10582f495c39SBenjamin Herrenschmidt if (phydev->dev_flags & MARVELL_PHY_M1145_FLAGS_RESISTANCE) { 105976884679SAndy Fleming err = phy_write(phydev, 0x1d, 0x0012); 106076884679SAndy Fleming if (err < 0) 106176884679SAndy Fleming return err; 106276884679SAndy Fleming 1063f102852fSRussell King err = phy_modify(phydev, 0x1e, 0x0fc0, 1064fea23fb5SRussell King 2 << 9 | /* 36 ohm */ 1065fea23fb5SRussell King 2 << 6); /* 39 ohm */ 106676884679SAndy Fleming if (err < 0) 106776884679SAndy Fleming return err; 106876884679SAndy Fleming 106976884679SAndy Fleming err = phy_write(phydev, 0x1d, 0x3); 107076884679SAndy Fleming if (err < 0) 107176884679SAndy Fleming return err; 107276884679SAndy Fleming 107376884679SAndy Fleming err = phy_write(phydev, 0x1e, 0x8000); 1074e1dde8dcSAndrew Lunn } 107576884679SAndy Fleming return err; 107676884679SAndy Fleming } 107776884679SAndy Fleming 1078e1dde8dcSAndrew Lunn static int m88e1145_config_init_sgmii(struct phy_device *phydev) 1079e1dde8dcSAndrew Lunn { 1080865b813aSAndrew Lunn return m88e1111_config_init_hwcfg_mode( 1081865b813aSAndrew Lunn phydev, MII_M1111_HWCFG_MODE_SGMII_NO_CLK, 1082865b813aSAndrew Lunn MII_M1111_HWCFG_FIBER_COPPER_AUTO); 1083e1dde8dcSAndrew Lunn } 1084e1dde8dcSAndrew Lunn 1085e1dde8dcSAndrew Lunn static int m88e1145_config_init(struct phy_device *phydev) 1086e1dde8dcSAndrew Lunn { 1087e1dde8dcSAndrew Lunn int err; 1088e1dde8dcSAndrew Lunn 1089e1dde8dcSAndrew Lunn /* Take care of errata E0 & E1 */ 1090e1dde8dcSAndrew Lunn err = phy_write(phydev, 0x1d, 0x001b); 1091e1dde8dcSAndrew Lunn if (err < 0) 1092e1dde8dcSAndrew Lunn return err; 1093e1dde8dcSAndrew Lunn 1094e1dde8dcSAndrew Lunn err = phy_write(phydev, 0x1e, 0x418f); 1095e1dde8dcSAndrew Lunn if (err < 0) 1096e1dde8dcSAndrew Lunn return err; 1097e1dde8dcSAndrew Lunn 1098e1dde8dcSAndrew Lunn err = phy_write(phydev, 0x1d, 0x0016); 1099e1dde8dcSAndrew Lunn if (err < 0) 1100e1dde8dcSAndrew Lunn return err; 1101e1dde8dcSAndrew Lunn 1102e1dde8dcSAndrew Lunn err = phy_write(phydev, 0x1e, 0xa2da); 1103e1dde8dcSAndrew Lunn if (err < 0) 1104e1dde8dcSAndrew Lunn return err; 1105e1dde8dcSAndrew Lunn 1106e1dde8dcSAndrew Lunn if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID) { 1107e1dde8dcSAndrew Lunn err = m88e1145_config_init_rgmii(phydev); 1108e1dde8dcSAndrew Lunn if (err < 0) 1109e1dde8dcSAndrew Lunn return err; 1110e1dde8dcSAndrew Lunn } 1111e1dde8dcSAndrew Lunn 1112e1dde8dcSAndrew Lunn if (phydev->interface == PHY_INTERFACE_MODE_SGMII) { 1113e1dde8dcSAndrew Lunn err = m88e1145_config_init_sgmii(phydev); 1114b0224175SViet Nga Dao if (err < 0) 1115b0224175SViet Nga Dao return err; 1116b0224175SViet Nga Dao } 1117b0224175SViet Nga Dao 1118cf41a51dSDavid Daney err = marvell_of_reg_init(phydev); 1119cf41a51dSDavid Daney if (err < 0) 1120cf41a51dSDavid Daney return err; 1121cf41a51dSDavid Daney 112276884679SAndy Fleming return 0; 112376884679SAndy Fleming } 112400db8189SAndy Fleming 112569f42be8SHeiner Kallweit static int m88e1540_get_fld(struct phy_device *phydev, u8 *msecs) 112669f42be8SHeiner Kallweit { 112769f42be8SHeiner Kallweit int val; 112869f42be8SHeiner Kallweit 112969f42be8SHeiner Kallweit val = phy_read(phydev, MII_88E1540_COPPER_CTRL3); 113069f42be8SHeiner Kallweit if (val < 0) 113169f42be8SHeiner Kallweit return val; 113269f42be8SHeiner Kallweit 113369f42be8SHeiner Kallweit if (!(val & MII_88E1540_COPPER_CTRL3_FAST_LINK_DOWN)) { 113469f42be8SHeiner Kallweit *msecs = ETHTOOL_PHY_FAST_LINK_DOWN_OFF; 113569f42be8SHeiner Kallweit return 0; 113669f42be8SHeiner Kallweit } 113769f42be8SHeiner Kallweit 113869f42be8SHeiner Kallweit val = FIELD_GET(MII_88E1540_COPPER_CTRL3_LINK_DOWN_DELAY_MASK, val); 113969f42be8SHeiner Kallweit 114069f42be8SHeiner Kallweit switch (val) { 114169f42be8SHeiner Kallweit case MII_88E1540_COPPER_CTRL3_LINK_DOWN_DELAY_00MS: 114269f42be8SHeiner Kallweit *msecs = 0; 114369f42be8SHeiner Kallweit break; 114469f42be8SHeiner Kallweit case MII_88E1540_COPPER_CTRL3_LINK_DOWN_DELAY_10MS: 114569f42be8SHeiner Kallweit *msecs = 10; 114669f42be8SHeiner Kallweit break; 114769f42be8SHeiner Kallweit case MII_88E1540_COPPER_CTRL3_LINK_DOWN_DELAY_20MS: 114869f42be8SHeiner Kallweit *msecs = 20; 114969f42be8SHeiner Kallweit break; 115069f42be8SHeiner Kallweit case MII_88E1540_COPPER_CTRL3_LINK_DOWN_DELAY_40MS: 115169f42be8SHeiner Kallweit *msecs = 40; 115269f42be8SHeiner Kallweit break; 115369f42be8SHeiner Kallweit default: 115469f42be8SHeiner Kallweit return -EINVAL; 115569f42be8SHeiner Kallweit } 115669f42be8SHeiner Kallweit 115769f42be8SHeiner Kallweit return 0; 115869f42be8SHeiner Kallweit } 115969f42be8SHeiner Kallweit 116069f42be8SHeiner Kallweit static int m88e1540_set_fld(struct phy_device *phydev, const u8 *msecs) 116169f42be8SHeiner Kallweit { 116269f42be8SHeiner Kallweit struct ethtool_eee eee; 116369f42be8SHeiner Kallweit int val, ret; 116469f42be8SHeiner Kallweit 116569f42be8SHeiner Kallweit if (*msecs == ETHTOOL_PHY_FAST_LINK_DOWN_OFF) 116669f42be8SHeiner Kallweit return phy_clear_bits(phydev, MII_88E1540_COPPER_CTRL3, 116769f42be8SHeiner Kallweit MII_88E1540_COPPER_CTRL3_FAST_LINK_DOWN); 116869f42be8SHeiner Kallweit 116969f42be8SHeiner Kallweit /* According to the Marvell data sheet EEE must be disabled for 117069f42be8SHeiner Kallweit * Fast Link Down detection to work properly 117169f42be8SHeiner Kallweit */ 117269f42be8SHeiner Kallweit ret = phy_ethtool_get_eee(phydev, &eee); 117369f42be8SHeiner Kallweit if (!ret && eee.eee_enabled) { 117469f42be8SHeiner Kallweit phydev_warn(phydev, "Fast Link Down detection requires EEE to be disabled!\n"); 117569f42be8SHeiner Kallweit return -EBUSY; 117669f42be8SHeiner Kallweit } 117769f42be8SHeiner Kallweit 117869f42be8SHeiner Kallweit if (*msecs <= 5) 117969f42be8SHeiner Kallweit val = MII_88E1540_COPPER_CTRL3_LINK_DOWN_DELAY_00MS; 118069f42be8SHeiner Kallweit else if (*msecs <= 15) 118169f42be8SHeiner Kallweit val = MII_88E1540_COPPER_CTRL3_LINK_DOWN_DELAY_10MS; 118269f42be8SHeiner Kallweit else if (*msecs <= 30) 118369f42be8SHeiner Kallweit val = MII_88E1540_COPPER_CTRL3_LINK_DOWN_DELAY_20MS; 118469f42be8SHeiner Kallweit else 118569f42be8SHeiner Kallweit val = MII_88E1540_COPPER_CTRL3_LINK_DOWN_DELAY_40MS; 118669f42be8SHeiner Kallweit 118769f42be8SHeiner Kallweit val = FIELD_PREP(MII_88E1540_COPPER_CTRL3_LINK_DOWN_DELAY_MASK, val); 118869f42be8SHeiner Kallweit 118969f42be8SHeiner Kallweit ret = phy_modify(phydev, MII_88E1540_COPPER_CTRL3, 119069f42be8SHeiner Kallweit MII_88E1540_COPPER_CTRL3_LINK_DOWN_DELAY_MASK, val); 119169f42be8SHeiner Kallweit if (ret) 119269f42be8SHeiner Kallweit return ret; 119369f42be8SHeiner Kallweit 119469f42be8SHeiner Kallweit return phy_set_bits(phydev, MII_88E1540_COPPER_CTRL3, 119569f42be8SHeiner Kallweit MII_88E1540_COPPER_CTRL3_FAST_LINK_DOWN); 119669f42be8SHeiner Kallweit } 119769f42be8SHeiner Kallweit 119869f42be8SHeiner Kallweit static int m88e1540_get_tunable(struct phy_device *phydev, 119969f42be8SHeiner Kallweit struct ethtool_tunable *tuna, void *data) 120069f42be8SHeiner Kallweit { 120169f42be8SHeiner Kallweit switch (tuna->id) { 120269f42be8SHeiner Kallweit case ETHTOOL_PHY_FAST_LINK_DOWN: 120369f42be8SHeiner Kallweit return m88e1540_get_fld(phydev, data); 1204a3bdfce7SHeiner Kallweit case ETHTOOL_PHY_DOWNSHIFT: 1205911af5e1SHeiner Kallweit return m88e1011_get_downshift(phydev, data); 120669f42be8SHeiner Kallweit default: 120769f42be8SHeiner Kallweit return -EOPNOTSUPP; 120869f42be8SHeiner Kallweit } 120969f42be8SHeiner Kallweit } 121069f42be8SHeiner Kallweit 121169f42be8SHeiner Kallweit static int m88e1540_set_tunable(struct phy_device *phydev, 121269f42be8SHeiner Kallweit struct ethtool_tunable *tuna, const void *data) 121369f42be8SHeiner Kallweit { 121469f42be8SHeiner Kallweit switch (tuna->id) { 121569f42be8SHeiner Kallweit case ETHTOOL_PHY_FAST_LINK_DOWN: 121669f42be8SHeiner Kallweit return m88e1540_set_fld(phydev, data); 1217a3bdfce7SHeiner Kallweit case ETHTOOL_PHY_DOWNSHIFT: 1218911af5e1SHeiner Kallweit return m88e1011_set_downshift(phydev, *(const u8 *)data); 121969f42be8SHeiner Kallweit default: 122069f42be8SHeiner Kallweit return -EOPNOTSUPP; 122169f42be8SHeiner Kallweit } 122269f42be8SHeiner Kallweit } 122369f42be8SHeiner Kallweit 12248cbcdc1aSAndrew Lunn /* The VOD can be out of specification on link up. Poke an 12258cbcdc1aSAndrew Lunn * undocumented register, in an undocumented page, with a magic value 12268cbcdc1aSAndrew Lunn * to fix this. 12278cbcdc1aSAndrew Lunn */ 12288cbcdc1aSAndrew Lunn static int m88e6390_errata(struct phy_device *phydev) 12298cbcdc1aSAndrew Lunn { 12308cbcdc1aSAndrew Lunn int err; 12318cbcdc1aSAndrew Lunn 12328cbcdc1aSAndrew Lunn err = phy_write(phydev, MII_BMCR, 12338cbcdc1aSAndrew Lunn BMCR_ANENABLE | BMCR_SPEED1000 | BMCR_FULLDPLX); 12348cbcdc1aSAndrew Lunn if (err) 12358cbcdc1aSAndrew Lunn return err; 12368cbcdc1aSAndrew Lunn 12378cbcdc1aSAndrew Lunn usleep_range(300, 400); 12388cbcdc1aSAndrew Lunn 12398cbcdc1aSAndrew Lunn err = phy_write_paged(phydev, 0xf8, 0x08, 0x36); 12408cbcdc1aSAndrew Lunn if (err) 12418cbcdc1aSAndrew Lunn return err; 12428cbcdc1aSAndrew Lunn 12438cbcdc1aSAndrew Lunn return genphy_soft_reset(phydev); 12448cbcdc1aSAndrew Lunn } 12458cbcdc1aSAndrew Lunn 12468cbcdc1aSAndrew Lunn static int m88e6390_config_aneg(struct phy_device *phydev) 12478cbcdc1aSAndrew Lunn { 12488cbcdc1aSAndrew Lunn int err; 12498cbcdc1aSAndrew Lunn 12508cbcdc1aSAndrew Lunn err = m88e6390_errata(phydev); 12518cbcdc1aSAndrew Lunn if (err) 12528cbcdc1aSAndrew Lunn return err; 12538cbcdc1aSAndrew Lunn 12548cbcdc1aSAndrew Lunn return m88e1510_config_aneg(phydev); 12558cbcdc1aSAndrew Lunn } 12568cbcdc1aSAndrew Lunn 12576cfb3bccSCharles-Antoine Couret /** 1258ab9cb729SAndrew Lunn * fiber_lpa_mod_linkmode_lpa_t 1259c0ec3c27SAndrew Lunn * @advertising: the linkmode advertisement settings 12606cfb3bccSCharles-Antoine Couret * @lpa: value of the MII_LPA register for fiber link 1261be937f1fSAlexandr Smirnov * 1262ab9cb729SAndrew Lunn * A small helper function that translates MII_LPA bits to linkmode LP 1263ab9cb729SAndrew Lunn * advertisement settings. Other bits in advertising are left 1264ab9cb729SAndrew Lunn * unchanged. 12656cfb3bccSCharles-Antoine Couret */ 1266ab9cb729SAndrew Lunn static void fiber_lpa_mod_linkmode_lpa_t(unsigned long *advertising, u32 lpa) 12676cfb3bccSCharles-Antoine Couret { 1268ab9cb729SAndrew Lunn linkmode_mod_bit(ETHTOOL_LINK_MODE_1000baseT_Half_BIT, 126920ecf424SRussell King advertising, lpa & LPA_1000XHALF); 1270ab9cb729SAndrew Lunn 1271ab9cb729SAndrew Lunn linkmode_mod_bit(ETHTOOL_LINK_MODE_1000baseT_Full_BIT, 127220ecf424SRussell King advertising, lpa & LPA_1000XFULL); 12736cfb3bccSCharles-Antoine Couret } 12746cfb3bccSCharles-Antoine Couret 1275e1dde8dcSAndrew Lunn static int marvell_read_status_page_an(struct phy_device *phydev, 1276d2004e27SRussell King int fiber, int status) 1277be937f1fSAlexandr Smirnov { 1278be937f1fSAlexandr Smirnov int lpa; 1279fcf1f59aSRussell King int err; 1280be937f1fSAlexandr Smirnov 1281fcf1f59aSRussell King if (!fiber) { 1282fcf1f59aSRussell King err = genphy_read_lpa(phydev); 1283fcf1f59aSRussell King if (err < 0) 1284fcf1f59aSRussell King return err; 1285fcf1f59aSRussell King 1286fcf1f59aSRussell King phy_resolve_aneg_pause(phydev); 1287fcf1f59aSRussell King } else { 1288be937f1fSAlexandr Smirnov lpa = phy_read(phydev, MII_LPA); 1289be937f1fSAlexandr Smirnov if (lpa < 0) 1290be937f1fSAlexandr Smirnov return lpa; 1291be937f1fSAlexandr Smirnov 12926cfb3bccSCharles-Antoine Couret /* The fiber link is only 1000M capable */ 1293ab9cb729SAndrew Lunn fiber_lpa_mod_linkmode_lpa_t(phydev->lp_advertising, lpa); 12946cfb3bccSCharles-Antoine Couret 12956cfb3bccSCharles-Antoine Couret if (phydev->duplex == DUPLEX_FULL) { 12966cfb3bccSCharles-Antoine Couret if (!(lpa & LPA_PAUSE_FIBER)) { 12976cfb3bccSCharles-Antoine Couret phydev->pause = 0; 12986cfb3bccSCharles-Antoine Couret phydev->asym_pause = 0; 12996cfb3bccSCharles-Antoine Couret } else if ((lpa & LPA_PAUSE_ASYM_FIBER)) { 13006cfb3bccSCharles-Antoine Couret phydev->pause = 1; 13016cfb3bccSCharles-Antoine Couret phydev->asym_pause = 1; 13026cfb3bccSCharles-Antoine Couret } else { 13036cfb3bccSCharles-Antoine Couret phydev->pause = 1; 13046cfb3bccSCharles-Antoine Couret phydev->asym_pause = 0; 13056cfb3bccSCharles-Antoine Couret } 13066cfb3bccSCharles-Antoine Couret } 13076cfb3bccSCharles-Antoine Couret } 1308fcf1f59aSRussell King 1309b82cf17fSRussell King if (!(status & MII_M1011_PHY_STATUS_RESOLVED)) 1310b82cf17fSRussell King return 0; 1311b82cf17fSRussell King 1312fcf1f59aSRussell King if (status & MII_M1011_PHY_STATUS_FULLDUPLEX) 1313fcf1f59aSRussell King phydev->duplex = DUPLEX_FULL; 1314fcf1f59aSRussell King else 1315fcf1f59aSRussell King phydev->duplex = DUPLEX_HALF; 1316fcf1f59aSRussell King 1317fcf1f59aSRussell King switch (status & MII_M1011_PHY_STATUS_SPD_MASK) { 1318fcf1f59aSRussell King case MII_M1011_PHY_STATUS_1000: 1319fcf1f59aSRussell King phydev->speed = SPEED_1000; 1320fcf1f59aSRussell King break; 1321fcf1f59aSRussell King 1322fcf1f59aSRussell King case MII_M1011_PHY_STATUS_100: 1323fcf1f59aSRussell King phydev->speed = SPEED_100; 1324fcf1f59aSRussell King break; 1325fcf1f59aSRussell King 1326fcf1f59aSRussell King default: 1327fcf1f59aSRussell King phydev->speed = SPEED_10; 1328fcf1f59aSRussell King break; 1329fcf1f59aSRussell King } 1330fcf1f59aSRussell King 1331e1dde8dcSAndrew Lunn return 0; 1332e1dde8dcSAndrew Lunn } 1333e1dde8dcSAndrew Lunn 1334e1dde8dcSAndrew Lunn /* marvell_read_status_page 1335e1dde8dcSAndrew Lunn * 1336e1dde8dcSAndrew Lunn * Description: 1337e1dde8dcSAndrew Lunn * Check the link, then figure out the current state 1338e1dde8dcSAndrew Lunn * by comparing what we advertise with what the link partner 1339e1dde8dcSAndrew Lunn * advertises. Start by checking the gigabit possibilities, 1340e1dde8dcSAndrew Lunn * then move on to 10/100. 1341e1dde8dcSAndrew Lunn */ 1342e1dde8dcSAndrew Lunn static int marvell_read_status_page(struct phy_device *phydev, int page) 1343e1dde8dcSAndrew Lunn { 1344d2004e27SRussell King int status; 1345e1dde8dcSAndrew Lunn int fiber; 1346e1dde8dcSAndrew Lunn int err; 1347e1dde8dcSAndrew Lunn 1348d2004e27SRussell King status = phy_read(phydev, MII_M1011_PHY_STATUS); 1349d2004e27SRussell King if (status < 0) 1350d2004e27SRussell King return status; 1351d2004e27SRussell King 1352d2004e27SRussell King /* Use the generic register for copper link status, 1353d2004e27SRussell King * and the PHY status register for fiber link status. 1354e1dde8dcSAndrew Lunn */ 1355d2004e27SRussell King if (page == MII_MARVELL_FIBER_PAGE) { 1356d2004e27SRussell King phydev->link = !!(status & MII_M1011_PHY_STATUS_LINK); 1357d2004e27SRussell King } else { 1358d2004e27SRussell King err = genphy_update_link(phydev); 1359d2004e27SRussell King if (err) 1360d2004e27SRussell King return err; 1361d2004e27SRussell King } 1362d2004e27SRussell King 136352295666SAndrew Lunn if (page == MII_MARVELL_FIBER_PAGE) 1364e1dde8dcSAndrew Lunn fiber = 1; 1365e1dde8dcSAndrew Lunn else 1366e1dde8dcSAndrew Lunn fiber = 0; 1367e1dde8dcSAndrew Lunn 136898f92831SRussell King linkmode_zero(phydev->lp_advertising); 136998f92831SRussell King phydev->pause = 0; 137098f92831SRussell King phydev->asym_pause = 0; 1371b82cf17fSRussell King phydev->speed = SPEED_UNKNOWN; 1372b82cf17fSRussell King phydev->duplex = DUPLEX_UNKNOWN; 137398f92831SRussell King 1374e1dde8dcSAndrew Lunn if (phydev->autoneg == AUTONEG_ENABLE) 1375d2004e27SRussell King err = marvell_read_status_page_an(phydev, fiber, status); 1376e1dde8dcSAndrew Lunn else 137798f92831SRussell King err = genphy_read_status_fixed(phydev); 1378e1dde8dcSAndrew Lunn 1379e1dde8dcSAndrew Lunn return err; 1380e1dde8dcSAndrew Lunn } 1381e1dde8dcSAndrew Lunn 13826cfb3bccSCharles-Antoine Couret /* marvell_read_status 13836cfb3bccSCharles-Antoine Couret * 13846cfb3bccSCharles-Antoine Couret * Some Marvell's phys have two modes: fiber and copper. 13856cfb3bccSCharles-Antoine Couret * Both need status checked. 13866cfb3bccSCharles-Antoine Couret * Description: 13876cfb3bccSCharles-Antoine Couret * First, check the fiber link and status. 13886cfb3bccSCharles-Antoine Couret * If the fiber link is down, check the copper link and status which 13896cfb3bccSCharles-Antoine Couret * will be the default value if both link are down. 13906cfb3bccSCharles-Antoine Couret */ 13916cfb3bccSCharles-Antoine Couret static int marvell_read_status(struct phy_device *phydev) 13926cfb3bccSCharles-Antoine Couret { 13936cfb3bccSCharles-Antoine Couret int err; 13946cfb3bccSCharles-Antoine Couret 13956cfb3bccSCharles-Antoine Couret /* Check the fiber mode first */ 13963c1bcc86SAndrew Lunn if (linkmode_test_bit(ETHTOOL_LINK_MODE_FIBRE_BIT, 13973c1bcc86SAndrew Lunn phydev->supported) && 1398a13c0652SRussell King phydev->interface != PHY_INTERFACE_MODE_SGMII) { 139952295666SAndrew Lunn err = marvell_set_page(phydev, MII_MARVELL_FIBER_PAGE); 14006cfb3bccSCharles-Antoine Couret if (err < 0) 14016cfb3bccSCharles-Antoine Couret goto error; 14026cfb3bccSCharles-Antoine Couret 140352295666SAndrew Lunn err = marvell_read_status_page(phydev, MII_MARVELL_FIBER_PAGE); 14046cfb3bccSCharles-Antoine Couret if (err < 0) 14056cfb3bccSCharles-Antoine Couret goto error; 14066cfb3bccSCharles-Antoine Couret 14070c3439bcSAndrew Lunn /* If the fiber link is up, it is the selected and 14080c3439bcSAndrew Lunn * used link. In this case, we need to stay in the 14090c3439bcSAndrew Lunn * fiber page. Please to be careful about that, avoid 14100c3439bcSAndrew Lunn * to restore Copper page in other functions which 14110c3439bcSAndrew Lunn * could break the behaviour for some fiber phy like 14120c3439bcSAndrew Lunn * 88E1512. 14130c3439bcSAndrew Lunn */ 14146cfb3bccSCharles-Antoine Couret if (phydev->link) 14156cfb3bccSCharles-Antoine Couret return 0; 14166cfb3bccSCharles-Antoine Couret 14176cfb3bccSCharles-Antoine Couret /* If fiber link is down, check and save copper mode state */ 141852295666SAndrew Lunn err = marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE); 14196cfb3bccSCharles-Antoine Couret if (err < 0) 14206cfb3bccSCharles-Antoine Couret goto error; 14216cfb3bccSCharles-Antoine Couret } 14226cfb3bccSCharles-Antoine Couret 142352295666SAndrew Lunn return marvell_read_status_page(phydev, MII_MARVELL_COPPER_PAGE); 14246cfb3bccSCharles-Antoine Couret 14256cfb3bccSCharles-Antoine Couret error: 142652295666SAndrew Lunn marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE); 14276cfb3bccSCharles-Antoine Couret return err; 14286cfb3bccSCharles-Antoine Couret } 14293758be3dSCharles-Antoine Couret 14303758be3dSCharles-Antoine Couret /* marvell_suspend 14313758be3dSCharles-Antoine Couret * 14323758be3dSCharles-Antoine Couret * Some Marvell's phys have two modes: fiber and copper. 14333758be3dSCharles-Antoine Couret * Both need to be suspended 14343758be3dSCharles-Antoine Couret */ 14353758be3dSCharles-Antoine Couret static int marvell_suspend(struct phy_device *phydev) 14363758be3dSCharles-Antoine Couret { 14373758be3dSCharles-Antoine Couret int err; 14383758be3dSCharles-Antoine Couret 14393758be3dSCharles-Antoine Couret /* Suspend the fiber mode first */ 14403c1bcc86SAndrew Lunn if (!linkmode_test_bit(ETHTOOL_LINK_MODE_FIBRE_BIT, 14413c1bcc86SAndrew Lunn phydev->supported)) { 144252295666SAndrew Lunn err = marvell_set_page(phydev, MII_MARVELL_FIBER_PAGE); 14433758be3dSCharles-Antoine Couret if (err < 0) 14443758be3dSCharles-Antoine Couret goto error; 14453758be3dSCharles-Antoine Couret 14463758be3dSCharles-Antoine Couret /* With the page set, use the generic suspend */ 14473758be3dSCharles-Antoine Couret err = genphy_suspend(phydev); 14483758be3dSCharles-Antoine Couret if (err < 0) 14493758be3dSCharles-Antoine Couret goto error; 14503758be3dSCharles-Antoine Couret 14513758be3dSCharles-Antoine Couret /* Then, the copper link */ 145252295666SAndrew Lunn err = marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE); 14533758be3dSCharles-Antoine Couret if (err < 0) 14543758be3dSCharles-Antoine Couret goto error; 14553758be3dSCharles-Antoine Couret } 14563758be3dSCharles-Antoine Couret 14573758be3dSCharles-Antoine Couret /* With the page set, use the generic suspend */ 14583758be3dSCharles-Antoine Couret return genphy_suspend(phydev); 14593758be3dSCharles-Antoine Couret 14603758be3dSCharles-Antoine Couret error: 146152295666SAndrew Lunn marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE); 14623758be3dSCharles-Antoine Couret return err; 14633758be3dSCharles-Antoine Couret } 14643758be3dSCharles-Antoine Couret 14653758be3dSCharles-Antoine Couret /* marvell_resume 14663758be3dSCharles-Antoine Couret * 14673758be3dSCharles-Antoine Couret * Some Marvell's phys have two modes: fiber and copper. 14683758be3dSCharles-Antoine Couret * Both need to be resumed 14693758be3dSCharles-Antoine Couret */ 14703758be3dSCharles-Antoine Couret static int marvell_resume(struct phy_device *phydev) 14713758be3dSCharles-Antoine Couret { 14723758be3dSCharles-Antoine Couret int err; 14733758be3dSCharles-Antoine Couret 14743758be3dSCharles-Antoine Couret /* Resume the fiber mode first */ 14753c1bcc86SAndrew Lunn if (!linkmode_test_bit(ETHTOOL_LINK_MODE_FIBRE_BIT, 14763c1bcc86SAndrew Lunn phydev->supported)) { 147752295666SAndrew Lunn err = marvell_set_page(phydev, MII_MARVELL_FIBER_PAGE); 14783758be3dSCharles-Antoine Couret if (err < 0) 14793758be3dSCharles-Antoine Couret goto error; 14803758be3dSCharles-Antoine Couret 14813758be3dSCharles-Antoine Couret /* With the page set, use the generic resume */ 14823758be3dSCharles-Antoine Couret err = genphy_resume(phydev); 14833758be3dSCharles-Antoine Couret if (err < 0) 14843758be3dSCharles-Antoine Couret goto error; 14853758be3dSCharles-Antoine Couret 14863758be3dSCharles-Antoine Couret /* Then, the copper link */ 148752295666SAndrew Lunn err = marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE); 14883758be3dSCharles-Antoine Couret if (err < 0) 14893758be3dSCharles-Antoine Couret goto error; 14903758be3dSCharles-Antoine Couret } 14913758be3dSCharles-Antoine Couret 14923758be3dSCharles-Antoine Couret /* With the page set, use the generic resume */ 14933758be3dSCharles-Antoine Couret return genphy_resume(phydev); 14943758be3dSCharles-Antoine Couret 14953758be3dSCharles-Antoine Couret error: 149652295666SAndrew Lunn marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE); 14973758be3dSCharles-Antoine Couret return err; 14983758be3dSCharles-Antoine Couret } 14993758be3dSCharles-Antoine Couret 15006b358aedSSebastian Hesselbarth static int marvell_aneg_done(struct phy_device *phydev) 15016b358aedSSebastian Hesselbarth { 15026b358aedSSebastian Hesselbarth int retval = phy_read(phydev, MII_M1011_PHY_STATUS); 1503e69d9ed4SAndrew Lunn 15046b358aedSSebastian Hesselbarth return (retval < 0) ? retval : (retval & MII_M1011_PHY_STATUS_RESOLVED); 15056b358aedSSebastian Hesselbarth } 15066b358aedSSebastian Hesselbarth 1507dcd07be3SAnatolij Gustschin static int m88e1121_did_interrupt(struct phy_device *phydev) 1508dcd07be3SAnatolij Gustschin { 1509dcd07be3SAnatolij Gustschin int imask; 1510dcd07be3SAnatolij Gustschin 1511dcd07be3SAnatolij Gustschin imask = phy_read(phydev, MII_M1011_IEVENT); 1512dcd07be3SAnatolij Gustschin 1513dcd07be3SAnatolij Gustschin if (imask & MII_M1011_IMASK_INIT) 1514dcd07be3SAnatolij Gustschin return 1; 1515dcd07be3SAnatolij Gustschin 1516dcd07be3SAnatolij Gustschin return 0; 1517dcd07be3SAnatolij Gustschin } 1518dcd07be3SAnatolij Gustschin 151923beb38fSAndrew Lunn static void m88e1318_get_wol(struct phy_device *phydev, 152023beb38fSAndrew Lunn struct ethtool_wolinfo *wol) 15213871c387SMichael Stapelberg { 1522424ca4c5SRussell King int oldpage, ret = 0; 1523424ca4c5SRussell King 15243871c387SMichael Stapelberg wol->supported = WAKE_MAGIC; 15253871c387SMichael Stapelberg wol->wolopts = 0; 15263871c387SMichael Stapelberg 1527424ca4c5SRussell King oldpage = phy_select_page(phydev, MII_MARVELL_WOL_PAGE); 1528424ca4c5SRussell King if (oldpage < 0) 1529424ca4c5SRussell King goto error; 15303871c387SMichael Stapelberg 1531424ca4c5SRussell King ret = __phy_read(phydev, MII_88E1318S_PHY_WOL_CTRL); 1532424ca4c5SRussell King if (ret & MII_88E1318S_PHY_WOL_CTRL_MAGIC_PACKET_MATCH_ENABLE) 15333871c387SMichael Stapelberg wol->wolopts |= WAKE_MAGIC; 15343871c387SMichael Stapelberg 1535424ca4c5SRussell King error: 1536424ca4c5SRussell King phy_restore_page(phydev, oldpage, ret); 15373871c387SMichael Stapelberg } 15383871c387SMichael Stapelberg 153923beb38fSAndrew Lunn static int m88e1318_set_wol(struct phy_device *phydev, 154023beb38fSAndrew Lunn struct ethtool_wolinfo *wol) 15413871c387SMichael Stapelberg { 1542424ca4c5SRussell King int err = 0, oldpage; 15433871c387SMichael Stapelberg 1544424ca4c5SRussell King oldpage = phy_save_page(phydev); 1545424ca4c5SRussell King if (oldpage < 0) 1546424ca4c5SRussell King goto error; 15473871c387SMichael Stapelberg 15483871c387SMichael Stapelberg if (wol->wolopts & WAKE_MAGIC) { 15493871c387SMichael Stapelberg /* Explicitly switch to page 0x00, just to be sure */ 1550424ca4c5SRussell King err = marvell_write_page(phydev, MII_MARVELL_COPPER_PAGE); 15513871c387SMichael Stapelberg if (err < 0) 1552424ca4c5SRussell King goto error; 15533871c387SMichael Stapelberg 1554b6a930faSJingju Hou /* If WOL event happened once, the LED[2] interrupt pin 1555b6a930faSJingju Hou * will not be cleared unless we reading the interrupt status 1556b6a930faSJingju Hou * register. If interrupts are in use, the normal interrupt 1557b6a930faSJingju Hou * handling will clear the WOL event. Clear the WOL event 1558b6a930faSJingju Hou * before enabling it if !phy_interrupt_is_valid() 1559b6a930faSJingju Hou */ 1560b6a930faSJingju Hou if (!phy_interrupt_is_valid(phydev)) 1561e0a7328fSAndrew Lunn __phy_read(phydev, MII_M1011_IEVENT); 1562b6a930faSJingju Hou 15633871c387SMichael Stapelberg /* Enable the WOL interrupt */ 1564424ca4c5SRussell King err = __phy_modify(phydev, MII_88E1318S_PHY_CSIER, 0, 1565424ca4c5SRussell King MII_88E1318S_PHY_CSIER_WOL_EIE); 15663871c387SMichael Stapelberg if (err < 0) 1567424ca4c5SRussell King goto error; 15683871c387SMichael Stapelberg 1569424ca4c5SRussell King err = marvell_write_page(phydev, MII_MARVELL_LED_PAGE); 15703871c387SMichael Stapelberg if (err < 0) 1571424ca4c5SRussell King goto error; 15723871c387SMichael Stapelberg 15733871c387SMichael Stapelberg /* Setup LED[2] as interrupt pin (active low) */ 1574424ca4c5SRussell King err = __phy_modify(phydev, MII_88E1318S_PHY_LED_TCR, 1575f102852fSRussell King MII_88E1318S_PHY_LED_TCR_FORCE_INT, 1576424ca4c5SRussell King MII_88E1318S_PHY_LED_TCR_INTn_ENABLE | 1577424ca4c5SRussell King MII_88E1318S_PHY_LED_TCR_INT_ACTIVE_LOW); 15783871c387SMichael Stapelberg if (err < 0) 1579424ca4c5SRussell King goto error; 15803871c387SMichael Stapelberg 1581424ca4c5SRussell King err = marvell_write_page(phydev, MII_MARVELL_WOL_PAGE); 15823871c387SMichael Stapelberg if (err < 0) 1583424ca4c5SRussell King goto error; 15843871c387SMichael Stapelberg 15853871c387SMichael Stapelberg /* Store the device address for the magic packet */ 1586424ca4c5SRussell King err = __phy_write(phydev, MII_88E1318S_PHY_MAGIC_PACKET_WORD2, 15873871c387SMichael Stapelberg ((phydev->attached_dev->dev_addr[5] << 8) | 15883871c387SMichael Stapelberg phydev->attached_dev->dev_addr[4])); 15893871c387SMichael Stapelberg if (err < 0) 1590424ca4c5SRussell King goto error; 1591424ca4c5SRussell King err = __phy_write(phydev, MII_88E1318S_PHY_MAGIC_PACKET_WORD1, 15923871c387SMichael Stapelberg ((phydev->attached_dev->dev_addr[3] << 8) | 15933871c387SMichael Stapelberg phydev->attached_dev->dev_addr[2])); 15943871c387SMichael Stapelberg if (err < 0) 1595424ca4c5SRussell King goto error; 1596424ca4c5SRussell King err = __phy_write(phydev, MII_88E1318S_PHY_MAGIC_PACKET_WORD0, 15973871c387SMichael Stapelberg ((phydev->attached_dev->dev_addr[1] << 8) | 15983871c387SMichael Stapelberg phydev->attached_dev->dev_addr[0])); 15993871c387SMichael Stapelberg if (err < 0) 1600424ca4c5SRussell King goto error; 16013871c387SMichael Stapelberg 16023871c387SMichael Stapelberg /* Clear WOL status and enable magic packet matching */ 1603424ca4c5SRussell King err = __phy_modify(phydev, MII_88E1318S_PHY_WOL_CTRL, 0, 1604424ca4c5SRussell King MII_88E1318S_PHY_WOL_CTRL_CLEAR_WOL_STATUS | 1605424ca4c5SRussell King MII_88E1318S_PHY_WOL_CTRL_MAGIC_PACKET_MATCH_ENABLE); 16063871c387SMichael Stapelberg if (err < 0) 1607424ca4c5SRussell King goto error; 16083871c387SMichael Stapelberg } else { 1609424ca4c5SRussell King err = marvell_write_page(phydev, MII_MARVELL_WOL_PAGE); 16103871c387SMichael Stapelberg if (err < 0) 1611424ca4c5SRussell King goto error; 16123871c387SMichael Stapelberg 16133871c387SMichael Stapelberg /* Clear WOL status and disable magic packet matching */ 1614424ca4c5SRussell King err = __phy_modify(phydev, MII_88E1318S_PHY_WOL_CTRL, 1615f102852fSRussell King MII_88E1318S_PHY_WOL_CTRL_MAGIC_PACKET_MATCH_ENABLE, 1616424ca4c5SRussell King MII_88E1318S_PHY_WOL_CTRL_CLEAR_WOL_STATUS); 16173871c387SMichael Stapelberg if (err < 0) 1618424ca4c5SRussell King goto error; 16193871c387SMichael Stapelberg } 16203871c387SMichael Stapelberg 1621424ca4c5SRussell King error: 1622424ca4c5SRussell King return phy_restore_page(phydev, oldpage, err); 16233871c387SMichael Stapelberg } 16243871c387SMichael Stapelberg 1625d2fa47d9SAndrew Lunn static int marvell_get_sset_count(struct phy_device *phydev) 1626d2fa47d9SAndrew Lunn { 16273c1bcc86SAndrew Lunn if (linkmode_test_bit(ETHTOOL_LINK_MODE_FIBRE_BIT, 16283c1bcc86SAndrew Lunn phydev->supported)) 1629d2fa47d9SAndrew Lunn return ARRAY_SIZE(marvell_hw_stats); 16302170fef7SCharles-Antoine Couret else 16312170fef7SCharles-Antoine Couret return ARRAY_SIZE(marvell_hw_stats) - NB_FIBER_STATS; 1632d2fa47d9SAndrew Lunn } 1633d2fa47d9SAndrew Lunn 1634d2fa47d9SAndrew Lunn static void marvell_get_strings(struct phy_device *phydev, u8 *data) 1635d2fa47d9SAndrew Lunn { 1636fdfdf867SAndrew Lunn int count = marvell_get_sset_count(phydev); 1637d2fa47d9SAndrew Lunn int i; 1638d2fa47d9SAndrew Lunn 1639fdfdf867SAndrew Lunn for (i = 0; i < count; i++) { 164098409b2bSFlorian Fainelli strlcpy(data + i * ETH_GSTRING_LEN, 1641d2fa47d9SAndrew Lunn marvell_hw_stats[i].string, ETH_GSTRING_LEN); 1642d2fa47d9SAndrew Lunn } 1643d2fa47d9SAndrew Lunn } 1644d2fa47d9SAndrew Lunn 1645d2fa47d9SAndrew Lunn static u64 marvell_get_stat(struct phy_device *phydev, int i) 1646d2fa47d9SAndrew Lunn { 1647d2fa47d9SAndrew Lunn struct marvell_hw_stat stat = marvell_hw_stats[i]; 1648d2fa47d9SAndrew Lunn struct marvell_priv *priv = phydev->priv; 1649424ca4c5SRussell King int val; 1650321b4d4bSAndrew Lunn u64 ret; 1651d2fa47d9SAndrew Lunn 1652424ca4c5SRussell King val = phy_read_paged(phydev, stat.page, stat.reg); 1653d2fa47d9SAndrew Lunn if (val < 0) { 16546c3442f5SJisheng Zhang ret = U64_MAX; 1655d2fa47d9SAndrew Lunn } else { 1656d2fa47d9SAndrew Lunn val = val & ((1 << stat.bits) - 1); 1657d2fa47d9SAndrew Lunn priv->stats[i] += val; 1658321b4d4bSAndrew Lunn ret = priv->stats[i]; 1659d2fa47d9SAndrew Lunn } 1660d2fa47d9SAndrew Lunn 1661321b4d4bSAndrew Lunn return ret; 1662d2fa47d9SAndrew Lunn } 1663d2fa47d9SAndrew Lunn 1664d2fa47d9SAndrew Lunn static void marvell_get_stats(struct phy_device *phydev, 1665d2fa47d9SAndrew Lunn struct ethtool_stats *stats, u64 *data) 1666d2fa47d9SAndrew Lunn { 1667fdfdf867SAndrew Lunn int count = marvell_get_sset_count(phydev); 1668d2fa47d9SAndrew Lunn int i; 1669d2fa47d9SAndrew Lunn 1670fdfdf867SAndrew Lunn for (i = 0; i < count; i++) 1671d2fa47d9SAndrew Lunn data[i] = marvell_get_stat(phydev, i); 1672d2fa47d9SAndrew Lunn } 1673d2fa47d9SAndrew Lunn 16740b04680fSAndrew Lunn #ifdef CONFIG_HWMON 16750b04680fSAndrew Lunn static int m88e1121_get_temp(struct phy_device *phydev, long *temp) 16760b04680fSAndrew Lunn { 1677975b388cSAndrew Lunn int oldpage; 1678424ca4c5SRussell King int ret = 0; 16790b04680fSAndrew Lunn int val; 16800b04680fSAndrew Lunn 16810b04680fSAndrew Lunn *temp = 0; 16820b04680fSAndrew Lunn 1683424ca4c5SRussell King oldpage = phy_select_page(phydev, MII_MARVELL_MISC_TEST_PAGE); 1684424ca4c5SRussell King if (oldpage < 0) 1685424ca4c5SRussell King goto error; 1686975b388cSAndrew Lunn 16870b04680fSAndrew Lunn /* Enable temperature sensor */ 1688424ca4c5SRussell King ret = __phy_read(phydev, MII_88E1121_MISC_TEST); 16890b04680fSAndrew Lunn if (ret < 0) 16900b04680fSAndrew Lunn goto error; 16910b04680fSAndrew Lunn 1692424ca4c5SRussell King ret = __phy_write(phydev, MII_88E1121_MISC_TEST, 16930b04680fSAndrew Lunn ret | MII_88E1121_MISC_TEST_TEMP_SENSOR_EN); 16940b04680fSAndrew Lunn if (ret < 0) 16950b04680fSAndrew Lunn goto error; 16960b04680fSAndrew Lunn 16970b04680fSAndrew Lunn /* Wait for temperature to stabilize */ 16980b04680fSAndrew Lunn usleep_range(10000, 12000); 16990b04680fSAndrew Lunn 1700424ca4c5SRussell King val = __phy_read(phydev, MII_88E1121_MISC_TEST); 17010b04680fSAndrew Lunn if (val < 0) { 17020b04680fSAndrew Lunn ret = val; 17030b04680fSAndrew Lunn goto error; 17040b04680fSAndrew Lunn } 17050b04680fSAndrew Lunn 17060b04680fSAndrew Lunn /* Disable temperature sensor */ 1707424ca4c5SRussell King ret = __phy_write(phydev, MII_88E1121_MISC_TEST, 17080b04680fSAndrew Lunn ret & ~MII_88E1121_MISC_TEST_TEMP_SENSOR_EN); 17090b04680fSAndrew Lunn if (ret < 0) 17100b04680fSAndrew Lunn goto error; 17110b04680fSAndrew Lunn 17120b04680fSAndrew Lunn *temp = ((val & MII_88E1121_MISC_TEST_TEMP_MASK) - 5) * 5000; 17130b04680fSAndrew Lunn 17140b04680fSAndrew Lunn error: 1715424ca4c5SRussell King return phy_restore_page(phydev, oldpage, ret); 17160b04680fSAndrew Lunn } 17170b04680fSAndrew Lunn 17180b04680fSAndrew Lunn static int m88e1121_hwmon_read(struct device *dev, 17190b04680fSAndrew Lunn enum hwmon_sensor_types type, 17200b04680fSAndrew Lunn u32 attr, int channel, long *temp) 17210b04680fSAndrew Lunn { 17220b04680fSAndrew Lunn struct phy_device *phydev = dev_get_drvdata(dev); 17230b04680fSAndrew Lunn int err; 17240b04680fSAndrew Lunn 17250b04680fSAndrew Lunn switch (attr) { 17260b04680fSAndrew Lunn case hwmon_temp_input: 17270b04680fSAndrew Lunn err = m88e1121_get_temp(phydev, temp); 17280b04680fSAndrew Lunn break; 17290b04680fSAndrew Lunn default: 17300b04680fSAndrew Lunn return -EOPNOTSUPP; 17310b04680fSAndrew Lunn } 17320b04680fSAndrew Lunn 17330b04680fSAndrew Lunn return err; 17340b04680fSAndrew Lunn } 17350b04680fSAndrew Lunn 17360b04680fSAndrew Lunn static umode_t m88e1121_hwmon_is_visible(const void *data, 17370b04680fSAndrew Lunn enum hwmon_sensor_types type, 17380b04680fSAndrew Lunn u32 attr, int channel) 17390b04680fSAndrew Lunn { 17400b04680fSAndrew Lunn if (type != hwmon_temp) 17410b04680fSAndrew Lunn return 0; 17420b04680fSAndrew Lunn 17430b04680fSAndrew Lunn switch (attr) { 17440b04680fSAndrew Lunn case hwmon_temp_input: 17450b04680fSAndrew Lunn return 0444; 17460b04680fSAndrew Lunn default: 17470b04680fSAndrew Lunn return 0; 17480b04680fSAndrew Lunn } 17490b04680fSAndrew Lunn } 17500b04680fSAndrew Lunn 17510b04680fSAndrew Lunn static u32 m88e1121_hwmon_chip_config[] = { 17520b04680fSAndrew Lunn HWMON_C_REGISTER_TZ, 17530b04680fSAndrew Lunn 0 17540b04680fSAndrew Lunn }; 17550b04680fSAndrew Lunn 17560b04680fSAndrew Lunn static const struct hwmon_channel_info m88e1121_hwmon_chip = { 17570b04680fSAndrew Lunn .type = hwmon_chip, 17580b04680fSAndrew Lunn .config = m88e1121_hwmon_chip_config, 17590b04680fSAndrew Lunn }; 17600b04680fSAndrew Lunn 17610b04680fSAndrew Lunn static u32 m88e1121_hwmon_temp_config[] = { 17620b04680fSAndrew Lunn HWMON_T_INPUT, 17630b04680fSAndrew Lunn 0 17640b04680fSAndrew Lunn }; 17650b04680fSAndrew Lunn 17660b04680fSAndrew Lunn static const struct hwmon_channel_info m88e1121_hwmon_temp = { 17670b04680fSAndrew Lunn .type = hwmon_temp, 17680b04680fSAndrew Lunn .config = m88e1121_hwmon_temp_config, 17690b04680fSAndrew Lunn }; 17700b04680fSAndrew Lunn 17710b04680fSAndrew Lunn static const struct hwmon_channel_info *m88e1121_hwmon_info[] = { 17720b04680fSAndrew Lunn &m88e1121_hwmon_chip, 17730b04680fSAndrew Lunn &m88e1121_hwmon_temp, 17740b04680fSAndrew Lunn NULL 17750b04680fSAndrew Lunn }; 17760b04680fSAndrew Lunn 17770b04680fSAndrew Lunn static const struct hwmon_ops m88e1121_hwmon_hwmon_ops = { 17780b04680fSAndrew Lunn .is_visible = m88e1121_hwmon_is_visible, 17790b04680fSAndrew Lunn .read = m88e1121_hwmon_read, 17800b04680fSAndrew Lunn }; 17810b04680fSAndrew Lunn 17820b04680fSAndrew Lunn static const struct hwmon_chip_info m88e1121_hwmon_chip_info = { 17830b04680fSAndrew Lunn .ops = &m88e1121_hwmon_hwmon_ops, 17840b04680fSAndrew Lunn .info = m88e1121_hwmon_info, 17850b04680fSAndrew Lunn }; 17860b04680fSAndrew Lunn 17870b04680fSAndrew Lunn static int m88e1510_get_temp(struct phy_device *phydev, long *temp) 17880b04680fSAndrew Lunn { 17890b04680fSAndrew Lunn int ret; 17900b04680fSAndrew Lunn 17910b04680fSAndrew Lunn *temp = 0; 17920b04680fSAndrew Lunn 1793424ca4c5SRussell King ret = phy_read_paged(phydev, MII_MARVELL_MISC_TEST_PAGE, 1794424ca4c5SRussell King MII_88E1510_TEMP_SENSOR); 17950b04680fSAndrew Lunn if (ret < 0) 1796424ca4c5SRussell King return ret; 17970b04680fSAndrew Lunn 17980b04680fSAndrew Lunn *temp = ((ret & MII_88E1510_TEMP_SENSOR_MASK) - 25) * 1000; 17990b04680fSAndrew Lunn 1800424ca4c5SRussell King return 0; 18010b04680fSAndrew Lunn } 18020b04680fSAndrew Lunn 1803f0a45816SColin Ian King static int m88e1510_get_temp_critical(struct phy_device *phydev, long *temp) 18040b04680fSAndrew Lunn { 18050b04680fSAndrew Lunn int ret; 18060b04680fSAndrew Lunn 18070b04680fSAndrew Lunn *temp = 0; 18080b04680fSAndrew Lunn 1809424ca4c5SRussell King ret = phy_read_paged(phydev, MII_MARVELL_MISC_TEST_PAGE, 1810424ca4c5SRussell King MII_88E1121_MISC_TEST); 18110b04680fSAndrew Lunn if (ret < 0) 1812424ca4c5SRussell King return ret; 18130b04680fSAndrew Lunn 18140b04680fSAndrew Lunn *temp = (((ret & MII_88E1510_MISC_TEST_TEMP_THRESHOLD_MASK) >> 18150b04680fSAndrew Lunn MII_88E1510_MISC_TEST_TEMP_THRESHOLD_SHIFT) * 5) - 25; 18160b04680fSAndrew Lunn /* convert to mC */ 18170b04680fSAndrew Lunn *temp *= 1000; 18180b04680fSAndrew Lunn 1819424ca4c5SRussell King return 0; 18200b04680fSAndrew Lunn } 18210b04680fSAndrew Lunn 1822f0a45816SColin Ian King static int m88e1510_set_temp_critical(struct phy_device *phydev, long temp) 18230b04680fSAndrew Lunn { 18240b04680fSAndrew Lunn temp = temp / 1000; 18250b04680fSAndrew Lunn temp = clamp_val(DIV_ROUND_CLOSEST(temp, 5) + 5, 0, 0x1f); 18260b04680fSAndrew Lunn 1827424ca4c5SRussell King return phy_modify_paged(phydev, MII_MARVELL_MISC_TEST_PAGE, 1828424ca4c5SRussell King MII_88E1121_MISC_TEST, 1829424ca4c5SRussell King MII_88E1510_MISC_TEST_TEMP_THRESHOLD_MASK, 1830424ca4c5SRussell King temp << MII_88E1510_MISC_TEST_TEMP_THRESHOLD_SHIFT); 18310b04680fSAndrew Lunn } 18320b04680fSAndrew Lunn 1833f0a45816SColin Ian King static int m88e1510_get_temp_alarm(struct phy_device *phydev, long *alarm) 18340b04680fSAndrew Lunn { 18350b04680fSAndrew Lunn int ret; 18360b04680fSAndrew Lunn 18370b04680fSAndrew Lunn *alarm = false; 18380b04680fSAndrew Lunn 1839424ca4c5SRussell King ret = phy_read_paged(phydev, MII_MARVELL_MISC_TEST_PAGE, 1840424ca4c5SRussell King MII_88E1121_MISC_TEST); 18410b04680fSAndrew Lunn if (ret < 0) 1842424ca4c5SRussell King return ret; 1843424ca4c5SRussell King 18440b04680fSAndrew Lunn *alarm = !!(ret & MII_88E1510_MISC_TEST_TEMP_IRQ); 18450b04680fSAndrew Lunn 1846424ca4c5SRussell King return 0; 18470b04680fSAndrew Lunn } 18480b04680fSAndrew Lunn 18490b04680fSAndrew Lunn static int m88e1510_hwmon_read(struct device *dev, 18500b04680fSAndrew Lunn enum hwmon_sensor_types type, 18510b04680fSAndrew Lunn u32 attr, int channel, long *temp) 18520b04680fSAndrew Lunn { 18530b04680fSAndrew Lunn struct phy_device *phydev = dev_get_drvdata(dev); 18540b04680fSAndrew Lunn int err; 18550b04680fSAndrew Lunn 18560b04680fSAndrew Lunn switch (attr) { 18570b04680fSAndrew Lunn case hwmon_temp_input: 18580b04680fSAndrew Lunn err = m88e1510_get_temp(phydev, temp); 18590b04680fSAndrew Lunn break; 18600b04680fSAndrew Lunn case hwmon_temp_crit: 18610b04680fSAndrew Lunn err = m88e1510_get_temp_critical(phydev, temp); 18620b04680fSAndrew Lunn break; 18630b04680fSAndrew Lunn case hwmon_temp_max_alarm: 18640b04680fSAndrew Lunn err = m88e1510_get_temp_alarm(phydev, temp); 18650b04680fSAndrew Lunn break; 18660b04680fSAndrew Lunn default: 18670b04680fSAndrew Lunn return -EOPNOTSUPP; 18680b04680fSAndrew Lunn } 18690b04680fSAndrew Lunn 18700b04680fSAndrew Lunn return err; 18710b04680fSAndrew Lunn } 18720b04680fSAndrew Lunn 18730b04680fSAndrew Lunn static int m88e1510_hwmon_write(struct device *dev, 18740b04680fSAndrew Lunn enum hwmon_sensor_types type, 18750b04680fSAndrew Lunn u32 attr, int channel, long temp) 18760b04680fSAndrew Lunn { 18770b04680fSAndrew Lunn struct phy_device *phydev = dev_get_drvdata(dev); 18780b04680fSAndrew Lunn int err; 18790b04680fSAndrew Lunn 18800b04680fSAndrew Lunn switch (attr) { 18810b04680fSAndrew Lunn case hwmon_temp_crit: 18820b04680fSAndrew Lunn err = m88e1510_set_temp_critical(phydev, temp); 18830b04680fSAndrew Lunn break; 18840b04680fSAndrew Lunn default: 18850b04680fSAndrew Lunn return -EOPNOTSUPP; 18860b04680fSAndrew Lunn } 18870b04680fSAndrew Lunn return err; 18880b04680fSAndrew Lunn } 18890b04680fSAndrew Lunn 18900b04680fSAndrew Lunn static umode_t m88e1510_hwmon_is_visible(const void *data, 18910b04680fSAndrew Lunn enum hwmon_sensor_types type, 18920b04680fSAndrew Lunn u32 attr, int channel) 18930b04680fSAndrew Lunn { 18940b04680fSAndrew Lunn if (type != hwmon_temp) 18950b04680fSAndrew Lunn return 0; 18960b04680fSAndrew Lunn 18970b04680fSAndrew Lunn switch (attr) { 18980b04680fSAndrew Lunn case hwmon_temp_input: 18990b04680fSAndrew Lunn case hwmon_temp_max_alarm: 19000b04680fSAndrew Lunn return 0444; 19010b04680fSAndrew Lunn case hwmon_temp_crit: 19020b04680fSAndrew Lunn return 0644; 19030b04680fSAndrew Lunn default: 19040b04680fSAndrew Lunn return 0; 19050b04680fSAndrew Lunn } 19060b04680fSAndrew Lunn } 19070b04680fSAndrew Lunn 19080b04680fSAndrew Lunn static u32 m88e1510_hwmon_temp_config[] = { 19090b04680fSAndrew Lunn HWMON_T_INPUT | HWMON_T_CRIT | HWMON_T_MAX_ALARM, 19100b04680fSAndrew Lunn 0 19110b04680fSAndrew Lunn }; 19120b04680fSAndrew Lunn 19130b04680fSAndrew Lunn static const struct hwmon_channel_info m88e1510_hwmon_temp = { 19140b04680fSAndrew Lunn .type = hwmon_temp, 19150b04680fSAndrew Lunn .config = m88e1510_hwmon_temp_config, 19160b04680fSAndrew Lunn }; 19170b04680fSAndrew Lunn 19180b04680fSAndrew Lunn static const struct hwmon_channel_info *m88e1510_hwmon_info[] = { 19190b04680fSAndrew Lunn &m88e1121_hwmon_chip, 19200b04680fSAndrew Lunn &m88e1510_hwmon_temp, 19210b04680fSAndrew Lunn NULL 19220b04680fSAndrew Lunn }; 19230b04680fSAndrew Lunn 19240b04680fSAndrew Lunn static const struct hwmon_ops m88e1510_hwmon_hwmon_ops = { 19250b04680fSAndrew Lunn .is_visible = m88e1510_hwmon_is_visible, 19260b04680fSAndrew Lunn .read = m88e1510_hwmon_read, 19270b04680fSAndrew Lunn .write = m88e1510_hwmon_write, 19280b04680fSAndrew Lunn }; 19290b04680fSAndrew Lunn 19300b04680fSAndrew Lunn static const struct hwmon_chip_info m88e1510_hwmon_chip_info = { 19310b04680fSAndrew Lunn .ops = &m88e1510_hwmon_hwmon_ops, 19320b04680fSAndrew Lunn .info = m88e1510_hwmon_info, 19330b04680fSAndrew Lunn }; 19340b04680fSAndrew Lunn 1935fee2d546SAndrew Lunn static int m88e6390_get_temp(struct phy_device *phydev, long *temp) 1936fee2d546SAndrew Lunn { 1937fee2d546SAndrew Lunn int sum = 0; 1938fee2d546SAndrew Lunn int oldpage; 1939fee2d546SAndrew Lunn int ret = 0; 1940fee2d546SAndrew Lunn int i; 1941fee2d546SAndrew Lunn 1942fee2d546SAndrew Lunn *temp = 0; 1943fee2d546SAndrew Lunn 1944fee2d546SAndrew Lunn oldpage = phy_select_page(phydev, MII_MARVELL_MISC_TEST_PAGE); 1945fee2d546SAndrew Lunn if (oldpage < 0) 1946fee2d546SAndrew Lunn goto error; 1947fee2d546SAndrew Lunn 1948fee2d546SAndrew Lunn /* Enable temperature sensor */ 1949fee2d546SAndrew Lunn ret = __phy_read(phydev, MII_88E6390_MISC_TEST); 1950fee2d546SAndrew Lunn if (ret < 0) 1951fee2d546SAndrew Lunn goto error; 1952fee2d546SAndrew Lunn 1953fee2d546SAndrew Lunn ret = ret & ~MII_88E6390_MISC_TEST_SAMPLE_MASK; 1954fee2d546SAndrew Lunn ret |= MII_88E6390_MISC_TEST_SAMPLE_ENABLE | 1955fee2d546SAndrew Lunn MII_88E6390_MISC_TEST_SAMPLE_1S; 1956fee2d546SAndrew Lunn 1957fee2d546SAndrew Lunn ret = __phy_write(phydev, MII_88E6390_MISC_TEST, ret); 1958fee2d546SAndrew Lunn if (ret < 0) 1959fee2d546SAndrew Lunn goto error; 1960fee2d546SAndrew Lunn 1961fee2d546SAndrew Lunn /* Wait for temperature to stabilize */ 1962fee2d546SAndrew Lunn usleep_range(10000, 12000); 1963fee2d546SAndrew Lunn 1964fee2d546SAndrew Lunn /* Reading the temperature sense has an errata. You need to read 1965fee2d546SAndrew Lunn * a number of times and take an average. 1966fee2d546SAndrew Lunn */ 1967fee2d546SAndrew Lunn for (i = 0; i < MII_88E6390_TEMP_SENSOR_SAMPLES; i++) { 1968fee2d546SAndrew Lunn ret = __phy_read(phydev, MII_88E6390_TEMP_SENSOR); 1969fee2d546SAndrew Lunn if (ret < 0) 1970fee2d546SAndrew Lunn goto error; 1971fee2d546SAndrew Lunn sum += ret & MII_88E6390_TEMP_SENSOR_MASK; 1972fee2d546SAndrew Lunn } 1973fee2d546SAndrew Lunn 1974fee2d546SAndrew Lunn sum /= MII_88E6390_TEMP_SENSOR_SAMPLES; 1975fee2d546SAndrew Lunn *temp = (sum - 75) * 1000; 1976fee2d546SAndrew Lunn 1977fee2d546SAndrew Lunn /* Disable temperature sensor */ 1978fee2d546SAndrew Lunn ret = __phy_read(phydev, MII_88E6390_MISC_TEST); 1979fee2d546SAndrew Lunn if (ret < 0) 1980fee2d546SAndrew Lunn goto error; 1981fee2d546SAndrew Lunn 1982fee2d546SAndrew Lunn ret = ret & ~MII_88E6390_MISC_TEST_SAMPLE_MASK; 1983fee2d546SAndrew Lunn ret |= MII_88E6390_MISC_TEST_SAMPLE_DISABLE; 1984fee2d546SAndrew Lunn 1985fee2d546SAndrew Lunn ret = __phy_write(phydev, MII_88E6390_MISC_TEST, ret); 1986fee2d546SAndrew Lunn 1987fee2d546SAndrew Lunn error: 1988fee2d546SAndrew Lunn phy_restore_page(phydev, oldpage, ret); 1989fee2d546SAndrew Lunn 1990fee2d546SAndrew Lunn return ret; 1991fee2d546SAndrew Lunn } 1992fee2d546SAndrew Lunn 1993fee2d546SAndrew Lunn static int m88e6390_hwmon_read(struct device *dev, 1994fee2d546SAndrew Lunn enum hwmon_sensor_types type, 1995fee2d546SAndrew Lunn u32 attr, int channel, long *temp) 1996fee2d546SAndrew Lunn { 1997fee2d546SAndrew Lunn struct phy_device *phydev = dev_get_drvdata(dev); 1998fee2d546SAndrew Lunn int err; 1999fee2d546SAndrew Lunn 2000fee2d546SAndrew Lunn switch (attr) { 2001fee2d546SAndrew Lunn case hwmon_temp_input: 2002fee2d546SAndrew Lunn err = m88e6390_get_temp(phydev, temp); 2003fee2d546SAndrew Lunn break; 2004fee2d546SAndrew Lunn default: 2005fee2d546SAndrew Lunn return -EOPNOTSUPP; 2006fee2d546SAndrew Lunn } 2007fee2d546SAndrew Lunn 2008fee2d546SAndrew Lunn return err; 2009fee2d546SAndrew Lunn } 2010fee2d546SAndrew Lunn 2011fee2d546SAndrew Lunn static umode_t m88e6390_hwmon_is_visible(const void *data, 2012fee2d546SAndrew Lunn enum hwmon_sensor_types type, 2013fee2d546SAndrew Lunn u32 attr, int channel) 2014fee2d546SAndrew Lunn { 2015fee2d546SAndrew Lunn if (type != hwmon_temp) 2016fee2d546SAndrew Lunn return 0; 2017fee2d546SAndrew Lunn 2018fee2d546SAndrew Lunn switch (attr) { 2019fee2d546SAndrew Lunn case hwmon_temp_input: 2020fee2d546SAndrew Lunn return 0444; 2021fee2d546SAndrew Lunn default: 2022fee2d546SAndrew Lunn return 0; 2023fee2d546SAndrew Lunn } 2024fee2d546SAndrew Lunn } 2025fee2d546SAndrew Lunn 2026fee2d546SAndrew Lunn static u32 m88e6390_hwmon_temp_config[] = { 2027fee2d546SAndrew Lunn HWMON_T_INPUT, 2028fee2d546SAndrew Lunn 0 2029fee2d546SAndrew Lunn }; 2030fee2d546SAndrew Lunn 2031fee2d546SAndrew Lunn static const struct hwmon_channel_info m88e6390_hwmon_temp = { 2032fee2d546SAndrew Lunn .type = hwmon_temp, 2033fee2d546SAndrew Lunn .config = m88e6390_hwmon_temp_config, 2034fee2d546SAndrew Lunn }; 2035fee2d546SAndrew Lunn 2036fee2d546SAndrew Lunn static const struct hwmon_channel_info *m88e6390_hwmon_info[] = { 2037fee2d546SAndrew Lunn &m88e1121_hwmon_chip, 2038fee2d546SAndrew Lunn &m88e6390_hwmon_temp, 2039fee2d546SAndrew Lunn NULL 2040fee2d546SAndrew Lunn }; 2041fee2d546SAndrew Lunn 2042fee2d546SAndrew Lunn static const struct hwmon_ops m88e6390_hwmon_hwmon_ops = { 2043fee2d546SAndrew Lunn .is_visible = m88e6390_hwmon_is_visible, 2044fee2d546SAndrew Lunn .read = m88e6390_hwmon_read, 2045fee2d546SAndrew Lunn }; 2046fee2d546SAndrew Lunn 2047fee2d546SAndrew Lunn static const struct hwmon_chip_info m88e6390_hwmon_chip_info = { 2048fee2d546SAndrew Lunn .ops = &m88e6390_hwmon_hwmon_ops, 2049fee2d546SAndrew Lunn .info = m88e6390_hwmon_info, 2050fee2d546SAndrew Lunn }; 2051fee2d546SAndrew Lunn 20520b04680fSAndrew Lunn static int marvell_hwmon_name(struct phy_device *phydev) 20530b04680fSAndrew Lunn { 20540b04680fSAndrew Lunn struct marvell_priv *priv = phydev->priv; 20550b04680fSAndrew Lunn struct device *dev = &phydev->mdio.dev; 20560b04680fSAndrew Lunn const char *devname = dev_name(dev); 20570b04680fSAndrew Lunn size_t len = strlen(devname); 20580b04680fSAndrew Lunn int i, j; 20590b04680fSAndrew Lunn 20600b04680fSAndrew Lunn priv->hwmon_name = devm_kzalloc(dev, len, GFP_KERNEL); 20610b04680fSAndrew Lunn if (!priv->hwmon_name) 20620b04680fSAndrew Lunn return -ENOMEM; 20630b04680fSAndrew Lunn 20640b04680fSAndrew Lunn for (i = j = 0; i < len && devname[i]; i++) { 20650b04680fSAndrew Lunn if (isalnum(devname[i])) 20660b04680fSAndrew Lunn priv->hwmon_name[j++] = devname[i]; 20670b04680fSAndrew Lunn } 20680b04680fSAndrew Lunn 20690b04680fSAndrew Lunn return 0; 20700b04680fSAndrew Lunn } 20710b04680fSAndrew Lunn 20720b04680fSAndrew Lunn static int marvell_hwmon_probe(struct phy_device *phydev, 20730b04680fSAndrew Lunn const struct hwmon_chip_info *chip) 20740b04680fSAndrew Lunn { 20750b04680fSAndrew Lunn struct marvell_priv *priv = phydev->priv; 20760b04680fSAndrew Lunn struct device *dev = &phydev->mdio.dev; 20770b04680fSAndrew Lunn int err; 20780b04680fSAndrew Lunn 20790b04680fSAndrew Lunn err = marvell_hwmon_name(phydev); 20800b04680fSAndrew Lunn if (err) 20810b04680fSAndrew Lunn return err; 20820b04680fSAndrew Lunn 20830b04680fSAndrew Lunn priv->hwmon_dev = devm_hwmon_device_register_with_info( 20840b04680fSAndrew Lunn dev, priv->hwmon_name, phydev, chip, NULL); 20850b04680fSAndrew Lunn 20860b04680fSAndrew Lunn return PTR_ERR_OR_ZERO(priv->hwmon_dev); 20870b04680fSAndrew Lunn } 20880b04680fSAndrew Lunn 20890b04680fSAndrew Lunn static int m88e1121_hwmon_probe(struct phy_device *phydev) 20900b04680fSAndrew Lunn { 20910b04680fSAndrew Lunn return marvell_hwmon_probe(phydev, &m88e1121_hwmon_chip_info); 20920b04680fSAndrew Lunn } 20930b04680fSAndrew Lunn 20940b04680fSAndrew Lunn static int m88e1510_hwmon_probe(struct phy_device *phydev) 20950b04680fSAndrew Lunn { 20960b04680fSAndrew Lunn return marvell_hwmon_probe(phydev, &m88e1510_hwmon_chip_info); 20970b04680fSAndrew Lunn } 2098fee2d546SAndrew Lunn 2099fee2d546SAndrew Lunn static int m88e6390_hwmon_probe(struct phy_device *phydev) 2100fee2d546SAndrew Lunn { 2101fee2d546SAndrew Lunn return marvell_hwmon_probe(phydev, &m88e6390_hwmon_chip_info); 2102fee2d546SAndrew Lunn } 21030b04680fSAndrew Lunn #else 21040b04680fSAndrew Lunn static int m88e1121_hwmon_probe(struct phy_device *phydev) 21050b04680fSAndrew Lunn { 21060b04680fSAndrew Lunn return 0; 21070b04680fSAndrew Lunn } 21080b04680fSAndrew Lunn 21090b04680fSAndrew Lunn static int m88e1510_hwmon_probe(struct phy_device *phydev) 21100b04680fSAndrew Lunn { 21110b04680fSAndrew Lunn return 0; 21120b04680fSAndrew Lunn } 2113fee2d546SAndrew Lunn 2114fee2d546SAndrew Lunn static int m88e6390_hwmon_probe(struct phy_device *phydev) 2115fee2d546SAndrew Lunn { 2116fee2d546SAndrew Lunn return 0; 2117fee2d546SAndrew Lunn } 21180b04680fSAndrew Lunn #endif 21190b04680fSAndrew Lunn 2120d2fa47d9SAndrew Lunn static int marvell_probe(struct phy_device *phydev) 2121d2fa47d9SAndrew Lunn { 2122d2fa47d9SAndrew Lunn struct marvell_priv *priv; 2123d2fa47d9SAndrew Lunn 2124e5a03bfdSAndrew Lunn priv = devm_kzalloc(&phydev->mdio.dev, sizeof(*priv), GFP_KERNEL); 2125d2fa47d9SAndrew Lunn if (!priv) 2126d2fa47d9SAndrew Lunn return -ENOMEM; 2127d2fa47d9SAndrew Lunn 2128d2fa47d9SAndrew Lunn phydev->priv = priv; 2129d2fa47d9SAndrew Lunn 2130d2fa47d9SAndrew Lunn return 0; 2131d2fa47d9SAndrew Lunn } 2132d2fa47d9SAndrew Lunn 21330b04680fSAndrew Lunn static int m88e1121_probe(struct phy_device *phydev) 21340b04680fSAndrew Lunn { 21350b04680fSAndrew Lunn int err; 21360b04680fSAndrew Lunn 21370b04680fSAndrew Lunn err = marvell_probe(phydev); 21380b04680fSAndrew Lunn if (err) 21390b04680fSAndrew Lunn return err; 21400b04680fSAndrew Lunn 21410b04680fSAndrew Lunn return m88e1121_hwmon_probe(phydev); 21420b04680fSAndrew Lunn } 21430b04680fSAndrew Lunn 21440b04680fSAndrew Lunn static int m88e1510_probe(struct phy_device *phydev) 21450b04680fSAndrew Lunn { 21460b04680fSAndrew Lunn int err; 21470b04680fSAndrew Lunn 21480b04680fSAndrew Lunn err = marvell_probe(phydev); 21490b04680fSAndrew Lunn if (err) 21500b04680fSAndrew Lunn return err; 21510b04680fSAndrew Lunn 21520b04680fSAndrew Lunn return m88e1510_hwmon_probe(phydev); 21530b04680fSAndrew Lunn } 21540b04680fSAndrew Lunn 2155fee2d546SAndrew Lunn static int m88e6390_probe(struct phy_device *phydev) 2156fee2d546SAndrew Lunn { 2157fee2d546SAndrew Lunn int err; 2158fee2d546SAndrew Lunn 2159fee2d546SAndrew Lunn err = marvell_probe(phydev); 2160fee2d546SAndrew Lunn if (err) 2161fee2d546SAndrew Lunn return err; 2162fee2d546SAndrew Lunn 2163fee2d546SAndrew Lunn return m88e6390_hwmon_probe(phydev); 2164fee2d546SAndrew Lunn } 2165fee2d546SAndrew Lunn 2166e5479239SOlof Johansson static struct phy_driver marvell_drivers[] = { 2167e5479239SOlof Johansson { 21682f495c39SBenjamin Herrenschmidt .phy_id = MARVELL_PHY_ID_88E1101, 21692f495c39SBenjamin Herrenschmidt .phy_id_mask = MARVELL_PHY_ID_MASK, 217000db8189SAndy Fleming .name = "Marvell 88E1101", 2171dcdecdcfSHeiner Kallweit /* PHY_GBIT_FEATURES */ 217218702414SArnd Bergmann .probe = marvell_probe, 217379be1a1cSClemens Gruber .config_init = &marvell_config_init, 2174f2899788SAndrew Lunn .config_aneg = &m88e1101_config_aneg, 217500db8189SAndy Fleming .ack_interrupt = &marvell_ack_interrupt, 217600db8189SAndy Fleming .config_intr = &marvell_config_intr, 21770898b448SSebastian Hesselbarth .resume = &genphy_resume, 21780898b448SSebastian Hesselbarth .suspend = &genphy_suspend, 2179424ca4c5SRussell King .read_page = marvell_read_page, 2180424ca4c5SRussell King .write_page = marvell_write_page, 2181d2fa47d9SAndrew Lunn .get_sset_count = marvell_get_sset_count, 2182d2fa47d9SAndrew Lunn .get_strings = marvell_get_strings, 2183d2fa47d9SAndrew Lunn .get_stats = marvell_get_stats, 2184e5479239SOlof Johansson }, 2185e5479239SOlof Johansson { 21862f495c39SBenjamin Herrenschmidt .phy_id = MARVELL_PHY_ID_88E1112, 21872f495c39SBenjamin Herrenschmidt .phy_id_mask = MARVELL_PHY_ID_MASK, 218885cfb534SOlof Johansson .name = "Marvell 88E1112", 2189dcdecdcfSHeiner Kallweit /* PHY_GBIT_FEATURES */ 2190d2fa47d9SAndrew Lunn .probe = marvell_probe, 219185cfb534SOlof Johansson .config_init = &m88e1111_config_init, 219285cfb534SOlof Johansson .config_aneg = &marvell_config_aneg, 219385cfb534SOlof Johansson .ack_interrupt = &marvell_ack_interrupt, 219485cfb534SOlof Johansson .config_intr = &marvell_config_intr, 21950898b448SSebastian Hesselbarth .resume = &genphy_resume, 21960898b448SSebastian Hesselbarth .suspend = &genphy_suspend, 2197424ca4c5SRussell King .read_page = marvell_read_page, 2198424ca4c5SRussell King .write_page = marvell_write_page, 2199d2fa47d9SAndrew Lunn .get_sset_count = marvell_get_sset_count, 2200d2fa47d9SAndrew Lunn .get_strings = marvell_get_strings, 2201d2fa47d9SAndrew Lunn .get_stats = marvell_get_stats, 2202262caf47SHeiner Kallweit .get_tunable = m88e1011_get_tunable, 2203262caf47SHeiner Kallweit .set_tunable = m88e1011_set_tunable, 2204262caf47SHeiner Kallweit .link_change_notify = m88e1011_link_change_notify, 220585cfb534SOlof Johansson }, 220685cfb534SOlof Johansson { 22072f495c39SBenjamin Herrenschmidt .phy_id = MARVELL_PHY_ID_88E1111, 22082f495c39SBenjamin Herrenschmidt .phy_id_mask = MARVELL_PHY_ID_MASK, 220976884679SAndy Fleming .name = "Marvell 88E1111", 2210dcdecdcfSHeiner Kallweit /* PHY_GBIT_FEATURES */ 2211d2fa47d9SAndrew Lunn .probe = marvell_probe, 2212e5479239SOlof Johansson .config_init = &m88e1111_config_init, 2213d6ab9336SFlorian Fainelli .config_aneg = &marvell_config_aneg, 2214be937f1fSAlexandr Smirnov .read_status = &marvell_read_status, 221576884679SAndy Fleming .ack_interrupt = &marvell_ack_interrupt, 221676884679SAndy Fleming .config_intr = &marvell_config_intr, 22170898b448SSebastian Hesselbarth .resume = &genphy_resume, 22180898b448SSebastian Hesselbarth .suspend = &genphy_suspend, 2219424ca4c5SRussell King .read_page = marvell_read_page, 2220424ca4c5SRussell King .write_page = marvell_write_page, 2221d2fa47d9SAndrew Lunn .get_sset_count = marvell_get_sset_count, 2222d2fa47d9SAndrew Lunn .get_strings = marvell_get_strings, 2223d2fa47d9SAndrew Lunn .get_stats = marvell_get_stats, 22245c6bc519SHeiner Kallweit .get_tunable = m88e1111_get_tunable, 22255c6bc519SHeiner Kallweit .set_tunable = m88e1111_set_tunable, 22265c6bc519SHeiner Kallweit .link_change_notify = m88e1011_link_change_notify, 2227e5479239SOlof Johansson }, 2228e5479239SOlof Johansson { 22292f495c39SBenjamin Herrenschmidt .phy_id = MARVELL_PHY_ID_88E1118, 22302f495c39SBenjamin Herrenschmidt .phy_id_mask = MARVELL_PHY_ID_MASK, 2231605f196eSRon Madrid .name = "Marvell 88E1118", 2232dcdecdcfSHeiner Kallweit /* PHY_GBIT_FEATURES */ 2233d2fa47d9SAndrew Lunn .probe = marvell_probe, 2234605f196eSRon Madrid .config_init = &m88e1118_config_init, 2235605f196eSRon Madrid .config_aneg = &m88e1118_config_aneg, 2236605f196eSRon Madrid .ack_interrupt = &marvell_ack_interrupt, 2237605f196eSRon Madrid .config_intr = &marvell_config_intr, 22380898b448SSebastian Hesselbarth .resume = &genphy_resume, 22390898b448SSebastian Hesselbarth .suspend = &genphy_suspend, 2240424ca4c5SRussell King .read_page = marvell_read_page, 2241424ca4c5SRussell King .write_page = marvell_write_page, 2242d2fa47d9SAndrew Lunn .get_sset_count = marvell_get_sset_count, 2243d2fa47d9SAndrew Lunn .get_strings = marvell_get_strings, 2244d2fa47d9SAndrew Lunn .get_stats = marvell_get_stats, 2245605f196eSRon Madrid }, 2246605f196eSRon Madrid { 22472f495c39SBenjamin Herrenschmidt .phy_id = MARVELL_PHY_ID_88E1121R, 22482f495c39SBenjamin Herrenschmidt .phy_id_mask = MARVELL_PHY_ID_MASK, 2249140bc929SSergei Poselenov .name = "Marvell 88E1121R", 2250dcdecdcfSHeiner Kallweit /* PHY_GBIT_FEATURES */ 225118702414SArnd Bergmann .probe = &m88e1121_probe, 225207777246SWang Dongsheng .config_init = &marvell_config_init, 2253140bc929SSergei Poselenov .config_aneg = &m88e1121_config_aneg, 2254140bc929SSergei Poselenov .read_status = &marvell_read_status, 2255140bc929SSergei Poselenov .ack_interrupt = &marvell_ack_interrupt, 2256140bc929SSergei Poselenov .config_intr = &marvell_config_intr, 2257dcd07be3SAnatolij Gustschin .did_interrupt = &m88e1121_did_interrupt, 22580898b448SSebastian Hesselbarth .resume = &genphy_resume, 22590898b448SSebastian Hesselbarth .suspend = &genphy_suspend, 2260424ca4c5SRussell King .read_page = marvell_read_page, 2261424ca4c5SRussell King .write_page = marvell_write_page, 2262d2fa47d9SAndrew Lunn .get_sset_count = marvell_get_sset_count, 2263d2fa47d9SAndrew Lunn .get_strings = marvell_get_strings, 2264d2fa47d9SAndrew Lunn .get_stats = marvell_get_stats, 2265911af5e1SHeiner Kallweit .get_tunable = m88e1011_get_tunable, 2266911af5e1SHeiner Kallweit .set_tunable = m88e1011_set_tunable, 2267911af5e1SHeiner Kallweit .link_change_notify = m88e1011_link_change_notify, 2268140bc929SSergei Poselenov }, 2269140bc929SSergei Poselenov { 2270337ac9d5SCyril Chemparathy .phy_id = MARVELL_PHY_ID_88E1318S, 22716ba74014SLinus Torvalds .phy_id_mask = MARVELL_PHY_ID_MASK, 2272337ac9d5SCyril Chemparathy .name = "Marvell 88E1318S", 2273dcdecdcfSHeiner Kallweit /* PHY_GBIT_FEATURES */ 2274d2fa47d9SAndrew Lunn .probe = marvell_probe, 2275dd9a122aSEsben Haabendal .config_init = &m88e1318_config_init, 2276337ac9d5SCyril Chemparathy .config_aneg = &m88e1318_config_aneg, 22773ff1c259SCyril Chemparathy .read_status = &marvell_read_status, 22783ff1c259SCyril Chemparathy .ack_interrupt = &marvell_ack_interrupt, 22793ff1c259SCyril Chemparathy .config_intr = &marvell_config_intr, 22803ff1c259SCyril Chemparathy .did_interrupt = &m88e1121_did_interrupt, 22813871c387SMichael Stapelberg .get_wol = &m88e1318_get_wol, 22823871c387SMichael Stapelberg .set_wol = &m88e1318_set_wol, 22830898b448SSebastian Hesselbarth .resume = &genphy_resume, 22840898b448SSebastian Hesselbarth .suspend = &genphy_suspend, 2285424ca4c5SRussell King .read_page = marvell_read_page, 2286424ca4c5SRussell King .write_page = marvell_write_page, 2287d2fa47d9SAndrew Lunn .get_sset_count = marvell_get_sset_count, 2288d2fa47d9SAndrew Lunn .get_strings = marvell_get_strings, 2289d2fa47d9SAndrew Lunn .get_stats = marvell_get_stats, 22903ff1c259SCyril Chemparathy }, 22913ff1c259SCyril Chemparathy { 22922f495c39SBenjamin Herrenschmidt .phy_id = MARVELL_PHY_ID_88E1145, 22932f495c39SBenjamin Herrenschmidt .phy_id_mask = MARVELL_PHY_ID_MASK, 229476884679SAndy Fleming .name = "Marvell 88E1145", 2295dcdecdcfSHeiner Kallweit /* PHY_GBIT_FEATURES */ 2296d2fa47d9SAndrew Lunn .probe = marvell_probe, 229776884679SAndy Fleming .config_init = &m88e1145_config_init, 2298c505873eSZhao Qiang .config_aneg = &m88e1101_config_aneg, 229976884679SAndy Fleming .read_status = &genphy_read_status, 230076884679SAndy Fleming .ack_interrupt = &marvell_ack_interrupt, 230176884679SAndy Fleming .config_intr = &marvell_config_intr, 23020898b448SSebastian Hesselbarth .resume = &genphy_resume, 23030898b448SSebastian Hesselbarth .suspend = &genphy_suspend, 2304424ca4c5SRussell King .read_page = marvell_read_page, 2305424ca4c5SRussell King .write_page = marvell_write_page, 2306d2fa47d9SAndrew Lunn .get_sset_count = marvell_get_sset_count, 2307d2fa47d9SAndrew Lunn .get_strings = marvell_get_strings, 2308d2fa47d9SAndrew Lunn .get_stats = marvell_get_stats, 2309a319fb52SHeiner Kallweit .get_tunable = m88e1111_get_tunable, 2310a319fb52SHeiner Kallweit .set_tunable = m88e1111_set_tunable, 2311a319fb52SHeiner Kallweit .link_change_notify = m88e1011_link_change_notify, 2312ac8c635aSOlof Johansson }, 2313ac8c635aSOlof Johansson { 231490600732SDavid Daney .phy_id = MARVELL_PHY_ID_88E1149R, 231590600732SDavid Daney .phy_id_mask = MARVELL_PHY_ID_MASK, 231690600732SDavid Daney .name = "Marvell 88E1149R", 2317dcdecdcfSHeiner Kallweit /* PHY_GBIT_FEATURES */ 2318d2fa47d9SAndrew Lunn .probe = marvell_probe, 231990600732SDavid Daney .config_init = &m88e1149_config_init, 232090600732SDavid Daney .config_aneg = &m88e1118_config_aneg, 232190600732SDavid Daney .ack_interrupt = &marvell_ack_interrupt, 232290600732SDavid Daney .config_intr = &marvell_config_intr, 23230898b448SSebastian Hesselbarth .resume = &genphy_resume, 23240898b448SSebastian Hesselbarth .suspend = &genphy_suspend, 2325424ca4c5SRussell King .read_page = marvell_read_page, 2326424ca4c5SRussell King .write_page = marvell_write_page, 2327d2fa47d9SAndrew Lunn .get_sset_count = marvell_get_sset_count, 2328d2fa47d9SAndrew Lunn .get_strings = marvell_get_strings, 2329d2fa47d9SAndrew Lunn .get_stats = marvell_get_stats, 233090600732SDavid Daney }, 233190600732SDavid Daney { 23322f495c39SBenjamin Herrenschmidt .phy_id = MARVELL_PHY_ID_88E1240, 23332f495c39SBenjamin Herrenschmidt .phy_id_mask = MARVELL_PHY_ID_MASK, 2334ac8c635aSOlof Johansson .name = "Marvell 88E1240", 2335dcdecdcfSHeiner Kallweit /* PHY_GBIT_FEATURES */ 2336d2fa47d9SAndrew Lunn .probe = marvell_probe, 2337ac8c635aSOlof Johansson .config_init = &m88e1111_config_init, 2338ac8c635aSOlof Johansson .config_aneg = &marvell_config_aneg, 2339ac8c635aSOlof Johansson .ack_interrupt = &marvell_ack_interrupt, 2340ac8c635aSOlof Johansson .config_intr = &marvell_config_intr, 23410898b448SSebastian Hesselbarth .resume = &genphy_resume, 23420898b448SSebastian Hesselbarth .suspend = &genphy_suspend, 2343424ca4c5SRussell King .read_page = marvell_read_page, 2344424ca4c5SRussell King .write_page = marvell_write_page, 2345d2fa47d9SAndrew Lunn .get_sset_count = marvell_get_sset_count, 2346d2fa47d9SAndrew Lunn .get_strings = marvell_get_strings, 2347d2fa47d9SAndrew Lunn .get_stats = marvell_get_stats, 2348ac8c635aSOlof Johansson }, 23493da09a51SMichal Simek { 23503da09a51SMichal Simek .phy_id = MARVELL_PHY_ID_88E1116R, 23513da09a51SMichal Simek .phy_id_mask = MARVELL_PHY_ID_MASK, 23523da09a51SMichal Simek .name = "Marvell 88E1116R", 2353dcdecdcfSHeiner Kallweit /* PHY_GBIT_FEATURES */ 2354d2fa47d9SAndrew Lunn .probe = marvell_probe, 23553da09a51SMichal Simek .config_init = &m88e1116r_config_init, 23563da09a51SMichal Simek .ack_interrupt = &marvell_ack_interrupt, 23573da09a51SMichal Simek .config_intr = &marvell_config_intr, 23580898b448SSebastian Hesselbarth .resume = &genphy_resume, 23590898b448SSebastian Hesselbarth .suspend = &genphy_suspend, 2360424ca4c5SRussell King .read_page = marvell_read_page, 2361424ca4c5SRussell King .write_page = marvell_write_page, 2362d2fa47d9SAndrew Lunn .get_sset_count = marvell_get_sset_count, 2363d2fa47d9SAndrew Lunn .get_strings = marvell_get_strings, 2364d2fa47d9SAndrew Lunn .get_stats = marvell_get_stats, 2365262caf47SHeiner Kallweit .get_tunable = m88e1011_get_tunable, 2366262caf47SHeiner Kallweit .set_tunable = m88e1011_set_tunable, 2367262caf47SHeiner Kallweit .link_change_notify = m88e1011_link_change_notify, 23683da09a51SMichal Simek }, 236910e24caaSMichal Simek { 237010e24caaSMichal Simek .phy_id = MARVELL_PHY_ID_88E1510, 237110e24caaSMichal Simek .phy_id_mask = MARVELL_PHY_ID_MASK, 237210e24caaSMichal Simek .name = "Marvell 88E1510", 2373719655a1SAndrew Lunn .features = PHY_GBIT_FIBRE_FEATURES, 23740b04680fSAndrew Lunn .probe = &m88e1510_probe, 2375930b37eeSStefan Roese .config_init = &m88e1510_config_init, 237610e24caaSMichal Simek .config_aneg = &m88e1510_config_aneg, 237710e24caaSMichal Simek .read_status = &marvell_read_status, 237810e24caaSMichal Simek .ack_interrupt = &marvell_ack_interrupt, 237910e24caaSMichal Simek .config_intr = &marvell_config_intr, 238010e24caaSMichal Simek .did_interrupt = &m88e1121_did_interrupt, 2381f39aac7eSJingju Hou .get_wol = &m88e1318_get_wol, 2382f39aac7eSJingju Hou .set_wol = &m88e1318_set_wol, 23833758be3dSCharles-Antoine Couret .resume = &marvell_resume, 23843758be3dSCharles-Antoine Couret .suspend = &marvell_suspend, 2385424ca4c5SRussell King .read_page = marvell_read_page, 2386424ca4c5SRussell King .write_page = marvell_write_page, 2387d2fa47d9SAndrew Lunn .get_sset_count = marvell_get_sset_count, 2388d2fa47d9SAndrew Lunn .get_strings = marvell_get_strings, 2389d2fa47d9SAndrew Lunn .get_stats = marvell_get_stats, 2390f0f9b4edSLin Yun Sheng .set_loopback = genphy_loopback, 2391262caf47SHeiner Kallweit .get_tunable = m88e1011_get_tunable, 2392262caf47SHeiner Kallweit .set_tunable = m88e1011_set_tunable, 2393262caf47SHeiner Kallweit .link_change_notify = m88e1011_link_change_notify, 239410e24caaSMichal Simek }, 23956b358aedSSebastian Hesselbarth { 2396819ec8e1SAndrew Lunn .phy_id = MARVELL_PHY_ID_88E1540, 2397819ec8e1SAndrew Lunn .phy_id_mask = MARVELL_PHY_ID_MASK, 2398819ec8e1SAndrew Lunn .name = "Marvell 88E1540", 2399dcdecdcfSHeiner Kallweit /* PHY_GBIT_FEATURES */ 240018702414SArnd Bergmann .probe = m88e1510_probe, 240179be1a1cSClemens Gruber .config_init = &marvell_config_init, 2402819ec8e1SAndrew Lunn .config_aneg = &m88e1510_config_aneg, 2403819ec8e1SAndrew Lunn .read_status = &marvell_read_status, 2404819ec8e1SAndrew Lunn .ack_interrupt = &marvell_ack_interrupt, 2405819ec8e1SAndrew Lunn .config_intr = &marvell_config_intr, 2406819ec8e1SAndrew Lunn .did_interrupt = &m88e1121_did_interrupt, 2407819ec8e1SAndrew Lunn .resume = &genphy_resume, 2408819ec8e1SAndrew Lunn .suspend = &genphy_suspend, 2409424ca4c5SRussell King .read_page = marvell_read_page, 2410424ca4c5SRussell King .write_page = marvell_write_page, 2411d2fa47d9SAndrew Lunn .get_sset_count = marvell_get_sset_count, 2412d2fa47d9SAndrew Lunn .get_strings = marvell_get_strings, 2413d2fa47d9SAndrew Lunn .get_stats = marvell_get_stats, 241469f42be8SHeiner Kallweit .get_tunable = m88e1540_get_tunable, 241569f42be8SHeiner Kallweit .set_tunable = m88e1540_set_tunable, 2416911af5e1SHeiner Kallweit .link_change_notify = m88e1011_link_change_notify, 2417819ec8e1SAndrew Lunn }, 2418819ec8e1SAndrew Lunn { 241960f06fdeSAndrew Lunn .phy_id = MARVELL_PHY_ID_88E1545, 242060f06fdeSAndrew Lunn .phy_id_mask = MARVELL_PHY_ID_MASK, 242160f06fdeSAndrew Lunn .name = "Marvell 88E1545", 242260f06fdeSAndrew Lunn .probe = m88e1510_probe, 2423dcdecdcfSHeiner Kallweit /* PHY_GBIT_FEATURES */ 242460f06fdeSAndrew Lunn .config_init = &marvell_config_init, 242560f06fdeSAndrew Lunn .config_aneg = &m88e1510_config_aneg, 242660f06fdeSAndrew Lunn .read_status = &marvell_read_status, 242760f06fdeSAndrew Lunn .ack_interrupt = &marvell_ack_interrupt, 242860f06fdeSAndrew Lunn .config_intr = &marvell_config_intr, 242960f06fdeSAndrew Lunn .did_interrupt = &m88e1121_did_interrupt, 243060f06fdeSAndrew Lunn .resume = &genphy_resume, 243160f06fdeSAndrew Lunn .suspend = &genphy_suspend, 2432424ca4c5SRussell King .read_page = marvell_read_page, 2433424ca4c5SRussell King .write_page = marvell_write_page, 243460f06fdeSAndrew Lunn .get_sset_count = marvell_get_sset_count, 243560f06fdeSAndrew Lunn .get_strings = marvell_get_strings, 243660f06fdeSAndrew Lunn .get_stats = marvell_get_stats, 2437262caf47SHeiner Kallweit .get_tunable = m88e1540_get_tunable, 2438262caf47SHeiner Kallweit .set_tunable = m88e1540_set_tunable, 2439262caf47SHeiner Kallweit .link_change_notify = m88e1011_link_change_notify, 244060f06fdeSAndrew Lunn }, 244160f06fdeSAndrew Lunn { 24426b358aedSSebastian Hesselbarth .phy_id = MARVELL_PHY_ID_88E3016, 24436b358aedSSebastian Hesselbarth .phy_id_mask = MARVELL_PHY_ID_MASK, 24446b358aedSSebastian Hesselbarth .name = "Marvell 88E3016", 2445dcdecdcfSHeiner Kallweit /* PHY_BASIC_FEATURES */ 2446d2fa47d9SAndrew Lunn .probe = marvell_probe, 24476b358aedSSebastian Hesselbarth .config_init = &m88e3016_config_init, 24486b358aedSSebastian Hesselbarth .aneg_done = &marvell_aneg_done, 24496b358aedSSebastian Hesselbarth .read_status = &marvell_read_status, 24506b358aedSSebastian Hesselbarth .ack_interrupt = &marvell_ack_interrupt, 24516b358aedSSebastian Hesselbarth .config_intr = &marvell_config_intr, 24526b358aedSSebastian Hesselbarth .did_interrupt = &m88e1121_did_interrupt, 24536b358aedSSebastian Hesselbarth .resume = &genphy_resume, 24546b358aedSSebastian Hesselbarth .suspend = &genphy_suspend, 2455424ca4c5SRussell King .read_page = marvell_read_page, 2456424ca4c5SRussell King .write_page = marvell_write_page, 2457d2fa47d9SAndrew Lunn .get_sset_count = marvell_get_sset_count, 2458d2fa47d9SAndrew Lunn .get_strings = marvell_get_strings, 2459d2fa47d9SAndrew Lunn .get_stats = marvell_get_stats, 24606b358aedSSebastian Hesselbarth }, 2461e4cf8a38SAndrew Lunn { 2462e4cf8a38SAndrew Lunn .phy_id = MARVELL_PHY_ID_88E6390, 2463e4cf8a38SAndrew Lunn .phy_id_mask = MARVELL_PHY_ID_MASK, 2464e4cf8a38SAndrew Lunn .name = "Marvell 88E6390", 2465dcdecdcfSHeiner Kallweit /* PHY_GBIT_FEATURES */ 2466fee2d546SAndrew Lunn .probe = m88e6390_probe, 2467e4cf8a38SAndrew Lunn .config_init = &marvell_config_init, 24688cbcdc1aSAndrew Lunn .config_aneg = &m88e6390_config_aneg, 2469e4cf8a38SAndrew Lunn .read_status = &marvell_read_status, 2470e4cf8a38SAndrew Lunn .ack_interrupt = &marvell_ack_interrupt, 2471e4cf8a38SAndrew Lunn .config_intr = &marvell_config_intr, 2472e4cf8a38SAndrew Lunn .did_interrupt = &m88e1121_did_interrupt, 2473e4cf8a38SAndrew Lunn .resume = &genphy_resume, 2474e4cf8a38SAndrew Lunn .suspend = &genphy_suspend, 2475424ca4c5SRussell King .read_page = marvell_read_page, 2476424ca4c5SRussell King .write_page = marvell_write_page, 2477e4cf8a38SAndrew Lunn .get_sset_count = marvell_get_sset_count, 2478e4cf8a38SAndrew Lunn .get_strings = marvell_get_strings, 2479e4cf8a38SAndrew Lunn .get_stats = marvell_get_stats, 248069f42be8SHeiner Kallweit .get_tunable = m88e1540_get_tunable, 248169f42be8SHeiner Kallweit .set_tunable = m88e1540_set_tunable, 2482911af5e1SHeiner Kallweit .link_change_notify = m88e1011_link_change_notify, 2483e4cf8a38SAndrew Lunn }, 248476884679SAndy Fleming }; 248576884679SAndy Fleming 248650fd7150SJohan Hovold module_phy_driver(marvell_drivers); 24874e4f10f6SDavid Woodhouse 2488cf93c945SUwe Kleine-König static struct mdio_device_id __maybe_unused marvell_tbl[] = { 2489f5e1cabfSMichal Simek { MARVELL_PHY_ID_88E1101, MARVELL_PHY_ID_MASK }, 2490f5e1cabfSMichal Simek { MARVELL_PHY_ID_88E1112, MARVELL_PHY_ID_MASK }, 2491f5e1cabfSMichal Simek { MARVELL_PHY_ID_88E1111, MARVELL_PHY_ID_MASK }, 2492f5e1cabfSMichal Simek { MARVELL_PHY_ID_88E1118, MARVELL_PHY_ID_MASK }, 2493f5e1cabfSMichal Simek { MARVELL_PHY_ID_88E1121R, MARVELL_PHY_ID_MASK }, 2494f5e1cabfSMichal Simek { MARVELL_PHY_ID_88E1145, MARVELL_PHY_ID_MASK }, 2495f5e1cabfSMichal Simek { MARVELL_PHY_ID_88E1149R, MARVELL_PHY_ID_MASK }, 2496f5e1cabfSMichal Simek { MARVELL_PHY_ID_88E1240, MARVELL_PHY_ID_MASK }, 2497f5e1cabfSMichal Simek { MARVELL_PHY_ID_88E1318S, MARVELL_PHY_ID_MASK }, 24983da09a51SMichal Simek { MARVELL_PHY_ID_88E1116R, MARVELL_PHY_ID_MASK }, 249910e24caaSMichal Simek { MARVELL_PHY_ID_88E1510, MARVELL_PHY_ID_MASK }, 2500819ec8e1SAndrew Lunn { MARVELL_PHY_ID_88E1540, MARVELL_PHY_ID_MASK }, 250160f06fdeSAndrew Lunn { MARVELL_PHY_ID_88E1545, MARVELL_PHY_ID_MASK }, 25026b358aedSSebastian Hesselbarth { MARVELL_PHY_ID_88E3016, MARVELL_PHY_ID_MASK }, 2503e4cf8a38SAndrew Lunn { MARVELL_PHY_ID_88E6390, MARVELL_PHY_ID_MASK }, 25044e4f10f6SDavid Woodhouse { } 25054e4f10f6SDavid Woodhouse }; 25064e4f10f6SDavid Woodhouse 25074e4f10f6SDavid Woodhouse MODULE_DEVICE_TABLE(mdio, marvell_tbl); 2508