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

phy.c (13641B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * drivers/net/ethernet/ibm/emac/phy.c
      4 *
      5 * Driver for PowerPC 4xx on-chip ethernet controller, PHY support.
      6 * Borrowed from sungem_phy.c, though I only kept the generic MII
      7 * driver for now.
      8 *
      9 * This file should be shared with other drivers or eventually
     10 * merged as the "low level" part of miilib
     11 *
     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_read
     33#define phy_write _phy_write
     34
     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		else
    266			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		else
    272			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_link
    285};
    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_ops
    292};
    293
    294/* CIS8201 */
    295#define MII_CIS8201_10BTCSR	0x16
    296#define  TENBTCSR_ECHO_DISABLE	0x2000
    297#define MII_CIS8201_EPCR	0x17
    298#define  EPCR_MODE_MASK		0x3000
    299#define  EPCR_GMII_MODE		0x0000
    300#define  EPCR_RGMII_MODE	0x1000
    301#define  EPCR_TBI_MODE		0x2000
    302#define  EPCR_RTBI_MODE		0x3000
    303#define MII_CIS8201_ACSR	0x1c
    304#define  ACSR_PIN_PRIO_SELECT	0x0004
    305
    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_link
    350};
    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_ops
    357};
    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_ops
    365};
    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 MAC
    384	 * interace (page 2) properly configured to
    385	 * 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_link
    430};
    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_ops
    437};
    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_link
    449};
    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_link
    465};
    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	NULL
    508};
    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");