Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 9e3cb294 authored by Victor Gallardo's avatar Victor Gallardo Committed by Josh Boyer
Browse files

ibm_newemac: Add support for GPCS, SGMII and M88E1112 PHY



Add support for the phy types found on the Arches and other
PowerPC 460 based boards.

Signed-off-by: default avatarVictor Gallardo <vgallardo@amcc.com>
Acked-by: default avatarBenjamin Herrenschmidt <benh@kernel.crashing.org>
Acked-by: default avatarJeff Garzik <jeff@garzik.org>
Signed-off-by: default avatarJosh Boyer <jwboyer@linux.vnet.ibm.com>
parent 5a013fc7
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -75,6 +75,10 @@
#define ICINTSTAT_ICTX1 0x20000000
#define ICINTSTAT_ICTX	0x60000000

/* SDRs (460EX/460GT) */
#define SDR0_ETH_CFG		0x4103
#define SDR0_ETH_CFG_ECS	0x00000100	/* EMAC int clk source */

/*
 * All those DCR register addresses are offsets from the base address
 * for the SRAM0 controller (e.g. 0x20 on 440GX). The base address is
+49 −9
Original line number Diff line number Diff line
@@ -130,6 +130,7 @@ static inline void emac_report_timeout_error(struct emac_instance *dev,
					     const char *error)
{
	if (emac_has_feature(dev, EMAC_FTR_440GX_PHY_CLK_FIX |
				  EMAC_FTR_460EX_PHY_CLK_FIX |
				  EMAC_FTR_440EP_PHY_CLK_FIX))
		DBG(dev, "%s" NL, error);
	else if (net_ratelimit())
@@ -201,13 +202,15 @@ static inline int emac_phy_supports_gige(int phy_mode)
{
	return  phy_mode == PHY_MODE_GMII ||
		phy_mode == PHY_MODE_RGMII ||
		phy_mode == PHY_MODE_SGMII ||
		phy_mode == PHY_MODE_TBI ||
		phy_mode == PHY_MODE_RTBI;
}

static inline int emac_phy_gpcs(int phy_mode)
{
	return  phy_mode == PHY_MODE_TBI ||
	return  phy_mode == PHY_MODE_SGMII ||
		phy_mode == PHY_MODE_TBI ||
		phy_mode == PHY_MODE_RTBI;
}

@@ -351,10 +354,24 @@ static int emac_reset(struct emac_instance *dev)
		emac_tx_disable(dev);
	}

#ifdef CONFIG_PPC_DCR_NATIVE
	/* Enable internal clock source */
	if (emac_has_feature(dev, EMAC_FTR_460EX_PHY_CLK_FIX))
		dcri_clrset(SDR0, SDR0_ETH_CFG,
			    0, SDR0_ETH_CFG_ECS << dev->cell_index);
#endif

	out_be32(&p->mr0, EMAC_MR0_SRST);
	while ((in_be32(&p->mr0) & EMAC_MR0_SRST) && n)
		--n;

#ifdef CONFIG_PPC_DCR_NATIVE
	 /* Enable external clock source */
	if (emac_has_feature(dev, EMAC_FTR_460EX_PHY_CLK_FIX))
		dcri_clrset(SDR0, SDR0_ETH_CFG,
			    SDR0_ETH_CFG_ECS << dev->cell_index, 0);
#endif

	if (n) {
		dev->reset_failed = 0;
		return 0;
@@ -547,8 +564,9 @@ static int emac_configure(struct emac_instance *dev)
	switch (dev->phy.speed) {
	case SPEED_1000:
		if (emac_phy_gpcs(dev->phy.mode)) {
			mr1 |= EMAC_MR1_MF_1000GPCS |
				EMAC_MR1_MF_IPPA(dev->phy.address);
			mr1 |= EMAC_MR1_MF_1000GPCS | EMAC_MR1_MF_IPPA(
				(dev->phy.gpcs_address != 0xffffffff) ?
				 dev->phy.gpcs_address : dev->phy.address);

			/* Put some arbitrary OUI, Manuf & Rev IDs so we can
			 * identify this GPCS PHY later.
@@ -660,8 +678,12 @@ static int emac_configure(struct emac_instance *dev)
	out_be32(&p->iser,  r);

	/* We need to take GPCS PHY out of isolate mode after EMAC reset */
	if (emac_phy_gpcs(dev->phy.mode))
	if (emac_phy_gpcs(dev->phy.mode)) {
		if (dev->phy.gpcs_address != 0xffffffff)
			emac_mii_reset_gpcs(&dev->phy);
		else
			emac_mii_reset_phy(&dev->phy);
	}

	return 0;
}
@@ -866,7 +888,9 @@ static int emac_mdio_read(struct net_device *ndev, int id, int reg)
	struct emac_instance *dev = netdev_priv(ndev);
	int res;

	res = __emac_mdio_read(dev->mdio_instance ? dev->mdio_instance : dev,
	res = __emac_mdio_read((dev->mdio_instance &&
				dev->phy.gpcs_address != id) ?
				dev->mdio_instance : dev,
			       (u8) id, (u8) reg);
	return res;
}
@@ -875,7 +899,9 @@ static void emac_mdio_write(struct net_device *ndev, int id, int reg, int val)
{
	struct emac_instance *dev = netdev_priv(ndev);

	__emac_mdio_write(dev->mdio_instance ? dev->mdio_instance : dev,
	__emac_mdio_write((dev->mdio_instance &&
			   dev->phy.gpcs_address != id) ?
			   dev->mdio_instance : dev,
			  (u8) id, (u8) reg, (u16) val);
}

@@ -2367,7 +2393,11 @@ static int __devinit emac_init_phy(struct emac_instance *dev)
		 * XXX I probably should move these settings to the dev tree
		 */
		dev->phy.address = -1;
		dev->phy.features = SUPPORTED_100baseT_Full | SUPPORTED_MII;
		dev->phy.features = SUPPORTED_MII;
		if (emac_phy_supports_gige(dev->phy_mode))
			dev->phy.features |= SUPPORTED_1000baseT_Full;
		else
			dev->phy.features |= SUPPORTED_100baseT_Full;
		dev->phy.pause = 1;

		return 0;
@@ -2406,6 +2436,8 @@ static int __devinit emac_init_phy(struct emac_instance *dev)
		 * Note that the busy_phy_map is currently global
		 * while it should probably be per-ASIC...
		 */
		dev->phy.gpcs_address = dev->gpcs_address;
		if (dev->phy.gpcs_address == 0xffffffff)
			dev->phy.address = dev->cell_index;
	}

@@ -2516,6 +2548,8 @@ static int __devinit emac_init_config(struct emac_instance *dev)
		dev->phy_address = 0xffffffff;
	if (emac_read_uint_prop(np, "phy-map", &dev->phy_map, 0))
		dev->phy_map = 0xffffffff;
	if (emac_read_uint_prop(np, "gpcs-address", &dev->gpcs_address, 0))
		dev->gpcs_address = 0xffffffff;
	if (emac_read_uint_prop(np->parent, "clock-frequency", &dev->opb_bus_freq, 1))
		return -ENXIO;
	if (emac_read_uint_prop(np, "tah-device", &dev->tah_ph, 0))
@@ -2559,6 +2593,9 @@ static int __devinit emac_init_config(struct emac_instance *dev)
	/* Check EMAC version */
	if (of_device_is_compatible(np, "ibm,emac4sync")) {
		dev->features |= (EMAC_FTR_EMAC4 | EMAC_FTR_EMAC4SYNC);
		if (of_device_is_compatible(np, "ibm,emac-460ex") ||
		    of_device_is_compatible(np, "ibm,emac-460gt"))
			dev->features |= EMAC_FTR_460EX_PHY_CLK_FIX;
	} else if (of_device_is_compatible(np, "ibm,emac4")) {
		dev->features |= EMAC_FTR_EMAC4;
		if (of_device_is_compatible(np, "ibm,emac-440gx"))
@@ -2826,6 +2863,9 @@ static int __devinit emac_probe(struct of_device *ofdev,
	       ndev->dev_addr[0], ndev->dev_addr[1], ndev->dev_addr[2],
	       ndev->dev_addr[3], ndev->dev_addr[4], ndev->dev_addr[5]);

	if (dev->phy_mode == PHY_MODE_SGMII)
		printk(KERN_NOTICE "%s: in SGMII mode\n", ndev->name);

	if (dev->phy.address >= 0)
		printk("%s: found %s PHY (0x%02x)\n", ndev->name,
		       dev->phy.def->name, dev->phy.address);
+8 −0
Original line number Diff line number Diff line
@@ -190,6 +190,9 @@ struct emac_instance {
	struct delayed_work		link_work;
	int				link_polling;

	/* GPCS PHY infos */
	u32				gpcs_address;

	/* Shared MDIO if any */
	u32				mdio_ph;
	struct of_device		*mdio_dev;
@@ -317,6 +320,10 @@ struct emac_instance {
 * The 405EX and 460EX contain the EMAC4SYNC core
 */
#define EMAC_FTR_EMAC4SYNC		0x00000200
/*
 * Set if we need phy clock workaround for 460ex or 460gt
 */
#define EMAC_FTR_460EX_PHY_CLK_FIX	0x00000400


/* Right now, we don't quite handle the always/possible masks on the
@@ -344,6 +351,7 @@ enum {
#ifdef CONFIG_IBM_NEW_EMAC_NO_FLOW_CTRL
	    EMAC_FTR_NO_FLOW_CONTROL_40x |
#endif
	EMAC_FTR_460EX_PHY_CLK_FIX |
	EMAC_FTR_440EP_PHY_CLK_FIX,
};

+84 −0
Original line number Diff line number Diff line
@@ -38,6 +38,16 @@ static inline void phy_write(struct mii_phy *phy, int reg, int val)
	phy->mdio_write(phy->dev, phy->address, reg, val);
}

static inline int gpcs_phy_read(struct mii_phy *phy, int reg)
{
	return phy->mdio_read(phy->dev, phy->gpcs_address, reg);
}

static inline void gpcs_phy_write(struct mii_phy *phy, int reg, int val)
{
	phy->mdio_write(phy->dev, phy->gpcs_address, reg, val);
}

int emac_mii_reset_phy(struct mii_phy *phy)
{
	int val;
@@ -62,6 +72,37 @@ int emac_mii_reset_phy(struct mii_phy *phy)
	return limit <= 0;
}

int emac_mii_reset_gpcs(struct mii_phy *phy)
{
	int val;
	int limit = 10000;

	val = gpcs_phy_read(phy, MII_BMCR);
	val &= ~(BMCR_ISOLATE | BMCR_ANENABLE);
	val |= BMCR_RESET;
	gpcs_phy_write(phy, MII_BMCR, val);

	udelay(300);

	while (limit--) {
		val = gpcs_phy_read(phy, MII_BMCR);
		if (val >= 0 && (val & BMCR_RESET) == 0)
			break;
		udelay(10);
	}
	if ((val & BMCR_ISOLATE) && limit > 0)
		gpcs_phy_write(phy, MII_BMCR, val & ~BMCR_ISOLATE);

	if (limit > 0 && phy->mode == PHY_MODE_SGMII) {
		/* Configure GPCS interface to recommended setting for SGMII */
		gpcs_phy_write(phy, 0x04, 0x8120); /* AsymPause, FDX */
		gpcs_phy_write(phy, 0x07, 0x2801); /* msg_pg, toggle */
		gpcs_phy_write(phy, 0x00, 0x0140); /* 1Gbps, FDX     */
	}

	return limit <= 0;
}

static int genmii_setup_aneg(struct mii_phy *phy, u32 advertise)
{
	int ctl, adv;
@@ -332,6 +373,33 @@ static int m88e1111_init(struct mii_phy *phy)
	return  0;
}

static int m88e1112_init(struct mii_phy *phy)
{
	/*
	 * Marvell 88E1112 PHY needs to have the SGMII MAC
	 * interace (page 2) properly configured to
	 * communicate with the 460EX/GT GPCS interface.
	 */

	u16 reg_short;

	pr_debug("%s: Marvell 88E1112 Ethernet\n", __func__);

	/* Set access to Page 2 */
	phy_write(phy, 0x16, 0x0002);

	phy_write(phy, 0x00, 0x0040); /* 1Gbps */
	reg_short = (u16)(phy_read(phy, 0x1a));
	reg_short |= 0x8000; /* bypass Auto-Negotiation */
	phy_write(phy, 0x1a, reg_short);
	emac_mii_reset_phy(phy); /* reset MAC interface */

	/* Reset access to Page 0 */
	phy_write(phy, 0x16, 0x0000);

	return  0;
}

static int et1011c_init(struct mii_phy *phy)
{
	u16 reg_short;
@@ -384,11 +452,27 @@ static struct mii_phy_def m88e1111_phy_def = {
	.ops		= &m88e1111_phy_ops,
};

static struct mii_phy_ops m88e1112_phy_ops = {
	.init		= m88e1112_init,
	.setup_aneg	= genmii_setup_aneg,
	.setup_forced	= genmii_setup_forced,
	.poll_link	= genmii_poll_link,
	.read_link	= genmii_read_link
};

static struct mii_phy_def m88e1112_phy_def = {
	.phy_id		= 0x01410C90,
	.phy_id_mask	= 0x0ffffff0,
	.name		= "Marvell 88E1112 Ethernet",
	.ops		= &m88e1112_phy_ops,
};

static struct mii_phy_def *mii_phy_table[] = {
	&et1011c_phy_def,
	&cis8201_phy_def,
	&bcm5248_phy_def,
	&m88e1111_phy_def,
	&m88e1112_phy_def,
	&genmii_phy_def,
	NULL
};
+2 −0
Original line number Diff line number Diff line
@@ -57,6 +57,7 @@ struct mii_phy {
				   or determined automaticaly */
	int address;		/* PHY address */
	int mode;		/* PHY mode */
	int gpcs_address;	/* GPCS PHY address */

	/* 1: autoneg enabled, 0: disabled */
	int autoneg;
@@ -81,5 +82,6 @@ struct mii_phy {
 */
int emac_mii_phy_probe(struct mii_phy *phy, int address);
int emac_mii_reset_phy(struct mii_phy *phy);
int emac_mii_reset_gpcs(struct mii_phy *phy);

#endif /* __IBM_NEWEMAC_PHY_H */