cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

sungem_phy.c (30472B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * PHY drivers for the sungem ethernet driver.
      4 *
      5 * This file could be shared with other drivers.
      6 *
      7 * (c) 2002-2007, Benjamin Herrenscmidt (benh@kernel.crashing.org)
      8 *
      9 * TODO:
     10 *  - Add support for PHYs that provide an IRQ line
     11 *  - Eventually moved the entire polling state machine in
     12 *    there (out of the eth driver), so that it can easily be
     13 *    skipped on PHYs that implement it in hardware.
     14 *  - On LXT971 & BCM5201, Apple uses some chip specific regs
     15 *    to read the link status. Figure out why and if it makes
     16 *    sense to do the same (magic aneg ?)
     17 *  - Apple has some additional power management code for some
     18 *    Broadcom PHYs that they "hide" from the OpenSource version
     19 *    of darwin, still need to reverse engineer that
     20 */
     21
     22
     23#include <linux/module.h>
     24
     25#include <linux/kernel.h>
     26#include <linux/types.h>
     27#include <linux/netdevice.h>
     28#include <linux/etherdevice.h>
     29#include <linux/mii.h>
     30#include <linux/ethtool.h>
     31#include <linux/delay.h>
     32#include <linux/of.h>
     33#include <linux/sungem_phy.h>
     34
     35/* Link modes of the BCM5400 PHY */
     36static const int phy_BCM5400_link_table[8][3] = {
     37	{ 0, 0, 0 },	/* No link */
     38	{ 0, 0, 0 },	/* 10BT Half Duplex */
     39	{ 1, 0, 0 },	/* 10BT Full Duplex */
     40	{ 0, 1, 0 },	/* 100BT Half Duplex */
     41	{ 0, 1, 0 },	/* 100BT Half Duplex */
     42	{ 1, 1, 0 },	/* 100BT Full Duplex*/
     43	{ 1, 0, 1 },	/* 1000BT */
     44	{ 1, 0, 1 },	/* 1000BT */
     45};
     46
     47static inline int __sungem_phy_read(struct mii_phy* phy, int id, int reg)
     48{
     49	return phy->mdio_read(phy->dev, id, reg);
     50}
     51
     52static inline void __sungem_phy_write(struct mii_phy* phy, int id, int reg, int val)
     53{
     54	phy->mdio_write(phy->dev, id, reg, val);
     55}
     56
     57static inline int sungem_phy_read(struct mii_phy* phy, int reg)
     58{
     59	return phy->mdio_read(phy->dev, phy->mii_id, reg);
     60}
     61
     62static inline void sungem_phy_write(struct mii_phy* phy, int reg, int val)
     63{
     64	phy->mdio_write(phy->dev, phy->mii_id, reg, val);
     65}
     66
     67static int reset_one_mii_phy(struct mii_phy* phy, int phy_id)
     68{
     69	u16 val;
     70	int limit = 10000;
     71
     72	val = __sungem_phy_read(phy, phy_id, MII_BMCR);
     73	val &= ~(BMCR_ISOLATE | BMCR_PDOWN);
     74	val |= BMCR_RESET;
     75	__sungem_phy_write(phy, phy_id, MII_BMCR, val);
     76
     77	udelay(100);
     78
     79	while (--limit) {
     80		val = __sungem_phy_read(phy, phy_id, MII_BMCR);
     81		if ((val & BMCR_RESET) == 0)
     82			break;
     83		udelay(10);
     84	}
     85	if ((val & BMCR_ISOLATE) && limit > 0)
     86		__sungem_phy_write(phy, phy_id, MII_BMCR, val & ~BMCR_ISOLATE);
     87
     88	return limit <= 0;
     89}
     90
     91static int bcm5201_init(struct mii_phy* phy)
     92{
     93	u16 data;
     94
     95	data = sungem_phy_read(phy, MII_BCM5201_MULTIPHY);
     96	data &= ~MII_BCM5201_MULTIPHY_SUPERISOLATE;
     97	sungem_phy_write(phy, MII_BCM5201_MULTIPHY, data);
     98
     99	sungem_phy_write(phy, MII_BCM5201_INTERRUPT, 0);
    100
    101	return 0;
    102}
    103
    104static int bcm5201_suspend(struct mii_phy* phy)
    105{
    106	sungem_phy_write(phy, MII_BCM5201_INTERRUPT, 0);
    107	sungem_phy_write(phy, MII_BCM5201_MULTIPHY, MII_BCM5201_MULTIPHY_SUPERISOLATE);
    108
    109	return 0;
    110}
    111
    112static int bcm5221_init(struct mii_phy* phy)
    113{
    114	u16 data;
    115
    116	data = sungem_phy_read(phy, MII_BCM5221_TEST);
    117	sungem_phy_write(phy, MII_BCM5221_TEST,
    118		data | MII_BCM5221_TEST_ENABLE_SHADOWS);
    119
    120	data = sungem_phy_read(phy, MII_BCM5221_SHDOW_AUX_STAT2);
    121	sungem_phy_write(phy, MII_BCM5221_SHDOW_AUX_STAT2,
    122		data | MII_BCM5221_SHDOW_AUX_STAT2_APD);
    123
    124	data = sungem_phy_read(phy, MII_BCM5221_SHDOW_AUX_MODE4);
    125	sungem_phy_write(phy, MII_BCM5221_SHDOW_AUX_MODE4,
    126		data | MII_BCM5221_SHDOW_AUX_MODE4_CLKLOPWR);
    127
    128	data = sungem_phy_read(phy, MII_BCM5221_TEST);
    129	sungem_phy_write(phy, MII_BCM5221_TEST,
    130		data & ~MII_BCM5221_TEST_ENABLE_SHADOWS);
    131
    132	return 0;
    133}
    134
    135static int bcm5221_suspend(struct mii_phy* phy)
    136{
    137	u16 data;
    138
    139	data = sungem_phy_read(phy, MII_BCM5221_TEST);
    140	sungem_phy_write(phy, MII_BCM5221_TEST,
    141		data | MII_BCM5221_TEST_ENABLE_SHADOWS);
    142
    143	data = sungem_phy_read(phy, MII_BCM5221_SHDOW_AUX_MODE4);
    144	sungem_phy_write(phy, MII_BCM5221_SHDOW_AUX_MODE4,
    145		  data | MII_BCM5221_SHDOW_AUX_MODE4_IDDQMODE);
    146
    147	return 0;
    148}
    149
    150static int bcm5241_init(struct mii_phy* phy)
    151{
    152	u16 data;
    153
    154	data = sungem_phy_read(phy, MII_BCM5221_TEST);
    155	sungem_phy_write(phy, MII_BCM5221_TEST,
    156		data | MII_BCM5221_TEST_ENABLE_SHADOWS);
    157
    158	data = sungem_phy_read(phy, MII_BCM5221_SHDOW_AUX_STAT2);
    159	sungem_phy_write(phy, MII_BCM5221_SHDOW_AUX_STAT2,
    160		data | MII_BCM5221_SHDOW_AUX_STAT2_APD);
    161
    162	data = sungem_phy_read(phy, MII_BCM5221_SHDOW_AUX_MODE4);
    163	sungem_phy_write(phy, MII_BCM5221_SHDOW_AUX_MODE4,
    164		data & ~MII_BCM5241_SHDOW_AUX_MODE4_STANDBYPWR);
    165
    166	data = sungem_phy_read(phy, MII_BCM5221_TEST);
    167	sungem_phy_write(phy, MII_BCM5221_TEST,
    168		data & ~MII_BCM5221_TEST_ENABLE_SHADOWS);
    169
    170	return 0;
    171}
    172
    173static int bcm5241_suspend(struct mii_phy* phy)
    174{
    175	u16 data;
    176
    177	data = sungem_phy_read(phy, MII_BCM5221_TEST);
    178	sungem_phy_write(phy, MII_BCM5221_TEST,
    179		data | MII_BCM5221_TEST_ENABLE_SHADOWS);
    180
    181	data = sungem_phy_read(phy, MII_BCM5221_SHDOW_AUX_MODE4);
    182	sungem_phy_write(phy, MII_BCM5221_SHDOW_AUX_MODE4,
    183		  data | MII_BCM5241_SHDOW_AUX_MODE4_STANDBYPWR);
    184
    185	return 0;
    186}
    187
    188static int bcm5400_init(struct mii_phy* phy)
    189{
    190	u16 data;
    191
    192	/* Configure for gigabit full duplex */
    193	data = sungem_phy_read(phy, MII_BCM5400_AUXCONTROL);
    194	data |= MII_BCM5400_AUXCONTROL_PWR10BASET;
    195	sungem_phy_write(phy, MII_BCM5400_AUXCONTROL, data);
    196
    197	data = sungem_phy_read(phy, MII_BCM5400_GB_CONTROL);
    198	data |= MII_BCM5400_GB_CONTROL_FULLDUPLEXCAP;
    199	sungem_phy_write(phy, MII_BCM5400_GB_CONTROL, data);
    200
    201	udelay(100);
    202
    203	/* Reset and configure cascaded 10/100 PHY */
    204	(void)reset_one_mii_phy(phy, 0x1f);
    205
    206	data = __sungem_phy_read(phy, 0x1f, MII_BCM5201_MULTIPHY);
    207	data |= MII_BCM5201_MULTIPHY_SERIALMODE;
    208	__sungem_phy_write(phy, 0x1f, MII_BCM5201_MULTIPHY, data);
    209
    210	data = sungem_phy_read(phy, MII_BCM5400_AUXCONTROL);
    211	data &= ~MII_BCM5400_AUXCONTROL_PWR10BASET;
    212	sungem_phy_write(phy, MII_BCM5400_AUXCONTROL, data);
    213
    214	return 0;
    215}
    216
    217static int bcm5400_suspend(struct mii_phy* phy)
    218{
    219#if 0 /* Commented out in Darwin... someone has those dawn docs ? */
    220	sungem_phy_write(phy, MII_BMCR, BMCR_PDOWN);
    221#endif
    222	return 0;
    223}
    224
    225static int bcm5401_init(struct mii_phy* phy)
    226{
    227	u16 data;
    228	int rev;
    229
    230	rev = sungem_phy_read(phy, MII_PHYSID2) & 0x000f;
    231	if (rev == 0 || rev == 3) {
    232		/* Some revisions of 5401 appear to need this
    233		 * initialisation sequence to disable, according
    234		 * to OF, "tap power management"
    235		 *
    236		 * WARNING ! OF and Darwin don't agree on the
    237		 * register addresses. OF seem to interpret the
    238		 * register numbers below as decimal
    239		 *
    240		 * Note: This should (and does) match tg3_init_5401phy_dsp
    241		 *       in the tg3.c driver. -DaveM
    242		 */
    243		sungem_phy_write(phy, 0x18, 0x0c20);
    244		sungem_phy_write(phy, 0x17, 0x0012);
    245		sungem_phy_write(phy, 0x15, 0x1804);
    246		sungem_phy_write(phy, 0x17, 0x0013);
    247		sungem_phy_write(phy, 0x15, 0x1204);
    248		sungem_phy_write(phy, 0x17, 0x8006);
    249		sungem_phy_write(phy, 0x15, 0x0132);
    250		sungem_phy_write(phy, 0x17, 0x8006);
    251		sungem_phy_write(phy, 0x15, 0x0232);
    252		sungem_phy_write(phy, 0x17, 0x201f);
    253		sungem_phy_write(phy, 0x15, 0x0a20);
    254	}
    255
    256	/* Configure for gigabit full duplex */
    257	data = sungem_phy_read(phy, MII_BCM5400_GB_CONTROL);
    258	data |= MII_BCM5400_GB_CONTROL_FULLDUPLEXCAP;
    259	sungem_phy_write(phy, MII_BCM5400_GB_CONTROL, data);
    260
    261	udelay(10);
    262
    263	/* Reset and configure cascaded 10/100 PHY */
    264	(void)reset_one_mii_phy(phy, 0x1f);
    265
    266	data = __sungem_phy_read(phy, 0x1f, MII_BCM5201_MULTIPHY);
    267	data |= MII_BCM5201_MULTIPHY_SERIALMODE;
    268	__sungem_phy_write(phy, 0x1f, MII_BCM5201_MULTIPHY, data);
    269
    270	return 0;
    271}
    272
    273static int bcm5401_suspend(struct mii_phy* phy)
    274{
    275#if 0 /* Commented out in Darwin... someone has those dawn docs ? */
    276	sungem_phy_write(phy, MII_BMCR, BMCR_PDOWN);
    277#endif
    278	return 0;
    279}
    280
    281static int bcm5411_init(struct mii_phy* phy)
    282{
    283	u16 data;
    284
    285	/* Here's some more Apple black magic to setup
    286	 * some voltage stuffs.
    287	 */
    288	sungem_phy_write(phy, 0x1c, 0x8c23);
    289	sungem_phy_write(phy, 0x1c, 0x8ca3);
    290	sungem_phy_write(phy, 0x1c, 0x8c23);
    291
    292	/* Here, Apple seems to want to reset it, do
    293	 * it as well
    294	 */
    295	sungem_phy_write(phy, MII_BMCR, BMCR_RESET);
    296	sungem_phy_write(phy, MII_BMCR, 0x1340);
    297
    298	data = sungem_phy_read(phy, MII_BCM5400_GB_CONTROL);
    299	data |= MII_BCM5400_GB_CONTROL_FULLDUPLEXCAP;
    300	sungem_phy_write(phy, MII_BCM5400_GB_CONTROL, data);
    301
    302	udelay(10);
    303
    304	/* Reset and configure cascaded 10/100 PHY */
    305	(void)reset_one_mii_phy(phy, 0x1f);
    306
    307	return 0;
    308}
    309
    310static int genmii_setup_aneg(struct mii_phy *phy, u32 advertise)
    311{
    312	u16 ctl, adv;
    313
    314	phy->autoneg = 1;
    315	phy->speed = SPEED_10;
    316	phy->duplex = DUPLEX_HALF;
    317	phy->pause = 0;
    318	phy->advertising = advertise;
    319
    320	/* Setup standard advertise */
    321	adv = sungem_phy_read(phy, MII_ADVERTISE);
    322	adv &= ~(ADVERTISE_ALL | ADVERTISE_100BASE4);
    323	if (advertise & ADVERTISED_10baseT_Half)
    324		adv |= ADVERTISE_10HALF;
    325	if (advertise & ADVERTISED_10baseT_Full)
    326		adv |= ADVERTISE_10FULL;
    327	if (advertise & ADVERTISED_100baseT_Half)
    328		adv |= ADVERTISE_100HALF;
    329	if (advertise & ADVERTISED_100baseT_Full)
    330		adv |= ADVERTISE_100FULL;
    331	sungem_phy_write(phy, MII_ADVERTISE, adv);
    332
    333	/* Start/Restart aneg */
    334	ctl = sungem_phy_read(phy, MII_BMCR);
    335	ctl |= (BMCR_ANENABLE | BMCR_ANRESTART);
    336	sungem_phy_write(phy, MII_BMCR, ctl);
    337
    338	return 0;
    339}
    340
    341static int genmii_setup_forced(struct mii_phy *phy, int speed, int fd)
    342{
    343	u16 ctl;
    344
    345	phy->autoneg = 0;
    346	phy->speed = speed;
    347	phy->duplex = fd;
    348	phy->pause = 0;
    349
    350	ctl = sungem_phy_read(phy, MII_BMCR);
    351	ctl &= ~(BMCR_FULLDPLX|BMCR_SPEED100|BMCR_ANENABLE);
    352
    353	/* First reset the PHY */
    354	sungem_phy_write(phy, MII_BMCR, ctl | BMCR_RESET);
    355
    356	/* Select speed & duplex */
    357	switch(speed) {
    358	case SPEED_10:
    359		break;
    360	case SPEED_100:
    361		ctl |= BMCR_SPEED100;
    362		break;
    363	case SPEED_1000:
    364	default:
    365		return -EINVAL;
    366	}
    367	if (fd == DUPLEX_FULL)
    368		ctl |= BMCR_FULLDPLX;
    369	sungem_phy_write(phy, MII_BMCR, ctl);
    370
    371	return 0;
    372}
    373
    374static int genmii_poll_link(struct mii_phy *phy)
    375{
    376	u16 status;
    377
    378	(void)sungem_phy_read(phy, MII_BMSR);
    379	status = sungem_phy_read(phy, MII_BMSR);
    380	if ((status & BMSR_LSTATUS) == 0)
    381		return 0;
    382	if (phy->autoneg && !(status & BMSR_ANEGCOMPLETE))
    383		return 0;
    384	return 1;
    385}
    386
    387static int genmii_read_link(struct mii_phy *phy)
    388{
    389	u16 lpa;
    390
    391	if (phy->autoneg) {
    392		lpa = sungem_phy_read(phy, MII_LPA);
    393
    394		if (lpa & (LPA_10FULL | LPA_100FULL))
    395			phy->duplex = DUPLEX_FULL;
    396		else
    397			phy->duplex = DUPLEX_HALF;
    398		if (lpa & (LPA_100FULL | LPA_100HALF))
    399			phy->speed = SPEED_100;
    400		else
    401			phy->speed = SPEED_10;
    402		phy->pause = 0;
    403	}
    404	/* On non-aneg, we assume what we put in BMCR is the speed,
    405	 * though magic-aneg shouldn't prevent this case from occurring
    406	 */
    407
    408	return 0;
    409}
    410
    411static int generic_suspend(struct mii_phy* phy)
    412{
    413	sungem_phy_write(phy, MII_BMCR, BMCR_PDOWN);
    414
    415	return 0;
    416}
    417
    418static int bcm5421_init(struct mii_phy* phy)
    419{
    420	u16 data;
    421	unsigned int id;
    422
    423	id = (sungem_phy_read(phy, MII_PHYSID1) << 16 | sungem_phy_read(phy, MII_PHYSID2));
    424
    425	/* Revision 0 of 5421 needs some fixups */
    426	if (id == 0x002060e0) {
    427		/* This is borrowed from MacOS
    428		 */
    429		sungem_phy_write(phy, 0x18, 0x1007);
    430		data = sungem_phy_read(phy, 0x18);
    431		sungem_phy_write(phy, 0x18, data | 0x0400);
    432		sungem_phy_write(phy, 0x18, 0x0007);
    433		data = sungem_phy_read(phy, 0x18);
    434		sungem_phy_write(phy, 0x18, data | 0x0800);
    435		sungem_phy_write(phy, 0x17, 0x000a);
    436		data = sungem_phy_read(phy, 0x15);
    437		sungem_phy_write(phy, 0x15, data | 0x0200);
    438	}
    439
    440	/* Pick up some init code from OF for K2 version */
    441	if ((id & 0xfffffff0) == 0x002062e0) {
    442		sungem_phy_write(phy, 4, 0x01e1);
    443		sungem_phy_write(phy, 9, 0x0300);
    444	}
    445
    446	/* Check if we can enable automatic low power */
    447#ifdef CONFIG_PPC_PMAC
    448	if (phy->platform_data) {
    449		struct device_node *np = of_get_parent(phy->platform_data);
    450		int can_low_power = 1;
    451		if (np == NULL || of_get_property(np, "no-autolowpower", NULL))
    452			can_low_power = 0;
    453		if (can_low_power) {
    454			/* Enable automatic low-power */
    455			sungem_phy_write(phy, 0x1c, 0x9002);
    456			sungem_phy_write(phy, 0x1c, 0xa821);
    457			sungem_phy_write(phy, 0x1c, 0x941d);
    458		}
    459	}
    460#endif /* CONFIG_PPC_PMAC */
    461
    462	return 0;
    463}
    464
    465static int bcm54xx_setup_aneg(struct mii_phy *phy, u32 advertise)
    466{
    467	u16 ctl, adv;
    468
    469	phy->autoneg = 1;
    470	phy->speed = SPEED_10;
    471	phy->duplex = DUPLEX_HALF;
    472	phy->pause = 0;
    473	phy->advertising = advertise;
    474
    475	/* Setup standard advertise */
    476	adv = sungem_phy_read(phy, MII_ADVERTISE);
    477	adv &= ~(ADVERTISE_ALL | ADVERTISE_100BASE4);
    478	if (advertise & ADVERTISED_10baseT_Half)
    479		adv |= ADVERTISE_10HALF;
    480	if (advertise & ADVERTISED_10baseT_Full)
    481		adv |= ADVERTISE_10FULL;
    482	if (advertise & ADVERTISED_100baseT_Half)
    483		adv |= ADVERTISE_100HALF;
    484	if (advertise & ADVERTISED_100baseT_Full)
    485		adv |= ADVERTISE_100FULL;
    486	if (advertise & ADVERTISED_Pause)
    487		adv |= ADVERTISE_PAUSE_CAP;
    488	if (advertise & ADVERTISED_Asym_Pause)
    489		adv |= ADVERTISE_PAUSE_ASYM;
    490	sungem_phy_write(phy, MII_ADVERTISE, adv);
    491
    492	/* Setup 1000BT advertise */
    493	adv = sungem_phy_read(phy, MII_1000BASETCONTROL);
    494	adv &= ~(MII_1000BASETCONTROL_FULLDUPLEXCAP|MII_1000BASETCONTROL_HALFDUPLEXCAP);
    495	if (advertise & SUPPORTED_1000baseT_Half)
    496		adv |= MII_1000BASETCONTROL_HALFDUPLEXCAP;
    497	if (advertise & SUPPORTED_1000baseT_Full)
    498		adv |= MII_1000BASETCONTROL_FULLDUPLEXCAP;
    499	sungem_phy_write(phy, MII_1000BASETCONTROL, adv);
    500
    501	/* Start/Restart aneg */
    502	ctl = sungem_phy_read(phy, MII_BMCR);
    503	ctl |= (BMCR_ANENABLE | BMCR_ANRESTART);
    504	sungem_phy_write(phy, MII_BMCR, ctl);
    505
    506	return 0;
    507}
    508
    509static int bcm54xx_setup_forced(struct mii_phy *phy, int speed, int fd)
    510{
    511	u16 ctl;
    512
    513	phy->autoneg = 0;
    514	phy->speed = speed;
    515	phy->duplex = fd;
    516	phy->pause = 0;
    517
    518	ctl = sungem_phy_read(phy, MII_BMCR);
    519	ctl &= ~(BMCR_FULLDPLX|BMCR_SPEED100|BMCR_SPD2|BMCR_ANENABLE);
    520
    521	/* First reset the PHY */
    522	sungem_phy_write(phy, MII_BMCR, ctl | BMCR_RESET);
    523
    524	/* Select speed & duplex */
    525	switch(speed) {
    526	case SPEED_10:
    527		break;
    528	case SPEED_100:
    529		ctl |= BMCR_SPEED100;
    530		break;
    531	case SPEED_1000:
    532		ctl |= BMCR_SPD2;
    533	}
    534	if (fd == DUPLEX_FULL)
    535		ctl |= BMCR_FULLDPLX;
    536
    537	// XXX Should we set the sungem to GII now on 1000BT ?
    538
    539	sungem_phy_write(phy, MII_BMCR, ctl);
    540
    541	return 0;
    542}
    543
    544static int bcm54xx_read_link(struct mii_phy *phy)
    545{
    546	int link_mode;
    547	u16 val;
    548
    549	if (phy->autoneg) {
    550	    	val = sungem_phy_read(phy, MII_BCM5400_AUXSTATUS);
    551		link_mode = ((val & MII_BCM5400_AUXSTATUS_LINKMODE_MASK) >>
    552			     MII_BCM5400_AUXSTATUS_LINKMODE_SHIFT);
    553		phy->duplex = phy_BCM5400_link_table[link_mode][0] ?
    554			DUPLEX_FULL : DUPLEX_HALF;
    555		phy->speed = phy_BCM5400_link_table[link_mode][2] ?
    556				SPEED_1000 :
    557				(phy_BCM5400_link_table[link_mode][1] ?
    558				 SPEED_100 : SPEED_10);
    559		val = sungem_phy_read(phy, MII_LPA);
    560		phy->pause = (phy->duplex == DUPLEX_FULL) &&
    561			((val & LPA_PAUSE) != 0);
    562	}
    563	/* On non-aneg, we assume what we put in BMCR is the speed,
    564	 * though magic-aneg shouldn't prevent this case from occurring
    565	 */
    566
    567	return 0;
    568}
    569
    570static int marvell88e1111_init(struct mii_phy* phy)
    571{
    572	u16 rev;
    573
    574	/* magic init sequence for rev 0 */
    575	rev = sungem_phy_read(phy, MII_PHYSID2) & 0x000f;
    576	if (rev == 0) {
    577		sungem_phy_write(phy, 0x1d, 0x000a);
    578		sungem_phy_write(phy, 0x1e, 0x0821);
    579
    580		sungem_phy_write(phy, 0x1d, 0x0006);
    581		sungem_phy_write(phy, 0x1e, 0x8600);
    582
    583		sungem_phy_write(phy, 0x1d, 0x000b);
    584		sungem_phy_write(phy, 0x1e, 0x0100);
    585
    586		sungem_phy_write(phy, 0x1d, 0x0004);
    587		sungem_phy_write(phy, 0x1e, 0x4850);
    588	}
    589	return 0;
    590}
    591
    592#define BCM5421_MODE_MASK	(1 << 5)
    593
    594static int bcm5421_poll_link(struct mii_phy* phy)
    595{
    596	u32 phy_reg;
    597	int mode;
    598
    599	/* find out in what mode we are */
    600	sungem_phy_write(phy, MII_NCONFIG, 0x1000);
    601	phy_reg = sungem_phy_read(phy, MII_NCONFIG);
    602
    603	mode = (phy_reg & BCM5421_MODE_MASK) >> 5;
    604
    605	if ( mode == BCM54XX_COPPER)
    606		return genmii_poll_link(phy);
    607
    608	/* try to find out whether we have a link */
    609	sungem_phy_write(phy, MII_NCONFIG, 0x2000);
    610	phy_reg = sungem_phy_read(phy, MII_NCONFIG);
    611
    612	if (phy_reg & 0x0020)
    613		return 0;
    614	else
    615		return 1;
    616}
    617
    618static int bcm5421_read_link(struct mii_phy* phy)
    619{
    620	u32 phy_reg;
    621	int mode;
    622
    623	/* find out in what mode we are */
    624	sungem_phy_write(phy, MII_NCONFIG, 0x1000);
    625	phy_reg = sungem_phy_read(phy, MII_NCONFIG);
    626
    627	mode = (phy_reg & BCM5421_MODE_MASK ) >> 5;
    628
    629	if ( mode == BCM54XX_COPPER)
    630		return bcm54xx_read_link(phy);
    631
    632	phy->speed = SPEED_1000;
    633
    634	/* find out whether we are running half- or full duplex */
    635	sungem_phy_write(phy, MII_NCONFIG, 0x2000);
    636	phy_reg = sungem_phy_read(phy, MII_NCONFIG);
    637
    638	if ( (phy_reg & 0x0080) >> 7)
    639		phy->duplex |=  DUPLEX_HALF;
    640	else
    641		phy->duplex |=  DUPLEX_FULL;
    642
    643	return 0;
    644}
    645
    646static int bcm5421_enable_fiber(struct mii_phy* phy, int autoneg)
    647{
    648	/* enable fiber mode */
    649	sungem_phy_write(phy, MII_NCONFIG, 0x9020);
    650	/* LEDs active in both modes, autosense prio = fiber */
    651	sungem_phy_write(phy, MII_NCONFIG, 0x945f);
    652
    653	if (!autoneg) {
    654		/* switch off fibre autoneg */
    655		sungem_phy_write(phy, MII_NCONFIG, 0xfc01);
    656		sungem_phy_write(phy, 0x0b, 0x0004);
    657	}
    658
    659	phy->autoneg = autoneg;
    660
    661	return 0;
    662}
    663
    664#define BCM5461_FIBER_LINK	(1 << 2)
    665#define BCM5461_MODE_MASK	(3 << 1)
    666
    667static int bcm5461_poll_link(struct mii_phy* phy)
    668{
    669	u32 phy_reg;
    670	int mode;
    671
    672	/* find out in what mode we are */
    673	sungem_phy_write(phy, MII_NCONFIG, 0x7c00);
    674	phy_reg = sungem_phy_read(phy, MII_NCONFIG);
    675
    676	mode = (phy_reg & BCM5461_MODE_MASK ) >> 1;
    677
    678	if ( mode == BCM54XX_COPPER)
    679		return genmii_poll_link(phy);
    680
    681	/* find out whether we have a link */
    682	sungem_phy_write(phy, MII_NCONFIG, 0x7000);
    683	phy_reg = sungem_phy_read(phy, MII_NCONFIG);
    684
    685	if (phy_reg & BCM5461_FIBER_LINK)
    686		return 1;
    687	else
    688		return 0;
    689}
    690
    691#define BCM5461_FIBER_DUPLEX	(1 << 3)
    692
    693static int bcm5461_read_link(struct mii_phy* phy)
    694{
    695	u32 phy_reg;
    696	int mode;
    697
    698	/* find out in what mode we are */
    699	sungem_phy_write(phy, MII_NCONFIG, 0x7c00);
    700	phy_reg = sungem_phy_read(phy, MII_NCONFIG);
    701
    702	mode = (phy_reg & BCM5461_MODE_MASK ) >> 1;
    703
    704	if ( mode == BCM54XX_COPPER) {
    705		return bcm54xx_read_link(phy);
    706	}
    707
    708	phy->speed = SPEED_1000;
    709
    710	/* find out whether we are running half- or full duplex */
    711	sungem_phy_write(phy, MII_NCONFIG, 0x7000);
    712	phy_reg = sungem_phy_read(phy, MII_NCONFIG);
    713
    714	if (phy_reg & BCM5461_FIBER_DUPLEX)
    715		phy->duplex |=  DUPLEX_FULL;
    716	else
    717		phy->duplex |=  DUPLEX_HALF;
    718
    719	return 0;
    720}
    721
    722static int bcm5461_enable_fiber(struct mii_phy* phy, int autoneg)
    723{
    724	/* select fiber mode, enable 1000 base-X registers */
    725	sungem_phy_write(phy, MII_NCONFIG, 0xfc0b);
    726
    727	if (autoneg) {
    728		/* enable fiber with no autonegotiation */
    729		sungem_phy_write(phy, MII_ADVERTISE, 0x01e0);
    730		sungem_phy_write(phy, MII_BMCR, 0x1140);
    731	} else {
    732		/* enable fiber with autonegotiation */
    733		sungem_phy_write(phy, MII_BMCR, 0x0140);
    734	}
    735
    736	phy->autoneg = autoneg;
    737
    738	return 0;
    739}
    740
    741static int marvell_setup_aneg(struct mii_phy *phy, u32 advertise)
    742{
    743	u16 ctl, adv;
    744
    745	phy->autoneg = 1;
    746	phy->speed = SPEED_10;
    747	phy->duplex = DUPLEX_HALF;
    748	phy->pause = 0;
    749	phy->advertising = advertise;
    750
    751	/* Setup standard advertise */
    752	adv = sungem_phy_read(phy, MII_ADVERTISE);
    753	adv &= ~(ADVERTISE_ALL | ADVERTISE_100BASE4);
    754	if (advertise & ADVERTISED_10baseT_Half)
    755		adv |= ADVERTISE_10HALF;
    756	if (advertise & ADVERTISED_10baseT_Full)
    757		adv |= ADVERTISE_10FULL;
    758	if (advertise & ADVERTISED_100baseT_Half)
    759		adv |= ADVERTISE_100HALF;
    760	if (advertise & ADVERTISED_100baseT_Full)
    761		adv |= ADVERTISE_100FULL;
    762	if (advertise & ADVERTISED_Pause)
    763		adv |= ADVERTISE_PAUSE_CAP;
    764	if (advertise & ADVERTISED_Asym_Pause)
    765		adv |= ADVERTISE_PAUSE_ASYM;
    766	sungem_phy_write(phy, MII_ADVERTISE, adv);
    767
    768	/* Setup 1000BT advertise & enable crossover detect
    769	 * XXX How do we advertise 1000BT ? Darwin source is
    770	 * confusing here, they read from specific control and
    771	 * write to control... Someone has specs for those
    772	 * beasts ?
    773	 */
    774	adv = sungem_phy_read(phy, MII_M1011_PHY_SPEC_CONTROL);
    775	adv |= MII_M1011_PHY_SPEC_CONTROL_AUTO_MDIX;
    776	adv &= ~(MII_1000BASETCONTROL_FULLDUPLEXCAP |
    777			MII_1000BASETCONTROL_HALFDUPLEXCAP);
    778	if (advertise & SUPPORTED_1000baseT_Half)
    779		adv |= MII_1000BASETCONTROL_HALFDUPLEXCAP;
    780	if (advertise & SUPPORTED_1000baseT_Full)
    781		adv |= MII_1000BASETCONTROL_FULLDUPLEXCAP;
    782	sungem_phy_write(phy, MII_1000BASETCONTROL, adv);
    783
    784	/* Start/Restart aneg */
    785	ctl = sungem_phy_read(phy, MII_BMCR);
    786	ctl |= (BMCR_ANENABLE | BMCR_ANRESTART);
    787	sungem_phy_write(phy, MII_BMCR, ctl);
    788
    789	return 0;
    790}
    791
    792static int marvell_setup_forced(struct mii_phy *phy, int speed, int fd)
    793{
    794	u16 ctl, ctl2;
    795
    796	phy->autoneg = 0;
    797	phy->speed = speed;
    798	phy->duplex = fd;
    799	phy->pause = 0;
    800
    801	ctl = sungem_phy_read(phy, MII_BMCR);
    802	ctl &= ~(BMCR_FULLDPLX|BMCR_SPEED100|BMCR_SPD2|BMCR_ANENABLE);
    803	ctl |= BMCR_RESET;
    804
    805	/* Select speed & duplex */
    806	switch(speed) {
    807	case SPEED_10:
    808		break;
    809	case SPEED_100:
    810		ctl |= BMCR_SPEED100;
    811		break;
    812	/* I'm not sure about the one below, again, Darwin source is
    813	 * quite confusing and I lack chip specs
    814	 */
    815	case SPEED_1000:
    816		ctl |= BMCR_SPD2;
    817	}
    818	if (fd == DUPLEX_FULL)
    819		ctl |= BMCR_FULLDPLX;
    820
    821	/* Disable crossover. Again, the way Apple does it is strange,
    822	 * though I don't assume they are wrong ;)
    823	 */
    824	ctl2 = sungem_phy_read(phy, MII_M1011_PHY_SPEC_CONTROL);
    825	ctl2 &= ~(MII_M1011_PHY_SPEC_CONTROL_MANUAL_MDIX |
    826		MII_M1011_PHY_SPEC_CONTROL_AUTO_MDIX |
    827		MII_1000BASETCONTROL_FULLDUPLEXCAP |
    828		MII_1000BASETCONTROL_HALFDUPLEXCAP);
    829	if (speed == SPEED_1000)
    830		ctl2 |= (fd == DUPLEX_FULL) ?
    831			MII_1000BASETCONTROL_FULLDUPLEXCAP :
    832			MII_1000BASETCONTROL_HALFDUPLEXCAP;
    833	sungem_phy_write(phy, MII_1000BASETCONTROL, ctl2);
    834
    835	// XXX Should we set the sungem to GII now on 1000BT ?
    836
    837	sungem_phy_write(phy, MII_BMCR, ctl);
    838
    839	return 0;
    840}
    841
    842static int marvell_read_link(struct mii_phy *phy)
    843{
    844	u16 status, pmask;
    845
    846	if (phy->autoneg) {
    847		status = sungem_phy_read(phy, MII_M1011_PHY_SPEC_STATUS);
    848		if ((status & MII_M1011_PHY_SPEC_STATUS_RESOLVED) == 0)
    849			return -EAGAIN;
    850		if (status & MII_M1011_PHY_SPEC_STATUS_1000)
    851			phy->speed = SPEED_1000;
    852		else if (status & MII_M1011_PHY_SPEC_STATUS_100)
    853			phy->speed = SPEED_100;
    854		else
    855			phy->speed = SPEED_10;
    856		if (status & MII_M1011_PHY_SPEC_STATUS_FULLDUPLEX)
    857			phy->duplex = DUPLEX_FULL;
    858		else
    859			phy->duplex = DUPLEX_HALF;
    860		pmask = MII_M1011_PHY_SPEC_STATUS_TX_PAUSE |
    861			MII_M1011_PHY_SPEC_STATUS_RX_PAUSE;
    862		phy->pause = (status & pmask) == pmask;
    863	}
    864	/* On non-aneg, we assume what we put in BMCR is the speed,
    865	 * though magic-aneg shouldn't prevent this case from occurring
    866	 */
    867
    868	return 0;
    869}
    870
    871#define MII_BASIC_FEATURES \
    872	(SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full |	\
    873	 SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full |	\
    874	 SUPPORTED_Autoneg | SUPPORTED_TP | SUPPORTED_MII |	\
    875	 SUPPORTED_Pause)
    876
    877/* On gigabit capable PHYs, we advertise Pause support but not asym pause
    878 * support for now as I'm not sure it's supported and Darwin doesn't do
    879 * it neither. --BenH.
    880 */
    881#define MII_GBIT_FEATURES \
    882	(MII_BASIC_FEATURES |	\
    883	 SUPPORTED_1000baseT_Half | SUPPORTED_1000baseT_Full)
    884
    885/* Broadcom BCM 5201 */
    886static const struct mii_phy_ops bcm5201_phy_ops = {
    887	.init		= bcm5201_init,
    888	.suspend	= bcm5201_suspend,
    889	.setup_aneg	= genmii_setup_aneg,
    890	.setup_forced	= genmii_setup_forced,
    891	.poll_link	= genmii_poll_link,
    892	.read_link	= genmii_read_link,
    893};
    894
    895static struct mii_phy_def bcm5201_phy_def = {
    896	.phy_id		= 0x00406210,
    897	.phy_id_mask	= 0xfffffff0,
    898	.name		= "BCM5201",
    899	.features	= MII_BASIC_FEATURES,
    900	.magic_aneg	= 1,
    901	.ops		= &bcm5201_phy_ops
    902};
    903
    904/* Broadcom BCM 5221 */
    905static const struct mii_phy_ops bcm5221_phy_ops = {
    906	.suspend	= bcm5221_suspend,
    907	.init		= bcm5221_init,
    908	.setup_aneg	= genmii_setup_aneg,
    909	.setup_forced	= genmii_setup_forced,
    910	.poll_link	= genmii_poll_link,
    911	.read_link	= genmii_read_link,
    912};
    913
    914static struct mii_phy_def bcm5221_phy_def = {
    915	.phy_id		= 0x004061e0,
    916	.phy_id_mask	= 0xfffffff0,
    917	.name		= "BCM5221",
    918	.features	= MII_BASIC_FEATURES,
    919	.magic_aneg	= 1,
    920	.ops		= &bcm5221_phy_ops
    921};
    922
    923/* Broadcom BCM 5241 */
    924static const struct mii_phy_ops bcm5241_phy_ops = {
    925	.suspend	= bcm5241_suspend,
    926	.init		= bcm5241_init,
    927	.setup_aneg	= genmii_setup_aneg,
    928	.setup_forced	= genmii_setup_forced,
    929	.poll_link	= genmii_poll_link,
    930	.read_link	= genmii_read_link,
    931};
    932static struct mii_phy_def bcm5241_phy_def = {
    933	.phy_id		= 0x0143bc30,
    934	.phy_id_mask	= 0xfffffff0,
    935	.name		= "BCM5241",
    936	.features	= MII_BASIC_FEATURES,
    937	.magic_aneg	= 1,
    938	.ops		= &bcm5241_phy_ops
    939};
    940
    941/* Broadcom BCM 5400 */
    942static const struct mii_phy_ops bcm5400_phy_ops = {
    943	.init		= bcm5400_init,
    944	.suspend	= bcm5400_suspend,
    945	.setup_aneg	= bcm54xx_setup_aneg,
    946	.setup_forced	= bcm54xx_setup_forced,
    947	.poll_link	= genmii_poll_link,
    948	.read_link	= bcm54xx_read_link,
    949};
    950
    951static struct mii_phy_def bcm5400_phy_def = {
    952	.phy_id		= 0x00206040,
    953	.phy_id_mask	= 0xfffffff0,
    954	.name		= "BCM5400",
    955	.features	= MII_GBIT_FEATURES,
    956	.magic_aneg	= 1,
    957	.ops		= &bcm5400_phy_ops
    958};
    959
    960/* Broadcom BCM 5401 */
    961static const struct mii_phy_ops bcm5401_phy_ops = {
    962	.init		= bcm5401_init,
    963	.suspend	= bcm5401_suspend,
    964	.setup_aneg	= bcm54xx_setup_aneg,
    965	.setup_forced	= bcm54xx_setup_forced,
    966	.poll_link	= genmii_poll_link,
    967	.read_link	= bcm54xx_read_link,
    968};
    969
    970static struct mii_phy_def bcm5401_phy_def = {
    971	.phy_id		= 0x00206050,
    972	.phy_id_mask	= 0xfffffff0,
    973	.name		= "BCM5401",
    974	.features	= MII_GBIT_FEATURES,
    975	.magic_aneg	= 1,
    976	.ops		= &bcm5401_phy_ops
    977};
    978
    979/* Broadcom BCM 5411 */
    980static const struct mii_phy_ops bcm5411_phy_ops = {
    981	.init		= bcm5411_init,
    982	.suspend	= generic_suspend,
    983	.setup_aneg	= bcm54xx_setup_aneg,
    984	.setup_forced	= bcm54xx_setup_forced,
    985	.poll_link	= genmii_poll_link,
    986	.read_link	= bcm54xx_read_link,
    987};
    988
    989static struct mii_phy_def bcm5411_phy_def = {
    990	.phy_id		= 0x00206070,
    991	.phy_id_mask	= 0xfffffff0,
    992	.name		= "BCM5411",
    993	.features	= MII_GBIT_FEATURES,
    994	.magic_aneg	= 1,
    995	.ops		= &bcm5411_phy_ops
    996};
    997
    998/* Broadcom BCM 5421 */
    999static const struct mii_phy_ops bcm5421_phy_ops = {
   1000	.init		= bcm5421_init,
   1001	.suspend	= generic_suspend,
   1002	.setup_aneg	= bcm54xx_setup_aneg,
   1003	.setup_forced	= bcm54xx_setup_forced,
   1004	.poll_link	= bcm5421_poll_link,
   1005	.read_link	= bcm5421_read_link,
   1006	.enable_fiber   = bcm5421_enable_fiber,
   1007};
   1008
   1009static struct mii_phy_def bcm5421_phy_def = {
   1010	.phy_id		= 0x002060e0,
   1011	.phy_id_mask	= 0xfffffff0,
   1012	.name		= "BCM5421",
   1013	.features	= MII_GBIT_FEATURES,
   1014	.magic_aneg	= 1,
   1015	.ops		= &bcm5421_phy_ops
   1016};
   1017
   1018/* Broadcom BCM 5421 built-in K2 */
   1019static const struct mii_phy_ops bcm5421k2_phy_ops = {
   1020	.init		= bcm5421_init,
   1021	.suspend	= generic_suspend,
   1022	.setup_aneg	= bcm54xx_setup_aneg,
   1023	.setup_forced	= bcm54xx_setup_forced,
   1024	.poll_link	= genmii_poll_link,
   1025	.read_link	= bcm54xx_read_link,
   1026};
   1027
   1028static struct mii_phy_def bcm5421k2_phy_def = {
   1029	.phy_id		= 0x002062e0,
   1030	.phy_id_mask	= 0xfffffff0,
   1031	.name		= "BCM5421-K2",
   1032	.features	= MII_GBIT_FEATURES,
   1033	.magic_aneg	= 1,
   1034	.ops		= &bcm5421k2_phy_ops
   1035};
   1036
   1037static const struct mii_phy_ops bcm5461_phy_ops = {
   1038	.init		= bcm5421_init,
   1039	.suspend	= generic_suspend,
   1040	.setup_aneg	= bcm54xx_setup_aneg,
   1041	.setup_forced	= bcm54xx_setup_forced,
   1042	.poll_link	= bcm5461_poll_link,
   1043	.read_link	= bcm5461_read_link,
   1044	.enable_fiber   = bcm5461_enable_fiber,
   1045};
   1046
   1047static struct mii_phy_def bcm5461_phy_def = {
   1048	.phy_id		= 0x002060c0,
   1049	.phy_id_mask	= 0xfffffff0,
   1050	.name		= "BCM5461",
   1051	.features	= MII_GBIT_FEATURES,
   1052	.magic_aneg	= 1,
   1053	.ops		= &bcm5461_phy_ops
   1054};
   1055
   1056/* Broadcom BCM 5462 built-in Vesta */
   1057static const struct mii_phy_ops bcm5462V_phy_ops = {
   1058	.init		= bcm5421_init,
   1059	.suspend	= generic_suspend,
   1060	.setup_aneg	= bcm54xx_setup_aneg,
   1061	.setup_forced	= bcm54xx_setup_forced,
   1062	.poll_link	= genmii_poll_link,
   1063	.read_link	= bcm54xx_read_link,
   1064};
   1065
   1066static struct mii_phy_def bcm5462V_phy_def = {
   1067	.phy_id		= 0x002060d0,
   1068	.phy_id_mask	= 0xfffffff0,
   1069	.name		= "BCM5462-Vesta",
   1070	.features	= MII_GBIT_FEATURES,
   1071	.magic_aneg	= 1,
   1072	.ops		= &bcm5462V_phy_ops
   1073};
   1074
   1075/* Marvell 88E1101 amd 88E1111 */
   1076static const struct mii_phy_ops marvell88e1101_phy_ops = {
   1077	.suspend	= generic_suspend,
   1078	.setup_aneg	= marvell_setup_aneg,
   1079	.setup_forced	= marvell_setup_forced,
   1080	.poll_link	= genmii_poll_link,
   1081	.read_link	= marvell_read_link
   1082};
   1083
   1084static const struct mii_phy_ops marvell88e1111_phy_ops = {
   1085	.init		= marvell88e1111_init,
   1086	.suspend	= generic_suspend,
   1087	.setup_aneg	= marvell_setup_aneg,
   1088	.setup_forced	= marvell_setup_forced,
   1089	.poll_link	= genmii_poll_link,
   1090	.read_link	= marvell_read_link
   1091};
   1092
   1093/* two revs in darwin for the 88e1101 ... I could use a datasheet
   1094 * to get the proper names...
   1095 */
   1096static struct mii_phy_def marvell88e1101v1_phy_def = {
   1097	.phy_id		= 0x01410c20,
   1098	.phy_id_mask	= 0xfffffff0,
   1099	.name		= "Marvell 88E1101v1",
   1100	.features	= MII_GBIT_FEATURES,
   1101	.magic_aneg	= 1,
   1102	.ops		= &marvell88e1101_phy_ops
   1103};
   1104static struct mii_phy_def marvell88e1101v2_phy_def = {
   1105	.phy_id		= 0x01410c60,
   1106	.phy_id_mask	= 0xfffffff0,
   1107	.name		= "Marvell 88E1101v2",
   1108	.features	= MII_GBIT_FEATURES,
   1109	.magic_aneg	= 1,
   1110	.ops		= &marvell88e1101_phy_ops
   1111};
   1112static struct mii_phy_def marvell88e1111_phy_def = {
   1113	.phy_id		= 0x01410cc0,
   1114	.phy_id_mask	= 0xfffffff0,
   1115	.name		= "Marvell 88E1111",
   1116	.features	= MII_GBIT_FEATURES,
   1117	.magic_aneg	= 1,
   1118	.ops		= &marvell88e1111_phy_ops
   1119};
   1120
   1121/* Generic implementation for most 10/100 PHYs */
   1122static const struct mii_phy_ops generic_phy_ops = {
   1123	.setup_aneg	= genmii_setup_aneg,
   1124	.setup_forced	= genmii_setup_forced,
   1125	.poll_link	= genmii_poll_link,
   1126	.read_link	= genmii_read_link
   1127};
   1128
   1129static struct mii_phy_def genmii_phy_def = {
   1130	.phy_id		= 0x00000000,
   1131	.phy_id_mask	= 0x00000000,
   1132	.name		= "Generic MII",
   1133	.features	= MII_BASIC_FEATURES,
   1134	.magic_aneg	= 0,
   1135	.ops		= &generic_phy_ops
   1136};
   1137
   1138static struct mii_phy_def* mii_phy_table[] = {
   1139	&bcm5201_phy_def,
   1140	&bcm5221_phy_def,
   1141	&bcm5241_phy_def,
   1142	&bcm5400_phy_def,
   1143	&bcm5401_phy_def,
   1144	&bcm5411_phy_def,
   1145	&bcm5421_phy_def,
   1146	&bcm5421k2_phy_def,
   1147	&bcm5461_phy_def,
   1148	&bcm5462V_phy_def,
   1149	&marvell88e1101v1_phy_def,
   1150	&marvell88e1101v2_phy_def,
   1151	&marvell88e1111_phy_def,
   1152	&genmii_phy_def,
   1153	NULL
   1154};
   1155
   1156int sungem_phy_probe(struct mii_phy *phy, int mii_id)
   1157{
   1158	int rc;
   1159	u32 id;
   1160	struct mii_phy_def* def;
   1161	int i;
   1162
   1163	/* We do not reset the mii_phy structure as the driver
   1164	 * may re-probe the PHY regulary
   1165	 */
   1166	phy->mii_id = mii_id;
   1167
   1168	/* Take PHY out of isloate mode and reset it. */
   1169	rc = reset_one_mii_phy(phy, mii_id);
   1170	if (rc)
   1171		goto fail;
   1172
   1173	/* Read ID and find matching entry */
   1174	id = (sungem_phy_read(phy, MII_PHYSID1) << 16 | sungem_phy_read(phy, MII_PHYSID2));
   1175	printk(KERN_DEBUG KBUILD_MODNAME ": " "PHY ID: %x, addr: %x\n",
   1176	       id, mii_id);
   1177	for (i=0; (def = mii_phy_table[i]) != NULL; i++)
   1178		if ((id & def->phy_id_mask) == def->phy_id)
   1179			break;
   1180	/* Should never be NULL (we have a generic entry), but... */
   1181	if (def == NULL)
   1182		goto fail;
   1183
   1184	phy->def = def;
   1185
   1186	return 0;
   1187fail:
   1188	phy->speed = 0;
   1189	phy->duplex = 0;
   1190	phy->pause = 0;
   1191	phy->advertising = 0;
   1192	return -ENODEV;
   1193}
   1194
   1195EXPORT_SYMBOL(sungem_phy_probe);
   1196MODULE_LICENSE("GPL");