162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* Copyright Sunplus Technology Co., Ltd. 362306a36Sopenharmony_ci * All rights reserved. 462306a36Sopenharmony_ci */ 562306a36Sopenharmony_ci 662306a36Sopenharmony_ci#include <linux/netdevice.h> 762306a36Sopenharmony_ci#include <linux/bitfield.h> 862306a36Sopenharmony_ci#include <linux/of_mdio.h> 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci#include "spl2sw_register.h" 1162306a36Sopenharmony_ci#include "spl2sw_define.h" 1262306a36Sopenharmony_ci#include "spl2sw_phy.h" 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_cistatic void spl2sw_mii_link_change(struct net_device *ndev) 1562306a36Sopenharmony_ci{ 1662306a36Sopenharmony_ci struct spl2sw_mac *mac = netdev_priv(ndev); 1762306a36Sopenharmony_ci struct phy_device *phydev = ndev->phydev; 1862306a36Sopenharmony_ci struct spl2sw_common *comm = mac->comm; 1962306a36Sopenharmony_ci u32 reg; 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_ci reg = readl(comm->l2sw_reg_base + L2SW_MAC_FORCE_MODE); 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_ci if (phydev->link) { 2462306a36Sopenharmony_ci reg |= FIELD_PREP(MAC_FORCE_RMII_LINK, mac->lan_port); 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_ci if (phydev->speed == 100) { 2762306a36Sopenharmony_ci reg |= FIELD_PREP(MAC_FORCE_RMII_SPD, mac->lan_port); 2862306a36Sopenharmony_ci } else { 2962306a36Sopenharmony_ci reg &= FIELD_PREP(MAC_FORCE_RMII_SPD, ~mac->lan_port) | 3062306a36Sopenharmony_ci ~MAC_FORCE_RMII_SPD; 3162306a36Sopenharmony_ci } 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_ci if (phydev->duplex) { 3462306a36Sopenharmony_ci reg |= FIELD_PREP(MAC_FORCE_RMII_DPX, mac->lan_port); 3562306a36Sopenharmony_ci } else { 3662306a36Sopenharmony_ci reg &= FIELD_PREP(MAC_FORCE_RMII_DPX, ~mac->lan_port) | 3762306a36Sopenharmony_ci ~MAC_FORCE_RMII_DPX; 3862306a36Sopenharmony_ci } 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_ci if (phydev->pause) { 4162306a36Sopenharmony_ci reg |= FIELD_PREP(MAC_FORCE_RMII_FC, mac->lan_port); 4262306a36Sopenharmony_ci } else { 4362306a36Sopenharmony_ci reg &= FIELD_PREP(MAC_FORCE_RMII_FC, ~mac->lan_port) | 4462306a36Sopenharmony_ci ~MAC_FORCE_RMII_FC; 4562306a36Sopenharmony_ci } 4662306a36Sopenharmony_ci } else { 4762306a36Sopenharmony_ci reg &= FIELD_PREP(MAC_FORCE_RMII_LINK, ~mac->lan_port) | 4862306a36Sopenharmony_ci ~MAC_FORCE_RMII_LINK; 4962306a36Sopenharmony_ci } 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_ci writel(reg, comm->l2sw_reg_base + L2SW_MAC_FORCE_MODE); 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_ci phy_print_status(phydev); 5462306a36Sopenharmony_ci} 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ciint spl2sw_phy_connect(struct spl2sw_common *comm) 5762306a36Sopenharmony_ci{ 5862306a36Sopenharmony_ci struct phy_device *phydev; 5962306a36Sopenharmony_ci struct net_device *ndev; 6062306a36Sopenharmony_ci struct spl2sw_mac *mac; 6162306a36Sopenharmony_ci int i; 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_ci for (i = 0; i < MAX_NETDEV_NUM; i++) 6462306a36Sopenharmony_ci if (comm->ndev[i]) { 6562306a36Sopenharmony_ci ndev = comm->ndev[i]; 6662306a36Sopenharmony_ci mac = netdev_priv(ndev); 6762306a36Sopenharmony_ci phydev = of_phy_connect(ndev, mac->phy_node, spl2sw_mii_link_change, 6862306a36Sopenharmony_ci 0, mac->phy_mode); 6962306a36Sopenharmony_ci if (!phydev) 7062306a36Sopenharmony_ci return -ENODEV; 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_ci phy_support_asym_pause(phydev); 7362306a36Sopenharmony_ci phy_attached_info(phydev); 7462306a36Sopenharmony_ci } 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_ci return 0; 7762306a36Sopenharmony_ci} 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_civoid spl2sw_phy_remove(struct spl2sw_common *comm) 8062306a36Sopenharmony_ci{ 8162306a36Sopenharmony_ci struct net_device *ndev; 8262306a36Sopenharmony_ci int i; 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_ci for (i = 0; i < MAX_NETDEV_NUM; i++) 8562306a36Sopenharmony_ci if (comm->ndev[i]) { 8662306a36Sopenharmony_ci ndev = comm->ndev[i]; 8762306a36Sopenharmony_ci if (ndev) 8862306a36Sopenharmony_ci phy_disconnect(ndev->phydev); 8962306a36Sopenharmony_ci } 9062306a36Sopenharmony_ci} 91