Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v2.6.24 454 lines 11 kB view raw
1/* 2 * drivers/net/ibm_newemac/phy.c 3 * 4 * Driver for PowerPC 4xx on-chip ethernet controller, PHY support. 5 * Borrowed from sungem_phy.c, though I only kept the generic MII 6 * driver for now. 7 * 8 * This file should be shared with other drivers or eventually 9 * merged as the "low level" part of miilib 10 * 11 * Copyright 2007 Benjamin Herrenschmidt, IBM Corp. 12 * <benh@kernel.crashing.org> 13 * 14 * Based on the arch/ppc version of the driver: 15 * 16 * (c) 2003, Benjamin Herrenscmidt (benh@kernel.crashing.org) 17 * (c) 2004-2005, Eugene Surovegin <ebs@ebshome.net> 18 * 19 */ 20#include <linux/module.h> 21#include <linux/kernel.h> 22#include <linux/types.h> 23#include <linux/netdevice.h> 24#include <linux/mii.h> 25#include <linux/ethtool.h> 26#include <linux/delay.h> 27 28#include "emac.h" 29#include "phy.h" 30 31static inline int phy_read(struct mii_phy *phy, int reg) 32{ 33 return phy->mdio_read(phy->dev, phy->address, reg); 34} 35 36static inline void phy_write(struct mii_phy *phy, int reg, int val) 37{ 38 phy->mdio_write(phy->dev, phy->address, reg, val); 39} 40 41int emac_mii_reset_phy(struct mii_phy *phy) 42{ 43 int val; 44 int limit = 10000; 45 46 val = phy_read(phy, MII_BMCR); 47 val &= ~(BMCR_ISOLATE | BMCR_ANENABLE); 48 val |= BMCR_RESET; 49 phy_write(phy, MII_BMCR, val); 50 51 udelay(300); 52 53 while (limit--) { 54 val = phy_read(phy, MII_BMCR); 55 if (val >= 0 && (val & BMCR_RESET) == 0) 56 break; 57 udelay(10); 58 } 59 if ((val & BMCR_ISOLATE) && limit > 0) 60 phy_write(phy, MII_BMCR, val & ~BMCR_ISOLATE); 61 62 return limit <= 0; 63} 64 65static int genmii_setup_aneg(struct mii_phy *phy, u32 advertise) 66{ 67 int ctl, adv; 68 69 phy->autoneg = AUTONEG_ENABLE; 70 phy->speed = SPEED_10; 71 phy->duplex = DUPLEX_HALF; 72 phy->pause = phy->asym_pause = 0; 73 phy->advertising = advertise; 74 75 ctl = phy_read(phy, MII_BMCR); 76 if (ctl < 0) 77 return ctl; 78 ctl &= ~(BMCR_FULLDPLX | BMCR_SPEED100 | BMCR_SPEED1000 | BMCR_ANENABLE); 79 80 /* First clear the PHY */ 81 phy_write(phy, MII_BMCR, ctl); 82 83 /* Setup standard advertise */ 84 adv = phy_read(phy, MII_ADVERTISE); 85 if (adv < 0) 86 return adv; 87 adv &= ~(ADVERTISE_ALL | ADVERTISE_100BASE4 | ADVERTISE_PAUSE_CAP | 88 ADVERTISE_PAUSE_ASYM); 89 if (advertise & ADVERTISED_10baseT_Half) 90 adv |= ADVERTISE_10HALF; 91 if (advertise & ADVERTISED_10baseT_Full) 92 adv |= ADVERTISE_10FULL; 93 if (advertise & ADVERTISED_100baseT_Half) 94 adv |= ADVERTISE_100HALF; 95 if (advertise & ADVERTISED_100baseT_Full) 96 adv |= ADVERTISE_100FULL; 97 if (advertise & ADVERTISED_Pause) 98 adv |= ADVERTISE_PAUSE_CAP; 99 if (advertise & ADVERTISED_Asym_Pause) 100 adv |= ADVERTISE_PAUSE_ASYM; 101 phy_write(phy, MII_ADVERTISE, adv); 102 103 if (phy->features & 104 (SUPPORTED_1000baseT_Full | SUPPORTED_1000baseT_Half)) { 105 adv = phy_read(phy, MII_CTRL1000); 106 if (adv < 0) 107 return adv; 108 adv &= ~(ADVERTISE_1000FULL | ADVERTISE_1000HALF); 109 if (advertise & ADVERTISED_1000baseT_Full) 110 adv |= ADVERTISE_1000FULL; 111 if (advertise & ADVERTISED_1000baseT_Half) 112 adv |= ADVERTISE_1000HALF; 113 phy_write(phy, MII_CTRL1000, adv); 114 } 115 116 /* Start/Restart aneg */ 117 ctl = phy_read(phy, MII_BMCR); 118 ctl |= (BMCR_ANENABLE | BMCR_ANRESTART); 119 phy_write(phy, MII_BMCR, ctl); 120 121 return 0; 122} 123 124static int genmii_setup_forced(struct mii_phy *phy, int speed, int fd) 125{ 126 int ctl; 127 128 phy->autoneg = AUTONEG_DISABLE; 129 phy->speed = speed; 130 phy->duplex = fd; 131 phy->pause = phy->asym_pause = 0; 132 133 ctl = phy_read(phy, MII_BMCR); 134 if (ctl < 0) 135 return ctl; 136 ctl &= ~(BMCR_FULLDPLX | BMCR_SPEED100 | BMCR_SPEED1000 | BMCR_ANENABLE); 137 138 /* First clear the PHY */ 139 phy_write(phy, MII_BMCR, ctl | BMCR_RESET); 140 141 /* Select speed & duplex */ 142 switch (speed) { 143 case SPEED_10: 144 break; 145 case SPEED_100: 146 ctl |= BMCR_SPEED100; 147 break; 148 case SPEED_1000: 149 ctl |= BMCR_SPEED1000; 150 break; 151 default: 152 return -EINVAL; 153 } 154 if (fd == DUPLEX_FULL) 155 ctl |= BMCR_FULLDPLX; 156 phy_write(phy, MII_BMCR, ctl); 157 158 return 0; 159} 160 161static int genmii_poll_link(struct mii_phy *phy) 162{ 163 int status; 164 165 /* Clear latched value with dummy read */ 166 phy_read(phy, MII_BMSR); 167 status = phy_read(phy, MII_BMSR); 168 if (status < 0 || (status & BMSR_LSTATUS) == 0) 169 return 0; 170 if (phy->autoneg == AUTONEG_ENABLE && !(status & BMSR_ANEGCOMPLETE)) 171 return 0; 172 return 1; 173} 174 175static int genmii_read_link(struct mii_phy *phy) 176{ 177 if (phy->autoneg == AUTONEG_ENABLE) { 178 int glpa = 0; 179 int lpa = phy_read(phy, MII_LPA) & phy_read(phy, MII_ADVERTISE); 180 if (lpa < 0) 181 return lpa; 182 183 if (phy->features & 184 (SUPPORTED_1000baseT_Full | SUPPORTED_1000baseT_Half)) { 185 int adv = phy_read(phy, MII_CTRL1000); 186 glpa = phy_read(phy, MII_STAT1000); 187 188 if (glpa < 0 || adv < 0) 189 return adv; 190 191 glpa &= adv << 2; 192 } 193 194 phy->speed = SPEED_10; 195 phy->duplex = DUPLEX_HALF; 196 phy->pause = phy->asym_pause = 0; 197 198 if (glpa & (LPA_1000FULL | LPA_1000HALF)) { 199 phy->speed = SPEED_1000; 200 if (glpa & LPA_1000FULL) 201 phy->duplex = DUPLEX_FULL; 202 } else if (lpa & (LPA_100FULL | LPA_100HALF)) { 203 phy->speed = SPEED_100; 204 if (lpa & LPA_100FULL) 205 phy->duplex = DUPLEX_FULL; 206 } else if (lpa & LPA_10FULL) 207 phy->duplex = DUPLEX_FULL; 208 209 if (phy->duplex == DUPLEX_FULL) { 210 phy->pause = lpa & LPA_PAUSE_CAP ? 1 : 0; 211 phy->asym_pause = lpa & LPA_PAUSE_ASYM ? 1 : 0; 212 } 213 } else { 214 int bmcr = phy_read(phy, MII_BMCR); 215 if (bmcr < 0) 216 return bmcr; 217 218 if (bmcr & BMCR_FULLDPLX) 219 phy->duplex = DUPLEX_FULL; 220 else 221 phy->duplex = DUPLEX_HALF; 222 if (bmcr & BMCR_SPEED1000) 223 phy->speed = SPEED_1000; 224 else if (bmcr & BMCR_SPEED100) 225 phy->speed = SPEED_100; 226 else 227 phy->speed = SPEED_10; 228 229 phy->pause = phy->asym_pause = 0; 230 } 231 return 0; 232} 233 234/* Generic implementation for most 10/100/1000 PHYs */ 235static struct mii_phy_ops generic_phy_ops = { 236 .setup_aneg = genmii_setup_aneg, 237 .setup_forced = genmii_setup_forced, 238 .poll_link = genmii_poll_link, 239 .read_link = genmii_read_link 240}; 241 242static struct mii_phy_def genmii_phy_def = { 243 .phy_id = 0x00000000, 244 .phy_id_mask = 0x00000000, 245 .name = "Generic MII", 246 .ops = &generic_phy_ops 247}; 248 249/* CIS8201 */ 250#define MII_CIS8201_10BTCSR 0x16 251#define TENBTCSR_ECHO_DISABLE 0x2000 252#define MII_CIS8201_EPCR 0x17 253#define EPCR_MODE_MASK 0x3000 254#define EPCR_GMII_MODE 0x0000 255#define EPCR_RGMII_MODE 0x1000 256#define EPCR_TBI_MODE 0x2000 257#define EPCR_RTBI_MODE 0x3000 258#define MII_CIS8201_ACSR 0x1c 259#define ACSR_PIN_PRIO_SELECT 0x0004 260 261static int cis8201_init(struct mii_phy *phy) 262{ 263 int epcr; 264 265 epcr = phy_read(phy, MII_CIS8201_EPCR); 266 if (epcr < 0) 267 return epcr; 268 269 epcr &= ~EPCR_MODE_MASK; 270 271 switch (phy->mode) { 272 case PHY_MODE_TBI: 273 epcr |= EPCR_TBI_MODE; 274 break; 275 case PHY_MODE_RTBI: 276 epcr |= EPCR_RTBI_MODE; 277 break; 278 case PHY_MODE_GMII: 279 epcr |= EPCR_GMII_MODE; 280 break; 281 case PHY_MODE_RGMII: 282 default: 283 epcr |= EPCR_RGMII_MODE; 284 } 285 286 phy_write(phy, MII_CIS8201_EPCR, epcr); 287 288 /* MII regs override strap pins */ 289 phy_write(phy, MII_CIS8201_ACSR, 290 phy_read(phy, MII_CIS8201_ACSR) | ACSR_PIN_PRIO_SELECT); 291 292 /* Disable TX_EN -> CRS echo mode, otherwise 10/HDX doesn't work */ 293 phy_write(phy, MII_CIS8201_10BTCSR, 294 phy_read(phy, MII_CIS8201_10BTCSR) | TENBTCSR_ECHO_DISABLE); 295 296 return 0; 297} 298 299static struct mii_phy_ops cis8201_phy_ops = { 300 .init = cis8201_init, 301 .setup_aneg = genmii_setup_aneg, 302 .setup_forced = genmii_setup_forced, 303 .poll_link = genmii_poll_link, 304 .read_link = genmii_read_link 305}; 306 307static struct mii_phy_def cis8201_phy_def = { 308 .phy_id = 0x000fc410, 309 .phy_id_mask = 0x000ffff0, 310 .name = "CIS8201 Gigabit Ethernet", 311 .ops = &cis8201_phy_ops 312}; 313 314static struct mii_phy_def bcm5248_phy_def = { 315 316 .phy_id = 0x0143bc00, 317 .phy_id_mask = 0x0ffffff0, 318 .name = "BCM5248 10/100 SMII Ethernet", 319 .ops = &generic_phy_ops 320}; 321 322static int m88e1111_init(struct mii_phy *phy) 323{ 324 pr_debug("%s: Marvell 88E1111 Ethernet\n", __FUNCTION__); 325 phy_write(phy, 0x14, 0x0ce3); 326 phy_write(phy, 0x18, 0x4101); 327 phy_write(phy, 0x09, 0x0e00); 328 phy_write(phy, 0x04, 0x01e1); 329 phy_write(phy, 0x00, 0x9140); 330 phy_write(phy, 0x00, 0x1140); 331 332 return 0; 333} 334 335static int et1011c_init(struct mii_phy *phy) 336{ 337 u16 reg_short; 338 339 reg_short = (u16)(phy_read(phy, 0x16)); 340 reg_short &= ~(0x7); 341 reg_short |= 0x6; /* RGMII Trace Delay*/ 342 phy_write(phy, 0x16, reg_short); 343 344 reg_short = (u16)(phy_read(phy, 0x17)); 345 reg_short &= ~(0x40); 346 phy_write(phy, 0x17, reg_short); 347 348 phy_write(phy, 0x1c, 0x74f0); 349 return 0; 350} 351 352static struct mii_phy_ops et1011c_phy_ops = { 353 .init = et1011c_init, 354 .setup_aneg = genmii_setup_aneg, 355 .setup_forced = genmii_setup_forced, 356 .poll_link = genmii_poll_link, 357 .read_link = genmii_read_link 358}; 359 360static struct mii_phy_def et1011c_phy_def = { 361 .phy_id = 0x0282f000, 362 .phy_id_mask = 0x0fffff00, 363 .name = "ET1011C Gigabit Ethernet", 364 .ops = &et1011c_phy_ops 365}; 366 367 368 369 370 371static struct mii_phy_ops m88e1111_phy_ops = { 372 .init = m88e1111_init, 373 .setup_aneg = genmii_setup_aneg, 374 .setup_forced = genmii_setup_forced, 375 .poll_link = genmii_poll_link, 376 .read_link = genmii_read_link 377}; 378 379static struct mii_phy_def m88e1111_phy_def = { 380 381 .phy_id = 0x01410CC0, 382 .phy_id_mask = 0x0ffffff0, 383 .name = "Marvell 88E1111 Ethernet", 384 .ops = &m88e1111_phy_ops, 385}; 386 387static struct mii_phy_def *mii_phy_table[] = { 388 &et1011c_phy_def, 389 &cis8201_phy_def, 390 &bcm5248_phy_def, 391 &m88e1111_phy_def, 392 &genmii_phy_def, 393 NULL 394}; 395 396int emac_mii_phy_probe(struct mii_phy *phy, int address) 397{ 398 struct mii_phy_def *def; 399 int i; 400 u32 id; 401 402 phy->autoneg = AUTONEG_DISABLE; 403 phy->advertising = 0; 404 phy->address = address; 405 phy->speed = SPEED_10; 406 phy->duplex = DUPLEX_HALF; 407 phy->pause = phy->asym_pause = 0; 408 409 /* Take PHY out of isolate mode and reset it. */ 410 if (emac_mii_reset_phy(phy)) 411 return -ENODEV; 412 413 /* Read ID and find matching entry */ 414 id = (phy_read(phy, MII_PHYSID1) << 16) | phy_read(phy, MII_PHYSID2); 415 for (i = 0; (def = mii_phy_table[i]) != NULL; i++) 416 if ((id & def->phy_id_mask) == def->phy_id) 417 break; 418 /* Should never be NULL (we have a generic entry), but... */ 419 if (!def) 420 return -ENODEV; 421 422 phy->def = def; 423 424 /* Determine PHY features if needed */ 425 phy->features = def->features; 426 if (!phy->features) { 427 u16 bmsr = phy_read(phy, MII_BMSR); 428 if (bmsr & BMSR_ANEGCAPABLE) 429 phy->features |= SUPPORTED_Autoneg; 430 if (bmsr & BMSR_10HALF) 431 phy->features |= SUPPORTED_10baseT_Half; 432 if (bmsr & BMSR_10FULL) 433 phy->features |= SUPPORTED_10baseT_Full; 434 if (bmsr & BMSR_100HALF) 435 phy->features |= SUPPORTED_100baseT_Half; 436 if (bmsr & BMSR_100FULL) 437 phy->features |= SUPPORTED_100baseT_Full; 438 if (bmsr & BMSR_ESTATEN) { 439 u16 esr = phy_read(phy, MII_ESTATUS); 440 if (esr & ESTATUS_1000_TFULL) 441 phy->features |= SUPPORTED_1000baseT_Full; 442 if (esr & ESTATUS_1000_THALF) 443 phy->features |= SUPPORTED_1000baseT_Half; 444 } 445 phy->features |= SUPPORTED_MII; 446 } 447 448 /* Setup default advertising */ 449 phy->advertising = phy->features; 450 451 return 0; 452} 453 454MODULE_LICENSE("GPL");