1 // SPDX-License-Identifier: GPL-2.0 2 /* Copyright (c) 2019 - 2022 Beijing WangXun Technology Co., Ltd. */ 3 4 #include <linux/ethtool.h> 5 #include <linux/iopoll.h> 6 #include <linux/pci.h> 7 #include <linux/phy.h> 8 9 #include "../libwx/wx_type.h" 10 #include "../libwx/wx_hw.h" 11 #include "ngbe_type.h" 12 #include "ngbe_mdio.h" 13 14 static int ngbe_phy_read_reg_internal(struct mii_bus *bus, int phy_addr, int regnum) 15 { 16 struct wx *wx = bus->priv; 17 18 if (phy_addr != 0) 19 return 0xffff; 20 return (u16)rd32(wx, NGBE_PHY_CONFIG(regnum)); 21 } 22 23 static int ngbe_phy_write_reg_internal(struct mii_bus *bus, int phy_addr, int regnum, u16 value) 24 { 25 struct wx *wx = bus->priv; 26 27 if (phy_addr == 0) 28 wr32(wx, NGBE_PHY_CONFIG(regnum), value); 29 return 0; 30 } 31 32 static int ngbe_phy_read_reg_c22(struct mii_bus *bus, int phy_addr, int regnum) 33 { 34 struct wx *wx = bus->priv; 35 u16 phy_data; 36 37 if (wx->mac_type == em_mac_type_mdi) 38 phy_data = ngbe_phy_read_reg_internal(bus, phy_addr, regnum); 39 else 40 phy_data = wx_phy_read_reg_mdi_c22(bus, phy_addr, regnum); 41 42 return phy_data; 43 } 44 45 static int ngbe_phy_write_reg_c22(struct mii_bus *bus, int phy_addr, 46 int regnum, u16 value) 47 { 48 struct wx *wx = bus->priv; 49 int ret; 50 51 if (wx->mac_type == em_mac_type_mdi) 52 ret = ngbe_phy_write_reg_internal(bus, phy_addr, regnum, value); 53 else 54 ret = wx_phy_write_reg_mdi_c22(bus, phy_addr, regnum, value); 55 56 return ret; 57 } 58 59 static void ngbe_handle_link_change(struct net_device *dev) 60 { 61 struct wx *wx = netdev_priv(dev); 62 struct phy_device *phydev; 63 u32 lan_speed, reg; 64 65 phydev = wx->phydev; 66 if (!(wx->link != phydev->link || 67 wx->speed != phydev->speed || 68 wx->duplex != phydev->duplex)) 69 return; 70 71 wx->link = phydev->link; 72 wx->speed = phydev->speed; 73 wx->duplex = phydev->duplex; 74 switch (phydev->speed) { 75 case SPEED_10: 76 lan_speed = 0; 77 break; 78 case SPEED_100: 79 lan_speed = 1; 80 break; 81 case SPEED_1000: 82 default: 83 lan_speed = 2; 84 break; 85 } 86 wr32m(wx, NGBE_CFG_LAN_SPEED, 0x3, lan_speed); 87 88 if (phydev->link) { 89 reg = rd32(wx, WX_MAC_TX_CFG); 90 reg &= ~WX_MAC_TX_CFG_SPEED_MASK; 91 reg |= WX_MAC_TX_CFG_SPEED_1G | WX_MAC_TX_CFG_TE; 92 wr32(wx, WX_MAC_TX_CFG, reg); 93 /* Re configure MAC RX */ 94 reg = rd32(wx, WX_MAC_RX_CFG); 95 wr32(wx, WX_MAC_RX_CFG, reg); 96 wr32(wx, WX_MAC_PKT_FLT, WX_MAC_PKT_FLT_PR); 97 reg = rd32(wx, WX_MAC_WDG_TIMEOUT); 98 wr32(wx, WX_MAC_WDG_TIMEOUT, reg); 99 } 100 phy_print_status(phydev); 101 } 102 103 int ngbe_phy_connect(struct wx *wx) 104 { 105 int ret; 106 107 ret = phy_connect_direct(wx->netdev, 108 wx->phydev, 109 ngbe_handle_link_change, 110 PHY_INTERFACE_MODE_RGMII_ID); 111 if (ret) { 112 wx_err(wx, "PHY connect failed.\n"); 113 return ret; 114 } 115 116 return 0; 117 } 118 119 static void ngbe_phy_fixup(struct wx *wx) 120 { 121 struct phy_device *phydev = wx->phydev; 122 struct ethtool_eee eee; 123 124 phy_remove_link_mode(phydev, ETHTOOL_LINK_MODE_10baseT_Half_BIT); 125 phy_remove_link_mode(phydev, ETHTOOL_LINK_MODE_100baseT_Half_BIT); 126 phy_remove_link_mode(phydev, ETHTOOL_LINK_MODE_1000baseT_Half_BIT); 127 128 phydev->mac_managed_pm = true; 129 if (wx->mac_type != em_mac_type_mdi) 130 return; 131 /* disable EEE, internal phy does not support eee */ 132 memset(&eee, 0, sizeof(eee)); 133 phy_ethtool_set_eee(phydev, &eee); 134 } 135 136 int ngbe_mdio_init(struct wx *wx) 137 { 138 struct pci_dev *pdev = wx->pdev; 139 struct mii_bus *mii_bus; 140 int ret; 141 142 mii_bus = devm_mdiobus_alloc(&pdev->dev); 143 if (!mii_bus) 144 return -ENOMEM; 145 146 mii_bus->name = "ngbe_mii_bus"; 147 mii_bus->read = ngbe_phy_read_reg_c22; 148 mii_bus->write = ngbe_phy_write_reg_c22; 149 mii_bus->phy_mask = GENMASK(31, 4); 150 mii_bus->parent = &pdev->dev; 151 mii_bus->priv = wx; 152 153 if (wx->mac_type == em_mac_type_rgmii) { 154 mii_bus->read_c45 = wx_phy_read_reg_mdi_c45; 155 mii_bus->write_c45 = wx_phy_write_reg_mdi_c45; 156 } 157 158 snprintf(mii_bus->id, MII_BUS_ID_SIZE, "ngbe-%x", pci_dev_id(pdev)); 159 ret = devm_mdiobus_register(&pdev->dev, mii_bus); 160 if (ret) 161 return ret; 162 163 wx->phydev = phy_find_first(mii_bus); 164 if (!wx->phydev) 165 return -ENODEV; 166 167 phy_attached_info(wx->phydev); 168 ngbe_phy_fixup(wx); 169 170 wx->link = 0; 171 wx->speed = 0; 172 wx->duplex = 0; 173 174 return 0; 175 } 176