brintos

brintos / linux-shallow public Read only

0
0
Text · 13.3 KiB · 1e798cc Raw
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