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> 2000db8189SAndy Fleming #include <linux/errno.h> 2100db8189SAndy Fleming #include <linux/unistd.h> 2200db8189SAndy Fleming #include <linux/interrupt.h> 2300db8189SAndy Fleming #include <linux/init.h> 2400db8189SAndy Fleming #include <linux/delay.h> 2500db8189SAndy Fleming #include <linux/netdevice.h> 2600db8189SAndy Fleming #include <linux/etherdevice.h> 2700db8189SAndy Fleming #include <linux/skbuff.h> 2800db8189SAndy Fleming #include <linux/spinlock.h> 2900db8189SAndy Fleming #include <linux/mm.h> 3000db8189SAndy Fleming #include <linux/module.h> 3100db8189SAndy Fleming #include <linux/mii.h> 3200db8189SAndy Fleming #include <linux/ethtool.h> 3300db8189SAndy Fleming #include <linux/phy.h> 342f495c39SBenjamin Herrenschmidt #include <linux/marvell_phy.h> 35cf41a51dSDavid Daney #include <linux/of.h> 3600db8189SAndy Fleming 37eea3b201SAvinash Kumar #include <linux/io.h> 3800db8189SAndy Fleming #include <asm/irq.h> 39eea3b201SAvinash Kumar #include <linux/uaccess.h> 4000db8189SAndy Fleming 4127d916d6SDavid Daney #define MII_MARVELL_PHY_PAGE 22 4227d916d6SDavid Daney 4300db8189SAndy Fleming #define MII_M1011_IEVENT 0x13 4400db8189SAndy Fleming #define MII_M1011_IEVENT_CLEAR 0x0000 4500db8189SAndy Fleming 4600db8189SAndy Fleming #define MII_M1011_IMASK 0x12 4700db8189SAndy Fleming #define MII_M1011_IMASK_INIT 0x6400 4800db8189SAndy Fleming #define MII_M1011_IMASK_CLEAR 0x0000 4900db8189SAndy Fleming 5076884679SAndy Fleming #define MII_M1011_PHY_SCR 0x10 51239aa55bSDavid Thomson #define MII_M1011_PHY_SCR_MDI 0x0000 52239aa55bSDavid Thomson #define MII_M1011_PHY_SCR_MDI_X 0x0020 5376884679SAndy Fleming #define MII_M1011_PHY_SCR_AUTO_CROSS 0x0060 5476884679SAndy Fleming 5507151bc9SMadalin Bucur #define MII_M1145_PHY_EXT_ADDR_PAGE 0x16 56b0224175SViet Nga Dao #define MII_M1145_PHY_EXT_SR 0x1b 5776884679SAndy Fleming #define MII_M1145_PHY_EXT_CR 0x14 5876884679SAndy Fleming #define MII_M1145_RGMII_RX_DELAY 0x0080 5976884679SAndy Fleming #define MII_M1145_RGMII_TX_DELAY 0x0002 60b0224175SViet Nga Dao #define MII_M1145_HWCFG_MODE_SGMII_NO_CLK 0x4 61b0224175SViet Nga Dao #define MII_M1145_HWCFG_MODE_MASK 0xf 62b0224175SViet Nga Dao #define MII_M1145_HWCFG_FIBER_COPPER_AUTO 0x8000 6376884679SAndy Fleming 6499d881f9SVince Bridgers #define MII_M1145_HWCFG_MODE_SGMII_NO_CLK 0x4 6599d881f9SVince Bridgers #define MII_M1145_HWCFG_MODE_MASK 0xf 6699d881f9SVince Bridgers #define MII_M1145_HWCFG_FIBER_COPPER_AUTO 0x8000 6799d881f9SVince Bridgers 6876884679SAndy Fleming #define MII_M1111_PHY_LED_CONTROL 0x18 6976884679SAndy Fleming #define MII_M1111_PHY_LED_DIRECT 0x4100 7076884679SAndy Fleming #define MII_M1111_PHY_LED_COMBINE 0x411c 71895ee682SKim Phillips #define MII_M1111_PHY_EXT_CR 0x14 72895ee682SKim Phillips #define MII_M1111_RX_DELAY 0x80 73895ee682SKim Phillips #define MII_M1111_TX_DELAY 0x2 74895ee682SKim Phillips #define MII_M1111_PHY_EXT_SR 0x1b 75be937f1fSAlexandr Smirnov 76895ee682SKim Phillips #define MII_M1111_HWCFG_MODE_MASK 0xf 77be937f1fSAlexandr Smirnov #define MII_M1111_HWCFG_MODE_COPPER_RGMII 0xb 78be937f1fSAlexandr Smirnov #define MII_M1111_HWCFG_MODE_FIBER_RGMII 0x3 794117b5beSKapil Juneja #define MII_M1111_HWCFG_MODE_SGMII_NO_CLK 0x4 805f8cbc13SLiu Yu-B13201 #define MII_M1111_HWCFG_MODE_COPPER_RTBI 0x9 81be937f1fSAlexandr Smirnov #define MII_M1111_HWCFG_FIBER_COPPER_AUTO 0x8000 82be937f1fSAlexandr Smirnov #define MII_M1111_HWCFG_FIBER_COPPER_RES 0x2000 83be937f1fSAlexandr Smirnov 84be937f1fSAlexandr Smirnov #define MII_M1111_COPPER 0 85be937f1fSAlexandr Smirnov #define MII_M1111_FIBER 1 86be937f1fSAlexandr Smirnov 87c477d044SCyril Chemparathy #define MII_88E1121_PHY_MSCR_PAGE 2 88c477d044SCyril Chemparathy #define MII_88E1121_PHY_MSCR_REG 21 89c477d044SCyril Chemparathy #define MII_88E1121_PHY_MSCR_RX_DELAY BIT(5) 90c477d044SCyril Chemparathy #define MII_88E1121_PHY_MSCR_TX_DELAY BIT(4) 91c477d044SCyril Chemparathy #define MII_88E1121_PHY_MSCR_DELAY_MASK (~(0x3 << 4)) 92c477d044SCyril Chemparathy 93337ac9d5SCyril Chemparathy #define MII_88E1318S_PHY_MSCR1_REG 16 94337ac9d5SCyril Chemparathy #define MII_88E1318S_PHY_MSCR1_PAD_ODD BIT(6) 953ff1c259SCyril Chemparathy 963871c387SMichael Stapelberg /* Copper Specific Interrupt Enable Register */ 973871c387SMichael Stapelberg #define MII_88E1318S_PHY_CSIER 0x12 983871c387SMichael Stapelberg /* WOL Event Interrupt Enable */ 993871c387SMichael Stapelberg #define MII_88E1318S_PHY_CSIER_WOL_EIE BIT(7) 1003871c387SMichael Stapelberg 1013871c387SMichael Stapelberg /* LED Timer Control Register */ 1023871c387SMichael Stapelberg #define MII_88E1318S_PHY_LED_PAGE 0x03 1033871c387SMichael Stapelberg #define MII_88E1318S_PHY_LED_TCR 0x12 1043871c387SMichael Stapelberg #define MII_88E1318S_PHY_LED_TCR_FORCE_INT BIT(15) 1053871c387SMichael Stapelberg #define MII_88E1318S_PHY_LED_TCR_INTn_ENABLE BIT(7) 1063871c387SMichael Stapelberg #define MII_88E1318S_PHY_LED_TCR_INT_ACTIVE_LOW BIT(11) 1073871c387SMichael Stapelberg 1083871c387SMichael Stapelberg /* Magic Packet MAC address registers */ 1093871c387SMichael Stapelberg #define MII_88E1318S_PHY_MAGIC_PACKET_WORD2 0x17 1103871c387SMichael Stapelberg #define MII_88E1318S_PHY_MAGIC_PACKET_WORD1 0x18 1113871c387SMichael Stapelberg #define MII_88E1318S_PHY_MAGIC_PACKET_WORD0 0x19 1123871c387SMichael Stapelberg 1133871c387SMichael Stapelberg #define MII_88E1318S_PHY_WOL_PAGE 0x11 1143871c387SMichael Stapelberg #define MII_88E1318S_PHY_WOL_CTRL 0x10 1153871c387SMichael Stapelberg #define MII_88E1318S_PHY_WOL_CTRL_CLEAR_WOL_STATUS BIT(12) 1163871c387SMichael Stapelberg #define MII_88E1318S_PHY_WOL_CTRL_MAGIC_PACKET_MATCH_ENABLE BIT(14) 1173871c387SMichael Stapelberg 118140bc929SSergei Poselenov #define MII_88E1121_PHY_LED_CTRL 16 119140bc929SSergei Poselenov #define MII_88E1121_PHY_LED_PAGE 3 120140bc929SSergei Poselenov #define MII_88E1121_PHY_LED_DEF 0x0030 121140bc929SSergei Poselenov 122be937f1fSAlexandr Smirnov #define MII_M1011_PHY_STATUS 0x11 123be937f1fSAlexandr Smirnov #define MII_M1011_PHY_STATUS_1000 0x8000 124be937f1fSAlexandr Smirnov #define MII_M1011_PHY_STATUS_100 0x4000 125be937f1fSAlexandr Smirnov #define MII_M1011_PHY_STATUS_SPD_MASK 0xc000 126be937f1fSAlexandr Smirnov #define MII_M1011_PHY_STATUS_FULLDUPLEX 0x2000 127be937f1fSAlexandr Smirnov #define MII_M1011_PHY_STATUS_RESOLVED 0x0800 128be937f1fSAlexandr Smirnov #define MII_M1011_PHY_STATUS_LINK 0x0400 129be937f1fSAlexandr Smirnov 1303da09a51SMichal Simek #define MII_M1116R_CONTROL_REG_MAC 21 1313da09a51SMichal Simek 1326b358aedSSebastian Hesselbarth #define MII_88E3016_PHY_SPEC_CTRL 0x10 1336b358aedSSebastian Hesselbarth #define MII_88E3016_DISABLE_SCRAMBLER 0x0200 1346b358aedSSebastian Hesselbarth #define MII_88E3016_AUTO_MDIX_CROSSOVER 0x0030 13576884679SAndy Fleming 136930b37eeSStefan Roese #define MII_88E1510_GEN_CTRL_REG_1 0x14 137930b37eeSStefan Roese #define MII_88E1510_GEN_CTRL_REG_1_MODE_MASK 0x7 138930b37eeSStefan Roese #define MII_88E1510_GEN_CTRL_REG_1_MODE_SGMII 0x1 /* SGMII to copper */ 139930b37eeSStefan Roese #define MII_88E1510_GEN_CTRL_REG_1_RESET 0x8000 /* Soft reset */ 140930b37eeSStefan Roese 1416cfb3bccSCharles-Antoine Couret #define LPA_FIBER_1000HALF 0x40 1426cfb3bccSCharles-Antoine Couret #define LPA_FIBER_1000FULL 0x20 1436cfb3bccSCharles-Antoine Couret 1446cfb3bccSCharles-Antoine Couret #define LPA_PAUSE_FIBER 0x180 1456cfb3bccSCharles-Antoine Couret #define LPA_PAUSE_ASYM_FIBER 0x100 1466cfb3bccSCharles-Antoine Couret 1476cfb3bccSCharles-Antoine Couret #define ADVERTISE_FIBER_1000HALF 0x40 1486cfb3bccSCharles-Antoine Couret #define ADVERTISE_FIBER_1000FULL 0x20 1496cfb3bccSCharles-Antoine Couret 1506cfb3bccSCharles-Antoine Couret #define ADVERTISE_PAUSE_FIBER 0x180 1516cfb3bccSCharles-Antoine Couret #define ADVERTISE_PAUSE_ASYM_FIBER 0x100 1526cfb3bccSCharles-Antoine Couret 1536cfb3bccSCharles-Antoine Couret #define REGISTER_LINK_STATUS 0x400 1542170fef7SCharles-Antoine Couret #define NB_FIBER_STATS 1 1556cfb3bccSCharles-Antoine Couret 15600db8189SAndy Fleming MODULE_DESCRIPTION("Marvell PHY driver"); 15700db8189SAndy Fleming MODULE_AUTHOR("Andy Fleming"); 15800db8189SAndy Fleming MODULE_LICENSE("GPL"); 15900db8189SAndy Fleming 160d2fa47d9SAndrew Lunn struct marvell_hw_stat { 161d2fa47d9SAndrew Lunn const char *string; 162d2fa47d9SAndrew Lunn u8 page; 163d2fa47d9SAndrew Lunn u8 reg; 164d2fa47d9SAndrew Lunn u8 bits; 165d2fa47d9SAndrew Lunn }; 166d2fa47d9SAndrew Lunn 167d2fa47d9SAndrew Lunn static struct marvell_hw_stat marvell_hw_stats[] = { 1682170fef7SCharles-Antoine Couret { "phy_receive_errors_copper", 0, 21, 16}, 169d2fa47d9SAndrew Lunn { "phy_idle_errors", 0, 10, 8 }, 1702170fef7SCharles-Antoine Couret { "phy_receive_errors_fiber", 1, 21, 16}, 171d2fa47d9SAndrew Lunn }; 172d2fa47d9SAndrew Lunn 173d2fa47d9SAndrew Lunn struct marvell_priv { 174d2fa47d9SAndrew Lunn u64 stats[ARRAY_SIZE(marvell_hw_stats)]; 175d2fa47d9SAndrew Lunn }; 176d2fa47d9SAndrew Lunn 17700db8189SAndy Fleming static int marvell_ack_interrupt(struct phy_device *phydev) 17800db8189SAndy Fleming { 17900db8189SAndy Fleming int err; 18000db8189SAndy Fleming 18100db8189SAndy Fleming /* Clear the interrupts by reading the reg */ 18200db8189SAndy Fleming err = phy_read(phydev, MII_M1011_IEVENT); 18300db8189SAndy Fleming 18400db8189SAndy Fleming if (err < 0) 18500db8189SAndy Fleming return err; 18600db8189SAndy Fleming 18700db8189SAndy Fleming return 0; 18800db8189SAndy Fleming } 18900db8189SAndy Fleming 19000db8189SAndy Fleming static int marvell_config_intr(struct phy_device *phydev) 19100db8189SAndy Fleming { 19200db8189SAndy Fleming int err; 19300db8189SAndy Fleming 19400db8189SAndy Fleming if (phydev->interrupts == PHY_INTERRUPT_ENABLED) 19500db8189SAndy Fleming err = phy_write(phydev, MII_M1011_IMASK, MII_M1011_IMASK_INIT); 19600db8189SAndy Fleming else 19700db8189SAndy Fleming err = phy_write(phydev, MII_M1011_IMASK, MII_M1011_IMASK_CLEAR); 19800db8189SAndy Fleming 19900db8189SAndy Fleming return err; 20000db8189SAndy Fleming } 20100db8189SAndy Fleming 202239aa55bSDavid Thomson static int marvell_set_polarity(struct phy_device *phydev, int polarity) 203239aa55bSDavid Thomson { 204239aa55bSDavid Thomson int reg; 205239aa55bSDavid Thomson int err; 206239aa55bSDavid Thomson int val; 207239aa55bSDavid Thomson 208239aa55bSDavid Thomson /* get the current settings */ 209239aa55bSDavid Thomson reg = phy_read(phydev, MII_M1011_PHY_SCR); 210239aa55bSDavid Thomson if (reg < 0) 211239aa55bSDavid Thomson return reg; 212239aa55bSDavid Thomson 213239aa55bSDavid Thomson val = reg; 214239aa55bSDavid Thomson val &= ~MII_M1011_PHY_SCR_AUTO_CROSS; 215239aa55bSDavid Thomson switch (polarity) { 216239aa55bSDavid Thomson case ETH_TP_MDI: 217239aa55bSDavid Thomson val |= MII_M1011_PHY_SCR_MDI; 218239aa55bSDavid Thomson break; 219239aa55bSDavid Thomson case ETH_TP_MDI_X: 220239aa55bSDavid Thomson val |= MII_M1011_PHY_SCR_MDI_X; 221239aa55bSDavid Thomson break; 222239aa55bSDavid Thomson case ETH_TP_MDI_AUTO: 223239aa55bSDavid Thomson case ETH_TP_MDI_INVALID: 224239aa55bSDavid Thomson default: 225239aa55bSDavid Thomson val |= MII_M1011_PHY_SCR_AUTO_CROSS; 226239aa55bSDavid Thomson break; 227239aa55bSDavid Thomson } 228239aa55bSDavid Thomson 229239aa55bSDavid Thomson if (val != reg) { 230239aa55bSDavid Thomson /* Set the new polarity value in the register */ 231239aa55bSDavid Thomson err = phy_write(phydev, MII_M1011_PHY_SCR, val); 232239aa55bSDavid Thomson if (err) 233239aa55bSDavid Thomson return err; 234239aa55bSDavid Thomson } 235239aa55bSDavid Thomson 236239aa55bSDavid Thomson return 0; 237239aa55bSDavid Thomson } 238239aa55bSDavid Thomson 23900db8189SAndy Fleming static int marvell_config_aneg(struct phy_device *phydev) 24000db8189SAndy Fleming { 24100db8189SAndy Fleming int err; 24200db8189SAndy Fleming 24300db8189SAndy Fleming /* The Marvell PHY has an errata which requires 24400db8189SAndy Fleming * that certain registers get written in order 24500db8189SAndy Fleming * to restart autonegotiation */ 24600db8189SAndy Fleming err = phy_write(phydev, MII_BMCR, BMCR_RESET); 24700db8189SAndy Fleming 24800db8189SAndy Fleming if (err < 0) 24900db8189SAndy Fleming return err; 25000db8189SAndy Fleming 25100db8189SAndy Fleming err = phy_write(phydev, 0x1d, 0x1f); 25200db8189SAndy Fleming if (err < 0) 25300db8189SAndy Fleming return err; 25400db8189SAndy Fleming 25500db8189SAndy Fleming err = phy_write(phydev, 0x1e, 0x200c); 25600db8189SAndy Fleming if (err < 0) 25700db8189SAndy Fleming return err; 25800db8189SAndy Fleming 25900db8189SAndy Fleming err = phy_write(phydev, 0x1d, 0x5); 26000db8189SAndy Fleming if (err < 0) 26100db8189SAndy Fleming return err; 26200db8189SAndy Fleming 26300db8189SAndy Fleming err = phy_write(phydev, 0x1e, 0); 26400db8189SAndy Fleming if (err < 0) 26500db8189SAndy Fleming return err; 26600db8189SAndy Fleming 26700db8189SAndy Fleming err = phy_write(phydev, 0x1e, 0x100); 26800db8189SAndy Fleming if (err < 0) 26900db8189SAndy Fleming return err; 27000db8189SAndy Fleming 271239aa55bSDavid Thomson err = marvell_set_polarity(phydev, phydev->mdix); 27276884679SAndy Fleming if (err < 0) 27376884679SAndy Fleming return err; 27476884679SAndy Fleming 27576884679SAndy Fleming err = phy_write(phydev, MII_M1111_PHY_LED_CONTROL, 27676884679SAndy Fleming MII_M1111_PHY_LED_DIRECT); 27776884679SAndy Fleming if (err < 0) 27876884679SAndy Fleming return err; 27900db8189SAndy Fleming 28000db8189SAndy Fleming err = genphy_config_aneg(phydev); 2818ff44985SAnton Vorontsov if (err < 0) 28200db8189SAndy Fleming return err; 2838ff44985SAnton Vorontsov 2848ff44985SAnton Vorontsov if (phydev->autoneg != AUTONEG_ENABLE) { 2858ff44985SAnton Vorontsov int bmcr; 2868ff44985SAnton Vorontsov 2878ff44985SAnton Vorontsov /* 2888ff44985SAnton Vorontsov * A write to speed/duplex bits (that is performed by 2898ff44985SAnton Vorontsov * genphy_config_aneg() call above) must be followed by 2908ff44985SAnton Vorontsov * a software reset. Otherwise, the write has no effect. 2918ff44985SAnton Vorontsov */ 2928ff44985SAnton Vorontsov bmcr = phy_read(phydev, MII_BMCR); 2938ff44985SAnton Vorontsov if (bmcr < 0) 2948ff44985SAnton Vorontsov return bmcr; 2958ff44985SAnton Vorontsov 2968ff44985SAnton Vorontsov err = phy_write(phydev, MII_BMCR, bmcr | BMCR_RESET); 2978ff44985SAnton Vorontsov if (err < 0) 2988ff44985SAnton Vorontsov return err; 2998ff44985SAnton Vorontsov } 3008ff44985SAnton Vorontsov 3018ff44985SAnton Vorontsov return 0; 30200db8189SAndy Fleming } 30300db8189SAndy Fleming 3043ec0a0f1SHarini Katakam static int m88e1111_config_aneg(struct phy_device *phydev) 3053ec0a0f1SHarini Katakam { 3063ec0a0f1SHarini Katakam int err; 3073ec0a0f1SHarini Katakam 3083ec0a0f1SHarini Katakam /* The Marvell PHY has an errata which requires 3093ec0a0f1SHarini Katakam * that certain registers get written in order 3103ec0a0f1SHarini Katakam * to restart autonegotiation 3113ec0a0f1SHarini Katakam */ 3123ec0a0f1SHarini Katakam err = phy_write(phydev, MII_BMCR, BMCR_RESET); 3133ec0a0f1SHarini Katakam 3143ec0a0f1SHarini Katakam err = marvell_set_polarity(phydev, phydev->mdix); 3153ec0a0f1SHarini Katakam if (err < 0) 3163ec0a0f1SHarini Katakam return err; 3173ec0a0f1SHarini Katakam 3183ec0a0f1SHarini Katakam err = phy_write(phydev, MII_M1111_PHY_LED_CONTROL, 3193ec0a0f1SHarini Katakam MII_M1111_PHY_LED_DIRECT); 3203ec0a0f1SHarini Katakam if (err < 0) 3213ec0a0f1SHarini Katakam return err; 3223ec0a0f1SHarini Katakam 3233ec0a0f1SHarini Katakam err = genphy_config_aneg(phydev); 3243ec0a0f1SHarini Katakam if (err < 0) 3253ec0a0f1SHarini Katakam return err; 3263ec0a0f1SHarini Katakam 3273ec0a0f1SHarini Katakam if (phydev->autoneg != AUTONEG_ENABLE) { 3283ec0a0f1SHarini Katakam int bmcr; 3293ec0a0f1SHarini Katakam 3303ec0a0f1SHarini Katakam /* A write to speed/duplex bits (that is performed by 3313ec0a0f1SHarini Katakam * genphy_config_aneg() call above) must be followed by 3323ec0a0f1SHarini Katakam * a software reset. Otherwise, the write has no effect. 3333ec0a0f1SHarini Katakam */ 3343ec0a0f1SHarini Katakam bmcr = phy_read(phydev, MII_BMCR); 3353ec0a0f1SHarini Katakam if (bmcr < 0) 3363ec0a0f1SHarini Katakam return bmcr; 3373ec0a0f1SHarini Katakam 3383ec0a0f1SHarini Katakam err = phy_write(phydev, MII_BMCR, bmcr | BMCR_RESET); 3393ec0a0f1SHarini Katakam if (err < 0) 3403ec0a0f1SHarini Katakam return err; 3413ec0a0f1SHarini Katakam } 3423ec0a0f1SHarini Katakam 3433ec0a0f1SHarini Katakam return 0; 3443ec0a0f1SHarini Katakam } 3453ec0a0f1SHarini Katakam 346cf41a51dSDavid Daney #ifdef CONFIG_OF_MDIO 347cf41a51dSDavid Daney /* 348cf41a51dSDavid Daney * Set and/or override some configuration registers based on the 349cf41a51dSDavid Daney * marvell,reg-init property stored in the of_node for the phydev. 350cf41a51dSDavid Daney * 351cf41a51dSDavid Daney * marvell,reg-init = <reg-page reg mask value>,...; 352cf41a51dSDavid Daney * 353cf41a51dSDavid Daney * There may be one or more sets of <reg-page reg mask value>: 354cf41a51dSDavid Daney * 355cf41a51dSDavid Daney * reg-page: which register bank to use. 356cf41a51dSDavid Daney * reg: the register. 357cf41a51dSDavid Daney * mask: if non-zero, ANDed with existing register value. 358cf41a51dSDavid Daney * value: ORed with the masked value and written to the regiser. 359cf41a51dSDavid Daney * 360cf41a51dSDavid Daney */ 361cf41a51dSDavid Daney static int marvell_of_reg_init(struct phy_device *phydev) 362cf41a51dSDavid Daney { 363cf41a51dSDavid Daney const __be32 *paddr; 364cf41a51dSDavid Daney int len, i, saved_page, current_page, page_changed, ret; 365cf41a51dSDavid Daney 366e5a03bfdSAndrew Lunn if (!phydev->mdio.dev.of_node) 367cf41a51dSDavid Daney return 0; 368cf41a51dSDavid Daney 369e5a03bfdSAndrew Lunn paddr = of_get_property(phydev->mdio.dev.of_node, 370e5a03bfdSAndrew Lunn "marvell,reg-init", &len); 371cf41a51dSDavid Daney if (!paddr || len < (4 * sizeof(*paddr))) 372cf41a51dSDavid Daney return 0; 373cf41a51dSDavid Daney 374cf41a51dSDavid Daney saved_page = phy_read(phydev, MII_MARVELL_PHY_PAGE); 375cf41a51dSDavid Daney if (saved_page < 0) 376cf41a51dSDavid Daney return saved_page; 377cf41a51dSDavid Daney page_changed = 0; 378cf41a51dSDavid Daney current_page = saved_page; 379cf41a51dSDavid Daney 380cf41a51dSDavid Daney ret = 0; 381cf41a51dSDavid Daney len /= sizeof(*paddr); 382cf41a51dSDavid Daney for (i = 0; i < len - 3; i += 4) { 383cf41a51dSDavid Daney u16 reg_page = be32_to_cpup(paddr + i); 384cf41a51dSDavid Daney u16 reg = be32_to_cpup(paddr + i + 1); 385cf41a51dSDavid Daney u16 mask = be32_to_cpup(paddr + i + 2); 386cf41a51dSDavid Daney u16 val_bits = be32_to_cpup(paddr + i + 3); 387cf41a51dSDavid Daney int val; 388cf41a51dSDavid Daney 389cf41a51dSDavid Daney if (reg_page != current_page) { 390cf41a51dSDavid Daney current_page = reg_page; 391cf41a51dSDavid Daney page_changed = 1; 392cf41a51dSDavid Daney ret = phy_write(phydev, MII_MARVELL_PHY_PAGE, reg_page); 393cf41a51dSDavid Daney if (ret < 0) 394cf41a51dSDavid Daney goto err; 395cf41a51dSDavid Daney } 396cf41a51dSDavid Daney 397cf41a51dSDavid Daney val = 0; 398cf41a51dSDavid Daney if (mask) { 399cf41a51dSDavid Daney val = phy_read(phydev, reg); 400cf41a51dSDavid Daney if (val < 0) { 401cf41a51dSDavid Daney ret = val; 402cf41a51dSDavid Daney goto err; 403cf41a51dSDavid Daney } 404cf41a51dSDavid Daney val &= mask; 405cf41a51dSDavid Daney } 406cf41a51dSDavid Daney val |= val_bits; 407cf41a51dSDavid Daney 408cf41a51dSDavid Daney ret = phy_write(phydev, reg, val); 409cf41a51dSDavid Daney if (ret < 0) 410cf41a51dSDavid Daney goto err; 411cf41a51dSDavid Daney 412cf41a51dSDavid Daney } 413cf41a51dSDavid Daney err: 414cf41a51dSDavid Daney if (page_changed) { 415cf41a51dSDavid Daney i = phy_write(phydev, MII_MARVELL_PHY_PAGE, saved_page); 416cf41a51dSDavid Daney if (ret == 0) 417cf41a51dSDavid Daney ret = i; 418cf41a51dSDavid Daney } 419cf41a51dSDavid Daney return ret; 420cf41a51dSDavid Daney } 421cf41a51dSDavid Daney #else 422cf41a51dSDavid Daney static int marvell_of_reg_init(struct phy_device *phydev) 423cf41a51dSDavid Daney { 424cf41a51dSDavid Daney return 0; 425cf41a51dSDavid Daney } 426cf41a51dSDavid Daney #endif /* CONFIG_OF_MDIO */ 427cf41a51dSDavid Daney 428140bc929SSergei Poselenov static int m88e1121_config_aneg(struct phy_device *phydev) 429140bc929SSergei Poselenov { 430c477d044SCyril Chemparathy int err, oldpage, mscr; 431c477d044SCyril Chemparathy 43227d916d6SDavid Daney oldpage = phy_read(phydev, MII_MARVELL_PHY_PAGE); 433c477d044SCyril Chemparathy 43427d916d6SDavid Daney err = phy_write(phydev, MII_MARVELL_PHY_PAGE, 435c477d044SCyril Chemparathy MII_88E1121_PHY_MSCR_PAGE); 436c477d044SCyril Chemparathy if (err < 0) 437c477d044SCyril Chemparathy return err; 438be8c6480SArnaud Patard 43932a64161SFlorian Fainelli if (phy_interface_is_rgmii(phydev)) { 440be8c6480SArnaud Patard 441c477d044SCyril Chemparathy mscr = phy_read(phydev, MII_88E1121_PHY_MSCR_REG) & 442c477d044SCyril Chemparathy MII_88E1121_PHY_MSCR_DELAY_MASK; 443c477d044SCyril Chemparathy 444c477d044SCyril Chemparathy if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID) 445c477d044SCyril Chemparathy mscr |= (MII_88E1121_PHY_MSCR_RX_DELAY | 446c477d044SCyril Chemparathy MII_88E1121_PHY_MSCR_TX_DELAY); 447c477d044SCyril Chemparathy else if (phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID) 448c477d044SCyril Chemparathy mscr |= MII_88E1121_PHY_MSCR_RX_DELAY; 449c477d044SCyril Chemparathy else if (phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID) 450c477d044SCyril Chemparathy mscr |= MII_88E1121_PHY_MSCR_TX_DELAY; 451c477d044SCyril Chemparathy 452c477d044SCyril Chemparathy err = phy_write(phydev, MII_88E1121_PHY_MSCR_REG, mscr); 453c477d044SCyril Chemparathy if (err < 0) 454c477d044SCyril Chemparathy return err; 455be8c6480SArnaud Patard } 456c477d044SCyril Chemparathy 45727d916d6SDavid Daney phy_write(phydev, MII_MARVELL_PHY_PAGE, oldpage); 458140bc929SSergei Poselenov 459140bc929SSergei Poselenov err = phy_write(phydev, MII_BMCR, BMCR_RESET); 460140bc929SSergei Poselenov if (err < 0) 461140bc929SSergei Poselenov return err; 462140bc929SSergei Poselenov 463140bc929SSergei Poselenov err = phy_write(phydev, MII_M1011_PHY_SCR, 464140bc929SSergei Poselenov MII_M1011_PHY_SCR_AUTO_CROSS); 465140bc929SSergei Poselenov if (err < 0) 466140bc929SSergei Poselenov return err; 467140bc929SSergei Poselenov 468fdecf36fSClemens Gruber return genphy_config_aneg(phydev); 469140bc929SSergei Poselenov } 470140bc929SSergei Poselenov 471337ac9d5SCyril Chemparathy static int m88e1318_config_aneg(struct phy_device *phydev) 4723ff1c259SCyril Chemparathy { 4733ff1c259SCyril Chemparathy int err, oldpage, mscr; 4743ff1c259SCyril Chemparathy 47527d916d6SDavid Daney oldpage = phy_read(phydev, MII_MARVELL_PHY_PAGE); 4763ff1c259SCyril Chemparathy 47727d916d6SDavid Daney err = phy_write(phydev, MII_MARVELL_PHY_PAGE, 4783ff1c259SCyril Chemparathy MII_88E1121_PHY_MSCR_PAGE); 4793ff1c259SCyril Chemparathy if (err < 0) 4803ff1c259SCyril Chemparathy return err; 4813ff1c259SCyril Chemparathy 482337ac9d5SCyril Chemparathy mscr = phy_read(phydev, MII_88E1318S_PHY_MSCR1_REG); 483337ac9d5SCyril Chemparathy mscr |= MII_88E1318S_PHY_MSCR1_PAD_ODD; 4843ff1c259SCyril Chemparathy 485337ac9d5SCyril Chemparathy err = phy_write(phydev, MII_88E1318S_PHY_MSCR1_REG, mscr); 4863ff1c259SCyril Chemparathy if (err < 0) 4873ff1c259SCyril Chemparathy return err; 4883ff1c259SCyril Chemparathy 48927d916d6SDavid Daney err = phy_write(phydev, MII_MARVELL_PHY_PAGE, oldpage); 4903ff1c259SCyril Chemparathy if (err < 0) 4913ff1c259SCyril Chemparathy return err; 4923ff1c259SCyril Chemparathy 4933ff1c259SCyril Chemparathy return m88e1121_config_aneg(phydev); 4943ff1c259SCyril Chemparathy } 4953ff1c259SCyril Chemparathy 49678301ebeSCharles-Antoine Couret /** 49778301ebeSCharles-Antoine Couret * ethtool_adv_to_fiber_adv_t 49878301ebeSCharles-Antoine Couret * @ethadv: the ethtool advertisement settings 49978301ebeSCharles-Antoine Couret * 50078301ebeSCharles-Antoine Couret * A small helper function that translates ethtool advertisement 50178301ebeSCharles-Antoine Couret * settings to phy autonegotiation advertisements for the 50278301ebeSCharles-Antoine Couret * MII_ADV register for fiber link. 50378301ebeSCharles-Antoine Couret */ 50478301ebeSCharles-Antoine Couret static inline u32 ethtool_adv_to_fiber_adv_t(u32 ethadv) 50578301ebeSCharles-Antoine Couret { 50678301ebeSCharles-Antoine Couret u32 result = 0; 50778301ebeSCharles-Antoine Couret 50878301ebeSCharles-Antoine Couret if (ethadv & ADVERTISED_1000baseT_Half) 50978301ebeSCharles-Antoine Couret result |= ADVERTISE_FIBER_1000HALF; 51078301ebeSCharles-Antoine Couret if (ethadv & ADVERTISED_1000baseT_Full) 51178301ebeSCharles-Antoine Couret result |= ADVERTISE_FIBER_1000FULL; 51278301ebeSCharles-Antoine Couret 51378301ebeSCharles-Antoine Couret if ((ethadv & ADVERTISE_PAUSE_ASYM) && (ethadv & ADVERTISE_PAUSE_CAP)) 51478301ebeSCharles-Antoine Couret result |= LPA_PAUSE_ASYM_FIBER; 51578301ebeSCharles-Antoine Couret else if (ethadv & ADVERTISE_PAUSE_CAP) 51678301ebeSCharles-Antoine Couret result |= (ADVERTISE_PAUSE_FIBER 51778301ebeSCharles-Antoine Couret & (~ADVERTISE_PAUSE_ASYM_FIBER)); 51878301ebeSCharles-Antoine Couret 51978301ebeSCharles-Antoine Couret return result; 52078301ebeSCharles-Antoine Couret } 52178301ebeSCharles-Antoine Couret 52278301ebeSCharles-Antoine Couret /** 52378301ebeSCharles-Antoine Couret * marvell_config_aneg_fiber - restart auto-negotiation or write BMCR 52478301ebeSCharles-Antoine Couret * @phydev: target phy_device struct 52578301ebeSCharles-Antoine Couret * 52678301ebeSCharles-Antoine Couret * Description: If auto-negotiation is enabled, we configure the 52778301ebeSCharles-Antoine Couret * advertising, and then restart auto-negotiation. If it is not 52878301ebeSCharles-Antoine Couret * enabled, then we write the BMCR. Adapted for fiber link in 52978301ebeSCharles-Antoine Couret * some Marvell's devices. 53078301ebeSCharles-Antoine Couret */ 53178301ebeSCharles-Antoine Couret static int marvell_config_aneg_fiber(struct phy_device *phydev) 53278301ebeSCharles-Antoine Couret { 53378301ebeSCharles-Antoine Couret int changed = 0; 53478301ebeSCharles-Antoine Couret int err; 53578301ebeSCharles-Antoine Couret int adv, oldadv; 53678301ebeSCharles-Antoine Couret u32 advertise; 53778301ebeSCharles-Antoine Couret 53878301ebeSCharles-Antoine Couret if (phydev->autoneg != AUTONEG_ENABLE) 53978301ebeSCharles-Antoine Couret return genphy_setup_forced(phydev); 54078301ebeSCharles-Antoine Couret 54178301ebeSCharles-Antoine Couret /* Only allow advertising what this PHY supports */ 54278301ebeSCharles-Antoine Couret phydev->advertising &= phydev->supported; 54378301ebeSCharles-Antoine Couret advertise = phydev->advertising; 54478301ebeSCharles-Antoine Couret 54578301ebeSCharles-Antoine Couret /* Setup fiber advertisement */ 54678301ebeSCharles-Antoine Couret adv = phy_read(phydev, MII_ADVERTISE); 54778301ebeSCharles-Antoine Couret if (adv < 0) 54878301ebeSCharles-Antoine Couret return adv; 54978301ebeSCharles-Antoine Couret 55078301ebeSCharles-Antoine Couret oldadv = adv; 55178301ebeSCharles-Antoine Couret adv &= ~(ADVERTISE_FIBER_1000HALF | ADVERTISE_FIBER_1000FULL 55278301ebeSCharles-Antoine Couret | LPA_PAUSE_FIBER); 55378301ebeSCharles-Antoine Couret adv |= ethtool_adv_to_fiber_adv_t(advertise); 55478301ebeSCharles-Antoine Couret 55578301ebeSCharles-Antoine Couret if (adv != oldadv) { 55678301ebeSCharles-Antoine Couret err = phy_write(phydev, MII_ADVERTISE, adv); 55778301ebeSCharles-Antoine Couret if (err < 0) 55878301ebeSCharles-Antoine Couret return err; 55978301ebeSCharles-Antoine Couret 56078301ebeSCharles-Antoine Couret changed = 1; 56178301ebeSCharles-Antoine Couret } 56278301ebeSCharles-Antoine Couret 56378301ebeSCharles-Antoine Couret if (changed == 0) { 56478301ebeSCharles-Antoine Couret /* Advertisement hasn't changed, but maybe aneg was never on to 56578301ebeSCharles-Antoine Couret * begin with? Or maybe phy was isolated? 56678301ebeSCharles-Antoine Couret */ 56778301ebeSCharles-Antoine Couret int ctl = phy_read(phydev, MII_BMCR); 56878301ebeSCharles-Antoine Couret 56978301ebeSCharles-Antoine Couret if (ctl < 0) 57078301ebeSCharles-Antoine Couret return ctl; 57178301ebeSCharles-Antoine Couret 57278301ebeSCharles-Antoine Couret if (!(ctl & BMCR_ANENABLE) || (ctl & BMCR_ISOLATE)) 57378301ebeSCharles-Antoine Couret changed = 1; /* do restart aneg */ 57478301ebeSCharles-Antoine Couret } 57578301ebeSCharles-Antoine Couret 57678301ebeSCharles-Antoine Couret /* Only restart aneg if we are advertising something different 57778301ebeSCharles-Antoine Couret * than we were before. 57878301ebeSCharles-Antoine Couret */ 57978301ebeSCharles-Antoine Couret if (changed > 0) 58078301ebeSCharles-Antoine Couret changed = genphy_restart_aneg(phydev); 58178301ebeSCharles-Antoine Couret 58278301ebeSCharles-Antoine Couret return changed; 58378301ebeSCharles-Antoine Couret } 58478301ebeSCharles-Antoine Couret 58510e24caaSMichal Simek static int m88e1510_config_aneg(struct phy_device *phydev) 58610e24caaSMichal Simek { 58710e24caaSMichal Simek int err; 58810e24caaSMichal Simek 58978301ebeSCharles-Antoine Couret err = phy_write(phydev, MII_MARVELL_PHY_PAGE, MII_M1111_COPPER); 59078301ebeSCharles-Antoine Couret if (err < 0) 59178301ebeSCharles-Antoine Couret goto error; 59278301ebeSCharles-Antoine Couret 59378301ebeSCharles-Antoine Couret /* Configure the copper link first */ 59410e24caaSMichal Simek err = m88e1318_config_aneg(phydev); 59510e24caaSMichal Simek if (err < 0) 59678301ebeSCharles-Antoine Couret goto error; 59710e24caaSMichal Simek 59878301ebeSCharles-Antoine Couret /* Then the fiber link */ 59978301ebeSCharles-Antoine Couret err = phy_write(phydev, MII_MARVELL_PHY_PAGE, MII_M1111_FIBER); 60078301ebeSCharles-Antoine Couret if (err < 0) 60178301ebeSCharles-Antoine Couret goto error; 60278301ebeSCharles-Antoine Couret 60378301ebeSCharles-Antoine Couret err = marvell_config_aneg_fiber(phydev); 60478301ebeSCharles-Antoine Couret if (err < 0) 60578301ebeSCharles-Antoine Couret goto error; 60678301ebeSCharles-Antoine Couret 60778301ebeSCharles-Antoine Couret return phy_write(phydev, MII_MARVELL_PHY_PAGE, MII_M1111_COPPER); 60878301ebeSCharles-Antoine Couret 60978301ebeSCharles-Antoine Couret error: 61078301ebeSCharles-Antoine Couret phy_write(phydev, MII_MARVELL_PHY_PAGE, MII_M1111_COPPER); 61178301ebeSCharles-Antoine Couret return err; 61279be1a1cSClemens Gruber } 61379be1a1cSClemens Gruber 61479be1a1cSClemens Gruber static int marvell_config_init(struct phy_device *phydev) 61579be1a1cSClemens Gruber { 61679be1a1cSClemens Gruber /* Set registers from marvell,reg-init DT property */ 61710e24caaSMichal Simek return marvell_of_reg_init(phydev); 61810e24caaSMichal Simek } 61910e24caaSMichal Simek 6203da09a51SMichal Simek static int m88e1116r_config_init(struct phy_device *phydev) 6213da09a51SMichal Simek { 6223da09a51SMichal Simek int temp; 6233da09a51SMichal Simek int err; 6243da09a51SMichal Simek 6253da09a51SMichal Simek temp = phy_read(phydev, MII_BMCR); 6263da09a51SMichal Simek temp |= BMCR_RESET; 6273da09a51SMichal Simek err = phy_write(phydev, MII_BMCR, temp); 6283da09a51SMichal Simek if (err < 0) 6293da09a51SMichal Simek return err; 6303da09a51SMichal Simek 6313da09a51SMichal Simek mdelay(500); 6323da09a51SMichal Simek 6333da09a51SMichal Simek err = phy_write(phydev, MII_MARVELL_PHY_PAGE, 0); 6343da09a51SMichal Simek if (err < 0) 6353da09a51SMichal Simek return err; 6363da09a51SMichal Simek 6373da09a51SMichal Simek temp = phy_read(phydev, MII_M1011_PHY_SCR); 6383da09a51SMichal Simek temp |= (7 << 12); /* max number of gigabit attempts */ 6393da09a51SMichal Simek temp |= (1 << 11); /* enable downshift */ 6403da09a51SMichal Simek temp |= MII_M1011_PHY_SCR_AUTO_CROSS; 6413da09a51SMichal Simek err = phy_write(phydev, MII_M1011_PHY_SCR, temp); 6423da09a51SMichal Simek if (err < 0) 6433da09a51SMichal Simek return err; 6443da09a51SMichal Simek 6453da09a51SMichal Simek err = phy_write(phydev, MII_MARVELL_PHY_PAGE, 2); 6463da09a51SMichal Simek if (err < 0) 6473da09a51SMichal Simek return err; 6483da09a51SMichal Simek temp = phy_read(phydev, MII_M1116R_CONTROL_REG_MAC); 6493da09a51SMichal Simek temp |= (1 << 5); 6503da09a51SMichal Simek temp |= (1 << 4); 6513da09a51SMichal Simek err = phy_write(phydev, MII_M1116R_CONTROL_REG_MAC, temp); 6523da09a51SMichal Simek if (err < 0) 6533da09a51SMichal Simek return err; 6543da09a51SMichal Simek err = phy_write(phydev, MII_MARVELL_PHY_PAGE, 0); 6553da09a51SMichal Simek if (err < 0) 6563da09a51SMichal Simek return err; 6573da09a51SMichal Simek 6583da09a51SMichal Simek temp = phy_read(phydev, MII_BMCR); 6593da09a51SMichal Simek temp |= BMCR_RESET; 6603da09a51SMichal Simek err = phy_write(phydev, MII_BMCR, temp); 6613da09a51SMichal Simek if (err < 0) 6623da09a51SMichal Simek return err; 6633da09a51SMichal Simek 6643da09a51SMichal Simek mdelay(500); 6653da09a51SMichal Simek 66679be1a1cSClemens Gruber return marvell_config_init(phydev); 6673da09a51SMichal Simek } 6683da09a51SMichal Simek 6696b358aedSSebastian Hesselbarth static int m88e3016_config_init(struct phy_device *phydev) 6706b358aedSSebastian Hesselbarth { 6716b358aedSSebastian Hesselbarth int reg; 6726b358aedSSebastian Hesselbarth 6736b358aedSSebastian Hesselbarth /* Enable Scrambler and Auto-Crossover */ 6746b358aedSSebastian Hesselbarth reg = phy_read(phydev, MII_88E3016_PHY_SPEC_CTRL); 6756b358aedSSebastian Hesselbarth if (reg < 0) 6766b358aedSSebastian Hesselbarth return reg; 6776b358aedSSebastian Hesselbarth 6786b358aedSSebastian Hesselbarth reg &= ~MII_88E3016_DISABLE_SCRAMBLER; 6796b358aedSSebastian Hesselbarth reg |= MII_88E3016_AUTO_MDIX_CROSSOVER; 6806b358aedSSebastian Hesselbarth 6816b358aedSSebastian Hesselbarth reg = phy_write(phydev, MII_88E3016_PHY_SPEC_CTRL, reg); 6826b358aedSSebastian Hesselbarth if (reg < 0) 6836b358aedSSebastian Hesselbarth return reg; 6846b358aedSSebastian Hesselbarth 68579be1a1cSClemens Gruber return marvell_config_init(phydev); 6866b358aedSSebastian Hesselbarth } 6876b358aedSSebastian Hesselbarth 688895ee682SKim Phillips static int m88e1111_config_init(struct phy_device *phydev) 689895ee682SKim Phillips { 690895ee682SKim Phillips int err; 691be937f1fSAlexandr Smirnov int temp; 692be937f1fSAlexandr Smirnov 69332a64161SFlorian Fainelli if (phy_interface_is_rgmii(phydev)) { 694895ee682SKim Phillips 695895ee682SKim Phillips temp = phy_read(phydev, MII_M1111_PHY_EXT_CR); 696895ee682SKim Phillips if (temp < 0) 697895ee682SKim Phillips return temp; 698895ee682SKim Phillips 6999daf5a76SKim Phillips if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID) { 700895ee682SKim Phillips temp |= (MII_M1111_RX_DELAY | MII_M1111_TX_DELAY); 7019daf5a76SKim Phillips } else if (phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID) { 7029daf5a76SKim Phillips temp &= ~MII_M1111_TX_DELAY; 7039daf5a76SKim Phillips temp |= MII_M1111_RX_DELAY; 7049daf5a76SKim Phillips } else if (phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID) { 7059daf5a76SKim Phillips temp &= ~MII_M1111_RX_DELAY; 7069daf5a76SKim Phillips temp |= MII_M1111_TX_DELAY; 7079daf5a76SKim Phillips } 708895ee682SKim Phillips 709895ee682SKim Phillips err = phy_write(phydev, MII_M1111_PHY_EXT_CR, temp); 710895ee682SKim Phillips if (err < 0) 711895ee682SKim Phillips return err; 712895ee682SKim Phillips 713895ee682SKim Phillips temp = phy_read(phydev, MII_M1111_PHY_EXT_SR); 714895ee682SKim Phillips if (temp < 0) 715895ee682SKim Phillips return temp; 716895ee682SKim Phillips 717895ee682SKim Phillips temp &= ~(MII_M1111_HWCFG_MODE_MASK); 718be937f1fSAlexandr Smirnov 7197239016dSWang Jian if (temp & MII_M1111_HWCFG_FIBER_COPPER_RES) 720be937f1fSAlexandr Smirnov temp |= MII_M1111_HWCFG_MODE_FIBER_RGMII; 721be937f1fSAlexandr Smirnov else 722be937f1fSAlexandr Smirnov temp |= MII_M1111_HWCFG_MODE_COPPER_RGMII; 723895ee682SKim Phillips 724895ee682SKim Phillips err = phy_write(phydev, MII_M1111_PHY_EXT_SR, temp); 725895ee682SKim Phillips if (err < 0) 726895ee682SKim Phillips return err; 727895ee682SKim Phillips } 728895ee682SKim Phillips 7294117b5beSKapil Juneja if (phydev->interface == PHY_INTERFACE_MODE_SGMII) { 7304117b5beSKapil Juneja temp = phy_read(phydev, MII_M1111_PHY_EXT_SR); 7314117b5beSKapil Juneja if (temp < 0) 7324117b5beSKapil Juneja return temp; 7334117b5beSKapil Juneja 7344117b5beSKapil Juneja temp &= ~(MII_M1111_HWCFG_MODE_MASK); 7354117b5beSKapil Juneja temp |= MII_M1111_HWCFG_MODE_SGMII_NO_CLK; 73632d0c1e1SHaiying Wang temp |= MII_M1111_HWCFG_FIBER_COPPER_AUTO; 7374117b5beSKapil Juneja 7384117b5beSKapil Juneja err = phy_write(phydev, MII_M1111_PHY_EXT_SR, temp); 7394117b5beSKapil Juneja if (err < 0) 7404117b5beSKapil Juneja return err; 74107151bc9SMadalin Bucur 74207151bc9SMadalin Bucur /* make sure copper is selected */ 74307151bc9SMadalin Bucur err = phy_read(phydev, MII_M1145_PHY_EXT_ADDR_PAGE); 74407151bc9SMadalin Bucur if (err < 0) 74507151bc9SMadalin Bucur return err; 74607151bc9SMadalin Bucur 74707151bc9SMadalin Bucur err = phy_write(phydev, MII_M1145_PHY_EXT_ADDR_PAGE, 74807151bc9SMadalin Bucur err & (~0xff)); 74907151bc9SMadalin Bucur if (err < 0) 75007151bc9SMadalin Bucur return err; 7514117b5beSKapil Juneja } 7524117b5beSKapil Juneja 7535f8cbc13SLiu Yu-B13201 if (phydev->interface == PHY_INTERFACE_MODE_RTBI) { 7545f8cbc13SLiu Yu-B13201 temp = phy_read(phydev, MII_M1111_PHY_EXT_CR); 7555f8cbc13SLiu Yu-B13201 if (temp < 0) 7565f8cbc13SLiu Yu-B13201 return temp; 7575f8cbc13SLiu Yu-B13201 temp |= (MII_M1111_RX_DELAY | MII_M1111_TX_DELAY); 7585f8cbc13SLiu Yu-B13201 err = phy_write(phydev, MII_M1111_PHY_EXT_CR, temp); 7595f8cbc13SLiu Yu-B13201 if (err < 0) 7605f8cbc13SLiu Yu-B13201 return err; 7615f8cbc13SLiu Yu-B13201 7625f8cbc13SLiu Yu-B13201 temp = phy_read(phydev, MII_M1111_PHY_EXT_SR); 7635f8cbc13SLiu Yu-B13201 if (temp < 0) 7645f8cbc13SLiu Yu-B13201 return temp; 7655f8cbc13SLiu Yu-B13201 temp &= ~(MII_M1111_HWCFG_MODE_MASK | MII_M1111_HWCFG_FIBER_COPPER_RES); 7665f8cbc13SLiu Yu-B13201 temp |= 0x7 | MII_M1111_HWCFG_FIBER_COPPER_AUTO; 7675f8cbc13SLiu Yu-B13201 err = phy_write(phydev, MII_M1111_PHY_EXT_SR, temp); 7685f8cbc13SLiu Yu-B13201 if (err < 0) 7695f8cbc13SLiu Yu-B13201 return err; 7705f8cbc13SLiu Yu-B13201 7715f8cbc13SLiu Yu-B13201 /* soft reset */ 7725f8cbc13SLiu Yu-B13201 err = phy_write(phydev, MII_BMCR, BMCR_RESET); 7735f8cbc13SLiu Yu-B13201 if (err < 0) 7745f8cbc13SLiu Yu-B13201 return err; 7755f8cbc13SLiu Yu-B13201 do 7765f8cbc13SLiu Yu-B13201 temp = phy_read(phydev, MII_BMCR); 7775f8cbc13SLiu Yu-B13201 while (temp & BMCR_RESET); 7785f8cbc13SLiu Yu-B13201 7795f8cbc13SLiu Yu-B13201 temp = phy_read(phydev, MII_M1111_PHY_EXT_SR); 7805f8cbc13SLiu Yu-B13201 if (temp < 0) 7815f8cbc13SLiu Yu-B13201 return temp; 7825f8cbc13SLiu Yu-B13201 temp &= ~(MII_M1111_HWCFG_MODE_MASK | MII_M1111_HWCFG_FIBER_COPPER_RES); 7835f8cbc13SLiu Yu-B13201 temp |= MII_M1111_HWCFG_MODE_COPPER_RTBI | MII_M1111_HWCFG_FIBER_COPPER_AUTO; 7845f8cbc13SLiu Yu-B13201 err = phy_write(phydev, MII_M1111_PHY_EXT_SR, temp); 7855f8cbc13SLiu Yu-B13201 if (err < 0) 7865f8cbc13SLiu Yu-B13201 return err; 7875f8cbc13SLiu Yu-B13201 } 7885f8cbc13SLiu Yu-B13201 789cf41a51dSDavid Daney err = marvell_of_reg_init(phydev); 790cf41a51dSDavid Daney if (err < 0) 791cf41a51dSDavid Daney return err; 7925f8cbc13SLiu Yu-B13201 793cc90cb3bSSrinivas Kandagatla return phy_write(phydev, MII_BMCR, BMCR_RESET); 794895ee682SKim Phillips } 795895ee682SKim Phillips 796fdecf36fSClemens Gruber static int m88e1121_config_init(struct phy_device *phydev) 797fdecf36fSClemens Gruber { 798fdecf36fSClemens Gruber int err, oldpage; 799fdecf36fSClemens Gruber 800fdecf36fSClemens Gruber oldpage = phy_read(phydev, MII_MARVELL_PHY_PAGE); 801fdecf36fSClemens Gruber 802fdecf36fSClemens Gruber err = phy_write(phydev, MII_MARVELL_PHY_PAGE, MII_88E1121_PHY_LED_PAGE); 803fdecf36fSClemens Gruber if (err < 0) 804fdecf36fSClemens Gruber return err; 805fdecf36fSClemens Gruber 806fdecf36fSClemens Gruber /* Default PHY LED config: LED[0] .. Link, LED[1] .. Activity */ 807fdecf36fSClemens Gruber err = phy_write(phydev, MII_88E1121_PHY_LED_CTRL, 808fdecf36fSClemens Gruber MII_88E1121_PHY_LED_DEF); 809fdecf36fSClemens Gruber if (err < 0) 810fdecf36fSClemens Gruber return err; 811fdecf36fSClemens Gruber 812fdecf36fSClemens Gruber phy_write(phydev, MII_MARVELL_PHY_PAGE, oldpage); 813fdecf36fSClemens Gruber 814fdecf36fSClemens Gruber /* Set marvell,reg-init configuration from device tree */ 815fdecf36fSClemens Gruber return marvell_config_init(phydev); 816fdecf36fSClemens Gruber } 817fdecf36fSClemens Gruber 818407353ecSClemens Gruber static int m88e1510_config_init(struct phy_device *phydev) 819407353ecSClemens Gruber { 820407353ecSClemens Gruber int err; 821407353ecSClemens Gruber int temp; 822407353ecSClemens Gruber 823407353ecSClemens Gruber /* SGMII-to-Copper mode initialization */ 824407353ecSClemens Gruber if (phydev->interface == PHY_INTERFACE_MODE_SGMII) { 825407353ecSClemens Gruber /* Select page 18 */ 826407353ecSClemens Gruber err = phy_write(phydev, MII_MARVELL_PHY_PAGE, 18); 827407353ecSClemens Gruber if (err < 0) 828407353ecSClemens Gruber return err; 829407353ecSClemens Gruber 830407353ecSClemens Gruber /* In reg 20, write MODE[2:0] = 0x1 (SGMII to Copper) */ 831407353ecSClemens Gruber temp = phy_read(phydev, MII_88E1510_GEN_CTRL_REG_1); 832407353ecSClemens Gruber temp &= ~MII_88E1510_GEN_CTRL_REG_1_MODE_MASK; 833407353ecSClemens Gruber temp |= MII_88E1510_GEN_CTRL_REG_1_MODE_SGMII; 834407353ecSClemens Gruber err = phy_write(phydev, MII_88E1510_GEN_CTRL_REG_1, temp); 835407353ecSClemens Gruber if (err < 0) 836407353ecSClemens Gruber return err; 837407353ecSClemens Gruber 838407353ecSClemens Gruber /* PHY reset is necessary after changing MODE[2:0] */ 839407353ecSClemens Gruber temp |= MII_88E1510_GEN_CTRL_REG_1_RESET; 840407353ecSClemens Gruber err = phy_write(phydev, MII_88E1510_GEN_CTRL_REG_1, temp); 841407353ecSClemens Gruber if (err < 0) 842407353ecSClemens Gruber return err; 843407353ecSClemens Gruber 844407353ecSClemens Gruber /* Reset page selection */ 845407353ecSClemens Gruber err = phy_write(phydev, MII_MARVELL_PHY_PAGE, 0); 846407353ecSClemens Gruber if (err < 0) 847407353ecSClemens Gruber return err; 848407353ecSClemens Gruber } 849407353ecSClemens Gruber 850fdecf36fSClemens Gruber return m88e1121_config_init(phydev); 851407353ecSClemens Gruber } 852407353ecSClemens Gruber 853605f196eSRon Madrid static int m88e1118_config_aneg(struct phy_device *phydev) 854605f196eSRon Madrid { 855605f196eSRon Madrid int err; 856605f196eSRon Madrid 857605f196eSRon Madrid err = phy_write(phydev, MII_BMCR, BMCR_RESET); 858605f196eSRon Madrid if (err < 0) 859605f196eSRon Madrid return err; 860605f196eSRon Madrid 861605f196eSRon Madrid err = phy_write(phydev, MII_M1011_PHY_SCR, 862605f196eSRon Madrid MII_M1011_PHY_SCR_AUTO_CROSS); 863605f196eSRon Madrid if (err < 0) 864605f196eSRon Madrid return err; 865605f196eSRon Madrid 866605f196eSRon Madrid err = genphy_config_aneg(phydev); 867605f196eSRon Madrid return 0; 868605f196eSRon Madrid } 869605f196eSRon Madrid 870605f196eSRon Madrid static int m88e1118_config_init(struct phy_device *phydev) 871605f196eSRon Madrid { 872605f196eSRon Madrid int err; 873605f196eSRon Madrid 874605f196eSRon Madrid /* Change address */ 87527d916d6SDavid Daney err = phy_write(phydev, MII_MARVELL_PHY_PAGE, 0x0002); 876605f196eSRon Madrid if (err < 0) 877605f196eSRon Madrid return err; 878605f196eSRon Madrid 879605f196eSRon Madrid /* Enable 1000 Mbit */ 880605f196eSRon Madrid err = phy_write(phydev, 0x15, 0x1070); 881605f196eSRon Madrid if (err < 0) 882605f196eSRon Madrid return err; 883605f196eSRon Madrid 884605f196eSRon Madrid /* Change address */ 88527d916d6SDavid Daney err = phy_write(phydev, MII_MARVELL_PHY_PAGE, 0x0003); 886605f196eSRon Madrid if (err < 0) 887605f196eSRon Madrid return err; 888605f196eSRon Madrid 889605f196eSRon Madrid /* Adjust LED Control */ 8902f495c39SBenjamin Herrenschmidt if (phydev->dev_flags & MARVELL_PHY_M1118_DNS323_LEDS) 8912f495c39SBenjamin Herrenschmidt err = phy_write(phydev, 0x10, 0x1100); 8922f495c39SBenjamin Herrenschmidt else 893605f196eSRon Madrid err = phy_write(phydev, 0x10, 0x021e); 894605f196eSRon Madrid if (err < 0) 895605f196eSRon Madrid return err; 896605f196eSRon Madrid 897cf41a51dSDavid Daney err = marvell_of_reg_init(phydev); 898cf41a51dSDavid Daney if (err < 0) 899cf41a51dSDavid Daney return err; 900cf41a51dSDavid Daney 901605f196eSRon Madrid /* Reset address */ 90227d916d6SDavid Daney err = phy_write(phydev, MII_MARVELL_PHY_PAGE, 0x0); 903605f196eSRon Madrid if (err < 0) 904605f196eSRon Madrid return err; 905605f196eSRon Madrid 906cc90cb3bSSrinivas Kandagatla return phy_write(phydev, MII_BMCR, BMCR_RESET); 907605f196eSRon Madrid } 908605f196eSRon Madrid 90990600732SDavid Daney static int m88e1149_config_init(struct phy_device *phydev) 91090600732SDavid Daney { 91190600732SDavid Daney int err; 91290600732SDavid Daney 91390600732SDavid Daney /* Change address */ 91490600732SDavid Daney err = phy_write(phydev, MII_MARVELL_PHY_PAGE, 0x0002); 91590600732SDavid Daney if (err < 0) 91690600732SDavid Daney return err; 91790600732SDavid Daney 91890600732SDavid Daney /* Enable 1000 Mbit */ 91990600732SDavid Daney err = phy_write(phydev, 0x15, 0x1048); 92090600732SDavid Daney if (err < 0) 92190600732SDavid Daney return err; 92290600732SDavid Daney 923cf41a51dSDavid Daney err = marvell_of_reg_init(phydev); 924cf41a51dSDavid Daney if (err < 0) 925cf41a51dSDavid Daney return err; 926cf41a51dSDavid Daney 92790600732SDavid Daney /* Reset address */ 92890600732SDavid Daney err = phy_write(phydev, MII_MARVELL_PHY_PAGE, 0x0); 92990600732SDavid Daney if (err < 0) 93090600732SDavid Daney return err; 93190600732SDavid Daney 932cc90cb3bSSrinivas Kandagatla return phy_write(phydev, MII_BMCR, BMCR_RESET); 93390600732SDavid Daney } 93490600732SDavid Daney 93576884679SAndy Fleming static int m88e1145_config_init(struct phy_device *phydev) 93676884679SAndy Fleming { 93776884679SAndy Fleming int err; 938b0224175SViet Nga Dao int temp; 93976884679SAndy Fleming 94076884679SAndy Fleming /* Take care of errata E0 & E1 */ 94176884679SAndy Fleming err = phy_write(phydev, 0x1d, 0x001b); 94276884679SAndy Fleming if (err < 0) 94376884679SAndy Fleming return err; 94476884679SAndy Fleming 94576884679SAndy Fleming err = phy_write(phydev, 0x1e, 0x418f); 94676884679SAndy Fleming if (err < 0) 94776884679SAndy Fleming return err; 94876884679SAndy Fleming 94976884679SAndy Fleming err = phy_write(phydev, 0x1d, 0x0016); 95076884679SAndy Fleming if (err < 0) 95176884679SAndy Fleming return err; 95276884679SAndy Fleming 95376884679SAndy Fleming err = phy_write(phydev, 0x1e, 0xa2da); 95476884679SAndy Fleming if (err < 0) 95576884679SAndy Fleming return err; 95676884679SAndy Fleming 957895ee682SKim Phillips if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID) { 95876884679SAndy Fleming int temp = phy_read(phydev, MII_M1145_PHY_EXT_CR); 95976884679SAndy Fleming if (temp < 0) 96076884679SAndy Fleming return temp; 96176884679SAndy Fleming 96276884679SAndy Fleming temp |= (MII_M1145_RGMII_RX_DELAY | MII_M1145_RGMII_TX_DELAY); 96376884679SAndy Fleming 96476884679SAndy Fleming err = phy_write(phydev, MII_M1145_PHY_EXT_CR, temp); 96576884679SAndy Fleming if (err < 0) 96676884679SAndy Fleming return err; 96776884679SAndy Fleming 9682f495c39SBenjamin Herrenschmidt if (phydev->dev_flags & MARVELL_PHY_M1145_FLAGS_RESISTANCE) { 96976884679SAndy Fleming err = phy_write(phydev, 0x1d, 0x0012); 97076884679SAndy Fleming if (err < 0) 97176884679SAndy Fleming return err; 97276884679SAndy Fleming 97376884679SAndy Fleming temp = phy_read(phydev, 0x1e); 97476884679SAndy Fleming if (temp < 0) 97576884679SAndy Fleming return temp; 97676884679SAndy Fleming 97776884679SAndy Fleming temp &= 0xf03f; 97876884679SAndy Fleming temp |= 2 << 9; /* 36 ohm */ 97976884679SAndy Fleming temp |= 2 << 6; /* 39 ohm */ 98076884679SAndy Fleming 98176884679SAndy Fleming err = phy_write(phydev, 0x1e, temp); 98276884679SAndy Fleming if (err < 0) 98376884679SAndy Fleming return err; 98476884679SAndy Fleming 98576884679SAndy Fleming err = phy_write(phydev, 0x1d, 0x3); 98676884679SAndy Fleming if (err < 0) 98776884679SAndy Fleming return err; 98876884679SAndy Fleming 98976884679SAndy Fleming err = phy_write(phydev, 0x1e, 0x8000); 99076884679SAndy Fleming if (err < 0) 99176884679SAndy Fleming return err; 99276884679SAndy Fleming } 99376884679SAndy Fleming } 99476884679SAndy Fleming 995b0224175SViet Nga Dao if (phydev->interface == PHY_INTERFACE_MODE_SGMII) { 996b0224175SViet Nga Dao temp = phy_read(phydev, MII_M1145_PHY_EXT_SR); 997b0224175SViet Nga Dao if (temp < 0) 998b0224175SViet Nga Dao return temp; 999b0224175SViet Nga Dao 100099d881f9SVince Bridgers temp &= ~MII_M1145_HWCFG_MODE_MASK; 1001b0224175SViet Nga Dao temp |= MII_M1145_HWCFG_MODE_SGMII_NO_CLK; 1002b0224175SViet Nga Dao temp |= MII_M1145_HWCFG_FIBER_COPPER_AUTO; 1003b0224175SViet Nga Dao 1004b0224175SViet Nga Dao err = phy_write(phydev, MII_M1145_PHY_EXT_SR, temp); 1005b0224175SViet Nga Dao if (err < 0) 1006b0224175SViet Nga Dao return err; 1007b0224175SViet Nga Dao } 1008b0224175SViet Nga Dao 1009cf41a51dSDavid Daney err = marvell_of_reg_init(phydev); 1010cf41a51dSDavid Daney if (err < 0) 1011cf41a51dSDavid Daney return err; 1012cf41a51dSDavid Daney 101376884679SAndy Fleming return 0; 101476884679SAndy Fleming } 101500db8189SAndy Fleming 10166cfb3bccSCharles-Antoine Couret /** 10176cfb3bccSCharles-Antoine Couret * fiber_lpa_to_ethtool_lpa_t 10186cfb3bccSCharles-Antoine Couret * @lpa: value of the MII_LPA register for fiber link 1019be937f1fSAlexandr Smirnov * 10206cfb3bccSCharles-Antoine Couret * A small helper function that translates MII_LPA 10216cfb3bccSCharles-Antoine Couret * bits to ethtool LP advertisement settings. 10226cfb3bccSCharles-Antoine Couret */ 10236cfb3bccSCharles-Antoine Couret static u32 fiber_lpa_to_ethtool_lpa_t(u32 lpa) 10246cfb3bccSCharles-Antoine Couret { 10256cfb3bccSCharles-Antoine Couret u32 result = 0; 10266cfb3bccSCharles-Antoine Couret 10276cfb3bccSCharles-Antoine Couret if (lpa & LPA_FIBER_1000HALF) 10286cfb3bccSCharles-Antoine Couret result |= ADVERTISED_1000baseT_Half; 10296cfb3bccSCharles-Antoine Couret if (lpa & LPA_FIBER_1000FULL) 10306cfb3bccSCharles-Antoine Couret result |= ADVERTISED_1000baseT_Full; 10316cfb3bccSCharles-Antoine Couret 10326cfb3bccSCharles-Antoine Couret return result; 10336cfb3bccSCharles-Antoine Couret } 10346cfb3bccSCharles-Antoine Couret 10356cfb3bccSCharles-Antoine Couret /** 10366cfb3bccSCharles-Antoine Couret * marvell_update_link - update link status in real time in @phydev 10376cfb3bccSCharles-Antoine Couret * @phydev: target phy_device struct 10386cfb3bccSCharles-Antoine Couret * 10396cfb3bccSCharles-Antoine Couret * Description: Update the value in phydev->link to reflect the 10406cfb3bccSCharles-Antoine Couret * current link value. 10416cfb3bccSCharles-Antoine Couret */ 10426cfb3bccSCharles-Antoine Couret static int marvell_update_link(struct phy_device *phydev, int fiber) 10436cfb3bccSCharles-Antoine Couret { 10446cfb3bccSCharles-Antoine Couret int status; 10456cfb3bccSCharles-Antoine Couret 10466cfb3bccSCharles-Antoine Couret /* Use the generic register for copper link, or specific 10476cfb3bccSCharles-Antoine Couret * register for fiber case */ 10486cfb3bccSCharles-Antoine Couret if (fiber) { 10496cfb3bccSCharles-Antoine Couret status = phy_read(phydev, MII_M1011_PHY_STATUS); 10506cfb3bccSCharles-Antoine Couret if (status < 0) 10516cfb3bccSCharles-Antoine Couret return status; 10526cfb3bccSCharles-Antoine Couret 10536cfb3bccSCharles-Antoine Couret if ((status & REGISTER_LINK_STATUS) == 0) 10546cfb3bccSCharles-Antoine Couret phydev->link = 0; 10556cfb3bccSCharles-Antoine Couret else 10566cfb3bccSCharles-Antoine Couret phydev->link = 1; 10576cfb3bccSCharles-Antoine Couret } else { 10586cfb3bccSCharles-Antoine Couret return genphy_update_link(phydev); 10596cfb3bccSCharles-Antoine Couret } 10606cfb3bccSCharles-Antoine Couret 10616cfb3bccSCharles-Antoine Couret return 0; 10626cfb3bccSCharles-Antoine Couret } 10636cfb3bccSCharles-Antoine Couret 10646cfb3bccSCharles-Antoine Couret /* marvell_read_status_page 10656cfb3bccSCharles-Antoine Couret * 1066be937f1fSAlexandr Smirnov * Description: 1067be937f1fSAlexandr Smirnov * Check the link, then figure out the current state 1068be937f1fSAlexandr Smirnov * by comparing what we advertise with what the link partner 1069be937f1fSAlexandr Smirnov * advertises. Start by checking the gigabit possibilities, 1070be937f1fSAlexandr Smirnov * then move on to 10/100. 1071be937f1fSAlexandr Smirnov */ 10726cfb3bccSCharles-Antoine Couret static int marvell_read_status_page(struct phy_device *phydev, int page) 1073be937f1fSAlexandr Smirnov { 1074be937f1fSAlexandr Smirnov int adv; 1075be937f1fSAlexandr Smirnov int err; 1076be937f1fSAlexandr Smirnov int lpa; 1077357cd64cSRussell King int lpagb; 1078be937f1fSAlexandr Smirnov int status = 0; 10796cfb3bccSCharles-Antoine Couret int fiber; 1080be937f1fSAlexandr Smirnov 10816cfb3bccSCharles-Antoine Couret /* Detect and update the link, but return if there 1082be937f1fSAlexandr Smirnov * was an error */ 10836cfb3bccSCharles-Antoine Couret if (page == MII_M1111_FIBER) 10846cfb3bccSCharles-Antoine Couret fiber = 1; 10856cfb3bccSCharles-Antoine Couret else 10866cfb3bccSCharles-Antoine Couret fiber = 0; 10876cfb3bccSCharles-Antoine Couret 10886cfb3bccSCharles-Antoine Couret err = marvell_update_link(phydev, fiber); 1089be937f1fSAlexandr Smirnov if (err) 1090be937f1fSAlexandr Smirnov return err; 1091be937f1fSAlexandr Smirnov 1092be937f1fSAlexandr Smirnov if (AUTONEG_ENABLE == phydev->autoneg) { 1093be937f1fSAlexandr Smirnov status = phy_read(phydev, MII_M1011_PHY_STATUS); 1094be937f1fSAlexandr Smirnov if (status < 0) 1095be937f1fSAlexandr Smirnov return status; 1096be937f1fSAlexandr Smirnov 1097be937f1fSAlexandr Smirnov lpa = phy_read(phydev, MII_LPA); 1098be937f1fSAlexandr Smirnov if (lpa < 0) 1099be937f1fSAlexandr Smirnov return lpa; 1100be937f1fSAlexandr Smirnov 1101357cd64cSRussell King lpagb = phy_read(phydev, MII_STAT1000); 1102357cd64cSRussell King if (lpagb < 0) 1103357cd64cSRussell King return lpagb; 1104357cd64cSRussell King 1105be937f1fSAlexandr Smirnov adv = phy_read(phydev, MII_ADVERTISE); 1106be937f1fSAlexandr Smirnov if (adv < 0) 1107be937f1fSAlexandr Smirnov return adv; 1108be937f1fSAlexandr Smirnov 1109be937f1fSAlexandr Smirnov lpa &= adv; 1110be937f1fSAlexandr Smirnov 1111be937f1fSAlexandr Smirnov if (status & MII_M1011_PHY_STATUS_FULLDUPLEX) 1112be937f1fSAlexandr Smirnov phydev->duplex = DUPLEX_FULL; 1113be937f1fSAlexandr Smirnov else 1114be937f1fSAlexandr Smirnov phydev->duplex = DUPLEX_HALF; 1115be937f1fSAlexandr Smirnov 1116be937f1fSAlexandr Smirnov status = status & MII_M1011_PHY_STATUS_SPD_MASK; 1117be937f1fSAlexandr Smirnov phydev->pause = phydev->asym_pause = 0; 1118be937f1fSAlexandr Smirnov 1119be937f1fSAlexandr Smirnov switch (status) { 1120be937f1fSAlexandr Smirnov case MII_M1011_PHY_STATUS_1000: 1121be937f1fSAlexandr Smirnov phydev->speed = SPEED_1000; 1122be937f1fSAlexandr Smirnov break; 1123be937f1fSAlexandr Smirnov 1124be937f1fSAlexandr Smirnov case MII_M1011_PHY_STATUS_100: 1125be937f1fSAlexandr Smirnov phydev->speed = SPEED_100; 1126be937f1fSAlexandr Smirnov break; 1127be937f1fSAlexandr Smirnov 1128be937f1fSAlexandr Smirnov default: 1129be937f1fSAlexandr Smirnov phydev->speed = SPEED_10; 1130be937f1fSAlexandr Smirnov break; 1131be937f1fSAlexandr Smirnov } 1132be937f1fSAlexandr Smirnov 11336cfb3bccSCharles-Antoine Couret if (!fiber) { 11346cfb3bccSCharles-Antoine Couret phydev->lp_advertising = mii_stat1000_to_ethtool_lpa_t(lpagb) | 11356cfb3bccSCharles-Antoine Couret mii_lpa_to_ethtool_lpa_t(lpa); 11366cfb3bccSCharles-Antoine Couret 1137be937f1fSAlexandr Smirnov if (phydev->duplex == DUPLEX_FULL) { 1138be937f1fSAlexandr Smirnov phydev->pause = lpa & LPA_PAUSE_CAP ? 1 : 0; 1139be937f1fSAlexandr Smirnov phydev->asym_pause = lpa & LPA_PAUSE_ASYM ? 1 : 0; 1140be937f1fSAlexandr Smirnov } 1141be937f1fSAlexandr Smirnov } else { 11426cfb3bccSCharles-Antoine Couret /* The fiber link is only 1000M capable */ 11436cfb3bccSCharles-Antoine Couret phydev->lp_advertising = fiber_lpa_to_ethtool_lpa_t(lpa); 11446cfb3bccSCharles-Antoine Couret 11456cfb3bccSCharles-Antoine Couret if (phydev->duplex == DUPLEX_FULL) { 11466cfb3bccSCharles-Antoine Couret if (!(lpa & LPA_PAUSE_FIBER)) { 11476cfb3bccSCharles-Antoine Couret phydev->pause = 0; 11486cfb3bccSCharles-Antoine Couret phydev->asym_pause = 0; 11496cfb3bccSCharles-Antoine Couret } else if ((lpa & LPA_PAUSE_ASYM_FIBER)) { 11506cfb3bccSCharles-Antoine Couret phydev->pause = 1; 11516cfb3bccSCharles-Antoine Couret phydev->asym_pause = 1; 11526cfb3bccSCharles-Antoine Couret } else { 11536cfb3bccSCharles-Antoine Couret phydev->pause = 1; 11546cfb3bccSCharles-Antoine Couret phydev->asym_pause = 0; 11556cfb3bccSCharles-Antoine Couret } 11566cfb3bccSCharles-Antoine Couret } 11576cfb3bccSCharles-Antoine Couret } 11586cfb3bccSCharles-Antoine Couret } else { 1159be937f1fSAlexandr Smirnov int bmcr = phy_read(phydev, MII_BMCR); 1160be937f1fSAlexandr Smirnov 1161be937f1fSAlexandr Smirnov if (bmcr < 0) 1162be937f1fSAlexandr Smirnov return bmcr; 1163be937f1fSAlexandr Smirnov 1164be937f1fSAlexandr Smirnov if (bmcr & BMCR_FULLDPLX) 1165be937f1fSAlexandr Smirnov phydev->duplex = DUPLEX_FULL; 1166be937f1fSAlexandr Smirnov else 1167be937f1fSAlexandr Smirnov phydev->duplex = DUPLEX_HALF; 1168be937f1fSAlexandr Smirnov 1169be937f1fSAlexandr Smirnov if (bmcr & BMCR_SPEED1000) 1170be937f1fSAlexandr Smirnov phydev->speed = SPEED_1000; 1171be937f1fSAlexandr Smirnov else if (bmcr & BMCR_SPEED100) 1172be937f1fSAlexandr Smirnov phydev->speed = SPEED_100; 1173be937f1fSAlexandr Smirnov else 1174be937f1fSAlexandr Smirnov phydev->speed = SPEED_10; 1175be937f1fSAlexandr Smirnov 1176be937f1fSAlexandr Smirnov phydev->pause = phydev->asym_pause = 0; 1177357cd64cSRussell King phydev->lp_advertising = 0; 1178be937f1fSAlexandr Smirnov } 1179be937f1fSAlexandr Smirnov 1180be937f1fSAlexandr Smirnov return 0; 1181be937f1fSAlexandr Smirnov } 1182be937f1fSAlexandr Smirnov 11836cfb3bccSCharles-Antoine Couret /* marvell_read_status 11846cfb3bccSCharles-Antoine Couret * 11856cfb3bccSCharles-Antoine Couret * Some Marvell's phys have two modes: fiber and copper. 11866cfb3bccSCharles-Antoine Couret * Both need status checked. 11876cfb3bccSCharles-Antoine Couret * Description: 11886cfb3bccSCharles-Antoine Couret * First, check the fiber link and status. 11896cfb3bccSCharles-Antoine Couret * If the fiber link is down, check the copper link and status which 11906cfb3bccSCharles-Antoine Couret * will be the default value if both link are down. 11916cfb3bccSCharles-Antoine Couret */ 11926cfb3bccSCharles-Antoine Couret static int marvell_read_status(struct phy_device *phydev) 11936cfb3bccSCharles-Antoine Couret { 11946cfb3bccSCharles-Antoine Couret int err; 11956cfb3bccSCharles-Antoine Couret 11966cfb3bccSCharles-Antoine Couret /* Check the fiber mode first */ 11976cfb3bccSCharles-Antoine Couret if (phydev->supported & SUPPORTED_FIBRE) { 11986cfb3bccSCharles-Antoine Couret err = phy_write(phydev, MII_MARVELL_PHY_PAGE, MII_M1111_FIBER); 11996cfb3bccSCharles-Antoine Couret if (err < 0) 12006cfb3bccSCharles-Antoine Couret goto error; 12016cfb3bccSCharles-Antoine Couret 12026cfb3bccSCharles-Antoine Couret err = marvell_read_status_page(phydev, MII_M1111_FIBER); 12036cfb3bccSCharles-Antoine Couret if (err < 0) 12046cfb3bccSCharles-Antoine Couret goto error; 12056cfb3bccSCharles-Antoine Couret 12066cfb3bccSCharles-Antoine Couret /* If the fiber link is up, it is the selected and used link. 12076cfb3bccSCharles-Antoine Couret * In this case, we need to stay in the fiber page. 12086cfb3bccSCharles-Antoine Couret * Please to be careful about that, avoid to restore Copper page 12096cfb3bccSCharles-Antoine Couret * in other functions which could break the behaviour 12106cfb3bccSCharles-Antoine Couret * for some fiber phy like 88E1512. 12116cfb3bccSCharles-Antoine Couret * */ 12126cfb3bccSCharles-Antoine Couret if (phydev->link) 12136cfb3bccSCharles-Antoine Couret return 0; 12146cfb3bccSCharles-Antoine Couret 12156cfb3bccSCharles-Antoine Couret /* If fiber link is down, check and save copper mode state */ 12166cfb3bccSCharles-Antoine Couret err = phy_write(phydev, MII_MARVELL_PHY_PAGE, MII_M1111_COPPER); 12176cfb3bccSCharles-Antoine Couret if (err < 0) 12186cfb3bccSCharles-Antoine Couret goto error; 12196cfb3bccSCharles-Antoine Couret } 12206cfb3bccSCharles-Antoine Couret 12216cfb3bccSCharles-Antoine Couret return marvell_read_status_page(phydev, MII_M1111_COPPER); 12226cfb3bccSCharles-Antoine Couret 12236cfb3bccSCharles-Antoine Couret error: 12246cfb3bccSCharles-Antoine Couret phy_write(phydev, MII_MARVELL_PHY_PAGE, MII_M1111_COPPER); 12256cfb3bccSCharles-Antoine Couret return err; 12266cfb3bccSCharles-Antoine Couret } 12276b358aedSSebastian Hesselbarth static int marvell_aneg_done(struct phy_device *phydev) 12286b358aedSSebastian Hesselbarth { 12296b358aedSSebastian Hesselbarth int retval = phy_read(phydev, MII_M1011_PHY_STATUS); 12306b358aedSSebastian Hesselbarth return (retval < 0) ? retval : (retval & MII_M1011_PHY_STATUS_RESOLVED); 12316b358aedSSebastian Hesselbarth } 12326b358aedSSebastian Hesselbarth 1233dcd07be3SAnatolij Gustschin static int m88e1121_did_interrupt(struct phy_device *phydev) 1234dcd07be3SAnatolij Gustschin { 1235dcd07be3SAnatolij Gustschin int imask; 1236dcd07be3SAnatolij Gustschin 1237dcd07be3SAnatolij Gustschin imask = phy_read(phydev, MII_M1011_IEVENT); 1238dcd07be3SAnatolij Gustschin 1239dcd07be3SAnatolij Gustschin if (imask & MII_M1011_IMASK_INIT) 1240dcd07be3SAnatolij Gustschin return 1; 1241dcd07be3SAnatolij Gustschin 1242dcd07be3SAnatolij Gustschin return 0; 1243dcd07be3SAnatolij Gustschin } 1244dcd07be3SAnatolij Gustschin 12453871c387SMichael Stapelberg static void m88e1318_get_wol(struct phy_device *phydev, struct ethtool_wolinfo *wol) 12463871c387SMichael Stapelberg { 12473871c387SMichael Stapelberg wol->supported = WAKE_MAGIC; 12483871c387SMichael Stapelberg wol->wolopts = 0; 12493871c387SMichael Stapelberg 12503871c387SMichael Stapelberg if (phy_write(phydev, MII_MARVELL_PHY_PAGE, 12513871c387SMichael Stapelberg MII_88E1318S_PHY_WOL_PAGE) < 0) 12523871c387SMichael Stapelberg return; 12533871c387SMichael Stapelberg 12543871c387SMichael Stapelberg if (phy_read(phydev, MII_88E1318S_PHY_WOL_CTRL) & 12553871c387SMichael Stapelberg MII_88E1318S_PHY_WOL_CTRL_MAGIC_PACKET_MATCH_ENABLE) 12563871c387SMichael Stapelberg wol->wolopts |= WAKE_MAGIC; 12573871c387SMichael Stapelberg 12583871c387SMichael Stapelberg if (phy_write(phydev, MII_MARVELL_PHY_PAGE, 0x00) < 0) 12593871c387SMichael Stapelberg return; 12603871c387SMichael Stapelberg } 12613871c387SMichael Stapelberg 12623871c387SMichael Stapelberg static int m88e1318_set_wol(struct phy_device *phydev, struct ethtool_wolinfo *wol) 12633871c387SMichael Stapelberg { 12643871c387SMichael Stapelberg int err, oldpage, temp; 12653871c387SMichael Stapelberg 12663871c387SMichael Stapelberg oldpage = phy_read(phydev, MII_MARVELL_PHY_PAGE); 12673871c387SMichael Stapelberg 12683871c387SMichael Stapelberg if (wol->wolopts & WAKE_MAGIC) { 12693871c387SMichael Stapelberg /* Explicitly switch to page 0x00, just to be sure */ 12703871c387SMichael Stapelberg err = phy_write(phydev, MII_MARVELL_PHY_PAGE, 0x00); 12713871c387SMichael Stapelberg if (err < 0) 12723871c387SMichael Stapelberg return err; 12733871c387SMichael Stapelberg 12743871c387SMichael Stapelberg /* Enable the WOL interrupt */ 12753871c387SMichael Stapelberg temp = phy_read(phydev, MII_88E1318S_PHY_CSIER); 12763871c387SMichael Stapelberg temp |= MII_88E1318S_PHY_CSIER_WOL_EIE; 12773871c387SMichael Stapelberg err = phy_write(phydev, MII_88E1318S_PHY_CSIER, temp); 12783871c387SMichael Stapelberg if (err < 0) 12793871c387SMichael Stapelberg return err; 12803871c387SMichael Stapelberg 12813871c387SMichael Stapelberg err = phy_write(phydev, MII_MARVELL_PHY_PAGE, 12823871c387SMichael Stapelberg MII_88E1318S_PHY_LED_PAGE); 12833871c387SMichael Stapelberg if (err < 0) 12843871c387SMichael Stapelberg return err; 12853871c387SMichael Stapelberg 12863871c387SMichael Stapelberg /* Setup LED[2] as interrupt pin (active low) */ 12873871c387SMichael Stapelberg temp = phy_read(phydev, MII_88E1318S_PHY_LED_TCR); 12883871c387SMichael Stapelberg temp &= ~MII_88E1318S_PHY_LED_TCR_FORCE_INT; 12893871c387SMichael Stapelberg temp |= MII_88E1318S_PHY_LED_TCR_INTn_ENABLE; 12903871c387SMichael Stapelberg temp |= MII_88E1318S_PHY_LED_TCR_INT_ACTIVE_LOW; 12913871c387SMichael Stapelberg err = phy_write(phydev, MII_88E1318S_PHY_LED_TCR, temp); 12923871c387SMichael Stapelberg if (err < 0) 12933871c387SMichael Stapelberg return err; 12943871c387SMichael Stapelberg 12953871c387SMichael Stapelberg err = phy_write(phydev, MII_MARVELL_PHY_PAGE, 12963871c387SMichael Stapelberg MII_88E1318S_PHY_WOL_PAGE); 12973871c387SMichael Stapelberg if (err < 0) 12983871c387SMichael Stapelberg return err; 12993871c387SMichael Stapelberg 13003871c387SMichael Stapelberg /* Store the device address for the magic packet */ 13013871c387SMichael Stapelberg err = phy_write(phydev, MII_88E1318S_PHY_MAGIC_PACKET_WORD2, 13023871c387SMichael Stapelberg ((phydev->attached_dev->dev_addr[5] << 8) | 13033871c387SMichael Stapelberg phydev->attached_dev->dev_addr[4])); 13043871c387SMichael Stapelberg if (err < 0) 13053871c387SMichael Stapelberg return err; 13063871c387SMichael Stapelberg err = phy_write(phydev, MII_88E1318S_PHY_MAGIC_PACKET_WORD1, 13073871c387SMichael Stapelberg ((phydev->attached_dev->dev_addr[3] << 8) | 13083871c387SMichael Stapelberg phydev->attached_dev->dev_addr[2])); 13093871c387SMichael Stapelberg if (err < 0) 13103871c387SMichael Stapelberg return err; 13113871c387SMichael Stapelberg err = phy_write(phydev, MII_88E1318S_PHY_MAGIC_PACKET_WORD0, 13123871c387SMichael Stapelberg ((phydev->attached_dev->dev_addr[1] << 8) | 13133871c387SMichael Stapelberg phydev->attached_dev->dev_addr[0])); 13143871c387SMichael Stapelberg if (err < 0) 13153871c387SMichael Stapelberg return err; 13163871c387SMichael Stapelberg 13173871c387SMichael Stapelberg /* Clear WOL status and enable magic packet matching */ 13183871c387SMichael Stapelberg temp = phy_read(phydev, MII_88E1318S_PHY_WOL_CTRL); 13193871c387SMichael Stapelberg temp |= MII_88E1318S_PHY_WOL_CTRL_CLEAR_WOL_STATUS; 13203871c387SMichael Stapelberg temp |= MII_88E1318S_PHY_WOL_CTRL_MAGIC_PACKET_MATCH_ENABLE; 13213871c387SMichael Stapelberg err = phy_write(phydev, MII_88E1318S_PHY_WOL_CTRL, temp); 13223871c387SMichael Stapelberg if (err < 0) 13233871c387SMichael Stapelberg return err; 13243871c387SMichael Stapelberg } else { 13253871c387SMichael Stapelberg err = phy_write(phydev, MII_MARVELL_PHY_PAGE, 13263871c387SMichael Stapelberg MII_88E1318S_PHY_WOL_PAGE); 13273871c387SMichael Stapelberg if (err < 0) 13283871c387SMichael Stapelberg return err; 13293871c387SMichael Stapelberg 13303871c387SMichael Stapelberg /* Clear WOL status and disable magic packet matching */ 13313871c387SMichael Stapelberg temp = phy_read(phydev, MII_88E1318S_PHY_WOL_CTRL); 13323871c387SMichael Stapelberg temp |= MII_88E1318S_PHY_WOL_CTRL_CLEAR_WOL_STATUS; 13333871c387SMichael Stapelberg temp &= ~MII_88E1318S_PHY_WOL_CTRL_MAGIC_PACKET_MATCH_ENABLE; 13343871c387SMichael Stapelberg err = phy_write(phydev, MII_88E1318S_PHY_WOL_CTRL, temp); 13353871c387SMichael Stapelberg if (err < 0) 13363871c387SMichael Stapelberg return err; 13373871c387SMichael Stapelberg } 13383871c387SMichael Stapelberg 13393871c387SMichael Stapelberg err = phy_write(phydev, MII_MARVELL_PHY_PAGE, oldpage); 13403871c387SMichael Stapelberg if (err < 0) 13413871c387SMichael Stapelberg return err; 13423871c387SMichael Stapelberg 13433871c387SMichael Stapelberg return 0; 13443871c387SMichael Stapelberg } 13453871c387SMichael Stapelberg 1346d2fa47d9SAndrew Lunn static int marvell_get_sset_count(struct phy_device *phydev) 1347d2fa47d9SAndrew Lunn { 13482170fef7SCharles-Antoine Couret if (phydev->supported & SUPPORTED_FIBRE) 1349d2fa47d9SAndrew Lunn return ARRAY_SIZE(marvell_hw_stats); 13502170fef7SCharles-Antoine Couret else 13512170fef7SCharles-Antoine Couret return ARRAY_SIZE(marvell_hw_stats) - NB_FIBER_STATS; 1352d2fa47d9SAndrew Lunn } 1353d2fa47d9SAndrew Lunn 1354d2fa47d9SAndrew Lunn static void marvell_get_strings(struct phy_device *phydev, u8 *data) 1355d2fa47d9SAndrew Lunn { 1356d2fa47d9SAndrew Lunn int i; 1357d2fa47d9SAndrew Lunn 1358d2fa47d9SAndrew Lunn for (i = 0; i < ARRAY_SIZE(marvell_hw_stats); i++) { 1359d2fa47d9SAndrew Lunn memcpy(data + i * ETH_GSTRING_LEN, 1360d2fa47d9SAndrew Lunn marvell_hw_stats[i].string, ETH_GSTRING_LEN); 1361d2fa47d9SAndrew Lunn } 1362d2fa47d9SAndrew Lunn } 1363d2fa47d9SAndrew Lunn 1364d2fa47d9SAndrew Lunn #ifndef UINT64_MAX 1365d2fa47d9SAndrew Lunn #define UINT64_MAX (u64)(~((u64)0)) 1366d2fa47d9SAndrew Lunn #endif 1367d2fa47d9SAndrew Lunn static u64 marvell_get_stat(struct phy_device *phydev, int i) 1368d2fa47d9SAndrew Lunn { 1369d2fa47d9SAndrew Lunn struct marvell_hw_stat stat = marvell_hw_stats[i]; 1370d2fa47d9SAndrew Lunn struct marvell_priv *priv = phydev->priv; 1371321b4d4bSAndrew Lunn int err, oldpage, val; 1372321b4d4bSAndrew Lunn u64 ret; 1373d2fa47d9SAndrew Lunn 1374d2fa47d9SAndrew Lunn oldpage = phy_read(phydev, MII_MARVELL_PHY_PAGE); 1375d2fa47d9SAndrew Lunn err = phy_write(phydev, MII_MARVELL_PHY_PAGE, 1376d2fa47d9SAndrew Lunn stat.page); 1377d2fa47d9SAndrew Lunn if (err < 0) 1378d2fa47d9SAndrew Lunn return UINT64_MAX; 1379d2fa47d9SAndrew Lunn 1380d2fa47d9SAndrew Lunn val = phy_read(phydev, stat.reg); 1381d2fa47d9SAndrew Lunn if (val < 0) { 1382321b4d4bSAndrew Lunn ret = UINT64_MAX; 1383d2fa47d9SAndrew Lunn } else { 1384d2fa47d9SAndrew Lunn val = val & ((1 << stat.bits) - 1); 1385d2fa47d9SAndrew Lunn priv->stats[i] += val; 1386321b4d4bSAndrew Lunn ret = priv->stats[i]; 1387d2fa47d9SAndrew Lunn } 1388d2fa47d9SAndrew Lunn 1389d2fa47d9SAndrew Lunn phy_write(phydev, MII_MARVELL_PHY_PAGE, oldpage); 1390d2fa47d9SAndrew Lunn 1391321b4d4bSAndrew Lunn return ret; 1392d2fa47d9SAndrew Lunn } 1393d2fa47d9SAndrew Lunn 1394d2fa47d9SAndrew Lunn static void marvell_get_stats(struct phy_device *phydev, 1395d2fa47d9SAndrew Lunn struct ethtool_stats *stats, u64 *data) 1396d2fa47d9SAndrew Lunn { 1397d2fa47d9SAndrew Lunn int i; 1398d2fa47d9SAndrew Lunn 1399d2fa47d9SAndrew Lunn for (i = 0; i < ARRAY_SIZE(marvell_hw_stats); i++) 1400d2fa47d9SAndrew Lunn data[i] = marvell_get_stat(phydev, i); 1401d2fa47d9SAndrew Lunn } 1402d2fa47d9SAndrew Lunn 1403d2fa47d9SAndrew Lunn static int marvell_probe(struct phy_device *phydev) 1404d2fa47d9SAndrew Lunn { 1405d2fa47d9SAndrew Lunn struct marvell_priv *priv; 1406d2fa47d9SAndrew Lunn 1407e5a03bfdSAndrew Lunn priv = devm_kzalloc(&phydev->mdio.dev, sizeof(*priv), GFP_KERNEL); 1408d2fa47d9SAndrew Lunn if (!priv) 1409d2fa47d9SAndrew Lunn return -ENOMEM; 1410d2fa47d9SAndrew Lunn 1411d2fa47d9SAndrew Lunn phydev->priv = priv; 1412d2fa47d9SAndrew Lunn 1413d2fa47d9SAndrew Lunn return 0; 1414d2fa47d9SAndrew Lunn } 1415d2fa47d9SAndrew Lunn 1416e5479239SOlof Johansson static struct phy_driver marvell_drivers[] = { 1417e5479239SOlof Johansson { 14182f495c39SBenjamin Herrenschmidt .phy_id = MARVELL_PHY_ID_88E1101, 14192f495c39SBenjamin Herrenschmidt .phy_id_mask = MARVELL_PHY_ID_MASK, 142000db8189SAndy Fleming .name = "Marvell 88E1101", 142100db8189SAndy Fleming .features = PHY_GBIT_FEATURES, 1422d2fa47d9SAndrew Lunn .probe = marvell_probe, 142300db8189SAndy Fleming .flags = PHY_HAS_INTERRUPT, 142479be1a1cSClemens Gruber .config_init = &marvell_config_init, 142500db8189SAndy Fleming .config_aneg = &marvell_config_aneg, 142600db8189SAndy Fleming .read_status = &genphy_read_status, 142700db8189SAndy Fleming .ack_interrupt = &marvell_ack_interrupt, 142800db8189SAndy Fleming .config_intr = &marvell_config_intr, 14290898b448SSebastian Hesselbarth .resume = &genphy_resume, 14300898b448SSebastian Hesselbarth .suspend = &genphy_suspend, 1431d2fa47d9SAndrew Lunn .get_sset_count = marvell_get_sset_count, 1432d2fa47d9SAndrew Lunn .get_strings = marvell_get_strings, 1433d2fa47d9SAndrew Lunn .get_stats = marvell_get_stats, 1434e5479239SOlof Johansson }, 1435e5479239SOlof Johansson { 14362f495c39SBenjamin Herrenschmidt .phy_id = MARVELL_PHY_ID_88E1112, 14372f495c39SBenjamin Herrenschmidt .phy_id_mask = MARVELL_PHY_ID_MASK, 143885cfb534SOlof Johansson .name = "Marvell 88E1112", 143985cfb534SOlof Johansson .features = PHY_GBIT_FEATURES, 144085cfb534SOlof Johansson .flags = PHY_HAS_INTERRUPT, 1441d2fa47d9SAndrew Lunn .probe = marvell_probe, 144285cfb534SOlof Johansson .config_init = &m88e1111_config_init, 144385cfb534SOlof Johansson .config_aneg = &marvell_config_aneg, 144485cfb534SOlof Johansson .read_status = &genphy_read_status, 144585cfb534SOlof Johansson .ack_interrupt = &marvell_ack_interrupt, 144685cfb534SOlof Johansson .config_intr = &marvell_config_intr, 14470898b448SSebastian Hesselbarth .resume = &genphy_resume, 14480898b448SSebastian Hesselbarth .suspend = &genphy_suspend, 1449d2fa47d9SAndrew Lunn .get_sset_count = marvell_get_sset_count, 1450d2fa47d9SAndrew Lunn .get_strings = marvell_get_strings, 1451d2fa47d9SAndrew Lunn .get_stats = marvell_get_stats, 145285cfb534SOlof Johansson }, 145385cfb534SOlof Johansson { 14542f495c39SBenjamin Herrenschmidt .phy_id = MARVELL_PHY_ID_88E1111, 14552f495c39SBenjamin Herrenschmidt .phy_id_mask = MARVELL_PHY_ID_MASK, 145676884679SAndy Fleming .name = "Marvell 88E1111", 145776884679SAndy Fleming .features = PHY_GBIT_FEATURES, 145876884679SAndy Fleming .flags = PHY_HAS_INTERRUPT, 1459d2fa47d9SAndrew Lunn .probe = marvell_probe, 1460e5479239SOlof Johansson .config_init = &m88e1111_config_init, 14613ec0a0f1SHarini Katakam .config_aneg = &m88e1111_config_aneg, 1462be937f1fSAlexandr Smirnov .read_status = &marvell_read_status, 146376884679SAndy Fleming .ack_interrupt = &marvell_ack_interrupt, 146476884679SAndy Fleming .config_intr = &marvell_config_intr, 14650898b448SSebastian Hesselbarth .resume = &genphy_resume, 14660898b448SSebastian Hesselbarth .suspend = &genphy_suspend, 1467d2fa47d9SAndrew Lunn .get_sset_count = marvell_get_sset_count, 1468d2fa47d9SAndrew Lunn .get_strings = marvell_get_strings, 1469d2fa47d9SAndrew Lunn .get_stats = marvell_get_stats, 1470e5479239SOlof Johansson }, 1471e5479239SOlof Johansson { 14722f495c39SBenjamin Herrenschmidt .phy_id = MARVELL_PHY_ID_88E1118, 14732f495c39SBenjamin Herrenschmidt .phy_id_mask = MARVELL_PHY_ID_MASK, 1474605f196eSRon Madrid .name = "Marvell 88E1118", 1475605f196eSRon Madrid .features = PHY_GBIT_FEATURES, 1476605f196eSRon Madrid .flags = PHY_HAS_INTERRUPT, 1477d2fa47d9SAndrew Lunn .probe = marvell_probe, 1478605f196eSRon Madrid .config_init = &m88e1118_config_init, 1479605f196eSRon Madrid .config_aneg = &m88e1118_config_aneg, 1480605f196eSRon Madrid .read_status = &genphy_read_status, 1481605f196eSRon Madrid .ack_interrupt = &marvell_ack_interrupt, 1482605f196eSRon Madrid .config_intr = &marvell_config_intr, 14830898b448SSebastian Hesselbarth .resume = &genphy_resume, 14840898b448SSebastian Hesselbarth .suspend = &genphy_suspend, 1485d2fa47d9SAndrew Lunn .get_sset_count = marvell_get_sset_count, 1486d2fa47d9SAndrew Lunn .get_strings = marvell_get_strings, 1487d2fa47d9SAndrew Lunn .get_stats = marvell_get_stats, 1488605f196eSRon Madrid }, 1489605f196eSRon Madrid { 14902f495c39SBenjamin Herrenschmidt .phy_id = MARVELL_PHY_ID_88E1121R, 14912f495c39SBenjamin Herrenschmidt .phy_id_mask = MARVELL_PHY_ID_MASK, 1492140bc929SSergei Poselenov .name = "Marvell 88E1121R", 1493140bc929SSergei Poselenov .features = PHY_GBIT_FEATURES, 1494140bc929SSergei Poselenov .flags = PHY_HAS_INTERRUPT, 1495d2fa47d9SAndrew Lunn .probe = marvell_probe, 1496fdecf36fSClemens Gruber .config_init = &m88e1121_config_init, 1497140bc929SSergei Poselenov .config_aneg = &m88e1121_config_aneg, 1498140bc929SSergei Poselenov .read_status = &marvell_read_status, 1499140bc929SSergei Poselenov .ack_interrupt = &marvell_ack_interrupt, 1500140bc929SSergei Poselenov .config_intr = &marvell_config_intr, 1501dcd07be3SAnatolij Gustschin .did_interrupt = &m88e1121_did_interrupt, 15020898b448SSebastian Hesselbarth .resume = &genphy_resume, 15030898b448SSebastian Hesselbarth .suspend = &genphy_suspend, 1504d2fa47d9SAndrew Lunn .get_sset_count = marvell_get_sset_count, 1505d2fa47d9SAndrew Lunn .get_strings = marvell_get_strings, 1506d2fa47d9SAndrew Lunn .get_stats = marvell_get_stats, 1507140bc929SSergei Poselenov }, 1508140bc929SSergei Poselenov { 1509337ac9d5SCyril Chemparathy .phy_id = MARVELL_PHY_ID_88E1318S, 15106ba74014SLinus Torvalds .phy_id_mask = MARVELL_PHY_ID_MASK, 1511337ac9d5SCyril Chemparathy .name = "Marvell 88E1318S", 15123ff1c259SCyril Chemparathy .features = PHY_GBIT_FEATURES, 15133ff1c259SCyril Chemparathy .flags = PHY_HAS_INTERRUPT, 1514d2fa47d9SAndrew Lunn .probe = marvell_probe, 1515fdecf36fSClemens Gruber .config_init = &m88e1121_config_init, 1516337ac9d5SCyril Chemparathy .config_aneg = &m88e1318_config_aneg, 15173ff1c259SCyril Chemparathy .read_status = &marvell_read_status, 15183ff1c259SCyril Chemparathy .ack_interrupt = &marvell_ack_interrupt, 15193ff1c259SCyril Chemparathy .config_intr = &marvell_config_intr, 15203ff1c259SCyril Chemparathy .did_interrupt = &m88e1121_did_interrupt, 15213871c387SMichael Stapelberg .get_wol = &m88e1318_get_wol, 15223871c387SMichael Stapelberg .set_wol = &m88e1318_set_wol, 15230898b448SSebastian Hesselbarth .resume = &genphy_resume, 15240898b448SSebastian Hesselbarth .suspend = &genphy_suspend, 1525d2fa47d9SAndrew Lunn .get_sset_count = marvell_get_sset_count, 1526d2fa47d9SAndrew Lunn .get_strings = marvell_get_strings, 1527d2fa47d9SAndrew Lunn .get_stats = marvell_get_stats, 15283ff1c259SCyril Chemparathy }, 15293ff1c259SCyril Chemparathy { 15302f495c39SBenjamin Herrenschmidt .phy_id = MARVELL_PHY_ID_88E1145, 15312f495c39SBenjamin Herrenschmidt .phy_id_mask = MARVELL_PHY_ID_MASK, 153276884679SAndy Fleming .name = "Marvell 88E1145", 153376884679SAndy Fleming .features = PHY_GBIT_FEATURES, 153476884679SAndy Fleming .flags = PHY_HAS_INTERRUPT, 1535d2fa47d9SAndrew Lunn .probe = marvell_probe, 153676884679SAndy Fleming .config_init = &m88e1145_config_init, 153776884679SAndy Fleming .config_aneg = &marvell_config_aneg, 153876884679SAndy Fleming .read_status = &genphy_read_status, 153976884679SAndy Fleming .ack_interrupt = &marvell_ack_interrupt, 154076884679SAndy Fleming .config_intr = &marvell_config_intr, 15410898b448SSebastian Hesselbarth .resume = &genphy_resume, 15420898b448SSebastian Hesselbarth .suspend = &genphy_suspend, 1543d2fa47d9SAndrew Lunn .get_sset_count = marvell_get_sset_count, 1544d2fa47d9SAndrew Lunn .get_strings = marvell_get_strings, 1545d2fa47d9SAndrew Lunn .get_stats = marvell_get_stats, 1546ac8c635aSOlof Johansson }, 1547ac8c635aSOlof Johansson { 154890600732SDavid Daney .phy_id = MARVELL_PHY_ID_88E1149R, 154990600732SDavid Daney .phy_id_mask = MARVELL_PHY_ID_MASK, 155090600732SDavid Daney .name = "Marvell 88E1149R", 155190600732SDavid Daney .features = PHY_GBIT_FEATURES, 155290600732SDavid Daney .flags = PHY_HAS_INTERRUPT, 1553d2fa47d9SAndrew Lunn .probe = marvell_probe, 155490600732SDavid Daney .config_init = &m88e1149_config_init, 155590600732SDavid Daney .config_aneg = &m88e1118_config_aneg, 155690600732SDavid Daney .read_status = &genphy_read_status, 155790600732SDavid Daney .ack_interrupt = &marvell_ack_interrupt, 155890600732SDavid Daney .config_intr = &marvell_config_intr, 15590898b448SSebastian Hesselbarth .resume = &genphy_resume, 15600898b448SSebastian Hesselbarth .suspend = &genphy_suspend, 1561d2fa47d9SAndrew Lunn .get_sset_count = marvell_get_sset_count, 1562d2fa47d9SAndrew Lunn .get_strings = marvell_get_strings, 1563d2fa47d9SAndrew Lunn .get_stats = marvell_get_stats, 156490600732SDavid Daney }, 156590600732SDavid Daney { 15662f495c39SBenjamin Herrenschmidt .phy_id = MARVELL_PHY_ID_88E1240, 15672f495c39SBenjamin Herrenschmidt .phy_id_mask = MARVELL_PHY_ID_MASK, 1568ac8c635aSOlof Johansson .name = "Marvell 88E1240", 1569ac8c635aSOlof Johansson .features = PHY_GBIT_FEATURES, 1570ac8c635aSOlof Johansson .flags = PHY_HAS_INTERRUPT, 1571d2fa47d9SAndrew Lunn .probe = marvell_probe, 1572ac8c635aSOlof Johansson .config_init = &m88e1111_config_init, 1573ac8c635aSOlof Johansson .config_aneg = &marvell_config_aneg, 1574ac8c635aSOlof Johansson .read_status = &genphy_read_status, 1575ac8c635aSOlof Johansson .ack_interrupt = &marvell_ack_interrupt, 1576ac8c635aSOlof Johansson .config_intr = &marvell_config_intr, 15770898b448SSebastian Hesselbarth .resume = &genphy_resume, 15780898b448SSebastian Hesselbarth .suspend = &genphy_suspend, 1579d2fa47d9SAndrew Lunn .get_sset_count = marvell_get_sset_count, 1580d2fa47d9SAndrew Lunn .get_strings = marvell_get_strings, 1581d2fa47d9SAndrew Lunn .get_stats = marvell_get_stats, 1582ac8c635aSOlof Johansson }, 15833da09a51SMichal Simek { 15843da09a51SMichal Simek .phy_id = MARVELL_PHY_ID_88E1116R, 15853da09a51SMichal Simek .phy_id_mask = MARVELL_PHY_ID_MASK, 15863da09a51SMichal Simek .name = "Marvell 88E1116R", 15873da09a51SMichal Simek .features = PHY_GBIT_FEATURES, 15883da09a51SMichal Simek .flags = PHY_HAS_INTERRUPT, 1589d2fa47d9SAndrew Lunn .probe = marvell_probe, 15903da09a51SMichal Simek .config_init = &m88e1116r_config_init, 15913da09a51SMichal Simek .config_aneg = &genphy_config_aneg, 15923da09a51SMichal Simek .read_status = &genphy_read_status, 15933da09a51SMichal Simek .ack_interrupt = &marvell_ack_interrupt, 15943da09a51SMichal Simek .config_intr = &marvell_config_intr, 15950898b448SSebastian Hesselbarth .resume = &genphy_resume, 15960898b448SSebastian Hesselbarth .suspend = &genphy_suspend, 1597d2fa47d9SAndrew Lunn .get_sset_count = marvell_get_sset_count, 1598d2fa47d9SAndrew Lunn .get_strings = marvell_get_strings, 1599d2fa47d9SAndrew Lunn .get_stats = marvell_get_stats, 16003da09a51SMichal Simek }, 160110e24caaSMichal Simek { 160210e24caaSMichal Simek .phy_id = MARVELL_PHY_ID_88E1510, 160310e24caaSMichal Simek .phy_id_mask = MARVELL_PHY_ID_MASK, 160410e24caaSMichal Simek .name = "Marvell 88E1510", 16056cfb3bccSCharles-Antoine Couret .features = PHY_GBIT_FEATURES | SUPPORTED_FIBRE, 160610e24caaSMichal Simek .flags = PHY_HAS_INTERRUPT, 1607d2fa47d9SAndrew Lunn .probe = marvell_probe, 1608930b37eeSStefan Roese .config_init = &m88e1510_config_init, 160910e24caaSMichal Simek .config_aneg = &m88e1510_config_aneg, 161010e24caaSMichal Simek .read_status = &marvell_read_status, 161110e24caaSMichal Simek .ack_interrupt = &marvell_ack_interrupt, 161210e24caaSMichal Simek .config_intr = &marvell_config_intr, 161310e24caaSMichal Simek .did_interrupt = &m88e1121_did_interrupt, 16140898b448SSebastian Hesselbarth .resume = &genphy_resume, 16150898b448SSebastian Hesselbarth .suspend = &genphy_suspend, 1616d2fa47d9SAndrew Lunn .get_sset_count = marvell_get_sset_count, 1617d2fa47d9SAndrew Lunn .get_strings = marvell_get_strings, 1618d2fa47d9SAndrew Lunn .get_stats = marvell_get_stats, 161910e24caaSMichal Simek }, 16206b358aedSSebastian Hesselbarth { 1621819ec8e1SAndrew Lunn .phy_id = MARVELL_PHY_ID_88E1540, 1622819ec8e1SAndrew Lunn .phy_id_mask = MARVELL_PHY_ID_MASK, 1623819ec8e1SAndrew Lunn .name = "Marvell 88E1540", 1624819ec8e1SAndrew Lunn .features = PHY_GBIT_FEATURES, 1625819ec8e1SAndrew Lunn .flags = PHY_HAS_INTERRUPT, 1626d2fa47d9SAndrew Lunn .probe = marvell_probe, 162779be1a1cSClemens Gruber .config_init = &marvell_config_init, 1628819ec8e1SAndrew Lunn .config_aneg = &m88e1510_config_aneg, 1629819ec8e1SAndrew Lunn .read_status = &marvell_read_status, 1630819ec8e1SAndrew Lunn .ack_interrupt = &marvell_ack_interrupt, 1631819ec8e1SAndrew Lunn .config_intr = &marvell_config_intr, 1632819ec8e1SAndrew Lunn .did_interrupt = &m88e1121_did_interrupt, 1633819ec8e1SAndrew Lunn .resume = &genphy_resume, 1634819ec8e1SAndrew Lunn .suspend = &genphy_suspend, 1635d2fa47d9SAndrew Lunn .get_sset_count = marvell_get_sset_count, 1636d2fa47d9SAndrew Lunn .get_strings = marvell_get_strings, 1637d2fa47d9SAndrew Lunn .get_stats = marvell_get_stats, 1638819ec8e1SAndrew Lunn }, 1639819ec8e1SAndrew Lunn { 16406b358aedSSebastian Hesselbarth .phy_id = MARVELL_PHY_ID_88E3016, 16416b358aedSSebastian Hesselbarth .phy_id_mask = MARVELL_PHY_ID_MASK, 16426b358aedSSebastian Hesselbarth .name = "Marvell 88E3016", 16436b358aedSSebastian Hesselbarth .features = PHY_BASIC_FEATURES, 16446b358aedSSebastian Hesselbarth .flags = PHY_HAS_INTERRUPT, 1645d2fa47d9SAndrew Lunn .probe = marvell_probe, 16466b358aedSSebastian Hesselbarth .config_aneg = &genphy_config_aneg, 16476b358aedSSebastian Hesselbarth .config_init = &m88e3016_config_init, 16486b358aedSSebastian Hesselbarth .aneg_done = &marvell_aneg_done, 16496b358aedSSebastian Hesselbarth .read_status = &marvell_read_status, 16506b358aedSSebastian Hesselbarth .ack_interrupt = &marvell_ack_interrupt, 16516b358aedSSebastian Hesselbarth .config_intr = &marvell_config_intr, 16526b358aedSSebastian Hesselbarth .did_interrupt = &m88e1121_did_interrupt, 16536b358aedSSebastian Hesselbarth .resume = &genphy_resume, 16546b358aedSSebastian Hesselbarth .suspend = &genphy_suspend, 1655d2fa47d9SAndrew Lunn .get_sset_count = marvell_get_sset_count, 1656d2fa47d9SAndrew Lunn .get_strings = marvell_get_strings, 1657d2fa47d9SAndrew Lunn .get_stats = marvell_get_stats, 16586b358aedSSebastian Hesselbarth }, 165976884679SAndy Fleming }; 166076884679SAndy Fleming 166150fd7150SJohan Hovold module_phy_driver(marvell_drivers); 16624e4f10f6SDavid Woodhouse 1663cf93c945SUwe Kleine-König static struct mdio_device_id __maybe_unused marvell_tbl[] = { 1664f5e1cabfSMichal Simek { MARVELL_PHY_ID_88E1101, MARVELL_PHY_ID_MASK }, 1665f5e1cabfSMichal Simek { MARVELL_PHY_ID_88E1112, MARVELL_PHY_ID_MASK }, 1666f5e1cabfSMichal Simek { MARVELL_PHY_ID_88E1111, MARVELL_PHY_ID_MASK }, 1667f5e1cabfSMichal Simek { MARVELL_PHY_ID_88E1118, MARVELL_PHY_ID_MASK }, 1668f5e1cabfSMichal Simek { MARVELL_PHY_ID_88E1121R, MARVELL_PHY_ID_MASK }, 1669f5e1cabfSMichal Simek { MARVELL_PHY_ID_88E1145, MARVELL_PHY_ID_MASK }, 1670f5e1cabfSMichal Simek { MARVELL_PHY_ID_88E1149R, MARVELL_PHY_ID_MASK }, 1671f5e1cabfSMichal Simek { MARVELL_PHY_ID_88E1240, MARVELL_PHY_ID_MASK }, 1672f5e1cabfSMichal Simek { MARVELL_PHY_ID_88E1318S, MARVELL_PHY_ID_MASK }, 16733da09a51SMichal Simek { MARVELL_PHY_ID_88E1116R, MARVELL_PHY_ID_MASK }, 167410e24caaSMichal Simek { MARVELL_PHY_ID_88E1510, MARVELL_PHY_ID_MASK }, 1675819ec8e1SAndrew Lunn { MARVELL_PHY_ID_88E1540, MARVELL_PHY_ID_MASK }, 16766b358aedSSebastian Hesselbarth { MARVELL_PHY_ID_88E3016, MARVELL_PHY_ID_MASK }, 16774e4f10f6SDavid Woodhouse { } 16784e4f10f6SDavid Woodhouse }; 16794e4f10f6SDavid Woodhouse 16804e4f10f6SDavid Woodhouse MODULE_DEVICE_TABLE(mdio, marvell_tbl); 1681