[U-Boot] [PATCH 1/3] phy: Add phy driver support for xilinx PCS/PMA core

From: Siva Durga Prasad Paladugu siva.durga.paladugu@xilinx.com
Add phy driver support for xilinx PCS/PMA core
Signed-off-by: Siva Durga Prasad Paladugu sivadur@xilinx.com Signed-off-by: Kedareswara rao Appana appanad@xilinx.com Signed-off-by: Michal Simek michal.simek@xilinx.com ---
drivers/net/phy/Makefile | 1 + drivers/net/phy/phy.c | 3 + drivers/net/phy/xilinx_phy.c | 144 +++++++++++++++++++++++++++++++++++++++++++ include/phy.h | 1 + 4 files changed, 149 insertions(+) create mode 100644 drivers/net/phy/xilinx_phy.c
diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile index 9e4d4927e676..1e299b97b961 100644 --- a/drivers/net/phy/Makefile +++ b/drivers/net/phy/Makefile @@ -25,4 +25,5 @@ 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 diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c index 17866a244b3a..23c82bb36e93 100644 --- a/drivers/net/phy/phy.c +++ b/drivers/net/phy/phy.c @@ -503,6 +503,9 @@ int phy_init(void) #ifdef CONFIG_PHY_VITESSE phy_vitesse_init(); #endif +#ifdef CONFIG_PHY_XILINX + phy_xilinx_init(); +#endif
return 0; } diff --git a/drivers/net/phy/xilinx_phy.c b/drivers/net/phy/xilinx_phy.c new file mode 100644 index 000000000000..f3eaf2e97ced --- /dev/null +++ b/drivers/net/phy/xilinx_phy.c @@ -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; +} diff --git a/include/phy.h b/include/phy.h index 09bbe483a4b1..21459a8c8093 100644 --- a/include/phy.h +++ b/include/phy.h @@ -264,6 +264,7 @@ int phy_smsc_init(void); int phy_teranetics_init(void); int phy_ti_init(void); int phy_vitesse_init(void); +int phy_xilinx_init(void);
int board_phy_config(struct phy_device *phydev); int get_phy_id(struct mii_dev *bus, int addr, int devad, u32 *phy_id);

From: Siva Durga Prasad Paladugu siva.durga.paladugu@xilinx.com
Add support of SGMII interface for zynq GEM. Read xlnx,emio property from DT.
Signed-off-by: Siva Durga Prasad Paladugu sivadur@xilinx.com Signed-off-by: Michal Simek michal.simek@xilinx.com ---
drivers/net/zynq_gem.c | 26 +++++++++++++++++++------- 1 file changed, 19 insertions(+), 7 deletions(-)
diff --git a/drivers/net/zynq_gem.c b/drivers/net/zynq_gem.c index b3821c31a91d..4049e1cb94e8 100644 --- a/drivers/net/zynq_gem.c +++ b/drivers/net/zynq_gem.c @@ -57,6 +57,8 @@ DECLARE_GLOBAL_DATA_PTR; #define ZYNQ_GEM_NWCFG_SPEED1000 0x000000400 /* 1Gbps operation */ #define ZYNQ_GEM_NWCFG_FDEN 0x000000002 /* Full Duplex mode */ #define ZYNQ_GEM_NWCFG_FSREM 0x000020000 /* FCS removal */ +#define ZYNQ_GEM_NWCFG_SGMII_ENBL 0x080000000 /* SGMII Enable */ +#define ZYNQ_GEM_NWCFG_PCS_SEL 0x000000800 /* PCS select */ #ifdef CONFIG_ARM64 #define ZYNQ_GEM_NWCFG_MDCCLKDIV 0x000100000 /* Div pclk by 64, max 160MHz */ #else @@ -330,10 +332,12 @@ static int zynq_phy_init(struct udevice *dev) /* Enable only MDIO bus */ writel(ZYNQ_GEM_NWCTRL_MDEN_MASK, ®s->nwctrl);
- ret = phy_detection(dev); - if (ret) { - printf("GEM PHY init failed\n"); - return ret; + if (priv->interface != PHY_INTERFACE_MODE_SGMII) { + ret = phy_detection(dev); + if (ret) { + printf("GEM PHY init failed\n"); + return ret; + } }
priv->phydev = phy_connect(priv->bus, priv->phyaddr, dev, @@ -351,7 +355,7 @@ static int zynq_phy_init(struct udevice *dev)
static int zynq_gem_init(struct udevice *dev) { - u32 i; + u32 i, nwconfig; unsigned long clk_rate = 0; struct zynq_gem_priv *priv = dev_get_priv(dev); struct zynq_gem_regs *regs = priv->iobase; @@ -426,14 +430,20 @@ static int zynq_gem_init(struct udevice *dev) return -1; }
+ nwconfig = ZYNQ_GEM_NWCFG_INIT; + + if (priv->interface == PHY_INTERFACE_MODE_SGMII) + nwconfig |= ZYNQ_GEM_NWCFG_SGMII_ENBL | + ZYNQ_GEM_NWCFG_PCS_SEL; + switch (priv->phydev->speed) { case SPEED_1000: - writel(ZYNQ_GEM_NWCFG_INIT | ZYNQ_GEM_NWCFG_SPEED1000, + writel(nwconfig | ZYNQ_GEM_NWCFG_SPEED1000, ®s->nwcfg); clk_rate = ZYNQ_GEM_FREQUENCY_1000; break; case SPEED_100: - writel(ZYNQ_GEM_NWCFG_INIT | ZYNQ_GEM_NWCFG_SPEED100, + writel(nwconfig | ZYNQ_GEM_NWCFG_SPEED100, ®s->nwcfg); clk_rate = ZYNQ_GEM_FREQUENCY_100; break; @@ -663,6 +673,8 @@ static int zynq_gem_ofdata_to_platdata(struct udevice *dev) } priv->interface = pdata->phy_interface;
+ priv->emio = fdtdec_get_bool(gd->fdt_blob, dev->of_offset, "xlnx,emio"); + printf("ZYNQ GEM: %lx, phyaddr %d, interface %s\n", (ulong)priv->iobase, priv->phyaddr, phy_string_for_interface(priv->interface));

On Mon, Feb 15, 2016 at 3:55 AM, Michal Simek michal.simek@xilinx.com wrote:
From: Siva Durga Prasad Paladugu siva.durga.paladugu@xilinx.com
Add support of SGMII interface for zynq GEM. Read xlnx,emio property from DT.
Signed-off-by: Siva Durga Prasad Paladugu sivadur@xilinx.com Signed-off-by: Michal Simek michal.simek@xilinx.com
drivers/net/zynq_gem.c | 26 +++++++++++++++++++------- 1 file changed, 19 insertions(+), 7 deletions(-)
diff --git a/drivers/net/zynq_gem.c b/drivers/net/zynq_gem.c index b3821c31a91d..4049e1cb94e8 100644 --- a/drivers/net/zynq_gem.c +++ b/drivers/net/zynq_gem.c @@ -57,6 +57,8 @@ DECLARE_GLOBAL_DATA_PTR; #define ZYNQ_GEM_NWCFG_SPEED1000 0x000000400 /* 1Gbps operation */ #define ZYNQ_GEM_NWCFG_FDEN 0x000000002 /* Full Duplex mode */ #define ZYNQ_GEM_NWCFG_FSREM 0x000020000 /* FCS removal */ +#define ZYNQ_GEM_NWCFG_SGMII_ENBL 0x080000000 /* SGMII Enable */ +#define ZYNQ_GEM_NWCFG_PCS_SEL 0x000000800 /* PCS select */
Use BIT() macro.
#ifdef CONFIG_ARM64 #define ZYNQ_GEM_NWCFG_MDCCLKDIV 0x000100000 /* Div pclk by 64, max 160MHz */ #else @@ -330,10 +332,12 @@ static int zynq_phy_init(struct udevice *dev) /* Enable only MDIO bus */ writel(ZYNQ_GEM_NWCTRL_MDEN_MASK, ®s->nwctrl);
ret = phy_detection(dev);
if (ret) {
printf("GEM PHY init failed\n");
return ret;
if (priv->interface != PHY_INTERFACE_MODE_SGMII) {
ret = phy_detection(dev);
if (ret) {
printf("GEM PHY init failed\n");
return ret;
} } priv->phydev = phy_connect(priv->bus, priv->phyaddr, dev,
@@ -351,7 +355,7 @@ static int zynq_phy_init(struct udevice *dev)
static int zynq_gem_init(struct udevice *dev) {
u32 i;
u32 i, nwconfig; unsigned long clk_rate = 0; struct zynq_gem_priv *priv = dev_get_priv(dev); struct zynq_gem_regs *regs = priv->iobase;
@@ -426,14 +430,20 @@ static int zynq_gem_init(struct udevice *dev) return -1; }
nwconfig = ZYNQ_GEM_NWCFG_INIT;
if (priv->interface == PHY_INTERFACE_MODE_SGMII)
nwconfig |= ZYNQ_GEM_NWCFG_SGMII_ENBL |
ZYNQ_GEM_NWCFG_PCS_SEL;
switch (priv->phydev->speed) { case SPEED_1000:
writel(ZYNQ_GEM_NWCFG_INIT | ZYNQ_GEM_NWCFG_SPEED1000,
writel(nwconfig | ZYNQ_GEM_NWCFG_SPEED1000, ®s->nwcfg); clk_rate = ZYNQ_GEM_FREQUENCY_1000; break; case SPEED_100:
writel(ZYNQ_GEM_NWCFG_INIT | ZYNQ_GEM_NWCFG_SPEED100,
writel(nwconfig | ZYNQ_GEM_NWCFG_SPEED100, ®s->nwcfg); clk_rate = ZYNQ_GEM_FREQUENCY_100; break;
@@ -663,6 +673,8 @@ static int zynq_gem_ofdata_to_platdata(struct udevice *dev) } priv->interface = pdata->phy_interface;
priv->emio = fdtdec_get_bool(gd->fdt_blob, dev->of_offset, "xlnx,emio");
It seems this belongs in a separate patch.
printf("ZYNQ GEM: %lx, phyaddr %d, interface %s\n", (ulong)priv->iobase, priv->phyaddr, phy_string_for_interface(priv->interface));
-- 1.9.1
U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot

From: Siva Durga Prasad Paladugu siva.durga.paladugu@xilinx.com
Add support of Xilinx PCS/PMA core phy for Zynq
Signed-off-by: Siva Durga Prasad Paladugu sivadur@xilinx.com Signed-off-by: Michal Simek michal.simek@xilinx.com ---
include/configs/zynq-common.h | 1 + 1 file changed, 1 insertion(+)
diff --git a/include/configs/zynq-common.h b/include/configs/zynq-common.h index e8c3ef0c3872..ea273b8d54b7 100644 --- a/include/configs/zynq-common.h +++ b/include/configs/zynq-common.h @@ -50,6 +50,7 @@ # define CONFIG_MII # define CONFIG_SYS_FAULT_ECHO_LINK_DOWN # define CONFIG_PHY_MARVELL +# define CONFIG_PHY_XILINX # define CONFIG_BOOTP_SERVERIP # define CONFIG_BOOTP_BOOTPATH # define CONFIG_BOOTP_GATEWAY

On Mon, Feb 15, 2016 at 3:54 AM, Michal Simek michal.simek@xilinx.com wrote:
From: Siva Durga Prasad Paladugu siva.durga.paladugu@xilinx.com
Add phy driver support for xilinx PCS/PMA core
Signed-off-by: Siva Durga Prasad Paladugu sivadur@xilinx.com Signed-off-by: Kedareswara rao Appana appanad@xilinx.com Signed-off-by: Michal Simek michal.simek@xilinx.com
drivers/net/phy/Makefile | 1 + drivers/net/phy/phy.c | 3 + drivers/net/phy/xilinx_phy.c | 144 +++++++++++++++++++++++++++++++++++++++++++ include/phy.h | 1 + 4 files changed, 149 insertions(+) create mode 100644 drivers/net/phy/xilinx_phy.c
diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile index 9e4d4927e676..1e299b97b961 100644 --- a/drivers/net/phy/Makefile +++ b/drivers/net/phy/Makefile @@ -25,4 +25,5 @@ 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 diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c index 17866a244b3a..23c82bb36e93 100644 --- a/drivers/net/phy/phy.c +++ b/drivers/net/phy/phy.c @@ -503,6 +503,9 @@ int phy_init(void) #ifdef CONFIG_PHY_VITESSE phy_vitesse_init(); #endif +#ifdef CONFIG_PHY_XILINX
phy_xilinx_init();
+#endif
return 0;
} diff --git a/drivers/net/phy/xilinx_phy.c b/drivers/net/phy/xilinx_phy.c new file mode 100644 index 000000000000..f3eaf2e97ced --- /dev/null +++ b/drivers/net/phy/xilinx_phy.c @@ -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
Use the BIT() macro where appropriate.
+#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);
Is there a bindings document that can be included to describe this?
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;
+} diff --git a/include/phy.h b/include/phy.h index 09bbe483a4b1..21459a8c8093 100644 --- a/include/phy.h +++ b/include/phy.h @@ -264,6 +264,7 @@ int phy_smsc_init(void); int phy_teranetics_init(void); int phy_ti_init(void); int phy_vitesse_init(void); +int phy_xilinx_init(void);
int board_phy_config(struct phy_device *phydev); int get_phy_id(struct mii_dev *bus, int addr, int devad, u32 *phy_id); -- 1.9.1
U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot

On 25/04/16 15:36, Joe Hershberger wrote:
On Mon, Feb 15, 2016 at 3:54 AM, Michal Simek michal.simek@xilinx.com wrote:
From: Siva Durga Prasad Paladugu siva.durga.paladugu@xilinx.com
Add phy driver support for xilinx PCS/PMA core
Signed-off-by: Siva Durga Prasad Paladugu sivadur@xilinx.com Signed-off-by: Kedareswara rao Appana appanad@xilinx.com Signed-off-by: Michal Simek michal.simek@xilinx.com
[snip]
+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);
Is there a bindings document that can be included to describe this?
If that is meant to be the PHY type (MII, RGMII etc.) the standard property name is either 'phy-mode' or 'phy-connection-type', the latter being the one described in ePAPR, while the former has been widely adopted by Linux nowadays (and other OSes possibly).
My 2 cents since I don't typically review u-boot changes.

On 26.4.2016 00:36, Joe Hershberger wrote:
On Mon, Feb 15, 2016 at 3:54 AM, Michal Simek michal.simek@xilinx.com wrote:
From: Siva Durga Prasad Paladugu siva.durga.paladugu@xilinx.com
Add phy driver support for xilinx PCS/PMA core
Signed-off-by: Siva Durga Prasad Paladugu sivadur@xilinx.com Signed-off-by: Kedareswara rao Appana appanad@xilinx.com Signed-off-by: Michal Simek michal.simek@xilinx.com
drivers/net/phy/Makefile | 1 + drivers/net/phy/phy.c | 3 + drivers/net/phy/xilinx_phy.c | 144 +++++++++++++++++++++++++++++++++++++++++++ include/phy.h | 1 + 4 files changed, 149 insertions(+) create mode 100644 drivers/net/phy/xilinx_phy.c
diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile index 9e4d4927e676..1e299b97b961 100644 --- a/drivers/net/phy/Makefile +++ b/drivers/net/phy/Makefile @@ -25,4 +25,5 @@ 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 diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c index 17866a244b3a..23c82bb36e93 100644 --- a/drivers/net/phy/phy.c +++ b/drivers/net/phy/phy.c @@ -503,6 +503,9 @@ int phy_init(void) #ifdef CONFIG_PHY_VITESSE phy_vitesse_init(); #endif +#ifdef CONFIG_PHY_XILINX
phy_xilinx_init();
+#endif
return 0;
} diff --git a/drivers/net/phy/xilinx_phy.c b/drivers/net/phy/xilinx_phy.c new file mode 100644 index 000000000000..f3eaf2e97ced --- /dev/null +++ b/drivers/net/phy/xilinx_phy.c @@ -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
Use the BIT() macro where appropriate.
+#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);
Is there a bindings document that can be included to describe this?
It should be added.
Siva: Can you please look at it?
Thanks, Michal
participants (3)
-
Florian Fainelli
-
Joe Hershberger
-
Michal Simek