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 * 1000db8189SAndy Fleming * This program is free software; you can redistribute it and/or modify it 1100db8189SAndy Fleming * under the terms of the GNU General Public License as published by the 1200db8189SAndy Fleming * Free Software Foundation; either version 2 of the License, or (at your 1300db8189SAndy Fleming * option) any later version. 1400db8189SAndy Fleming * 1500db8189SAndy Fleming */ 1600db8189SAndy Fleming #include <linux/kernel.h> 1700db8189SAndy Fleming #include <linux/string.h> 1800db8189SAndy Fleming #include <linux/errno.h> 1900db8189SAndy Fleming #include <linux/unistd.h> 2000db8189SAndy Fleming #include <linux/interrupt.h> 2100db8189SAndy Fleming #include <linux/init.h> 2200db8189SAndy Fleming #include <linux/delay.h> 2300db8189SAndy Fleming #include <linux/netdevice.h> 2400db8189SAndy Fleming #include <linux/etherdevice.h> 2500db8189SAndy Fleming #include <linux/skbuff.h> 2600db8189SAndy Fleming #include <linux/spinlock.h> 2700db8189SAndy Fleming #include <linux/mm.h> 2800db8189SAndy Fleming #include <linux/module.h> 2900db8189SAndy Fleming #include <linux/mii.h> 3000db8189SAndy Fleming #include <linux/ethtool.h> 3100db8189SAndy Fleming #include <linux/phy.h> 322f495c39SBenjamin Herrenschmidt #include <linux/marvell_phy.h> 33cf41a51dSDavid Daney #include <linux/of.h> 3400db8189SAndy Fleming 3500db8189SAndy Fleming #include <asm/io.h> 3600db8189SAndy Fleming #include <asm/irq.h> 3700db8189SAndy Fleming #include <asm/uaccess.h> 3800db8189SAndy Fleming 3927d916d6SDavid Daney #define MII_MARVELL_PHY_PAGE 22 4027d916d6SDavid Daney 4100db8189SAndy Fleming #define MII_M1011_IEVENT 0x13 4200db8189SAndy Fleming #define MII_M1011_IEVENT_CLEAR 0x0000 4300db8189SAndy Fleming 4400db8189SAndy Fleming #define MII_M1011_IMASK 0x12 4500db8189SAndy Fleming #define MII_M1011_IMASK_INIT 0x6400 4600db8189SAndy Fleming #define MII_M1011_IMASK_CLEAR 0x0000 4700db8189SAndy Fleming 4876884679SAndy Fleming #define MII_M1011_PHY_SCR 0x10 4976884679SAndy Fleming #define MII_M1011_PHY_SCR_AUTO_CROSS 0x0060 5076884679SAndy Fleming 5176884679SAndy Fleming #define MII_M1145_PHY_EXT_CR 0x14 5276884679SAndy Fleming #define MII_M1145_RGMII_RX_DELAY 0x0080 5376884679SAndy Fleming #define MII_M1145_RGMII_TX_DELAY 0x0002 5476884679SAndy Fleming 5576884679SAndy Fleming #define MII_M1111_PHY_LED_CONTROL 0x18 5676884679SAndy Fleming #define MII_M1111_PHY_LED_DIRECT 0x4100 5776884679SAndy Fleming #define MII_M1111_PHY_LED_COMBINE 0x411c 58895ee682SKim Phillips #define MII_M1111_PHY_EXT_CR 0x14 59895ee682SKim Phillips #define MII_M1111_RX_DELAY 0x80 60895ee682SKim Phillips #define MII_M1111_TX_DELAY 0x2 61895ee682SKim Phillips #define MII_M1111_PHY_EXT_SR 0x1b 62be937f1fSAlexandr Smirnov 63895ee682SKim Phillips #define MII_M1111_HWCFG_MODE_MASK 0xf 64be937f1fSAlexandr Smirnov #define MII_M1111_HWCFG_MODE_COPPER_RGMII 0xb 65be937f1fSAlexandr Smirnov #define MII_M1111_HWCFG_MODE_FIBER_RGMII 0x3 664117b5beSKapil Juneja #define MII_M1111_HWCFG_MODE_SGMII_NO_CLK 0x4 675f8cbc13SLiu Yu-B13201 #define MII_M1111_HWCFG_MODE_COPPER_RTBI 0x9 68be937f1fSAlexandr Smirnov #define MII_M1111_HWCFG_FIBER_COPPER_AUTO 0x8000 69be937f1fSAlexandr Smirnov #define MII_M1111_HWCFG_FIBER_COPPER_RES 0x2000 70be937f1fSAlexandr Smirnov 71be937f1fSAlexandr Smirnov #define MII_M1111_COPPER 0 72be937f1fSAlexandr Smirnov #define MII_M1111_FIBER 1 73be937f1fSAlexandr Smirnov 74c477d044SCyril Chemparathy #define MII_88E1121_PHY_MSCR_PAGE 2 75c477d044SCyril Chemparathy #define MII_88E1121_PHY_MSCR_REG 21 76c477d044SCyril Chemparathy #define MII_88E1121_PHY_MSCR_RX_DELAY BIT(5) 77c477d044SCyril Chemparathy #define MII_88E1121_PHY_MSCR_TX_DELAY BIT(4) 78c477d044SCyril Chemparathy #define MII_88E1121_PHY_MSCR_DELAY_MASK (~(0x3 << 4)) 79c477d044SCyril Chemparathy 80337ac9d5SCyril Chemparathy #define MII_88E1318S_PHY_MSCR1_REG 16 81337ac9d5SCyril Chemparathy #define MII_88E1318S_PHY_MSCR1_PAD_ODD BIT(6) 823ff1c259SCyril Chemparathy 83140bc929SSergei Poselenov #define MII_88E1121_PHY_LED_CTRL 16 84140bc929SSergei Poselenov #define MII_88E1121_PHY_LED_PAGE 3 85140bc929SSergei Poselenov #define MII_88E1121_PHY_LED_DEF 0x0030 86140bc929SSergei Poselenov 87be937f1fSAlexandr Smirnov #define MII_M1011_PHY_STATUS 0x11 88be937f1fSAlexandr Smirnov #define MII_M1011_PHY_STATUS_1000 0x8000 89be937f1fSAlexandr Smirnov #define MII_M1011_PHY_STATUS_100 0x4000 90be937f1fSAlexandr Smirnov #define MII_M1011_PHY_STATUS_SPD_MASK 0xc000 91be937f1fSAlexandr Smirnov #define MII_M1011_PHY_STATUS_FULLDUPLEX 0x2000 92be937f1fSAlexandr Smirnov #define MII_M1011_PHY_STATUS_RESOLVED 0x0800 93be937f1fSAlexandr Smirnov #define MII_M1011_PHY_STATUS_LINK 0x0400 94be937f1fSAlexandr Smirnov 9576884679SAndy Fleming 9600db8189SAndy Fleming MODULE_DESCRIPTION("Marvell PHY driver"); 9700db8189SAndy Fleming MODULE_AUTHOR("Andy Fleming"); 9800db8189SAndy Fleming MODULE_LICENSE("GPL"); 9900db8189SAndy Fleming 10000db8189SAndy Fleming static int marvell_ack_interrupt(struct phy_device *phydev) 10100db8189SAndy Fleming { 10200db8189SAndy Fleming int err; 10300db8189SAndy Fleming 10400db8189SAndy Fleming /* Clear the interrupts by reading the reg */ 10500db8189SAndy Fleming err = phy_read(phydev, MII_M1011_IEVENT); 10600db8189SAndy Fleming 10700db8189SAndy Fleming if (err < 0) 10800db8189SAndy Fleming return err; 10900db8189SAndy Fleming 11000db8189SAndy Fleming return 0; 11100db8189SAndy Fleming } 11200db8189SAndy Fleming 11300db8189SAndy Fleming static int marvell_config_intr(struct phy_device *phydev) 11400db8189SAndy Fleming { 11500db8189SAndy Fleming int err; 11600db8189SAndy Fleming 11700db8189SAndy Fleming if (phydev->interrupts == PHY_INTERRUPT_ENABLED) 11800db8189SAndy Fleming err = phy_write(phydev, MII_M1011_IMASK, MII_M1011_IMASK_INIT); 11900db8189SAndy Fleming else 12000db8189SAndy Fleming err = phy_write(phydev, MII_M1011_IMASK, MII_M1011_IMASK_CLEAR); 12100db8189SAndy Fleming 12200db8189SAndy Fleming return err; 12300db8189SAndy Fleming } 12400db8189SAndy Fleming 12500db8189SAndy Fleming static int marvell_config_aneg(struct phy_device *phydev) 12600db8189SAndy Fleming { 12700db8189SAndy Fleming int err; 12800db8189SAndy Fleming 12900db8189SAndy Fleming /* The Marvell PHY has an errata which requires 13000db8189SAndy Fleming * that certain registers get written in order 13100db8189SAndy Fleming * to restart autonegotiation */ 13200db8189SAndy Fleming err = phy_write(phydev, MII_BMCR, BMCR_RESET); 13300db8189SAndy Fleming 13400db8189SAndy Fleming if (err < 0) 13500db8189SAndy Fleming return err; 13600db8189SAndy Fleming 13700db8189SAndy Fleming err = phy_write(phydev, 0x1d, 0x1f); 13800db8189SAndy Fleming if (err < 0) 13900db8189SAndy Fleming return err; 14000db8189SAndy Fleming 14100db8189SAndy Fleming err = phy_write(phydev, 0x1e, 0x200c); 14200db8189SAndy Fleming if (err < 0) 14300db8189SAndy Fleming return err; 14400db8189SAndy Fleming 14500db8189SAndy Fleming err = phy_write(phydev, 0x1d, 0x5); 14600db8189SAndy Fleming if (err < 0) 14700db8189SAndy Fleming return err; 14800db8189SAndy Fleming 14900db8189SAndy Fleming err = phy_write(phydev, 0x1e, 0); 15000db8189SAndy Fleming if (err < 0) 15100db8189SAndy Fleming return err; 15200db8189SAndy Fleming 15300db8189SAndy Fleming err = phy_write(phydev, 0x1e, 0x100); 15400db8189SAndy Fleming if (err < 0) 15500db8189SAndy Fleming return err; 15600db8189SAndy Fleming 15776884679SAndy Fleming err = phy_write(phydev, MII_M1011_PHY_SCR, 15876884679SAndy Fleming MII_M1011_PHY_SCR_AUTO_CROSS); 15976884679SAndy Fleming if (err < 0) 16076884679SAndy Fleming return err; 16176884679SAndy Fleming 16276884679SAndy Fleming err = phy_write(phydev, MII_M1111_PHY_LED_CONTROL, 16376884679SAndy Fleming MII_M1111_PHY_LED_DIRECT); 16476884679SAndy Fleming if (err < 0) 16576884679SAndy Fleming return err; 16600db8189SAndy Fleming 16700db8189SAndy Fleming err = genphy_config_aneg(phydev); 1688ff44985SAnton Vorontsov if (err < 0) 16900db8189SAndy Fleming return err; 1708ff44985SAnton Vorontsov 1718ff44985SAnton Vorontsov if (phydev->autoneg != AUTONEG_ENABLE) { 1728ff44985SAnton Vorontsov int bmcr; 1738ff44985SAnton Vorontsov 1748ff44985SAnton Vorontsov /* 1758ff44985SAnton Vorontsov * A write to speed/duplex bits (that is performed by 1768ff44985SAnton Vorontsov * genphy_config_aneg() call above) must be followed by 1778ff44985SAnton Vorontsov * a software reset. Otherwise, the write has no effect. 1788ff44985SAnton Vorontsov */ 1798ff44985SAnton Vorontsov bmcr = phy_read(phydev, MII_BMCR); 1808ff44985SAnton Vorontsov if (bmcr < 0) 1818ff44985SAnton Vorontsov return bmcr; 1828ff44985SAnton Vorontsov 1838ff44985SAnton Vorontsov err = phy_write(phydev, MII_BMCR, bmcr | BMCR_RESET); 1848ff44985SAnton Vorontsov if (err < 0) 1858ff44985SAnton Vorontsov return err; 1868ff44985SAnton Vorontsov } 1878ff44985SAnton Vorontsov 1888ff44985SAnton Vorontsov return 0; 18900db8189SAndy Fleming } 19000db8189SAndy Fleming 191cf41a51dSDavid Daney #ifdef CONFIG_OF_MDIO 192cf41a51dSDavid Daney /* 193cf41a51dSDavid Daney * Set and/or override some configuration registers based on the 194cf41a51dSDavid Daney * marvell,reg-init property stored in the of_node for the phydev. 195cf41a51dSDavid Daney * 196cf41a51dSDavid Daney * marvell,reg-init = <reg-page reg mask value>,...; 197cf41a51dSDavid Daney * 198cf41a51dSDavid Daney * There may be one or more sets of <reg-page reg mask value>: 199cf41a51dSDavid Daney * 200cf41a51dSDavid Daney * reg-page: which register bank to use. 201cf41a51dSDavid Daney * reg: the register. 202cf41a51dSDavid Daney * mask: if non-zero, ANDed with existing register value. 203cf41a51dSDavid Daney * value: ORed with the masked value and written to the regiser. 204cf41a51dSDavid Daney * 205cf41a51dSDavid Daney */ 206cf41a51dSDavid Daney static int marvell_of_reg_init(struct phy_device *phydev) 207cf41a51dSDavid Daney { 208cf41a51dSDavid Daney const __be32 *paddr; 209cf41a51dSDavid Daney int len, i, saved_page, current_page, page_changed, ret; 210cf41a51dSDavid Daney 211cf41a51dSDavid Daney if (!phydev->dev.of_node) 212cf41a51dSDavid Daney return 0; 213cf41a51dSDavid Daney 214cf41a51dSDavid Daney paddr = of_get_property(phydev->dev.of_node, "marvell,reg-init", &len); 215cf41a51dSDavid Daney if (!paddr || len < (4 * sizeof(*paddr))) 216cf41a51dSDavid Daney return 0; 217cf41a51dSDavid Daney 218cf41a51dSDavid Daney saved_page = phy_read(phydev, MII_MARVELL_PHY_PAGE); 219cf41a51dSDavid Daney if (saved_page < 0) 220cf41a51dSDavid Daney return saved_page; 221cf41a51dSDavid Daney page_changed = 0; 222cf41a51dSDavid Daney current_page = saved_page; 223cf41a51dSDavid Daney 224cf41a51dSDavid Daney ret = 0; 225cf41a51dSDavid Daney len /= sizeof(*paddr); 226cf41a51dSDavid Daney for (i = 0; i < len - 3; i += 4) { 227cf41a51dSDavid Daney u16 reg_page = be32_to_cpup(paddr + i); 228cf41a51dSDavid Daney u16 reg = be32_to_cpup(paddr + i + 1); 229cf41a51dSDavid Daney u16 mask = be32_to_cpup(paddr + i + 2); 230cf41a51dSDavid Daney u16 val_bits = be32_to_cpup(paddr + i + 3); 231cf41a51dSDavid Daney int val; 232cf41a51dSDavid Daney 233cf41a51dSDavid Daney if (reg_page != current_page) { 234cf41a51dSDavid Daney current_page = reg_page; 235cf41a51dSDavid Daney page_changed = 1; 236cf41a51dSDavid Daney ret = phy_write(phydev, MII_MARVELL_PHY_PAGE, reg_page); 237cf41a51dSDavid Daney if (ret < 0) 238cf41a51dSDavid Daney goto err; 239cf41a51dSDavid Daney } 240cf41a51dSDavid Daney 241cf41a51dSDavid Daney val = 0; 242cf41a51dSDavid Daney if (mask) { 243cf41a51dSDavid Daney val = phy_read(phydev, reg); 244cf41a51dSDavid Daney if (val < 0) { 245cf41a51dSDavid Daney ret = val; 246cf41a51dSDavid Daney goto err; 247cf41a51dSDavid Daney } 248cf41a51dSDavid Daney val &= mask; 249cf41a51dSDavid Daney } 250cf41a51dSDavid Daney val |= val_bits; 251cf41a51dSDavid Daney 252cf41a51dSDavid Daney ret = phy_write(phydev, reg, val); 253cf41a51dSDavid Daney if (ret < 0) 254cf41a51dSDavid Daney goto err; 255cf41a51dSDavid Daney 256cf41a51dSDavid Daney } 257cf41a51dSDavid Daney err: 258cf41a51dSDavid Daney if (page_changed) { 259cf41a51dSDavid Daney i = phy_write(phydev, MII_MARVELL_PHY_PAGE, saved_page); 260cf41a51dSDavid Daney if (ret == 0) 261cf41a51dSDavid Daney ret = i; 262cf41a51dSDavid Daney } 263cf41a51dSDavid Daney return ret; 264cf41a51dSDavid Daney } 265cf41a51dSDavid Daney #else 266cf41a51dSDavid Daney static int marvell_of_reg_init(struct phy_device *phydev) 267cf41a51dSDavid Daney { 268cf41a51dSDavid Daney return 0; 269cf41a51dSDavid Daney } 270cf41a51dSDavid Daney #endif /* CONFIG_OF_MDIO */ 271cf41a51dSDavid Daney 272140bc929SSergei Poselenov static int m88e1121_config_aneg(struct phy_device *phydev) 273140bc929SSergei Poselenov { 274c477d044SCyril Chemparathy int err, oldpage, mscr; 275c477d044SCyril Chemparathy 27627d916d6SDavid Daney oldpage = phy_read(phydev, MII_MARVELL_PHY_PAGE); 277c477d044SCyril Chemparathy 27827d916d6SDavid Daney err = phy_write(phydev, MII_MARVELL_PHY_PAGE, 279c477d044SCyril Chemparathy MII_88E1121_PHY_MSCR_PAGE); 280c477d044SCyril Chemparathy if (err < 0) 281c477d044SCyril Chemparathy return err; 282be8c6480SArnaud Patard 283be8c6480SArnaud Patard if ((phydev->interface == PHY_INTERFACE_MODE_RGMII) || 284be8c6480SArnaud Patard (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID) || 285be8c6480SArnaud Patard (phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID) || 286be8c6480SArnaud Patard (phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID)) { 287be8c6480SArnaud Patard 288c477d044SCyril Chemparathy mscr = phy_read(phydev, MII_88E1121_PHY_MSCR_REG) & 289c477d044SCyril Chemparathy MII_88E1121_PHY_MSCR_DELAY_MASK; 290c477d044SCyril Chemparathy 291c477d044SCyril Chemparathy if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID) 292c477d044SCyril Chemparathy mscr |= (MII_88E1121_PHY_MSCR_RX_DELAY | 293c477d044SCyril Chemparathy MII_88E1121_PHY_MSCR_TX_DELAY); 294c477d044SCyril Chemparathy else if (phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID) 295c477d044SCyril Chemparathy mscr |= MII_88E1121_PHY_MSCR_RX_DELAY; 296c477d044SCyril Chemparathy else if (phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID) 297c477d044SCyril Chemparathy mscr |= MII_88E1121_PHY_MSCR_TX_DELAY; 298c477d044SCyril Chemparathy 299c477d044SCyril Chemparathy err = phy_write(phydev, MII_88E1121_PHY_MSCR_REG, mscr); 300c477d044SCyril Chemparathy if (err < 0) 301c477d044SCyril Chemparathy return err; 302be8c6480SArnaud Patard } 303c477d044SCyril Chemparathy 30427d916d6SDavid Daney phy_write(phydev, MII_MARVELL_PHY_PAGE, oldpage); 305140bc929SSergei Poselenov 306140bc929SSergei Poselenov err = phy_write(phydev, MII_BMCR, BMCR_RESET); 307140bc929SSergei Poselenov if (err < 0) 308140bc929SSergei Poselenov return err; 309140bc929SSergei Poselenov 310140bc929SSergei Poselenov err = phy_write(phydev, MII_M1011_PHY_SCR, 311140bc929SSergei Poselenov MII_M1011_PHY_SCR_AUTO_CROSS); 312140bc929SSergei Poselenov if (err < 0) 313140bc929SSergei Poselenov return err; 314140bc929SSergei Poselenov 31527d916d6SDavid Daney oldpage = phy_read(phydev, MII_MARVELL_PHY_PAGE); 316140bc929SSergei Poselenov 31727d916d6SDavid Daney phy_write(phydev, MII_MARVELL_PHY_PAGE, MII_88E1121_PHY_LED_PAGE); 318140bc929SSergei Poselenov phy_write(phydev, MII_88E1121_PHY_LED_CTRL, MII_88E1121_PHY_LED_DEF); 31927d916d6SDavid Daney phy_write(phydev, MII_MARVELL_PHY_PAGE, oldpage); 320140bc929SSergei Poselenov 321140bc929SSergei Poselenov err = genphy_config_aneg(phydev); 322140bc929SSergei Poselenov 323140bc929SSergei Poselenov return err; 324140bc929SSergei Poselenov } 325140bc929SSergei Poselenov 326337ac9d5SCyril Chemparathy static int m88e1318_config_aneg(struct phy_device *phydev) 3273ff1c259SCyril Chemparathy { 3283ff1c259SCyril Chemparathy int err, oldpage, mscr; 3293ff1c259SCyril Chemparathy 33027d916d6SDavid Daney oldpage = phy_read(phydev, MII_MARVELL_PHY_PAGE); 3313ff1c259SCyril Chemparathy 33227d916d6SDavid Daney err = phy_write(phydev, MII_MARVELL_PHY_PAGE, 3333ff1c259SCyril Chemparathy MII_88E1121_PHY_MSCR_PAGE); 3343ff1c259SCyril Chemparathy if (err < 0) 3353ff1c259SCyril Chemparathy return err; 3363ff1c259SCyril Chemparathy 337337ac9d5SCyril Chemparathy mscr = phy_read(phydev, MII_88E1318S_PHY_MSCR1_REG); 338337ac9d5SCyril Chemparathy mscr |= MII_88E1318S_PHY_MSCR1_PAD_ODD; 3393ff1c259SCyril Chemparathy 340337ac9d5SCyril Chemparathy err = phy_write(phydev, MII_88E1318S_PHY_MSCR1_REG, mscr); 3413ff1c259SCyril Chemparathy if (err < 0) 3423ff1c259SCyril Chemparathy return err; 3433ff1c259SCyril Chemparathy 34427d916d6SDavid Daney err = phy_write(phydev, MII_MARVELL_PHY_PAGE, oldpage); 3453ff1c259SCyril Chemparathy if (err < 0) 3463ff1c259SCyril Chemparathy return err; 3473ff1c259SCyril Chemparathy 3483ff1c259SCyril Chemparathy return m88e1121_config_aneg(phydev); 3493ff1c259SCyril Chemparathy } 3503ff1c259SCyril Chemparathy 351895ee682SKim Phillips static int m88e1111_config_init(struct phy_device *phydev) 352895ee682SKim Phillips { 353895ee682SKim Phillips int err; 354be937f1fSAlexandr Smirnov int temp; 355be937f1fSAlexandr Smirnov 356be937f1fSAlexandr Smirnov /* Enable Fiber/Copper auto selection */ 357be937f1fSAlexandr Smirnov temp = phy_read(phydev, MII_M1111_PHY_EXT_SR); 3589cf8fa43SWang Jian temp &= ~MII_M1111_HWCFG_FIBER_COPPER_AUTO; 359be937f1fSAlexandr Smirnov phy_write(phydev, MII_M1111_PHY_EXT_SR, temp); 360be937f1fSAlexandr Smirnov 361be937f1fSAlexandr Smirnov temp = phy_read(phydev, MII_BMCR); 362be937f1fSAlexandr Smirnov temp |= BMCR_RESET; 363be937f1fSAlexandr Smirnov phy_write(phydev, MII_BMCR, temp); 364895ee682SKim Phillips 365895ee682SKim Phillips if ((phydev->interface == PHY_INTERFACE_MODE_RGMII) || 3669daf5a76SKim Phillips (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID) || 3679daf5a76SKim Phillips (phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID) || 3689daf5a76SKim Phillips (phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID)) { 369895ee682SKim Phillips 370895ee682SKim Phillips temp = phy_read(phydev, MII_M1111_PHY_EXT_CR); 371895ee682SKim Phillips if (temp < 0) 372895ee682SKim Phillips return temp; 373895ee682SKim Phillips 3749daf5a76SKim Phillips if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID) { 375895ee682SKim Phillips temp |= (MII_M1111_RX_DELAY | MII_M1111_TX_DELAY); 3769daf5a76SKim Phillips } else if (phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID) { 3779daf5a76SKim Phillips temp &= ~MII_M1111_TX_DELAY; 3789daf5a76SKim Phillips temp |= MII_M1111_RX_DELAY; 3799daf5a76SKim Phillips } else if (phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID) { 3809daf5a76SKim Phillips temp &= ~MII_M1111_RX_DELAY; 3819daf5a76SKim Phillips temp |= MII_M1111_TX_DELAY; 3829daf5a76SKim Phillips } 383895ee682SKim Phillips 384895ee682SKim Phillips err = phy_write(phydev, MII_M1111_PHY_EXT_CR, temp); 385895ee682SKim Phillips if (err < 0) 386895ee682SKim Phillips return err; 387895ee682SKim Phillips 388895ee682SKim Phillips temp = phy_read(phydev, MII_M1111_PHY_EXT_SR); 389895ee682SKim Phillips if (temp < 0) 390895ee682SKim Phillips return temp; 391895ee682SKim Phillips 392895ee682SKim Phillips temp &= ~(MII_M1111_HWCFG_MODE_MASK); 393be937f1fSAlexandr Smirnov 3947239016dSWang Jian if (temp & MII_M1111_HWCFG_FIBER_COPPER_RES) 395be937f1fSAlexandr Smirnov temp |= MII_M1111_HWCFG_MODE_FIBER_RGMII; 396be937f1fSAlexandr Smirnov else 397be937f1fSAlexandr Smirnov temp |= MII_M1111_HWCFG_MODE_COPPER_RGMII; 398895ee682SKim Phillips 399895ee682SKim Phillips err = phy_write(phydev, MII_M1111_PHY_EXT_SR, temp); 400895ee682SKim Phillips if (err < 0) 401895ee682SKim Phillips return err; 402895ee682SKim Phillips } 403895ee682SKim Phillips 4044117b5beSKapil Juneja if (phydev->interface == PHY_INTERFACE_MODE_SGMII) { 4054117b5beSKapil Juneja temp = phy_read(phydev, MII_M1111_PHY_EXT_SR); 4064117b5beSKapil Juneja if (temp < 0) 4074117b5beSKapil Juneja return temp; 4084117b5beSKapil Juneja 4094117b5beSKapil Juneja temp &= ~(MII_M1111_HWCFG_MODE_MASK); 4104117b5beSKapil Juneja temp |= MII_M1111_HWCFG_MODE_SGMII_NO_CLK; 41132d0c1e1SHaiying Wang temp |= MII_M1111_HWCFG_FIBER_COPPER_AUTO; 4124117b5beSKapil Juneja 4134117b5beSKapil Juneja err = phy_write(phydev, MII_M1111_PHY_EXT_SR, temp); 4144117b5beSKapil Juneja if (err < 0) 4154117b5beSKapil Juneja return err; 4164117b5beSKapil Juneja } 4174117b5beSKapil Juneja 4185f8cbc13SLiu Yu-B13201 if (phydev->interface == PHY_INTERFACE_MODE_RTBI) { 4195f8cbc13SLiu Yu-B13201 temp = phy_read(phydev, MII_M1111_PHY_EXT_CR); 4205f8cbc13SLiu Yu-B13201 if (temp < 0) 4215f8cbc13SLiu Yu-B13201 return temp; 4225f8cbc13SLiu Yu-B13201 temp |= (MII_M1111_RX_DELAY | MII_M1111_TX_DELAY); 4235f8cbc13SLiu Yu-B13201 err = phy_write(phydev, MII_M1111_PHY_EXT_CR, temp); 4245f8cbc13SLiu Yu-B13201 if (err < 0) 4255f8cbc13SLiu Yu-B13201 return err; 4265f8cbc13SLiu Yu-B13201 4275f8cbc13SLiu Yu-B13201 temp = phy_read(phydev, MII_M1111_PHY_EXT_SR); 4285f8cbc13SLiu Yu-B13201 if (temp < 0) 4295f8cbc13SLiu Yu-B13201 return temp; 4305f8cbc13SLiu Yu-B13201 temp &= ~(MII_M1111_HWCFG_MODE_MASK | MII_M1111_HWCFG_FIBER_COPPER_RES); 4315f8cbc13SLiu Yu-B13201 temp |= 0x7 | MII_M1111_HWCFG_FIBER_COPPER_AUTO; 4325f8cbc13SLiu Yu-B13201 err = phy_write(phydev, MII_M1111_PHY_EXT_SR, temp); 4335f8cbc13SLiu Yu-B13201 if (err < 0) 4345f8cbc13SLiu Yu-B13201 return err; 4355f8cbc13SLiu Yu-B13201 4365f8cbc13SLiu Yu-B13201 /* soft reset */ 4375f8cbc13SLiu Yu-B13201 err = phy_write(phydev, MII_BMCR, BMCR_RESET); 4385f8cbc13SLiu Yu-B13201 if (err < 0) 4395f8cbc13SLiu Yu-B13201 return err; 4405f8cbc13SLiu Yu-B13201 do 4415f8cbc13SLiu Yu-B13201 temp = phy_read(phydev, MII_BMCR); 4425f8cbc13SLiu Yu-B13201 while (temp & BMCR_RESET); 4435f8cbc13SLiu Yu-B13201 4445f8cbc13SLiu Yu-B13201 temp = phy_read(phydev, MII_M1111_PHY_EXT_SR); 4455f8cbc13SLiu Yu-B13201 if (temp < 0) 4465f8cbc13SLiu Yu-B13201 return temp; 4475f8cbc13SLiu Yu-B13201 temp &= ~(MII_M1111_HWCFG_MODE_MASK | MII_M1111_HWCFG_FIBER_COPPER_RES); 4485f8cbc13SLiu Yu-B13201 temp |= MII_M1111_HWCFG_MODE_COPPER_RTBI | MII_M1111_HWCFG_FIBER_COPPER_AUTO; 4495f8cbc13SLiu Yu-B13201 err = phy_write(phydev, MII_M1111_PHY_EXT_SR, temp); 4505f8cbc13SLiu Yu-B13201 if (err < 0) 4515f8cbc13SLiu Yu-B13201 return err; 4525f8cbc13SLiu Yu-B13201 } 4535f8cbc13SLiu Yu-B13201 454cf41a51dSDavid Daney err = marvell_of_reg_init(phydev); 455cf41a51dSDavid Daney if (err < 0) 456cf41a51dSDavid Daney return err; 4575f8cbc13SLiu Yu-B13201 458cc90cb3bSSrinivas Kandagatla return phy_write(phydev, MII_BMCR, BMCR_RESET); 459895ee682SKim Phillips } 460895ee682SKim Phillips 461605f196eSRon Madrid static int m88e1118_config_aneg(struct phy_device *phydev) 462605f196eSRon Madrid { 463605f196eSRon Madrid int err; 464605f196eSRon Madrid 465605f196eSRon Madrid err = phy_write(phydev, MII_BMCR, BMCR_RESET); 466605f196eSRon Madrid if (err < 0) 467605f196eSRon Madrid return err; 468605f196eSRon Madrid 469605f196eSRon Madrid err = phy_write(phydev, MII_M1011_PHY_SCR, 470605f196eSRon Madrid MII_M1011_PHY_SCR_AUTO_CROSS); 471605f196eSRon Madrid if (err < 0) 472605f196eSRon Madrid return err; 473605f196eSRon Madrid 474605f196eSRon Madrid err = genphy_config_aneg(phydev); 475605f196eSRon Madrid return 0; 476605f196eSRon Madrid } 477605f196eSRon Madrid 478605f196eSRon Madrid static int m88e1118_config_init(struct phy_device *phydev) 479605f196eSRon Madrid { 480605f196eSRon Madrid int err; 481605f196eSRon Madrid 482605f196eSRon Madrid /* Change address */ 48327d916d6SDavid Daney err = phy_write(phydev, MII_MARVELL_PHY_PAGE, 0x0002); 484605f196eSRon Madrid if (err < 0) 485605f196eSRon Madrid return err; 486605f196eSRon Madrid 487605f196eSRon Madrid /* Enable 1000 Mbit */ 488605f196eSRon Madrid err = phy_write(phydev, 0x15, 0x1070); 489605f196eSRon Madrid if (err < 0) 490605f196eSRon Madrid return err; 491605f196eSRon Madrid 492605f196eSRon Madrid /* Change address */ 49327d916d6SDavid Daney err = phy_write(phydev, MII_MARVELL_PHY_PAGE, 0x0003); 494605f196eSRon Madrid if (err < 0) 495605f196eSRon Madrid return err; 496605f196eSRon Madrid 497605f196eSRon Madrid /* Adjust LED Control */ 4982f495c39SBenjamin Herrenschmidt if (phydev->dev_flags & MARVELL_PHY_M1118_DNS323_LEDS) 4992f495c39SBenjamin Herrenschmidt err = phy_write(phydev, 0x10, 0x1100); 5002f495c39SBenjamin Herrenschmidt else 501605f196eSRon Madrid err = phy_write(phydev, 0x10, 0x021e); 502605f196eSRon Madrid if (err < 0) 503605f196eSRon Madrid return err; 504605f196eSRon Madrid 505cf41a51dSDavid Daney err = marvell_of_reg_init(phydev); 506cf41a51dSDavid Daney if (err < 0) 507cf41a51dSDavid Daney return err; 508cf41a51dSDavid Daney 509605f196eSRon Madrid /* Reset address */ 51027d916d6SDavid Daney err = phy_write(phydev, MII_MARVELL_PHY_PAGE, 0x0); 511605f196eSRon Madrid if (err < 0) 512605f196eSRon Madrid return err; 513605f196eSRon Madrid 514cc90cb3bSSrinivas Kandagatla return phy_write(phydev, MII_BMCR, BMCR_RESET); 515605f196eSRon Madrid } 516605f196eSRon Madrid 51790600732SDavid Daney static int m88e1149_config_init(struct phy_device *phydev) 51890600732SDavid Daney { 51990600732SDavid Daney int err; 52090600732SDavid Daney 52190600732SDavid Daney /* Change address */ 52290600732SDavid Daney err = phy_write(phydev, MII_MARVELL_PHY_PAGE, 0x0002); 52390600732SDavid Daney if (err < 0) 52490600732SDavid Daney return err; 52590600732SDavid Daney 52690600732SDavid Daney /* Enable 1000 Mbit */ 52790600732SDavid Daney err = phy_write(phydev, 0x15, 0x1048); 52890600732SDavid Daney if (err < 0) 52990600732SDavid Daney return err; 53090600732SDavid Daney 531cf41a51dSDavid Daney err = marvell_of_reg_init(phydev); 532cf41a51dSDavid Daney if (err < 0) 533cf41a51dSDavid Daney return err; 534cf41a51dSDavid Daney 53590600732SDavid Daney /* Reset address */ 53690600732SDavid Daney err = phy_write(phydev, MII_MARVELL_PHY_PAGE, 0x0); 53790600732SDavid Daney if (err < 0) 53890600732SDavid Daney return err; 53990600732SDavid Daney 540cc90cb3bSSrinivas Kandagatla return phy_write(phydev, MII_BMCR, BMCR_RESET); 54190600732SDavid Daney } 54290600732SDavid Daney 54376884679SAndy Fleming static int m88e1145_config_init(struct phy_device *phydev) 54476884679SAndy Fleming { 54576884679SAndy Fleming int err; 54676884679SAndy Fleming 54776884679SAndy Fleming /* Take care of errata E0 & E1 */ 54876884679SAndy Fleming err = phy_write(phydev, 0x1d, 0x001b); 54976884679SAndy Fleming if (err < 0) 55076884679SAndy Fleming return err; 55176884679SAndy Fleming 55276884679SAndy Fleming err = phy_write(phydev, 0x1e, 0x418f); 55376884679SAndy Fleming if (err < 0) 55476884679SAndy Fleming return err; 55576884679SAndy Fleming 55676884679SAndy Fleming err = phy_write(phydev, 0x1d, 0x0016); 55776884679SAndy Fleming if (err < 0) 55876884679SAndy Fleming return err; 55976884679SAndy Fleming 56076884679SAndy Fleming err = phy_write(phydev, 0x1e, 0xa2da); 56176884679SAndy Fleming if (err < 0) 56276884679SAndy Fleming return err; 56376884679SAndy Fleming 564895ee682SKim Phillips if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID) { 56576884679SAndy Fleming int temp = phy_read(phydev, MII_M1145_PHY_EXT_CR); 56676884679SAndy Fleming if (temp < 0) 56776884679SAndy Fleming return temp; 56876884679SAndy Fleming 56976884679SAndy Fleming temp |= (MII_M1145_RGMII_RX_DELAY | MII_M1145_RGMII_TX_DELAY); 57076884679SAndy Fleming 57176884679SAndy Fleming err = phy_write(phydev, MII_M1145_PHY_EXT_CR, temp); 57276884679SAndy Fleming if (err < 0) 57376884679SAndy Fleming return err; 57476884679SAndy Fleming 5752f495c39SBenjamin Herrenschmidt if (phydev->dev_flags & MARVELL_PHY_M1145_FLAGS_RESISTANCE) { 57676884679SAndy Fleming err = phy_write(phydev, 0x1d, 0x0012); 57776884679SAndy Fleming if (err < 0) 57876884679SAndy Fleming return err; 57976884679SAndy Fleming 58076884679SAndy Fleming temp = phy_read(phydev, 0x1e); 58176884679SAndy Fleming if (temp < 0) 58276884679SAndy Fleming return temp; 58376884679SAndy Fleming 58476884679SAndy Fleming temp &= 0xf03f; 58576884679SAndy Fleming temp |= 2 << 9; /* 36 ohm */ 58676884679SAndy Fleming temp |= 2 << 6; /* 39 ohm */ 58776884679SAndy Fleming 58876884679SAndy Fleming err = phy_write(phydev, 0x1e, temp); 58976884679SAndy Fleming if (err < 0) 59076884679SAndy Fleming return err; 59176884679SAndy Fleming 59276884679SAndy Fleming err = phy_write(phydev, 0x1d, 0x3); 59376884679SAndy Fleming if (err < 0) 59476884679SAndy Fleming return err; 59576884679SAndy Fleming 59676884679SAndy Fleming err = phy_write(phydev, 0x1e, 0x8000); 59776884679SAndy Fleming if (err < 0) 59876884679SAndy Fleming return err; 59976884679SAndy Fleming } 60076884679SAndy Fleming } 60176884679SAndy Fleming 602cf41a51dSDavid Daney err = marvell_of_reg_init(phydev); 603cf41a51dSDavid Daney if (err < 0) 604cf41a51dSDavid Daney return err; 605cf41a51dSDavid Daney 60676884679SAndy Fleming return 0; 60776884679SAndy Fleming } 60800db8189SAndy Fleming 609be937f1fSAlexandr Smirnov /* marvell_read_status 610be937f1fSAlexandr Smirnov * 611be937f1fSAlexandr Smirnov * Generic status code does not detect Fiber correctly! 612be937f1fSAlexandr Smirnov * Description: 613be937f1fSAlexandr Smirnov * Check the link, then figure out the current state 614be937f1fSAlexandr Smirnov * by comparing what we advertise with what the link partner 615be937f1fSAlexandr Smirnov * advertises. Start by checking the gigabit possibilities, 616be937f1fSAlexandr Smirnov * then move on to 10/100. 617be937f1fSAlexandr Smirnov */ 618be937f1fSAlexandr Smirnov static int marvell_read_status(struct phy_device *phydev) 619be937f1fSAlexandr Smirnov { 620be937f1fSAlexandr Smirnov int adv; 621be937f1fSAlexandr Smirnov int err; 622be937f1fSAlexandr Smirnov int lpa; 623be937f1fSAlexandr Smirnov int status = 0; 624be937f1fSAlexandr Smirnov 625be937f1fSAlexandr Smirnov /* Update the link, but return if there 626be937f1fSAlexandr Smirnov * was an error */ 627be937f1fSAlexandr Smirnov err = genphy_update_link(phydev); 628be937f1fSAlexandr Smirnov if (err) 629be937f1fSAlexandr Smirnov return err; 630be937f1fSAlexandr Smirnov 631be937f1fSAlexandr Smirnov if (AUTONEG_ENABLE == phydev->autoneg) { 632be937f1fSAlexandr Smirnov status = phy_read(phydev, MII_M1011_PHY_STATUS); 633be937f1fSAlexandr Smirnov if (status < 0) 634be937f1fSAlexandr Smirnov return status; 635be937f1fSAlexandr Smirnov 636be937f1fSAlexandr Smirnov lpa = phy_read(phydev, MII_LPA); 637be937f1fSAlexandr Smirnov if (lpa < 0) 638be937f1fSAlexandr Smirnov return lpa; 639be937f1fSAlexandr Smirnov 640be937f1fSAlexandr Smirnov adv = phy_read(phydev, MII_ADVERTISE); 641be937f1fSAlexandr Smirnov if (adv < 0) 642be937f1fSAlexandr Smirnov return adv; 643be937f1fSAlexandr Smirnov 644be937f1fSAlexandr Smirnov lpa &= adv; 645be937f1fSAlexandr Smirnov 646be937f1fSAlexandr Smirnov if (status & MII_M1011_PHY_STATUS_FULLDUPLEX) 647be937f1fSAlexandr Smirnov phydev->duplex = DUPLEX_FULL; 648be937f1fSAlexandr Smirnov else 649be937f1fSAlexandr Smirnov phydev->duplex = DUPLEX_HALF; 650be937f1fSAlexandr Smirnov 651be937f1fSAlexandr Smirnov status = status & MII_M1011_PHY_STATUS_SPD_MASK; 652be937f1fSAlexandr Smirnov phydev->pause = phydev->asym_pause = 0; 653be937f1fSAlexandr Smirnov 654be937f1fSAlexandr Smirnov switch (status) { 655be937f1fSAlexandr Smirnov case MII_M1011_PHY_STATUS_1000: 656be937f1fSAlexandr Smirnov phydev->speed = SPEED_1000; 657be937f1fSAlexandr Smirnov break; 658be937f1fSAlexandr Smirnov 659be937f1fSAlexandr Smirnov case MII_M1011_PHY_STATUS_100: 660be937f1fSAlexandr Smirnov phydev->speed = SPEED_100; 661be937f1fSAlexandr Smirnov break; 662be937f1fSAlexandr Smirnov 663be937f1fSAlexandr Smirnov default: 664be937f1fSAlexandr Smirnov phydev->speed = SPEED_10; 665be937f1fSAlexandr Smirnov break; 666be937f1fSAlexandr Smirnov } 667be937f1fSAlexandr Smirnov 668be937f1fSAlexandr Smirnov if (phydev->duplex == DUPLEX_FULL) { 669be937f1fSAlexandr Smirnov phydev->pause = lpa & LPA_PAUSE_CAP ? 1 : 0; 670be937f1fSAlexandr Smirnov phydev->asym_pause = lpa & LPA_PAUSE_ASYM ? 1 : 0; 671be937f1fSAlexandr Smirnov } 672be937f1fSAlexandr Smirnov } else { 673be937f1fSAlexandr Smirnov int bmcr = phy_read(phydev, MII_BMCR); 674be937f1fSAlexandr Smirnov 675be937f1fSAlexandr Smirnov if (bmcr < 0) 676be937f1fSAlexandr Smirnov return bmcr; 677be937f1fSAlexandr Smirnov 678be937f1fSAlexandr Smirnov if (bmcr & BMCR_FULLDPLX) 679be937f1fSAlexandr Smirnov phydev->duplex = DUPLEX_FULL; 680be937f1fSAlexandr Smirnov else 681be937f1fSAlexandr Smirnov phydev->duplex = DUPLEX_HALF; 682be937f1fSAlexandr Smirnov 683be937f1fSAlexandr Smirnov if (bmcr & BMCR_SPEED1000) 684be937f1fSAlexandr Smirnov phydev->speed = SPEED_1000; 685be937f1fSAlexandr Smirnov else if (bmcr & BMCR_SPEED100) 686be937f1fSAlexandr Smirnov phydev->speed = SPEED_100; 687be937f1fSAlexandr Smirnov else 688be937f1fSAlexandr Smirnov phydev->speed = SPEED_10; 689be937f1fSAlexandr Smirnov 690be937f1fSAlexandr Smirnov phydev->pause = phydev->asym_pause = 0; 691be937f1fSAlexandr Smirnov } 692be937f1fSAlexandr Smirnov 693be937f1fSAlexandr Smirnov return 0; 694be937f1fSAlexandr Smirnov } 695be937f1fSAlexandr Smirnov 696dcd07be3SAnatolij Gustschin static int m88e1121_did_interrupt(struct phy_device *phydev) 697dcd07be3SAnatolij Gustschin { 698dcd07be3SAnatolij Gustschin int imask; 699dcd07be3SAnatolij Gustschin 700dcd07be3SAnatolij Gustschin imask = phy_read(phydev, MII_M1011_IEVENT); 701dcd07be3SAnatolij Gustschin 702dcd07be3SAnatolij Gustschin if (imask & MII_M1011_IMASK_INIT) 703dcd07be3SAnatolij Gustschin return 1; 704dcd07be3SAnatolij Gustschin 705dcd07be3SAnatolij Gustschin return 0; 706dcd07be3SAnatolij Gustschin } 707dcd07be3SAnatolij Gustschin 708e5479239SOlof Johansson static struct phy_driver marvell_drivers[] = { 709e5479239SOlof Johansson { 7102f495c39SBenjamin Herrenschmidt .phy_id = MARVELL_PHY_ID_88E1101, 7112f495c39SBenjamin Herrenschmidt .phy_id_mask = MARVELL_PHY_ID_MASK, 71200db8189SAndy Fleming .name = "Marvell 88E1101", 71300db8189SAndy Fleming .features = PHY_GBIT_FEATURES, 71400db8189SAndy Fleming .flags = PHY_HAS_INTERRUPT, 71500db8189SAndy Fleming .config_aneg = &marvell_config_aneg, 71600db8189SAndy Fleming .read_status = &genphy_read_status, 71700db8189SAndy Fleming .ack_interrupt = &marvell_ack_interrupt, 71800db8189SAndy Fleming .config_intr = &marvell_config_intr, 719ac8c635aSOlof Johansson .driver = { .owner = THIS_MODULE }, 720e5479239SOlof Johansson }, 721e5479239SOlof Johansson { 7222f495c39SBenjamin Herrenschmidt .phy_id = MARVELL_PHY_ID_88E1112, 7232f495c39SBenjamin Herrenschmidt .phy_id_mask = MARVELL_PHY_ID_MASK, 72485cfb534SOlof Johansson .name = "Marvell 88E1112", 72585cfb534SOlof Johansson .features = PHY_GBIT_FEATURES, 72685cfb534SOlof Johansson .flags = PHY_HAS_INTERRUPT, 72785cfb534SOlof Johansson .config_init = &m88e1111_config_init, 72885cfb534SOlof Johansson .config_aneg = &marvell_config_aneg, 72985cfb534SOlof Johansson .read_status = &genphy_read_status, 73085cfb534SOlof Johansson .ack_interrupt = &marvell_ack_interrupt, 73185cfb534SOlof Johansson .config_intr = &marvell_config_intr, 732ac8c635aSOlof Johansson .driver = { .owner = THIS_MODULE }, 73385cfb534SOlof Johansson }, 73485cfb534SOlof Johansson { 7352f495c39SBenjamin Herrenschmidt .phy_id = MARVELL_PHY_ID_88E1111, 7362f495c39SBenjamin Herrenschmidt .phy_id_mask = MARVELL_PHY_ID_MASK, 73776884679SAndy Fleming .name = "Marvell 88E1111", 73876884679SAndy Fleming .features = PHY_GBIT_FEATURES, 73976884679SAndy Fleming .flags = PHY_HAS_INTERRUPT, 740e5479239SOlof Johansson .config_init = &m88e1111_config_init, 74176884679SAndy Fleming .config_aneg = &marvell_config_aneg, 742be937f1fSAlexandr Smirnov .read_status = &marvell_read_status, 74376884679SAndy Fleming .ack_interrupt = &marvell_ack_interrupt, 74476884679SAndy Fleming .config_intr = &marvell_config_intr, 745ac8c635aSOlof Johansson .driver = { .owner = THIS_MODULE }, 746e5479239SOlof Johansson }, 747e5479239SOlof Johansson { 7482f495c39SBenjamin Herrenschmidt .phy_id = MARVELL_PHY_ID_88E1118, 7492f495c39SBenjamin Herrenschmidt .phy_id_mask = MARVELL_PHY_ID_MASK, 750605f196eSRon Madrid .name = "Marvell 88E1118", 751605f196eSRon Madrid .features = PHY_GBIT_FEATURES, 752605f196eSRon Madrid .flags = PHY_HAS_INTERRUPT, 753605f196eSRon Madrid .config_init = &m88e1118_config_init, 754605f196eSRon Madrid .config_aneg = &m88e1118_config_aneg, 755605f196eSRon Madrid .read_status = &genphy_read_status, 756605f196eSRon Madrid .ack_interrupt = &marvell_ack_interrupt, 757605f196eSRon Madrid .config_intr = &marvell_config_intr, 758605f196eSRon Madrid .driver = {.owner = THIS_MODULE,}, 759605f196eSRon Madrid }, 760605f196eSRon Madrid { 7612f495c39SBenjamin Herrenschmidt .phy_id = MARVELL_PHY_ID_88E1121R, 7622f495c39SBenjamin Herrenschmidt .phy_id_mask = MARVELL_PHY_ID_MASK, 763140bc929SSergei Poselenov .name = "Marvell 88E1121R", 764140bc929SSergei Poselenov .features = PHY_GBIT_FEATURES, 765140bc929SSergei Poselenov .flags = PHY_HAS_INTERRUPT, 766140bc929SSergei Poselenov .config_aneg = &m88e1121_config_aneg, 767140bc929SSergei Poselenov .read_status = &marvell_read_status, 768140bc929SSergei Poselenov .ack_interrupt = &marvell_ack_interrupt, 769140bc929SSergei Poselenov .config_intr = &marvell_config_intr, 770dcd07be3SAnatolij Gustschin .did_interrupt = &m88e1121_did_interrupt, 771140bc929SSergei Poselenov .driver = { .owner = THIS_MODULE }, 772140bc929SSergei Poselenov }, 773140bc929SSergei Poselenov { 774337ac9d5SCyril Chemparathy .phy_id = MARVELL_PHY_ID_88E1318S, 7756ba74014SLinus Torvalds .phy_id_mask = MARVELL_PHY_ID_MASK, 776337ac9d5SCyril Chemparathy .name = "Marvell 88E1318S", 7773ff1c259SCyril Chemparathy .features = PHY_GBIT_FEATURES, 7783ff1c259SCyril Chemparathy .flags = PHY_HAS_INTERRUPT, 779337ac9d5SCyril Chemparathy .config_aneg = &m88e1318_config_aneg, 7803ff1c259SCyril Chemparathy .read_status = &marvell_read_status, 7813ff1c259SCyril Chemparathy .ack_interrupt = &marvell_ack_interrupt, 7823ff1c259SCyril Chemparathy .config_intr = &marvell_config_intr, 7833ff1c259SCyril Chemparathy .did_interrupt = &m88e1121_did_interrupt, 7843ff1c259SCyril Chemparathy .driver = { .owner = THIS_MODULE }, 7853ff1c259SCyril Chemparathy }, 7863ff1c259SCyril Chemparathy { 7872f495c39SBenjamin Herrenschmidt .phy_id = MARVELL_PHY_ID_88E1145, 7882f495c39SBenjamin Herrenschmidt .phy_id_mask = MARVELL_PHY_ID_MASK, 78976884679SAndy Fleming .name = "Marvell 88E1145", 79076884679SAndy Fleming .features = PHY_GBIT_FEATURES, 79176884679SAndy Fleming .flags = PHY_HAS_INTERRUPT, 79276884679SAndy Fleming .config_init = &m88e1145_config_init, 79376884679SAndy Fleming .config_aneg = &marvell_config_aneg, 79476884679SAndy Fleming .read_status = &genphy_read_status, 79576884679SAndy Fleming .ack_interrupt = &marvell_ack_interrupt, 79676884679SAndy Fleming .config_intr = &marvell_config_intr, 797ac8c635aSOlof Johansson .driver = { .owner = THIS_MODULE }, 798ac8c635aSOlof Johansson }, 799ac8c635aSOlof Johansson { 80090600732SDavid Daney .phy_id = MARVELL_PHY_ID_88E1149R, 80190600732SDavid Daney .phy_id_mask = MARVELL_PHY_ID_MASK, 80290600732SDavid Daney .name = "Marvell 88E1149R", 80390600732SDavid Daney .features = PHY_GBIT_FEATURES, 80490600732SDavid Daney .flags = PHY_HAS_INTERRUPT, 80590600732SDavid Daney .config_init = &m88e1149_config_init, 80690600732SDavid Daney .config_aneg = &m88e1118_config_aneg, 80790600732SDavid Daney .read_status = &genphy_read_status, 80890600732SDavid Daney .ack_interrupt = &marvell_ack_interrupt, 80990600732SDavid Daney .config_intr = &marvell_config_intr, 81090600732SDavid Daney .driver = { .owner = THIS_MODULE }, 81190600732SDavid Daney }, 81290600732SDavid Daney { 8132f495c39SBenjamin Herrenschmidt .phy_id = MARVELL_PHY_ID_88E1240, 8142f495c39SBenjamin Herrenschmidt .phy_id_mask = MARVELL_PHY_ID_MASK, 815ac8c635aSOlof Johansson .name = "Marvell 88E1240", 816ac8c635aSOlof Johansson .features = PHY_GBIT_FEATURES, 817ac8c635aSOlof Johansson .flags = PHY_HAS_INTERRUPT, 818ac8c635aSOlof Johansson .config_init = &m88e1111_config_init, 819ac8c635aSOlof Johansson .config_aneg = &marvell_config_aneg, 820ac8c635aSOlof Johansson .read_status = &genphy_read_status, 821ac8c635aSOlof Johansson .ack_interrupt = &marvell_ack_interrupt, 822ac8c635aSOlof Johansson .config_intr = &marvell_config_intr, 823ac8c635aSOlof Johansson .driver = { .owner = THIS_MODULE }, 824ac8c635aSOlof Johansson }, 82576884679SAndy Fleming }; 82676884679SAndy Fleming 82700db8189SAndy Fleming static int __init marvell_init(void) 82800db8189SAndy Fleming { 82976884679SAndy Fleming int ret; 830e5479239SOlof Johansson int i; 83176884679SAndy Fleming 832e5479239SOlof Johansson for (i = 0; i < ARRAY_SIZE(marvell_drivers); i++) { 833e5479239SOlof Johansson ret = phy_driver_register(&marvell_drivers[i]); 834e5479239SOlof Johansson 835e5479239SOlof Johansson if (ret) { 836e5479239SOlof Johansson while (i-- > 0) 837e5479239SOlof Johansson phy_driver_unregister(&marvell_drivers[i]); 83876884679SAndy Fleming return ret; 839e5479239SOlof Johansson } 840e5479239SOlof Johansson } 84176884679SAndy Fleming 84276884679SAndy Fleming return 0; 84300db8189SAndy Fleming } 84400db8189SAndy Fleming 84500db8189SAndy Fleming static void __exit marvell_exit(void) 84600db8189SAndy Fleming { 847e5479239SOlof Johansson int i; 848e5479239SOlof Johansson 849e5479239SOlof Johansson for (i = 0; i < ARRAY_SIZE(marvell_drivers); i++) 850e5479239SOlof Johansson phy_driver_unregister(&marvell_drivers[i]); 85100db8189SAndy Fleming } 85200db8189SAndy Fleming 85300db8189SAndy Fleming module_init(marvell_init); 85400db8189SAndy Fleming module_exit(marvell_exit); 8554e4f10f6SDavid Woodhouse 856cf93c945SUwe Kleine-König static struct mdio_device_id __maybe_unused marvell_tbl[] = { 8574e4f10f6SDavid Woodhouse { 0x01410c60, 0xfffffff0 }, 8584e4f10f6SDavid Woodhouse { 0x01410c90, 0xfffffff0 }, 8594e4f10f6SDavid Woodhouse { 0x01410cc0, 0xfffffff0 }, 8604e4f10f6SDavid Woodhouse { 0x01410e10, 0xfffffff0 }, 8614e4f10f6SDavid Woodhouse { 0x01410cb0, 0xfffffff0 }, 8624e4f10f6SDavid Woodhouse { 0x01410cd0, 0xfffffff0 }, 86390600732SDavid Daney { 0x01410e50, 0xfffffff0 }, 8644e4f10f6SDavid Woodhouse { 0x01410e30, 0xfffffff0 }, 8653ff1c259SCyril Chemparathy { 0x01410e90, 0xfffffff0 }, 8664e4f10f6SDavid Woodhouse { } 8674e4f10f6SDavid Woodhouse }; 8684e4f10f6SDavid Woodhouse 8694e4f10f6SDavid Woodhouse MODULE_DEVICE_TABLE(mdio, marvell_tbl); 870