[U-Boot-Users] [PATCH 4/6 part 8] PHY support for QE

Jiang Bo-r61859 tanya.jiang at freescale.com
Thu Aug 17 14:28:50 CEST 2006


Subject: [PATCH] PHY support for QE

---

 drivers/sysdev/qe_lib/ucc/ucc_geth_phy.c |  568
++++++++++++++++++++++++++++++
 drivers/sysdev/qe_lib/ucc/ucc_geth_phy.h |  262 ++++++++++++++
 2 files changed, 830 insertions(+), 0 deletions(-)
 create mode 100644 drivers/sysdev/qe_lib/ucc/ucc_geth_phy.c
 create mode 100644 drivers/sysdev/qe_lib/ucc/ucc_geth_phy.h

e066a4f092e8a4812983e0ff5fde933c4727e354
diff --git a/drivers/sysdev/qe_lib/ucc/ucc_geth_phy.c
b/drivers/sysdev/qe_lib/ucc/ucc_geth_phy.c
new file mode 100644
index 0000000..7cf725b
--- /dev/null
+++ b/drivers/sysdev/qe_lib/ucc/ucc_geth_phy.c
@@ -0,0 +1,568 @@
+/*
+ * drivers/sysdev/qe_lib/ucc/ucc_geth_phy.c
+ *
+ * UCC GETH Driver -- PHY handling
+ * Driver for UEC on QE
+ * Based on 8260_io/fcc_enet.c
+ *
+ * Copyright (c) 2002-2006 Freescale Semiconductor, Inc.
+ * Author: Shlomi Gridish
+ * Maintainer: Kumar Gala (kumar.gala at freescale.com)
+ *
+ * History:
+ * 20060601 tanya jiang (tanya.jiang at freescale.com)
+ *	    Code style fixed; move from cpu/mpc83xx to drivers/sysdev
+ *
+ * This program is free software; you can redistribute  it and/or
modify it
+ * under  the terms of  the GNU General  Public License as published by
the
+ * Free Software Foundation;  either version 2 of the  License, or (at
your
+ * option) any later version.
+ */
+
+#include "common.h"
+#include "net.h"
+#include "malloc.h"
+#include "list.h"
+#include "asm/errno.h"
+#include "immap_qe.h"
+#include "qe.h"
+#include "asm/io.h"
+#include "ucc.h"
+#include "ucc_fast.h"
+#include "ucc_geth.h"
+#include "ucc_geth_phy.h"
+
+#include "miiphy.h"
+
+#define UGETH_VERBOSE_DEBUG
+#define ugphy_printk(format, arg...)  \
+        printf(format "\n", ## arg)
+
+#define ugphy_dbg(format, arg...)            \
+        ugphy_printk(format , ## arg)
+#define ugphy_err(format, arg...)            \
+        ugphy_printk(format , ## arg)
+#define ugphy_info(format, arg...)           \
+        ugphy_printk(format , ## arg)
+#define ugphy_warn(format, arg...)           \
+        ugphy_printk(format , ## arg)
+
+#ifdef UGETH_VERBOSE_DEBUG
+#define ugphy_vdbg ugphy_dbg
+#else
+#define ugphy_vdbg(ugeth, fmt, args...) do { } while (0)
+#endif				/* UGETH_VERBOSE_DEBUG */
+
+static void config_genmii_advert(struct ugeth_mii_info *mii_info);
+static void genmii_setup_forced(struct ugeth_mii_info *mii_info);
+static void genmii_restart_aneg(struct ugeth_mii_info *mii_info);
+static int gbit_config_aneg(struct ugeth_mii_info *mii_info);
+static int genmii_config_aneg(struct ugeth_mii_info *mii_info);
+static int genmii_update_link(struct ugeth_mii_info *mii_info);
+static int genmii_read_status(struct ugeth_mii_info *mii_info);
+u16 phy_read(struct ugeth_mii_info *mii_info, u16 regnum);
+void phy_write(struct ugeth_mii_info *mii_info, u16 regnum, u16 val);
+
+/* Write value to the PHY for this device to the register at regnum, */
+/* waiting until the write is done before it returns.  All PHY */
+/* configuration has to be done through the TSEC1 MIIM regs */
+void write_phy_reg(struct eth_device *dev, int mii_id, int regnum, int
value)
+{
+	ucc_geth_private_t *ugeth = (ucc_geth_private_t *) dev->priv;
+	ucc_geth_t *ug_regs;
+	enet_tbi_mii_reg_e mii_reg = (enet_tbi_mii_reg_e) regnum;
+	u32 tmp_reg;
+
+	ug_regs = ugeth->ug_regs;
+
+	/* Stop the MII management read cycle */
+	out_be32(&ug_regs->miimcom, 0);
+	/* Setting up the MII Mangement Address Register */
+	tmp_reg = ((u32) mii_id << MIIMADD_PHY_ADDRESS_SHIFT) | mii_reg;
+	out_be32(&ug_regs->miimadd, tmp_reg);
+
+	/* Setting up the MII Mangement Control Register with the value
*/
+	out_be32(&ug_regs->miimcon, (u32) value);
+
+	/* Wait till MII management write is complete */
+	while ((in_be32(&ug_regs->miimind)) & MIIMIND_BUSY) ;
+
+	udelay(100000);
+}
+
+/* Reads from register regnum in the PHY for device dev, */
+/* returning the value.  Clears miimcom first.  All PHY */
+/* configuration has to be done through the TSEC1 MIIM regs */
+int read_phy_reg(struct eth_device *dev, int mii_id, int regnum)
+{
+	ucc_geth_private_t *ugeth = (ucc_geth_private_t *) dev->priv;
+	ucc_geth_t *ug_regs;
+	enet_tbi_mii_reg_e mii_reg = (enet_tbi_mii_reg_e) regnum;
+	u32 tmp_reg;
+	u16 value;
+
+	ug_regs = ugeth->ug_regs;
+
+	/* Setting up the MII Mangement Address Register */
+	tmp_reg = ((u32) mii_id << MIIMADD_PHY_ADDRESS_SHIFT) | mii_reg;
+	out_be32(&ug_regs->miimadd, tmp_reg);
+
+	/* Perform an MII management read cycle */
+	out_be32(&ug_regs->miimcom, 0);
+	out_be32(&ug_regs->miimcom, MIIMCOM_READ_CYCLE);
+
+	/* Wait till MII management write is complete */
+	while ((in_be32(&ug_regs->miimind)) &
+	       (MIIMIND_NOT_VALID | MIIMIND_BUSY)) ;
+
+	udelay(100000);
+
+	/* Read MII management status  */
+	value = (u16) in_be32(&ug_regs->miimstat);
+	if (value == 0xffff)
+		ugphy_warn("read wrong value : mii_id %d,mii_reg %d,
base %08x",
+			   mii_id, mii_reg, (u32) & (ug_regs->miimcfg));
+
+	return (value);
+}
+
+void mii_clear_phy_interrupt(struct ugeth_mii_info *mii_info)
+{
+	if (mii_info->phyinfo->ack_interrupt)
+		mii_info->phyinfo->ack_interrupt(mii_info);
+}
+
+void mii_configure_phy_interrupt(struct ugeth_mii_info *mii_info,
+				 u32 interrupts)
+{
+	mii_info->interrupts = interrupts;
+	if (mii_info->phyinfo->config_intr)
+		mii_info->phyinfo->config_intr(mii_info);
+}
+
+/* Writes MII_ADVERTISE with the appropriate values, after
+ * sanitizing advertise to make sure only supported features
+ * are advertised
+ */
+static void config_genmii_advert(struct ugeth_mii_info *mii_info)
+{
+	u32 advertise;
+	u16 adv;
+
+	/* Only allow advertising what this PHY supports */
+	mii_info->advertising &= mii_info->phyinfo->features;
+	advertise = mii_info->advertising;
+
+	/* Setup standard advertisement */
+	adv = phy_read(mii_info, PHY_ANAR);
+	adv &= ~(ADVERTISE_ALL | ADVERTISE_100BASE4);
+	if (advertise & ADVERTISED_10baseT_Half)
+		adv |= ADVERTISE_10HALF;
+	if (advertise & ADVERTISED_10baseT_Full)
+		adv |= ADVERTISE_10FULL;
+	if (advertise & ADVERTISED_100baseT_Half)
+		adv |= ADVERTISE_100HALF;
+	if (advertise & ADVERTISED_100baseT_Full)
+		adv |= ADVERTISE_100FULL;
+	phy_write(mii_info, PHY_ANAR, adv);
+}
+
+static void genmii_setup_forced(struct ugeth_mii_info *mii_info)
+{
+	u16 ctrl;
+	u32 features = mii_info->phyinfo->features;
+
+	ctrl = phy_read(mii_info, PHY_BMCR);
+
+	ctrl &=
+	    ~(PHY_BMCR_DPLX | PHY_BMCR_100_MBPS | PHY_BMCR_1000_MBPS |
+	      PHY_BMCR_AUTON);
+	ctrl |= PHY_BMCR_RESET;
+
+	switch (mii_info->speed) {
+	case SPEED_1000:
+		if (features & (SUPPORTED_1000baseT_Half
+				| SUPPORTED_1000baseT_Full)) {
+			ctrl |= PHY_BMCR_1000_MBPS;
+			break;
+		}
+		mii_info->speed = SPEED_100;
+	case SPEED_100:
+		if (features & (SUPPORTED_100baseT_Half
+				| SUPPORTED_100baseT_Full)) {
+			ctrl |= PHY_BMCR_100_MBPS;
+			break;
+		}
+		mii_info->speed = SPEED_10;
+	case SPEED_10:
+		if (features & (SUPPORTED_10baseT_Half
+				| SUPPORTED_10baseT_Full))
+			break;
+	default:		/* Unsupported speed! */
+		ugphy_err("%s: Bad speed!", mii_info->dev->name);
+		break;
+	}
+
+	phy_write(mii_info, PHY_BMCR, ctrl);
+}
+
+/* Enable and Restart Autonegotiation */
+static void genmii_restart_aneg(struct ugeth_mii_info *mii_info)
+{
+	u16 ctl;
+
+	ctl = phy_read(mii_info, PHY_BMCR);
+	ctl |= (PHY_BMCR_AUTON | PHY_BMCR_RST_NEG);
+	phy_write(mii_info, PHY_BMCR, ctl);
+}
+
+static int gbit_config_aneg(struct ugeth_mii_info *mii_info)
+{
+	u16 adv;
+	u32 advertise;
+
+	if (mii_info->autoneg) {
+		/* Configure the ADVERTISE register */
+		config_genmii_advert(mii_info);
+		advertise = mii_info->advertising;
+
+		adv = phy_read(mii_info, MII_1000BASETCONTROL);
+		adv &= ~(MII_1000BASETCONTROL_FULLDUPLEXCAP |
+			 MII_1000BASETCONTROL_HALFDUPLEXCAP);
+		if (advertise & SUPPORTED_1000baseT_Half)
+			adv |= MII_1000BASETCONTROL_HALFDUPLEXCAP;
+		if (advertise & SUPPORTED_1000baseT_Full)
+			adv |= MII_1000BASETCONTROL_FULLDUPLEXCAP;
+		phy_write(mii_info, MII_1000BASETCONTROL, adv);
+
+		/* Start/Restart aneg */
+		genmii_restart_aneg(mii_info);
+	} else
+		genmii_setup_forced(mii_info);
+
+	return 0;
+}
+
+static int marvell_config_aneg(struct ugeth_mii_info *mii_info)
+{
+	/* The Marvell PHY has an errata which requires
+	 * that certain registers get written in order
+	 * to restart autonegotiation */
+	phy_write(mii_info, PHY_BMCR, PHY_BMCR_RESET);
+
+	phy_write(mii_info, 0x1d, 0x1f);
+	phy_write(mii_info, 0x1e, 0x200c);
+	phy_write(mii_info, 0x1d, 0x5);
+	phy_write(mii_info, 0x1e, 0);
+	phy_write(mii_info, 0x1e, 0x100);
+
+	gbit_config_aneg(mii_info);
+
+	return 0;
+}
+static int genmii_config_aneg(struct ugeth_mii_info *mii_info)
+{
+	if (mii_info->autoneg) {
+		config_genmii_advert(mii_info);
+		genmii_restart_aneg(mii_info);
+	} else
+		genmii_setup_forced(mii_info);
+
+	return 0;
+}
+
+static int genmii_update_link(struct ugeth_mii_info *mii_info)
+{
+	u16 status;
+
+	/* Do a fake read */
+	phy_read(mii_info, PHY_BMSR);
+
+	/* Read link and autonegotiation status */
+	status = phy_read(mii_info, PHY_BMSR);
+	if ((status & PHY_BMSR_LS) == 0)
+		mii_info->link = 0;
+	else
+		mii_info->link = 1;
+
+	/* If we are autonegotiating, and not done,
+	 * return an error */
+	if (mii_info->autoneg && !(status & PHY_BMSR_AUTN_COMP))
+		return -EAGAIN;
+
+	return 0;
+}
+
+static int genmii_read_status(struct ugeth_mii_info *mii_info)
+{
+	u16 status;
+	int err;
+
+	/* Update the link, but return if there
+	 * was an error */
+	err = genmii_update_link(mii_info);
+	if (err)
+		return err;
+
+	if (mii_info->autoneg) {
+		status = phy_read(mii_info, PHY_ANLPAR);
+
+		if (status & (PHY_ANLPAR_10FD | PHY_ANLPAR_TXFD))
+			mii_info->duplex = DUPLEX_FULL;
+		else
+			mii_info->duplex = DUPLEX_HALF;
+		if (status & (PHY_ANLPAR_TXFD | PHY_ANLPAR_TX))
+			mii_info->speed = SPEED_100;
+		else
+			mii_info->speed = SPEED_10;
+		mii_info->pause = 0;
+	}
+	/* On non-aneg, we assume what we put in BMCR is the speed,
+	 * though magic-aneg shouldn't prevent this case from occurring
+	 */
+
+	return 0;
+}
+static int marvell_read_status(struct ugeth_mii_info *mii_info)
+{
+	u16 status;
+	int err;
+
+	/* Update the link, but return if there
+	 * was an error */
+	err = genmii_update_link(mii_info);
+	if (err)
+		return err;
+
+	/* If the link is up, read the speed and duplex */
+	/* If we aren't autonegotiating, assume speeds
+	 * are as set */
+	if (mii_info->autoneg && mii_info->link) {
+		int speed;
+		status = phy_read(mii_info, MII_M1011_PHY_SPEC_STATUS);
+
+#if 0
+		/* If speed and duplex aren't resolved,
+		 * return an error.  Isn't this handled
+		 * by checking aneg?
+		 */
+		if ((status & MII_M1011_PHY_SPEC_STATUS_RESOLVED) == 0)
+			return -EAGAIN;
+#endif
+
+		/* Get the duplexity */
+		if (status & MII_M1011_PHY_SPEC_STATUS_FULLDUPLEX)
+			mii_info->duplex = DUPLEX_FULL;
+		else
+			mii_info->duplex = DUPLEX_HALF;
+
+		/* Get the speed */
+		speed = status & MII_M1011_PHY_SPEC_STATUS_SPD_MASK;
+		switch (speed) {
+		case MII_M1011_PHY_SPEC_STATUS_1000:
+			mii_info->speed = SPEED_1000;
+			break;
+		case MII_M1011_PHY_SPEC_STATUS_100:
+			mii_info->speed = SPEED_100;
+			break;
+		default:
+			mii_info->speed = SPEED_10;
+			break;
+		}
+		mii_info->pause = 0;
+	}
+
+	return 0;
+}
+
+static int marvell_ack_interrupt(struct ugeth_mii_info *mii_info)
+{
+	/* Clear the interrupts by reading the reg */
+	phy_read(mii_info, MII_M1011_IEVENT);
+
+	return 0;
+}
+
+static int marvell_config_intr(struct ugeth_mii_info *mii_info)
+{
+	if (mii_info->interrupts == MII_INTERRUPT_ENABLED)
+		phy_write(mii_info, MII_M1011_IMASK,
MII_M1011_IMASK_INIT);
+	else
+		phy_write(mii_info, MII_M1011_IMASK,
MII_M1011_IMASK_CLEAR);
+
+	return 0;
+}
+
+static int dm9161_init(struct ugeth_mii_info *mii_info)
+{
+	/* Reset the PHY */
+	phy_write(mii_info, PHY_BMCR,
+		  phy_read(mii_info, PHY_BMCR) | PHY_BMCR_RESET);
+	/* PHY and MAC connect */
+	phy_write(mii_info, PHY_BMCR,
+		  phy_read(mii_info, PHY_BMCR) & ~PHY_BMCR_ISO);
+#if CONFIG_RMII_MODE == 1
+	phy_write(mii_info, MII_DM9161_SCR, MII_DM9161_SCR_RMII_INIT);
+#else
+	phy_write(mii_info, MII_DM9161_SCR, MII_DM9161_SCR_INIT);
+#endif
+	config_genmii_advert(mii_info);
+	/* Start/restart aneg */
+	genmii_config_aneg(mii_info);
+
+	udelay(3000000);
+
+	return 0;
+}
+
+static int dm9161_config_aneg(struct ugeth_mii_info *mii_info)
+{
+	return 0;
+}
+
+static int dm9161_read_status(struct ugeth_mii_info *mii_info)
+{
+	u16 status;
+	int err;
+
+	/* Update the link, but return if there was an error */
+	err = genmii_update_link(mii_info);
+	if (err)
+		return err;
+	/* If the link is up, read the speed and duplex
+	   If we aren't autonegotiating assume speeds are as set */
+	if (mii_info->autoneg && mii_info->link) {
+		status = phy_read(mii_info, MII_DM9161_SCSR);
+		if (status & (MII_DM9161_SCSR_100F |
MII_DM9161_SCSR_100H))
+			mii_info->speed = SPEED_100;
+		else
+			mii_info->speed = SPEED_10;
+
+		if (status & (MII_DM9161_SCSR_100F |
MII_DM9161_SCSR_10F))
+			mii_info->duplex = DUPLEX_FULL;
+		else
+			mii_info->duplex = DUPLEX_HALF;
+	}
+
+	return 0;
+}
+
+static int dm9161_ack_interrupt(struct ugeth_mii_info *mii_info)
+{
+	/* Clear the interrupt by reading the reg */
+	phy_read(mii_info, MII_DM9161_INTR);
+
+	return 0;
+}
+
+static int dm9161_config_intr(struct ugeth_mii_info *mii_info)
+{
+	if (mii_info->interrupts == MII_INTERRUPT_ENABLED)
+		phy_write(mii_info, MII_DM9161_INTR,
MII_DM9161_INTR_INIT);
+	else
+		phy_write(mii_info, MII_DM9161_INTR,
MII_DM9161_INTR_STOP);
+
+	return 0;
+}
+
+static void dm9161_close(struct ugeth_mii_info *mii_info)
+{
+}
+
+static struct phy_info phy_info_dm9161 = {
+	.phy_id = 0x0181b880,
+	.phy_id_mask = 0x0ffffff0,
+	.name = "Davicom DM9161E",
+	.init = dm9161_init,
+	.config_aneg = dm9161_config_aneg,
+	.read_status = dm9161_read_status,
+	.close = dm9161_close,
+};
+
+static struct phy_info phy_info_dm9161a = {
+	.phy_id = 0x0181b8a0,
+	.phy_id_mask = 0x0ffffff0,
+	.name = "Davicom DM9161A",
+	.features = MII_BASIC_FEATURES,
+	.init = dm9161_init,
+	.config_aneg = dm9161_config_aneg,
+	.read_status = dm9161_read_status,
+	.ack_interrupt = dm9161_ack_interrupt,
+	.config_intr = dm9161_config_intr,
+	.close = dm9161_close,
+};
+
+static struct phy_info phy_info_marvell = {
+	.phy_id = 0x01410c00,
+	.phy_id_mask = 0xffffff00,
+	.name = "Marvell 88E11x1",
+	.features = MII_GBIT_FEATURES,
+	.config_aneg = &marvell_config_aneg,
+	.read_status = &marvell_read_status,
+	.ack_interrupt = &marvell_ack_interrupt,
+	.config_intr = &marvell_config_intr,
+};
+
+static struct phy_info phy_info_genmii = {
+	.phy_id = 0x00000000,
+	.phy_id_mask = 0x00000000,
+	.name = "Generic MII",
+	.features = MII_BASIC_FEATURES,
+	.config_aneg = genmii_config_aneg,
+	.read_status = genmii_read_status,
+};
+
+static struct phy_info *phy_info[] = {
+	&phy_info_dm9161,
+	&phy_info_dm9161a,
+	&phy_info_marvell,
+	&phy_info_genmii,
+	NULL
+};
+
+u16 phy_read(struct ugeth_mii_info *mii_info, u16 regnum)
+{
+	return mii_info->mdio_read(mii_info->dev, mii_info->mii_id,
regnum);
+}
+
+void phy_write(struct ugeth_mii_info *mii_info, u16 regnum, u16 val)
+{
+	mii_info->mdio_write(mii_info->dev, mii_info->mii_id, regnum,
val);
+}
+
+/* Use the PHY ID registers to determine what type of PHY is attached
+ * to device dev.  return a struct phy_info structure describing that
PHY
+ */
+struct phy_info *get_phy_info(struct ugeth_mii_info *mii_info)
+{
+	u16 phy_reg;
+	u32 phy_ID;
+	int i;
+	struct phy_info *theInfo = NULL;
+
+	/* Grab the bits from PHYIR1, and put them in the upper half */
+	phy_reg = phy_read(mii_info, PHY_PHYIDR1);
+	phy_ID = (phy_reg & 0xffff) << 16;
+
+	/* Grab the bits from PHYIR2, and put them in the lower half */
+	phy_reg = phy_read(mii_info, PHY_PHYIDR2);
+	phy_ID |= (phy_reg & 0xffff);
+
+	/* loop through all the known PHY types, and find one that */
+	/* matches the ID we read from the PHY. */
+	for (i = 0; phy_info[i]; i++)
+		if (phy_info[i]->phy_id == (phy_ID &
phy_info[i]->phy_id_mask)) {
+			theInfo = phy_info[i];
+			break;
+		}
+
+	/* This shouldn't happen, as we have generic PHY support */
+	if (theInfo == NULL) {
+		ugphy_info("geth: PHY id %x is not supported!", phy_ID);
+		return NULL;
+	} else {
+		ugphy_info("geth: PHY is %s (%x)", theInfo->name,
phy_ID);
+	}
+
+	return theInfo;
+}
diff --git a/drivers/sysdev/qe_lib/ucc/ucc_geth_phy.h
b/drivers/sysdev/qe_lib/ucc/ucc_geth_phy.h
new file mode 100644
index 0000000..a711116
--- /dev/null
+++ b/drivers/sysdev/qe_lib/ucc/ucc_geth_phy.h
@@ -0,0 +1,262 @@
+/*
+ * drivers/sysdev/qe_lib/ucc/ucc_geth_phy.h
+ *
+ * UCC GETH Driver Header File
+ *
+ * Copyright (c) 2002-2006 Freescale Semiconductor, Inc.
+ * Author: Shlomi Gridish
+ * Maintainer: Kumar Gala (kumar.gala at freescale.com)
+ *
+ * History:
+ * 20060601 tanya jiang (tanya.jiang at freescale.com)
+ *	    Code style fixed; move from cpu/mpc83xx to drivers/sysdev
+ *
+ * This program is free software; you can redistribute  it and/or
modify it
+ * under  the terms of  the GNU General  Public License as published by
the
+ * Free Software Foundation;  either version 2 of the  License, or (at
your
+ * option) any later version.
+ */
+#ifndef __UCC_GETH_PHY_H__
+#define __UCC_GETH_PHY_H__
+
+#define MII_end ((u32)-2)
+#define MII_read ((u32)-1)
+
+#define MIIMIND_BUSY            0x00000001
+#define MIIMIND_NOTVALID        0x00000004
+
+#define UGETH_AN_TIMEOUT        2000
+
+/* 1000BT control (Marvell & BCM54xx at least) */
+#define MII_1000BASETCONTROL                  0x09
+#define MII_1000BASETCONTROL_FULLDUPLEXCAP    0x0200
+#define MII_1000BASETCONTROL_HALFDUPLEXCAP    0x0100
+
+/* Cicada Extended Control Register 1 */
+#define MII_CIS8201_EXT_CON1        0x17
+#define MII_CIS8201_EXTCON1_INIT    0x0000
+
+/* Cicada Interrupt Mask Register */
+#define MII_CIS8201_IMASK           0x19
+#define MII_CIS8201_IMASK_IEN       0x8000
+#define MII_CIS8201_IMASK_SPEED     0x4000
+#define MII_CIS8201_IMASK_LINK      0x2000
+#define MII_CIS8201_IMASK_DUPLEX    0x1000
+#define MII_CIS8201_IMASK_MASK      0xf000
+
+/* Cicada Interrupt Status Register */
+#define MII_CIS8201_ISTAT           0x1a
+#define MII_CIS8201_ISTAT_STATUS    0x8000
+#define MII_CIS8201_ISTAT_SPEED     0x4000
+#define MII_CIS8201_ISTAT_LINK      0x2000
+#define MII_CIS8201_ISTAT_DUPLEX    0x1000
+
+/* Cicada Auxiliary Control/Status Register */
+#define MII_CIS8201_AUX_CONSTAT        0x1c
+#define MII_CIS8201_AUXCONSTAT_INIT    0x0004
+#define MII_CIS8201_AUXCONSTAT_DUPLEX  0x0020
+#define MII_CIS8201_AUXCONSTAT_SPEED   0x0018
+#define MII_CIS8201_AUXCONSTAT_GBIT    0x0010
+#define MII_CIS8201_AUXCONSTAT_100     0x0008
+
+/* 88E1011 PHY Status Register */
+#define MII_M1011_PHY_SPEC_STATUS               0x11
+#define MII_M1011_PHY_SPEC_STATUS_1000          0x8000
+#define MII_M1011_PHY_SPEC_STATUS_100           0x4000
+#define MII_M1011_PHY_SPEC_STATUS_SPD_MASK      0xc000
+#define MII_M1011_PHY_SPEC_STATUS_FULLDUPLEX    0x2000
+#define MII_M1011_PHY_SPEC_STATUS_RESOLVED      0x0800
+#define MII_M1011_PHY_SPEC_STATUS_LINK          0x0400
+
+#define MII_M1011_IEVENT                0x13
+#define MII_M1011_IEVENT_CLEAR          0x0000
+
+#define MII_M1011_IMASK                 0x12
+#define MII_M1011_IMASK_INIT            0x6400
+#define MII_M1011_IMASK_CLEAR           0x0000
+
+#define MII_DM9161_SCR                  0x10
+#define MII_DM9161_SCR_INIT             0x0610
+#define MII_DM9161_SCR_RMII_INIT	0x0710
+
+/* DM9161 Specified Configuration and Status Register */
+#define MII_DM9161_SCSR                 0x11
+#define MII_DM9161_SCSR_100F            0x8000
+#define MII_DM9161_SCSR_100H            0x4000
+#define MII_DM9161_SCSR_10F             0x2000
+#define MII_DM9161_SCSR_10H             0x1000
+
+/* DM9161 Interrupt Register */
+#define MII_DM9161_INTR                 0x15
+#define MII_DM9161_INTR_PEND            0x8000
+#define MII_DM9161_INTR_DPLX_MASK       0x0800
+#define MII_DM9161_INTR_SPD_MASK        0x0400
+#define MII_DM9161_INTR_LINK_MASK       0x0200
+#define MII_DM9161_INTR_MASK            0x0100
+#define MII_DM9161_INTR_DPLX_CHANGE     0x0010
+#define MII_DM9161_INTR_SPD_CHANGE      0x0008
+#define MII_DM9161_INTR_LINK_CHANGE     0x0004
+#define MII_DM9161_INTR_INIT            0x0000
+#define MII_DM9161_INTR_STOP    \
+	(MII_DM9161_INTR_DPLX_MASK | MII_DM9161_INTR_SPD_MASK \
+	 | MII_DM9161_INTR_LINK_MASK | MII_DM9161_INTR_MASK)
+
+/* DM9161 10BT Configuration/Status */
+#define MII_DM9161_10BTCSR              0x12
+#define MII_DM9161_10BTCSR_INIT         0x7800
+
+#define MII_BASIC_FEATURES	(SUPPORTED_10baseT_Half | \
+		                 SUPPORTED_10baseT_Full | \
+                		 SUPPORTED_100baseT_Half | \
+                 		 SUPPORTED_100baseT_Full | \
+		                 SUPPORTED_Autoneg | \
+                		 SUPPORTED_TP | \
+		                 SUPPORTED_MII)
+
+#define MII_GBIT_FEATURES	(MII_BASIC_FEATURES | \
+				SUPPORTED_1000baseT_Half | \
+				SUPPORTED_1000baseT_Full)
+
+#define MII_READ_COMMAND                0x00000001
+
+#define MII_INTERRUPT_DISABLED          0x0
+#define MII_INTERRUPT_ENABLED           0x1
+
+#define SPEED_10    10
+#define SPEED_100   100
+#define SPEED_1000  1000
+
+/* Duplex, half or full. */
+#define DUPLEX_HALF             0x00
+#define DUPLEX_FULL             0x01
+
+/* Indicates what features are supported by the interface. */
+#define SUPPORTED_10baseT_Half          (1 << 0)
+#define SUPPORTED_10baseT_Full          (1 << 1)
+#define SUPPORTED_100baseT_Half         (1 << 2)
+#define SUPPORTED_100baseT_Full         (1 << 3)
+#define SUPPORTED_1000baseT_Half        (1 << 4)
+#define SUPPORTED_1000baseT_Full        (1 << 5)
+#define SUPPORTED_Autoneg               (1 << 6)
+#define SUPPORTED_TP                    (1 << 7)
+#define SUPPORTED_AUI                   (1 << 8)
+#define SUPPORTED_MII                   (1 << 9)
+#define SUPPORTED_FIBRE                 (1 << 10)
+#define SUPPORTED_BNC                   (1 << 11)
+#define SUPPORTED_10000baseT_Full       (1 << 12)
+
+#define ADVERTISED_10baseT_Half         (1 << 0)
+#define ADVERTISED_10baseT_Full         (1 << 1)
+#define ADVERTISED_100baseT_Half        (1 << 2)
+#define ADVERTISED_100baseT_Full        (1 << 3)
+#define ADVERTISED_1000baseT_Half       (1 << 4)
+#define ADVERTISED_1000baseT_Full       (1 << 5)
+#define ADVERTISED_Autoneg              (1 << 6)
+#define ADVERTISED_TP                   (1 << 7)
+#define ADVERTISED_AUI                  (1 << 8)
+#define ADVERTISED_MII                  (1 << 9)
+#define ADVERTISED_FIBRE                (1 << 10)
+#define ADVERTISED_BNC                  (1 << 11)
+#define ADVERTISED_10000baseT_Full      (1 << 12)
+
+/* Advertisement control register. */
+#define ADVERTISE_SLCT          0x001f	/* Selector bits
*/
+#define ADVERTISE_CSMA          0x0001	/* Only selector supported
*/
+#define ADVERTISE_10HALF        0x0020	/* Try for 10mbps half-duplex
*/
+#define ADVERTISE_10FULL        0x0040	/* Try for 10mbps full-duplex
*/
+#define ADVERTISE_100HALF       0x0080	/* Try for 100mbps half-duplex
*/
+#define ADVERTISE_100FULL       0x0100	/* Try for 100mbps full-duplex
*/
+#define ADVERTISE_100BASE4      0x0200	/* Try for 100mbps 4k packets
*/
+#define ADVERTISE_RESV          0x1c00	/* Unused...
*/
+#define ADVERTISE_RFAULT        0x2000	/* Say we can detect faults
*/
+#define ADVERTISE_LPACK         0x4000	/* Ack link partners response
*/
+#define ADVERTISE_NPAGE         0x8000	/* Next page bit
*/
+
+#define ADVERTISE_FULL (ADVERTISE_100FULL | ADVERTISE_10FULL | \
+                        ADVERTISE_CSMA)
+#define ADVERTISE_ALL (ADVERTISE_10HALF | ADVERTISE_10FULL | \
+                       ADVERTISE_100HALF | ADVERTISE_100FULL)
+
+/* Taken from mii_if_info and sungem_phy.h */
+struct ugeth_mii_info {
+	/* Information about the PHY type */
+	/* And management functions */
+	struct phy_info *phyinfo;
+
+	struct eth_device *dev;
+
+	/* forced speed & duplex (no autoneg)
+	 * partner speed & duplex & pause (autoneg)
+	 */
+	int speed;
+	int duplex;
+	int pause;
+
+	/* The most recently read link state */
+	int link;
+
+	/* Enabled Interrupts */
+	u32 interrupts;
+
+	u32 advertising;
+	int autoneg;
+	int mii_id;
+
+	/* private data pointer */
+	/* For use by PHYs to maintain extra state */
+	void *priv;
+
+	/* Provided by ethernet driver */
+	int (*mdio_read) (struct eth_device * dev, int mii_id, int reg);
+	void (*mdio_write) (struct eth_device * dev, int mii_id, int
reg,
+			    int val);
+};
+
+/* struct phy_info: a structure which defines attributes for a PHY
+ *
+ * id will contain a number which represents the PHY.  During
+ * startup, the driver will poll the PHY to find out what its
+ * UID--as defined by registers 2 and 3--is.  The 32-bit result
+ * gotten from the PHY will be ANDed with phy_id_mask to
+ * discard any bits which may change based on revision numbers
+ * unimportant to functionality
+ *
+ * There are 6 commands which take a ugeth_mii_info structure.
+ * Each PHY must declare config_aneg, and read_status.
+ */
+struct phy_info {
+	u32 phy_id;
+	char *name;
+	unsigned int phy_id_mask;
+	u32 features;
+
+	/* Called to initialize the PHY */
+	int (*init) (struct ugeth_mii_info * mii_info);
+
+	/* Called to suspend the PHY for power */
+	int (*suspend) (struct ugeth_mii_info * mii_info);
+
+	/* Reconfigures autonegotiation (or disables it) */
+	int (*config_aneg) (struct ugeth_mii_info * mii_info);
+
+	/* Determines the negotiated speed and duplex */
+	int (*read_status) (struct ugeth_mii_info * mii_info);
+
+	/* Clears any pending interrupts */
+	int (*ack_interrupt) (struct ugeth_mii_info * mii_info);
+
+	/* Enables or disables interrupts */
+	int (*config_intr) (struct ugeth_mii_info * mii_info);
+
+	/* Clears up any memory if needed */
+	void (*close) (struct ugeth_mii_info * mii_info);
+};
+
+struct phy_info *get_phy_info(struct ugeth_mii_info *mii_info);
+void write_phy_reg(struct eth_device *dev, int mii_id, int regnum, int
value);
+int read_phy_reg(struct eth_device *dev, int mii_id, int regnum);
+void mii_clear_phy_interrupt(struct ugeth_mii_info *mii_info);
+void mii_configure_phy_interrupt(struct ugeth_mii_info *mii_info,
+				 u32 interrupts);
+
+#endif	/* __UCC_GETH_PHY_H__ */
-- 
1.3.GIT




More information about the U-Boot mailing list