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

Submitted by Brilliantov Kirill Vladimirovich on May 4, 2012, 10:58 a.m.

Details

Message ID 1336129094-396-1-git-send-email-brilliantov@byterg.ru
State Changes Requested
Delegated to: Tom Rini
Headers show

Commit Message

Brilliantov Kirill Vladimirovich May 4, 2012, 10:58 a.m.
added Marvell 88E1111 PHY support for Davinchi DM36x
tested on DM368ZCEF

 Signed-off-by: Brilliantov Kirill Vladimirovich
 <brilliantov@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

Comments

Tom Rini May 4, 2012, 4:58 p.m.
On 05/04/2012 03:58 AM, Brilliantov Kirill Vladimirovich wrote:

> added Marvell 88E1111 PHY support for Davinchi DM36x
> tested on DM368ZCEF
>
>   Signed-off-by: Brilliantov Kirill Vladimirovich
>   <brilliantov@byterg.ru>

OK, we really need the emac driver converted to phylib (which already 
has this PHY it looks like).  Any chance you would have time to try 
doing that?
Brilliantov Kirill Vladimirovich May 5, 2012, 6:55 a.m.
Tom Rini wrote on 05/04/2012 08:58 PM:

>
> OK, we really need the emac driver converted to phylib (which already
> has this PHY it looks like). Any chance you would have time to try doing
> that?
>

Tom, now I try modify driver/net/phy/marvell.c.
I add next defines in include/configs/davinci_dm365evn.h:
#define CONFIG_PHYLIB
#define CONFIG_PHY_MARVELL

After starting U-Boot I see initializing Marvell driver, but I don't see 
another functions, e.g. config or startup.

How can I link phylib and TI_EMAC?


Thank you and excuse me for my bad english.
Tom Rini May 7, 2012, 10:50 p.m.
On Fri, May 4, 2012 at 11:55 PM, Brilliantov Kirill Vladimirovich
<brilliantov@byterg.ru> wrote:
> Tom Rini wrote on 05/04/2012 08:58 PM:
>
>
>>
>> OK, we really need the emac driver converted to phylib (which already
>> has this PHY it looks like). Any chance you would have time to try doing
>> that?
>>
>
> Tom, now I try modify driver/net/phy/marvell.c.
> I add next defines in include/configs/davinci_dm365evn.h:
> #define CONFIG_PHYLIB
> #define CONFIG_PHY_MARVELL
>
> After starting U-Boot I see initializing Marvell driver, but I don't see
> another functions, e.g. config or startup.
>
> How can I link phylib and TI_EMAC?

The driver itself needs to be ported to PHYLIB.  When I talked with
others before about doing the conversion I was given the following
patches to look at, as examples of drivers implementing PHYLIB
support:
http://patchwork.ozlabs.org/patch/80589/
http://patchwork.ozlabs.org/patch/114793/

Patch hide | download patch | download mbox

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@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);
 	}