avionic design with actual uboot and tooling
submodule of avionic design uboot bootloader and with included tools to get you started , read readme.md and readme-tk1-loader.md
This commit is contained in:
29
u-boot/drivers/net/phy/Makefile
Normal file
29
u-boot/drivers/net/phy/Makefile
Normal file
@@ -0,0 +1,29 @@
|
||||
#
|
||||
# (C) Copyright 2008
|
||||
# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0+
|
||||
#
|
||||
|
||||
obj-$(CONFIG_BITBANGMII) += miiphybb.o
|
||||
obj-$(CONFIG_MV88E61XX_SWITCH) += mv88e61xx.o
|
||||
obj-$(CONFIG_MV88E6352_SWITCH) += mv88e6352.o
|
||||
|
||||
obj-$(CONFIG_PHYLIB) += phy.o
|
||||
obj-$(CONFIG_PHYLIB_10G) += generic_10g.o
|
||||
obj-$(CONFIG_PHY_AQUANTIA) += aquantia.o
|
||||
obj-$(CONFIG_PHY_ATHEROS) += atheros.o
|
||||
obj-$(CONFIG_PHY_BROADCOM) += broadcom.o
|
||||
obj-$(CONFIG_PHY_CORTINA) += cortina.o
|
||||
obj-$(CONFIG_PHY_DAVICOM) += davicom.o
|
||||
obj-$(CONFIG_PHY_ET1011C) += et1011c.o
|
||||
obj-$(CONFIG_PHY_LXT) += lxt.o
|
||||
obj-$(CONFIG_PHY_MARVELL) += marvell.o
|
||||
obj-$(CONFIG_PHY_MICREL) += micrel.o
|
||||
obj-$(CONFIG_PHY_NATSEMI) += natsemi.o
|
||||
obj-$(CONFIG_PHY_REALTEK) += realtek.o
|
||||
obj-$(CONFIG_PHY_SMSC) += smsc.o
|
||||
obj-$(CONFIG_PHY_TERANETICS) += teranetics.o
|
||||
obj-$(CONFIG_PHY_TI) += ti.o
|
||||
obj-$(CONFIG_PHY_XILINX) += xilinx_phy.o
|
||||
obj-$(CONFIG_PHY_VITESSE) += vitesse.o
|
||||
199
u-boot/drivers/net/phy/aquantia.c
Normal file
199
u-boot/drivers/net/phy/aquantia.c
Normal file
@@ -0,0 +1,199 @@
|
||||
/*
|
||||
* Aquantia PHY drivers
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*
|
||||
* Copyright 2014 Freescale Semiconductor, Inc.
|
||||
*/
|
||||
#include <config.h>
|
||||
#include <common.h>
|
||||
#include <phy.h>
|
||||
|
||||
#ifndef CONFIG_PHYLIB_10G
|
||||
#error The Aquantia PHY needs 10G support
|
||||
#endif
|
||||
|
||||
#define AQUNTIA_10G_CTL 0x20
|
||||
#define AQUNTIA_VENDOR_P1 0xc400
|
||||
|
||||
#define AQUNTIA_SPEED_LSB_MASK 0x2000
|
||||
#define AQUNTIA_SPEED_MSB_MASK 0x40
|
||||
|
||||
int aquantia_config(struct phy_device *phydev)
|
||||
{
|
||||
u32 val = phy_read(phydev, MDIO_MMD_PMAPMD, MII_BMCR);
|
||||
|
||||
if (phydev->interface == PHY_INTERFACE_MODE_SGMII) {
|
||||
/* 1000BASE-T mode */
|
||||
phydev->advertising = SUPPORTED_1000baseT_Full;
|
||||
phydev->supported = phydev->advertising;
|
||||
|
||||
val = (val & ~AQUNTIA_SPEED_LSB_MASK) | AQUNTIA_SPEED_MSB_MASK;
|
||||
phy_write(phydev, MDIO_MMD_PMAPMD, MII_BMCR, val);
|
||||
} else if (phydev->interface == PHY_INTERFACE_MODE_XGMII) {
|
||||
/* 10GBASE-T mode */
|
||||
phydev->advertising = SUPPORTED_10000baseT_Full;
|
||||
phydev->supported = phydev->advertising;
|
||||
|
||||
if (!(val & AQUNTIA_SPEED_LSB_MASK) ||
|
||||
!(val & AQUNTIA_SPEED_MSB_MASK))
|
||||
phy_write(phydev, MDIO_MMD_PMAPMD, MII_BMCR,
|
||||
AQUNTIA_SPEED_LSB_MASK |
|
||||
AQUNTIA_SPEED_MSB_MASK);
|
||||
} else if (phydev->interface == PHY_INTERFACE_MODE_SGMII_2500) {
|
||||
/* 2.5GBASE-T mode */
|
||||
phydev->advertising = SUPPORTED_1000baseT_Full;
|
||||
phydev->supported = phydev->advertising;
|
||||
|
||||
phy_write(phydev, MDIO_MMD_AN, AQUNTIA_10G_CTL, 1);
|
||||
phy_write(phydev, MDIO_MMD_AN, AQUNTIA_VENDOR_P1, 0x9440);
|
||||
} else if (phydev->interface == PHY_INTERFACE_MODE_MII) {
|
||||
/* 100BASE-TX mode */
|
||||
phydev->advertising = SUPPORTED_100baseT_Full;
|
||||
phydev->supported = phydev->advertising;
|
||||
|
||||
val = (val & ~AQUNTIA_SPEED_MSB_MASK) | AQUNTIA_SPEED_LSB_MASK;
|
||||
phy_write(phydev, MDIO_MMD_PMAPMD, MII_BMCR, val);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int aquantia_startup(struct phy_device *phydev)
|
||||
{
|
||||
u32 reg, speed;
|
||||
int i = 0;
|
||||
|
||||
phydev->duplex = DUPLEX_FULL;
|
||||
|
||||
/* if the AN is still in progress, wait till timeout. */
|
||||
phy_read(phydev, MDIO_MMD_AN, MDIO_STAT1);
|
||||
reg = phy_read(phydev, MDIO_MMD_AN, MDIO_STAT1);
|
||||
if (!(reg & MDIO_AN_STAT1_COMPLETE)) {
|
||||
printf("%s Waiting for PHY auto negotiation to complete",
|
||||
phydev->dev->name);
|
||||
do {
|
||||
udelay(1000);
|
||||
reg = phy_read(phydev, MDIO_MMD_AN, MDIO_STAT1);
|
||||
if ((i++ % 500) == 0)
|
||||
printf(".");
|
||||
} while (!(reg & MDIO_AN_STAT1_COMPLETE) &&
|
||||
i < (4 * PHY_ANEG_TIMEOUT));
|
||||
|
||||
if (i > PHY_ANEG_TIMEOUT)
|
||||
printf(" TIMEOUT !\n");
|
||||
}
|
||||
|
||||
/* Read twice because link state is latched and a
|
||||
* read moves the current state into the register */
|
||||
phy_read(phydev, MDIO_MMD_AN, MDIO_STAT1);
|
||||
reg = phy_read(phydev, MDIO_MMD_AN, MDIO_STAT1);
|
||||
if (reg < 0 || !(reg & MDIO_STAT1_LSTATUS))
|
||||
phydev->link = 0;
|
||||
else
|
||||
phydev->link = 1;
|
||||
|
||||
speed = phy_read(phydev, MDIO_MMD_PMAPMD, MII_BMCR);
|
||||
if (speed & AQUNTIA_SPEED_MSB_MASK) {
|
||||
if (speed & AQUNTIA_SPEED_LSB_MASK)
|
||||
phydev->speed = SPEED_10000;
|
||||
else
|
||||
phydev->speed = SPEED_1000;
|
||||
} else {
|
||||
if (speed & AQUNTIA_SPEED_LSB_MASK)
|
||||
phydev->speed = SPEED_100;
|
||||
else
|
||||
phydev->speed = SPEED_10;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct phy_driver aq1202_driver = {
|
||||
.name = "Aquantia AQ1202",
|
||||
.uid = 0x3a1b445,
|
||||
.mask = 0xfffffff0,
|
||||
.features = PHY_10G_FEATURES,
|
||||
.mmds = (MDIO_MMD_PMAPMD | MDIO_MMD_PCS|
|
||||
MDIO_MMD_PHYXS | MDIO_MMD_AN |
|
||||
MDIO_MMD_VEND1),
|
||||
.config = &aquantia_config,
|
||||
.startup = &aquantia_startup,
|
||||
.shutdown = &gen10g_shutdown,
|
||||
};
|
||||
|
||||
struct phy_driver aq2104_driver = {
|
||||
.name = "Aquantia AQ2104",
|
||||
.uid = 0x3a1b460,
|
||||
.mask = 0xfffffff0,
|
||||
.features = PHY_10G_FEATURES,
|
||||
.mmds = (MDIO_MMD_PMAPMD | MDIO_MMD_PCS|
|
||||
MDIO_MMD_PHYXS | MDIO_MMD_AN |
|
||||
MDIO_MMD_VEND1),
|
||||
.config = &aquantia_config,
|
||||
.startup = &aquantia_startup,
|
||||
.shutdown = &gen10g_shutdown,
|
||||
};
|
||||
|
||||
struct phy_driver aqr105_driver = {
|
||||
.name = "Aquantia AQR105",
|
||||
.uid = 0x3a1b4a2,
|
||||
.mask = 0xfffffff0,
|
||||
.features = PHY_10G_FEATURES,
|
||||
.mmds = (MDIO_MMD_PMAPMD | MDIO_MMD_PCS|
|
||||
MDIO_MMD_PHYXS | MDIO_MMD_AN |
|
||||
MDIO_MMD_VEND1),
|
||||
.config = &aquantia_config,
|
||||
.startup = &aquantia_startup,
|
||||
.shutdown = &gen10g_shutdown,
|
||||
};
|
||||
|
||||
struct phy_driver aqr106_driver = {
|
||||
.name = "Aquantia AQR106",
|
||||
.uid = 0x3a1b4d0,
|
||||
.mask = 0xfffffff0,
|
||||
.features = PHY_10G_FEATURES,
|
||||
.mmds = (MDIO_MMD_PMAPMD | MDIO_MMD_PCS|
|
||||
MDIO_MMD_PHYXS | MDIO_MMD_AN |
|
||||
MDIO_MMD_VEND1),
|
||||
.config = &aquantia_config,
|
||||
.startup = &aquantia_startup,
|
||||
.shutdown = &gen10g_shutdown,
|
||||
};
|
||||
|
||||
struct phy_driver aqr107_driver = {
|
||||
.name = "Aquantia AQR107",
|
||||
.uid = 0x3a1b4e0,
|
||||
.mask = 0xfffffff0,
|
||||
.features = PHY_10G_FEATURES,
|
||||
.mmds = (MDIO_MMD_PMAPMD | MDIO_MMD_PCS|
|
||||
MDIO_MMD_PHYXS | MDIO_MMD_AN |
|
||||
MDIO_MMD_VEND1),
|
||||
.config = &aquantia_config,
|
||||
.startup = &aquantia_startup,
|
||||
.shutdown = &gen10g_shutdown,
|
||||
};
|
||||
|
||||
struct phy_driver aqr405_driver = {
|
||||
.name = "Aquantia AQR405",
|
||||
.uid = 0x3a1b4b2,
|
||||
.mask = 0xfffffff0,
|
||||
.features = PHY_10G_FEATURES,
|
||||
.mmds = (MDIO_MMD_PMAPMD | MDIO_MMD_PCS|
|
||||
MDIO_MMD_PHYXS | MDIO_MMD_AN |
|
||||
MDIO_MMD_VEND1),
|
||||
.config = &aquantia_config,
|
||||
.startup = &aquantia_startup,
|
||||
.shutdown = &gen10g_shutdown,
|
||||
};
|
||||
|
||||
int phy_aquantia_init(void)
|
||||
{
|
||||
phy_register(&aq1202_driver);
|
||||
phy_register(&aq2104_driver);
|
||||
phy_register(&aqr105_driver);
|
||||
phy_register(&aqr106_driver);
|
||||
phy_register(&aqr107_driver);
|
||||
phy_register(&aqr405_driver);
|
||||
|
||||
return 0;
|
||||
}
|
||||
79
u-boot/drivers/net/phy/atheros.c
Normal file
79
u-boot/drivers/net/phy/atheros.c
Normal file
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
* Atheros PHY drivers
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*
|
||||
* Copyright 2011, 2013 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);
|
||||
|
||||
phydev->supported = phydev->drv->features;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ar8035_config(struct phy_device *phydev)
|
||||
{
|
||||
int regval;
|
||||
|
||||
phy_write(phydev, MDIO_DEVAD_NONE, 0xd, 0x0007);
|
||||
phy_write(phydev, MDIO_DEVAD_NONE, 0xe, 0x8016);
|
||||
phy_write(phydev, MDIO_DEVAD_NONE, 0xd, 0x4007);
|
||||
regval = phy_read(phydev, MDIO_DEVAD_NONE, 0xe);
|
||||
phy_write(phydev, MDIO_DEVAD_NONE, 0xe, (regval|0x0018));
|
||||
|
||||
phy_write(phydev, MDIO_DEVAD_NONE, 0x1d, 0x05);
|
||||
regval = phy_read(phydev, MDIO_DEVAD_NONE, 0x1e);
|
||||
phy_write(phydev, MDIO_DEVAD_NONE, 0x1e, (regval|0x0100));
|
||||
|
||||
phydev->supported = phydev->drv->features;
|
||||
|
||||
genphy_config_aneg(phydev);
|
||||
genphy_restart_aneg(phydev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct phy_driver AR8021_driver = {
|
||||
.name = "AR8021",
|
||||
.uid = 0x4dd040,
|
||||
.mask = 0x4ffff0,
|
||||
.features = PHY_GBIT_FEATURES,
|
||||
.config = ar8021_config,
|
||||
.startup = genphy_startup,
|
||||
.shutdown = genphy_shutdown,
|
||||
};
|
||||
|
||||
static struct phy_driver AR8031_driver = {
|
||||
.name = "AR8031/AR8033",
|
||||
.uid = 0x4dd074,
|
||||
.mask = 0xffffffef,
|
||||
.features = PHY_GBIT_FEATURES,
|
||||
.config = ar8035_config,
|
||||
.startup = genphy_startup,
|
||||
.shutdown = genphy_shutdown,
|
||||
};
|
||||
|
||||
static struct phy_driver AR8035_driver = {
|
||||
.name = "AR8035",
|
||||
.uid = 0x4dd072,
|
||||
.mask = 0xffffffef,
|
||||
.features = PHY_GBIT_FEATURES,
|
||||
.config = ar8035_config,
|
||||
.startup = genphy_startup,
|
||||
.shutdown = genphy_shutdown,
|
||||
};
|
||||
|
||||
int phy_atheros_init(void)
|
||||
{
|
||||
phy_register(&AR8021_driver);
|
||||
phy_register(&AR8031_driver);
|
||||
phy_register(&AR8035_driver);
|
||||
|
||||
return 0;
|
||||
}
|
||||
313
u-boot/drivers/net/phy/broadcom.c
Normal file
313
u-boot/drivers/net/phy/broadcom.c
Normal file
@@ -0,0 +1,313 @@
|
||||
/*
|
||||
* Broadcom PHY drivers
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*
|
||||
* 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)
|
||||
{
|
||||
int ret;
|
||||
|
||||
/* Read the Status (2x to make sure link is right) */
|
||||
ret = genphy_update_link(phydev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return bcm54xx_parse_status(phydev);
|
||||
}
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
static int bcm_cygnus_startup(struct phy_device *phydev)
|
||||
{
|
||||
int ret;
|
||||
|
||||
/* Read the Status (2x to make sure link is right) */
|
||||
ret = genphy_update_link(phydev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return genphy_parse_link(phydev);
|
||||
}
|
||||
|
||||
static int bcm_cygnus_config(struct phy_device *phydev)
|
||||
{
|
||||
genphy_config_aneg(phydev);
|
||||
|
||||
phy_reset(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)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (bcm5482_is_serdes(phydev)) {
|
||||
bcm5482_parse_serdes_sr(phydev);
|
||||
phydev->port = PORT_FIBRE;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Wait for auto-negotiation to complete or fail */
|
||||
ret = genphy_update_link(phydev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Parse BCM54xx copper aux status register */
|
||||
return bcm54xx_parse_status(phydev);
|
||||
}
|
||||
|
||||
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,
|
||||
};
|
||||
|
||||
static struct phy_driver BCM_CYGNUS_driver = {
|
||||
.name = "Broadcom CYGNUS GPHY",
|
||||
.uid = 0xae025200,
|
||||
.mask = 0xfffff0,
|
||||
.features = PHY_GBIT_FEATURES,
|
||||
.config = &bcm_cygnus_config,
|
||||
.startup = &bcm_cygnus_startup,
|
||||
.shutdown = &genphy_shutdown,
|
||||
};
|
||||
|
||||
int phy_broadcom_init(void)
|
||||
{
|
||||
phy_register(&BCM5482S_driver);
|
||||
phy_register(&BCM5464S_driver);
|
||||
phy_register(&BCM5461S_driver);
|
||||
phy_register(&BCM_CYGNUS_driver);
|
||||
|
||||
return 0;
|
||||
}
|
||||
341
u-boot/drivers/net/phy/cortina.c
Normal file
341
u-boot/drivers/net/phy/cortina.c
Normal file
@@ -0,0 +1,341 @@
|
||||
/*
|
||||
* Cortina CS4315/CS4340 10G PHY drivers
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*
|
||||
* Copyright 2014 Freescale Semiconductor, Inc.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include <common.h>
|
||||
#include <malloc.h>
|
||||
#include <linux/ctype.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/err.h>
|
||||
#include <phy.h>
|
||||
#include <cortina.h>
|
||||
#ifdef CONFIG_SYS_CORTINA_FW_IN_NAND
|
||||
#include <nand.h>
|
||||
#elif defined(CONFIG_SYS_CORTINA_FW_IN_SPIFLASH)
|
||||
#include <spi_flash.h>
|
||||
#elif defined(CONFIG_SYS_CORTINA_FW_IN_MMC)
|
||||
#include <mmc.h>
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_PHYLIB_10G
|
||||
#error The Cortina PHY needs 10G support
|
||||
#endif
|
||||
|
||||
struct cortina_reg_config cortina_reg_cfg[] = {
|
||||
/* CS4315_enable_sr_mode */
|
||||
{VILLA_GLOBAL_MSEQCLKCTRL, 0x8004},
|
||||
{VILLA_MSEQ_OPTIONS, 0xf},
|
||||
{VILLA_MSEQ_PC, 0x0},
|
||||
{VILLA_MSEQ_BANKSELECT, 0x4},
|
||||
{VILLA_LINE_SDS_COMMON_SRX0_RX_CPA, 0x55},
|
||||
{VILLA_LINE_SDS_COMMON_SRX0_RX_LOOP_FILTER, 0x30},
|
||||
{VILLA_DSP_SDS_SERDES_SRX_DFE0_SELECT, 0x1},
|
||||
{VILLA_DSP_SDS_DSP_COEF_DFE0_SELECT, 0x2},
|
||||
{VILLA_LINE_SDS_COMMON_SRX0_RX_CPB, 0x2003},
|
||||
{VILLA_DSP_SDS_SERDES_SRX_FFE_DELAY_CTRL, 0xF047},
|
||||
{VILLA_MSEQ_ENABLE_MSB, 0x0000},
|
||||
{VILLA_MSEQ_SPARE21_LSB, 0x6},
|
||||
{VILLA_MSEQ_RESET_COUNT_LSB, 0x0},
|
||||
{VILLA_MSEQ_SPARE12_MSB, 0x0000},
|
||||
/*
|
||||
* to invert the receiver path, uncomment the next line
|
||||
* write (VILLA_MSEQ_SPARE12_MSB, 0x4000)
|
||||
*
|
||||
* SPARE2_LSB is used to configure the device while in sr mode to
|
||||
* enable power savings and to use the optical module LOS signal.
|
||||
* in power savings mode, the internal prbs checker can not be used.
|
||||
* if the optical module LOS signal is used as an input to the micro
|
||||
* code, then the micro code will wait until the optical module
|
||||
* LOS = 0 before turning on the adaptive equalizer.
|
||||
* Setting SPARE2_LSB bit 0 to 1 places the devie in power savings mode
|
||||
* while setting bit 0 to 0 disables power savings mode.
|
||||
* Setting SPARE2_LSB bit 2 to 0 configures the device to use the
|
||||
* optical module LOS signal while setting bit 2 to 1 configures the
|
||||
* device so that it will ignore the optical module LOS SPARE2_LSB = 0
|
||||
*/
|
||||
|
||||
/* enable power savings, ignore optical module LOS */
|
||||
{VILLA_MSEQ_SPARE2_LSB, 0x5},
|
||||
|
||||
{VILLA_MSEQ_SPARE7_LSB, 0x1e},
|
||||
{VILLA_MSEQ_BANKSELECT, 0x4},
|
||||
{VILLA_MSEQ_SPARE9_LSB, 0x2},
|
||||
{VILLA_MSEQ_SPARE3_LSB, 0x0F53},
|
||||
{VILLA_MSEQ_SPARE3_MSB, 0x2006},
|
||||
{VILLA_MSEQ_SPARE8_LSB, 0x3FF7},
|
||||
{VILLA_MSEQ_SPARE8_MSB, 0x0A46},
|
||||
{VILLA_MSEQ_COEF8_FFE0_LSB, 0xD500},
|
||||
{VILLA_MSEQ_COEF8_FFE1_LSB, 0x0200},
|
||||
{VILLA_MSEQ_COEF8_FFE2_LSB, 0xBA00},
|
||||
{VILLA_MSEQ_COEF8_FFE3_LSB, 0x0100},
|
||||
{VILLA_MSEQ_COEF8_FFE4_LSB, 0x0300},
|
||||
{VILLA_MSEQ_COEF8_FFE5_LSB, 0x0300},
|
||||
{VILLA_MSEQ_COEF8_DFE0_LSB, 0x0700},
|
||||
{VILLA_MSEQ_COEF8_DFE0N_LSB, 0x0E00},
|
||||
{VILLA_MSEQ_COEF8_DFE1_LSB, 0x0B00},
|
||||
{VILLA_DSP_SDS_DSP_COEF_LARGE_LEAK, 0x2},
|
||||
{VILLA_DSP_SDS_SERDES_SRX_DAC_ENABLEB_LSB, 0xD000},
|
||||
{VILLA_MSEQ_POWER_DOWN_LSB, 0xFFFF},
|
||||
{VILLA_MSEQ_POWER_DOWN_MSB, 0x0},
|
||||
{VILLA_MSEQ_CAL_RX_SLICER, 0x80},
|
||||
{VILLA_DSP_SDS_SERDES_SRX_DAC_BIAS_SELECT1_MSB, 0x3f},
|
||||
{VILLA_GLOBAL_MSEQCLKCTRL, 0x4},
|
||||
{VILLA_MSEQ_OPTIONS, 0x7},
|
||||
|
||||
/* set up min value for ffe1 */
|
||||
{VILLA_MSEQ_COEF_INIT_SEL, 0x2},
|
||||
{VILLA_DSP_SDS_DSP_PRECODEDINITFFE21, 0x41},
|
||||
|
||||
/* CS4315_sr_rx_pre_eq_set_4in */
|
||||
{VILLA_GLOBAL_MSEQCLKCTRL, 0x8004},
|
||||
{VILLA_MSEQ_OPTIONS, 0xf},
|
||||
{VILLA_MSEQ_BANKSELECT, 0x4},
|
||||
{VILLA_MSEQ_PC, 0x0},
|
||||
|
||||
/* for lengths from 3.5 to 4.5inches */
|
||||
{VILLA_MSEQ_SERDES_PARAM_LSB, 0x0306},
|
||||
{VILLA_MSEQ_SPARE25_LSB, 0x0306},
|
||||
{VILLA_MSEQ_SPARE21_LSB, 0x2},
|
||||
{VILLA_MSEQ_SPARE23_LSB, 0x2},
|
||||
{VILLA_MSEQ_CAL_RX_DFE_EQ, 0x0},
|
||||
|
||||
{VILLA_GLOBAL_MSEQCLKCTRL, 0x4},
|
||||
{VILLA_MSEQ_OPTIONS, 0x7},
|
||||
|
||||
/* CS4315_rx_drive_4inch */
|
||||
/* for length 4inches */
|
||||
{VILLA_GLOBAL_VILLA2_COMPATIBLE, 0x0000},
|
||||
{VILLA_HOST_SDS_COMMON_STX0_TX_OUTPUT_CTRLA, 0x3023},
|
||||
{VILLA_LINE_SDS_COMMON_STX0_TX_OUTPUT_CTRLB, 0xc01E},
|
||||
|
||||
/* CS4315_tx_drive_4inch */
|
||||
/* for length 4inches */
|
||||
{VILLA_GLOBAL_VILLA2_COMPATIBLE, 0x0000},
|
||||
{VILLA_LINE_SDS_COMMON_STX0_TX_OUTPUT_CTRLA, 0x3023},
|
||||
{VILLA_LINE_SDS_COMMON_STX0_TX_OUTPUT_CTRLB, 0xc01E},
|
||||
};
|
||||
|
||||
void cs4340_upload_firmware(struct phy_device *phydev)
|
||||
{
|
||||
char line_temp[0x50] = {0};
|
||||
char reg_addr[0x50] = {0};
|
||||
char reg_data[0x50] = {0};
|
||||
int i, line_cnt = 0, column_cnt = 0;
|
||||
struct cortina_reg_config fw_temp;
|
||||
char *addr = NULL;
|
||||
|
||||
#if defined(CONFIG_SYS_CORTINA_FW_IN_NOR) || \
|
||||
defined(CONFIG_SYS_CORTINA_FW_IN_REMOTE)
|
||||
|
||||
addr = (char *)CONFIG_CORTINA_FW_ADDR;
|
||||
#elif defined(CONFIG_SYS_CORTINA_FW_IN_NAND)
|
||||
int ret;
|
||||
size_t fw_length = CONFIG_CORTINA_FW_LENGTH;
|
||||
|
||||
addr = malloc(CONFIG_CORTINA_FW_LENGTH);
|
||||
ret = nand_read(nand_info[0], (loff_t)CONFIG_CORTINA_FW_ADDR,
|
||||
&fw_length, (u_char *)addr);
|
||||
if (ret == -EUCLEAN) {
|
||||
printf("NAND read of Cortina firmware at 0x%x failed %d\n",
|
||||
CONFIG_CORTINA_FW_ADDR, ret);
|
||||
}
|
||||
#elif defined(CONFIG_SYS_CORTINA_FW_IN_SPIFLASH)
|
||||
int ret;
|
||||
struct spi_flash *ucode_flash;
|
||||
|
||||
addr = malloc(CONFIG_CORTINA_FW_LENGTH);
|
||||
ucode_flash = spi_flash_probe(CONFIG_ENV_SPI_BUS, CONFIG_ENV_SPI_CS,
|
||||
CONFIG_ENV_SPI_MAX_HZ, CONFIG_ENV_SPI_MODE);
|
||||
if (!ucode_flash) {
|
||||
puts("SF: probe for Cortina ucode failed\n");
|
||||
} else {
|
||||
ret = spi_flash_read(ucode_flash, CONFIG_CORTINA_FW_ADDR,
|
||||
CONFIG_CORTINA_FW_LENGTH, addr);
|
||||
if (ret)
|
||||
puts("SF: read for Cortina ucode failed\n");
|
||||
spi_flash_free(ucode_flash);
|
||||
}
|
||||
#elif defined(CONFIG_SYS_CORTINA_FW_IN_MMC)
|
||||
int dev = CONFIG_SYS_MMC_ENV_DEV;
|
||||
u32 cnt = CONFIG_CORTINA_FW_LENGTH / 512;
|
||||
u32 blk = CONFIG_CORTINA_FW_ADDR / 512;
|
||||
struct mmc *mmc = find_mmc_device(CONFIG_SYS_MMC_ENV_DEV);
|
||||
|
||||
if (!mmc) {
|
||||
puts("Failed to find MMC device for Cortina ucode\n");
|
||||
} else {
|
||||
addr = malloc(CONFIG_CORTINA_FW_LENGTH);
|
||||
printf("MMC read: dev # %u, block # %u, count %u ...\n",
|
||||
dev, blk, cnt);
|
||||
mmc_init(mmc);
|
||||
(void)mmc->block_dev.block_read(&mmc->block_dev, blk, cnt,
|
||||
addr);
|
||||
/* flush cache after read */
|
||||
flush_cache((ulong)addr, cnt * 512);
|
||||
}
|
||||
#endif
|
||||
|
||||
while (*addr != 'Q') {
|
||||
i = 0;
|
||||
|
||||
while (*addr != 0x0a) {
|
||||
line_temp[i++] = *addr++;
|
||||
if (0x50 < i) {
|
||||
printf("Not found Cortina PHY ucode at 0x%p\n",
|
||||
(char *)CONFIG_CORTINA_FW_ADDR);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
addr++; /* skip '\n' */
|
||||
line_cnt++;
|
||||
column_cnt = i;
|
||||
line_temp[column_cnt] = '\0';
|
||||
|
||||
if (CONFIG_CORTINA_FW_LENGTH < line_cnt)
|
||||
return;
|
||||
|
||||
for (i = 0; i < column_cnt; i++) {
|
||||
if (isspace(line_temp[i++]))
|
||||
break;
|
||||
}
|
||||
|
||||
memcpy(reg_addr, line_temp, i);
|
||||
memcpy(reg_data, &line_temp[i], column_cnt - i);
|
||||
strim(reg_addr);
|
||||
strim(reg_data);
|
||||
fw_temp.reg_addr = (simple_strtoul(reg_addr, NULL, 0)) & 0xffff;
|
||||
fw_temp.reg_value = (simple_strtoul(reg_data, NULL, 0)) &
|
||||
0xffff;
|
||||
phy_write(phydev, 0x00, fw_temp.reg_addr, fw_temp.reg_value);
|
||||
}
|
||||
}
|
||||
|
||||
int cs4340_phy_init(struct phy_device *phydev)
|
||||
{
|
||||
int timeout = 100; /* 100ms */
|
||||
int reg_value;
|
||||
|
||||
/* step1: BIST test */
|
||||
phy_write(phydev, 0x00, VILLA_GLOBAL_MSEQCLKCTRL, 0x0004);
|
||||
phy_write(phydev, 0x00, VILLA_GLOBAL_LINE_SOFT_RESET, 0x0000);
|
||||
phy_write(phydev, 0x00, VILLA_GLOBAL_BIST_CONTROL, 0x0001);
|
||||
while (--timeout) {
|
||||
reg_value = phy_read(phydev, 0x00, VILLA_GLOBAL_BIST_STATUS);
|
||||
if (reg_value & mseq_edc_bist_done) {
|
||||
if (0 == (reg_value & mseq_edc_bist_fail))
|
||||
break;
|
||||
}
|
||||
udelay(1000);
|
||||
}
|
||||
|
||||
if (!timeout) {
|
||||
printf("%s BIST mseq_edc_bist_done timeout!\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* setp2: upload ucode */
|
||||
cs4340_upload_firmware(phydev);
|
||||
reg_value = phy_read(phydev, 0x00, VILLA_GLOBAL_DWNLD_CHECKSUM_STATUS);
|
||||
if (reg_value) {
|
||||
debug("%s checksum status failed.\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cs4340_config(struct phy_device *phydev)
|
||||
{
|
||||
cs4340_phy_init(phydev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cs4340_probe(struct phy_device *phydev)
|
||||
{
|
||||
phydev->flags = PHY_FLAG_BROKEN_RESET;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cs4340_startup(struct phy_device *phydev)
|
||||
{
|
||||
phydev->link = 1;
|
||||
|
||||
/* For now just lie and say it's 10G all the time */
|
||||
phydev->speed = SPEED_10000;
|
||||
phydev->duplex = DUPLEX_FULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct phy_driver cs4340_driver = {
|
||||
.name = "Cortina CS4315/CS4340",
|
||||
.uid = PHY_UID_CS4340,
|
||||
.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 = &cs4340_config,
|
||||
.probe = &cs4340_probe,
|
||||
.startup = &cs4340_startup,
|
||||
.shutdown = &gen10g_shutdown,
|
||||
};
|
||||
|
||||
int phy_cortina_init(void)
|
||||
{
|
||||
phy_register(&cs4340_driver);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int get_phy_id(struct mii_dev *bus, int addr, int devad, u32 *phy_id)
|
||||
{
|
||||
int phy_reg;
|
||||
bool is_cortina_phy = false;
|
||||
|
||||
switch (addr) {
|
||||
#ifdef CORTINA_PHY_ADDR1
|
||||
case CORTINA_PHY_ADDR1:
|
||||
#endif
|
||||
#ifdef CORTINA_PHY_ADDR2
|
||||
case CORTINA_PHY_ADDR2:
|
||||
#endif
|
||||
#ifdef CORTINA_PHY_ADDR3
|
||||
case CORTINA_PHY_ADDR3:
|
||||
#endif
|
||||
#ifdef CORTINA_PHY_ADDR4
|
||||
case CORTINA_PHY_ADDR4:
|
||||
#endif
|
||||
is_cortina_phy = true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
/* Cortina PHY has non-standard offset of PHY ID registers */
|
||||
if (is_cortina_phy)
|
||||
phy_reg = bus->read(bus, addr, 0, VILLA_GLOBAL_CHIP_ID_LSB);
|
||||
else
|
||||
phy_reg = bus->read(bus, addr, devad, MII_PHYSID1);
|
||||
|
||||
if (phy_reg < 0)
|
||||
return -EIO;
|
||||
|
||||
*phy_id = (phy_reg & 0xffff) << 16;
|
||||
if (is_cortina_phy)
|
||||
phy_reg = bus->read(bus, addr, 0, VILLA_GLOBAL_CHIP_ID_MSB);
|
||||
else
|
||||
phy_reg = bus->read(bus, addr, devad, MII_PHYSID2);
|
||||
|
||||
if (phy_reg < 0)
|
||||
return -EIO;
|
||||
|
||||
*phy_id |= (phy_reg & 0xffff);
|
||||
|
||||
return 0;
|
||||
}
|
||||
87
u-boot/drivers/net/phy/davicom.c
Normal file
87
u-boot/drivers/net/phy/davicom.c
Normal file
@@ -0,0 +1,87 @@
|
||||
/*
|
||||
* Davicom PHY drivers
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*
|
||||
* 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)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = genphy_update_link(phydev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return dm9161_parse_status(phydev);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
105
u-boot/drivers/net/phy/et1011c.c
Normal file
105
u-boot/drivers/net/phy/et1011c.c
Normal file
@@ -0,0 +1,105 @@
|
||||
/*
|
||||
* ET1011C PHY driver
|
||||
*
|
||||
* Derived from Linux kernel driver by Chaithrika U S
|
||||
* Copyright (C) 2013, Texas Instruments, Incorporated - http://www.ti.com/
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
#include <config.h>
|
||||
#include <phy.h>
|
||||
|
||||
#define ET1011C_CONFIG_REG (0x16)
|
||||
#define ET1011C_TX_FIFO_MASK (0x3 << 12)
|
||||
#define ET1011C_TX_FIFO_DEPTH_8 (0x0 << 12)
|
||||
#define ET1011C_TX_FIFO_DEPTH_16 (0x1 << 12)
|
||||
#define ET1011C_INTERFACE_MASK (0x7 << 0)
|
||||
#define ET1011C_GMII_INTERFACE (0x2 << 0)
|
||||
#define ET1011C_SYS_CLK_EN (0x1 << 4)
|
||||
#define ET1011C_TX_CLK_EN (0x1 << 5)
|
||||
|
||||
#define ET1011C_STATUS_REG (0x1A)
|
||||
#define ET1011C_DUPLEX_STATUS (0x1 << 7)
|
||||
#define ET1011C_SPEED_MASK (0x3 << 8)
|
||||
#define ET1011C_SPEED_1000 (0x2 << 8)
|
||||
#define ET1011C_SPEED_100 (0x1 << 8)
|
||||
#define ET1011C_SPEED_10 (0x0 << 8)
|
||||
|
||||
static int et1011c_config(struct phy_device *phydev)
|
||||
{
|
||||
int ctl = 0;
|
||||
ctl = phy_read(phydev, MDIO_DEVAD_NONE, MII_BMCR);
|
||||
if (ctl < 0)
|
||||
return ctl;
|
||||
ctl &= ~(BMCR_FULLDPLX | BMCR_SPEED100 | BMCR_SPEED1000 |
|
||||
BMCR_ANENABLE);
|
||||
/* First clear the PHY */
|
||||
phy_write(phydev, MDIO_DEVAD_NONE, MII_BMCR, ctl | BMCR_RESET);
|
||||
|
||||
return genphy_config_aneg(phydev);
|
||||
}
|
||||
|
||||
static int et1011c_parse_status(struct phy_device *phydev)
|
||||
{
|
||||
int mii_reg;
|
||||
int speed;
|
||||
|
||||
mii_reg = phy_read(phydev, MDIO_DEVAD_NONE, ET1011C_STATUS_REG);
|
||||
|
||||
if (mii_reg & ET1011C_DUPLEX_STATUS)
|
||||
phydev->duplex = DUPLEX_FULL;
|
||||
else
|
||||
phydev->duplex = DUPLEX_HALF;
|
||||
|
||||
speed = mii_reg & ET1011C_SPEED_MASK;
|
||||
switch (speed) {
|
||||
case ET1011C_SPEED_1000:
|
||||
phydev->speed = SPEED_1000;
|
||||
mii_reg = phy_read(phydev, MDIO_DEVAD_NONE, ET1011C_CONFIG_REG);
|
||||
mii_reg &= ~ET1011C_TX_FIFO_MASK;
|
||||
phy_write(phydev, MDIO_DEVAD_NONE, ET1011C_CONFIG_REG,
|
||||
mii_reg |
|
||||
ET1011C_GMII_INTERFACE |
|
||||
ET1011C_SYS_CLK_EN |
|
||||
#ifdef CONFIG_PHY_ET1011C_TX_CLK_FIX
|
||||
ET1011C_TX_CLK_EN |
|
||||
#endif
|
||||
ET1011C_TX_FIFO_DEPTH_16);
|
||||
break;
|
||||
case ET1011C_SPEED_100:
|
||||
phydev->speed = SPEED_100;
|
||||
break;
|
||||
case ET1011C_SPEED_10:
|
||||
phydev->speed = SPEED_10;
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int et1011c_startup(struct phy_device *phydev)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = genphy_update_link(phydev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return et1011c_parse_status(phydev);
|
||||
}
|
||||
|
||||
static struct phy_driver et1011c_driver = {
|
||||
.name = "ET1011C",
|
||||
.uid = 0x0282f014,
|
||||
.mask = 0xfffffff0,
|
||||
.features = PHY_GBIT_FEATURES,
|
||||
.config = &et1011c_config,
|
||||
.startup = &et1011c_startup,
|
||||
};
|
||||
|
||||
int phy_et1011c_init(void)
|
||||
{
|
||||
phy_register(&et1011c_driver);
|
||||
|
||||
return 0;
|
||||
}
|
||||
94
u-boot/drivers/net/phy/generic_10g.c
Normal file
94
u-boot/drivers/net/phy/generic_10g.c
Normal file
@@ -0,0 +1,94 @@
|
||||
/*
|
||||
* Generic PHY Management code
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*
|
||||
* Copyright 2011 Freescale Semiconductor, Inc.
|
||||
* author Andy Fleming
|
||||
*
|
||||
* Based loosely off of Linux's PHY Lib
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include <common.h>
|
||||
#include <miiphy.h>
|
||||
#include <phy.h>
|
||||
|
||||
int gen10g_shutdown(struct phy_device *phydev)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int gen10g_startup(struct phy_device *phydev)
|
||||
{
|
||||
int devad, reg;
|
||||
u32 mmd_mask = phydev->mmds & MDIO_DEVS_LINK;
|
||||
|
||||
phydev->link = 1;
|
||||
|
||||
/* For now just lie and say it's 10G all the time */
|
||||
phydev->speed = SPEED_10000;
|
||||
phydev->duplex = DUPLEX_FULL;
|
||||
|
||||
/*
|
||||
* Go through all the link-reporting devices, and make sure
|
||||
* they're all up and happy
|
||||
*/
|
||||
for (devad = 0; mmd_mask; devad++, mmd_mask = mmd_mask >> 1) {
|
||||
if (!(mmd_mask & 1))
|
||||
continue;
|
||||
|
||||
/* Read twice because link state is latched and a
|
||||
* read moves the current state into the register */
|
||||
phy_read(phydev, devad, MDIO_STAT1);
|
||||
reg = phy_read(phydev, devad, MDIO_STAT1);
|
||||
if (reg < 0 || !(reg & MDIO_STAT1_LSTATUS))
|
||||
phydev->link = 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int gen10g_discover_mmds(struct phy_device *phydev)
|
||||
{
|
||||
int mmd, stat2, devs1, devs2;
|
||||
|
||||
/* Assume PHY must have at least one of PMA/PMD, WIS, PCS, PHY
|
||||
* XS or DTE XS; give up if none is present. */
|
||||
for (mmd = 1; mmd <= 5; mmd++) {
|
||||
/* Is this MMD present? */
|
||||
stat2 = phy_read(phydev, mmd, MDIO_STAT2);
|
||||
if (stat2 < 0 ||
|
||||
(stat2 & MDIO_STAT2_DEVPRST) != MDIO_STAT2_DEVPRST_VAL)
|
||||
continue;
|
||||
|
||||
/* It should tell us about all the other MMDs */
|
||||
devs1 = phy_read(phydev, mmd, MDIO_DEVS1);
|
||||
devs2 = phy_read(phydev, mmd, MDIO_DEVS2);
|
||||
if (devs1 < 0 || devs2 < 0)
|
||||
continue;
|
||||
|
||||
phydev->mmds = devs1 | (devs2 << 16);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int gen10g_config(struct phy_device *phydev)
|
||||
{
|
||||
/* For now, assume 10000baseT. Fill in later */
|
||||
phydev->supported = phydev->advertising = SUPPORTED_10000baseT_Full;
|
||||
|
||||
return gen10g_discover_mmds(phydev);
|
||||
}
|
||||
|
||||
struct phy_driver gen10g_driver = {
|
||||
.uid = 0xffffffff,
|
||||
.mask = 0xffffffff,
|
||||
.name = "Generic 10G PHY",
|
||||
.features = 0,
|
||||
.config = gen10g_config,
|
||||
.startup = gen10g_startup,
|
||||
.shutdown = gen10g_shutdown,
|
||||
};
|
||||
76
u-boot/drivers/net/phy/lxt.c
Normal file
76
u-boot/drivers/net/phy/lxt.c
Normal file
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
* LXT PHY drivers
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*
|
||||
* 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)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = genphy_update_link(phydev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return lxt971_parse_status(phydev);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
596
u-boot/drivers/net/phy/marvell.c
Normal file
596
u-boot/drivers/net/phy/marvell.c
Normal file
@@ -0,0 +1,596 @@
|
||||
/*
|
||||
* Marvell PHY drivers
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*
|
||||
* 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
|
||||
|
||||
/* 88E1111 Extended PHY Specific Control Register */
|
||||
#define MIIM_88E1111_PHY_EXT_CR 0x14
|
||||
#define MIIM_88E1111_RX_DELAY 0x80
|
||||
#define MIIM_88E1111_TX_DELAY 0x2
|
||||
|
||||
/* 88E1111 Extended PHY Specific Status Register */
|
||||
#define MIIM_88E1111_PHY_EXT_SR 0x1b
|
||||
#define MIIM_88E1111_HWCFG_MODE_MASK 0xf
|
||||
#define MIIM_88E1111_HWCFG_MODE_COPPER_RGMII 0xb
|
||||
#define MIIM_88E1111_HWCFG_MODE_FIBER_RGMII 0x3
|
||||
#define MIIM_88E1111_HWCFG_MODE_SGMII_NO_CLK 0x4
|
||||
#define MIIM_88E1111_HWCFG_MODE_COPPER_RTBI 0x9
|
||||
#define MIIM_88E1111_HWCFG_FIBER_COPPER_AUTO 0x8000
|
||||
#define MIIM_88E1111_HWCFG_FIBER_COPPER_RES 0x2000
|
||||
|
||||
#define MIIM_88E1111_COPPER 0
|
||||
#define MIIM_88E1111_FIBER 1
|
||||
|
||||
/* 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
|
||||
|
||||
/* 88E1310 PHY defines */
|
||||
#define MIIM_88E1310_PHY_LED_CTRL 16
|
||||
#define MIIM_88E1310_PHY_IRQ_EN 18
|
||||
#define MIIM_88E1310_PHY_RGMII_CTRL 21
|
||||
#define MIIM_88E1310_PHY_PAGE 22
|
||||
|
||||
/* 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 int 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;
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = genphy_update_link(phydev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return m88e1xxx_parse_status(phydev);
|
||||
}
|
||||
|
||||
/* 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, MIIM_88E1111_PHY_EXT_CR);
|
||||
if ((phydev->interface == PHY_INTERFACE_MODE_RGMII) ||
|
||||
(phydev->interface == PHY_INTERFACE_MODE_RGMII_ID)) {
|
||||
reg |= (MIIM_88E1111_RX_DELAY | MIIM_88E1111_TX_DELAY);
|
||||
} else if (phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID) {
|
||||
reg &= ~MIIM_88E1111_TX_DELAY;
|
||||
reg |= MIIM_88E1111_RX_DELAY;
|
||||
} else if (phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID) {
|
||||
reg &= ~MIIM_88E1111_RX_DELAY;
|
||||
reg |= MIIM_88E1111_TX_DELAY;
|
||||
}
|
||||
|
||||
phy_write(phydev,
|
||||
MDIO_DEVAD_NONE, MIIM_88E1111_PHY_EXT_CR, reg);
|
||||
|
||||
reg = phy_read(phydev,
|
||||
MDIO_DEVAD_NONE, MIIM_88E1111_PHY_EXT_SR);
|
||||
|
||||
reg &= ~(MIIM_88E1111_HWCFG_MODE_MASK);
|
||||
|
||||
if (reg & MIIM_88E1111_HWCFG_FIBER_COPPER_RES)
|
||||
reg |= MIIM_88E1111_HWCFG_MODE_FIBER_RGMII;
|
||||
else
|
||||
reg |= MIIM_88E1111_HWCFG_MODE_COPPER_RGMII;
|
||||
|
||||
phy_write(phydev,
|
||||
MDIO_DEVAD_NONE, MIIM_88E1111_PHY_EXT_SR, reg);
|
||||
}
|
||||
|
||||
if (phydev->interface == PHY_INTERFACE_MODE_SGMII) {
|
||||
reg = phy_read(phydev,
|
||||
MDIO_DEVAD_NONE, MIIM_88E1111_PHY_EXT_SR);
|
||||
|
||||
reg &= ~(MIIM_88E1111_HWCFG_MODE_MASK);
|
||||
reg |= MIIM_88E1111_HWCFG_MODE_SGMII_NO_CLK;
|
||||
reg |= MIIM_88E1111_HWCFG_FIBER_COPPER_AUTO;
|
||||
|
||||
phy_write(phydev, MDIO_DEVAD_NONE,
|
||||
MIIM_88E1111_PHY_EXT_SR, reg);
|
||||
}
|
||||
|
||||
if (phydev->interface == PHY_INTERFACE_MODE_RTBI) {
|
||||
reg = phy_read(phydev,
|
||||
MDIO_DEVAD_NONE, MIIM_88E1111_PHY_EXT_CR);
|
||||
reg |= (MIIM_88E1111_RX_DELAY | MIIM_88E1111_TX_DELAY);
|
||||
phy_write(phydev,
|
||||
MDIO_DEVAD_NONE, MIIM_88E1111_PHY_EXT_CR, reg);
|
||||
|
||||
reg = phy_read(phydev, MDIO_DEVAD_NONE,
|
||||
MIIM_88E1111_PHY_EXT_SR);
|
||||
reg &= ~(MIIM_88E1111_HWCFG_MODE_MASK |
|
||||
MIIM_88E1111_HWCFG_FIBER_COPPER_RES);
|
||||
reg |= 0x7 | MIIM_88E1111_HWCFG_FIBER_COPPER_AUTO;
|
||||
phy_write(phydev, MDIO_DEVAD_NONE,
|
||||
MIIM_88E1111_PHY_EXT_SR, reg);
|
||||
|
||||
/* soft reset */
|
||||
phy_reset(phydev);
|
||||
|
||||
reg = phy_read(phydev, MDIO_DEVAD_NONE,
|
||||
MIIM_88E1111_PHY_EXT_SR);
|
||||
reg &= ~(MIIM_88E1111_HWCFG_MODE_MASK |
|
||||
MIIM_88E1111_HWCFG_FIBER_COPPER_RES);
|
||||
reg |= MIIM_88E1111_HWCFG_MODE_COPPER_RTBI |
|
||||
MIIM_88E1111_HWCFG_FIBER_COPPER_AUTO;
|
||||
phy_write(phydev, MDIO_DEVAD_NONE,
|
||||
MIIM_88E1111_PHY_EXT_SR, reg);
|
||||
}
|
||||
|
||||
/* soft reset */
|
||||
phy_reset(phydev);
|
||||
|
||||
genphy_config_aneg(phydev);
|
||||
genphy_restart_aneg(phydev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* m88e1518_phy_writebits - write bits to a register
|
||||
*/
|
||||
void m88e1518_phy_writebits(struct phy_device *phydev,
|
||||
u8 reg_num, u16 offset, u16 len, u16 data)
|
||||
{
|
||||
u16 reg, mask;
|
||||
|
||||
if ((len + offset) >= 16)
|
||||
mask = 0 - (1 << offset);
|
||||
else
|
||||
mask = (1 << (len + offset)) - (1 << offset);
|
||||
|
||||
reg = phy_read(phydev, MDIO_DEVAD_NONE, reg_num);
|
||||
|
||||
reg &= ~mask;
|
||||
reg |= data << offset;
|
||||
|
||||
phy_write(phydev, MDIO_DEVAD_NONE, reg_num, reg);
|
||||
}
|
||||
|
||||
static int m88e1518_config(struct phy_device *phydev)
|
||||
{
|
||||
/*
|
||||
* As per Marvell Release Notes - Alaska 88E1510/88E1518/88E1512
|
||||
* /88E1514 Rev A0, Errata Section 3.1
|
||||
*/
|
||||
|
||||
/* EEE initialization */
|
||||
phy_write(phydev, MDIO_DEVAD_NONE, 22, 0x00ff);
|
||||
phy_write(phydev, MDIO_DEVAD_NONE, 17, 0x214B);
|
||||
phy_write(phydev, MDIO_DEVAD_NONE, 16, 0x2144);
|
||||
phy_write(phydev, MDIO_DEVAD_NONE, 17, 0x0C28);
|
||||
phy_write(phydev, MDIO_DEVAD_NONE, 16, 0x2146);
|
||||
phy_write(phydev, MDIO_DEVAD_NONE, 17, 0xB233);
|
||||
phy_write(phydev, MDIO_DEVAD_NONE, 16, 0x214D);
|
||||
phy_write(phydev, MDIO_DEVAD_NONE, 17, 0xCC0C);
|
||||
phy_write(phydev, MDIO_DEVAD_NONE, 16, 0x2159);
|
||||
phy_write(phydev, MDIO_DEVAD_NONE, 22, 0x0000);
|
||||
|
||||
/* SGMII-to-Copper mode initialization */
|
||||
if (phydev->interface == PHY_INTERFACE_MODE_SGMII) {
|
||||
/* Select page 18 */
|
||||
phy_write(phydev, MDIO_DEVAD_NONE, 22, 18);
|
||||
|
||||
/* In reg 20, write MODE[2:0] = 0x1 (SGMII to Copper) */
|
||||
m88e1518_phy_writebits(phydev, 20, 0, 3, 1);
|
||||
|
||||
/* PHY reset is necessary after changing MODE[2:0] */
|
||||
m88e1518_phy_writebits(phydev, 20, 15, 1, 1);
|
||||
|
||||
/* Reset page selection */
|
||||
phy_write(phydev, MDIO_DEVAD_NONE, 22, 0);
|
||||
|
||||
udelay(100);
|
||||
}
|
||||
|
||||
return m88e1111s_config(phydev);
|
||||
}
|
||||
|
||||
/* Marvell 88E1510 */
|
||||
static int m88e1510_config(struct phy_device *phydev)
|
||||
{
|
||||
/* Select page 3 */
|
||||
phy_write(phydev, MDIO_DEVAD_NONE, 22, 3);
|
||||
|
||||
/* Enable INTn output on LED[2] */
|
||||
m88e1518_phy_writebits(phydev, 18, 7, 1, 1);
|
||||
|
||||
/* Configure LEDs */
|
||||
m88e1518_phy_writebits(phydev, 16, 0, 4, 3); /* LED[0]:0011 (ACT) */
|
||||
m88e1518_phy_writebits(phydev, 16, 4, 4, 6); /* LED[1]:0110 (LINK) */
|
||||
|
||||
/* Reset page selection */
|
||||
phy_write(phydev, MDIO_DEVAD_NONE, 22, 0);
|
||||
|
||||
return m88e1518_config(phydev);
|
||||
}
|
||||
|
||||
/* 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);
|
||||
|
||||
return genphy_config_aneg(phydev);
|
||||
}
|
||||
|
||||
static int m88e1118_startup(struct phy_device *phydev)
|
||||
{
|
||||
int ret;
|
||||
|
||||
/* Change Page Number */
|
||||
phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1118_PHY_PAGE, 0x0000);
|
||||
|
||||
ret = genphy_update_link(phydev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return m88e1xxx_parse_status(phydev);
|
||||
}
|
||||
|
||||
/* 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)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = genphy_update_link(phydev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1145_PHY_LED_CONTROL,
|
||||
MIIM_88E1145_PHY_LED_DIRECT);
|
||||
return m88e1xxx_parse_status(phydev);
|
||||
}
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
/* Marvell 88E1310 */
|
||||
static int m88e1310_config(struct phy_device *phydev)
|
||||
{
|
||||
u16 reg;
|
||||
|
||||
/* LED link and activity */
|
||||
phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1310_PHY_PAGE, 0x0003);
|
||||
reg = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_88E1310_PHY_LED_CTRL);
|
||||
reg = (reg & ~0xf) | 0x1;
|
||||
phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1310_PHY_LED_CTRL, reg);
|
||||
|
||||
/* Set LED2/INT to INT mode, low active */
|
||||
phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1310_PHY_PAGE, 0x0003);
|
||||
reg = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_88E1310_PHY_IRQ_EN);
|
||||
reg = (reg & 0x77ff) | 0x0880;
|
||||
phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1310_PHY_IRQ_EN, reg);
|
||||
|
||||
/* Set RGMII delay */
|
||||
phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1310_PHY_PAGE, 0x0002);
|
||||
reg = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_88E1310_PHY_RGMII_CTRL);
|
||||
reg |= 0x0030;
|
||||
phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1310_PHY_RGMII_CTRL, reg);
|
||||
|
||||
/* Ensure to return to page 0 */
|
||||
phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1310_PHY_PAGE, 0x0000);
|
||||
|
||||
return genphy_config_aneg(phydev);
|
||||
}
|
||||
|
||||
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 M88E1118R_driver = {
|
||||
.name = "Marvell 88E1118R",
|
||||
.uid = 0x1410e40,
|
||||
.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,
|
||||
};
|
||||
|
||||
static struct phy_driver M88E1510_driver = {
|
||||
.name = "Marvell 88E1510",
|
||||
.uid = 0x1410dd0,
|
||||
.mask = 0xffffff0,
|
||||
.features = PHY_GBIT_FEATURES,
|
||||
.config = &m88e1510_config,
|
||||
.startup = &m88e1011s_startup,
|
||||
.shutdown = &genphy_shutdown,
|
||||
};
|
||||
|
||||
static struct phy_driver M88E1518_driver = {
|
||||
.name = "Marvell 88E1518",
|
||||
.uid = 0x1410dd1,
|
||||
.mask = 0xffffff0,
|
||||
.features = PHY_GBIT_FEATURES,
|
||||
.config = &m88e1518_config,
|
||||
.startup = &m88e1011s_startup,
|
||||
.shutdown = &genphy_shutdown,
|
||||
};
|
||||
|
||||
static struct phy_driver M88E1310_driver = {
|
||||
.name = "Marvell 88E1310",
|
||||
.uid = 0x01410e90,
|
||||
.mask = 0xffffff0,
|
||||
.features = PHY_GBIT_FEATURES,
|
||||
.config = &m88e1310_config,
|
||||
.startup = &m88e1011s_startup,
|
||||
.shutdown = &genphy_shutdown,
|
||||
};
|
||||
|
||||
int phy_marvell_init(void)
|
||||
{
|
||||
phy_register(&M88E1310_driver);
|
||||
phy_register(&M88E1149S_driver);
|
||||
phy_register(&M88E1145_driver);
|
||||
phy_register(&M88E1121R_driver);
|
||||
phy_register(&M88E1118_driver);
|
||||
phy_register(&M88E1118R_driver);
|
||||
phy_register(&M88E1111S_driver);
|
||||
phy_register(&M88E1011S_driver);
|
||||
phy_register(&M88E1510_driver);
|
||||
phy_register(&M88E1518_driver);
|
||||
|
||||
return 0;
|
||||
}
|
||||
530
u-boot/drivers/net/phy/micrel.c
Normal file
530
u-boot/drivers/net/phy/micrel.c
Normal file
@@ -0,0 +1,530 @@
|
||||
/*
|
||||
* Micrel PHY drivers
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*
|
||||
* Copyright 2010-2011 Freescale Semiconductor, Inc.
|
||||
* author Andy Fleming
|
||||
* (C) 2012 NetModule AG, David Andrey, added KSZ9031
|
||||
*/
|
||||
#include <config.h>
|
||||
#include <common.h>
|
||||
#include <dm.h>
|
||||
#include <errno.h>
|
||||
#include <fdtdec.h>
|
||||
#include <micrel.h>
|
||||
#include <phy.h>
|
||||
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
|
||||
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,
|
||||
};
|
||||
|
||||
#define MII_KSZPHY_OMSO 0x16
|
||||
#define KSZPHY_OMSO_B_CAST_OFF (1 << 9)
|
||||
|
||||
static int ksz_genconfig_bcastoff(struct phy_device *phydev)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = phy_read(phydev, MDIO_DEVAD_NONE, MII_KSZPHY_OMSO);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = phy_write(phydev, MDIO_DEVAD_NONE, MII_KSZPHY_OMSO,
|
||||
ret | KSZPHY_OMSO_B_CAST_OFF);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return genphy_config(phydev);
|
||||
}
|
||||
|
||||
static struct phy_driver KSZ8031_driver = {
|
||||
.name = "Micrel KSZ8021/KSZ8031",
|
||||
.uid = 0x221550,
|
||||
.mask = 0xfffff0,
|
||||
.features = PHY_BASIC_FEATURES,
|
||||
.config = &ksz_genconfig_bcastoff,
|
||||
.startup = &genphy_startup,
|
||||
.shutdown = &genphy_shutdown,
|
||||
};
|
||||
|
||||
/**
|
||||
* KSZ8051
|
||||
*/
|
||||
#define MII_KSZ8051_PHY_OMSO 0x16
|
||||
#define MII_KSZ8051_PHY_OMSO_NAND_TREE_ON (1 << 5)
|
||||
|
||||
static int ksz8051_config(struct phy_device *phydev)
|
||||
{
|
||||
unsigned val;
|
||||
|
||||
/* Disable NAND-tree */
|
||||
val = phy_read(phydev, MDIO_DEVAD_NONE, MII_KSZ8051_PHY_OMSO);
|
||||
val &= ~MII_KSZ8051_PHY_OMSO_NAND_TREE_ON;
|
||||
phy_write(phydev, MDIO_DEVAD_NONE, MII_KSZ8051_PHY_OMSO, val);
|
||||
|
||||
return genphy_config(phydev);
|
||||
}
|
||||
|
||||
static struct phy_driver KSZ8051_driver = {
|
||||
.name = "Micrel KSZ8051",
|
||||
.uid = 0x221550,
|
||||
.mask = 0xfffff0,
|
||||
.features = PHY_BASIC_FEATURES,
|
||||
.config = &ksz8051_config,
|
||||
.startup = &genphy_startup,
|
||||
.shutdown = &genphy_shutdown,
|
||||
};
|
||||
|
||||
static struct phy_driver KSZ8081_driver = {
|
||||
.name = "Micrel KSZ8081",
|
||||
.uid = 0x221560,
|
||||
.mask = 0xfffff0,
|
||||
.features = PHY_BASIC_FEATURES,
|
||||
.config = &ksz_genconfig_bcastoff,
|
||||
.startup = &genphy_startup,
|
||||
.shutdown = &genphy_shutdown,
|
||||
};
|
||||
|
||||
/**
|
||||
* KSZ8895
|
||||
*/
|
||||
|
||||
static unsigned short smireg_to_phy(unsigned short reg)
|
||||
{
|
||||
return ((reg & 0xc0) >> 3) + 0x06 + ((reg & 0x20) >> 5);
|
||||
}
|
||||
|
||||
static unsigned short smireg_to_reg(unsigned short reg)
|
||||
{
|
||||
return reg & 0x1F;
|
||||
}
|
||||
|
||||
static void ksz8895_write_smireg(struct phy_device *phydev, int smireg, int val)
|
||||
{
|
||||
phydev->bus->write(phydev->bus, smireg_to_phy(smireg), MDIO_DEVAD_NONE,
|
||||
smireg_to_reg(smireg), val);
|
||||
}
|
||||
|
||||
#if 0
|
||||
static int ksz8895_read_smireg(struct phy_device *phydev, int smireg)
|
||||
{
|
||||
return phydev->bus->read(phydev->bus, smireg_to_phy(smireg),
|
||||
MDIO_DEVAD_NONE, smireg_to_reg(smireg));
|
||||
}
|
||||
#endif
|
||||
|
||||
int ksz8895_config(struct phy_device *phydev)
|
||||
{
|
||||
/* we are connected directly to the switch without
|
||||
* dedicated PHY. SCONF1 == 001 */
|
||||
phydev->link = 1;
|
||||
phydev->duplex = DUPLEX_FULL;
|
||||
phydev->speed = SPEED_100;
|
||||
|
||||
/* Force the switch to start */
|
||||
ksz8895_write_smireg(phydev, 1, 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ksz8895_startup(struct phy_device *phydev)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct phy_driver ksz8895_driver = {
|
||||
.name = "Micrel KSZ8895/KSZ8864",
|
||||
.uid = 0x221450,
|
||||
.mask = 0xffffe1,
|
||||
.features = PHY_BASIC_FEATURES,
|
||||
.config = &ksz8895_config,
|
||||
.startup = &ksz8895_startup,
|
||||
.shutdown = &genphy_shutdown,
|
||||
};
|
||||
|
||||
#ifndef CONFIG_PHY_MICREL_KSZ9021
|
||||
/*
|
||||
* I can't believe Micrel used the exact same part number
|
||||
* for the KSZ9021. Shame Micrel, Shame!
|
||||
*/
|
||||
static struct phy_driver KS8721_driver = {
|
||||
.name = "Micrel KS8721BL",
|
||||
.uid = 0x221610,
|
||||
.mask = 0xfffff0,
|
||||
.features = PHY_BASIC_FEATURES,
|
||||
.config = &genphy_config,
|
||||
.startup = &genphy_startup,
|
||||
.shutdown = &genphy_shutdown,
|
||||
};
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* KSZ9021 - KSZ9031 common
|
||||
*/
|
||||
|
||||
#define MII_KSZ90xx_PHY_CTL 0x1f
|
||||
#define MIIM_KSZ90xx_PHYCTL_1000 (1 << 6)
|
||||
#define MIIM_KSZ90xx_PHYCTL_100 (1 << 5)
|
||||
#define MIIM_KSZ90xx_PHYCTL_10 (1 << 4)
|
||||
#define MIIM_KSZ90xx_PHYCTL_DUPLEX (1 << 3)
|
||||
|
||||
static int ksz90xx_startup(struct phy_device *phydev)
|
||||
{
|
||||
unsigned phy_ctl;
|
||||
int ret;
|
||||
|
||||
ret = genphy_update_link(phydev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
phy_ctl = phy_read(phydev, MDIO_DEVAD_NONE, MII_KSZ90xx_PHY_CTL);
|
||||
|
||||
if (phy_ctl & MIIM_KSZ90xx_PHYCTL_DUPLEX)
|
||||
phydev->duplex = DUPLEX_FULL;
|
||||
else
|
||||
phydev->duplex = DUPLEX_HALF;
|
||||
|
||||
if (phy_ctl & MIIM_KSZ90xx_PHYCTL_1000)
|
||||
phydev->speed = SPEED_1000;
|
||||
else if (phy_ctl & MIIM_KSZ90xx_PHYCTL_100)
|
||||
phydev->speed = SPEED_100;
|
||||
else if (phy_ctl & MIIM_KSZ90xx_PHYCTL_10)
|
||||
phydev->speed = SPEED_10;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Common OF config bits for KSZ9021 and KSZ9031 */
|
||||
#if defined(CONFIG_PHY_MICREL_KSZ9021) || defined(CONFIG_PHY_MICREL_KSZ9031)
|
||||
#ifdef CONFIG_DM_ETH
|
||||
struct ksz90x1_reg_field {
|
||||
const char *name;
|
||||
const u8 size; /* Size of the bitfield, in bits */
|
||||
const u8 off; /* Offset from bit 0 */
|
||||
const u8 dflt; /* Default value */
|
||||
};
|
||||
|
||||
struct ksz90x1_ofcfg {
|
||||
const u16 reg;
|
||||
const u16 devad;
|
||||
const struct ksz90x1_reg_field *grp;
|
||||
const u16 grpsz;
|
||||
};
|
||||
|
||||
static const struct ksz90x1_reg_field ksz90x1_rxd_grp[] = {
|
||||
{ "rxd0-skew-ps", 4, 0, 0x7 }, { "rxd1-skew-ps", 4, 4, 0x7 },
|
||||
{ "rxd2-skew-ps", 4, 8, 0x7 }, { "rxd3-skew-ps", 4, 12, 0x7 }
|
||||
};
|
||||
|
||||
static const struct ksz90x1_reg_field ksz90x1_txd_grp[] = {
|
||||
{ "txd0-skew-ps", 4, 0, 0x7 }, { "txd1-skew-ps", 4, 4, 0x7 },
|
||||
{ "txd2-skew-ps", 4, 8, 0x7 }, { "txd3-skew-ps", 4, 12, 0x7 },
|
||||
};
|
||||
|
||||
static int ksz90x1_of_config_group(struct phy_device *phydev,
|
||||
struct ksz90x1_ofcfg *ofcfg)
|
||||
{
|
||||
struct udevice *dev = phydev->dev;
|
||||
struct phy_driver *drv = phydev->drv;
|
||||
const int ps_to_regval = 60;
|
||||
int val[4];
|
||||
int i, changed = 0, offset, max;
|
||||
u16 regval = 0;
|
||||
|
||||
if (!drv || !drv->writeext)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
for (i = 0; i < ofcfg->grpsz; i++) {
|
||||
val[i] = fdtdec_get_uint(gd->fdt_blob, dev->of_offset,
|
||||
ofcfg->grp[i].name, -1);
|
||||
offset = ofcfg->grp[i].off;
|
||||
if (val[i] == -1) {
|
||||
/* Default register value for KSZ9021 */
|
||||
regval |= ofcfg->grp[i].dflt << offset;
|
||||
} else {
|
||||
changed = 1; /* Value was changed in OF */
|
||||
/* Calculate the register value and fix corner cases */
|
||||
if (val[i] > ps_to_regval * 0xf) {
|
||||
max = (1 << ofcfg->grp[i].size) - 1;
|
||||
regval |= max << offset;
|
||||
} else {
|
||||
regval |= (val[i] / ps_to_regval) << offset;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!changed)
|
||||
return 0;
|
||||
|
||||
return drv->writeext(phydev, 0, ofcfg->devad, ofcfg->reg, regval);
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_PHY_MICREL_KSZ9021
|
||||
/*
|
||||
* KSZ9021
|
||||
*/
|
||||
|
||||
/* PHY Registers */
|
||||
#define MII_KSZ9021_EXTENDED_CTRL 0x0b
|
||||
#define MII_KSZ9021_EXTENDED_DATAW 0x0c
|
||||
#define MII_KSZ9021_EXTENDED_DATAR 0x0d
|
||||
|
||||
#define CTRL1000_PREFER_MASTER (1 << 10)
|
||||
#define CTRL1000_CONFIG_MASTER (1 << 11)
|
||||
#define CTRL1000_MANUAL_CONFIG (1 << 12)
|
||||
|
||||
#if defined(CONFIG_DM_ETH) && (defined(CONFIG_PHY_MICREL_KSZ9021) || \
|
||||
defined(CONFIG_PHY_MICREL_KSZ9031))
|
||||
static const struct ksz90x1_reg_field ksz9021_clk_grp[] = {
|
||||
{ "txen-skew-ps", 4, 0, 0x7 }, { "txc-skew-ps", 4, 4, 0x7 },
|
||||
{ "rxdv-skew-ps", 4, 8, 0x7 }, { "rxc-skew-ps", 4, 12, 0x7 },
|
||||
};
|
||||
|
||||
static int ksz9021_of_config(struct phy_device *phydev)
|
||||
{
|
||||
struct ksz90x1_ofcfg ofcfg[] = {
|
||||
{ MII_KSZ9021_EXT_RGMII_RX_DATA_SKEW, 0, ksz90x1_rxd_grp, 4 },
|
||||
{ MII_KSZ9021_EXT_RGMII_TX_DATA_SKEW, 0, ksz90x1_txd_grp, 4 },
|
||||
{ MII_KSZ9021_EXT_RGMII_CLOCK_SKEW, 0, ksz9021_clk_grp, 4 },
|
||||
};
|
||||
int i, ret = 0;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(ofcfg); i++)
|
||||
ret = ksz90x1_of_config_group(phydev, &(ofcfg[i]));
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
static int ksz9021_of_config(struct phy_device *phydev)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
int ksz9021_phy_extended_write(struct phy_device *phydev, int regnum, u16 val)
|
||||
{
|
||||
/* extended registers */
|
||||
phy_write(phydev, MDIO_DEVAD_NONE,
|
||||
MII_KSZ9021_EXTENDED_CTRL, regnum | 0x8000);
|
||||
return phy_write(phydev, MDIO_DEVAD_NONE,
|
||||
MII_KSZ9021_EXTENDED_DATAW, val);
|
||||
}
|
||||
|
||||
int ksz9021_phy_extended_read(struct phy_device *phydev, int regnum)
|
||||
{
|
||||
/* extended registers */
|
||||
phy_write(phydev, MDIO_DEVAD_NONE, MII_KSZ9021_EXTENDED_CTRL, regnum);
|
||||
return phy_read(phydev, MDIO_DEVAD_NONE, MII_KSZ9021_EXTENDED_DATAR);
|
||||
}
|
||||
|
||||
|
||||
static int ksz9021_phy_extread(struct phy_device *phydev, int addr, int devaddr,
|
||||
int regnum)
|
||||
{
|
||||
return ksz9021_phy_extended_read(phydev, regnum);
|
||||
}
|
||||
|
||||
static int ksz9021_phy_extwrite(struct phy_device *phydev, int addr,
|
||||
int devaddr, int regnum, u16 val)
|
||||
{
|
||||
return ksz9021_phy_extended_write(phydev, regnum, val);
|
||||
}
|
||||
|
||||
/* Micrel ksz9021 */
|
||||
static int ksz9021_config(struct phy_device *phydev)
|
||||
{
|
||||
unsigned ctrl1000 = 0;
|
||||
const unsigned master = CTRL1000_PREFER_MASTER |
|
||||
CTRL1000_CONFIG_MASTER | CTRL1000_MANUAL_CONFIG;
|
||||
unsigned features = phydev->drv->features;
|
||||
int ret;
|
||||
|
||||
ret = ksz9021_of_config(phydev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (getenv("disable_giga"))
|
||||
features &= ~(SUPPORTED_1000baseT_Half |
|
||||
SUPPORTED_1000baseT_Full);
|
||||
/* force master mode for 1000BaseT due to chip errata */
|
||||
if (features & SUPPORTED_1000baseT_Half)
|
||||
ctrl1000 |= ADVERTISE_1000HALF | master;
|
||||
if (features & SUPPORTED_1000baseT_Full)
|
||||
ctrl1000 |= ADVERTISE_1000FULL | master;
|
||||
phydev->advertising = phydev->supported = features;
|
||||
phy_write(phydev, MDIO_DEVAD_NONE, MII_CTRL1000, ctrl1000);
|
||||
genphy_config_aneg(phydev);
|
||||
genphy_restart_aneg(phydev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct phy_driver ksz9021_driver = {
|
||||
.name = "Micrel ksz9021",
|
||||
.uid = 0x221610,
|
||||
.mask = 0xfffff0,
|
||||
.features = PHY_GBIT_FEATURES,
|
||||
.config = &ksz9021_config,
|
||||
.startup = &ksz90xx_startup,
|
||||
.shutdown = &genphy_shutdown,
|
||||
.writeext = &ksz9021_phy_extwrite,
|
||||
.readext = &ksz9021_phy_extread,
|
||||
};
|
||||
#endif
|
||||
|
||||
/**
|
||||
* KSZ9031
|
||||
*/
|
||||
/* PHY Registers */
|
||||
#define MII_KSZ9031_MMD_ACCES_CTRL 0x0d
|
||||
#define MII_KSZ9031_MMD_REG_DATA 0x0e
|
||||
|
||||
#if defined(CONFIG_DM_ETH) && (defined(CONFIG_PHY_MICREL_KSZ9021) || \
|
||||
defined(CONFIG_PHY_MICREL_KSZ9031))
|
||||
static const struct ksz90x1_reg_field ksz9031_ctl_grp[] =
|
||||
{ { "txen-skew-ps", 4, 0, 0x7 }, { "rxdv-skew-ps", 4, 4, 0x7 } };
|
||||
static const struct ksz90x1_reg_field ksz9031_clk_grp[] =
|
||||
{ { "rxc-skew-ps", 5, 0, 0xf }, { "txc-skew-ps", 5, 5, 0xf } };
|
||||
|
||||
static int ksz9031_of_config(struct phy_device *phydev)
|
||||
{
|
||||
struct ksz90x1_ofcfg ofcfg[] = {
|
||||
{ MII_KSZ9031_EXT_RGMII_CTRL_SIG_SKEW, 2, ksz9031_ctl_grp, 2 },
|
||||
{ MII_KSZ9031_EXT_RGMII_RX_DATA_SKEW, 2, ksz90x1_rxd_grp, 4 },
|
||||
{ MII_KSZ9031_EXT_RGMII_TX_DATA_SKEW, 2, ksz90x1_txd_grp, 4 },
|
||||
{ MII_KSZ9031_EXT_RGMII_CLOCK_SKEW, 2, ksz9031_clk_grp, 2 },
|
||||
};
|
||||
int i, ret = 0;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(ofcfg); i++)
|
||||
ret = ksz90x1_of_config_group(phydev, &(ofcfg[i]));
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
static int ksz9031_of_config(struct phy_device *phydev)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Accessors to extended registers*/
|
||||
int ksz9031_phy_extended_write(struct phy_device *phydev,
|
||||
int devaddr, int regnum, u16 mode, u16 val)
|
||||
{
|
||||
/*select register addr for mmd*/
|
||||
phy_write(phydev, MDIO_DEVAD_NONE,
|
||||
MII_KSZ9031_MMD_ACCES_CTRL, devaddr);
|
||||
/*select register for mmd*/
|
||||
phy_write(phydev, MDIO_DEVAD_NONE,
|
||||
MII_KSZ9031_MMD_REG_DATA, regnum);
|
||||
/*setup mode*/
|
||||
phy_write(phydev, MDIO_DEVAD_NONE,
|
||||
MII_KSZ9031_MMD_ACCES_CTRL, (mode | devaddr));
|
||||
/*write the value*/
|
||||
return phy_write(phydev, MDIO_DEVAD_NONE,
|
||||
MII_KSZ9031_MMD_REG_DATA, val);
|
||||
}
|
||||
|
||||
int ksz9031_phy_extended_read(struct phy_device *phydev, int devaddr,
|
||||
int regnum, u16 mode)
|
||||
{
|
||||
phy_write(phydev, MDIO_DEVAD_NONE,
|
||||
MII_KSZ9031_MMD_ACCES_CTRL, devaddr);
|
||||
phy_write(phydev, MDIO_DEVAD_NONE,
|
||||
MII_KSZ9031_MMD_REG_DATA, regnum);
|
||||
phy_write(phydev, MDIO_DEVAD_NONE,
|
||||
MII_KSZ9031_MMD_ACCES_CTRL, (devaddr | mode));
|
||||
return phy_read(phydev, MDIO_DEVAD_NONE, MII_KSZ9031_MMD_REG_DATA);
|
||||
}
|
||||
|
||||
static int ksz9031_phy_extread(struct phy_device *phydev, int addr, int devaddr,
|
||||
int regnum)
|
||||
{
|
||||
return ksz9031_phy_extended_read(phydev, devaddr, regnum,
|
||||
MII_KSZ9031_MOD_DATA_NO_POST_INC);
|
||||
};
|
||||
|
||||
static int ksz9031_phy_extwrite(struct phy_device *phydev, int addr,
|
||||
int devaddr, int regnum, u16 val)
|
||||
{
|
||||
return ksz9031_phy_extended_write(phydev, devaddr, regnum,
|
||||
MII_KSZ9031_MOD_DATA_POST_INC_RW, val);
|
||||
};
|
||||
|
||||
static int ksz9031_config(struct phy_device *phydev)
|
||||
{
|
||||
int ret;
|
||||
ret = ksz9031_of_config(phydev);
|
||||
if (ret)
|
||||
return ret;
|
||||
return genphy_config(phydev);
|
||||
}
|
||||
|
||||
static struct phy_driver ksz9031_driver = {
|
||||
.name = "Micrel ksz9031",
|
||||
.uid = 0x221620,
|
||||
.mask = 0xfffff0,
|
||||
.features = PHY_GBIT_FEATURES,
|
||||
.config = &ksz9031_config,
|
||||
.startup = &ksz90xx_startup,
|
||||
.shutdown = &genphy_shutdown,
|
||||
.writeext = &ksz9031_phy_extwrite,
|
||||
.readext = &ksz9031_phy_extread,
|
||||
};
|
||||
|
||||
int ksz886x_config(struct phy_device *phydev)
|
||||
{
|
||||
/* we are connected directly to the switch without
|
||||
* dedicated PHY. */
|
||||
phydev->link = 1;
|
||||
phydev->duplex = DUPLEX_FULL;
|
||||
phydev->speed = SPEED_100;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ksz886x_startup(struct phy_device *phydev)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct phy_driver ksz886x_driver = {
|
||||
.name = "Micrel KSZ886x Switch",
|
||||
.uid = 0x00221430,
|
||||
.mask = 0xfffff0,
|
||||
.features = PHY_BASIC_FEATURES,
|
||||
.config = &ksz886x_config,
|
||||
.startup = &ksz886x_startup,
|
||||
.shutdown = &genphy_shutdown,
|
||||
};
|
||||
|
||||
int phy_micrel_init(void)
|
||||
{
|
||||
phy_register(&KSZ804_driver);
|
||||
phy_register(&KSZ8031_driver);
|
||||
phy_register(&KSZ8051_driver);
|
||||
phy_register(&KSZ8081_driver);
|
||||
#ifdef CONFIG_PHY_MICREL_KSZ9021
|
||||
phy_register(&ksz9021_driver);
|
||||
#else
|
||||
phy_register(&KS8721_driver);
|
||||
#endif
|
||||
phy_register(&ksz9031_driver);
|
||||
phy_register(&ksz8895_driver);
|
||||
phy_register(&ksz886x_driver);
|
||||
return 0;
|
||||
}
|
||||
364
u-boot/drivers/net/phy/miiphybb.c
Normal file
364
u-boot/drivers/net/phy/miiphybb.c
Normal file
@@ -0,0 +1,364 @@
|
||||
/*
|
||||
* (C) Copyright 2009 Industrie Dial Face S.p.A.
|
||||
* Luigi 'Comio' Mantellini <luigi.mantellini@idf-hit.com>
|
||||
*
|
||||
* (C) Copyright 2001
|
||||
* Gerald Van Baren, Custom IDEAS, vanbaren@cideas.com.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
/*
|
||||
* This provides a bit-banged interface to the ethernet MII management
|
||||
* channel.
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <ioports.h>
|
||||
#include <ppc_asm.tmpl>
|
||||
#include <miiphy.h>
|
||||
|
||||
#define BB_MII_RELOCATE(v,off) (v += (v?off:0))
|
||||
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
|
||||
#ifndef CONFIG_BITBANGMII_MULTI
|
||||
|
||||
/*
|
||||
* If CONFIG_BITBANGMII_MULTI is not defined we use a
|
||||
* compatibility layer with the previous miiphybb implementation
|
||||
* based on macros usage.
|
||||
*
|
||||
*/
|
||||
static int bb_mii_init_wrap(struct bb_miiphy_bus *bus)
|
||||
{
|
||||
#ifdef MII_INIT
|
||||
MII_INIT;
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bb_mdio_active_wrap(struct bb_miiphy_bus *bus)
|
||||
{
|
||||
#ifdef MDIO_DECLARE
|
||||
MDIO_DECLARE;
|
||||
#endif
|
||||
MDIO_ACTIVE;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bb_mdio_tristate_wrap(struct bb_miiphy_bus *bus)
|
||||
{
|
||||
#ifdef MDIO_DECLARE
|
||||
MDIO_DECLARE;
|
||||
#endif
|
||||
MDIO_TRISTATE;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bb_set_mdio_wrap(struct bb_miiphy_bus *bus, int v)
|
||||
{
|
||||
#ifdef MDIO_DECLARE
|
||||
MDIO_DECLARE;
|
||||
#endif
|
||||
MDIO(v);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bb_get_mdio_wrap(struct bb_miiphy_bus *bus, int *v)
|
||||
{
|
||||
#ifdef MDIO_DECLARE
|
||||
MDIO_DECLARE;
|
||||
#endif
|
||||
*v = MDIO_READ;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bb_set_mdc_wrap(struct bb_miiphy_bus *bus, int v)
|
||||
{
|
||||
#ifdef MDC_DECLARE
|
||||
MDC_DECLARE;
|
||||
#endif
|
||||
MDC(v);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bb_delay_wrap(struct bb_miiphy_bus *bus)
|
||||
{
|
||||
MIIDELAY;
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct bb_miiphy_bus bb_miiphy_buses[] = {
|
||||
{
|
||||
.name = BB_MII_DEVNAME,
|
||||
.init = bb_mii_init_wrap,
|
||||
.mdio_active = bb_mdio_active_wrap,
|
||||
.mdio_tristate = bb_mdio_tristate_wrap,
|
||||
.set_mdio = bb_set_mdio_wrap,
|
||||
.get_mdio = bb_get_mdio_wrap,
|
||||
.set_mdc = bb_set_mdc_wrap,
|
||||
.delay = bb_delay_wrap,
|
||||
}
|
||||
};
|
||||
|
||||
int bb_miiphy_buses_num = sizeof(bb_miiphy_buses) /
|
||||
sizeof(bb_miiphy_buses[0]);
|
||||
#endif
|
||||
|
||||
void bb_miiphy_init(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < bb_miiphy_buses_num; i++) {
|
||||
#if defined(CONFIG_NEEDS_MANUAL_RELOC)
|
||||
/* Relocate the hook pointers*/
|
||||
BB_MII_RELOCATE(bb_miiphy_buses[i].init, gd->reloc_off);
|
||||
BB_MII_RELOCATE(bb_miiphy_buses[i].mdio_active, gd->reloc_off);
|
||||
BB_MII_RELOCATE(bb_miiphy_buses[i].mdio_tristate, gd->reloc_off);
|
||||
BB_MII_RELOCATE(bb_miiphy_buses[i].set_mdio, gd->reloc_off);
|
||||
BB_MII_RELOCATE(bb_miiphy_buses[i].get_mdio, gd->reloc_off);
|
||||
BB_MII_RELOCATE(bb_miiphy_buses[i].set_mdc, gd->reloc_off);
|
||||
BB_MII_RELOCATE(bb_miiphy_buses[i].delay, gd->reloc_off);
|
||||
#endif
|
||||
if (bb_miiphy_buses[i].init != NULL) {
|
||||
bb_miiphy_buses[i].init(&bb_miiphy_buses[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static inline struct bb_miiphy_bus *bb_miiphy_getbus(const char *devname)
|
||||
{
|
||||
#ifdef CONFIG_BITBANGMII_MULTI
|
||||
int i;
|
||||
|
||||
/* Search the correct bus */
|
||||
for (i = 0; i < bb_miiphy_buses_num; i++) {
|
||||
if (!strcmp(bb_miiphy_buses[i].name, devname)) {
|
||||
return &bb_miiphy_buses[i];
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
#else
|
||||
/* We have just one bitbanging bus */
|
||||
return &bb_miiphy_buses[0];
|
||||
#endif
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
*
|
||||
* Utility to send the preamble, address, and register (common to read
|
||||
* and write).
|
||||
*/
|
||||
static void miiphy_pre(struct bb_miiphy_bus *bus, char read,
|
||||
unsigned char addr, unsigned char reg)
|
||||
{
|
||||
int j;
|
||||
|
||||
/*
|
||||
* Send a 32 bit preamble ('1's) with an extra '1' bit for good measure.
|
||||
* The IEEE spec says this is a PHY optional requirement. The AMD
|
||||
* 79C874 requires one after power up and one after a MII communications
|
||||
* error. This means that we are doing more preambles than we need,
|
||||
* but it is safer and will be much more robust.
|
||||
*/
|
||||
|
||||
bus->mdio_active(bus);
|
||||
bus->set_mdio(bus, 1);
|
||||
for (j = 0; j < 32; j++) {
|
||||
bus->set_mdc(bus, 0);
|
||||
bus->delay(bus);
|
||||
bus->set_mdc(bus, 1);
|
||||
bus->delay(bus);
|
||||
}
|
||||
|
||||
/* send the start bit (01) and the read opcode (10) or write (10) */
|
||||
bus->set_mdc(bus, 0);
|
||||
bus->set_mdio(bus, 0);
|
||||
bus->delay(bus);
|
||||
bus->set_mdc(bus, 1);
|
||||
bus->delay(bus);
|
||||
bus->set_mdc(bus, 0);
|
||||
bus->set_mdio(bus, 1);
|
||||
bus->delay(bus);
|
||||
bus->set_mdc(bus, 1);
|
||||
bus->delay(bus);
|
||||
bus->set_mdc(bus, 0);
|
||||
bus->set_mdio(bus, read);
|
||||
bus->delay(bus);
|
||||
bus->set_mdc(bus, 1);
|
||||
bus->delay(bus);
|
||||
bus->set_mdc(bus, 0);
|
||||
bus->set_mdio(bus, !read);
|
||||
bus->delay(bus);
|
||||
bus->set_mdc(bus, 1);
|
||||
bus->delay(bus);
|
||||
|
||||
/* send the PHY address */
|
||||
for (j = 0; j < 5; j++) {
|
||||
bus->set_mdc(bus, 0);
|
||||
if ((addr & 0x10) == 0) {
|
||||
bus->set_mdio(bus, 0);
|
||||
} else {
|
||||
bus->set_mdio(bus, 1);
|
||||
}
|
||||
bus->delay(bus);
|
||||
bus->set_mdc(bus, 1);
|
||||
bus->delay(bus);
|
||||
addr <<= 1;
|
||||
}
|
||||
|
||||
/* send the register address */
|
||||
for (j = 0; j < 5; j++) {
|
||||
bus->set_mdc(bus, 0);
|
||||
if ((reg & 0x10) == 0) {
|
||||
bus->set_mdio(bus, 0);
|
||||
} else {
|
||||
bus->set_mdio(bus, 1);
|
||||
}
|
||||
bus->delay(bus);
|
||||
bus->set_mdc(bus, 1);
|
||||
bus->delay(bus);
|
||||
reg <<= 1;
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
*
|
||||
* Read a MII PHY register.
|
||||
*
|
||||
* Returns:
|
||||
* 0 on success
|
||||
*/
|
||||
int bb_miiphy_read(const char *devname, unsigned char addr,
|
||||
unsigned char reg, unsigned short *value)
|
||||
{
|
||||
short rdreg; /* register working value */
|
||||
int v;
|
||||
int j; /* counter */
|
||||
struct bb_miiphy_bus *bus;
|
||||
|
||||
bus = bb_miiphy_getbus(devname);
|
||||
if (bus == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (value == NULL) {
|
||||
puts("NULL value pointer\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
miiphy_pre (bus, 1, addr, reg);
|
||||
|
||||
/* tri-state our MDIO I/O pin so we can read */
|
||||
bus->set_mdc(bus, 0);
|
||||
bus->mdio_tristate(bus);
|
||||
bus->delay(bus);
|
||||
bus->set_mdc(bus, 1);
|
||||
bus->delay(bus);
|
||||
|
||||
/* check the turnaround bit: the PHY should be driving it to zero */
|
||||
bus->get_mdio(bus, &v);
|
||||
if (v != 0) {
|
||||
/* puts ("PHY didn't drive TA low\n"); */
|
||||
for (j = 0; j < 32; j++) {
|
||||
bus->set_mdc(bus, 0);
|
||||
bus->delay(bus);
|
||||
bus->set_mdc(bus, 1);
|
||||
bus->delay(bus);
|
||||
}
|
||||
/* There is no PHY, set value to 0xFFFF and return */
|
||||
*value = 0xFFFF;
|
||||
return -1;
|
||||
}
|
||||
|
||||
bus->set_mdc(bus, 0);
|
||||
bus->delay(bus);
|
||||
|
||||
/* read 16 bits of register data, MSB first */
|
||||
rdreg = 0;
|
||||
for (j = 0; j < 16; j++) {
|
||||
bus->set_mdc(bus, 1);
|
||||
bus->delay(bus);
|
||||
rdreg <<= 1;
|
||||
bus->get_mdio(bus, &v);
|
||||
rdreg |= (v & 0x1);
|
||||
bus->set_mdc(bus, 0);
|
||||
bus->delay(bus);
|
||||
}
|
||||
|
||||
bus->set_mdc(bus, 1);
|
||||
bus->delay(bus);
|
||||
bus->set_mdc(bus, 0);
|
||||
bus->delay(bus);
|
||||
bus->set_mdc(bus, 1);
|
||||
bus->delay(bus);
|
||||
|
||||
*value = rdreg;
|
||||
|
||||
#ifdef DEBUG
|
||||
printf ("miiphy_read(0x%x) @ 0x%x = 0x%04x\n", reg, addr, *value);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************************************
|
||||
*
|
||||
* Write a MII PHY register.
|
||||
*
|
||||
* Returns:
|
||||
* 0 on success
|
||||
*/
|
||||
int bb_miiphy_write (const char *devname, unsigned char addr,
|
||||
unsigned char reg, unsigned short value)
|
||||
{
|
||||
struct bb_miiphy_bus *bus;
|
||||
int j; /* counter */
|
||||
|
||||
bus = bb_miiphy_getbus(devname);
|
||||
if (bus == NULL) {
|
||||
/* Bus not found! */
|
||||
return -1;
|
||||
}
|
||||
|
||||
miiphy_pre (bus, 0, addr, reg);
|
||||
|
||||
/* send the turnaround (10) */
|
||||
bus->set_mdc(bus, 0);
|
||||
bus->set_mdio(bus, 1);
|
||||
bus->delay(bus);
|
||||
bus->set_mdc(bus, 1);
|
||||
bus->delay(bus);
|
||||
bus->set_mdc(bus, 0);
|
||||
bus->set_mdio(bus, 0);
|
||||
bus->delay(bus);
|
||||
bus->set_mdc(bus, 1);
|
||||
bus->delay(bus);
|
||||
|
||||
/* write 16 bits of register data, MSB first */
|
||||
for (j = 0; j < 16; j++) {
|
||||
bus->set_mdc(bus, 0);
|
||||
if ((value & 0x00008000) == 0) {
|
||||
bus->set_mdio(bus, 0);
|
||||
} else {
|
||||
bus->set_mdio(bus, 1);
|
||||
}
|
||||
bus->delay(bus);
|
||||
bus->set_mdc(bus, 1);
|
||||
bus->delay(bus);
|
||||
value <<= 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Tri-state the MDIO line.
|
||||
*/
|
||||
bus->mdio_tristate(bus);
|
||||
bus->set_mdc(bus, 0);
|
||||
bus->delay(bus);
|
||||
bus->set_mdc(bus, 1);
|
||||
bus->delay(bus);
|
||||
|
||||
return 0;
|
||||
}
|
||||
1017
u-boot/drivers/net/phy/mv88e61xx.c
Normal file
1017
u-boot/drivers/net/phy/mv88e61xx.c
Normal file
File diff suppressed because it is too large
Load Diff
302
u-boot/drivers/net/phy/mv88e6352.c
Normal file
302
u-boot/drivers/net/phy/mv88e6352.c
Normal file
@@ -0,0 +1,302 @@
|
||||
/*
|
||||
* (C) Copyright 2012
|
||||
* Valentin Lontgchamp, Keymile AG, valentin.longchamp@keymile.com
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <miiphy.h>
|
||||
#include <asm/errno.h>
|
||||
#include <mv88e6352.h>
|
||||
|
||||
#define SMI_HDR ((0x8 | 0x1) << 12)
|
||||
#define SMI_BUSY_MASK (0x8000)
|
||||
#define SMIRD_OP (0x2 << 10)
|
||||
#define SMIWR_OP (0x1 << 10)
|
||||
#define SMI_MASK 0x1f
|
||||
#define PORT_SHIFT 5
|
||||
|
||||
#define COMMAND_REG 0
|
||||
#define DATA_REG 1
|
||||
|
||||
/* global registers */
|
||||
#define GLOBAL 0x1b
|
||||
|
||||
#define GLOBAL_STATUS 0x00
|
||||
#define PPU_STATE 0x8000
|
||||
|
||||
#define GLOBAL_CTRL 0x04
|
||||
#define SW_RESET 0x8000
|
||||
#define PPU_ENABLE 0x4000
|
||||
|
||||
static int sw_wait_rdy(const char *devname, u8 phy_addr)
|
||||
{
|
||||
u16 command;
|
||||
u32 timeout = 100;
|
||||
int ret;
|
||||
|
||||
/* wait till the SMI is not busy */
|
||||
do {
|
||||
/* read command register */
|
||||
ret = miiphy_read(devname, phy_addr, COMMAND_REG, &command);
|
||||
if (ret < 0) {
|
||||
printf("%s: Error reading command register\n",
|
||||
__func__);
|
||||
return ret;
|
||||
}
|
||||
if (timeout-- == 0) {
|
||||
printf("Err..(%s) SMI busy timeout\n", __func__);
|
||||
return -EFAULT;
|
||||
}
|
||||
} while (command & SMI_BUSY_MASK);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sw_reg_read(const char *devname, u8 phy_addr, u8 port,
|
||||
u8 reg, u16 *data)
|
||||
{
|
||||
int ret;
|
||||
u16 command;
|
||||
|
||||
ret = sw_wait_rdy(devname, phy_addr);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
command = SMI_HDR | SMIRD_OP | ((port&SMI_MASK) << PORT_SHIFT) |
|
||||
(reg & SMI_MASK);
|
||||
debug("%s: write to command: %#x\n", __func__, command);
|
||||
ret = miiphy_write(devname, phy_addr, COMMAND_REG, command);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = sw_wait_rdy(devname, phy_addr);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = miiphy_read(devname, phy_addr, DATA_REG, data);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int sw_reg_write(const char *devname, u8 phy_addr, u8 port,
|
||||
u8 reg, u16 data)
|
||||
{
|
||||
int ret;
|
||||
u16 value;
|
||||
|
||||
ret = sw_wait_rdy(devname, phy_addr);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
debug("%s: write to data: %#x\n", __func__, data);
|
||||
ret = miiphy_write(devname, phy_addr, DATA_REG, data);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
value = SMI_HDR | SMIWR_OP | ((port & SMI_MASK) << PORT_SHIFT) |
|
||||
(reg & SMI_MASK);
|
||||
debug("%s: write to command: %#x\n", __func__, value);
|
||||
ret = miiphy_write(devname, phy_addr, COMMAND_REG, value);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = sw_wait_rdy(devname, phy_addr);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ppu_enable(const char *devname, u8 phy_addr)
|
||||
{
|
||||
int i, ret = 0;
|
||||
u16 reg;
|
||||
|
||||
ret = sw_reg_read(devname, phy_addr, GLOBAL, GLOBAL_CTRL, ®);
|
||||
if (ret) {
|
||||
printf("%s: Error reading global ctrl reg\n", __func__);
|
||||
return ret;
|
||||
}
|
||||
|
||||
reg |= PPU_ENABLE;
|
||||
|
||||
ret = sw_reg_write(devname, phy_addr, GLOBAL, GLOBAL_CTRL, reg);
|
||||
if (ret) {
|
||||
printf("%s: Error writing global ctrl reg\n", __func__);
|
||||
return ret;
|
||||
}
|
||||
|
||||
for (i = 0; i < 1000; i++) {
|
||||
sw_reg_read(devname, phy_addr, GLOBAL, GLOBAL_STATUS,
|
||||
®);
|
||||
if ((reg & 0xc000) == 0xc000)
|
||||
return 0;
|
||||
udelay(1000);
|
||||
}
|
||||
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
static int ppu_disable(const char *devname, u8 phy_addr)
|
||||
{
|
||||
int i, ret = 0;
|
||||
u16 reg;
|
||||
|
||||
ret = sw_reg_read(devname, phy_addr, GLOBAL, GLOBAL_CTRL, ®);
|
||||
if (ret) {
|
||||
printf("%s: Error reading global ctrl reg\n", __func__);
|
||||
return ret;
|
||||
}
|
||||
|
||||
reg &= ~PPU_ENABLE;
|
||||
|
||||
ret = sw_reg_write(devname, phy_addr, GLOBAL, GLOBAL_CTRL, reg);
|
||||
if (ret) {
|
||||
printf("%s: Error writing global ctrl reg\n", __func__);
|
||||
return ret;
|
||||
}
|
||||
|
||||
for (i = 0; i < 1000; i++) {
|
||||
sw_reg_read(devname, phy_addr, GLOBAL, GLOBAL_STATUS,
|
||||
®);
|
||||
if ((reg & 0xc000) != 0xc000)
|
||||
return 0;
|
||||
udelay(1000);
|
||||
}
|
||||
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
int mv88e_sw_program(const char *devname, u8 phy_addr,
|
||||
struct mv88e_sw_reg *regs, int regs_nb)
|
||||
{
|
||||
int i, ret = 0;
|
||||
|
||||
/* first we need to disable the PPU */
|
||||
ret = ppu_disable(devname, phy_addr);
|
||||
if (ret) {
|
||||
printf("%s: Error disabling PPU\n", __func__);
|
||||
return ret;
|
||||
}
|
||||
|
||||
for (i = 0; i < regs_nb; i++) {
|
||||
ret = sw_reg_write(devname, phy_addr, regs[i].port,
|
||||
regs[i].reg, regs[i].value);
|
||||
if (ret) {
|
||||
printf("%s: Error configuring switch\n", __func__);
|
||||
ppu_enable(devname, phy_addr);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
/* re-enable the PPU */
|
||||
ret = ppu_enable(devname, phy_addr);
|
||||
if (ret) {
|
||||
printf("%s: Error enabling PPU\n", __func__);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mv88e_sw_reset(const char *devname, u8 phy_addr)
|
||||
{
|
||||
int i, ret = 0;
|
||||
u16 reg;
|
||||
|
||||
ret = sw_reg_read(devname, phy_addr, GLOBAL, GLOBAL_CTRL, ®);
|
||||
if (ret) {
|
||||
printf("%s: Error reading global ctrl reg\n", __func__);
|
||||
return ret;
|
||||
}
|
||||
|
||||
reg = SW_RESET | PPU_ENABLE | 0x0400;
|
||||
|
||||
ret = sw_reg_write(devname, phy_addr, GLOBAL, GLOBAL_CTRL, reg);
|
||||
if (ret) {
|
||||
printf("%s: Error writing global ctrl reg\n", __func__);
|
||||
return ret;
|
||||
}
|
||||
|
||||
for (i = 0; i < 1000; i++) {
|
||||
sw_reg_read(devname, phy_addr, GLOBAL, GLOBAL_STATUS,
|
||||
®);
|
||||
if ((reg & 0xc800) != 0xc800)
|
||||
return 0;
|
||||
udelay(1000);
|
||||
}
|
||||
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
int do_mvsw_reg_read(const char *name, int argc, char * const argv[])
|
||||
{
|
||||
u16 value = 0, phyaddr, reg, port;
|
||||
int ret;
|
||||
|
||||
phyaddr = simple_strtoul(argv[1], NULL, 10);
|
||||
port = simple_strtoul(argv[2], NULL, 10);
|
||||
reg = simple_strtoul(argv[3], NULL, 10);
|
||||
|
||||
ret = sw_reg_read(name, phyaddr, port, reg, &value);
|
||||
printf("%#x\n", value);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int do_mvsw_reg_write(const char *name, int argc, char * const argv[])
|
||||
{
|
||||
u16 value = 0, phyaddr, reg, port;
|
||||
int ret;
|
||||
|
||||
phyaddr = simple_strtoul(argv[1], NULL, 10);
|
||||
port = simple_strtoul(argv[2], NULL, 10);
|
||||
reg = simple_strtoul(argv[3], NULL, 10);
|
||||
value = simple_strtoul(argv[4], NULL, 16);
|
||||
|
||||
ret = sw_reg_write(name, phyaddr, port, reg, value);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
int do_mvsw_reg(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
|
||||
{
|
||||
int ret;
|
||||
const char *cmd, *ethname;
|
||||
|
||||
if (argc < 2)
|
||||
return cmd_usage(cmdtp);
|
||||
|
||||
cmd = argv[1];
|
||||
--argc;
|
||||
++argv;
|
||||
|
||||
if (strcmp(cmd, "read") == 0) {
|
||||
if (argc < 5)
|
||||
return cmd_usage(cmdtp);
|
||||
ethname = argv[1];
|
||||
--argc;
|
||||
++argv;
|
||||
ret = do_mvsw_reg_read(ethname, argc, argv);
|
||||
} else if (strcmp(cmd, "write") == 0) {
|
||||
if (argc < 6)
|
||||
return cmd_usage(cmdtp);
|
||||
ethname = argv[1];
|
||||
--argc;
|
||||
++argv;
|
||||
ret = do_mvsw_reg_write(ethname, argc, argv);
|
||||
} else
|
||||
return cmd_usage(cmdtp);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
U_BOOT_CMD(
|
||||
mvsw_reg, 7, 1, do_mvsw_reg,
|
||||
"marvell 88e6352 switch register access",
|
||||
"write ethname phyaddr port reg value\n"
|
||||
"mvsw_reg read ethname phyaddr port reg\n"
|
||||
);
|
||||
166
u-boot/drivers/net/phy/natsemi.c
Normal file
166
u-boot/drivers/net/phy/natsemi.c
Normal file
@@ -0,0 +1,166 @@
|
||||
/*
|
||||
* National Semiconductor PHY drivers
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*
|
||||
* Copyright 2010-2011 Freescale Semiconductor, Inc.
|
||||
* author Andy Fleming
|
||||
*/
|
||||
#include <phy.h>
|
||||
|
||||
/* NatSemi DP83630 */
|
||||
|
||||
#define DP83630_PHY_PAGESEL_REG 0x13
|
||||
#define DP83630_PHY_PTP_COC_REG 0x14
|
||||
#define DP83630_PHY_PTP_CLKOUT_EN (1<<15)
|
||||
#define DP83630_PHY_RBR_REG 0x17
|
||||
|
||||
static int dp83630_config(struct phy_device *phydev)
|
||||
{
|
||||
int ptp_coc_reg;
|
||||
|
||||
phy_write(phydev, MDIO_DEVAD_NONE, MII_BMCR, BMCR_RESET);
|
||||
phy_write(phydev, MDIO_DEVAD_NONE, DP83630_PHY_PAGESEL_REG, 0x6);
|
||||
ptp_coc_reg = phy_read(phydev, MDIO_DEVAD_NONE,
|
||||
DP83630_PHY_PTP_COC_REG);
|
||||
ptp_coc_reg &= ~DP83630_PHY_PTP_CLKOUT_EN;
|
||||
phy_write(phydev, MDIO_DEVAD_NONE, DP83630_PHY_PTP_COC_REG,
|
||||
ptp_coc_reg);
|
||||
phy_write(phydev, MDIO_DEVAD_NONE, DP83630_PHY_PAGESEL_REG, 0);
|
||||
|
||||
genphy_config_aneg(phydev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct phy_driver DP83630_driver = {
|
||||
.name = "NatSemi DP83630",
|
||||
.uid = 0x20005ce1,
|
||||
.mask = 0xfffffff0,
|
||||
.features = PHY_BASIC_FEATURES,
|
||||
.config = &dp83630_config,
|
||||
.startup = &genphy_startup,
|
||||
.shutdown = &genphy_shutdown,
|
||||
};
|
||||
|
||||
|
||||
/* 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 dp838xx_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)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = genphy_update_link(phydev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return dp83865_parse_status(phydev);
|
||||
}
|
||||
|
||||
|
||||
static struct phy_driver DP83865_driver = {
|
||||
.name = "NatSemi DP83865",
|
||||
.uid = 0x20005c70,
|
||||
.mask = 0xfffffff0,
|
||||
.features = PHY_GBIT_FEATURES,
|
||||
.config = &dp838xx_config,
|
||||
.startup = &dp83865_startup,
|
||||
.shutdown = &genphy_shutdown,
|
||||
};
|
||||
|
||||
/* NatSemi DP83848 */
|
||||
static int dp83848_parse_status(struct phy_device *phydev)
|
||||
{
|
||||
int mii_reg;
|
||||
|
||||
mii_reg = phy_read(phydev, MDIO_DEVAD_NONE, MII_BMSR);
|
||||
|
||||
if(mii_reg & (BMSR_100FULL | BMSR_100HALF)) {
|
||||
phydev->speed = SPEED_100;
|
||||
} else {
|
||||
phydev->speed = SPEED_10;
|
||||
}
|
||||
|
||||
if (mii_reg & (BMSR_10FULL | BMSR_100FULL)) {
|
||||
phydev->duplex = DUPLEX_FULL;
|
||||
} else {
|
||||
phydev->duplex = DUPLEX_HALF;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dp83848_startup(struct phy_device *phydev)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = genphy_update_link(phydev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return dp83848_parse_status(phydev);
|
||||
}
|
||||
|
||||
static struct phy_driver DP83848_driver = {
|
||||
.name = "NatSemi DP83848",
|
||||
.uid = 0x20005c90,
|
||||
.mask = 0x2000ff90,
|
||||
.features = PHY_BASIC_FEATURES,
|
||||
.config = &dp838xx_config,
|
||||
.startup = &dp83848_startup,
|
||||
.shutdown = &genphy_shutdown,
|
||||
};
|
||||
|
||||
int phy_natsemi_init(void)
|
||||
{
|
||||
phy_register(&DP83630_driver);
|
||||
phy_register(&DP83865_driver);
|
||||
phy_register(&DP83848_driver);
|
||||
|
||||
return 0;
|
||||
}
|
||||
906
u-boot/drivers/net/phy/phy.c
Normal file
906
u-boot/drivers/net/phy/phy.c
Normal file
@@ -0,0 +1,906 @@
|
||||
/*
|
||||
* Generic PHY Management code
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*
|
||||
* Copyright 2011 Freescale Semiconductor, Inc.
|
||||
* author Andy Fleming
|
||||
*
|
||||
* Based loosely off of Linux's PHY Lib
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include <common.h>
|
||||
#include <console.h>
|
||||
#include <dm.h>
|
||||
#include <malloc.h>
|
||||
#include <net.h>
|
||||
#include <command.h>
|
||||
#include <miiphy.h>
|
||||
#include <phy.h>
|
||||
#include <errno.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/compiler.h>
|
||||
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
|
||||
/* Generic PHY support and helper functions */
|
||||
|
||||
/**
|
||||
* genphy_config_advert - sanitize and advertise auto-negotation parameters
|
||||
* @phydev: target phy_device struct
|
||||
*
|
||||
* Description: Writes MII_ADVERTISE with the appropriate values,
|
||||
* after sanitizing the values to make sure we only advertise
|
||||
* what is supported. Returns < 0 on error, 0 if the PHY's advertisement
|
||||
* hasn't changed, and > 0 if it has changed.
|
||||
*/
|
||||
static int genphy_config_advert(struct phy_device *phydev)
|
||||
{
|
||||
u32 advertise;
|
||||
int oldadv, adv, bmsr;
|
||||
int err, changed = 0;
|
||||
|
||||
/* Only allow advertising what this PHY supports */
|
||||
phydev->advertising &= phydev->supported;
|
||||
advertise = phydev->advertising;
|
||||
|
||||
/* Setup standard advertisement */
|
||||
adv = phy_read(phydev, MDIO_DEVAD_NONE, MII_ADVERTISE);
|
||||
oldadv = adv;
|
||||
|
||||
if (adv < 0)
|
||||
return adv;
|
||||
|
||||
adv &= ~(ADVERTISE_ALL | ADVERTISE_100BASE4 | ADVERTISE_PAUSE_CAP |
|
||||
ADVERTISE_PAUSE_ASYM);
|
||||
if (advertise & ADVERTISED_10baseT_Half)
|
||||
adv |= ADVERTISE_10HALF;
|
||||
if (advertise & ADVERTISED_10baseT_Full)
|
||||
adv |= ADVERTISE_10FULL;
|
||||
if (advertise & ADVERTISED_100baseT_Half)
|
||||
adv |= ADVERTISE_100HALF;
|
||||
if (advertise & ADVERTISED_100baseT_Full)
|
||||
adv |= ADVERTISE_100FULL;
|
||||
if (advertise & ADVERTISED_Pause)
|
||||
adv |= ADVERTISE_PAUSE_CAP;
|
||||
if (advertise & ADVERTISED_Asym_Pause)
|
||||
adv |= ADVERTISE_PAUSE_ASYM;
|
||||
if (advertise & ADVERTISED_1000baseX_Half)
|
||||
adv |= ADVERTISE_1000XHALF;
|
||||
if (advertise & ADVERTISED_1000baseX_Full)
|
||||
adv |= ADVERTISE_1000XFULL;
|
||||
|
||||
if (adv != oldadv) {
|
||||
err = phy_write(phydev, MDIO_DEVAD_NONE, MII_ADVERTISE, adv);
|
||||
|
||||
if (err < 0)
|
||||
return err;
|
||||
changed = 1;
|
||||
}
|
||||
|
||||
bmsr = phy_read(phydev, MDIO_DEVAD_NONE, MII_BMSR);
|
||||
if (bmsr < 0)
|
||||
return bmsr;
|
||||
|
||||
/* Per 802.3-2008, Section 22.2.4.2.16 Extended status all
|
||||
* 1000Mbits/sec capable PHYs shall have the BMSR_ESTATEN bit set to a
|
||||
* logical 1.
|
||||
*/
|
||||
if (!(bmsr & BMSR_ESTATEN))
|
||||
return changed;
|
||||
|
||||
/* Configure gigabit if it's supported */
|
||||
adv = phy_read(phydev, MDIO_DEVAD_NONE, MII_CTRL1000);
|
||||
oldadv = adv;
|
||||
|
||||
if (adv < 0)
|
||||
return adv;
|
||||
|
||||
adv &= ~(ADVERTISE_1000FULL | ADVERTISE_1000HALF);
|
||||
|
||||
if (phydev->supported & (SUPPORTED_1000baseT_Half |
|
||||
SUPPORTED_1000baseT_Full)) {
|
||||
if (advertise & SUPPORTED_1000baseT_Half)
|
||||
adv |= ADVERTISE_1000HALF;
|
||||
if (advertise & SUPPORTED_1000baseT_Full)
|
||||
adv |= ADVERTISE_1000FULL;
|
||||
}
|
||||
|
||||
if (adv != oldadv)
|
||||
changed = 1;
|
||||
|
||||
err = phy_write(phydev, MDIO_DEVAD_NONE, MII_CTRL1000, adv);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
return changed;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* genphy_setup_forced - configures/forces speed/duplex from @phydev
|
||||
* @phydev: target phy_device struct
|
||||
*
|
||||
* Description: Configures MII_BMCR to force speed/duplex
|
||||
* to the values in phydev. Assumes that the values are valid.
|
||||
*/
|
||||
static int genphy_setup_forced(struct phy_device *phydev)
|
||||
{
|
||||
int err;
|
||||
int ctl = BMCR_ANRESTART;
|
||||
|
||||
phydev->pause = phydev->asym_pause = 0;
|
||||
|
||||
if (SPEED_1000 == phydev->speed)
|
||||
ctl |= BMCR_SPEED1000;
|
||||
else if (SPEED_100 == phydev->speed)
|
||||
ctl |= BMCR_SPEED100;
|
||||
|
||||
if (DUPLEX_FULL == phydev->duplex)
|
||||
ctl |= BMCR_FULLDPLX;
|
||||
|
||||
err = phy_write(phydev, MDIO_DEVAD_NONE, MII_BMCR, ctl);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* genphy_restart_aneg - Enable and Restart Autonegotiation
|
||||
* @phydev: target phy_device struct
|
||||
*/
|
||||
int genphy_restart_aneg(struct phy_device *phydev)
|
||||
{
|
||||
int ctl;
|
||||
|
||||
ctl = phy_read(phydev, MDIO_DEVAD_NONE, MII_BMCR);
|
||||
|
||||
if (ctl < 0)
|
||||
return ctl;
|
||||
|
||||
ctl |= (BMCR_ANENABLE | BMCR_ANRESTART);
|
||||
|
||||
/* Don't isolate the PHY if we're negotiating */
|
||||
ctl &= ~(BMCR_ISOLATE);
|
||||
|
||||
ctl = phy_write(phydev, MDIO_DEVAD_NONE, MII_BMCR, ctl);
|
||||
|
||||
return ctl;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* genphy_config_aneg - restart auto-negotiation or write BMCR
|
||||
* @phydev: target phy_device struct
|
||||
*
|
||||
* Description: If auto-negotiation is enabled, we configure the
|
||||
* advertising, and then restart auto-negotiation. If it is not
|
||||
* enabled, then we write the BMCR.
|
||||
*/
|
||||
int genphy_config_aneg(struct phy_device *phydev)
|
||||
{
|
||||
int result;
|
||||
|
||||
if (AUTONEG_ENABLE != phydev->autoneg)
|
||||
return genphy_setup_forced(phydev);
|
||||
|
||||
result = genphy_config_advert(phydev);
|
||||
|
||||
if (result < 0) /* error */
|
||||
return result;
|
||||
|
||||
if (result == 0) {
|
||||
/* Advertisment hasn't changed, but maybe aneg was never on to
|
||||
* begin with? Or maybe phy was isolated? */
|
||||
int ctl = phy_read(phydev, MDIO_DEVAD_NONE, MII_BMCR);
|
||||
|
||||
if (ctl < 0)
|
||||
return ctl;
|
||||
|
||||
if (!(ctl & BMCR_ANENABLE) || (ctl & BMCR_ISOLATE))
|
||||
result = 1; /* do restart aneg */
|
||||
}
|
||||
|
||||
/* Only restart aneg if we are advertising something different
|
||||
* than we were before. */
|
||||
if (result > 0)
|
||||
result = genphy_restart_aneg(phydev);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* genphy_update_link - update link status in @phydev
|
||||
* @phydev: target phy_device struct
|
||||
*
|
||||
* Description: Update the value in phydev->link to reflect the
|
||||
* current link value. In order to do this, we need to read
|
||||
* the status register twice, keeping the second value.
|
||||
*/
|
||||
int genphy_update_link(struct phy_device *phydev)
|
||||
{
|
||||
unsigned int mii_reg;
|
||||
|
||||
/*
|
||||
* Wait if the link is up, and autonegotiation is in progress
|
||||
* (ie - we're capable and it's not done)
|
||||
*/
|
||||
mii_reg = phy_read(phydev, MDIO_DEVAD_NONE, MII_BMSR);
|
||||
|
||||
/*
|
||||
* If we already saw the link up, and it hasn't gone down, then
|
||||
* we don't need to wait for autoneg again
|
||||
*/
|
||||
if (phydev->link && mii_reg & BMSR_LSTATUS)
|
||||
return 0;
|
||||
|
||||
if ((phydev->autoneg == AUTONEG_ENABLE) &&
|
||||
!(mii_reg & BMSR_ANEGCOMPLETE)) {
|
||||
int i = 0;
|
||||
|
||||
printf("%s Waiting for PHY auto negotiation to complete",
|
||||
phydev->dev->name);
|
||||
while (!(mii_reg & BMSR_ANEGCOMPLETE)) {
|
||||
/*
|
||||
* Timeout reached ?
|
||||
*/
|
||||
if (i > PHY_ANEG_TIMEOUT) {
|
||||
printf(" TIMEOUT !\n");
|
||||
phydev->link = 0;
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
if (ctrlc()) {
|
||||
puts("user interrupt!\n");
|
||||
phydev->link = 0;
|
||||
return -EINTR;
|
||||
}
|
||||
|
||||
if ((i++ % 500) == 0)
|
||||
printf(".");
|
||||
|
||||
udelay(1000); /* 1 ms */
|
||||
mii_reg = phy_read(phydev, MDIO_DEVAD_NONE, MII_BMSR);
|
||||
}
|
||||
printf(" done\n");
|
||||
phydev->link = 1;
|
||||
} else {
|
||||
/* Read the link a second time to clear the latched state */
|
||||
mii_reg = phy_read(phydev, MDIO_DEVAD_NONE, MII_BMSR);
|
||||
|
||||
if (mii_reg & BMSR_LSTATUS)
|
||||
phydev->link = 1;
|
||||
else
|
||||
phydev->link = 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Generic function which updates the speed and duplex. If
|
||||
* autonegotiation is enabled, it uses the AND of the link
|
||||
* partner's advertised capabilities and our advertised
|
||||
* capabilities. If autonegotiation is disabled, we use the
|
||||
* appropriate bits in the control register.
|
||||
*
|
||||
* Stolen from Linux's mii.c and phy_device.c
|
||||
*/
|
||||
int genphy_parse_link(struct phy_device *phydev)
|
||||
{
|
||||
int mii_reg = phy_read(phydev, MDIO_DEVAD_NONE, MII_BMSR);
|
||||
|
||||
/* We're using autonegotiation */
|
||||
if (phydev->autoneg == AUTONEG_ENABLE) {
|
||||
u32 lpa = 0;
|
||||
int gblpa = 0;
|
||||
u32 estatus = 0;
|
||||
|
||||
/* Check for gigabit capability */
|
||||
if (phydev->supported & (SUPPORTED_1000baseT_Full |
|
||||
SUPPORTED_1000baseT_Half)) {
|
||||
/* We want a list of states supported by
|
||||
* both PHYs in the link
|
||||
*/
|
||||
gblpa = phy_read(phydev, MDIO_DEVAD_NONE, MII_STAT1000);
|
||||
if (gblpa < 0) {
|
||||
debug("Could not read MII_STAT1000. Ignoring gigabit capability\n");
|
||||
gblpa = 0;
|
||||
}
|
||||
gblpa &= phy_read(phydev,
|
||||
MDIO_DEVAD_NONE, MII_CTRL1000) << 2;
|
||||
}
|
||||
|
||||
/* Set the baseline so we only have to set them
|
||||
* if they're different
|
||||
*/
|
||||
phydev->speed = SPEED_10;
|
||||
phydev->duplex = DUPLEX_HALF;
|
||||
|
||||
/* Check the gigabit fields */
|
||||
if (gblpa & (PHY_1000BTSR_1000FD | PHY_1000BTSR_1000HD)) {
|
||||
phydev->speed = SPEED_1000;
|
||||
|
||||
if (gblpa & PHY_1000BTSR_1000FD)
|
||||
phydev->duplex = DUPLEX_FULL;
|
||||
|
||||
/* We're done! */
|
||||
return 0;
|
||||
}
|
||||
|
||||
lpa = phy_read(phydev, MDIO_DEVAD_NONE, MII_ADVERTISE);
|
||||
lpa &= phy_read(phydev, MDIO_DEVAD_NONE, MII_LPA);
|
||||
|
||||
if (lpa & (LPA_100FULL | LPA_100HALF)) {
|
||||
phydev->speed = SPEED_100;
|
||||
|
||||
if (lpa & LPA_100FULL)
|
||||
phydev->duplex = DUPLEX_FULL;
|
||||
|
||||
} else if (lpa & LPA_10FULL)
|
||||
phydev->duplex = DUPLEX_FULL;
|
||||
|
||||
/*
|
||||
* Extended status may indicate that the PHY supports
|
||||
* 1000BASE-T/X even though the 1000BASE-T registers
|
||||
* are missing. In this case we can't tell whether the
|
||||
* peer also supports it, so we only check extended
|
||||
* status if the 1000BASE-T registers are actually
|
||||
* missing.
|
||||
*/
|
||||
if ((mii_reg & BMSR_ESTATEN) && !(mii_reg & BMSR_ERCAP))
|
||||
estatus = phy_read(phydev, MDIO_DEVAD_NONE,
|
||||
MII_ESTATUS);
|
||||
|
||||
if (estatus & (ESTATUS_1000_XFULL | ESTATUS_1000_XHALF |
|
||||
ESTATUS_1000_TFULL | ESTATUS_1000_THALF)) {
|
||||
phydev->speed = SPEED_1000;
|
||||
if (estatus & (ESTATUS_1000_XFULL | ESTATUS_1000_TFULL))
|
||||
phydev->duplex = DUPLEX_FULL;
|
||||
}
|
||||
|
||||
} else {
|
||||
u32 bmcr = phy_read(phydev, MDIO_DEVAD_NONE, MII_BMCR);
|
||||
|
||||
phydev->speed = SPEED_10;
|
||||
phydev->duplex = DUPLEX_HALF;
|
||||
|
||||
if (bmcr & BMCR_FULLDPLX)
|
||||
phydev->duplex = DUPLEX_FULL;
|
||||
|
||||
if (bmcr & BMCR_SPEED1000)
|
||||
phydev->speed = SPEED_1000;
|
||||
else if (bmcr & BMCR_SPEED100)
|
||||
phydev->speed = SPEED_100;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int genphy_config(struct phy_device *phydev)
|
||||
{
|
||||
int val;
|
||||
u32 features;
|
||||
|
||||
features = (SUPPORTED_TP | SUPPORTED_MII
|
||||
| SUPPORTED_AUI | SUPPORTED_FIBRE |
|
||||
SUPPORTED_BNC);
|
||||
|
||||
/* Do we support autonegotiation? */
|
||||
val = phy_read(phydev, MDIO_DEVAD_NONE, MII_BMSR);
|
||||
|
||||
if (val < 0)
|
||||
return val;
|
||||
|
||||
if (val & BMSR_ANEGCAPABLE)
|
||||
features |= SUPPORTED_Autoneg;
|
||||
|
||||
if (val & BMSR_100FULL)
|
||||
features |= SUPPORTED_100baseT_Full;
|
||||
if (val & BMSR_100HALF)
|
||||
features |= SUPPORTED_100baseT_Half;
|
||||
if (val & BMSR_10FULL)
|
||||
features |= SUPPORTED_10baseT_Full;
|
||||
if (val & BMSR_10HALF)
|
||||
features |= SUPPORTED_10baseT_Half;
|
||||
|
||||
if (val & BMSR_ESTATEN) {
|
||||
val = phy_read(phydev, MDIO_DEVAD_NONE, MII_ESTATUS);
|
||||
|
||||
if (val < 0)
|
||||
return val;
|
||||
|
||||
if (val & ESTATUS_1000_TFULL)
|
||||
features |= SUPPORTED_1000baseT_Full;
|
||||
if (val & ESTATUS_1000_THALF)
|
||||
features |= SUPPORTED_1000baseT_Half;
|
||||
if (val & ESTATUS_1000_XFULL)
|
||||
features |= SUPPORTED_1000baseX_Full;
|
||||
if (val & ESTATUS_1000_XHALF)
|
||||
features |= SUPPORTED_1000baseX_Half;
|
||||
}
|
||||
|
||||
phydev->supported &= features;
|
||||
phydev->advertising &= features;
|
||||
|
||||
genphy_config_aneg(phydev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int genphy_startup(struct phy_device *phydev)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = genphy_update_link(phydev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return genphy_parse_link(phydev);
|
||||
}
|
||||
|
||||
int genphy_shutdown(struct phy_device *phydev)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct phy_driver genphy_driver = {
|
||||
.uid = 0xffffffff,
|
||||
.mask = 0xffffffff,
|
||||
.name = "Generic PHY",
|
||||
.features = PHY_GBIT_FEATURES | SUPPORTED_MII |
|
||||
SUPPORTED_AUI | SUPPORTED_FIBRE |
|
||||
SUPPORTED_BNC,
|
||||
.config = genphy_config,
|
||||
.startup = genphy_startup,
|
||||
.shutdown = genphy_shutdown,
|
||||
};
|
||||
|
||||
static LIST_HEAD(phy_drivers);
|
||||
|
||||
int phy_init(void)
|
||||
{
|
||||
#ifdef CONFIG_MV88E61XX_SWITCH
|
||||
phy_mv88e61xx_init();
|
||||
#endif
|
||||
#ifdef CONFIG_PHY_AQUANTIA
|
||||
phy_aquantia_init();
|
||||
#endif
|
||||
#ifdef CONFIG_PHY_ATHEROS
|
||||
phy_atheros_init();
|
||||
#endif
|
||||
#ifdef CONFIG_PHY_BROADCOM
|
||||
phy_broadcom_init();
|
||||
#endif
|
||||
#ifdef CONFIG_PHY_CORTINA
|
||||
phy_cortina_init();
|
||||
#endif
|
||||
#ifdef CONFIG_PHY_DAVICOM
|
||||
phy_davicom_init();
|
||||
#endif
|
||||
#ifdef CONFIG_PHY_ET1011C
|
||||
phy_et1011c_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_SMSC
|
||||
phy_smsc_init();
|
||||
#endif
|
||||
#ifdef CONFIG_PHY_TERANETICS
|
||||
phy_teranetics_init();
|
||||
#endif
|
||||
#ifdef CONFIG_PHY_TI
|
||||
phy_ti_init();
|
||||
#endif
|
||||
#ifdef CONFIG_PHY_VITESSE
|
||||
phy_vitesse_init();
|
||||
#endif
|
||||
#ifdef CONFIG_PHY_XILINX
|
||||
phy_xilinx_init();
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int phy_register(struct phy_driver *drv)
|
||||
{
|
||||
INIT_LIST_HEAD(&drv->list);
|
||||
list_add_tail(&drv->list, &phy_drivers);
|
||||
|
||||
#ifdef CONFIG_NEEDS_MANUAL_RELOC
|
||||
if (drv->probe)
|
||||
drv->probe += gd->reloc_off;
|
||||
if (drv->config)
|
||||
drv->config += gd->reloc_off;
|
||||
if (drv->startup)
|
||||
drv->startup += gd->reloc_off;
|
||||
if (drv->shutdown)
|
||||
drv->shutdown += gd->reloc_off;
|
||||
if (drv->readext)
|
||||
drv->readext += gd->reloc_off;
|
||||
if (drv->writeext)
|
||||
drv->writeext += gd->reloc_off;
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
int phy_set_supported(struct phy_device *phydev, u32 max_speed)
|
||||
{
|
||||
/* The default values for phydev->supported are provided by the PHY
|
||||
* driver "features" member, we want to reset to sane defaults first
|
||||
* before supporting higher speeds.
|
||||
*/
|
||||
phydev->supported &= PHY_DEFAULT_FEATURES;
|
||||
|
||||
switch (max_speed) {
|
||||
default:
|
||||
return -ENOTSUPP;
|
||||
case SPEED_1000:
|
||||
phydev->supported |= PHY_1000BT_FEATURES;
|
||||
/* fall through */
|
||||
case SPEED_100:
|
||||
phydev->supported |= PHY_100BT_FEATURES;
|
||||
/* fall through */
|
||||
case SPEED_10:
|
||||
phydev->supported |= PHY_10BT_FEATURES;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int phy_probe(struct phy_device *phydev)
|
||||
{
|
||||
int err = 0;
|
||||
|
||||
phydev->advertising = phydev->supported = phydev->drv->features;
|
||||
phydev->mmds = phydev->drv->mmds;
|
||||
|
||||
if (phydev->drv->probe)
|
||||
err = phydev->drv->probe(phydev);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static struct phy_driver *generic_for_interface(phy_interface_t interface)
|
||||
{
|
||||
#ifdef CONFIG_PHYLIB_10G
|
||||
if (is_10g_interface(interface))
|
||||
return &gen10g_driver;
|
||||
#endif
|
||||
|
||||
return &genphy_driver;
|
||||
}
|
||||
|
||||
static struct phy_driver *get_phy_driver(struct phy_device *phydev,
|
||||
phy_interface_t interface)
|
||||
{
|
||||
struct list_head *entry;
|
||||
int phy_id = phydev->phy_id;
|
||||
struct phy_driver *drv = NULL;
|
||||
|
||||
list_for_each(entry, &phy_drivers) {
|
||||
drv = list_entry(entry, struct phy_driver, list);
|
||||
if ((drv->uid & drv->mask) == (phy_id & drv->mask))
|
||||
return drv;
|
||||
}
|
||||
|
||||
/* If we made it here, there's no driver for this PHY */
|
||||
return generic_for_interface(interface);
|
||||
}
|
||||
|
||||
static struct phy_device *phy_device_create(struct mii_dev *bus, int addr,
|
||||
u32 phy_id,
|
||||
phy_interface_t interface)
|
||||
{
|
||||
struct phy_device *dev;
|
||||
|
||||
/* We allocate the device, and initialize the
|
||||
* default values */
|
||||
dev = malloc(sizeof(*dev));
|
||||
if (!dev) {
|
||||
printf("Failed to allocate PHY device for %s:%d\n",
|
||||
bus->name, addr);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memset(dev, 0, sizeof(*dev));
|
||||
|
||||
dev->duplex = -1;
|
||||
dev->link = 0;
|
||||
dev->interface = interface;
|
||||
|
||||
dev->autoneg = AUTONEG_ENABLE;
|
||||
|
||||
dev->addr = addr;
|
||||
dev->phy_id = phy_id;
|
||||
dev->bus = bus;
|
||||
|
||||
dev->drv = get_phy_driver(dev, interface);
|
||||
|
||||
phy_probe(dev);
|
||||
|
||||
bus->phymap[addr] = dev;
|
||||
|
||||
return dev;
|
||||
}
|
||||
|
||||
/**
|
||||
* get_phy_id - reads the specified addr for its ID.
|
||||
* @bus: the target MII bus
|
||||
* @addr: PHY address on the MII bus
|
||||
* @phy_id: where to store the ID retrieved.
|
||||
*
|
||||
* Description: Reads the ID registers of the PHY at @addr on the
|
||||
* @bus, stores it in @phy_id and returns zero on success.
|
||||
*/
|
||||
int __weak get_phy_id(struct mii_dev *bus, int addr, int devad, u32 *phy_id)
|
||||
{
|
||||
int phy_reg;
|
||||
|
||||
/* Grab the bits from PHYIR1, and put them
|
||||
* in the upper half */
|
||||
phy_reg = bus->read(bus, addr, devad, MII_PHYSID1);
|
||||
|
||||
if (phy_reg < 0)
|
||||
return -EIO;
|
||||
|
||||
*phy_id = (phy_reg & 0xffff) << 16;
|
||||
|
||||
/* Grab the bits from PHYIR2, and put them in the lower half */
|
||||
phy_reg = bus->read(bus, addr, devad, MII_PHYSID2);
|
||||
|
||||
if (phy_reg < 0)
|
||||
return -EIO;
|
||||
|
||||
*phy_id |= (phy_reg & 0xffff);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct phy_device *create_phy_by_mask(struct mii_dev *bus,
|
||||
unsigned phy_mask, int devad, phy_interface_t interface)
|
||||
{
|
||||
u32 phy_id = 0xffffffff;
|
||||
while (phy_mask) {
|
||||
int addr = ffs(phy_mask) - 1;
|
||||
int r = get_phy_id(bus, addr, devad, &phy_id);
|
||||
/* If the PHY ID is mostly f's, we didn't find anything */
|
||||
if (r == 0 && (phy_id & 0x1fffffff) != 0x1fffffff)
|
||||
return phy_device_create(bus, addr, phy_id, interface);
|
||||
phy_mask &= ~(1 << addr);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static struct phy_device *search_for_existing_phy(struct mii_dev *bus,
|
||||
unsigned phy_mask, phy_interface_t interface)
|
||||
{
|
||||
/* If we have one, return the existing device, with new interface */
|
||||
while (phy_mask) {
|
||||
int addr = ffs(phy_mask) - 1;
|
||||
if (bus->phymap[addr]) {
|
||||
bus->phymap[addr]->interface = interface;
|
||||
return bus->phymap[addr];
|
||||
}
|
||||
phy_mask &= ~(1 << addr);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static struct phy_device *get_phy_device_by_mask(struct mii_dev *bus,
|
||||
unsigned phy_mask, phy_interface_t interface)
|
||||
{
|
||||
int i;
|
||||
struct phy_device *phydev;
|
||||
|
||||
phydev = search_for_existing_phy(bus, phy_mask, interface);
|
||||
if (phydev)
|
||||
return phydev;
|
||||
/* Try Standard (ie Clause 22) access */
|
||||
/* Otherwise we have to try Clause 45 */
|
||||
for (i = 0; i < 5; i++) {
|
||||
phydev = create_phy_by_mask(bus, phy_mask,
|
||||
i ? i : MDIO_DEVAD_NONE, interface);
|
||||
if (IS_ERR(phydev))
|
||||
return NULL;
|
||||
if (phydev)
|
||||
return phydev;
|
||||
}
|
||||
|
||||
debug("\n%s PHY: ", bus->name);
|
||||
while (phy_mask) {
|
||||
int addr = ffs(phy_mask) - 1;
|
||||
debug("%d ", addr);
|
||||
phy_mask &= ~(1 << addr);
|
||||
}
|
||||
debug("not found\n");
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* get_phy_device - reads the specified PHY device and returns its @phy_device struct
|
||||
* @bus: the target MII bus
|
||||
* @addr: PHY address on the MII bus
|
||||
*
|
||||
* Description: Reads the ID registers of the PHY at @addr on the
|
||||
* @bus, then allocates and returns the phy_device to represent it.
|
||||
*/
|
||||
static struct phy_device *get_phy_device(struct mii_dev *bus, int addr,
|
||||
phy_interface_t interface)
|
||||
{
|
||||
return get_phy_device_by_mask(bus, 1 << addr, interface);
|
||||
}
|
||||
|
||||
int phy_reset(struct phy_device *phydev)
|
||||
{
|
||||
int reg;
|
||||
int timeout = 500;
|
||||
int devad = MDIO_DEVAD_NONE;
|
||||
|
||||
if (phydev->flags & PHY_FLAG_BROKEN_RESET)
|
||||
return 0;
|
||||
|
||||
#ifdef CONFIG_PHYLIB_10G
|
||||
/* If it's 10G, we need to issue reset through one of the MMDs */
|
||||
if (is_10g_interface(phydev->interface)) {
|
||||
if (!phydev->mmds)
|
||||
gen10g_discover_mmds(phydev);
|
||||
|
||||
devad = ffs(phydev->mmds) - 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (phy_write(phydev, devad, MII_BMCR, BMCR_RESET) < 0) {
|
||||
debug("PHY reset failed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PHY_RESET_DELAY
|
||||
udelay(CONFIG_PHY_RESET_DELAY); /* Intel LXT971A needs this */
|
||||
#endif
|
||||
/*
|
||||
* Poll the control register for the reset bit to go to 0 (it is
|
||||
* auto-clearing). This should happen within 0.5 seconds per the
|
||||
* IEEE spec.
|
||||
*/
|
||||
reg = phy_read(phydev, devad, MII_BMCR);
|
||||
while ((reg & BMCR_RESET) && timeout--) {
|
||||
reg = phy_read(phydev, devad, MII_BMCR);
|
||||
|
||||
if (reg < 0) {
|
||||
debug("PHY status read failed\n");
|
||||
return -1;
|
||||
}
|
||||
udelay(1000);
|
||||
}
|
||||
|
||||
if (reg & BMCR_RESET) {
|
||||
puts("PHY reset timed out\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int miiphy_reset(const char *devname, unsigned char addr)
|
||||
{
|
||||
struct mii_dev *bus = miiphy_get_dev_by_name(devname);
|
||||
struct phy_device *phydev;
|
||||
|
||||
/*
|
||||
* miiphy_reset was only used on standard PHYs, so we'll fake it here.
|
||||
* If later code tries to connect with the right interface, this will
|
||||
* be corrected by get_phy_device in phy_connect()
|
||||
*/
|
||||
phydev = get_phy_device(bus, addr, PHY_INTERFACE_MODE_MII);
|
||||
|
||||
return phy_reset(phydev);
|
||||
}
|
||||
|
||||
struct phy_device *phy_find_by_mask(struct mii_dev *bus, unsigned phy_mask,
|
||||
phy_interface_t interface)
|
||||
{
|
||||
/* Reset the bus */
|
||||
if (bus->reset) {
|
||||
bus->reset(bus);
|
||||
|
||||
/* Wait 15ms to make sure the PHY has come out of hard reset */
|
||||
udelay(15000);
|
||||
}
|
||||
|
||||
return get_phy_device_by_mask(bus, phy_mask, interface);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_DM_ETH
|
||||
void phy_connect_dev(struct phy_device *phydev, struct udevice *dev)
|
||||
#else
|
||||
void phy_connect_dev(struct phy_device *phydev, struct eth_device *dev)
|
||||
#endif
|
||||
{
|
||||
/* Soft Reset the PHY */
|
||||
phy_reset(phydev);
|
||||
if (phydev->dev && phydev->dev != dev) {
|
||||
printf("%s:%d is connected to %s. Reconnecting to %s\n",
|
||||
phydev->bus->name, phydev->addr,
|
||||
phydev->dev->name, dev->name);
|
||||
}
|
||||
phydev->dev = dev;
|
||||
debug("%s connected to %s\n", dev->name, phydev->drv->name);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_DM_ETH
|
||||
struct phy_device *phy_connect(struct mii_dev *bus, int addr,
|
||||
struct udevice *dev, phy_interface_t interface)
|
||||
#else
|
||||
struct phy_device *phy_connect(struct mii_dev *bus, int addr,
|
||||
struct eth_device *dev, phy_interface_t interface)
|
||||
#endif
|
||||
{
|
||||
struct phy_device *phydev;
|
||||
|
||||
phydev = phy_find_by_mask(bus, 1 << addr, interface);
|
||||
if (phydev)
|
||||
phy_connect_dev(phydev, dev);
|
||||
else
|
||||
printf("Could not get PHY for %s: addr %d\n", bus->name, addr);
|
||||
return phydev;
|
||||
}
|
||||
|
||||
/*
|
||||
* Start the PHY. Returns 0 on success, or a negative error code.
|
||||
*/
|
||||
int phy_startup(struct phy_device *phydev)
|
||||
{
|
||||
if (phydev->drv->startup)
|
||||
return phydev->drv->startup(phydev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
__weak int board_phy_config(struct phy_device *phydev)
|
||||
{
|
||||
if (phydev->drv->config)
|
||||
return phydev->drv->config(phydev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int phy_config(struct phy_device *phydev)
|
||||
{
|
||||
/* Invoke an optional board-specific helper */
|
||||
return board_phy_config(phydev);
|
||||
}
|
||||
|
||||
int phy_shutdown(struct phy_device *phydev)
|
||||
{
|
||||
if (phydev->drv->shutdown)
|
||||
phydev->drv->shutdown(phydev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int phy_get_interface_by_name(const char *str)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < PHY_INTERFACE_MODE_COUNT; i++) {
|
||||
if (!strcmp(str, phy_interface_strings[i]))
|
||||
return i;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
297
u-boot/drivers/net/phy/realtek.c
Normal file
297
u-boot/drivers/net/phy/realtek.c
Normal file
@@ -0,0 +1,297 @@
|
||||
/*
|
||||
* RealTek PHY drivers
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*
|
||||
* Copyright 2010-2011, 2015 Freescale Semiconductor, Inc.
|
||||
* author Andy Fleming
|
||||
* Copyright 2016 Karsten Merker <merker@debian.org>
|
||||
*/
|
||||
#include <config.h>
|
||||
#include <common.h>
|
||||
#include <phy.h>
|
||||
|
||||
#define PHY_AUTONEGOTIATE_TIMEOUT 5000
|
||||
|
||||
/* RTL8211x 1000BASE-T Control Register */
|
||||
#define MIIM_RTL8211x_CTRL1000T_MSCE (1 << 12);
|
||||
#define MIIM_RTL8211X_CTRL1000T_MASTER (1 << 11);
|
||||
|
||||
/* RTL8211x PHY Status Register */
|
||||
#define MIIM_RTL8211x_PHY_STATUS 0x11
|
||||
#define MIIM_RTL8211x_PHYSTAT_SPEED 0xc000
|
||||
#define MIIM_RTL8211x_PHYSTAT_GBIT 0x8000
|
||||
#define MIIM_RTL8211x_PHYSTAT_100 0x4000
|
||||
#define MIIM_RTL8211x_PHYSTAT_DUPLEX 0x2000
|
||||
#define MIIM_RTL8211x_PHYSTAT_SPDDONE 0x0800
|
||||
#define MIIM_RTL8211x_PHYSTAT_LINK 0x0400
|
||||
|
||||
/* RTL8211x PHY Interrupt Enable Register */
|
||||
#define MIIM_RTL8211x_PHY_INER 0x12
|
||||
#define MIIM_RTL8211x_PHY_INTR_ENA 0x9f01
|
||||
#define MIIM_RTL8211x_PHY_INTR_DIS 0x0000
|
||||
|
||||
/* RTL8211x PHY Interrupt Status Register */
|
||||
#define MIIM_RTL8211x_PHY_INSR 0x13
|
||||
|
||||
/* RTL8211F PHY Status Register */
|
||||
#define MIIM_RTL8211F_PHY_STATUS 0x1a
|
||||
#define MIIM_RTL8211F_AUTONEG_ENABLE 0x1000
|
||||
#define MIIM_RTL8211F_PHYSTAT_SPEED 0x0030
|
||||
#define MIIM_RTL8211F_PHYSTAT_GBIT 0x0020
|
||||
#define MIIM_RTL8211F_PHYSTAT_100 0x0010
|
||||
#define MIIM_RTL8211F_PHYSTAT_DUPLEX 0x0008
|
||||
#define MIIM_RTL8211F_PHYSTAT_SPDDONE 0x0800
|
||||
#define MIIM_RTL8211F_PHYSTAT_LINK 0x0004
|
||||
|
||||
#define MIIM_RTL8211F_PAGE_SELECT 0x1f
|
||||
#define MIIM_RTL8211F_TX_DELAY 0x100
|
||||
#define MIIM_RTL8211F_LCR 0x10
|
||||
|
||||
/* RealTek RTL8211x */
|
||||
static int rtl8211x_config(struct phy_device *phydev)
|
||||
{
|
||||
phy_write(phydev, MDIO_DEVAD_NONE, MII_BMCR, BMCR_RESET);
|
||||
|
||||
/* mask interrupt at init; if the interrupt is
|
||||
* needed indeed, it should be explicitly enabled
|
||||
*/
|
||||
phy_write(phydev, MDIO_DEVAD_NONE, MIIM_RTL8211x_PHY_INER,
|
||||
MIIM_RTL8211x_PHY_INTR_DIS);
|
||||
#ifdef CONFIG_RTL8211X_PHY_FORCE_MASTER
|
||||
unsigned int reg = phy_read(phydev, MDIO_DEVAD_NONE, MII_CTRL1000);
|
||||
/* force manual master/slave configuration */
|
||||
reg |= MIIM_RTL8211x_CTRL1000T_MSCE;
|
||||
/* force master mode */
|
||||
reg |= MIIM_RTL8211X_CTRL1000T_MASTER;
|
||||
phy_write(phydev, MDIO_DEVAD_NONE, MII_CTRL1000, reg);
|
||||
#endif
|
||||
/* read interrupt status just to clear it */
|
||||
phy_read(phydev, MDIO_DEVAD_NONE, MIIM_RTL8211x_PHY_INER);
|
||||
|
||||
genphy_config_aneg(phydev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rtl8211f_config(struct phy_device *phydev)
|
||||
{
|
||||
u16 reg;
|
||||
|
||||
phy_write(phydev, MDIO_DEVAD_NONE, MII_BMCR, BMCR_RESET);
|
||||
|
||||
if (phydev->interface == PHY_INTERFACE_MODE_RGMII) {
|
||||
/* enable TXDLY */
|
||||
phy_write(phydev, MDIO_DEVAD_NONE,
|
||||
MIIM_RTL8211F_PAGE_SELECT, 0xd08);
|
||||
reg = phy_read(phydev, MDIO_DEVAD_NONE, 0x11);
|
||||
reg |= MIIM_RTL8211F_TX_DELAY;
|
||||
phy_write(phydev, MDIO_DEVAD_NONE, 0x11, reg);
|
||||
/* restore to default page 0 */
|
||||
phy_write(phydev, MDIO_DEVAD_NONE,
|
||||
MIIM_RTL8211F_PAGE_SELECT, 0x0);
|
||||
}
|
||||
|
||||
/* Set green LED for Link, yellow LED for Active */
|
||||
phy_write(phydev, MDIO_DEVAD_NONE,
|
||||
MIIM_RTL8211F_PAGE_SELECT, 0xd04);
|
||||
phy_write(phydev, MDIO_DEVAD_NONE, 0x10, 0x617f);
|
||||
phy_write(phydev, MDIO_DEVAD_NONE,
|
||||
MIIM_RTL8211F_PAGE_SELECT, 0x0);
|
||||
|
||||
genphy_config_aneg(phydev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rtl8211x_parse_status(struct phy_device *phydev)
|
||||
{
|
||||
unsigned int speed;
|
||||
unsigned int mii_reg;
|
||||
|
||||
mii_reg = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_RTL8211x_PHY_STATUS);
|
||||
|
||||
if (!(mii_reg & MIIM_RTL8211x_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_RTL8211x_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_RTL8211x_PHY_STATUS);
|
||||
}
|
||||
puts(" done\n");
|
||||
udelay(500000); /* another 500 ms (results in faster booting) */
|
||||
} else {
|
||||
if (mii_reg & MIIM_RTL8211x_PHYSTAT_LINK)
|
||||
phydev->link = 1;
|
||||
else
|
||||
phydev->link = 0;
|
||||
}
|
||||
|
||||
if (mii_reg & MIIM_RTL8211x_PHYSTAT_DUPLEX)
|
||||
phydev->duplex = DUPLEX_FULL;
|
||||
else
|
||||
phydev->duplex = DUPLEX_HALF;
|
||||
|
||||
speed = (mii_reg & MIIM_RTL8211x_PHYSTAT_SPEED);
|
||||
|
||||
switch (speed) {
|
||||
case MIIM_RTL8211x_PHYSTAT_GBIT:
|
||||
phydev->speed = SPEED_1000;
|
||||
break;
|
||||
case MIIM_RTL8211x_PHYSTAT_100:
|
||||
phydev->speed = SPEED_100;
|
||||
break;
|
||||
default:
|
||||
phydev->speed = SPEED_10;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rtl8211f_parse_status(struct phy_device *phydev)
|
||||
{
|
||||
unsigned int speed;
|
||||
unsigned int mii_reg;
|
||||
int i = 0;
|
||||
|
||||
phy_write(phydev, MDIO_DEVAD_NONE, MIIM_RTL8211F_PAGE_SELECT, 0xa43);
|
||||
mii_reg = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_RTL8211F_PHY_STATUS);
|
||||
|
||||
phydev->link = 1;
|
||||
while (!(mii_reg & MIIM_RTL8211F_PHYSTAT_LINK)) {
|
||||
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_RTL8211F_PHY_STATUS);
|
||||
}
|
||||
|
||||
if (mii_reg & MIIM_RTL8211F_PHYSTAT_DUPLEX)
|
||||
phydev->duplex = DUPLEX_FULL;
|
||||
else
|
||||
phydev->duplex = DUPLEX_HALF;
|
||||
|
||||
speed = (mii_reg & MIIM_RTL8211F_PHYSTAT_SPEED);
|
||||
|
||||
switch (speed) {
|
||||
case MIIM_RTL8211F_PHYSTAT_GBIT:
|
||||
phydev->speed = SPEED_1000;
|
||||
break;
|
||||
case MIIM_RTL8211F_PHYSTAT_100:
|
||||
phydev->speed = SPEED_100;
|
||||
break;
|
||||
default:
|
||||
phydev->speed = SPEED_10;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rtl8211x_startup(struct phy_device *phydev)
|
||||
{
|
||||
int ret;
|
||||
|
||||
/* Read the Status (2x to make sure link is right) */
|
||||
ret = genphy_update_link(phydev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return rtl8211x_parse_status(phydev);
|
||||
}
|
||||
|
||||
static int rtl8211e_startup(struct phy_device *phydev)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = genphy_update_link(phydev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return genphy_parse_link(phydev);
|
||||
}
|
||||
|
||||
static int rtl8211f_startup(struct phy_device *phydev)
|
||||
{
|
||||
int ret;
|
||||
|
||||
/* Read the Status (2x to make sure link is right) */
|
||||
ret = genphy_update_link(phydev);
|
||||
if (ret)
|
||||
return ret;
|
||||
/* Read the Status (2x to make sure link is right) */
|
||||
|
||||
return rtl8211f_parse_status(phydev);
|
||||
}
|
||||
|
||||
/* Support for RTL8211B PHY */
|
||||
static struct phy_driver RTL8211B_driver = {
|
||||
.name = "RealTek RTL8211B",
|
||||
.uid = 0x1cc912,
|
||||
.mask = 0xffffff,
|
||||
.features = PHY_GBIT_FEATURES,
|
||||
.config = &rtl8211x_config,
|
||||
.startup = &rtl8211x_startup,
|
||||
.shutdown = &genphy_shutdown,
|
||||
};
|
||||
|
||||
/* Support for RTL8211E-VB-CG, RTL8211E-VL-CG and RTL8211EG-VB-CG PHYs */
|
||||
static struct phy_driver RTL8211E_driver = {
|
||||
.name = "RealTek RTL8211E",
|
||||
.uid = 0x1cc915,
|
||||
.mask = 0xffffff,
|
||||
.features = PHY_GBIT_FEATURES,
|
||||
.config = &rtl8211x_config,
|
||||
.startup = &rtl8211e_startup,
|
||||
.shutdown = &genphy_shutdown,
|
||||
};
|
||||
|
||||
/* Support for RTL8211DN PHY */
|
||||
static struct phy_driver RTL8211DN_driver = {
|
||||
.name = "RealTek RTL8211DN",
|
||||
.uid = 0x1cc914,
|
||||
.mask = 0xffffff,
|
||||
.features = PHY_GBIT_FEATURES,
|
||||
.config = &rtl8211x_config,
|
||||
.startup = &rtl8211x_startup,
|
||||
.shutdown = &genphy_shutdown,
|
||||
};
|
||||
|
||||
/* Support for RTL8211F PHY */
|
||||
static struct phy_driver RTL8211F_driver = {
|
||||
.name = "RealTek RTL8211F",
|
||||
.uid = 0x1cc916,
|
||||
.mask = 0xffffff,
|
||||
.features = PHY_GBIT_FEATURES,
|
||||
.config = &rtl8211f_config,
|
||||
.startup = &rtl8211f_startup,
|
||||
.shutdown = &genphy_shutdown,
|
||||
};
|
||||
|
||||
int phy_realtek_init(void)
|
||||
{
|
||||
phy_register(&RTL8211B_driver);
|
||||
phy_register(&RTL8211E_driver);
|
||||
phy_register(&RTL8211F_driver);
|
||||
phy_register(&RTL8211DN_driver);
|
||||
|
||||
return 0;
|
||||
}
|
||||
93
u-boot/drivers/net/phy/smsc.c
Normal file
93
u-boot/drivers/net/phy/smsc.c
Normal file
@@ -0,0 +1,93 @@
|
||||
/*
|
||||
* SMSC PHY drivers
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*
|
||||
* Base code from drivers/net/phy/davicom.c
|
||||
* Copyright 2010-2011 Freescale Semiconductor, Inc.
|
||||
* author Andy Fleming
|
||||
*
|
||||
* Some code copied from linux kernel
|
||||
* Copyright (c) 2006 Herbert Valerio Riedel <hvr@gnu.org>
|
||||
*/
|
||||
#include <miiphy.h>
|
||||
|
||||
/* This code does not check the partner abilities. */
|
||||
static int smsc_parse_status(struct phy_device *phydev)
|
||||
{
|
||||
int mii_reg;
|
||||
|
||||
mii_reg = phy_read(phydev, MDIO_DEVAD_NONE, MII_BMSR);
|
||||
|
||||
if (mii_reg & (BMSR_100FULL | BMSR_100HALF))
|
||||
phydev->speed = SPEED_100;
|
||||
else
|
||||
phydev->speed = SPEED_10;
|
||||
|
||||
if (mii_reg & (BMSR_10FULL | BMSR_100FULL))
|
||||
phydev->duplex = DUPLEX_FULL;
|
||||
else
|
||||
phydev->duplex = DUPLEX_HALF;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int smsc_startup(struct phy_device *phydev)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = genphy_update_link(phydev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return smsc_parse_status(phydev);
|
||||
}
|
||||
|
||||
static struct phy_driver lan8700_driver = {
|
||||
.name = "SMSC LAN8700",
|
||||
.uid = 0x0007c0c0,
|
||||
.mask = 0xffff0,
|
||||
.features = PHY_BASIC_FEATURES,
|
||||
.config = &genphy_config_aneg,
|
||||
.startup = &smsc_startup,
|
||||
.shutdown = &genphy_shutdown,
|
||||
};
|
||||
|
||||
static struct phy_driver lan911x_driver = {
|
||||
.name = "SMSC LAN911x Internal PHY",
|
||||
.uid = 0x0007c0d0,
|
||||
.mask = 0xffff0,
|
||||
.features = PHY_BASIC_FEATURES,
|
||||
.config = &genphy_config_aneg,
|
||||
.startup = &smsc_startup,
|
||||
.shutdown = &genphy_shutdown,
|
||||
};
|
||||
|
||||
static struct phy_driver lan8710_driver = {
|
||||
.name = "SMSC LAN8710/LAN8720",
|
||||
.uid = 0x0007c0f0,
|
||||
.mask = 0xffff0,
|
||||
.features = PHY_BASIC_FEATURES,
|
||||
.config = &genphy_config_aneg,
|
||||
.startup = &genphy_startup,
|
||||
.shutdown = &genphy_shutdown,
|
||||
};
|
||||
|
||||
static struct phy_driver lan8740_driver = {
|
||||
.name = "SMSC LAN8740",
|
||||
.uid = 0x0007c110,
|
||||
.mask = 0xffff0,
|
||||
.features = PHY_BASIC_FEATURES,
|
||||
.config = &genphy_config_aneg,
|
||||
.startup = &genphy_startup,
|
||||
.shutdown = &genphy_shutdown,
|
||||
};
|
||||
int phy_smsc_init(void)
|
||||
{
|
||||
phy_register(&lan8710_driver);
|
||||
phy_register(&lan911x_driver);
|
||||
phy_register(&lan8700_driver);
|
||||
phy_register(&lan8740_driver);
|
||||
|
||||
return 0;
|
||||
}
|
||||
112
u-boot/drivers/net/phy/teranetics.c
Normal file
112
u-boot/drivers/net/phy/teranetics.c
Normal file
@@ -0,0 +1,112 @@
|
||||
/*
|
||||
* Teranetics PHY drivers
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*
|
||||
* Copyright 2010-2011 Freescale Semiconductor, Inc.
|
||||
* author Andy Fleming
|
||||
*/
|
||||
#include <config.h>
|
||||
#include <common.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);
|
||||
u8 phy_hwversion;
|
||||
|
||||
/*
|
||||
* bit 15:12 of register 30.32 indicates PHY hardware
|
||||
* version. It can be used to distinguish TN80xx from
|
||||
* TN2020. TN2020 needs write 0x2 to 30.93, but TN80xx
|
||||
* needs 0x1.
|
||||
*/
|
||||
phy_hwversion = (phy_read(phydev, 30, 32) >> 12) & 0xf;
|
||||
if (phy_hwversion <= 3) {
|
||||
phy_write(phydev, 30, 93, 2);
|
||||
phy_write(phydev, MDIO_MMD_AN, MDIO_CTRL1, restart_an);
|
||||
} else {
|
||||
phy_write(phydev, 30, 93, 1);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int tn2020_startup(struct phy_device *phydev)
|
||||
{
|
||||
unsigned int timeout = 5 * 1000; /* 5 second timeout */
|
||||
|
||||
#define MDIO_PHYXS_LANE_READY (MDIO_PHYXS_LNSTAT_SYNC0 | \
|
||||
MDIO_PHYXS_LNSTAT_SYNC1 | \
|
||||
MDIO_PHYXS_LNSTAT_SYNC2 | \
|
||||
MDIO_PHYXS_LNSTAT_SYNC3 | \
|
||||
MDIO_PHYXS_LNSTAT_ALIGN)
|
||||
|
||||
/*
|
||||
* Wait for the XAUI-SERDES lanes to align first. Under normal
|
||||
* circumstances, this can take up to three seconds.
|
||||
*/
|
||||
while (--timeout) {
|
||||
int reg = phy_read(phydev, MDIO_MMD_PHYXS, MDIO_PHYXS_LNSTAT);
|
||||
if (reg < 0) {
|
||||
printf("TN2020: Error reading from PHY at "
|
||||
"address %u\n", phydev->addr);
|
||||
break;
|
||||
}
|
||||
if ((reg & MDIO_PHYXS_LANE_READY) == MDIO_PHYXS_LANE_READY)
|
||||
break;
|
||||
udelay(1000);
|
||||
}
|
||||
if (!timeout) {
|
||||
/*
|
||||
* A timeout is bad, but it may not be fatal, so don't
|
||||
* return an error. Display a warning instead.
|
||||
*/
|
||||
printf("TN2020: Timeout waiting for PHY at address %u to "
|
||||
"align.\n", phydev->addr);
|
||||
}
|
||||
|
||||
if (phydev->port != PORT_FIBRE)
|
||||
return gen10g_startup(phydev);
|
||||
|
||||
/*
|
||||
* The TN2020 only pretends to support fiber.
|
||||
* It works, but it doesn't look like it works,
|
||||
* so the link status reports no link.
|
||||
*/
|
||||
phydev->link = 1;
|
||||
|
||||
/* For now just lie and say it's 10G all the time */
|
||||
phydev->speed = SPEED_10000;
|
||||
phydev->duplex = DUPLEX_FULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct phy_driver tn2020_driver = {
|
||||
.name = "Teranetics TN2020",
|
||||
.uid = PHY_UID_TN2020,
|
||||
.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 = &tn2020_startup,
|
||||
.shutdown = &gen10g_shutdown,
|
||||
};
|
||||
|
||||
int phy_teranetics_init(void)
|
||||
{
|
||||
phy_register(&tn2020_driver);
|
||||
|
||||
return 0;
|
||||
}
|
||||
296
u-boot/drivers/net/phy/ti.c
Normal file
296
u-boot/drivers/net/phy/ti.c
Normal file
@@ -0,0 +1,296 @@
|
||||
/*
|
||||
* TI PHY drivers
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0
|
||||
*
|
||||
*/
|
||||
#include <common.h>
|
||||
#include <phy.h>
|
||||
#include <linux/compat.h>
|
||||
#include <malloc.h>
|
||||
|
||||
#include <fdtdec.h>
|
||||
#include <dm.h>
|
||||
#include <dt-bindings/net/ti-dp83867.h>
|
||||
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
|
||||
/* TI DP83867 */
|
||||
#define DP83867_DEVADDR 0x1f
|
||||
|
||||
#define MII_DP83867_PHYCTRL 0x10
|
||||
#define MII_DP83867_MICR 0x12
|
||||
#define MII_DP83867_CFG2 0x14
|
||||
#define MII_DP83867_BISCR 0x16
|
||||
#define DP83867_CTRL 0x1f
|
||||
|
||||
/* Extended Registers */
|
||||
#define DP83867_RGMIICTL 0x0032
|
||||
#define DP83867_RGMIIDCTL 0x0086
|
||||
|
||||
#define DP83867_SW_RESET BIT(15)
|
||||
#define DP83867_SW_RESTART BIT(14)
|
||||
|
||||
/* MICR Interrupt bits */
|
||||
#define MII_DP83867_MICR_AN_ERR_INT_EN BIT(15)
|
||||
#define MII_DP83867_MICR_SPEED_CHNG_INT_EN BIT(14)
|
||||
#define MII_DP83867_MICR_DUP_MODE_CHNG_INT_EN BIT(13)
|
||||
#define MII_DP83867_MICR_PAGE_RXD_INT_EN BIT(12)
|
||||
#define MII_DP83867_MICR_AUTONEG_COMP_INT_EN BIT(11)
|
||||
#define MII_DP83867_MICR_LINK_STS_CHNG_INT_EN BIT(10)
|
||||
#define MII_DP83867_MICR_FALSE_CARRIER_INT_EN BIT(8)
|
||||
#define MII_DP83867_MICR_SLEEP_MODE_CHNG_INT_EN BIT(4)
|
||||
#define MII_DP83867_MICR_WOL_INT_EN BIT(3)
|
||||
#define MII_DP83867_MICR_XGMII_ERR_INT_EN BIT(2)
|
||||
#define MII_DP83867_MICR_POL_CHNG_INT_EN BIT(1)
|
||||
#define MII_DP83867_MICR_JABBER_INT_EN BIT(0)
|
||||
|
||||
/* RGMIICTL bits */
|
||||
#define DP83867_RGMII_TX_CLK_DELAY_EN BIT(1)
|
||||
#define DP83867_RGMII_RX_CLK_DELAY_EN BIT(0)
|
||||
|
||||
/* PHY CTRL bits */
|
||||
#define DP83867_PHYCR_FIFO_DEPTH_SHIFT 14
|
||||
#define DP83867_MDI_CROSSOVER 5
|
||||
#define DP83867_MDI_CROSSOVER_AUTO 2
|
||||
#define DP83867_MDI_CROSSOVER_MDIX 2
|
||||
#define DP83867_PHYCTRL_SGMIIEN 0x0800
|
||||
#define DP83867_PHYCTRL_RXFIFO_SHIFT 12
|
||||
#define DP83867_PHYCTRL_TXFIFO_SHIFT 14
|
||||
|
||||
/* RGMIIDCTL bits */
|
||||
#define DP83867_RGMII_TX_CLK_DELAY_SHIFT 4
|
||||
|
||||
/* CFG2 bits */
|
||||
#define MII_DP83867_CFG2_SPEEDOPT_10EN 0x0040
|
||||
#define MII_DP83867_CFG2_SGMII_AUTONEGEN 0x0080
|
||||
#define MII_DP83867_CFG2_SPEEDOPT_ENH 0x0100
|
||||
#define MII_DP83867_CFG2_SPEEDOPT_CNT 0x0800
|
||||
#define MII_DP83867_CFG2_SPEEDOPT_INTLOW 0x2000
|
||||
#define MII_DP83867_CFG2_MASK 0x003F
|
||||
|
||||
#define MII_MMD_CTRL 0x0d /* MMD Access Control Register */
|
||||
#define MII_MMD_DATA 0x0e /* MMD Access Data Register */
|
||||
|
||||
/* MMD Access Control register fields */
|
||||
#define MII_MMD_CTRL_DEVAD_MASK 0x1f /* Mask MMD DEVAD*/
|
||||
#define MII_MMD_CTRL_ADDR 0x0000 /* Address */
|
||||
#define MII_MMD_CTRL_NOINCR 0x4000 /* no post increment */
|
||||
#define MII_MMD_CTRL_INCR_RDWT 0x8000 /* post increment on reads & writes */
|
||||
#define MII_MMD_CTRL_INCR_ON_WT 0xC000 /* post increment on writes only */
|
||||
|
||||
/* User setting - can be taken from DTS */
|
||||
#define DEFAULT_RX_ID_DELAY DP83867_RGMIIDCTL_2_25_NS
|
||||
#define DEFAULT_TX_ID_DELAY DP83867_RGMIIDCTL_2_75_NS
|
||||
#define DEFAULT_FIFO_DEPTH DP83867_PHYCR_FIFO_DEPTH_4_B_NIB
|
||||
|
||||
struct dp83867_private {
|
||||
int rx_id_delay;
|
||||
int tx_id_delay;
|
||||
int fifo_depth;
|
||||
};
|
||||
|
||||
/**
|
||||
* phy_read_mmd_indirect - reads data from the MMD registers
|
||||
* @phydev: The PHY device bus
|
||||
* @prtad: MMD Address
|
||||
* @devad: MMD DEVAD
|
||||
* @addr: PHY address on the MII bus
|
||||
*
|
||||
* Description: it reads data from the MMD registers (clause 22 to access to
|
||||
* clause 45) of the specified phy address.
|
||||
* To read these registers we have:
|
||||
* 1) Write reg 13 // DEVAD
|
||||
* 2) Write reg 14 // MMD Address
|
||||
* 3) Write reg 13 // MMD Data Command for MMD DEVAD
|
||||
* 3) Read reg 14 // Read MMD data
|
||||
*/
|
||||
int phy_read_mmd_indirect(struct phy_device *phydev, int prtad,
|
||||
int devad, int addr)
|
||||
{
|
||||
int value = -1;
|
||||
|
||||
/* Write the desired MMD Devad */
|
||||
phy_write(phydev, addr, MII_MMD_CTRL, devad);
|
||||
|
||||
/* Write the desired MMD register address */
|
||||
phy_write(phydev, addr, MII_MMD_DATA, prtad);
|
||||
|
||||
/* Select the Function : DATA with no post increment */
|
||||
phy_write(phydev, addr, MII_MMD_CTRL, (devad | MII_MMD_CTRL_NOINCR));
|
||||
|
||||
/* Read the content of the MMD's selected register */
|
||||
value = phy_read(phydev, addr, MII_MMD_DATA);
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* phy_write_mmd_indirect - writes data to the MMD registers
|
||||
* @phydev: The PHY device
|
||||
* @prtad: MMD Address
|
||||
* @devad: MMD DEVAD
|
||||
* @addr: PHY address on the MII bus
|
||||
* @data: data to write in the MMD register
|
||||
*
|
||||
* Description: Write data from the MMD registers of the specified
|
||||
* phy address.
|
||||
* To write these registers we have:
|
||||
* 1) Write reg 13 // DEVAD
|
||||
* 2) Write reg 14 // MMD Address
|
||||
* 3) Write reg 13 // MMD Data Command for MMD DEVAD
|
||||
* 3) Write reg 14 // Write MMD data
|
||||
*/
|
||||
void phy_write_mmd_indirect(struct phy_device *phydev, int prtad,
|
||||
int devad, int addr, u32 data)
|
||||
{
|
||||
/* Write the desired MMD Devad */
|
||||
phy_write(phydev, addr, MII_MMD_CTRL, devad);
|
||||
|
||||
/* Write the desired MMD register address */
|
||||
phy_write(phydev, addr, MII_MMD_DATA, prtad);
|
||||
|
||||
/* Select the Function : DATA with no post increment */
|
||||
phy_write(phydev, addr, MII_MMD_CTRL, (devad | MII_MMD_CTRL_NOINCR));
|
||||
|
||||
/* Write the data into MMD's selected register */
|
||||
phy_write(phydev, addr, MII_MMD_DATA, data);
|
||||
}
|
||||
|
||||
#if defined(CONFIG_DM_ETH)
|
||||
/**
|
||||
* dp83867_data_init - Convenience function for setting PHY specific data
|
||||
*
|
||||
* @phydev: the phy_device struct
|
||||
*/
|
||||
static int dp83867_of_init(struct phy_device *phydev)
|
||||
{
|
||||
struct dp83867_private *dp83867 = phydev->priv;
|
||||
struct udevice *dev = phydev->dev;
|
||||
|
||||
dp83867->rx_id_delay = fdtdec_get_uint(gd->fdt_blob, dev->of_offset,
|
||||
"ti,rx-internal-delay", -1);
|
||||
|
||||
dp83867->tx_id_delay = fdtdec_get_uint(gd->fdt_blob, dev->of_offset,
|
||||
"ti,tx-internal-delay", -1);
|
||||
|
||||
dp83867->fifo_depth = fdtdec_get_uint(gd->fdt_blob, dev->of_offset,
|
||||
"ti,fifo-depth", -1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
static int dp83867_of_init(struct phy_device *phydev)
|
||||
{
|
||||
struct dp83867_private *dp83867 = phydev->priv;
|
||||
|
||||
dp83867->rx_id_delay = DEFAULT_RX_ID_DELAY;
|
||||
dp83867->tx_id_delay = DEFAULT_TX_ID_DELAY;
|
||||
dp83867->fifo_depth = DEFAULT_FIFO_DEPTH;
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int dp83867_config(struct phy_device *phydev)
|
||||
{
|
||||
struct dp83867_private *dp83867;
|
||||
unsigned int val, delay, cfg2;
|
||||
int ret;
|
||||
|
||||
if (!phydev->priv) {
|
||||
dp83867 = kzalloc(sizeof(*dp83867), GFP_KERNEL);
|
||||
if (!dp83867)
|
||||
return -ENOMEM;
|
||||
|
||||
phydev->priv = dp83867;
|
||||
ret = dp83867_of_init(phydev);
|
||||
if (ret)
|
||||
goto err_out;
|
||||
} else {
|
||||
dp83867 = (struct dp83867_private *)phydev->priv;
|
||||
}
|
||||
|
||||
/* Restart the PHY. */
|
||||
val = phy_read(phydev, MDIO_DEVAD_NONE, DP83867_CTRL);
|
||||
phy_write(phydev, MDIO_DEVAD_NONE, DP83867_CTRL,
|
||||
val | DP83867_SW_RESTART);
|
||||
|
||||
if (phy_interface_is_rgmii(phydev)) {
|
||||
ret = phy_write(phydev, MDIO_DEVAD_NONE, MII_DP83867_PHYCTRL,
|
||||
(DP83867_MDI_CROSSOVER_AUTO << DP83867_MDI_CROSSOVER) |
|
||||
(dp83867->fifo_depth << DP83867_PHYCR_FIFO_DEPTH_SHIFT));
|
||||
if (ret)
|
||||
goto err_out;
|
||||
} else if (phy_interface_is_sgmii(phydev)) {
|
||||
phy_write(phydev, MDIO_DEVAD_NONE, MII_BMCR,
|
||||
(BMCR_ANENABLE | BMCR_FULLDPLX | BMCR_SPEED1000));
|
||||
|
||||
cfg2 = phy_read(phydev, phydev->addr, MII_DP83867_CFG2);
|
||||
cfg2 &= MII_DP83867_CFG2_MASK;
|
||||
cfg2 |= (MII_DP83867_CFG2_SPEEDOPT_10EN |
|
||||
MII_DP83867_CFG2_SGMII_AUTONEGEN |
|
||||
MII_DP83867_CFG2_SPEEDOPT_ENH |
|
||||
MII_DP83867_CFG2_SPEEDOPT_CNT |
|
||||
MII_DP83867_CFG2_SPEEDOPT_INTLOW);
|
||||
phy_write(phydev, MDIO_DEVAD_NONE, MII_DP83867_CFG2, cfg2);
|
||||
|
||||
phy_write_mmd_indirect(phydev, DP83867_RGMIICTL,
|
||||
DP83867_DEVADDR, phydev->addr, 0x0);
|
||||
|
||||
phy_write(phydev, MDIO_DEVAD_NONE, MII_DP83867_PHYCTRL,
|
||||
DP83867_PHYCTRL_SGMIIEN |
|
||||
(DP83867_MDI_CROSSOVER_MDIX <<
|
||||
DP83867_MDI_CROSSOVER) |
|
||||
(dp83867->fifo_depth << DP83867_PHYCTRL_RXFIFO_SHIFT) |
|
||||
(dp83867->fifo_depth << DP83867_PHYCTRL_TXFIFO_SHIFT));
|
||||
phy_write(phydev, MDIO_DEVAD_NONE, MII_DP83867_BISCR, 0x0);
|
||||
}
|
||||
|
||||
if ((phydev->interface >= PHY_INTERFACE_MODE_RGMII_ID) &&
|
||||
(phydev->interface <= PHY_INTERFACE_MODE_RGMII_RXID)) {
|
||||
val = phy_read_mmd_indirect(phydev, DP83867_RGMIICTL,
|
||||
DP83867_DEVADDR, phydev->addr);
|
||||
|
||||
if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID)
|
||||
val |= (DP83867_RGMII_TX_CLK_DELAY_EN |
|
||||
DP83867_RGMII_RX_CLK_DELAY_EN);
|
||||
|
||||
if (phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID)
|
||||
val |= DP83867_RGMII_TX_CLK_DELAY_EN;
|
||||
|
||||
if (phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID)
|
||||
val |= DP83867_RGMII_RX_CLK_DELAY_EN;
|
||||
|
||||
phy_write_mmd_indirect(phydev, DP83867_RGMIICTL,
|
||||
DP83867_DEVADDR, phydev->addr, val);
|
||||
|
||||
delay = (dp83867->rx_id_delay |
|
||||
(dp83867->tx_id_delay << DP83867_RGMII_TX_CLK_DELAY_SHIFT));
|
||||
|
||||
phy_write_mmd_indirect(phydev, DP83867_RGMIIDCTL,
|
||||
DP83867_DEVADDR, phydev->addr, delay);
|
||||
}
|
||||
|
||||
genphy_config_aneg(phydev);
|
||||
return 0;
|
||||
|
||||
err_out:
|
||||
kfree(dp83867);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static struct phy_driver DP83867_driver = {
|
||||
.name = "TI DP83867",
|
||||
.uid = 0x2000a231,
|
||||
.mask = 0xfffffff0,
|
||||
.features = PHY_GBIT_FEATURES,
|
||||
.config = &dp83867_config,
|
||||
.startup = &genphy_startup,
|
||||
.shutdown = &genphy_shutdown,
|
||||
};
|
||||
|
||||
int phy_ti_init(void)
|
||||
{
|
||||
phy_register(&DP83867_driver);
|
||||
return 0;
|
||||
}
|
||||
440
u-boot/drivers/net/phy/vitesse.c
Normal file
440
u-boot/drivers/net/phy/vitesse.c
Normal file
@@ -0,0 +1,440 @@
|
||||
/*
|
||||
* Vitesse PHY drivers
|
||||
*
|
||||
* Copyright 2010-2014 Freescale Semiconductor, Inc.
|
||||
* Original Author: Andy Fleming
|
||||
* Add vsc8662 phy support - Priyanka Jain
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
#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
|
||||
#define PHY_EXT_PAGE_ACCESS_GENERAL 0x10
|
||||
#define PHY_EXT_PAGE_ACCESS_EXTENDED3 0x3
|
||||
|
||||
/* Vitesse VSC8574 control register */
|
||||
#define MIIM_VSC8574_MAC_SERDES_CON 0x10
|
||||
#define MIIM_VSC8574_MAC_SERDES_ANEG 0x80
|
||||
#define MIIM_VSC8574_GENERAL18 0x12
|
||||
#define MIIM_VSC8574_GENERAL19 0x13
|
||||
|
||||
/* Vitesse VSC8574 gerenal purpose register 18 */
|
||||
#define MIIM_VSC8574_18G_SGMII 0x80f0
|
||||
#define MIIM_VSC8574_18G_QSGMII 0x80e0
|
||||
#define MIIM_VSC8574_18G_CMDSTAT 0x8000
|
||||
|
||||
/* Vitesse VSC8514 control register */
|
||||
#define MIIM_VSC8514_MAC_SERDES_CON 0x10
|
||||
#define MIIM_VSC8514_GENERAL18 0x12
|
||||
#define MIIM_VSC8514_GENERAL19 0x13
|
||||
#define MIIM_VSC8514_GENERAL23 0x17
|
||||
|
||||
/* Vitesse VSC8514 gerenal purpose register 18 */
|
||||
#define MIIM_VSC8514_18G_QSGMII 0x80e0
|
||||
#define MIIM_VSC8514_18G_CMDSTAT 0x8000
|
||||
|
||||
/* Vitesse VSC8664 Control/Status Register */
|
||||
#define MIIM_VSC8664_SERDES_AND_SIGDET 0x13
|
||||
#define MIIM_VSC8664_ADDITIONAL_DEV 0x16
|
||||
#define MIIM_VSC8664_EPHY_CON 0x17
|
||||
#define MIIM_VSC8664_LED_CON 0x1E
|
||||
|
||||
#define PHY_EXT_PAGE_ACCESS_EXTENDED 0x0001
|
||||
|
||||
/* 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)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = genphy_update_link(phydev);
|
||||
if (ret)
|
||||
return ret;
|
||||
return vitesse_parse_status(phydev);
|
||||
}
|
||||
|
||||
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_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 */
|
||||
static 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 int vsc8574_config(struct phy_device *phydev)
|
||||
{
|
||||
u32 val;
|
||||
/* configure register 19G for MAC */
|
||||
phy_write(phydev, MDIO_DEVAD_NONE, PHY_EXT_PAGE_ACCESS,
|
||||
PHY_EXT_PAGE_ACCESS_GENERAL);
|
||||
|
||||
val = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_VSC8574_GENERAL19);
|
||||
if (phydev->interface == PHY_INTERFACE_MODE_QSGMII) {
|
||||
/* set bit 15:14 to '01' for QSGMII mode */
|
||||
val = (val & 0x3fff) | (1 << 14);
|
||||
phy_write(phydev, MDIO_DEVAD_NONE,
|
||||
MIIM_VSC8574_GENERAL19, val);
|
||||
/* Enable 4 ports MAC QSGMII */
|
||||
phy_write(phydev, MDIO_DEVAD_NONE, MIIM_VSC8574_GENERAL18,
|
||||
MIIM_VSC8574_18G_QSGMII);
|
||||
} else {
|
||||
/* set bit 15:14 to '00' for SGMII mode */
|
||||
val = val & 0x3fff;
|
||||
phy_write(phydev, MDIO_DEVAD_NONE, MIIM_VSC8574_GENERAL19, val);
|
||||
/* Enable 4 ports MAC SGMII */
|
||||
phy_write(phydev, MDIO_DEVAD_NONE, MIIM_VSC8574_GENERAL18,
|
||||
MIIM_VSC8574_18G_SGMII);
|
||||
}
|
||||
val = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_VSC8574_GENERAL18);
|
||||
/* When bit 15 is cleared the command has completed */
|
||||
while (val & MIIM_VSC8574_18G_CMDSTAT)
|
||||
val = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_VSC8574_GENERAL18);
|
||||
|
||||
/* Enable Serdes Auto-negotiation */
|
||||
phy_write(phydev, MDIO_DEVAD_NONE, PHY_EXT_PAGE_ACCESS,
|
||||
PHY_EXT_PAGE_ACCESS_EXTENDED3);
|
||||
val = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_VSC8574_MAC_SERDES_CON);
|
||||
val = val | MIIM_VSC8574_MAC_SERDES_ANEG;
|
||||
phy_write(phydev, MDIO_DEVAD_NONE, MIIM_VSC8574_MAC_SERDES_CON, val);
|
||||
|
||||
phy_write(phydev, MDIO_DEVAD_NONE, PHY_EXT_PAGE_ACCESS, 0);
|
||||
|
||||
genphy_config_aneg(phydev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vsc8514_config(struct phy_device *phydev)
|
||||
{
|
||||
u32 val;
|
||||
int timeout = 1000000;
|
||||
|
||||
/* configure register to access 19G */
|
||||
phy_write(phydev, MDIO_DEVAD_NONE, PHY_EXT_PAGE_ACCESS,
|
||||
PHY_EXT_PAGE_ACCESS_GENERAL);
|
||||
|
||||
val = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_VSC8514_GENERAL19);
|
||||
if (phydev->interface == PHY_INTERFACE_MODE_QSGMII) {
|
||||
/* set bit 15:14 to '01' for QSGMII mode */
|
||||
val = (val & 0x3fff) | (1 << 14);
|
||||
phy_write(phydev, MDIO_DEVAD_NONE,
|
||||
MIIM_VSC8514_GENERAL19, val);
|
||||
/* Enable 4 ports MAC QSGMII */
|
||||
phy_write(phydev, MDIO_DEVAD_NONE, MIIM_VSC8514_GENERAL18,
|
||||
MIIM_VSC8514_18G_QSGMII);
|
||||
} else {
|
||||
/*TODO Add SGMII functionality once spec sheet
|
||||
* for VSC8514 defines complete functionality
|
||||
*/
|
||||
}
|
||||
|
||||
val = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_VSC8514_GENERAL18);
|
||||
/* When bit 15 is cleared the command has completed */
|
||||
while ((val & MIIM_VSC8514_18G_CMDSTAT) && timeout--)
|
||||
val = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_VSC8514_GENERAL18);
|
||||
|
||||
if (0 == timeout) {
|
||||
printf("PHY 8514 config failed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
phy_write(phydev, MDIO_DEVAD_NONE, PHY_EXT_PAGE_ACCESS, 0);
|
||||
|
||||
/* configure register to access 23 */
|
||||
val = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_VSC8514_GENERAL23);
|
||||
/* set bits 10:8 to '000' */
|
||||
val = (val & 0xf8ff);
|
||||
phy_write(phydev, MDIO_DEVAD_NONE, MIIM_VSC8514_GENERAL23, val);
|
||||
|
||||
/* Enable Serdes Auto-negotiation */
|
||||
phy_write(phydev, MDIO_DEVAD_NONE, PHY_EXT_PAGE_ACCESS,
|
||||
PHY_EXT_PAGE_ACCESS_EXTENDED3);
|
||||
val = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_VSC8514_MAC_SERDES_CON);
|
||||
val = val | MIIM_VSC8574_MAC_SERDES_ANEG;
|
||||
phy_write(phydev, MDIO_DEVAD_NONE, MIIM_VSC8514_MAC_SERDES_CON, val);
|
||||
phy_write(phydev, MDIO_DEVAD_NONE, PHY_EXT_PAGE_ACCESS, 0);
|
||||
|
||||
genphy_config_aneg(phydev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vsc8664_config(struct phy_device *phydev)
|
||||
{
|
||||
u32 val;
|
||||
|
||||
/* Enable MAC interface auto-negotiation */
|
||||
phy_write(phydev, MDIO_DEVAD_NONE, PHY_EXT_PAGE_ACCESS, 0);
|
||||
val = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_VSC8664_EPHY_CON);
|
||||
val |= (1 << 13);
|
||||
phy_write(phydev, MDIO_DEVAD_NONE, MIIM_VSC8664_EPHY_CON, val);
|
||||
|
||||
phy_write(phydev, MDIO_DEVAD_NONE, PHY_EXT_PAGE_ACCESS,
|
||||
PHY_EXT_PAGE_ACCESS_EXTENDED);
|
||||
val = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_VSC8664_SERDES_AND_SIGDET);
|
||||
val |= (1 << 11);
|
||||
phy_write(phydev, MDIO_DEVAD_NONE, MIIM_VSC8664_SERDES_AND_SIGDET, val);
|
||||
phy_write(phydev, MDIO_DEVAD_NONE, PHY_EXT_PAGE_ACCESS, 0);
|
||||
|
||||
/* Enable LED blink */
|
||||
val = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_VSC8664_LED_CON);
|
||||
val &= ~(1 << 2);
|
||||
phy_write(phydev, MDIO_DEVAD_NONE, MIIM_VSC8664_LED_CON, val);
|
||||
|
||||
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 VSC8574_driver = {
|
||||
.name = "Vitesse VSC8574",
|
||||
.uid = 0x704a0,
|
||||
.mask = 0xffff0,
|
||||
.features = PHY_GBIT_FEATURES,
|
||||
.config = &vsc8574_config,
|
||||
.startup = &vitesse_startup,
|
||||
.shutdown = &genphy_shutdown,
|
||||
};
|
||||
|
||||
static struct phy_driver VSC8514_driver = {
|
||||
.name = "Vitesse VSC8514",
|
||||
.uid = 0x70670,
|
||||
.mask = 0xffff0,
|
||||
.features = PHY_GBIT_FEATURES,
|
||||
.config = &vsc8514_config,
|
||||
.startup = &vitesse_startup,
|
||||
.shutdown = &genphy_shutdown,
|
||||
};
|
||||
|
||||
static struct phy_driver VSC8584_driver = {
|
||||
.name = "Vitesse VSC8584",
|
||||
.uid = 0x707c0,
|
||||
.mask = 0xffff0,
|
||||
.features = PHY_GBIT_FEATURES,
|
||||
.config = &vsc8574_config,
|
||||
.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,
|
||||
};
|
||||
|
||||
static struct phy_driver VSC8662_driver = {
|
||||
.name = "Vitesse VSC8662",
|
||||
.uid = 0x70660,
|
||||
.mask = 0xffff0,
|
||||
.features = PHY_GBIT_FEATURES,
|
||||
.config = &genphy_config_aneg,
|
||||
.startup = &vitesse_startup,
|
||||
.shutdown = &genphy_shutdown,
|
||||
};
|
||||
|
||||
static struct phy_driver VSC8664_driver = {
|
||||
.name = "Vitesse VSC8664",
|
||||
.uid = 0x70660,
|
||||
.mask = 0xffff0,
|
||||
.features = PHY_GBIT_FEATURES,
|
||||
.config = &vsc8664_config,
|
||||
.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(&VSC8574_driver);
|
||||
phy_register(&VSC8584_driver);
|
||||
phy_register(&VSC8514_driver);
|
||||
phy_register(&VSC8662_driver);
|
||||
phy_register(&VSC8664_driver);
|
||||
phy_register(&cis8201_driver);
|
||||
phy_register(&cis8204_driver);
|
||||
|
||||
return 0;
|
||||
}
|
||||
144
u-boot/drivers/net/phy/xilinx_phy.c
Normal file
144
u-boot/drivers/net/phy/xilinx_phy.c
Normal file
@@ -0,0 +1,144 @@
|
||||
/*
|
||||
* Xilinx PCS/PMA Core phy driver
|
||||
*
|
||||
* Copyright (C) 2015 - 2016 Xilinx, Inc.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include <common.h>
|
||||
#include <phy.h>
|
||||
#include <dm.h>
|
||||
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
|
||||
#define MII_PHY_STATUS_SPD_MASK 0x0C00
|
||||
#define MII_PHY_STATUS_FULLDUPLEX 0x1000
|
||||
#define MII_PHY_STATUS_1000 0x0800
|
||||
#define MII_PHY_STATUS_100 0x0400
|
||||
#define XPCSPMA_PHY_CTRL_ISOLATE_DISABLE 0xFBFF
|
||||
|
||||
/* Mask used for ID comparisons */
|
||||
#define XILINX_PHY_ID_MASK 0xfffffff0
|
||||
|
||||
/* Known PHY IDs */
|
||||
#define XILINX_PHY_ID 0x01740c00
|
||||
|
||||
/* struct phy_device dev_flags definitions */
|
||||
#define XAE_PHY_TYPE_MII 0
|
||||
#define XAE_PHY_TYPE_GMII 1
|
||||
#define XAE_PHY_TYPE_RGMII_1_3 2
|
||||
#define XAE_PHY_TYPE_RGMII_2_0 3
|
||||
#define XAE_PHY_TYPE_SGMII 4
|
||||
#define XAE_PHY_TYPE_1000BASE_X 5
|
||||
|
||||
static int xilinxphy_startup(struct phy_device *phydev)
|
||||
{
|
||||
int err;
|
||||
int status = 0;
|
||||
|
||||
debug("%s\n", __func__);
|
||||
/* Update the link, but return if there
|
||||
* was an error
|
||||
*/
|
||||
err = genphy_update_link(phydev);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (AUTONEG_ENABLE == phydev->autoneg) {
|
||||
status = phy_read(phydev, MDIO_DEVAD_NONE, MII_LPA);
|
||||
status = status & MII_PHY_STATUS_SPD_MASK;
|
||||
|
||||
if (status & MII_PHY_STATUS_FULLDUPLEX)
|
||||
phydev->duplex = DUPLEX_FULL;
|
||||
else
|
||||
phydev->duplex = DUPLEX_HALF;
|
||||
|
||||
switch (status) {
|
||||
case MII_PHY_STATUS_1000:
|
||||
phydev->speed = SPEED_1000;
|
||||
break;
|
||||
|
||||
case MII_PHY_STATUS_100:
|
||||
phydev->speed = SPEED_100;
|
||||
break;
|
||||
|
||||
default:
|
||||
phydev->speed = SPEED_10;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
int bmcr = phy_read(phydev, MDIO_DEVAD_NONE, MII_BMCR);
|
||||
|
||||
if (bmcr < 0)
|
||||
return bmcr;
|
||||
|
||||
if (bmcr & BMCR_FULLDPLX)
|
||||
phydev->duplex = DUPLEX_FULL;
|
||||
else
|
||||
phydev->duplex = DUPLEX_HALF;
|
||||
|
||||
if (bmcr & BMCR_SPEED1000)
|
||||
phydev->speed = SPEED_1000;
|
||||
else if (bmcr & BMCR_SPEED100)
|
||||
phydev->speed = SPEED_100;
|
||||
else
|
||||
phydev->speed = SPEED_10;
|
||||
}
|
||||
|
||||
/*
|
||||
* For 1000BASE-X Phy Mode the speed/duplex will always be
|
||||
* 1000Mbps/fullduplex
|
||||
*/
|
||||
if (phydev->flags == XAE_PHY_TYPE_1000BASE_X) {
|
||||
phydev->duplex = DUPLEX_FULL;
|
||||
phydev->speed = SPEED_1000;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int xilinxphy_of_init(struct phy_device *phydev)
|
||||
{
|
||||
struct udevice *dev = (struct udevice *)&phydev->dev;
|
||||
u32 phytype;
|
||||
|
||||
debug("%s\n", __func__);
|
||||
phytype = fdtdec_get_int(gd->fdt_blob, dev->of_offset, "phy-type", -1);
|
||||
if (phytype == XAE_PHY_TYPE_1000BASE_X)
|
||||
phydev->flags |= XAE_PHY_TYPE_1000BASE_X;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int xilinxphy_config(struct phy_device *phydev)
|
||||
{
|
||||
int temp;
|
||||
|
||||
debug("%s\n", __func__);
|
||||
xilinxphy_of_init(phydev);
|
||||
temp = phy_read(phydev, MDIO_DEVAD_NONE, MII_BMCR);
|
||||
temp &= XPCSPMA_PHY_CTRL_ISOLATE_DISABLE;
|
||||
phy_write(phydev, MDIO_DEVAD_NONE, MII_BMCR, temp);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct phy_driver xilinxphy_driver = {
|
||||
.uid = XILINX_PHY_ID,
|
||||
.mask = XILINX_PHY_ID_MASK,
|
||||
.name = "Xilinx PCS/PMA PHY",
|
||||
.features = PHY_GBIT_FEATURES,
|
||||
.config = &xilinxphy_config,
|
||||
.startup = &xilinxphy_startup,
|
||||
.shutdown = &genphy_shutdown,
|
||||
};
|
||||
|
||||
int phy_xilinx_init(void)
|
||||
{
|
||||
debug("%s\n", __func__);
|
||||
phy_register(&xilinxphy_driver);
|
||||
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user