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 59239aa55bSDavid Thomson #define MII_M1011_PHY_SCR_MDI 0x0000 60239aa55bSDavid Thomson #define MII_M1011_PHY_SCR_MDI_X 0x0020 6176884679SAndy Fleming #define MII_M1011_PHY_SCR_AUTO_CROSS 0x0060 6276884679SAndy Fleming 63b0224175SViet Nga Dao #define MII_M1145_PHY_EXT_SR 0x1b 6476884679SAndy Fleming #define MII_M1145_PHY_EXT_CR 0x14 6576884679SAndy Fleming #define MII_M1145_RGMII_RX_DELAY 0x0080 6676884679SAndy Fleming #define MII_M1145_RGMII_TX_DELAY 0x0002 67b0224175SViet Nga Dao #define MII_M1145_HWCFG_MODE_SGMII_NO_CLK 0x4 68b0224175SViet Nga Dao #define MII_M1145_HWCFG_MODE_MASK 0xf 69b0224175SViet Nga Dao #define MII_M1145_HWCFG_FIBER_COPPER_AUTO 0x8000 7076884679SAndy Fleming 7199d881f9SVince Bridgers #define MII_M1145_HWCFG_MODE_SGMII_NO_CLK 0x4 7299d881f9SVince Bridgers #define MII_M1145_HWCFG_MODE_MASK 0xf 7399d881f9SVince Bridgers #define MII_M1145_HWCFG_FIBER_COPPER_AUTO 0x8000 7499d881f9SVince Bridgers 7576884679SAndy Fleming #define MII_M1111_PHY_LED_CONTROL 0x18 7676884679SAndy Fleming #define MII_M1111_PHY_LED_DIRECT 0x4100 7776884679SAndy Fleming #define MII_M1111_PHY_LED_COMBINE 0x411c 78895ee682SKim Phillips #define MII_M1111_PHY_EXT_CR 0x14 79895ee682SKim Phillips #define MII_M1111_RX_DELAY 0x80 80895ee682SKim Phillips #define MII_M1111_TX_DELAY 0x2 81895ee682SKim Phillips #define MII_M1111_PHY_EXT_SR 0x1b 82be937f1fSAlexandr Smirnov 83895ee682SKim Phillips #define MII_M1111_HWCFG_MODE_MASK 0xf 84be937f1fSAlexandr Smirnov #define MII_M1111_HWCFG_MODE_COPPER_RGMII 0xb 85be937f1fSAlexandr Smirnov #define MII_M1111_HWCFG_MODE_FIBER_RGMII 0x3 864117b5beSKapil Juneja #define MII_M1111_HWCFG_MODE_SGMII_NO_CLK 0x4 875f8cbc13SLiu Yu-B13201 #define MII_M1111_HWCFG_MODE_COPPER_RTBI 0x9 88be937f1fSAlexandr Smirnov #define MII_M1111_HWCFG_FIBER_COPPER_AUTO 0x8000 89be937f1fSAlexandr Smirnov #define MII_M1111_HWCFG_FIBER_COPPER_RES 0x2000 90be937f1fSAlexandr Smirnov 91c477d044SCyril Chemparathy #define MII_88E1121_PHY_MSCR_REG 21 92c477d044SCyril Chemparathy #define MII_88E1121_PHY_MSCR_RX_DELAY BIT(5) 93c477d044SCyril Chemparathy #define MII_88E1121_PHY_MSCR_TX_DELAY BIT(4) 94c477d044SCyril Chemparathy #define MII_88E1121_PHY_MSCR_DELAY_MASK (~(0x3 << 4)) 95c477d044SCyril Chemparathy 960b04680fSAndrew Lunn #define MII_88E1121_MISC_TEST 0x1a 970b04680fSAndrew Lunn #define MII_88E1510_MISC_TEST_TEMP_THRESHOLD_MASK 0x1f00 980b04680fSAndrew Lunn #define MII_88E1510_MISC_TEST_TEMP_THRESHOLD_SHIFT 8 990b04680fSAndrew Lunn #define MII_88E1510_MISC_TEST_TEMP_IRQ_EN BIT(7) 1000b04680fSAndrew Lunn #define MII_88E1510_MISC_TEST_TEMP_IRQ BIT(6) 1010b04680fSAndrew Lunn #define MII_88E1121_MISC_TEST_TEMP_SENSOR_EN BIT(5) 1020b04680fSAndrew Lunn #define MII_88E1121_MISC_TEST_TEMP_MASK 0x1f 1030b04680fSAndrew Lunn 1040b04680fSAndrew Lunn #define MII_88E1510_TEMP_SENSOR 0x1b 1050b04680fSAndrew Lunn #define MII_88E1510_TEMP_SENSOR_MASK 0xff 1060b04680fSAndrew Lunn 107337ac9d5SCyril Chemparathy #define MII_88E1318S_PHY_MSCR1_REG 16 108337ac9d5SCyril Chemparathy #define MII_88E1318S_PHY_MSCR1_PAD_ODD BIT(6) 1093ff1c259SCyril Chemparathy 1103871c387SMichael Stapelberg /* Copper Specific Interrupt Enable Register */ 1113871c387SMichael Stapelberg #define MII_88E1318S_PHY_CSIER 0x12 1123871c387SMichael Stapelberg /* WOL Event Interrupt Enable */ 1133871c387SMichael Stapelberg #define MII_88E1318S_PHY_CSIER_WOL_EIE BIT(7) 1143871c387SMichael Stapelberg 1153871c387SMichael Stapelberg /* LED Timer Control Register */ 1163871c387SMichael Stapelberg #define MII_88E1318S_PHY_LED_TCR 0x12 1173871c387SMichael Stapelberg #define MII_88E1318S_PHY_LED_TCR_FORCE_INT BIT(15) 1183871c387SMichael Stapelberg #define MII_88E1318S_PHY_LED_TCR_INTn_ENABLE BIT(7) 1193871c387SMichael Stapelberg #define MII_88E1318S_PHY_LED_TCR_INT_ACTIVE_LOW BIT(11) 1203871c387SMichael Stapelberg 1213871c387SMichael Stapelberg /* Magic Packet MAC address registers */ 1223871c387SMichael Stapelberg #define MII_88E1318S_PHY_MAGIC_PACKET_WORD2 0x17 1233871c387SMichael Stapelberg #define MII_88E1318S_PHY_MAGIC_PACKET_WORD1 0x18 1243871c387SMichael Stapelberg #define MII_88E1318S_PHY_MAGIC_PACKET_WORD0 0x19 1253871c387SMichael Stapelberg 1263871c387SMichael Stapelberg #define MII_88E1318S_PHY_WOL_CTRL 0x10 1273871c387SMichael Stapelberg #define MII_88E1318S_PHY_WOL_CTRL_CLEAR_WOL_STATUS BIT(12) 1283871c387SMichael Stapelberg #define MII_88E1318S_PHY_WOL_CTRL_MAGIC_PACKET_MATCH_ENABLE BIT(14) 1293871c387SMichael Stapelberg 130140bc929SSergei Poselenov #define MII_88E1121_PHY_LED_CTRL 16 131140bc929SSergei Poselenov #define MII_88E1121_PHY_LED_DEF 0x0030 132140bc929SSergei Poselenov 133be937f1fSAlexandr Smirnov #define MII_M1011_PHY_STATUS 0x11 134be937f1fSAlexandr Smirnov #define MII_M1011_PHY_STATUS_1000 0x8000 135be937f1fSAlexandr Smirnov #define MII_M1011_PHY_STATUS_100 0x4000 136be937f1fSAlexandr Smirnov #define MII_M1011_PHY_STATUS_SPD_MASK 0xc000 137be937f1fSAlexandr Smirnov #define MII_M1011_PHY_STATUS_FULLDUPLEX 0x2000 138be937f1fSAlexandr Smirnov #define MII_M1011_PHY_STATUS_RESOLVED 0x0800 139be937f1fSAlexandr Smirnov #define MII_M1011_PHY_STATUS_LINK 0x0400 140be937f1fSAlexandr Smirnov 1413da09a51SMichal Simek #define MII_M1116R_CONTROL_REG_MAC 21 1423da09a51SMichal Simek 1436b358aedSSebastian Hesselbarth #define MII_88E3016_PHY_SPEC_CTRL 0x10 1446b358aedSSebastian Hesselbarth #define MII_88E3016_DISABLE_SCRAMBLER 0x0200 1456b358aedSSebastian Hesselbarth #define MII_88E3016_AUTO_MDIX_CROSSOVER 0x0030 14676884679SAndy Fleming 147930b37eeSStefan Roese #define MII_88E1510_GEN_CTRL_REG_1 0x14 148930b37eeSStefan Roese #define MII_88E1510_GEN_CTRL_REG_1_MODE_MASK 0x7 149930b37eeSStefan Roese #define MII_88E1510_GEN_CTRL_REG_1_MODE_SGMII 0x1 /* SGMII to copper */ 150930b37eeSStefan Roese #define MII_88E1510_GEN_CTRL_REG_1_RESET 0x8000 /* Soft reset */ 151930b37eeSStefan Roese 1526cfb3bccSCharles-Antoine Couret #define LPA_FIBER_1000HALF 0x40 1536cfb3bccSCharles-Antoine Couret #define LPA_FIBER_1000FULL 0x20 1546cfb3bccSCharles-Antoine Couret 1556cfb3bccSCharles-Antoine Couret #define LPA_PAUSE_FIBER 0x180 1566cfb3bccSCharles-Antoine Couret #define LPA_PAUSE_ASYM_FIBER 0x100 1576cfb3bccSCharles-Antoine Couret 1586cfb3bccSCharles-Antoine Couret #define ADVERTISE_FIBER_1000HALF 0x40 1596cfb3bccSCharles-Antoine Couret #define ADVERTISE_FIBER_1000FULL 0x20 1606cfb3bccSCharles-Antoine Couret 1616cfb3bccSCharles-Antoine Couret #define ADVERTISE_PAUSE_FIBER 0x180 1626cfb3bccSCharles-Antoine Couret #define ADVERTISE_PAUSE_ASYM_FIBER 0x100 1636cfb3bccSCharles-Antoine Couret 1646cfb3bccSCharles-Antoine Couret #define REGISTER_LINK_STATUS 0x400 1652170fef7SCharles-Antoine Couret #define NB_FIBER_STATS 1 1666cfb3bccSCharles-Antoine Couret 16700db8189SAndy Fleming MODULE_DESCRIPTION("Marvell PHY driver"); 16800db8189SAndy Fleming MODULE_AUTHOR("Andy Fleming"); 16900db8189SAndy Fleming MODULE_LICENSE("GPL"); 17000db8189SAndy Fleming 171d2fa47d9SAndrew Lunn struct marvell_hw_stat { 172d2fa47d9SAndrew Lunn const char *string; 173d2fa47d9SAndrew Lunn u8 page; 174d2fa47d9SAndrew Lunn u8 reg; 175d2fa47d9SAndrew Lunn u8 bits; 176d2fa47d9SAndrew Lunn }; 177d2fa47d9SAndrew Lunn 178d2fa47d9SAndrew Lunn static struct marvell_hw_stat marvell_hw_stats[] = { 1792170fef7SCharles-Antoine Couret { "phy_receive_errors_copper", 0, 21, 16}, 180d2fa47d9SAndrew Lunn { "phy_idle_errors", 0, 10, 8 }, 1812170fef7SCharles-Antoine Couret { "phy_receive_errors_fiber", 1, 21, 16}, 182d2fa47d9SAndrew Lunn }; 183d2fa47d9SAndrew Lunn 184d2fa47d9SAndrew Lunn struct marvell_priv { 185d2fa47d9SAndrew Lunn u64 stats[ARRAY_SIZE(marvell_hw_stats)]; 1860b04680fSAndrew Lunn char *hwmon_name; 1870b04680fSAndrew Lunn struct device *hwmon_dev; 188d2fa47d9SAndrew Lunn }; 189d2fa47d9SAndrew Lunn 1906427bb2dSAndrew Lunn static int marvell_get_page(struct phy_device *phydev) 1916427bb2dSAndrew Lunn { 1926427bb2dSAndrew Lunn return phy_read(phydev, MII_MARVELL_PHY_PAGE); 1936427bb2dSAndrew Lunn } 1946427bb2dSAndrew Lunn 1956427bb2dSAndrew Lunn static int marvell_set_page(struct phy_device *phydev, int page) 1966427bb2dSAndrew Lunn { 1976427bb2dSAndrew Lunn return phy_write(phydev, MII_MARVELL_PHY_PAGE, page); 1986427bb2dSAndrew Lunn } 1996427bb2dSAndrew Lunn 20053798328SAndrew Lunn static int marvell_get_set_page(struct phy_device *phydev, int page) 20153798328SAndrew Lunn { 20253798328SAndrew Lunn int oldpage = marvell_get_page(phydev); 20353798328SAndrew Lunn 20453798328SAndrew Lunn if (oldpage < 0) 20553798328SAndrew Lunn return oldpage; 20653798328SAndrew Lunn 20753798328SAndrew Lunn if (page != oldpage) 20853798328SAndrew Lunn return marvell_set_page(phydev, page); 20953798328SAndrew Lunn 21053798328SAndrew Lunn return 0; 21153798328SAndrew Lunn } 21253798328SAndrew Lunn 21300db8189SAndy Fleming static int marvell_ack_interrupt(struct phy_device *phydev) 21400db8189SAndy Fleming { 21500db8189SAndy Fleming int err; 21600db8189SAndy Fleming 21700db8189SAndy Fleming /* Clear the interrupts by reading the reg */ 21800db8189SAndy Fleming err = phy_read(phydev, MII_M1011_IEVENT); 21900db8189SAndy Fleming 22000db8189SAndy Fleming if (err < 0) 22100db8189SAndy Fleming return err; 22200db8189SAndy Fleming 22300db8189SAndy Fleming return 0; 22400db8189SAndy Fleming } 22500db8189SAndy Fleming 22600db8189SAndy Fleming static int marvell_config_intr(struct phy_device *phydev) 22700db8189SAndy Fleming { 22800db8189SAndy Fleming int err; 22900db8189SAndy Fleming 23000db8189SAndy Fleming if (phydev->interrupts == PHY_INTERRUPT_ENABLED) 23123beb38fSAndrew Lunn err = phy_write(phydev, MII_M1011_IMASK, 23223beb38fSAndrew Lunn MII_M1011_IMASK_INIT); 23300db8189SAndy Fleming else 23423beb38fSAndrew Lunn err = phy_write(phydev, MII_M1011_IMASK, 23523beb38fSAndrew Lunn MII_M1011_IMASK_CLEAR); 23600db8189SAndy Fleming 23700db8189SAndy Fleming return err; 23800db8189SAndy Fleming } 23900db8189SAndy Fleming 240239aa55bSDavid Thomson static int marvell_set_polarity(struct phy_device *phydev, int polarity) 241239aa55bSDavid Thomson { 242239aa55bSDavid Thomson int reg; 243239aa55bSDavid Thomson int err; 244239aa55bSDavid Thomson int val; 245239aa55bSDavid Thomson 246239aa55bSDavid Thomson /* get the current settings */ 247239aa55bSDavid Thomson reg = phy_read(phydev, MII_M1011_PHY_SCR); 248239aa55bSDavid Thomson if (reg < 0) 249239aa55bSDavid Thomson return reg; 250239aa55bSDavid Thomson 251239aa55bSDavid Thomson val = reg; 252239aa55bSDavid Thomson val &= ~MII_M1011_PHY_SCR_AUTO_CROSS; 253239aa55bSDavid Thomson switch (polarity) { 254239aa55bSDavid Thomson case ETH_TP_MDI: 255239aa55bSDavid Thomson val |= MII_M1011_PHY_SCR_MDI; 256239aa55bSDavid Thomson break; 257239aa55bSDavid Thomson case ETH_TP_MDI_X: 258239aa55bSDavid Thomson val |= MII_M1011_PHY_SCR_MDI_X; 259239aa55bSDavid Thomson break; 260239aa55bSDavid Thomson case ETH_TP_MDI_AUTO: 261239aa55bSDavid Thomson case ETH_TP_MDI_INVALID: 262239aa55bSDavid Thomson default: 263239aa55bSDavid Thomson val |= MII_M1011_PHY_SCR_AUTO_CROSS; 264239aa55bSDavid Thomson break; 265239aa55bSDavid Thomson } 266239aa55bSDavid Thomson 267239aa55bSDavid Thomson if (val != reg) { 268239aa55bSDavid Thomson /* Set the new polarity value in the register */ 269239aa55bSDavid Thomson err = phy_write(phydev, MII_M1011_PHY_SCR, val); 270239aa55bSDavid Thomson if (err) 271239aa55bSDavid Thomson return err; 272239aa55bSDavid Thomson } 273239aa55bSDavid Thomson 274239aa55bSDavid Thomson return 0; 275239aa55bSDavid Thomson } 276239aa55bSDavid Thomson 27700db8189SAndy Fleming static int marvell_config_aneg(struct phy_device *phydev) 27800db8189SAndy Fleming { 27900db8189SAndy Fleming int err; 28000db8189SAndy Fleming 2814e26c5c3SRaju Lakkaraju err = marvell_set_polarity(phydev, phydev->mdix_ctrl); 28276884679SAndy Fleming if (err < 0) 28376884679SAndy Fleming return err; 28476884679SAndy Fleming 28576884679SAndy Fleming err = phy_write(phydev, MII_M1111_PHY_LED_CONTROL, 28676884679SAndy Fleming MII_M1111_PHY_LED_DIRECT); 28776884679SAndy Fleming if (err < 0) 28876884679SAndy Fleming return err; 28900db8189SAndy Fleming 29000db8189SAndy Fleming err = genphy_config_aneg(phydev); 2918ff44985SAnton Vorontsov if (err < 0) 29200db8189SAndy Fleming return err; 2938ff44985SAnton Vorontsov 2948ff44985SAnton Vorontsov if (phydev->autoneg != AUTONEG_ENABLE) { 2958ff44985SAnton Vorontsov int bmcr; 2968ff44985SAnton Vorontsov 2970c3439bcSAndrew Lunn /* A write to speed/duplex bits (that is performed by 2988ff44985SAnton Vorontsov * genphy_config_aneg() call above) must be followed by 2998ff44985SAnton Vorontsov * a software reset. Otherwise, the write has no effect. 3008ff44985SAnton Vorontsov */ 3018ff44985SAnton Vorontsov bmcr = phy_read(phydev, MII_BMCR); 3028ff44985SAnton Vorontsov if (bmcr < 0) 3038ff44985SAnton Vorontsov return bmcr; 3048ff44985SAnton Vorontsov 3058ff44985SAnton Vorontsov err = phy_write(phydev, MII_BMCR, bmcr | BMCR_RESET); 3068ff44985SAnton Vorontsov if (err < 0) 3078ff44985SAnton Vorontsov return err; 3088ff44985SAnton Vorontsov } 3098ff44985SAnton Vorontsov 3108ff44985SAnton Vorontsov return 0; 31100db8189SAndy Fleming } 31200db8189SAndy Fleming 313f2899788SAndrew Lunn static int m88e1101_config_aneg(struct phy_device *phydev) 314f2899788SAndrew Lunn { 315f2899788SAndrew Lunn int err; 316f2899788SAndrew Lunn 317f2899788SAndrew Lunn /* This Marvell PHY has an errata which requires 318f2899788SAndrew Lunn * that certain registers get written in order 319f2899788SAndrew Lunn * to restart autonegotiation 320f2899788SAndrew Lunn */ 321f2899788SAndrew Lunn err = phy_write(phydev, MII_BMCR, BMCR_RESET); 322f2899788SAndrew Lunn 323f2899788SAndrew Lunn if (err < 0) 324f2899788SAndrew Lunn return err; 325f2899788SAndrew Lunn 326f2899788SAndrew Lunn err = phy_write(phydev, 0x1d, 0x1f); 327f2899788SAndrew Lunn if (err < 0) 328f2899788SAndrew Lunn return err; 329f2899788SAndrew Lunn 330f2899788SAndrew Lunn err = phy_write(phydev, 0x1e, 0x200c); 331f2899788SAndrew Lunn if (err < 0) 332f2899788SAndrew Lunn return err; 333f2899788SAndrew Lunn 334f2899788SAndrew Lunn err = phy_write(phydev, 0x1d, 0x5); 335f2899788SAndrew Lunn if (err < 0) 336f2899788SAndrew Lunn return err; 337f2899788SAndrew Lunn 338f2899788SAndrew Lunn err = phy_write(phydev, 0x1e, 0); 339f2899788SAndrew Lunn if (err < 0) 340f2899788SAndrew Lunn return err; 341f2899788SAndrew Lunn 342f2899788SAndrew Lunn err = phy_write(phydev, 0x1e, 0x100); 343f2899788SAndrew Lunn if (err < 0) 344f2899788SAndrew Lunn return err; 345f2899788SAndrew Lunn 346f2899788SAndrew Lunn return marvell_config_aneg(phydev); 347f2899788SAndrew Lunn } 348f2899788SAndrew Lunn 3493ec0a0f1SHarini Katakam static int m88e1111_config_aneg(struct phy_device *phydev) 3503ec0a0f1SHarini Katakam { 3513ec0a0f1SHarini Katakam int err; 3523ec0a0f1SHarini Katakam 3533ec0a0f1SHarini Katakam /* The Marvell PHY has an errata which requires 3543ec0a0f1SHarini Katakam * that certain registers get written in order 3553ec0a0f1SHarini Katakam * to restart autonegotiation 3563ec0a0f1SHarini Katakam */ 3573ec0a0f1SHarini Katakam err = phy_write(phydev, MII_BMCR, BMCR_RESET); 3583ec0a0f1SHarini Katakam 3594e26c5c3SRaju Lakkaraju err = marvell_set_polarity(phydev, phydev->mdix_ctrl); 3603ec0a0f1SHarini Katakam if (err < 0) 3613ec0a0f1SHarini Katakam return err; 3623ec0a0f1SHarini Katakam 3633ec0a0f1SHarini Katakam err = phy_write(phydev, MII_M1111_PHY_LED_CONTROL, 3643ec0a0f1SHarini Katakam MII_M1111_PHY_LED_DIRECT); 3653ec0a0f1SHarini Katakam if (err < 0) 3663ec0a0f1SHarini Katakam return err; 3673ec0a0f1SHarini Katakam 3683ec0a0f1SHarini Katakam err = genphy_config_aneg(phydev); 3693ec0a0f1SHarini Katakam if (err < 0) 3703ec0a0f1SHarini Katakam return err; 3713ec0a0f1SHarini Katakam 3723ec0a0f1SHarini Katakam if (phydev->autoneg != AUTONEG_ENABLE) { 3733ec0a0f1SHarini Katakam int bmcr; 3743ec0a0f1SHarini Katakam 3753ec0a0f1SHarini Katakam /* A write to speed/duplex bits (that is performed by 3763ec0a0f1SHarini Katakam * genphy_config_aneg() call above) must be followed by 3773ec0a0f1SHarini Katakam * a software reset. Otherwise, the write has no effect. 3783ec0a0f1SHarini Katakam */ 3793ec0a0f1SHarini Katakam bmcr = phy_read(phydev, MII_BMCR); 3803ec0a0f1SHarini Katakam if (bmcr < 0) 3813ec0a0f1SHarini Katakam return bmcr; 3823ec0a0f1SHarini Katakam 3833ec0a0f1SHarini Katakam err = phy_write(phydev, MII_BMCR, bmcr | BMCR_RESET); 3843ec0a0f1SHarini Katakam if (err < 0) 3853ec0a0f1SHarini Katakam return err; 3863ec0a0f1SHarini Katakam } 3873ec0a0f1SHarini Katakam 3883ec0a0f1SHarini Katakam return 0; 3893ec0a0f1SHarini Katakam } 3903ec0a0f1SHarini Katakam 391cf41a51dSDavid Daney #ifdef CONFIG_OF_MDIO 3920c3439bcSAndrew Lunn /* Set and/or override some configuration registers based on the 393cf41a51dSDavid Daney * marvell,reg-init property stored in the of_node for the phydev. 394cf41a51dSDavid Daney * 395cf41a51dSDavid Daney * marvell,reg-init = <reg-page reg mask value>,...; 396cf41a51dSDavid Daney * 397cf41a51dSDavid Daney * There may be one or more sets of <reg-page reg mask value>: 398cf41a51dSDavid Daney * 399cf41a51dSDavid Daney * reg-page: which register bank to use. 400cf41a51dSDavid Daney * reg: the register. 401cf41a51dSDavid Daney * mask: if non-zero, ANDed with existing register value. 402cf41a51dSDavid Daney * value: ORed with the masked value and written to the regiser. 403cf41a51dSDavid Daney * 404cf41a51dSDavid Daney */ 405cf41a51dSDavid Daney static int marvell_of_reg_init(struct phy_device *phydev) 406cf41a51dSDavid Daney { 407cf41a51dSDavid Daney const __be32 *paddr; 408b5718b5aSUwe Kleine-König int len, i, saved_page, current_page, ret; 409cf41a51dSDavid Daney 410e5a03bfdSAndrew Lunn if (!phydev->mdio.dev.of_node) 411cf41a51dSDavid Daney return 0; 412cf41a51dSDavid Daney 413e5a03bfdSAndrew Lunn paddr = of_get_property(phydev->mdio.dev.of_node, 414e5a03bfdSAndrew Lunn "marvell,reg-init", &len); 415cf41a51dSDavid Daney if (!paddr || len < (4 * sizeof(*paddr))) 416cf41a51dSDavid Daney return 0; 417cf41a51dSDavid Daney 4186427bb2dSAndrew Lunn saved_page = marvell_get_page(phydev); 419cf41a51dSDavid Daney if (saved_page < 0) 420cf41a51dSDavid Daney return saved_page; 421cf41a51dSDavid Daney current_page = saved_page; 422cf41a51dSDavid Daney 423cf41a51dSDavid Daney ret = 0; 424cf41a51dSDavid Daney len /= sizeof(*paddr); 425cf41a51dSDavid Daney for (i = 0; i < len - 3; i += 4) { 4266427bb2dSAndrew Lunn u16 page = be32_to_cpup(paddr + i); 427cf41a51dSDavid Daney u16 reg = be32_to_cpup(paddr + i + 1); 428cf41a51dSDavid Daney u16 mask = be32_to_cpup(paddr + i + 2); 429cf41a51dSDavid Daney u16 val_bits = be32_to_cpup(paddr + i + 3); 430cf41a51dSDavid Daney int val; 431cf41a51dSDavid Daney 4326427bb2dSAndrew Lunn if (page != current_page) { 4336427bb2dSAndrew Lunn current_page = page; 4346427bb2dSAndrew Lunn ret = marvell_set_page(phydev, page); 435cf41a51dSDavid Daney if (ret < 0) 436cf41a51dSDavid Daney goto err; 437cf41a51dSDavid Daney } 438cf41a51dSDavid Daney 439cf41a51dSDavid Daney val = 0; 440cf41a51dSDavid Daney if (mask) { 441cf41a51dSDavid Daney val = phy_read(phydev, reg); 442cf41a51dSDavid Daney if (val < 0) { 443cf41a51dSDavid Daney ret = val; 444cf41a51dSDavid Daney goto err; 445cf41a51dSDavid Daney } 446cf41a51dSDavid Daney val &= mask; 447cf41a51dSDavid Daney } 448cf41a51dSDavid Daney val |= val_bits; 449cf41a51dSDavid Daney 450cf41a51dSDavid Daney ret = phy_write(phydev, reg, val); 451cf41a51dSDavid Daney if (ret < 0) 452cf41a51dSDavid Daney goto err; 453cf41a51dSDavid Daney } 454cf41a51dSDavid Daney err: 455b5718b5aSUwe Kleine-König if (current_page != saved_page) { 4566427bb2dSAndrew Lunn i = marvell_set_page(phydev, saved_page); 457cf41a51dSDavid Daney if (ret == 0) 458cf41a51dSDavid Daney ret = i; 459cf41a51dSDavid Daney } 460cf41a51dSDavid Daney return ret; 461cf41a51dSDavid Daney } 462cf41a51dSDavid Daney #else 463cf41a51dSDavid Daney static int marvell_of_reg_init(struct phy_device *phydev) 464cf41a51dSDavid Daney { 465cf41a51dSDavid Daney return 0; 466cf41a51dSDavid Daney } 467cf41a51dSDavid Daney #endif /* CONFIG_OF_MDIO */ 468cf41a51dSDavid Daney 469140bc929SSergei Poselenov static int m88e1121_config_aneg(struct phy_device *phydev) 470140bc929SSergei Poselenov { 471c477d044SCyril Chemparathy int err, oldpage, mscr; 472c477d044SCyril Chemparathy 47352295666SAndrew Lunn oldpage = marvell_get_set_page(phydev, MII_MARVELL_MSCR_PAGE); 47453798328SAndrew Lunn if (oldpage < 0) 47553798328SAndrew Lunn return oldpage; 476be8c6480SArnaud Patard 47732a64161SFlorian Fainelli if (phy_interface_is_rgmii(phydev)) { 478c477d044SCyril Chemparathy mscr = phy_read(phydev, MII_88E1121_PHY_MSCR_REG) & 479c477d044SCyril Chemparathy MII_88E1121_PHY_MSCR_DELAY_MASK; 480c477d044SCyril Chemparathy 481c477d044SCyril Chemparathy if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID) 482c477d044SCyril Chemparathy mscr |= (MII_88E1121_PHY_MSCR_RX_DELAY | 483c477d044SCyril Chemparathy MII_88E1121_PHY_MSCR_TX_DELAY); 484c477d044SCyril Chemparathy else if (phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID) 485c477d044SCyril Chemparathy mscr |= MII_88E1121_PHY_MSCR_RX_DELAY; 486c477d044SCyril Chemparathy else if (phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID) 487c477d044SCyril Chemparathy mscr |= MII_88E1121_PHY_MSCR_TX_DELAY; 488c477d044SCyril Chemparathy 489c477d044SCyril Chemparathy err = phy_write(phydev, MII_88E1121_PHY_MSCR_REG, mscr); 490c477d044SCyril Chemparathy if (err < 0) 491c477d044SCyril Chemparathy return err; 492be8c6480SArnaud Patard } 493c477d044SCyril Chemparathy 4946427bb2dSAndrew Lunn marvell_set_page(phydev, oldpage); 495140bc929SSergei Poselenov 496140bc929SSergei Poselenov err = phy_write(phydev, MII_BMCR, BMCR_RESET); 497140bc929SSergei Poselenov if (err < 0) 498140bc929SSergei Poselenov return err; 499140bc929SSergei Poselenov 500140bc929SSergei Poselenov err = phy_write(phydev, MII_M1011_PHY_SCR, 501140bc929SSergei Poselenov MII_M1011_PHY_SCR_AUTO_CROSS); 502140bc929SSergei Poselenov if (err < 0) 503140bc929SSergei Poselenov return err; 504140bc929SSergei Poselenov 505fdecf36fSClemens Gruber return genphy_config_aneg(phydev); 506140bc929SSergei Poselenov } 507140bc929SSergei Poselenov 508337ac9d5SCyril Chemparathy static int m88e1318_config_aneg(struct phy_device *phydev) 5093ff1c259SCyril Chemparathy { 5103ff1c259SCyril Chemparathy int err, oldpage, mscr; 5113ff1c259SCyril Chemparathy 51252295666SAndrew Lunn oldpage = marvell_get_set_page(phydev, MII_MARVELL_MSCR_PAGE); 51353798328SAndrew Lunn if (oldpage < 0) 51453798328SAndrew Lunn return oldpage; 5153ff1c259SCyril Chemparathy 516337ac9d5SCyril Chemparathy mscr = phy_read(phydev, MII_88E1318S_PHY_MSCR1_REG); 517337ac9d5SCyril Chemparathy mscr |= MII_88E1318S_PHY_MSCR1_PAD_ODD; 5183ff1c259SCyril Chemparathy 519337ac9d5SCyril Chemparathy err = phy_write(phydev, MII_88E1318S_PHY_MSCR1_REG, mscr); 5203ff1c259SCyril Chemparathy if (err < 0) 5213ff1c259SCyril Chemparathy return err; 5223ff1c259SCyril Chemparathy 5236427bb2dSAndrew Lunn err = marvell_set_page(phydev, oldpage); 5243ff1c259SCyril Chemparathy if (err < 0) 5253ff1c259SCyril Chemparathy return err; 5263ff1c259SCyril Chemparathy 5273ff1c259SCyril Chemparathy return m88e1121_config_aneg(phydev); 5283ff1c259SCyril Chemparathy } 5293ff1c259SCyril Chemparathy 53078301ebeSCharles-Antoine Couret /** 53178301ebeSCharles-Antoine Couret * ethtool_adv_to_fiber_adv_t 53278301ebeSCharles-Antoine Couret * @ethadv: the ethtool advertisement settings 53378301ebeSCharles-Antoine Couret * 53478301ebeSCharles-Antoine Couret * A small helper function that translates ethtool advertisement 53578301ebeSCharles-Antoine Couret * settings to phy autonegotiation advertisements for the 53678301ebeSCharles-Antoine Couret * MII_ADV register for fiber link. 53778301ebeSCharles-Antoine Couret */ 53878301ebeSCharles-Antoine Couret static inline u32 ethtool_adv_to_fiber_adv_t(u32 ethadv) 53978301ebeSCharles-Antoine Couret { 54078301ebeSCharles-Antoine Couret u32 result = 0; 54178301ebeSCharles-Antoine Couret 54278301ebeSCharles-Antoine Couret if (ethadv & ADVERTISED_1000baseT_Half) 54378301ebeSCharles-Antoine Couret result |= ADVERTISE_FIBER_1000HALF; 54478301ebeSCharles-Antoine Couret if (ethadv & ADVERTISED_1000baseT_Full) 54578301ebeSCharles-Antoine Couret result |= ADVERTISE_FIBER_1000FULL; 54678301ebeSCharles-Antoine Couret 54778301ebeSCharles-Antoine Couret if ((ethadv & ADVERTISE_PAUSE_ASYM) && (ethadv & ADVERTISE_PAUSE_CAP)) 54878301ebeSCharles-Antoine Couret result |= LPA_PAUSE_ASYM_FIBER; 54978301ebeSCharles-Antoine Couret else if (ethadv & ADVERTISE_PAUSE_CAP) 55078301ebeSCharles-Antoine Couret result |= (ADVERTISE_PAUSE_FIBER 55178301ebeSCharles-Antoine Couret & (~ADVERTISE_PAUSE_ASYM_FIBER)); 55278301ebeSCharles-Antoine Couret 55378301ebeSCharles-Antoine Couret return result; 55478301ebeSCharles-Antoine Couret } 55578301ebeSCharles-Antoine Couret 55678301ebeSCharles-Antoine Couret /** 55778301ebeSCharles-Antoine Couret * marvell_config_aneg_fiber - restart auto-negotiation or write BMCR 55878301ebeSCharles-Antoine Couret * @phydev: target phy_device struct 55978301ebeSCharles-Antoine Couret * 56078301ebeSCharles-Antoine Couret * Description: If auto-negotiation is enabled, we configure the 56178301ebeSCharles-Antoine Couret * advertising, and then restart auto-negotiation. If it is not 56278301ebeSCharles-Antoine Couret * enabled, then we write the BMCR. Adapted for fiber link in 56378301ebeSCharles-Antoine Couret * some Marvell's devices. 56478301ebeSCharles-Antoine Couret */ 56578301ebeSCharles-Antoine Couret static int marvell_config_aneg_fiber(struct phy_device *phydev) 56678301ebeSCharles-Antoine Couret { 56778301ebeSCharles-Antoine Couret int changed = 0; 56878301ebeSCharles-Antoine Couret int err; 56978301ebeSCharles-Antoine Couret int adv, oldadv; 57078301ebeSCharles-Antoine Couret u32 advertise; 57178301ebeSCharles-Antoine Couret 57278301ebeSCharles-Antoine Couret if (phydev->autoneg != AUTONEG_ENABLE) 57378301ebeSCharles-Antoine Couret return genphy_setup_forced(phydev); 57478301ebeSCharles-Antoine Couret 57578301ebeSCharles-Antoine Couret /* Only allow advertising what this PHY supports */ 57678301ebeSCharles-Antoine Couret phydev->advertising &= phydev->supported; 57778301ebeSCharles-Antoine Couret advertise = phydev->advertising; 57878301ebeSCharles-Antoine Couret 57978301ebeSCharles-Antoine Couret /* Setup fiber advertisement */ 58078301ebeSCharles-Antoine Couret adv = phy_read(phydev, MII_ADVERTISE); 58178301ebeSCharles-Antoine Couret if (adv < 0) 58278301ebeSCharles-Antoine Couret return adv; 58378301ebeSCharles-Antoine Couret 58478301ebeSCharles-Antoine Couret oldadv = adv; 58578301ebeSCharles-Antoine Couret adv &= ~(ADVERTISE_FIBER_1000HALF | ADVERTISE_FIBER_1000FULL 58678301ebeSCharles-Antoine Couret | LPA_PAUSE_FIBER); 58778301ebeSCharles-Antoine Couret adv |= ethtool_adv_to_fiber_adv_t(advertise); 58878301ebeSCharles-Antoine Couret 58978301ebeSCharles-Antoine Couret if (adv != oldadv) { 59078301ebeSCharles-Antoine Couret err = phy_write(phydev, MII_ADVERTISE, adv); 59178301ebeSCharles-Antoine Couret if (err < 0) 59278301ebeSCharles-Antoine Couret return err; 59378301ebeSCharles-Antoine Couret 59478301ebeSCharles-Antoine Couret changed = 1; 59578301ebeSCharles-Antoine Couret } 59678301ebeSCharles-Antoine Couret 59778301ebeSCharles-Antoine Couret if (changed == 0) { 59878301ebeSCharles-Antoine Couret /* Advertisement hasn't changed, but maybe aneg was never on to 59978301ebeSCharles-Antoine Couret * begin with? Or maybe phy was isolated? 60078301ebeSCharles-Antoine Couret */ 60178301ebeSCharles-Antoine Couret int ctl = phy_read(phydev, MII_BMCR); 60278301ebeSCharles-Antoine Couret 60378301ebeSCharles-Antoine Couret if (ctl < 0) 60478301ebeSCharles-Antoine Couret return ctl; 60578301ebeSCharles-Antoine Couret 60678301ebeSCharles-Antoine Couret if (!(ctl & BMCR_ANENABLE) || (ctl & BMCR_ISOLATE)) 60778301ebeSCharles-Antoine Couret changed = 1; /* do restart aneg */ 60878301ebeSCharles-Antoine Couret } 60978301ebeSCharles-Antoine Couret 61078301ebeSCharles-Antoine Couret /* Only restart aneg if we are advertising something different 61178301ebeSCharles-Antoine Couret * than we were before. 61278301ebeSCharles-Antoine Couret */ 61378301ebeSCharles-Antoine Couret if (changed > 0) 61478301ebeSCharles-Antoine Couret changed = genphy_restart_aneg(phydev); 61578301ebeSCharles-Antoine Couret 61678301ebeSCharles-Antoine Couret return changed; 61778301ebeSCharles-Antoine Couret } 61878301ebeSCharles-Antoine Couret 61910e24caaSMichal Simek static int m88e1510_config_aneg(struct phy_device *phydev) 62010e24caaSMichal Simek { 62110e24caaSMichal Simek int err; 62210e24caaSMichal Simek 62352295666SAndrew Lunn err = marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE); 62478301ebeSCharles-Antoine Couret if (err < 0) 62578301ebeSCharles-Antoine Couret goto error; 62678301ebeSCharles-Antoine Couret 62778301ebeSCharles-Antoine Couret /* Configure the copper link first */ 62810e24caaSMichal Simek err = m88e1318_config_aneg(phydev); 62910e24caaSMichal Simek if (err < 0) 63078301ebeSCharles-Antoine Couret goto error; 63110e24caaSMichal Simek 63278301ebeSCharles-Antoine Couret /* Then the fiber link */ 63352295666SAndrew Lunn err = marvell_set_page(phydev, MII_MARVELL_FIBER_PAGE); 63478301ebeSCharles-Antoine Couret if (err < 0) 63578301ebeSCharles-Antoine Couret goto error; 63678301ebeSCharles-Antoine Couret 63778301ebeSCharles-Antoine Couret err = marvell_config_aneg_fiber(phydev); 63878301ebeSCharles-Antoine Couret if (err < 0) 63978301ebeSCharles-Antoine Couret goto error; 64078301ebeSCharles-Antoine Couret 64152295666SAndrew Lunn return marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE); 64278301ebeSCharles-Antoine Couret 64378301ebeSCharles-Antoine Couret error: 64452295666SAndrew Lunn marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE); 64578301ebeSCharles-Antoine Couret return err; 64679be1a1cSClemens Gruber } 64779be1a1cSClemens Gruber 64879be1a1cSClemens Gruber static int marvell_config_init(struct phy_device *phydev) 64979be1a1cSClemens Gruber { 65079be1a1cSClemens Gruber /* Set registers from marvell,reg-init DT property */ 65110e24caaSMichal Simek return marvell_of_reg_init(phydev); 65210e24caaSMichal Simek } 65310e24caaSMichal Simek 6543da09a51SMichal Simek static int m88e1116r_config_init(struct phy_device *phydev) 6553da09a51SMichal Simek { 6563da09a51SMichal Simek int temp; 6573da09a51SMichal Simek int err; 6583da09a51SMichal Simek 6593da09a51SMichal Simek temp = phy_read(phydev, MII_BMCR); 6603da09a51SMichal Simek temp |= BMCR_RESET; 6613da09a51SMichal Simek err = phy_write(phydev, MII_BMCR, temp); 6623da09a51SMichal Simek if (err < 0) 6633da09a51SMichal Simek return err; 6643da09a51SMichal Simek 6653da09a51SMichal Simek mdelay(500); 6663da09a51SMichal Simek 66752295666SAndrew Lunn err = marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE); 6683da09a51SMichal Simek if (err < 0) 6693da09a51SMichal Simek return err; 6703da09a51SMichal Simek 6713da09a51SMichal Simek temp = phy_read(phydev, MII_M1011_PHY_SCR); 6723da09a51SMichal Simek temp |= (7 << 12); /* max number of gigabit attempts */ 6733da09a51SMichal Simek temp |= (1 << 11); /* enable downshift */ 6743da09a51SMichal Simek temp |= MII_M1011_PHY_SCR_AUTO_CROSS; 6753da09a51SMichal Simek err = phy_write(phydev, MII_M1011_PHY_SCR, temp); 6763da09a51SMichal Simek if (err < 0) 6773da09a51SMichal Simek return err; 6783da09a51SMichal Simek 67952295666SAndrew Lunn err = marvell_set_page(phydev, MII_MARVELL_MSCR_PAGE); 6803da09a51SMichal Simek if (err < 0) 6813da09a51SMichal Simek return err; 6823da09a51SMichal Simek temp = phy_read(phydev, MII_M1116R_CONTROL_REG_MAC); 6833da09a51SMichal Simek temp |= (1 << 5); 6843da09a51SMichal Simek temp |= (1 << 4); 6853da09a51SMichal Simek err = phy_write(phydev, MII_M1116R_CONTROL_REG_MAC, temp); 6863da09a51SMichal Simek if (err < 0) 6873da09a51SMichal Simek return err; 68852295666SAndrew Lunn err = marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE); 6893da09a51SMichal Simek if (err < 0) 6903da09a51SMichal Simek return err; 6913da09a51SMichal Simek 6923da09a51SMichal Simek temp = phy_read(phydev, MII_BMCR); 6933da09a51SMichal Simek temp |= BMCR_RESET; 6943da09a51SMichal Simek err = phy_write(phydev, MII_BMCR, temp); 6953da09a51SMichal Simek if (err < 0) 6963da09a51SMichal Simek return err; 6973da09a51SMichal Simek 6983da09a51SMichal Simek mdelay(500); 6993da09a51SMichal Simek 70079be1a1cSClemens Gruber return marvell_config_init(phydev); 7013da09a51SMichal Simek } 7023da09a51SMichal Simek 7036b358aedSSebastian Hesselbarth static int m88e3016_config_init(struct phy_device *phydev) 7046b358aedSSebastian Hesselbarth { 7056b358aedSSebastian Hesselbarth int reg; 7066b358aedSSebastian Hesselbarth 7076b358aedSSebastian Hesselbarth /* Enable Scrambler and Auto-Crossover */ 7086b358aedSSebastian Hesselbarth reg = phy_read(phydev, MII_88E3016_PHY_SPEC_CTRL); 7096b358aedSSebastian Hesselbarth if (reg < 0) 7106b358aedSSebastian Hesselbarth return reg; 7116b358aedSSebastian Hesselbarth 7126b358aedSSebastian Hesselbarth reg &= ~MII_88E3016_DISABLE_SCRAMBLER; 7136b358aedSSebastian Hesselbarth reg |= MII_88E3016_AUTO_MDIX_CROSSOVER; 7146b358aedSSebastian Hesselbarth 7156b358aedSSebastian Hesselbarth reg = phy_write(phydev, MII_88E3016_PHY_SPEC_CTRL, reg); 7166b358aedSSebastian Hesselbarth if (reg < 0) 7176b358aedSSebastian Hesselbarth return reg; 7186b358aedSSebastian Hesselbarth 71979be1a1cSClemens Gruber return marvell_config_init(phydev); 7206b358aedSSebastian Hesselbarth } 7216b358aedSSebastian Hesselbarth 722e1dde8dcSAndrew Lunn static int m88e1111_config_init_rgmii(struct phy_device *phydev) 723895ee682SKim Phillips { 724895ee682SKim Phillips int err; 725be937f1fSAlexandr Smirnov int temp; 726be937f1fSAlexandr Smirnov 727895ee682SKim Phillips temp = phy_read(phydev, MII_M1111_PHY_EXT_CR); 728895ee682SKim Phillips if (temp < 0) 729895ee682SKim Phillips return temp; 730895ee682SKim Phillips 7319daf5a76SKim Phillips if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID) { 732895ee682SKim Phillips temp |= (MII_M1111_RX_DELAY | MII_M1111_TX_DELAY); 7339daf5a76SKim Phillips } else if (phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID) { 7349daf5a76SKim Phillips temp &= ~MII_M1111_TX_DELAY; 7359daf5a76SKim Phillips temp |= MII_M1111_RX_DELAY; 7369daf5a76SKim Phillips } else if (phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID) { 7379daf5a76SKim Phillips temp &= ~MII_M1111_RX_DELAY; 7389daf5a76SKim Phillips temp |= MII_M1111_TX_DELAY; 7399daf5a76SKim Phillips } 740895ee682SKim Phillips 741895ee682SKim Phillips err = phy_write(phydev, MII_M1111_PHY_EXT_CR, temp); 742895ee682SKim Phillips if (err < 0) 743895ee682SKim Phillips return err; 744895ee682SKim Phillips 745895ee682SKim Phillips temp = phy_read(phydev, MII_M1111_PHY_EXT_SR); 746895ee682SKim Phillips if (temp < 0) 747895ee682SKim Phillips return temp; 748895ee682SKim Phillips 749895ee682SKim Phillips temp &= ~(MII_M1111_HWCFG_MODE_MASK); 750be937f1fSAlexandr Smirnov 7517239016dSWang Jian if (temp & MII_M1111_HWCFG_FIBER_COPPER_RES) 752be937f1fSAlexandr Smirnov temp |= MII_M1111_HWCFG_MODE_FIBER_RGMII; 753be937f1fSAlexandr Smirnov else 754be937f1fSAlexandr Smirnov temp |= MII_M1111_HWCFG_MODE_COPPER_RGMII; 755895ee682SKim Phillips 756e1dde8dcSAndrew Lunn return phy_write(phydev, MII_M1111_PHY_EXT_SR, temp); 757895ee682SKim Phillips } 758895ee682SKim Phillips 759e1dde8dcSAndrew Lunn static int m88e1111_config_init_sgmii(struct phy_device *phydev) 760e1dde8dcSAndrew Lunn { 761e1dde8dcSAndrew Lunn int err; 762e1dde8dcSAndrew Lunn int temp; 763e1dde8dcSAndrew Lunn 7644117b5beSKapil Juneja temp = phy_read(phydev, MII_M1111_PHY_EXT_SR); 7654117b5beSKapil Juneja if (temp < 0) 7664117b5beSKapil Juneja return temp; 7674117b5beSKapil Juneja 7684117b5beSKapil Juneja temp &= ~(MII_M1111_HWCFG_MODE_MASK); 7694117b5beSKapil Juneja temp |= MII_M1111_HWCFG_MODE_SGMII_NO_CLK; 77032d0c1e1SHaiying Wang temp |= MII_M1111_HWCFG_FIBER_COPPER_AUTO; 7714117b5beSKapil Juneja 7724117b5beSKapil Juneja err = phy_write(phydev, MII_M1111_PHY_EXT_SR, temp); 7734117b5beSKapil Juneja if (err < 0) 7744117b5beSKapil Juneja return err; 77507151bc9SMadalin Bucur 77607151bc9SMadalin Bucur /* make sure copper is selected */ 77752295666SAndrew Lunn return marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE); 7784117b5beSKapil Juneja } 7794117b5beSKapil Juneja 780e1dde8dcSAndrew Lunn static int m88e1111_config_init_rtbi(struct phy_device *phydev) 781e1dde8dcSAndrew Lunn { 782e1dde8dcSAndrew Lunn int err; 783e1dde8dcSAndrew Lunn int temp; 784e1dde8dcSAndrew Lunn 7855f8cbc13SLiu Yu-B13201 temp = phy_read(phydev, MII_M1111_PHY_EXT_CR); 7865f8cbc13SLiu Yu-B13201 if (temp < 0) 7875f8cbc13SLiu Yu-B13201 return temp; 788e1dde8dcSAndrew Lunn 7895f8cbc13SLiu Yu-B13201 temp |= (MII_M1111_RX_DELAY | MII_M1111_TX_DELAY); 7905f8cbc13SLiu Yu-B13201 err = phy_write(phydev, MII_M1111_PHY_EXT_CR, temp); 7915f8cbc13SLiu Yu-B13201 if (err < 0) 7925f8cbc13SLiu Yu-B13201 return err; 7935f8cbc13SLiu Yu-B13201 7945f8cbc13SLiu Yu-B13201 temp = phy_read(phydev, MII_M1111_PHY_EXT_SR); 7955f8cbc13SLiu Yu-B13201 if (temp < 0) 7965f8cbc13SLiu Yu-B13201 return temp; 797e1dde8dcSAndrew Lunn 798e1dde8dcSAndrew Lunn temp &= ~(MII_M1111_HWCFG_MODE_MASK | 799e1dde8dcSAndrew Lunn MII_M1111_HWCFG_FIBER_COPPER_RES); 8005f8cbc13SLiu Yu-B13201 temp |= 0x7 | MII_M1111_HWCFG_FIBER_COPPER_AUTO; 801e1dde8dcSAndrew Lunn 8025f8cbc13SLiu Yu-B13201 err = phy_write(phydev, MII_M1111_PHY_EXT_SR, temp); 8035f8cbc13SLiu Yu-B13201 if (err < 0) 8045f8cbc13SLiu Yu-B13201 return err; 8055f8cbc13SLiu Yu-B13201 8065f8cbc13SLiu Yu-B13201 /* soft reset */ 8075f8cbc13SLiu Yu-B13201 err = phy_write(phydev, MII_BMCR, BMCR_RESET); 8085f8cbc13SLiu Yu-B13201 if (err < 0) 8095f8cbc13SLiu Yu-B13201 return err; 810e1dde8dcSAndrew Lunn 8115f8cbc13SLiu Yu-B13201 do 8125f8cbc13SLiu Yu-B13201 temp = phy_read(phydev, MII_BMCR); 8135f8cbc13SLiu Yu-B13201 while (temp & BMCR_RESET); 8145f8cbc13SLiu Yu-B13201 8155f8cbc13SLiu Yu-B13201 temp = phy_read(phydev, MII_M1111_PHY_EXT_SR); 8165f8cbc13SLiu Yu-B13201 if (temp < 0) 8175f8cbc13SLiu Yu-B13201 return temp; 818e1dde8dcSAndrew Lunn 819e1dde8dcSAndrew Lunn temp &= ~(MII_M1111_HWCFG_MODE_MASK | 820e1dde8dcSAndrew Lunn MII_M1111_HWCFG_FIBER_COPPER_RES); 821e1dde8dcSAndrew Lunn temp |= MII_M1111_HWCFG_MODE_COPPER_RTBI | 822e1dde8dcSAndrew Lunn MII_M1111_HWCFG_FIBER_COPPER_AUTO; 823e1dde8dcSAndrew Lunn 824e1dde8dcSAndrew Lunn return phy_write(phydev, MII_M1111_PHY_EXT_SR, temp); 825e1dde8dcSAndrew Lunn } 826e1dde8dcSAndrew Lunn 827e1dde8dcSAndrew Lunn static int m88e1111_config_init(struct phy_device *phydev) 828e1dde8dcSAndrew Lunn { 829e1dde8dcSAndrew Lunn int err; 830e1dde8dcSAndrew Lunn 831e1dde8dcSAndrew Lunn if (phy_interface_is_rgmii(phydev)) { 832e1dde8dcSAndrew Lunn err = m88e1111_config_init_rgmii(phydev); 833e1dde8dcSAndrew Lunn if (err) 834e1dde8dcSAndrew Lunn return err; 835e1dde8dcSAndrew Lunn } 836e1dde8dcSAndrew Lunn 837e1dde8dcSAndrew Lunn if (phydev->interface == PHY_INTERFACE_MODE_SGMII) { 838e1dde8dcSAndrew Lunn err = m88e1111_config_init_sgmii(phydev); 839e1dde8dcSAndrew Lunn if (err < 0) 840e1dde8dcSAndrew Lunn return err; 841e1dde8dcSAndrew Lunn } 842e1dde8dcSAndrew Lunn 843e1dde8dcSAndrew Lunn if (phydev->interface == PHY_INTERFACE_MODE_RTBI) { 844e1dde8dcSAndrew Lunn err = m88e1111_config_init_rtbi(phydev); 8455f8cbc13SLiu Yu-B13201 if (err < 0) 8465f8cbc13SLiu Yu-B13201 return err; 8475f8cbc13SLiu Yu-B13201 } 8485f8cbc13SLiu Yu-B13201 849cf41a51dSDavid Daney err = marvell_of_reg_init(phydev); 850cf41a51dSDavid Daney if (err < 0) 851cf41a51dSDavid Daney return err; 8525f8cbc13SLiu Yu-B13201 853cc90cb3bSSrinivas Kandagatla return phy_write(phydev, MII_BMCR, BMCR_RESET); 854895ee682SKim Phillips } 855895ee682SKim Phillips 856fdecf36fSClemens Gruber static int m88e1121_config_init(struct phy_device *phydev) 857fdecf36fSClemens Gruber { 858fdecf36fSClemens Gruber int err, oldpage; 859fdecf36fSClemens Gruber 86052295666SAndrew Lunn oldpage = marvell_get_set_page(phydev, MII_MARVELL_LED_PAGE); 86153798328SAndrew Lunn if (oldpage < 0) 86253798328SAndrew Lunn return oldpage; 863fdecf36fSClemens Gruber 864fdecf36fSClemens Gruber /* Default PHY LED config: LED[0] .. Link, LED[1] .. Activity */ 865fdecf36fSClemens Gruber err = phy_write(phydev, MII_88E1121_PHY_LED_CTRL, 866fdecf36fSClemens Gruber MII_88E1121_PHY_LED_DEF); 867fdecf36fSClemens Gruber if (err < 0) 868fdecf36fSClemens Gruber return err; 869fdecf36fSClemens Gruber 8706427bb2dSAndrew Lunn marvell_set_page(phydev, oldpage); 871fdecf36fSClemens Gruber 872fdecf36fSClemens Gruber /* Set marvell,reg-init configuration from device tree */ 873fdecf36fSClemens Gruber return marvell_config_init(phydev); 874fdecf36fSClemens Gruber } 875fdecf36fSClemens Gruber 876407353ecSClemens Gruber static int m88e1510_config_init(struct phy_device *phydev) 877407353ecSClemens Gruber { 878407353ecSClemens Gruber int err; 879407353ecSClemens Gruber int temp; 880407353ecSClemens Gruber 881407353ecSClemens Gruber /* SGMII-to-Copper mode initialization */ 882407353ecSClemens Gruber if (phydev->interface == PHY_INTERFACE_MODE_SGMII) { 883407353ecSClemens Gruber /* Select page 18 */ 8846427bb2dSAndrew Lunn err = marvell_set_page(phydev, 18); 885407353ecSClemens Gruber if (err < 0) 886407353ecSClemens Gruber return err; 887407353ecSClemens Gruber 888407353ecSClemens Gruber /* In reg 20, write MODE[2:0] = 0x1 (SGMII to Copper) */ 889407353ecSClemens Gruber temp = phy_read(phydev, MII_88E1510_GEN_CTRL_REG_1); 890407353ecSClemens Gruber temp &= ~MII_88E1510_GEN_CTRL_REG_1_MODE_MASK; 891407353ecSClemens Gruber temp |= MII_88E1510_GEN_CTRL_REG_1_MODE_SGMII; 892407353ecSClemens Gruber err = phy_write(phydev, MII_88E1510_GEN_CTRL_REG_1, temp); 893407353ecSClemens Gruber if (err < 0) 894407353ecSClemens Gruber return err; 895407353ecSClemens Gruber 896407353ecSClemens Gruber /* PHY reset is necessary after changing MODE[2:0] */ 897407353ecSClemens Gruber temp |= MII_88E1510_GEN_CTRL_REG_1_RESET; 898407353ecSClemens Gruber err = phy_write(phydev, MII_88E1510_GEN_CTRL_REG_1, temp); 899407353ecSClemens Gruber if (err < 0) 900407353ecSClemens Gruber return err; 901407353ecSClemens Gruber 902407353ecSClemens Gruber /* Reset page selection */ 90352295666SAndrew Lunn err = marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE); 904407353ecSClemens Gruber if (err < 0) 905407353ecSClemens Gruber return err; 906407353ecSClemens Gruber } 907407353ecSClemens Gruber 908fdecf36fSClemens Gruber return m88e1121_config_init(phydev); 909407353ecSClemens Gruber } 910407353ecSClemens Gruber 911605f196eSRon Madrid static int m88e1118_config_aneg(struct phy_device *phydev) 912605f196eSRon Madrid { 913605f196eSRon Madrid int err; 914605f196eSRon Madrid 915605f196eSRon Madrid err = phy_write(phydev, MII_BMCR, BMCR_RESET); 916605f196eSRon Madrid if (err < 0) 917605f196eSRon Madrid return err; 918605f196eSRon Madrid 919605f196eSRon Madrid err = phy_write(phydev, MII_M1011_PHY_SCR, 920605f196eSRon Madrid MII_M1011_PHY_SCR_AUTO_CROSS); 921605f196eSRon Madrid if (err < 0) 922605f196eSRon Madrid return err; 923605f196eSRon Madrid 924605f196eSRon Madrid err = genphy_config_aneg(phydev); 925605f196eSRon Madrid return 0; 926605f196eSRon Madrid } 927605f196eSRon Madrid 928605f196eSRon Madrid static int m88e1118_config_init(struct phy_device *phydev) 929605f196eSRon Madrid { 930605f196eSRon Madrid int err; 931605f196eSRon Madrid 932605f196eSRon Madrid /* Change address */ 93352295666SAndrew Lunn err = marvell_set_page(phydev, MII_MARVELL_MSCR_PAGE); 934605f196eSRon Madrid if (err < 0) 935605f196eSRon Madrid return err; 936605f196eSRon Madrid 937605f196eSRon Madrid /* Enable 1000 Mbit */ 938605f196eSRon Madrid err = phy_write(phydev, 0x15, 0x1070); 939605f196eSRon Madrid if (err < 0) 940605f196eSRon Madrid return err; 941605f196eSRon Madrid 942605f196eSRon Madrid /* Change address */ 94352295666SAndrew Lunn err = marvell_set_page(phydev, MII_MARVELL_LED_PAGE); 944605f196eSRon Madrid if (err < 0) 945605f196eSRon Madrid return err; 946605f196eSRon Madrid 947605f196eSRon Madrid /* Adjust LED Control */ 9482f495c39SBenjamin Herrenschmidt if (phydev->dev_flags & MARVELL_PHY_M1118_DNS323_LEDS) 9492f495c39SBenjamin Herrenschmidt err = phy_write(phydev, 0x10, 0x1100); 9502f495c39SBenjamin Herrenschmidt else 951605f196eSRon Madrid err = phy_write(phydev, 0x10, 0x021e); 952605f196eSRon Madrid if (err < 0) 953605f196eSRon Madrid return err; 954605f196eSRon Madrid 955cf41a51dSDavid Daney err = marvell_of_reg_init(phydev); 956cf41a51dSDavid Daney if (err < 0) 957cf41a51dSDavid Daney return err; 958cf41a51dSDavid Daney 959605f196eSRon Madrid /* Reset address */ 96052295666SAndrew Lunn err = marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE); 961605f196eSRon Madrid if (err < 0) 962605f196eSRon Madrid return err; 963605f196eSRon Madrid 964cc90cb3bSSrinivas Kandagatla return phy_write(phydev, MII_BMCR, BMCR_RESET); 965605f196eSRon Madrid } 966605f196eSRon Madrid 96790600732SDavid Daney static int m88e1149_config_init(struct phy_device *phydev) 96890600732SDavid Daney { 96990600732SDavid Daney int err; 97090600732SDavid Daney 97190600732SDavid Daney /* Change address */ 97252295666SAndrew Lunn err = marvell_set_page(phydev, MII_MARVELL_MSCR_PAGE); 97390600732SDavid Daney if (err < 0) 97490600732SDavid Daney return err; 97590600732SDavid Daney 97690600732SDavid Daney /* Enable 1000 Mbit */ 97790600732SDavid Daney err = phy_write(phydev, 0x15, 0x1048); 97890600732SDavid Daney if (err < 0) 97990600732SDavid Daney return err; 98090600732SDavid Daney 981cf41a51dSDavid Daney err = marvell_of_reg_init(phydev); 982cf41a51dSDavid Daney if (err < 0) 983cf41a51dSDavid Daney return err; 984cf41a51dSDavid Daney 98590600732SDavid Daney /* Reset address */ 98652295666SAndrew Lunn err = marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE); 98790600732SDavid Daney if (err < 0) 98890600732SDavid Daney return err; 98990600732SDavid Daney 990cc90cb3bSSrinivas Kandagatla return phy_write(phydev, MII_BMCR, BMCR_RESET); 99190600732SDavid Daney } 99290600732SDavid Daney 993e1dde8dcSAndrew Lunn static int m88e1145_config_init_rgmii(struct phy_device *phydev) 99476884679SAndy Fleming { 99576884679SAndy Fleming int err; 99676884679SAndy Fleming int temp = phy_read(phydev, MII_M1145_PHY_EXT_CR); 997e69d9ed4SAndrew Lunn 99876884679SAndy Fleming if (temp < 0) 99976884679SAndy Fleming return temp; 100076884679SAndy Fleming 100176884679SAndy Fleming temp |= (MII_M1145_RGMII_RX_DELAY | MII_M1145_RGMII_TX_DELAY); 100276884679SAndy Fleming 100376884679SAndy Fleming err = phy_write(phydev, MII_M1145_PHY_EXT_CR, temp); 100476884679SAndy Fleming if (err < 0) 100576884679SAndy Fleming return err; 100676884679SAndy Fleming 10072f495c39SBenjamin Herrenschmidt if (phydev->dev_flags & MARVELL_PHY_M1145_FLAGS_RESISTANCE) { 100876884679SAndy Fleming err = phy_write(phydev, 0x1d, 0x0012); 100976884679SAndy Fleming if (err < 0) 101076884679SAndy Fleming return err; 101176884679SAndy Fleming 101276884679SAndy Fleming temp = phy_read(phydev, 0x1e); 101376884679SAndy Fleming if (temp < 0) 101476884679SAndy Fleming return temp; 101576884679SAndy Fleming 101676884679SAndy Fleming temp &= 0xf03f; 101776884679SAndy Fleming temp |= 2 << 9; /* 36 ohm */ 101876884679SAndy Fleming temp |= 2 << 6; /* 39 ohm */ 101976884679SAndy Fleming 102076884679SAndy Fleming err = phy_write(phydev, 0x1e, temp); 102176884679SAndy Fleming if (err < 0) 102276884679SAndy Fleming return err; 102376884679SAndy Fleming 102476884679SAndy Fleming err = phy_write(phydev, 0x1d, 0x3); 102576884679SAndy Fleming if (err < 0) 102676884679SAndy Fleming return err; 102776884679SAndy Fleming 102876884679SAndy Fleming err = phy_write(phydev, 0x1e, 0x8000); 1029e1dde8dcSAndrew Lunn } 103076884679SAndy Fleming return err; 103176884679SAndy Fleming } 103276884679SAndy Fleming 1033e1dde8dcSAndrew Lunn static int m88e1145_config_init_sgmii(struct phy_device *phydev) 1034e1dde8dcSAndrew Lunn { 1035e1dde8dcSAndrew Lunn int temp = phy_read(phydev, MII_M1145_PHY_EXT_SR); 1036e1dde8dcSAndrew Lunn 1037b0224175SViet Nga Dao if (temp < 0) 1038b0224175SViet Nga Dao return temp; 1039b0224175SViet Nga Dao 104099d881f9SVince Bridgers temp &= ~MII_M1145_HWCFG_MODE_MASK; 1041b0224175SViet Nga Dao temp |= MII_M1145_HWCFG_MODE_SGMII_NO_CLK; 1042b0224175SViet Nga Dao temp |= MII_M1145_HWCFG_FIBER_COPPER_AUTO; 1043b0224175SViet Nga Dao 1044e1dde8dcSAndrew Lunn return phy_write(phydev, MII_M1145_PHY_EXT_SR, temp); 1045e1dde8dcSAndrew Lunn } 1046e1dde8dcSAndrew Lunn 1047e1dde8dcSAndrew Lunn static int m88e1145_config_init(struct phy_device *phydev) 1048e1dde8dcSAndrew Lunn { 1049e1dde8dcSAndrew Lunn int err; 1050e1dde8dcSAndrew Lunn 1051e1dde8dcSAndrew Lunn /* Take care of errata E0 & E1 */ 1052e1dde8dcSAndrew Lunn err = phy_write(phydev, 0x1d, 0x001b); 1053e1dde8dcSAndrew Lunn if (err < 0) 1054e1dde8dcSAndrew Lunn return err; 1055e1dde8dcSAndrew Lunn 1056e1dde8dcSAndrew Lunn err = phy_write(phydev, 0x1e, 0x418f); 1057e1dde8dcSAndrew Lunn if (err < 0) 1058e1dde8dcSAndrew Lunn return err; 1059e1dde8dcSAndrew Lunn 1060e1dde8dcSAndrew Lunn err = phy_write(phydev, 0x1d, 0x0016); 1061e1dde8dcSAndrew Lunn if (err < 0) 1062e1dde8dcSAndrew Lunn return err; 1063e1dde8dcSAndrew Lunn 1064e1dde8dcSAndrew Lunn err = phy_write(phydev, 0x1e, 0xa2da); 1065e1dde8dcSAndrew Lunn if (err < 0) 1066e1dde8dcSAndrew Lunn return err; 1067e1dde8dcSAndrew Lunn 1068e1dde8dcSAndrew Lunn if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID) { 1069e1dde8dcSAndrew Lunn err = m88e1145_config_init_rgmii(phydev); 1070e1dde8dcSAndrew Lunn if (err < 0) 1071e1dde8dcSAndrew Lunn return err; 1072e1dde8dcSAndrew Lunn } 1073e1dde8dcSAndrew Lunn 1074e1dde8dcSAndrew Lunn if (phydev->interface == PHY_INTERFACE_MODE_SGMII) { 1075e1dde8dcSAndrew Lunn err = m88e1145_config_init_sgmii(phydev); 1076b0224175SViet Nga Dao if (err < 0) 1077b0224175SViet Nga Dao return err; 1078b0224175SViet Nga Dao } 1079b0224175SViet Nga Dao 1080cf41a51dSDavid Daney err = marvell_of_reg_init(phydev); 1081cf41a51dSDavid Daney if (err < 0) 1082cf41a51dSDavid Daney return err; 1083cf41a51dSDavid Daney 108476884679SAndy Fleming return 0; 108576884679SAndy Fleming } 108600db8189SAndy Fleming 10876cfb3bccSCharles-Antoine Couret /** 10886cfb3bccSCharles-Antoine Couret * fiber_lpa_to_ethtool_lpa_t 10896cfb3bccSCharles-Antoine Couret * @lpa: value of the MII_LPA register for fiber link 1090be937f1fSAlexandr Smirnov * 10916cfb3bccSCharles-Antoine Couret * A small helper function that translates MII_LPA 10926cfb3bccSCharles-Antoine Couret * bits to ethtool LP advertisement settings. 10936cfb3bccSCharles-Antoine Couret */ 10946cfb3bccSCharles-Antoine Couret static u32 fiber_lpa_to_ethtool_lpa_t(u32 lpa) 10956cfb3bccSCharles-Antoine Couret { 10966cfb3bccSCharles-Antoine Couret u32 result = 0; 10976cfb3bccSCharles-Antoine Couret 10986cfb3bccSCharles-Antoine Couret if (lpa & LPA_FIBER_1000HALF) 10996cfb3bccSCharles-Antoine Couret result |= ADVERTISED_1000baseT_Half; 11006cfb3bccSCharles-Antoine Couret if (lpa & LPA_FIBER_1000FULL) 11016cfb3bccSCharles-Antoine Couret result |= ADVERTISED_1000baseT_Full; 11026cfb3bccSCharles-Antoine Couret 11036cfb3bccSCharles-Antoine Couret return result; 11046cfb3bccSCharles-Antoine Couret } 11056cfb3bccSCharles-Antoine Couret 11066cfb3bccSCharles-Antoine Couret /** 11076cfb3bccSCharles-Antoine Couret * marvell_update_link - update link status in real time in @phydev 11086cfb3bccSCharles-Antoine Couret * @phydev: target phy_device struct 11096cfb3bccSCharles-Antoine Couret * 11106cfb3bccSCharles-Antoine Couret * Description: Update the value in phydev->link to reflect the 11116cfb3bccSCharles-Antoine Couret * current link value. 11126cfb3bccSCharles-Antoine Couret */ 11136cfb3bccSCharles-Antoine Couret static int marvell_update_link(struct phy_device *phydev, int fiber) 11146cfb3bccSCharles-Antoine Couret { 11156cfb3bccSCharles-Antoine Couret int status; 11166cfb3bccSCharles-Antoine Couret 11176cfb3bccSCharles-Antoine Couret /* Use the generic register for copper link, or specific 11180c3439bcSAndrew Lunn * register for fiber case 11190c3439bcSAndrew Lunn */ 11206cfb3bccSCharles-Antoine Couret if (fiber) { 11216cfb3bccSCharles-Antoine Couret status = phy_read(phydev, MII_M1011_PHY_STATUS); 11226cfb3bccSCharles-Antoine Couret if (status < 0) 11236cfb3bccSCharles-Antoine Couret return status; 11246cfb3bccSCharles-Antoine Couret 11256cfb3bccSCharles-Antoine Couret if ((status & REGISTER_LINK_STATUS) == 0) 11266cfb3bccSCharles-Antoine Couret phydev->link = 0; 11276cfb3bccSCharles-Antoine Couret else 11286cfb3bccSCharles-Antoine Couret phydev->link = 1; 11296cfb3bccSCharles-Antoine Couret } else { 11306cfb3bccSCharles-Antoine Couret return genphy_update_link(phydev); 11316cfb3bccSCharles-Antoine Couret } 11326cfb3bccSCharles-Antoine Couret 11336cfb3bccSCharles-Antoine Couret return 0; 11346cfb3bccSCharles-Antoine Couret } 11356cfb3bccSCharles-Antoine Couret 1136e1dde8dcSAndrew Lunn static int marvell_read_status_page_an(struct phy_device *phydev, 1137e1dde8dcSAndrew Lunn int fiber) 1138be937f1fSAlexandr Smirnov { 1139e1dde8dcSAndrew Lunn int status; 1140be937f1fSAlexandr Smirnov int lpa; 1141357cd64cSRussell King int lpagb; 1142e1dde8dcSAndrew Lunn int adv; 1143be937f1fSAlexandr Smirnov 1144be937f1fSAlexandr Smirnov status = phy_read(phydev, MII_M1011_PHY_STATUS); 1145be937f1fSAlexandr Smirnov if (status < 0) 1146be937f1fSAlexandr Smirnov return status; 1147be937f1fSAlexandr Smirnov 1148be937f1fSAlexandr Smirnov lpa = phy_read(phydev, MII_LPA); 1149be937f1fSAlexandr Smirnov if (lpa < 0) 1150be937f1fSAlexandr Smirnov return lpa; 1151be937f1fSAlexandr Smirnov 1152357cd64cSRussell King lpagb = phy_read(phydev, MII_STAT1000); 1153357cd64cSRussell King if (lpagb < 0) 1154357cd64cSRussell King return lpagb; 1155357cd64cSRussell King 1156be937f1fSAlexandr Smirnov adv = phy_read(phydev, MII_ADVERTISE); 1157be937f1fSAlexandr Smirnov if (adv < 0) 1158be937f1fSAlexandr Smirnov return adv; 1159be937f1fSAlexandr Smirnov 1160be937f1fSAlexandr Smirnov lpa &= adv; 1161be937f1fSAlexandr Smirnov 1162be937f1fSAlexandr Smirnov if (status & MII_M1011_PHY_STATUS_FULLDUPLEX) 1163be937f1fSAlexandr Smirnov phydev->duplex = DUPLEX_FULL; 1164be937f1fSAlexandr Smirnov else 1165be937f1fSAlexandr Smirnov phydev->duplex = DUPLEX_HALF; 1166be937f1fSAlexandr Smirnov 1167be937f1fSAlexandr Smirnov status = status & MII_M1011_PHY_STATUS_SPD_MASK; 11684f48ed32SAndrew Lunn phydev->pause = 0; 11694f48ed32SAndrew Lunn phydev->asym_pause = 0; 1170be937f1fSAlexandr Smirnov 1171be937f1fSAlexandr Smirnov switch (status) { 1172be937f1fSAlexandr Smirnov case MII_M1011_PHY_STATUS_1000: 1173be937f1fSAlexandr Smirnov phydev->speed = SPEED_1000; 1174be937f1fSAlexandr Smirnov break; 1175be937f1fSAlexandr Smirnov 1176be937f1fSAlexandr Smirnov case MII_M1011_PHY_STATUS_100: 1177be937f1fSAlexandr Smirnov phydev->speed = SPEED_100; 1178be937f1fSAlexandr Smirnov break; 1179be937f1fSAlexandr Smirnov 1180be937f1fSAlexandr Smirnov default: 1181be937f1fSAlexandr Smirnov phydev->speed = SPEED_10; 1182be937f1fSAlexandr Smirnov break; 1183be937f1fSAlexandr Smirnov } 1184be937f1fSAlexandr Smirnov 11856cfb3bccSCharles-Antoine Couret if (!fiber) { 1186e1dde8dcSAndrew Lunn phydev->lp_advertising = 1187e1dde8dcSAndrew Lunn mii_stat1000_to_ethtool_lpa_t(lpagb) | 11886cfb3bccSCharles-Antoine Couret mii_lpa_to_ethtool_lpa_t(lpa); 11896cfb3bccSCharles-Antoine Couret 1190be937f1fSAlexandr Smirnov if (phydev->duplex == DUPLEX_FULL) { 1191be937f1fSAlexandr Smirnov phydev->pause = lpa & LPA_PAUSE_CAP ? 1 : 0; 1192be937f1fSAlexandr Smirnov phydev->asym_pause = lpa & LPA_PAUSE_ASYM ? 1 : 0; 1193be937f1fSAlexandr Smirnov } 1194be937f1fSAlexandr Smirnov } else { 11956cfb3bccSCharles-Antoine Couret /* The fiber link is only 1000M capable */ 11966cfb3bccSCharles-Antoine Couret phydev->lp_advertising = fiber_lpa_to_ethtool_lpa_t(lpa); 11976cfb3bccSCharles-Antoine Couret 11986cfb3bccSCharles-Antoine Couret if (phydev->duplex == DUPLEX_FULL) { 11996cfb3bccSCharles-Antoine Couret if (!(lpa & LPA_PAUSE_FIBER)) { 12006cfb3bccSCharles-Antoine Couret phydev->pause = 0; 12016cfb3bccSCharles-Antoine Couret phydev->asym_pause = 0; 12026cfb3bccSCharles-Antoine Couret } else if ((lpa & LPA_PAUSE_ASYM_FIBER)) { 12036cfb3bccSCharles-Antoine Couret phydev->pause = 1; 12046cfb3bccSCharles-Antoine Couret phydev->asym_pause = 1; 12056cfb3bccSCharles-Antoine Couret } else { 12066cfb3bccSCharles-Antoine Couret phydev->pause = 1; 12076cfb3bccSCharles-Antoine Couret phydev->asym_pause = 0; 12086cfb3bccSCharles-Antoine Couret } 12096cfb3bccSCharles-Antoine Couret } 12106cfb3bccSCharles-Antoine Couret } 1211e1dde8dcSAndrew Lunn return 0; 1212e1dde8dcSAndrew Lunn } 1213e1dde8dcSAndrew Lunn 1214e1dde8dcSAndrew Lunn static int marvell_read_status_page_fixed(struct phy_device *phydev) 1215e1dde8dcSAndrew Lunn { 1216be937f1fSAlexandr Smirnov int bmcr = phy_read(phydev, MII_BMCR); 1217be937f1fSAlexandr Smirnov 1218be937f1fSAlexandr Smirnov if (bmcr < 0) 1219be937f1fSAlexandr Smirnov return bmcr; 1220be937f1fSAlexandr Smirnov 1221be937f1fSAlexandr Smirnov if (bmcr & BMCR_FULLDPLX) 1222be937f1fSAlexandr Smirnov phydev->duplex = DUPLEX_FULL; 1223be937f1fSAlexandr Smirnov else 1224be937f1fSAlexandr Smirnov phydev->duplex = DUPLEX_HALF; 1225be937f1fSAlexandr Smirnov 1226be937f1fSAlexandr Smirnov if (bmcr & BMCR_SPEED1000) 1227be937f1fSAlexandr Smirnov phydev->speed = SPEED_1000; 1228be937f1fSAlexandr Smirnov else if (bmcr & BMCR_SPEED100) 1229be937f1fSAlexandr Smirnov phydev->speed = SPEED_100; 1230be937f1fSAlexandr Smirnov else 1231be937f1fSAlexandr Smirnov phydev->speed = SPEED_10; 1232be937f1fSAlexandr Smirnov 12334f48ed32SAndrew Lunn phydev->pause = 0; 12344f48ed32SAndrew Lunn phydev->asym_pause = 0; 1235357cd64cSRussell King phydev->lp_advertising = 0; 1236be937f1fSAlexandr Smirnov 1237be937f1fSAlexandr Smirnov return 0; 1238be937f1fSAlexandr Smirnov } 1239be937f1fSAlexandr Smirnov 1240e1dde8dcSAndrew Lunn /* marvell_read_status_page 1241e1dde8dcSAndrew Lunn * 1242e1dde8dcSAndrew Lunn * Description: 1243e1dde8dcSAndrew Lunn * Check the link, then figure out the current state 1244e1dde8dcSAndrew Lunn * by comparing what we advertise with what the link partner 1245e1dde8dcSAndrew Lunn * advertises. Start by checking the gigabit possibilities, 1246e1dde8dcSAndrew Lunn * then move on to 10/100. 1247e1dde8dcSAndrew Lunn */ 1248e1dde8dcSAndrew Lunn static int marvell_read_status_page(struct phy_device *phydev, int page) 1249e1dde8dcSAndrew Lunn { 1250e1dde8dcSAndrew Lunn int fiber; 1251e1dde8dcSAndrew Lunn int err; 1252e1dde8dcSAndrew Lunn 1253e1dde8dcSAndrew Lunn /* Detect and update the link, but return if there 1254e1dde8dcSAndrew Lunn * was an error 1255e1dde8dcSAndrew Lunn */ 125652295666SAndrew Lunn if (page == MII_MARVELL_FIBER_PAGE) 1257e1dde8dcSAndrew Lunn fiber = 1; 1258e1dde8dcSAndrew Lunn else 1259e1dde8dcSAndrew Lunn fiber = 0; 1260e1dde8dcSAndrew Lunn 1261e1dde8dcSAndrew Lunn err = marvell_update_link(phydev, fiber); 1262e1dde8dcSAndrew Lunn if (err) 1263e1dde8dcSAndrew Lunn return err; 1264e1dde8dcSAndrew Lunn 1265e1dde8dcSAndrew Lunn if (phydev->autoneg == AUTONEG_ENABLE) 1266e1dde8dcSAndrew Lunn err = marvell_read_status_page_an(phydev, fiber); 1267e1dde8dcSAndrew Lunn else 1268e1dde8dcSAndrew Lunn err = marvell_read_status_page_fixed(phydev); 1269e1dde8dcSAndrew Lunn 1270e1dde8dcSAndrew Lunn return err; 1271e1dde8dcSAndrew Lunn } 1272e1dde8dcSAndrew Lunn 12736cfb3bccSCharles-Antoine Couret /* marvell_read_status 12746cfb3bccSCharles-Antoine Couret * 12756cfb3bccSCharles-Antoine Couret * Some Marvell's phys have two modes: fiber and copper. 12766cfb3bccSCharles-Antoine Couret * Both need status checked. 12776cfb3bccSCharles-Antoine Couret * Description: 12786cfb3bccSCharles-Antoine Couret * First, check the fiber link and status. 12796cfb3bccSCharles-Antoine Couret * If the fiber link is down, check the copper link and status which 12806cfb3bccSCharles-Antoine Couret * will be the default value if both link are down. 12816cfb3bccSCharles-Antoine Couret */ 12826cfb3bccSCharles-Antoine Couret static int marvell_read_status(struct phy_device *phydev) 12836cfb3bccSCharles-Antoine Couret { 12846cfb3bccSCharles-Antoine Couret int err; 12856cfb3bccSCharles-Antoine Couret 12866cfb3bccSCharles-Antoine Couret /* Check the fiber mode first */ 1287a13c0652SRussell King if (phydev->supported & SUPPORTED_FIBRE && 1288a13c0652SRussell King phydev->interface != PHY_INTERFACE_MODE_SGMII) { 128952295666SAndrew Lunn err = marvell_set_page(phydev, MII_MARVELL_FIBER_PAGE); 12906cfb3bccSCharles-Antoine Couret if (err < 0) 12916cfb3bccSCharles-Antoine Couret goto error; 12926cfb3bccSCharles-Antoine Couret 129352295666SAndrew Lunn err = marvell_read_status_page(phydev, MII_MARVELL_FIBER_PAGE); 12946cfb3bccSCharles-Antoine Couret if (err < 0) 12956cfb3bccSCharles-Antoine Couret goto error; 12966cfb3bccSCharles-Antoine Couret 12970c3439bcSAndrew Lunn /* If the fiber link is up, it is the selected and 12980c3439bcSAndrew Lunn * used link. In this case, we need to stay in the 12990c3439bcSAndrew Lunn * fiber page. Please to be careful about that, avoid 13000c3439bcSAndrew Lunn * to restore Copper page in other functions which 13010c3439bcSAndrew Lunn * could break the behaviour for some fiber phy like 13020c3439bcSAndrew Lunn * 88E1512. 13030c3439bcSAndrew Lunn */ 13046cfb3bccSCharles-Antoine Couret if (phydev->link) 13056cfb3bccSCharles-Antoine Couret return 0; 13066cfb3bccSCharles-Antoine Couret 13076cfb3bccSCharles-Antoine Couret /* If fiber link is down, check and save copper mode state */ 130852295666SAndrew Lunn err = marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE); 13096cfb3bccSCharles-Antoine Couret if (err < 0) 13106cfb3bccSCharles-Antoine Couret goto error; 13116cfb3bccSCharles-Antoine Couret } 13126cfb3bccSCharles-Antoine Couret 131352295666SAndrew Lunn return marvell_read_status_page(phydev, MII_MARVELL_COPPER_PAGE); 13146cfb3bccSCharles-Antoine Couret 13156cfb3bccSCharles-Antoine Couret error: 131652295666SAndrew Lunn marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE); 13176cfb3bccSCharles-Antoine Couret return err; 13186cfb3bccSCharles-Antoine Couret } 13193758be3dSCharles-Antoine Couret 13203758be3dSCharles-Antoine Couret /* marvell_suspend 13213758be3dSCharles-Antoine Couret * 13223758be3dSCharles-Antoine Couret * Some Marvell's phys have two modes: fiber and copper. 13233758be3dSCharles-Antoine Couret * Both need to be suspended 13243758be3dSCharles-Antoine Couret */ 13253758be3dSCharles-Antoine Couret static int marvell_suspend(struct phy_device *phydev) 13263758be3dSCharles-Antoine Couret { 13273758be3dSCharles-Antoine Couret int err; 13283758be3dSCharles-Antoine Couret 13293758be3dSCharles-Antoine Couret /* Suspend the fiber mode first */ 13303758be3dSCharles-Antoine Couret if (!(phydev->supported & SUPPORTED_FIBRE)) { 133152295666SAndrew Lunn err = marvell_set_page(phydev, MII_MARVELL_FIBER_PAGE); 13323758be3dSCharles-Antoine Couret if (err < 0) 13333758be3dSCharles-Antoine Couret goto error; 13343758be3dSCharles-Antoine Couret 13353758be3dSCharles-Antoine Couret /* With the page set, use the generic suspend */ 13363758be3dSCharles-Antoine Couret err = genphy_suspend(phydev); 13373758be3dSCharles-Antoine Couret if (err < 0) 13383758be3dSCharles-Antoine Couret goto error; 13393758be3dSCharles-Antoine Couret 13403758be3dSCharles-Antoine Couret /* Then, the copper link */ 134152295666SAndrew Lunn err = marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE); 13423758be3dSCharles-Antoine Couret if (err < 0) 13433758be3dSCharles-Antoine Couret goto error; 13443758be3dSCharles-Antoine Couret } 13453758be3dSCharles-Antoine Couret 13463758be3dSCharles-Antoine Couret /* With the page set, use the generic suspend */ 13473758be3dSCharles-Antoine Couret return genphy_suspend(phydev); 13483758be3dSCharles-Antoine Couret 13493758be3dSCharles-Antoine Couret error: 135052295666SAndrew Lunn marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE); 13513758be3dSCharles-Antoine Couret return err; 13523758be3dSCharles-Antoine Couret } 13533758be3dSCharles-Antoine Couret 13543758be3dSCharles-Antoine Couret /* marvell_resume 13553758be3dSCharles-Antoine Couret * 13563758be3dSCharles-Antoine Couret * Some Marvell's phys have two modes: fiber and copper. 13573758be3dSCharles-Antoine Couret * Both need to be resumed 13583758be3dSCharles-Antoine Couret */ 13593758be3dSCharles-Antoine Couret static int marvell_resume(struct phy_device *phydev) 13603758be3dSCharles-Antoine Couret { 13613758be3dSCharles-Antoine Couret int err; 13623758be3dSCharles-Antoine Couret 13633758be3dSCharles-Antoine Couret /* Resume the fiber mode first */ 13643758be3dSCharles-Antoine Couret if (!(phydev->supported & SUPPORTED_FIBRE)) { 136552295666SAndrew Lunn err = marvell_set_page(phydev, MII_MARVELL_FIBER_PAGE); 13663758be3dSCharles-Antoine Couret if (err < 0) 13673758be3dSCharles-Antoine Couret goto error; 13683758be3dSCharles-Antoine Couret 13693758be3dSCharles-Antoine Couret /* With the page set, use the generic resume */ 13703758be3dSCharles-Antoine Couret err = genphy_resume(phydev); 13713758be3dSCharles-Antoine Couret if (err < 0) 13723758be3dSCharles-Antoine Couret goto error; 13733758be3dSCharles-Antoine Couret 13743758be3dSCharles-Antoine Couret /* Then, the copper link */ 137552295666SAndrew Lunn err = marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE); 13763758be3dSCharles-Antoine Couret if (err < 0) 13773758be3dSCharles-Antoine Couret goto error; 13783758be3dSCharles-Antoine Couret } 13793758be3dSCharles-Antoine Couret 13803758be3dSCharles-Antoine Couret /* With the page set, use the generic resume */ 13813758be3dSCharles-Antoine Couret return genphy_resume(phydev); 13823758be3dSCharles-Antoine Couret 13833758be3dSCharles-Antoine Couret error: 138452295666SAndrew Lunn marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE); 13853758be3dSCharles-Antoine Couret return err; 13863758be3dSCharles-Antoine Couret } 13873758be3dSCharles-Antoine Couret 13886b358aedSSebastian Hesselbarth static int marvell_aneg_done(struct phy_device *phydev) 13896b358aedSSebastian Hesselbarth { 13906b358aedSSebastian Hesselbarth int retval = phy_read(phydev, MII_M1011_PHY_STATUS); 1391e69d9ed4SAndrew Lunn 13926b358aedSSebastian Hesselbarth return (retval < 0) ? retval : (retval & MII_M1011_PHY_STATUS_RESOLVED); 13936b358aedSSebastian Hesselbarth } 13946b358aedSSebastian Hesselbarth 1395dcd07be3SAnatolij Gustschin static int m88e1121_did_interrupt(struct phy_device *phydev) 1396dcd07be3SAnatolij Gustschin { 1397dcd07be3SAnatolij Gustschin int imask; 1398dcd07be3SAnatolij Gustschin 1399dcd07be3SAnatolij Gustschin imask = phy_read(phydev, MII_M1011_IEVENT); 1400dcd07be3SAnatolij Gustschin 1401dcd07be3SAnatolij Gustschin if (imask & MII_M1011_IMASK_INIT) 1402dcd07be3SAnatolij Gustschin return 1; 1403dcd07be3SAnatolij Gustschin 1404dcd07be3SAnatolij Gustschin return 0; 1405dcd07be3SAnatolij Gustschin } 1406dcd07be3SAnatolij Gustschin 140723beb38fSAndrew Lunn static void m88e1318_get_wol(struct phy_device *phydev, 140823beb38fSAndrew Lunn struct ethtool_wolinfo *wol) 14093871c387SMichael Stapelberg { 14103871c387SMichael Stapelberg wol->supported = WAKE_MAGIC; 14113871c387SMichael Stapelberg wol->wolopts = 0; 14123871c387SMichael Stapelberg 141352295666SAndrew Lunn if (marvell_set_page(phydev, MII_MARVELL_WOL_PAGE) < 0) 14143871c387SMichael Stapelberg return; 14153871c387SMichael Stapelberg 14163871c387SMichael Stapelberg if (phy_read(phydev, MII_88E1318S_PHY_WOL_CTRL) & 14173871c387SMichael Stapelberg MII_88E1318S_PHY_WOL_CTRL_MAGIC_PACKET_MATCH_ENABLE) 14183871c387SMichael Stapelberg wol->wolopts |= WAKE_MAGIC; 14193871c387SMichael Stapelberg 142052295666SAndrew Lunn if (marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE) < 0) 14213871c387SMichael Stapelberg return; 14223871c387SMichael Stapelberg } 14233871c387SMichael Stapelberg 142423beb38fSAndrew Lunn static int m88e1318_set_wol(struct phy_device *phydev, 142523beb38fSAndrew Lunn struct ethtool_wolinfo *wol) 14263871c387SMichael Stapelberg { 14273871c387SMichael Stapelberg int err, oldpage, temp; 14283871c387SMichael Stapelberg 14296427bb2dSAndrew Lunn oldpage = marvell_get_page(phydev); 14303871c387SMichael Stapelberg 14313871c387SMichael Stapelberg if (wol->wolopts & WAKE_MAGIC) { 14323871c387SMichael Stapelberg /* Explicitly switch to page 0x00, just to be sure */ 143352295666SAndrew Lunn err = marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE); 14343871c387SMichael Stapelberg if (err < 0) 14353871c387SMichael Stapelberg return err; 14363871c387SMichael Stapelberg 14373871c387SMichael Stapelberg /* Enable the WOL interrupt */ 14383871c387SMichael Stapelberg temp = phy_read(phydev, MII_88E1318S_PHY_CSIER); 14393871c387SMichael Stapelberg temp |= MII_88E1318S_PHY_CSIER_WOL_EIE; 14403871c387SMichael Stapelberg err = phy_write(phydev, MII_88E1318S_PHY_CSIER, temp); 14413871c387SMichael Stapelberg if (err < 0) 14423871c387SMichael Stapelberg return err; 14433871c387SMichael Stapelberg 144452295666SAndrew Lunn err = marvell_set_page(phydev, MII_MARVELL_LED_PAGE); 14453871c387SMichael Stapelberg if (err < 0) 14463871c387SMichael Stapelberg return err; 14473871c387SMichael Stapelberg 14483871c387SMichael Stapelberg /* Setup LED[2] as interrupt pin (active low) */ 14493871c387SMichael Stapelberg temp = phy_read(phydev, MII_88E1318S_PHY_LED_TCR); 14503871c387SMichael Stapelberg temp &= ~MII_88E1318S_PHY_LED_TCR_FORCE_INT; 14513871c387SMichael Stapelberg temp |= MII_88E1318S_PHY_LED_TCR_INTn_ENABLE; 14523871c387SMichael Stapelberg temp |= MII_88E1318S_PHY_LED_TCR_INT_ACTIVE_LOW; 14533871c387SMichael Stapelberg err = phy_write(phydev, MII_88E1318S_PHY_LED_TCR, temp); 14543871c387SMichael Stapelberg if (err < 0) 14553871c387SMichael Stapelberg return err; 14563871c387SMichael Stapelberg 145752295666SAndrew Lunn err = marvell_set_page(phydev, MII_MARVELL_WOL_PAGE); 14583871c387SMichael Stapelberg if (err < 0) 14593871c387SMichael Stapelberg return err; 14603871c387SMichael Stapelberg 14613871c387SMichael Stapelberg /* Store the device address for the magic packet */ 14623871c387SMichael Stapelberg err = phy_write(phydev, MII_88E1318S_PHY_MAGIC_PACKET_WORD2, 14633871c387SMichael Stapelberg ((phydev->attached_dev->dev_addr[5] << 8) | 14643871c387SMichael Stapelberg phydev->attached_dev->dev_addr[4])); 14653871c387SMichael Stapelberg if (err < 0) 14663871c387SMichael Stapelberg return err; 14673871c387SMichael Stapelberg err = phy_write(phydev, MII_88E1318S_PHY_MAGIC_PACKET_WORD1, 14683871c387SMichael Stapelberg ((phydev->attached_dev->dev_addr[3] << 8) | 14693871c387SMichael Stapelberg phydev->attached_dev->dev_addr[2])); 14703871c387SMichael Stapelberg if (err < 0) 14713871c387SMichael Stapelberg return err; 14723871c387SMichael Stapelberg err = phy_write(phydev, MII_88E1318S_PHY_MAGIC_PACKET_WORD0, 14733871c387SMichael Stapelberg ((phydev->attached_dev->dev_addr[1] << 8) | 14743871c387SMichael Stapelberg phydev->attached_dev->dev_addr[0])); 14753871c387SMichael Stapelberg if (err < 0) 14763871c387SMichael Stapelberg return err; 14773871c387SMichael Stapelberg 14783871c387SMichael Stapelberg /* Clear WOL status and enable magic packet matching */ 14793871c387SMichael Stapelberg temp = phy_read(phydev, MII_88E1318S_PHY_WOL_CTRL); 14803871c387SMichael Stapelberg temp |= MII_88E1318S_PHY_WOL_CTRL_CLEAR_WOL_STATUS; 14813871c387SMichael Stapelberg temp |= MII_88E1318S_PHY_WOL_CTRL_MAGIC_PACKET_MATCH_ENABLE; 14823871c387SMichael Stapelberg err = phy_write(phydev, MII_88E1318S_PHY_WOL_CTRL, temp); 14833871c387SMichael Stapelberg if (err < 0) 14843871c387SMichael Stapelberg return err; 14853871c387SMichael Stapelberg } else { 148652295666SAndrew Lunn err = marvell_set_page(phydev, MII_MARVELL_WOL_PAGE); 14873871c387SMichael Stapelberg if (err < 0) 14883871c387SMichael Stapelberg return err; 14893871c387SMichael Stapelberg 14903871c387SMichael Stapelberg /* Clear WOL status and disable magic packet matching */ 14913871c387SMichael Stapelberg temp = phy_read(phydev, MII_88E1318S_PHY_WOL_CTRL); 14923871c387SMichael Stapelberg temp |= MII_88E1318S_PHY_WOL_CTRL_CLEAR_WOL_STATUS; 14933871c387SMichael Stapelberg temp &= ~MII_88E1318S_PHY_WOL_CTRL_MAGIC_PACKET_MATCH_ENABLE; 14943871c387SMichael Stapelberg err = phy_write(phydev, MII_88E1318S_PHY_WOL_CTRL, temp); 14953871c387SMichael Stapelberg if (err < 0) 14963871c387SMichael Stapelberg return err; 14973871c387SMichael Stapelberg } 14983871c387SMichael Stapelberg 14996427bb2dSAndrew Lunn err = marvell_set_page(phydev, oldpage); 15003871c387SMichael Stapelberg if (err < 0) 15013871c387SMichael Stapelberg return err; 15023871c387SMichael Stapelberg 15033871c387SMichael Stapelberg return 0; 15043871c387SMichael Stapelberg } 15053871c387SMichael Stapelberg 1506d2fa47d9SAndrew Lunn static int marvell_get_sset_count(struct phy_device *phydev) 1507d2fa47d9SAndrew Lunn { 15082170fef7SCharles-Antoine Couret if (phydev->supported & SUPPORTED_FIBRE) 1509d2fa47d9SAndrew Lunn return ARRAY_SIZE(marvell_hw_stats); 15102170fef7SCharles-Antoine Couret else 15112170fef7SCharles-Antoine Couret return ARRAY_SIZE(marvell_hw_stats) - NB_FIBER_STATS; 1512d2fa47d9SAndrew Lunn } 1513d2fa47d9SAndrew Lunn 1514d2fa47d9SAndrew Lunn static void marvell_get_strings(struct phy_device *phydev, u8 *data) 1515d2fa47d9SAndrew Lunn { 1516d2fa47d9SAndrew Lunn int i; 1517d2fa47d9SAndrew Lunn 1518d2fa47d9SAndrew Lunn for (i = 0; i < ARRAY_SIZE(marvell_hw_stats); i++) { 1519d2fa47d9SAndrew Lunn memcpy(data + i * ETH_GSTRING_LEN, 1520d2fa47d9SAndrew Lunn marvell_hw_stats[i].string, ETH_GSTRING_LEN); 1521d2fa47d9SAndrew Lunn } 1522d2fa47d9SAndrew Lunn } 1523d2fa47d9SAndrew Lunn 1524d2fa47d9SAndrew Lunn #ifndef UINT64_MAX 1525d2fa47d9SAndrew Lunn #define UINT64_MAX (u64)(~((u64)0)) 1526d2fa47d9SAndrew Lunn #endif 1527d2fa47d9SAndrew Lunn static u64 marvell_get_stat(struct phy_device *phydev, int i) 1528d2fa47d9SAndrew Lunn { 1529d2fa47d9SAndrew Lunn struct marvell_hw_stat stat = marvell_hw_stats[i]; 1530d2fa47d9SAndrew Lunn struct marvell_priv *priv = phydev->priv; 153153798328SAndrew Lunn int oldpage, val; 1532321b4d4bSAndrew Lunn u64 ret; 1533d2fa47d9SAndrew Lunn 153453798328SAndrew Lunn oldpage = marvell_get_set_page(phydev, stat.page); 153553798328SAndrew Lunn if (oldpage < 0) 1536d2fa47d9SAndrew Lunn return UINT64_MAX; 1537d2fa47d9SAndrew Lunn 1538d2fa47d9SAndrew Lunn val = phy_read(phydev, stat.reg); 1539d2fa47d9SAndrew Lunn if (val < 0) { 1540321b4d4bSAndrew Lunn ret = UINT64_MAX; 1541d2fa47d9SAndrew Lunn } else { 1542d2fa47d9SAndrew Lunn val = val & ((1 << stat.bits) - 1); 1543d2fa47d9SAndrew Lunn priv->stats[i] += val; 1544321b4d4bSAndrew Lunn ret = priv->stats[i]; 1545d2fa47d9SAndrew Lunn } 1546d2fa47d9SAndrew Lunn 15476427bb2dSAndrew Lunn marvell_set_page(phydev, oldpage); 1548d2fa47d9SAndrew Lunn 1549321b4d4bSAndrew Lunn return ret; 1550d2fa47d9SAndrew Lunn } 1551d2fa47d9SAndrew Lunn 1552d2fa47d9SAndrew Lunn static void marvell_get_stats(struct phy_device *phydev, 1553d2fa47d9SAndrew Lunn struct ethtool_stats *stats, u64 *data) 1554d2fa47d9SAndrew Lunn { 1555d2fa47d9SAndrew Lunn int i; 1556d2fa47d9SAndrew Lunn 1557d2fa47d9SAndrew Lunn for (i = 0; i < ARRAY_SIZE(marvell_hw_stats); i++) 1558d2fa47d9SAndrew Lunn data[i] = marvell_get_stat(phydev, i); 1559d2fa47d9SAndrew Lunn } 1560d2fa47d9SAndrew Lunn 15610b04680fSAndrew Lunn #ifdef CONFIG_HWMON 15620b04680fSAndrew Lunn static int m88e1121_get_temp(struct phy_device *phydev, long *temp) 15630b04680fSAndrew Lunn { 1564975b388cSAndrew Lunn int oldpage; 15650b04680fSAndrew Lunn int ret; 15660b04680fSAndrew Lunn int val; 15670b04680fSAndrew Lunn 15680b04680fSAndrew Lunn *temp = 0; 15690b04680fSAndrew Lunn 15700b04680fSAndrew Lunn mutex_lock(&phydev->lock); 15710b04680fSAndrew Lunn 157252295666SAndrew Lunn oldpage = marvell_get_set_page(phydev, MII_MARVELL_MISC_TEST_PAGE); 1573975b388cSAndrew Lunn if (oldpage < 0) { 1574975b388cSAndrew Lunn mutex_unlock(&phydev->lock); 1575975b388cSAndrew Lunn return oldpage; 1576975b388cSAndrew Lunn } 1577975b388cSAndrew Lunn 15780b04680fSAndrew Lunn /* Enable temperature sensor */ 15790b04680fSAndrew Lunn ret = phy_read(phydev, MII_88E1121_MISC_TEST); 15800b04680fSAndrew Lunn if (ret < 0) 15810b04680fSAndrew Lunn goto error; 15820b04680fSAndrew Lunn 15830b04680fSAndrew Lunn ret = phy_write(phydev, MII_88E1121_MISC_TEST, 15840b04680fSAndrew Lunn ret | MII_88E1121_MISC_TEST_TEMP_SENSOR_EN); 15850b04680fSAndrew Lunn if (ret < 0) 15860b04680fSAndrew Lunn goto error; 15870b04680fSAndrew Lunn 15880b04680fSAndrew Lunn /* Wait for temperature to stabilize */ 15890b04680fSAndrew Lunn usleep_range(10000, 12000); 15900b04680fSAndrew Lunn 15910b04680fSAndrew Lunn val = phy_read(phydev, MII_88E1121_MISC_TEST); 15920b04680fSAndrew Lunn if (val < 0) { 15930b04680fSAndrew Lunn ret = val; 15940b04680fSAndrew Lunn goto error; 15950b04680fSAndrew Lunn } 15960b04680fSAndrew Lunn 15970b04680fSAndrew Lunn /* Disable temperature sensor */ 15980b04680fSAndrew Lunn ret = phy_write(phydev, MII_88E1121_MISC_TEST, 15990b04680fSAndrew Lunn ret & ~MII_88E1121_MISC_TEST_TEMP_SENSOR_EN); 16000b04680fSAndrew Lunn if (ret < 0) 16010b04680fSAndrew Lunn goto error; 16020b04680fSAndrew Lunn 16030b04680fSAndrew Lunn *temp = ((val & MII_88E1121_MISC_TEST_TEMP_MASK) - 5) * 5000; 16040b04680fSAndrew Lunn 16050b04680fSAndrew Lunn error: 1606975b388cSAndrew Lunn marvell_set_page(phydev, oldpage); 16070b04680fSAndrew Lunn mutex_unlock(&phydev->lock); 16080b04680fSAndrew Lunn 16090b04680fSAndrew Lunn return ret; 16100b04680fSAndrew Lunn } 16110b04680fSAndrew Lunn 16120b04680fSAndrew Lunn static int m88e1121_hwmon_read(struct device *dev, 16130b04680fSAndrew Lunn enum hwmon_sensor_types type, 16140b04680fSAndrew Lunn u32 attr, int channel, long *temp) 16150b04680fSAndrew Lunn { 16160b04680fSAndrew Lunn struct phy_device *phydev = dev_get_drvdata(dev); 16170b04680fSAndrew Lunn int err; 16180b04680fSAndrew Lunn 16190b04680fSAndrew Lunn switch (attr) { 16200b04680fSAndrew Lunn case hwmon_temp_input: 16210b04680fSAndrew Lunn err = m88e1121_get_temp(phydev, temp); 16220b04680fSAndrew Lunn break; 16230b04680fSAndrew Lunn default: 16240b04680fSAndrew Lunn return -EOPNOTSUPP; 16250b04680fSAndrew Lunn } 16260b04680fSAndrew Lunn 16270b04680fSAndrew Lunn return err; 16280b04680fSAndrew Lunn } 16290b04680fSAndrew Lunn 16300b04680fSAndrew Lunn static umode_t m88e1121_hwmon_is_visible(const void *data, 16310b04680fSAndrew Lunn enum hwmon_sensor_types type, 16320b04680fSAndrew Lunn u32 attr, int channel) 16330b04680fSAndrew Lunn { 16340b04680fSAndrew Lunn if (type != hwmon_temp) 16350b04680fSAndrew Lunn return 0; 16360b04680fSAndrew Lunn 16370b04680fSAndrew Lunn switch (attr) { 16380b04680fSAndrew Lunn case hwmon_temp_input: 16390b04680fSAndrew Lunn return 0444; 16400b04680fSAndrew Lunn default: 16410b04680fSAndrew Lunn return 0; 16420b04680fSAndrew Lunn } 16430b04680fSAndrew Lunn } 16440b04680fSAndrew Lunn 16450b04680fSAndrew Lunn static u32 m88e1121_hwmon_chip_config[] = { 16460b04680fSAndrew Lunn HWMON_C_REGISTER_TZ, 16470b04680fSAndrew Lunn 0 16480b04680fSAndrew Lunn }; 16490b04680fSAndrew Lunn 16500b04680fSAndrew Lunn static const struct hwmon_channel_info m88e1121_hwmon_chip = { 16510b04680fSAndrew Lunn .type = hwmon_chip, 16520b04680fSAndrew Lunn .config = m88e1121_hwmon_chip_config, 16530b04680fSAndrew Lunn }; 16540b04680fSAndrew Lunn 16550b04680fSAndrew Lunn static u32 m88e1121_hwmon_temp_config[] = { 16560b04680fSAndrew Lunn HWMON_T_INPUT, 16570b04680fSAndrew Lunn 0 16580b04680fSAndrew Lunn }; 16590b04680fSAndrew Lunn 16600b04680fSAndrew Lunn static const struct hwmon_channel_info m88e1121_hwmon_temp = { 16610b04680fSAndrew Lunn .type = hwmon_temp, 16620b04680fSAndrew Lunn .config = m88e1121_hwmon_temp_config, 16630b04680fSAndrew Lunn }; 16640b04680fSAndrew Lunn 16650b04680fSAndrew Lunn static const struct hwmon_channel_info *m88e1121_hwmon_info[] = { 16660b04680fSAndrew Lunn &m88e1121_hwmon_chip, 16670b04680fSAndrew Lunn &m88e1121_hwmon_temp, 16680b04680fSAndrew Lunn NULL 16690b04680fSAndrew Lunn }; 16700b04680fSAndrew Lunn 16710b04680fSAndrew Lunn static const struct hwmon_ops m88e1121_hwmon_hwmon_ops = { 16720b04680fSAndrew Lunn .is_visible = m88e1121_hwmon_is_visible, 16730b04680fSAndrew Lunn .read = m88e1121_hwmon_read, 16740b04680fSAndrew Lunn }; 16750b04680fSAndrew Lunn 16760b04680fSAndrew Lunn static const struct hwmon_chip_info m88e1121_hwmon_chip_info = { 16770b04680fSAndrew Lunn .ops = &m88e1121_hwmon_hwmon_ops, 16780b04680fSAndrew Lunn .info = m88e1121_hwmon_info, 16790b04680fSAndrew Lunn }; 16800b04680fSAndrew Lunn 16810b04680fSAndrew Lunn static int m88e1510_get_temp(struct phy_device *phydev, long *temp) 16820b04680fSAndrew Lunn { 1683975b388cSAndrew Lunn int oldpage; 16840b04680fSAndrew Lunn int ret; 16850b04680fSAndrew Lunn 16860b04680fSAndrew Lunn *temp = 0; 16870b04680fSAndrew Lunn 16880b04680fSAndrew Lunn mutex_lock(&phydev->lock); 16890b04680fSAndrew Lunn 169052295666SAndrew Lunn oldpage = marvell_get_set_page(phydev, MII_MARVELL_MISC_TEST_PAGE); 1691975b388cSAndrew Lunn if (oldpage < 0) { 1692975b388cSAndrew Lunn mutex_unlock(&phydev->lock); 1693975b388cSAndrew Lunn return oldpage; 1694975b388cSAndrew Lunn } 1695975b388cSAndrew Lunn 16960b04680fSAndrew Lunn ret = phy_read(phydev, MII_88E1510_TEMP_SENSOR); 16970b04680fSAndrew Lunn if (ret < 0) 16980b04680fSAndrew Lunn goto error; 16990b04680fSAndrew Lunn 17000b04680fSAndrew Lunn *temp = ((ret & MII_88E1510_TEMP_SENSOR_MASK) - 25) * 1000; 17010b04680fSAndrew Lunn 17020b04680fSAndrew Lunn error: 1703975b388cSAndrew Lunn marvell_set_page(phydev, oldpage); 17040b04680fSAndrew Lunn mutex_unlock(&phydev->lock); 17050b04680fSAndrew Lunn 17060b04680fSAndrew Lunn return ret; 17070b04680fSAndrew Lunn } 17080b04680fSAndrew Lunn 1709f0a45816SColin Ian King static int m88e1510_get_temp_critical(struct phy_device *phydev, long *temp) 17100b04680fSAndrew Lunn { 1711975b388cSAndrew Lunn int oldpage; 17120b04680fSAndrew Lunn int ret; 17130b04680fSAndrew Lunn 17140b04680fSAndrew Lunn *temp = 0; 17150b04680fSAndrew Lunn 17160b04680fSAndrew Lunn mutex_lock(&phydev->lock); 171753798328SAndrew Lunn 171852295666SAndrew Lunn oldpage = marvell_get_set_page(phydev, MII_MARVELL_MISC_TEST_PAGE); 1719975b388cSAndrew Lunn if (oldpage < 0) { 1720975b388cSAndrew Lunn mutex_unlock(&phydev->lock); 1721975b388cSAndrew Lunn return oldpage; 1722975b388cSAndrew Lunn } 17230b04680fSAndrew Lunn 17240b04680fSAndrew Lunn ret = phy_read(phydev, MII_88E1121_MISC_TEST); 17250b04680fSAndrew Lunn if (ret < 0) 17260b04680fSAndrew Lunn goto error; 17270b04680fSAndrew Lunn 17280b04680fSAndrew Lunn *temp = (((ret & MII_88E1510_MISC_TEST_TEMP_THRESHOLD_MASK) >> 17290b04680fSAndrew Lunn MII_88E1510_MISC_TEST_TEMP_THRESHOLD_SHIFT) * 5) - 25; 17300b04680fSAndrew Lunn /* convert to mC */ 17310b04680fSAndrew Lunn *temp *= 1000; 17320b04680fSAndrew Lunn 17330b04680fSAndrew Lunn error: 1734975b388cSAndrew Lunn marvell_set_page(phydev, oldpage); 17350b04680fSAndrew Lunn mutex_unlock(&phydev->lock); 17360b04680fSAndrew Lunn 17370b04680fSAndrew Lunn return ret; 17380b04680fSAndrew Lunn } 17390b04680fSAndrew Lunn 1740f0a45816SColin Ian King static int m88e1510_set_temp_critical(struct phy_device *phydev, long temp) 17410b04680fSAndrew Lunn { 1742975b388cSAndrew Lunn int oldpage; 17430b04680fSAndrew Lunn int ret; 17440b04680fSAndrew Lunn 17450b04680fSAndrew Lunn mutex_lock(&phydev->lock); 17460b04680fSAndrew Lunn 174752295666SAndrew Lunn oldpage = marvell_get_set_page(phydev, MII_MARVELL_MISC_TEST_PAGE); 1748975b388cSAndrew Lunn if (oldpage < 0) { 1749975b388cSAndrew Lunn mutex_unlock(&phydev->lock); 1750975b388cSAndrew Lunn return oldpage; 1751975b388cSAndrew Lunn } 1752975b388cSAndrew Lunn 17530b04680fSAndrew Lunn ret = phy_read(phydev, MII_88E1121_MISC_TEST); 17540b04680fSAndrew Lunn if (ret < 0) 17550b04680fSAndrew Lunn goto error; 17560b04680fSAndrew Lunn 17570b04680fSAndrew Lunn temp = temp / 1000; 17580b04680fSAndrew Lunn temp = clamp_val(DIV_ROUND_CLOSEST(temp, 5) + 5, 0, 0x1f); 17590b04680fSAndrew Lunn ret = phy_write(phydev, MII_88E1121_MISC_TEST, 17600b04680fSAndrew Lunn (ret & ~MII_88E1510_MISC_TEST_TEMP_THRESHOLD_MASK) | 17610b04680fSAndrew Lunn (temp << MII_88E1510_MISC_TEST_TEMP_THRESHOLD_SHIFT)); 17620b04680fSAndrew Lunn 17630b04680fSAndrew Lunn error: 1764975b388cSAndrew Lunn marvell_set_page(phydev, oldpage); 17650b04680fSAndrew Lunn mutex_unlock(&phydev->lock); 17660b04680fSAndrew Lunn 17670b04680fSAndrew Lunn return ret; 17680b04680fSAndrew Lunn } 17690b04680fSAndrew Lunn 1770f0a45816SColin Ian King static int m88e1510_get_temp_alarm(struct phy_device *phydev, long *alarm) 17710b04680fSAndrew Lunn { 1772975b388cSAndrew Lunn int oldpage; 17730b04680fSAndrew Lunn int ret; 17740b04680fSAndrew Lunn 17750b04680fSAndrew Lunn *alarm = false; 17760b04680fSAndrew Lunn 17770b04680fSAndrew Lunn mutex_lock(&phydev->lock); 17780b04680fSAndrew Lunn 177952295666SAndrew Lunn oldpage = marvell_get_set_page(phydev, MII_MARVELL_MISC_TEST_PAGE); 1780975b388cSAndrew Lunn if (oldpage < 0) { 1781975b388cSAndrew Lunn mutex_unlock(&phydev->lock); 1782975b388cSAndrew Lunn return oldpage; 1783975b388cSAndrew Lunn } 1784975b388cSAndrew Lunn 17850b04680fSAndrew Lunn ret = phy_read(phydev, MII_88E1121_MISC_TEST); 17860b04680fSAndrew Lunn if (ret < 0) 17870b04680fSAndrew Lunn goto error; 17880b04680fSAndrew Lunn *alarm = !!(ret & MII_88E1510_MISC_TEST_TEMP_IRQ); 17890b04680fSAndrew Lunn 17900b04680fSAndrew Lunn error: 1791975b388cSAndrew Lunn marvell_set_page(phydev, oldpage); 17920b04680fSAndrew Lunn mutex_unlock(&phydev->lock); 17930b04680fSAndrew Lunn 17940b04680fSAndrew Lunn return ret; 17950b04680fSAndrew Lunn } 17960b04680fSAndrew Lunn 17970b04680fSAndrew Lunn static int m88e1510_hwmon_read(struct device *dev, 17980b04680fSAndrew Lunn enum hwmon_sensor_types type, 17990b04680fSAndrew Lunn u32 attr, int channel, long *temp) 18000b04680fSAndrew Lunn { 18010b04680fSAndrew Lunn struct phy_device *phydev = dev_get_drvdata(dev); 18020b04680fSAndrew Lunn int err; 18030b04680fSAndrew Lunn 18040b04680fSAndrew Lunn switch (attr) { 18050b04680fSAndrew Lunn case hwmon_temp_input: 18060b04680fSAndrew Lunn err = m88e1510_get_temp(phydev, temp); 18070b04680fSAndrew Lunn break; 18080b04680fSAndrew Lunn case hwmon_temp_crit: 18090b04680fSAndrew Lunn err = m88e1510_get_temp_critical(phydev, temp); 18100b04680fSAndrew Lunn break; 18110b04680fSAndrew Lunn case hwmon_temp_max_alarm: 18120b04680fSAndrew Lunn err = m88e1510_get_temp_alarm(phydev, temp); 18130b04680fSAndrew Lunn break; 18140b04680fSAndrew Lunn default: 18150b04680fSAndrew Lunn return -EOPNOTSUPP; 18160b04680fSAndrew Lunn } 18170b04680fSAndrew Lunn 18180b04680fSAndrew Lunn return err; 18190b04680fSAndrew Lunn } 18200b04680fSAndrew Lunn 18210b04680fSAndrew Lunn static int m88e1510_hwmon_write(struct device *dev, 18220b04680fSAndrew Lunn enum hwmon_sensor_types type, 18230b04680fSAndrew Lunn u32 attr, int channel, long temp) 18240b04680fSAndrew Lunn { 18250b04680fSAndrew Lunn struct phy_device *phydev = dev_get_drvdata(dev); 18260b04680fSAndrew Lunn int err; 18270b04680fSAndrew Lunn 18280b04680fSAndrew Lunn switch (attr) { 18290b04680fSAndrew Lunn case hwmon_temp_crit: 18300b04680fSAndrew Lunn err = m88e1510_set_temp_critical(phydev, temp); 18310b04680fSAndrew Lunn break; 18320b04680fSAndrew Lunn default: 18330b04680fSAndrew Lunn return -EOPNOTSUPP; 18340b04680fSAndrew Lunn } 18350b04680fSAndrew Lunn return err; 18360b04680fSAndrew Lunn } 18370b04680fSAndrew Lunn 18380b04680fSAndrew Lunn static umode_t m88e1510_hwmon_is_visible(const void *data, 18390b04680fSAndrew Lunn enum hwmon_sensor_types type, 18400b04680fSAndrew Lunn u32 attr, int channel) 18410b04680fSAndrew Lunn { 18420b04680fSAndrew Lunn if (type != hwmon_temp) 18430b04680fSAndrew Lunn return 0; 18440b04680fSAndrew Lunn 18450b04680fSAndrew Lunn switch (attr) { 18460b04680fSAndrew Lunn case hwmon_temp_input: 18470b04680fSAndrew Lunn case hwmon_temp_max_alarm: 18480b04680fSAndrew Lunn return 0444; 18490b04680fSAndrew Lunn case hwmon_temp_crit: 18500b04680fSAndrew Lunn return 0644; 18510b04680fSAndrew Lunn default: 18520b04680fSAndrew Lunn return 0; 18530b04680fSAndrew Lunn } 18540b04680fSAndrew Lunn } 18550b04680fSAndrew Lunn 18560b04680fSAndrew Lunn static u32 m88e1510_hwmon_temp_config[] = { 18570b04680fSAndrew Lunn HWMON_T_INPUT | HWMON_T_CRIT | HWMON_T_MAX_ALARM, 18580b04680fSAndrew Lunn 0 18590b04680fSAndrew Lunn }; 18600b04680fSAndrew Lunn 18610b04680fSAndrew Lunn static const struct hwmon_channel_info m88e1510_hwmon_temp = { 18620b04680fSAndrew Lunn .type = hwmon_temp, 18630b04680fSAndrew Lunn .config = m88e1510_hwmon_temp_config, 18640b04680fSAndrew Lunn }; 18650b04680fSAndrew Lunn 18660b04680fSAndrew Lunn static const struct hwmon_channel_info *m88e1510_hwmon_info[] = { 18670b04680fSAndrew Lunn &m88e1121_hwmon_chip, 18680b04680fSAndrew Lunn &m88e1510_hwmon_temp, 18690b04680fSAndrew Lunn NULL 18700b04680fSAndrew Lunn }; 18710b04680fSAndrew Lunn 18720b04680fSAndrew Lunn static const struct hwmon_ops m88e1510_hwmon_hwmon_ops = { 18730b04680fSAndrew Lunn .is_visible = m88e1510_hwmon_is_visible, 18740b04680fSAndrew Lunn .read = m88e1510_hwmon_read, 18750b04680fSAndrew Lunn .write = m88e1510_hwmon_write, 18760b04680fSAndrew Lunn }; 18770b04680fSAndrew Lunn 18780b04680fSAndrew Lunn static const struct hwmon_chip_info m88e1510_hwmon_chip_info = { 18790b04680fSAndrew Lunn .ops = &m88e1510_hwmon_hwmon_ops, 18800b04680fSAndrew Lunn .info = m88e1510_hwmon_info, 18810b04680fSAndrew Lunn }; 18820b04680fSAndrew Lunn 18830b04680fSAndrew Lunn static int marvell_hwmon_name(struct phy_device *phydev) 18840b04680fSAndrew Lunn { 18850b04680fSAndrew Lunn struct marvell_priv *priv = phydev->priv; 18860b04680fSAndrew Lunn struct device *dev = &phydev->mdio.dev; 18870b04680fSAndrew Lunn const char *devname = dev_name(dev); 18880b04680fSAndrew Lunn size_t len = strlen(devname); 18890b04680fSAndrew Lunn int i, j; 18900b04680fSAndrew Lunn 18910b04680fSAndrew Lunn priv->hwmon_name = devm_kzalloc(dev, len, GFP_KERNEL); 18920b04680fSAndrew Lunn if (!priv->hwmon_name) 18930b04680fSAndrew Lunn return -ENOMEM; 18940b04680fSAndrew Lunn 18950b04680fSAndrew Lunn for (i = j = 0; i < len && devname[i]; i++) { 18960b04680fSAndrew Lunn if (isalnum(devname[i])) 18970b04680fSAndrew Lunn priv->hwmon_name[j++] = devname[i]; 18980b04680fSAndrew Lunn } 18990b04680fSAndrew Lunn 19000b04680fSAndrew Lunn return 0; 19010b04680fSAndrew Lunn } 19020b04680fSAndrew Lunn 19030b04680fSAndrew Lunn static int marvell_hwmon_probe(struct phy_device *phydev, 19040b04680fSAndrew Lunn const struct hwmon_chip_info *chip) 19050b04680fSAndrew Lunn { 19060b04680fSAndrew Lunn struct marvell_priv *priv = phydev->priv; 19070b04680fSAndrew Lunn struct device *dev = &phydev->mdio.dev; 19080b04680fSAndrew Lunn int err; 19090b04680fSAndrew Lunn 19100b04680fSAndrew Lunn err = marvell_hwmon_name(phydev); 19110b04680fSAndrew Lunn if (err) 19120b04680fSAndrew Lunn return err; 19130b04680fSAndrew Lunn 19140b04680fSAndrew Lunn priv->hwmon_dev = devm_hwmon_device_register_with_info( 19150b04680fSAndrew Lunn dev, priv->hwmon_name, phydev, chip, NULL); 19160b04680fSAndrew Lunn 19170b04680fSAndrew Lunn return PTR_ERR_OR_ZERO(priv->hwmon_dev); 19180b04680fSAndrew Lunn } 19190b04680fSAndrew Lunn 19200b04680fSAndrew Lunn static int m88e1121_hwmon_probe(struct phy_device *phydev) 19210b04680fSAndrew Lunn { 19220b04680fSAndrew Lunn return marvell_hwmon_probe(phydev, &m88e1121_hwmon_chip_info); 19230b04680fSAndrew Lunn } 19240b04680fSAndrew Lunn 19250b04680fSAndrew Lunn static int m88e1510_hwmon_probe(struct phy_device *phydev) 19260b04680fSAndrew Lunn { 19270b04680fSAndrew Lunn return marvell_hwmon_probe(phydev, &m88e1510_hwmon_chip_info); 19280b04680fSAndrew Lunn } 19290b04680fSAndrew Lunn #else 19300b04680fSAndrew Lunn static int m88e1121_hwmon_probe(struct phy_device *phydev) 19310b04680fSAndrew Lunn { 19320b04680fSAndrew Lunn return 0; 19330b04680fSAndrew Lunn } 19340b04680fSAndrew Lunn 19350b04680fSAndrew Lunn static int m88e1510_hwmon_probe(struct phy_device *phydev) 19360b04680fSAndrew Lunn { 19370b04680fSAndrew Lunn return 0; 19380b04680fSAndrew Lunn } 19390b04680fSAndrew Lunn #endif 19400b04680fSAndrew Lunn 1941d2fa47d9SAndrew Lunn static int marvell_probe(struct phy_device *phydev) 1942d2fa47d9SAndrew Lunn { 1943d2fa47d9SAndrew Lunn struct marvell_priv *priv; 1944d2fa47d9SAndrew Lunn 1945e5a03bfdSAndrew Lunn priv = devm_kzalloc(&phydev->mdio.dev, sizeof(*priv), GFP_KERNEL); 1946d2fa47d9SAndrew Lunn if (!priv) 1947d2fa47d9SAndrew Lunn return -ENOMEM; 1948d2fa47d9SAndrew Lunn 1949d2fa47d9SAndrew Lunn phydev->priv = priv; 1950d2fa47d9SAndrew Lunn 1951d2fa47d9SAndrew Lunn return 0; 1952d2fa47d9SAndrew Lunn } 1953d2fa47d9SAndrew Lunn 19540b04680fSAndrew Lunn static int m88e1121_probe(struct phy_device *phydev) 19550b04680fSAndrew Lunn { 19560b04680fSAndrew Lunn int err; 19570b04680fSAndrew Lunn 19580b04680fSAndrew Lunn err = marvell_probe(phydev); 19590b04680fSAndrew Lunn if (err) 19600b04680fSAndrew Lunn return err; 19610b04680fSAndrew Lunn 19620b04680fSAndrew Lunn return m88e1121_hwmon_probe(phydev); 19630b04680fSAndrew Lunn } 19640b04680fSAndrew Lunn 19650b04680fSAndrew Lunn static int m88e1510_probe(struct phy_device *phydev) 19660b04680fSAndrew Lunn { 19670b04680fSAndrew Lunn int err; 19680b04680fSAndrew Lunn 19690b04680fSAndrew Lunn err = marvell_probe(phydev); 19700b04680fSAndrew Lunn if (err) 19710b04680fSAndrew Lunn return err; 19720b04680fSAndrew Lunn 19730b04680fSAndrew Lunn return m88e1510_hwmon_probe(phydev); 19740b04680fSAndrew Lunn } 19750b04680fSAndrew Lunn 1976e5479239SOlof Johansson static struct phy_driver marvell_drivers[] = { 1977e5479239SOlof Johansson { 19782f495c39SBenjamin Herrenschmidt .phy_id = MARVELL_PHY_ID_88E1101, 19792f495c39SBenjamin Herrenschmidt .phy_id_mask = MARVELL_PHY_ID_MASK, 198000db8189SAndy Fleming .name = "Marvell 88E1101", 198100db8189SAndy Fleming .features = PHY_GBIT_FEATURES, 198200db8189SAndy Fleming .flags = PHY_HAS_INTERRUPT, 198318702414SArnd Bergmann .probe = marvell_probe, 198479be1a1cSClemens Gruber .config_init = &marvell_config_init, 1985f2899788SAndrew Lunn .config_aneg = &m88e1101_config_aneg, 198600db8189SAndy Fleming .read_status = &genphy_read_status, 198700db8189SAndy Fleming .ack_interrupt = &marvell_ack_interrupt, 198800db8189SAndy Fleming .config_intr = &marvell_config_intr, 19890898b448SSebastian Hesselbarth .resume = &genphy_resume, 19900898b448SSebastian Hesselbarth .suspend = &genphy_suspend, 1991d2fa47d9SAndrew Lunn .get_sset_count = marvell_get_sset_count, 1992d2fa47d9SAndrew Lunn .get_strings = marvell_get_strings, 1993d2fa47d9SAndrew Lunn .get_stats = marvell_get_stats, 1994e5479239SOlof Johansson }, 1995e5479239SOlof Johansson { 19962f495c39SBenjamin Herrenschmidt .phy_id = MARVELL_PHY_ID_88E1112, 19972f495c39SBenjamin Herrenschmidt .phy_id_mask = MARVELL_PHY_ID_MASK, 199885cfb534SOlof Johansson .name = "Marvell 88E1112", 199985cfb534SOlof Johansson .features = PHY_GBIT_FEATURES, 200085cfb534SOlof Johansson .flags = PHY_HAS_INTERRUPT, 2001d2fa47d9SAndrew Lunn .probe = marvell_probe, 200285cfb534SOlof Johansson .config_init = &m88e1111_config_init, 200385cfb534SOlof Johansson .config_aneg = &marvell_config_aneg, 200485cfb534SOlof Johansson .read_status = &genphy_read_status, 200585cfb534SOlof Johansson .ack_interrupt = &marvell_ack_interrupt, 200685cfb534SOlof Johansson .config_intr = &marvell_config_intr, 20070898b448SSebastian Hesselbarth .resume = &genphy_resume, 20080898b448SSebastian Hesselbarth .suspend = &genphy_suspend, 2009d2fa47d9SAndrew Lunn .get_sset_count = marvell_get_sset_count, 2010d2fa47d9SAndrew Lunn .get_strings = marvell_get_strings, 2011d2fa47d9SAndrew Lunn .get_stats = marvell_get_stats, 201285cfb534SOlof Johansson }, 201385cfb534SOlof Johansson { 20142f495c39SBenjamin Herrenschmidt .phy_id = MARVELL_PHY_ID_88E1111, 20152f495c39SBenjamin Herrenschmidt .phy_id_mask = MARVELL_PHY_ID_MASK, 201676884679SAndy Fleming .name = "Marvell 88E1111", 201776884679SAndy Fleming .features = PHY_GBIT_FEATURES, 201876884679SAndy Fleming .flags = PHY_HAS_INTERRUPT, 2019d2fa47d9SAndrew Lunn .probe = marvell_probe, 2020e5479239SOlof Johansson .config_init = &m88e1111_config_init, 20213ec0a0f1SHarini Katakam .config_aneg = &m88e1111_config_aneg, 2022be937f1fSAlexandr Smirnov .read_status = &marvell_read_status, 202376884679SAndy Fleming .ack_interrupt = &marvell_ack_interrupt, 202476884679SAndy Fleming .config_intr = &marvell_config_intr, 20250898b448SSebastian Hesselbarth .resume = &genphy_resume, 20260898b448SSebastian Hesselbarth .suspend = &genphy_suspend, 2027d2fa47d9SAndrew Lunn .get_sset_count = marvell_get_sset_count, 2028d2fa47d9SAndrew Lunn .get_strings = marvell_get_strings, 2029d2fa47d9SAndrew Lunn .get_stats = marvell_get_stats, 2030e5479239SOlof Johansson }, 2031e5479239SOlof Johansson { 20322f495c39SBenjamin Herrenschmidt .phy_id = MARVELL_PHY_ID_88E1118, 20332f495c39SBenjamin Herrenschmidt .phy_id_mask = MARVELL_PHY_ID_MASK, 2034605f196eSRon Madrid .name = "Marvell 88E1118", 2035605f196eSRon Madrid .features = PHY_GBIT_FEATURES, 2036605f196eSRon Madrid .flags = PHY_HAS_INTERRUPT, 2037d2fa47d9SAndrew Lunn .probe = marvell_probe, 2038605f196eSRon Madrid .config_init = &m88e1118_config_init, 2039605f196eSRon Madrid .config_aneg = &m88e1118_config_aneg, 2040605f196eSRon Madrid .read_status = &genphy_read_status, 2041605f196eSRon Madrid .ack_interrupt = &marvell_ack_interrupt, 2042605f196eSRon Madrid .config_intr = &marvell_config_intr, 20430898b448SSebastian Hesselbarth .resume = &genphy_resume, 20440898b448SSebastian Hesselbarth .suspend = &genphy_suspend, 2045d2fa47d9SAndrew Lunn .get_sset_count = marvell_get_sset_count, 2046d2fa47d9SAndrew Lunn .get_strings = marvell_get_strings, 2047d2fa47d9SAndrew Lunn .get_stats = marvell_get_stats, 2048605f196eSRon Madrid }, 2049605f196eSRon Madrid { 20502f495c39SBenjamin Herrenschmidt .phy_id = MARVELL_PHY_ID_88E1121R, 20512f495c39SBenjamin Herrenschmidt .phy_id_mask = MARVELL_PHY_ID_MASK, 2052140bc929SSergei Poselenov .name = "Marvell 88E1121R", 2053140bc929SSergei Poselenov .features = PHY_GBIT_FEATURES, 2054140bc929SSergei Poselenov .flags = PHY_HAS_INTERRUPT, 205518702414SArnd Bergmann .probe = &m88e1121_probe, 2056fdecf36fSClemens Gruber .config_init = &m88e1121_config_init, 2057140bc929SSergei Poselenov .config_aneg = &m88e1121_config_aneg, 2058140bc929SSergei Poselenov .read_status = &marvell_read_status, 2059140bc929SSergei Poselenov .ack_interrupt = &marvell_ack_interrupt, 2060140bc929SSergei Poselenov .config_intr = &marvell_config_intr, 2061dcd07be3SAnatolij Gustschin .did_interrupt = &m88e1121_did_interrupt, 20620898b448SSebastian Hesselbarth .resume = &genphy_resume, 20630898b448SSebastian Hesselbarth .suspend = &genphy_suspend, 2064d2fa47d9SAndrew Lunn .get_sset_count = marvell_get_sset_count, 2065d2fa47d9SAndrew Lunn .get_strings = marvell_get_strings, 2066d2fa47d9SAndrew Lunn .get_stats = marvell_get_stats, 2067140bc929SSergei Poselenov }, 2068140bc929SSergei Poselenov { 2069337ac9d5SCyril Chemparathy .phy_id = MARVELL_PHY_ID_88E1318S, 20706ba74014SLinus Torvalds .phy_id_mask = MARVELL_PHY_ID_MASK, 2071337ac9d5SCyril Chemparathy .name = "Marvell 88E1318S", 20723ff1c259SCyril Chemparathy .features = PHY_GBIT_FEATURES, 20733ff1c259SCyril Chemparathy .flags = PHY_HAS_INTERRUPT, 2074d2fa47d9SAndrew Lunn .probe = marvell_probe, 2075fdecf36fSClemens Gruber .config_init = &m88e1121_config_init, 2076337ac9d5SCyril Chemparathy .config_aneg = &m88e1318_config_aneg, 20773ff1c259SCyril Chemparathy .read_status = &marvell_read_status, 20783ff1c259SCyril Chemparathy .ack_interrupt = &marvell_ack_interrupt, 20793ff1c259SCyril Chemparathy .config_intr = &marvell_config_intr, 20803ff1c259SCyril Chemparathy .did_interrupt = &m88e1121_did_interrupt, 20813871c387SMichael Stapelberg .get_wol = &m88e1318_get_wol, 20823871c387SMichael Stapelberg .set_wol = &m88e1318_set_wol, 20830898b448SSebastian Hesselbarth .resume = &genphy_resume, 20840898b448SSebastian Hesselbarth .suspend = &genphy_suspend, 2085d2fa47d9SAndrew Lunn .get_sset_count = marvell_get_sset_count, 2086d2fa47d9SAndrew Lunn .get_strings = marvell_get_strings, 2087d2fa47d9SAndrew Lunn .get_stats = marvell_get_stats, 20883ff1c259SCyril Chemparathy }, 20893ff1c259SCyril Chemparathy { 20902f495c39SBenjamin Herrenschmidt .phy_id = MARVELL_PHY_ID_88E1145, 20912f495c39SBenjamin Herrenschmidt .phy_id_mask = MARVELL_PHY_ID_MASK, 209276884679SAndy Fleming .name = "Marvell 88E1145", 209376884679SAndy Fleming .features = PHY_GBIT_FEATURES, 209476884679SAndy Fleming .flags = PHY_HAS_INTERRUPT, 2095d2fa47d9SAndrew Lunn .probe = marvell_probe, 209676884679SAndy Fleming .config_init = &m88e1145_config_init, 209776884679SAndy Fleming .config_aneg = &marvell_config_aneg, 209876884679SAndy Fleming .read_status = &genphy_read_status, 209976884679SAndy Fleming .ack_interrupt = &marvell_ack_interrupt, 210076884679SAndy Fleming .config_intr = &marvell_config_intr, 21010898b448SSebastian Hesselbarth .resume = &genphy_resume, 21020898b448SSebastian Hesselbarth .suspend = &genphy_suspend, 2103d2fa47d9SAndrew Lunn .get_sset_count = marvell_get_sset_count, 2104d2fa47d9SAndrew Lunn .get_strings = marvell_get_strings, 2105d2fa47d9SAndrew Lunn .get_stats = marvell_get_stats, 2106ac8c635aSOlof Johansson }, 2107ac8c635aSOlof Johansson { 210890600732SDavid Daney .phy_id = MARVELL_PHY_ID_88E1149R, 210990600732SDavid Daney .phy_id_mask = MARVELL_PHY_ID_MASK, 211090600732SDavid Daney .name = "Marvell 88E1149R", 211190600732SDavid Daney .features = PHY_GBIT_FEATURES, 211290600732SDavid Daney .flags = PHY_HAS_INTERRUPT, 2113d2fa47d9SAndrew Lunn .probe = marvell_probe, 211490600732SDavid Daney .config_init = &m88e1149_config_init, 211590600732SDavid Daney .config_aneg = &m88e1118_config_aneg, 211690600732SDavid Daney .read_status = &genphy_read_status, 211790600732SDavid Daney .ack_interrupt = &marvell_ack_interrupt, 211890600732SDavid Daney .config_intr = &marvell_config_intr, 21190898b448SSebastian Hesselbarth .resume = &genphy_resume, 21200898b448SSebastian Hesselbarth .suspend = &genphy_suspend, 2121d2fa47d9SAndrew Lunn .get_sset_count = marvell_get_sset_count, 2122d2fa47d9SAndrew Lunn .get_strings = marvell_get_strings, 2123d2fa47d9SAndrew Lunn .get_stats = marvell_get_stats, 212490600732SDavid Daney }, 212590600732SDavid Daney { 21262f495c39SBenjamin Herrenschmidt .phy_id = MARVELL_PHY_ID_88E1240, 21272f495c39SBenjamin Herrenschmidt .phy_id_mask = MARVELL_PHY_ID_MASK, 2128ac8c635aSOlof Johansson .name = "Marvell 88E1240", 2129ac8c635aSOlof Johansson .features = PHY_GBIT_FEATURES, 2130ac8c635aSOlof Johansson .flags = PHY_HAS_INTERRUPT, 2131d2fa47d9SAndrew Lunn .probe = marvell_probe, 2132ac8c635aSOlof Johansson .config_init = &m88e1111_config_init, 2133ac8c635aSOlof Johansson .config_aneg = &marvell_config_aneg, 2134ac8c635aSOlof Johansson .read_status = &genphy_read_status, 2135ac8c635aSOlof Johansson .ack_interrupt = &marvell_ack_interrupt, 2136ac8c635aSOlof Johansson .config_intr = &marvell_config_intr, 21370898b448SSebastian Hesselbarth .resume = &genphy_resume, 21380898b448SSebastian Hesselbarth .suspend = &genphy_suspend, 2139d2fa47d9SAndrew Lunn .get_sset_count = marvell_get_sset_count, 2140d2fa47d9SAndrew Lunn .get_strings = marvell_get_strings, 2141d2fa47d9SAndrew Lunn .get_stats = marvell_get_stats, 2142ac8c635aSOlof Johansson }, 21433da09a51SMichal Simek { 21443da09a51SMichal Simek .phy_id = MARVELL_PHY_ID_88E1116R, 21453da09a51SMichal Simek .phy_id_mask = MARVELL_PHY_ID_MASK, 21463da09a51SMichal Simek .name = "Marvell 88E1116R", 21473da09a51SMichal Simek .features = PHY_GBIT_FEATURES, 21483da09a51SMichal Simek .flags = PHY_HAS_INTERRUPT, 2149d2fa47d9SAndrew Lunn .probe = marvell_probe, 21503da09a51SMichal Simek .config_init = &m88e1116r_config_init, 21513da09a51SMichal Simek .config_aneg = &genphy_config_aneg, 21523da09a51SMichal Simek .read_status = &genphy_read_status, 21533da09a51SMichal Simek .ack_interrupt = &marvell_ack_interrupt, 21543da09a51SMichal Simek .config_intr = &marvell_config_intr, 21550898b448SSebastian Hesselbarth .resume = &genphy_resume, 21560898b448SSebastian Hesselbarth .suspend = &genphy_suspend, 2157d2fa47d9SAndrew Lunn .get_sset_count = marvell_get_sset_count, 2158d2fa47d9SAndrew Lunn .get_strings = marvell_get_strings, 2159d2fa47d9SAndrew Lunn .get_stats = marvell_get_stats, 21603da09a51SMichal Simek }, 216110e24caaSMichal Simek { 216210e24caaSMichal Simek .phy_id = MARVELL_PHY_ID_88E1510, 216310e24caaSMichal Simek .phy_id_mask = MARVELL_PHY_ID_MASK, 216410e24caaSMichal Simek .name = "Marvell 88E1510", 21656cfb3bccSCharles-Antoine Couret .features = PHY_GBIT_FEATURES | SUPPORTED_FIBRE, 216618702414SArnd Bergmann .flags = PHY_HAS_INTERRUPT, 21670b04680fSAndrew Lunn .probe = &m88e1510_probe, 2168930b37eeSStefan Roese .config_init = &m88e1510_config_init, 216910e24caaSMichal Simek .config_aneg = &m88e1510_config_aneg, 217010e24caaSMichal Simek .read_status = &marvell_read_status, 217110e24caaSMichal Simek .ack_interrupt = &marvell_ack_interrupt, 217210e24caaSMichal Simek .config_intr = &marvell_config_intr, 217310e24caaSMichal Simek .did_interrupt = &m88e1121_did_interrupt, 2174f39aac7eSJingju Hou .get_wol = &m88e1318_get_wol, 2175f39aac7eSJingju Hou .set_wol = &m88e1318_set_wol, 21763758be3dSCharles-Antoine Couret .resume = &marvell_resume, 21773758be3dSCharles-Antoine Couret .suspend = &marvell_suspend, 2178d2fa47d9SAndrew Lunn .get_sset_count = marvell_get_sset_count, 2179d2fa47d9SAndrew Lunn .get_strings = marvell_get_strings, 2180d2fa47d9SAndrew Lunn .get_stats = marvell_get_stats, 218110e24caaSMichal Simek }, 21826b358aedSSebastian Hesselbarth { 2183819ec8e1SAndrew Lunn .phy_id = MARVELL_PHY_ID_88E1540, 2184819ec8e1SAndrew Lunn .phy_id_mask = MARVELL_PHY_ID_MASK, 2185819ec8e1SAndrew Lunn .name = "Marvell 88E1540", 2186819ec8e1SAndrew Lunn .features = PHY_GBIT_FEATURES, 2187819ec8e1SAndrew Lunn .flags = PHY_HAS_INTERRUPT, 218818702414SArnd Bergmann .probe = m88e1510_probe, 218979be1a1cSClemens Gruber .config_init = &marvell_config_init, 2190819ec8e1SAndrew Lunn .config_aneg = &m88e1510_config_aneg, 2191819ec8e1SAndrew Lunn .read_status = &marvell_read_status, 2192819ec8e1SAndrew Lunn .ack_interrupt = &marvell_ack_interrupt, 2193819ec8e1SAndrew Lunn .config_intr = &marvell_config_intr, 2194819ec8e1SAndrew Lunn .did_interrupt = &m88e1121_did_interrupt, 2195819ec8e1SAndrew Lunn .resume = &genphy_resume, 2196819ec8e1SAndrew Lunn .suspend = &genphy_suspend, 2197d2fa47d9SAndrew Lunn .get_sset_count = marvell_get_sset_count, 2198d2fa47d9SAndrew Lunn .get_strings = marvell_get_strings, 2199d2fa47d9SAndrew Lunn .get_stats = marvell_get_stats, 2200819ec8e1SAndrew Lunn }, 2201819ec8e1SAndrew Lunn { 220260f06fdeSAndrew Lunn .phy_id = MARVELL_PHY_ID_88E1545, 220360f06fdeSAndrew Lunn .phy_id_mask = MARVELL_PHY_ID_MASK, 220460f06fdeSAndrew Lunn .name = "Marvell 88E1545", 220560f06fdeSAndrew Lunn .probe = m88e1510_probe, 220660f06fdeSAndrew Lunn .features = PHY_GBIT_FEATURES, 220760f06fdeSAndrew Lunn .flags = PHY_HAS_INTERRUPT, 220860f06fdeSAndrew Lunn .config_init = &marvell_config_init, 220960f06fdeSAndrew Lunn .config_aneg = &m88e1510_config_aneg, 221060f06fdeSAndrew Lunn .read_status = &marvell_read_status, 221160f06fdeSAndrew Lunn .ack_interrupt = &marvell_ack_interrupt, 221260f06fdeSAndrew Lunn .config_intr = &marvell_config_intr, 221360f06fdeSAndrew Lunn .did_interrupt = &m88e1121_did_interrupt, 221460f06fdeSAndrew Lunn .resume = &genphy_resume, 221560f06fdeSAndrew Lunn .suspend = &genphy_suspend, 221660f06fdeSAndrew Lunn .get_sset_count = marvell_get_sset_count, 221760f06fdeSAndrew Lunn .get_strings = marvell_get_strings, 221860f06fdeSAndrew Lunn .get_stats = marvell_get_stats, 221960f06fdeSAndrew Lunn }, 222060f06fdeSAndrew Lunn { 22216b358aedSSebastian Hesselbarth .phy_id = MARVELL_PHY_ID_88E3016, 22226b358aedSSebastian Hesselbarth .phy_id_mask = MARVELL_PHY_ID_MASK, 22236b358aedSSebastian Hesselbarth .name = "Marvell 88E3016", 22246b358aedSSebastian Hesselbarth .features = PHY_BASIC_FEATURES, 22256b358aedSSebastian Hesselbarth .flags = PHY_HAS_INTERRUPT, 2226d2fa47d9SAndrew Lunn .probe = marvell_probe, 22276b358aedSSebastian Hesselbarth .config_aneg = &genphy_config_aneg, 22286b358aedSSebastian Hesselbarth .config_init = &m88e3016_config_init, 22296b358aedSSebastian Hesselbarth .aneg_done = &marvell_aneg_done, 22306b358aedSSebastian Hesselbarth .read_status = &marvell_read_status, 22316b358aedSSebastian Hesselbarth .ack_interrupt = &marvell_ack_interrupt, 22326b358aedSSebastian Hesselbarth .config_intr = &marvell_config_intr, 22336b358aedSSebastian Hesselbarth .did_interrupt = &m88e1121_did_interrupt, 22346b358aedSSebastian Hesselbarth .resume = &genphy_resume, 22356b358aedSSebastian Hesselbarth .suspend = &genphy_suspend, 2236d2fa47d9SAndrew Lunn .get_sset_count = marvell_get_sset_count, 2237d2fa47d9SAndrew Lunn .get_strings = marvell_get_strings, 2238d2fa47d9SAndrew Lunn .get_stats = marvell_get_stats, 22396b358aedSSebastian Hesselbarth }, 2240e4cf8a38SAndrew Lunn { 2241e4cf8a38SAndrew Lunn .phy_id = MARVELL_PHY_ID_88E6390, 2242e4cf8a38SAndrew Lunn .phy_id_mask = MARVELL_PHY_ID_MASK, 2243e4cf8a38SAndrew Lunn .name = "Marvell 88E6390", 2244e4cf8a38SAndrew Lunn .features = PHY_GBIT_FEATURES, 2245e4cf8a38SAndrew Lunn .flags = PHY_HAS_INTERRUPT, 2246e4cf8a38SAndrew Lunn .probe = m88e1510_probe, 2247e4cf8a38SAndrew Lunn .config_init = &marvell_config_init, 2248e4cf8a38SAndrew Lunn .config_aneg = &m88e1510_config_aneg, 2249e4cf8a38SAndrew Lunn .read_status = &marvell_read_status, 2250e4cf8a38SAndrew Lunn .ack_interrupt = &marvell_ack_interrupt, 2251e4cf8a38SAndrew Lunn .config_intr = &marvell_config_intr, 2252e4cf8a38SAndrew Lunn .did_interrupt = &m88e1121_did_interrupt, 2253e4cf8a38SAndrew Lunn .resume = &genphy_resume, 2254e4cf8a38SAndrew Lunn .suspend = &genphy_suspend, 2255e4cf8a38SAndrew Lunn .get_sset_count = marvell_get_sset_count, 2256e4cf8a38SAndrew Lunn .get_strings = marvell_get_strings, 2257e4cf8a38SAndrew Lunn .get_stats = marvell_get_stats, 2258e4cf8a38SAndrew Lunn }, 225976884679SAndy Fleming }; 226076884679SAndy Fleming 226150fd7150SJohan Hovold module_phy_driver(marvell_drivers); 22624e4f10f6SDavid Woodhouse 2263cf93c945SUwe Kleine-König static struct mdio_device_id __maybe_unused marvell_tbl[] = { 2264f5e1cabfSMichal Simek { MARVELL_PHY_ID_88E1101, MARVELL_PHY_ID_MASK }, 2265f5e1cabfSMichal Simek { MARVELL_PHY_ID_88E1112, MARVELL_PHY_ID_MASK }, 2266f5e1cabfSMichal Simek { MARVELL_PHY_ID_88E1111, MARVELL_PHY_ID_MASK }, 2267f5e1cabfSMichal Simek { MARVELL_PHY_ID_88E1118, MARVELL_PHY_ID_MASK }, 2268f5e1cabfSMichal Simek { MARVELL_PHY_ID_88E1121R, MARVELL_PHY_ID_MASK }, 2269f5e1cabfSMichal Simek { MARVELL_PHY_ID_88E1145, MARVELL_PHY_ID_MASK }, 2270f5e1cabfSMichal Simek { MARVELL_PHY_ID_88E1149R, MARVELL_PHY_ID_MASK }, 2271f5e1cabfSMichal Simek { MARVELL_PHY_ID_88E1240, MARVELL_PHY_ID_MASK }, 2272f5e1cabfSMichal Simek { MARVELL_PHY_ID_88E1318S, MARVELL_PHY_ID_MASK }, 22733da09a51SMichal Simek { MARVELL_PHY_ID_88E1116R, MARVELL_PHY_ID_MASK }, 227410e24caaSMichal Simek { MARVELL_PHY_ID_88E1510, MARVELL_PHY_ID_MASK }, 2275819ec8e1SAndrew Lunn { MARVELL_PHY_ID_88E1540, MARVELL_PHY_ID_MASK }, 227660f06fdeSAndrew Lunn { MARVELL_PHY_ID_88E1545, MARVELL_PHY_ID_MASK }, 22776b358aedSSebastian Hesselbarth { MARVELL_PHY_ID_88E3016, MARVELL_PHY_ID_MASK }, 2278e4cf8a38SAndrew Lunn { MARVELL_PHY_ID_88E6390, MARVELL_PHY_ID_MASK }, 22794e4f10f6SDavid Woodhouse { } 22804e4f10f6SDavid Woodhouse }; 22814e4f10f6SDavid Woodhouse 22824e4f10f6SDavid Woodhouse MODULE_DEVICE_TABLE(mdio, marvell_tbl); 2283