1*83d290c5STom Rini // SPDX-License-Identifier: GPL-2.0+
27737d5c6SDave Liu /*
32b21ec92SKumar Gala * Copyright (C) 2005,2010-2011 Freescale Semiconductor, Inc.
47737d5c6SDave Liu *
57737d5c6SDave Liu * Author: Shlomi Gridish
67737d5c6SDave Liu *
77737d5c6SDave Liu * Description: UCC GETH Driver -- PHY handling
87737d5c6SDave Liu * Driver for UEC on QE
97737d5c6SDave Liu * Based on 8260_io/fcc_enet.c
107737d5c6SDave Liu */
117737d5c6SDave Liu
12b5bf5cb3SMasahiro Yamada #include <common.h>
13b5bf5cb3SMasahiro Yamada #include <net.h>
14b5bf5cb3SMasahiro Yamada #include <malloc.h>
151221ce45SMasahiro Yamada #include <linux/errno.h>
16b5bf5cb3SMasahiro Yamada #include <linux/immap_qe.h>
17b5bf5cb3SMasahiro Yamada #include <asm/io.h>
187737d5c6SDave Liu #include "uccf.h"
197737d5c6SDave Liu #include "uec.h"
207737d5c6SDave Liu #include "uec_phy.h"
217737d5c6SDave Liu #include "miiphy.h"
222459afb1SQianyu Gong #include <fsl_qe.h>
23865ff856SAndy Fleming #include <phy.h>
247737d5c6SDave Liu
257737d5c6SDave Liu #define ugphy_printk(format, arg...) \
267737d5c6SDave Liu printf(format "\n", ## arg)
277737d5c6SDave Liu
287737d5c6SDave Liu #define ugphy_dbg(format, arg...) \
297737d5c6SDave Liu ugphy_printk(format , ## arg)
307737d5c6SDave Liu #define ugphy_err(format, arg...) \
317737d5c6SDave Liu ugphy_printk(format , ## arg)
327737d5c6SDave Liu #define ugphy_info(format, arg...) \
337737d5c6SDave Liu ugphy_printk(format , ## arg)
347737d5c6SDave Liu #define ugphy_warn(format, arg...) \
357737d5c6SDave Liu ugphy_printk(format , ## arg)
367737d5c6SDave Liu
377737d5c6SDave Liu #ifdef UEC_VERBOSE_DEBUG
387737d5c6SDave Liu #define ugphy_vdbg ugphy_dbg
397737d5c6SDave Liu #else
407737d5c6SDave Liu #define ugphy_vdbg(ugeth, fmt, args...) do { } while (0)
417737d5c6SDave Liu #endif /* UEC_VERBOSE_DEBUG */
427737d5c6SDave Liu
43edf3fe7dSRichard Retanubun /*--------------------------------------------------------------------+
44edf3fe7dSRichard Retanubun * Fixed PHY (PHY-less) support for Ethernet Ports.
45edf3fe7dSRichard Retanubun *
46a47a12beSStefan Roese * Copied from arch/powerpc/cpu/ppc4xx/4xx_enet.c
47edf3fe7dSRichard Retanubun *--------------------------------------------------------------------*/
48edf3fe7dSRichard Retanubun
49edf3fe7dSRichard Retanubun /*
501443cd7eSRichard Retanubun * Some boards do not have a PHY for each ethernet port. These ports are known
511443cd7eSRichard Retanubun * as Fixed PHY (or PHY-less) ports. For such ports, set the appropriate
521443cd7eSRichard Retanubun * CONFIG_SYS_UECx_PHY_ADDR equal to CONFIG_FIXED_PHY_ADDR (an unused address)
531443cd7eSRichard Retanubun * When the drver tries to identify the PHYs, CONFIG_FIXED_PHY will be returned
541443cd7eSRichard Retanubun * and the driver will search CONFIG_SYS_FIXED_PHY_PORTS to find what network
551443cd7eSRichard Retanubun * speed and duplex should be for the port.
56edf3fe7dSRichard Retanubun *
571443cd7eSRichard Retanubun * Example board header configuration file:
58edf3fe7dSRichard Retanubun * #define CONFIG_FIXED_PHY 0xFFFFFFFF
591443cd7eSRichard Retanubun * #define CONFIG_SYS_FIXED_PHY_ADDR 0x1E (pick an unused phy address)
60edf3fe7dSRichard Retanubun *
611443cd7eSRichard Retanubun * #define CONFIG_SYS_UEC1_PHY_ADDR CONFIG_SYS_FIXED_PHY_ADDR
621443cd7eSRichard Retanubun * #define CONFIG_SYS_UEC2_PHY_ADDR 0x02
631443cd7eSRichard Retanubun * #define CONFIG_SYS_UEC3_PHY_ADDR CONFIG_SYS_FIXED_PHY_ADDR
641443cd7eSRichard Retanubun * #define CONFIG_SYS_UEC4_PHY_ADDR 0x04
65edf3fe7dSRichard Retanubun *
661443cd7eSRichard Retanubun * #define CONFIG_SYS_FIXED_PHY_PORT(name,speed,duplex) \
671443cd7eSRichard Retanubun * {name, speed, duplex},
68edf3fe7dSRichard Retanubun *
69edf3fe7dSRichard Retanubun * #define CONFIG_SYS_FIXED_PHY_PORTS \
7078b7a8efSKim Phillips * CONFIG_SYS_FIXED_PHY_PORT("UEC0",SPEED_100,DUPLEX_FULL) \
7178b7a8efSKim Phillips * CONFIG_SYS_FIXED_PHY_PORT("UEC2",SPEED_100,DUPLEX_HALF)
72edf3fe7dSRichard Retanubun */
73edf3fe7dSRichard Retanubun
74edf3fe7dSRichard Retanubun #ifndef CONFIG_FIXED_PHY
75edf3fe7dSRichard Retanubun #define CONFIG_FIXED_PHY 0xFFFFFFFF /* Fixed PHY (PHY-less) */
76edf3fe7dSRichard Retanubun #endif
77edf3fe7dSRichard Retanubun
78edf3fe7dSRichard Retanubun #ifndef CONFIG_SYS_FIXED_PHY_PORTS
79edf3fe7dSRichard Retanubun #define CONFIG_SYS_FIXED_PHY_PORTS /* default is an empty array */
80edf3fe7dSRichard Retanubun #endif
81edf3fe7dSRichard Retanubun
82edf3fe7dSRichard Retanubun struct fixed_phy_port {
83f6add132SMike Frysinger char name[16]; /* ethernet port name */
84edf3fe7dSRichard Retanubun unsigned int speed; /* specified speed 10,100 or 1000 */
85edf3fe7dSRichard Retanubun unsigned int duplex; /* specified duplex FULL or HALF */
86edf3fe7dSRichard Retanubun };
87edf3fe7dSRichard Retanubun
88edf3fe7dSRichard Retanubun static const struct fixed_phy_port fixed_phy_port[] = {
89edf3fe7dSRichard Retanubun CONFIG_SYS_FIXED_PHY_PORTS /* defined in board configuration file */
90edf3fe7dSRichard Retanubun };
91edf3fe7dSRichard Retanubun
9223c34af4SRichard Retanubun /*--------------------------------------------------------------------+
9323c34af4SRichard Retanubun * BitBang MII support for ethernet ports
9423c34af4SRichard Retanubun *
9523c34af4SRichard Retanubun * Based from MPC8560ADS implementation
9623c34af4SRichard Retanubun *--------------------------------------------------------------------*/
9723c34af4SRichard Retanubun /*
9823c34af4SRichard Retanubun * Example board header file to define bitbang ethernet ports:
9923c34af4SRichard Retanubun *
10023c34af4SRichard Retanubun * #define CONFIG_SYS_BITBANG_PHY_PORT(name) name,
10178b7a8efSKim Phillips * #define CONFIG_SYS_BITBANG_PHY_PORTS CONFIG_SYS_BITBANG_PHY_PORT("UEC0")
10223c34af4SRichard Retanubun */
10323c34af4SRichard Retanubun #ifndef CONFIG_SYS_BITBANG_PHY_PORTS
10423c34af4SRichard Retanubun #define CONFIG_SYS_BITBANG_PHY_PORTS /* default is an empty array */
10523c34af4SRichard Retanubun #endif
10623c34af4SRichard Retanubun
10723c34af4SRichard Retanubun #if defined(CONFIG_BITBANGMII)
10823c34af4SRichard Retanubun static const char *bitbang_phy_port[] = {
10923c34af4SRichard Retanubun CONFIG_SYS_BITBANG_PHY_PORTS /* defined in board configuration file */
11023c34af4SRichard Retanubun };
11123c34af4SRichard Retanubun #endif /* CONFIG_BITBANGMII */
11223c34af4SRichard Retanubun
1137737d5c6SDave Liu static void config_genmii_advert (struct uec_mii_info *mii_info);
1147737d5c6SDave Liu static void genmii_setup_forced (struct uec_mii_info *mii_info);
1157737d5c6SDave Liu static void genmii_restart_aneg (struct uec_mii_info *mii_info);
1167737d5c6SDave Liu static int gbit_config_aneg (struct uec_mii_info *mii_info);
1177737d5c6SDave Liu static int genmii_config_aneg (struct uec_mii_info *mii_info);
1187737d5c6SDave Liu static int genmii_update_link (struct uec_mii_info *mii_info);
1197737d5c6SDave Liu static int genmii_read_status (struct uec_mii_info *mii_info);
12009c04c20SAndy Fleming u16 uec_phy_read(struct uec_mii_info *mii_info, u16 regnum);
12109c04c20SAndy Fleming void uec_phy_write(struct uec_mii_info *mii_info, u16 regnum, u16 val);
1227737d5c6SDave Liu
1237737d5c6SDave Liu /* Write value to the PHY for this device to the register at regnum, */
1247737d5c6SDave Liu /* waiting until the write is done before it returns. All PHY */
1257737d5c6SDave Liu /* configuration has to be done through the TSEC1 MIIM regs */
uec_write_phy_reg(struct eth_device * dev,int mii_id,int regnum,int value)126da9d4610SAndy Fleming void uec_write_phy_reg (struct eth_device *dev, int mii_id, int regnum, int value)
1277737d5c6SDave Liu {
1287737d5c6SDave Liu uec_private_t *ugeth = (uec_private_t *) dev->priv;
129da9d4610SAndy Fleming uec_mii_t *ug_regs;
1307737d5c6SDave Liu enet_tbi_mii_reg_e mii_reg = (enet_tbi_mii_reg_e) regnum;
1317737d5c6SDave Liu u32 tmp_reg;
1327737d5c6SDave Liu
13323c34af4SRichard Retanubun
13423c34af4SRichard Retanubun #if defined(CONFIG_BITBANGMII)
13523c34af4SRichard Retanubun u32 i = 0;
13623c34af4SRichard Retanubun
13723c34af4SRichard Retanubun for (i = 0; i < ARRAY_SIZE(bitbang_phy_port); i++) {
13823c34af4SRichard Retanubun if (strncmp(dev->name, bitbang_phy_port[i],
13923c34af4SRichard Retanubun sizeof(dev->name)) == 0) {
14023c34af4SRichard Retanubun (void)bb_miiphy_write(NULL, mii_id, regnum, value);
14123c34af4SRichard Retanubun return;
14223c34af4SRichard Retanubun }
14323c34af4SRichard Retanubun }
14423c34af4SRichard Retanubun #endif /* CONFIG_BITBANGMII */
14523c34af4SRichard Retanubun
146da9d4610SAndy Fleming ug_regs = ugeth->uec_mii_regs;
1477737d5c6SDave Liu
1487737d5c6SDave Liu /* Stop the MII management read cycle */
1497737d5c6SDave Liu out_be32 (&ug_regs->miimcom, 0);
1507737d5c6SDave Liu /* Setting up the MII Mangement Address Register */
1517737d5c6SDave Liu tmp_reg = ((u32) mii_id << MIIMADD_PHY_ADDRESS_SHIFT) | mii_reg;
1527737d5c6SDave Liu out_be32 (&ug_regs->miimadd, tmp_reg);
1537737d5c6SDave Liu
1547737d5c6SDave Liu /* Setting up the MII Mangement Control Register with the value */
1557737d5c6SDave Liu out_be32 (&ug_regs->miimcon, (u32) value);
156ee62ed32SKim Phillips sync();
1577737d5c6SDave Liu
1587737d5c6SDave Liu /* Wait till MII management write is complete */
1597737d5c6SDave Liu while ((in_be32 (&ug_regs->miimind)) & MIIMIND_BUSY);
1607737d5c6SDave Liu }
1617737d5c6SDave Liu
1627737d5c6SDave Liu /* Reads from register regnum in the PHY for device dev, */
1637737d5c6SDave Liu /* returning the value. Clears miimcom first. All PHY */
1647737d5c6SDave Liu /* configuration has to be done through the TSEC1 MIIM regs */
uec_read_phy_reg(struct eth_device * dev,int mii_id,int regnum)165da9d4610SAndy Fleming int uec_read_phy_reg (struct eth_device *dev, int mii_id, int regnum)
1667737d5c6SDave Liu {
1677737d5c6SDave Liu uec_private_t *ugeth = (uec_private_t *) dev->priv;
168da9d4610SAndy Fleming uec_mii_t *ug_regs;
1697737d5c6SDave Liu enet_tbi_mii_reg_e mii_reg = (enet_tbi_mii_reg_e) regnum;
1707737d5c6SDave Liu u32 tmp_reg;
1717737d5c6SDave Liu u16 value;
1727737d5c6SDave Liu
17323c34af4SRichard Retanubun
17423c34af4SRichard Retanubun #if defined(CONFIG_BITBANGMII)
17523c34af4SRichard Retanubun u32 i = 0;
17623c34af4SRichard Retanubun
17723c34af4SRichard Retanubun for (i = 0; i < ARRAY_SIZE(bitbang_phy_port); i++) {
17823c34af4SRichard Retanubun if (strncmp(dev->name, bitbang_phy_port[i],
17923c34af4SRichard Retanubun sizeof(dev->name)) == 0) {
18023c34af4SRichard Retanubun (void)bb_miiphy_read(NULL, mii_id, regnum, &value);
18123c34af4SRichard Retanubun return (value);
18223c34af4SRichard Retanubun }
18323c34af4SRichard Retanubun }
18423c34af4SRichard Retanubun #endif /* CONFIG_BITBANGMII */
18523c34af4SRichard Retanubun
186da9d4610SAndy Fleming ug_regs = ugeth->uec_mii_regs;
1877737d5c6SDave Liu
1887737d5c6SDave Liu /* Setting up the MII Mangement Address Register */
1897737d5c6SDave Liu tmp_reg = ((u32) mii_id << MIIMADD_PHY_ADDRESS_SHIFT) | mii_reg;
1907737d5c6SDave Liu out_be32 (&ug_regs->miimadd, tmp_reg);
1917737d5c6SDave Liu
192ee62ed32SKim Phillips /* clear MII management command cycle */
1937737d5c6SDave Liu out_be32 (&ug_regs->miimcom, 0);
194ee62ed32SKim Phillips sync();
195ee62ed32SKim Phillips
196ee62ed32SKim Phillips /* Perform an MII management read cycle */
1977737d5c6SDave Liu out_be32 (&ug_regs->miimcom, MIIMCOM_READ_CYCLE);
1987737d5c6SDave Liu
1997737d5c6SDave Liu /* Wait till MII management write is complete */
200dd520bf3SWolfgang Denk while ((in_be32 (&ug_regs->miimind)) &
201dd520bf3SWolfgang Denk (MIIMIND_NOT_VALID | MIIMIND_BUSY));
2027737d5c6SDave Liu
2037737d5c6SDave Liu /* Read MII management status */
2047737d5c6SDave Liu value = (u16) in_be32 (&ug_regs->miimstat);
2057737d5c6SDave Liu if (value == 0xffff)
20684a3047bSJoakim Tjernlund ugphy_vdbg
207dd520bf3SWolfgang Denk ("read wrong value : mii_id %d,mii_reg %d, base %08x",
2087737d5c6SDave Liu mii_id, mii_reg, (u32) & (ug_regs->miimcfg));
2097737d5c6SDave Liu
2107737d5c6SDave Liu return (value);
2117737d5c6SDave Liu }
2127737d5c6SDave Liu
mii_clear_phy_interrupt(struct uec_mii_info * mii_info)2137737d5c6SDave Liu void mii_clear_phy_interrupt (struct uec_mii_info *mii_info)
2147737d5c6SDave Liu {
2157737d5c6SDave Liu if (mii_info->phyinfo->ack_interrupt)
2167737d5c6SDave Liu mii_info->phyinfo->ack_interrupt (mii_info);
2177737d5c6SDave Liu }
2187737d5c6SDave Liu
mii_configure_phy_interrupt(struct uec_mii_info * mii_info,u32 interrupts)219dd520bf3SWolfgang Denk void mii_configure_phy_interrupt (struct uec_mii_info *mii_info,
220dd520bf3SWolfgang Denk u32 interrupts)
2217737d5c6SDave Liu {
2227737d5c6SDave Liu mii_info->interrupts = interrupts;
2237737d5c6SDave Liu if (mii_info->phyinfo->config_intr)
2247737d5c6SDave Liu mii_info->phyinfo->config_intr (mii_info);
2257737d5c6SDave Liu }
2267737d5c6SDave Liu
2277737d5c6SDave Liu /* Writes MII_ADVERTISE with the appropriate values, after
2287737d5c6SDave Liu * sanitizing advertise to make sure only supported features
2297737d5c6SDave Liu * are advertised
2307737d5c6SDave Liu */
config_genmii_advert(struct uec_mii_info * mii_info)2317737d5c6SDave Liu static void config_genmii_advert (struct uec_mii_info *mii_info)
2327737d5c6SDave Liu {
2337737d5c6SDave Liu u32 advertise;
2347737d5c6SDave Liu u16 adv;
2357737d5c6SDave Liu
2367737d5c6SDave Liu /* Only allow advertising what this PHY supports */
2377737d5c6SDave Liu mii_info->advertising &= mii_info->phyinfo->features;
2387737d5c6SDave Liu advertise = mii_info->advertising;
2397737d5c6SDave Liu
2407737d5c6SDave Liu /* Setup standard advertisement */
24109c04c20SAndy Fleming adv = uec_phy_read(mii_info, MII_ADVERTISE);
2427737d5c6SDave Liu adv &= ~(ADVERTISE_ALL | ADVERTISE_100BASE4);
2437737d5c6SDave Liu if (advertise & ADVERTISED_10baseT_Half)
2447737d5c6SDave Liu adv |= ADVERTISE_10HALF;
2457737d5c6SDave Liu if (advertise & ADVERTISED_10baseT_Full)
2467737d5c6SDave Liu adv |= ADVERTISE_10FULL;
2477737d5c6SDave Liu if (advertise & ADVERTISED_100baseT_Half)
2487737d5c6SDave Liu adv |= ADVERTISE_100HALF;
2497737d5c6SDave Liu if (advertise & ADVERTISED_100baseT_Full)
2507737d5c6SDave Liu adv |= ADVERTISE_100FULL;
25109c04c20SAndy Fleming uec_phy_write(mii_info, MII_ADVERTISE, adv);
2527737d5c6SDave Liu }
2537737d5c6SDave Liu
genmii_setup_forced(struct uec_mii_info * mii_info)2547737d5c6SDave Liu static void genmii_setup_forced (struct uec_mii_info *mii_info)
2557737d5c6SDave Liu {
2567737d5c6SDave Liu u16 ctrl;
2577737d5c6SDave Liu u32 features = mii_info->phyinfo->features;
2587737d5c6SDave Liu
25909c04c20SAndy Fleming ctrl = uec_phy_read(mii_info, MII_BMCR);
2607737d5c6SDave Liu
2618ef583a0SMike Frysinger ctrl &= ~(BMCR_FULLDPLX | BMCR_SPEED100 |
2628ef583a0SMike Frysinger BMCR_SPEED1000 | BMCR_ANENABLE);
2638ef583a0SMike Frysinger ctrl |= BMCR_RESET;
2647737d5c6SDave Liu
2657737d5c6SDave Liu switch (mii_info->speed) {
2667737d5c6SDave Liu case SPEED_1000:
2677737d5c6SDave Liu if (features & (SUPPORTED_1000baseT_Half
2687737d5c6SDave Liu | SUPPORTED_1000baseT_Full)) {
2698ef583a0SMike Frysinger ctrl |= BMCR_SPEED1000;
2707737d5c6SDave Liu break;
2717737d5c6SDave Liu }
2727737d5c6SDave Liu mii_info->speed = SPEED_100;
2737737d5c6SDave Liu case SPEED_100:
2747737d5c6SDave Liu if (features & (SUPPORTED_100baseT_Half
2757737d5c6SDave Liu | SUPPORTED_100baseT_Full)) {
2768ef583a0SMike Frysinger ctrl |= BMCR_SPEED100;
2777737d5c6SDave Liu break;
2787737d5c6SDave Liu }
2797737d5c6SDave Liu mii_info->speed = SPEED_10;
2807737d5c6SDave Liu case SPEED_10:
2817737d5c6SDave Liu if (features & (SUPPORTED_10baseT_Half
2827737d5c6SDave Liu | SUPPORTED_10baseT_Full))
2837737d5c6SDave Liu break;
2847737d5c6SDave Liu default: /* Unsupported speed! */
2857737d5c6SDave Liu ugphy_err ("%s: Bad speed!", mii_info->dev->name);
2867737d5c6SDave Liu break;
2877737d5c6SDave Liu }
2887737d5c6SDave Liu
28909c04c20SAndy Fleming uec_phy_write(mii_info, MII_BMCR, ctrl);
2907737d5c6SDave Liu }
2917737d5c6SDave Liu
2927737d5c6SDave Liu /* Enable and Restart Autonegotiation */
genmii_restart_aneg(struct uec_mii_info * mii_info)2937737d5c6SDave Liu static void genmii_restart_aneg (struct uec_mii_info *mii_info)
2947737d5c6SDave Liu {
2957737d5c6SDave Liu u16 ctl;
2967737d5c6SDave Liu
29709c04c20SAndy Fleming ctl = uec_phy_read(mii_info, MII_BMCR);
2988ef583a0SMike Frysinger ctl |= (BMCR_ANENABLE | BMCR_ANRESTART);
29909c04c20SAndy Fleming uec_phy_write(mii_info, MII_BMCR, ctl);
3007737d5c6SDave Liu }
3017737d5c6SDave Liu
gbit_config_aneg(struct uec_mii_info * mii_info)3027737d5c6SDave Liu static int gbit_config_aneg (struct uec_mii_info *mii_info)
3037737d5c6SDave Liu {
3047737d5c6SDave Liu u16 adv;
3057737d5c6SDave Liu u32 advertise;
3067737d5c6SDave Liu
3077737d5c6SDave Liu if (mii_info->autoneg) {
3087737d5c6SDave Liu /* Configure the ADVERTISE register */
3097737d5c6SDave Liu config_genmii_advert (mii_info);
3107737d5c6SDave Liu advertise = mii_info->advertising;
3117737d5c6SDave Liu
31209c04c20SAndy Fleming adv = uec_phy_read(mii_info, MII_CTRL1000);
3132b21ec92SKumar Gala adv &= ~(ADVERTISE_1000FULL |
3142b21ec92SKumar Gala ADVERTISE_1000HALF);
3157737d5c6SDave Liu if (advertise & SUPPORTED_1000baseT_Half)
3162b21ec92SKumar Gala adv |= ADVERTISE_1000HALF;
3177737d5c6SDave Liu if (advertise & SUPPORTED_1000baseT_Full)
3182b21ec92SKumar Gala adv |= ADVERTISE_1000FULL;
31909c04c20SAndy Fleming uec_phy_write(mii_info, MII_CTRL1000, adv);
3207737d5c6SDave Liu
3217737d5c6SDave Liu /* Start/Restart aneg */
3227737d5c6SDave Liu genmii_restart_aneg (mii_info);
3237737d5c6SDave Liu } else
3247737d5c6SDave Liu genmii_setup_forced (mii_info);
3257737d5c6SDave Liu
3267737d5c6SDave Liu return 0;
3277737d5c6SDave Liu }
3287737d5c6SDave Liu
marvell_config_aneg(struct uec_mii_info * mii_info)3297737d5c6SDave Liu static int marvell_config_aneg (struct uec_mii_info *mii_info)
3307737d5c6SDave Liu {
3317737d5c6SDave Liu /* The Marvell PHY has an errata which requires
3327737d5c6SDave Liu * that certain registers get written in order
3337737d5c6SDave Liu * to restart autonegotiation */
33409c04c20SAndy Fleming uec_phy_write(mii_info, MII_BMCR, BMCR_RESET);
3357737d5c6SDave Liu
33609c04c20SAndy Fleming uec_phy_write(mii_info, 0x1d, 0x1f);
33709c04c20SAndy Fleming uec_phy_write(mii_info, 0x1e, 0x200c);
33809c04c20SAndy Fleming uec_phy_write(mii_info, 0x1d, 0x5);
33909c04c20SAndy Fleming uec_phy_write(mii_info, 0x1e, 0);
34009c04c20SAndy Fleming uec_phy_write(mii_info, 0x1e, 0x100);
3417737d5c6SDave Liu
3427737d5c6SDave Liu gbit_config_aneg (mii_info);
3437737d5c6SDave Liu
3447737d5c6SDave Liu return 0;
3457737d5c6SDave Liu }
3467737d5c6SDave Liu
genmii_config_aneg(struct uec_mii_info * mii_info)3477737d5c6SDave Liu static int genmii_config_aneg (struct uec_mii_info *mii_info)
3487737d5c6SDave Liu {
3497737d5c6SDave Liu if (mii_info->autoneg) {
350f29c181cSJoakim Tjernlund /* Speed up the common case, if link is already up, speed and
351f29c181cSJoakim Tjernlund duplex match, skip auto neg as it already matches */
352f29c181cSJoakim Tjernlund if (!genmii_read_status(mii_info) && mii_info->link)
353f29c181cSJoakim Tjernlund if (mii_info->duplex == DUPLEX_FULL &&
354f29c181cSJoakim Tjernlund mii_info->speed == SPEED_100)
355f29c181cSJoakim Tjernlund if (mii_info->advertising &
356f29c181cSJoakim Tjernlund ADVERTISED_100baseT_Full)
357f29c181cSJoakim Tjernlund return 0;
358f29c181cSJoakim Tjernlund
3597737d5c6SDave Liu config_genmii_advert (mii_info);
3607737d5c6SDave Liu genmii_restart_aneg (mii_info);
3617737d5c6SDave Liu } else
3627737d5c6SDave Liu genmii_setup_forced (mii_info);
3637737d5c6SDave Liu
3647737d5c6SDave Liu return 0;
3657737d5c6SDave Liu }
3667737d5c6SDave Liu
genmii_update_link(struct uec_mii_info * mii_info)3677737d5c6SDave Liu static int genmii_update_link (struct uec_mii_info *mii_info)
3687737d5c6SDave Liu {
3697737d5c6SDave Liu u16 status;
3707737d5c6SDave Liu
371ee62ed32SKim Phillips /* Status is read once to clear old link state */
37209c04c20SAndy Fleming uec_phy_read(mii_info, MII_BMSR);
3737737d5c6SDave Liu
374ee62ed32SKim Phillips /*
375ee62ed32SKim Phillips * Wait if the link is up, and autonegotiation is in progress
376ee62ed32SKim Phillips * (ie - we're capable and it's not done)
377ee62ed32SKim Phillips */
37809c04c20SAndy Fleming status = uec_phy_read(mii_info, MII_BMSR);
3798ef583a0SMike Frysinger if ((status & BMSR_LSTATUS) && (status & BMSR_ANEGCAPABLE)
3808ef583a0SMike Frysinger && !(status & BMSR_ANEGCOMPLETE)) {
381ee62ed32SKim Phillips int i = 0;
3827737d5c6SDave Liu
3838ef583a0SMike Frysinger while (!(status & BMSR_ANEGCOMPLETE)) {
384ee62ed32SKim Phillips /*
385ee62ed32SKim Phillips * Timeout reached ?
386ee62ed32SKim Phillips */
387ee62ed32SKim Phillips if (i > UGETH_AN_TIMEOUT) {
388ee62ed32SKim Phillips mii_info->link = 0;
389ee62ed32SKim Phillips return 0;
390ee62ed32SKim Phillips }
391ee62ed32SKim Phillips
392f30b6154SKim Phillips i++;
393ee62ed32SKim Phillips udelay(1000); /* 1 ms */
39409c04c20SAndy Fleming status = uec_phy_read(mii_info, MII_BMSR);
395ee62ed32SKim Phillips }
396ee62ed32SKim Phillips mii_info->link = 1;
397ee62ed32SKim Phillips } else {
3988ef583a0SMike Frysinger if (status & BMSR_LSTATUS)
399ee62ed32SKim Phillips mii_info->link = 1;
400ee62ed32SKim Phillips else
401ee62ed32SKim Phillips mii_info->link = 0;
402ee62ed32SKim Phillips }
4037737d5c6SDave Liu
4047737d5c6SDave Liu return 0;
4057737d5c6SDave Liu }
4067737d5c6SDave Liu
genmii_read_status(struct uec_mii_info * mii_info)4077737d5c6SDave Liu static int genmii_read_status (struct uec_mii_info *mii_info)
4087737d5c6SDave Liu {
4097737d5c6SDave Liu u16 status;
4107737d5c6SDave Liu int err;
4117737d5c6SDave Liu
4127737d5c6SDave Liu /* Update the link, but return if there
4137737d5c6SDave Liu * was an error */
4147737d5c6SDave Liu err = genmii_update_link (mii_info);
4157737d5c6SDave Liu if (err)
4167737d5c6SDave Liu return err;
4177737d5c6SDave Liu
4187737d5c6SDave Liu if (mii_info->autoneg) {
41909c04c20SAndy Fleming status = uec_phy_read(mii_info, MII_STAT1000);
42091cdaa3aSAnton Vorontsov
42191cdaa3aSAnton Vorontsov if (status & (LPA_1000FULL | LPA_1000HALF)) {
42291cdaa3aSAnton Vorontsov mii_info->speed = SPEED_1000;
42391cdaa3aSAnton Vorontsov if (status & LPA_1000FULL)
42491cdaa3aSAnton Vorontsov mii_info->duplex = DUPLEX_FULL;
42591cdaa3aSAnton Vorontsov else
42691cdaa3aSAnton Vorontsov mii_info->duplex = DUPLEX_HALF;
42791cdaa3aSAnton Vorontsov } else {
42809c04c20SAndy Fleming status = uec_phy_read(mii_info, MII_LPA);
4297737d5c6SDave Liu
4308ef583a0SMike Frysinger if (status & (LPA_10FULL | LPA_100FULL))
4317737d5c6SDave Liu mii_info->duplex = DUPLEX_FULL;
4327737d5c6SDave Liu else
4337737d5c6SDave Liu mii_info->duplex = DUPLEX_HALF;
4348ef583a0SMike Frysinger if (status & (LPA_100FULL | LPA_100HALF))
4357737d5c6SDave Liu mii_info->speed = SPEED_100;
4367737d5c6SDave Liu else
4377737d5c6SDave Liu mii_info->speed = SPEED_10;
43891cdaa3aSAnton Vorontsov }
4397737d5c6SDave Liu mii_info->pause = 0;
4407737d5c6SDave Liu }
4417737d5c6SDave Liu /* On non-aneg, we assume what we put in BMCR is the speed,
4427737d5c6SDave Liu * though magic-aneg shouldn't prevent this case from occurring
4437737d5c6SDave Liu */
4447737d5c6SDave Liu
4457737d5c6SDave Liu return 0;
4467737d5c6SDave Liu }
4477737d5c6SDave Liu
bcm_init(struct uec_mii_info * mii_info)448300615dcSAnton Vorontsov static int bcm_init(struct uec_mii_info *mii_info)
449300615dcSAnton Vorontsov {
450300615dcSAnton Vorontsov struct eth_device *edev = mii_info->dev;
451300615dcSAnton Vorontsov uec_private_t *uec = edev->priv;
452300615dcSAnton Vorontsov
453300615dcSAnton Vorontsov gbit_config_aneg(mii_info);
454300615dcSAnton Vorontsov
455865ff856SAndy Fleming if ((uec->uec_info->enet_interface_type ==
456865ff856SAndy Fleming PHY_INTERFACE_MODE_RGMII_RXID) &&
457865ff856SAndy Fleming (uec->uec_info->speed == SPEED_1000)) {
458300615dcSAnton Vorontsov u16 val;
459300615dcSAnton Vorontsov int cnt = 50;
460300615dcSAnton Vorontsov
461300615dcSAnton Vorontsov /* Wait for aneg to complete. */
462300615dcSAnton Vorontsov do
46309c04c20SAndy Fleming val = uec_phy_read(mii_info, MII_BMSR);
4648ef583a0SMike Frysinger while (--cnt && !(val & BMSR_ANEGCOMPLETE));
465300615dcSAnton Vorontsov
466300615dcSAnton Vorontsov /* Set RDX clk delay. */
46709c04c20SAndy Fleming uec_phy_write(mii_info, 0x18, 0x7 | (7 << 12));
468300615dcSAnton Vorontsov
46909c04c20SAndy Fleming val = uec_phy_read(mii_info, 0x18);
470300615dcSAnton Vorontsov /* Set RDX-RXC skew. */
471300615dcSAnton Vorontsov val |= (1 << 8);
472300615dcSAnton Vorontsov val |= (7 | (7 << 12));
473300615dcSAnton Vorontsov /* Write bits 14:0. */
474300615dcSAnton Vorontsov val |= (1 << 15);
47509c04c20SAndy Fleming uec_phy_write(mii_info, 0x18, val);
476300615dcSAnton Vorontsov }
477300615dcSAnton Vorontsov
478300615dcSAnton Vorontsov return 0;
479300615dcSAnton Vorontsov }
480300615dcSAnton Vorontsov
uec_marvell_init(struct uec_mii_info * mii_info)48109c04c20SAndy Fleming static int uec_marvell_init(struct uec_mii_info *mii_info)
48241410eeeSHaiying Wang {
48341410eeeSHaiying Wang struct eth_device *edev = mii_info->dev;
48441410eeeSHaiying Wang uec_private_t *uec = edev->priv;
485865ff856SAndy Fleming phy_interface_t iface = uec->uec_info->enet_interface_type;
486582c55a0SHeiko Schocher int speed = uec->uec_info->speed;
48741410eeeSHaiying Wang
488865ff856SAndy Fleming if ((speed == SPEED_1000) &&
489865ff856SAndy Fleming (iface == PHY_INTERFACE_MODE_RGMII_ID ||
490865ff856SAndy Fleming iface == PHY_INTERFACE_MODE_RGMII_RXID ||
491865ff856SAndy Fleming iface == PHY_INTERFACE_MODE_RGMII_TXID)) {
49241410eeeSHaiying Wang int temp;
49341410eeeSHaiying Wang
49409c04c20SAndy Fleming temp = uec_phy_read(mii_info, MII_M1111_PHY_EXT_CR);
495865ff856SAndy Fleming if (iface == PHY_INTERFACE_MODE_RGMII_ID) {
4966185f80cSAnton Vorontsov temp |= MII_M1111_RX_DELAY | MII_M1111_TX_DELAY;
497865ff856SAndy Fleming } else if (iface == PHY_INTERFACE_MODE_RGMII_RXID) {
4986185f80cSAnton Vorontsov temp &= ~MII_M1111_TX_DELAY;
4996185f80cSAnton Vorontsov temp |= MII_M1111_RX_DELAY;
500865ff856SAndy Fleming } else if (iface == PHY_INTERFACE_MODE_RGMII_TXID) {
5016185f80cSAnton Vorontsov temp &= ~MII_M1111_RX_DELAY;
5026185f80cSAnton Vorontsov temp |= MII_M1111_TX_DELAY;
5036185f80cSAnton Vorontsov }
50409c04c20SAndy Fleming uec_phy_write(mii_info, MII_M1111_PHY_EXT_CR, temp);
50541410eeeSHaiying Wang
50609c04c20SAndy Fleming temp = uec_phy_read(mii_info, MII_M1111_PHY_EXT_SR);
50741410eeeSHaiying Wang temp &= ~MII_M1111_HWCFG_MODE_MASK;
50841410eeeSHaiying Wang temp |= MII_M1111_HWCFG_MODE_RGMII;
50909c04c20SAndy Fleming uec_phy_write(mii_info, MII_M1111_PHY_EXT_SR, temp);
51041410eeeSHaiying Wang
51109c04c20SAndy Fleming uec_phy_write(mii_info, MII_BMCR, BMCR_RESET);
51241410eeeSHaiying Wang }
51341410eeeSHaiying Wang
51441410eeeSHaiying Wang return 0;
51541410eeeSHaiying Wang }
51641410eeeSHaiying Wang
marvell_read_status(struct uec_mii_info * mii_info)5177737d5c6SDave Liu static int marvell_read_status (struct uec_mii_info *mii_info)
5187737d5c6SDave Liu {
5197737d5c6SDave Liu u16 status;
5207737d5c6SDave Liu int err;
5217737d5c6SDave Liu
5227737d5c6SDave Liu /* Update the link, but return if there
5237737d5c6SDave Liu * was an error */
5247737d5c6SDave Liu err = genmii_update_link (mii_info);
5257737d5c6SDave Liu if (err)
5267737d5c6SDave Liu return err;
5277737d5c6SDave Liu
5287737d5c6SDave Liu /* If the link is up, read the speed and duplex */
5297737d5c6SDave Liu /* If we aren't autonegotiating, assume speeds
5307737d5c6SDave Liu * are as set */
5317737d5c6SDave Liu if (mii_info->autoneg && mii_info->link) {
5327737d5c6SDave Liu int speed;
533dd520bf3SWolfgang Denk
53409c04c20SAndy Fleming status = uec_phy_read(mii_info, MII_M1011_PHY_SPEC_STATUS);
5357737d5c6SDave Liu
5367737d5c6SDave Liu /* Get the duplexity */
5377737d5c6SDave Liu if (status & MII_M1011_PHY_SPEC_STATUS_FULLDUPLEX)
5387737d5c6SDave Liu mii_info->duplex = DUPLEX_FULL;
5397737d5c6SDave Liu else
5407737d5c6SDave Liu mii_info->duplex = DUPLEX_HALF;
5417737d5c6SDave Liu
5427737d5c6SDave Liu /* Get the speed */
5437737d5c6SDave Liu speed = status & MII_M1011_PHY_SPEC_STATUS_SPD_MASK;
5447737d5c6SDave Liu switch (speed) {
5457737d5c6SDave Liu case MII_M1011_PHY_SPEC_STATUS_1000:
5467737d5c6SDave Liu mii_info->speed = SPEED_1000;
5477737d5c6SDave Liu break;
5487737d5c6SDave Liu case MII_M1011_PHY_SPEC_STATUS_100:
5497737d5c6SDave Liu mii_info->speed = SPEED_100;
5507737d5c6SDave Liu break;
5517737d5c6SDave Liu default:
5527737d5c6SDave Liu mii_info->speed = SPEED_10;
5537737d5c6SDave Liu break;
5547737d5c6SDave Liu }
5557737d5c6SDave Liu mii_info->pause = 0;
5567737d5c6SDave Liu }
5577737d5c6SDave Liu
5587737d5c6SDave Liu return 0;
5597737d5c6SDave Liu }
5607737d5c6SDave Liu
marvell_ack_interrupt(struct uec_mii_info * mii_info)5617737d5c6SDave Liu static int marvell_ack_interrupt (struct uec_mii_info *mii_info)
5627737d5c6SDave Liu {
5637737d5c6SDave Liu /* Clear the interrupts by reading the reg */
56409c04c20SAndy Fleming uec_phy_read(mii_info, MII_M1011_IEVENT);
5657737d5c6SDave Liu
5667737d5c6SDave Liu return 0;
5677737d5c6SDave Liu }
5687737d5c6SDave Liu
marvell_config_intr(struct uec_mii_info * mii_info)5697737d5c6SDave Liu static int marvell_config_intr (struct uec_mii_info *mii_info)
5707737d5c6SDave Liu {
5717737d5c6SDave Liu if (mii_info->interrupts == MII_INTERRUPT_ENABLED)
57209c04c20SAndy Fleming uec_phy_write(mii_info, MII_M1011_IMASK, MII_M1011_IMASK_INIT);
5737737d5c6SDave Liu else
57409c04c20SAndy Fleming uec_phy_write(mii_info, MII_M1011_IMASK,
57509c04c20SAndy Fleming MII_M1011_IMASK_CLEAR);
5767737d5c6SDave Liu
5777737d5c6SDave Liu return 0;
5787737d5c6SDave Liu }
5797737d5c6SDave Liu
dm9161_init(struct uec_mii_info * mii_info)5807737d5c6SDave Liu static int dm9161_init (struct uec_mii_info *mii_info)
5817737d5c6SDave Liu {
5827737d5c6SDave Liu /* Reset the PHY */
58309c04c20SAndy Fleming uec_phy_write(mii_info, MII_BMCR, uec_phy_read(mii_info, MII_BMCR) |
5848ef583a0SMike Frysinger BMCR_RESET);
5857737d5c6SDave Liu /* PHY and MAC connect */
58609c04c20SAndy Fleming uec_phy_write(mii_info, MII_BMCR, uec_phy_read(mii_info, MII_BMCR) &
5878ef583a0SMike Frysinger ~BMCR_ISOLATE);
588ee62ed32SKim Phillips
58909c04c20SAndy Fleming uec_phy_write(mii_info, MII_DM9161_SCR, MII_DM9161_SCR_INIT);
590ee62ed32SKim Phillips
5917737d5c6SDave Liu config_genmii_advert (mii_info);
5927737d5c6SDave Liu /* Start/restart aneg */
5937737d5c6SDave Liu genmii_config_aneg (mii_info);
5947737d5c6SDave Liu
5957737d5c6SDave Liu return 0;
5967737d5c6SDave Liu }
5977737d5c6SDave Liu
dm9161_config_aneg(struct uec_mii_info * mii_info)5987737d5c6SDave Liu static int dm9161_config_aneg (struct uec_mii_info *mii_info)
5997737d5c6SDave Liu {
6007737d5c6SDave Liu return 0;
6017737d5c6SDave Liu }
6027737d5c6SDave Liu
dm9161_read_status(struct uec_mii_info * mii_info)6037737d5c6SDave Liu static int dm9161_read_status (struct uec_mii_info *mii_info)
6047737d5c6SDave Liu {
6057737d5c6SDave Liu u16 status;
6067737d5c6SDave Liu int err;
6077737d5c6SDave Liu
6087737d5c6SDave Liu /* Update the link, but return if there was an error */
6097737d5c6SDave Liu err = genmii_update_link (mii_info);
6107737d5c6SDave Liu if (err)
6117737d5c6SDave Liu return err;
6127737d5c6SDave Liu /* If the link is up, read the speed and duplex
6137737d5c6SDave Liu If we aren't autonegotiating assume speeds are as set */
6147737d5c6SDave Liu if (mii_info->autoneg && mii_info->link) {
61509c04c20SAndy Fleming status = uec_phy_read(mii_info, MII_DM9161_SCSR);
6167737d5c6SDave Liu if (status & (MII_DM9161_SCSR_100F | MII_DM9161_SCSR_100H))
6177737d5c6SDave Liu mii_info->speed = SPEED_100;
6187737d5c6SDave Liu else
6197737d5c6SDave Liu mii_info->speed = SPEED_10;
6207737d5c6SDave Liu
6217737d5c6SDave Liu if (status & (MII_DM9161_SCSR_100F | MII_DM9161_SCSR_10F))
6227737d5c6SDave Liu mii_info->duplex = DUPLEX_FULL;
6237737d5c6SDave Liu else
6247737d5c6SDave Liu mii_info->duplex = DUPLEX_HALF;
6257737d5c6SDave Liu }
6267737d5c6SDave Liu
6277737d5c6SDave Liu return 0;
6287737d5c6SDave Liu }
6297737d5c6SDave Liu
dm9161_ack_interrupt(struct uec_mii_info * mii_info)6307737d5c6SDave Liu static int dm9161_ack_interrupt (struct uec_mii_info *mii_info)
6317737d5c6SDave Liu {
6327737d5c6SDave Liu /* Clear the interrupt by reading the reg */
63309c04c20SAndy Fleming uec_phy_read(mii_info, MII_DM9161_INTR);
6347737d5c6SDave Liu
6357737d5c6SDave Liu return 0;
6367737d5c6SDave Liu }
6377737d5c6SDave Liu
dm9161_config_intr(struct uec_mii_info * mii_info)6387737d5c6SDave Liu static int dm9161_config_intr (struct uec_mii_info *mii_info)
6397737d5c6SDave Liu {
6407737d5c6SDave Liu if (mii_info->interrupts == MII_INTERRUPT_ENABLED)
64109c04c20SAndy Fleming uec_phy_write(mii_info, MII_DM9161_INTR, MII_DM9161_INTR_INIT);
6427737d5c6SDave Liu else
64309c04c20SAndy Fleming uec_phy_write(mii_info, MII_DM9161_INTR, MII_DM9161_INTR_STOP);
6447737d5c6SDave Liu
6457737d5c6SDave Liu return 0;
6467737d5c6SDave Liu }
6477737d5c6SDave Liu
dm9161_close(struct uec_mii_info * mii_info)6487737d5c6SDave Liu static void dm9161_close (struct uec_mii_info *mii_info)
6497737d5c6SDave Liu {
6507737d5c6SDave Liu }
6517737d5c6SDave Liu
fixed_phy_aneg(struct uec_mii_info * mii_info)652edf3fe7dSRichard Retanubun static int fixed_phy_aneg (struct uec_mii_info *mii_info)
653edf3fe7dSRichard Retanubun {
654edf3fe7dSRichard Retanubun mii_info->autoneg = 0; /* Turn off auto negotiation for fixed phy */
655edf3fe7dSRichard Retanubun return 0;
656edf3fe7dSRichard Retanubun }
657edf3fe7dSRichard Retanubun
fixed_phy_read_status(struct uec_mii_info * mii_info)658edf3fe7dSRichard Retanubun static int fixed_phy_read_status (struct uec_mii_info *mii_info)
659edf3fe7dSRichard Retanubun {
660edf3fe7dSRichard Retanubun int i = 0;
661edf3fe7dSRichard Retanubun
662edf3fe7dSRichard Retanubun for (i = 0; i < ARRAY_SIZE(fixed_phy_port); i++) {
6631443cd7eSRichard Retanubun if (strncmp(mii_info->dev->name, fixed_phy_port[i].name,
6641443cd7eSRichard Retanubun strlen(mii_info->dev->name)) == 0) {
665edf3fe7dSRichard Retanubun mii_info->speed = fixed_phy_port[i].speed;
666edf3fe7dSRichard Retanubun mii_info->duplex = fixed_phy_port[i].duplex;
667edf3fe7dSRichard Retanubun mii_info->link = 1; /* Link is always UP */
668edf3fe7dSRichard Retanubun mii_info->pause = 0;
669edf3fe7dSRichard Retanubun break;
670edf3fe7dSRichard Retanubun }
671edf3fe7dSRichard Retanubun }
672edf3fe7dSRichard Retanubun return 0;
673edf3fe7dSRichard Retanubun }
674edf3fe7dSRichard Retanubun
smsc_config_aneg(struct uec_mii_info * mii_info)6758b69b563SHeiko Schocher static int smsc_config_aneg (struct uec_mii_info *mii_info)
6768b69b563SHeiko Schocher {
6778b69b563SHeiko Schocher return 0;
6788b69b563SHeiko Schocher }
6798b69b563SHeiko Schocher
smsc_read_status(struct uec_mii_info * mii_info)6808b69b563SHeiko Schocher static int smsc_read_status (struct uec_mii_info *mii_info)
6818b69b563SHeiko Schocher {
6828b69b563SHeiko Schocher u16 status;
6838b69b563SHeiko Schocher int err;
6848b69b563SHeiko Schocher
6858b69b563SHeiko Schocher /* Update the link, but return if there
6868b69b563SHeiko Schocher * was an error */
6878b69b563SHeiko Schocher err = genmii_update_link (mii_info);
6888b69b563SHeiko Schocher if (err)
6898b69b563SHeiko Schocher return err;
6908b69b563SHeiko Schocher
6918b69b563SHeiko Schocher /* If the link is up, read the speed and duplex */
6928b69b563SHeiko Schocher /* If we aren't autonegotiating, assume speeds
6938b69b563SHeiko Schocher * are as set */
6948b69b563SHeiko Schocher if (mii_info->autoneg && mii_info->link) {
6958b69b563SHeiko Schocher int val;
6968b69b563SHeiko Schocher
69709c04c20SAndy Fleming status = uec_phy_read(mii_info, 0x1f);
6988b69b563SHeiko Schocher val = (status & 0x1c) >> 2;
6998b69b563SHeiko Schocher
7008b69b563SHeiko Schocher switch (val) {
7018b69b563SHeiko Schocher case 1:
7028b69b563SHeiko Schocher mii_info->duplex = DUPLEX_HALF;
7038b69b563SHeiko Schocher mii_info->speed = SPEED_10;
7048b69b563SHeiko Schocher break;
7058b69b563SHeiko Schocher case 5:
7068b69b563SHeiko Schocher mii_info->duplex = DUPLEX_FULL;
7078b69b563SHeiko Schocher mii_info->speed = SPEED_10;
7088b69b563SHeiko Schocher break;
7098b69b563SHeiko Schocher case 2:
7108b69b563SHeiko Schocher mii_info->duplex = DUPLEX_HALF;
7118b69b563SHeiko Schocher mii_info->speed = SPEED_100;
7128b69b563SHeiko Schocher break;
7138b69b563SHeiko Schocher case 6:
7148b69b563SHeiko Schocher mii_info->duplex = DUPLEX_FULL;
7158b69b563SHeiko Schocher mii_info->speed = SPEED_100;
7168b69b563SHeiko Schocher break;
7178b69b563SHeiko Schocher }
7188b69b563SHeiko Schocher mii_info->pause = 0;
7198b69b563SHeiko Schocher }
7208b69b563SHeiko Schocher
7218b69b563SHeiko Schocher return 0;
7228b69b563SHeiko Schocher }
7238b69b563SHeiko Schocher
7247737d5c6SDave Liu static struct phy_info phy_info_dm9161 = {
7257737d5c6SDave Liu .phy_id = 0x0181b880,
7267737d5c6SDave Liu .phy_id_mask = 0x0ffffff0,
7277737d5c6SDave Liu .name = "Davicom DM9161E",
7287737d5c6SDave Liu .init = dm9161_init,
7297737d5c6SDave Liu .config_aneg = dm9161_config_aneg,
7307737d5c6SDave Liu .read_status = dm9161_read_status,
7317737d5c6SDave Liu .close = dm9161_close,
7327737d5c6SDave Liu };
7337737d5c6SDave Liu
7347737d5c6SDave Liu static struct phy_info phy_info_dm9161a = {
7357737d5c6SDave Liu .phy_id = 0x0181b8a0,
7367737d5c6SDave Liu .phy_id_mask = 0x0ffffff0,
7377737d5c6SDave Liu .name = "Davicom DM9161A",
7387737d5c6SDave Liu .features = MII_BASIC_FEATURES,
7397737d5c6SDave Liu .init = dm9161_init,
7407737d5c6SDave Liu .config_aneg = dm9161_config_aneg,
7417737d5c6SDave Liu .read_status = dm9161_read_status,
7427737d5c6SDave Liu .ack_interrupt = dm9161_ack_interrupt,
7437737d5c6SDave Liu .config_intr = dm9161_config_intr,
7447737d5c6SDave Liu .close = dm9161_close,
7457737d5c6SDave Liu };
7467737d5c6SDave Liu
7477737d5c6SDave Liu static struct phy_info phy_info_marvell = {
7487737d5c6SDave Liu .phy_id = 0x01410c00,
7497737d5c6SDave Liu .phy_id_mask = 0xffffff00,
7507737d5c6SDave Liu .name = "Marvell 88E11x1",
7517737d5c6SDave Liu .features = MII_GBIT_FEATURES,
75209c04c20SAndy Fleming .init = &uec_marvell_init,
7537737d5c6SDave Liu .config_aneg = &marvell_config_aneg,
7547737d5c6SDave Liu .read_status = &marvell_read_status,
7557737d5c6SDave Liu .ack_interrupt = &marvell_ack_interrupt,
7567737d5c6SDave Liu .config_intr = &marvell_config_intr,
7577737d5c6SDave Liu };
7587737d5c6SDave Liu
759300615dcSAnton Vorontsov static struct phy_info phy_info_bcm5481 = {
760300615dcSAnton Vorontsov .phy_id = 0x0143bca0,
761300615dcSAnton Vorontsov .phy_id_mask = 0xffffff0,
762300615dcSAnton Vorontsov .name = "Broadcom 5481",
763300615dcSAnton Vorontsov .features = MII_GBIT_FEATURES,
764300615dcSAnton Vorontsov .read_status = genmii_read_status,
765300615dcSAnton Vorontsov .init = bcm_init,
766300615dcSAnton Vorontsov };
767300615dcSAnton Vorontsov
768edf3fe7dSRichard Retanubun static struct phy_info phy_info_fixedphy = {
769edf3fe7dSRichard Retanubun .phy_id = CONFIG_FIXED_PHY,
770edf3fe7dSRichard Retanubun .phy_id_mask = CONFIG_FIXED_PHY,
771edf3fe7dSRichard Retanubun .name = "Fixed PHY",
772edf3fe7dSRichard Retanubun .config_aneg = fixed_phy_aneg,
773edf3fe7dSRichard Retanubun .read_status = fixed_phy_read_status,
774edf3fe7dSRichard Retanubun };
775edf3fe7dSRichard Retanubun
7768b69b563SHeiko Schocher static struct phy_info phy_info_smsclan8700 = {
7778b69b563SHeiko Schocher .phy_id = 0x0007c0c0,
7788b69b563SHeiko Schocher .phy_id_mask = 0xfffffff0,
7798b69b563SHeiko Schocher .name = "SMSC LAN8700",
7808b69b563SHeiko Schocher .features = MII_BASIC_FEATURES,
7818b69b563SHeiko Schocher .config_aneg = smsc_config_aneg,
7828b69b563SHeiko Schocher .read_status = smsc_read_status,
7838b69b563SHeiko Schocher };
7848b69b563SHeiko Schocher
7857737d5c6SDave Liu static struct phy_info phy_info_genmii = {
7867737d5c6SDave Liu .phy_id = 0x00000000,
7877737d5c6SDave Liu .phy_id_mask = 0x00000000,
7887737d5c6SDave Liu .name = "Generic MII",
7897737d5c6SDave Liu .features = MII_BASIC_FEATURES,
7907737d5c6SDave Liu .config_aneg = genmii_config_aneg,
7917737d5c6SDave Liu .read_status = genmii_read_status,
7927737d5c6SDave Liu };
7937737d5c6SDave Liu
7947737d5c6SDave Liu static struct phy_info *phy_info[] = {
7957737d5c6SDave Liu &phy_info_dm9161,
7967737d5c6SDave Liu &phy_info_dm9161a,
7977737d5c6SDave Liu &phy_info_marvell,
798300615dcSAnton Vorontsov &phy_info_bcm5481,
7998b69b563SHeiko Schocher &phy_info_smsclan8700,
800edf3fe7dSRichard Retanubun &phy_info_fixedphy,
8017737d5c6SDave Liu &phy_info_genmii,
8027737d5c6SDave Liu NULL
8037737d5c6SDave Liu };
8047737d5c6SDave Liu
uec_phy_read(struct uec_mii_info * mii_info,u16 regnum)80509c04c20SAndy Fleming u16 uec_phy_read(struct uec_mii_info *mii_info, u16 regnum)
8067737d5c6SDave Liu {
8077737d5c6SDave Liu return mii_info->mdio_read (mii_info->dev, mii_info->mii_id, regnum);
8087737d5c6SDave Liu }
8097737d5c6SDave Liu
uec_phy_write(struct uec_mii_info * mii_info,u16 regnum,u16 val)81009c04c20SAndy Fleming void uec_phy_write(struct uec_mii_info *mii_info, u16 regnum, u16 val)
8117737d5c6SDave Liu {
812dd520bf3SWolfgang Denk mii_info->mdio_write (mii_info->dev, mii_info->mii_id, regnum, val);
8137737d5c6SDave Liu }
8147737d5c6SDave Liu
8157737d5c6SDave Liu /* Use the PHY ID registers to determine what type of PHY is attached
8167737d5c6SDave Liu * to device dev. return a struct phy_info structure describing that PHY
8177737d5c6SDave Liu */
uec_get_phy_info(struct uec_mii_info * mii_info)818da9d4610SAndy Fleming struct phy_info *uec_get_phy_info (struct uec_mii_info *mii_info)
8197737d5c6SDave Liu {
8207737d5c6SDave Liu u16 phy_reg;
8217737d5c6SDave Liu u32 phy_ID;
8227737d5c6SDave Liu int i;
8237737d5c6SDave Liu struct phy_info *theInfo = NULL;
8247737d5c6SDave Liu
8257737d5c6SDave Liu /* Grab the bits from PHYIR1, and put them in the upper half */
82609c04c20SAndy Fleming phy_reg = uec_phy_read(mii_info, MII_PHYSID1);
8277737d5c6SDave Liu phy_ID = (phy_reg & 0xffff) << 16;
8287737d5c6SDave Liu
8297737d5c6SDave Liu /* Grab the bits from PHYIR2, and put them in the lower half */
83009c04c20SAndy Fleming phy_reg = uec_phy_read(mii_info, MII_PHYSID2);
8317737d5c6SDave Liu phy_ID |= (phy_reg & 0xffff);
8327737d5c6SDave Liu
8337737d5c6SDave Liu /* loop through all the known PHY types, and find one that */
8347737d5c6SDave Liu /* matches the ID we read from the PHY. */
8357737d5c6SDave Liu for (i = 0; phy_info[i]; i++)
8367737d5c6SDave Liu if (phy_info[i]->phy_id ==
8377737d5c6SDave Liu (phy_ID & phy_info[i]->phy_id_mask)) {
8387737d5c6SDave Liu theInfo = phy_info[i];
8397737d5c6SDave Liu break;
8407737d5c6SDave Liu }
8417737d5c6SDave Liu
8427737d5c6SDave Liu /* This shouldn't happen, as we have generic PHY support */
8437737d5c6SDave Liu if (theInfo == NULL) {
8447737d5c6SDave Liu ugphy_info ("UEC: PHY id %x is not supported!", phy_ID);
8457737d5c6SDave Liu return NULL;
8467737d5c6SDave Liu } else {
8477737d5c6SDave Liu ugphy_info ("UEC: PHY is %s (%x)", theInfo->name, phy_ID);
8487737d5c6SDave Liu }
8497737d5c6SDave Liu
8507737d5c6SDave Liu return theInfo;
8517737d5c6SDave Liu }
8527737d5c6SDave Liu
marvell_phy_interface_mode(struct eth_device * dev,phy_interface_t type,int speed)853865ff856SAndy Fleming void marvell_phy_interface_mode(struct eth_device *dev, phy_interface_t type,
854865ff856SAndy Fleming int speed)
8557737d5c6SDave Liu {
8567737d5c6SDave Liu uec_private_t *uec = (uec_private_t *) dev->priv;
8577737d5c6SDave Liu struct uec_mii_info *mii_info;
858f655adefSKim Phillips u16 status;
8597737d5c6SDave Liu
8607737d5c6SDave Liu if (!uec->mii_info) {
861f30b6154SKim Phillips printf ("%s: the PHY not initialized\n", __FUNCTION__);
8627737d5c6SDave Liu return;
8637737d5c6SDave Liu }
8647737d5c6SDave Liu mii_info = uec->mii_info;
8657737d5c6SDave Liu
866865ff856SAndy Fleming if (type == PHY_INTERFACE_MODE_RGMII) {
867865ff856SAndy Fleming if (speed == SPEED_100) {
86809c04c20SAndy Fleming uec_phy_write(mii_info, 0x00, 0x9140);
86909c04c20SAndy Fleming uec_phy_write(mii_info, 0x1d, 0x001f);
87009c04c20SAndy Fleming uec_phy_write(mii_info, 0x1e, 0x200c);
87109c04c20SAndy Fleming uec_phy_write(mii_info, 0x1d, 0x0005);
87209c04c20SAndy Fleming uec_phy_write(mii_info, 0x1e, 0x0000);
87309c04c20SAndy Fleming uec_phy_write(mii_info, 0x1e, 0x0100);
87409c04c20SAndy Fleming uec_phy_write(mii_info, 0x09, 0x0e00);
87509c04c20SAndy Fleming uec_phy_write(mii_info, 0x04, 0x01e1);
87609c04c20SAndy Fleming uec_phy_write(mii_info, 0x00, 0x9140);
87709c04c20SAndy Fleming uec_phy_write(mii_info, 0x00, 0x1000);
8787737d5c6SDave Liu udelay (100000);
87909c04c20SAndy Fleming uec_phy_write(mii_info, 0x00, 0x2900);
88009c04c20SAndy Fleming uec_phy_write(mii_info, 0x14, 0x0cd2);
88109c04c20SAndy Fleming uec_phy_write(mii_info, 0x00, 0xa100);
88209c04c20SAndy Fleming uec_phy_write(mii_info, 0x09, 0x0000);
88309c04c20SAndy Fleming uec_phy_write(mii_info, 0x1b, 0x800b);
88409c04c20SAndy Fleming uec_phy_write(mii_info, 0x04, 0x05e1);
88509c04c20SAndy Fleming uec_phy_write(mii_info, 0x00, 0xa100);
88609c04c20SAndy Fleming uec_phy_write(mii_info, 0x00, 0x2100);
8877737d5c6SDave Liu udelay (1000000);
888865ff856SAndy Fleming } else if (speed == SPEED_10) {
88909c04c20SAndy Fleming uec_phy_write(mii_info, 0x14, 0x8e40);
89009c04c20SAndy Fleming uec_phy_write(mii_info, 0x1b, 0x800b);
89109c04c20SAndy Fleming uec_phy_write(mii_info, 0x14, 0x0c82);
89209c04c20SAndy Fleming uec_phy_write(mii_info, 0x00, 0x8100);
8937737d5c6SDave Liu udelay (1000000);
8947737d5c6SDave Liu }
895582c55a0SHeiko Schocher }
896f655adefSKim Phillips
897f655adefSKim Phillips /* handle 88e1111 rev.B2 erratum 5.6 */
898f655adefSKim Phillips if (mii_info->autoneg) {
89909c04c20SAndy Fleming status = uec_phy_read(mii_info, MII_BMCR);
90009c04c20SAndy Fleming uec_phy_write(mii_info, MII_BMCR, status | BMCR_ANENABLE);
901f655adefSKim Phillips }
902f655adefSKim Phillips /* now the B2 will correctly report autoneg completion status */
9037737d5c6SDave Liu }
9047737d5c6SDave Liu
change_phy_interface_mode(struct eth_device * dev,phy_interface_t type,int speed)905582c55a0SHeiko Schocher void change_phy_interface_mode (struct eth_device *dev,
906865ff856SAndy Fleming phy_interface_t type, int speed)
9077737d5c6SDave Liu {
9087737d5c6SDave Liu #ifdef CONFIG_PHY_MODE_NEED_CHANGE
909582c55a0SHeiko Schocher marvell_phy_interface_mode (dev, type, speed);
9107737d5c6SDave Liu #endif
9117737d5c6SDave Liu }
912