e24b58f5ed
Currently we require PHY interface mode to be known when finding/creating the PHY - the functions * phy_connect_phy_id() * phy_device_create() * create_phy_by_mask() * search_for_existing_phy() * get_phy_device_by_mask() * phy_find_by_mask() all require the interface parameter, but the only thing done with it is that it is assigned to phydev->interface. This makes it impossible to find a PHY device without overwriting the set mode. Since the interface mode is not used during .probe() and should be used at first in .config(), drop the interface parameter from these functions. Make the default value of phydev->interface (in phy_device_create()) to be PHY_INTERFACE_MODE_NA. Move the interface parameter to phy_connect_dev(), where it should be. Change all occurrences treewide. In occurrences where we don't call phy_connect_dev() for some reason (they only configure the PHY without connecting it to an ethernet controller), set phydev->interface = value from phy_find_by_mask call. Signed-off-by: Marek Behún <marek.behun@nic.cz> Reviewed-by: Ramon Fried <rfried.dev@gmail.com> Reviewed-by: Vladimir Oltean <vladimir.oltean@nxp.com>
145 lines
3.2 KiB
C
145 lines
3.2 KiB
C
// SPDX-License-Identifier: GPL-2.0
|
|
/*
|
|
* Xilinx GMII2RGMII phy driver
|
|
*
|
|
* Copyright (C) 2018 Xilinx, Inc.
|
|
*/
|
|
|
|
#include <common.h>
|
|
#include <dm.h>
|
|
#include <log.h>
|
|
#include <phy.h>
|
|
#include <asm/global_data.h>
|
|
|
|
DECLARE_GLOBAL_DATA_PTR;
|
|
|
|
#define ZYNQ_GMII2RGMII_REG 0x10
|
|
#define ZYNQ_GMII2RGMII_SPEED_MASK (BMCR_SPEED1000 | BMCR_SPEED100)
|
|
|
|
static int xilinxgmiitorgmii_config(struct phy_device *phydev)
|
|
{
|
|
ofnode node = phy_get_ofnode(phydev);
|
|
struct phy_device *ext_phydev;
|
|
struct ofnode_phandle_args phandle;
|
|
int ext_phyaddr = -1;
|
|
int ret;
|
|
|
|
debug("%s\n", __func__);
|
|
|
|
if (phydev->interface != PHY_INTERFACE_MODE_GMII) {
|
|
printf("Incorrect interface type\n");
|
|
return -EINVAL;
|
|
}
|
|
|
|
if (!ofnode_valid(node))
|
|
return -EINVAL;
|
|
|
|
phydev->addr = ofnode_read_u32_default(node, "reg", -1);
|
|
ret = ofnode_parse_phandle_with_args(node, "phy-handle",
|
|
NULL, 0, 0, &phandle);
|
|
if (ret)
|
|
return ret;
|
|
|
|
ext_phyaddr = ofnode_read_u32_default(phandle.node, "reg", -1);
|
|
ext_phydev = phy_find_by_mask(phydev->bus,
|
|
1 << ext_phyaddr);
|
|
if (!ext_phydev) {
|
|
printf("%s, No external phy device found\n", __func__);
|
|
return -EINVAL;
|
|
}
|
|
|
|
ext_phydev->interface = PHY_INTERFACE_MODE_RGMII;
|
|
ext_phydev->node = phandle.node;
|
|
phydev->priv = ext_phydev;
|
|
|
|
debug("%s, gmii2rgmmi:0x%x, extphy:0x%x\n", __func__, phydev->addr,
|
|
ext_phyaddr);
|
|
|
|
if (ext_phydev->drv->config)
|
|
ext_phydev->drv->config(ext_phydev);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int xilinxgmiitorgmii_extread(struct phy_device *phydev, int addr,
|
|
int devaddr, int regnum)
|
|
{
|
|
struct phy_device *ext_phydev = phydev->priv;
|
|
|
|
debug("%s\n", __func__);
|
|
if (ext_phydev->drv->readext)
|
|
ext_phydev->drv->readext(ext_phydev, addr, devaddr, regnum);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int xilinxgmiitorgmii_extwrite(struct phy_device *phydev, int addr,
|
|
int devaddr, int regnum, u16 val)
|
|
|
|
{
|
|
struct phy_device *ext_phydev = phydev->priv;
|
|
|
|
debug("%s\n", __func__);
|
|
if (ext_phydev->drv->writeext)
|
|
ext_phydev->drv->writeext(ext_phydev, addr, devaddr, regnum,
|
|
val);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int xilinxgmiitorgmii_startup(struct phy_device *phydev)
|
|
{
|
|
u16 val = 0;
|
|
struct phy_device *ext_phydev = phydev->priv;
|
|
|
|
debug("%s\n", __func__);
|
|
ext_phydev->dev = phydev->dev;
|
|
if (ext_phydev->drv->startup)
|
|
ext_phydev->drv->startup(ext_phydev);
|
|
|
|
val = phy_read(phydev, phydev->addr, ZYNQ_GMII2RGMII_REG);
|
|
val &= ~ZYNQ_GMII2RGMII_SPEED_MASK;
|
|
|
|
if (ext_phydev->speed == SPEED_1000)
|
|
val |= BMCR_SPEED1000;
|
|
else if (ext_phydev->speed == SPEED_100)
|
|
val |= BMCR_SPEED100;
|
|
|
|
phy_write(phydev, phydev->addr, ZYNQ_GMII2RGMII_REG, val |
|
|
BMCR_FULLDPLX);
|
|
|
|
phydev->duplex = ext_phydev->duplex;
|
|
phydev->speed = ext_phydev->speed;
|
|
phydev->link = ext_phydev->link;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int xilinxgmiitorgmii_probe(struct phy_device *phydev)
|
|
{
|
|
debug("%s\n", __func__);
|
|
|
|
phydev->flags |= PHY_FLAG_BROKEN_RESET;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static struct phy_driver gmii2rgmii_driver = {
|
|
.name = "XILINX GMII2RGMII",
|
|
.uid = PHY_GMII2RGMII_ID,
|
|
.mask = 0xffffffff,
|
|
.features = PHY_GBIT_FEATURES,
|
|
.probe = xilinxgmiitorgmii_probe,
|
|
.config = xilinxgmiitorgmii_config,
|
|
.startup = xilinxgmiitorgmii_startup,
|
|
.writeext = xilinxgmiitorgmii_extwrite,
|
|
.readext = xilinxgmiitorgmii_extread,
|
|
};
|
|
|
|
int phy_xilinx_gmii2rgmii_init(void)
|
|
{
|
|
phy_register(&gmii2rgmii_driver);
|
|
|
|
return 0;
|
|
}
|