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 831407353ecSClemens Gruber static int m88e1510_config_init(struct phy_device *phydev) 832407353ecSClemens Gruber { 833407353ecSClemens Gruber int err; 834407353ecSClemens Gruber 835407353ecSClemens Gruber /* SGMII-to-Copper mode initialization */ 836407353ecSClemens Gruber if (phydev->interface == PHY_INTERFACE_MODE_SGMII) { 8376623c0fbSRussell King u32 pause; 8386623c0fbSRussell King 839407353ecSClemens Gruber /* Select page 18 */ 8406427bb2dSAndrew Lunn err = marvell_set_page(phydev, 18); 841407353ecSClemens Gruber if (err < 0) 842407353ecSClemens Gruber return err; 843407353ecSClemens Gruber 844407353ecSClemens Gruber /* In reg 20, write MODE[2:0] = 0x1 (SGMII to Copper) */ 845fea23fb5SRussell King err = phy_modify(phydev, MII_88E1510_GEN_CTRL_REG_1, 846f102852fSRussell King MII_88E1510_GEN_CTRL_REG_1_MODE_MASK, 847fea23fb5SRussell King MII_88E1510_GEN_CTRL_REG_1_MODE_SGMII); 848407353ecSClemens Gruber if (err < 0) 849407353ecSClemens Gruber return err; 850407353ecSClemens Gruber 851407353ecSClemens Gruber /* PHY reset is necessary after changing MODE[2:0] */ 852fea23fb5SRussell King err = phy_modify(phydev, MII_88E1510_GEN_CTRL_REG_1, 0, 853fea23fb5SRussell King MII_88E1510_GEN_CTRL_REG_1_RESET); 854407353ecSClemens Gruber if (err < 0) 855407353ecSClemens Gruber return err; 856407353ecSClemens Gruber 857407353ecSClemens Gruber /* Reset page selection */ 85852295666SAndrew Lunn err = marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE); 859407353ecSClemens Gruber if (err < 0) 860407353ecSClemens Gruber return err; 8616623c0fbSRussell King 8626623c0fbSRussell King /* There appears to be a bug in the 88e1512 when used in 8636623c0fbSRussell King * SGMII to copper mode, where the AN advertisment register 8646623c0fbSRussell King * clears the pause bits each time a negotiation occurs. 8656623c0fbSRussell King * This means we can never be truely sure what was advertised, 8666623c0fbSRussell King * so disable Pause support. 8676623c0fbSRussell King */ 8686623c0fbSRussell King pause = SUPPORTED_Pause | SUPPORTED_Asym_Pause; 8696623c0fbSRussell King phydev->supported &= ~pause; 8706623c0fbSRussell King phydev->advertising &= ~pause; 871407353ecSClemens Gruber } 872407353ecSClemens Gruber 873fdecf36fSClemens Gruber return m88e1121_config_init(phydev); 874407353ecSClemens Gruber } 875407353ecSClemens Gruber 876605f196eSRon Madrid static int m88e1118_config_aneg(struct phy_device *phydev) 877605f196eSRon Madrid { 878605f196eSRon Madrid int err; 879605f196eSRon Madrid 88034386344SAndrew Lunn err = genphy_soft_reset(phydev); 881605f196eSRon Madrid if (err < 0) 882605f196eSRon Madrid return err; 883605f196eSRon Madrid 884fecd5e91SAndrew Lunn err = marvell_set_polarity(phydev, phydev->mdix_ctrl); 885605f196eSRon Madrid if (err < 0) 886605f196eSRon Madrid return err; 887605f196eSRon Madrid 888605f196eSRon Madrid err = genphy_config_aneg(phydev); 889605f196eSRon Madrid return 0; 890605f196eSRon Madrid } 891605f196eSRon Madrid 892605f196eSRon Madrid static int m88e1118_config_init(struct phy_device *phydev) 893605f196eSRon Madrid { 894605f196eSRon Madrid int err; 895605f196eSRon Madrid 896605f196eSRon Madrid /* Change address */ 89752295666SAndrew Lunn err = marvell_set_page(phydev, MII_MARVELL_MSCR_PAGE); 898605f196eSRon Madrid if (err < 0) 899605f196eSRon Madrid return err; 900605f196eSRon Madrid 901605f196eSRon Madrid /* Enable 1000 Mbit */ 902605f196eSRon Madrid err = phy_write(phydev, 0x15, 0x1070); 903605f196eSRon Madrid if (err < 0) 904605f196eSRon Madrid return err; 905605f196eSRon Madrid 906605f196eSRon Madrid /* Change address */ 90752295666SAndrew Lunn err = marvell_set_page(phydev, MII_MARVELL_LED_PAGE); 908605f196eSRon Madrid if (err < 0) 909605f196eSRon Madrid return err; 910605f196eSRon Madrid 911605f196eSRon Madrid /* Adjust LED Control */ 9122f495c39SBenjamin Herrenschmidt if (phydev->dev_flags & MARVELL_PHY_M1118_DNS323_LEDS) 9132f495c39SBenjamin Herrenschmidt err = phy_write(phydev, 0x10, 0x1100); 9142f495c39SBenjamin Herrenschmidt else 915605f196eSRon Madrid err = phy_write(phydev, 0x10, 0x021e); 916605f196eSRon Madrid if (err < 0) 917605f196eSRon Madrid return err; 918605f196eSRon Madrid 919cf41a51dSDavid Daney err = marvell_of_reg_init(phydev); 920cf41a51dSDavid Daney if (err < 0) 921cf41a51dSDavid Daney return err; 922cf41a51dSDavid Daney 923605f196eSRon Madrid /* Reset address */ 92452295666SAndrew Lunn err = marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE); 925605f196eSRon Madrid if (err < 0) 926605f196eSRon Madrid return err; 927605f196eSRon Madrid 92834386344SAndrew Lunn return genphy_soft_reset(phydev); 929605f196eSRon Madrid } 930605f196eSRon Madrid 93190600732SDavid Daney static int m88e1149_config_init(struct phy_device *phydev) 93290600732SDavid Daney { 93390600732SDavid Daney int err; 93490600732SDavid Daney 93590600732SDavid Daney /* Change address */ 93652295666SAndrew Lunn err = marvell_set_page(phydev, MII_MARVELL_MSCR_PAGE); 93790600732SDavid Daney if (err < 0) 93890600732SDavid Daney return err; 93990600732SDavid Daney 94090600732SDavid Daney /* Enable 1000 Mbit */ 94190600732SDavid Daney err = phy_write(phydev, 0x15, 0x1048); 94290600732SDavid Daney if (err < 0) 94390600732SDavid Daney return err; 94490600732SDavid Daney 945cf41a51dSDavid Daney err = marvell_of_reg_init(phydev); 946cf41a51dSDavid Daney if (err < 0) 947cf41a51dSDavid Daney return err; 948cf41a51dSDavid Daney 94990600732SDavid Daney /* Reset address */ 95052295666SAndrew Lunn err = marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE); 95190600732SDavid Daney if (err < 0) 95290600732SDavid Daney return err; 95390600732SDavid Daney 95434386344SAndrew Lunn return genphy_soft_reset(phydev); 95590600732SDavid Daney } 95690600732SDavid Daney 957e1dde8dcSAndrew Lunn static int m88e1145_config_init_rgmii(struct phy_device *phydev) 95876884679SAndy Fleming { 95976884679SAndy Fleming int err; 960e69d9ed4SAndrew Lunn 96161111598SAndrew Lunn err = m88e1111_config_init_rgmii_delays(phydev); 96276884679SAndy Fleming if (err < 0) 96376884679SAndy Fleming return err; 96476884679SAndy Fleming 9652f495c39SBenjamin Herrenschmidt if (phydev->dev_flags & MARVELL_PHY_M1145_FLAGS_RESISTANCE) { 96676884679SAndy Fleming err = phy_write(phydev, 0x1d, 0x0012); 96776884679SAndy Fleming if (err < 0) 96876884679SAndy Fleming return err; 96976884679SAndy Fleming 970f102852fSRussell King err = phy_modify(phydev, 0x1e, 0x0fc0, 971fea23fb5SRussell King 2 << 9 | /* 36 ohm */ 972fea23fb5SRussell King 2 << 6); /* 39 ohm */ 97376884679SAndy Fleming if (err < 0) 97476884679SAndy Fleming return err; 97576884679SAndy Fleming 97676884679SAndy Fleming err = phy_write(phydev, 0x1d, 0x3); 97776884679SAndy Fleming if (err < 0) 97876884679SAndy Fleming return err; 97976884679SAndy Fleming 98076884679SAndy Fleming err = phy_write(phydev, 0x1e, 0x8000); 981e1dde8dcSAndrew Lunn } 98276884679SAndy Fleming return err; 98376884679SAndy Fleming } 98476884679SAndy Fleming 985e1dde8dcSAndrew Lunn static int m88e1145_config_init_sgmii(struct phy_device *phydev) 986e1dde8dcSAndrew Lunn { 987865b813aSAndrew Lunn return m88e1111_config_init_hwcfg_mode( 988865b813aSAndrew Lunn phydev, MII_M1111_HWCFG_MODE_SGMII_NO_CLK, 989865b813aSAndrew Lunn MII_M1111_HWCFG_FIBER_COPPER_AUTO); 990e1dde8dcSAndrew Lunn } 991e1dde8dcSAndrew Lunn 992e1dde8dcSAndrew Lunn static int m88e1145_config_init(struct phy_device *phydev) 993e1dde8dcSAndrew Lunn { 994e1dde8dcSAndrew Lunn int err; 995e1dde8dcSAndrew Lunn 996e1dde8dcSAndrew Lunn /* Take care of errata E0 & E1 */ 997e1dde8dcSAndrew Lunn err = phy_write(phydev, 0x1d, 0x001b); 998e1dde8dcSAndrew Lunn if (err < 0) 999e1dde8dcSAndrew Lunn return err; 1000e1dde8dcSAndrew Lunn 1001e1dde8dcSAndrew Lunn err = phy_write(phydev, 0x1e, 0x418f); 1002e1dde8dcSAndrew Lunn if (err < 0) 1003e1dde8dcSAndrew Lunn return err; 1004e1dde8dcSAndrew Lunn 1005e1dde8dcSAndrew Lunn err = phy_write(phydev, 0x1d, 0x0016); 1006e1dde8dcSAndrew Lunn if (err < 0) 1007e1dde8dcSAndrew Lunn return err; 1008e1dde8dcSAndrew Lunn 1009e1dde8dcSAndrew Lunn err = phy_write(phydev, 0x1e, 0xa2da); 1010e1dde8dcSAndrew Lunn if (err < 0) 1011e1dde8dcSAndrew Lunn return err; 1012e1dde8dcSAndrew Lunn 1013e1dde8dcSAndrew Lunn if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID) { 1014e1dde8dcSAndrew Lunn err = m88e1145_config_init_rgmii(phydev); 1015e1dde8dcSAndrew Lunn if (err < 0) 1016e1dde8dcSAndrew Lunn return err; 1017e1dde8dcSAndrew Lunn } 1018e1dde8dcSAndrew Lunn 1019e1dde8dcSAndrew Lunn if (phydev->interface == PHY_INTERFACE_MODE_SGMII) { 1020e1dde8dcSAndrew Lunn err = m88e1145_config_init_sgmii(phydev); 1021b0224175SViet Nga Dao if (err < 0) 1022b0224175SViet Nga Dao return err; 1023b0224175SViet Nga Dao } 1024b0224175SViet Nga Dao 1025cf41a51dSDavid Daney err = marvell_of_reg_init(phydev); 1026cf41a51dSDavid Daney if (err < 0) 1027cf41a51dSDavid Daney return err; 1028cf41a51dSDavid Daney 102976884679SAndy Fleming return 0; 103076884679SAndy Fleming } 103100db8189SAndy Fleming 10326cfb3bccSCharles-Antoine Couret /** 10336cfb3bccSCharles-Antoine Couret * fiber_lpa_to_ethtool_lpa_t 10346cfb3bccSCharles-Antoine Couret * @lpa: value of the MII_LPA register for fiber link 1035be937f1fSAlexandr Smirnov * 10366cfb3bccSCharles-Antoine Couret * A small helper function that translates MII_LPA 10376cfb3bccSCharles-Antoine Couret * bits to ethtool LP advertisement settings. 10386cfb3bccSCharles-Antoine Couret */ 10396cfb3bccSCharles-Antoine Couret static u32 fiber_lpa_to_ethtool_lpa_t(u32 lpa) 10406cfb3bccSCharles-Antoine Couret { 10416cfb3bccSCharles-Antoine Couret u32 result = 0; 10426cfb3bccSCharles-Antoine Couret 10436cfb3bccSCharles-Antoine Couret if (lpa & LPA_FIBER_1000HALF) 10446cfb3bccSCharles-Antoine Couret result |= ADVERTISED_1000baseT_Half; 10456cfb3bccSCharles-Antoine Couret if (lpa & LPA_FIBER_1000FULL) 10466cfb3bccSCharles-Antoine Couret result |= ADVERTISED_1000baseT_Full; 10476cfb3bccSCharles-Antoine Couret 10486cfb3bccSCharles-Antoine Couret return result; 10496cfb3bccSCharles-Antoine Couret } 10506cfb3bccSCharles-Antoine Couret 10516cfb3bccSCharles-Antoine Couret /** 10526cfb3bccSCharles-Antoine Couret * marvell_update_link - update link status in real time in @phydev 10536cfb3bccSCharles-Antoine Couret * @phydev: target phy_device struct 10546cfb3bccSCharles-Antoine Couret * 10556cfb3bccSCharles-Antoine Couret * Description: Update the value in phydev->link to reflect the 10566cfb3bccSCharles-Antoine Couret * current link value. 10576cfb3bccSCharles-Antoine Couret */ 10586cfb3bccSCharles-Antoine Couret static int marvell_update_link(struct phy_device *phydev, int fiber) 10596cfb3bccSCharles-Antoine Couret { 10606cfb3bccSCharles-Antoine Couret int status; 10616cfb3bccSCharles-Antoine Couret 10626cfb3bccSCharles-Antoine Couret /* Use the generic register for copper link, or specific 10630c3439bcSAndrew Lunn * register for fiber case 10640c3439bcSAndrew Lunn */ 10656cfb3bccSCharles-Antoine Couret if (fiber) { 10666cfb3bccSCharles-Antoine Couret status = phy_read(phydev, MII_M1011_PHY_STATUS); 10676cfb3bccSCharles-Antoine Couret if (status < 0) 10686cfb3bccSCharles-Antoine Couret return status; 10696cfb3bccSCharles-Antoine Couret 10706cfb3bccSCharles-Antoine Couret if ((status & REGISTER_LINK_STATUS) == 0) 10716cfb3bccSCharles-Antoine Couret phydev->link = 0; 10726cfb3bccSCharles-Antoine Couret else 10736cfb3bccSCharles-Antoine Couret phydev->link = 1; 10746cfb3bccSCharles-Antoine Couret } else { 10756cfb3bccSCharles-Antoine Couret return genphy_update_link(phydev); 10766cfb3bccSCharles-Antoine Couret } 10776cfb3bccSCharles-Antoine Couret 10786cfb3bccSCharles-Antoine Couret return 0; 10796cfb3bccSCharles-Antoine Couret } 10806cfb3bccSCharles-Antoine Couret 1081e1dde8dcSAndrew Lunn static int marvell_read_status_page_an(struct phy_device *phydev, 1082e1dde8dcSAndrew Lunn int fiber) 1083be937f1fSAlexandr Smirnov { 1084e1dde8dcSAndrew Lunn int status; 1085be937f1fSAlexandr Smirnov int lpa; 1086357cd64cSRussell King int lpagb; 1087be937f1fSAlexandr Smirnov 1088be937f1fSAlexandr Smirnov status = phy_read(phydev, MII_M1011_PHY_STATUS); 1089be937f1fSAlexandr Smirnov if (status < 0) 1090be937f1fSAlexandr Smirnov return status; 1091be937f1fSAlexandr Smirnov 1092be937f1fSAlexandr Smirnov lpa = phy_read(phydev, MII_LPA); 1093be937f1fSAlexandr Smirnov if (lpa < 0) 1094be937f1fSAlexandr Smirnov return lpa; 1095be937f1fSAlexandr Smirnov 1096357cd64cSRussell King lpagb = phy_read(phydev, MII_STAT1000); 1097357cd64cSRussell King if (lpagb < 0) 1098357cd64cSRussell King return lpagb; 1099357cd64cSRussell King 1100be937f1fSAlexandr Smirnov if (status & MII_M1011_PHY_STATUS_FULLDUPLEX) 1101be937f1fSAlexandr Smirnov phydev->duplex = DUPLEX_FULL; 1102be937f1fSAlexandr Smirnov else 1103be937f1fSAlexandr Smirnov phydev->duplex = DUPLEX_HALF; 1104be937f1fSAlexandr Smirnov 1105be937f1fSAlexandr Smirnov status = status & MII_M1011_PHY_STATUS_SPD_MASK; 11064f48ed32SAndrew Lunn phydev->pause = 0; 11074f48ed32SAndrew Lunn phydev->asym_pause = 0; 1108be937f1fSAlexandr Smirnov 1109be937f1fSAlexandr Smirnov switch (status) { 1110be937f1fSAlexandr Smirnov case MII_M1011_PHY_STATUS_1000: 1111be937f1fSAlexandr Smirnov phydev->speed = SPEED_1000; 1112be937f1fSAlexandr Smirnov break; 1113be937f1fSAlexandr Smirnov 1114be937f1fSAlexandr Smirnov case MII_M1011_PHY_STATUS_100: 1115be937f1fSAlexandr Smirnov phydev->speed = SPEED_100; 1116be937f1fSAlexandr Smirnov break; 1117be937f1fSAlexandr Smirnov 1118be937f1fSAlexandr Smirnov default: 1119be937f1fSAlexandr Smirnov phydev->speed = SPEED_10; 1120be937f1fSAlexandr Smirnov break; 1121be937f1fSAlexandr Smirnov } 1122be937f1fSAlexandr Smirnov 11236cfb3bccSCharles-Antoine Couret if (!fiber) { 1124e1dde8dcSAndrew Lunn phydev->lp_advertising = 1125e1dde8dcSAndrew Lunn mii_stat1000_to_ethtool_lpa_t(lpagb) | 11266cfb3bccSCharles-Antoine Couret mii_lpa_to_ethtool_lpa_t(lpa); 11276cfb3bccSCharles-Antoine Couret 1128be937f1fSAlexandr Smirnov if (phydev->duplex == DUPLEX_FULL) { 1129be937f1fSAlexandr Smirnov phydev->pause = lpa & LPA_PAUSE_CAP ? 1 : 0; 1130be937f1fSAlexandr Smirnov phydev->asym_pause = lpa & LPA_PAUSE_ASYM ? 1 : 0; 1131be937f1fSAlexandr Smirnov } 1132be937f1fSAlexandr Smirnov } else { 11336cfb3bccSCharles-Antoine Couret /* The fiber link is only 1000M capable */ 11346cfb3bccSCharles-Antoine Couret phydev->lp_advertising = fiber_lpa_to_ethtool_lpa_t(lpa); 11356cfb3bccSCharles-Antoine Couret 11366cfb3bccSCharles-Antoine Couret if (phydev->duplex == DUPLEX_FULL) { 11376cfb3bccSCharles-Antoine Couret if (!(lpa & LPA_PAUSE_FIBER)) { 11386cfb3bccSCharles-Antoine Couret phydev->pause = 0; 11396cfb3bccSCharles-Antoine Couret phydev->asym_pause = 0; 11406cfb3bccSCharles-Antoine Couret } else if ((lpa & LPA_PAUSE_ASYM_FIBER)) { 11416cfb3bccSCharles-Antoine Couret phydev->pause = 1; 11426cfb3bccSCharles-Antoine Couret phydev->asym_pause = 1; 11436cfb3bccSCharles-Antoine Couret } else { 11446cfb3bccSCharles-Antoine Couret phydev->pause = 1; 11456cfb3bccSCharles-Antoine Couret phydev->asym_pause = 0; 11466cfb3bccSCharles-Antoine Couret } 11476cfb3bccSCharles-Antoine Couret } 11486cfb3bccSCharles-Antoine Couret } 1149e1dde8dcSAndrew Lunn return 0; 1150e1dde8dcSAndrew Lunn } 1151e1dde8dcSAndrew Lunn 1152e1dde8dcSAndrew Lunn static int marvell_read_status_page_fixed(struct phy_device *phydev) 1153e1dde8dcSAndrew Lunn { 1154be937f1fSAlexandr Smirnov int bmcr = phy_read(phydev, MII_BMCR); 1155be937f1fSAlexandr Smirnov 1156be937f1fSAlexandr Smirnov if (bmcr < 0) 1157be937f1fSAlexandr Smirnov return bmcr; 1158be937f1fSAlexandr Smirnov 1159be937f1fSAlexandr Smirnov if (bmcr & BMCR_FULLDPLX) 1160be937f1fSAlexandr Smirnov phydev->duplex = DUPLEX_FULL; 1161be937f1fSAlexandr Smirnov else 1162be937f1fSAlexandr Smirnov phydev->duplex = DUPLEX_HALF; 1163be937f1fSAlexandr Smirnov 1164be937f1fSAlexandr Smirnov if (bmcr & BMCR_SPEED1000) 1165be937f1fSAlexandr Smirnov phydev->speed = SPEED_1000; 1166be937f1fSAlexandr Smirnov else if (bmcr & BMCR_SPEED100) 1167be937f1fSAlexandr Smirnov phydev->speed = SPEED_100; 1168be937f1fSAlexandr Smirnov else 1169be937f1fSAlexandr Smirnov phydev->speed = SPEED_10; 1170be937f1fSAlexandr Smirnov 11714f48ed32SAndrew Lunn phydev->pause = 0; 11724f48ed32SAndrew Lunn phydev->asym_pause = 0; 1173357cd64cSRussell King phydev->lp_advertising = 0; 1174be937f1fSAlexandr Smirnov 1175be937f1fSAlexandr Smirnov return 0; 1176be937f1fSAlexandr Smirnov } 1177be937f1fSAlexandr Smirnov 1178e1dde8dcSAndrew Lunn /* marvell_read_status_page 1179e1dde8dcSAndrew Lunn * 1180e1dde8dcSAndrew Lunn * Description: 1181e1dde8dcSAndrew Lunn * Check the link, then figure out the current state 1182e1dde8dcSAndrew Lunn * by comparing what we advertise with what the link partner 1183e1dde8dcSAndrew Lunn * advertises. Start by checking the gigabit possibilities, 1184e1dde8dcSAndrew Lunn * then move on to 10/100. 1185e1dde8dcSAndrew Lunn */ 1186e1dde8dcSAndrew Lunn static int marvell_read_status_page(struct phy_device *phydev, int page) 1187e1dde8dcSAndrew Lunn { 1188e1dde8dcSAndrew Lunn int fiber; 1189e1dde8dcSAndrew Lunn int err; 1190e1dde8dcSAndrew Lunn 1191e1dde8dcSAndrew Lunn /* Detect and update the link, but return if there 1192e1dde8dcSAndrew Lunn * was an error 1193e1dde8dcSAndrew Lunn */ 119452295666SAndrew Lunn if (page == MII_MARVELL_FIBER_PAGE) 1195e1dde8dcSAndrew Lunn fiber = 1; 1196e1dde8dcSAndrew Lunn else 1197e1dde8dcSAndrew Lunn fiber = 0; 1198e1dde8dcSAndrew Lunn 1199e1dde8dcSAndrew Lunn err = marvell_update_link(phydev, fiber); 1200e1dde8dcSAndrew Lunn if (err) 1201e1dde8dcSAndrew Lunn return err; 1202e1dde8dcSAndrew Lunn 1203e1dde8dcSAndrew Lunn if (phydev->autoneg == AUTONEG_ENABLE) 1204e1dde8dcSAndrew Lunn err = marvell_read_status_page_an(phydev, fiber); 1205e1dde8dcSAndrew Lunn else 1206e1dde8dcSAndrew Lunn err = marvell_read_status_page_fixed(phydev); 1207e1dde8dcSAndrew Lunn 1208e1dde8dcSAndrew Lunn return err; 1209e1dde8dcSAndrew Lunn } 1210e1dde8dcSAndrew Lunn 12116cfb3bccSCharles-Antoine Couret /* marvell_read_status 12126cfb3bccSCharles-Antoine Couret * 12136cfb3bccSCharles-Antoine Couret * Some Marvell's phys have two modes: fiber and copper. 12146cfb3bccSCharles-Antoine Couret * Both need status checked. 12156cfb3bccSCharles-Antoine Couret * Description: 12166cfb3bccSCharles-Antoine Couret * First, check the fiber link and status. 12176cfb3bccSCharles-Antoine Couret * If the fiber link is down, check the copper link and status which 12186cfb3bccSCharles-Antoine Couret * will be the default value if both link are down. 12196cfb3bccSCharles-Antoine Couret */ 12206cfb3bccSCharles-Antoine Couret static int marvell_read_status(struct phy_device *phydev) 12216cfb3bccSCharles-Antoine Couret { 12226cfb3bccSCharles-Antoine Couret int err; 12236cfb3bccSCharles-Antoine Couret 12246cfb3bccSCharles-Antoine Couret /* Check the fiber mode first */ 1225a13c0652SRussell King if (phydev->supported & SUPPORTED_FIBRE && 1226a13c0652SRussell King phydev->interface != PHY_INTERFACE_MODE_SGMII) { 122752295666SAndrew Lunn err = marvell_set_page(phydev, MII_MARVELL_FIBER_PAGE); 12286cfb3bccSCharles-Antoine Couret if (err < 0) 12296cfb3bccSCharles-Antoine Couret goto error; 12306cfb3bccSCharles-Antoine Couret 123152295666SAndrew Lunn err = marvell_read_status_page(phydev, MII_MARVELL_FIBER_PAGE); 12326cfb3bccSCharles-Antoine Couret if (err < 0) 12336cfb3bccSCharles-Antoine Couret goto error; 12346cfb3bccSCharles-Antoine Couret 12350c3439bcSAndrew Lunn /* If the fiber link is up, it is the selected and 12360c3439bcSAndrew Lunn * used link. In this case, we need to stay in the 12370c3439bcSAndrew Lunn * fiber page. Please to be careful about that, avoid 12380c3439bcSAndrew Lunn * to restore Copper page in other functions which 12390c3439bcSAndrew Lunn * could break the behaviour for some fiber phy like 12400c3439bcSAndrew Lunn * 88E1512. 12410c3439bcSAndrew Lunn */ 12426cfb3bccSCharles-Antoine Couret if (phydev->link) 12436cfb3bccSCharles-Antoine Couret return 0; 12446cfb3bccSCharles-Antoine Couret 12456cfb3bccSCharles-Antoine Couret /* If fiber link is down, check and save copper mode state */ 124652295666SAndrew Lunn err = marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE); 12476cfb3bccSCharles-Antoine Couret if (err < 0) 12486cfb3bccSCharles-Antoine Couret goto error; 12496cfb3bccSCharles-Antoine Couret } 12506cfb3bccSCharles-Antoine Couret 125152295666SAndrew Lunn return marvell_read_status_page(phydev, MII_MARVELL_COPPER_PAGE); 12526cfb3bccSCharles-Antoine Couret 12536cfb3bccSCharles-Antoine Couret error: 125452295666SAndrew Lunn marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE); 12556cfb3bccSCharles-Antoine Couret return err; 12566cfb3bccSCharles-Antoine Couret } 12573758be3dSCharles-Antoine Couret 12583758be3dSCharles-Antoine Couret /* marvell_suspend 12593758be3dSCharles-Antoine Couret * 12603758be3dSCharles-Antoine Couret * Some Marvell's phys have two modes: fiber and copper. 12613758be3dSCharles-Antoine Couret * Both need to be suspended 12623758be3dSCharles-Antoine Couret */ 12633758be3dSCharles-Antoine Couret static int marvell_suspend(struct phy_device *phydev) 12643758be3dSCharles-Antoine Couret { 12653758be3dSCharles-Antoine Couret int err; 12663758be3dSCharles-Antoine Couret 12673758be3dSCharles-Antoine Couret /* Suspend the fiber mode first */ 12683758be3dSCharles-Antoine Couret if (!(phydev->supported & SUPPORTED_FIBRE)) { 126952295666SAndrew Lunn err = marvell_set_page(phydev, MII_MARVELL_FIBER_PAGE); 12703758be3dSCharles-Antoine Couret if (err < 0) 12713758be3dSCharles-Antoine Couret goto error; 12723758be3dSCharles-Antoine Couret 12733758be3dSCharles-Antoine Couret /* With the page set, use the generic suspend */ 12743758be3dSCharles-Antoine Couret err = genphy_suspend(phydev); 12753758be3dSCharles-Antoine Couret if (err < 0) 12763758be3dSCharles-Antoine Couret goto error; 12773758be3dSCharles-Antoine Couret 12783758be3dSCharles-Antoine Couret /* Then, the copper link */ 127952295666SAndrew Lunn err = marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE); 12803758be3dSCharles-Antoine Couret if (err < 0) 12813758be3dSCharles-Antoine Couret goto error; 12823758be3dSCharles-Antoine Couret } 12833758be3dSCharles-Antoine Couret 12843758be3dSCharles-Antoine Couret /* With the page set, use the generic suspend */ 12853758be3dSCharles-Antoine Couret return genphy_suspend(phydev); 12863758be3dSCharles-Antoine Couret 12873758be3dSCharles-Antoine Couret error: 128852295666SAndrew Lunn marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE); 12893758be3dSCharles-Antoine Couret return err; 12903758be3dSCharles-Antoine Couret } 12913758be3dSCharles-Antoine Couret 12923758be3dSCharles-Antoine Couret /* marvell_resume 12933758be3dSCharles-Antoine Couret * 12943758be3dSCharles-Antoine Couret * Some Marvell's phys have two modes: fiber and copper. 12953758be3dSCharles-Antoine Couret * Both need to be resumed 12963758be3dSCharles-Antoine Couret */ 12973758be3dSCharles-Antoine Couret static int marvell_resume(struct phy_device *phydev) 12983758be3dSCharles-Antoine Couret { 12993758be3dSCharles-Antoine Couret int err; 13003758be3dSCharles-Antoine Couret 13013758be3dSCharles-Antoine Couret /* Resume the fiber mode first */ 13023758be3dSCharles-Antoine Couret if (!(phydev->supported & SUPPORTED_FIBRE)) { 130352295666SAndrew Lunn err = marvell_set_page(phydev, MII_MARVELL_FIBER_PAGE); 13043758be3dSCharles-Antoine Couret if (err < 0) 13053758be3dSCharles-Antoine Couret goto error; 13063758be3dSCharles-Antoine Couret 13073758be3dSCharles-Antoine Couret /* With the page set, use the generic resume */ 13083758be3dSCharles-Antoine Couret err = genphy_resume(phydev); 13093758be3dSCharles-Antoine Couret if (err < 0) 13103758be3dSCharles-Antoine Couret goto error; 13113758be3dSCharles-Antoine Couret 13123758be3dSCharles-Antoine Couret /* Then, the copper link */ 131352295666SAndrew Lunn err = marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE); 13143758be3dSCharles-Antoine Couret if (err < 0) 13153758be3dSCharles-Antoine Couret goto error; 13163758be3dSCharles-Antoine Couret } 13173758be3dSCharles-Antoine Couret 13183758be3dSCharles-Antoine Couret /* With the page set, use the generic resume */ 13193758be3dSCharles-Antoine Couret return genphy_resume(phydev); 13203758be3dSCharles-Antoine Couret 13213758be3dSCharles-Antoine Couret error: 132252295666SAndrew Lunn marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE); 13233758be3dSCharles-Antoine Couret return err; 13243758be3dSCharles-Antoine Couret } 13253758be3dSCharles-Antoine Couret 13266b358aedSSebastian Hesselbarth static int marvell_aneg_done(struct phy_device *phydev) 13276b358aedSSebastian Hesselbarth { 13286b358aedSSebastian Hesselbarth int retval = phy_read(phydev, MII_M1011_PHY_STATUS); 1329e69d9ed4SAndrew Lunn 13306b358aedSSebastian Hesselbarth return (retval < 0) ? retval : (retval & MII_M1011_PHY_STATUS_RESOLVED); 13316b358aedSSebastian Hesselbarth } 13326b358aedSSebastian Hesselbarth 1333dcd07be3SAnatolij Gustschin static int m88e1121_did_interrupt(struct phy_device *phydev) 1334dcd07be3SAnatolij Gustschin { 1335dcd07be3SAnatolij Gustschin int imask; 1336dcd07be3SAnatolij Gustschin 1337dcd07be3SAnatolij Gustschin imask = phy_read(phydev, MII_M1011_IEVENT); 1338dcd07be3SAnatolij Gustschin 1339dcd07be3SAnatolij Gustschin if (imask & MII_M1011_IMASK_INIT) 1340dcd07be3SAnatolij Gustschin return 1; 1341dcd07be3SAnatolij Gustschin 1342dcd07be3SAnatolij Gustschin return 0; 1343dcd07be3SAnatolij Gustschin } 1344dcd07be3SAnatolij Gustschin 134523beb38fSAndrew Lunn static void m88e1318_get_wol(struct phy_device *phydev, 134623beb38fSAndrew Lunn struct ethtool_wolinfo *wol) 13473871c387SMichael Stapelberg { 1348424ca4c5SRussell King int oldpage, ret = 0; 1349424ca4c5SRussell King 13503871c387SMichael Stapelberg wol->supported = WAKE_MAGIC; 13513871c387SMichael Stapelberg wol->wolopts = 0; 13523871c387SMichael Stapelberg 1353424ca4c5SRussell King oldpage = phy_select_page(phydev, MII_MARVELL_WOL_PAGE); 1354424ca4c5SRussell King if (oldpage < 0) 1355424ca4c5SRussell King goto error; 13563871c387SMichael Stapelberg 1357424ca4c5SRussell King ret = __phy_read(phydev, MII_88E1318S_PHY_WOL_CTRL); 1358424ca4c5SRussell King if (ret & MII_88E1318S_PHY_WOL_CTRL_MAGIC_PACKET_MATCH_ENABLE) 13593871c387SMichael Stapelberg wol->wolopts |= WAKE_MAGIC; 13603871c387SMichael Stapelberg 1361424ca4c5SRussell King error: 1362424ca4c5SRussell King phy_restore_page(phydev, oldpage, ret); 13633871c387SMichael Stapelberg } 13643871c387SMichael Stapelberg 136523beb38fSAndrew Lunn static int m88e1318_set_wol(struct phy_device *phydev, 136623beb38fSAndrew Lunn struct ethtool_wolinfo *wol) 13673871c387SMichael Stapelberg { 1368424ca4c5SRussell King int err = 0, oldpage; 13693871c387SMichael Stapelberg 1370424ca4c5SRussell King oldpage = phy_save_page(phydev); 1371424ca4c5SRussell King if (oldpage < 0) 1372424ca4c5SRussell King goto error; 13733871c387SMichael Stapelberg 13743871c387SMichael Stapelberg if (wol->wolopts & WAKE_MAGIC) { 13753871c387SMichael Stapelberg /* Explicitly switch to page 0x00, just to be sure */ 1376424ca4c5SRussell King err = marvell_write_page(phydev, MII_MARVELL_COPPER_PAGE); 13773871c387SMichael Stapelberg if (err < 0) 1378424ca4c5SRussell King goto error; 13793871c387SMichael Stapelberg 13803871c387SMichael Stapelberg /* Enable the WOL interrupt */ 1381424ca4c5SRussell King err = __phy_modify(phydev, MII_88E1318S_PHY_CSIER, 0, 1382424ca4c5SRussell King MII_88E1318S_PHY_CSIER_WOL_EIE); 13833871c387SMichael Stapelberg if (err < 0) 1384424ca4c5SRussell King goto error; 13853871c387SMichael Stapelberg 1386424ca4c5SRussell King err = marvell_write_page(phydev, MII_MARVELL_LED_PAGE); 13873871c387SMichael Stapelberg if (err < 0) 1388424ca4c5SRussell King goto error; 13893871c387SMichael Stapelberg 13903871c387SMichael Stapelberg /* Setup LED[2] as interrupt pin (active low) */ 1391424ca4c5SRussell King err = __phy_modify(phydev, MII_88E1318S_PHY_LED_TCR, 1392f102852fSRussell King MII_88E1318S_PHY_LED_TCR_FORCE_INT, 1393424ca4c5SRussell King MII_88E1318S_PHY_LED_TCR_INTn_ENABLE | 1394424ca4c5SRussell King MII_88E1318S_PHY_LED_TCR_INT_ACTIVE_LOW); 13953871c387SMichael Stapelberg if (err < 0) 1396424ca4c5SRussell King goto error; 13973871c387SMichael Stapelberg 1398424ca4c5SRussell King err = marvell_write_page(phydev, MII_MARVELL_WOL_PAGE); 13993871c387SMichael Stapelberg if (err < 0) 1400424ca4c5SRussell King goto error; 14013871c387SMichael Stapelberg 14023871c387SMichael Stapelberg /* Store the device address for the magic packet */ 1403424ca4c5SRussell King err = __phy_write(phydev, MII_88E1318S_PHY_MAGIC_PACKET_WORD2, 14043871c387SMichael Stapelberg ((phydev->attached_dev->dev_addr[5] << 8) | 14053871c387SMichael Stapelberg phydev->attached_dev->dev_addr[4])); 14063871c387SMichael Stapelberg if (err < 0) 1407424ca4c5SRussell King goto error; 1408424ca4c5SRussell King err = __phy_write(phydev, MII_88E1318S_PHY_MAGIC_PACKET_WORD1, 14093871c387SMichael Stapelberg ((phydev->attached_dev->dev_addr[3] << 8) | 14103871c387SMichael Stapelberg phydev->attached_dev->dev_addr[2])); 14113871c387SMichael Stapelberg if (err < 0) 1412424ca4c5SRussell King goto error; 1413424ca4c5SRussell King err = __phy_write(phydev, MII_88E1318S_PHY_MAGIC_PACKET_WORD0, 14143871c387SMichael Stapelberg ((phydev->attached_dev->dev_addr[1] << 8) | 14153871c387SMichael Stapelberg phydev->attached_dev->dev_addr[0])); 14163871c387SMichael Stapelberg if (err < 0) 1417424ca4c5SRussell King goto error; 14183871c387SMichael Stapelberg 14193871c387SMichael Stapelberg /* Clear WOL status and enable magic packet matching */ 1420424ca4c5SRussell King err = __phy_modify(phydev, MII_88E1318S_PHY_WOL_CTRL, 0, 1421424ca4c5SRussell King MII_88E1318S_PHY_WOL_CTRL_CLEAR_WOL_STATUS | 1422424ca4c5SRussell King MII_88E1318S_PHY_WOL_CTRL_MAGIC_PACKET_MATCH_ENABLE); 14233871c387SMichael Stapelberg if (err < 0) 1424424ca4c5SRussell King goto error; 14253871c387SMichael Stapelberg } else { 1426424ca4c5SRussell King err = marvell_write_page(phydev, MII_MARVELL_WOL_PAGE); 14273871c387SMichael Stapelberg if (err < 0) 1428424ca4c5SRussell King goto error; 14293871c387SMichael Stapelberg 14303871c387SMichael Stapelberg /* Clear WOL status and disable magic packet matching */ 1431424ca4c5SRussell King err = __phy_modify(phydev, MII_88E1318S_PHY_WOL_CTRL, 1432f102852fSRussell King MII_88E1318S_PHY_WOL_CTRL_MAGIC_PACKET_MATCH_ENABLE, 1433424ca4c5SRussell King MII_88E1318S_PHY_WOL_CTRL_CLEAR_WOL_STATUS); 14343871c387SMichael Stapelberg if (err < 0) 1435424ca4c5SRussell King goto error; 14363871c387SMichael Stapelberg } 14373871c387SMichael Stapelberg 1438424ca4c5SRussell King error: 1439424ca4c5SRussell King return phy_restore_page(phydev, oldpage, err); 14403871c387SMichael Stapelberg } 14413871c387SMichael Stapelberg 1442d2fa47d9SAndrew Lunn static int marvell_get_sset_count(struct phy_device *phydev) 1443d2fa47d9SAndrew Lunn { 14442170fef7SCharles-Antoine Couret if (phydev->supported & SUPPORTED_FIBRE) 1445d2fa47d9SAndrew Lunn return ARRAY_SIZE(marvell_hw_stats); 14462170fef7SCharles-Antoine Couret else 14472170fef7SCharles-Antoine Couret return ARRAY_SIZE(marvell_hw_stats) - NB_FIBER_STATS; 1448d2fa47d9SAndrew Lunn } 1449d2fa47d9SAndrew Lunn 1450d2fa47d9SAndrew Lunn static void marvell_get_strings(struct phy_device *phydev, u8 *data) 1451d2fa47d9SAndrew Lunn { 1452d2fa47d9SAndrew Lunn int i; 1453d2fa47d9SAndrew Lunn 1454d2fa47d9SAndrew Lunn for (i = 0; i < ARRAY_SIZE(marvell_hw_stats); i++) { 145598409b2bSFlorian Fainelli strlcpy(data + i * ETH_GSTRING_LEN, 1456d2fa47d9SAndrew Lunn marvell_hw_stats[i].string, ETH_GSTRING_LEN); 1457d2fa47d9SAndrew Lunn } 1458d2fa47d9SAndrew Lunn } 1459d2fa47d9SAndrew Lunn 1460d2fa47d9SAndrew Lunn #ifndef UINT64_MAX 1461d2fa47d9SAndrew Lunn #define UINT64_MAX (u64)(~((u64)0)) 1462d2fa47d9SAndrew Lunn #endif 1463d2fa47d9SAndrew Lunn static u64 marvell_get_stat(struct phy_device *phydev, int i) 1464d2fa47d9SAndrew Lunn { 1465d2fa47d9SAndrew Lunn struct marvell_hw_stat stat = marvell_hw_stats[i]; 1466d2fa47d9SAndrew Lunn struct marvell_priv *priv = phydev->priv; 1467424ca4c5SRussell King int val; 1468321b4d4bSAndrew Lunn u64 ret; 1469d2fa47d9SAndrew Lunn 1470424ca4c5SRussell King val = phy_read_paged(phydev, stat.page, stat.reg); 1471d2fa47d9SAndrew Lunn if (val < 0) { 1472321b4d4bSAndrew Lunn ret = UINT64_MAX; 1473d2fa47d9SAndrew Lunn } else { 1474d2fa47d9SAndrew Lunn val = val & ((1 << stat.bits) - 1); 1475d2fa47d9SAndrew Lunn priv->stats[i] += val; 1476321b4d4bSAndrew Lunn ret = priv->stats[i]; 1477d2fa47d9SAndrew Lunn } 1478d2fa47d9SAndrew Lunn 1479321b4d4bSAndrew Lunn return ret; 1480d2fa47d9SAndrew Lunn } 1481d2fa47d9SAndrew Lunn 1482d2fa47d9SAndrew Lunn static void marvell_get_stats(struct phy_device *phydev, 1483d2fa47d9SAndrew Lunn struct ethtool_stats *stats, u64 *data) 1484d2fa47d9SAndrew Lunn { 1485d2fa47d9SAndrew Lunn int i; 1486d2fa47d9SAndrew Lunn 1487d2fa47d9SAndrew Lunn for (i = 0; i < ARRAY_SIZE(marvell_hw_stats); i++) 1488d2fa47d9SAndrew Lunn data[i] = marvell_get_stat(phydev, i); 1489d2fa47d9SAndrew Lunn } 1490d2fa47d9SAndrew Lunn 14910b04680fSAndrew Lunn #ifdef CONFIG_HWMON 14920b04680fSAndrew Lunn static int m88e1121_get_temp(struct phy_device *phydev, long *temp) 14930b04680fSAndrew Lunn { 1494975b388cSAndrew Lunn int oldpage; 1495424ca4c5SRussell King int ret = 0; 14960b04680fSAndrew Lunn int val; 14970b04680fSAndrew Lunn 14980b04680fSAndrew Lunn *temp = 0; 14990b04680fSAndrew Lunn 1500424ca4c5SRussell King oldpage = phy_select_page(phydev, MII_MARVELL_MISC_TEST_PAGE); 1501424ca4c5SRussell King if (oldpage < 0) 1502424ca4c5SRussell King goto error; 1503975b388cSAndrew Lunn 15040b04680fSAndrew Lunn /* Enable temperature sensor */ 1505424ca4c5SRussell King ret = __phy_read(phydev, MII_88E1121_MISC_TEST); 15060b04680fSAndrew Lunn if (ret < 0) 15070b04680fSAndrew Lunn goto error; 15080b04680fSAndrew Lunn 1509424ca4c5SRussell King ret = __phy_write(phydev, MII_88E1121_MISC_TEST, 15100b04680fSAndrew Lunn ret | MII_88E1121_MISC_TEST_TEMP_SENSOR_EN); 15110b04680fSAndrew Lunn if (ret < 0) 15120b04680fSAndrew Lunn goto error; 15130b04680fSAndrew Lunn 15140b04680fSAndrew Lunn /* Wait for temperature to stabilize */ 15150b04680fSAndrew Lunn usleep_range(10000, 12000); 15160b04680fSAndrew Lunn 1517424ca4c5SRussell King val = __phy_read(phydev, MII_88E1121_MISC_TEST); 15180b04680fSAndrew Lunn if (val < 0) { 15190b04680fSAndrew Lunn ret = val; 15200b04680fSAndrew Lunn goto error; 15210b04680fSAndrew Lunn } 15220b04680fSAndrew Lunn 15230b04680fSAndrew Lunn /* Disable temperature sensor */ 1524424ca4c5SRussell King ret = __phy_write(phydev, MII_88E1121_MISC_TEST, 15250b04680fSAndrew Lunn ret & ~MII_88E1121_MISC_TEST_TEMP_SENSOR_EN); 15260b04680fSAndrew Lunn if (ret < 0) 15270b04680fSAndrew Lunn goto error; 15280b04680fSAndrew Lunn 15290b04680fSAndrew Lunn *temp = ((val & MII_88E1121_MISC_TEST_TEMP_MASK) - 5) * 5000; 15300b04680fSAndrew Lunn 15310b04680fSAndrew Lunn error: 1532424ca4c5SRussell King return phy_restore_page(phydev, oldpage, ret); 15330b04680fSAndrew Lunn } 15340b04680fSAndrew Lunn 15350b04680fSAndrew Lunn static int m88e1121_hwmon_read(struct device *dev, 15360b04680fSAndrew Lunn enum hwmon_sensor_types type, 15370b04680fSAndrew Lunn u32 attr, int channel, long *temp) 15380b04680fSAndrew Lunn { 15390b04680fSAndrew Lunn struct phy_device *phydev = dev_get_drvdata(dev); 15400b04680fSAndrew Lunn int err; 15410b04680fSAndrew Lunn 15420b04680fSAndrew Lunn switch (attr) { 15430b04680fSAndrew Lunn case hwmon_temp_input: 15440b04680fSAndrew Lunn err = m88e1121_get_temp(phydev, temp); 15450b04680fSAndrew Lunn break; 15460b04680fSAndrew Lunn default: 15470b04680fSAndrew Lunn return -EOPNOTSUPP; 15480b04680fSAndrew Lunn } 15490b04680fSAndrew Lunn 15500b04680fSAndrew Lunn return err; 15510b04680fSAndrew Lunn } 15520b04680fSAndrew Lunn 15530b04680fSAndrew Lunn static umode_t m88e1121_hwmon_is_visible(const void *data, 15540b04680fSAndrew Lunn enum hwmon_sensor_types type, 15550b04680fSAndrew Lunn u32 attr, int channel) 15560b04680fSAndrew Lunn { 15570b04680fSAndrew Lunn if (type != hwmon_temp) 15580b04680fSAndrew Lunn return 0; 15590b04680fSAndrew Lunn 15600b04680fSAndrew Lunn switch (attr) { 15610b04680fSAndrew Lunn case hwmon_temp_input: 15620b04680fSAndrew Lunn return 0444; 15630b04680fSAndrew Lunn default: 15640b04680fSAndrew Lunn return 0; 15650b04680fSAndrew Lunn } 15660b04680fSAndrew Lunn } 15670b04680fSAndrew Lunn 15680b04680fSAndrew Lunn static u32 m88e1121_hwmon_chip_config[] = { 15690b04680fSAndrew Lunn HWMON_C_REGISTER_TZ, 15700b04680fSAndrew Lunn 0 15710b04680fSAndrew Lunn }; 15720b04680fSAndrew Lunn 15730b04680fSAndrew Lunn static const struct hwmon_channel_info m88e1121_hwmon_chip = { 15740b04680fSAndrew Lunn .type = hwmon_chip, 15750b04680fSAndrew Lunn .config = m88e1121_hwmon_chip_config, 15760b04680fSAndrew Lunn }; 15770b04680fSAndrew Lunn 15780b04680fSAndrew Lunn static u32 m88e1121_hwmon_temp_config[] = { 15790b04680fSAndrew Lunn HWMON_T_INPUT, 15800b04680fSAndrew Lunn 0 15810b04680fSAndrew Lunn }; 15820b04680fSAndrew Lunn 15830b04680fSAndrew Lunn static const struct hwmon_channel_info m88e1121_hwmon_temp = { 15840b04680fSAndrew Lunn .type = hwmon_temp, 15850b04680fSAndrew Lunn .config = m88e1121_hwmon_temp_config, 15860b04680fSAndrew Lunn }; 15870b04680fSAndrew Lunn 15880b04680fSAndrew Lunn static const struct hwmon_channel_info *m88e1121_hwmon_info[] = { 15890b04680fSAndrew Lunn &m88e1121_hwmon_chip, 15900b04680fSAndrew Lunn &m88e1121_hwmon_temp, 15910b04680fSAndrew Lunn NULL 15920b04680fSAndrew Lunn }; 15930b04680fSAndrew Lunn 15940b04680fSAndrew Lunn static const struct hwmon_ops m88e1121_hwmon_hwmon_ops = { 15950b04680fSAndrew Lunn .is_visible = m88e1121_hwmon_is_visible, 15960b04680fSAndrew Lunn .read = m88e1121_hwmon_read, 15970b04680fSAndrew Lunn }; 15980b04680fSAndrew Lunn 15990b04680fSAndrew Lunn static const struct hwmon_chip_info m88e1121_hwmon_chip_info = { 16000b04680fSAndrew Lunn .ops = &m88e1121_hwmon_hwmon_ops, 16010b04680fSAndrew Lunn .info = m88e1121_hwmon_info, 16020b04680fSAndrew Lunn }; 16030b04680fSAndrew Lunn 16040b04680fSAndrew Lunn static int m88e1510_get_temp(struct phy_device *phydev, long *temp) 16050b04680fSAndrew Lunn { 16060b04680fSAndrew Lunn int ret; 16070b04680fSAndrew Lunn 16080b04680fSAndrew Lunn *temp = 0; 16090b04680fSAndrew Lunn 1610424ca4c5SRussell King ret = phy_read_paged(phydev, MII_MARVELL_MISC_TEST_PAGE, 1611424ca4c5SRussell King MII_88E1510_TEMP_SENSOR); 16120b04680fSAndrew Lunn if (ret < 0) 1613424ca4c5SRussell King return ret; 16140b04680fSAndrew Lunn 16150b04680fSAndrew Lunn *temp = ((ret & MII_88E1510_TEMP_SENSOR_MASK) - 25) * 1000; 16160b04680fSAndrew Lunn 1617424ca4c5SRussell King return 0; 16180b04680fSAndrew Lunn } 16190b04680fSAndrew Lunn 1620f0a45816SColin Ian King static int m88e1510_get_temp_critical(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_88E1121_MISC_TEST); 16280b04680fSAndrew Lunn if (ret < 0) 1629424ca4c5SRussell King return ret; 16300b04680fSAndrew Lunn 16310b04680fSAndrew Lunn *temp = (((ret & MII_88E1510_MISC_TEST_TEMP_THRESHOLD_MASK) >> 16320b04680fSAndrew Lunn MII_88E1510_MISC_TEST_TEMP_THRESHOLD_SHIFT) * 5) - 25; 16330b04680fSAndrew Lunn /* convert to mC */ 16340b04680fSAndrew Lunn *temp *= 1000; 16350b04680fSAndrew Lunn 1636424ca4c5SRussell King return 0; 16370b04680fSAndrew Lunn } 16380b04680fSAndrew Lunn 1639f0a45816SColin Ian King static int m88e1510_set_temp_critical(struct phy_device *phydev, long temp) 16400b04680fSAndrew Lunn { 16410b04680fSAndrew Lunn temp = temp / 1000; 16420b04680fSAndrew Lunn temp = clamp_val(DIV_ROUND_CLOSEST(temp, 5) + 5, 0, 0x1f); 16430b04680fSAndrew Lunn 1644424ca4c5SRussell King return phy_modify_paged(phydev, MII_MARVELL_MISC_TEST_PAGE, 1645424ca4c5SRussell King MII_88E1121_MISC_TEST, 1646424ca4c5SRussell King MII_88E1510_MISC_TEST_TEMP_THRESHOLD_MASK, 1647424ca4c5SRussell King temp << MII_88E1510_MISC_TEST_TEMP_THRESHOLD_SHIFT); 16480b04680fSAndrew Lunn } 16490b04680fSAndrew Lunn 1650f0a45816SColin Ian King static int m88e1510_get_temp_alarm(struct phy_device *phydev, long *alarm) 16510b04680fSAndrew Lunn { 16520b04680fSAndrew Lunn int ret; 16530b04680fSAndrew Lunn 16540b04680fSAndrew Lunn *alarm = false; 16550b04680fSAndrew Lunn 1656424ca4c5SRussell King ret = phy_read_paged(phydev, MII_MARVELL_MISC_TEST_PAGE, 1657424ca4c5SRussell King MII_88E1121_MISC_TEST); 16580b04680fSAndrew Lunn if (ret < 0) 1659424ca4c5SRussell King return ret; 1660424ca4c5SRussell King 16610b04680fSAndrew Lunn *alarm = !!(ret & MII_88E1510_MISC_TEST_TEMP_IRQ); 16620b04680fSAndrew Lunn 1663424ca4c5SRussell King return 0; 16640b04680fSAndrew Lunn } 16650b04680fSAndrew Lunn 16660b04680fSAndrew Lunn static int m88e1510_hwmon_read(struct device *dev, 16670b04680fSAndrew Lunn enum hwmon_sensor_types type, 16680b04680fSAndrew Lunn u32 attr, int channel, long *temp) 16690b04680fSAndrew Lunn { 16700b04680fSAndrew Lunn struct phy_device *phydev = dev_get_drvdata(dev); 16710b04680fSAndrew Lunn int err; 16720b04680fSAndrew Lunn 16730b04680fSAndrew Lunn switch (attr) { 16740b04680fSAndrew Lunn case hwmon_temp_input: 16750b04680fSAndrew Lunn err = m88e1510_get_temp(phydev, temp); 16760b04680fSAndrew Lunn break; 16770b04680fSAndrew Lunn case hwmon_temp_crit: 16780b04680fSAndrew Lunn err = m88e1510_get_temp_critical(phydev, temp); 16790b04680fSAndrew Lunn break; 16800b04680fSAndrew Lunn case hwmon_temp_max_alarm: 16810b04680fSAndrew Lunn err = m88e1510_get_temp_alarm(phydev, temp); 16820b04680fSAndrew Lunn break; 16830b04680fSAndrew Lunn default: 16840b04680fSAndrew Lunn return -EOPNOTSUPP; 16850b04680fSAndrew Lunn } 16860b04680fSAndrew Lunn 16870b04680fSAndrew Lunn return err; 16880b04680fSAndrew Lunn } 16890b04680fSAndrew Lunn 16900b04680fSAndrew Lunn static int m88e1510_hwmon_write(struct device *dev, 16910b04680fSAndrew Lunn enum hwmon_sensor_types type, 16920b04680fSAndrew Lunn u32 attr, int channel, long temp) 16930b04680fSAndrew Lunn { 16940b04680fSAndrew Lunn struct phy_device *phydev = dev_get_drvdata(dev); 16950b04680fSAndrew Lunn int err; 16960b04680fSAndrew Lunn 16970b04680fSAndrew Lunn switch (attr) { 16980b04680fSAndrew Lunn case hwmon_temp_crit: 16990b04680fSAndrew Lunn err = m88e1510_set_temp_critical(phydev, temp); 17000b04680fSAndrew Lunn break; 17010b04680fSAndrew Lunn default: 17020b04680fSAndrew Lunn return -EOPNOTSUPP; 17030b04680fSAndrew Lunn } 17040b04680fSAndrew Lunn return err; 17050b04680fSAndrew Lunn } 17060b04680fSAndrew Lunn 17070b04680fSAndrew Lunn static umode_t m88e1510_hwmon_is_visible(const void *data, 17080b04680fSAndrew Lunn enum hwmon_sensor_types type, 17090b04680fSAndrew Lunn u32 attr, int channel) 17100b04680fSAndrew Lunn { 17110b04680fSAndrew Lunn if (type != hwmon_temp) 17120b04680fSAndrew Lunn return 0; 17130b04680fSAndrew Lunn 17140b04680fSAndrew Lunn switch (attr) { 17150b04680fSAndrew Lunn case hwmon_temp_input: 17160b04680fSAndrew Lunn case hwmon_temp_max_alarm: 17170b04680fSAndrew Lunn return 0444; 17180b04680fSAndrew Lunn case hwmon_temp_crit: 17190b04680fSAndrew Lunn return 0644; 17200b04680fSAndrew Lunn default: 17210b04680fSAndrew Lunn return 0; 17220b04680fSAndrew Lunn } 17230b04680fSAndrew Lunn } 17240b04680fSAndrew Lunn 17250b04680fSAndrew Lunn static u32 m88e1510_hwmon_temp_config[] = { 17260b04680fSAndrew Lunn HWMON_T_INPUT | HWMON_T_CRIT | HWMON_T_MAX_ALARM, 17270b04680fSAndrew Lunn 0 17280b04680fSAndrew Lunn }; 17290b04680fSAndrew Lunn 17300b04680fSAndrew Lunn static const struct hwmon_channel_info m88e1510_hwmon_temp = { 17310b04680fSAndrew Lunn .type = hwmon_temp, 17320b04680fSAndrew Lunn .config = m88e1510_hwmon_temp_config, 17330b04680fSAndrew Lunn }; 17340b04680fSAndrew Lunn 17350b04680fSAndrew Lunn static const struct hwmon_channel_info *m88e1510_hwmon_info[] = { 17360b04680fSAndrew Lunn &m88e1121_hwmon_chip, 17370b04680fSAndrew Lunn &m88e1510_hwmon_temp, 17380b04680fSAndrew Lunn NULL 17390b04680fSAndrew Lunn }; 17400b04680fSAndrew Lunn 17410b04680fSAndrew Lunn static const struct hwmon_ops m88e1510_hwmon_hwmon_ops = { 17420b04680fSAndrew Lunn .is_visible = m88e1510_hwmon_is_visible, 17430b04680fSAndrew Lunn .read = m88e1510_hwmon_read, 17440b04680fSAndrew Lunn .write = m88e1510_hwmon_write, 17450b04680fSAndrew Lunn }; 17460b04680fSAndrew Lunn 17470b04680fSAndrew Lunn static const struct hwmon_chip_info m88e1510_hwmon_chip_info = { 17480b04680fSAndrew Lunn .ops = &m88e1510_hwmon_hwmon_ops, 17490b04680fSAndrew Lunn .info = m88e1510_hwmon_info, 17500b04680fSAndrew Lunn }; 17510b04680fSAndrew Lunn 1752fee2d546SAndrew Lunn static int m88e6390_get_temp(struct phy_device *phydev, long *temp) 1753fee2d546SAndrew Lunn { 1754fee2d546SAndrew Lunn int sum = 0; 1755fee2d546SAndrew Lunn int oldpage; 1756fee2d546SAndrew Lunn int ret = 0; 1757fee2d546SAndrew Lunn int i; 1758fee2d546SAndrew Lunn 1759fee2d546SAndrew Lunn *temp = 0; 1760fee2d546SAndrew Lunn 1761fee2d546SAndrew Lunn oldpage = phy_select_page(phydev, MII_MARVELL_MISC_TEST_PAGE); 1762fee2d546SAndrew Lunn if (oldpage < 0) 1763fee2d546SAndrew Lunn goto error; 1764fee2d546SAndrew Lunn 1765fee2d546SAndrew Lunn /* Enable temperature sensor */ 1766fee2d546SAndrew Lunn ret = __phy_read(phydev, MII_88E6390_MISC_TEST); 1767fee2d546SAndrew Lunn if (ret < 0) 1768fee2d546SAndrew Lunn goto error; 1769fee2d546SAndrew Lunn 1770fee2d546SAndrew Lunn ret = ret & ~MII_88E6390_MISC_TEST_SAMPLE_MASK; 1771fee2d546SAndrew Lunn ret |= MII_88E6390_MISC_TEST_SAMPLE_ENABLE | 1772fee2d546SAndrew Lunn MII_88E6390_MISC_TEST_SAMPLE_1S; 1773fee2d546SAndrew Lunn 1774fee2d546SAndrew Lunn ret = __phy_write(phydev, MII_88E6390_MISC_TEST, ret); 1775fee2d546SAndrew Lunn if (ret < 0) 1776fee2d546SAndrew Lunn goto error; 1777fee2d546SAndrew Lunn 1778fee2d546SAndrew Lunn /* Wait for temperature to stabilize */ 1779fee2d546SAndrew Lunn usleep_range(10000, 12000); 1780fee2d546SAndrew Lunn 1781fee2d546SAndrew Lunn /* Reading the temperature sense has an errata. You need to read 1782fee2d546SAndrew Lunn * a number of times and take an average. 1783fee2d546SAndrew Lunn */ 1784fee2d546SAndrew Lunn for (i = 0; i < MII_88E6390_TEMP_SENSOR_SAMPLES; i++) { 1785fee2d546SAndrew Lunn ret = __phy_read(phydev, MII_88E6390_TEMP_SENSOR); 1786fee2d546SAndrew Lunn if (ret < 0) 1787fee2d546SAndrew Lunn goto error; 1788fee2d546SAndrew Lunn sum += ret & MII_88E6390_TEMP_SENSOR_MASK; 1789fee2d546SAndrew Lunn } 1790fee2d546SAndrew Lunn 1791fee2d546SAndrew Lunn sum /= MII_88E6390_TEMP_SENSOR_SAMPLES; 1792fee2d546SAndrew Lunn *temp = (sum - 75) * 1000; 1793fee2d546SAndrew Lunn 1794fee2d546SAndrew Lunn /* Disable temperature sensor */ 1795fee2d546SAndrew Lunn ret = __phy_read(phydev, MII_88E6390_MISC_TEST); 1796fee2d546SAndrew Lunn if (ret < 0) 1797fee2d546SAndrew Lunn goto error; 1798fee2d546SAndrew Lunn 1799fee2d546SAndrew Lunn ret = ret & ~MII_88E6390_MISC_TEST_SAMPLE_MASK; 1800fee2d546SAndrew Lunn ret |= MII_88E6390_MISC_TEST_SAMPLE_DISABLE; 1801fee2d546SAndrew Lunn 1802fee2d546SAndrew Lunn ret = __phy_write(phydev, MII_88E6390_MISC_TEST, ret); 1803fee2d546SAndrew Lunn 1804fee2d546SAndrew Lunn error: 1805fee2d546SAndrew Lunn phy_restore_page(phydev, oldpage, ret); 1806fee2d546SAndrew Lunn 1807fee2d546SAndrew Lunn return ret; 1808fee2d546SAndrew Lunn } 1809fee2d546SAndrew Lunn 1810fee2d546SAndrew Lunn static int m88e6390_hwmon_read(struct device *dev, 1811fee2d546SAndrew Lunn enum hwmon_sensor_types type, 1812fee2d546SAndrew Lunn u32 attr, int channel, long *temp) 1813fee2d546SAndrew Lunn { 1814fee2d546SAndrew Lunn struct phy_device *phydev = dev_get_drvdata(dev); 1815fee2d546SAndrew Lunn int err; 1816fee2d546SAndrew Lunn 1817fee2d546SAndrew Lunn switch (attr) { 1818fee2d546SAndrew Lunn case hwmon_temp_input: 1819fee2d546SAndrew Lunn err = m88e6390_get_temp(phydev, temp); 1820fee2d546SAndrew Lunn break; 1821fee2d546SAndrew Lunn default: 1822fee2d546SAndrew Lunn return -EOPNOTSUPP; 1823fee2d546SAndrew Lunn } 1824fee2d546SAndrew Lunn 1825fee2d546SAndrew Lunn return err; 1826fee2d546SAndrew Lunn } 1827fee2d546SAndrew Lunn 1828fee2d546SAndrew Lunn static umode_t m88e6390_hwmon_is_visible(const void *data, 1829fee2d546SAndrew Lunn enum hwmon_sensor_types type, 1830fee2d546SAndrew Lunn u32 attr, int channel) 1831fee2d546SAndrew Lunn { 1832fee2d546SAndrew Lunn if (type != hwmon_temp) 1833fee2d546SAndrew Lunn return 0; 1834fee2d546SAndrew Lunn 1835fee2d546SAndrew Lunn switch (attr) { 1836fee2d546SAndrew Lunn case hwmon_temp_input: 1837fee2d546SAndrew Lunn return 0444; 1838fee2d546SAndrew Lunn default: 1839fee2d546SAndrew Lunn return 0; 1840fee2d546SAndrew Lunn } 1841fee2d546SAndrew Lunn } 1842fee2d546SAndrew Lunn 1843fee2d546SAndrew Lunn static u32 m88e6390_hwmon_temp_config[] = { 1844fee2d546SAndrew Lunn HWMON_T_INPUT, 1845fee2d546SAndrew Lunn 0 1846fee2d546SAndrew Lunn }; 1847fee2d546SAndrew Lunn 1848fee2d546SAndrew Lunn static const struct hwmon_channel_info m88e6390_hwmon_temp = { 1849fee2d546SAndrew Lunn .type = hwmon_temp, 1850fee2d546SAndrew Lunn .config = m88e6390_hwmon_temp_config, 1851fee2d546SAndrew Lunn }; 1852fee2d546SAndrew Lunn 1853fee2d546SAndrew Lunn static const struct hwmon_channel_info *m88e6390_hwmon_info[] = { 1854fee2d546SAndrew Lunn &m88e1121_hwmon_chip, 1855fee2d546SAndrew Lunn &m88e6390_hwmon_temp, 1856fee2d546SAndrew Lunn NULL 1857fee2d546SAndrew Lunn }; 1858fee2d546SAndrew Lunn 1859fee2d546SAndrew Lunn static const struct hwmon_ops m88e6390_hwmon_hwmon_ops = { 1860fee2d546SAndrew Lunn .is_visible = m88e6390_hwmon_is_visible, 1861fee2d546SAndrew Lunn .read = m88e6390_hwmon_read, 1862fee2d546SAndrew Lunn }; 1863fee2d546SAndrew Lunn 1864fee2d546SAndrew Lunn static const struct hwmon_chip_info m88e6390_hwmon_chip_info = { 1865fee2d546SAndrew Lunn .ops = &m88e6390_hwmon_hwmon_ops, 1866fee2d546SAndrew Lunn .info = m88e6390_hwmon_info, 1867fee2d546SAndrew Lunn }; 1868fee2d546SAndrew Lunn 18690b04680fSAndrew Lunn static int marvell_hwmon_name(struct phy_device *phydev) 18700b04680fSAndrew Lunn { 18710b04680fSAndrew Lunn struct marvell_priv *priv = phydev->priv; 18720b04680fSAndrew Lunn struct device *dev = &phydev->mdio.dev; 18730b04680fSAndrew Lunn const char *devname = dev_name(dev); 18740b04680fSAndrew Lunn size_t len = strlen(devname); 18750b04680fSAndrew Lunn int i, j; 18760b04680fSAndrew Lunn 18770b04680fSAndrew Lunn priv->hwmon_name = devm_kzalloc(dev, len, GFP_KERNEL); 18780b04680fSAndrew Lunn if (!priv->hwmon_name) 18790b04680fSAndrew Lunn return -ENOMEM; 18800b04680fSAndrew Lunn 18810b04680fSAndrew Lunn for (i = j = 0; i < len && devname[i]; i++) { 18820b04680fSAndrew Lunn if (isalnum(devname[i])) 18830b04680fSAndrew Lunn priv->hwmon_name[j++] = devname[i]; 18840b04680fSAndrew Lunn } 18850b04680fSAndrew Lunn 18860b04680fSAndrew Lunn return 0; 18870b04680fSAndrew Lunn } 18880b04680fSAndrew Lunn 18890b04680fSAndrew Lunn static int marvell_hwmon_probe(struct phy_device *phydev, 18900b04680fSAndrew Lunn const struct hwmon_chip_info *chip) 18910b04680fSAndrew Lunn { 18920b04680fSAndrew Lunn struct marvell_priv *priv = phydev->priv; 18930b04680fSAndrew Lunn struct device *dev = &phydev->mdio.dev; 18940b04680fSAndrew Lunn int err; 18950b04680fSAndrew Lunn 18960b04680fSAndrew Lunn err = marvell_hwmon_name(phydev); 18970b04680fSAndrew Lunn if (err) 18980b04680fSAndrew Lunn return err; 18990b04680fSAndrew Lunn 19000b04680fSAndrew Lunn priv->hwmon_dev = devm_hwmon_device_register_with_info( 19010b04680fSAndrew Lunn dev, priv->hwmon_name, phydev, chip, NULL); 19020b04680fSAndrew Lunn 19030b04680fSAndrew Lunn return PTR_ERR_OR_ZERO(priv->hwmon_dev); 19040b04680fSAndrew Lunn } 19050b04680fSAndrew Lunn 19060b04680fSAndrew Lunn static int m88e1121_hwmon_probe(struct phy_device *phydev) 19070b04680fSAndrew Lunn { 19080b04680fSAndrew Lunn return marvell_hwmon_probe(phydev, &m88e1121_hwmon_chip_info); 19090b04680fSAndrew Lunn } 19100b04680fSAndrew Lunn 19110b04680fSAndrew Lunn static int m88e1510_hwmon_probe(struct phy_device *phydev) 19120b04680fSAndrew Lunn { 19130b04680fSAndrew Lunn return marvell_hwmon_probe(phydev, &m88e1510_hwmon_chip_info); 19140b04680fSAndrew Lunn } 1915fee2d546SAndrew Lunn 1916fee2d546SAndrew Lunn static int m88e6390_hwmon_probe(struct phy_device *phydev) 1917fee2d546SAndrew Lunn { 1918fee2d546SAndrew Lunn return marvell_hwmon_probe(phydev, &m88e6390_hwmon_chip_info); 1919fee2d546SAndrew Lunn } 19200b04680fSAndrew Lunn #else 19210b04680fSAndrew Lunn static int m88e1121_hwmon_probe(struct phy_device *phydev) 19220b04680fSAndrew Lunn { 19230b04680fSAndrew Lunn return 0; 19240b04680fSAndrew Lunn } 19250b04680fSAndrew Lunn 19260b04680fSAndrew Lunn static int m88e1510_hwmon_probe(struct phy_device *phydev) 19270b04680fSAndrew Lunn { 19280b04680fSAndrew Lunn return 0; 19290b04680fSAndrew Lunn } 1930fee2d546SAndrew Lunn 1931fee2d546SAndrew Lunn static int m88e6390_hwmon_probe(struct phy_device *phydev) 1932fee2d546SAndrew Lunn { 1933fee2d546SAndrew Lunn return 0; 1934fee2d546SAndrew Lunn } 19350b04680fSAndrew Lunn #endif 19360b04680fSAndrew Lunn 1937d2fa47d9SAndrew Lunn static int marvell_probe(struct phy_device *phydev) 1938d2fa47d9SAndrew Lunn { 1939d2fa47d9SAndrew Lunn struct marvell_priv *priv; 1940d2fa47d9SAndrew Lunn 1941e5a03bfdSAndrew Lunn priv = devm_kzalloc(&phydev->mdio.dev, sizeof(*priv), GFP_KERNEL); 1942d2fa47d9SAndrew Lunn if (!priv) 1943d2fa47d9SAndrew Lunn return -ENOMEM; 1944d2fa47d9SAndrew Lunn 1945d2fa47d9SAndrew Lunn phydev->priv = priv; 1946d2fa47d9SAndrew Lunn 1947d2fa47d9SAndrew Lunn return 0; 1948d2fa47d9SAndrew Lunn } 1949d2fa47d9SAndrew Lunn 19500b04680fSAndrew Lunn static int m88e1121_probe(struct phy_device *phydev) 19510b04680fSAndrew Lunn { 19520b04680fSAndrew Lunn int err; 19530b04680fSAndrew Lunn 19540b04680fSAndrew Lunn err = marvell_probe(phydev); 19550b04680fSAndrew Lunn if (err) 19560b04680fSAndrew Lunn return err; 19570b04680fSAndrew Lunn 19580b04680fSAndrew Lunn return m88e1121_hwmon_probe(phydev); 19590b04680fSAndrew Lunn } 19600b04680fSAndrew Lunn 19610b04680fSAndrew Lunn static int m88e1510_probe(struct phy_device *phydev) 19620b04680fSAndrew Lunn { 19630b04680fSAndrew Lunn int err; 19640b04680fSAndrew Lunn 19650b04680fSAndrew Lunn err = marvell_probe(phydev); 19660b04680fSAndrew Lunn if (err) 19670b04680fSAndrew Lunn return err; 19680b04680fSAndrew Lunn 19690b04680fSAndrew Lunn return m88e1510_hwmon_probe(phydev); 19700b04680fSAndrew Lunn } 19710b04680fSAndrew Lunn 1972fee2d546SAndrew Lunn static int m88e6390_probe(struct phy_device *phydev) 1973fee2d546SAndrew Lunn { 1974fee2d546SAndrew Lunn int err; 1975fee2d546SAndrew Lunn 1976fee2d546SAndrew Lunn err = marvell_probe(phydev); 1977fee2d546SAndrew Lunn if (err) 1978fee2d546SAndrew Lunn return err; 1979fee2d546SAndrew Lunn 1980fee2d546SAndrew Lunn return m88e6390_hwmon_probe(phydev); 1981fee2d546SAndrew Lunn } 1982fee2d546SAndrew Lunn 1983e5479239SOlof Johansson static struct phy_driver marvell_drivers[] = { 1984e5479239SOlof Johansson { 19852f495c39SBenjamin Herrenschmidt .phy_id = MARVELL_PHY_ID_88E1101, 19862f495c39SBenjamin Herrenschmidt .phy_id_mask = MARVELL_PHY_ID_MASK, 198700db8189SAndy Fleming .name = "Marvell 88E1101", 198800db8189SAndy Fleming .features = PHY_GBIT_FEATURES, 198900db8189SAndy Fleming .flags = PHY_HAS_INTERRUPT, 199018702414SArnd Bergmann .probe = marvell_probe, 199179be1a1cSClemens Gruber .config_init = &marvell_config_init, 1992f2899788SAndrew Lunn .config_aneg = &m88e1101_config_aneg, 199300db8189SAndy Fleming .ack_interrupt = &marvell_ack_interrupt, 199400db8189SAndy Fleming .config_intr = &marvell_config_intr, 19950898b448SSebastian Hesselbarth .resume = &genphy_resume, 19960898b448SSebastian Hesselbarth .suspend = &genphy_suspend, 1997424ca4c5SRussell King .read_page = marvell_read_page, 1998424ca4c5SRussell King .write_page = marvell_write_page, 1999d2fa47d9SAndrew Lunn .get_sset_count = marvell_get_sset_count, 2000d2fa47d9SAndrew Lunn .get_strings = marvell_get_strings, 2001d2fa47d9SAndrew Lunn .get_stats = marvell_get_stats, 2002e5479239SOlof Johansson }, 2003e5479239SOlof Johansson { 20042f495c39SBenjamin Herrenschmidt .phy_id = MARVELL_PHY_ID_88E1112, 20052f495c39SBenjamin Herrenschmidt .phy_id_mask = MARVELL_PHY_ID_MASK, 200685cfb534SOlof Johansson .name = "Marvell 88E1112", 200785cfb534SOlof Johansson .features = PHY_GBIT_FEATURES, 200885cfb534SOlof Johansson .flags = PHY_HAS_INTERRUPT, 2009d2fa47d9SAndrew Lunn .probe = marvell_probe, 201085cfb534SOlof Johansson .config_init = &m88e1111_config_init, 201185cfb534SOlof Johansson .config_aneg = &marvell_config_aneg, 201285cfb534SOlof Johansson .ack_interrupt = &marvell_ack_interrupt, 201385cfb534SOlof Johansson .config_intr = &marvell_config_intr, 20140898b448SSebastian Hesselbarth .resume = &genphy_resume, 20150898b448SSebastian Hesselbarth .suspend = &genphy_suspend, 2016424ca4c5SRussell King .read_page = marvell_read_page, 2017424ca4c5SRussell King .write_page = marvell_write_page, 2018d2fa47d9SAndrew Lunn .get_sset_count = marvell_get_sset_count, 2019d2fa47d9SAndrew Lunn .get_strings = marvell_get_strings, 2020d2fa47d9SAndrew Lunn .get_stats = marvell_get_stats, 202185cfb534SOlof Johansson }, 202285cfb534SOlof Johansson { 20232f495c39SBenjamin Herrenschmidt .phy_id = MARVELL_PHY_ID_88E1111, 20242f495c39SBenjamin Herrenschmidt .phy_id_mask = MARVELL_PHY_ID_MASK, 202576884679SAndy Fleming .name = "Marvell 88E1111", 202676884679SAndy Fleming .features = PHY_GBIT_FEATURES, 202776884679SAndy Fleming .flags = PHY_HAS_INTERRUPT, 2028d2fa47d9SAndrew Lunn .probe = marvell_probe, 2029e5479239SOlof Johansson .config_init = &m88e1111_config_init, 20303ec0a0f1SHarini Katakam .config_aneg = &m88e1111_config_aneg, 2031be937f1fSAlexandr Smirnov .read_status = &marvell_read_status, 203276884679SAndy Fleming .ack_interrupt = &marvell_ack_interrupt, 203376884679SAndy Fleming .config_intr = &marvell_config_intr, 20340898b448SSebastian Hesselbarth .resume = &genphy_resume, 20350898b448SSebastian Hesselbarth .suspend = &genphy_suspend, 2036424ca4c5SRussell King .read_page = marvell_read_page, 2037424ca4c5SRussell King .write_page = marvell_write_page, 2038d2fa47d9SAndrew Lunn .get_sset_count = marvell_get_sset_count, 2039d2fa47d9SAndrew Lunn .get_strings = marvell_get_strings, 2040d2fa47d9SAndrew Lunn .get_stats = marvell_get_stats, 2041e5479239SOlof Johansson }, 2042e5479239SOlof Johansson { 20432f495c39SBenjamin Herrenschmidt .phy_id = MARVELL_PHY_ID_88E1118, 20442f495c39SBenjamin Herrenschmidt .phy_id_mask = MARVELL_PHY_ID_MASK, 2045605f196eSRon Madrid .name = "Marvell 88E1118", 2046605f196eSRon Madrid .features = PHY_GBIT_FEATURES, 2047605f196eSRon Madrid .flags = PHY_HAS_INTERRUPT, 2048d2fa47d9SAndrew Lunn .probe = marvell_probe, 2049605f196eSRon Madrid .config_init = &m88e1118_config_init, 2050605f196eSRon Madrid .config_aneg = &m88e1118_config_aneg, 2051605f196eSRon Madrid .ack_interrupt = &marvell_ack_interrupt, 2052605f196eSRon Madrid .config_intr = &marvell_config_intr, 20530898b448SSebastian Hesselbarth .resume = &genphy_resume, 20540898b448SSebastian Hesselbarth .suspend = &genphy_suspend, 2055424ca4c5SRussell King .read_page = marvell_read_page, 2056424ca4c5SRussell King .write_page = marvell_write_page, 2057d2fa47d9SAndrew Lunn .get_sset_count = marvell_get_sset_count, 2058d2fa47d9SAndrew Lunn .get_strings = marvell_get_strings, 2059d2fa47d9SAndrew Lunn .get_stats = marvell_get_stats, 2060605f196eSRon Madrid }, 2061605f196eSRon Madrid { 20622f495c39SBenjamin Herrenschmidt .phy_id = MARVELL_PHY_ID_88E1121R, 20632f495c39SBenjamin Herrenschmidt .phy_id_mask = MARVELL_PHY_ID_MASK, 2064140bc929SSergei Poselenov .name = "Marvell 88E1121R", 2065140bc929SSergei Poselenov .features = PHY_GBIT_FEATURES, 2066140bc929SSergei Poselenov .flags = PHY_HAS_INTERRUPT, 206718702414SArnd Bergmann .probe = &m88e1121_probe, 2068fdecf36fSClemens Gruber .config_init = &m88e1121_config_init, 2069140bc929SSergei Poselenov .config_aneg = &m88e1121_config_aneg, 2070140bc929SSergei Poselenov .read_status = &marvell_read_status, 2071140bc929SSergei Poselenov .ack_interrupt = &marvell_ack_interrupt, 2072140bc929SSergei Poselenov .config_intr = &marvell_config_intr, 2073dcd07be3SAnatolij Gustschin .did_interrupt = &m88e1121_did_interrupt, 20740898b448SSebastian Hesselbarth .resume = &genphy_resume, 20750898b448SSebastian Hesselbarth .suspend = &genphy_suspend, 2076424ca4c5SRussell King .read_page = marvell_read_page, 2077424ca4c5SRussell King .write_page = marvell_write_page, 2078d2fa47d9SAndrew Lunn .get_sset_count = marvell_get_sset_count, 2079d2fa47d9SAndrew Lunn .get_strings = marvell_get_strings, 2080d2fa47d9SAndrew Lunn .get_stats = marvell_get_stats, 2081140bc929SSergei Poselenov }, 2082140bc929SSergei Poselenov { 2083337ac9d5SCyril Chemparathy .phy_id = MARVELL_PHY_ID_88E1318S, 20846ba74014SLinus Torvalds .phy_id_mask = MARVELL_PHY_ID_MASK, 2085337ac9d5SCyril Chemparathy .name = "Marvell 88E1318S", 20863ff1c259SCyril Chemparathy .features = PHY_GBIT_FEATURES, 20873ff1c259SCyril Chemparathy .flags = PHY_HAS_INTERRUPT, 2088d2fa47d9SAndrew Lunn .probe = marvell_probe, 2089fdecf36fSClemens Gruber .config_init = &m88e1121_config_init, 2090337ac9d5SCyril Chemparathy .config_aneg = &m88e1318_config_aneg, 20913ff1c259SCyril Chemparathy .read_status = &marvell_read_status, 20923ff1c259SCyril Chemparathy .ack_interrupt = &marvell_ack_interrupt, 20933ff1c259SCyril Chemparathy .config_intr = &marvell_config_intr, 20943ff1c259SCyril Chemparathy .did_interrupt = &m88e1121_did_interrupt, 20953871c387SMichael Stapelberg .get_wol = &m88e1318_get_wol, 20963871c387SMichael Stapelberg .set_wol = &m88e1318_set_wol, 20970898b448SSebastian Hesselbarth .resume = &genphy_resume, 20980898b448SSebastian Hesselbarth .suspend = &genphy_suspend, 2099424ca4c5SRussell King .read_page = marvell_read_page, 2100424ca4c5SRussell King .write_page = marvell_write_page, 2101d2fa47d9SAndrew Lunn .get_sset_count = marvell_get_sset_count, 2102d2fa47d9SAndrew Lunn .get_strings = marvell_get_strings, 2103d2fa47d9SAndrew Lunn .get_stats = marvell_get_stats, 21043ff1c259SCyril Chemparathy }, 21053ff1c259SCyril Chemparathy { 21062f495c39SBenjamin Herrenschmidt .phy_id = MARVELL_PHY_ID_88E1145, 21072f495c39SBenjamin Herrenschmidt .phy_id_mask = MARVELL_PHY_ID_MASK, 210876884679SAndy Fleming .name = "Marvell 88E1145", 210976884679SAndy Fleming .features = PHY_GBIT_FEATURES, 211076884679SAndy Fleming .flags = PHY_HAS_INTERRUPT, 2111d2fa47d9SAndrew Lunn .probe = marvell_probe, 211276884679SAndy Fleming .config_init = &m88e1145_config_init, 2113c505873eSZhao Qiang .config_aneg = &m88e1101_config_aneg, 211476884679SAndy Fleming .read_status = &genphy_read_status, 211576884679SAndy Fleming .ack_interrupt = &marvell_ack_interrupt, 211676884679SAndy Fleming .config_intr = &marvell_config_intr, 21170898b448SSebastian Hesselbarth .resume = &genphy_resume, 21180898b448SSebastian Hesselbarth .suspend = &genphy_suspend, 2119424ca4c5SRussell King .read_page = marvell_read_page, 2120424ca4c5SRussell King .write_page = marvell_write_page, 2121d2fa47d9SAndrew Lunn .get_sset_count = marvell_get_sset_count, 2122d2fa47d9SAndrew Lunn .get_strings = marvell_get_strings, 2123d2fa47d9SAndrew Lunn .get_stats = marvell_get_stats, 2124ac8c635aSOlof Johansson }, 2125ac8c635aSOlof Johansson { 212690600732SDavid Daney .phy_id = MARVELL_PHY_ID_88E1149R, 212790600732SDavid Daney .phy_id_mask = MARVELL_PHY_ID_MASK, 212890600732SDavid Daney .name = "Marvell 88E1149R", 212990600732SDavid Daney .features = PHY_GBIT_FEATURES, 213090600732SDavid Daney .flags = PHY_HAS_INTERRUPT, 2131d2fa47d9SAndrew Lunn .probe = marvell_probe, 213290600732SDavid Daney .config_init = &m88e1149_config_init, 213390600732SDavid Daney .config_aneg = &m88e1118_config_aneg, 213490600732SDavid Daney .ack_interrupt = &marvell_ack_interrupt, 213590600732SDavid Daney .config_intr = &marvell_config_intr, 21360898b448SSebastian Hesselbarth .resume = &genphy_resume, 21370898b448SSebastian Hesselbarth .suspend = &genphy_suspend, 2138424ca4c5SRussell King .read_page = marvell_read_page, 2139424ca4c5SRussell King .write_page = marvell_write_page, 2140d2fa47d9SAndrew Lunn .get_sset_count = marvell_get_sset_count, 2141d2fa47d9SAndrew Lunn .get_strings = marvell_get_strings, 2142d2fa47d9SAndrew Lunn .get_stats = marvell_get_stats, 214390600732SDavid Daney }, 214490600732SDavid Daney { 21452f495c39SBenjamin Herrenschmidt .phy_id = MARVELL_PHY_ID_88E1240, 21462f495c39SBenjamin Herrenschmidt .phy_id_mask = MARVELL_PHY_ID_MASK, 2147ac8c635aSOlof Johansson .name = "Marvell 88E1240", 2148ac8c635aSOlof Johansson .features = PHY_GBIT_FEATURES, 2149ac8c635aSOlof Johansson .flags = PHY_HAS_INTERRUPT, 2150d2fa47d9SAndrew Lunn .probe = marvell_probe, 2151ac8c635aSOlof Johansson .config_init = &m88e1111_config_init, 2152ac8c635aSOlof Johansson .config_aneg = &marvell_config_aneg, 2153ac8c635aSOlof Johansson .ack_interrupt = &marvell_ack_interrupt, 2154ac8c635aSOlof Johansson .config_intr = &marvell_config_intr, 21550898b448SSebastian Hesselbarth .resume = &genphy_resume, 21560898b448SSebastian Hesselbarth .suspend = &genphy_suspend, 2157424ca4c5SRussell King .read_page = marvell_read_page, 2158424ca4c5SRussell King .write_page = marvell_write_page, 2159d2fa47d9SAndrew Lunn .get_sset_count = marvell_get_sset_count, 2160d2fa47d9SAndrew Lunn .get_strings = marvell_get_strings, 2161d2fa47d9SAndrew Lunn .get_stats = marvell_get_stats, 2162ac8c635aSOlof Johansson }, 21633da09a51SMichal Simek { 21643da09a51SMichal Simek .phy_id = MARVELL_PHY_ID_88E1116R, 21653da09a51SMichal Simek .phy_id_mask = MARVELL_PHY_ID_MASK, 21663da09a51SMichal Simek .name = "Marvell 88E1116R", 21673da09a51SMichal Simek .features = PHY_GBIT_FEATURES, 21683da09a51SMichal Simek .flags = PHY_HAS_INTERRUPT, 2169d2fa47d9SAndrew Lunn .probe = marvell_probe, 21703da09a51SMichal Simek .config_init = &m88e1116r_config_init, 21713da09a51SMichal Simek .ack_interrupt = &marvell_ack_interrupt, 21723da09a51SMichal Simek .config_intr = &marvell_config_intr, 21730898b448SSebastian Hesselbarth .resume = &genphy_resume, 21740898b448SSebastian Hesselbarth .suspend = &genphy_suspend, 2175424ca4c5SRussell King .read_page = marvell_read_page, 2176424ca4c5SRussell King .write_page = marvell_write_page, 2177d2fa47d9SAndrew Lunn .get_sset_count = marvell_get_sset_count, 2178d2fa47d9SAndrew Lunn .get_strings = marvell_get_strings, 2179d2fa47d9SAndrew Lunn .get_stats = marvell_get_stats, 21803da09a51SMichal Simek }, 218110e24caaSMichal Simek { 218210e24caaSMichal Simek .phy_id = MARVELL_PHY_ID_88E1510, 218310e24caaSMichal Simek .phy_id_mask = MARVELL_PHY_ID_MASK, 218410e24caaSMichal Simek .name = "Marvell 88E1510", 21856cfb3bccSCharles-Antoine Couret .features = PHY_GBIT_FEATURES | SUPPORTED_FIBRE, 218618702414SArnd Bergmann .flags = PHY_HAS_INTERRUPT, 21870b04680fSAndrew Lunn .probe = &m88e1510_probe, 2188930b37eeSStefan Roese .config_init = &m88e1510_config_init, 218910e24caaSMichal Simek .config_aneg = &m88e1510_config_aneg, 219010e24caaSMichal Simek .read_status = &marvell_read_status, 219110e24caaSMichal Simek .ack_interrupt = &marvell_ack_interrupt, 219210e24caaSMichal Simek .config_intr = &marvell_config_intr, 219310e24caaSMichal Simek .did_interrupt = &m88e1121_did_interrupt, 2194f39aac7eSJingju Hou .get_wol = &m88e1318_get_wol, 2195f39aac7eSJingju Hou .set_wol = &m88e1318_set_wol, 21963758be3dSCharles-Antoine Couret .resume = &marvell_resume, 21973758be3dSCharles-Antoine Couret .suspend = &marvell_suspend, 2198424ca4c5SRussell King .read_page = marvell_read_page, 2199424ca4c5SRussell King .write_page = marvell_write_page, 2200d2fa47d9SAndrew Lunn .get_sset_count = marvell_get_sset_count, 2201d2fa47d9SAndrew Lunn .get_strings = marvell_get_strings, 2202d2fa47d9SAndrew Lunn .get_stats = marvell_get_stats, 2203f0f9b4edSLin Yun Sheng .set_loopback = genphy_loopback, 220410e24caaSMichal Simek }, 22056b358aedSSebastian Hesselbarth { 2206819ec8e1SAndrew Lunn .phy_id = MARVELL_PHY_ID_88E1540, 2207819ec8e1SAndrew Lunn .phy_id_mask = MARVELL_PHY_ID_MASK, 2208819ec8e1SAndrew Lunn .name = "Marvell 88E1540", 2209819ec8e1SAndrew Lunn .features = PHY_GBIT_FEATURES, 2210819ec8e1SAndrew Lunn .flags = PHY_HAS_INTERRUPT, 221118702414SArnd Bergmann .probe = m88e1510_probe, 221279be1a1cSClemens Gruber .config_init = &marvell_config_init, 2213819ec8e1SAndrew Lunn .config_aneg = &m88e1510_config_aneg, 2214819ec8e1SAndrew Lunn .read_status = &marvell_read_status, 2215819ec8e1SAndrew Lunn .ack_interrupt = &marvell_ack_interrupt, 2216819ec8e1SAndrew Lunn .config_intr = &marvell_config_intr, 2217819ec8e1SAndrew Lunn .did_interrupt = &m88e1121_did_interrupt, 2218819ec8e1SAndrew Lunn .resume = &genphy_resume, 2219819ec8e1SAndrew Lunn .suspend = &genphy_suspend, 2220424ca4c5SRussell King .read_page = marvell_read_page, 2221424ca4c5SRussell King .write_page = marvell_write_page, 2222d2fa47d9SAndrew Lunn .get_sset_count = marvell_get_sset_count, 2223d2fa47d9SAndrew Lunn .get_strings = marvell_get_strings, 2224d2fa47d9SAndrew Lunn .get_stats = marvell_get_stats, 2225819ec8e1SAndrew Lunn }, 2226819ec8e1SAndrew Lunn { 222760f06fdeSAndrew Lunn .phy_id = MARVELL_PHY_ID_88E1545, 222860f06fdeSAndrew Lunn .phy_id_mask = MARVELL_PHY_ID_MASK, 222960f06fdeSAndrew Lunn .name = "Marvell 88E1545", 223060f06fdeSAndrew Lunn .probe = m88e1510_probe, 223160f06fdeSAndrew Lunn .features = PHY_GBIT_FEATURES, 223260f06fdeSAndrew Lunn .flags = PHY_HAS_INTERRUPT, 223360f06fdeSAndrew Lunn .config_init = &marvell_config_init, 223460f06fdeSAndrew Lunn .config_aneg = &m88e1510_config_aneg, 223560f06fdeSAndrew Lunn .read_status = &marvell_read_status, 223660f06fdeSAndrew Lunn .ack_interrupt = &marvell_ack_interrupt, 223760f06fdeSAndrew Lunn .config_intr = &marvell_config_intr, 223860f06fdeSAndrew Lunn .did_interrupt = &m88e1121_did_interrupt, 223960f06fdeSAndrew Lunn .resume = &genphy_resume, 224060f06fdeSAndrew Lunn .suspend = &genphy_suspend, 2241424ca4c5SRussell King .read_page = marvell_read_page, 2242424ca4c5SRussell King .write_page = marvell_write_page, 224360f06fdeSAndrew Lunn .get_sset_count = marvell_get_sset_count, 224460f06fdeSAndrew Lunn .get_strings = marvell_get_strings, 224560f06fdeSAndrew Lunn .get_stats = marvell_get_stats, 224660f06fdeSAndrew Lunn }, 224760f06fdeSAndrew Lunn { 22486b358aedSSebastian Hesselbarth .phy_id = MARVELL_PHY_ID_88E3016, 22496b358aedSSebastian Hesselbarth .phy_id_mask = MARVELL_PHY_ID_MASK, 22506b358aedSSebastian Hesselbarth .name = "Marvell 88E3016", 22516b358aedSSebastian Hesselbarth .features = PHY_BASIC_FEATURES, 22526b358aedSSebastian Hesselbarth .flags = PHY_HAS_INTERRUPT, 2253d2fa47d9SAndrew Lunn .probe = marvell_probe, 22546b358aedSSebastian Hesselbarth .config_init = &m88e3016_config_init, 22556b358aedSSebastian Hesselbarth .aneg_done = &marvell_aneg_done, 22566b358aedSSebastian Hesselbarth .read_status = &marvell_read_status, 22576b358aedSSebastian Hesselbarth .ack_interrupt = &marvell_ack_interrupt, 22586b358aedSSebastian Hesselbarth .config_intr = &marvell_config_intr, 22596b358aedSSebastian Hesselbarth .did_interrupt = &m88e1121_did_interrupt, 22606b358aedSSebastian Hesselbarth .resume = &genphy_resume, 22616b358aedSSebastian Hesselbarth .suspend = &genphy_suspend, 2262424ca4c5SRussell King .read_page = marvell_read_page, 2263424ca4c5SRussell King .write_page = marvell_write_page, 2264d2fa47d9SAndrew Lunn .get_sset_count = marvell_get_sset_count, 2265d2fa47d9SAndrew Lunn .get_strings = marvell_get_strings, 2266d2fa47d9SAndrew Lunn .get_stats = marvell_get_stats, 22676b358aedSSebastian Hesselbarth }, 2268e4cf8a38SAndrew Lunn { 2269e4cf8a38SAndrew Lunn .phy_id = MARVELL_PHY_ID_88E6390, 2270e4cf8a38SAndrew Lunn .phy_id_mask = MARVELL_PHY_ID_MASK, 2271e4cf8a38SAndrew Lunn .name = "Marvell 88E6390", 2272e4cf8a38SAndrew Lunn .features = PHY_GBIT_FEATURES, 2273e4cf8a38SAndrew Lunn .flags = PHY_HAS_INTERRUPT, 2274fee2d546SAndrew Lunn .probe = m88e6390_probe, 2275e4cf8a38SAndrew Lunn .config_init = &marvell_config_init, 2276e4cf8a38SAndrew Lunn .config_aneg = &m88e1510_config_aneg, 2277e4cf8a38SAndrew Lunn .read_status = &marvell_read_status, 2278e4cf8a38SAndrew Lunn .ack_interrupt = &marvell_ack_interrupt, 2279e4cf8a38SAndrew Lunn .config_intr = &marvell_config_intr, 2280e4cf8a38SAndrew Lunn .did_interrupt = &m88e1121_did_interrupt, 2281e4cf8a38SAndrew Lunn .resume = &genphy_resume, 2282e4cf8a38SAndrew Lunn .suspend = &genphy_suspend, 2283424ca4c5SRussell King .read_page = marvell_read_page, 2284424ca4c5SRussell King .write_page = marvell_write_page, 2285e4cf8a38SAndrew Lunn .get_sset_count = marvell_get_sset_count, 2286e4cf8a38SAndrew Lunn .get_strings = marvell_get_strings, 2287e4cf8a38SAndrew Lunn .get_stats = marvell_get_stats, 2288e4cf8a38SAndrew Lunn }, 228976884679SAndy Fleming }; 229076884679SAndy Fleming 229150fd7150SJohan Hovold module_phy_driver(marvell_drivers); 22924e4f10f6SDavid Woodhouse 2293cf93c945SUwe Kleine-König static struct mdio_device_id __maybe_unused marvell_tbl[] = { 2294f5e1cabfSMichal Simek { MARVELL_PHY_ID_88E1101, MARVELL_PHY_ID_MASK }, 2295f5e1cabfSMichal Simek { MARVELL_PHY_ID_88E1112, MARVELL_PHY_ID_MASK }, 2296f5e1cabfSMichal Simek { MARVELL_PHY_ID_88E1111, MARVELL_PHY_ID_MASK }, 2297f5e1cabfSMichal Simek { MARVELL_PHY_ID_88E1118, MARVELL_PHY_ID_MASK }, 2298f5e1cabfSMichal Simek { MARVELL_PHY_ID_88E1121R, MARVELL_PHY_ID_MASK }, 2299f5e1cabfSMichal Simek { MARVELL_PHY_ID_88E1145, MARVELL_PHY_ID_MASK }, 2300f5e1cabfSMichal Simek { MARVELL_PHY_ID_88E1149R, MARVELL_PHY_ID_MASK }, 2301f5e1cabfSMichal Simek { MARVELL_PHY_ID_88E1240, MARVELL_PHY_ID_MASK }, 2302f5e1cabfSMichal Simek { MARVELL_PHY_ID_88E1318S, MARVELL_PHY_ID_MASK }, 23033da09a51SMichal Simek { MARVELL_PHY_ID_88E1116R, MARVELL_PHY_ID_MASK }, 230410e24caaSMichal Simek { MARVELL_PHY_ID_88E1510, MARVELL_PHY_ID_MASK }, 2305819ec8e1SAndrew Lunn { MARVELL_PHY_ID_88E1540, MARVELL_PHY_ID_MASK }, 230660f06fdeSAndrew Lunn { MARVELL_PHY_ID_88E1545, MARVELL_PHY_ID_MASK }, 23076b358aedSSebastian Hesselbarth { MARVELL_PHY_ID_88E3016, MARVELL_PHY_ID_MASK }, 2308e4cf8a38SAndrew Lunn { MARVELL_PHY_ID_88E6390, MARVELL_PHY_ID_MASK }, 23094e4f10f6SDavid Woodhouse { } 23104e4f10f6SDavid Woodhouse }; 23114e4f10f6SDavid Woodhouse 23124e4f10f6SDavid Woodhouse MODULE_DEVICE_TABLE(mdio, marvell_tbl); 2313