0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023 #include <linux/module.h>
0024
0025 #include <linux/kernel.h>
0026 #include <linux/types.h>
0027 #include <linux/netdevice.h>
0028 #include <linux/etherdevice.h>
0029 #include <linux/mii.h>
0030 #include <linux/ethtool.h>
0031 #include <linux/delay.h>
0032 #include <linux/of.h>
0033 #include <linux/sungem_phy.h>
0034
0035
0036 static const int phy_BCM5400_link_table[8][3] = {
0037 { 0, 0, 0 },
0038 { 0, 0, 0 },
0039 { 1, 0, 0 },
0040 { 0, 1, 0 },
0041 { 0, 1, 0 },
0042 { 1, 1, 0 },
0043 { 1, 0, 1 },
0044 { 1, 0, 1 },
0045 };
0046
0047 static inline int __sungem_phy_read(struct mii_phy* phy, int id, int reg)
0048 {
0049 return phy->mdio_read(phy->dev, id, reg);
0050 }
0051
0052 static inline void __sungem_phy_write(struct mii_phy* phy, int id, int reg, int val)
0053 {
0054 phy->mdio_write(phy->dev, id, reg, val);
0055 }
0056
0057 static inline int sungem_phy_read(struct mii_phy* phy, int reg)
0058 {
0059 return phy->mdio_read(phy->dev, phy->mii_id, reg);
0060 }
0061
0062 static inline void sungem_phy_write(struct mii_phy* phy, int reg, int val)
0063 {
0064 phy->mdio_write(phy->dev, phy->mii_id, reg, val);
0065 }
0066
0067 static int reset_one_mii_phy(struct mii_phy* phy, int phy_id)
0068 {
0069 u16 val;
0070 int limit = 10000;
0071
0072 val = __sungem_phy_read(phy, phy_id, MII_BMCR);
0073 val &= ~(BMCR_ISOLATE | BMCR_PDOWN);
0074 val |= BMCR_RESET;
0075 __sungem_phy_write(phy, phy_id, MII_BMCR, val);
0076
0077 udelay(100);
0078
0079 while (--limit) {
0080 val = __sungem_phy_read(phy, phy_id, MII_BMCR);
0081 if ((val & BMCR_RESET) == 0)
0082 break;
0083 udelay(10);
0084 }
0085 if ((val & BMCR_ISOLATE) && limit > 0)
0086 __sungem_phy_write(phy, phy_id, MII_BMCR, val & ~BMCR_ISOLATE);
0087
0088 return limit <= 0;
0089 }
0090
0091 static int bcm5201_init(struct mii_phy* phy)
0092 {
0093 u16 data;
0094
0095 data = sungem_phy_read(phy, MII_BCM5201_MULTIPHY);
0096 data &= ~MII_BCM5201_MULTIPHY_SUPERISOLATE;
0097 sungem_phy_write(phy, MII_BCM5201_MULTIPHY, data);
0098
0099 sungem_phy_write(phy, MII_BCM5201_INTERRUPT, 0);
0100
0101 return 0;
0102 }
0103
0104 static int bcm5201_suspend(struct mii_phy* phy)
0105 {
0106 sungem_phy_write(phy, MII_BCM5201_INTERRUPT, 0);
0107 sungem_phy_write(phy, MII_BCM5201_MULTIPHY, MII_BCM5201_MULTIPHY_SUPERISOLATE);
0108
0109 return 0;
0110 }
0111
0112 static int bcm5221_init(struct mii_phy* phy)
0113 {
0114 u16 data;
0115
0116 data = sungem_phy_read(phy, MII_BCM5221_TEST);
0117 sungem_phy_write(phy, MII_BCM5221_TEST,
0118 data | MII_BCM5221_TEST_ENABLE_SHADOWS);
0119
0120 data = sungem_phy_read(phy, MII_BCM5221_SHDOW_AUX_STAT2);
0121 sungem_phy_write(phy, MII_BCM5221_SHDOW_AUX_STAT2,
0122 data | MII_BCM5221_SHDOW_AUX_STAT2_APD);
0123
0124 data = sungem_phy_read(phy, MII_BCM5221_SHDOW_AUX_MODE4);
0125 sungem_phy_write(phy, MII_BCM5221_SHDOW_AUX_MODE4,
0126 data | MII_BCM5221_SHDOW_AUX_MODE4_CLKLOPWR);
0127
0128 data = sungem_phy_read(phy, MII_BCM5221_TEST);
0129 sungem_phy_write(phy, MII_BCM5221_TEST,
0130 data & ~MII_BCM5221_TEST_ENABLE_SHADOWS);
0131
0132 return 0;
0133 }
0134
0135 static int bcm5221_suspend(struct mii_phy* phy)
0136 {
0137 u16 data;
0138
0139 data = sungem_phy_read(phy, MII_BCM5221_TEST);
0140 sungem_phy_write(phy, MII_BCM5221_TEST,
0141 data | MII_BCM5221_TEST_ENABLE_SHADOWS);
0142
0143 data = sungem_phy_read(phy, MII_BCM5221_SHDOW_AUX_MODE4);
0144 sungem_phy_write(phy, MII_BCM5221_SHDOW_AUX_MODE4,
0145 data | MII_BCM5221_SHDOW_AUX_MODE4_IDDQMODE);
0146
0147 return 0;
0148 }
0149
0150 static int bcm5241_init(struct mii_phy* phy)
0151 {
0152 u16 data;
0153
0154 data = sungem_phy_read(phy, MII_BCM5221_TEST);
0155 sungem_phy_write(phy, MII_BCM5221_TEST,
0156 data | MII_BCM5221_TEST_ENABLE_SHADOWS);
0157
0158 data = sungem_phy_read(phy, MII_BCM5221_SHDOW_AUX_STAT2);
0159 sungem_phy_write(phy, MII_BCM5221_SHDOW_AUX_STAT2,
0160 data | MII_BCM5221_SHDOW_AUX_STAT2_APD);
0161
0162 data = sungem_phy_read(phy, MII_BCM5221_SHDOW_AUX_MODE4);
0163 sungem_phy_write(phy, MII_BCM5221_SHDOW_AUX_MODE4,
0164 data & ~MII_BCM5241_SHDOW_AUX_MODE4_STANDBYPWR);
0165
0166 data = sungem_phy_read(phy, MII_BCM5221_TEST);
0167 sungem_phy_write(phy, MII_BCM5221_TEST,
0168 data & ~MII_BCM5221_TEST_ENABLE_SHADOWS);
0169
0170 return 0;
0171 }
0172
0173 static int bcm5241_suspend(struct mii_phy* phy)
0174 {
0175 u16 data;
0176
0177 data = sungem_phy_read(phy, MII_BCM5221_TEST);
0178 sungem_phy_write(phy, MII_BCM5221_TEST,
0179 data | MII_BCM5221_TEST_ENABLE_SHADOWS);
0180
0181 data = sungem_phy_read(phy, MII_BCM5221_SHDOW_AUX_MODE4);
0182 sungem_phy_write(phy, MII_BCM5221_SHDOW_AUX_MODE4,
0183 data | MII_BCM5241_SHDOW_AUX_MODE4_STANDBYPWR);
0184
0185 return 0;
0186 }
0187
0188 static int bcm5400_init(struct mii_phy* phy)
0189 {
0190 u16 data;
0191
0192
0193 data = sungem_phy_read(phy, MII_BCM5400_AUXCONTROL);
0194 data |= MII_BCM5400_AUXCONTROL_PWR10BASET;
0195 sungem_phy_write(phy, MII_BCM5400_AUXCONTROL, data);
0196
0197 data = sungem_phy_read(phy, MII_BCM5400_GB_CONTROL);
0198 data |= MII_BCM5400_GB_CONTROL_FULLDUPLEXCAP;
0199 sungem_phy_write(phy, MII_BCM5400_GB_CONTROL, data);
0200
0201 udelay(100);
0202
0203
0204 (void)reset_one_mii_phy(phy, 0x1f);
0205
0206 data = __sungem_phy_read(phy, 0x1f, MII_BCM5201_MULTIPHY);
0207 data |= MII_BCM5201_MULTIPHY_SERIALMODE;
0208 __sungem_phy_write(phy, 0x1f, MII_BCM5201_MULTIPHY, data);
0209
0210 data = sungem_phy_read(phy, MII_BCM5400_AUXCONTROL);
0211 data &= ~MII_BCM5400_AUXCONTROL_PWR10BASET;
0212 sungem_phy_write(phy, MII_BCM5400_AUXCONTROL, data);
0213
0214 return 0;
0215 }
0216
0217 static int bcm5400_suspend(struct mii_phy* phy)
0218 {
0219 #if 0
0220 sungem_phy_write(phy, MII_BMCR, BMCR_PDOWN);
0221 #endif
0222 return 0;
0223 }
0224
0225 static int bcm5401_init(struct mii_phy* phy)
0226 {
0227 u16 data;
0228 int rev;
0229
0230 rev = sungem_phy_read(phy, MII_PHYSID2) & 0x000f;
0231 if (rev == 0 || rev == 3) {
0232
0233
0234
0235
0236
0237
0238
0239
0240
0241
0242
0243 sungem_phy_write(phy, 0x18, 0x0c20);
0244 sungem_phy_write(phy, 0x17, 0x0012);
0245 sungem_phy_write(phy, 0x15, 0x1804);
0246 sungem_phy_write(phy, 0x17, 0x0013);
0247 sungem_phy_write(phy, 0x15, 0x1204);
0248 sungem_phy_write(phy, 0x17, 0x8006);
0249 sungem_phy_write(phy, 0x15, 0x0132);
0250 sungem_phy_write(phy, 0x17, 0x8006);
0251 sungem_phy_write(phy, 0x15, 0x0232);
0252 sungem_phy_write(phy, 0x17, 0x201f);
0253 sungem_phy_write(phy, 0x15, 0x0a20);
0254 }
0255
0256
0257 data = sungem_phy_read(phy, MII_BCM5400_GB_CONTROL);
0258 data |= MII_BCM5400_GB_CONTROL_FULLDUPLEXCAP;
0259 sungem_phy_write(phy, MII_BCM5400_GB_CONTROL, data);
0260
0261 udelay(10);
0262
0263
0264 (void)reset_one_mii_phy(phy, 0x1f);
0265
0266 data = __sungem_phy_read(phy, 0x1f, MII_BCM5201_MULTIPHY);
0267 data |= MII_BCM5201_MULTIPHY_SERIALMODE;
0268 __sungem_phy_write(phy, 0x1f, MII_BCM5201_MULTIPHY, data);
0269
0270 return 0;
0271 }
0272
0273 static int bcm5401_suspend(struct mii_phy* phy)
0274 {
0275 #if 0
0276 sungem_phy_write(phy, MII_BMCR, BMCR_PDOWN);
0277 #endif
0278 return 0;
0279 }
0280
0281 static int bcm5411_init(struct mii_phy* phy)
0282 {
0283 u16 data;
0284
0285
0286
0287
0288 sungem_phy_write(phy, 0x1c, 0x8c23);
0289 sungem_phy_write(phy, 0x1c, 0x8ca3);
0290 sungem_phy_write(phy, 0x1c, 0x8c23);
0291
0292
0293
0294
0295 sungem_phy_write(phy, MII_BMCR, BMCR_RESET);
0296 sungem_phy_write(phy, MII_BMCR, 0x1340);
0297
0298 data = sungem_phy_read(phy, MII_BCM5400_GB_CONTROL);
0299 data |= MII_BCM5400_GB_CONTROL_FULLDUPLEXCAP;
0300 sungem_phy_write(phy, MII_BCM5400_GB_CONTROL, data);
0301
0302 udelay(10);
0303
0304
0305 (void)reset_one_mii_phy(phy, 0x1f);
0306
0307 return 0;
0308 }
0309
0310 static int genmii_setup_aneg(struct mii_phy *phy, u32 advertise)
0311 {
0312 u16 ctl, adv;
0313
0314 phy->autoneg = 1;
0315 phy->speed = SPEED_10;
0316 phy->duplex = DUPLEX_HALF;
0317 phy->pause = 0;
0318 phy->advertising = advertise;
0319
0320
0321 adv = sungem_phy_read(phy, MII_ADVERTISE);
0322 adv &= ~(ADVERTISE_ALL | ADVERTISE_100BASE4);
0323 if (advertise & ADVERTISED_10baseT_Half)
0324 adv |= ADVERTISE_10HALF;
0325 if (advertise & ADVERTISED_10baseT_Full)
0326 adv |= ADVERTISE_10FULL;
0327 if (advertise & ADVERTISED_100baseT_Half)
0328 adv |= ADVERTISE_100HALF;
0329 if (advertise & ADVERTISED_100baseT_Full)
0330 adv |= ADVERTISE_100FULL;
0331 sungem_phy_write(phy, MII_ADVERTISE, adv);
0332
0333
0334 ctl = sungem_phy_read(phy, MII_BMCR);
0335 ctl |= (BMCR_ANENABLE | BMCR_ANRESTART);
0336 sungem_phy_write(phy, MII_BMCR, ctl);
0337
0338 return 0;
0339 }
0340
0341 static int genmii_setup_forced(struct mii_phy *phy, int speed, int fd)
0342 {
0343 u16 ctl;
0344
0345 phy->autoneg = 0;
0346 phy->speed = speed;
0347 phy->duplex = fd;
0348 phy->pause = 0;
0349
0350 ctl = sungem_phy_read(phy, MII_BMCR);
0351 ctl &= ~(BMCR_FULLDPLX|BMCR_SPEED100|BMCR_ANENABLE);
0352
0353
0354 sungem_phy_write(phy, MII_BMCR, ctl | BMCR_RESET);
0355
0356
0357 switch(speed) {
0358 case SPEED_10:
0359 break;
0360 case SPEED_100:
0361 ctl |= BMCR_SPEED100;
0362 break;
0363 case SPEED_1000:
0364 default:
0365 return -EINVAL;
0366 }
0367 if (fd == DUPLEX_FULL)
0368 ctl |= BMCR_FULLDPLX;
0369 sungem_phy_write(phy, MII_BMCR, ctl);
0370
0371 return 0;
0372 }
0373
0374 static int genmii_poll_link(struct mii_phy *phy)
0375 {
0376 u16 status;
0377
0378 (void)sungem_phy_read(phy, MII_BMSR);
0379 status = sungem_phy_read(phy, MII_BMSR);
0380 if ((status & BMSR_LSTATUS) == 0)
0381 return 0;
0382 if (phy->autoneg && !(status & BMSR_ANEGCOMPLETE))
0383 return 0;
0384 return 1;
0385 }
0386
0387 static int genmii_read_link(struct mii_phy *phy)
0388 {
0389 u16 lpa;
0390
0391 if (phy->autoneg) {
0392 lpa = sungem_phy_read(phy, MII_LPA);
0393
0394 if (lpa & (LPA_10FULL | LPA_100FULL))
0395 phy->duplex = DUPLEX_FULL;
0396 else
0397 phy->duplex = DUPLEX_HALF;
0398 if (lpa & (LPA_100FULL | LPA_100HALF))
0399 phy->speed = SPEED_100;
0400 else
0401 phy->speed = SPEED_10;
0402 phy->pause = 0;
0403 }
0404
0405
0406
0407
0408 return 0;
0409 }
0410
0411 static int generic_suspend(struct mii_phy* phy)
0412 {
0413 sungem_phy_write(phy, MII_BMCR, BMCR_PDOWN);
0414
0415 return 0;
0416 }
0417
0418 static int bcm5421_init(struct mii_phy* phy)
0419 {
0420 u16 data;
0421 unsigned int id;
0422
0423 id = (sungem_phy_read(phy, MII_PHYSID1) << 16 | sungem_phy_read(phy, MII_PHYSID2));
0424
0425
0426 if (id == 0x002060e0) {
0427
0428
0429 sungem_phy_write(phy, 0x18, 0x1007);
0430 data = sungem_phy_read(phy, 0x18);
0431 sungem_phy_write(phy, 0x18, data | 0x0400);
0432 sungem_phy_write(phy, 0x18, 0x0007);
0433 data = sungem_phy_read(phy, 0x18);
0434 sungem_phy_write(phy, 0x18, data | 0x0800);
0435 sungem_phy_write(phy, 0x17, 0x000a);
0436 data = sungem_phy_read(phy, 0x15);
0437 sungem_phy_write(phy, 0x15, data | 0x0200);
0438 }
0439
0440
0441 if ((id & 0xfffffff0) == 0x002062e0) {
0442 sungem_phy_write(phy, 4, 0x01e1);
0443 sungem_phy_write(phy, 9, 0x0300);
0444 }
0445
0446
0447 #ifdef CONFIG_PPC_PMAC
0448 if (phy->platform_data) {
0449 struct device_node *np = of_get_parent(phy->platform_data);
0450 int can_low_power = 1;
0451 if (np == NULL || of_get_property(np, "no-autolowpower", NULL))
0452 can_low_power = 0;
0453 of_node_put(np);
0454 if (can_low_power) {
0455
0456 sungem_phy_write(phy, 0x1c, 0x9002);
0457 sungem_phy_write(phy, 0x1c, 0xa821);
0458 sungem_phy_write(phy, 0x1c, 0x941d);
0459 }
0460 }
0461 #endif
0462
0463 return 0;
0464 }
0465
0466 static int bcm54xx_setup_aneg(struct mii_phy *phy, u32 advertise)
0467 {
0468 u16 ctl, adv;
0469
0470 phy->autoneg = 1;
0471 phy->speed = SPEED_10;
0472 phy->duplex = DUPLEX_HALF;
0473 phy->pause = 0;
0474 phy->advertising = advertise;
0475
0476
0477 adv = sungem_phy_read(phy, MII_ADVERTISE);
0478 adv &= ~(ADVERTISE_ALL | ADVERTISE_100BASE4);
0479 if (advertise & ADVERTISED_10baseT_Half)
0480 adv |= ADVERTISE_10HALF;
0481 if (advertise & ADVERTISED_10baseT_Full)
0482 adv |= ADVERTISE_10FULL;
0483 if (advertise & ADVERTISED_100baseT_Half)
0484 adv |= ADVERTISE_100HALF;
0485 if (advertise & ADVERTISED_100baseT_Full)
0486 adv |= ADVERTISE_100FULL;
0487 if (advertise & ADVERTISED_Pause)
0488 adv |= ADVERTISE_PAUSE_CAP;
0489 if (advertise & ADVERTISED_Asym_Pause)
0490 adv |= ADVERTISE_PAUSE_ASYM;
0491 sungem_phy_write(phy, MII_ADVERTISE, adv);
0492
0493
0494 adv = sungem_phy_read(phy, MII_1000BASETCONTROL);
0495 adv &= ~(MII_1000BASETCONTROL_FULLDUPLEXCAP|MII_1000BASETCONTROL_HALFDUPLEXCAP);
0496 if (advertise & SUPPORTED_1000baseT_Half)
0497 adv |= MII_1000BASETCONTROL_HALFDUPLEXCAP;
0498 if (advertise & SUPPORTED_1000baseT_Full)
0499 adv |= MII_1000BASETCONTROL_FULLDUPLEXCAP;
0500 sungem_phy_write(phy, MII_1000BASETCONTROL, adv);
0501
0502
0503 ctl = sungem_phy_read(phy, MII_BMCR);
0504 ctl |= (BMCR_ANENABLE | BMCR_ANRESTART);
0505 sungem_phy_write(phy, MII_BMCR, ctl);
0506
0507 return 0;
0508 }
0509
0510 static int bcm54xx_setup_forced(struct mii_phy *phy, int speed, int fd)
0511 {
0512 u16 ctl;
0513
0514 phy->autoneg = 0;
0515 phy->speed = speed;
0516 phy->duplex = fd;
0517 phy->pause = 0;
0518
0519 ctl = sungem_phy_read(phy, MII_BMCR);
0520 ctl &= ~(BMCR_FULLDPLX|BMCR_SPEED100|BMCR_SPD2|BMCR_ANENABLE);
0521
0522
0523 sungem_phy_write(phy, MII_BMCR, ctl | BMCR_RESET);
0524
0525
0526 switch(speed) {
0527 case SPEED_10:
0528 break;
0529 case SPEED_100:
0530 ctl |= BMCR_SPEED100;
0531 break;
0532 case SPEED_1000:
0533 ctl |= BMCR_SPD2;
0534 }
0535 if (fd == DUPLEX_FULL)
0536 ctl |= BMCR_FULLDPLX;
0537
0538
0539
0540 sungem_phy_write(phy, MII_BMCR, ctl);
0541
0542 return 0;
0543 }
0544
0545 static int bcm54xx_read_link(struct mii_phy *phy)
0546 {
0547 int link_mode;
0548 u16 val;
0549
0550 if (phy->autoneg) {
0551 val = sungem_phy_read(phy, MII_BCM5400_AUXSTATUS);
0552 link_mode = ((val & MII_BCM5400_AUXSTATUS_LINKMODE_MASK) >>
0553 MII_BCM5400_AUXSTATUS_LINKMODE_SHIFT);
0554 phy->duplex = phy_BCM5400_link_table[link_mode][0] ?
0555 DUPLEX_FULL : DUPLEX_HALF;
0556 phy->speed = phy_BCM5400_link_table[link_mode][2] ?
0557 SPEED_1000 :
0558 (phy_BCM5400_link_table[link_mode][1] ?
0559 SPEED_100 : SPEED_10);
0560 val = sungem_phy_read(phy, MII_LPA);
0561 phy->pause = (phy->duplex == DUPLEX_FULL) &&
0562 ((val & LPA_PAUSE) != 0);
0563 }
0564
0565
0566
0567
0568 return 0;
0569 }
0570
0571 static int marvell88e1111_init(struct mii_phy* phy)
0572 {
0573 u16 rev;
0574
0575
0576 rev = sungem_phy_read(phy, MII_PHYSID2) & 0x000f;
0577 if (rev == 0) {
0578 sungem_phy_write(phy, 0x1d, 0x000a);
0579 sungem_phy_write(phy, 0x1e, 0x0821);
0580
0581 sungem_phy_write(phy, 0x1d, 0x0006);
0582 sungem_phy_write(phy, 0x1e, 0x8600);
0583
0584 sungem_phy_write(phy, 0x1d, 0x000b);
0585 sungem_phy_write(phy, 0x1e, 0x0100);
0586
0587 sungem_phy_write(phy, 0x1d, 0x0004);
0588 sungem_phy_write(phy, 0x1e, 0x4850);
0589 }
0590 return 0;
0591 }
0592
0593 #define BCM5421_MODE_MASK (1 << 5)
0594
0595 static int bcm5421_poll_link(struct mii_phy* phy)
0596 {
0597 u32 phy_reg;
0598 int mode;
0599
0600
0601 sungem_phy_write(phy, MII_NCONFIG, 0x1000);
0602 phy_reg = sungem_phy_read(phy, MII_NCONFIG);
0603
0604 mode = (phy_reg & BCM5421_MODE_MASK) >> 5;
0605
0606 if ( mode == BCM54XX_COPPER)
0607 return genmii_poll_link(phy);
0608
0609
0610 sungem_phy_write(phy, MII_NCONFIG, 0x2000);
0611 phy_reg = sungem_phy_read(phy, MII_NCONFIG);
0612
0613 if (phy_reg & 0x0020)
0614 return 0;
0615 else
0616 return 1;
0617 }
0618
0619 static int bcm5421_read_link(struct mii_phy* phy)
0620 {
0621 u32 phy_reg;
0622 int mode;
0623
0624
0625 sungem_phy_write(phy, MII_NCONFIG, 0x1000);
0626 phy_reg = sungem_phy_read(phy, MII_NCONFIG);
0627
0628 mode = (phy_reg & BCM5421_MODE_MASK ) >> 5;
0629
0630 if ( mode == BCM54XX_COPPER)
0631 return bcm54xx_read_link(phy);
0632
0633 phy->speed = SPEED_1000;
0634
0635
0636 sungem_phy_write(phy, MII_NCONFIG, 0x2000);
0637 phy_reg = sungem_phy_read(phy, MII_NCONFIG);
0638
0639 if ( (phy_reg & 0x0080) >> 7)
0640 phy->duplex |= DUPLEX_HALF;
0641 else
0642 phy->duplex |= DUPLEX_FULL;
0643
0644 return 0;
0645 }
0646
0647 static int bcm5421_enable_fiber(struct mii_phy* phy, int autoneg)
0648 {
0649
0650 sungem_phy_write(phy, MII_NCONFIG, 0x9020);
0651
0652 sungem_phy_write(phy, MII_NCONFIG, 0x945f);
0653
0654 if (!autoneg) {
0655
0656 sungem_phy_write(phy, MII_NCONFIG, 0xfc01);
0657 sungem_phy_write(phy, 0x0b, 0x0004);
0658 }
0659
0660 phy->autoneg = autoneg;
0661
0662 return 0;
0663 }
0664
0665 #define BCM5461_FIBER_LINK (1 << 2)
0666 #define BCM5461_MODE_MASK (3 << 1)
0667
0668 static int bcm5461_poll_link(struct mii_phy* phy)
0669 {
0670 u32 phy_reg;
0671 int mode;
0672
0673
0674 sungem_phy_write(phy, MII_NCONFIG, 0x7c00);
0675 phy_reg = sungem_phy_read(phy, MII_NCONFIG);
0676
0677 mode = (phy_reg & BCM5461_MODE_MASK ) >> 1;
0678
0679 if ( mode == BCM54XX_COPPER)
0680 return genmii_poll_link(phy);
0681
0682
0683 sungem_phy_write(phy, MII_NCONFIG, 0x7000);
0684 phy_reg = sungem_phy_read(phy, MII_NCONFIG);
0685
0686 if (phy_reg & BCM5461_FIBER_LINK)
0687 return 1;
0688 else
0689 return 0;
0690 }
0691
0692 #define BCM5461_FIBER_DUPLEX (1 << 3)
0693
0694 static int bcm5461_read_link(struct mii_phy* phy)
0695 {
0696 u32 phy_reg;
0697 int mode;
0698
0699
0700 sungem_phy_write(phy, MII_NCONFIG, 0x7c00);
0701 phy_reg = sungem_phy_read(phy, MII_NCONFIG);
0702
0703 mode = (phy_reg & BCM5461_MODE_MASK ) >> 1;
0704
0705 if ( mode == BCM54XX_COPPER) {
0706 return bcm54xx_read_link(phy);
0707 }
0708
0709 phy->speed = SPEED_1000;
0710
0711
0712 sungem_phy_write(phy, MII_NCONFIG, 0x7000);
0713 phy_reg = sungem_phy_read(phy, MII_NCONFIG);
0714
0715 if (phy_reg & BCM5461_FIBER_DUPLEX)
0716 phy->duplex |= DUPLEX_FULL;
0717 else
0718 phy->duplex |= DUPLEX_HALF;
0719
0720 return 0;
0721 }
0722
0723 static int bcm5461_enable_fiber(struct mii_phy* phy, int autoneg)
0724 {
0725
0726 sungem_phy_write(phy, MII_NCONFIG, 0xfc0b);
0727
0728 if (autoneg) {
0729
0730 sungem_phy_write(phy, MII_ADVERTISE, 0x01e0);
0731 sungem_phy_write(phy, MII_BMCR, 0x1140);
0732 } else {
0733
0734 sungem_phy_write(phy, MII_BMCR, 0x0140);
0735 }
0736
0737 phy->autoneg = autoneg;
0738
0739 return 0;
0740 }
0741
0742 static int marvell_setup_aneg(struct mii_phy *phy, u32 advertise)
0743 {
0744 u16 ctl, adv;
0745
0746 phy->autoneg = 1;
0747 phy->speed = SPEED_10;
0748 phy->duplex = DUPLEX_HALF;
0749 phy->pause = 0;
0750 phy->advertising = advertise;
0751
0752
0753 adv = sungem_phy_read(phy, MII_ADVERTISE);
0754 adv &= ~(ADVERTISE_ALL | ADVERTISE_100BASE4);
0755 if (advertise & ADVERTISED_10baseT_Half)
0756 adv |= ADVERTISE_10HALF;
0757 if (advertise & ADVERTISED_10baseT_Full)
0758 adv |= ADVERTISE_10FULL;
0759 if (advertise & ADVERTISED_100baseT_Half)
0760 adv |= ADVERTISE_100HALF;
0761 if (advertise & ADVERTISED_100baseT_Full)
0762 adv |= ADVERTISE_100FULL;
0763 if (advertise & ADVERTISED_Pause)
0764 adv |= ADVERTISE_PAUSE_CAP;
0765 if (advertise & ADVERTISED_Asym_Pause)
0766 adv |= ADVERTISE_PAUSE_ASYM;
0767 sungem_phy_write(phy, MII_ADVERTISE, adv);
0768
0769
0770
0771
0772
0773
0774
0775 adv = sungem_phy_read(phy, MII_M1011_PHY_SPEC_CONTROL);
0776 adv |= MII_M1011_PHY_SPEC_CONTROL_AUTO_MDIX;
0777 adv &= ~(MII_1000BASETCONTROL_FULLDUPLEXCAP |
0778 MII_1000BASETCONTROL_HALFDUPLEXCAP);
0779 if (advertise & SUPPORTED_1000baseT_Half)
0780 adv |= MII_1000BASETCONTROL_HALFDUPLEXCAP;
0781 if (advertise & SUPPORTED_1000baseT_Full)
0782 adv |= MII_1000BASETCONTROL_FULLDUPLEXCAP;
0783 sungem_phy_write(phy, MII_1000BASETCONTROL, adv);
0784
0785
0786 ctl = sungem_phy_read(phy, MII_BMCR);
0787 ctl |= (BMCR_ANENABLE | BMCR_ANRESTART);
0788 sungem_phy_write(phy, MII_BMCR, ctl);
0789
0790 return 0;
0791 }
0792
0793 static int marvell_setup_forced(struct mii_phy *phy, int speed, int fd)
0794 {
0795 u16 ctl, ctl2;
0796
0797 phy->autoneg = 0;
0798 phy->speed = speed;
0799 phy->duplex = fd;
0800 phy->pause = 0;
0801
0802 ctl = sungem_phy_read(phy, MII_BMCR);
0803 ctl &= ~(BMCR_FULLDPLX|BMCR_SPEED100|BMCR_SPD2|BMCR_ANENABLE);
0804 ctl |= BMCR_RESET;
0805
0806
0807 switch(speed) {
0808 case SPEED_10:
0809 break;
0810 case SPEED_100:
0811 ctl |= BMCR_SPEED100;
0812 break;
0813
0814
0815
0816 case SPEED_1000:
0817 ctl |= BMCR_SPD2;
0818 }
0819 if (fd == DUPLEX_FULL)
0820 ctl |= BMCR_FULLDPLX;
0821
0822
0823
0824
0825 ctl2 = sungem_phy_read(phy, MII_M1011_PHY_SPEC_CONTROL);
0826 ctl2 &= ~(MII_M1011_PHY_SPEC_CONTROL_MANUAL_MDIX |
0827 MII_M1011_PHY_SPEC_CONTROL_AUTO_MDIX |
0828 MII_1000BASETCONTROL_FULLDUPLEXCAP |
0829 MII_1000BASETCONTROL_HALFDUPLEXCAP);
0830 if (speed == SPEED_1000)
0831 ctl2 |= (fd == DUPLEX_FULL) ?
0832 MII_1000BASETCONTROL_FULLDUPLEXCAP :
0833 MII_1000BASETCONTROL_HALFDUPLEXCAP;
0834 sungem_phy_write(phy, MII_1000BASETCONTROL, ctl2);
0835
0836
0837
0838 sungem_phy_write(phy, MII_BMCR, ctl);
0839
0840 return 0;
0841 }
0842
0843 static int marvell_read_link(struct mii_phy *phy)
0844 {
0845 u16 status, pmask;
0846
0847 if (phy->autoneg) {
0848 status = sungem_phy_read(phy, MII_M1011_PHY_SPEC_STATUS);
0849 if ((status & MII_M1011_PHY_SPEC_STATUS_RESOLVED) == 0)
0850 return -EAGAIN;
0851 if (status & MII_M1011_PHY_SPEC_STATUS_1000)
0852 phy->speed = SPEED_1000;
0853 else if (status & MII_M1011_PHY_SPEC_STATUS_100)
0854 phy->speed = SPEED_100;
0855 else
0856 phy->speed = SPEED_10;
0857 if (status & MII_M1011_PHY_SPEC_STATUS_FULLDUPLEX)
0858 phy->duplex = DUPLEX_FULL;
0859 else
0860 phy->duplex = DUPLEX_HALF;
0861 pmask = MII_M1011_PHY_SPEC_STATUS_TX_PAUSE |
0862 MII_M1011_PHY_SPEC_STATUS_RX_PAUSE;
0863 phy->pause = (status & pmask) == pmask;
0864 }
0865
0866
0867
0868
0869 return 0;
0870 }
0871
0872 #define MII_BASIC_FEATURES \
0873 (SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full | \
0874 SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full | \
0875 SUPPORTED_Autoneg | SUPPORTED_TP | SUPPORTED_MII | \
0876 SUPPORTED_Pause)
0877
0878
0879
0880
0881
0882 #define MII_GBIT_FEATURES \
0883 (MII_BASIC_FEATURES | \
0884 SUPPORTED_1000baseT_Half | SUPPORTED_1000baseT_Full)
0885
0886
0887 static const struct mii_phy_ops bcm5201_phy_ops = {
0888 .init = bcm5201_init,
0889 .suspend = bcm5201_suspend,
0890 .setup_aneg = genmii_setup_aneg,
0891 .setup_forced = genmii_setup_forced,
0892 .poll_link = genmii_poll_link,
0893 .read_link = genmii_read_link,
0894 };
0895
0896 static struct mii_phy_def bcm5201_phy_def = {
0897 .phy_id = 0x00406210,
0898 .phy_id_mask = 0xfffffff0,
0899 .name = "BCM5201",
0900 .features = MII_BASIC_FEATURES,
0901 .magic_aneg = 1,
0902 .ops = &bcm5201_phy_ops
0903 };
0904
0905
0906 static const struct mii_phy_ops bcm5221_phy_ops = {
0907 .suspend = bcm5221_suspend,
0908 .init = bcm5221_init,
0909 .setup_aneg = genmii_setup_aneg,
0910 .setup_forced = genmii_setup_forced,
0911 .poll_link = genmii_poll_link,
0912 .read_link = genmii_read_link,
0913 };
0914
0915 static struct mii_phy_def bcm5221_phy_def = {
0916 .phy_id = 0x004061e0,
0917 .phy_id_mask = 0xfffffff0,
0918 .name = "BCM5221",
0919 .features = MII_BASIC_FEATURES,
0920 .magic_aneg = 1,
0921 .ops = &bcm5221_phy_ops
0922 };
0923
0924
0925 static const struct mii_phy_ops bcm5241_phy_ops = {
0926 .suspend = bcm5241_suspend,
0927 .init = bcm5241_init,
0928 .setup_aneg = genmii_setup_aneg,
0929 .setup_forced = genmii_setup_forced,
0930 .poll_link = genmii_poll_link,
0931 .read_link = genmii_read_link,
0932 };
0933 static struct mii_phy_def bcm5241_phy_def = {
0934 .phy_id = 0x0143bc30,
0935 .phy_id_mask = 0xfffffff0,
0936 .name = "BCM5241",
0937 .features = MII_BASIC_FEATURES,
0938 .magic_aneg = 1,
0939 .ops = &bcm5241_phy_ops
0940 };
0941
0942
0943 static const struct mii_phy_ops bcm5400_phy_ops = {
0944 .init = bcm5400_init,
0945 .suspend = bcm5400_suspend,
0946 .setup_aneg = bcm54xx_setup_aneg,
0947 .setup_forced = bcm54xx_setup_forced,
0948 .poll_link = genmii_poll_link,
0949 .read_link = bcm54xx_read_link,
0950 };
0951
0952 static struct mii_phy_def bcm5400_phy_def = {
0953 .phy_id = 0x00206040,
0954 .phy_id_mask = 0xfffffff0,
0955 .name = "BCM5400",
0956 .features = MII_GBIT_FEATURES,
0957 .magic_aneg = 1,
0958 .ops = &bcm5400_phy_ops
0959 };
0960
0961
0962 static const struct mii_phy_ops bcm5401_phy_ops = {
0963 .init = bcm5401_init,
0964 .suspend = bcm5401_suspend,
0965 .setup_aneg = bcm54xx_setup_aneg,
0966 .setup_forced = bcm54xx_setup_forced,
0967 .poll_link = genmii_poll_link,
0968 .read_link = bcm54xx_read_link,
0969 };
0970
0971 static struct mii_phy_def bcm5401_phy_def = {
0972 .phy_id = 0x00206050,
0973 .phy_id_mask = 0xfffffff0,
0974 .name = "BCM5401",
0975 .features = MII_GBIT_FEATURES,
0976 .magic_aneg = 1,
0977 .ops = &bcm5401_phy_ops
0978 };
0979
0980
0981 static const struct mii_phy_ops bcm5411_phy_ops = {
0982 .init = bcm5411_init,
0983 .suspend = generic_suspend,
0984 .setup_aneg = bcm54xx_setup_aneg,
0985 .setup_forced = bcm54xx_setup_forced,
0986 .poll_link = genmii_poll_link,
0987 .read_link = bcm54xx_read_link,
0988 };
0989
0990 static struct mii_phy_def bcm5411_phy_def = {
0991 .phy_id = 0x00206070,
0992 .phy_id_mask = 0xfffffff0,
0993 .name = "BCM5411",
0994 .features = MII_GBIT_FEATURES,
0995 .magic_aneg = 1,
0996 .ops = &bcm5411_phy_ops
0997 };
0998
0999
1000 static const struct mii_phy_ops bcm5421_phy_ops = {
1001 .init = bcm5421_init,
1002 .suspend = generic_suspend,
1003 .setup_aneg = bcm54xx_setup_aneg,
1004 .setup_forced = bcm54xx_setup_forced,
1005 .poll_link = bcm5421_poll_link,
1006 .read_link = bcm5421_read_link,
1007 .enable_fiber = bcm5421_enable_fiber,
1008 };
1009
1010 static struct mii_phy_def bcm5421_phy_def = {
1011 .phy_id = 0x002060e0,
1012 .phy_id_mask = 0xfffffff0,
1013 .name = "BCM5421",
1014 .features = MII_GBIT_FEATURES,
1015 .magic_aneg = 1,
1016 .ops = &bcm5421_phy_ops
1017 };
1018
1019
1020 static const struct mii_phy_ops bcm5421k2_phy_ops = {
1021 .init = bcm5421_init,
1022 .suspend = generic_suspend,
1023 .setup_aneg = bcm54xx_setup_aneg,
1024 .setup_forced = bcm54xx_setup_forced,
1025 .poll_link = genmii_poll_link,
1026 .read_link = bcm54xx_read_link,
1027 };
1028
1029 static struct mii_phy_def bcm5421k2_phy_def = {
1030 .phy_id = 0x002062e0,
1031 .phy_id_mask = 0xfffffff0,
1032 .name = "BCM5421-K2",
1033 .features = MII_GBIT_FEATURES,
1034 .magic_aneg = 1,
1035 .ops = &bcm5421k2_phy_ops
1036 };
1037
1038 static const struct mii_phy_ops bcm5461_phy_ops = {
1039 .init = bcm5421_init,
1040 .suspend = generic_suspend,
1041 .setup_aneg = bcm54xx_setup_aneg,
1042 .setup_forced = bcm54xx_setup_forced,
1043 .poll_link = bcm5461_poll_link,
1044 .read_link = bcm5461_read_link,
1045 .enable_fiber = bcm5461_enable_fiber,
1046 };
1047
1048 static struct mii_phy_def bcm5461_phy_def = {
1049 .phy_id = 0x002060c0,
1050 .phy_id_mask = 0xfffffff0,
1051 .name = "BCM5461",
1052 .features = MII_GBIT_FEATURES,
1053 .magic_aneg = 1,
1054 .ops = &bcm5461_phy_ops
1055 };
1056
1057
1058 static const struct mii_phy_ops bcm5462V_phy_ops = {
1059 .init = bcm5421_init,
1060 .suspend = generic_suspend,
1061 .setup_aneg = bcm54xx_setup_aneg,
1062 .setup_forced = bcm54xx_setup_forced,
1063 .poll_link = genmii_poll_link,
1064 .read_link = bcm54xx_read_link,
1065 };
1066
1067 static struct mii_phy_def bcm5462V_phy_def = {
1068 .phy_id = 0x002060d0,
1069 .phy_id_mask = 0xfffffff0,
1070 .name = "BCM5462-Vesta",
1071 .features = MII_GBIT_FEATURES,
1072 .magic_aneg = 1,
1073 .ops = &bcm5462V_phy_ops
1074 };
1075
1076
1077 static const struct mii_phy_ops marvell88e1101_phy_ops = {
1078 .suspend = generic_suspend,
1079 .setup_aneg = marvell_setup_aneg,
1080 .setup_forced = marvell_setup_forced,
1081 .poll_link = genmii_poll_link,
1082 .read_link = marvell_read_link
1083 };
1084
1085 static const struct mii_phy_ops marvell88e1111_phy_ops = {
1086 .init = marvell88e1111_init,
1087 .suspend = generic_suspend,
1088 .setup_aneg = marvell_setup_aneg,
1089 .setup_forced = marvell_setup_forced,
1090 .poll_link = genmii_poll_link,
1091 .read_link = marvell_read_link
1092 };
1093
1094
1095
1096
1097 static struct mii_phy_def marvell88e1101v1_phy_def = {
1098 .phy_id = 0x01410c20,
1099 .phy_id_mask = 0xfffffff0,
1100 .name = "Marvell 88E1101v1",
1101 .features = MII_GBIT_FEATURES,
1102 .magic_aneg = 1,
1103 .ops = &marvell88e1101_phy_ops
1104 };
1105 static struct mii_phy_def marvell88e1101v2_phy_def = {
1106 .phy_id = 0x01410c60,
1107 .phy_id_mask = 0xfffffff0,
1108 .name = "Marvell 88E1101v2",
1109 .features = MII_GBIT_FEATURES,
1110 .magic_aneg = 1,
1111 .ops = &marvell88e1101_phy_ops
1112 };
1113 static struct mii_phy_def marvell88e1111_phy_def = {
1114 .phy_id = 0x01410cc0,
1115 .phy_id_mask = 0xfffffff0,
1116 .name = "Marvell 88E1111",
1117 .features = MII_GBIT_FEATURES,
1118 .magic_aneg = 1,
1119 .ops = &marvell88e1111_phy_ops
1120 };
1121
1122
1123 static const struct mii_phy_ops generic_phy_ops = {
1124 .setup_aneg = genmii_setup_aneg,
1125 .setup_forced = genmii_setup_forced,
1126 .poll_link = genmii_poll_link,
1127 .read_link = genmii_read_link
1128 };
1129
1130 static struct mii_phy_def genmii_phy_def = {
1131 .phy_id = 0x00000000,
1132 .phy_id_mask = 0x00000000,
1133 .name = "Generic MII",
1134 .features = MII_BASIC_FEATURES,
1135 .magic_aneg = 0,
1136 .ops = &generic_phy_ops
1137 };
1138
1139 static struct mii_phy_def* mii_phy_table[] = {
1140 &bcm5201_phy_def,
1141 &bcm5221_phy_def,
1142 &bcm5241_phy_def,
1143 &bcm5400_phy_def,
1144 &bcm5401_phy_def,
1145 &bcm5411_phy_def,
1146 &bcm5421_phy_def,
1147 &bcm5421k2_phy_def,
1148 &bcm5461_phy_def,
1149 &bcm5462V_phy_def,
1150 &marvell88e1101v1_phy_def,
1151 &marvell88e1101v2_phy_def,
1152 &marvell88e1111_phy_def,
1153 &genmii_phy_def,
1154 NULL
1155 };
1156
1157 int sungem_phy_probe(struct mii_phy *phy, int mii_id)
1158 {
1159 int rc;
1160 u32 id;
1161 struct mii_phy_def* def;
1162 int i;
1163
1164
1165
1166
1167 phy->mii_id = mii_id;
1168
1169
1170 rc = reset_one_mii_phy(phy, mii_id);
1171 if (rc)
1172 goto fail;
1173
1174
1175 id = (sungem_phy_read(phy, MII_PHYSID1) << 16 | sungem_phy_read(phy, MII_PHYSID2));
1176 printk(KERN_DEBUG KBUILD_MODNAME ": " "PHY ID: %x, addr: %x\n",
1177 id, mii_id);
1178 for (i=0; (def = mii_phy_table[i]) != NULL; i++)
1179 if ((id & def->phy_id_mask) == def->phy_id)
1180 break;
1181
1182 if (def == NULL)
1183 goto fail;
1184
1185 phy->def = def;
1186
1187 return 0;
1188 fail:
1189 phy->speed = 0;
1190 phy->duplex = 0;
1191 phy->pause = 0;
1192 phy->advertising = 0;
1193 return -ENODEV;
1194 }
1195
1196 EXPORT_SYMBOL(sungem_phy_probe);
1197 MODULE_LICENSE("GPL");