19082eeacSAndy Fleming /* 29082eeacSAndy Fleming * Marvell PHY drivers 39082eeacSAndy Fleming * 41a459660SWolfgang Denk * SPDX-License-Identifier: GPL-2.0+ 59082eeacSAndy Fleming * 69082eeacSAndy Fleming * Copyright 2010-2011 Freescale Semiconductor, Inc. 79082eeacSAndy Fleming * author Andy Fleming 89082eeacSAndy Fleming */ 99082eeacSAndy Fleming #include <config.h> 109082eeacSAndy Fleming #include <common.h> 119082eeacSAndy Fleming #include <phy.h> 129082eeacSAndy Fleming 139082eeacSAndy Fleming #define PHY_AUTONEGOTIATE_TIMEOUT 5000 149082eeacSAndy Fleming 159082eeacSAndy Fleming /* 88E1011 PHY Status Register */ 169082eeacSAndy Fleming #define MIIM_88E1xxx_PHY_STATUS 0x11 179082eeacSAndy Fleming #define MIIM_88E1xxx_PHYSTAT_SPEED 0xc000 189082eeacSAndy Fleming #define MIIM_88E1xxx_PHYSTAT_GBIT 0x8000 199082eeacSAndy Fleming #define MIIM_88E1xxx_PHYSTAT_100 0x4000 209082eeacSAndy Fleming #define MIIM_88E1xxx_PHYSTAT_DUPLEX 0x2000 219082eeacSAndy Fleming #define MIIM_88E1xxx_PHYSTAT_SPDDONE 0x0800 229082eeacSAndy Fleming #define MIIM_88E1xxx_PHYSTAT_LINK 0x0400 239082eeacSAndy Fleming 249082eeacSAndy Fleming #define MIIM_88E1xxx_PHY_SCR 0x10 259082eeacSAndy Fleming #define MIIM_88E1xxx_PHY_MDI_X_AUTO 0x0060 269082eeacSAndy Fleming 279082eeacSAndy Fleming /* 88E1111 PHY LED Control Register */ 289082eeacSAndy Fleming #define MIIM_88E1111_PHY_LED_CONTROL 24 299082eeacSAndy Fleming #define MIIM_88E1111_PHY_LED_DIRECT 0x4100 309082eeacSAndy Fleming #define MIIM_88E1111_PHY_LED_COMBINE 0x411C 319082eeacSAndy Fleming 32fa12a08eSZang Roy-R61911 /* 88E1111 Extended PHY Specific Control Register */ 33fa12a08eSZang Roy-R61911 #define MIIM_88E1111_PHY_EXT_CR 0x14 34fa12a08eSZang Roy-R61911 #define MIIM_88E1111_RX_DELAY 0x80 35fa12a08eSZang Roy-R61911 #define MIIM_88E1111_TX_DELAY 0x2 36fa12a08eSZang Roy-R61911 37fa12a08eSZang Roy-R61911 /* 88E1111 Extended PHY Specific Status Register */ 38fa12a08eSZang Roy-R61911 #define MIIM_88E1111_PHY_EXT_SR 0x1b 39fa12a08eSZang Roy-R61911 #define MIIM_88E1111_HWCFG_MODE_MASK 0xf 40fa12a08eSZang Roy-R61911 #define MIIM_88E1111_HWCFG_MODE_COPPER_RGMII 0xb 41fa12a08eSZang Roy-R61911 #define MIIM_88E1111_HWCFG_MODE_FIBER_RGMII 0x3 42fa12a08eSZang Roy-R61911 #define MIIM_88E1111_HWCFG_MODE_SGMII_NO_CLK 0x4 43fa12a08eSZang Roy-R61911 #define MIIM_88E1111_HWCFG_MODE_COPPER_RTBI 0x9 44fa12a08eSZang Roy-R61911 #define MIIM_88E1111_HWCFG_FIBER_COPPER_AUTO 0x8000 45fa12a08eSZang Roy-R61911 #define MIIM_88E1111_HWCFG_FIBER_COPPER_RES 0x2000 46fa12a08eSZang Roy-R61911 47fa12a08eSZang Roy-R61911 #define MIIM_88E1111_COPPER 0 48fa12a08eSZang Roy-R61911 #define MIIM_88E1111_FIBER 1 49fa12a08eSZang Roy-R61911 509082eeacSAndy Fleming /* 88E1118 PHY defines */ 519082eeacSAndy Fleming #define MIIM_88E1118_PHY_PAGE 22 529082eeacSAndy Fleming #define MIIM_88E1118_PHY_LED_PAGE 3 539082eeacSAndy Fleming 549082eeacSAndy Fleming /* 88E1121 PHY LED Control Register */ 559082eeacSAndy Fleming #define MIIM_88E1121_PHY_LED_CTRL 16 569082eeacSAndy Fleming #define MIIM_88E1121_PHY_LED_PAGE 3 579082eeacSAndy Fleming #define MIIM_88E1121_PHY_LED_DEF 0x0030 589082eeacSAndy Fleming 599082eeacSAndy Fleming /* 88E1121 PHY IRQ Enable/Status Register */ 609082eeacSAndy Fleming #define MIIM_88E1121_PHY_IRQ_EN 18 619082eeacSAndy Fleming #define MIIM_88E1121_PHY_IRQ_STATUS 19 629082eeacSAndy Fleming 639082eeacSAndy Fleming #define MIIM_88E1121_PHY_PAGE 22 649082eeacSAndy Fleming 659082eeacSAndy Fleming /* 88E1145 Extended PHY Specific Control Register */ 669082eeacSAndy Fleming #define MIIM_88E1145_PHY_EXT_CR 20 679082eeacSAndy Fleming #define MIIM_M88E1145_RGMII_RX_DELAY 0x0080 689082eeacSAndy Fleming #define MIIM_M88E1145_RGMII_TX_DELAY 0x0002 699082eeacSAndy Fleming 709082eeacSAndy Fleming #define MIIM_88E1145_PHY_LED_CONTROL 24 719082eeacSAndy Fleming #define MIIM_88E1145_PHY_LED_DIRECT 0x4100 729082eeacSAndy Fleming 739082eeacSAndy Fleming #define MIIM_88E1145_PHY_PAGE 29 749082eeacSAndy Fleming #define MIIM_88E1145_PHY_CAL_OV 30 759082eeacSAndy Fleming 769082eeacSAndy Fleming #define MIIM_88E1149_PHY_PAGE 29 779082eeacSAndy Fleming 78aeceec0dSSebastian Hesselbarth /* 88E1310 PHY defines */ 79aeceec0dSSebastian Hesselbarth #define MIIM_88E1310_PHY_LED_CTRL 16 80aeceec0dSSebastian Hesselbarth #define MIIM_88E1310_PHY_IRQ_EN 18 81aeceec0dSSebastian Hesselbarth #define MIIM_88E1310_PHY_RGMII_CTRL 21 82aeceec0dSSebastian Hesselbarth #define MIIM_88E1310_PHY_PAGE 22 83aeceec0dSSebastian Hesselbarth 849082eeacSAndy Fleming /* Marvell 88E1011S */ 859082eeacSAndy Fleming static int m88e1011s_config(struct phy_device *phydev) 869082eeacSAndy Fleming { 879082eeacSAndy Fleming /* Reset and configure the PHY */ 889082eeacSAndy Fleming phy_write(phydev, MDIO_DEVAD_NONE, MII_BMCR, BMCR_RESET); 899082eeacSAndy Fleming 909082eeacSAndy Fleming phy_write(phydev, MDIO_DEVAD_NONE, 0x1d, 0x1f); 919082eeacSAndy Fleming phy_write(phydev, MDIO_DEVAD_NONE, 0x1e, 0x200c); 929082eeacSAndy Fleming phy_write(phydev, MDIO_DEVAD_NONE, 0x1d, 0x5); 939082eeacSAndy Fleming phy_write(phydev, MDIO_DEVAD_NONE, 0x1e, 0); 949082eeacSAndy Fleming phy_write(phydev, MDIO_DEVAD_NONE, 0x1e, 0x100); 959082eeacSAndy Fleming 969082eeacSAndy Fleming phy_write(phydev, MDIO_DEVAD_NONE, MII_BMCR, BMCR_RESET); 979082eeacSAndy Fleming 989082eeacSAndy Fleming genphy_config_aneg(phydev); 999082eeacSAndy Fleming 1009082eeacSAndy Fleming return 0; 1019082eeacSAndy Fleming } 1029082eeacSAndy Fleming 1039082eeacSAndy Fleming /* Parse the 88E1011's status register for speed and duplex 1049082eeacSAndy Fleming * information 1059082eeacSAndy Fleming */ 1069082eeacSAndy Fleming static uint m88e1xxx_parse_status(struct phy_device *phydev) 1079082eeacSAndy Fleming { 1089082eeacSAndy Fleming unsigned int speed; 1099082eeacSAndy Fleming unsigned int mii_reg; 1109082eeacSAndy Fleming 1119082eeacSAndy Fleming mii_reg = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_88E1xxx_PHY_STATUS); 1129082eeacSAndy Fleming 1139082eeacSAndy Fleming if ((mii_reg & MIIM_88E1xxx_PHYSTAT_LINK) && 1149082eeacSAndy Fleming !(mii_reg & MIIM_88E1xxx_PHYSTAT_SPDDONE)) { 1159082eeacSAndy Fleming int i = 0; 1169082eeacSAndy Fleming 1179082eeacSAndy Fleming puts("Waiting for PHY realtime link"); 1189082eeacSAndy Fleming while (!(mii_reg & MIIM_88E1xxx_PHYSTAT_SPDDONE)) { 1199082eeacSAndy Fleming /* Timeout reached ? */ 1209082eeacSAndy Fleming if (i > PHY_AUTONEGOTIATE_TIMEOUT) { 1219082eeacSAndy Fleming puts(" TIMEOUT !\n"); 1229082eeacSAndy Fleming phydev->link = 0; 1239082eeacSAndy Fleming break; 1249082eeacSAndy Fleming } 1259082eeacSAndy Fleming 1269082eeacSAndy Fleming if ((i++ % 1000) == 0) 1279082eeacSAndy Fleming putc('.'); 1289082eeacSAndy Fleming udelay(1000); 1299082eeacSAndy Fleming mii_reg = phy_read(phydev, MDIO_DEVAD_NONE, 1309082eeacSAndy Fleming MIIM_88E1xxx_PHY_STATUS); 1319082eeacSAndy Fleming } 1329082eeacSAndy Fleming puts(" done\n"); 1339082eeacSAndy Fleming udelay(500000); /* another 500 ms (results in faster booting) */ 1349082eeacSAndy Fleming } else { 1359082eeacSAndy Fleming if (mii_reg & MIIM_88E1xxx_PHYSTAT_LINK) 1369082eeacSAndy Fleming phydev->link = 1; 1379082eeacSAndy Fleming else 1389082eeacSAndy Fleming phydev->link = 0; 1399082eeacSAndy Fleming } 1409082eeacSAndy Fleming 1419082eeacSAndy Fleming if (mii_reg & MIIM_88E1xxx_PHYSTAT_DUPLEX) 1429082eeacSAndy Fleming phydev->duplex = DUPLEX_FULL; 1439082eeacSAndy Fleming else 1449082eeacSAndy Fleming phydev->duplex = DUPLEX_HALF; 1459082eeacSAndy Fleming 1469082eeacSAndy Fleming speed = mii_reg & MIIM_88E1xxx_PHYSTAT_SPEED; 1479082eeacSAndy Fleming 1489082eeacSAndy Fleming switch (speed) { 1499082eeacSAndy Fleming case MIIM_88E1xxx_PHYSTAT_GBIT: 1509082eeacSAndy Fleming phydev->speed = SPEED_1000; 1519082eeacSAndy Fleming break; 1529082eeacSAndy Fleming case MIIM_88E1xxx_PHYSTAT_100: 1539082eeacSAndy Fleming phydev->speed = SPEED_100; 1549082eeacSAndy Fleming break; 1559082eeacSAndy Fleming default: 1569082eeacSAndy Fleming phydev->speed = SPEED_10; 1579082eeacSAndy Fleming break; 1589082eeacSAndy Fleming } 1599082eeacSAndy Fleming 1609082eeacSAndy Fleming return 0; 1619082eeacSAndy Fleming } 1629082eeacSAndy Fleming 1639082eeacSAndy Fleming static int m88e1011s_startup(struct phy_device *phydev) 1649082eeacSAndy Fleming { 1659082eeacSAndy Fleming genphy_update_link(phydev); 1669082eeacSAndy Fleming m88e1xxx_parse_status(phydev); 1679082eeacSAndy Fleming 1689082eeacSAndy Fleming return 0; 1699082eeacSAndy Fleming } 1709082eeacSAndy Fleming 1719082eeacSAndy Fleming /* Marvell 88E1111S */ 1729082eeacSAndy Fleming static int m88e1111s_config(struct phy_device *phydev) 1739082eeacSAndy Fleming { 1749082eeacSAndy Fleming int reg; 175fa12a08eSZang Roy-R61911 int timeout; 1769082eeacSAndy Fleming 1779082eeacSAndy Fleming if ((phydev->interface == PHY_INTERFACE_MODE_RGMII) || 1789082eeacSAndy Fleming (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID) || 1799082eeacSAndy Fleming (phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID) || 1809082eeacSAndy Fleming (phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID)) { 181fa12a08eSZang Roy-R61911 reg = phy_read(phydev, 182fa12a08eSZang Roy-R61911 MDIO_DEVAD_NONE, MIIM_88E1111_PHY_EXT_CR); 183fa12a08eSZang Roy-R61911 if ((phydev->interface == PHY_INTERFACE_MODE_RGMII) || 184fa12a08eSZang Roy-R61911 (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID)) { 185fa12a08eSZang Roy-R61911 reg |= (MIIM_88E1111_RX_DELAY | MIIM_88E1111_TX_DELAY); 186fa12a08eSZang Roy-R61911 } else if (phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID) { 187fa12a08eSZang Roy-R61911 reg &= ~MIIM_88E1111_TX_DELAY; 188fa12a08eSZang Roy-R61911 reg |= MIIM_88E1111_RX_DELAY; 189fa12a08eSZang Roy-R61911 } else if (phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID) { 190fa12a08eSZang Roy-R61911 reg &= ~MIIM_88E1111_RX_DELAY; 191fa12a08eSZang Roy-R61911 reg |= MIIM_88E1111_TX_DELAY; 1929082eeacSAndy Fleming } 1939082eeacSAndy Fleming 194fa12a08eSZang Roy-R61911 phy_write(phydev, 195fa12a08eSZang Roy-R61911 MDIO_DEVAD_NONE, MIIM_88E1111_PHY_EXT_CR, reg); 196fa12a08eSZang Roy-R61911 197fa12a08eSZang Roy-R61911 reg = phy_read(phydev, 198fa12a08eSZang Roy-R61911 MDIO_DEVAD_NONE, MIIM_88E1111_PHY_EXT_SR); 199fa12a08eSZang Roy-R61911 200fa12a08eSZang Roy-R61911 reg &= ~(MIIM_88E1111_HWCFG_MODE_MASK); 201fa12a08eSZang Roy-R61911 202fa12a08eSZang Roy-R61911 if (reg & MIIM_88E1111_HWCFG_FIBER_COPPER_RES) 203fa12a08eSZang Roy-R61911 reg |= MIIM_88E1111_HWCFG_MODE_FIBER_RGMII; 204fa12a08eSZang Roy-R61911 else 205fa12a08eSZang Roy-R61911 reg |= MIIM_88E1111_HWCFG_MODE_COPPER_RGMII; 206fa12a08eSZang Roy-R61911 207fa12a08eSZang Roy-R61911 phy_write(phydev, 208fa12a08eSZang Roy-R61911 MDIO_DEVAD_NONE, MIIM_88E1111_PHY_EXT_SR, reg); 209fa12a08eSZang Roy-R61911 } 210fa12a08eSZang Roy-R61911 211fa12a08eSZang Roy-R61911 if (phydev->interface == PHY_INTERFACE_MODE_SGMII) { 212fa12a08eSZang Roy-R61911 reg = phy_read(phydev, 213fa12a08eSZang Roy-R61911 MDIO_DEVAD_NONE, MIIM_88E1111_PHY_EXT_SR); 214fa12a08eSZang Roy-R61911 215fa12a08eSZang Roy-R61911 reg &= ~(MIIM_88E1111_HWCFG_MODE_MASK); 216fa12a08eSZang Roy-R61911 reg |= MIIM_88E1111_HWCFG_MODE_SGMII_NO_CLK; 217fa12a08eSZang Roy-R61911 reg |= MIIM_88E1111_HWCFG_FIBER_COPPER_AUTO; 218fa12a08eSZang Roy-R61911 219fa12a08eSZang Roy-R61911 phy_write(phydev, MDIO_DEVAD_NONE, 220fa12a08eSZang Roy-R61911 MIIM_88E1111_PHY_EXT_SR, reg); 221fa12a08eSZang Roy-R61911 } 222fa12a08eSZang Roy-R61911 223fa12a08eSZang Roy-R61911 if (phydev->interface == PHY_INTERFACE_MODE_RTBI) { 224fa12a08eSZang Roy-R61911 reg = phy_read(phydev, 225fa12a08eSZang Roy-R61911 MDIO_DEVAD_NONE, MIIM_88E1111_PHY_EXT_CR); 226fa12a08eSZang Roy-R61911 reg |= (MIIM_88E1111_RX_DELAY | MIIM_88E1111_TX_DELAY); 227fa12a08eSZang Roy-R61911 phy_write(phydev, 228fa12a08eSZang Roy-R61911 MDIO_DEVAD_NONE, MIIM_88E1111_PHY_EXT_CR, reg); 229fa12a08eSZang Roy-R61911 230fa12a08eSZang Roy-R61911 reg = phy_read(phydev, MDIO_DEVAD_NONE, 231fa12a08eSZang Roy-R61911 MIIM_88E1111_PHY_EXT_SR); 232fa12a08eSZang Roy-R61911 reg &= ~(MIIM_88E1111_HWCFG_MODE_MASK | 233fa12a08eSZang Roy-R61911 MIIM_88E1111_HWCFG_FIBER_COPPER_RES); 234fa12a08eSZang Roy-R61911 reg |= 0x7 | MIIM_88E1111_HWCFG_FIBER_COPPER_AUTO; 235fa12a08eSZang Roy-R61911 phy_write(phydev, MDIO_DEVAD_NONE, 236fa12a08eSZang Roy-R61911 MIIM_88E1111_PHY_EXT_SR, reg); 237fa12a08eSZang Roy-R61911 238fa12a08eSZang Roy-R61911 /* soft reset */ 239fa12a08eSZang Roy-R61911 timeout = 1000; 240fa12a08eSZang Roy-R61911 phy_write(phydev, MDIO_DEVAD_NONE, MII_BMCR, BMCR_RESET); 241fa12a08eSZang Roy-R61911 udelay(1000); 242fa12a08eSZang Roy-R61911 reg = phy_read(phydev, MDIO_DEVAD_NONE, MII_BMCR); 243fa12a08eSZang Roy-R61911 while ((reg & BMCR_RESET) && --timeout) { 244fa12a08eSZang Roy-R61911 udelay(1000); 245fa12a08eSZang Roy-R61911 reg = phy_read(phydev, MDIO_DEVAD_NONE, MII_BMCR); 246fa12a08eSZang Roy-R61911 } 247fa12a08eSZang Roy-R61911 if (!timeout) 248fa12a08eSZang Roy-R61911 printf("%s: phy soft reset timeout\n", __func__); 249fa12a08eSZang Roy-R61911 250fa12a08eSZang Roy-R61911 reg = phy_read(phydev, MDIO_DEVAD_NONE, 251fa12a08eSZang Roy-R61911 MIIM_88E1111_PHY_EXT_SR); 252fa12a08eSZang Roy-R61911 reg &= ~(MIIM_88E1111_HWCFG_MODE_MASK | 253fa12a08eSZang Roy-R61911 MIIM_88E1111_HWCFG_FIBER_COPPER_RES); 254fa12a08eSZang Roy-R61911 reg |= MIIM_88E1111_HWCFG_MODE_COPPER_RTBI | 255fa12a08eSZang Roy-R61911 MIIM_88E1111_HWCFG_FIBER_COPPER_AUTO; 256fa12a08eSZang Roy-R61911 phy_write(phydev, MDIO_DEVAD_NONE, 257fa12a08eSZang Roy-R61911 MIIM_88E1111_PHY_EXT_SR, reg); 258fa12a08eSZang Roy-R61911 } 259fa12a08eSZang Roy-R61911 260fa12a08eSZang Roy-R61911 /* soft reset */ 261fa12a08eSZang Roy-R61911 timeout = 1000; 262fa12a08eSZang Roy-R61911 phy_write(phydev, MDIO_DEVAD_NONE, MII_BMCR, BMCR_RESET); 263fa12a08eSZang Roy-R61911 udelay(1000); 264fa12a08eSZang Roy-R61911 reg = phy_read(phydev, MDIO_DEVAD_NONE, MII_BMCR); 265fa12a08eSZang Roy-R61911 while ((reg & BMCR_RESET) && --timeout) { 266fa12a08eSZang Roy-R61911 udelay(1000); 267fa12a08eSZang Roy-R61911 reg = phy_read(phydev, MDIO_DEVAD_NONE, MII_BMCR); 268fa12a08eSZang Roy-R61911 } 269fa12a08eSZang Roy-R61911 if (!timeout) 270fa12a08eSZang Roy-R61911 printf("%s: phy soft reset timeout\n", __func__); 2719082eeacSAndy Fleming 2729082eeacSAndy Fleming genphy_config_aneg(phydev); 2739082eeacSAndy Fleming 2749082eeacSAndy Fleming phy_reset(phydev); 2759082eeacSAndy Fleming 2769082eeacSAndy Fleming return 0; 2779082eeacSAndy Fleming } 2789082eeacSAndy Fleming 27935fa0ddaSHao Zhang /** 28035fa0ddaSHao Zhang * m88e1518_phy_writebits - write bits to a register 28135fa0ddaSHao Zhang */ 28235fa0ddaSHao Zhang void m88e1518_phy_writebits(struct phy_device *phydev, 28335fa0ddaSHao Zhang u8 reg_num, u16 offset, u16 len, u16 data) 28435fa0ddaSHao Zhang { 28535fa0ddaSHao Zhang u16 reg, mask; 28635fa0ddaSHao Zhang 28735fa0ddaSHao Zhang if ((len + offset) >= 16) 28835fa0ddaSHao Zhang mask = 0 - (1 << offset); 28935fa0ddaSHao Zhang else 29035fa0ddaSHao Zhang mask = (1 << (len + offset)) - (1 << offset); 29135fa0ddaSHao Zhang 29235fa0ddaSHao Zhang reg = phy_read(phydev, MDIO_DEVAD_NONE, reg_num); 29335fa0ddaSHao Zhang 29435fa0ddaSHao Zhang reg &= ~mask; 29535fa0ddaSHao Zhang reg |= data << offset; 29635fa0ddaSHao Zhang 29735fa0ddaSHao Zhang phy_write(phydev, MDIO_DEVAD_NONE, reg_num, reg); 29835fa0ddaSHao Zhang } 29935fa0ddaSHao Zhang 30035fa0ddaSHao Zhang static int m88e1518_config(struct phy_device *phydev) 30135fa0ddaSHao Zhang { 30235fa0ddaSHao Zhang /* 30335fa0ddaSHao Zhang * As per Marvell Release Notes - Alaska 88E1510/88E1518/88E1512 30435fa0ddaSHao Zhang * /88E1514 Rev A0, Errata Section 3.1 30535fa0ddaSHao Zhang */ 306*90a94ef6SClemens Gruber 307*90a94ef6SClemens Gruber /* EEE initialization */ 308*90a94ef6SClemens Gruber phy_write(phydev, MDIO_DEVAD_NONE, 22, 0x00ff); 30935fa0ddaSHao Zhang phy_write(phydev, MDIO_DEVAD_NONE, 17, 0x214B); 31035fa0ddaSHao Zhang phy_write(phydev, MDIO_DEVAD_NONE, 16, 0x2144); 31135fa0ddaSHao Zhang phy_write(phydev, MDIO_DEVAD_NONE, 17, 0x0C28); 31235fa0ddaSHao Zhang phy_write(phydev, MDIO_DEVAD_NONE, 16, 0x2146); 31335fa0ddaSHao Zhang phy_write(phydev, MDIO_DEVAD_NONE, 17, 0xB233); 31435fa0ddaSHao Zhang phy_write(phydev, MDIO_DEVAD_NONE, 16, 0x214D); 31535fa0ddaSHao Zhang phy_write(phydev, MDIO_DEVAD_NONE, 17, 0xCC0C); 31635fa0ddaSHao Zhang phy_write(phydev, MDIO_DEVAD_NONE, 16, 0x2159); 317*90a94ef6SClemens Gruber phy_write(phydev, MDIO_DEVAD_NONE, 22, 0x0000); 318*90a94ef6SClemens Gruber 319*90a94ef6SClemens Gruber /* SGMII-to-Copper mode initialization */ 320*90a94ef6SClemens Gruber if (phydev->interface == PHY_INTERFACE_MODE_SGMII) { 321*90a94ef6SClemens Gruber /* Select page 18 */ 322*90a94ef6SClemens Gruber phy_write(phydev, MDIO_DEVAD_NONE, 22, 18); 323*90a94ef6SClemens Gruber 324*90a94ef6SClemens Gruber /* In reg 20, write MODE[2:0] = 0x1 (SGMII to Copper) */ 32535fa0ddaSHao Zhang m88e1518_phy_writebits(phydev, 20, 0, 3, 1); 32635fa0ddaSHao Zhang 327*90a94ef6SClemens Gruber /* PHY reset is necessary after changing MODE[2:0] */ 32835fa0ddaSHao Zhang m88e1518_phy_writebits(phydev, 20, 15, 1, 1); 329*90a94ef6SClemens Gruber 330*90a94ef6SClemens Gruber /* Reset page selection */ 331*90a94ef6SClemens Gruber phy_write(phydev, MDIO_DEVAD_NONE, 22, 0); 332*90a94ef6SClemens Gruber 33335fa0ddaSHao Zhang udelay(100); 33435fa0ddaSHao Zhang } 33535fa0ddaSHao Zhang 33635fa0ddaSHao Zhang return m88e1111s_config(phydev); 33735fa0ddaSHao Zhang } 33835fa0ddaSHao Zhang 3399082eeacSAndy Fleming /* Marvell 88E1118 */ 3409082eeacSAndy Fleming static int m88e1118_config(struct phy_device *phydev) 3419082eeacSAndy Fleming { 3429082eeacSAndy Fleming /* Change Page Number */ 3439082eeacSAndy Fleming phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1118_PHY_PAGE, 0x0002); 3449082eeacSAndy Fleming /* Delay RGMII TX and RX */ 3459082eeacSAndy Fleming phy_write(phydev, MDIO_DEVAD_NONE, 0x15, 0x1070); 3469082eeacSAndy Fleming /* Change Page Number */ 3479082eeacSAndy Fleming phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1118_PHY_PAGE, 0x0003); 3489082eeacSAndy Fleming /* Adjust LED control */ 3499082eeacSAndy Fleming phy_write(phydev, MDIO_DEVAD_NONE, 0x10, 0x021e); 3509082eeacSAndy Fleming /* Change Page Number */ 3519082eeacSAndy Fleming phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1118_PHY_PAGE, 0x0000); 3529082eeacSAndy Fleming 3539082eeacSAndy Fleming genphy_config_aneg(phydev); 3549082eeacSAndy Fleming 3559082eeacSAndy Fleming phy_reset(phydev); 3569082eeacSAndy Fleming 3579082eeacSAndy Fleming return 0; 3589082eeacSAndy Fleming } 3599082eeacSAndy Fleming 3609082eeacSAndy Fleming static int m88e1118_startup(struct phy_device *phydev) 3619082eeacSAndy Fleming { 3629082eeacSAndy Fleming /* Change Page Number */ 3639082eeacSAndy Fleming phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1118_PHY_PAGE, 0x0000); 3649082eeacSAndy Fleming 3659082eeacSAndy Fleming genphy_update_link(phydev); 3669082eeacSAndy Fleming m88e1xxx_parse_status(phydev); 3679082eeacSAndy Fleming 3689082eeacSAndy Fleming return 0; 3699082eeacSAndy Fleming } 3709082eeacSAndy Fleming 3719082eeacSAndy Fleming /* Marvell 88E1121R */ 3729082eeacSAndy Fleming static int m88e1121_config(struct phy_device *phydev) 3739082eeacSAndy Fleming { 3749082eeacSAndy Fleming int pg; 3759082eeacSAndy Fleming 3769082eeacSAndy Fleming /* Configure the PHY */ 3779082eeacSAndy Fleming genphy_config_aneg(phydev); 3789082eeacSAndy Fleming 3799082eeacSAndy Fleming /* Switch the page to access the led register */ 3809082eeacSAndy Fleming pg = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_88E1121_PHY_PAGE); 3819082eeacSAndy Fleming phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1121_PHY_PAGE, 3829082eeacSAndy Fleming MIIM_88E1121_PHY_LED_PAGE); 3839082eeacSAndy Fleming /* Configure leds */ 3849082eeacSAndy Fleming phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1121_PHY_LED_CTRL, 3859082eeacSAndy Fleming MIIM_88E1121_PHY_LED_DEF); 3869082eeacSAndy Fleming /* Restore the page pointer */ 3879082eeacSAndy Fleming phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1121_PHY_PAGE, pg); 3889082eeacSAndy Fleming 3899082eeacSAndy Fleming /* Disable IRQs and de-assert interrupt */ 3909082eeacSAndy Fleming phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1121_PHY_IRQ_EN, 0); 3919082eeacSAndy Fleming phy_read(phydev, MDIO_DEVAD_NONE, MIIM_88E1121_PHY_IRQ_STATUS); 3929082eeacSAndy Fleming 3939082eeacSAndy Fleming return 0; 3949082eeacSAndy Fleming } 3959082eeacSAndy Fleming 3969082eeacSAndy Fleming /* Marvell 88E1145 */ 3979082eeacSAndy Fleming static int m88e1145_config(struct phy_device *phydev) 3989082eeacSAndy Fleming { 3999082eeacSAndy Fleming int reg; 4009082eeacSAndy Fleming 4019082eeacSAndy Fleming /* Errata E0, E1 */ 4029082eeacSAndy Fleming phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1145_PHY_PAGE, 0x001b); 4039082eeacSAndy Fleming phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1145_PHY_CAL_OV, 0x418f); 4049082eeacSAndy Fleming phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1145_PHY_PAGE, 0x0016); 4059082eeacSAndy Fleming phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1145_PHY_CAL_OV, 0xa2da); 4069082eeacSAndy Fleming 4079082eeacSAndy Fleming phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1xxx_PHY_SCR, 4089082eeacSAndy Fleming MIIM_88E1xxx_PHY_MDI_X_AUTO); 4099082eeacSAndy Fleming 4109082eeacSAndy Fleming reg = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_88E1145_PHY_EXT_CR); 4119082eeacSAndy Fleming if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID) 4129082eeacSAndy Fleming reg |= MIIM_M88E1145_RGMII_RX_DELAY | 4139082eeacSAndy Fleming MIIM_M88E1145_RGMII_TX_DELAY; 4149082eeacSAndy Fleming phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1145_PHY_EXT_CR, reg); 4159082eeacSAndy Fleming 4169082eeacSAndy Fleming genphy_config_aneg(phydev); 4179082eeacSAndy Fleming 4189082eeacSAndy Fleming phy_reset(phydev); 4199082eeacSAndy Fleming 4209082eeacSAndy Fleming return 0; 4219082eeacSAndy Fleming } 4229082eeacSAndy Fleming 4239082eeacSAndy Fleming static int m88e1145_startup(struct phy_device *phydev) 4249082eeacSAndy Fleming { 4259082eeacSAndy Fleming genphy_update_link(phydev); 4269082eeacSAndy Fleming phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1145_PHY_LED_CONTROL, 4279082eeacSAndy Fleming MIIM_88E1145_PHY_LED_DIRECT); 4289082eeacSAndy Fleming m88e1xxx_parse_status(phydev); 4299082eeacSAndy Fleming 4309082eeacSAndy Fleming return 0; 4319082eeacSAndy Fleming } 4329082eeacSAndy Fleming 4339082eeacSAndy Fleming /* Marvell 88E1149S */ 4349082eeacSAndy Fleming static int m88e1149_config(struct phy_device *phydev) 4359082eeacSAndy Fleming { 4369082eeacSAndy Fleming phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1149_PHY_PAGE, 0x1f); 4379082eeacSAndy Fleming phy_write(phydev, MDIO_DEVAD_NONE, 0x1e, 0x200c); 4389082eeacSAndy Fleming phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1149_PHY_PAGE, 0x5); 4399082eeacSAndy Fleming phy_write(phydev, MDIO_DEVAD_NONE, 0x1e, 0x0); 4409082eeacSAndy Fleming phy_write(phydev, MDIO_DEVAD_NONE, 0x1e, 0x100); 4419082eeacSAndy Fleming 4429082eeacSAndy Fleming genphy_config_aneg(phydev); 4439082eeacSAndy Fleming 4449082eeacSAndy Fleming phy_reset(phydev); 4459082eeacSAndy Fleming 4469082eeacSAndy Fleming return 0; 4479082eeacSAndy Fleming } 4489082eeacSAndy Fleming 449aeceec0dSSebastian Hesselbarth /* Marvell 88E1310 */ 450aeceec0dSSebastian Hesselbarth static int m88e1310_config(struct phy_device *phydev) 451aeceec0dSSebastian Hesselbarth { 452aeceec0dSSebastian Hesselbarth u16 reg; 453aeceec0dSSebastian Hesselbarth 454aeceec0dSSebastian Hesselbarth /* LED link and activity */ 455aeceec0dSSebastian Hesselbarth phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1310_PHY_PAGE, 0x0003); 456aeceec0dSSebastian Hesselbarth reg = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_88E1310_PHY_LED_CTRL); 457aeceec0dSSebastian Hesselbarth reg = (reg & ~0xf) | 0x1; 458aeceec0dSSebastian Hesselbarth phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1310_PHY_LED_CTRL, reg); 459aeceec0dSSebastian Hesselbarth 460aeceec0dSSebastian Hesselbarth /* Set LED2/INT to INT mode, low active */ 461aeceec0dSSebastian Hesselbarth phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1310_PHY_PAGE, 0x0003); 462aeceec0dSSebastian Hesselbarth reg = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_88E1310_PHY_IRQ_EN); 463aeceec0dSSebastian Hesselbarth reg = (reg & 0x77ff) | 0x0880; 464aeceec0dSSebastian Hesselbarth phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1310_PHY_IRQ_EN, reg); 465aeceec0dSSebastian Hesselbarth 466aeceec0dSSebastian Hesselbarth /* Set RGMII delay */ 467aeceec0dSSebastian Hesselbarth phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1310_PHY_PAGE, 0x0002); 468aeceec0dSSebastian Hesselbarth reg = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_88E1310_PHY_RGMII_CTRL); 469aeceec0dSSebastian Hesselbarth reg |= 0x0030; 470aeceec0dSSebastian Hesselbarth phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1310_PHY_RGMII_CTRL, reg); 471aeceec0dSSebastian Hesselbarth 472aeceec0dSSebastian Hesselbarth /* Ensure to return to page 0 */ 473aeceec0dSSebastian Hesselbarth phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1310_PHY_PAGE, 0x0000); 474aeceec0dSSebastian Hesselbarth 475aeceec0dSSebastian Hesselbarth genphy_config_aneg(phydev); 476aeceec0dSSebastian Hesselbarth phy_reset(phydev); 477aeceec0dSSebastian Hesselbarth 478aeceec0dSSebastian Hesselbarth return 0; 479aeceec0dSSebastian Hesselbarth } 4809082eeacSAndy Fleming 4819082eeacSAndy Fleming static struct phy_driver M88E1011S_driver = { 4829082eeacSAndy Fleming .name = "Marvell 88E1011S", 4839082eeacSAndy Fleming .uid = 0x1410c60, 4849082eeacSAndy Fleming .mask = 0xffffff0, 4859082eeacSAndy Fleming .features = PHY_GBIT_FEATURES, 4869082eeacSAndy Fleming .config = &m88e1011s_config, 4879082eeacSAndy Fleming .startup = &m88e1011s_startup, 4889082eeacSAndy Fleming .shutdown = &genphy_shutdown, 4899082eeacSAndy Fleming }; 4909082eeacSAndy Fleming 4919082eeacSAndy Fleming static struct phy_driver M88E1111S_driver = { 4929082eeacSAndy Fleming .name = "Marvell 88E1111S", 4939082eeacSAndy Fleming .uid = 0x1410cc0, 4949082eeacSAndy Fleming .mask = 0xffffff0, 4959082eeacSAndy Fleming .features = PHY_GBIT_FEATURES, 4969082eeacSAndy Fleming .config = &m88e1111s_config, 4979082eeacSAndy Fleming .startup = &m88e1011s_startup, 4989082eeacSAndy Fleming .shutdown = &genphy_shutdown, 4999082eeacSAndy Fleming }; 5009082eeacSAndy Fleming 5019082eeacSAndy Fleming static struct phy_driver M88E1118_driver = { 5029082eeacSAndy Fleming .name = "Marvell 88E1118", 5039082eeacSAndy Fleming .uid = 0x1410e10, 5049082eeacSAndy Fleming .mask = 0xffffff0, 5059082eeacSAndy Fleming .features = PHY_GBIT_FEATURES, 5069082eeacSAndy Fleming .config = &m88e1118_config, 5079082eeacSAndy Fleming .startup = &m88e1118_startup, 5089082eeacSAndy Fleming .shutdown = &genphy_shutdown, 5099082eeacSAndy Fleming }; 5109082eeacSAndy Fleming 511b4b81e83SMichal Simek static struct phy_driver M88E1118R_driver = { 512b4b81e83SMichal Simek .name = "Marvell 88E1118R", 513b4b81e83SMichal Simek .uid = 0x1410e40, 514b4b81e83SMichal Simek .mask = 0xffffff0, 515b4b81e83SMichal Simek .features = PHY_GBIT_FEATURES, 516b4b81e83SMichal Simek .config = &m88e1118_config, 517b4b81e83SMichal Simek .startup = &m88e1118_startup, 518b4b81e83SMichal Simek .shutdown = &genphy_shutdown, 519b4b81e83SMichal Simek }; 520b4b81e83SMichal Simek 5219082eeacSAndy Fleming static struct phy_driver M88E1121R_driver = { 5229082eeacSAndy Fleming .name = "Marvell 88E1121R", 5239082eeacSAndy Fleming .uid = 0x1410cb0, 5249082eeacSAndy Fleming .mask = 0xffffff0, 5259082eeacSAndy Fleming .features = PHY_GBIT_FEATURES, 5269082eeacSAndy Fleming .config = &m88e1121_config, 5279082eeacSAndy Fleming .startup = &genphy_startup, 5289082eeacSAndy Fleming .shutdown = &genphy_shutdown, 5299082eeacSAndy Fleming }; 5309082eeacSAndy Fleming 5319082eeacSAndy Fleming static struct phy_driver M88E1145_driver = { 5329082eeacSAndy Fleming .name = "Marvell 88E1145", 5339082eeacSAndy Fleming .uid = 0x1410cd0, 5349082eeacSAndy Fleming .mask = 0xffffff0, 5359082eeacSAndy Fleming .features = PHY_GBIT_FEATURES, 5369082eeacSAndy Fleming .config = &m88e1145_config, 5379082eeacSAndy Fleming .startup = &m88e1145_startup, 5389082eeacSAndy Fleming .shutdown = &genphy_shutdown, 5399082eeacSAndy Fleming }; 5409082eeacSAndy Fleming 5419082eeacSAndy Fleming static struct phy_driver M88E1149S_driver = { 5429082eeacSAndy Fleming .name = "Marvell 88E1149S", 5439082eeacSAndy Fleming .uid = 0x1410ca0, 5449082eeacSAndy Fleming .mask = 0xffffff0, 5459082eeacSAndy Fleming .features = PHY_GBIT_FEATURES, 5469082eeacSAndy Fleming .config = &m88e1149_config, 5479082eeacSAndy Fleming .startup = &m88e1011s_startup, 5489082eeacSAndy Fleming .shutdown = &genphy_shutdown, 5499082eeacSAndy Fleming }; 5509082eeacSAndy Fleming 5511415107eSMichal Simek static struct phy_driver M88E1518_driver = { 5521415107eSMichal Simek .name = "Marvell 88E1518", 5531415107eSMichal Simek .uid = 0x1410dd1, 5541415107eSMichal Simek .mask = 0xffffff0, 5551415107eSMichal Simek .features = PHY_GBIT_FEATURES, 55635fa0ddaSHao Zhang .config = &m88e1518_config, 5571415107eSMichal Simek .startup = &m88e1011s_startup, 5581415107eSMichal Simek .shutdown = &genphy_shutdown, 5591415107eSMichal Simek }; 5601415107eSMichal Simek 561aeceec0dSSebastian Hesselbarth static struct phy_driver M88E1310_driver = { 562aeceec0dSSebastian Hesselbarth .name = "Marvell 88E1310", 563aeceec0dSSebastian Hesselbarth .uid = 0x01410e90, 564aeceec0dSSebastian Hesselbarth .mask = 0xffffff0, 565aeceec0dSSebastian Hesselbarth .features = PHY_GBIT_FEATURES, 566aeceec0dSSebastian Hesselbarth .config = &m88e1310_config, 567aeceec0dSSebastian Hesselbarth .startup = &m88e1011s_startup, 568aeceec0dSSebastian Hesselbarth .shutdown = &genphy_shutdown, 569aeceec0dSSebastian Hesselbarth }; 570aeceec0dSSebastian Hesselbarth 5719082eeacSAndy Fleming int phy_marvell_init(void) 5729082eeacSAndy Fleming { 573aeceec0dSSebastian Hesselbarth phy_register(&M88E1310_driver); 5749082eeacSAndy Fleming phy_register(&M88E1149S_driver); 5759082eeacSAndy Fleming phy_register(&M88E1145_driver); 5769082eeacSAndy Fleming phy_register(&M88E1121R_driver); 5779082eeacSAndy Fleming phy_register(&M88E1118_driver); 578b4b81e83SMichal Simek phy_register(&M88E1118R_driver); 5799082eeacSAndy Fleming phy_register(&M88E1111S_driver); 5809082eeacSAndy Fleming phy_register(&M88E1011S_driver); 5811415107eSMichal Simek phy_register(&M88E1518_driver); 5829082eeacSAndy Fleming 5839082eeacSAndy Fleming return 0; 5849082eeacSAndy Fleming } 585