add xilinx_phy driver

This commit is contained in:
uzi 2024-04-28 18:32:12 +08:00
parent 2d5c250396
commit a2e92d1350
4 changed files with 191 additions and 0 deletions

View File

@ -338,6 +338,14 @@ config VITESSE_PHY
help
Currently supports the vsc8244
config XILINX_PHY
tristate "Drivers for xilinx PHYs"
help
This module provides a driver for the Xilinx PCS/PMA Core.
The supported PHY modes include SGMII and 1000BaseX.
This can be used an Ethernet controller, for example Xilinx
Axi Ethernet or Cadence GEM in Xilinx devices.
config XILINX_GMII2RGMII
tristate "Xilinx GMII2RGMII converter driver"
help

View File

@ -84,5 +84,6 @@ obj-$(CONFIG_SMSC_PHY) += smsc.o
obj-$(CONFIG_STE10XP) += ste10Xp.o
obj-$(CONFIG_TERANETICS_PHY) += teranetics.o
obj-$(CONFIG_VITESSE_PHY) += vitesse.o
obj-$(CONFIG_XILINX_PHY) += xilinx_phy.o
obj-$(CONFIG_XILINX_GMII2RGMII) += xilinx_gmii2rgmii.o
obj-$(CONFIG_CTC_PHY) += mars.o

View File

@ -0,0 +1,162 @@
// SPDX-License-Identifier: GPL-2.0+
/* Xilinx PCS/PMA Core phy driver
*
* Copyright (C) 2015 Xilinx, Inc.
*
* Description:
* This driver is developed for PCS/PMA Core.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/mii.h>
#include <linux/phy.h>
#include <linux/of.h>
#include <linux/xilinx_phy.h>
#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
static int xilinxphy_read_status(struct phy_device *phydev)
{
int err;
int status = 0;
/* Update the link, but return if there
* was an error
*/
err = genphy_update_link(phydev);
if (err)
return err;
if (phydev->autoneg == AUTONEG_ENABLE) {
status = phy_read(phydev, MII_LPA);
if (status & MII_PHY_STATUS_FULLDUPLEX)
phydev->duplex = DUPLEX_FULL;
else
phydev->duplex = DUPLEX_HALF;
switch (status & MII_PHY_STATUS_SPD_MASK) {
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, 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->dev_flags == XAE_PHY_TYPE_1000BASE_X) {
phydev->duplex = DUPLEX_FULL;
phydev->speed = SPEED_1000;
}
/* For 2500BASE-X Phy Mode the speed/duplex will always be
* 2500Mbps/fullduplex
*/
if (phydev->dev_flags == XAE_PHY_TYPE_2500) {
phydev->duplex = DUPLEX_FULL;
phydev->speed = SPEED_2500;
}
return 0;
}
static int xilinxphy_of_init(struct phy_device *phydev)
{
struct device *dev = &phydev->mdio.dev;
struct device_node *of_node = dev->of_node;
u32 phytype;
if (!IS_ENABLED(CONFIG_OF_MDIO))
return 0;
if (!of_node)
return -ENODEV;
if (!of_property_read_u32(of_node, "xlnx,phy-type", &phytype)) {
if (phytype == XAE_PHY_TYPE_1000BASE_X)
phydev->dev_flags |= XAE_PHY_TYPE_1000BASE_X;
if (phytype == XAE_PHY_TYPE_2500)
phydev->dev_flags |= XAE_PHY_TYPE_2500;
}
return 0;
}
static int xilinxphy_config_init(struct phy_device *phydev)
{
int temp;
xilinxphy_of_init(phydev);
temp = phy_read(phydev, MII_BMCR);
temp &= XPCSPMA_PHY_CTRL_ISOLATE_DISABLE;
phy_write(phydev, MII_BMCR, temp);
return 0;
}
static struct phy_driver xilinx_drivers[] = {
{
.phy_id = XILINX_PHY_ID,
.phy_id_mask = XILINX_PHY_ID_MASK,
.name = "Xilinx PCS/PMA PHY",
.flags = PHY_RST_AFTER_CLK_EN,
.features = PHY_GBIT_FEATURES,
.config_init = &xilinxphy_config_init,
.config_aneg = &genphy_config_aneg,
.read_status = &xilinxphy_read_status,
.resume = &genphy_resume,
.suspend = &genphy_suspend,
},
};
module_phy_driver(xilinx_drivers);
static struct mdio_device_id __maybe_unused xilinx_tbl[] = {
{ XILINX_PHY_ID, XILINX_PHY_ID_MASK },
{ }
};
MODULE_DEVICE_TABLE(mdio, xilinx_tbl);
MODULE_DESCRIPTION("Xilinx PCS/PMA PHY driver");
MODULE_LICENSE("GPL");

View File

@ -0,0 +1,20 @@
/* SPDX-License-Identifier: GPL-2.0+ */
#ifndef _XILINX_PHY_H
#define _XILINX_PHY_H
/* 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
#define XAE_PHY_TYPE_2500 6
#endif /* _XILINX_PHY_H */