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

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

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?

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.

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/
participants (2)
-
Brilliantov Kirill Vladimirovich
-
Tom Rini