1 /* 2 * Vitesse PHY drivers 3 * 4 * Copyright 2010-2012 Freescale Semiconductor, Inc. 5 * Author: Andy Fleming 6 * Add vsc8662 phy support - Priyanka Jain 7 * This program is free software; you can redistribute it and/or 8 * modify it under the terms of the GNU General Public License as 9 * published by the Free Software Foundation; either version 2 of 10 * the License, or (at your option) any later version. 11 * 12 * This program is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 * GNU General Public License for more details. 16 * 17 * You should have received a copy of the GNU General Public License 18 * along with this program; if not, write to the Free Software 19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, 20 * MA 02111-1307 USA 21 */ 22 #include <miiphy.h> 23 24 /* Cicada Auxiliary Control/Status Register */ 25 #define MIIM_CIS82xx_AUX_CONSTAT 0x1c 26 #define MIIM_CIS82xx_AUXCONSTAT_INIT 0x0004 27 #define MIIM_CIS82xx_AUXCONSTAT_DUPLEX 0x0020 28 #define MIIM_CIS82xx_AUXCONSTAT_SPEED 0x0018 29 #define MIIM_CIS82xx_AUXCONSTAT_GBIT 0x0010 30 #define MIIM_CIS82xx_AUXCONSTAT_100 0x0008 31 32 /* Cicada Extended Control Register 1 */ 33 #define MIIM_CIS82xx_EXT_CON1 0x17 34 #define MIIM_CIS8201_EXTCON1_INIT 0x0000 35 36 /* Cicada 8204 Extended PHY Control Register 1 */ 37 #define MIIM_CIS8204_EPHY_CON 0x17 38 #define MIIM_CIS8204_EPHYCON_INIT 0x0006 39 #define MIIM_CIS8204_EPHYCON_RGMII 0x1100 40 41 /* Cicada 8204 Serial LED Control Register */ 42 #define MIIM_CIS8204_SLED_CON 0x1b 43 #define MIIM_CIS8204_SLEDCON_INIT 0x1115 44 45 /* Vitesse VSC8601 Extended PHY Control Register 1 */ 46 #define MIIM_VSC8601_EPHY_CON 0x17 47 #define MIIM_VSC8601_EPHY_CON_INIT_SKEW 0x1120 48 #define MIIM_VSC8601_SKEW_CTRL 0x1c 49 50 #define PHY_EXT_PAGE_ACCESS 0x1f 51 #define PHY_EXT_PAGE_ACCESS_GENERAL 0x10 52 #define PHY_EXT_PAGE_ACCESS_EXTENDED3 0x3 53 54 /* Vitesse VSC8574 control register */ 55 #define MIIM_VSC8574_MAC_SERDES_CON 0x10 56 #define MIIM_VSC8574_MAC_SERDES_ANEG 0x80 57 #define MIIM_VSC8574_GENERAL18 0x12 58 #define MIIM_VSC8574_GENERAL19 0x13 59 60 /* Vitesse VSC8574 gerenal purpose register 18 */ 61 #define MIIM_VSC8574_18G_SGMII 0x80f0 62 #define MIIM_VSC8574_18G_QSGMII 0x80e0 63 #define MIIM_VSC8574_18G_CMDSTAT 0x8000 64 65 /* CIS8201 */ 66 static int vitesse_config(struct phy_device *phydev) 67 { 68 /* Override PHY config settings */ 69 phy_write(phydev, MDIO_DEVAD_NONE, MIIM_CIS82xx_AUX_CONSTAT, 70 MIIM_CIS82xx_AUXCONSTAT_INIT); 71 /* Set up the interface mode */ 72 phy_write(phydev, MDIO_DEVAD_NONE, MIIM_CIS82xx_EXT_CON1, 73 MIIM_CIS8201_EXTCON1_INIT); 74 75 genphy_config_aneg(phydev); 76 77 return 0; 78 } 79 80 static int vitesse_parse_status(struct phy_device *phydev) 81 { 82 int speed; 83 int mii_reg; 84 85 mii_reg = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_CIS82xx_AUX_CONSTAT); 86 87 if (mii_reg & MIIM_CIS82xx_AUXCONSTAT_DUPLEX) 88 phydev->duplex = DUPLEX_FULL; 89 else 90 phydev->duplex = DUPLEX_HALF; 91 92 speed = mii_reg & MIIM_CIS82xx_AUXCONSTAT_SPEED; 93 switch (speed) { 94 case MIIM_CIS82xx_AUXCONSTAT_GBIT: 95 phydev->speed = SPEED_1000; 96 break; 97 case MIIM_CIS82xx_AUXCONSTAT_100: 98 phydev->speed = SPEED_100; 99 break; 100 default: 101 phydev->speed = SPEED_10; 102 break; 103 } 104 105 return 0; 106 } 107 108 static int vitesse_startup(struct phy_device *phydev) 109 { 110 genphy_update_link(phydev); 111 vitesse_parse_status(phydev); 112 113 return 0; 114 } 115 116 static int cis8204_config(struct phy_device *phydev) 117 { 118 /* Override PHY config settings */ 119 phy_write(phydev, MDIO_DEVAD_NONE, MIIM_CIS82xx_AUX_CONSTAT, 120 MIIM_CIS82xx_AUXCONSTAT_INIT); 121 122 genphy_config_aneg(phydev); 123 124 if ((phydev->interface == PHY_INTERFACE_MODE_RGMII) || 125 (phydev->interface == PHY_INTERFACE_MODE_RGMII) || 126 (phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID) || 127 (phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID)) 128 phy_write(phydev, MDIO_DEVAD_NONE, MIIM_CIS8204_EPHY_CON, 129 MIIM_CIS8204_EPHYCON_INIT | 130 MIIM_CIS8204_EPHYCON_RGMII); 131 else 132 phy_write(phydev, MDIO_DEVAD_NONE, MIIM_CIS8204_EPHY_CON, 133 MIIM_CIS8204_EPHYCON_INIT); 134 135 return 0; 136 } 137 138 /* Vitesse VSC8601 */ 139 static int vsc8601_config(struct phy_device *phydev) 140 { 141 /* Configure some basic stuff */ 142 #ifdef CONFIG_SYS_VSC8601_SKEWFIX 143 phy_write(phydev, MDIO_DEVAD_NONE, MIIM_VSC8601_EPHY_CON, 144 MIIM_VSC8601_EPHY_CON_INIT_SKEW); 145 #if defined(CONFIG_SYS_VSC8601_SKEW_TX) && defined(CONFIG_SYS_VSC8601_SKEW_RX) 146 phy_write(phydev, MDIO_DEVAD_NONE, PHY_EXT_PAGE_ACCESS, 1); 147 #define VSC8101_SKEW \ 148 ((CONFIG_SYS_VSC8601_SKEW_TX << 14) \ 149 | (CONFIG_SYS_VSC8601_SKEW_RX << 12)) 150 phy_write(phydev, MDIO_DEVAD_NONE, MIIM_VSC8601_SKEW_CTRL, 151 VSC8101_SKEW); 152 phy_write(phydev, MDIO_DEVAD_NONE, PHY_EXT_PAGE_ACCESS, 0); 153 #endif 154 #endif 155 156 genphy_config_aneg(phydev); 157 158 return 0; 159 } 160 161 static int vsc8574_config(struct phy_device *phydev) 162 { 163 u32 val; 164 /* configure regiser 19G for MAC */ 165 phy_write(phydev, MDIO_DEVAD_NONE, PHY_EXT_PAGE_ACCESS, 166 PHY_EXT_PAGE_ACCESS_GENERAL); 167 168 val = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_VSC8574_GENERAL19); 169 if (phydev->interface == PHY_INTERFACE_MODE_QSGMII) { 170 /* set bit 15:14 to '01' for QSGMII mode */ 171 val = (val & 0x3fff) | (1 << 14); 172 phy_write(phydev, MDIO_DEVAD_NONE, 173 MIIM_VSC8574_GENERAL19, val); 174 /* Enable 4 ports MAC QSGMII */ 175 phy_write(phydev, MDIO_DEVAD_NONE, MIIM_VSC8574_GENERAL18, 176 MIIM_VSC8574_18G_QSGMII); 177 } else { 178 /* set bit 15:14 to '00' for SGMII mode */ 179 val = val & 0x3fff; 180 phy_write(phydev, MDIO_DEVAD_NONE, MIIM_VSC8574_GENERAL19, val); 181 /* Enable 4 ports MAC SGMII */ 182 phy_write(phydev, MDIO_DEVAD_NONE, MIIM_VSC8574_GENERAL18, 183 MIIM_VSC8574_18G_SGMII); 184 } 185 val = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_VSC8574_GENERAL18); 186 /* When bit 15 is cleared the command has completed */ 187 while (val & MIIM_VSC8574_18G_CMDSTAT) 188 val = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_VSC8574_GENERAL18); 189 190 /* Enable Serdes Auto-negotiation */ 191 phy_write(phydev, MDIO_DEVAD_NONE, PHY_EXT_PAGE_ACCESS, 192 PHY_EXT_PAGE_ACCESS_EXTENDED3); 193 val = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_VSC8574_MAC_SERDES_CON); 194 val = val | MIIM_VSC8574_MAC_SERDES_ANEG; 195 phy_write(phydev, MDIO_DEVAD_NONE, MIIM_VSC8574_MAC_SERDES_CON, val); 196 197 phy_write(phydev, MDIO_DEVAD_NONE, PHY_EXT_PAGE_ACCESS, 0); 198 199 genphy_config_aneg(phydev); 200 201 return 0; 202 } 203 204 static struct phy_driver VSC8211_driver = { 205 .name = "Vitesse VSC8211", 206 .uid = 0xfc4b0, 207 .mask = 0xffff0, 208 .features = PHY_GBIT_FEATURES, 209 .config = &vitesse_config, 210 .startup = &vitesse_startup, 211 .shutdown = &genphy_shutdown, 212 }; 213 214 static struct phy_driver VSC8221_driver = { 215 .name = "Vitesse VSC8221", 216 .uid = 0xfc550, 217 .mask = 0xffff0, 218 .features = PHY_GBIT_FEATURES, 219 .config = &genphy_config_aneg, 220 .startup = &vitesse_startup, 221 .shutdown = &genphy_shutdown, 222 }; 223 224 static struct phy_driver VSC8244_driver = { 225 .name = "Vitesse VSC8244", 226 .uid = 0xfc6c0, 227 .mask = 0xffff0, 228 .features = PHY_GBIT_FEATURES, 229 .config = &genphy_config_aneg, 230 .startup = &vitesse_startup, 231 .shutdown = &genphy_shutdown, 232 }; 233 234 static struct phy_driver VSC8234_driver = { 235 .name = "Vitesse VSC8234", 236 .uid = 0xfc620, 237 .mask = 0xffff0, 238 .features = PHY_GBIT_FEATURES, 239 .config = &genphy_config_aneg, 240 .startup = &vitesse_startup, 241 .shutdown = &genphy_shutdown, 242 }; 243 244 static struct phy_driver VSC8574_driver = { 245 .name = "Vitesse VSC8574", 246 .uid = 0x704a0, 247 .mask = 0xffff0, 248 .features = PHY_GBIT_FEATURES, 249 .config = &vsc8574_config, 250 .startup = &vitesse_startup, 251 .shutdown = &genphy_shutdown, 252 }; 253 254 static struct phy_driver VSC8601_driver = { 255 .name = "Vitesse VSC8601", 256 .uid = 0x70420, 257 .mask = 0xffff0, 258 .features = PHY_GBIT_FEATURES, 259 .config = &vsc8601_config, 260 .startup = &vitesse_startup, 261 .shutdown = &genphy_shutdown, 262 }; 263 264 static struct phy_driver VSC8641_driver = { 265 .name = "Vitesse VSC8641", 266 .uid = 0x70430, 267 .mask = 0xffff0, 268 .features = PHY_GBIT_FEATURES, 269 .config = &genphy_config_aneg, 270 .startup = &vitesse_startup, 271 .shutdown = &genphy_shutdown, 272 }; 273 274 static struct phy_driver VSC8662_driver = { 275 .name = "Vitesse VSC8662", 276 .uid = 0x70660, 277 .mask = 0xffff0, 278 .features = PHY_GBIT_FEATURES, 279 .config = &genphy_config_aneg, 280 .startup = &vitesse_startup, 281 .shutdown = &genphy_shutdown, 282 }; 283 284 /* Vitesse bought Cicada, so we'll put these here */ 285 static struct phy_driver cis8201_driver = { 286 .name = "CIS8201", 287 .uid = 0xfc410, 288 .mask = 0xffff0, 289 .features = PHY_GBIT_FEATURES, 290 .config = &vitesse_config, 291 .startup = &vitesse_startup, 292 .shutdown = &genphy_shutdown, 293 }; 294 295 static struct phy_driver cis8204_driver = { 296 .name = "Cicada Cis8204", 297 .uid = 0xfc440, 298 .mask = 0xffff0, 299 .features = PHY_GBIT_FEATURES, 300 .config = &cis8204_config, 301 .startup = &vitesse_startup, 302 .shutdown = &genphy_shutdown, 303 }; 304 305 int phy_vitesse_init(void) 306 { 307 phy_register(&VSC8641_driver); 308 phy_register(&VSC8601_driver); 309 phy_register(&VSC8234_driver); 310 phy_register(&VSC8244_driver); 311 phy_register(&VSC8211_driver); 312 phy_register(&VSC8221_driver); 313 phy_register(&VSC8574_driver); 314 phy_register(&VSC8662_driver); 315 phy_register(&cis8201_driver); 316 phy_register(&cis8204_driver); 317 318 return 0; 319 } 320