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> 30fc879f72SAndrew Lunn #include <linux/ethtool_netlink.h> 3100db8189SAndy Fleming #include <linux/phy.h> 322f495c39SBenjamin Herrenschmidt #include <linux/marvell_phy.h> 3369f42be8SHeiner Kallweit #include <linux/bitfield.h> 34cf41a51dSDavid Daney #include <linux/of.h> 3500db8189SAndy Fleming 36eea3b201SAvinash Kumar #include <linux/io.h> 3700db8189SAndy Fleming #include <asm/irq.h> 38eea3b201SAvinash Kumar #include <linux/uaccess.h> 3900db8189SAndy Fleming 4027d916d6SDavid Daney #define MII_MARVELL_PHY_PAGE 22 4152295666SAndrew Lunn #define MII_MARVELL_COPPER_PAGE 0x00 4252295666SAndrew Lunn #define MII_MARVELL_FIBER_PAGE 0x01 4352295666SAndrew Lunn #define MII_MARVELL_MSCR_PAGE 0x02 4452295666SAndrew Lunn #define MII_MARVELL_LED_PAGE 0x03 4552295666SAndrew Lunn #define MII_MARVELL_MISC_TEST_PAGE 0x06 46fc879f72SAndrew Lunn #define MII_MARVELL_VCT7_PAGE 0x07 4752295666SAndrew Lunn #define MII_MARVELL_WOL_PAGE 0x11 4827d916d6SDavid Daney 4900db8189SAndy Fleming #define MII_M1011_IEVENT 0x13 5000db8189SAndy Fleming #define MII_M1011_IEVENT_CLEAR 0x0000 5100db8189SAndy Fleming 5200db8189SAndy Fleming #define MII_M1011_IMASK 0x12 5300db8189SAndy Fleming #define MII_M1011_IMASK_INIT 0x6400 5400db8189SAndy Fleming #define MII_M1011_IMASK_CLEAR 0x0000 5500db8189SAndy Fleming 5676884679SAndy Fleming #define MII_M1011_PHY_SCR 0x10 57fecd5e91SAndrew Lunn #define MII_M1011_PHY_SCR_DOWNSHIFT_EN BIT(11) 58f8d975beSHeiner Kallweit #define MII_M1011_PHY_SCR_DOWNSHIFT_MASK GENMASK(14, 12) 59a3bdfce7SHeiner Kallweit #define MII_M1011_PHY_SCR_DOWNSHIFT_MAX 8 60fecd5e91SAndrew Lunn #define MII_M1011_PHY_SCR_MDI (0x0 << 5) 61fecd5e91SAndrew Lunn #define MII_M1011_PHY_SCR_MDI_X (0x1 << 5) 62fecd5e91SAndrew Lunn #define MII_M1011_PHY_SCR_AUTO_CROSS (0x3 << 5) 6376884679SAndy Fleming 64a3bdfce7SHeiner Kallweit #define MII_M1011_PHY_SSR 0x11 65a3bdfce7SHeiner Kallweit #define MII_M1011_PHY_SSR_DOWNSHIFT BIT(5) 66a3bdfce7SHeiner Kallweit 6776884679SAndy Fleming #define MII_M1111_PHY_LED_CONTROL 0x18 6876884679SAndy Fleming #define MII_M1111_PHY_LED_DIRECT 0x4100 6976884679SAndy Fleming #define MII_M1111_PHY_LED_COMBINE 0x411c 70895ee682SKim Phillips #define MII_M1111_PHY_EXT_CR 0x14 715c6bc519SHeiner Kallweit #define MII_M1111_PHY_EXT_CR_DOWNSHIFT_MASK GENMASK(11, 9) 725c6bc519SHeiner Kallweit #define MII_M1111_PHY_EXT_CR_DOWNSHIFT_MAX 8 735c6bc519SHeiner Kallweit #define MII_M1111_PHY_EXT_CR_DOWNSHIFT_EN BIT(8) 7461111598SAndrew Lunn #define MII_M1111_RGMII_RX_DELAY BIT(7) 7561111598SAndrew Lunn #define MII_M1111_RGMII_TX_DELAY BIT(1) 76895ee682SKim Phillips #define MII_M1111_PHY_EXT_SR 0x1b 77be937f1fSAlexandr Smirnov 78895ee682SKim Phillips #define MII_M1111_HWCFG_MODE_MASK 0xf 79be937f1fSAlexandr Smirnov #define MII_M1111_HWCFG_MODE_FIBER_RGMII 0x3 804117b5beSKapil Juneja #define MII_M1111_HWCFG_MODE_SGMII_NO_CLK 0x4 81865b813aSAndrew Lunn #define MII_M1111_HWCFG_MODE_RTBI 0x7 825f8cbc13SLiu Yu-B13201 #define MII_M1111_HWCFG_MODE_COPPER_RTBI 0x9 83865b813aSAndrew Lunn #define MII_M1111_HWCFG_MODE_COPPER_RGMII 0xb 84865b813aSAndrew Lunn #define MII_M1111_HWCFG_FIBER_COPPER_RES BIT(13) 85865b813aSAndrew Lunn #define MII_M1111_HWCFG_FIBER_COPPER_AUTO BIT(15) 86be937f1fSAlexandr Smirnov 87c477d044SCyril Chemparathy #define MII_88E1121_PHY_MSCR_REG 21 88c477d044SCyril Chemparathy #define MII_88E1121_PHY_MSCR_RX_DELAY BIT(5) 89c477d044SCyril Chemparathy #define MII_88E1121_PHY_MSCR_TX_DELAY BIT(4) 90424ca4c5SRussell King #define MII_88E1121_PHY_MSCR_DELAY_MASK (BIT(5) | BIT(4)) 91c477d044SCyril Chemparathy 920b04680fSAndrew Lunn #define MII_88E1121_MISC_TEST 0x1a 930b04680fSAndrew Lunn #define MII_88E1510_MISC_TEST_TEMP_THRESHOLD_MASK 0x1f00 940b04680fSAndrew Lunn #define MII_88E1510_MISC_TEST_TEMP_THRESHOLD_SHIFT 8 950b04680fSAndrew Lunn #define MII_88E1510_MISC_TEST_TEMP_IRQ_EN BIT(7) 960b04680fSAndrew Lunn #define MII_88E1510_MISC_TEST_TEMP_IRQ BIT(6) 970b04680fSAndrew Lunn #define MII_88E1121_MISC_TEST_TEMP_SENSOR_EN BIT(5) 980b04680fSAndrew Lunn #define MII_88E1121_MISC_TEST_TEMP_MASK 0x1f 990b04680fSAndrew Lunn 1000b04680fSAndrew Lunn #define MII_88E1510_TEMP_SENSOR 0x1b 1010b04680fSAndrew Lunn #define MII_88E1510_TEMP_SENSOR_MASK 0xff 1020b04680fSAndrew Lunn 10369f42be8SHeiner Kallweit #define MII_88E1540_COPPER_CTRL3 0x1a 10469f42be8SHeiner Kallweit #define MII_88E1540_COPPER_CTRL3_LINK_DOWN_DELAY_MASK GENMASK(11, 10) 10569f42be8SHeiner Kallweit #define MII_88E1540_COPPER_CTRL3_LINK_DOWN_DELAY_00MS 0 10669f42be8SHeiner Kallweit #define MII_88E1540_COPPER_CTRL3_LINK_DOWN_DELAY_10MS 1 10769f42be8SHeiner Kallweit #define MII_88E1540_COPPER_CTRL3_LINK_DOWN_DELAY_20MS 2 10869f42be8SHeiner Kallweit #define MII_88E1540_COPPER_CTRL3_LINK_DOWN_DELAY_40MS 3 10969f42be8SHeiner Kallweit #define MII_88E1540_COPPER_CTRL3_FAST_LINK_DOWN BIT(9) 11069f42be8SHeiner Kallweit 111fee2d546SAndrew Lunn #define MII_88E6390_MISC_TEST 0x1b 112fee2d546SAndrew Lunn #define MII_88E6390_MISC_TEST_SAMPLE_1S 0 113fee2d546SAndrew Lunn #define MII_88E6390_MISC_TEST_SAMPLE_10MS BIT(14) 114fee2d546SAndrew Lunn #define MII_88E6390_MISC_TEST_SAMPLE_DISABLE BIT(15) 115fee2d546SAndrew Lunn #define MII_88E6390_MISC_TEST_SAMPLE_ENABLE 0 116fee2d546SAndrew Lunn #define MII_88E6390_MISC_TEST_SAMPLE_MASK (0x3 << 14) 117fee2d546SAndrew Lunn 118fee2d546SAndrew Lunn #define MII_88E6390_TEMP_SENSOR 0x1c 119fee2d546SAndrew Lunn #define MII_88E6390_TEMP_SENSOR_MASK 0xff 120fee2d546SAndrew Lunn #define MII_88E6390_TEMP_SENSOR_SAMPLES 10 121fee2d546SAndrew Lunn 122337ac9d5SCyril Chemparathy #define MII_88E1318S_PHY_MSCR1_REG 16 123337ac9d5SCyril Chemparathy #define MII_88E1318S_PHY_MSCR1_PAD_ODD BIT(6) 1243ff1c259SCyril Chemparathy 1253871c387SMichael Stapelberg /* Copper Specific Interrupt Enable Register */ 1263871c387SMichael Stapelberg #define MII_88E1318S_PHY_CSIER 0x12 1273871c387SMichael Stapelberg /* WOL Event Interrupt Enable */ 1283871c387SMichael Stapelberg #define MII_88E1318S_PHY_CSIER_WOL_EIE BIT(7) 1293871c387SMichael Stapelberg 1303871c387SMichael Stapelberg /* LED Timer Control Register */ 1313871c387SMichael Stapelberg #define MII_88E1318S_PHY_LED_TCR 0x12 1323871c387SMichael Stapelberg #define MII_88E1318S_PHY_LED_TCR_FORCE_INT BIT(15) 1333871c387SMichael Stapelberg #define MII_88E1318S_PHY_LED_TCR_INTn_ENABLE BIT(7) 1343871c387SMichael Stapelberg #define MII_88E1318S_PHY_LED_TCR_INT_ACTIVE_LOW BIT(11) 1353871c387SMichael Stapelberg 1363871c387SMichael Stapelberg /* Magic Packet MAC address registers */ 1373871c387SMichael Stapelberg #define MII_88E1318S_PHY_MAGIC_PACKET_WORD2 0x17 1383871c387SMichael Stapelberg #define MII_88E1318S_PHY_MAGIC_PACKET_WORD1 0x18 1393871c387SMichael Stapelberg #define MII_88E1318S_PHY_MAGIC_PACKET_WORD0 0x19 1403871c387SMichael Stapelberg 1413871c387SMichael Stapelberg #define MII_88E1318S_PHY_WOL_CTRL 0x10 1423871c387SMichael Stapelberg #define MII_88E1318S_PHY_WOL_CTRL_CLEAR_WOL_STATUS BIT(12) 1433871c387SMichael Stapelberg #define MII_88E1318S_PHY_WOL_CTRL_MAGIC_PACKET_MATCH_ENABLE BIT(14) 1443871c387SMichael Stapelberg 14507777246SWang Dongsheng #define MII_PHY_LED_CTRL 16 146140bc929SSergei Poselenov #define MII_88E1121_PHY_LED_DEF 0x0030 14707777246SWang Dongsheng #define MII_88E1510_PHY_LED_DEF 0x1177 148a93f7fe1SJian Shen #define MII_88E1510_PHY_LED0_LINK_LED1_ACTIVE 0x1040 149140bc929SSergei Poselenov 150be937f1fSAlexandr Smirnov #define MII_M1011_PHY_STATUS 0x11 151be937f1fSAlexandr Smirnov #define MII_M1011_PHY_STATUS_1000 0x8000 152be937f1fSAlexandr Smirnov #define MII_M1011_PHY_STATUS_100 0x4000 153be937f1fSAlexandr Smirnov #define MII_M1011_PHY_STATUS_SPD_MASK 0xc000 154be937f1fSAlexandr Smirnov #define MII_M1011_PHY_STATUS_FULLDUPLEX 0x2000 155be937f1fSAlexandr Smirnov #define MII_M1011_PHY_STATUS_RESOLVED 0x0800 156be937f1fSAlexandr Smirnov #define MII_M1011_PHY_STATUS_LINK 0x0400 157be937f1fSAlexandr Smirnov 1586b358aedSSebastian Hesselbarth #define MII_88E3016_PHY_SPEC_CTRL 0x10 1596b358aedSSebastian Hesselbarth #define MII_88E3016_DISABLE_SCRAMBLER 0x0200 1606b358aedSSebastian Hesselbarth #define MII_88E3016_AUTO_MDIX_CROSSOVER 0x0030 16176884679SAndy Fleming 162930b37eeSStefan Roese #define MII_88E1510_GEN_CTRL_REG_1 0x14 163930b37eeSStefan Roese #define MII_88E1510_GEN_CTRL_REG_1_MODE_MASK 0x7 164930b37eeSStefan Roese #define MII_88E1510_GEN_CTRL_REG_1_MODE_SGMII 0x1 /* SGMII to copper */ 165930b37eeSStefan Roese #define MII_88E1510_GEN_CTRL_REG_1_RESET 0x8000 /* Soft reset */ 166930b37eeSStefan Roese 167fc879f72SAndrew Lunn #define MII_VCT7_PAIR_0_DISTANCE 0x10 168fc879f72SAndrew Lunn #define MII_VCT7_PAIR_1_DISTANCE 0x11 169fc879f72SAndrew Lunn #define MII_VCT7_PAIR_2_DISTANCE 0x12 170fc879f72SAndrew Lunn #define MII_VCT7_PAIR_3_DISTANCE 0x13 171fc879f72SAndrew Lunn 172fc879f72SAndrew Lunn #define MII_VCT7_RESULTS 0x14 173fc879f72SAndrew Lunn #define MII_VCT7_RESULTS_PAIR3_MASK 0xf000 174fc879f72SAndrew Lunn #define MII_VCT7_RESULTS_PAIR2_MASK 0x0f00 175fc879f72SAndrew Lunn #define MII_VCT7_RESULTS_PAIR1_MASK 0x00f0 176fc879f72SAndrew Lunn #define MII_VCT7_RESULTS_PAIR0_MASK 0x000f 177fc879f72SAndrew Lunn #define MII_VCT7_RESULTS_PAIR3_SHIFT 12 178fc879f72SAndrew Lunn #define MII_VCT7_RESULTS_PAIR2_SHIFT 8 179fc879f72SAndrew Lunn #define MII_VCT7_RESULTS_PAIR1_SHIFT 4 180fc879f72SAndrew Lunn #define MII_VCT7_RESULTS_PAIR0_SHIFT 0 181fc879f72SAndrew Lunn #define MII_VCT7_RESULTS_INVALID 0 182fc879f72SAndrew Lunn #define MII_VCT7_RESULTS_OK 1 183fc879f72SAndrew Lunn #define MII_VCT7_RESULTS_OPEN 2 184fc879f72SAndrew Lunn #define MII_VCT7_RESULTS_SAME_SHORT 3 185fc879f72SAndrew Lunn #define MII_VCT7_RESULTS_CROSS_SHORT 4 186fc879f72SAndrew Lunn #define MII_VCT7_RESULTS_BUSY 9 187fc879f72SAndrew Lunn 188fc879f72SAndrew Lunn #define MII_VCT7_CTRL 0x15 189fc879f72SAndrew Lunn #define MII_VCT7_CTRL_RUN_NOW BIT(15) 190fc879f72SAndrew Lunn #define MII_VCT7_CTRL_RUN_ANEG BIT(14) 191fc879f72SAndrew Lunn #define MII_VCT7_CTRL_DISABLE_CROSS BIT(13) 192fc879f72SAndrew Lunn #define MII_VCT7_CTRL_RUN_AFTER_BREAK_LINK BIT(12) 193fc879f72SAndrew Lunn #define MII_VCT7_CTRL_IN_PROGRESS BIT(11) 194fc879f72SAndrew Lunn #define MII_VCT7_CTRL_METERS BIT(10) 195fc879f72SAndrew Lunn #define MII_VCT7_CTRL_CENTIMETERS 0 196fc879f72SAndrew Lunn 1976cfb3bccSCharles-Antoine Couret #define LPA_PAUSE_FIBER 0x180 1986cfb3bccSCharles-Antoine Couret #define LPA_PAUSE_ASYM_FIBER 0x100 1996cfb3bccSCharles-Antoine Couret 2002170fef7SCharles-Antoine Couret #define NB_FIBER_STATS 1 2016cfb3bccSCharles-Antoine Couret 20200db8189SAndy Fleming MODULE_DESCRIPTION("Marvell PHY driver"); 20300db8189SAndy Fleming MODULE_AUTHOR("Andy Fleming"); 20400db8189SAndy Fleming MODULE_LICENSE("GPL"); 20500db8189SAndy Fleming 206d2fa47d9SAndrew Lunn struct marvell_hw_stat { 207d2fa47d9SAndrew Lunn const char *string; 208d2fa47d9SAndrew Lunn u8 page; 209d2fa47d9SAndrew Lunn u8 reg; 210d2fa47d9SAndrew Lunn u8 bits; 211d2fa47d9SAndrew Lunn }; 212d2fa47d9SAndrew Lunn 213d2fa47d9SAndrew Lunn static struct marvell_hw_stat marvell_hw_stats[] = { 2142170fef7SCharles-Antoine Couret { "phy_receive_errors_copper", 0, 21, 16}, 215d2fa47d9SAndrew Lunn { "phy_idle_errors", 0, 10, 8 }, 2162170fef7SCharles-Antoine Couret { "phy_receive_errors_fiber", 1, 21, 16}, 217d2fa47d9SAndrew Lunn }; 218d2fa47d9SAndrew Lunn 219d2fa47d9SAndrew Lunn struct marvell_priv { 220d2fa47d9SAndrew Lunn u64 stats[ARRAY_SIZE(marvell_hw_stats)]; 2210b04680fSAndrew Lunn char *hwmon_name; 2220b04680fSAndrew Lunn struct device *hwmon_dev; 223d2fa47d9SAndrew Lunn }; 224d2fa47d9SAndrew Lunn 225424ca4c5SRussell King static int marvell_read_page(struct phy_device *phydev) 2266427bb2dSAndrew Lunn { 227424ca4c5SRussell King return __phy_read(phydev, MII_MARVELL_PHY_PAGE); 228424ca4c5SRussell King } 229424ca4c5SRussell King 230424ca4c5SRussell King static int marvell_write_page(struct phy_device *phydev, int page) 231424ca4c5SRussell King { 232424ca4c5SRussell King return __phy_write(phydev, MII_MARVELL_PHY_PAGE, page); 2336427bb2dSAndrew Lunn } 2346427bb2dSAndrew Lunn 2356427bb2dSAndrew Lunn static int marvell_set_page(struct phy_device *phydev, int page) 2366427bb2dSAndrew Lunn { 2376427bb2dSAndrew Lunn return phy_write(phydev, MII_MARVELL_PHY_PAGE, page); 2386427bb2dSAndrew Lunn } 2396427bb2dSAndrew Lunn 24000db8189SAndy Fleming static int marvell_ack_interrupt(struct phy_device *phydev) 24100db8189SAndy Fleming { 24200db8189SAndy Fleming int err; 24300db8189SAndy Fleming 24400db8189SAndy Fleming /* Clear the interrupts by reading the reg */ 24500db8189SAndy Fleming err = phy_read(phydev, MII_M1011_IEVENT); 24600db8189SAndy Fleming 24700db8189SAndy Fleming if (err < 0) 24800db8189SAndy Fleming return err; 24900db8189SAndy Fleming 25000db8189SAndy Fleming return 0; 25100db8189SAndy Fleming } 25200db8189SAndy Fleming 25300db8189SAndy Fleming static int marvell_config_intr(struct phy_device *phydev) 25400db8189SAndy Fleming { 25500db8189SAndy Fleming int err; 25600db8189SAndy Fleming 25700db8189SAndy Fleming if (phydev->interrupts == PHY_INTERRUPT_ENABLED) 25823beb38fSAndrew Lunn err = phy_write(phydev, MII_M1011_IMASK, 25923beb38fSAndrew Lunn MII_M1011_IMASK_INIT); 26000db8189SAndy Fleming else 26123beb38fSAndrew Lunn err = phy_write(phydev, MII_M1011_IMASK, 26223beb38fSAndrew Lunn MII_M1011_IMASK_CLEAR); 26300db8189SAndy Fleming 26400db8189SAndy Fleming return err; 26500db8189SAndy Fleming } 26600db8189SAndy Fleming 267239aa55bSDavid Thomson static int marvell_set_polarity(struct phy_device *phydev, int polarity) 268239aa55bSDavid Thomson { 269239aa55bSDavid Thomson int reg; 270239aa55bSDavid Thomson int err; 271239aa55bSDavid Thomson int val; 272239aa55bSDavid Thomson 273239aa55bSDavid Thomson /* get the current settings */ 274239aa55bSDavid Thomson reg = phy_read(phydev, MII_M1011_PHY_SCR); 275239aa55bSDavid Thomson if (reg < 0) 276239aa55bSDavid Thomson return reg; 277239aa55bSDavid Thomson 278239aa55bSDavid Thomson val = reg; 279239aa55bSDavid Thomson val &= ~MII_M1011_PHY_SCR_AUTO_CROSS; 280239aa55bSDavid Thomson switch (polarity) { 281239aa55bSDavid Thomson case ETH_TP_MDI: 282239aa55bSDavid Thomson val |= MII_M1011_PHY_SCR_MDI; 283239aa55bSDavid Thomson break; 284239aa55bSDavid Thomson case ETH_TP_MDI_X: 285239aa55bSDavid Thomson val |= MII_M1011_PHY_SCR_MDI_X; 286239aa55bSDavid Thomson break; 287239aa55bSDavid Thomson case ETH_TP_MDI_AUTO: 288239aa55bSDavid Thomson case ETH_TP_MDI_INVALID: 289239aa55bSDavid Thomson default: 290239aa55bSDavid Thomson val |= MII_M1011_PHY_SCR_AUTO_CROSS; 291239aa55bSDavid Thomson break; 292239aa55bSDavid Thomson } 293239aa55bSDavid Thomson 294239aa55bSDavid Thomson if (val != reg) { 295239aa55bSDavid Thomson /* Set the new polarity value in the register */ 296239aa55bSDavid Thomson err = phy_write(phydev, MII_M1011_PHY_SCR, val); 297239aa55bSDavid Thomson if (err) 298239aa55bSDavid Thomson return err; 299239aa55bSDavid Thomson } 300239aa55bSDavid Thomson 301d6ab9336SFlorian Fainelli return val != reg; 302239aa55bSDavid Thomson } 303239aa55bSDavid Thomson 30400db8189SAndy Fleming static int marvell_config_aneg(struct phy_device *phydev) 30500db8189SAndy Fleming { 306d6ab9336SFlorian Fainelli int changed = 0; 30700db8189SAndy Fleming int err; 30800db8189SAndy Fleming 3094e26c5c3SRaju Lakkaraju err = marvell_set_polarity(phydev, phydev->mdix_ctrl); 31076884679SAndy Fleming if (err < 0) 31176884679SAndy Fleming return err; 31276884679SAndy Fleming 313d6ab9336SFlorian Fainelli changed = err; 314d6ab9336SFlorian Fainelli 31576884679SAndy Fleming err = phy_write(phydev, MII_M1111_PHY_LED_CONTROL, 31676884679SAndy Fleming MII_M1111_PHY_LED_DIRECT); 31776884679SAndy Fleming if (err < 0) 31876884679SAndy Fleming return err; 31900db8189SAndy Fleming 32000db8189SAndy Fleming err = genphy_config_aneg(phydev); 3218ff44985SAnton Vorontsov if (err < 0) 32200db8189SAndy Fleming return err; 3238ff44985SAnton Vorontsov 324d6ab9336SFlorian Fainelli if (phydev->autoneg != AUTONEG_ENABLE || changed) { 3250c3439bcSAndrew Lunn /* A write to speed/duplex bits (that is performed by 3268ff44985SAnton Vorontsov * genphy_config_aneg() call above) must be followed by 3278ff44985SAnton Vorontsov * a software reset. Otherwise, the write has no effect. 3288ff44985SAnton Vorontsov */ 32934386344SAndrew Lunn err = genphy_soft_reset(phydev); 3308ff44985SAnton Vorontsov if (err < 0) 3318ff44985SAnton Vorontsov return err; 3328ff44985SAnton Vorontsov } 3338ff44985SAnton Vorontsov 3348ff44985SAnton Vorontsov return 0; 33500db8189SAndy Fleming } 33600db8189SAndy Fleming 337f2899788SAndrew Lunn static int m88e1101_config_aneg(struct phy_device *phydev) 338f2899788SAndrew Lunn { 339f2899788SAndrew Lunn int err; 340f2899788SAndrew Lunn 341f2899788SAndrew Lunn /* This Marvell PHY has an errata which requires 342f2899788SAndrew Lunn * that certain registers get written in order 343f2899788SAndrew Lunn * to restart autonegotiation 344f2899788SAndrew Lunn */ 34534386344SAndrew Lunn err = genphy_soft_reset(phydev); 346f2899788SAndrew Lunn if (err < 0) 347f2899788SAndrew Lunn return err; 348f2899788SAndrew Lunn 349f2899788SAndrew Lunn err = phy_write(phydev, 0x1d, 0x1f); 350f2899788SAndrew Lunn if (err < 0) 351f2899788SAndrew Lunn return err; 352f2899788SAndrew Lunn 353f2899788SAndrew Lunn err = phy_write(phydev, 0x1e, 0x200c); 354f2899788SAndrew Lunn if (err < 0) 355f2899788SAndrew Lunn return err; 356f2899788SAndrew Lunn 357f2899788SAndrew Lunn err = phy_write(phydev, 0x1d, 0x5); 358f2899788SAndrew Lunn if (err < 0) 359f2899788SAndrew Lunn return err; 360f2899788SAndrew Lunn 361f2899788SAndrew Lunn err = phy_write(phydev, 0x1e, 0); 362f2899788SAndrew Lunn if (err < 0) 363f2899788SAndrew Lunn return err; 364f2899788SAndrew Lunn 365f2899788SAndrew Lunn err = phy_write(phydev, 0x1e, 0x100); 366f2899788SAndrew Lunn if (err < 0) 367f2899788SAndrew Lunn return err; 368f2899788SAndrew Lunn 369f2899788SAndrew Lunn return marvell_config_aneg(phydev); 370f2899788SAndrew Lunn } 371f2899788SAndrew Lunn 372cf41a51dSDavid Daney #ifdef CONFIG_OF_MDIO 3730c3439bcSAndrew Lunn /* Set and/or override some configuration registers based on the 374cf41a51dSDavid Daney * marvell,reg-init property stored in the of_node for the phydev. 375cf41a51dSDavid Daney * 376cf41a51dSDavid Daney * marvell,reg-init = <reg-page reg mask value>,...; 377cf41a51dSDavid Daney * 378cf41a51dSDavid Daney * There may be one or more sets of <reg-page reg mask value>: 379cf41a51dSDavid Daney * 380cf41a51dSDavid Daney * reg-page: which register bank to use. 381cf41a51dSDavid Daney * reg: the register. 382cf41a51dSDavid Daney * mask: if non-zero, ANDed with existing register value. 383cf41a51dSDavid Daney * value: ORed with the masked value and written to the regiser. 384cf41a51dSDavid Daney * 385cf41a51dSDavid Daney */ 386cf41a51dSDavid Daney static int marvell_of_reg_init(struct phy_device *phydev) 387cf41a51dSDavid Daney { 388cf41a51dSDavid Daney const __be32 *paddr; 389424ca4c5SRussell King int len, i, saved_page, current_page, ret = 0; 390cf41a51dSDavid Daney 391e5a03bfdSAndrew Lunn if (!phydev->mdio.dev.of_node) 392cf41a51dSDavid Daney return 0; 393cf41a51dSDavid Daney 394e5a03bfdSAndrew Lunn paddr = of_get_property(phydev->mdio.dev.of_node, 395e5a03bfdSAndrew Lunn "marvell,reg-init", &len); 396cf41a51dSDavid Daney if (!paddr || len < (4 * sizeof(*paddr))) 397cf41a51dSDavid Daney return 0; 398cf41a51dSDavid Daney 399424ca4c5SRussell King saved_page = phy_save_page(phydev); 400cf41a51dSDavid Daney if (saved_page < 0) 401424ca4c5SRussell King goto err; 402cf41a51dSDavid Daney current_page = saved_page; 403cf41a51dSDavid Daney 404cf41a51dSDavid Daney len /= sizeof(*paddr); 405cf41a51dSDavid Daney for (i = 0; i < len - 3; i += 4) { 4066427bb2dSAndrew Lunn u16 page = be32_to_cpup(paddr + i); 407cf41a51dSDavid Daney u16 reg = be32_to_cpup(paddr + i + 1); 408cf41a51dSDavid Daney u16 mask = be32_to_cpup(paddr + i + 2); 409cf41a51dSDavid Daney u16 val_bits = be32_to_cpup(paddr + i + 3); 410cf41a51dSDavid Daney int val; 411cf41a51dSDavid Daney 4126427bb2dSAndrew Lunn if (page != current_page) { 4136427bb2dSAndrew Lunn current_page = page; 414424ca4c5SRussell King ret = marvell_write_page(phydev, page); 415cf41a51dSDavid Daney if (ret < 0) 416cf41a51dSDavid Daney goto err; 417cf41a51dSDavid Daney } 418cf41a51dSDavid Daney 419cf41a51dSDavid Daney val = 0; 420cf41a51dSDavid Daney if (mask) { 421424ca4c5SRussell King val = __phy_read(phydev, reg); 422cf41a51dSDavid Daney if (val < 0) { 423cf41a51dSDavid Daney ret = val; 424cf41a51dSDavid Daney goto err; 425cf41a51dSDavid Daney } 426cf41a51dSDavid Daney val &= mask; 427cf41a51dSDavid Daney } 428cf41a51dSDavid Daney val |= val_bits; 429cf41a51dSDavid Daney 430424ca4c5SRussell King ret = __phy_write(phydev, reg, val); 431cf41a51dSDavid Daney if (ret < 0) 432cf41a51dSDavid Daney goto err; 433cf41a51dSDavid Daney } 434cf41a51dSDavid Daney err: 435424ca4c5SRussell King return phy_restore_page(phydev, saved_page, ret); 436cf41a51dSDavid Daney } 437cf41a51dSDavid Daney #else 438cf41a51dSDavid Daney static int marvell_of_reg_init(struct phy_device *phydev) 439cf41a51dSDavid Daney { 440cf41a51dSDavid Daney return 0; 441cf41a51dSDavid Daney } 442cf41a51dSDavid Daney #endif /* CONFIG_OF_MDIO */ 443cf41a51dSDavid Daney 444864dc729SAndrew Lunn static int m88e1121_config_aneg_rgmii_delays(struct phy_device *phydev) 445140bc929SSergei Poselenov { 446424ca4c5SRussell King int mscr; 447c477d044SCyril Chemparathy 448c477d044SCyril Chemparathy if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID) 449424ca4c5SRussell King mscr = MII_88E1121_PHY_MSCR_RX_DELAY | 450424ca4c5SRussell King MII_88E1121_PHY_MSCR_TX_DELAY; 451c477d044SCyril Chemparathy else if (phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID) 452424ca4c5SRussell King mscr = MII_88E1121_PHY_MSCR_RX_DELAY; 453c477d044SCyril Chemparathy else if (phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID) 454424ca4c5SRussell King mscr = MII_88E1121_PHY_MSCR_TX_DELAY; 455424ca4c5SRussell King else 456424ca4c5SRussell King mscr = 0; 457c477d044SCyril Chemparathy 458424ca4c5SRussell King return phy_modify_paged(phydev, MII_MARVELL_MSCR_PAGE, 459424ca4c5SRussell King MII_88E1121_PHY_MSCR_REG, 460424ca4c5SRussell King MII_88E1121_PHY_MSCR_DELAY_MASK, mscr); 461be8c6480SArnaud Patard } 462c477d044SCyril Chemparathy 463864dc729SAndrew Lunn static int m88e1121_config_aneg(struct phy_device *phydev) 464864dc729SAndrew Lunn { 465d6ab9336SFlorian Fainelli int changed = 0; 466864dc729SAndrew Lunn int err = 0; 467864dc729SAndrew Lunn 468864dc729SAndrew Lunn if (phy_interface_is_rgmii(phydev)) { 469864dc729SAndrew Lunn err = m88e1121_config_aneg_rgmii_delays(phydev); 470fea23fb5SRussell King if (err < 0) 471864dc729SAndrew Lunn return err; 472864dc729SAndrew Lunn } 473140bc929SSergei Poselenov 474fecd5e91SAndrew Lunn err = marvell_set_polarity(phydev, phydev->mdix_ctrl); 475140bc929SSergei Poselenov if (err < 0) 476140bc929SSergei Poselenov return err; 477140bc929SSergei Poselenov 478d6ab9336SFlorian Fainelli changed = err; 479d6ab9336SFlorian Fainelli 480d6ab9336SFlorian Fainelli err = genphy_config_aneg(phydev); 481d6ab9336SFlorian Fainelli if (err < 0) 482d6ab9336SFlorian Fainelli return err; 483d6ab9336SFlorian Fainelli 4844b1bd697SDavid S. Miller if (phydev->autoneg != AUTONEG_ENABLE || changed) { 485d6ab9336SFlorian Fainelli /* A software reset is used to ensure a "commit" of the 486d6ab9336SFlorian Fainelli * changes is done. 487d6ab9336SFlorian Fainelli */ 488d6ab9336SFlorian Fainelli err = genphy_soft_reset(phydev); 489d6ab9336SFlorian Fainelli if (err < 0) 490d6ab9336SFlorian Fainelli return err; 491d6ab9336SFlorian Fainelli } 492d6ab9336SFlorian Fainelli 493d6ab9336SFlorian Fainelli return 0; 494140bc929SSergei Poselenov } 495140bc929SSergei Poselenov 496337ac9d5SCyril Chemparathy static int m88e1318_config_aneg(struct phy_device *phydev) 4973ff1c259SCyril Chemparathy { 498424ca4c5SRussell King int err; 4993ff1c259SCyril Chemparathy 500424ca4c5SRussell King err = phy_modify_paged(phydev, MII_MARVELL_MSCR_PAGE, 501424ca4c5SRussell King MII_88E1318S_PHY_MSCR1_REG, 502424ca4c5SRussell King 0, MII_88E1318S_PHY_MSCR1_PAD_ODD); 5033ff1c259SCyril Chemparathy if (err < 0) 5043ff1c259SCyril Chemparathy return err; 5053ff1c259SCyril Chemparathy 5063ff1c259SCyril Chemparathy return m88e1121_config_aneg(phydev); 5073ff1c259SCyril Chemparathy } 5083ff1c259SCyril Chemparathy 50978301ebeSCharles-Antoine Couret /** 5103c1bcc86SAndrew Lunn * linkmode_adv_to_fiber_adv_t 5113c1bcc86SAndrew Lunn * @advertise: the linkmode advertisement settings 51278301ebeSCharles-Antoine Couret * 5133c1bcc86SAndrew Lunn * A small helper function that translates linkmode advertisement 5143c1bcc86SAndrew Lunn * settings to phy autonegotiation advertisements for the MII_ADV 5153c1bcc86SAndrew Lunn * register for fiber link. 51678301ebeSCharles-Antoine Couret */ 5173c1bcc86SAndrew Lunn static inline u32 linkmode_adv_to_fiber_adv_t(unsigned long *advertise) 51878301ebeSCharles-Antoine Couret { 51978301ebeSCharles-Antoine Couret u32 result = 0; 52078301ebeSCharles-Antoine Couret 5213c1bcc86SAndrew Lunn if (linkmode_test_bit(ETHTOOL_LINK_MODE_1000baseT_Half_BIT, advertise)) 52220ecf424SRussell King result |= ADVERTISE_1000XHALF; 5233c1bcc86SAndrew Lunn if (linkmode_test_bit(ETHTOOL_LINK_MODE_1000baseT_Full_BIT, advertise)) 52420ecf424SRussell King result |= ADVERTISE_1000XFULL; 52578301ebeSCharles-Antoine Couret 5263c1bcc86SAndrew Lunn if (linkmode_test_bit(ETHTOOL_LINK_MODE_Asym_Pause_BIT, advertise) && 5273c1bcc86SAndrew Lunn linkmode_test_bit(ETHTOOL_LINK_MODE_Pause_BIT, advertise)) 52820ecf424SRussell King result |= ADVERTISE_1000XPSE_ASYM; 5293c1bcc86SAndrew Lunn else if (linkmode_test_bit(ETHTOOL_LINK_MODE_Pause_BIT, advertise)) 53020ecf424SRussell King result |= ADVERTISE_1000XPAUSE; 53178301ebeSCharles-Antoine Couret 53278301ebeSCharles-Antoine Couret return result; 53378301ebeSCharles-Antoine Couret } 53478301ebeSCharles-Antoine Couret 53578301ebeSCharles-Antoine Couret /** 53678301ebeSCharles-Antoine Couret * marvell_config_aneg_fiber - restart auto-negotiation or write BMCR 53778301ebeSCharles-Antoine Couret * @phydev: target phy_device struct 53878301ebeSCharles-Antoine Couret * 53978301ebeSCharles-Antoine Couret * Description: If auto-negotiation is enabled, we configure the 54078301ebeSCharles-Antoine Couret * advertising, and then restart auto-negotiation. If it is not 54178301ebeSCharles-Antoine Couret * enabled, then we write the BMCR. Adapted for fiber link in 54278301ebeSCharles-Antoine Couret * some Marvell's devices. 54378301ebeSCharles-Antoine Couret */ 54478301ebeSCharles-Antoine Couret static int marvell_config_aneg_fiber(struct phy_device *phydev) 54578301ebeSCharles-Antoine Couret { 54678301ebeSCharles-Antoine Couret int changed = 0; 54778301ebeSCharles-Antoine Couret int err; 5489f4bae70SRussell King u16 adv; 54978301ebeSCharles-Antoine Couret 55078301ebeSCharles-Antoine Couret if (phydev->autoneg != AUTONEG_ENABLE) 55178301ebeSCharles-Antoine Couret return genphy_setup_forced(phydev); 55278301ebeSCharles-Antoine Couret 55378301ebeSCharles-Antoine Couret /* Only allow advertising what this PHY supports */ 5543c1bcc86SAndrew Lunn linkmode_and(phydev->advertising, phydev->advertising, 5553c1bcc86SAndrew Lunn phydev->supported); 55678301ebeSCharles-Antoine Couret 5579f4bae70SRussell King adv = linkmode_adv_to_fiber_adv_t(phydev->advertising); 5589f4bae70SRussell King 55978301ebeSCharles-Antoine Couret /* Setup fiber advertisement */ 5609f4bae70SRussell King err = phy_modify_changed(phydev, MII_ADVERTISE, 5619f4bae70SRussell King ADVERTISE_1000XHALF | ADVERTISE_1000XFULL | 5629f4bae70SRussell King ADVERTISE_1000XPAUSE | ADVERTISE_1000XPSE_ASYM, 5639f4bae70SRussell King adv); 56478301ebeSCharles-Antoine Couret if (err < 0) 56578301ebeSCharles-Antoine Couret return err; 5669f4bae70SRussell King if (err > 0) 56778301ebeSCharles-Antoine Couret changed = 1; 56878301ebeSCharles-Antoine Couret 569b5abac2dSRussell King return genphy_check_and_restart_aneg(phydev, changed); 57078301ebeSCharles-Antoine Couret } 57178301ebeSCharles-Antoine Couret 57210e24caaSMichal Simek static int m88e1510_config_aneg(struct phy_device *phydev) 57310e24caaSMichal Simek { 57410e24caaSMichal Simek int err; 57510e24caaSMichal Simek 57652295666SAndrew Lunn err = marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE); 57778301ebeSCharles-Antoine Couret if (err < 0) 57878301ebeSCharles-Antoine Couret goto error; 57978301ebeSCharles-Antoine Couret 58078301ebeSCharles-Antoine Couret /* Configure the copper link first */ 58110e24caaSMichal Simek err = m88e1318_config_aneg(phydev); 58210e24caaSMichal Simek if (err < 0) 58378301ebeSCharles-Antoine Couret goto error; 58410e24caaSMichal Simek 585de9c4e06SRussell King /* Do not touch the fiber page if we're in copper->sgmii mode */ 586de9c4e06SRussell King if (phydev->interface == PHY_INTERFACE_MODE_SGMII) 587de9c4e06SRussell King return 0; 588de9c4e06SRussell King 58978301ebeSCharles-Antoine Couret /* Then the fiber link */ 59052295666SAndrew Lunn err = marvell_set_page(phydev, MII_MARVELL_FIBER_PAGE); 59178301ebeSCharles-Antoine Couret if (err < 0) 59278301ebeSCharles-Antoine Couret goto error; 59378301ebeSCharles-Antoine Couret 59478301ebeSCharles-Antoine Couret err = marvell_config_aneg_fiber(phydev); 59578301ebeSCharles-Antoine Couret if (err < 0) 59678301ebeSCharles-Antoine Couret goto error; 59778301ebeSCharles-Antoine Couret 59852295666SAndrew Lunn return marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE); 59978301ebeSCharles-Antoine Couret 60078301ebeSCharles-Antoine Couret error: 60152295666SAndrew Lunn marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE); 60278301ebeSCharles-Antoine Couret return err; 60379be1a1cSClemens Gruber } 60479be1a1cSClemens Gruber 60507777246SWang Dongsheng static void marvell_config_led(struct phy_device *phydev) 60607777246SWang Dongsheng { 60707777246SWang Dongsheng u16 def_config; 60807777246SWang Dongsheng int err; 60907777246SWang Dongsheng 61007777246SWang Dongsheng switch (MARVELL_PHY_FAMILY_ID(phydev->phy_id)) { 61107777246SWang Dongsheng /* Default PHY LED config: LED[0] .. Link, LED[1] .. Activity */ 61207777246SWang Dongsheng case MARVELL_PHY_FAMILY_ID(MARVELL_PHY_ID_88E1121R): 61307777246SWang Dongsheng case MARVELL_PHY_FAMILY_ID(MARVELL_PHY_ID_88E1318S): 61407777246SWang Dongsheng def_config = MII_88E1121_PHY_LED_DEF; 61507777246SWang Dongsheng break; 61607777246SWang Dongsheng /* Default PHY LED config: 61707777246SWang Dongsheng * LED[0] .. 1000Mbps Link 61807777246SWang Dongsheng * LED[1] .. 100Mbps Link 61907777246SWang Dongsheng * LED[2] .. Blink, Activity 62007777246SWang Dongsheng */ 62107777246SWang Dongsheng case MARVELL_PHY_FAMILY_ID(MARVELL_PHY_ID_88E1510): 622a93f7fe1SJian Shen if (phydev->dev_flags & MARVELL_PHY_LED0_LINK_LED1_ACTIVE) 623a93f7fe1SJian Shen def_config = MII_88E1510_PHY_LED0_LINK_LED1_ACTIVE; 624a93f7fe1SJian Shen else 62507777246SWang Dongsheng def_config = MII_88E1510_PHY_LED_DEF; 62607777246SWang Dongsheng break; 62707777246SWang Dongsheng default: 62807777246SWang Dongsheng return; 62907777246SWang Dongsheng } 63007777246SWang Dongsheng 63107777246SWang Dongsheng err = phy_write_paged(phydev, MII_MARVELL_LED_PAGE, MII_PHY_LED_CTRL, 63207777246SWang Dongsheng def_config); 63307777246SWang Dongsheng if (err < 0) 634ab2a605fSAndrew Lunn phydev_warn(phydev, "Fail to config marvell phy LED.\n"); 63507777246SWang Dongsheng } 63607777246SWang Dongsheng 63779be1a1cSClemens Gruber static int marvell_config_init(struct phy_device *phydev) 63879be1a1cSClemens Gruber { 63907777246SWang Dongsheng /* Set defalut LED */ 64007777246SWang Dongsheng marvell_config_led(phydev); 64107777246SWang Dongsheng 64279be1a1cSClemens Gruber /* Set registers from marvell,reg-init DT property */ 64310e24caaSMichal Simek return marvell_of_reg_init(phydev); 64410e24caaSMichal Simek } 64510e24caaSMichal Simek 6466b358aedSSebastian Hesselbarth static int m88e3016_config_init(struct phy_device *phydev) 6476b358aedSSebastian Hesselbarth { 648fea23fb5SRussell King int ret; 6496b358aedSSebastian Hesselbarth 6506b358aedSSebastian Hesselbarth /* Enable Scrambler and Auto-Crossover */ 651fea23fb5SRussell King ret = phy_modify(phydev, MII_88E3016_PHY_SPEC_CTRL, 652f102852fSRussell King MII_88E3016_DISABLE_SCRAMBLER, 653fea23fb5SRussell King MII_88E3016_AUTO_MDIX_CROSSOVER); 654fea23fb5SRussell King if (ret < 0) 655fea23fb5SRussell King return ret; 6566b358aedSSebastian Hesselbarth 65779be1a1cSClemens Gruber return marvell_config_init(phydev); 6586b358aedSSebastian Hesselbarth } 6596b358aedSSebastian Hesselbarth 660865b813aSAndrew Lunn static int m88e1111_config_init_hwcfg_mode(struct phy_device *phydev, 661865b813aSAndrew Lunn u16 mode, 662865b813aSAndrew Lunn int fibre_copper_auto) 663865b813aSAndrew Lunn { 664865b813aSAndrew Lunn if (fibre_copper_auto) 665fea23fb5SRussell King mode |= MII_M1111_HWCFG_FIBER_COPPER_AUTO; 666865b813aSAndrew Lunn 667fea23fb5SRussell King return phy_modify(phydev, MII_M1111_PHY_EXT_SR, 668f102852fSRussell King MII_M1111_HWCFG_MODE_MASK | 669fea23fb5SRussell King MII_M1111_HWCFG_FIBER_COPPER_AUTO | 670f102852fSRussell King MII_M1111_HWCFG_FIBER_COPPER_RES, 671fea23fb5SRussell King mode); 672865b813aSAndrew Lunn } 673865b813aSAndrew Lunn 67461111598SAndrew Lunn static int m88e1111_config_init_rgmii_delays(struct phy_device *phydev) 675895ee682SKim Phillips { 676fea23fb5SRussell King int delay; 677895ee682SKim Phillips 6789daf5a76SKim Phillips if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID) { 679fea23fb5SRussell King delay = MII_M1111_RGMII_RX_DELAY | MII_M1111_RGMII_TX_DELAY; 6809daf5a76SKim Phillips } else if (phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID) { 681fea23fb5SRussell King delay = MII_M1111_RGMII_RX_DELAY; 6829daf5a76SKim Phillips } else if (phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID) { 683fea23fb5SRussell King delay = MII_M1111_RGMII_TX_DELAY; 684fea23fb5SRussell King } else { 685fea23fb5SRussell King delay = 0; 6869daf5a76SKim Phillips } 687895ee682SKim Phillips 688fea23fb5SRussell King return phy_modify(phydev, MII_M1111_PHY_EXT_CR, 689f102852fSRussell King MII_M1111_RGMII_RX_DELAY | MII_M1111_RGMII_TX_DELAY, 690fea23fb5SRussell King delay); 69161111598SAndrew Lunn } 69261111598SAndrew Lunn 69361111598SAndrew Lunn static int m88e1111_config_init_rgmii(struct phy_device *phydev) 69461111598SAndrew Lunn { 69561111598SAndrew Lunn int temp; 69661111598SAndrew Lunn int err; 69761111598SAndrew Lunn 69861111598SAndrew Lunn err = m88e1111_config_init_rgmii_delays(phydev); 699895ee682SKim Phillips if (err < 0) 700895ee682SKim Phillips return err; 701895ee682SKim Phillips 702895ee682SKim Phillips temp = phy_read(phydev, MII_M1111_PHY_EXT_SR); 703895ee682SKim Phillips if (temp < 0) 704895ee682SKim Phillips return temp; 705895ee682SKim Phillips 706895ee682SKim Phillips temp &= ~(MII_M1111_HWCFG_MODE_MASK); 707be937f1fSAlexandr Smirnov 7087239016dSWang Jian if (temp & MII_M1111_HWCFG_FIBER_COPPER_RES) 709be937f1fSAlexandr Smirnov temp |= MII_M1111_HWCFG_MODE_FIBER_RGMII; 710be937f1fSAlexandr Smirnov else 711be937f1fSAlexandr Smirnov temp |= MII_M1111_HWCFG_MODE_COPPER_RGMII; 712895ee682SKim Phillips 713e1dde8dcSAndrew Lunn return phy_write(phydev, MII_M1111_PHY_EXT_SR, temp); 714895ee682SKim Phillips } 715895ee682SKim Phillips 716e1dde8dcSAndrew Lunn static int m88e1111_config_init_sgmii(struct phy_device *phydev) 717e1dde8dcSAndrew Lunn { 718e1dde8dcSAndrew Lunn int err; 719e1dde8dcSAndrew Lunn 720865b813aSAndrew Lunn err = m88e1111_config_init_hwcfg_mode( 721865b813aSAndrew Lunn phydev, 722865b813aSAndrew Lunn MII_M1111_HWCFG_MODE_SGMII_NO_CLK, 723865b813aSAndrew Lunn MII_M1111_HWCFG_FIBER_COPPER_AUTO); 7244117b5beSKapil Juneja if (err < 0) 7254117b5beSKapil Juneja return err; 72607151bc9SMadalin Bucur 72707151bc9SMadalin Bucur /* make sure copper is selected */ 72852295666SAndrew Lunn return marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE); 7294117b5beSKapil Juneja } 7304117b5beSKapil Juneja 731e1dde8dcSAndrew Lunn static int m88e1111_config_init_rtbi(struct phy_device *phydev) 732e1dde8dcSAndrew Lunn { 73361111598SAndrew Lunn int err; 734e1dde8dcSAndrew Lunn 73561111598SAndrew Lunn err = m88e1111_config_init_rgmii_delays(phydev); 736fea23fb5SRussell King if (err < 0) 7375f8cbc13SLiu Yu-B13201 return err; 7385f8cbc13SLiu Yu-B13201 739865b813aSAndrew Lunn err = m88e1111_config_init_hwcfg_mode( 740865b813aSAndrew Lunn phydev, 741865b813aSAndrew Lunn MII_M1111_HWCFG_MODE_RTBI, 742865b813aSAndrew Lunn MII_M1111_HWCFG_FIBER_COPPER_AUTO); 7435f8cbc13SLiu Yu-B13201 if (err < 0) 7445f8cbc13SLiu Yu-B13201 return err; 7455f8cbc13SLiu Yu-B13201 7465f8cbc13SLiu Yu-B13201 /* soft reset */ 74734386344SAndrew Lunn err = genphy_soft_reset(phydev); 7485f8cbc13SLiu Yu-B13201 if (err < 0) 7495f8cbc13SLiu Yu-B13201 return err; 750e1dde8dcSAndrew Lunn 751865b813aSAndrew Lunn return m88e1111_config_init_hwcfg_mode( 752865b813aSAndrew Lunn phydev, 753865b813aSAndrew Lunn MII_M1111_HWCFG_MODE_RTBI, 754865b813aSAndrew Lunn MII_M1111_HWCFG_FIBER_COPPER_AUTO); 755e1dde8dcSAndrew Lunn } 756e1dde8dcSAndrew Lunn 757e1dde8dcSAndrew Lunn static int m88e1111_config_init(struct phy_device *phydev) 758e1dde8dcSAndrew Lunn { 759e1dde8dcSAndrew Lunn int err; 760e1dde8dcSAndrew Lunn 761e1dde8dcSAndrew Lunn if (phy_interface_is_rgmii(phydev)) { 762e1dde8dcSAndrew Lunn err = m88e1111_config_init_rgmii(phydev); 763fea23fb5SRussell King if (err < 0) 764e1dde8dcSAndrew Lunn return err; 765e1dde8dcSAndrew Lunn } 766e1dde8dcSAndrew Lunn 767e1dde8dcSAndrew Lunn if (phydev->interface == PHY_INTERFACE_MODE_SGMII) { 768e1dde8dcSAndrew Lunn err = m88e1111_config_init_sgmii(phydev); 769e1dde8dcSAndrew Lunn if (err < 0) 770e1dde8dcSAndrew Lunn return err; 771e1dde8dcSAndrew Lunn } 772e1dde8dcSAndrew Lunn 773e1dde8dcSAndrew Lunn if (phydev->interface == PHY_INTERFACE_MODE_RTBI) { 774e1dde8dcSAndrew Lunn err = m88e1111_config_init_rtbi(phydev); 7755f8cbc13SLiu Yu-B13201 if (err < 0) 7765f8cbc13SLiu Yu-B13201 return err; 7775f8cbc13SLiu Yu-B13201 } 7785f8cbc13SLiu Yu-B13201 779cf41a51dSDavid Daney err = marvell_of_reg_init(phydev); 780cf41a51dSDavid Daney if (err < 0) 781cf41a51dSDavid Daney return err; 7825f8cbc13SLiu Yu-B13201 78334386344SAndrew Lunn return genphy_soft_reset(phydev); 784895ee682SKim Phillips } 785895ee682SKim Phillips 7865c6bc519SHeiner Kallweit static int m88e1111_get_downshift(struct phy_device *phydev, u8 *data) 7875c6bc519SHeiner Kallweit { 7885c6bc519SHeiner Kallweit int val, cnt, enable; 7895c6bc519SHeiner Kallweit 7905c6bc519SHeiner Kallweit val = phy_read(phydev, MII_M1111_PHY_EXT_CR); 7915c6bc519SHeiner Kallweit if (val < 0) 7925c6bc519SHeiner Kallweit return val; 7935c6bc519SHeiner Kallweit 7945c6bc519SHeiner Kallweit enable = FIELD_GET(MII_M1111_PHY_EXT_CR_DOWNSHIFT_EN, val); 7955c6bc519SHeiner Kallweit cnt = FIELD_GET(MII_M1111_PHY_EXT_CR_DOWNSHIFT_MASK, val) + 1; 7965c6bc519SHeiner Kallweit 7975c6bc519SHeiner Kallweit *data = enable ? cnt : DOWNSHIFT_DEV_DISABLE; 7985c6bc519SHeiner Kallweit 7995c6bc519SHeiner Kallweit return 0; 8005c6bc519SHeiner Kallweit } 8015c6bc519SHeiner Kallweit 8025c6bc519SHeiner Kallweit static int m88e1111_set_downshift(struct phy_device *phydev, u8 cnt) 8035c6bc519SHeiner Kallweit { 8045c6bc519SHeiner Kallweit int val; 8055c6bc519SHeiner Kallweit 8065c6bc519SHeiner Kallweit if (cnt > MII_M1111_PHY_EXT_CR_DOWNSHIFT_MAX) 8075c6bc519SHeiner Kallweit return -E2BIG; 8085c6bc519SHeiner Kallweit 8095c6bc519SHeiner Kallweit if (!cnt) 8105c6bc519SHeiner Kallweit return phy_clear_bits(phydev, MII_M1111_PHY_EXT_CR, 8115c6bc519SHeiner Kallweit MII_M1111_PHY_EXT_CR_DOWNSHIFT_EN); 8125c6bc519SHeiner Kallweit 8135c6bc519SHeiner Kallweit val = MII_M1111_PHY_EXT_CR_DOWNSHIFT_EN; 8145c6bc519SHeiner Kallweit val |= FIELD_PREP(MII_M1111_PHY_EXT_CR_DOWNSHIFT_MASK, cnt - 1); 8155c6bc519SHeiner Kallweit 8165c6bc519SHeiner Kallweit return phy_modify(phydev, MII_M1111_PHY_EXT_CR, 8175c6bc519SHeiner Kallweit MII_M1111_PHY_EXT_CR_DOWNSHIFT_EN | 8185c6bc519SHeiner Kallweit MII_M1111_PHY_EXT_CR_DOWNSHIFT_MASK, 8195c6bc519SHeiner Kallweit val); 8205c6bc519SHeiner Kallweit } 8215c6bc519SHeiner Kallweit 8225c6bc519SHeiner Kallweit static int m88e1111_get_tunable(struct phy_device *phydev, 8235c6bc519SHeiner Kallweit struct ethtool_tunable *tuna, void *data) 8245c6bc519SHeiner Kallweit { 8255c6bc519SHeiner Kallweit switch (tuna->id) { 8265c6bc519SHeiner Kallweit case ETHTOOL_PHY_DOWNSHIFT: 8275c6bc519SHeiner Kallweit return m88e1111_get_downshift(phydev, data); 8285c6bc519SHeiner Kallweit default: 8295c6bc519SHeiner Kallweit return -EOPNOTSUPP; 8305c6bc519SHeiner Kallweit } 8315c6bc519SHeiner Kallweit } 8325c6bc519SHeiner Kallweit 8335c6bc519SHeiner Kallweit static int m88e1111_set_tunable(struct phy_device *phydev, 8345c6bc519SHeiner Kallweit struct ethtool_tunable *tuna, const void *data) 8355c6bc519SHeiner Kallweit { 8365c6bc519SHeiner Kallweit switch (tuna->id) { 8375c6bc519SHeiner Kallweit case ETHTOOL_PHY_DOWNSHIFT: 8385c6bc519SHeiner Kallweit return m88e1111_set_downshift(phydev, *(const u8 *)data); 8395c6bc519SHeiner Kallweit default: 8405c6bc519SHeiner Kallweit return -EOPNOTSUPP; 8415c6bc519SHeiner Kallweit } 8425c6bc519SHeiner Kallweit } 8435c6bc519SHeiner Kallweit 844911af5e1SHeiner Kallweit static int m88e1011_get_downshift(struct phy_device *phydev, u8 *data) 845a3bdfce7SHeiner Kallweit { 846a3bdfce7SHeiner Kallweit int val, cnt, enable; 847a3bdfce7SHeiner Kallweit 848a3bdfce7SHeiner Kallweit val = phy_read(phydev, MII_M1011_PHY_SCR); 849a3bdfce7SHeiner Kallweit if (val < 0) 850a3bdfce7SHeiner Kallweit return val; 851a3bdfce7SHeiner Kallweit 852a3bdfce7SHeiner Kallweit enable = FIELD_GET(MII_M1011_PHY_SCR_DOWNSHIFT_EN, val); 853f8d975beSHeiner Kallweit cnt = FIELD_GET(MII_M1011_PHY_SCR_DOWNSHIFT_MASK, val) + 1; 854a3bdfce7SHeiner Kallweit 855a3bdfce7SHeiner Kallweit *data = enable ? cnt : DOWNSHIFT_DEV_DISABLE; 856a3bdfce7SHeiner Kallweit 857a3bdfce7SHeiner Kallweit return 0; 858a3bdfce7SHeiner Kallweit } 859a3bdfce7SHeiner Kallweit 860911af5e1SHeiner Kallweit static int m88e1011_set_downshift(struct phy_device *phydev, u8 cnt) 861a3bdfce7SHeiner Kallweit { 862a3bdfce7SHeiner Kallweit int val; 863a3bdfce7SHeiner Kallweit 864a3bdfce7SHeiner Kallweit if (cnt > MII_M1011_PHY_SCR_DOWNSHIFT_MAX) 865a3bdfce7SHeiner Kallweit return -E2BIG; 866a3bdfce7SHeiner Kallweit 867a3bdfce7SHeiner Kallweit if (!cnt) 868a3bdfce7SHeiner Kallweit return phy_clear_bits(phydev, MII_M1011_PHY_SCR, 869a3bdfce7SHeiner Kallweit MII_M1011_PHY_SCR_DOWNSHIFT_EN); 870a3bdfce7SHeiner Kallweit 871a3bdfce7SHeiner Kallweit val = MII_M1011_PHY_SCR_DOWNSHIFT_EN; 872f8d975beSHeiner Kallweit val |= FIELD_PREP(MII_M1011_PHY_SCR_DOWNSHIFT_MASK, cnt - 1); 873a3bdfce7SHeiner Kallweit 874a3bdfce7SHeiner Kallweit return phy_modify(phydev, MII_M1011_PHY_SCR, 875a3bdfce7SHeiner Kallweit MII_M1011_PHY_SCR_DOWNSHIFT_EN | 876f8d975beSHeiner Kallweit MII_M1011_PHY_SCR_DOWNSHIFT_MASK, 877a3bdfce7SHeiner Kallweit val); 878a3bdfce7SHeiner Kallweit } 879a3bdfce7SHeiner Kallweit 880911af5e1SHeiner Kallweit static int m88e1011_get_tunable(struct phy_device *phydev, 881a3bdfce7SHeiner Kallweit struct ethtool_tunable *tuna, void *data) 882a3bdfce7SHeiner Kallweit { 883a3bdfce7SHeiner Kallweit switch (tuna->id) { 884a3bdfce7SHeiner Kallweit case ETHTOOL_PHY_DOWNSHIFT: 885911af5e1SHeiner Kallweit return m88e1011_get_downshift(phydev, data); 886a3bdfce7SHeiner Kallweit default: 887a3bdfce7SHeiner Kallweit return -EOPNOTSUPP; 888a3bdfce7SHeiner Kallweit } 889a3bdfce7SHeiner Kallweit } 890a3bdfce7SHeiner Kallweit 891911af5e1SHeiner Kallweit static int m88e1011_set_tunable(struct phy_device *phydev, 892a3bdfce7SHeiner Kallweit struct ethtool_tunable *tuna, const void *data) 893a3bdfce7SHeiner Kallweit { 894a3bdfce7SHeiner Kallweit switch (tuna->id) { 895a3bdfce7SHeiner Kallweit case ETHTOOL_PHY_DOWNSHIFT: 896911af5e1SHeiner Kallweit return m88e1011_set_downshift(phydev, *(const u8 *)data); 897a3bdfce7SHeiner Kallweit default: 898a3bdfce7SHeiner Kallweit return -EOPNOTSUPP; 899a3bdfce7SHeiner Kallweit } 900a3bdfce7SHeiner Kallweit } 901a3bdfce7SHeiner Kallweit 902e2d861ccSHeiner Kallweit static int m88e1116r_config_init(struct phy_device *phydev) 903e2d861ccSHeiner Kallweit { 904e2d861ccSHeiner Kallweit int err; 905e2d861ccSHeiner Kallweit 906e2d861ccSHeiner Kallweit err = genphy_soft_reset(phydev); 907e2d861ccSHeiner Kallweit if (err < 0) 908e2d861ccSHeiner Kallweit return err; 909e2d861ccSHeiner Kallweit 910e2d861ccSHeiner Kallweit msleep(500); 911e2d861ccSHeiner Kallweit 912e2d861ccSHeiner Kallweit err = marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE); 913e2d861ccSHeiner Kallweit if (err < 0) 914e2d861ccSHeiner Kallweit return err; 915e2d861ccSHeiner Kallweit 916e2d861ccSHeiner Kallweit err = marvell_set_polarity(phydev, phydev->mdix_ctrl); 917e2d861ccSHeiner Kallweit if (err < 0) 918e2d861ccSHeiner Kallweit return err; 919e2d861ccSHeiner Kallweit 920911af5e1SHeiner Kallweit err = m88e1011_set_downshift(phydev, 8); 921e2d861ccSHeiner Kallweit if (err < 0) 922e2d861ccSHeiner Kallweit return err; 923e2d861ccSHeiner Kallweit 924e2d861ccSHeiner Kallweit if (phy_interface_is_rgmii(phydev)) { 925e2d861ccSHeiner Kallweit err = m88e1121_config_aneg_rgmii_delays(phydev); 926e2d861ccSHeiner Kallweit if (err < 0) 927e2d861ccSHeiner Kallweit return err; 928e2d861ccSHeiner Kallweit } 929e2d861ccSHeiner Kallweit 930e2d861ccSHeiner Kallweit err = genphy_soft_reset(phydev); 931e2d861ccSHeiner Kallweit if (err < 0) 932e2d861ccSHeiner Kallweit return err; 933e2d861ccSHeiner Kallweit 934e2d861ccSHeiner Kallweit return marvell_config_init(phydev); 935e2d861ccSHeiner Kallweit } 936e2d861ccSHeiner Kallweit 937dd9a122aSEsben Haabendal static int m88e1318_config_init(struct phy_device *phydev) 938dd9a122aSEsben Haabendal { 939dd9a122aSEsben Haabendal if (phy_interrupt_is_valid(phydev)) { 940dd9a122aSEsben Haabendal int err = phy_modify_paged( 941dd9a122aSEsben Haabendal phydev, MII_MARVELL_LED_PAGE, 942dd9a122aSEsben Haabendal MII_88E1318S_PHY_LED_TCR, 943dd9a122aSEsben Haabendal MII_88E1318S_PHY_LED_TCR_FORCE_INT, 944dd9a122aSEsben Haabendal MII_88E1318S_PHY_LED_TCR_INTn_ENABLE | 945dd9a122aSEsben Haabendal MII_88E1318S_PHY_LED_TCR_INT_ACTIVE_LOW); 946dd9a122aSEsben Haabendal if (err < 0) 947dd9a122aSEsben Haabendal return err; 948dd9a122aSEsben Haabendal } 949dd9a122aSEsben Haabendal 95007777246SWang Dongsheng return marvell_config_init(phydev); 951dd9a122aSEsben Haabendal } 952dd9a122aSEsben Haabendal 953407353ecSClemens Gruber static int m88e1510_config_init(struct phy_device *phydev) 954407353ecSClemens Gruber { 955407353ecSClemens Gruber int err; 956407353ecSClemens Gruber 957407353ecSClemens Gruber /* SGMII-to-Copper mode initialization */ 958407353ecSClemens Gruber if (phydev->interface == PHY_INTERFACE_MODE_SGMII) { 959407353ecSClemens Gruber /* Select page 18 */ 9606427bb2dSAndrew Lunn err = marvell_set_page(phydev, 18); 961407353ecSClemens Gruber if (err < 0) 962407353ecSClemens Gruber return err; 963407353ecSClemens Gruber 964407353ecSClemens Gruber /* In reg 20, write MODE[2:0] = 0x1 (SGMII to Copper) */ 965fea23fb5SRussell King err = phy_modify(phydev, MII_88E1510_GEN_CTRL_REG_1, 966f102852fSRussell King MII_88E1510_GEN_CTRL_REG_1_MODE_MASK, 967fea23fb5SRussell King MII_88E1510_GEN_CTRL_REG_1_MODE_SGMII); 968407353ecSClemens Gruber if (err < 0) 969407353ecSClemens Gruber return err; 970407353ecSClemens Gruber 971407353ecSClemens Gruber /* PHY reset is necessary after changing MODE[2:0] */ 972fea23fb5SRussell King err = phy_modify(phydev, MII_88E1510_GEN_CTRL_REG_1, 0, 973fea23fb5SRussell King MII_88E1510_GEN_CTRL_REG_1_RESET); 974407353ecSClemens Gruber if (err < 0) 975407353ecSClemens Gruber return err; 976407353ecSClemens Gruber 977407353ecSClemens Gruber /* Reset page selection */ 97852295666SAndrew Lunn err = marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE); 979407353ecSClemens Gruber if (err < 0) 980407353ecSClemens Gruber return err; 981407353ecSClemens Gruber } 982407353ecSClemens Gruber 983dd9a122aSEsben Haabendal return m88e1318_config_init(phydev); 984407353ecSClemens Gruber } 985407353ecSClemens Gruber 986605f196eSRon Madrid static int m88e1118_config_aneg(struct phy_device *phydev) 987605f196eSRon Madrid { 988605f196eSRon Madrid int err; 989605f196eSRon Madrid 99034386344SAndrew Lunn err = genphy_soft_reset(phydev); 991605f196eSRon Madrid if (err < 0) 992605f196eSRon Madrid return err; 993605f196eSRon Madrid 994fecd5e91SAndrew Lunn err = marvell_set_polarity(phydev, phydev->mdix_ctrl); 995605f196eSRon Madrid if (err < 0) 996605f196eSRon Madrid return err; 997605f196eSRon Madrid 998605f196eSRon Madrid err = genphy_config_aneg(phydev); 999605f196eSRon Madrid return 0; 1000605f196eSRon Madrid } 1001605f196eSRon Madrid 1002605f196eSRon Madrid static int m88e1118_config_init(struct phy_device *phydev) 1003605f196eSRon Madrid { 1004605f196eSRon Madrid int err; 1005605f196eSRon Madrid 1006605f196eSRon Madrid /* Change address */ 100752295666SAndrew Lunn err = marvell_set_page(phydev, MII_MARVELL_MSCR_PAGE); 1008605f196eSRon Madrid if (err < 0) 1009605f196eSRon Madrid return err; 1010605f196eSRon Madrid 1011605f196eSRon Madrid /* Enable 1000 Mbit */ 1012605f196eSRon Madrid err = phy_write(phydev, 0x15, 0x1070); 1013605f196eSRon Madrid if (err < 0) 1014605f196eSRon Madrid return err; 1015605f196eSRon Madrid 1016605f196eSRon Madrid /* Change address */ 101752295666SAndrew Lunn err = marvell_set_page(phydev, MII_MARVELL_LED_PAGE); 1018605f196eSRon Madrid if (err < 0) 1019605f196eSRon Madrid return err; 1020605f196eSRon Madrid 1021605f196eSRon Madrid /* Adjust LED Control */ 10222f495c39SBenjamin Herrenschmidt if (phydev->dev_flags & MARVELL_PHY_M1118_DNS323_LEDS) 10232f495c39SBenjamin Herrenschmidt err = phy_write(phydev, 0x10, 0x1100); 10242f495c39SBenjamin Herrenschmidt else 1025605f196eSRon Madrid err = phy_write(phydev, 0x10, 0x021e); 1026605f196eSRon Madrid if (err < 0) 1027605f196eSRon Madrid return err; 1028605f196eSRon Madrid 1029cf41a51dSDavid Daney err = marvell_of_reg_init(phydev); 1030cf41a51dSDavid Daney if (err < 0) 1031cf41a51dSDavid Daney return err; 1032cf41a51dSDavid Daney 1033605f196eSRon Madrid /* Reset address */ 103452295666SAndrew Lunn err = marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE); 1035605f196eSRon Madrid if (err < 0) 1036605f196eSRon Madrid return err; 1037605f196eSRon Madrid 103834386344SAndrew Lunn return genphy_soft_reset(phydev); 1039605f196eSRon Madrid } 1040605f196eSRon Madrid 104190600732SDavid Daney static int m88e1149_config_init(struct phy_device *phydev) 104290600732SDavid Daney { 104390600732SDavid Daney int err; 104490600732SDavid Daney 104590600732SDavid Daney /* Change address */ 104652295666SAndrew Lunn err = marvell_set_page(phydev, MII_MARVELL_MSCR_PAGE); 104790600732SDavid Daney if (err < 0) 104890600732SDavid Daney return err; 104990600732SDavid Daney 105090600732SDavid Daney /* Enable 1000 Mbit */ 105190600732SDavid Daney err = phy_write(phydev, 0x15, 0x1048); 105290600732SDavid Daney if (err < 0) 105390600732SDavid Daney return err; 105490600732SDavid Daney 1055cf41a51dSDavid Daney err = marvell_of_reg_init(phydev); 1056cf41a51dSDavid Daney if (err < 0) 1057cf41a51dSDavid Daney return err; 1058cf41a51dSDavid Daney 105990600732SDavid Daney /* Reset address */ 106052295666SAndrew Lunn err = marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE); 106190600732SDavid Daney if (err < 0) 106290600732SDavid Daney return err; 106390600732SDavid Daney 106434386344SAndrew Lunn return genphy_soft_reset(phydev); 106590600732SDavid Daney } 106690600732SDavid Daney 1067e1dde8dcSAndrew Lunn static int m88e1145_config_init_rgmii(struct phy_device *phydev) 106876884679SAndy Fleming { 106976884679SAndy Fleming int err; 1070e69d9ed4SAndrew Lunn 107161111598SAndrew Lunn err = m88e1111_config_init_rgmii_delays(phydev); 107276884679SAndy Fleming if (err < 0) 107376884679SAndy Fleming return err; 107476884679SAndy Fleming 10752f495c39SBenjamin Herrenschmidt if (phydev->dev_flags & MARVELL_PHY_M1145_FLAGS_RESISTANCE) { 107676884679SAndy Fleming err = phy_write(phydev, 0x1d, 0x0012); 107776884679SAndy Fleming if (err < 0) 107876884679SAndy Fleming return err; 107976884679SAndy Fleming 1080f102852fSRussell King err = phy_modify(phydev, 0x1e, 0x0fc0, 1081fea23fb5SRussell King 2 << 9 | /* 36 ohm */ 1082fea23fb5SRussell King 2 << 6); /* 39 ohm */ 108376884679SAndy Fleming if (err < 0) 108476884679SAndy Fleming return err; 108576884679SAndy Fleming 108676884679SAndy Fleming err = phy_write(phydev, 0x1d, 0x3); 108776884679SAndy Fleming if (err < 0) 108876884679SAndy Fleming return err; 108976884679SAndy Fleming 109076884679SAndy Fleming err = phy_write(phydev, 0x1e, 0x8000); 1091e1dde8dcSAndrew Lunn } 109276884679SAndy Fleming return err; 109376884679SAndy Fleming } 109476884679SAndy Fleming 1095e1dde8dcSAndrew Lunn static int m88e1145_config_init_sgmii(struct phy_device *phydev) 1096e1dde8dcSAndrew Lunn { 1097865b813aSAndrew Lunn return m88e1111_config_init_hwcfg_mode( 1098865b813aSAndrew Lunn phydev, MII_M1111_HWCFG_MODE_SGMII_NO_CLK, 1099865b813aSAndrew Lunn MII_M1111_HWCFG_FIBER_COPPER_AUTO); 1100e1dde8dcSAndrew Lunn } 1101e1dde8dcSAndrew Lunn 1102e1dde8dcSAndrew Lunn static int m88e1145_config_init(struct phy_device *phydev) 1103e1dde8dcSAndrew Lunn { 1104e1dde8dcSAndrew Lunn int err; 1105e1dde8dcSAndrew Lunn 1106e1dde8dcSAndrew Lunn /* Take care of errata E0 & E1 */ 1107e1dde8dcSAndrew Lunn err = phy_write(phydev, 0x1d, 0x001b); 1108e1dde8dcSAndrew Lunn if (err < 0) 1109e1dde8dcSAndrew Lunn return err; 1110e1dde8dcSAndrew Lunn 1111e1dde8dcSAndrew Lunn err = phy_write(phydev, 0x1e, 0x418f); 1112e1dde8dcSAndrew Lunn if (err < 0) 1113e1dde8dcSAndrew Lunn return err; 1114e1dde8dcSAndrew Lunn 1115e1dde8dcSAndrew Lunn err = phy_write(phydev, 0x1d, 0x0016); 1116e1dde8dcSAndrew Lunn if (err < 0) 1117e1dde8dcSAndrew Lunn return err; 1118e1dde8dcSAndrew Lunn 1119e1dde8dcSAndrew Lunn err = phy_write(phydev, 0x1e, 0xa2da); 1120e1dde8dcSAndrew Lunn if (err < 0) 1121e1dde8dcSAndrew Lunn return err; 1122e1dde8dcSAndrew Lunn 1123e1dde8dcSAndrew Lunn if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID) { 1124e1dde8dcSAndrew Lunn err = m88e1145_config_init_rgmii(phydev); 1125e1dde8dcSAndrew Lunn if (err < 0) 1126e1dde8dcSAndrew Lunn return err; 1127e1dde8dcSAndrew Lunn } 1128e1dde8dcSAndrew Lunn 1129e1dde8dcSAndrew Lunn if (phydev->interface == PHY_INTERFACE_MODE_SGMII) { 1130e1dde8dcSAndrew Lunn err = m88e1145_config_init_sgmii(phydev); 1131b0224175SViet Nga Dao if (err < 0) 1132b0224175SViet Nga Dao return err; 1133b0224175SViet Nga Dao } 1134b0224175SViet Nga Dao 1135cf41a51dSDavid Daney err = marvell_of_reg_init(phydev); 1136cf41a51dSDavid Daney if (err < 0) 1137cf41a51dSDavid Daney return err; 1138cf41a51dSDavid Daney 113976884679SAndy Fleming return 0; 114076884679SAndy Fleming } 114100db8189SAndy Fleming 114269f42be8SHeiner Kallweit static int m88e1540_get_fld(struct phy_device *phydev, u8 *msecs) 114369f42be8SHeiner Kallweit { 114469f42be8SHeiner Kallweit int val; 114569f42be8SHeiner Kallweit 114669f42be8SHeiner Kallweit val = phy_read(phydev, MII_88E1540_COPPER_CTRL3); 114769f42be8SHeiner Kallweit if (val < 0) 114869f42be8SHeiner Kallweit return val; 114969f42be8SHeiner Kallweit 115069f42be8SHeiner Kallweit if (!(val & MII_88E1540_COPPER_CTRL3_FAST_LINK_DOWN)) { 115169f42be8SHeiner Kallweit *msecs = ETHTOOL_PHY_FAST_LINK_DOWN_OFF; 115269f42be8SHeiner Kallweit return 0; 115369f42be8SHeiner Kallweit } 115469f42be8SHeiner Kallweit 115569f42be8SHeiner Kallweit val = FIELD_GET(MII_88E1540_COPPER_CTRL3_LINK_DOWN_DELAY_MASK, val); 115669f42be8SHeiner Kallweit 115769f42be8SHeiner Kallweit switch (val) { 115869f42be8SHeiner Kallweit case MII_88E1540_COPPER_CTRL3_LINK_DOWN_DELAY_00MS: 115969f42be8SHeiner Kallweit *msecs = 0; 116069f42be8SHeiner Kallweit break; 116169f42be8SHeiner Kallweit case MII_88E1540_COPPER_CTRL3_LINK_DOWN_DELAY_10MS: 116269f42be8SHeiner Kallweit *msecs = 10; 116369f42be8SHeiner Kallweit break; 116469f42be8SHeiner Kallweit case MII_88E1540_COPPER_CTRL3_LINK_DOWN_DELAY_20MS: 116569f42be8SHeiner Kallweit *msecs = 20; 116669f42be8SHeiner Kallweit break; 116769f42be8SHeiner Kallweit case MII_88E1540_COPPER_CTRL3_LINK_DOWN_DELAY_40MS: 116869f42be8SHeiner Kallweit *msecs = 40; 116969f42be8SHeiner Kallweit break; 117069f42be8SHeiner Kallweit default: 117169f42be8SHeiner Kallweit return -EINVAL; 117269f42be8SHeiner Kallweit } 117369f42be8SHeiner Kallweit 117469f42be8SHeiner Kallweit return 0; 117569f42be8SHeiner Kallweit } 117669f42be8SHeiner Kallweit 117769f42be8SHeiner Kallweit static int m88e1540_set_fld(struct phy_device *phydev, const u8 *msecs) 117869f42be8SHeiner Kallweit { 117969f42be8SHeiner Kallweit struct ethtool_eee eee; 118069f42be8SHeiner Kallweit int val, ret; 118169f42be8SHeiner Kallweit 118269f42be8SHeiner Kallweit if (*msecs == ETHTOOL_PHY_FAST_LINK_DOWN_OFF) 118369f42be8SHeiner Kallweit return phy_clear_bits(phydev, MII_88E1540_COPPER_CTRL3, 118469f42be8SHeiner Kallweit MII_88E1540_COPPER_CTRL3_FAST_LINK_DOWN); 118569f42be8SHeiner Kallweit 118669f42be8SHeiner Kallweit /* According to the Marvell data sheet EEE must be disabled for 118769f42be8SHeiner Kallweit * Fast Link Down detection to work properly 118869f42be8SHeiner Kallweit */ 118969f42be8SHeiner Kallweit ret = phy_ethtool_get_eee(phydev, &eee); 119069f42be8SHeiner Kallweit if (!ret && eee.eee_enabled) { 119169f42be8SHeiner Kallweit phydev_warn(phydev, "Fast Link Down detection requires EEE to be disabled!\n"); 119269f42be8SHeiner Kallweit return -EBUSY; 119369f42be8SHeiner Kallweit } 119469f42be8SHeiner Kallweit 119569f42be8SHeiner Kallweit if (*msecs <= 5) 119669f42be8SHeiner Kallweit val = MII_88E1540_COPPER_CTRL3_LINK_DOWN_DELAY_00MS; 119769f42be8SHeiner Kallweit else if (*msecs <= 15) 119869f42be8SHeiner Kallweit val = MII_88E1540_COPPER_CTRL3_LINK_DOWN_DELAY_10MS; 119969f42be8SHeiner Kallweit else if (*msecs <= 30) 120069f42be8SHeiner Kallweit val = MII_88E1540_COPPER_CTRL3_LINK_DOWN_DELAY_20MS; 120169f42be8SHeiner Kallweit else 120269f42be8SHeiner Kallweit val = MII_88E1540_COPPER_CTRL3_LINK_DOWN_DELAY_40MS; 120369f42be8SHeiner Kallweit 120469f42be8SHeiner Kallweit val = FIELD_PREP(MII_88E1540_COPPER_CTRL3_LINK_DOWN_DELAY_MASK, val); 120569f42be8SHeiner Kallweit 120669f42be8SHeiner Kallweit ret = phy_modify(phydev, MII_88E1540_COPPER_CTRL3, 120769f42be8SHeiner Kallweit MII_88E1540_COPPER_CTRL3_LINK_DOWN_DELAY_MASK, val); 120869f42be8SHeiner Kallweit if (ret) 120969f42be8SHeiner Kallweit return ret; 121069f42be8SHeiner Kallweit 121169f42be8SHeiner Kallweit return phy_set_bits(phydev, MII_88E1540_COPPER_CTRL3, 121269f42be8SHeiner Kallweit MII_88E1540_COPPER_CTRL3_FAST_LINK_DOWN); 121369f42be8SHeiner Kallweit } 121469f42be8SHeiner Kallweit 121569f42be8SHeiner Kallweit static int m88e1540_get_tunable(struct phy_device *phydev, 121669f42be8SHeiner Kallweit struct ethtool_tunable *tuna, void *data) 121769f42be8SHeiner Kallweit { 121869f42be8SHeiner Kallweit switch (tuna->id) { 121969f42be8SHeiner Kallweit case ETHTOOL_PHY_FAST_LINK_DOWN: 122069f42be8SHeiner Kallweit return m88e1540_get_fld(phydev, data); 1221a3bdfce7SHeiner Kallweit case ETHTOOL_PHY_DOWNSHIFT: 1222911af5e1SHeiner Kallweit return m88e1011_get_downshift(phydev, data); 122369f42be8SHeiner Kallweit default: 122469f42be8SHeiner Kallweit return -EOPNOTSUPP; 122569f42be8SHeiner Kallweit } 122669f42be8SHeiner Kallweit } 122769f42be8SHeiner Kallweit 122869f42be8SHeiner Kallweit static int m88e1540_set_tunable(struct phy_device *phydev, 122969f42be8SHeiner Kallweit struct ethtool_tunable *tuna, const void *data) 123069f42be8SHeiner Kallweit { 123169f42be8SHeiner Kallweit switch (tuna->id) { 123269f42be8SHeiner Kallweit case ETHTOOL_PHY_FAST_LINK_DOWN: 123369f42be8SHeiner Kallweit return m88e1540_set_fld(phydev, data); 1234a3bdfce7SHeiner Kallweit case ETHTOOL_PHY_DOWNSHIFT: 1235911af5e1SHeiner Kallweit return m88e1011_set_downshift(phydev, *(const u8 *)data); 123669f42be8SHeiner Kallweit default: 123769f42be8SHeiner Kallweit return -EOPNOTSUPP; 123869f42be8SHeiner Kallweit } 123969f42be8SHeiner Kallweit } 124069f42be8SHeiner Kallweit 12418cbcdc1aSAndrew Lunn /* The VOD can be out of specification on link up. Poke an 12428cbcdc1aSAndrew Lunn * undocumented register, in an undocumented page, with a magic value 12438cbcdc1aSAndrew Lunn * to fix this. 12448cbcdc1aSAndrew Lunn */ 12458cbcdc1aSAndrew Lunn static int m88e6390_errata(struct phy_device *phydev) 12468cbcdc1aSAndrew Lunn { 12478cbcdc1aSAndrew Lunn int err; 12488cbcdc1aSAndrew Lunn 12498cbcdc1aSAndrew Lunn err = phy_write(phydev, MII_BMCR, 12508cbcdc1aSAndrew Lunn BMCR_ANENABLE | BMCR_SPEED1000 | BMCR_FULLDPLX); 12518cbcdc1aSAndrew Lunn if (err) 12528cbcdc1aSAndrew Lunn return err; 12538cbcdc1aSAndrew Lunn 12548cbcdc1aSAndrew Lunn usleep_range(300, 400); 12558cbcdc1aSAndrew Lunn 12568cbcdc1aSAndrew Lunn err = phy_write_paged(phydev, 0xf8, 0x08, 0x36); 12578cbcdc1aSAndrew Lunn if (err) 12588cbcdc1aSAndrew Lunn return err; 12598cbcdc1aSAndrew Lunn 12608cbcdc1aSAndrew Lunn return genphy_soft_reset(phydev); 12618cbcdc1aSAndrew Lunn } 12628cbcdc1aSAndrew Lunn 12638cbcdc1aSAndrew Lunn static int m88e6390_config_aneg(struct phy_device *phydev) 12648cbcdc1aSAndrew Lunn { 12658cbcdc1aSAndrew Lunn int err; 12668cbcdc1aSAndrew Lunn 12678cbcdc1aSAndrew Lunn err = m88e6390_errata(phydev); 12688cbcdc1aSAndrew Lunn if (err) 12698cbcdc1aSAndrew Lunn return err; 12708cbcdc1aSAndrew Lunn 12718cbcdc1aSAndrew Lunn return m88e1510_config_aneg(phydev); 12728cbcdc1aSAndrew Lunn } 12738cbcdc1aSAndrew Lunn 12746cfb3bccSCharles-Antoine Couret /** 1275ab9cb729SAndrew Lunn * fiber_lpa_mod_linkmode_lpa_t 1276c0ec3c27SAndrew Lunn * @advertising: the linkmode advertisement settings 12776cfb3bccSCharles-Antoine Couret * @lpa: value of the MII_LPA register for fiber link 1278be937f1fSAlexandr Smirnov * 1279ab9cb729SAndrew Lunn * A small helper function that translates MII_LPA bits to linkmode LP 1280ab9cb729SAndrew Lunn * advertisement settings. Other bits in advertising are left 1281ab9cb729SAndrew Lunn * unchanged. 12826cfb3bccSCharles-Antoine Couret */ 1283ab9cb729SAndrew Lunn static void fiber_lpa_mod_linkmode_lpa_t(unsigned long *advertising, u32 lpa) 12846cfb3bccSCharles-Antoine Couret { 1285ab9cb729SAndrew Lunn linkmode_mod_bit(ETHTOOL_LINK_MODE_1000baseT_Half_BIT, 128620ecf424SRussell King advertising, lpa & LPA_1000XHALF); 1287ab9cb729SAndrew Lunn 1288ab9cb729SAndrew Lunn linkmode_mod_bit(ETHTOOL_LINK_MODE_1000baseT_Full_BIT, 128920ecf424SRussell King advertising, lpa & LPA_1000XFULL); 12906cfb3bccSCharles-Antoine Couret } 12916cfb3bccSCharles-Antoine Couret 1292e1dde8dcSAndrew Lunn static int marvell_read_status_page_an(struct phy_device *phydev, 1293d2004e27SRussell King int fiber, int status) 1294be937f1fSAlexandr Smirnov { 1295be937f1fSAlexandr Smirnov int lpa; 1296fcf1f59aSRussell King int err; 1297be937f1fSAlexandr Smirnov 12983b72f84fSClemens Gruber if (!(status & MII_M1011_PHY_STATUS_RESOLVED)) { 12993b72f84fSClemens Gruber phydev->link = 0; 13003b72f84fSClemens Gruber return 0; 13013b72f84fSClemens Gruber } 13023b72f84fSClemens Gruber 13033b72f84fSClemens Gruber if (status & MII_M1011_PHY_STATUS_FULLDUPLEX) 13043b72f84fSClemens Gruber phydev->duplex = DUPLEX_FULL; 13053b72f84fSClemens Gruber else 13063b72f84fSClemens Gruber phydev->duplex = DUPLEX_HALF; 13073b72f84fSClemens Gruber 13083b72f84fSClemens Gruber switch (status & MII_M1011_PHY_STATUS_SPD_MASK) { 13093b72f84fSClemens Gruber case MII_M1011_PHY_STATUS_1000: 13103b72f84fSClemens Gruber phydev->speed = SPEED_1000; 13113b72f84fSClemens Gruber break; 13123b72f84fSClemens Gruber 13133b72f84fSClemens Gruber case MII_M1011_PHY_STATUS_100: 13143b72f84fSClemens Gruber phydev->speed = SPEED_100; 13153b72f84fSClemens Gruber break; 13163b72f84fSClemens Gruber 13173b72f84fSClemens Gruber default: 13183b72f84fSClemens Gruber phydev->speed = SPEED_10; 13193b72f84fSClemens Gruber break; 13203b72f84fSClemens Gruber } 13213b72f84fSClemens Gruber 1322fcf1f59aSRussell King if (!fiber) { 1323fcf1f59aSRussell King err = genphy_read_lpa(phydev); 1324fcf1f59aSRussell King if (err < 0) 1325fcf1f59aSRussell King return err; 1326fcf1f59aSRussell King 1327fcf1f59aSRussell King phy_resolve_aneg_pause(phydev); 1328fcf1f59aSRussell King } else { 1329be937f1fSAlexandr Smirnov lpa = phy_read(phydev, MII_LPA); 1330be937f1fSAlexandr Smirnov if (lpa < 0) 1331be937f1fSAlexandr Smirnov return lpa; 1332be937f1fSAlexandr Smirnov 13336cfb3bccSCharles-Antoine Couret /* The fiber link is only 1000M capable */ 1334ab9cb729SAndrew Lunn fiber_lpa_mod_linkmode_lpa_t(phydev->lp_advertising, lpa); 13356cfb3bccSCharles-Antoine Couret 13366cfb3bccSCharles-Antoine Couret if (phydev->duplex == DUPLEX_FULL) { 13376cfb3bccSCharles-Antoine Couret if (!(lpa & LPA_PAUSE_FIBER)) { 13386cfb3bccSCharles-Antoine Couret phydev->pause = 0; 13396cfb3bccSCharles-Antoine Couret phydev->asym_pause = 0; 13406cfb3bccSCharles-Antoine Couret } else if ((lpa & LPA_PAUSE_ASYM_FIBER)) { 13416cfb3bccSCharles-Antoine Couret phydev->pause = 1; 13426cfb3bccSCharles-Antoine Couret phydev->asym_pause = 1; 13436cfb3bccSCharles-Antoine Couret } else { 13446cfb3bccSCharles-Antoine Couret phydev->pause = 1; 13456cfb3bccSCharles-Antoine Couret phydev->asym_pause = 0; 13466cfb3bccSCharles-Antoine Couret } 13476cfb3bccSCharles-Antoine Couret } 13486cfb3bccSCharles-Antoine Couret } 1349fcf1f59aSRussell King 1350e1dde8dcSAndrew Lunn return 0; 1351e1dde8dcSAndrew Lunn } 1352e1dde8dcSAndrew Lunn 1353e1dde8dcSAndrew Lunn /* marvell_read_status_page 1354e1dde8dcSAndrew Lunn * 1355e1dde8dcSAndrew Lunn * Description: 1356e1dde8dcSAndrew Lunn * Check the link, then figure out the current state 1357e1dde8dcSAndrew Lunn * by comparing what we advertise with what the link partner 1358e1dde8dcSAndrew Lunn * advertises. Start by checking the gigabit possibilities, 1359e1dde8dcSAndrew Lunn * then move on to 10/100. 1360e1dde8dcSAndrew Lunn */ 1361e1dde8dcSAndrew Lunn static int marvell_read_status_page(struct phy_device *phydev, int page) 1362e1dde8dcSAndrew Lunn { 1363d2004e27SRussell King int status; 1364e1dde8dcSAndrew Lunn int fiber; 1365e1dde8dcSAndrew Lunn int err; 1366e1dde8dcSAndrew Lunn 1367d2004e27SRussell King status = phy_read(phydev, MII_M1011_PHY_STATUS); 1368d2004e27SRussell King if (status < 0) 1369d2004e27SRussell King return status; 1370d2004e27SRussell King 1371d2004e27SRussell King /* Use the generic register for copper link status, 1372d2004e27SRussell King * and the PHY status register for fiber link status. 1373e1dde8dcSAndrew Lunn */ 1374d2004e27SRussell King if (page == MII_MARVELL_FIBER_PAGE) { 1375d2004e27SRussell King phydev->link = !!(status & MII_M1011_PHY_STATUS_LINK); 1376d2004e27SRussell King } else { 1377d2004e27SRussell King err = genphy_update_link(phydev); 1378d2004e27SRussell King if (err) 1379d2004e27SRussell King return err; 1380d2004e27SRussell King } 1381d2004e27SRussell King 138252295666SAndrew Lunn if (page == MII_MARVELL_FIBER_PAGE) 1383e1dde8dcSAndrew Lunn fiber = 1; 1384e1dde8dcSAndrew Lunn else 1385e1dde8dcSAndrew Lunn fiber = 0; 1386e1dde8dcSAndrew Lunn 138798f92831SRussell King linkmode_zero(phydev->lp_advertising); 138898f92831SRussell King phydev->pause = 0; 138998f92831SRussell King phydev->asym_pause = 0; 1390b82cf17fSRussell King phydev->speed = SPEED_UNKNOWN; 1391b82cf17fSRussell King phydev->duplex = DUPLEX_UNKNOWN; 139298f92831SRussell King 1393e1dde8dcSAndrew Lunn if (phydev->autoneg == AUTONEG_ENABLE) 1394d2004e27SRussell King err = marvell_read_status_page_an(phydev, fiber, status); 1395e1dde8dcSAndrew Lunn else 139698f92831SRussell King err = genphy_read_status_fixed(phydev); 1397e1dde8dcSAndrew Lunn 1398e1dde8dcSAndrew Lunn return err; 1399e1dde8dcSAndrew Lunn } 1400e1dde8dcSAndrew Lunn 14016cfb3bccSCharles-Antoine Couret /* marvell_read_status 14026cfb3bccSCharles-Antoine Couret * 14036cfb3bccSCharles-Antoine Couret * Some Marvell's phys have two modes: fiber and copper. 14046cfb3bccSCharles-Antoine Couret * Both need status checked. 14056cfb3bccSCharles-Antoine Couret * Description: 14066cfb3bccSCharles-Antoine Couret * First, check the fiber link and status. 14076cfb3bccSCharles-Antoine Couret * If the fiber link is down, check the copper link and status which 14086cfb3bccSCharles-Antoine Couret * will be the default value if both link are down. 14096cfb3bccSCharles-Antoine Couret */ 14106cfb3bccSCharles-Antoine Couret static int marvell_read_status(struct phy_device *phydev) 14116cfb3bccSCharles-Antoine Couret { 14126cfb3bccSCharles-Antoine Couret int err; 14136cfb3bccSCharles-Antoine Couret 14146cfb3bccSCharles-Antoine Couret /* Check the fiber mode first */ 14153c1bcc86SAndrew Lunn if (linkmode_test_bit(ETHTOOL_LINK_MODE_FIBRE_BIT, 14163c1bcc86SAndrew Lunn phydev->supported) && 1417a13c0652SRussell King phydev->interface != PHY_INTERFACE_MODE_SGMII) { 141852295666SAndrew Lunn err = marvell_set_page(phydev, MII_MARVELL_FIBER_PAGE); 14196cfb3bccSCharles-Antoine Couret if (err < 0) 14206cfb3bccSCharles-Antoine Couret goto error; 14216cfb3bccSCharles-Antoine Couret 142252295666SAndrew Lunn err = marvell_read_status_page(phydev, MII_MARVELL_FIBER_PAGE); 14236cfb3bccSCharles-Antoine Couret if (err < 0) 14246cfb3bccSCharles-Antoine Couret goto error; 14256cfb3bccSCharles-Antoine Couret 14260c3439bcSAndrew Lunn /* If the fiber link is up, it is the selected and 14270c3439bcSAndrew Lunn * used link. In this case, we need to stay in the 14280c3439bcSAndrew Lunn * fiber page. Please to be careful about that, avoid 14290c3439bcSAndrew Lunn * to restore Copper page in other functions which 14300c3439bcSAndrew Lunn * could break the behaviour for some fiber phy like 14310c3439bcSAndrew Lunn * 88E1512. 14320c3439bcSAndrew Lunn */ 14336cfb3bccSCharles-Antoine Couret if (phydev->link) 14346cfb3bccSCharles-Antoine Couret return 0; 14356cfb3bccSCharles-Antoine Couret 14366cfb3bccSCharles-Antoine Couret /* If fiber link is down, check and save copper mode state */ 143752295666SAndrew Lunn err = marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE); 14386cfb3bccSCharles-Antoine Couret if (err < 0) 14396cfb3bccSCharles-Antoine Couret goto error; 14406cfb3bccSCharles-Antoine Couret } 14416cfb3bccSCharles-Antoine Couret 144252295666SAndrew Lunn return marvell_read_status_page(phydev, MII_MARVELL_COPPER_PAGE); 14436cfb3bccSCharles-Antoine Couret 14446cfb3bccSCharles-Antoine Couret error: 144552295666SAndrew Lunn marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE); 14466cfb3bccSCharles-Antoine Couret return err; 14476cfb3bccSCharles-Antoine Couret } 14483758be3dSCharles-Antoine Couret 14493758be3dSCharles-Antoine Couret /* marvell_suspend 14503758be3dSCharles-Antoine Couret * 14513758be3dSCharles-Antoine Couret * Some Marvell's phys have two modes: fiber and copper. 14523758be3dSCharles-Antoine Couret * Both need to be suspended 14533758be3dSCharles-Antoine Couret */ 14543758be3dSCharles-Antoine Couret static int marvell_suspend(struct phy_device *phydev) 14553758be3dSCharles-Antoine Couret { 14563758be3dSCharles-Antoine Couret int err; 14573758be3dSCharles-Antoine Couret 14583758be3dSCharles-Antoine Couret /* Suspend the fiber mode first */ 14593c1bcc86SAndrew Lunn if (!linkmode_test_bit(ETHTOOL_LINK_MODE_FIBRE_BIT, 14603c1bcc86SAndrew Lunn phydev->supported)) { 146152295666SAndrew Lunn err = marvell_set_page(phydev, MII_MARVELL_FIBER_PAGE); 14623758be3dSCharles-Antoine Couret if (err < 0) 14633758be3dSCharles-Antoine Couret goto error; 14643758be3dSCharles-Antoine Couret 14653758be3dSCharles-Antoine Couret /* With the page set, use the generic suspend */ 14663758be3dSCharles-Antoine Couret err = genphy_suspend(phydev); 14673758be3dSCharles-Antoine Couret if (err < 0) 14683758be3dSCharles-Antoine Couret goto error; 14693758be3dSCharles-Antoine Couret 14703758be3dSCharles-Antoine Couret /* Then, the copper link */ 147152295666SAndrew Lunn err = marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE); 14723758be3dSCharles-Antoine Couret if (err < 0) 14733758be3dSCharles-Antoine Couret goto error; 14743758be3dSCharles-Antoine Couret } 14753758be3dSCharles-Antoine Couret 14763758be3dSCharles-Antoine Couret /* With the page set, use the generic suspend */ 14773758be3dSCharles-Antoine Couret return genphy_suspend(phydev); 14783758be3dSCharles-Antoine Couret 14793758be3dSCharles-Antoine Couret error: 148052295666SAndrew Lunn marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE); 14813758be3dSCharles-Antoine Couret return err; 14823758be3dSCharles-Antoine Couret } 14833758be3dSCharles-Antoine Couret 14843758be3dSCharles-Antoine Couret /* marvell_resume 14853758be3dSCharles-Antoine Couret * 14863758be3dSCharles-Antoine Couret * Some Marvell's phys have two modes: fiber and copper. 14873758be3dSCharles-Antoine Couret * Both need to be resumed 14883758be3dSCharles-Antoine Couret */ 14893758be3dSCharles-Antoine Couret static int marvell_resume(struct phy_device *phydev) 14903758be3dSCharles-Antoine Couret { 14913758be3dSCharles-Antoine Couret int err; 14923758be3dSCharles-Antoine Couret 14933758be3dSCharles-Antoine Couret /* Resume the fiber mode first */ 14943c1bcc86SAndrew Lunn if (!linkmode_test_bit(ETHTOOL_LINK_MODE_FIBRE_BIT, 14953c1bcc86SAndrew Lunn phydev->supported)) { 149652295666SAndrew Lunn err = marvell_set_page(phydev, MII_MARVELL_FIBER_PAGE); 14973758be3dSCharles-Antoine Couret if (err < 0) 14983758be3dSCharles-Antoine Couret goto error; 14993758be3dSCharles-Antoine Couret 15003758be3dSCharles-Antoine Couret /* With the page set, use the generic resume */ 15013758be3dSCharles-Antoine Couret err = genphy_resume(phydev); 15023758be3dSCharles-Antoine Couret if (err < 0) 15033758be3dSCharles-Antoine Couret goto error; 15043758be3dSCharles-Antoine Couret 15053758be3dSCharles-Antoine Couret /* Then, the copper link */ 150652295666SAndrew Lunn err = marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE); 15073758be3dSCharles-Antoine Couret if (err < 0) 15083758be3dSCharles-Antoine Couret goto error; 15093758be3dSCharles-Antoine Couret } 15103758be3dSCharles-Antoine Couret 15113758be3dSCharles-Antoine Couret /* With the page set, use the generic resume */ 15123758be3dSCharles-Antoine Couret return genphy_resume(phydev); 15133758be3dSCharles-Antoine Couret 15143758be3dSCharles-Antoine Couret error: 151552295666SAndrew Lunn marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE); 15163758be3dSCharles-Antoine Couret return err; 15173758be3dSCharles-Antoine Couret } 15183758be3dSCharles-Antoine Couret 15196b358aedSSebastian Hesselbarth static int marvell_aneg_done(struct phy_device *phydev) 15206b358aedSSebastian Hesselbarth { 15216b358aedSSebastian Hesselbarth int retval = phy_read(phydev, MII_M1011_PHY_STATUS); 1522e69d9ed4SAndrew Lunn 15236b358aedSSebastian Hesselbarth return (retval < 0) ? retval : (retval & MII_M1011_PHY_STATUS_RESOLVED); 15246b358aedSSebastian Hesselbarth } 15256b358aedSSebastian Hesselbarth 1526dcd07be3SAnatolij Gustschin static int m88e1121_did_interrupt(struct phy_device *phydev) 1527dcd07be3SAnatolij Gustschin { 1528dcd07be3SAnatolij Gustschin int imask; 1529dcd07be3SAnatolij Gustschin 1530dcd07be3SAnatolij Gustschin imask = phy_read(phydev, MII_M1011_IEVENT); 1531dcd07be3SAnatolij Gustschin 1532dcd07be3SAnatolij Gustschin if (imask & MII_M1011_IMASK_INIT) 1533dcd07be3SAnatolij Gustschin return 1; 1534dcd07be3SAnatolij Gustschin 1535dcd07be3SAnatolij Gustschin return 0; 1536dcd07be3SAnatolij Gustschin } 1537dcd07be3SAnatolij Gustschin 153823beb38fSAndrew Lunn static void m88e1318_get_wol(struct phy_device *phydev, 153923beb38fSAndrew Lunn struct ethtool_wolinfo *wol) 15403871c387SMichael Stapelberg { 1541424ca4c5SRussell King int oldpage, ret = 0; 1542424ca4c5SRussell King 15433871c387SMichael Stapelberg wol->supported = WAKE_MAGIC; 15443871c387SMichael Stapelberg wol->wolopts = 0; 15453871c387SMichael Stapelberg 1546424ca4c5SRussell King oldpage = phy_select_page(phydev, MII_MARVELL_WOL_PAGE); 1547424ca4c5SRussell King if (oldpage < 0) 1548424ca4c5SRussell King goto error; 15493871c387SMichael Stapelberg 1550424ca4c5SRussell King ret = __phy_read(phydev, MII_88E1318S_PHY_WOL_CTRL); 1551424ca4c5SRussell King if (ret & MII_88E1318S_PHY_WOL_CTRL_MAGIC_PACKET_MATCH_ENABLE) 15523871c387SMichael Stapelberg wol->wolopts |= WAKE_MAGIC; 15533871c387SMichael Stapelberg 1554424ca4c5SRussell King error: 1555424ca4c5SRussell King phy_restore_page(phydev, oldpage, ret); 15563871c387SMichael Stapelberg } 15573871c387SMichael Stapelberg 155823beb38fSAndrew Lunn static int m88e1318_set_wol(struct phy_device *phydev, 155923beb38fSAndrew Lunn struct ethtool_wolinfo *wol) 15603871c387SMichael Stapelberg { 1561424ca4c5SRussell King int err = 0, oldpage; 15623871c387SMichael Stapelberg 1563424ca4c5SRussell King oldpage = phy_save_page(phydev); 1564424ca4c5SRussell King if (oldpage < 0) 1565424ca4c5SRussell King goto error; 15663871c387SMichael Stapelberg 15673871c387SMichael Stapelberg if (wol->wolopts & WAKE_MAGIC) { 15683871c387SMichael Stapelberg /* Explicitly switch to page 0x00, just to be sure */ 1569424ca4c5SRussell King err = marvell_write_page(phydev, MII_MARVELL_COPPER_PAGE); 15703871c387SMichael Stapelberg if (err < 0) 1571424ca4c5SRussell King goto error; 15723871c387SMichael Stapelberg 1573b6a930faSJingju Hou /* If WOL event happened once, the LED[2] interrupt pin 1574b6a930faSJingju Hou * will not be cleared unless we reading the interrupt status 1575b6a930faSJingju Hou * register. If interrupts are in use, the normal interrupt 1576b6a930faSJingju Hou * handling will clear the WOL event. Clear the WOL event 1577b6a930faSJingju Hou * before enabling it if !phy_interrupt_is_valid() 1578b6a930faSJingju Hou */ 1579b6a930faSJingju Hou if (!phy_interrupt_is_valid(phydev)) 1580e0a7328fSAndrew Lunn __phy_read(phydev, MII_M1011_IEVENT); 1581b6a930faSJingju Hou 15823871c387SMichael Stapelberg /* Enable the WOL interrupt */ 1583424ca4c5SRussell King err = __phy_modify(phydev, MII_88E1318S_PHY_CSIER, 0, 1584424ca4c5SRussell King MII_88E1318S_PHY_CSIER_WOL_EIE); 15853871c387SMichael Stapelberg if (err < 0) 1586424ca4c5SRussell King goto error; 15873871c387SMichael Stapelberg 1588424ca4c5SRussell King err = marvell_write_page(phydev, MII_MARVELL_LED_PAGE); 15893871c387SMichael Stapelberg if (err < 0) 1590424ca4c5SRussell King goto error; 15913871c387SMichael Stapelberg 15923871c387SMichael Stapelberg /* Setup LED[2] as interrupt pin (active low) */ 1593424ca4c5SRussell King err = __phy_modify(phydev, MII_88E1318S_PHY_LED_TCR, 1594f102852fSRussell King MII_88E1318S_PHY_LED_TCR_FORCE_INT, 1595424ca4c5SRussell King MII_88E1318S_PHY_LED_TCR_INTn_ENABLE | 1596424ca4c5SRussell King MII_88E1318S_PHY_LED_TCR_INT_ACTIVE_LOW); 15973871c387SMichael Stapelberg if (err < 0) 1598424ca4c5SRussell King goto error; 15993871c387SMichael Stapelberg 1600424ca4c5SRussell King err = marvell_write_page(phydev, MII_MARVELL_WOL_PAGE); 16013871c387SMichael Stapelberg if (err < 0) 1602424ca4c5SRussell King goto error; 16033871c387SMichael Stapelberg 16043871c387SMichael Stapelberg /* Store the device address for the magic packet */ 1605424ca4c5SRussell King err = __phy_write(phydev, MII_88E1318S_PHY_MAGIC_PACKET_WORD2, 16063871c387SMichael Stapelberg ((phydev->attached_dev->dev_addr[5] << 8) | 16073871c387SMichael Stapelberg phydev->attached_dev->dev_addr[4])); 16083871c387SMichael Stapelberg if (err < 0) 1609424ca4c5SRussell King goto error; 1610424ca4c5SRussell King err = __phy_write(phydev, MII_88E1318S_PHY_MAGIC_PACKET_WORD1, 16113871c387SMichael Stapelberg ((phydev->attached_dev->dev_addr[3] << 8) | 16123871c387SMichael Stapelberg phydev->attached_dev->dev_addr[2])); 16133871c387SMichael Stapelberg if (err < 0) 1614424ca4c5SRussell King goto error; 1615424ca4c5SRussell King err = __phy_write(phydev, MII_88E1318S_PHY_MAGIC_PACKET_WORD0, 16163871c387SMichael Stapelberg ((phydev->attached_dev->dev_addr[1] << 8) | 16173871c387SMichael Stapelberg phydev->attached_dev->dev_addr[0])); 16183871c387SMichael Stapelberg if (err < 0) 1619424ca4c5SRussell King goto error; 16203871c387SMichael Stapelberg 16213871c387SMichael Stapelberg /* Clear WOL status and enable magic packet matching */ 1622424ca4c5SRussell King err = __phy_modify(phydev, MII_88E1318S_PHY_WOL_CTRL, 0, 1623424ca4c5SRussell King MII_88E1318S_PHY_WOL_CTRL_CLEAR_WOL_STATUS | 1624424ca4c5SRussell King MII_88E1318S_PHY_WOL_CTRL_MAGIC_PACKET_MATCH_ENABLE); 16253871c387SMichael Stapelberg if (err < 0) 1626424ca4c5SRussell King goto error; 16273871c387SMichael Stapelberg } else { 1628424ca4c5SRussell King err = marvell_write_page(phydev, MII_MARVELL_WOL_PAGE); 16293871c387SMichael Stapelberg if (err < 0) 1630424ca4c5SRussell King goto error; 16313871c387SMichael Stapelberg 16323871c387SMichael Stapelberg /* Clear WOL status and disable magic packet matching */ 1633424ca4c5SRussell King err = __phy_modify(phydev, MII_88E1318S_PHY_WOL_CTRL, 1634f102852fSRussell King MII_88E1318S_PHY_WOL_CTRL_MAGIC_PACKET_MATCH_ENABLE, 1635424ca4c5SRussell King MII_88E1318S_PHY_WOL_CTRL_CLEAR_WOL_STATUS); 16363871c387SMichael Stapelberg if (err < 0) 1637424ca4c5SRussell King goto error; 16383871c387SMichael Stapelberg } 16393871c387SMichael Stapelberg 1640424ca4c5SRussell King error: 1641424ca4c5SRussell King return phy_restore_page(phydev, oldpage, err); 16423871c387SMichael Stapelberg } 16433871c387SMichael Stapelberg 1644d2fa47d9SAndrew Lunn static int marvell_get_sset_count(struct phy_device *phydev) 1645d2fa47d9SAndrew Lunn { 16463c1bcc86SAndrew Lunn if (linkmode_test_bit(ETHTOOL_LINK_MODE_FIBRE_BIT, 16473c1bcc86SAndrew Lunn phydev->supported)) 1648d2fa47d9SAndrew Lunn return ARRAY_SIZE(marvell_hw_stats); 16492170fef7SCharles-Antoine Couret else 16502170fef7SCharles-Antoine Couret return ARRAY_SIZE(marvell_hw_stats) - NB_FIBER_STATS; 1651d2fa47d9SAndrew Lunn } 1652d2fa47d9SAndrew Lunn 1653d2fa47d9SAndrew Lunn static void marvell_get_strings(struct phy_device *phydev, u8 *data) 1654d2fa47d9SAndrew Lunn { 1655fdfdf867SAndrew Lunn int count = marvell_get_sset_count(phydev); 1656d2fa47d9SAndrew Lunn int i; 1657d2fa47d9SAndrew Lunn 1658fdfdf867SAndrew Lunn for (i = 0; i < count; i++) { 165998409b2bSFlorian Fainelli strlcpy(data + i * ETH_GSTRING_LEN, 1660d2fa47d9SAndrew Lunn marvell_hw_stats[i].string, ETH_GSTRING_LEN); 1661d2fa47d9SAndrew Lunn } 1662d2fa47d9SAndrew Lunn } 1663d2fa47d9SAndrew Lunn 1664d2fa47d9SAndrew Lunn static u64 marvell_get_stat(struct phy_device *phydev, int i) 1665d2fa47d9SAndrew Lunn { 1666d2fa47d9SAndrew Lunn struct marvell_hw_stat stat = marvell_hw_stats[i]; 1667d2fa47d9SAndrew Lunn struct marvell_priv *priv = phydev->priv; 1668424ca4c5SRussell King int val; 1669321b4d4bSAndrew Lunn u64 ret; 1670d2fa47d9SAndrew Lunn 1671424ca4c5SRussell King val = phy_read_paged(phydev, stat.page, stat.reg); 1672d2fa47d9SAndrew Lunn if (val < 0) { 16736c3442f5SJisheng Zhang ret = U64_MAX; 1674d2fa47d9SAndrew Lunn } else { 1675d2fa47d9SAndrew Lunn val = val & ((1 << stat.bits) - 1); 1676d2fa47d9SAndrew Lunn priv->stats[i] += val; 1677321b4d4bSAndrew Lunn ret = priv->stats[i]; 1678d2fa47d9SAndrew Lunn } 1679d2fa47d9SAndrew Lunn 1680321b4d4bSAndrew Lunn return ret; 1681d2fa47d9SAndrew Lunn } 1682d2fa47d9SAndrew Lunn 1683d2fa47d9SAndrew Lunn static void marvell_get_stats(struct phy_device *phydev, 1684d2fa47d9SAndrew Lunn struct ethtool_stats *stats, u64 *data) 1685d2fa47d9SAndrew Lunn { 1686fdfdf867SAndrew Lunn int count = marvell_get_sset_count(phydev); 1687d2fa47d9SAndrew Lunn int i; 1688d2fa47d9SAndrew Lunn 1689fdfdf867SAndrew Lunn for (i = 0; i < count; i++) 1690d2fa47d9SAndrew Lunn data[i] = marvell_get_stat(phydev, i); 1691d2fa47d9SAndrew Lunn } 1692d2fa47d9SAndrew Lunn 1693fc879f72SAndrew Lunn static int marvell_vct7_cable_test_start(struct phy_device *phydev) 1694fc879f72SAndrew Lunn { 1695fc879f72SAndrew Lunn int bmcr, bmsr, ret; 1696fc879f72SAndrew Lunn 1697fc879f72SAndrew Lunn /* If auto-negotiation is enabled, but not complete, the cable 1698fc879f72SAndrew Lunn * test never completes. So disable auto-neg. 1699fc879f72SAndrew Lunn */ 1700fc879f72SAndrew Lunn bmcr = phy_read(phydev, MII_BMCR); 1701fc879f72SAndrew Lunn if (bmcr < 0) 1702fc879f72SAndrew Lunn return bmcr; 1703fc879f72SAndrew Lunn 1704fc879f72SAndrew Lunn bmsr = phy_read(phydev, MII_BMSR); 1705fc879f72SAndrew Lunn 1706fc879f72SAndrew Lunn if (bmsr < 0) 1707fc879f72SAndrew Lunn return bmsr; 1708fc879f72SAndrew Lunn 1709fc879f72SAndrew Lunn if (bmcr & BMCR_ANENABLE) { 1710fc879f72SAndrew Lunn ret = phy_modify(phydev, MII_BMCR, BMCR_ANENABLE, 0); 1711fc879f72SAndrew Lunn if (ret < 0) 1712fc879f72SAndrew Lunn return ret; 1713fc879f72SAndrew Lunn ret = genphy_soft_reset(phydev); 1714fc879f72SAndrew Lunn if (ret < 0) 1715fc879f72SAndrew Lunn return ret; 1716fc879f72SAndrew Lunn } 1717fc879f72SAndrew Lunn 1718fc879f72SAndrew Lunn /* If the link is up, allow it some time to go down */ 1719fc879f72SAndrew Lunn if (bmsr & BMSR_LSTATUS) 1720fc879f72SAndrew Lunn msleep(1500); 1721fc879f72SAndrew Lunn 1722fc879f72SAndrew Lunn return phy_write_paged(phydev, MII_MARVELL_VCT7_PAGE, 1723fc879f72SAndrew Lunn MII_VCT7_CTRL, 1724fc879f72SAndrew Lunn MII_VCT7_CTRL_RUN_NOW | 1725fc879f72SAndrew Lunn MII_VCT7_CTRL_CENTIMETERS); 1726fc879f72SAndrew Lunn } 1727fc879f72SAndrew Lunn 1728fc879f72SAndrew Lunn static int marvell_vct7_distance_to_length(int distance, bool meter) 1729fc879f72SAndrew Lunn { 1730fc879f72SAndrew Lunn if (meter) 1731fc879f72SAndrew Lunn distance *= 100; 1732fc879f72SAndrew Lunn 1733fc879f72SAndrew Lunn return distance; 1734fc879f72SAndrew Lunn } 1735fc879f72SAndrew Lunn 1736fc879f72SAndrew Lunn static bool marvell_vct7_distance_valid(int result) 1737fc879f72SAndrew Lunn { 1738fc879f72SAndrew Lunn switch (result) { 1739fc879f72SAndrew Lunn case MII_VCT7_RESULTS_OPEN: 1740fc879f72SAndrew Lunn case MII_VCT7_RESULTS_SAME_SHORT: 1741fc879f72SAndrew Lunn case MII_VCT7_RESULTS_CROSS_SHORT: 1742fc879f72SAndrew Lunn return true; 1743fc879f72SAndrew Lunn } 1744fc879f72SAndrew Lunn return false; 1745fc879f72SAndrew Lunn } 1746fc879f72SAndrew Lunn 1747fc879f72SAndrew Lunn static int marvell_vct7_report_length(struct phy_device *phydev, 1748fc879f72SAndrew Lunn int pair, bool meter) 1749fc879f72SAndrew Lunn { 1750fc879f72SAndrew Lunn int length; 1751fc879f72SAndrew Lunn int ret; 1752fc879f72SAndrew Lunn 1753fc879f72SAndrew Lunn ret = phy_read_paged(phydev, MII_MARVELL_VCT7_PAGE, 1754fc879f72SAndrew Lunn MII_VCT7_PAIR_0_DISTANCE + pair); 1755fc879f72SAndrew Lunn if (ret < 0) 1756fc879f72SAndrew Lunn return ret; 1757fc879f72SAndrew Lunn 1758fc879f72SAndrew Lunn length = marvell_vct7_distance_to_length(ret, meter); 1759fc879f72SAndrew Lunn 1760fc879f72SAndrew Lunn ethnl_cable_test_fault_length(phydev, pair, length); 1761fc879f72SAndrew Lunn 1762fc879f72SAndrew Lunn return 0; 1763fc879f72SAndrew Lunn } 1764fc879f72SAndrew Lunn 1765fc879f72SAndrew Lunn static int marvell_vct7_cable_test_report_trans(int result) 1766fc879f72SAndrew Lunn { 1767fc879f72SAndrew Lunn switch (result) { 1768fc879f72SAndrew Lunn case MII_VCT7_RESULTS_OK: 1769fc879f72SAndrew Lunn return ETHTOOL_A_CABLE_RESULT_CODE_OK; 1770fc879f72SAndrew Lunn case MII_VCT7_RESULTS_OPEN: 1771fc879f72SAndrew Lunn return ETHTOOL_A_CABLE_RESULT_CODE_OPEN; 1772fc879f72SAndrew Lunn case MII_VCT7_RESULTS_SAME_SHORT: 1773fc879f72SAndrew Lunn return ETHTOOL_A_CABLE_RESULT_CODE_SAME_SHORT; 1774fc879f72SAndrew Lunn case MII_VCT7_RESULTS_CROSS_SHORT: 1775fc879f72SAndrew Lunn return ETHTOOL_A_CABLE_RESULT_CODE_CROSS_SHORT; 1776fc879f72SAndrew Lunn default: 1777fc879f72SAndrew Lunn return ETHTOOL_A_CABLE_RESULT_CODE_UNSPEC; 1778fc879f72SAndrew Lunn } 1779fc879f72SAndrew Lunn } 1780fc879f72SAndrew Lunn 1781fc879f72SAndrew Lunn static int marvell_vct7_cable_test_report(struct phy_device *phydev) 1782fc879f72SAndrew Lunn { 1783fc879f72SAndrew Lunn int pair0, pair1, pair2, pair3; 1784fc879f72SAndrew Lunn bool meter; 1785fc879f72SAndrew Lunn int ret; 1786fc879f72SAndrew Lunn 1787fc879f72SAndrew Lunn ret = phy_read_paged(phydev, MII_MARVELL_VCT7_PAGE, 1788fc879f72SAndrew Lunn MII_VCT7_RESULTS); 1789fc879f72SAndrew Lunn if (ret < 0) 1790fc879f72SAndrew Lunn return ret; 1791fc879f72SAndrew Lunn 1792fc879f72SAndrew Lunn pair3 = (ret & MII_VCT7_RESULTS_PAIR3_MASK) >> 1793fc879f72SAndrew Lunn MII_VCT7_RESULTS_PAIR3_SHIFT; 1794fc879f72SAndrew Lunn pair2 = (ret & MII_VCT7_RESULTS_PAIR2_MASK) >> 1795fc879f72SAndrew Lunn MII_VCT7_RESULTS_PAIR2_SHIFT; 1796fc879f72SAndrew Lunn pair1 = (ret & MII_VCT7_RESULTS_PAIR1_MASK) >> 1797fc879f72SAndrew Lunn MII_VCT7_RESULTS_PAIR1_SHIFT; 1798fc879f72SAndrew Lunn pair0 = (ret & MII_VCT7_RESULTS_PAIR0_MASK) >> 1799fc879f72SAndrew Lunn MII_VCT7_RESULTS_PAIR0_SHIFT; 1800fc879f72SAndrew Lunn 1801fc879f72SAndrew Lunn ethnl_cable_test_result(phydev, ETHTOOL_A_CABLE_PAIR_A, 1802fc879f72SAndrew Lunn marvell_vct7_cable_test_report_trans(pair0)); 1803fc879f72SAndrew Lunn ethnl_cable_test_result(phydev, ETHTOOL_A_CABLE_PAIR_B, 1804fc879f72SAndrew Lunn marvell_vct7_cable_test_report_trans(pair1)); 1805fc879f72SAndrew Lunn ethnl_cable_test_result(phydev, ETHTOOL_A_CABLE_PAIR_C, 1806fc879f72SAndrew Lunn marvell_vct7_cable_test_report_trans(pair2)); 1807fc879f72SAndrew Lunn ethnl_cable_test_result(phydev, ETHTOOL_A_CABLE_PAIR_D, 1808fc879f72SAndrew Lunn marvell_vct7_cable_test_report_trans(pair3)); 1809fc879f72SAndrew Lunn 1810fc879f72SAndrew Lunn ret = phy_read_paged(phydev, MII_MARVELL_VCT7_PAGE, MII_VCT7_CTRL); 1811fc879f72SAndrew Lunn if (ret < 0) 1812fc879f72SAndrew Lunn return ret; 1813fc879f72SAndrew Lunn 1814fc879f72SAndrew Lunn meter = ret & MII_VCT7_CTRL_METERS; 1815fc879f72SAndrew Lunn 1816fc879f72SAndrew Lunn if (marvell_vct7_distance_valid(pair0)) 1817fc879f72SAndrew Lunn marvell_vct7_report_length(phydev, 0, meter); 1818fc879f72SAndrew Lunn if (marvell_vct7_distance_valid(pair1)) 1819fc879f72SAndrew Lunn marvell_vct7_report_length(phydev, 1, meter); 1820fc879f72SAndrew Lunn if (marvell_vct7_distance_valid(pair2)) 1821fc879f72SAndrew Lunn marvell_vct7_report_length(phydev, 2, meter); 1822fc879f72SAndrew Lunn if (marvell_vct7_distance_valid(pair3)) 1823fc879f72SAndrew Lunn marvell_vct7_report_length(phydev, 3, meter); 1824fc879f72SAndrew Lunn 1825fc879f72SAndrew Lunn return 0; 1826fc879f72SAndrew Lunn } 1827fc879f72SAndrew Lunn 1828fc879f72SAndrew Lunn static int marvell_vct7_cable_test_get_status(struct phy_device *phydev, 1829fc879f72SAndrew Lunn bool *finished) 1830fc879f72SAndrew Lunn { 1831fc879f72SAndrew Lunn int ret; 1832fc879f72SAndrew Lunn 1833fc879f72SAndrew Lunn *finished = false; 1834fc879f72SAndrew Lunn 1835fc879f72SAndrew Lunn ret = phy_read_paged(phydev, MII_MARVELL_VCT7_PAGE, 1836fc879f72SAndrew Lunn MII_VCT7_CTRL); 1837fc879f72SAndrew Lunn 1838fc879f72SAndrew Lunn if (ret < 0) 1839fc879f72SAndrew Lunn return ret; 1840fc879f72SAndrew Lunn 1841fc879f72SAndrew Lunn if (!(ret & MII_VCT7_CTRL_IN_PROGRESS)) { 1842fc879f72SAndrew Lunn *finished = true; 1843fc879f72SAndrew Lunn 1844fc879f72SAndrew Lunn return marvell_vct7_cable_test_report(phydev); 1845fc879f72SAndrew Lunn } 1846fc879f72SAndrew Lunn 1847fc879f72SAndrew Lunn return 0; 1848fc879f72SAndrew Lunn } 1849fc879f72SAndrew Lunn 18500b04680fSAndrew Lunn #ifdef CONFIG_HWMON 18510b04680fSAndrew Lunn static int m88e1121_get_temp(struct phy_device *phydev, long *temp) 18520b04680fSAndrew Lunn { 1853975b388cSAndrew Lunn int oldpage; 1854424ca4c5SRussell King int ret = 0; 18550b04680fSAndrew Lunn int val; 18560b04680fSAndrew Lunn 18570b04680fSAndrew Lunn *temp = 0; 18580b04680fSAndrew Lunn 1859424ca4c5SRussell King oldpage = phy_select_page(phydev, MII_MARVELL_MISC_TEST_PAGE); 1860424ca4c5SRussell King if (oldpage < 0) 1861424ca4c5SRussell King goto error; 1862975b388cSAndrew Lunn 18630b04680fSAndrew Lunn /* Enable temperature sensor */ 1864424ca4c5SRussell King ret = __phy_read(phydev, MII_88E1121_MISC_TEST); 18650b04680fSAndrew Lunn if (ret < 0) 18660b04680fSAndrew Lunn goto error; 18670b04680fSAndrew Lunn 1868424ca4c5SRussell King ret = __phy_write(phydev, MII_88E1121_MISC_TEST, 18690b04680fSAndrew Lunn ret | MII_88E1121_MISC_TEST_TEMP_SENSOR_EN); 18700b04680fSAndrew Lunn if (ret < 0) 18710b04680fSAndrew Lunn goto error; 18720b04680fSAndrew Lunn 18730b04680fSAndrew Lunn /* Wait for temperature to stabilize */ 18740b04680fSAndrew Lunn usleep_range(10000, 12000); 18750b04680fSAndrew Lunn 1876424ca4c5SRussell King val = __phy_read(phydev, MII_88E1121_MISC_TEST); 18770b04680fSAndrew Lunn if (val < 0) { 18780b04680fSAndrew Lunn ret = val; 18790b04680fSAndrew Lunn goto error; 18800b04680fSAndrew Lunn } 18810b04680fSAndrew Lunn 18820b04680fSAndrew Lunn /* Disable temperature sensor */ 1883424ca4c5SRussell King ret = __phy_write(phydev, MII_88E1121_MISC_TEST, 18840b04680fSAndrew Lunn ret & ~MII_88E1121_MISC_TEST_TEMP_SENSOR_EN); 18850b04680fSAndrew Lunn if (ret < 0) 18860b04680fSAndrew Lunn goto error; 18870b04680fSAndrew Lunn 18880b04680fSAndrew Lunn *temp = ((val & MII_88E1121_MISC_TEST_TEMP_MASK) - 5) * 5000; 18890b04680fSAndrew Lunn 18900b04680fSAndrew Lunn error: 1891424ca4c5SRussell King return phy_restore_page(phydev, oldpage, ret); 18920b04680fSAndrew Lunn } 18930b04680fSAndrew Lunn 18940b04680fSAndrew Lunn static int m88e1121_hwmon_read(struct device *dev, 18950b04680fSAndrew Lunn enum hwmon_sensor_types type, 18960b04680fSAndrew Lunn u32 attr, int channel, long *temp) 18970b04680fSAndrew Lunn { 18980b04680fSAndrew Lunn struct phy_device *phydev = dev_get_drvdata(dev); 18990b04680fSAndrew Lunn int err; 19000b04680fSAndrew Lunn 19010b04680fSAndrew Lunn switch (attr) { 19020b04680fSAndrew Lunn case hwmon_temp_input: 19030b04680fSAndrew Lunn err = m88e1121_get_temp(phydev, temp); 19040b04680fSAndrew Lunn break; 19050b04680fSAndrew Lunn default: 19060b04680fSAndrew Lunn return -EOPNOTSUPP; 19070b04680fSAndrew Lunn } 19080b04680fSAndrew Lunn 19090b04680fSAndrew Lunn return err; 19100b04680fSAndrew Lunn } 19110b04680fSAndrew Lunn 19120b04680fSAndrew Lunn static umode_t m88e1121_hwmon_is_visible(const void *data, 19130b04680fSAndrew Lunn enum hwmon_sensor_types type, 19140b04680fSAndrew Lunn u32 attr, int channel) 19150b04680fSAndrew Lunn { 19160b04680fSAndrew Lunn if (type != hwmon_temp) 19170b04680fSAndrew Lunn return 0; 19180b04680fSAndrew Lunn 19190b04680fSAndrew Lunn switch (attr) { 19200b04680fSAndrew Lunn case hwmon_temp_input: 19210b04680fSAndrew Lunn return 0444; 19220b04680fSAndrew Lunn default: 19230b04680fSAndrew Lunn return 0; 19240b04680fSAndrew Lunn } 19250b04680fSAndrew Lunn } 19260b04680fSAndrew Lunn 19270b04680fSAndrew Lunn static u32 m88e1121_hwmon_chip_config[] = { 19280b04680fSAndrew Lunn HWMON_C_REGISTER_TZ, 19290b04680fSAndrew Lunn 0 19300b04680fSAndrew Lunn }; 19310b04680fSAndrew Lunn 19320b04680fSAndrew Lunn static const struct hwmon_channel_info m88e1121_hwmon_chip = { 19330b04680fSAndrew Lunn .type = hwmon_chip, 19340b04680fSAndrew Lunn .config = m88e1121_hwmon_chip_config, 19350b04680fSAndrew Lunn }; 19360b04680fSAndrew Lunn 19370b04680fSAndrew Lunn static u32 m88e1121_hwmon_temp_config[] = { 19380b04680fSAndrew Lunn HWMON_T_INPUT, 19390b04680fSAndrew Lunn 0 19400b04680fSAndrew Lunn }; 19410b04680fSAndrew Lunn 19420b04680fSAndrew Lunn static const struct hwmon_channel_info m88e1121_hwmon_temp = { 19430b04680fSAndrew Lunn .type = hwmon_temp, 19440b04680fSAndrew Lunn .config = m88e1121_hwmon_temp_config, 19450b04680fSAndrew Lunn }; 19460b04680fSAndrew Lunn 19470b04680fSAndrew Lunn static const struct hwmon_channel_info *m88e1121_hwmon_info[] = { 19480b04680fSAndrew Lunn &m88e1121_hwmon_chip, 19490b04680fSAndrew Lunn &m88e1121_hwmon_temp, 19500b04680fSAndrew Lunn NULL 19510b04680fSAndrew Lunn }; 19520b04680fSAndrew Lunn 19530b04680fSAndrew Lunn static const struct hwmon_ops m88e1121_hwmon_hwmon_ops = { 19540b04680fSAndrew Lunn .is_visible = m88e1121_hwmon_is_visible, 19550b04680fSAndrew Lunn .read = m88e1121_hwmon_read, 19560b04680fSAndrew Lunn }; 19570b04680fSAndrew Lunn 19580b04680fSAndrew Lunn static const struct hwmon_chip_info m88e1121_hwmon_chip_info = { 19590b04680fSAndrew Lunn .ops = &m88e1121_hwmon_hwmon_ops, 19600b04680fSAndrew Lunn .info = m88e1121_hwmon_info, 19610b04680fSAndrew Lunn }; 19620b04680fSAndrew Lunn 19630b04680fSAndrew Lunn static int m88e1510_get_temp(struct phy_device *phydev, long *temp) 19640b04680fSAndrew Lunn { 19650b04680fSAndrew Lunn int ret; 19660b04680fSAndrew Lunn 19670b04680fSAndrew Lunn *temp = 0; 19680b04680fSAndrew Lunn 1969424ca4c5SRussell King ret = phy_read_paged(phydev, MII_MARVELL_MISC_TEST_PAGE, 1970424ca4c5SRussell King MII_88E1510_TEMP_SENSOR); 19710b04680fSAndrew Lunn if (ret < 0) 1972424ca4c5SRussell King return ret; 19730b04680fSAndrew Lunn 19740b04680fSAndrew Lunn *temp = ((ret & MII_88E1510_TEMP_SENSOR_MASK) - 25) * 1000; 19750b04680fSAndrew Lunn 1976424ca4c5SRussell King return 0; 19770b04680fSAndrew Lunn } 19780b04680fSAndrew Lunn 1979f0a45816SColin Ian King static int m88e1510_get_temp_critical(struct phy_device *phydev, long *temp) 19800b04680fSAndrew Lunn { 19810b04680fSAndrew Lunn int ret; 19820b04680fSAndrew Lunn 19830b04680fSAndrew Lunn *temp = 0; 19840b04680fSAndrew Lunn 1985424ca4c5SRussell King ret = phy_read_paged(phydev, MII_MARVELL_MISC_TEST_PAGE, 1986424ca4c5SRussell King MII_88E1121_MISC_TEST); 19870b04680fSAndrew Lunn if (ret < 0) 1988424ca4c5SRussell King return ret; 19890b04680fSAndrew Lunn 19900b04680fSAndrew Lunn *temp = (((ret & MII_88E1510_MISC_TEST_TEMP_THRESHOLD_MASK) >> 19910b04680fSAndrew Lunn MII_88E1510_MISC_TEST_TEMP_THRESHOLD_SHIFT) * 5) - 25; 19920b04680fSAndrew Lunn /* convert to mC */ 19930b04680fSAndrew Lunn *temp *= 1000; 19940b04680fSAndrew Lunn 1995424ca4c5SRussell King return 0; 19960b04680fSAndrew Lunn } 19970b04680fSAndrew Lunn 1998f0a45816SColin Ian King static int m88e1510_set_temp_critical(struct phy_device *phydev, long temp) 19990b04680fSAndrew Lunn { 20000b04680fSAndrew Lunn temp = temp / 1000; 20010b04680fSAndrew Lunn temp = clamp_val(DIV_ROUND_CLOSEST(temp, 5) + 5, 0, 0x1f); 20020b04680fSAndrew Lunn 2003424ca4c5SRussell King return phy_modify_paged(phydev, MII_MARVELL_MISC_TEST_PAGE, 2004424ca4c5SRussell King MII_88E1121_MISC_TEST, 2005424ca4c5SRussell King MII_88E1510_MISC_TEST_TEMP_THRESHOLD_MASK, 2006424ca4c5SRussell King temp << MII_88E1510_MISC_TEST_TEMP_THRESHOLD_SHIFT); 20070b04680fSAndrew Lunn } 20080b04680fSAndrew Lunn 2009f0a45816SColin Ian King static int m88e1510_get_temp_alarm(struct phy_device *phydev, long *alarm) 20100b04680fSAndrew Lunn { 20110b04680fSAndrew Lunn int ret; 20120b04680fSAndrew Lunn 20130b04680fSAndrew Lunn *alarm = false; 20140b04680fSAndrew Lunn 2015424ca4c5SRussell King ret = phy_read_paged(phydev, MII_MARVELL_MISC_TEST_PAGE, 2016424ca4c5SRussell King MII_88E1121_MISC_TEST); 20170b04680fSAndrew Lunn if (ret < 0) 2018424ca4c5SRussell King return ret; 2019424ca4c5SRussell King 20200b04680fSAndrew Lunn *alarm = !!(ret & MII_88E1510_MISC_TEST_TEMP_IRQ); 20210b04680fSAndrew Lunn 2022424ca4c5SRussell King return 0; 20230b04680fSAndrew Lunn } 20240b04680fSAndrew Lunn 20250b04680fSAndrew Lunn static int m88e1510_hwmon_read(struct device *dev, 20260b04680fSAndrew Lunn enum hwmon_sensor_types type, 20270b04680fSAndrew Lunn u32 attr, int channel, long *temp) 20280b04680fSAndrew Lunn { 20290b04680fSAndrew Lunn struct phy_device *phydev = dev_get_drvdata(dev); 20300b04680fSAndrew Lunn int err; 20310b04680fSAndrew Lunn 20320b04680fSAndrew Lunn switch (attr) { 20330b04680fSAndrew Lunn case hwmon_temp_input: 20340b04680fSAndrew Lunn err = m88e1510_get_temp(phydev, temp); 20350b04680fSAndrew Lunn break; 20360b04680fSAndrew Lunn case hwmon_temp_crit: 20370b04680fSAndrew Lunn err = m88e1510_get_temp_critical(phydev, temp); 20380b04680fSAndrew Lunn break; 20390b04680fSAndrew Lunn case hwmon_temp_max_alarm: 20400b04680fSAndrew Lunn err = m88e1510_get_temp_alarm(phydev, temp); 20410b04680fSAndrew Lunn break; 20420b04680fSAndrew Lunn default: 20430b04680fSAndrew Lunn return -EOPNOTSUPP; 20440b04680fSAndrew Lunn } 20450b04680fSAndrew Lunn 20460b04680fSAndrew Lunn return err; 20470b04680fSAndrew Lunn } 20480b04680fSAndrew Lunn 20490b04680fSAndrew Lunn static int m88e1510_hwmon_write(struct device *dev, 20500b04680fSAndrew Lunn enum hwmon_sensor_types type, 20510b04680fSAndrew Lunn u32 attr, int channel, long temp) 20520b04680fSAndrew Lunn { 20530b04680fSAndrew Lunn struct phy_device *phydev = dev_get_drvdata(dev); 20540b04680fSAndrew Lunn int err; 20550b04680fSAndrew Lunn 20560b04680fSAndrew Lunn switch (attr) { 20570b04680fSAndrew Lunn case hwmon_temp_crit: 20580b04680fSAndrew Lunn err = m88e1510_set_temp_critical(phydev, temp); 20590b04680fSAndrew Lunn break; 20600b04680fSAndrew Lunn default: 20610b04680fSAndrew Lunn return -EOPNOTSUPP; 20620b04680fSAndrew Lunn } 20630b04680fSAndrew Lunn return err; 20640b04680fSAndrew Lunn } 20650b04680fSAndrew Lunn 20660b04680fSAndrew Lunn static umode_t m88e1510_hwmon_is_visible(const void *data, 20670b04680fSAndrew Lunn enum hwmon_sensor_types type, 20680b04680fSAndrew Lunn u32 attr, int channel) 20690b04680fSAndrew Lunn { 20700b04680fSAndrew Lunn if (type != hwmon_temp) 20710b04680fSAndrew Lunn return 0; 20720b04680fSAndrew Lunn 20730b04680fSAndrew Lunn switch (attr) { 20740b04680fSAndrew Lunn case hwmon_temp_input: 20750b04680fSAndrew Lunn case hwmon_temp_max_alarm: 20760b04680fSAndrew Lunn return 0444; 20770b04680fSAndrew Lunn case hwmon_temp_crit: 20780b04680fSAndrew Lunn return 0644; 20790b04680fSAndrew Lunn default: 20800b04680fSAndrew Lunn return 0; 20810b04680fSAndrew Lunn } 20820b04680fSAndrew Lunn } 20830b04680fSAndrew Lunn 20840b04680fSAndrew Lunn static u32 m88e1510_hwmon_temp_config[] = { 20850b04680fSAndrew Lunn HWMON_T_INPUT | HWMON_T_CRIT | HWMON_T_MAX_ALARM, 20860b04680fSAndrew Lunn 0 20870b04680fSAndrew Lunn }; 20880b04680fSAndrew Lunn 20890b04680fSAndrew Lunn static const struct hwmon_channel_info m88e1510_hwmon_temp = { 20900b04680fSAndrew Lunn .type = hwmon_temp, 20910b04680fSAndrew Lunn .config = m88e1510_hwmon_temp_config, 20920b04680fSAndrew Lunn }; 20930b04680fSAndrew Lunn 20940b04680fSAndrew Lunn static const struct hwmon_channel_info *m88e1510_hwmon_info[] = { 20950b04680fSAndrew Lunn &m88e1121_hwmon_chip, 20960b04680fSAndrew Lunn &m88e1510_hwmon_temp, 20970b04680fSAndrew Lunn NULL 20980b04680fSAndrew Lunn }; 20990b04680fSAndrew Lunn 21000b04680fSAndrew Lunn static const struct hwmon_ops m88e1510_hwmon_hwmon_ops = { 21010b04680fSAndrew Lunn .is_visible = m88e1510_hwmon_is_visible, 21020b04680fSAndrew Lunn .read = m88e1510_hwmon_read, 21030b04680fSAndrew Lunn .write = m88e1510_hwmon_write, 21040b04680fSAndrew Lunn }; 21050b04680fSAndrew Lunn 21060b04680fSAndrew Lunn static const struct hwmon_chip_info m88e1510_hwmon_chip_info = { 21070b04680fSAndrew Lunn .ops = &m88e1510_hwmon_hwmon_ops, 21080b04680fSAndrew Lunn .info = m88e1510_hwmon_info, 21090b04680fSAndrew Lunn }; 21100b04680fSAndrew Lunn 2111fee2d546SAndrew Lunn static int m88e6390_get_temp(struct phy_device *phydev, long *temp) 2112fee2d546SAndrew Lunn { 2113fee2d546SAndrew Lunn int sum = 0; 2114fee2d546SAndrew Lunn int oldpage; 2115fee2d546SAndrew Lunn int ret = 0; 2116fee2d546SAndrew Lunn int i; 2117fee2d546SAndrew Lunn 2118fee2d546SAndrew Lunn *temp = 0; 2119fee2d546SAndrew Lunn 2120fee2d546SAndrew Lunn oldpage = phy_select_page(phydev, MII_MARVELL_MISC_TEST_PAGE); 2121fee2d546SAndrew Lunn if (oldpage < 0) 2122fee2d546SAndrew Lunn goto error; 2123fee2d546SAndrew Lunn 2124fee2d546SAndrew Lunn /* Enable temperature sensor */ 2125fee2d546SAndrew Lunn ret = __phy_read(phydev, MII_88E6390_MISC_TEST); 2126fee2d546SAndrew Lunn if (ret < 0) 2127fee2d546SAndrew Lunn goto error; 2128fee2d546SAndrew Lunn 2129fee2d546SAndrew Lunn ret = ret & ~MII_88E6390_MISC_TEST_SAMPLE_MASK; 2130fee2d546SAndrew Lunn ret |= MII_88E6390_MISC_TEST_SAMPLE_ENABLE | 2131fee2d546SAndrew Lunn MII_88E6390_MISC_TEST_SAMPLE_1S; 2132fee2d546SAndrew Lunn 2133fee2d546SAndrew Lunn ret = __phy_write(phydev, MII_88E6390_MISC_TEST, ret); 2134fee2d546SAndrew Lunn if (ret < 0) 2135fee2d546SAndrew Lunn goto error; 2136fee2d546SAndrew Lunn 2137fee2d546SAndrew Lunn /* Wait for temperature to stabilize */ 2138fee2d546SAndrew Lunn usleep_range(10000, 12000); 2139fee2d546SAndrew Lunn 2140fee2d546SAndrew Lunn /* Reading the temperature sense has an errata. You need to read 2141fee2d546SAndrew Lunn * a number of times and take an average. 2142fee2d546SAndrew Lunn */ 2143fee2d546SAndrew Lunn for (i = 0; i < MII_88E6390_TEMP_SENSOR_SAMPLES; i++) { 2144fee2d546SAndrew Lunn ret = __phy_read(phydev, MII_88E6390_TEMP_SENSOR); 2145fee2d546SAndrew Lunn if (ret < 0) 2146fee2d546SAndrew Lunn goto error; 2147fee2d546SAndrew Lunn sum += ret & MII_88E6390_TEMP_SENSOR_MASK; 2148fee2d546SAndrew Lunn } 2149fee2d546SAndrew Lunn 2150fee2d546SAndrew Lunn sum /= MII_88E6390_TEMP_SENSOR_SAMPLES; 2151fee2d546SAndrew Lunn *temp = (sum - 75) * 1000; 2152fee2d546SAndrew Lunn 2153fee2d546SAndrew Lunn /* Disable temperature sensor */ 2154fee2d546SAndrew Lunn ret = __phy_read(phydev, MII_88E6390_MISC_TEST); 2155fee2d546SAndrew Lunn if (ret < 0) 2156fee2d546SAndrew Lunn goto error; 2157fee2d546SAndrew Lunn 2158fee2d546SAndrew Lunn ret = ret & ~MII_88E6390_MISC_TEST_SAMPLE_MASK; 2159fee2d546SAndrew Lunn ret |= MII_88E6390_MISC_TEST_SAMPLE_DISABLE; 2160fee2d546SAndrew Lunn 2161fee2d546SAndrew Lunn ret = __phy_write(phydev, MII_88E6390_MISC_TEST, ret); 2162fee2d546SAndrew Lunn 2163fee2d546SAndrew Lunn error: 2164fee2d546SAndrew Lunn phy_restore_page(phydev, oldpage, ret); 2165fee2d546SAndrew Lunn 2166fee2d546SAndrew Lunn return ret; 2167fee2d546SAndrew Lunn } 2168fee2d546SAndrew Lunn 2169fee2d546SAndrew Lunn static int m88e6390_hwmon_read(struct device *dev, 2170fee2d546SAndrew Lunn enum hwmon_sensor_types type, 2171fee2d546SAndrew Lunn u32 attr, int channel, long *temp) 2172fee2d546SAndrew Lunn { 2173fee2d546SAndrew Lunn struct phy_device *phydev = dev_get_drvdata(dev); 2174fee2d546SAndrew Lunn int err; 2175fee2d546SAndrew Lunn 2176fee2d546SAndrew Lunn switch (attr) { 2177fee2d546SAndrew Lunn case hwmon_temp_input: 2178fee2d546SAndrew Lunn err = m88e6390_get_temp(phydev, temp); 2179fee2d546SAndrew Lunn break; 2180fee2d546SAndrew Lunn default: 2181fee2d546SAndrew Lunn return -EOPNOTSUPP; 2182fee2d546SAndrew Lunn } 2183fee2d546SAndrew Lunn 2184fee2d546SAndrew Lunn return err; 2185fee2d546SAndrew Lunn } 2186fee2d546SAndrew Lunn 2187fee2d546SAndrew Lunn static umode_t m88e6390_hwmon_is_visible(const void *data, 2188fee2d546SAndrew Lunn enum hwmon_sensor_types type, 2189fee2d546SAndrew Lunn u32 attr, int channel) 2190fee2d546SAndrew Lunn { 2191fee2d546SAndrew Lunn if (type != hwmon_temp) 2192fee2d546SAndrew Lunn return 0; 2193fee2d546SAndrew Lunn 2194fee2d546SAndrew Lunn switch (attr) { 2195fee2d546SAndrew Lunn case hwmon_temp_input: 2196fee2d546SAndrew Lunn return 0444; 2197fee2d546SAndrew Lunn default: 2198fee2d546SAndrew Lunn return 0; 2199fee2d546SAndrew Lunn } 2200fee2d546SAndrew Lunn } 2201fee2d546SAndrew Lunn 2202fee2d546SAndrew Lunn static u32 m88e6390_hwmon_temp_config[] = { 2203fee2d546SAndrew Lunn HWMON_T_INPUT, 2204fee2d546SAndrew Lunn 0 2205fee2d546SAndrew Lunn }; 2206fee2d546SAndrew Lunn 2207fee2d546SAndrew Lunn static const struct hwmon_channel_info m88e6390_hwmon_temp = { 2208fee2d546SAndrew Lunn .type = hwmon_temp, 2209fee2d546SAndrew Lunn .config = m88e6390_hwmon_temp_config, 2210fee2d546SAndrew Lunn }; 2211fee2d546SAndrew Lunn 2212fee2d546SAndrew Lunn static const struct hwmon_channel_info *m88e6390_hwmon_info[] = { 2213fee2d546SAndrew Lunn &m88e1121_hwmon_chip, 2214fee2d546SAndrew Lunn &m88e6390_hwmon_temp, 2215fee2d546SAndrew Lunn NULL 2216fee2d546SAndrew Lunn }; 2217fee2d546SAndrew Lunn 2218fee2d546SAndrew Lunn static const struct hwmon_ops m88e6390_hwmon_hwmon_ops = { 2219fee2d546SAndrew Lunn .is_visible = m88e6390_hwmon_is_visible, 2220fee2d546SAndrew Lunn .read = m88e6390_hwmon_read, 2221fee2d546SAndrew Lunn }; 2222fee2d546SAndrew Lunn 2223fee2d546SAndrew Lunn static const struct hwmon_chip_info m88e6390_hwmon_chip_info = { 2224fee2d546SAndrew Lunn .ops = &m88e6390_hwmon_hwmon_ops, 2225fee2d546SAndrew Lunn .info = m88e6390_hwmon_info, 2226fee2d546SAndrew Lunn }; 2227fee2d546SAndrew Lunn 22280b04680fSAndrew Lunn static int marvell_hwmon_name(struct phy_device *phydev) 22290b04680fSAndrew Lunn { 22300b04680fSAndrew Lunn struct marvell_priv *priv = phydev->priv; 22310b04680fSAndrew Lunn struct device *dev = &phydev->mdio.dev; 22320b04680fSAndrew Lunn const char *devname = dev_name(dev); 22330b04680fSAndrew Lunn size_t len = strlen(devname); 22340b04680fSAndrew Lunn int i, j; 22350b04680fSAndrew Lunn 22360b04680fSAndrew Lunn priv->hwmon_name = devm_kzalloc(dev, len, GFP_KERNEL); 22370b04680fSAndrew Lunn if (!priv->hwmon_name) 22380b04680fSAndrew Lunn return -ENOMEM; 22390b04680fSAndrew Lunn 22400b04680fSAndrew Lunn for (i = j = 0; i < len && devname[i]; i++) { 22410b04680fSAndrew Lunn if (isalnum(devname[i])) 22420b04680fSAndrew Lunn priv->hwmon_name[j++] = devname[i]; 22430b04680fSAndrew Lunn } 22440b04680fSAndrew Lunn 22450b04680fSAndrew Lunn return 0; 22460b04680fSAndrew Lunn } 22470b04680fSAndrew Lunn 22480b04680fSAndrew Lunn static int marvell_hwmon_probe(struct phy_device *phydev, 22490b04680fSAndrew Lunn const struct hwmon_chip_info *chip) 22500b04680fSAndrew Lunn { 22510b04680fSAndrew Lunn struct marvell_priv *priv = phydev->priv; 22520b04680fSAndrew Lunn struct device *dev = &phydev->mdio.dev; 22530b04680fSAndrew Lunn int err; 22540b04680fSAndrew Lunn 22550b04680fSAndrew Lunn err = marvell_hwmon_name(phydev); 22560b04680fSAndrew Lunn if (err) 22570b04680fSAndrew Lunn return err; 22580b04680fSAndrew Lunn 22590b04680fSAndrew Lunn priv->hwmon_dev = devm_hwmon_device_register_with_info( 22600b04680fSAndrew Lunn dev, priv->hwmon_name, phydev, chip, NULL); 22610b04680fSAndrew Lunn 22620b04680fSAndrew Lunn return PTR_ERR_OR_ZERO(priv->hwmon_dev); 22630b04680fSAndrew Lunn } 22640b04680fSAndrew Lunn 22650b04680fSAndrew Lunn static int m88e1121_hwmon_probe(struct phy_device *phydev) 22660b04680fSAndrew Lunn { 22670b04680fSAndrew Lunn return marvell_hwmon_probe(phydev, &m88e1121_hwmon_chip_info); 22680b04680fSAndrew Lunn } 22690b04680fSAndrew Lunn 22700b04680fSAndrew Lunn static int m88e1510_hwmon_probe(struct phy_device *phydev) 22710b04680fSAndrew Lunn { 22720b04680fSAndrew Lunn return marvell_hwmon_probe(phydev, &m88e1510_hwmon_chip_info); 22730b04680fSAndrew Lunn } 2274fee2d546SAndrew Lunn 2275fee2d546SAndrew Lunn static int m88e6390_hwmon_probe(struct phy_device *phydev) 2276fee2d546SAndrew Lunn { 2277fee2d546SAndrew Lunn return marvell_hwmon_probe(phydev, &m88e6390_hwmon_chip_info); 2278fee2d546SAndrew Lunn } 22790b04680fSAndrew Lunn #else 22800b04680fSAndrew Lunn static int m88e1121_hwmon_probe(struct phy_device *phydev) 22810b04680fSAndrew Lunn { 22820b04680fSAndrew Lunn return 0; 22830b04680fSAndrew Lunn } 22840b04680fSAndrew Lunn 22850b04680fSAndrew Lunn static int m88e1510_hwmon_probe(struct phy_device *phydev) 22860b04680fSAndrew Lunn { 22870b04680fSAndrew Lunn return 0; 22880b04680fSAndrew Lunn } 2289fee2d546SAndrew Lunn 2290fee2d546SAndrew Lunn static int m88e6390_hwmon_probe(struct phy_device *phydev) 2291fee2d546SAndrew Lunn { 2292fee2d546SAndrew Lunn return 0; 2293fee2d546SAndrew Lunn } 22940b04680fSAndrew Lunn #endif 22950b04680fSAndrew Lunn 2296d2fa47d9SAndrew Lunn static int marvell_probe(struct phy_device *phydev) 2297d2fa47d9SAndrew Lunn { 2298d2fa47d9SAndrew Lunn struct marvell_priv *priv; 2299d2fa47d9SAndrew Lunn 2300e5a03bfdSAndrew Lunn priv = devm_kzalloc(&phydev->mdio.dev, sizeof(*priv), GFP_KERNEL); 2301d2fa47d9SAndrew Lunn if (!priv) 2302d2fa47d9SAndrew Lunn return -ENOMEM; 2303d2fa47d9SAndrew Lunn 2304d2fa47d9SAndrew Lunn phydev->priv = priv; 2305d2fa47d9SAndrew Lunn 2306d2fa47d9SAndrew Lunn return 0; 2307d2fa47d9SAndrew Lunn } 2308d2fa47d9SAndrew Lunn 23090b04680fSAndrew Lunn static int m88e1121_probe(struct phy_device *phydev) 23100b04680fSAndrew Lunn { 23110b04680fSAndrew Lunn int err; 23120b04680fSAndrew Lunn 23130b04680fSAndrew Lunn err = marvell_probe(phydev); 23140b04680fSAndrew Lunn if (err) 23150b04680fSAndrew Lunn return err; 23160b04680fSAndrew Lunn 23170b04680fSAndrew Lunn return m88e1121_hwmon_probe(phydev); 23180b04680fSAndrew Lunn } 23190b04680fSAndrew Lunn 23200b04680fSAndrew Lunn static int m88e1510_probe(struct phy_device *phydev) 23210b04680fSAndrew Lunn { 23220b04680fSAndrew Lunn int err; 23230b04680fSAndrew Lunn 23240b04680fSAndrew Lunn err = marvell_probe(phydev); 23250b04680fSAndrew Lunn if (err) 23260b04680fSAndrew Lunn return err; 23270b04680fSAndrew Lunn 23280b04680fSAndrew Lunn return m88e1510_hwmon_probe(phydev); 23290b04680fSAndrew Lunn } 23300b04680fSAndrew Lunn 2331fee2d546SAndrew Lunn static int m88e6390_probe(struct phy_device *phydev) 2332fee2d546SAndrew Lunn { 2333fee2d546SAndrew Lunn int err; 2334fee2d546SAndrew Lunn 2335fee2d546SAndrew Lunn err = marvell_probe(phydev); 2336fee2d546SAndrew Lunn if (err) 2337fee2d546SAndrew Lunn return err; 2338fee2d546SAndrew Lunn 2339fee2d546SAndrew Lunn return m88e6390_hwmon_probe(phydev); 2340fee2d546SAndrew Lunn } 2341fee2d546SAndrew Lunn 2342e5479239SOlof Johansson static struct phy_driver marvell_drivers[] = { 2343e5479239SOlof Johansson { 23442f495c39SBenjamin Herrenschmidt .phy_id = MARVELL_PHY_ID_88E1101, 23452f495c39SBenjamin Herrenschmidt .phy_id_mask = MARVELL_PHY_ID_MASK, 234600db8189SAndy Fleming .name = "Marvell 88E1101", 2347dcdecdcfSHeiner Kallweit /* PHY_GBIT_FEATURES */ 234818702414SArnd Bergmann .probe = marvell_probe, 234979be1a1cSClemens Gruber .config_init = &marvell_config_init, 2350f2899788SAndrew Lunn .config_aneg = &m88e1101_config_aneg, 235100db8189SAndy Fleming .ack_interrupt = &marvell_ack_interrupt, 235200db8189SAndy Fleming .config_intr = &marvell_config_intr, 23530898b448SSebastian Hesselbarth .resume = &genphy_resume, 23540898b448SSebastian Hesselbarth .suspend = &genphy_suspend, 2355424ca4c5SRussell King .read_page = marvell_read_page, 2356424ca4c5SRussell King .write_page = marvell_write_page, 2357d2fa47d9SAndrew Lunn .get_sset_count = marvell_get_sset_count, 2358d2fa47d9SAndrew Lunn .get_strings = marvell_get_strings, 2359d2fa47d9SAndrew Lunn .get_stats = marvell_get_stats, 2360e5479239SOlof Johansson }, 2361e5479239SOlof Johansson { 23622f495c39SBenjamin Herrenschmidt .phy_id = MARVELL_PHY_ID_88E1112, 23632f495c39SBenjamin Herrenschmidt .phy_id_mask = MARVELL_PHY_ID_MASK, 236485cfb534SOlof Johansson .name = "Marvell 88E1112", 2365dcdecdcfSHeiner Kallweit /* PHY_GBIT_FEATURES */ 2366d2fa47d9SAndrew Lunn .probe = marvell_probe, 236785cfb534SOlof Johansson .config_init = &m88e1111_config_init, 236885cfb534SOlof Johansson .config_aneg = &marvell_config_aneg, 236985cfb534SOlof Johansson .ack_interrupt = &marvell_ack_interrupt, 237085cfb534SOlof Johansson .config_intr = &marvell_config_intr, 23710898b448SSebastian Hesselbarth .resume = &genphy_resume, 23720898b448SSebastian Hesselbarth .suspend = &genphy_suspend, 2373424ca4c5SRussell King .read_page = marvell_read_page, 2374424ca4c5SRussell King .write_page = marvell_write_page, 2375d2fa47d9SAndrew Lunn .get_sset_count = marvell_get_sset_count, 2376d2fa47d9SAndrew Lunn .get_strings = marvell_get_strings, 2377d2fa47d9SAndrew Lunn .get_stats = marvell_get_stats, 2378262caf47SHeiner Kallweit .get_tunable = m88e1011_get_tunable, 2379262caf47SHeiner Kallweit .set_tunable = m88e1011_set_tunable, 238085cfb534SOlof Johansson }, 238185cfb534SOlof Johansson { 23822f495c39SBenjamin Herrenschmidt .phy_id = MARVELL_PHY_ID_88E1111, 23832f495c39SBenjamin Herrenschmidt .phy_id_mask = MARVELL_PHY_ID_MASK, 238476884679SAndy Fleming .name = "Marvell 88E1111", 2385dcdecdcfSHeiner Kallweit /* PHY_GBIT_FEATURES */ 2386d2fa47d9SAndrew Lunn .probe = marvell_probe, 2387e5479239SOlof Johansson .config_init = &m88e1111_config_init, 2388d6ab9336SFlorian Fainelli .config_aneg = &marvell_config_aneg, 2389be937f1fSAlexandr Smirnov .read_status = &marvell_read_status, 239076884679SAndy Fleming .ack_interrupt = &marvell_ack_interrupt, 239176884679SAndy Fleming .config_intr = &marvell_config_intr, 23920898b448SSebastian Hesselbarth .resume = &genphy_resume, 23930898b448SSebastian Hesselbarth .suspend = &genphy_suspend, 2394424ca4c5SRussell King .read_page = marvell_read_page, 2395424ca4c5SRussell King .write_page = marvell_write_page, 2396d2fa47d9SAndrew Lunn .get_sset_count = marvell_get_sset_count, 2397d2fa47d9SAndrew Lunn .get_strings = marvell_get_strings, 2398d2fa47d9SAndrew Lunn .get_stats = marvell_get_stats, 23995c6bc519SHeiner Kallweit .get_tunable = m88e1111_get_tunable, 24005c6bc519SHeiner Kallweit .set_tunable = m88e1111_set_tunable, 2401e5479239SOlof Johansson }, 2402e5479239SOlof Johansson { 24032f495c39SBenjamin Herrenschmidt .phy_id = MARVELL_PHY_ID_88E1118, 24042f495c39SBenjamin Herrenschmidt .phy_id_mask = MARVELL_PHY_ID_MASK, 2405605f196eSRon Madrid .name = "Marvell 88E1118", 2406dcdecdcfSHeiner Kallweit /* PHY_GBIT_FEATURES */ 2407d2fa47d9SAndrew Lunn .probe = marvell_probe, 2408605f196eSRon Madrid .config_init = &m88e1118_config_init, 2409605f196eSRon Madrid .config_aneg = &m88e1118_config_aneg, 2410605f196eSRon Madrid .ack_interrupt = &marvell_ack_interrupt, 2411605f196eSRon Madrid .config_intr = &marvell_config_intr, 24120898b448SSebastian Hesselbarth .resume = &genphy_resume, 24130898b448SSebastian Hesselbarth .suspend = &genphy_suspend, 2414424ca4c5SRussell King .read_page = marvell_read_page, 2415424ca4c5SRussell King .write_page = marvell_write_page, 2416d2fa47d9SAndrew Lunn .get_sset_count = marvell_get_sset_count, 2417d2fa47d9SAndrew Lunn .get_strings = marvell_get_strings, 2418d2fa47d9SAndrew Lunn .get_stats = marvell_get_stats, 2419605f196eSRon Madrid }, 2420605f196eSRon Madrid { 24212f495c39SBenjamin Herrenschmidt .phy_id = MARVELL_PHY_ID_88E1121R, 24222f495c39SBenjamin Herrenschmidt .phy_id_mask = MARVELL_PHY_ID_MASK, 2423140bc929SSergei Poselenov .name = "Marvell 88E1121R", 2424dcdecdcfSHeiner Kallweit /* PHY_GBIT_FEATURES */ 242518702414SArnd Bergmann .probe = &m88e1121_probe, 242607777246SWang Dongsheng .config_init = &marvell_config_init, 2427140bc929SSergei Poselenov .config_aneg = &m88e1121_config_aneg, 2428140bc929SSergei Poselenov .read_status = &marvell_read_status, 2429140bc929SSergei Poselenov .ack_interrupt = &marvell_ack_interrupt, 2430140bc929SSergei Poselenov .config_intr = &marvell_config_intr, 2431dcd07be3SAnatolij Gustschin .did_interrupt = &m88e1121_did_interrupt, 24320898b448SSebastian Hesselbarth .resume = &genphy_resume, 24330898b448SSebastian Hesselbarth .suspend = &genphy_suspend, 2434424ca4c5SRussell King .read_page = marvell_read_page, 2435424ca4c5SRussell King .write_page = marvell_write_page, 2436d2fa47d9SAndrew Lunn .get_sset_count = marvell_get_sset_count, 2437d2fa47d9SAndrew Lunn .get_strings = marvell_get_strings, 2438d2fa47d9SAndrew Lunn .get_stats = marvell_get_stats, 2439911af5e1SHeiner Kallweit .get_tunable = m88e1011_get_tunable, 2440911af5e1SHeiner Kallweit .set_tunable = m88e1011_set_tunable, 2441140bc929SSergei Poselenov }, 2442140bc929SSergei Poselenov { 2443337ac9d5SCyril Chemparathy .phy_id = MARVELL_PHY_ID_88E1318S, 24446ba74014SLinus Torvalds .phy_id_mask = MARVELL_PHY_ID_MASK, 2445337ac9d5SCyril Chemparathy .name = "Marvell 88E1318S", 2446dcdecdcfSHeiner Kallweit /* PHY_GBIT_FEATURES */ 2447d2fa47d9SAndrew Lunn .probe = marvell_probe, 2448dd9a122aSEsben Haabendal .config_init = &m88e1318_config_init, 2449337ac9d5SCyril Chemparathy .config_aneg = &m88e1318_config_aneg, 24503ff1c259SCyril Chemparathy .read_status = &marvell_read_status, 24513ff1c259SCyril Chemparathy .ack_interrupt = &marvell_ack_interrupt, 24523ff1c259SCyril Chemparathy .config_intr = &marvell_config_intr, 24533ff1c259SCyril Chemparathy .did_interrupt = &m88e1121_did_interrupt, 24543871c387SMichael Stapelberg .get_wol = &m88e1318_get_wol, 24553871c387SMichael Stapelberg .set_wol = &m88e1318_set_wol, 24560898b448SSebastian Hesselbarth .resume = &genphy_resume, 24570898b448SSebastian Hesselbarth .suspend = &genphy_suspend, 2458424ca4c5SRussell King .read_page = marvell_read_page, 2459424ca4c5SRussell King .write_page = marvell_write_page, 2460d2fa47d9SAndrew Lunn .get_sset_count = marvell_get_sset_count, 2461d2fa47d9SAndrew Lunn .get_strings = marvell_get_strings, 2462d2fa47d9SAndrew Lunn .get_stats = marvell_get_stats, 24633ff1c259SCyril Chemparathy }, 24643ff1c259SCyril Chemparathy { 24652f495c39SBenjamin Herrenschmidt .phy_id = MARVELL_PHY_ID_88E1145, 24662f495c39SBenjamin Herrenschmidt .phy_id_mask = MARVELL_PHY_ID_MASK, 246776884679SAndy Fleming .name = "Marvell 88E1145", 2468dcdecdcfSHeiner Kallweit /* PHY_GBIT_FEATURES */ 2469d2fa47d9SAndrew Lunn .probe = marvell_probe, 247076884679SAndy Fleming .config_init = &m88e1145_config_init, 2471c505873eSZhao Qiang .config_aneg = &m88e1101_config_aneg, 247276884679SAndy Fleming .read_status = &genphy_read_status, 247376884679SAndy Fleming .ack_interrupt = &marvell_ack_interrupt, 247476884679SAndy Fleming .config_intr = &marvell_config_intr, 24750898b448SSebastian Hesselbarth .resume = &genphy_resume, 24760898b448SSebastian Hesselbarth .suspend = &genphy_suspend, 2477424ca4c5SRussell King .read_page = marvell_read_page, 2478424ca4c5SRussell King .write_page = marvell_write_page, 2479d2fa47d9SAndrew Lunn .get_sset_count = marvell_get_sset_count, 2480d2fa47d9SAndrew Lunn .get_strings = marvell_get_strings, 2481d2fa47d9SAndrew Lunn .get_stats = marvell_get_stats, 2482a319fb52SHeiner Kallweit .get_tunable = m88e1111_get_tunable, 2483a319fb52SHeiner Kallweit .set_tunable = m88e1111_set_tunable, 2484ac8c635aSOlof Johansson }, 2485ac8c635aSOlof Johansson { 248690600732SDavid Daney .phy_id = MARVELL_PHY_ID_88E1149R, 248790600732SDavid Daney .phy_id_mask = MARVELL_PHY_ID_MASK, 248890600732SDavid Daney .name = "Marvell 88E1149R", 2489dcdecdcfSHeiner Kallweit /* PHY_GBIT_FEATURES */ 2490d2fa47d9SAndrew Lunn .probe = marvell_probe, 249190600732SDavid Daney .config_init = &m88e1149_config_init, 249290600732SDavid Daney .config_aneg = &m88e1118_config_aneg, 249390600732SDavid Daney .ack_interrupt = &marvell_ack_interrupt, 249490600732SDavid Daney .config_intr = &marvell_config_intr, 24950898b448SSebastian Hesselbarth .resume = &genphy_resume, 24960898b448SSebastian Hesselbarth .suspend = &genphy_suspend, 2497424ca4c5SRussell King .read_page = marvell_read_page, 2498424ca4c5SRussell King .write_page = marvell_write_page, 2499d2fa47d9SAndrew Lunn .get_sset_count = marvell_get_sset_count, 2500d2fa47d9SAndrew Lunn .get_strings = marvell_get_strings, 2501d2fa47d9SAndrew Lunn .get_stats = marvell_get_stats, 250290600732SDavid Daney }, 250390600732SDavid Daney { 25042f495c39SBenjamin Herrenschmidt .phy_id = MARVELL_PHY_ID_88E1240, 25052f495c39SBenjamin Herrenschmidt .phy_id_mask = MARVELL_PHY_ID_MASK, 2506ac8c635aSOlof Johansson .name = "Marvell 88E1240", 2507dcdecdcfSHeiner Kallweit /* PHY_GBIT_FEATURES */ 2508d2fa47d9SAndrew Lunn .probe = marvell_probe, 2509ac8c635aSOlof Johansson .config_init = &m88e1111_config_init, 2510ac8c635aSOlof Johansson .config_aneg = &marvell_config_aneg, 2511ac8c635aSOlof Johansson .ack_interrupt = &marvell_ack_interrupt, 2512ac8c635aSOlof Johansson .config_intr = &marvell_config_intr, 25130898b448SSebastian Hesselbarth .resume = &genphy_resume, 25140898b448SSebastian Hesselbarth .suspend = &genphy_suspend, 2515424ca4c5SRussell King .read_page = marvell_read_page, 2516424ca4c5SRussell King .write_page = marvell_write_page, 2517d2fa47d9SAndrew Lunn .get_sset_count = marvell_get_sset_count, 2518d2fa47d9SAndrew Lunn .get_strings = marvell_get_strings, 2519d2fa47d9SAndrew Lunn .get_stats = marvell_get_stats, 2520ac8c635aSOlof Johansson }, 25213da09a51SMichal Simek { 25223da09a51SMichal Simek .phy_id = MARVELL_PHY_ID_88E1116R, 25233da09a51SMichal Simek .phy_id_mask = MARVELL_PHY_ID_MASK, 25243da09a51SMichal Simek .name = "Marvell 88E1116R", 2525dcdecdcfSHeiner Kallweit /* PHY_GBIT_FEATURES */ 2526d2fa47d9SAndrew Lunn .probe = marvell_probe, 25273da09a51SMichal Simek .config_init = &m88e1116r_config_init, 25283da09a51SMichal Simek .ack_interrupt = &marvell_ack_interrupt, 25293da09a51SMichal Simek .config_intr = &marvell_config_intr, 25300898b448SSebastian Hesselbarth .resume = &genphy_resume, 25310898b448SSebastian Hesselbarth .suspend = &genphy_suspend, 2532424ca4c5SRussell King .read_page = marvell_read_page, 2533424ca4c5SRussell King .write_page = marvell_write_page, 2534d2fa47d9SAndrew Lunn .get_sset_count = marvell_get_sset_count, 2535d2fa47d9SAndrew Lunn .get_strings = marvell_get_strings, 2536d2fa47d9SAndrew Lunn .get_stats = marvell_get_stats, 2537262caf47SHeiner Kallweit .get_tunable = m88e1011_get_tunable, 2538262caf47SHeiner Kallweit .set_tunable = m88e1011_set_tunable, 25393da09a51SMichal Simek }, 254010e24caaSMichal Simek { 254110e24caaSMichal Simek .phy_id = MARVELL_PHY_ID_88E1510, 254210e24caaSMichal Simek .phy_id_mask = MARVELL_PHY_ID_MASK, 254310e24caaSMichal Simek .name = "Marvell 88E1510", 2544719655a1SAndrew Lunn .features = PHY_GBIT_FIBRE_FEATURES, 2545fc879f72SAndrew Lunn .flags = PHY_POLL_CABLE_TEST, 25460b04680fSAndrew Lunn .probe = &m88e1510_probe, 2547930b37eeSStefan Roese .config_init = &m88e1510_config_init, 254810e24caaSMichal Simek .config_aneg = &m88e1510_config_aneg, 254910e24caaSMichal Simek .read_status = &marvell_read_status, 255010e24caaSMichal Simek .ack_interrupt = &marvell_ack_interrupt, 255110e24caaSMichal Simek .config_intr = &marvell_config_intr, 255210e24caaSMichal Simek .did_interrupt = &m88e1121_did_interrupt, 2553f39aac7eSJingju Hou .get_wol = &m88e1318_get_wol, 2554f39aac7eSJingju Hou .set_wol = &m88e1318_set_wol, 25553758be3dSCharles-Antoine Couret .resume = &marvell_resume, 25563758be3dSCharles-Antoine Couret .suspend = &marvell_suspend, 2557424ca4c5SRussell King .read_page = marvell_read_page, 2558424ca4c5SRussell King .write_page = marvell_write_page, 2559d2fa47d9SAndrew Lunn .get_sset_count = marvell_get_sset_count, 2560d2fa47d9SAndrew Lunn .get_strings = marvell_get_strings, 2561d2fa47d9SAndrew Lunn .get_stats = marvell_get_stats, 2562f0f9b4edSLin Yun Sheng .set_loopback = genphy_loopback, 2563262caf47SHeiner Kallweit .get_tunable = m88e1011_get_tunable, 2564262caf47SHeiner Kallweit .set_tunable = m88e1011_set_tunable, 2565fc879f72SAndrew Lunn .cable_test_start = marvell_vct7_cable_test_start, 2566fc879f72SAndrew Lunn .cable_test_get_status = marvell_vct7_cable_test_get_status, 256710e24caaSMichal Simek }, 25686b358aedSSebastian Hesselbarth { 2569819ec8e1SAndrew Lunn .phy_id = MARVELL_PHY_ID_88E1540, 2570819ec8e1SAndrew Lunn .phy_id_mask = MARVELL_PHY_ID_MASK, 2571819ec8e1SAndrew Lunn .name = "Marvell 88E1540", 2572dcdecdcfSHeiner Kallweit /* PHY_GBIT_FEATURES */ 2573fc879f72SAndrew Lunn .flags = PHY_POLL_CABLE_TEST, 257418702414SArnd Bergmann .probe = m88e1510_probe, 257579be1a1cSClemens Gruber .config_init = &marvell_config_init, 2576819ec8e1SAndrew Lunn .config_aneg = &m88e1510_config_aneg, 2577819ec8e1SAndrew Lunn .read_status = &marvell_read_status, 2578819ec8e1SAndrew Lunn .ack_interrupt = &marvell_ack_interrupt, 2579819ec8e1SAndrew Lunn .config_intr = &marvell_config_intr, 2580819ec8e1SAndrew Lunn .did_interrupt = &m88e1121_did_interrupt, 2581819ec8e1SAndrew Lunn .resume = &genphy_resume, 2582819ec8e1SAndrew Lunn .suspend = &genphy_suspend, 2583424ca4c5SRussell King .read_page = marvell_read_page, 2584424ca4c5SRussell King .write_page = marvell_write_page, 2585d2fa47d9SAndrew Lunn .get_sset_count = marvell_get_sset_count, 2586d2fa47d9SAndrew Lunn .get_strings = marvell_get_strings, 2587d2fa47d9SAndrew Lunn .get_stats = marvell_get_stats, 258869f42be8SHeiner Kallweit .get_tunable = m88e1540_get_tunable, 258969f42be8SHeiner Kallweit .set_tunable = m88e1540_set_tunable, 2590fc879f72SAndrew Lunn .cable_test_start = marvell_vct7_cable_test_start, 2591fc879f72SAndrew Lunn .cable_test_get_status = marvell_vct7_cable_test_get_status, 2592819ec8e1SAndrew Lunn }, 2593819ec8e1SAndrew Lunn { 259460f06fdeSAndrew Lunn .phy_id = MARVELL_PHY_ID_88E1545, 259560f06fdeSAndrew Lunn .phy_id_mask = MARVELL_PHY_ID_MASK, 259660f06fdeSAndrew Lunn .name = "Marvell 88E1545", 259760f06fdeSAndrew Lunn .probe = m88e1510_probe, 2598dcdecdcfSHeiner Kallweit /* PHY_GBIT_FEATURES */ 2599fc879f72SAndrew Lunn .flags = PHY_POLL_CABLE_TEST, 260060f06fdeSAndrew Lunn .config_init = &marvell_config_init, 260160f06fdeSAndrew Lunn .config_aneg = &m88e1510_config_aneg, 260260f06fdeSAndrew Lunn .read_status = &marvell_read_status, 260360f06fdeSAndrew Lunn .ack_interrupt = &marvell_ack_interrupt, 260460f06fdeSAndrew Lunn .config_intr = &marvell_config_intr, 260560f06fdeSAndrew Lunn .did_interrupt = &m88e1121_did_interrupt, 260660f06fdeSAndrew Lunn .resume = &genphy_resume, 260760f06fdeSAndrew Lunn .suspend = &genphy_suspend, 2608424ca4c5SRussell King .read_page = marvell_read_page, 2609424ca4c5SRussell King .write_page = marvell_write_page, 261060f06fdeSAndrew Lunn .get_sset_count = marvell_get_sset_count, 261160f06fdeSAndrew Lunn .get_strings = marvell_get_strings, 261260f06fdeSAndrew Lunn .get_stats = marvell_get_stats, 2613262caf47SHeiner Kallweit .get_tunable = m88e1540_get_tunable, 2614262caf47SHeiner Kallweit .set_tunable = m88e1540_set_tunable, 2615fc879f72SAndrew Lunn .cable_test_start = marvell_vct7_cable_test_start, 2616fc879f72SAndrew Lunn .cable_test_get_status = marvell_vct7_cable_test_get_status, 261760f06fdeSAndrew Lunn }, 261860f06fdeSAndrew Lunn { 26196b358aedSSebastian Hesselbarth .phy_id = MARVELL_PHY_ID_88E3016, 26206b358aedSSebastian Hesselbarth .phy_id_mask = MARVELL_PHY_ID_MASK, 26216b358aedSSebastian Hesselbarth .name = "Marvell 88E3016", 2622dcdecdcfSHeiner Kallweit /* PHY_BASIC_FEATURES */ 2623d2fa47d9SAndrew Lunn .probe = marvell_probe, 26246b358aedSSebastian Hesselbarth .config_init = &m88e3016_config_init, 26256b358aedSSebastian Hesselbarth .aneg_done = &marvell_aneg_done, 26266b358aedSSebastian Hesselbarth .read_status = &marvell_read_status, 26276b358aedSSebastian Hesselbarth .ack_interrupt = &marvell_ack_interrupt, 26286b358aedSSebastian Hesselbarth .config_intr = &marvell_config_intr, 26296b358aedSSebastian Hesselbarth .did_interrupt = &m88e1121_did_interrupt, 26306b358aedSSebastian Hesselbarth .resume = &genphy_resume, 26316b358aedSSebastian Hesselbarth .suspend = &genphy_suspend, 2632424ca4c5SRussell King .read_page = marvell_read_page, 2633424ca4c5SRussell King .write_page = marvell_write_page, 2634d2fa47d9SAndrew Lunn .get_sset_count = marvell_get_sset_count, 2635d2fa47d9SAndrew Lunn .get_strings = marvell_get_strings, 2636d2fa47d9SAndrew Lunn .get_stats = marvell_get_stats, 26376b358aedSSebastian Hesselbarth }, 2638e4cf8a38SAndrew Lunn { 2639e4cf8a38SAndrew Lunn .phy_id = MARVELL_PHY_ID_88E6390, 2640e4cf8a38SAndrew Lunn .phy_id_mask = MARVELL_PHY_ID_MASK, 2641e4cf8a38SAndrew Lunn .name = "Marvell 88E6390", 2642dcdecdcfSHeiner Kallweit /* PHY_GBIT_FEATURES */ 2643fc879f72SAndrew Lunn .flags = PHY_POLL_CABLE_TEST, 2644fee2d546SAndrew Lunn .probe = m88e6390_probe, 2645e4cf8a38SAndrew Lunn .config_init = &marvell_config_init, 26468cbcdc1aSAndrew Lunn .config_aneg = &m88e6390_config_aneg, 2647e4cf8a38SAndrew Lunn .read_status = &marvell_read_status, 2648e4cf8a38SAndrew Lunn .ack_interrupt = &marvell_ack_interrupt, 2649e4cf8a38SAndrew Lunn .config_intr = &marvell_config_intr, 2650e4cf8a38SAndrew Lunn .did_interrupt = &m88e1121_did_interrupt, 2651e4cf8a38SAndrew Lunn .resume = &genphy_resume, 2652e4cf8a38SAndrew Lunn .suspend = &genphy_suspend, 2653424ca4c5SRussell King .read_page = marvell_read_page, 2654424ca4c5SRussell King .write_page = marvell_write_page, 2655e4cf8a38SAndrew Lunn .get_sset_count = marvell_get_sset_count, 2656e4cf8a38SAndrew Lunn .get_strings = marvell_get_strings, 2657e4cf8a38SAndrew Lunn .get_stats = marvell_get_stats, 265869f42be8SHeiner Kallweit .get_tunable = m88e1540_get_tunable, 265969f42be8SHeiner Kallweit .set_tunable = m88e1540_set_tunable, 2660fc879f72SAndrew Lunn .cable_test_start = marvell_vct7_cable_test_start, 2661fc879f72SAndrew Lunn .cable_test_get_status = marvell_vct7_cable_test_get_status, 2662e4cf8a38SAndrew Lunn }, 266376884679SAndy Fleming }; 266476884679SAndy Fleming 266550fd7150SJohan Hovold module_phy_driver(marvell_drivers); 26664e4f10f6SDavid Woodhouse 2667cf93c945SUwe Kleine-König static struct mdio_device_id __maybe_unused marvell_tbl[] = { 2668f5e1cabfSMichal Simek { MARVELL_PHY_ID_88E1101, MARVELL_PHY_ID_MASK }, 2669f5e1cabfSMichal Simek { MARVELL_PHY_ID_88E1112, MARVELL_PHY_ID_MASK }, 2670f5e1cabfSMichal Simek { MARVELL_PHY_ID_88E1111, MARVELL_PHY_ID_MASK }, 2671f5e1cabfSMichal Simek { MARVELL_PHY_ID_88E1118, MARVELL_PHY_ID_MASK }, 2672f5e1cabfSMichal Simek { MARVELL_PHY_ID_88E1121R, MARVELL_PHY_ID_MASK }, 2673f5e1cabfSMichal Simek { MARVELL_PHY_ID_88E1145, MARVELL_PHY_ID_MASK }, 2674f5e1cabfSMichal Simek { MARVELL_PHY_ID_88E1149R, MARVELL_PHY_ID_MASK }, 2675f5e1cabfSMichal Simek { MARVELL_PHY_ID_88E1240, MARVELL_PHY_ID_MASK }, 2676f5e1cabfSMichal Simek { MARVELL_PHY_ID_88E1318S, MARVELL_PHY_ID_MASK }, 26773da09a51SMichal Simek { MARVELL_PHY_ID_88E1116R, MARVELL_PHY_ID_MASK }, 267810e24caaSMichal Simek { MARVELL_PHY_ID_88E1510, MARVELL_PHY_ID_MASK }, 2679819ec8e1SAndrew Lunn { MARVELL_PHY_ID_88E1540, MARVELL_PHY_ID_MASK }, 268060f06fdeSAndrew Lunn { MARVELL_PHY_ID_88E1545, MARVELL_PHY_ID_MASK }, 26816b358aedSSebastian Hesselbarth { MARVELL_PHY_ID_88E3016, MARVELL_PHY_ID_MASK }, 2682e4cf8a38SAndrew Lunn { MARVELL_PHY_ID_88E6390, MARVELL_PHY_ID_MASK }, 26834e4f10f6SDavid Woodhouse { } 26844e4f10f6SDavid Woodhouse }; 26854e4f10f6SDavid Woodhouse 26864e4f10f6SDavid Woodhouse MODULE_DEVICE_TABLE(mdio, marvell_tbl); 2687