569 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * drivers/net/ethernet/ibm/emac/phy.c4 *5 * Driver for PowerPC 4xx on-chip ethernet controller, PHY support.6 * Borrowed from sungem_phy.c, though I only kept the generic MII7 * driver for now.8 *9 * This file should be shared with other drivers or eventually10 * merged as the "low level" part of miilib11 *12 * Copyright 2007 Benjamin Herrenschmidt, IBM Corp.13 * <benh@kernel.crashing.org>14 *15 * Based on the arch/ppc version of the driver:16 *17 * (c) 2003, Benjamin Herrenscmidt (benh@kernel.crashing.org)18 * (c) 2004-2005, Eugene Surovegin <ebs@ebshome.net>19 *20 */21#include <linux/module.h>22#include <linux/kernel.h>23#include <linux/types.h>24#include <linux/netdevice.h>25#include <linux/mii.h>26#include <linux/ethtool.h>27#include <linux/delay.h>28 29#include "emac.h"30#include "phy.h"31 32#define phy_read _phy_read33#define phy_write _phy_write34 35static inline int _phy_read(struct mii_phy *phy, int reg)36{37 return phy->mdio_read(phy->dev, phy->address, reg);38}39 40static inline void _phy_write(struct mii_phy *phy, int reg, int val)41{42 phy->mdio_write(phy->dev, phy->address, reg, val);43}44 45static inline int gpcs_phy_read(struct mii_phy *phy, int reg)46{47 return phy->mdio_read(phy->dev, phy->gpcs_address, reg);48}49 50static inline void gpcs_phy_write(struct mii_phy *phy, int reg, int val)51{52 phy->mdio_write(phy->dev, phy->gpcs_address, reg, val);53}54 55int emac_mii_reset_phy(struct mii_phy *phy)56{57 int val;58 int limit = 10000;59 60 val = phy_read(phy, MII_BMCR);61 val &= ~(BMCR_ISOLATE | BMCR_ANENABLE);62 val |= BMCR_RESET;63 phy_write(phy, MII_BMCR, val);64 65 udelay(300);66 67 while (--limit) {68 val = phy_read(phy, MII_BMCR);69 if (val >= 0 && (val & BMCR_RESET) == 0)70 break;71 udelay(10);72 }73 if ((val & BMCR_ISOLATE) && limit > 0)74 phy_write(phy, MII_BMCR, val & ~BMCR_ISOLATE);75 76 return limit <= 0;77}78 79int emac_mii_reset_gpcs(struct mii_phy *phy)80{81 int val;82 int limit = 10000;83 84 val = gpcs_phy_read(phy, MII_BMCR);85 val &= ~(BMCR_ISOLATE | BMCR_ANENABLE);86 val |= BMCR_RESET;87 gpcs_phy_write(phy, MII_BMCR, val);88 89 udelay(300);90 91 while (--limit) {92 val = gpcs_phy_read(phy, MII_BMCR);93 if (val >= 0 && (val & BMCR_RESET) == 0)94 break;95 udelay(10);96 }97 if ((val & BMCR_ISOLATE) && limit > 0)98 gpcs_phy_write(phy, MII_BMCR, val & ~BMCR_ISOLATE);99 100 if (limit > 0 && phy->mode == PHY_INTERFACE_MODE_SGMII) {101 /* Configure GPCS interface to recommended setting for SGMII */102 gpcs_phy_write(phy, 0x04, 0x8120); /* AsymPause, FDX */103 gpcs_phy_write(phy, 0x07, 0x2801); /* msg_pg, toggle */104 gpcs_phy_write(phy, 0x00, 0x0140); /* 1Gbps, FDX */105 }106 107 return limit <= 0;108}109 110static int genmii_setup_aneg(struct mii_phy *phy, u32 advertise)111{112 int ctl, adv;113 114 phy->autoneg = AUTONEG_ENABLE;115 phy->speed = SPEED_10;116 phy->duplex = DUPLEX_HALF;117 phy->pause = phy->asym_pause = 0;118 phy->advertising = advertise;119 120 ctl = phy_read(phy, MII_BMCR);121 if (ctl < 0)122 return ctl;123 ctl &= ~(BMCR_FULLDPLX | BMCR_SPEED100 | BMCR_SPEED1000 | BMCR_ANENABLE);124 125 /* First clear the PHY */126 phy_write(phy, MII_BMCR, ctl);127 128 /* Setup standard advertise */129 adv = phy_read(phy, MII_ADVERTISE);130 if (adv < 0)131 return adv;132 adv &= ~(ADVERTISE_ALL | ADVERTISE_100BASE4 | ADVERTISE_PAUSE_CAP |133 ADVERTISE_PAUSE_ASYM);134 if (advertise & ADVERTISED_10baseT_Half)135 adv |= ADVERTISE_10HALF;136 if (advertise & ADVERTISED_10baseT_Full)137 adv |= ADVERTISE_10FULL;138 if (advertise & ADVERTISED_100baseT_Half)139 adv |= ADVERTISE_100HALF;140 if (advertise & ADVERTISED_100baseT_Full)141 adv |= ADVERTISE_100FULL;142 if (advertise & ADVERTISED_Pause)143 adv |= ADVERTISE_PAUSE_CAP;144 if (advertise & ADVERTISED_Asym_Pause)145 adv |= ADVERTISE_PAUSE_ASYM;146 phy_write(phy, MII_ADVERTISE, adv);147 148 if (phy->features &149 (SUPPORTED_1000baseT_Full | SUPPORTED_1000baseT_Half)) {150 adv = phy_read(phy, MII_CTRL1000);151 if (adv < 0)152 return adv;153 adv &= ~(ADVERTISE_1000FULL | ADVERTISE_1000HALF);154 if (advertise & ADVERTISED_1000baseT_Full)155 adv |= ADVERTISE_1000FULL;156 if (advertise & ADVERTISED_1000baseT_Half)157 adv |= ADVERTISE_1000HALF;158 phy_write(phy, MII_CTRL1000, adv);159 }160 161 /* Start/Restart aneg */162 ctl = phy_read(phy, MII_BMCR);163 ctl |= (BMCR_ANENABLE | BMCR_ANRESTART);164 phy_write(phy, MII_BMCR, ctl);165 166 return 0;167}168 169static int genmii_setup_forced(struct mii_phy *phy, int speed, int fd)170{171 int ctl;172 173 phy->autoneg = AUTONEG_DISABLE;174 phy->speed = speed;175 phy->duplex = fd;176 phy->pause = phy->asym_pause = 0;177 178 ctl = phy_read(phy, MII_BMCR);179 if (ctl < 0)180 return ctl;181 ctl &= ~(BMCR_FULLDPLX | BMCR_SPEED100 | BMCR_SPEED1000 | BMCR_ANENABLE);182 183 /* First clear the PHY */184 phy_write(phy, MII_BMCR, ctl | BMCR_RESET);185 186 /* Select speed & duplex */187 switch (speed) {188 case SPEED_10:189 break;190 case SPEED_100:191 ctl |= BMCR_SPEED100;192 break;193 case SPEED_1000:194 ctl |= BMCR_SPEED1000;195 break;196 default:197 return -EINVAL;198 }199 if (fd == DUPLEX_FULL)200 ctl |= BMCR_FULLDPLX;201 phy_write(phy, MII_BMCR, ctl);202 203 return 0;204}205 206static int genmii_poll_link(struct mii_phy *phy)207{208 int status;209 210 /* Clear latched value with dummy read */211 phy_read(phy, MII_BMSR);212 status = phy_read(phy, MII_BMSR);213 if (status < 0 || (status & BMSR_LSTATUS) == 0)214 return 0;215 if (phy->autoneg == AUTONEG_ENABLE && !(status & BMSR_ANEGCOMPLETE))216 return 0;217 return 1;218}219 220static int genmii_read_link(struct mii_phy *phy)221{222 if (phy->autoneg == AUTONEG_ENABLE) {223 int glpa = 0;224 int lpa = phy_read(phy, MII_LPA) & phy_read(phy, MII_ADVERTISE);225 if (lpa < 0)226 return lpa;227 228 if (phy->features &229 (SUPPORTED_1000baseT_Full | SUPPORTED_1000baseT_Half)) {230 int adv = phy_read(phy, MII_CTRL1000);231 glpa = phy_read(phy, MII_STAT1000);232 233 if (glpa < 0 || adv < 0)234 return adv;235 236 glpa &= adv << 2;237 }238 239 phy->speed = SPEED_10;240 phy->duplex = DUPLEX_HALF;241 phy->pause = phy->asym_pause = 0;242 243 if (glpa & (LPA_1000FULL | LPA_1000HALF)) {244 phy->speed = SPEED_1000;245 if (glpa & LPA_1000FULL)246 phy->duplex = DUPLEX_FULL;247 } else if (lpa & (LPA_100FULL | LPA_100HALF)) {248 phy->speed = SPEED_100;249 if (lpa & LPA_100FULL)250 phy->duplex = DUPLEX_FULL;251 } else if (lpa & LPA_10FULL)252 phy->duplex = DUPLEX_FULL;253 254 if (phy->duplex == DUPLEX_FULL) {255 phy->pause = lpa & LPA_PAUSE_CAP ? 1 : 0;256 phy->asym_pause = lpa & LPA_PAUSE_ASYM ? 1 : 0;257 }258 } else {259 int bmcr = phy_read(phy, MII_BMCR);260 if (bmcr < 0)261 return bmcr;262 263 if (bmcr & BMCR_FULLDPLX)264 phy->duplex = DUPLEX_FULL;265 else266 phy->duplex = DUPLEX_HALF;267 if (bmcr & BMCR_SPEED1000)268 phy->speed = SPEED_1000;269 else if (bmcr & BMCR_SPEED100)270 phy->speed = SPEED_100;271 else272 phy->speed = SPEED_10;273 274 phy->pause = phy->asym_pause = 0;275 }276 return 0;277}278 279/* Generic implementation for most 10/100/1000 PHYs */280static const struct mii_phy_ops generic_phy_ops = {281 .setup_aneg = genmii_setup_aneg,282 .setup_forced = genmii_setup_forced,283 .poll_link = genmii_poll_link,284 .read_link = genmii_read_link285};286 287static struct mii_phy_def genmii_phy_def = {288 .phy_id = 0x00000000,289 .phy_id_mask = 0x00000000,290 .name = "Generic MII",291 .ops = &generic_phy_ops292};293 294/* CIS8201 */295#define MII_CIS8201_10BTCSR 0x16296#define TENBTCSR_ECHO_DISABLE 0x2000297#define MII_CIS8201_EPCR 0x17298#define EPCR_MODE_MASK 0x3000299#define EPCR_GMII_MODE 0x0000300#define EPCR_RGMII_MODE 0x1000301#define EPCR_TBI_MODE 0x2000302#define EPCR_RTBI_MODE 0x3000303#define MII_CIS8201_ACSR 0x1c304#define ACSR_PIN_PRIO_SELECT 0x0004305 306static int cis8201_init(struct mii_phy *phy)307{308 int epcr;309 310 epcr = phy_read(phy, MII_CIS8201_EPCR);311 if (epcr < 0)312 return epcr;313 314 epcr &= ~EPCR_MODE_MASK;315 316 switch (phy->mode) {317 case PHY_INTERFACE_MODE_TBI:318 epcr |= EPCR_TBI_MODE;319 break;320 case PHY_INTERFACE_MODE_RTBI:321 epcr |= EPCR_RTBI_MODE;322 break;323 case PHY_INTERFACE_MODE_GMII:324 epcr |= EPCR_GMII_MODE;325 break;326 case PHY_INTERFACE_MODE_RGMII:327 default:328 epcr |= EPCR_RGMII_MODE;329 }330 331 phy_write(phy, MII_CIS8201_EPCR, epcr);332 333 /* MII regs override strap pins */334 phy_write(phy, MII_CIS8201_ACSR,335 phy_read(phy, MII_CIS8201_ACSR) | ACSR_PIN_PRIO_SELECT);336 337 /* Disable TX_EN -> CRS echo mode, otherwise 10/HDX doesn't work */338 phy_write(phy, MII_CIS8201_10BTCSR,339 phy_read(phy, MII_CIS8201_10BTCSR) | TENBTCSR_ECHO_DISABLE);340 341 return 0;342}343 344static const struct mii_phy_ops cis8201_phy_ops = {345 .init = cis8201_init,346 .setup_aneg = genmii_setup_aneg,347 .setup_forced = genmii_setup_forced,348 .poll_link = genmii_poll_link,349 .read_link = genmii_read_link350};351 352static struct mii_phy_def cis8201_phy_def = {353 .phy_id = 0x000fc410,354 .phy_id_mask = 0x000ffff0,355 .name = "CIS8201 Gigabit Ethernet",356 .ops = &cis8201_phy_ops357};358 359static struct mii_phy_def bcm5248_phy_def = {360 361 .phy_id = 0x0143bc00,362 .phy_id_mask = 0x0ffffff0,363 .name = "BCM5248 10/100 SMII Ethernet",364 .ops = &generic_phy_ops365};366 367static int m88e1111_init(struct mii_phy *phy)368{369 pr_debug("%s: Marvell 88E1111 Ethernet\n", __func__);370 phy_write(phy, 0x14, 0x0ce3);371 phy_write(phy, 0x18, 0x4101);372 phy_write(phy, 0x09, 0x0e00);373 phy_write(phy, 0x04, 0x01e1);374 phy_write(phy, 0x00, 0x9140);375 phy_write(phy, 0x00, 0x1140);376 377 return 0;378}379 380static int m88e1112_init(struct mii_phy *phy)381{382 /*383 * Marvell 88E1112 PHY needs to have the SGMII MAC384 * interace (page 2) properly configured to385 * communicate with the 460EX/GT GPCS interface.386 */387 388 u16 reg_short;389 390 pr_debug("%s: Marvell 88E1112 Ethernet\n", __func__);391 392 /* Set access to Page 2 */393 phy_write(phy, 0x16, 0x0002);394 395 phy_write(phy, 0x00, 0x0040); /* 1Gbps */396 reg_short = (u16)(phy_read(phy, 0x1a));397 reg_short |= 0x8000; /* bypass Auto-Negotiation */398 phy_write(phy, 0x1a, reg_short);399 emac_mii_reset_phy(phy); /* reset MAC interface */400 401 /* Reset access to Page 0 */402 phy_write(phy, 0x16, 0x0000);403 404 return 0;405}406 407static int et1011c_init(struct mii_phy *phy)408{409 u16 reg_short;410 411 reg_short = (u16)(phy_read(phy, 0x16));412 reg_short &= ~(0x7);413 reg_short |= 0x6; /* RGMII Trace Delay*/414 phy_write(phy, 0x16, reg_short);415 416 reg_short = (u16)(phy_read(phy, 0x17));417 reg_short &= ~(0x40);418 phy_write(phy, 0x17, reg_short);419 420 phy_write(phy, 0x1c, 0x74f0);421 return 0;422}423 424static const struct mii_phy_ops et1011c_phy_ops = {425 .init = et1011c_init,426 .setup_aneg = genmii_setup_aneg,427 .setup_forced = genmii_setup_forced,428 .poll_link = genmii_poll_link,429 .read_link = genmii_read_link430};431 432static struct mii_phy_def et1011c_phy_def = {433 .phy_id = 0x0282f000,434 .phy_id_mask = 0x0fffff00,435 .name = "ET1011C Gigabit Ethernet",436 .ops = &et1011c_phy_ops437};438 439 440 441 442 443static const struct mii_phy_ops m88e1111_phy_ops = {444 .init = m88e1111_init,445 .setup_aneg = genmii_setup_aneg,446 .setup_forced = genmii_setup_forced,447 .poll_link = genmii_poll_link,448 .read_link = genmii_read_link449};450 451static struct mii_phy_def m88e1111_phy_def = {452 453 .phy_id = 0x01410CC0,454 .phy_id_mask = 0x0ffffff0,455 .name = "Marvell 88E1111 Ethernet",456 .ops = &m88e1111_phy_ops,457};458 459static const struct mii_phy_ops m88e1112_phy_ops = {460 .init = m88e1112_init,461 .setup_aneg = genmii_setup_aneg,462 .setup_forced = genmii_setup_forced,463 .poll_link = genmii_poll_link,464 .read_link = genmii_read_link465};466 467static struct mii_phy_def m88e1112_phy_def = {468 .phy_id = 0x01410C90,469 .phy_id_mask = 0x0ffffff0,470 .name = "Marvell 88E1112 Ethernet",471 .ops = &m88e1112_phy_ops,472};473 474static int ar8035_init(struct mii_phy *phy)475{476 phy_write(phy, 0x1d, 0x5); /* Address debug register 5 */477 phy_write(phy, 0x1e, 0x2d47); /* Value copied from u-boot */478 phy_write(phy, 0x1d, 0xb); /* Address hib ctrl */479 phy_write(phy, 0x1e, 0xbc20); /* Value copied from u-boot */480 481 return 0;482}483 484static const struct mii_phy_ops ar8035_phy_ops = {485 .init = ar8035_init,486 .setup_aneg = genmii_setup_aneg,487 .setup_forced = genmii_setup_forced,488 .poll_link = genmii_poll_link,489 .read_link = genmii_read_link,490};491 492static struct mii_phy_def ar8035_phy_def = {493 .phy_id = 0x004dd070,494 .phy_id_mask = 0xfffffff0,495 .name = "Atheros 8035 Gigabit Ethernet",496 .ops = &ar8035_phy_ops,497};498 499static struct mii_phy_def *mii_phy_table[] = {500 &et1011c_phy_def,501 &cis8201_phy_def,502 &bcm5248_phy_def,503 &m88e1111_phy_def,504 &m88e1112_phy_def,505 &ar8035_phy_def,506 &genmii_phy_def,507 NULL508};509 510int emac_mii_phy_probe(struct mii_phy *phy, int address)511{512 struct mii_phy_def *def;513 int i;514 u32 id;515 516 phy->autoneg = AUTONEG_DISABLE;517 phy->advertising = 0;518 phy->address = address;519 phy->speed = SPEED_10;520 phy->duplex = DUPLEX_HALF;521 phy->pause = phy->asym_pause = 0;522 523 /* Take PHY out of isolate mode and reset it. */524 if (emac_mii_reset_phy(phy))525 return -ENODEV;526 527 /* Read ID and find matching entry */528 id = (phy_read(phy, MII_PHYSID1) << 16) | phy_read(phy, MII_PHYSID2);529 for (i = 0; (def = mii_phy_table[i]) != NULL; i++)530 if ((id & def->phy_id_mask) == def->phy_id)531 break;532 /* Should never be NULL (we have a generic entry), but... */533 if (!def)534 return -ENODEV;535 536 phy->def = def;537 538 /* Determine PHY features if needed */539 phy->features = def->features;540 if (!phy->features) {541 u16 bmsr = phy_read(phy, MII_BMSR);542 if (bmsr & BMSR_ANEGCAPABLE)543 phy->features |= SUPPORTED_Autoneg;544 if (bmsr & BMSR_10HALF)545 phy->features |= SUPPORTED_10baseT_Half;546 if (bmsr & BMSR_10FULL)547 phy->features |= SUPPORTED_10baseT_Full;548 if (bmsr & BMSR_100HALF)549 phy->features |= SUPPORTED_100baseT_Half;550 if (bmsr & BMSR_100FULL)551 phy->features |= SUPPORTED_100baseT_Full;552 if (bmsr & BMSR_ESTATEN) {553 u16 esr = phy_read(phy, MII_ESTATUS);554 if (esr & ESTATUS_1000_TFULL)555 phy->features |= SUPPORTED_1000baseT_Full;556 if (esr & ESTATUS_1000_THALF)557 phy->features |= SUPPORTED_1000baseT_Half;558 }559 phy->features |= SUPPORTED_MII;560 }561 562 /* Setup default advertising */563 phy->advertising = phy->features;564 565 return 0;566}567 568MODULE_LICENSE("GPL");569