[U-Boot] [PATCH] davinci: added Marvell 88E1111 PHY support

Brilliantov Kirill Vladimirovich brilliantov at byterg.ru
Fri May 4 12:58:14 CEST 2012


added Marvell 88E1111 PHY support for Davinchi DM36x
tested on DM368ZCEF

 Signed-off-by: Brilliantov Kirill Vladimirovich
 <brilliantov at byterg.ru>

---
 arch/arm/cpu/arm926ejs/davinci/Makefile       |    1 +
 arch/arm/cpu/arm926ejs/davinci/marvell.c      |  232 +++++++++++++++++++++++++
 arch/arm/include/asm/arch-davinci/emac_defs.h |    6 +
 drivers/net/davinci_emac.c                    |   18 ++
 4 files changed, 257 insertions(+), 0 deletions(-)
 create mode 100644 arch/arm/cpu/arm926ejs/davinci/marvell.c

diff --git a/arch/arm/cpu/arm926ejs/davinci/Makefile b/arch/arm/cpu/arm926ejs/davinci/Makefile
index da7efac..687c58b 100644
--- a/arch/arm/cpu/arm926ejs/davinci/Makefile
+++ b/arch/arm/cpu/arm926ejs/davinci/Makefile
@@ -35,6 +35,7 @@ COBJS-$(CONFIG_SOC_DM644X)	+= dm644x.o
 COBJS-$(CONFIG_SOC_DM646X)	+= dm646x.o
 COBJS-$(CONFIG_SOC_DA850)	+= da850_pinmux.o
 COBJS-$(CONFIG_DRIVER_TI_EMAC)	+= lxt972.o dp83848.o et1011c.o ksz8873.o
+COBJS-$(CONFIG_DRIVER_TI_EMAC)	+= marvell.o
 
 ifdef CONFIG_SPL_BUILD
 COBJS-y	+= spl.o
diff --git a/arch/arm/cpu/arm926ejs/davinci/marvell.c b/arch/arm/cpu/arm926ejs/davinci/marvell.c
new file mode 100644
index 0000000..00e896a
--- /dev/null
+++ b/arch/arm/cpu/arm926ejs/davinci/marvell.c
@@ -0,0 +1,232 @@
+/*
+ * Marvel 88E1111 Driver for TI DaVinci (TMS320DM635) based boards.
+ *
+ * Copyright (C) 2011 Brilliantov Kirill Vladimirovich <brilliantov at byterg.ru>
+ * References: 88E1111 Datasheet Integrated 10/100/1000
+ *              Ultra Gigabit Ethernet Transceiver
+ * 		Doc. No. MV-S100649-00, Rev. F
+ * 		December, 3, 2004
+ * --------------------------------------------------------
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <miiphy.h>
+#include <net.h>
+#include <asm/arch/emac_defs.h>
+#include "../../../../../drivers/net/davinci_emac.h"
+
+#ifdef CONFIG_DRIVER_TI_EMAC
+
+#ifdef CONFIG_CMD_NET
+
+#define DEBUG		0
+#define DBG(f, a...)	\
+	do { \
+		if (DEBUG) \
+			printf("Marvell: " f "\n", ##a);\
+	} while (0)
+#define ERR(f, a...)	printf("Marvell: " f "\n", ##a)
+
+#define EXTENDED_PHY_SPECIFIC_STATUS_REGISTER	27
+
+int m88e1111_is_phy_connected(int phy_addr)
+{
+	u_int16_t id1 = 0, id2 = 0;
+
+	DBG("starting %s", __func__);
+
+	if (!davinci_eth_phy_read(phy_addr, MII_PHYSID1, &id1)) {
+		ERR("can't read register %d (MII_PHYSID1)", MII_PHYSID1);
+		return (0);
+	}
+
+	if (!davinci_eth_phy_read(phy_addr, MII_PHYSID2, &id2)) {
+		ERR("can't read register %d (MII_PHYSID2)", MII_PHYSID2);
+		return (0);
+	}
+
+	DBG("ID1 %#x, ID2 %#x", id1, id2);
+
+	if ((id1 == 0x141) && ((id2 & 0xFFF0) == 0x0CC0))
+		return (1);
+
+	ERR("ID1 or ID2 not corrected");
+
+	return (0);
+}
+
+int m88e1111_get_link_speed(int phy_addr)
+{
+	u_int16_t val = 0;
+	volatile emac_regs *emac = (emac_regs *) EMAC_BASE_ADDR;
+
+	DBG("starting %s", __func__);
+
+	if (!davinci_eth_phy_read(phy_addr, MII_BMSR, &val)) {
+		ERR("can't read register %d (MII_BMSR)", MII_BMSR);
+		return (0);
+	}
+
+	if (!(val & BMSR_LSTATUS)) {
+		ERR("link down");
+		return (0);
+	}
+	DBG("link up");
+
+	if (!davinci_eth_phy_read(phy_addr, MII_BMCR, &val)) {
+		ERR("can't read register %d (MII_BMCR)", MII_BMCR);
+		return (0);
+	}
+
+	emac->MACCONTROL = EMAC_MACCONTROL_MIIEN_ENABLE;
+	if (val & BMCR_FULLDPLX)
+		emac->MACCONTROL |= EMAC_MACCONTROL_FULLDUPLEX_ENABLE;
+	DBG("set emac in %s duplex mode",
+		val & BMCR_FULLDPLX ? "full" : "half");
+
+	return (1);
+}
+
+int m88e1111_auto_negotiate(int phy_addr)
+{
+	u_int16_t val = 0;
+
+	DBG("starting %s", __func__);
+
+#if defined(CONFIG_SOC_DM365)
+	/* disable 1000Mb/s auto-negotination */
+	if (!davinci_eth_phy_read(phy_addr, MII_CTRL1000, &val)) {
+		ERR("can't read register %d (MII_CTRL1000)", MII_CTRL1000);
+		return (0);
+	}
+
+	if (!davinci_eth_phy_write(phy_addr, MII_CTRL1000,
+			val & (~(ADVERTISE_1000FULL | ADVERTISE_1000HALF)))) {
+		ERR("can't disable 1000Mb/s autonegotiation");
+		return (0);
+	}
+	DBG("1000Mb/s autonegotiation disabled");
+#endif
+
+	if (!davinci_eth_phy_read(phy_addr, MII_ADVERTISE, &val)) {
+		ERR("can't read register %d (MII_ADVERTISE)", MII_ADVERTISE);
+		return (0);
+	}
+
+	val |= (ADVERTISE_100FULL | ADVERTISE_100HALF |
+		ADVERTISE_10FULL | ADVERTISE_10HALF);
+	if (!davinci_eth_phy_write(phy_addr, MII_ADVERTISE, val)) {
+		ERR("can't set 100Mb/s autonegotiation");
+		return (0);
+	}
+
+	if (!davinci_eth_phy_read(phy_addr, MII_BMCR, &val)) {
+		ERR("can't read register %d (MII_BMCR)", MII_BMCR);
+		return (0);
+	}
+
+	davinci_eth_phy_write(phy_addr, MII_BMCR, val | BMCR_RESET);
+
+	/* TODO: very long time on auto-negotiation */
+	udelay(2000000);
+	if (!davinci_eth_phy_read(phy_addr, MII_BMSR, &val)) {
+		ERR("can't read register %d (MII_BMSR)", MII_BMSR);
+		return (0);
+	}
+
+	if (DEBUG) {
+		u_int8_t i;
+		u_int16_t v = 0;
+
+		for (i = 0; i < 32; i++) {
+			davinci_eth_phy_read(phy_addr, i, &v);
+			printf("Register %d: value %#x\n", i, v);
+		}
+	}
+
+	if (!(val & BMSR_ANEGCOMPLETE)) {
+		ERR("autonegotiation not completed");
+		return (0);
+	}
+	DBG("autonegotiation completed");
+
+	return (m88e1111_get_link_speed(phy_addr));
+}
+
+int m88e1111_init_phy(int phy_addr)
+{
+	int ret = 1;
+	u_int16_t val = 0;
+
+	DBG("starting %s", __func__);
+
+	if (!davinci_eth_phy_read(phy_addr, MII_BMCR, &val)) {
+		ERR("can't read register %d (MII_BMCR)", MII_BMCR);
+		return(0);
+	}
+
+	if (!davinci_eth_phy_write(phy_addr, MII_BMCR, val | BMCR_RESET)) {
+		ERR("can't set soft reset");
+		return(0);
+	}
+
+	udelay(20000);
+	if (!davinci_eth_phy_read(phy_addr, MII_BMCR, &val)) {
+		ERR("can't read register %d (MII_BMCR)", MII_BMCR);
+		return(0);
+	}
+	while (val & BMCR_RESET) {
+		udelay(10000);
+		davinci_eth_phy_read(phy_addr, MII_BMCR, &val);
+	}
+
+#if defined(CONFIG_SOC_DM365)
+	if (!davinci_eth_phy_read(phy_addr,
+				EXTENDED_PHY_SPECIFIC_STATUS_REGISTER, &val)) {
+		ERR("can't read register %d (Extended PHY Status)",
+			EXTENDED_PHY_SPECIFIC_STATUS_REGISTER);
+		return (0);
+	}
+	if (!davinci_eth_phy_write(phy_addr,
+				EXTENDED_PHY_SPECIFIC_STATUS_REGISTER,
+				val | 0xF)) {
+		ERR("can't set GMII to cooper mode");
+		return (0);
+	}
+	DBG("hardware configred set in GMII to cooper mode");
+
+	if (!m88e1111_auto_negotiate(phy_addr))
+		ret = m88e1111_auto_negotiate(phy_addr);
+#else
+	if (!m88e1111_get_link_speed(phy_addr))
+		ret = m88e1111_get_link_speed(phy_addr);
+#endif
+
+	return (ret);
+}
+
+
+
+#endif	/* CONFIG_CMD_NET */
+
+#endif	/* CONFIG_DRIVER_ETHER */
+
+/* vim: set noet sw=8 ts=8: */
diff --git a/arch/arm/include/asm/arch-davinci/emac_defs.h b/arch/arm/include/asm/arch-davinci/emac_defs.h
index 8a17de9..5f27600 100644
--- a/arch/arm/include/asm/arch-davinci/emac_defs.h
+++ b/arch/arm/include/asm/arch-davinci/emac_defs.h
@@ -105,4 +105,10 @@ int dp83848_auto_negotiate(int phy_addr);
 #define PHY_ET1011C	(0x282f013)
 int et1011c_get_link_speed(int phy_addr);
 
+#define PHY_M88E1111 (0x1410CC2)
+int m88e1111_is_phy_connected(int phy_addr);
+int m88e1111_get_link_speed(int phy_addr);
+int m88e1111_init_phy(int phy_addr);
+int m88e1111_auto_negotiate(int phy_addr);
+
 #endif  /* _DM644X_EMAC_H_ */
diff --git a/drivers/net/davinci_emac.c b/drivers/net/davinci_emac.c
index fbd0f1b..fdca1ae 100644
--- a/drivers/net/davinci_emac.c
+++ b/drivers/net/davinci_emac.c
@@ -881,6 +881,16 @@ int davinci_emac_initialize(void)
 			phy[i].auto_negotiate = gen_auto_negotiate;
 			break;
 #endif
+#ifdef PHY_M88E1111
+		case PHY_M88E1111:
+			sprintf(phy[i].name, "MARVELL88E1111 @ 0x%02x",
+				active_phy_addr[i]);
+			    phy[i].init = m88e1111_init_phy;
+			    phy[i].is_phy_connected = m88e1111_is_phy_connected;
+			    phy[i].get_link_speed = m88e1111_get_link_speed;
+			    phy[i].auto_negotiate = m88e1111_auto_negotiate;
+			break;
+#endif
 		default:
 			sprintf(phy[i].name, "GENERIC @ 0x%02x",
 						active_phy_addr[i]);
@@ -892,6 +902,14 @@ int davinci_emac_initialize(void)
 
 		debug("Ethernet PHY: %s\n", phy[i].name);
 
+#if defined(PHY_M88E1111) && defined(CONFIG_SOC_DM365)
+		/* I always get 1000Mb/s without this */
+		if (PHY_M88E1111 == phy_id) {
+			if (!phy[i].init(active_phy_addr[i]))
+				return(0);
+		}
+#endif
+
 		miiphy_register(phy[i].name, davinci_mii_phy_read,
 						davinci_mii_phy_write);
 	}
-- 
1.7.9



More information about the U-Boot mailing list