diff options
| -rw-r--r-- | drivers/net/phy/Makefile | 11 | ||||
| -rw-r--r-- | drivers/net/phy/atheros.c | 48 | ||||
| -rw-r--r-- | drivers/net/phy/broadcom.c | 288 | ||||
| -rw-r--r-- | drivers/net/phy/davicom.c | 98 | ||||
| -rw-r--r-- | drivers/net/phy/lxt.c | 87 | ||||
| -rw-r--r-- | drivers/net/phy/marvell.c | 367 | ||||
| -rw-r--r-- | drivers/net/phy/micrel.c | 40 | ||||
| -rw-r--r-- | drivers/net/phy/natsemi.c | 96 | ||||
| -rw-r--r-- | drivers/net/phy/phy.c | 31 | ||||
| -rw-r--r-- | drivers/net/phy/realtek.c | 130 | ||||
| -rw-r--r-- | drivers/net/phy/teranetics.c | 62 | ||||
| -rw-r--r-- | drivers/net/phy/vitesse.c | 242 | ||||
| -rw-r--r-- | include/config_phylib_all_drivers.h | 32 | ||||
| -rw-r--r-- | include/phy.h | 10 | 
14 files changed, 1542 insertions, 0 deletions
| diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile index 609a22f2b..a59834b29 100644 --- a/drivers/net/phy/Makefile +++ b/drivers/net/phy/Makefile @@ -27,8 +27,19 @@ LIB	:= $(obj)libphy.o  COBJS-$(CONFIG_BITBANGMII) += miiphybb.o  COBJS-$(CONFIG_MV88E61XX_SWITCH) += mv88e61xx.o +  COBJS-$(CONFIG_PHYLIB) += phy.o  COBJS-$(CONFIG_PHYLIB_10G) += generic_10g.o +COBJS-$(CONFIG_PHY_ATHEROS) += atheros.o +COBJS-$(CONFIG_PHY_BROADCOM) += broadcom.o +COBJS-$(CONFIG_PHY_DAVICOM) += davicom.o +COBJS-$(CONFIG_PHY_LXT) += lxt.o +COBJS-$(CONFIG_PHY_MARVELL) += marvell.o +COBJS-$(CONFIG_PHY_MICREL) += micrel.o +COBJS-$(CONFIG_PHY_NATSEMI) += natsemi.o +COBJS-$(CONFIG_PHY_REALTEK) += realtek.o +COBJS-$(CONFIG_PHY_TERANETICS) += teranetics.o +COBJS-$(CONFIG_PHY_VITESSE) += vitesse.o  COBJS	:= $(COBJS-y)  SRCS	:= $(COBJS:.o=.c) diff --git a/drivers/net/phy/atheros.c b/drivers/net/phy/atheros.c new file mode 100644 index 000000000..798473dd6 --- /dev/null +++ b/drivers/net/phy/atheros.c @@ -0,0 +1,48 @@ +/* + * Atheros PHY drivers + * + * 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 + * + * Copyright 2011 Freescale Semiconductor, Inc. + * author Andy Fleming + * + */ +#include <phy.h> + +static int ar8021_config(struct phy_device *phydev) +{ +	phy_write(phydev, MDIO_DEVAD_NONE, 0x1d, 0x05); +	phy_write(phydev, MDIO_DEVAD_NONE, 0x1e, 0x3D47); + +	return 0; +} + +struct phy_driver AR8021_driver =  { +	.name = "AR8021", +	.uid = 0x4dd040, +	.mask = 0xfffff0, +	.features = PHY_GBIT_FEATURES, +	.config = ar8021_config, +	.startup = genphy_startup, +	.shutdown = genphy_shutdown, +}; + +int phy_atheros_init(void) +{ +	phy_register(&AR8021_driver); + +	return 0; +} diff --git a/drivers/net/phy/broadcom.c b/drivers/net/phy/broadcom.c new file mode 100644 index 000000000..427ac6013 --- /dev/null +++ b/drivers/net/phy/broadcom.c @@ -0,0 +1,288 @@ +/* + * Broadcom PHY drivers + * + * 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 + * + * Copyright 2010-2011 Freescale Semiconductor, Inc. + * author Andy Fleming + * + */ +#include <config.h> +#include <common.h> +#include <phy.h> + +/* Broadcom BCM54xx -- taken from linux sungem_phy */ +#define MIIM_BCM54xx_AUXCNTL			0x18 +#define MIIM_BCM54xx_AUXCNTL_ENCODE(val) (((val & 0x7) << 12)|(val & 0x7)) +#define MIIM_BCM54xx_AUXSTATUS			0x19 +#define MIIM_BCM54xx_AUXSTATUS_LINKMODE_MASK	0x0700 +#define MIIM_BCM54xx_AUXSTATUS_LINKMODE_SHIFT	8 + +#define MIIM_BCM54XX_SHD			0x1c +#define MIIM_BCM54XX_SHD_WRITE			0x8000 +#define MIIM_BCM54XX_SHD_VAL(x)			((x & 0x1f) << 10) +#define MIIM_BCM54XX_SHD_DATA(x)		((x & 0x3ff) << 0) +#define MIIM_BCM54XX_SHD_WR_ENCODE(val, data)	\ +	(MIIM_BCM54XX_SHD_WRITE | MIIM_BCM54XX_SHD_VAL(val) | \ +	 MIIM_BCM54XX_SHD_DATA(data)) + +#define MIIM_BCM54XX_EXP_DATA		0x15	/* Expansion register data */ +#define MIIM_BCM54XX_EXP_SEL		0x17	/* Expansion register select */ +#define MIIM_BCM54XX_EXP_SEL_SSD	0x0e00	/* Secondary SerDes select */ +#define MIIM_BCM54XX_EXP_SEL_ER		0x0f00	/* Expansion register select */ + +/* Broadcom BCM5461S */ +static int bcm5461_config(struct phy_device *phydev) +{ +	genphy_config_aneg(phydev); + +	phy_reset(phydev); + +	return 0; +} + +static int bcm54xx_parse_status(struct phy_device *phydev) +{ +	unsigned int mii_reg; + +	mii_reg = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_BCM54xx_AUXSTATUS); + +	switch ((mii_reg & MIIM_BCM54xx_AUXSTATUS_LINKMODE_MASK) >> +			MIIM_BCM54xx_AUXSTATUS_LINKMODE_SHIFT) { +	case 1: +		phydev->duplex = DUPLEX_HALF; +		phydev->speed = SPEED_10; +		break; +	case 2: +		phydev->duplex = DUPLEX_FULL; +		phydev->speed = SPEED_10; +		break; +	case 3: +		phydev->duplex = DUPLEX_HALF; +		phydev->speed = SPEED_100; +		break; +	case 5: +		phydev->duplex = DUPLEX_FULL; +		phydev->speed = SPEED_100; +		break; +	case 6: +		phydev->duplex = DUPLEX_HALF; +		phydev->speed = SPEED_1000; +		break; +	case 7: +		phydev->duplex = DUPLEX_FULL; +		phydev->speed = SPEED_1000; +		break; +	default: +		printf("Auto-neg error, defaulting to 10BT/HD\n"); +		phydev->duplex = DUPLEX_HALF; +		phydev->speed = SPEED_10; +		break; +	} + +	return 0; +} + +static int bcm54xx_startup(struct phy_device *phydev) +{ +	/* Read the Status (2x to make sure link is right) */ +	genphy_update_link(phydev); +	bcm54xx_parse_status(phydev); + +	return 0; +} + +/* Broadcom BCM5482S */ +/* + * "Ethernet@Wirespeed" needs to be enabled to achieve link in certain + * circumstances.  eg a gigabit TSEC connected to a gigabit switch with + * a 4-wire ethernet cable.  Both ends advertise gigabit, but can't + * link.  "Ethernet@Wirespeed" reduces advertised speed until link + * can be achieved. + */ +static u32 bcm5482_read_wirespeed(struct phy_device *phydev, u32 reg) +{ +	return (phy_read(phydev, MDIO_DEVAD_NONE, reg) & 0x8FFF) | 0x8010; +} + +static int bcm5482_config(struct phy_device *phydev) +{ +	unsigned int reg; + +	/* reset the PHY */ +	reg = phy_read(phydev, MDIO_DEVAD_NONE, MII_BMCR); +	reg |= BMCR_RESET; +	phy_write(phydev, MDIO_DEVAD_NONE, MII_BMCR, reg); + +	/* Setup read from auxilary control shadow register 7 */ +	phy_write(phydev, MDIO_DEVAD_NONE, MIIM_BCM54xx_AUXCNTL, +			MIIM_BCM54xx_AUXCNTL_ENCODE(7)); +	/* Read Misc Control register and or in Ethernet@Wirespeed */ +	reg = bcm5482_read_wirespeed(phydev, MIIM_BCM54xx_AUXCNTL); +	phy_write(phydev, MDIO_DEVAD_NONE, MIIM_BCM54xx_AUXCNTL, reg); + +	/* Initial config/enable of secondary SerDes interface */ +	phy_write(phydev, MDIO_DEVAD_NONE, MIIM_BCM54XX_SHD, +			MIIM_BCM54XX_SHD_WR_ENCODE(0x14, 0xf)); +	/* Write intial value to secondary SerDes Contol */ +	phy_write(phydev, MDIO_DEVAD_NONE, MIIM_BCM54XX_EXP_SEL, +			MIIM_BCM54XX_EXP_SEL_SSD | 0); +	phy_write(phydev, MDIO_DEVAD_NONE, MIIM_BCM54XX_EXP_DATA, +			BMCR_ANRESTART); +	/* Enable copper/fiber auto-detect */ +	phy_write(phydev, MDIO_DEVAD_NONE, MIIM_BCM54XX_SHD, +			MIIM_BCM54XX_SHD_WR_ENCODE(0x1e, 0x201)); + +	genphy_config_aneg(phydev); + +	return 0; +} + +/* + * Find out if PHY is in copper or serdes mode by looking at Expansion Reg + * 0x42 - "Operating Mode Status Register" + */ +static int bcm5482_is_serdes(struct phy_device *phydev) +{ +	u16 val; +	int serdes = 0; + +	phy_write(phydev, MDIO_DEVAD_NONE, MIIM_BCM54XX_EXP_SEL, +			MIIM_BCM54XX_EXP_SEL_ER | 0x42); +	val = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_BCM54XX_EXP_DATA); + +	switch (val & 0x1f) { +	case 0x0d:	/* RGMII-to-100Base-FX */ +	case 0x0e:	/* RGMII-to-SGMII */ +	case 0x0f:	/* RGMII-to-SerDes */ +	case 0x12:	/* SGMII-to-SerDes */ +	case 0x13:	/* SGMII-to-100Base-FX */ +	case 0x16:	/* SerDes-to-Serdes */ +		serdes = 1; +		break; +	case 0x6:	/* RGMII-to-Copper */ +	case 0x14:	/* SGMII-to-Copper */ +	case 0x17:	/* SerDes-to-Copper */ +		break; +	default: +		printf("ERROR, invalid PHY mode (0x%x\n)", val); +		break; +	} + +	return serdes; +} + +/* + * Determine SerDes link speed and duplex from Expansion reg 0x42 "Operating + * Mode Status Register" + */ +static u32 bcm5482_parse_serdes_sr(struct phy_device *phydev) +{ +	u16 val; +	int i = 0; + +	/* Wait 1s for link - Clause 37 autonegotiation happens very fast */ +	while (1) { +		phy_write(phydev, MDIO_DEVAD_NONE, MIIM_BCM54XX_EXP_SEL, +				MIIM_BCM54XX_EXP_SEL_ER | 0x42); +		val = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_BCM54XX_EXP_DATA); + +		if (val & 0x8000) +			break; + +		if (i++ > 1000) { +			phydev->link = 0; +			return 1; +		} + +		udelay(1000);	/* 1 ms */ +	} + +	phydev->link = 1; +	switch ((val >> 13) & 0x3) { +	case (0x00): +		phydev->speed = 10; +		break; +	case (0x01): +		phydev->speed = 100; +		break; +	case (0x02): +		phydev->speed = 1000; +		break; +	} + +	phydev->duplex = (val & 0x1000) == 0x1000; + +	return 0; +} + +/* + * Figure out if BCM5482 is in serdes or copper mode and determine link + * configuration accordingly + */ +static int bcm5482_startup(struct phy_device *phydev) +{ +	if (bcm5482_is_serdes(phydev)) { +		bcm5482_parse_serdes_sr(phydev); +		phydev->port = PORT_FIBRE; +	} else { +		/* Wait for auto-negotiation to complete or fail */ +		genphy_update_link(phydev); +		/* Parse BCM54xx copper aux status register */ +		bcm54xx_parse_status(phydev); +	} + +	return 0; +} + +static struct phy_driver BCM5461S_driver = { +	.name = "Broadcom BCM5461S", +	.uid = 0x2060c0, +	.mask = 0xfffff0, +	.features = PHY_GBIT_FEATURES, +	.config = &bcm5461_config, +	.startup = &bcm54xx_startup, +	.shutdown = &genphy_shutdown, +}; + +static struct phy_driver BCM5464S_driver = { +	.name = "Broadcom BCM5464S", +	.uid = 0x2060b0, +	.mask = 0xfffff0, +	.features = PHY_GBIT_FEATURES, +	.config = &bcm5461_config, +	.startup = &bcm54xx_startup, +	.shutdown = &genphy_shutdown, +}; + +static struct phy_driver BCM5482S_driver = { +	.name = "Broadcom BCM5482S", +	.uid = 0x143bcb0, +	.mask = 0xffffff0, +	.features = PHY_GBIT_FEATURES, +	.config = &bcm5482_config, +	.startup = &bcm5482_startup, +	.shutdown = &genphy_shutdown, +}; + +int phy_broadcom_init(void) +{ +	phy_register(&BCM5482S_driver); +	phy_register(&BCM5464S_driver); +	phy_register(&BCM5461S_driver); + +	return 0; +} diff --git a/drivers/net/phy/davicom.c b/drivers/net/phy/davicom.c new file mode 100644 index 000000000..e96a4af03 --- /dev/null +++ b/drivers/net/phy/davicom.c @@ -0,0 +1,98 @@ +/* + * Davicom PHY drivers + * + * 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 + * + * Copyright 2010-2011 Freescale Semiconductor, Inc. + * author Andy Fleming + * + */ +#include <phy.h> + +#define MIIM_DM9161_SCR                0x10 +#define MIIM_DM9161_SCR_INIT   0x0610 + +/* DM9161 Specified Configuration and Status Register */ +#define MIIM_DM9161_SCSR       0x11 +#define MIIM_DM9161_SCSR_100F  0x8000 +#define MIIM_DM9161_SCSR_100H  0x4000 +#define MIIM_DM9161_SCSR_10F   0x2000 +#define MIIM_DM9161_SCSR_10H   0x1000 + +/* DM9161 10BT Configuration/Status */ +#define MIIM_DM9161_10BTCSR    0x12 +#define MIIM_DM9161_10BTCSR_INIT       0x7800 + + +/* Davicom DM9161E */ +static int dm9161_config(struct phy_device *phydev) +{ +	phy_write(phydev, MDIO_DEVAD_NONE, MII_BMCR, BMCR_ISOLATE); +	/* Do not bypass the scrambler/descrambler */ +	phy_write(phydev, MDIO_DEVAD_NONE, MIIM_DM9161_SCR, +			MIIM_DM9161_SCR_INIT); +	/* Clear 10BTCSR to default */ +	phy_write(phydev, MDIO_DEVAD_NONE, MIIM_DM9161_10BTCSR, +			MIIM_DM9161_10BTCSR_INIT); + +	genphy_config_aneg(phydev); + +	return 0; +} + +static int dm9161_parse_status(struct phy_device *phydev) +{ +	int mii_reg; + +	mii_reg = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_DM9161_SCSR); + +	if (mii_reg & (MIIM_DM9161_SCSR_100F | MIIM_DM9161_SCSR_100H)) +		phydev->speed = SPEED_100; +	else +		phydev->speed = SPEED_10; + +	if (mii_reg & (MIIM_DM9161_SCSR_100F | MIIM_DM9161_SCSR_10F)) +		phydev->duplex = DUPLEX_FULL; +	else +		phydev->duplex = DUPLEX_HALF; + +	return 0; +} + +static int dm9161_startup(struct phy_device *phydev) +{ +	genphy_update_link(phydev); +	dm9161_parse_status(phydev); + +	return 0; +} + +static struct phy_driver DM9161_driver = { +	.name = "Davicom DM9161E", +	.uid = 0x181b880, +	.mask = 0xffffff0, +	.features = PHY_BASIC_FEATURES, +	.config = &dm9161_config, +	.startup = &dm9161_startup, +	.shutdown = &genphy_shutdown, +}; + +int phy_davicom_init(void) +{ +	phy_register(&DM9161_driver); + +	return 0; +} diff --git a/drivers/net/phy/lxt.c b/drivers/net/phy/lxt.c new file mode 100644 index 000000000..d67bbdd9c --- /dev/null +++ b/drivers/net/phy/lxt.c @@ -0,0 +1,87 @@ +/* + * LXT PHY drivers + * + * 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 + * + * Copyright 2010-2011 Freescale Semiconductor, Inc. + * author Andy Fleming + * + */ +#include <phy.h> + +/* LXT971 Status 2 registers */ +#define MIIM_LXT971_SR2                     0x11  /* Status Register 2  */ +#define MIIM_LXT971_SR2_SPEED_MASK 0x4200 +#define MIIM_LXT971_SR2_10HDX     0x0000  /*  10 Mbit half duplex selected */ +#define MIIM_LXT971_SR2_10FDX     0x0200  /*  10 Mbit full duplex selected */ +#define MIIM_LXT971_SR2_100HDX    0x4000  /* 100 Mbit half duplex selected */ +#define MIIM_LXT971_SR2_100FDX    0x4200  /* 100 Mbit full duplex selected */ + + +/* LXT971 */ +static int lxt971_parse_status(struct phy_device *phydev) +{ +	int mii_reg; +	int speed; + +	mii_reg = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_LXT971_SR2); +	speed = mii_reg & MIIM_LXT971_SR2_SPEED_MASK; + +	switch (speed) { +	case MIIM_LXT971_SR2_10HDX: +		phydev->speed = SPEED_10; +		phydev->duplex = DUPLEX_HALF; +		break; +	case MIIM_LXT971_SR2_10FDX: +		phydev->speed = SPEED_10; +		phydev->duplex = DUPLEX_FULL; +		break; +	case MIIM_LXT971_SR2_100HDX: +		phydev->speed = SPEED_100; +		phydev->duplex = DUPLEX_HALF; +		break; +	default: +		phydev->speed = SPEED_100; +		phydev->duplex = DUPLEX_FULL; +	} + +	return 0; +} + +static int lxt971_startup(struct phy_device *phydev) +{ +	genphy_update_link(phydev); +	lxt971_parse_status(phydev); + +	return 0; +} + +static struct phy_driver LXT971_driver = { +	.name = "LXT971", +	.uid = 0x1378e0, +	.mask = 0xfffff0, +	.features = PHY_BASIC_FEATURES, +	.config = &genphy_config_aneg, +	.startup = &lxt971_startup, +	.shutdown = &genphy_shutdown, +}; + +int phy_lxt_init(void) +{ +	phy_register(&LXT971_driver); + +	return 0; +} diff --git a/drivers/net/phy/marvell.c b/drivers/net/phy/marvell.c new file mode 100644 index 000000000..bd1cdc4f1 --- /dev/null +++ b/drivers/net/phy/marvell.c @@ -0,0 +1,367 @@ +/* + * Marvell PHY drivers + * + * 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 + * + * Copyright 2010-2011 Freescale Semiconductor, Inc. + * author Andy Fleming + * + */ +#include <config.h> +#include <common.h> +#include <phy.h> + +#define PHY_AUTONEGOTIATE_TIMEOUT 5000 + +/* 88E1011 PHY Status Register */ +#define MIIM_88E1xxx_PHY_STATUS		0x11 +#define MIIM_88E1xxx_PHYSTAT_SPEED	0xc000 +#define MIIM_88E1xxx_PHYSTAT_GBIT	0x8000 +#define MIIM_88E1xxx_PHYSTAT_100	0x4000 +#define MIIM_88E1xxx_PHYSTAT_DUPLEX	0x2000 +#define MIIM_88E1xxx_PHYSTAT_SPDDONE	0x0800 +#define MIIM_88E1xxx_PHYSTAT_LINK	0x0400 + +#define MIIM_88E1xxx_PHY_SCR		0x10 +#define MIIM_88E1xxx_PHY_MDI_X_AUTO	0x0060 + +/* 88E1111 PHY LED Control Register */ +#define MIIM_88E1111_PHY_LED_CONTROL	24 +#define MIIM_88E1111_PHY_LED_DIRECT	0x4100 +#define MIIM_88E1111_PHY_LED_COMBINE	0x411C + +/* 88E1118 PHY defines */ +#define MIIM_88E1118_PHY_PAGE		22 +#define MIIM_88E1118_PHY_LED_PAGE	3 + +/* 88E1121 PHY LED Control Register */ +#define MIIM_88E1121_PHY_LED_CTRL	16 +#define MIIM_88E1121_PHY_LED_PAGE	3 +#define MIIM_88E1121_PHY_LED_DEF	0x0030 + +/* 88E1121 PHY IRQ Enable/Status Register */ +#define MIIM_88E1121_PHY_IRQ_EN		18 +#define MIIM_88E1121_PHY_IRQ_STATUS	19 + +#define MIIM_88E1121_PHY_PAGE		22 + +/* 88E1145 Extended PHY Specific Control Register */ +#define MIIM_88E1145_PHY_EXT_CR 20 +#define MIIM_M88E1145_RGMII_RX_DELAY	0x0080 +#define MIIM_M88E1145_RGMII_TX_DELAY	0x0002 + +#define MIIM_88E1145_PHY_LED_CONTROL	24 +#define MIIM_88E1145_PHY_LED_DIRECT	0x4100 + +#define MIIM_88E1145_PHY_PAGE	29 +#define MIIM_88E1145_PHY_CAL_OV 30 + +#define MIIM_88E1149_PHY_PAGE	29 + +/* Marvell 88E1011S */ +static int m88e1011s_config(struct phy_device *phydev) +{ +	/* Reset and configure the PHY */ +	phy_write(phydev, MDIO_DEVAD_NONE, MII_BMCR, BMCR_RESET); + +	phy_write(phydev, MDIO_DEVAD_NONE, 0x1d, 0x1f); +	phy_write(phydev, MDIO_DEVAD_NONE, 0x1e, 0x200c); +	phy_write(phydev, MDIO_DEVAD_NONE, 0x1d, 0x5); +	phy_write(phydev, MDIO_DEVAD_NONE, 0x1e, 0); +	phy_write(phydev, MDIO_DEVAD_NONE, 0x1e, 0x100); + +	phy_write(phydev, MDIO_DEVAD_NONE, MII_BMCR, BMCR_RESET); + +	genphy_config_aneg(phydev); + +	return 0; +} + +/* Parse the 88E1011's status register for speed and duplex + * information + */ +static uint m88e1xxx_parse_status(struct phy_device *phydev) +{ +	unsigned int speed; +	unsigned int mii_reg; + +	mii_reg = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_88E1xxx_PHY_STATUS); + +	if ((mii_reg & MIIM_88E1xxx_PHYSTAT_LINK) && +		!(mii_reg & MIIM_88E1xxx_PHYSTAT_SPDDONE)) { +		int i = 0; + +		puts("Waiting for PHY realtime link"); +		while (!(mii_reg & MIIM_88E1xxx_PHYSTAT_SPDDONE)) { +			/* Timeout reached ? */ +			if (i > PHY_AUTONEGOTIATE_TIMEOUT) { +				puts(" TIMEOUT !\n"); +				phydev->link = 0; +				break; +			} + +			if ((i++ % 1000) == 0) +				putc('.'); +			udelay(1000); +			mii_reg = phy_read(phydev, MDIO_DEVAD_NONE, +					MIIM_88E1xxx_PHY_STATUS); +		} +		puts(" done\n"); +		udelay(500000);	/* another 500 ms (results in faster booting) */ +	} else { +		if (mii_reg & MIIM_88E1xxx_PHYSTAT_LINK) +			phydev->link = 1; +		else +			phydev->link = 0; +	} + +	if (mii_reg & MIIM_88E1xxx_PHYSTAT_DUPLEX) +		phydev->duplex = DUPLEX_FULL; +	else +		phydev->duplex = DUPLEX_HALF; + +	speed = mii_reg & MIIM_88E1xxx_PHYSTAT_SPEED; + +	switch (speed) { +	case MIIM_88E1xxx_PHYSTAT_GBIT: +		phydev->speed = SPEED_1000; +		break; +	case MIIM_88E1xxx_PHYSTAT_100: +		phydev->speed = SPEED_100; +		break; +	default: +		phydev->speed = SPEED_10; +		break; +	} + +	return 0; +} + +static int m88e1011s_startup(struct phy_device *phydev) +{ +	genphy_update_link(phydev); +	m88e1xxx_parse_status(phydev); + +	return 0; +} + +/* Marvell 88E1111S */ +static int m88e1111s_config(struct phy_device *phydev) +{ +	int reg; + +	if ((phydev->interface == PHY_INTERFACE_MODE_RGMII) || +			(phydev->interface == PHY_INTERFACE_MODE_RGMII_ID) || +			(phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID) || +			(phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID)) { +		reg = phy_read(phydev, MDIO_DEVAD_NONE, 0x1b); +		reg = (reg & 0xfff0) | 0xb; +		phy_write(phydev, MDIO_DEVAD_NONE, 0x1b, reg); +	} else { +		phy_write(phydev, MDIO_DEVAD_NONE, 0x1b, 0x1f); +	} + +	phy_write(phydev, MDIO_DEVAD_NONE, 0x14, 0x0cd2); + +	genphy_config_aneg(phydev); + +	phy_reset(phydev); + +	return 0; +} + +/* Marvell 88E1118 */ +static int m88e1118_config(struct phy_device *phydev) +{ +	/* Change Page Number */ +	phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1118_PHY_PAGE, 0x0002); +	/* Delay RGMII TX and RX */ +	phy_write(phydev, MDIO_DEVAD_NONE, 0x15, 0x1070); +	/* Change Page Number */ +	phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1118_PHY_PAGE, 0x0003); +	/* Adjust LED control */ +	phy_write(phydev, MDIO_DEVAD_NONE, 0x10, 0x021e); +	/* Change Page Number */ +	phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1118_PHY_PAGE, 0x0000); + +	genphy_config_aneg(phydev); + +	phy_reset(phydev); + +	return 0; +} + +static int m88e1118_startup(struct phy_device *phydev) +{ +	/* Change Page Number */ +	phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1118_PHY_PAGE, 0x0000); + +	genphy_update_link(phydev); +	m88e1xxx_parse_status(phydev); + +	return 0; +} + +/* Marvell 88E1121R */ +static int m88e1121_config(struct phy_device *phydev) +{ +	int pg; + +	/* Configure the PHY */ +	genphy_config_aneg(phydev); + +	/* Switch the page to access the led register */ +	pg = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_88E1121_PHY_PAGE); +	phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1121_PHY_PAGE, +			MIIM_88E1121_PHY_LED_PAGE); +	/* Configure leds */ +	phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1121_PHY_LED_CTRL, +			MIIM_88E1121_PHY_LED_DEF); +	/* Restore the page pointer */ +	phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1121_PHY_PAGE, pg); + +	/* Disable IRQs and de-assert interrupt */ +	phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1121_PHY_IRQ_EN, 0); +	phy_read(phydev, MDIO_DEVAD_NONE, MIIM_88E1121_PHY_IRQ_STATUS); + +	return 0; +} + +/* Marvell 88E1145 */ +static int m88e1145_config(struct phy_device *phydev) +{ +	int reg; + +	/* Errata E0, E1 */ +	phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1145_PHY_PAGE, 0x001b); +	phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1145_PHY_CAL_OV, 0x418f); +	phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1145_PHY_PAGE, 0x0016); +	phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1145_PHY_CAL_OV, 0xa2da); + +	phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1xxx_PHY_SCR, +			MIIM_88E1xxx_PHY_MDI_X_AUTO); + +	reg = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_88E1145_PHY_EXT_CR); +	if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID) +		reg |= MIIM_M88E1145_RGMII_RX_DELAY | +			MIIM_M88E1145_RGMII_TX_DELAY; +	phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1145_PHY_EXT_CR, reg); + +	genphy_config_aneg(phydev); + +	phy_reset(phydev); + +	return 0; +} + +static int m88e1145_startup(struct phy_device *phydev) +{ +	genphy_update_link(phydev); +	phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1145_PHY_LED_CONTROL, +			MIIM_88E1145_PHY_LED_DIRECT); +	m88e1xxx_parse_status(phydev); + +	return 0; +} + +/* Marvell 88E1149S */ +static int m88e1149_config(struct phy_device *phydev) +{ +	phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1149_PHY_PAGE, 0x1f); +	phy_write(phydev, MDIO_DEVAD_NONE, 0x1e, 0x200c); +	phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1149_PHY_PAGE, 0x5); +	phy_write(phydev, MDIO_DEVAD_NONE, 0x1e, 0x0); +	phy_write(phydev, MDIO_DEVAD_NONE, 0x1e, 0x100); + +	genphy_config_aneg(phydev); + +	phy_reset(phydev); + +	return 0; +} + + +static struct phy_driver M88E1011S_driver = { +	.name = "Marvell 88E1011S", +	.uid = 0x1410c60, +	.mask = 0xffffff0, +	.features = PHY_GBIT_FEATURES, +	.config = &m88e1011s_config, +	.startup = &m88e1011s_startup, +	.shutdown = &genphy_shutdown, +}; + +static struct phy_driver M88E1111S_driver = { +	.name = "Marvell 88E1111S", +	.uid = 0x1410cc0, +	.mask = 0xffffff0, +	.features = PHY_GBIT_FEATURES, +	.config = &m88e1111s_config, +	.startup = &m88e1011s_startup, +	.shutdown = &genphy_shutdown, +}; + +static struct phy_driver M88E1118_driver = { +	.name = "Marvell 88E1118", +	.uid = 0x1410e10, +	.mask = 0xffffff0, +	.features = PHY_GBIT_FEATURES, +	.config = &m88e1118_config, +	.startup = &m88e1118_startup, +	.shutdown = &genphy_shutdown, +}; + +static struct phy_driver M88E1121R_driver = { +	.name = "Marvell 88E1121R", +	.uid = 0x1410cb0, +	.mask = 0xffffff0, +	.features = PHY_GBIT_FEATURES, +	.config = &m88e1121_config, +	.startup = &genphy_startup, +	.shutdown = &genphy_shutdown, +}; + +static struct phy_driver M88E1145_driver = { +	.name = "Marvell 88E1145", +	.uid = 0x1410cd0, +	.mask = 0xffffff0, +	.features = PHY_GBIT_FEATURES, +	.config = &m88e1145_config, +	.startup = &m88e1145_startup, +	.shutdown = &genphy_shutdown, +}; + +static struct phy_driver M88E1149S_driver = { +	.name = "Marvell 88E1149S", +	.uid = 0x1410ca0, +	.mask = 0xffffff0, +	.features = PHY_GBIT_FEATURES, +	.config = &m88e1149_config, +	.startup = &m88e1011s_startup, +	.shutdown = &genphy_shutdown, +}; + +int phy_marvell_init(void) +{ +	phy_register(&M88E1149S_driver); +	phy_register(&M88E1145_driver); +	phy_register(&M88E1121R_driver); +	phy_register(&M88E1118_driver); +	phy_register(&M88E1111S_driver); +	phy_register(&M88E1011S_driver); + +	return 0; +} diff --git a/drivers/net/phy/micrel.c b/drivers/net/phy/micrel.c new file mode 100644 index 000000000..47064a185 --- /dev/null +++ b/drivers/net/phy/micrel.c @@ -0,0 +1,40 @@ +/* + * Micrel PHY drivers + * + * 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 + * + * Copyright 2010-2011 Freescale Semiconductor, Inc. + * author Andy Fleming + * + */ +#include <phy.h> + +static struct phy_driver KSZ804_driver = { +	.name = "Micrel KSZ804", +	.uid = 0x221510, +	.mask = 0xfffff0, +	.features = PHY_BASIC_FEATURES, +	.config = &genphy_config, +	.startup = &genphy_startup, +	.shutdown = &genphy_shutdown, +}; + +int phy_micrel_init(void) +{ +	phy_register(&KSZ804_driver); + +	return 0; +} diff --git a/drivers/net/phy/natsemi.c b/drivers/net/phy/natsemi.c new file mode 100644 index 000000000..ea60ac1b0 --- /dev/null +++ b/drivers/net/phy/natsemi.c @@ -0,0 +1,96 @@ +/* + * National Semiconductor PHY drivers + * + * 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 + * + * Copyright 2010-2011 Freescale Semiconductor, Inc. + * author Andy Fleming + * + */ +#include <phy.h> + +/* DP83865 Link and Auto-Neg Status Register */ +#define MIIM_DP83865_LANR      0x11 +#define MIIM_DP83865_SPD_MASK  0x0018 +#define MIIM_DP83865_SPD_1000  0x0010 +#define MIIM_DP83865_SPD_100   0x0008 +#define MIIM_DP83865_DPX_FULL  0x0002 + + +/* NatSemi DP83865 */ +static int dp83865_config(struct phy_device *phydev) +{ +	phy_write(phydev, MDIO_DEVAD_NONE, MII_BMCR, BMCR_RESET); +	genphy_config_aneg(phydev); + +	return 0; +} + +static int dp83865_parse_status(struct phy_device *phydev) +{ +	int mii_reg; + +	mii_reg = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_DP83865_LANR); + +	switch (mii_reg & MIIM_DP83865_SPD_MASK) { + +	case MIIM_DP83865_SPD_1000: +		phydev->speed = SPEED_1000; +		break; + +	case MIIM_DP83865_SPD_100: +		phydev->speed = SPEED_100; +		break; + +	default: +		phydev->speed = SPEED_10; +		break; + +	} + +	if (mii_reg & MIIM_DP83865_DPX_FULL) +		phydev->duplex = DUPLEX_FULL; +	else +		phydev->duplex = DUPLEX_HALF; + +	return 0; +} + +static int dp83865_startup(struct phy_device *phydev) +{ +	genphy_update_link(phydev); +	dp83865_parse_status(phydev); + +	return 0; +} + + +static struct phy_driver DP83865_driver = { +	.name = "NatSemi DP83865", +	.uid = 0x20005c70, +	.mask = 0xfffffff0, +	.features = PHY_GBIT_FEATURES, +	.config = &dp83865_config, +	.startup = &dp83865_startup, +	.shutdown = &genphy_shutdown, +}; + +int phy_natsemi_init(void) +{ +	phy_register(&DP83865_driver); + +	return 0; +} diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c index 919011dbe..c7edcc090 100644 --- a/drivers/net/phy/phy.c +++ b/drivers/net/phy/phy.c @@ -420,6 +420,37 @@ static LIST_HEAD(phy_drivers);  int phy_init(void)  { +#ifdef CONFIG_PHY_ATHEROS +	phy_atheros_init(); +#endif +#ifdef CONFIG_PHY_BROADCOM +	phy_broadcom_init(); +#endif +#ifdef CONFIG_PHY_DAVICOM +	phy_davicom_init(); +#endif +#ifdef CONFIG_PHY_LXT +	phy_lxt_init(); +#endif +#ifdef CONFIG_PHY_MARVELL +	phy_marvell_init(); +#endif +#ifdef CONFIG_PHY_MICREL +	phy_micrel_init(); +#endif +#ifdef CONFIG_PHY_NATSEMI +	phy_natsemi_init(); +#endif +#ifdef CONFIG_PHY_REALTEK +	phy_realtek_init(); +#endif +#ifdef CONFIG_PHY_TERANETICS +	phy_teranetics_init(); +#endif +#ifdef CONFIG_PHY_VITESSE +	phy_vitesse_init(); +#endif +  	return 0;  } diff --git a/drivers/net/phy/realtek.c b/drivers/net/phy/realtek.c new file mode 100644 index 000000000..b7e2753f7 --- /dev/null +++ b/drivers/net/phy/realtek.c @@ -0,0 +1,130 @@ +/* + * RealTek PHY drivers + * + * 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 + * + * Copyright 2010-2011 Freescale Semiconductor, Inc. + * author Andy Fleming + * + */ +#include <config.h> +#include <common.h> +#include <phy.h> + +#define PHY_AUTONEGOTIATE_TIMEOUT 5000 + +/* RTL8211B PHY Status Register */ +#define MIIM_RTL8211B_PHY_STATUS       0x11 +#define MIIM_RTL8211B_PHYSTAT_SPEED    0xc000 +#define MIIM_RTL8211B_PHYSTAT_GBIT     0x8000 +#define MIIM_RTL8211B_PHYSTAT_100      0x4000 +#define MIIM_RTL8211B_PHYSTAT_DUPLEX   0x2000 +#define MIIM_RTL8211B_PHYSTAT_SPDDONE  0x0800 +#define MIIM_RTL8211B_PHYSTAT_LINK     0x0400 + + +/* RealTek RTL8211B */ +static int rtl8211b_config(struct phy_device *phydev) +{ +	phy_write(phydev, MDIO_DEVAD_NONE, MII_BMCR, BMCR_RESET); + +	genphy_config_aneg(phydev); + +	return 0; +} + +static int rtl8211b_parse_status(struct phy_device *phydev) +{ +	unsigned int speed; +	unsigned int mii_reg; + +	mii_reg = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_RTL8211B_PHY_STATUS); + +	if (!(mii_reg & MIIM_RTL8211B_PHYSTAT_SPDDONE)) { +		int i = 0; + +		/* in case of timeout ->link is cleared */ +		phydev->link = 1; +		puts("Waiting for PHY realtime link"); +		while (!(mii_reg & MIIM_RTL8211B_PHYSTAT_SPDDONE)) { +			/* Timeout reached ? */ +			if (i > PHY_AUTONEGOTIATE_TIMEOUT) { +				puts(" TIMEOUT !\n"); +				phydev->link = 0; +				break; +			} + +			if ((i++ % 1000) == 0) +				putc('.'); +			udelay(1000);	/* 1 ms */ +			mii_reg = phy_read(phydev, MDIO_DEVAD_NONE, +					MIIM_RTL8211B_PHY_STATUS); +		} +		puts(" done\n"); +		udelay(500000);	/* another 500 ms (results in faster booting) */ +	} else { +		if (mii_reg & MIIM_RTL8211B_PHYSTAT_LINK) +			phydev->link = 1; +		else +			phydev->link = 0; +	} + +	if (mii_reg & MIIM_RTL8211B_PHYSTAT_DUPLEX) +		phydev->duplex = DUPLEX_FULL; +	else +		phydev->duplex = DUPLEX_HALF; + +	speed = (mii_reg & MIIM_RTL8211B_PHYSTAT_SPEED); + +	switch (speed) { +	case MIIM_RTL8211B_PHYSTAT_GBIT: +		phydev->speed = SPEED_1000; +		break; +	case MIIM_RTL8211B_PHYSTAT_100: +		phydev->speed = SPEED_100; +		break; +	default: +		phydev->speed = SPEED_10; +	} + +	return 0; +} + +static int rtl8211b_startup(struct phy_device *phydev) +{ +	/* Read the Status (2x to make sure link is right) */ +	genphy_update_link(phydev); +	rtl8211b_parse_status(phydev); + +	return 0; +} + +static struct phy_driver RTL8211B_driver = { +	.name = "RealTek RTL8211B", +	.uid = 0x1cc910, +	.mask = 0xfffff0, +	.features = PHY_GBIT_FEATURES, +	.config = &rtl8211b_config, +	.startup = &rtl8211b_startup, +	.shutdown = &genphy_shutdown, +}; + +int phy_realtek_init(void) +{ +	phy_register(&RTL8211B_driver); + +	return 0; +} diff --git a/drivers/net/phy/teranetics.c b/drivers/net/phy/teranetics.c new file mode 100644 index 000000000..a771791b7 --- /dev/null +++ b/drivers/net/phy/teranetics.c @@ -0,0 +1,62 @@ +/* + * Teranetics PHY drivers + * + * 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 + * + * Copyright 2010-2011 Freescale Semiconductor, Inc. + * author Andy Fleming + * + */ +#include <config.h> +#include <phy.h> + +#ifndef CONFIG_PHYLIB_10G +#error The Teranetics PHY needs 10G support +#endif + +int tn2020_config(struct phy_device *phydev) +{ +	if (phydev->port == PORT_FIBRE) { +		unsigned short restart_an = (MDIO_AN_CTRL1_RESTART | +						MDIO_AN_CTRL1_ENABLE | +						MDIO_AN_CTRL1_XNP); + +		phy_write(phydev, 30, 93, 2); +		phy_write(phydev, MDIO_MMD_AN, MDIO_CTRL1, restart_an); +	} + +	return 0; +} + +struct phy_driver tn2020_driver = { +	.name = "Teranetics TN2020", +	.uid = 0x00a19410, +	.mask = 0xfffffff0, +	.features = PHY_10G_FEATURES, +	.mmds = (MDIO_DEVS_PMAPMD | MDIO_DEVS_PCS | +			MDIO_DEVS_PHYXS | MDIO_DEVS_AN | +			MDIO_DEVS_VEND1 | MDIO_DEVS_VEND2), +	.config = &tn2020_config, +	.startup = &gen10g_startup, +	.shutdown = &gen10g_shutdown, +}; + +int phy_teranetics_init(void) +{ +	phy_register(&tn2020_driver); + +	return 0; +} diff --git a/drivers/net/phy/vitesse.c b/drivers/net/phy/vitesse.c new file mode 100644 index 000000000..d48d4fe73 --- /dev/null +++ b/drivers/net/phy/vitesse.c @@ -0,0 +1,242 @@ +/* + * Vitesse PHY drivers + * + * 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 + * + * Copyright 2010-2011 Freescale Semiconductor, Inc. + * author Andy Fleming + * + */ +#include <miiphy.h> + +/* Cicada Auxiliary Control/Status Register */ +#define MIIM_CIS82xx_AUX_CONSTAT	0x1c +#define MIIM_CIS82xx_AUXCONSTAT_INIT	0x0004 +#define MIIM_CIS82xx_AUXCONSTAT_DUPLEX	0x0020 +#define MIIM_CIS82xx_AUXCONSTAT_SPEED	0x0018 +#define MIIM_CIS82xx_AUXCONSTAT_GBIT	0x0010 +#define MIIM_CIS82xx_AUXCONSTAT_100	0x0008 + +/* Cicada Extended Control Register 1 */ +#define MIIM_CIS82xx_EXT_CON1		0x17 +#define MIIM_CIS8201_EXTCON1_INIT	0x0000 + +/* Cicada 8204 Extended PHY Control Register 1 */ +#define MIIM_CIS8204_EPHY_CON		0x17 +#define MIIM_CIS8204_EPHYCON_INIT	0x0006 +#define MIIM_CIS8204_EPHYCON_RGMII	0x1100 + +/* Cicada 8204 Serial LED Control Register */ +#define MIIM_CIS8204_SLED_CON		0x1b +#define MIIM_CIS8204_SLEDCON_INIT	0x1115 + +/* Vitesse VSC8601 Extended PHY Control Register 1 */ +#define MIIM_VSC8601_EPHY_CON		0x17 +#define MIIM_VSC8601_EPHY_CON_INIT_SKEW	0x1120 +#define MIIM_VSC8601_SKEW_CTRL		0x1c + +#define PHY_EXT_PAGE_ACCESS    0x1f + +/* CIS8201 */ +static int vitesse_config(struct phy_device *phydev) +{ +	/* Override PHY config settings */ +	phy_write(phydev, MDIO_DEVAD_NONE, MIIM_CIS82xx_AUX_CONSTAT, +			MIIM_CIS82xx_AUXCONSTAT_INIT); +	/* Set up the interface mode */ +	phy_write(phydev, MDIO_DEVAD_NONE, MIIM_CIS82xx_EXT_CON1, +			MIIM_CIS8201_EXTCON1_INIT); + +	genphy_config_aneg(phydev); + +	return 0; +} + +static int vitesse_parse_status(struct phy_device *phydev) +{ +	int speed; +	int mii_reg; + +	mii_reg = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_CIS82xx_AUX_CONSTAT); + +	if (mii_reg & MIIM_CIS82xx_AUXCONSTAT_DUPLEX) +		phydev->duplex = DUPLEX_FULL; +	else +		phydev->duplex = DUPLEX_HALF; + +	speed = mii_reg & MIIM_CIS82xx_AUXCONSTAT_SPEED; +	switch (speed) { +	case MIIM_CIS82xx_AUXCONSTAT_GBIT: +		phydev->speed = SPEED_1000; +		break; +	case MIIM_CIS82xx_AUXCONSTAT_100: +		phydev->speed = SPEED_100; +		break; +	default: +		phydev->speed = SPEED_10; +		break; +	} + +	return 0; +} + +static int vitesse_startup(struct phy_device *phydev) +{ +	genphy_update_link(phydev); +	vitesse_parse_status(phydev); + +	return 0; +} + +static int cis8204_config(struct phy_device *phydev) +{ +	/* Override PHY config settings */ +	phy_write(phydev, MDIO_DEVAD_NONE, MIIM_CIS82xx_AUX_CONSTAT, +			MIIM_CIS82xx_AUXCONSTAT_INIT); + +	genphy_config_aneg(phydev); + +	if ((phydev->interface == PHY_INTERFACE_MODE_RGMII) || +			(phydev->interface == PHY_INTERFACE_MODE_RGMII) || +			(phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID) || +			(phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID)) +		phy_write(phydev, MDIO_DEVAD_NONE, MIIM_CIS8204_EPHY_CON, +				MIIM_CIS8204_EPHYCON_INIT | +				MIIM_CIS8204_EPHYCON_RGMII); +	else +		phy_write(phydev, MDIO_DEVAD_NONE, MIIM_CIS8204_EPHY_CON, +				MIIM_CIS8204_EPHYCON_INIT); + +	return 0; +} + +/* Vitesse VSC8601 */ +int vsc8601_config(struct phy_device *phydev) +{ +	/* Configure some basic stuff */ +#ifdef CONFIG_SYS_VSC8601_SKEWFIX +	phy_write(phydev, MDIO_DEVAD_NONE, MIIM_VSC8601_EPHY_CON, +			MIIM_VSC8601_EPHY_CON_INIT_SKEW); +#if defined(CONFIG_SYS_VSC8601_SKEW_TX) && defined(CONFIG_SYS_VSC8601_SKEW_RX) +	phy_write(phydev, MDIO_DEVAD_NONE, PHY_EXT_PAGE_ACCESS, 1); +#define VSC8101_SKEW \ +	((CONFIG_SYS_VSC8601_SKEW_TX << 14) \ +	| (CONFIG_SYS_VSC8601_SKEW_RX << 12)) +	phy_write(phydev, MDIO_DEVAD_NONE, MIIM_VSC8601_SKEW_CTRL, +			VSC8101_SKEW); +	phy_write(phydev, MDIO_DEVAD_NONE, PHY_EXT_PAGE_ACCESS, 0); +#endif +#endif + +	genphy_config_aneg(phydev); + +	return 0; +} + +static struct phy_driver VSC8211_driver = { +	.name	= "Vitesse VSC8211", +	.uid	= 0xfc4b0, +	.mask	= 0xffff0, +	.features = PHY_GBIT_FEATURES, +	.config = &vitesse_config, +	.startup = &vitesse_startup, +	.shutdown = &genphy_shutdown, +}; + +static struct phy_driver VSC8221_driver = { +	.name = "Vitesse VSC8221", +	.uid = 0xfc550, +	.mask = 0xffff0, +	.features = PHY_GBIT_FEATURES, +	.config = &genphy_config_aneg, +	.startup = &vitesse_startup, +	.shutdown = &genphy_shutdown, +}; + +static struct phy_driver VSC8244_driver = { +	.name = "Vitesse VSC8244", +	.uid = 0xfc6c0, +	.mask = 0xffff0, +	.features = PHY_GBIT_FEATURES, +	.config = &genphy_config_aneg, +	.startup = &vitesse_startup, +	.shutdown = &genphy_shutdown, +}; + +static struct phy_driver VSC8234_driver = { +	.name = "Vitesse VSC8234", +	.uid = 0xfc620, +	.mask = 0xffff0, +	.features = PHY_GBIT_FEATURES, +	.config = &genphy_config_aneg, +	.startup = &vitesse_startup, +	.shutdown = &genphy_shutdown, +}; + +static struct phy_driver VSC8601_driver = { +	.name = "Vitesse VSC8601", +	.uid = 0x70420, +	.mask = 0xffff0, +	.features = PHY_GBIT_FEATURES, +	.config = &vsc8601_config, +	.startup = &vitesse_startup, +	.shutdown = &genphy_shutdown, +}; + +static struct phy_driver VSC8641_driver = { +	.name = "Vitesse VSC8641", +	.uid = 0x70430, +	.mask = 0xffff0, +	.features = PHY_GBIT_FEATURES, +	.config = &genphy_config_aneg, +	.startup = &vitesse_startup, +	.shutdown = &genphy_shutdown, +}; + +/* Vitesse bought Cicada, so we'll put these here */ +static struct phy_driver cis8201_driver = { +	.name = "CIS8201", +	.uid = 0xfc410, +	.mask = 0xffff0, +	.features = PHY_GBIT_FEATURES, +	.config = &vitesse_config, +	.startup = &vitesse_startup, +	.shutdown = &genphy_shutdown, +}; + +static struct phy_driver cis8204_driver = { +	.name = "Cicada Cis8204", +	.uid = 0xfc440, +	.mask = 0xffff0, +	.features = PHY_GBIT_FEATURES, +	.config = &cis8204_config, +	.startup = &vitesse_startup, +	.shutdown = &genphy_shutdown, +}; + +int phy_vitesse_init(void) +{ +	phy_register(&VSC8641_driver); +	phy_register(&VSC8601_driver); +	phy_register(&VSC8234_driver); +	phy_register(&VSC8244_driver); +	phy_register(&VSC8211_driver); +	phy_register(&VSC8221_driver); +	phy_register(&cis8201_driver); +	phy_register(&cis8204_driver); + +	return 0; +} diff --git a/include/config_phylib_all_drivers.h b/include/config_phylib_all_drivers.h new file mode 100644 index 000000000..903c7a775 --- /dev/null +++ b/include/config_phylib_all_drivers.h @@ -0,0 +1,32 @@ +/* + * Enable all PHYs + * + * This software may be used and distributed according to the + * terms of the GNU Public License, Version 2, incorporated + * herein by reference. + * + * Copyright 2011 Freescale Semiconductor, Inc. + * author Andy Fleming + * + */ +#ifndef _CONFIG_PHYLIB_ALL_H +#define _CONFIG_PHYLIB_ALL_H + +#ifdef CONFIG_PHYLIB + +#define CONFIG_PHY_VITESSE +#define CONFIG_PHY_MARVELL +#define CONFIG_PHY_MICREL +#define CONFIG_PHY_BROADCOM +#define CONFIG_PHY_DAVICOM +#define CONFIG_PHY_REALTEK +#define CONFIG_PHY_NATSEMI +#define CONFIG_PHY_LXT + +#ifdef CONFIG_PHYLIB_10G +#define CONFIG_PHY_TERANETICS +#endif /* CONFIG_PHYLIB_10G */ + +#endif /* CONFIG_PHYLIB */ + +#endif /*_CONFIG_PHYLIB_ALL_H */ diff --git a/include/phy.h b/include/phy.h index 2abd23bf2..d5817bf19 100644 --- a/include/phy.h +++ b/include/phy.h @@ -216,4 +216,14 @@ int gen10g_startup(struct phy_device *phydev);  int gen10g_shutdown(struct phy_device *phydev);  int gen10g_discover_mmds(struct phy_device *phydev); +int phy_atheros_init(void); +int phy_broadcom_init(void); +int phy_davicom_init(void); +int phy_lxt_init(void); +int phy_marvell_init(void); +int phy_micrel_init(void); +int phy_natsemi_init(void); +int phy_realtek_init(void); +int phy_teranetics_init(void); +int phy_vitesse_init(void);  #endif |