mirror of
https://github.com/torvalds/linux.git
synced 2026-05-25 23:52:08 +02:00
net: usb: lan78xx: refactor PHY init to separate detection and MAC configuration
Split out PHY detection into lan78xx_get_phy() and MAC-side setup into lan78xx_mac_prepare_for_phy(), making the main lan78xx_phy_init() cleaner and easier to follow. This improves separation of concerns and prepares the code for a future transition to phylink. Fixed PHY registration and interface selection are now handled in lan78xx_get_phy(), while MAC-side delay configuration is done in lan78xx_mac_prepare_for_phy(). The fixed PHY fallback is preserved for setups like EVB-KSZ9897-1, where LAN7801 connects directly to a KSZ switch without a standard PHY or device tree support. No functional changes intended. Signed-off-by: Oleksij Rempel <o.rempel@pengutronix.de> Reviewed-by: Thangaraj Samynathan <thangaraj.s@microchip.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
3da0ae5270
commit
d39f339d26
|
|
@ -2508,53 +2508,145 @@ static void lan78xx_remove_irq_domain(struct lan78xx_net *dev)
|
|||
dev->domain_data.irqdomain = NULL;
|
||||
}
|
||||
|
||||
static struct phy_device *lan7801_phy_init(struct lan78xx_net *dev)
|
||||
/**
|
||||
* lan78xx_register_fixed_phy() - Register a fallback fixed PHY
|
||||
* @dev: LAN78xx device
|
||||
*
|
||||
* Registers a fixed PHY with 1 Gbps full duplex. This is used in special cases
|
||||
* like EVB-KSZ9897-1, where LAN7801 acts as a USB-to-Ethernet interface to a
|
||||
* switch without a visible PHY.
|
||||
*
|
||||
* Return: pointer to the registered fixed PHY, or ERR_PTR() on error.
|
||||
*/
|
||||
static struct phy_device *lan78xx_register_fixed_phy(struct lan78xx_net *dev)
|
||||
{
|
||||
struct fixed_phy_status fphy_status = {
|
||||
.link = 1,
|
||||
.speed = SPEED_1000,
|
||||
.duplex = DUPLEX_FULL,
|
||||
};
|
||||
|
||||
netdev_info(dev->net,
|
||||
"No PHY found on LAN7801 – registering fixed PHY (e.g. EVB-KSZ9897-1)\n");
|
||||
|
||||
return fixed_phy_register(PHY_POLL, &fphy_status, NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* lan78xx_get_phy() - Probe or register PHY device and set interface mode
|
||||
* @dev: LAN78xx device structure
|
||||
*
|
||||
* This function attempts to find a PHY on the MDIO bus. If no PHY is found
|
||||
* and the chip is LAN7801, it registers a fixed PHY as fallback. It also
|
||||
* sets dev->interface based on chip ID and detected PHY type.
|
||||
*
|
||||
* Return: a valid PHY device pointer, or ERR_PTR() on failure.
|
||||
*/
|
||||
static struct phy_device *lan78xx_get_phy(struct lan78xx_net *dev)
|
||||
{
|
||||
struct phy_device *phydev;
|
||||
|
||||
/* Attempt to locate a PHY on the MDIO bus */
|
||||
phydev = phy_find_first(dev->mdiobus);
|
||||
|
||||
switch (dev->chipid) {
|
||||
case ID_REV_CHIP_ID_7801_:
|
||||
if (phydev) {
|
||||
/* External RGMII PHY detected */
|
||||
dev->interface = PHY_INTERFACE_MODE_RGMII_ID;
|
||||
phydev->is_internal = false;
|
||||
|
||||
if (!phydev->drv)
|
||||
netdev_warn(dev->net,
|
||||
"PHY driver not found – assuming RGMII delays are on PCB or strapped for the PHY\n");
|
||||
|
||||
return phydev;
|
||||
}
|
||||
|
||||
dev->interface = PHY_INTERFACE_MODE_RGMII;
|
||||
/* No PHY found – fallback to fixed PHY (e.g. KSZ switch board) */
|
||||
return lan78xx_register_fixed_phy(dev);
|
||||
|
||||
case ID_REV_CHIP_ID_7800_:
|
||||
case ID_REV_CHIP_ID_7850_:
|
||||
if (!phydev)
|
||||
return ERR_PTR(-ENODEV);
|
||||
|
||||
/* These use internal GMII-connected PHY */
|
||||
dev->interface = PHY_INTERFACE_MODE_GMII;
|
||||
phydev->is_internal = true;
|
||||
return phydev;
|
||||
|
||||
default:
|
||||
netdev_err(dev->net, "Unknown CHIP ID: 0x%08x\n", dev->chipid);
|
||||
return ERR_PTR(-ENODEV);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* lan78xx_mac_prepare_for_phy() - Preconfigure MAC-side interface settings
|
||||
* @dev: LAN78xx device
|
||||
*
|
||||
* Configure MAC-side registers according to dev->interface, which should be
|
||||
* set by lan78xx_get_phy().
|
||||
*
|
||||
* - For PHY_INTERFACE_MODE_RGMII:
|
||||
* Enable MAC-side TXC delay. This mode seems to be used in a special setup
|
||||
* without a real PHY, likely on EVB-KSZ9897-1. In that design, LAN7801 is
|
||||
* connected to the KSZ9897 switch, and the link timing is expected to be
|
||||
* hardwired (e.g. via strapping or board layout). No devicetree support is
|
||||
* assumed here.
|
||||
*
|
||||
* - For PHY_INTERFACE_MODE_RGMII_ID:
|
||||
* Disable MAC-side delay and rely on the PHY driver to provide delay.
|
||||
*
|
||||
* - For GMII, no MAC-specific config is needed.
|
||||
*
|
||||
* Return: 0 on success or a negative error code.
|
||||
*/
|
||||
static int lan78xx_mac_prepare_for_phy(struct lan78xx_net *dev)
|
||||
{
|
||||
int ret;
|
||||
|
||||
phydev = phy_find_first(dev->mdiobus);
|
||||
if (!phydev) {
|
||||
netdev_dbg(dev->net, "PHY Not Found!! Registering Fixed PHY\n");
|
||||
phydev = fixed_phy_register(PHY_POLL, &fphy_status, NULL);
|
||||
if (IS_ERR(phydev)) {
|
||||
netdev_err(dev->net, "No PHY/fixed_PHY found\n");
|
||||
return ERR_PTR(-ENODEV);
|
||||
}
|
||||
netdev_dbg(dev->net, "Registered FIXED PHY\n");
|
||||
dev->interface = PHY_INTERFACE_MODE_RGMII;
|
||||
switch (dev->interface) {
|
||||
case PHY_INTERFACE_MODE_RGMII:
|
||||
/* Enable MAC-side TX clock delay */
|
||||
ret = lan78xx_write_reg(dev, MAC_RGMII_ID,
|
||||
MAC_RGMII_ID_TXC_DELAY_EN_);
|
||||
if (ret < 0)
|
||||
return ERR_PTR(ret);
|
||||
return ret;
|
||||
|
||||
ret = lan78xx_write_reg(dev, RGMII_TX_BYP_DLL, 0x3D00);
|
||||
if (ret < 0)
|
||||
return ERR_PTR(ret);
|
||||
return ret;
|
||||
|
||||
ret = lan78xx_update_reg(dev, HW_CFG, HW_CFG_CLK125_EN_ |
|
||||
HW_CFG_REFCLK25_EN_,
|
||||
ret = lan78xx_update_reg(dev, HW_CFG,
|
||||
HW_CFG_CLK125_EN_ | HW_CFG_REFCLK25_EN_,
|
||||
HW_CFG_CLK125_EN_ | HW_CFG_REFCLK25_EN_);
|
||||
if (ret < 0)
|
||||
return ERR_PTR(ret);
|
||||
} else {
|
||||
dev->interface = PHY_INTERFACE_MODE_RGMII_ID;
|
||||
/* The PHY driver is responsible to configure proper RGMII
|
||||
* interface delays. Disable RGMII delays on MAC side.
|
||||
*/
|
||||
return ret;
|
||||
|
||||
break;
|
||||
|
||||
case PHY_INTERFACE_MODE_RGMII_ID:
|
||||
/* Disable MAC-side TXC delay, PHY provides it */
|
||||
ret = lan78xx_write_reg(dev, MAC_RGMII_ID, 0);
|
||||
if (ret < 0)
|
||||
return ERR_PTR(ret);
|
||||
return ret;
|
||||
|
||||
phydev->is_internal = false;
|
||||
break;
|
||||
|
||||
case PHY_INTERFACE_MODE_GMII:
|
||||
/* No MAC-specific configuration required */
|
||||
break;
|
||||
|
||||
default:
|
||||
netdev_warn(dev->net, "Unsupported interface mode: %d\n",
|
||||
dev->interface);
|
||||
break;
|
||||
}
|
||||
|
||||
return phydev;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int lan78xx_phy_init(struct lan78xx_net *dev)
|
||||
|
|
@ -2564,31 +2656,13 @@ static int lan78xx_phy_init(struct lan78xx_net *dev)
|
|||
u32 mii_adv;
|
||||
struct phy_device *phydev;
|
||||
|
||||
switch (dev->chipid) {
|
||||
case ID_REV_CHIP_ID_7801_:
|
||||
phydev = lan7801_phy_init(dev);
|
||||
if (IS_ERR(phydev)) {
|
||||
netdev_err(dev->net, "lan7801: failed to init PHY: %pe\n",
|
||||
phydev);
|
||||
return PTR_ERR(phydev);
|
||||
}
|
||||
break;
|
||||
phydev = lan78xx_get_phy(dev);
|
||||
if (IS_ERR(phydev))
|
||||
return PTR_ERR(phydev);
|
||||
|
||||
case ID_REV_CHIP_ID_7800_:
|
||||
case ID_REV_CHIP_ID_7850_:
|
||||
phydev = phy_find_first(dev->mdiobus);
|
||||
if (!phydev) {
|
||||
netdev_err(dev->net, "no PHY found\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
phydev->is_internal = true;
|
||||
dev->interface = PHY_INTERFACE_MODE_GMII;
|
||||
break;
|
||||
|
||||
default:
|
||||
netdev_err(dev->net, "Unknown CHIP ID found\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
ret = lan78xx_mac_prepare_for_phy(dev);
|
||||
if (ret < 0)
|
||||
goto free_phy;
|
||||
|
||||
/* if phyirq is not set, use polling mode in phylib */
|
||||
if (dev->domain_data.phyirq > 0)
|
||||
|
|
@ -2662,6 +2736,14 @@ static int lan78xx_phy_init(struct lan78xx_net *dev)
|
|||
dev->fc_autoneg = phydev->autoneg;
|
||||
|
||||
return 0;
|
||||
|
||||
free_phy:
|
||||
if (phy_is_pseudo_fixed_link(phydev)) {
|
||||
fixed_phy_unregister(phydev);
|
||||
phy_device_free(phydev);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int lan78xx_set_rx_max_frame_length(struct lan78xx_net *dev, int size)
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user