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 6961111598SAndrew Lunn #define MII_M1111_RGMII_RX_DELAY BIT(7) 7061111598SAndrew Lunn #define MII_M1111_RGMII_TX_DELAY BIT(1) 71895ee682SKim Phillips #define MII_M1111_PHY_EXT_SR 0x1b 72be937f1fSAlexandr Smirnov 73895ee682SKim Phillips #define MII_M1111_HWCFG_MODE_MASK 0xf 74be937f1fSAlexandr Smirnov #define MII_M1111_HWCFG_MODE_FIBER_RGMII 0x3 754117b5beSKapil Juneja #define MII_M1111_HWCFG_MODE_SGMII_NO_CLK 0x4 76865b813aSAndrew Lunn #define MII_M1111_HWCFG_MODE_RTBI 0x7 775f8cbc13SLiu Yu-B13201 #define MII_M1111_HWCFG_MODE_COPPER_RTBI 0x9 78865b813aSAndrew Lunn #define MII_M1111_HWCFG_MODE_COPPER_RGMII 0xb 79865b813aSAndrew Lunn #define MII_M1111_HWCFG_FIBER_COPPER_RES BIT(13) 80865b813aSAndrew Lunn #define MII_M1111_HWCFG_FIBER_COPPER_AUTO BIT(15) 81be937f1fSAlexandr Smirnov 82c477d044SCyril Chemparathy #define MII_88E1121_PHY_MSCR_REG 21 83c477d044SCyril Chemparathy #define MII_88E1121_PHY_MSCR_RX_DELAY BIT(5) 84c477d044SCyril Chemparathy #define MII_88E1121_PHY_MSCR_TX_DELAY BIT(4) 85424ca4c5SRussell King #define MII_88E1121_PHY_MSCR_DELAY_MASK (BIT(5) | BIT(4)) 86c477d044SCyril Chemparathy 870b04680fSAndrew Lunn #define MII_88E1121_MISC_TEST 0x1a 880b04680fSAndrew Lunn #define MII_88E1510_MISC_TEST_TEMP_THRESHOLD_MASK 0x1f00 890b04680fSAndrew Lunn #define MII_88E1510_MISC_TEST_TEMP_THRESHOLD_SHIFT 8 900b04680fSAndrew Lunn #define MII_88E1510_MISC_TEST_TEMP_IRQ_EN BIT(7) 910b04680fSAndrew Lunn #define MII_88E1510_MISC_TEST_TEMP_IRQ BIT(6) 920b04680fSAndrew Lunn #define MII_88E1121_MISC_TEST_TEMP_SENSOR_EN BIT(5) 930b04680fSAndrew Lunn #define MII_88E1121_MISC_TEST_TEMP_MASK 0x1f 940b04680fSAndrew Lunn 950b04680fSAndrew Lunn #define MII_88E1510_TEMP_SENSOR 0x1b 960b04680fSAndrew Lunn #define MII_88E1510_TEMP_SENSOR_MASK 0xff 970b04680fSAndrew Lunn 9869f42be8SHeiner Kallweit #define MII_88E1540_COPPER_CTRL3 0x1a 9969f42be8SHeiner Kallweit #define MII_88E1540_COPPER_CTRL3_LINK_DOWN_DELAY_MASK GENMASK(11, 10) 10069f42be8SHeiner Kallweit #define MII_88E1540_COPPER_CTRL3_LINK_DOWN_DELAY_00MS 0 10169f42be8SHeiner Kallweit #define MII_88E1540_COPPER_CTRL3_LINK_DOWN_DELAY_10MS 1 10269f42be8SHeiner Kallweit #define MII_88E1540_COPPER_CTRL3_LINK_DOWN_DELAY_20MS 2 10369f42be8SHeiner Kallweit #define MII_88E1540_COPPER_CTRL3_LINK_DOWN_DELAY_40MS 3 10469f42be8SHeiner Kallweit #define MII_88E1540_COPPER_CTRL3_FAST_LINK_DOWN BIT(9) 10569f42be8SHeiner Kallweit 106fee2d546SAndrew Lunn #define MII_88E6390_MISC_TEST 0x1b 107fee2d546SAndrew Lunn #define MII_88E6390_MISC_TEST_SAMPLE_1S 0 108fee2d546SAndrew Lunn #define MII_88E6390_MISC_TEST_SAMPLE_10MS BIT(14) 109fee2d546SAndrew Lunn #define MII_88E6390_MISC_TEST_SAMPLE_DISABLE BIT(15) 110fee2d546SAndrew Lunn #define MII_88E6390_MISC_TEST_SAMPLE_ENABLE 0 111fee2d546SAndrew Lunn #define MII_88E6390_MISC_TEST_SAMPLE_MASK (0x3 << 14) 112fee2d546SAndrew Lunn 113fee2d546SAndrew Lunn #define MII_88E6390_TEMP_SENSOR 0x1c 114fee2d546SAndrew Lunn #define MII_88E6390_TEMP_SENSOR_MASK 0xff 115fee2d546SAndrew Lunn #define MII_88E6390_TEMP_SENSOR_SAMPLES 10 116fee2d546SAndrew Lunn 117337ac9d5SCyril Chemparathy #define MII_88E1318S_PHY_MSCR1_REG 16 118337ac9d5SCyril Chemparathy #define MII_88E1318S_PHY_MSCR1_PAD_ODD BIT(6) 1193ff1c259SCyril Chemparathy 1203871c387SMichael Stapelberg /* Copper Specific Interrupt Enable Register */ 1213871c387SMichael Stapelberg #define MII_88E1318S_PHY_CSIER 0x12 1223871c387SMichael Stapelberg /* WOL Event Interrupt Enable */ 1233871c387SMichael Stapelberg #define MII_88E1318S_PHY_CSIER_WOL_EIE BIT(7) 1243871c387SMichael Stapelberg 1253871c387SMichael Stapelberg /* LED Timer Control Register */ 1263871c387SMichael Stapelberg #define MII_88E1318S_PHY_LED_TCR 0x12 1273871c387SMichael Stapelberg #define MII_88E1318S_PHY_LED_TCR_FORCE_INT BIT(15) 1283871c387SMichael Stapelberg #define MII_88E1318S_PHY_LED_TCR_INTn_ENABLE BIT(7) 1293871c387SMichael Stapelberg #define MII_88E1318S_PHY_LED_TCR_INT_ACTIVE_LOW BIT(11) 1303871c387SMichael Stapelberg 1313871c387SMichael Stapelberg /* Magic Packet MAC address registers */ 1323871c387SMichael Stapelberg #define MII_88E1318S_PHY_MAGIC_PACKET_WORD2 0x17 1333871c387SMichael Stapelberg #define MII_88E1318S_PHY_MAGIC_PACKET_WORD1 0x18 1343871c387SMichael Stapelberg #define MII_88E1318S_PHY_MAGIC_PACKET_WORD0 0x19 1353871c387SMichael Stapelberg 1363871c387SMichael Stapelberg #define MII_88E1318S_PHY_WOL_CTRL 0x10 1373871c387SMichael Stapelberg #define MII_88E1318S_PHY_WOL_CTRL_CLEAR_WOL_STATUS BIT(12) 1383871c387SMichael Stapelberg #define MII_88E1318S_PHY_WOL_CTRL_MAGIC_PACKET_MATCH_ENABLE BIT(14) 1393871c387SMichael Stapelberg 14007777246SWang Dongsheng #define MII_PHY_LED_CTRL 16 141140bc929SSergei Poselenov #define MII_88E1121_PHY_LED_DEF 0x0030 14207777246SWang Dongsheng #define MII_88E1510_PHY_LED_DEF 0x1177 143a93f7fe1SJian Shen #define MII_88E1510_PHY_LED0_LINK_LED1_ACTIVE 0x1040 144140bc929SSergei Poselenov 145be937f1fSAlexandr Smirnov #define MII_M1011_PHY_STATUS 0x11 146be937f1fSAlexandr Smirnov #define MII_M1011_PHY_STATUS_1000 0x8000 147be937f1fSAlexandr Smirnov #define MII_M1011_PHY_STATUS_100 0x4000 148be937f1fSAlexandr Smirnov #define MII_M1011_PHY_STATUS_SPD_MASK 0xc000 149be937f1fSAlexandr Smirnov #define MII_M1011_PHY_STATUS_FULLDUPLEX 0x2000 150be937f1fSAlexandr Smirnov #define MII_M1011_PHY_STATUS_RESOLVED 0x0800 151be937f1fSAlexandr Smirnov #define MII_M1011_PHY_STATUS_LINK 0x0400 152be937f1fSAlexandr Smirnov 1536b358aedSSebastian Hesselbarth #define MII_88E3016_PHY_SPEC_CTRL 0x10 1546b358aedSSebastian Hesselbarth #define MII_88E3016_DISABLE_SCRAMBLER 0x0200 1556b358aedSSebastian Hesselbarth #define MII_88E3016_AUTO_MDIX_CROSSOVER 0x0030 15676884679SAndy Fleming 157930b37eeSStefan Roese #define MII_88E1510_GEN_CTRL_REG_1 0x14 158930b37eeSStefan Roese #define MII_88E1510_GEN_CTRL_REG_1_MODE_MASK 0x7 159930b37eeSStefan Roese #define MII_88E1510_GEN_CTRL_REG_1_MODE_SGMII 0x1 /* SGMII to copper */ 160930b37eeSStefan Roese #define MII_88E1510_GEN_CTRL_REG_1_RESET 0x8000 /* Soft reset */ 161930b37eeSStefan Roese 1626cfb3bccSCharles-Antoine Couret #define LPA_FIBER_1000HALF 0x40 1636cfb3bccSCharles-Antoine Couret #define LPA_FIBER_1000FULL 0x20 1646cfb3bccSCharles-Antoine Couret 1656cfb3bccSCharles-Antoine Couret #define LPA_PAUSE_FIBER 0x180 1666cfb3bccSCharles-Antoine Couret #define LPA_PAUSE_ASYM_FIBER 0x100 1676cfb3bccSCharles-Antoine Couret 1686cfb3bccSCharles-Antoine Couret #define ADVERTISE_FIBER_1000HALF 0x40 1696cfb3bccSCharles-Antoine Couret #define ADVERTISE_FIBER_1000FULL 0x20 1706cfb3bccSCharles-Antoine Couret 1716cfb3bccSCharles-Antoine Couret #define ADVERTISE_PAUSE_FIBER 0x180 1726cfb3bccSCharles-Antoine Couret #define ADVERTISE_PAUSE_ASYM_FIBER 0x100 1736cfb3bccSCharles-Antoine Couret 1746cfb3bccSCharles-Antoine Couret #define REGISTER_LINK_STATUS 0x400 1752170fef7SCharles-Antoine Couret #define NB_FIBER_STATS 1 1766cfb3bccSCharles-Antoine Couret 17700db8189SAndy Fleming MODULE_DESCRIPTION("Marvell PHY driver"); 17800db8189SAndy Fleming MODULE_AUTHOR("Andy Fleming"); 17900db8189SAndy Fleming MODULE_LICENSE("GPL"); 18000db8189SAndy Fleming 181d2fa47d9SAndrew Lunn struct marvell_hw_stat { 182d2fa47d9SAndrew Lunn const char *string; 183d2fa47d9SAndrew Lunn u8 page; 184d2fa47d9SAndrew Lunn u8 reg; 185d2fa47d9SAndrew Lunn u8 bits; 186d2fa47d9SAndrew Lunn }; 187d2fa47d9SAndrew Lunn 188d2fa47d9SAndrew Lunn static struct marvell_hw_stat marvell_hw_stats[] = { 1892170fef7SCharles-Antoine Couret { "phy_receive_errors_copper", 0, 21, 16}, 190d2fa47d9SAndrew Lunn { "phy_idle_errors", 0, 10, 8 }, 1912170fef7SCharles-Antoine Couret { "phy_receive_errors_fiber", 1, 21, 16}, 192d2fa47d9SAndrew Lunn }; 193d2fa47d9SAndrew Lunn 194d2fa47d9SAndrew Lunn struct marvell_priv { 195d2fa47d9SAndrew Lunn u64 stats[ARRAY_SIZE(marvell_hw_stats)]; 1960b04680fSAndrew Lunn char *hwmon_name; 1970b04680fSAndrew Lunn struct device *hwmon_dev; 198d2fa47d9SAndrew Lunn }; 199d2fa47d9SAndrew Lunn 200424ca4c5SRussell King static int marvell_read_page(struct phy_device *phydev) 2016427bb2dSAndrew Lunn { 202424ca4c5SRussell King return __phy_read(phydev, MII_MARVELL_PHY_PAGE); 203424ca4c5SRussell King } 204424ca4c5SRussell King 205424ca4c5SRussell King static int marvell_write_page(struct phy_device *phydev, int page) 206424ca4c5SRussell King { 207424ca4c5SRussell King return __phy_write(phydev, MII_MARVELL_PHY_PAGE, page); 2086427bb2dSAndrew Lunn } 2096427bb2dSAndrew Lunn 2106427bb2dSAndrew Lunn static int marvell_set_page(struct phy_device *phydev, int page) 2116427bb2dSAndrew Lunn { 2126427bb2dSAndrew Lunn return phy_write(phydev, MII_MARVELL_PHY_PAGE, page); 2136427bb2dSAndrew Lunn } 2146427bb2dSAndrew Lunn 21500db8189SAndy Fleming static int marvell_ack_interrupt(struct phy_device *phydev) 21600db8189SAndy Fleming { 21700db8189SAndy Fleming int err; 21800db8189SAndy Fleming 21900db8189SAndy Fleming /* Clear the interrupts by reading the reg */ 22000db8189SAndy Fleming err = phy_read(phydev, MII_M1011_IEVENT); 22100db8189SAndy Fleming 22200db8189SAndy Fleming if (err < 0) 22300db8189SAndy Fleming return err; 22400db8189SAndy Fleming 22500db8189SAndy Fleming return 0; 22600db8189SAndy Fleming } 22700db8189SAndy Fleming 22800db8189SAndy Fleming static int marvell_config_intr(struct phy_device *phydev) 22900db8189SAndy Fleming { 23000db8189SAndy Fleming int err; 23100db8189SAndy Fleming 23200db8189SAndy Fleming if (phydev->interrupts == PHY_INTERRUPT_ENABLED) 23323beb38fSAndrew Lunn err = phy_write(phydev, MII_M1011_IMASK, 23423beb38fSAndrew Lunn MII_M1011_IMASK_INIT); 23500db8189SAndy Fleming else 23623beb38fSAndrew Lunn err = phy_write(phydev, MII_M1011_IMASK, 23723beb38fSAndrew Lunn MII_M1011_IMASK_CLEAR); 23800db8189SAndy Fleming 23900db8189SAndy Fleming return err; 24000db8189SAndy Fleming } 24100db8189SAndy Fleming 242239aa55bSDavid Thomson static int marvell_set_polarity(struct phy_device *phydev, int polarity) 243239aa55bSDavid Thomson { 244239aa55bSDavid Thomson int reg; 245239aa55bSDavid Thomson int err; 246239aa55bSDavid Thomson int val; 247239aa55bSDavid Thomson 248239aa55bSDavid Thomson /* get the current settings */ 249239aa55bSDavid Thomson reg = phy_read(phydev, MII_M1011_PHY_SCR); 250239aa55bSDavid Thomson if (reg < 0) 251239aa55bSDavid Thomson return reg; 252239aa55bSDavid Thomson 253239aa55bSDavid Thomson val = reg; 254239aa55bSDavid Thomson val &= ~MII_M1011_PHY_SCR_AUTO_CROSS; 255239aa55bSDavid Thomson switch (polarity) { 256239aa55bSDavid Thomson case ETH_TP_MDI: 257239aa55bSDavid Thomson val |= MII_M1011_PHY_SCR_MDI; 258239aa55bSDavid Thomson break; 259239aa55bSDavid Thomson case ETH_TP_MDI_X: 260239aa55bSDavid Thomson val |= MII_M1011_PHY_SCR_MDI_X; 261239aa55bSDavid Thomson break; 262239aa55bSDavid Thomson case ETH_TP_MDI_AUTO: 263239aa55bSDavid Thomson case ETH_TP_MDI_INVALID: 264239aa55bSDavid Thomson default: 265239aa55bSDavid Thomson val |= MII_M1011_PHY_SCR_AUTO_CROSS; 266239aa55bSDavid Thomson break; 267239aa55bSDavid Thomson } 268239aa55bSDavid Thomson 269239aa55bSDavid Thomson if (val != reg) { 270239aa55bSDavid Thomson /* Set the new polarity value in the register */ 271239aa55bSDavid Thomson err = phy_write(phydev, MII_M1011_PHY_SCR, val); 272239aa55bSDavid Thomson if (err) 273239aa55bSDavid Thomson return err; 274239aa55bSDavid Thomson } 275239aa55bSDavid Thomson 276d6ab9336SFlorian Fainelli return val != reg; 277239aa55bSDavid Thomson } 278239aa55bSDavid Thomson 27900db8189SAndy Fleming static int marvell_config_aneg(struct phy_device *phydev) 28000db8189SAndy Fleming { 281d6ab9336SFlorian Fainelli int changed = 0; 28200db8189SAndy Fleming int err; 28300db8189SAndy Fleming 2844e26c5c3SRaju Lakkaraju err = marvell_set_polarity(phydev, phydev->mdix_ctrl); 28576884679SAndy Fleming if (err < 0) 28676884679SAndy Fleming return err; 28776884679SAndy Fleming 288d6ab9336SFlorian Fainelli changed = err; 289d6ab9336SFlorian Fainelli 29076884679SAndy Fleming err = phy_write(phydev, MII_M1111_PHY_LED_CONTROL, 29176884679SAndy Fleming MII_M1111_PHY_LED_DIRECT); 29276884679SAndy Fleming if (err < 0) 29376884679SAndy Fleming return err; 29400db8189SAndy Fleming 29500db8189SAndy Fleming err = genphy_config_aneg(phydev); 2968ff44985SAnton Vorontsov if (err < 0) 29700db8189SAndy Fleming return err; 2988ff44985SAnton Vorontsov 299d6ab9336SFlorian Fainelli if (phydev->autoneg != AUTONEG_ENABLE || changed) { 3000c3439bcSAndrew Lunn /* A write to speed/duplex bits (that is performed by 3018ff44985SAnton Vorontsov * genphy_config_aneg() call above) must be followed by 3028ff44985SAnton Vorontsov * a software reset. Otherwise, the write has no effect. 3038ff44985SAnton Vorontsov */ 30434386344SAndrew Lunn err = genphy_soft_reset(phydev); 3058ff44985SAnton Vorontsov if (err < 0) 3068ff44985SAnton Vorontsov return err; 3078ff44985SAnton Vorontsov } 3088ff44985SAnton Vorontsov 3098ff44985SAnton Vorontsov return 0; 31000db8189SAndy Fleming } 31100db8189SAndy Fleming 312f2899788SAndrew Lunn static int m88e1101_config_aneg(struct phy_device *phydev) 313f2899788SAndrew Lunn { 314f2899788SAndrew Lunn int err; 315f2899788SAndrew Lunn 316f2899788SAndrew Lunn /* This Marvell PHY has an errata which requires 317f2899788SAndrew Lunn * that certain registers get written in order 318f2899788SAndrew Lunn * to restart autonegotiation 319f2899788SAndrew Lunn */ 32034386344SAndrew Lunn err = genphy_soft_reset(phydev); 321f2899788SAndrew Lunn if (err < 0) 322f2899788SAndrew Lunn return err; 323f2899788SAndrew Lunn 324f2899788SAndrew Lunn err = phy_write(phydev, 0x1d, 0x1f); 325f2899788SAndrew Lunn if (err < 0) 326f2899788SAndrew Lunn return err; 327f2899788SAndrew Lunn 328f2899788SAndrew Lunn err = phy_write(phydev, 0x1e, 0x200c); 329f2899788SAndrew Lunn if (err < 0) 330f2899788SAndrew Lunn return err; 331f2899788SAndrew Lunn 332f2899788SAndrew Lunn err = phy_write(phydev, 0x1d, 0x5); 333f2899788SAndrew Lunn if (err < 0) 334f2899788SAndrew Lunn return err; 335f2899788SAndrew Lunn 336f2899788SAndrew Lunn err = phy_write(phydev, 0x1e, 0); 337f2899788SAndrew Lunn if (err < 0) 338f2899788SAndrew Lunn return err; 339f2899788SAndrew Lunn 340f2899788SAndrew Lunn err = phy_write(phydev, 0x1e, 0x100); 341f2899788SAndrew Lunn if (err < 0) 342f2899788SAndrew Lunn return err; 343f2899788SAndrew Lunn 344f2899788SAndrew Lunn return marvell_config_aneg(phydev); 345f2899788SAndrew Lunn } 346f2899788SAndrew Lunn 347cf41a51dSDavid Daney #ifdef CONFIG_OF_MDIO 3480c3439bcSAndrew Lunn /* Set and/or override some configuration registers based on the 349cf41a51dSDavid Daney * marvell,reg-init property stored in the of_node for the phydev. 350cf41a51dSDavid Daney * 351cf41a51dSDavid Daney * marvell,reg-init = <reg-page reg mask value>,...; 352cf41a51dSDavid Daney * 353cf41a51dSDavid Daney * There may be one or more sets of <reg-page reg mask value>: 354cf41a51dSDavid Daney * 355cf41a51dSDavid Daney * reg-page: which register bank to use. 356cf41a51dSDavid Daney * reg: the register. 357cf41a51dSDavid Daney * mask: if non-zero, ANDed with existing register value. 358cf41a51dSDavid Daney * value: ORed with the masked value and written to the regiser. 359cf41a51dSDavid Daney * 360cf41a51dSDavid Daney */ 361cf41a51dSDavid Daney static int marvell_of_reg_init(struct phy_device *phydev) 362cf41a51dSDavid Daney { 363cf41a51dSDavid Daney const __be32 *paddr; 364424ca4c5SRussell King int len, i, saved_page, current_page, ret = 0; 365cf41a51dSDavid Daney 366e5a03bfdSAndrew Lunn if (!phydev->mdio.dev.of_node) 367cf41a51dSDavid Daney return 0; 368cf41a51dSDavid Daney 369e5a03bfdSAndrew Lunn paddr = of_get_property(phydev->mdio.dev.of_node, 370e5a03bfdSAndrew Lunn "marvell,reg-init", &len); 371cf41a51dSDavid Daney if (!paddr || len < (4 * sizeof(*paddr))) 372cf41a51dSDavid Daney return 0; 373cf41a51dSDavid Daney 374424ca4c5SRussell King saved_page = phy_save_page(phydev); 375cf41a51dSDavid Daney if (saved_page < 0) 376424ca4c5SRussell King goto err; 377cf41a51dSDavid Daney current_page = saved_page; 378cf41a51dSDavid Daney 379cf41a51dSDavid Daney len /= sizeof(*paddr); 380cf41a51dSDavid Daney for (i = 0; i < len - 3; i += 4) { 3816427bb2dSAndrew Lunn u16 page = be32_to_cpup(paddr + i); 382cf41a51dSDavid Daney u16 reg = be32_to_cpup(paddr + i + 1); 383cf41a51dSDavid Daney u16 mask = be32_to_cpup(paddr + i + 2); 384cf41a51dSDavid Daney u16 val_bits = be32_to_cpup(paddr + i + 3); 385cf41a51dSDavid Daney int val; 386cf41a51dSDavid Daney 3876427bb2dSAndrew Lunn if (page != current_page) { 3886427bb2dSAndrew Lunn current_page = page; 389424ca4c5SRussell King ret = marvell_write_page(phydev, page); 390cf41a51dSDavid Daney if (ret < 0) 391cf41a51dSDavid Daney goto err; 392cf41a51dSDavid Daney } 393cf41a51dSDavid Daney 394cf41a51dSDavid Daney val = 0; 395cf41a51dSDavid Daney if (mask) { 396424ca4c5SRussell King val = __phy_read(phydev, reg); 397cf41a51dSDavid Daney if (val < 0) { 398cf41a51dSDavid Daney ret = val; 399cf41a51dSDavid Daney goto err; 400cf41a51dSDavid Daney } 401cf41a51dSDavid Daney val &= mask; 402cf41a51dSDavid Daney } 403cf41a51dSDavid Daney val |= val_bits; 404cf41a51dSDavid Daney 405424ca4c5SRussell King ret = __phy_write(phydev, reg, val); 406cf41a51dSDavid Daney if (ret < 0) 407cf41a51dSDavid Daney goto err; 408cf41a51dSDavid Daney } 409cf41a51dSDavid Daney err: 410424ca4c5SRussell King return phy_restore_page(phydev, saved_page, ret); 411cf41a51dSDavid Daney } 412cf41a51dSDavid Daney #else 413cf41a51dSDavid Daney static int marvell_of_reg_init(struct phy_device *phydev) 414cf41a51dSDavid Daney { 415cf41a51dSDavid Daney return 0; 416cf41a51dSDavid Daney } 417cf41a51dSDavid Daney #endif /* CONFIG_OF_MDIO */ 418cf41a51dSDavid Daney 419864dc729SAndrew Lunn static int m88e1121_config_aneg_rgmii_delays(struct phy_device *phydev) 420140bc929SSergei Poselenov { 421424ca4c5SRussell King int mscr; 422c477d044SCyril Chemparathy 423c477d044SCyril Chemparathy if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID) 424424ca4c5SRussell King mscr = MII_88E1121_PHY_MSCR_RX_DELAY | 425424ca4c5SRussell King MII_88E1121_PHY_MSCR_TX_DELAY; 426c477d044SCyril Chemparathy else if (phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID) 427424ca4c5SRussell King mscr = MII_88E1121_PHY_MSCR_RX_DELAY; 428c477d044SCyril Chemparathy else if (phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID) 429424ca4c5SRussell King mscr = MII_88E1121_PHY_MSCR_TX_DELAY; 430424ca4c5SRussell King else 431424ca4c5SRussell King mscr = 0; 432c477d044SCyril Chemparathy 433424ca4c5SRussell King return phy_modify_paged(phydev, MII_MARVELL_MSCR_PAGE, 434424ca4c5SRussell King MII_88E1121_PHY_MSCR_REG, 435424ca4c5SRussell King MII_88E1121_PHY_MSCR_DELAY_MASK, mscr); 436be8c6480SArnaud Patard } 437c477d044SCyril Chemparathy 438864dc729SAndrew Lunn static int m88e1121_config_aneg(struct phy_device *phydev) 439864dc729SAndrew Lunn { 440d6ab9336SFlorian Fainelli int changed = 0; 441864dc729SAndrew Lunn int err = 0; 442864dc729SAndrew Lunn 443864dc729SAndrew Lunn if (phy_interface_is_rgmii(phydev)) { 444864dc729SAndrew Lunn err = m88e1121_config_aneg_rgmii_delays(phydev); 445fea23fb5SRussell King if (err < 0) 446864dc729SAndrew Lunn return err; 447864dc729SAndrew Lunn } 448140bc929SSergei Poselenov 449fecd5e91SAndrew Lunn err = marvell_set_polarity(phydev, phydev->mdix_ctrl); 450140bc929SSergei Poselenov if (err < 0) 451140bc929SSergei Poselenov return err; 452140bc929SSergei Poselenov 453d6ab9336SFlorian Fainelli changed = err; 454d6ab9336SFlorian Fainelli 455d6ab9336SFlorian Fainelli err = genphy_config_aneg(phydev); 456d6ab9336SFlorian Fainelli if (err < 0) 457d6ab9336SFlorian Fainelli return err; 458d6ab9336SFlorian Fainelli 4594b1bd697SDavid S. Miller if (phydev->autoneg != AUTONEG_ENABLE || changed) { 460d6ab9336SFlorian Fainelli /* A software reset is used to ensure a "commit" of the 461d6ab9336SFlorian Fainelli * changes is done. 462d6ab9336SFlorian Fainelli */ 463d6ab9336SFlorian Fainelli err = genphy_soft_reset(phydev); 464d6ab9336SFlorian Fainelli if (err < 0) 465d6ab9336SFlorian Fainelli return err; 466d6ab9336SFlorian Fainelli } 467d6ab9336SFlorian Fainelli 468d6ab9336SFlorian Fainelli return 0; 469140bc929SSergei Poselenov } 470140bc929SSergei Poselenov 471337ac9d5SCyril Chemparathy static int m88e1318_config_aneg(struct phy_device *phydev) 4723ff1c259SCyril Chemparathy { 473424ca4c5SRussell King int err; 4743ff1c259SCyril Chemparathy 475424ca4c5SRussell King err = phy_modify_paged(phydev, MII_MARVELL_MSCR_PAGE, 476424ca4c5SRussell King MII_88E1318S_PHY_MSCR1_REG, 477424ca4c5SRussell King 0, MII_88E1318S_PHY_MSCR1_PAD_ODD); 4783ff1c259SCyril Chemparathy if (err < 0) 4793ff1c259SCyril Chemparathy return err; 4803ff1c259SCyril Chemparathy 4813ff1c259SCyril Chemparathy return m88e1121_config_aneg(phydev); 4823ff1c259SCyril Chemparathy } 4833ff1c259SCyril Chemparathy 48478301ebeSCharles-Antoine Couret /** 4853c1bcc86SAndrew Lunn * linkmode_adv_to_fiber_adv_t 4863c1bcc86SAndrew Lunn * @advertise: the linkmode advertisement settings 48778301ebeSCharles-Antoine Couret * 4883c1bcc86SAndrew Lunn * A small helper function that translates linkmode advertisement 4893c1bcc86SAndrew Lunn * settings to phy autonegotiation advertisements for the MII_ADV 4903c1bcc86SAndrew Lunn * register for fiber link. 49178301ebeSCharles-Antoine Couret */ 4923c1bcc86SAndrew Lunn static inline u32 linkmode_adv_to_fiber_adv_t(unsigned long *advertise) 49378301ebeSCharles-Antoine Couret { 49478301ebeSCharles-Antoine Couret u32 result = 0; 49578301ebeSCharles-Antoine Couret 4963c1bcc86SAndrew Lunn if (linkmode_test_bit(ETHTOOL_LINK_MODE_1000baseT_Half_BIT, advertise)) 49778301ebeSCharles-Antoine Couret result |= ADVERTISE_FIBER_1000HALF; 4983c1bcc86SAndrew Lunn if (linkmode_test_bit(ETHTOOL_LINK_MODE_1000baseT_Full_BIT, advertise)) 49978301ebeSCharles-Antoine Couret result |= ADVERTISE_FIBER_1000FULL; 50078301ebeSCharles-Antoine Couret 5013c1bcc86SAndrew Lunn if (linkmode_test_bit(ETHTOOL_LINK_MODE_Asym_Pause_BIT, advertise) && 5023c1bcc86SAndrew Lunn linkmode_test_bit(ETHTOOL_LINK_MODE_Pause_BIT, advertise)) 50378301ebeSCharles-Antoine Couret result |= LPA_PAUSE_ASYM_FIBER; 5043c1bcc86SAndrew Lunn else if (linkmode_test_bit(ETHTOOL_LINK_MODE_Pause_BIT, advertise)) 50578301ebeSCharles-Antoine Couret result |= (ADVERTISE_PAUSE_FIBER 50678301ebeSCharles-Antoine Couret & (~ADVERTISE_PAUSE_ASYM_FIBER)); 50778301ebeSCharles-Antoine Couret 50878301ebeSCharles-Antoine Couret return result; 50978301ebeSCharles-Antoine Couret } 51078301ebeSCharles-Antoine Couret 51178301ebeSCharles-Antoine Couret /** 51278301ebeSCharles-Antoine Couret * marvell_config_aneg_fiber - restart auto-negotiation or write BMCR 51378301ebeSCharles-Antoine Couret * @phydev: target phy_device struct 51478301ebeSCharles-Antoine Couret * 51578301ebeSCharles-Antoine Couret * Description: If auto-negotiation is enabled, we configure the 51678301ebeSCharles-Antoine Couret * advertising, and then restart auto-negotiation. If it is not 51778301ebeSCharles-Antoine Couret * enabled, then we write the BMCR. Adapted for fiber link in 51878301ebeSCharles-Antoine Couret * some Marvell's devices. 51978301ebeSCharles-Antoine Couret */ 52078301ebeSCharles-Antoine Couret static int marvell_config_aneg_fiber(struct phy_device *phydev) 52178301ebeSCharles-Antoine Couret { 52278301ebeSCharles-Antoine Couret int changed = 0; 52378301ebeSCharles-Antoine Couret int err; 52478301ebeSCharles-Antoine Couret int adv, oldadv; 52578301ebeSCharles-Antoine Couret 52678301ebeSCharles-Antoine Couret if (phydev->autoneg != AUTONEG_ENABLE) 52778301ebeSCharles-Antoine Couret return genphy_setup_forced(phydev); 52878301ebeSCharles-Antoine Couret 52978301ebeSCharles-Antoine Couret /* Only allow advertising what this PHY supports */ 5303c1bcc86SAndrew Lunn linkmode_and(phydev->advertising, phydev->advertising, 5313c1bcc86SAndrew Lunn phydev->supported); 53278301ebeSCharles-Antoine Couret 53378301ebeSCharles-Antoine Couret /* Setup fiber advertisement */ 53478301ebeSCharles-Antoine Couret adv = phy_read(phydev, MII_ADVERTISE); 53578301ebeSCharles-Antoine Couret if (adv < 0) 53678301ebeSCharles-Antoine Couret return adv; 53778301ebeSCharles-Antoine Couret 53878301ebeSCharles-Antoine Couret oldadv = adv; 53978301ebeSCharles-Antoine Couret adv &= ~(ADVERTISE_FIBER_1000HALF | ADVERTISE_FIBER_1000FULL 54078301ebeSCharles-Antoine Couret | LPA_PAUSE_FIBER); 5413c1bcc86SAndrew Lunn adv |= linkmode_adv_to_fiber_adv_t(phydev->advertising); 54278301ebeSCharles-Antoine Couret 54378301ebeSCharles-Antoine Couret if (adv != oldadv) { 54478301ebeSCharles-Antoine Couret err = phy_write(phydev, MII_ADVERTISE, adv); 54578301ebeSCharles-Antoine Couret if (err < 0) 54678301ebeSCharles-Antoine Couret return err; 54778301ebeSCharles-Antoine Couret 54878301ebeSCharles-Antoine Couret changed = 1; 54978301ebeSCharles-Antoine Couret } 55078301ebeSCharles-Antoine Couret 55178301ebeSCharles-Antoine Couret if (changed == 0) { 55278301ebeSCharles-Antoine Couret /* Advertisement hasn't changed, but maybe aneg was never on to 55378301ebeSCharles-Antoine Couret * begin with? Or maybe phy was isolated? 55478301ebeSCharles-Antoine Couret */ 55578301ebeSCharles-Antoine Couret int ctl = phy_read(phydev, MII_BMCR); 55678301ebeSCharles-Antoine Couret 55778301ebeSCharles-Antoine Couret if (ctl < 0) 55878301ebeSCharles-Antoine Couret return ctl; 55978301ebeSCharles-Antoine Couret 56078301ebeSCharles-Antoine Couret if (!(ctl & BMCR_ANENABLE) || (ctl & BMCR_ISOLATE)) 56178301ebeSCharles-Antoine Couret changed = 1; /* do restart aneg */ 56278301ebeSCharles-Antoine Couret } 56378301ebeSCharles-Antoine Couret 56478301ebeSCharles-Antoine Couret /* Only restart aneg if we are advertising something different 56578301ebeSCharles-Antoine Couret * than we were before. 56678301ebeSCharles-Antoine Couret */ 56778301ebeSCharles-Antoine Couret if (changed > 0) 56878301ebeSCharles-Antoine Couret changed = genphy_restart_aneg(phydev); 56978301ebeSCharles-Antoine Couret 57078301ebeSCharles-Antoine Couret return changed; 57178301ebeSCharles-Antoine Couret } 57278301ebeSCharles-Antoine Couret 57310e24caaSMichal Simek static int m88e1510_config_aneg(struct phy_device *phydev) 57410e24caaSMichal Simek { 57510e24caaSMichal Simek int err; 57610e24caaSMichal Simek 57752295666SAndrew Lunn err = marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE); 57878301ebeSCharles-Antoine Couret if (err < 0) 57978301ebeSCharles-Antoine Couret goto error; 58078301ebeSCharles-Antoine Couret 58178301ebeSCharles-Antoine Couret /* Configure the copper link first */ 58210e24caaSMichal Simek err = m88e1318_config_aneg(phydev); 58310e24caaSMichal Simek if (err < 0) 58478301ebeSCharles-Antoine Couret goto error; 58510e24caaSMichal Simek 586de9c4e06SRussell King /* Do not touch the fiber page if we're in copper->sgmii mode */ 587de9c4e06SRussell King if (phydev->interface == PHY_INTERFACE_MODE_SGMII) 588de9c4e06SRussell King return 0; 589de9c4e06SRussell King 59078301ebeSCharles-Antoine Couret /* Then the fiber link */ 59152295666SAndrew Lunn err = marvell_set_page(phydev, MII_MARVELL_FIBER_PAGE); 59278301ebeSCharles-Antoine Couret if (err < 0) 59378301ebeSCharles-Antoine Couret goto error; 59478301ebeSCharles-Antoine Couret 59578301ebeSCharles-Antoine Couret err = marvell_config_aneg_fiber(phydev); 59678301ebeSCharles-Antoine Couret if (err < 0) 59778301ebeSCharles-Antoine Couret goto error; 59878301ebeSCharles-Antoine Couret 59952295666SAndrew Lunn return marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE); 60078301ebeSCharles-Antoine Couret 60178301ebeSCharles-Antoine Couret error: 60252295666SAndrew Lunn marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE); 60378301ebeSCharles-Antoine Couret return err; 60479be1a1cSClemens Gruber } 60579be1a1cSClemens Gruber 60607777246SWang Dongsheng static void marvell_config_led(struct phy_device *phydev) 60707777246SWang Dongsheng { 60807777246SWang Dongsheng u16 def_config; 60907777246SWang Dongsheng int err; 61007777246SWang Dongsheng 61107777246SWang Dongsheng switch (MARVELL_PHY_FAMILY_ID(phydev->phy_id)) { 61207777246SWang Dongsheng /* Default PHY LED config: LED[0] .. Link, LED[1] .. Activity */ 61307777246SWang Dongsheng case MARVELL_PHY_FAMILY_ID(MARVELL_PHY_ID_88E1121R): 61407777246SWang Dongsheng case MARVELL_PHY_FAMILY_ID(MARVELL_PHY_ID_88E1318S): 61507777246SWang Dongsheng def_config = MII_88E1121_PHY_LED_DEF; 61607777246SWang Dongsheng break; 61707777246SWang Dongsheng /* Default PHY LED config: 61807777246SWang Dongsheng * LED[0] .. 1000Mbps Link 61907777246SWang Dongsheng * LED[1] .. 100Mbps Link 62007777246SWang Dongsheng * LED[2] .. Blink, Activity 62107777246SWang Dongsheng */ 62207777246SWang Dongsheng case MARVELL_PHY_FAMILY_ID(MARVELL_PHY_ID_88E1510): 623a93f7fe1SJian Shen if (phydev->dev_flags & MARVELL_PHY_LED0_LINK_LED1_ACTIVE) 624a93f7fe1SJian Shen def_config = MII_88E1510_PHY_LED0_LINK_LED1_ACTIVE; 625a93f7fe1SJian Shen else 62607777246SWang Dongsheng def_config = MII_88E1510_PHY_LED_DEF; 62707777246SWang Dongsheng break; 62807777246SWang Dongsheng default: 62907777246SWang Dongsheng return; 63007777246SWang Dongsheng } 63107777246SWang Dongsheng 63207777246SWang Dongsheng err = phy_write_paged(phydev, MII_MARVELL_LED_PAGE, MII_PHY_LED_CTRL, 63307777246SWang Dongsheng def_config); 63407777246SWang Dongsheng if (err < 0) 635ab2a605fSAndrew Lunn phydev_warn(phydev, "Fail to config marvell phy LED.\n"); 63607777246SWang Dongsheng } 63707777246SWang Dongsheng 63879be1a1cSClemens Gruber static int marvell_config_init(struct phy_device *phydev) 63979be1a1cSClemens Gruber { 64007777246SWang Dongsheng /* Set defalut LED */ 64107777246SWang Dongsheng marvell_config_led(phydev); 64207777246SWang Dongsheng 64379be1a1cSClemens Gruber /* Set registers from marvell,reg-init DT property */ 64410e24caaSMichal Simek return marvell_of_reg_init(phydev); 64510e24caaSMichal Simek } 64610e24caaSMichal Simek 6476b358aedSSebastian Hesselbarth static int m88e3016_config_init(struct phy_device *phydev) 6486b358aedSSebastian Hesselbarth { 649fea23fb5SRussell King int ret; 6506b358aedSSebastian Hesselbarth 6516b358aedSSebastian Hesselbarth /* Enable Scrambler and Auto-Crossover */ 652fea23fb5SRussell King ret = phy_modify(phydev, MII_88E3016_PHY_SPEC_CTRL, 653f102852fSRussell King MII_88E3016_DISABLE_SCRAMBLER, 654fea23fb5SRussell King MII_88E3016_AUTO_MDIX_CROSSOVER); 655fea23fb5SRussell King if (ret < 0) 656fea23fb5SRussell King return ret; 6576b358aedSSebastian Hesselbarth 65879be1a1cSClemens Gruber return marvell_config_init(phydev); 6596b358aedSSebastian Hesselbarth } 6606b358aedSSebastian Hesselbarth 661865b813aSAndrew Lunn static int m88e1111_config_init_hwcfg_mode(struct phy_device *phydev, 662865b813aSAndrew Lunn u16 mode, 663865b813aSAndrew Lunn int fibre_copper_auto) 664865b813aSAndrew Lunn { 665865b813aSAndrew Lunn if (fibre_copper_auto) 666fea23fb5SRussell King mode |= MII_M1111_HWCFG_FIBER_COPPER_AUTO; 667865b813aSAndrew Lunn 668fea23fb5SRussell King return phy_modify(phydev, MII_M1111_PHY_EXT_SR, 669f102852fSRussell King MII_M1111_HWCFG_MODE_MASK | 670fea23fb5SRussell King MII_M1111_HWCFG_FIBER_COPPER_AUTO | 671f102852fSRussell King MII_M1111_HWCFG_FIBER_COPPER_RES, 672fea23fb5SRussell King mode); 673865b813aSAndrew Lunn } 674865b813aSAndrew Lunn 67561111598SAndrew Lunn static int m88e1111_config_init_rgmii_delays(struct phy_device *phydev) 676895ee682SKim Phillips { 677fea23fb5SRussell King int delay; 678895ee682SKim Phillips 6799daf5a76SKim Phillips if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID) { 680fea23fb5SRussell King delay = MII_M1111_RGMII_RX_DELAY | MII_M1111_RGMII_TX_DELAY; 6819daf5a76SKim Phillips } else if (phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID) { 682fea23fb5SRussell King delay = MII_M1111_RGMII_RX_DELAY; 6839daf5a76SKim Phillips } else if (phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID) { 684fea23fb5SRussell King delay = MII_M1111_RGMII_TX_DELAY; 685fea23fb5SRussell King } else { 686fea23fb5SRussell King delay = 0; 6879daf5a76SKim Phillips } 688895ee682SKim Phillips 689fea23fb5SRussell King return phy_modify(phydev, MII_M1111_PHY_EXT_CR, 690f102852fSRussell King MII_M1111_RGMII_RX_DELAY | MII_M1111_RGMII_TX_DELAY, 691fea23fb5SRussell King delay); 69261111598SAndrew Lunn } 69361111598SAndrew Lunn 69461111598SAndrew Lunn static int m88e1111_config_init_rgmii(struct phy_device *phydev) 69561111598SAndrew Lunn { 69661111598SAndrew Lunn int temp; 69761111598SAndrew Lunn int err; 69861111598SAndrew Lunn 69961111598SAndrew Lunn err = m88e1111_config_init_rgmii_delays(phydev); 700895ee682SKim Phillips if (err < 0) 701895ee682SKim Phillips return err; 702895ee682SKim Phillips 703895ee682SKim Phillips temp = phy_read(phydev, MII_M1111_PHY_EXT_SR); 704895ee682SKim Phillips if (temp < 0) 705895ee682SKim Phillips return temp; 706895ee682SKim Phillips 707895ee682SKim Phillips temp &= ~(MII_M1111_HWCFG_MODE_MASK); 708be937f1fSAlexandr Smirnov 7097239016dSWang Jian if (temp & MII_M1111_HWCFG_FIBER_COPPER_RES) 710be937f1fSAlexandr Smirnov temp |= MII_M1111_HWCFG_MODE_FIBER_RGMII; 711be937f1fSAlexandr Smirnov else 712be937f1fSAlexandr Smirnov temp |= MII_M1111_HWCFG_MODE_COPPER_RGMII; 713895ee682SKim Phillips 714e1dde8dcSAndrew Lunn return phy_write(phydev, MII_M1111_PHY_EXT_SR, temp); 715895ee682SKim Phillips } 716895ee682SKim Phillips 717e1dde8dcSAndrew Lunn static int m88e1111_config_init_sgmii(struct phy_device *phydev) 718e1dde8dcSAndrew Lunn { 719e1dde8dcSAndrew Lunn int err; 720e1dde8dcSAndrew Lunn 721865b813aSAndrew Lunn err = m88e1111_config_init_hwcfg_mode( 722865b813aSAndrew Lunn phydev, 723865b813aSAndrew Lunn MII_M1111_HWCFG_MODE_SGMII_NO_CLK, 724865b813aSAndrew Lunn MII_M1111_HWCFG_FIBER_COPPER_AUTO); 7254117b5beSKapil Juneja if (err < 0) 7264117b5beSKapil Juneja return err; 72707151bc9SMadalin Bucur 72807151bc9SMadalin Bucur /* make sure copper is selected */ 72952295666SAndrew Lunn return marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE); 7304117b5beSKapil Juneja } 7314117b5beSKapil Juneja 732e1dde8dcSAndrew Lunn static int m88e1111_config_init_rtbi(struct phy_device *phydev) 733e1dde8dcSAndrew Lunn { 73461111598SAndrew Lunn int err; 735e1dde8dcSAndrew Lunn 73661111598SAndrew Lunn err = m88e1111_config_init_rgmii_delays(phydev); 737fea23fb5SRussell King if (err < 0) 7385f8cbc13SLiu Yu-B13201 return err; 7395f8cbc13SLiu Yu-B13201 740865b813aSAndrew Lunn err = m88e1111_config_init_hwcfg_mode( 741865b813aSAndrew Lunn phydev, 742865b813aSAndrew Lunn MII_M1111_HWCFG_MODE_RTBI, 743865b813aSAndrew Lunn MII_M1111_HWCFG_FIBER_COPPER_AUTO); 7445f8cbc13SLiu Yu-B13201 if (err < 0) 7455f8cbc13SLiu Yu-B13201 return err; 7465f8cbc13SLiu Yu-B13201 7475f8cbc13SLiu Yu-B13201 /* soft reset */ 74834386344SAndrew Lunn err = genphy_soft_reset(phydev); 7495f8cbc13SLiu Yu-B13201 if (err < 0) 7505f8cbc13SLiu Yu-B13201 return err; 751e1dde8dcSAndrew Lunn 752865b813aSAndrew Lunn return m88e1111_config_init_hwcfg_mode( 753865b813aSAndrew Lunn phydev, 754865b813aSAndrew Lunn MII_M1111_HWCFG_MODE_RTBI, 755865b813aSAndrew Lunn MII_M1111_HWCFG_FIBER_COPPER_AUTO); 756e1dde8dcSAndrew Lunn } 757e1dde8dcSAndrew Lunn 758e1dde8dcSAndrew Lunn static int m88e1111_config_init(struct phy_device *phydev) 759e1dde8dcSAndrew Lunn { 760e1dde8dcSAndrew Lunn int err; 761e1dde8dcSAndrew Lunn 762e1dde8dcSAndrew Lunn if (phy_interface_is_rgmii(phydev)) { 763e1dde8dcSAndrew Lunn err = m88e1111_config_init_rgmii(phydev); 764fea23fb5SRussell King if (err < 0) 765e1dde8dcSAndrew Lunn return err; 766e1dde8dcSAndrew Lunn } 767e1dde8dcSAndrew Lunn 768e1dde8dcSAndrew Lunn if (phydev->interface == PHY_INTERFACE_MODE_SGMII) { 769e1dde8dcSAndrew Lunn err = m88e1111_config_init_sgmii(phydev); 770e1dde8dcSAndrew Lunn if (err < 0) 771e1dde8dcSAndrew Lunn return err; 772e1dde8dcSAndrew Lunn } 773e1dde8dcSAndrew Lunn 774e1dde8dcSAndrew Lunn if (phydev->interface == PHY_INTERFACE_MODE_RTBI) { 775e1dde8dcSAndrew Lunn err = m88e1111_config_init_rtbi(phydev); 7765f8cbc13SLiu Yu-B13201 if (err < 0) 7775f8cbc13SLiu Yu-B13201 return err; 7785f8cbc13SLiu Yu-B13201 } 7795f8cbc13SLiu Yu-B13201 780cf41a51dSDavid Daney err = marvell_of_reg_init(phydev); 781cf41a51dSDavid Daney if (err < 0) 782cf41a51dSDavid Daney return err; 7835f8cbc13SLiu Yu-B13201 78434386344SAndrew Lunn return genphy_soft_reset(phydev); 785895ee682SKim Phillips } 786895ee682SKim Phillips 787911af5e1SHeiner Kallweit static int m88e1011_get_downshift(struct phy_device *phydev, u8 *data) 788a3bdfce7SHeiner Kallweit { 789a3bdfce7SHeiner Kallweit int val, cnt, enable; 790a3bdfce7SHeiner Kallweit 791a3bdfce7SHeiner Kallweit val = phy_read(phydev, MII_M1011_PHY_SCR); 792a3bdfce7SHeiner Kallweit if (val < 0) 793a3bdfce7SHeiner Kallweit return val; 794a3bdfce7SHeiner Kallweit 795a3bdfce7SHeiner Kallweit enable = FIELD_GET(MII_M1011_PHY_SCR_DOWNSHIFT_EN, val); 796f8d975beSHeiner Kallweit cnt = FIELD_GET(MII_M1011_PHY_SCR_DOWNSHIFT_MASK, val) + 1; 797a3bdfce7SHeiner Kallweit 798a3bdfce7SHeiner Kallweit *data = enable ? cnt : DOWNSHIFT_DEV_DISABLE; 799a3bdfce7SHeiner Kallweit 800a3bdfce7SHeiner Kallweit return 0; 801a3bdfce7SHeiner Kallweit } 802a3bdfce7SHeiner Kallweit 803911af5e1SHeiner Kallweit static int m88e1011_set_downshift(struct phy_device *phydev, u8 cnt) 804a3bdfce7SHeiner Kallweit { 805a3bdfce7SHeiner Kallweit int val; 806a3bdfce7SHeiner Kallweit 807a3bdfce7SHeiner Kallweit if (cnt > MII_M1011_PHY_SCR_DOWNSHIFT_MAX) 808a3bdfce7SHeiner Kallweit return -E2BIG; 809a3bdfce7SHeiner Kallweit 810a3bdfce7SHeiner Kallweit if (!cnt) 811a3bdfce7SHeiner Kallweit return phy_clear_bits(phydev, MII_M1011_PHY_SCR, 812a3bdfce7SHeiner Kallweit MII_M1011_PHY_SCR_DOWNSHIFT_EN); 813a3bdfce7SHeiner Kallweit 814a3bdfce7SHeiner Kallweit val = MII_M1011_PHY_SCR_DOWNSHIFT_EN; 815f8d975beSHeiner Kallweit val |= FIELD_PREP(MII_M1011_PHY_SCR_DOWNSHIFT_MASK, cnt - 1); 816a3bdfce7SHeiner Kallweit 817a3bdfce7SHeiner Kallweit return phy_modify(phydev, MII_M1011_PHY_SCR, 818a3bdfce7SHeiner Kallweit MII_M1011_PHY_SCR_DOWNSHIFT_EN | 819f8d975beSHeiner Kallweit MII_M1011_PHY_SCR_DOWNSHIFT_MASK, 820a3bdfce7SHeiner Kallweit val); 821a3bdfce7SHeiner Kallweit } 822a3bdfce7SHeiner Kallweit 823911af5e1SHeiner Kallweit static int m88e1011_get_tunable(struct phy_device *phydev, 824a3bdfce7SHeiner Kallweit struct ethtool_tunable *tuna, void *data) 825a3bdfce7SHeiner Kallweit { 826a3bdfce7SHeiner Kallweit switch (tuna->id) { 827a3bdfce7SHeiner Kallweit case ETHTOOL_PHY_DOWNSHIFT: 828911af5e1SHeiner Kallweit return m88e1011_get_downshift(phydev, data); 829a3bdfce7SHeiner Kallweit default: 830a3bdfce7SHeiner Kallweit return -EOPNOTSUPP; 831a3bdfce7SHeiner Kallweit } 832a3bdfce7SHeiner Kallweit } 833a3bdfce7SHeiner Kallweit 834911af5e1SHeiner Kallweit static int m88e1011_set_tunable(struct phy_device *phydev, 835a3bdfce7SHeiner Kallweit struct ethtool_tunable *tuna, const void *data) 836a3bdfce7SHeiner Kallweit { 837a3bdfce7SHeiner Kallweit switch (tuna->id) { 838a3bdfce7SHeiner Kallweit case ETHTOOL_PHY_DOWNSHIFT: 839911af5e1SHeiner Kallweit return m88e1011_set_downshift(phydev, *(const u8 *)data); 840a3bdfce7SHeiner Kallweit default: 841a3bdfce7SHeiner Kallweit return -EOPNOTSUPP; 842a3bdfce7SHeiner Kallweit } 843a3bdfce7SHeiner Kallweit } 844a3bdfce7SHeiner Kallweit 845911af5e1SHeiner Kallweit static void m88e1011_link_change_notify(struct phy_device *phydev) 846a3bdfce7SHeiner Kallweit { 847a3bdfce7SHeiner Kallweit int status; 848a3bdfce7SHeiner Kallweit 849a3bdfce7SHeiner Kallweit if (phydev->state != PHY_RUNNING) 850a3bdfce7SHeiner Kallweit return; 851a3bdfce7SHeiner Kallweit 852a3bdfce7SHeiner Kallweit /* we may be on fiber page currently */ 853a3bdfce7SHeiner Kallweit status = phy_read_paged(phydev, MII_MARVELL_COPPER_PAGE, 854a3bdfce7SHeiner Kallweit MII_M1011_PHY_SSR); 855a3bdfce7SHeiner Kallweit 856a3bdfce7SHeiner Kallweit if (status > 0 && status & MII_M1011_PHY_SSR_DOWNSHIFT) 857a3bdfce7SHeiner Kallweit phydev_warn(phydev, "Downshift occurred! Cabling may be defective.\n"); 858a3bdfce7SHeiner Kallweit } 859a3bdfce7SHeiner Kallweit 860e2d861ccSHeiner Kallweit static int m88e1116r_config_init(struct phy_device *phydev) 861e2d861ccSHeiner Kallweit { 862e2d861ccSHeiner Kallweit int err; 863e2d861ccSHeiner Kallweit 864e2d861ccSHeiner Kallweit err = genphy_soft_reset(phydev); 865e2d861ccSHeiner Kallweit if (err < 0) 866e2d861ccSHeiner Kallweit return err; 867e2d861ccSHeiner Kallweit 868e2d861ccSHeiner Kallweit msleep(500); 869e2d861ccSHeiner Kallweit 870e2d861ccSHeiner Kallweit err = marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE); 871e2d861ccSHeiner Kallweit if (err < 0) 872e2d861ccSHeiner Kallweit return err; 873e2d861ccSHeiner Kallweit 874e2d861ccSHeiner Kallweit err = marvell_set_polarity(phydev, phydev->mdix_ctrl); 875e2d861ccSHeiner Kallweit if (err < 0) 876e2d861ccSHeiner Kallweit return err; 877e2d861ccSHeiner Kallweit 878911af5e1SHeiner Kallweit err = m88e1011_set_downshift(phydev, 8); 879e2d861ccSHeiner Kallweit if (err < 0) 880e2d861ccSHeiner Kallweit return err; 881e2d861ccSHeiner Kallweit 882e2d861ccSHeiner Kallweit if (phy_interface_is_rgmii(phydev)) { 883e2d861ccSHeiner Kallweit err = m88e1121_config_aneg_rgmii_delays(phydev); 884e2d861ccSHeiner Kallweit if (err < 0) 885e2d861ccSHeiner Kallweit return err; 886e2d861ccSHeiner Kallweit } 887e2d861ccSHeiner Kallweit 888e2d861ccSHeiner Kallweit err = genphy_soft_reset(phydev); 889e2d861ccSHeiner Kallweit if (err < 0) 890e2d861ccSHeiner Kallweit return err; 891e2d861ccSHeiner Kallweit 892e2d861ccSHeiner Kallweit return marvell_config_init(phydev); 893e2d861ccSHeiner Kallweit } 894e2d861ccSHeiner Kallweit 895dd9a122aSEsben Haabendal static int m88e1318_config_init(struct phy_device *phydev) 896dd9a122aSEsben Haabendal { 897dd9a122aSEsben Haabendal if (phy_interrupt_is_valid(phydev)) { 898dd9a122aSEsben Haabendal int err = phy_modify_paged( 899dd9a122aSEsben Haabendal phydev, MII_MARVELL_LED_PAGE, 900dd9a122aSEsben Haabendal MII_88E1318S_PHY_LED_TCR, 901dd9a122aSEsben Haabendal MII_88E1318S_PHY_LED_TCR_FORCE_INT, 902dd9a122aSEsben Haabendal MII_88E1318S_PHY_LED_TCR_INTn_ENABLE | 903dd9a122aSEsben Haabendal MII_88E1318S_PHY_LED_TCR_INT_ACTIVE_LOW); 904dd9a122aSEsben Haabendal if (err < 0) 905dd9a122aSEsben Haabendal return err; 906dd9a122aSEsben Haabendal } 907dd9a122aSEsben Haabendal 90807777246SWang Dongsheng return marvell_config_init(phydev); 909dd9a122aSEsben Haabendal } 910dd9a122aSEsben Haabendal 911407353ecSClemens Gruber static int m88e1510_config_init(struct phy_device *phydev) 912407353ecSClemens Gruber { 913407353ecSClemens Gruber int err; 914407353ecSClemens Gruber 915407353ecSClemens Gruber /* SGMII-to-Copper mode initialization */ 916407353ecSClemens Gruber if (phydev->interface == PHY_INTERFACE_MODE_SGMII) { 917407353ecSClemens Gruber /* Select page 18 */ 9186427bb2dSAndrew Lunn err = marvell_set_page(phydev, 18); 919407353ecSClemens Gruber if (err < 0) 920407353ecSClemens Gruber return err; 921407353ecSClemens Gruber 922407353ecSClemens Gruber /* In reg 20, write MODE[2:0] = 0x1 (SGMII to Copper) */ 923fea23fb5SRussell King err = phy_modify(phydev, MII_88E1510_GEN_CTRL_REG_1, 924f102852fSRussell King MII_88E1510_GEN_CTRL_REG_1_MODE_MASK, 925fea23fb5SRussell King MII_88E1510_GEN_CTRL_REG_1_MODE_SGMII); 926407353ecSClemens Gruber if (err < 0) 927407353ecSClemens Gruber return err; 928407353ecSClemens Gruber 929407353ecSClemens Gruber /* PHY reset is necessary after changing MODE[2:0] */ 930fea23fb5SRussell King err = phy_modify(phydev, MII_88E1510_GEN_CTRL_REG_1, 0, 931fea23fb5SRussell King MII_88E1510_GEN_CTRL_REG_1_RESET); 932407353ecSClemens Gruber if (err < 0) 933407353ecSClemens Gruber return err; 934407353ecSClemens Gruber 935407353ecSClemens Gruber /* Reset page selection */ 93652295666SAndrew Lunn err = marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE); 937407353ecSClemens Gruber if (err < 0) 938407353ecSClemens Gruber return err; 939407353ecSClemens Gruber } 940407353ecSClemens Gruber 941dd9a122aSEsben Haabendal return m88e1318_config_init(phydev); 942407353ecSClemens Gruber } 943407353ecSClemens Gruber 944605f196eSRon Madrid static int m88e1118_config_aneg(struct phy_device *phydev) 945605f196eSRon Madrid { 946605f196eSRon Madrid int err; 947605f196eSRon Madrid 94834386344SAndrew Lunn err = genphy_soft_reset(phydev); 949605f196eSRon Madrid if (err < 0) 950605f196eSRon Madrid return err; 951605f196eSRon Madrid 952fecd5e91SAndrew Lunn err = marvell_set_polarity(phydev, phydev->mdix_ctrl); 953605f196eSRon Madrid if (err < 0) 954605f196eSRon Madrid return err; 955605f196eSRon Madrid 956605f196eSRon Madrid err = genphy_config_aneg(phydev); 957605f196eSRon Madrid return 0; 958605f196eSRon Madrid } 959605f196eSRon Madrid 960605f196eSRon Madrid static int m88e1118_config_init(struct phy_device *phydev) 961605f196eSRon Madrid { 962605f196eSRon Madrid int err; 963605f196eSRon Madrid 964605f196eSRon Madrid /* Change address */ 96552295666SAndrew Lunn err = marvell_set_page(phydev, MII_MARVELL_MSCR_PAGE); 966605f196eSRon Madrid if (err < 0) 967605f196eSRon Madrid return err; 968605f196eSRon Madrid 969605f196eSRon Madrid /* Enable 1000 Mbit */ 970605f196eSRon Madrid err = phy_write(phydev, 0x15, 0x1070); 971605f196eSRon Madrid if (err < 0) 972605f196eSRon Madrid return err; 973605f196eSRon Madrid 974605f196eSRon Madrid /* Change address */ 97552295666SAndrew Lunn err = marvell_set_page(phydev, MII_MARVELL_LED_PAGE); 976605f196eSRon Madrid if (err < 0) 977605f196eSRon Madrid return err; 978605f196eSRon Madrid 979605f196eSRon Madrid /* Adjust LED Control */ 9802f495c39SBenjamin Herrenschmidt if (phydev->dev_flags & MARVELL_PHY_M1118_DNS323_LEDS) 9812f495c39SBenjamin Herrenschmidt err = phy_write(phydev, 0x10, 0x1100); 9822f495c39SBenjamin Herrenschmidt else 983605f196eSRon Madrid err = phy_write(phydev, 0x10, 0x021e); 984605f196eSRon Madrid if (err < 0) 985605f196eSRon Madrid return err; 986605f196eSRon Madrid 987cf41a51dSDavid Daney err = marvell_of_reg_init(phydev); 988cf41a51dSDavid Daney if (err < 0) 989cf41a51dSDavid Daney return err; 990cf41a51dSDavid Daney 991605f196eSRon Madrid /* Reset address */ 99252295666SAndrew Lunn err = marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE); 993605f196eSRon Madrid if (err < 0) 994605f196eSRon Madrid return err; 995605f196eSRon Madrid 99634386344SAndrew Lunn return genphy_soft_reset(phydev); 997605f196eSRon Madrid } 998605f196eSRon Madrid 99990600732SDavid Daney static int m88e1149_config_init(struct phy_device *phydev) 100090600732SDavid Daney { 100190600732SDavid Daney int err; 100290600732SDavid Daney 100390600732SDavid Daney /* Change address */ 100452295666SAndrew Lunn err = marvell_set_page(phydev, MII_MARVELL_MSCR_PAGE); 100590600732SDavid Daney if (err < 0) 100690600732SDavid Daney return err; 100790600732SDavid Daney 100890600732SDavid Daney /* Enable 1000 Mbit */ 100990600732SDavid Daney err = phy_write(phydev, 0x15, 0x1048); 101090600732SDavid Daney if (err < 0) 101190600732SDavid Daney return err; 101290600732SDavid Daney 1013cf41a51dSDavid Daney err = marvell_of_reg_init(phydev); 1014cf41a51dSDavid Daney if (err < 0) 1015cf41a51dSDavid Daney return err; 1016cf41a51dSDavid Daney 101790600732SDavid Daney /* Reset address */ 101852295666SAndrew Lunn err = marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE); 101990600732SDavid Daney if (err < 0) 102090600732SDavid Daney return err; 102190600732SDavid Daney 102234386344SAndrew Lunn return genphy_soft_reset(phydev); 102390600732SDavid Daney } 102490600732SDavid Daney 1025e1dde8dcSAndrew Lunn static int m88e1145_config_init_rgmii(struct phy_device *phydev) 102676884679SAndy Fleming { 102776884679SAndy Fleming int err; 1028e69d9ed4SAndrew Lunn 102961111598SAndrew Lunn err = m88e1111_config_init_rgmii_delays(phydev); 103076884679SAndy Fleming if (err < 0) 103176884679SAndy Fleming return err; 103276884679SAndy Fleming 10332f495c39SBenjamin Herrenschmidt if (phydev->dev_flags & MARVELL_PHY_M1145_FLAGS_RESISTANCE) { 103476884679SAndy Fleming err = phy_write(phydev, 0x1d, 0x0012); 103576884679SAndy Fleming if (err < 0) 103676884679SAndy Fleming return err; 103776884679SAndy Fleming 1038f102852fSRussell King err = phy_modify(phydev, 0x1e, 0x0fc0, 1039fea23fb5SRussell King 2 << 9 | /* 36 ohm */ 1040fea23fb5SRussell King 2 << 6); /* 39 ohm */ 104176884679SAndy Fleming if (err < 0) 104276884679SAndy Fleming return err; 104376884679SAndy Fleming 104476884679SAndy Fleming err = phy_write(phydev, 0x1d, 0x3); 104576884679SAndy Fleming if (err < 0) 104676884679SAndy Fleming return err; 104776884679SAndy Fleming 104876884679SAndy Fleming err = phy_write(phydev, 0x1e, 0x8000); 1049e1dde8dcSAndrew Lunn } 105076884679SAndy Fleming return err; 105176884679SAndy Fleming } 105276884679SAndy Fleming 1053e1dde8dcSAndrew Lunn static int m88e1145_config_init_sgmii(struct phy_device *phydev) 1054e1dde8dcSAndrew Lunn { 1055865b813aSAndrew Lunn return m88e1111_config_init_hwcfg_mode( 1056865b813aSAndrew Lunn phydev, MII_M1111_HWCFG_MODE_SGMII_NO_CLK, 1057865b813aSAndrew Lunn MII_M1111_HWCFG_FIBER_COPPER_AUTO); 1058e1dde8dcSAndrew Lunn } 1059e1dde8dcSAndrew Lunn 1060e1dde8dcSAndrew Lunn static int m88e1145_config_init(struct phy_device *phydev) 1061e1dde8dcSAndrew Lunn { 1062e1dde8dcSAndrew Lunn int err; 1063e1dde8dcSAndrew Lunn 1064e1dde8dcSAndrew Lunn /* Take care of errata E0 & E1 */ 1065e1dde8dcSAndrew Lunn err = phy_write(phydev, 0x1d, 0x001b); 1066e1dde8dcSAndrew Lunn if (err < 0) 1067e1dde8dcSAndrew Lunn return err; 1068e1dde8dcSAndrew Lunn 1069e1dde8dcSAndrew Lunn err = phy_write(phydev, 0x1e, 0x418f); 1070e1dde8dcSAndrew Lunn if (err < 0) 1071e1dde8dcSAndrew Lunn return err; 1072e1dde8dcSAndrew Lunn 1073e1dde8dcSAndrew Lunn err = phy_write(phydev, 0x1d, 0x0016); 1074e1dde8dcSAndrew Lunn if (err < 0) 1075e1dde8dcSAndrew Lunn return err; 1076e1dde8dcSAndrew Lunn 1077e1dde8dcSAndrew Lunn err = phy_write(phydev, 0x1e, 0xa2da); 1078e1dde8dcSAndrew Lunn if (err < 0) 1079e1dde8dcSAndrew Lunn return err; 1080e1dde8dcSAndrew Lunn 1081e1dde8dcSAndrew Lunn if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID) { 1082e1dde8dcSAndrew Lunn err = m88e1145_config_init_rgmii(phydev); 1083e1dde8dcSAndrew Lunn if (err < 0) 1084e1dde8dcSAndrew Lunn return err; 1085e1dde8dcSAndrew Lunn } 1086e1dde8dcSAndrew Lunn 1087e1dde8dcSAndrew Lunn if (phydev->interface == PHY_INTERFACE_MODE_SGMII) { 1088e1dde8dcSAndrew Lunn err = m88e1145_config_init_sgmii(phydev); 1089b0224175SViet Nga Dao if (err < 0) 1090b0224175SViet Nga Dao return err; 1091b0224175SViet Nga Dao } 1092b0224175SViet Nga Dao 1093cf41a51dSDavid Daney err = marvell_of_reg_init(phydev); 1094cf41a51dSDavid Daney if (err < 0) 1095cf41a51dSDavid Daney return err; 1096cf41a51dSDavid Daney 109776884679SAndy Fleming return 0; 109876884679SAndy Fleming } 109900db8189SAndy Fleming 110069f42be8SHeiner Kallweit static int m88e1540_get_fld(struct phy_device *phydev, u8 *msecs) 110169f42be8SHeiner Kallweit { 110269f42be8SHeiner Kallweit int val; 110369f42be8SHeiner Kallweit 110469f42be8SHeiner Kallweit val = phy_read(phydev, MII_88E1540_COPPER_CTRL3); 110569f42be8SHeiner Kallweit if (val < 0) 110669f42be8SHeiner Kallweit return val; 110769f42be8SHeiner Kallweit 110869f42be8SHeiner Kallweit if (!(val & MII_88E1540_COPPER_CTRL3_FAST_LINK_DOWN)) { 110969f42be8SHeiner Kallweit *msecs = ETHTOOL_PHY_FAST_LINK_DOWN_OFF; 111069f42be8SHeiner Kallweit return 0; 111169f42be8SHeiner Kallweit } 111269f42be8SHeiner Kallweit 111369f42be8SHeiner Kallweit val = FIELD_GET(MII_88E1540_COPPER_CTRL3_LINK_DOWN_DELAY_MASK, val); 111469f42be8SHeiner Kallweit 111569f42be8SHeiner Kallweit switch (val) { 111669f42be8SHeiner Kallweit case MII_88E1540_COPPER_CTRL3_LINK_DOWN_DELAY_00MS: 111769f42be8SHeiner Kallweit *msecs = 0; 111869f42be8SHeiner Kallweit break; 111969f42be8SHeiner Kallweit case MII_88E1540_COPPER_CTRL3_LINK_DOWN_DELAY_10MS: 112069f42be8SHeiner Kallweit *msecs = 10; 112169f42be8SHeiner Kallweit break; 112269f42be8SHeiner Kallweit case MII_88E1540_COPPER_CTRL3_LINK_DOWN_DELAY_20MS: 112369f42be8SHeiner Kallweit *msecs = 20; 112469f42be8SHeiner Kallweit break; 112569f42be8SHeiner Kallweit case MII_88E1540_COPPER_CTRL3_LINK_DOWN_DELAY_40MS: 112669f42be8SHeiner Kallweit *msecs = 40; 112769f42be8SHeiner Kallweit break; 112869f42be8SHeiner Kallweit default: 112969f42be8SHeiner Kallweit return -EINVAL; 113069f42be8SHeiner Kallweit } 113169f42be8SHeiner Kallweit 113269f42be8SHeiner Kallweit return 0; 113369f42be8SHeiner Kallweit } 113469f42be8SHeiner Kallweit 113569f42be8SHeiner Kallweit static int m88e1540_set_fld(struct phy_device *phydev, const u8 *msecs) 113669f42be8SHeiner Kallweit { 113769f42be8SHeiner Kallweit struct ethtool_eee eee; 113869f42be8SHeiner Kallweit int val, ret; 113969f42be8SHeiner Kallweit 114069f42be8SHeiner Kallweit if (*msecs == ETHTOOL_PHY_FAST_LINK_DOWN_OFF) 114169f42be8SHeiner Kallweit return phy_clear_bits(phydev, MII_88E1540_COPPER_CTRL3, 114269f42be8SHeiner Kallweit MII_88E1540_COPPER_CTRL3_FAST_LINK_DOWN); 114369f42be8SHeiner Kallweit 114469f42be8SHeiner Kallweit /* According to the Marvell data sheet EEE must be disabled for 114569f42be8SHeiner Kallweit * Fast Link Down detection to work properly 114669f42be8SHeiner Kallweit */ 114769f42be8SHeiner Kallweit ret = phy_ethtool_get_eee(phydev, &eee); 114869f42be8SHeiner Kallweit if (!ret && eee.eee_enabled) { 114969f42be8SHeiner Kallweit phydev_warn(phydev, "Fast Link Down detection requires EEE to be disabled!\n"); 115069f42be8SHeiner Kallweit return -EBUSY; 115169f42be8SHeiner Kallweit } 115269f42be8SHeiner Kallweit 115369f42be8SHeiner Kallweit if (*msecs <= 5) 115469f42be8SHeiner Kallweit val = MII_88E1540_COPPER_CTRL3_LINK_DOWN_DELAY_00MS; 115569f42be8SHeiner Kallweit else if (*msecs <= 15) 115669f42be8SHeiner Kallweit val = MII_88E1540_COPPER_CTRL3_LINK_DOWN_DELAY_10MS; 115769f42be8SHeiner Kallweit else if (*msecs <= 30) 115869f42be8SHeiner Kallweit val = MII_88E1540_COPPER_CTRL3_LINK_DOWN_DELAY_20MS; 115969f42be8SHeiner Kallweit else 116069f42be8SHeiner Kallweit val = MII_88E1540_COPPER_CTRL3_LINK_DOWN_DELAY_40MS; 116169f42be8SHeiner Kallweit 116269f42be8SHeiner Kallweit val = FIELD_PREP(MII_88E1540_COPPER_CTRL3_LINK_DOWN_DELAY_MASK, val); 116369f42be8SHeiner Kallweit 116469f42be8SHeiner Kallweit ret = phy_modify(phydev, MII_88E1540_COPPER_CTRL3, 116569f42be8SHeiner Kallweit MII_88E1540_COPPER_CTRL3_LINK_DOWN_DELAY_MASK, val); 116669f42be8SHeiner Kallweit if (ret) 116769f42be8SHeiner Kallweit return ret; 116869f42be8SHeiner Kallweit 116969f42be8SHeiner Kallweit return phy_set_bits(phydev, MII_88E1540_COPPER_CTRL3, 117069f42be8SHeiner Kallweit MII_88E1540_COPPER_CTRL3_FAST_LINK_DOWN); 117169f42be8SHeiner Kallweit } 117269f42be8SHeiner Kallweit 117369f42be8SHeiner Kallweit static int m88e1540_get_tunable(struct phy_device *phydev, 117469f42be8SHeiner Kallweit struct ethtool_tunable *tuna, void *data) 117569f42be8SHeiner Kallweit { 117669f42be8SHeiner Kallweit switch (tuna->id) { 117769f42be8SHeiner Kallweit case ETHTOOL_PHY_FAST_LINK_DOWN: 117869f42be8SHeiner Kallweit return m88e1540_get_fld(phydev, data); 1179a3bdfce7SHeiner Kallweit case ETHTOOL_PHY_DOWNSHIFT: 1180911af5e1SHeiner Kallweit return m88e1011_get_downshift(phydev, data); 118169f42be8SHeiner Kallweit default: 118269f42be8SHeiner Kallweit return -EOPNOTSUPP; 118369f42be8SHeiner Kallweit } 118469f42be8SHeiner Kallweit } 118569f42be8SHeiner Kallweit 118669f42be8SHeiner Kallweit static int m88e1540_set_tunable(struct phy_device *phydev, 118769f42be8SHeiner Kallweit struct ethtool_tunable *tuna, const void *data) 118869f42be8SHeiner Kallweit { 118969f42be8SHeiner Kallweit switch (tuna->id) { 119069f42be8SHeiner Kallweit case ETHTOOL_PHY_FAST_LINK_DOWN: 119169f42be8SHeiner Kallweit return m88e1540_set_fld(phydev, data); 1192a3bdfce7SHeiner Kallweit case ETHTOOL_PHY_DOWNSHIFT: 1193911af5e1SHeiner Kallweit return m88e1011_set_downshift(phydev, *(const u8 *)data); 119469f42be8SHeiner Kallweit default: 119569f42be8SHeiner Kallweit return -EOPNOTSUPP; 119669f42be8SHeiner Kallweit } 119769f42be8SHeiner Kallweit } 119869f42be8SHeiner Kallweit 11998cbcdc1aSAndrew Lunn /* The VOD can be out of specification on link up. Poke an 12008cbcdc1aSAndrew Lunn * undocumented register, in an undocumented page, with a magic value 12018cbcdc1aSAndrew Lunn * to fix this. 12028cbcdc1aSAndrew Lunn */ 12038cbcdc1aSAndrew Lunn static int m88e6390_errata(struct phy_device *phydev) 12048cbcdc1aSAndrew Lunn { 12058cbcdc1aSAndrew Lunn int err; 12068cbcdc1aSAndrew Lunn 12078cbcdc1aSAndrew Lunn err = phy_write(phydev, MII_BMCR, 12088cbcdc1aSAndrew Lunn BMCR_ANENABLE | BMCR_SPEED1000 | BMCR_FULLDPLX); 12098cbcdc1aSAndrew Lunn if (err) 12108cbcdc1aSAndrew Lunn return err; 12118cbcdc1aSAndrew Lunn 12128cbcdc1aSAndrew Lunn usleep_range(300, 400); 12138cbcdc1aSAndrew Lunn 12148cbcdc1aSAndrew Lunn err = phy_write_paged(phydev, 0xf8, 0x08, 0x36); 12158cbcdc1aSAndrew Lunn if (err) 12168cbcdc1aSAndrew Lunn return err; 12178cbcdc1aSAndrew Lunn 12188cbcdc1aSAndrew Lunn return genphy_soft_reset(phydev); 12198cbcdc1aSAndrew Lunn } 12208cbcdc1aSAndrew Lunn 12218cbcdc1aSAndrew Lunn static int m88e6390_config_aneg(struct phy_device *phydev) 12228cbcdc1aSAndrew Lunn { 12238cbcdc1aSAndrew Lunn int err; 12248cbcdc1aSAndrew Lunn 12258cbcdc1aSAndrew Lunn err = m88e6390_errata(phydev); 12268cbcdc1aSAndrew Lunn if (err) 12278cbcdc1aSAndrew Lunn return err; 12288cbcdc1aSAndrew Lunn 12298cbcdc1aSAndrew Lunn return m88e1510_config_aneg(phydev); 12308cbcdc1aSAndrew Lunn } 12318cbcdc1aSAndrew Lunn 12326cfb3bccSCharles-Antoine Couret /** 1233ab9cb729SAndrew Lunn * fiber_lpa_mod_linkmode_lpa_t 1234c0ec3c27SAndrew Lunn * @advertising: the linkmode advertisement settings 12356cfb3bccSCharles-Antoine Couret * @lpa: value of the MII_LPA register for fiber link 1236be937f1fSAlexandr Smirnov * 1237ab9cb729SAndrew Lunn * A small helper function that translates MII_LPA bits to linkmode LP 1238ab9cb729SAndrew Lunn * advertisement settings. Other bits in advertising are left 1239ab9cb729SAndrew Lunn * unchanged. 12406cfb3bccSCharles-Antoine Couret */ 1241ab9cb729SAndrew Lunn static void fiber_lpa_mod_linkmode_lpa_t(unsigned long *advertising, u32 lpa) 12426cfb3bccSCharles-Antoine Couret { 1243ab9cb729SAndrew Lunn linkmode_mod_bit(ETHTOOL_LINK_MODE_1000baseT_Half_BIT, 1244ab9cb729SAndrew Lunn advertising, lpa & LPA_FIBER_1000HALF); 1245ab9cb729SAndrew Lunn 1246ab9cb729SAndrew Lunn linkmode_mod_bit(ETHTOOL_LINK_MODE_1000baseT_Full_BIT, 1247ab9cb729SAndrew Lunn advertising, lpa & LPA_FIBER_1000FULL); 12486cfb3bccSCharles-Antoine Couret } 12496cfb3bccSCharles-Antoine Couret 12506cfb3bccSCharles-Antoine Couret /** 12516cfb3bccSCharles-Antoine Couret * marvell_update_link - update link status in real time in @phydev 12526cfb3bccSCharles-Antoine Couret * @phydev: target phy_device struct 12536cfb3bccSCharles-Antoine Couret * 12546cfb3bccSCharles-Antoine Couret * Description: Update the value in phydev->link to reflect the 12556cfb3bccSCharles-Antoine Couret * current link value. 12566cfb3bccSCharles-Antoine Couret */ 12576cfb3bccSCharles-Antoine Couret static int marvell_update_link(struct phy_device *phydev, int fiber) 12586cfb3bccSCharles-Antoine Couret { 12596cfb3bccSCharles-Antoine Couret int status; 12606cfb3bccSCharles-Antoine Couret 12616cfb3bccSCharles-Antoine Couret /* Use the generic register for copper link, or specific 12620c3439bcSAndrew Lunn * register for fiber case 12630c3439bcSAndrew Lunn */ 12646cfb3bccSCharles-Antoine Couret if (fiber) { 12656cfb3bccSCharles-Antoine Couret status = phy_read(phydev, MII_M1011_PHY_STATUS); 12666cfb3bccSCharles-Antoine Couret if (status < 0) 12676cfb3bccSCharles-Antoine Couret return status; 12686cfb3bccSCharles-Antoine Couret 12696cfb3bccSCharles-Antoine Couret if ((status & REGISTER_LINK_STATUS) == 0) 12706cfb3bccSCharles-Antoine Couret phydev->link = 0; 12716cfb3bccSCharles-Antoine Couret else 12726cfb3bccSCharles-Antoine Couret phydev->link = 1; 12736cfb3bccSCharles-Antoine Couret } else { 12746cfb3bccSCharles-Antoine Couret return genphy_update_link(phydev); 12756cfb3bccSCharles-Antoine Couret } 12766cfb3bccSCharles-Antoine Couret 12776cfb3bccSCharles-Antoine Couret return 0; 12786cfb3bccSCharles-Antoine Couret } 12796cfb3bccSCharles-Antoine Couret 1280e1dde8dcSAndrew Lunn static int marvell_read_status_page_an(struct phy_device *phydev, 1281e1dde8dcSAndrew Lunn int fiber) 1282be937f1fSAlexandr Smirnov { 1283e1dde8dcSAndrew Lunn int status; 1284be937f1fSAlexandr Smirnov int lpa; 1285357cd64cSRussell King int lpagb; 1286be937f1fSAlexandr Smirnov 1287be937f1fSAlexandr Smirnov status = phy_read(phydev, MII_M1011_PHY_STATUS); 1288be937f1fSAlexandr Smirnov if (status < 0) 1289be937f1fSAlexandr Smirnov return status; 1290be937f1fSAlexandr Smirnov 1291be937f1fSAlexandr Smirnov lpa = phy_read(phydev, MII_LPA); 1292be937f1fSAlexandr Smirnov if (lpa < 0) 1293be937f1fSAlexandr Smirnov return lpa; 1294be937f1fSAlexandr Smirnov 1295357cd64cSRussell King lpagb = phy_read(phydev, MII_STAT1000); 1296357cd64cSRussell King if (lpagb < 0) 1297357cd64cSRussell King return lpagb; 1298357cd64cSRussell King 1299be937f1fSAlexandr Smirnov if (status & MII_M1011_PHY_STATUS_FULLDUPLEX) 1300be937f1fSAlexandr Smirnov phydev->duplex = DUPLEX_FULL; 1301be937f1fSAlexandr Smirnov else 1302be937f1fSAlexandr Smirnov phydev->duplex = DUPLEX_HALF; 1303be937f1fSAlexandr Smirnov 1304be937f1fSAlexandr Smirnov status = status & MII_M1011_PHY_STATUS_SPD_MASK; 13054f48ed32SAndrew Lunn phydev->pause = 0; 13064f48ed32SAndrew Lunn phydev->asym_pause = 0; 1307be937f1fSAlexandr Smirnov 1308be937f1fSAlexandr Smirnov switch (status) { 1309be937f1fSAlexandr Smirnov case MII_M1011_PHY_STATUS_1000: 1310be937f1fSAlexandr Smirnov phydev->speed = SPEED_1000; 1311be937f1fSAlexandr Smirnov break; 1312be937f1fSAlexandr Smirnov 1313be937f1fSAlexandr Smirnov case MII_M1011_PHY_STATUS_100: 1314be937f1fSAlexandr Smirnov phydev->speed = SPEED_100; 1315be937f1fSAlexandr Smirnov break; 1316be937f1fSAlexandr Smirnov 1317be937f1fSAlexandr Smirnov default: 1318be937f1fSAlexandr Smirnov phydev->speed = SPEED_10; 1319be937f1fSAlexandr Smirnov break; 1320be937f1fSAlexandr Smirnov } 1321be937f1fSAlexandr Smirnov 13226cfb3bccSCharles-Antoine Couret if (!fiber) { 1323c0ec3c27SAndrew Lunn mii_lpa_to_linkmode_lpa_t(phydev->lp_advertising, lpa); 132478a24df3SAndrew Lunn mii_stat1000_mod_linkmode_lpa_t(phydev->lp_advertising, lpagb); 13256cfb3bccSCharles-Antoine Couret 1326be937f1fSAlexandr Smirnov if (phydev->duplex == DUPLEX_FULL) { 1327be937f1fSAlexandr Smirnov phydev->pause = lpa & LPA_PAUSE_CAP ? 1 : 0; 1328be937f1fSAlexandr Smirnov phydev->asym_pause = lpa & LPA_PAUSE_ASYM ? 1 : 0; 1329be937f1fSAlexandr Smirnov } 1330be937f1fSAlexandr Smirnov } else { 13316cfb3bccSCharles-Antoine Couret /* The fiber link is only 1000M capable */ 1332ab9cb729SAndrew Lunn fiber_lpa_mod_linkmode_lpa_t(phydev->lp_advertising, lpa); 13336cfb3bccSCharles-Antoine Couret 13346cfb3bccSCharles-Antoine Couret if (phydev->duplex == DUPLEX_FULL) { 13356cfb3bccSCharles-Antoine Couret if (!(lpa & LPA_PAUSE_FIBER)) { 13366cfb3bccSCharles-Antoine Couret phydev->pause = 0; 13376cfb3bccSCharles-Antoine Couret phydev->asym_pause = 0; 13386cfb3bccSCharles-Antoine Couret } else if ((lpa & LPA_PAUSE_ASYM_FIBER)) { 13396cfb3bccSCharles-Antoine Couret phydev->pause = 1; 13406cfb3bccSCharles-Antoine Couret phydev->asym_pause = 1; 13416cfb3bccSCharles-Antoine Couret } else { 13426cfb3bccSCharles-Antoine Couret phydev->pause = 1; 13436cfb3bccSCharles-Antoine Couret phydev->asym_pause = 0; 13446cfb3bccSCharles-Antoine Couret } 13456cfb3bccSCharles-Antoine Couret } 13466cfb3bccSCharles-Antoine Couret } 1347e1dde8dcSAndrew Lunn return 0; 1348e1dde8dcSAndrew Lunn } 1349e1dde8dcSAndrew Lunn 1350e1dde8dcSAndrew Lunn static int marvell_read_status_page_fixed(struct phy_device *phydev) 1351e1dde8dcSAndrew Lunn { 1352be937f1fSAlexandr Smirnov int bmcr = phy_read(phydev, MII_BMCR); 1353be937f1fSAlexandr Smirnov 1354be937f1fSAlexandr Smirnov if (bmcr < 0) 1355be937f1fSAlexandr Smirnov return bmcr; 1356be937f1fSAlexandr Smirnov 1357be937f1fSAlexandr Smirnov if (bmcr & BMCR_FULLDPLX) 1358be937f1fSAlexandr Smirnov phydev->duplex = DUPLEX_FULL; 1359be937f1fSAlexandr Smirnov else 1360be937f1fSAlexandr Smirnov phydev->duplex = DUPLEX_HALF; 1361be937f1fSAlexandr Smirnov 1362be937f1fSAlexandr Smirnov if (bmcr & BMCR_SPEED1000) 1363be937f1fSAlexandr Smirnov phydev->speed = SPEED_1000; 1364be937f1fSAlexandr Smirnov else if (bmcr & BMCR_SPEED100) 1365be937f1fSAlexandr Smirnov phydev->speed = SPEED_100; 1366be937f1fSAlexandr Smirnov else 1367be937f1fSAlexandr Smirnov phydev->speed = SPEED_10; 1368be937f1fSAlexandr Smirnov 13694f48ed32SAndrew Lunn phydev->pause = 0; 13704f48ed32SAndrew Lunn phydev->asym_pause = 0; 1371c0ec3c27SAndrew Lunn linkmode_zero(phydev->lp_advertising); 1372be937f1fSAlexandr Smirnov 1373be937f1fSAlexandr Smirnov return 0; 1374be937f1fSAlexandr Smirnov } 1375be937f1fSAlexandr Smirnov 1376e1dde8dcSAndrew Lunn /* marvell_read_status_page 1377e1dde8dcSAndrew Lunn * 1378e1dde8dcSAndrew Lunn * Description: 1379e1dde8dcSAndrew Lunn * Check the link, then figure out the current state 1380e1dde8dcSAndrew Lunn * by comparing what we advertise with what the link partner 1381e1dde8dcSAndrew Lunn * advertises. Start by checking the gigabit possibilities, 1382e1dde8dcSAndrew Lunn * then move on to 10/100. 1383e1dde8dcSAndrew Lunn */ 1384e1dde8dcSAndrew Lunn static int marvell_read_status_page(struct phy_device *phydev, int page) 1385e1dde8dcSAndrew Lunn { 1386e1dde8dcSAndrew Lunn int fiber; 1387e1dde8dcSAndrew Lunn int err; 1388e1dde8dcSAndrew Lunn 1389e1dde8dcSAndrew Lunn /* Detect and update the link, but return if there 1390e1dde8dcSAndrew Lunn * was an error 1391e1dde8dcSAndrew Lunn */ 139252295666SAndrew Lunn if (page == MII_MARVELL_FIBER_PAGE) 1393e1dde8dcSAndrew Lunn fiber = 1; 1394e1dde8dcSAndrew Lunn else 1395e1dde8dcSAndrew Lunn fiber = 0; 1396e1dde8dcSAndrew Lunn 1397e1dde8dcSAndrew Lunn err = marvell_update_link(phydev, fiber); 1398e1dde8dcSAndrew Lunn if (err) 1399e1dde8dcSAndrew Lunn return err; 1400e1dde8dcSAndrew Lunn 1401e1dde8dcSAndrew Lunn if (phydev->autoneg == AUTONEG_ENABLE) 1402e1dde8dcSAndrew Lunn err = marvell_read_status_page_an(phydev, fiber); 1403e1dde8dcSAndrew Lunn else 1404e1dde8dcSAndrew Lunn err = marvell_read_status_page_fixed(phydev); 1405e1dde8dcSAndrew Lunn 1406e1dde8dcSAndrew Lunn return err; 1407e1dde8dcSAndrew Lunn } 1408e1dde8dcSAndrew Lunn 14096cfb3bccSCharles-Antoine Couret /* marvell_read_status 14106cfb3bccSCharles-Antoine Couret * 14116cfb3bccSCharles-Antoine Couret * Some Marvell's phys have two modes: fiber and copper. 14126cfb3bccSCharles-Antoine Couret * Both need status checked. 14136cfb3bccSCharles-Antoine Couret * Description: 14146cfb3bccSCharles-Antoine Couret * First, check the fiber link and status. 14156cfb3bccSCharles-Antoine Couret * If the fiber link is down, check the copper link and status which 14166cfb3bccSCharles-Antoine Couret * will be the default value if both link are down. 14176cfb3bccSCharles-Antoine Couret */ 14186cfb3bccSCharles-Antoine Couret static int marvell_read_status(struct phy_device *phydev) 14196cfb3bccSCharles-Antoine Couret { 14206cfb3bccSCharles-Antoine Couret int err; 14216cfb3bccSCharles-Antoine Couret 14226cfb3bccSCharles-Antoine Couret /* Check the fiber mode first */ 14233c1bcc86SAndrew Lunn if (linkmode_test_bit(ETHTOOL_LINK_MODE_FIBRE_BIT, 14243c1bcc86SAndrew Lunn phydev->supported) && 1425a13c0652SRussell King phydev->interface != PHY_INTERFACE_MODE_SGMII) { 142652295666SAndrew Lunn err = marvell_set_page(phydev, MII_MARVELL_FIBER_PAGE); 14276cfb3bccSCharles-Antoine Couret if (err < 0) 14286cfb3bccSCharles-Antoine Couret goto error; 14296cfb3bccSCharles-Antoine Couret 143052295666SAndrew Lunn err = marvell_read_status_page(phydev, MII_MARVELL_FIBER_PAGE); 14316cfb3bccSCharles-Antoine Couret if (err < 0) 14326cfb3bccSCharles-Antoine Couret goto error; 14336cfb3bccSCharles-Antoine Couret 14340c3439bcSAndrew Lunn /* If the fiber link is up, it is the selected and 14350c3439bcSAndrew Lunn * used link. In this case, we need to stay in the 14360c3439bcSAndrew Lunn * fiber page. Please to be careful about that, avoid 14370c3439bcSAndrew Lunn * to restore Copper page in other functions which 14380c3439bcSAndrew Lunn * could break the behaviour for some fiber phy like 14390c3439bcSAndrew Lunn * 88E1512. 14400c3439bcSAndrew Lunn */ 14416cfb3bccSCharles-Antoine Couret if (phydev->link) 14426cfb3bccSCharles-Antoine Couret return 0; 14436cfb3bccSCharles-Antoine Couret 14446cfb3bccSCharles-Antoine Couret /* If fiber link is down, check and save copper mode state */ 144552295666SAndrew Lunn err = marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE); 14466cfb3bccSCharles-Antoine Couret if (err < 0) 14476cfb3bccSCharles-Antoine Couret goto error; 14486cfb3bccSCharles-Antoine Couret } 14496cfb3bccSCharles-Antoine Couret 145052295666SAndrew Lunn return marvell_read_status_page(phydev, MII_MARVELL_COPPER_PAGE); 14516cfb3bccSCharles-Antoine Couret 14526cfb3bccSCharles-Antoine Couret error: 145352295666SAndrew Lunn marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE); 14546cfb3bccSCharles-Antoine Couret return err; 14556cfb3bccSCharles-Antoine Couret } 14563758be3dSCharles-Antoine Couret 14573758be3dSCharles-Antoine Couret /* marvell_suspend 14583758be3dSCharles-Antoine Couret * 14593758be3dSCharles-Antoine Couret * Some Marvell's phys have two modes: fiber and copper. 14603758be3dSCharles-Antoine Couret * Both need to be suspended 14613758be3dSCharles-Antoine Couret */ 14623758be3dSCharles-Antoine Couret static int marvell_suspend(struct phy_device *phydev) 14633758be3dSCharles-Antoine Couret { 14643758be3dSCharles-Antoine Couret int err; 14653758be3dSCharles-Antoine Couret 14663758be3dSCharles-Antoine Couret /* Suspend the fiber mode first */ 14673c1bcc86SAndrew Lunn if (!linkmode_test_bit(ETHTOOL_LINK_MODE_FIBRE_BIT, 14683c1bcc86SAndrew Lunn phydev->supported)) { 146952295666SAndrew Lunn err = marvell_set_page(phydev, MII_MARVELL_FIBER_PAGE); 14703758be3dSCharles-Antoine Couret if (err < 0) 14713758be3dSCharles-Antoine Couret goto error; 14723758be3dSCharles-Antoine Couret 14733758be3dSCharles-Antoine Couret /* With the page set, use the generic suspend */ 14743758be3dSCharles-Antoine Couret err = genphy_suspend(phydev); 14753758be3dSCharles-Antoine Couret if (err < 0) 14763758be3dSCharles-Antoine Couret goto error; 14773758be3dSCharles-Antoine Couret 14783758be3dSCharles-Antoine Couret /* Then, the copper link */ 147952295666SAndrew Lunn err = marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE); 14803758be3dSCharles-Antoine Couret if (err < 0) 14813758be3dSCharles-Antoine Couret goto error; 14823758be3dSCharles-Antoine Couret } 14833758be3dSCharles-Antoine Couret 14843758be3dSCharles-Antoine Couret /* With the page set, use the generic suspend */ 14853758be3dSCharles-Antoine Couret return genphy_suspend(phydev); 14863758be3dSCharles-Antoine Couret 14873758be3dSCharles-Antoine Couret error: 148852295666SAndrew Lunn marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE); 14893758be3dSCharles-Antoine Couret return err; 14903758be3dSCharles-Antoine Couret } 14913758be3dSCharles-Antoine Couret 14923758be3dSCharles-Antoine Couret /* marvell_resume 14933758be3dSCharles-Antoine Couret * 14943758be3dSCharles-Antoine Couret * Some Marvell's phys have two modes: fiber and copper. 14953758be3dSCharles-Antoine Couret * Both need to be resumed 14963758be3dSCharles-Antoine Couret */ 14973758be3dSCharles-Antoine Couret static int marvell_resume(struct phy_device *phydev) 14983758be3dSCharles-Antoine Couret { 14993758be3dSCharles-Antoine Couret int err; 15003758be3dSCharles-Antoine Couret 15013758be3dSCharles-Antoine Couret /* Resume the fiber mode first */ 15023c1bcc86SAndrew Lunn if (!linkmode_test_bit(ETHTOOL_LINK_MODE_FIBRE_BIT, 15033c1bcc86SAndrew Lunn phydev->supported)) { 150452295666SAndrew Lunn err = marvell_set_page(phydev, MII_MARVELL_FIBER_PAGE); 15053758be3dSCharles-Antoine Couret if (err < 0) 15063758be3dSCharles-Antoine Couret goto error; 15073758be3dSCharles-Antoine Couret 15083758be3dSCharles-Antoine Couret /* With the page set, use the generic resume */ 15093758be3dSCharles-Antoine Couret err = genphy_resume(phydev); 15103758be3dSCharles-Antoine Couret if (err < 0) 15113758be3dSCharles-Antoine Couret goto error; 15123758be3dSCharles-Antoine Couret 15133758be3dSCharles-Antoine Couret /* Then, the copper link */ 151452295666SAndrew Lunn err = marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE); 15153758be3dSCharles-Antoine Couret if (err < 0) 15163758be3dSCharles-Antoine Couret goto error; 15173758be3dSCharles-Antoine Couret } 15183758be3dSCharles-Antoine Couret 15193758be3dSCharles-Antoine Couret /* With the page set, use the generic resume */ 15203758be3dSCharles-Antoine Couret return genphy_resume(phydev); 15213758be3dSCharles-Antoine Couret 15223758be3dSCharles-Antoine Couret error: 152352295666SAndrew Lunn marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE); 15243758be3dSCharles-Antoine Couret return err; 15253758be3dSCharles-Antoine Couret } 15263758be3dSCharles-Antoine Couret 15276b358aedSSebastian Hesselbarth static int marvell_aneg_done(struct phy_device *phydev) 15286b358aedSSebastian Hesselbarth { 15296b358aedSSebastian Hesselbarth int retval = phy_read(phydev, MII_M1011_PHY_STATUS); 1530e69d9ed4SAndrew Lunn 15316b358aedSSebastian Hesselbarth return (retval < 0) ? retval : (retval & MII_M1011_PHY_STATUS_RESOLVED); 15326b358aedSSebastian Hesselbarth } 15336b358aedSSebastian Hesselbarth 1534dcd07be3SAnatolij Gustschin static int m88e1121_did_interrupt(struct phy_device *phydev) 1535dcd07be3SAnatolij Gustschin { 1536dcd07be3SAnatolij Gustschin int imask; 1537dcd07be3SAnatolij Gustschin 1538dcd07be3SAnatolij Gustschin imask = phy_read(phydev, MII_M1011_IEVENT); 1539dcd07be3SAnatolij Gustschin 1540dcd07be3SAnatolij Gustschin if (imask & MII_M1011_IMASK_INIT) 1541dcd07be3SAnatolij Gustschin return 1; 1542dcd07be3SAnatolij Gustschin 1543dcd07be3SAnatolij Gustschin return 0; 1544dcd07be3SAnatolij Gustschin } 1545dcd07be3SAnatolij Gustschin 154623beb38fSAndrew Lunn static void m88e1318_get_wol(struct phy_device *phydev, 154723beb38fSAndrew Lunn struct ethtool_wolinfo *wol) 15483871c387SMichael Stapelberg { 1549424ca4c5SRussell King int oldpage, ret = 0; 1550424ca4c5SRussell King 15513871c387SMichael Stapelberg wol->supported = WAKE_MAGIC; 15523871c387SMichael Stapelberg wol->wolopts = 0; 15533871c387SMichael Stapelberg 1554424ca4c5SRussell King oldpage = phy_select_page(phydev, MII_MARVELL_WOL_PAGE); 1555424ca4c5SRussell King if (oldpage < 0) 1556424ca4c5SRussell King goto error; 15573871c387SMichael Stapelberg 1558424ca4c5SRussell King ret = __phy_read(phydev, MII_88E1318S_PHY_WOL_CTRL); 1559424ca4c5SRussell King if (ret & MII_88E1318S_PHY_WOL_CTRL_MAGIC_PACKET_MATCH_ENABLE) 15603871c387SMichael Stapelberg wol->wolopts |= WAKE_MAGIC; 15613871c387SMichael Stapelberg 1562424ca4c5SRussell King error: 1563424ca4c5SRussell King phy_restore_page(phydev, oldpage, ret); 15643871c387SMichael Stapelberg } 15653871c387SMichael Stapelberg 156623beb38fSAndrew Lunn static int m88e1318_set_wol(struct phy_device *phydev, 156723beb38fSAndrew Lunn struct ethtool_wolinfo *wol) 15683871c387SMichael Stapelberg { 1569424ca4c5SRussell King int err = 0, oldpage; 15703871c387SMichael Stapelberg 1571424ca4c5SRussell King oldpage = phy_save_page(phydev); 1572424ca4c5SRussell King if (oldpage < 0) 1573424ca4c5SRussell King goto error; 15743871c387SMichael Stapelberg 15753871c387SMichael Stapelberg if (wol->wolopts & WAKE_MAGIC) { 15763871c387SMichael Stapelberg /* Explicitly switch to page 0x00, just to be sure */ 1577424ca4c5SRussell King err = marvell_write_page(phydev, MII_MARVELL_COPPER_PAGE); 15783871c387SMichael Stapelberg if (err < 0) 1579424ca4c5SRussell King goto error; 15803871c387SMichael Stapelberg 1581b6a930faSJingju Hou /* If WOL event happened once, the LED[2] interrupt pin 1582b6a930faSJingju Hou * will not be cleared unless we reading the interrupt status 1583b6a930faSJingju Hou * register. If interrupts are in use, the normal interrupt 1584b6a930faSJingju Hou * handling will clear the WOL event. Clear the WOL event 1585b6a930faSJingju Hou * before enabling it if !phy_interrupt_is_valid() 1586b6a930faSJingju Hou */ 1587b6a930faSJingju Hou if (!phy_interrupt_is_valid(phydev)) 1588e0a7328fSAndrew Lunn __phy_read(phydev, MII_M1011_IEVENT); 1589b6a930faSJingju Hou 15903871c387SMichael Stapelberg /* Enable the WOL interrupt */ 1591424ca4c5SRussell King err = __phy_modify(phydev, MII_88E1318S_PHY_CSIER, 0, 1592424ca4c5SRussell King MII_88E1318S_PHY_CSIER_WOL_EIE); 15933871c387SMichael Stapelberg if (err < 0) 1594424ca4c5SRussell King goto error; 15953871c387SMichael Stapelberg 1596424ca4c5SRussell King err = marvell_write_page(phydev, MII_MARVELL_LED_PAGE); 15973871c387SMichael Stapelberg if (err < 0) 1598424ca4c5SRussell King goto error; 15993871c387SMichael Stapelberg 16003871c387SMichael Stapelberg /* Setup LED[2] as interrupt pin (active low) */ 1601424ca4c5SRussell King err = __phy_modify(phydev, MII_88E1318S_PHY_LED_TCR, 1602f102852fSRussell King MII_88E1318S_PHY_LED_TCR_FORCE_INT, 1603424ca4c5SRussell King MII_88E1318S_PHY_LED_TCR_INTn_ENABLE | 1604424ca4c5SRussell King MII_88E1318S_PHY_LED_TCR_INT_ACTIVE_LOW); 16053871c387SMichael Stapelberg if (err < 0) 1606424ca4c5SRussell King goto error; 16073871c387SMichael Stapelberg 1608424ca4c5SRussell King err = marvell_write_page(phydev, MII_MARVELL_WOL_PAGE); 16093871c387SMichael Stapelberg if (err < 0) 1610424ca4c5SRussell King goto error; 16113871c387SMichael Stapelberg 16123871c387SMichael Stapelberg /* Store the device address for the magic packet */ 1613424ca4c5SRussell King err = __phy_write(phydev, MII_88E1318S_PHY_MAGIC_PACKET_WORD2, 16143871c387SMichael Stapelberg ((phydev->attached_dev->dev_addr[5] << 8) | 16153871c387SMichael Stapelberg phydev->attached_dev->dev_addr[4])); 16163871c387SMichael Stapelberg if (err < 0) 1617424ca4c5SRussell King goto error; 1618424ca4c5SRussell King err = __phy_write(phydev, MII_88E1318S_PHY_MAGIC_PACKET_WORD1, 16193871c387SMichael Stapelberg ((phydev->attached_dev->dev_addr[3] << 8) | 16203871c387SMichael Stapelberg phydev->attached_dev->dev_addr[2])); 16213871c387SMichael Stapelberg if (err < 0) 1622424ca4c5SRussell King goto error; 1623424ca4c5SRussell King err = __phy_write(phydev, MII_88E1318S_PHY_MAGIC_PACKET_WORD0, 16243871c387SMichael Stapelberg ((phydev->attached_dev->dev_addr[1] << 8) | 16253871c387SMichael Stapelberg phydev->attached_dev->dev_addr[0])); 16263871c387SMichael Stapelberg if (err < 0) 1627424ca4c5SRussell King goto error; 16283871c387SMichael Stapelberg 16293871c387SMichael Stapelberg /* Clear WOL status and enable magic packet matching */ 1630424ca4c5SRussell King err = __phy_modify(phydev, MII_88E1318S_PHY_WOL_CTRL, 0, 1631424ca4c5SRussell King MII_88E1318S_PHY_WOL_CTRL_CLEAR_WOL_STATUS | 1632424ca4c5SRussell King MII_88E1318S_PHY_WOL_CTRL_MAGIC_PACKET_MATCH_ENABLE); 16333871c387SMichael Stapelberg if (err < 0) 1634424ca4c5SRussell King goto error; 16353871c387SMichael Stapelberg } else { 1636424ca4c5SRussell King err = marvell_write_page(phydev, MII_MARVELL_WOL_PAGE); 16373871c387SMichael Stapelberg if (err < 0) 1638424ca4c5SRussell King goto error; 16393871c387SMichael Stapelberg 16403871c387SMichael Stapelberg /* Clear WOL status and disable magic packet matching */ 1641424ca4c5SRussell King err = __phy_modify(phydev, MII_88E1318S_PHY_WOL_CTRL, 1642f102852fSRussell King MII_88E1318S_PHY_WOL_CTRL_MAGIC_PACKET_MATCH_ENABLE, 1643424ca4c5SRussell King MII_88E1318S_PHY_WOL_CTRL_CLEAR_WOL_STATUS); 16443871c387SMichael Stapelberg if (err < 0) 1645424ca4c5SRussell King goto error; 16463871c387SMichael Stapelberg } 16473871c387SMichael Stapelberg 1648424ca4c5SRussell King error: 1649424ca4c5SRussell King return phy_restore_page(phydev, oldpage, err); 16503871c387SMichael Stapelberg } 16513871c387SMichael Stapelberg 1652d2fa47d9SAndrew Lunn static int marvell_get_sset_count(struct phy_device *phydev) 1653d2fa47d9SAndrew Lunn { 16543c1bcc86SAndrew Lunn if (linkmode_test_bit(ETHTOOL_LINK_MODE_FIBRE_BIT, 16553c1bcc86SAndrew Lunn phydev->supported)) 1656d2fa47d9SAndrew Lunn return ARRAY_SIZE(marvell_hw_stats); 16572170fef7SCharles-Antoine Couret else 16582170fef7SCharles-Antoine Couret return ARRAY_SIZE(marvell_hw_stats) - NB_FIBER_STATS; 1659d2fa47d9SAndrew Lunn } 1660d2fa47d9SAndrew Lunn 1661d2fa47d9SAndrew Lunn static void marvell_get_strings(struct phy_device *phydev, u8 *data) 1662d2fa47d9SAndrew Lunn { 1663fdfdf867SAndrew Lunn int count = marvell_get_sset_count(phydev); 1664d2fa47d9SAndrew Lunn int i; 1665d2fa47d9SAndrew Lunn 1666fdfdf867SAndrew Lunn for (i = 0; i < count; i++) { 166798409b2bSFlorian Fainelli strlcpy(data + i * ETH_GSTRING_LEN, 1668d2fa47d9SAndrew Lunn marvell_hw_stats[i].string, ETH_GSTRING_LEN); 1669d2fa47d9SAndrew Lunn } 1670d2fa47d9SAndrew Lunn } 1671d2fa47d9SAndrew Lunn 1672d2fa47d9SAndrew Lunn static u64 marvell_get_stat(struct phy_device *phydev, int i) 1673d2fa47d9SAndrew Lunn { 1674d2fa47d9SAndrew Lunn struct marvell_hw_stat stat = marvell_hw_stats[i]; 1675d2fa47d9SAndrew Lunn struct marvell_priv *priv = phydev->priv; 1676424ca4c5SRussell King int val; 1677321b4d4bSAndrew Lunn u64 ret; 1678d2fa47d9SAndrew Lunn 1679424ca4c5SRussell King val = phy_read_paged(phydev, stat.page, stat.reg); 1680d2fa47d9SAndrew Lunn if (val < 0) { 16816c3442f5SJisheng Zhang ret = U64_MAX; 1682d2fa47d9SAndrew Lunn } else { 1683d2fa47d9SAndrew Lunn val = val & ((1 << stat.bits) - 1); 1684d2fa47d9SAndrew Lunn priv->stats[i] += val; 1685321b4d4bSAndrew Lunn ret = priv->stats[i]; 1686d2fa47d9SAndrew Lunn } 1687d2fa47d9SAndrew Lunn 1688321b4d4bSAndrew Lunn return ret; 1689d2fa47d9SAndrew Lunn } 1690d2fa47d9SAndrew Lunn 1691d2fa47d9SAndrew Lunn static void marvell_get_stats(struct phy_device *phydev, 1692d2fa47d9SAndrew Lunn struct ethtool_stats *stats, u64 *data) 1693d2fa47d9SAndrew Lunn { 1694fdfdf867SAndrew Lunn int count = marvell_get_sset_count(phydev); 1695d2fa47d9SAndrew Lunn int i; 1696d2fa47d9SAndrew Lunn 1697fdfdf867SAndrew Lunn for (i = 0; i < count; i++) 1698d2fa47d9SAndrew Lunn data[i] = marvell_get_stat(phydev, i); 1699d2fa47d9SAndrew Lunn } 1700d2fa47d9SAndrew Lunn 17010b04680fSAndrew Lunn #ifdef CONFIG_HWMON 17020b04680fSAndrew Lunn static int m88e1121_get_temp(struct phy_device *phydev, long *temp) 17030b04680fSAndrew Lunn { 1704975b388cSAndrew Lunn int oldpage; 1705424ca4c5SRussell King int ret = 0; 17060b04680fSAndrew Lunn int val; 17070b04680fSAndrew Lunn 17080b04680fSAndrew Lunn *temp = 0; 17090b04680fSAndrew Lunn 1710424ca4c5SRussell King oldpage = phy_select_page(phydev, MII_MARVELL_MISC_TEST_PAGE); 1711424ca4c5SRussell King if (oldpage < 0) 1712424ca4c5SRussell King goto error; 1713975b388cSAndrew Lunn 17140b04680fSAndrew Lunn /* Enable temperature sensor */ 1715424ca4c5SRussell King ret = __phy_read(phydev, MII_88E1121_MISC_TEST); 17160b04680fSAndrew Lunn if (ret < 0) 17170b04680fSAndrew Lunn goto error; 17180b04680fSAndrew Lunn 1719424ca4c5SRussell King ret = __phy_write(phydev, MII_88E1121_MISC_TEST, 17200b04680fSAndrew Lunn ret | MII_88E1121_MISC_TEST_TEMP_SENSOR_EN); 17210b04680fSAndrew Lunn if (ret < 0) 17220b04680fSAndrew Lunn goto error; 17230b04680fSAndrew Lunn 17240b04680fSAndrew Lunn /* Wait for temperature to stabilize */ 17250b04680fSAndrew Lunn usleep_range(10000, 12000); 17260b04680fSAndrew Lunn 1727424ca4c5SRussell King val = __phy_read(phydev, MII_88E1121_MISC_TEST); 17280b04680fSAndrew Lunn if (val < 0) { 17290b04680fSAndrew Lunn ret = val; 17300b04680fSAndrew Lunn goto error; 17310b04680fSAndrew Lunn } 17320b04680fSAndrew Lunn 17330b04680fSAndrew Lunn /* Disable temperature sensor */ 1734424ca4c5SRussell King ret = __phy_write(phydev, MII_88E1121_MISC_TEST, 17350b04680fSAndrew Lunn ret & ~MII_88E1121_MISC_TEST_TEMP_SENSOR_EN); 17360b04680fSAndrew Lunn if (ret < 0) 17370b04680fSAndrew Lunn goto error; 17380b04680fSAndrew Lunn 17390b04680fSAndrew Lunn *temp = ((val & MII_88E1121_MISC_TEST_TEMP_MASK) - 5) * 5000; 17400b04680fSAndrew Lunn 17410b04680fSAndrew Lunn error: 1742424ca4c5SRussell King return phy_restore_page(phydev, oldpage, ret); 17430b04680fSAndrew Lunn } 17440b04680fSAndrew Lunn 17450b04680fSAndrew Lunn static int m88e1121_hwmon_read(struct device *dev, 17460b04680fSAndrew Lunn enum hwmon_sensor_types type, 17470b04680fSAndrew Lunn u32 attr, int channel, long *temp) 17480b04680fSAndrew Lunn { 17490b04680fSAndrew Lunn struct phy_device *phydev = dev_get_drvdata(dev); 17500b04680fSAndrew Lunn int err; 17510b04680fSAndrew Lunn 17520b04680fSAndrew Lunn switch (attr) { 17530b04680fSAndrew Lunn case hwmon_temp_input: 17540b04680fSAndrew Lunn err = m88e1121_get_temp(phydev, temp); 17550b04680fSAndrew Lunn break; 17560b04680fSAndrew Lunn default: 17570b04680fSAndrew Lunn return -EOPNOTSUPP; 17580b04680fSAndrew Lunn } 17590b04680fSAndrew Lunn 17600b04680fSAndrew Lunn return err; 17610b04680fSAndrew Lunn } 17620b04680fSAndrew Lunn 17630b04680fSAndrew Lunn static umode_t m88e1121_hwmon_is_visible(const void *data, 17640b04680fSAndrew Lunn enum hwmon_sensor_types type, 17650b04680fSAndrew Lunn u32 attr, int channel) 17660b04680fSAndrew Lunn { 17670b04680fSAndrew Lunn if (type != hwmon_temp) 17680b04680fSAndrew Lunn return 0; 17690b04680fSAndrew Lunn 17700b04680fSAndrew Lunn switch (attr) { 17710b04680fSAndrew Lunn case hwmon_temp_input: 17720b04680fSAndrew Lunn return 0444; 17730b04680fSAndrew Lunn default: 17740b04680fSAndrew Lunn return 0; 17750b04680fSAndrew Lunn } 17760b04680fSAndrew Lunn } 17770b04680fSAndrew Lunn 17780b04680fSAndrew Lunn static u32 m88e1121_hwmon_chip_config[] = { 17790b04680fSAndrew Lunn HWMON_C_REGISTER_TZ, 17800b04680fSAndrew Lunn 0 17810b04680fSAndrew Lunn }; 17820b04680fSAndrew Lunn 17830b04680fSAndrew Lunn static const struct hwmon_channel_info m88e1121_hwmon_chip = { 17840b04680fSAndrew Lunn .type = hwmon_chip, 17850b04680fSAndrew Lunn .config = m88e1121_hwmon_chip_config, 17860b04680fSAndrew Lunn }; 17870b04680fSAndrew Lunn 17880b04680fSAndrew Lunn static u32 m88e1121_hwmon_temp_config[] = { 17890b04680fSAndrew Lunn HWMON_T_INPUT, 17900b04680fSAndrew Lunn 0 17910b04680fSAndrew Lunn }; 17920b04680fSAndrew Lunn 17930b04680fSAndrew Lunn static const struct hwmon_channel_info m88e1121_hwmon_temp = { 17940b04680fSAndrew Lunn .type = hwmon_temp, 17950b04680fSAndrew Lunn .config = m88e1121_hwmon_temp_config, 17960b04680fSAndrew Lunn }; 17970b04680fSAndrew Lunn 17980b04680fSAndrew Lunn static const struct hwmon_channel_info *m88e1121_hwmon_info[] = { 17990b04680fSAndrew Lunn &m88e1121_hwmon_chip, 18000b04680fSAndrew Lunn &m88e1121_hwmon_temp, 18010b04680fSAndrew Lunn NULL 18020b04680fSAndrew Lunn }; 18030b04680fSAndrew Lunn 18040b04680fSAndrew Lunn static const struct hwmon_ops m88e1121_hwmon_hwmon_ops = { 18050b04680fSAndrew Lunn .is_visible = m88e1121_hwmon_is_visible, 18060b04680fSAndrew Lunn .read = m88e1121_hwmon_read, 18070b04680fSAndrew Lunn }; 18080b04680fSAndrew Lunn 18090b04680fSAndrew Lunn static const struct hwmon_chip_info m88e1121_hwmon_chip_info = { 18100b04680fSAndrew Lunn .ops = &m88e1121_hwmon_hwmon_ops, 18110b04680fSAndrew Lunn .info = m88e1121_hwmon_info, 18120b04680fSAndrew Lunn }; 18130b04680fSAndrew Lunn 18140b04680fSAndrew Lunn static int m88e1510_get_temp(struct phy_device *phydev, long *temp) 18150b04680fSAndrew Lunn { 18160b04680fSAndrew Lunn int ret; 18170b04680fSAndrew Lunn 18180b04680fSAndrew Lunn *temp = 0; 18190b04680fSAndrew Lunn 1820424ca4c5SRussell King ret = phy_read_paged(phydev, MII_MARVELL_MISC_TEST_PAGE, 1821424ca4c5SRussell King MII_88E1510_TEMP_SENSOR); 18220b04680fSAndrew Lunn if (ret < 0) 1823424ca4c5SRussell King return ret; 18240b04680fSAndrew Lunn 18250b04680fSAndrew Lunn *temp = ((ret & MII_88E1510_TEMP_SENSOR_MASK) - 25) * 1000; 18260b04680fSAndrew Lunn 1827424ca4c5SRussell King return 0; 18280b04680fSAndrew Lunn } 18290b04680fSAndrew Lunn 1830f0a45816SColin Ian King static int m88e1510_get_temp_critical(struct phy_device *phydev, long *temp) 18310b04680fSAndrew Lunn { 18320b04680fSAndrew Lunn int ret; 18330b04680fSAndrew Lunn 18340b04680fSAndrew Lunn *temp = 0; 18350b04680fSAndrew Lunn 1836424ca4c5SRussell King ret = phy_read_paged(phydev, MII_MARVELL_MISC_TEST_PAGE, 1837424ca4c5SRussell King MII_88E1121_MISC_TEST); 18380b04680fSAndrew Lunn if (ret < 0) 1839424ca4c5SRussell King return ret; 18400b04680fSAndrew Lunn 18410b04680fSAndrew Lunn *temp = (((ret & MII_88E1510_MISC_TEST_TEMP_THRESHOLD_MASK) >> 18420b04680fSAndrew Lunn MII_88E1510_MISC_TEST_TEMP_THRESHOLD_SHIFT) * 5) - 25; 18430b04680fSAndrew Lunn /* convert to mC */ 18440b04680fSAndrew Lunn *temp *= 1000; 18450b04680fSAndrew Lunn 1846424ca4c5SRussell King return 0; 18470b04680fSAndrew Lunn } 18480b04680fSAndrew Lunn 1849f0a45816SColin Ian King static int m88e1510_set_temp_critical(struct phy_device *phydev, long temp) 18500b04680fSAndrew Lunn { 18510b04680fSAndrew Lunn temp = temp / 1000; 18520b04680fSAndrew Lunn temp = clamp_val(DIV_ROUND_CLOSEST(temp, 5) + 5, 0, 0x1f); 18530b04680fSAndrew Lunn 1854424ca4c5SRussell King return phy_modify_paged(phydev, MII_MARVELL_MISC_TEST_PAGE, 1855424ca4c5SRussell King MII_88E1121_MISC_TEST, 1856424ca4c5SRussell King MII_88E1510_MISC_TEST_TEMP_THRESHOLD_MASK, 1857424ca4c5SRussell King temp << MII_88E1510_MISC_TEST_TEMP_THRESHOLD_SHIFT); 18580b04680fSAndrew Lunn } 18590b04680fSAndrew Lunn 1860f0a45816SColin Ian King static int m88e1510_get_temp_alarm(struct phy_device *phydev, long *alarm) 18610b04680fSAndrew Lunn { 18620b04680fSAndrew Lunn int ret; 18630b04680fSAndrew Lunn 18640b04680fSAndrew Lunn *alarm = false; 18650b04680fSAndrew Lunn 1866424ca4c5SRussell King ret = phy_read_paged(phydev, MII_MARVELL_MISC_TEST_PAGE, 1867424ca4c5SRussell King MII_88E1121_MISC_TEST); 18680b04680fSAndrew Lunn if (ret < 0) 1869424ca4c5SRussell King return ret; 1870424ca4c5SRussell King 18710b04680fSAndrew Lunn *alarm = !!(ret & MII_88E1510_MISC_TEST_TEMP_IRQ); 18720b04680fSAndrew Lunn 1873424ca4c5SRussell King return 0; 18740b04680fSAndrew Lunn } 18750b04680fSAndrew Lunn 18760b04680fSAndrew Lunn static int m88e1510_hwmon_read(struct device *dev, 18770b04680fSAndrew Lunn enum hwmon_sensor_types type, 18780b04680fSAndrew Lunn u32 attr, int channel, long *temp) 18790b04680fSAndrew Lunn { 18800b04680fSAndrew Lunn struct phy_device *phydev = dev_get_drvdata(dev); 18810b04680fSAndrew Lunn int err; 18820b04680fSAndrew Lunn 18830b04680fSAndrew Lunn switch (attr) { 18840b04680fSAndrew Lunn case hwmon_temp_input: 18850b04680fSAndrew Lunn err = m88e1510_get_temp(phydev, temp); 18860b04680fSAndrew Lunn break; 18870b04680fSAndrew Lunn case hwmon_temp_crit: 18880b04680fSAndrew Lunn err = m88e1510_get_temp_critical(phydev, temp); 18890b04680fSAndrew Lunn break; 18900b04680fSAndrew Lunn case hwmon_temp_max_alarm: 18910b04680fSAndrew Lunn err = m88e1510_get_temp_alarm(phydev, temp); 18920b04680fSAndrew Lunn break; 18930b04680fSAndrew Lunn default: 18940b04680fSAndrew Lunn return -EOPNOTSUPP; 18950b04680fSAndrew Lunn } 18960b04680fSAndrew Lunn 18970b04680fSAndrew Lunn return err; 18980b04680fSAndrew Lunn } 18990b04680fSAndrew Lunn 19000b04680fSAndrew Lunn static int m88e1510_hwmon_write(struct device *dev, 19010b04680fSAndrew Lunn enum hwmon_sensor_types type, 19020b04680fSAndrew Lunn u32 attr, int channel, long temp) 19030b04680fSAndrew Lunn { 19040b04680fSAndrew Lunn struct phy_device *phydev = dev_get_drvdata(dev); 19050b04680fSAndrew Lunn int err; 19060b04680fSAndrew Lunn 19070b04680fSAndrew Lunn switch (attr) { 19080b04680fSAndrew Lunn case hwmon_temp_crit: 19090b04680fSAndrew Lunn err = m88e1510_set_temp_critical(phydev, temp); 19100b04680fSAndrew Lunn break; 19110b04680fSAndrew Lunn default: 19120b04680fSAndrew Lunn return -EOPNOTSUPP; 19130b04680fSAndrew Lunn } 19140b04680fSAndrew Lunn return err; 19150b04680fSAndrew Lunn } 19160b04680fSAndrew Lunn 19170b04680fSAndrew Lunn static umode_t m88e1510_hwmon_is_visible(const void *data, 19180b04680fSAndrew Lunn enum hwmon_sensor_types type, 19190b04680fSAndrew Lunn u32 attr, int channel) 19200b04680fSAndrew Lunn { 19210b04680fSAndrew Lunn if (type != hwmon_temp) 19220b04680fSAndrew Lunn return 0; 19230b04680fSAndrew Lunn 19240b04680fSAndrew Lunn switch (attr) { 19250b04680fSAndrew Lunn case hwmon_temp_input: 19260b04680fSAndrew Lunn case hwmon_temp_max_alarm: 19270b04680fSAndrew Lunn return 0444; 19280b04680fSAndrew Lunn case hwmon_temp_crit: 19290b04680fSAndrew Lunn return 0644; 19300b04680fSAndrew Lunn default: 19310b04680fSAndrew Lunn return 0; 19320b04680fSAndrew Lunn } 19330b04680fSAndrew Lunn } 19340b04680fSAndrew Lunn 19350b04680fSAndrew Lunn static u32 m88e1510_hwmon_temp_config[] = { 19360b04680fSAndrew Lunn HWMON_T_INPUT | HWMON_T_CRIT | HWMON_T_MAX_ALARM, 19370b04680fSAndrew Lunn 0 19380b04680fSAndrew Lunn }; 19390b04680fSAndrew Lunn 19400b04680fSAndrew Lunn static const struct hwmon_channel_info m88e1510_hwmon_temp = { 19410b04680fSAndrew Lunn .type = hwmon_temp, 19420b04680fSAndrew Lunn .config = m88e1510_hwmon_temp_config, 19430b04680fSAndrew Lunn }; 19440b04680fSAndrew Lunn 19450b04680fSAndrew Lunn static const struct hwmon_channel_info *m88e1510_hwmon_info[] = { 19460b04680fSAndrew Lunn &m88e1121_hwmon_chip, 19470b04680fSAndrew Lunn &m88e1510_hwmon_temp, 19480b04680fSAndrew Lunn NULL 19490b04680fSAndrew Lunn }; 19500b04680fSAndrew Lunn 19510b04680fSAndrew Lunn static const struct hwmon_ops m88e1510_hwmon_hwmon_ops = { 19520b04680fSAndrew Lunn .is_visible = m88e1510_hwmon_is_visible, 19530b04680fSAndrew Lunn .read = m88e1510_hwmon_read, 19540b04680fSAndrew Lunn .write = m88e1510_hwmon_write, 19550b04680fSAndrew Lunn }; 19560b04680fSAndrew Lunn 19570b04680fSAndrew Lunn static const struct hwmon_chip_info m88e1510_hwmon_chip_info = { 19580b04680fSAndrew Lunn .ops = &m88e1510_hwmon_hwmon_ops, 19590b04680fSAndrew Lunn .info = m88e1510_hwmon_info, 19600b04680fSAndrew Lunn }; 19610b04680fSAndrew Lunn 1962fee2d546SAndrew Lunn static int m88e6390_get_temp(struct phy_device *phydev, long *temp) 1963fee2d546SAndrew Lunn { 1964fee2d546SAndrew Lunn int sum = 0; 1965fee2d546SAndrew Lunn int oldpage; 1966fee2d546SAndrew Lunn int ret = 0; 1967fee2d546SAndrew Lunn int i; 1968fee2d546SAndrew Lunn 1969fee2d546SAndrew Lunn *temp = 0; 1970fee2d546SAndrew Lunn 1971fee2d546SAndrew Lunn oldpage = phy_select_page(phydev, MII_MARVELL_MISC_TEST_PAGE); 1972fee2d546SAndrew Lunn if (oldpage < 0) 1973fee2d546SAndrew Lunn goto error; 1974fee2d546SAndrew Lunn 1975fee2d546SAndrew Lunn /* Enable temperature sensor */ 1976fee2d546SAndrew Lunn ret = __phy_read(phydev, MII_88E6390_MISC_TEST); 1977fee2d546SAndrew Lunn if (ret < 0) 1978fee2d546SAndrew Lunn goto error; 1979fee2d546SAndrew Lunn 1980fee2d546SAndrew Lunn ret = ret & ~MII_88E6390_MISC_TEST_SAMPLE_MASK; 1981fee2d546SAndrew Lunn ret |= MII_88E6390_MISC_TEST_SAMPLE_ENABLE | 1982fee2d546SAndrew Lunn MII_88E6390_MISC_TEST_SAMPLE_1S; 1983fee2d546SAndrew Lunn 1984fee2d546SAndrew Lunn ret = __phy_write(phydev, MII_88E6390_MISC_TEST, ret); 1985fee2d546SAndrew Lunn if (ret < 0) 1986fee2d546SAndrew Lunn goto error; 1987fee2d546SAndrew Lunn 1988fee2d546SAndrew Lunn /* Wait for temperature to stabilize */ 1989fee2d546SAndrew Lunn usleep_range(10000, 12000); 1990fee2d546SAndrew Lunn 1991fee2d546SAndrew Lunn /* Reading the temperature sense has an errata. You need to read 1992fee2d546SAndrew Lunn * a number of times and take an average. 1993fee2d546SAndrew Lunn */ 1994fee2d546SAndrew Lunn for (i = 0; i < MII_88E6390_TEMP_SENSOR_SAMPLES; i++) { 1995fee2d546SAndrew Lunn ret = __phy_read(phydev, MII_88E6390_TEMP_SENSOR); 1996fee2d546SAndrew Lunn if (ret < 0) 1997fee2d546SAndrew Lunn goto error; 1998fee2d546SAndrew Lunn sum += ret & MII_88E6390_TEMP_SENSOR_MASK; 1999fee2d546SAndrew Lunn } 2000fee2d546SAndrew Lunn 2001fee2d546SAndrew Lunn sum /= MII_88E6390_TEMP_SENSOR_SAMPLES; 2002fee2d546SAndrew Lunn *temp = (sum - 75) * 1000; 2003fee2d546SAndrew Lunn 2004fee2d546SAndrew Lunn /* Disable temperature sensor */ 2005fee2d546SAndrew Lunn ret = __phy_read(phydev, MII_88E6390_MISC_TEST); 2006fee2d546SAndrew Lunn if (ret < 0) 2007fee2d546SAndrew Lunn goto error; 2008fee2d546SAndrew Lunn 2009fee2d546SAndrew Lunn ret = ret & ~MII_88E6390_MISC_TEST_SAMPLE_MASK; 2010fee2d546SAndrew Lunn ret |= MII_88E6390_MISC_TEST_SAMPLE_DISABLE; 2011fee2d546SAndrew Lunn 2012fee2d546SAndrew Lunn ret = __phy_write(phydev, MII_88E6390_MISC_TEST, ret); 2013fee2d546SAndrew Lunn 2014fee2d546SAndrew Lunn error: 2015fee2d546SAndrew Lunn phy_restore_page(phydev, oldpage, ret); 2016fee2d546SAndrew Lunn 2017fee2d546SAndrew Lunn return ret; 2018fee2d546SAndrew Lunn } 2019fee2d546SAndrew Lunn 2020fee2d546SAndrew Lunn static int m88e6390_hwmon_read(struct device *dev, 2021fee2d546SAndrew Lunn enum hwmon_sensor_types type, 2022fee2d546SAndrew Lunn u32 attr, int channel, long *temp) 2023fee2d546SAndrew Lunn { 2024fee2d546SAndrew Lunn struct phy_device *phydev = dev_get_drvdata(dev); 2025fee2d546SAndrew Lunn int err; 2026fee2d546SAndrew Lunn 2027fee2d546SAndrew Lunn switch (attr) { 2028fee2d546SAndrew Lunn case hwmon_temp_input: 2029fee2d546SAndrew Lunn err = m88e6390_get_temp(phydev, temp); 2030fee2d546SAndrew Lunn break; 2031fee2d546SAndrew Lunn default: 2032fee2d546SAndrew Lunn return -EOPNOTSUPP; 2033fee2d546SAndrew Lunn } 2034fee2d546SAndrew Lunn 2035fee2d546SAndrew Lunn return err; 2036fee2d546SAndrew Lunn } 2037fee2d546SAndrew Lunn 2038fee2d546SAndrew Lunn static umode_t m88e6390_hwmon_is_visible(const void *data, 2039fee2d546SAndrew Lunn enum hwmon_sensor_types type, 2040fee2d546SAndrew Lunn u32 attr, int channel) 2041fee2d546SAndrew Lunn { 2042fee2d546SAndrew Lunn if (type != hwmon_temp) 2043fee2d546SAndrew Lunn return 0; 2044fee2d546SAndrew Lunn 2045fee2d546SAndrew Lunn switch (attr) { 2046fee2d546SAndrew Lunn case hwmon_temp_input: 2047fee2d546SAndrew Lunn return 0444; 2048fee2d546SAndrew Lunn default: 2049fee2d546SAndrew Lunn return 0; 2050fee2d546SAndrew Lunn } 2051fee2d546SAndrew Lunn } 2052fee2d546SAndrew Lunn 2053fee2d546SAndrew Lunn static u32 m88e6390_hwmon_temp_config[] = { 2054fee2d546SAndrew Lunn HWMON_T_INPUT, 2055fee2d546SAndrew Lunn 0 2056fee2d546SAndrew Lunn }; 2057fee2d546SAndrew Lunn 2058fee2d546SAndrew Lunn static const struct hwmon_channel_info m88e6390_hwmon_temp = { 2059fee2d546SAndrew Lunn .type = hwmon_temp, 2060fee2d546SAndrew Lunn .config = m88e6390_hwmon_temp_config, 2061fee2d546SAndrew Lunn }; 2062fee2d546SAndrew Lunn 2063fee2d546SAndrew Lunn static const struct hwmon_channel_info *m88e6390_hwmon_info[] = { 2064fee2d546SAndrew Lunn &m88e1121_hwmon_chip, 2065fee2d546SAndrew Lunn &m88e6390_hwmon_temp, 2066fee2d546SAndrew Lunn NULL 2067fee2d546SAndrew Lunn }; 2068fee2d546SAndrew Lunn 2069fee2d546SAndrew Lunn static const struct hwmon_ops m88e6390_hwmon_hwmon_ops = { 2070fee2d546SAndrew Lunn .is_visible = m88e6390_hwmon_is_visible, 2071fee2d546SAndrew Lunn .read = m88e6390_hwmon_read, 2072fee2d546SAndrew Lunn }; 2073fee2d546SAndrew Lunn 2074fee2d546SAndrew Lunn static const struct hwmon_chip_info m88e6390_hwmon_chip_info = { 2075fee2d546SAndrew Lunn .ops = &m88e6390_hwmon_hwmon_ops, 2076fee2d546SAndrew Lunn .info = m88e6390_hwmon_info, 2077fee2d546SAndrew Lunn }; 2078fee2d546SAndrew Lunn 20790b04680fSAndrew Lunn static int marvell_hwmon_name(struct phy_device *phydev) 20800b04680fSAndrew Lunn { 20810b04680fSAndrew Lunn struct marvell_priv *priv = phydev->priv; 20820b04680fSAndrew Lunn struct device *dev = &phydev->mdio.dev; 20830b04680fSAndrew Lunn const char *devname = dev_name(dev); 20840b04680fSAndrew Lunn size_t len = strlen(devname); 20850b04680fSAndrew Lunn int i, j; 20860b04680fSAndrew Lunn 20870b04680fSAndrew Lunn priv->hwmon_name = devm_kzalloc(dev, len, GFP_KERNEL); 20880b04680fSAndrew Lunn if (!priv->hwmon_name) 20890b04680fSAndrew Lunn return -ENOMEM; 20900b04680fSAndrew Lunn 20910b04680fSAndrew Lunn for (i = j = 0; i < len && devname[i]; i++) { 20920b04680fSAndrew Lunn if (isalnum(devname[i])) 20930b04680fSAndrew Lunn priv->hwmon_name[j++] = devname[i]; 20940b04680fSAndrew Lunn } 20950b04680fSAndrew Lunn 20960b04680fSAndrew Lunn return 0; 20970b04680fSAndrew Lunn } 20980b04680fSAndrew Lunn 20990b04680fSAndrew Lunn static int marvell_hwmon_probe(struct phy_device *phydev, 21000b04680fSAndrew Lunn const struct hwmon_chip_info *chip) 21010b04680fSAndrew Lunn { 21020b04680fSAndrew Lunn struct marvell_priv *priv = phydev->priv; 21030b04680fSAndrew Lunn struct device *dev = &phydev->mdio.dev; 21040b04680fSAndrew Lunn int err; 21050b04680fSAndrew Lunn 21060b04680fSAndrew Lunn err = marvell_hwmon_name(phydev); 21070b04680fSAndrew Lunn if (err) 21080b04680fSAndrew Lunn return err; 21090b04680fSAndrew Lunn 21100b04680fSAndrew Lunn priv->hwmon_dev = devm_hwmon_device_register_with_info( 21110b04680fSAndrew Lunn dev, priv->hwmon_name, phydev, chip, NULL); 21120b04680fSAndrew Lunn 21130b04680fSAndrew Lunn return PTR_ERR_OR_ZERO(priv->hwmon_dev); 21140b04680fSAndrew Lunn } 21150b04680fSAndrew Lunn 21160b04680fSAndrew Lunn static int m88e1121_hwmon_probe(struct phy_device *phydev) 21170b04680fSAndrew Lunn { 21180b04680fSAndrew Lunn return marvell_hwmon_probe(phydev, &m88e1121_hwmon_chip_info); 21190b04680fSAndrew Lunn } 21200b04680fSAndrew Lunn 21210b04680fSAndrew Lunn static int m88e1510_hwmon_probe(struct phy_device *phydev) 21220b04680fSAndrew Lunn { 21230b04680fSAndrew Lunn return marvell_hwmon_probe(phydev, &m88e1510_hwmon_chip_info); 21240b04680fSAndrew Lunn } 2125fee2d546SAndrew Lunn 2126fee2d546SAndrew Lunn static int m88e6390_hwmon_probe(struct phy_device *phydev) 2127fee2d546SAndrew Lunn { 2128fee2d546SAndrew Lunn return marvell_hwmon_probe(phydev, &m88e6390_hwmon_chip_info); 2129fee2d546SAndrew Lunn } 21300b04680fSAndrew Lunn #else 21310b04680fSAndrew Lunn static int m88e1121_hwmon_probe(struct phy_device *phydev) 21320b04680fSAndrew Lunn { 21330b04680fSAndrew Lunn return 0; 21340b04680fSAndrew Lunn } 21350b04680fSAndrew Lunn 21360b04680fSAndrew Lunn static int m88e1510_hwmon_probe(struct phy_device *phydev) 21370b04680fSAndrew Lunn { 21380b04680fSAndrew Lunn return 0; 21390b04680fSAndrew Lunn } 2140fee2d546SAndrew Lunn 2141fee2d546SAndrew Lunn static int m88e6390_hwmon_probe(struct phy_device *phydev) 2142fee2d546SAndrew Lunn { 2143fee2d546SAndrew Lunn return 0; 2144fee2d546SAndrew Lunn } 21450b04680fSAndrew Lunn #endif 21460b04680fSAndrew Lunn 2147d2fa47d9SAndrew Lunn static int marvell_probe(struct phy_device *phydev) 2148d2fa47d9SAndrew Lunn { 2149d2fa47d9SAndrew Lunn struct marvell_priv *priv; 2150d2fa47d9SAndrew Lunn 2151e5a03bfdSAndrew Lunn priv = devm_kzalloc(&phydev->mdio.dev, sizeof(*priv), GFP_KERNEL); 2152d2fa47d9SAndrew Lunn if (!priv) 2153d2fa47d9SAndrew Lunn return -ENOMEM; 2154d2fa47d9SAndrew Lunn 2155d2fa47d9SAndrew Lunn phydev->priv = priv; 2156d2fa47d9SAndrew Lunn 2157d2fa47d9SAndrew Lunn return 0; 2158d2fa47d9SAndrew Lunn } 2159d2fa47d9SAndrew Lunn 21600b04680fSAndrew Lunn static int m88e1121_probe(struct phy_device *phydev) 21610b04680fSAndrew Lunn { 21620b04680fSAndrew Lunn int err; 21630b04680fSAndrew Lunn 21640b04680fSAndrew Lunn err = marvell_probe(phydev); 21650b04680fSAndrew Lunn if (err) 21660b04680fSAndrew Lunn return err; 21670b04680fSAndrew Lunn 21680b04680fSAndrew Lunn return m88e1121_hwmon_probe(phydev); 21690b04680fSAndrew Lunn } 21700b04680fSAndrew Lunn 21710b04680fSAndrew Lunn static int m88e1510_probe(struct phy_device *phydev) 21720b04680fSAndrew Lunn { 21730b04680fSAndrew Lunn int err; 21740b04680fSAndrew Lunn 21750b04680fSAndrew Lunn err = marvell_probe(phydev); 21760b04680fSAndrew Lunn if (err) 21770b04680fSAndrew Lunn return err; 21780b04680fSAndrew Lunn 21790b04680fSAndrew Lunn return m88e1510_hwmon_probe(phydev); 21800b04680fSAndrew Lunn } 21810b04680fSAndrew Lunn 2182fee2d546SAndrew Lunn static int m88e6390_probe(struct phy_device *phydev) 2183fee2d546SAndrew Lunn { 2184fee2d546SAndrew Lunn int err; 2185fee2d546SAndrew Lunn 2186fee2d546SAndrew Lunn err = marvell_probe(phydev); 2187fee2d546SAndrew Lunn if (err) 2188fee2d546SAndrew Lunn return err; 2189fee2d546SAndrew Lunn 2190fee2d546SAndrew Lunn return m88e6390_hwmon_probe(phydev); 2191fee2d546SAndrew Lunn } 2192fee2d546SAndrew Lunn 2193e5479239SOlof Johansson static struct phy_driver marvell_drivers[] = { 2194e5479239SOlof Johansson { 21952f495c39SBenjamin Herrenschmidt .phy_id = MARVELL_PHY_ID_88E1101, 21962f495c39SBenjamin Herrenschmidt .phy_id_mask = MARVELL_PHY_ID_MASK, 219700db8189SAndy Fleming .name = "Marvell 88E1101", 2198dcdecdcfSHeiner Kallweit /* PHY_GBIT_FEATURES */ 219918702414SArnd Bergmann .probe = marvell_probe, 220079be1a1cSClemens Gruber .config_init = &marvell_config_init, 2201f2899788SAndrew Lunn .config_aneg = &m88e1101_config_aneg, 220200db8189SAndy Fleming .ack_interrupt = &marvell_ack_interrupt, 220300db8189SAndy Fleming .config_intr = &marvell_config_intr, 22040898b448SSebastian Hesselbarth .resume = &genphy_resume, 22050898b448SSebastian Hesselbarth .suspend = &genphy_suspend, 2206424ca4c5SRussell King .read_page = marvell_read_page, 2207424ca4c5SRussell King .write_page = marvell_write_page, 2208d2fa47d9SAndrew Lunn .get_sset_count = marvell_get_sset_count, 2209d2fa47d9SAndrew Lunn .get_strings = marvell_get_strings, 2210d2fa47d9SAndrew Lunn .get_stats = marvell_get_stats, 2211e5479239SOlof Johansson }, 2212e5479239SOlof Johansson { 22132f495c39SBenjamin Herrenschmidt .phy_id = MARVELL_PHY_ID_88E1112, 22142f495c39SBenjamin Herrenschmidt .phy_id_mask = MARVELL_PHY_ID_MASK, 221585cfb534SOlof Johansson .name = "Marvell 88E1112", 2216dcdecdcfSHeiner Kallweit /* PHY_GBIT_FEATURES */ 2217d2fa47d9SAndrew Lunn .probe = marvell_probe, 221885cfb534SOlof Johansson .config_init = &m88e1111_config_init, 221985cfb534SOlof Johansson .config_aneg = &marvell_config_aneg, 222085cfb534SOlof Johansson .ack_interrupt = &marvell_ack_interrupt, 222185cfb534SOlof Johansson .config_intr = &marvell_config_intr, 22220898b448SSebastian Hesselbarth .resume = &genphy_resume, 22230898b448SSebastian Hesselbarth .suspend = &genphy_suspend, 2224424ca4c5SRussell King .read_page = marvell_read_page, 2225424ca4c5SRussell King .write_page = marvell_write_page, 2226d2fa47d9SAndrew Lunn .get_sset_count = marvell_get_sset_count, 2227d2fa47d9SAndrew Lunn .get_strings = marvell_get_strings, 2228d2fa47d9SAndrew Lunn .get_stats = marvell_get_stats, 222985cfb534SOlof Johansson }, 223085cfb534SOlof Johansson { 22312f495c39SBenjamin Herrenschmidt .phy_id = MARVELL_PHY_ID_88E1111, 22322f495c39SBenjamin Herrenschmidt .phy_id_mask = MARVELL_PHY_ID_MASK, 223376884679SAndy Fleming .name = "Marvell 88E1111", 2234dcdecdcfSHeiner Kallweit /* PHY_GBIT_FEATURES */ 2235d2fa47d9SAndrew Lunn .probe = marvell_probe, 2236e5479239SOlof Johansson .config_init = &m88e1111_config_init, 2237d6ab9336SFlorian Fainelli .config_aneg = &marvell_config_aneg, 2238be937f1fSAlexandr Smirnov .read_status = &marvell_read_status, 223976884679SAndy Fleming .ack_interrupt = &marvell_ack_interrupt, 224076884679SAndy Fleming .config_intr = &marvell_config_intr, 22410898b448SSebastian Hesselbarth .resume = &genphy_resume, 22420898b448SSebastian Hesselbarth .suspend = &genphy_suspend, 2243424ca4c5SRussell King .read_page = marvell_read_page, 2244424ca4c5SRussell King .write_page = marvell_write_page, 2245d2fa47d9SAndrew Lunn .get_sset_count = marvell_get_sset_count, 2246d2fa47d9SAndrew Lunn .get_strings = marvell_get_strings, 2247d2fa47d9SAndrew Lunn .get_stats = marvell_get_stats, 2248e5479239SOlof Johansson }, 2249e5479239SOlof Johansson { 22502f495c39SBenjamin Herrenschmidt .phy_id = MARVELL_PHY_ID_88E1118, 22512f495c39SBenjamin Herrenschmidt .phy_id_mask = MARVELL_PHY_ID_MASK, 2252605f196eSRon Madrid .name = "Marvell 88E1118", 2253dcdecdcfSHeiner Kallweit /* PHY_GBIT_FEATURES */ 2254d2fa47d9SAndrew Lunn .probe = marvell_probe, 2255605f196eSRon Madrid .config_init = &m88e1118_config_init, 2256605f196eSRon Madrid .config_aneg = &m88e1118_config_aneg, 2257605f196eSRon Madrid .ack_interrupt = &marvell_ack_interrupt, 2258605f196eSRon Madrid .config_intr = &marvell_config_intr, 22590898b448SSebastian Hesselbarth .resume = &genphy_resume, 22600898b448SSebastian Hesselbarth .suspend = &genphy_suspend, 2261424ca4c5SRussell King .read_page = marvell_read_page, 2262424ca4c5SRussell King .write_page = marvell_write_page, 2263d2fa47d9SAndrew Lunn .get_sset_count = marvell_get_sset_count, 2264d2fa47d9SAndrew Lunn .get_strings = marvell_get_strings, 2265d2fa47d9SAndrew Lunn .get_stats = marvell_get_stats, 2266605f196eSRon Madrid }, 2267605f196eSRon Madrid { 22682f495c39SBenjamin Herrenschmidt .phy_id = MARVELL_PHY_ID_88E1121R, 22692f495c39SBenjamin Herrenschmidt .phy_id_mask = MARVELL_PHY_ID_MASK, 2270140bc929SSergei Poselenov .name = "Marvell 88E1121R", 2271dcdecdcfSHeiner Kallweit /* PHY_GBIT_FEATURES */ 227218702414SArnd Bergmann .probe = &m88e1121_probe, 227307777246SWang Dongsheng .config_init = &marvell_config_init, 2274140bc929SSergei Poselenov .config_aneg = &m88e1121_config_aneg, 2275140bc929SSergei Poselenov .read_status = &marvell_read_status, 2276140bc929SSergei Poselenov .ack_interrupt = &marvell_ack_interrupt, 2277140bc929SSergei Poselenov .config_intr = &marvell_config_intr, 2278dcd07be3SAnatolij Gustschin .did_interrupt = &m88e1121_did_interrupt, 22790898b448SSebastian Hesselbarth .resume = &genphy_resume, 22800898b448SSebastian Hesselbarth .suspend = &genphy_suspend, 2281424ca4c5SRussell King .read_page = marvell_read_page, 2282424ca4c5SRussell King .write_page = marvell_write_page, 2283d2fa47d9SAndrew Lunn .get_sset_count = marvell_get_sset_count, 2284d2fa47d9SAndrew Lunn .get_strings = marvell_get_strings, 2285d2fa47d9SAndrew Lunn .get_stats = marvell_get_stats, 2286911af5e1SHeiner Kallweit .get_tunable = m88e1011_get_tunable, 2287911af5e1SHeiner Kallweit .set_tunable = m88e1011_set_tunable, 2288911af5e1SHeiner Kallweit .link_change_notify = m88e1011_link_change_notify, 2289140bc929SSergei Poselenov }, 2290140bc929SSergei Poselenov { 2291337ac9d5SCyril Chemparathy .phy_id = MARVELL_PHY_ID_88E1318S, 22926ba74014SLinus Torvalds .phy_id_mask = MARVELL_PHY_ID_MASK, 2293337ac9d5SCyril Chemparathy .name = "Marvell 88E1318S", 2294dcdecdcfSHeiner Kallweit /* PHY_GBIT_FEATURES */ 2295d2fa47d9SAndrew Lunn .probe = marvell_probe, 2296dd9a122aSEsben Haabendal .config_init = &m88e1318_config_init, 2297337ac9d5SCyril Chemparathy .config_aneg = &m88e1318_config_aneg, 22983ff1c259SCyril Chemparathy .read_status = &marvell_read_status, 22993ff1c259SCyril Chemparathy .ack_interrupt = &marvell_ack_interrupt, 23003ff1c259SCyril Chemparathy .config_intr = &marvell_config_intr, 23013ff1c259SCyril Chemparathy .did_interrupt = &m88e1121_did_interrupt, 23023871c387SMichael Stapelberg .get_wol = &m88e1318_get_wol, 23033871c387SMichael Stapelberg .set_wol = &m88e1318_set_wol, 23040898b448SSebastian Hesselbarth .resume = &genphy_resume, 23050898b448SSebastian Hesselbarth .suspend = &genphy_suspend, 2306424ca4c5SRussell King .read_page = marvell_read_page, 2307424ca4c5SRussell King .write_page = marvell_write_page, 2308d2fa47d9SAndrew Lunn .get_sset_count = marvell_get_sset_count, 2309d2fa47d9SAndrew Lunn .get_strings = marvell_get_strings, 2310d2fa47d9SAndrew Lunn .get_stats = marvell_get_stats, 23113ff1c259SCyril Chemparathy }, 23123ff1c259SCyril Chemparathy { 23132f495c39SBenjamin Herrenschmidt .phy_id = MARVELL_PHY_ID_88E1145, 23142f495c39SBenjamin Herrenschmidt .phy_id_mask = MARVELL_PHY_ID_MASK, 231576884679SAndy Fleming .name = "Marvell 88E1145", 2316dcdecdcfSHeiner Kallweit /* PHY_GBIT_FEATURES */ 2317d2fa47d9SAndrew Lunn .probe = marvell_probe, 231876884679SAndy Fleming .config_init = &m88e1145_config_init, 2319c505873eSZhao Qiang .config_aneg = &m88e1101_config_aneg, 232076884679SAndy Fleming .read_status = &genphy_read_status, 232176884679SAndy Fleming .ack_interrupt = &marvell_ack_interrupt, 232276884679SAndy Fleming .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, 2330ac8c635aSOlof Johansson }, 2331ac8c635aSOlof Johansson { 233290600732SDavid Daney .phy_id = MARVELL_PHY_ID_88E1149R, 233390600732SDavid Daney .phy_id_mask = MARVELL_PHY_ID_MASK, 233490600732SDavid Daney .name = "Marvell 88E1149R", 2335dcdecdcfSHeiner Kallweit /* PHY_GBIT_FEATURES */ 2336d2fa47d9SAndrew Lunn .probe = marvell_probe, 233790600732SDavid Daney .config_init = &m88e1149_config_init, 233890600732SDavid Daney .config_aneg = &m88e1118_config_aneg, 233990600732SDavid Daney .ack_interrupt = &marvell_ack_interrupt, 234090600732SDavid Daney .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, 234890600732SDavid Daney }, 234990600732SDavid Daney { 23502f495c39SBenjamin Herrenschmidt .phy_id = MARVELL_PHY_ID_88E1240, 23512f495c39SBenjamin Herrenschmidt .phy_id_mask = MARVELL_PHY_ID_MASK, 2352ac8c635aSOlof Johansson .name = "Marvell 88E1240", 2353dcdecdcfSHeiner Kallweit /* PHY_GBIT_FEATURES */ 2354d2fa47d9SAndrew Lunn .probe = marvell_probe, 2355ac8c635aSOlof Johansson .config_init = &m88e1111_config_init, 2356ac8c635aSOlof Johansson .config_aneg = &marvell_config_aneg, 2357ac8c635aSOlof Johansson .ack_interrupt = &marvell_ack_interrupt, 2358ac8c635aSOlof Johansson .config_intr = &marvell_config_intr, 23590898b448SSebastian Hesselbarth .resume = &genphy_resume, 23600898b448SSebastian Hesselbarth .suspend = &genphy_suspend, 2361424ca4c5SRussell King .read_page = marvell_read_page, 2362424ca4c5SRussell King .write_page = marvell_write_page, 2363d2fa47d9SAndrew Lunn .get_sset_count = marvell_get_sset_count, 2364d2fa47d9SAndrew Lunn .get_strings = marvell_get_strings, 2365d2fa47d9SAndrew Lunn .get_stats = marvell_get_stats, 2366ac8c635aSOlof Johansson }, 23673da09a51SMichal Simek { 23683da09a51SMichal Simek .phy_id = MARVELL_PHY_ID_88E1116R, 23693da09a51SMichal Simek .phy_id_mask = MARVELL_PHY_ID_MASK, 23703da09a51SMichal Simek .name = "Marvell 88E1116R", 2371dcdecdcfSHeiner Kallweit /* PHY_GBIT_FEATURES */ 2372d2fa47d9SAndrew Lunn .probe = marvell_probe, 23733da09a51SMichal Simek .config_init = &m88e1116r_config_init, 23743da09a51SMichal Simek .ack_interrupt = &marvell_ack_interrupt, 23753da09a51SMichal Simek .config_intr = &marvell_config_intr, 23760898b448SSebastian Hesselbarth .resume = &genphy_resume, 23770898b448SSebastian Hesselbarth .suspend = &genphy_suspend, 2378424ca4c5SRussell King .read_page = marvell_read_page, 2379424ca4c5SRussell King .write_page = marvell_write_page, 2380d2fa47d9SAndrew Lunn .get_sset_count = marvell_get_sset_count, 2381d2fa47d9SAndrew Lunn .get_strings = marvell_get_strings, 2382d2fa47d9SAndrew Lunn .get_stats = marvell_get_stats, 23833da09a51SMichal Simek }, 238410e24caaSMichal Simek { 238510e24caaSMichal Simek .phy_id = MARVELL_PHY_ID_88E1510, 238610e24caaSMichal Simek .phy_id_mask = MARVELL_PHY_ID_MASK, 238710e24caaSMichal Simek .name = "Marvell 88E1510", 2388719655a1SAndrew Lunn .features = PHY_GBIT_FIBRE_FEATURES, 23890b04680fSAndrew Lunn .probe = &m88e1510_probe, 2390930b37eeSStefan Roese .config_init = &m88e1510_config_init, 239110e24caaSMichal Simek .config_aneg = &m88e1510_config_aneg, 239210e24caaSMichal Simek .read_status = &marvell_read_status, 239310e24caaSMichal Simek .ack_interrupt = &marvell_ack_interrupt, 239410e24caaSMichal Simek .config_intr = &marvell_config_intr, 239510e24caaSMichal Simek .did_interrupt = &m88e1121_did_interrupt, 2396f39aac7eSJingju Hou .get_wol = &m88e1318_get_wol, 2397f39aac7eSJingju Hou .set_wol = &m88e1318_set_wol, 23983758be3dSCharles-Antoine Couret .resume = &marvell_resume, 23993758be3dSCharles-Antoine Couret .suspend = &marvell_suspend, 2400424ca4c5SRussell King .read_page = marvell_read_page, 2401424ca4c5SRussell King .write_page = marvell_write_page, 2402d2fa47d9SAndrew Lunn .get_sset_count = marvell_get_sset_count, 2403d2fa47d9SAndrew Lunn .get_strings = marvell_get_strings, 2404d2fa47d9SAndrew Lunn .get_stats = marvell_get_stats, 2405f0f9b4edSLin Yun Sheng .set_loopback = genphy_loopback, 240610e24caaSMichal Simek }, 24076b358aedSSebastian Hesselbarth { 2408819ec8e1SAndrew Lunn .phy_id = MARVELL_PHY_ID_88E1540, 2409819ec8e1SAndrew Lunn .phy_id_mask = MARVELL_PHY_ID_MASK, 2410819ec8e1SAndrew Lunn .name = "Marvell 88E1540", 2411dcdecdcfSHeiner Kallweit /* PHY_GBIT_FEATURES */ 241218702414SArnd Bergmann .probe = m88e1510_probe, 241379be1a1cSClemens Gruber .config_init = &marvell_config_init, 2414819ec8e1SAndrew Lunn .config_aneg = &m88e1510_config_aneg, 2415819ec8e1SAndrew Lunn .read_status = &marvell_read_status, 2416819ec8e1SAndrew Lunn .ack_interrupt = &marvell_ack_interrupt, 2417819ec8e1SAndrew Lunn .config_intr = &marvell_config_intr, 2418819ec8e1SAndrew Lunn .did_interrupt = &m88e1121_did_interrupt, 2419819ec8e1SAndrew Lunn .resume = &genphy_resume, 2420819ec8e1SAndrew Lunn .suspend = &genphy_suspend, 2421424ca4c5SRussell King .read_page = marvell_read_page, 2422424ca4c5SRussell King .write_page = marvell_write_page, 2423d2fa47d9SAndrew Lunn .get_sset_count = marvell_get_sset_count, 2424d2fa47d9SAndrew Lunn .get_strings = marvell_get_strings, 2425d2fa47d9SAndrew Lunn .get_stats = marvell_get_stats, 242669f42be8SHeiner Kallweit .get_tunable = m88e1540_get_tunable, 242769f42be8SHeiner Kallweit .set_tunable = m88e1540_set_tunable, 2428911af5e1SHeiner Kallweit .link_change_notify = m88e1011_link_change_notify, 2429819ec8e1SAndrew Lunn }, 2430819ec8e1SAndrew Lunn { 243160f06fdeSAndrew Lunn .phy_id = MARVELL_PHY_ID_88E1545, 243260f06fdeSAndrew Lunn .phy_id_mask = MARVELL_PHY_ID_MASK, 243360f06fdeSAndrew Lunn .name = "Marvell 88E1545", 243460f06fdeSAndrew Lunn .probe = m88e1510_probe, 2435dcdecdcfSHeiner Kallweit /* PHY_GBIT_FEATURES */ 243660f06fdeSAndrew Lunn .config_init = &marvell_config_init, 243760f06fdeSAndrew Lunn .config_aneg = &m88e1510_config_aneg, 243860f06fdeSAndrew Lunn .read_status = &marvell_read_status, 243960f06fdeSAndrew Lunn .ack_interrupt = &marvell_ack_interrupt, 244060f06fdeSAndrew Lunn .config_intr = &marvell_config_intr, 244160f06fdeSAndrew Lunn .did_interrupt = &m88e1121_did_interrupt, 244260f06fdeSAndrew Lunn .resume = &genphy_resume, 244360f06fdeSAndrew Lunn .suspend = &genphy_suspend, 2444424ca4c5SRussell King .read_page = marvell_read_page, 2445424ca4c5SRussell King .write_page = marvell_write_page, 244660f06fdeSAndrew Lunn .get_sset_count = marvell_get_sset_count, 244760f06fdeSAndrew Lunn .get_strings = marvell_get_strings, 244860f06fdeSAndrew Lunn .get_stats = marvell_get_stats, 244960f06fdeSAndrew Lunn }, 245060f06fdeSAndrew Lunn { 24516b358aedSSebastian Hesselbarth .phy_id = MARVELL_PHY_ID_88E3016, 24526b358aedSSebastian Hesselbarth .phy_id_mask = MARVELL_PHY_ID_MASK, 24536b358aedSSebastian Hesselbarth .name = "Marvell 88E3016", 2454dcdecdcfSHeiner Kallweit /* PHY_BASIC_FEATURES */ 2455d2fa47d9SAndrew Lunn .probe = marvell_probe, 24566b358aedSSebastian Hesselbarth .config_init = &m88e3016_config_init, 24576b358aedSSebastian Hesselbarth .aneg_done = &marvell_aneg_done, 24586b358aedSSebastian Hesselbarth .read_status = &marvell_read_status, 24596b358aedSSebastian Hesselbarth .ack_interrupt = &marvell_ack_interrupt, 24606b358aedSSebastian Hesselbarth .config_intr = &marvell_config_intr, 24616b358aedSSebastian Hesselbarth .did_interrupt = &m88e1121_did_interrupt, 24626b358aedSSebastian Hesselbarth .resume = &genphy_resume, 24636b358aedSSebastian Hesselbarth .suspend = &genphy_suspend, 2464424ca4c5SRussell King .read_page = marvell_read_page, 2465424ca4c5SRussell King .write_page = marvell_write_page, 2466d2fa47d9SAndrew Lunn .get_sset_count = marvell_get_sset_count, 2467d2fa47d9SAndrew Lunn .get_strings = marvell_get_strings, 2468d2fa47d9SAndrew Lunn .get_stats = marvell_get_stats, 24696b358aedSSebastian Hesselbarth }, 2470e4cf8a38SAndrew Lunn { 2471e4cf8a38SAndrew Lunn .phy_id = MARVELL_PHY_ID_88E6390, 2472e4cf8a38SAndrew Lunn .phy_id_mask = MARVELL_PHY_ID_MASK, 2473e4cf8a38SAndrew Lunn .name = "Marvell 88E6390", 2474dcdecdcfSHeiner Kallweit /* PHY_GBIT_FEATURES */ 2475fee2d546SAndrew Lunn .probe = m88e6390_probe, 2476e4cf8a38SAndrew Lunn .config_init = &marvell_config_init, 24778cbcdc1aSAndrew Lunn .config_aneg = &m88e6390_config_aneg, 2478e4cf8a38SAndrew Lunn .read_status = &marvell_read_status, 2479e4cf8a38SAndrew Lunn .ack_interrupt = &marvell_ack_interrupt, 2480e4cf8a38SAndrew Lunn .config_intr = &marvell_config_intr, 2481e4cf8a38SAndrew Lunn .did_interrupt = &m88e1121_did_interrupt, 2482e4cf8a38SAndrew Lunn .resume = &genphy_resume, 2483e4cf8a38SAndrew Lunn .suspend = &genphy_suspend, 2484424ca4c5SRussell King .read_page = marvell_read_page, 2485424ca4c5SRussell King .write_page = marvell_write_page, 2486e4cf8a38SAndrew Lunn .get_sset_count = marvell_get_sset_count, 2487e4cf8a38SAndrew Lunn .get_strings = marvell_get_strings, 2488e4cf8a38SAndrew Lunn .get_stats = marvell_get_stats, 248969f42be8SHeiner Kallweit .get_tunable = m88e1540_get_tunable, 249069f42be8SHeiner Kallweit .set_tunable = m88e1540_set_tunable, 2491911af5e1SHeiner Kallweit .link_change_notify = m88e1011_link_change_notify, 2492e4cf8a38SAndrew Lunn }, 249376884679SAndy Fleming }; 249476884679SAndy Fleming 249550fd7150SJohan Hovold module_phy_driver(marvell_drivers); 24964e4f10f6SDavid Woodhouse 2497cf93c945SUwe Kleine-König static struct mdio_device_id __maybe_unused marvell_tbl[] = { 2498f5e1cabfSMichal Simek { MARVELL_PHY_ID_88E1101, MARVELL_PHY_ID_MASK }, 2499f5e1cabfSMichal Simek { MARVELL_PHY_ID_88E1112, MARVELL_PHY_ID_MASK }, 2500f5e1cabfSMichal Simek { MARVELL_PHY_ID_88E1111, MARVELL_PHY_ID_MASK }, 2501f5e1cabfSMichal Simek { MARVELL_PHY_ID_88E1118, MARVELL_PHY_ID_MASK }, 2502f5e1cabfSMichal Simek { MARVELL_PHY_ID_88E1121R, MARVELL_PHY_ID_MASK }, 2503f5e1cabfSMichal Simek { MARVELL_PHY_ID_88E1145, MARVELL_PHY_ID_MASK }, 2504f5e1cabfSMichal Simek { MARVELL_PHY_ID_88E1149R, MARVELL_PHY_ID_MASK }, 2505f5e1cabfSMichal Simek { MARVELL_PHY_ID_88E1240, MARVELL_PHY_ID_MASK }, 2506f5e1cabfSMichal Simek { MARVELL_PHY_ID_88E1318S, MARVELL_PHY_ID_MASK }, 25073da09a51SMichal Simek { MARVELL_PHY_ID_88E1116R, MARVELL_PHY_ID_MASK }, 250810e24caaSMichal Simek { MARVELL_PHY_ID_88E1510, MARVELL_PHY_ID_MASK }, 2509819ec8e1SAndrew Lunn { MARVELL_PHY_ID_88E1540, MARVELL_PHY_ID_MASK }, 251060f06fdeSAndrew Lunn { MARVELL_PHY_ID_88E1545, MARVELL_PHY_ID_MASK }, 25116b358aedSSebastian Hesselbarth { MARVELL_PHY_ID_88E3016, MARVELL_PHY_ID_MASK }, 2512e4cf8a38SAndrew Lunn { MARVELL_PHY_ID_88E6390, MARVELL_PHY_ID_MASK }, 25134e4f10f6SDavid Woodhouse { } 25144e4f10f6SDavid Woodhouse }; 25154e4f10f6SDavid Woodhouse 25164e4f10f6SDavid Woodhouse MODULE_DEVICE_TABLE(mdio, marvell_tbl); 2517