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 1546cfb3bccSCharles-Antoine Couret 15500db8189SAndy Fleming MODULE_DESCRIPTION("Marvell PHY driver"); 15600db8189SAndy Fleming MODULE_AUTHOR("Andy Fleming"); 15700db8189SAndy Fleming MODULE_LICENSE("GPL"); 15800db8189SAndy Fleming 159d2fa47d9SAndrew Lunn struct marvell_hw_stat { 160d2fa47d9SAndrew Lunn const char *string; 161d2fa47d9SAndrew Lunn u8 page; 162d2fa47d9SAndrew Lunn u8 reg; 163d2fa47d9SAndrew Lunn u8 bits; 164d2fa47d9SAndrew Lunn }; 165d2fa47d9SAndrew Lunn 166d2fa47d9SAndrew Lunn static struct marvell_hw_stat marvell_hw_stats[] = { 167d2fa47d9SAndrew Lunn { "phy_receive_errors", 0, 21, 16}, 168d2fa47d9SAndrew Lunn { "phy_idle_errors", 0, 10, 8 }, 169d2fa47d9SAndrew Lunn }; 170d2fa47d9SAndrew Lunn 171d2fa47d9SAndrew Lunn struct marvell_priv { 172d2fa47d9SAndrew Lunn u64 stats[ARRAY_SIZE(marvell_hw_stats)]; 173d2fa47d9SAndrew Lunn }; 174d2fa47d9SAndrew Lunn 17500db8189SAndy Fleming static int marvell_ack_interrupt(struct phy_device *phydev) 17600db8189SAndy Fleming { 17700db8189SAndy Fleming int err; 17800db8189SAndy Fleming 17900db8189SAndy Fleming /* Clear the interrupts by reading the reg */ 18000db8189SAndy Fleming err = phy_read(phydev, MII_M1011_IEVENT); 18100db8189SAndy Fleming 18200db8189SAndy Fleming if (err < 0) 18300db8189SAndy Fleming return err; 18400db8189SAndy Fleming 18500db8189SAndy Fleming return 0; 18600db8189SAndy Fleming } 18700db8189SAndy Fleming 18800db8189SAndy Fleming static int marvell_config_intr(struct phy_device *phydev) 18900db8189SAndy Fleming { 19000db8189SAndy Fleming int err; 19100db8189SAndy Fleming 19200db8189SAndy Fleming if (phydev->interrupts == PHY_INTERRUPT_ENABLED) 19300db8189SAndy Fleming err = phy_write(phydev, MII_M1011_IMASK, MII_M1011_IMASK_INIT); 19400db8189SAndy Fleming else 19500db8189SAndy Fleming err = phy_write(phydev, MII_M1011_IMASK, MII_M1011_IMASK_CLEAR); 19600db8189SAndy Fleming 19700db8189SAndy Fleming return err; 19800db8189SAndy Fleming } 19900db8189SAndy Fleming 200239aa55bSDavid Thomson static int marvell_set_polarity(struct phy_device *phydev, int polarity) 201239aa55bSDavid Thomson { 202239aa55bSDavid Thomson int reg; 203239aa55bSDavid Thomson int err; 204239aa55bSDavid Thomson int val; 205239aa55bSDavid Thomson 206239aa55bSDavid Thomson /* get the current settings */ 207239aa55bSDavid Thomson reg = phy_read(phydev, MII_M1011_PHY_SCR); 208239aa55bSDavid Thomson if (reg < 0) 209239aa55bSDavid Thomson return reg; 210239aa55bSDavid Thomson 211239aa55bSDavid Thomson val = reg; 212239aa55bSDavid Thomson val &= ~MII_M1011_PHY_SCR_AUTO_CROSS; 213239aa55bSDavid Thomson switch (polarity) { 214239aa55bSDavid Thomson case ETH_TP_MDI: 215239aa55bSDavid Thomson val |= MII_M1011_PHY_SCR_MDI; 216239aa55bSDavid Thomson break; 217239aa55bSDavid Thomson case ETH_TP_MDI_X: 218239aa55bSDavid Thomson val |= MII_M1011_PHY_SCR_MDI_X; 219239aa55bSDavid Thomson break; 220239aa55bSDavid Thomson case ETH_TP_MDI_AUTO: 221239aa55bSDavid Thomson case ETH_TP_MDI_INVALID: 222239aa55bSDavid Thomson default: 223239aa55bSDavid Thomson val |= MII_M1011_PHY_SCR_AUTO_CROSS; 224239aa55bSDavid Thomson break; 225239aa55bSDavid Thomson } 226239aa55bSDavid Thomson 227239aa55bSDavid Thomson if (val != reg) { 228239aa55bSDavid Thomson /* Set the new polarity value in the register */ 229239aa55bSDavid Thomson err = phy_write(phydev, MII_M1011_PHY_SCR, val); 230239aa55bSDavid Thomson if (err) 231239aa55bSDavid Thomson return err; 232239aa55bSDavid Thomson } 233239aa55bSDavid Thomson 234239aa55bSDavid Thomson return 0; 235239aa55bSDavid Thomson } 236239aa55bSDavid Thomson 23700db8189SAndy Fleming static int marvell_config_aneg(struct phy_device *phydev) 23800db8189SAndy Fleming { 23900db8189SAndy Fleming int err; 24000db8189SAndy Fleming 24100db8189SAndy Fleming /* The Marvell PHY has an errata which requires 24200db8189SAndy Fleming * that certain registers get written in order 24300db8189SAndy Fleming * to restart autonegotiation */ 24400db8189SAndy Fleming err = phy_write(phydev, MII_BMCR, BMCR_RESET); 24500db8189SAndy Fleming 24600db8189SAndy Fleming if (err < 0) 24700db8189SAndy Fleming return err; 24800db8189SAndy Fleming 24900db8189SAndy Fleming err = phy_write(phydev, 0x1d, 0x1f); 25000db8189SAndy Fleming if (err < 0) 25100db8189SAndy Fleming return err; 25200db8189SAndy Fleming 25300db8189SAndy Fleming err = phy_write(phydev, 0x1e, 0x200c); 25400db8189SAndy Fleming if (err < 0) 25500db8189SAndy Fleming return err; 25600db8189SAndy Fleming 25700db8189SAndy Fleming err = phy_write(phydev, 0x1d, 0x5); 25800db8189SAndy Fleming if (err < 0) 25900db8189SAndy Fleming return err; 26000db8189SAndy Fleming 26100db8189SAndy Fleming err = phy_write(phydev, 0x1e, 0); 26200db8189SAndy Fleming if (err < 0) 26300db8189SAndy Fleming return err; 26400db8189SAndy Fleming 26500db8189SAndy Fleming err = phy_write(phydev, 0x1e, 0x100); 26600db8189SAndy Fleming if (err < 0) 26700db8189SAndy Fleming return err; 26800db8189SAndy Fleming 269239aa55bSDavid Thomson err = marvell_set_polarity(phydev, phydev->mdix); 27076884679SAndy Fleming if (err < 0) 27176884679SAndy Fleming return err; 27276884679SAndy Fleming 27376884679SAndy Fleming err = phy_write(phydev, MII_M1111_PHY_LED_CONTROL, 27476884679SAndy Fleming MII_M1111_PHY_LED_DIRECT); 27576884679SAndy Fleming if (err < 0) 27676884679SAndy Fleming return err; 27700db8189SAndy Fleming 27800db8189SAndy Fleming err = genphy_config_aneg(phydev); 2798ff44985SAnton Vorontsov if (err < 0) 28000db8189SAndy Fleming return err; 2818ff44985SAnton Vorontsov 2828ff44985SAnton Vorontsov if (phydev->autoneg != AUTONEG_ENABLE) { 2838ff44985SAnton Vorontsov int bmcr; 2848ff44985SAnton Vorontsov 2858ff44985SAnton Vorontsov /* 2868ff44985SAnton Vorontsov * A write to speed/duplex bits (that is performed by 2878ff44985SAnton Vorontsov * genphy_config_aneg() call above) must be followed by 2888ff44985SAnton Vorontsov * a software reset. Otherwise, the write has no effect. 2898ff44985SAnton Vorontsov */ 2908ff44985SAnton Vorontsov bmcr = phy_read(phydev, MII_BMCR); 2918ff44985SAnton Vorontsov if (bmcr < 0) 2928ff44985SAnton Vorontsov return bmcr; 2938ff44985SAnton Vorontsov 2948ff44985SAnton Vorontsov err = phy_write(phydev, MII_BMCR, bmcr | BMCR_RESET); 2958ff44985SAnton Vorontsov if (err < 0) 2968ff44985SAnton Vorontsov return err; 2978ff44985SAnton Vorontsov } 2988ff44985SAnton Vorontsov 2998ff44985SAnton Vorontsov return 0; 30000db8189SAndy Fleming } 30100db8189SAndy Fleming 3023ec0a0f1SHarini Katakam static int m88e1111_config_aneg(struct phy_device *phydev) 3033ec0a0f1SHarini Katakam { 3043ec0a0f1SHarini Katakam int err; 3053ec0a0f1SHarini Katakam 3063ec0a0f1SHarini Katakam /* The Marvell PHY has an errata which requires 3073ec0a0f1SHarini Katakam * that certain registers get written in order 3083ec0a0f1SHarini Katakam * to restart autonegotiation 3093ec0a0f1SHarini Katakam */ 3103ec0a0f1SHarini Katakam err = phy_write(phydev, MII_BMCR, BMCR_RESET); 3113ec0a0f1SHarini Katakam 3123ec0a0f1SHarini Katakam err = marvell_set_polarity(phydev, phydev->mdix); 3133ec0a0f1SHarini Katakam if (err < 0) 3143ec0a0f1SHarini Katakam return err; 3153ec0a0f1SHarini Katakam 3163ec0a0f1SHarini Katakam err = phy_write(phydev, MII_M1111_PHY_LED_CONTROL, 3173ec0a0f1SHarini Katakam MII_M1111_PHY_LED_DIRECT); 3183ec0a0f1SHarini Katakam if (err < 0) 3193ec0a0f1SHarini Katakam return err; 3203ec0a0f1SHarini Katakam 3213ec0a0f1SHarini Katakam err = genphy_config_aneg(phydev); 3223ec0a0f1SHarini Katakam if (err < 0) 3233ec0a0f1SHarini Katakam return err; 3243ec0a0f1SHarini Katakam 3253ec0a0f1SHarini Katakam if (phydev->autoneg != AUTONEG_ENABLE) { 3263ec0a0f1SHarini Katakam int bmcr; 3273ec0a0f1SHarini Katakam 3283ec0a0f1SHarini Katakam /* A write to speed/duplex bits (that is performed by 3293ec0a0f1SHarini Katakam * genphy_config_aneg() call above) must be followed by 3303ec0a0f1SHarini Katakam * a software reset. Otherwise, the write has no effect. 3313ec0a0f1SHarini Katakam */ 3323ec0a0f1SHarini Katakam bmcr = phy_read(phydev, MII_BMCR); 3333ec0a0f1SHarini Katakam if (bmcr < 0) 3343ec0a0f1SHarini Katakam return bmcr; 3353ec0a0f1SHarini Katakam 3363ec0a0f1SHarini Katakam err = phy_write(phydev, MII_BMCR, bmcr | BMCR_RESET); 3373ec0a0f1SHarini Katakam if (err < 0) 3383ec0a0f1SHarini Katakam return err; 3393ec0a0f1SHarini Katakam } 3403ec0a0f1SHarini Katakam 3413ec0a0f1SHarini Katakam return 0; 3423ec0a0f1SHarini Katakam } 3433ec0a0f1SHarini Katakam 344cf41a51dSDavid Daney #ifdef CONFIG_OF_MDIO 345cf41a51dSDavid Daney /* 346cf41a51dSDavid Daney * Set and/or override some configuration registers based on the 347cf41a51dSDavid Daney * marvell,reg-init property stored in the of_node for the phydev. 348cf41a51dSDavid Daney * 349cf41a51dSDavid Daney * marvell,reg-init = <reg-page reg mask value>,...; 350cf41a51dSDavid Daney * 351cf41a51dSDavid Daney * There may be one or more sets of <reg-page reg mask value>: 352cf41a51dSDavid Daney * 353cf41a51dSDavid Daney * reg-page: which register bank to use. 354cf41a51dSDavid Daney * reg: the register. 355cf41a51dSDavid Daney * mask: if non-zero, ANDed with existing register value. 356cf41a51dSDavid Daney * value: ORed with the masked value and written to the regiser. 357cf41a51dSDavid Daney * 358cf41a51dSDavid Daney */ 359cf41a51dSDavid Daney static int marvell_of_reg_init(struct phy_device *phydev) 360cf41a51dSDavid Daney { 361cf41a51dSDavid Daney const __be32 *paddr; 362cf41a51dSDavid Daney int len, i, saved_page, current_page, page_changed, ret; 363cf41a51dSDavid Daney 364e5a03bfdSAndrew Lunn if (!phydev->mdio.dev.of_node) 365cf41a51dSDavid Daney return 0; 366cf41a51dSDavid Daney 367e5a03bfdSAndrew Lunn paddr = of_get_property(phydev->mdio.dev.of_node, 368e5a03bfdSAndrew Lunn "marvell,reg-init", &len); 369cf41a51dSDavid Daney if (!paddr || len < (4 * sizeof(*paddr))) 370cf41a51dSDavid Daney return 0; 371cf41a51dSDavid Daney 372cf41a51dSDavid Daney saved_page = phy_read(phydev, MII_MARVELL_PHY_PAGE); 373cf41a51dSDavid Daney if (saved_page < 0) 374cf41a51dSDavid Daney return saved_page; 375cf41a51dSDavid Daney page_changed = 0; 376cf41a51dSDavid Daney current_page = saved_page; 377cf41a51dSDavid Daney 378cf41a51dSDavid Daney ret = 0; 379cf41a51dSDavid Daney len /= sizeof(*paddr); 380cf41a51dSDavid Daney for (i = 0; i < len - 3; i += 4) { 381cf41a51dSDavid Daney u16 reg_page = be32_to_cpup(paddr + i); 382cf41a51dSDavid Daney u16 reg = be32_to_cpup(paddr + i + 1); 383cf41a51dSDavid Daney u16 mask = be32_to_cpup(paddr + i + 2); 384cf41a51dSDavid Daney u16 val_bits = be32_to_cpup(paddr + i + 3); 385cf41a51dSDavid Daney int val; 386cf41a51dSDavid Daney 387cf41a51dSDavid Daney if (reg_page != current_page) { 388cf41a51dSDavid Daney current_page = reg_page; 389cf41a51dSDavid Daney page_changed = 1; 390cf41a51dSDavid Daney ret = phy_write(phydev, MII_MARVELL_PHY_PAGE, reg_page); 391cf41a51dSDavid Daney if (ret < 0) 392cf41a51dSDavid Daney goto err; 393cf41a51dSDavid Daney } 394cf41a51dSDavid Daney 395cf41a51dSDavid Daney val = 0; 396cf41a51dSDavid Daney if (mask) { 397cf41a51dSDavid Daney val = phy_read(phydev, reg); 398cf41a51dSDavid Daney if (val < 0) { 399cf41a51dSDavid Daney ret = val; 400cf41a51dSDavid Daney goto err; 401cf41a51dSDavid Daney } 402cf41a51dSDavid Daney val &= mask; 403cf41a51dSDavid Daney } 404cf41a51dSDavid Daney val |= val_bits; 405cf41a51dSDavid Daney 406cf41a51dSDavid Daney ret = phy_write(phydev, reg, val); 407cf41a51dSDavid Daney if (ret < 0) 408cf41a51dSDavid Daney goto err; 409cf41a51dSDavid Daney 410cf41a51dSDavid Daney } 411cf41a51dSDavid Daney err: 412cf41a51dSDavid Daney if (page_changed) { 413cf41a51dSDavid Daney i = phy_write(phydev, MII_MARVELL_PHY_PAGE, saved_page); 414cf41a51dSDavid Daney if (ret == 0) 415cf41a51dSDavid Daney ret = i; 416cf41a51dSDavid Daney } 417cf41a51dSDavid Daney return ret; 418cf41a51dSDavid Daney } 419cf41a51dSDavid Daney #else 420cf41a51dSDavid Daney static int marvell_of_reg_init(struct phy_device *phydev) 421cf41a51dSDavid Daney { 422cf41a51dSDavid Daney return 0; 423cf41a51dSDavid Daney } 424cf41a51dSDavid Daney #endif /* CONFIG_OF_MDIO */ 425cf41a51dSDavid Daney 426140bc929SSergei Poselenov static int m88e1121_config_aneg(struct phy_device *phydev) 427140bc929SSergei Poselenov { 428c477d044SCyril Chemparathy int err, oldpage, mscr; 429c477d044SCyril Chemparathy 43027d916d6SDavid Daney oldpage = phy_read(phydev, MII_MARVELL_PHY_PAGE); 431c477d044SCyril Chemparathy 43227d916d6SDavid Daney err = phy_write(phydev, MII_MARVELL_PHY_PAGE, 433c477d044SCyril Chemparathy MII_88E1121_PHY_MSCR_PAGE); 434c477d044SCyril Chemparathy if (err < 0) 435c477d044SCyril Chemparathy return err; 436be8c6480SArnaud Patard 43732a64161SFlorian Fainelli if (phy_interface_is_rgmii(phydev)) { 438be8c6480SArnaud Patard 439c477d044SCyril Chemparathy mscr = phy_read(phydev, MII_88E1121_PHY_MSCR_REG) & 440c477d044SCyril Chemparathy MII_88E1121_PHY_MSCR_DELAY_MASK; 441c477d044SCyril Chemparathy 442c477d044SCyril Chemparathy if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID) 443c477d044SCyril Chemparathy mscr |= (MII_88E1121_PHY_MSCR_RX_DELAY | 444c477d044SCyril Chemparathy MII_88E1121_PHY_MSCR_TX_DELAY); 445c477d044SCyril Chemparathy else if (phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID) 446c477d044SCyril Chemparathy mscr |= MII_88E1121_PHY_MSCR_RX_DELAY; 447c477d044SCyril Chemparathy else if (phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID) 448c477d044SCyril Chemparathy mscr |= MII_88E1121_PHY_MSCR_TX_DELAY; 449c477d044SCyril Chemparathy 450c477d044SCyril Chemparathy err = phy_write(phydev, MII_88E1121_PHY_MSCR_REG, mscr); 451c477d044SCyril Chemparathy if (err < 0) 452c477d044SCyril Chemparathy return err; 453be8c6480SArnaud Patard } 454c477d044SCyril Chemparathy 45527d916d6SDavid Daney phy_write(phydev, MII_MARVELL_PHY_PAGE, oldpage); 456140bc929SSergei Poselenov 457140bc929SSergei Poselenov err = phy_write(phydev, MII_BMCR, BMCR_RESET); 458140bc929SSergei Poselenov if (err < 0) 459140bc929SSergei Poselenov return err; 460140bc929SSergei Poselenov 461140bc929SSergei Poselenov err = phy_write(phydev, MII_M1011_PHY_SCR, 462140bc929SSergei Poselenov MII_M1011_PHY_SCR_AUTO_CROSS); 463140bc929SSergei Poselenov if (err < 0) 464140bc929SSergei Poselenov return err; 465140bc929SSergei Poselenov 466fdecf36fSClemens Gruber return genphy_config_aneg(phydev); 467140bc929SSergei Poselenov } 468140bc929SSergei Poselenov 469337ac9d5SCyril Chemparathy static int m88e1318_config_aneg(struct phy_device *phydev) 4703ff1c259SCyril Chemparathy { 4713ff1c259SCyril Chemparathy int err, oldpage, mscr; 4723ff1c259SCyril Chemparathy 47327d916d6SDavid Daney oldpage = phy_read(phydev, MII_MARVELL_PHY_PAGE); 4743ff1c259SCyril Chemparathy 47527d916d6SDavid Daney err = phy_write(phydev, MII_MARVELL_PHY_PAGE, 4763ff1c259SCyril Chemparathy MII_88E1121_PHY_MSCR_PAGE); 4773ff1c259SCyril Chemparathy if (err < 0) 4783ff1c259SCyril Chemparathy return err; 4793ff1c259SCyril Chemparathy 480337ac9d5SCyril Chemparathy mscr = phy_read(phydev, MII_88E1318S_PHY_MSCR1_REG); 481337ac9d5SCyril Chemparathy mscr |= MII_88E1318S_PHY_MSCR1_PAD_ODD; 4823ff1c259SCyril Chemparathy 483337ac9d5SCyril Chemparathy err = phy_write(phydev, MII_88E1318S_PHY_MSCR1_REG, mscr); 4843ff1c259SCyril Chemparathy if (err < 0) 4853ff1c259SCyril Chemparathy return err; 4863ff1c259SCyril Chemparathy 48727d916d6SDavid Daney err = phy_write(phydev, MII_MARVELL_PHY_PAGE, oldpage); 4883ff1c259SCyril Chemparathy if (err < 0) 4893ff1c259SCyril Chemparathy return err; 4903ff1c259SCyril Chemparathy 4913ff1c259SCyril Chemparathy return m88e1121_config_aneg(phydev); 4923ff1c259SCyril Chemparathy } 4933ff1c259SCyril Chemparathy 49410e24caaSMichal Simek static int m88e1510_config_aneg(struct phy_device *phydev) 49510e24caaSMichal Simek { 49610e24caaSMichal Simek int err; 49710e24caaSMichal Simek 49810e24caaSMichal Simek err = m88e1318_config_aneg(phydev); 49910e24caaSMichal Simek if (err < 0) 50010e24caaSMichal Simek return err; 50110e24caaSMichal Simek 50279be1a1cSClemens Gruber return 0; 50379be1a1cSClemens Gruber } 50479be1a1cSClemens Gruber 50579be1a1cSClemens Gruber static int marvell_config_init(struct phy_device *phydev) 50679be1a1cSClemens Gruber { 50779be1a1cSClemens Gruber /* Set registers from marvell,reg-init DT property */ 50810e24caaSMichal Simek return marvell_of_reg_init(phydev); 50910e24caaSMichal Simek } 51010e24caaSMichal Simek 5113da09a51SMichal Simek static int m88e1116r_config_init(struct phy_device *phydev) 5123da09a51SMichal Simek { 5133da09a51SMichal Simek int temp; 5143da09a51SMichal Simek int err; 5153da09a51SMichal Simek 5163da09a51SMichal Simek temp = phy_read(phydev, MII_BMCR); 5173da09a51SMichal Simek temp |= BMCR_RESET; 5183da09a51SMichal Simek err = phy_write(phydev, MII_BMCR, temp); 5193da09a51SMichal Simek if (err < 0) 5203da09a51SMichal Simek return err; 5213da09a51SMichal Simek 5223da09a51SMichal Simek mdelay(500); 5233da09a51SMichal Simek 5243da09a51SMichal Simek err = phy_write(phydev, MII_MARVELL_PHY_PAGE, 0); 5253da09a51SMichal Simek if (err < 0) 5263da09a51SMichal Simek return err; 5273da09a51SMichal Simek 5283da09a51SMichal Simek temp = phy_read(phydev, MII_M1011_PHY_SCR); 5293da09a51SMichal Simek temp |= (7 << 12); /* max number of gigabit attempts */ 5303da09a51SMichal Simek temp |= (1 << 11); /* enable downshift */ 5313da09a51SMichal Simek temp |= MII_M1011_PHY_SCR_AUTO_CROSS; 5323da09a51SMichal Simek err = phy_write(phydev, MII_M1011_PHY_SCR, temp); 5333da09a51SMichal Simek if (err < 0) 5343da09a51SMichal Simek return err; 5353da09a51SMichal Simek 5363da09a51SMichal Simek err = phy_write(phydev, MII_MARVELL_PHY_PAGE, 2); 5373da09a51SMichal Simek if (err < 0) 5383da09a51SMichal Simek return err; 5393da09a51SMichal Simek temp = phy_read(phydev, MII_M1116R_CONTROL_REG_MAC); 5403da09a51SMichal Simek temp |= (1 << 5); 5413da09a51SMichal Simek temp |= (1 << 4); 5423da09a51SMichal Simek err = phy_write(phydev, MII_M1116R_CONTROL_REG_MAC, temp); 5433da09a51SMichal Simek if (err < 0) 5443da09a51SMichal Simek return err; 5453da09a51SMichal Simek err = phy_write(phydev, MII_MARVELL_PHY_PAGE, 0); 5463da09a51SMichal Simek if (err < 0) 5473da09a51SMichal Simek return err; 5483da09a51SMichal Simek 5493da09a51SMichal Simek temp = phy_read(phydev, MII_BMCR); 5503da09a51SMichal Simek temp |= BMCR_RESET; 5513da09a51SMichal Simek err = phy_write(phydev, MII_BMCR, temp); 5523da09a51SMichal Simek if (err < 0) 5533da09a51SMichal Simek return err; 5543da09a51SMichal Simek 5553da09a51SMichal Simek mdelay(500); 5563da09a51SMichal Simek 55779be1a1cSClemens Gruber return marvell_config_init(phydev); 5583da09a51SMichal Simek } 5593da09a51SMichal Simek 5606b358aedSSebastian Hesselbarth static int m88e3016_config_init(struct phy_device *phydev) 5616b358aedSSebastian Hesselbarth { 5626b358aedSSebastian Hesselbarth int reg; 5636b358aedSSebastian Hesselbarth 5646b358aedSSebastian Hesselbarth /* Enable Scrambler and Auto-Crossover */ 5656b358aedSSebastian Hesselbarth reg = phy_read(phydev, MII_88E3016_PHY_SPEC_CTRL); 5666b358aedSSebastian Hesselbarth if (reg < 0) 5676b358aedSSebastian Hesselbarth return reg; 5686b358aedSSebastian Hesselbarth 5696b358aedSSebastian Hesselbarth reg &= ~MII_88E3016_DISABLE_SCRAMBLER; 5706b358aedSSebastian Hesselbarth reg |= MII_88E3016_AUTO_MDIX_CROSSOVER; 5716b358aedSSebastian Hesselbarth 5726b358aedSSebastian Hesselbarth reg = phy_write(phydev, MII_88E3016_PHY_SPEC_CTRL, reg); 5736b358aedSSebastian Hesselbarth if (reg < 0) 5746b358aedSSebastian Hesselbarth return reg; 5756b358aedSSebastian Hesselbarth 57679be1a1cSClemens Gruber return marvell_config_init(phydev); 5776b358aedSSebastian Hesselbarth } 5786b358aedSSebastian Hesselbarth 579895ee682SKim Phillips static int m88e1111_config_init(struct phy_device *phydev) 580895ee682SKim Phillips { 581895ee682SKim Phillips int err; 582be937f1fSAlexandr Smirnov int temp; 583be937f1fSAlexandr Smirnov 58432a64161SFlorian Fainelli if (phy_interface_is_rgmii(phydev)) { 585895ee682SKim Phillips 586895ee682SKim Phillips temp = phy_read(phydev, MII_M1111_PHY_EXT_CR); 587895ee682SKim Phillips if (temp < 0) 588895ee682SKim Phillips return temp; 589895ee682SKim Phillips 5909daf5a76SKim Phillips if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID) { 591895ee682SKim Phillips temp |= (MII_M1111_RX_DELAY | MII_M1111_TX_DELAY); 5929daf5a76SKim Phillips } else if (phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID) { 5939daf5a76SKim Phillips temp &= ~MII_M1111_TX_DELAY; 5949daf5a76SKim Phillips temp |= MII_M1111_RX_DELAY; 5959daf5a76SKim Phillips } else if (phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID) { 5969daf5a76SKim Phillips temp &= ~MII_M1111_RX_DELAY; 5979daf5a76SKim Phillips temp |= MII_M1111_TX_DELAY; 5989daf5a76SKim Phillips } 599895ee682SKim Phillips 600895ee682SKim Phillips err = phy_write(phydev, MII_M1111_PHY_EXT_CR, temp); 601895ee682SKim Phillips if (err < 0) 602895ee682SKim Phillips return err; 603895ee682SKim Phillips 604895ee682SKim Phillips temp = phy_read(phydev, MII_M1111_PHY_EXT_SR); 605895ee682SKim Phillips if (temp < 0) 606895ee682SKim Phillips return temp; 607895ee682SKim Phillips 608895ee682SKim Phillips temp &= ~(MII_M1111_HWCFG_MODE_MASK); 609be937f1fSAlexandr Smirnov 6107239016dSWang Jian if (temp & MII_M1111_HWCFG_FIBER_COPPER_RES) 611be937f1fSAlexandr Smirnov temp |= MII_M1111_HWCFG_MODE_FIBER_RGMII; 612be937f1fSAlexandr Smirnov else 613be937f1fSAlexandr Smirnov temp |= MII_M1111_HWCFG_MODE_COPPER_RGMII; 614895ee682SKim Phillips 615895ee682SKim Phillips err = phy_write(phydev, MII_M1111_PHY_EXT_SR, temp); 616895ee682SKim Phillips if (err < 0) 617895ee682SKim Phillips return err; 618895ee682SKim Phillips } 619895ee682SKim Phillips 6204117b5beSKapil Juneja if (phydev->interface == PHY_INTERFACE_MODE_SGMII) { 6214117b5beSKapil Juneja temp = phy_read(phydev, MII_M1111_PHY_EXT_SR); 6224117b5beSKapil Juneja if (temp < 0) 6234117b5beSKapil Juneja return temp; 6244117b5beSKapil Juneja 6254117b5beSKapil Juneja temp &= ~(MII_M1111_HWCFG_MODE_MASK); 6264117b5beSKapil Juneja temp |= MII_M1111_HWCFG_MODE_SGMII_NO_CLK; 62732d0c1e1SHaiying Wang temp |= MII_M1111_HWCFG_FIBER_COPPER_AUTO; 6284117b5beSKapil Juneja 6294117b5beSKapil Juneja err = phy_write(phydev, MII_M1111_PHY_EXT_SR, temp); 6304117b5beSKapil Juneja if (err < 0) 6314117b5beSKapil Juneja return err; 63207151bc9SMadalin Bucur 63307151bc9SMadalin Bucur /* make sure copper is selected */ 63407151bc9SMadalin Bucur err = phy_read(phydev, MII_M1145_PHY_EXT_ADDR_PAGE); 63507151bc9SMadalin Bucur if (err < 0) 63607151bc9SMadalin Bucur return err; 63707151bc9SMadalin Bucur 63807151bc9SMadalin Bucur err = phy_write(phydev, MII_M1145_PHY_EXT_ADDR_PAGE, 63907151bc9SMadalin Bucur err & (~0xff)); 64007151bc9SMadalin Bucur if (err < 0) 64107151bc9SMadalin Bucur return err; 6424117b5beSKapil Juneja } 6434117b5beSKapil Juneja 6445f8cbc13SLiu Yu-B13201 if (phydev->interface == PHY_INTERFACE_MODE_RTBI) { 6455f8cbc13SLiu Yu-B13201 temp = phy_read(phydev, MII_M1111_PHY_EXT_CR); 6465f8cbc13SLiu Yu-B13201 if (temp < 0) 6475f8cbc13SLiu Yu-B13201 return temp; 6485f8cbc13SLiu Yu-B13201 temp |= (MII_M1111_RX_DELAY | MII_M1111_TX_DELAY); 6495f8cbc13SLiu Yu-B13201 err = phy_write(phydev, MII_M1111_PHY_EXT_CR, temp); 6505f8cbc13SLiu Yu-B13201 if (err < 0) 6515f8cbc13SLiu Yu-B13201 return err; 6525f8cbc13SLiu Yu-B13201 6535f8cbc13SLiu Yu-B13201 temp = phy_read(phydev, MII_M1111_PHY_EXT_SR); 6545f8cbc13SLiu Yu-B13201 if (temp < 0) 6555f8cbc13SLiu Yu-B13201 return temp; 6565f8cbc13SLiu Yu-B13201 temp &= ~(MII_M1111_HWCFG_MODE_MASK | MII_M1111_HWCFG_FIBER_COPPER_RES); 6575f8cbc13SLiu Yu-B13201 temp |= 0x7 | MII_M1111_HWCFG_FIBER_COPPER_AUTO; 6585f8cbc13SLiu Yu-B13201 err = phy_write(phydev, MII_M1111_PHY_EXT_SR, temp); 6595f8cbc13SLiu Yu-B13201 if (err < 0) 6605f8cbc13SLiu Yu-B13201 return err; 6615f8cbc13SLiu Yu-B13201 6625f8cbc13SLiu Yu-B13201 /* soft reset */ 6635f8cbc13SLiu Yu-B13201 err = phy_write(phydev, MII_BMCR, BMCR_RESET); 6645f8cbc13SLiu Yu-B13201 if (err < 0) 6655f8cbc13SLiu Yu-B13201 return err; 6665f8cbc13SLiu Yu-B13201 do 6675f8cbc13SLiu Yu-B13201 temp = phy_read(phydev, MII_BMCR); 6685f8cbc13SLiu Yu-B13201 while (temp & BMCR_RESET); 6695f8cbc13SLiu Yu-B13201 6705f8cbc13SLiu Yu-B13201 temp = phy_read(phydev, MII_M1111_PHY_EXT_SR); 6715f8cbc13SLiu Yu-B13201 if (temp < 0) 6725f8cbc13SLiu Yu-B13201 return temp; 6735f8cbc13SLiu Yu-B13201 temp &= ~(MII_M1111_HWCFG_MODE_MASK | MII_M1111_HWCFG_FIBER_COPPER_RES); 6745f8cbc13SLiu Yu-B13201 temp |= MII_M1111_HWCFG_MODE_COPPER_RTBI | MII_M1111_HWCFG_FIBER_COPPER_AUTO; 6755f8cbc13SLiu Yu-B13201 err = phy_write(phydev, MII_M1111_PHY_EXT_SR, temp); 6765f8cbc13SLiu Yu-B13201 if (err < 0) 6775f8cbc13SLiu Yu-B13201 return err; 6785f8cbc13SLiu Yu-B13201 } 6795f8cbc13SLiu Yu-B13201 680cf41a51dSDavid Daney err = marvell_of_reg_init(phydev); 681cf41a51dSDavid Daney if (err < 0) 682cf41a51dSDavid Daney return err; 6835f8cbc13SLiu Yu-B13201 684cc90cb3bSSrinivas Kandagatla return phy_write(phydev, MII_BMCR, BMCR_RESET); 685895ee682SKim Phillips } 686895ee682SKim Phillips 687fdecf36fSClemens Gruber static int m88e1121_config_init(struct phy_device *phydev) 688fdecf36fSClemens Gruber { 689fdecf36fSClemens Gruber int err, oldpage; 690fdecf36fSClemens Gruber 691fdecf36fSClemens Gruber oldpage = phy_read(phydev, MII_MARVELL_PHY_PAGE); 692fdecf36fSClemens Gruber 693fdecf36fSClemens Gruber err = phy_write(phydev, MII_MARVELL_PHY_PAGE, MII_88E1121_PHY_LED_PAGE); 694fdecf36fSClemens Gruber if (err < 0) 695fdecf36fSClemens Gruber return err; 696fdecf36fSClemens Gruber 697fdecf36fSClemens Gruber /* Default PHY LED config: LED[0] .. Link, LED[1] .. Activity */ 698fdecf36fSClemens Gruber err = phy_write(phydev, MII_88E1121_PHY_LED_CTRL, 699fdecf36fSClemens Gruber MII_88E1121_PHY_LED_DEF); 700fdecf36fSClemens Gruber if (err < 0) 701fdecf36fSClemens Gruber return err; 702fdecf36fSClemens Gruber 703fdecf36fSClemens Gruber phy_write(phydev, MII_MARVELL_PHY_PAGE, oldpage); 704fdecf36fSClemens Gruber 705fdecf36fSClemens Gruber /* Set marvell,reg-init configuration from device tree */ 706fdecf36fSClemens Gruber return marvell_config_init(phydev); 707fdecf36fSClemens Gruber } 708fdecf36fSClemens Gruber 709407353ecSClemens Gruber static int m88e1510_config_init(struct phy_device *phydev) 710407353ecSClemens Gruber { 711407353ecSClemens Gruber int err; 712407353ecSClemens Gruber int temp; 713407353ecSClemens Gruber 714407353ecSClemens Gruber /* SGMII-to-Copper mode initialization */ 715407353ecSClemens Gruber if (phydev->interface == PHY_INTERFACE_MODE_SGMII) { 716407353ecSClemens Gruber /* Select page 18 */ 717407353ecSClemens Gruber err = phy_write(phydev, MII_MARVELL_PHY_PAGE, 18); 718407353ecSClemens Gruber if (err < 0) 719407353ecSClemens Gruber return err; 720407353ecSClemens Gruber 721407353ecSClemens Gruber /* In reg 20, write MODE[2:0] = 0x1 (SGMII to Copper) */ 722407353ecSClemens Gruber temp = phy_read(phydev, MII_88E1510_GEN_CTRL_REG_1); 723407353ecSClemens Gruber temp &= ~MII_88E1510_GEN_CTRL_REG_1_MODE_MASK; 724407353ecSClemens Gruber temp |= MII_88E1510_GEN_CTRL_REG_1_MODE_SGMII; 725407353ecSClemens Gruber err = phy_write(phydev, MII_88E1510_GEN_CTRL_REG_1, temp); 726407353ecSClemens Gruber if (err < 0) 727407353ecSClemens Gruber return err; 728407353ecSClemens Gruber 729407353ecSClemens Gruber /* PHY reset is necessary after changing MODE[2:0] */ 730407353ecSClemens Gruber temp |= MII_88E1510_GEN_CTRL_REG_1_RESET; 731407353ecSClemens Gruber err = phy_write(phydev, MII_88E1510_GEN_CTRL_REG_1, temp); 732407353ecSClemens Gruber if (err < 0) 733407353ecSClemens Gruber return err; 734407353ecSClemens Gruber 735407353ecSClemens Gruber /* Reset page selection */ 736407353ecSClemens Gruber err = phy_write(phydev, MII_MARVELL_PHY_PAGE, 0); 737407353ecSClemens Gruber if (err < 0) 738407353ecSClemens Gruber return err; 739407353ecSClemens Gruber } 740407353ecSClemens Gruber 741fdecf36fSClemens Gruber return m88e1121_config_init(phydev); 742407353ecSClemens Gruber } 743407353ecSClemens Gruber 744605f196eSRon Madrid static int m88e1118_config_aneg(struct phy_device *phydev) 745605f196eSRon Madrid { 746605f196eSRon Madrid int err; 747605f196eSRon Madrid 748605f196eSRon Madrid err = phy_write(phydev, MII_BMCR, BMCR_RESET); 749605f196eSRon Madrid if (err < 0) 750605f196eSRon Madrid return err; 751605f196eSRon Madrid 752605f196eSRon Madrid err = phy_write(phydev, MII_M1011_PHY_SCR, 753605f196eSRon Madrid MII_M1011_PHY_SCR_AUTO_CROSS); 754605f196eSRon Madrid if (err < 0) 755605f196eSRon Madrid return err; 756605f196eSRon Madrid 757605f196eSRon Madrid err = genphy_config_aneg(phydev); 758605f196eSRon Madrid return 0; 759605f196eSRon Madrid } 760605f196eSRon Madrid 761605f196eSRon Madrid static int m88e1118_config_init(struct phy_device *phydev) 762605f196eSRon Madrid { 763605f196eSRon Madrid int err; 764605f196eSRon Madrid 765605f196eSRon Madrid /* Change address */ 76627d916d6SDavid Daney err = phy_write(phydev, MII_MARVELL_PHY_PAGE, 0x0002); 767605f196eSRon Madrid if (err < 0) 768605f196eSRon Madrid return err; 769605f196eSRon Madrid 770605f196eSRon Madrid /* Enable 1000 Mbit */ 771605f196eSRon Madrid err = phy_write(phydev, 0x15, 0x1070); 772605f196eSRon Madrid if (err < 0) 773605f196eSRon Madrid return err; 774605f196eSRon Madrid 775605f196eSRon Madrid /* Change address */ 77627d916d6SDavid Daney err = phy_write(phydev, MII_MARVELL_PHY_PAGE, 0x0003); 777605f196eSRon Madrid if (err < 0) 778605f196eSRon Madrid return err; 779605f196eSRon Madrid 780605f196eSRon Madrid /* Adjust LED Control */ 7812f495c39SBenjamin Herrenschmidt if (phydev->dev_flags & MARVELL_PHY_M1118_DNS323_LEDS) 7822f495c39SBenjamin Herrenschmidt err = phy_write(phydev, 0x10, 0x1100); 7832f495c39SBenjamin Herrenschmidt else 784605f196eSRon Madrid err = phy_write(phydev, 0x10, 0x021e); 785605f196eSRon Madrid if (err < 0) 786605f196eSRon Madrid return err; 787605f196eSRon Madrid 788cf41a51dSDavid Daney err = marvell_of_reg_init(phydev); 789cf41a51dSDavid Daney if (err < 0) 790cf41a51dSDavid Daney return err; 791cf41a51dSDavid Daney 792605f196eSRon Madrid /* Reset address */ 79327d916d6SDavid Daney err = phy_write(phydev, MII_MARVELL_PHY_PAGE, 0x0); 794605f196eSRon Madrid if (err < 0) 795605f196eSRon Madrid return err; 796605f196eSRon Madrid 797cc90cb3bSSrinivas Kandagatla return phy_write(phydev, MII_BMCR, BMCR_RESET); 798605f196eSRon Madrid } 799605f196eSRon Madrid 80090600732SDavid Daney static int m88e1149_config_init(struct phy_device *phydev) 80190600732SDavid Daney { 80290600732SDavid Daney int err; 80390600732SDavid Daney 80490600732SDavid Daney /* Change address */ 80590600732SDavid Daney err = phy_write(phydev, MII_MARVELL_PHY_PAGE, 0x0002); 80690600732SDavid Daney if (err < 0) 80790600732SDavid Daney return err; 80890600732SDavid Daney 80990600732SDavid Daney /* Enable 1000 Mbit */ 81090600732SDavid Daney err = phy_write(phydev, 0x15, 0x1048); 81190600732SDavid Daney if (err < 0) 81290600732SDavid Daney return err; 81390600732SDavid Daney 814cf41a51dSDavid Daney err = marvell_of_reg_init(phydev); 815cf41a51dSDavid Daney if (err < 0) 816cf41a51dSDavid Daney return err; 817cf41a51dSDavid Daney 81890600732SDavid Daney /* Reset address */ 81990600732SDavid Daney err = phy_write(phydev, MII_MARVELL_PHY_PAGE, 0x0); 82090600732SDavid Daney if (err < 0) 82190600732SDavid Daney return err; 82290600732SDavid Daney 823cc90cb3bSSrinivas Kandagatla return phy_write(phydev, MII_BMCR, BMCR_RESET); 82490600732SDavid Daney } 82590600732SDavid Daney 82676884679SAndy Fleming static int m88e1145_config_init(struct phy_device *phydev) 82776884679SAndy Fleming { 82876884679SAndy Fleming int err; 829b0224175SViet Nga Dao int temp; 83076884679SAndy Fleming 83176884679SAndy Fleming /* Take care of errata E0 & E1 */ 83276884679SAndy Fleming err = phy_write(phydev, 0x1d, 0x001b); 83376884679SAndy Fleming if (err < 0) 83476884679SAndy Fleming return err; 83576884679SAndy Fleming 83676884679SAndy Fleming err = phy_write(phydev, 0x1e, 0x418f); 83776884679SAndy Fleming if (err < 0) 83876884679SAndy Fleming return err; 83976884679SAndy Fleming 84076884679SAndy Fleming err = phy_write(phydev, 0x1d, 0x0016); 84176884679SAndy Fleming if (err < 0) 84276884679SAndy Fleming return err; 84376884679SAndy Fleming 84476884679SAndy Fleming err = phy_write(phydev, 0x1e, 0xa2da); 84576884679SAndy Fleming if (err < 0) 84676884679SAndy Fleming return err; 84776884679SAndy Fleming 848895ee682SKim Phillips if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID) { 84976884679SAndy Fleming int temp = phy_read(phydev, MII_M1145_PHY_EXT_CR); 85076884679SAndy Fleming if (temp < 0) 85176884679SAndy Fleming return temp; 85276884679SAndy Fleming 85376884679SAndy Fleming temp |= (MII_M1145_RGMII_RX_DELAY | MII_M1145_RGMII_TX_DELAY); 85476884679SAndy Fleming 85576884679SAndy Fleming err = phy_write(phydev, MII_M1145_PHY_EXT_CR, temp); 85676884679SAndy Fleming if (err < 0) 85776884679SAndy Fleming return err; 85876884679SAndy Fleming 8592f495c39SBenjamin Herrenschmidt if (phydev->dev_flags & MARVELL_PHY_M1145_FLAGS_RESISTANCE) { 86076884679SAndy Fleming err = phy_write(phydev, 0x1d, 0x0012); 86176884679SAndy Fleming if (err < 0) 86276884679SAndy Fleming return err; 86376884679SAndy Fleming 86476884679SAndy Fleming temp = phy_read(phydev, 0x1e); 86576884679SAndy Fleming if (temp < 0) 86676884679SAndy Fleming return temp; 86776884679SAndy Fleming 86876884679SAndy Fleming temp &= 0xf03f; 86976884679SAndy Fleming temp |= 2 << 9; /* 36 ohm */ 87076884679SAndy Fleming temp |= 2 << 6; /* 39 ohm */ 87176884679SAndy Fleming 87276884679SAndy Fleming err = phy_write(phydev, 0x1e, temp); 87376884679SAndy Fleming if (err < 0) 87476884679SAndy Fleming return err; 87576884679SAndy Fleming 87676884679SAndy Fleming err = phy_write(phydev, 0x1d, 0x3); 87776884679SAndy Fleming if (err < 0) 87876884679SAndy Fleming return err; 87976884679SAndy Fleming 88076884679SAndy Fleming err = phy_write(phydev, 0x1e, 0x8000); 88176884679SAndy Fleming if (err < 0) 88276884679SAndy Fleming return err; 88376884679SAndy Fleming } 88476884679SAndy Fleming } 88576884679SAndy Fleming 886b0224175SViet Nga Dao if (phydev->interface == PHY_INTERFACE_MODE_SGMII) { 887b0224175SViet Nga Dao temp = phy_read(phydev, MII_M1145_PHY_EXT_SR); 888b0224175SViet Nga Dao if (temp < 0) 889b0224175SViet Nga Dao return temp; 890b0224175SViet Nga Dao 89199d881f9SVince Bridgers temp &= ~MII_M1145_HWCFG_MODE_MASK; 892b0224175SViet Nga Dao temp |= MII_M1145_HWCFG_MODE_SGMII_NO_CLK; 893b0224175SViet Nga Dao temp |= MII_M1145_HWCFG_FIBER_COPPER_AUTO; 894b0224175SViet Nga Dao 895b0224175SViet Nga Dao err = phy_write(phydev, MII_M1145_PHY_EXT_SR, temp); 896b0224175SViet Nga Dao if (err < 0) 897b0224175SViet Nga Dao return err; 898b0224175SViet Nga Dao } 899b0224175SViet Nga Dao 900cf41a51dSDavid Daney err = marvell_of_reg_init(phydev); 901cf41a51dSDavid Daney if (err < 0) 902cf41a51dSDavid Daney return err; 903cf41a51dSDavid Daney 90476884679SAndy Fleming return 0; 90576884679SAndy Fleming } 90600db8189SAndy Fleming 9076cfb3bccSCharles-Antoine Couret /** 9086cfb3bccSCharles-Antoine Couret * fiber_lpa_to_ethtool_lpa_t 9096cfb3bccSCharles-Antoine Couret * @lpa: value of the MII_LPA register for fiber link 910be937f1fSAlexandr Smirnov * 9116cfb3bccSCharles-Antoine Couret * A small helper function that translates MII_LPA 9126cfb3bccSCharles-Antoine Couret * bits to ethtool LP advertisement settings. 9136cfb3bccSCharles-Antoine Couret */ 9146cfb3bccSCharles-Antoine Couret static u32 fiber_lpa_to_ethtool_lpa_t(u32 lpa) 9156cfb3bccSCharles-Antoine Couret { 9166cfb3bccSCharles-Antoine Couret u32 result = 0; 9176cfb3bccSCharles-Antoine Couret 9186cfb3bccSCharles-Antoine Couret if (lpa & LPA_FIBER_1000HALF) 9196cfb3bccSCharles-Antoine Couret result |= ADVERTISED_1000baseT_Half; 9206cfb3bccSCharles-Antoine Couret if (lpa & LPA_FIBER_1000FULL) 9216cfb3bccSCharles-Antoine Couret result |= ADVERTISED_1000baseT_Full; 9226cfb3bccSCharles-Antoine Couret 9236cfb3bccSCharles-Antoine Couret return result; 9246cfb3bccSCharles-Antoine Couret } 9256cfb3bccSCharles-Antoine Couret 9266cfb3bccSCharles-Antoine Couret /** 9276cfb3bccSCharles-Antoine Couret * marvell_update_link - update link status in real time in @phydev 9286cfb3bccSCharles-Antoine Couret * @phydev: target phy_device struct 9296cfb3bccSCharles-Antoine Couret * 9306cfb3bccSCharles-Antoine Couret * Description: Update the value in phydev->link to reflect the 9316cfb3bccSCharles-Antoine Couret * current link value. 9326cfb3bccSCharles-Antoine Couret */ 9336cfb3bccSCharles-Antoine Couret static int marvell_update_link(struct phy_device *phydev, int fiber) 9346cfb3bccSCharles-Antoine Couret { 9356cfb3bccSCharles-Antoine Couret int status; 9366cfb3bccSCharles-Antoine Couret 9376cfb3bccSCharles-Antoine Couret /* Use the generic register for copper link, or specific 9386cfb3bccSCharles-Antoine Couret * register for fiber case */ 9396cfb3bccSCharles-Antoine Couret if (fiber) { 9406cfb3bccSCharles-Antoine Couret status = phy_read(phydev, MII_M1011_PHY_STATUS); 9416cfb3bccSCharles-Antoine Couret if (status < 0) 9426cfb3bccSCharles-Antoine Couret return status; 9436cfb3bccSCharles-Antoine Couret 9446cfb3bccSCharles-Antoine Couret if ((status & REGISTER_LINK_STATUS) == 0) 9456cfb3bccSCharles-Antoine Couret phydev->link = 0; 9466cfb3bccSCharles-Antoine Couret else 9476cfb3bccSCharles-Antoine Couret phydev->link = 1; 9486cfb3bccSCharles-Antoine Couret } else { 9496cfb3bccSCharles-Antoine Couret return genphy_update_link(phydev); 9506cfb3bccSCharles-Antoine Couret } 9516cfb3bccSCharles-Antoine Couret 9526cfb3bccSCharles-Antoine Couret return 0; 9536cfb3bccSCharles-Antoine Couret } 9546cfb3bccSCharles-Antoine Couret 9556cfb3bccSCharles-Antoine Couret /* marvell_read_status_page 9566cfb3bccSCharles-Antoine Couret * 957be937f1fSAlexandr Smirnov * Description: 958be937f1fSAlexandr Smirnov * Check the link, then figure out the current state 959be937f1fSAlexandr Smirnov * by comparing what we advertise with what the link partner 960be937f1fSAlexandr Smirnov * advertises. Start by checking the gigabit possibilities, 961be937f1fSAlexandr Smirnov * then move on to 10/100. 962be937f1fSAlexandr Smirnov */ 9636cfb3bccSCharles-Antoine Couret static int marvell_read_status_page(struct phy_device *phydev, int page) 964be937f1fSAlexandr Smirnov { 965be937f1fSAlexandr Smirnov int adv; 966be937f1fSAlexandr Smirnov int err; 967be937f1fSAlexandr Smirnov int lpa; 968357cd64cSRussell King int lpagb; 969be937f1fSAlexandr Smirnov int status = 0; 9706cfb3bccSCharles-Antoine Couret int fiber; 971be937f1fSAlexandr Smirnov 9726cfb3bccSCharles-Antoine Couret /* Detect and update the link, but return if there 973be937f1fSAlexandr Smirnov * was an error */ 9746cfb3bccSCharles-Antoine Couret if (page == MII_M1111_FIBER) 9756cfb3bccSCharles-Antoine Couret fiber = 1; 9766cfb3bccSCharles-Antoine Couret else 9776cfb3bccSCharles-Antoine Couret fiber = 0; 9786cfb3bccSCharles-Antoine Couret 9796cfb3bccSCharles-Antoine Couret err = marvell_update_link(phydev, fiber); 980be937f1fSAlexandr Smirnov if (err) 981be937f1fSAlexandr Smirnov return err; 982be937f1fSAlexandr Smirnov 983be937f1fSAlexandr Smirnov if (AUTONEG_ENABLE == phydev->autoneg) { 984be937f1fSAlexandr Smirnov status = phy_read(phydev, MII_M1011_PHY_STATUS); 985be937f1fSAlexandr Smirnov if (status < 0) 986be937f1fSAlexandr Smirnov return status; 987be937f1fSAlexandr Smirnov 988be937f1fSAlexandr Smirnov lpa = phy_read(phydev, MII_LPA); 989be937f1fSAlexandr Smirnov if (lpa < 0) 990be937f1fSAlexandr Smirnov return lpa; 991be937f1fSAlexandr Smirnov 992357cd64cSRussell King lpagb = phy_read(phydev, MII_STAT1000); 993357cd64cSRussell King if (lpagb < 0) 994357cd64cSRussell King return lpagb; 995357cd64cSRussell King 996be937f1fSAlexandr Smirnov adv = phy_read(phydev, MII_ADVERTISE); 997be937f1fSAlexandr Smirnov if (adv < 0) 998be937f1fSAlexandr Smirnov return adv; 999be937f1fSAlexandr Smirnov 1000be937f1fSAlexandr Smirnov lpa &= adv; 1001be937f1fSAlexandr Smirnov 1002be937f1fSAlexandr Smirnov if (status & MII_M1011_PHY_STATUS_FULLDUPLEX) 1003be937f1fSAlexandr Smirnov phydev->duplex = DUPLEX_FULL; 1004be937f1fSAlexandr Smirnov else 1005be937f1fSAlexandr Smirnov phydev->duplex = DUPLEX_HALF; 1006be937f1fSAlexandr Smirnov 1007be937f1fSAlexandr Smirnov status = status & MII_M1011_PHY_STATUS_SPD_MASK; 1008be937f1fSAlexandr Smirnov phydev->pause = phydev->asym_pause = 0; 1009be937f1fSAlexandr Smirnov 1010be937f1fSAlexandr Smirnov switch (status) { 1011be937f1fSAlexandr Smirnov case MII_M1011_PHY_STATUS_1000: 1012be937f1fSAlexandr Smirnov phydev->speed = SPEED_1000; 1013be937f1fSAlexandr Smirnov break; 1014be937f1fSAlexandr Smirnov 1015be937f1fSAlexandr Smirnov case MII_M1011_PHY_STATUS_100: 1016be937f1fSAlexandr Smirnov phydev->speed = SPEED_100; 1017be937f1fSAlexandr Smirnov break; 1018be937f1fSAlexandr Smirnov 1019be937f1fSAlexandr Smirnov default: 1020be937f1fSAlexandr Smirnov phydev->speed = SPEED_10; 1021be937f1fSAlexandr Smirnov break; 1022be937f1fSAlexandr Smirnov } 1023be937f1fSAlexandr Smirnov 10246cfb3bccSCharles-Antoine Couret if (!fiber) { 10256cfb3bccSCharles-Antoine Couret phydev->lp_advertising = mii_stat1000_to_ethtool_lpa_t(lpagb) | 10266cfb3bccSCharles-Antoine Couret mii_lpa_to_ethtool_lpa_t(lpa); 10276cfb3bccSCharles-Antoine Couret 1028be937f1fSAlexandr Smirnov if (phydev->duplex == DUPLEX_FULL) { 1029be937f1fSAlexandr Smirnov phydev->pause = lpa & LPA_PAUSE_CAP ? 1 : 0; 1030be937f1fSAlexandr Smirnov phydev->asym_pause = lpa & LPA_PAUSE_ASYM ? 1 : 0; 1031be937f1fSAlexandr Smirnov } 1032be937f1fSAlexandr Smirnov } else { 10336cfb3bccSCharles-Antoine Couret /* The fiber link is only 1000M capable */ 10346cfb3bccSCharles-Antoine Couret phydev->lp_advertising = fiber_lpa_to_ethtool_lpa_t(lpa); 10356cfb3bccSCharles-Antoine Couret 10366cfb3bccSCharles-Antoine Couret if (phydev->duplex == DUPLEX_FULL) { 10376cfb3bccSCharles-Antoine Couret if (!(lpa & LPA_PAUSE_FIBER)) { 10386cfb3bccSCharles-Antoine Couret phydev->pause = 0; 10396cfb3bccSCharles-Antoine Couret phydev->asym_pause = 0; 10406cfb3bccSCharles-Antoine Couret } else if ((lpa & LPA_PAUSE_ASYM_FIBER)) { 10416cfb3bccSCharles-Antoine Couret phydev->pause = 1; 10426cfb3bccSCharles-Antoine Couret phydev->asym_pause = 1; 10436cfb3bccSCharles-Antoine Couret } else { 10446cfb3bccSCharles-Antoine Couret phydev->pause = 1; 10456cfb3bccSCharles-Antoine Couret phydev->asym_pause = 0; 10466cfb3bccSCharles-Antoine Couret } 10476cfb3bccSCharles-Antoine Couret } 10486cfb3bccSCharles-Antoine Couret } 10496cfb3bccSCharles-Antoine Couret } else { 1050be937f1fSAlexandr Smirnov int bmcr = phy_read(phydev, MII_BMCR); 1051be937f1fSAlexandr Smirnov 1052be937f1fSAlexandr Smirnov if (bmcr < 0) 1053be937f1fSAlexandr Smirnov return bmcr; 1054be937f1fSAlexandr Smirnov 1055be937f1fSAlexandr Smirnov if (bmcr & BMCR_FULLDPLX) 1056be937f1fSAlexandr Smirnov phydev->duplex = DUPLEX_FULL; 1057be937f1fSAlexandr Smirnov else 1058be937f1fSAlexandr Smirnov phydev->duplex = DUPLEX_HALF; 1059be937f1fSAlexandr Smirnov 1060be937f1fSAlexandr Smirnov if (bmcr & BMCR_SPEED1000) 1061be937f1fSAlexandr Smirnov phydev->speed = SPEED_1000; 1062be937f1fSAlexandr Smirnov else if (bmcr & BMCR_SPEED100) 1063be937f1fSAlexandr Smirnov phydev->speed = SPEED_100; 1064be937f1fSAlexandr Smirnov else 1065be937f1fSAlexandr Smirnov phydev->speed = SPEED_10; 1066be937f1fSAlexandr Smirnov 1067be937f1fSAlexandr Smirnov phydev->pause = phydev->asym_pause = 0; 1068357cd64cSRussell King phydev->lp_advertising = 0; 1069be937f1fSAlexandr Smirnov } 1070be937f1fSAlexandr Smirnov 1071be937f1fSAlexandr Smirnov return 0; 1072be937f1fSAlexandr Smirnov } 1073be937f1fSAlexandr Smirnov 10746cfb3bccSCharles-Antoine Couret /* marvell_read_status 10756cfb3bccSCharles-Antoine Couret * 10766cfb3bccSCharles-Antoine Couret * Some Marvell's phys have two modes: fiber and copper. 10776cfb3bccSCharles-Antoine Couret * Both need status checked. 10786cfb3bccSCharles-Antoine Couret * Description: 10796cfb3bccSCharles-Antoine Couret * First, check the fiber link and status. 10806cfb3bccSCharles-Antoine Couret * If the fiber link is down, check the copper link and status which 10816cfb3bccSCharles-Antoine Couret * will be the default value if both link are down. 10826cfb3bccSCharles-Antoine Couret */ 10836cfb3bccSCharles-Antoine Couret static int marvell_read_status(struct phy_device *phydev) 10846cfb3bccSCharles-Antoine Couret { 10856cfb3bccSCharles-Antoine Couret int err; 10866cfb3bccSCharles-Antoine Couret 10876cfb3bccSCharles-Antoine Couret /* Check the fiber mode first */ 10886cfb3bccSCharles-Antoine Couret if (phydev->supported & SUPPORTED_FIBRE) { 10896cfb3bccSCharles-Antoine Couret err = phy_write(phydev, MII_MARVELL_PHY_PAGE, MII_M1111_FIBER); 10906cfb3bccSCharles-Antoine Couret if (err < 0) 10916cfb3bccSCharles-Antoine Couret goto error; 10926cfb3bccSCharles-Antoine Couret 10936cfb3bccSCharles-Antoine Couret err = marvell_read_status_page(phydev, MII_M1111_FIBER); 10946cfb3bccSCharles-Antoine Couret if (err < 0) 10956cfb3bccSCharles-Antoine Couret goto error; 10966cfb3bccSCharles-Antoine Couret 10976cfb3bccSCharles-Antoine Couret /* If the fiber link is up, it is the selected and used link. 10986cfb3bccSCharles-Antoine Couret * In this case, we need to stay in the fiber page. 10996cfb3bccSCharles-Antoine Couret * Please to be careful about that, avoid to restore Copper page 11006cfb3bccSCharles-Antoine Couret * in other functions which could break the behaviour 11016cfb3bccSCharles-Antoine Couret * for some fiber phy like 88E1512. 11026cfb3bccSCharles-Antoine Couret * */ 11036cfb3bccSCharles-Antoine Couret if (phydev->link) 11046cfb3bccSCharles-Antoine Couret return 0; 11056cfb3bccSCharles-Antoine Couret 11066cfb3bccSCharles-Antoine Couret /* If fiber link is down, check and save copper mode state */ 11076cfb3bccSCharles-Antoine Couret err = phy_write(phydev, MII_MARVELL_PHY_PAGE, MII_M1111_COPPER); 11086cfb3bccSCharles-Antoine Couret if (err < 0) 11096cfb3bccSCharles-Antoine Couret goto error; 11106cfb3bccSCharles-Antoine Couret } 11116cfb3bccSCharles-Antoine Couret 11126cfb3bccSCharles-Antoine Couret return marvell_read_status_page(phydev, MII_M1111_COPPER); 11136cfb3bccSCharles-Antoine Couret 11146cfb3bccSCharles-Antoine Couret error: 11156cfb3bccSCharles-Antoine Couret phy_write(phydev, MII_MARVELL_PHY_PAGE, MII_M1111_COPPER); 11166cfb3bccSCharles-Antoine Couret return err; 11176cfb3bccSCharles-Antoine Couret } 11186b358aedSSebastian Hesselbarth static int marvell_aneg_done(struct phy_device *phydev) 11196b358aedSSebastian Hesselbarth { 11206b358aedSSebastian Hesselbarth int retval = phy_read(phydev, MII_M1011_PHY_STATUS); 11216b358aedSSebastian Hesselbarth return (retval < 0) ? retval : (retval & MII_M1011_PHY_STATUS_RESOLVED); 11226b358aedSSebastian Hesselbarth } 11236b358aedSSebastian Hesselbarth 1124dcd07be3SAnatolij Gustschin static int m88e1121_did_interrupt(struct phy_device *phydev) 1125dcd07be3SAnatolij Gustschin { 1126dcd07be3SAnatolij Gustschin int imask; 1127dcd07be3SAnatolij Gustschin 1128dcd07be3SAnatolij Gustschin imask = phy_read(phydev, MII_M1011_IEVENT); 1129dcd07be3SAnatolij Gustschin 1130dcd07be3SAnatolij Gustschin if (imask & MII_M1011_IMASK_INIT) 1131dcd07be3SAnatolij Gustschin return 1; 1132dcd07be3SAnatolij Gustschin 1133dcd07be3SAnatolij Gustschin return 0; 1134dcd07be3SAnatolij Gustschin } 1135dcd07be3SAnatolij Gustschin 11363871c387SMichael Stapelberg static void m88e1318_get_wol(struct phy_device *phydev, struct ethtool_wolinfo *wol) 11373871c387SMichael Stapelberg { 11383871c387SMichael Stapelberg wol->supported = WAKE_MAGIC; 11393871c387SMichael Stapelberg wol->wolopts = 0; 11403871c387SMichael Stapelberg 11413871c387SMichael Stapelberg if (phy_write(phydev, MII_MARVELL_PHY_PAGE, 11423871c387SMichael Stapelberg MII_88E1318S_PHY_WOL_PAGE) < 0) 11433871c387SMichael Stapelberg return; 11443871c387SMichael Stapelberg 11453871c387SMichael Stapelberg if (phy_read(phydev, MII_88E1318S_PHY_WOL_CTRL) & 11463871c387SMichael Stapelberg MII_88E1318S_PHY_WOL_CTRL_MAGIC_PACKET_MATCH_ENABLE) 11473871c387SMichael Stapelberg wol->wolopts |= WAKE_MAGIC; 11483871c387SMichael Stapelberg 11493871c387SMichael Stapelberg if (phy_write(phydev, MII_MARVELL_PHY_PAGE, 0x00) < 0) 11503871c387SMichael Stapelberg return; 11513871c387SMichael Stapelberg } 11523871c387SMichael Stapelberg 11533871c387SMichael Stapelberg static int m88e1318_set_wol(struct phy_device *phydev, struct ethtool_wolinfo *wol) 11543871c387SMichael Stapelberg { 11553871c387SMichael Stapelberg int err, oldpage, temp; 11563871c387SMichael Stapelberg 11573871c387SMichael Stapelberg oldpage = phy_read(phydev, MII_MARVELL_PHY_PAGE); 11583871c387SMichael Stapelberg 11593871c387SMichael Stapelberg if (wol->wolopts & WAKE_MAGIC) { 11603871c387SMichael Stapelberg /* Explicitly switch to page 0x00, just to be sure */ 11613871c387SMichael Stapelberg err = phy_write(phydev, MII_MARVELL_PHY_PAGE, 0x00); 11623871c387SMichael Stapelberg if (err < 0) 11633871c387SMichael Stapelberg return err; 11643871c387SMichael Stapelberg 11653871c387SMichael Stapelberg /* Enable the WOL interrupt */ 11663871c387SMichael Stapelberg temp = phy_read(phydev, MII_88E1318S_PHY_CSIER); 11673871c387SMichael Stapelberg temp |= MII_88E1318S_PHY_CSIER_WOL_EIE; 11683871c387SMichael Stapelberg err = phy_write(phydev, MII_88E1318S_PHY_CSIER, temp); 11693871c387SMichael Stapelberg if (err < 0) 11703871c387SMichael Stapelberg return err; 11713871c387SMichael Stapelberg 11723871c387SMichael Stapelberg err = phy_write(phydev, MII_MARVELL_PHY_PAGE, 11733871c387SMichael Stapelberg MII_88E1318S_PHY_LED_PAGE); 11743871c387SMichael Stapelberg if (err < 0) 11753871c387SMichael Stapelberg return err; 11763871c387SMichael Stapelberg 11773871c387SMichael Stapelberg /* Setup LED[2] as interrupt pin (active low) */ 11783871c387SMichael Stapelberg temp = phy_read(phydev, MII_88E1318S_PHY_LED_TCR); 11793871c387SMichael Stapelberg temp &= ~MII_88E1318S_PHY_LED_TCR_FORCE_INT; 11803871c387SMichael Stapelberg temp |= MII_88E1318S_PHY_LED_TCR_INTn_ENABLE; 11813871c387SMichael Stapelberg temp |= MII_88E1318S_PHY_LED_TCR_INT_ACTIVE_LOW; 11823871c387SMichael Stapelberg err = phy_write(phydev, MII_88E1318S_PHY_LED_TCR, temp); 11833871c387SMichael Stapelberg if (err < 0) 11843871c387SMichael Stapelberg return err; 11853871c387SMichael Stapelberg 11863871c387SMichael Stapelberg err = phy_write(phydev, MII_MARVELL_PHY_PAGE, 11873871c387SMichael Stapelberg MII_88E1318S_PHY_WOL_PAGE); 11883871c387SMichael Stapelberg if (err < 0) 11893871c387SMichael Stapelberg return err; 11903871c387SMichael Stapelberg 11913871c387SMichael Stapelberg /* Store the device address for the magic packet */ 11923871c387SMichael Stapelberg err = phy_write(phydev, MII_88E1318S_PHY_MAGIC_PACKET_WORD2, 11933871c387SMichael Stapelberg ((phydev->attached_dev->dev_addr[5] << 8) | 11943871c387SMichael Stapelberg phydev->attached_dev->dev_addr[4])); 11953871c387SMichael Stapelberg if (err < 0) 11963871c387SMichael Stapelberg return err; 11973871c387SMichael Stapelberg err = phy_write(phydev, MII_88E1318S_PHY_MAGIC_PACKET_WORD1, 11983871c387SMichael Stapelberg ((phydev->attached_dev->dev_addr[3] << 8) | 11993871c387SMichael Stapelberg phydev->attached_dev->dev_addr[2])); 12003871c387SMichael Stapelberg if (err < 0) 12013871c387SMichael Stapelberg return err; 12023871c387SMichael Stapelberg err = phy_write(phydev, MII_88E1318S_PHY_MAGIC_PACKET_WORD0, 12033871c387SMichael Stapelberg ((phydev->attached_dev->dev_addr[1] << 8) | 12043871c387SMichael Stapelberg phydev->attached_dev->dev_addr[0])); 12053871c387SMichael Stapelberg if (err < 0) 12063871c387SMichael Stapelberg return err; 12073871c387SMichael Stapelberg 12083871c387SMichael Stapelberg /* Clear WOL status and enable magic packet matching */ 12093871c387SMichael Stapelberg temp = phy_read(phydev, MII_88E1318S_PHY_WOL_CTRL); 12103871c387SMichael Stapelberg temp |= MII_88E1318S_PHY_WOL_CTRL_CLEAR_WOL_STATUS; 12113871c387SMichael Stapelberg temp |= MII_88E1318S_PHY_WOL_CTRL_MAGIC_PACKET_MATCH_ENABLE; 12123871c387SMichael Stapelberg err = phy_write(phydev, MII_88E1318S_PHY_WOL_CTRL, temp); 12133871c387SMichael Stapelberg if (err < 0) 12143871c387SMichael Stapelberg return err; 12153871c387SMichael Stapelberg } else { 12163871c387SMichael Stapelberg err = phy_write(phydev, MII_MARVELL_PHY_PAGE, 12173871c387SMichael Stapelberg MII_88E1318S_PHY_WOL_PAGE); 12183871c387SMichael Stapelberg if (err < 0) 12193871c387SMichael Stapelberg return err; 12203871c387SMichael Stapelberg 12213871c387SMichael Stapelberg /* Clear WOL status and disable magic packet matching */ 12223871c387SMichael Stapelberg temp = phy_read(phydev, MII_88E1318S_PHY_WOL_CTRL); 12233871c387SMichael Stapelberg temp |= MII_88E1318S_PHY_WOL_CTRL_CLEAR_WOL_STATUS; 12243871c387SMichael Stapelberg temp &= ~MII_88E1318S_PHY_WOL_CTRL_MAGIC_PACKET_MATCH_ENABLE; 12253871c387SMichael Stapelberg err = phy_write(phydev, MII_88E1318S_PHY_WOL_CTRL, temp); 12263871c387SMichael Stapelberg if (err < 0) 12273871c387SMichael Stapelberg return err; 12283871c387SMichael Stapelberg } 12293871c387SMichael Stapelberg 12303871c387SMichael Stapelberg err = phy_write(phydev, MII_MARVELL_PHY_PAGE, oldpage); 12313871c387SMichael Stapelberg if (err < 0) 12323871c387SMichael Stapelberg return err; 12333871c387SMichael Stapelberg 12343871c387SMichael Stapelberg return 0; 12353871c387SMichael Stapelberg } 12363871c387SMichael Stapelberg 1237d2fa47d9SAndrew Lunn static int marvell_get_sset_count(struct phy_device *phydev) 1238d2fa47d9SAndrew Lunn { 1239d2fa47d9SAndrew Lunn return ARRAY_SIZE(marvell_hw_stats); 1240d2fa47d9SAndrew Lunn } 1241d2fa47d9SAndrew Lunn 1242d2fa47d9SAndrew Lunn static void marvell_get_strings(struct phy_device *phydev, u8 *data) 1243d2fa47d9SAndrew Lunn { 1244d2fa47d9SAndrew Lunn int i; 1245d2fa47d9SAndrew Lunn 1246d2fa47d9SAndrew Lunn for (i = 0; i < ARRAY_SIZE(marvell_hw_stats); i++) { 1247d2fa47d9SAndrew Lunn memcpy(data + i * ETH_GSTRING_LEN, 1248d2fa47d9SAndrew Lunn marvell_hw_stats[i].string, ETH_GSTRING_LEN); 1249d2fa47d9SAndrew Lunn } 1250d2fa47d9SAndrew Lunn } 1251d2fa47d9SAndrew Lunn 1252d2fa47d9SAndrew Lunn #ifndef UINT64_MAX 1253d2fa47d9SAndrew Lunn #define UINT64_MAX (u64)(~((u64)0)) 1254d2fa47d9SAndrew Lunn #endif 1255d2fa47d9SAndrew Lunn static u64 marvell_get_stat(struct phy_device *phydev, int i) 1256d2fa47d9SAndrew Lunn { 1257d2fa47d9SAndrew Lunn struct marvell_hw_stat stat = marvell_hw_stats[i]; 1258d2fa47d9SAndrew Lunn struct marvell_priv *priv = phydev->priv; 1259321b4d4bSAndrew Lunn int err, oldpage, val; 1260321b4d4bSAndrew Lunn u64 ret; 1261d2fa47d9SAndrew Lunn 1262d2fa47d9SAndrew Lunn oldpage = phy_read(phydev, MII_MARVELL_PHY_PAGE); 1263d2fa47d9SAndrew Lunn err = phy_write(phydev, MII_MARVELL_PHY_PAGE, 1264d2fa47d9SAndrew Lunn stat.page); 1265d2fa47d9SAndrew Lunn if (err < 0) 1266d2fa47d9SAndrew Lunn return UINT64_MAX; 1267d2fa47d9SAndrew Lunn 1268d2fa47d9SAndrew Lunn val = phy_read(phydev, stat.reg); 1269d2fa47d9SAndrew Lunn if (val < 0) { 1270321b4d4bSAndrew Lunn ret = UINT64_MAX; 1271d2fa47d9SAndrew Lunn } else { 1272d2fa47d9SAndrew Lunn val = val & ((1 << stat.bits) - 1); 1273d2fa47d9SAndrew Lunn priv->stats[i] += val; 1274321b4d4bSAndrew Lunn ret = priv->stats[i]; 1275d2fa47d9SAndrew Lunn } 1276d2fa47d9SAndrew Lunn 1277d2fa47d9SAndrew Lunn phy_write(phydev, MII_MARVELL_PHY_PAGE, oldpage); 1278d2fa47d9SAndrew Lunn 1279321b4d4bSAndrew Lunn return ret; 1280d2fa47d9SAndrew Lunn } 1281d2fa47d9SAndrew Lunn 1282d2fa47d9SAndrew Lunn static void marvell_get_stats(struct phy_device *phydev, 1283d2fa47d9SAndrew Lunn struct ethtool_stats *stats, u64 *data) 1284d2fa47d9SAndrew Lunn { 1285d2fa47d9SAndrew Lunn int i; 1286d2fa47d9SAndrew Lunn 1287d2fa47d9SAndrew Lunn for (i = 0; i < ARRAY_SIZE(marvell_hw_stats); i++) 1288d2fa47d9SAndrew Lunn data[i] = marvell_get_stat(phydev, i); 1289d2fa47d9SAndrew Lunn } 1290d2fa47d9SAndrew Lunn 1291d2fa47d9SAndrew Lunn static int marvell_probe(struct phy_device *phydev) 1292d2fa47d9SAndrew Lunn { 1293d2fa47d9SAndrew Lunn struct marvell_priv *priv; 1294d2fa47d9SAndrew Lunn 1295e5a03bfdSAndrew Lunn priv = devm_kzalloc(&phydev->mdio.dev, sizeof(*priv), GFP_KERNEL); 1296d2fa47d9SAndrew Lunn if (!priv) 1297d2fa47d9SAndrew Lunn return -ENOMEM; 1298d2fa47d9SAndrew Lunn 1299d2fa47d9SAndrew Lunn phydev->priv = priv; 1300d2fa47d9SAndrew Lunn 1301d2fa47d9SAndrew Lunn return 0; 1302d2fa47d9SAndrew Lunn } 1303d2fa47d9SAndrew Lunn 1304e5479239SOlof Johansson static struct phy_driver marvell_drivers[] = { 1305e5479239SOlof Johansson { 13062f495c39SBenjamin Herrenschmidt .phy_id = MARVELL_PHY_ID_88E1101, 13072f495c39SBenjamin Herrenschmidt .phy_id_mask = MARVELL_PHY_ID_MASK, 130800db8189SAndy Fleming .name = "Marvell 88E1101", 130900db8189SAndy Fleming .features = PHY_GBIT_FEATURES, 1310d2fa47d9SAndrew Lunn .probe = marvell_probe, 131100db8189SAndy Fleming .flags = PHY_HAS_INTERRUPT, 131279be1a1cSClemens Gruber .config_init = &marvell_config_init, 131300db8189SAndy Fleming .config_aneg = &marvell_config_aneg, 131400db8189SAndy Fleming .read_status = &genphy_read_status, 131500db8189SAndy Fleming .ack_interrupt = &marvell_ack_interrupt, 131600db8189SAndy Fleming .config_intr = &marvell_config_intr, 13170898b448SSebastian Hesselbarth .resume = &genphy_resume, 13180898b448SSebastian Hesselbarth .suspend = &genphy_suspend, 1319d2fa47d9SAndrew Lunn .get_sset_count = marvell_get_sset_count, 1320d2fa47d9SAndrew Lunn .get_strings = marvell_get_strings, 1321d2fa47d9SAndrew Lunn .get_stats = marvell_get_stats, 1322e5479239SOlof Johansson }, 1323e5479239SOlof Johansson { 13242f495c39SBenjamin Herrenschmidt .phy_id = MARVELL_PHY_ID_88E1112, 13252f495c39SBenjamin Herrenschmidt .phy_id_mask = MARVELL_PHY_ID_MASK, 132685cfb534SOlof Johansson .name = "Marvell 88E1112", 132785cfb534SOlof Johansson .features = PHY_GBIT_FEATURES, 132885cfb534SOlof Johansson .flags = PHY_HAS_INTERRUPT, 1329d2fa47d9SAndrew Lunn .probe = marvell_probe, 133085cfb534SOlof Johansson .config_init = &m88e1111_config_init, 133185cfb534SOlof Johansson .config_aneg = &marvell_config_aneg, 133285cfb534SOlof Johansson .read_status = &genphy_read_status, 133385cfb534SOlof Johansson .ack_interrupt = &marvell_ack_interrupt, 133485cfb534SOlof Johansson .config_intr = &marvell_config_intr, 13350898b448SSebastian Hesselbarth .resume = &genphy_resume, 13360898b448SSebastian Hesselbarth .suspend = &genphy_suspend, 1337d2fa47d9SAndrew Lunn .get_sset_count = marvell_get_sset_count, 1338d2fa47d9SAndrew Lunn .get_strings = marvell_get_strings, 1339d2fa47d9SAndrew Lunn .get_stats = marvell_get_stats, 134085cfb534SOlof Johansson }, 134185cfb534SOlof Johansson { 13422f495c39SBenjamin Herrenschmidt .phy_id = MARVELL_PHY_ID_88E1111, 13432f495c39SBenjamin Herrenschmidt .phy_id_mask = MARVELL_PHY_ID_MASK, 134476884679SAndy Fleming .name = "Marvell 88E1111", 134576884679SAndy Fleming .features = PHY_GBIT_FEATURES, 134676884679SAndy Fleming .flags = PHY_HAS_INTERRUPT, 1347d2fa47d9SAndrew Lunn .probe = marvell_probe, 1348e5479239SOlof Johansson .config_init = &m88e1111_config_init, 13493ec0a0f1SHarini Katakam .config_aneg = &m88e1111_config_aneg, 1350be937f1fSAlexandr Smirnov .read_status = &marvell_read_status, 135176884679SAndy Fleming .ack_interrupt = &marvell_ack_interrupt, 135276884679SAndy Fleming .config_intr = &marvell_config_intr, 13530898b448SSebastian Hesselbarth .resume = &genphy_resume, 13540898b448SSebastian Hesselbarth .suspend = &genphy_suspend, 1355d2fa47d9SAndrew Lunn .get_sset_count = marvell_get_sset_count, 1356d2fa47d9SAndrew Lunn .get_strings = marvell_get_strings, 1357d2fa47d9SAndrew Lunn .get_stats = marvell_get_stats, 1358e5479239SOlof Johansson }, 1359e5479239SOlof Johansson { 13602f495c39SBenjamin Herrenschmidt .phy_id = MARVELL_PHY_ID_88E1118, 13612f495c39SBenjamin Herrenschmidt .phy_id_mask = MARVELL_PHY_ID_MASK, 1362605f196eSRon Madrid .name = "Marvell 88E1118", 1363605f196eSRon Madrid .features = PHY_GBIT_FEATURES, 1364605f196eSRon Madrid .flags = PHY_HAS_INTERRUPT, 1365d2fa47d9SAndrew Lunn .probe = marvell_probe, 1366605f196eSRon Madrid .config_init = &m88e1118_config_init, 1367605f196eSRon Madrid .config_aneg = &m88e1118_config_aneg, 1368605f196eSRon Madrid .read_status = &genphy_read_status, 1369605f196eSRon Madrid .ack_interrupt = &marvell_ack_interrupt, 1370605f196eSRon Madrid .config_intr = &marvell_config_intr, 13710898b448SSebastian Hesselbarth .resume = &genphy_resume, 13720898b448SSebastian Hesselbarth .suspend = &genphy_suspend, 1373d2fa47d9SAndrew Lunn .get_sset_count = marvell_get_sset_count, 1374d2fa47d9SAndrew Lunn .get_strings = marvell_get_strings, 1375d2fa47d9SAndrew Lunn .get_stats = marvell_get_stats, 1376605f196eSRon Madrid }, 1377605f196eSRon Madrid { 13782f495c39SBenjamin Herrenschmidt .phy_id = MARVELL_PHY_ID_88E1121R, 13792f495c39SBenjamin Herrenschmidt .phy_id_mask = MARVELL_PHY_ID_MASK, 1380140bc929SSergei Poselenov .name = "Marvell 88E1121R", 1381140bc929SSergei Poselenov .features = PHY_GBIT_FEATURES, 1382140bc929SSergei Poselenov .flags = PHY_HAS_INTERRUPT, 1383d2fa47d9SAndrew Lunn .probe = marvell_probe, 1384fdecf36fSClemens Gruber .config_init = &m88e1121_config_init, 1385140bc929SSergei Poselenov .config_aneg = &m88e1121_config_aneg, 1386140bc929SSergei Poselenov .read_status = &marvell_read_status, 1387140bc929SSergei Poselenov .ack_interrupt = &marvell_ack_interrupt, 1388140bc929SSergei Poselenov .config_intr = &marvell_config_intr, 1389dcd07be3SAnatolij Gustschin .did_interrupt = &m88e1121_did_interrupt, 13900898b448SSebastian Hesselbarth .resume = &genphy_resume, 13910898b448SSebastian Hesselbarth .suspend = &genphy_suspend, 1392d2fa47d9SAndrew Lunn .get_sset_count = marvell_get_sset_count, 1393d2fa47d9SAndrew Lunn .get_strings = marvell_get_strings, 1394d2fa47d9SAndrew Lunn .get_stats = marvell_get_stats, 1395140bc929SSergei Poselenov }, 1396140bc929SSergei Poselenov { 1397337ac9d5SCyril Chemparathy .phy_id = MARVELL_PHY_ID_88E1318S, 13986ba74014SLinus Torvalds .phy_id_mask = MARVELL_PHY_ID_MASK, 1399337ac9d5SCyril Chemparathy .name = "Marvell 88E1318S", 14003ff1c259SCyril Chemparathy .features = PHY_GBIT_FEATURES, 14013ff1c259SCyril Chemparathy .flags = PHY_HAS_INTERRUPT, 1402d2fa47d9SAndrew Lunn .probe = marvell_probe, 1403fdecf36fSClemens Gruber .config_init = &m88e1121_config_init, 1404337ac9d5SCyril Chemparathy .config_aneg = &m88e1318_config_aneg, 14053ff1c259SCyril Chemparathy .read_status = &marvell_read_status, 14063ff1c259SCyril Chemparathy .ack_interrupt = &marvell_ack_interrupt, 14073ff1c259SCyril Chemparathy .config_intr = &marvell_config_intr, 14083ff1c259SCyril Chemparathy .did_interrupt = &m88e1121_did_interrupt, 14093871c387SMichael Stapelberg .get_wol = &m88e1318_get_wol, 14103871c387SMichael Stapelberg .set_wol = &m88e1318_set_wol, 14110898b448SSebastian Hesselbarth .resume = &genphy_resume, 14120898b448SSebastian Hesselbarth .suspend = &genphy_suspend, 1413d2fa47d9SAndrew Lunn .get_sset_count = marvell_get_sset_count, 1414d2fa47d9SAndrew Lunn .get_strings = marvell_get_strings, 1415d2fa47d9SAndrew Lunn .get_stats = marvell_get_stats, 14163ff1c259SCyril Chemparathy }, 14173ff1c259SCyril Chemparathy { 14182f495c39SBenjamin Herrenschmidt .phy_id = MARVELL_PHY_ID_88E1145, 14192f495c39SBenjamin Herrenschmidt .phy_id_mask = MARVELL_PHY_ID_MASK, 142076884679SAndy Fleming .name = "Marvell 88E1145", 142176884679SAndy Fleming .features = PHY_GBIT_FEATURES, 142276884679SAndy Fleming .flags = PHY_HAS_INTERRUPT, 1423d2fa47d9SAndrew Lunn .probe = marvell_probe, 142476884679SAndy Fleming .config_init = &m88e1145_config_init, 142576884679SAndy Fleming .config_aneg = &marvell_config_aneg, 142676884679SAndy Fleming .read_status = &genphy_read_status, 142776884679SAndy Fleming .ack_interrupt = &marvell_ack_interrupt, 142876884679SAndy 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, 1434ac8c635aSOlof Johansson }, 1435ac8c635aSOlof Johansson { 143690600732SDavid Daney .phy_id = MARVELL_PHY_ID_88E1149R, 143790600732SDavid Daney .phy_id_mask = MARVELL_PHY_ID_MASK, 143890600732SDavid Daney .name = "Marvell 88E1149R", 143990600732SDavid Daney .features = PHY_GBIT_FEATURES, 144090600732SDavid Daney .flags = PHY_HAS_INTERRUPT, 1441d2fa47d9SAndrew Lunn .probe = marvell_probe, 144290600732SDavid Daney .config_init = &m88e1149_config_init, 144390600732SDavid Daney .config_aneg = &m88e1118_config_aneg, 144490600732SDavid Daney .read_status = &genphy_read_status, 144590600732SDavid Daney .ack_interrupt = &marvell_ack_interrupt, 144690600732SDavid Daney .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, 145290600732SDavid Daney }, 145390600732SDavid Daney { 14542f495c39SBenjamin Herrenschmidt .phy_id = MARVELL_PHY_ID_88E1240, 14552f495c39SBenjamin Herrenschmidt .phy_id_mask = MARVELL_PHY_ID_MASK, 1456ac8c635aSOlof Johansson .name = "Marvell 88E1240", 1457ac8c635aSOlof Johansson .features = PHY_GBIT_FEATURES, 1458ac8c635aSOlof Johansson .flags = PHY_HAS_INTERRUPT, 1459d2fa47d9SAndrew Lunn .probe = marvell_probe, 1460ac8c635aSOlof Johansson .config_init = &m88e1111_config_init, 1461ac8c635aSOlof Johansson .config_aneg = &marvell_config_aneg, 1462ac8c635aSOlof Johansson .read_status = &genphy_read_status, 1463ac8c635aSOlof Johansson .ack_interrupt = &marvell_ack_interrupt, 1464ac8c635aSOlof Johansson .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, 1470ac8c635aSOlof Johansson }, 14713da09a51SMichal Simek { 14723da09a51SMichal Simek .phy_id = MARVELL_PHY_ID_88E1116R, 14733da09a51SMichal Simek .phy_id_mask = MARVELL_PHY_ID_MASK, 14743da09a51SMichal Simek .name = "Marvell 88E1116R", 14753da09a51SMichal Simek .features = PHY_GBIT_FEATURES, 14763da09a51SMichal Simek .flags = PHY_HAS_INTERRUPT, 1477d2fa47d9SAndrew Lunn .probe = marvell_probe, 14783da09a51SMichal Simek .config_init = &m88e1116r_config_init, 14793da09a51SMichal Simek .config_aneg = &genphy_config_aneg, 14803da09a51SMichal Simek .read_status = &genphy_read_status, 14813da09a51SMichal Simek .ack_interrupt = &marvell_ack_interrupt, 14823da09a51SMichal Simek .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, 14883da09a51SMichal Simek }, 148910e24caaSMichal Simek { 149010e24caaSMichal Simek .phy_id = MARVELL_PHY_ID_88E1510, 149110e24caaSMichal Simek .phy_id_mask = MARVELL_PHY_ID_MASK, 149210e24caaSMichal Simek .name = "Marvell 88E1510", 14936cfb3bccSCharles-Antoine Couret .features = PHY_GBIT_FEATURES | SUPPORTED_FIBRE, 149410e24caaSMichal Simek .flags = PHY_HAS_INTERRUPT, 1495d2fa47d9SAndrew Lunn .probe = marvell_probe, 1496930b37eeSStefan Roese .config_init = &m88e1510_config_init, 149710e24caaSMichal Simek .config_aneg = &m88e1510_config_aneg, 149810e24caaSMichal Simek .read_status = &marvell_read_status, 149910e24caaSMichal Simek .ack_interrupt = &marvell_ack_interrupt, 150010e24caaSMichal Simek .config_intr = &marvell_config_intr, 150110e24caaSMichal Simek .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, 150710e24caaSMichal Simek }, 15086b358aedSSebastian Hesselbarth { 1509819ec8e1SAndrew Lunn .phy_id = MARVELL_PHY_ID_88E1540, 1510819ec8e1SAndrew Lunn .phy_id_mask = MARVELL_PHY_ID_MASK, 1511819ec8e1SAndrew Lunn .name = "Marvell 88E1540", 1512819ec8e1SAndrew Lunn .features = PHY_GBIT_FEATURES, 1513819ec8e1SAndrew Lunn .flags = PHY_HAS_INTERRUPT, 1514d2fa47d9SAndrew Lunn .probe = marvell_probe, 151579be1a1cSClemens Gruber .config_init = &marvell_config_init, 1516819ec8e1SAndrew Lunn .config_aneg = &m88e1510_config_aneg, 1517819ec8e1SAndrew Lunn .read_status = &marvell_read_status, 1518819ec8e1SAndrew Lunn .ack_interrupt = &marvell_ack_interrupt, 1519819ec8e1SAndrew Lunn .config_intr = &marvell_config_intr, 1520819ec8e1SAndrew Lunn .did_interrupt = &m88e1121_did_interrupt, 1521819ec8e1SAndrew Lunn .resume = &genphy_resume, 1522819ec8e1SAndrew Lunn .suspend = &genphy_suspend, 1523d2fa47d9SAndrew Lunn .get_sset_count = marvell_get_sset_count, 1524d2fa47d9SAndrew Lunn .get_strings = marvell_get_strings, 1525d2fa47d9SAndrew Lunn .get_stats = marvell_get_stats, 1526819ec8e1SAndrew Lunn }, 1527819ec8e1SAndrew Lunn { 15286b358aedSSebastian Hesselbarth .phy_id = MARVELL_PHY_ID_88E3016, 15296b358aedSSebastian Hesselbarth .phy_id_mask = MARVELL_PHY_ID_MASK, 15306b358aedSSebastian Hesselbarth .name = "Marvell 88E3016", 15316b358aedSSebastian Hesselbarth .features = PHY_BASIC_FEATURES, 15326b358aedSSebastian Hesselbarth .flags = PHY_HAS_INTERRUPT, 1533d2fa47d9SAndrew Lunn .probe = marvell_probe, 15346b358aedSSebastian Hesselbarth .config_aneg = &genphy_config_aneg, 15356b358aedSSebastian Hesselbarth .config_init = &m88e3016_config_init, 15366b358aedSSebastian Hesselbarth .aneg_done = &marvell_aneg_done, 15376b358aedSSebastian Hesselbarth .read_status = &marvell_read_status, 15386b358aedSSebastian Hesselbarth .ack_interrupt = &marvell_ack_interrupt, 15396b358aedSSebastian Hesselbarth .config_intr = &marvell_config_intr, 15406b358aedSSebastian Hesselbarth .did_interrupt = &m88e1121_did_interrupt, 15416b358aedSSebastian Hesselbarth .resume = &genphy_resume, 15426b358aedSSebastian 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, 15466b358aedSSebastian Hesselbarth }, 154776884679SAndy Fleming }; 154876884679SAndy Fleming 154950fd7150SJohan Hovold module_phy_driver(marvell_drivers); 15504e4f10f6SDavid Woodhouse 1551cf93c945SUwe Kleine-König static struct mdio_device_id __maybe_unused marvell_tbl[] = { 1552f5e1cabfSMichal Simek { MARVELL_PHY_ID_88E1101, MARVELL_PHY_ID_MASK }, 1553f5e1cabfSMichal Simek { MARVELL_PHY_ID_88E1112, MARVELL_PHY_ID_MASK }, 1554f5e1cabfSMichal Simek { MARVELL_PHY_ID_88E1111, MARVELL_PHY_ID_MASK }, 1555f5e1cabfSMichal Simek { MARVELL_PHY_ID_88E1118, MARVELL_PHY_ID_MASK }, 1556f5e1cabfSMichal Simek { MARVELL_PHY_ID_88E1121R, MARVELL_PHY_ID_MASK }, 1557f5e1cabfSMichal Simek { MARVELL_PHY_ID_88E1145, MARVELL_PHY_ID_MASK }, 1558f5e1cabfSMichal Simek { MARVELL_PHY_ID_88E1149R, MARVELL_PHY_ID_MASK }, 1559f5e1cabfSMichal Simek { MARVELL_PHY_ID_88E1240, MARVELL_PHY_ID_MASK }, 1560f5e1cabfSMichal Simek { MARVELL_PHY_ID_88E1318S, MARVELL_PHY_ID_MASK }, 15613da09a51SMichal Simek { MARVELL_PHY_ID_88E1116R, MARVELL_PHY_ID_MASK }, 156210e24caaSMichal Simek { MARVELL_PHY_ID_88E1510, MARVELL_PHY_ID_MASK }, 1563819ec8e1SAndrew Lunn { MARVELL_PHY_ID_88E1540, MARVELL_PHY_ID_MASK }, 15646b358aedSSebastian Hesselbarth { MARVELL_PHY_ID_88E3016, MARVELL_PHY_ID_MASK }, 15654e4f10f6SDavid Woodhouse { } 15664e4f10f6SDavid Woodhouse }; 15674e4f10f6SDavid Woodhouse 15684e4f10f6SDavid Woodhouse MODULE_DEVICE_TABLE(mdio, marvell_tbl); 1569