From patchwork Tue Mar 29 19:30:09 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Andy Fleming X-Patchwork-Id: 88845 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from theia.denx.de (theia.denx.de [85.214.87.163]) by ozlabs.org (Postfix) with ESMTP id 2D049B6F14 for ; Wed, 30 Mar 2011 06:46:03 +1100 (EST) Received: from localhost (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id 952ED280AB; Tue, 29 Mar 2011 21:45:57 +0200 (CEST) X-Virus-Scanned: Debian amavisd-new at theia.denx.de Received: from theia.denx.de ([127.0.0.1]) by localhost (theia.denx.de [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id hWIOt1tIWEUw; Tue, 29 Mar 2011 21:45:57 +0200 (CEST) Received: from theia.denx.de (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id DEE2B280A6; Tue, 29 Mar 2011 21:45:46 +0200 (CEST) Received: from localhost (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id 9DD01280AD for ; Tue, 29 Mar 2011 21:45:38 +0200 (CEST) X-Virus-Scanned: Debian amavisd-new at theia.denx.de Received: from theia.denx.de ([127.0.0.1]) by localhost (theia.denx.de [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id HgLonlm0-i2W for ; Tue, 29 Mar 2011 21:45:33 +0200 (CEST) X-policyd-weight: NOT_IN_SBL_XBL_SPAMHAUS=-1.5 NOT_IN_SPAMCOP=-1.5 NOT_IN_BL_NJABL=-1.5 (only DNSBL check requested) Received: from DB3EHSOBE001.bigfish.com (db3ehsobe001.messaging.microsoft.com [213.199.154.139]) by theia.denx.de (Postfix) with ESMTPS id 045CD2809C for ; Tue, 29 Mar 2011 21:45:30 +0200 (CEST) Received: from mail6-db3-R.bigfish.com (10.3.81.245) by DB3EHSOBE001.bigfish.com (10.3.84.21) with Microsoft SMTP Server id 14.1.225.8; Tue, 29 Mar 2011 19:30:26 +0000 Received: from mail6-db3 (localhost.localdomain [127.0.0.1]) by mail6-db3-R.bigfish.com (Postfix) with ESMTP id 80BF410D02DB; Tue, 29 Mar 2011 19:30:26 +0000 (UTC) X-SpamScore: 0 X-BigFish: VS0(zzzz1202hzz8275bhz2dh2a8h668h) X-Forefront-Antispam-Report: KIP:(null); UIP:(null); IPVD:NLI; H:mail.freescale.net; RD:none; EFVD:NLI Received: from mail6-db3 (localhost.localdomain [127.0.0.1]) by mail6-db3 (MessageSwitch) id 1301427022556616_6341; Tue, 29 Mar 2011 19:30:22 +0000 (UTC) Received: from DB3EHSMHS004.bigfish.com (unknown [10.3.81.249]) by mail6-db3.bigfish.com (Postfix) with ESMTP id 756F2155004E; Tue, 29 Mar 2011 19:30:22 +0000 (UTC) Received: from mail.freescale.net (70.37.183.190) by DB3EHSMHS004.bigfish.com (10.3.87.104) with Microsoft SMTP Server (TLS) id 14.1.225.22; Tue, 29 Mar 2011 19:30:16 +0000 Received: from az33smr01.freescale.net (10.64.34.199) by 039-SN1MMR1-003.039d.mgd.msft.net (10.84.1.16) with Microsoft SMTP Server id 14.1.270.2; Tue, 29 Mar 2011 14:30:14 -0500 Received: from localhost (firefly.am.freescale.net [10.82.123.6]) by az33smr01.freescale.net (8.13.1/8.13.0) with ESMTP id p2TJUErP018584; Tue, 29 Mar 2011 14:30:14 -0500 (CDT) From: Andy Fleming To: Date: Tue, 29 Mar 2011 14:30:09 -0500 Message-ID: <1301427010-7429-7-git-send-email-afleming@freescale.com> X-Mailer: git-send-email 1.6.5.2.g6ff9a In-Reply-To: <1301427010-7429-6-git-send-email-afleming@freescale.com> References: <1301427010-7429-1-git-send-email-afleming@freescale.com> <1301427010-7429-2-git-send-email-afleming@freescale.com> <1301427010-7429-3-git-send-email-afleming@freescale.com> <1301427010-7429-4-git-send-email-afleming@freescale.com> <1301427010-7429-5-git-send-email-afleming@freescale.com> <1301427010-7429-6-git-send-email-afleming@freescale.com> MIME-Version: 1.0 X-OriginatorOrg: freescale.com Cc: u-boot@lists.denx.de Subject: [U-Boot] [PATCH 6/7] phylib: Add a bunch of PHY drivers from tsec X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.9 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: u-boot-bounces@lists.denx.de Errors-To: u-boot-bounces@lists.denx.de The tsec driver had a bunch of PHY drivers already written. This converts them all into PHY Lib drivers, and serves as the first set of PHY drivers for PHY Lib. Signed-off-by: Andy Fleming --- drivers/net/phy/Makefile | 10 ++ drivers/net/phy/atheros.c | 37 +++++ drivers/net/phy/broadcom.c | 275 ++++++++++++++++++++++++++++++++ drivers/net/phy/davicom.c | 86 ++++++++++ drivers/net/phy/lxt.c | 76 +++++++++ drivers/net/phy/marvell.c | 357 ++++++++++++++++++++++++++++++++++++++++++ drivers/net/phy/micrel.c | 29 ++++ drivers/net/phy/natsemi.c | 85 ++++++++++ drivers/net/phy/phy.c | 28 ++++ drivers/net/phy/realtek.c | 120 ++++++++++++++ drivers/net/phy/teranetics.c | 43 +++++ drivers/net/phy/vitesse.c | 330 ++++++++++++++++++++++++++++++++++++++ include/phy.h | 11 ++ include/phylib_all_drivers.h | 25 +++ 14 files changed, 1512 insertions(+), 0 deletions(-) create mode 100644 drivers/net/phy/atheros.c create mode 100644 drivers/net/phy/broadcom.c create mode 100644 drivers/net/phy/davicom.c create mode 100644 drivers/net/phy/lxt.c create mode 100644 drivers/net/phy/marvell.c create mode 100644 drivers/net/phy/micrel.c create mode 100644 drivers/net/phy/natsemi.c create mode 100644 drivers/net/phy/realtek.c create mode 100644 drivers/net/phy/teranetics.c create mode 100644 drivers/net/phy/vitesse.c create mode 100644 include/phylib_all_drivers.h diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile index 7cb1094..f67a79a 100644 --- a/drivers/net/phy/Makefile +++ b/drivers/net/phy/Makefile @@ -28,6 +28,16 @@ LIB := $(obj)libphy.o COBJS-$(CONFIG_BITBANGMII) += miiphybb.o COBJS-$(CONFIG_MV88E61XX_SWITCH) += mv88e61xx.o COBJS-$(CONFIG_PHYLIB) += phy.o +COBJS-$(CONFIG_PHY_VITESSE) += vitesse.o +COBJS-$(CONFIG_PHY_TERANETICS) += teranetics.o +COBJS-$(CONFIG_PHY_MARVELL) += marvell.o +COBJS-$(CONFIG_PHY_REALTEK) += realtek.o +COBJS-$(CONFIG_PHY_BROADCOM) += broadcom.o +COBJS-$(CONFIG_PHY_DAVICOM) += davicom.o +COBJS-$(CONFIG_PHY_LXT) += lxt.o +COBJS-$(CONFIG_PHY_NATSEMI) += natsemi.o +COBJS-$(CONFIG_PHY_MICREL) += micrel.o +COBJS-$(CONFIG_PHY_ATHEROS) += atheros.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 0000000..68bb5cd --- /dev/null +++ b/drivers/net/phy/atheros.c @@ -0,0 +1,37 @@ +/* + * Atheros PHY drivers + * + * 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 + * + */ +#include + +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 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 0000000..e62a81d --- /dev/null +++ b/drivers/net/phy/broadcom.c @@ -0,0 +1,275 @@ +/* + * Broadcom PHY drivers + * + * This software may be used and distributed according to the + * terms of the GNU Public License, Version 2, incorporated + * herein by reference. + * + * Copyright 2010-2011 Freescale Semiconductor, Inc. + * author Andy Fleming + * + */ +#include +#include +#include + +/* 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); + + 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 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 0000000..229e1bd --- /dev/null +++ b/drivers/net/phy/davicom.c @@ -0,0 +1,86 @@ +/* + * Davicom PHY drivers + * + * This software may be used and distributed according to the + * terms of the GNU Public License, Version 2, incorporated + * herein by reference. + * + * Copyright 2010-2011 Freescale Semiconductor, Inc. + * author Andy Fleming + * + */ +#include + +#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 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 0000000..4e38bb6 --- /dev/null +++ b/drivers/net/phy/lxt.c @@ -0,0 +1,76 @@ +/* + * LXT PHY drivers + * + * This software may be used and distributed according to the + * terms of the GNU Public License, Version 2, incorporated + * herein by reference. + * + * Copyright 2010-2011 Freescale Semiconductor, Inc. + * author Andy Fleming + * + */ +#include + +/* 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, + .startup = &lxt971_startup, + .shutdown = &genphy_shutdown, +}; + +int 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 0000000..6937c93 --- /dev/null +++ b/drivers/net/phy/marvell.c @@ -0,0 +1,357 @@ +/* + * Marvell PHY drivers + * + * This software may be used and distributed according to the + * terms of the GNU Public License, Version 2, incorporated + * herein by reference. + * + * Copyright 2010-2011 Freescale Semiconductor, Inc. + * author Andy Fleming + * + */ +#include +#include +#include + +#define PHY_AUTONEGOTIATE_TIMEOUT 5000 + +/* 88E1011 PHY Status Register */ +#define MIIM_88E1011_PHY_STATUS 0x11 +#define MIIM_88E1011_PHYSTAT_SPEED 0xc000 +#define MIIM_88E1011_PHYSTAT_GBIT 0x8000 +#define MIIM_88E1011_PHYSTAT_100 0x4000 +#define MIIM_88E1011_PHYSTAT_DUPLEX 0x2000 +#define MIIM_88E1011_PHYSTAT_SPDDONE 0x0800 +#define MIIM_88E1011_PHYSTAT_LINK 0x0400 + +#define MIIM_88E1011_PHY_SCR 0x10 +#define MIIM_88E1011_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 + +/* 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_PAGE 29 +#define MIIM_88E1145_PHY_CAL_OV 30 + +/* 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 m88e1011s_parse_status(struct phy_device *phydev) +{ + unsigned int speed; + unsigned int mii_reg; + + mii_reg = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_88E1011_PHY_STATUS); + + if ((mii_reg & MIIM_88E1011_PHYSTAT_LINK) && + !(mii_reg & MIIM_88E1011_PHYSTAT_SPDDONE)) { + int i = 0; + + puts("Waiting for PHY realtime link"); + while (!(mii_reg & MIIM_88E1011_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_88E1011_PHY_STATUS); + } + puts(" done\n"); + udelay(500000); /* another 500 ms (results in faster booting) */ + } else { + if (mii_reg & MIIM_88E1011_PHYSTAT_LINK) + phydev->link = 1; + else + phydev->link = 0; + } + + if (mii_reg & MIIM_88E1011_PHYSTAT_DUPLEX) + phydev->duplex = DUPLEX_FULL; + else + phydev->duplex = DUPLEX_HALF; + + speed = mii_reg & MIIM_88E1011_PHYSTAT_SPEED; + + switch (speed) { + case MIIM_88E1011_PHYSTAT_GBIT: + phydev->speed = SPEED_1000; + break; + case MIIM_88E1011_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); + m88e1011s_parse_status(phydev); + + return 0; +} + +/* Marvell 88E1111S */ +static int m88e1111s_config(struct phy_device *phydev) +{ + int reg; + + /* Reset and configure the PHY */ + phy_write(phydev, MDIO_DEVAD_NONE, MII_BMCR, BMCR_RESET); + + 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); + + return 0; +} + +/* Marvell 88E1118 */ +static int m88e1118_config(struct phy_device *phydev) +{ + /* Reset and configure the PHY */ + phy_write(phydev, MDIO_DEVAD_NONE, MII_BMCR, BMCR_RESET); + /* Change Page Number */ + phy_write(phydev, MDIO_DEVAD_NONE, 0x16, 0x0002); + /* Delay RGMII TX and RX */ + phy_write(phydev, MDIO_DEVAD_NONE, 0x15, 0x1070); + /* Change Page Number */ + phy_write(phydev, MDIO_DEVAD_NONE, 0x16, 0x0003); + /* Adjust LED control */ + phy_write(phydev, MDIO_DEVAD_NONE, 0x10, 0x021e); + /* Change Page Number */ + phy_write(phydev, MDIO_DEVAD_NONE, 0x16, 0x0000); + + phy_write(phydev, MDIO_DEVAD_NONE, MII_BMCR, BMCR_RESET); + + genphy_config_aneg(phydev); + + return 0; +} + +static int m88e1118_startup(struct phy_device *phydev) +{ + /* Change Page Number */ + phy_write(phydev, MDIO_DEVAD_NONE, 0x16, 0x0000); + + genphy_update_link(phydev); + m88e1011s_parse_status(phydev); + + return 0; +} + +/* Marvell 88E1121R */ +static int m88e1121_config(struct phy_device *phydev) +{ + int pg; + + /* Reset and configure the PHY */ + phy_write(phydev, MDIO_DEVAD_NONE, MII_BMCR, BMCR_RESET); + 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; + + /* Reset and configure the PHY */ + phy_write(phydev, MDIO_DEVAD_NONE, MII_BMCR, BMCR_RESET); + + /* Errata E0, E1 */ + phy_write(phydev, MDIO_DEVAD_NONE, 29, 0x001b); + phy_write(phydev, MDIO_DEVAD_NONE, 30, 0x418f); + phy_write(phydev, MDIO_DEVAD_NONE, 29, 0x0016); + phy_write(phydev, MDIO_DEVAD_NONE, 30, 0xa2da); + + phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1011_PHY_SCR, + MIIM_88E1011_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); + + phy_write(phydev, MDIO_DEVAD_NONE, MII_BMCR, BMCR_RESET); + + genphy_config_aneg(phydev); + + return 0; +} + +static int m88e1145_startup(struct phy_device *phydev) +{ + genphy_update_link(phydev); + phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1111_PHY_LED_CONTROL, + MIIM_88E1111_PHY_LED_DIRECT); + m88e1011s_parse_status(phydev); + + return 0; +} + +/* Marvell 88E1149S */ +static int m88e1149_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, 0x0); + phy_write(phydev, MDIO_DEVAD_NONE, 0x1e, 0x100); + + phy_write(phydev, MDIO_DEVAD_NONE, MII_BMCR, BMCR_RESET); + genphy_config_aneg(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 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 0000000..4e0389a --- /dev/null +++ b/drivers/net/phy/micrel.c @@ -0,0 +1,29 @@ +/* + * Micrel PHY drivers + * + * This software may be used and distributed according to the + * terms of the GNU Public License, Version 2, incorporated + * herein by reference. + * + * Copyright 2010-2011 Freescale Semiconductor, Inc. + * author Andy Fleming + * + */ +#include + +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 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 0000000..a669eac --- /dev/null +++ b/drivers/net/phy/natsemi.c @@ -0,0 +1,85 @@ +/* + * National Semiconductor PHY drivers + * + * This software may be used and distributed according to the + * terms of the GNU Public License, Version 2, incorporated + * herein by reference. + * + * Copyright 2010-2011 Freescale Semiconductor, Inc. + * author Andy Fleming + * + */ +#include + +/* 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 natsemi_init(void) +{ + phy_register(&DP83865_driver); + + return 0; +} diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c index ca35404..50e85fe 100644 --- a/drivers/net/phy/phy.c +++ b/drivers/net/phy/phy.c @@ -494,6 +494,34 @@ int phy_init(void) { INIT_LIST_HEAD(&phy_drivers); +#ifdef CONFIG_PHY_BROADCOM + broadcom_init(); +#endif +#ifdef CONFIG_PHY_DAVICOM + davicom_init(); +#endif +#ifdef CONFIG_PHY_LXT + lxt_init(); +#endif +#ifdef CONFIG_PHY_MARVELL + marvell_init(); +#endif +#ifdef CONFIG_PHY_MICREL + micrel_init(); +#endif +#ifdef CONFIG_PHY_NATSEMI + natsemi_init(); +#endif +#ifdef CONFIG_PHY_REALTEK + realtek_init(); +#endif +#ifdef CONFIG_PHY_VITESSE + vitesse_init(); +#endif +#ifdef CONFIG_PHY_ATHEROS + atheros_init(); +#endif + return 0; } diff --git a/drivers/net/phy/realtek.c b/drivers/net/phy/realtek.c new file mode 100644 index 0000000..8cb696f --- /dev/null +++ b/drivers/net/phy/realtek.c @@ -0,0 +1,120 @@ +/* + * RealTek PHY drivers + * + * This software may be used and distributed according to the + * terms of the GNU Public License, Version 2, incorporated + * herein by reference. + * + * Copyright 2010-2011 Freescale Semiconductor, Inc. + * author Andy Fleming + * + */ +#include +#include +#include + +#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 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 0000000..387e044 --- /dev/null +++ b/drivers/net/phy/teranetics.c @@ -0,0 +1,43 @@ +/* + * Teranetics PHY drivers + * + * This software may be used and distributed according to the + * terms of the GNU Public License, Version 2, incorporated + * herein by reference. + * + * Copyright 2010-2011 Freescale Semiconductor, Inc. + * author Andy Fleming + * + */ +#include + +int tn2020_config(struct phy_device *phydev) +{ + if (phydev->port == PORT_FIBRE) { + phy_write(phydev, 30, 93, 2); + phy_write(phydev, 7, 0, 0x3200); + } + + phydev->mmds = (MDIO_DEVS_PMAPMD | MDIO_DEVS_PCS | + MDIO_DEVS_PHYXS | MDIO_DEVS_AN | + MDIO_DEVS_VEND1 | MDIO_DEVS_VEND2); + + return 0; +} + +struct phy_driver tn2020_driver = { + .name = "Teranetics TN2020", + .uid = 0x00a19410, + .mask = 0xfffffff0, + .features = PHY_10G_FEATURES, + .config = &tn2020_config, + .startup = &gen10g_startup, + .shutdown = &gen10g_shutdown, +}; + +int 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 0000000..d34f04b --- /dev/null +++ b/drivers/net/phy/vitesse.c @@ -0,0 +1,330 @@ +/* + * Vitesse PHY drivers + * + * This software may be used and distributed according to the + * terms of the GNU Public License, Version 2, incorporated + * herein by reference. + * + * Copyright 2010-2011 Freescale Semiconductor, Inc. + * author Andy Fleming + * + */ +#include + +/* Cicada Auxiliary Control/Status Register */ +#define MIIM_CIS8201_AUX_CONSTAT 0x1c +#define MIIM_CIS8201_AUXCONSTAT_INIT 0x0004 +#define MIIM_CIS8201_AUXCONSTAT_DUPLEX 0x0020 +#define MIIM_CIS8201_AUXCONSTAT_SPEED 0x0018 +#define MIIM_CIS8201_AUXCONSTAT_GBIT 0x0010 +#define MIIM_CIS8201_AUXCONSTAT_100 0x0008 + +/* Cicada Extended Control Register 1 */ +#define MIIM_CIS8201_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 + +/* Entry for Vitesse VSC8244 regs starts here */ +/* Vitesse VSC8244 Auxiliary Control/Status Register */ +#define MIIM_VSC8244_AUX_CONSTAT 0x1c +#define MIIM_VSC8244_AUXCONSTAT_INIT 0x0000 +#define MIIM_VSC8244_AUXCONSTAT_DUPLEX 0x0020 +#define MIIM_VSC8244_AUXCONSTAT_SPEED 0x0018 +#define MIIM_VSC8244_AUXCONSTAT_GBIT 0x0010 +#define MIIM_VSC8244_AUXCONSTAT_100 0x0008 +#define MIIM_CONTROL_INIT_LOOPBACK 0x4000 + +/* 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 cis8201_config(struct phy_device *phydev) +{ + /* Override PHY config settings */ + phy_write(phydev, MDIO_DEVAD_NONE, MIIM_CIS8201_AUX_CONSTAT, + MIIM_CIS8201_AUXCONSTAT_INIT); + /* Set up the interface mode */ + phy_write(phydev, MDIO_DEVAD_NONE, MIIM_CIS8201_EXT_CON1, + MIIM_CIS8201_EXTCON1_INIT); + + genphy_config_aneg(phydev); + + return 0; +} + +static int cis8201_parse_status(struct phy_device *phydev) +{ + int speed; + int mii_reg; + + mii_reg = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_CIS8201_AUX_CONSTAT); + + if (mii_reg & MIIM_CIS8201_AUXCONSTAT_DUPLEX) + phydev->duplex = DUPLEX_FULL; + else + phydev->duplex = DUPLEX_HALF; + + speed = mii_reg & MIIM_CIS8201_AUXCONSTAT_SPEED; + switch (speed) { + case MIIM_CIS8201_AUXCONSTAT_GBIT: + phydev->speed = SPEED_1000; + break; + case MIIM_CIS8201_AUXCONSTAT_100: + phydev->speed = SPEED_100; + break; + default: + phydev->speed = SPEED_10; + break; + } + + return 0; +} + +static int cis8201_startup(struct phy_device *phydev) +{ + genphy_update_link(phydev); + cis8201_parse_status(phydev); + + return 0; +} + +static int cis8204_config(struct phy_device *phydev) +{ + /* Override PHY config settings */ + phy_write(phydev, MDIO_DEVAD_NONE, MIIM_CIS8201_AUX_CONSTAT, + MIIM_CIS8201_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 VSC8211 */ +static int vsc8211_config(struct phy_device *phydev) +{ + /* Override PHY config settings */ + phy_write(phydev, MDIO_DEVAD_NONE, MIIM_CIS8201_AUX_CONSTAT, + MIIM_CIS8201_AUXCONSTAT_INIT); + /* Set up the interface mode */ + phy_write(phydev, MDIO_DEVAD_NONE, MIIM_CIS8201_EXT_CON1, + MIIM_CIS8201_EXTCON1_INIT); + + genphy_config_aneg(phydev); + + return 0; +} + +static int vsc8211_parse_status(struct phy_device *phydev) +{ + unsigned int speed; + unsigned int mii_reg; + + mii_reg = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_CIS8201_AUX_CONSTAT); + + if (mii_reg & MIIM_CIS8201_AUXCONSTAT_DUPLEX) + phydev->duplex = DUPLEX_FULL; + else + phydev->duplex = DUPLEX_HALF; + + speed = mii_reg & MIIM_CIS8201_AUXCONSTAT_SPEED; + switch (speed) { + case MIIM_CIS8201_AUXCONSTAT_GBIT: + phydev->speed = SPEED_1000; + break; + case MIIM_CIS8201_AUXCONSTAT_100: + phydev->speed = SPEED_100; + break; + default: + phydev->speed = SPEED_10; + break; + } + + return 0; +} + +static int vsc8211_startup(struct phy_device *phydev) +{ + /* Read the Status (2x to make sure link is right) */ + genphy_update_link(phydev); + vsc8211_parse_status(phydev); + + return 0; +} + +/* Vitesse VSC8244 */ +static int vsc8244_parse_status(struct phy_device *phydev) +{ + unsigned int speed; + unsigned int mii_reg; + + mii_reg = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_VSC8244_AUX_CONSTAT); + + if (mii_reg & MIIM_VSC8244_AUXCONSTAT_DUPLEX) + phydev->duplex = DUPLEX_FULL; + else + phydev->duplex = DUPLEX_HALF; + + speed = mii_reg & MIIM_VSC8244_AUXCONSTAT_SPEED; + switch (speed) { + case MIIM_VSC8244_AUXCONSTAT_GBIT: + phydev->speed = SPEED_1000; + break; + case MIIM_VSC8244_AUXCONSTAT_100: + phydev->speed = SPEED_100; + break; + default: + phydev->speed = SPEED_10; + break; + } + + return 0; +} + +static int vsc8244_startup(struct phy_device *phydev) +{ + /* Read the Status (2x to make sure link is right) */ + genphy_update_link(phydev); + vsc8244_parse_status(phydev); + + 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 = &vsc8211_config, + .startup = &vsc8211_startup, + .shutdown = &genphy_shutdown, +}; + +static struct phy_driver VSC8221_driver = { + .name = "Vitesse VSC8221", + .uid = 0xfc550, + .mask = 0xffff0, + .features = PHY_GBIT_FEATURES, + .config = &genphy_config, + .startup = &vsc8244_startup, + .shutdown = &genphy_shutdown, +}; + +static struct phy_driver VSC8244_driver = { + .name = "Vitesse VSC8244", + .uid = 0xfc6c0, + .mask = 0xffff0, + .features = PHY_GBIT_FEATURES, + .config = &genphy_config, + .startup = &vsc8244_startup, + .shutdown = &genphy_shutdown, +}; + +static struct phy_driver VSC8234_driver = { + .name = "Vitesse VSC8234", + .uid = 0xfc620, + .mask = 0xffff0, + .features = PHY_GBIT_FEATURES, + .config = &genphy_config, + .startup = &vsc8244_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 = &vsc8244_startup, + .shutdown = &genphy_shutdown, +}; + +static struct phy_driver VSC8641_driver = { + .name = "Vitesse VSC8641", + .uid = 0x70430, + .mask = 0xffff0, + .features = PHY_GBIT_FEATURES, + .config = &genphy_config, + .startup = &vsc8244_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 = &cis8201_config, + .startup = &cis8201_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 = &cis8201_startup, + .shutdown = &genphy_shutdown, +}; + +int 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/phy.h b/include/phy.h index fccf1f7..54b5663 100644 --- a/include/phy.h +++ b/include/phy.h @@ -484,4 +484,15 @@ int genphy_shutdown(struct phy_device *phydev); int gen10g_config(struct phy_device *phydev); int gen10g_startup(struct phy_device *phydev); int gen10g_shutdown(struct phy_device *phydev); + +int teranetics_init(void); +int vitesse_init(void); +int marvell_init(void); +int davicom_init(void); +int realtek_init(void); +int micrel_init(void); +int natsemi_init(void); +int broadcom_init(void); +int lxt_init(void); +int atheros_init(void); #endif diff --git a/include/phylib_all_drivers.h b/include/phylib_all_drivers.h new file mode 100644 index 0000000..a73b3d7 --- /dev/null +++ b/include/phylib_all_drivers.h @@ -0,0 +1,25 @@ +/* + * 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 + +#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_TERANETICS +#define CONFIG_PHY_LXT + +#endif