100db8189SAndy Fleming /* 200db8189SAndy Fleming * drivers/net/phy/marvell.c 300db8189SAndy Fleming * 400db8189SAndy Fleming * Driver for Marvell PHYs 500db8189SAndy Fleming * 600db8189SAndy Fleming * Author: Andy Fleming 700db8189SAndy Fleming * 800db8189SAndy Fleming * Copyright (c) 2004 Freescale Semiconductor, Inc. 900db8189SAndy Fleming * 103871c387SMichael Stapelberg * Copyright (c) 2013 Michael Stapelberg <michael@stapelberg.de> 113871c387SMichael Stapelberg * 1200db8189SAndy Fleming * This program is free software; you can redistribute it and/or modify it 1300db8189SAndy Fleming * under the terms of the GNU General Public License as published by the 1400db8189SAndy Fleming * Free Software Foundation; either version 2 of the License, or (at your 1500db8189SAndy Fleming * option) any later version. 1600db8189SAndy Fleming * 1700db8189SAndy Fleming */ 1800db8189SAndy Fleming #include <linux/kernel.h> 1900db8189SAndy Fleming #include <linux/string.h> 200b04680fSAndrew Lunn #include <linux/ctype.h> 2100db8189SAndy Fleming #include <linux/errno.h> 2200db8189SAndy Fleming #include <linux/unistd.h> 230b04680fSAndrew Lunn #include <linux/hwmon.h> 2400db8189SAndy Fleming #include <linux/interrupt.h> 2500db8189SAndy Fleming #include <linux/init.h> 2600db8189SAndy Fleming #include <linux/delay.h> 2700db8189SAndy Fleming #include <linux/netdevice.h> 2800db8189SAndy Fleming #include <linux/etherdevice.h> 2900db8189SAndy Fleming #include <linux/skbuff.h> 3000db8189SAndy Fleming #include <linux/spinlock.h> 3100db8189SAndy Fleming #include <linux/mm.h> 3200db8189SAndy Fleming #include <linux/module.h> 3300db8189SAndy Fleming #include <linux/mii.h> 3400db8189SAndy Fleming #include <linux/ethtool.h> 3500db8189SAndy Fleming #include <linux/phy.h> 362f495c39SBenjamin Herrenschmidt #include <linux/marvell_phy.h> 37cf41a51dSDavid Daney #include <linux/of.h> 3800db8189SAndy Fleming 39eea3b201SAvinash Kumar #include <linux/io.h> 4000db8189SAndy Fleming #include <asm/irq.h> 41eea3b201SAvinash Kumar #include <linux/uaccess.h> 4200db8189SAndy Fleming 4327d916d6SDavid Daney #define MII_MARVELL_PHY_PAGE 22 4452295666SAndrew Lunn #define MII_MARVELL_COPPER_PAGE 0x00 4552295666SAndrew Lunn #define MII_MARVELL_FIBER_PAGE 0x01 4652295666SAndrew Lunn #define MII_MARVELL_MSCR_PAGE 0x02 4752295666SAndrew Lunn #define MII_MARVELL_LED_PAGE 0x03 4852295666SAndrew Lunn #define MII_MARVELL_MISC_TEST_PAGE 0x06 4952295666SAndrew Lunn #define MII_MARVELL_WOL_PAGE 0x11 5027d916d6SDavid Daney 5100db8189SAndy Fleming #define MII_M1011_IEVENT 0x13 5200db8189SAndy Fleming #define MII_M1011_IEVENT_CLEAR 0x0000 5300db8189SAndy Fleming 5400db8189SAndy Fleming #define MII_M1011_IMASK 0x12 5500db8189SAndy Fleming #define MII_M1011_IMASK_INIT 0x6400 5600db8189SAndy Fleming #define MII_M1011_IMASK_CLEAR 0x0000 5700db8189SAndy Fleming 5876884679SAndy Fleming #define MII_M1011_PHY_SCR 0x10 59fecd5e91SAndrew Lunn #define MII_M1011_PHY_SCR_DOWNSHIFT_EN BIT(11) 60fecd5e91SAndrew Lunn #define MII_M1011_PHY_SCR_DOWNSHIFT_SHIFT 12 616ef05eb7SAndrew Lunn #define MII_M1011_PHY_SRC_DOWNSHIFT_MASK 0x7800 62fecd5e91SAndrew Lunn #define MII_M1011_PHY_SCR_MDI (0x0 << 5) 63fecd5e91SAndrew Lunn #define MII_M1011_PHY_SCR_MDI_X (0x1 << 5) 64fecd5e91SAndrew Lunn #define MII_M1011_PHY_SCR_AUTO_CROSS (0x3 << 5) 6576884679SAndy Fleming 6676884679SAndy Fleming #define MII_M1111_PHY_LED_CONTROL 0x18 6776884679SAndy Fleming #define MII_M1111_PHY_LED_DIRECT 0x4100 6876884679SAndy Fleming #define MII_M1111_PHY_LED_COMBINE 0x411c 69895ee682SKim Phillips #define MII_M1111_PHY_EXT_CR 0x14 7061111598SAndrew Lunn #define MII_M1111_RGMII_RX_DELAY BIT(7) 7161111598SAndrew Lunn #define MII_M1111_RGMII_TX_DELAY BIT(1) 72895ee682SKim Phillips #define MII_M1111_PHY_EXT_SR 0x1b 73be937f1fSAlexandr Smirnov 74895ee682SKim Phillips #define MII_M1111_HWCFG_MODE_MASK 0xf 75be937f1fSAlexandr Smirnov #define MII_M1111_HWCFG_MODE_FIBER_RGMII 0x3 764117b5beSKapil Juneja #define MII_M1111_HWCFG_MODE_SGMII_NO_CLK 0x4 77865b813aSAndrew Lunn #define MII_M1111_HWCFG_MODE_RTBI 0x7 785f8cbc13SLiu Yu-B13201 #define MII_M1111_HWCFG_MODE_COPPER_RTBI 0x9 79865b813aSAndrew Lunn #define MII_M1111_HWCFG_MODE_COPPER_RGMII 0xb 80865b813aSAndrew Lunn #define MII_M1111_HWCFG_FIBER_COPPER_RES BIT(13) 81865b813aSAndrew Lunn #define MII_M1111_HWCFG_FIBER_COPPER_AUTO BIT(15) 82be937f1fSAlexandr Smirnov 83c477d044SCyril Chemparathy #define MII_88E1121_PHY_MSCR_REG 21 84c477d044SCyril Chemparathy #define MII_88E1121_PHY_MSCR_RX_DELAY BIT(5) 85c477d044SCyril Chemparathy #define MII_88E1121_PHY_MSCR_TX_DELAY BIT(4) 86424ca4c5SRussell King #define MII_88E1121_PHY_MSCR_DELAY_MASK (BIT(5) | BIT(4)) 87c477d044SCyril Chemparathy 880b04680fSAndrew Lunn #define MII_88E1121_MISC_TEST 0x1a 890b04680fSAndrew Lunn #define MII_88E1510_MISC_TEST_TEMP_THRESHOLD_MASK 0x1f00 900b04680fSAndrew Lunn #define MII_88E1510_MISC_TEST_TEMP_THRESHOLD_SHIFT 8 910b04680fSAndrew Lunn #define MII_88E1510_MISC_TEST_TEMP_IRQ_EN BIT(7) 920b04680fSAndrew Lunn #define MII_88E1510_MISC_TEST_TEMP_IRQ BIT(6) 930b04680fSAndrew Lunn #define MII_88E1121_MISC_TEST_TEMP_SENSOR_EN BIT(5) 940b04680fSAndrew Lunn #define MII_88E1121_MISC_TEST_TEMP_MASK 0x1f 950b04680fSAndrew Lunn 960b04680fSAndrew Lunn #define MII_88E1510_TEMP_SENSOR 0x1b 970b04680fSAndrew Lunn #define MII_88E1510_TEMP_SENSOR_MASK 0xff 980b04680fSAndrew Lunn 99fee2d546SAndrew Lunn #define MII_88E6390_MISC_TEST 0x1b 100fee2d546SAndrew Lunn #define MII_88E6390_MISC_TEST_SAMPLE_1S 0 101fee2d546SAndrew Lunn #define MII_88E6390_MISC_TEST_SAMPLE_10MS BIT(14) 102fee2d546SAndrew Lunn #define MII_88E6390_MISC_TEST_SAMPLE_DISABLE BIT(15) 103fee2d546SAndrew Lunn #define MII_88E6390_MISC_TEST_SAMPLE_ENABLE 0 104fee2d546SAndrew Lunn #define MII_88E6390_MISC_TEST_SAMPLE_MASK (0x3 << 14) 105fee2d546SAndrew Lunn 106fee2d546SAndrew Lunn #define MII_88E6390_TEMP_SENSOR 0x1c 107fee2d546SAndrew Lunn #define MII_88E6390_TEMP_SENSOR_MASK 0xff 108fee2d546SAndrew Lunn #define MII_88E6390_TEMP_SENSOR_SAMPLES 10 109fee2d546SAndrew Lunn 110337ac9d5SCyril Chemparathy #define MII_88E1318S_PHY_MSCR1_REG 16 111337ac9d5SCyril Chemparathy #define MII_88E1318S_PHY_MSCR1_PAD_ODD BIT(6) 1123ff1c259SCyril Chemparathy 1133871c387SMichael Stapelberg /* Copper Specific Interrupt Enable Register */ 1143871c387SMichael Stapelberg #define MII_88E1318S_PHY_CSIER 0x12 1153871c387SMichael Stapelberg /* WOL Event Interrupt Enable */ 1163871c387SMichael Stapelberg #define MII_88E1318S_PHY_CSIER_WOL_EIE BIT(7) 1173871c387SMichael Stapelberg 1183871c387SMichael Stapelberg /* LED Timer Control Register */ 1193871c387SMichael Stapelberg #define MII_88E1318S_PHY_LED_TCR 0x12 1203871c387SMichael Stapelberg #define MII_88E1318S_PHY_LED_TCR_FORCE_INT BIT(15) 1213871c387SMichael Stapelberg #define MII_88E1318S_PHY_LED_TCR_INTn_ENABLE BIT(7) 1223871c387SMichael Stapelberg #define MII_88E1318S_PHY_LED_TCR_INT_ACTIVE_LOW BIT(11) 1233871c387SMichael Stapelberg 1243871c387SMichael Stapelberg /* Magic Packet MAC address registers */ 1253871c387SMichael Stapelberg #define MII_88E1318S_PHY_MAGIC_PACKET_WORD2 0x17 1263871c387SMichael Stapelberg #define MII_88E1318S_PHY_MAGIC_PACKET_WORD1 0x18 1273871c387SMichael Stapelberg #define MII_88E1318S_PHY_MAGIC_PACKET_WORD0 0x19 1283871c387SMichael Stapelberg 1293871c387SMichael Stapelberg #define MII_88E1318S_PHY_WOL_CTRL 0x10 1303871c387SMichael Stapelberg #define MII_88E1318S_PHY_WOL_CTRL_CLEAR_WOL_STATUS BIT(12) 1313871c387SMichael Stapelberg #define MII_88E1318S_PHY_WOL_CTRL_MAGIC_PACKET_MATCH_ENABLE BIT(14) 1323871c387SMichael Stapelberg 133140bc929SSergei Poselenov #define MII_88E1121_PHY_LED_CTRL 16 134140bc929SSergei Poselenov #define MII_88E1121_PHY_LED_DEF 0x0030 135140bc929SSergei Poselenov 136be937f1fSAlexandr Smirnov #define MII_M1011_PHY_STATUS 0x11 137be937f1fSAlexandr Smirnov #define MII_M1011_PHY_STATUS_1000 0x8000 138be937f1fSAlexandr Smirnov #define MII_M1011_PHY_STATUS_100 0x4000 139be937f1fSAlexandr Smirnov #define MII_M1011_PHY_STATUS_SPD_MASK 0xc000 140be937f1fSAlexandr Smirnov #define MII_M1011_PHY_STATUS_FULLDUPLEX 0x2000 141be937f1fSAlexandr Smirnov #define MII_M1011_PHY_STATUS_RESOLVED 0x0800 142be937f1fSAlexandr Smirnov #define MII_M1011_PHY_STATUS_LINK 0x0400 143be937f1fSAlexandr Smirnov 1446b358aedSSebastian Hesselbarth #define MII_88E3016_PHY_SPEC_CTRL 0x10 1456b358aedSSebastian Hesselbarth #define MII_88E3016_DISABLE_SCRAMBLER 0x0200 1466b358aedSSebastian Hesselbarth #define MII_88E3016_AUTO_MDIX_CROSSOVER 0x0030 14776884679SAndy Fleming 148930b37eeSStefan Roese #define MII_88E1510_GEN_CTRL_REG_1 0x14 149930b37eeSStefan Roese #define MII_88E1510_GEN_CTRL_REG_1_MODE_MASK 0x7 150930b37eeSStefan Roese #define MII_88E1510_GEN_CTRL_REG_1_MODE_SGMII 0x1 /* SGMII to copper */ 151930b37eeSStefan Roese #define MII_88E1510_GEN_CTRL_REG_1_RESET 0x8000 /* Soft reset */ 152930b37eeSStefan Roese 1536cfb3bccSCharles-Antoine Couret #define LPA_FIBER_1000HALF 0x40 1546cfb3bccSCharles-Antoine Couret #define LPA_FIBER_1000FULL 0x20 1556cfb3bccSCharles-Antoine Couret 1566cfb3bccSCharles-Antoine Couret #define LPA_PAUSE_FIBER 0x180 1576cfb3bccSCharles-Antoine Couret #define LPA_PAUSE_ASYM_FIBER 0x100 1586cfb3bccSCharles-Antoine Couret 1596cfb3bccSCharles-Antoine Couret #define ADVERTISE_FIBER_1000HALF 0x40 1606cfb3bccSCharles-Antoine Couret #define ADVERTISE_FIBER_1000FULL 0x20 1616cfb3bccSCharles-Antoine Couret 1626cfb3bccSCharles-Antoine Couret #define ADVERTISE_PAUSE_FIBER 0x180 1636cfb3bccSCharles-Antoine Couret #define ADVERTISE_PAUSE_ASYM_FIBER 0x100 1646cfb3bccSCharles-Antoine Couret 1656cfb3bccSCharles-Antoine Couret #define REGISTER_LINK_STATUS 0x400 1662170fef7SCharles-Antoine Couret #define NB_FIBER_STATS 1 1676cfb3bccSCharles-Antoine Couret 16800db8189SAndy Fleming MODULE_DESCRIPTION("Marvell PHY driver"); 16900db8189SAndy Fleming MODULE_AUTHOR("Andy Fleming"); 17000db8189SAndy Fleming MODULE_LICENSE("GPL"); 17100db8189SAndy Fleming 172d2fa47d9SAndrew Lunn struct marvell_hw_stat { 173d2fa47d9SAndrew Lunn const char *string; 174d2fa47d9SAndrew Lunn u8 page; 175d2fa47d9SAndrew Lunn u8 reg; 176d2fa47d9SAndrew Lunn u8 bits; 177d2fa47d9SAndrew Lunn }; 178d2fa47d9SAndrew Lunn 179d2fa47d9SAndrew Lunn static struct marvell_hw_stat marvell_hw_stats[] = { 1802170fef7SCharles-Antoine Couret { "phy_receive_errors_copper", 0, 21, 16}, 181d2fa47d9SAndrew Lunn { "phy_idle_errors", 0, 10, 8 }, 1822170fef7SCharles-Antoine Couret { "phy_receive_errors_fiber", 1, 21, 16}, 183d2fa47d9SAndrew Lunn }; 184d2fa47d9SAndrew Lunn 185d2fa47d9SAndrew Lunn struct marvell_priv { 186d2fa47d9SAndrew Lunn u64 stats[ARRAY_SIZE(marvell_hw_stats)]; 1870b04680fSAndrew Lunn char *hwmon_name; 1880b04680fSAndrew Lunn struct device *hwmon_dev; 189d2fa47d9SAndrew Lunn }; 190d2fa47d9SAndrew Lunn 191424ca4c5SRussell King static int marvell_read_page(struct phy_device *phydev) 1926427bb2dSAndrew Lunn { 193424ca4c5SRussell King return __phy_read(phydev, MII_MARVELL_PHY_PAGE); 194424ca4c5SRussell King } 195424ca4c5SRussell King 196424ca4c5SRussell King static int marvell_write_page(struct phy_device *phydev, int page) 197424ca4c5SRussell King { 198424ca4c5SRussell King return __phy_write(phydev, MII_MARVELL_PHY_PAGE, page); 1996427bb2dSAndrew Lunn } 2006427bb2dSAndrew Lunn 2016427bb2dSAndrew Lunn static int marvell_set_page(struct phy_device *phydev, int page) 2026427bb2dSAndrew Lunn { 2036427bb2dSAndrew Lunn return phy_write(phydev, MII_MARVELL_PHY_PAGE, page); 2046427bb2dSAndrew Lunn } 2056427bb2dSAndrew Lunn 20600db8189SAndy Fleming static int marvell_ack_interrupt(struct phy_device *phydev) 20700db8189SAndy Fleming { 20800db8189SAndy Fleming int err; 20900db8189SAndy Fleming 21000db8189SAndy Fleming /* Clear the interrupts by reading the reg */ 21100db8189SAndy Fleming err = phy_read(phydev, MII_M1011_IEVENT); 21200db8189SAndy Fleming 21300db8189SAndy Fleming if (err < 0) 21400db8189SAndy Fleming return err; 21500db8189SAndy Fleming 21600db8189SAndy Fleming return 0; 21700db8189SAndy Fleming } 21800db8189SAndy Fleming 21900db8189SAndy Fleming static int marvell_config_intr(struct phy_device *phydev) 22000db8189SAndy Fleming { 22100db8189SAndy Fleming int err; 22200db8189SAndy Fleming 22300db8189SAndy Fleming if (phydev->interrupts == PHY_INTERRUPT_ENABLED) 22423beb38fSAndrew Lunn err = phy_write(phydev, MII_M1011_IMASK, 22523beb38fSAndrew Lunn MII_M1011_IMASK_INIT); 22600db8189SAndy Fleming else 22723beb38fSAndrew Lunn err = phy_write(phydev, MII_M1011_IMASK, 22823beb38fSAndrew Lunn MII_M1011_IMASK_CLEAR); 22900db8189SAndy Fleming 23000db8189SAndy Fleming return err; 23100db8189SAndy Fleming } 23200db8189SAndy Fleming 233239aa55bSDavid Thomson static int marvell_set_polarity(struct phy_device *phydev, int polarity) 234239aa55bSDavid Thomson { 235239aa55bSDavid Thomson int reg; 236239aa55bSDavid Thomson int err; 237239aa55bSDavid Thomson int val; 238239aa55bSDavid Thomson 239239aa55bSDavid Thomson /* get the current settings */ 240239aa55bSDavid Thomson reg = phy_read(phydev, MII_M1011_PHY_SCR); 241239aa55bSDavid Thomson if (reg < 0) 242239aa55bSDavid Thomson return reg; 243239aa55bSDavid Thomson 244239aa55bSDavid Thomson val = reg; 245239aa55bSDavid Thomson val &= ~MII_M1011_PHY_SCR_AUTO_CROSS; 246239aa55bSDavid Thomson switch (polarity) { 247239aa55bSDavid Thomson case ETH_TP_MDI: 248239aa55bSDavid Thomson val |= MII_M1011_PHY_SCR_MDI; 249239aa55bSDavid Thomson break; 250239aa55bSDavid Thomson case ETH_TP_MDI_X: 251239aa55bSDavid Thomson val |= MII_M1011_PHY_SCR_MDI_X; 252239aa55bSDavid Thomson break; 253239aa55bSDavid Thomson case ETH_TP_MDI_AUTO: 254239aa55bSDavid Thomson case ETH_TP_MDI_INVALID: 255239aa55bSDavid Thomson default: 256239aa55bSDavid Thomson val |= MII_M1011_PHY_SCR_AUTO_CROSS; 257239aa55bSDavid Thomson break; 258239aa55bSDavid Thomson } 259239aa55bSDavid Thomson 260239aa55bSDavid Thomson if (val != reg) { 261239aa55bSDavid Thomson /* Set the new polarity value in the register */ 262239aa55bSDavid Thomson err = phy_write(phydev, MII_M1011_PHY_SCR, val); 263239aa55bSDavid Thomson if (err) 264239aa55bSDavid Thomson return err; 265239aa55bSDavid Thomson } 266239aa55bSDavid Thomson 267239aa55bSDavid Thomson return 0; 268239aa55bSDavid Thomson } 269239aa55bSDavid Thomson 2706ef05eb7SAndrew Lunn static int marvell_set_downshift(struct phy_device *phydev, bool enable, 2716ef05eb7SAndrew Lunn u8 retries) 2726ef05eb7SAndrew Lunn { 2736ef05eb7SAndrew Lunn int reg; 2746ef05eb7SAndrew Lunn 2756ef05eb7SAndrew Lunn reg = phy_read(phydev, MII_M1011_PHY_SCR); 2766ef05eb7SAndrew Lunn if (reg < 0) 2776ef05eb7SAndrew Lunn return reg; 2786ef05eb7SAndrew Lunn 2796ef05eb7SAndrew Lunn reg &= MII_M1011_PHY_SRC_DOWNSHIFT_MASK; 2806ef05eb7SAndrew Lunn reg |= ((retries - 1) << MII_M1011_PHY_SCR_DOWNSHIFT_SHIFT); 2816ef05eb7SAndrew Lunn if (enable) 2826ef05eb7SAndrew Lunn reg |= MII_M1011_PHY_SCR_DOWNSHIFT_EN; 2836ef05eb7SAndrew Lunn 2846ef05eb7SAndrew Lunn return phy_write(phydev, MII_M1011_PHY_SCR, reg); 2856ef05eb7SAndrew Lunn } 2866ef05eb7SAndrew Lunn 28700db8189SAndy Fleming static int marvell_config_aneg(struct phy_device *phydev) 28800db8189SAndy Fleming { 28900db8189SAndy Fleming int err; 29000db8189SAndy Fleming 2914e26c5c3SRaju Lakkaraju err = marvell_set_polarity(phydev, phydev->mdix_ctrl); 29276884679SAndy Fleming if (err < 0) 29376884679SAndy Fleming return err; 29476884679SAndy Fleming 29576884679SAndy Fleming err = phy_write(phydev, MII_M1111_PHY_LED_CONTROL, 29676884679SAndy Fleming MII_M1111_PHY_LED_DIRECT); 29776884679SAndy Fleming if (err < 0) 29876884679SAndy Fleming return err; 29900db8189SAndy Fleming 30000db8189SAndy Fleming err = genphy_config_aneg(phydev); 3018ff44985SAnton Vorontsov if (err < 0) 30200db8189SAndy Fleming return err; 3038ff44985SAnton Vorontsov 3048ff44985SAnton Vorontsov if (phydev->autoneg != AUTONEG_ENABLE) { 3050c3439bcSAndrew Lunn /* A write to speed/duplex bits (that is performed by 3068ff44985SAnton Vorontsov * genphy_config_aneg() call above) must be followed by 3078ff44985SAnton Vorontsov * a software reset. Otherwise, the write has no effect. 3088ff44985SAnton Vorontsov */ 30934386344SAndrew Lunn err = genphy_soft_reset(phydev); 3108ff44985SAnton Vorontsov if (err < 0) 3118ff44985SAnton Vorontsov return err; 3128ff44985SAnton Vorontsov } 3138ff44985SAnton Vorontsov 3148ff44985SAnton Vorontsov return 0; 31500db8189SAndy Fleming } 31600db8189SAndy Fleming 317f2899788SAndrew Lunn static int m88e1101_config_aneg(struct phy_device *phydev) 318f2899788SAndrew Lunn { 319f2899788SAndrew Lunn int err; 320f2899788SAndrew Lunn 321f2899788SAndrew Lunn /* This Marvell PHY has an errata which requires 322f2899788SAndrew Lunn * that certain registers get written in order 323f2899788SAndrew Lunn * to restart autonegotiation 324f2899788SAndrew Lunn */ 32534386344SAndrew Lunn err = genphy_soft_reset(phydev); 326f2899788SAndrew Lunn if (err < 0) 327f2899788SAndrew Lunn return err; 328f2899788SAndrew Lunn 329f2899788SAndrew Lunn err = phy_write(phydev, 0x1d, 0x1f); 330f2899788SAndrew Lunn if (err < 0) 331f2899788SAndrew Lunn return err; 332f2899788SAndrew Lunn 333f2899788SAndrew Lunn err = phy_write(phydev, 0x1e, 0x200c); 334f2899788SAndrew Lunn if (err < 0) 335f2899788SAndrew Lunn return err; 336f2899788SAndrew Lunn 337f2899788SAndrew Lunn err = phy_write(phydev, 0x1d, 0x5); 338f2899788SAndrew Lunn if (err < 0) 339f2899788SAndrew Lunn return err; 340f2899788SAndrew Lunn 341f2899788SAndrew Lunn err = phy_write(phydev, 0x1e, 0); 342f2899788SAndrew Lunn if (err < 0) 343f2899788SAndrew Lunn return err; 344f2899788SAndrew Lunn 345f2899788SAndrew Lunn err = phy_write(phydev, 0x1e, 0x100); 346f2899788SAndrew Lunn if (err < 0) 347f2899788SAndrew Lunn return err; 348f2899788SAndrew Lunn 349f2899788SAndrew Lunn return marvell_config_aneg(phydev); 350f2899788SAndrew Lunn } 351f2899788SAndrew Lunn 3523ec0a0f1SHarini Katakam static int m88e1111_config_aneg(struct phy_device *phydev) 3533ec0a0f1SHarini Katakam { 3543ec0a0f1SHarini Katakam int err; 3553ec0a0f1SHarini Katakam 3563ec0a0f1SHarini Katakam /* The Marvell PHY has an errata which requires 3573ec0a0f1SHarini Katakam * that certain registers get written in order 3583ec0a0f1SHarini Katakam * to restart autonegotiation 3593ec0a0f1SHarini Katakam */ 36034386344SAndrew Lunn err = genphy_soft_reset(phydev); 3613ec0a0f1SHarini Katakam 3624e26c5c3SRaju Lakkaraju err = marvell_set_polarity(phydev, phydev->mdix_ctrl); 3633ec0a0f1SHarini Katakam if (err < 0) 3643ec0a0f1SHarini Katakam return err; 3653ec0a0f1SHarini Katakam 3663ec0a0f1SHarini Katakam err = phy_write(phydev, MII_M1111_PHY_LED_CONTROL, 3673ec0a0f1SHarini Katakam MII_M1111_PHY_LED_DIRECT); 3683ec0a0f1SHarini Katakam if (err < 0) 3693ec0a0f1SHarini Katakam return err; 3703ec0a0f1SHarini Katakam 3713ec0a0f1SHarini Katakam err = genphy_config_aneg(phydev); 3723ec0a0f1SHarini Katakam if (err < 0) 3733ec0a0f1SHarini Katakam return err; 3743ec0a0f1SHarini Katakam 3753ec0a0f1SHarini Katakam if (phydev->autoneg != AUTONEG_ENABLE) { 3763ec0a0f1SHarini Katakam /* A write to speed/duplex bits (that is performed by 3773ec0a0f1SHarini Katakam * genphy_config_aneg() call above) must be followed by 3783ec0a0f1SHarini Katakam * a software reset. Otherwise, the write has no effect. 3793ec0a0f1SHarini Katakam */ 38034386344SAndrew Lunn err = genphy_soft_reset(phydev); 3813ec0a0f1SHarini Katakam if (err < 0) 3823ec0a0f1SHarini Katakam return err; 3833ec0a0f1SHarini Katakam } 3843ec0a0f1SHarini Katakam 3853ec0a0f1SHarini Katakam return 0; 3863ec0a0f1SHarini Katakam } 3873ec0a0f1SHarini Katakam 388cf41a51dSDavid Daney #ifdef CONFIG_OF_MDIO 3890c3439bcSAndrew Lunn /* Set and/or override some configuration registers based on the 390cf41a51dSDavid Daney * marvell,reg-init property stored in the of_node for the phydev. 391cf41a51dSDavid Daney * 392cf41a51dSDavid Daney * marvell,reg-init = <reg-page reg mask value>,...; 393cf41a51dSDavid Daney * 394cf41a51dSDavid Daney * There may be one or more sets of <reg-page reg mask value>: 395cf41a51dSDavid Daney * 396cf41a51dSDavid Daney * reg-page: which register bank to use. 397cf41a51dSDavid Daney * reg: the register. 398cf41a51dSDavid Daney * mask: if non-zero, ANDed with existing register value. 399cf41a51dSDavid Daney * value: ORed with the masked value and written to the regiser. 400cf41a51dSDavid Daney * 401cf41a51dSDavid Daney */ 402cf41a51dSDavid Daney static int marvell_of_reg_init(struct phy_device *phydev) 403cf41a51dSDavid Daney { 404cf41a51dSDavid Daney const __be32 *paddr; 405424ca4c5SRussell King int len, i, saved_page, current_page, ret = 0; 406cf41a51dSDavid Daney 407e5a03bfdSAndrew Lunn if (!phydev->mdio.dev.of_node) 408cf41a51dSDavid Daney return 0; 409cf41a51dSDavid Daney 410e5a03bfdSAndrew Lunn paddr = of_get_property(phydev->mdio.dev.of_node, 411e5a03bfdSAndrew Lunn "marvell,reg-init", &len); 412cf41a51dSDavid Daney if (!paddr || len < (4 * sizeof(*paddr))) 413cf41a51dSDavid Daney return 0; 414cf41a51dSDavid Daney 415424ca4c5SRussell King saved_page = phy_save_page(phydev); 416cf41a51dSDavid Daney if (saved_page < 0) 417424ca4c5SRussell King goto err; 418cf41a51dSDavid Daney current_page = saved_page; 419cf41a51dSDavid Daney 420cf41a51dSDavid Daney len /= sizeof(*paddr); 421cf41a51dSDavid Daney for (i = 0; i < len - 3; i += 4) { 4226427bb2dSAndrew Lunn u16 page = be32_to_cpup(paddr + i); 423cf41a51dSDavid Daney u16 reg = be32_to_cpup(paddr + i + 1); 424cf41a51dSDavid Daney u16 mask = be32_to_cpup(paddr + i + 2); 425cf41a51dSDavid Daney u16 val_bits = be32_to_cpup(paddr + i + 3); 426cf41a51dSDavid Daney int val; 427cf41a51dSDavid Daney 4286427bb2dSAndrew Lunn if (page != current_page) { 4296427bb2dSAndrew Lunn current_page = page; 430424ca4c5SRussell King ret = marvell_write_page(phydev, page); 431cf41a51dSDavid Daney if (ret < 0) 432cf41a51dSDavid Daney goto err; 433cf41a51dSDavid Daney } 434cf41a51dSDavid Daney 435cf41a51dSDavid Daney val = 0; 436cf41a51dSDavid Daney if (mask) { 437424ca4c5SRussell King val = __phy_read(phydev, reg); 438cf41a51dSDavid Daney if (val < 0) { 439cf41a51dSDavid Daney ret = val; 440cf41a51dSDavid Daney goto err; 441cf41a51dSDavid Daney } 442cf41a51dSDavid Daney val &= mask; 443cf41a51dSDavid Daney } 444cf41a51dSDavid Daney val |= val_bits; 445cf41a51dSDavid Daney 446424ca4c5SRussell King ret = __phy_write(phydev, reg, val); 447cf41a51dSDavid Daney if (ret < 0) 448cf41a51dSDavid Daney goto err; 449cf41a51dSDavid Daney } 450cf41a51dSDavid Daney err: 451424ca4c5SRussell King return phy_restore_page(phydev, saved_page, ret); 452cf41a51dSDavid Daney } 453cf41a51dSDavid Daney #else 454cf41a51dSDavid Daney static int marvell_of_reg_init(struct phy_device *phydev) 455cf41a51dSDavid Daney { 456cf41a51dSDavid Daney return 0; 457cf41a51dSDavid Daney } 458cf41a51dSDavid Daney #endif /* CONFIG_OF_MDIO */ 459cf41a51dSDavid Daney 460864dc729SAndrew Lunn static int m88e1121_config_aneg_rgmii_delays(struct phy_device *phydev) 461140bc929SSergei Poselenov { 462424ca4c5SRussell King int mscr; 463c477d044SCyril Chemparathy 464c477d044SCyril Chemparathy if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID) 465424ca4c5SRussell King mscr = MII_88E1121_PHY_MSCR_RX_DELAY | 466424ca4c5SRussell King MII_88E1121_PHY_MSCR_TX_DELAY; 467c477d044SCyril Chemparathy else if (phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID) 468424ca4c5SRussell King mscr = MII_88E1121_PHY_MSCR_RX_DELAY; 469c477d044SCyril Chemparathy else if (phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID) 470424ca4c5SRussell King mscr = MII_88E1121_PHY_MSCR_TX_DELAY; 471424ca4c5SRussell King else 472424ca4c5SRussell King mscr = 0; 473c477d044SCyril Chemparathy 474424ca4c5SRussell King return phy_modify_paged(phydev, MII_MARVELL_MSCR_PAGE, 475424ca4c5SRussell King MII_88E1121_PHY_MSCR_REG, 476424ca4c5SRussell King MII_88E1121_PHY_MSCR_DELAY_MASK, mscr); 477be8c6480SArnaud Patard } 478c477d044SCyril Chemparathy 479864dc729SAndrew Lunn static int m88e1121_config_aneg(struct phy_device *phydev) 480864dc729SAndrew Lunn { 481864dc729SAndrew Lunn int err = 0; 482864dc729SAndrew Lunn 483864dc729SAndrew Lunn if (phy_interface_is_rgmii(phydev)) { 484864dc729SAndrew Lunn err = m88e1121_config_aneg_rgmii_delays(phydev); 485fea23fb5SRussell King if (err < 0) 486864dc729SAndrew Lunn return err; 487864dc729SAndrew Lunn } 488140bc929SSergei Poselenov 48934386344SAndrew Lunn err = genphy_soft_reset(phydev); 490140bc929SSergei Poselenov if (err < 0) 491140bc929SSergei Poselenov return err; 492140bc929SSergei Poselenov 493fecd5e91SAndrew Lunn err = marvell_set_polarity(phydev, phydev->mdix_ctrl); 494140bc929SSergei Poselenov if (err < 0) 495140bc929SSergei Poselenov return err; 496140bc929SSergei Poselenov 497fdecf36fSClemens Gruber return genphy_config_aneg(phydev); 498140bc929SSergei Poselenov } 499140bc929SSergei Poselenov 500337ac9d5SCyril Chemparathy static int m88e1318_config_aneg(struct phy_device *phydev) 5013ff1c259SCyril Chemparathy { 502424ca4c5SRussell King int err; 5033ff1c259SCyril Chemparathy 504424ca4c5SRussell King err = phy_modify_paged(phydev, MII_MARVELL_MSCR_PAGE, 505424ca4c5SRussell King MII_88E1318S_PHY_MSCR1_REG, 506424ca4c5SRussell King 0, MII_88E1318S_PHY_MSCR1_PAD_ODD); 5073ff1c259SCyril Chemparathy if (err < 0) 5083ff1c259SCyril Chemparathy return err; 5093ff1c259SCyril Chemparathy 5103ff1c259SCyril Chemparathy return m88e1121_config_aneg(phydev); 5113ff1c259SCyril Chemparathy } 5123ff1c259SCyril Chemparathy 51378301ebeSCharles-Antoine Couret /** 51478301ebeSCharles-Antoine Couret * ethtool_adv_to_fiber_adv_t 51578301ebeSCharles-Antoine Couret * @ethadv: the ethtool advertisement settings 51678301ebeSCharles-Antoine Couret * 51778301ebeSCharles-Antoine Couret * A small helper function that translates ethtool advertisement 51878301ebeSCharles-Antoine Couret * settings to phy autonegotiation advertisements for the 51978301ebeSCharles-Antoine Couret * MII_ADV register for fiber link. 52078301ebeSCharles-Antoine Couret */ 52178301ebeSCharles-Antoine Couret static inline u32 ethtool_adv_to_fiber_adv_t(u32 ethadv) 52278301ebeSCharles-Antoine Couret { 52378301ebeSCharles-Antoine Couret u32 result = 0; 52478301ebeSCharles-Antoine Couret 52578301ebeSCharles-Antoine Couret if (ethadv & ADVERTISED_1000baseT_Half) 52678301ebeSCharles-Antoine Couret result |= ADVERTISE_FIBER_1000HALF; 52778301ebeSCharles-Antoine Couret if (ethadv & ADVERTISED_1000baseT_Full) 52878301ebeSCharles-Antoine Couret result |= ADVERTISE_FIBER_1000FULL; 52978301ebeSCharles-Antoine Couret 53078301ebeSCharles-Antoine Couret if ((ethadv & ADVERTISE_PAUSE_ASYM) && (ethadv & ADVERTISE_PAUSE_CAP)) 53178301ebeSCharles-Antoine Couret result |= LPA_PAUSE_ASYM_FIBER; 53278301ebeSCharles-Antoine Couret else if (ethadv & ADVERTISE_PAUSE_CAP) 53378301ebeSCharles-Antoine Couret result |= (ADVERTISE_PAUSE_FIBER 53478301ebeSCharles-Antoine Couret & (~ADVERTISE_PAUSE_ASYM_FIBER)); 53578301ebeSCharles-Antoine Couret 53678301ebeSCharles-Antoine Couret return result; 53778301ebeSCharles-Antoine Couret } 53878301ebeSCharles-Antoine Couret 53978301ebeSCharles-Antoine Couret /** 54078301ebeSCharles-Antoine Couret * marvell_config_aneg_fiber - restart auto-negotiation or write BMCR 54178301ebeSCharles-Antoine Couret * @phydev: target phy_device struct 54278301ebeSCharles-Antoine Couret * 54378301ebeSCharles-Antoine Couret * Description: If auto-negotiation is enabled, we configure the 54478301ebeSCharles-Antoine Couret * advertising, and then restart auto-negotiation. If it is not 54578301ebeSCharles-Antoine Couret * enabled, then we write the BMCR. Adapted for fiber link in 54678301ebeSCharles-Antoine Couret * some Marvell's devices. 54778301ebeSCharles-Antoine Couret */ 54878301ebeSCharles-Antoine Couret static int marvell_config_aneg_fiber(struct phy_device *phydev) 54978301ebeSCharles-Antoine Couret { 55078301ebeSCharles-Antoine Couret int changed = 0; 55178301ebeSCharles-Antoine Couret int err; 55278301ebeSCharles-Antoine Couret int adv, oldadv; 55378301ebeSCharles-Antoine Couret u32 advertise; 55478301ebeSCharles-Antoine Couret 55578301ebeSCharles-Antoine Couret if (phydev->autoneg != AUTONEG_ENABLE) 55678301ebeSCharles-Antoine Couret return genphy_setup_forced(phydev); 55778301ebeSCharles-Antoine Couret 55878301ebeSCharles-Antoine Couret /* Only allow advertising what this PHY supports */ 55978301ebeSCharles-Antoine Couret phydev->advertising &= phydev->supported; 56078301ebeSCharles-Antoine Couret advertise = phydev->advertising; 56178301ebeSCharles-Antoine Couret 56278301ebeSCharles-Antoine Couret /* Setup fiber advertisement */ 56378301ebeSCharles-Antoine Couret adv = phy_read(phydev, MII_ADVERTISE); 56478301ebeSCharles-Antoine Couret if (adv < 0) 56578301ebeSCharles-Antoine Couret return adv; 56678301ebeSCharles-Antoine Couret 56778301ebeSCharles-Antoine Couret oldadv = adv; 56878301ebeSCharles-Antoine Couret adv &= ~(ADVERTISE_FIBER_1000HALF | ADVERTISE_FIBER_1000FULL 56978301ebeSCharles-Antoine Couret | LPA_PAUSE_FIBER); 57078301ebeSCharles-Antoine Couret adv |= ethtool_adv_to_fiber_adv_t(advertise); 57178301ebeSCharles-Antoine Couret 57278301ebeSCharles-Antoine Couret if (adv != oldadv) { 57378301ebeSCharles-Antoine Couret err = phy_write(phydev, MII_ADVERTISE, adv); 57478301ebeSCharles-Antoine Couret if (err < 0) 57578301ebeSCharles-Antoine Couret return err; 57678301ebeSCharles-Antoine Couret 57778301ebeSCharles-Antoine Couret changed = 1; 57878301ebeSCharles-Antoine Couret } 57978301ebeSCharles-Antoine Couret 58078301ebeSCharles-Antoine Couret if (changed == 0) { 58178301ebeSCharles-Antoine Couret /* Advertisement hasn't changed, but maybe aneg was never on to 58278301ebeSCharles-Antoine Couret * begin with? Or maybe phy was isolated? 58378301ebeSCharles-Antoine Couret */ 58478301ebeSCharles-Antoine Couret int ctl = phy_read(phydev, MII_BMCR); 58578301ebeSCharles-Antoine Couret 58678301ebeSCharles-Antoine Couret if (ctl < 0) 58778301ebeSCharles-Antoine Couret return ctl; 58878301ebeSCharles-Antoine Couret 58978301ebeSCharles-Antoine Couret if (!(ctl & BMCR_ANENABLE) || (ctl & BMCR_ISOLATE)) 59078301ebeSCharles-Antoine Couret changed = 1; /* do restart aneg */ 59178301ebeSCharles-Antoine Couret } 59278301ebeSCharles-Antoine Couret 59378301ebeSCharles-Antoine Couret /* Only restart aneg if we are advertising something different 59478301ebeSCharles-Antoine Couret * than we were before. 59578301ebeSCharles-Antoine Couret */ 59678301ebeSCharles-Antoine Couret if (changed > 0) 59778301ebeSCharles-Antoine Couret changed = genphy_restart_aneg(phydev); 59878301ebeSCharles-Antoine Couret 59978301ebeSCharles-Antoine Couret return changed; 60078301ebeSCharles-Antoine Couret } 60178301ebeSCharles-Antoine Couret 60210e24caaSMichal Simek static int m88e1510_config_aneg(struct phy_device *phydev) 60310e24caaSMichal Simek { 60410e24caaSMichal Simek int err; 60510e24caaSMichal Simek 60652295666SAndrew Lunn err = marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE); 60778301ebeSCharles-Antoine Couret if (err < 0) 60878301ebeSCharles-Antoine Couret goto error; 60978301ebeSCharles-Antoine Couret 61078301ebeSCharles-Antoine Couret /* Configure the copper link first */ 61110e24caaSMichal Simek err = m88e1318_config_aneg(phydev); 61210e24caaSMichal Simek if (err < 0) 61378301ebeSCharles-Antoine Couret goto error; 61410e24caaSMichal Simek 615de9c4e06SRussell King /* Do not touch the fiber page if we're in copper->sgmii mode */ 616de9c4e06SRussell King if (phydev->interface == PHY_INTERFACE_MODE_SGMII) 617de9c4e06SRussell King return 0; 618de9c4e06SRussell King 61978301ebeSCharles-Antoine Couret /* Then the fiber link */ 62052295666SAndrew Lunn err = marvell_set_page(phydev, MII_MARVELL_FIBER_PAGE); 62178301ebeSCharles-Antoine Couret if (err < 0) 62278301ebeSCharles-Antoine Couret goto error; 62378301ebeSCharles-Antoine Couret 62478301ebeSCharles-Antoine Couret err = marvell_config_aneg_fiber(phydev); 62578301ebeSCharles-Antoine Couret if (err < 0) 62678301ebeSCharles-Antoine Couret goto error; 62778301ebeSCharles-Antoine Couret 62852295666SAndrew Lunn return marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE); 62978301ebeSCharles-Antoine Couret 63078301ebeSCharles-Antoine Couret error: 63152295666SAndrew Lunn marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE); 63278301ebeSCharles-Antoine Couret return err; 63379be1a1cSClemens Gruber } 63479be1a1cSClemens Gruber 63579be1a1cSClemens Gruber static int marvell_config_init(struct phy_device *phydev) 63679be1a1cSClemens Gruber { 63779be1a1cSClemens Gruber /* Set registers from marvell,reg-init DT property */ 63810e24caaSMichal Simek return marvell_of_reg_init(phydev); 63910e24caaSMichal Simek } 64010e24caaSMichal Simek 6413da09a51SMichal Simek static int m88e1116r_config_init(struct phy_device *phydev) 6423da09a51SMichal Simek { 6433da09a51SMichal Simek int err; 6443da09a51SMichal Simek 64534386344SAndrew Lunn err = genphy_soft_reset(phydev); 6463da09a51SMichal Simek if (err < 0) 6473da09a51SMichal Simek return err; 6483da09a51SMichal Simek 6493da09a51SMichal Simek mdelay(500); 6503da09a51SMichal Simek 65152295666SAndrew Lunn err = marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE); 6523da09a51SMichal Simek if (err < 0) 6533da09a51SMichal Simek return err; 6543da09a51SMichal Simek 655fecd5e91SAndrew Lunn err = marvell_set_polarity(phydev, phydev->mdix_ctrl); 656fecd5e91SAndrew Lunn if (err < 0) 657fecd5e91SAndrew Lunn return err; 658fecd5e91SAndrew Lunn 6596ef05eb7SAndrew Lunn err = marvell_set_downshift(phydev, true, 8); 6603da09a51SMichal Simek if (err < 0) 6613da09a51SMichal Simek return err; 6623da09a51SMichal Simek 66314fc0abaSAndrew Lunn if (phy_interface_is_rgmii(phydev)) { 664864dc729SAndrew Lunn err = m88e1121_config_aneg_rgmii_delays(phydev); 6653da09a51SMichal Simek if (err < 0) 6663da09a51SMichal Simek return err; 66714fc0abaSAndrew Lunn } 6683da09a51SMichal Simek 66934386344SAndrew Lunn err = genphy_soft_reset(phydev); 6703da09a51SMichal Simek if (err < 0) 6713da09a51SMichal Simek return err; 6723da09a51SMichal Simek 67379be1a1cSClemens Gruber return marvell_config_init(phydev); 6743da09a51SMichal Simek } 6753da09a51SMichal Simek 6766b358aedSSebastian Hesselbarth static int m88e3016_config_init(struct phy_device *phydev) 6776b358aedSSebastian Hesselbarth { 678fea23fb5SRussell King int ret; 6796b358aedSSebastian Hesselbarth 6806b358aedSSebastian Hesselbarth /* Enable Scrambler and Auto-Crossover */ 681fea23fb5SRussell King ret = phy_modify(phydev, MII_88E3016_PHY_SPEC_CTRL, 682f102852fSRussell King MII_88E3016_DISABLE_SCRAMBLER, 683fea23fb5SRussell King MII_88E3016_AUTO_MDIX_CROSSOVER); 684fea23fb5SRussell King if (ret < 0) 685fea23fb5SRussell King return ret; 6866b358aedSSebastian Hesselbarth 68779be1a1cSClemens Gruber return marvell_config_init(phydev); 6886b358aedSSebastian Hesselbarth } 6896b358aedSSebastian Hesselbarth 690865b813aSAndrew Lunn static int m88e1111_config_init_hwcfg_mode(struct phy_device *phydev, 691865b813aSAndrew Lunn u16 mode, 692865b813aSAndrew Lunn int fibre_copper_auto) 693865b813aSAndrew Lunn { 694865b813aSAndrew Lunn if (fibre_copper_auto) 695fea23fb5SRussell King mode |= MII_M1111_HWCFG_FIBER_COPPER_AUTO; 696865b813aSAndrew Lunn 697fea23fb5SRussell King return phy_modify(phydev, MII_M1111_PHY_EXT_SR, 698f102852fSRussell King MII_M1111_HWCFG_MODE_MASK | 699fea23fb5SRussell King MII_M1111_HWCFG_FIBER_COPPER_AUTO | 700f102852fSRussell King MII_M1111_HWCFG_FIBER_COPPER_RES, 701fea23fb5SRussell King mode); 702865b813aSAndrew Lunn } 703865b813aSAndrew Lunn 70461111598SAndrew Lunn static int m88e1111_config_init_rgmii_delays(struct phy_device *phydev) 705895ee682SKim Phillips { 706fea23fb5SRussell King int delay; 707895ee682SKim Phillips 7089daf5a76SKim Phillips if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID) { 709fea23fb5SRussell King delay = MII_M1111_RGMII_RX_DELAY | MII_M1111_RGMII_TX_DELAY; 7109daf5a76SKim Phillips } else if (phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID) { 711fea23fb5SRussell King delay = MII_M1111_RGMII_RX_DELAY; 7129daf5a76SKim Phillips } else if (phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID) { 713fea23fb5SRussell King delay = MII_M1111_RGMII_TX_DELAY; 714fea23fb5SRussell King } else { 715fea23fb5SRussell King delay = 0; 7169daf5a76SKim Phillips } 717895ee682SKim Phillips 718fea23fb5SRussell King return phy_modify(phydev, MII_M1111_PHY_EXT_CR, 719f102852fSRussell King MII_M1111_RGMII_RX_DELAY | MII_M1111_RGMII_TX_DELAY, 720fea23fb5SRussell King delay); 72161111598SAndrew Lunn } 72261111598SAndrew Lunn 72361111598SAndrew Lunn static int m88e1111_config_init_rgmii(struct phy_device *phydev) 72461111598SAndrew Lunn { 72561111598SAndrew Lunn int temp; 72661111598SAndrew Lunn int err; 72761111598SAndrew Lunn 72861111598SAndrew Lunn err = m88e1111_config_init_rgmii_delays(phydev); 729895ee682SKim Phillips if (err < 0) 730895ee682SKim Phillips return err; 731895ee682SKim Phillips 732895ee682SKim Phillips temp = phy_read(phydev, MII_M1111_PHY_EXT_SR); 733895ee682SKim Phillips if (temp < 0) 734895ee682SKim Phillips return temp; 735895ee682SKim Phillips 736895ee682SKim Phillips temp &= ~(MII_M1111_HWCFG_MODE_MASK); 737be937f1fSAlexandr Smirnov 7387239016dSWang Jian if (temp & MII_M1111_HWCFG_FIBER_COPPER_RES) 739be937f1fSAlexandr Smirnov temp |= MII_M1111_HWCFG_MODE_FIBER_RGMII; 740be937f1fSAlexandr Smirnov else 741be937f1fSAlexandr Smirnov temp |= MII_M1111_HWCFG_MODE_COPPER_RGMII; 742895ee682SKim Phillips 743e1dde8dcSAndrew Lunn return phy_write(phydev, MII_M1111_PHY_EXT_SR, temp); 744895ee682SKim Phillips } 745895ee682SKim Phillips 746e1dde8dcSAndrew Lunn static int m88e1111_config_init_sgmii(struct phy_device *phydev) 747e1dde8dcSAndrew Lunn { 748e1dde8dcSAndrew Lunn int err; 749e1dde8dcSAndrew Lunn 750865b813aSAndrew Lunn err = m88e1111_config_init_hwcfg_mode( 751865b813aSAndrew Lunn phydev, 752865b813aSAndrew Lunn MII_M1111_HWCFG_MODE_SGMII_NO_CLK, 753865b813aSAndrew Lunn MII_M1111_HWCFG_FIBER_COPPER_AUTO); 7544117b5beSKapil Juneja if (err < 0) 7554117b5beSKapil Juneja return err; 75607151bc9SMadalin Bucur 75707151bc9SMadalin Bucur /* make sure copper is selected */ 75852295666SAndrew Lunn return marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE); 7594117b5beSKapil Juneja } 7604117b5beSKapil Juneja 761e1dde8dcSAndrew Lunn static int m88e1111_config_init_rtbi(struct phy_device *phydev) 762e1dde8dcSAndrew Lunn { 76361111598SAndrew Lunn int err; 764e1dde8dcSAndrew Lunn 76561111598SAndrew Lunn err = m88e1111_config_init_rgmii_delays(phydev); 766fea23fb5SRussell King if (err < 0) 7675f8cbc13SLiu Yu-B13201 return err; 7685f8cbc13SLiu Yu-B13201 769865b813aSAndrew Lunn err = m88e1111_config_init_hwcfg_mode( 770865b813aSAndrew Lunn phydev, 771865b813aSAndrew Lunn MII_M1111_HWCFG_MODE_RTBI, 772865b813aSAndrew Lunn MII_M1111_HWCFG_FIBER_COPPER_AUTO); 7735f8cbc13SLiu Yu-B13201 if (err < 0) 7745f8cbc13SLiu Yu-B13201 return err; 7755f8cbc13SLiu Yu-B13201 7765f8cbc13SLiu Yu-B13201 /* soft reset */ 77734386344SAndrew Lunn err = genphy_soft_reset(phydev); 7785f8cbc13SLiu Yu-B13201 if (err < 0) 7795f8cbc13SLiu Yu-B13201 return err; 780e1dde8dcSAndrew Lunn 781865b813aSAndrew Lunn return m88e1111_config_init_hwcfg_mode( 782865b813aSAndrew Lunn phydev, 783865b813aSAndrew Lunn MII_M1111_HWCFG_MODE_RTBI, 784865b813aSAndrew Lunn MII_M1111_HWCFG_FIBER_COPPER_AUTO); 785e1dde8dcSAndrew Lunn } 786e1dde8dcSAndrew Lunn 787e1dde8dcSAndrew Lunn static int m88e1111_config_init(struct phy_device *phydev) 788e1dde8dcSAndrew Lunn { 789e1dde8dcSAndrew Lunn int err; 790e1dde8dcSAndrew Lunn 791e1dde8dcSAndrew Lunn if (phy_interface_is_rgmii(phydev)) { 792e1dde8dcSAndrew Lunn err = m88e1111_config_init_rgmii(phydev); 793fea23fb5SRussell King if (err < 0) 794e1dde8dcSAndrew Lunn return err; 795e1dde8dcSAndrew Lunn } 796e1dde8dcSAndrew Lunn 797e1dde8dcSAndrew Lunn if (phydev->interface == PHY_INTERFACE_MODE_SGMII) { 798e1dde8dcSAndrew Lunn err = m88e1111_config_init_sgmii(phydev); 799e1dde8dcSAndrew Lunn if (err < 0) 800e1dde8dcSAndrew Lunn return err; 801e1dde8dcSAndrew Lunn } 802e1dde8dcSAndrew Lunn 803e1dde8dcSAndrew Lunn if (phydev->interface == PHY_INTERFACE_MODE_RTBI) { 804e1dde8dcSAndrew Lunn err = m88e1111_config_init_rtbi(phydev); 8055f8cbc13SLiu Yu-B13201 if (err < 0) 8065f8cbc13SLiu Yu-B13201 return err; 8075f8cbc13SLiu Yu-B13201 } 8085f8cbc13SLiu Yu-B13201 809cf41a51dSDavid Daney err = marvell_of_reg_init(phydev); 810cf41a51dSDavid Daney if (err < 0) 811cf41a51dSDavid Daney return err; 8125f8cbc13SLiu Yu-B13201 81334386344SAndrew Lunn return genphy_soft_reset(phydev); 814895ee682SKim Phillips } 815895ee682SKim Phillips 816fdecf36fSClemens Gruber static int m88e1121_config_init(struct phy_device *phydev) 817fdecf36fSClemens Gruber { 818424ca4c5SRussell King int err; 819fdecf36fSClemens Gruber 820fdecf36fSClemens Gruber /* Default PHY LED config: LED[0] .. Link, LED[1] .. Activity */ 821424ca4c5SRussell King err = phy_write_paged(phydev, MII_MARVELL_LED_PAGE, 822424ca4c5SRussell King MII_88E1121_PHY_LED_CTRL, 823fdecf36fSClemens Gruber MII_88E1121_PHY_LED_DEF); 824fdecf36fSClemens Gruber if (err < 0) 825fdecf36fSClemens Gruber return err; 826fdecf36fSClemens Gruber 827fdecf36fSClemens Gruber /* Set marvell,reg-init configuration from device tree */ 828fdecf36fSClemens Gruber return marvell_config_init(phydev); 829fdecf36fSClemens Gruber } 830fdecf36fSClemens Gruber 831dd9a122aSEsben Haabendal static int m88e1318_config_init(struct phy_device *phydev) 832dd9a122aSEsben Haabendal { 833dd9a122aSEsben Haabendal if (phy_interrupt_is_valid(phydev)) { 834dd9a122aSEsben Haabendal int err = phy_modify_paged( 835dd9a122aSEsben Haabendal phydev, MII_MARVELL_LED_PAGE, 836dd9a122aSEsben Haabendal MII_88E1318S_PHY_LED_TCR, 837dd9a122aSEsben Haabendal MII_88E1318S_PHY_LED_TCR_FORCE_INT, 838dd9a122aSEsben Haabendal MII_88E1318S_PHY_LED_TCR_INTn_ENABLE | 839dd9a122aSEsben Haabendal MII_88E1318S_PHY_LED_TCR_INT_ACTIVE_LOW); 840dd9a122aSEsben Haabendal if (err < 0) 841dd9a122aSEsben Haabendal return err; 842dd9a122aSEsben Haabendal } 843dd9a122aSEsben Haabendal 844dd9a122aSEsben Haabendal return m88e1121_config_init(phydev); 845dd9a122aSEsben Haabendal } 846dd9a122aSEsben Haabendal 847407353ecSClemens Gruber static int m88e1510_config_init(struct phy_device *phydev) 848407353ecSClemens Gruber { 849407353ecSClemens Gruber int err; 850407353ecSClemens Gruber 851407353ecSClemens Gruber /* SGMII-to-Copper mode initialization */ 852407353ecSClemens Gruber if (phydev->interface == PHY_INTERFACE_MODE_SGMII) { 8536623c0fbSRussell King u32 pause; 8546623c0fbSRussell King 855407353ecSClemens Gruber /* Select page 18 */ 8566427bb2dSAndrew Lunn err = marvell_set_page(phydev, 18); 857407353ecSClemens Gruber if (err < 0) 858407353ecSClemens Gruber return err; 859407353ecSClemens Gruber 860407353ecSClemens Gruber /* In reg 20, write MODE[2:0] = 0x1 (SGMII to Copper) */ 861fea23fb5SRussell King err = phy_modify(phydev, MII_88E1510_GEN_CTRL_REG_1, 862f102852fSRussell King MII_88E1510_GEN_CTRL_REG_1_MODE_MASK, 863fea23fb5SRussell King MII_88E1510_GEN_CTRL_REG_1_MODE_SGMII); 864407353ecSClemens Gruber if (err < 0) 865407353ecSClemens Gruber return err; 866407353ecSClemens Gruber 867407353ecSClemens Gruber /* PHY reset is necessary after changing MODE[2:0] */ 868fea23fb5SRussell King err = phy_modify(phydev, MII_88E1510_GEN_CTRL_REG_1, 0, 869fea23fb5SRussell King MII_88E1510_GEN_CTRL_REG_1_RESET); 870407353ecSClemens Gruber if (err < 0) 871407353ecSClemens Gruber return err; 872407353ecSClemens Gruber 873407353ecSClemens Gruber /* Reset page selection */ 87452295666SAndrew Lunn err = marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE); 875407353ecSClemens Gruber if (err < 0) 876407353ecSClemens Gruber return err; 8776623c0fbSRussell King 8786623c0fbSRussell King /* There appears to be a bug in the 88e1512 when used in 879cc1122b0SColin Ian King * SGMII to copper mode, where the AN advertisement register 8806623c0fbSRussell King * clears the pause bits each time a negotiation occurs. 8816623c0fbSRussell King * This means we can never be truely sure what was advertised, 8826623c0fbSRussell King * so disable Pause support. 8836623c0fbSRussell King */ 8846623c0fbSRussell King pause = SUPPORTED_Pause | SUPPORTED_Asym_Pause; 8856623c0fbSRussell King phydev->supported &= ~pause; 8866623c0fbSRussell King phydev->advertising &= ~pause; 887407353ecSClemens Gruber } 888407353ecSClemens Gruber 889dd9a122aSEsben Haabendal return m88e1318_config_init(phydev); 890407353ecSClemens Gruber } 891407353ecSClemens Gruber 892605f196eSRon Madrid static int m88e1118_config_aneg(struct phy_device *phydev) 893605f196eSRon Madrid { 894605f196eSRon Madrid int err; 895605f196eSRon Madrid 89634386344SAndrew Lunn err = genphy_soft_reset(phydev); 897605f196eSRon Madrid if (err < 0) 898605f196eSRon Madrid return err; 899605f196eSRon Madrid 900fecd5e91SAndrew Lunn err = marvell_set_polarity(phydev, phydev->mdix_ctrl); 901605f196eSRon Madrid if (err < 0) 902605f196eSRon Madrid return err; 903605f196eSRon Madrid 904605f196eSRon Madrid err = genphy_config_aneg(phydev); 905605f196eSRon Madrid return 0; 906605f196eSRon Madrid } 907605f196eSRon Madrid 908605f196eSRon Madrid static int m88e1118_config_init(struct phy_device *phydev) 909605f196eSRon Madrid { 910605f196eSRon Madrid int err; 911605f196eSRon Madrid 912605f196eSRon Madrid /* Change address */ 91352295666SAndrew Lunn err = marvell_set_page(phydev, MII_MARVELL_MSCR_PAGE); 914605f196eSRon Madrid if (err < 0) 915605f196eSRon Madrid return err; 916605f196eSRon Madrid 917605f196eSRon Madrid /* Enable 1000 Mbit */ 918605f196eSRon Madrid err = phy_write(phydev, 0x15, 0x1070); 919605f196eSRon Madrid if (err < 0) 920605f196eSRon Madrid return err; 921605f196eSRon Madrid 922605f196eSRon Madrid /* Change address */ 92352295666SAndrew Lunn err = marvell_set_page(phydev, MII_MARVELL_LED_PAGE); 924605f196eSRon Madrid if (err < 0) 925605f196eSRon Madrid return err; 926605f196eSRon Madrid 927605f196eSRon Madrid /* Adjust LED Control */ 9282f495c39SBenjamin Herrenschmidt if (phydev->dev_flags & MARVELL_PHY_M1118_DNS323_LEDS) 9292f495c39SBenjamin Herrenschmidt err = phy_write(phydev, 0x10, 0x1100); 9302f495c39SBenjamin Herrenschmidt else 931605f196eSRon Madrid err = phy_write(phydev, 0x10, 0x021e); 932605f196eSRon Madrid if (err < 0) 933605f196eSRon Madrid return err; 934605f196eSRon Madrid 935cf41a51dSDavid Daney err = marvell_of_reg_init(phydev); 936cf41a51dSDavid Daney if (err < 0) 937cf41a51dSDavid Daney return err; 938cf41a51dSDavid Daney 939605f196eSRon Madrid /* Reset address */ 94052295666SAndrew Lunn err = marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE); 941605f196eSRon Madrid if (err < 0) 942605f196eSRon Madrid return err; 943605f196eSRon Madrid 94434386344SAndrew Lunn return genphy_soft_reset(phydev); 945605f196eSRon Madrid } 946605f196eSRon Madrid 94790600732SDavid Daney static int m88e1149_config_init(struct phy_device *phydev) 94890600732SDavid Daney { 94990600732SDavid Daney int err; 95090600732SDavid Daney 95190600732SDavid Daney /* Change address */ 95252295666SAndrew Lunn err = marvell_set_page(phydev, MII_MARVELL_MSCR_PAGE); 95390600732SDavid Daney if (err < 0) 95490600732SDavid Daney return err; 95590600732SDavid Daney 95690600732SDavid Daney /* Enable 1000 Mbit */ 95790600732SDavid Daney err = phy_write(phydev, 0x15, 0x1048); 95890600732SDavid Daney if (err < 0) 95990600732SDavid Daney return err; 96090600732SDavid Daney 961cf41a51dSDavid Daney err = marvell_of_reg_init(phydev); 962cf41a51dSDavid Daney if (err < 0) 963cf41a51dSDavid Daney return err; 964cf41a51dSDavid Daney 96590600732SDavid Daney /* Reset address */ 96652295666SAndrew Lunn err = marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE); 96790600732SDavid Daney if (err < 0) 96890600732SDavid Daney return err; 96990600732SDavid Daney 97034386344SAndrew Lunn return genphy_soft_reset(phydev); 97190600732SDavid Daney } 97290600732SDavid Daney 973e1dde8dcSAndrew Lunn static int m88e1145_config_init_rgmii(struct phy_device *phydev) 97476884679SAndy Fleming { 97576884679SAndy Fleming int err; 976e69d9ed4SAndrew Lunn 97761111598SAndrew Lunn err = m88e1111_config_init_rgmii_delays(phydev); 97876884679SAndy Fleming if (err < 0) 97976884679SAndy Fleming return err; 98076884679SAndy Fleming 9812f495c39SBenjamin Herrenschmidt if (phydev->dev_flags & MARVELL_PHY_M1145_FLAGS_RESISTANCE) { 98276884679SAndy Fleming err = phy_write(phydev, 0x1d, 0x0012); 98376884679SAndy Fleming if (err < 0) 98476884679SAndy Fleming return err; 98576884679SAndy Fleming 986f102852fSRussell King err = phy_modify(phydev, 0x1e, 0x0fc0, 987fea23fb5SRussell King 2 << 9 | /* 36 ohm */ 988fea23fb5SRussell King 2 << 6); /* 39 ohm */ 98976884679SAndy Fleming if (err < 0) 99076884679SAndy Fleming return err; 99176884679SAndy Fleming 99276884679SAndy Fleming err = phy_write(phydev, 0x1d, 0x3); 99376884679SAndy Fleming if (err < 0) 99476884679SAndy Fleming return err; 99576884679SAndy Fleming 99676884679SAndy Fleming err = phy_write(phydev, 0x1e, 0x8000); 997e1dde8dcSAndrew Lunn } 99876884679SAndy Fleming return err; 99976884679SAndy Fleming } 100076884679SAndy Fleming 1001e1dde8dcSAndrew Lunn static int m88e1145_config_init_sgmii(struct phy_device *phydev) 1002e1dde8dcSAndrew Lunn { 1003865b813aSAndrew Lunn return m88e1111_config_init_hwcfg_mode( 1004865b813aSAndrew Lunn phydev, MII_M1111_HWCFG_MODE_SGMII_NO_CLK, 1005865b813aSAndrew Lunn MII_M1111_HWCFG_FIBER_COPPER_AUTO); 1006e1dde8dcSAndrew Lunn } 1007e1dde8dcSAndrew Lunn 1008e1dde8dcSAndrew Lunn static int m88e1145_config_init(struct phy_device *phydev) 1009e1dde8dcSAndrew Lunn { 1010e1dde8dcSAndrew Lunn int err; 1011e1dde8dcSAndrew Lunn 1012e1dde8dcSAndrew Lunn /* Take care of errata E0 & E1 */ 1013e1dde8dcSAndrew Lunn err = phy_write(phydev, 0x1d, 0x001b); 1014e1dde8dcSAndrew Lunn if (err < 0) 1015e1dde8dcSAndrew Lunn return err; 1016e1dde8dcSAndrew Lunn 1017e1dde8dcSAndrew Lunn err = phy_write(phydev, 0x1e, 0x418f); 1018e1dde8dcSAndrew Lunn if (err < 0) 1019e1dde8dcSAndrew Lunn return err; 1020e1dde8dcSAndrew Lunn 1021e1dde8dcSAndrew Lunn err = phy_write(phydev, 0x1d, 0x0016); 1022e1dde8dcSAndrew Lunn if (err < 0) 1023e1dde8dcSAndrew Lunn return err; 1024e1dde8dcSAndrew Lunn 1025e1dde8dcSAndrew Lunn err = phy_write(phydev, 0x1e, 0xa2da); 1026e1dde8dcSAndrew Lunn if (err < 0) 1027e1dde8dcSAndrew Lunn return err; 1028e1dde8dcSAndrew Lunn 1029e1dde8dcSAndrew Lunn if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID) { 1030e1dde8dcSAndrew Lunn err = m88e1145_config_init_rgmii(phydev); 1031e1dde8dcSAndrew Lunn if (err < 0) 1032e1dde8dcSAndrew Lunn return err; 1033e1dde8dcSAndrew Lunn } 1034e1dde8dcSAndrew Lunn 1035e1dde8dcSAndrew Lunn if (phydev->interface == PHY_INTERFACE_MODE_SGMII) { 1036e1dde8dcSAndrew Lunn err = m88e1145_config_init_sgmii(phydev); 1037b0224175SViet Nga Dao if (err < 0) 1038b0224175SViet Nga Dao return err; 1039b0224175SViet Nga Dao } 1040b0224175SViet Nga Dao 1041cf41a51dSDavid Daney err = marvell_of_reg_init(phydev); 1042cf41a51dSDavid Daney if (err < 0) 1043cf41a51dSDavid Daney return err; 1044cf41a51dSDavid Daney 104576884679SAndy Fleming return 0; 104676884679SAndy Fleming } 104700db8189SAndy Fleming 10486cfb3bccSCharles-Antoine Couret /** 10496cfb3bccSCharles-Antoine Couret * fiber_lpa_to_ethtool_lpa_t 10506cfb3bccSCharles-Antoine Couret * @lpa: value of the MII_LPA register for fiber link 1051be937f1fSAlexandr Smirnov * 10526cfb3bccSCharles-Antoine Couret * A small helper function that translates MII_LPA 10536cfb3bccSCharles-Antoine Couret * bits to ethtool LP advertisement settings. 10546cfb3bccSCharles-Antoine Couret */ 10556cfb3bccSCharles-Antoine Couret static u32 fiber_lpa_to_ethtool_lpa_t(u32 lpa) 10566cfb3bccSCharles-Antoine Couret { 10576cfb3bccSCharles-Antoine Couret u32 result = 0; 10586cfb3bccSCharles-Antoine Couret 10596cfb3bccSCharles-Antoine Couret if (lpa & LPA_FIBER_1000HALF) 10606cfb3bccSCharles-Antoine Couret result |= ADVERTISED_1000baseT_Half; 10616cfb3bccSCharles-Antoine Couret if (lpa & LPA_FIBER_1000FULL) 10626cfb3bccSCharles-Antoine Couret result |= ADVERTISED_1000baseT_Full; 10636cfb3bccSCharles-Antoine Couret 10646cfb3bccSCharles-Antoine Couret return result; 10656cfb3bccSCharles-Antoine Couret } 10666cfb3bccSCharles-Antoine Couret 10676cfb3bccSCharles-Antoine Couret /** 10686cfb3bccSCharles-Antoine Couret * marvell_update_link - update link status in real time in @phydev 10696cfb3bccSCharles-Antoine Couret * @phydev: target phy_device struct 10706cfb3bccSCharles-Antoine Couret * 10716cfb3bccSCharles-Antoine Couret * Description: Update the value in phydev->link to reflect the 10726cfb3bccSCharles-Antoine Couret * current link value. 10736cfb3bccSCharles-Antoine Couret */ 10746cfb3bccSCharles-Antoine Couret static int marvell_update_link(struct phy_device *phydev, int fiber) 10756cfb3bccSCharles-Antoine Couret { 10766cfb3bccSCharles-Antoine Couret int status; 10776cfb3bccSCharles-Antoine Couret 10786cfb3bccSCharles-Antoine Couret /* Use the generic register for copper link, or specific 10790c3439bcSAndrew Lunn * register for fiber case 10800c3439bcSAndrew Lunn */ 10816cfb3bccSCharles-Antoine Couret if (fiber) { 10826cfb3bccSCharles-Antoine Couret status = phy_read(phydev, MII_M1011_PHY_STATUS); 10836cfb3bccSCharles-Antoine Couret if (status < 0) 10846cfb3bccSCharles-Antoine Couret return status; 10856cfb3bccSCharles-Antoine Couret 10866cfb3bccSCharles-Antoine Couret if ((status & REGISTER_LINK_STATUS) == 0) 10876cfb3bccSCharles-Antoine Couret phydev->link = 0; 10886cfb3bccSCharles-Antoine Couret else 10896cfb3bccSCharles-Antoine Couret phydev->link = 1; 10906cfb3bccSCharles-Antoine Couret } else { 10916cfb3bccSCharles-Antoine Couret return genphy_update_link(phydev); 10926cfb3bccSCharles-Antoine Couret } 10936cfb3bccSCharles-Antoine Couret 10946cfb3bccSCharles-Antoine Couret return 0; 10956cfb3bccSCharles-Antoine Couret } 10966cfb3bccSCharles-Antoine Couret 1097e1dde8dcSAndrew Lunn static int marvell_read_status_page_an(struct phy_device *phydev, 1098e1dde8dcSAndrew Lunn int fiber) 1099be937f1fSAlexandr Smirnov { 1100e1dde8dcSAndrew Lunn int status; 1101be937f1fSAlexandr Smirnov int lpa; 1102357cd64cSRussell King int lpagb; 1103be937f1fSAlexandr Smirnov 1104be937f1fSAlexandr Smirnov status = phy_read(phydev, MII_M1011_PHY_STATUS); 1105be937f1fSAlexandr Smirnov if (status < 0) 1106be937f1fSAlexandr Smirnov return status; 1107be937f1fSAlexandr Smirnov 1108be937f1fSAlexandr Smirnov lpa = phy_read(phydev, MII_LPA); 1109be937f1fSAlexandr Smirnov if (lpa < 0) 1110be937f1fSAlexandr Smirnov return lpa; 1111be937f1fSAlexandr Smirnov 1112357cd64cSRussell King lpagb = phy_read(phydev, MII_STAT1000); 1113357cd64cSRussell King if (lpagb < 0) 1114357cd64cSRussell King return lpagb; 1115357cd64cSRussell King 1116be937f1fSAlexandr Smirnov if (status & MII_M1011_PHY_STATUS_FULLDUPLEX) 1117be937f1fSAlexandr Smirnov phydev->duplex = DUPLEX_FULL; 1118be937f1fSAlexandr Smirnov else 1119be937f1fSAlexandr Smirnov phydev->duplex = DUPLEX_HALF; 1120be937f1fSAlexandr Smirnov 1121be937f1fSAlexandr Smirnov status = status & MII_M1011_PHY_STATUS_SPD_MASK; 11224f48ed32SAndrew Lunn phydev->pause = 0; 11234f48ed32SAndrew Lunn phydev->asym_pause = 0; 1124be937f1fSAlexandr Smirnov 1125be937f1fSAlexandr Smirnov switch (status) { 1126be937f1fSAlexandr Smirnov case MII_M1011_PHY_STATUS_1000: 1127be937f1fSAlexandr Smirnov phydev->speed = SPEED_1000; 1128be937f1fSAlexandr Smirnov break; 1129be937f1fSAlexandr Smirnov 1130be937f1fSAlexandr Smirnov case MII_M1011_PHY_STATUS_100: 1131be937f1fSAlexandr Smirnov phydev->speed = SPEED_100; 1132be937f1fSAlexandr Smirnov break; 1133be937f1fSAlexandr Smirnov 1134be937f1fSAlexandr Smirnov default: 1135be937f1fSAlexandr Smirnov phydev->speed = SPEED_10; 1136be937f1fSAlexandr Smirnov break; 1137be937f1fSAlexandr Smirnov } 1138be937f1fSAlexandr Smirnov 11396cfb3bccSCharles-Antoine Couret if (!fiber) { 1140e1dde8dcSAndrew Lunn phydev->lp_advertising = 1141e1dde8dcSAndrew Lunn mii_stat1000_to_ethtool_lpa_t(lpagb) | 11426cfb3bccSCharles-Antoine Couret mii_lpa_to_ethtool_lpa_t(lpa); 11436cfb3bccSCharles-Antoine Couret 1144be937f1fSAlexandr Smirnov if (phydev->duplex == DUPLEX_FULL) { 1145be937f1fSAlexandr Smirnov phydev->pause = lpa & LPA_PAUSE_CAP ? 1 : 0; 1146be937f1fSAlexandr Smirnov phydev->asym_pause = lpa & LPA_PAUSE_ASYM ? 1 : 0; 1147be937f1fSAlexandr Smirnov } 1148be937f1fSAlexandr Smirnov } else { 11496cfb3bccSCharles-Antoine Couret /* The fiber link is only 1000M capable */ 11506cfb3bccSCharles-Antoine Couret phydev->lp_advertising = fiber_lpa_to_ethtool_lpa_t(lpa); 11516cfb3bccSCharles-Antoine Couret 11526cfb3bccSCharles-Antoine Couret if (phydev->duplex == DUPLEX_FULL) { 11536cfb3bccSCharles-Antoine Couret if (!(lpa & LPA_PAUSE_FIBER)) { 11546cfb3bccSCharles-Antoine Couret phydev->pause = 0; 11556cfb3bccSCharles-Antoine Couret phydev->asym_pause = 0; 11566cfb3bccSCharles-Antoine Couret } else if ((lpa & LPA_PAUSE_ASYM_FIBER)) { 11576cfb3bccSCharles-Antoine Couret phydev->pause = 1; 11586cfb3bccSCharles-Antoine Couret phydev->asym_pause = 1; 11596cfb3bccSCharles-Antoine Couret } else { 11606cfb3bccSCharles-Antoine Couret phydev->pause = 1; 11616cfb3bccSCharles-Antoine Couret phydev->asym_pause = 0; 11626cfb3bccSCharles-Antoine Couret } 11636cfb3bccSCharles-Antoine Couret } 11646cfb3bccSCharles-Antoine Couret } 1165e1dde8dcSAndrew Lunn return 0; 1166e1dde8dcSAndrew Lunn } 1167e1dde8dcSAndrew Lunn 1168e1dde8dcSAndrew Lunn static int marvell_read_status_page_fixed(struct phy_device *phydev) 1169e1dde8dcSAndrew Lunn { 1170be937f1fSAlexandr Smirnov int bmcr = phy_read(phydev, MII_BMCR); 1171be937f1fSAlexandr Smirnov 1172be937f1fSAlexandr Smirnov if (bmcr < 0) 1173be937f1fSAlexandr Smirnov return bmcr; 1174be937f1fSAlexandr Smirnov 1175be937f1fSAlexandr Smirnov if (bmcr & BMCR_FULLDPLX) 1176be937f1fSAlexandr Smirnov phydev->duplex = DUPLEX_FULL; 1177be937f1fSAlexandr Smirnov else 1178be937f1fSAlexandr Smirnov phydev->duplex = DUPLEX_HALF; 1179be937f1fSAlexandr Smirnov 1180be937f1fSAlexandr Smirnov if (bmcr & BMCR_SPEED1000) 1181be937f1fSAlexandr Smirnov phydev->speed = SPEED_1000; 1182be937f1fSAlexandr Smirnov else if (bmcr & BMCR_SPEED100) 1183be937f1fSAlexandr Smirnov phydev->speed = SPEED_100; 1184be937f1fSAlexandr Smirnov else 1185be937f1fSAlexandr Smirnov phydev->speed = SPEED_10; 1186be937f1fSAlexandr Smirnov 11874f48ed32SAndrew Lunn phydev->pause = 0; 11884f48ed32SAndrew Lunn phydev->asym_pause = 0; 1189357cd64cSRussell King phydev->lp_advertising = 0; 1190be937f1fSAlexandr Smirnov 1191be937f1fSAlexandr Smirnov return 0; 1192be937f1fSAlexandr Smirnov } 1193be937f1fSAlexandr Smirnov 1194e1dde8dcSAndrew Lunn /* marvell_read_status_page 1195e1dde8dcSAndrew Lunn * 1196e1dde8dcSAndrew Lunn * Description: 1197e1dde8dcSAndrew Lunn * Check the link, then figure out the current state 1198e1dde8dcSAndrew Lunn * by comparing what we advertise with what the link partner 1199e1dde8dcSAndrew Lunn * advertises. Start by checking the gigabit possibilities, 1200e1dde8dcSAndrew Lunn * then move on to 10/100. 1201e1dde8dcSAndrew Lunn */ 1202e1dde8dcSAndrew Lunn static int marvell_read_status_page(struct phy_device *phydev, int page) 1203e1dde8dcSAndrew Lunn { 1204e1dde8dcSAndrew Lunn int fiber; 1205e1dde8dcSAndrew Lunn int err; 1206e1dde8dcSAndrew Lunn 1207e1dde8dcSAndrew Lunn /* Detect and update the link, but return if there 1208e1dde8dcSAndrew Lunn * was an error 1209e1dde8dcSAndrew Lunn */ 121052295666SAndrew Lunn if (page == MII_MARVELL_FIBER_PAGE) 1211e1dde8dcSAndrew Lunn fiber = 1; 1212e1dde8dcSAndrew Lunn else 1213e1dde8dcSAndrew Lunn fiber = 0; 1214e1dde8dcSAndrew Lunn 1215e1dde8dcSAndrew Lunn err = marvell_update_link(phydev, fiber); 1216e1dde8dcSAndrew Lunn if (err) 1217e1dde8dcSAndrew Lunn return err; 1218e1dde8dcSAndrew Lunn 1219e1dde8dcSAndrew Lunn if (phydev->autoneg == AUTONEG_ENABLE) 1220e1dde8dcSAndrew Lunn err = marvell_read_status_page_an(phydev, fiber); 1221e1dde8dcSAndrew Lunn else 1222e1dde8dcSAndrew Lunn err = marvell_read_status_page_fixed(phydev); 1223e1dde8dcSAndrew Lunn 1224e1dde8dcSAndrew Lunn return err; 1225e1dde8dcSAndrew Lunn } 1226e1dde8dcSAndrew Lunn 12276cfb3bccSCharles-Antoine Couret /* marvell_read_status 12286cfb3bccSCharles-Antoine Couret * 12296cfb3bccSCharles-Antoine Couret * Some Marvell's phys have two modes: fiber and copper. 12306cfb3bccSCharles-Antoine Couret * Both need status checked. 12316cfb3bccSCharles-Antoine Couret * Description: 12326cfb3bccSCharles-Antoine Couret * First, check the fiber link and status. 12336cfb3bccSCharles-Antoine Couret * If the fiber link is down, check the copper link and status which 12346cfb3bccSCharles-Antoine Couret * will be the default value if both link are down. 12356cfb3bccSCharles-Antoine Couret */ 12366cfb3bccSCharles-Antoine Couret static int marvell_read_status(struct phy_device *phydev) 12376cfb3bccSCharles-Antoine Couret { 12386cfb3bccSCharles-Antoine Couret int err; 12396cfb3bccSCharles-Antoine Couret 12406cfb3bccSCharles-Antoine Couret /* Check the fiber mode first */ 1241a13c0652SRussell King if (phydev->supported & SUPPORTED_FIBRE && 1242a13c0652SRussell King phydev->interface != PHY_INTERFACE_MODE_SGMII) { 124352295666SAndrew Lunn err = marvell_set_page(phydev, MII_MARVELL_FIBER_PAGE); 12446cfb3bccSCharles-Antoine Couret if (err < 0) 12456cfb3bccSCharles-Antoine Couret goto error; 12466cfb3bccSCharles-Antoine Couret 124752295666SAndrew Lunn err = marvell_read_status_page(phydev, MII_MARVELL_FIBER_PAGE); 12486cfb3bccSCharles-Antoine Couret if (err < 0) 12496cfb3bccSCharles-Antoine Couret goto error; 12506cfb3bccSCharles-Antoine Couret 12510c3439bcSAndrew Lunn /* If the fiber link is up, it is the selected and 12520c3439bcSAndrew Lunn * used link. In this case, we need to stay in the 12530c3439bcSAndrew Lunn * fiber page. Please to be careful about that, avoid 12540c3439bcSAndrew Lunn * to restore Copper page in other functions which 12550c3439bcSAndrew Lunn * could break the behaviour for some fiber phy like 12560c3439bcSAndrew Lunn * 88E1512. 12570c3439bcSAndrew Lunn */ 12586cfb3bccSCharles-Antoine Couret if (phydev->link) 12596cfb3bccSCharles-Antoine Couret return 0; 12606cfb3bccSCharles-Antoine Couret 12616cfb3bccSCharles-Antoine Couret /* If fiber link is down, check and save copper mode state */ 126252295666SAndrew Lunn err = marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE); 12636cfb3bccSCharles-Antoine Couret if (err < 0) 12646cfb3bccSCharles-Antoine Couret goto error; 12656cfb3bccSCharles-Antoine Couret } 12666cfb3bccSCharles-Antoine Couret 126752295666SAndrew Lunn return marvell_read_status_page(phydev, MII_MARVELL_COPPER_PAGE); 12686cfb3bccSCharles-Antoine Couret 12696cfb3bccSCharles-Antoine Couret error: 127052295666SAndrew Lunn marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE); 12716cfb3bccSCharles-Antoine Couret return err; 12726cfb3bccSCharles-Antoine Couret } 12733758be3dSCharles-Antoine Couret 12743758be3dSCharles-Antoine Couret /* marvell_suspend 12753758be3dSCharles-Antoine Couret * 12763758be3dSCharles-Antoine Couret * Some Marvell's phys have two modes: fiber and copper. 12773758be3dSCharles-Antoine Couret * Both need to be suspended 12783758be3dSCharles-Antoine Couret */ 12793758be3dSCharles-Antoine Couret static int marvell_suspend(struct phy_device *phydev) 12803758be3dSCharles-Antoine Couret { 12813758be3dSCharles-Antoine Couret int err; 12823758be3dSCharles-Antoine Couret 12833758be3dSCharles-Antoine Couret /* Suspend the fiber mode first */ 12843758be3dSCharles-Antoine Couret if (!(phydev->supported & SUPPORTED_FIBRE)) { 128552295666SAndrew Lunn err = marvell_set_page(phydev, MII_MARVELL_FIBER_PAGE); 12863758be3dSCharles-Antoine Couret if (err < 0) 12873758be3dSCharles-Antoine Couret goto error; 12883758be3dSCharles-Antoine Couret 12893758be3dSCharles-Antoine Couret /* With the page set, use the generic suspend */ 12903758be3dSCharles-Antoine Couret err = genphy_suspend(phydev); 12913758be3dSCharles-Antoine Couret if (err < 0) 12923758be3dSCharles-Antoine Couret goto error; 12933758be3dSCharles-Antoine Couret 12943758be3dSCharles-Antoine Couret /* Then, the copper link */ 129552295666SAndrew Lunn err = marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE); 12963758be3dSCharles-Antoine Couret if (err < 0) 12973758be3dSCharles-Antoine Couret goto error; 12983758be3dSCharles-Antoine Couret } 12993758be3dSCharles-Antoine Couret 13003758be3dSCharles-Antoine Couret /* With the page set, use the generic suspend */ 13013758be3dSCharles-Antoine Couret return genphy_suspend(phydev); 13023758be3dSCharles-Antoine Couret 13033758be3dSCharles-Antoine Couret error: 130452295666SAndrew Lunn marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE); 13053758be3dSCharles-Antoine Couret return err; 13063758be3dSCharles-Antoine Couret } 13073758be3dSCharles-Antoine Couret 13083758be3dSCharles-Antoine Couret /* marvell_resume 13093758be3dSCharles-Antoine Couret * 13103758be3dSCharles-Antoine Couret * Some Marvell's phys have two modes: fiber and copper. 13113758be3dSCharles-Antoine Couret * Both need to be resumed 13123758be3dSCharles-Antoine Couret */ 13133758be3dSCharles-Antoine Couret static int marvell_resume(struct phy_device *phydev) 13143758be3dSCharles-Antoine Couret { 13153758be3dSCharles-Antoine Couret int err; 13163758be3dSCharles-Antoine Couret 13173758be3dSCharles-Antoine Couret /* Resume the fiber mode first */ 13183758be3dSCharles-Antoine Couret if (!(phydev->supported & SUPPORTED_FIBRE)) { 131952295666SAndrew Lunn err = marvell_set_page(phydev, MII_MARVELL_FIBER_PAGE); 13203758be3dSCharles-Antoine Couret if (err < 0) 13213758be3dSCharles-Antoine Couret goto error; 13223758be3dSCharles-Antoine Couret 13233758be3dSCharles-Antoine Couret /* With the page set, use the generic resume */ 13243758be3dSCharles-Antoine Couret err = genphy_resume(phydev); 13253758be3dSCharles-Antoine Couret if (err < 0) 13263758be3dSCharles-Antoine Couret goto error; 13273758be3dSCharles-Antoine Couret 13283758be3dSCharles-Antoine Couret /* Then, the copper link */ 132952295666SAndrew Lunn err = marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE); 13303758be3dSCharles-Antoine Couret if (err < 0) 13313758be3dSCharles-Antoine Couret goto error; 13323758be3dSCharles-Antoine Couret } 13333758be3dSCharles-Antoine Couret 13343758be3dSCharles-Antoine Couret /* With the page set, use the generic resume */ 13353758be3dSCharles-Antoine Couret return genphy_resume(phydev); 13363758be3dSCharles-Antoine Couret 13373758be3dSCharles-Antoine Couret error: 133852295666SAndrew Lunn marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE); 13393758be3dSCharles-Antoine Couret return err; 13403758be3dSCharles-Antoine Couret } 13413758be3dSCharles-Antoine Couret 13426b358aedSSebastian Hesselbarth static int marvell_aneg_done(struct phy_device *phydev) 13436b358aedSSebastian Hesselbarth { 13446b358aedSSebastian Hesselbarth int retval = phy_read(phydev, MII_M1011_PHY_STATUS); 1345e69d9ed4SAndrew Lunn 13466b358aedSSebastian Hesselbarth return (retval < 0) ? retval : (retval & MII_M1011_PHY_STATUS_RESOLVED); 13476b358aedSSebastian Hesselbarth } 13486b358aedSSebastian Hesselbarth 1349dcd07be3SAnatolij Gustschin static int m88e1121_did_interrupt(struct phy_device *phydev) 1350dcd07be3SAnatolij Gustschin { 1351dcd07be3SAnatolij Gustschin int imask; 1352dcd07be3SAnatolij Gustschin 1353dcd07be3SAnatolij Gustschin imask = phy_read(phydev, MII_M1011_IEVENT); 1354dcd07be3SAnatolij Gustschin 1355dcd07be3SAnatolij Gustschin if (imask & MII_M1011_IMASK_INIT) 1356dcd07be3SAnatolij Gustschin return 1; 1357dcd07be3SAnatolij Gustschin 1358dcd07be3SAnatolij Gustschin return 0; 1359dcd07be3SAnatolij Gustschin } 1360dcd07be3SAnatolij Gustschin 136123beb38fSAndrew Lunn static void m88e1318_get_wol(struct phy_device *phydev, 136223beb38fSAndrew Lunn struct ethtool_wolinfo *wol) 13633871c387SMichael Stapelberg { 1364424ca4c5SRussell King int oldpage, ret = 0; 1365424ca4c5SRussell King 13663871c387SMichael Stapelberg wol->supported = WAKE_MAGIC; 13673871c387SMichael Stapelberg wol->wolopts = 0; 13683871c387SMichael Stapelberg 1369424ca4c5SRussell King oldpage = phy_select_page(phydev, MII_MARVELL_WOL_PAGE); 1370424ca4c5SRussell King if (oldpage < 0) 1371424ca4c5SRussell King goto error; 13723871c387SMichael Stapelberg 1373424ca4c5SRussell King ret = __phy_read(phydev, MII_88E1318S_PHY_WOL_CTRL); 1374424ca4c5SRussell King if (ret & MII_88E1318S_PHY_WOL_CTRL_MAGIC_PACKET_MATCH_ENABLE) 13753871c387SMichael Stapelberg wol->wolopts |= WAKE_MAGIC; 13763871c387SMichael Stapelberg 1377424ca4c5SRussell King error: 1378424ca4c5SRussell King phy_restore_page(phydev, oldpage, ret); 13793871c387SMichael Stapelberg } 13803871c387SMichael Stapelberg 138123beb38fSAndrew Lunn static int m88e1318_set_wol(struct phy_device *phydev, 138223beb38fSAndrew Lunn struct ethtool_wolinfo *wol) 13833871c387SMichael Stapelberg { 1384424ca4c5SRussell King int err = 0, oldpage; 13853871c387SMichael Stapelberg 1386424ca4c5SRussell King oldpage = phy_save_page(phydev); 1387424ca4c5SRussell King if (oldpage < 0) 1388424ca4c5SRussell King goto error; 13893871c387SMichael Stapelberg 13903871c387SMichael Stapelberg if (wol->wolopts & WAKE_MAGIC) { 13913871c387SMichael Stapelberg /* Explicitly switch to page 0x00, just to be sure */ 1392424ca4c5SRussell King err = marvell_write_page(phydev, MII_MARVELL_COPPER_PAGE); 13933871c387SMichael Stapelberg if (err < 0) 1394424ca4c5SRussell King goto error; 13953871c387SMichael Stapelberg 13963871c387SMichael Stapelberg /* Enable the WOL interrupt */ 1397424ca4c5SRussell King err = __phy_modify(phydev, MII_88E1318S_PHY_CSIER, 0, 1398424ca4c5SRussell King MII_88E1318S_PHY_CSIER_WOL_EIE); 13993871c387SMichael Stapelberg if (err < 0) 1400424ca4c5SRussell King goto error; 14013871c387SMichael Stapelberg 1402424ca4c5SRussell King err = marvell_write_page(phydev, MII_MARVELL_LED_PAGE); 14033871c387SMichael Stapelberg if (err < 0) 1404424ca4c5SRussell King goto error; 14053871c387SMichael Stapelberg 14063871c387SMichael Stapelberg /* Setup LED[2] as interrupt pin (active low) */ 1407424ca4c5SRussell King err = __phy_modify(phydev, MII_88E1318S_PHY_LED_TCR, 1408f102852fSRussell King MII_88E1318S_PHY_LED_TCR_FORCE_INT, 1409424ca4c5SRussell King MII_88E1318S_PHY_LED_TCR_INTn_ENABLE | 1410424ca4c5SRussell King MII_88E1318S_PHY_LED_TCR_INT_ACTIVE_LOW); 14113871c387SMichael Stapelberg if (err < 0) 1412424ca4c5SRussell King goto error; 14133871c387SMichael Stapelberg 1414424ca4c5SRussell King err = marvell_write_page(phydev, MII_MARVELL_WOL_PAGE); 14153871c387SMichael Stapelberg if (err < 0) 1416424ca4c5SRussell King goto error; 14173871c387SMichael Stapelberg 14183871c387SMichael Stapelberg /* Store the device address for the magic packet */ 1419424ca4c5SRussell King err = __phy_write(phydev, MII_88E1318S_PHY_MAGIC_PACKET_WORD2, 14203871c387SMichael Stapelberg ((phydev->attached_dev->dev_addr[5] << 8) | 14213871c387SMichael Stapelberg phydev->attached_dev->dev_addr[4])); 14223871c387SMichael Stapelberg if (err < 0) 1423424ca4c5SRussell King goto error; 1424424ca4c5SRussell King err = __phy_write(phydev, MII_88E1318S_PHY_MAGIC_PACKET_WORD1, 14253871c387SMichael Stapelberg ((phydev->attached_dev->dev_addr[3] << 8) | 14263871c387SMichael Stapelberg phydev->attached_dev->dev_addr[2])); 14273871c387SMichael Stapelberg if (err < 0) 1428424ca4c5SRussell King goto error; 1429424ca4c5SRussell King err = __phy_write(phydev, MII_88E1318S_PHY_MAGIC_PACKET_WORD0, 14303871c387SMichael Stapelberg ((phydev->attached_dev->dev_addr[1] << 8) | 14313871c387SMichael Stapelberg phydev->attached_dev->dev_addr[0])); 14323871c387SMichael Stapelberg if (err < 0) 1433424ca4c5SRussell King goto error; 14343871c387SMichael Stapelberg 14353871c387SMichael Stapelberg /* Clear WOL status and enable magic packet matching */ 1436424ca4c5SRussell King err = __phy_modify(phydev, MII_88E1318S_PHY_WOL_CTRL, 0, 1437424ca4c5SRussell King MII_88E1318S_PHY_WOL_CTRL_CLEAR_WOL_STATUS | 1438424ca4c5SRussell King MII_88E1318S_PHY_WOL_CTRL_MAGIC_PACKET_MATCH_ENABLE); 14393871c387SMichael Stapelberg if (err < 0) 1440424ca4c5SRussell King goto error; 14413871c387SMichael Stapelberg } else { 1442424ca4c5SRussell King err = marvell_write_page(phydev, MII_MARVELL_WOL_PAGE); 14433871c387SMichael Stapelberg if (err < 0) 1444424ca4c5SRussell King goto error; 14453871c387SMichael Stapelberg 14463871c387SMichael Stapelberg /* Clear WOL status and disable magic packet matching */ 1447424ca4c5SRussell King err = __phy_modify(phydev, MII_88E1318S_PHY_WOL_CTRL, 1448f102852fSRussell King MII_88E1318S_PHY_WOL_CTRL_MAGIC_PACKET_MATCH_ENABLE, 1449424ca4c5SRussell King MII_88E1318S_PHY_WOL_CTRL_CLEAR_WOL_STATUS); 14503871c387SMichael Stapelberg if (err < 0) 1451424ca4c5SRussell King goto error; 14523871c387SMichael Stapelberg } 14533871c387SMichael Stapelberg 1454424ca4c5SRussell King error: 1455424ca4c5SRussell King return phy_restore_page(phydev, oldpage, err); 14563871c387SMichael Stapelberg } 14573871c387SMichael Stapelberg 1458d2fa47d9SAndrew Lunn static int marvell_get_sset_count(struct phy_device *phydev) 1459d2fa47d9SAndrew Lunn { 14602170fef7SCharles-Antoine Couret if (phydev->supported & SUPPORTED_FIBRE) 1461d2fa47d9SAndrew Lunn return ARRAY_SIZE(marvell_hw_stats); 14622170fef7SCharles-Antoine Couret else 14632170fef7SCharles-Antoine Couret return ARRAY_SIZE(marvell_hw_stats) - NB_FIBER_STATS; 1464d2fa47d9SAndrew Lunn } 1465d2fa47d9SAndrew Lunn 1466d2fa47d9SAndrew Lunn static void marvell_get_strings(struct phy_device *phydev, u8 *data) 1467d2fa47d9SAndrew Lunn { 1468d2fa47d9SAndrew Lunn int i; 1469d2fa47d9SAndrew Lunn 1470d2fa47d9SAndrew Lunn for (i = 0; i < ARRAY_SIZE(marvell_hw_stats); i++) { 147198409b2bSFlorian Fainelli strlcpy(data + i * ETH_GSTRING_LEN, 1472d2fa47d9SAndrew Lunn marvell_hw_stats[i].string, ETH_GSTRING_LEN); 1473d2fa47d9SAndrew Lunn } 1474d2fa47d9SAndrew Lunn } 1475d2fa47d9SAndrew Lunn 1476d2fa47d9SAndrew Lunn #ifndef UINT64_MAX 1477d2fa47d9SAndrew Lunn #define UINT64_MAX (u64)(~((u64)0)) 1478d2fa47d9SAndrew Lunn #endif 1479d2fa47d9SAndrew Lunn static u64 marvell_get_stat(struct phy_device *phydev, int i) 1480d2fa47d9SAndrew Lunn { 1481d2fa47d9SAndrew Lunn struct marvell_hw_stat stat = marvell_hw_stats[i]; 1482d2fa47d9SAndrew Lunn struct marvell_priv *priv = phydev->priv; 1483424ca4c5SRussell King int val; 1484321b4d4bSAndrew Lunn u64 ret; 1485d2fa47d9SAndrew Lunn 1486424ca4c5SRussell King val = phy_read_paged(phydev, stat.page, stat.reg); 1487d2fa47d9SAndrew Lunn if (val < 0) { 1488321b4d4bSAndrew Lunn ret = UINT64_MAX; 1489d2fa47d9SAndrew Lunn } else { 1490d2fa47d9SAndrew Lunn val = val & ((1 << stat.bits) - 1); 1491d2fa47d9SAndrew Lunn priv->stats[i] += val; 1492321b4d4bSAndrew Lunn ret = priv->stats[i]; 1493d2fa47d9SAndrew Lunn } 1494d2fa47d9SAndrew Lunn 1495321b4d4bSAndrew Lunn return ret; 1496d2fa47d9SAndrew Lunn } 1497d2fa47d9SAndrew Lunn 1498d2fa47d9SAndrew Lunn static void marvell_get_stats(struct phy_device *phydev, 1499d2fa47d9SAndrew Lunn struct ethtool_stats *stats, u64 *data) 1500d2fa47d9SAndrew Lunn { 1501d2fa47d9SAndrew Lunn int i; 1502d2fa47d9SAndrew Lunn 1503d2fa47d9SAndrew Lunn for (i = 0; i < ARRAY_SIZE(marvell_hw_stats); i++) 1504d2fa47d9SAndrew Lunn data[i] = marvell_get_stat(phydev, i); 1505d2fa47d9SAndrew Lunn } 1506d2fa47d9SAndrew Lunn 15070b04680fSAndrew Lunn #ifdef CONFIG_HWMON 15080b04680fSAndrew Lunn static int m88e1121_get_temp(struct phy_device *phydev, long *temp) 15090b04680fSAndrew Lunn { 1510975b388cSAndrew Lunn int oldpage; 1511424ca4c5SRussell King int ret = 0; 15120b04680fSAndrew Lunn int val; 15130b04680fSAndrew Lunn 15140b04680fSAndrew Lunn *temp = 0; 15150b04680fSAndrew Lunn 1516424ca4c5SRussell King oldpage = phy_select_page(phydev, MII_MARVELL_MISC_TEST_PAGE); 1517424ca4c5SRussell King if (oldpage < 0) 1518424ca4c5SRussell King goto error; 1519975b388cSAndrew Lunn 15200b04680fSAndrew Lunn /* Enable temperature sensor */ 1521424ca4c5SRussell King ret = __phy_read(phydev, MII_88E1121_MISC_TEST); 15220b04680fSAndrew Lunn if (ret < 0) 15230b04680fSAndrew Lunn goto error; 15240b04680fSAndrew Lunn 1525424ca4c5SRussell King ret = __phy_write(phydev, MII_88E1121_MISC_TEST, 15260b04680fSAndrew Lunn ret | MII_88E1121_MISC_TEST_TEMP_SENSOR_EN); 15270b04680fSAndrew Lunn if (ret < 0) 15280b04680fSAndrew Lunn goto error; 15290b04680fSAndrew Lunn 15300b04680fSAndrew Lunn /* Wait for temperature to stabilize */ 15310b04680fSAndrew Lunn usleep_range(10000, 12000); 15320b04680fSAndrew Lunn 1533424ca4c5SRussell King val = __phy_read(phydev, MII_88E1121_MISC_TEST); 15340b04680fSAndrew Lunn if (val < 0) { 15350b04680fSAndrew Lunn ret = val; 15360b04680fSAndrew Lunn goto error; 15370b04680fSAndrew Lunn } 15380b04680fSAndrew Lunn 15390b04680fSAndrew Lunn /* Disable temperature sensor */ 1540424ca4c5SRussell King ret = __phy_write(phydev, MII_88E1121_MISC_TEST, 15410b04680fSAndrew Lunn ret & ~MII_88E1121_MISC_TEST_TEMP_SENSOR_EN); 15420b04680fSAndrew Lunn if (ret < 0) 15430b04680fSAndrew Lunn goto error; 15440b04680fSAndrew Lunn 15450b04680fSAndrew Lunn *temp = ((val & MII_88E1121_MISC_TEST_TEMP_MASK) - 5) * 5000; 15460b04680fSAndrew Lunn 15470b04680fSAndrew Lunn error: 1548424ca4c5SRussell King return phy_restore_page(phydev, oldpage, ret); 15490b04680fSAndrew Lunn } 15500b04680fSAndrew Lunn 15510b04680fSAndrew Lunn static int m88e1121_hwmon_read(struct device *dev, 15520b04680fSAndrew Lunn enum hwmon_sensor_types type, 15530b04680fSAndrew Lunn u32 attr, int channel, long *temp) 15540b04680fSAndrew Lunn { 15550b04680fSAndrew Lunn struct phy_device *phydev = dev_get_drvdata(dev); 15560b04680fSAndrew Lunn int err; 15570b04680fSAndrew Lunn 15580b04680fSAndrew Lunn switch (attr) { 15590b04680fSAndrew Lunn case hwmon_temp_input: 15600b04680fSAndrew Lunn err = m88e1121_get_temp(phydev, temp); 15610b04680fSAndrew Lunn break; 15620b04680fSAndrew Lunn default: 15630b04680fSAndrew Lunn return -EOPNOTSUPP; 15640b04680fSAndrew Lunn } 15650b04680fSAndrew Lunn 15660b04680fSAndrew Lunn return err; 15670b04680fSAndrew Lunn } 15680b04680fSAndrew Lunn 15690b04680fSAndrew Lunn static umode_t m88e1121_hwmon_is_visible(const void *data, 15700b04680fSAndrew Lunn enum hwmon_sensor_types type, 15710b04680fSAndrew Lunn u32 attr, int channel) 15720b04680fSAndrew Lunn { 15730b04680fSAndrew Lunn if (type != hwmon_temp) 15740b04680fSAndrew Lunn return 0; 15750b04680fSAndrew Lunn 15760b04680fSAndrew Lunn switch (attr) { 15770b04680fSAndrew Lunn case hwmon_temp_input: 15780b04680fSAndrew Lunn return 0444; 15790b04680fSAndrew Lunn default: 15800b04680fSAndrew Lunn return 0; 15810b04680fSAndrew Lunn } 15820b04680fSAndrew Lunn } 15830b04680fSAndrew Lunn 15840b04680fSAndrew Lunn static u32 m88e1121_hwmon_chip_config[] = { 15850b04680fSAndrew Lunn HWMON_C_REGISTER_TZ, 15860b04680fSAndrew Lunn 0 15870b04680fSAndrew Lunn }; 15880b04680fSAndrew Lunn 15890b04680fSAndrew Lunn static const struct hwmon_channel_info m88e1121_hwmon_chip = { 15900b04680fSAndrew Lunn .type = hwmon_chip, 15910b04680fSAndrew Lunn .config = m88e1121_hwmon_chip_config, 15920b04680fSAndrew Lunn }; 15930b04680fSAndrew Lunn 15940b04680fSAndrew Lunn static u32 m88e1121_hwmon_temp_config[] = { 15950b04680fSAndrew Lunn HWMON_T_INPUT, 15960b04680fSAndrew Lunn 0 15970b04680fSAndrew Lunn }; 15980b04680fSAndrew Lunn 15990b04680fSAndrew Lunn static const struct hwmon_channel_info m88e1121_hwmon_temp = { 16000b04680fSAndrew Lunn .type = hwmon_temp, 16010b04680fSAndrew Lunn .config = m88e1121_hwmon_temp_config, 16020b04680fSAndrew Lunn }; 16030b04680fSAndrew Lunn 16040b04680fSAndrew Lunn static const struct hwmon_channel_info *m88e1121_hwmon_info[] = { 16050b04680fSAndrew Lunn &m88e1121_hwmon_chip, 16060b04680fSAndrew Lunn &m88e1121_hwmon_temp, 16070b04680fSAndrew Lunn NULL 16080b04680fSAndrew Lunn }; 16090b04680fSAndrew Lunn 16100b04680fSAndrew Lunn static const struct hwmon_ops m88e1121_hwmon_hwmon_ops = { 16110b04680fSAndrew Lunn .is_visible = m88e1121_hwmon_is_visible, 16120b04680fSAndrew Lunn .read = m88e1121_hwmon_read, 16130b04680fSAndrew Lunn }; 16140b04680fSAndrew Lunn 16150b04680fSAndrew Lunn static const struct hwmon_chip_info m88e1121_hwmon_chip_info = { 16160b04680fSAndrew Lunn .ops = &m88e1121_hwmon_hwmon_ops, 16170b04680fSAndrew Lunn .info = m88e1121_hwmon_info, 16180b04680fSAndrew Lunn }; 16190b04680fSAndrew Lunn 16200b04680fSAndrew Lunn static int m88e1510_get_temp(struct phy_device *phydev, long *temp) 16210b04680fSAndrew Lunn { 16220b04680fSAndrew Lunn int ret; 16230b04680fSAndrew Lunn 16240b04680fSAndrew Lunn *temp = 0; 16250b04680fSAndrew Lunn 1626424ca4c5SRussell King ret = phy_read_paged(phydev, MII_MARVELL_MISC_TEST_PAGE, 1627424ca4c5SRussell King MII_88E1510_TEMP_SENSOR); 16280b04680fSAndrew Lunn if (ret < 0) 1629424ca4c5SRussell King return ret; 16300b04680fSAndrew Lunn 16310b04680fSAndrew Lunn *temp = ((ret & MII_88E1510_TEMP_SENSOR_MASK) - 25) * 1000; 16320b04680fSAndrew Lunn 1633424ca4c5SRussell King return 0; 16340b04680fSAndrew Lunn } 16350b04680fSAndrew Lunn 1636f0a45816SColin Ian King static int m88e1510_get_temp_critical(struct phy_device *phydev, long *temp) 16370b04680fSAndrew Lunn { 16380b04680fSAndrew Lunn int ret; 16390b04680fSAndrew Lunn 16400b04680fSAndrew Lunn *temp = 0; 16410b04680fSAndrew Lunn 1642424ca4c5SRussell King ret = phy_read_paged(phydev, MII_MARVELL_MISC_TEST_PAGE, 1643424ca4c5SRussell King MII_88E1121_MISC_TEST); 16440b04680fSAndrew Lunn if (ret < 0) 1645424ca4c5SRussell King return ret; 16460b04680fSAndrew Lunn 16470b04680fSAndrew Lunn *temp = (((ret & MII_88E1510_MISC_TEST_TEMP_THRESHOLD_MASK) >> 16480b04680fSAndrew Lunn MII_88E1510_MISC_TEST_TEMP_THRESHOLD_SHIFT) * 5) - 25; 16490b04680fSAndrew Lunn /* convert to mC */ 16500b04680fSAndrew Lunn *temp *= 1000; 16510b04680fSAndrew Lunn 1652424ca4c5SRussell King return 0; 16530b04680fSAndrew Lunn } 16540b04680fSAndrew Lunn 1655f0a45816SColin Ian King static int m88e1510_set_temp_critical(struct phy_device *phydev, long temp) 16560b04680fSAndrew Lunn { 16570b04680fSAndrew Lunn temp = temp / 1000; 16580b04680fSAndrew Lunn temp = clamp_val(DIV_ROUND_CLOSEST(temp, 5) + 5, 0, 0x1f); 16590b04680fSAndrew Lunn 1660424ca4c5SRussell King return phy_modify_paged(phydev, MII_MARVELL_MISC_TEST_PAGE, 1661424ca4c5SRussell King MII_88E1121_MISC_TEST, 1662424ca4c5SRussell King MII_88E1510_MISC_TEST_TEMP_THRESHOLD_MASK, 1663424ca4c5SRussell King temp << MII_88E1510_MISC_TEST_TEMP_THRESHOLD_SHIFT); 16640b04680fSAndrew Lunn } 16650b04680fSAndrew Lunn 1666f0a45816SColin Ian King static int m88e1510_get_temp_alarm(struct phy_device *phydev, long *alarm) 16670b04680fSAndrew Lunn { 16680b04680fSAndrew Lunn int ret; 16690b04680fSAndrew Lunn 16700b04680fSAndrew Lunn *alarm = false; 16710b04680fSAndrew Lunn 1672424ca4c5SRussell King ret = phy_read_paged(phydev, MII_MARVELL_MISC_TEST_PAGE, 1673424ca4c5SRussell King MII_88E1121_MISC_TEST); 16740b04680fSAndrew Lunn if (ret < 0) 1675424ca4c5SRussell King return ret; 1676424ca4c5SRussell King 16770b04680fSAndrew Lunn *alarm = !!(ret & MII_88E1510_MISC_TEST_TEMP_IRQ); 16780b04680fSAndrew Lunn 1679424ca4c5SRussell King return 0; 16800b04680fSAndrew Lunn } 16810b04680fSAndrew Lunn 16820b04680fSAndrew Lunn static int m88e1510_hwmon_read(struct device *dev, 16830b04680fSAndrew Lunn enum hwmon_sensor_types type, 16840b04680fSAndrew Lunn u32 attr, int channel, long *temp) 16850b04680fSAndrew Lunn { 16860b04680fSAndrew Lunn struct phy_device *phydev = dev_get_drvdata(dev); 16870b04680fSAndrew Lunn int err; 16880b04680fSAndrew Lunn 16890b04680fSAndrew Lunn switch (attr) { 16900b04680fSAndrew Lunn case hwmon_temp_input: 16910b04680fSAndrew Lunn err = m88e1510_get_temp(phydev, temp); 16920b04680fSAndrew Lunn break; 16930b04680fSAndrew Lunn case hwmon_temp_crit: 16940b04680fSAndrew Lunn err = m88e1510_get_temp_critical(phydev, temp); 16950b04680fSAndrew Lunn break; 16960b04680fSAndrew Lunn case hwmon_temp_max_alarm: 16970b04680fSAndrew Lunn err = m88e1510_get_temp_alarm(phydev, temp); 16980b04680fSAndrew Lunn break; 16990b04680fSAndrew Lunn default: 17000b04680fSAndrew Lunn return -EOPNOTSUPP; 17010b04680fSAndrew Lunn } 17020b04680fSAndrew Lunn 17030b04680fSAndrew Lunn return err; 17040b04680fSAndrew Lunn } 17050b04680fSAndrew Lunn 17060b04680fSAndrew Lunn static int m88e1510_hwmon_write(struct device *dev, 17070b04680fSAndrew Lunn enum hwmon_sensor_types type, 17080b04680fSAndrew Lunn u32 attr, int channel, long temp) 17090b04680fSAndrew Lunn { 17100b04680fSAndrew Lunn struct phy_device *phydev = dev_get_drvdata(dev); 17110b04680fSAndrew Lunn int err; 17120b04680fSAndrew Lunn 17130b04680fSAndrew Lunn switch (attr) { 17140b04680fSAndrew Lunn case hwmon_temp_crit: 17150b04680fSAndrew Lunn err = m88e1510_set_temp_critical(phydev, temp); 17160b04680fSAndrew Lunn break; 17170b04680fSAndrew Lunn default: 17180b04680fSAndrew Lunn return -EOPNOTSUPP; 17190b04680fSAndrew Lunn } 17200b04680fSAndrew Lunn return err; 17210b04680fSAndrew Lunn } 17220b04680fSAndrew Lunn 17230b04680fSAndrew Lunn static umode_t m88e1510_hwmon_is_visible(const void *data, 17240b04680fSAndrew Lunn enum hwmon_sensor_types type, 17250b04680fSAndrew Lunn u32 attr, int channel) 17260b04680fSAndrew Lunn { 17270b04680fSAndrew Lunn if (type != hwmon_temp) 17280b04680fSAndrew Lunn return 0; 17290b04680fSAndrew Lunn 17300b04680fSAndrew Lunn switch (attr) { 17310b04680fSAndrew Lunn case hwmon_temp_input: 17320b04680fSAndrew Lunn case hwmon_temp_max_alarm: 17330b04680fSAndrew Lunn return 0444; 17340b04680fSAndrew Lunn case hwmon_temp_crit: 17350b04680fSAndrew Lunn return 0644; 17360b04680fSAndrew Lunn default: 17370b04680fSAndrew Lunn return 0; 17380b04680fSAndrew Lunn } 17390b04680fSAndrew Lunn } 17400b04680fSAndrew Lunn 17410b04680fSAndrew Lunn static u32 m88e1510_hwmon_temp_config[] = { 17420b04680fSAndrew Lunn HWMON_T_INPUT | HWMON_T_CRIT | HWMON_T_MAX_ALARM, 17430b04680fSAndrew Lunn 0 17440b04680fSAndrew Lunn }; 17450b04680fSAndrew Lunn 17460b04680fSAndrew Lunn static const struct hwmon_channel_info m88e1510_hwmon_temp = { 17470b04680fSAndrew Lunn .type = hwmon_temp, 17480b04680fSAndrew Lunn .config = m88e1510_hwmon_temp_config, 17490b04680fSAndrew Lunn }; 17500b04680fSAndrew Lunn 17510b04680fSAndrew Lunn static const struct hwmon_channel_info *m88e1510_hwmon_info[] = { 17520b04680fSAndrew Lunn &m88e1121_hwmon_chip, 17530b04680fSAndrew Lunn &m88e1510_hwmon_temp, 17540b04680fSAndrew Lunn NULL 17550b04680fSAndrew Lunn }; 17560b04680fSAndrew Lunn 17570b04680fSAndrew Lunn static const struct hwmon_ops m88e1510_hwmon_hwmon_ops = { 17580b04680fSAndrew Lunn .is_visible = m88e1510_hwmon_is_visible, 17590b04680fSAndrew Lunn .read = m88e1510_hwmon_read, 17600b04680fSAndrew Lunn .write = m88e1510_hwmon_write, 17610b04680fSAndrew Lunn }; 17620b04680fSAndrew Lunn 17630b04680fSAndrew Lunn static const struct hwmon_chip_info m88e1510_hwmon_chip_info = { 17640b04680fSAndrew Lunn .ops = &m88e1510_hwmon_hwmon_ops, 17650b04680fSAndrew Lunn .info = m88e1510_hwmon_info, 17660b04680fSAndrew Lunn }; 17670b04680fSAndrew Lunn 1768fee2d546SAndrew Lunn static int m88e6390_get_temp(struct phy_device *phydev, long *temp) 1769fee2d546SAndrew Lunn { 1770fee2d546SAndrew Lunn int sum = 0; 1771fee2d546SAndrew Lunn int oldpage; 1772fee2d546SAndrew Lunn int ret = 0; 1773fee2d546SAndrew Lunn int i; 1774fee2d546SAndrew Lunn 1775fee2d546SAndrew Lunn *temp = 0; 1776fee2d546SAndrew Lunn 1777fee2d546SAndrew Lunn oldpage = phy_select_page(phydev, MII_MARVELL_MISC_TEST_PAGE); 1778fee2d546SAndrew Lunn if (oldpage < 0) 1779fee2d546SAndrew Lunn goto error; 1780fee2d546SAndrew Lunn 1781fee2d546SAndrew Lunn /* Enable temperature sensor */ 1782fee2d546SAndrew Lunn ret = __phy_read(phydev, MII_88E6390_MISC_TEST); 1783fee2d546SAndrew Lunn if (ret < 0) 1784fee2d546SAndrew Lunn goto error; 1785fee2d546SAndrew Lunn 1786fee2d546SAndrew Lunn ret = ret & ~MII_88E6390_MISC_TEST_SAMPLE_MASK; 1787fee2d546SAndrew Lunn ret |= MII_88E6390_MISC_TEST_SAMPLE_ENABLE | 1788fee2d546SAndrew Lunn MII_88E6390_MISC_TEST_SAMPLE_1S; 1789fee2d546SAndrew Lunn 1790fee2d546SAndrew Lunn ret = __phy_write(phydev, MII_88E6390_MISC_TEST, ret); 1791fee2d546SAndrew Lunn if (ret < 0) 1792fee2d546SAndrew Lunn goto error; 1793fee2d546SAndrew Lunn 1794fee2d546SAndrew Lunn /* Wait for temperature to stabilize */ 1795fee2d546SAndrew Lunn usleep_range(10000, 12000); 1796fee2d546SAndrew Lunn 1797fee2d546SAndrew Lunn /* Reading the temperature sense has an errata. You need to read 1798fee2d546SAndrew Lunn * a number of times and take an average. 1799fee2d546SAndrew Lunn */ 1800fee2d546SAndrew Lunn for (i = 0; i < MII_88E6390_TEMP_SENSOR_SAMPLES; i++) { 1801fee2d546SAndrew Lunn ret = __phy_read(phydev, MII_88E6390_TEMP_SENSOR); 1802fee2d546SAndrew Lunn if (ret < 0) 1803fee2d546SAndrew Lunn goto error; 1804fee2d546SAndrew Lunn sum += ret & MII_88E6390_TEMP_SENSOR_MASK; 1805fee2d546SAndrew Lunn } 1806fee2d546SAndrew Lunn 1807fee2d546SAndrew Lunn sum /= MII_88E6390_TEMP_SENSOR_SAMPLES; 1808fee2d546SAndrew Lunn *temp = (sum - 75) * 1000; 1809fee2d546SAndrew Lunn 1810fee2d546SAndrew Lunn /* Disable temperature sensor */ 1811fee2d546SAndrew Lunn ret = __phy_read(phydev, MII_88E6390_MISC_TEST); 1812fee2d546SAndrew Lunn if (ret < 0) 1813fee2d546SAndrew Lunn goto error; 1814fee2d546SAndrew Lunn 1815fee2d546SAndrew Lunn ret = ret & ~MII_88E6390_MISC_TEST_SAMPLE_MASK; 1816fee2d546SAndrew Lunn ret |= MII_88E6390_MISC_TEST_SAMPLE_DISABLE; 1817fee2d546SAndrew Lunn 1818fee2d546SAndrew Lunn ret = __phy_write(phydev, MII_88E6390_MISC_TEST, ret); 1819fee2d546SAndrew Lunn 1820fee2d546SAndrew Lunn error: 1821fee2d546SAndrew Lunn phy_restore_page(phydev, oldpage, ret); 1822fee2d546SAndrew Lunn 1823fee2d546SAndrew Lunn return ret; 1824fee2d546SAndrew Lunn } 1825fee2d546SAndrew Lunn 1826fee2d546SAndrew Lunn static int m88e6390_hwmon_read(struct device *dev, 1827fee2d546SAndrew Lunn enum hwmon_sensor_types type, 1828fee2d546SAndrew Lunn u32 attr, int channel, long *temp) 1829fee2d546SAndrew Lunn { 1830fee2d546SAndrew Lunn struct phy_device *phydev = dev_get_drvdata(dev); 1831fee2d546SAndrew Lunn int err; 1832fee2d546SAndrew Lunn 1833fee2d546SAndrew Lunn switch (attr) { 1834fee2d546SAndrew Lunn case hwmon_temp_input: 1835fee2d546SAndrew Lunn err = m88e6390_get_temp(phydev, temp); 1836fee2d546SAndrew Lunn break; 1837fee2d546SAndrew Lunn default: 1838fee2d546SAndrew Lunn return -EOPNOTSUPP; 1839fee2d546SAndrew Lunn } 1840fee2d546SAndrew Lunn 1841fee2d546SAndrew Lunn return err; 1842fee2d546SAndrew Lunn } 1843fee2d546SAndrew Lunn 1844fee2d546SAndrew Lunn static umode_t m88e6390_hwmon_is_visible(const void *data, 1845fee2d546SAndrew Lunn enum hwmon_sensor_types type, 1846fee2d546SAndrew Lunn u32 attr, int channel) 1847fee2d546SAndrew Lunn { 1848fee2d546SAndrew Lunn if (type != hwmon_temp) 1849fee2d546SAndrew Lunn return 0; 1850fee2d546SAndrew Lunn 1851fee2d546SAndrew Lunn switch (attr) { 1852fee2d546SAndrew Lunn case hwmon_temp_input: 1853fee2d546SAndrew Lunn return 0444; 1854fee2d546SAndrew Lunn default: 1855fee2d546SAndrew Lunn return 0; 1856fee2d546SAndrew Lunn } 1857fee2d546SAndrew Lunn } 1858fee2d546SAndrew Lunn 1859fee2d546SAndrew Lunn static u32 m88e6390_hwmon_temp_config[] = { 1860fee2d546SAndrew Lunn HWMON_T_INPUT, 1861fee2d546SAndrew Lunn 0 1862fee2d546SAndrew Lunn }; 1863fee2d546SAndrew Lunn 1864fee2d546SAndrew Lunn static const struct hwmon_channel_info m88e6390_hwmon_temp = { 1865fee2d546SAndrew Lunn .type = hwmon_temp, 1866fee2d546SAndrew Lunn .config = m88e6390_hwmon_temp_config, 1867fee2d546SAndrew Lunn }; 1868fee2d546SAndrew Lunn 1869fee2d546SAndrew Lunn static const struct hwmon_channel_info *m88e6390_hwmon_info[] = { 1870fee2d546SAndrew Lunn &m88e1121_hwmon_chip, 1871fee2d546SAndrew Lunn &m88e6390_hwmon_temp, 1872fee2d546SAndrew Lunn NULL 1873fee2d546SAndrew Lunn }; 1874fee2d546SAndrew Lunn 1875fee2d546SAndrew Lunn static const struct hwmon_ops m88e6390_hwmon_hwmon_ops = { 1876fee2d546SAndrew Lunn .is_visible = m88e6390_hwmon_is_visible, 1877fee2d546SAndrew Lunn .read = m88e6390_hwmon_read, 1878fee2d546SAndrew Lunn }; 1879fee2d546SAndrew Lunn 1880fee2d546SAndrew Lunn static const struct hwmon_chip_info m88e6390_hwmon_chip_info = { 1881fee2d546SAndrew Lunn .ops = &m88e6390_hwmon_hwmon_ops, 1882fee2d546SAndrew Lunn .info = m88e6390_hwmon_info, 1883fee2d546SAndrew Lunn }; 1884fee2d546SAndrew Lunn 18850b04680fSAndrew Lunn static int marvell_hwmon_name(struct phy_device *phydev) 18860b04680fSAndrew Lunn { 18870b04680fSAndrew Lunn struct marvell_priv *priv = phydev->priv; 18880b04680fSAndrew Lunn struct device *dev = &phydev->mdio.dev; 18890b04680fSAndrew Lunn const char *devname = dev_name(dev); 18900b04680fSAndrew Lunn size_t len = strlen(devname); 18910b04680fSAndrew Lunn int i, j; 18920b04680fSAndrew Lunn 18930b04680fSAndrew Lunn priv->hwmon_name = devm_kzalloc(dev, len, GFP_KERNEL); 18940b04680fSAndrew Lunn if (!priv->hwmon_name) 18950b04680fSAndrew Lunn return -ENOMEM; 18960b04680fSAndrew Lunn 18970b04680fSAndrew Lunn for (i = j = 0; i < len && devname[i]; i++) { 18980b04680fSAndrew Lunn if (isalnum(devname[i])) 18990b04680fSAndrew Lunn priv->hwmon_name[j++] = devname[i]; 19000b04680fSAndrew Lunn } 19010b04680fSAndrew Lunn 19020b04680fSAndrew Lunn return 0; 19030b04680fSAndrew Lunn } 19040b04680fSAndrew Lunn 19050b04680fSAndrew Lunn static int marvell_hwmon_probe(struct phy_device *phydev, 19060b04680fSAndrew Lunn const struct hwmon_chip_info *chip) 19070b04680fSAndrew Lunn { 19080b04680fSAndrew Lunn struct marvell_priv *priv = phydev->priv; 19090b04680fSAndrew Lunn struct device *dev = &phydev->mdio.dev; 19100b04680fSAndrew Lunn int err; 19110b04680fSAndrew Lunn 19120b04680fSAndrew Lunn err = marvell_hwmon_name(phydev); 19130b04680fSAndrew Lunn if (err) 19140b04680fSAndrew Lunn return err; 19150b04680fSAndrew Lunn 19160b04680fSAndrew Lunn priv->hwmon_dev = devm_hwmon_device_register_with_info( 19170b04680fSAndrew Lunn dev, priv->hwmon_name, phydev, chip, NULL); 19180b04680fSAndrew Lunn 19190b04680fSAndrew Lunn return PTR_ERR_OR_ZERO(priv->hwmon_dev); 19200b04680fSAndrew Lunn } 19210b04680fSAndrew Lunn 19220b04680fSAndrew Lunn static int m88e1121_hwmon_probe(struct phy_device *phydev) 19230b04680fSAndrew Lunn { 19240b04680fSAndrew Lunn return marvell_hwmon_probe(phydev, &m88e1121_hwmon_chip_info); 19250b04680fSAndrew Lunn } 19260b04680fSAndrew Lunn 19270b04680fSAndrew Lunn static int m88e1510_hwmon_probe(struct phy_device *phydev) 19280b04680fSAndrew Lunn { 19290b04680fSAndrew Lunn return marvell_hwmon_probe(phydev, &m88e1510_hwmon_chip_info); 19300b04680fSAndrew Lunn } 1931fee2d546SAndrew Lunn 1932fee2d546SAndrew Lunn static int m88e6390_hwmon_probe(struct phy_device *phydev) 1933fee2d546SAndrew Lunn { 1934fee2d546SAndrew Lunn return marvell_hwmon_probe(phydev, &m88e6390_hwmon_chip_info); 1935fee2d546SAndrew Lunn } 19360b04680fSAndrew Lunn #else 19370b04680fSAndrew Lunn static int m88e1121_hwmon_probe(struct phy_device *phydev) 19380b04680fSAndrew Lunn { 19390b04680fSAndrew Lunn return 0; 19400b04680fSAndrew Lunn } 19410b04680fSAndrew Lunn 19420b04680fSAndrew Lunn static int m88e1510_hwmon_probe(struct phy_device *phydev) 19430b04680fSAndrew Lunn { 19440b04680fSAndrew Lunn return 0; 19450b04680fSAndrew Lunn } 1946fee2d546SAndrew Lunn 1947fee2d546SAndrew Lunn static int m88e6390_hwmon_probe(struct phy_device *phydev) 1948fee2d546SAndrew Lunn { 1949fee2d546SAndrew Lunn return 0; 1950fee2d546SAndrew Lunn } 19510b04680fSAndrew Lunn #endif 19520b04680fSAndrew Lunn 1953d2fa47d9SAndrew Lunn static int marvell_probe(struct phy_device *phydev) 1954d2fa47d9SAndrew Lunn { 1955d2fa47d9SAndrew Lunn struct marvell_priv *priv; 1956d2fa47d9SAndrew Lunn 1957e5a03bfdSAndrew Lunn priv = devm_kzalloc(&phydev->mdio.dev, sizeof(*priv), GFP_KERNEL); 1958d2fa47d9SAndrew Lunn if (!priv) 1959d2fa47d9SAndrew Lunn return -ENOMEM; 1960d2fa47d9SAndrew Lunn 1961d2fa47d9SAndrew Lunn phydev->priv = priv; 1962d2fa47d9SAndrew Lunn 1963d2fa47d9SAndrew Lunn return 0; 1964d2fa47d9SAndrew Lunn } 1965d2fa47d9SAndrew Lunn 19660b04680fSAndrew Lunn static int m88e1121_probe(struct phy_device *phydev) 19670b04680fSAndrew Lunn { 19680b04680fSAndrew Lunn int err; 19690b04680fSAndrew Lunn 19700b04680fSAndrew Lunn err = marvell_probe(phydev); 19710b04680fSAndrew Lunn if (err) 19720b04680fSAndrew Lunn return err; 19730b04680fSAndrew Lunn 19740b04680fSAndrew Lunn return m88e1121_hwmon_probe(phydev); 19750b04680fSAndrew Lunn } 19760b04680fSAndrew Lunn 19770b04680fSAndrew Lunn static int m88e1510_probe(struct phy_device *phydev) 19780b04680fSAndrew Lunn { 19790b04680fSAndrew Lunn int err; 19800b04680fSAndrew Lunn 19810b04680fSAndrew Lunn err = marvell_probe(phydev); 19820b04680fSAndrew Lunn if (err) 19830b04680fSAndrew Lunn return err; 19840b04680fSAndrew Lunn 19850b04680fSAndrew Lunn return m88e1510_hwmon_probe(phydev); 19860b04680fSAndrew Lunn } 19870b04680fSAndrew Lunn 1988fee2d546SAndrew Lunn static int m88e6390_probe(struct phy_device *phydev) 1989fee2d546SAndrew Lunn { 1990fee2d546SAndrew Lunn int err; 1991fee2d546SAndrew Lunn 1992fee2d546SAndrew Lunn err = marvell_probe(phydev); 1993fee2d546SAndrew Lunn if (err) 1994fee2d546SAndrew Lunn return err; 1995fee2d546SAndrew Lunn 1996fee2d546SAndrew Lunn return m88e6390_hwmon_probe(phydev); 1997fee2d546SAndrew Lunn } 1998fee2d546SAndrew Lunn 1999e5479239SOlof Johansson static struct phy_driver marvell_drivers[] = { 2000e5479239SOlof Johansson { 20012f495c39SBenjamin Herrenschmidt .phy_id = MARVELL_PHY_ID_88E1101, 20022f495c39SBenjamin Herrenschmidt .phy_id_mask = MARVELL_PHY_ID_MASK, 200300db8189SAndy Fleming .name = "Marvell 88E1101", 200400db8189SAndy Fleming .features = PHY_GBIT_FEATURES, 200500db8189SAndy Fleming .flags = PHY_HAS_INTERRUPT, 200618702414SArnd Bergmann .probe = marvell_probe, 200779be1a1cSClemens Gruber .config_init = &marvell_config_init, 2008f2899788SAndrew Lunn .config_aneg = &m88e1101_config_aneg, 200900db8189SAndy Fleming .ack_interrupt = &marvell_ack_interrupt, 201000db8189SAndy Fleming .config_intr = &marvell_config_intr, 20110898b448SSebastian Hesselbarth .resume = &genphy_resume, 20120898b448SSebastian Hesselbarth .suspend = &genphy_suspend, 2013424ca4c5SRussell King .read_page = marvell_read_page, 2014424ca4c5SRussell King .write_page = marvell_write_page, 2015d2fa47d9SAndrew Lunn .get_sset_count = marvell_get_sset_count, 2016d2fa47d9SAndrew Lunn .get_strings = marvell_get_strings, 2017d2fa47d9SAndrew Lunn .get_stats = marvell_get_stats, 2018e5479239SOlof Johansson }, 2019e5479239SOlof Johansson { 20202f495c39SBenjamin Herrenschmidt .phy_id = MARVELL_PHY_ID_88E1112, 20212f495c39SBenjamin Herrenschmidt .phy_id_mask = MARVELL_PHY_ID_MASK, 202285cfb534SOlof Johansson .name = "Marvell 88E1112", 202385cfb534SOlof Johansson .features = PHY_GBIT_FEATURES, 202485cfb534SOlof Johansson .flags = PHY_HAS_INTERRUPT, 2025d2fa47d9SAndrew Lunn .probe = marvell_probe, 202685cfb534SOlof Johansson .config_init = &m88e1111_config_init, 202785cfb534SOlof Johansson .config_aneg = &marvell_config_aneg, 202885cfb534SOlof Johansson .ack_interrupt = &marvell_ack_interrupt, 202985cfb534SOlof Johansson .config_intr = &marvell_config_intr, 20300898b448SSebastian Hesselbarth .resume = &genphy_resume, 20310898b448SSebastian Hesselbarth .suspend = &genphy_suspend, 2032424ca4c5SRussell King .read_page = marvell_read_page, 2033424ca4c5SRussell King .write_page = marvell_write_page, 2034d2fa47d9SAndrew Lunn .get_sset_count = marvell_get_sset_count, 2035d2fa47d9SAndrew Lunn .get_strings = marvell_get_strings, 2036d2fa47d9SAndrew Lunn .get_stats = marvell_get_stats, 203785cfb534SOlof Johansson }, 203885cfb534SOlof Johansson { 20392f495c39SBenjamin Herrenschmidt .phy_id = MARVELL_PHY_ID_88E1111, 20402f495c39SBenjamin Herrenschmidt .phy_id_mask = MARVELL_PHY_ID_MASK, 204176884679SAndy Fleming .name = "Marvell 88E1111", 204276884679SAndy Fleming .features = PHY_GBIT_FEATURES, 204376884679SAndy Fleming .flags = PHY_HAS_INTERRUPT, 2044d2fa47d9SAndrew Lunn .probe = marvell_probe, 2045e5479239SOlof Johansson .config_init = &m88e1111_config_init, 20463ec0a0f1SHarini Katakam .config_aneg = &m88e1111_config_aneg, 2047be937f1fSAlexandr Smirnov .read_status = &marvell_read_status, 204876884679SAndy Fleming .ack_interrupt = &marvell_ack_interrupt, 204976884679SAndy Fleming .config_intr = &marvell_config_intr, 20500898b448SSebastian Hesselbarth .resume = &genphy_resume, 20510898b448SSebastian Hesselbarth .suspend = &genphy_suspend, 2052424ca4c5SRussell King .read_page = marvell_read_page, 2053424ca4c5SRussell King .write_page = marvell_write_page, 2054d2fa47d9SAndrew Lunn .get_sset_count = marvell_get_sset_count, 2055d2fa47d9SAndrew Lunn .get_strings = marvell_get_strings, 2056d2fa47d9SAndrew Lunn .get_stats = marvell_get_stats, 2057e5479239SOlof Johansson }, 2058e5479239SOlof Johansson { 20592f495c39SBenjamin Herrenschmidt .phy_id = MARVELL_PHY_ID_88E1118, 20602f495c39SBenjamin Herrenschmidt .phy_id_mask = MARVELL_PHY_ID_MASK, 2061605f196eSRon Madrid .name = "Marvell 88E1118", 2062605f196eSRon Madrid .features = PHY_GBIT_FEATURES, 2063605f196eSRon Madrid .flags = PHY_HAS_INTERRUPT, 2064d2fa47d9SAndrew Lunn .probe = marvell_probe, 2065605f196eSRon Madrid .config_init = &m88e1118_config_init, 2066605f196eSRon Madrid .config_aneg = &m88e1118_config_aneg, 2067605f196eSRon Madrid .ack_interrupt = &marvell_ack_interrupt, 2068605f196eSRon Madrid .config_intr = &marvell_config_intr, 20690898b448SSebastian Hesselbarth .resume = &genphy_resume, 20700898b448SSebastian Hesselbarth .suspend = &genphy_suspend, 2071424ca4c5SRussell King .read_page = marvell_read_page, 2072424ca4c5SRussell King .write_page = marvell_write_page, 2073d2fa47d9SAndrew Lunn .get_sset_count = marvell_get_sset_count, 2074d2fa47d9SAndrew Lunn .get_strings = marvell_get_strings, 2075d2fa47d9SAndrew Lunn .get_stats = marvell_get_stats, 2076605f196eSRon Madrid }, 2077605f196eSRon Madrid { 20782f495c39SBenjamin Herrenschmidt .phy_id = MARVELL_PHY_ID_88E1121R, 20792f495c39SBenjamin Herrenschmidt .phy_id_mask = MARVELL_PHY_ID_MASK, 2080140bc929SSergei Poselenov .name = "Marvell 88E1121R", 2081140bc929SSergei Poselenov .features = PHY_GBIT_FEATURES, 2082140bc929SSergei Poselenov .flags = PHY_HAS_INTERRUPT, 208318702414SArnd Bergmann .probe = &m88e1121_probe, 2084fdecf36fSClemens Gruber .config_init = &m88e1121_config_init, 2085140bc929SSergei Poselenov .config_aneg = &m88e1121_config_aneg, 2086140bc929SSergei Poselenov .read_status = &marvell_read_status, 2087140bc929SSergei Poselenov .ack_interrupt = &marvell_ack_interrupt, 2088140bc929SSergei Poselenov .config_intr = &marvell_config_intr, 2089dcd07be3SAnatolij Gustschin .did_interrupt = &m88e1121_did_interrupt, 20900898b448SSebastian Hesselbarth .resume = &genphy_resume, 20910898b448SSebastian Hesselbarth .suspend = &genphy_suspend, 2092424ca4c5SRussell King .read_page = marvell_read_page, 2093424ca4c5SRussell King .write_page = marvell_write_page, 2094d2fa47d9SAndrew Lunn .get_sset_count = marvell_get_sset_count, 2095d2fa47d9SAndrew Lunn .get_strings = marvell_get_strings, 2096d2fa47d9SAndrew Lunn .get_stats = marvell_get_stats, 2097140bc929SSergei Poselenov }, 2098140bc929SSergei Poselenov { 2099337ac9d5SCyril Chemparathy .phy_id = MARVELL_PHY_ID_88E1318S, 21006ba74014SLinus Torvalds .phy_id_mask = MARVELL_PHY_ID_MASK, 2101337ac9d5SCyril Chemparathy .name = "Marvell 88E1318S", 21023ff1c259SCyril Chemparathy .features = PHY_GBIT_FEATURES, 21033ff1c259SCyril Chemparathy .flags = PHY_HAS_INTERRUPT, 2104d2fa47d9SAndrew Lunn .probe = marvell_probe, 2105dd9a122aSEsben Haabendal .config_init = &m88e1318_config_init, 2106337ac9d5SCyril Chemparathy .config_aneg = &m88e1318_config_aneg, 21073ff1c259SCyril Chemparathy .read_status = &marvell_read_status, 21083ff1c259SCyril Chemparathy .ack_interrupt = &marvell_ack_interrupt, 21093ff1c259SCyril Chemparathy .config_intr = &marvell_config_intr, 21103ff1c259SCyril Chemparathy .did_interrupt = &m88e1121_did_interrupt, 21113871c387SMichael Stapelberg .get_wol = &m88e1318_get_wol, 21123871c387SMichael Stapelberg .set_wol = &m88e1318_set_wol, 21130898b448SSebastian Hesselbarth .resume = &genphy_resume, 21140898b448SSebastian Hesselbarth .suspend = &genphy_suspend, 2115424ca4c5SRussell King .read_page = marvell_read_page, 2116424ca4c5SRussell King .write_page = marvell_write_page, 2117d2fa47d9SAndrew Lunn .get_sset_count = marvell_get_sset_count, 2118d2fa47d9SAndrew Lunn .get_strings = marvell_get_strings, 2119d2fa47d9SAndrew Lunn .get_stats = marvell_get_stats, 21203ff1c259SCyril Chemparathy }, 21213ff1c259SCyril Chemparathy { 21222f495c39SBenjamin Herrenschmidt .phy_id = MARVELL_PHY_ID_88E1145, 21232f495c39SBenjamin Herrenschmidt .phy_id_mask = MARVELL_PHY_ID_MASK, 212476884679SAndy Fleming .name = "Marvell 88E1145", 212576884679SAndy Fleming .features = PHY_GBIT_FEATURES, 212676884679SAndy Fleming .flags = PHY_HAS_INTERRUPT, 2127d2fa47d9SAndrew Lunn .probe = marvell_probe, 212876884679SAndy Fleming .config_init = &m88e1145_config_init, 2129c505873eSZhao Qiang .config_aneg = &m88e1101_config_aneg, 213076884679SAndy Fleming .read_status = &genphy_read_status, 213176884679SAndy Fleming .ack_interrupt = &marvell_ack_interrupt, 213276884679SAndy Fleming .config_intr = &marvell_config_intr, 21330898b448SSebastian Hesselbarth .resume = &genphy_resume, 21340898b448SSebastian Hesselbarth .suspend = &genphy_suspend, 2135424ca4c5SRussell King .read_page = marvell_read_page, 2136424ca4c5SRussell King .write_page = marvell_write_page, 2137d2fa47d9SAndrew Lunn .get_sset_count = marvell_get_sset_count, 2138d2fa47d9SAndrew Lunn .get_strings = marvell_get_strings, 2139d2fa47d9SAndrew Lunn .get_stats = marvell_get_stats, 2140ac8c635aSOlof Johansson }, 2141ac8c635aSOlof Johansson { 214290600732SDavid Daney .phy_id = MARVELL_PHY_ID_88E1149R, 214390600732SDavid Daney .phy_id_mask = MARVELL_PHY_ID_MASK, 214490600732SDavid Daney .name = "Marvell 88E1149R", 214590600732SDavid Daney .features = PHY_GBIT_FEATURES, 214690600732SDavid Daney .flags = PHY_HAS_INTERRUPT, 2147d2fa47d9SAndrew Lunn .probe = marvell_probe, 214890600732SDavid Daney .config_init = &m88e1149_config_init, 214990600732SDavid Daney .config_aneg = &m88e1118_config_aneg, 215090600732SDavid Daney .ack_interrupt = &marvell_ack_interrupt, 215190600732SDavid Daney .config_intr = &marvell_config_intr, 21520898b448SSebastian Hesselbarth .resume = &genphy_resume, 21530898b448SSebastian Hesselbarth .suspend = &genphy_suspend, 2154424ca4c5SRussell King .read_page = marvell_read_page, 2155424ca4c5SRussell King .write_page = marvell_write_page, 2156d2fa47d9SAndrew Lunn .get_sset_count = marvell_get_sset_count, 2157d2fa47d9SAndrew Lunn .get_strings = marvell_get_strings, 2158d2fa47d9SAndrew Lunn .get_stats = marvell_get_stats, 215990600732SDavid Daney }, 216090600732SDavid Daney { 21612f495c39SBenjamin Herrenschmidt .phy_id = MARVELL_PHY_ID_88E1240, 21622f495c39SBenjamin Herrenschmidt .phy_id_mask = MARVELL_PHY_ID_MASK, 2163ac8c635aSOlof Johansson .name = "Marvell 88E1240", 2164ac8c635aSOlof Johansson .features = PHY_GBIT_FEATURES, 2165ac8c635aSOlof Johansson .flags = PHY_HAS_INTERRUPT, 2166d2fa47d9SAndrew Lunn .probe = marvell_probe, 2167ac8c635aSOlof Johansson .config_init = &m88e1111_config_init, 2168ac8c635aSOlof Johansson .config_aneg = &marvell_config_aneg, 2169ac8c635aSOlof Johansson .ack_interrupt = &marvell_ack_interrupt, 2170ac8c635aSOlof Johansson .config_intr = &marvell_config_intr, 21710898b448SSebastian Hesselbarth .resume = &genphy_resume, 21720898b448SSebastian Hesselbarth .suspend = &genphy_suspend, 2173424ca4c5SRussell King .read_page = marvell_read_page, 2174424ca4c5SRussell King .write_page = marvell_write_page, 2175d2fa47d9SAndrew Lunn .get_sset_count = marvell_get_sset_count, 2176d2fa47d9SAndrew Lunn .get_strings = marvell_get_strings, 2177d2fa47d9SAndrew Lunn .get_stats = marvell_get_stats, 2178ac8c635aSOlof Johansson }, 21793da09a51SMichal Simek { 21803da09a51SMichal Simek .phy_id = MARVELL_PHY_ID_88E1116R, 21813da09a51SMichal Simek .phy_id_mask = MARVELL_PHY_ID_MASK, 21823da09a51SMichal Simek .name = "Marvell 88E1116R", 21833da09a51SMichal Simek .features = PHY_GBIT_FEATURES, 21843da09a51SMichal Simek .flags = PHY_HAS_INTERRUPT, 2185d2fa47d9SAndrew Lunn .probe = marvell_probe, 21863da09a51SMichal Simek .config_init = &m88e1116r_config_init, 21873da09a51SMichal Simek .ack_interrupt = &marvell_ack_interrupt, 21883da09a51SMichal Simek .config_intr = &marvell_config_intr, 21890898b448SSebastian Hesselbarth .resume = &genphy_resume, 21900898b448SSebastian Hesselbarth .suspend = &genphy_suspend, 2191424ca4c5SRussell King .read_page = marvell_read_page, 2192424ca4c5SRussell King .write_page = marvell_write_page, 2193d2fa47d9SAndrew Lunn .get_sset_count = marvell_get_sset_count, 2194d2fa47d9SAndrew Lunn .get_strings = marvell_get_strings, 2195d2fa47d9SAndrew Lunn .get_stats = marvell_get_stats, 21963da09a51SMichal Simek }, 219710e24caaSMichal Simek { 219810e24caaSMichal Simek .phy_id = MARVELL_PHY_ID_88E1510, 219910e24caaSMichal Simek .phy_id_mask = MARVELL_PHY_ID_MASK, 220010e24caaSMichal Simek .name = "Marvell 88E1510", 22016cfb3bccSCharles-Antoine Couret .features = PHY_GBIT_FEATURES | SUPPORTED_FIBRE, 220218702414SArnd Bergmann .flags = PHY_HAS_INTERRUPT, 22030b04680fSAndrew Lunn .probe = &m88e1510_probe, 2204930b37eeSStefan Roese .config_init = &m88e1510_config_init, 220510e24caaSMichal Simek .config_aneg = &m88e1510_config_aneg, 220610e24caaSMichal Simek .read_status = &marvell_read_status, 220710e24caaSMichal Simek .ack_interrupt = &marvell_ack_interrupt, 220810e24caaSMichal Simek .config_intr = &marvell_config_intr, 220910e24caaSMichal Simek .did_interrupt = &m88e1121_did_interrupt, 2210f39aac7eSJingju Hou .get_wol = &m88e1318_get_wol, 2211f39aac7eSJingju Hou .set_wol = &m88e1318_set_wol, 22123758be3dSCharles-Antoine Couret .resume = &marvell_resume, 22133758be3dSCharles-Antoine Couret .suspend = &marvell_suspend, 2214424ca4c5SRussell King .read_page = marvell_read_page, 2215424ca4c5SRussell King .write_page = marvell_write_page, 2216d2fa47d9SAndrew Lunn .get_sset_count = marvell_get_sset_count, 2217d2fa47d9SAndrew Lunn .get_strings = marvell_get_strings, 2218d2fa47d9SAndrew Lunn .get_stats = marvell_get_stats, 2219f0f9b4edSLin Yun Sheng .set_loopback = genphy_loopback, 222010e24caaSMichal Simek }, 22216b358aedSSebastian Hesselbarth { 2222819ec8e1SAndrew Lunn .phy_id = MARVELL_PHY_ID_88E1540, 2223819ec8e1SAndrew Lunn .phy_id_mask = MARVELL_PHY_ID_MASK, 2224819ec8e1SAndrew Lunn .name = "Marvell 88E1540", 2225819ec8e1SAndrew Lunn .features = PHY_GBIT_FEATURES, 2226819ec8e1SAndrew Lunn .flags = PHY_HAS_INTERRUPT, 222718702414SArnd Bergmann .probe = m88e1510_probe, 222879be1a1cSClemens Gruber .config_init = &marvell_config_init, 2229819ec8e1SAndrew Lunn .config_aneg = &m88e1510_config_aneg, 2230819ec8e1SAndrew Lunn .read_status = &marvell_read_status, 2231819ec8e1SAndrew Lunn .ack_interrupt = &marvell_ack_interrupt, 2232819ec8e1SAndrew Lunn .config_intr = &marvell_config_intr, 2233819ec8e1SAndrew Lunn .did_interrupt = &m88e1121_did_interrupt, 2234819ec8e1SAndrew Lunn .resume = &genphy_resume, 2235819ec8e1SAndrew Lunn .suspend = &genphy_suspend, 2236424ca4c5SRussell King .read_page = marvell_read_page, 2237424ca4c5SRussell King .write_page = marvell_write_page, 2238d2fa47d9SAndrew Lunn .get_sset_count = marvell_get_sset_count, 2239d2fa47d9SAndrew Lunn .get_strings = marvell_get_strings, 2240d2fa47d9SAndrew Lunn .get_stats = marvell_get_stats, 2241819ec8e1SAndrew Lunn }, 2242819ec8e1SAndrew Lunn { 224360f06fdeSAndrew Lunn .phy_id = MARVELL_PHY_ID_88E1545, 224460f06fdeSAndrew Lunn .phy_id_mask = MARVELL_PHY_ID_MASK, 224560f06fdeSAndrew Lunn .name = "Marvell 88E1545", 224660f06fdeSAndrew Lunn .probe = m88e1510_probe, 224760f06fdeSAndrew Lunn .features = PHY_GBIT_FEATURES, 224860f06fdeSAndrew Lunn .flags = PHY_HAS_INTERRUPT, 224960f06fdeSAndrew Lunn .config_init = &marvell_config_init, 225060f06fdeSAndrew Lunn .config_aneg = &m88e1510_config_aneg, 225160f06fdeSAndrew Lunn .read_status = &marvell_read_status, 225260f06fdeSAndrew Lunn .ack_interrupt = &marvell_ack_interrupt, 225360f06fdeSAndrew Lunn .config_intr = &marvell_config_intr, 225460f06fdeSAndrew Lunn .did_interrupt = &m88e1121_did_interrupt, 225560f06fdeSAndrew Lunn .resume = &genphy_resume, 225660f06fdeSAndrew Lunn .suspend = &genphy_suspend, 2257424ca4c5SRussell King .read_page = marvell_read_page, 2258424ca4c5SRussell King .write_page = marvell_write_page, 225960f06fdeSAndrew Lunn .get_sset_count = marvell_get_sset_count, 226060f06fdeSAndrew Lunn .get_strings = marvell_get_strings, 226160f06fdeSAndrew Lunn .get_stats = marvell_get_stats, 226260f06fdeSAndrew Lunn }, 226360f06fdeSAndrew Lunn { 22646b358aedSSebastian Hesselbarth .phy_id = MARVELL_PHY_ID_88E3016, 22656b358aedSSebastian Hesselbarth .phy_id_mask = MARVELL_PHY_ID_MASK, 22666b358aedSSebastian Hesselbarth .name = "Marvell 88E3016", 22676b358aedSSebastian Hesselbarth .features = PHY_BASIC_FEATURES, 22686b358aedSSebastian Hesselbarth .flags = PHY_HAS_INTERRUPT, 2269d2fa47d9SAndrew Lunn .probe = marvell_probe, 22706b358aedSSebastian Hesselbarth .config_init = &m88e3016_config_init, 22716b358aedSSebastian Hesselbarth .aneg_done = &marvell_aneg_done, 22726b358aedSSebastian Hesselbarth .read_status = &marvell_read_status, 22736b358aedSSebastian Hesselbarth .ack_interrupt = &marvell_ack_interrupt, 22746b358aedSSebastian Hesselbarth .config_intr = &marvell_config_intr, 22756b358aedSSebastian Hesselbarth .did_interrupt = &m88e1121_did_interrupt, 22766b358aedSSebastian Hesselbarth .resume = &genphy_resume, 22776b358aedSSebastian Hesselbarth .suspend = &genphy_suspend, 2278424ca4c5SRussell King .read_page = marvell_read_page, 2279424ca4c5SRussell King .write_page = marvell_write_page, 2280d2fa47d9SAndrew Lunn .get_sset_count = marvell_get_sset_count, 2281d2fa47d9SAndrew Lunn .get_strings = marvell_get_strings, 2282d2fa47d9SAndrew Lunn .get_stats = marvell_get_stats, 22836b358aedSSebastian Hesselbarth }, 2284e4cf8a38SAndrew Lunn { 2285e4cf8a38SAndrew Lunn .phy_id = MARVELL_PHY_ID_88E6390, 2286e4cf8a38SAndrew Lunn .phy_id_mask = MARVELL_PHY_ID_MASK, 2287e4cf8a38SAndrew Lunn .name = "Marvell 88E6390", 2288e4cf8a38SAndrew Lunn .features = PHY_GBIT_FEATURES, 2289e4cf8a38SAndrew Lunn .flags = PHY_HAS_INTERRUPT, 2290fee2d546SAndrew Lunn .probe = m88e6390_probe, 2291e4cf8a38SAndrew Lunn .config_init = &marvell_config_init, 2292e4cf8a38SAndrew Lunn .config_aneg = &m88e1510_config_aneg, 2293e4cf8a38SAndrew Lunn .read_status = &marvell_read_status, 2294e4cf8a38SAndrew Lunn .ack_interrupt = &marvell_ack_interrupt, 2295e4cf8a38SAndrew Lunn .config_intr = &marvell_config_intr, 2296e4cf8a38SAndrew Lunn .did_interrupt = &m88e1121_did_interrupt, 2297e4cf8a38SAndrew Lunn .resume = &genphy_resume, 2298e4cf8a38SAndrew Lunn .suspend = &genphy_suspend, 2299424ca4c5SRussell King .read_page = marvell_read_page, 2300424ca4c5SRussell King .write_page = marvell_write_page, 2301e4cf8a38SAndrew Lunn .get_sset_count = marvell_get_sset_count, 2302e4cf8a38SAndrew Lunn .get_strings = marvell_get_strings, 2303e4cf8a38SAndrew Lunn .get_stats = marvell_get_stats, 2304e4cf8a38SAndrew Lunn }, 230576884679SAndy Fleming }; 230676884679SAndy Fleming 230750fd7150SJohan Hovold module_phy_driver(marvell_drivers); 23084e4f10f6SDavid Woodhouse 2309cf93c945SUwe Kleine-König static struct mdio_device_id __maybe_unused marvell_tbl[] = { 2310f5e1cabfSMichal Simek { MARVELL_PHY_ID_88E1101, MARVELL_PHY_ID_MASK }, 2311f5e1cabfSMichal Simek { MARVELL_PHY_ID_88E1112, MARVELL_PHY_ID_MASK }, 2312f5e1cabfSMichal Simek { MARVELL_PHY_ID_88E1111, MARVELL_PHY_ID_MASK }, 2313f5e1cabfSMichal Simek { MARVELL_PHY_ID_88E1118, MARVELL_PHY_ID_MASK }, 2314f5e1cabfSMichal Simek { MARVELL_PHY_ID_88E1121R, MARVELL_PHY_ID_MASK }, 2315f5e1cabfSMichal Simek { MARVELL_PHY_ID_88E1145, MARVELL_PHY_ID_MASK }, 2316f5e1cabfSMichal Simek { MARVELL_PHY_ID_88E1149R, MARVELL_PHY_ID_MASK }, 2317f5e1cabfSMichal Simek { MARVELL_PHY_ID_88E1240, MARVELL_PHY_ID_MASK }, 2318f5e1cabfSMichal Simek { MARVELL_PHY_ID_88E1318S, MARVELL_PHY_ID_MASK }, 23193da09a51SMichal Simek { MARVELL_PHY_ID_88E1116R, MARVELL_PHY_ID_MASK }, 232010e24caaSMichal Simek { MARVELL_PHY_ID_88E1510, MARVELL_PHY_ID_MASK }, 2321819ec8e1SAndrew Lunn { MARVELL_PHY_ID_88E1540, MARVELL_PHY_ID_MASK }, 232260f06fdeSAndrew Lunn { MARVELL_PHY_ID_88E1545, MARVELL_PHY_ID_MASK }, 23236b358aedSSebastian Hesselbarth { MARVELL_PHY_ID_88E3016, MARVELL_PHY_ID_MASK }, 2324e4cf8a38SAndrew Lunn { MARVELL_PHY_ID_88E6390, MARVELL_PHY_ID_MASK }, 23254e4f10f6SDavid Woodhouse { } 23264e4f10f6SDavid Woodhouse }; 23274e4f10f6SDavid Woodhouse 23284e4f10f6SDavid Woodhouse MODULE_DEVICE_TABLE(mdio, marvell_tbl); 2329